(include "game.ddh")
(include "menu.ddh")

(def extern int numberOfPlayers)
(def extern int startingPlayer)
(def extern int guide)

# game phases
(def int PHASE_INIT 0)
(def int PHASE_PLAN 1)
(def int PHASE_EXECUTION 2)
(def int PHASE_END 3)

# cards
(def int CARD_SINGLE_STEP 0)
(def int CARD_THREE_STEPS 1)
(def int CARD_TRADE 2)
(def int CARD_CONDITIONAL 3)
(def int CARD_REPLACE 4)
(def int CARD_GRAB 5)
(def int CARD_GRAB_GENERIC 6)
(def int CARD_APPROACH 7)
(def int CARD_WIN 8)
(def int CARD_ROSE 9)
(def int CARD_TUT_1 10)

# actions
(def int ACTION_DELAY 0)
(def int ACTION_ADVANCE_ROSE 2)
(def int ACTION_DRAW_CARD 3)
(def int ACTION_SELECT_CARD 4)
(def int ACTION_PLAN_CARD 5)
(def int ACTION_SET_ACTIVE_PLAYER 6)
(def int ACTION_REVEAL_PLANNED_CARD 7)
(def int ACTION_EXECUTE_PLANNED_CARD 8)
(def int ACTION_DISCARD_PLANNED_CARD 9)
(def int ACTION_CHANGE_PHASE 10)
(def int ACTION_GIVE_CARD 11)
(def int ACTION_HIDE_CARD 12)
(def int ACTION_GRAB_ROSE 13)
(def int ACTION_DISCARD_CARD 14)
(def int ACTION_DISCARD_TO_DECK 15)
(def int ACTION_WIN_CONDITION 16)

