gdle/Source/Healer.cpp
2019-07-07 20:56:15 +00:00

322 lines
9.3 KiB
C++

#include <StdAfx.h>
#include "WeenieObject.h"
#include "Healer.h"
#include "Player.h"
CHealerWeenie::CHealerWeenie()
{
SetName("Healer");
m_Qualities.m_WeenieType = Healer_WeenieType;
}
CHealerWeenie::~CHealerWeenie()
{
}
void CHealerWeenie::ApplyQualityOverrides()
{
}
int CHealerWeenie::UseWith(CPlayerWeenie *player, CWeenieObject *with)
{
if (!with->AsPlayer())
{
player->NotifyWeenieError(WERROR_HEAL_PLAYERS_ONLY);
player->NotifyUseDone(0);
return WERROR_NONE;
}
if (player->IsInPortalSpace())
{
player->NotifyUseDone(0);
return WERROR_ACTIONS_LOCKED;
}
uint32_t healing_skill = 0;
if (!player->InqSkill(HEALING_SKILL, healing_skill, TRUE) || !healing_skill)
{
player->NotifyWeenieError(WERROR_HEAL_NOT_TRAINED);
player->NotifyUseDone(0);
return WERROR_NONE;
}
uint32_t boostEnum = m_Qualities.GetInt(BOOSTER_ENUM_INT, 0);
switch (boostEnum)
{
case HEALTH_ATTRIBUTE_2ND:
{
if (with->GetHealth() == with->GetMaxHealth())
{
player->NotifyWeenieErrorWithString(WERROR_HEAL_FULL_HEALTH, with->GetName().c_str());
player->NotifyUseDone(0);
return WERROR_NONE;
}
else
break;
}
case STAMINA_ATTRIBUTE_2ND:
{
if (with->GetStamina() == with->GetMaxStamina())
{
player->NotifyWeenieError(WERROR_NONE);
player->NotifyUseDone(0);
return WERROR_NONE;
}
else
break;
}
case MANA_ATTRIBUTE_2ND:
{
if (with->GetMana() == with->GetMaxMana())
{
player->NotifyWeenieError(WERROR_NONE);
player->NotifyUseDone(0);
return WERROR_NONE;
}
else
break;
}
}
CHealerUseEvent *useEvent = new CHealerUseEvent;
useEvent->_target_id = with->GetID();
useEvent->_tool_id = GetID();
useEvent->_max_use_distance = 1.0;
useEvent->_initial_use_position = player->m_Position;
player->ExecuteUseEvent(useEvent);
return WERROR_NONE;
}
void CHealerUseEvent::OnReadyToUse()
{
if (_weenie->GetStamina() == 0)
{
//don't perform healing animation if there's zero stamina
_weenie->NotifyWeenieError(WERROR_STAMINA_TOO_LOW);
Cancel();
return;
}
if (_target_id == _weenie->GetID())
{
_weenie->DoForcedStopCompletely();
ExecuteUseAnimation(Motion_SkillHealSelf);
}
else
{
_weenie->DoForcedStopCompletely();
ExecuteUseAnimation(Motion_Woah);
}
}
void CHealerUseEvent::OnUseAnimSuccess(uint32_t motion)
{
CWeenieObject *target = GetTarget();
CWeenieObject *tool = GetTool();
if (tool && target && !target->IsDead() && !target->IsInPortalSpace())
{
if (_target_id == _weenie->GetID() && _weenie->m_Position.distance(_initial_use_position) > 5.0) //Distance check between initial use and now but only if heal was executed on self.
return Cancel(WERROR_MOVED_TOO_FAR);
int amountHealed = 0;
int usesLeft = tool->InqIntQuality(STRUCTURE_INT, -1);
if (usesLeft != 0)
{
if (usesLeft > 0)
usesLeft--;
const char *prefix = "";
const char *vitalName = "";
uint32_t boost_stat = tool->InqIntQuality(BOOSTER_ENUM_INT, 0);
uint32_t boost_value = tool->InqIntQuality(BOOST_VALUE_INT, 0);
bool success = false;
switch (boost_stat)
{
case HEALTH_ATTRIBUTE_2ND:
case STAMINA_ATTRIBUTE_2ND:
case MANA_ATTRIBUTE_2ND:
{
STypeAttribute2nd maxStatType = (STypeAttribute2nd)(boost_stat - 1);
STypeAttribute2nd statType = (STypeAttribute2nd)boost_stat;
uint32_t statValue = 0, maxStatValue = 0;
target->m_Qualities.InqAttribute2nd(statType, statValue, FALSE);
target->m_Qualities.InqAttribute2nd(maxStatType, maxStatValue, FALSE);
int missingVital = max(0, (int)maxStatValue - (int)statValue);
double combat_mod = _weenie->IsInPeaceMode() ? 1.0 : 1.1;
int difficulty = max(0, (int)((missingVital * 2) * combat_mod));
Skill skill;
uint32_t healing_skill = 0;
_weenie->InqSkill(HEALING_SKILL, healing_skill, FALSE);
_weenie->m_Qualities.InqSkill(HEALING_SKILL, skill);
uint32_t base_skill = healing_skill;
double sac_mod = skill._sac == SPECIALIZED_SKILL_ADVANCEMENT_CLASS ? 1.5 : 1.1;
healing_skill = (healing_skill + boost_value) * sac_mod;
success = Random::RollDice(0.0, 1.0) <= GetSkillChance(healing_skill, difficulty);
if (success)
{
double heal_min = 0;
double heal_max = 0;
if (skill._sac == SPECIALIZED_SKILL_ADVANCEMENT_CLASS)
{
heal_min = 0.09;
heal_max = 0.28;
}
else
{
heal_min = 0.07;
heal_max = 0.235;
}
double healedVariance = Random::GenFloat(heal_min, heal_max);
amountHealed = (int)(base_skill * healedVariance * tool->InqFloatQuality(HEALKIT_MOD_FLOAT, 1.0));
if (Random::RollDice(0.0, 1.0) <= 0.15)
{
prefix = "expertly ";
amountHealed *= difficulty / 2;
}
if (amountHealed > missingVital)
amountHealed = missingVital;
int staminaNecessary = amountHealed / 5; //1 point of stamina used for every 5 health healed.
if (_weenie->GetStamina() < staminaNecessary)
{
staminaNecessary = _weenie->GetStamina();
amountHealed = staminaNecessary * 5;
if (CPlayerWeenie *pPlayer = _weenie->AsPlayer())
{
pPlayer->SendText("You're exhausted!", LTT_ERROR);
}
}
_weenie->AdjustStamina(-staminaNecessary);
uint32_t newStatValue = min(statValue + amountHealed, maxStatValue);
int statChange = newStatValue - statValue;
if (statChange)
{
if (target->AsPlayer() && statType == HEALTH_ATTRIBUTE_2ND)
{
target->AdjustHealth(statChange);
target->NotifyAttribute2ndStatUpdated(statType);
}
else
{
target->m_Qualities.SetAttribute2nd(statType, newStatValue);
target->NotifyAttribute2ndStatUpdated(statType);
}
}
}
switch (boost_stat)
{
case HEALTH_ATTRIBUTE_2ND: vitalName = "Health"; break;
case STAMINA_ATTRIBUTE_2ND: vitalName = "Stamina"; break;
case MANA_ATTRIBUTE_2ND: vitalName = "Mana"; break;
}
break;
}
}
amountHealed = max(0, amountHealed);
// heal up
if (success)
{
if (_target_id == _weenie->GetID())
{
if (vitalName == "Health")
{
if (usesLeft >= 0)
_weenie->SendText(csprintf("You %sheal yourself for %d %s points. Your %s has %u uses left.", prefix, amountHealed, vitalName, tool->GetName().c_str(), usesLeft), LTT_DEFAULT);
else
_weenie->SendText(csprintf("You %sheal yourself for %d %s points with %s.", prefix, amountHealed, vitalName, tool->GetName().c_str()), LTT_DEFAULT);
}
else
{
if (usesLeft >= 0)
_weenie->SendText(csprintf("You %srecover %d %s points. Your %s has %u uses left.", prefix, amountHealed, vitalName, tool->GetName().c_str(), usesLeft), LTT_DEFAULT);
else
_weenie->SendText(csprintf("You %srecover %d %s points with %s.", prefix, amountHealed, vitalName, tool->GetName().c_str()), LTT_DEFAULT);
}
}
else
{
if (vitalName == "Health")
{
if (usesLeft >= 0)
_weenie->SendText(csprintf("You %sheal %s for %d %s points. Your %s has %u uses left.", prefix, target->GetName().c_str(), amountHealed, vitalName, tool->GetName().c_str(), usesLeft), LTT_DEFAULT);
else
_weenie->SendText(csprintf("You %sheal %s for %d %s points with %s.", prefix, target->GetName().c_str(), amountHealed, vitalName, tool->GetName().c_str()), LTT_DEFAULT);
target->SendText(csprintf("%s heals you for %d %s points.", _weenie->GetName().c_str(), amountHealed, vitalName), LTT_DEFAULT);
}
else
{
if (usesLeft >= 0)
_weenie->SendText(csprintf("You %srestore %s for %d %s points. Your %s has %u uses left.", prefix, target->GetName().c_str(), amountHealed, vitalName, tool->GetName().c_str(), usesLeft), LTT_DEFAULT);
else
_weenie->SendText(csprintf("You %srestore %s for %d %s points with %s.", prefix, target->GetName().c_str(), amountHealed, vitalName, tool->GetName().c_str()), LTT_DEFAULT);
target->SendText(csprintf("%s restores you for %d %s points.", _weenie->GetName().c_str(), amountHealed, vitalName), LTT_DEFAULT);
}
}
if (boost_stat == HEALTH_ATTRIBUTE_2ND)
{
if (_weenie->AsPlayer())
{
// update the target's health on the healing player asap
((CPlayerWeenie*)_weenie)->RefreshTargetHealth();
}
}
}
else
{
if (_target_id == _weenie->GetID())
{
if(vitalName == "Health")
_weenie->SendText(csprintf("You fail to heal yourself. Your %s has %d uses left.", tool->GetName().c_str(), usesLeft), LTT_DEFAULT);
else
_weenie->SendText(csprintf("You fail to recover any vitals. Your %s has %d uses left.", tool->GetName().c_str(), usesLeft), LTT_DEFAULT);
}
else
{
if (vitalName == "Health")
{
_weenie->SendText(csprintf("You fail to heal %s. Your %s has %d uses left.", target->GetName().c_str(), tool->GetName().c_str(), usesLeft), LTT_DEFAULT);
target->SendText(csprintf("%s fails to heal you.", _weenie->GetName().c_str()), LTT_DEFAULT);
}
else
{
_weenie->SendText(csprintf("You fail to restore any vitals to %s. Your %s has %d uses left.", target->GetName().c_str(), tool->GetName().c_str(), usesLeft), LTT_DEFAULT);
target->SendText(csprintf("%s fails to restore any of your vitals.", _weenie->GetName().c_str()), LTT_DEFAULT);
}
}
}
tool->DecrementStackOrStructureNum(true);
}
}
Done();
}