Beispiel #1
0
void Map::loadNPC(FileParser &infile) {
	std::string s;
	if (infile.key == "type") {
		// @ATTR npc.type|string|Type of NPC
		npcs.back().id = infile.val;
	}
	if (infile.key == "requires_status") {
		// @ATTR npc.requires_status|string|Status required for NPC load. There can be multiple states, separated by comma
		while ( (s = infile.nextValue()) != "")
			npcs.back().requires_status.push_back(s);
	}
	if (infile.key == "requires_not_status") {
		// @ATTR npc.requires_not|string|Status required to be missing for NPC load. There can be multiple states, separated by comma
		while ( (s = infile.nextValue()) != "")
			npcs.back().requires_not_status.push_back(s);
	}
	else if (infile.key == "location") {
		// @ATTR npc.location|[x(integer), y(integer)]|Location of NPC
		npcs.back().pos.x = toInt(infile.nextValue()) + 0.5f;
		npcs.back().pos.y = toInt(infile.nextValue()) + 0.5f;
	}
}
Beispiel #2
0
void Map::loadNPC(FileParser &infile) {
	std::string s;
	if (infile.key == "type") {
		// @ATTR npc.type|string|Filename of an NPC definition.
		npcs.back().id = infile.val;
	}
	else if (infile.key == "requires_status") {
		// @ATTR npc.requires_status|string|Status required for NPC load. There can be multiple states, separated by comma
		while ( (s = infile.nextValue()) != "")
			npcs.back().requires_status.push_back(s);
	}
	else if (infile.key == "requires_not_status") {
		// @ATTR npc.requires_not_status|string|Status required to be missing for NPC load. There can be multiple states, separated by comma
		while ( (s = infile.nextValue()) != "")
			npcs.back().requires_not_status.push_back(s);
	}
	else if (infile.key == "location") {
		// @ATTR npc.location|[x(integer), y(integer)]|Location of NPC
		npcs.back().pos.x = static_cast<float>(toInt(infile.nextValue())) + 0.5f;
		npcs.back().pos.y = static_cast<float>(toInt(infile.nextValue())) + 0.5f;

		// make sure this NPC has a collision tile
		// otherwise, it becomes possible for the player to stand "inside" the npc, which will trigger their event infinitely
		if (collision_layer != -1) {
			unsigned tile_x = static_cast<unsigned>(npcs.back().pos.x);
			unsigned tile_y = static_cast<unsigned>(npcs.back().pos.y);
			if (tile_x < static_cast<unsigned>(w) && tile_y < static_cast<unsigned>(h)) {
				short unsigned int& tile = layers[collision_layer][tile_x][tile_y];
				if (tile == BLOCKS_NONE) {
					logError("Map: NPC at (%d, %d) does not have a collision tile. Creating one now.", tile_x, tile_y);
					tile = BLOCKS_MOVEMENT_HIDDEN;
				}
			}
		}
	}
	else {
		infile.error("Map: '%s' is not a valid key.", infile.key.c_str());
	}
}
Beispiel #3
0
void Map::loadHeader(FileParser &infile) {
	if (infile.key == "title") {
		this->title = msg->get(infile.val);
	}
	else if (infile.key == "width") {
		this->w = toInt(infile.val);
	}
	else if (infile.key == "height") {
		this->h = toInt(infile.val);
	}
	else if (infile.key == "tileset") {
		this->tileset = infile.val;
	}
	else if (infile.key == "music") {
		music_filename = infile.val;
	}
	else if (infile.key == "location") {
		spawn.x = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2;
		spawn.y = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2;
		spawn_dir = toInt(infile.nextValue());
	}
}
Beispiel #4
0
void ItemManager::loadSets(const string& filename) {
	FileParser infile;
	if (!infile.open(filename)) {
		fprintf(stderr, "Unable to open %s!\n", filename.c_str());
		return;
	}

	int id = 0;
	bool id_line;
	while (infile.next()) {
		if (infile.key == "id") {
			id_line = true;
			id = toInt(infile.val);
			if (id > 0 && id >= (int)item_sets.size()) {
				// *2 to amortize the resizing to O(log(n)).
				item_sets.resize((2*id) + 1);
			}
		} else id_line = false;

		if (id < 1) {
			if (id_line) fprintf(stderr, "Item set index out of bounds 1-%d, skipping\n", INT_MAX);
			continue;
		}
		if (id_line) continue;

		if (infile.key == "name") {
			item_sets[id].name = msg->get(infile.val);
		}
		else if (infile.key == "items") {
			string item_id = infile.nextValue();
			while (item_id != "") {
				if (toInt(item_id) > 0) {
					items[toInt(item_id)].set = id;
					item_sets[id].items.push_back(toInt(item_id));
					item_id = infile.nextValue();
				} else fprintf(stderr, "Item index inside item set %s definition out of bounds 1-%d, skipping item\n", item_sets[id].name.c_str(), INT_MAX);
			}
		}
		else if (infile.key == "color") {
			item_sets[id].color.r = toInt(infile.nextValue());
			item_sets[id].color.g = toInt(infile.nextValue());
			item_sets[id].color.b = toInt(infile.nextValue());
		}
		else if (infile.key == "bonus") {
			Set_bonus bonus;
			bonus.requirement = toInt(infile.nextValue());
			bonus.bonus_stat = infile.nextValue();
			bonus.bonus_val = toInt(infile.nextValue());
			item_sets[id].bonus.push_back(bonus);
		}
	}
	infile.close();
}
Beispiel #5
0
void Map::loadEnemyGroup(FileParser &infile, Map_Group *group) {
	if (infile.key == "type") {
		group->category = infile.val;
	}
	else if (infile.key == "level") {
		group->levelmin = toInt(infile.nextValue());
		group->levelmax = toInt(infile.nextValue());
	}
	else if (infile.key == "location") {
		group->pos.x = toInt(infile.nextValue());
		group->pos.y = toInt(infile.nextValue());
		group->area.x = toInt(infile.nextValue());
		group->area.y = toInt(infile.nextValue());
	}
	else if (infile.key == "number") {
		group->numbermin = toInt(infile.nextValue());
		group->numbermax = toInt(infile.nextValue());
	}
	else if (infile.key == "chance") {
		float n = toInt(infile.nextValue()) / 100.0f;
		group->chance = std::min(1.0f, std::max(0.0f, n));
	}
}
bool GameStateConfig::getLanguagesList() {
	FileParser infile;
	if (infile.open("engine/languages.txt")) {
		unsigned int i=0;
		while (infile.next()) {
			language_ISO[i] = infile.key;
			language_full[i] = infile.nextValue();
			i += 1;
		}
		infile.close();
	}

	return true;
}
Beispiel #7
0
bool GameStateConfig::getLanguagesList()
{
	FileParser infile;
	if (infile.open(mods->locate("engine/languages.txt"))) {
		unsigned int i=0;
		while (infile.next()) {
			   language_ISO[i] = infile.key;
			   language_full[i] = infile.nextValue();
			   i += 1;
			}
		} else fprintf(stderr, "Unable to open languages.txt!\n");
		infile.close();

	return true;
}
Beispiel #8
0
void GameStateLoad::readGameSlot(int slot) {

	stringstream filename;
	FileParser infile;
	
	// abort if not a valid slot number
	if (slot < 0 || slot >= GAME_SLOT_MAX) return;

	// save slots are named save#.txt
	filename << "saves/save" << (slot+1) << ".txt";

	if (!infile.open(filename.str())) return;
	
	while (infile.next()) {
	
		// load (key=value) pairs
		if (infile.key == "name")
			stats[slot].name = infile.val;
		else if (infile.key == "xp")
			stats[slot].xp = atoi(infile.val.c_str());
		else if (infile.key == "build") {
			stats[slot].physical_character = atoi(infile.nextValue().c_str());
			stats[slot].mental_character = atoi(infile.nextValue().c_str());
			stats[slot].offense_character = atoi(infile.nextValue().c_str());
			stats[slot].defense_character = atoi(infile.nextValue().c_str());
		}
		else if (infile.key == "equipped") {
			equipped[slot][0] = atoi(infile.nextValue().c_str());
			equipped[slot][1] = atoi(infile.nextValue().c_str());
			equipped[slot][2] = atoi(infile.nextValue().c_str());
		}
		else if (infile.key == "option") {
			stats[slot].base = infile.nextValue();
			stats[slot].head = infile.nextValue();
			stats[slot].portrait = infile.nextValue();
		}
		else if (infile.key == "spawn") {
			current_map[slot] = getMapName(infile.nextValue());
		}
	}
	infile.close();
	
	stats[slot].recalc();
	loadPreview(slot);

}
Beispiel #9
0
void Map::loadEnemy(FileParser &infile) {
	if (infile.key == "type") {
		// @ATTR enemy.type|string|Enemy type
		enemies.back().type = infile.val;
	}
	else if (infile.key == "location") {
		// @ATTR enemy.location|[x(integer), y(integer)]|Location of enemy
		enemies.back().pos.x = toInt(infile.nextValue()) + 0.5f;
		enemies.back().pos.y = toInt(infile.nextValue()) + 0.5f;
	}
	else if (infile.key == "direction") {
		// @ATTR enemy.direction|integer|Direction of enemy
		enemies.back().direction = toInt(infile.val);
	}
	else if (infile.key == "waypoints") {
		// @ATTR enemy.waypoint|[x(integer), y(integer)]|Enemy waypoint
		std::string none = "";
		std::string a = infile.nextValue();
		std::string b = infile.nextValue();

		while (a != none) {
			FPoint p;
			p.x = toInt(a) + 0.5f;
			p.y = toInt(b) + 0.5f;
			enemies.back().waypoints.push(p);
			a = infile.nextValue();
			b = infile.nextValue();
		}
	}
	else if (infile.key == "wander_area") {
		// @ATTR enemy.wander_area|[x(integer),y(integer),w(integer),h(integer)]|Wander area for the enemy.
		enemies.back().wander = true;
		enemies.back().wander_area.x = toInt(infile.nextValue());
		enemies.back().wander_area.y = toInt(infile.nextValue());
		enemies.back().wander_area.w = toInt(infile.nextValue());
		enemies.back().wander_area.h = toInt(infile.nextValue());
	}
	// @ATTR enemy.requires_status|string|Status required for enemy load
	else if (infile.key == "requires_status")
        enemies.back().requires_status.push_back(infile.nextValue());
    // @ATTR enemy.requires_not_status|string|Status required to be missing for enemy load
	else if (infile.key == "requires_not_status")
        enemies.back().requires_not_status.push_back(infile.nextValue());
}
Beispiel #10
0
void loadTilesetSettings() {
	FileParser infile;
	// load tileset settings from engine config
	if (infile.open(mods->locate("engine/tileset_config.txt").c_str())) {
		while (infile.next()) {
			if (infile.key == "units_per_tile") {
				UNITS_PER_TILE = atoi(infile.val.c_str());
			}
			else if (infile.key == "tile_size") {
				TILE_W = atoi(infile.nextValue().c_str());
				TILE_H = atoi(infile.nextValue().c_str());
				TILE_W_HALF = TILE_W /2;
				TILE_H_HALF = TILE_H /2;
			}
			else if (infile.key == "orientation") {
				if (infile.val == "isometric")
					TILESET_ORIENTATION = TILESET_ISOMETRIC;
				else if (infile.val == "orthogonal")
					TILESET_ORIENTATION = TILESET_ORTHOGONAL;
			}
		}
		infile.close();
	}
	else {
		fprintf(stderr, "No tileset config found! Defaulting to 64x32 isometric tiles.\n");
	}

	// Init automatically calculated parameters
	TILE_SHIFT = log2(UNITS_PER_TILE);
	VIEW_W_HALF = VIEW_W / 2;
	VIEW_H_HALF = VIEW_H / 2;
	if (TILESET_ORIENTATION == TILESET_ISOMETRIC) {
		UNITS_PER_PIXEL_X = UNITS_PER_TILE / TILE_W * 2;
		UNITS_PER_PIXEL_Y = UNITS_PER_TILE / TILE_H * 2;
	}
	else { // TILESET_ORTHOGONAL
		UNITS_PER_PIXEL_X = UNITS_PER_TILE / TILE_W;
		UNITS_PER_PIXEL_Y = UNITS_PER_TILE / TILE_H;
	}
}
Beispiel #11
0
void EnemyGroupManager::parseEnemyFileAndStore(const string& filename) {
	FileParser infile;
	if (infile.open(mods->locate("enemies/" + filename))) {
		Enemy_Level new_enemy;
		new_enemy.type = filename.substr(0, filename.length()-4); //removes the ".txt" from the filename
		while (infile.next()) {
			if (infile.key == "level") {
				new_enemy.level = atoi(infile.val.c_str());
			}
			else if (infile.key == "rarity") {
				new_enemy.rarity = infile.val.c_str();
			}
			else if (infile.key == "categories") {
				string cat;
				while ( (cat = infile.nextValue()) != "") {
					_categories[cat].push_back(new_enemy);
				}
			}
		}
		infile.close();
	}
}
Beispiel #12
0
void loadTilesetSettings() {
	FileParser infile;
	// load tileset settings from engine config
	if (infile.open("engine/tileset_config.txt", true, true, "Unable to open engine/tileset_config.txt! Defaulting to 64x32 isometric tiles.\n")) {
		while (infile.next()) {
			if (infile.key == "tile_size") {
				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") {
				if (infile.val == "isometric")
					TILESET_ORIENTATION = TILESET_ISOMETRIC;
				else if (infile.val == "orthogonal")
					TILESET_ORIENTATION = TILESET_ORTHOGONAL;
			}
		}
		infile.close();
	}

	// Init automatically calculated parameters
	VIEW_W_HALF = VIEW_W / 2;
	VIEW_H_HALF = VIEW_H / 2;
	if (TILESET_ORIENTATION == TILESET_ISOMETRIC) {
		UNITS_PER_PIXEL_X = 2.0f / TILE_W;
		UNITS_PER_PIXEL_Y = 2.0f / TILE_H;
	}
	else { // TILESET_ORTHOGONAL
		UNITS_PER_PIXEL_X = 1.0f / TILE_W;
		UNITS_PER_PIXEL_Y = 1.0f / TILE_H;
	}
	if (UNITS_PER_PIXEL_X == 0 || UNITS_PER_PIXEL_Y == 0) {
		fprintf(stderr, "One of UNITS_PER_PIXEL values is zero! %dx%d\n", (int)UNITS_PER_PIXEL_X, (int)UNITS_PER_PIXEL_Y);
		SDL_Quit();
		exit(1);
	}
}
void EnemyGroupManager::parseEnemyFilesAndStore() {
	std::vector<std::string> enemy_paths = mods->list("enemies", false);

	for (unsigned i=0; i<enemy_paths.size(); ++i) {
		FileParser infile;

		// @CLASS EnemyGroupManager|Description of enemies in enemies/
		if (!infile.open(enemy_paths[i]))
			return;

		Enemy_Level new_enemy;
		infile.new_section = true;
		bool first = true;
		while (infile.next()) {
			if (infile.new_section || first) {
				new_enemy.type = enemy_paths[i];
				first = false;
			}

			if (infile.key == "level") {
				// @ATTR level|integer|Level of the enemy
				new_enemy.level = toInt(infile.val);
			}
			else if (infile.key == "rarity") {
				// @ATTR rarity|[common,uncommon,rare]|Enemy rarity
				new_enemy.rarity = infile.val;
			}
			else if (infile.key == "categories") {
				// @ATTR categories|string,...|Comma separated list of enemy categories
				string cat;
				while ( (cat = infile.nextValue()) != "") {
					_categories[cat].push_back(new_enemy);
				}
			}
		}
		infile.close();
	}
}
void EnemyGroupManager::parseEnemyFilesAndStore() {
	FileParser infile;

	// @CLASS enemies|Describing enemies files in enemies/
	if (!infile.open("enemies", true, false))
		return;

	Enemy_Level new_enemy;
	infile.new_section = true;
	bool first = true;
	while (infile.next()) {
		if (infile.new_section || first) {
			const string fname = infile.getFileName();
			const int firstpos = fname.rfind("/") + 1;
			const int len = fname.length() - firstpos - 4; //removes the ".txt" from the filename
			new_enemy.type = fname.substr(firstpos, len);
			first = false;
		}

		if (infile.key == "level") {
			// @ATTR level|integer|Level of the enemy
			new_enemy.level = toInt(infile.val);
		}
		else if (infile.key == "rarity") {
			// @ATTR rarity|[common,uncommon,rare]|Enemy rarity
			new_enemy.rarity = infile.val;
		}
		else if (infile.key == "categories") {
			// @ATTR categories|string,...|Comma separated list of enemy categories
			string cat;
			while ( (cat = infile.nextValue()) != "") {
				_categories[cat].push_back(new_enemy);
			}
		}
	}
	infile.close();
}
Beispiel #15
0
/**
 * 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 = toInt(infile.val);

			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 == "item_class") {
				string str;
				while ((str = infile.nextValue()) != "") {
					if (!isInt(str)) {
						item_classes.push_back(str);
						item_class_prob.push_back(1);
						item_class_prob_sum++;
					}
					else {
						num = toInt(str);
						item_class_prob[item_classes.size()-1] = num;
						item_class_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 = toInt(infile.nextValue());
			}
			// 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;

			// 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;

			// hp countdown
			else if (infile.key == "hp_countdown_ticks") hp_countdown_ticks = num;

			// hide enemy HP bar
			else if (infile.key == "suppress_hp") suppress_hp = num;

			for (unsigned int i=0; i<ELEMENTS.size(); i++) {
				if (infile.key == "vulnerable_" + ELEMENTS[i].name) vulnerable[i] = num;
			}
		}
		infile.close();
	} else fprintf(stderr, "Unable to open %s!\n", filename.c_str());
}
Beispiel #16
0
/**
 * NPCs are stored in simple config files
 *
 * @param npc_id Config file for npc
 */
