/** * Load a specific items file * * @param filename The full path and name of the file to load */ void ItemManager::load(const string& filename) { FileParser infile; int id = 0; string s; int bonus_counter = 0; if (infile.open(filename)) { while (infile.next()) { if (infile.key == "id") { id = atoi(infile.val.c_str()); // new item, reset bonus counter bonus_counter = 0; } else if (infile.key == "name") items[id].name = msg->get(infile.val); else if (infile.key == "level") items[id].level = atoi(infile.val.c_str()); else if (infile.key == "icon") { items[id].icon32 = atoi(infile.nextValue().c_str()); items[id].icon64 = atoi(infile.nextValue().c_str()); } else if (infile.key == "quality") { if (infile.val == "low") items[id].quality = ITEM_QUALITY_LOW; else if (infile.val == "high") items[id].quality = ITEM_QUALITY_HIGH; else if (infile.val == "epic") items[id].quality = ITEM_QUALITY_EPIC; } else if (infile.key == "type") { if (infile.val == "main") items[id].type = ITEM_TYPE_MAIN; else if (infile.val == "body") items[id].type = ITEM_TYPE_BODY; else if (infile.val == "off") items[id].type = ITEM_TYPE_OFF; else if (infile.val == "artifact") items[id].type = ITEM_TYPE_ARTIFACT; else if (infile.val == "consumable") items[id].type = ITEM_TYPE_CONSUMABLE; else if (infile.val == "gem") items[id].type = ITEM_TYPE_GEM; else if (infile.val == "quest") items[id].type = ITEM_TYPE_QUEST; } else if (infile.key == "dmg") { items[id].dmg_min = atoi(infile.nextValue().c_str()); if (infile.val.length() > 0) items[id].dmg_max = atoi(infile.nextValue().c_str()); else items[id].dmg_max = items[id].dmg_min; } else if (infile.key == "abs") { items[id].abs_min = atoi(infile.nextValue().c_str()); if (infile.val.length() > 0) items[id].abs_max = atoi(infile.nextValue().c_str()); else items[id].abs_max = items[id].abs_min; } else if (infile.key == "req") { s = infile.nextValue(); if (s == "p") items[id].req_stat = REQUIRES_PHYS; else if (s == "m") items[id].req_stat = REQUIRES_MENT; else if (s == "o") items[id].req_stat = REQUIRES_OFF; else if (s == "d") items[id].req_stat = REQUIRES_DEF; items[id].req_val = atoi(infile.nextValue().c_str()); } else if (infile.key == "bonus") { if (bonus_counter < ITEM_MAX_BONUSES) { items[id].bonus_stat[bonus_counter] = infile.nextValue(); items[id].bonus_val[bonus_counter] = atoi(infile.nextValue().c_str()); bonus_counter++; } } else if (infile.key == "sfx") { if (infile.val == "book") items[id].sfx = SFX_BOOK; else if (infile.val == "cloth") items[id].sfx = SFX_CLOTH; else if (infile.val == "coins") items[id].sfx = SFX_COINS; else if (infile.val == "gem") items[id].sfx = SFX_GEM; else if (infile.val == "leather") items[id].sfx = SFX_LEATHER; else if (infile.val == "metal") items[id].sfx = SFX_METAL; else if (infile.val == "page") items[id].sfx = SFX_PAGE; else if (infile.val == "maille") items[id].sfx = SFX_MAILLE; else if (infile.val == "object") items[id].sfx = SFX_OBJECT; else if (infile.val == "heavy") items[id].sfx = SFX_HEAVY; else if (infile.val == "wood") items[id].sfx = SFX_WOOD; else if (infile.val == "potion") items[id].sfx = SFX_POTION; } else if (infile.key == "gfx") items[id].gfx = infile.val; else if (infile.key == "loot") items[id].loot = infile.val; else if (infile.key == "power") items[id].power = atoi(infile.val.c_str()); else if (infile.key == "power_mod") items[id].power_mod = atoi(infile.val.c_str()); else if (infile.key == "power_desc") items[id].power_desc = msg->get(infile.val); else if (infile.key == "price") items[id].price = atoi(infile.val.c_str()); else if (infile.key == "price_sell") items[id].price_sell = atoi(infile.val.c_str()); else if (infile.key == "max_quantity") items[id].max_quantity = atoi(infile.val.c_str()); else if (infile.key == "rand_loot") items[id].rand_loot = atoi(infile.val.c_str()); else if (infile.key == "rand_vendor") items[id].rand_vendor = atoi(infile.val.c_str()); else if (infile.key == "pickup_status") items[id].pickup_status = infile.val; else if (infile.key == "stepfx") items[id].stepfx = infile.val; } infile.close(); } }
MenuDevConsole::MenuDevConsole() : Menu() , input_scrollback_pos(0) { button_close = new WidgetButton("images/menus/buttons/button_x.png"); tablist.add(button_close); input_box = new WidgetInput("images/menus/input_console.png"); tablist.add(input_box); button_confirm = new WidgetButton(); button_confirm->label = msg->get("Execute"); tablist.add(button_confirm); // Load config settings FileParser infile; // @CLASS MenuDevConsole|Description of menus/devconsole.txt if(infile.open("menus/devconsole.txt")) { while(infile.next()) { if (parseMenuKey(infile.key, infile.val)) continue; // @ATTR close|x (integer), y (integer)|Position of the close button. if(infile.key == "close") { Point pos = toPoint(infile.val); button_close->setBasePos(pos.x, pos.y); } // @ATTR label_title|label|Position of the "Developer Console" label. else if(infile.key == "label_title") title = eatLabelInfo(infile.val); // @ATTR confirm|x (integer), y (integer)|Position of the "Execute" button. else if(infile.key == "confirm") { Point pos = toPoint(infile.val); button_confirm->setBasePos(pos.x, pos.y); } // @ATTR input|x (integer), y (integer)|Position of the command entry widget. else if(infile.key == "input") { Point pos = toPoint(infile.val); input_box->setBasePos(pos.x, pos.y); } // @ATTR history|x (integer), y (integer), w (integer), h (integer)|Position and dimensions of the command history. else if(infile.key == "history") history_area = toRect(infile.val); else infile.error("MenuDevConsole: '%s' is not a valid key.", infile.key.c_str()); } infile.close(); } log_history = new WidgetLog(history_area.w, history_area.h); log_history->setBasePos(history_area.x, history_area.y); tablist.add(log_history->getWidget()); setBackground("images/menus/dev_console.png"); color_echo = font->getColor("widget_disabled"); color_error = font->getColor("menu_penalty"); color_hint = font->getColor("menu_bonus"); align(); input_box->inFocus = true; }
/** * load a statblock, typically for an enemy definition */ void StatBlock::load(string filename) { FileParser infile; int num; if (infile.open(PATH_DATA + filename)) { while (infile.next()) { if (isInt(infile.val)) num = atoi(infile.val.c_str()); if (infile.key == "name") name = infile.val; else if (infile.key == "sfx_prefix") sfx_prefix = infile.val; else if (infile.key == "gfx_prefix") gfx_prefix = infile.val; else if (infile.key == "level") level = num; // enemy death rewards and events else if (infile.key == "xp") xp = num; else if (infile.key == "loot_chance") loot_chance = num; else if (infile.key == "defeat_status") defeat_status = infile.val; else if (infile.key == "first_defeat_loot") first_defeat_loot = num; else if (infile.key == "quest_loot") { quest_loot_requires = infile.nextValue(); quest_loot_not = infile.nextValue(); quest_loot_id = atoi(infile.nextValue().c_str()); } // combat stats else if (infile.key == "hp") { hp = num; maxhp = num; } else if (infile.key == "mp") { mp = num; maxmp = num; } else if (infile.key == "cooldown") cooldown = num; else if (infile.key == "accuracy") accuracy = num; else if (infile.key == "avoidance") avoidance = num; else if (infile.key == "dmg_melee_min") dmg_melee_min = num; else if (infile.key == "dmg_melee_max") dmg_melee_max = num; else if (infile.key == "dmg_ment_min") dmg_ment_min = num; else if (infile.key == "dmg_ment_max") dmg_ment_max = num; else if (infile.key == "dmg_ranged_min") dmg_ranged_min = num; else if (infile.key == "dmg_ranged_max") dmg_ranged_max = num; else if (infile.key == "absorb_min") absorb_min = num; else if (infile.key == "absorb_max") absorb_max = num; // behavior stats else if (infile.key == "speed") speed = num; else if (infile.key == "dspeed") dspeed = num; else if (infile.key == "dir_favor") dir_favor = num; else if (infile.key == "chance_pursue") chance_pursue = num; else if (infile.key == "chance_flee") chance_flee = num; else if (infile.key == "chance_melee_phys") power_chance[MELEE_PHYS] = num; else if (infile.key == "chance_melee_ment") power_chance[MELEE_MENT] = num; else if (infile.key == "chance_ranged_phys") power_chance[RANGED_PHYS] = num; else if (infile.key == "chance_ranged_ment") power_chance[RANGED_MENT] = num; else if (infile.key == "power_melee_phys") power_index[MELEE_PHYS] = num; else if (infile.key == "power_melee_ment") power_index[MELEE_MENT] = num; else if (infile.key == "power_ranged_phys") power_index[RANGED_PHYS] = num; else if (infile.key == "power_ranged_ment") power_index[RANGED_MENT] = num; else if (infile.key == "power_beacon") power_index[BEACON] = num; else if (infile.key == "cooldown_melee_phys") power_cooldown[MELEE_PHYS] = num; else if (infile.key == "cooldown_melee_ment") power_cooldown[MELEE_MENT] = num; else if (infile.key == "cooldown_ranged_phys") power_cooldown[RANGED_PHYS] = num; else if (infile.key == "cooldown_ranged_ment") power_cooldown[RANGED_MENT] = num; else if (infile.key == "melee_range") melee_range = num; else if (infile.key == "threat_range") threat_range = num; else if (infile.key == "attunement_fire") attunement_fire=num; else if (infile.key == "attunement_ice") attunement_ice=num; // animation stats else if (infile.key == "melee_weapon_power") melee_weapon_power = num; else if (infile.key == "mental_weapon_power") mental_weapon_power = num; else if (infile.key == "ranged_weapon_power") ranged_weapon_power = num; else if (infile.key == "animations") animations = infile.val; else if (infile.key == "animation_speed") animationSpeed = num; } infile.close(); } }
/** * Load a specific items file * * @param filename The (full) path and name of the file to load */ void ItemManager::loadItems(const std::string& filename) { FileParser infile; // @CLASS ItemManager: Items|Description about the class and it usage, items/items.txt... if (!infile.open(filename, FileParser::MOD_FILE, FileParser::ERROR_NORMAL)) return; // used to clear vectors when overriding items bool clear_req_stat = true; bool clear_bonus = true; bool clear_loot_anim = true; bool clear_replace_power = true; int id = 0; bool id_line = false; while (infile.next()) { if (infile.key == "id") { // @ATTR id|item_id|An uniq id of the item used as reference from other classes. id_line = true; id = Parse::toInt(infile.val); addUnknownItem(id); items[id].max_quantity = 1; clear_req_stat = true; clear_bonus = true; clear_loot_anim = true; clear_replace_power = true; } else id_line = false; if (id < 1) { if (id_line) infile.error("ItemManager: Item index out of bounds 1-%d, skipping item.", INT_MAX); continue; } if (id_line) continue; assert(items.size() > std::size_t(id)); if (infile.key == "name") { // @ATTR name|string|Item name displayed on long and short tooltips. items[id].name = msg->get(infile.val); items[id].has_name = true; } else if (infile.key == "flavor") // @ATTR flavor|string|A description of the item. items[id].flavor = msg->get(infile.val); else if (infile.key == "level") // @ATTR level|int|The item's level. Has no gameplay impact. (Deprecated?) items[id].level = Parse::toInt(infile.val); else if (infile.key == "icon") { // @ATTR icon|icon_id|An id for the icon to display for this item. items[id].icon = Parse::toInt(infile.val); } else if (infile.key == "book") { // @ATTR book|filename|A book file to open when this item is activated. items[id].book = infile.val; } else if (infile.key == "book_is_readable") { // @ATTR book_is_readable|bool|If true, "read" is displayed in the tooltip instead of "use". Defaults to true. items[id].book_is_readable = Parse::toBool(infile.val); } else if (infile.key == "quality") { // @ATTR quality|predefined_string|Item quality matching an id in items/qualities.txt items[id].quality = infile.val; } else if (infile.key == "item_type") { // @ATTR item_type|predefined_string|Equipment slot matching an id in items/types.txt items[id].type = infile.val; } else if (infile.key == "equip_flags") { // @ATTR equip_flags|list(predefined_string)|A comma separated list of flags to set when this item is equipped. See engine/equip_flags.txt. items[id].equip_flags.clear(); std::string flag = Parse::popFirstString(infile.val); while (flag != "") { items[id].equip_flags.push_back(flag); flag = Parse::popFirstString(infile.val); } } else if (infile.key == "dmg") { // @ATTR dmg|predefined_string, int, int : Damage type, Min, Max|Defines the item's base damage type and range. Max may be ommitted and will default to Min. std::string dmg_type_str = Parse::popFirstString(infile.val); size_t dmg_type = eset->damage_types.list.size(); for (size_t i = 0; i < eset->damage_types.list.size(); ++i) { if (dmg_type_str == eset->damage_types.list[i].id) { dmg_type = i; break; } } if (dmg_type == eset->damage_types.list.size()) { infile.error("ItemManager: '%s' is not a known damage type id.", dmg_type_str.c_str()); } else { items[id].dmg_min[dmg_type] = Parse::popFirstInt(infile.val); if (infile.val.length() > 0) items[id].dmg_max[dmg_type] = Parse::popFirstInt(infile.val); else items[id].dmg_max[dmg_type] = items[id].dmg_min[dmg_type]; } } else if (infile.key == "abs") { // @ATTR abs|int, int : Min, Max|Defines the item absorb value, if only min is specified the absorb value is fixed. items[id].abs_min = Parse::popFirstInt(infile.val); if (infile.val.length() > 0) items[id].abs_max = Parse::popFirstInt(infile.val); else items[id].abs_max = items[id].abs_min; } else if (infile.key == "requires_level") { // @ATTR requires_level|int|The hero's level must match or exceed this value in order to equip this item. items[id].requires_level = Parse::toInt(infile.val); } else if (infile.key == "requires_stat") { // @ATTR requires_stat|repeatable(predefined_string, int) : Primary stat name, Value|Make item require specific stat level ex. requires_stat=physical,6 will require hero to have level 6 in physical stats if (clear_req_stat) { items[id].req_stat.clear(); items[id].req_val.clear(); clear_req_stat = false; } std::string s = Parse::popFirstString(infile.val); size_t req_stat_index = eset->primary_stats.getIndexByID(s); if (req_stat_index != eset->primary_stats.list.size()) items[id].req_stat.push_back(req_stat_index); else infile.error("ItemManager: '%s' is not a valid primary stat.", s.c_str()); items[id].req_val.push_back(Parse::popFirstInt(infile.val)); } else if (infile.key == "requires_class") { // @ATTR requires_class|predefined_string|The hero's base class (engine/classes.txt) must match for this item to be equipped. items[id].requires_class = infile.val; } else if (infile.key == "bonus") { // @ATTR bonus|repeatable(predefined_string, int) : Stat name, Value|Adds a bonus to the item by stat name, example: bonus=hp, 50 if (clear_bonus) { items[id].bonus.clear(); clear_bonus = false; } BonusData bdata; parseBonus(bdata, infile); items[id].bonus.push_back(bdata); } else if (infile.key == "bonus_power_level") { // @ATTR bonus_power_level|repeatable(power_id, int) : Base power, Bonus levels|Grants bonus levels to a given base power. BonusData bdata; bdata.power_id = Parse::popFirstInt(infile.val); bdata.value = Parse::popFirstInt(infile.val); items[id].bonus.push_back(bdata); } else if (infile.key == "soundfx") { // @ATTR soundfx|filename|Sound effect filename to play for the specific item. items[id].sfx = infile.val; items[id].sfx_id = snd->load(items[id].sfx, "ItemManager"); } else if (infile.key == "gfx") // @ATTR gfx|filename|Filename of an animation set to display when the item is equipped. items[id].gfx = infile.val; else if (infile.key == "loot_animation") { // @ATTR loot_animation|repeatable(filename, int, int) : Loot image, Min quantity, Max quantity|Specifies the loot animation file for the item. The max quantity, or both quantity values, may be omitted. if (clear_loot_anim) { items[id].loot_animation.clear(); clear_loot_anim = false; } LootAnimation la; la.name = Parse::popFirstString(infile.val); la.low = Parse::popFirstInt(infile.val); la.high = Parse::popFirstInt(infile.val); items[id].loot_animation.push_back(la); } else if (infile.key == "power") { // @ATTR power|power_id|Adds a specific power to the item which makes it usable as a power and can be placed in action bar. if (Parse::toInt(infile.val) > 0) items[id].power = Parse::toInt(infile.val); else infile.error("ItemManager: Power index out of bounds 1-%d, skipping power.", INT_MAX); } else if (infile.key == "replace_power") { // @ATTR replace_power|repeatable(int, int) : Old power, New power|Replaces the old power id with the new power id in the action bar when equipped. if (clear_replace_power) { items[id].replace_power.clear(); clear_replace_power = false; } Point power_ids = Parse::toPoint(infile.val); items[id].replace_power.push_back(power_ids); } else if (infile.key == "power_desc") // @ATTR power_desc|string|A string describing the additional power. items[id].power_desc = msg->get(infile.val); else if (infile.key == "price") // @ATTR price|int|The amount of currency the item costs, if set to 0 the item cannot be sold. items[id].price = Parse::toInt(infile.val); else if (infile.key == "price_per_level") // @ATTR price_per_level|int|Additional price for each player level above 1 items[id].price_per_level = Parse::toInt(infile.val); else if (infile.key == "price_sell") // @ATTR price_sell|int|The amount of currency the item is sold for, if set to 0 the sell prices is prices*vendor_ratio. items[id].price_sell = Parse::toInt(infile.val); else if (infile.key == "max_quantity") // @ATTR max_quantity|int|Max item count per stack. items[id].max_quantity = Parse::toInt(infile.val); else if (infile.key == "pickup_status") // @ATTR pickup_status|string|Set a campaign status when item is picked up, this is used for quest items. items[id].pickup_status = infile.val; else if (infile.key == "stepfx") // @ATTR stepfx|predefined_string|Sound effect when walking, this applies only to armors. items[id].stepfx = infile.val; else if (infile.key == "disable_slots") { // @ATTR disable_slots|list(predefined_string)|A comma separated list of equip slot types to disable when this item is equipped. items[id].disable_slots.clear(); std::string slot_type = Parse::popFirstString(infile.val); while (slot_type != "") { items[id].disable_slots.push_back(slot_type); slot_type = Parse::popFirstString(infile.val); } } else if (infile.key == "quest_item") { // @ATTR quest_item|bool|If true, this item is a quest item and can not be dropped, stashed, or sold. items[id].quest_item = Parse::toBool(infile.val); } else if (infile.key == "no_stash") { // @ATTR no_stash|bool|If true, this item can not be stashed. items[id].no_stash = Parse::toBool(infile.val); } else { infile.error("ItemManager: '%s' is not a valid key.", infile.key.c_str()); } } infile.close(); }
/** * load a statblock, typically for an enemy definition */ void StatBlock::load(const string& filename) { FileParser infile; int num = 0; if (infile.open(mods->locate(filename))) { while (infile.next()) { if (isInt(infile.val)) num = atoi(infile.val.c_str()); if (infile.key == "name") name = msg->get(infile.val); else if (infile.key == "humanoid") { if (infile.val == "true") humanoid = true; } else if (infile.key == "sfx_prefix") sfx_prefix = infile.val; else if (infile.key == "gfx_prefix") gfx_prefix = infile.val; else if (infile.key == "level") level = num; // enemy death rewards and events else if (infile.key == "xp") xp = num; else if (infile.key == "loot_chance") loot_chance = num; else if (infile.key == "loot_type") { string str; while ((str = infile.nextValue()) != "") { if (!isInt(str)) { loot_types.push_back(str); loot_prob.push_back(1); loot_prob_sum++; } else { num = atoi(str.c_str()); loot_prob[loot_types.size()-1] = num; loot_prob_sum += num - 1; // one was already added, so add one less } } } else if (infile.key == "defeat_status") defeat_status = infile.val; else if (infile.key == "first_defeat_loot") first_defeat_loot = num; else if (infile.key == "quest_loot") { quest_loot_requires = infile.nextValue(); quest_loot_not = infile.nextValue(); quest_loot_id = atoi(infile.nextValue().c_str()); } // combat stats else if (infile.key == "hp") { hp = num; maxhp = num; } else if (infile.key == "mp") { mp = num; maxmp = num; } else if (infile.key == "cooldown") cooldown = num; else if (infile.key == "accuracy") accuracy = num; else if (infile.key == "avoidance") avoidance = num; else if (infile.key == "dmg_melee_min") dmg_melee_min = num; else if (infile.key == "dmg_melee_max") dmg_melee_max = num; else if (infile.key == "dmg_ment_min") dmg_ment_min = num; else if (infile.key == "dmg_ment_max") dmg_ment_max = num; else if (infile.key == "dmg_ranged_min") dmg_ranged_min = num; else if (infile.key == "dmg_ranged_max") dmg_ranged_max = num; else if (infile.key == "absorb_min") absorb_min = num; else if (infile.key == "absorb_max") absorb_max = num; // behavior stats else if (infile.key == "flying") { if (num == 1) flying = true; } else if (infile.key == "intangible") { if (num == 1) intangible = true; } else if (infile.key == "facing") { if (num == 0) facing = false; } else if (infile.key == "waypoint_pause") waypoint_pause = num; else if (infile.key == "speed") speed = num; else if (infile.key == "dspeed") dspeed = num; else if (infile.key == "turn_delay") turn_delay = num; else if (infile.key == "chance_pursue") chance_pursue = num; else if (infile.key == "chance_flee") chance_flee = num; else if (infile.key == "chance_melee_phys") power_chance[MELEE_PHYS] = num; else if (infile.key == "chance_melee_ment") power_chance[MELEE_MENT] = num; else if (infile.key == "chance_ranged_phys") power_chance[RANGED_PHYS] = num; else if (infile.key == "chance_ranged_ment") power_chance[RANGED_MENT] = num; else if (infile.key == "power_melee_phys") power_index[MELEE_PHYS] = num; else if (infile.key == "power_melee_ment") power_index[MELEE_MENT] = num; else if (infile.key == "power_ranged_phys") power_index[RANGED_PHYS] = num; else if (infile.key == "power_ranged_ment") power_index[RANGED_MENT] = num; else if (infile.key == "power_beacon") power_index[BEACON] = num; else if (infile.key == "cooldown_melee_phys") power_cooldown[MELEE_PHYS] = num; else if (infile.key == "cooldown_melee_ment") power_cooldown[MELEE_MENT] = num; else if (infile.key == "cooldown_ranged_phys") power_cooldown[RANGED_PHYS] = num; else if (infile.key == "cooldown_ranged_ment") power_cooldown[RANGED_MENT] = num; else if (infile.key == "power_on_hit") power_index[ON_HIT] = num; else if (infile.key == "power_on_death") power_index[ON_DEATH] = num; else if (infile.key == "power_on_half_dead") power_index[ON_HALF_DEAD] = num; else if (infile.key == "power_on_debuff") power_index[ON_DEBUFF] = num; else if (infile.key == "power_on_join_combat") power_index[ON_JOIN_COMBAT] = num; else if (infile.key == "chance_on_hit") power_chance[ON_HIT] = num; else if (infile.key == "chance_on_death") power_chance[ON_DEATH] = num; else if (infile.key == "chance_on_half_dead") power_chance[ON_HALF_DEAD] = num; else if (infile.key == "chance_on_debuff") power_chance[ON_DEBUFF] = num; else if (infile.key == "chance_on_join_combat") power_chance[ON_JOIN_COMBAT] = num; else if (infile.key == "melee_range") melee_range = num; else if (infile.key == "threat_range") threat_range = num; else if (infile.key == "attunement_fire") attunement_fire=num; else if (infile.key == "attunement_ice") attunement_ice=num; // animation stats else if (infile.key == "melee_weapon_power") melee_weapon_power = num; else if (infile.key == "mental_weapon_power") mental_weapon_power = num; else if (infile.key == "ranged_weapon_power") ranged_weapon_power = num; else if (infile.key == "animations") animations = infile.val; else if (infile.key == "animation_speed") animationSpeed = num; } infile.close(); } }
MenuTalker::MenuTalker(MenuManager *_menu) : Menu() , menu(_menu) , portrait(NULL) , dialog_node(0) , event_cursor(0) , font_who("font_regular") , font_dialog("font_regular") , color_normal(font->getColor("menu_normal")) , npc(NULL) , vendor_visible(false) , advanceButton(new WidgetButton("images/menus/buttons/right.png")) , closeButton(new WidgetButton("images/menus/buttons/button_x.png")) { background = loadGraphicSurface("images/menus/dialog_box.png"); // Load config settings FileParser infile; if(infile.open("menus/talker.txt")) { while(infile.next()) { infile.val = infile.val + ','; if(infile.key == "close") { close_pos.x = eatFirstInt(infile.val,','); close_pos.y = eatFirstInt(infile.val,','); } else if(infile.key == "advance") { advance_pos.x = eatFirstInt(infile.val,','); advance_pos.y = eatFirstInt(infile.val,','); } else if (infile.key == "dialogbox") { dialog_pos.x = eatFirstInt(infile.val,','); dialog_pos.y = eatFirstInt(infile.val,','); dialog_pos.w = eatFirstInt(infile.val,','); dialog_pos.h = eatFirstInt(infile.val,','); } else if (infile.key == "dialogtext") { text_pos.x = eatFirstInt(infile.val,','); text_pos.y = eatFirstInt(infile.val,','); text_pos.w = eatFirstInt(infile.val,','); text_pos.h = eatFirstInt(infile.val,','); } else if (infile.key == "text_offset") { text_offset.x = eatFirstInt(infile.val,','); text_offset.y = eatFirstInt(infile.val,','); } else if (infile.key == "portrait_he") { portrait_he.x = eatFirstInt(infile.val,','); portrait_he.y = eatFirstInt(infile.val,','); portrait_he.w = eatFirstInt(infile.val,','); portrait_he.h = eatFirstInt(infile.val,','); } else if (infile.key == "portrait_you") { portrait_you.x = eatFirstInt(infile.val,','); portrait_you.y = eatFirstInt(infile.val,','); portrait_you.w = eatFirstInt(infile.val,','); portrait_you.h = eatFirstInt(infile.val,','); } else if (infile.key == "font_who") { font_who = eatFirstString(infile.val,','); } else if (infile.key == "font_dialog") { font_dialog = eatFirstString(infile.val,','); } } infile.close(); } label_name = new WidgetLabel(); textbox = new WidgetScrollBox(text_pos.w, text_pos.h-(text_offset.y*2)); tablist.add(advanceButton); tablist.add(closeButton); tablist.add(textbox); }
void loadMiscSettings() { FileParser infile; // load miscellaneous settings from engine config // misc.txt if (infile.open(mods->locate("engine/misc.txt").c_str())) { while (infile.next()) { if (infile.key == "save_hpmp") { SAVE_HPMP = toInt(infile.val); } else if (infile.key == "default_name") { DEFAULT_NAME = infile.val.c_str(); } else if (infile.key == "corpse_timeout") { CORPSE_TIMEOUT = toInt(infile.val); } else if (infile.key == "sell_without_vendor") { SELL_WITHOUT_VENDOR = toInt(infile.val); } } infile.close(); } else fprintf(stderr, "Unable to open engine/misc.txt!\n"); // resolutions.txt if (infile.open(mods->locate("engine/resolutions.txt").c_str())) { while (infile.next()) { if (infile.key == "menu_frame_width") FRAME_W = toInt(infile.val); else if (infile.key == "menu_frame_height") FRAME_H = toInt(infile.val); else if (infile.key == "icon_size") ICON_SIZE = toInt(infile.val); else if (infile.key == "required_width") { MIN_VIEW_W = toInt(infile.val); if (VIEW_W < MIN_VIEW_W) VIEW_W = MIN_VIEW_W; VIEW_W_HALF = VIEW_W/2; } else if (infile.key == "required_height") { MIN_VIEW_H = toInt(infile.val); if (VIEW_H < MIN_VIEW_H) VIEW_H = MIN_VIEW_H; VIEW_H_HALF = VIEW_H/2; } } infile.close(); } else fprintf(stderr, "Unable to open engine/resolutions.txt!\n"); // gameplay.txt if (infile.open(mods->locate("engine/gameplay.txt").c_str())) { while (infile.next()) { if (infile.key == "enable_playgame") { ENABLE_PLAYGAME = toInt(infile.val); } } infile.close(); } else fprintf(stderr, "Unable to open engine/gameplay.txt!\n"); // combat.txt if (infile.open(mods->locate("engine/combat.txt").c_str())) { while (infile.next()) { if (infile.key == "max_absorb_percent") { MAX_ABSORB = toInt(infile.val); } else if (infile.key == "max_resist_percent") { MAX_RESIST = toInt(infile.val); } else if (infile.key == "max_block_percent") { MAX_BLOCK = toInt(infile.val); } else if (infile.key == "max_avoidance_percent") { MAX_AVOIDANCE = toInt(infile.val); } } infile.close(); } else fprintf(stderr, "Unable to open engine/combat.txt!\n"); // elements.txt if (infile.open(mods->locate("engine/elements.txt").c_str())) { Element e; ELEMENTS.clear(); while (infile.next()) { if (infile.key == "name") e.name = infile.val; else if (infile.key == "resist") e.resist = infile.val; if (e.name != "" && e.resist != "") { ELEMENTS.push_back(e); e.name = e.resist = ""; } } infile.close(); } else fprintf(stderr, "Unable to open engine/elements.txt!\n"); // classes.txt if (infile.open(mods->locate("engine/classes.txt").c_str())) { HeroClass c; HERO_CLASSES.clear(); while (infile.next()) { if (infile.key == "name") c.name = infile.val; if (c.name != "") { HERO_CLASSES.push_back(c); c.name = ""; } if (!HERO_CLASSES.empty()) { if (infile.key == "description") HERO_CLASSES.back().description = infile.val; else if (infile.key == "currency") HERO_CLASSES.back().currency = toInt(infile.val); else if (infile.key == "equipment") HERO_CLASSES.back().equipment = infile.val; else if (infile.key == "physical") HERO_CLASSES.back().physical = toInt(infile.val); else if (infile.key == "mental") HERO_CLASSES.back().mental = toInt(infile.val); else if (infile.key == "offense") HERO_CLASSES.back().offense = toInt(infile.val); else if (infile.key == "defense") HERO_CLASSES.back().defense = toInt(infile.val); else if (infile.key == "actionbar") { for (int i=0; i<12; i++) { HERO_CLASSES.back().hotkeys[i] = toInt(infile.nextValue()); } } else if (infile.key == "powers") { string power; while ( (power = infile.nextValue()) != "") { HERO_CLASSES.back().powers.push_back(toInt(power)); } } } } infile.close(); } else fprintf(stderr, "Unable to open engine/classes.txt!\n"); // Make a default hero class if none were found if (HERO_CLASSES.empty()) { HeroClass c; c.name = msg->get("Adventurer"); HERO_CLASSES.push_back(c); } }
void loadMiscSettings() { // reset to defaults ELEMENTS.clear(); EQUIP_FLAGS.clear(); HERO_CLASSES.clear(); FRAME_W = 0; FRAME_H = 0; ICON_SIZE = 0; AUTOPICKUP_CURRENCY = false; MAX_ABSORB = 90; MAX_RESIST = 90; MAX_BLOCK = 100; MAX_AVOIDANCE = 99; MIN_ABSORB = 0; MIN_RESIST = 0; MIN_BLOCK = 0; MIN_AVOIDANCE = 0; CURRENCY = "Gold"; VENDOR_RATIO = 0.25; DEATH_PENALTY = true; DEATH_PENALTY_PERMADEATH = false; DEATH_PENALTY_CURRENCY = 50; DEATH_PENALTY_XP = 0; DEATH_PENALTY_XP_CURRENT = 0; DEATH_PENALTY_ITEM = false; MENUS_PAUSE = false; SAVE_HPMP = false; ENABLE_PLAYGAME = false; CORPSE_TIMEOUT = 60*MAX_FRAMES_PER_SEC; SELL_WITHOUT_VENDOR = true; AIM_ASSIST = 0; WINDOW_TITLE = "Flare"; SOUND_FALLOFF = 15; PARTY_EXP_PERCENTAGE = 100; ENABLE_ALLY_COLLISION_AI = true; ENABLE_ALLY_COLLISION = true; CURRENCY_ID = 1; INTERACT_RANGE = 3; FileParser infile; // @CLASS Settings: Misc|Description of engine/misc.txt if (infile.open("engine/misc.txt")) { while (infile.next()) { // @ATTR save_hpmp|boolean|When saving the game, keep the hero's current HP and MP. if (infile.key == "save_hpmp") SAVE_HPMP = toBool(infile.val); // @ATTR corpse_timeout|duration|Duration that a corpse can exist on the map. else if (infile.key == "corpse_timeout") CORPSE_TIMEOUT = parse_duration(infile.val); // @ATTR sell_without_vendor|boolean|Allows selling items when not at a vendor via CTRL-Click. else if (infile.key == "sell_without_vendor") SELL_WITHOUT_VENDOR = toBool(infile.val); // @ATTR aim_assist|integer|The pixel offset for powers that use aim_assist. else if (infile.key == "aim_assist") AIM_ASSIST = toInt(infile.val); // @ATTR window_title|string|Sets the text in the window's titlebar. else if (infile.key == "window_title") WINDOW_TITLE = infile.val; // @ATTR save_prefix|string|A string that's prepended to save filenames to prevent conflicts between mods. else if (infile.key == "save_prefix") SAVE_PREFIX = infile.val; // @ATTR sound_falloff|integer|The maximum radius in tiles that any single sound is audible. else if (infile.key == "sound_falloff") SOUND_FALLOFF = toInt(infile.val); // @ATTR party_exp_percentage|integer|The percentage of XP given to allies. else if (infile.key == "party_exp_percentage") PARTY_EXP_PERCENTAGE = toInt(infile.val); // @ATTR enable_ally_collision|boolean|Allows allies to block the player's path. else if (infile.key == "enable_ally_collision") ENABLE_ALLY_COLLISION = toBool(infile.val); // @ATTR enable_ally_collision_ai|boolean|Allows allies to block the path of other AI creatures. else if (infile.key == "enable_ally_collision_ai") ENABLE_ALLY_COLLISION_AI = toBool(infile.val); else if (infile.key == "currency_id") { // @ATTR currency_id|integer|An item id that will be used as currency. CURRENCY_ID = toInt(infile.val); if (CURRENCY_ID < 1) { CURRENCY_ID = 1; fprintf(stderr, "Currency ID below the minimum allowed value. Resetting it to %d\n", CURRENCY_ID); } } // @ATTR interact_range|float|Distance where the player can interact with objects and NPCs. else if (infile.key == "interact_range") INTERACT_RANGE = toFloat(infile.val); // @ATTR menus_pause|boolean|Opening any menu will pause the game. else if (infile.key == "menus_pause") MENUS_PAUSE = toBool(infile.val); } infile.close(); } // @CLASS Settings: Resolution|Description of engine/resolutions.txt if (infile.open("engine/resolutions.txt")) { while (infile.next()) { // @ATTR menu_frame_width|integer|Width of frame for New Game, Configuration, etc. menus. if (infile.key == "menu_frame_width") FRAME_W = toInt(infile.val); // @ATTR menu_frame_width|integer|Height of frame for New Game, Configuration, etc. menus. else if (infile.key == "menu_frame_height") FRAME_H = toInt(infile.val); // @ATTR icon_size|integer|Size of icons. else if (infile.key == "icon_size") ICON_SIZE = toInt(infile.val); // @ATTR required_width|integer|Minimum window/screen resolution width. else if (infile.key == "required_width") { MIN_VIEW_W = toInt(infile.val); if (VIEW_W < MIN_VIEW_W) VIEW_W = MIN_VIEW_W; VIEW_W_HALF = VIEW_W/2; } // @ATTR required_width|integer|Minimum window/screen resolution height. else if (infile.key == "required_height") { MIN_VIEW_H = toInt(infile.val); if (VIEW_H < MIN_VIEW_H) VIEW_H = MIN_VIEW_H; VIEW_H_HALF = VIEW_H/2; } } infile.close(); } // @CLASS Settings: Gameplay|Description of engine/gameplay.txt if (infile.open("engine/gameplay.txt")) { while (infile.next()) { if (infile.key == "enable_playgame") { // @ATTR enable_playgame|boolean|Enables the "Play Game" button on the main menu. ENABLE_PLAYGAME = toBool(infile.val); } } infile.close(); } // @CLASS Settings: Combat|Description of engine/combat.txt if (infile.open("engine/combat.txt")) { while (infile.next()) { // @ATTR max_absorb_percent|integer|Maximum percentage of damage that can be absorbed. if (infile.key == "max_absorb_percent") MAX_ABSORB = toInt(infile.val); // @ATTR max_resist_percent|integer|Maximum percentage of elemental damage that can be resisted. else if (infile.key == "max_resist_percent") MAX_RESIST = toInt(infile.val); // @ATTR max_block_percent|integer|Maximum percentage of damage that can be blocked. else if (infile.key == "max_block_percent") MAX_BLOCK = toInt(infile.val); // @ATTR max_avoidance_percent|integer|Maximum percentage chance that hazards can be avoided. else if (infile.key == "max_avoidance_percent") MAX_AVOIDANCE = toInt(infile.val); // @ATTR min_absorb_percent|integer|Minimum percentage of damage that can be absorbed. else if (infile.key == "min_absorb_percent") MIN_ABSORB = toInt(infile.val); // @ATTR min_resist_percent|integer|Minimum percentage of elemental damage that can be resisted. else if (infile.key == "min_resist_percent") MIN_RESIST = toInt(infile.val); // @ATTR min_block_percent|integer|Minimum percentage of damage that can be blocked. else if (infile.key == "min_block_percent") MIN_BLOCK = toInt(infile.val); // @ATTR min_avoidance_percent|integer|Minimum percentage chance that hazards can be avoided. else if (infile.key == "min_avoidance_percent") MIN_AVOIDANCE = toInt(infile.val); } infile.close(); } // @CLASS Settings: Elements|Description of engine/elements.txt if (infile.open("engine/elements.txt")) { Element e; while (infile.next()) { // @ATTR name|string|An identifier for this element. if (infile.key == "name") e.name = infile.val; // @ATTR dscription|string|The displayed name of this element. else if (infile.key == "description") e.description = infile.val; if (e.name != "" && e.description != "") { ELEMENTS.push_back(e); e.name = e.description = ""; } } infile.close(); } // @CLASS Settings: Equip flags|Description of engine/equip_flags.txt if (infile.open("engine/equip_flags.txt")) { string type,description; type = description = ""; while (infile.next()) { // @ATTR name|string|An identifier for this equip flag. if (infile.key == "name") type = infile.val; // @ATTR dscription|string|The displayed name of this equip flag. else if (infile.key == "description") description = infile.val; if (type != "" && description != "") { EQUIP_FLAGS[type] = description; type = description = ""; } } infile.close(); } // @CLASS Settings: Classes|Description of engine/classes.txt if (infile.open("engine/classes.txt")) { HeroClass c; while (infile.next()) { // @ATTR name|string|The displayed name of this class. if (infile.key == "name") c.name = infile.val; if (c.name != "") { HERO_CLASSES.push_back(c); c.name = ""; } if (!HERO_CLASSES.empty()) { // @ATTR description|string|A description of this class. if (infile.key == "description") HERO_CLASSES.back().description = infile.val; // @ATTR currency|integer|The amount of currency this class will start with. else if (infile.key == "currency") HERO_CLASSES.back().currency = toInt(infile.val); // @ATTR equipment|item (integer), ...|A list of items that are equipped when starting with this class. else if (infile.key == "equipment") HERO_CLASSES.back().equipment = infile.val; // @ATTR physical|integer|Class starts with this physical stat. else if (infile.key == "physical") HERO_CLASSES.back().physical = toInt(infile.val); // @ATTR mental|integer|Class starts with this mental stat. else if (infile.key == "mental") HERO_CLASSES.back().mental = toInt(infile.val); // @ATTR offense|integer|Class starts with this offense stat. else if (infile.key == "offense") HERO_CLASSES.back().offense = toInt(infile.val); // @ATTR defense|integer|Class starts with this defense stat. else if (infile.key == "defense") HERO_CLASSES.back().defense = toInt(infile.val); else if (infile.key == "actionbar") { // @ATTR actionbar|power (integer), ...|A list of powers to place in the action bar for the class. for (int i=0; i<12; i++) { HERO_CLASSES.back().hotkeys[i] = toInt(infile.nextValue()); } } else if (infile.key == "powers") { // @ATTR powers|power (integer), ...|A list of powers that are unlocked when starting this class. string power; while ( (power = infile.nextValue()) != "") { HERO_CLASSES.back().powers.push_back(toInt(power)); } } else if (infile.key == "campaign") { // @ATTR campaign|status (string), ...|A list of campaign statuses that are set when starting this class. string status; while ( (status = infile.nextValue()) != "") { HERO_CLASSES.back().statuses.push_back(status); } } } } infile.close(); } // Make a default hero class if none were found if (HERO_CLASSES.empty()) { HeroClass c; c.name = msg->get("Adventurer"); HERO_CLASSES.push_back(c); } // @CLASS Settings: Death penalty|Description of engine/death_penalty.txt if (infile.open("engine/death_penalty.txt")) { while (infile.next()) { // @ATTR enable|boolean|Enable the death penalty. if (infile.key == "enable") DEATH_PENALTY = toBool(infile.val); // @ATTR permadeath|boolean|Force permadeath for all new saves. else if (infile.key == "permadeath") DEATH_PENALTY_PERMADEATH = toBool(infile.val); // @ATTR currency|integer|Remove this percentage of currency. else if (infile.key == "currency") DEATH_PENALTY_CURRENCY = toInt(infile.val); // @ATTR xp_total|integer|Remove this percentage of total XP. else if (infile.key == "xp_total") DEATH_PENALTY_XP = toInt(infile.val); // @ATTR xp_current_level|integer|Remove this percentage of the XP gained since the last level. else if (infile.key == "xp_current_level") DEATH_PENALTY_XP_CURRENT = toInt(infile.val); // @ATTR random_item|integer|Removes a random item from the player's inventory. else if (infile.key == "random_item") DEATH_PENALTY_ITEM = toBool(infile.val); } infile.close(); } }
/** * Powers are defined in [mod]/powers/powers.txt * * @param filename The full path and filename to this powers.txt file */ void PowerManager::loadPowers(const std::string& filename) { FileParser infile; if (!infile.open(filename)) { fprintf(stderr, "Unable to open %s!\n", filename.c_str()); return; } int input_id = 0; bool skippingEntry = false; while (infile.next()) { // id needs to be the first component of each power. That is how we write // data to the correct power. if (infile.key == "id") { input_id = toInt(infile.val); skippingEntry = input_id < 1; if (skippingEntry) fprintf(stderr, "Power index out of bounds 1-%d, skipping\n", INT_MAX); if (static_cast<int>(powers.size()) < input_id + 1) powers.resize(input_id + 1); continue; } if (skippingEntry) continue; if (infile.key == "type") { if (infile.val == "fixed") powers[input_id].type = POWTYPE_FIXED; else if (infile.val == "missile") powers[input_id].type = POWTYPE_MISSILE; else if (infile.val == "repeater") powers[input_id].type = POWTYPE_REPEATER; else if (infile.val == "spawn") powers[input_id].type = POWTYPE_SPAWN; else if (infile.val == "transform") powers[input_id].type = POWTYPE_TRANSFORM; else if (infile.val == "effect") powers[input_id].type = POWTYPE_EFFECT; else fprintf(stderr, "unknown type %s\n", infile.val.c_str()); } else if (infile.key == "name") powers[input_id].name = msg->get(infile.val); else if (infile.key == "description") powers[input_id].description = msg->get(infile.val); else if (infile.key == "tag") powers[input_id].tag = infile.val; else if (infile.key == "icon") powers[input_id].icon = toInt(infile.val); else if (infile.key == "new_state") { if (infile.val == "swing") powers[input_id].new_state = POWSTATE_SWING; else if (infile.val == "shoot") powers[input_id].new_state = POWSTATE_SHOOT; else if (infile.val == "cast") powers[input_id].new_state = POWSTATE_CAST; else if (infile.val == "block") powers[input_id].new_state = POWSTATE_BLOCK; else if (infile.val == "instant") powers[input_id].new_state = POWSTATE_INSTANT; else fprintf(stderr, "unknown new_state %s\n", infile.val.c_str()); } else if (infile.key == "face") powers[input_id].face = toBool(infile.val); else if (infile.key == "source_type") { if (infile.val == "hero") powers[input_id].source_type = SOURCE_TYPE_HERO; else if (infile.val == "neutral") powers[input_id].source_type = SOURCE_TYPE_NEUTRAL; else if (infile.val == "enemy") powers[input_id].source_type = SOURCE_TYPE_ENEMY; else fprintf(stderr, "unknown source_type %s\n", infile.val.c_str()); } else if (infile.key == "beacon") powers[input_id].beacon = toBool(infile.val); else if (infile.key == "count") powers[input_id].count = toInt(infile.val); else if (infile.key == "passive") powers[input_id].passive = toBool(infile.val); else if (infile.key == "passive_trigger") { if (infile.val == "on_block") powers[input_id].passive_trigger = TRIGGER_BLOCK; else if (infile.val == "on_hit") powers[input_id].passive_trigger = TRIGGER_HIT; else if (infile.val == "on_halfdeath") powers[input_id].passive_trigger = TRIGGER_HALFDEATH; else if (infile.val == "on_joincombat") powers[input_id].passive_trigger = TRIGGER_JOINCOMBAT; else if (infile.val == "on_death") powers[input_id].passive_trigger = TRIGGER_DEATH; else fprintf(stderr, "unknown passive trigger %s\n", infile.val.c_str()); } // power requirements else if (infile.key == "requires_physical_weapon") powers[input_id].requires_physical_weapon = toBool(infile.val); else if (infile.key == "requires_mental_weapon") powers[input_id].requires_mental_weapon = toBool(infile.val); else if (infile.key == "requires_offense_weapon") powers[input_id].requires_offense_weapon = toBool(infile.val); else if (infile.key == "requires_mp") powers[input_id].requires_mp = toInt(infile.val); else if (infile.key == "requires_hp") powers[input_id].requires_hp = toInt(infile.val); else if (infile.key == "sacrifice") powers[input_id].sacrifice = toBool(infile.val); else if (infile.key == "requires_los") powers[input_id].requires_los = toBool(infile.val); else if (infile.key == "requires_empty_target") powers[input_id].requires_empty_target = toBool(infile.val); else if (infile.key == "requires_item") powers[input_id].requires_item = toInt(infile.val); else if (infile.key == "requires_equipped_item") powers[input_id].requires_equipped_item = toInt(infile.val); else if (infile.key == "requires_targeting") powers[input_id].requires_targeting = toBool(infile.val); else if (infile.key == "cooldown") powers[input_id].cooldown = parse_duration(infile.val); // animation info else if (infile.key == "animation") powers[input_id].animation_name = "animations/powers/" + infile.val; else if (infile.key == "soundfx") powers[input_id].sfx_index = loadSFX(infile.val); else if (infile.key == "directional") powers[input_id].directional = toBool(infile.val); else if (infile.key == "visual_random") powers[input_id].visual_random = toInt(infile.val); else if (infile.key == "visual_option") powers[input_id].visual_option = toInt(infile.val); else if (infile.key == "aim_assist") powers[input_id].aim_assist = toBool(infile.val); else if (infile.key == "speed") powers[input_id].speed = toInt(infile.val); else if (infile.key == "lifespan") powers[input_id].lifespan = parse_duration(infile.val); else if (infile.key == "floor") powers[input_id].floor = toBool(infile.val); else if (infile.key == "complete_animation") powers[input_id].complete_animation = toBool(infile.val); // hazard traits else if (infile.key == "use_hazard") powers[input_id].use_hazard = toBool(infile.val); else if (infile.key == "no_attack") powers[input_id].no_attack = toBool(infile.val); else if (infile.key == "radius") powers[input_id].radius = toInt(infile.val); else if (infile.key == "base_damage") { if (infile.val == "none") powers[input_id].base_damage = BASE_DAMAGE_NONE; else if (infile.val == "melee") powers[input_id].base_damage = BASE_DAMAGE_MELEE; else if (infile.val == "ranged") powers[input_id].base_damage = BASE_DAMAGE_RANGED; else if (infile.val == "ment") powers[input_id].base_damage = BASE_DAMAGE_MENT; else fprintf(stderr, "unknown base_damage %s\n", infile.val.c_str()); } else if (infile.key == "damage_multiplier") powers[input_id].damage_multiplier = toInt(infile.val); else if (infile.key == "starting_pos") { if (infile.val == "source") powers[input_id].starting_pos = STARTING_POS_SOURCE; else if (infile.val == "target") powers[input_id].starting_pos = STARTING_POS_TARGET; else if (infile.val == "melee") powers[input_id].starting_pos = STARTING_POS_MELEE; else fprintf(stderr, "unknown starting_pos %s\n", infile.val.c_str()); } else if (infile.key == "multitarget") powers[input_id].multitarget = toBool(infile.val); else if (infile.key == "trait_armor_penetration") powers[input_id].trait_armor_penetration = toBool(infile.val); else if (infile.key == "trait_crits_impaired") powers[input_id].trait_crits_impaired = toInt(infile.val); else if (infile.key == "trait_elemental") { for (unsigned int i=0; i<ELEMENTS.size(); i++) { if (infile.val == ELEMENTS[i].name) powers[input_id].trait_elemental = i; } } else if (infile.key == "range") powers[input_id].range = toInt(infile.nextValue()); //steal effects else if (infile.key == "hp_steal") powers[input_id].hp_steal = toInt(infile.val); else if (infile.key == "mp_steal") powers[input_id].mp_steal = toInt(infile.val); //missile modifiers else if (infile.key == "missile_angle") powers[input_id].missile_angle = toInt(infile.val); else if (infile.key == "angle_variance") powers[input_id].angle_variance = toInt(infile.val); else if (infile.key == "speed_variance") powers[input_id].speed_variance = toInt(infile.val); //repeater modifiers else if (infile.key == "delay") powers[input_id].delay = parse_duration(infile.val); // buff/debuff durations else if (infile.key == "transform_duration") powers[input_id].transform_duration = toInt(infile.val); else if (infile.key == "manual_untransform") powers[input_id].manual_untransform = toBool(infile.val); else if (infile.key == "keep_equipment") powers[input_id].keep_equipment = toBool(infile.val); // buffs else if (infile.key == "buff") powers[input_id].buff= toBool(infile.val); else if (infile.key == "buff_teleport") powers[input_id].buff_teleport = toBool(infile.val); else if (infile.key == "post_effect") { infile.val = infile.val + ','; PostEffect pe; pe.id = eatFirstInt(infile.val, ','); pe.magnitude = eatFirstInt(infile.val, ','); pe.duration = eatFirstInt(infile.val, ','); powers[input_id].post_effects.push_back(pe); } else if (infile.key == "effect_type") powers[input_id].effect_type = infile.val; else if (infile.key == "effect_additive") powers[input_id].effect_additive = toBool(infile.val); else if (infile.key == "effect_render_above") powers[input_id].effect_render_above = toBool(infile.val); // pre and post power effects else if (infile.key == "post_power") powers[input_id].post_power = toInt(infile.val); else if (infile.key == "wall_power") powers[input_id].wall_power = toInt(infile.val); else if (infile.key == "allow_power_mod") powers[input_id].allow_power_mod = toBool(infile.val); // spawn info else if (infile.key == "spawn_type") powers[input_id].spawn_type = infile.val; else if (infile.key == "target_neighbor") powers[input_id].target_neighbor = toInt(infile.val); else fprintf(stderr, "ignoring unknown key %s set to %s\n", infile.key.c_str(), infile.val.c_str()); } infile.close(); }
/** * Loads a given power tree and sets up the menu accordingly * * @param filename Path to the file that will be loaded */ void MenuPowers::loadPowerTree(const std::string &filename) { // only load the power tree once per instance if (tree_loaded) return; // First, parse the power tree file FileParser infile; // @CLASS MenuPowers: Power tree layout|Description of powers/trees/ if (infile.open(filename)) { while (infile.next()) { if (infile.new_section) { // for sections that are stored in collections, add a new object here if (infile.section == "power") { slots.push_back(NULL); upgradeButtons.push_back(NULL); power_cell.push_back(Power_Menu_Cell()); } else if (infile.section == "upgrade") power_cell_upgrade.push_back(Power_Menu_Cell()); else if (infile.section == "tab") tabs.push_back(Power_Menu_Tab()); } if (infile.section == "") { // @ATTR background|filename|Filename of the default background image if (infile.key == "background") default_background = infile.val; } else if (infile.section == "tab") loadTab(infile); else if (infile.section == "power") loadPower(infile); else if (infile.section == "upgrade") loadUpgrade(infile); } infile.close(); } // save a copy of the base level powers, as they get overwritten during upgrades power_cell_base = power_cell; // store the appropriate level for all upgrades for (size_t i=0; i<power_cell_upgrade.size(); ++i) { for (size_t j=0; j<power_cell_base.size(); j++) { std::vector<int>::iterator it = std::find(power_cell_base[j].upgrades.begin(), power_cell_base[j].upgrades.end(), power_cell_upgrade[i].id); if (it != power_cell_base[j].upgrades.end()) { power_cell_upgrade[i].upgrade_level = static_cast<int>(std::distance(power_cell_base[j].upgrades.begin(), it) + 2); break; } } } // combine base and upgrade powers into a single list for (size_t i=0; i<power_cell_base.size(); ++i) { power_cell_all.push_back(power_cell_base[i]); } for (size_t i=0; i<power_cell_upgrade.size(); ++i) { power_cell_all.push_back(power_cell_upgrade[i]); } // save cell indexes for required powers for (size_t i=0; i<power_cell_all.size(); ++i) { for (size_t j=0; j<power_cell_all[i].requires_power.size(); ++j) { int cell_index = getCellByPowerIndex(power_cell_all[i].requires_power[j], power_cell_all); power_cell_all[i].requires_power_cell.push_back(cell_index); } } // load any specified graphics into the tree_surf vector Image *graphics; if (tabs.empty() && default_background != "") { graphics = render_device->loadImage(default_background); if (graphics) { tree_surf.push_back(graphics->createSprite()); graphics->unref(); } } else { for (size_t i=0; i<tabs.size(); ++i) { if (tabs[i].background == "") tabs[i].background = default_background; if (tabs[i].background == "") { tree_surf.push_back(NULL); continue; } graphics = render_device->loadImage(tabs[i].background); if (graphics) { tree_surf.push_back(graphics->createSprite()); graphics->unref(); } else { tree_surf.push_back(NULL); } } } // If we have more than one tab, create tab_control if (!tabs.empty()) { tab_control = new WidgetTabControl(); if (tab_control) { // Initialize the tab control. tab_control->setMainArea(window_area.x+tab_area.x, window_area.y+tab_area.y, tab_area.w, tab_area.h); // Define the header. for (size_t i=0; i<tabs.size(); i++) tab_control->setTabTitle(static_cast<unsigned>(i), msg->get(tabs[i].title)); tab_control->updateHeader(); tablist.add(tab_control); } tablist_pow.resize(tabs.size()); } // create power slots for (size_t i=0; i<slots.size(); i++) { if (static_cast<size_t>(power_cell[i].id) < powers->powers.size()) { slots[i] = new WidgetSlot(powers->powers[power_cell[i].id].icon); slots[i]->setBasePos(power_cell[i].pos.x, power_cell[i].pos.y); if (!tablist_pow.empty()) { tablist_pow[power_cell[i].tab].add(slots[i]); tablist_pow[power_cell[i].tab].setPrevTabList(&tablist); tablist_pow[power_cell[i].tab].lock(); } else { tablist.add(slots[i]); } if (upgradeButtons[i] != NULL) { upgradeButtons[i]->setBasePos(power_cell[i].pos.x + ICON_SIZE, power_cell[i].pos.y); } } } applyPowerUpgrades(); tree_loaded = true; align(); }
bool GameStateCutscene::load(std::string filename) { FileParser infile; // @CLASS Cutscene|Description of cutscenes in cutscenes/ if (!infile.open("cutscenes/" + filename, true, false)) return false; // parse the cutscene file while (infile.next()) { if (infile.new_section) { if (infile.section == "scene") scenes.push(Scene()); } if (infile.section.empty()) { // allow having an empty section (globals such as scale_gfx might be set here } else if (infile.section == "scene") { SceneComponent sc = SceneComponent(); if (infile.key == "caption") { // @ATTR scene.caption|string|A caption that will be shown. sc.type = infile.key; sc.s = msg->get(infile.val); } else if (infile.key == "image") { // @ATTR scene.image|string|An image that will be shown. sc.type = infile.key; sc.i.setGraphics(loadImage(infile.val)); sc.i.keep_graphics = true; if (sc.i.graphicsIsNull()) sc.type = ""; } else if (infile.key == "pause") { // @ATTR scene.pause|integer|Pause before next component sc.type = infile.key; sc.x = toInt(infile.val); } else if (infile.key == "soundfx") { // @ATTR scene.soundfx|string|A sound that will be played sc.type = infile.key; sc.s = infile.val; } if (sc.type != "") scenes.back().components.push(sc); } else { fprintf(stderr, "unknown section %s in file %s\n", infile.section.c_str(), infile.getFileName().c_str()); } if (infile.key == "scale_gfx") { // @ATTR scale_gfx|bool|The graphics will be scaled to fit screen width scale_graphics = toBool(infile.val); } else if (infile.key == "caption_margins") { // @ATTR caption_margins|[x,y]|Percentage-based margins for the caption text based on screen size caption_margins.x = toFloat(infile.nextValue())/100.0f; caption_margins.y = toFloat(infile.val)/100.0f; } } if (scenes.empty()) { fprintf(stderr, "No scenes defined in cutscene file %s\n", filename.c_str()); return false; } return true; }
/** * NPCs are stored in simple config files * * @param npc_id Config file loaded at npcs/[npc_id].txt */ void NPC::load(const string& npc_id, int hero_level) { FileParser infile; ItemStack stack; string filename_portrait = ""; if (infile.open(mods->locate("npcs/" + npc_id + ".txt"))) { while (infile.next()) { if (infile.section == "dialog") { if (infile.new_section) { dialog.push_back(vector<Event_Component>()); } Event_Component e; e.type = infile.key; if (infile.key == "requires_status") e.s = infile.val; else if (infile.key == "requires_not") e.s = infile.val; else if (infile.key == "requires_level") e.x = toInt(infile.val); else if (infile.key == "requires_not_level") e.x = toInt(infile.val); else if (infile.key == "requires_item") e.x = toInt(infile.val); else if (infile.key == "him" || infile.key == "her") e.s = msg->get(infile.val); else if (infile.key == "you") e.s = msg->get(infile.val); else if (infile.key == "reward_item") { // id,count e.x = toInt(infile.nextValue()); e.y = toInt(infile.val); } else if (infile.key == "reward_xp") e.x = toInt(infile.val); else if (infile.key == "restore") e.s = infile.val; else if (infile.key == "reward_currency") e.x = toInt(infile.val); else if (infile.key == "remove_item") e.x = toInt(infile.val); else if (infile.key == "set_status") e.s = infile.val; else if (infile.key == "unset_status") e.s = infile.val; else if (infile.key == "voice") { e.x = loadSound(infile.val, NPC_VOX_QUEST); } else if (infile.key == "topic") { e.s = msg->get(infile.val); } else if (infile.key == "group") { e.s = infile.val; } dialog.back().push_back(e); } else { filename = npc_id; if (infile.key == "name") { name = msg->get(infile.val); } else if (infile.key == "level") { if (infile.val == "hero") level = hero_level; else level = toInt(infile.val); } else if (infile.key == "gfx") { gfx = infile.val; } // handle talkers else if (infile.key == "talker") { if (infile.val == "true") talker = true; } else if (infile.key == "portrait") { filename_portrait = infile.val; } // handle vendors else if (infile.key == "vendor") { if (infile.val == "true") vendor = true; } else if (infile.key == "constant_stock") { stack.quantity = 1; while (infile.val != "") { stack.item = toInt(infile.nextValue()); stock.add(stack); } } else if (infile.key == "status_stock") { if (map->camp->checkStatus(infile.nextValue())) { stack.quantity = 1; while (infile.val != "") { stack.item = toInt(infile.nextValue()); stock.add(stack); } } } // handle vocals else if (infile.key == "vox_intro") { loadSound(infile.val, NPC_VOX_INTRO); } } } infile.close(); } else fprintf(stderr, "Unable to open npcs/%s.txt!\n", npc_id.c_str()); loadGraphics(filename_portrait); }
void StatBlock::loadHeroStats() { // Redefine numbers from config file if present FileParser infile; if (!infile.open(mods->locate("engine/stats.txt"))) { fprintf(stderr, "Unable to open engine/stats.txt!\n"); return; } while (infile.next()) { int value = toInt(infile.val); if (infile.key == "max_points_per_stat") { max_points_per_stat = value; } else if (infile.key == "hp_base") { hp_base = value; } else if (infile.key == "hp_per_level") { hp_per_level = value; } else if (infile.key == "hp_per_physical") { hp_per_physical = value; } else if (infile.key == "hp_regen_base") { hp_regen_base = value; } else if (infile.key == "hp_regen_per_level") { hp_regen_per_level = value; } else if (infile.key == "hp_regen_per_physical") { hp_regen_per_physical = value; } else if (infile.key == "mp_base") { mp_base = value; } else if (infile.key == "mp_per_level") { mp_per_level = value; } else if (infile.key == "mp_per_mental") { mp_per_mental = value; } else if (infile.key == "mp_regen_base") { mp_regen_base = value; } else if (infile.key == "mp_regen_per_level") { mp_regen_per_level = value; } else if (infile.key == "mp_regen_per_mental") { mp_regen_per_mental = value; } else if (infile.key == "accuracy_base") { accuracy_base = value; } else if (infile.key == "accuracy_per_level") { accuracy_per_level = value; } else if (infile.key == "accuracy_per_offense") { accuracy_per_offense = value; } else if (infile.key == "avoidance_base") { avoidance_base = value; } else if (infile.key == "avoidance_per_level") { avoidance_per_level = value; } else if (infile.key == "avoidance_per_defense") { avoidance_per_defense = value; } else if (infile.key == "crit_base") { crit_base = value; } else if (infile.key == "crit_per_level") { crit_per_level = value; } else if (infile.key == "dmg_melee_min") { dmg_melee_min = dmg_melee_min_default = value; } else if (infile.key == "dmg_melee_max") { dmg_melee_max = dmg_melee_max_default = value; } else if (infile.key == "dmg_ranged_min") { dmg_ranged_min = dmg_ranged_min_default = value; } else if (infile.key == "dmg_ranged_max") { dmg_ranged_max = dmg_ranged_max_default = value; } else if (infile.key == "dmg_ment_min") { dmg_ment_min = dmg_ment_min_default = value; } else if (infile.key == "dmg_ment_max") { dmg_ment_max = dmg_ment_max_default = value; } else if (infile.key == "absorb_min") { absorb_min = absorb_min_default = value; } else if (infile.key == "absorb_max") { absorb_max = absorb_max_default = value; } else if (infile.key == "speed") { speed = speed_default = value; } else if (infile.key == "dspeed") { dspeed = dspeed_default = value; } else if (infile.key == "bonus_per_physical") { bonus_per_physical = value; } else if (infile.key == "bonus_per_mental") { bonus_per_mental = value; } else if (infile.key == "bonus_per_offense") { bonus_per_offense = value; } else if (infile.key == "bonus_per_defense") { bonus_per_defense = value; } else if (infile.key == "sfx_step") { sfx_step = infile.val; } else if (infile.key == "stat_points_per_level") { stat_points_per_level = value; } else if (infile.key == "power_points_per_level") { power_points_per_level = value; } else if (infile.key == "cooldown_hit") { cooldown_hit = value; } } infile.close(); if (max_points_per_stat == 0) max_points_per_stat = max_spendable_stat_points / 4 + 1; statsLoaded = true; // Load the XP table as well if (!infile.open(mods->locate("engine/xp_table.txt"))) { fprintf(stderr, "Unable to open engine/xp_table.txt!\n"); return; } while(infile.next()) { xp_table[toInt(infile.key) - 1] = toInt(infile.val); } max_spendable_stat_points = toInt(infile.key) * stat_points_per_level; infile.close(); }
/** * load a statblock, typically for an enemy definition */ void StatBlock::load(const string& filename) { FileParser infile; if (!infile.open(mods->locate(filename))) { fprintf(stderr, "Unable to open %s!\n", filename.c_str()); return; } int num = 0; string loot_token; while (infile.next()) { if (isInt(infile.val)) num = toInt(infile.val); bool valid = false; for (unsigned int i=0; i<ELEMENTS.size(); i++) { if (infile.key == "vulnerable_" + ELEMENTS[i].name) { vulnerable[i] = vulnerable_base[i] = num; valid = true; } } if (infile.key == "name") name = msg->get(infile.val); else if (infile.key == "humanoid") { if (infile.val == "true") humanoid = true; } else if (infile.key == "sfx_prefix") sfx_prefix = infile.val; else if (infile.key == "level") level = num; // enemy death rewards and events else if (infile.key == "xp") xp = num; else if (infile.key == "loot") { // loot entries format: // loot=[id],[percent_chance] // optionally allow range: // loot=[id],[percent_chance],[count_min],[count_max] EnemyLoot el; std::string loot_id = infile.nextValue(); // id 0 means currency. The keyword "currency" can also be used. if (loot_id == "currency") el.id = 0; else el.id = toInt(loot_id); el.chance = toInt(infile.nextValue()); // check for optional range. loot_token = infile.nextValue(); if (loot_token != "") { el.count_min = toInt(loot_token); el.count_max = el.count_min; } loot_token = infile.nextValue(); if (loot_token != "") { el.count_max = toInt(loot_token); } loot.push_back(el); } else if (infile.key == "defeat_status") defeat_status = infile.val; else if (infile.key == "first_defeat_loot") first_defeat_loot = num; else if (infile.key == "quest_loot") { quest_loot_requires = infile.nextValue(); quest_loot_not = infile.nextValue(); quest_loot_id = toInt(infile.nextValue()); } // combat stats else if (infile.key == "hp") hp = hp_base = maxhp = num; else if (infile.key == "mp") mp = mp_base = maxmp = num; else if (infile.key == "cooldown") cooldown = parse_duration(infile.val); else if (infile.key == "accuracy") accuracy = accuracy_base = num; else if (infile.key == "avoidance") avoidance = avoidance_base = num; else if (infile.key == "dmg_melee_min") dmg_melee_min = num; else if (infile.key == "dmg_melee_max") dmg_melee_max = num; else if (infile.key == "dmg_ment_min") dmg_ment_min = num; else if (infile.key == "dmg_ment_max") dmg_ment_max = num; else if (infile.key == "dmg_ranged_min") dmg_ranged_min = num; else if (infile.key == "dmg_ranged_max") dmg_ranged_max = num; else if (infile.key == "absorb_min") absorb_min = num; else if (infile.key == "absorb_max") absorb_max = num; else if (infile.key == "poise") poise = poise_base = num; // behavior stats else if (infile.key == "flying") { if (num == 1) flying = true; } else if (infile.key == "intangible") { if (num == 1) intangible = true; } else if (infile.key == "facing") { if (num == 0) facing = false; } else if (infile.key == "waypoint_pause") waypoint_pause = num; else if (infile.key == "speed") speed = speed_default = num; else if (infile.key == "dspeed") dspeed = dspeed_default = num; else if (infile.key == "turn_delay") turn_delay = num; else if (infile.key == "chance_pursue") chance_pursue = num; else if (infile.key == "chance_flee") chance_flee = num; else if (infile.key == "chance_melee_phys") power_chance[MELEE_PHYS] = num; else if (infile.key == "chance_melee_ment") power_chance[MELEE_MENT] = num; else if (infile.key == "chance_ranged_phys") power_chance[RANGED_PHYS] = num; else if (infile.key == "chance_ranged_ment") power_chance[RANGED_MENT] = num; else if (infile.key == "power_melee_phys") power_index[MELEE_PHYS] = num; else if (infile.key == "power_melee_ment") power_index[MELEE_MENT] = num; else if (infile.key == "power_ranged_phys") power_index[RANGED_PHYS] = num; else if (infile.key == "power_ranged_ment") power_index[RANGED_MENT] = num; else if (infile.key == "power_beacon") power_index[BEACON] = num; else if (infile.key == "cooldown_melee_phys") power_cooldown[MELEE_PHYS] = parse_duration(infile.val); else if (infile.key == "cooldown_melee_ment") power_cooldown[MELEE_MENT] = parse_duration(infile.val); else if (infile.key == "cooldown_ranged_phys") power_cooldown[RANGED_PHYS] = parse_duration(infile.val); else if (infile.key == "cooldown_ranged_ment") power_cooldown[RANGED_MENT] = parse_duration(infile.val); else if (infile.key == "power_on_hit") power_index[ON_HIT] = num; else if (infile.key == "power_on_death") power_index[ON_DEATH] = num; else if (infile.key == "power_on_half_dead") power_index[ON_HALF_DEAD] = num; else if (infile.key == "power_on_debuff") power_index[ON_DEBUFF] = num; else if (infile.key == "power_on_join_combat") power_index[ON_JOIN_COMBAT] = num; else if (infile.key == "chance_on_hit") power_chance[ON_HIT] = num; else if (infile.key == "chance_on_death") power_chance[ON_DEATH] = num; else if (infile.key == "chance_on_half_dead") power_chance[ON_HALF_DEAD] = num; else if (infile.key == "chance_on_debuff") power_chance[ON_DEBUFF] = num; else if (infile.key == "chance_on_join_combat") power_chance[ON_JOIN_COMBAT] = num; else if (infile.key == "cooldown_hit") cooldown_hit = num; else if (infile.key == "passive_powers") { std::string p = infile.nextValue(); while (p != "") { powers_passive.push_back(toInt(p)); p = infile.nextValue(); } } else if (infile.key == "melee_range") melee_range = num; else if (infile.key == "threat_range") threat_range = num; // animation stats else if (infile.key == "melee_weapon_power") melee_weapon_power = num; else if (infile.key == "mental_weapon_power") mental_weapon_power = num; else if (infile.key == "ranged_weapon_power") ranged_weapon_power = num; else if (infile.key == "animations") animations = infile.val; // hide enemy HP bar else if (infile.key == "suppress_hp") { if (num == 1) suppress_hp = true; else suppress_hp = false; } // these are only used for EnemyGroupManager // we check for them here so that we don't get an error saying they are invalid else if (infile.key == "categories") valid = true; else if (infile.key == "rarity") valid = true; else if (!valid) { fprintf(stderr, "%s=%s not a valid StatBlock parameter\n", infile.key.c_str(), infile.val.c_str()); } } infile.close(); // sort loot table std::sort(loot.begin(), loot.end(), sortLoot); }
void AnimationSet::load() { assert(!loaded); loaded = true; FileParser parser; // @CLASS AnimationSet|Description of animations in animations/ if (!parser.open(name, true, "Error loading animation definition: " + name)) return; std::string _name = ""; unsigned short position = 0; unsigned short frames = 0; unsigned short duration = 0; Point render_size; Point render_offset; std::string type = ""; std::string starting_animation = ""; bool first_section=true; bool compressed_loading=false; // is reset every section to false, set by frame keyword Animation *newanim = NULL; std::vector<short> active_frames; unsigned short parent_anim_frames = 0; // Parse the file and on each new section create an animation object from the data parsed previously while (parser.next()) { // create the animation if finished parsing a section if (parser.new_section) { if (!first_section && !compressed_loading) { Animation *a = new Animation(_name, type, sprite); a->setupUncompressed(render_size, render_offset, position, frames, duration); if (!active_frames.empty()) a->setActiveFrames(active_frames); active_frames.clear(); animations.push_back(a); } first_section = false; compressed_loading = false; if (parent) { parent_anim_frames = static_cast<unsigned short>(parent->getAnimationFrames(parser.section)); } } if (parser.key == "image") { // @ATTR image|filename|Filename of sprite-sheet image. if (sprite != NULL) { parser.error("AnimationSet: Multiple images specified. Dragons be here!"); Exit(128); } sprite = render_device->loadImage(parser.val); } else if (parser.key == "position") { // @ATTR position|int|Number of frames to the right to use as the first frame. Unpacked animations only. position = static_cast<unsigned short>(toInt(parser.val)); } else if (parser.key == "frames") { // @ATTR frames|int|The total number of frames frames = static_cast<unsigned short>(toInt(parser.val)); if (parent && frames != parent_anim_frames) { parser.error("AnimationSet: Frame count %d != %d for matching animation in %s", frames, parent_anim_frames, parent->getName().c_str()); frames = parent_anim_frames; } } else if (parser.key == "duration") { // @ATTR duration|duration|The duration of the entire animation in 'ms' or 's'. duration = static_cast<unsigned short>(parse_duration(parser.val)); } else if (parser.key == "type") // @ATTR type|["play_once", "back_forth", "looped"]|How to loop (or not loop) this animation. type = parser.val; else if (parser.key == "render_size") { // @ATTR render_size|int, int : Width, Height|Width and height of animation. render_size.x = toInt(parser.nextValue()); render_size.y = toInt(parser.nextValue()); } else if (parser.key == "render_offset") { // @ATTR render_offset|int, int : X offset, Y offset|Render x/y offset. render_offset.x = toInt(parser.nextValue()); render_offset.y = toInt(parser.nextValue()); } else if (parser.key == "active_frame") { // @ATTR active_frame|[list(int), "all"]|A list of frames marked as "active". Also, "all" can be used to mark all frames as active. active_frames.clear(); std::string nv = parser.nextValue(); if (nv == "all") { active_frames.push_back(-1); } else { while (nv != "") { active_frames.push_back(static_cast<short>(toInt(nv))); nv = parser.nextValue(); } std::sort(active_frames.begin(), active_frames.end()); active_frames.erase(std::unique(active_frames.begin(), active_frames.end()), active_frames.end()); } } else if (parser.key == "frame") { // @ATTR frame|int, int, int, int, int, int, int, int : Index, Direction, X, Y, Width, Height, X offset, Y offset|A single frame of a compressed animation. if (compressed_loading == false) { // first frame statement in section newanim = new Animation(_name, type, sprite); newanim->setup(frames, duration); if (!active_frames.empty()) newanim->setActiveFrames(active_frames); active_frames.clear(); animations.push_back(newanim); compressed_loading = true; } // frame = index, direction, x, y, w, h, offsetx, offsety Rect r; Point offset; const unsigned short index = static_cast<unsigned short>(toInt(parser.nextValue())); const unsigned short direction = static_cast<unsigned short>(toInt(parser.nextValue())); r.x = toInt(parser.nextValue()); r.y = toInt(parser.nextValue()); r.w = toInt(parser.nextValue()); r.h = toInt(parser.nextValue()); offset.x = toInt(parser.nextValue()); offset.y = toInt(parser.nextValue()); newanim->addFrame(index, direction, r, offset); } else { parser.error("AnimationSet: '%s' is not a valid key.", parser.key.c_str()); } if (_name == "") { // This is the first animation starting_animation = parser.section; } _name = parser.section; } parser.close(); if (!compressed_loading) { // add final animation Animation *a = new Animation(_name, type, sprite); a->setupUncompressed(render_size, render_offset, position, frames, duration); if (!active_frames.empty()) a->setActiveFrames(active_frames); active_frames.clear(); animations.push_back(a); } if (starting_animation != "") { Animation *a = getAnimation(starting_animation); delete defaultAnimation; defaultAnimation = a; } }
/** * load a statblock, typically for an enemy definition */ void StatBlock::load(const std::string& filename) { // @CLASS StatBlock: Enemies|Description of enemies in enemies/ FileParser infile; if (!infile.open(filename)) return; bool clear_loot = true; while (infile.next()) { if (infile.new_section) { // APPENDed file clear_loot = true; } int num = toInt(infile.val); float fnum = toFloat(infile.val); bool valid = loadCoreStat(&infile) || loadSfxStat(&infile); // @ATTR name|string|Name if (infile.key == "name") name = msg->get(infile.val); // @ATTR humanoid|boolean|This creature gives human traits when transformed into, such as the ability to talk with NPCs. else if (infile.key == "humanoid") humanoid = toBool(infile.val); // @ATTR level|integer|Level else if (infile.key == "level") level = num; // enemy death rewards and events // @ATTR xp|integer|XP awarded upon death. else if (infile.key == "xp") xp = num; else if (infile.key == "loot") { // @ATTR loot|[currency:item (integer)], chance (integer), min (integer), max (integer)|Possible loot that can be dropped on death. // loot entries format: // loot=[id],[percent_chance] // optionally allow range: // loot=[id],[percent_chance],[count_min],[count_max] if (clear_loot) { loot_table.clear(); clear_loot = false; } loot_table.push_back(Event_Component()); loot->parseLoot(infile, &loot_table.back(), &loot_table); } // @ATTR defeat_status|string|Campaign status to set upon death. else if (infile.key == "defeat_status") defeat_status = infile.val; // @ATTR convert_status|string|Campaign status to set upon being converted to a player ally. else if (infile.key == "convert_status") convert_status = infile.val; // @ATTR first_defeat_loot|integer|Drops this item upon first death. else if (infile.key == "first_defeat_loot") first_defeat_loot = num; // @ATTR quest_loot|[requires status (string), requires not status (string), item (integer)|Drops this item when campaign status is met. else if (infile.key == "quest_loot") { quest_loot_requires_status = infile.nextValue(); quest_loot_requires_not_status = infile.nextValue(); quest_loot_id = toInt(infile.nextValue()); } // combat stats // @ATTR cooldown|integer|Cooldown between attacks in 'ms' or 's'. else if (infile.key == "cooldown") cooldown = parse_duration(infile.val); // behavior stats // @ATTR flying|boolean|Creature can move over gaps/water. else if (infile.key == "flying") flying = toBool(infile.val); // @ATTR intangible|boolean|Creature can move through walls. else if (infile.key == "intangible") intangible = toBool(infile.val); // @ATTR facing|boolean|Creature can turn to face their target. else if (infile.key == "facing") facing = toBool(infile.val); // @ATTR waypoint_pause|duration|Duration to wait at each waypoint in 'ms' or 's'. else if (infile.key == "waypoint_pause") waypoint_pause = parse_duration(infile.val); // @ATTR turn_delay|duration|Duration it takes for this creature to turn and face their target in 'ms' or 's'. else if (infile.key == "turn_delay") turn_delay = parse_duration(infile.val); // @ATTR chance_pursue|integer|Percentage change that the creature will chase their target. else if (infile.key == "chance_pursue") chance_pursue = num; // @ATTR chance_flee|integer|Percentage chance that the creature will run away from their target. else if (infile.key == "chance_flee") chance_flee = num; // @ATTR chance_melee_phys|integer|Percentage chance that the creature will use their physical melee power. else if (infile.key == "chance_melee_phys") power_chance[MELEE_PHYS] = num; // @ATTR chance_melee_ment|integer|Percentage chance that the creature will use their mental melee power. else if (infile.key == "chance_melee_ment") power_chance[MELEE_MENT] = num; // @ATTR chance_ranged_phys|integer|Percentage chance that the creature will use their physical ranged power. else if (infile.key == "chance_ranged_phys") power_chance[RANGED_PHYS] = num; // @ATTR chance_ranged_ment|integer|Percentage chance that the creature will use their mental ranged power. else if (infile.key == "chance_ranged_ment") power_chance[RANGED_MENT] = num; // @ATTR power_melee_phys|integer|Power index for the physical melee power. else if (infile.key == "power_melee_phys") power_index[MELEE_PHYS] = num; // @ATTR power_melee_ment|integer|Power index for the mental melee power. else if (infile.key == "power_melee_ment") power_index[MELEE_MENT] = num; // @ATTR power_ranged_phys|integer|Power index for the physical ranged power. else if (infile.key == "power_ranged_phys") power_index[RANGED_PHYS] = num; // @ATTR power_ranged_ment|integer|Power index for the mental ranged power. else if (infile.key == "power_ranged_ment") power_index[RANGED_MENT] = num; // @ATTR power_beacon|integer|Power index of a "beacon" power used to aggro nearby creatures. else if (infile.key == "power_beacon") power_index[BEACON] = num; // @ATTR power_on_hit|integer|Power index that is triggered when hit. else if (infile.key == "power_on_hit") power_index[ON_HIT] = num; // @ATTR power_on_death|integer|Power index that is triggered when dead. else if (infile.key == "power_on_death") power_index[ON_DEATH] = num; // @ATTR power_on_half_dead|integer|Power index that is triggered when at half health. else if (infile.key == "power_on_half_dead") power_index[ON_HALF_DEAD] = num; // @ATTR power_on_debuff|integer|Power index that is triggered when under a negative status effect. else if (infile.key == "power_on_debuff") power_index[ON_DEBUFF] = num; // @ATTR power_on_join_combat|integer|Power index that is triggered when initiating combat. else if (infile.key == "power_on_join_combat") power_index[ON_JOIN_COMBAT] = num; // @ATTR chance_on_hit|integer|Percentage chance that power_on_hit will be triggered. else if (infile.key == "chance_on_hit") power_chance[ON_HIT] = num; // @ATTR chance_on_death|integer|Percentage chance that power_on_death will be triggered. else if (infile.key == "chance_on_death") power_chance[ON_DEATH] = num; // @ATTR chance_on_half_dead|integer|Percentage chance that power_on_half_dead will be triggered. else if (infile.key == "chance_on_half_dead") power_chance[ON_HALF_DEAD] = num; // @ATTR chance_on_debuff|integer|Percentage chance that power_on_debuff will be triggered. else if (infile.key == "chance_on_debuff") power_chance[ON_DEBUFF] = num; // @ATTR chance_on_join_combat|integer|Percentage chance that power_on_join_combat will be triggered. else if (infile.key == "chance_on_join_combat") power_chance[ON_JOIN_COMBAT] = num; // @ATTR cooldown_hit|duration|Duration of cooldown after being hit in 'ms' or 's'. else if (infile.key == "cooldown_hit") cooldown_hit = parse_duration(infile.val); else if (infile.key == "passive_powers") { // @ATTR passive_powers|power (integer), ...|A list of passive powers this creature has. powers_passive.clear(); std::string p = infile.nextValue(); while (p != "") { powers_passive.push_back(toInt(p)); p = infile.nextValue(); } } // @ATTR melee_range|float|Minimum distance from target required to use melee powers. else if (infile.key == "melee_range") melee_range = fnum; // @ATTR threat_range|float|Radius of the area this creature will be able to start chasing the hero. else if (infile.key == "threat_range") threat_range = fnum; // @ATTR combat_style|[default:aggressive:passive]|How the creature will enter combat. Default is within range of the hero; Aggressive is always in combat; Passive must be attacked to enter combat. else if (infile.key == "combat_style") { if (infile.val == "default") combat_style = COMBAT_DEFAULT; else if (infile.val == "aggressive") combat_style = COMBAT_AGGRESSIVE; else if (infile.val == "passive") combat_style = COMBAT_PASSIVE; else infile.error("StatBlock: Unknown combat style '%s'", infile.val.c_str()); } // @ATTR animations|string|Filename of an animation definition. else if (infile.key == "animations") animations = infile.val; // @ATTR suppress_hp|boolean|Hides the enemy HP bar for this creature. else if (infile.key == "suppress_hp") suppress_hp = toBool(infile.val); else if (infile.key == "categories") { // @ATTR categories|category (string), ...|Categories that this enemy belongs to. categories.clear(); std::string cat; while ((cat = infile.nextValue()) != "") { categories.push_back(cat); } } // this is only used for EnemyGroupManager // we check for them here so that we don't get an error saying they are invalid else if (infile.key == "rarity") ; // but do nothing else if (!valid) { infile.error("StatBlock: '%s' is not a valid key.", infile.key.c_str()); } } infile.close(); hp = starting[STAT_HP_MAX]; mp = starting[STAT_MP_MAX]; applyEffects(); }
/** * When loading the game, load from file if possible */ void GameStatePlay::loadGame() { int saved_hp = 0; int saved_mp = 0; int currency = 0; // game slots are currently 1-4 if (game_slot == 0) return; FileParser infile; int hotkeys[12]; for (int i=0; i<12; i++) { hotkeys[i] = -1; } stringstream ss; ss.str(""); ss << PATH_USER; if (GAME_PREFIX.length() > 0) ss << GAME_PREFIX << "_"; ss << "save" << game_slot << ".txt"; if (infile.open(ss.str(), false)) { while (infile.next()) { if (infile.key == "name") pc->stats.name = infile.val; else if (infile.key == "permadeath") { pc->stats.permadeath = toBool(infile.val); } else if (infile.key == "option") { pc->stats.gfx_base = infile.nextValue(); pc->stats.gfx_head = infile.nextValue(); pc->stats.gfx_portrait = infile.nextValue(); } else if (infile.key == "class") { pc->stats.character_class = infile.nextValue(); } else if (infile.key == "xp") { pc->stats.xp = toUnsignedLong(infile.val); } else if (infile.key == "hpmp") { saved_hp = toInt(infile.nextValue()); saved_mp = toInt(infile.nextValue()); } else if (infile.key == "build") { pc->stats.physical_character = toInt(infile.nextValue()); pc->stats.mental_character = toInt(infile.nextValue()); pc->stats.offense_character = toInt(infile.nextValue()); pc->stats.defense_character = toInt(infile.nextValue()); if (pc->stats.physical_character < 0 || pc->stats.physical_character > pc->stats.max_points_per_stat || pc->stats.mental_character < 0 || pc->stats.mental_character > pc->stats.max_points_per_stat || pc->stats.offense_character < 0 || pc->stats.offense_character > pc->stats.max_points_per_stat || pc->stats.defense_character < 0 || pc->stats.defense_character > pc->stats.max_points_per_stat) { fprintf(stderr, "Some basic stats are out of bounds, setting to zero\n"); pc->stats.physical_character = 0; pc->stats.mental_character = 0; pc->stats.offense_character = 0; pc->stats.defense_character = 0; } } else if (infile.key == "currency") { currency = toInt(infile.val); } else if (infile.key == "equipped") { menu->inv->inventory[EQUIPMENT].setItems(infile.val); } else if (infile.key == "equipped_quantity") { menu->inv->inventory[EQUIPMENT].setQuantities(infile.val); } else if (infile.key == "carried") { menu->inv->inventory[CARRIED].setItems(infile.val); } else if (infile.key == "carried_quantity") { menu->inv->inventory[CARRIED].setQuantities(infile.val); } else if (infile.key == "spawn") { mapr->teleport_mapname = infile.nextValue(); if (fileExists(mods->locate(mapr->teleport_mapname))) { mapr->teleport_destination.x = toInt(infile.nextValue()) + 0.5f; mapr->teleport_destination.y = toInt(infile.nextValue()) + 0.5f; mapr->teleportation = true; // prevent spawn.txt from putting us on the starting map mapr->clearEvents(); } else { fprintf(stderr, "Unable to find %s, loading maps/spawn.txt\n", mapr->teleport_mapname.c_str()); mapr->teleport_mapname = "maps/spawn.txt"; mapr->teleport_destination.x = 1; mapr->teleport_destination.y = 1; mapr->teleportation = true; } } else if (infile.key == "actionbar") { for (int i=0; i<12; i++) { hotkeys[i] = toInt(infile.nextValue()); if (hotkeys[i] < 0) { fprintf(stderr, "Hotkey power on position %d has negative id, skipping\n", i); hotkeys[i] = 0; } else if ((unsigned)hotkeys[i] > powers->powers.size()-1) { fprintf(stderr, "Hotkey power id (%d) out of bounds 1-%d, skipping\n", hotkeys[i], (int)powers->powers.size()); hotkeys[i] = 0; } else if (hotkeys[i] != 0 && powers->powers[hotkeys[i]].name == "") { fprintf(stderr, "Hotkey power with id=%d, found on position %d does not exist, skipping\n", hotkeys[i], i); hotkeys[i] = 0; } } menu->act->set(hotkeys); } else if (infile.key == "transformed") { pc->stats.transform_type = infile.nextValue(); if (pc->stats.transform_type != "") { pc->stats.transform_duration = -1; pc->stats.manual_untransform = toBool(infile.nextValue()); } } else if (infile.key == "powers") { string power; while ( (power = infile.nextValue()) != "") { if (toInt(power) > 0) pc->stats.powers_list.push_back(toInt(power)); } } else if (infile.key == "campaign") camp->setAll(infile.val); } infile.close(); } else fprintf(stderr, "Unable to open %s!\n", ss.str().c_str()); menu->inv->fillEquipmentSlots(); menu->inv->addCurrency(currency); // remove items with zero quantity from inventory menu->inv->inventory[EQUIPMENT].clean(); menu->inv->inventory[CARRIED].clean(); // Load stash loadStash(); // initialize vars pc->stats.recalc(); menu->inv->applyEquipment(menu->inv->inventory[EQUIPMENT].storage); // trigger passive effects here? Saved HP/MP values might depend on passively boosted HP/MP // powers->activatePassives(pc->stats); pc->stats.logic(); // run stat logic once to apply items bonuses if (SAVE_HPMP) { if (saved_hp < 0 || saved_hp > pc->stats.get(STAT_HP_MAX)) { fprintf(stderr, "HP value is out of bounds, setting to maximum\n"); pc->stats.hp = pc->stats.get(STAT_HP_MAX); } else pc->stats.hp = saved_hp; if (saved_mp < 0 || saved_mp > pc->stats.get(STAT_MP_MAX)) { fprintf(stderr, "MP value is out of bounds, setting to maximum\n"); pc->stats.mp = pc->stats.get(STAT_MP_MAX); } else pc->stats.mp = saved_mp; } else { pc->stats.hp = pc->stats.get(STAT_HP_MAX); pc->stats.mp = pc->stats.get(STAT_MP_MAX); } // reset character menu menu->chr->refreshStats(); // just for aesthetics, turn the hero to face the camera pc->stats.direction = 6; // set up MenuTalker for this hero menu->talker->setHero(pc->stats.name, pc->stats.character_class, pc->stats.gfx_portrait); // load sounds (gender specific) pc->loadSounds(); // apply power upgrades menu->pow->applyPowerUpgrades(); }
void GameStateConfig::readConfig () { //Load the menu configuration from file int offset_x = 0; int offset_y = 0; FileParser infile; if (infile.open("menus/config.txt")) { while (infile.next()) { infile.val = infile.val + ','; int x1 = eatFirstInt(infile.val, ','); int y1 = eatFirstInt(infile.val, ','); int x2 = eatFirstInt(infile.val, ','); int y2 = eatFirstInt(infile.val, ','); int setting_num = -1; if (infile.key == "listbox_scrollbar_offset") { activemods_lstb->scrollbar_offset = x1; inactivemods_lstb->scrollbar_offset = x1; joystick_device_lstb->scrollbar_offset = x1; resolution_lstb->scrollbar_offset = x1; language_lstb->scrollbar_offset = x1; } //checkboxes else if (infile.key == "fullscreen") { placeLabeledCheckbox( fullscreen_lb, fullscreen_cb, x1, y1, x2, y2, msg->get("Full Screen Mode"), 0); } else if (infile.key == "mouse_move") { placeLabeledCheckbox( mouse_move_lb, mouse_move_cb, x1, y1, x2, y2, msg->get("Move hero using mouse"), 3); } else if (infile.key == "combat_text") { placeLabeledCheckbox( combat_text_lb, combat_text_cb, x1, y1, x2, y2, msg->get("Show combat text"), 2); } else if (infile.key == "hwsurface") { placeLabeledCheckbox( hwsurface_lb, hwsurface_cb, x1, y1, x2, y2, msg->get("Hardware surfaces"), 0); } else if (infile.key == "doublebuf") { placeLabeledCheckbox( doublebuf_lb, doublebuf_cb, x1, y1, x2, y2, msg->get("Double buffering"), 0); } else if (infile.key == "enable_joystick") { placeLabeledCheckbox( enable_joystick_lb, enable_joystick_cb, x1, y1, x2, y2, msg->get("Use joystick"), 3); } else if (infile.key == "texture_quality") { placeLabeledCheckbox( texture_quality_lb, texture_quality_cb, x1, y1, x2, y2, msg->get("High Quality Textures"), 0); } else if (infile.key == "change_gamma") { placeLabeledCheckbox( change_gamma_lb, change_gamma_cb, x1, y1, x2, y2, msg->get("Allow changing gamma"), 0); } else if (infile.key == "animated_tiles") { placeLabeledCheckbox( animated_tiles_lb, animated_tiles_cb, x1, y1, x2, y2, msg->get("Animated tiles"), 0); } else if (infile.key == "mouse_aim") { placeLabeledCheckbox( mouse_aim_lb, mouse_aim_cb, x1, y1, x2, y2, msg->get("Mouse aim"), 3); } else if (infile.key == "no_mouse") { placeLabeledCheckbox( no_mouse_lb, no_mouse_cb, x1, y1, x2, y2, msg->get("Do not use mouse"), 3); } else if (infile.key == "show_fps") { placeLabeledCheckbox( show_fps_lb, show_fps_cb, x1, y1, x2, y2, msg->get("Show FPS"), 2); } else if (infile.key == "show_hotkeys") { placeLabeledCheckbox( show_hotkeys_lb, show_hotkeys_cb, x1, y1, x2, y2, msg->get("Show Hotkeys Labels"), 2); } else if (infile.key == "colorblind") { placeLabeledCheckbox( colorblind_lb, colorblind_cb, x1, y1, x2, y2, msg->get("Colorblind Mode"), 2); } //sliders else if (infile.key == "music_volume") { music_volume_sl->pos.x = frame.x + x2; music_volume_sl->pos.y = frame.y + y2; child_widget.push_back(music_volume_sl); optiontab[child_widget.size()-1] = 1; music_volume_lb->setX(frame.x + x1); music_volume_lb->setY(frame.y + y1); music_volume_lb->set(msg->get("Music Volume")); music_volume_lb->setJustify(JUSTIFY_RIGHT); child_widget.push_back(music_volume_lb); optiontab[child_widget.size()-1] = 1; } else if (infile.key == "sound_volume") { sound_volume_sl->pos.x = frame.x + x2; sound_volume_sl->pos.y = frame.y + y2; child_widget.push_back(sound_volume_sl); optiontab[child_widget.size()-1] = 1; sound_volume_lb->setX(frame.x + x1); sound_volume_lb->setY(frame.y + y1); sound_volume_lb->set(msg->get("Sound Volume")); sound_volume_lb->setJustify(JUSTIFY_RIGHT); child_widget.push_back(sound_volume_lb); optiontab[child_widget.size()-1] = 1; } else if (infile.key == "gamma") { gamma_sl->pos.x = frame.x + x2; gamma_sl->pos.y = frame.y + y2; child_widget.push_back(gamma_sl); optiontab[child_widget.size()-1] = 0; gamma_lb->setX(frame.x + x1); gamma_lb->setY(frame.y + y1); gamma_lb->set(msg->get("Gamma")); gamma_lb->setJustify(JUSTIFY_RIGHT); child_widget.push_back(gamma_lb); optiontab[child_widget.size()-1] = 0; } else if (infile.key == "joystick_deadzone") { joystick_deadzone_sl->pos.x = frame.x + x2; joystick_deadzone_sl->pos.y = frame.y + y2; child_widget.push_back(joystick_deadzone_sl); optiontab[child_widget.size()-1] = 3; joystick_deadzone_lb->setX(frame.x + x1); joystick_deadzone_lb->setY(frame.y + y1); joystick_deadzone_lb->set(msg->get("Joystick Deadzone")); joystick_deadzone_lb->setJustify(JUSTIFY_RIGHT); child_widget.push_back(joystick_deadzone_lb); optiontab[child_widget.size()-1] = 3; } //listboxes else if (infile.key == "resolution") { resolution_lstb->pos.x = frame.x + x2; resolution_lstb->pos.y = frame.y + y2; child_widget.push_back(resolution_lstb); optiontab[child_widget.size()-1] = 0; resolution_lb->setX(frame.x + x1); resolution_lb->setY(frame.y + y1); resolution_lb->set(msg->get("Resolution")); child_widget.push_back(resolution_lb); optiontab[child_widget.size()-1] = 0; } else if (infile.key == "activemods") { activemods_lstb->pos.x = frame.x + x2; activemods_lstb->pos.y = frame.y + y2; activemods_lb->setX(frame.x + x1); activemods_lb->setY(frame.y + y1); activemods_lb->set(msg->get("Active Mods")); child_widget.push_back(activemods_lb); optiontab[child_widget.size()-1] = 5; } else if (infile.key == "inactivemods") { inactivemods_lstb->pos.x = frame.x + x2; inactivemods_lstb->pos.y = frame.y + y2; inactivemods_lb->setX(frame.x + x1); inactivemods_lb->setY(frame.y + y1); inactivemods_lb->set(msg->get("Available Mods")); child_widget.push_back(inactivemods_lb); optiontab[child_widget.size()-1] = 5; } else if (infile.key == "joystick_device") { joystick_device_lstb->pos.x = frame.x + x2; joystick_device_lstb->pos.y = frame.y + y2; for(int i = 0; i < SDL_NumJoysticks(); i++) { if (SDL_JoystickName(i) != NULL) joystick_device_lstb->append(SDL_JoystickName(i),SDL_JoystickName(i)); } child_widget.push_back(joystick_device_lstb); optiontab[child_widget.size()-1] = 3; joystick_device_lb->setX(frame.x + x1); joystick_device_lb->setY(frame.y + y1); joystick_device_lb->set(msg->get("Joystick")); child_widget.push_back(joystick_device_lb); optiontab[child_widget.size()-1] = 3; } else if (infile.key == "language") { language_lstb->pos.x = frame.x + x2; language_lstb->pos.y = frame.y + y2; child_widget.push_back(language_lstb); optiontab[child_widget.size()-1] = 2; language_lb->setX(frame.x + x1); language_lb->setY(frame.y + y1); language_lb->set(msg->get("Language")); child_widget.push_back(language_lb); optiontab[child_widget.size()-1] = 2; } // buttons begin else if (infile.key == "cancel") setting_num = CANCEL; else if (infile.key == "accept") setting_num = ACCEPT; else if (infile.key == "up") setting_num = UP; else if (infile.key == "down") setting_num = DOWN; else if (infile.key == "left") setting_num = LEFT; else if (infile.key == "right") setting_num = RIGHT; else if (infile.key == "bar1") setting_num = BAR_1; else if (infile.key == "bar2") setting_num = BAR_2; else if (infile.key == "bar3") setting_num = BAR_3; else if (infile.key == "bar4") setting_num = BAR_4; else if (infile.key == "bar5") setting_num = BAR_5; else if (infile.key == "bar6") setting_num = BAR_6; else if (infile.key == "bar7") setting_num = BAR_7; else if (infile.key == "bar8") setting_num = BAR_8; else if (infile.key == "bar9") setting_num = BAR_9; else if (infile.key == "bar0") setting_num = BAR_0; else if (infile.key == "main1") setting_num = MAIN1; else if (infile.key == "main2") setting_num = MAIN2; else if (infile.key == "character") setting_num = CHARACTER; else if (infile.key == "inventory") setting_num = INVENTORY; else if (infile.key == "powers") setting_num = POWERS; else if (infile.key == "log") setting_num = LOG; else if (infile.key == "ctrl") setting_num = CTRL; else if (infile.key == "shift") setting_num = SHIFT; else if (infile.key == "delete") setting_num = DEL; else if (infile.key == "actionbar") setting_num = ACTIONBAR; else if (infile.key == "actionbar_back") setting_num = ACTIONBAR_BACK; else if (infile.key == "actionbar_forward") setting_num = ACTIONBAR_FORWARD; else if (infile.key == "actionbar_use") setting_num = ACTIONBAR_USE; // buttons end else if (infile.key == "hws_note") { hws_note_lb->setX(frame.x + x1); hws_note_lb->setY(frame.y + y1); hws_note_lb->set(msg->get("Disable for performance")); child_widget.push_back(hws_note_lb); optiontab[child_widget.size()-1] = 0; } else if (infile.key == "dbuf_note") { dbuf_note_lb->setX(frame.x + x1); dbuf_note_lb->setY(frame.y + y1); dbuf_note_lb->set(msg->get("Disable for performance")); child_widget.push_back(dbuf_note_lb); optiontab[child_widget.size()-1] = 0; } else if (infile.key == "anim_tiles_note") { anim_tiles_note_lb->setX(frame.x + x1); anim_tiles_note_lb->setY(frame.y + y1); anim_tiles_note_lb->set(msg->get("Disable for performance")); child_widget.push_back(anim_tiles_note_lb); optiontab[child_widget.size()-1] = 0; } else if (infile.key == "test_note") { test_note_lb->setX(frame.x + x1); test_note_lb->setY(frame.y + y1); test_note_lb->set(msg->get("Experimental")); child_widget.push_back(test_note_lb); optiontab[child_widget.size()-1] = 0; } else if (infile.key == "handheld_note") { handheld_note_lb->setX(frame.x + x1); handheld_note_lb->setY(frame.y + y1); handheld_note_lb->set(msg->get("For handheld devices")); child_widget.push_back(handheld_note_lb); optiontab[child_widget.size()-1] = 3; } //buttons else if (infile.key == "activemods_shiftup") { activemods_shiftup_btn->pos.x = frame.x + x1; activemods_shiftup_btn->pos.y = frame.y + y1; activemods_shiftup_btn->refresh(); child_widget.push_back(activemods_shiftup_btn); optiontab[child_widget.size()-1] = 5; } else if (infile.key == "activemods_shiftdown") { activemods_shiftdown_btn->pos.x = frame.x + x1; activemods_shiftdown_btn->pos.y = frame.y + y1; activemods_shiftdown_btn->refresh(); child_widget.push_back(activemods_shiftdown_btn); optiontab[child_widget.size()-1] = 5; } else if (infile.key == "activemods_deactivate") { activemods_deactivate_btn->label = msg->get("<< Disable"); activemods_deactivate_btn->pos.x = frame.x + x1; activemods_deactivate_btn->pos.y = frame.y + y1; activemods_deactivate_btn->refresh(); child_widget.push_back(activemods_deactivate_btn); optiontab[child_widget.size()-1] = 5; } else if (infile.key == "inactivemods_activate") { inactivemods_activate_btn->label = msg->get("Enable >>"); inactivemods_activate_btn->pos.x = frame.x + x1; inactivemods_activate_btn->pos.y = frame.y + y1; inactivemods_activate_btn->refresh(); child_widget.push_back(inactivemods_activate_btn); optiontab[child_widget.size()-1] = 5; } else if (infile.key == "secondary_offset") { offset_x = x1; offset_y = y1; } else if (infile.key == "keybinds_bg_color") { // background color for keybinds scrollbox scrollpane_color.r = x1; scrollpane_color.g = y1; scrollpane_color.b = x2; } else if (infile.key == "scrollpane") { scrollpane.x = x1; scrollpane.y = y1; scrollpane.w = x2; scrollpane.h = y2; } else if (infile.key == "scrollpane_contents") { scrollpane_contents = x1; } if (setting_num > -1 && setting_num < 29) { //keybindings settings_lb[setting_num]->setX(x1); settings_lb[setting_num]->setY(y1); settings_key[setting_num]->pos.x = x2; settings_key[setting_num]->pos.y = y2; } } infile.close(); } // Load the MenuConfirm positions and alignments from menus/menus.txt if (infile.open("menus/menus.txt")) { int menu_index = -1; while (infile.next()) { if (infile.key == "id") { if (infile.val == "confirm") menu_index = 0; else menu_index = -1; } if (menu_index == -1) continue; if (infile.key == "layout") { infile.val = infile.val + ','; menuConfirm_area.x = eatFirstInt(infile.val, ','); menuConfirm_area.y = eatFirstInt(infile.val, ','); menuConfirm_area.w = eatFirstInt(infile.val, ','); menuConfirm_area.h = eatFirstInt(infile.val, ','); } if (infile.key == "align") { menuConfirm_align = infile.val; } } infile.close(); } defaults_confirm->window_area = menuConfirm_area; defaults_confirm->alignment = menuConfirm_align; defaults_confirm->align(); defaults_confirm->update(); resolution_confirm->window_area = menuConfirm_area; resolution_confirm->alignment = menuConfirm_align; resolution_confirm->align(); resolution_confirm->update(); // Allocate KeyBindings ScrollBox input_scrollbox = new WidgetScrollBox(scrollpane.w, scrollpane.h); input_scrollbox->pos.x = scrollpane.x + frame.x; input_scrollbox->pos.y = scrollpane.y + frame.y; input_scrollbox->bg.r = scrollpane_color.r; input_scrollbox->bg.g = scrollpane_color.g; input_scrollbox->bg.b = scrollpane_color.b; input_scrollbox->transparent = false; input_scrollbox->resize(scrollpane_contents); // Set positions of secondary key bindings for (unsigned int i = 29; i < 58; i++) { settings_key[i]->pos.x = settings_key[i-29]->pos.x + offset_x; settings_key[i]->pos.y = settings_key[i-29]->pos.y + offset_y; } }
void loadMiscSettings() { FileParser infile; // load miscellaneous settings from engine config // misc.txt if (infile.open(mods->locate("engine/misc.txt").c_str())) { while (infile.next()) { if (infile.key == "save_hpmp") { SAVE_HPMP = atoi(infile.val.c_str()); } else if (infile.key == "default_name") { DEFAULT_NAME = infile.val.c_str(); } } infile.close(); } else { fprintf(stderr, "No misc engine settings config found!\n"); } // resolutions.txt if (infile.open(mods->locate("engine/resolutions.txt").c_str())) { while (infile.next()) { if (infile.key == "menu_frame_width") { FRAME_W = atoi(infile.val.c_str()); } else if (infile.key == "menu_frame_height") { FRAME_H = atoi(infile.val.c_str()); } else if (infile.key == "small_icon_size") { ICON_SIZE_SMALL = atoi(infile.val.c_str()); } else if (infile.key == "large_icon_size") { ICON_SIZE_LARGE = atoi(infile.val.c_str()); } else if (infile.key == "required_width") { MIN_VIEW_W = atoi(infile.val.c_str()); if (VIEW_W < MIN_VIEW_W) VIEW_W = MIN_VIEW_W; VIEW_W_HALF = VIEW_W/2; } else if (infile.key == "required_height") { MIN_VIEW_H = atoi(infile.val.c_str()); if (VIEW_H < MIN_VIEW_H) VIEW_H = MIN_VIEW_H; VIEW_H_HALF = VIEW_H/2; } } infile.close(); } else { fprintf(stderr, "No resolutions engine settings config found!\n"); } // gameplay.txt if (infile.open(mods->locate("engine/gameplay.txt").c_str())) { while (infile.next()) { if (infile.key == "enable_playgame") { ENABLE_PLAYGAME = atoi(infile.val.c_str()); } } infile.close(); } else { fprintf(stderr, "No gameplay engine settings config found!\n"); } // combat.txt if (infile.open(mods->locate("engine/combat.txt").c_str())) { while (infile.next()) { if (infile.key == "max_absorb_percent") { MAX_ABSORB = atoi(infile.val.c_str()); } else if (infile.key == "max_resist_percent") { MAX_RESIST = atoi(infile.val.c_str()); } else if (infile.key == "max_block_percent") { MAX_BLOCK = atoi(infile.val.c_str()); } else if (infile.key == "max_avoidance_percent") { MAX_AVOIDANCE = atoi(infile.val.c_str()); } } infile.close(); } else { fprintf(stderr, "No combat engine settings config found!\n"); } }
MenuInventory::MenuInventory(StatBlock *_stats) { stats = _stats; MAX_EQUIPPED = 4; MAX_CARRIED = 64; visible = false; background = loadGraphicSurface("images/menus/inventory.png"); currency = 0; drag_prev_src = -1; changed_equipment = true; changed_artifact = true; log_msg = ""; drop_stack.item = 0; drop_stack.quantity = 0; closeButton = new WidgetButton("images/menus/buttons/button_x.png"); // Load config settings SDL_Rect equipment_slot; FileParser infile; if(infile.open("menus/inventory.txt")) { while(infile.next()) { infile.val = infile.val + ','; if(infile.key == "close") { close_pos.x = eatFirstInt(infile.val,','); close_pos.y = eatFirstInt(infile.val,','); } else if(infile.key == "equipment_slot") { equipment_slot.x = eatFirstInt(infile.val,','); equipment_slot.y = eatFirstInt(infile.val,','); equipment_slot.w = equipment_slot.h = eatFirstInt(infile.val,','); equipped_area.push_back(equipment_slot); slot_type.push_back(eatFirstString(infile.val,',')); } else if(infile.key == "slot_name") { slot_desc.push_back(eatFirstString(infile.val,',')); } else if(infile.key == "carried_area") { carried_area.x = eatFirstInt(infile.val,','); carried_area.y = eatFirstInt(infile.val,','); } else if (infile.key == "carried_cols") { carried_cols = eatFirstInt(infile.val,','); } else if (infile.key == "carried_rows") { carried_rows = eatFirstInt(infile.val,','); } else if (infile.key == "caption") { title = eatLabelInfo(infile.val); } else if (infile.key == "currency") { currency_lbl = eatLabelInfo(infile.val); } else if (infile.key == "help") { help_pos.x = eatFirstInt(infile.val,','); help_pos.y = eatFirstInt(infile.val,','); help_pos.w = eatFirstInt(infile.val,','); help_pos.h = eatFirstInt(infile.val,','); } } infile.close(); } MAX_EQUIPPED = equipped_area.size(); MAX_CARRIED = carried_cols * carried_rows; color_normal = font->getColor("menu_normal"); color_high = font->getColor("menu_bonus"); }
SDLFontEngine::SDLFontEngine() : FontEngine(), active_font(NULL) { // Initiate SDL_ttf if(!TTF_WasInit() && TTF_Init()==-1) { logError("SDLFontEngine: TTF_Init: %s", TTF_GetError()); exit(2); } // load the fonts // @CLASS SDLFontEngine: Font settings|Description of engine/font_settings.txt FileParser infile; if (infile.open("engine/font_settings.txt")) { while (infile.next()) { if (infile.new_section) { SDLFontStyle f; f.name = infile.section; font_styles.push_back(f); } if (font_styles.empty()) continue; SDLFontStyle *style = &(font_styles.back()); if ((infile.key == "default" && style->path == "") || infile.key == LANGUAGE) { // @ATTR $STYLE.default, $STYLE.$LANGUAGE|filename (string), point size (integer), blending (boolean)|Filename, point size, and blend mode of the font to use for this language. $STYLE can be something like "font_normal" or "font_bold". $LANGUAGE can be a 2-letter region code. style->path = popFirstString(infile.val); style->ptsize = popFirstInt(infile.val); style->blend = toBool(popFirstString(infile.val)); style->ttfont = TTF_OpenFont(mods->locate("fonts/" + style->path).c_str(), style->ptsize); if(style->ttfont == NULL) { logError("FontEngine: TTF_OpenFont: %s", TTF_GetError()); } else { int lineskip = TTF_FontLineSkip(style->ttfont); style->line_height = lineskip; style->font_height = lineskip; } } } infile.close(); } // set the font colors Color color; if (infile.open("engine/font_colors.txt")) { while (infile.next()) { // @ATTR menu_normal, menu_bonus, menu_penalty, widget_normal, widget_disabled|r (integer), g (integer), b (integer)|Colors for menus and widgets // @ATTR combat_givedmg, combat_takedmg, combat_crit, combat_buff, combat_miss|r (integer), g (integer), b (integer)|Colors for combat text // @ATTR requirements_not_met, item_bonus, item_penalty, item_flavor|r (integer), g (integer), b (integer)|Colors for tooltips // @ATTR item_$QUALITY|r (integer), g (integer), b (integer)|Colors for item quality. $QUALITY should match qualities used in items/items.txt color_map[infile.key] = toRGB(infile.val); } infile.close(); } // Attempt to set the default active font setFont("font_regular"); if (!active_font) { logError("FontEngine: Unable to determine default font!"); SDL_Quit(); exit(1); } }
void loadTilesetSettings() { // reset defaults UNITS_PER_PIXEL_X = 2; UNITS_PER_PIXEL_Y = 4; TILE_W = 64; TILE_H = 32; TILE_W_HALF = TILE_W/2; TILE_H_HALF = TILE_H/2; TILESET_ISOMETRIC = 0; TILESET_ORTHOGONAL = 1; TILESET_ORIENTATION = TILESET_ISOMETRIC; FileParser infile; // load tileset settings from engine config // @CLASS Settings: Tileset config|Description of engine/tileset_config.txt if (infile.open("engine/tileset_config.txt", true, "Unable to open engine/tileset_config.txt! Defaulting to 64x32 isometric tiles.")) { while (infile.next()) { if (infile.key == "tile_size") { // @ATTR tile_size|w (integet), h (integer)|The width and height of a tile. TILE_W = toInt(infile.nextValue()); TILE_H = toInt(infile.nextValue()); TILE_W_HALF = TILE_W /2; TILE_H_HALF = TILE_H /2; } else if (infile.key == "orientation") { // @ATTR orientation|[isometric, orthogonal]|The perspective of tiles; isometric or orthogonal. if (infile.val == "isometric") TILESET_ORIENTATION = TILESET_ISOMETRIC; else if (infile.val == "orthogonal") TILESET_ORIENTATION = TILESET_ORTHOGONAL; } else { infile.error("Settings: '%s' is not a valid key.", infile.key.c_str()); } } infile.close(); } // Init automatically calculated parameters if (TILESET_ORIENTATION == TILESET_ISOMETRIC) { if (TILE_W > 0 && TILE_H > 0) { UNITS_PER_PIXEL_X = 2.0f / TILE_W; UNITS_PER_PIXEL_Y = 2.0f / TILE_H; } else { logError("Settings: Tile dimensions must be greater than 0. Resetting to the default size of 64x32."); TILE_W = 64; TILE_H = 32; } } else { // TILESET_ORTHOGONAL if (TILE_W > 0 && TILE_H > 0) { UNITS_PER_PIXEL_X = 1.0f / TILE_W; UNITS_PER_PIXEL_Y = 1.0f / TILE_H; } else { logError("Settings: Tile dimensions must be greater than 0. Resetting to the default size of 64x32."); TILE_W = 64; TILE_H = 32; } } if (UNITS_PER_PIXEL_X == 0 || UNITS_PER_PIXEL_Y == 0) { logError("Settings: One of UNITS_PER_PIXEL values is zero! %dx%d", (int)UNITS_PER_PIXEL_X, (int)UNITS_PER_PIXEL_Y); SDL_Quit(); exit(1); } }
/** * Load a specific item sets file * * @param filename The (full) path and name of the file to load */ void ItemManager::loadSets(const std::string& filename) { FileParser infile; // @CLASS ItemManager: Sets|Definition of a item sets, items/sets.txt... if (!infile.open(filename, FileParser::MOD_FILE, FileParser::ERROR_NORMAL)) return; bool clear_bonus = true; int id = 0; bool id_line; while (infile.next()) { if (infile.key == "id") { // @ATTR id|int|A uniq id for the item set. id_line = true; id = Parse::toInt(infile.val); if (id > 0) { size_t new_size = id+1; if (item_sets.size() <= new_size) item_sets.resize(new_size); } clear_bonus = true; } else id_line = false; if (id < 1) { if (id_line) infile.error("ItemManager: Item set index out of bounds 1-%d, skipping set.", INT_MAX); continue; } if (id_line) continue; assert(item_sets.size() > std::size_t(id)); if (infile.key == "name") { // @ATTR name|string|Name of the item set. item_sets[id].name = msg->get(infile.val); } else if (infile.key == "items") { // @ATTR items|list(item_id)|List of item id's that is part of the set. item_sets[id].items.clear(); std::string item_id = Parse::popFirstString(infile.val); while (item_id != "") { int temp_id = Parse::toInt(item_id); if (temp_id > 0 && temp_id < static_cast<int>(items.size())) { items[temp_id].set = id; item_sets[id].items.push_back(temp_id); } else { const int maxsize = static_cast<int>(items.size()-1); infile.error("ItemManager: Item index out of bounds 1-%d, skipping item.", maxsize); } item_id = Parse::popFirstString(infile.val); } } else if (infile.key == "color") { // @ATTR color|color|A specific of color for the set. item_sets[id].color = Parse::toRGB(infile.val); } else if (infile.key == "bonus") { // @ATTR bonus|repeatable(int, string, int) : Required set item count, Stat name, Value|Bonus to append to items in the set. if (clear_bonus) { item_sets[id].bonus.clear(); clear_bonus = false; } SetBonusData bonus; bonus.requirement = Parse::popFirstInt(infile.val); parseBonus(bonus, infile); item_sets[id].bonus.push_back(bonus); } else if (infile.key == "bonus_power_level") { // @ATTR bonus_power_level|repeatable(int, power_id, int) : Required set item count, Base power, Bonus levels|Grants bonus levels to a given base power. SetBonusData bonus; bonus.requirement = Parse::popFirstInt(infile.val); bonus.power_id = Parse::popFirstInt(infile.val); bonus.value = Parse::popFirstInt(infile.val); item_sets[id].bonus.push_back(bonus); } else { infile.error("ItemManager: '%s' is not a valid key.", infile.key.c_str()); } } infile.close(); }
void loadMiscSettings() { // reset to defaults ELEMENTS.clear(); EQUIP_FLAGS.clear(); HERO_CLASSES.clear(); FRAME_W = 0; FRAME_H = 0; IGNORE_TEXTURE_FILTER = false; ICON_SIZE = 0; AUTOPICKUP_CURRENCY = false; MAX_ABSORB = 90; MAX_RESIST = 90; MAX_BLOCK = 100; MAX_AVOIDANCE = 99; MIN_ABSORB = 0; MIN_RESIST = 0; MIN_BLOCK = 0; MIN_AVOIDANCE = 0; CURRENCY = "Gold"; VENDOR_RATIO = 0.25; DEATH_PENALTY = true; DEATH_PENALTY_PERMADEATH = false; DEATH_PENALTY_CURRENCY = 50; DEATH_PENALTY_XP = 0; DEATH_PENALTY_XP_CURRENT = 0; DEATH_PENALTY_ITEM = false; MENUS_PAUSE = false; SAVE_HPMP = false; ENABLE_PLAYGAME = false; CORPSE_TIMEOUT = 60*MAX_FRAMES_PER_SEC; SELL_WITHOUT_VENDOR = true; AIM_ASSIST = 0; SAVE_PREFIX = ""; WINDOW_TITLE = "Flare"; SOUND_FALLOFF = 15; PARTY_EXP_PERCENTAGE = 100; ENABLE_ALLY_COLLISION_AI = true; ENABLE_ALLY_COLLISION = true; CURRENCY_ID = 1; INTERACT_RANGE = 3; SAVE_ONLOAD = true; SAVE_ONEXIT = true; TOOLTIP_OFFSET = 0; TOOLTIP_WIDTH = 1; TOOLTIP_MARGIN = 0; TOOLTIP_MARGIN_NPC = 0; FileParser infile; // @CLASS Settings: Misc|Description of engine/misc.txt if (infile.open("engine/misc.txt")) { while (infile.next()) { // @ATTR save_hpmp|boolean|When saving the game, keep the hero's current HP and MP. if (infile.key == "save_hpmp") SAVE_HPMP = toBool(infile.val); // @ATTR corpse_timeout|duration|Duration that a corpse can exist on the map in 'ms' or 's'. else if (infile.key == "corpse_timeout") CORPSE_TIMEOUT = parse_duration(infile.val); // @ATTR sell_without_vendor|boolean|Allows selling items when not at a vendor via CTRL-Click. else if (infile.key == "sell_without_vendor") SELL_WITHOUT_VENDOR = toBool(infile.val); // @ATTR aim_assist|integer|The pixel offset for powers that use aim_assist. else if (infile.key == "aim_assist") AIM_ASSIST = toInt(infile.val); // @ATTR window_title|string|Sets the text in the window's titlebar. else if (infile.key == "window_title") WINDOW_TITLE = infile.val; // @ATTR save_prefix|string|A string that's prepended to save filenames to prevent conflicts between mods. else if (infile.key == "save_prefix") SAVE_PREFIX = infile.val; // @ATTR sound_falloff|integer|The maximum radius in tiles that any single sound is audible. else if (infile.key == "sound_falloff") SOUND_FALLOFF = toInt(infile.val); // @ATTR party_exp_percentage|integer|The percentage of XP given to allies. else if (infile.key == "party_exp_percentage") PARTY_EXP_PERCENTAGE = toInt(infile.val); // @ATTR enable_ally_collision|boolean|Allows allies to block the player's path. else if (infile.key == "enable_ally_collision") ENABLE_ALLY_COLLISION = toBool(infile.val); // @ATTR enable_ally_collision_ai|boolean|Allows allies to block the path of other AI creatures. else if (infile.key == "enable_ally_collision_ai") ENABLE_ALLY_COLLISION_AI = toBool(infile.val); else if (infile.key == "currency_id") { // @ATTR currency_id|integer|An item id that will be used as currency. CURRENCY_ID = toInt(infile.val); if (CURRENCY_ID < 1) { CURRENCY_ID = 1; logError("Settings: Currency ID below the minimum allowed value. Resetting it to %d", CURRENCY_ID); } } // @ATTR interact_range|float|Distance where the player can interact with objects and NPCs. else if (infile.key == "interact_range") INTERACT_RANGE = toFloat(infile.val); // @ATTR menus_pause|boolean|Opening any menu will pause the game. else if (infile.key == "menus_pause") MENUS_PAUSE = toBool(infile.val); // @ATTR save_onload|boolean|Save the game upon changing maps. else if (infile.key == "save_onload") SAVE_ONLOAD = toBool(infile.val); // @ATTR save_onexit|boolean|Save the game upon quitting to the title screen or desktop. else if (infile.key == "save_onexit") SAVE_ONEXIT = toBool(infile.val); else infile.error("Settings: '%s' is not a valid key.", infile.key.c_str()); } infile.close(); } if (SAVE_PREFIX == "") { logError("Settings: save_prefix not found in engine/misc.txt, setting to 'default'. This may cause save file conflicts between games that have no save_prefix."); SAVE_PREFIX = "default"; } // @CLASS Settings: Resolution|Description of engine/resolutions.txt if (infile.open("engine/resolutions.txt")) { while (infile.next()) { // @ATTR menu_frame_width|integer|Width of frame for New Game, Configuration, etc. menus. if (infile.key == "menu_frame_width") FRAME_W = toInt(infile.val); // @ATTR menu_frame_height|integer|Height of frame for New Game, Configuration, etc. menus. else if (infile.key == "menu_frame_height") FRAME_H = toInt(infile.val); // @ATTR icon_size|integer|Size of icons. else if (infile.key == "icon_size") ICON_SIZE = toInt(infile.val); // @ATTR required_width|integer|Minimum window/screen resolution width. else if (infile.key == "required_width") { MIN_SCREEN_W = toInt(infile.val); } // @ATTR required_height|integer|Minimum window/screen resolution height. else if (infile.key == "required_height") { MIN_SCREEN_H = toInt(infile.val); } // @ATTR virtual_height|integer|The height (in pixels) of the game's actual rendering area. The width will be resized to match the window's aspect ration, and everything will be scaled up to fill the window. else if (infile.key == "virtual_height") { VIEW_H = toInt(infile.val); VIEW_H_HALF = VIEW_H / 2; } // @ATTR ignore_texture_filter|boolean|If true, this ignores the "Texture Filtering" video setting and uses only nearest-neighbor scaling. This is good for games that use pixel art assets. else if (infile.key == "ignore_texture_filter") { IGNORE_TEXTURE_FILTER = toBool(infile.val); } else infile.error("Settings: '%s' is not a valid key.", infile.key.c_str()); } infile.close(); } // prevent the window from being too small if (SCREEN_W < MIN_SCREEN_W) SCREEN_W = MIN_SCREEN_W; if (SCREEN_H < MIN_SCREEN_H) SCREEN_H = MIN_SCREEN_H; // set the default virtual height if it's not defined if (VIEW_H == 0) { logError("Settings: virtual_height is undefined. Setting it to %d.", MIN_SCREEN_H); VIEW_H = MIN_SCREEN_H; VIEW_H_HALF = VIEW_H / 2; } // @CLASS Settings: Gameplay|Description of engine/gameplay.txt if (infile.open("engine/gameplay.txt")) { while (infile.next()) { if (infile.key == "enable_playgame") { // @ATTR enable_playgame|boolean|Enables the "Play Game" button on the main menu. ENABLE_PLAYGAME = toBool(infile.val); } else infile.error("Settings: '%s' is not a valid key.", infile.key.c_str()); } infile.close(); } // @CLASS Settings: Combat|Description of engine/combat.txt if (infile.open("engine/combat.txt")) { while (infile.next()) { // @ATTR max_absorb_percent|integer|Maximum percentage of damage that can be absorbed. if (infile.key == "max_absorb_percent") MAX_ABSORB = toInt(infile.val); // @ATTR max_resist_percent|integer|Maximum percentage of elemental damage that can be resisted. else if (infile.key == "max_resist_percent") MAX_RESIST = toInt(infile.val); // @ATTR max_block_percent|integer|Maximum percentage of damage that can be blocked. else if (infile.key == "max_block_percent") MAX_BLOCK = toInt(infile.val); // @ATTR max_avoidance_percent|integer|Maximum percentage chance that hazards can be avoided. else if (infile.key == "max_avoidance_percent") MAX_AVOIDANCE = toInt(infile.val); // @ATTR min_absorb_percent|integer|Minimum percentage of damage that can be absorbed. else if (infile.key == "min_absorb_percent") MIN_ABSORB = toInt(infile.val); // @ATTR min_resist_percent|integer|Minimum percentage of elemental damage that can be resisted. else if (infile.key == "min_resist_percent") MIN_RESIST = toInt(infile.val); // @ATTR min_block_percent|integer|Minimum percentage of damage that can be blocked. else if (infile.key == "min_block_percent") MIN_BLOCK = toInt(infile.val); // @ATTR min_avoidance_percent|integer|Minimum percentage chance that hazards can be avoided. else if (infile.key == "min_avoidance_percent") MIN_AVOIDANCE = toInt(infile.val); else infile.error("Settings: '%s' is not a valid key.", infile.key.c_str()); } infile.close(); } // @CLASS Settings: Elements|Description of engine/elements.txt if (infile.open("engine/elements.txt")) { Element e; while (infile.next()) { // @ATTR name|string|An identifier for this element. if (infile.key == "name") e.name = infile.val; // @ATTR description|string|The displayed name of this element. else if (infile.key == "description") e.description = infile.val; else infile.error("Settings: '%s' is not a valid key.", infile.key.c_str()); if (e.name != "" && e.description != "") { ELEMENTS.push_back(e); e.name = e.description = ""; } } infile.close(); } // @CLASS Settings: Equip flags|Description of engine/equip_flags.txt if (infile.open("engine/equip_flags.txt")) { std::string type,description; type = description = ""; while (infile.next()) { // @ATTR name|string|An identifier for this equip flag. if (infile.key == "name") type = infile.val; // @ATTR description|string|The displayed name of this equip flag. else if (infile.key == "description") description = infile.val; else infile.error("Settings: '%s' is not a valid key.", infile.key.c_str()); if (type != "" && description != "") { EQUIP_FLAGS[type] = description; type = description = ""; } } infile.close(); } // @CLASS Settings: Classes|Description of engine/classes.txt if (infile.open("engine/classes.txt")) { while (infile.next()) { if (infile.new_section) { if (infile.section == "class") { HERO_CLASSES.push_back(HeroClass()); } } if (infile.section != "class") continue; if (!HERO_CLASSES.empty()) { // @ATTR name|string|The displayed name of this class. if (infile.key == "name") HERO_CLASSES.back().name = infile.val; // @ATTR description|string|A description of this class. else if (infile.key == "description") HERO_CLASSES.back().description = infile.val; // @ATTR currency|integer|The amount of currency this class will start with. else if (infile.key == "currency") HERO_CLASSES.back().currency = toInt(infile.val); // @ATTR equipment|item (integer), ...|A list of items that are equipped when starting with this class. else if (infile.key == "equipment") HERO_CLASSES.back().equipment = infile.val; // @ATTR physical|integer|Class starts with this physical stat. else if (infile.key == "physical") HERO_CLASSES.back().physical = toInt(infile.val); // @ATTR mental|integer|Class starts with this mental stat. else if (infile.key == "mental") HERO_CLASSES.back().mental = toInt(infile.val); // @ATTR offense|integer|Class starts with this offense stat. else if (infile.key == "offense") HERO_CLASSES.back().offense = toInt(infile.val); // @ATTR defense|integer|Class starts with this defense stat. else if (infile.key == "defense") HERO_CLASSES.back().defense = toInt(infile.val); else if (infile.key == "actionbar") { // @ATTR actionbar|power (integer), ...|A list of powers to place in the action bar for the class. for (int i=0; i<12; i++) { HERO_CLASSES.back().hotkeys[i] = toInt(infile.nextValue()); } } else if (infile.key == "powers") { // @ATTR powers|power (integer), ...|A list of powers that are unlocked when starting this class. std::string power; while ( (power = infile.nextValue()) != "") { HERO_CLASSES.back().powers.push_back(toInt(power)); } } else if (infile.key == "campaign") { // @ATTR campaign|status (string), ...|A list of campaign statuses that are set when starting this class. std::string status; while ( (status = infile.nextValue()) != "") { HERO_CLASSES.back().statuses.push_back(status); } } // @ATTR power_tree|string|Power tree that will be loaded by MenuPowers else if (infile.key == "power_tree") HERO_CLASSES.back().power_tree = infile.val; else infile.error("Settings: '%s' is not a valid key.", infile.key.c_str()); } } infile.close(); } // Make a default hero class if none were found if (HERO_CLASSES.empty()) { HeroClass c; c.name = "Adventurer"; HERO_CLASSES.push_back(c); } // @CLASS Settings: Death penalty|Description of engine/death_penalty.txt if (infile.open("engine/death_penalty.txt")) { while (infile.next()) { // @ATTR enable|boolean|Enable the death penalty. if (infile.key == "enable") DEATH_PENALTY = toBool(infile.val); // @ATTR permadeath|boolean|Force permadeath for all new saves. else if (infile.key == "permadeath") DEATH_PENALTY_PERMADEATH = toBool(infile.val); // @ATTR currency|integer|Remove this percentage of currency. else if (infile.key == "currency") DEATH_PENALTY_CURRENCY = toInt(infile.val); // @ATTR xp_total|integer|Remove this percentage of total XP. else if (infile.key == "xp_total") DEATH_PENALTY_XP = toInt(infile.val); // @ATTR xp_current_level|integer|Remove this percentage of the XP gained since the last level. else if (infile.key == "xp_current_level") DEATH_PENALTY_XP_CURRENT = toInt(infile.val); // @ATTR random_item|integer|Removes a random item from the player's inventory. else if (infile.key == "random_item") DEATH_PENALTY_ITEM = toBool(infile.val); else infile.error("Settings: '%s' is not a valid key.", infile.key.c_str()); } infile.close(); } // @CLASS Settings: Tooltips|Description of engine/tooltips.txt if (infile.open("engine/tooltips.txt")) { while (infile.next()) { // @ATTR tooltip_offset|integer|Offset in pixels from the origin point (usually mouse cursor). if (infile.key == "tooltip_offset") TOOLTIP_OFFSET = toInt(infile.val); // @ATTR tooltip_width|integer|Maximum width of tooltip in pixels. else if (infile.key == "tooltip_width") TOOLTIP_WIDTH = toInt(infile.val); // @ATTR tooltip_margin|integer|Padding between the text and the tooltip borders. else if (infile.key == "tooltip_margin") TOOLTIP_MARGIN = toInt(infile.val); // @ATTR npc_tooltip_margin|integer|Vertical offset for NPC labels. else if (infile.key == "npc_tooltip_margin") TOOLTIP_MARGIN_NPC = toInt(infile.val); } infile.close(); } }
StatBlock::StatBlock() { name = ""; alive = true; corpse = false; hero = false; humanoid = false; hero_pos.x = hero_pos.y = -1; hero_alive = true; permadeath = false; transform_type = ""; transformed = false; movement_type = MOVEMENT_NORMAL; flying = false; intangible = false; facing = true; // core stats offense_character = defense_character = physical_character = mental_character = 0; offense_additional = defense_additional = physical_additional = mental_additional = 0; physoff = physdef = mentoff = mentdef = 0; physment = offdef = 0; character_class=""; level = 0; hp = maxhp = hp_per_minute = hp_ticker = 0; mp = maxmp = mp_per_minute = mp_ticker = 0; xp = 0; accuracy = 75; avoidance = 25; crit = 0; level_up = false; // equipment stats dmg_melee_min = 1; dmg_melee_max = 4; dmg_ment_min = 0; dmg_ment_max = 0; dmg_ranged_min = 0; dmg_ranged_max = 0; absorb_min = 0; absorb_max = 0; wielding_physical = false; wielding_mental = false; wielding_offense = false; // buff and debuff stats slow_duration = 0; slow_duration_total = 0; bleed_duration = 0; bleed_duration_total = 0; stun_duration = 0; stun_duration_total = 0; immobilize_duration = 0; immobilize_duration_total = 0; immunity_duration = 0; immunity_duration_total = 0; transform_duration = 0; transform_duration_total = 0; manual_untransform = false; haste_duration = 0; haste_duration_total = 0; hot_duration = 0; hot_duration_total = 0; hot_value = 0; forced_move_duration = 0; forced_move_duration_total = 0; shield_hp = 0; shield_hp_total = 0; shield_frame = 0; vengeance_stacks = 0; vengeance_frame = 0; cooldown_ticks = 0; blocking = false; // patrol waypoints waypoint_pause = 0; waypoint_pause_ticks = 0; // xp table // default to MAX_INT for (int i=0; i<MAX_CHARACTER_LEVEL; i++) { xp_table[i] = std::numeric_limits<int>::max(); } // overwrite with data from config FileParser infile; infile.open(mods->locate("engine/xp_table.txt")); while(infile.next()) { xp_table[atoi(infile.key.c_str()) - 1] = atoi(infile.val.c_str()); } infile.close(); loot_chance = 50; loot_types = vector<string>(); loot_prob = vector<int>(); loot_prob_sum = 0; teleportation = false; for (int i=0; i<POWERSLOT_COUNT; i++) { power_chance[i] = 0; power_index[i] = -1; power_cooldown[i] = 0; power_ticks[i] = 0; } melee_range = 64; melee_weapon_power = -1; ranged_weapon_power = -1; mental_weapon_power = -1; attunement_fire = 100; attunement_ice = 100; gold = 0; death_penalty = false; // campaign status interaction defeat_status = ""; quest_loot_requires = ""; quest_loot_not = ""; quest_loot_id = 0; first_defeat_loot = 0; // default hero base/option base="male"; head="head_short"; portrait="male01"; // default animations animations = ""; // default animation speed animationSpeed = 100; statsLoaded = false; // formula numbers. Used only for hero hp_base = 10; hp_per_level = 2; hp_per_physical = 8; hp_regen_base = 10; hp_regen_per_level = 1; hp_regen_per_physical = 4; mp_base = 10; mp_per_level = 2; mp_per_mental = 8; mp_regen_base = 10; mp_regen_per_level = 1; mp_regen_per_mental = 4; accuracy_base = 75; accuracy_per_level = 1; accuracy_per_offense = 5; avoidance_base = 25; avoidance_per_level = 1; avoidance_per_defense = 5; crit_base = 5; crit_per_level = 1; }
MenuCharacter::MenuCharacter(StatBlock *_stats) { stats = _stats; skill_points = 0; visible = false; newPowerNotification = false; for (int i=0; i<CSTAT_COUNT; i++) { cstat[i].label = new WidgetLabel(); cstat[i].value = new WidgetLabel(); cstat[i].hover.x = cstat[i].hover.y = 0; cstat[i].hover.w = cstat[i].hover.h = 0; cstat[i].visible = true; } for (int i=0; i<STATLIST_COUNT; i++) { show_stat[i] = true; } statlist_rows = 10; statlist_scrollbar_offset = 0; closeButton = new WidgetButton("images/menus/buttons/button_x.png"); // Upgrade buttons for (int i=0; i<4; i++) { upgradeButton[i] = new WidgetButton("images/menus/buttons/upgrade.png"); upgradeButton[i]->enabled = false; show_upgrade[i] = true; } physical_up = false; mental_up = false; offense_up = false; defense_up = false; // menu title labelCharacter = new WidgetLabel(); // unspent points labelUnspent = new WidgetLabel(); // Load config settings FileParser infile; if (infile.open("menus/character.txt")) { while(infile.next()) { infile.val = infile.val + ','; if(infile.key == "close") { close_pos.x = eatFirstInt(infile.val,','); close_pos.y = eatFirstInt(infile.val,','); } else if(infile.key == "caption") { title = eatLabelInfo(infile.val); } else if(infile.key == "upgrade_physical") { upgrade_pos[0].x = eatFirstInt(infile.val,','); upgrade_pos[0].y = eatFirstInt(infile.val,','); } else if(infile.key == "upgrade_mental") { upgrade_pos[1].x = eatFirstInt(infile.val,','); upgrade_pos[1].y = eatFirstInt(infile.val,','); } else if(infile.key == "upgrade_offense") { upgrade_pos[2].x = eatFirstInt(infile.val,','); upgrade_pos[2].y = eatFirstInt(infile.val,','); } else if(infile.key == "upgrade_defense") { upgrade_pos[3].x = eatFirstInt(infile.val,','); upgrade_pos[3].y = eatFirstInt(infile.val,','); } else if(infile.key == "statlist") { statlist_pos.x = eatFirstInt(infile.val,','); statlist_pos.y = eatFirstInt(infile.val,','); } else if (infile.key == "statlist_rows") { statlist_rows = eatFirstInt(infile.val,','); } else if (infile.key == "statlist_scrollbar_offset") { statlist_scrollbar_offset = eatFirstInt(infile.val,','); } else if(infile.key == "label_name") { label_pos[0] = eatLabelInfo(infile.val); cstat[CSTAT_NAME].visible = !label_pos[0].hidden; } else if(infile.key == "label_level") { label_pos[1] = eatLabelInfo(infile.val); cstat[CSTAT_LEVEL].visible = !label_pos[1].hidden; } else if(infile.key == "label_physical") { label_pos[2] = eatLabelInfo(infile.val); cstat[CSTAT_PHYSICAL].visible = !label_pos[2].hidden; } else if(infile.key == "label_mental") { label_pos[3] = eatLabelInfo(infile.val); cstat[CSTAT_MENTAL].visible = !label_pos[3].hidden; } else if(infile.key == "label_offense") { label_pos[4] = eatLabelInfo(infile.val); cstat[CSTAT_OFFENSE].visible = !label_pos[4].hidden; } else if(infile.key == "label_defense") { label_pos[5] = eatLabelInfo(infile.val); cstat[CSTAT_DEFENSE].visible = !label_pos[5].hidden; } else if(infile.key == "name") { value_pos[0].x = eatFirstInt(infile.val,','); value_pos[0].y = eatFirstInt(infile.val,','); value_pos[0].w = eatFirstInt(infile.val,','); value_pos[0].h = eatFirstInt(infile.val,','); } else if(infile.key == "level") { value_pos[1].x = eatFirstInt(infile.val,','); value_pos[1].y = eatFirstInt(infile.val,','); value_pos[1].w = eatFirstInt(infile.val,','); value_pos[1].h = eatFirstInt(infile.val,','); } else if(infile.key == "physical") { value_pos[2].x = eatFirstInt(infile.val,','); value_pos[2].y = eatFirstInt(infile.val,','); value_pos[2].w = eatFirstInt(infile.val,','); value_pos[2].h = eatFirstInt(infile.val,','); } else if(infile.key == "mental") { value_pos[3].x = eatFirstInt(infile.val,','); value_pos[3].y = eatFirstInt(infile.val,','); value_pos[3].w = eatFirstInt(infile.val,','); value_pos[3].h = eatFirstInt(infile.val,','); } else if(infile.key == "offense") { value_pos[4].x = eatFirstInt(infile.val,','); value_pos[4].y = eatFirstInt(infile.val,','); value_pos[4].w = eatFirstInt(infile.val,','); value_pos[4].h = eatFirstInt(infile.val,','); } else if(infile.key == "defense") { value_pos[5].x = eatFirstInt(infile.val,','); value_pos[5].y = eatFirstInt(infile.val,','); value_pos[5].w = eatFirstInt(infile.val,','); value_pos[5].h = eatFirstInt(infile.val,','); } else if(infile.key == "unspent") { unspent_pos = eatLabelInfo(infile.val); } else if (infile.key == "show_upgrade_physical") { if (eatFirstInt(infile.val,',') == 0) show_upgrade[0] = false; } else if (infile.key == "show_upgrade_mental") { if (eatFirstInt(infile.val,',') == 0) show_upgrade[1] = false; } else if (infile.key == "show_upgrade_offense") { if (eatFirstInt(infile.val,',') == 0) show_upgrade[2] = false; } else if (infile.key == "show_upgrade_defense") { if (eatFirstInt(infile.val,',') == 0) show_upgrade[3] = false; } else if (infile.key == "show_maxhp") { if (eatFirstInt(infile.val,',') == 0) show_stat[0] = false; } else if (infile.key == "show_hpregen") { if (eatFirstInt(infile.val,',') == 0) show_stat[1] = false; } else if (infile.key == "show_maxmp") { if (eatFirstInt(infile.val,',') == 0) show_stat[2] = false; } else if (infile.key == "show_mpregen") { if (eatFirstInt(infile.val,',') == 0) show_stat[3] = false; } else if (infile.key == "show_accuracy") { if (eatFirstInt(infile.val,',') == 0) show_stat[4] = false; } else if (infile.key == "show_avoidance") { if (eatFirstInt(infile.val,',') == 0) show_stat[5] = false; } else if (infile.key == "show_melee") { if (eatFirstInt(infile.val,',') == 0) show_stat[6] = false; } else if (infile.key == "show_ranged") { if (eatFirstInt(infile.val,',') == 0) show_stat[7] = false; } else if (infile.key == "show_mental") { if (eatFirstInt(infile.val,',') == 0) show_stat[8] = false; } else if (infile.key == "show_crit") { if (eatFirstInt(infile.val,',') == 0) show_stat[9] = false; } else if (infile.key == "show_absorb") { if (eatFirstInt(infile.val,',') == 0) show_stat[10] = false; } else if (infile.key == "show_poise") { if (eatFirstInt(infile.val,',') == 0) show_stat[11] = false; } else if (infile.key == "show_bonus_xp") { if (eatFirstInt(infile.val,',') == 0) show_stat[12] = false; } else if (infile.key == "show_bonus_currency") { if (eatFirstInt(infile.val,',') == 0) show_stat[13] = false; } else if (infile.key == "show_bonus_itemfind") { if (eatFirstInt(infile.val,',') == 0) show_stat[14] = false; } else if (infile.key == "show_bonus_stealth") { if (eatFirstInt(infile.val,',') == 0) show_stat[15] = false; } else if (infile.key == "show_resists") { if (eatFirstInt(infile.val,',') == 0) show_stat[16] = false; } } infile.close(); } // stat list statList = new WidgetListBox(STATLIST_COUNT-1+stats->vulnerable.size(), statlist_rows, "images/menus/buttons/listbox_char.png"); tablist.add(statList); statList->can_select = false; statList->scrollbar_offset = statlist_scrollbar_offset; background = loadGraphicSurface("images/menus/character.png"); }
LootManager::LootManager(ItemManager *_items, MapRenderer *_map, StatBlock *_hero) { items = _items; map = _map; // we need to be able to read loot that drops from map containers hero = _hero; // we need the player's position for dropping loot in a valid spot tip = new WidgetTooltip(); FileParser infile; // load loot animation settings from engine config file if (infile.open(mods->locate("engine/loot.txt").c_str())) { while (infile.next()) { infile.val = infile.val + ','; if (infile.key == "loot_animation") { animation_pos.x = eatFirstInt(infile.val, ','); animation_pos.y = eatFirstInt(infile.val, ','); animation_pos.w = eatFirstInt(infile.val, ','); animation_pos.h = eatFirstInt(infile.val, ','); } else if (infile.key == "loot_animation_offset") { animation_offset.x = eatFirstInt(infile.val, ','); animation_offset.y = eatFirstInt(infile.val, ','); } else if (infile.key == "tooltip_margin") { tooltip_margin = eatFirstInt(infile.val, ','); } else if (infile.key == "autopickup_range") { AUTOPICKUP_RANGE = eatFirstInt(infile.val, ','); } else if (infile.key == "autopickup_currency") { int currency = eatFirstInt(infile.val, ','); if (currency == 1) AUTOPICKUP_CURRENCY = true; else AUTOPICKUP_CURRENCY = false; } else if (infile.key == "currency_name") { CURRENCY = msg->get(eatFirstString(infile.val, ',')); } else if (infile.key == "vendor_ratio") { VENDOR_RATIO = eatFirstInt(infile.val, ',') / 100.0f; } else if (infile.key == "currency_range") { CurrencyRange cr; cr.filename = eatFirstString(infile.val, ','); cr.low = eatFirstInt(infile.val, ','); cr.high = eatFirstInt(infile.val, ','); currency_range.push_back(cr); } } infile.close(); } else fprintf(stderr, "Unable to open engine/loot.txt!\n"); loot_flip = NULL; // reset current map loot loot.clear(); loadGraphics(); loot_flip = loadSfx("soundfx/flying_loot.ogg", "LootManager dropping loot"); full_msg = false; if (!lootManager) lootManager = this; else exit(25); // TODO: make sure only one instance of the lootmanager is created. }
FontEngine::FontEngine() : ttf(NULL) , active_font(NULL) , cursor_y(0) { // Initiate SDL_ttf if(!TTF_WasInit() && TTF_Init()==-1) { printf("TTF_Init: %s\n", TTF_GetError()); exit(2); } // load the fonts FileParser infile; if (infile.open("engine/font_settings.txt")) { while (infile.next()) { infile.val = infile.val + ','; if (infile.new_section) { FontStyle f; f.name = infile.section; font_styles.push_back(f); } if (font_styles.empty()) continue; FontStyle *style = &(font_styles.back()); if ((infile.key == "default" && style->path == "") || infile.key == LANGUAGE) { style->path = eatFirstString(infile.val,','); style->ptsize = eatFirstInt(infile.val,','); int blend = eatFirstInt(infile.val,','); if (blend == 1) style->blend = true; else style->blend = false; style->ttfont = TTF_OpenFont(mods->locate("fonts/" + style->path).c_str(), style->ptsize); if(style->ttfont == NULL) { printf("TTF_OpenFont: %s\n", TTF_GetError()); } else { style->line_height = TTF_FontLineSkip(style->ttfont); style->font_height = TTF_FontLineSkip(style->ttfont); } } } infile.close(); } // set the font colors // RGB values, the last value is 'unused'. For info, // see http://www.libsdl.org/cgi/docwiki.cgi/SDL_Color SDL_Color color; if (infile.open("engine/font_colors.txt")) { while (infile.next()) { infile.val = infile.val + ','; color.r = eatFirstInt(infile.val,','); color.g = eatFirstInt(infile.val,','); color.b = eatFirstInt(infile.val,','); color_map[infile.key] = color; } infile.close(); } // Attempt to set the default active font setFont("font_regular"); if (!active_font) { fprintf(stderr, "Unable to determine default font!\n"); SDL_Quit(); exit(1); } }
/** * Powers are defined in [mod]/powers/powers.txt * * @param filename The full path and filename to this powers.txt file */ void PowerManager::loadPowers(const std::string& filename) { FileParser infile; int input_id = 0; if (infile.open(filename.c_str())) { while (infile.next()) { // id needs to be the first component of each power. That is how we write // data to the correct power. if (infile.key == "id") { input_id = atoi(infile.val.c_str()); } else if (infile.key == "type") { if (infile.val == "single") powers[input_id].type = POWTYPE_SINGLE; else if (infile.val == "effect") powers[input_id].type = POWTYPE_EFFECT; else if (infile.val == "missile") powers[input_id].type = POWTYPE_MISSILE; else if (infile.val == "repeater") powers[input_id].type = POWTYPE_REPEATER; else if (infile.val == "spawn") powers[input_id].type = POWTYPE_SPAWN; } else if (infile.key == "name") { powers[input_id].name = msg->get(infile.val); } else if (infile.key == "description") { powers[input_id].description = msg->get(infile.val); } else if (infile.key == "icon") { powers[input_id].icon = atoi(infile.val.c_str()); } else if (infile.key == "new_state") { if (infile.val == "swing") powers[input_id].new_state = POWSTATE_SWING; else if (infile.val == "shoot") powers[input_id].new_state = POWSTATE_SHOOT; else if (infile.val == "cast") powers[input_id].new_state = POWSTATE_CAST; else if (infile.val == "block") powers[input_id].new_state = POWSTATE_BLOCK; } else if (infile.key == "face") { if (infile.val == "true") powers[input_id].face = true; } else if (infile.key == "source_type") { if (infile.val == "hero") powers[input_id].source_type = SOURCE_TYPE_HERO; else if (infile.val == "neutral") powers[input_id].source_type = SOURCE_TYPE_NEUTRAL; else if (infile.val == "enemy") powers[input_id].source_type = SOURCE_TYPE_ENEMY; } else if (infile.key == "beacon") { if (infile.val == "true") powers[input_id].beacon = true; } // power requirements else if (infile.key == "requires_physical_weapon") { if (infile.val == "true") powers[input_id].requires_physical_weapon = true; } else if (infile.key == "requires_mental_weapon") { if (infile.val == "true") powers[input_id].requires_mental_weapon = true; } else if (infile.key == "requires_offense_weapon") { if (infile.val == "true") powers[input_id].requires_offense_weapon = true; } else if (infile.key == "requires_mp") { powers[input_id].requires_mp = atoi(infile.val.c_str()); } else if (infile.key == "requires_los") { if (infile.val == "true") powers[input_id].requires_los = true; } else if (infile.key == "requires_empty_target") { if (infile.val == "true") powers[input_id].requires_empty_target = true; } else if (infile.key == "requires_item") { powers[input_id].requires_item = atoi(infile.val.c_str()); } else if (infile.key == "requires_targeting") { if (infile.val == "true") powers[input_id].requires_targeting = true; } else if (infile.key == "cooldown") { powers[input_id].cooldown = atoi(infile.val.c_str()); } // animation info else if (infile.key == "gfx") { powers[input_id].gfx_index = loadGFX(infile.val); } else if (infile.key == "sfx") { powers[input_id].sfx_index = loadSFX(infile.val); } else if (infile.key == "rendered") { if (infile.val == "true") powers[input_id].rendered = true; } else if (infile.key == "directional") { if (infile.val == "true") powers[input_id].directional = true; } else if (infile.key == "visual_random") { powers[input_id].visual_random = atoi(infile.val.c_str()); } else if (infile.key == "visual_option") { powers[input_id].visual_option = atoi(infile.val.c_str()); } else if (infile.key == "aim_assist") { powers[input_id].aim_assist = atoi(infile.val.c_str()); } else if (infile.key == "speed") { powers[input_id].speed = atoi(infile.val.c_str()); } else if (infile.key == "lifespan") { powers[input_id].lifespan = atoi(infile.val.c_str()); } else if (infile.key == "frame_loop") { powers[input_id].frame_loop = atoi(infile.val.c_str()); } else if (infile.key == "frame_duration") { powers[input_id].frame_duration = atoi(infile.val.c_str()); } else if (infile.key == "frame_size") { powers[input_id].frame_size.x = atoi(infile.nextValue().c_str()); powers[input_id].frame_size.y = atoi(infile.nextValue().c_str()); } else if (infile.key == "frame_offset") { powers[input_id].frame_offset.x = atoi(infile.nextValue().c_str()); powers[input_id].frame_offset.y = atoi(infile.nextValue().c_str()); } else if (infile.key == "floor") { if (infile.val == "true") powers[input_id].floor = true; } else if (infile.key == "active_frame") { powers[input_id].active_frame = atoi(infile.val.c_str()); } else if (infile.key == "complete_animation") { if (infile.val == "true") powers[input_id].complete_animation = true; } // hazard traits else if (infile.key == "use_hazard") { if (infile.val == "true") powers[input_id].use_hazard = true; } else if (infile.key == "no_attack") { if (infile.val == "true") powers[input_id].no_attack = true; } else if (infile.key == "radius") { powers[input_id].radius = atoi(infile.val.c_str()); } else if (infile.key == "base_damage") { if (infile.val == "none") powers[input_id].base_damage = BASE_DAMAGE_NONE; else if (infile.val == "melee") powers[input_id].base_damage = BASE_DAMAGE_MELEE; else if (infile.val == "ranged") powers[input_id].base_damage = BASE_DAMAGE_RANGED; else if (infile.val == "ment") powers[input_id].base_damage = BASE_DAMAGE_MENT; } else if (infile.key == "damage_multiplier") { powers[input_id].damage_multiplier = atoi(infile.val.c_str()); } else if (infile.key == "starting_pos") { if (infile.val == "source") powers[input_id].starting_pos = STARTING_POS_SOURCE; else if (infile.val == "target") powers[input_id].starting_pos = STARTING_POS_TARGET; else if (infile.val == "melee") powers[input_id].starting_pos = STARTING_POS_MELEE; } else if (infile.key == "multitarget") { if (infile.val == "true") powers[input_id].multitarget = true; } else if (infile.key == "trait_armor_penetration") { if (infile.val == "true") powers[input_id].trait_armor_penetration = true; } else if (infile.key == "trait_crits_impaired") { powers[input_id].trait_crits_impaired = atoi(infile.val.c_str()); } else if (infile.key == "trait_elemental") { if (infile.val == "wood") powers[input_id].trait_elemental = ELEMENT_WOOD; else if (infile.val == "metal") powers[input_id].trait_elemental = ELEMENT_METAL; else if (infile.val == "wind") powers[input_id].trait_elemental = ELEMENT_WIND; else if (infile.val == "water") powers[input_id].trait_elemental = ELEMENT_WATER; else if (infile.val == "earth") powers[input_id].trait_elemental = ELEMENT_EARTH; else if (infile.val == "fire") powers[input_id].trait_elemental = ELEMENT_FIRE; else if (infile.val == "shadow") powers[input_id].trait_elemental = ELEMENT_SHADOW; else if (infile.val == "light") powers[input_id].trait_elemental = ELEMENT_LIGHT; } else if (infile.key == "forced_move") { powers[input_id].forced_move_speed = atoi(infile.nextValue().c_str()); powers[input_id].forced_move_duration = atoi(infile.nextValue().c_str()); } //steal effects else if (infile.key == "hp_steal") { powers[input_id].hp_steal = atoi(infile.val.c_str()); } else if (infile.key == "mp_steal") { powers[input_id].mp_steal = atoi(infile.val.c_str()); } //missile modifiers else if (infile.key == "missile_num") { powers[input_id].missile_num = atoi(infile.val.c_str()); } else if (infile.key == "missile_angle") { powers[input_id].missile_angle = atoi(infile.val.c_str()); } else if (infile.key == "angle_variance") { powers[input_id].angle_variance = atoi(infile.val.c_str()); } else if (infile.key == "speed_variance") { powers[input_id].speed_variance = atoi(infile.val.c_str()); } //repeater modifiers else if (infile.key == "delay") { powers[input_id].delay = atoi(infile.val.c_str()); } else if (infile.key == "start_frame") { powers[input_id].start_frame = atoi(infile.val.c_str()); } else if (infile.key == "repeater_num") { powers[input_id].repeater_num = atoi(infile.val.c_str()); } // buff/debuff durations else if (infile.key == "bleed_duration") { powers[input_id].bleed_duration = atoi(infile.val.c_str()); } else if (infile.key == "stun_duration") { powers[input_id].stun_duration = atoi(infile.val.c_str()); } else if (infile.key == "slow_duration") { powers[input_id].slow_duration = atoi(infile.val.c_str()); } else if (infile.key == "immobilize_duration") { powers[input_id].immobilize_duration = atoi(infile.val.c_str()); } else if (infile.key == "immunity_duration") { powers[input_id].immunity_duration = atoi(infile.val.c_str()); } else if (infile.key == "haste_duration") { powers[input_id].haste_duration = atoi(infile.val.c_str()); } else if (infile.key == "hot_duration") { powers[input_id].hot_duration = atoi(infile.val.c_str()); } else if (infile.key == "hot_value") { powers[input_id].hot_value = atoi(infile.val.c_str()); } // buffs else if (infile.key == "buff_heal") { if (infile.val == "true") powers[input_id].buff_heal = true; } else if (infile.key == "buff_shield") { if (infile.val == "true") powers[input_id].buff_shield = true; } else if (infile.key == "buff_teleport") { if (infile.val == "true") powers[input_id].buff_teleport = true; } else if (infile.key == "buff_immunity") { if (infile.val == "true") powers[input_id].buff_immunity = true; } else if (infile.key == "buff_restore_hp") { powers[input_id].buff_restore_hp = atoi(infile.val.c_str()); } else if (infile.key == "buff_restore_mp") { powers[input_id].buff_restore_mp = atoi(infile.val.c_str()); } // pre and post power effects else if (infile.key == "post_power") { powers[input_id].post_power = atoi(infile.val.c_str()); } else if (infile.key == "wall_power") { powers[input_id].wall_power = atoi(infile.val.c_str()); } else if (infile.key == "allow_power_mod") { if (infile.val == "true") powers[input_id].allow_power_mod = true; } // spawn info else if (infile.key == "spawn_type") { powers[input_id].spawn_type = infile.val; } } infile.close(); } }
MenuCharacter::MenuCharacter(StatBlock *_stats) { stats = _stats; skill_points = 0; visible = false; newPowerNotification = false; for (int i=0; i<CSTAT_COUNT; i++) { cstat[i].label = new WidgetLabel(); cstat[i].value = new WidgetLabel(); cstat[i].hover.x = cstat[i].hover.y = 0; cstat[i].hover.w = cstat[i].hover.h = 0; cstat[i].visible = true; } for (int i=0; i<14; i++) { show_stat[i] = true; } closeButton = new WidgetButton(mods->locate("images/menus/buttons/button_x.png")); // Upgrade buttons for (int i=0; i<4; i++) { upgradeButton[i] = new WidgetButton(mods->locate("images/menus/buttons/upgrade.png")); upgradeButton[i]->enabled = false; show_upgrade[i] = true; } physical_up = false; mental_up = false; offense_up = false; defense_up = false; // menu title labelCharacter = new WidgetLabel(); // stat list statList = new WidgetListBox(13+stats->vulnerable.size(), 10, mods->locate("images/menus/buttons/listbox_char.png")); // Load config settings FileParser infile; if(infile.open(mods->locate("menus/character.txt"))) { while(infile.next()) { infile.val = infile.val + ','; if(infile.key == "close") { close_pos.x = eatFirstInt(infile.val,','); close_pos.y = eatFirstInt(infile.val,','); } else if(infile.key == "caption") { title = eatLabelInfo(infile.val); } else if(infile.key == "upgrade_physical") { upgrade_pos[0].x = eatFirstInt(infile.val,','); upgrade_pos[0].y = eatFirstInt(infile.val,','); } else if(infile.key == "upgrade_mental") { upgrade_pos[1].x = eatFirstInt(infile.val,','); upgrade_pos[1].y = eatFirstInt(infile.val,','); } else if(infile.key == "upgrade_offense") { upgrade_pos[2].x = eatFirstInt(infile.val,','); upgrade_pos[2].y = eatFirstInt(infile.val,','); } else if(infile.key == "upgrade_defense") { upgrade_pos[3].x = eatFirstInt(infile.val,','); upgrade_pos[3].y = eatFirstInt(infile.val,','); } else if(infile.key == "statlist") { statlist_pos.x = eatFirstInt(infile.val,','); statlist_pos.y = eatFirstInt(infile.val,','); } else if(infile.key == "label_name") { label_pos[0] = eatLabelInfo(infile.val); cstat[CSTAT_NAME].visible = !label_pos[0].hidden; } else if(infile.key == "label_level") { label_pos[1] = eatLabelInfo(infile.val); cstat[CSTAT_LEVEL].visible = !label_pos[1].hidden; } else if(infile.key == "label_physical") { label_pos[2] = eatLabelInfo(infile.val); cstat[CSTAT_PHYSICAL].visible = !label_pos[2].hidden; } else if(infile.key == "label_mental") { label_pos[3] = eatLabelInfo(infile.val); cstat[CSTAT_MENTAL].visible = !label_pos[3].hidden; } else if(infile.key == "label_offense") { label_pos[4] = eatLabelInfo(infile.val); cstat[CSTAT_OFFENSE].visible = !label_pos[4].hidden; } else if(infile.key == "label_defense") { label_pos[5] = eatLabelInfo(infile.val); cstat[CSTAT_DEFENSE].visible = !label_pos[5].hidden; } else if(infile.key == "name") { value_pos[0].x = eatFirstInt(infile.val,','); value_pos[0].y = eatFirstInt(infile.val,','); value_pos[0].w = eatFirstInt(infile.val,','); value_pos[0].h = eatFirstInt(infile.val,','); } else if(infile.key == "level") { value_pos[1].x = eatFirstInt(infile.val,','); value_pos[1].y = eatFirstInt(infile.val,','); value_pos[1].w = eatFirstInt(infile.val,','); value_pos[1].h = eatFirstInt(infile.val,','); } else if(infile.key == "physical") { value_pos[2].x = eatFirstInt(infile.val,','); value_pos[2].y = eatFirstInt(infile.val,','); value_pos[2].w = eatFirstInt(infile.val,','); value_pos[2].h = eatFirstInt(infile.val,','); } else if(infile.key == "mental") { value_pos[3].x = eatFirstInt(infile.val,','); value_pos[3].y = eatFirstInt(infile.val,','); value_pos[3].w = eatFirstInt(infile.val,','); value_pos[3].h = eatFirstInt(infile.val,','); } else if(infile.key == "offense") { value_pos[4].x = eatFirstInt(infile.val,','); value_pos[4].y = eatFirstInt(infile.val,','); value_pos[4].w = eatFirstInt(infile.val,','); value_pos[4].h = eatFirstInt(infile.val,','); } else if(infile.key == "defense") { value_pos[5].x = eatFirstInt(infile.val,','); value_pos[5].y = eatFirstInt(infile.val,','); value_pos[5].w = eatFirstInt(infile.val,','); value_pos[5].h = eatFirstInt(infile.val,','); } else if(infile.key == "unspent") { value_pos[6].x = eatFirstInt(infile.val,','); value_pos[6].y = eatFirstInt(infile.val,','); value_pos[6].w = eatFirstInt(infile.val,','); value_pos[6].h = eatFirstInt(infile.val,','); } else if (infile.key == "show_unspent"){ if (eatFirstInt(infile.val,',') == 0) cstat[CSTAT_UNSPENT].visible = false; } else if (infile.key == "show_upgrade_physical"){ if (eatFirstInt(infile.val,',') == 0) show_upgrade[0] = false; } else if (infile.key == "show_upgrade_mental"){ if (eatFirstInt(infile.val,',') == 0) show_upgrade[1] = false; } else if (infile.key == "show_upgrade_offense"){ if (eatFirstInt(infile.val,',') == 0) show_upgrade[2] = false; } else if (infile.key == "show_upgrade_defense"){ if (eatFirstInt(infile.val,',') == 0) show_upgrade[3] = false; } else if (infile.key == "show_maxhp"){ if (eatFirstInt(infile.val,',') == 0) show_stat[0] = false; } else if (infile.key == "show_hpregen"){ if (eatFirstInt(infile.val,',') == 0) show_stat[1] = false; } else if (infile.key == "show_maxmp"){ if (eatFirstInt(infile.val,',') == 0) show_stat[2] = false; } else if (infile.key == "show_mpregen"){ if (eatFirstInt(infile.val,',') == 0) show_stat[3] = false; } else if (infile.key == "show_accuracy_v1"){ if (eatFirstInt(infile.val,',') == 0) show_stat[4] = false; } else if (infile.key == "show_accuracy_v5"){ if (eatFirstInt(infile.val,',') == 0) show_stat[5] = false; } else if (infile.key == "show_avoidance_v1"){ if (eatFirstInt(infile.val,',') == 0) show_stat[6] = false; } else if (infile.key == "show_avoidance_v5"){ if (eatFirstInt(infile.val,',') == 0) show_stat[7] = false; } else if (infile.key == "show_melee"){ if (eatFirstInt(infile.val,',') == 0) show_stat[8] = false; } else if (infile.key == "show_ranged"){ if (eatFirstInt(infile.val,',') == 0) show_stat[9] = false; } else if (infile.key == "show_mental"){ if (eatFirstInt(infile.val,',') == 0) show_stat[10] = false; } else if (infile.key == "show_crit"){ if (eatFirstInt(infile.val,',') == 0) show_stat[11] = false; } else if (infile.key == "show_absorb"){ if (eatFirstInt(infile.val,',') == 0) show_stat[12] = false; } else if (infile.key == "show_resists"){ if (eatFirstInt(infile.val,',') == 0) show_stat[13] = false; } } infile.close(); } else fprintf(stderr, "Unable to open menus/character.txt!\n"); loadGraphics(); }