(def extern ref dd_meshColour newCardMesh)
(def extern ref Card newCard)
(class_function world_game void create (group)
	(group

	(= this.victoriousPlayer -1)

	# game phases text
	(= this.phaseText "setting up the table")

	# game actions init
	(= this.actionsTotal 0)
	(= this.injectActionsTotal 0)

	# font
	(this.font.setAlign DD_STRING3D_ALIGN_CENTER)
	(this.font.setColorFront 0.9 0.9 0.9)
	(this.font.setColorBack 0.3 0.3 0.3)

	# card font
	(this.cardFont.setAlign DD_STRING3D_ALIGN_CENTER)
	(this.cardFont.setColorFront 0.0 0.0 0.0)
	(this.cardFont.setColorBack 0.0 0.0 0.0)

	# camera control
	(= this.rotX 0)
	(= this.rotY -15)
	(= this.targetRotX 0)
	(= this.targetRotY -15)
	(= this.holdRotX -1)
	(= this.holdRotY -1)

	# looking at mesh
	(this.lookat.load (asset "assets/looking_at.asset" DD_PLY))

	# center of world
	(dd_matrix_identity this.matCenter)
	(dd_matrix_translate this.matCenter 0 -4 -5)

	# stage
	(this.stage.load (asset "assets/stage_2.asset" DD_PLY))
	(this.table.load (asset "assets/table_1.asset" DD_PLY))
	(this.tableArrow.load (asset "assets/table_arrow.asset" DD_PLY))
	(this.tableArrowDecoration.load (asset "assets/table_arrow_decoration.asset" DD_PLY))

	# card back
	(this.cardBack.load (asset "assets/card_border.asset" DD_PLY))
	(this.cardBack.loadTexture (asset "assets/card_border_texture.asset" DD_PLY))

	# card cardFront
	(this.cardFront[0].load (asset "assets/card.asset" DD_PLY))
	(this.cardFront[0].loadTexture (asset "assets/card_single_step.asset" DD_PLY))

	(this.cardFront[1].load (asset "assets/card.asset" DD_PLY))
	(this.cardFront[1].loadTexture (asset "assets/card_triple_step.asset" DD_PLY))

	(this.cardFront[2].load (asset "assets/card.asset" DD_PLY))
	(this.cardFront[2].loadTexture (asset "assets/card_trade.asset" DD_PLY))

	(this.cardFront[3].load (asset "assets/card.asset" DD_PLY))
	(this.cardFront[3].loadTexture (asset "assets/card_one_step_cond.asset" DD_PLY))

	(this.cardFront[4].load (asset "assets/card.asset" DD_PLY))
	(this.cardFront[4].loadTexture (asset "assets/card_replace.asset" DD_PLY))

	(this.cardFront[5].load (asset "assets/card.asset" DD_PLY))
	(this.cardFront[5].loadTexture (asset "assets/card_grab.asset" DD_PLY))

	(this.cardFront[6].load (asset "assets/card.asset" DD_PLY))
	(this.cardFront[6].loadTexture (asset "assets/card_grab_gen.asset" DD_PLY))

	(this.cardFront[7].load (asset "assets/card.asset" DD_PLY))
	(this.cardFront[7].loadTexture (asset "assets/card_approach.asset" DD_PLY))

	(this.cardFront[8].load (asset "assets/card.asset" DD_PLY))
	(this.cardFront[8].loadTexture (asset "assets/card_win.asset" DD_PLY))

	(this.cardFront[9].load (asset "assets/card.asset" DD_PLY))
	(this.cardFront[9].loadTexture (asset "assets/card_tutorial.asset" DD_PLY))

	# cards
	#(= this.cardsTotal 48)
	(= this.cardsTotal 36)
	(for (def int i 0) (< i this.cardsTotal) (= i (+ i 1))
		(group
		#(def int index (dd_math_rand 5))
		#(= this.cards[i].mesh this.cardFront[index])
		#(= this.cards[i].font this.font)
		(= this.cards[i].hidden 1)
		(= this.cards[i].font this.cardFont)
		(= this.cards[i].meshBack this.cardBack)
		(dd_matrix_identity this.cards[i])
		)
	)

	# single steps
	(for (def int i 0) (< i 5) (= i (+ i 1))
		(group
		(this.cards[i].setId CARD_SINGLE_STEP)
		(= this.cards[i].mesh this.cardFront[CARD_SINGLE_STEP])
		)
	)

	# triple steps
	(for (def int i 5) (< i (+ 5 4)) (= i (+ i 1))
		(group
		(this.cards[i].setId CARD_THREE_STEPS)
		(= this.cards[i].mesh this.cardFront[CARD_THREE_STEPS])
		)
	)

	# trade
	(for (def int i 9) (< i (+ 9 3)) (= i (+ i 1))
		(group
		(this.cards[i].setId CARD_TRADE)
		(= this.cards[i].mesh this.cardFront[CARD_TRADE])
		)
	)

	# conditional
	(for (def int i 12) (< i (+ 12 5)) (= i (+ i 1))
		(group
		(this.cards[i].setId CARD_CONDITIONAL)
		(= this.cards[i].mesh this.cardFront[CARD_CONDITIONAL])
		)
	)

	# replace
	(for (def int i 17) (< i (+ 17 3)) (= i (+ i 1))
		(group
		(this.cards[i].setId CARD_REPLACE)
		(= this.cards[i].mesh this.cardFront[CARD_REPLACE])
		)
	)

	# grab
	(for (def int i 20) (< i (+ 20 4)) (= i (+ i 1))
		(group
		(this.cards[i].setId CARD_GRAB)
		(= this.cards[i].mesh this.cardFront[CARD_GRAB])
		)
	)

	# grab gen
	(for (def int i 24) (< i (+ 24 5)) (= i (+ i 1))
		(group
		(this.cards[i].setId CARD_GRAB_GENERIC)
		(= this.cards[i].mesh this.cardFront[CARD_GRAB_GENERIC])
		)
	)

	# approach
	(for (def int i 29) (< i (+ 29 3)) (= i (+ i 1))
		(group
		(this.cards[i].setId CARD_APPROACH)
		(= this.cards[i].mesh this.cardFront[CARD_APPROACH])
		)
	)

	# win
	(for (def int i 32) (< i (+ 32 4)) (= i (+ i 1))
		(group
		(this.cards[i].setId CARD_WIN)
		(= this.cards[i].mesh this.cardFront[CARD_WIN])
		)
	)

#	# all set debug
#	(for (def int i 0) (< i 36) (= i (+ i 1))
#		(group
#		(= this.cards[i].id CARD_TRADE)
#		(= this.cards[i].mesh this.cardFront[CARD_TRADE])
#		)
#	)

	# tut cards
	(= this.guide guide)
	(= this.tutCardsTotal 10)
	(for (def int i 0) (< i this.tutCardsTotal) (= i (+ i 1))
		(group
		(= this.tutCards[i].hidden 0)
		(this.tutCards[i].setId (+ CARD_TUT_1 i))
		(= this.tutCards[i].mesh this.cardFront[9])
		(= this.tutCards[i].font this.cardFont)
		(= this.tutCards[i].meshBack this.cardBack)
		(dd_matrix_identity this.tutCards[i].target)
		(dd_matrix_translate this.tutCards[i].target -1.75 2.01 2.7)
		(dd_matrix_rotate this.tutCards[i].target -90 1 0 0)
		(dd_matrix_rotate this.tutCards[i].target 55 0 0 1)
		(dd_matrix_copy this.tutCards[i] this.tutCards[i].target)
		)
	)

	# deck
	(dd_matrix_identity this.deckMatrix)
	(dd_matrix_translate this.deckMatrix -0.40 2 0)
	(dd_matrix_rotate this.deckMatrix 90 1 0 0)
	(= this.deckTotal 0)
	(for (def int i 0) (< i this.cardsTotal) (= i (+ i 1))
		(group
		(this.addToDeck this.cards[i])
		(dd_matrix_copy this.cards[i] this.cards[i].target)
		)
	)
	(this.shuffleDeck)

	# discard
	(dd_matrix_identity this.discardMatrix)
	(dd_matrix_translate this.discardMatrix 0.40 2 0)
	(dd_matrix_rotate this.discardMatrix -90 1 0 0)
	(= this.discardTotal 0)

	# players 3-8
	#(= this.playersTotal 4)
	(= this.playersTotal numberOfPlayers)
	(= this.player[0].isUser 1)

	# init player positions
	(for (def int i 1) (< i this.playersTotal) (= i (+ i 1))
		(group

		# rotate players kinda towards user
		(def float angle)
		(= angle (+ 0 (* (/ 360.0 this.playersTotal) i)))
		(= angle (/ (- angle 180) 180.0))
		(= angle (* angle 0.9))
		(= angle (+ (* angle 180) 180))
		(dd_matrix_identity this.player[i])
		(dd_matrix_rotate this.player[i] angle 0 -1 0)
		(dd_matrix_translate this.player[i] 0 0 4)

		(def float offset (* -20 (/ (- 180 angle) 180.0)))
		(dd_matrix_rotate this.player[i] offset 0 1 0)

		(dd_matrix_rotate this.player[i] 180 0 1 0)

		# players actual location
		(dd_matrix_identity this.player[i].actual)
		(dd_matrix_rotate this.player[i].actual (- 0 (* (/ 360.0 this.playersTotal) i)) 0 1 0)
		(dd_matrix_translate this.player[i].actual 0 0 4)
		(dd_matrix_rotate this.player[i].actual 180 0 1 0)

		)
	)

	# user's custom matrices
	(dd_matrix_identity this.player[0])
	(dd_matrix_translate this.player[0] 0 0 5)

	(dd_matrix_identity this.player[0].actual)
	(dd_matrix_translate this.player[0].actual 0 0 5)

	(dd_matrix_identity this.player[0].selectedMatrix)
	(dd_matrix_translate this.player[0].selectedMatrix 0 2.01 -3.6)
	(dd_matrix_rotate this.player[0].selectedMatrix 90 1 0 0)
	(dd_matrix_rotate this.player[0].selectedMatrix 180 0 0 1)

	# temp rotating card
	(= this.rotating 0)

	# rose player
	(= this.isRoseFlat 1)
	(this.roseCardMesh.load (asset "assets/card.asset" DD_PLY))
	(this.roseCardMesh.loadTexture (asset "assets/rose.asset" DD_PLY))
	(this.roseCard.setId CARD_ROSE)
	(= this.roseCard.mesh this.roseCardMesh)
	(= this.roseCard.meshBack this.cardBack)

	# begin the game
	(this.addAction ACTION_CHANGE_PHASE 0 PHASE_INIT 50)

	(this.arrowProgramAvdl.setVertexShader
		(multistring
			"AVDL_IN vec4 position;\n"
			"AVDL_IN vec3 colour;\n"

			"uniform mat4 matrix;\n"
			"uniform vec3 tint;\n"

			"AVDL_OUT vec4 outColour;\n"

			"void main() {\n"
			"	vec4 pos = matrix *position;\n"
			"       gl_Position = pos;\n"
			"       outColour = vec4(colour.rgb *tint.rgb, 1.0);\n"
			"}\n"
		)
	)
	(this.arrowProgramAvdl.setFragmentShader
		(multistring
			"AVDL_IN vec4 outColour;\n"

			"void main() {\n"
			"       avdl_frag_color = outColour;\n"
			"}\n"
		)
	)

	(= this.arrowActiveCol[0] 0.403)
	(= this.arrowActiveCol[1] 0.698)
	(= this.arrowActiveCol[2] 0.349)

	(= this.arrowInactiveCol[0] 0.694)
	(= this.arrowInactiveCol[1] 0.137)
	(= this.arrowInactiveCol[2] 0.137)

	(= this.arrowCurrentCol[0] 0.0)
	(= this.arrowCurrentCol[1] 0.0)
	(= this.arrowCurrentCol[2] 0.0)

	)
)