void NPC::load(const std::string& npc_id) {

	FileParser infile;
	ItemStack stack;

	std::string filename_portrait = "";

	bool clear_random_table = true;

	// @CLASS NPC|Description of NPCs in npcs/
	if (infile.open(npc_id)) {
		while (infile.next()) {
			if (infile.section == "dialog") {
				if (infile.new_section) {
					dialog.push_back(std::vector<Event_Component>());
				}
				Event_Component e;
				e.type = EC_NONE;
				if (infile.key == "him" || infile.key == "her") {
					// @ATTR dialog.him, dialog.her|string|A line of dialog from the NPC.
					e.type = EC_NPC_DIALOG_THEM;
					e.s = msg->get(infile.val);
				}
				else if (infile.key == "you") {
					// @ATTR dialog.you|string|A line of dialog from the player.
					e.type = EC_NPC_DIALOG_YOU;
					e.s = msg->get(infile.val);
				}
				else if (infile.key == "voice") {
					// @ATTR dialog.voice|string|Filename of a voice sound file to play.
					e.type = EC_NPC_VOICE;
					e.x = loadSound(infile.val, NPC_VOX_QUEST);
				}
				else if (infile.key == "topic") {
					// @ATTR dialog.topic|string|The name of this dialog topic. Displayed when picking a dialog tree.
					e.type = EC_NPC_DIALOG_TOPIC;
					e.s = msg->get(infile.val);
				}
				else if (infile.key == "group") {
					// @ATTR dialog.group|string|Dialog group.
					e.type = EC_NPC_DIALOG_GROUP;
					e.s = infile.val;
				}
				else if (infile.key == "allow_movement") {
					// @ATTR dialog.allow_movement|boolean|Restrict the player's mvoement during dialog.
					e.type = EC_NPC_ALLOW_MOVEMENT;
					e.s = infile.val;
				}
				else {
					Event ev;
					EventManager::loadEventComponent(infile, &ev, NULL);

					for (size_t i=0; i<ev.components.size(); ++i) {
						if (ev.components[i].type != EC_NONE) {
							dialog.back().push_back(ev.components[i]);
						}
					}
				}

				if (e.type != EC_NONE) {
					dialog.back().push_back(e);
				}
			}
			else {
				filename = npc_id;

				if (infile.new_section) {
					// APPENDed file
					clear_random_table = true;
				}

				if (infile.key == "name") {
					// @ATTR name|string|NPC's name.
					name = msg->get(infile.val);
				}
				else if (infile.key == "gfx") {
					// @ATTR gfx|string|Filename of an animation definition.
					gfx = infile.val;
				}

				// handle talkers
				else if (infile.key == "talker") {
					// @ATTR talker|boolean|Allows this NPC to be talked to.
					talker = toBool(infile.val);
				}
				else if (infile.key == "portrait") {
					// @ATTR portrait|string|Filename of a portrait image.
					filename_portrait = infile.val;
				}

				// handle vendors
				else if (infile.key == "vendor") {
					// @ATTR vendor|string|Allows this NPC to buy/sell items.
					vendor = toBool(infile.val);
				}
				else if (infile.key == "constant_stock") {
					// @ATTR constant_stock|item (integer), ...|A list of items this vendor has for sale.
					stack.quantity = 1;
					while (infile.val != "") {
						stack.item = toInt(infile.nextValue());
						stock.add(stack);
					}
				}
				else if (infile.key == "status_stock") {
					// @ATTR status_stock|status (string), item (integer), ...|A list of items this vendor will have for sale if the required status is met.
					if (camp->checkStatus(infile.nextValue())) {
						stack.quantity = 1;
						while (infile.val != "") {
							stack.item = toInt(infile.nextValue());
							stock.add(stack);
						}
					}
				}
				else if (infile.key == "random_stock") {
					// @ATTR random_stock|[string,drop_chance([fixed:chance(integer)]),quantity_min(integer),quantity_max(integer)],...|Use a loot table to add random items to the stock; either a filename or an inline definition.
					if (clear_random_table) {
						random_table.clear();
						clear_random_table = false;
					}

					random_table.push_back(Event_Component());
					loot->parseLoot(infile, &random_table.back(), &random_table);
				}
				else if (infile.key == "random_stock_count") {
					// @ATTR random_stock_count|min (integer), max (integer)|Sets the minimum (and optionally, the maximum) amount of random items this npc can have.
					random_table_count.x = toInt(infile.nextValue());
					random_table_count.y = toInt(infile.nextValue());
					if (random_table_count.x != 0 || random_table_count.y != 0) {
						clampFloor(random_table_count.x, 1);
						clampFloor(random_table_count.y, random_table_count.x);
					}
				}

				// handle vocals
				else if (infile.key == "vox_intro") {
					// @ATTR vox_intro|string|Filename of a sound file to play when initially interacting with the NPC.
					loadSound(infile.val, NPC_VOX_INTRO);
				}

				else {
					infile.error("NPC: '%s' is not a valid key.", infile.key.c_str());
				}
			}
		}
		infile.close();
	}
	loadGraphics(filename_portrait);

	// fill inventory with items from random stock table
	unsigned rand_count = randBetween(random_table_count.x, random_table_count.y);

	std::vector<ItemStack> rand_itemstacks;
	for (unsigned i=0; i<rand_count; ++i) {
		loot->checkLoot(random_table, NULL, &rand_itemstacks);
	}
	std::sort(rand_itemstacks.begin(), rand_itemstacks.end(), compareItemStack);
	for (size_t i=0; i<rand_itemstacks.size(); ++i) {
		stock.add(rand_itemstacks[i]);
	}
}
Beispiel #17
0
void AnimationSet::load() {
	assert(!loaded);
	loaded = true;

	FileParser parser;
	const string filename = mods->locate(name);

	if (!parser.open(filename, "Error loading animation definition: " + name))
		return;

	string _name = "";
	int position = 0;
	int frames = 0;
	int duration = 0;
	Point render_size;
	Point render_offset;
	string type = "";
	string starting_animation = "";
	bool first_section=true;
	bool compressed_loading=false; // is reset every section to false, set by frame keyword
	Animation *newanim = NULL;
	vector<short> active_frames;

	// Parse the file and on each new section create an animation object from the data parsed previously
	parser.next();

	do {
		// 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 (parser.key == "image") {
			if (sprite) {
				printf("multiple images specified in %s, dragons be here!\n", name.c_str());
				SDL_Quit();
				exit(128);
			}
			imagefile = parser.val;
			imag->increaseCount(imagefile);
			sprite = imag->getSurface(imagefile);
		}
		else if (parser.key == "position") {
			position = toInt(parser.val);
		}
		else if (parser.key == "frames") {
			frames = toInt(parser.val);
		}
		else if (parser.key == "duration") {
			duration = toInt(parser.val);

			// TEMP: if an animation is too fast, display one frame per fps anyway
			if (duration < 1) duration=1;
		}
		else if (parser.key == "type")
			type = parser.val;
		else if (parser.key == "render_size") {
			render_size.x = toInt(parser.nextValue());
			render_size.y = toInt(parser.nextValue());
		}
		else if (parser.key == "render_offset") {
			render_offset.x = toInt(parser.nextValue());
			render_offset.y = toInt(parser.nextValue());
		}
		else if (parser.key == "active_frame") {
			active_frames.clear();
			string nv = parser.nextValue();
			if (nv == "all") {
				active_frames.push_back(-1);
			}
			else {
				while (nv != "") {
					active_frames.push_back(toInt(nv));
					nv = parser.nextValue();
				}
				sort(active_frames.begin(), active_frames.end());
				active_frames.erase(unique(active_frames.begin(), active_frames.end()), active_frames.end());
			}
		}
		else if (parser.key == "frame") {
			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
			SDL_Rect r;
			Point offset;
			const int index = toInt(parser.nextValue());
			const int direction = 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 {
			fprintf(stderr, "animations definitions (%s): Key %s not supported!\n", filename.c_str(), parser.key.c_str());
		}

		if (_name == "") {
			// This is the first animation
			starting_animation = parser.section;
		}
		_name = parser.section;
	}
	while (parser.next());

	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;
	}
}
Beispiel #18
0
/**
 * 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;
	if (!infile.open(filename)) {
		fprintf(stderr, "Unable to open %s!\n", filename.c_str());
		return;
	}

	int id = 0;
	bool id_line = false;
	while (infile.next()) {
		if (infile.key == "id") {
			id_line = true;
			id = toInt(infile.val);
			ensureFitsId(items, id+1);
		} else id_line = false;

		if (id < 1) {
			if (id_line) fprintf(stderr, "Item index out of bounds 1-%d, skipping\n", INT_MAX);
			continue;
		}
		if (id_line) continue;

		assert(items.size() > std::size_t(id));

		if (infile.key == "name")
			items[id].name = msg->get(infile.val);
		else if (infile.key == "flavor")
			items[id].flavor = msg->get(infile.val);
		else if (infile.key == "level")
			items[id].level = toInt(infile.val);
		else if (infile.key == "icon") {
			items[id].icon = toInt(infile.nextValue());
		}
		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 == "item_type") {
				items[id].type = infile.val;
		}
		else if (infile.key == "dmg_melee") {
			items[id].dmg_melee_min = toInt(infile.nextValue());
			if (infile.val.length() > 0)
				items[id].dmg_melee_max = toInt(infile.nextValue());
			else
				items[id].dmg_melee_max = items[id].dmg_melee_min;
		}
		else if (infile.key == "dmg_ranged") {
			items[id].dmg_ranged_min = toInt(infile.nextValue());
			if (infile.val.length() > 0)
				items[id].dmg_ranged_max = toInt(infile.nextValue());
			else
				items[id].dmg_ranged_max = items[id].dmg_ranged_min;
		}
		else if (infile.key == "dmg_ment") {
			items[id].dmg_ment_min = toInt(infile.nextValue());
			if (infile.val.length() > 0)
				items[id].dmg_ment_max = toInt(infile.nextValue());
			else
				items[id].dmg_ment_max = items[id].dmg_ment_min;
		}
		else if (infile.key == "abs") {
			items[id].abs_min = toInt(infile.nextValue());
			if (infile.val.length() > 0)
				items[id].abs_max = toInt(infile.nextValue());
			else
				items[id].abs_max = items[id].abs_min;
		}
		else if (infile.key == "req") {
			string 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 = toInt(infile.nextValue());
		}
		else if (infile.key == "bonus") {
			items[id].bonus_stat.push_back(infile.nextValue());
			items[id].bonus_val.push_back(toInt(infile.nextValue()));
		}
		else if (infile.key == "soundfx") {
			items[id].sfx = snd->load(infile.val, "ItemManager");
		}
		else if (infile.key == "gfx")
			items[id].gfx = infile.val;
		else if (infile.key == "loot_animation")
			items[id].loot_animation = infile.val;
		else if (infile.key == "power") {
			if (toInt(infile.val) > 0) {
				items[id].power = toInt(infile.val);
			}
			else fprintf(stderr, "Power index inside item %d definition out of bounds 1-%d, skipping item\n", id, INT_MAX);
		}
		else if (infile.key == "power_mod")
			items[id].power_mod = toInt(infile.val);
		else if (infile.key == "power_desc")
			items[id].power_desc = msg->get(infile.val);
		else if (infile.key == "price")
			items[id].price = toInt(infile.val);
		else if (infile.key == "price_sell")
			items[id].price_sell = toInt(infile.val);
		else if (infile.key == "max_quantity")
			items[id].max_quantity = toInt(infile.val);
		else if (infile.key == "rand_loot")
			items[id].rand_loot = toInt(infile.val);
		else if (infile.key == "rand_vendor")
			items[id].rand_vendor = toInt(infile.val);
		else if (infile.key == "pickup_status")
			items[id].pickup_status = infile.val;
		else if (infile.key == "stepfx")
			items[id].stepfx = infile.val;
		else if (infile.key == "class") {
			string classname = infile.nextValue();
			while (classname != "") {
				unsigned pos; // find the position where this classname is stored:
				for (pos = 0; pos < item_class_names.size(); pos++) {
					if (item_class_names[pos] == classname)
						break;
				}
				// if it was not found, add it to the end.
				// pos is already the correct index.
				if (pos == item_class_names.size()) {
					item_class_names.push_back(classname);
					item_class_items.push_back(vector<unsigned int>());
				}
				// add item id to the item list of that class:
				item_class_items[pos].push_back(id);
				classname = infile.nextValue();
			}
		}

	}
	infile.close();
}
Beispiel #19
0
/**
 * 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 = toInt(infile.val);
		// animation info
		else if (infile.key == "animation")
			powers[input_id].animation_name = "animations/powers/" + infile.val;
		else if (infile.key == "sfx")
			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 = toInt(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 = toInt(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);
		// 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();
}
Beispiel #20
0
void Map::loadEnemyGroup(FileParser &infile, Map_Group *group) {
	if (infile.key == "type") {
		// @ATTR enemygroup.type|string|The category of enemies that will spawn in this group.
		group->category = infile.val;
	}
	else if (infile.key == "level") {
		// @ATTR enemygroup.level|[min(integer), max(integer)]|Defines the level range of enemies in group. If only one number is given, it's the exact level.
		group->levelmin = std::max(0, toInt(infile.nextValue()));
		group->levelmax = std::max(0, toInt(infile.nextValue(), group->levelmin));
	}
	else if (infile.key == "location") {
		// @ATTR enemygroup.location|[x(integer), y(integer), x2(integer), y2(integer)]|Location area for enemygroup
		group->pos.x = toInt(infile.nextValue());
		group->pos.y = toInt(infile.nextValue());
		group->area.x = toInt(infile.nextValue());
		group->area.y = toInt(infile.nextValue());
	}
	else if (infile.key == "number") {
		// @ATTR enemygroup.number|[min(integer), max(integer]|Defines the range of enemies in group. If only one number is given, it's the exact amount.
		group->numbermin = std::max(0, toInt(infile.nextValue()));
		group->numbermax = std::max(0, toInt(infile.nextValue(), group->numbermin));
	}
	else if (infile.key == "chance") {
		// @ATTR enemygroup.chance|integer|Percentage of chance
		float n = static_cast<float>(std::max(0, toInt(infile.nextValue()))) / 100.0f;
		group->chance = std::min(1.0f, std::max(0.0f, n));
	}
	else if (infile.key == "direction") {
		// @ATTR enemygroup.direction|direction|Direction that enemies will initially face.
		group->direction = parse_direction(infile.val);
	}
	else if (infile.key == "waypoints") {
		// @ATTR enemygroup.waypoints|[x(integer), y(integer)]|Enemy waypoints; single enemy only; negates wander_radius
		std::string none = "";
		std::string a = infile.nextValue();
		std::string b = infile.nextValue();

		while (a != none) {
			FPoint p;
			p.x = static_cast<float>(toInt(a)) + 0.5f;
			p.y = static_cast<float>(toInt(b)) + 0.5f;
			group->waypoints.push(p);
			a = infile.nextValue();
			b = infile.nextValue();
		}

		// disable wander radius, since we can't have waypoints and wandering at the same time
		group->wander_radius = 0;
	}
	else if (infile.key == "wander_radius") {
		// @ATTR enemygroup.wander_radius|integer|The radius (in tiles) that an enemy will wander around randomly; negates waypoints
		group->wander_radius = std::max(0, toInt(infile.nextValue()));

		// clear waypoints, since wandering will use the waypoint queue
		while (!group->waypoints.empty()) {
			group->waypoints.pop();
		}
	}
	else if (infile.key == "requires_status") {
		// @ATTR enemygroup.requires_status|string|Status required for loading enemies
		group->requires_status.push_back(infile.nextValue());
	}
	else if (infile.key == "requires_not_status") {
		// @ATTR enemygroup.requires_not_status|string|Status required to be missing for loading enemies
		group->requires_not_status.push_back(infile.nextValue());
	}
	else {
		infile.error("Map: '%s' is not a valid key.", infile.key.c_str());
	}
}
Beispiel #21
0
/**
 * load
 */
