521 lines
16 KiB
GDScript3
521 lines
16 KiB
GDScript3
|
class_name Player
|
||
|
extends Node2D
|
||
|
|
||
|
signal draft_completed
|
||
|
signal board_attached
|
||
|
|
||
|
enum FSMState {DRAFT, SETUP, MANAGEMENT, WORKER, H_WORKER, SHIFT, H_CLIENT}
|
||
|
enum DraftType {HIRE_WORKER}
|
||
|
|
||
|
@export var roster_positions : Array[Node2D] = []
|
||
|
@export var slot_buttons : Array[Node2D] = []
|
||
|
@export var seconds_to_hide_hand := 2.0
|
||
|
@export var seconds_to_show_hand := 2.0
|
||
|
var money := 0
|
||
|
var payout := 0
|
||
|
var cost := 0
|
||
|
var hire_costs := [40, 50, 60, 70, 80]
|
||
|
var shift_deck : Array[Client] = []
|
||
|
var workers : Array[Worker] = []
|
||
|
var hand : Array[Worker] = []
|
||
|
var active_workers : Array[Worker] = [null, null, null, null, null]
|
||
|
var active_clients : Array[Client] = [null, null, null, null, null]
|
||
|
var poor_discard : Array[Client] = []
|
||
|
var good_discard : Array[Client] = []
|
||
|
var great_discard : Array[Client] = []
|
||
|
var last_fsm_state := FSMState.SETUP
|
||
|
var current_fsm_state := FSMState.SETUP
|
||
|
var draft := DraftType.HIRE_WORKER
|
||
|
var hand_hiding := false
|
||
|
var hand_hidden := false
|
||
|
var hand_hiding_progress := 0.0
|
||
|
var hand_showing := false
|
||
|
var hand_showing_progress := 0.0
|
||
|
var shown_for_draft : Array[Worker] = []
|
||
|
var selected_for_draft : Array[Worker] = []
|
||
|
var draft_limit := 0
|
||
|
var current_client : Client
|
||
|
var selected_worker : Worker
|
||
|
var task_drawn := false
|
||
|
var client_assignment : int = -1
|
||
|
var board : Board = null
|
||
|
var turn_completed = false
|
||
|
var round_completed = false
|
||
|
|
||
|
|
||
|
func _ready() -> void:
|
||
|
#Bug in Godot 4.0.3.stable makes it nessesary to add these manually
|
||
|
roster_positions.append($RosterSection/Position1)
|
||
|
roster_positions.append($RosterSection/Position2)
|
||
|
roster_positions.append($RosterSection/Position3)
|
||
|
roster_positions.append($RosterSection/Position4)
|
||
|
roster_positions.append($RosterSection/Position5)
|
||
|
roster_positions.append($RosterSection/Position6)
|
||
|
roster_positions.append($RosterSection/Position7)
|
||
|
roster_positions.append($RosterSection/Position8)
|
||
|
roster_positions.append($RosterSection/Position9)
|
||
|
roster_positions.append($RosterSection/Position10)
|
||
|
roster_positions.append($RosterSection/Position11)
|
||
|
roster_positions.append($RosterSection/Position12)
|
||
|
roster_positions.append($RosterSection/Position13)
|
||
|
roster_positions.append($RosterSection/Position14)
|
||
|
roster_positions.append($RosterSection/Position15)
|
||
|
slot_buttons.append($WorkerPlaySlots/Slot1)
|
||
|
slot_buttons.append($WorkerPlaySlots/Slot2)
|
||
|
slot_buttons.append($WorkerPlaySlots/Slot3)
|
||
|
slot_buttons.append($WorkerPlaySlots/Slot4)
|
||
|
slot_buttons.append($WorkerPlaySlots/Slot5)
|
||
|
for button in slot_buttons:
|
||
|
button.button_pushed.connect(select_slot)
|
||
|
$PoorDiscardPile/Label.text = "No / Poor service"
|
||
|
$GoodDiscardPile/Label.text = "Good service"
|
||
|
$GreatDiscardPile/Label.text = "Great service"
|
||
|
$TaskDrawDeck/Label.text = "Click to draw task card"
|
||
|
$Camera2D.make_current()
|
||
|
await board_attached
|
||
|
enter_setup_state()
|
||
|
|
||
|
|
||
|
func _process(delta) -> void:
|
||
|
if (hand_hiding):
|
||
|
if hand_hiding_progress < seconds_to_hide_hand:
|
||
|
hand_hiding_progress += delta
|
||
|
var percent = clampf(hand_hiding_progress / seconds_to_hide_hand, 0.0, 1.0)
|
||
|
for card in hand:
|
||
|
card.hand_position.y = lerpf($Hand.position.y, $Hand.position.y + 300.0, percent)
|
||
|
else:
|
||
|
hand_hiding = false
|
||
|
hand_hidden = true
|
||
|
hand_hiding_progress = 0.0
|
||
|
if (hand_showing):
|
||
|
if hand_showing_progress < seconds_to_show_hand:
|
||
|
hand_showing_progress += delta
|
||
|
var percent = clampf(hand_showing_progress / seconds_to_show_hand, 0.0, 1.0)
|
||
|
for card in hand:
|
||
|
card.hand_position.y = lerpf($Hand.position.y + 300.0, $Hand.position.y, percent)
|
||
|
else:
|
||
|
hand_showing = false
|
||
|
hand_showing_progress = 0.0
|
||
|
|
||
|
|
||
|
func start_turn():
|
||
|
pass
|
||
|
|
||
|
|
||
|
func start_round():
|
||
|
pass
|
||
|
|
||
|
|
||
|
@rpc("call_local")
|
||
|
func attach_board(board_path : NodePath):
|
||
|
board = get_node(board_path) as Board
|
||
|
board_attached.emit()
|
||
|
|
||
|
|
||
|
func add_to_hand(card):
|
||
|
hand.append(card)
|
||
|
for x in hand.size():
|
||
|
var hand_ratio = 0.5
|
||
|
|
||
|
if hand.size() > 1:
|
||
|
hand_ratio = float(x) / float(hand.size() - 1)
|
||
|
hand[x].position = $Hand.position
|
||
|
hand[x].hand_ratio = hand_ratio
|
||
|
hand[x].in_hand = true
|
||
|
hand[x].hand_position = $Hand.position
|
||
|
hand[x].visible = true
|
||
|
hand[x].set_process(true)
|
||
|
|
||
|
|
||
|
func lift_hand():
|
||
|
for card in hand:
|
||
|
card.hovered = true
|
||
|
|
||
|
|
||
|
func drop_hand():
|
||
|
for card in hand:
|
||
|
card.hovered = false
|
||
|
|
||
|
|
||
|
func _on_hire_button_pressed():
|
||
|
if money >= hire_costs[workers.size()]:
|
||
|
money -= hire_costs[workers.size()]
|
||
|
$Camera2D/Money.text = "$" + str(money)
|
||
|
draft_workers(3, 1, true)
|
||
|
await draft_completed
|
||
|
$Button.text = "Hire Worker: $" + str(hire_costs[workers.size()])
|
||
|
|
||
|
|
||
|
func assign_task_to_worker():
|
||
|
client_assignment = active_workers.find(selected_worker)
|
||
|
if active_clients[client_assignment] != null:
|
||
|
return
|
||
|
current_client.slide_to_position(selected_worker.position.x - 100, selected_worker.position.y - 100, 0.0, 0.3)
|
||
|
current_client.show_time_selector()
|
||
|
await current_client.time_slots_selected
|
||
|
payout = 0
|
||
|
payout += current_client.turns_left * 2
|
||
|
for service in current_client.services:
|
||
|
if selected_worker.services.has(service):
|
||
|
payout += Data.service_prices[service]
|
||
|
$Camera2D/Payout.text = "$" + str(payout)
|
||
|
$"Camera2D/EndTurn".visible = true
|
||
|
|
||
|
|
||
|
func move_to_poor_discard(_button):
|
||
|
current_client.slide_to_position($PoorDiscardPile.position.x, $PoorDiscardPile.position.y, 0.0, 0.2)
|
||
|
client_assignment = -1
|
||
|
$Camera2D/EndTurn.visible = true
|
||
|
payout = 0
|
||
|
$Camera2D/Payout.text = ""
|
||
|
|
||
|
|
||
|
func select_card(card):
|
||
|
if current_fsm_state == FSMState.DRAFT:
|
||
|
if selected_for_draft.size() <= draft_limit:
|
||
|
if selected_for_draft.has(card):
|
||
|
selected_for_draft.remove_at(selected_for_draft.find(card))
|
||
|
card.slide_to_position(card.position.x, card.position.y + 40, 0.0, 0.1)
|
||
|
else:
|
||
|
if selected_for_draft.size() < draft_limit:
|
||
|
selected_for_draft.append(card)
|
||
|
card.slide_to_position(card.position.x, card.position.y - 40, 0.0, 0.1)
|
||
|
return
|
||
|
selected_worker = card
|
||
|
if current_client != null:
|
||
|
assign_task_to_worker()
|
||
|
|
||
|
|
||
|
func select_slot(slot):
|
||
|
if selected_worker == null:
|
||
|
return
|
||
|
if active_workers.has(selected_worker):
|
||
|
active_workers[active_workers.find(selected_worker)] = null
|
||
|
if hand.has(selected_worker):
|
||
|
hand.remove_at(hand.find(selected_worker))
|
||
|
active_workers[slot_buttons.find(slot)] = selected_worker
|
||
|
selected_worker.slide_to_position(slot.position.x, slot.position.y, 0.0, 0.3)
|
||
|
selected_worker = null
|
||
|
|
||
|
#Shift Phase
|
||
|
#1. Swap 1 time token on each worker over to the stress side
|
||
|
#2. Pick up the next client card in the deck, and either assign it to
|
||
|
# a worker or place it in the no service pile
|
||
|
#3. If a worker both has no client, and at least one stress token, remove
|
||
|
# a stress token
|
||
|
|
||
|
#Management Phase
|
||
|
#Market Research
|
||
|
#Look at the 10 clients, and place them back in the same order
|
||
|
#Targeted Advertising
|
||
|
#Search through the client discard deck, and add all clients
|
||
|
#with one extra type to your shift deck
|
||
|
#Roster Worker
|
||
|
#Add 1 worker from your hand into the next open slot on your board
|
||
|
|
||
|
|
||
|
func _on_area_2d_input_event(_viewport, event, _shape_idx):
|
||
|
if event is InputEventMouseButton and event.pressed:
|
||
|
enter_workers_view_state()
|
||
|
|
||
|
|
||
|
func _on_area_2d_2_input_event(_viewport, event, _shape_idx):
|
||
|
if event is InputEventMouseButton and event.pressed:
|
||
|
enter_management_overview_state()
|
||
|
|
||
|
|
||
|
func _on_task_draw_deck_button_pushed(_button):
|
||
|
enter_holding_task_state()
|
||
|
|
||
|
|
||
|
func evaluate_task_success(num):
|
||
|
var successfulness = 0
|
||
|
var worker = active_workers[num]
|
||
|
var client = active_clients[num]
|
||
|
match client.services.size():
|
||
|
2, 3:
|
||
|
successfulness = 2
|
||
|
4:
|
||
|
successfulness = 1
|
||
|
if worker.services.has(client.services[3]):
|
||
|
successfulness = 2
|
||
|
5:
|
||
|
successfulness = 1
|
||
|
if worker.services.has(client.services[4]):
|
||
|
successfulness = 2
|
||
|
6:
|
||
|
successfulness = 0
|
||
|
if worker.services.has(client.services[3]) or worker.services.has(client.services[4]):
|
||
|
successfulness = 1
|
||
|
if worker.services.has(client.services[5]):
|
||
|
successfulness = 2
|
||
|
7:
|
||
|
successfulness = 0
|
||
|
if worker.services.has(client.services[3]) or worker.services.has(client.services[4]):
|
||
|
successfulness = 1
|
||
|
if worker.services.has(client.services[5]) or worker.services.has(client.services[6]):
|
||
|
successfulness = 2
|
||
|
var slide_destination : Vector2
|
||
|
match successfulness:
|
||
|
0:
|
||
|
poor_discard.append(client)
|
||
|
slide_destination = $PoorDiscardPile.position
|
||
|
1:
|
||
|
good_discard.append(client)
|
||
|
slide_destination = $GoodDiscardPile.position
|
||
|
2:
|
||
|
great_discard.append(client)
|
||
|
slide_destination = $GreatDiscardPile.position
|
||
|
client.slide_to_position(slide_destination.x, slide_destination.y, 0.0, 0.2)
|
||
|
client.z_index = 0
|
||
|
active_clients[num] = null
|
||
|
|
||
|
|
||
|
func worker_exceeded_capacity(num):
|
||
|
active_workers[num].stress = 0
|
||
|
active_workers[num].set_process(false)
|
||
|
active_workers[num].visible = false
|
||
|
workers.remove_at(workers.find(active_workers[num]))
|
||
|
active_workers[num] = null
|
||
|
|
||
|
|
||
|
func draft_workers(_draw, pick, cancelable):
|
||
|
draft = DraftType.HIRE_WORKER
|
||
|
draft_limit = pick
|
||
|
shown_for_draft = []
|
||
|
selected_for_draft = []
|
||
|
var y = 0
|
||
|
var x = (250.0 * _draw) / 2.0
|
||
|
shown_for_draft.append_array(board.draw_worker(_draw))
|
||
|
for i in shown_for_draft.size():
|
||
|
var card = shown_for_draft[i]
|
||
|
card.visible = true
|
||
|
card.set_process(true)
|
||
|
card.card_clicked.connect(select_card)
|
||
|
var ratio = float(i) / float(_draw - 1)
|
||
|
var xx = lerpf(-1 * x, x, ratio)
|
||
|
card.slide_to_position(xx, y, 0.0, 0.3)
|
||
|
enter_draft_state(cancelable)
|
||
|
|
||
|
|
||
|
func pad_shift_deck():
|
||
|
var padding = (2 + (2 * board.round_num)) - shift_deck.size()
|
||
|
shift_deck.append_array(board.draw_client(padding))
|
||
|
|
||
|
|
||
|
func process_discard_decks():
|
||
|
poor_discard.shuffle()
|
||
|
good_discard.shuffle()
|
||
|
great_discard.shuffle()
|
||
|
for x in range(poor_discard.size() - 1, -1, -1):
|
||
|
if x == 0:
|
||
|
shift_deck.append(poor_discard[x])
|
||
|
else:
|
||
|
board.discard_client(poor_discard[x])
|
||
|
poor_discard[x].position = Vector2(9999, 9999)
|
||
|
poor_discard[x].visible = false
|
||
|
poor_discard.remove_at(x)
|
||
|
for x in range(good_discard.size() - 1, -1, -1):
|
||
|
if x <= int(good_discard.size() / 2.0):
|
||
|
shift_deck.append(good_discard[x])
|
||
|
else:
|
||
|
board.discard_client(good_discard[x])
|
||
|
good_discard[x].position = Vector2(9999, 9999)
|
||
|
good_discard[x].visible = false
|
||
|
good_discard.remove_at(x)
|
||
|
for x in range(great_discard.size() - 1, -1, -1):
|
||
|
if x < great_discard.size() - 1:
|
||
|
shift_deck.append(great_discard[x])
|
||
|
else:
|
||
|
board.discard_client(great_discard[x])
|
||
|
great_discard[x].position = Vector2(9999, 9999)
|
||
|
great_discard[x].visible = false
|
||
|
great_discard.remove_at(x)
|
||
|
|
||
|
|
||
|
func confirm_draft():
|
||
|
if selected_for_draft.size() != draft_limit:
|
||
|
return
|
||
|
$Camera2D/EndDraft.visible = false
|
||
|
$Camera2D/CancelDraft.visible = false
|
||
|
match(draft):
|
||
|
DraftType.HIRE_WORKER:
|
||
|
for card in selected_for_draft:
|
||
|
add_to_hand(card)
|
||
|
workers.append(card)
|
||
|
shown_for_draft.remove_at(shown_for_draft.find(card))
|
||
|
for card in shown_for_draft:
|
||
|
card.position = Vector2(9999, 9999)
|
||
|
board.discard_worker(card)
|
||
|
match(last_fsm_state):
|
||
|
FSMState.SETUP, FSMState.MANAGEMENT:
|
||
|
enter_management_overview_state()
|
||
|
draft_completed.emit()
|
||
|
|
||
|
|
||
|
func cancel_draft():
|
||
|
$Camera2D/EndDraft.visible = false
|
||
|
$Camera2D/CancelDraft.visible = false
|
||
|
match(draft):
|
||
|
DraftType.HIRE_WORKER:
|
||
|
for card in shown_for_draft:
|
||
|
card.visible = false
|
||
|
card.set_process(false)
|
||
|
board.discard_worker(board.search_and_draw_worker(card))
|
||
|
match(last_fsm_state):
|
||
|
FSMState.SETUP, FSMState.MANAGEMENT:
|
||
|
enter_management_overview_state()
|
||
|
draft_completed.emit()
|
||
|
|
||
|
|
||
|
func enter_draft_state(cancelable):
|
||
|
last_fsm_state = current_fsm_state
|
||
|
current_fsm_state = FSMState.DRAFT
|
||
|
$Camera2D/PhaseLabel.text = "Choose " + str(draft_limit) + " cards"
|
||
|
$Camera2D/EndManagement.visible = false
|
||
|
$RosterButton/CollisionShape2D.disabled = true
|
||
|
$ReturnButton.visible = false
|
||
|
$ReturnButton/CollisionShape2D.disabled = true
|
||
|
$Camera2D/EndDraft.visible = true
|
||
|
if cancelable:
|
||
|
$Camera2D/CancelDraft.visible = true
|
||
|
|
||
|
|
||
|
func enter_setup_state():
|
||
|
last_fsm_state = current_fsm_state
|
||
|
current_fsm_state = FSMState.SETUP
|
||
|
#money = 100
|
||
|
$Camera2D/Money.text = "$" + str(money)
|
||
|
draft_workers(4, 2, false)
|
||
|
|
||
|
|
||
|
func enter_management_overview_state():
|
||
|
last_fsm_state = current_fsm_state
|
||
|
current_fsm_state = FSMState.MANAGEMENT
|
||
|
for worker in active_workers:
|
||
|
if worker != null:
|
||
|
worker.decrease_stress(worker.stress)
|
||
|
$Camera2D/RoundCounter.text = "Round: " + str(board.round_num)
|
||
|
$Camera2D/PhaseLabel.text = "Management Phase"
|
||
|
$Camera2D/EndManagement.visible = true
|
||
|
$Camera2D/Cost.visible = true
|
||
|
$Camera2D/EndShift.visible = false
|
||
|
$Camera2D/EndTurn.visible = false
|
||
|
$RosterButton/CollisionShape2D.disabled = false
|
||
|
$WorkerPlaySlots/Slot1.visible = true
|
||
|
$WorkerPlaySlots/Slot2.visible = true
|
||
|
$WorkerPlaySlots/Slot3.visible = true
|
||
|
$WorkerPlaySlots/Slot4.visible = true
|
||
|
$WorkerPlaySlots/Slot5.visible = true
|
||
|
$HireWorkerButton.visible = true
|
||
|
$Camera2D/TurnCounter.visible = false
|
||
|
hand_showing = true
|
||
|
selected_worker = null
|
||
|
$RosterButton/CollisionShape2D.disabled = false
|
||
|
$ReturnButton.visible = false
|
||
|
$ReturnButton/CollisionShape2D.disabled = true
|
||
|
$Camera2D.position.y = 0
|
||
|
for x in hand.size():
|
||
|
hand[x].in_hand = true
|
||
|
$TaskDrawDeck/Area2D/CollisionShape2D.disabled = true
|
||
|
$PoorDiscardPile/Area2D/CollisionShape2D.disabled = true
|
||
|
process_discard_decks()
|
||
|
pad_shift_deck()
|
||
|
$TaskDrawDeck/Count.text = str(shift_deck.size())
|
||
|
|
||
|
|
||
|
func enter_workers_view_state():
|
||
|
last_fsm_state = current_fsm_state
|
||
|
current_fsm_state = FSMState.WORKER
|
||
|
selected_worker = null
|
||
|
$RosterButton/CollisionShape2D.disabled = true
|
||
|
$ReturnButton.visible = true
|
||
|
$ReturnButton/CollisionShape2D.disabled = false
|
||
|
$Camera2D.position.y = 640
|
||
|
for x in hand.size():
|
||
|
hand[x].in_hand = false
|
||
|
hand[x].slide_to_position(roster_positions[x].position.x, roster_positions[x].position.y, 0.0, 0.2)
|
||
|
|
||
|
|
||
|
func enter_holding_worker_state():
|
||
|
last_fsm_state = current_fsm_state
|
||
|
current_fsm_state = FSMState.H_WORKER
|
||
|
|
||
|
|
||
|
func enter_shift_overview_state():
|
||
|
last_fsm_state = current_fsm_state
|
||
|
current_fsm_state = FSMState.SHIFT
|
||
|
$Camera2D/TurnCounter.visible = true
|
||
|
$Camera2D/TurnCounter.text = "Turn: " + str(board.turn_num)
|
||
|
$Camera2D/PhaseLabel.text = "Shift Phase"
|
||
|
$Camera2D/EndManagement.visible = false
|
||
|
$RosterButton/CollisionShape2D.disabled = true
|
||
|
$WorkerPlaySlots/Slot1.visible = false
|
||
|
$WorkerPlaySlots/Slot2.visible = false
|
||
|
$WorkerPlaySlots/Slot3.visible = false
|
||
|
$WorkerPlaySlots/Slot4.visible = false
|
||
|
$WorkerPlaySlots/Slot5.visible = false
|
||
|
$ReturnButton.visible = false
|
||
|
$ReturnButton/CollisionShape2D.disabled = true
|
||
|
$Camera2D.position.y = 0
|
||
|
$Camera2D/Cost.visible = false
|
||
|
$HireWorkerButton.visible = false
|
||
|
for x in hand.size():
|
||
|
hand[x].in_hand = true
|
||
|
if hand_hidden == false:
|
||
|
hand_hiding = true
|
||
|
$TaskDrawDeck/Area2D/CollisionShape2D.disabled = false
|
||
|
task_drawn = false
|
||
|
money += payout
|
||
|
payout = 0
|
||
|
if client_assignment != null and current_client != null:
|
||
|
active_clients[client_assignment] = current_client
|
||
|
if active_workers[client_assignment].increase_stress(current_client.initial_stress):
|
||
|
worker_exceeded_capacity(client_assignment)
|
||
|
client_assignment = -1
|
||
|
current_client = null
|
||
|
elif client_assignment == -1 and current_client != null:
|
||
|
poor_discard.append(current_client)
|
||
|
current_client = null
|
||
|
$Camera2D/Payout.text = ""
|
||
|
$Camera2D/Money.text = "$" + str(money)
|
||
|
$Camera2D/EndTurn.visible = false
|
||
|
$PoorDiscardPile/Area2D/CollisionShape2D.disabled = true
|
||
|
#Pretty sure these are done in the right order even though it looks the wrong way around
|
||
|
for x in active_workers.size():
|
||
|
if active_workers[x] != null and active_clients[x] == null:
|
||
|
active_workers[x].decrease_stress(1)
|
||
|
if active_workers[x] != null and active_clients[x] != null:
|
||
|
if active_workers[x].increase_stress(1):
|
||
|
worker_exceeded_capacity(x)
|
||
|
active_clients[x].turns_left -= 1
|
||
|
active_clients[x].update_counter()
|
||
|
if active_clients[x].turns_left == 0:
|
||
|
evaluate_task_success(x)
|
||
|
var tasks_done = true
|
||
|
for client in active_clients:
|
||
|
if client != null:
|
||
|
tasks_done = false
|
||
|
if shift_deck.size() == 0:
|
||
|
if tasks_done:
|
||
|
round_completed = true
|
||
|
#enter_management_overview_state()
|
||
|
else:
|
||
|
$Camera2D/EndTurn.visible = true
|
||
|
$TaskDrawDeck/Area2D/CollisionShape2D.disabled = true
|
||
|
|
||
|
|
||
|
func enter_holding_task_state():
|
||
|
last_fsm_state = current_fsm_state
|
||
|
current_fsm_state = FSMState.H_CLIENT
|
||
|
current_client = shift_deck.pop_back()
|
||
|
current_client.position = Vector2(494, -414)
|
||
|
current_client.visible = true
|
||
|
current_client.z_index = 1
|
||
|
current_client.slide_to_position($PreviewTask.position.x, $PreviewTask.position.y, 0.0, 0.3)
|
||
|
task_drawn = true
|
||
|
$TaskDrawDeck/Area2D/CollisionShape2D.disabled = true
|
||
|
$PoorDiscardPile/Area2D/CollisionShape2D.disabled = false
|
||
|
$TaskDrawDeck/Count.text = str(shift_deck.size())
|
||
|
|