; SPDX-FileCopyrightText: 2023 Jummit
;
; SPDX-License-Identifier: GPL-3.0-or-later
(local {: get-online-of : get-cards-on : is-online : get-cell}
(require :match.info))
(local {: move} (require :move))
(local {: view} (require :fennel))
(fn online-at [world player x y]
(. (icollect [_ card (ipairs (get-cards-on world x y))]
(when (and (= card.card.owner player) (is-online card.card))
card)) 1))
(fn give-terminal [world player kind]
(var slot nil)
(each [_ entity (ipairs world)]
(match entity
{:slot {: kind :owner player}} (set slot entity)))
(set slot.slot.used true)
(table.insert world {:in-slot slot :card {: kind :owner player :open true}}))
(fn remove-children [world card]
(each [num entity (ipairs world)]
(match entity {:parent card} (world.remove num))))
(fn capture [world player card]
(let [slot (. (icollect [_ entity (ipairs world)]
(match entity
{:slot {:owner player :kind card.card.kind :used nil}} entity))
1)]
(set card.in-slot slot)
(set slot.slot.used true))
(move card)
(set card.circuit-x nil)
(set card.circuit-y nil)
(set card.card.open true)
(set card.captured true)
(when card.boosted
(set card.boosted false)
(give-terminal world card.card.owner :line-boost)
(remove-children world card)))
(fn perform-action [world action]
(case action
{:kind :setup : cards : player}
(let [online (get-online-of world player)]
(each [_ {: x : y : kind} (ipairs cards)]
(var found nil)
(each [i {:card {:kind kind*} &as card} (ipairs online)]
(when (and (not found) (= kind kind*))
(set found card)
(table.remove online i)))
(move found)
(set found.circuit-x x)
(set found.circuit-y y))
(var not-set-up false)
(each [_ entity (ipairs world)]
(when (and entity.card (is-online entity.card) (not entity.circuit-x))
(set not-set-up true)))
(if (not not-set-up)
(set world.phase.kind :turn)))
{: from-x : from-y : to-x : to-y : player}
(let [card (online-at world player from-x from-y)]
(assert card)
(each [_ other (ipairs (get-cards-on world to-x to-y))]
(when (and (is-online other.card) (not= other.card.owner card.owner))
(capture world player other)))
(move card)
(set card.circuit-x to-x)
(set card.circuit-y to-y))
{:kind :fire-wall : x : y : player}
(do
(var found-id nil)
(var card nil)
(each [id entity (ipairs world)]
(match entity {:card {:owner player :kind :fire-wall}} (do
(set found-id id)
(set card entity))))
(world.remove found-id)
(set card.in-slot.slot.used nil)
(let [cell (get-cell world x y)]
(set cell.cell.fire-walled player)))
{:kind :virus-check : x : y : player}
(do
(var to-reveal nil)
(each [_ card (ipairs (get-cards-on world x y))]
(when (is-online card.card)
(set to-reveal card)))
(set to-reveal.card.open true)
(each [id card (ipairs world)]
(match card {:card {:kind :virus-check :owner player}} (world.remove id))))
{:kind :line-boost : x : y : player}
(do
(var to-boost nil)
(each [_ card (ipairs (get-cards-on world x y))]
(when (is-online card.card)
(set to-boost card)))
(set to-boost.boosted true)
(table.insert world {:particles (fcollect [i 1 (* math.pi 3) (/ math.pi 5)]
{:x (* (math.sin i) 8)
:y (* (math.cos i) 8)
:dir [0 0]
:angle (+ i (/ math.pi 2))
:torque 0.07})
:parent to-boost})
(each [id card (ipairs world)]
(match card {:card {:kind :line-boost :owner player}} (world.remove id))))
{:kind :remove-line-boost : player}
(do
(each [_ entity (ipairs world)]
(match entity {:boosted true :card {:owner player}} (do
(set entity.boosted false)
(remove-children world entity))))
(give-terminal world player :line-boost))
{:kind :remove-fire-wall : player : x : y}
(do
(each [_ entity (ipairs world)]
(match entity
{:cell {:fire-walled player} :circuit-x x :circuit-y y}
(set entity.cell.fire-walled nil)))
(give-terminal world player :fire-wall))
{:kind :infiltrate : x : y : player}
(do
(capture world player (. (icollect [_ card (ipairs (get-cards-on world x
y))]
(when (and (is-online card.card)
(= card.card.owner player))
card)) 1)))
{:kind :404 : xa : ya : xb : yb : player}
(do
(let [a (online-at world player xa ya)
b (online-at world player xb yb)
a-kind a.card.kind]
(var card nil)
(each [id entity (ipairs world)]
(match entity {:card {:owner player :kind :404}} (set card id)))
(world.remove card)
(set a.move {:from-x b.x :from-y b.y :start (_G.time)})
(set b.move {:from-x a.x :from-y a.y :start (_G.time)})
(set a.card.kind b.card.kind)
(set b.card.kind a-kind)))
other
(error (.. "Invalid action: " (view other))))
(set world.last-action action)
(set world.phase
{:kind world.phase.kind
:player (+ (% world.phase.player (length world.players)) 1)}))
{: perform-action}