int MapRenderer::load(string filename) {
	FileParser infile;
	string val;
	string cur_layer;
	string data_format;

	clearEvents();

	bool collider_set = false;

	if (infile.open(mods->locate("maps/" + filename))) {
		while (infile.next()) {
			if (infile.new_section) {
				data_format = "dec"; // default

				if (enemy_awaiting_queue) {
					enemies.push(new_enemy);
					enemy_awaiting_queue = false;
				}
				if (npc_awaiting_queue) {
					npcs.push(new_npc);
					npc_awaiting_queue = false;
				}
				if (group_awaiting_queue) {
					push_enemy_group(new_group);
					group_awaiting_queue = false;
				}

				// for sections that are stored in collections, add a new object here
				if (infile.section == "enemy") {
					new_enemy.clear();
					enemy_awaiting_queue = true;
				}
				else if (infile.section == "enemygroup") {
					new_group.clear();
					group_awaiting_queue = true;
				}
				else if (infile.section == "npc") {
					new_npc.clear();
					npc_awaiting_queue = true;
				}
				else if (infile.section == "event") {
					events.push_back(Map_Event());
				}

			}
			if (infile.section == "header") {
				if (infile.key == "title") {
					this->title = msg->get(infile.val);
				}
				else if (infile.key == "width") {
					this->w = atoi(infile.val.c_str());
				}
				else if (infile.key == "height") {
					this->h = atoi(infile.val.c_str());
				}
				else if (infile.key == "tileset") {
					this->tileset = infile.val;
				}
				else if (infile.key == "music") {
					if (this->music_filename == infile.val) {
						this->new_music = false;
					}
					else {
						this->music_filename = infile.val;
						this->new_music = true;
					}
				}
				else if (infile.key == "location") {
					spawn.x = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE/2;
					spawn.y = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE/2;
					spawn_dir = atoi(infile.nextValue().c_str());
				}
			}
			else if (infile.section == "layer") {
				if (infile.key == "type") {
					cur_layer = infile.val;
				}
				else if (infile.key == "format") {
					data_format = infile.val;
				}
				else if (infile.key == "data") {
					// layer map data handled as a special case

					// The next h lines must contain layer data.  TODO: err
					if (data_format == "hex") {
						for (int j=0; j<h; j++) {
							val = infile.getRawLine() + ',';
							for (int i=0; i<w; i++) {
								if (cur_layer == "background") background[i][j] = eatFirstHex(val, ',');
								else if (cur_layer == "object") object[i][j] = eatFirstHex(val, ',');
								else if (cur_layer == "collision") collision[i][j] = eatFirstHex(val, ',');
							}
						}
					}
					else if (data_format == "dec") {
						for (int j=0; j<h; j++) {
							val = infile.getRawLine() + ',';
							for (int i=0; i<w; i++) {
								if (cur_layer == "background") background[i][j] = eatFirstInt(val, ',');
								else if (cur_layer == "object") object[i][j] = eatFirstInt(val, ',');
								else if (cur_layer == "collision") collision[i][j] = eatFirstInt(val, ',');
							}
						}
					}
					if ((cur_layer == "collision") && !collider_set) {
						collider.setmap(collision);
						collider.map_size.x = w;
						collider.map_size.y = h;
					}
				}
			}
			else if (infile.section == "enemy") {
				if (infile.key == "type") {
					new_enemy.type = infile.val;
				}
				else if (infile.key == "location") {
					new_enemy.pos.x = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE/2;
					new_enemy.pos.y = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE/2;
				}
				else if (infile.key == "direction") {
					new_enemy.direction = atoi(infile.val.c_str());
				}
				else if (infile.key == "waypoints") {
					string none = "";
					string a = infile.nextValue();
					string b = infile.nextValue();

					while (a != none) {
						Point p;
						p.x = atoi(a.c_str()) * UNITS_PER_TILE + UNITS_PER_TILE / 2;
						p.y = atoi(b.c_str()) * UNITS_PER_TILE + UNITS_PER_TILE / 2;
						new_enemy.waypoints.push(p);
						a = infile.nextValue();
						b = infile.nextValue();
					}
				} else if (infile.key == "wander_area") {
					new_enemy.wander = true;
					new_enemy.wander_area.x = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE / 2;
					new_enemy.wander_area.y = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE / 2;
					new_enemy.wander_area.w = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE / 2;
					new_enemy.wander_area.h = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE / 2;
				}
			}
			else if (infile.section == "enemygroup") {
				if (infile.key == "type") {
					new_group.category = infile.val;
				}
				else if (infile.key == "level") {
					new_group.levelmin = atoi(infile.nextValue().c_str());
					new_group.levelmax = atoi(infile.nextValue().c_str());
				}
				else if (infile.key == "location") {
					new_group.pos.x = atoi(infile.nextValue().c_str());
					new_group.pos.y = atoi(infile.nextValue().c_str());
					new_group.area.x = atoi(infile.nextValue().c_str());
					new_group.area.y = atoi(infile.nextValue().c_str());
				}
				else if (infile.key == "number") {
					new_group.numbermin = atoi(infile.nextValue().c_str());
					new_group.numbermax = atoi(infile.nextValue().c_str());
				}
				else if (infile.key == "chance") {
					new_group.chance = atoi(infile.nextValue().c_str()) / 100.0f;
					if (new_group.chance > 1.0f) {
						new_group.chance = 1.0f;
					}
					if (new_group.chance < 0.0f) {
						new_group.chance = 0.0f;
					}
				}
			}
			else if (infile.section == "npc") {
				if (infile.key == "type") {
					new_npc.id = infile.val;
				}
				else if (infile.key == "location") {
					new_npc.pos.x = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE/2;
					new_npc.pos.y = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE/2;
				}
			}
			else if (infile.section == "event") {
				if (infile.key == "type") {
					events.back().type = infile.val;
				}
				else if (infile.key == "location") {
					events.back().location.x = atoi(infile.nextValue().c_str());
					events.back().location.y = atoi(infile.nextValue().c_str());
					events.back().location.w = atoi(infile.nextValue().c_str());
					events.back().location.h = atoi(infile.nextValue().c_str());
				}
				else if (infile.key == "hotspot") {
					events.back().hotspot.x = atoi(infile.nextValue().c_str());
					events.back().hotspot.y = atoi(infile.nextValue().c_str());
					events.back().hotspot.w = atoi(infile.nextValue().c_str());
					events.back().hotspot.h = atoi(infile.nextValue().c_str());
				}
				else if (infile.key == "tooltip") {
					events.back().tooltip = msg->get(infile.val);
				}
				else if (infile.key == "power_path") {
					events.back().power_src.x = atoi(infile.nextValue().c_str());
					events.back().power_src.y = atoi(infile.nextValue().c_str());
					string dest = infile.nextValue();
					if (dest == "hero") {
						events.back().targetHero = true;
					}
					else {
						events.back().power_dest.x = atoi(dest.c_str());
						events.back().power_dest.y = atoi(infile.nextValue().c_str());
					}
				}
				else if (infile.key == "power_damage") {
					events.back().damagemin = atoi(infile.nextValue().c_str());
					events.back().damagemax = atoi(infile.nextValue().c_str());
				}
				else if (infile.key == "cooldown") {
					events.back().cooldown = atoi(infile.val.c_str());
				}
				else {
					// new event component
					Event_Component *e = &(events.back()).components[events.back().comp_num];
					e->type = infile.key;

					if (infile.key == "intermap") {
						e->s = infile.nextValue();
						e->x = atoi(infile.nextValue().c_str());
						e->y = atoi(infile.nextValue().c_str());
					}
					else if (infile.key == "intramap") {
						e->x = atoi(infile.nextValue().c_str());
						e->y = atoi(infile.nextValue().c_str());
					}
					else if (infile.key == "mapmod") {
						e->s = infile.nextValue();
						e->x = atoi(infile.nextValue().c_str());
						e->y = atoi(infile.nextValue().c_str());
						e->z = atoi(infile.nextValue().c_str());

						// add repeating mapmods
						string repeat_val = infile.nextValue();
						while (repeat_val != "") {
							events.back().comp_num++;
							e = &events.back().components[events.back().comp_num];
							e->type = infile.key;
							e->s = repeat_val;
							e->x = atoi(infile.nextValue().c_str());
							e->y = atoi(infile.nextValue().c_str());
							e->z = atoi(infile.nextValue().c_str());

							repeat_val = infile.nextValue();
						}
					}
					else if (infile.key == "soundfx") {
						e->s = infile.val;
					}
					else if (infile.key == "loot") {
						e->s = infile.nextValue();
						e->x = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE/2;
						e->y = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE/2;
						e->z = atoi(infile.nextValue().c_str());

						// add repeating loot
						string repeat_val = infile.nextValue();
						while (repeat_val != "") {
							events.back().comp_num++;
							e = &events.back().components[events.back().comp_num];
							e->type = infile.key;
							e->s = repeat_val;
							e->x = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE/2;
							e->y = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE/2;
							e->z = atoi(infile.nextValue().c_str());

							repeat_val = infile.nextValue();
						}
					}
					else if (infile.key == "msg") {
						e->s = msg->get(infile.val);
					}
					else if (infile.key == "shakycam") {
						e->x = atoi(infile.val.c_str());
					}
					else if (infile.key == "requires_status") {
						e->s = infile.nextValue();

						// add repeating requires_status
						string repeat_val = infile.nextValue();
						while (repeat_val != "") {
							events.back().comp_num++;
							e = &events.back().components[events.back().comp_num];
							e->type = infile.key;
							e->s = repeat_val;

							repeat_val = infile.nextValue();
						}
					}
					else if (infile.key == "requires_not") {
						e->s = infile.nextValue();

						// add repeating requires_not
						string repeat_val = infile.nextValue();
						while (repeat_val != "") {
							events.back().comp_num++;
							e = &events.back().components[events.back().comp_num];
							e->type = infile.key;
							e->s = repeat_val;

							repeat_val = infile.nextValue();
						}
					}
					else if (infile.key == "requires_item") {
						e->x = atoi(infile.nextValue().c_str());

						// add repeating requires_item
						string repeat_val = infile.nextValue();
						while (repeat_val != "") {
							events.back().comp_num++;
							e = &events.back().components[events.back().comp_num];
							e->type = infile.key;
							e->x = atoi(repeat_val.c_str());

							repeat_val = infile.nextValue();
						}
					}
					else if (infile.key == "set_status") {
						e->s = infile.nextValue();

						// add repeating set_status
						string repeat_val = infile.nextValue();
						while (repeat_val != "") {
							events.back().comp_num++;
							e = &events.back().components[events.back().comp_num];
							e->type = infile.key;
							e->s = repeat_val;

							repeat_val = infile.nextValue();
						}
					}
					else if (infile.key == "unset_status") {
						e->s = infile.nextValue();

						// add repeating unset_status
						string repeat_val = infile.nextValue();
						while (repeat_val != "") {
							events.back().comp_num++;
							e = &events.back().components[events.back().comp_num];
							e->type = infile.key;
							e->s = repeat_val;

							repeat_val = infile.nextValue();
						}
					}
					else if (infile.key == "remove_item") {
						e->x = atoi(infile.nextValue().c_str());

						// add repeating remove_item
						string repeat_val = infile.nextValue();
						while (repeat_val != "") {
							events.back().comp_num++;
							e = &events.back().components[events.back().comp_num];
							e->type = infile.key;
							e->x = atoi(repeat_val.c_str());

							repeat_val = infile.nextValue();
						}
					}
					else if (infile.key == "reward_xp") {
						e->x = atoi(infile.val.c_str());
					}
					else if (infile.key == "power") {
						e->x = atoi(infile.val.c_str());
					}
					else if (infile.key == "spawn") {

						e->s = infile.nextValue();
						e->x = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE/2;
						e->y = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE/2;

						// add repeating spawn
						string repeat_val = infile.nextValue();
						while (repeat_val != "") {
							events.back().comp_num++;
							e = &events.back().components[events.back().comp_num];
							e->type = infile.key;

							e->s = repeat_val;
							e->x = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE/2;
							e->y = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE/2;

							repeat_val = infile.nextValue();
						}
					}
					events.back().comp_num++;
				}
			}
		}

		infile.close();

		// reached end of file.  Handle any final sections.
		if (enemy_awaiting_queue) {
			enemies.push(new_enemy);
			enemy_awaiting_queue = false;
		}
		if (npc_awaiting_queue) {
			npcs.push(new_npc);
			npc_awaiting_queue = false;
		}
		if (group_awaiting_queue){
			push_enemy_group(new_group);
			group_awaiting_queue = false;
		}
	}

	if (this->new_music) {
		loadMusic();
		this->new_music = false;
	}
	tset.load(this->tileset);

	return 0;
}
Beispiel #22
0
/**
 * Load a specific items file
 *
 * @param filename The full path and name of the file to load
 */
