mirror of
https://github.com/EQEmu/Server.git
synced 2026-01-27 05:23:52 +00:00
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:
commit
2d77adeeb8
@ -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`;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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]);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user