Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
73bfb8c
stack_tec added
MelloBoo44 Aug 7, 2024
e506a99
Updated IRS to be holdable
electraminer Aug 7, 2024
b6b1581
Merge branch 'irs'
electraminer Aug 7, 2024
f6d8211
IRS buffering and cancelling via DCD
electraminer Aug 8, 2024
2562d51
Fixed a crash with instant IHS
electraminer Aug 9, 2024
fa34e2c
Merge remote-tracking branch 'upstream/main'
electraminer Aug 9, 2024
3e3c68e
Merge remote-tracking branch 'origin/main' into irs
electraminer Aug 9, 2024
2f1094d
Merge remote-tracking branch 'origin/main' into irs
electraminer Aug 9, 2024
3c94297
Merge remote-tracking branch 'upstream/main' into irs
electraminer Aug 29, 2024
8417122
IRS changes to allow further flexibility in controls and game modes
electraminer Aug 29, 2024
e6cb527
Forgot to save classic_e file
electraminer Aug 29, 2024
11f41b3
Logical IRS disabled will now buffer on the first frame instead of th…
electraminer Aug 29, 2024
d2e4739
Removed stack_tec (it has its own branch)
electraminer Aug 29, 2024
fa89718
Update main.yml to allow more version strings
electraminer Oct 8, 2024
bea81c6
Update main.yml to be under a different org
electraminer Oct 9, 2024
6847a3b
Fixed action system loading bug
electraminer Oct 9, 2024
ab64248
Fixed passthrough
electraminer Oct 9, 2024
9189f79
Forgot to rename a variable
electraminer Oct 9, 2024
3f12e1c
It works!
electraminer Oct 9, 2024
307a423
Completed merge
electraminer Oct 9, 2024
f46c840
Merge branch 'passthroughfix'
electraminer Nov 3, 2024
3bcaa2b
Merge remote-tracking branch 'upstream/main'
electraminer Nov 3, 2024
a699e6f
Merge remote-tracking branch 'upstream/main' into passthroughfix
electraminer Nov 19, 2024
9ec582e
Merge branch 'passthroughfix'
electraminer Nov 19, 2024
ee9de2c
removed special version tag
electraminer Nov 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
local version = require "version"
os.execute('echo "app-name=Techmino" >> $GITHUB_OUTPUT')
os.execute('echo "version-name=' .. version.name .. '" >> $GITHUB_OUTPUT')
os.execute('echo "version-string=' .. version.string:gsub("%a", "") .. '" >> $GITHUB_OUTPUT')
os.execute('echo "version-string=' .. version.string:gsub(" ", "_") .. '" >> $GITHUB_OUTPUT')
os.execute('echo "version-code=' .. tostring(version.code) .. '" >> $GITHUB_OUTPUT')

