basic auction process works, but I still need to restrict the purchase/sale of these commodities on the Market tab

This commit is contained in:
Tenari
2026-03-26 07:28:10 -05:00
parent 4aece817b6
commit c9f33d9b0e
3 changed files with 121 additions and 20 deletions
+57
View File
@@ -65,6 +65,9 @@ typedef enum PassengersTabStates {
typedef enum AuctionTabStates { typedef enum AuctionTabStates {
AuctionTabStateMain, AuctionTabStateMain,
AuctionTabStateLoading, AuctionTabStateLoading,
AuctionTabStateNotEnoughMoney,
AuctionTabStateNotEnoughCargoSpace,
AuctionTabStateAlreadyFinished,
AuctionTabStateResult, AuctionTabStateResult,
AuctionTabStates_Count, AuctionTabStates_Count,
} AuctionTabStates; } AuctionTabStates;
@@ -348,6 +351,7 @@ fn void handleIncomingMessage(u8* message, u32 len, SocketAddress sender, i32 so
case MessageNewAccountCreated: case MessageNewAccountCreated:
case MessageNotAlive: case MessageNotAlive:
case MessageBadPw: {/*nothing to parse but the type*/} break; case MessageBadPw: {/*nothing to parse but the type*/} break;
case MessageAuctionBidResult: // same as GameOver
case MessageGameOver: { case MessageGameOver: {
parsed.byte = message[msg_pos++]; parsed.byte = message[msg_pos++];
} break; } break;
@@ -565,6 +569,26 @@ 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 MessageAuctionBidResult: {
AuctionBidResult result = msg.byte;
switch (result) {
case AuctionBidResultNotEnoughMoney:
state->auction_tab_state = AuctionTabStateNotEnoughMoney;
break;
case AuctionBidResultNotEnoughCargoSpace:
state->auction_tab_state = AuctionTabStateNotEnoughCargoSpace;
break;
case AuctionBidResultPurchased:
state->auction_tab_state = AuctionTabStateResult;
break;
case AuctionBidResultAuctionAlreadyFinished:
state->auction_tab_state = AuctionTabStateAlreadyFinished;
break;
case AuctionBidResult_Count:
assert(false && "unhandled message result");
break;
}
} break;
case MessageNotAlive: { case MessageNotAlive: {
// auto-re-login // auto-re-login
if (state->me.base_cost > 0) { if (state->me.base_cost > 0) {
@@ -1272,10 +1296,20 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
} break; } break;
case TabAuction: { case TabAuction: {
u32 yoff = box.y+1; u32 yoff = box.y+1;
drawStatusLine(tui, sbuf, &state->me, box.x+2, yoff);
yoff++;
renderStrToBuffer(tui->frame_buffer, box.x+((box.width - 13)/2), yoff++, "Auction House", screen_dimensions); renderStrToBuffer(tui->frame_buffer, box.x+((box.width - 13)/2), yoff++, "Auction House", screen_dimensions);
yoff++; yoff++;
if (curr.auction.finished_at > curr.auction.started_at) { if (curr.auction.finished_at > curr.auction.started_at) {
if (state->auction_tab_state == AuctionTabStateResult) {
renderStrToBuffer(tui->frame_buffer, box.x+2, yoff++, "Your bid was accepted", screen_dimensions);
yoff++;
} else if (state->auction_tab_state == AuctionTabStateAlreadyFinished) {
renderStrToBuffer(tui->frame_buffer, box.x+2, yoff++, "Your bid was too late..", screen_dimensions);
yoff++;
}
MemoryZero(sbuf, SBUFLEN); MemoryZero(sbuf, SBUFLEN);
sprintf(sbuf, "Sold! %d containers of %s were sold for $%d", curr.auction.qty, COMMODITY_STRINGS[curr.auction.type], curr.auction.price); sprintf(sbuf, "Sold! %d containers of %s were sold for $%d", curr.auction.qty, COMMODITY_STRINGS[curr.auction.type], curr.auction.price);
renderStrToBuffer(tui->frame_buffer, box.x+2, yoff++, sbuf, screen_dimensions); renderStrToBuffer(tui->frame_buffer, box.x+2, yoff++, sbuf, screen_dimensions);
@@ -1294,6 +1328,9 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
renderStrToBuffer(tui->frame_buffer, box.x+2, yoff++, sbuf, screen_dimensions); renderStrToBuffer(tui->frame_buffer, box.x+2, yoff++, sbuf, screen_dimensions);
yoff++; yoff++;
bool player_has_money_for_purchase = state->me.credits > curr.auction.price;
bool player_has_cargo_space_for_purchase = (state->me.vacuum_cargo_slots - usedVacuumCargoSlots(state->me)) > curr.auction.qty;
if (player_has_money_for_purchase && player_has_cargo_space_for_purchase) {
const char* label = "ACCEPT OFFER [ENTER]"; const char* label = "ACCEPT OFFER [ENTER]";
Range1u32 range = { Range1u32 range = {
.min = XYToPos(box.x+6, yoff, screen_dimensions.width), .min = XYToPos(box.x+6, yoff, screen_dimensions.width),
@@ -1314,6 +1351,26 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
state->auction_tab_state = AuctionTabStateLoading; state->auction_tab_state = AuctionTabStateLoading;
} }
} else {
if (!player_has_money_for_purchase) {
const char* no_money_label = "You do not have enough money";
Range1u32 range = {
.min = XYToPos(box.x+6, yoff, screen_dimensions.width),
.max = XYToPos(box.x+6+strlen(no_money_label), yoff, screen_dimensions.width),
};
colorizeRange(tui, range, ANSI_DULL_RED, ANSI_WHITE);
renderStrToBuffer(tui->frame_buffer, box.x+6, yoff++, no_money_label, screen_dimensions);
}
if (!player_has_cargo_space_for_purchase) {
const char* no_cargo_label = "You do not have enough cargo space";
Range1u32 range = {
.min = XYToPos(box.x+6, yoff, screen_dimensions.width),
.max = XYToPos(box.x+6+strlen(no_cargo_label), yoff, screen_dimensions.width),
};
colorizeRange(tui, range, ANSI_DULL_RED, ANSI_WHITE);
renderStrToBuffer(tui->frame_buffer, box.x+6, yoff++, no_cargo_label, screen_dimensions);
}
}
} else if (state->auction_tab_state == AuctionTabStateLoading) { } else if (state->auction_tab_state == AuctionTabStateLoading) {
renderStrToBuffer(tui->frame_buffer, box.x+((box.width - 13)/2), yoff++, "Bid submitted...", screen_dimensions); renderStrToBuffer(tui->frame_buffer, box.x+((box.width - 13)/2), yoff++, "Bid submitted...", screen_dimensions);
} }
+36 -2
View File
@@ -419,6 +419,16 @@ fn void sendMessagePlayerDetails(PlayerShip ship, SocketAddress addr) {
addSystemMessage((u8*)"MessagePlayerDetails sent"); addSystemMessage((u8*)"MessagePlayerDetails sent");
} }
fn void sendMessageAuctionBidResult(SocketAddress addr, AuctionBidResult result) {
UDPMessage outgoing_message = {.address = addr};
u32 msg_i = 0;
outgoing_message.bytes[msg_i++] = (u8)MessageAuctionBidResult;
outgoing_message.bytes[msg_i++] = result;
outgoing_message.bytes_len = msg_i;
outgoingMessageQueuePush(state.network_send_queue, &outgoing_message);
addSystemMessage((u8*)"Message AuctionBidResult sent");
}
fn void handleIncomingMessage(u8* message, u32 len, SocketAddress sender, i32 socket) { fn void handleIncomingMessage(u8* message, u32 len, SocketAddress sender, i32 socket) {
dbg("%d: %s from %s:%d\n", len, command_type_strings[message[0]], inet_ntoa(sender.sin_addr), sender.sin_port); dbg("%d: %s from %s:%d\n", len, command_type_strings[message[0]], inet_ntoa(sender.sin_addr), sender.sin_port);
char sbuf[SBUFLEN] = {0}; char sbuf[SBUFLEN] = {0};
@@ -435,6 +445,7 @@ fn void handleIncomingMessage(u8* message, u32 len, SocketAddress sender, i32 so
.capacity = 0, .capacity = 0,
}; };
switch (parsed.type) { switch (parsed.type) {
case CommandBuyAuction: break; // nothing to parse but the type
case CommandLogin: { case CommandLogin: {
// parse the login command // parse the login command
parsed.alt_port = ~readU16FromBufferLE(message + msg_idx); parsed.alt_port = ~readU16FromBufferLE(message + msg_idx);
@@ -690,6 +701,29 @@ 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 CommandBuyAuction: {
if (client_handle == 0) break;
Account* account = &state.accounts[client->account_id];
StarSystem* player_sys = &state.map[account->ship.system_idx];
bool is_auction_still_running = player_sys->auction.finished_at == 0;
if (is_auction_still_running) {
bool player_has_money_for_purchase = account->ship.credits >= player_sys->auction.price;
bool player_has_cargo_space_for_purchase = (account->ship.vacuum_cargo_slots - usedVacuumCargoSlots(account->ship)) >= player_sys->auction.qty;
if (player_has_cargo_space_for_purchase && player_has_money_for_purchase) {
player_sys->auction.finished_at = state.frame;
account->ship.credits -= player_sys->auction.price;
account->ship.commodities[player_sys->auction.type] += player_sys->auction.qty;
sendMessageAuctionBidResult(sender, AuctionBidResultPurchased);
sendMessagePlayerDetails(account->ship, sender);
} else if (!player_has_money_for_purchase) {
sendMessageAuctionBidResult(sender, AuctionBidResultNotEnoughMoney);
} else {
sendMessageAuctionBidResult(sender, AuctionBidResultNotEnoughCargoSpace);
}
} else {
sendMessageAuctionBidResult(sender, AuctionBidResultAuctionAlreadyFinished);
}
} break;
case CommandAcceptPassengerJob: { case CommandAcceptPassengerJob: {
if (client_handle == 0) break; if (client_handle == 0) break;
// move the offer out of the system and INTO the PlayerShip // move the offer out of the system and INTO the PlayerShip
@@ -937,7 +971,7 @@ fn void* gameLoop(void* params) {
.base_cost = template.base_cost, .base_cost = template.base_cost,
.remaining_mortgage = template.base_cost - STARTING_DOWN_PAYMENT, .remaining_mortgage = template.base_cost - STARTING_DOWN_PAYMENT,
.interest_rate = calcInterestRate(template.base_cost, STARTING_DOWN_PAYMENT), .interest_rate = calcInterestRate(template.base_cost, STARTING_DOWN_PAYMENT),
.credits = 2000.0, .credits = 20000.0,
.cu_m_fuel = template.cu_m_fuel, .cu_m_fuel = template.cu_m_fuel,
.cu_m_o2 = template.cu_m_o2, .cu_m_o2 = template.cu_m_o2,
.id = account->id, .id = account->id,
@@ -1039,7 +1073,7 @@ fn void* gameLoop(void* params) {
f32 t_sec = ((f32)state.frame - (f32)grace_period_ends_at) / (f32)GOAL_GAME_LOOPS_PER_S; f32 t_sec = ((f32)state.frame - (f32)grace_period_ends_at) / (f32)GOAL_GAME_LOOPS_PER_S;
// t is in minutes // t is in minutes
f32 t = t_sec / 60; f32 t = t_sec / 60;
f32 decay = -0.30 * t; f32 decay = -0.50 * t;
f32 floor_price = COMMODITIES[sys->auction.type].price * 0.9; f32 floor_price = COMMODITIES[sys->auction.type].price * 0.9;
sys->auction.price = Max((initial_price * pow(EULERS_E, decay)), floor_price); sys->auction.price = Max((initial_price * pow(EULERS_E, decay)), floor_price);
} }
+10
View File
@@ -342,6 +342,14 @@ global str STAR_NAMES[STAR_SYSTEM_COUNT] = {
*/ */
}; };
typedef enum AuctionBidResult {
AuctionBidResultPurchased,
AuctionBidResultNotEnoughMoney,
AuctionBidResultNotEnoughCargoSpace,
AuctionBidResultAuctionAlreadyFinished,
AuctionBidResult_Count
} AuctionBidResult;
typedef enum Direction { typedef enum Direction {
DirectionInvalid, DirectionInvalid,
North, North,
@@ -396,6 +404,7 @@ typedef enum Message {
MessageJobComplete, MessageJobComplete,
MessageNotAlive, MessageNotAlive,
MessageAuctionDetails, MessageAuctionDetails,
MessageAuctionBidResult,
Message_Count, Message_Count,
} Message; } Message;
@@ -415,6 +424,7 @@ static const char* MESSAGE_STRINGS[] = {
"JobAcceptResult", "JobAcceptResult",
"NotAlive", "NotAlive",
"AuctionDetails", "AuctionDetails",
"AuctionBidResult",
}; };
///// shared helper functions ///// shared helper functions