I'm currently making an effort to get as much data as possible into text files in lib/gamedata (here's an example I've just done).
Some of this involves getting information at run time to put into functions that have to be defined at compile time. We have two ways of dealing with this:
Note that the first one the data is actually not in a data file but in a .h template file, but there are cases where it is and the .h file for the preprocessor is just a link to get the name of the function compiled in.
I was going to ask which of these is better, but on looking at them I think the second one clearly wins - which is a shame, since there's only one of those and lots of the other.
Am I right? Have I missed something? Is there another method (not involving lua, python or whatever)?
Some of this involves getting information at run time to put into functions that have to be defined at compile time. We have two ways of dealing with this:
- Preprocessor shenanigans, like:
Code:PROJ_ENV(LIGHT_WEAK, COLOUR_ORANGE, "light")
Code:static const project_feature_handler_f feature_handlers[] = { #define PROJ_ENV(a, col, desc) project_feature_handler_##a, #include "list-project-environs.h" #undef PROJ_ENV NULL };
Code:/* Light up the grid */ static void project_feature_handler_LIGHT_WEAK(project_feature_handler_context_t *context) { const int x = context->x; const int y = context->y; /* Turn on the light */ sqinfo_on(cave->squares[y][x].info, SQUARE_GLOW); /* Grid is in line of sight */ if (square_isview(cave, y, x)) { if (!player->timed[TMD_BLIND]) { /* Observe */ context->obvious = true; } /* Fully update the visuals */ player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); } }
- Explicit coupling, like:
Code:name:BA_ACID hit:100 effect:BALL:ACID:2 dice:15+1d$S expr:S:MONSTER_LEVEL:* 3
Code:expression_base_value_f spell_value_base_by_name(const char *name) { static const struct value_base_s { const char *name; expression_base_value_f function; } value_bases[] = { { "MONSTER_LEVEL", spell_value_base_monster_level }, { "PLAYER_LEVEL", spell_value_base_player_level }, { "DUNGEON_LEVEL", spell_value_base_dungeon_level }, { "MAX_SIGHT", spell_value_base_max_sight }, { "FOOD_FAINT", spell_value_base_food_faint }, { "FOOD_STARVE", spell_value_base_food_starve }, { "WEAPON_DAMAGE", spell_value_base_weapon_damage }, { NULL, NULL }, }; const struct value_base_s *current = value_bases; while (current->name != NULL && current->function != NULL) { if (my_stricmp(name, current->name) == 0) return current->function; current++; } return NULL; }
Code:static int spell_value_base_monster_level(void) { int level = 0; /* Check the reference race first */ if (ref_race) level = ref_race->level; /* Otherwise the current monster if there is one */ else if (cave->mon_current > 0) level = cave_monster(cave, cave->mon_current)->race->level; return level; }
Note that the first one the data is actually not in a data file but in a .h template file, but there are cases where it is and the .h file for the preprocessor is just a link to get the name of the function compiled in.
I was going to ask which of these is better, but on looking at them I think the second one clearly wins - which is a shame, since there's only one of those and lots of the other.
Am I right? Have I missed something? Is there another method (not involving lua, python or whatever)?
Comment