02TvͫgE#2Tv2Tv ] qqaaQQAAqaQA1 -- title: Tug of War -- author: claude -- desc: 2-player rope-tugging tap-off for Arcade TV -- script: lua -- Both players tap A as fast as they can. The faster tapper drags the -- rope toward their side. First to pull the marker past their finish -- line wins. Best of 3 rounds. local PLAYERS = 2 local KA = {26, 20} local COL = {2, 11} -- Title melody. {note, duration_in_frames} (or {nil, dur} for a rest). -- The whole table loops on the title screen as a rhythm-aware phrase. local MELODY = {{"D-4",12},{"D-4",12},{"A-4",12},{"A-4",12}, {"B-4",12},{"B-4",12},{"A-4",24}, {"G-4",12},{"G-4",12},{"F-4",12},{"F-4",12}, {"E-4",12},{"E-4",12},{"D-4",24},} local M_TOTAL = 0 for _, m in ipairs(MELODY) do M_TOTAL = M_TOTAL + m[2] end local WIN_ROUNDS = 2 local PULL_PER_TAP = 1.6 local DECAY = 0.04 local state, timer, winner = "title", 0, 0 local pos, sc, round_winner local function reset_match() pos = 0 -- 0 = center; positive = P1 winning, negative = P2 winning sc = {0, 0} round_winner = 0 winner = 0 end local function any_press() for i=1,PLAYERS do if keyp(KA[i],-1,-1) then return true end end; return false end local function cprint(t,y,c,s) s=s or 1; print(t,(240-#t*6*s)//2,y,c,false,s) end local function reset_round() pos = 0 round_winner = 0 end function TIC() cls(0) timer = timer + 1 if state == "title" then local bob = math.floor(math.sin(timer / 14) * 2) local tw = #"TUG OF WAR" * 6 * 3 print("TUG OF WAR",(240-tw)//2+1,28+bob+1,14,false,3) print("TUG OF WAR",(240-tw)//2,27+bob,12,false,3) cprint("Tap A as fast as you can!", 64, 13) cprint("Pull the marker to your side", 78, 13) cprint("Best of " .. (WIN_ROUNDS * 2 - 1) .. " rounds", 92, 12) if (timer // 30) % 2 == 0 then cprint("Press A to start", 116, 4) end -- Walk MELODY (module scope) and play one note at each onset. local pos, cum = timer % M_TOTAL, 0 for _, m in ipairs(MELODY) do if pos == cum and m[1] then sfx(0, m[1], m[2] - 1, 0) end cum = cum + m[2] end if any_press() then reset_match(); state="play"; timer=0; sfx(1,"C-5",18,1) end return end if state == "play" then -- header score cprint("P1 " .. sc[1] .. " - " .. sc[2] .. " P2", 4, 12) -- inputs for i = 1, PLAYERS do if keyp(KA[i],-1,-1) then pos = pos + (i == 1 and PULL_PER_TAP or -PULL_PER_TAP) sfx(1, "C-5", 3, i - 1) end end -- decay back toward center slightly (so spamming matters) pos = pos * (1 - DECAY) -- finish lines local LIMIT = 100 -- field rect(20, 60, 200, 16, 1) rectb(20, 60, 200, 16, 13) -- center line line(120, 56, 120, 80, 14) -- finish lines line(20, 56, 20, 80, COL[2]) line(220, 56, 220, 80, COL[1]) -- rope mark local mx = math.max(20, math.min(220, 120 + pos)) rect(mx - 3, 56, 6, 24, 4) rectb(mx - 3, 56, 6, 24, 0) -- direction arrows if pos > 5 then for k = 0, 3 do print(">", 130 + k * 6, 90, COL[1]) end elseif pos < -5 then for k = 0, 3 do print("<", 100 - k * 6, 90, COL[2]) end end cprint("P1 PULL <--> P2 PULL", 100, 13) if pos >= LIMIT then round_winner = 1 sc[1] = sc[1] + 1 trace("SCORE:1:" .. sc[1]) sfx(3, "G-5", 24, 1) if sc[1] >= WIN_ROUNDS then winner = 1; trace("WIN:1"); sfx(4, "C-5", 60, 2); state = "win"; timer = 0 else state = "round"; timer = 0 end elseif pos <= -LIMIT then round_winner = 2 sc[2] = sc[2] + 1 trace("SCORE:2:" .. sc[2]) sfx(3, "G-5", 24, 1) if sc[2] >= WIN_ROUNDS then winner = 2; trace("WIN:2"); sfx(4, "C-5", 60, 2); state = "win"; timer = 0 else state = "round"; timer = 0 end end return end if state == "round" then cprint("ROUND TO P" .. round_winner, 50, COL[round_winner], 2) cprint("P1 " .. sc[1] .. " - " .. sc[2] .. " P2", 80, 12) cprint("Get ready...", 100, 13) if timer >= 120 then reset_round(); state = "play"; timer = 0 end return end if state == "win" then rect(40, 40, 160, 50, 0) rectb(40, 40, 160, 50, COL[winner]) cprint("PLAYER " .. winner, 50, COL[winner], 2) cprint("WINS!", 70, 4, 2) if (timer // 30) % 2 == 0 then cprint("Press A to play again", 100, 12) end if timer > 60 and any_press() then reset_match(); state="play"; timer=0 end return end end