示例#1
0
CombatText::CombatText() {
	msg_color[COMBAT_MESSAGE_GIVEDMG] = font->getColor("combat_givedmg");
	msg_color[COMBAT_MESSAGE_TAKEDMG] = font->getColor("combat_takedmg");
	msg_color[COMBAT_MESSAGE_CRIT] = font->getColor("combat_crit");
	msg_color[COMBAT_MESSAGE_BUFF] = font->getColor("combat_buff");
	msg_color[COMBAT_MESSAGE_MISS] = font->getColor("combat_miss");

	duration = MAX_FRAMES_PER_SEC; // 1 second
	speed = 60.f / MAX_FRAMES_PER_SEC;
	offset = 48; // average height of flare-game enemies, so a sensible default

	// Load config settings
	FileParser infile;
	// @CLASS CombatText|Description of engine/combat_text.txt
	if(infile.open("engine/combat_text.txt")) {
		while(infile.next()) {
			if(infile.key == "duration") {
				// @ATTR duration|duration|Duration of the combat text in 'ms' or 's'.
				duration = parse_duration(infile.val);
			}
			else if(infile.key == "speed") {
				// @ATTR speed|int|Motion speed of the combat text.
				speed = static_cast<float>(toInt(infile.val) * 60) / MAX_FRAMES_PER_SEC;
			}
			else if (infile.key == "offset") {
				// @ATTR offset|int|The vertical offset for the combat text's starting position.
				offset = toInt(infile.val);
			}
			else {
				infile.error("CombatText: '%s' is not a valid key.",infile.key.c_str());
			}
		}
		infile.close();
	}
}
示例#2
0
/*=export_func  optionTimeVal
 * private:
 *
 * what:  process an option with a time value.
 * arg:   + tOptions* + pOpts    + program options descriptor +
 * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
 *
 * doc:
 *  Decipher a time duration value.
=*/
void
optionTimeVal(tOptions* pOpts, tOptDesc* pOD )
{
    long  val;

    if ((pOD->fOptState & OPTST_RESET) != 0)
        return;

    val = parse_duration(pOD->optArg.argString);
    if (errno != 0)
        goto bad_time;

    if (pOD->fOptState & OPTST_ALLOC_ARG) {
        AGFREE(pOD->optArg.argString);
        pOD->fOptState &= ~OPTST_ALLOC_ARG;
    }

    pOD->optArg.argInt = val;
    return;

bad_time:
    fprintf( stderr, zNotNumber, pOpts->pzProgName, pOD->optArg.argString );
    if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0)
        (*(pOpts->pUsageProc))(pOpts, EXIT_FAILURE);

    pOD->optArg.argInt = ~0;
}
示例#3
0
/*
=================
G_AddIP_f
=================
*/
void G_AddIP_f(edict_t *ent)
{
    unsigned mask, compare;
    unsigned duration;
    ipaction_t action;
    int start, argc;
    char *s;

    start = ent ? 0 : 1;
    argc = gi.argc() - start;

    if (argc < 2) {
        gi.cprintf(ent, PRINT_HIGH, "Usage: %s <ip-mask> [duration] [action]\n", gi.argv(start));
        return;
    }

    if (numipfilters == MAX_IPFILTERS) {
        gi.cprintf(ent, PRINT_HIGH, "IP filter list is full\n");
        return;
    }

    s = gi.argv(start + 1);
    if (!parse_filter(s, &mask, &compare)) {
        gi.cprintf(ent, PRINT_HIGH, "Bad filter address: %s\n", s);
        return;
    }

    duration = ent ? DEF_DURATION : 0;
    action = IPA_BAN;
    if (argc > 2) {
        s = gi.argv(start + 2);
        duration = parse_duration(s);
        if (ent) {
            if (!duration) {
                gi.cprintf(ent, PRINT_HIGH, "You may not add permanent bans.\n");
                return;
            }
            if (duration > MAX_DURATION) {
                duration = MAX_DURATION;
            }
        }
        if (argc > 3) {
            s = gi.argv(start + 3);
            action = parse_action(s);
            if (action == IPA_NONE) {
                gi.cprintf(ent, PRINT_HIGH, "Bad action specifier: %s\n", s);
                return;
            }
        }
    }

    add_filter(action, mask, compare, duration, ent);
}
示例#4
0
文件: value.c 项目: Firstyear/ds
long 
slapi_value_get_timelong(const Slapi_Value *value)
{
	long r= 0;
	if(NULL!=value)
	{
		char *p;
        p = slapi_ch_malloc(value->bv.bv_len + 1);
        memcpy (p, value->bv.bv_val, value->bv.bv_len);
        p [value->bv.bv_len] = '\0';
        r = parse_duration(p);
        slapi_ch_free((void **)&p);
	}
	return r;
}
示例#5
0
/*=gfunc time_string_to_number
 *
 * what:   duration string to seconds
 * general_use:
 * exparg: time_spec, string to parse
 *
 * doc:    Convert the argument string to a time period in seconds.
 *         The string may use multiple parts consisting of days, hours
 *         minutes and seconds.  These are indicated with a suffix of
 *         @code{d}, @code{h}, @code{m} and @code{s} respectively.
 *         Hours, minutes and seconds may also be represented with
 *         @code{HH:MM:SS} or, without hours, as @code{MM:SS}.
=*/
SCM
ag_scm_time_string_to_number(SCM time_spec)
{
    extern time_t parse_duration(char const * in_pz);

    char const * pz;
    time_t  time_period;

    if (! AG_SCM_STRING_P(time_spec))
        return SCM_UNDEFINED;

    pz = scm_i_string_chars(time_spec);
    time_period = parse_duration(pz);

    return scm_from_int((int)time_period);
}
示例#6
0
void Map::loadEvent(FileParser &infile) {
	if (infile.key == "type") {
		std::string type = infile.val;
		events.back().type = type;

		if      (type == "on_trigger");
		else if (type == "on_mapexit"); // no need to set keep_after_trigger to false correctly, it's ignored anyway
		else if (type == "on_leave");
		else if (type == "on_load") {
			events.back().keep_after_trigger = false;
		}
		else if (type == "on_clear") {
			events.back().keep_after_trigger = false;
		}
		else {
			fprintf(stderr, "Map: Loading event in file %s\nEvent type %s unknown, change to \"on_trigger\" to suppress this warning.\n", infile.getFileName().c_str(), type.c_str());
		}
	}
	else if (infile.key == "location") {
		events.back().location.x = toInt(infile.nextValue());
		events.back().location.y = toInt(infile.nextValue());
		events.back().location.w = toInt(infile.nextValue());
		events.back().location.h = toInt(infile.nextValue());
	}
	else if (infile.key == "hotspot") {
		if (infile.val == "location") {
			events.back().hotspot.x = events.back().location.x;
			events.back().hotspot.y = events.back().location.y;
			events.back().hotspot.w = events.back().location.w;
			events.back().hotspot.h = events.back().location.h;
		}
		else {
			events.back().hotspot.x = toInt(infile.nextValue());
			events.back().hotspot.y = toInt(infile.nextValue());
			events.back().hotspot.w = toInt(infile.nextValue());
			events.back().hotspot.h = toInt(infile.nextValue());
		}
	}
	else if (infile.key == "cooldown") {
		events.back().cooldown = parse_duration(infile.val);
	}
	else {
		loadEventComponent(infile);
	}
}
示例#7
0
/*=export_func  optionTimeVal
 * private:
 *
 * what:  process an option with a time duration.
 * arg:   + tOptions * + opts + program options descriptor +
 * arg:   + tOptDesc * + od   + the descriptor for this arg +
 *
 * doc:
 *  Decipher a time duration value.
=*/
void
optionTimeVal(tOptions * opts, tOptDesc * od)
{
    time_t val;

    if (INQUERY_CALL(opts, od))
        return;

    val = parse_duration(od->optArg.argString);
    if (val == BAD_TIME) {
        fprintf(stderr, zNotDuration, opts->pzProgName, od->optArg.argString);
        if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0)
            (*(opts->pUsageProc))(opts, EXIT_FAILURE);
    }

    if (od->fOptState & OPTST_ALLOC_ARG) {
        AGFREE(od->optArg.argString);
        od->fOptState &= ~OPTST_ALLOC_ARG;
    }

    od->optArg.argInt = (long)val;
}
示例#8
0
/*=export_func  optionTimeVal
 * private:
 *
 * what:  process an option with a time duration.
 * arg:   + tOptions* + pOpts    + program options descriptor +
 * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
 *
 * doc:
 *  Decipher a time duration value.
=*/
void
optionTimeVal(tOptions * pOpts, tOptDesc * pOD)
{
    time_t val;

    if ((pOD->fOptState & OPTST_RESET) != 0)
        return;

    val = parse_duration(pOD->optArg.argString);
    if (val == BAD_TIME) {
        fprintf(stderr, zNotDuration, pOpts->pzProgName, pOD->optArg.argString);
        if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0)
            (*(pOpts->pUsageProc))(pOpts, EXIT_FAILURE);
    }

    if (pOD->fOptState & OPTST_ALLOC_ARG) {
        AGFREE(pOD->optArg.argString);
        pOD->fOptState &= ~OPTST_ALLOC_ARG;
    }

    pOD->optArg.argInt = (unsigned long)val;
}
示例#9
0
int
main (int argc, char *argv[])
{
    if (--argc <= 0)
    {
        fprintf (stderr, "USAGE: %s <time-spec> [...]", argv[0]);
        return 1;
    }

    do
    {
        char const * arg = *++argv;
        time_t res = parse_duration (arg);
        if (errno != 0)
        {
            fprintf (stderr, "could not parse time:  %s\n\terr %d - %s\n", arg,
                     errno, strerror (errno));
            return 1;
        }
        printf ("%u\n", (unsigned int)res);
    } while (--argc > 0);

    return 0;
}
示例#10
0
bool GameStateCutscene::load(const 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(new Scene(caption_margins, scale_graphics));
		}

		if (infile.section.empty()) {
			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;
			}
			else if (infile.key == "menu_backgrounds") {
				// @ATTR menu_backgrounds|bool|This cutscene will use a random fullscreen background image, like the title screen does
				has_background = true;
			}
			else {
				infile.error("GameStateCutscene: '%s' is not a valid key.", infile.key.c_str());
			}
		}
		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|Filename of 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 in 'ms' or 's'.
				sc.type = infile.key;
				sc.x = parse_duration(infile.val);
			}
			else if (infile.key == "soundfx") {
				// @ATTR scene.soundfx|string|Filename of a sound that will be played
				sc.type = infile.key;
				sc.s = infile.val;
			}
			else {
				infile.error("GameStateCutscene: '%s' is not a valid key.", infile.key.c_str());
			}

			if (sc.type != "")
				scenes.back()->components.push(sc);

		}
		else {
			infile.error("GameStateCutscene: '%s' is not a valid section.", infile.section.c_str());
		}

	}

	infile.close();

	if (scenes.empty()) {
		logError("GameStateCutscene: No scenes defined in cutscene file %s", filename.c_str());
		return false;
	}

	return true;
}
示例#11
0
文件: time.c 项目: Firstyear/ds
time_t
slapi_parse_duration(const char *value)
{
    return (time_t)parse_duration((char *)value);
}
示例#12
0
void StatBlock::loadHeroStats() {
	// set the default global cooldown
	cooldown = parse_duration("66ms");

	// Redefine numbers from config file if present
	FileParser infile;
	// @CLASS StatBlock: Hero stats|Description of engine/stats.txt
	if (infile.open("engine/stats.txt")) {
		while (infile.next()) {
			int value = toInt(infile.val);

			bool valid = loadCoreStat(&infile);

			if (infile.key == "max_points_per_stat") {
				// @ATTR max_points_per_stat|int|Maximum points for each primary stat.
				max_points_per_stat = value;
			}
			else if (infile.key == "sfx_step") {
				// @ATTR sfx_step|string|An id for a set of step sound effects. See items/step_sounds.txt.
				sfx_step = infile.val;
			}
			else if (infile.key == "stat_points_per_level") {
				// @ATTR stat_points_per_level|int|The amount of stat points awarded each level.
				stat_points_per_level = value;
			}
			else if (infile.key == "power_points_per_level") {
				// @ATTR power_points_per_level|int|The amount of power points awarded each level.
				power_points_per_level = value;
			}
			else if (!valid) {
				infile.error("StatBlock: '%s' is not a valid key.", infile.key.c_str());
			}
		}
		infile.close();
	}

	if (max_points_per_stat == 0) max_points_per_stat = max_spendable_stat_points / 4 + 1;
	statsLoaded = true;

	// load the XP table
	// @CLASS StatBlock: XP table|Description of engine/xp_table.txt
	if (infile.open("engine/xp_table.txt")) {
		while(infile.next()) {
			if (infile.key == "level") {
				// @ATTR level|int, int : Level, XP|The amount of XP required for this level.
				unsigned lvl_id = popFirstInt(infile.val);
				unsigned long lvl_xp = toUnsignedLong(popFirstString(infile.val));

				if (lvl_id > xp_table.size())
					xp_table.resize(lvl_id);

				xp_table[lvl_id - 1] = lvl_xp;
			}
		}
		infile.close();
	}

	if (xp_table.empty()) {
		logError("StatBlock: No XP table defined.");
		xp_table.push_back(0);
	}

	max_spendable_stat_points = static_cast<int>(xp_table.size()) * stat_points_per_level;
}
示例#13
0
/**
 * load a statblock, typically for an enemy definition
 */
