bool Game::combatChangeHealth(const CombatParams& params, Creature* attacker, Creature* target, int32_t healthChange, bool force)
{
const Position& targetPos = target->getPosition();
if(healthChange > 0)
{
if(!force && target->getHealth() <= 0)
return false;
// START BONUS STORAGE HEALING
std::string value;
target->getPlayer()->getStorage(8888, value); // SET STORAGE HERE
int32_t storageBonus = atoi(value.c_str());
if (storageBonus >= 1)
healthChange = healthChange * (1 + (storageBonus * 0.1)); // 0.1 = 10%
// END BONUS STORAGE HEALING
bool deny = false;
CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE);
for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it)
{
if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_HEALTHGAIN, params.combatType, healthChange))
deny = true;
}
if(deny)
return false;
int32_t oldHealth = target->getHealth();
target->gainHealth(attacker, healthChange);
if(oldHealth != target->getHealth() && g_config.getBool(ConfigManager::SHOW_HEALTH_CHANGE) && !target->isGhost() &&
(g_config.getBool(ConfigManager::SHOW_HEALTH_CHANGE_MONSTER) || !target->getMonster()))
{
const SpectatorVec& list = getSpectators(targetPos);
if(params.combatType != COMBAT_HEALING)
addMagicEffect(list, targetPos, MAGIC_EFFECT_WRAPS_BLUE);
SpectatorVec textList;
for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
{
if(!(*it)->getPlayer())
continue;
if((*it) != attacker && (*it) != target && (*it)->getPosition().z == target->getPosition().z)
textList.push_back(*it);
}
healthChange = (target->getHealth() - oldHealth);
std::string plural = (healthChange != 1 ? "s." : ".");
std::stringstream ss;
char buffer[20];
sprintf(buffer, "+%d", healthChange);
addAnimatedText(list, targetPos, COLOR_MAYABLUE, buffer);
if(!textList.empty())
{
if(!attacker)
ss << ucfirst(target->getNameDescription()) << " is healed for " << healthChange << " hitpoint" << plural;
else if(attacker != target)
ss << ucfirst(attacker->getNameDescription()) << " heals " << target->getNameDescription() << " for " << healthChange << " hitpoint" << plural;
else
{
ss << ucfirst(attacker->getNameDescription()) << " heals ";
if(Player* attackerPlayer = attacker->getPlayer())
ss << (attackerPlayer->getSex(false) == PLAYERSEX_FEMALE ? "herself" : "himself") << " for " << healthChange << " hitpoint" << plural;
else
ss << "itself for " << healthChange << " hitpoint" << plural;
}
addStatsMessage(textList, MSG_HEALED_OTHERS, ss.str(), targetPos);
ss.str("");
}
Player* player = NULL;
if(attacker && (player = attacker->getPlayer()))
{
if(attacker != target)
ss << "You healed " << target->getNameDescription() << " for " << healthChange << " hitpoint" << plural;
else
ss << "You healed yourself for " << healthChange << " hitpoint" << plural;
player->sendStatsMessage(MSG_HEALED, ss.str(), targetPos);
ss.str("");
}
if((player = target->getPlayer()) && attacker != target)
{
if(attacker)
ss << ucfirst(attacker->getNameDescription()) << " heals you for " << healthChange << " hitpoint" << plural;
else
ss << "You are healed for " << healthChange << " hitpoint" << plural;
player->sendStatsMessage(MSG_HEALED, ss.str(), targetPos);
}
}
}
else
{
const SpectatorVec& list = getSpectators(targetPos);
if(target->getHealth() < 1 || Combat::canDoCombat(attacker, target, true) != RET_NOERROR)
{
addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF);
return true;
}
int32_t elementDamage = 0;
if(params.element.damage && params.element.type != COMBAT_NONE)
elementDamage = -params.element.damage;
int32_t damage = -healthChange;
if(damage > 0)
{
if(target->hasCondition(CONDITION_MANASHIELD) && params.combatType != COMBAT_UNDEFINEDDAMAGE)
{
int32_t manaDamage = std::min(target->getMana(), damage + elementDamage);
damage = std::max((int32_t)0, damage + elementDamage - manaDamage);
elementDamage = 0; // TODO: I don't know how it works ;(
if(manaDamage && combatChangeMana(attacker, target, -manaDamage, params.combatType, true))
addMagicEffect(list, targetPos, MAGIC_EFFECT_LOSE_ENERGY);
}
damage = std::min(target->getHealth(), damage);
if(damage > 0)
{
bool deny = false;
CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE);
for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it)
{
if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_HEALTHLOSS, params.combatType, damage))
deny = true;
}
if(deny)
return false;
target->drainHealth(attacker, params.combatType, damage);
if(elementDamage)
target->drainHealth(attacker, params.element.type, elementDamage);
Color_t textColor = COLOR_NONE;
MagicEffect_t magicEffect = MAGIC_EFFECT_NONE;
addCreatureHealth(list, target);
if(params.combatType == COMBAT_PHYSICALDAMAGE)
{
Item* splash = NULL;
switch(target->getRace())
{
case RACE_VENOM:
textColor = COLOR_LIGHTGREEN;
magicEffect = MAGIC_EFFECT_POISON;
splash = Item::CreateItem(ITEM_SMALLSPLASH, FLUID_GREEN);
break;
case RACE_BLOOD:
textColor = COLOR_RED;
magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
splash = Item::CreateItem(ITEM_SMALLSPLASH, FLUID_BLOOD);
break;
case RACE_UNDEAD:
textColor = COLOR_GREY;
magicEffect = MAGIC_EFFECT_HIT_AREA;
break;
case RACE_FIRE:
textColor = COLOR_ORANGE;
magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
break;
case RACE_ENERGY:
textColor = COLOR_PURPLE;
magicEffect = MAGIC_EFFECT_PURPLEENERGY;
break;
default:
break;
}
if(splash)
{
internalAddItem(NULL, target->getTile(), splash, INDEX_WHEREEVER, FLAG_NOLIMIT);
startDecay(splash);
}
}
else
getCombatDetails(params.combatType, magicEffect, textColor);
if(params.effects.hit != MAGIC_EFFECT_UNKNOWN)
magicEffect = params.effects.hit;
if(params.effects.color != COLOR_UNKNOWN)
textColor = params.effects.color;
if(textColor < COLOR_NONE && magicEffect < MAGIC_EFFECT_NONE)
{
addMagicEffect(list, targetPos, magicEffect);
SpectatorVec textList;
for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
{
if(!(*it)->getPlayer())
continue;
if((*it) != attacker && (*it) != target && (*it)->getPosition().z == target->getPosition().z)
textList.push_back(*it);
}
MessageDetails* details = new MessageDetails(damage, textColor);
if(elementDamage)
{
getCombatDetails(params.element.type, magicEffect, textColor);
details->sub = new MessageDetails(elementDamage, textColor);
addMagicEffect(list, targetPos, magicEffect);
}
std::stringstream ss;
int32_t totalDamage = damage + elementDamage;
std::string plural = (totalDamage != 1 ? "s" : "");
if(!textList.empty())
{
if(!attacker)
ss << ucfirst(target->getNameDescription()) << " loses " << totalDamage << " hitpoint" << plural << ".";
else if(attacker != target)
ss << ucfirst(target->getNameDescription()) << " loses " << totalDamage << " hitpoint" << plural << " due to an attack by " << attacker->getNameDescription() << ".";
else
ss << ucfirst(target->getNameDescription()) << " loses " << totalDamage << " hitpoint" << plural << " due to a self attack.";
addStatsMessage(textList, MSG_DAMAGE_OTHERS, ss.str(), targetPos, details);
ss.str("");
}
Player* player = NULL;
if(attacker && (player = attacker->getPlayer()))
{
if(attacker != target)
ss << ucfirst(target->getNameDescription()) << " loses " << totalDamage << " hitpoint" << plural << " due to your attack.";
else
ss << "You lose " << totalDamage << " hitpoint" << plural << " due to your attack.";
player->sendStatsMessage(MSG_DAMAGE_DEALT, ss.str(), targetPos, details);
ss.str("");
}
if((player = target->getPlayer()) && attacker != target)
{
if(attacker)
ss << "You lose " << totalDamage << " hitpoint" << plural << " due to an attack by " << attacker->getNameDescription() << ".";
else
ss << "You lose " << totalDamage << " hitpoint" << plural << ".";
player->sendStatsMessage(MSG_DAMAGE_RECEIVED, ss.str(), targetPos, details);
}
if(details->sub)
delete details->sub;
delete details;
}
}
}
}
return true;
}