NPC Special Attacks should all work right: also huge explanation in changelog.txt

This commit is contained in:
KimLS 2013-07-11 13:44:45 -07:00
parent ab2c184b54
commit 239d4afb13
10 changed files with 233 additions and 36 deletions

View File

@ -1,5 +1,114 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
== 07/11/2013 ==
KLS: Added a few lua functions.
KLS: Redid the npcspecialatk system with a new system that is more flexible but a little more complicated (this will break any 3rd party tools that deal with them).
Instead of a string such as "ERS" to denote "Enrage Rampage Summon" abilities are indexed by their ability number, level and params separated by '^'.
It is stored in the following format: ability,level[,param0,param1,param2,param3,param4,param5,param6,param7] Params will be read until there are 8 total or a '^' is reached.
Eg: 'ERS' -> '2,1^3,1^1,1
Levels allow us to dictate how abilities behave that may be different even though they're the same ability.
Params allow us to further refine behaviors on a case by case basis. Passing 0 as a param will use the default value.
NOTE: Be sure to source 2013_07_11_NPC_Special_Abilities.sql. Also due to the large impact this has on a database it is very HIGHLY SUGGESTED to BACKUP YOUR DATABASE FIRST.
The following are the special abilities currently in the game as well as their levels and parameters currently in use:
SPECATK_SUMMON = 1
Level 1: Summon target to NPC
Level 2: Summon NPC to target
Param0: Cooldown in ms (default: 6000)
Param1: HP ratio required to summon (default: 97)
SPECATK_ENRAGE = 2
Param0: HP ratio required to enrage (default: rule NPC:StartEnrageValue)
Param1: Enrage duration in ms (default: 10000)
Param2: Enrage cooldown in ms (default: 360000)
SPECATK_RAMPAGE = 3
Param0: Proc chance (default: 20)
Param1: Rampage target count (default: rule Combat:MaxRampageTargets)
Param2: Percent of a normal attack damage to deal (default: 100)
Param3: Flat damage bonus to add to the rampage attack (default: 0)
Param4: Ignore % armor for this attack (default 0)
Param5: Ignore flat armor for this attack (default 0)
Param6: Percent of npc's natual crit that can go toward this rampage (default: 100)
Param7: Flat crit bonus on top of npc's natual crit that can go toward this attack (default 0)
SPECATK_AREA_RAMPAGE = 4
Param0: Proc chance (default: 20)
Param1: Rampage target count (default: 1)
Param2: Percent of a normal attack damage to deal (default: 100)
Param3: Flat damage bonus to add to the rampage attack (default: 0)
Param4: Ignore % armor for this attack (default 0)
Param5: Ignore flat armor for this attack (default 0)
Param6: Percent of npc's natual crit that can go toward this rampage (default: 100)
Param7: Flat crit bonus on top of npc's natual crit that can go toward this attack (default 0)
SPECATK_FLURRY = 5
Param0: Proc chance (default: rule Combat:NPCFlurryChance)
Param1: Flurry attack count (default: rule Combat:MaxFlurryHits)
Param2: Percent of a normal attack damage to deal (default: 100)
Param3: Flat damage bonus to add to the flurry attack (default: 0)
Param4: Ignore % armor for this attack (default 0)
Param5: Ignore flat armor for this attack (default 0)
Param6: Percent of npc's natual crit that can go toward this attack (default: 100)
Param7: Flat crit bonus on top of npc's natual crit that can go toward this attack (default 0)
Ex: Normal Flurry with 25% proc rate and 100% crit chance that ignores 500 armor.
5,1,25,0,0,0,0,500,0,100
SPECATK_TRIPLE = 6
SPECATK_QUAD = 7
SPECATK_INNATE_DW = 8
SPECATK_BANE = 9
SPECATK_MAGICAL = 10
SPECATK_RANGED_ATK = 11
UNSLOWABLE = 12
UNMEZABLE = 13
UNCHARMABLE = 14
UNSTUNABLE = 15
UNSNAREABLE = 16
UNFEARABLE = 17
UNDISPELLABLE = 18
IMMUNE_MELEE = 19
IMMUNE_MAGIC = 20
IMMUNE_FLEEING = 21
IMMUNE_MELEE_EXCEPT_BANE = 22
IMMUNE_MELEE_NONMAGICAL = 23
IMMUNE_AGGRO = 24
IMMUNE_AGGRO_ON = 25
IMMUNE_CASTING_FROM_RANGE = 26
IMMUNE_FEIGN_DEATH = 27
IMMUNE_TAUNT = 28
NPC_TUNNELVISION = 29
Param0: Aggro modifier on non-tanks (default: rule Aggro:TunnelVisionAggroMod)
NPC_NO_BUFFHEAL_FRIENDS = 30
IMMUNE_PACIFY = 31
LEASH = 32
Param0: Range (default: aggro range * aggro range)
TETHER = 33
Param0: Range (default: aggro range * aggro range)
DESTRUCTIBLE_OBJECT = 34
NO_HARM_FROM_CLIENT = 35
The following Lua API functions were added to deal with the new system:
Integer GetSpecialAbility(Integer ability);
Integer GetSpecialAbilityParam(Integer ability, Integer param);
Void SetSpecialAbility(Integer ability, Integer level);
Void SetSpecialAbilityParam(Integer ability, Integer param, Integer value);
Void ClearSpecialAbilities();
Void ProcessSpecialAbilities(String str);
The old API functions that worked with letters still exist for backwards compatibility reasons but wont be updated further.
== 07/08/2013 ==
Secrets: Cleanup of some log functions that did not have an 'off' function.**
Secrets: Unknown opcode messages only show on EQDEBUG* >= 5 or higher now. (including the dumped packet)

