This commit is contained in:
Tenari
2026-03-10 07:18:40 -05:00
parent 5c177d5071
commit f71295dcc1
4 changed files with 74 additions and 249 deletions
+3 -61
View File
@@ -77,22 +77,6 @@ typedef enum SpeechTailDirection {
SpeechTailDirection_Count
} SpeechTailDirection;
typedef struct Entity {
EntityType type;
u8 x;
u8 y;
u8 color;
u64 features;
u64 id;
StringChunkList name;
} Entity;
typedef struct EntityList {
u64 length; // the currently used length
u64 capacity;
Entity* items;
} EntityList;
typedef struct TransactionResult {
bool buying;
u32 qty;
@@ -108,13 +92,11 @@ typedef struct ParsedServerMessage {
u32 ip2;
u64 id;
u64 server_frame;
XYZ xyz;
Pos2u8 positions[STAR_SYSTEM_COUNT];
PlanetType planet_types[MAX_PLANETS*STAR_SYSTEM_COUNT];
StarSystem sys;
PlayerShip ship;
TransactionResult tx_result;
//Entity entities[PARSED_CLIENT_ENTITY_LEN];
//u64 ids[PARSED_IDS_LEN];
} ParsedServerMessage;
@@ -145,11 +127,9 @@ typedef struct MenuState {
typedef struct GameState {
Screen screen;
Screen old_screen;
EntityList entities;
PlayerShip me;
u64 server_frame;
u64 loop_count;
Arena entity_arena;
StringArena string_arena;
LoginState login_state;
MenuState menu;
@@ -222,33 +202,6 @@ fn ParsedServerMessage* psmThreadSafeNonblockingQueuePop(ParsedServerMessageThre
return result;
}
fn void entityPush(EntityList* list, Entity e) {
if (list->length >= list->capacity) {
arenaAllocArray(&state.entity_arena, Entity, list->capacity);
list->capacity = list->capacity * 2;
}
list->items[list->length] = e;
list->length += 1;
}
fn bool entityDelete(EntityList* list, u64 id) {
assert(list->length > 0);
if (list->items[list->length - 1].id == id) {
list->length -= 1;
return true;
} else {
for (u32 i = 0; i < list->length; i++) {
if (list->items[i].id == id) {
// copy the last one over the one we are deleting
list->items[i] = list->items[list->length - 1];
list->length -= 1;
return true;
}
}
}
return false;
}
fn void addSystemMessage(u8* msg) {
// save the message to our system_messages ring buffer
memset(system_messages[system_message_index].items, 0, SYSTEM_MESSAGES_LEN);
@@ -341,13 +294,6 @@ fn void renderStaticAssetToPixelBuffer(TuiState* tui, u8* asset, u32 len, u16 x,
}
}
fn void clearServerSentState() {
arenaClear(&state.entity_arena);
state.entities.capacity = 64;
state.entities.length = 0;
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;
@@ -440,7 +386,7 @@ fn void handleIncomingMessage(u8* message, u32 len, SocketAddress sender, i32 so
msg_pos += 4;
parsed.ship.cu_m_o2 = readU32FromBufferLE(message + msg_pos);
msg_pos += 4;
parsed.ship.credits = readF32FromBufferLE(message + msg_pos);
parsed.ship.credits = readU32FromBufferLE(message + msg_pos);
msg_pos += 4;
parsed.ship.id = readU64FromBufferLE(message + msg_pos);
msg_pos += 8;
@@ -697,7 +643,7 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
f32 mortgage_rate = calcInterestRate(selected_ship_cost, STARTING_DOWN_PAYMENT);
f32 r = mortgage_rate / 100.0;
u32 payment = principal_borrowed * r;
sprintf(sbuf, "Mortgage: $%d @ %f%% = $%d interest after first turn", selected_ship_cost - STARTING_DOWN_PAYMENT, mortgage_rate, payment);
sprintf(sbuf, "Mortgage: $%d @ %.2f%% = $%d interest after first turn", selected_ship_cost - STARTING_DOWN_PAYMENT, mortgage_rate, payment);
renderStrToBuffer(tui->frame_buffer, 5, ++line, sbuf, screen_dimensions);
line++;
// the table
@@ -936,7 +882,7 @@ fn bool updateAndRender(TuiState* tui, void* s, u8* input_buffer, u64 loop_count
renderStrToBuffer(tui->frame_buffer, box.x+2, yoff++, sbuf, screen_dimensions);
MemoryZero(sbuf, SBUFLEN);
sprintf(sbuf, "Credits: %.2f", state->me.credits);
sprintf(sbuf, "Credits: %d", state->me.credits);
renderStrToBuffer(tui->frame_buffer, box.x+2, yoff++, sbuf, screen_dimensions);
u32 used_cargo = usedVacuumCargoSlots(state->me);
@@ -1363,10 +1309,6 @@ i32 main(i32 argc, ptr argv[]) {
// clear and init the state
arenaInit(&permanent_arena);
arenaInit(&state.entity_arena);
state.entities.capacity = 64;
state.entities.length = 0;
state.entities.items = arenaAllocArray(&state.entity_arena, Entity, state.entities.capacity);
arenaInit(&state.string_arena.a);
state.string_arena.mutex = newMutex();
state.message_input = stringChunkListInit(&state.string_arena);
-96
View File
@@ -24,99 +24,3 @@ fn str strForPlanet(PlanetType type) {
}
}
fn str charForEntity(EntityType e) {
switch (e) {
case EntityStarSystem:
return "";
case EntityCharacter:
return "🧙";
//return "웃";
case EntityNull:
case EntityType_Count:
//default: // commented out so that we get a warning for missing entity
return " ";
}
}
/* HERE IS WHERE I USUALLY PUT THE "room" OR "map" DRAWING FUNCTION
*
fn void renderRoom(Pixel* buf, u32 x, u32 y, RenderableRoom* room, Dim2 screen_dimensions, bool active) {
// x,y is starting cursor location of upper-left corner
Box b = { .x = x, .y = y, .width = ROOM_WIDTH*2, .height = ROOM_HEIGHT };
drawAnsiBox(buf, b, screen_dimensions, active);
// start printing the rows
// move cursor to beginning of the room
for (i32 j = 0; j < ROOM_HEIGHT; j++) {
for (i32 i = 0; i < ROOM_WIDTH; i++) {
u32 roompos = XYToPos(i, j, ROOM_WIDTH);
if (!room->visible[roompos] && room->memory[roompos] == RememberedTileQualityNone) {
continue;
}
u32 bufpos = (x+1+(i*2)) + (screen_dimensions.width*(y+1+j));
str fg_char = charForEntity(room->foreground[roompos]);
RGB background_color = colorForTile(room->background[roompos]);
if (room->visible[roompos]) {
buf[bufpos].foreground = ansiColorForEntity(room->foreground[roompos]);
if (room->light[roompos] < VISIBLE_BRIGHTNESS_CUTOFF) {
fg_char = charForEntity(EntityMurkyUnknown);
background_color = rgbDarken(background_color, 0.8);
}
} else if (room->memory[roompos] == RememberedTileQualityDim) {
background_color = rgbDarken(background_color, 0.4);
buf[bufpos].foreground = ansiColorForEntity(room->foreground[roompos]);
fg_char = charForEntity(EntityMurkyUnknown);
} else if (room->memory[roompos] == RememberedTileQualityClear) {
background_color = rgbDarken(background_color, 0.6);
buf[bufpos].foreground = ansiColorForEntity(room->foreground[roompos]);
}
buf[bufpos].background = rgbToAnsi(background_color);
Utf8Character first_character_class = classifyUtf8Character((u8)fg_char[0]);
// if it's a single ASCII character
if (first_character_class == Utf8CharacterAscii && fg_char[1] == '\0') {
buf[bufpos].bytes[0] = fg_char[0];
// if it's a pair of ASCII characters
} else if (first_character_class == Utf8CharacterAscii && fg_char[1] > 0 && fg_char[2] == '\0') {
buf[bufpos].bytes[0] = fg_char[0];
buf[bufpos+1].bytes[0] = fg_char[1];
buf[bufpos+1].background = buf[bufpos].background;
buf[bufpos+1].foreground = buf[bufpos].foreground;
} else if (first_character_class == Utf8CharacterThreeByte) {
if (strlen(fg_char) == 3) {// handle 2-wide characters
buf[bufpos+1].background = buf[bufpos].background;
buf[bufpos+1].foreground = buf[bufpos].foreground;
}
for (u32 k = 0; k < strlen(fg_char)/3; k++) {
if (k != 0) {
buf[bufpos+k].background = buf[bufpos].background;
buf[bufpos+k].foreground = buf[bufpos].foreground;
}
for (u32 l = 0; l < 3; l++) {
buf[bufpos+k].bytes[l] = fg_char[l+(k*3)];
}
}
} else if (first_character_class == Utf8CharacterFourByte) {
if (strlen(fg_char) == UTF8_MAX_WIDTH) {// assume all of these characters are 2-wide
buf[bufpos+1].background = buf[bufpos].background;
buf[bufpos+1].foreground = buf[bufpos].foreground;
}
for (u32 k = 0; k < strlen(fg_char)/UTF8_MAX_WIDTH; k++) {
for (u32 l = 0; l < UTF8_MAX_WIDTH; l++) {
buf[bufpos+k].bytes[l] = fg_char[l+(k*UTF8_MAX_WIDTH)];
}
}
// handle secondary bytes that didn't divide evenly
for (u32 k = 0; k < strlen(fg_char)%UTF8_MAX_WIDTH; k++) {
buf[bufpos+1].background = buf[bufpos].background;
buf[bufpos+1].foreground = buf[bufpos].foreground;
buf[bufpos+1].bytes[k] = fg_char[UTF8_MAX_WIDTH+k];
}
} else {
assert(false && "unhandled bullshit");
}
}
}
}
*/
+15 -14
View File
@@ -17,7 +17,6 @@
#include "string_chunk.c"
///// CONSTANTS
#define MAX_ENTITIES (2<<18)
#define LEFT_ROOM_ENTITES_LEN (KB(1))
#define ROOM_MAP_COLLISIONS_LEN MAX_ROOMS/8
#define CLIENT_COMMAND_LIST_LEN 8
@@ -282,7 +281,7 @@ fn UDPMessage makeMessagePlayerDetails(PlayerShip ship) {
msg_i += writeF32ToBufferLE(outgoing_message.bytes + msg_i, ship.interest_rate);
msg_i += writeU32ToBufferLE(outgoing_message.bytes + msg_i, ship.cu_m_fuel);
msg_i += writeU32ToBufferLE(outgoing_message.bytes + msg_i, ship.cu_m_o2);
msg_i += writeF32ToBufferLE(outgoing_message.bytes + msg_i, ship.credits);
msg_i += writeU32ToBufferLE(outgoing_message.bytes + msg_i, ship.credits);
msg_i += writeU64ToBufferLE(outgoing_message.bytes + msg_i, ship.id);
for (u32 i = 0; i < Commodity_Count; i++) {
msg_i += writeU32ToBufferLE(outgoing_message.bytes + msg_i, ship.commodities[i]);
@@ -524,14 +523,15 @@ fn void* gameLoop(void* params) {
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;
u32 amount_to_pay = msg.id;
if (amount_to_pay > account->ship.credits) {
amount_to_pay = account->ship.credits;
}
if (amount_to_pay > account->ship.remaining_mortgage) {
amount_to_pay = account->ship.remaining_mortgage;
}
account->ship.credits -= amount_to_pay;
account->ship.remaining_mortgage -= amount_to_pay;
account->changed = true;
sendMessagePayoffResult(sender);
} break;
@@ -839,7 +839,8 @@ fn void* gameLoop(void* params) {
// increase the mortgage from interest
if (!shipIsNull(&acct->ship)) {
if (acct->ship.remaining_mortgage > 0) {
acct->ship.remaining_mortgage += acct->ship.remaining_mortgage * (acct->ship.interest_rate / 100.0);
f64 compounding = ((f64)acct->ship.remaining_mortgage) * (f64)(acct->ship.interest_rate / 100.0);
acct->ship.remaining_mortgage += (u32)compounding;
}
}
}
@@ -853,7 +854,7 @@ fn void* gameLoop(void* params) {
if (acct->ship.remaining_mortgage == 0) {
state.winner_id = acct->id;
state.someone_won = true;
printf("someone WON!!! %d\n", i);
printf("%s WON!!! %d\n", acct->name.bytes, i);
acct->changed = true;
break;
}
@@ -961,7 +962,7 @@ i32 main(i32 argc, ptr argv[]) {
setLowProductionCommodity(p, CommodityHighGradeOre);
setLowProductionCommodity(p, CommodityCommonMetals);
setLowProductionCommodity(p, CommodityRareMetals);
setLowProductionCommodity(p, CommodityPreciousMetals);
//setLowProductionCommodity(p, CommodityPreciousMetals);
} break;
case PlanetTypeGas: {
// a lot of fuel and chemicals
@@ -975,7 +976,7 @@ i32 main(i32 argc, ptr argv[]) {
setLowProductionCommodity(p, CommodityHighGradeOre);
setLowProductionCommodity(p, CommodityCommonMetals);
setLowProductionCommodity(p, CommodityRareMetals);
setLowProductionCommodity(p, CommodityPreciousMetals);
//setLowProductionCommodity(p, CommodityPreciousMetals);
setLowProductionCommodity(p, CommodityClothes);
setLowProductionCommodity(p, CommodityRawTextiles);
setLowProductionCommodity(p, CommodityGlass);
@@ -1002,7 +1003,7 @@ i32 main(i32 argc, ptr argv[]) {
setHighProductionCommodity(p, CommodityHighGradeOre);
setHighProductionCommodity(p, CommodityCommonMetals);
setHighProductionCommodity(p, CommodityRareMetals);
setHighProductionCommodity(p, CommodityPreciousMetals);
//setHighProductionCommodity(p, CommodityPreciousMetals);
setHighProductionCommodity(p, CommoditySemiConductors);
setLowProductionCommodity(p, CommodityHydrogenFuel);
+56 -78
View File
@@ -12,24 +12,6 @@
#define MAP_HEIGHT (12)
#define MAX_PLANETS (3)
typedef enum EntityFeature {
FeatureWalksAround,
FeatureCanFight,
EntityFeature_Count
} EntityFeature;
typedef enum EntityType {
EntityNull,
EntityStarSystem,
EntityCharacter,
EntityType_Count,
} EntityType;
static const char* ENTITY_STRINGS[] = {
"NULL",
"StarSystem",
"Character",
};
typedef enum ShipType {
ShipSparrow,
ShipDart,
@@ -37,6 +19,7 @@ typedef enum ShipType {
// ShipNX400,
ShipType_Count,
} ShipType;
global str SHIP_TYPE_STRINGS[] = {
"Sparrow",
"Dart",
@@ -89,11 +72,6 @@ global ShipTemplate SHIPS[] = {
},*/
};
fn f32 calcInterestRate(u32 cost, u32 down_payment) {
f32 mortgage_rate = 10.0 *(1.0 - (3.0*(f32)down_payment / ((f32)cost/3.0)));
return mortgage_rate;
}
global FieldDescriptor SHIP_FIELDS[SHIP_DETAIL_COUNT] = {
{ "Type", FieldTypeEnum, offsetof(ShipTemplate, type), 16, (str*)&SHIP_TYPE_STRINGS },
{ "Cost", FieldTypeU32, offsetof(ShipTemplate, base_cost), 8 },
@@ -130,7 +108,7 @@ typedef enum CommodityType {
CommoditySemiConductors,
CommodityCommonMetals,
CommodityRareMetals,
CommodityPreciousMetals,
// CommodityPreciousMetals,
CommodityAlcohol,
CommodityClothes,
CommodityPersonalSundries,
@@ -153,13 +131,13 @@ global str COMMODITY_STRINGS[Commodity_Count] = {
"Electronics",
"Glass",
"Hand Tools",
"Semi-conductors (Silicon, Arsenic, Boron)",
"Common Metals (Iron, Nickel, Zinc)",
"Rare Metals (Titanium, Chromium)",
"Precious Metals (Silver, Gold, Platinum)",
"Semi-conductors",//"Semi-conductors (Silicon, Arsenic, Boron)",
"Common Metals",//"Common Metals (Iron, Nickel, Zinc)",
"Rare Metals",//"Rare Metals (Titanium, Chromium)",
// "Precious Metals (Silver, Gold, Platinum)",
"Alcohol",
"Clothes",
"Personal Sundries (Cutlery, Toys, Misc)",
"Personal Sundries",//"Personal Sundries (Cutlery, Toys, Misc)",
"Industrial Chemicals",
};
@@ -188,11 +166,11 @@ typedef struct Commodity {
global Commodity COMMODITIES[Commodity_Count] = {
{ .type = CommodityHydrogenFuel, .unit = StorageUnitKg,
.name = "Hydrogen Fuel",
.price = 10, .qty = 1000, .consumption = 200,
.price = 10, .qty = 10000, .consumption = 100,
},
{ .type = CommodityOxygen, .unit = StorageUnitKg,
.name = "Oxygen",
.price = 5, .qty = 10000, .consumption = 500,
.price = 5, .qty = 10000, .consumption = 100,
},
{ .type = CommodityWater, .unit = StorageUnitContainer,
.name = "Water",
@@ -243,21 +221,21 @@ global Commodity COMMODITIES[Commodity_Count] = {
.price = 5000, .qty = 5, .consumption = 1,
},
{ .type = CommoditySemiConductors, .unit = StorageUnitContainer,
.name = "Semi-conductors (Silicon, Arsenic, Boron)",
.name = "Semi-conductors",//"Semi-conductors (Silicon, Arsenic, Boron)",
.price = 1800, .qty = 40, .consumption = 3,
},
{ .type = CommodityCommonMetals, .unit = StorageUnitContainer,
.name = "Common Metals (Iron, Nickel, Zinc)",
.name = "Common Metals",//"Common Metals (Iron, Nickel, Zinc)",
.price = 1800, .qty = 40, .consumption = 3,
},
{ .type = CommodityRareMetals, .unit = StorageUnitContainer,
.name = "Rare Metals (Titanium, Chromium)",
.name = "Rare Metals",//"Rare Metals (Titanium, Chromium)",
.price = 1800, .qty = 40, .consumption = 3,
},
{ .type = CommodityPreciousMetals, .unit = StorageUnitKg,
/* { .type = CommodityPreciousMetals, .unit = StorageUnitKg,
.name = "Precious Metals (Silver, Gold, Platinum)",
.price = 1800, .qty = 40, .consumption = 3,
},
},*/
{ .type = CommodityAlcohol, .unit = StorageUnitContainer,
.name = "Alcohol",
.price = 1800, .qty = 40, .consumption = 3,
@@ -267,7 +245,7 @@ global Commodity COMMODITIES[Commodity_Count] = {
.price = 1800, .qty = 40, .consumption = 3,
},
{ .type = CommodityPersonalSundries, .unit = StorageUnitContainer,
.name = "Personal Sundries (Cutlery, Toys, Misc)",
.name = "Personal Sundries",//"Personal Sundries (Cutlery, Toys, Misc)",
.price = 1800, .qty = 40, .consumption = 3,
},
{ .type = CommodityIndustrialChemicals, .unit = StorageUnitContainer,
@@ -294,30 +272,6 @@ global FieldDescriptor MARKET_COMMODITY_FIELDS[Commodity_Count] = {
{ "Owned", FieldTypeU32, offsetof(MarketCommodity, owned), 6 },
};
fn f32 priceForCommodity(CommodityType type, u32 quantity, bool bid) {
f32 result = 0.0;
Commodity details = COMMODITIES[type];
f32 max = details.price * 5;
f32 min = (f32)details.price / 5.0;
if (quantity == 0) {
return max;
}
result = ((f32)details.price) * ((f32)details.qty / (f32)quantity); // the bid/ask spread
if (max < result) {
result = max;
}
if (min > result) {
result = min;
}
// the bid/ask spread
if (bid) {
result = result * 0.98;
} else {
result = result * 1.02;
}
return result;
}
typedef struct PlayerShip {
ShipType type;
bool ready_to_depart;
@@ -334,21 +288,11 @@ typedef struct PlayerShip {
f32 interest_rate;
u32 cu_m_fuel; // we are just saying you can buy as much fuel as you want
u32 cu_m_o2; // we are just saying you can buy as much o2 as you want
f32 credits;
u32 credits;
u64 id;
u32 commodities[Commodity_Count];
} PlayerShip;
fn u32 usedVacuumCargoSlots(PlayerShip ship) {
u32 used_cargo = 0;
for (u32 i = 0; i < Commodity_Count; i++) {
if (COMMODITIES[i].unit == StorageUnitContainer) {
used_cargo += ship.commodities[i];
}
}
return used_cargo;
}
typedef enum PlanetType {
PlanetTypeNull,
PlanetTypeEarth,
@@ -418,12 +362,6 @@ global str STAR_NAMES[STAR_SYSTEM_COUNT] = {
"Eltanin",
};
typedef struct XYZ {
i32 x;
i32 y;
i32 z;
} XYZ;
typedef enum Direction {
DirectionInvalid,
North,
@@ -488,6 +426,7 @@ static const char* MESSAGE_STRINGS[] = {
"PayoffResult",
};
///// shared helper functions
fn u32 fuelCostForTravel(u32 drive_efficiency, Pos2 current, Pos2 dest) {
u32 x_distance = Max(current.x, dest.x) - Min(current.x, dest.x);
u32 y_distance = Max(current.y, dest.y) - Min(current.y, dest.y);
@@ -495,4 +434,43 @@ fn u32 fuelCostForTravel(u32 drive_efficiency, Pos2 current, Pos2 dest) {
return (x_distance + y_distance) * fuel_per_dist;
}
fn u32 usedVacuumCargoSlots(PlayerShip ship) {
u32 used_cargo = 0;
for (u32 i = 0; i < Commodity_Count; i++) {
if (COMMODITIES[i].unit == StorageUnitContainer) {
used_cargo += ship.commodities[i];
}
}
return used_cargo;
}
fn f32 priceForCommodity(CommodityType type, u32 quantity, bool bid) {
f32 result = 0.0;
Commodity details = COMMODITIES[type];
f32 max = details.price * 5;
f32 min = (f32)details.price / 5.0;
if (quantity == 0) {
return max;
}
result = ((f32)details.price) * ((f32)details.qty / (f32)quantity); // the bid/ask spread
if (max < result) {
result = max;
}
if (min > result) {
result = min;
}
// the bid/ask spread
if (bid) {
result = result * 0.98;
} else {
result = result * 1.02;
}
return result;
}
fn f32 calcInterestRate(u32 cost, u32 down_payment) {
f32 mortgage_rate = 10.0 *(1.0 - (3.0*(f32)down_payment / ((f32)cost/3.0)));
return mortgage_rate;
}
#endif //GAMESHARED_H