(class_function world_game void onload (group)
	(group
	)
)

#(class_function world_game void resize (group)
#	(group
#	)
#)

(class_function world_game void update (group)
	(group

	# currently displaying a card, handle that instead of game state
	(if this.ovButtons.cardToShow
		(this.ovButtons.lookAt this.rotX this.rotY)
	)

	# execute remaining actions
	(if (&& (> this.actionsTotal 0) (== this.ovButtons.cardToShow 0))
		(group

		# delay after executing an action
		(if (== this.actions[0].actionType ACTION_DELAY)
			(group
			(if (> this.actions[0].delay 0)
				(= this.actions[0].delay (- this.actions[0].delay 1))
				(this.removeAction)
			)
			)
		# change phases
		(== this.actions[0].actionType ACTION_CHANGE_PHASE)
			(group

			# initialise phase
			(if (== this.actions[0].value PHASE_INIT)
				(group
				(= this.phaseText "initialising game")

				# decide starting player
				(if (== startingPlayer -1)
					(= startingPlayer (dd_math_rand this.playersTotal))
				)
				(this.setRosePlayer startingPlayer)
				(dd_matrix_copy this.roseCard this.roseCard.target)

				# all players draw starting cards
				(for (def int j 0) (< j 5) (= j (+ j 1))
				(for (def int i 0) (< i this.playersTotal) (= i (+ i 1))
					(this.addAction ACTION_DRAW_CARD i 0 5)
				)
				)

				# start with planning phase
				(this.addAction ACTION_CHANGE_PHASE 0 PHASE_PLAN 50)

				# guide
				(if (== this.guide 0)
					(group
					(this.ovButtons.setCard this.tutCards[0])
					(= this.guide (+ this.guide 1))
					)
				)
				#(this.ovButtons.setCard this.deck[0])

				)
			# planning phase
			(== this.actions[0].value PHASE_PLAN)
				(group
				(= this.phaseText "planning phase")

				# ask all players to plan a card
				(for (def int i this.rosePlayer) (< i (+ this.playersTotal this.rosePlayer)) (= i (+ i 1))
					(group
					(def int index (% i this.playersTotal))
					(this.addAction ACTION_SET_ACTIVE_PLAYER index 0 20)
					(this.addAction ACTION_SELECT_CARD index 0 0)
					(this.addAction ACTION_PLAN_CARD -1 0 50)
					)
				)

				# when done, move to execution phase
				(this.addAction ACTION_CHANGE_PHASE 0 PHASE_EXECUTION 50)

				(if (== this.guide 1)
					(group
					(this.ovButtons.setCard this.tutCards[1])
					(= this.guide (+ this.guide 1))
					)
				)

				)
			# execution phase
			(== this.actions[0].value PHASE_EXECUTION)
				(group
				(= this.phaseText "execution phase")

				# reveal all planned cards, and execute their actions
				(for (def int i this.rosePlayer) (< i (+ this.playersTotal this.rosePlayer)) (= i (+ i 1))
					(group
					(def int index (% i this.playersTotal))
					(this.addAction ACTION_SET_ACTIVE_PLAYER index 0 20)
					(this.addAction ACTION_REVEAL_PLANNED_CARD index 0 50)
					(this.addAction ACTION_EXECUTE_PLANNED_CARD index 0 50)
					(this.addAction ACTION_DISCARD_PLANNED_CARD index 0 50)
					)
				)

				# when done, move to end phase
				(this.addAction ACTION_CHANGE_PHASE 0 PHASE_END 50)

				(if (== this.guide 3)
					(group
					(this.ovButtons.setCard this.tutCards[3])
					(= this.guide (+ this.guide 1))
					)
				)

				)
			# end phase
			(== this.actions[0].value PHASE_END)
				(group
				(= this.phaseText "end phase")

				# all players, apart from the rose player, draw a card
				(for (def int i (+ this.rosePlayer 1)) (< i (+ this.playersTotal this.rosePlayer)) (= i (+ i 1))
					(group
					(def int index (% i this.playersTotal))
					(this.addAction ACTION_DRAW_CARD index 0 5)
					)
				)

				# if held, flat rose
				(if (== this.isRoseFlat 0)
					(this.addAction ACTION_ADVANCE_ROSE 0 1 5)
				)

				# check for victory condition
				(this.addAction ACTION_WIN_CONDITION 0 0 0)

				# when done, restart planning phase
				(this.addAction ACTION_CHANGE_PHASE 0 PHASE_PLAN 50)

				(if (== this.guide 4)
					(group
					(this.ovButtons.setCard this.tutCards[4])
					(= this.guide (+ this.guide 1))
					)
				)

				)
			# error phase (should never trigger)
				(group
				(= this.phaseText "error phase")
				)
			)

			(= this.actions[0].actionType ACTION_DELAY)

			)
		# advance rose to next player
		(== this.actions[0].actionType ACTION_ADVANCE_ROSE)
			(group

			# rose is held by someone, flat it and lose one movement
			(if (== this.isRoseFlat 0)
				(group

				(= this.isRoseFlat 1)
				(= this.actions[0].value (- this.actions[0].value 1))

				# find the rose
				(def int roseIndex -1)
				(for (def int i 0) (< i this.player[this.rosePlayer].cardsTotal) (= i (+ i 1))
					(group
					(if (== this.player[this.rosePlayer].cards[i].id CARD_ROSE)
						(group
						(= roseIndex i)
						(= i 100)
						)
					)
					)
				)

				# should never happen
				(if (== roseIndex -1)
					(echo "rose is not held by rose player ?")
				# flat the rose
					(group
					(this.player[this.rosePlayer].removeCard roseIndex)
					(this.setRosePlayer this.rosePlayer)
					)
				)

				)
			)

			# there is movement left, move the rose
			(if (> this.actions[0].value 0)
				(group
				(this.setRosePlayer (% (+ this.rosePlayer this.actions[0].value) this.playersTotal))
				)
			)

			(= this.actions[0].actionType ACTION_DELAY)

			)
		# draw card
		(== this.actions[0].actionType ACTION_DRAW_CARD)
			(group
			(this.drawCard this.actions[0].playerIndex)
			(= this.actions[0].actionType ACTION_DELAY)
			)
		# select a card
		(== this.actions[0].actionType ACTION_SELECT_CARD)
			(group

			# invalid player has to select a card? (shouldn't happen)
			(if (|| (< this.actions[0].playerIndex 0) (>= this.actions[0].playerIndex this.playersTotal))
				(echo "invalid player cannot select a card")
			# user has to select a card
			(&& (== this.actions[0].playerIndex 0) (== this.actions[0].value 0))
				(group
				(if (== this.guide 2)
					(group
					(this.ovButtons.setCard this.tutCards[2])
					(= this.guide (+ this.guide 1))
					)
				)
				)
			# AI has to select a card or user selects randomly
				(group
				(= this.lastSelectedCardPlayerIndex this.actions[0].playerIndex)
				(= this.lastSelectedCardIndex (dd_math_rand this.player[this.lastSelectedCardPlayerIndex].cardsTotal))
				(= this.actions[0].actionType ACTION_DELAY)
				#(this.player[this.actions[0].playerIndex].selectCard)
				)
			)

			)
		# plan card
		(== this.actions[0].actionType ACTION_PLAN_CARD)
			(group

			# player index is given as -1, use last selected card/player combo
			(if (== this.actions[0].playerIndex -1)
				(group

				# player tried to plan the rose! blasphemy! select another card
				(if (== this.player[this.lastSelectedCardPlayerIndex].cards[this.lastSelectedCardIndex].id CARD_ROSE)
					(group
					(this.addInjectAction ACTION_SELECT_CARD this.lastSelectedCardPlayerIndex 0 0)
					(this.addInjectAction ACTION_PLAN_CARD -1 0 50)
					(this.injectActionsToActions)
					)
				# player tried to plan the "replace" card, while being last, select another card
				(&&
					(== this.player[this.lastSelectedCardPlayerIndex].cards[this.lastSelectedCardIndex].id CARD_REPLACE)
					(== (% (+ this.rosePlayer this.playersTotal -1) this.playersTotal) this.lastSelectedCardPlayerIndex)
				)
					(group
					(this.addInjectAction ACTION_SELECT_CARD this.lastSelectedCardPlayerIndex 0 0)
					(this.addInjectAction ACTION_PLAN_CARD -1 0 50)
					(this.injectActionsToActions)
					)
				# selected card can be planned, so plan it
					(this.player[this.lastSelectedCardPlayerIndex].planCard this.lastSelectedCardIndex)
				)

				)
			# player and card index are given, use those instead
				(group
				(this.player[this.actions[0].playerIndex].planCard this.actions[0].value)
				)
			)

			(= this.actions[0].actionType ACTION_DELAY)
			)
		# set active player
		(== this.actions[0].actionType ACTION_SET_ACTIVE_PLAYER)
			(group
			(this.applyArrowRotation this.actions[0].playerIndex)
			(= this.actions[0].actionType ACTION_DELAY)
			)
		# reveal planned card
		(== this.actions[0].actionType ACTION_REVEAL_PLANNED_CARD)
			(group
			(def int playerIndex this.actions[0].playerIndex)
			(= this.player[playerIndex].selectedCard2.hidden 0)
			(dd_matrix_rotate this.player[playerIndex].selectedCard2.target 180 0 1 0)
			(= this.actions[0].actionType ACTION_DELAY)

			(this.ovButtons.setCard this.player[playerIndex].selectedCard2)
			)
		# execute planned card
		(== this.actions[0].actionType ACTION_EXECUTE_PLANNED_CARD)
			(group

			(def int cardId this.player[this.actions[0].playerIndex].selectedCard2.id)

			# based on the card being executed, inject it's actions in the stack

			# move rose one step
			(if (== cardId CARD_SINGLE_STEP)
				(group
				(this.addInjectAction ACTION_ADVANCE_ROSE 0 1 50)
				(this.injectActionsToActions)
				)
			# move rose three steps
			(== cardId CARD_THREE_STEPS)
				(group
				(this.addInjectAction ACTION_ADVANCE_ROSE 0 1 20)
				(this.addInjectAction ACTION_ADVANCE_ROSE 0 1 20)
				(this.addInjectAction ACTION_ADVANCE_ROSE 0 1 20)
				(this.injectActionsToActions)
				)
			# trade - give 1 card to rose player, take 1 card back
			(== cardId CARD_TRADE)
				(group

				(if (== this.rosePlayer this.actions[0].playerIndex)
					(group
					)
					(group

					# rose player picks up rose
					(if this.isRoseFlat
						(this.addInjectAction ACTION_GRAB_ROSE 0 0 50)
					)

					# active player selects and gives a card to rose player
					(this.addInjectAction ACTION_SELECT_CARD this.actions[0].playerIndex 0 0)
					(this.addInjectAction ACTION_GIVE_CARD this.rosePlayer 0 50)

					# rose player selects and gives a card to active player
					# TODO: should be given a card at random, rose player doesn't select
					(this.addInjectAction ACTION_SELECT_CARD this.rosePlayer -1 0)
					(this.addInjectAction ACTION_GIVE_CARD this.actions[0].playerIndex 0 50)

					# move rose one step
					(this.addInjectAction ACTION_ADVANCE_ROSE 0 1 50)

					(this.injectActionsToActions)

					)
				)

				)
			# If rose is one step before active user, move it one step, otherwise move it three steps
			(== cardId CARD_CONDITIONAL)
				(group
				(def int onePreviousIndex (% (- (+ this.actions[0].playerIndex this.playersTotal) 1) 5))
				(if (== onePreviousIndex this.rosePlayer)
					(group
					(this.addInjectAction ACTION_ADVANCE_ROSE 0 1 50)
					(this.injectActionsToActions)
					)
				# else
					(group
					(this.addInjectAction ACTION_ADVANCE_ROSE 0 1 20)
					(this.addInjectAction ACTION_ADVANCE_ROSE 0 1 20)
					(this.addInjectAction ACTION_ADVANCE_ROSE 0 1 20)
					(this.injectActionsToActions)
					)
				)
				)
			# discard your planned card, draw one card, plan another card and execute it
			(== cardId CARD_REPLACE)
				(group
				(this.addInjectAction ACTION_DISCARD_PLANNED_CARD this.actions[0].playerIndex 0 50)
				(this.addInjectAction ACTION_DRAW_CARD this.actions[0].playerIndex 0 50)
				(this.addInjectAction ACTION_SELECT_CARD this.actions[0].playerIndex 0 0)
				(this.addInjectAction ACTION_PLAN_CARD -1 0 50)
				(this.addInjectAction ACTION_REVEAL_PLANNED_CARD this.actions[0].playerIndex 0 50)
				(this.addInjectAction ACTION_EXECUTE_PLANNED_CARD this.actions[0].playerIndex 0 50)
				(this.injectActionsToActions)
				)
			# grab
			# If rose is in front of you, grab it, otherwise move rose 1 step.
			#	The new rose player grabs the rose.
			(== cardId CARD_GRAB)
				(group

				# rose is in front of user, grab it
				(if (== this.actions[0].playerIndex this.rosePlayer)
					(group
					(this.addInjectAction ACTION_GRAB_ROSE 0 0 50)
					(this.injectActionsToActions)
					)
				# otherwise, move one step, rose player grabs rose
					(group
					(this.addInjectAction ACTION_ADVANCE_ROSE 0 1 50)
					(this.addInjectAction ACTION_GRAB_ROSE 0 0 50)
					(this.injectActionsToActions)
					)
				)

				)
			# grab generic
			# If rose is flat, the player in front of it grabs it.
			(== cardId CARD_GRAB_GENERIC)
				(group

				(this.addInjectAction ACTION_GRAB_ROSE 0 0 50)
				(this.injectActionsToActions)

				)
			# aproach
			# If you are not the rose player, move rose 1 step, otherwise move it 3 steps.
			(== cardId CARD_APPROACH)
				(group

				# active user is rose player, move rose 3 steps
				(if (== this.actions[0].playerIndex this.rosePlayer)
					(group
					(this.addInjectAction ACTION_ADVANCE_ROSE 0 1 20)
					(this.addInjectAction ACTION_ADVANCE_ROSE 0 1 20)
					(this.addInjectAction ACTION_ADVANCE_ROSE 0 1 20)
					(this.injectActionsToActions)
					)
				# active user is not rose player, move rose 1 step
					(group
					(this.addInjectAction ACTION_ADVANCE_ROSE 0 1 50)
					(this.injectActionsToActions)
					)
				)

				)
			# win
			# If you are holding the rose, discard 1 card. Move rose 1 step.
			(== cardId CARD_WIN)
				(group

				# holding the rose, discard 1 card
				(if (&& (== this.actions[0].playerIndex this.rosePlayer) (== this.isRoseFlat 0))
					(group
					(this.addInjectAction ACTION_SELECT_CARD this.actions[0].playerIndex 0 50)
					)
				)

				(this.addInjectAction ACTION_ADVANCE_ROSE 0 1 50)
				(this.injectActionsToActions)

				)
			)

			(= this.actions[0].actionType ACTION_DELAY)
			)
		# discard planned card
		(== this.actions[0].actionType ACTION_DISCARD_PLANNED_CARD)
			(group
			(def int playerIndex this.actions[0].playerIndex)

			(this.addToDiscard this.player[playerIndex].selectedCard2)
			(this.player[playerIndex].deselectCard)

			(= this.actions[0].actionType ACTION_DELAY)

			)
		# give card to another player
		(== this.actions[0].actionType ACTION_GIVE_CARD)
			(group

			(def int receiverIndex this.actions[0].playerIndex)

			# user is receiving a card, reveal it straight away
			(if (== receiverIndex 0)
				(= this.player[this.lastSelectedCardPlayerIndex].cards[this.lastSelectedCardIndex].hidden 0)
			)

			# rose is being given
			(if (== this.player[this.lastSelectedCardPlayerIndex].cards[this.lastSelectedCardIndex].id CARD_ROSE)
				(= this.rosePlayer receiverIndex)
			# user is giving a non-rose card, mark it to become hidden when arriving at opponent
			(== this.lastSelectedCardPlayerIndex 0)
				(group
				(this.addInjectAction ACTION_HIDE_CARD receiverIndex this.player[receiverIndex].cardsTotal 0)
				(this.injectActionsToActions)
				)
			)

			(this.player[receiverIndex].addCard this.player[this.lastSelectedCardPlayerIndex].cards[this.lastSelectedCardIndex])
			(this.player[this.lastSelectedCardPlayerIndex].removeCard this.lastSelectedCardIndex)
			(= this.actions[0].actionType ACTION_DELAY)

			)

		# hide given card
		(== this.actions[0].actionType ACTION_HIDE_CARD)
			(group
			(= this.player[this.actions[0].playerIndex].cards[this.actions[0].value].hidden 1)
			(= this.actions[0].actionType ACTION_DELAY)
			)

		# the rose player, grabs the rose
		(== this.actions[0].actionType ACTION_GRAB_ROSE)
			(group

			(if this.isRoseFlat
				(this.grabRose)
			)

			(= this.actions[0].actionType ACTION_DELAY)

			)

		# discard card from player's hand
		(== this.actions[0].actionType ACTION_DISCARD_CARD)
			(group

			(def int playerIndex)
			(def int cardIndex)
			# discard previously selected card
			(if (== this.actions[0].playerIndex -1)
				(group
				(= playerIndex this.lastSelectedCardPlayerIndex)
				(= cardIndex this.lastSelectedCardIndex)
				)
			# discard given card
				(group
				(= playerIndex this.actions[0].playerIndex)
				(= cardIndex this.actions[0].value)
				)
			)

			# attempting to discard rose, flat it instead
			(if (== this.player[playerIndex].cards[cardIndex].id CARD_ROSE)
				(group
				(this.addInjectAction ACTION_ADVANCE_ROSE 0 1 50)
				(this.injectActionsToActions)
				)
			# discard selected card
				(group
				(= this.player[playerIndex].cards[cardIndex].hidden 0)
				(this.addToDiscard this.player[playerIndex].cards[cardIndex])
				(this.player[playerIndex].removeCard cardIndex)
				)
			)

			(= this.actions[0].actionType ACTION_DELAY)

			)

		# put discard pile to deck
		(== this.actions[0].actionType ACTION_DISCARD_TO_DECK)
			(group

			# there are still discarded cards
			(if (> this.discardTotal 0)
				(group

				# delay between each card
				(= this.actions[0].value (- this.actions[0].value 1))

				# put next discarded card to deck
				(if (<= this.actions[0].value 0)
					(group
					(def int disIndex (- this.discardTotal 1))
					(this.addToDeck this.discard[disIndex])
					(= this.discard[disIndex] 0)
					(= this.discardTotal (- this.discardTotal 1))
					(= this.actions[0].value this.actions[0].delay)
					)
				)
				)
			# no cards left in discard pile - move to next part
				(group
				(this.shuffleDeck)
				(= this.actions[0].actionType ACTION_DELAY)
				)
			)

			) # discard pile to deck

		# win condition
		(== this.actions[0].actionType ACTION_WIN_CONDITION)
			(group

			(if (< this.victoriousPlayer 0)
				(group
				(def int winningPlayer -1)

				# a player with 2 cards or less is the winner
				# tie-breaker is whoever is closest to the rose player
				(for (def int i this.rosePlayer) (< i (+ this.rosePlayer this.playersTotal)) (= i (+ i 1))
					(group

					(def int index (% i this.playersTotal))

					# player won
					(if (<= this.player[index].cardsTotal 2)
						(group
						(= winningPlayer index)
						(= i 100)
						)
					)

					)
				)

				# someone won
				(if (>= winningPlayer 0)
					(group
					(= this.victoriousPlayer winningPlayer)
					#(dd_world_prepare world_menu 1.0)
					#(dd_world_ready)
					)
				# nobody won
					(group
					(= this.actions[0].actionType ACTION_DELAY)
					)
				)
				)
			)

			)

		) # different behavior for each action

		)
	)

	(= this.rotating (+ this.rotating 0.05))

	# calculate new camera look at point
	(if (>= this.holdRotX 0)
		(group

		# not rotating yet, check threshold
		(if (== this.isRotating 0)
			(group
			(if (|| (> (dd_math_abs (- (dd_mouse_x) this.holdRotX)) 15)
			        (> (dd_math_abs (- (dd_mouse_y) this.holdRotY)) 15))
				(group
				(= this.isRotating 1)
				(= this.holdRotX (dd_mouse_x))
				(= this.holdRotY (dd_mouse_y))
				)
			)
			)
		# is rotating, keep rotating
			(group
			(= this.targetRotX
				(dd_math_max
					(dd_math_min
						(+ this.targetRotX (* (- (dd_mouse_x) this.holdRotX) 0.25))
						100
					)
					-100
				)
			)
			(= this.targetRotY
				(dd_math_max
					(dd_math_min
						(- this.targetRotY (* (- (dd_mouse_y) this.holdRotY) 0.25))
						70
					)
					-65
				)
			)
			(= this.holdRotX (dd_mouse_x))
			(= this.holdRotY (dd_mouse_y))
			)
		)
		)
	)

	# slowly approach camera look at point
	(= this.rotX (dd_math_ease_linear 0.1 this.rotX this.targetRotX))
	(= this.rotY (dd_math_ease_linear 0.1 this.rotY this.targetRotY))

	#(if this.waitingPlayerCard
		(this.player[0].lookAtCard this.rotX this.rotY)
	#)

	#(def float tempRotX this.rotX)
	#(def float tempRotY this.rotY)
	#(echo "rot: " tempRotX " | " tempRotY)

	# update all cards to approach target
	(for (def int i 0) (< i this.cardsTotal) (= i (+ i 1))
		(group
		(dd_matrix_approach this.cards[i] this.cards[i].target 0.1)
		)
	)
	(dd_matrix_approach this.roseCard this.roseCard.target 0.1)
	(for (def int i 0) (< i this.tutCardsTotal) (= i (+ i 1))
		(dd_matrix_approach this.tutCards[i] this.tutCards[i].target 0.1)
	)

	# update table arrow
	(= this.arrowRotation (dd_math_ease_linear 0.1 this.arrowRotation this.arrowRotationTarget))

	# user is about to play a card
	(if (&& (> this.actionsTotal 0) (== this.actions[0].actionType ACTION_SELECT_CARD) (== this.actions[0].playerIndex 0))
		(group
		(= this.arrowCurrentCol[0] (dd_math_ease_linear 0.1 this.arrowCurrentCol[0] this.arrowActiveCol[0] ))
		(= this.arrowCurrentCol[1] (dd_math_ease_linear 0.1 this.arrowCurrentCol[1] this.arrowActiveCol[1] ))
		(= this.arrowCurrentCol[2] (dd_math_ease_linear 0.1 this.arrowCurrentCol[2] this.arrowActiveCol[2] ))
		)
		(group
		(= this.arrowCurrentCol[0] (dd_math_ease_linear 0.1 this.arrowCurrentCol[0] this.arrowInactiveCol[0] ))
		(= this.arrowCurrentCol[1] (dd_math_ease_linear 0.1 this.arrowCurrentCol[1] this.arrowInactiveCol[1] ))
		(= this.arrowCurrentCol[2] (dd_math_ease_linear 0.1 this.arrowCurrentCol[2] this.arrowInactiveCol[2] ))
		)
	)

	(this.ovButtons.update)

	)
) # update