View File

@ -0,0 +1,39 @@
ALTER TABLE `npc_types` ADD COLUMN `special_abilities` TEXT NOT NULL DEFAULT '' AFTER `npcspecialattks`;
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "1,1^") WHERE npcspecialattks LIKE BINARY '%S%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "2,1^") WHERE npcspecialattks LIKE BINARY '%E%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "3,1^") WHERE npcspecialattks LIKE BINARY '%R%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "4,1^") WHERE npcspecialattks LIKE BINARY '%r%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "5,1^") WHERE npcspecialattks LIKE BINARY '%F%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "6,1^") WHERE npcspecialattks LIKE BINARY '%T%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "7,1^") WHERE npcspecialattks LIKE BINARY '%Q%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "8,1^") WHERE npcspecialattks LIKE BINARY '%L%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "9,1^") WHERE npcspecialattks LIKE BINARY '%b%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "10,1^") WHERE npcspecialattks LIKE BINARY '%m%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "11,1^") WHERE npcspecialattks LIKE BINARY '%Y%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "12,1^") WHERE npcspecialattks LIKE BINARY '%U%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "13,1^") WHERE npcspecialattks LIKE BINARY '%M%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "14,1^") WHERE npcspecialattks LIKE BINARY '%C%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "15,1^") WHERE npcspecialattks LIKE BINARY '%N%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "16,1^") WHERE npcspecialattks LIKE BINARY '%I%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "17,1^") WHERE npcspecialattks LIKE BINARY '%D%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "18,1^") WHERE npcspecialattks LIKE BINARY '%K%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "19,1^") WHERE npcspecialattks LIKE BINARY '%A%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "20,1^") WHERE npcspecialattks LIKE BINARY '%B%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "21,1^") WHERE npcspecialattks LIKE BINARY '%f%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "22,1^") WHERE npcspecialattks LIKE BINARY '%O%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "23,1^") WHERE npcspecialattks LIKE BINARY '%W%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "24,1^") WHERE npcspecialattks LIKE BINARY '%H%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "25,1^") WHERE npcspecialattks LIKE BINARY '%G%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "26,1^") WHERE npcspecialattks LIKE BINARY '%g%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "27,1^") WHERE npcspecialattks LIKE BINARY '%d%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "28,1^") WHERE npcspecialattks LIKE BINARY '%i%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "29,1^") WHERE npcspecialattks LIKE BINARY '%t%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "30,1^") WHERE npcspecialattks LIKE BINARY '%n%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "31,1^") WHERE npcspecialattks LIKE BINARY '%p%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "32,1^") WHERE npcspecialattks LIKE BINARY '%J%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "33,1^") WHERE npcspecialattks LIKE BINARY '%j%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "34,1^") WHERE npcspecialattks LIKE BINARY '%o%';
UPDATE npc_types SET special_abilities = TRIM(TRAILING '^' FROM special_abilities);
ALTER TABLE `npc_types` DROP COLUMN `npcspecialattks`;

