Esempio n. 1
0
/**
 * Repeaters are multiple hazards that spawn in a straight line
 */
bool PowerManager::repeater(int power_index, StatBlock *src_stats, Point target) {
	// pay costs
	if (powers[power_index].requires_mp>0) src_stats->mp-=powers[power_index].requires_mp;
	used_item = powers[power_index].requires_item;
	
	//initialize variables
	Hazard *haz[10];
	FPoint location_iterator;
	FPoint speed;
	int delay_iterator;
	int map_speed = 64;

	// calculate speed
	float dx = (float)(target.x - src_stats->pos.x);
	float dy = (float)(target.y - src_stats->pos.y);
	float theta = atan(dy/dx);
	speed.x = (float)map_speed * cos(theta);
	speed.y = (float)map_speed * sin(theta);
	if (dx > 0.0 && speed.x < 0.0 || dx < 0.0 && speed.x > 0.0)
		speed.x *= -1.0;
	if (dy > 0.0 && speed.y < 0.0 || dy < 0.0 && speed.y > 0.0)
		speed.y *= -1.0;

	location_iterator.x = (float)src_stats->pos.x;
	location_iterator.y = (float)src_stats->pos.y;
	delay_iterator = 0;

	playSound(power_index, src_stats);

	for (int i=0; i<powers[power_index].repeater_num; i++) {

		location_iterator.x += speed.x;
		location_iterator.y += speed.y;

		// only travels until it hits a wall
		if (collider->is_wall((int)location_iterator.x, (int)location_iterator.y)) {
			break; // no more hazards
		}
		
		haz[i] = new Hazard();
		initHazard(power_index, src_stats, target, haz[i]);

		haz[i]->pos.x = location_iterator.x;
		haz[i]->pos.y = location_iterator.y;
		haz[i]->delay_frames = delay_iterator;
		delay_iterator += powers[power_index].delay;
		
		haz[i]->frame = powers[power_index].start_frame; // start at bottom frame
		
		hazards.push(haz[i]);
	}

	return true;
	
}
Esempio n. 2
0
/**
 * The activated power creates a group of missile hazards (e.g. arrow, thrown knife, firebolt).
 * Each individual missile is a single animated hazard that travels from the caster position to the
 * mouse target position.
 *
 * @param power_index The activated power ID
 * @param src_stats The StatBlock of the power activator
 * @param target The mouse cursor position in map coordinates
 * return boolean true if successful
 */
bool PowerManager::missile(int power_index, StatBlock *src_stats, Point target) {
	float pi = 3.1415926535898;

	Point src;
	if (powers[power_index].starting_pos == STARTING_POS_TARGET) {
		src.x = target.x;
		src.y = target.y;
	}
	else {
		src.x = src_stats->pos.x;
		src.y = src_stats->pos.y;
	}

	Hazard *haz;

	// calculate polar coordinates angle
	float theta = calcTheta(src.x, src.y, target.x, target.y);
	
	//generate hazards
	for (int i=0; i < powers[power_index].missile_num; i++) {
		haz = new Hazard();

		//calculate individual missile angle
		float offset_angle = ((1.0 - powers[power_index].missile_num)/2 + i) * (powers[power_index].missile_angle * pi / 180.0);
		float variance = 0;
		if (powers[power_index].angle_variance != 0)
			variance = pow(-1.0f, (rand() % 2) - 1) * (rand() % powers[power_index].angle_variance) * pi / 180.0; //random between 0 and angle_variance away
		float alpha = theta + offset_angle + variance;
		while (alpha >= pi+pi) alpha -= pi+pi;
		while (alpha < 0.0) alpha += pi+pi;

		initHazard(power_index, src_stats, target, haz);

		//calculate the missile velocity
		int speed_var = 0;
		if (powers[power_index].speed_variance != 0)
			speed_var = (int)(pow(-1.0f, (rand() % 2) - 1) * (rand() % powers[power_index].speed_variance + 1) - 1);
		haz->speed.x = (haz->base_speed + speed_var) * cos(alpha);
		haz->speed.y = (haz->base_speed + speed_var) * sin(alpha);
		
		//calculate direction based on trajectory, not actual target (UNITS_PER_TILE reduces round off error)
		if (powers[power_index].directional)
			haz->direction = calcDirection(src.x, src.y, src.x + UNITS_PER_TILE * haz->speed.x, src.y + UNITS_PER_TILE * haz->speed.y);
		
		hazards.push(haz);
	}

	// if all else succeeded, pay costs
	if (src_stats->hero && powers[power_index].requires_mp > 0) src_stats->mp -= powers[power_index].requires_mp;
	if (src_stats->hero && powers[power_index].requires_item != -1) used_item = powers[power_index].requires_item;

	playSound(power_index, src_stats);
	return true;
}
Esempio n. 3
0
/**
 * Repeaters are multiple hazards that spawn in a straight line
 */