(class_function world_game void draw (group)
	(group

	(dd_matrix_push)

	# camera
	(dd_rotatef this.rotY -1 0 0)
	(dd_rotatef this.rotX 0 1 0)

	# center of world
	(dd_multMatrixf this.matCenter)

	# stage
	(this.stage.draw)
	(this.table.draw)
	(dd_matrix_push)
	(dd_rotatef this.arrowRotation 0 1 0)
	(this.arrowProgramAvdl.useProgram)
	(def int colLoc)
	(= colLoc (avdl_getUniformLocation this.arrowProgramAvdl "tint"))
	(avdl_setUniform3f colLoc this.arrowCurrentCol[0] this.arrowCurrentCol[1] this.arrowCurrentCol[2])
	(this.tableArrow.draw)
	(avdl_useProgram 0)
	(this.tableArrowDecoration.draw)
	(dd_matrix_pop)

	# draw deck
	(dd_matrix_push)
	(for (def int i 0) (< i this.deckTotal) (= i (+ i 1))
		(group
		(if this.deck[i]
			(this.deck[i].draw)
		)
		)
	)

	# draw tut cards
	(for (def int i 0) (< i this.tutCardsTotal) (= i (+ i 1))
		(group
		(this.tutCards[i].draw)
		)
	)

	# rose is flat, draw it
	# if rose is held, player will draw it
	(if this.isRoseFlat
		(this.roseCard.draw)
	)

	(dd_multMatrixf this.deckMatrix)

	# draw deck number
	(dd_rotatef 180 1 0 0)
	(dd_translatef 0 0 (+ (* 0.003 this.deckTotal) 0.12))
	(dd_rotatef 90 1 0 0)
	(dd_scalef 0.15 0.15 0.15)
	(this.font.drawInt this.deckTotal)
	(dd_matrix_pop)

	# draw discard
	(dd_matrix_push)
	(for (def int i 0) (< i this.discardTotal) (= i (+ i 1))
		(group
		(if this.discard[i]
			(this.discard[i].draw)
		)
		)
	)
	(dd_multMatrixf this.discardMatrix)

	# draw discard number
	(dd_translatef 0 0 (+ (* 0.003 this.discardTotal) 0.12))
	(dd_rotatef 90 1 0 0)
	(dd_scalef 0.15 0.15 0.15)
	(this.font.drawInt this.discardTotal)
	(dd_matrix_pop)

	# draw every player apart from self
	(for (def int i 1) (< i this.playersTotal) (= i (+ i 1))
		(group
		(dd_matrix_push)
		(this.player[i].draw)
		(dd_matrix_pop)
		)
	)

	# draw player
	(dd_matrix_push)
	(this.player[0].draw)
	(dd_matrix_pop)

	(if this.ovButtons.cardToShow
		(this.ovButtons.draw)
	)

	# rotating card
	#(dd_translatef 0 3.5 0)
	#(dd_rotatef this.rotating 0 1 0)
	#(dd_scalef 5.0 5.0 5.0)
	#(this.deck[32].drawRaw)
	#(this.tutCards[0].drawRaw)
	#(this.cardBack.draw)
	#(this.cardFront[1].draw)

	(dd_matrix_pop)

	(glClear GL_DEPTH_BUFFER_BIT)

	# states
	(dd_matrix_push)
	(dd_translatef 0 8 -25)
	# draw end game
	(if (>= this.victoriousPlayer 0)
		(if (== this.victoriousPlayer 0)
			(this.font.drawLimit "You won click anywhere to continue"
				(* (dd_screen_width_get 25) 1.8)
			)
			(this.font.drawLimit "You lost click anywhere to continue"
				(* (dd_screen_width_get 25) 1.8)
			)
		)
	# draw text of overlay card
	this.ovButtons.isLookingAtCard
		(this.font.drawLimit this.ovButtons.cardToShow.cardDescription
			(* (dd_screen_width_get 25) 1.8)
		)
	# player looking card
	(>= this.player[0].userLookingAtCard 0)
		(this.font.drawLimit this.player[0].cards[this.player[0].userLookingAtCard].cardDescription
			(* (dd_screen_width_get 25) 1.8)
		)
	# draw phase
		(this.font.drawLimit this.phaseText
			(* (dd_screen_width_get 25) 1.8)
		)
	)
	(dd_matrix_pop)

	# clear depth
	(glClear GL_DEPTH_BUFFER_BIT)

	# lookat mesh
	(dd_matrix_push)
	(dd_translatef 0 0 -25)
	(this.lookat.draw)
	(dd_matrix_pop)

	(this.player[0].drawLookingAtText)

	)
)