View File

@ -1095,17 +1095,25 @@ void Mob::AI_Process() {
if(DivineAura())
return;
if(GetSpecialAbility(TETHER) || GetSpecialAbility(LEASH)) {
if(DistNoRootNoZ(CastToNPC()->GetSpawnPointX(), CastToNPC()->GetSpawnPointY()) > pAggroRange*pAggroRange) {
if(GetSpecialAbility(TETHER)) {
float aggro_range = static_cast<float>(GetSpecialAbilityParam(TETHER, 0));
aggro_range = aggro_range > 0.0f ? aggro_range : pAggroRange * pAggroRange;
if(DistNoRootNoZ(CastToNPC()->GetSpawnPointX(), CastToNPC()->GetSpawnPointY()) > aggro_range) {
GMMove(CastToNPC()->GetSpawnPointX(), CastToNPC()->GetSpawnPointY(), CastToNPC()->GetSpawnPointZ(), CastToNPC()->GetSpawnPointH());
}
} else if(GetSpecialAbility(LEASH)) {
float aggro_range = static_cast<float>(GetSpecialAbilityParam(LEASH, 0));
aggro_range = aggro_range > 0.0f ? aggro_range : pAggroRange * pAggroRange;
if(DistNoRootNoZ(CastToNPC()->GetSpawnPointX(), CastToNPC()->GetSpawnPointY()) > aggro_range) {
GMMove(CastToNPC()->GetSpawnPointX(), CastToNPC()->GetSpawnPointY(), CastToNPC()->GetSpawnPointZ(), CastToNPC()->GetSpawnPointH());
if(GetSpecialAbility(LEASH)) {
SetHP(GetMaxHP());
BuffFadeAll();
WipeHateList();
return;
}
}
}
StartEnrage();
@ -1180,32 +1188,32 @@ void Mob::AI_Process() {
flurry_chance = flurry_chance > 0 ? flurry_chance : RuleI(Combat, NPCFlurryChance);
ExtraAttackOptions opts;
int cur = GetSpecialAbilityParam(SPECATK_FLURRY, 1);
int cur = GetSpecialAbilityParam(SPECATK_FLURRY, 2);
if(cur > 0) {
opts.damage_percent = cur / 100.0f;
}
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 2);
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 3);
if(cur > 0) {
opts.damage_flat = cur;
}
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 3);
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 4);
if(cur > 0) {
opts.armor_pen_percent = cur / 100.0f;
}
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 4);
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 5);
if(cur > 0) {
opts.armor_pen_flat = cur;
}
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 5);
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 6);
if(cur > 0) {
opts.crit_percent = cur / 100.0f;
}
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 6);
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 7);
if(cur > 0) {
opts.crit_flat = cur;
}
@ -1232,32 +1240,32 @@ void Mob::AI_Process() {
rampage_chance = rampage_chance > 0 ? rampage_chance : 20;
if(MakeRandomInt(0, 99) < rampage_chance) {
ExtraAttackOptions opts;
int cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 1);
int cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 2);
if(cur > 0) {
opts.damage_percent = cur / 100.0f;
}
cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 2);
cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 3);
if(cur > 0) {
opts.damage_flat = cur;
}
cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 3);
cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 4);
if(cur > 0) {
opts.armor_pen_percent = cur / 100.0f;
}
cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 4);
cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 5);
if(cur > 0) {
opts.armor_pen_flat = cur;
}
cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 5);
cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 6);
if(cur > 0) {
opts.crit_percent = cur / 100.0f;
}
cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 6);
cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 7);
if(cur > 0) {
opts.crit_flat = cur;
}
@ -1271,32 +1279,32 @@ void Mob::AI_Process() {
rampage_chance = rampage_chance > 0 ? rampage_chance : 20;
if(MakeRandomInt(0, 99) < rampage_chance) {
ExtraAttackOptions opts;
int cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 1);
int cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 2);
if(cur > 0) {
opts.damage_percent = cur / 100.0f;
}
cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 2);
cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 3);
if(cur > 0) {
opts.damage_flat = cur;
}
cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 3);
cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 4);
if(cur > 0) {
opts.armor_pen_percent = cur / 100.0f;
}
cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 4);
cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 5);
if(cur > 0) {
opts.armor_pen_flat = cur;
}
cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 5);
cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 6);
if(cur > 0) {
opts.crit_percent = cur / 100.0f;
}
cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 6);
cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 7);
if(cur > 0) {
opts.crit_flat = cur;
}
@ -2008,7 +2016,10 @@ bool Mob::Flurry(ExtraAttackOptions *opts)
} else {
entity_list.MessageClose_StringID(this, true, 200, MT_PetFlurry, NPC_FLURRY, GetCleanName(), target->GetCleanName());
}
for (int i = 0; i < RuleI(Combat, MaxFlurryHits); i++)
int num_attacks = GetSpecialAbilityParam(SPECATK_FLURRY, 1);
num_attacks = num_attacks > 0 ? num_attacks : RuleI(Combat, MaxFlurryHits);
for (int i = 0; i < num_attacks; i++)
Attack(target, 13, false, false, false, opts);
}
return true;
@ -2045,9 +2056,12 @@ bool Mob::Rampage(ExtraAttackOptions *opts)
} else {
entity_list.MessageClose_StringID(this, true, 200, MT_PetFlurry, NPC_RAMPAGE, GetCleanName());
}
int rampage_targets = GetSpecialAbilityParam(SPECATK_RAMPAGE, 1);
rampage_targets = rampage_targets > 0 ? rampage_targets : RuleI(Combat, MaxRampageTargets);
for (int i = 0; i < RampageArray.size(); i++)
{
if(index_hit >= RuleI(Combat, MaxRampageTargets))
if(index_hit >= rampage_targets)
break;
// range is important
Mob *m_target = entity_list.GetMob(RampageArray[i].c_str());
@ -2063,7 +2077,7 @@ bool Mob::Rampage(ExtraAttackOptions *opts)
}
}
if(index_hit < RuleI(Combat, MaxRampageTargets)) {
if(index_hit < rampage_targets) {
Attack(GetTarget(), 13, false, false, false, opts);
}
return true;
@ -2077,7 +2091,10 @@ void Mob::AreaRampage(ExtraAttackOptions *opts)
} else {
entity_list.MessageClose_StringID(this, true, 200, MT_PetFlurry, AE_RAMPAGE, GetCleanName());
}
index_hit = hate_list.AreaRampage(this, GetTarget(), opts);
int rampage_targets = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 1);
rampage_targets = rampage_targets > 0 ? rampage_targets : 1;
index_hit = hate_list.AreaRampage(this, GetTarget(), rampage_targets, opts);
if(index_hit == 0) {
Attack(GetTarget(), 13, false, false, false, opts);

View File

@ -473,7 +473,7 @@ void HateList::PrintToClient(Client *c)
}
}
int HateList::AreaRampage(Mob *caster, Mob *target, ExtraAttackOptions *opts)
int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOptions *opts)
{
if(!target || !caster)
return 0;
@ -501,8 +501,10 @@ int HateList::AreaRampage(Mob *caster, Mob *target, ExtraAttackOptions *opts)
Mob *cur = entity_list.GetMobID((*iter));
if(cur)
{
for(int i = 0; i < count; ++i) {
caster->Attack(cur, 13, false, false, false, opts);
}
}
iter++;
}

