you can pay off the mortgage

This commit is contained in:
Tenari
2026-03-09 08:12:32 -05:00
parent a95315f3a3
commit 18efda0b71
4 changed files with 242 additions and 53 deletions
+139 -23
View File
@@ -37,6 +37,13 @@ typedef enum Tab {
Tab_Count, Tab_Count,
} Tab; } Tab;
typedef enum ShipTabStates {
ShipTabStateMain,
ShipTabStatePayoffModal,
ShipTabStateLoading,
ShipTabStates_Count,
} ShipTabStates;
typedef enum StationTabStates { typedef enum StationTabStates {
StationTabStateTable, StationTabStateTable,
StationTabStateTransact, StationTabStateTransact,
@@ -154,6 +161,7 @@ typedef struct GameState {
Pos2 pos; Pos2 pos;
u8 destination_sys_idx; u8 destination_sys_idx;
StationTabStates station_tab_state; StationTabStates station_tab_state;
ShipTabStates ship_tab_states;
TransactionResult tx_result; TransactionResult tx_result;
u64 turn_tick_started_on; u64 turn_tick_started_on;
} GameState; } GameState;
@@ -384,6 +392,33 @@ fn void clearServerSentState() {
state.entities.items = arenaAllocArray(&state.entity_arena, Entity, state.entities.capacity); state.entities.items = arenaAllocArray(&state.entity_arena, Entity, state.entities.capacity);
} }
fn void resetTabRow(Tab tab) {
if (state.menu.selected_index == TabStation) {
state.row.len = Commodity_Count;
state.row.selected_index = 0;
} else if (state.menu.selected_index == TabShip) {
state.ship_tab_states = ShipTabStateMain;
state.row.len = 2;
state.row.selected_index = 0;
}
}
fn void moveRowUpDown(bool user_pressed_up, bool user_pressed_down) {
if (user_pressed_up) {
if (state.row.selected_index == 0) {
state.row.selected_index = state.row.len - 1;
} else {
state.row.selected_index -= 1;
}
} else if (user_pressed_down) {
if (state.row.selected_index == state.row.len - 1) {
state.row.selected_index = 0;
} else {
state.row.selected_index += 1;
}
}
}
fn void handleIncomingMessage(u8* message, u32 len, SocketAddress sender, i32 socket) { fn void handleIncomingMessage(u8* message, u32 len, SocketAddress sender, i32 socket) {
u64 msg_pos = 0; u64 msg_pos = 0;
Message msg_type = message[msg_pos++]; Message msg_type = message[msg_pos++];
@@ -392,6 +427,7 @@ fn void handleIncomingMessage(u8* message, u32 len, SocketAddress sender, i32 so
ParsedServerMessage parsed = {0}; ParsedServerMessage parsed = {0};
parsed.type = msg_type; parsed.type = msg_type;
switch (msg_type) { switch (msg_type) {
case MessagePayoffResult:
case MessageTurnTick: case MessageTurnTick:
case MessageNewAccountCreated: case MessageNewAccountCreated:
case MessageBadPw: {/*nothing to parse but the type*/} break; case MessageBadPw: {/*nothing to parse but the type*/} break;
@@ -515,6 +551,9 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
while (next_net_msg != NULL) { while (next_net_msg != NULL) {
msg_iters += 0; msg_iters += 0;
switch (msg.type) { switch (msg.type) {
case MessagePayoffResult: {
state->ship_tab_states = ShipTabStateMain;
} break;
case MessageTurnTick: { case MessageTurnTick: {
state->screen = ScreenTurnTick; state->screen = ScreenTurnTick;
state->turn_tick_started_on = loop_count; state->turn_tick_started_on = loop_count;
@@ -712,20 +751,14 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
if (state->menu.selected_index >= state->menu.len) { if (state->menu.selected_index >= state->menu.len) {
state->menu.selected_index = 0; state->menu.selected_index = 0;
} }
if (state->menu.selected_index == TabStation) { resetTabRow(state->menu.selected_index);
state->row.len = Commodity_Count;
state->row.selected_index = 0;
}
} else if (user_pressed_shift_tab) { } else if (user_pressed_shift_tab) {
if (state->menu.selected_index > 0) { if (state->menu.selected_index > 0) {
state->menu.selected_index -= 1; state->menu.selected_index -= 1;
} else { } else {
state->menu.selected_index = state->menu.len - 1; state->menu.selected_index = state->menu.len - 1;
} }
if (state->menu.selected_index == TabStation) { resetTabRow(state->menu.selected_index);
state->row.len = Commodity_Count;
state->row.selected_index = 0;
}
} }
Tab tab = state->menu.selected_index; Tab tab = state->menu.selected_index;
@@ -785,6 +818,8 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
u32 x_off = box.x+((box.width - MAP_WIDTH*xw)/2); u32 x_off = box.x+((box.width - MAP_WIDTH*xw)/2);
u32 y_off = box.y+1; u32 y_off = box.y+1;
StarSystem dest = state->map[state->destination_sys_idx]; StarSystem dest = state->map[state->destination_sys_idx];
tui->cursor.x = x_off+state->pos.x*xw;
tui->cursor.y = y_off+state->pos.y*yh;
for (u32 i = 0; i < MAP_WIDTH*xw; i++) { for (u32 i = 0; i < MAP_WIDTH*xw; i++) {
for (u32 ii = 0; ii < MAP_HEIGHT*yh; ii++) { for (u32 ii = 0; ii < MAP_HEIGHT*yh; ii++) {
u32 sysx = i / xw; u32 sysx = i / xw;
@@ -906,6 +941,9 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
if (input_buffer[0] == 'q' || user_pressed_esc) { if (input_buffer[0] == 'q' || user_pressed_esc) {
should_quit = true; should_quit = true;
} }
moveRowUpDown(user_pressed_up, user_pressed_down);
u32 yoff = box.y+1; u32 yoff = box.y+1;
MemoryZero(sbuf, SBUFLEN); MemoryZero(sbuf, SBUFLEN);
sprintf(sbuf, "Player: %s", state->login_state.name.bytes); sprintf(sbuf, "Player: %s", state->login_state.name.bytes);
@@ -915,6 +953,26 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
sprintf(sbuf, "Ship Type: %s", SHIP_TYPE_STRINGS[state->me.type]); sprintf(sbuf, "Ship Type: %s", SHIP_TYPE_STRINGS[state->me.type]);
renderStrToBuffer(tui->frame_buffer, box.x+2, yoff++, sbuf, screen_dimensions); renderStrToBuffer(tui->frame_buffer, box.x+2, yoff++, sbuf, screen_dimensions);
MemoryZero(sbuf, SBUFLEN);
sprintf(sbuf, "Remaining Mortgage: %d @ %.2f%%", state->me.remaining_mortgage, state->me.interest_rate);
if (state->row.selected_index == 0) {
Range1u32 range = {
.min = XYToPos(box.x+2, yoff, screen_dimensions.width),
.max = XYToPos(box.x+2+strlen(sbuf), yoff, screen_dimensions.width),
};
tui->cursor.x = box.x+2;
tui->cursor.y = yoff;
colorizeRange(tui, range, ANSI_WHITE, ANSI_BLACK);
renderStrToBuffer(tui->frame_buffer, box.x+2+strlen(sbuf), yoff, " [ENTER] to pay off", screen_dimensions);
if (user_pressed_enter && state->ship_tab_states == ShipTabStateMain) {
// open the payoff modal
state->ship_tab_states = ShipTabStatePayoffModal;
user_pressed_enter = false; // to prevent immediately submitting the modal
}
}
renderStrToBuffer(tui->frame_buffer, box.x+2, yoff++, sbuf, screen_dimensions);
MemoryZero(sbuf, SBUFLEN); MemoryZero(sbuf, SBUFLEN);
sprintf(sbuf, "Credits: %.2f", state->me.credits); sprintf(sbuf, "Credits: %.2f", state->me.credits);
renderStrToBuffer(tui->frame_buffer, box.x+2, yoff++, sbuf, screen_dimensions); renderStrToBuffer(tui->frame_buffer, box.x+2, yoff++, sbuf, screen_dimensions);
@@ -926,6 +984,7 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
MemoryZero(sbuf, SBUFLEN); MemoryZero(sbuf, SBUFLEN);
sprintf(sbuf, "Ready To Depart: %s", state->me.ready_to_depart ? "yes" : "no"); sprintf(sbuf, "Ready To Depart: %s", state->me.ready_to_depart ? "yes" : "no");
if (state->row.selected_index == 1) {
Range1u32 range = { Range1u32 range = {
.min = XYToPos(box.x+2, yoff, screen_dimensions.width), .min = XYToPos(box.x+2, yoff, screen_dimensions.width),
.max = XYToPos(box.x+2+strlen(sbuf), yoff, screen_dimensions.width), .max = XYToPos(box.x+2+strlen(sbuf), yoff, screen_dimensions.width),
@@ -933,9 +992,10 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
tui->cursor.x = box.x+2; tui->cursor.x = box.x+2;
tui->cursor.y = yoff; tui->cursor.y = yoff;
colorizeRange(tui, range, ANSI_WHITE, ANSI_BLACK); colorizeRange(tui, range, ANSI_WHITE, ANSI_BLACK);
renderStrToBuffer(tui->frame_buffer, box.x+2, yoff++, sbuf, screen_dimensions);
if (user_pressed_enter) { renderStrToBuffer(tui->frame_buffer, box.x+2+strlen(sbuf), yoff, " [ENTER] to toggle", screen_dimensions);
if (user_pressed_enter && state->ship_tab_states == ShipTabStateMain) {
// send the "ready" or "not ready" message to the server // send the "ready" or "not ready" message to the server
u32 msg_idx = 0; u32 msg_idx = 0;
UDPMessage msg = {0}; UDPMessage msg = {0};
@@ -948,12 +1008,79 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
outgoingMessageQueuePush(network_send_queue, &msg); outgoingMessageQueuePush(network_send_queue, &msg);
} }
}
renderStrToBuffer(tui->frame_buffer, box.x+2, yoff++, sbuf, screen_dimensions);
for (u32 i = 0; i < Commodity_Count; i++) { for (u32 i = 0; i < Commodity_Count; i++) {
MemoryZero(sbuf, SBUFLEN); MemoryZero(sbuf, SBUFLEN);
sprintf(sbuf, "%-42s %d", COMMODITIES[i].name, state->me.commodities[i]); sprintf(sbuf, "%-42s %d", COMMODITIES[i].name, state->me.commodities[i]);
renderStrToBuffer(tui->frame_buffer, box.x+4, yoff+4+i, sbuf, screen_dimensions); renderStrToBuffer(tui->frame_buffer, box.x+4, yoff+4+i, sbuf, screen_dimensions);
} }
Box modal_outline = {
.x = (tui->screen_dimensions.width - 50) / 2,
.y = (tui->screen_dimensions.height - 15) / 2,
.height = 15,
.width = 50,
};
u32 y_off = modal_outline.y+2;
if (state->ship_tab_states == ShipTabStatePayoffModal) {
if (user_pressed_a_number) {
String next_char = { 1, 2, (char*)input_buffer };
stringChunkListAppend(&state->string_arena, &state->message_input, next_char);
} else if (user_pressed_backspace) {
stringChunkListDeleteLast(&state->string_arena, &state->message_input);
}
// draw the modal
clearBox(tui, modal_outline);
drawAnsiBox(tui->frame_buffer, modal_outline, tui->screen_dimensions, false);
MemoryZero(sbuf, SBUFLEN);
sprintf(sbuf, "How much would you like to pay?");
renderStrToBuffer(tui->frame_buffer, modal_outline.x+((modal_outline.width-strlen(sbuf))/2), y_off++, sbuf, screen_dimensions);
renderStringChunkList(tui, &state->message_input, modal_outline.x+8, y_off);
tui->cursor.x = modal_outline.x + 8 + state->message_input.total_size;
tui->cursor.y = y_off++;
String input_q_str = stringChunkToString(&permanent_arena, state->message_input);
u32 input_quantity = atoi(input_q_str.bytes);
u32 remaining = input_quantity > state->me.remaining_mortgage ? 0 : (state->me.remaining_mortgage - input_quantity);
arenaDealloc(&permanent_arena, input_q_str.capacity);
MemoryZero(sbuf, SBUFLEN);
sprintf(sbuf, "Leaving $%d remaining to pay off", remaining);
renderStrToBuffer(tui->frame_buffer, modal_outline.x+8, y_off++, sbuf, screen_dimensions);
u32 exit_x = modal_outline.x+((modal_outline.width-3)/2);
u32 pos = XYToPos(exit_x, y_off, tui->screen_dimensions.width);
for (u32 i = 0; i < 3; i++) {
tui->frame_buffer[pos+i].background = ANSI_WHITE;
tui->frame_buffer[pos+i].foreground = ANSI_BLACK;
}
renderStrToBuffer(tui->frame_buffer, exit_x, y_off++, "PAY", screen_dimensions);
if (user_pressed_enter) {
// send the "payoff" message to server
u32 msg_idx = 0;
UDPMessage msg = {0};
msg.address = udp->server_address;
// 1. msg type/CommandType
msg.bytes[msg_idx++] = CommandPayMortgage;
// 2. buy?
msg_idx += writeU64ToBufferLE(msg.bytes + msg_idx, input_quantity);
msg.bytes_len = msg_idx;
outgoingMessageQueuePush(network_send_queue, &msg);
state->ship_tab_states = ShipTabStateLoading;
}
} else if (state->ship_tab_states == ShipTabStateLoading) {
// draw the modal
clearBox(tui, modal_outline);
drawAnsiBox(tui->frame_buffer, modal_outline, tui->screen_dimensions, false);
renderStrToBuffer(tui->frame_buffer, modal_outline.x+2, y_off, "Loading...", screen_dimensions);
}
} break; } break;
case TabStation: { case TabStation: {
if (input_buffer[0] == 'q' || user_pressed_esc) { if (input_buffer[0] == 'q' || user_pressed_esc) {
@@ -973,19 +1100,8 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
case StationTabStates_Count: assert(false && "something has gone horribly wrong"); case StationTabStates_Count: assert(false && "something has gone horribly wrong");
} }
} }
if (user_pressed_up) { moveRowUpDown(user_pressed_up, user_pressed_down);
if (state->row.selected_index == 0) {
state->row.selected_index = state->row.len - 1;
} else {
state->row.selected_index -= 1;
}
} else if (user_pressed_down) {
if (state->row.selected_index == state->row.len - 1) {
state->row.selected_index = 0;
} else {
state->row.selected_index += 1;
}
}
renderStrToBuffer(tui->frame_buffer, box.x+2, box.y+1, "Welcome to ", screen_dimensions); renderStrToBuffer(tui->frame_buffer, box.x+2, box.y+1, "Welcome to ", screen_dimensions);
renderStrToBuffer(tui->frame_buffer, box.x+2+11, box.y+1, curr.name, screen_dimensions); renderStrToBuffer(tui->frame_buffer, box.x+2+11, box.y+1, curr.name, screen_dimensions);
+2
View File
@@ -569,6 +569,8 @@ fn void renderTable(TuiState* tui, TableDrawInfo t, u32 selected_index, FieldDes
// render the columns // render the columns
for (u32 ii = 0; ii < t.cols; col_x_pos += fields[ii].width+table_col_pad, ii++) { for (u32 ii = 0; ii < t.cols; col_x_pos += fields[ii].width+table_col_pad, ii++) {
if (i == selected_index) { if (i == selected_index) {
tui->cursor.x = t.x_offset;
tui->cursor.y = t.y_offset;
for (u32 iii = 0; iii < fields[ii].width+table_col_pad; iii++) { for (u32 iii = 0; iii < fields[ii].width+table_col_pad; iii++) {
u32 pos = XYToPos(t.x_offset+col_x_pos+iii, t.y_offset, tui->screen_dimensions.width); u32 pos = XYToPos(t.x_offset+col_x_pos+iii, t.y_offset, tui->screen_dimensions.width);
tui->frame_buffer[pos].background = ANSI_WHITE; tui->frame_buffer[pos].background = ANSI_WHITE;
+76 -11
View File
@@ -116,6 +116,8 @@ typedef struct ClientList {
typedef struct State { typedef struct State {
bool all_accounts_ready; bool all_accounts_ready;
u8 winner_id;
bool someone_won;
Mutex client_mutex; Mutex client_mutex;
Mutex mutex; Mutex mutex;
ClientList clients; ClientList clients;
@@ -447,6 +449,16 @@ fn UDPMessage makeMessagePlayerDetails(PlayerShip ship) {
return outgoing_message; return outgoing_message;
} }
fn void sendMessagePayoffResult(SocketAddress addr) {
UDPMessage outgoing_message = {0};
outgoing_message.address = addr;
u32 msg_i = 0;
outgoing_message.bytes[msg_i++] = (u8)MessagePayoffResult;
outgoing_message.bytes_len = msg_i;
outgoingMessageQueuePush(state.network_send_queue, &outgoing_message);
printf("%s sent\n", MESSAGE_STRINGS[outgoing_message.bytes[0]]);
}
fn void sendMessagePlayerDetails(PlayerShip ship, SocketAddress addr) { fn void sendMessagePlayerDetails(PlayerShip ship, SocketAddress addr) {
UDPMessage outgoing_message = makeMessagePlayerDetails(ship); UDPMessage outgoing_message = makeMessagePlayerDetails(ship);
outgoing_message.address = addr; outgoing_message.address = addr;
@@ -505,6 +517,10 @@ fn void handleIncomingMessage(u8* message, u32 len, SocketAddress sender, i32 so
} break; } break;
case CommandKeepAlive: case CommandKeepAlive:
break; break;
case CommandPayMortgage: {
parsed.id = readU64FromBufferLE(message + msg_idx);
printf("paying off %lld\n", parsed.id);
} break;
case CommandSetDestination: { case CommandSetDestination: {
parsed.byte = message[1]; // index of system in array parsed.byte = message[1]; // index of system in array
} break; } break;
@@ -622,6 +638,10 @@ fn bool accountIsEmpty(Account* a) {
return a->id == 0 && a->name.length == 0; return a->id == 0 && a->name.length == 0;
} }
fn bool shipIsNull(PlayerShip* ship) {
return ship->id == 0 && ship->base_cost == 0;
}
fn void* gameLoop(void* params) { fn void* gameLoop(void* params) {
LaneCtx* lane_ctx = (LaneCtx*)params; LaneCtx* lane_ctx = (LaneCtx*)params;
ThreadContext tctx = { ThreadContext tctx = {
@@ -642,6 +662,10 @@ fn void* gameLoop(void* params) {
if (LaneIdx() == 0) { // narrow if (LaneIdx() == 0) { // narrow
state.frame += 1; state.frame += 1;
if (state.all_accounts_ready) {
state.all_accounts_ready = false;
}
// 1. process client messages // 1. process client messages
lockMutex(&state.client_mutex); lockMutex(&state.mutex); { lockMutex(&state.client_mutex); lockMutex(&state.mutex); {
@@ -657,6 +681,19 @@ fn void* gameLoop(void* params) {
u32 client_handle = findClientHandleBySocketAddress(&state.clients, sender); u32 client_handle = findClientHandleBySocketAddress(&state.clients, sender);
Client* client = &state.clients.items[client_handle]; Client* client = &state.clients.items[client_handle];
switch (msg.type) { switch (msg.type) {
case CommandPayMortgage: {
Account* account = &state.accounts[client->account_id];
f32 amount_to_pay = (f32)msg.id;
if (account->ship.credits >= amount_to_pay) {
account->ship.credits -= amount_to_pay;
account->ship.remaining_mortgage -= msg.id;
} else {
account->ship.remaining_mortgage -= (u32)account->ship.credits;
account->ship.credits = 0.0;
}
account->changed = true;
sendMessagePayoffResult(sender);
} break;
case CommandSetDestination: { case CommandSetDestination: {
Account* account = &state.accounts[client->account_id]; Account* account = &state.accounts[client->account_id];
account->destination_sys_idx = msg.byte; account->destination_sys_idx = msg.byte;
@@ -780,11 +817,12 @@ fn void* gameLoop(void* params) {
break; break;
} }
} }
printf("new account id=%d\n", existing_account->id);
existing_account->name = name; existing_account->name = name;
existing_account->pw = pw; existing_account->pw = pw;
} }
client->account_id = existing_account->id; client->account_id = existing_account->id;
if (existing_account->ship.id != 0) { if (!shipIsNull(&existing_account->ship)) {
// tell the client their account id // tell the client their account id
outgoing_message.bytes[0] = (u8)MessageCharacterId; outgoing_message.bytes[0] = (u8)MessageCharacterId;
writeU64ToBufferLE(outgoing_message.bytes + 1, existing_account->ship.id); writeU64ToBufferLE(outgoing_message.bytes + 1, existing_account->ship.id);
@@ -804,7 +842,8 @@ fn void* gameLoop(void* params) {
} break; } break;
case CommandCreateCharacter: { case CommandCreateCharacter: {
Account* account = &state.accounts[client->account_id]; Account* account = &state.accounts[client->account_id];
if (account->ship.id == 0) { printf("creating character for account id=%d, %s\n", account->id, SHIP_TYPE_STRINGS[msg.byte]);
if (shipIsNull(&account->ship)) {
ShipTemplate template = SHIPS[msg.byte]; ShipTemplate template = SHIPS[msg.byte];
PlayerShip player_ship = { PlayerShip player_ship = {
.type = msg.byte, .type = msg.byte,
@@ -821,7 +860,7 @@ fn void* gameLoop(void* params) {
.credits = 10000.0, .credits = 10000.0,
//.cu_m_fuel; // we are just saying you can buy as much fuel as you want //.cu_m_fuel; // we are just saying you can buy as much fuel as you want
//.cu_m_o2; // we are just saying you can buy as much o2 as you want //.cu_m_o2; // we are just saying you can buy as much o2 as you want
.id = ++state.next_eid, // start from 1 .id = account->id,
}; };
player_ship.commodities[CommodityHydrogenFuel] = 2000; player_ship.commodities[CommodityHydrogenFuel] = 2000;
player_ship.commodities[CommodityOxygen] = 1000; player_ship.commodities[CommodityOxygen] = 1000;
@@ -884,11 +923,31 @@ fn void* gameLoop(void* params) {
} }
} }
if (state.someone_won) {
for (u32 i = 1; i < SERVER_MAX_CLIENTS; i++) {
if (state.clients.items[i].last_ping != 0) {
outgoing_message.address = state.clients.items[i].address;
outgoing_message.bytes_len = 2;
outgoing_message.bytes[0] = (u8)MessageGameOver;
outgoing_message.bytes[1] = state.winner_id;
outgoingMessageQueuePush(state.network_send_queue, &outgoing_message);
}
}
return NULL;
}
} unlockMutex(&state.mutex); unlockMutex(&state.client_mutex); } unlockMutex(&state.mutex); unlockMutex(&state.client_mutex);
} }
LaneSync(); LaneSync();
u32 player_count = 0;
for (u32 i = 0; i < ACCOUNT_LEN; i++) {
if (!accountIsEmpty(&state.accounts[i])) {
player_count += 1;
}
}
// 2. tick non-user entities // 2. tick non-user entities
if (state.all_accounts_ready) { if (state.all_accounts_ready) {
// tick all the star systems // tick all the star systems
@@ -911,16 +970,11 @@ fn void* gameLoop(void* params) {
} }
} }
// move all the players
u32 player_count = 0;
for (u32 i = 0; i < ACCOUNT_LEN; i++) {
if (!accountIsEmpty(&state.accounts[i])) {
player_count += 1;
}
}
Range1u64 ship_range = LaneRange(player_count); Range1u64 ship_range = LaneRange(player_count);
for (u32 i = ship_range.min; i < ship_range.max; i++) { for (u32 i = ship_range.min; i < ship_range.max; i++) {
Account* acct = &state.accounts[i]; Account* acct = &state.accounts[i];
// move all the players
StarSystem dest = state.map[acct->destination_sys_idx]; StarSystem dest = state.map[acct->destination_sys_idx];
StarSystem current = state.map[acct->ship.system_idx]; StarSystem current = state.map[acct->ship.system_idx];
Pos2 dest_pos = {dest.x, dest.y}; Pos2 dest_pos = {dest.x, dest.y};
@@ -935,11 +989,22 @@ fn void* gameLoop(void* params) {
} }
acct->ship.ready_to_depart = false; acct->ship.ready_to_depart = false;
acct->changed = true; acct->changed = true;
// look for a winner + increase the mortgage from interest
if (!shipIsNull(&acct->ship)) {
if (acct->ship.remaining_mortgage == 0) {
state.winner_id = acct->id;
state.someone_won = true;
printf("someone WON!!! %d\n", i);
break;
} else {
acct->ship.remaining_mortgage += acct->ship.remaining_mortgage * (acct->ship.interest_rate / 100.0);
}
}
} }
// TODO pay the mortgage payment // TODO pay the mortgage payment
} }
state.all_accounts_ready = false;
// 3. scratch cleanup // 3. scratch cleanup
arenaClear(&scratch_arena); arenaClear(&scratch_arena);
+8 -2
View File
@@ -8,8 +8,8 @@
#define STARTING_DOWN_PAYMENT (10000) #define STARTING_DOWN_PAYMENT (10000)
#define SHIP_DETAIL_COUNT (8) #define SHIP_DETAIL_COUNT (8)
#define STAR_SYSTEM_COUNT (40) #define STAR_SYSTEM_COUNT (40)
#define MAP_WIDTH (40) #define MAP_WIDTH (36)
#define MAP_HEIGHT (10) #define MAP_HEIGHT (12)
#define MAX_PLANETS (3) #define MAX_PLANETS (3)
typedef enum EntityFeature { typedef enum EntityFeature {
@@ -437,6 +437,7 @@ typedef enum CommandType {
CommandTransact, CommandTransact,
CommandReadyStatus, CommandReadyStatus,
CommandSetDestination, CommandSetDestination,
CommandPayMortgage,
CommandType_Count, CommandType_Count,
} CommandType; } CommandType;
@@ -447,6 +448,7 @@ static const char* command_type_strings[CommandType_Count] = {
"CreateCharacter", "CreateCharacter",
"ReadyStatus", "ReadyStatus",
"SetDestination", "SetDestination",
"PayMortgage",
}; };
#define ENTITY_HEADER_MESSAGE_SIZE (8+8+1+1+1) #define ENTITY_HEADER_MESSAGE_SIZE (8+8+1+1+1)
@@ -461,6 +463,8 @@ typedef enum Message {
MessagePlayerDetails, MessagePlayerDetails,
MessageTransactionResult, MessageTransactionResult,
MessageTurnTick, MessageTurnTick,
MessageGameOver,
MessagePayoffResult,
Message_Count, Message_Count,
} Message; } Message;
@@ -474,6 +478,8 @@ static const char* MESSAGE_STRINGS[] = {
"PlayerDetails", "PlayerDetails",
"TransactionResult", "TransactionResult",
"TurnTick", "TurnTick",
"GameOver",
"PayoffResult",
}; };
fn u32 fuelCostForTravel(u32 drive_efficiency, Pos2 current, Pos2 dest) { fn u32 fuelCostForTravel(u32 drive_efficiency, Pos2 current, Pos2 dest) {