void StatBlock::load(const std::string& filename) {
	// @CLASS StatBlock: Enemies|Description of enemies in enemies/
	FileParser infile;
	if (!infile.open(filename))
		return;

	bool clear_loot = true;
	bool flee_range_defined = false;

	while (infile.next()) {
		if (infile.new_section) {
			// APPENDed file
			clear_loot = true;
		}

		int num = toInt(infile.val);
		float fnum = toFloat(infile.val);
		bool valid = loadCoreStat(&infile) || loadSfxStat(&infile);

		// @ATTR name|string|Name
		if (infile.key == "name") name = msg->get(infile.val);
		// @ATTR humanoid|bool|This creature gives human traits when transformed into, such as the ability to talk with NPCs.
		else if (infile.key == "humanoid") humanoid = toBool(infile.val);

		// @ATTR level|int|Level
		else if (infile.key == "level") level = num;

		// enemy death rewards and events
		// @ATTR xp|int|XP awarded upon death.
		else if (infile.key == "xp") xp = num;
		else if (infile.key == "loot") {
			// @ATTR loot|repeatable(loot)|Possible loot that can be dropped on death.

			// loot entries format:
			// loot=[id],[percent_chance]
			// optionally allow range:
			// loot=[id],[percent_chance],[count_min],[count_max]

			if (clear_loot) {
				loot_table.clear();
				clear_loot = false;
			}

			loot_table.push_back(Event_Component());
			loot->parseLoot(infile.val, &loot_table.back(), &loot_table);
		}
		else if (infile.key == "loot_count") {
			// @ATTR loot_count|int, int : Min, Max|Sets the minimum (and optionally, the maximum) amount of loot this creature can drop. Overrides the global drop_max setting.
			loot_count.x = popFirstInt(infile.val);
			loot_count.y = popFirstInt(infile.val);
			if (loot_count.x != 0 || loot_count.y != 0) {
				loot_count.x = std::max(loot_count.x, 1);
				loot_count.y = std::max(loot_count.y, loot_count.x);
			}
		}
		// @ATTR defeat_status|string|Campaign status to set upon death.
		else if (infile.key == "defeat_status") defeat_status = infile.val;
		// @ATTR convert_status|string|Campaign status to set upon being converted to a player ally.
		else if (infile.key == "convert_status") convert_status = infile.val;
		// @ATTR first_defeat_loot|item_id|Drops this item upon first death.
		else if (infile.key == "first_defeat_loot") first_defeat_loot = num;
		// @ATTR quest_loot|string, string, item_id : Required status, Required not status, Item|Drops this item when campaign status is met.
		else if (infile.key == "quest_loot") {
			quest_loot_requires_status = popFirstString(infile.val);
			quest_loot_requires_not_status = popFirstString(infile.val);
			quest_loot_id = popFirstInt(infile.val);
		}

		// behavior stats
		// @ATTR flying|bool|Creature can move over gaps/water.
		else if (infile.key == "flying") flying = toBool(infile.val);
		// @ATTR intangible|bool|Creature can move through walls.
		else if (infile.key == "intangible") intangible = toBool(infile.val);
		// @ATTR facing|bool|Creature can turn to face their target.
		else if (infile.key == "facing") facing = toBool(infile.val);

		// @ATTR waypoint_pause|duration|Duration to wait at each waypoint in 'ms' or 's'.
		else if (infile.key == "waypoint_pause") waypoint_pause = parse_duration(infile.val);

		// @ATTR turn_delay|duration|Duration it takes for this creature to turn and face their target in 'ms' or 's'.
		else if (infile.key == "turn_delay") turn_delay = parse_duration(infile.val);
		// @ATTR chance_pursue|int|Percentage change that the creature will chase their target.
		else if (infile.key == "chance_pursue") chance_pursue = num;
		// @ATTR chance_flee|int|Percentage chance that the creature will run away from their target.
		else if (infile.key == "chance_flee") chance_flee = num;

		else if (infile.key == "power") {
			// @ATTR power|["melee", "ranged", "beacon", "on_hit", "on_death", "on_half_dead", "on_join_combat", "on_debuff"], power_id, int : State, Power, Chance|A power that has a chance of being triggered in a certain state.
			AIPower ai_power;

			std::string ai_type = popFirstString(infile.val);

			ai_power.id = powers->verifyID(popFirstInt(infile.val), &infile, false);
			if (ai_power.id == 0)
				continue; // verifyID() will print our error message

			ai_power.chance = popFirstInt(infile.val);

			if (ai_type == "melee") ai_power.type = AI_POWER_MELEE;
			else if (ai_type == "ranged") ai_power.type = AI_POWER_RANGED;
			else if (ai_type == "beacon") ai_power.type = AI_POWER_BEACON;
			else if (ai_type == "on_hit") ai_power.type = AI_POWER_HIT;
			else if (ai_type == "on_death") ai_power.type = AI_POWER_DEATH;
			else if (ai_type == "on_half_dead") ai_power.type = AI_POWER_HALF_DEAD;
			else if (ai_type == "on_join_combat") ai_power.type = AI_POWER_JOIN_COMBAT;
			else if (ai_type == "on_debuff") ai_power.type = AI_POWER_DEBUFF;
			else {
				infile.error("StatBlock: '%s' is not a valid enemy power type.", ai_type.c_str());
				continue;
			}

			if (ai_power.type == AI_POWER_HALF_DEAD)
				half_dead_power = true;

			powers_ai.push_back(ai_power);
		}

		else if (infile.key == "passive_powers") {
			// @ATTR passive_powers|list(power_id)|A list of passive powers this creature has.
			powers_passive.clear();
			std::string p = popFirstString(infile.val);
			while (p != "") {
				powers_passive.push_back(toInt(p));
				p = popFirstString(infile.val);
			}
		}

		// @ATTR melee_range|float|Minimum distance from target required to use melee powers.
		else if (infile.key == "melee_range") melee_range = fnum;
		// @ATTR threat_range|float, float: Engage distance, Stop distance|The first value is the radius of the area this creature will be able to start chasing the hero. The second, optional, value is the radius at which this creature will stop pursuing their target and defaults to double the first value.
		else if (infile.key == "threat_range") {
			threat_range = toFloat(popFirstString(infile.val));

			std::string tr_far = popFirstString(infile.val);
			if (!tr_far.empty())
				threat_range_far = toFloat(tr_far);
			else
				threat_range_far = threat_range * 2;
		}
		// @ATTR flee_range|float|The radius at which this creature will start moving to a safe distance. Defaults to half of the threat_range.
		else if (infile.key == "flee_range") {
			flee_range = fnum;
			flee_range_defined = true;
		}
		// @ATTR combat_style|["default", "aggressive", "passive"]|How the creature will enter combat. Default is within range of the hero; Aggressive is always in combat; Passive must be attacked to enter combat.
		else if (infile.key == "combat_style") {
			if (infile.val == "default") combat_style = COMBAT_DEFAULT;
			else if (infile.val == "aggressive") combat_style = COMBAT_AGGRESSIVE;
			else if (infile.val == "passive") combat_style = COMBAT_PASSIVE;
			else infile.error("StatBlock: Unknown combat style '%s'", infile.val.c_str());
		}

		// @ATTR animations|filename|Filename of an animation definition.
		else if (infile.key == "animations") animations = infile.val;

		// @ATTR suppress_hp|bool|Hides the enemy HP bar for this creature.
		else if (infile.key == "suppress_hp") suppress_hp = toBool(infile.val);

		else if (infile.key == "categories") {
			// @ATTR categories|list(string)|Categories that this enemy belongs to.
			categories.clear();
			std::string cat;
			while ((cat = popFirstString(infile.val)) != "") {
				categories.push_back(cat);
			}
		}

		// @ATTR flee_duration|duration|The minimum amount of time that this creature will flee. They may flee longer than the specified time.
		else if (infile.key == "flee_duration") flee_duration = parse_duration(infile.val);
		// @ATTR flee_cooldown|duration|The amount of time this creature must wait before they can start fleeing again.
		else if (infile.key == "flee_cooldown") flee_cooldown = parse_duration(infile.val);

		// this is only used for EnemyGroupManager
		// we check for them here so that we don't get an error saying they are invalid
		else if (infile.key == "rarity") ; // but do nothing

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

	hp = starting[STAT_HP_MAX];
	mp = starting[STAT_MP_MAX];

	if (!flee_range_defined)
		flee_range = threat_range / 2;

	applyEffects();
}
示例#14
0
void EventManager::loadEvent(FileParser &infile, Event* evnt) {
	if (!evnt) return;
	// @CLASS EventManager|Description of events in maps/ and npcs/

	if (infile.key == "type") {
		// @ATTR event.type|string|(IGNORED BY ENGINE) The "type" field, as used by Tiled and other mapping tools.
		evnt->type = infile.val;
	}
	else if (infile.key == "activate") {
		// @ATTR event.activate|["on_trigger", "on_load", "on_leave", "on_mapexit", "on_clear", "static"]|Set the state in which the event will be activated (map events only).
		if (infile.val == "on_trigger") {
			evnt->activate_type = EVENT_ON_TRIGGER;
		}
		else if (infile.val == "on_mapexit") {
			// no need to set keep_after_trigger to false correctly, it's ignored anyway
			evnt->activate_type = EVENT_ON_MAPEXIT;
		}
		else if (infile.val == "on_leave") {
			evnt->activate_type = EVENT_ON_LEAVE;
		}
		else if (infile.val == "on_load") {
			evnt->activate_type = EVENT_ON_LOAD;
			evnt->keep_after_trigger = false;
		}
		else if (infile.val == "on_clear") {
			evnt->activate_type = EVENT_ON_CLEAR;
			evnt->keep_after_trigger = false;
		}
		else if (infile.val == "static") {
			evnt->activate_type = EVENT_STATIC;
		}
		else {
			infile.error("EventManager: Event activation type '%s' unknown, change to \"on_trigger\" to suppress this warning.", infile.val.c_str());
		}
	}
	else if (infile.key == "location") {
		// @ATTR event.location|rectangle|Defines the location area for the event.
		evnt->location.x = popFirstInt(infile.val);
		evnt->location.y = popFirstInt(infile.val);
		evnt->location.w = popFirstInt(infile.val);
		evnt->location.h = popFirstInt(infile.val);

		if (evnt->center.x == -1 && evnt->center.y == -1) {
			evnt->center.x = static_cast<float>(evnt->location.x) + static_cast<float>(evnt->location.w)/2;
			evnt->center.y = static_cast<float>(evnt->location.y) + static_cast<float>(evnt->location.h)/2;
		}
	}
	else if (infile.key == "hotspot") {
		//  @ATTR event.hotspot|["location", rectangle]|Event uses location as hotspot or defined by rect.
		if (infile.val == "location") {
			evnt->hotspot.x = evnt->location.x;
			evnt->hotspot.y = evnt->location.y;
			evnt->hotspot.w = evnt->location.w;
			evnt->hotspot.h = evnt->location.h;
		}
		else {
			evnt->hotspot.x = popFirstInt(infile.val);
			evnt->hotspot.y = popFirstInt(infile.val);
			evnt->hotspot.w = popFirstInt(infile.val);
			evnt->hotspot.h = popFirstInt(infile.val);
		}

		evnt->center.x = static_cast<float>(evnt->hotspot.x) + static_cast<float>(evnt->hotspot.w)/2;
		evnt->center.y = static_cast<float>(evnt->hotspot.y) + static_cast<float>(evnt->hotspot.h)/2;
	}
	else if (infile.key == "cooldown") {
		// @ATTR event.cooldown|duration|Duration for event cooldown in 'ms' or 's'.
		evnt->cooldown = parse_duration(infile.val);
	}
	else if (infile.key == "delay") {
		// @ATTR event.delay|duration|Event will execute after a specified duration.
		evnt->delay = parse_duration(infile.val);
	}
	else if (infile.key == "reachable_from") {
		// @ATTR event.reachable_from|rectangle|If the hero is inside this rectangle, they can activate the event.
		evnt->reachable_from.x = popFirstInt(infile.val);
		evnt->reachable_from.y = popFirstInt(infile.val);
		evnt->reachable_from.w = popFirstInt(infile.val);
		evnt->reachable_from.h = popFirstInt(infile.val);
	}
	else {
		loadEventComponent(infile, evnt, NULL);
	}
}
示例#15
0
int main(int argc, char *argv[])
{
    int ch, exit_status, status;
    pid_t bill;

    exit_status = EXIT_SUCCESS;

    while ((ch = getopt(argc, argv, "h?q")) != -1) {
        switch (ch) {
        case 'q':
            Flag_Quiet = true;
            break;

        case 'h':
        case '?':
        default:
            emit_help();
            /* NOTREACHED */
        }
    }
    argc -= optind;
    argv += optind;

    if (argc < 2)
        emit_help();

    iTimer.it_value.tv_sec = parse_duration(*argv++);

    bill = vfork();
    if (bill == 0) {            /* child */
        if (execvp(*argv, argv) == -1)
            err(EX_OSERR, "could not exec %s", *argv);
        /* NOTREACHED */

    } else if (bill > 0) {      /* parent */
        /* do not restart the wait() after SIGALRM, skip to the end... */
        if (siginterrupt(SIGALRM, 1) == -1)
            err(EX_SOFTWARE, "could not siginterrupt()");

        if (signal(SIGALRM, handle_alarm) == SIG_ERR)
            err(EX_SOFTWARE, "could not setup signal()");

        if (setitimer(ITIMER_REAL, &iTimer, NULL) == -1)
            err(EX_SOFTWARE, "could not setitimer()");

        wait(&status);

        /* the end */
        if (Kill_Bill) {
            if (!Flag_Quiet)
                warnx("duration %ld exceeded: killing pid %d",
                      (long)iTimer.it_value.tv_sec, bill);
            /*
             * Assume child is well behaved, and does not deadlock or
             * otherwise require multiple signals (race condition risk) to
             * take down.
             */
            if (kill(bill, SIGTERM) == -1)
                err(EX_OSERR, "could not kill child pid %d", bill);

            exit_status = EXIT_TIMEOUT;
        } else {
            /*
             * Pass on the child exit status. These can be illustrated
             * via something like:
             *
             *   timeout 99 perl -e 'exit 42'      ; echo $?
             *   timeout 99 perl -e 'kill 15, $$'  ; echo $?
             */
            if (WIFEXITED(status))
                exit_status = WEXITSTATUS(status);
            else if (WIFSIGNALED(status))
                exit_status = 128 + WTERMSIG(status);
        }
    } else {
        err(EX_OSERR, "could not fork()");
    }

    exit(exit_status);
}
示例#16
0
文件: timeout.c 项目: fengsi/freebsd
int
main(int argc, char **argv)
{
    int ch;
    unsigned long i;
    int foreground, preserve;
    int error, pstat, status;
    int killsig = SIGTERM;
    pid_t pid, cpid;
    double first_kill;
    double second_kill;
    bool timedout = false;
    bool do_second_kill = false;
    bool child_done = false;
    struct sigaction signals;
    struct procctl_reaper_status info;
    struct procctl_reaper_kill killemall;
    int signums[] = {
        -1,
        SIGTERM,
        SIGINT,
        SIGHUP,
        SIGCHLD,
        SIGALRM,
        SIGQUIT,
    };

    foreground = preserve = 0;
    second_kill = 0;

    const struct option longopts[] = {
        { "preserve-status", no_argument,       &preserve,    1 },
        { "foreground",      no_argument,       &foreground,  1 },
        { "kill-after",      required_argument, NULL,        'k'},
        { "signal",          required_argument, NULL,        's'},
        { "help",            no_argument,       NULL,        'h'},
        { NULL,              0,                 NULL,         0 }
    };

    while ((ch = getopt_long(argc, argv, "+k:s:h", longopts, NULL)) != -1) {
        switch (ch) {
        case 'k':
            do_second_kill = true;
            second_kill = parse_duration(optarg);
            break;
        case 's':
            killsig = parse_signal(optarg);
            break;
        case 0:
            break;
        case 'h':
        default:
            usage();
            break;
        }
    }

    argc -= optind;
    argv += optind;

    if (argc < 2)
        usage();

    first_kill = parse_duration(argv[0]);
    argc--;
    argv++;

    if (!foreground) {
        /* Aquire a reaper */
        if (procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) == -1)
            err(EX_OSERR, "Fail to acquire the reaper");
    }

    memset(&signals, 0, sizeof(signals));
    sigemptyset(&signals.sa_mask);

    if (killsig != SIGKILL && killsig != SIGSTOP)
        signums[0] = killsig;

    for (i = 0; i < sizeof(signums) / sizeof(signums[0]); i ++)
        sigaddset(&signals.sa_mask, signums[i]);

    signals.sa_handler = sig_handler;
    signals.sa_flags = SA_RESTART;

    for (i = 0; i < sizeof(signums) / sizeof(signums[0]); i ++)
        if (signums[i] != -1 && signums[i] != 0 &&
                sigaction(signums[i], &signals, NULL) == -1)
            err(EX_OSERR, "sigaction()");

    signal(SIGTTIN, SIG_IGN);
    signal(SIGTTOU, SIG_IGN);

    pid = fork();
    if (pid == -1)
        err(EX_OSERR, "fork()");
    else if (pid == 0) {
        /* child process */
        signal(SIGTTIN, SIG_DFL);
        signal(SIGTTOU, SIG_DFL);

        error = execvp(argv[0], argv);
        if (error == -1) {
            if (errno == ENOENT)
                err(127, "exec(%s)", argv[0]);
            else
                err(126, "exec(%s)", argv[0]);
        }
    }

    if (sigprocmask(SIG_BLOCK, &signals.sa_mask, NULL) == -1)
        err(EX_OSERR, "sigprocmask()");

    /* parent continues here */
    set_interval(first_kill);

    for (;;) {
        sigemptyset(&signals.sa_mask);
        sigsuspend(&signals.sa_mask);

        if (sig_chld) {
            sig_chld = 0;

            while ((cpid = waitpid(-1, &status, WNOHANG)) != 0) {
                if (cpid < 0) {
                    if (errno == EINTR)
                        continue;
                    else
                        break;
                } else if (cpid == pid) {
                    pstat = status;
                    child_done = true;
                }
            }
            if (child_done) {
                if (foreground) {
                    break;
                } else {
                    procctl(P_PID, getpid(),
                            PROC_REAP_STATUS, &info);
                    if (info.rs_children == 0)
                        break;
                }
            }
        } else if (sig_alrm) {
            sig_alrm = 0;

            timedout = true;
            if (!foreground) {
                killemall.rk_sig = killsig;
                killemall.rk_flags = 0;
                procctl(P_PID, getpid(), PROC_REAP_KILL,
                        &killemall);
            } else
                kill(pid, killsig);

            if (do_second_kill) {
                set_interval(second_kill);
                second_kill = 0;
                sig_ign = killsig;
                killsig = SIGKILL;
            } else
                break;

        } else if (sig_term) {
            if (!foreground) {
                killemall.rk_sig = sig_term;
                killemall.rk_flags = 0;
                procctl(P_PID, getpid(), PROC_REAP_KILL,
                        &killemall);
            } else
                kill(pid, sig_term);

            if (do_second_kill) {
                set_interval(second_kill);
                second_kill = 0;
                sig_ign = killsig;
                killsig = SIGKILL;
            } else
                break;
        }
    }

    while (!child_done && wait(&pstat) == -1) {
        if (errno != EINTR)
            err(EX_OSERR, "waitpid()");
    }

    if (!foreground)
        procctl(P_PID, getpid(), PROC_REAP_RELEASE, NULL);

    if (WEXITSTATUS(pstat))
        pstat = WEXITSTATUS(pstat);
    else if(WIFSIGNALED(pstat))
        pstat = 128 + WTERMSIG(pstat);

    if (timedout && !preserve)
        pstat = EXIT_TIMEOUT;

    return (pstat);
}
示例#17
0
文件: timeout.c 项目: Alkzndr/freebsd
int
main(int argc, char **argv)
{
	int ch;
	unsigned long i;
	int foreground, preserve;
	int error, pstat, status;
	int killsig = SIGTERM;
	pid_t pgid, pid, cpid;
	double first_kill;
	double second_kill;
	bool timedout = false;
	bool do_second_kill = false;
	struct sigaction signals;
	int signums[] = {
		-1,
		SIGTERM,
		SIGINT,
		SIGHUP,
		SIGCHLD,
		SIGALRM,
		SIGQUIT,
	};

	foreground = preserve = 0;
	second_kill = 0;
	cpid = -1;
	pgid = -1;

	const struct option longopts[] = {
		{ "preserve-status", no_argument,       &preserve,    1 },
		{ "foreground",      no_argument,       &foreground,  1 },
		{ "kill-after",      required_argument, NULL,        'k'},
		{ "signal",          required_argument, NULL,        's'},
		{ "help",            no_argument,       NULL,        'h'},
		{ NULL,              0,                 NULL,         0 }
	};

	while ((ch = getopt_long(argc, argv, "+k:s:h", longopts, NULL)) != -1) {
		switch (ch) {
			case 'k':
				do_second_kill = true;
				second_kill = parse_duration(optarg);
				break;
			case 's':
				killsig = parse_signal(optarg);
				break;
			case 0:
				break;
			case 'h':
			default:
				usage();
				break;
		}
	}

	argc -= optind;
	argv += optind;

	if (argc < 2)
		usage();

	first_kill = parse_duration(argv[0]);
	argc--;
	argv++;

	if (!foreground) {
		pgid = setpgid(0,0);

		if (pgid == -1)
			err(EX_OSERR, "setpgid()");
	}

	memset(&signals, 0, sizeof(signals));
	sigemptyset(&signals.sa_mask);

	if (killsig != SIGKILL && killsig != SIGSTOP)
		signums[0] = killsig;

	for (i = 0; i < sizeof(signums) / sizeof(signums[0]); i ++)
		sigaddset(&signals.sa_mask, signums[i]);

	signals.sa_handler = sig_handler;
	signals.sa_flags = SA_RESTART;

	for (i = 0; i < sizeof(signums) / sizeof(signums[0]); i ++)
		if (signums[i] != -1 && signums[i] != 0 &&
		    sigaction(signums[i], &signals, NULL) == -1)
			err(EX_OSERR, "sigaction()");

	signal(SIGTTIN, SIG_IGN);
	signal(SIGTTOU, SIG_IGN);

	pid = fork();
	if (pid == -1)
		err(EX_OSERR, "fork()");
	else if (pid == 0) {
		/* child process */
		signal(SIGTTIN, SIG_DFL);
		signal(SIGTTOU, SIG_DFL);

		error = execvp(argv[0], argv);
		if (error == -1)
			err(EX_UNAVAILABLE, "exec()");
	}

	if (sigprocmask(SIG_BLOCK, &signals.sa_mask, NULL) == -1)
		err(EX_OSERR, "sigprocmask()");

	/* parent continues here */
	set_interval(first_kill);

	for (;;) {
		sigemptyset(&signals.sa_mask);
		sigsuspend(&signals.sa_mask);

		if (sig_chld) {
			sig_chld = 0;
			while (((cpid = wait(&status)) < 0) && errno == EINTR)
				continue;

			if (cpid == pid) {
				pstat = status;
				break;
			}
		} else if (sig_alrm) {
			sig_alrm = 0;

			timedout = true;
			if (!foreground)
				killpg(pgid, killsig);
			else
				kill(pid, killsig);

			if (do_second_kill) {
				set_interval(second_kill);
				second_kill = 0;
				sig_ign = killsig;
				killsig = SIGKILL;
			} else
				break;

		} else if (sig_term) {
			if (!foreground)
				killpg(pgid, killsig);
			else
				kill(pid, sig_term);

			if (do_second_kill) {
				set_interval(second_kill);
				second_kill = 0;
				sig_ign = killsig;
				killsig = SIGKILL;
			} else
				break;
		}
	}

	while (cpid != pid  && wait(&pstat) == -1) {
		if (errno != EINTR)
			err(EX_OSERR, "waitpid()");
	}

	if (WEXITSTATUS(pstat))
		pstat = WEXITSTATUS(pstat);
	else if(WIFSIGNALED(pstat))
		pstat = 128 + WTERMSIG(pstat);

	if (timedout && !preserve)
		pstat = EXIT_TIMEOUT;

	return (pstat);
}
bool GameStateCutscene::load(const std::string& filename) {
	CutsceneSettings settings;
	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(new Scene(settings, CUTSCENE_STATIC));
			}
			else if (infile.section == "vscroll") {
				// if the previous scene was also a vertical scroller, don't create a new scene
				// instead, the previous scene will be extended
				if (scenes.empty() || scenes.front()->cutscene_type != CUTSCENE_VSCROLL) {
					scenes.push(new Scene(settings, CUTSCENE_VSCROLL));
				}
			}
		}

		if (infile.section.empty()) {
			if (infile.key == "scale_gfx") {
				// @ATTR scale_gfx|bool|The graphics will be scaled to fit screen width
				settings.scale_graphics = toBool(infile.val);
			}
			else if (infile.key == "caption_margins") {
				// @ATTR caption_margins|float, float : X margin, Y margin|Percentage-based margins for the caption text based on screen size
				settings.caption_margins.x = toFloat(infile.nextValue())/100.0f;
				settings.caption_margins.y = toFloat(infile.val)/100.0f;
			}
			else if (infile.key == "vscroll_speed") {
				// @ATTR vscroll_speed|float|The speed at which elements will scroll in 'vscroll' scenes.
				settings.vscroll_speed = toFloat(infile.val);
			}
			else if (infile.key == "menu_backgrounds") {
				// @ATTR menu_backgrounds|bool|This cutscene will use a random fullscreen background image, like the title screen does
				has_background = true;
			}
			else {
				infile.error("GameStateCutscene: '%s' is not a valid key.", infile.key.c_str());
			}
		}
		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|filename|Filename of 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 in 'ms' or 's'.
				sc.type = infile.key;
				sc.x = parse_duration(infile.val);
			}
			else if (infile.key == "soundfx") {
				// @ATTR scene.soundfx|filename|Filename of a sound that will be played
				sc.type = infile.key;
				sc.s = infile.val;
			}
			else {
				infile.error("GameStateCutscene: '%s' is not a valid key.", infile.key.c_str());
			}

			if (sc.type != "")
				scenes.back()->components.push(sc);

		}
		else if (infile.section == "vscroll") {
			SceneComponent sc = SceneComponent();

			if (infile.key == "text") {
				// @ATTR vscroll.text|string|A single, non-wrapping line of text.
				sc.type = infile.key;
				sc.s = msg->get(infile.val);
			}
			else if (infile.key == "image") {
				// @ATTR vscroll.image|filename|Filename of an image that will be shown.
				sc.type = infile.key;
				sc.s = infile.val;
			}
			else if (infile.key == "separator") {
				// @ATTR vscroll.separator|int|Places an invisible gap of a specified height between elements.
				sc.type = infile.key;
				sc.x = toInt(infile.nextValue());
			}
			else {
				infile.error("GameStateCutscene: '%s' is not a valid key.", infile.key.c_str());
			}

			if (sc.type != "")
				scenes.back()->components.push(sc);

		}
		else {
			infile.error("GameStateCutscene: '%s' is not a valid section.", infile.section.c_str());
		}

	}

	infile.close();

	if (scenes.empty()) {
		logError("GameStateCutscene: No scenes defined in cutscene file %s", filename.c_str());
		return false;
	}

	return true;
}
示例#19
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|filename|Filename of a tile sheet image.
				loadGraphics(infile.val);
			}
			else if (infile.key == "tile") {
				// @ATTR tile|int, int, int, int, int, int, int : Index, X, Y, Width, Height, X offset, Y offset|A single tile definition.

				// Verify that we have graphics for tiles
				if (!sprites) {
					infile.error("Tileset: No 'img' defined. Aborting.");
					logErrorDialog("Tileset: No 'img' defined. Aborting.");
					mods->resetModConfig();
					Exit(1);
				}

				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|color|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|list(int, int, int, duration) : Tile index, X, Y, duration|An animation for a tile. Durations are in 'ms' or 's'.
				int frame = 0;
				unsigned TILE_ID = popFirstInt(infile.val);

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

				std::string repeat_val = popFirstString(infile.val);
				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 = popFirstInt(infile.val);
					anim[TILE_ID].frame_duration[frame] = static_cast<unsigned short>(parse_duration(popFirstString(infile.val)));

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

	current_map = filename;
}
示例#20
0
int
main (int argc, char *argv[])
{
  struct gengetopt_args_info args_info;
  char *secret;
  size_t secretlen = 0;
  int rc;
  size_t window;
  uint64_t moving_factor;
  unsigned digits;
  char otp[10];
  time_t now, when, t0, time_step_size;
  int totpflags = 0;

  set_program_name (argv[0]);

  if (cmdline_parser (argc, argv, &args_info) != 0)
    return EXIT_FAILURE;

  if (args_info.version_given)
    {
      char *p;
      int l = -1;

      if (strcmp (oath_check_version (NULL), OATH_VERSION) != 0)
	l = asprintf (&p, "OATH Toolkit liboath.so %s oath.h %s",
		      oath_check_version (NULL), OATH_VERSION);
      else if (strcmp (OATH_VERSION, PACKAGE_VERSION) != 0)
	l = asprintf (&p, "OATH Toolkit %s",
		      oath_check_version (NULL), OATH_VERSION);
      version_etc (stdout, "oathtool", l == -1 ? "OATH Toolkit" : p,
		   PACKAGE_VERSION, "Simon Josefsson", (char *) NULL);
      if (l != -1)
	free (p);
      return EXIT_SUCCESS;
    }

  if (args_info.help_given)
    usage (EXIT_SUCCESS);

  if (args_info.inputs_num == 0)
    {
      cmdline_parser_print_help ();
      emit_bug_reporting_address ();
      return EXIT_SUCCESS;
    }

  rc = oath_init ();
  if (rc != OATH_OK)
    error (EXIT_FAILURE, 0, "liboath initialization failed: %s",
	   oath_strerror (rc));

  if (args_info.base32_flag)
    {
      rc = oath_base32_decode (args_info.inputs[0],
			       strlen (args_info.inputs[0]),
			       &secret, &secretlen);
      if (rc != OATH_OK)
	error (EXIT_FAILURE, 0, "base32 decoding failed: %s",
	       oath_strerror (rc));
    }
  else
    {
      secretlen = 1 + strlen (args_info.inputs[0]) / 2;
      secret = malloc (secretlen);
      if (!secret)
	error (EXIT_FAILURE, errno, "malloc");

      rc = oath_hex2bin (args_info.inputs[0], secret, &secretlen);
      if (rc != OATH_OK)
	error (EXIT_FAILURE, 0, "hex decoding of secret key failed");
    }

  if (args_info.counter_orig)
    moving_factor = args_info.counter_arg;
  else
    moving_factor = 0;

  if (args_info.digits_orig)
    digits = args_info.digits_arg;
  else
    digits = 6;

  if (args_info.window_orig)
    window = args_info.window_arg;
  else
    window = 0;

  if (digits != 6 && digits != 7 && digits != 8)
    error (EXIT_FAILURE, 0, "only digits 6, 7 and 8 are supported");

  if (validate_otp_p (args_info.inputs_num) && !args_info.digits_orig)
    digits = strlen (args_info.inputs[1]);
  else if (validate_otp_p (args_info.inputs_num) && args_info.digits_orig &&
	   args_info.digits_arg != strlen (args_info.inputs[1]))
    error (EXIT_FAILURE, 0,
	   "given one-time password has bad length %d != %ld",
	   args_info.digits_arg, strlen (args_info.inputs[1]));

  if (args_info.inputs_num > 2)
    error (EXIT_FAILURE, 0, "too many parameters");

  if (args_info.verbose_flag)
    {
      char *tmp;

      tmp = malloc (2 * secretlen + 1);
      if (!tmp)
	error (EXIT_FAILURE, errno, "malloc");

      oath_bin2hex (secret, secretlen, tmp);

      printf ("Hex secret: %s\n", tmp);
      free (tmp);

      rc = oath_base32_encode (secret, secretlen, &tmp, NULL);
      if (rc != OATH_OK)
	error (EXIT_FAILURE, 0, "base32 encoding failed: %s",
	       oath_strerror (rc));

      printf ("Base32 secret: %s\n", tmp);
      free (tmp);

      if (args_info.inputs_num == 2)
	printf ("OTP: %s\n", args_info.inputs[1]);
      printf ("Digits: %d\n", digits);
      printf ("Window size: %ld\n", window);
    }

  if (args_info.totp_given)
    {
      now = time (NULL);
      when = parse_time (args_info.now_arg, now);
      t0 = parse_time (args_info.start_time_arg, now);
      time_step_size = parse_duration (args_info.time_step_size_arg);

      if (when == BAD_TIME)
	error (EXIT_FAILURE, 0, "cannot parse time `%s'", args_info.now_arg);

      if (t0 == BAD_TIME)
	error (EXIT_FAILURE, 0, "cannot parse time `%s'",
	       args_info.start_time_arg);

      if (time_step_size == BAD_TIME)
	error (EXIT_FAILURE, 0, "cannot parse time `%s'",
	       args_info.time_step_size_arg);

      if (strcmp (args_info.totp_arg, "sha256") == 0)
	totpflags = OATH_TOTP_HMAC_SHA256;
      else if (strcmp (args_info.totp_arg, "sha512") == 0)
	totpflags = OATH_TOTP_HMAC_SHA512;

      if (args_info.verbose_flag)
	verbose_totp (t0, time_step_size, when);
    }
  else
    {
      if (args_info.verbose_flag)
	verbose_hotp (moving_factor);
    }

  if (generate_otp_p (args_info.inputs_num) && !args_info.totp_given)
    {
      size_t iter = 0;

      do
	{
	  rc = oath_hotp_generate (secret,
				   secretlen,
				   moving_factor + iter,
				   digits,
				   false, OATH_HOTP_DYNAMIC_TRUNCATION, otp);
	  if (rc != OATH_OK)
	    error (EXIT_FAILURE, 0,
		   "generating one-time password failed (%d)", rc);

	  printf ("%s\n", otp);
	}
      while (window - iter++ > 0);
    }
  else if (generate_otp_p (args_info.inputs_num) && args_info.totp_given)
    {
      size_t iter = 0;

      do
	{
	  rc = oath_totp_generate2 (secret,
				    secretlen,
				    when + iter * time_step_size,
				    time_step_size, t0, digits, totpflags,
				    otp);
	  if (rc != OATH_OK)
	    error (EXIT_FAILURE, 0,
		   "generating one-time password failed (%d)", rc);

	  printf ("%s\n", otp);
	}
      while (window - iter++ > 0);
    }
  else if (validate_otp_p (args_info.inputs_num) && !args_info.totp_given)
    {
      rc = oath_hotp_validate (secret,
			       secretlen,
			       moving_factor, window, args_info.inputs[1]);
      if (rc == OATH_INVALID_OTP)
	error (EXIT_OTP_INVALID, 0,
	       "password \"%s\" not found in range %ld .. %ld",
	       args_info.inputs[1],
	       (long) moving_factor, (long) moving_factor + window);
      else if (rc < 0)
	error (EXIT_FAILURE, 0,
	       "validating one-time password failed (%d)", rc);
      printf ("%d\n", rc);
    }
  else if (validate_otp_p (args_info.inputs_num) && args_info.totp_given)
    {
      rc = oath_totp_validate4 (secret,
				secretlen,
				when,
				time_step_size,
				t0,
				window,
				NULL, NULL, totpflags, args_info.inputs[1]);
      if (rc == OATH_INVALID_OTP)
	error (EXIT_OTP_INVALID, 0,
	       "password \"%s\" not found in range %ld .. %ld",
	       args_info.inputs[1],
	       (long) ((when - t0) / time_step_size - window / 2),
	       (long) ((when - t0) / time_step_size + window / 2));
      else if (rc < 0)
	error (EXIT_FAILURE, 0,
	       "validating one-time password failed (%d)", rc);
      printf ("%d\n", rc);
    }

  free (secret);
  oath_done ();

  return EXIT_SUCCESS;
}
示例#21
0
void AnimationSet::load() {
	assert(!loaded);
	loaded = true;

	FileParser parser;
	// @CLASS AnimationSet|Description of animations in animations/
	if (!parser.open(name, true, "Error loading animation definition: " + name))
		return;

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

	unsigned short parent_anim_frames = 0;

	// Parse the file and on each new section create an animation object from the data parsed previously
	while (parser.next()) {
		// create the animation if finished parsing a section
		if (parser.new_section) {
			if (!first_section && !compressed_loading) {
				Animation *a = new Animation(_name, type, sprite);
				a->setupUncompressed(render_size, render_offset, position, frames, duration);
				if (!active_frames.empty())
					a->setActiveFrames(active_frames);
				active_frames.clear();
				animations.push_back(a);
			}
			first_section = false;
			compressed_loading = false;

			if (parent) {
				parent_anim_frames = static_cast<unsigned short>(parent->getAnimationFrames(parser.section));
			}
		}
		if (parser.key == "image") {
			// @ATTR image|filename|Filename of sprite-sheet image.
			if (sprite != NULL) {
				parser.error("AnimationSet: Multiple images specified. Dragons be here!");
				Exit(128);
			}

			sprite = render_device->loadImage(parser.val);
		}
		else if (parser.key == "position") {
			// @ATTR position|int|Number of frames to the right to use as the first frame. Unpacked animations only.
			position = static_cast<unsigned short>(toInt(parser.val));
		}
		else if (parser.key == "frames") {
			// @ATTR frames|int|The total number of frames
			frames = static_cast<unsigned short>(toInt(parser.val));
			if (parent && frames != parent_anim_frames) {
				parser.error("AnimationSet: Frame count %d != %d for matching animation in %s", frames, parent_anim_frames, parent->getName().c_str());
				frames = parent_anim_frames;
			}
		}
		else if (parser.key == "duration") {
			// @ATTR duration|duration|The duration of the entire animation in 'ms' or 's'.
			duration = static_cast<unsigned short>(parse_duration(parser.val));
		}
		else if (parser.key == "type")
			// @ATTR type|["play_once", "back_forth", "looped"]|How to loop (or not loop) this animation.
			type = parser.val;
		else if (parser.key == "render_size") {
			// @ATTR render_size|int, int : Width, Height|Width and height of animation.
			render_size.x = toInt(parser.nextValue());
			render_size.y = toInt(parser.nextValue());
		}
		else if (parser.key == "render_offset") {
			// @ATTR render_offset|int, int : X offset, Y offset|Render x/y offset.
			render_offset.x = toInt(parser.nextValue());
			render_offset.y = toInt(parser.nextValue());
		}
		else if (parser.key == "active_frame") {
			// @ATTR active_frame|[list(int), "all"]|A list of frames marked as "active". Also, "all" can be used to mark all frames as active.
			active_frames.clear();
			std::string nv = parser.nextValue();
			if (nv == "all") {
				active_frames.push_back(-1);
			}
			else {
				while (nv != "") {
					active_frames.push_back(static_cast<short>(toInt(nv)));
					nv = parser.nextValue();
				}
				std::sort(active_frames.begin(), active_frames.end());
				active_frames.erase(std::unique(active_frames.begin(), active_frames.end()), active_frames.end());
			}
		}
		else if (parser.key == "frame") {
			// @ATTR frame|int, int, int, int, int, int, int, int : Index, Direction, X, Y, Width, Height, X offset, Y offset|A single frame of a compressed animation.
			if (compressed_loading == false) { // first frame statement in section
				newanim = new Animation(_name, type, sprite);
				newanim->setup(frames, duration);
				if (!active_frames.empty())
					newanim->setActiveFrames(active_frames);
				active_frames.clear();
				animations.push_back(newanim);
				compressed_loading = true;
			}
			// frame = index, direction, x, y, w, h, offsetx, offsety
			Rect r;
			Point offset;
			const unsigned short index = static_cast<unsigned short>(toInt(parser.nextValue()));
			const unsigned short direction = static_cast<unsigned short>(toInt(parser.nextValue()));
			r.x = toInt(parser.nextValue());
			r.y = toInt(parser.nextValue());
			r.w = toInt(parser.nextValue());
			r.h = toInt(parser.nextValue());
			offset.x = toInt(parser.nextValue());
			offset.y = toInt(parser.nextValue());
			newanim->addFrame(index, direction, r, offset);
		}
		else {
			parser.error("AnimationSet: '%s' is not a valid key.", parser.key.c_str());
		}

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

	if (!compressed_loading) {
		// add final animation
		Animation *a = new Animation(_name, type, sprite);
		a->setupUncompressed(render_size, render_offset, position, frames, duration);
		if (!active_frames.empty())
			a->setActiveFrames(active_frames);
		active_frames.clear();
		animations.push_back(a);
	}

	if (starting_animation != "") {
		Animation *a = getAnimation(starting_animation);
		delete defaultAnimation;
		defaultAnimation = a;
	}
}
示例#22
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;
}
示例#23
0
void EventManager::loadEventComponent(FileParser &infile, Event* evnt, Event_Component* ec) {
	Event_Component *e = NULL;
	if (evnt) {
		evnt->components.push_back(Event_Component());
		e = &evnt->components.back();
	}
	else if (ec) {
		e = ec;
	}

	if (!e) return;

	e->type = EC_NONE;

	if (infile.key == "tooltip") {
		// @ATTR event.tooltip|string|Tooltip for event
		e->type = EC_TOOLTIP;

		e->s = msg->get(infile.val);
	}
	else if (infile.key == "power_path") {
		// @ATTR event.power_path|[hero:[x,y]]|Event power path
		e->type = EC_POWER_PATH;

		// x,y are src, if s=="hero" we target the hero,
		// else we'll use values in a,b as coordinates
		e->x = toInt(infile.nextValue());
		e->y = toInt(infile.nextValue());

		std::string dest = infile.nextValue();
		if (dest == "hero") {
			e->s = "hero";
		}
		else {
			e->a = toInt(dest);
			e->b = toInt(infile.nextValue());
		}
	}
	else if (infile.key == "power_damage") {
		// @ATTR event.power_damage|min(integer), max(integer)|Range of power damage
		e->type = EC_POWER_DAMAGE;

		e->a = toInt(infile.nextValue());
		e->b = toInt(infile.nextValue());
	}
	else if (infile.key == "intermap") {
		// @ATTR event.intermap|[map(string),x(integer),y(integer)]|Jump to specific map at location specified.
		e->type = EC_INTERMAP;

		e->s = infile.nextValue();
		e->x = toInt(infile.nextValue());
		e->y = toInt(infile.nextValue());
	}
	else if (infile.key == "intramap") {
		// @ATTR event.intramap|[x(integer),y(integer)]|Jump to specific position within current map.
		e->type = EC_INTRAMAP;

		e->x = toInt(infile.nextValue());
		e->y = toInt(infile.nextValue());
	}
	else if (infile.key == "mapmod") {
		// @ATTR event.mapmod|[string,int,int,int],..|Modify map tiles
		e->type = EC_MAPMOD;

		e->s = infile.nextValue();
		e->x = toInt(infile.nextValue());
		e->y = toInt(infile.nextValue());
		e->z = toInt(infile.nextValue());

		// add repeating mapmods
		if (evnt) {
			std::string repeat_val = infile.nextValue();
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_MAPMOD;
				e->s = repeat_val;
				e->x = toInt(infile.nextValue());
				e->y = toInt(infile.nextValue());
				e->z = toInt(infile.nextValue());

				repeat_val = infile.nextValue();
			}
		}
	}
	else if (infile.key == "soundfx") {
		// @ATTR event.soundfx|[soundfile(string),x(integer),y(integer),loop(boolean)]|Filename of a sound to play. Optionally, it can be played at a specific location and/or looped.
		e->type = EC_SOUNDFX;

		e->s = infile.nextValue();
		e->x = e->y = -1;
		e->z = static_cast<int>(false);

		std::string s = infile.nextValue();
		if (s != "") e->x = toInt(s);

		s = infile.nextValue();
		if (s != "") e->y = toInt(s);

		s = infile.nextValue();
		if (s != "") e->z = static_cast<int>(toBool(s));
	}
	else if (infile.key == "loot") {
		// @ATTR event.loot|[string,drop_chance([fixed:chance(integer)]),quantity_min(integer),quantity_max(integer)],...|Add loot to the event; either a filename or an inline definition.
		e->type = EC_LOOT;

		loot->parseLoot(infile, e, &evnt->components);
	}
	else if (infile.key == "loot_count") {
		// @ATTR event.loot_count|min (integer), max (integer)|Sets the minimum (and optionally, the maximum) amount of loot this event can drop. Overrides the global drop_max setting.
		e->type = EC_LOOT_COUNT;

		e->x = toInt(infile.nextValue());
		e->y = toInt(infile.nextValue());
		if (e->x != 0 || e->y != 0) {
			clampFloor(e->x, 1);
			clampFloor(e->y, e->x);
		}
	}
	else if (infile.key == "msg") {
		// @ATTR event.msg|string|Adds a message to be displayed for the event.
		e->type = EC_MSG;

		e->s = msg->get(infile.val);
	}
	else if (infile.key == "shakycam") {
		// @ATTR event.shakycam|duration|Makes the camera shake for this duration in 'ms' or 's'.
		e->type = EC_SHAKYCAM;

		e->x = parse_duration(infile.val);
	}
	else if (infile.key == "requires_status") {
		// @ATTR event.requires_status|string,...|Event requires list of statuses
		e->type = EC_REQUIRES_STATUS;

		e->s = infile.nextValue();

		// add repeating requires_status
		if (evnt) {
			std::string repeat_val = infile.nextValue();
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_REQUIRES_STATUS;
				e->s = repeat_val;

				repeat_val = infile.nextValue();
			}
		}
	}
	else if (infile.key == "requires_not_status") {
		// @ATTR event.requires_not_status|string,...|Event requires not list of statuses
		e->type = EC_REQUIRES_NOT_STATUS;

		e->s = infile.nextValue();

		// add repeating requires_not
		if (evnt) {
			std::string repeat_val = infile.nextValue();
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_REQUIRES_NOT_STATUS;
				e->s = repeat_val;

				repeat_val = infile.nextValue();
			}
		}
	}
	else if (infile.key == "requires_level") {
		// @ATTR event.requires_level|integer|Event requires hero level
		e->type = EC_REQUIRES_LEVEL;

		e->x = toInt(infile.nextValue());
	}
	else if (infile.key == "requires_not_level") {
		// @ATTR event.requires_not_level|integer|Event requires not hero level
		e->type = EC_REQUIRES_NOT_LEVEL;

		e->x = toInt(infile.nextValue());
	}
	else if (infile.key == "requires_currency") {
		// @ATTR event.requires_currency|integer|Event requires atleast this much currency
		e->type = EC_REQUIRES_CURRENCY;

		e->x = toInt(infile.nextValue());
	}
	else if (infile.key == "requires_not_currency") {
		// @ATTR event.requires_not_currency|integer|Event requires no more than this much currency
		e->type = EC_REQUIRES_NOT_CURRENCY;

		e->x = toInt(infile.nextValue());
	}
	else if (infile.key == "requires_item") {
		// @ATTR event.requires_item|integer,...|Event requires specific item
		e->type = EC_REQUIRES_ITEM;

		e->x = toInt(infile.nextValue());

		// add repeating requires_item
		if (evnt) {
			std::string repeat_val = infile.nextValue();
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_REQUIRES_ITEM;
				e->x = toInt(repeat_val);

				repeat_val = infile.nextValue();
			}
		}
	}
	else if (infile.key == "requires_not_item") {
		// @ATTR event.requires_not_item|integer,...|Event requires not having a specific item
		e->type = EC_REQUIRES_NOT_ITEM;

		e->x = toInt(infile.nextValue());

		// add repeating requires_not_item
		if (evnt) {
			std::string repeat_val = infile.nextValue();
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_REQUIRES_NOT_ITEM;
				e->x = toInt(repeat_val);

				repeat_val = infile.nextValue();
			}
		}
	}
	else if (infile.key == "requires_class") {
		// @ATTR event.requires_class|string|Event requires this base class
		e->type = EC_REQUIRES_CLASS;

		e->s = infile.nextValue();
	}
	else if (infile.key == "requires_not_class") {
		// @ATTR event.requires_not_class|string|Event requires not this base class
		e->type = EC_REQUIRES_NOT_CLASS;

		e->s = infile.nextValue();
	}
	else if (infile.key == "set_status") {
		// @ATTR event.set_status|string,...|Sets specified statuses
		e->type = EC_SET_STATUS;

		e->s = infile.nextValue();

		// add repeating set_status
		if (evnt) {
			std::string repeat_val = infile.nextValue();
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_SET_STATUS;
				e->s = repeat_val;

				repeat_val = infile.nextValue();
			}
		}
	}
	else if (infile.key == "unset_status") {
		// @ATTR event.unset_status|string,...|Unsets specified statuses
		e->type = EC_UNSET_STATUS;

		e->s = infile.nextValue();

		// add repeating unset_status
		if (evnt) {
			std::string repeat_val = infile.nextValue();
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_UNSET_STATUS;
				e->s = repeat_val;

				repeat_val = infile.nextValue();
			}
		}
	}
	else if (infile.key == "remove_currency") {
		// @ATTR event.remove_currency|integer|Removes specified amount of currency from hero inventory
		e->type = EC_REMOVE_CURRENCY;

		e->x = toInt(infile.val);
		clampFloor(e->x, 0);
	}
	else if (infile.key == "remove_item") {
		// @ATTR event.remove_item|integer,...|Removes specified item from hero inventory
		e->type = EC_REMOVE_ITEM;

		e->x = toInt(infile.nextValue());

		// add repeating remove_item
		if (evnt) {
			std::string repeat_val = infile.nextValue();
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_REMOVE_ITEM;
				e->x = toInt(repeat_val);

				repeat_val = infile.nextValue();
			}
		}
	}
	else if (infile.key == "reward_xp") {
		// @ATTR event.reward_xp|integer|Reward hero with specified amount of experience points.
		e->type = EC_REWARD_XP;

		e->x = toInt(infile.val);
		clampFloor(e->x, 0);
	}
	else if (infile.key == "reward_currency") {
		// @ATTR event.reward_currency|integer|Reward hero with specified amount of currency.
		e->type = EC_REWARD_CURRENCY;

		e->x = toInt(infile.val);
		clampFloor(e->x, 0);
	}
	else if (infile.key == "reward_item") {
		// @ATTR event.reward_item|x(integer),y(integer)|Reward hero with y number of item x.
		e->type = EC_REWARD_ITEM;

		e->x = toInt(infile.nextValue());
		e->y = toInt(infile.val);
		clampFloor(e->y, 0);
	}
	else if (infile.key == "restore") {
		// @ATTR event.restore|string|Restore the hero's HP, MP, and/or status.
		e->type = EC_RESTORE;

		e->s = infile.val;
	}
	else if (infile.key == "power") {
		// @ATTR event.power|power_id|Specify power coupled with event.
		e->type = EC_POWER;

		e->x = toInt(infile.val);
	}
	else if (infile.key == "spawn") {
		// @ATTR event.spawn|[string,x(integer),y(integer)], ...|Spawn an enemy from this category at location
		e->type = EC_SPAWN;

		e->s = infile.nextValue();
		e->x = toInt(infile.nextValue());
		e->y = toInt(infile.nextValue());

		// add repeating spawn
		if (evnt) {
			std::string repeat_val = infile.nextValue();
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_SPAWN;

				e->s = repeat_val;
				e->x = toInt(infile.nextValue());
				e->y = toInt(infile.nextValue());

				repeat_val = infile.nextValue();
			}
		}
	}
	else if (infile.key == "stash") {
		// @ATTR event.stash|boolean|Opens the Stash menu.
		e->type = EC_STASH;

		e->s = infile.val;
	}
	else if (infile.key == "npc") {
		// @ATTR event.npc|string|Filename of an NPC to start dialog with.
		e->type = EC_NPC;

		e->s = infile.val;
	}
	else if (infile.key == "music") {
		// @ATTR event.music|string|Change background music to specified file.
		e->type = EC_MUSIC;

		e->s = infile.val;
	}
	else if (infile.key == "cutscene") {
		// @ATTR event.cutscene|string|Show specified cutscene by filename.
		e->type = EC_CUTSCENE;

		e->s = infile.val;
	}
	else if (infile.key == "repeat") {
		// @ATTR event.repeat|boolean|Allows the event to be triggered again.
		e->type = EC_REPEAT;

		e->s = infile.val;
	}
	else if (infile.key == "save_game") {
		// @ATTR event.save_game|boolean|Saves the game when the event is triggered. The respawn position is set to where the player is standing.
		e->type = EC_SAVE_GAME;

		e->s = infile.val;
	}
	else if (infile.key == "book") {
		// @ATTR event.book|string|Opens a book by filename.
		e->type = EC_BOOK;

		e->s = infile.val;
	}
	else {
		infile.error("EventManager: '%s' is not a valid key.", infile.key.c_str());
	}
}
示例#24
0
void EventManager::loadEventComponent(FileParser &infile, Event* evnt, Event_Component* ec) {
    Event_Component *e = NULL;
    if (evnt) {
        evnt->components.push_back(Event_Component());
        e = &evnt->components.back();
    }
    else if (ec) {
        e = ec;
    }

    if (!e) return;

    e->type = infile.key;

    if (infile.key == "tooltip") {
        // @ATTR event.tooltip|string|Tooltip for event
        e->s = msg->get(infile.val);
    }
    else if (infile.key == "power_path") {
        // @ATTR event.power_path|[hero:[x,y]]|Event power path
        // x,y are src, if s=="hero" we target the hero,
        // else we'll use values in a,b as coordinates
        e->x = toInt(infile.nextValue());
        e->y = toInt(infile.nextValue());

        std::string dest = infile.nextValue();
        if (dest == "hero") {
            e->s = "hero";
        }
        else {
            e->a = toInt(dest);
            e->b = toInt(infile.nextValue());
        }
    }
    else if (infile.key == "power_damage") {
        // @ATTR event.power_damage|min(integer), max(integer)|Range of power damage
        e->a = toInt(infile.nextValue());
        e->b = toInt(infile.nextValue());
    }
    else if (infile.key == "intermap") {
        // @ATTR event.intermap|[map(string),x(integer),y(integer)]|Jump to specific map at location specified.
        e->s = infile.nextValue();
        e->x = toInt(infile.nextValue());
        e->y = toInt(infile.nextValue());
    }
    else if (infile.key == "intramap") {
        // @ATTR event.intramap|[x(integer),y(integer)]|Jump to specific position within current map.
        e->x = toInt(infile.nextValue());
        e->y = toInt(infile.nextValue());
    }
    else if (infile.key == "mapmod") {
        // @ATTR event.mapmod|[string,int,int,int],..|Modify map tiles
        e->s = infile.nextValue();
        e->x = toInt(infile.nextValue());
        e->y = toInt(infile.nextValue());
        e->z = toInt(infile.nextValue());

        // add repeating mapmods
        if (evnt) {
            std::string repeat_val = infile.nextValue();
            while (repeat_val != "") {
                evnt->components.push_back(Event_Component());
                e = &evnt->components.back();
                e->type = infile.key;
                e->s = repeat_val;
                e->x = toInt(infile.nextValue());
                e->y = toInt(infile.nextValue());
                e->z = toInt(infile.nextValue());

                repeat_val = infile.nextValue();
            }
        }
    }
    else if (infile.key == "soundfx") {
        // @ATTR event.soundfx|[soundfile(string),x(integer),y(integer)]|Filename of a sound to play at an optional location
        e->s = infile.nextValue();
        e->x = e->y = -1;

        std::string s = infile.nextValue();
        if (s != "") e->x = toInt(s);

        s = infile.nextValue();
        if (s != "") e->y = toInt(s);

    }
    else if (infile.key == "loot") {
        // @ATTR event.loot|[string,drop_chance([fixed:chance(integer)]),quantity_min(integer),quantity_max(integer)],...|Add loot to the event; either a filename or an inline definition.
        loot->parseLoot(infile, e, &evnt->components);
    }
    else if (infile.key == "msg") {
        // @ATTR event.msg|string|Adds a message to be displayed for the event.
        e->s = msg->get(infile.val);
    }
    else if (infile.key == "shakycam") {
        // @ATTR event.shakycam|duration|Makes the camera shake for this duration in 'ms' or 's'.
        e->x = parse_duration(infile.val);
    }
    else if (infile.key == "requires_status") {
        // @ATTR event.requires_status|string,...|Event requires list of statuses
        e->s = infile.nextValue();

        // add repeating requires_status
        if (evnt) {
            std::string repeat_val = infile.nextValue();
            while (repeat_val != "") {
                evnt->components.push_back(Event_Component());
                e = &evnt->components.back();
                e->type = infile.key;
                e->s = repeat_val;

                repeat_val = infile.nextValue();
            }
        }
    }
    else if (infile.key == "requires_not_status") {
        // @ATTR event.requires_not_status|string,...|Event requires not list of statuses
        e->s = infile.nextValue();

        // add repeating requires_not
        if (evnt) {
            std::string repeat_val = infile.nextValue();
            while (repeat_val != "") {
                evnt->components.push_back(Event_Component());
                e = &evnt->components.back();
                e->type = infile.key;
                e->s = repeat_val;

                repeat_val = infile.nextValue();
            }
        }
    }
    else if (infile.key == "requires_level") {
        // @ATTR event.requires_level|integer|Event requires hero level
        e->x = toInt(infile.nextValue());
    }
    else if (infile.key == "requires_not_level") {
        // @ATTR event.requires_not_level|integer|Event requires not hero level
        e->x = toInt(infile.nextValue());
    }
    else if (infile.key == "requires_currency") {
        // @ATTR event.requires_currency|integer|Event requires atleast this much currency
        e->x = toInt(infile.nextValue());
    }
    else if (infile.key == "requires_item") {
        // @ATTR event.requires_item|integer,...|Event requires specific item
        e->x = toInt(infile.nextValue());

        // add repeating requires_item
        if (evnt) {
            std::string repeat_val = infile.nextValue();
            while (repeat_val != "") {
                evnt->components.push_back(Event_Component());
                e = &evnt->components.back();
                e->type = infile.key;
                e->x = toInt(repeat_val);

                repeat_val = infile.nextValue();
            }
        }
    }
    else if (infile.key == "requires_class") {
        // @ATTR event.requires_class|string|Event requires this base class
        e->s = infile.nextValue();
    }
    else if (infile.key == "set_status") {
        // @ATTR event.set_status|string,...|Sets specified statuses
        e->s = infile.nextValue();

        // add repeating set_status
        if (evnt) {
            std::string repeat_val = infile.nextValue();
            while (repeat_val != "") {
                evnt->components.push_back(Event_Component());
                e = &evnt->components.back();
                e->type = infile.key;
                e->s = repeat_val;

                repeat_val = infile.nextValue();
            }
        }
    }
    else if (infile.key == "unset_status") {
        // @ATTR event.unset_status|string,...|Unsets specified statuses
        e->s = infile.nextValue();

        // add repeating unset_status
        if (evnt) {
            std::string repeat_val = infile.nextValue();
            while (repeat_val != "") {
                evnt->components.push_back(Event_Component());
                e = &evnt->components.back();
                e->type = infile.key;
                e->s = repeat_val;

                repeat_val = infile.nextValue();
            }
        }
    }
    else if (infile.key == "remove_currency") {
        // @ATTR event.remove_currency|integer|Removes specified amount of currency from hero inventory
        e->x = toInt(infile.val);
        clampFloor(e->x, 0);
    }
    else if (infile.key == "remove_item") {
        // @ATTR event.remove_item|integer,...|Removes specified item from hero inventory
        e->x = toInt(infile.nextValue());

        // add repeating remove_item
        if (evnt) {
            std::string repeat_val = infile.nextValue();
            while (repeat_val != "") {
                evnt->components.push_back(Event_Component());
                e = &evnt->components.back();
                e->type = infile.key;
                e->x = toInt(repeat_val);

                repeat_val = infile.nextValue();
            }
        }
    }
    else if (infile.key == "reward_xp") {
        // @ATTR event.reward_xp|integer|Reward hero with specified amount of experience points.
        e->x = toInt(infile.val);
        clampFloor(e->x, 0);
    }
    else if (infile.key == "reward_currency") {
        // @ATTR event.reward_currency|integer|Reward hero with specified amount of currency.
        e->x = toInt(infile.val);
        clampFloor(e->x, 0);
    }
    else if (infile.key == "reward_item") {
        // @ATTR event.reward_item|x(integer),y(integer)|Reward hero with y number of item x.
        e->x = toInt(infile.nextValue());
        e->y = toInt(infile.val);
        clampFloor(e->y, 0);
    }
    else if (infile.key == "restore") {
        // @ATTR event.restore|string|Restore the hero's HP, MP, and/or status.
        e->s = infile.val;
    }
    else if (infile.key == "power") {
        // @ATTR event.power|power_id|Specify power coupled with event.
        e->x = toInt(infile.val);
    }
    else if (infile.key == "spawn") {
        // @ATTR event.spawn|[string,x(integer),y(integer)], ...|Spawn an enemy from this category at location
        e->s = infile.nextValue();
        e->x = toInt(infile.nextValue());
        e->y = toInt(infile.nextValue());

        // add repeating spawn
        if (evnt) {
            std::string repeat_val = infile.nextValue();
            while (repeat_val != "") {
                evnt->components.push_back(Event_Component());
                e = &evnt->components.back();
                e->type = infile.key;

                e->s = repeat_val;
                e->x = toInt(infile.nextValue());
                e->y = toInt(infile.nextValue());

                repeat_val = infile.nextValue();
            }
        }
    }
    else if (infile.key == "stash") {
        // @ATTR event.stash|boolean|Opens the Stash menu.
        e->s = infile.val;
    }
    else if (infile.key == "npc") {
        // @ATTR event.npc|string|Filename of an NPC to start dialog with.
        e->s = infile.val;
    }
    else if (infile.key == "music") {
        // @ATTR event.music|string|Change background music to specified file.
        e->s = infile.val;
    }
    else if (infile.key == "cutscene") {
        // @ATTR event.cutscene|string|Show specified cutscene by filename.
        e->s = infile.val;
    }
    else if (infile.key == "repeat") {
        // @ATTR event.repeat|boolean|Allows the event to be triggered again.
        e->s = infile.val;
    }
    else if (infile.key == "save_game") {
        // @ATTR event.save_game|boolean|Saves the game when the event is triggered. The respawn position is set to where the player is standing.
        e->s = infile.val;
    }
    else {
        infile.error("EventManager: '%s' is not a valid key.", infile.key.c_str());
    }
}
示例#25
0
/**
 * load a statblock, typically for an enemy definition
 */
