void StatBlock::removeFromSummons() { if(summoner != NULL && !summoner->summons.empty()) { std::vector<StatBlock*>::iterator parent_ref = std::find(summoner->summons.begin(), summoner->summons.end(), this); if(parent_ref != summoner->summons.end()) summoner->summons.erase(parent_ref); summoner = NULL; } removeSummons(); }
/** * Process per-frame actions */ void StatBlock::logic() { alive = !(hp <= 0 && !effects.triggered_death && !effects.revive); // handle party buffs if (enemym && powers) { while (!party_buffs.empty()) { int power_index = party_buffs.front(); party_buffs.pop(); Power *buff_power = &powers->powers[power_index]; for (size_t i=0; i < enemym->enemies.size(); ++i) { if(enemym->enemies[i]->stats.hp > 0 && ((enemym->enemies[i]->stats.hero_ally && hero) || (enemym->enemies[i]->stats.enemy_ally && enemym->enemies[i]->stats.summoner == this)) && (buff_power->buff_party_power_id == 0 || buff_power->buff_party_power_id == enemym->enemies[i]->stats.summoned_power_index) ) { powers->effect(&enemym->enemies[i]->stats, this, power_index, (hero ? Power::SOURCE_TYPE_HERO : Power::SOURCE_TYPE_ENEMY)); } } } } // handle effect timers effects.logic(); // apply bonuses from items/effects to base stats applyEffects(); if (hero && effects.refresh_stats) { refresh_stats = true; effects.refresh_stats = false; } // preserve ratio on maxmp and maxhp changes float ratio; if (prev_maxhp != get(Stats::HP_MAX)) { ratio = static_cast<float>(prev_hp) / static_cast<float>(prev_maxhp); hp = static_cast<int>(ratio * static_cast<float>(get(Stats::HP_MAX))); } if (prev_maxmp != get(Stats::MP_MAX)) { ratio = static_cast<float>(prev_mp) / static_cast<float>(prev_maxmp); mp = static_cast<int>(ratio * static_cast<float>(get(Stats::MP_MAX))); } // handle cooldowns if (cooldown_ticks > 0) cooldown_ticks--; // global cooldown for (size_t i=0; i<powers_ai.size(); ++i) { // NPC/enemy powerslot cooldown if (powers_ai[i].ticks > 0) powers_ai[i].ticks--; } // HP regen if (get(Stats::HP_REGEN) > 0 && hp < get(Stats::HP_MAX) && hp > 0) { hp_ticker++; if (hp_ticker >= (60 * settings->max_frames_per_sec) / get(Stats::HP_REGEN)) { hp++; hp_ticker = 0; } } // MP regen if (get(Stats::MP_REGEN) > 0 && mp < get(Stats::MP_MAX) && hp > 0) { mp_ticker++; if (mp_ticker >= (60 * settings->max_frames_per_sec) / get(Stats::MP_REGEN)) { mp++; mp_ticker = 0; } } // handle buff/debuff durations if (transform_duration > 0) transform_duration--; // apply bleed if (effects.damage > 0 && hp > 0) { takeDamage(effects.damage); comb->addInt(effects.damage, pos, CombatText::MSG_TAKEDMG); } if (effects.damage_percent > 0 && hp > 0) { int damage = (get(Stats::HP_MAX)*effects.damage_percent)/100; takeDamage(damage); comb->addInt(damage, pos, CombatText::MSG_TAKEDMG); } if(effects.death_sentence) hp = 0; if(cooldown_hit_ticks > 0) cooldown_hit_ticks--; if (effects.stun) { // stun stops charge attacks state_ticks = 0; charge_speed = 0; } else if (state_ticks > 0) { state_ticks--; } // apply healing over time if (effects.hpot > 0) { comb->addString(msg->get("+%d HP",effects.hpot), pos, CombatText::MSG_BUFF); hp += effects.hpot; if (hp > get(Stats::HP_MAX)) hp = get(Stats::HP_MAX); } if (effects.hpot_percent > 0) { int hpot = (get(Stats::HP_MAX)*effects.hpot_percent)/100; comb->addString(msg->get("+%d HP",hpot), pos, CombatText::MSG_BUFF); hp += hpot; if (hp > get(Stats::HP_MAX)) hp = get(Stats::HP_MAX); } if (effects.mpot > 0) { comb->addString(msg->get("+%d MP",effects.mpot), pos, CombatText::MSG_BUFF); mp += effects.mpot; if (mp > get(Stats::MP_MAX)) mp = get(Stats::MP_MAX); } if (effects.mpot_percent > 0) { int mpot = (get(Stats::MP_MAX)*effects.mpot_percent)/100; comb->addString(msg->get("+%d MP",mpot), pos, CombatText::MSG_BUFF); mp += mpot; if (mp > get(Stats::MP_MAX)) mp = get(Stats::MP_MAX); } // set movement type // some creatures may shift between movement types if (intangible) movement_type = MapCollision::MOVE_INTANGIBLE; else if (flying) movement_type = MapCollision::MOVE_FLYING; else movement_type = MapCollision::MOVE_NORMAL; if (hp == 0) removeSummons(); if (effects.knockback_speed != 0) { float theta = Utils::calcTheta(knockback_srcpos.x, knockback_srcpos.y, knockback_destpos.x, knockback_destpos.y); knockback_speed.x = effects.knockback_speed * cosf(theta); knockback_speed.y = effects.knockback_speed * sinf(theta); mapr->collider.unblock(pos.x, pos.y); mapr->collider.move(pos.x, pos.y, knockback_speed.x, knockback_speed.y, movement_type, mapr->collider.getCollideType(hero)); mapr->collider.block(pos.x, pos.y, hero_ally); } else if (charge_speed != 0.0f) { float tmp_speed = charge_speed * speedMultiplyer[direction]; float dx = tmp_speed * static_cast<float>(directionDeltaX[direction]); float dy = tmp_speed * static_cast<float>(directionDeltaY[direction]); mapr->collider.unblock(pos.x, pos.y); mapr->collider.move(pos.x, pos.y, dx, dy, movement_type, mapr->collider.getCollideType(hero)); mapr->collider.block(pos.x, pos.y, hero_ally); } // enemies heal rapidly while not in combat if (!in_combat && !hero_ally && !hero) { if (alive && pc->stats.alive) { hp++; if (hp > get(Stats::HP_MAX)) hp = get(Stats::HP_MAX); } } if (waypoint_pause_ticks > 0) waypoint_pause_ticks--; // check for revive if (hp <= 0 && effects.revive) { hp = get(Stats::HP_MAX); alive = true; corpse = false; if (hero) cur_state = AVATAR_STANCE; else cur_state = ENEMY_STANCE; } // check for bleeding to death if (hp <= 0 && !hero && cur_state != ENEMY_DEAD && cur_state != ENEMY_CRITDEAD) { for (size_t i = 0; i < effects.effect_list.size(); ++i) { if (effects.effect_list[i].type == Effect::DAMAGE || effects.effect_list[i].type == Effect::DAMAGE_PERCENT) { bleed_source_type = effects.effect_list[i].source_type; break; } } effects.triggered_death = true; cur_state = ENEMY_DEAD; } else if (hp <= 0 && hero && cur_state != AVATAR_DEAD) { effects.triggered_death = true; cur_state = AVATAR_DEAD; } }
/** * Process per-frame actions */ void StatBlock::logic() { if (hp <= 0 && !effects.triggered_death && !effects.revive) alive = false; else alive = true; // handle effect timers effects.logic(); // apply bonuses from items/effects to base stats applyEffects(); // preserve ratio on maxmp and maxhp changes float ratio; if (prev_maxhp != get(STAT_HP_MAX)) { ratio = (float)pres_hp / (float)prev_maxhp; hp = (int)(ratio * get(STAT_HP_MAX)); } if (prev_maxmp != get(STAT_MP_MAX)) { ratio = (float)pres_mp / (float)prev_maxmp; mp = (int)(ratio * get(STAT_MP_MAX)); } // handle cooldowns if (cooldown_ticks > 0) cooldown_ticks--; // global cooldown for (int i=0; i<POWERSLOT_COUNT; i++) { // NPC/enemy powerslot cooldown if (power_ticks[i] > 0) power_ticks[i]--; } // HP regen if (get(STAT_HP_REGEN) > 0 && hp < get(STAT_HP_MAX) && hp > 0) { hp_ticker++; if (hp_ticker >= (60 * MAX_FRAMES_PER_SEC)/get(STAT_HP_REGEN)) { hp++; hp_ticker = 0; } } // MP regen if (get(STAT_MP_REGEN) > 0 && mp < get(STAT_MP_MAX) && hp > 0) { mp_ticker++; if (mp_ticker >= (60 * MAX_FRAMES_PER_SEC)/get(STAT_MP_REGEN)) { mp++; mp_ticker = 0; } } // handle buff/debuff durations if (transform_duration > 0) transform_duration--; // apply bleed if (effects.damage > 0 && hp > 0) { takeDamage(effects.damage); comb->addMessage(effects.damage, pos, COMBAT_MESSAGE_TAKEDMG); } if (effects.damage_percent > 0 && hp > 0) { int damage = (get(STAT_HP_MAX)*effects.damage_percent)/100; takeDamage(damage); comb->addMessage(damage, pos, COMBAT_MESSAGE_TAKEDMG); } if(effects.death_sentence) hp = 0; if(cooldown_hit_ticks > 0) cooldown_hit_ticks--; // apply healing over time if (effects.hpot > 0) { comb->addMessage(msg->get("+%d HP",effects.hpot), pos, COMBAT_MESSAGE_BUFF); hp += effects.hpot; if (hp > get(STAT_HP_MAX)) hp = get(STAT_HP_MAX); } if (effects.hpot_percent > 0) { int hpot = (get(STAT_HP_MAX)*effects.hpot_percent)/100; comb->addMessage(msg->get("+%d HP",hpot), pos, COMBAT_MESSAGE_BUFF); hp += hpot; if (hp > get(STAT_HP_MAX)) hp = get(STAT_HP_MAX); } if (effects.mpot > 0) { comb->addMessage(msg->get("+%d MP",effects.mpot), pos, COMBAT_MESSAGE_BUFF); mp += effects.mpot; if (mp > get(STAT_MP_MAX)) mp = get(STAT_MP_MAX); } if (effects.mpot_percent > 0) { int mpot = (get(STAT_MP_MAX)*effects.mpot_percent)/100; comb->addMessage(msg->get("+%d MP",mpot), pos, COMBAT_MESSAGE_BUFF); mp += mpot; if (mp > get(STAT_MP_MAX)) mp = get(STAT_MP_MAX); } // set movement type // some creatures may shift between movement types if (intangible) movement_type = MOVEMENT_INTANGIBLE; else if (flying) movement_type = MOVEMENT_FLYING; else movement_type = MOVEMENT_NORMAL; if (hp == 0) removeSummons(); }
/** * Process per-frame actions */ void StatBlock::logic() { if (hp <= 0 && !effects.triggered_death && !effects.revive) alive = false; else alive = true; // handle party buffs if (enemym && powers) { while (!party_buffs.empty()) { int power_index = party_buffs.front(); party_buffs.pop(); Power *buff_power = &powers->powers[power_index]; for (size_t i=0; i < enemym->enemies.size(); ++i) { if(enemym->enemies[i]->stats.hp > 0 && ((enemym->enemies[i]->stats.hero_ally && hero) || (enemym->enemies[i]->stats.enemy_ally && enemym->enemies[i]->stats.summoner == this)) && (buff_power->buff_party_power_id == 0 || buff_power->buff_party_power_id == enemym->enemies[i]->stats.summoned_power_index) ) { powers->effect(&enemym->enemies[i]->stats, this, power_index, (hero ? SOURCE_TYPE_HERO : SOURCE_TYPE_ENEMY)); } } } } // handle effect timers effects.logic(); // apply bonuses from items/effects to base stats applyEffects(); if (hero && effects.refresh_stats) { refresh_stats = true; effects.refresh_stats = false; } // preserve ratio on maxmp and maxhp changes float ratio; if (prev_maxhp != get(STAT_HP_MAX)) { ratio = static_cast<float>(pres_hp) / static_cast<float>(prev_maxhp); hp = static_cast<int>(ratio * static_cast<float>(get(STAT_HP_MAX))); } if (prev_maxmp != get(STAT_MP_MAX)) { ratio = static_cast<float>(pres_mp) / static_cast<float>(prev_maxmp); mp = static_cast<int>(ratio * static_cast<float>(get(STAT_MP_MAX))); } // handle cooldowns if (cooldown_ticks > 0) cooldown_ticks--; // global cooldown for (size_t i=0; i<powers_ai.size(); ++i) { // NPC/enemy powerslot cooldown if (powers_ai[i].ticks > 0) powers_ai[i].ticks--; } // HP regen if (get(STAT_HP_REGEN) > 0 && hp < get(STAT_HP_MAX) && hp > 0) { hp_ticker++; if (hp_ticker >= (60 * MAX_FRAMES_PER_SEC)/get(STAT_HP_REGEN)) { hp++; hp_ticker = 0; } } // MP regen if (get(STAT_MP_REGEN) > 0 && mp < get(STAT_MP_MAX) && hp > 0) { mp_ticker++; if (mp_ticker >= (60 * MAX_FRAMES_PER_SEC)/get(STAT_MP_REGEN)) { mp++; mp_ticker = 0; } } // handle buff/debuff durations if (transform_duration > 0) transform_duration--; // apply bleed if (effects.damage > 0 && hp > 0) { takeDamage(effects.damage); comb->addInt(effects.damage, pos, COMBAT_MESSAGE_TAKEDMG); } if (effects.damage_percent > 0 && hp > 0) { int damage = (get(STAT_HP_MAX)*effects.damage_percent)/100; takeDamage(damage); comb->addInt(damage, pos, COMBAT_MESSAGE_TAKEDMG); } if(effects.death_sentence) hp = 0; if(cooldown_hit_ticks > 0) cooldown_hit_ticks--; if (effects.stun) { // stun stops charge attacks state_ticks = 0; charge_speed = 0; } else if (state_ticks > 0) { state_ticks--; } // apply healing over time if (effects.hpot > 0) { comb->addString(msg->get("+%d HP",effects.hpot), pos, COMBAT_MESSAGE_BUFF); hp += effects.hpot; if (hp > get(STAT_HP_MAX)) hp = get(STAT_HP_MAX); } if (effects.hpot_percent > 0) { int hpot = (get(STAT_HP_MAX)*effects.hpot_percent)/100; comb->addString(msg->get("+%d HP",hpot), pos, COMBAT_MESSAGE_BUFF); hp += hpot; if (hp > get(STAT_HP_MAX)) hp = get(STAT_HP_MAX); } if (effects.mpot > 0) { comb->addString(msg->get("+%d MP",effects.mpot), pos, COMBAT_MESSAGE_BUFF); mp += effects.mpot; if (mp > get(STAT_MP_MAX)) mp = get(STAT_MP_MAX); } if (effects.mpot_percent > 0) { int mpot = (get(STAT_MP_MAX)*effects.mpot_percent)/100; comb->addString(msg->get("+%d MP",mpot), pos, COMBAT_MESSAGE_BUFF); mp += mpot; if (mp > get(STAT_MP_MAX)) mp = get(STAT_MP_MAX); } // set movement type // some creatures may shift between movement types if (intangible) movement_type = MOVEMENT_INTANGIBLE; else if (flying) movement_type = MOVEMENT_FLYING; else movement_type = MOVEMENT_NORMAL; if (hp == 0) removeSummons(); if (effects.knockback_speed != 0) { float theta = calcTheta(knockback_srcpos.x, knockback_srcpos.y, knockback_destpos.x, knockback_destpos.y); knockback_speed.x = effects.knockback_speed * cosf(theta); knockback_speed.y = effects.knockback_speed * sinf(theta); mapr->collider.unblock(pos.x, pos.y); mapr->collider.move(pos.x, pos.y, knockback_speed.x, knockback_speed.y, movement_type, hero); mapr->collider.block(pos.x, pos.y, hero_ally); } else if (charge_speed != 0.0f) { float tmp_speed = charge_speed * speedMultiplyer[direction]; float dx = tmp_speed * static_cast<float>(directionDeltaX[direction]); float dy = tmp_speed * static_cast<float>(directionDeltaY[direction]); mapr->collider.unblock(pos.x, pos.y); mapr->collider.move(pos.x, pos.y, dx, dy, movement_type, hero); mapr->collider.block(pos.x, pos.y, hero_ally); } }
/** * Process per-frame actions */ void StatBlock::logic() { if (hp <= 0 && !effects.triggered_death && !effects.revive) alive = false; else alive = true; // handle effect timers effects.logic(); // apply bonuses from items/effects to base stats applyEffects(); // preserve ratio on maxmp and maxhp changes float ratio; if (prev_maxhp != get(STAT_HP_MAX)) { ratio = static_cast<float>(pres_hp) / static_cast<float>(prev_maxhp); hp = static_cast<int>(ratio * static_cast<float>(get(STAT_HP_MAX))); } if (prev_maxmp != get(STAT_MP_MAX)) { ratio = static_cast<float>(pres_mp) / static_cast<float>(prev_maxmp); mp = static_cast<int>(ratio * static_cast<float>(get(STAT_MP_MAX))); } // handle cooldowns if (cooldown_ticks > 0) cooldown_ticks--; // global cooldown for (size_t i=0; i<powers_ai.size(); ++i) { // NPC/enemy powerslot cooldown if (powers_ai[i].ticks > 0) powers_ai[i].ticks--; } // HP regen if (get(STAT_HP_REGEN) > 0 && hp < get(STAT_HP_MAX) && hp > 0) { hp_ticker++; if (hp_ticker >= (60 * MAX_FRAMES_PER_SEC)/get(STAT_HP_REGEN)) { hp++; hp_ticker = 0; } } // MP regen if (get(STAT_MP_REGEN) > 0 && mp < get(STAT_MP_MAX) && hp > 0) { mp_ticker++; if (mp_ticker >= (60 * MAX_FRAMES_PER_SEC)/get(STAT_MP_REGEN)) { mp++; mp_ticker = 0; } } // handle buff/debuff durations if (transform_duration > 0) transform_duration--; // apply bleed if (effects.damage > 0 && hp > 0) { takeDamage(effects.damage); comb->addMessage(effects.damage, pos, COMBAT_MESSAGE_TAKEDMG); } if (effects.damage_percent > 0 && hp > 0) { int damage = (get(STAT_HP_MAX)*effects.damage_percent)/100; takeDamage(damage); comb->addMessage(damage, pos, COMBAT_MESSAGE_TAKEDMG); } if(effects.death_sentence) hp = 0; if(cooldown_hit_ticks > 0) cooldown_hit_ticks--; // apply healing over time if (effects.hpot > 0) { comb->addMessage(msg->get("+%d HP",effects.hpot), pos, COMBAT_MESSAGE_BUFF); hp += effects.hpot; if (hp > get(STAT_HP_MAX)) hp = get(STAT_HP_MAX); } if (effects.hpot_percent > 0) { int hpot = (get(STAT_HP_MAX)*effects.hpot_percent)/100; comb->addMessage(msg->get("+%d HP",hpot), pos, COMBAT_MESSAGE_BUFF); hp += hpot; if (hp > get(STAT_HP_MAX)) hp = get(STAT_HP_MAX); } if (effects.mpot > 0) { comb->addMessage(msg->get("+%d MP",effects.mpot), pos, COMBAT_MESSAGE_BUFF); mp += effects.mpot; if (mp > get(STAT_MP_MAX)) mp = get(STAT_MP_MAX); } if (effects.mpot_percent > 0) { int mpot = (get(STAT_MP_MAX)*effects.mpot_percent)/100; comb->addMessage(msg->get("+%d MP",mpot), pos, COMBAT_MESSAGE_BUFF); mp += mpot; if (mp > get(STAT_MP_MAX)) mp = get(STAT_MP_MAX); } // set movement type // some creatures may shift between movement types if (intangible) movement_type = MOVEMENT_INTANGIBLE; else if (flying) movement_type = MOVEMENT_FLYING; else movement_type = MOVEMENT_NORMAL; if (hp == 0) removeSummons(); if (effects.knockback_speed != 0) { float theta = calcTheta(knockback_srcpos.x, knockback_srcpos.y, knockback_destpos.x, knockback_destpos.y); knockback_speed.x = effects.knockback_speed * static_cast<float>(cos(theta)); knockback_speed.y = effects.knockback_speed * static_cast<float>(sin(theta)); } if (effects.knockback_speed != 0) { mapr->collider.unblock(pos.x, pos.y); mapr->collider.move(pos.x, pos.y, knockback_speed.x, knockback_speed.y, movement_type, hero); mapr->collider.block(pos.x, pos.y, hero_ally); } }