(class_function world_game void key_input (group char key)
	(group
	(if (== key 27)
		(= dd_flag_exit 1) # exit game
	) # key input
	)
)

(class_function world_game void clean (group)
	(group
	)
)

(class_function world_game void mouse_input (group int button int type)
	(group

	# control the camera look at point when click and dragging
	(if (== type DD_INPUT_MOUSE_TYPE_PRESSED)
		(group
		(= this.holdRotX (dd_mouse_x))
		(= this.holdRotY (dd_mouse_y))
		(= this.isRotating 0)
		)
	(== type DD_INPUT_MOUSE_TYPE_RELEASED)
		(group

		(= this.holdRotX -1)
		(= this.holdRotY -1)

		# was not rotating - click
		(if (== this.isRotating 0)
			(group

			# someone has won, move to next menu
			(if (>= this.victoriousPlayer 0)
				(group
				(dd_world_prepare world_menu 1.0)
				(dd_world_ready)
				)
			# showing overlay card
			this.ovButtons.cardToShow
				(group
				(this.ovButtons.click)
				)
			# waiting user to select a card
			(&& (> this.actionsTotal 0) (== this.actions[0].actionType ACTION_SELECT_CARD) (== this.actions[0].playerIndex 0))
				(group

				# just selected a card
				(if (&& (== this.player[0].userLookingAtCard this.player[0].highlightCard)
					(>= this.player[0].highlightCard 0))
					(group

					(= this.lastSelectedCardPlayerIndex 0)
					(= this.lastSelectedCardIndex this.player[0].highlightCard)
					(= this.actions[0].actionType ACTION_DELAY)

					(= this.player[0].userLookingAtCard -1)
					(= this.player[0].highlightCard -1)
					)
				# just highlighted card
					(this.player[0].highlightLookingCard)
				)

				)
			) # was waiting for user input
			)
		)

		)
	) # mouse button released

	)
) # mouse input