View File

@ -59,7 +59,7 @@ public:
//Gets the target with the most hate regardless of things like frenzy etc.
Mob* GetMostHate();
int AreaRampage(Mob *caster, Mob *target, ExtraAttackOptions *opts);
int AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOptions *opts);
void SpellCast(Mob *caster, uint32 spell_id, float range);

View File

@ -151,7 +151,7 @@ static const struct luaL_Reg bit_funcs[] = {
*/
#define BAD_SAR (bsar(-8, 2) != (SBits)-2)
LUALIB_API int luaopen_bit(lua_State *L)
int luaopen_bit(lua_State *L)
{
UBits b;
lua_pushnumber(L, (lua_Number)1437217655L);

View File

@ -5,6 +5,7 @@
#include <luabind/object.hpp>
#include "doors.h"
#include "lua_mob.h"
#include "lua_door.h"
void Lua_Door::SetDoorName(const char *name) {
@ -137,6 +138,26 @@ void Lua_Door::CreateDatabaseEntry() {
self->CreateDatabaseEntry();
}
void Lua_Door::ForceOpen(Lua_Mob sender) {
Lua_Safe_Call_Void();
self->ForceOpen(sender);
}
void Lua_Door::ForceOpen(Lua_Mob sender, bool alt_mode) {
Lua_Safe_Call_Void();
self->ForceOpen(sender, alt_mode);
}
void Lua_Door::ForceClose(Lua_Mob sender) {
Lua_Safe_Call_Void();
self->ForceClose(sender);
}
void Lua_Door::ForceClose(Lua_Mob sender, bool alt_mode) {
Lua_Safe_Call_Void();
self->ForceClose(sender, alt_mode);
}
luabind::scope lua_register_door() {
return luabind::class_<Lua_Door, Lua_Entity>("Door")
.def(luabind::constructor<>())
@ -167,7 +188,11 @@ luabind::scope lua_register_door() {
.def("GetKeyItem", (uint32(Lua_Door::*)(void))&Lua_Door::GetKeyItem)
.def("SetNoKeyring", (void(Lua_Door::*)(int))&Lua_Door::SetNoKeyring)
.def("GetNoKeyring", (int(Lua_Door::*)(void))&Lua_Door::GetNoKeyring)
.def("CreateDatabaseEntry", (void(Lua_Door::*)(void))&Lua_Door::CreateDatabaseEntry);
.def("CreateDatabaseEntry", (void(Lua_Door::*)(void))&Lua_Door::CreateDatabaseEntry)
.def("ForceOpen", (void(Lua_Door::*)(Lua_Mob))&Lua_Door::ForceOpen)
.def("ForceOpen", (void(Lua_Door::*)(Lua_Mob,bool))&Lua_Door::ForceOpen)
.def("ForceClose", (void(Lua_Door::*)(Lua_Mob))&Lua_Door::ForceClose)
.def("ForceClose", (void(Lua_Door::*)(Lua_Mob,bool))&Lua_Door::ForceClose);
}
#endif

View File

@ -5,6 +5,7 @@
#include "lua_entity.h"
class Doors;
class Lua_Mob;
namespace luabind {
struct scope;
@ -55,6 +56,10 @@ public:
void SetNoKeyring(int type);
int GetNoKeyring();
void CreateDatabaseEntry();
void ForceOpen(Lua_Mob sender);
void ForceOpen(Lua_Mob sender, bool alt_mode);
void ForceClose(Lua_Mob sender);
void ForceClose(Lua_Mob sender, bool alt_mode);
};
#endif

View File

@ -1820,6 +1820,7 @@ luabind::scope lua_register_mob() {
.def("Attack", (bool(Lua_Mob::*)(Lua_Mob,int,bool))&Lua_Mob::Attack)
.def("Attack", (bool(Lua_Mob::*)(Lua_Mob,int,bool,bool))&Lua_Mob::Attack)
.def("Attack", (bool(Lua_Mob::*)(Lua_Mob,int,bool,bool,bool))&Lua_Mob::Attack)
.def("Attack", (bool(Lua_Mob::*)(Lua_Mob,int,bool,bool,bool,luabind::object))&Lua_Mob::Attack)
.def("Damage", (void(Lua_Mob::*)(Lua_Mob,int,int,int))&Lua_Mob::Damage)
.def("Damage", (void(Lua_Mob::*)(Lua_Mob,int,int,int,bool))&Lua_Mob::Damage)
.def("Damage", (void(Lua_Mob::*)(Lua_Mob,int,int,int,bool,int))&Lua_Mob::Damage)

View File

@ -2338,7 +2338,6 @@ bool Mob::HateSummon() {
int summon_level = GetSpecialAbility(SPECATK_SUMMON);
if(summon_level == 1 || summon_level == 2) {
//Summon things always
if(!GetTarget() || (mob_owner && mob_owner->IsClient() && !CheckLosFN(GetTarget()))) {
return false;
}