From ae6718ec0fb21077b767e189aca26b0fed488775 Mon Sep 17 00:00:00 2001 From: kasull Date: Wed, 11 Mar 2026 00:24:47 -0400 Subject: editor object placement and context menus replace the editor menubar dropdown flow with a reusable context menu component merge sprite/entity placement into a single object tool persist entities, and add undo support for created sprites and entities --- src/game/world/map.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'src/game/world/map.cpp') diff --git a/src/game/world/map.cpp b/src/game/world/map.cpp index ba6bb00..a44f191 100644 --- a/src/game/world/map.cpp +++ b/src/game/world/map.cpp @@ -303,6 +303,40 @@ STAT map_sprites_from_section( WORLD_MAP* m, GAME_DATA* g, CFG_SECTION* sprites, return parsec > 0 ? STAT_OK : STAT_ERR; } +STAT map_entities_from_section( WORLD_MAP* m, GAME_DATA*, CFG_SECTION* entities, U32 entityc ) { + if( !entityc ) { + dlog( "map_entities_from_section() : no entities in %s\n", m->name ); + return STAT_OK; + } + + U32 parsec = 0; + char entitysec[256] = { 0 }; + for( U32 i = 0; i < entityc; ++i ) { + MAP_ENTITY entity{}; + + sprintf( entitysec, "%d", i ); + CFG_SECTION* s = cfg_section( entities, entitysec ); + if( !s ) { + dlog( "map_entities_from_section() : missing entity %d in %s\n", i, m->name ); + continue; + } + + CFG_INT* classid = cfg_int( s, "classid" ); + CFG_VEC3* pos = cfg_vec3( s, "pos" ); + if( !classid || !pos ) { + dlog( "map_entities_from_section() : invalid entity %d in %s\n", i, m->name ); + continue; + } + + entity.classid = (U32)classid->value; + entity.pos = pos->value; + m->entities.push( entity ); + ++parsec; + } + + return parsec > 0 ? STAT_OK : STAT_ERR; +} + STAT map_skybox_from_section( CFG_SECTION* s, GAME_DATA* g, WORLD_MAP* m ) { CFG_SECTION* props = cfg_section( s, "props" ); if( !props ) @@ -496,6 +530,13 @@ WORLD_MAP* map_from_file( GAME_DATA* game, const char* path ) { if( !OK( map_sprites_from_section( m, game, sprites, spritec->value ) ) ) { delete m; return 0; } } + CFG_INT* entityc = cfg_int( s, "entitycount" ); + if( entityc ) { + CFG_SECTION* entities = cfg_section( s, "entities" ); + if( !entities ) { dlog( errstr, path, "entities" ); delete m; return 0; } + if( !OK( map_entities_from_section( m, game, entities, entityc->value ) ) ) { delete m; return 0; } + } + CFG_VEC3* startpos = cfg_vec3( s, "startpos" ); if( !startpos ) { dlog( errstr, path, "startpos" ); @@ -537,6 +578,7 @@ void map_serialize_info( CFG_SECTION* s, WORLD_MAP* map ) { cfg_int( "polycount", s, map->polygons.size ); cfg_int( "propcount", s, map->props.size ); cfg_int( "spritecount", s, map->sprites.size ); + cfg_int( "entitycount", s, map->entities.size ); cfg_vec3( "startpos", s, map->startpos ); cfg_float( "startang", s, map->startang ); } @@ -597,6 +639,19 @@ void map_serialize_sprites( CFG_SECTION* s, WORLD_MAP* map ) { } ); } +void map_serialize_entities( CFG_SECTION* s, WORLD_MAP* map ) { + CFG_SECTION* entities = cfg_section_new( "entities", s ); + char name[64]; + + U32 i = 0; + map->entities.each( fn( MAP_ENTITY* e ) { + sprintf( name, "%d", i++ ); + CFG_SECTION* entitysec = cfg_section_new( name, entities ); + cfg_int( "classid", entitysec, e->classid ); + cfg_vec3( "pos", entitysec, e->pos ); + } ); +} + void map_serialize_props( CFG_SECTION* s, WORLD_MAP* map ) { CFG_SECTION* props = cfg_section_new( "props", s ); char name[64]; @@ -623,6 +678,7 @@ CFG_SECTION* map_serialize( WORLD_MAP* map ) { map_serialize_walls( s, map ); map_serialize_polygons( s, map ); map_serialize_sprites( s, map ); + map_serialize_entities( s, map ); return s; } -- cgit v1.2.3