bool PowerManager::repeater(int power_index, StatBlock *src_stats, Point target) {

	
	// pay costs up front
	if (src_stats->hero && powers[power_index].requires_mp > 0) src_stats->mp -= powers[power_index].requires_mp;
	if (src_stats->hero && powers[power_index].requires_item != -1) used_item = powers[power_index].requires_item;
	
	//initialize variables
	Hazard *haz[10];
	FPoint location_iterator;
	FPoint speed;
	int delay_iterator;
	int map_speed = 64;

	// calculate polar coordinates angle
	float theta = calcTheta(src_stats->pos.x, src_stats->pos.y, target.x, target.y);

	speed.x = (float)map_speed * cos(theta);
	speed.y = (float)map_speed * sin(theta);

	location_iterator.x = (float)src_stats->pos.x;
	location_iterator.y = (float)src_stats->pos.y;
	delay_iterator = 0;

	playSound(power_index, src_stats);

	for (int i=0; i<powers[power_index].repeater_num; i++) {

		location_iterator.x += speed.x;
		location_iterator.y += speed.y;

		// only travels until it hits a wall
		if (collider->is_wall((int)location_iterator.x, (int)location_iterator.y)) {
			break; // no more hazards
		}
		
		haz[i] = new Hazard();
		initHazard(power_index, src_stats, target, haz[i]);

		haz[i]->pos.x = location_iterator.x;
		haz[i]->pos.y = location_iterator.y;
		haz[i]->delay_frames = delay_iterator;
		delay_iterator += powers[power_index].delay;
		
		haz[i]->frame = powers[power_index].start_frame; // start at bottom frame
		
		hazards.push(haz[i]);
	}

	return true;
	
}
Esempio n. 4
0
/**
 * The activated power creates a group of missile hazards (e.g. arrow, thrown knife, firebolt).
 * Each individual missile is a single animated hazard that travels from the caster position to the
 * mouse target position.
 *
 * @param power_index The activated power ID
 * @param src_stats The StatBlock of the power activator
 * @param target The mouse cursor position in map coordinates
 * return boolean true if successful
 */
bool PowerManager::missile(int power_index, StatBlock *src_stats, Point target) {
	float pi = 3.1415926535898;

	Hazard *haz[powers[power_index].missile_num];

	// calculate base angle
	float dx = (float)target.x - (float)src_stats->pos.x;
	float dy = (float)target.y - (float)src_stats->pos.y;
	float theta = atan(dy/dx);
	if (dx > 0) theta += pi; //theta corrector

	//generate hazards
	for (int i=0; i < powers[power_index].missile_num; i++) {
		haz[i] = new Hazard();
		Point rot_target;

		//calculate individual missile angle
		float offset_angle = ((1.0 - powers[power_index].missile_num)/2 + i) * (powers[power_index].missile_angle * pi / 180.0);
		float variance = 0;
		if (powers[power_index].angle_variance != 0)
			variance = pow(-1, (rand() % 2) - 1) * (rand() % powers[power_index].angle_variance) * pi / 180.0; //random between 0 and angle_variance away
		float alpha = theta + offset_angle + variance;
		while (alpha >= 2 * pi) alpha -= 2 * pi;
		while (alpha < 0) alpha += 2 * pi;

		//calculate animation direction (the UNITS_PER_TILE just reduces round-off error)
		rot_target.x = src_stats->pos.x - UNITS_PER_TILE * cos(alpha);
		rot_target.y = src_stats->pos.y - UNITS_PER_TILE * sin(alpha);

		initHazard(power_index, src_stats, rot_target, haz[i]);

		//calculate the missile velocity
		int speed_var = 0;
		if (powers[power_index].speed_variance != 0)
			speed_var = pow(-1, (rand() % 2) - 1) * (rand() % powers[power_index].speed_variance + 1) - 1;
		haz[i]->speed.x = (haz[0]->base_speed + speed_var) * -cos(alpha);
		haz[i]->speed.y = (haz[0]->base_speed + speed_var) * -sin(alpha);
		hazards.push(haz[i]);
	}

	// pay costs
	if (powers[power_index].requires_mp>0) src_stats->mp-=powers[power_index].requires_mp;
	used_item = powers[power_index].requires_item;

	playSound(power_index, src_stats);
	return true;
}
Esempio n. 5
0
/**
 * The activated power creates a static effect (not a moving hazard)
 *
 * @param power_index The activated power ID
 * @param src_stats The StatBlock of the power activator
 * @param target The mouse cursor position in map coordinates
 * return boolean true if successful
 */