#
# call it to make a player draw a card from the deck
# `playerIndex` should be the index of that player
#
(class_function world_game void drawCard (group int playerIndex)
	(group

	# if deck is empty, refill it from discard pile
	# this should happen infinitely, and they should
	# never run out
	(if (&& (<= this.deckTotal 0) (> this.discardTotal 0))
		(group

		# add discard to deck
		# draw 1 card, same player
		(this.addInjectAction ACTION_DISCARD_TO_DECK 0 0 10)
		(this.addInjectAction ACTION_DRAW_CARD playerIndex 0 5)
		(this.injectActionsToActions)

		)
	# check player index validity (shouldn't happen)
	(|| (< playerIndex 0) (>= playerIndex this.playersTotal))
		(echo "INVALID PLAYER ID")
	# not any cards left in deck
	(<= this.deckTotal 0)
		(group

		# deck is empty, and wasn't replenished by discard pile
		(echo "CANNOT DRAW MORE CARDS FROM THE DECK, DISCARD ALSO EMPTY")

		)
	# deck has cards to draw from
		(group

		# get top card
		(def int cardIndex (- this.deckTotal 1))

		# player has too many cards already (should never happen)
		(if (== this.player[playerIndex].cardsTotal 10)
			(echo "CANNOT GIVE MORE CARDS, SKIP")
		# player can handle one more card
			(group

			(this.player[playerIndex].addCard this.deck[cardIndex])

			# if card goes to an opponent, hide it
			(if (> playerIndex 0)
				(= this.deck[cardIndex].hidden 1)
				(= this.deck[cardIndex].hidden 0)
			)

			# remove card from deck
			(= this.deck[cardIndex] 0)
			(= this.deckTotal (- this.deckTotal 1))

			)
		) # player has too many cards

		)
	) #deck has cards to draw from

	)
) # draw card

