you can pay off the mortgage
This commit is contained in:
+156
-40
@@ -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,34 +984,103 @@ 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");
|
||||||
Range1u32 range = {
|
if (state->row.selected_index == 1) {
|
||||||
.min = XYToPos(box.x+2, yoff, screen_dimensions.width),
|
Range1u32 range = {
|
||||||
.max = XYToPos(box.x+2+strlen(sbuf), yoff, screen_dimensions.width),
|
.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;
|
tui->cursor.x = box.x+2;
|
||||||
colorizeRange(tui, range, ANSI_WHITE, ANSI_BLACK);
|
tui->cursor.y = yoff;
|
||||||
renderStrToBuffer(tui->frame_buffer, box.x+2, yoff++, sbuf, screen_dimensions);
|
colorizeRange(tui, range, ANSI_WHITE, ANSI_BLACK);
|
||||||
|
|
||||||
if (user_pressed_enter) {
|
renderStrToBuffer(tui->frame_buffer, box.x+2+strlen(sbuf), yoff, " [ENTER] to toggle", screen_dimensions);
|
||||||
// send the "ready" or "not ready" message to the server
|
|
||||||
u32 msg_idx = 0;
|
|
||||||
UDPMessage msg = {0};
|
|
||||||
msg.address = udp->server_address;
|
|
||||||
// 1. msg type/CommandType
|
|
||||||
msg.bytes[msg_idx++] = CommandReadyStatus;
|
|
||||||
// 2. buy?
|
|
||||||
msg.bytes[msg_idx++] = !state->me.ready_to_depart;
|
|
||||||
msg.bytes_len = msg_idx;
|
|
||||||
|
|
||||||
outgoingMessageQueuePush(network_send_queue, &msg);
|
if (user_pressed_enter && state->ship_tab_states == ShipTabStateMain) {
|
||||||
|
// send the "ready" or "not ready" message to the server
|
||||||
|
u32 msg_idx = 0;
|
||||||
|
UDPMessage msg = {0};
|
||||||
|
msg.address = udp->server_address;
|
||||||
|
// 1. msg type/CommandType
|
||||||
|
msg.bytes[msg_idx++] = CommandReadyStatus;
|
||||||
|
// 2. buy?
|
||||||
|
msg.bytes[msg_idx++] = !state->me.ready_to_depart;
|
||||||
|
msg.bytes_len = msg_idx;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user