void StatBlock::load(const std::string& filename) {
	// @CLASS StatBlock: Enemies|Description of enemies in enemies/
	FileParser infile;
	if (!infile.open(filename))
		return;

	bool clear_loot = true;

	while (infile.next()) {
		if (infile.new_section) {
			// APPENDed file
			clear_loot = true;
		}

		int num = toInt(infile.val);
		float fnum = toFloat(infile.val);
		bool valid = loadCoreStat(&infile) || loadSfxStat(&infile);

		// @ATTR name|string|Name
		if (infile.key == "name") name = msg->get(infile.val);
		// @ATTR humanoid|boolean|This creature gives human traits when transformed into, such as the ability to talk with NPCs.
		else if (infile.key == "humanoid") humanoid = toBool(infile.val);

		// @ATTR level|integer|Level
		else if (infile.key == "level") level = num;

		// enemy death rewards and events
		// @ATTR xp|integer|XP awarded upon death.
		else if (infile.key == "xp") xp = num;
		else if (infile.key == "loot") {
			// @ATTR loot|[currency:item (integer)], chance (integer), min (integer), max (integer)|Possible loot that can be dropped on death.

			// loot entries format:
			// loot=[id],[percent_chance]
			// optionally allow range:
			// loot=[id],[percent_chance],[count_min],[count_max]

			if (clear_loot) {
				loot_table.clear();
				clear_loot = false;
			}

			loot_table.push_back(Event_Component());
			loot->parseLoot(infile, &loot_table.back(), &loot_table);
		}
		// @ATTR defeat_status|string|Campaign status to set upon death.
		else if (infile.key == "defeat_status") defeat_status = infile.val;
		// @ATTR convert_status|string|Campaign status to set upon being converted to a player ally.
		else if (infile.key == "convert_status") convert_status = infile.val;
		// @ATTR first_defeat_loot|integer|Drops this item upon first death.
		else if (infile.key == "first_defeat_loot") first_defeat_loot = num;
		// @ATTR quest_loot|[requires status (string), requires not status (string), item (integer)|Drops this item when campaign status is met.
		else if (infile.key == "quest_loot") {
			quest_loot_requires_status = infile.nextValue();
			quest_loot_requires_not_status = infile.nextValue();
			quest_loot_id = toInt(infile.nextValue());
		}
		// combat stats
		// @ATTR cooldown|integer|Cooldown between attacks in 'ms' or 's'.
		else if (infile.key == "cooldown") cooldown = parse_duration(infile.val);

		// behavior stats
		// @ATTR flying|boolean|Creature can move over gaps/water.
		else if (infile.key == "flying") flying = toBool(infile.val);
		// @ATTR intangible|boolean|Creature can move through walls.
		else if (infile.key == "intangible") intangible = toBool(infile.val);
		// @ATTR facing|boolean|Creature can turn to face their target.
		else if (infile.key == "facing") facing = toBool(infile.val);

		// @ATTR waypoint_pause|duration|Duration to wait at each waypoint in 'ms' or 's'.
		else if (infile.key == "waypoint_pause") waypoint_pause = parse_duration(infile.val);

		// @ATTR turn_delay|duration|Duration it takes for this creature to turn and face their target in 'ms' or 's'.
		else if (infile.key == "turn_delay") turn_delay = parse_duration(infile.val);
		// @ATTR chance_pursue|integer|Percentage change that the creature will chase their target.
		else if (infile.key == "chance_pursue") chance_pursue = num;
		// @ATTR chance_flee|integer|Percentage chance that the creature will run away from their target.
		else if (infile.key == "chance_flee") chance_flee = num;

		// @ATTR chance_melee_phys|integer|Percentage chance that the creature will use their physical melee power.
		else if (infile.key == "chance_melee_phys") power_chance[MELEE_PHYS] = num;
		// @ATTR chance_melee_ment|integer|Percentage chance that the creature will use their mental melee power.
		else if (infile.key == "chance_melee_ment") power_chance[MELEE_MENT] = num;
		// @ATTR chance_ranged_phys|integer|Percentage chance that the creature will use their physical ranged power.
		else if (infile.key == "chance_ranged_phys") power_chance[RANGED_PHYS] = num;
		// @ATTR chance_ranged_ment|integer|Percentage chance that the creature will use their mental ranged power.
		else if (infile.key == "chance_ranged_ment") power_chance[RANGED_MENT] = num;
		// @ATTR power_melee_phys|integer|Power index for the physical melee power.
		else if (infile.key == "power_melee_phys") power_index[MELEE_PHYS] = num;
		// @ATTR power_melee_ment|integer|Power index for the mental melee power.
		else if (infile.key == "power_melee_ment") power_index[MELEE_MENT] = num;
		// @ATTR power_ranged_phys|integer|Power index for the physical ranged power.
		else if (infile.key == "power_ranged_phys") power_index[RANGED_PHYS] = num;
		// @ATTR power_ranged_ment|integer|Power index for the mental ranged power.
		else if (infile.key == "power_ranged_ment") power_index[RANGED_MENT] = num;
		// @ATTR power_beacon|integer|Power index of a "beacon" power used to aggro nearby creatures.
		else if (infile.key == "power_beacon") power_index[BEACON] = num;
		// @ATTR power_on_hit|integer|Power index that is triggered when hit.
		else if (infile.key == "power_on_hit") power_index[ON_HIT] = num;
		// @ATTR power_on_death|integer|Power index that is triggered when dead.
		else if (infile.key == "power_on_death") power_index[ON_DEATH] = num;
		// @ATTR power_on_half_dead|integer|Power index that is triggered when at half health.
		else if (infile.key == "power_on_half_dead") power_index[ON_HALF_DEAD] = num;
		// @ATTR power_on_debuff|integer|Power index that is triggered when under a negative status effect.
		else if (infile.key == "power_on_debuff") power_index[ON_DEBUFF] = num;
		// @ATTR power_on_join_combat|integer|Power index that is triggered when initiating combat.
		else if (infile.key == "power_on_join_combat") power_index[ON_JOIN_COMBAT] = num;
		// @ATTR chance_on_hit|integer|Percentage chance that power_on_hit will be triggered.
		else if (infile.key == "chance_on_hit") power_chance[ON_HIT] = num;
		// @ATTR chance_on_death|integer|Percentage chance that power_on_death will be triggered.
		else if (infile.key == "chance_on_death") power_chance[ON_DEATH] = num;
		// @ATTR chance_on_half_dead|integer|Percentage chance that power_on_half_dead will be triggered.
		else if (infile.key == "chance_on_half_dead") power_chance[ON_HALF_DEAD] = num;
		// @ATTR chance_on_debuff|integer|Percentage chance that power_on_debuff will be triggered.
		else if (infile.key == "chance_on_debuff") power_chance[ON_DEBUFF] = num;
		// @ATTR chance_on_join_combat|integer|Percentage chance that power_on_join_combat will be triggered.
		else if (infile.key == "chance_on_join_combat") power_chance[ON_JOIN_COMBAT] = num;
		// @ATTR cooldown_hit|duration|Duration of cooldown after being hit in 'ms' or 's'.
		else if (infile.key == "cooldown_hit") cooldown_hit = parse_duration(infile.val);

		else if (infile.key == "passive_powers") {
			// @ATTR passive_powers|power (integer), ...|A list of passive powers this creature has.
			powers_passive.clear();
			std::string p = infile.nextValue();
			while (p != "") {
				powers_passive.push_back(toInt(p));
				p = infile.nextValue();
			}
		}

		// @ATTR melee_range|float|Minimum distance from target required to use melee powers.
		else if (infile.key == "melee_range") melee_range = fnum;
		// @ATTR threat_range|float|Radius of the area this creature will be able to start chasing the hero.
		else if (infile.key == "threat_range") threat_range = fnum;
		// @ATTR combat_style|[default:aggressive:passive]|How the creature will enter combat. Default is within range of the hero; Aggressive is always in combat; Passive must be attacked to enter combat.
		else if (infile.key == "combat_style") {
			if (infile.val == "default") combat_style = COMBAT_DEFAULT;
			else if (infile.val == "aggressive") combat_style = COMBAT_AGGRESSIVE;
			else if (infile.val == "passive") combat_style = COMBAT_PASSIVE;
			else infile.error("StatBlock: Unknown combat style '%s'", infile.val.c_str());
		}

		// @ATTR animations|string|Filename of an animation definition.
		else if (infile.key == "animations") animations = infile.val;

		// @ATTR suppress_hp|boolean|Hides the enemy HP bar for this creature.
		else if (infile.key == "suppress_hp") suppress_hp = toBool(infile.val);

		else if (infile.key == "categories") {
			// @ATTR categories|category (string), ...|Categories that this enemy belongs to.
			categories.clear();
			std::string cat;
			while ((cat = infile.nextValue()) != "") {
				categories.push_back(cat);
			}
		}

		// this is only used for EnemyGroupManager
		// we check for them here so that we don't get an error saying they are invalid
		else if (infile.key == "rarity") ; // but do nothing

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

	hp = starting[STAT_HP_MAX];
	mp = starting[STAT_MP_MAX];

	applyEffects();
}
示例#26
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();
	}
}
示例#27
0
bool StatBlock::loadCoreStat(FileParser *infile) {
	// @CLASS StatBlock: Core stats|Description of engine/stats.txt and enemies in enemies/

	if (infile->key == "speed") {
		// @ATTR speed|float|Movement speed
		float fvalue = toFloat(infile->val, 0);
		speed = speed_default = fvalue / MAX_FRAMES_PER_SEC;
		return true;
	}
	else if (infile->key == "cooldown") {
		// @ATTR cooldown|int|Cooldown between attacks in 'ms' or 's'.
		cooldown = parse_duration(infile->val);
		return true;
	}
	else if (infile->key == "cooldown_hit") {
		// @ATTR cooldown_hit|duration|Duration of cooldown after being hit in 'ms' or 's'.
		cooldown_hit = parse_duration(infile->val);
		return true;
	}
	else if (infile->key == "stat") {
		// @ATTR stat|string, int : Stat name, Value|The starting value for this stat.
		std::string stat = popFirstString(infile->val);
		int value = popFirstInt(infile->val);

		for (size_t i=0; i<STAT_COUNT; ++i) {
			if (STAT_KEY[i] == stat) {
				starting[i] = value;
				return true;
			}
		}

		for (size_t i = 0; i < DAMAGE_TYPES.size(); ++i) {
			if (DAMAGE_TYPES[i].min == stat) {
				starting[STAT_COUNT + (i*2)] = value;
				return true;
			}
			else if (DAMAGE_TYPES[i].max == stat) {
				starting[STAT_COUNT + (i*2) + 1] = value;
				return true;
			}
		}
	}
	else if (infile->key == "stat_per_level") {
		// @ATTR stat_per_level|predefined_string, int : Stat name, Value|The value for this stat added per level.
		std::string stat = popFirstString(infile->val);
		int value = popFirstInt(infile->val);

		for (unsigned i=0; i<STAT_COUNT; i++) {
			if (STAT_KEY[i] == stat) {
				per_level[i] = value;
				return true;
			}
		}

		for (size_t i = 0; i < DAMAGE_TYPES.size(); ++i) {
			if (DAMAGE_TYPES[i].min == stat) {
				per_level[STAT_COUNT + (i*2)] = value;
				return true;
			}
			else if (DAMAGE_TYPES[i].max == stat) {
				per_level[STAT_COUNT + (i*2) + 1] = value;
				return true;
			}
		}
	}
	else if (infile->key == "stat_per_primary") {
		// @ATTR stat_per_primary|predefined_string, predefined_string, int : Primary Stat, Stat name, Value|The value for this stat added for every point allocated to this primary stat.
		std::string prim_stat = popFirstString(infile->val);
		size_t prim_stat_index = getPrimaryStatIndex(prim_stat);

		std::string stat = popFirstString(infile->val);
		int value = popFirstInt(infile->val);

		for (unsigned i=0; i<STAT_COUNT; i++) {
			if (STAT_KEY[i] == stat) {
				per_primary[prim_stat_index][i] = value;
				return true;
			}
		}

		for (size_t i = 0; i < DAMAGE_TYPES.size(); ++i) {
			if (DAMAGE_TYPES[i].min == stat) {
				per_primary[prim_stat_index][STAT_COUNT + (i*2)] = value;
				return true;
			}
			else if (DAMAGE_TYPES[i].max == stat) {
				per_primary[prim_stat_index][STAT_COUNT + (i*2) + 1] = value;
				return true;
			}
		}
	}
	else if (infile->key == "vulnerable") {
		// @ATTR vulnerable|predefined_string, int : Element, Value|Percentage weakness to this element.
		std::string element = popFirstString(infile->val);
		int value = popFirstInt(infile->val);

		for (unsigned int i=0; i<ELEMENTS.size(); i++) {
			if (element == ELEMENTS[i].id) {
				vulnerable[i] = vulnerable_base[i] = value;
				return true;
			}
		}
	}
	else if (infile->key == "power_filter") {
		// @ATTR power_filter|list(power_id)|Only these powers are allowed to hit this entity.
		std::string power_id = popFirstString(infile->val);
		while (!power_id.empty()) {
			power_filter.push_back(toInt(power_id));
			power_id = popFirstString(infile->val);
		}
		return true;
	}

	return false;
}
示例#28
0
void EventManager::loadEvent(FileParser &infile, Event* evnt) {
	if (!evnt) return;
	// @CLASS EventManager|Description of events in maps/ and npcs/

	if (infile.key == "type") {
		// @ATTR event.type|[on_trigger:on_mapexit:on_leave:on_load:on_clear]|Type of map event.
		std::string type = infile.val;
		evnt->type = type;

		if      (type == "on_trigger");
		else if (type == "on_mapexit"); // no need to set keep_after_trigger to false correctly, it's ignored anyway
		else if (type == "on_leave");
		else if (type == "on_load") {
			evnt->keep_after_trigger = false;
		}
		else if (type == "on_clear") {
			evnt->keep_after_trigger = false;
		}
		else {
			infile.error("EventManager: Event type '%s' unknown, change to \"on_trigger\" to suppress this warning.", type.c_str());
		}
	}
	else if (infile.key == "location") {
		// @ATTR event.location|[x,y,w,h]|Defines the location area for the event.
		evnt->location.x = toInt(infile.nextValue());
		evnt->location.y = toInt(infile.nextValue());
		evnt->location.w = toInt(infile.nextValue());
		evnt->location.h = toInt(infile.nextValue());

		if (evnt->center.x == -1 && evnt->center.y == -1) {
			evnt->center.x = static_cast<float>(evnt->location.x) + static_cast<float>(evnt->location.w)/2;
			evnt->center.y = static_cast<float>(evnt->location.y) + static_cast<float>(evnt->location.h)/2;
		}
	}
	else if (infile.key == "hotspot") {
		//  @ATTR event.hotspot|[ [x, y, w, h] : location ]|Event uses location as hotspot or defined by rect.
		if (infile.val == "location") {
			evnt->hotspot.x = evnt->location.x;
			evnt->hotspot.y = evnt->location.y;
			evnt->hotspot.w = evnt->location.w;
			evnt->hotspot.h = evnt->location.h;
		}
		else {
			evnt->hotspot.x = toInt(infile.nextValue());
			evnt->hotspot.y = toInt(infile.nextValue());
			evnt->hotspot.w = toInt(infile.nextValue());
			evnt->hotspot.h = toInt(infile.nextValue());
		}

		evnt->center.x = static_cast<float>(evnt->hotspot.x) + static_cast<float>(evnt->hotspot.w)/2;
		evnt->center.y = static_cast<float>(evnt->hotspot.y) + static_cast<float>(evnt->hotspot.h)/2;
	}
	else if (infile.key == "cooldown") {
		// @ATTR event.cooldown|duration|Duration for event cooldown in 'ms' or 's'.
		evnt->cooldown = parse_duration(infile.val);
	}
	else if (infile.key == "reachable_from") {
		// @ATTR event.reachable_from|[x,y,w,h]|If the hero is inside this rectangle, they can activate the event.
		evnt->reachable_from.x = toInt(infile.nextValue());
		evnt->reachable_from.y = toInt(infile.nextValue());
		evnt->reachable_from.w = toInt(infile.nextValue());
		evnt->reachable_from.h = toInt(infile.nextValue());
	}
	else {
		loadEventComponent(infile, evnt, NULL);
	}
}
示例#29
0
bool EventManager::loadEventComponentString(std::string &key, std::string &val, Event* evnt, Event_Component* ec) {
	Event_Component *e = NULL;
	if (evnt) {
		evnt->components.push_back(Event_Component());
		e = &evnt->components.back();
	}
	else if (ec) {
		e = ec;
	}

	if (!e) return true;

	e->type = EC_NONE;

	if (key == "tooltip") {
		// @ATTR event.tooltip|string|Tooltip for event
		e->type = EC_TOOLTIP;

		e->s = msg->get(val);
	}
	else if (key == "power_path") {
		// @ATTR event.power_path|["hero", point]|Event power path
		e->type = EC_POWER_PATH;

		// x,y are src, if s=="hero" we target the hero,
		// else we'll use values in a,b as coordinates
		e->x = popFirstInt(val);
		e->y = popFirstInt(val);

		std::string dest = popFirstString(val);
		if (dest == "hero") {
			e->s = "hero";
		}
		else {
			e->a = toInt(dest);
			e->b = popFirstInt(val);
		}
	}
	else if (key == "power_damage") {
		// @ATTR event.power_damage|int, int : Min, Max|Range of power damage
		e->type = EC_POWER_DAMAGE;

		e->a = popFirstInt(val);
		e->b = popFirstInt(val);
	}
	else if (key == "intermap") {
		// @ATTR event.intermap|filename, int, int : Map file, X, Y|Jump to specific map at location specified.
		e->type = EC_INTERMAP;

		e->s = popFirstString(val);
		e->x = -1;
		e->y = -1;

		std::string test_x = popFirstString(val);
		if (!test_x.empty()) {
			e->x = toInt(test_x);
			e->y = popFirstInt(val);
		}
	}
	else if (key == "intermap_random") {
		// @ATTR event.intermap_random|filename|Pick a random map from a map list file and teleport to it.
		e->type = EC_INTERMAP;

		e->s = popFirstString(val);
		e->z = 1; // flag that tells an intermap event that it contains a map list
	}
	else if (key == "intramap") {
		// @ATTR event.intramap|int, int : X, Y|Jump to specific position within current map.
		e->type = EC_INTRAMAP;

		e->x = popFirstInt(val);
		e->y = popFirstInt(val);
	}
	else if (key == "mapmod") {
		// @ATTR event.mapmod|list(predefined_string, int, int, int) : Layer, X, Y, Tile ID|Modify map tiles
		e->type = EC_MAPMOD;

		e->s = popFirstString(val);
		e->x = popFirstInt(val);
		e->y = popFirstInt(val);
		e->z = popFirstInt(val);

		// add repeating mapmods
		if (evnt) {
			std::string repeat_val = popFirstString(val);
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_MAPMOD;
				e->s = repeat_val;
				e->x = popFirstInt(val);
				e->y = popFirstInt(val);
				e->z = popFirstInt(val);

				repeat_val = popFirstString(val);
			}
		}
	}
	else if (key == "soundfx") {
		// @ATTR event.soundfx|filename, int, int, bool : Sound file, X, Y, loop|Filename of a sound to play. Optionally, it can be played at a specific location and/or looped.
		e->type = EC_SOUNDFX;

		e->s = popFirstString(val);
		e->x = e->y = -1;
		e->z = static_cast<int>(false);

		std::string s = popFirstString(val);
		if (s != "") e->x = toInt(s);

		s = popFirstString(val);
		if (s != "") e->y = toInt(s);

		s = popFirstString(val);
		if (s != "") e->z = static_cast<int>(toBool(s));
	}
	else if (key == "loot") {
		// @ATTR event.loot|list(loot)|Add loot to the event.
		e->type = EC_LOOT;

		loot->parseLoot(val, e, &evnt->components);
	}
	else if (key == "loot_count") {
		// @ATTR event.loot_count|int, int : Min, Max|Sets the minimum (and optionally, the maximum) amount of loot this event can drop. Overrides the global drop_max setting.
		e->type = EC_LOOT_COUNT;

		e->x = popFirstInt(val);
		e->y = popFirstInt(val);
		if (e->x != 0 || e->y != 0) {
			e->x = std::max(e->x, 1);
			e->y = std::max(e->y, e->x);
		}
	}
	else if (key == "msg") {
		// @ATTR event.msg|string|Adds a message to be displayed for the event.
		e->type = EC_MSG;

		e->s = msg->get(val);
	}
	else if (key == "shakycam") {
		// @ATTR event.shakycam|duration|Makes the camera shake for this duration in 'ms' or 's'.
		e->type = EC_SHAKYCAM;

		e->x = parse_duration(val);
	}
	else if (key == "requires_status") {
		// @ATTR event.requires_status|list(string)|Event requires list of statuses
		e->type = EC_REQUIRES_STATUS;

		e->s = popFirstString(val);

		// add repeating requires_status
		if (evnt) {
			std::string repeat_val = popFirstString(val);
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_REQUIRES_STATUS;
				e->s = repeat_val;

				repeat_val = popFirstString(val);
			}
		}
	}
	else if (key == "requires_not_status") {
		// @ATTR event.requires_not_status|list(string)|Event requires not list of statuses
		e->type = EC_REQUIRES_NOT_STATUS;

		e->s = popFirstString(val);

		// add repeating requires_not
		if (evnt) {
			std::string repeat_val = popFirstString(val);
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_REQUIRES_NOT_STATUS;
				e->s = repeat_val;

				repeat_val = popFirstString(val);
			}
		}
	}
	else if (key == "requires_level") {
		// @ATTR event.requires_level|int|Event requires hero level
		e->type = EC_REQUIRES_LEVEL;

		e->x = popFirstInt(val);
	}
	else if (key == "requires_not_level") {
		// @ATTR event.requires_not_level|int|Event requires not hero level
		e->type = EC_REQUIRES_NOT_LEVEL;

		e->x = popFirstInt(val);
	}
	else if (key == "requires_currency") {
		// @ATTR event.requires_currency|int|Event requires atleast this much currency
		e->type = EC_REQUIRES_CURRENCY;

		e->x = popFirstInt(val);
	}
	else if (key == "requires_not_currency") {
		// @ATTR event.requires_not_currency|int|Event requires no more than this much currency
		e->type = EC_REQUIRES_NOT_CURRENCY;

		e->x = popFirstInt(val);
	}
	else if (key == "requires_item") {
		// @ATTR event.requires_item|list(item_id)|Event requires specific item (not equipped)
		e->type = EC_REQUIRES_ITEM;

		e->x = popFirstInt(val);

		// add repeating requires_item
		if (evnt) {
			std::string repeat_val = popFirstString(val);
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_REQUIRES_ITEM;
				e->x = toInt(repeat_val);

				repeat_val = popFirstString(val);
			}
		}
	}
	else if (key == "requires_not_item") {
		// @ATTR event.requires_not_item|list(item_id)|Event requires not having a specific item (not equipped)
		e->type = EC_REQUIRES_NOT_ITEM;

		e->x = popFirstInt(val);

		// add repeating requires_not_item
		if (evnt) {
			std::string repeat_val = popFirstString(val);
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_REQUIRES_NOT_ITEM;
				e->x = toInt(repeat_val);

				repeat_val = popFirstString(val);
			}
		}
	}
	else if (key == "requires_class") {
		// @ATTR event.requires_class|predefined_string|Event requires this base class
		e->type = EC_REQUIRES_CLASS;

		e->s = popFirstString(val);
	}
	else if (key == "requires_not_class") {
		// @ATTR event.requires_not_class|predefined_string|Event requires not this base class
		e->type = EC_REQUIRES_NOT_CLASS;

		e->s = popFirstString(val);
	}
	else if (key == "set_status") {
		// @ATTR event.set_status|list(string)|Sets specified statuses
		e->type = EC_SET_STATUS;

		e->s = popFirstString(val);

		// add repeating set_status
		if (evnt) {
			std::string repeat_val = popFirstString(val);
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_SET_STATUS;
				e->s = repeat_val;

				repeat_val = popFirstString(val);
			}
		}
	}
	else if (key == "unset_status") {
		// @ATTR event.unset_status|list(string)|Unsets specified statuses
		e->type = EC_UNSET_STATUS;

		e->s = popFirstString(val);

		// add repeating unset_status
		if (evnt) {
			std::string repeat_val = popFirstString(val);
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_UNSET_STATUS;
				e->s = repeat_val;

				repeat_val = popFirstString(val);
			}
		}
	}
	else if (key == "remove_currency") {
		// @ATTR event.remove_currency|int|Removes specified amount of currency from hero inventory
		e->type = EC_REMOVE_CURRENCY;

		e->x = std::max(toInt(val), 0);
	}
	else if (key == "remove_item") {
		// @ATTR event.remove_item|list(item_id)|Removes specified item from hero inventory
		e->type = EC_REMOVE_ITEM;

		e->x = popFirstInt(val);

		// add repeating remove_item
		if (evnt) {
			std::string repeat_val = popFirstString(val);
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_REMOVE_ITEM;
				e->x = toInt(repeat_val);

				repeat_val = popFirstString(val);
			}
		}
	}
	else if (key == "reward_xp") {
		// @ATTR event.reward_xp|int|Reward hero with specified amount of experience points.
		e->type = EC_REWARD_XP;

		e->x = std::max(toInt(val), 0);
	}
	else if (key == "reward_currency") {
		// @ATTR event.reward_currency|int|Reward hero with specified amount of currency.
		e->type = EC_REWARD_CURRENCY;

		e->x = std::max(toInt(val), 0);
	}
	else if (key == "reward_item") {
		// @ATTR event.reward_item|item_id, int : Item, Quantity|Reward hero with y number of item x.
		e->type = EC_REWARD_ITEM;

		e->x = popFirstInt(val);
		e->y = std::max(popFirstInt(val), 1);
	}
	else if (key == "restore") {
		// @ATTR event.restore|["hp", "mp", "hpmp", "status", "all"]|Restore the hero's HP, MP, and/or status.
		e->type = EC_RESTORE;

		e->s = val;
	}
	else if (key == "power") {
		// @ATTR event.power|power_id|Specify power coupled with event.
		e->type = EC_POWER;

		e->x = toInt(val);
	}
	else if (key == "spawn") {
		// @ATTR event.spawn|list(predefined_string, int, int) : Enemy category, X, Y|Spawn an enemy from this category at location
		e->type = EC_SPAWN;

		e->s = popFirstString(val);
		e->x = popFirstInt(val);
		e->y = popFirstInt(val);

		// add repeating spawn
		if (evnt) {
			std::string repeat_val = popFirstString(val);
			while (repeat_val != "") {
				evnt->components.push_back(Event_Component());
				e = &evnt->components.back();
				e->type = EC_SPAWN;

				e->s = repeat_val;
				e->x = popFirstInt(val);
				e->y = popFirstInt(val);

				repeat_val = popFirstString(val);
			}
		}
	}
	else if (key == "stash") {
		// @ATTR event.stash|bool|If true, the Stash menu if opened.
		e->type = EC_STASH;

		e->x = static_cast<int>(toBool(val));
	}
	else if (key == "npc") {
		// @ATTR event.npc|filename|Filename of an NPC to start dialog with.
		e->type = EC_NPC;

		e->s = val;
	}
	else if (key == "music") {
		// @ATTR event.music|filename|Change background music to specified file.
		e->type = EC_MUSIC;

		e->s = val;
	}
	else if (key == "cutscene") {
		// @ATTR event.cutscene|filename|Show specified cutscene by filename.
		e->type = EC_CUTSCENE;

		e->s = val;
	}
	else if (key == "repeat") {
		// @ATTR event.repeat|bool|If true, the event to be triggered again.
		e->type = EC_REPEAT;

		e->x = static_cast<int>(toBool(val));
	}
	else if (key == "save_game") {
		// @ATTR event.save_game|bool|If true, the game is saved when the event is triggered. The respawn position is set to where the player is standing.
		e->type = EC_SAVE_GAME;

		e->x = static_cast<int>(toBool(val));
	}
	else if (key == "book") {
		// @ATTR event.book|filename|Opens a book by filename.
		e->type = EC_BOOK;

		e->s = val;
	}
	else if (key == "script") {
		// @ATTR event.script|filename|Loads and executes an Event from a file.
		e->type = EC_SCRIPT;

		e->s = val;
	}
	else if (key == "chance_exec") {
		// @ATTR event.chance_exec|int|Percentage chance that this event will execute when triggered.
		e->type = EC_CHANCE_EXEC;

		e->x = popFirstInt(val);
	}
	else {
		return false;
	}

	return true;
}