diff options
Diffstat (limited to 'src/init1.c')
-rw-r--r-- | src/init1.c | 11819 |
1 files changed, 11819 insertions, 0 deletions
diff --git a/src/init1.c b/src/init1.c new file mode 100644 index 00000000..9715831d --- /dev/null +++ b/src/init1.c @@ -0,0 +1,11819 @@ +/* File: init1.c */ + +/* Purpose: Initialization (part 1) -BEN- */ + +#include "angband.h" + + +/* + * This file is used to initialize various variables and arrays for the + * Angband game. Note the use of "fd_read()" and "fd_write()" to bypass + * the common limitation of "read()" and "write()" to only 32767 bytes + * at a time. + * + * Several of the arrays for Angband are built from "template" files in + * the "lib/file" directory, from which quick-load binary "image" files + * are constructed whenever they are not present in the "lib/data" + * directory, or if those files become obsolete, if we are allowed. + * + * Warning -- the "ascii" file parsers use a minor hack to collect the + * name and text information in a single pass. Thus, the game will not + * be able to load any template file with more than 20K of names or 60K + * of text, even though technically, up to 64K should be legal. + */ + + +/*** Helper arrays for parsing ascii template files ***/ + +/* + * Monster Blow Methods + */ +static cptr r_info_blow_method[] = +{ + "*", + "HIT", + "TOUCH", + "PUNCH", + "KICK", + "CLAW", + "BITE", + "STING", + "XXX1", + "BUTT", + "CRUSH", + "ENGULF", + "CHARGE", + "CRAWL", + "DROOL", + "SPIT", + "EXPLODE", + "GAZE", + "WAIL", + "SPORE", + "XXX4", + "BEG", + "INSULT", + "MOAN", + "SHOW", + NULL +}; + + +/* + * Monster Blow Effects + */ +static cptr r_info_blow_effect[] = +{ + "*", + "HURT", + "POISON", + "UN_BONUS", + "UN_POWER", + "EAT_GOLD", + "EAT_ITEM", + "EAT_FOOD", + "EAT_LITE", + "ACID", + "ELEC", + "FIRE", + "COLD", + "BLIND", + "CONFUSE", + "TERRIFY", + "PARALYZE", + "LOSE_STR", + "LOSE_INT", + "LOSE_WIS", + "LOSE_DEX", + "LOSE_CON", + "LOSE_CHR", + "LOSE_ALL", + "SHATTER", + "EXP_10", + "EXP_20", + "EXP_40", + "EXP_80", + "DISEASE", + "TIME", + "INSANITY", + "HALLU", + "PARASITE", + "ABOMINATION", + NULL +}; + + +/* + * Monster race flags + */ +static cptr r_info_flags1[] = +{ + "UNIQUE", + "QUESTOR", + "MALE", + "FEMALE", + "CHAR_CLEAR", + "CHAR_MULTI", + "ATTR_CLEAR", + "ATTR_MULTI", + "FORCE_DEPTH", + "FORCE_MAXHP", + "FORCE_SLEEP", + "FORCE_EXTRA", + "FRIEND", + "FRIENDS", + "ESCORT", + "ESCORTS", + "NEVER_BLOW", + "NEVER_MOVE", + "RAND_25", + "RAND_50", + "ONLY_GOLD", + "ONLY_ITEM", + "DROP_60", + "DROP_90", + "DROP_1D2", + "DROP_2D2", + "DROP_3D2", + "DROP_4D2", + "DROP_GOOD", + "DROP_GREAT", + "DROP_USEFUL", + "DROP_CHOSEN" +}; + +/* + * Monster race flags + */ +static cptr r_info_flags2[] = +{ + "STUPID", + "SMART", + "CAN_SPEAK", + "REFLECTING", + "INVISIBLE", + "COLD_BLOOD", + "EMPTY_MIND", + "WEIRD_MIND", + "DEATH_ORB", + "REGENERATE", + "SHAPECHANGER", + "ATTR_ANY", + "POWERFUL", + "ELDRITCH_HORROR", + "AURA_FIRE", + "AURA_ELEC", + "OPEN_DOOR", + "BASH_DOOR", + "PASS_WALL", + "KILL_WALL", + "MOVE_BODY", + "KILL_BODY", + "TAKE_ITEM", + "KILL_ITEM", + "BRAIN_1", + "BRAIN_2", + "BRAIN_3", + "BRAIN_4", + "BRAIN_5", + "BRAIN_6", + "BRAIN_7", + "BRAIN_8" +}; + +/* + * Monster race flags + */ +static cptr r_info_flags3[] = +{ + "ORC", + "TROLL", + "GIANT", + "DRAGON", + "DEMON", + "UNDEAD", + "EVIL", + "ANIMAL", + "THUNDERLORD", + "GOOD", + "AURA_COLD", /* TODO: Implement aura_cold */ + "NONLIVING", + "HURT_LITE", + "HURT_ROCK", + "SUSCEP_FIRE", + "SUSCEP_COLD", + "IM_ACID", + "IM_ELEC", + "IM_FIRE", + "IM_COLD", + "IM_POIS", + "RES_TELE", + "RES_NETH", + "RES_WATE", + "RES_PLAS", + "RES_NEXU", + "RES_DISE", + "UNIQUE_4", + "NO_FEAR", + "NO_STUN", + "NO_CONF", + "NO_SLEEP" +}; + +/* + * Monster race flags + */ +static cptr r_info_flags4[] = +{ + "SHRIEK", + "MULTIPLY", + "S_ANIMAL", + "ROCKET", + "ARROW_1", + "ARROW_2", + "ARROW_3", + "ARROW_4", + "BR_ACID", + "BR_ELEC", + "BR_FIRE", + "BR_COLD", + "BR_POIS", + "BR_NETH", + "BR_LITE", + "BR_DARK", + "BR_CONF", + "BR_SOUN", + "BR_CHAO", + "BR_DISE", + "BR_NEXU", + "BR_TIME", + "BR_INER", + "BR_GRAV", + "BR_SHAR", + "BR_PLAS", + "BR_WALL", + "BR_MANA", + "BA_NUKE", + "BR_NUKE", + "BA_CHAO", + "BR_DISI", +}; + +/* + * Monster race flags + */ +static cptr r_info_flags5[] = +{ + "BA_ACID", + "BA_ELEC", + "BA_FIRE", + "BA_COLD", + "BA_POIS", + "BA_NETH", + "BA_WATE", + "BA_MANA", + "BA_DARK", + "DRAIN_MANA", + "MIND_BLAST", + "BRAIN_SMASH", + "CAUSE_1", + "CAUSE_2", + "CAUSE_3", + "CAUSE_4", + "BO_ACID", + "BO_ELEC", + "BO_FIRE", + "BO_COLD", + "BO_POIS", + "BO_NETH", + "BO_WATE", + "BO_MANA", + "BO_PLAS", + "BO_ICEE", + "MISSILE", + "SCARE", + "BLIND", + "CONF", + "SLOW", + "HOLD" +}; + +/* + * Monster race flags + */ +static cptr r_info_flags6[] = +{ + "HASTE", + "HAND_DOOM", + "HEAL", + "S_ANIMALS", + "BLINK", + "TPORT", + "TELE_TO", + "TELE_AWAY", + "TELE_LEVEL", + "DARKNESS", + "TRAPS", + "FORGET", + "ANIM_DEAD", /* ToDo: Implement ANIM_DEAD */ + "S_BUG", + "S_RNG", + "S_THUNDERLORD", /* DG : Summon Thunderlord */ + "S_KIN", + "S_HI_DEMON", + "S_MONSTER", + "S_MONSTERS", + "S_ANT", + "S_SPIDER", + "S_HOUND", + "S_HYDRA", + "S_ANGEL", + "S_DEMON", + "S_UNDEAD", + "S_DRAGON", + "S_HI_UNDEAD", + "S_HI_DRAGON", + "S_WRAITH", + "S_UNIQUE" +}; + + +/* + * Monster race flags + */ +static cptr r_info_flags7[] = +{ + "AQUATIC", + "CAN_SWIM", + "CAN_FLY", + "FRIENDLY", + "PET", + "MORTAL", + "SPIDER", + "NAZGUL", + "DG_CURSE", + "POSSESSOR", + "NO_DEATH", + "NO_TARGET", + "AI_ANNOY", + "AI_SPECIAL", + "NEUTRAL", + "DROP_ART", + "DROP_RANDART", + "AI_PLAYER", + "NO_THEFT", + "SPIRIT", + "IM_MELEE", + "XXX7X21", + "XXX7X22", + "XXX7X23", + "XXX7X24", + "XXX7X25", + "XXX7X26", + "XXX7X27", + "XXX7X28", + "XXX7X29", + "XXX7X30", + "XXX7X31", +}; + +/* + * Monster race flags + */ +static cptr r_info_flags8[] = +{ + "WILD_ONLY", + "WILD_TOWN", + "XXX8X02", + "WILD_SHORE", + "WILD_OCEAN", + "WILD_WASTE", + "WILD_WOOD", + "WILD_VOLCANO", + "XXX8X08", + "WILD_MOUNTAIN", + "WILD_GRASS", + "NO_CUT", + "CTHANGBAND", + "XXX8X13", + "ZANGBAND", + "JOKEANGBAND", + "BASEANGBAND", + "XXX8X17", + "XXX8X18", + "XXX8X19", + "XXX8X20", + "XXX8X21", + "XXX8X22", + "XXX8X23", + "XXX8X24", + "XXX8X25", + "XXX8X26", + "XXX8X27", + "XXX8X28", + "XXX8X29", + "WILD_SWAMP", /* ToDo: Implement Swamp */ + "WILD_TOO", +}; + + +/* + * Monster race flags - Drops + */ +static cptr r_info_flags9[] = +{ + "DROP_CORPSE", + "DROP_SKELETON", + "HAS_LITE", + "MIMIC", + "HAS_EGG", + "IMPRESED", + "SUSCEP_ACID", + "SUSCEP_ELEC", + "SUSCEP_POIS", + "KILL_TREES", + "WYRM_PROTECT", + "DOPPLEGANGER", + "ONLY_DEPTH", + "SPECIAL_GENE", + "NEVER_GENE", + "XXX9X15", + "XXX9X16", + "XXX9X17", + "XXX9X18", + "XXX9X19", + "XXX9X20", + "XXX9X21", + "XXX9X22", + "XXX9X23", + "XXX9X24", + "XXX9X25", + "XXX9X26", + "XXX9X27", + "XXX9X28", + "XXX9X29", + "XXX9X30", + "XXX9X31", +}; + + +/* + * Object flags + */ +cptr k_info_flags1[] = +{ + "STR", + "INT", + "WIS", + "DEX", + "CON", + "CHR", + "MANA", + "SPELL", + "STEALTH", + "SEARCH", + "INFRA", + "TUNNEL", + "SPEED", + "BLOWS", + "CHAOTIC", + "VAMPIRIC", + "SLAY_ANIMAL", + "SLAY_EVIL", + "SLAY_UNDEAD", + "SLAY_DEMON", + "SLAY_ORC", + "SLAY_TROLL", + "SLAY_GIANT", + "SLAY_DRAGON", + "KILL_DRAGON", + "VORPAL", + "IMPACT", + "BRAND_POIS", + "BRAND_ACID", + "BRAND_ELEC", + "BRAND_FIRE", + "BRAND_COLD" +}; + +/* + * Object flags + */ +cptr k_info_flags2[] = +{ + "SUST_STR", + "SUST_INT", + "SUST_WIS", + "SUST_DEX", + "SUST_CON", + "SUST_CHR", + "INVIS", + "LIFE", + "IM_ACID", + "IM_ELEC", + "IM_FIRE", + "IM_COLD", + "SENS_FIRE", + "REFLECT", + "FREE_ACT", + "HOLD_LIFE", + "RES_ACID", + "RES_ELEC", + "RES_FIRE", + "RES_COLD", + "RES_POIS", + "RES_FEAR", + "RES_LITE", + "RES_DARK", + "RES_BLIND", + "RES_CONF", + "RES_SOUND", + "RES_SHARDS", + "RES_NETHER", + "RES_NEXUS", + "RES_CHAOS", + "RES_DISEN" +}; + +/* + * Trap flags + */ +cptr k_info_flags2_trap[] = +{ + "AUTOMATIC_5", + "AUTOMATIC_99", + "KILL_GHOST", + "TELEPORT_TO", + "ONLY_DRAGON", + "ONLY_DEMON", + "XXX3", + "XXX3", + "ONLY_ANIMAL", + "ONLY_UNDEAD", + "ONLY_EVIL", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", + "XXX3", +}; + + +/* + * Object flags + */ +cptr k_info_flags3[] = +{ + "SH_FIRE", + "SH_ELEC", + "AUTO_CURSE", + "DECAY", + "NO_TELE", + "NO_MAGIC", + "WRAITH", + "TY_CURSE", + "EASY_KNOW", + "HIDE_TYPE", + "SHOW_MODS", + "INSTA_ART", + "FEATHER", + "LITE1", + "SEE_INVIS", + "NORM_ART", + "SLOW_DIGEST", + "REGEN", + "XTRA_MIGHT", + "XTRA_SHOTS", + "IGNORE_ACID", + "IGNORE_ELEC", + "IGNORE_FIRE", + "IGNORE_COLD", + "ACTIVATE", + "DRAIN_EXP", + "TELEPORT", + "AGGRAVATE", + "BLESSED", + "CURSED", + "HEAVY_CURSE", + "PERMA_CURSE" +}; + +/* + * Object flags + */ +cptr k_info_flags4[] = +{ + "NEVER_BLOW", + "PRECOGNITION", + "BLACK_BREATH", + "RECHARGE", + "FLY", + "DG_CURSE", + "COULD2H", + "MUST2H", + "LEVELS", + "CLONE", + "SPECIAL_GENE", + "CLIMB", + "FAST_CAST", + "CAPACITY", + "CHARGING", + "CHEAPNESS", + "FOUNTAIN", + "ANTIMAGIC_50", + "ANTIMAGIC_30", + "ANTIMAGIC_20", + "ANTIMAGIC_10", + "EASY_USE", + "IM_NETHER", + "RECHARGED", + "ULTIMATE", + "AUTO_ID", + "LITE2", + "LITE3", + "FUEL_LITE", + "ART_EXP", + "CURSE_NO_DROP", + "NO_RECHARGE" +}; + +/* + * Object flags + */ +cptr k_info_flags5[] = +{ + "TEMPORARY", + "DRAIN_MANA", + "DRAIN_HP", + "KILL_DEMON", + "KILL_UNDEAD", + "CRIT", + "ATTR_MULTI", + "WOUNDING", + "FULL_NAME", + "LUCK", + "IMMOVABLE", + "SPELL_CONTAIN", + "RES_MORGUL", + "ACTIVATE_NO_WIELD", + "MAGIC_BREATH", + "WATER_BREATH", + "WIELD_CAST", + "XXX8X17", + "XXX8X18", + "XXX8X19", + "XXX8X20", + "XXX8X21", + "XXX8X22", + "XXX8X23", + "XXX8X24", + "XXX8X25", + "XXX8X26", + "XXX8X27", + "XXX8X28", + "XXX8X29", + "XXX8X02", + "XXX8X22", +}; + +/* + * ESP flags + */ +cptr esp_flags[] = +{ + "ESP_ORC", + "ESP_TROLL", + "ESP_DRAGON", + "ESP_GIANT", + "ESP_DEMON", + "ESP_UNDEAD", + "ESP_EVIL", + "ESP_ANIMAL", + "ESP_THUNDERLORD", + "ESP_GOOD", + "ESP_NONLIVING", + "ESP_UNIQUE", + "ESP_SPIDER", + "XXX8X02", + "XXX8X02", + "XXX8X02", + "XXX8X02", + "XXX8X17", + "XXX8X18", + "XXX8X19", + "XXX8X20", + "XXX8X21", + "XXX8X22", + "XXX8X23", + "XXX8X24", + "XXX8X25", + "XXX8X26", + "XXX8X27", + "XXX8X28", + "XXX8X29", + "XXX8X02", + "ESP_ALL", +}; + +/* Specially handled properties for ego-items */ + +static cptr ego_flags[] = +{ + "SUSTAIN", + "OLD_RESIST", + "ABILITY", + "R_ELEM", + "R_LOW", + "R_HIGH", + "R_ANY", + "R_DRAGON", + "SLAY_WEAP", + "DAM_DIE", + "DAM_SIZE", + "PVAL_M1", + "PVAL_M2", + "PVAL_M3", + "PVAL_M5", + "AC_M1", + "AC_M2", + "AC_M3", + "AC_M5", + "TH_M1", + "TH_M2", + "TH_M3", + "TH_M5", + "TD_M1", + "TD_M2", + "TD_M3", + "TD_M5", + "R_P_ABILITY", + "R_STAT", + "R_STAT_SUST", + "R_IMMUNITY", + "LIMIT_BLOWS" +}; + +/* + * Feature flags + */ +static cptr f_info_flags1[] = +{ + "NO_WALK", + "NO_VISION", + "CAN_LEVITATE", + "CAN_PASS", + "FLOOR", + "WALL", + "PERMANENT", + "CAN_FLY", + "REMEMBER", + "NOTICE", + "DONT_NOTICE_RUNNING", + "CAN_RUN", + "DOOR", + "SUPPORT_LIGHT", + "CAN_CLIMB", + "TUNNELABLE", + "WEB", + "ATTR_MULTI", + "SUPPORT_GROWTH", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1" +}; + +/* + * Dungeon flags + */ +static cptr d_info_flags1[] = +{ + "PRINCIPAL", + "MAZE", + "SMALLEST", + "SMALL", + "BIG", + "NO_DOORS", + "WATER_RIVER", + "LAVA_RIVER", + "WATER_RIVERS", + "LAVA_RIVERS", + "CAVE", + "CAVERN", + "NO_UP", + "HOT", + "COLD", + "FORCE_DOWN", + "FORGET", + "NO_DESTROY", + "SAND_VEIN", + "CIRCULAR_ROOMS", + "EMPTY", + "DAMAGE_FEAT", + "FLAT", + "TOWER", + "RANDOM_TOWNS", + "DOUBLE", + "LIFE_LEVEL", + "EVOLVE", + "ADJUST_LEVEL_1", + "ADJUST_LEVEL_2", + "NO_RECALL", + "NO_STREAMERS" +}; + +static cptr d_info_flags2[] = +{ + "ADJUST_LEVEL_1_2", + "NO_SHAFT", + "ADJUST_LEVEL_PLAYER", + "NO_TELEPORT", + "ASK_LEAVE", + "NO_STAIR", + "SPECIAL", + "NO_NEW_MONSTER", + "DESC", + "NO_GENO", + "NO_BREATH", + "WATER_BREATH", + "ELVEN", + "DWARVEN", + "NO_EASY_MOVE", + "NO_RECALL_OUT", + "DESC_ALWAYS", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1" +}; + +/* + * Trap flags + */ +static cptr t_info_flags[] = +{ + "CHEST", + "DOOR", + "FLOOR", + "XXX4", + "XXX5", + "XXX6", + "XXX7", + "XXX8", + "XXX9", + "XXX10", + "XXX11", + "XXX12", + "XXX13", + "XXX14", + "XXX15", + "XXX16", + "LEVEL1", + "LEVEL2", + "LEVEL3", + "LEVEL4", + "XXX21", + "XXX22", + "XXX23", + "XXX24", + "XXX25", + "XXX26", + "XXX27", + "XXX28", + "XXX29", + "XXX30", + "XXX31", + "XXX32" +}; + +/* + * Wilderness feature flags + */ +static cptr wf_info_flags1[] = +{ + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1" +}; + +/* + * Stores flags + */ +static cptr st_info_flags1[] = +{ + "DEPEND_LEVEL", + "SHALLOW_LEVEL", + "MEDIUM_LEVEL", + "DEEP_LEVEL", + "RARE", + "VERY_RARE", + "COMMON", + "ALL_ITEM", + "RANDOM", + "FORCE_LEVEL", + "MUSEUM", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1" +}; + +/* + * Race flags + */ +cptr rp_info_flags1[] = +{ + "EXPERIMENTAL", + "XXX", + "RESIST_BLACK_BREATH", + "NO_STUN", + "XTRA_MIGHT_BOW", + "XTRA_MIGHT_XBOW", + "XTRA_MIGHT_SLING", + "AC_LEVEL", + "HURT_LITE", + "VAMPIRE", + "UNDEAD", + "NO_CUT", + "CORRUPT", + "NO_FOOD", + "NO_GOD", + "XXX", + "ELF", + "SEMI_WRAITH", + "NO_SUBRACE_CHANGE", + "XXX", + "XXX", + "MOLD_FRIEND", + "GOD_FRIEND", + "XXX", + "INNATE_SPELLS", + "XXX", + "XXX", + "EASE_STEAL", + "XXX", + "XXX", + "XXX", + "XXX" +}; + +/* + * Race flags + */ +cptr rp_info_flags2[] = +{ + "XXX", + "ASTRAL", + "XXX", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1" +}; + +/* Skill flags */ +static cptr s_info_flags1[] = +{ + "HIDDEN", + "AUTO_HIDE", + "RANDOM_GAIN", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1", + "XXX1" +}; + +/* + * Dungeon effect types (used in E:damage:frequency:type entry in d_info.txt) + */ +static struct +{ +cptr name; +int feat; +} +d_info_dtypes[] = +{ + {"ELEC", GF_ELEC}, + {"POISON", GF_POIS}, + {"ACID", GF_ACID}, + {"COLD", GF_COLD}, + {"FIRE", GF_FIRE}, + {"MISSILE", GF_MISSILE}, + {"ARROW", GF_ARROW}, + {"PLASMA", GF_PLASMA}, + {"WATER", GF_WATER}, + {"LITE", GF_LITE}, + {"DARK", GF_DARK}, + {"LITE_WEAK", GF_LITE_WEAK}, + {"LITE_DARK", GF_DARK_WEAK}, + {"SHARDS", GF_SHARDS}, + {"SOUND", GF_SOUND}, + {"CONFUSION", GF_CONFUSION}, + {"FORCE", GF_FORCE}, + {"INERTIA", GF_INERTIA}, + {"MANA", GF_MANA}, + {"METEOR", GF_METEOR}, + {"ICE", GF_ICE}, + {"CHAOS", GF_CHAOS}, + {"NETHER", GF_NETHER}, + {"DISENCHANT", GF_DISENCHANT}, + {"NEXUS", GF_NEXUS}, + {"TIME", GF_TIME}, + {"GRAVITY", GF_GRAVITY}, + {"ROCKET", GF_ROCKET}, + {"NUKE", GF_NUKE}, + {"HOLY_FIRE", GF_HOLY_FIRE}, + {"HELL_FIRE", GF_HELL_FIRE}, + {"DISINTEGRATE", GF_DISINTEGRATE}, + {"DESTRUCTION", GF_DESTRUCTION}, + {"RAISE", GF_RAISE}, + {NULL, 0} +}; + +/* Essence names for al_info.txt */ +static const char *essence_names[] = +{ + "No name here", /* can't be matched, sscanf stops at spaces */ + "POISON", + "EXPLOSION", + "TELEPORT", + "COLD", + "FIRE", + "ACID", + "LIFE", + "CONFUSION", + "LITE", + "CHAOS", + "TIME", + "MAGIC", + "EXTRALIFE", + "DARKNESS", + "KNOWLEDGE", + "FORCE", + "LIGHTNING", + "MANA", + "" +}; +static const char *activation_names[] = +{ + "NO_ACTIVATION", /* 0*/ + "SUNLIGHT", /* 1*/ + "BO_MISS_1", /* 2*/ + "BA_POIS_1", /* 3*/ + "BO_ELEC_1", /* 4*/ + "BO_ACID_1", /* 5*/ + "BO_COLD_1", /* 6*/ + "BO_FIRE_1", /* 7*/ + "BA_COLD_1", /* 8*/ + "BA_FIRE_1", /* 9*/ + "DRAIN_1", /* 10*/ + "BA_COLD_2", /* 11*/ + "BA_ELEC_2", /* 12*/ + "DRAIN_2", /* 13*/ + "VAMPIRE_1", /* 14*/ + "BO_MISS_2", /* 15*/ + "BA_FIRE_2", /* 16*/ + "BA_COLD_3", /* 17*/ + "BA_ELEC_3", /* 18*/ + "WHIRLWIND", /* 19*/ + "VAMPIRE_2", /* 20*/ + "CALL_CHAOS", /* 21*/ + "ROCKET", /* 22*/ + "DISP_EVIL", /* 23*/ + "BA_MISS_3", /* 24*/ + "DISP_GOOD", /* 25*/ + "GILGALAD", /* 26*/ + "CELEBRIMBOR", /* 27*/ + "SKULLCLEAVER", /* 28*/ + "HARADRIM", /* 29*/ + "FUNDIN", /* 30*/ + "EOL", /* 31*/ + "UMBAR", /* 32*/ + "NUMENOR", /* 33*/ + "KNOWLEDGE", /* 34*/ + "UNDEATH", /* 35*/ + "THRAIN", /* 36*/ + "BARAHIR", /* 37*/ + "TULKAS", /* 38*/ + "NARYA", /* 39*/ + "NENYA", /* 40*/ + "VILYA", /* 41*/ + "POWER", /* 42*/ + "STONE_LORE", /* 43*/ + "RAZORBACK", /* 44*/ + "BLADETURNER", /* 45*/ + "MEDIATOR", /* 46*/ + "BELEGENNON", /* 47*/ + "GORLIM", /* 48*/ + "COLLUIN", /* 49*/ + "BELANGIL", /* 50*/ + "CONFUSE", /* 51*/ + "SLEEP", /* 52*/ + "QUAKE", /* 53*/ + "TERROR", /* 54*/ + "TELE_AWAY", /* 55*/ + "BANISH_EVIL", /* 56*/ + "GENOCIDE", /* 57*/ + "MASS_GENO", /* 58*/ + "ANGUIREL", /* 59*/ + "ERU", /* 60*/ + "DAWN", /* 61*/ + "FIRESTAR", /* 62*/ + "TURMIL", /* 63*/ + "CUBRAGOL", /* 64*/ + "CHARM_ANIMAL", /* 65*/ + "CHARM_UNDEAD", /* 66*/ + "CHARM_OTHER", /* 67*/ + "CHARM_ANIMALS", /* 68*/ + "CHARM_OTHERS", /* 69*/ + "SUMMON_ANIMAL", /* 70*/ + "SUMMON_PHANTOM", /* 71*/ + "SUMMON_ELEMENTAL", /* 72*/ + "SUMMON_DEMON", /* 73*/ + "SUMMON_UNDEAD", /* 74*/ + "ELESSAR", /* 75*/ + "GANDALF", /* 76*/ + "MARDA", /* 77*/ + "PALANTIR", /* 78*/ + "XXX79", + "XXX80", + "CURE_LW", /* 81*/ + "CURE_MW", /* 82*/ + "CURE_POISON", /* 83*/ + "REST_LIFE", /* 84*/ + "REST_ALL", /* 85*/ + "CURE_700", /* 86*/ + "CURE_1000", /* 87*/ + "XXX88", + "EREBOR", /* 89*/ + "DRUEDAIN", /* 90*/ + "ESP", /* 91*/ + "BERSERK", /* 92*/ + "PROT_EVIL", /* 93*/ + "RESIST_ALL", /* 94*/ + "SPEED", /* 95*/ + "XTRA_SPEED", /* 96*/ + "WRAITH", /* 97*/ + "INVULN", /* 98*/ + "ROHAN", /* 99*/ + "HELM", /* 100*/ + "BOROMIR", /* 101*/ + "HURIN", /* 102*/ + "AXE_GOTHMOG", /* 103*/ + "MELKOR", /* 104*/ + "GROND", /* 105*/ + "NATUREBANE", /* 106*/ + "NIGHT", /* 107*/ + "ORCHAST", /* 108*/ + "XXX109", + "XXX110", + "LIGHT", /* 111*/ + "MAP_LIGHT", /* 112*/ + "DETECT_ALL", /* 113*/ + "DETECT_XTRA", /* 114*/ + "ID_FULL", /* 115*/ + "ID_PLAIN", /* 116*/ + "RUNE_EXPLO", /* 117*/ + "RUNE_PROT", /* 118*/ + "SATIATE", /* 119*/ + "DEST_DOOR", /* 120*/ + "STONE_MUD", /* 121*/ + "RECHARGE", /* 122*/ + "ALCHEMY", /* 123*/ + "DIM_DOOR", /* 124*/ + "TELEPORT", /* 125*/ + "RECALL", /* 126*/ + "DEATH", /* 127*/ + "RUINATION", /* 128*/ + "DESTRUC", /* 129*/ + "UNINT", /* 130*/ + "UNSTR", /* 131*/ + "UNCON", /* 132*/ + "UNCHR", /* 133*/ + "UNDEX", /* 134*/ + "UNWIS", /* 135*/ + "STATLOSS", /* 136*/ + "HISTATLOSS", /* 137*/ + "EXPLOSS", /* 138*/ + "HIEXPLOSS", /* 139*/ + "SUMMON_MONST", /* 140*/ + "PARALYZE", /* 141*/ + "HALLU", /* 142*/ + "POISON", /* 143*/ + "HUNGER", /* 144*/ + "STUN", /* 145*/ + "CUTS", /* 146*/ + "PARANO", /* 147*/ + "CONFUSION", /* 148*/ + "BLIND", /* 149*/ + "PET_SUMMON", /* 150*/ + "CURE_PARA", /* 151*/ + "CURE_HALLU", /* 152*/ + "CURE_POIS", /* 153*/ + "CURE_HUNGER", /* 154*/ + "CURE_STUN", /* 155*/ + "CURE_CUTS", /* 156*/ + "CURE_FEAR", /* 157*/ + "CURE_CONF", /* 158*/ + "CURE_BLIND", /* 159*/ + "CURING", /* 160*/ + "DARKNESS", /* 161*/ + "LEV_TELE", /* 162*/ + "ACQUIREMENT", /* 163*/ + "WEIRD", /* 164*/ + "AGGRAVATE", /* 165*/ + "MUT", /* 166*/ + "CURE_INSANITY", /* 167*/ + "CURE_MUT", /* 168*/ + "LIGHT_ABSORBTION", /* 169*/ + "BA_FIRE_H", /* 170*/ + "BA_COLD_H", /* 171*/ + "BA_ELEC_H", /* 172*/ + "BA_ACID_H", /* 173*/ + "SPIN", /* 174*/ + "NOLDOR", /* 175*/ + "SPECTRAL", /* 176*/ + "JUMP", /* 177*/ + "DEST_TELE", /* 178*/ + "BA_POIS_4", /* 179*/ + "BA_COLD_4", /* 180*/ + "BA_FIRE_4", /* 181*/ + "BA_ACID_4", /* 182*/ + "BA_ELEC_4", /* 183*/ + "BR_ELEC", /* 184*/ + "BR_COLD", /* 185*/ + "BR_FIRE", /* 186*/ + "BR_ACID", /* 187*/ + "BR_POIS", /* 188*/ + "BR_MANY", /* 189*/ + "BR_CONF", /* 190*/ + "BR_SOUND", /* 191*/ + "BR_CHAOS", /* 192*/ + "BR_SHARD", /* 193*/ + "BR_BALANCE", /* 194*/ + "BR_LIGHT", /* 195*/ + "BR_POWER", /* 196*/ + "GROW_MOLD", /* 197*/ + "XXX198", + "XXX199", + "MUSIC", /* 200*/ + "" +}; + +/* + * Convert a "color letter" into an "actual" color + * The colors are: dwsorgbuDWvyRGBU, as shown below + */ +int color_char_to_attr(char c) +{ + switch (c) + { + case 'd': + return (TERM_DARK); + case 'w': + return (TERM_WHITE); + case 's': + return (TERM_SLATE); + case 'o': + return (TERM_ORANGE); + case 'r': + return (TERM_RED); + case 'g': + return (TERM_GREEN); + case 'b': + return (TERM_BLUE); + case 'u': + return (TERM_UMBER); + + case 'D': + return (TERM_L_DARK); + case 'W': + return (TERM_L_WHITE); + case 'v': + return (TERM_VIOLET); + case 'y': + return (TERM_YELLOW); + case 'R': + return (TERM_L_RED); + case 'G': + return (TERM_L_GREEN); + case 'B': + return (TERM_L_BLUE); + case 'U': + return (TERM_L_UMBER); + } + + return ( -1); +} + +/* + * Attr value-to-char convertion table + */ +byte conv_color[16] = +{ + 'd', + 'w', + 's', + 'o', + 'r', + 'g', + 'b', + 'u', + 'D', + 'W', + 'v', + 'y', + 'R', + 'G', + 'B', + 'U', +}; + + +/* Values in re_info can be fixed, added, substracted or percented */ +static byte monster_ego_modify(char c) +{ + switch (c) + { + case '+': + return MEGO_ADD; + case '-': + return MEGO_SUB; + case '=': + return MEGO_FIX; + case '%': + return MEGO_PRC; + default: + { + msg_format("Unknown mego value modifier %c.", c); + return MEGO_ADD; + } + } +} + +/* + * Implements fp stacks, for included files + */ +static FILE *fp_stack[10]; +static int fp_stack_idx = 0; + +/* + * Must be caleld before the main loop + */ +static void fp_stack_init(FILE *fp) +{ + fp_stack[0] = fp; + fp_stack_idx = 0; +} + +static void fp_stack_push(cptr name) +{ + if (fp_stack_idx < 9) + { + char buf[1024]; + FILE *fp; + + /* Build the filename */ + path_build(buf, 1024, ANGBAND_DIR_EDIT, name); + + /* Open the file */ + fp = my_fopen(buf, "r"); + + /* Parse it */ + if (!fp) quit(format("Cannot open '%s' file.", name)); + + printf("ibncluding %s\n", name); + + fp_stack[++fp_stack_idx] = fp; + } +} + +static bool_ fp_stack_pop() +{ + if (fp_stack_idx > 0) + { + FILE *fp = fp_stack[fp_stack_idx--]; + my_fclose(fp); + return TRUE; + } + else + return FALSE; +} + +/* + * Must be used instead of my_fgets for teh main loop + */ +static int my_fgets_dostack(char *buf, int len) +{ + // End of a file + if (0 != my_fgets(fp_stack[fp_stack_idx], buf, len)) + { + // If any left, use them + if (fp_stack_pop()) + return my_fgets_dostack(buf, len); + // If not, this is the end + else + return 1; + } + else + { + return 0; + } +} + + +/*** Initialize from ascii template files ***/ + +/* + * Grab one race flag from a textual string + */ +static bool_ unknown_shut_up = FALSE; +static errr grab_one_class_flag(u32b *choice, cptr what) +{ + int i; + cptr s; + + /* Scan classes flags */ + for (i = 0; i < max_c_idx && (s = class_info[i].title + c_name); i++) + { + if (streq(what, s)) + { + (choice[i / 32]) |= (1L << i); + return (0); + } + } + + /* Oops */ + if (!unknown_shut_up) msg_format("Unknown class flag '%s'.", what); + + /* Failure */ + return (1); +} +static errr grab_one_race_allow_flag(u32b *choice, cptr what) +{ + int i; + cptr s; + + /* Scan classes flags */ + for (i = 0; i < max_rp_idx && (s = race_info[i].title + rp_name); i++) + { + if (streq(what, s)) + { + (choice[i / 32]) |= (1L << i); + return (0); + } + } + + /* Oops */ + if (!unknown_shut_up) msg_format("(1)Unknown race flag '%s'.", what); + + /* Failure */ + return (1); +} + +/* + * Grab one flag from a textual string + */ +static errr grab_one_skill_flag(u32b *f1, cptr what) +{ + int i; + + /* Check flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, s_info_flags1[i])) + { + (*f1) |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("(2)Unknown skill flag '%s'.", what); + + /* Error */ + return (1); +} +/* + * Grab one flag from a textual string + */ +static errr grab_one_player_race_flag(u32b *f1, u32b *f2, cptr what) +{ + int i; + + /* Check flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, rp_info_flags1[i])) + { + (*f1) |= (1L << i); + return (0); + } + } + + /* Check flags2 */ + for (i = 0; i < 32; i++) + { + if (streq(what, rp_info_flags2[i])) + { + (*f2) |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("(2)Unknown race flag '%s'.", what); + + /* Error */ + return (1); +} + +/* Get an activation number (good for artifacts, recipes, egos, and object kinds) */ +int get_activation(char *activation) +{ + int i; + for ( i = 0 ; activation_names[i][0] ; i++) + if (!strncmp(activation_names[i], activation, 19)) + { + return i; + } + return -1; +} + +/* + * Grab one flag in an object_kind from a textual string + */ +static errr grab_one_race_kind_flag(u32b *f1, u32b *f2, u32b *f3, u32b *f4, u32b *f5, u32b *esp, cptr what) +{ + int i; + + /* Check flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags1[i])) + { + (*f1) |= (1L << i); + return (0); + } + } + + /* Check flags2 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags2[i])) + { + (*f2) |= (1L << i); + return (0); + } + } + + /* Check flags2 -- traps*/ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags2_trap[i])) + { + (*f3) |= (1L << i); + return (0); + } + } + + /* Check flags3 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags3[i])) + { + (*f3) |= (1L << i); + return (0); + } + } + + /* Check flags4 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags4[i])) + { + (*f4) |= (1L << i); + return (0); + } + } + + /* Check flags5 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags5[i])) + { + (*f5) |= (1L << i); + return (0); + } + } + + /* Check esp_flags */ + for (i = 0; i < 32; i++) + { + if (streq(what, esp_flags[i])) + { + (*esp) |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("Unknown object flag '%s'.", what); + + /* Error */ + return (1); +} + +/* + * Initialize the "player" arrays, by parsing an ascii "template" file + */ +errr init_player_info_txt(FILE *fp, char *buf) +{ + int i = 0, z; + int powers = 0; + int lev = 1; + int tit_idx = 0; + int spec_idx = 0; + int cur_ab = -1; + + char *s, *t; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + player_race *rp_ptr = NULL; + player_race_mod *rmp_ptr = NULL; + player_class *c_ptr = NULL; + player_spec *s_ptr = NULL; + meta_class_type *mc_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Start the "fake" stuff */ + rp_head->name_size = 0; + rp_head->text_size = 0; + rmp_head->name_size = 0; + rmp_head->text_size = 0; + c_head->name_size = 0; + c_head->text_size = 0; + + /* Init general skills */ + for (z = 0; z < MAX_SKILLS; z++) + { + gen_skill_basem[z] = 0; + gen_skill_base[z] = 0; + gen_skill_modm[z] = 0; + gen_skill_mod[z] = 0; + } + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Reinit error_idx */ + if (buf[0] == 'I') + { + error_idx = -1; + continue; + } + + /* Process 'H' for "History" */ + if (buf[0] == 'H') + { + int idx; + char *zz[6]; + + /* Scan for the values */ + if (tokenize(buf + 2, 6, zz, ':', ':') != 6) return (1); + + idx = atoi(zz[0]); + bg[idx].roll = atoi(zz[1]); + bg[idx].chart = atoi(zz[2]); + bg[idx].next = atoi(zz[3]); + bg[idx].bonus = atoi(zz[4]); + + bg[idx].info = ++rp_head->text_size; + + /* Append chars to the name */ + strcpy(rp_text + rp_head->text_size, zz[5]); + + /* Advance the index */ + rp_head->text_size += strlen(zz[5]); + + /* Next... */ + continue; + } + + /* Process 'G:k' for "General skills" */ + if ((buf[0] == 'G') && (buf[2] == 'k')) + { + long val, mod, i; + char name[200], v, m; + + /* Scan for the values */ + if (5 != sscanf(buf + 4, "%c%ld:%c%ld:%s", + &v, &val, &m, &mod, name)) return (1); + + if ((i = find_skill(name)) == -1) return (1); + gen_skill_basem[i] = monster_ego_modify(v); + gen_skill_base[i] = val; + gen_skill_modm[i] = monster_ego_modify(m); + gen_skill_mod[i] = mod; + + /* Next... */ + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if ((buf[0] == 'R') && (buf[2] == 'N')) + { + /* Find the colon before the name */ + s = strchr(buf + 4, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 4); + + /* Verify information */ + if (i < error_idx) return (4); + + /* Verify information */ + if (i >= rp_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + rp_ptr = &race_info[i]; + + /* Hack -- Verify space */ + if (rp_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!rp_ptr->title) rp_ptr->title = ++rp_head->name_size; + + /* Append chars to the name */ + strcpy(rp_name + rp_head->name_size, s); + + /* Advance the index */ + rp_head->name_size += strlen(s); + + rp_ptr->powers[0] = rp_ptr->powers[1] = rp_ptr->powers[2] = rp_ptr->powers[3] = -1; + powers = 0; + lev = 1; + cur_ab = 0; + for (z = 0; z < 10; z++) + rp_ptr->abilities[z].level = -1; + + /* Next... */ + continue; + } + + /* Process 'D' for "Description" */ + if ((buf[0] == 'R') && (buf[2] == 'D')) + { + /* Acquire the text */ + s = buf + 4; + + /* Hack -- Verify space */ + if (rp_head->text_size + strlen(s) + 8 > fake_text_size) return (7); + + /* Advance and Save the text index */ + if (!rp_ptr->desc) + { + rp_ptr->desc = ++rp_head->text_size; + + /* Append chars to the name */ + strcpy(rp_text + rp_head->text_size, s); + + /* Advance the index */ + rp_head->text_size += strlen(s); + } + else + { + /* Append chars to the name */ + strcpy(rp_text + rp_head->text_size, format("\n%s", s)); + + /* Advance the index */ + rp_head->text_size += strlen(s) + 1; + } + + /* Next... */ + continue; + } + + /* Process 'E' for "body parts" */ + if ((buf[0] == 'R') && (buf[2] == 'E')) + { + int s[BODY_MAX], z; + + /* Scan for the values */ + if (BODY_MAX != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d", + &s[0], &s[1], &s[2], &s[3], &s[4], &s[5])) return (1); + + for (z = 0; z < BODY_MAX; z++) + rp_ptr->body_parts[z] = s[z]; + + /* Next... */ + continue; + } + + /* Process 'R' for "flag level" */ + if ((buf[0] == 'R') && (buf[2] == 'R')) + { + int s[2]; + + /* Scan for the values */ + if (2 != sscanf(buf + 4, "%d:%d", + &s[0], &s[1])) return (1); + + lev = s[0]; + rp_ptr->opval[lev] = s[1]; + + /* Next... */ + continue; + } + + /* Process 'S' for "Stats" */ + if ((buf[0] == 'R') && (buf[2] == 'S')) + { + int s[7], z; + + /* Scan for the values */ + if (7 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d", + &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6])) return (1); + + rp_ptr->luck = s[6]; + for (z = 0; z < 6; z++) + rp_ptr->r_adj[z] = s[z]; + + /* Next... */ + continue; + } + + /* Process 'Z' for "powers" */ + if ((buf[0] == 'R') && (buf[2] == 'Z')) + { + int i; + + /* Acquire the text */ + s = buf + 4; + + /* Find it in the list */ + for (i = 0; i < power_max; i++) + { + if (!stricmp(s, powers_type[i].name)) break; + } + + if (i == power_max) return (6); + + rp_ptr->powers[powers++] = i; + + /* Next... */ + continue; + } + + /* Process 'K' for "sKills" */ + if ((buf[0] == 'R') && (buf[2] == 'K')) + { + int s[8]; + + /* Scan for the values */ + if (8 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d:%d", + &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7])) return (1); + + rp_ptr->r_dis = s[0]; + rp_ptr->r_dev = s[1]; + rp_ptr->r_sav = s[2]; + rp_ptr->r_stl = s[3]; + rp_ptr->r_srh = s[4]; + rp_ptr->r_fos = s[5]; + rp_ptr->r_thn = s[6]; + rp_ptr->r_thb = s[7]; + + /* Next... */ + continue; + } + + /* Process 'k' for "skills" */ + if ((buf[0] == 'R') && (buf[2] == 'k')) + { + long val, mod, i; + char name[200], v, m; + + /* Scan for the values */ + if (5 != sscanf(buf + 4, "%c%ld:%c%ld:%s", + &v, &val, &m, &mod, name)) return (1); + + if ((i = find_skill(name)) == -1) return (1); + rp_ptr->skill_basem[i] = monster_ego_modify(v); + rp_ptr->skill_base[i] = val; + rp_ptr->skill_modm[i] = monster_ego_modify(m); + rp_ptr->skill_mod[i] = mod; + + /* Next... */ + continue; + } + + /* Process 'b' for "abilities" */ + if ((buf[0] == 'R') && (buf[2] == 'b')) + { + char *sec; + + /* Scan for the values */ + if (NULL == (sec = strchr(buf + 4, ':'))) + { + return (1); + } + *sec = '\0'; + sec++; + if (!*sec) return (1); + + if ((i = find_ability(sec)) == -1) return (1); + + rp_ptr->abilities[cur_ab].ability = i; + rp_ptr->abilities[cur_ab].level = atoi(buf + 4); + cur_ab++; + + /* Next... */ + continue; + } + + /* Process 'M' for "Mods" */ + if ((buf[0] == 'R') && (buf[2] == 'M')) + { + int s[10]; + + /* Scan for the values */ + if (10 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7], &s[8], &s[9])) return (1); + + rp_ptr->b_age = s[0]; + rp_ptr->m_age = s[1]; + rp_ptr->m_b_ht = s[2]; + rp_ptr->m_m_ht = s[3]; + rp_ptr->m_b_wt = s[4]; + rp_ptr->m_m_wt = s[5]; + rp_ptr->f_b_ht = s[6]; + rp_ptr->f_m_ht = s[7]; + rp_ptr->f_b_wt = s[8]; + rp_ptr->f_m_wt = s[9]; + + /* Next... */ + continue; + } + + /* Process 'P' for "xtra" */ + if ((buf[0] == 'R') && (buf[2] == 'P')) + { + int s[4]; + + /* Scan for the values */ + if (4 != sscanf(buf + 4, "%d:%d:%d:%d", + &s[0], &s[1], &s[2], &s[3])) return (1); + + rp_ptr->r_mhp = s[0]; + rp_ptr->r_exp = s[1]; + rp_ptr->infra = s[2]; + rp_ptr->chart = s[3]; + + /* Next... */ + continue; + } + + /* Process 'G' for "Player flags" (multiple lines) */ + if ((buf[0] == 'R') && (buf[2] == 'G')) + { + /* Parse every entry */ + for (s = buf + 4; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_player_race_flag(&rp_ptr->flags1, &rp_ptr->flags2, s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'F' for "level Flags" (multiple lines) */ + if ((buf[0] == 'R') && (buf[2] == 'F')) + { + /* Parse every entry */ + for (s = buf + 4; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_race_kind_flag(&rp_ptr->oflags1[lev], &rp_ptr->oflags2[lev], &rp_ptr->oflags3[lev], &rp_ptr->oflags4[lev], &rp_ptr->oflags5[lev], &rp_ptr->oesp[lev], s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'O' for "Object birth" */ + if ((buf[0] == 'R') && (buf[2] == 'O')) + { + int s[5]; + + /* Scan for the values */ + if (5 != sscanf(buf + 4, "%d:%d:%d:%dd%d", + &s[0], &s[1], &s[4], &s[2], &s[3])) + { + s[4] = 0; + + if (4 != sscanf(buf + 4, "%d:%d:%dd%d", + &s[0], &s[1], &s[2], &s[3])) + { + return (1); + } + } + + rp_ptr->obj_pval[rp_ptr->obj_num] = s[4]; + rp_ptr->obj_tval[rp_ptr->obj_num] = s[0]; + rp_ptr->obj_sval[rp_ptr->obj_num] = s[1]; + rp_ptr->obj_dd[rp_ptr->obj_num] = s[2]; + rp_ptr->obj_ds[rp_ptr->obj_num++] = s[3]; + + /* Next... */ + continue; + } + + /* Process 'C' for "Class choice flags" (multiple lines) */ + if ((buf[0] == 'R') && (buf[2] == 'C')) + { + /* Parse every entry */ + for (s = buf + 4; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_class_flag(rp_ptr->choice, s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if ((buf[0] == 'S') && (buf[2] == 'N')) + { + /* Find the colon before the name */ + s = strchr(buf + 4, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 4); + + /* Verify information */ + if (i < error_idx) return (4); + + /* Verify information */ + if (i >= rmp_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + rmp_ptr = &race_mod_info[i]; + + /* Hack -- Verify space */ + if (rmp_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!rmp_ptr->title) rmp_ptr->title = ++rmp_head->name_size; + + /* Append chars to the name */ + strcpy(rmp_name + rmp_head->name_size, s); + + /* Advance the index */ + rmp_head->name_size += strlen(s); + + rmp_ptr->powers[0] = rmp_ptr->powers[1] = rmp_ptr->powers[2] = rmp_ptr->powers[3] = -1; + powers = 0; + lev = 1; + cur_ab = 0; + for (z = 0; z < 10; z++) + rmp_ptr->abilities[z].level = -1; + + /* Next... */ + continue; + } + + /* Process 'D' for "Description" */ + if ((buf[0] == 'S') && (buf[2] == 'D')) + { + /* Acquire the text */ + s = buf + 6; + + if (buf[4] == 'A') rmp_ptr->place = TRUE; + else rmp_ptr->place = FALSE; + + /* Hack -- Verify space */ + if (rmp_head->text_size + strlen(s) + 8 > fake_text_size) return (7); + + /* Advance and Save the text index */ + if (!rmp_ptr->desc) + { + rmp_ptr->desc = ++rmp_head->text_size; + + /* Append chars to the name */ + strcpy(rmp_text + rmp_head->text_size, s); + + /* Advance the index */ + rmp_head->text_size += strlen(s); + } + else + { + /* Append chars to the name */ + strcpy(rmp_text + rmp_head->text_size, format("\n%s", s)); + + /* Advance the index */ + rmp_head->text_size += strlen(s) + 1; + } + + /* Next... */ + continue; + } + + /* Process 'E' for "body parts" */ + if ((buf[0] == 'S') && (buf[2] == 'E')) + { + int s[BODY_MAX], z; + + /* Scan for the values */ + if (BODY_MAX != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d", + &s[0], &s[1], &s[2], &s[3], &s[4], &s[5])) return (1); + + for (z = 0; z < BODY_MAX; z++) + rmp_ptr->body_parts[z] = s[z]; + + /* Next... */ + continue; + } + + /* Process 'R' for "flag level" */ + if ((buf[0] == 'S') && (buf[2] == 'R')) + { + int s[2]; + + /* Scan for the values */ + if (2 != sscanf(buf + 4, "%d:%d", + &s[0], &s[1])) return (1); + + lev = s[0]; + rmp_ptr->opval[lev] = s[1]; + + /* Next... */ + continue; + } + + /* Process 'S' for "Stats" */ + if ((buf[0] == 'S') && (buf[2] == 'S')) + { + int s[8], z; + + /* Scan for the values */ + if (8 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d:%d", + &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7])) return (1); + + rmp_ptr->mana = s[7]; + rmp_ptr->luck = s[6]; + for (z = 0; z < 6; z++) + rmp_ptr->r_adj[z] = s[z]; + + /* Next... */ + continue; + } + + /* Process 'Z' for "powers" */ + if ((buf[0] == 'S') && (buf[2] == 'Z')) + { + int i; + + /* Acquire the text */ + s = buf + 4; + + /* Find it in the list */ + for (i = 0; i < power_max; i++) + { + if (!stricmp(s, powers_type[i].name)) break; + } + + if (i == power_max) return (6); + + rmp_ptr->powers[powers++] = i; + + /* Next... */ + continue; + } + + /* Process 'k' for "skills" */ + if ((buf[0] == 'S') && (buf[2] == 'k')) + { + long val, mod, i; + char name[200], v, m; + + /* Scan for the values */ + if (5 != sscanf(buf + 4, "%c%ld:%c%ld:%s", + &v, &val, &m, &mod, name)) return (1); + + if ((i = find_skill(name)) == -1) return (1); + rmp_ptr->skill_basem[i] = monster_ego_modify(v); + rmp_ptr->skill_base[i] = val; + rmp_ptr->skill_modm[i] = monster_ego_modify(m); + rmp_ptr->skill_mod[i] = mod; + + /* Next... */ + continue; + } + + /* Process 'b' for "abilities" */ + if ((buf[0] == 'S') && (buf[2] == 'b')) + { + char *sec; + + /* Scan for the values */ + if (NULL == (sec = strchr(buf + 4, ':'))) + { + return (1); + } + *sec = '\0'; + sec++; + if (!*sec) return (1); + + if ((i = find_ability(sec)) == -1) return (1); + + rmp_ptr->abilities[cur_ab].ability = i; + rmp_ptr->abilities[cur_ab].level = atoi(buf + 4); + cur_ab++; + + /* Next... */ + continue; + } + + /* Process 'K' for "sKills" */ + if ((buf[0] == 'S') && (buf[2] == 'K')) + { + int s[8]; + + /* Scan for the values */ + if (8 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d:%d", + &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7])) return (1); + + rmp_ptr->r_dis = s[0]; + rmp_ptr->r_dev = s[1]; + rmp_ptr->r_sav = s[2]; + rmp_ptr->r_stl = s[3]; + rmp_ptr->r_srh = s[4]; + rmp_ptr->r_fos = s[5]; + rmp_ptr->r_thn = s[6]; + rmp_ptr->r_thb = s[7]; + + /* Next... */ + continue; + } + + /* Process 'M' for "Mods" */ + if ((buf[0] == 'S') && (buf[2] == 'M')) + { + int s[10]; + + /* Scan for the values */ + if (10 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7], &s[8], &s[9])) return (1); + + rmp_ptr->b_age = s[0]; + rmp_ptr->m_age = s[1]; + rmp_ptr->m_b_ht = s[2]; + rmp_ptr->m_m_ht = s[3]; + rmp_ptr->m_b_wt = s[4]; + rmp_ptr->m_m_wt = s[5]; + rmp_ptr->f_b_ht = s[6]; + rmp_ptr->f_m_ht = s[7]; + rmp_ptr->f_b_wt = s[8]; + rmp_ptr->f_m_wt = s[9]; + + /* Next... */ + continue; + } + + /* Process 'P' for "xtra" */ + if ((buf[0] == 'S') && (buf[2] == 'P')) + { + int s[3]; + + /* Scan for the values */ + if (3 != sscanf(buf + 4, "%d:%d:%d", + &s[0], &s[1], &s[2])) return (1); + + rmp_ptr->r_mhp = s[0]; + rmp_ptr->r_exp = s[1]; + rmp_ptr->infra = s[2]; + + /* Next... */ + continue; + } + + /* Process 'G' for "Player flags" (multiple lines) */ + if ((buf[0] == 'S') && (buf[2] == 'G')) + { + /* Parse every entry */ + for (s = buf + 4; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_player_race_flag(&rmp_ptr->flags1, &rmp_ptr->flags2, s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'F' for "level Flags" (multiple lines) */ + if ((buf[0] == 'S') && (buf[2] == 'F')) + { + /* Parse every entry */ + for (s = buf + 4; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_race_kind_flag(&rmp_ptr->oflags1[lev], &rmp_ptr->oflags2[lev], &rmp_ptr->oflags3[lev], &rmp_ptr->oflags4[lev], &rmp_ptr->oflags5[lev], &rmp_ptr->oesp[lev], s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'O' for "Object birth" */ + if ((buf[0] == 'S') && (buf[2] == 'O')) + { + int s[5]; + + /* Scan for the values */ + if (5 != sscanf(buf + 4, "%d:%d:%d:%dd%d", + &s[0], &s[1], &s[4], &s[2], &s[3])) + { + s[4] = 0; + + if (4 != sscanf(buf + 4, "%d:%d:%dd%d", + &s[0], &s[1], &s[2], &s[3])) + { + return (1); + } + } + + rmp_ptr->obj_pval[rmp_ptr->obj_num] = s[4]; + rmp_ptr->obj_tval[rmp_ptr->obj_num] = s[0]; + rmp_ptr->obj_sval[rmp_ptr->obj_num] = s[1]; + rmp_ptr->obj_dd[rmp_ptr->obj_num] = s[2]; + rmp_ptr->obj_ds[rmp_ptr->obj_num++] = s[3]; + + /* Next... */ + continue; + } + + /* Process 'A' for "Allowed races" (multiple lines) */ + if ((buf[0] == 'S') && (buf[2] == 'A')) + { + /* Parse every entry */ + for (s = buf + 4; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_race_allow_flag(rmp_ptr->choice, s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'C' for "Class choice flags" (multiple lines) */ + if ((buf[0] == 'S') && (buf[2] == 'C')) + { + u32b choice[2] = {0, 0}, z; + + /* Parse every entry */ + for (s = buf + 6; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_class_flag(choice, s)) return (5); + + /* Start the next entry */ + s = t; + } + + for (z = 0; z < 2; z++) + { + if (buf[4] == 'A') rmp_ptr->pclass[z] |= choice[z]; + else rmp_ptr->mclass[z] |= choice[z]; + } + + /* Next... */ + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if ((buf[0] == 'C') && (buf[2] == 'N')) + { + int z; + + /* Find the colon before the name */ + s = strchr(buf + 4, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 4); + + /* Verify information */ + if (i < error_idx) return (4); + + /* Verify information */ + if (i >= c_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + c_ptr = &class_info[i]; + + /* Hack -- Verify space */ + if (c_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!c_ptr->title) c_ptr->title = ++c_head->name_size; + + /* Append chars to the name */ + strcpy(c_name + c_head->name_size, s); + + /* Advance the index */ + c_head->name_size += strlen(s); + + c_ptr->powers[0] = c_ptr->powers[1] = c_ptr->powers[2] = c_ptr->powers[3] = -1; + powers = 0; + lev = 1; + for (z = 0; z < 10; z++) + c_ptr->abilities[z].level = -1; + cur_ab = 0; + c_ptr->obj_num = 0; + tit_idx = 0; + spec_idx = -1; + for (z = 0; z < MAX_SPEC; z++) + c_ptr->spec[z].title = 0; + + /* Next... */ + continue; + } + + /* Process 'D' for "Description" */ + if ((buf[0] == 'C') && (buf[2] == 'D')) + { + /* Acquire the text */ + s = buf + 6; + + /* Hack -- Verify space */ + if (c_head->text_size + strlen(s) + 8 > fake_text_size) return (7); + + switch (buf[4]) + { + case '0': + /* Advance and Save the text index */ + if (!c_ptr->desc) + { + c_ptr->desc = ++c_head->text_size; + + /* Append chars to the name */ + strcpy(c_text + c_head->text_size, s); + + /* Advance the index */ + c_head->text_size += strlen(s); + } + else + { + /* Append chars to the name */ + strcpy(c_text + c_head->text_size, format("\n%s", s)); + + /* Advance the index */ + c_head->text_size += strlen(s) + 1; + } + break; + case '1': + /* Advance and Save the text index */ + c_ptr->titles[tit_idx++] = ++c_head->text_size; + + /* Append chars to the name */ + strcpy(c_text + c_head->text_size, s); + + /* Advance the index */ + c_head->text_size += strlen(s); + break; + default: + return (6); + break; + } + + /* Next... */ + continue; + } + + /* Process 'O' for "Object birth" */ + if ((buf[0] == 'C') && (buf[2] == 'O')) + { + int s[5]; + + /* Scan for the values */ + if (5 != sscanf(buf + 4, "%d:%d:%d:%dd%d", + &s[0], &s[1], &s[4], &s[2], &s[3])) + { + s[4] = 0; + + if (4 != sscanf(buf + 4, "%d:%d:%dd%d", + &s[0], &s[1], &s[2], &s[3])) + { + return (1); + } + } + + c_ptr->obj_pval[c_ptr->obj_num] = s[4]; + c_ptr->obj_tval[c_ptr->obj_num] = s[0]; + c_ptr->obj_sval[c_ptr->obj_num] = s[1]; + c_ptr->obj_dd[c_ptr->obj_num] = s[2]; + c_ptr->obj_ds[c_ptr->obj_num++] = s[3]; + + /* Next... */ + continue; + } + + /* Process 'E' for "body parts" */ + if ((buf[0] == 'C') && (buf[2] == 'E')) + { + int s[BODY_MAX], z; + + /* Scan for the values */ + if (BODY_MAX != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d", + &s[0], &s[1], &s[2], &s[3], &s[4], &s[5])) return (1); + + for (z = 0; z < BODY_MAX; z++) + c_ptr->body_parts[z] = s[z]; + + /* Next... */ + continue; + } + + /* Process 'R' for "flag level" */ + if ((buf[0] == 'C') && (buf[2] == 'R')) + { + int s[2]; + + /* Scan for the values */ + if (2 != sscanf(buf + 4, "%d:%d", + &s[0], &s[1])) return (1); + + lev = s[0]; + c_ptr->opval[lev] = s[1]; + + /* Next... */ + continue; + } + + /* Process 'C' for "Stats" */ + if ((buf[0] == 'C') && (buf[2] == 'S')) + { + int s[8], z; + + /* Scan for the values */ + if (8 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d:%d", + &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7])) return (1); + + c_ptr->mana = s[6]; + c_ptr->extra_blows = s[7]; + for (z = 0; z < 6; z++) + c_ptr->c_adj[z] = s[z]; + + /* Next... */ + continue; + } + + /* Process 'k' for "skills" */ + if ((buf[0] == 'C') && (buf[2] == 'k')) + { + long val, mod, i; + char name[200], v, m; + + /* Scan for the values */ + if (5 != sscanf(buf + 4, "%c%ld:%c%ld:%s", + &v, &val, &m, &mod, name)) return (1); + + if ((i = find_skill(name)) == -1) return (1); + c_ptr->skill_basem[i] = monster_ego_modify(v); + c_ptr->skill_base[i] = val; + c_ptr->skill_modm[i] = monster_ego_modify(m); + c_ptr->skill_mod[i] = mod; + + /* Next... */ + continue; + } + + /* Process 'b' for "abilities" */ + if ((buf[0] == 'C') && (buf[2] == 'b')) + { + char *sec; + + /* Scan for the values */ + if (NULL == (sec = strchr(buf + 4, ':'))) + { + return (1); + } + *sec = '\0'; + sec++; + if (!*sec) return (1); + + if ((i = find_ability(sec)) == -1) return (1); + + c_ptr->abilities[cur_ab].ability = i; + c_ptr->abilities[cur_ab].level = atoi(buf + 4); + cur_ab++; + + /* Next... */ + continue; + } + + /* Process 'g' for "gods" */ + if ((buf[0] == 'C') && (buf[2] == 'g')) + { + int i; + + if (streq(buf + 4, "All Gods")) + c_ptr->gods = 0xFFFFFFFF; + else + { + if ((i = find_god(buf + 4)) == -1) return (1); + c_ptr->gods |= BIT(i); + } + + /* Next... */ + continue; + } + + /* Process 'Z' for "powers" */ + if ((buf[0] == 'C') && (buf[2] == 'Z')) + { + int i; + + /* Acquire the text */ + s = buf + 4; + + /* Find it in the list */ + for (i = 0; i < power_max; i++) + { + if (!stricmp(s, powers_type[i].name)) break; + } + + if (i == power_max) return (6); + + c_ptr->powers[powers++] = i; + + /* Next... */ + continue; + } + + /* Process 'K' for "sKills" */ + if ((buf[0] == 'C') && (buf[2] == 'K')) + { + int s[8]; + + /* Scan for the values */ + if (8 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d:%d", + &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7])) return (1); + + c_ptr->c_dis = s[0]; + c_ptr->c_dev = s[1]; + c_ptr->c_sav = s[2]; + c_ptr->c_stl = s[3]; + c_ptr->c_srh = s[4]; + c_ptr->c_fos = s[5]; + c_ptr->c_thn = s[6]; + c_ptr->c_thb = s[7]; + + /* Next... */ + continue; + } + + /* Process 'x' for "Xtra skills" */ + if ((buf[0] == 'C') && (buf[2] == 'X')) + { + int s[8]; + + /* Scan for the values */ + if (8 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d:%d", + &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7])) return (1); + + c_ptr->x_dis = s[0]; + c_ptr->x_dev = s[1]; + c_ptr->x_sav = s[2]; + c_ptr->x_stl = s[3]; + c_ptr->x_srh = s[4]; + c_ptr->x_fos = s[5]; + c_ptr->x_thn = s[6]; + c_ptr->x_thb = s[7]; + + /* Next... */ + continue; + } + + /* Process 'P' for "xtra" */ + if ((buf[0] == 'C') && (buf[2] == 'P')) + { + int s[2]; + + /* Scan for the values */ + if (2 != sscanf(buf + 4, "%d:%d", + &s[0], &s[1])) return (1); + + c_ptr->c_mhp = s[0]; + c_ptr->c_exp = s[1]; + + /* Next... */ + continue; + } + + /* Process 'C' for "sensing" */ + if ((buf[0] == 'C') && (buf[2] == 'C')) + { + long int s[3]; + char h, m; + + /* Scan for the values */ + if (5 != sscanf(buf + 4, "%c:%c:%ld:%ld:%ld", + &h, &m, &s[0], &s[1], &s[2])) return (1); + + c_ptr->sense_heavy = (h == 'H') ? TRUE : FALSE; + c_ptr->sense_heavy_magic = (m == 'H') ? TRUE : FALSE; + c_ptr->sense_base = s[0]; + c_ptr->sense_pl = s[1]; + c_ptr->sense_plus = s[2]; + + /* Next... */ + continue; + } + + /* Process 'B' for "blows" */ + if ((buf[0] == 'C') && (buf[2] == 'B')) + { + int s[3]; + + /* Scan for the values */ + if (3 != sscanf(buf + 4, "%d:%d:%d", + &s[0], &s[1], &s[2])) return (1); + + c_ptr->blow_num = s[0]; + c_ptr->blow_wgt = s[1]; + c_ptr->blow_mul = s[2]; + + /* Next... */ + continue; + } + + /* Process 'G' for "Player flags" (multiple lines) */ + if ((buf[0] == 'C') && (buf[2] == 'G')) + { + /* Parse every entry */ + for (s = buf + 4; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_player_race_flag(&c_ptr->flags1, &c_ptr->flags2, s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'F' for "level Flags" (multiple lines) */ + if ((buf[0] == 'C') && (buf[2] == 'F')) + { + /* Parse every entry */ + for (s = buf + 4; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_race_kind_flag(&c_ptr->oflags1[lev], &c_ptr->oflags2[lev], &c_ptr->oflags3[lev], &c_ptr->oflags4[lev], &c_ptr->oflags5[lev], &c_ptr->oesp[lev], s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Specialities */ + if ((buf[0] == 'C') && (buf[2] == 'a')) + { + /* Process 'N' for "New/Number/Name" */ + if (buf[4] == 'N') + { + /* Find the colon before the name */ + s = buf + 6; + + /* Paranoia -- require a name */ + if (!*s) return (1); + /* Get the index */ + spec_idx++; + + /* Verify information */ + if (spec_idx >= MAX_SPEC) return (2); + + /* Point at the "info" */ + s_ptr = &c_ptr->spec[spec_idx]; + + /* Hack -- Verify space */ + if (c_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!s_ptr->title) s_ptr->title = ++c_head->name_size; + + /* Append chars to the name */ + strcpy(c_name + c_head->name_size, s); + + /* Advance the index */ + c_head->name_size += strlen(s); + + s_ptr->obj_num = 0; + cur_ab = 0; + for (z = 0; z < 10; z++) + s_ptr->abilities[z].level = -1; + + /* Next... */ + continue; + } + + /* Process 'D' for "Description" */ + if (buf[4] == 'D') + { + /* Acquire the text */ + s = buf + 6; + + /* Hack -- Verify space */ + if (c_head->text_size + strlen(s) + 8 > fake_text_size) return (7); + + /* Advance and Save the text index */ + if (!s_ptr->desc) + { + s_ptr->desc = ++c_head->text_size; + + /* Append chars to the name */ + strcpy(c_text + c_head->text_size, s); + + /* Advance the index */ + c_head->text_size += strlen(s); + } + else + { + /* Append chars to the name */ + strcpy(c_text + c_head->text_size, format("\n%s", s)); + + /* Advance the index */ + c_head->text_size += strlen(s) + 1; + } + + /* Next... */ + continue; + } + + /* Process 'O' for "Object birth" */ + if (buf[4] == 'O') + { + int s[5]; + + /* Scan for the values */ + if (5 != sscanf(buf + 6, "%d:%d:%d:%dd%d", + &s[0], &s[1], &s[4], &s[2], &s[3])) + { + s[4] = 0; + + if (4 != sscanf(buf + 6, "%d:%d:%dd%d", + &s[0], &s[1], &s[2], &s[3])) + { + return (1); + } + } + + s_ptr->obj_pval[s_ptr->obj_num] = s[4]; + s_ptr->obj_tval[s_ptr->obj_num] = s[0]; + s_ptr->obj_sval[s_ptr->obj_num] = s[1]; + s_ptr->obj_dd[s_ptr->obj_num] = s[2]; + s_ptr->obj_ds[s_ptr->obj_num++] = s[3]; + + /* Next... */ + continue; + } + + /* Process 'g' for "gods" */ + if (buf[4] == 'g') + { + int i; + + if (streq(buf + 6, "All Gods")) + s_ptr->gods = 0xFFFFFFFF; + else + { + if ((i = find_god(buf + 6)) == -1) return (1); + s_ptr->gods |= BIT(i); + } + + /* Next... */ + continue; + } + + /* Process 'k' for "skills" */ + if (buf[4] == 'k') + { + long val, mod, i; + char name[200], v, m; + + /* Scan for the values */ + if (5 != sscanf(buf + 6, "%c%ld:%c%ld:%s", + &v, &val, &m, &mod, name)) return (1); + + if ((i = find_skill(name)) == -1) return (1); + s_ptr->skill_basem[i] = monster_ego_modify(v); + s_ptr->skill_base[i] = val; + s_ptr->skill_modm[i] = monster_ego_modify(m); + s_ptr->skill_mod[i] = mod; + + /* Next... */ + continue; + } + + /* Process 'b' for "abilities" */ + if (buf[4] == 'b') + { + char *sec; + + /* Scan for the values */ + if (NULL == (sec = strchr(buf + 6, ':'))) + { + return (1); + } + *sec = '\0'; + sec++; + if (!*sec) return (1); + + if ((i = find_ability(sec)) == -1) return (1); + + s_ptr->abilities[cur_ab].ability = i; + s_ptr->abilities[cur_ab].level = atoi(buf + 6); + cur_ab++; + + /* Next... */ + continue; + } + + /* Process 'G' for "Player flags" (multiple lines) */ + if (buf[4] == 'G') + { + /* Parse every entry */ + for (s = buf + 6; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_player_race_flag(&s_ptr->flags1, &s_ptr->flags2, s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + + /* Process 'K' for "desired skills" */ + if (buf[4] == 'K') + { + long val; + char name[200]; + + /* Scan for the values */ + if (2 != sscanf(buf + 6, "%ld:%s", + &val, name)) return (1); + + if ((i = find_skill(name)) == -1) return (1); + s_ptr->skill_ideal[i] = val; + + /* Next... */ + continue; + } + } + + /* Process 'N' for "New/Number/Name" */ + if ((buf[0] == 'M') && (buf[2] == 'N')) + { + /* Find the colon before the name */ + s = strchr(buf + 4, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 4); + + /* Verify information */ + if (i < error_idx) return (4); + + /* Verify information */ + if (i >= max_mc_idx) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + mc_ptr = &meta_class_info[i]; + + /* Append chars to the name */ + strcpy(mc_ptr->name, s + 2); + mc_ptr->color = color_char_to_attr(s[0]); + for (powers = 0; powers < max_c_idx; powers++) + mc_ptr->classes[powers] = -1; + powers = 0; + + /* Next... */ + continue; + } + + /* Process 'C' for "Classes" */ + if ((buf[0] == 'M') && (buf[2] == 'C')) + { + int i; + + /* Acquire the text */ + s = buf + 4; + + /* Find it in the list */ + for (i = 0; i < max_c_idx; i++) + { + if (!stricmp(s, class_info[i].title + c_name)) break; + } + + if (i == max_c_idx) return (6); + + mc_ptr->classes[powers++] = i; + + /* Next... */ + continue; + } + + /* Oops */ + return (6); + } + + /* Complete the "name" and "text" sizes */ + ++rp_head->name_size; + ++rp_head->text_size; + ++rmp_head->name_size; + ++rmp_head->text_size; + ++c_head->name_size; + ++c_head->text_size; + /* No version yet */ + if (!okay) return (2); + + /* Success */ + return (0); +} + + +/* + * Initialize the "v_info" array, by parsing an ascii "template" file + */ +errr init_v_info_txt(FILE *fp, char *buf, bool_ start) +{ + int i; + char *s; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + vault_type *v_ptr = NULL; + + if (start) + { + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + /* Prepare the "fake" stuff */ + v_head->name_size = 0; + v_head->text_size = 0; + } + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + if ((buf[0] == 'Q') || (buf[0] == 'T')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf, "V:%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if (buf[0] == 'N') + { + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i <= error_idx) return (4); + + /* Verify information */ + if (i >= v_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + v_ptr = &v_info[i]; + + /* Hack -- Verify space */ + if (v_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!v_ptr->name) v_ptr->name = ++v_head->name_size; + + /* Append chars to the name */ + strcpy(v_name + v_head->name_size, s); + + /* Advance the index */ + v_head->name_size += strlen(s); + + /* Next... */ + continue; + } + + /* There better be a current v_ptr */ + if (!v_ptr) return (3); + + /* Process 'D' for "Description" */ + if (buf[0] == 'D') + { + /* Acquire the text */ + s = buf + 2; + + /* Hack -- Verify space */ + if (v_head->text_size + strlen(s) + 8 > fake_text_size) return (7); + + /* Advance and Save the text index */ + if (!v_ptr->text) v_ptr->text = ++v_head->text_size; + + /* Append chars to the name */ + strcpy(v_text + v_head->text_size, s); + + /* Advance the index */ + v_head->text_size += strlen(s); + + /* Next... */ + continue; + } + + + /* Process 'X' for "Extra info" (one line only) */ + if (buf[0] == 'X') + { + int typ, rat, hgt, wid; + + /* Scan for the values */ + if (4 != sscanf(buf + 2, "%d:%d:%d:%d", + &typ, &rat, &hgt, &wid)) return (1); + + /* Save the values */ + v_ptr->typ = typ; + v_ptr->rat = rat; + v_ptr->hgt = hgt; + v_ptr->wid = wid; + + /* Next... */ + continue; + } + + /* There better be a current v_ptr */ + if (!v_ptr) return (3); + + /* Process monster, item and level info for special levels */ + if (buf[0] == 'Y') + { + + int mon1, mon2, mon3, mon4, mon5, mon6, mon7, mon8, mon9; + int mon10, item1, item2, item3, lvl, dun_type; + + /* Scan for the values */ + if (15 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &mon1, &mon2, &mon3, &mon4, &mon5, &mon6, &mon7, &mon8, &mon9, &mon10, &item1, &item2, &item3, &lvl, &dun_type)) return (1); + + /* Save the values */ + v_ptr->mon[0] = mon1; + v_ptr->mon[1] = mon2; + v_ptr->mon[2] = mon3; + v_ptr->mon[3] = mon4; + v_ptr->mon[4] = mon5; + v_ptr->mon[5] = mon6; + v_ptr->mon[6] = mon7; + v_ptr->mon[7] = mon8; + v_ptr->mon[8] = mon9; + v_ptr->mon[9] = mon10; + v_ptr->item[0] = item1; + v_ptr->item[1] = item2; + v_ptr->item[2] = item3; + v_ptr->lvl = lvl; + v_ptr->dun_type = dun_type; + + /* Next... */ + continue; + } + + + /* Oops */ + return (6); + } + + + /* Complete the "name" and "text" sizes */ + if (!start) + { + ++v_head->name_size; + ++v_head->text_size; + } + + + /* No version yet */ + if (!okay) return (2); + + + /* Success */ + return (0); +} + + +/* + * Grab one flag in an feature_type from a textual string + */ +static errr grab_one_feature_flag(feature_type *f_ptr, cptr what) +{ + int i; + + /* Check flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, f_info_flags1[i])) + { + f_ptr->flags1 |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("Unknown object flag '%s'.", what); + + /* Error */ + return (1); +} + + +/* + * Initialize the "f_info" array, by parsing an ascii "template" file + */ +errr init_f_info_txt(FILE *fp, char *buf) +{ + int i; + + char *s, *t; + + /* Not ready yet */ + bool_ okay = FALSE; + u32b default_desc = 0, default_tunnel = 0, default_block = 0; + + /* Current entry */ + feature_type *f_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Prepare the "fake" stuff */ + f_head->name_size = 0; + f_head->text_size = 0; + + /* Add some fake descs */ + default_desc = ++f_head->text_size; + strcpy(f_text + f_head->text_size, "a wall blocking your way"); + f_head->text_size += strlen("a wall blocking your way"); + + default_tunnel = ++f_head->text_size; + strcpy(f_text + f_head->text_size, "You cannot tunnel through that."); + f_head->text_size += strlen("You cannot tunnel through that."); + + default_block = ++f_head->text_size; + strcpy(f_text + f_head->text_size, "a wall blocking your way"); + f_head->text_size += strlen("a wall blocking your way"); + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if (buf[0] == 'N') + { + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i <= error_idx) return (4); + + /* Verify information */ + if (i >= f_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + f_ptr = &f_info[i]; + + /* Hack -- Verify space */ + if (f_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!f_ptr->name) f_ptr->name = ++f_head->name_size; + + /* Append chars to the name */ + strcpy(f_name + f_head->name_size, s); + + /* Advance the index */ + f_head->name_size += strlen(s); + + /* Default "mimic" */ + f_ptr->mimic = i; + f_ptr->text = default_desc; + f_ptr->block = default_desc; + f_ptr->tunnel = default_tunnel; + f_ptr->block = default_block; + + /* Next... */ + continue; + } + + /* There better be a current f_ptr */ + if (!f_ptr) return (3); + + + /* Process 'D' for "Descriptions" */ + if (buf[0] == 'D') + { + /* Acquire the text */ + s = buf + 4; + + /* Hack -- Verify space */ + if (f_head->text_size + strlen(s) + 8 > fake_text_size) return (7); + + switch (buf[2]) + { + case '0': + /* Advance and Save the text index */ + f_ptr->text = ++f_head->text_size; + break; + case '1': + /* Advance and Save the text index */ + f_ptr->tunnel = ++f_head->text_size; + break; + case '2': + /* Advance and Save the text index */ + f_ptr->block = ++f_head->text_size; + break; + default: + return (6); + break; + } + + /* Append chars to the name */ + strcpy(f_text + f_head->text_size, s); + + /* Advance the index */ + f_head->text_size += strlen(s); + + /* Next... */ + continue; + } + + + /* Process 'M' for "Mimic" (one line only) */ + if (buf[0] == 'M') + { + int mimic; + + /* Scan for the values */ + if (1 != sscanf(buf + 2, "%d", + &mimic)) return (1); + + /* Save the values */ + f_ptr->mimic = mimic; + + /* Next... */ + continue; + } + + /* Process 'S' for "Shimmer" (one line only) */ + if (buf[0] == 'S') + { + char s0, s1, s2, s3, s4, s5, s6; + + /* Scan for the values */ + if (7 != sscanf(buf + 2, "%c:%c:%c:%c:%c:%c:%c", + &s0, &s1, &s2, &s3, &s4, &s5, &s6)) return (1); + + /* Save the values */ + f_ptr->shimmer[0] = color_char_to_attr(s0); + f_ptr->shimmer[1] = color_char_to_attr(s1); + f_ptr->shimmer[2] = color_char_to_attr(s2); + f_ptr->shimmer[3] = color_char_to_attr(s3); + f_ptr->shimmer[4] = color_char_to_attr(s4); + f_ptr->shimmer[5] = color_char_to_attr(s5); + f_ptr->shimmer[6] = color_char_to_attr(s6); + + /* Next... */ + continue; + } + + + /* Process 'G' for "Graphics" (one line only) */ + if (buf[0] == 'G') + { + int tmp; + + /* Paranoia */ + if (!buf[2]) return (1); + if (!buf[3]) return (1); + if (!buf[4]) return (1); + + /* Extract the color */ + tmp = color_char_to_attr(buf[4]); + + /* Paranoia */ + if (tmp < 0) return (1); + + /* Save the values */ + f_ptr->d_attr = tmp; + f_ptr->d_char = buf[2]; + + /* Next... */ + continue; + } + + /* Process 'E' for "Effects" (up to four lines) -SC- */ + if (buf[0] == 'E') + { + int side, dice, freq, type; + cptr tmp; + + /* Find the next empty blow slot (if any) */ + for (i = 0; i < 4; i++) if ((!f_ptr->d_side[i]) && + (!f_ptr->d_dice[i])) break; + + /* Oops, no more slots */ + if (i == 4) return (1); + + /* Scan for the values */ + if (4 != sscanf(buf + 2, "%dd%d:%d:%d", + &dice, &side, &freq, &type)) + { + int j; + + if (3 != sscanf(buf + 2, "%dd%d:%d", + &dice, &side, &freq)) return (1); + + tmp = buf + 2; + for (j = 0; j < 2; j++) + { + tmp = strchr(tmp, ':'); + if (tmp == NULL) return (1); + tmp++; + } + + j = 0; + + while (d_info_dtypes[j].name != NULL) + if (strcmp(d_info_dtypes[j].name, tmp) == 0) + { + f_ptr->d_type[i] = d_info_dtypes[j].feat; + break; + } + else j++; + + if (d_info_dtypes[j].name == NULL) return (1); + } + else + f_ptr->d_type[i] = type; + + freq *= 10; + /* Save the values */ + f_ptr->d_side[i] = side; + f_ptr->d_dice[i] = dice; + f_ptr->d_frequency[i] = freq; + + /* Next... */ + continue; + } + + /* Hack -- Process 'F' for flags */ + if (buf[0] == 'F') + { + /* Parse every entry textually */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_feature_flag(f_ptr, s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + + + /* Oops */ + return (6); + } + + + /* Complete the "name" and "text" sizes */ + ++f_head->name_size; + ++f_head->text_size; + + + /* No version yet */ + if (!okay) return (2); + + + /* Success */ + return (0); +} + + +/* + * Grab one flag in an object_kind from a textual string + */ +static errr grab_one_kind_flag(object_kind *k_ptr, cptr what, bool_ obvious) +{ + int i; + + /* Check flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags1[i])) + { + if (obvious) + k_ptr->oflags1 |= (1L << i); + else + k_ptr->flags1 |= (1L << i); + return (0); + } + } + + /* Check flags2 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags2[i])) + { + if (obvious) + k_ptr->oflags2 |= (1L << i); + else + k_ptr->flags2 |= (1L << i); + return (0); + } + } + + /* Check flags2 -- traps*/ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags2_trap[i])) + { + if (obvious) + k_ptr->oflags2 |= (1L << i); + else + k_ptr->flags2 |= (1L << i); + return (0); + } + } + + /* Check flags3 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags3[i])) + { + if (obvious) + k_ptr->oflags3 |= (1L << i); + else + k_ptr->flags3 |= (1L << i); + return (0); + } + } + + /* Check flags4 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags4[i])) + { + if (obvious) + k_ptr->oflags4 |= (1L << i); + else + k_ptr->flags4 |= (1L << i); + return (0); + } + } + + /* Check flags5 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags5[i])) + { + if (obvious) + k_ptr->oflags5 |= (1L << i); + else + k_ptr->flags5 |= (1L << i); + return (0); + } + } + + /* Check esp_flags */ + for (i = 0; i < 32; i++) + { + if (streq(what, esp_flags[i])) + { + if (obvious) + k_ptr->oesp |= (1L << i); + else + k_ptr->esp |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("Unknown object flag '%s'.", what); + + /* Error */ + return (1); +} + +/* + * Initialize the "k_info" array, by parsing an ascii "template" file + */ +errr init_k_info_txt(FILE *fp, char *buf) +{ + int i; + + char *s, *t; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + object_kind *k_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Prepare the "fake" stuff */ + k_head->name_size = 0; + k_head->text_size = 0; + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if (buf[0] == 'N') + { + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i <= error_idx) return (4); + + /* Verify information */ + if (i >= k_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + k_ptr = &k_info[i]; + + /* Hack -- Verify space */ + if (k_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!k_ptr->name) k_ptr->name = ++k_head->name_size; + + /* Append chars to the name */ + strcpy(k_name + k_head->name_size, s); + + /* Advance the index */ + k_head->name_size += strlen(s); + + /* Needed hack */ + k_ptr->esp = 0; + k_ptr->power = -1; + + /* Next... */ + continue; + } + + /* There better be a current k_ptr */ + if (!k_ptr) return (3); + + /* Process 'D' for "Description" */ + if (buf[0] == 'D') + { + /* Acquire the text */ + s = buf + 2; + + /* Hack -- Verify space */ + if (k_head->text_size + strlen(s) + 8 > fake_text_size) return (7); + + /* Advance and Save the text index */ + if (!k_ptr->text) k_ptr->text = ++k_head->text_size; + + /* Append a space if needed */ + else if (k_text[k_head->text_size - 1] != ' ') + { + /* Append chars to the name */ + strcpy(k_text + k_head->text_size, " "); + + /* Advance the index */ + k_head->text_size += 1; + } + + /* Append chars to the name */ + strcpy(k_text + k_head->text_size, s); + + /* Advance the index */ + k_head->text_size += strlen(s); + + /* Next... */ + continue; + } + + /* Process 'G' for "Graphics" (one line only) */ + if (buf[0] == 'G') + { + char sym; + int tmp; + + /* Paranoia */ + if (!buf[2]) return (1); + if (!buf[3]) return (1); + if (!buf[4]) return (1); + + /* Extract the char */ + sym = buf[2]; + + /* Extract the attr */ + tmp = color_char_to_attr(buf[4]); + + /* Paranoia */ + if (tmp < 0) return (1); + + /* Save the values */ + k_ptr->d_attr = tmp; + k_ptr->d_char = sym; + + /* Next... */ + continue; + } + + /* Process 'I' for "Info" (one line only) */ + if (buf[0] == 'I') + { + int tval, sval, pval, pval2 = 0; + + /* Scan for the values */ + if (4 != sscanf(buf + 2, "%d:%d:%d:%d", + &tval, &sval, &pval, &pval2)) + { + char spl[70]; + + if (4 != sscanf(buf + 2, "%d:%d:%d:SPELL=%s", + &tval, &sval, &pval, spl)) + { + if (3 != sscanf(buf + 2, "%d:%d:%d", + &tval, &sval, &pval)) + return (1); + } + else + { + char *spl = strchr(buf + 2, '=') + 1; + + pval2 = find_spell(spl); + } + } + + /* Save the values */ + k_ptr->tval = tval; + k_ptr->sval = sval; + k_ptr->pval = pval; + k_ptr->pval2 = pval2; + + /* Next... */ + continue; + } + + /* Process 'W' for "More Info" (one line only) */ + if (buf[0] == 'W') + { + int level, extra, wgt; + long cost; + + /* Scan for the values */ + if (4 != sscanf(buf + 2, "%d:%d:%d:%ld", + &level, &extra, &wgt, &cost)) return (1); + + /* Save the values */ + k_ptr->level = level; + k_ptr->extra = extra; + k_ptr->weight = wgt; + k_ptr->cost = cost; + + /* Next... */ + continue; + } + + /* Process 'T' for "arTifact Info" (one line only) */ + if (buf[0] == 'T') + { + int btval, bsval; + + /* Scan for the values */ + if (2 != sscanf(buf + 2, "%d:%d", + &btval, &bsval)) return (1); + + /* Save the values */ + k_ptr->btval = btval; + k_ptr->bsval = bsval; + + /* Next... */ + continue; + } + + /* Process 'Z' for "Granted power" */ + if (buf[0] == 'Z') + { + int i; + + /* Acquire the text */ + s = buf + 2; + + /* Find it in the list */ + for (i = 0; i < power_max; i++) + { + if (!stricmp(s, powers_type[i].name)) break; + } + + if (i == power_max) return (6); + + k_ptr->power = i; + + /* Next... */ + continue; + } + + /* Process 'a' for Activation */ + if ( buf[0] == 'a') + { + if (prefix(buf + 2, "HARDCORE=")) + { + k_ptr->activate = get_activation(buf + 11); + if (k_ptr->activate == -1) + return 1; + } + else if (prefix(buf + 2, "SPELL=")) + { + k_ptr->activate = -find_spell(buf + 8); + if (k_ptr->activate == -( -1)) + return 1; + } + + /* Next... */ + continue; + } + + /* Process 'A' for "Allocation" (one line only) */ + if (buf[0] == 'A') + { + int i; + + /* XXX XXX XXX Simply read each number following a colon */ + for (i = 0, s = buf + 1; s && (s[0] == ':') && s[1]; ++i) + { + /* Default chance */ + k_ptr->chance[i] = 1; + + /* Store the level */ + k_ptr->locale[i] = atoi(s + 1); + + /* Find the slash */ + t = strchr(s + 1, '/'); + + /* Find the next colon */ + s = strchr(s + 1, ':'); + + /* If the slash is "nearby", use it */ + if (t && (!s || t < s)) + { + int chance = atoi(t + 1); + if (chance > 0) k_ptr->chance[i] = chance; + } + } + + /* Next... */ + continue; + } + + /* Hack -- Process 'P' for "power" and such */ + if (buf[0] == 'P') + { + int ac, hd1, hd2, th, td, ta; + + /* Scan for the values */ + if (6 != sscanf(buf + 2, "%d:%dd%d:%d:%d:%d", + &ac, &hd1, &hd2, &th, &td, &ta)) return (1); + + k_ptr->ac = ac; + k_ptr->dd = hd1; + k_ptr->ds = hd2; + k_ptr->to_h = th; + k_ptr->to_d = td; + k_ptr->to_a = ta; + + /* Next... */ + continue; + } + + /* Hack -- Process 'F' for flags */ + if (buf[0] == 'F') + { + /* Parse every entry textually */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_kind_flag(k_ptr, s, FALSE)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Hack -- Process 'f' for obvious flags */ + if (buf[0] == 'f') + { + /* Parse every entry textually */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_kind_flag(k_ptr, s, TRUE)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + + /* Oops */ + return (6); + } + + + /* Complete the "name" and "text" sizes */ + ++k_head->name_size; + ++k_head->text_size; + + + /* No version yet */ + if (!okay) return (2); + + + /* Success */ + return (0); +} + +/*Get a kind flag, return flag*32+bit number or -1 for unknown*/ + +int get_k_flag(char *what) +{ + int i; + + /* Check flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags1[i])) + return i; + if (streq(what, k_info_flags2[i])) + return 1*32 + i; + if (streq(what, k_info_flags2_trap[i])) + return 1*32 + i; + if (streq(what, k_info_flags3[i])) + return 2*32 + i; + if (streq(what, k_info_flags4[i])) + return 3*32 + i; + if (streq(what, k_info_flags5[i])) + return 4*32 + i; + if (streq(what, esp_flags[i])) + return 5*32 + i; + } + + /* Oops */ + msg_format("Unknown object flag '%s'.", what); + + /* Error */ + return ( -1); + +} + +int get_r_flag(char *what) +{ + int i; + + /* Check flags */ + /* this processes all r_info_flag arrays in parallel. + Seemed like a good idea at the time.. + */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags1[i])) + return i; + if (streq(what, r_info_flags2[i])) + return 1*32 + i; + if (streq(what, r_info_flags3[i])) + return 2*32 + i; + if (streq(what, r_info_flags4[i])) + return 3*32 + i; + if (streq(what, r_info_flags5[i])) + return 4*32 + i; + if (streq(what, r_info_flags6[i])) + return 5*32 + i; + if (streq(what, r_info_flags7[i])) + return 6*32 + i; + if (streq(what, r_info_flags8[i])) + return 7*32 + i; + if (streq(what, r_info_flags9[i])) + return 8*32 + i; + } + + /* Oops */ + msg_format("Unknown race flag '%s'.", what); + + /* Error */ + return ( -1); +} +int init_al_info_essence(char *essence) +{ + int i; + for ( i = 0 ; essence_names[i][0] ; i++) + if (!strncmp(essence_names[i], essence, 9)) + { + return i; + } + return -1; +} +/* + * Initialize the "al_info" array, by parsing an ascii "template" file + */ +errr init_al_info_txt(FILE *fp, char *buf) +{ + int al_idx = 0, a_idx = 0; + char *s, *t; + struct artifact_select_flag *a_ptr = NULL; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + /* Fun! */ + al_head->name_size = 0; + *al_name = 0; + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'I' for "Info" (one line only) */ + if (buf[0] == 'I') + { + int tval, sval, qty; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d:%d:%d", + &tval, &sval, &qty)) + { + return (1); + } + + /* ignore everything after the first space. */ + s = strchr(buf, ' '); + if (s != NULL) + *s = 0; + + /* Save the values */ + alchemist_recipes[al_idx].tval = tval; + alchemist_recipes[al_idx].sval = sval; + alchemist_recipes[al_idx].qty = qty; + alchemist_recipes[al_idx].sval_essence = init_al_info_essence(strrchr(buf, ':') + 1); + if (alchemist_recipes[al_idx].sval_essence < 0) + return 5; + + al_idx++; + if (al_idx >= max_al_idx) + return 7; + /* Next... */ + continue; + } + if (buf[0] == 'a') + { + int qty; + if ( 1 != sscanf(buf + 2, "%d", &qty)) + { + return (1); + } + s = strrchr(buf, ':'); + *(s++) = 0; + t = strchr(s, ' '); + *(t++) = 0; + alchemist_recipes[al_idx].tval = 0; + alchemist_recipes[al_idx].sval = get_k_flag(s); + alchemist_recipes[al_idx].qty = qty; + alchemist_recipes[al_idx].sval_essence = init_al_info_essence(t); + if (alchemist_recipes[al_idx].sval_essence < 0) + return 1; + + al_idx++; + if (al_idx >= max_al_idx) + return 7; /* 7 is an 'out of memory' error */ + + continue; + } + if (buf[0] == 'A') + { + int group, level, pval, rtval, rsval, rpval; + long xp; + /*Verify that complete description information is + Recorded for previous Artifact flag + */ + if (a_ptr + && (!a_ptr->group || !a_ptr->desc || !a_ptr->item_desc != !a_ptr->rtval) + ) + return (1); + + a_ptr = &a_select_flags[a_idx++]; + + if ( 7 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d:%ld", + &group, &rtval, &rsval, &rpval, &pval, &level, &xp)) + return (1); + a_ptr->group = group; + a_ptr->rtval = rtval; + a_ptr->rsval = rsval; + a_ptr->rpval = rpval; + a_ptr->pval = pval; + a_ptr->level = level; + a_ptr->xp = xp; + continue; + } + + /*Anything else here MUST be a artifact flag line*/ + if ( !a_ptr) + return (3); + + if (buf[0] == 'F') + { + /* Get the Item flag associated with this */ + a_ptr->flag = get_k_flag(buf + 2); + if (a_ptr->flag == -1) + return (1); + continue; + } + if (buf[0] == 'x') + { + /* Get the activation name associated with this */ + a_ptr->flag = -get_activation(buf + 2); + if (a_ptr->flag == 1) + return (1); + a_ptr->group = 88; + a_ptr->pval = 0; + continue; + } + /* Get the race flags associated with this */ + if (buf[0] == 'f') + { + char *s, *t; + int idx = 0; + + if ( a_ptr->rflag[0] ) + { + msg_print("duplicate f: entries for one corpse"); + return (5); + } + + if ( a_ptr->rtval != TV_CORPSE ) + { + msg_print("f: section for corpse flags only"); + return (5); + } + if ( a_ptr->rpval ) + { + msg_print("Can't specify r_info.txt index with f: section"); + return (5); + } + + /* Parse every entry textually */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while ((*t == ' ') || (*t == '|')) t++; + } + + if ( idx > 5 ) + { + msg_print("Limit on race flags is currently 6"); + return (5); + } + + /* Parse this entry */ + a_ptr->rflag[idx] = get_r_flag(s); + if (a_ptr->rflag[idx++] == -1) + return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'p' for "Plural Description" */ + /* Only valid for flag which depend on pval */ + if (buf[0] == 'p') + { + /* Reject if doesn't depend on pval */ + + if (!a_ptr->pval) + return (1); + + /* Acquire the description */ + s = buf + 2; + + /* Hack -- Verify space */ + if (al_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + a_ptr->item_descp = ++al_head->name_size; + + /* Append chars to the name */ + strcpy(al_name + al_head->name_size, s); + + /* Advance the index */ + al_head->name_size += strlen(s); + + /* Next... */ + continue; + } + + /* Process 'D' for "Description" */ + if (buf[0] == 'D') + { + /* Acquire the description */ + s = buf + 2; + + /* Hack -- Verify space */ + if (al_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + a_ptr->desc = ++al_head->name_size; + + /* Append chars to the name */ + strcpy(al_name + al_head->name_size, s); + + /* Advance the index */ + al_head->name_size += strlen(s); + + /* Next... */ + continue; + } + + /* Process 'd' for "Item Description" */ + if (buf[0] == 'd') + { + /* Acquire the name */ + s = buf + 2; + + /* Hack -- Verify space */ + if (al_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + if (a_ptr->item_desc) + return (7); + + /* Advance and Save the name index */ + a_ptr->item_desc = ++al_head->name_size; + + /* Append chars to the name */ + strcpy(al_name + al_head->name_size, s); + + /* Advance the index */ + al_head->name_size += strlen(s); + + /* Next... */ + continue; + } + + /* Oops */ + return (6); + } + + /* No version yet */ + if (!okay) return (2); + + /* Hack - set the al_head->text_size to byte size of array */ + al_head->text_size = (a_idx + 1) * sizeof(artifact_select_flag); + + /* Success */ + return (0); +} + +/* + * Grab one flag in an artifact_type from a textual string + */ +static errr grab_one_artifact_flag(artifact_type *a_ptr, cptr what, bool_ obvious) +{ + int i; + + /* Check flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags1[i])) + { + if (obvious) + a_ptr->oflags1 |= (1L << i); + else + a_ptr->flags1 |= (1L << i); + return (0); + } + } + + /* Check flags2 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags2[i])) + { + if (obvious) + a_ptr->oflags2 |= (1L << i); + else + a_ptr->flags2 |= (1L << i); + return (0); + } + } + + /* Check flags2 -- traps*/ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags2_trap[i])) + { + if (obvious) + a_ptr->oflags2 |= (1L << i); + else + a_ptr->flags2 |= (1L << i); + return (0); + } + } + + /* Check flags3 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags3[i])) + { + if (obvious) + a_ptr->oflags3 |= (1L << i); + else + a_ptr->flags3 |= (1L << i); + return (0); + } + } + + /* Check flags4 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags4[i])) + { + if (obvious) + a_ptr->oflags4 |= (1L << i); + else + a_ptr->flags4 |= (1L << i); + return (0); + } + } + + /* Check flags5 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags5[i])) + { + if (obvious) + a_ptr->oflags5 |= (1L << i); + else + a_ptr->flags5 |= (1L << i); + return (0); + } + } + + /* Check esp_flags */ + for (i = 0; i < 32; i++) + { + if (streq(what, esp_flags[i])) + { + if (obvious) + a_ptr->oesp |= (1L << i); + else + a_ptr->esp |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("Unknown artifact flag '%s'.", what); + + /* Error */ + return (1); +} + + + + +/* + * Initialize the "a_info" array, by parsing an ascii "template" file + */ +errr init_a_info_txt(FILE *fp, char *buf) +{ + int i; + + char *s, *t; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + artifact_type *a_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if (buf[0] == 'N') + { + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i < error_idx) return (4); + + /* Verify information */ + if (i >= a_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + a_ptr = &a_info[i]; + + /* Hack -- Verify space */ + if (a_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!a_ptr->name) a_ptr->name = ++a_head->name_size; + + /* Append chars to the name */ + strcpy(a_name + a_head->name_size, s); + + /* Advance the index */ + a_head->name_size += strlen(s); + + /* Ignore everything */ + a_ptr->flags3 |= (TR3_IGNORE_ACID); + a_ptr->flags3 |= (TR3_IGNORE_ELEC); + a_ptr->flags3 |= (TR3_IGNORE_FIRE); + a_ptr->flags3 |= (TR3_IGNORE_COLD); + + /* Needed hack */ + a_ptr->esp = 0; + a_ptr->power = -1; + + /*Require activating artifacts to have a activation type */ + if (a_ptr && a_ptr->flags3 & TR3_ACTIVATE && !a_ptr->activate) + { + msg_print("Activate flag without activate type"); + return 1; + } + + /* Next... */ + continue; + } + + /* There better be a current a_ptr */ + if (!a_ptr) return (3); + + /* Process 'D' for "Description" */ + if (buf[0] == 'D') + { + /* Acquire the text */ + s = buf + 2; + + /* Hack -- Verify space */ + if (a_head->text_size + strlen(s) + 8 > fake_text_size) return (7); + + /* Advance and Save the text index */ + if (!a_ptr->text) a_ptr->text = ++a_head->text_size; + + /* Append a space at the end of the line, if needed */ + else if (a_text[a_head->text_size - 1] != ' ') + { + /* Append the space */ + strcpy(a_text + a_head->text_size, " "); + + /* Advance the index */ + a_head->text_size += 1; + } + + /* Append chars to the name */ + strcpy(a_text + a_head->text_size, s); + + /* Advance the index */ + a_head->text_size += strlen(s); + + /* Next... */ + continue; + } + + /* Process 'I' for "Info" (one line only) */ + if (buf[0] == 'I') + { + int tval, sval, pval; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d:%d:%d", + &tval, &sval, &pval)) + { + return (1); + } + + /* Save the values */ + a_ptr->tval = tval; + a_ptr->sval = sval; + a_ptr->pval = pval; + + /* Verify */ + if (!lookup_kind(tval, sval)) return (6); + + /* Next... */ + continue; + } + + /* Process 'W' for "More Info" (one line only) */ + if (buf[0] == 'W') + { + int level, rarity, wgt; + long cost; + + /* Scan for the values */ + if (4 != sscanf(buf + 2, "%d:%d:%d:%ld", + &level, &rarity, &wgt, &cost)) return (1); + + /* Save the values */ + a_ptr->level = level; + a_ptr->rarity = rarity; + a_ptr->weight = wgt; + a_ptr->cost = cost; + + /* Next... */ + continue; + } + + /* Hack -- Process 'P' for "power" and such */ + if (buf[0] == 'P') + { + int ac, hd1, hd2, th, td, ta; + + /* Scan for the values */ + if (6 != sscanf(buf + 2, "%d:%dd%d:%d:%d:%d", + &ac, &hd1, &hd2, &th, &td, &ta)) return (1); + + a_ptr->ac = ac; + a_ptr->dd = hd1; + a_ptr->ds = hd2; + a_ptr->to_h = th; + a_ptr->to_d = td; + a_ptr->to_a = ta; + + /* Next... */ + continue; + } + + /* Process 'Z' for "Granted power" */ + if (buf[0] == 'Z') + { + int i; + + /* Acquire the text */ + s = buf + 2; + + /* Find it in the list */ + for (i = 0; i < power_max; i++) + { + if (!stricmp(s, powers_type[i].name)) break; + } + + if (i == power_max) return (6); + + a_ptr->power = i; + + /* Next... */ + continue; + } + + /* Hack -- Process 'F' for flags */ + if (buf[0] == 'F') + { + /* Parse every entry textually */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while ((*t == ' ') || (*t == '|')) t++; + } + + /* Parse this entry */ + if (0 != grab_one_artifact_flag(a_ptr, s, FALSE)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Hack -- Process 'f' for obvious flags */ + if (buf[0] == 'f') + { + /* Parse every entry textually */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_artifact_flag(a_ptr, s, TRUE)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Read activation type. */ + if (buf[0] == 'a') + { + if (prefix(buf + 2, "HARDCORE=")) + { + a_ptr->activate = get_activation(buf + 11); + if (a_ptr->activate == -1) + return 1; + } + else if (prefix(buf + 2, "SPELL=")) + { + a_ptr->activate = -find_spell(buf + 8); + if (a_ptr->activate == -( -1)) + return 1; + } + + /* Next... */ + continue; + } + + + /* Oops */ + return (6); + } + + + /* Complete the "name" and "text" sizes */ + ++a_head->name_size; + ++a_head->text_size; + + + /* No version yet */ + if (!okay) return (2); + + + /* Success */ + return (0); +} + +/* +* Initialize the "set_info" array, by parsing an ascii "template" file +*/ +errr init_set_info_txt(FILE *fp, char *buf) +{ + int i; + int cur_art = 0, cur_num = 0; + + char *s, *t; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + set_type *set_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if (buf[0] == 'N') + { + int z, y; + + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i < error_idx) return (4); + + /* Verify information */ + if (i >= set_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + set_ptr = &set_info[i]; + + /* Hack -- Verify space */ + if (set_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!set_ptr->name) set_ptr->name = ++set_head->name_size; + + /* Append chars to the name */ + strcpy(set_name + set_head->name_size, s); + + /* Advance the index */ + set_head->name_size += strlen(s); + + /* Needed hack */ + set_ptr->num = 0; + set_ptr->num_use = 0; + for (z = 0; z < 6; z++) + { + set_ptr->arts[z].a_idx = 0; + set_ptr->arts[z].present = FALSE; + for (y = 0; y < 6; y++) + { + set_ptr->arts[z].flags1[y] = 0; + set_ptr->arts[z].flags2[y] = 0; + set_ptr->arts[z].flags3[y] = 0; + set_ptr->arts[z].flags4[y] = 0; + set_ptr->arts[z].flags5[y] = 0; + set_ptr->arts[z].esp[y] = 0; + set_ptr->arts[z].pval[y] = 0; + } + } + + /* Next... */ + continue; + } + + /* There better be a current set_ptr */ + if (!set_ptr) return (3); + + /* Process 'D' for "Description" */ + if (buf[0] == 'D') + { + /* Acquire the text */ + s = buf + 2; + + /* Hack -- Verify space */ + if (set_head->text_size + strlen(s) + 8 > fake_text_size) return (7); + + /* Advance and Save the text index */ + if (!set_ptr->desc) set_ptr->desc = ++set_head->text_size; + + /* Append chars to the name */ + strcpy(set_text + set_head->text_size, s); + + /* Advance the index */ + set_head->text_size += strlen(s); + + /* Next... */ + continue; + } + + /* Process 'P' for "Power" (up to 6) */ + if (buf[0] == 'P') + { + int a_idx, num, pval; + int z; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d:%d:%d", + &a_idx, &num, &pval)) + { + return (1); + } + + for (z = 0; z < set_ptr->num; z++) + if (set_ptr->arts[z].a_idx == a_idx) break; + if (z == set_ptr->num) + { + set_ptr->num++; + set_ptr->arts[z].a_idx = a_idx; + } + + /* Save the values */ + set_ptr->arts[z].pval[num - 1] = pval; + cur_art = z; + cur_num = num - 1; + + /* Next... */ + continue; + } + + /* Process 'F' for flags */ + if (buf[0] == 'F') + { + /* Parse every entry textually */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while ((*t == ' ') || (*t == '|')) t++; + } + + /* Parse this entry */ + if (0 != grab_one_race_kind_flag(&set_ptr->arts[cur_art].flags1[cur_num], + &set_ptr->arts[cur_art].flags2[cur_num], + &set_ptr->arts[cur_art].flags3[cur_num], + &set_ptr->arts[cur_art].flags4[cur_num], + &set_ptr->arts[cur_art].flags5[cur_num], + &set_ptr->arts[cur_art].esp[cur_num], + s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + + /* Oops */ + return (6); + } + + + /* Complete the "name" and "text" sizes */ + ++set_head->name_size; + ++set_head->text_size; + + + /* No version yet */ + if (!okay) return (2); + + + /* Success */ + return (0); +} + + +/* + * Initialize the "s_info" array, by parsing an ascii "template" file + */ +errr init_s_info_txt(FILE *fp, char *buf) +{ + int i, z, order = 1; + + char *s; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + skill_type *s_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'T' for "skill Tree" */ + if (buf[0] == 'T') + { + char *sec; + s16b s1, s2; + + /* Scan for the values */ + if (NULL == (sec = strchr(buf + 2, ':'))) + { + return (1); + } + *sec = '\0'; + sec++; + if (!*sec) return (1); + + s1 = find_skill(buf + 2); + s2 = find_skill(sec); + if (s2 == -1) return (1); + + s_info[s2].father = s1; + s_info[s2].order = order++; + + /* Next... */ + continue; + } + + /* Process 'E' for "Exclusive" */ + if (buf[0] == 'E') + { + char *sec; + s16b s1, s2; + + /* Scan for the values */ + if (NULL == (sec = strchr(buf + 2, ':'))) + { + return (1); + } + *sec = '\0'; + sec++; + if (!*sec) return (1); + + s1 = find_skill(buf + 2); + s2 = find_skill(sec); + if ((s1 == -1) || (s2 == -1)) return (1); + + s_info[s1].action[s2] = SKILL_EXCLUSIVE; + s_info[s2].action[s1] = SKILL_EXCLUSIVE; + + /* Next... */ + continue; + } + + + /* Process 'O' for "Opposite" */ + if (buf[0] == 'O') + { + char *sec, *cval; + s16b s1, s2; + + /* Scan for the values */ + if (NULL == (sec = strchr(buf + 2, ':'))) + { + return (1); + } + *sec = '\0'; + sec++; + if (!*sec) return (1); + if (NULL == (cval = strchr(sec, '%'))) + { + return (1); + } + *cval = '\0'; + cval++; + if (!*cval) return (1); + + s1 = find_skill(buf + 2); + s2 = find_skill(sec); + if ((s1 == -1) || (s2 == -1)) return (1); + + s_info[s1].action[s2] = -atoi(cval); + + /* Next... */ + continue; + } + + /* Process 'A' for "Amical/friendly" */ + if (buf[0] == 'f') + { + char *sec, *cval; + s16b s1, s2; + + /* Scan for the values */ + if (NULL == (sec = strchr(buf + 2, ':'))) + { + return (1); + } + *sec = '\0'; + sec++; + if (!*sec) return (1); + if (NULL == (cval = strchr(sec, '%'))) + { + return (1); + } + *cval = '\0'; + cval++; + if (!*cval) return (1); + + s1 = find_skill(buf + 2); + s2 = find_skill(sec); + if ((s1 == -1) || (s2 == -1)) return (1); + + s_info[s1].action[s2] = atoi(cval); + + /* Next... */ + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if (buf[0] == 'N') + { + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i >= s_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + s_ptr = &s_info[i]; + + /* Hack -- Verify space */ + if (s_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!s_ptr->name) s_ptr->name = ++s_head->name_size; + + /* Append chars to the name */ + strcpy(s_name + s_head->name_size, s); + + /* Advance the index */ + s_head->name_size += strlen(s); + + /* Init */ + s_ptr->action_mkey = 0; + s_ptr->dev = FALSE; + s_ptr->random_gain_chance = 100; + for (z = 0; z < max_s_idx; z++) + { + s_ptr->action[z] = 0; + } + + /* Next... */ + continue; + } + + /* There better be a current s_ptr */ + if (!s_ptr) return (3); + + /* Process 'D' for "Description" */ + if (buf[0] == 'D') + { + /* Acquire the text */ + s = buf + 2; + + /* Hack -- Verify space */ + if (s_head->text_size + strlen(s) + 8 > fake_text_size) return (7); + + /* Advance and Save the text index */ + if (!s_ptr->desc) + { + s_ptr->desc = ++s_head->text_size; + + /* Append chars to the name */ + strcpy(s_text + s_head->text_size, s); + + /* Advance the index */ + s_head->text_size += strlen(s); + } + else + { + /* Append chars to the name */ + strcpy(s_text + s_head->text_size, format("\n%s", s)); + + /* Advance the index */ + s_head->text_size += strlen(s) + 1; + } + + /* Next... */ + continue; + } + + /* Process 'A' for "Activation Description" */ + if (buf[0] == 'A') + { + char *txt; + + /* Acquire the text */ + s = buf + 2; + + if (NULL == (txt = strchr(s, ':'))) return (1); + *txt = '\0'; + txt++; + + /* Hack -- Verify space */ + if (s_head->text_size + strlen(txt) + 8 > fake_text_size) return (7); + + /* Advance and Save the text index */ + if (!s_ptr->action_desc) s_ptr->action_desc = ++s_head->text_size; + + /* Append chars to the name */ + strcpy(s_text + s_head->text_size, txt); + s_ptr->action_mkey = atoi(s); + + /* Advance the index */ + s_head->text_size += strlen(txt); + + /* Next... */ + continue; + } + + /* Process 'I' for "Info" (one line only) */ + if (buf[0] == 'I') + { + int rate; + + /* Scan for the values */ + if (1 != sscanf(buf + 2, "%d", &rate)) + { + return (1); + } + + /* Save the values */ + s_ptr->rate = rate; + + /* Next... */ + continue; + } + + /* Process 'G' for "random Gain" (one line only) */ + if (buf[0] == 'G') + { + int chance; + + /* Scan for the values */ + if (1 != sscanf(buf + 2, "%d", &chance)) + { + return (1); + } + + /* Save the values */ + s_ptr->random_gain_chance = chance; + + /* Next... */ + continue; + } + + /* Process 'F' for flags */ + if (buf[0] == 'F') + { + char *t; + + /* Parse every entry textually */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while ((*t == ' ') || (*t == '|')) t++; + } + + /* Parse this entry */ + if (0 != grab_one_skill_flag(&(s_ptr->flags1), s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Oops */ + return (6); + } + + + /* Complete the "name" and "text" sizes */ + ++s_head->name_size; + ++s_head->text_size; + + + /* No version yet */ + if (!okay) return (2); + + + /* Success */ + return (0); +} + +/* + * Initialize the "ab_info" array, by parsing an ascii "template" file + */ +errr init_ab_info_txt(FILE *fp, char *buf) +{ + int i, z; + + char *s; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + ability_type *ab_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if (buf[0] == 'N') + { + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i >= ab_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + ab_ptr = &ab_info[i]; + + /* Hack -- Verify space */ + if (ab_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!ab_ptr->name) ab_ptr->name = ++ab_head->name_size; + + /* Append chars to the name */ + strcpy(ab_name + ab_head->name_size, s); + + /* Advance the index */ + ab_head->name_size += strlen(s); + + /* Init */ + ab_ptr->action_mkey = 0; + ab_ptr->acquired = FALSE; + for (z = 0; z < 10; z++) + { + ab_ptr->skills[z] = -1; + ab_ptr->need_abilities[z] = -1; + ab_ptr->forbid_abilities[z] = -1; + } + for (z = 0; z < 6; z++) + { + ab_ptr->stat[z] = -1; + } + + /* Next... */ + continue; + } + + /* There better be a current ab_ptr */ + if (!ab_ptr) return (3); + + /* Process 'D' for "Description" */ + if (buf[0] == 'D') + { + /* Acquire the text */ + s = buf + 2; + + /* Hack -- Verify space */ + if (ab_head->text_size + strlen(s) + 8 > fake_text_size) return (7); + + /* Advance and Save the text index */ + if (!ab_ptr->desc) + { + ab_ptr->desc = ++ab_head->text_size; + + /* Append chars to the name */ + strcpy(ab_text + ab_head->text_size, s); + + /* Advance the index */ + ab_head->text_size += strlen(s); + } + else + { + /* Append chars to the name */ + strcpy(ab_text + ab_head->text_size, format("\n%s", s)); + + /* Advance the index */ + ab_head->text_size += strlen(s) + 1; + } + + /* Next... */ + continue; + } + + /* Process 'A' for "Activation Description" */ + if (buf[0] == 'A') + { + char *txt; + + /* Acquire the text */ + s = buf + 2; + + if (NULL == (txt = strchr(s, ':'))) return (1); + *txt = '\0'; + txt++; + + /* Hack -- Verify space */ + if (ab_head->text_size + strlen(txt) + 8 > fake_text_size) return (7); + + /* Advance and Save the text index */ + if (!ab_ptr->action_desc) ab_ptr->action_desc = ++ab_head->text_size; + + /* Append chars to the name */ + strcpy(ab_text + ab_head->text_size, txt); + ab_ptr->action_mkey = atoi(s); + + /* Advance the index */ + ab_head->text_size += strlen(txt); + + /* Next... */ + continue; + } + + /* Process 'I' for "Info" (one line only) */ + if (buf[0] == 'I') + { + int cost; + + /* Scan for the values */ + if (1 != sscanf(buf + 2, "%d", &cost)) + { + return (1); + } + + /* Save the values */ + ab_ptr->cost = cost; + + /* Next... */ + continue; + } + + /* Process 'k' for "Skill" */ + if (buf[0] == 'k') + { + char *sec; + s16b level, skill; + + /* Scan for the values */ + if (NULL == (sec = strchr(buf + 2, ':'))) + { + return (1); + } + *sec = '\0'; + sec++; + if (!*sec) return (1); + + level = atoi(buf + 2); + skill = find_skill(sec); + + if (skill == -1) return (1); + + for (z = 0; z < 10; z++) + if (ab_ptr->skills[z] == -1) break; + + if (z < 10) + { + ab_ptr->skills[z] = skill; + ab_ptr->skill_levels[z] = level; + } + + /* Next... */ + continue; + } + + /* Process 'a' for "needed ability" */ + if (buf[0] == 'a') + { + s16b ab; + + ab = find_ability(buf + 2); + + if (ab == -1) return (1); + + for (z = 0; z < 10; z++) + if (ab_ptr->need_abilities[z] == -1) break; + + if (z < 10) + { + ab_ptr->need_abilities[z] = ab; + } + + /* Next... */ + continue; + } + + /* Process 'S' for "Stat" */ + if (buf[0] == 'S') + { + char *sec; + s16b stat; + + /* Scan for the values */ + if (NULL == (sec = strchr(buf + 2, ':'))) + { + return (1); + } + *sec = '\0'; + sec++; + if (!*sec) return (1); + + for (stat = 0; stat < 6; stat++) + { + if (!strcmp(stat_names[stat], sec)) + break; + } + + if (stat == 6) return (1); + + ab_ptr->stat[stat] = atoi(buf + 2); + + /* Next... */ + continue; + } + + /* Process 'E' for "Excluding ability" */ + if (buf[0] == 'E') + { + char *sec; + s16b ab1, ab2; + + /* Scan for the values */ + if (NULL == (sec = strchr(buf + 2, ':'))) + { + return (1); + } + *sec = '\0'; + sec++; + if (!*sec) return (1); + + ab1 = find_ability(buf + 2); + ab2 = find_ability(sec); + + if ((ab1 == -1) || (ab2 == -1)) return (1); + + for (z = 0; z < 10; z++) + if (ab_info[ab1].forbid_abilities[z] == -1) break; + if (z < 10) + { + ab_info[ab1].forbid_abilities[z] = ab2; + } + + for (z = 0; z < 10; z++) + if (ab_info[ab2].forbid_abilities[z] == -1) break; + if (z < 10) + { + ab_info[ab2].forbid_abilities[z] = ab1; + } + + /* Next... */ + continue; + } + + /* Oops */ + return (6); + } + + + /* Complete the "name" and "text" sizes */ + ++ab_head->name_size; + ++ab_head->text_size; + + + /* No version yet */ + if (!okay) return (2); + + + /* Success */ + return (0); +} + + +/* + * Grab one flag in a ego-item_type from a textual string + */ +static bool_ grab_one_ego_item_flag(ego_item_type *e_ptr, cptr what, int n, bool_ obvious) +{ + int i; + + /* Check flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags1[i])) + { + if (obvious) + e_ptr->oflags1[n] |= (1L << i); + else + e_ptr->flags1[n] |= (1L << i); + return (0); + } + } + + /* Check flags2 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags2[i])) + { + if (obvious) + e_ptr->oflags2[n] |= (1L << i); + else + e_ptr->flags2[n] |= (1L << i); + return (0); + } + } + + /* Check flags2 -- traps */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags2_trap[i])) + { + if (obvious) + e_ptr->oflags2[n] |= (1L << i); + else + e_ptr->flags2[n] |= (1L << i); + return (0); + } + } + + /* Check flags3 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags3[i])) + { + if (obvious) + e_ptr->oflags3[n] |= (1L << i); + else + e_ptr->flags3[n] |= (1L << i); + return (0); + } + } + + /* Check flags4 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags4[i])) + { + if (obvious) + e_ptr->oflags4[n] |= (1L << i); + else + e_ptr->flags4[n] |= (1L << i); + return (0); + } + } + + /* Check flags5 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags5[i])) + { + if (obvious) + e_ptr->oflags5[n] |= (1L << i); + else + e_ptr->flags5[n] |= (1L << i); + return (0); + } + } + + /* Check esp_flags */ + for (i = 0; i < 32; i++) + { + if (streq(what, esp_flags[i])) + { + if (obvious) + e_ptr->oesp[n] |= (1L << i); + else + e_ptr->esp[n] |= (1L << i); + return (0); + } + } + + /* Check ego_flags */ + for (i = 0; i < 32; i++) + { + if (streq(what, ego_flags[i])) + { + e_ptr->fego[n] |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("Unknown ego-item flag '%s'.", what); + + /* Error */ + return (1); +} + +static bool_ grab_one_ego_item_flag_restrict(ego_item_type *e_ptr, cptr what, bool_ need) +{ + int i; + + /* Check flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags1[i])) + { + if (need) + e_ptr->need_flags1 |= (1L << i); + else + e_ptr->forbid_flags1 |= (1L << i); + return (0); + } + } + + /* Check flags2 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags2[i])) + { + if (need) + e_ptr->need_flags2 |= (1L << i); + else + e_ptr->forbid_flags2 |= (1L << i); + return (0); + } + } + + /* Check flags2 -- traps */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags2_trap[i])) + { + if (need) + e_ptr->need_flags2 |= (1L << i); + else + e_ptr->forbid_flags2 |= (1L << i); + return (0); + } + } + + /* Check flags3 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags3[i])) + { + if (need) + e_ptr->need_flags3 |= (1L << i); + else + e_ptr->forbid_flags3 |= (1L << i); + return (0); + } + } + + /* Check flags4 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags4[i])) + { + if (need) + e_ptr->need_flags4 |= (1L << i); + else + e_ptr->forbid_flags4 |= (1L << i); + return (0); + } + } + + /* Check flags5 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags5[i])) + { + if (need) + e_ptr->need_flags5 |= (1L << i); + else + e_ptr->forbid_flags5 |= (1L << i); + return (0); + } + } + + /* Check esp_flags */ + for (i = 0; i < 32; i++) + { + if (streq(what, esp_flags[i])) + { + if (need) + e_ptr->need_esp |= (1L << i); + else + e_ptr->forbid_esp |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("Unknown ego-item restrict flag '%s'.", what); + + /* Error */ + return (1); +} + + + + +/* + * Initialize the "e_info" array, by parsing an ascii "template" file + */ +errr init_e_info_txt(FILE *fp, char *buf) +{ + int i, cur_r = -1, cur_t = 0, j; + + char *s, *t; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + ego_item_type *e_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if (buf[0] == 'N') + { + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i < error_idx) return (4); + + /* Verify information */ + if (i >= e_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + e_ptr = &e_info[i]; + + /* Hack -- Verify space */ + if (e_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!e_ptr->name) e_ptr->name = ++e_head->name_size; + + /* Append chars to the name */ + strcpy(e_name + e_head->name_size, s); + + /* Advance the index */ + e_head->name_size += strlen(s); + + /* Needed hack */ + e_ptr->power = -1; + cur_r = -1; + cur_t = 0; + + for (j = 0; j < 10; j++) + { + e_ptr->tval[j] = 255; + } + for (j = 0; j < 5; j++) + { + e_ptr->rar[j] = 0; + e_ptr->flags1[j] = 0; + e_ptr->flags2[j] = 0; + e_ptr->flags3[j] = 0; + e_ptr->flags4[j] = 0; + e_ptr->flags5[j] = 0; + e_ptr->esp[j] = 0; + } + + /* Next... */ + continue; + } + + /* There better be a current e_ptr */ + if (!e_ptr) return (3); + + + /* Process 'T' for "Tval/Sval" (up to 5 lines) */ + if (buf[0] == 'T') + { + int tv, minsv, maxsv; + + if (cur_t == 10) return 1; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d:%d:%d", + &tv, &minsv, &maxsv)) return (1); + + /* Save the values */ + e_ptr->tval[cur_t] = tv; + e_ptr->min_sval[cur_t] = minsv; + e_ptr->max_sval[cur_t] = maxsv; + + cur_t++; + + /* Next... */ + continue; + } + + /* Process 'R' for "flags rarity" (up to 5 lines) */ + if (buf[0] == 'R') + { + int rar; + + if (cur_r == 5) return 1; + + /* Scan for the values */ + if (1 != sscanf(buf + 2, "%d", + &rar)) return (1); + + cur_r++; + + /* Save the values */ + e_ptr->rar[cur_r] = rar; + + /* Next... */ + continue; + } + + /* Process 'X' for "Xtra" (one line only) */ + if (buf[0] == 'X') + { + int slot, rating; + char pos; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%c:%d:%d", + &pos, &slot, &rating)) return (1); + + /* Save the values */ + /* e_ptr->slot = slot; */ + e_ptr->rating = rating; + e_ptr->before = (pos == 'B') ? TRUE : FALSE; + + /* Next... */ + continue; + } + + /* Process 'W' for "More Info" (one line only) */ + if (buf[0] == 'W') + { + int level, rarity, rarity2; + long cost; + + /* Scan for the values */ + if (4 != sscanf(buf + 2, "%d:%d:%d:%ld", + &level, &rarity, &rarity2, &cost)) return (1); + + /* Save the values */ + e_ptr->level = level; + e_ptr->rarity = rarity; + e_ptr->mrarity = rarity2; + e_ptr->cost = cost; + + /* Next... */ + continue; + } + + /* Hack -- Process 'C' for "creation" */ + if (buf[0] == 'C') + { + int th, td, ta, pv; + + /* Scan for the values */ + if (4 != sscanf(buf + 2, "%d:%d:%d:%d", + &th, &td, &ta, &pv)) return (1); + + e_ptr->max_to_h = th; + e_ptr->max_to_d = td; + e_ptr->max_to_a = ta; + e_ptr->max_pval = pv; + + /* Next... */ + continue; + } + + /* Process 'Z' for "Granted power" */ + if (buf[0] == 'Z') + { + int i; + + /* Acquire the text */ + s = buf + 2; + + /* Find it in the list */ + for (i = 0; i < power_max; i++) + { + if (!stricmp(s, powers_type[i].name)) break; + } + + if (i == power_max) return (6); + + e_ptr->power = i; + + /* Next... */ + continue; + } + + if (buf[0] == 'a') + { + if (prefix(buf + 2, "HARDCORE=")) + { + e_ptr->activate = get_activation(buf + 11); + if (e_ptr->activate == -1) + return 1; + } + else if (prefix(buf + 2, "SPELL=")) + { + e_ptr->activate = -find_spell(buf + 8); + if (e_ptr->activate == -( -1)) + return 1; + } + + /* Next... */ + continue; + } + + /* Hack -- Process 'r:N' for needed flags */ + if ((buf[0] == 'r') && (buf[2] == 'N')) + { + /* Parse every entry textually */ + for (s = buf + 4; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while ((*t == ' ') || (*t == '|')) t++; + } + + /* Parse this entry */ + if (0 != grab_one_ego_item_flag_restrict(e_ptr, s, TRUE)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Hack -- Process 'r:F' for forbidden flags */ + if ((buf[0] == 'r') && (buf[2] == 'F')) + { + /* Parse every entry textually */ + for (s = buf + 4; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while ((*t == ' ') || (*t == '|')) t++; + } + + /* Parse this entry */ + if (0 != grab_one_ego_item_flag_restrict(e_ptr, s, FALSE)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Hack -- Process 'F' for flags */ + if (buf[0] == 'F') + { + if (cur_r == -1) return (6); + + /* Parse every entry textually */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while ((*t == ' ') || (*t == '|')) t++; + } + + /* Parse this entry */ + if (0 != grab_one_ego_item_flag(e_ptr, s, cur_r, FALSE)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Hack -- Process 'f' for obvious flags */ + if (buf[0] == 'f') + { + if (cur_r == -1) return (6); + + /* Parse every entry textually */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while ((*t == ' ') || (*t == '|')) t++; + } + + /* Parse this entry */ + if (0 != grab_one_ego_item_flag(e_ptr, s, cur_r, TRUE)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Oops */ + return (6); + } + + + /* Complete the "name" and "text" sizes */ + ++e_head->name_size; + ++e_head->text_size; + + + /* No version yet */ + if (!okay) return (2); + + + /* Success */ + return (0); +} + +/* + * Grab one flag in a randart_part_type from a textual string + */ +static bool_ grab_one_randart_item_flag(randart_part_type *ra_ptr, cptr what, char c) +{ + int i; + u32b *f1, *f2, *f3, *f4, *f5, *esp; + + if (c == 'F') + { + f1 = &ra_ptr->flags1; + f2 = &ra_ptr->flags2; + f3 = &ra_ptr->flags3; + f4 = &ra_ptr->flags4; + f5 = &ra_ptr->flags5; + esp = &ra_ptr->esp; + } + else + { + f1 = &ra_ptr->aflags1; + f2 = &ra_ptr->aflags2; + f3 = &ra_ptr->aflags3; + f4 = &ra_ptr->aflags4; + f5 = &ra_ptr->aflags5; + esp = &ra_ptr->aesp; + } + + /* Check flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags1[i])) + { + *f1 |= (1L << i); + return (0); + } + } + + /* Check flags2 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags2[i])) + { + *f2 |= (1L << i); + return (0); + } + } + + /* Check flags2 -- traps */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags2_trap[i])) + { + *f2 |= (1L << i); + return (0); + } + } + + /* Check flags3 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags3[i])) + { + *f3 |= (1L << i); + return (0); + } + } + + /* Check flags4 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags4[i])) + { + *f4 |= (1L << i); + return (0); + } + } + + /* Check flags5 */ + for (i = 0; i < 32; i++) + { + if (streq(what, k_info_flags5[i])) + { + *f5 |= (1L << i); + return (0); + } + } + + /* Check esp_flags */ + for (i = 0; i < 32; i++) + { + if (streq(what, esp_flags[i])) + { + *esp |= (1L << i); + return (0); + } + } + + /* Check ego_flags */ + if (c == 'F') + { + for (i = 0; i < 32; i++) + { + if (streq(what, ego_flags[i])) + { + ra_ptr->fego |= (1L << i); + return (0); + } + } + } + + /* Oops */ + msg_format("Unknown ego-item flag '%s'.", what); + + /* Error */ + return (1); +} + + + + +/* + * Initialize the "ra_info" array, by parsing an ascii "template" file + */ +errr init_ra_info_txt(FILE *fp, char *buf) +{ + int i, cur_t = 0, j, cur_g = 0; + + char *s, *t; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + randart_part_type *ra_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'G' for "General" (up to 30 lines) */ + if (buf[0] == 'G') + { + int chance, dd, ds, plus; + + /* Scan for the values */ + if (4 != sscanf(buf + 2, "%d:%dd%d:%d", + &chance, &dd, &ds, &plus)) return (1); + + /* Save the values */ + ra_gen[cur_g].chance = chance; + ra_gen[cur_g].dd = dd; + ra_gen[cur_g].ds = ds; + ra_gen[cur_g].plus = plus; + cur_g++; + + /* Next... */ + continue; + } + + /* Process 'N' for "New/Number" */ + if (buf[0] == 'N') + { + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i < error_idx) return (4); + + /* Verify information */ + if (i >= ra_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + ra_ptr = &ra_info[i]; + + /* Needed hack */ + ra_ptr->power = -1; + cur_t = 0; + + for (j = 0; j < 20; j++) + { + ra_ptr->tval[j] = 255; + } + ra_ptr->flags1 = 0; + ra_ptr->flags2 = 0; + ra_ptr->flags3 = 0; + ra_ptr->flags4 = 0; + ra_ptr->flags5 = 0; + ra_ptr->esp = 0; + ra_ptr->fego = 0; + + /* Next... */ + continue; + } + + /* There better be a current ra_ptr */ + if (!ra_ptr) return (3); + + /* Process 'T' for "Tval/Sval" (up to 5 lines) */ + if (buf[0] == 'T') + { + int tv, minsv, maxsv; + + if (cur_t == 20) return 1; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d:%d:%d", + &tv, &minsv, &maxsv)) return (1); + + /* Save the values */ + ra_ptr->tval[cur_t] = tv; + ra_ptr->min_sval[cur_t] = minsv; + ra_ptr->max_sval[cur_t] = maxsv; + + cur_t++; + + /* Next... */ + continue; + } + + /* Process 'X' for "Xtra" (one line only) */ + if (buf[0] == 'X') + { + int power, max; + + /* Scan for the values */ + if (2 != sscanf(buf + 2, "%d:%d", + &power, &max)) return (1); + + /* Save the values */ + ra_ptr->value = power; + ra_ptr->max = max; + + /* Next... */ + continue; + } + + /* Process 'W' for "More Info" (one line only) */ + if (buf[0] == 'W') + { + int level, rarity, rarity2; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d:%d:%d", + &level, &rarity, &rarity2)) return (1); + + /* Save the values */ + ra_ptr->level = level; + ra_ptr->rarity = rarity; + ra_ptr->mrarity = rarity2; + + /* Next... */ + continue; + } + + /* Hack -- Process 'C' for "creation" */ + if (buf[0] == 'C') + { + int th, td, ta, pv; + + /* Scan for the values */ + if (4 != sscanf(buf + 2, "%d:%d:%d:%d", + &th, &td, &ta, &pv)) return (1); + + ra_ptr->max_to_h = th; + ra_ptr->max_to_d = td; + ra_ptr->max_to_a = ta; + ra_ptr->max_pval = pv; + + /* Next... */ + continue; + } + + /* Process 'Z' for "Granted power" */ + if (buf[0] == 'Z') + { + int i; + + /* Acquire the text */ + s = buf + 2; + + /* Find it in the list */ + for (i = 0; i < power_max; i++) + { + if (!stricmp(s, powers_type[i].name)) break; + } + + if (i == power_max) return (6); + + ra_ptr->power = i; + + /* Next... */ + continue; + } + + /* Hack -- Process 'F' for flags */ + if (buf[0] == 'F') + { + /* Parse every entry textually */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while ((*t == ' ') || (*t == '|')) t++; + } + + /* Parse this entry */ + if (0 != grab_one_randart_item_flag(ra_ptr, s, 'F')) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Hack -- Process 'A' for antagonic flags */ + if (buf[0] == 'A') + { + /* Parse every entry textually */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while ((*t == ' ') || (*t == '|')) t++; + } + + /* Parse this entry */ + if (0 != grab_one_randart_item_flag(ra_ptr, s, 'A')) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Oops */ + return (6); + } + + + /* No version yet */ + if (!okay) return (2); + + + /* Success */ + return (0); +} + +/* + * Grab one (basic) flag in a monster_race from a textual string + */ +static errr grab_one_basic_flag(monster_race *r_ptr, cptr what) +{ + int i; + + /* Scan flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags1[i])) + { + r_ptr->flags1 |= (1L << i); + return (0); + } + } + + /* Scan flags2 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags2[i])) + { + r_ptr->flags2 |= (1L << i); + return (0); + } + } + + /* Scan flags3 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags3[i])) + { + r_ptr->flags3 |= (1L << i); + return (0); + } + } + + /* Scan flags7 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags7[i])) + { + r_ptr->flags7 |= (1L << i); + return (0); + } + } + + /* Scan flags8 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags8[i])) + { + r_ptr->flags8 |= (1L << i); + return (0); + } + } + + /* Scan flags9 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags9[i])) + { + r_ptr->flags9 |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("Unknown monster flag '%s'.", what); + + /* Failure */ + return (1); +} + + +/* + * Grab one (spell) flag in a monster_race from a textual string + */ +static errr grab_one_spell_flag(monster_race *r_ptr, cptr what) +{ + int i; + + /* Scan flags4 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags4[i])) + { + r_ptr->flags4 |= (1L << i); + return (0); + } + } + + /* Scan flags5 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags5[i])) + { + r_ptr->flags5 |= (1L << i); + return (0); + } + } + + /* Scan flags6 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags6[i])) + { + r_ptr->flags6 |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("Unknown monster flag '%s'.", what); + + /* Failure */ + return (1); +} + + +/* + * Initialize the "r_info" array, by parsing an ascii "template" file + */ +errr init_r_info_txt(FILE *fp, char *buf) +{ + int i; + + char *s, *t; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + monster_race *r_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Start the "fake" stuff */ + r_head->name_size = 0; + r_head->text_size = 0; + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if (buf[0] == 'N') + { + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i < error_idx) return (4); + + /* Verify information */ + if (i >= r_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + r_ptr = &r_info[i]; + + /* Hack -- Verify space */ + if (r_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!r_ptr->name) r_ptr->name = ++r_head->name_size; + + /* Append chars to the name */ + strcpy(r_name + r_head->name_size, s); + + /* Advance the index */ + r_head->name_size += strlen(s); + + /* HACK -- Those ones HAVE to have a set default value */ + r_ptr->drops.treasure = OBJ_GENE_TREASURE; + r_ptr->drops.combat = OBJ_GENE_COMBAT; + r_ptr->drops.magic = OBJ_GENE_MAGIC; + r_ptr->drops.tools = OBJ_GENE_TOOL; + r_ptr->freq_inate = r_ptr->freq_spell = 0; + + /* Next... */ + continue; + } + + /* There better be a current r_ptr */ + if (!r_ptr) return (3); + + + /* Process 'D' for "Description" */ + if (buf[0] == 'D') + { + /* Acquire the text */ + s = buf + 2; + + /* Hack -- Verify space */ + if (r_head->text_size + strlen(s) + 8 > fake_text_size) return (7); + + /* Advance and Save the text index */ + if (!r_ptr->text) r_ptr->text = ++r_head->text_size; + + /* Append chars to the name */ + strcpy(r_text + r_head->text_size, s); + + /* Advance the index */ + r_head->text_size += strlen(s); + + /* Next... */ + continue; + } + + /* Process 'G' for "Graphics" (one line only) */ + if (buf[0] == 'G') + { + char sym; + int tmp; + + /* Paranoia */ + if (!buf[2]) return (1); + if (!buf[3]) return (1); + if (!buf[4]) return (1); + + /* Extract the char */ + sym = buf[2]; + + /* Extract the attr */ + tmp = color_char_to_attr(buf[4]); + + /* Paranoia */ + if (tmp < 0) return (1); + + /* Save the values */ + r_ptr->d_char = sym; + r_ptr->d_attr = tmp; + + /* Next... */ + continue; + } + + /* Process 'I' for "Info" (one line only) */ + if (buf[0] == 'I') + { + int spd, hp1, hp2, aaf, ac, slp; + + /* Scan for the other values */ + if (6 != sscanf(buf + 2, "%d:%dd%d:%d:%d:%d", + &spd, &hp1, &hp2, &aaf, &ac, &slp)) return (1); + + /* Save the values */ + r_ptr->speed = spd; + r_ptr->hdice = hp1; + r_ptr->hside = hp2; + r_ptr->aaf = aaf; + r_ptr->ac = ac; + r_ptr->sleep = slp; + + /* Next... */ + continue; + } + + /* Process 'E' for "Body Parts" (one line only) */ + if (buf[0] == 'E') + { + int weap, tors, fing, head, arms, legs; + + /* Scan for the other values */ + if (BODY_MAX != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d", + &weap, &tors, &arms, &fing, &head, &legs)) return (1); + + /* Save the values */ + r_ptr->body_parts[BODY_WEAPON] = weap; + r_ptr->body_parts[BODY_TORSO] = tors; + r_ptr->body_parts[BODY_ARMS] = arms; + r_ptr->body_parts[BODY_FINGER] = fing; + r_ptr->body_parts[BODY_HEAD] = head; + r_ptr->body_parts[BODY_LEGS] = legs; + + /* Mega debugging hack */ + if (weap > arms) quit(format("monster %d, %d weapon(s), %d arm(s) !", error_idx, weap, arms)); + + /* Next... */ + continue; + } + + /* Process 'O' for "Object type" (one line only) */ + if (buf[0] == 'O') + { + int treasure, combat, magic, tools; + + /* Scan for the values */ + if (4 != sscanf(buf + 2, "%d:%d:%d:%d", + &treasure, &combat, &magic, &tools)) return (1); + + /* Save the values */ + r_ptr->drops.treasure = treasure; + r_ptr->drops.combat = combat; + r_ptr->drops.magic = magic; + r_ptr->drops.tools = tools; + + /* Next... */ + continue; + } + + /* Process 'W' for "More Info" (one line only) */ + if (buf[0] == 'W') + { + int lev, rar, wt; + long exp; + + /* Scan for the values */ + if (4 != sscanf(buf + 2, "%d:%d:%d:%ld", + &lev, &rar, &wt, &exp)) return (1); + + /* Save the values */ + r_ptr->level = lev; + r_ptr->rarity = rar; + /* MEGA HACK */ + if (!wt) wt = 100; + r_ptr->weight = wt; + r_ptr->mexp = exp; + + /* Next... */ + continue; + } + + /* Process 'B' for "Blows" (up to four lines) */ + if (buf[0] == 'B') + { + int n1, n2; + + /* Find the next empty blow slot (if any) */ + for (i = 0; i < 4; i++) if (!r_ptr->blow[i].method) break; + + /* Oops, no more slots */ + if (i == 4) return (1); + + /* Analyze the first field */ + for (s = t = buf + 2; *t && (*t != ':'); t++) /* loop */; + + /* Terminate the field (if necessary) */ + if (*t == ':') *t++ = '\0'; + + /* Analyze the method */ + for (n1 = 0; r_info_blow_method[n1]; n1++) + { + if (streq(s, r_info_blow_method[n1])) break; + } + + /* Invalid method */ + if (!r_info_blow_method[n1]) return (1); + + /* Analyze the second field */ + for (s = t; *t && (*t != ':'); t++) /* loop */; + + /* Terminate the field (if necessary) */ + if (*t == ':') *t++ = '\0'; + + /* Analyze effect */ + for (n2 = 0; r_info_blow_effect[n2]; n2++) + { + if (streq(s, r_info_blow_effect[n2])) break; + } + + /* Invalid effect */ + if (!r_info_blow_effect[n2]) return (1); + + /* Analyze the third field */ + for (s = t; *t && (*t != 'd'); t++) /* loop */; + + /* Terminate the field (if necessary) */ + if (*t == 'd') *t++ = '\0'; + + /* Save the method */ + r_ptr->blow[i].method = n1; + + /* Save the effect */ + r_ptr->blow[i].effect = n2; + + /* Extract the damage dice and sides */ + r_ptr->blow[i].d_dice = atoi(s); + r_ptr->blow[i].d_side = atoi(t); + + /* Next... */ + continue; + } + + /* Process 'F' for "Basic Flags" (multiple lines) */ + if (buf[0] == 'F') + { + /* Parse every entry */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_basic_flag(r_ptr, s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'S' for "Spell Flags" (multiple lines) */ + if (buf[0] == 'S') + { + /* Parse every entry */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while ((*t == ' ') || (*t == '|')) t++; + } + + /* XXX XXX XXX Hack -- Read spell frequency */ + if (1 == sscanf(s, "1_IN_%d", &i)) + { + /* Extract a "frequency" */ + r_ptr->freq_spell = r_ptr->freq_inate = 100 / i; + + /* Start at next entry */ + s = t; + + /* Continue */ + continue; + } + + /* Parse this entry */ + if (0 != grab_one_spell_flag(r_ptr, s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Oops */ + return (6); + } + + + /* Complete the "name" and "text" sizes */ + ++r_head->name_size; + ++r_head->text_size; + + for (i = 1; i < max_r_idx; i++) + { + /* Invert flag WILD_ONLY <-> RF8_DUNGEON */ + r_info[i].flags8 ^= 1L; + + /* WILD_TOO without any other wilderness flags enables all flags */ + if ((r_info[i].flags8 & RF8_WILD_TOO) && !(r_info[i].flags8 & 0x7FFFFFFE)) + r_info[i].flags8 = 0x0463; + } + + /* No version yet */ + if (!okay) return (2); + + /* Success */ + return (0); +} + + +/* + * Grab one (basic) flag in a monster_race from a textual string + */ +static errr grab_one_basic_ego_flag(monster_ego *re_ptr, cptr what, bool_ add) +{ + int i; + + /* Scan flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags1[i])) + { + if (add) + re_ptr->mflags1 |= (1L << i); + else + re_ptr->nflags1 |= (1L << i); + return (0); + } + } + + /* Scan flags2 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags2[i])) + { + if (add) + re_ptr->mflags2 |= (1L << i); + else + re_ptr->nflags2 |= (1L << i); + return (0); + } + } + + /* Scan flags3 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags3[i])) + { + if (add) + re_ptr->mflags3 |= (1L << i); + else + re_ptr->nflags3 |= (1L << i); + return (0); + } + } + + /* Scan flags7 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags7[i])) + { + if (add) + re_ptr->mflags7 |= (1L << i); + else + re_ptr->nflags7 |= (1L << i); + return (0); + } + } + + /* Scan flags8 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags8[i])) + { + if (add) + re_ptr->mflags8 |= (1L << i); + else + re_ptr->nflags8 |= (1L << i); + return (0); + } + } + + /* Scan flags9 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags9[i])) + { + if (add) + re_ptr->mflags9 |= (1L << i); + else + re_ptr->nflags9 |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("Unknown monster flag '%s'.", what); + + /* Failure */ + return (1); +} + + +/* + * Grab one (spell) flag in a monster_race from a textual string + */ +static errr grab_one_spell_ego_flag(monster_ego *re_ptr, cptr what, bool_ add) +{ + int i; + + /* Scan flags4 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags4[i])) + { + if (add) + re_ptr->mflags4 |= (1L << i); + else + re_ptr->nflags4 |= (1L << i); + return (0); + } + } + + /* Scan flags5 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags5[i])) + { + if (add) + re_ptr->mflags5 |= (1L << i); + else + re_ptr->nflags5 |= (1L << i); + return (0); + } + } + + /* Scan flags6 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags6[i])) + { + if (add) + re_ptr->mflags6 |= (1L << i); + else + re_ptr->nflags6 |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("Unknown monster flag '%s'.", what); + + /* Failure */ + return (1); +} + +/* + * Grab one (basic) flag in a monster_race from a textual string + */ +static errr grab_one_ego_flag(monster_ego *re_ptr, cptr what, bool_ must) +{ + int i; + + /* Scan flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags1[i])) + { + if (must) re_ptr->flags1 |= (1L << i); + else re_ptr->hflags1 |= (1L << i); + return (0); + } + } + + /* Scan flags2 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags2[i])) + { + if (must) re_ptr->flags2 |= (1L << i); + else re_ptr->hflags2 |= (1L << i); + return (0); + } + } + + /* Scan flags3 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags3[i])) + { + if (must) re_ptr->flags3 |= (1L << i); + else re_ptr->hflags3 |= (1L << i); + return (0); + } + } + + /* Scan flags7 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags7[i])) + { + if (must) re_ptr->flags7 |= (1L << i); + else re_ptr->hflags7 |= (1L << i); + return (0); + } + } + + /* Scan flags8 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags8[i])) + { + if (must) re_ptr->flags8 |= (1L << i); + else re_ptr->hflags8 |= (1L << i); + return (0); + } + } + + /* Scan flags9 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags9[i])) + { + if (must) re_ptr->flags9 |= (1L << i); + else re_ptr->hflags9 |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("Unknown monster flag '%s'.", what); + + /* Failure */ + return (1); +} + +/* + * Initialize the "re_info" array, by parsing an ascii "template" file + */ +errr init_re_info_txt(FILE *fp, char *buf) +{ + int i, j; + + byte blow_num = 0; + int r_char_number = 0, nr_char_number = 0; + + char *s, *t; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + monster_ego *re_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Start the "fake" stuff */ + re_head->name_size = 0; + re_head->text_size = 0; + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if (buf[0] == 'N') + { + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i < error_idx) return (4); + + /* Verify information */ + if (i >= re_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + re_ptr = &re_info[i]; + + /* Hack -- Verify space */ + if (re_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!re_ptr->name) re_ptr->name = ++re_head->name_size; + + /* Append chars to the name */ + strcpy(re_name + re_head->name_size, s); + + /* Advance the index */ + re_head->name_size += strlen(s); + + /* Some inits */ + blow_num = 0; + r_char_number = 0; + nr_char_number = 0; + for (j = 0; j < 5; j++) re_ptr->r_char[j] = 0; + for (j = 0; j < 5; j++) re_ptr->nr_char[j] = 0; + for (j = 0; j < 4; j++) + { + re_ptr->blow[j].method = 0; + re_ptr->blow[j].effect = 0; + re_ptr->blow[j].d_dice = 0; + re_ptr->blow[j].d_side = 0; + re_ptr->blowm[j][0] = MEGO_ADD; + re_ptr->blowm[j][1] = MEGO_ADD; + } + + /* Next... */ + continue; + } + + /* There better be a current re_ptr */ + if (!re_ptr) return (3); + + /* Process 'G' for "Graphics" (one line only) */ + if (buf[0] == 'G') + { + char sym; + int tmp; + + /* Paranoia */ + if (!buf[2]) return (1); + if (!buf[3]) return (1); + if (!buf[4]) return (1); + + /* Extract the char */ + if (buf[2] != '*') sym = buf[2]; + else sym = MEGO_CHAR_ANY; + + /* Extract the attr */ + if (buf[4] != '*') tmp = color_char_to_attr(buf[4]); + else tmp = MEGO_CHAR_ANY; + + /* Paranoia */ + if (tmp < 0) return (1); + + /* Save the values */ + re_ptr->d_char = sym; + re_ptr->d_attr = tmp; + + /* Next... */ + continue; + } + + /* Process 'I' for "Info" (one line only) */ + if (buf[0] == 'I') + { + int spd, hp1, hp2, aaf, ac, slp; + char mspd, mhp1, mhp2, maaf, mac, mslp; + + /* Scan for the other values */ + if (12 != sscanf(buf + 2, "%c%d:%c%dd%c%d:%c%d:%c%d:%c%d", + &mspd, &spd, &mhp1, &hp1, &mhp2, &hp2, &maaf, &aaf, &mac, &ac, &mslp, &slp)) return (1); + + /* Save the values */ + re_ptr->speed = (spd << 2) + monster_ego_modify(mspd); + re_ptr->hdice = (hp1 << 2) + monster_ego_modify(mhp1); + re_ptr->hside = (hp2 << 2) + monster_ego_modify(mhp2); + re_ptr->aaf = (aaf << 2) + monster_ego_modify(maaf); + re_ptr->ac = (ac << 2) + monster_ego_modify(mac); + re_ptr->sleep = (slp << 2) + monster_ego_modify(mslp); + + /* Next... */ + continue; + } + + /* Process 'W' for "More Info" (one line only) */ + if (buf[0] == 'W') + { + int lev, rar, wt; + char mlev, mwt, mexp, pos; + long exp; + + /* Scan for the values */ + if (8 != sscanf(buf + 2, "%c%d:%d:%c%d:%c%ld:%c", + &mlev, &lev, &rar, &mwt, &wt, &mexp, &exp, &pos)) return (1); + + /* Save the values */ + re_ptr->level = (lev << 2) + monster_ego_modify(mlev); + re_ptr->rarity = rar; + re_ptr->weight = (wt << 2) + monster_ego_modify(mwt); + re_ptr->mexp = (exp << 2) + monster_ego_modify(mexp); + re_ptr->before = (pos == 'B') ? TRUE : FALSE; + + /* Next... */ + continue; + } + + /* Process 'B' for "Blows" (up to four lines) */ + if (buf[0] == 'B') + { + int n1, n2, dice, side; + char mdice, mside; + + /* Oops, no more slots */ + if (blow_num == 4) return (1); + + /* Analyze the first field */ + for (s = t = buf + 2; *t && (*t != ':'); t++) /* loop */; + + /* Terminate the field (if necessary) */ + if (*t == ':') *t++ = '\0'; + + /* Analyze the method */ + for (n1 = 0; r_info_blow_method[n1]; n1++) + { + if (streq(s, r_info_blow_method[n1])) break; + } + + /* Invalid method */ + if (!r_info_blow_method[n1]) return (1); + + /* Analyze the second field */ + for (s = t; *t && (*t != ':'); t++) /* loop */; + + /* Terminate the field (if necessary) */ + if (*t == ':') *t++ = '\0'; + + /* Analyze effect */ + for (n2 = 0; r_info_blow_effect[n2]; n2++) + { + if (streq(s, r_info_blow_effect[n2])) break; + } + + /* Invalid effect */ + if (!r_info_blow_effect[n2]) return (1); + + /* Save the method */ + re_ptr->blow[blow_num].method = n1; + + /* Save the effect */ + re_ptr->blow[blow_num].effect = n2; + + /* Extract the damage dice and sides */ + if (4 != sscanf(t, "%c%dd%c%d", + &mdice, &dice, &mside, &side)) return (1); + + re_ptr->blow[blow_num].d_dice = dice; + re_ptr->blow[blow_num].d_side = side; + re_ptr->blowm[blow_num][0] = monster_ego_modify(mdice); + re_ptr->blowm[blow_num][1] = monster_ego_modify(mside); + blow_num++; + + /* Next... */ + continue; + } + + /* Process 'F' for "Flags monster must have" (multiple lines) */ + if (buf[0] == 'F') + { + char r_char; + + /* Parse every entry */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* XXX XXX XXX Hack -- Read monster symbols */ + if (1 == sscanf(s, "R_CHAR_%c", &r_char)) + { + /* Limited to 5 races */ + if (r_char_number >= 5) continue; + + /* Extract a "frequency" */ + re_ptr->r_char[r_char_number++] = r_char; + + /* Start at next entry */ + s = t; + + /* Continue */ + continue; + } + + /* Parse this entry */ + if (0 != grab_one_ego_flag(re_ptr, s, TRUE)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'H' for "Flags monster must not have" (multiple lines) */ + if (buf[0] == 'H') + { + char r_char; + + /* Parse every entry */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* XXX XXX XXX Hack -- Read monster symbols */ + if (1 == sscanf(s, "R_CHAR_%c", &r_char)) + { + /* Limited to 5 races */ + if (nr_char_number >= 5) continue; + + /* Extract a "frequency" */ + re_ptr->nr_char[nr_char_number++] = r_char; + + /* Start at next entry */ + s = t; + + /* Continue */ + continue; + } + + /* Parse this entry */ + if (0 != grab_one_ego_flag(re_ptr, s, FALSE)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'M' for "Basic Monster Flags" (multiple lines) */ + if (buf[0] == 'M') + { + /* Parse every entry */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_basic_ego_flag(re_ptr, s, TRUE)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'O' for "Basic Monster -Flags" (multiple lines) */ + if (buf[0] == 'O') + { + /* Parse every entry */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* XXX XXX XXX Hack -- Read no flags */ + if (!strcmp(s, "MF_ALL")) + { + /* No flags */ + re_ptr->nflags1 = re_ptr->nflags2 = re_ptr->nflags3 = re_ptr->nflags7 = re_ptr->nflags8 = re_ptr->nflags9 = 0xFFFFFFFF; + + /* Start at next entry */ + s = t; + + /* Continue */ + continue; + } + + /* Parse this entry */ + if (0 != grab_one_basic_ego_flag(re_ptr, s, FALSE)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'S' for "Spell Flags" (multiple lines) */ + if (buf[0] == 'S') + { + /* Parse every entry */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while ((*t == ' ') || (*t == '|')) t++; + } + + /* XXX XXX XXX Hack -- Read spell frequency */ + if (1 == sscanf(s, "1_IN_%d", &i)) + { + /* Extract a "frequency" */ + re_ptr->freq_spell = re_ptr->freq_inate = 100 / i; + + /* Start at next entry */ + s = t; + + /* Continue */ + continue; + } + + /* Parse this entry */ + if (0 != grab_one_spell_ego_flag(re_ptr, s, TRUE)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'T' for "Spell -Flags" (multiple lines) */ + if (buf[0] == 'T') + { + /* Parse every entry */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while ((*t == ' ') || (*t == '|')) t++; + } + + /* XXX XXX XXX Hack -- Read no flags */ + if (!strcmp(s, "MF_ALL")) + { + /* No flags */ + re_ptr->nflags4 = re_ptr->nflags5 = re_ptr->nflags6 = 0xFFFFFFFF; + + /* Start at next entry */ + s = t; + + /* Continue */ + continue; + } + + /* Parse this entry */ + if (0 != grab_one_spell_ego_flag(re_ptr, s, FALSE)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Oops */ + return (6); + } + + + /* Complete the "name" and "text" sizes */ + ++re_head->name_size; + + /* No version yet */ + if (!okay) return (2); + + /* Success */ + return (0); +} + + +/* + * Grab one flag in an trap_type from a textual string + */ +static errr grab_one_trap_type_flag(trap_type *t_ptr, cptr what) +{ + s16b i; + + /* Check flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, t_info_flags[i])) + { + t_ptr->flags |= (1L << i); + return (0); + } + } + /* Oops */ + msg_format("Unknown trap_type flag '%s'.", what); + + /* Error */ + return (1); +} + + +/* + * Initialize the "tr_info" array, by parsing an ascii "template" file + */ +errr init_t_info_txt(FILE *fp, char *buf) +{ + int i; + + char *s, *t; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + trap_type *t_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Prepare the "fake" stuff */ + t_head->name_size = 0; + t_head->text_size = 0; + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if (buf[0] == 'N') + { + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i <= error_idx) return (4); + + /* Verify information */ + if (i >= t_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + t_ptr = &t_info[i]; + + /* Hack -- Verify space */ + if (t_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!t_ptr->name) t_ptr->name = ++t_head->name_size; + + /* Append chars to the name */ + strcpy(t_name + t_head->name_size, s); + + /* Advance the index */ + t_head->name_size += strlen(s); + + /* Next... */ + continue; + } + + /* There better be a current t_ptr */ + if (!t_ptr) return (3); + + + /* Process 'I' for "Information" */ + if (buf[0] == 'I') + { + int probability, another, p1valinc, difficulty; + int minlevel; + int dd, ds; + char color; + + /* Scan for the values */ + if (8 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%dd%d:%c", + &difficulty, &probability, &another, + &p1valinc, &minlevel, &dd, &ds, + &color)) return (1); + + t_ptr->difficulty = (byte)difficulty; + t_ptr->probability = (s16b)probability; + t_ptr->another = (s16b)another; + t_ptr->p1valinc = (s16b)p1valinc; + t_ptr->minlevel = (byte)minlevel; + t_ptr->dd = (s16b)dd; + t_ptr->ds = (s16b)ds; + t_ptr->color = color_char_to_attr(color); + + /* Next... */ + continue; + } + + + /* Process 'D' for "Description" */ + if (buf[0] == 'D') + { + /* Acquire the text */ + s = buf + 2; + + /* Hack -- Verify space */ + if (t_head->text_size + strlen(s) + 8 > fake_text_size) return (7); + + /* Advance and Save the text index */ + if (!t_ptr->text) t_ptr->text = ++t_head->text_size; + + /* Append chars to the name */ + strcpy(t_text + t_head->text_size, s); + + /* Advance the index */ + t_head->text_size += strlen(s); + + /* Next... */ + continue; + } + + + /* Hack -- Process 'F' for flags */ + if (buf[0] == 'F') + { + + t_ptr->flags = 0; + + /* Parse every entry textually */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_trap_type_flag(t_ptr, s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + + /* Oops */ + return (6); + } + + + /* Complete the "name" and "text" sizes */ + ++t_head->name_size; + ++t_head->text_size; + + + /* No version yet */ + if (!okay) return (2); + + + /* Success */ + return (0); +} + +/* + * Grab one flag for a dungeon type from a textual string + */ +errr grab_one_dungeon_flag(u32b *flags1, u32b *flags2, cptr what) +{ + int i; + + /* Scan flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, d_info_flags1[i])) + { + *flags1 |= (1L << i); + return (0); + } + } + + /* Scan flags2 */ + for (i = 0; i < 32; i++) + { + if (streq(what, d_info_flags2[i])) + { + *flags2 |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("Unknown dungeon type flag '%s'.", what); + + /* Failure */ + return (1); +} + +/* + * Grab one (basic) flag in a monster_race from a textual string + */ +static errr grab_one_basic_monster_flag(dungeon_info_type *d_ptr, cptr what, byte rule) +{ + int i; + + /* Scan flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags1[i])) + { + d_ptr->rules[rule].mflags1 |= (1L << i); + return (0); + } + } + + /* Scan flags2 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags2[i])) + { + d_ptr->rules[rule].mflags2 |= (1L << i); + return (0); + } + } + + /* Scan flags3 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags3[i])) + { + d_ptr->rules[rule].mflags3 |= (1L << i); + return (0); + } + } + + /* Scan flags7 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags7[i])) + { + d_ptr->rules[rule].mflags7 |= (1L << i); + return (0); + } + } + + /* Scan flags8 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags8[i])) + { + d_ptr->rules[rule].mflags8 |= (1L << i); + return (0); + } + } + + /* Scan flags9 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags9[i])) + { + d_ptr->rules[rule].mflags9 |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("Unknown monster flag '%s'.", what); + + /* Failure */ + return (1); +} + + +/* + * Grab one (spell) flag in a monster_race from a textual string + */ +static errr grab_one_spell_monster_flag(dungeon_info_type *d_ptr, cptr what, byte rule) +{ + int i; + + /* Scan flags4 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags4[i])) + { + d_ptr->rules[rule].mflags4 |= (1L << i); + return (0); + } + } + + /* Scan flags5 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags5[i])) + { + d_ptr->rules[rule].mflags5 |= (1L << i); + return (0); + } + } + + /* Scan flags6 */ + for (i = 0; i < 32; i++) + { + if (streq(what, r_info_flags6[i])) + { + d_ptr->rules[rule].mflags6 |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("Unknown monster flag '%s'.", what); + + /* Failure */ + return (1); +} + +/* + * Initialize the "d_info" array, by parsing an ascii "template" file + */ +errr init_d_info_txt(FILE *fp, char *buf) +{ + int i, j; + + s16b rule_num = 0; + + byte r_char_number = 0; + + char *s, *t; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + dungeon_info_type *d_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Start the "fake" stuff */ + d_head->name_size = 0; + d_head->text_size = 0; + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if (buf[0] == 'N') + { + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i < error_idx) return (4); + + /* Verify information */ + if (i >= d_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + d_ptr = &d_info[i]; + + /* Hack -- Verify space */ + if (d_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!d_ptr->name) d_ptr->name = ++d_head->name_size; + + /* Append chars to the name */ + strcpy(d_name + d_head->name_size, s); + + /* Advance the index */ + d_head->name_size += strlen(s); + + /* HACK -- Those ones HAVE to have a set default value */ + d_ptr->size_x = -1; + d_ptr->size_y = -1; + d_ptr->ix = -1; + d_ptr->iy = -1; + d_ptr->ox = -1; + d_ptr->oy = -1; + d_ptr->fill_method = 1; + rule_num = -1; + r_char_number = 0; + for (j = 0; j < 5; j++) + { + int k; + + d_ptr->rules[j].mode = DUNGEON_MODE_NONE; + d_ptr->rules[j].percent = 0; + + for (k = 0; k < 5; k++) d_ptr->rules[j].r_char[k] = 0; + } + + /* HACK -- Those ones HAVE to have a set default value */ + d_ptr->objs.treasure = OBJ_GENE_TREASURE; + d_ptr->objs.combat = OBJ_GENE_COMBAT; + d_ptr->objs.magic = OBJ_GENE_MAGIC; + d_ptr->objs.tools = OBJ_GENE_TOOL; + + /* The default generator */ + strcpy(d_ptr->generator, "dungeon"); + + /* Next... */ + continue; + } + + /* There better be a current d_ptr */ + if (!d_ptr) return (3); + + /* Process 'D' for "Description */ + if (buf[0] == 'D') + { + /* Acquire short name */ + d_ptr->short_name[0] = buf[2]; + d_ptr->short_name[1] = buf[3]; + d_ptr->short_name[2] = buf[4]; + + /* Acquire the text */ + s = buf + 6; + + /* Hack -- Verify space */ + if (d_head->text_size + strlen(s) + 8 > fake_text_size) return (7); + + /* Advance and Save the text index */ + if (!d_ptr->text) d_ptr->text = ++d_head->text_size; + + /* Append chars to the name */ + strcpy(d_text + d_head->text_size, s); + + /* Advance the index */ + d_head->text_size += strlen(s); + + /* Next... */ + continue; + } + + /* Process 'W' for "More Info" (one line only) */ + if (buf[0] == 'W') + { + int min_lev, max_lev; + int min_plev, next; + int min_alloc, max_chance; + + /* Scan for the values */ + if (6 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d", + &min_lev, &max_lev, &min_plev, &next, &min_alloc, &max_chance)) return (1); + + /* Save the values */ + d_ptr->mindepth = min_lev; + d_ptr->maxdepth = max_lev; + d_ptr->min_plev = min_plev; + d_ptr->next = next; + d_ptr->min_m_alloc_level = min_alloc; + d_ptr->max_m_alloc_chance = max_chance; + + /* Next... */ + continue; + } + + /* Process 'L' for "fLoor type" (one line only) */ + if (buf[0] == 'L') + { + int f1, f2, f3; + int p1, p2, p3; + int i; + + /* Scan for the values */ + if (6 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d", + &f1, &p1, &f2, &p2, &f3, &p3)) + { + /* Scan for the values - part ii*/ + if (3 != sscanf(buf + 2, "%d:%d:%d", &p1, &p2, + &p3)) return (1); + + /* Save the values */ + d_ptr->floor_percent1[1] = p1; + d_ptr->floor_percent2[1] = p2; + d_ptr->floor_percent3[1] = p3; + + continue; + } + + /* Save the values */ + d_ptr->floor1 = f1; + d_ptr->floor2 = f2; + d_ptr->floor3 = f3; + + for (i = 0; i < 2; i++) + { + d_ptr->floor_percent1[i] = p1; + d_ptr->floor_percent2[i] = p2; + d_ptr->floor_percent3[i] = p3; + } + + /* Next... */ + continue; + } + + /* Process 'O' for "Object type" (one line only) */ + if (buf[0] == 'O') + { + int treasure, combat, magic, tools; + + /* Scan for the values */ + if (4 != sscanf(buf + 2, "%d:%d:%d:%d", + &treasure, &combat, &magic, &tools)) return (1); + + /* Save the values */ + d_ptr->objs.treasure = treasure; + d_ptr->objs.combat = combat; + d_ptr->objs.magic = magic; + d_ptr->objs.tools = tools; + + /* Next... */ + continue; + } + + /* Process 'G' for "Generator" (one line only) */ + if (buf[0] == 'G') + { + strnfmt(d_ptr->generator, 30, "%s", buf + 2); + + /* Next... */ + continue; + } + + /* Process 'A' for "wAll type" (one line only) */ + if (buf[0] == 'A') + { + int w1, w2, w3, outer, inner; + int p1, p2, p3; + int i; + + /* Scan for the values */ + if (8 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d:%d:%d", + &w1, &p1, &w2, &p2, &w3, &p3, &outer, &inner)) + { + /* Scan for the values - part ii*/ + if (3 != sscanf(buf + 2, "%d:%d:%d", &p1, &p2, + &p3)) return (1); + + /* Save the values */ + d_ptr->fill_percent1[1] = p1; + d_ptr->fill_percent2[1] = p2; + d_ptr->fill_percent3[1] = p3; + continue; + } + + /* Save the values */ + d_ptr->fill_type1 = w1; + d_ptr->fill_type2 = w2; + d_ptr->fill_type3 = w3; + + for (i = 0; i < 2; i++) + { + d_ptr->fill_percent1[i] = p1; + d_ptr->fill_percent2[i] = p2; + d_ptr->fill_percent3[i] = p3; + } + + d_ptr->outer_wall = outer; + d_ptr->inner_wall = inner; + + /* Next... */ + continue; + } + + /* Process 'E' for "Effects" (up to four lines) -SC- */ + if (buf[0] == 'E') + { + int side, dice, freq, type; + cptr tmp; + + /* Find the next empty blow slot (if any) */ + for (i = 0; i < 4; i++) if ((!d_ptr->d_side[i]) && + (!d_ptr->d_dice[i])) break; + + /* Oops, no more slots */ + if (i == 4) return (1); + + /* Scan for the values */ + if (4 != sscanf(buf + 2, "%dd%d:%d:%d", + &dice, &side, &freq, &type)) + { + int j; + + if (3 != sscanf(buf + 2, "%dd%d:%d", + &dice, &side, &freq)) return (1); + + tmp = buf + 2; + for (j = 0; j < 2; j++) + { + tmp = strchr(tmp, ':'); + if (tmp == NULL) return (1); + tmp++; + } + + j = 0; + + while (d_info_dtypes[j].name != NULL) + if (strcmp(d_info_dtypes[j].name, tmp) == 0) + { + d_ptr->d_type[i] = d_info_dtypes[j].feat; + break; + } + else j++; + + if (d_info_dtypes[j].name == NULL) return (1); + } + else + d_ptr->d_type[i] = type; + + freq *= 10; + /* Save the values */ + d_ptr->d_side[i] = side; + d_ptr->d_dice[i] = dice; + d_ptr->d_frequency[i] = freq; + + /* Next... */ + continue; + } + + /* Process 'F' for "Dungeon Flags" (multiple lines) */ + if (buf[0] == 'F') + { + int artif = 0, monst = 0, obj = 0; + int ix = -1, iy = -1, ox = -1, oy = -1; + int fill_method; + + /* Parse every entry */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Read dungeon in/out coords */ + if (4 == sscanf(s, "WILD_%d_%d__%d_%d", &ix, &iy, &ox, &oy)) + { + d_ptr->ix = ix; + d_ptr->iy = iy; + d_ptr->ox = ox; + d_ptr->oy = oy; + + /* Start at next entry */ + s = t; + + /* Continue */ + continue; + } + + /* Read dungeon size */ + if (2 == sscanf(s, "SIZE_%d_%d", &ix, &iy)) + { + d_ptr->size_x = ix; + d_ptr->size_y = iy; + + /* Start at next entry */ + s = t; + + /* Continue */ + continue; + } + + /* Read dungeon fill method */ + if (1 == sscanf(s, "FILL_METHOD_%d", &fill_method)) + { + d_ptr->fill_method = fill_method; + + /* Start at next entry */ + s = t; + + /* Continue */ + continue; + } + + /* Read Final Object */ + if (1 == sscanf(s, "FINAL_OBJECT_%d", &obj)) + { + /* Extract a "Final Artifact" */ + d_ptr->final_object = obj; + + /* Start at next entry */ + s = t; + + /* Continue */ + continue; + } + + /* Read Final Artifact */ + if (1 == sscanf(s, "FINAL_ARTIFACT_%d", &artif )) + { + /* Extract a "Final Artifact" */ + d_ptr->final_artifact = artif ; + + /* Start at next entry */ + s = t; + + /* Continue */ + continue; + } + + /* Read Artifact Guardian */ + if (1 == sscanf(s, "FINAL_GUARDIAN_%d", &monst)) + { + /* Extract a "Artifact Guardian" */ + d_ptr->final_guardian = monst; + + /* Start at next entry */ + s = t; + + /* Continue */ + continue; + } + + /* Parse this entry */ + if (0 != grab_one_dungeon_flag(&(d_ptr->flags1), &(d_ptr->flags2), s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'R' for "monster generation Rule" (up to 5 lines) */ + if (buf[0] == 'R') + { + int percent, mode; + int z, y, lims[5]; + + /* Scan for the values */ + if (2 != sscanf(buf + 2, "%d:%d", + &percent, &mode)) return (1); + + /* Save the values */ + r_char_number = 0; + rule_num++; + + d_ptr->rules[rule_num].percent = percent; + d_ptr->rules[rule_num].mode = mode; + + /* Lets remap the flat percents */ + lims[0] = d_ptr->rules[0].percent; + for (y = 1; y <= rule_num; y++) + { + lims[y] = lims[y - 1] + d_ptr->rules[y].percent; + } + for (z = 0; z < 100; z++) + { + for (y = rule_num; y >= 0; y--) + { + if (z < lims[y]) d_ptr->rule_percents[z] = y; + } + } + + /* Next... */ + continue; + } + + /* Process 'M' for "Basic Flags" (multiple lines) */ + if (buf[0] == 'M') + { + byte r_char; + + /* Parse every entry */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Read monster symbols */ + if (1 == sscanf(s, "R_CHAR_%c", &r_char)) + { + /* Limited to 5 races */ + if (r_char_number >= 5) continue; + + /* Extract a "frequency" */ + d_ptr->rules[rule_num].r_char[r_char_number++] = r_char; + + /* Start at next entry */ + s = t; + + /* Continue */ + continue; + } + + /* Parse this entry */ + if (0 != grab_one_basic_monster_flag(d_ptr, s, rule_num)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'S' for "Spell Flags" (multiple lines) */ + if (buf[0] == 'S') + { + /* Parse every entry */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while ((*t == ' ') || (*t == '|')) t++; + } + + /* Parse this entry */ + if (0 != grab_one_spell_monster_flag(d_ptr, s, rule_num)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Oops */ + return (6); + } + + + /* Complete the "name" and "text" sizes */ + ++d_head->name_size; + ++d_head->text_size; + + /* No version yet */ + if (!okay) return (2); + + /* Success */ + return (0); +} + +/* + * Grab one race flag from a textual string + */ +static errr grab_one_race_flag(owner_type *ow_ptr, int state, cptr what) +{ + /* int i; + cptr s; */ + + /* Scan race flags */ + unknown_shut_up = TRUE; + if (!grab_one_race_allow_flag(ow_ptr->races[state], what)) + { + unknown_shut_up = FALSE; + return (0); + } + + /* Scan classes flags */ + if (!grab_one_class_flag(ow_ptr->classes[state], what)) + { + unknown_shut_up = FALSE; + return (0); + } + + /* Oops */ + unknown_shut_up = FALSE; + msg_format("Unknown race/class flag '%s'.", what); + + /* Failure */ + return (1); +} + +/* + * Grab one store flag from a textual string + */ +static errr grab_one_store_flag(store_info_type *st_ptr, cptr what) +{ + int i; + + /* Scan store flags */ + for (i = 0; i < 32; i++) + { + if (streq(what, st_info_flags1[i])) + { + st_ptr->flags1 |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("Unknown store flag '%s'.", what); + + /* Failure */ + return (1); +} + +/* + * Initialize the "st_info" array, by parsing an ascii "template" file + */ +errr init_st_info_txt(FILE *fp, char *buf) +{ + int i = 0, item_idx = 0; + + char *s, *t; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + store_info_type *st_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Start the "fake" stuff */ + st_head->name_size = 0; + st_head->text_size = 0; + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if (buf[0] == 'N') + { + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i < error_idx) return (4); + + /* Verify information */ + if (i >= st_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + st_ptr = &st_info[i]; + + /* Hack -- Verify space */ + if (st_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!st_ptr->name) st_ptr->name = ++st_head->name_size; + + /* Append chars to the name */ + strcpy(st_name + st_head->name_size, s); + + /* Advance the index */ + st_head->name_size += strlen(s); + + /* We are ready for a new set of objects */ + item_idx = 0; + + /* Next... */ + continue; + } + + /* There better be a current st_ptr */ + if (!st_ptr) return (3); + + /* Process 'I' for "Items" (multiple lines) */ + if (buf[0] == 'I') + { + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + st_ptr->table[item_idx][1] = atoi(buf + 2); + + /* Append chars to the name */ + st_ptr->table[item_idx++][0] = test_item_name(s); + + st_ptr->table_num = item_idx; + + /* Next... */ + continue; + } + + /* Process 'T' for "Tval/sval" */ + if (buf[0] == 'T') + { + int tv1, sv1, rar1; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d:%d:%d", + &rar1, &tv1, &sv1)) return (1); + + /* Get the index */ + st_ptr->table[item_idx][1] = rar1; + /* Hack -- 256 as a sval means all possible items */ + st_ptr->table[item_idx++][0] = (sv1 < 256) ? lookup_kind(tv1, sv1) : tv1 + 10000; + + st_ptr->table_num = item_idx; + + /* Next... */ + continue; + } + + /* Process 'G' for "Graphics" one line only) */ + if (buf[0] == 'G') + { + char c, a; + int attr; + + /* Scan for the values */ + if (2 != sscanf(buf + 2, "%c:%c", + &c, &a)) return (1); + + /* Extract the color */ + attr = color_char_to_attr(a); + + /* Paranoia */ + if (attr < 0) return (1); + + /* Save the values */ + st_ptr->d_char = c; + st_ptr->d_attr = attr; + + /* Next... */ + continue; + } + + /* Process 'A' for "Actions" (one line only) */ + if (buf[0] == 'A') + { + int a1, a2, a3, a4, a5, a6; + + /* Scan for the values */ + if (6 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d", + &a1, &a2, &a3, &a4, &a5, &a6)) return (1); + + /* Save the values */ + st_ptr->actions[0] = a1; + st_ptr->actions[1] = a2; + st_ptr->actions[2] = a3; + st_ptr->actions[3] = a4; + st_ptr->actions[4] = a5; + st_ptr->actions[5] = a6; + + /* Next... */ + continue; + } + + /* Process 'F' for "store Flags" (multiple lines) */ + if (buf[0] == 'F') + { + /* Parse every entry */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_store_flag(st_ptr, s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Process 'O' for "Owners" (one line only) */ + if (buf[0] == 'O') + { + int a1, a2, a3, a4; + + /* Scan for the values */ + if (4 != sscanf(buf + 2, "%d:%d:%d:%d", + &a1, &a2, &a3, &a4)) return (1); + + /* Save the values */ + st_ptr->owners[0] = a1; + st_ptr->owners[1] = a2; + st_ptr->owners[2] = a3; + st_ptr->owners[3] = a4; + + /* Next... */ + continue; + } + + /* Process 'W' for "Extra info" (one line only) */ + if (buf[0] == 'W') + { + int max_obj; + + /* Scan for the values */ + if (1 != sscanf(buf + 2, "%d", + &max_obj)) return (1); + + /* Save the values */ + if (max_obj > STORE_INVEN_MAX) max_obj = STORE_INVEN_MAX; + st_ptr->max_obj = max_obj; + + /* Next... */ + continue; + } + + /* Oops */ + return (6); + } + + + /* Complete the "name" and "text" sizes */ + ++st_head->name_size; + ++st_head->text_size; + + /* No version yet */ + if (!okay) return (2); + + /* Success */ + return (0); +} + +/* + * Initialize the "ba_info" array, by parsing an ascii "template" file + */ +errr init_ba_info_txt(FILE *fp, char *buf) +{ + int i = 0; + + char *s; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + store_action_type *ba_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Start the "fake" stuff */ + ba_head->name_size = 0; + ba_head->text_size = 0; + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if (buf[0] == 'N') + { + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i < error_idx) return (4); + + /* Verify information */ + if (i >= ba_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + ba_ptr = &ba_info[i]; + + /* Hack -- Verify space */ + if (ba_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!ba_ptr->name) ba_ptr->name = ++ba_head->name_size; + + /* Append chars to the name */ + strcpy(ba_name + ba_head->name_size, s); + + /* Advance the index */ + ba_head->name_size += strlen(s); + + /* Next... */ + continue; + } + + /* There better be a current ba_ptr */ + if (!ba_ptr) return (3); + + /* Process 'C' for "Costs" (one line only) */ + if (buf[0] == 'C') + { + int ch, cn, cl; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d:%d:%d", + &ch, &cn, &cl)) return (1); + + /* Save the values */ + ba_ptr->costs[STORE_HATED] = ch; + ba_ptr->costs[STORE_NORMAL] = cn; + ba_ptr->costs[STORE_LIKED] = cl; + + /* Next... */ + continue; + } + + /* Process 'I' for "Infos" (one line only) */ + if (buf[0] == 'I') + { + int act, act_res; + char letter, letter_aux = 0; + + /* Scan for the values */ + if (4 != sscanf(buf + 2, "%d:%d:%c:%c", &act, &act_res, &letter, &letter_aux)) + if (3 != sscanf(buf + 2, "%d:%d:%c", &act, &act_res, &letter)) + return (1); + + /* Save the values */ + ba_ptr->action = act; + ba_ptr->action_restr = act_res; + ba_ptr->letter = letter; + ba_ptr->letter_aux = letter_aux; + + /* Next... */ + continue; + } + + /* Oops */ + return (6); + } + + + /* Complete the "name" and "text" sizes */ + ++ba_head->name_size; + ++ba_head->text_size; + + /* No version yet */ + if (!okay) return (2); + + /* Success */ + return (0); +} + +/* + * Initialize the "ow_info" array, by parsing an ascii "template" file + */ +errr init_ow_info_txt(FILE *fp, char *buf) +{ + int i; + + char *s, *t; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + owner_type *ow_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Start the "fake" stuff */ + ow_head->name_size = 0; + ow_head->text_size = 0; + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if (buf[0] == 'N') + { + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i < error_idx) return (4); + + /* Verify information */ + if (i >= ow_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + ow_ptr = &ow_info[i]; + + /* Hack -- Verify space */ + if (ow_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!ow_ptr->name) ow_ptr->name = ++ow_head->name_size; + + /* Append chars to the name */ + strcpy(ow_name + ow_head->name_size, s); + + /* Advance the index */ + ow_head->name_size += strlen(s); + + /* Next... */ + continue; + } + + /* There better be a current ow_ptr */ + if (!ow_ptr) return (3); + + + /* Process 'C' for "Costs" (one line only) */ + if (buf[0] == 'C') + { + int ch, cn, cl; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d:%d:%d", + &ch, &cn, &cl)) return (1); + + /* Save the values */ + ow_ptr->costs[STORE_HATED] = ch; + ow_ptr->costs[STORE_NORMAL] = cn; + ow_ptr->costs[STORE_LIKED] = cl; + + /* Next... */ + continue; + } + + /* Process 'I' for "Info" (multiple lines line only) */ + if (buf[0] == 'I') + { + int cost, max_inf, min_inf, haggle, insult; + + /* Scan for the values */ + if (5 != sscanf(buf + 2, "%d:%d:%d:%d:%d", + &cost, &max_inf, &min_inf, &haggle, &insult)) return (1); + + /* Save the values */ + ow_ptr->max_cost = cost; + ow_ptr->max_inflate = max_inf; + ow_ptr->min_inflate = min_inf; + ow_ptr->haggle_per = haggle; + ow_ptr->insult_max = insult; + + /* Next... */ + continue; + } + + /* Process 'L' for "Liked races/classes" (multiple lines) */ + if (buf[0] == 'L') + { + /* Parse every entry */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_race_flag(ow_ptr, STORE_LIKED, s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + /* Process 'H' for "Hated races/classes" (multiple lines) */ + if (buf[0] == 'H') + { + /* Parse every entry */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_race_flag(ow_ptr, STORE_HATED, s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Oops */ + return (6); + } + + + /* Complete the "name" and "text" sizes */ + ++ow_head->name_size; + ++ow_head->text_size; + + /* No version yet */ + if (!okay) return (2); + + /* Success */ + return (0); +} + +/* + * Grab one flag for a dungeon type from a textual string + */ +static errr grab_one_wf_info_flag(wilderness_type_info *wf_ptr, cptr what) +{ + int i; + + /* Scan flags1 */ + for (i = 0; i < 32; i++) + { + if (streq(what, wf_info_flags1[i])) + { + wf_ptr->flags1 |= (1L << i); + return (0); + } + } + + /* Oops */ + msg_format("Unknown monster flag '%s'.", what); + + /* Failure */ + return (1); +} + +/* + * Initialize the "wf_info" array, by parsing an ascii "template" file + */ +errr init_wf_info_txt(FILE *fp, char *buf) +{ + int i; + + char *s, *t; + + /* Not ready yet */ + bool_ okay = FALSE; + + /* Current entry */ + wilderness_type_info *wf_ptr = NULL; + + + /* Just before the first record */ + error_idx = -1; + + /* Just before the first line */ + error_line = -1; + + + /* Start the "fake" stuff */ + wf_head->name_size = 0; + wf_head->text_size = 0; + + /* Parse */ + fp_stack_init(fp); + while (0 == my_fgets_dostack(buf, 1024)) + { + /* Advance the line number */ + error_line++; + + /* Skip comments and blank lines */ + if (!buf[0] || (buf[0] == '#')) continue; + + /* Verify correct "colon" format */ + if (buf[1] != ':') return (1); + + + /* Hack -- Process 'V' for "Version" */ + if (buf[0] == 'V') + { + int v1, v2, v3; + + /* Scan for the values */ + if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2); + + /* Okay to proceed */ + okay = TRUE; + + /* Continue */ + continue; + } + + /* No version yet */ + if (!okay) return (2); + + /* Included file */ + if (buf[0] == '<') + { + fp_stack_push(buf + 2); + continue; + } + + /* Process 'N' for "New/Number/Name" */ + if (buf[0] == 'N') + { + /* Find the colon before the name */ + s = strchr(buf + 2, ':'); + + /* Verify that colon */ + if (!s) return (1); + + /* Nuke the colon, advance to the name */ + *s++ = '\0'; + + /* Paranoia -- require a name */ + if (!*s) return (1); + + /* Get the index */ + i = atoi(buf + 2); + + /* Verify information */ + if (i < error_idx) return (4); + + /* Verify information */ + if (i >= wf_head->info_num) return (2); + + /* Save the index */ + error_idx = i; + + /* Point at the "info" */ + wf_ptr = &wf_info[i]; + + /* Hack -- Verify space */ + if (wf_head->name_size + strlen(s) + 8 > fake_name_size) return (7); + + /* Advance and Save the name index */ + if (!wf_ptr->name) wf_ptr->name = ++wf_head->name_size; + + /* Append chars to the name */ + strcpy(wf_name + wf_head->name_size, s); + + /* Advance the index */ + wf_head->name_size += strlen(s); + + /* Next... */ + continue; + } + + /* There better be a current wf_ptr */ + if (!wf_ptr) return (3); + + /* Process 'D' for "Description */ + if (buf[0] == 'D') + { + /* Acquire the text */ + s = buf + 2; + + /* Hack -- Verify space */ + if (wf_head->text_size + strlen(s) + 8 > fake_text_size) return (7); + + /* Advance and Save the text index */ + if (!wf_ptr->text) wf_ptr->text = ++wf_head->text_size; + + /* Append chars to the name */ + strcpy(wf_text + wf_head->text_size, s); + + /* Advance the index */ + wf_head->text_size += strlen(s); + + /* Next... */ + continue; + } + + /* Process 'W' for "More Info" (one line only) */ + if (buf[0] == 'W') + { + int entrance, level; + int road, feat, ter_idx; + char car; + + /* Scan for the values */ + if (6 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%c", + &level, &entrance, &road, &feat, &ter_idx, &car)) return (1); + + /* Save the values */ + wf_ptr->level = level; + wf_ptr->entrance = entrance; + wf_ptr->road = road; + wf_ptr->feat = feat; + wf_ptr->terrain_idx = ter_idx; + + /* To acces it easily from the map structure */ + wildc2i[(int)car] = error_idx; + + /* Next... */ + continue; + } + + /* Process 'X' for "More Info" (one line only) */ + if (buf[0] == 'X') + { + int terrain[MAX_WILD_TERRAIN], i; + + /* Scan for the values */ + if (MAX_WILD_TERRAIN != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &terrain[0], &terrain[1], &terrain[2], + &terrain[3], &terrain[4], &terrain[5], + &terrain[6], &terrain[7], &terrain[8], + &terrain[9], &terrain[10], &terrain[11], + &terrain[12], &terrain[13], &terrain[14], + &terrain[15], &terrain[16], &terrain[17])) return (1); + + /* Save the values */ + for (i = 0; i < MAX_WILD_TERRAIN; i++) + { + wf_ptr->terrain[i] = terrain[i]; + } + + /* Next... */ + continue; + } + + /* Process 'F' for "Wilderness feature Flags" (multiple lines) */ + if (buf[0] == 'F') + { + /* Parse every entry */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_wf_info_flag(wf_ptr, s)) return (5); + + /* Start the next entry */ + s = t; + } + + /* Next... */ + continue; + } + + /* Oops */ + return (6); + } + + + /* Complete the "name" and "text" sizes */ + ++wf_head->name_size; + ++wf_head->text_size; + + /* No version yet */ + if (!okay) return (2); + + /* Success */ + return (0); +} + + +/* Random dungeon grid effects */ +#define RANDOM_NONE 0x00 +#define RANDOM_FEATURE 0x01 +#define RANDOM_MONSTER 0x02 +#define RANDOM_OBJECT 0x04 +#define RANDOM_EGO 0x08 +#define RANDOM_ARTIFACT 0x10 +#define RANDOM_TRAP 0x20 + + +typedef struct dungeon_grid dungeon_grid; + +struct dungeon_grid +{ + int feature; /* Terrain feature */ + int monster; /* Monster */ + int object; /* Object */ + int ego; /* Ego-Item */ + int artifact; /* Artifact */ + int trap; /* Trap */ + int cave_info; /* Flags for CAVE_MARK, CAVE_GLOW, CAVE_ICKY, CAVE_ROOM */ + int special; /* Reserved for special terrain info */ + int random; /* Number of the random effect */ + int bx, by; /* For between gates */ + int mimic; /* Mimiced features */ + s32b mflag; /* monster's mflag */ + bool_ ok; + bool_ defined; +}; +static bool_ meta_sleep = TRUE; + +static dungeon_grid letter[255]; + +/* + * Parse a sub-file of the "extra info" + */ +static errr process_dungeon_file_aux(char *buf, int *yval, int *xval, int xvalstart, int ymax, int xmax, bool_ full) +{ + int i; + + char *zz[33]; + + + /* Skip "empty" lines */ + if (!buf[0]) return (0); + + /* Skip "blank" lines */ + if (isspace(buf[0])) return (0); + + /* Skip comments */ + if (buf[0] == '#') return (0); + + /* Require "?:*" format */ + if (buf[1] != ':') return (1); + + + /* Process "%:<fname>" */ + if (buf[0] == '%') + { + /* Attempt to Process the given file */ + return (process_dungeon_file(buf + 2, yval, xval, ymax, xmax, FALSE, full)); + } + + /* Process "N:<sleep>" */ + if (buf[0] == 'N') + { + int num; + + if ((num = tokenize(buf + 2, 1, zz, ':', '/')) > 0) + { + meta_sleep = atoi(zz[0]); + } + + return (0); + } + + /* Process "F:<letter>:<terrain>:<cave_info>:<monster>:<object>:<ego>:<artifact>:<trap>:<special>:<mimic>:<mflag>" -- info for dungeon grid */ + if (buf[0] == 'F') + { + int num; + + if ((num = tokenize(buf + 2, 11, zz, ':', '/')) > 1) + { + int index = zz[0][0]; + + /* Reset the feature */ + letter[index].feature = 0; + letter[index].monster = 0; + letter[index].object = 0; + letter[index].ego = 0; + letter[index].artifact = 0; + letter[index].trap = 0; + letter[index].cave_info = 0; + letter[index].special = 0; + letter[index].random = 0; + letter[index].mimic = 0; + letter[index].mflag = 0; + letter[index].ok = TRUE; + letter[index].defined = TRUE; + + if (num > 1) + { + if (zz[1][0] == '*') + { + letter[index].random |= RANDOM_FEATURE; + if (zz[1][1]) + { + zz[1]++; + letter[index].feature = atoi(zz[1]); + } + } + else + { + letter[index].feature = atoi(zz[1]); + } + } + + if (num > 2) + letter[index].cave_info = atoi(zz[2]); + + /* Monster */ + if (num > 3) + { + if (zz[3][0] == '*') + { + letter[index].random |= RANDOM_MONSTER; + if (zz[3][1]) + { + zz[3]++; + letter[index].monster = atoi(zz[3]); + } + } + else + { + letter[index].monster = atoi(zz[3]); + } + } + + /* Object */ + if (num > 4) + { + if (zz[4][0] == '*') + { + letter[index].random |= RANDOM_OBJECT; + + if (zz[4][1]) + { + zz[4]++; + letter[index].object = atoi(zz[4]); + } + } + else + { + letter[index].object = atoi(zz[4]); + } + } + + /* Ego-Item */ + if (num > 5) + { + if (zz[5][0] == '*') + { + letter[index].random |= RANDOM_EGO; + + if (zz[5][1]) + { + zz[5]++; + letter[index].ego = atoi(zz[5]); + } + } + else + { + letter[index].ego = atoi(zz[5]); + } + } + + /* Artifact */ + if (num > 6) + { + if (zz[6][0] == '*') + { + letter[index].random |= RANDOM_ARTIFACT; + + if (zz[6][1]) + { + zz[6]++; + letter[index].artifact = atoi(zz[6]); + } + } + else + { + letter[index].artifact = atoi(zz[6]); + } + } + + if (num > 7) + { + if (zz[7][0] == '*') + { + letter[index].random |= RANDOM_TRAP; + + if (zz[7][1]) + { + zz[7]++; + letter[index].trap = atoi(zz[7]); + } + } + else + letter[index].trap = atoi(zz[7]); + } + + if (num > 8) + { + /* Quests can be defined by name only */ + if (zz[8][0] == '"') + { + int i; + + /* Hunt & shoot the ending " */ + i = strlen(zz[8]) - 1; + if (zz[8][i] == '"') zz[8][i] = '\0'; + letter[index].special = 0; + for (i = 0; i < max_q_idx; i++) + { + if (!strcmp(&zz[8][1], quest[i].name)) + { + letter[index].special = i; + break; + } + } + } + else + letter[index].special = atoi(zz[8]); + } + + if (num > 9) + { + letter[index].mimic = atoi(zz[9]); + } + + if (num > 10) + { + letter[index].mflag = atoi(zz[10]); + } + + return (0); + } + } + + /* Process "f:flags" -- level flags */ + else if (buf[0] == 'f') + { + char *s, *t; + + /* Parse every entry textually */ + for (s = buf + 2; *s; ) + { + /* Find the end of this entry */ + for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */; + + /* Nuke and skip any dividers */ + if (*t) + { + *t++ = '\0'; + while (*t == ' ' || *t == '|') t++; + } + + /* Parse this entry */ + if (0 != grab_one_dungeon_flag(&dungeon_flags1, &dungeon_flags2, s)) return 1; + + /* Start the next entry */ + s = t; + } + + return 0; + } + + /* Process "D:<dungeon>" -- info for the cave grids */ + else if (buf[0] == 'D') + { + int x, m_idx = 0; + + object_type object_type_body; + + /* Acquire the text */ + char *s = buf + 2; + + /* Length of the text */ + int len = strlen(s); + + int y = *yval; + *xval = xvalstart; + for (x = *xval, i = 0; ((x < xmax) && (i < len)); x++, s++, i++) + { + /* Access the grid */ + cave_type *c_ptr = &cave[y][x]; + + int idx = s[0]; + + int object_index = letter[idx].object; + int monster_index = letter[idx].monster; + int random = letter[idx].random; + int artifact_index = letter[idx].artifact; + + if (!letter[idx].ok) msg_format("Warning '%c' not defined but used.", idx); + + if (init_flags & INIT_GET_SIZE) continue; + + /* use the plasma generator wilderness */ + if (((!dun_level) || (!letter[idx].defined)) && (idx == ' ')) continue; + + /* Clear some info */ + c_ptr->info = 0; + + /* Lay down a floor */ + c_ptr->mimic = letter[idx].mimic; + cave_set_feat(y, x, letter[idx].feature); + + /* Cave info */ + c_ptr->info |= letter[idx].cave_info; + + /* Create a monster */ + if (random & RANDOM_MONSTER) + { + int level = monster_level; + + monster_level = quest[p_ptr->inside_quest].level + monster_index; + + m_idx = place_monster(y, x, meta_sleep, FALSE); + + monster_level = level; + } + else if (monster_index) + { + /* Place it */ + m_allow_special[monster_index] = TRUE; + m_idx = place_monster_aux(y, x, monster_index, meta_sleep, FALSE, MSTATUS_ENEMY); + m_allow_special[monster_index] = FALSE; + } + + /* Set the mflag of the monster */ + if (m_idx) m_list[m_idx].mflag |= letter[idx].mflag; + + /* Object (and possible trap) */ + if ((random & RANDOM_OBJECT) && (random & RANDOM_TRAP)) + { + int level = object_level; + + object_level = quest[p_ptr->inside_quest].level; + + /* + * Random trap and random treasure defined + * 25% chance for trap and 75% chance for object + */ + if (rand_int(100) < 75) + { + place_object(y, x, FALSE, FALSE, OBJ_FOUND_SPECIAL); + } + else + { + place_trap(y, x); + } + + object_level = level; + } + else if (random & RANDOM_OBJECT) + { + /* Create an out of deep object */ + if (object_index) + { + int level = object_level; + + object_level = quest[p_ptr->inside_quest].level + object_index; + if (rand_int(100) < 75) + place_object(y, x, FALSE, FALSE, OBJ_FOUND_SPECIAL); + else if (rand_int(100) < 80) + place_object(y, x, TRUE, FALSE, OBJ_FOUND_SPECIAL); + else + place_object(y, x, TRUE, TRUE, OBJ_FOUND_SPECIAL); + + object_level = level; + } + else if (rand_int(100) < 75) + { + place_object(y, x, FALSE, FALSE, OBJ_FOUND_SPECIAL); + } + else if (rand_int(100) < 80) + { + place_object(y, x, TRUE, FALSE, OBJ_FOUND_SPECIAL); + } + else + { + place_object(y, x, TRUE, TRUE, OBJ_FOUND_SPECIAL); + } + } + /* Random trap */ + else if (random & RANDOM_TRAP) + { + place_trap(y, x); + } + else if (object_index) + { + /* Get local object */ + object_type *o_ptr = &object_type_body; + + k_allow_special[object_index] = TRUE; + + /* Create the item */ + object_prep(o_ptr, object_index); + + /* Apply magic (no messages, no artifacts) */ + apply_magic(o_ptr, dun_level, FALSE, TRUE, FALSE); + + o_ptr->found = OBJ_FOUND_SPECIAL; + + k_allow_special[object_index] = FALSE; + + drop_near(o_ptr, -1, y, x); + } + + /* Artifact */ + if (artifact_index) + { + int I_kind = 0; + + artifact_type *a_ptr = &a_info[artifact_index]; + + object_type forge; + + /* Get local object */ + object_type *q_ptr = &forge; + + a_allow_special[artifact_index] = TRUE; + + /* Wipe the object */ + object_wipe(q_ptr); + + /* Acquire the "kind" index */ + I_kind = lookup_kind(a_ptr->tval, a_ptr->sval); + + /* Create the artifact */ + object_prep(q_ptr, I_kind); + + /* Save the name */ + q_ptr->name1 = artifact_index; + + /* Extract the fields */ + q_ptr->pval = a_ptr->pval; + q_ptr->ac = a_ptr->ac; + q_ptr->dd = a_ptr->dd; + q_ptr->ds = a_ptr->ds; + q_ptr->to_a = a_ptr->to_a; + q_ptr->to_h = a_ptr->to_h; + q_ptr->to_d = a_ptr->to_d; + q_ptr->weight = a_ptr->weight; + q_ptr->found = OBJ_FOUND_SPECIAL; + + random_artifact_resistance(q_ptr); + + a_info[artifact_index].cur_num = 1; + + a_allow_special[artifact_index] = FALSE; + + /* It's amazing that this "creating objects anywhere" + junk ever worked. + Let's just HACK around one observed bug: Shadow Cloak + of Luthien [Globe of Light] */ + { + u32b f1, f2, f3, f4, f5, esp; + object_flags(q_ptr, &f1, &f2, &f3, &f4, &f5, &esp); + if (f5 & TR5_SPELL_CONTAIN) + q_ptr->pval2 = -1; + } + + /* Drop the artifact */ + drop_near(q_ptr, -1, y, x); + + } + + /* Terrain special */ + if (letter[idx].special == -1) + { + if (!letter[idx].bx) + { + letter[idx].bx = x; + letter[idx].by = y; + } + else + { + c_ptr->special = (letter[idx].by << 8) + letter[idx].bx; + cave[letter[idx].by][letter[idx].bx].special = (y << 8) + x; + } + } + else + { + c_ptr->special = letter[idx].special; + } + } + if (full && (*xval < x)) *xval = x; + (*yval)++; + + return (0); + } + + /* Process "W:<command>: ..." -- info for the wilderness */ + else if (buf[0] == 'W') + { + /* Process "W:D:<layout> */ + /* Layout of the wilderness */ + if (buf[2] == 'D') + { + int x; + char i; + + /* Acquire the text */ + char *s = buf + 4; + + int y = *yval; + + for (x = 0; x < max_wild_x; x++) + { + if (1 != sscanf(s + x, "%c", &i)) return (1); + wild_map[y][x].feat = wildc2i[(int)i]; + + /* + * If this is a town/dungeon entrance, note + * its coordinates. (Have to check for + * duplicate Morias...) + */ + if (wf_info[wildc2i[(int)i]].entrance && + wf_info[wildc2i[(int)i]].wild_x == 0) + { + wf_info[wildc2i[(int)i]].wild_x = x; + wf_info[wildc2i[(int)i]].wild_y = y; + } + } + + (*yval)++; + + return (0); + } + /* Process "M:<plus>:<line>" -- move line lines */ + else if (buf[2] == 'M') + { + if (tokenize(buf + 4, 2, zz, ':', '/') == 2) + { + if (atoi(zz[0])) + { + (*yval) += atoi(zz[1]); + } + else + { + (*yval) -= atoi(zz[1]); + } + } + else + { + return (1); + } + return (0); + } + /* Process "W:P:<x>:<y> - starting position in the wilderness */ + else if (buf[2] == 'P') + { + if ((p_ptr->wilderness_x == 0) && + (p_ptr->wilderness_y == 0)) + { + if (tokenize(buf + 4, 2, zz, ':', '/') == 2) + { + p_ptr->wilderness_x = atoi(zz[0]); + p_ptr->wilderness_y = atoi(zz[1]); + } + else + { + return (1); + } + } + + return (0); + } + /* Process "W:E:<dungeon>:<y>:<x> - entrance to the dungeon <dungeon> */ + else if (buf[2] == 'E') + { + if (tokenize(buf + 4, 3, zz, ':', '/') == 3) + { + wild_map[atoi(zz[1])][atoi(zz[2])].entrance = 1000 + atoi(zz[0]); + } + else + { + return (1); + } + + return (0); + } + } + + /* Process "P:<y>:<x>" -- player position */ + else if (buf[0] == 'P') + { + if (init_flags & INIT_CREATE_DUNGEON) + { + if (tokenize(buf + 2, 2, zz, ':', '/') == 2) + { + /* Place player in a quest level */ + if (p_ptr->inside_quest || (init_flags & INIT_POSITION)) + { + p_ptr->py = atoi(zz[0]); + p_ptr->px = atoi(zz[1]); + } + /* Place player in the town */ + else if ((p_ptr->oldpx == 0) && (p_ptr->oldpy == 0)) + { + p_ptr->oldpy = atoi(zz[0]); + p_ptr->oldpx = atoi(zz[1]); + } + } + } + + return (0); + } + + /* Process "M:<type>:<maximum>" -- set maximum values */ + else if (buf[0] == 'M') + { + if (tokenize(buf + 2, 3, zz, ':', '/') >= 2) + { + /* Maximum towns */ + if (zz[0][0] == 'T') + { + max_towns = atoi(zz[1]); + } + + /* Maximum real towns */ + if (zz[0][0] == 't') + { + max_real_towns = atoi(zz[1]); + } + + /* Maximum r_idx */ + else if (zz[0][0] == 'R') + { + max_r_idx = atoi(zz[1]); + } + + /* Maximum re_idx */ + else if (zz[0][0] == 'r') + { + max_re_idx = atoi(zz[1]); + } + + /* Maximum s_idx */ + else if (zz[0][0] == 'k') + { + max_s_idx = atoi(zz[1]); + if (max_s_idx > MAX_SKILLS) return (1); + } + + /* Maximum ab_idx */ + else if (zz[0][0] == 'b') + { + max_ab_idx = atoi(zz[1]); + } + + /* Maximum k_idx */ + else if (zz[0][0] == 'K') + { + max_k_idx = atoi(zz[1]); + } + + /* Maximum v_idx */ + else if (zz[0][0] == 'V') + { + max_v_idx = atoi(zz[1]); + } + + /* Maximum f_idx */ + else if (zz[0][0] == 'F') + { + max_f_idx = atoi(zz[1]); + } + + /* Maximum a_idx */ + else if (zz[0][0] == 'A') + { + max_a_idx = atoi(zz[1]); + } + + /* Maximum al_idx */ + else if (zz[0][0] == 'a') + { + max_al_idx = atoi(zz[1]); + } + + /* Maximum e_idx */ + else if (zz[0][0] == 'E') + { + max_e_idx = atoi(zz[1]); + } + + /* Maximum ra_idx */ + else if (zz[0][0] == 'Z') + { + max_ra_idx = atoi(zz[1]); + } + + /* Maximum o_idx */ + else if (zz[0][0] == 'O') + { + max_o_idx = atoi(zz[1]); + } + + /* Maximum player types */ + else if (zz[0][0] == 'P') + { + if (zz[1][0] == 'R') + { + max_rp_idx = atoi(zz[2]); + } + else if (zz[1][0] == 'S') + { + max_rmp_idx = atoi(zz[2]); + } + else if (zz[1][0] == 'C') + { + max_c_idx = atoi(zz[2]); + } + else if (zz[1][0] == 'M') + { + max_mc_idx = atoi(zz[2]); + } + else if (zz[1][0] == 'H') + { + max_bg_idx = atoi(zz[2]); + } + } + + /* Maximum m_idx */ + else if (zz[0][0] == 'M') + { + max_m_idx = atoi(zz[1]); + } + + /* Maximum tr_idx */ + else if (zz[0][0] == 'U') + { + max_t_idx = atoi(zz[1]); + } + + /* Maximum wf_idx */ + else if (zz[0][0] == 'W') + { + max_wf_idx = atoi(zz[1]); + } + + /* Maximum ba_idx */ + else if (zz[0][0] == 'B') + { + max_ba_idx = atoi(zz[1]); + } + + /* Maximum st_idx */ + else if (zz[0][0] == 'S') + { + max_st_idx = atoi(zz[1]); + } + + /* Maximum set_idx */ + else if (zz[0][0] == 's') + { + max_set_idx = atoi(zz[1]); + } + + /* Maximum ow_idx */ + else if (zz[0][0] == 'N') + { + max_ow_idx = atoi(zz[1]); + } + + /* Maximum wilderness x size */ + else if (zz[0][0] == 'X') + { + max_wild_x = atoi(zz[1]); + } + + /* Maximum wilderness y size */ + else if (zz[0][0] == 'Y') + { + max_wild_y = atoi(zz[1]); + } + + /* Maximum d_idx */ + else if (zz[0][0] == 'D') + { + max_d_idx = atoi(zz[1]); + } + + return (0); + } + } + + /* Failure */ + return (1); +} + + + + +/* + * Helper function for "process_dungeon_file()" + */ +static cptr process_dungeon_file_expr(char **sp, char *fp) +{ + cptr v; + + char *b; + char *s; + + char b1 = '['; + char b2 = ']'; + + char f = ' '; + + /* Initial */ + s = (*sp); + + /* Skip spaces */ + while (isspace(*s)) s++; + + /* Save start */ + b = s; + + /* Default */ + v = "?o?o?"; + + /* Analyze */ + if (*s == b1) + { + const char *p; + const char *t; + + /* Skip b1 */ + s++; + + /* First */ + t = process_dungeon_file_expr(&s, &f); + + /* Oops */ + if (!*t) + { + /* Nothing */ + } + + /* Function: IOR */ + else if (streq(t, "IOR")) + { + v = "0"; + while (*s && (f != b2)) + { + t = process_dungeon_file_expr(&s, &f); + if (*t && !streq(t, "0")) v = "1"; + } + } + + /* Function: AND */ + else if (streq(t, "AND")) + { + v = "1"; + while (*s && (f != b2)) + { + t = process_dungeon_file_expr(&s, &f); + if (*t && streq(t, "0")) v = "0"; + } + } + + /* Function: NOT */ + else if (streq(t, "NOT")) + { + v = "1"; + while (*s && (f != b2)) + { + t = process_dungeon_file_expr(&s, &f); + if (*t && streq(t, "1")) v = "0"; + } + } + + /* Function: EQU */ + else if (streq(t, "EQU")) + { + v = "1"; + if (*s && (f != b2)) + { + t = process_dungeon_file_expr(&s, &f); + } + while (*s && (f != b2)) + { + p = t; + t = process_dungeon_file_expr(&s, &f); + if (*t && !streq(p, t)) v = "0"; + } + } + + /* Function: LEQ */ + else if (streq(t, "LEQ")) + { + v = "1"; + if (*s && (f != b2)) + { + t = process_dungeon_file_expr(&s, &f); + } + while (*s && (f != b2)) + { + p = t; + t = process_dungeon_file_expr(&s, &f); + if (*t && (strcmp(p, t) > 0)) v = "0"; + } + } + + /* Function: GEQ */ + else if (streq(t, "GEQ")) + { + v = "1"; + if (*s && (f != b2)) + { + t = process_dungeon_file_expr(&s, &f); + } + while (*s && (f != b2)) + { + p = t; + t = process_dungeon_file_expr(&s, &f); + if (*t && (strcmp(p, t) < 0)) v = "0"; + } + } + + /* Oops */ + else + { + while (*s && (f != b2)) + { + t = process_dungeon_file_expr(&s, &f); + } + } + + /* Verify ending */ + if (f != b2) v = "?x?x?"; + + /* Extract final and Terminate */ + if ((f = *s) != '\0') * s++ = '\0'; + } + + /* Other */ + else + { + bool_ text_mode = FALSE; + + /* Accept all printables except spaces and brackets */ + while (isprint(*s)) + { + if (*s == '"') text_mode = !text_mode; + if (!text_mode) + { + if (strchr(" []", *s)) + break; + } + else + { + if (strchr("[]", *s)) + break; + } + + ++s; + } + + /* Extract final and Terminate */ + if ((f = *s) != '\0') * s++ = '\0'; + + /* Variable */ + if (*b == '$') + { + /* System */ + if (streq(b + 1, "SYS")) + { + v = ANGBAND_SYS; + } + + /* Graphics */ + else if (streq(b + 1, "GRAF")) + { + v = ANGBAND_GRAF; + } + + /* Race */ + else if (streq(b + 1, "RACE")) + { + v = rp_ptr->title + rp_name; + } + + /* Race Mod */ + else if (streq(b + 1, "RACEMOD")) + { + v = rmp_ptr->title + rmp_name; + } + + /* Class */ + else if (streq(b + 1, "CLASS")) + { + v = cp_ptr->title + c_name; + } + + /* Player */ + else if (streq(b + 1, "PLAYER")) + { + v = player_base; + } + + /* Town */ + else if (streq(b + 1, "TOWN")) + { + strnfmt(pref_tmp_value, 8, "%d", p_ptr->town_num); + v = pref_tmp_value; + } + + /* Town destroyed */ + else if (prefix(b + 1, "TOWN_DESTROY")) + { + strnfmt(pref_tmp_value, 8, "%d", town_info[atoi(b + 13)].destroyed); + v = pref_tmp_value; + } + + /* Current quest number */ + else if (streq(b + 1, "QUEST_NUMBER")) + { + strnfmt(pref_tmp_value, 8, "%d", p_ptr->inside_quest); + v = pref_tmp_value; + } + + /* Number of last quest */ + else if (streq(b + 1, "LEAVING_QUEST")) + { + strnfmt(pref_tmp_value, 8, "%d", leaving_quest); + v = pref_tmp_value; + } + + /* DAYTIME status */ + else if (prefix(b + 1, "DAYTIME")) + { + if ((bst(HOUR, turn) >= 6) && (bst(HOUR, turn) < 18)) + v = "1"; + else + v = "0"; + } + + /* Quest status */ + else if (prefix(b + 1, "QUEST")) + { + /* "QUEST" uses a special parameter to determine the number of the quest */ + if (*(b + 6) != '"') + strnfmt(pref_tmp_value, 8, "%d", quest[atoi(b + 6)].status); + else + { + char c[80]; + int i; + + /* Copy it to temp array, so that we can modify it safely */ + strcpy(c, b + 7); + + /* Hunt & shoot the ending " */ + for (i = 0; (c[i] != '"') && (c[i] != '\0'); i++); + if (c[i] == '"') c[i] = '\0'; + strcpy(pref_tmp_value, "-1"); + for (i = 0; i < max_q_idx; i++) + { + if (streq(c, quest[i].name)) + { + strnfmt(pref_tmp_value, 8, "%d", quest[i].status); + break; + } + } + } + v = pref_tmp_value; + } + + /* Variant name */ + else if (streq(b + 1, "VARIANT")) + { + v = "ToME"; + } + + /* Wilderness */ + else if (streq(b + 1, "WILDERNESS")) + { + v = "NORMAL"; + } + } + + /* Constant */ + else + { + v = b; + } + } + + /* Save */ + (*fp) = f; + + /* Save */ + (*sp) = s; + + /* Result */ + return (v); +} + + +errr process_dungeon_file(cptr name, int *yval, int *xval, int ymax, int xmax, bool_ init, bool_ full) +{ + FILE *fp = 0; + + char buf[1024]; + + int num = -1, i; + + errr err = 0; + + bool_ bypass = FALSE; + + /* Save the start since it ought to be modified */ + int xmin = *xval; + + if (init) + { + meta_sleep = TRUE; + for (i = 0; i < 255; i++) + { + letter[i].defined = FALSE; + if (i == ' ') letter[i].ok = TRUE; + else letter[i].ok = FALSE; + letter[i].bx = 0; + letter[i].by = 0; + } + } + + /* Build the filename */ + path_build(buf, 1024, ANGBAND_DIR_EDIT, name); + + /* Open the file */ + fp = my_fopen(buf, "r"); + + /* No such file */ + if (!fp) + { + msg_format("Cannot find file %s at %s", name, buf); + return ( -1); + } + + /* Process the file */ + while (0 == my_fgets(fp, buf, 1024)) + { + /* Count lines */ + num++; + + + /* Skip "empty" lines */ + if (!buf[0]) continue; + + /* Skip "blank" lines */ + if (isspace(buf[0])) continue; + + /* Skip comments */ + if (buf[0] == '#') continue; + + + /* Process "?:<expr>" */ + if ((buf[0] == '?') && (buf[1] == ':')) + { + char f; + cptr v; + char *s; + + /* Start */ + s = buf + 2; + + /* Parse the expr */ + v = process_dungeon_file_expr(&s, &f); + + /* Set flag */ + bypass = (streq(v, "0") ? TRUE : FALSE); + + /* Continue */ + continue; + } + + /* Apply conditionals */ + if (bypass) continue; + + + /* Process "%:<file>" */ + if (buf[0] == '%') + { + /* Process that file if allowed */ + (void)process_dungeon_file(buf + 2, yval, xval, ymax, xmax, FALSE, full); + + /* Continue */ + continue; + } + + + /* Process the line */ + err = process_dungeon_file_aux(buf, yval, xval, xmin, ymax, xmax, full); + + /* Oops */ + if (err) break; + } + + + /* Error */ + if (err) + { + /* Useful error message */ + msg_format("Error %d in line %d of file '%s'.", err, num, name); + msg_format("Parsing '%s'", buf); + } + + /* Close the file */ + my_fclose(fp); + + /* Result */ + return (err); +} |