Compare commits

...

3 Commits

@ -13,7 +13,6 @@ D = bpy.data
ROOMS_EXPORT_NAME = "rooms"
EXPORT_DIRECTORY = "../assets/exported_3d"
if os.path.exists(bpy.path.abspath(f"//{EXPORT_DIRECTORY}")):
shutil.rmtree(bpy.path.abspath(f"//{EXPORT_DIRECTORY}"))
os.makedirs(bpy.path.abspath(f"//{EXPORT_DIRECTORY}"))
@ -152,6 +151,7 @@ def export_armatures():
with open(output_filepath, "wb") as f:
write_b8(f, True) # first byte is true if it's an armature file
write_string(f, armature_object.name)
write_string(f, mesh_image_filename)
bones_in_armature = []
for b in armature_object.data.bones:
@ -173,6 +173,7 @@ def export_armatures():
assert False, f"Couldn't find parent of bone {b}"
#print(f"Parent of bone {b.name} is index {parent_index} in list {bones_in_armature}")
write_string(f, b.name)
write_i32(f, parent_index)
write_4x4matrix(f, model_space_pose)
write_4x4matrix(f, inverse_model_space_pose)

115
main.c

@ -916,6 +916,7 @@ typedef struct Bone
struct Bone *parent;
Mat4 matrix_local;
Mat4 inverse_model_space_pos;
MD_String8 name;
float length;
} Bone;
@ -1096,6 +1097,8 @@ Armature load_armature(MD_Arena *arena, MD_String8 binary_file, MD_String8 armat
ser_bool(&ser, &is_armature);
assert(is_armature);
ser_MD_String8(&ser, &to_return.name, arena);
MD_String8 image_filename;
ser_MD_String8(&ser, &image_filename, scratch.arena);
arena->align = 16; // SSE requires quaternions are 16 byte aligned
@ -1113,6 +1116,7 @@ Armature load_armature(MD_Arena *arena, MD_String8 binary_file, MD_String8 armat
BlenderMat inverse_model_space_pose;
MD_i32 parent_index;
ser_MD_String8(&ser, &next_bone->name, arena);
ser_int(&ser, &parent_index);
ser_BlenderMat(&ser, &model_space_pose);
ser_BlenderMat(&ser, &inverse_model_space_pose);
@ -1273,7 +1277,7 @@ Room *get_cur_room(GameState *gs, ThreeDeeLevel *level)
Room *in_room = 0;
for(Room *cur = level->room_list; cur; cur = cur->next)
{
if(MD_S8Match(cur->name, gs->current_room_name, 0))
if(MD_S8Match(cur->name, gs->player->current_room_name, 0))
{
in_room = cur;
break;
@ -2009,7 +2013,7 @@ Entity *new_entity(GameState *gs)
}
}
assert(false);
return NULL;
return 0;
}
typedef struct ToVisit {
@ -2143,45 +2147,46 @@ Vec2 point_plane(Vec3 p)
#define parse_enumstr(arena, enum_str, errors, string_array, enum_kind_name, prefix) parse_enumstr_impl(arena, enum_str, string_array, ARRLEN(string_array), errors, enum_kind_name, prefix)
ThreeDeeLevel level_threedee = {0};
void transition_to_room(GameState *gs, ThreeDeeLevel *level, MD_String8 new_room_name)
{
Log("Transitioning to %.*s...\n", MD_S8VArg(new_room_name));
assert(gs);
(void)level;
gs->player->current_room_name = new_room_name;
}
void initialize_gamestate_from_threedee_level(GameState *gs, ThreeDeeLevel *level)
{
memset(gs, 0, sizeof(GameState));
rnd_gamerand_seed(&gs->random, RANDOM_SEED);
// the target room will be whichever room has the player
// make entities for all rooms
bool found_player = false;
for(Room *cur_room = level->room_list; cur_room; cur_room = cur_room->next)
{
for(PlacedEntity *cur = cur_room->placed_entity_list; cur; cur = cur->next)
for (PlacedEntity *cur = cur_room->placed_entity_list; cur; cur = cur->next)
{
if(cur->npc_kind == NPC_Player)
Entity *cur_entity = new_entity(gs);
cur_entity->npc_kind = cur->npc_kind;
cur_entity->pos = point_plane(cur->t.offset);
cur_entity->is_npc = true;
cur_entity->current_room_name = cur_room->name;
if (cur_entity->npc_kind == NPC_Player)
{
gs->current_room_name = cur_room->name;
break;
assert(!found_player);
found_player = true;
gs->player = cur_entity;
}
}
if(gs->current_room_name.size > 0) break;
}
Room *in_room = get_cur_room(gs, level);
bool found_player = false;
for(PlacedEntity *cur = in_room->placed_entity_list; cur; cur = cur->next)
{
Entity *cur_entity = new_entity(gs);
cur_entity->npc_kind = cur->npc_kind;
cur_entity->pos = point_plane(cur->t.offset);
cur_entity->is_npc = true;
if(cur_entity->npc_kind == NPC_Player)
{
found_player = true;
gs->player = cur_entity;
}
}
assert(found_player);
gs->world_entity = new_entity(gs);
gs->world_entity->is_world = true;
ENTITIES_ITER(gs->entities)
{
it->rotation = PI32;
@ -2378,9 +2383,13 @@ void initialize_gamestate_from_threedee_level(GameState *gs, ThreeDeeLevel *leve
it->perceptions_dirty = false; // nobody should say anything about jester memories
}
}
transition_to_room(gs, &level_threedee, gs->player->current_room_name);
}
ThreeDeeLevel level_threedee = {0};
void reset_level()
{
@ -3304,6 +3313,7 @@ MD_String8 make_devtools_help(MD_Arena *arena)
P("9 - instantly wins the game\n");
P("P - toggles spall profiling on/off, don't leave on for very long as it consumes a lot of storage if you do that. The resulting spall trace is saved to the file '%s'\n", PROFILING_SAVE_FILENAME);
P("If you hover over somebody it will display some parts of their memories, can be somewhat helpful\n");
P("P - immediately kills %s\n", characters[NPC_Raphael].name);
#undef P
MD_String8 to_return = MD_S8ListJoin(arena, list, &(MD_StringJoin){0});
@ -3380,7 +3390,7 @@ void init(void)
shifted_farmer_armature = load_armature(persistent_arena, binary_file, MD_S8Lit("Farmer.bin"));
shifted_farmer_armature.image = image_shifted_farmer;
Log("Done.\n");
Log("Done. Used %f of the frame arena, %llu kB\n", (double) frame_arena->pos / (double)frame_arena->cap, (frame_arena->pos/1024));
MD_ArenaClear(frame_arena);
@ -4642,7 +4652,7 @@ Vec2 move_and_slide(MoveSlideParams p)
{
ENTITIES_ITER(gs.entities)
{
if (it != p.from && !(it->is_npc && it->dead) && !it->is_world)
if (it != p.from && !(it->is_npc && it->dead) && !it->is_world && MD_S8Match(it->current_room_name, p.from->current_room_name, 0))
{
BUFF_APPEND(&to_check, ((CollisionObj){.circle.center = it->pos, .circle.radius = entity_radius(it), it}));
}
@ -5875,7 +5885,7 @@ void frame(void)
ENTITIES_ITER(gs.entities)
{
if(it->is_npc)
if(it->is_npc && MD_S8Match(it->current_room_name, gs.player->current_room_name, 0))
{
Transform draw_with = entity_transform(it);
@ -6004,7 +6014,7 @@ void frame(void)
Entity *angel_entity = 0;
ENTITIES_ITER(gs.entities)
{
if (it->is_npc && it->npc_kind == NPC_Angel)
if (it->is_npc && it->npc_kind == NPC_Angel && MD_S8Match(it->current_room_name, gs.player->current_room_name, 0))
{
assert(!angel_entity);
angel_entity = it;
@ -6096,7 +6106,7 @@ void frame(void)
draw_centered_text((TextParams){false, mission_text, V2(screen_size().x * 0.5f, screen_size().y * 0.25f + vert), blendalpha(WHITE, visible), mission_font_scale, .use_font = &font_for_text_input, .layer = LAYER_ANGEL_SCREEN});
if(imbutton(aabb_centered(V2(screen_size().x/2.0f, screen_size().y*0.25f - vert), MulV2F(V2(170.0f, button_height), visible)), visible, MD_S8Lit("Accept"), .layer = LAYER_ANGEL_SCREEN, .font = &font_for_text_input))
{
Log("Accepting mission...\n");
transition_to_room(&gs, &level_threedee, MD_S8Lit("Forest"));
}
}
else
@ -6147,7 +6157,7 @@ void frame(void)
{
ENTITIES_ITER(gs.entities)
{
if (it->is_npc && it->npc_kind != NPC_Player)
if (it->is_npc && it->npc_kind != NPC_Player && MD_S8Match(it->current_room_name, gs.player->current_room_name, 0))
{
if(it->undismissed_action)
{
@ -6917,7 +6927,7 @@ ISANERROR("Don't know how to do this stuff on this platform.")
else if(it->npc_kind == NPC_Angel)
{
action = "assign_gameplay_objective";
action_argument = "KILL Daniel";
action_argument = "KILL Raphael";
}
char *rigged_dialog[] = {
"Repeated amounts of testing dialog overwhelmingly in support of the mulaney brothers",
@ -6989,6 +6999,7 @@ ISANERROR("Don't know how to do this stuff on this platform.")
bool entity_talkable = true;
if (entity_talkable) entity_talkable = entity_talkable && (*it)->is_npc;
if (entity_talkable) entity_talkable = entity_talkable && (*it)->npc_kind != NPC_Player;
if (entity_talkable) entity_talkable = entity_talkable && !(*it)->killed;
#ifdef WEB
if (entity_talkable) entity_talkable = entity_talkable && (*it)->gen_request_id == 0;
#endif
@ -7089,7 +7100,45 @@ ISANERROR("Don't know how to do this stuff on this platform.")
pressed = before_gameplay_loops;
// check if game objective has been fulfilled
{
if(gs.no_angel_screen)
{
bool fulfilled = false;
assert(gs.assigned_objective);
switch(gs.objective.verb)
{
case KILL:
ENTITIES_ITER(gs.entities)
{
if(it->npc_kind == gs.objective.who_to_kill && it->killed)
{
fulfilled = true;
break;
}
}
break;
}
if(fulfilled)
{
gs.assigned_objective = false;
transition_to_room(&gs, &level_threedee, MD_S8Lit("StartingRoom"));
}
}
}
#ifdef DEVTOOLS
if(keypressed[SAPP_KEYCODE_P])
{
ENTITIES_ITER(gs.entities)
{
if(it->npc_kind == NPC_Raphael)
{
it->killed = true;
}
}
}
if(flycam)
{
Basis basis = flycam_basis();

@ -238,6 +238,7 @@ typedef struct Entity
Vec2 vel; // only used sometimes, like in old man and bullet
float damage; // at 1.0, dead! zero initialized
bool dead;
MD_String8 current_room_name;
// npcs
NpcKind npc_kind;
@ -291,7 +292,6 @@ typedef struct GameState {
uint64_t tick;
bool won;
MD_String8 current_room_name; // the string is allocated on the level that is currently loaded
bool finished_reading_dying_dialog;
bool no_angel_screen;
bool assigned_objective;

@ -1,9 +1,17 @@
Urgent:
- White sidebars on angel's speech that recede away.
- Mystical particles that float upwards.
- Gradient png on the bottom that has more alpha, controlled by same parameter as white sidebars.
- Fix everything about the shotgun, put shotgun away. Make them understand they're holding their shotgun more. REALLY look into characters not being able to shoot eachother
- On startup if devtools print the estimated cost per generation request of the worst offending character
- Remove (MD_) prefix from project
- Fix camera angle on forest map, probably introduce custom camera angles per map
- In debugtools show number of arenas allocated, and total megabytes allocated in arenas
- Angel dialog improvements:
- White sidebars on angel's speech that recede away.
- Mystical particles that float upwards.
- Gradient png on the bottom that has more alpha, controlled by same parameter as white sidebars.
- Fix everything about the shotgun, test put shotgun away. Make them understand they're holding their shotgun more. REALLY look into characters not being able to shoot eachother
- Cost estimation:
- On startup if devtools print the estimated cost per generation request of the worst offending character
- Show in upper right a $ amount for AI costs so far to user
- simple room transition system for angel/real map interop, angel room
- angel character that gives you randomized goals such as (kill so and so) or (befriend blank) or (get john to go to other room), and decides itself with gpt when you're done with the game, when you've 'learned your lesson'.
- can't interact with characters while they're thinking

Loading…
Cancel
Save