void ItemManager::loadItems() {
	FileParser infile;

	// @CLASS Item|Description about the class and it usage, items/items.txt...
	if (!infile.open("items/items.txt", true, false))
		return;

	int id = 0;
	bool id_line = false;
	while (infile.next()) {
		if (infile.key == "id") {
			// @ATTR id|integer|An uniq id of the item used as reference from other classes.
			id_line = true;
			id = toInt(infile.val);
			ensureFitsId(items, id+1);
		}
		else id_line = false;

		if (id < 1) {
			if (id_line) fprintf(stderr, "Item index out of bounds 1-%d, skipping\n", 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);
		else if (infile.key == "flavor")
			// @ATTR flavor|string|
			items[id].flavor = msg->get(infile.val);
		else if (infile.key == "level")
			// @ATTR level|integer|
			items[id].level = toInt(infile.val);
		else if (infile.key == "icon") {
			// @ATTR icon|integer|
			items[id].icon = toInt(infile.nextValue());
		}
		else if (infile.key == "quality") {
			// @ATTR quality|[low:high:epic]|Item quality, corresponds to item color.
			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 == "item_type") {
			// @ATTR item_type|string|Equipment slot [artifact, head, chest, hands, legs, feets, main, off, ring] or base item type [gem, consumable]
			items[id].type = infile.val;
		}
		else if (infile.key == "equip_flags") {
			infile.val = infile.val + ',';
			std::string flag = eatFirstString(infile.val,',');

			while (flag != "") {
				items[id].equip_flags.push_back(flag);
				flag = eatFirstString(infile.val,',');
			}
		}
		else if (infile.key == "dmg_melee") {
			// @ATTR dmg_melee|[min (integer), max (integer)]|Defines the item melee damage, if only min is specified the melee damage is fixed.
			items[id].dmg_melee_min = toInt(infile.nextValue());
			if (infile.val.length() > 0)
				items[id].dmg_melee_max = toInt(infile.nextValue());
			else
				items[id].dmg_melee_max = items[id].dmg_melee_min;
		}
		else if (infile.key == "dmg_ranged") {
			// @ATTR dmg_ranged|[min (integer), max (integer)]|Defines the item ranged damage, if only min is specified the ranged damage is fixed.
			items[id].dmg_ranged_min = toInt(infile.nextValue());
			if (infile.val.length() > 0)
				items[id].dmg_ranged_max = toInt(infile.nextValue());
			else
				items[id].dmg_ranged_max = items[id].dmg_ranged_min;
		}
		else if (infile.key == "dmg_ment") {
			// @ATTR dmg_ment|[min (integer), max (integer)]|Defines the item mental damage, if only min is specified the ranged damage is fixed.
			items[id].dmg_ment_min = toInt(infile.nextValue());
			if (infile.val.length() > 0)
				items[id].dmg_ment_max = toInt(infile.nextValue());
			else
				items[id].dmg_ment_max = items[id].dmg_ment_min;
		}
		else if (infile.key == "abs") {
			// @ATTR abs|[min (integer), max (integer)]|Defines the item absorb value, if only min is specified the absorb value is fixed.
			items[id].abs_min = toInt(infile.nextValue());
			if (infile.val.length() > 0)
				items[id].abs_max = toInt(infile.nextValue());
			else
				items[id].abs_max = items[id].abs_min;
		}
		else if (infile.key == "req") {
			// @ATTR req|[ [p:m:o:d], amount (integer) ]|Make item require specific stat level ex. req=p,6 will require hero to have level 6 in physical stats 
			string 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 = toInt(infile.nextValue());
		}
		else if (infile.key == "bonus") {
			// @ATTR bonus|[power_tag (string), amount (integer)]|Adds a bonus to the item power_tag being a uniq tag of a power definition, e.: bonus=HP regen, 50
			items[id].bonus_stat.push_back(infile.nextValue());
			items[id].bonus_val.push_back(toInt(infile.nextValue()));
		}
		else if (infile.key == "soundfx") {
			// @ATTR soundfx|string|Sound effect for the specific item.
			items[id].sfx = snd->load(infile.val, "ItemManager");
		}
		else if (infile.key == "gfx")
			// @ATTR gfx|string|Graphics for the specific item.
			items[id].gfx = infile.val;
		else if (infile.key == "loot_animation") {
			// @ATTR loot_animation|string|Specifies the loot animation for the item.
			infile.val = infile.val + ',';
			LootAnimation la;
			la.name = eatFirstString(infile.val, ',');
			la.low = eatFirstInt(infile.val, ',');
			la.high = eatFirstInt(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 (toInt(infile.val) > 0) {
				items[id].power = toInt(infile.val);
			}
			else fprintf(stderr, "Power index inside item %d definition out of bounds 1-%d, skipping item\n", id, INT_MAX);
		}
		else if (infile.key == "power_mod")
			// @ATTR power_mod|integer|Power modifier of item.
			items[id].power_mod = toInt(infile.val);
		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|integer|The amount of currency the item costs, if set to 0 the item cannot be sold.
			items[id].price = toInt(infile.val);
		else if (infile.key == "price_sell")
			// @ATTR sell_price|integer|The amount of currency the item is sold for, if set to 0 the sell prices is prices*vendor_ratio.
			items[id].price_sell = toInt(infile.val);
		else if (infile.key == "max_quantity")
			// @ATTR max_quantity|integer|Max item count per stack.
			items[id].max_quantity = toInt(infile.val);
		else if (infile.key == "rand_loot")
			// @ATTR rand_loot|integer|Max amount appearing in loot stack.
			items[id].rand_loot = toInt(infile.val);
		else if (infile.key == "rand_vendor")
			// @ATTR rand_vendor|integer|Max amount appearing in vendor stack.
			items[id].rand_vendor = 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|string|Sound effect when walking, this applies only to armors.
			items[id].stepfx = infile.val;
		else if (infile.key == "class") {
			// @ATTR class|[classname (string), ...]|A comma separated list of classes the item belongs too.
			string classname = infile.nextValue();
			while (classname != "") {
				unsigned pos; // find the position where this classname is stored:
				for (pos = 0; pos < item_class_names.size(); pos++) {
					if (item_class_names[pos] == classname)
						break;
				}
				// if it was not found, add it to the end.
				// pos is already the correct index.
				if (pos == item_class_names.size()) {
					item_class_names.push_back(classname);
					item_class_items.push_back(vector<unsigned int>());
				}
				// add item id to the item list of that class:
				item_class_items[pos].push_back(id);
				classname = infile.nextValue();
			}
		}

	}
	infile.close();
}
Beispiel #23
0
/**
 * 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;
	if (!infile.open(filename)) {
		fprintf(stderr, "Unable to open %s!\n", filename.c_str());
		return;
	}

	int id = 0;
	bool id_line = false;
	while (infile.next()) {
		if (infile.key == "id") {
			id_line = true;
			id = toInt(infile.val);
			if (id > 0 && id >= (int)items.size()) {
				// *2 to amortize the resizing to O(log(n)).
				items.resize((2*id) + 1);
			}
		} else id_line = false;

		if (id < 1) {
			if (id_line) fprintf(stderr, "Item index out of bounds 1-%d, skipping\n", INT_MAX);
			continue;
		}
		if (id_line) continue;

		if (infile.key == "name")
			items[id].name = msg->get(infile.val);
		else if (infile.key == "level")
			items[id].level = toInt(infile.val);
		else if (infile.key == "icon") {
			items[id].icon = toInt(infile.nextValue());
		}
		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 == "item_type") {
				items[id].type = infile.val;
		}
		else if (infile.key == "dmg_melee") {
			items[id].dmg_melee_min = toInt(infile.nextValue());
			if (infile.val.length() > 0)
				items[id].dmg_melee_max = toInt(infile.nextValue());
			else
				items[id].dmg_melee_max = items[id].dmg_melee_min;
		}
		else if (infile.key == "dmg_ranged") {
			items[id].dmg_ranged_min = toInt(infile.nextValue());
			if (infile.val.length() > 0)
				items[id].dmg_ranged_max = toInt(infile.nextValue());
			else
				items[id].dmg_ranged_max = items[id].dmg_ranged_min;
		}
		else if (infile.key == "dmg_ment") {
			items[id].dmg_ment_min = toInt(infile.nextValue());
			if (infile.val.length() > 0)
				items[id].dmg_ment_max = toInt(infile.nextValue());
			else
				items[id].dmg_ment_max = items[id].dmg_ment_min;
		}
		else if (infile.key == "abs") {
			items[id].abs_min = toInt(infile.nextValue());
			if (infile.val.length() > 0)
				items[id].abs_max = toInt(infile.nextValue());
			else
				items[id].abs_max = items[id].abs_min;
		}
		else if (infile.key == "req") {
			string 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 = toInt(infile.nextValue());
		}
		else if (infile.key == "bonus") {
			items[id].bonus_stat.push_back(infile.nextValue());
			items[id].bonus_val.push_back(toInt(infile.nextValue()));
		}
		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_animation")
			items[id].loot_animation = infile.val;
		else if (infile.key == "power") {
			if (toInt(infile.val) > 0) {
				items[id].power = toInt(infile.val);
			}
			else fprintf(stderr, "Power index inside item %d definition out of bounds 1-%d, skipping item\n", id, INT_MAX);
		}
		else if (infile.key == "power_mod")
			items[id].power_mod = toInt(infile.val);
		else if (infile.key == "power_desc")
			items[id].power_desc = msg->get(infile.val);
		else if (infile.key == "price")
			items[id].price = toInt(infile.val);
		else if (infile.key == "price_sell")
			items[id].price_sell = toInt(infile.val);
		else if (infile.key == "max_quantity")
			items[id].max_quantity = toInt(infile.val);
		else if (infile.key == "rand_loot")
			items[id].rand_loot = toInt(infile.val);
		else if (infile.key == "rand_vendor")
			items[id].rand_vendor = toInt(infile.val);
		else if (infile.key == "pickup_status")
			items[id].pickup_status = infile.val;
		else if (infile.key == "stepfx")
			items[id].stepfx = infile.val;
		else if (infile.key == "class") {
			string classname = infile.nextValue();
			while (classname != "") {
				unsigned pos; // find the position where this classname is stored:
				for (pos = 0; pos < item_class_names.size(); pos++) {
					if (item_class_names[pos] == classname)
						break;
				}
				// if it was not found, add it to the end.
				// pos is already the correct index.
				if (pos == item_class_names.size()) {
					item_class_names.push_back(classname);
					item_class_items.push_back(vector<unsigned int>());
				}
				// add item id to the item list of that class:
				item_class_items[pos].push_back(id);
				classname = infile.nextValue();
			}
		}

	}
	infile.close();
}
Beispiel #24
0
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 = static_cast<unsigned short>(toInt(infile.nextValue()));
				TILE_H = static_cast<unsigned short>(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);
		Exit(1);
	}
}
Beispiel #25
0
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 = static_cast<unsigned short>(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 = static_cast<unsigned short>(toInt(infile.val));
			// @ATTR icon_size|integer|Size of icons.
			else if (infile.key == "icon_size")
				ICON_SIZE = static_cast<unsigned short>(toInt(infile.val));
			// @ATTR required_width|integer|Minimum window/screen resolution width.
			else if (infile.key == "required_width") {
				MIN_SCREEN_W = static_cast<unsigned short>(toInt(infile.val));
			}
			// @ATTR required_height|integer|Minimum window/screen resolution height.
			else if (infile.key == "required_height") {
				MIN_SCREEN_H = static_cast<unsigned short>(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 = static_cast<unsigned short>(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 = static_cast<short>(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 = static_cast<short>(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 = static_cast<short>(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 = static_cast<short>(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 = static_cast<short>(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 = static_cast<short>(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 = static_cast<short>(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 = static_cast<short>(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")) {
		while (infile.next()) {
			if (infile.new_section) {
				if (infile.section == "element") {
					// check if the previous element and remove it if there is no identifier
					if (!ELEMENTS.empty() && ELEMENTS.back().id == "") {
						ELEMENTS.pop_back();
					}
					ELEMENTS.resize(ELEMENTS.size()+1);
				}
			}

			if (ELEMENTS.empty() || infile.section != "element")
				continue;

			// @ATTR element.id|string|An identifier for this element.
			if (infile.key == "id") ELEMENTS.back().id = infile.val;
			// @ATTR element.name|string|The displayed name of this element.
			else if (infile.key == "name") ELEMENTS.back().name = infile.val;

			else infile.error("Settings: '%s' is not a valid key.", infile.key.c_str());
		}
		infile.close();

		// check if the last element and remove it if there is no identifier
		if (!ELEMENTS.empty() && ELEMENTS.back().id == "") {
			ELEMENTS.pop_back();
		}
	}

	// @CLASS Settings: Equip flags|Description of engine/equip_flags.txt
	if (infile.open("engine/equip_flags.txt")) {
		while (infile.next()) {
			if (infile.new_section) {
				if (infile.section == "flag") {
					// check if the previous flag and remove it if there is no identifier
					if (!EQUIP_FLAGS.empty() && EQUIP_FLAGS.back().id == "") {
						EQUIP_FLAGS.pop_back();
					}
					EQUIP_FLAGS.resize(EQUIP_FLAGS.size()+1);
				}
			}

			if (EQUIP_FLAGS.empty() || infile.section != "flag")
				continue;

			// @ATTR flag.id|string|An identifier for this equip flag.
			if (infile.key == "id") EQUIP_FLAGS.back().id = infile.val;
			// @ATTR flag.name|string|The displayed name of this equip flag.
			else if (infile.key == "name") EQUIP_FLAGS.back().name = infile.val;

			else infile.error("Settings: '%s' is not a valid key.", infile.key.c_str());
		}
		infile.close();

		// check if the last flag and remove it if there is no identifier
		if (!EQUIP_FLAGS.empty() && EQUIP_FLAGS.back().id == "") {
			EQUIP_FLAGS.pop_back();
		}
	}

	// @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") {
					// check if the previous class and remove it if there is no name
					if (!HERO_CLASSES.empty() && HERO_CLASSES.back().name == "") {
						HERO_CLASSES.pop_back();
					}
					HERO_CLASSES.resize(HERO_CLASSES.size()+1);
				}
			}

			if (HERO_CLASSES.empty() || 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();

		// check if the last class and remove it if there is no name
		if (!HERO_CLASSES.empty() && HERO_CLASSES.back().name == "") {
			HERO_CLASSES.pop_back();
		}
	}
	// Make a default hero class if none were found
	if (HERO_CLASSES.empty()) {
		HeroClass c;
		c.name = "Adventurer";
		msg->get("Adventurer"); // this is needed for translation
		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();
	}

	// @CLASS Settings: Loot|Description of engine/loot.txt
	if (infile.open("engine/loot.txt")) {
		while (infile.next()) {
			if (infile.key == "currency_name") {
				// @ATTR currency_name|string|Define the name of currency in game
				CURRENCY = msg->get(infile.val);
			}
		}
		infile.close();
	}
}
bool GameStateCutscene::load(std::string filename) {
	FileParser infile;

	// @CLASS Cutscene|Description of cutscenes in cutscenes/
	if (!infile.open(filename))
		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.s = infile.val;
			}
			else if (infile.key == "pause") {
				// @ATTR scene.pause|duration|Pause before next component
				sc.type = infile.key;
				sc.x = parse_duration(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;
}
Beispiel #27
0
/**
 * 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("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 (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();
	}
	loadGraphics(filename_portrait);
}
Beispiel #28
0
/**
 * When loading the game, load from file if possible
 */
void GameStatePlay::loadGame() {

	// 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 << "save" << game_slot << ".txt";

	if (infile.open(ss.str())) {
		while (infile.next()) {
			if (infile.key == "name") pc->stats.name = infile.val;
			else if (infile.key == "permadeath") {
			    pc->stats.permadeath = atoi(infile.val.c_str());
			}
			else if (infile.key == "option") {
				pc->stats.base = infile.nextValue();
				pc->stats.head = infile.nextValue();
				pc->stats.portrait = infile.nextValue();
			}
			else if (infile.key == "xp") pc->stats.xp = atoi(infile.val.c_str());
			else if (infile.key == "build") {
				pc->stats.physical_character = atoi(infile.nextValue().c_str());
				pc->stats.mental_character = atoi(infile.nextValue().c_str());
				pc->stats.offense_character = atoi(infile.nextValue().c_str());
				pc->stats.defense_character = atoi(infile.nextValue().c_str());
			}
			else if (infile.key == "gold") {
				menu->inv->gold = atoi(infile.val.c_str());
			}
			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") {
				map->teleport_mapname = infile.nextValue();

				if (fileExists(mods->locate("maps/" + map->teleport_mapname))) {
					map->teleport_destination.x = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE/2;
					map->teleport_destination.y = atoi(infile.nextValue().c_str()) * UNITS_PER_TILE + UNITS_PER_TILE/2;
					map->teleportation = true;

					// prevent spawn.txt from putting us on the starting map
					map->clearEvents();
				}
				else {
					map->teleport_mapname = "spawn.txt";
					map->teleport_destination.x = 1;
					map->teleport_destination.y = 1;
					map->teleportation = true;

				}
			}
			else if (infile.key == "actionbar") {
				for (int i=0; i<12; i++)
					hotkeys[i] = atoi(infile.nextValue().c_str());
				menu->act->set(hotkeys);
			}
			else if (infile.key == "transformed") {
				pc->stats.transform_type = infile.nextValue().c_str();
				if (pc->stats.transform_type != "") pc->stats.transform_duration = -1;
			}
			else if (infile.key == "campaign") camp->setAll(infile.val);
		}

		infile.close();
	}

	// initialize vars
	pc->stats.recalc();
	menu->inv->applyEquipment(menu->inv->inventory[EQUIPMENT].storage);
	pc->stats.hp = pc->stats.maxhp;
	pc->stats.mp = pc->stats.maxmp;

	// 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.portrait);

	// load sounds (gender specific)
	pc->loadSounds();

}
Beispiel #29
0
void ItemManager::loadSets() {
	FileParser infile;

	// @CLASS Item Set|Definition of a item sets, items/sets.txt...
	if (!infile.open("items/sets.txt", true, false))
		return;

	int id = 0;
	bool id_line;
	while (infile.next()) {
		if (infile.key == "id") {
			// @ATTR id|integer|A uniq id for the item set.
			id_line = true;
			id = toInt(infile.val);
			ensureFitsId(item_sets, id+1);
		}
		else id_line = false;

		if (id < 1) {
			if (id_line) fprintf(stderr, "Item set index out of bounds 1-%d, skipping\n", 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 name|[item_id,...]|List of item id's that is part of the set.
			string item_id = infile.nextValue();
			while (item_id != "") {
				int temp_id = 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);
					const char* cname = item_sets[id].name.c_str();
					fprintf(stderr, "Item index inside item set %s definition out of bounds 1-%d, skipping item\n", cname, maxsize);
				}
				item_id = infile.nextValue();
			}
		}
		else if (infile.key == "color") {
			// @ATTR color|color|A specific of color for the set.
			item_sets[id].color.r = toInt(infile.nextValue());
			item_sets[id].color.g = toInt(infile.nextValue());
			item_sets[id].color.b = toInt(infile.nextValue());
		}
		else if (infile.key == "bonus") {
			// @ATTR bonus|[requirements (integer), bonus stat (string), bonus (integer)]|Bonus to append to items in the set.
			Set_bonus bonus;
			bonus.requirement = toInt(infile.nextValue());
			bonus.bonus_stat = infile.nextValue();
			bonus.bonus_val = toInt(infile.nextValue());
			item_sets[id].bonus.push_back(bonus);
		}
	}
	infile.close();
}
Beispiel #30
0
void TileSet::load(const std::string& filename) {
	if (current_map == filename) return;

	reset();

	FileParser infile;

	// @CLASS TileSet|Description of tilesets in tilesets/
	if (infile.open(filename)) {
		while (infile.next()) {
			if (infile.key == "img") {
				// @ATTR img|string|Filename of a tile sheet image.
				loadGraphics(infile.val);
			}
			else if (infile.key == "tile") {
				// @ATTR tile|index (integer), x (integer), y (integer), w (integer), h (integer), x offset (integer), y offset (integer)|A single tile definition.

				// Verify that we have graphics for tiles
				if (!sprites) {
					std::cerr << "No graphics for tileset definition '" << filename << "', aborting." << std::endl;
					Exit(0);
				}

				unsigned index = popFirstInt(infile.val);

				if (index >= tiles.size())
					tiles.resize(index + 1);

				tiles[index].tile = sprites->getGraphics()->createSprite();

				tiles[index].tile->setClipX(popFirstInt(infile.val));
				tiles[index].tile->setClipY(popFirstInt(infile.val));
				tiles[index].tile->setClipW(popFirstInt(infile.val));
				tiles[index].tile->setClipH(popFirstInt(infile.val));
				tiles[index].offset.x = popFirstInt(infile.val);
				tiles[index].offset.y = popFirstInt(infile.val);
				max_size_x = std::max(max_size_x, (tiles[index].tile->getClip().w / TILE_W) + 1);
				max_size_y = std::max(max_size_y, (tiles[index].tile->getClip().h / TILE_H) + 1);
			}
			else if (infile.key == "transparency") {
				// @ATTR transparency|r (integer), g (integer), b (integer)|An RGB color to key out and treat as transparent.
				alpha_background = false;

				trans_r = (Uint8)popFirstInt(infile.val);
				trans_g = (Uint8)popFirstInt(infile.val);
				trans_b = (Uint8)popFirstInt(infile.val);

			}
			else if (infile.key == "animation") {
				// @ATTR animation|tile index (integer), x (integer), y (integer), duration (duration), ...|An animation for a tile. Durations are in 'ms' or 's'.
				int frame = 0;
				unsigned TILE_ID = toInt(infile.nextValue());

				if (TILE_ID >= anim.size())
					anim.resize(TILE_ID + 1);

				std::string repeat_val = infile.nextValue();
				while (repeat_val != "") {
					anim[TILE_ID].frames++;
					anim[TILE_ID].pos.resize(frame + 1);
					anim[TILE_ID].frame_duration.resize(frame + 1);
					anim[TILE_ID].pos[frame].x = toInt(repeat_val);
					anim[TILE_ID].pos[frame].y = toInt(infile.nextValue());
					anim[TILE_ID].frame_duration[frame] = parse_duration(infile.nextValue());

					frame++;
					repeat_val = infile.nextValue();
				}
			}
			else {
				infile.error("TileSet: '%s' is not a valid key.", infile.key.c_str());
			}
		}
		infile.close();
	}

	current_map = filename;
}