(class_function world_game void addToDiscard (group Card card)
	(group

	# check limits, should never happen
	(if (>= this.discardTotal 48)
		(echo "Can't add card to discard")
	# add card to discard pile
		(group
		(= this.discard[this.discardTotal] card)
		(= this.discardTotal (+ this.discardTotal 1))
		(dd_matrix_copy card.target this.discardMatrix)
		(dd_matrix_translate card.target 0 0 (+ (* 0.003 (+ this.discardTotal 1)) 0.01))
		)
	)
	)
)

(class_function world_game void addToDeck (group Card card)
	(group

	# check limits, should never happen
	(if (>= this.deckTotal 48)
		(echo "Can't add card to deck")
	# add card to deck
		(group
		(= this.deck[this.deckTotal] card)
		(= this.deckTotal (+ this.deckTotal 1))
		(dd_matrix_copy card.target this.deckMatrix)
		(dd_matrix_translate card.target 0 0 (+ (* -0.003 (+ this.deckTotal 1)) -0.01))
		)
	)
	)
)

(class_function world_game void setRosePlayer (group int playerId)
	(group

	# check playerId sanity
	(if (|| (< playerId 0) (>= playerId this.playersTotal))
		(echo "invalid player id")
	# special functionality for user
	(== playerId 0)
		(group
		(= this.rosePlayer playerId)
		(dd_matrix_identity this.roseCard.target)
		(dd_matrix_translate this.roseCard.target 0 2.01 2.1)
		(dd_matrix_rotate this.roseCard.target -90 1 0 0)
		)
	# position rose in front of another player
		(group
		(= this.rosePlayer playerId)
		(dd_matrix_identity this.roseCard.target)
		(dd_matrix_mult this.roseCard.target this.player[playerId].actual)
		(dd_matrix_translate this.roseCard.target 0 2.01 1.9)
		(dd_matrix_rotate this.roseCard.target -90 1 0 0)
		(dd_matrix_rotate this.roseCard.target 180 0 0 1)
		)
	)

	)
)

