; SPDX-FileCopyrightText: 2023 Jummit
;
; SPDX-License-Identifier: GPL-3.0-or-later
(local {: new-world} (require :world))
(local {: draw-cards} (require :cards))
(local {: draw-portraits} (require :portraits))
(local {: update-particles : draw-particles} (require :particles))
(local {: select-with-mouse : perform-select} (require :select))
(local {: make-circuit-mat : make-slots : make-decks} (require :match.make))
(local {: arrange-on-circuit-mat
: draw-cells
: draw-highlighted-cells
: draw-slots
: draw-game-over
: arrange-in-slots
: draw-speech-bubbles} (require :match.draw))
(local {: perform-action} (require :match.action))
(local {: animate-movement} (require :move))
(local {: player-turn : player-setup} (require :match.player))
(local {: get-start-cells-for} (require :match.info))
(local {: make-state} (require :match.state))
(local {: decay} (require :decay))
(fn move-to-parent [world]
"Sets the x and y coordinates of entities to their parent."
(each [_ entity (ipairs world)]
(case entity
{: parent}
(do
(set entity.x (+ (or parent.screen-x parent.x) 2))
(set entity.y (+ (or parent.screen-y parent.y) 3))))))
(fn say [world message]
(table.insert world {:speech-bubble {:text message :progress 0}
:decay-in (+ (* (length message) 10) 100)
:x 145
:y 58}))
(fn ai-setup [world]
"Makes AIs perform the setup action when it's their turn."
(case world.phase
{:kind :setup : player}
(case (. world.players player)
{: setup : greeting}
(let [scores (icollect [_ {:circuit-x x :circuit-y y} (ipairs (get-start-cells-for world
player))]
{: x : y :score (setup x y)})]
(table.sort scores (fn [a b] (< a.score b.score)))
(var links-left 4)
(say world greeting)
(perform-action world
{:kind :setup
: player
:cards (icollect [_ {: x : y} (ipairs scores)]
(do
(set links-left (- links-left 1))
{:kind (if (<= 0 links-left) :link :virus)
: x
: y}))})))))
(fn ai-turn [world]
"Makes AIs perform an action when it's their turn."
(case world.phase
{:kind :turn : player}
(case (. world.players player)
{: turn : commentate : reply}
(do
(set world.phase.wait-time (+ (or world.phase.wait-time 0) 1))
(when (< 15 world.phase.wait-time)
(set world.phase.wait-time nil)
(let [state (make-state world player)
move (turn state world.last-action)]
(set move.player player)
(perform-action world move)
(-?>> (or (reply state world.last-action) (commentate state move))
(say world))))))))
(fn end-game [world]
"System which ends the game if a player won."
(when (not= world.phase.kind :game-over)
(var won nil)
(each [id player (ipairs world.players)]
(var links
(length (icollect [_ entity (ipairs world)]
(match entity
{:slot {:owner id :kind :link :used true}} true))))
(var virus
(length (icollect [_ entity (ipairs world)]
(match entity
{:slot {:owner id :kind :virus :used true}} true))))
(when (= 4 links)
(set won player))
(when (= 4 virus)
(set won (. (icollect [_ other (ipairs world.players)]
(when (not= other player) other)) 1))))
(when won
(_G.music 3)
(each [_ player (ipairs world.players)]
(case player
{: won-message : lost-message}
(say world (if (= player won) won-message lost-message))))
(set world.phase {:kind :game-over : won}))))
(fn continue [world]
"System which goes to the title screen after the game is over."
(when (= world.phase.kind :game-over)
(let [(_ _ down) (_G.mouse)]
(set world.phase.elapsed (+ (or world.phase.elapsed 0) 1))
(when (and (< 100 world.phase.elapsed) down)
(local {: new-title-screen} (require :title_screen))
(set world.next (new-title-screen))))))
(fn debug-setup-player [world opponent]
(set world.players [(opponent.ai) (opponent.ai)])
(set world.phase {:kind :setup :player 1})
(world.run)
(world.run)
(set world.players [(opponent.ai) :player])
(each [_ entity (ipairs world)]
(case entity
{:card {: owner}}
(when (= (. world.players owner) :player)
(set entity.card.open true)))))
(fn new-match [opponent]
"Returns a world containing a match against the given opponent."
(_G.music 2)
(local entities [{:portrait opponent :x 195 :y 22}])
(make-slots entities)
(make-circuit-mat entities)
(make-decks entities)
(local world (new-world [(fn [] (_G.cls 0))
move-to-parent
ai-setup
player-setup
ai-turn
player-turn
arrange-on-circuit-mat
arrange-in-slots
animate-movement
update-particles
draw-cells
draw-slots
draw-cards
draw-highlighted-cells
draw-particles
draw-game-over
draw-portraits
draw-speech-bubbles
select-with-mouse
perform-select
decay
end-game
continue] entities))
(set world.players [(opponent.ai) :player])
(set world.phase {:kind :setup :player 1})
(debug-setup-player world opponent)
world)
{: new-match}