local f = io.open("updateLog.txt", 'r')
Expand Down Expand Up @@ -179,10 +179,10 @@ jobs:
import re
with open(os.getenv('GITHUB_OUTPUT'), 'a') as f:
if "${{ env.BUILD_TYPE }}" == "dev":
f.write('bundle-id=org.f26_studio.' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '.snapshot\n')
f.write('bundle-id=org.electra.' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '.snapshot\n')
f.write('product-name=' + re.sub(r'[^A-Za-z0-9]+', '-', '${{ needs.get-info.outputs.app-name }}') + '_Snapshot\n')
else:
f.write('bundle-id=org.f26_studio.' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '\n')
f.write('bundle-id=org.electra.' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '\n')
f.write('product-name=' + re.sub(r'[^A-Za-z0-9]+', '-', '${{ needs.get-info.outputs.app-name }}') + '\n')
- name: Download core love package
uses: actions/download-artifact@v4
Expand Down Expand Up @@ -252,7 +252,7 @@ jobs:
import re
product_name = re.sub(r'[^A-Za-z0-9]+', '-', '${{ needs.get-info.outputs.app-name }}').strip('-').lower()
with open(os.getenv('GITHUB_OUTPUT'), 'a') as f:
f.write('bundle-id=org.26f-studio.' + product_name + '\n')
f.write('bundle-id=org.electra.' + product_name + '\n')
f.write('product-name=' + product_name + '\n')
- name: Download core love package
uses: actions/download-artifact@v4
Expand Down
6 changes: 3 additions & 3 deletions parts/player/gameEnv0.lua
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ return {

-- Some Events are registered in player/init.lua, see "tableNeedMerge"
extraEvent={
{'attack',4},
{'attack',5},
},
extraEventHandler={
attack=function(P,P2,...)
P:beAttacked(P2,...)
attack=function(P,source,...)
P:beAttacked(source,...)
end,
},

Expand Down
86 changes: 43 additions & 43 deletions parts/player/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,17 @@ local function _loadRemoteEnv(P,confStr)-- Load gameEnv
end
end
end
local tableNeedMerge={
local function _mergeFuncTable(f,L)
if type(f)=='function' then
ins(L,f)
elseif type(f)=='table' then
for i=1,#f do
ins(L,f[i])
end
end
return L
end
local tableNeedMerge = {
'task',
'mesDisp',
'hook_left',
Expand All @@ -250,63 +260,53 @@ local tableNeedMerge={
'hook_spawn',
'hook_hold',
'hook_die',
'extraEvent',
'hook_atk_calculation',
'task',
}
for _,k in next,tableNeedMerge do gameEnv0[k]={} end
local function _mergeFuncTable(f,L)
if type(f)=='function' then
ins(L,f)
elseif type(f)=='table' then
for i=1,#f do
ins(L,f[i])
end
end
return L
end
local function _applyGameEnv(P)-- Finish gameEnv processing
local ENV=P.gameEnv

-- Create event tables
-- Apply events
for i=1,#tableNeedMerge do
ENV[tableNeedMerge[i]]=_mergeFuncTable(ENV[tableNeedMerge[i]],{})
end

-- Apply eventSet
while true do
if not (ENV.eventSet and ENV.eventSet~="X") then
break
end
if type(ENV.eventSet)~='string' then
MES.new('warn',"Wrong event set type: "..type(ENV.eventSet))
break
end
local eventSet=require('parts.eventsets.'..ENV.eventSet)
if not eventSet then
MES.new('warn',"No event set called: "..ENV.eventSet)
break
end
for k,v in next,eventSet do
if k=='extraEventHandler' then
for ev,handler in next,v do
if ENV.extraEventHandler[ev] then
local prevHandler=ENV.extraEventHandler[ev]
ENV.extraEventHandler[ev]=function(...)
prevHandler(...)
handler(...)
if ENV.eventSet and ENV.eventSet~="X" then
if type(ENV.eventSet)=='string' then
local eventSet=require('parts.eventsets.'..ENV.eventSet)
if eventSet then
for k,v in next,eventSet do
if k == "extraEvent" then
for _,ev in ipairs(v) do
table.insert(ENV.extraEvent, ev)
end
elseif k == "extraEventHandler" then
for ev,handler in pairs(v) do
if ENV.extraEventHandler[ev] then
local prevHandler = ENV.extraEventHandler[ev]
ENV.extraEventHandler[ev] = function(...)
prevHandler(...)
handler(...)
end
else
ENV.extraEventHandler[ev] = handler
end
end
elseif TABLE.find(tableNeedMerge,k) then
_mergeFuncTable(v,ENV[k])
elseif type(v)=='table' then
ENV[k]=TABLE.copy(v)
else
ENV.extraEventHandler[ev]=handler
ENV[k]=v
end
end
elseif TABLE.find(tableNeedMerge,k) then
_mergeFuncTable(v,ENV[k])
elseif type(v)=='table' then
ENV[k]=TABLE.copy(v)
else
ENV[k]=v
MES.new('warn',"No event set called: "..ENV.eventSet)
end
else
MES.new('warn',"Wrong event set type: "..type(ENV.eventSet))
end
break
end

P._20G=ENV.drop==0
Expand Down Expand Up @@ -512,4 +512,4 @@ function PLY.newPlayer(id,mini,p)
_applyGameEnv(P)
end
--------------------------</Public>--------------------------
return PLY
return PLY
109 changes: 71 additions & 38 deletions parts/player/player.lua
Original file line number Diff line number Diff line change
Expand Up @@ -274,13 +274,13 @@ function Player:act_rotRight()
-- Ensure IRS is spent before the rotation is processed so it doesn't throw things off.
-- This is so that if you for instance, are holding left IRS and then rotate right, it doesn't process
-- the left and right rotates in the reverse order.
self.keyPressing[3]=false
self.keyPressing[3] = false
self:resolveIRS()
self.keyPressing[3]=true
self.keyPressing[3] = true
end
self:spin(1)
self:_triggerEvent('hook_rotate',1)

-- Disable held inputs if IRS is off
if not self.gameEnv.irs then
self.keyPressing[3]=false
Expand All @@ -295,9 +295,9 @@ function Player:act_rotLeft()
-- Ensure IRS is spent before the rotation is processed so it doesn't throw things off.
-- This is so that if you for instance, are holding left IRS and then rotate right, it doesn't process
-- the left and right rotates in the reverse order.
self.keyPressing[4]=false
self.keyPressing[4] = false
self:resolveIRS()
self.keyPressing[4]=true
self.keyPressing[4] = true
end
self:spin(3)
self:_triggerEvent('hook_rotate',3)
Expand All @@ -315,9 +315,9 @@ function Player:act_rot180()
-- Ensure IRS is spent before the rotation is processed so it doesn't throw things off.
-- This is so that if you for instance, are holding left IRS and then rotate right, it doesn't process
-- the left and right rotates in the reverse order.
self.keyPressing[5]=false
self.keyPressing[5] = false
self:resolveIRS()
self.keyPressing[5]=true
self.keyPressing[5] = true
end
self:spin(2)
self:_triggerEvent('hook_rotate',2)
Expand Down Expand Up @@ -909,12 +909,45 @@ function Player:ifoverlap(bk,x,y)
end
end
function Player:attack(R,send,time,line)
self:extraEvent('attack',R.sid,send,time,line)
end
function Player:beAttacked(P2,sid,send,time,line)
if self==P2 or self.sid~=sid then return end
self:receive(P2,send,time,line)
P2:createBeam(self,send)
local sid = R.sid
-- Add the attack to the list of in-transit attacks.
-- These attacks will be able to cancel with incoming attacks that cross them.
if not self.inTransitAttacks then
self.inTransitAttacks = {}
end
if not self.inTransitAttacks[sid] then
self.inTransitAttacks[sid] = {seenAttacks = 0}
end
table.insert(self.inTransitAttacks[sid], {send=send, time=time, line=line})
-- Send the attack
-- We also send the number of seen attacks from this player.
-- This allows that player to know which attacks are still in transit, and which have already arrived.
-- This is because... if a player already saw an attack before sending this one, the attacks did not cross.
-- But if they didn't see the attack, then the attacks must have crossed (and should cancel each other)
self:extraEvent('attack',sid,send,time,line,self.inTransitAttacks[sid].seenAttacks)
end
function Player:beAttacked(source,target_sid,send,time,line,seenCount)
-- Only recieve the attack if you are the target.
if self==source or self.sid~=target_sid then return end

if not self.inTransitAttacks then
self.inTransitAttacks = {}
end
if not self.inTransitAttacks[source.sid] then
self.inTransitAttacks[source.sid] = {seenAttacks = 0}
end
-- Increment the number of seen attacks from that player.
self.inTransitAttacks[source.sid].seenAttacks = self.inTransitAttacks[source.sid].seenAttacks + 1
-- Block against any in-transit attacks before recieving (this prevents passhtrough)
for i=seenCount+1,#self.inTransitAttacks[source.sid] do
local atk = self.inTransitAttacks[source.sid][i]
local cancel = MATH.min(atk.send, send)
atk.send = atk.send - cancel
send = send - cancel
end

self:receive(source,send,time,line)
source:createBeam(self,send)
end
function Player:receive(A,send,time,line)
self.lastRecv=A
Expand Down Expand Up @@ -1205,7 +1238,7 @@ function Player:resetBlock()-- Reset Block's position and execute I*S
self.curY=y
self.minY=y+sc[1]

local ENV=self.gameEnv
local ENV = self.gameEnv

-- In the game settings, there are user-set control flags for irs,irs,ims
-- These control in what way the user can buffer their rotate/hold/move inputs.
Expand All @@ -1221,10 +1254,10 @@ function Player:resetBlock()-- Reset Block's position and execute I*S
-- IMS is enabled only when logicalIMS is enabled, because otherwise, it's just faster DAS.
if ENV.logicalIMS and (pressing[1] and self.movDir==-1 or pressing[2] and self.movDir==1) and self.moving>=self.gameEnv.das then
-- To avoid a top-out
if self:ifoverlap(C.bk,self.curX,self.curY) then
if self:ifoverlap(C.bk, self.curX, self.curY) then
-- Always perform the shift, since you're topped out anyway
self.curX=self.curX+self.movDir
elseif ENV.wait>0 and ENV.ims then
self.curX = self.curX + self.movDir
elseif ENV.wait > 0 and ENV.ims then
-- Otherwise, only check IMS if it's enabled and you're in a mode with entry delay (20g)
local x=self.curX+self.movDir
if not self:ifoverlap(C.bk,x,y) then
Expand All @@ -1235,15 +1268,15 @@ function Player:resetBlock()-- Reset Block's position and execute I*S

if not ENV.logicalIRS then
-- If logical IRS is disabled, all IRS inputs will be buffered to prevent survival.
self.bufferedIRS=true
self.bufferedDelay=0
if ENV.wait==0 then
self.bufferedDelay=ENV.irscut
self.bufferedIRS = true
self.bufferedDelay = 0
if ENV.wait == 0 then
self.bufferedDelay = ENV.irscut
end
elseif ENV.wait==0 and ENV.irscut>0 and not self:ifoverlap(C.bk,self.curX,self.curY) then
elseif ENV.wait==0 and ENV.irscut>0 and not self:ifoverlap(C.bk, self.curX, self.curY) then
-- If IRS cut delay is enabled and we aren't currently dying, buffer the input instead.
self.bufferedIRS=true
self.bufferedDelay=ENV.irscut
self.bufferedIRS = true
self.bufferedDelay = ENV.irscut
else
-- If we're currently dying or in an entry-delay mode (20g), perform the rotation right away.
if pressing[5] then
Expand Down Expand Up @@ -1588,17 +1621,17 @@ function Player:_popNext(ifhold)-- Pop nextQueue to hand
if not ifhold and pressing[8] and self.holdTime>0 then
if not ENV.logicalIHS then
-- If logical IHS is disabled, all IHS inputs will be buffered to prevent survival.
self.bufferedIRS=true
self.bufferedIHS=true
self.bufferedDelay=0
if ENV.wait==0 then
self.bufferedDelay=ENV.irscut
self.bufferedIRS = true
self.bufferedIHS = true
self.bufferedDelay = 0
if ENV.wait == 0 then
self.bufferedDelay = ENV.irscut
end
elseif ENV.wait==0 and ENV.irscut>0 and not self:willDieWith(self.cur) then
-- If IRS cut delay is enabled and we're not currently dying, buffer the input instead.
self.bufferedIRS=true
self.bufferedIHS=true
self.bufferedDelay=ENV.irscut
self.bufferedIRS = true
self.bufferedIHS = true
self.bufferedDelay = ENV.irscut
self:resetBlock()
else
-- If we're currently dying or in an entry-delay mode (20g), perform the hold immediately.
Expand Down Expand Up @@ -2558,11 +2591,11 @@ end
function Player:resolveIRS()
if self.bufferedIHS then
self:hold(true)
self.bufferedIHS=false
self.bufferedIHS = false
end

self.bufferedIRS=false
local pressing=self.keyPressing
self.bufferedIRS = false
local pressing = self.keyPressing
if pressing[5] then
self:act_rot180()
elseif pressing[3] then
Expand Down Expand Up @@ -2633,13 +2666,13 @@ local function update_alive(P,dt)
end
end
end

-- Buffer IRS after IRS cut delay has elapsed.
-- The purpose of this is to allow the player to release their rotate key during the IRS cut delay,
-- which will allow them to avoid accidentally using IRS.
if P.bufferedDelay then
P.bufferedDelay=P.bufferedDelay-1
if P.bufferedDelay<=0 then
P.bufferedDelay = P.bufferedDelay - 1
if P.bufferedDelay <= 0 then
if P.bufferedIRS then
P:resolveIRS()
end
Expand Down
5 changes: 2 additions & 3 deletions parts/scenes/setting_control.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ function scene.enter()
das,arr=SETTING.das,SETTING.arr
pos,dir,wait=0,1,30
BG.set('bg1')
DiscordRPC.update("Tweaking control settings")
end

local trigFrame=0
Expand Down Expand Up @@ -97,11 +96,11 @@ scene.widgetList={
WIDGET.newSlider{name='dascut', x=250, y=420,lim=230,w=600,axis={0,20,1},disp=SETval('dascut'), show=_sliderShow,code=SETsto('dascut')},
WIDGET.newSlider{name='irscut', x=250, y=480,lim=230,w=600,axis={0,20,1},disp=SETval('irscut'), show=_sliderShow,code=SETsto('irscut')},
WIDGET.newSlider{name='dropcut',x=250, y=540,lim=230,w=300,axis={0,10,1},disp=SETval('dropcut'),show=_sliderShow,code=SETsto('dropcut')},

WIDGET.newSwitch{name='ihs', x=1100, y=240,lim=300, disp=SETval('ihs'), code=SETrev('ihs')},
WIDGET.newSwitch{name='irs', x=1100, y=300,lim=300, disp=SETval('irs'), code=SETrev('irs')},
WIDGET.newSwitch{name='ims', x=1100, y=360,lim=300, disp=SETval('ims'), code=SETrev('ims')},

WIDGET.newButton{name='reset', x=160, y=640,w=200,h=100,color='lR',font=40,
code=function()
local _=SETTING
Expand Down