# shuffle all cards in the deck
(class_function world_game void shuffleDeck (group)
	(group
	(for (def int i 0) (< i this.deckTotal) (= i (+ i 1))
		(group
		(def int target (dd_math_rand this.deckTotal))
		(def ref Card temp)
		(= temp this.deck[i])
		(= this.deck[i] this.deck[target])
		(= this.deck[target] temp)

		(dd_matrix_copy this.deck[i].target this.deckMatrix)
		(dd_matrix_translate this.deck[i].target 0 0 (+ (* -0.003 (+ i 1)) -0.01))

		(dd_matrix_copy this.deck[target].target this.deckMatrix)
		(dd_matrix_translate this.deck[target].target 0 0 (+ (* -0.003 (+ target 1)) -0.01))
		)
	)
	)
)

(class_function world_game void applyArrowRotation (group int playerIndex)
	(group
	(= this.arrowRotationTarget (- 0 (* (/ 360.0 this.playersTotal) playerIndex)))
	(if (< this.arrowRotation this.arrowRotationTarget)
		(group
		(= this.arrowRotation (+ this.arrowRotation 360))
		)
	)
	)
)

(class_function world_game void applyChooseCard (group int optionIndex)
	(group
	(if (== optionIndex 0)
		(this.setRosePlayer (% (+ this.rosePlayer 1) this.playersTotal))
		(this.setRosePlayer (% (+ this.rosePlayer 3) this.playersTotal))
	)
	)
)

(class_function world_game void addAction (group int actionType int playerIndex int valueAmount int delay)
	(group
	(if (>= this.actionsTotal 100)
		(group
		(echo "Max actions reached, cannot add more")
		)
	# else
		(group
		(this.actions[this.actionsTotal].set actionType playerIndex valueAmount delay)
		(= this.actionsTotal (+ this.actionsTotal 1))
		)
	)
	)
)

(class_function world_game void removeAction (group)
	(group
	(if (<= this.actionsTotal 0)
		(group
		(echo "No actions to remove")
		)
		(group
		(for (def int i 1) (< i this.actionsTotal) (= i (+ i 1))
			(group
			(def int prevIndex (- i 1))
			(this.actions[prevIndex].set this.actions[i].actionType this.actions[i].playerIndex this.actions[i].value this.actions[i].delay)
			)
		)
		)
	)

	(= this.actionsTotal (- this.actionsTotal 1))
	)
)

(class_function world_game void addInjectAction (group int actionType int playerIndex int valueAmount int delay)
	(group
	(if (>= this.injectActionsTotal 100)
		(group
		(echo "Max inject actions reached, cannot add more")
		)
	# else
		(group
		(this.injectActions[this.injectActionsTotal].set actionType playerIndex valueAmount delay)
		(= this.injectActionsTotal (+ this.injectActionsTotal 1))
		)
	)
	)
)

(class_function world_game void injectActionsToActions (group)
	(group
	(if (>= (+ this.injectActionsTotal this.actionsTotal) 100)
		(group
		(echo "Can't inject actions, too many")
		)
	# else
		(group

		# move all current actions towards the end of the array, to make room for injected ones
		# current action remains intact
		(for (def int i (- this.actionsTotal 1)) (> i 0) (= i (- i 1))
			(group
			(def int destIndex (+ i this.injectActionsTotal))
			(this.actions[destIndex].set
				this.actions[i].actionType
				this.actions[i].playerIndex
				this.actions[i].value
				this.actions[i].delay
			)
			)
		)

		# add injected actions in that space
		(for (def int i 0) (< i this.injectActionsTotal) (= i (+ i 1))
			(group
			(def int actIndex (+ i 1))
			(this.actions[actIndex].set
				this.injectActions[i].actionType
				this.injectActions[i].playerIndex
				this.injectActions[i].value
				this.injectActions[i].delay
			)
			)
		)

		# reset injected actions array
		(= this.actionsTotal (+ this.actionsTotal this.injectActionsTotal))
		(= this.injectActionsTotal 0)

		)
	)
	)
)

(class_function world_game void grabRose (group)
	(group

	# rose is flat, grab it!
	(if this.isRoseFlat
		(group
		(= this.isRoseFlat 0)
		(this.player[this.rosePlayer].addCard this.roseCard)
		)
	)

	)
)

# game actions
(class_function GameAction void create (group)
	(group
	(= this.actionType -1)
	(= this.playerIndex -1)
	(= this.value 0)
	)
)

(class_function GameAction void clean (group)
	(group
	)
)

(class_function GameAction void set (group int actionType int playerIndex int valueAmount int delay)
	(group
	(= this.actionType actionType)
	(= this.playerIndex playerIndex)
	(= this.value valueAmount)
	(= this.delay delay)
	)
)
