Merge pull request #273 from KayenEQ/Development

Allow npc_types field 'special_abilities' to be set as null in database.
This commit is contained in:
Michael Cook (mackal) 2014-10-30 22:01:55 -04:00
commit 2d77adeeb8
9 changed files with 68 additions and 26 deletions

View File

@ -0,0 +1,4 @@
ALTER TABLE `merc_stats` MODIFY COLUMN `special_abilities` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL AFTER `attack_speed`;
ALTER TABLE `npc_types` MODIFY COLUMN `special_abilities` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL AFTER `npcspecialattks`;

View File

@ -1288,15 +1288,18 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
mlog(COMBAT__DAMAGE, "Damage calculated to %d (min %d, max %d, str %d, skill %d, DMG %d, lv %d)",
damage, min_hit, max_hit, GetSTR(), GetSkill(skillinuse), weapon_damage, mylevel);
int hit_chance_bonus = 0;
if(opts) {
damage *= opts->damage_percent;
damage += opts->damage_flat;
hate *= opts->hate_percent;
hate += opts->hate_flat;
hit_chance_bonus += opts->hate_flat;
}
//check to see if we hit..
if(!other->CheckHitChance(this, skillinuse, Hand)) {
if(!other->CheckHitChance(this, skillinuse, Hand, hit_chance_bonus)) {
mlog(COMBAT__ATTACKS, "Attack missed. Damage set to 0.");
damage = 0;
} else { //we hit, try to avoid it
@ -1890,14 +1893,18 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
other->AddToHateList(this, hate);
} else {
int hit_chance_bonus = 0;
if(opts) {
damage *= opts->damage_percent;
damage += opts->damage_flat;
hate *= opts->hate_percent;
hate += opts->hate_flat;
hit_chance_bonus += opts->hit_chance;
}
if(!other->CheckHitChance(this, skillinuse, Hand)) {
if(!other->CheckHitChance(this, skillinuse, Hand, hit_chance_bonus)) {
damage = 0; //miss
} else { //hit, check for damage avoidance
other->AvoidDamage(this, damage);

View File

@ -563,7 +563,7 @@ struct ExtraAttackOptions {
: damage_percent(1.0f), damage_flat(0),
armor_pen_percent(0.0f), armor_pen_flat(0),
crit_percent(1.0f), crit_flat(0.0f),
hate_percent(1.0f), hate_flat(0)
hate_percent(1.0f), hate_flat(0), hit_chance(0)
{ }
float damage_percent;
@ -574,6 +574,7 @@ struct ExtraAttackOptions {
float crit_flat;
float hate_percent;
int hate_flat;
int hit_chance;
};
#endif

View File

@ -683,8 +683,18 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
{
uint32 reduced_recast = spell.recast_time / 1000;
reduced_recast -= CastToClient()->GetFocusEffect(focusReduceRecastTime, spell_id);
if(reduced_recast < 0)
if(reduced_recast <= 0){
reduced_recast = 0;
if (GetPTimers().Enabled((uint32)DiscTimer))
GetPTimers().Clear(&database, (uint32)DiscTimer);
}
if (reduced_recast > 0)
CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast);
else{
CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT);
return true;
}
CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast);
if(spells[spell_id].EndurTimerIndex < MAX_DISCIPLINE_TIMERS)

View File

@ -4612,42 +4612,49 @@ Client *EntityList::FindCorpseDragger(uint16 CorpseID)
return nullptr;
}
Mob *EntityList::GetTargetForVirus(Mob *spreader)
Mob *EntityList::GetTargetForVirus(Mob *spreader, int range)
{
int max_spread_range = RuleI(Spells, VirusSpreadDistance);
if (range)
max_spread_range = range;
std::vector<Mob *> TargetsInRange;
auto it = mob_list.begin();
while (it != mob_list.end()) {
Mob *cur = it->second;
// Make sure the target is in range, has los and is not the mob doing the spreading
if ((it->second->GetID() != spreader->GetID()) &&
(it->second->CalculateDistance(spreader->GetX(), spreader->GetY(),
if ((cur->GetID() != spreader->GetID()) &&
(cur->CalculateDistance(spreader->GetX(), spreader->GetY(),
spreader->GetZ()) <= max_spread_range) &&
(spreader->CheckLosFN(it->second))) {
(spreader->CheckLosFN(cur))) {
// If the spreader is an npc it can only spread to other npc controlled mobs
if (spreader->IsNPC() && !spreader->IsPet() && it->second->IsNPC()) {
TargetsInRange.push_back(it->second);
if (spreader->IsNPC() && !spreader->IsPet() && !spreader->CastToNPC()->GetSwarmOwner() && cur->IsNPC()) {
TargetsInRange.push_back(cur);
}
// If the spreader is an npc controlled pet it can spread to any other npc or an npc controlled pet
else if (spreader->IsNPC() && spreader->IsPet() && spreader->GetOwner()->IsNPC()) {
if (it->second->IsNPC() && !it->second->IsPet()) {
TargetsInRange.push_back(it->second);
} else if (it->second->IsNPC() && it->second->IsPet() && it->second->GetOwner()->IsNPC()) {
TargetsInRange.push_back(it->second);
if (cur->IsNPC() && !cur->IsPet()) {
TargetsInRange.push_back(cur);
} else if (cur->IsNPC() && cur->IsPet() && cur->GetOwner()->IsNPC()) {
TargetsInRange.push_back(cur);
}
else if (cur->IsNPC() && cur->CastToNPC()->GetSwarmOwner() && cur->GetOwner()->IsNPC()) {
TargetsInRange.push_back(cur);
}
}
// if the spreader is anything else(bot, pet, etc) then it should spread to everything but non client controlled npcs
else if (!spreader->IsNPC() && !it->second->IsNPC()) {
TargetsInRange.push_back(it->second);
else if (!spreader->IsNPC() && !cur->IsNPC()) {
TargetsInRange.push_back(cur);
}
// if its a pet we need to determine appropriate targets(pet to client, pet to pet, pet to bot, etc)
else if (spreader->IsNPC() && spreader->IsPet() && !spreader->GetOwner()->IsNPC()) {
if (!it->second->IsNPC()) {
TargetsInRange.push_back(it->second);
else if (spreader->IsNPC() && (spreader->IsPet() || spreader->CastToNPC()->GetSwarmOwner()) && !spreader->GetOwner()->IsNPC()) {
if (!cur->IsNPC()) {
TargetsInRange.push_back(cur);
}
else if (it->second->IsNPC() && it->second->IsPet() && !it->second->GetOwner()->IsNPC()) {
TargetsInRange.push_back(it->second);
else if (cur->IsNPC() && (cur->IsPet() || cur->CastToNPC()->GetSwarmOwner()) && !cur->GetOwner()->IsNPC()) {
TargetsInRange.push_back(cur);
}
}
}

View File

@ -134,7 +134,7 @@ public:
Mob *GetMob(const char* name);
Mob *GetMobByNpcTypeID(uint32 get_id);
bool IsMobSpawnedByNpcTypeID(uint32 get_id);
Mob *GetTargetForVirus(Mob* spreader);
Mob *GetTargetForVirus(Mob* spreader, int range);
inline NPC *GetNPCByID(uint16 id)
{ return npc_list.count(id) ? npc_list.at(id) : nullptr; }
NPC *GetNPCByNPCTypeID(uint32 npc_id);

View File

@ -4349,7 +4349,7 @@ void Mob::SpreadVirus(uint16 spell_id, uint16 casterID)
// Only spread in zones without perm buffs
if(!zone->BuffTimersSuspended()) {
for(int i = 0; i < num_targs; i++) {
target = entity_list.GetTargetForVirus(this);
target = entity_list.GetTargetForVirus(this, spells[spell_id].viral_range);
if(target) {
// Only spreads to the uninfected
if(!target->FindBuff(spell_id)) {

View File

@ -307,6 +307,10 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
sprintf(temp, "%d", spell_id);
parse->EventNPC(EVENT_CAST_BEGIN, CastToNPC(), nullptr, temp, 0);
}
//To prevent NPC ghosting when spells are cast from scripts
if (IsNPC() && IsMoving() && cast_time > 0)
SendPosition();
if(resist_adjust)
{
@ -2191,7 +2195,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
CastToClient()->GetPTimers().Start(casting_spell_timer, casting_spell_timer_duration);
mlog(SPELLS__CASTING, "Spell %d: Setting custom reuse timer %d to %d", spell_id, casting_spell_timer, casting_spell_timer_duration);
}
else if(spells[spell_id].recast_time > 1000) {
else if(spells[spell_id].recast_time > 1000 && !spells[spell_id].IsDisciplineBuff) {
int recast = spells[spell_id].recast_time/1000;
if (spell_id == SPELL_LAY_ON_HANDS) //lay on hands
{

View File

@ -1816,7 +1816,12 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
tmpNPCType->min_dmg = atoi(row[31]);
tmpNPCType->max_dmg = atoi(row[32]);
tmpNPCType->attack_count = atoi(row[33]);
strn0cpy(tmpNPCType->special_abilities, row[34], 512);
if (row[34] != nullptr)
strn0cpy(tmpNPCType->special_abilities, row[34], 512);
else
tmpNPCType->special_abilities[0] = '\0';
tmpNPCType->npc_spells_id = atoi(row[35]);
tmpNPCType->npc_spells_effects_id = atoi(row[36]);
tmpNPCType->d_meele_texture1 = atoi(row[37]);
@ -2018,7 +2023,11 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client
tmpNPCType->min_dmg = atoi(row[24]);
tmpNPCType->max_dmg = atoi(row[25]);
tmpNPCType->attack_count = atoi(row[26]);
strn0cpy(tmpNPCType->special_abilities, row[27], 512);
if (row[27] != nullptr)
strn0cpy(tmpNPCType->special_abilities, row[27], 512);
else
tmpNPCType->special_abilities[0] = '\0';
tmpNPCType->d_meele_texture1 = atoi(row[28]);
tmpNPCType->d_meele_texture2 = atoi(row[29]);