bool PowerManager::effect(int power_index, StatBlock *src_stats, Point target) {

	if (powers[power_index].use_hazard) {
		Hazard *haz = new Hazard();
		initHazard(power_index, src_stats, target, haz);
		
		// Hazard memory is now the responsibility of HazardManager
		hazards.push(haz);
	}

	buff(power_index, src_stats, target);
	
	// If there's a sound effect, play it here
	playSound(power_index, src_stats);

	// if all else succeeded, pay costs
	if (src_stats->hero && powers[power_index].requires_mp > 0) src_stats->mp -= powers[power_index].requires_mp;
	if (src_stats->hero && powers[power_index].requires_item != -1) used_item = powers[power_index].requires_item;
	
	return true;
}
Esempio n. 6
0
/**
 * Apply basic power info to a new hazard.
 *
 * This can be called several times to combine powers.
 * Typically done when a base power can be modified by equipment
 * (e.g. ammo type affects the traits of powers that shoot)
 *
 * @param power_index The activated power ID
 * @param src_stats The StatBlock of the power activator
 * @param target Aim position in map coordinates
 * @param haz A newly-initialized hazard
 */
void PowerManager::initHazard(int power_index, StatBlock *src_stats, Point target, Hazard *haz) {

	//the hazard holds the statblock of its source
	haz->src_stats = src_stats;

	// Hazard attributes based on power source
	haz->crit_chance = src_stats->crit;
	haz->accuracy = src_stats->accuracy;
	
	// Hazard damage depends on equipped weapons and the power's optional damage_multiplier
	if (powers[power_index].base_damage == BASE_DAMAGE_MELEE) {
		haz->dmg_min = src_stats->dmg_melee_min;
		haz->dmg_max = src_stats->dmg_melee_max;
	}
	else if (powers[power_index].base_damage == BASE_DAMAGE_RANGED) {
		haz->dmg_min = src_stats->dmg_ranged_min;
		haz->dmg_max = src_stats->dmg_ranged_max;
	}
	else if (powers[power_index].base_damage == BASE_DAMAGE_MENT) {
		haz->dmg_min = src_stats->dmg_ment_min;
		haz->dmg_max = src_stats->dmg_ment_max;
	}
	//apply the multiplier
	haz->dmg_min = ceil(haz->dmg_min * powers[power_index].damage_multiplier / 100.0);
	haz->dmg_max = ceil(haz->dmg_max * powers[power_index].damage_multiplier / 100.0);
	
	// Only apply stats from powers that are not defaults
	// If we do this, we can init with multiple power layers
	// (e.g. base spell plus weapon type)
	
	if (powers[power_index].gfx_index != -1) {
		haz->sprites = gfx[powers[power_index].gfx_index];
	}
	if (powers[power_index].rendered) {
		haz->rendered = powers[power_index].rendered;
	}
	if (powers[power_index].lifespan != 0) {
		haz->lifespan = powers[power_index].lifespan;
	}
	if (powers[power_index].frame_loop != 1) {
		haz->frame_loop = powers[power_index].frame_loop;
	}
	if (powers[power_index].frame_duration != 1) {
		haz->frame_duration = powers[power_index].frame_duration;
	}
	if (powers[power_index].frame_size.x != 0) {
		haz->frame_size.x = powers[power_index].frame_size.x;
	}
	if (powers[power_index].frame_size.y != 0) {
		haz->frame_size.y = powers[power_index].frame_size.y;
	}
	if (powers[power_index].frame_offset.x != 0) {
		haz->frame_offset.x = powers[power_index].frame_offset.x;
	}
	if (powers[power_index].frame_offset.y != 0) {
		haz->frame_offset.y = powers[power_index].frame_offset.y;
	}
	if (powers[power_index].directional) {
		haz->direction = calcDirection(src_stats->pos.x, src_stats->pos.y, target.x, target.y);
	}
	else if (powers[power_index].visual_random != 0) {
		haz->visual_option = rand() % powers[power_index].visual_random;
	}
	else if (powers[power_index].visual_option != 0) {
		haz->visual_option = powers[power_index].visual_option;
	}
	haz->floor = powers[power_index].floor;
	if (powers[power_index].speed > 0) {
		haz->base_speed = powers[power_index].speed;
	}
	if (powers[power_index].complete_animation) {
		haz->complete_animation = true;
	}
	
	// combat traits
	if (powers[power_index].no_attack) {
		haz->active = false;
	}
	if (powers[power_index].multitarget) {
		haz->multitarget = true;
	}
	if (powers[power_index].active_frame != -1) {
		haz->active_frame = powers[power_index].active_frame;
	}
	if (powers[power_index].radius != 0) {
		haz->radius = powers[power_index].radius;
	}
	if (powers[power_index].trait_armor_penetration) {
		haz->trait_armor_penetration = true;
	}
	haz->trait_crits_impaired = powers[power_index].trait_crits_impaired;
	if (powers[power_index].trait_elemental) {
		haz->trait_elemental = powers[power_index].trait_elemental;
	}
	
	// status effect durations
	// durations stack when combining powers (e.g. base power and weapon/ammo type)
	haz->bleed_duration += powers[power_index].bleed_duration;
	haz->stun_duration += powers[power_index].stun_duration;
	haz->slow_duration += powers[power_index].slow_duration;
	haz->immobilize_duration += powers[power_index].immobilize_duration;
	// steal effects
	haz->hp_steal += powers[power_index].hp_steal;
	haz->mp_steal += powers[power_index].mp_steal;
	
	// hazard starting position
	if (powers[power_index].starting_pos == STARTING_POS_SOURCE) {
		haz->pos.x = (float)src_stats->pos.x;
		haz->pos.y = (float)src_stats->pos.y;
	}
	else if (powers[power_index].starting_pos == STARTING_POS_TARGET) {
		haz->pos.x = (float)target.x;
		haz->pos.y = (float)target.y;	
	}
	else if (powers[power_index].starting_pos == STARTING_POS_MELEE) {
		haz->pos = calcVector(src_stats->pos, src_stats->direction, src_stats->melee_range);
	}
	
	// pre/post power effects
	if (powers[power_index].post_power != -1) {
		haz->post_power = powers[power_index].post_power;
	}
	if (powers[power_index].wall_power != -1) {
		haz->wall_power = powers[power_index].wall_power;
	}
	
	// if equipment has special powers, apply it here (if it hasn't already been applied)
	if (!haz->equipment_modified && powers[power_index].allow_power_mod) {
		if (powers[power_index].base_damage == BASE_DAMAGE_MELEE && src_stats->melee_weapon_power != -1) {
			haz->equipment_modified = true;
			initHazard(src_stats->melee_weapon_power, src_stats, target, haz);
		}
		else if (powers[power_index].base_damage == BASE_DAMAGE_MENT && src_stats->mental_weapon_power != -1) {
			haz->equipment_modified = true;
			initHazard(src_stats->mental_weapon_power, src_stats, target, haz);
		}
		else if (powers[power_index].base_damage == BASE_DAMAGE_RANGED && src_stats->ranged_weapon_power != -1) {
			haz->equipment_modified = true;
			initHazard(src_stats->ranged_weapon_power, src_stats, target, haz);
		}		
	}
}