mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-16 18:52:22 +00:00
Merge branch 'master' into lsid
This commit is contained in:
+21
-6
@@ -19,6 +19,7 @@ SET(zone_sources
|
||||
client_process.cpp
|
||||
command.cpp
|
||||
corpse.cpp
|
||||
data_bucket.cpp
|
||||
doors.cpp
|
||||
effects.cpp
|
||||
embparser.cpp
|
||||
@@ -28,6 +29,7 @@ SET(zone_sources
|
||||
encounter.cpp
|
||||
entity.cpp
|
||||
exp.cpp
|
||||
fastmath.cpp
|
||||
fearpath.cpp
|
||||
forage.cpp
|
||||
groups.cpp
|
||||
@@ -68,6 +70,7 @@ SET(zone_sources
|
||||
exp.cpp
|
||||
fearpath.cpp
|
||||
forage.cpp
|
||||
global_loot_manager.cpp
|
||||
groups.cpp
|
||||
guild.cpp
|
||||
guild_mgr.cpp
|
||||
@@ -79,12 +82,19 @@ SET(zone_sources
|
||||
merc.cpp
|
||||
mob.cpp
|
||||
mob_ai.cpp
|
||||
mob_appearance.cpp
|
||||
mob_movement_manager.cpp
|
||||
mob_info.cpp
|
||||
mod_functions.cpp
|
||||
net.cpp
|
||||
npc.cpp
|
||||
npc_ai.cpp
|
||||
npc_scale_manager.cpp
|
||||
object.cpp
|
||||
oriented_bounding_box.cpp
|
||||
pathfinder_interface.cpp
|
||||
pathfinder_nav_mesh.cpp
|
||||
pathfinder_null.cpp
|
||||
pathing.cpp
|
||||
perl_client.cpp
|
||||
perl_doors.cpp
|
||||
@@ -130,8 +140,7 @@ SET(zone_sources
|
||||
zone.cpp
|
||||
zone_config.cpp
|
||||
zonedb.cpp
|
||||
zoning.cpp
|
||||
)
|
||||
zoning.cpp)
|
||||
|
||||
SET(zone_headers
|
||||
aa.h
|
||||
@@ -149,6 +158,7 @@ SET(zone_headers
|
||||
command.h
|
||||
common.h
|
||||
corpse.h
|
||||
data_bucket.h
|
||||
doors.h
|
||||
embparser.h
|
||||
embperl.h
|
||||
@@ -157,7 +167,9 @@ SET(zone_headers
|
||||
entity.h
|
||||
errmsg.h
|
||||
event_codes.h
|
||||
fastmath.h
|
||||
forage.h
|
||||
global_loot_manager.h
|
||||
groups.h
|
||||
guild_mgr.h
|
||||
hate_list.h
|
||||
@@ -194,12 +206,16 @@ SET(zone_headers
|
||||
message.h
|
||||
merc.h
|
||||
mob.h
|
||||
mob_movement_manager.h
|
||||
net.h
|
||||
npc.h
|
||||
npc_ai.h
|
||||
npc_scale_manager.h
|
||||
object.h
|
||||
oriented_bounding_box.h
|
||||
pathing.h
|
||||
pathfinder_interface.h
|
||||
pathfinder_nav_mesh.h
|
||||
pathfinder_null.h
|
||||
perlpacket.h
|
||||
petitions.h
|
||||
pets.h
|
||||
@@ -229,8 +245,7 @@ SET(zone_headers
|
||||
zone.h
|
||||
zone_config.h
|
||||
zonedb.h
|
||||
zonedump.h
|
||||
)
|
||||
zonedump.h)
|
||||
|
||||
IF(EQEMU_DEPOP_INVALIDATES_CACHE)
|
||||
ADD_DEFINITIONS(-DDEPOP_INVALIDATES_NPC_TYPES_CACHE)
|
||||
@@ -246,7 +261,7 @@ TARGET_LINK_LIBRARIES(zone ${SERVER_LIBS})
|
||||
|
||||
IF(EQEMU_BUILD_PERL)
|
||||
TARGET_LINK_LIBRARIES(zone ${PERL_LIBRARY})
|
||||
ENDIF(EQEMU_BUILD_PERL)
|
||||
ENDIF()
|
||||
|
||||
IF(EQEMU_BUILD_LUA)
|
||||
TARGET_LINK_LIBRARIES(zone luabind ${LUA_LIBRARY})
|
||||
|
||||
+30
-18
@@ -126,7 +126,7 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u
|
||||
(npc_dup != nullptr) ? npc_dup : npc_type, //make sure we give the NPC the correct data pointer
|
||||
0,
|
||||
GetPosition() + glm::vec4(swarmPetLocations[summon_count], 0.0f, 0.0f),
|
||||
FlyMode3);
|
||||
GravityBehavior::Water);
|
||||
|
||||
if (followme)
|
||||
swarm_pet_npc->SetFollowID(GetID());
|
||||
@@ -225,7 +225,7 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid
|
||||
(npc_dup!=nullptr)?npc_dup:npc_type, //make sure we give the NPC the correct data pointer
|
||||
0,
|
||||
GetPosition() + glm::vec4(swarmPetLocations[summon_count], 0.0f, 0.0f),
|
||||
FlyMode3);
|
||||
GravityBehavior::Water);
|
||||
|
||||
if (followme)
|
||||
swarm_pet_npc->SetFollowID(GetID());
|
||||
@@ -286,7 +286,7 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
|
||||
make_npc->min_dmg = 1;
|
||||
|
||||
//base stats
|
||||
make_npc->cur_hp = (GetLevel() * 55);
|
||||
make_npc->current_hp = (GetLevel() * 55);
|
||||
make_npc->max_hp = (GetLevel() * 55);
|
||||
make_npc->STR = 85 + (GetLevel() * 3);
|
||||
make_npc->STA = 85 + (GetLevel() * 3);
|
||||
@@ -356,51 +356,51 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
|
||||
case PALADIN:
|
||||
//SPECATK_TRIPLE
|
||||
strcpy(make_npc->special_abilities, "6,1");
|
||||
make_npc->cur_hp = make_npc->cur_hp * 150 / 100;
|
||||
make_npc->current_hp = make_npc->current_hp * 150 / 100;
|
||||
make_npc->max_hp = make_npc->max_hp * 150 / 100;
|
||||
make_npc->npc_spells_id = 8;
|
||||
break;
|
||||
case SHADOWKNIGHT:
|
||||
strcpy(make_npc->special_abilities, "6,1");
|
||||
make_npc->cur_hp = make_npc->cur_hp * 150 / 100;
|
||||
make_npc->current_hp = make_npc->current_hp * 150 / 100;
|
||||
make_npc->max_hp = make_npc->max_hp * 150 / 100;
|
||||
make_npc->npc_spells_id = 9;
|
||||
break;
|
||||
case RANGER:
|
||||
strcpy(make_npc->special_abilities, "7,1");
|
||||
make_npc->cur_hp = make_npc->cur_hp * 135 / 100;
|
||||
make_npc->current_hp = make_npc->current_hp * 135 / 100;
|
||||
make_npc->max_hp = make_npc->max_hp * 135 / 100;
|
||||
make_npc->npc_spells_id = 10;
|
||||
break;
|
||||
case BARD:
|
||||
strcpy(make_npc->special_abilities, "6,1");
|
||||
make_npc->cur_hp = make_npc->cur_hp * 110 / 100;
|
||||
make_npc->current_hp = make_npc->current_hp * 110 / 100;
|
||||
make_npc->max_hp = make_npc->max_hp * 110 / 100;
|
||||
make_npc->npc_spells_id = 11;
|
||||
break;
|
||||
case BEASTLORD:
|
||||
strcpy(make_npc->special_abilities, "7,1");
|
||||
make_npc->cur_hp = make_npc->cur_hp * 110 / 100;
|
||||
make_npc->current_hp = make_npc->current_hp * 110 / 100;
|
||||
make_npc->max_hp = make_npc->max_hp * 110 / 100;
|
||||
make_npc->npc_spells_id = 12;
|
||||
break;
|
||||
case ROGUE:
|
||||
strcpy(make_npc->special_abilities, "7,1");
|
||||
make_npc->max_dmg = make_npc->max_dmg * 150 /100;
|
||||
make_npc->cur_hp = make_npc->cur_hp * 110 / 100;
|
||||
make_npc->current_hp = make_npc->current_hp * 110 / 100;
|
||||
make_npc->max_hp = make_npc->max_hp * 110 / 100;
|
||||
break;
|
||||
case MONK:
|
||||
strcpy(make_npc->special_abilities, "7,1");
|
||||
make_npc->max_dmg = make_npc->max_dmg * 150 /100;
|
||||
make_npc->cur_hp = make_npc->cur_hp * 135 / 100;
|
||||
make_npc->current_hp = make_npc->current_hp * 135 / 100;
|
||||
make_npc->max_hp = make_npc->max_hp * 135 / 100;
|
||||
break;
|
||||
case WARRIOR:
|
||||
case BERSERKER:
|
||||
strcpy(make_npc->special_abilities, "7,1");
|
||||
make_npc->max_dmg = make_npc->max_dmg * 150 /100;
|
||||
make_npc->cur_hp = make_npc->cur_hp * 175 / 100;
|
||||
make_npc->current_hp = make_npc->current_hp * 175 / 100;
|
||||
make_npc->max_hp = make_npc->max_hp * 175 / 100;
|
||||
break;
|
||||
default:
|
||||
@@ -413,7 +413,7 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
|
||||
make_npc->d_melee_texture1 = 0;
|
||||
make_npc->d_melee_texture2 = 0;
|
||||
|
||||
auto npca = new NPC(make_npc, 0, GetPosition(), FlyMode3);
|
||||
auto npca = new NPC(make_npc, 0, GetPosition(), GravityBehavior::Water);
|
||||
|
||||
if(!npca->GetSwarmInfo()){
|
||||
auto nSI = new SwarmPet;
|
||||
@@ -424,6 +424,7 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
|
||||
npca->GetSwarmInfo()->duration->Start(duration*1000);
|
||||
}
|
||||
|
||||
npca->StartSwarmTimer(duration * 1000);
|
||||
npca->GetSwarmInfo()->owner_id = GetID();
|
||||
|
||||
//give the pet somebody to "love"
|
||||
@@ -434,7 +435,7 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
|
||||
|
||||
//gear stuff, need to make sure there's
|
||||
//no situation where this stuff can be duped
|
||||
for (int x = EQEmu::legacy::EQUIPMENT_BEGIN; x <= EQEmu::legacy::EQUIPMENT_END; x++) // (< 21) added MainAmmo
|
||||
for (int x = EQEmu::invslot::EQUIPMENT_BEGIN; x <= EQEmu::invslot::EQUIPMENT_END; x++)
|
||||
{
|
||||
uint32 sitem = 0;
|
||||
sitem = CorpseToUse->GetWornItem(x);
|
||||
@@ -487,7 +488,7 @@ void Client::ResetAA() {
|
||||
|
||||
database.DeleteCharacterLeadershipAAs(CharacterID());
|
||||
// undefined for these clients
|
||||
if (ClientVersionBit() & EQEmu::versions::bit_TitaniumAndEarlier)
|
||||
if (ClientVersionBit() & EQEmu::versions::maskTitaniumAndEarlier)
|
||||
Kick();
|
||||
}
|
||||
|
||||
@@ -1171,7 +1172,7 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
|
||||
return;
|
||||
|
||||
//check cooldown
|
||||
if(!p_timers.Expired(&database, rank->spell_type + pTimerAAStart)) {
|
||||
if(!p_timers.Expired(&database, rank->spell_type + pTimerAAStart, false)) {
|
||||
uint32 aaremain = p_timers.GetRemainingTime(rank->spell_type + pTimerAAStart);
|
||||
uint32 aaremain_hr = aaremain / (60 * 60);
|
||||
uint32 aaremain_min = (aaremain / 60) % 60;
|
||||
@@ -1207,14 +1208,25 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
|
||||
if (spells[rank->spell].targettype == ST_Pet || spells[rank->spell].targettype == ST_SummonedPet)
|
||||
target_id = GetPetID();
|
||||
|
||||
// extra handling for cast_not_standing spells
|
||||
if (!spells[rank->spell].cast_not_standing) {
|
||||
if (GetAppearance() == eaSitting) // we need to stand!
|
||||
SetAppearance(eaStanding, false);
|
||||
|
||||
if (GetAppearance() != eaStanding) {
|
||||
Message_StringID(MT_SpellFailure, STAND_TO_CAST);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Bards can cast instant cast AAs while they are casting another song
|
||||
if(spells[rank->spell].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) {
|
||||
if(!SpellFinished(rank->spell, entity_list.GetMob(target_id), EQEmu::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].ResistDiff, false)) {
|
||||
if(!SpellFinished(rank->spell, entity_list.GetMob(target_id), EQEmu::spells::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].ResistDiff, false)) {
|
||||
return;
|
||||
}
|
||||
ExpendAlternateAdvancementCharge(ability->id);
|
||||
} else {
|
||||
if(!CastSpell(rank->spell, target_id, EQEmu::CastingSlot::AltAbility, -1, -1, 0, -1, rank->spell_type + pTimerAAStart, cooldown, nullptr, rank->id)) {
|
||||
if(!CastSpell(rank->spell, target_id, EQEmu::spells::CastingSlot::AltAbility, -1, -1, 0, -1, rank->spell_type + pTimerAAStart, cooldown, nullptr, rank->id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1443,7 +1455,7 @@ bool Mob::CanUseAlternateAdvancementRank(AA::Rank *rank) {
|
||||
//the one titanium hack i will allow
|
||||
//just to make sure we dont crash the client with newer aas
|
||||
//we'll exclude any expendable ones
|
||||
if(IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::bit_TitaniumAndEarlier) {
|
||||
if(IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::maskTitaniumAndEarlier) {
|
||||
if(ability->charges > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+65
-36
@@ -107,16 +107,10 @@ void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) {
|
||||
float iAggroRange = GetAggroRange();
|
||||
|
||||
float t1, t2, t3;
|
||||
t1 = mob->GetX() - GetX();
|
||||
t2 = mob->GetY() - GetY();
|
||||
t3 = mob->GetZ() - GetZ();
|
||||
//Cheap ABS()
|
||||
if(t1 < 0)
|
||||
t1 = 0 - t1;
|
||||
if(t2 < 0)
|
||||
t2 = 0 - t2;
|
||||
if(t3 < 0)
|
||||
t3 = 0 - t3;
|
||||
t1 = std::abs(mob->GetX() - GetX());
|
||||
t2 = std::abs(mob->GetY() - GetY());
|
||||
t3 = std::abs(mob->GetZ() - GetZ());
|
||||
|
||||
if(( t1 > iAggroRange)
|
||||
|| ( t2 > iAggroRange)
|
||||
|| ( t3 > iAggroRange) ) {
|
||||
@@ -158,7 +152,7 @@ void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) {
|
||||
|
||||
if (RuleB(Aggro, UseLevelAggro))
|
||||
{
|
||||
if (GetLevel() < 18 && mob->GetLevelCon(GetLevel()) == CON_GRAY && GetBodyType() != 3)
|
||||
if (GetLevel() < RuleI(Aggro, MinAggroLevel) && mob->GetLevelCon(GetLevel()) == CON_GRAY && GetBodyType() != 3)
|
||||
{
|
||||
towho->Message(0, "...%s is red to me (basically)", mob->GetName(), dist2, iAggroRange2);
|
||||
return;
|
||||
@@ -257,9 +251,17 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Mob *ownr = mob->GetOwner();
|
||||
if(ownr && ownr->IsClient() && !ownr->CastToClient()->ClientFinishedLoading())
|
||||
/**
|
||||
* Pets shouldn't scan for aggro
|
||||
*/
|
||||
if (this->GetOwner()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Mob *pet_owner = mob->GetOwner();
|
||||
if (pet_owner && pet_owner->IsClient()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float iAggroRange = GetAggroRange();
|
||||
|
||||
@@ -271,16 +273,10 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
// Image: I moved this up by itself above faction and distance checks because if one of these return true, theres no reason to go through the other information
|
||||
|
||||
float t1, t2, t3;
|
||||
t1 = mob->GetX() - GetX();
|
||||
t2 = mob->GetY() - GetY();
|
||||
t3 = mob->GetZ() - GetZ();
|
||||
//Cheap ABS()
|
||||
if(t1 < 0)
|
||||
t1 = 0 - t1;
|
||||
if(t2 < 0)
|
||||
t2 = 0 - t2;
|
||||
if(t3 < 0)
|
||||
t3 = 0 - t3;
|
||||
t1 = std::abs(mob->GetX() - GetX());
|
||||
t2 = std::abs(mob->GetY() - GetY());
|
||||
t3 = std::abs(mob->GetZ() - GetZ());
|
||||
|
||||
if(( t1 > iAggroRange)
|
||||
|| ( t2 > iAggroRange)
|
||||
|| ( t3 > iAggroRange)
|
||||
@@ -336,7 +332,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
(
|
||||
//old InZone check taken care of above by !mob->CastToClient()->Connected()
|
||||
(
|
||||
( GetLevel() >= 18 )
|
||||
( GetLevel() >= RuleI(Aggro, MinAggroLevel))
|
||||
||(GetBodyType() == 3)
|
||||
||( mob->IsClient() && mob->CastToClient()->IsSitting() )
|
||||
||( mob->GetLevelCon(GetLevel()) != CON_GRAY)
|
||||
@@ -424,7 +420,7 @@ Mob* EntityList::AICheckNPCtoNPCAggro(Mob* sender, float iAggroRange, float iAss
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int EntityList::GetHatedCount(Mob *attacker, Mob *exclude)
|
||||
int EntityList::GetHatedCount(Mob *attacker, Mob *exclude, bool inc_gray_con)
|
||||
{
|
||||
// Return a list of how many non-feared, non-mezzed, non-green mobs, within aggro range, hate *attacker
|
||||
if (!attacker)
|
||||
@@ -434,20 +430,25 @@ int EntityList::GetHatedCount(Mob *attacker, Mob *exclude)
|
||||
|
||||
for (auto it = npc_list.begin(); it != npc_list.end(); ++it) {
|
||||
NPC *mob = it->second;
|
||||
if (!mob || (mob == exclude))
|
||||
if (!mob || (mob == exclude)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!mob->IsEngaged())
|
||||
if (!mob->IsEngaged()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mob->IsFeared() || mob->IsMezzed())
|
||||
if (mob->IsFeared() || mob->IsMezzed()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (attacker->GetLevelCon(mob->GetLevel()) == CON_GRAY)
|
||||
if (!inc_gray_con && attacker->GetLevelCon(mob->GetLevel()) == CON_GRAY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!mob->CheckAggro(attacker))
|
||||
if (!mob->CheckAggro(attacker)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float AggroRange = mob->GetAggroRange();
|
||||
|
||||
@@ -455,14 +456,12 @@ int EntityList::GetHatedCount(Mob *attacker, Mob *exclude)
|
||||
|
||||
AggroRange *= AggroRange;
|
||||
|
||||
if (DistanceSquared(mob->GetPosition(), attacker->GetPosition()) > AggroRange)
|
||||
if (DistanceSquared(mob->GetPosition(), attacker->GetPosition()) > AggroRange) {
|
||||
continue;
|
||||
|
||||
}
|
||||
Count++;
|
||||
}
|
||||
|
||||
return Count;
|
||||
|
||||
}
|
||||
|
||||
void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) {
|
||||
@@ -523,7 +522,7 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) {
|
||||
Log(Logs::General, Logs::None, "AIYellForHelp(\"%s\",\"%s\") %s attacking %s Dist %f Z %f",
|
||||
sender->GetName(), attacker->GetName(), mob->GetName(),
|
||||
attacker->GetName(), DistanceSquared(mob->GetPosition(),
|
||||
sender->GetPosition()), fabs(sender->GetZ()+mob->GetZ()));
|
||||
sender->GetPosition()), std::abs(sender->GetZ()+mob->GetZ()));
|
||||
#endif
|
||||
mob->AddToHateList(attacker, 25, 0, false);
|
||||
sender->AddAssistCap();
|
||||
@@ -736,6 +735,7 @@ type', in which case, the answer is yes.
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
// this is HIGHLY inefficient
|
||||
bool HasRuleDefined = false;
|
||||
bool IsBotAttackAllowed = false;
|
||||
IsBotAttackAllowed = Bot::IsBotAttackAllowed(mob1, mob2, HasRuleDefined);
|
||||
@@ -931,7 +931,9 @@ bool Mob::CombatRange(Mob* other)
|
||||
if (size_mod > 10000)
|
||||
size_mod = size_mod / 7;
|
||||
|
||||
float _DistNoRoot = DistanceSquared(m_Position, other->GetPosition());
|
||||
float _DistNoRoot = DistanceSquaredNoZ(m_Position, other->GetPosition());
|
||||
float _zDist = m_Position.z - other->GetZ();
|
||||
_zDist *= _zDist;
|
||||
|
||||
if (GetSpecialAbility(NPC_CHASE_DISTANCE)){
|
||||
|
||||
@@ -960,6 +962,11 @@ bool Mob::CombatRange(Mob* other)
|
||||
|
||||
if (_DistNoRoot <= size_mod)
|
||||
{
|
||||
//A hack to kill an exploit till we get something better.
|
||||
if (flymode != GravityBehavior::Flying && _zDist > 500 && !CheckLastLosState()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1007,6 +1014,28 @@ bool Mob::CheckLosFN(float posX, float posY, float posZ, float mobSize) {
|
||||
return zone->zonemap->CheckLoS(myloc, oloc);
|
||||
}
|
||||
|
||||
bool Mob::CheckLosFN(glm::vec3 posWatcher, float sizeWatcher, glm::vec3 posTarget, float sizeTarget) {
|
||||
if (zone->zonemap == nullptr) {
|
||||
//not sure what the best return is on error
|
||||
//should make this a database variable, but im lazy today
|
||||
#ifdef LOS_DEFAULT_CAN_SEE
|
||||
return(true);
|
||||
#else
|
||||
return(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define LOS_DEFAULT_HEIGHT 6.0f
|
||||
|
||||
posWatcher.z += (sizeWatcher == 0.0f ? LOS_DEFAULT_HEIGHT : sizeWatcher) / 2 * HEAD_POSITION;
|
||||
posTarget.z += (sizeTarget == 0.0f ? LOS_DEFAULT_HEIGHT : sizeTarget) / 2 * SEE_POSITION;
|
||||
|
||||
#if LOSDEBUG>=5
|
||||
Log(Logs::General, Logs::None, "LOS from (%.2f, %.2f, %.2f) to (%.2f, %.2f, %.2f) sizes: (%.2f, %.2f) [static]", posWatcher.x, posWatcher.y, posWatcher.z, posTarget.x, posTarget.y, posTarget.z, sizeWatcher, sizeTarget);
|
||||
#endif
|
||||
return zone->zonemap->CheckLoS(posWatcher, posTarget);
|
||||
}
|
||||
|
||||
//offensive spell aggro
|
||||
int32 Mob::CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc)
|
||||
{
|
||||
|
||||
+139
-101
@@ -32,10 +32,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "worldserver.h"
|
||||
#include "zone.h"
|
||||
#include "lua_parser.h"
|
||||
#include "fastmath.h"
|
||||
#include "mob.h"
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <boost/concept_check.hpp>
|
||||
|
||||
#ifdef BOTS
|
||||
#include "bot.h"
|
||||
@@ -43,6 +47,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
extern QueryServ* QServ;
|
||||
extern WorldServer worldserver;
|
||||
extern FastMath g_Math;
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define snprintf _snprintf
|
||||
@@ -134,7 +139,7 @@ EQEmu::skills::SkillType Mob::AttackAnimation(int Hand, const EQEmu::ItemInstanc
|
||||
}
|
||||
|
||||
// If we're attacking with the secondary hand, play the dual wield anim
|
||||
if (Hand == EQEmu::inventory::slotSecondary) // DW anim
|
||||
if (Hand == EQEmu::invslot::slotSecondary) // DW anim
|
||||
type = animDualWield;
|
||||
|
||||
DoAnim(type, 0, false);
|
||||
@@ -358,7 +363,7 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit)
|
||||
Mob *attacker = other;
|
||||
Mob *defender = this;
|
||||
|
||||
bool InFront = attacker->InFrontMob(this, attacker->GetX(), attacker->GetY());
|
||||
bool InFront = !attacker->BehindMob(this, attacker->GetX(), attacker->GetY());
|
||||
|
||||
/*
|
||||
This special ability adds a negative modifer to the defenders riposte/block/parry/chance
|
||||
@@ -384,7 +389,7 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit)
|
||||
// riposte -- it may seem crazy, but if the attacker has SPA 173 on them, they are immune to Ripo
|
||||
bool ImmuneRipo = attacker->aabonuses.RiposteChance || attacker->spellbonuses.RiposteChance || attacker->itembonuses.RiposteChance || attacker->IsEnraged();
|
||||
// Need to check if we have something in MainHand to actually attack with (or fists)
|
||||
if (hit.hand != EQEmu::inventory::slotRange && (CanThisClassRiposte() || IsEnraged()) && InFront && !ImmuneRipo) {
|
||||
if (hit.hand != EQEmu::invslot::slotRange && (CanThisClassRiposte() || IsEnraged()) && InFront && !ImmuneRipo) {
|
||||
if (IsEnraged()) {
|
||||
hit.damage_done = DMG_RIPOSTED;
|
||||
Log(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack.");
|
||||
@@ -406,7 +411,7 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit)
|
||||
chance -= chance * counter;
|
||||
}
|
||||
// AA Slippery Attacks
|
||||
if (hit.hand == EQEmu::inventory::slotSecondary) {
|
||||
if (hit.hand == EQEmu::invslot::slotSecondary) {
|
||||
int slip = aabonuses.OffhandRiposteFail + itembonuses.OffhandRiposteFail + spellbonuses.OffhandRiposteFail;
|
||||
chance += chance * slip / 100;
|
||||
}
|
||||
@@ -451,7 +456,7 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit)
|
||||
}
|
||||
|
||||
// parry
|
||||
if (CanThisClassParry() && InFront && hit.hand != EQEmu::inventory::slotRange) {
|
||||
if (CanThisClassParry() && InFront && hit.hand != EQEmu::invslot::slotRange) {
|
||||
if (IsClient())
|
||||
CastToClient()->CheckIncreaseSkill(EQEmu::skills::SkillParry, other, -10);
|
||||
// check auto discs ... I guess aa/items too :P
|
||||
@@ -781,7 +786,7 @@ int Mob::ACSum()
|
||||
int shield_ac = 0;
|
||||
if (HasShieldEquiped() && IsClient()) {
|
||||
auto client = CastToClient();
|
||||
auto inst = client->GetInv().GetItem(EQEmu::inventory::slotSecondary);
|
||||
auto inst = client->GetInv().GetItem(EQEmu::invslot::slotSecondary);
|
||||
if (inst) {
|
||||
if (inst->GetItemRecommendedLevel(true) <= GetLevel())
|
||||
shield_ac = inst->GetItemArmorClass(true);
|
||||
@@ -1109,7 +1114,7 @@ int Mob::GetWeaponDamage(Mob *against, const EQEmu::ItemInstance *weapon_item, u
|
||||
else {
|
||||
bool MagicGloves = false;
|
||||
if (IsClient()) {
|
||||
const EQEmu::ItemInstance *gloves = CastToClient()->GetInv().GetItem(EQEmu::inventory::slotHands);
|
||||
const EQEmu::ItemInstance *gloves = CastToClient()->GetInv().GetItem(EQEmu::invslot::slotHands);
|
||||
if (gloves)
|
||||
MagicGloves = gloves->GetItemMagical(true);
|
||||
}
|
||||
@@ -1395,12 +1400,12 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
||||
return false; // Rogean: How can you attack while feigned? Moved up from Aggro Code.
|
||||
|
||||
EQEmu::ItemInstance* weapon = nullptr;
|
||||
if (Hand == EQEmu::inventory::slotSecondary) { // Kaiyodo - Pick weapon from the attacking hand
|
||||
weapon = GetInv().GetItem(EQEmu::inventory::slotSecondary);
|
||||
if (Hand == EQEmu::invslot::slotSecondary) { // Kaiyodo - Pick weapon from the attacking hand
|
||||
weapon = GetInv().GetItem(EQEmu::invslot::slotSecondary);
|
||||
OffHandAtk(true);
|
||||
}
|
||||
else {
|
||||
weapon = GetInv().GetItem(EQEmu::inventory::slotPrimary);
|
||||
weapon = GetInv().GetItem(EQEmu::invslot::slotPrimary);
|
||||
OffHandAtk(false);
|
||||
}
|
||||
|
||||
@@ -1438,10 +1443,10 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
||||
if (my_hit.base_damage > 0) {
|
||||
// if we revamp this function be more general, we will have to make sure this isn't
|
||||
// executed for anything BUT normal melee damage weapons from auto attack
|
||||
if (Hand == EQEmu::inventory::slotPrimary || Hand == EQEmu::inventory::slotSecondary)
|
||||
if (Hand == EQEmu::invslot::slotPrimary || Hand == EQEmu::invslot::slotSecondary)
|
||||
my_hit.base_damage = DoDamageCaps(my_hit.base_damage);
|
||||
auto shield_inc = spellbonuses.ShieldEquipDmgMod + itembonuses.ShieldEquipDmgMod + aabonuses.ShieldEquipDmgMod;
|
||||
if (shield_inc > 0 && HasShieldEquiped() && Hand == EQEmu::inventory::slotPrimary) {
|
||||
if (shield_inc > 0 && HasShieldEquiped() && Hand == EQEmu::invslot::slotPrimary) {
|
||||
my_hit.base_damage = my_hit.base_damage * (100 + shield_inc) / 100;
|
||||
hate = hate * (100 + shield_inc) / 100;
|
||||
}
|
||||
@@ -1463,7 +1468,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
||||
|
||||
int ucDamageBonus = 0;
|
||||
|
||||
if (Hand == EQEmu::inventory::slotPrimary && GetLevel() >= 28 && IsWarriorClass())
|
||||
if (Hand == EQEmu::invslot::slotPrimary && GetLevel() >= 28 && IsWarriorClass())
|
||||
{
|
||||
// Damage bonuses apply only to hits from the main hand (Hand == MainPrimary) by characters level 28 and above
|
||||
// who belong to a melee class. If we're here, then all of these conditions apply.
|
||||
@@ -1475,7 +1480,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
||||
}
|
||||
#endif
|
||||
//Live AA - Sinister Strikes *Adds weapon damage bonus to offhand weapon.
|
||||
if (Hand == EQEmu::inventory::slotSecondary) {
|
||||
if (Hand == EQEmu::invslot::slotSecondary) {
|
||||
if (aabonuses.SecondaryDmgInc || itembonuses.SecondaryDmgInc || spellbonuses.SecondaryDmgInc) {
|
||||
|
||||
ucDamageBonus = GetWeaponDamageBonus(weapon ? weapon->GetItem() : (const EQEmu::ItemData*) nullptr, true);
|
||||
@@ -1521,7 +1526,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
||||
IsValidSpell(aabonuses.SkillAttackProc[2])) {
|
||||
float chance = aabonuses.SkillAttackProc[0] / 1000.0f;
|
||||
if (zone->random.Roll(chance))
|
||||
SpellFinished(aabonuses.SkillAttackProc[2], other, EQEmu::CastingSlot::Item, 0, -1,
|
||||
SpellFinished(aabonuses.SkillAttackProc[2], other, EQEmu::spells::CastingSlot::Item, 0, -1,
|
||||
spells[aabonuses.SkillAttackProc[2]].ResistDiff);
|
||||
}
|
||||
other->Damage(this, my_hit.damage_done, SPELL_UNKNOWN, my_hit.skill, true, -1, false, m_specialattacks);
|
||||
@@ -1789,7 +1794,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQEmu::skills::Sk
|
||||
//this generates a lot of 'updates' to the client that the client does not need
|
||||
BuffFadeNonPersistDeath();
|
||||
if (RuleB(Character, UnmemSpellsOnDeath)) {
|
||||
if ((ClientVersionBit() & EQEmu::versions::bit_SoFAndLater) && RuleB(Character, RespawnFromHover))
|
||||
if ((ClientVersionBit() & EQEmu::versions::maskSoFAndLater) && RuleB(Character, RespawnFromHover))
|
||||
UnmemSpellAll(true);
|
||||
else
|
||||
UnmemSpellAll(false);
|
||||
@@ -1852,7 +1857,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQEmu::skills::Sk
|
||||
from these and overwrite what we set in pp anyway
|
||||
*/
|
||||
|
||||
if (LeftCorpse && (ClientVersionBit() & EQEmu::versions::bit_SoFAndLater) && RuleB(Character, RespawnFromHover))
|
||||
if (LeftCorpse && (ClientVersionBit() & EQEmu::versions::maskSoFAndLater) && RuleB(Character, RespawnFromHover))
|
||||
{
|
||||
ClearDraggedCorpses();
|
||||
RespawnFromHoverTimer.Start(RuleI(Character, RespawnFromHoverTimer) * 1000);
|
||||
@@ -1925,28 +1930,28 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
||||
my_hit.skill = EQEmu::skills::SkillHandtoHand;
|
||||
my_hit.hand = Hand;
|
||||
my_hit.damage_done = 1;
|
||||
if (Hand == EQEmu::inventory::slotPrimary) {
|
||||
if (Hand == EQEmu::invslot::slotPrimary) {
|
||||
my_hit.skill = static_cast<EQEmu::skills::SkillType>(GetPrimSkill());
|
||||
OffHandAtk(false);
|
||||
}
|
||||
if (Hand == EQEmu::inventory::slotSecondary) {
|
||||
if (Hand == EQEmu::invslot::slotSecondary) {
|
||||
my_hit.skill = static_cast<EQEmu::skills::SkillType>(GetSecSkill());
|
||||
OffHandAtk(true);
|
||||
}
|
||||
|
||||
//figure out what weapon they are using, if any
|
||||
const EQEmu::ItemData* weapon = nullptr;
|
||||
if (Hand == EQEmu::inventory::slotPrimary && equipment[EQEmu::inventory::slotPrimary] > 0)
|
||||
weapon = database.GetItem(equipment[EQEmu::inventory::slotPrimary]);
|
||||
else if (equipment[EQEmu::inventory::slotSecondary])
|
||||
weapon = database.GetItem(equipment[EQEmu::inventory::slotSecondary]);
|
||||
if (Hand == EQEmu::invslot::slotPrimary && equipment[EQEmu::invslot::slotPrimary] > 0)
|
||||
weapon = database.GetItem(equipment[EQEmu::invslot::slotPrimary]);
|
||||
else if (equipment[EQEmu::invslot::slotSecondary])
|
||||
weapon = database.GetItem(equipment[EQEmu::invslot::slotSecondary]);
|
||||
|
||||
//We dont factor much from the weapon into the attack.
|
||||
//Just the skill type so it doesn't look silly using punching animations and stuff while wielding weapons
|
||||
if (weapon) {
|
||||
Log(Logs::Detail, Logs::Combat, "Attacking with weapon: %s (%d) (too bad im not using it for much)", weapon->Name, weapon->ID);
|
||||
|
||||
if (Hand == EQEmu::inventory::slotSecondary && weapon->ItemType == EQEmu::item::ItemTypeShield) {
|
||||
if (Hand == EQEmu::invslot::slotSecondary && weapon->ItemType == EQEmu::item::ItemTypeShield) {
|
||||
Log(Logs::Detail, Logs::Combat, "Attack with shield canceled.");
|
||||
return false;
|
||||
}
|
||||
@@ -1998,14 +2003,17 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
||||
//if NPCs can't inheriently hit the target we don't add bane/magic dmg which isn't exactly the same as PCs
|
||||
int eleBane = 0;
|
||||
if (weapon) {
|
||||
if (weapon->BaneDmgBody == other->GetBodyType()) {
|
||||
eleBane += weapon->BaneDmgAmt;
|
||||
}
|
||||
|
||||
if (weapon->BaneDmgRace == other->GetRace()) {
|
||||
eleBane += weapon->BaneDmgRaceAmt;
|
||||
if (RuleB(NPC, UseBaneDamage)) {
|
||||
if (weapon->BaneDmgBody == other->GetBodyType()) {
|
||||
eleBane += weapon->BaneDmgAmt;
|
||||
}
|
||||
|
||||
if (weapon->BaneDmgRace == other->GetRace()) {
|
||||
eleBane += weapon->BaneDmgRaceAmt;
|
||||
}
|
||||
}
|
||||
|
||||
// I don't think NPCs use this either ....
|
||||
if (weapon->ElemDmgAmt) {
|
||||
eleBane += (weapon->ElemDmgAmt * other->ResistSpell(weapon->ElemDmgType, 0, this) / 100);
|
||||
}
|
||||
@@ -2122,7 +2130,7 @@ void NPC::Damage(Mob* other, int32 damage, uint16 spell_id, EQEmu::skills::Skill
|
||||
if (IsLDoNTrapped())
|
||||
{
|
||||
Message_StringID(13, LDON_ACCIDENT_SETOFF2);
|
||||
SpellFinished(GetLDoNTrapSpellID(), other, EQEmu::CastingSlot::Item, 0, -1, spells[GetLDoNTrapSpellID()].ResistDiff, false);
|
||||
SpellFinished(GetLDoNTrapSpellID(), other, EQEmu::spells::CastingSlot::Item, 0, -1, spells[GetLDoNTrapSpellID()].ResistDiff, false);
|
||||
SetLDoNTrapSpellID(0);
|
||||
SetLDoNTrapped(false);
|
||||
SetLDoNTrapDetected(false);
|
||||
@@ -2662,12 +2670,6 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsNPC() && CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
|
||||
if (!zone->watermap->InLiquid(glm::vec3(other->GetPosition()))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// first add self
|
||||
|
||||
// The damage on the hate list is used to award XP to the killer. This check is to prevent Killstealing.
|
||||
@@ -2689,16 +2691,24 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
||||
|
||||
#ifdef BOTS
|
||||
// if other is a bot, add the bots client to the hate list
|
||||
if (other->IsBot()) {
|
||||
if (other->CastToBot()->GetBotOwner() && other->CastToBot()->GetBotOwner()->CastToClient()->GetFeigned()) {
|
||||
AddFeignMemory(other->CastToBot()->GetBotOwner()->CastToClient());
|
||||
while (other->IsBot()) {
|
||||
auto other_ = other->CastToBot();
|
||||
if (!other_ || !other_->GetBotOwner())
|
||||
break;
|
||||
|
||||
auto owner_ = other_->GetBotOwner()->CastToClient();
|
||||
if (!owner_ || owner_->IsDead() || !owner_->InZone()) // added isdead and inzone checks to avoid issues in AddAutoXTarget(...) below
|
||||
break;
|
||||
|
||||
if (owner_->GetFeigned()) {
|
||||
AddFeignMemory(owner_);
|
||||
}
|
||||
else {
|
||||
if (!hate_list.IsEntOnHateList(other->CastToBot()->GetBotOwner())) {
|
||||
hate_list.AddEntToHateList(other->CastToBot()->GetBotOwner(), 0, 0, false, true);
|
||||
other->CastToBot()->GetBotOwner()->CastToClient()->AddAutoXTarget(this);
|
||||
}
|
||||
else if (!hate_list.IsEntOnHateList(owner_)) {
|
||||
hate_list.AddEntToHateList(owner_, 0, 0, false, true);
|
||||
owner_->AddAutoXTarget(this); // this was being called on dead/out-of-zone clients
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
#endif //BOTS
|
||||
|
||||
@@ -2710,6 +2720,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
||||
else {
|
||||
if (!hate_list.IsEntOnHateList(other->CastToMerc()->GetMercOwner()))
|
||||
hate_list.AddEntToHateList(other->CastToMerc()->GetMercOwner(), 0, 0, false, true);
|
||||
// if mercs are reworked to include adding 'this' to owner's xtarget list, this should reflect bots code above
|
||||
}
|
||||
} //MERC
|
||||
|
||||
@@ -3363,6 +3374,12 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
|
||||
damage = DMG_INVULNERABLE;
|
||||
}
|
||||
|
||||
// this should actually happen MUCH sooner, need to investigate though -- good enough for now
|
||||
if ((skill_used == EQEmu::skills::SkillArchery || skill_used == EQEmu::skills::SkillThrowing) && GetSpecialAbility(IMMUNE_RANGED_ATTACKS)) {
|
||||
Log(Logs::Detail, Logs::Combat, "Avoiding %d damage due to IMMUNE_RANGED_ATTACKS.", damage);
|
||||
damage = DMG_INVULNERABLE;
|
||||
}
|
||||
|
||||
if (spell_id != SPELL_UNKNOWN || attacker == nullptr)
|
||||
avoidable = false;
|
||||
|
||||
@@ -3605,26 +3622,21 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
|
||||
a->special = 2;
|
||||
else
|
||||
a->special = 0;
|
||||
a->meleepush_xy = attacker ? attacker->GetHeading() * 2.0f : 0.0f;
|
||||
a->hit_heading = attacker ? attacker->GetHeading() : 0.0f;
|
||||
if (RuleB(Combat, MeleePush) && damage > 0 && !IsRooted() &&
|
||||
(IsClient() || zone->random.Roll(RuleI(Combat, MeleePushChance)))) {
|
||||
a->force = EQEmu::skills::GetSkillMeleePushForce(skill_used);
|
||||
// update NPC stuff
|
||||
auto new_pos = glm::vec3(m_Position.x + (a->force * std::sin(a->meleepush_xy) + m_Delta.x),
|
||||
m_Position.y + (a->force * std::cos(a->meleepush_xy) + m_Delta.y), m_Position.z);
|
||||
if (zone->zonemap && zone->zonemap->CheckLoS(glm::vec3(m_Position), new_pos)) { // If we have LoS on the new loc it should be reachable.
|
||||
if (IsNPC()) {
|
||||
// Is this adequate?
|
||||
|
||||
Teleport(new_pos);
|
||||
if (position_update_melee_push_timer.Check()) {
|
||||
SendPositionUpdate();
|
||||
}
|
||||
if (IsNPC()) {
|
||||
if (attacker->IsNPC())
|
||||
a->force = 0.0f; // 2013 change that disabled NPC vs NPC push
|
||||
else
|
||||
a->force *= 0.10f; // force against NPCs is divided by 10 I guess? ex bash is 0.3, parsed 0.03 against an NPC
|
||||
if (ForcedMovement == 0 && a->force != 0.0f && position_update_melee_push_timer.Check()) {
|
||||
m_Delta.x += a->force * g_Math.FastSin(a->hit_heading);
|
||||
m_Delta.y += a->force * g_Math.FastCos(a->hit_heading);
|
||||
ForcedMovement = 3;
|
||||
}
|
||||
}
|
||||
else {
|
||||
a->force = 0.0f; // we couldn't move there, so lets not
|
||||
}
|
||||
}
|
||||
|
||||
//Note: if players can become pets, they will not receive damage messages of their own
|
||||
@@ -3779,7 +3791,7 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id)
|
||||
if (IsBuffSpell(spell_id)) { // hots
|
||||
// message to caster
|
||||
if (caster->IsClient() && caster == this) {
|
||||
if (caster->CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoFAndLater)
|
||||
if (caster->CastToClient()->ClientVersionBit() & EQEmu::versions::maskSoFAndLater)
|
||||
FilteredMessage_StringID(caster, MT_NonMelee, FilterHealOverTime,
|
||||
HOT_HEAL_SELF, itoa(acthealed), spells[spell_id].name);
|
||||
else
|
||||
@@ -3787,7 +3799,7 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id)
|
||||
YOU_HEALED, GetCleanName(), itoa(acthealed));
|
||||
}
|
||||
else if (caster->IsClient() && caster != this) {
|
||||
if (caster->CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoFAndLater)
|
||||
if (caster->CastToClient()->ClientVersionBit() & EQEmu::versions::maskSoFAndLater)
|
||||
caster->FilteredMessage_StringID(caster, MT_NonMelee, FilterHealOverTime,
|
||||
HOT_HEAL_OTHER, GetCleanName(), itoa(acthealed),
|
||||
spells[spell_id].name);
|
||||
@@ -3797,7 +3809,7 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id)
|
||||
}
|
||||
// message to target
|
||||
if (IsClient() && caster != this) {
|
||||
if (CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoFAndLater)
|
||||
if (CastToClient()->ClientVersionBit() & EQEmu::versions::maskSoFAndLater)
|
||||
FilteredMessage_StringID(this, MT_NonMelee, FilterHealOverTime,
|
||||
HOT_HEALED_OTHER, caster->GetCleanName(),
|
||||
itoa(acthealed), spells[spell_id].name);
|
||||
@@ -3890,7 +3902,7 @@ void Mob::TryDefensiveProc(Mob *on, uint16 hand) {
|
||||
float ProcChance, ProcBonus;
|
||||
on->GetDefensiveProcChances(ProcBonus, ProcChance, hand, this);
|
||||
|
||||
if (hand != EQEmu::inventory::slotPrimary)
|
||||
if (hand != EQEmu::invslot::slotPrimary)
|
||||
ProcChance /= 2;
|
||||
|
||||
int level_penalty = 0;
|
||||
@@ -3963,7 +3975,7 @@ void Mob::TryWeaponProc(const EQEmu::ItemInstance *inst, const EQEmu::ItemData *
|
||||
ProcBonus += static_cast<float>(itembonuses.ProcChance) / 10.0f; // Combat Effects
|
||||
float ProcChance = GetProcChances(ProcBonus, hand);
|
||||
|
||||
if (hand != EQEmu::inventory::slotPrimary) //Is Archery intened to proc at 50% rate?
|
||||
if (hand != EQEmu::invslot::slotPrimary) //Is Archery intened to proc at 50% rate?
|
||||
ProcChance /= 2;
|
||||
|
||||
// Try innate proc on weapon
|
||||
@@ -4002,7 +4014,7 @@ void Mob::TryWeaponProc(const EQEmu::ItemInstance *inst, const EQEmu::ItemData *
|
||||
proced = false;
|
||||
|
||||
if (!proced && inst) {
|
||||
for (int r = EQEmu::inventory::socketBegin; r < EQEmu::inventory::SocketCount; r++) {
|
||||
for (int r = EQEmu::invaug::SOCKET_BEGIN; r <= EQEmu::invaug::SOCKET_END; r++) {
|
||||
const EQEmu::ItemInstance *aug_i = inst->GetAugment(r);
|
||||
if (!aug_i) // no aug, try next slot!
|
||||
continue;
|
||||
@@ -4045,11 +4057,11 @@ void Mob::TrySpellProc(const EQEmu::ItemInstance *inst, const EQEmu::ItemData *w
|
||||
float ProcChance = 0.0f;
|
||||
ProcChance = GetProcChances(ProcBonus, hand);
|
||||
|
||||
if (hand != EQEmu::inventory::slotPrimary) //Is Archery intened to proc at 50% rate?
|
||||
if (hand != EQEmu::invslot::slotPrimary) //Is Archery intened to proc at 50% rate?
|
||||
ProcChance /= 2;
|
||||
|
||||
bool rangedattk = false;
|
||||
if (weapon && hand == EQEmu::inventory::slotRange) {
|
||||
if (weapon && hand == EQEmu::invslot::slotRange) {
|
||||
if (weapon->ItemType == EQEmu::item::ItemTypeArrow ||
|
||||
weapon->ItemType == EQEmu::item::ItemTypeLargeThrowing ||
|
||||
weapon->ItemType == EQEmu::item::ItemTypeSmallThrowing ||
|
||||
@@ -4058,11 +4070,11 @@ void Mob::TrySpellProc(const EQEmu::ItemInstance *inst, const EQEmu::ItemData *w
|
||||
}
|
||||
}
|
||||
|
||||
if (!weapon && hand == EQEmu::inventory::slotRange && GetSpecialAbility(SPECATK_RANGED_ATK))
|
||||
if (!weapon && hand == EQEmu::invslot::slotRange && GetSpecialAbility(SPECATK_RANGED_ATK))
|
||||
rangedattk = true;
|
||||
|
||||
for (uint32 i = 0; i < MAX_PROCS; i++) {
|
||||
if (IsPet() && hand != EQEmu::inventory::slotPrimary) //Pets can only proc spell procs from their primay hand (ie; beastlord pets)
|
||||
if (IsPet() && hand != EQEmu::invslot::slotPrimary) //Pets can only proc spell procs from their primay hand (ie; beastlord pets)
|
||||
continue; // If pets ever can proc from off hand, this will need to change
|
||||
|
||||
// Not ranged
|
||||
@@ -4122,7 +4134,7 @@ void Mob::TrySpellProc(const EQEmu::ItemInstance *inst, const EQEmu::ItemData *w
|
||||
}
|
||||
}
|
||||
|
||||
if (HasSkillProcs() && hand != EQEmu::inventory::slotRange) { //We check ranged skill procs within the attack functions.
|
||||
if (HasSkillProcs() && hand != EQEmu::invslot::slotRange) { //We check ranged skill procs within the attack functions.
|
||||
uint16 skillinuse = 28;
|
||||
if (weapon)
|
||||
skillinuse = GetSkillByItemType(weapon->ItemType);
|
||||
@@ -4439,7 +4451,13 @@ void Mob::DoRiposte(Mob *defender)
|
||||
if (!defender)
|
||||
return;
|
||||
|
||||
defender->Attack(this, EQEmu::inventory::slotPrimary, true);
|
||||
// so ahhh the angle you can riposte is larger than the angle you can hit :P
|
||||
if (!defender->IsFacingMob(this)) {
|
||||
defender->Message_StringID(MT_TooFarAway, CANT_SEE_TARGET);
|
||||
return;
|
||||
}
|
||||
|
||||
defender->Attack(this, EQEmu::invslot::slotPrimary, true);
|
||||
if (HasDied())
|
||||
return;
|
||||
|
||||
@@ -4450,7 +4468,7 @@ void Mob::DoRiposte(Mob *defender)
|
||||
if (DoubleRipChance && zone->random.Roll(DoubleRipChance)) {
|
||||
Log(Logs::Detail, Logs::Combat,
|
||||
"Preforming a double riposted from SE_DoubleRiposte (%d percent chance)", DoubleRipChance);
|
||||
defender->Attack(this, EQEmu::inventory::slotPrimary, true);
|
||||
defender->Attack(this, EQEmu::invslot::slotPrimary, true);
|
||||
if (HasDied())
|
||||
return;
|
||||
}
|
||||
@@ -4463,7 +4481,7 @@ void Mob::DoRiposte(Mob *defender)
|
||||
Log(Logs::Detail, Logs::Combat,
|
||||
"Preforming a double riposted from SE_GiveDoubleRiposte base1 == 0 (%d percent chance)",
|
||||
DoubleRipChance);
|
||||
defender->Attack(this, EQEmu::inventory::slotPrimary, true);
|
||||
defender->Attack(this, EQEmu::invslot::slotPrimary, true);
|
||||
if (HasDied())
|
||||
return;
|
||||
}
|
||||
@@ -4496,7 +4514,9 @@ void Mob::ApplyMeleeDamageMods(uint16 skill, int &damage, Mob *defender, ExtraAt
|
||||
if (defender->IsClient() && defender->GetClass() == WARRIOR)
|
||||
dmgbonusmod -= 5;
|
||||
// 168 defensive
|
||||
dmgbonusmod += (defender->spellbonuses.MeleeMitigationEffect + itembonuses.MeleeMitigationEffect + aabonuses.MeleeMitigationEffect);
|
||||
dmgbonusmod += (defender->spellbonuses.MeleeMitigationEffect +
|
||||
defender->itembonuses.MeleeMitigationEffect +
|
||||
defender->aabonuses.MeleeMitigationEffect);
|
||||
}
|
||||
|
||||
damage += damage * dmgbonusmod / 100;
|
||||
@@ -4876,7 +4896,7 @@ float Mob::GetSkillProcChances(uint16 ReuseTime, uint16 hand) {
|
||||
if (!ReuseTime && hand) {
|
||||
weapon_speed = GetWeaponSpeedbyHand(hand);
|
||||
ProcChance = static_cast<float>(weapon_speed) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f);
|
||||
if (hand != EQEmu::inventory::slotPrimary)
|
||||
if (hand != EQEmu::invslot::slotPrimary)
|
||||
ProcChance /= 2;
|
||||
}
|
||||
|
||||
@@ -5020,7 +5040,7 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
|
||||
hit.damage_done = headshot;
|
||||
}
|
||||
else if (GetClass() == RANGER && GetLevel() > 50) { // no double dmg on headshot
|
||||
if (defender->IsNPC() && !defender->IsMoving() && !defender->IsRooted()) {
|
||||
if ((defender->IsNPC() && !defender->IsMoving() && !defender->IsRooted()) || !RuleB(Combat, ArcheryBonusRequiresStationary)) {
|
||||
hit.damage_done *= 2;
|
||||
Message_StringID(MT_CritMelee, BOW_DOUBLE_DAMAGE);
|
||||
}
|
||||
@@ -5170,13 +5190,13 @@ void Client::SetAttackTimer()
|
||||
|
||||
Timer *TimerToUse = nullptr;
|
||||
|
||||
for (int i = EQEmu::inventory::slotRange; i <= EQEmu::inventory::slotSecondary; i++) {
|
||||
for (int i = EQEmu::invslot::slotRange; i <= EQEmu::invslot::slotSecondary; i++) {
|
||||
//pick a timer
|
||||
if (i == EQEmu::inventory::slotPrimary)
|
||||
if (i == EQEmu::invslot::slotPrimary)
|
||||
TimerToUse = &attack_timer;
|
||||
else if (i == EQEmu::inventory::slotRange)
|
||||
else if (i == EQEmu::invslot::slotRange)
|
||||
TimerToUse = &ranged_timer;
|
||||
else if (i == EQEmu::inventory::slotSecondary)
|
||||
else if (i == EQEmu::invslot::slotSecondary)
|
||||
TimerToUse = &attack_dw_timer;
|
||||
else //invalid slot (hands will always hit this)
|
||||
continue;
|
||||
@@ -5189,7 +5209,7 @@ void Client::SetAttackTimer()
|
||||
ItemToUse = ci->GetItem();
|
||||
|
||||
//special offhand stuff
|
||||
if (i == EQEmu::inventory::slotSecondary) {
|
||||
if (i == EQEmu::invslot::slotSecondary) {
|
||||
//if we cant dual wield, skip it
|
||||
if (!CanThisClassDualWield() || HasTwoHanderEquipped()) {
|
||||
attack_dw_timer.Disable();
|
||||
@@ -5264,19 +5284,19 @@ void NPC::SetAttackTimer()
|
||||
else
|
||||
speed = static_cast<int>((attack_delay / haste_mod) + ((hhe / 100.0f) * attack_delay));
|
||||
|
||||
for (int i = EQEmu::inventory::slotRange; i <= EQEmu::inventory::slotSecondary; i++) {
|
||||
for (int i = EQEmu::invslot::slotRange; i <= EQEmu::invslot::slotSecondary; i++) {
|
||||
//pick a timer
|
||||
if (i == EQEmu::inventory::slotPrimary)
|
||||
if (i == EQEmu::invslot::slotPrimary)
|
||||
TimerToUse = &attack_timer;
|
||||
else if (i == EQEmu::inventory::slotRange)
|
||||
else if (i == EQEmu::invslot::slotRange)
|
||||
TimerToUse = &ranged_timer;
|
||||
else if (i == EQEmu::inventory::slotSecondary)
|
||||
else if (i == EQEmu::invslot::slotSecondary)
|
||||
TimerToUse = &attack_dw_timer;
|
||||
else //invalid slot (hands will always hit this)
|
||||
continue;
|
||||
|
||||
//special offhand stuff
|
||||
if (i == EQEmu::inventory::slotSecondary) {
|
||||
if (i == EQEmu::invslot::slotSecondary) {
|
||||
// SPECATK_QUAD is uncheesable
|
||||
if (!CanThisClassDualWield() || (HasTwoHanderEquipped() && !GetSpecialAbility(SPECATK_QUAD))) {
|
||||
attack_dw_timer.Disable();
|
||||
@@ -5298,7 +5318,7 @@ void Client::DoAttackRounds(Mob *target, int hand, bool IsFromSpell)
|
||||
bool candouble = CanThisClassDoubleAttack();
|
||||
// extra off hand non-sense, can only double with skill of 150 or above
|
||||
// or you have any amount of GiveDoubleAttack
|
||||
if (candouble && hand == EQEmu::inventory::slotSecondary)
|
||||
if (candouble && hand == EQEmu::invslot::slotSecondary)
|
||||
candouble =
|
||||
GetSkill(EQEmu::skills::SkillDoubleAttack) > 149 ||
|
||||
(aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack) > 0;
|
||||
@@ -5309,7 +5329,7 @@ void Client::DoAttackRounds(Mob *target, int hand, bool IsFromSpell)
|
||||
Attack(target, hand, false, false, IsFromSpell);
|
||||
|
||||
// Modern AA description: Increases your chance of ... performing one additional hit with a 2-handed weapon when double attacking by 2%.
|
||||
if (hand == EQEmu::inventory::slotPrimary) {
|
||||
if (hand == EQEmu::invslot::slotPrimary) {
|
||||
auto extraattackchance = aabonuses.ExtraAttackChance + spellbonuses.ExtraAttackChance +
|
||||
itembonuses.ExtraAttackChance;
|
||||
if (extraattackchance && HasTwoHanderEquipped() && zone->random.Roll(extraattackchance))
|
||||
@@ -5317,7 +5337,7 @@ void Client::DoAttackRounds(Mob *target, int hand, bool IsFromSpell)
|
||||
}
|
||||
|
||||
// you can only triple from the main hand
|
||||
if (hand == EQEmu::inventory::slotPrimary && CanThisClassTripleAttack()) {
|
||||
if (hand == EQEmu::invslot::slotPrimary && CanThisClassTripleAttack()) {
|
||||
CheckIncreaseSkill(EQEmu::skills::SkillTripleAttack, target, -10);
|
||||
if (CheckTripleAttack()) {
|
||||
Attack(target, hand, false, false, IsFromSpell);
|
||||
@@ -5371,9 +5391,9 @@ void Mob::DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
|
||||
if (RuleB(Combat, UseLiveCombatRounds)) {
|
||||
// A "quad" on live really is just a successful dual wield where both double attack
|
||||
// The mobs that could triple lost the ability to when the triple attack skill was added in
|
||||
Attack(target, EQEmu::inventory::slotPrimary, false, false, false, opts);
|
||||
Attack(target, EQEmu::invslot::slotPrimary, false, false, false, opts);
|
||||
if (CanThisClassDoubleAttack() && CheckDoubleAttack()) {
|
||||
Attack(target, EQEmu::inventory::slotPrimary, false, false, false, opts);
|
||||
Attack(target, EQEmu::invslot::slotPrimary, false, false, false, opts);
|
||||
if ((IsPet() || IsTempPet()) && IsPetOwnerClient()) {
|
||||
int chance = spellbonuses.PC_Pet_Flurry + itembonuses.PC_Pet_Flurry + aabonuses.PC_Pet_Flurry;
|
||||
if (chance && zone->random.Roll(chance))
|
||||
@@ -5386,16 +5406,16 @@ void Mob::DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
|
||||
if (IsNPC()) {
|
||||
int16 n_atk = CastToNPC()->GetNumberOfAttacks();
|
||||
if (n_atk <= 1) {
|
||||
Attack(target, EQEmu::inventory::slotPrimary, false, false, false, opts);
|
||||
Attack(target, EQEmu::invslot::slotPrimary, false, false, false, opts);
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < n_atk; ++i) {
|
||||
Attack(target, EQEmu::inventory::slotPrimary, false, false, false, opts);
|
||||
Attack(target, EQEmu::invslot::slotPrimary, false, false, false, opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Attack(target, EQEmu::inventory::slotPrimary, false, false, false, opts);
|
||||
Attack(target, EQEmu::invslot::slotPrimary, false, false, false, opts);
|
||||
}
|
||||
|
||||
// we use this random value in three comparisons with different
|
||||
@@ -5406,15 +5426,15 @@ void Mob::DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
|
||||
// check double attack, this is NOT the same rules that clients use...
|
||||
&&
|
||||
RandRoll < (GetLevel() + NPCDualAttackModifier)) {
|
||||
Attack(target, EQEmu::inventory::slotPrimary, false, false, false, opts);
|
||||
Attack(target, EQEmu::invslot::slotPrimary, false, false, false, opts);
|
||||
// lets see if we can do a triple attack with the main hand
|
||||
// pets are excluded from triple and quads...
|
||||
if ((GetSpecialAbility(SPECATK_TRIPLE) || GetSpecialAbility(SPECATK_QUAD)) && !IsPet() &&
|
||||
RandRoll < (GetLevel() + NPCTripleAttackModifier)) {
|
||||
Attack(target, EQEmu::inventory::slotPrimary, false, false, false, opts);
|
||||
Attack(target, EQEmu::invslot::slotPrimary, false, false, false, opts);
|
||||
// now lets check the quad attack
|
||||
if (GetSpecialAbility(SPECATK_QUAD) && RandRoll < (GetLevel() + NPCQuadAttackModifier)) {
|
||||
Attack(target, EQEmu::inventory::slotPrimary, false, false, false, opts);
|
||||
Attack(target, EQEmu::invslot::slotPrimary, false, false, false, opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5428,11 +5448,11 @@ void Mob::DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
|
||||
// For now, SPECATK_QUAD means innate DW when Combat:UseLiveCombatRounds is true
|
||||
if ((GetSpecialAbility(SPECATK_INNATE_DW) ||
|
||||
(RuleB(Combat, UseLiveCombatRounds) && GetSpecialAbility(SPECATK_QUAD))) ||
|
||||
GetEquipment(EQEmu::textures::weaponSecondary) != 0) {
|
||||
GetEquippedItemFromTextureSlot(EQEmu::textures::weaponSecondary) != 0) {
|
||||
if (CheckDualWield()) {
|
||||
Attack(target, EQEmu::inventory::slotSecondary, false, false, false, opts);
|
||||
Attack(target, EQEmu::invslot::slotSecondary, false, false, false, opts);
|
||||
if (CanThisClassDoubleAttack() && GetLevel() > 35 && CheckDoubleAttack()) {
|
||||
Attack(target, EQEmu::inventory::slotSecondary, false, false, false, opts);
|
||||
Attack(target, EQEmu::invslot::slotSecondary, false, false, false, opts);
|
||||
|
||||
if ((IsPet() || IsTempPet()) && IsPetOwnerClient()) {
|
||||
int chance = spellbonuses.PC_Pet_Flurry + itembonuses.PC_Pet_Flurry + aabonuses.PC_Pet_Flurry;
|
||||
@@ -5443,3 +5463,21 @@ void Mob::DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Mob::GetWasSpawnedInWater() const {
|
||||
return spawned_in_water;
|
||||
}
|
||||
|
||||
void Mob::SetSpawnedInWater(bool spawned_in_water) {
|
||||
Mob::spawned_in_water = spawned_in_water;
|
||||
}
|
||||
|
||||
int32 Mob::GetHPRegen() const
|
||||
{
|
||||
return hp_regen;
|
||||
}
|
||||
|
||||
int32 Mob::GetManaRegen() const
|
||||
{
|
||||
return mana_regen;
|
||||
}
|
||||
|
||||
+5
-2
@@ -6,8 +6,8 @@
|
||||
#include "raids.h"
|
||||
|
||||
Aura::Aura(NPCType *type_data, Mob *owner, AuraRecord &record)
|
||||
: NPC(type_data, 0, owner->GetPosition(), FlyMode3), spell_id(record.spell_id), distance(record.distance),
|
||||
remove_timer(record.duration), movement_timer(100), process_timer(100), aura_id(-1)
|
||||
: NPC(type_data, 0, owner->GetPosition(), GravityBehavior::Flying), spell_id(record.spell_id), distance(record.distance),
|
||||
remove_timer(record.duration), movement_timer(100), process_timer(1000), aura_id(-1)
|
||||
{
|
||||
GiveNPCTypeData(type_data); // we will delete this later on
|
||||
m_owner = owner->GetID();
|
||||
@@ -616,6 +616,7 @@ bool Aura::Process()
|
||||
it = spawned_for.erase(it);
|
||||
}
|
||||
}
|
||||
safe_delete(app);
|
||||
}
|
||||
// TODO: waypoints?
|
||||
|
||||
@@ -757,6 +758,8 @@ void Mob::MakeAura(uint16 spell_id)
|
||||
|
||||
auto npc = new Aura(npc_type, this, record);
|
||||
npc->SetAuraID(spell_id);
|
||||
if (trap)
|
||||
npc->TryMoveAlong(5.0f, 0.0f, false); // try to place 5 units in front
|
||||
entity_list.AddNPC(npc, false);
|
||||
|
||||
if (trap)
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ Beacon::Beacon(Mob *at_mob, int lifetime)
|
||||
:Mob
|
||||
(
|
||||
nullptr, nullptr, 0, 0, 0, INVISIBLE_MAN, 0, BT_NoTarget, 0, 0, 0, 0, 0, at_mob->GetPosition(), 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EQEmu::TintProfile(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EQEmu::TintProfile(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
),
|
||||
remove_timer(lifetime),
|
||||
spell_timer(0)
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ public:
|
||||
//abstract virtual function implementations requird by base abstract class
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) { return true; }
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) { return; }
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
||||
ExtraAttackOptions *opts = nullptr) { return false; }
|
||||
virtual bool HasRaid() { return false; }
|
||||
virtual bool HasGroup() { return false; }
|
||||
|
||||
+47
-64
@@ -52,22 +52,18 @@ void Mob::CalcBonuses()
|
||||
We set this here because NPC's can cast spells to change walkspeed/runspeed
|
||||
*/
|
||||
float get_walk_speed = static_cast<float>(0.025f * this->GetWalkspeed());
|
||||
if (get_walk_speed >= 0.9 && this->fix_z_timer.GetDuration() != 100) {
|
||||
this->fix_z_timer.SetTimer(100);
|
||||
}
|
||||
|
||||
rooted = FindType(SE_Root);
|
||||
}
|
||||
|
||||
void NPC::CalcBonuses()
|
||||
{
|
||||
memset(&itembonuses, 0, sizeof(StatBonuses));
|
||||
if(RuleB(NPC, UseItemBonusesForNonPets)){
|
||||
if (RuleB(NPC, UseItemBonusesForNonPets)) {
|
||||
memset(&itembonuses, 0, sizeof(StatBonuses));
|
||||
CalcItemBonuses(&itembonuses);
|
||||
}
|
||||
else{
|
||||
if(GetOwner()){
|
||||
else {
|
||||
if (GetOwner()) {
|
||||
memset(&itembonuses, 0, sizeof(StatBonuses));
|
||||
CalcItemBonuses(&itembonuses);
|
||||
}
|
||||
@@ -161,35 +157,27 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
|
||||
|
||||
unsigned int i;
|
||||
// Update: MainAmmo should only calc skill mods (TODO: Check for other cases)
|
||||
for (i = EQEmu::inventory::slotCharm; i <= EQEmu::inventory::slotAmmo; i++) {
|
||||
for (i = EQEmu::invslot::BONUS_BEGIN; i <= EQEmu::invslot::BONUS_SKILL_END; i++) {
|
||||
const EQEmu::ItemInstance* inst = m_inv[i];
|
||||
if(inst == 0)
|
||||
continue;
|
||||
AddItemBonuses(inst, newbon, false, false, 0, (i == EQEmu::inventory::slotAmmo));
|
||||
AddItemBonuses(inst, newbon, false, false, 0, (i == EQEmu::invslot::slotAmmo));
|
||||
|
||||
//These are given special flags due to how often they are checked for various spell effects.
|
||||
const EQEmu::ItemData *item = inst->GetItem();
|
||||
if (i == EQEmu::inventory::slotSecondary && (item && item->ItemType == EQEmu::item::ItemTypeShield))
|
||||
if (i == EQEmu::invslot::slotSecondary && (item && item->ItemType == EQEmu::item::ItemTypeShield))
|
||||
SetShieldEquiped(true);
|
||||
else if (i == EQEmu::inventory::slotPrimary && (item && item->ItemType == EQEmu::item::ItemType2HBlunt)) {
|
||||
else if (i == EQEmu::invslot::slotPrimary && (item && item->ItemType == EQEmu::item::ItemType2HBlunt)) {
|
||||
SetTwoHandBluntEquiped(true);
|
||||
SetTwoHanderEquipped(true);
|
||||
}
|
||||
else if (i == EQEmu::inventory::slotPrimary && (item && (item->ItemType == EQEmu::item::ItemType2HSlash || item->ItemType == EQEmu::item::ItemType2HPiercing)))
|
||||
else if (i == EQEmu::invslot::slotPrimary && (item && (item->ItemType == EQEmu::item::ItemType2HSlash || item->ItemType == EQEmu::item::ItemType2HPiercing)))
|
||||
SetTwoHanderEquipped(true);
|
||||
}
|
||||
|
||||
//Power Source Slot
|
||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF)
|
||||
{
|
||||
const EQEmu::ItemInstance* inst = m_inv[EQEmu::inventory::slotPowerSource];
|
||||
if(inst)
|
||||
AddItemBonuses(inst, newbon);
|
||||
}
|
||||
|
||||
//tribute items
|
||||
for (i = 0; i < EQEmu::legacy::TRIBUTE_SIZE; i++) {
|
||||
const EQEmu::ItemInstance* inst = m_inv[EQEmu::legacy::TRIBUTE_BEGIN + i];
|
||||
for (i = EQEmu::invslot::TRIBUTE_BEGIN; i <= EQEmu::invslot::TRIBUTE_END; i++) {
|
||||
const EQEmu::ItemInstance* inst = m_inv[i];
|
||||
if(inst == 0)
|
||||
continue;
|
||||
AddItemBonuses(inst, newbon, false, true);
|
||||
@@ -197,7 +185,7 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
|
||||
|
||||
//Optional ability to have worn effects calculate as an addititive bonus instead of highest value
|
||||
if (RuleI(Spells, AdditiveBonusWornType) && RuleI(Spells, AdditiveBonusWornType) != EQEmu::item::ItemEffectWorn){
|
||||
for (i = EQEmu::inventory::slotCharm; i < EQEmu::inventory::slotAmmo; i++) {
|
||||
for (i = EQEmu::invslot::BONUS_BEGIN; i <= EQEmu::invslot::BONUS_STAT_END; i++) {
|
||||
const EQEmu::ItemInstance* inst = m_inv[i];
|
||||
if(inst == 0)
|
||||
continue;
|
||||
@@ -543,7 +531,7 @@ void Client::AddItemBonuses(const EQEmu::ItemInstance *inst, StatBonuses *newbon
|
||||
}
|
||||
|
||||
if (!isAug) {
|
||||
for (int i = EQEmu::inventory::socketBegin; i < EQEmu::inventory::SocketCount; i++)
|
||||
for (int i = EQEmu::invaug::SOCKET_BEGIN; i <= EQEmu::invaug::SOCKET_END; i++)
|
||||
AddItemBonuses(inst->GetAugment(i), newbon, true, false, rec_level, ammo_slot_item);
|
||||
}
|
||||
}
|
||||
@@ -581,7 +569,7 @@ void Client::AdditiveWornBonuses(const EQEmu::ItemInstance *inst, StatBonuses* n
|
||||
if (!isAug)
|
||||
{
|
||||
int i;
|
||||
for (i = EQEmu::inventory::socketBegin; i < EQEmu::inventory::SocketCount; i++) {
|
||||
for (i = EQEmu::invaug::SOCKET_BEGIN; i <= EQEmu::invaug::SOCKET_END; i++) {
|
||||
AdditiveWornBonuses(inst->GetAugment(i),newbon,true);
|
||||
}
|
||||
}
|
||||
@@ -592,32 +580,32 @@ void Client::CalcEdibleBonuses(StatBonuses* newbon) {
|
||||
|
||||
bool food = false;
|
||||
bool drink = false;
|
||||
for (i = EQEmu::legacy::GENERAL_BEGIN; i <= EQEmu::legacy::GENERAL_BAGS_BEGIN; i++)
|
||||
for (i = EQEmu::invslot::GENERAL_BEGIN; i <= EQEmu::invslot::GENERAL_END; i++)
|
||||
{
|
||||
if (food && drink)
|
||||
break;
|
||||
const EQEmu::ItemInstance* inst = GetInv().GetItem(i);
|
||||
if (inst && inst->GetItem() && inst->IsClassCommon()) {
|
||||
const EQEmu::ItemData *item = inst->GetItem();
|
||||
if (item->ItemType == EQEmu::item::ItemTypeFood && !food)
|
||||
if (!food && item->ItemType == EQEmu::item::ItemTypeFood)
|
||||
food = true;
|
||||
else if (item->ItemType == EQEmu::item::ItemTypeDrink && !drink)
|
||||
else if (!drink && item->ItemType == EQEmu::item::ItemTypeDrink)
|
||||
drink = true;
|
||||
else
|
||||
continue;
|
||||
AddItemBonuses(inst, newbon);
|
||||
}
|
||||
}
|
||||
for (i = EQEmu::legacy::GENERAL_BAGS_BEGIN; i <= EQEmu::legacy::GENERAL_BAGS_END; i++)
|
||||
for (i = EQEmu::invbag::GENERAL_BAGS_BEGIN; i <= EQEmu::invbag::GENERAL_BAGS_END; i++)
|
||||
{
|
||||
if (food && drink)
|
||||
break;
|
||||
const EQEmu::ItemInstance* inst = GetInv().GetItem(i);
|
||||
if (inst && inst->GetItem() && inst->IsClassCommon()) {
|
||||
const EQEmu::ItemData *item = inst->GetItem();
|
||||
if (item->ItemType == EQEmu::item::ItemTypeFood && !food)
|
||||
if (!food && item->ItemType == EQEmu::item::ItemTypeFood)
|
||||
food = true;
|
||||
else if (item->ItemType == EQEmu::item::ItemTypeDrink && !drink)
|
||||
else if (!drink && item->ItemType == EQEmu::item::ItemTypeDrink)
|
||||
drink = true;
|
||||
else
|
||||
continue;
|
||||
@@ -1484,6 +1472,17 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
newbon->trap_slots += base1;
|
||||
break;
|
||||
|
||||
case SE_ForageSkill:
|
||||
newbon->GrantForage += base1;
|
||||
// we need to grant a skill point here
|
||||
// I'd rather not do this here, but whatever, probably fine
|
||||
if (IsClient()) {
|
||||
auto client = CastToClient();
|
||||
if (client->GetRawSkill(EQEmu::skills::SkillType::SkillForage) == 0)
|
||||
client->SetSkill(EQEmu::skills::SkillType::SkillForage, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
// to do
|
||||
case SE_PetDiscipline:
|
||||
break;
|
||||
@@ -1491,8 +1490,6 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
break;
|
||||
case SE_BandolierSlots:
|
||||
break;
|
||||
case SE_ForageSkill:
|
||||
break;
|
||||
case SE_SecondaryForte:
|
||||
break;
|
||||
case SE_ExtendedShielding:
|
||||
@@ -3261,7 +3258,7 @@ void NPC::CalcItemBonuses(StatBonuses *newbon)
|
||||
{
|
||||
if(newbon){
|
||||
|
||||
for (int i = 0; i < EQEmu::legacy::EQUIPMENT_SIZE; i++){
|
||||
for (int i = EQEmu::invslot::BONUS_BEGIN; i <= EQEmu::invslot::BONUS_STAT_END; i++){
|
||||
const EQEmu::ItemData *cur = database.GetItem(equipment[i]);
|
||||
if(cur){
|
||||
//basic stats
|
||||
@@ -3339,27 +3336,20 @@ void Client::CalcItemScale() {
|
||||
bool changed = false;
|
||||
|
||||
// MainAmmo excluded in helper function below
|
||||
if (CalcItemScale(EQEmu::legacy::EQUIPMENT_BEGIN, EQEmu::legacy::EQUIPMENT_END)) // original coding excluded MainAmmo (< 21)
|
||||
if (CalcItemScale(EQEmu::invslot::EQUIPMENT_BEGIN, EQEmu::invslot::EQUIPMENT_END)) // original coding excluded MainAmmo (< 21)
|
||||
changed = true;
|
||||
|
||||
if (CalcItemScale(EQEmu::legacy::GENERAL_BEGIN, EQEmu::legacy::GENERAL_END)) // original coding excluded MainCursor (< 30)
|
||||
if (CalcItemScale(EQEmu::invslot::GENERAL_BEGIN, EQEmu::invslot::GENERAL_END)) // original coding excluded MainCursor (< 30)
|
||||
changed = true;
|
||||
|
||||
// I excluded cursor bag slots here because cursor was excluded above..if this is incorrect, change 'slot_y' here to CURSOR_BAG_END
|
||||
// and 'slot_y' above to CURSOR from GENERAL_END above - or however it is supposed to be...
|
||||
if (CalcItemScale(EQEmu::legacy::GENERAL_BAGS_BEGIN, EQEmu::legacy::GENERAL_BAGS_END)) // (< 341)
|
||||
if (CalcItemScale(EQEmu::invbag::GENERAL_BAGS_BEGIN, EQEmu::invbag::GENERAL_BAGS_END)) // (< 341)
|
||||
changed = true;
|
||||
|
||||
if (CalcItemScale(EQEmu::legacy::TRIBUTE_BEGIN, EQEmu::legacy::TRIBUTE_END)) // (< 405)
|
||||
if (CalcItemScale(EQEmu::invslot::TRIBUTE_BEGIN, EQEmu::invslot::TRIBUTE_END)) // (< 405)
|
||||
changed = true;
|
||||
|
||||
//Power Source Slot
|
||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF)
|
||||
{
|
||||
if (CalcItemScale(EQEmu::inventory::slotPowerSource, EQEmu::inventory::slotPowerSource))
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if(changed)
|
||||
{
|
||||
CalcBonuses();
|
||||
@@ -3371,7 +3361,7 @@ bool Client::CalcItemScale(uint32 slot_x, uint32 slot_y) {
|
||||
bool changed = false;
|
||||
uint32 i;
|
||||
for (i = slot_x; i <= slot_y; i++) {
|
||||
if (i == EQEmu::inventory::slotAmmo) // moved here from calling procedure to facilitate future range changes where MainAmmo may not be the last slot
|
||||
if (i == EQEmu::invslot::slotAmmo) // moved here from calling procedure to facilitate future range changes where MainAmmo may not be the last slot
|
||||
continue;
|
||||
|
||||
EQEmu::ItemInstance* inst = m_inv.GetItem(i);
|
||||
@@ -3381,7 +3371,7 @@ bool Client::CalcItemScale(uint32 slot_x, uint32 slot_y) {
|
||||
|
||||
// TEST CODE: test for bazaar trader crashing with charm items
|
||||
if (Trader)
|
||||
if (i >= EQEmu::legacy::GENERAL_BAGS_BEGIN && i <= EQEmu::legacy::GENERAL_BAGS_END) {
|
||||
if (i >= EQEmu::invbag::GENERAL_BAGS_BEGIN && i <= EQEmu::invbag::GENERAL_BAGS_END) {
|
||||
EQEmu::ItemInstance* parent_item = m_inv.GetItem(EQEmu::InventoryProfile::CalcSlotId(i));
|
||||
if (parent_item && parent_item->GetItem()->ID == 17899) // trader satchel
|
||||
continue;
|
||||
@@ -3401,7 +3391,7 @@ bool Client::CalcItemScale(uint32 slot_x, uint32 slot_y) {
|
||||
}
|
||||
|
||||
//iterate all augments
|
||||
for (int x = EQEmu::inventory::socketBegin; x < EQEmu::inventory::SocketCount; ++x)
|
||||
for (int x = EQEmu::invaug::SOCKET_BEGIN; x <= EQEmu::invaug::SOCKET_END; ++x)
|
||||
{
|
||||
EQEmu::ItemInstance * a_inst = inst->GetAugment(x);
|
||||
if(!a_inst)
|
||||
@@ -3433,27 +3423,20 @@ void Client::DoItemEnterZone() {
|
||||
bool changed = false;
|
||||
|
||||
// MainAmmo excluded in helper function below
|
||||
if (DoItemEnterZone(EQEmu::legacy::EQUIPMENT_BEGIN, EQEmu::legacy::EQUIPMENT_END)) // original coding excluded MainAmmo (< 21)
|
||||
if (DoItemEnterZone(EQEmu::invslot::EQUIPMENT_BEGIN, EQEmu::invslot::EQUIPMENT_END)) // original coding excluded MainAmmo (< 21)
|
||||
changed = true;
|
||||
|
||||
if (DoItemEnterZone(EQEmu::legacy::GENERAL_BEGIN, EQEmu::legacy::GENERAL_END)) // original coding excluded MainCursor (< 30)
|
||||
if (DoItemEnterZone(EQEmu::invslot::GENERAL_BEGIN, EQEmu::invslot::GENERAL_END)) // original coding excluded MainCursor (< 30)
|
||||
changed = true;
|
||||
|
||||
// I excluded cursor bag slots here because cursor was excluded above..if this is incorrect, change 'slot_y' here to CURSOR_BAG_END
|
||||
// and 'slot_y' above to CURSOR from GENERAL_END above - or however it is supposed to be...
|
||||
if (DoItemEnterZone(EQEmu::legacy::GENERAL_BAGS_BEGIN, EQEmu::legacy::GENERAL_BAGS_END)) // (< 341)
|
||||
if (DoItemEnterZone(EQEmu::invbag::GENERAL_BAGS_BEGIN, EQEmu::invbag::GENERAL_BAGS_END)) // (< 341)
|
||||
changed = true;
|
||||
|
||||
if (DoItemEnterZone(EQEmu::legacy::TRIBUTE_BEGIN, EQEmu::legacy::TRIBUTE_END)) // (< 405)
|
||||
if (DoItemEnterZone(EQEmu::invslot::TRIBUTE_BEGIN, EQEmu::invslot::TRIBUTE_END)) // (< 405)
|
||||
changed = true;
|
||||
|
||||
//Power Source Slot
|
||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF)
|
||||
{
|
||||
if (DoItemEnterZone(EQEmu::inventory::slotPowerSource, EQEmu::inventory::slotPowerSource))
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if(changed)
|
||||
{
|
||||
CalcBonuses();
|
||||
@@ -3464,7 +3447,7 @@ bool Client::DoItemEnterZone(uint32 slot_x, uint32 slot_y) {
|
||||
// behavior change: 'slot_y' is now [RANGE]_END and not [RANGE]_END + 1
|
||||
bool changed = false;
|
||||
for(uint32 i = slot_x; i <= slot_y; i++) {
|
||||
if (i == EQEmu::inventory::slotAmmo) // moved here from calling procedure to facilitate future range changes where MainAmmo may not be the last slot
|
||||
if (i == EQEmu::invslot::slotAmmo) // moved here from calling procedure to facilitate future range changes where MainAmmo may not be the last slot
|
||||
continue;
|
||||
|
||||
EQEmu::ItemInstance* inst = m_inv.GetItem(i);
|
||||
@@ -3474,7 +3457,7 @@ bool Client::DoItemEnterZone(uint32 slot_x, uint32 slot_y) {
|
||||
|
||||
// TEST CODE: test for bazaar trader crashing with charm items
|
||||
if (Trader)
|
||||
if (i >= EQEmu::legacy::GENERAL_BAGS_BEGIN && i <= EQEmu::legacy::GENERAL_BAGS_END) {
|
||||
if (i >= EQEmu::invbag::GENERAL_BAGS_BEGIN && i <= EQEmu::invbag::GENERAL_BAGS_END) {
|
||||
EQEmu::ItemInstance* parent_item = m_inv.GetItem(EQEmu::InventoryProfile::CalcSlotId(i));
|
||||
if (parent_item && parent_item->GetItem()->ID == 17899) // trader satchel
|
||||
continue;
|
||||
@@ -3486,7 +3469,7 @@ bool Client::DoItemEnterZone(uint32 slot_x, uint32 slot_y) {
|
||||
uint16 oldexp = inst->GetExp();
|
||||
|
||||
parse->EventItem(EVENT_ITEM_ENTER_ZONE, this, inst, nullptr, "", 0);
|
||||
if (i <= EQEmu::inventory::slotAmmo || i == EQEmu::inventory::slotPowerSource) {
|
||||
if (i <= EQEmu::invslot::EQUIPMENT_END) {
|
||||
parse->EventItem(EVENT_EQUIP_ITEM, this, inst, nullptr, "", i);
|
||||
}
|
||||
|
||||
@@ -3496,7 +3479,7 @@ bool Client::DoItemEnterZone(uint32 slot_x, uint32 slot_y) {
|
||||
update_slot = true;
|
||||
}
|
||||
} else {
|
||||
if (i <= EQEmu::inventory::slotAmmo || i == EQEmu::inventory::slotPowerSource) {
|
||||
if (i <= EQEmu::invslot::EQUIPMENT_END) {
|
||||
parse->EventItem(EVENT_EQUIP_ITEM, this, inst, nullptr, "", i);
|
||||
}
|
||||
|
||||
@@ -3504,7 +3487,7 @@ bool Client::DoItemEnterZone(uint32 slot_x, uint32 slot_y) {
|
||||
}
|
||||
|
||||
//iterate all augments
|
||||
for (int x = EQEmu::inventory::socketBegin; x < EQEmu::inventory::SocketCount; ++x)
|
||||
for (int x = EQEmu::invaug::SOCKET_BEGIN; x <= EQEmu::invaug::SOCKET_END; ++x)
|
||||
{
|
||||
EQEmu::ItemInstance *a_inst = inst->GetAugment(x);
|
||||
if(!a_inst)
|
||||
|
||||
+1200
-797
File diff suppressed because it is too large
Load Diff
+69
-136
@@ -29,7 +29,6 @@
|
||||
#include "groups.h"
|
||||
#include "corpse.h"
|
||||
#include "zonedb.h"
|
||||
#include "bot_database.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/global_define.h"
|
||||
@@ -42,6 +41,10 @@
|
||||
#define BOT_FOLLOW_DISTANCE_DEFAULT_MAX 2500 // as DSq value (50 units)
|
||||
#define BOT_FOLLOW_DISTANCE_WALK 1000 // as DSq value (~31.623 units)
|
||||
|
||||
#define BOT_LEASH_DISTANCE 250000 // as DSq value (500 units)
|
||||
|
||||
#define BOT_KEEP_ALIVE_INTERVAL 5000 // 5 seconds
|
||||
|
||||
extern WorldServer worldserver;
|
||||
|
||||
const int BotAISpellRange = 100; // TODO: Write a method that calcs what the bot's spell range is based on spell, equipment, AA, whatever and replace this
|
||||
@@ -50,91 +53,7 @@ const int MaxDisciplineTimer = 10;
|
||||
const int DisciplineReuseStart = MaxSpellTimer + 1;
|
||||
const int MaxTimer = MaxSpellTimer + MaxDisciplineTimer;
|
||||
|
||||
enum BotStanceType {
|
||||
BotStancePassive,
|
||||
BotStanceBalanced,
|
||||
BotStanceEfficient,
|
||||
BotStanceReactive,
|
||||
BotStanceAggressive,
|
||||
BotStanceBurn,
|
||||
BotStanceBurnAE,
|
||||
BotStanceUnknown,
|
||||
MaxStances = BotStanceUnknown
|
||||
};
|
||||
|
||||
#define BOT_STANCE_COUNT 8
|
||||
#define VALIDBOTSTANCE(x) ((x >= (int)BotStancePassive && x <= (int)BotStanceBurnAE) ? ((BotStanceType)x) : (BotStanceUnknown))
|
||||
|
||||
static const std::string bot_stance_name[BOT_STANCE_COUNT] = {
|
||||
"Passive", // 0
|
||||
"Balanced", // 1
|
||||
"Efficient", // 2
|
||||
"Reactive", // 3
|
||||
"Aggressive", // 4
|
||||
"Burn", // 5
|
||||
"BurnAE", // 6
|
||||
"Unknown" // 7
|
||||
};
|
||||
|
||||
static const char* GetBotStanceName(int stance_id) { return bot_stance_name[VALIDBOTSTANCE(stance_id)].c_str(); }
|
||||
|
||||
#define VALIDBOTEQUIPSLOT(x) ((x >= EQEmu::legacy::EQUIPMENT_BEGIN && x <= EQEmu::legacy::EQUIPMENT_END) ? (x) : ((x == EQEmu::inventory::slotPowerSource) ? (22) : (23)))
|
||||
|
||||
static std::string bot_equip_slot_name[EQEmu::legacy::EQUIPMENT_SIZE + 2] =
|
||||
{
|
||||
"Charm", // MainCharm
|
||||
"Left Ear", // MainEar1
|
||||
"Head", // MainHead
|
||||
"Face", // MainFace
|
||||
"Right Ear", // MainEar2
|
||||
"Neck", // MainNeck
|
||||
"Shoulders", // MainShoulders
|
||||
"Arms", // MainArms
|
||||
"Back", // MainBack
|
||||
"Left Wrist", // MainWrist1
|
||||
"Right Wrist", // MainWrist2
|
||||
"Range", // MainRange
|
||||
"Hands", // MainHands
|
||||
"Primary Hand", // MainPrimary
|
||||
"Secondary Hand", // MainSecondary
|
||||
"Left Finger", // MainFinger1
|
||||
"Right Finger", // MainFinger2
|
||||
"Chest", // MainChest
|
||||
"Legs", // MainLegs
|
||||
"Feet", // MainFeet
|
||||
"Waist", // MainWaist
|
||||
"Ammo", // MainAmmo
|
||||
"Power Source", // 22 (MainPowerSource = 9999)
|
||||
"Unknown"
|
||||
};
|
||||
|
||||
static const char* GetBotEquipSlotName(int slot_id) { return bot_equip_slot_name[VALIDBOTEQUIPSLOT(slot_id)].c_str(); }
|
||||
|
||||
enum SpellTypeIndex {
|
||||
SpellType_NukeIndex,
|
||||
SpellType_HealIndex,
|
||||
SpellType_RootIndex,
|
||||
SpellType_BuffIndex,
|
||||
SpellType_EscapeIndex,
|
||||
SpellType_PetIndex,
|
||||
SpellType_LifetapIndex,
|
||||
SpellType_SnareIndex,
|
||||
SpellType_DOTIndex,
|
||||
SpellType_DispelIndex,
|
||||
SpellType_InCombatBuffIndex,
|
||||
SpellType_MezIndex,
|
||||
SpellType_CharmIndex,
|
||||
SpellType_SlowIndex,
|
||||
SpellType_DebuffIndex,
|
||||
SpellType_CureIndex,
|
||||
SpellType_ResurrectIndex,
|
||||
SpellType_HateReduxIndex,
|
||||
SpellType_InCombatBuffSongIndex,
|
||||
SpellType_OutOfCombatBuffSongIndex,
|
||||
SpellType_PreCombatBuffIndex,
|
||||
SpellType_PreCombatBuffSongIndex,
|
||||
MaxSpellTypes
|
||||
};
|
||||
|
||||
// nHSND negative Healer/Slower/Nuker/Doter
|
||||
// pH positive Healer
|
||||
@@ -224,37 +143,43 @@ public:
|
||||
BotRoleRaidHealer
|
||||
};
|
||||
|
||||
enum EqExpansions { // expansions are off..EQ should be '0'
|
||||
ExpansionNone,
|
||||
ExpansionEQ,
|
||||
ExpansionRoK,
|
||||
ExpansionSoV,
|
||||
ExpansionSoL,
|
||||
ExpansionPoP,
|
||||
ExpansionLoY,
|
||||
ExpansionLDoN,
|
||||
ExpansionGoD,
|
||||
ExpansionOoW,
|
||||
ExpansionDoN,
|
||||
ExpansionDoDH,
|
||||
ExpansionPoR,
|
||||
ExpansionTSS,
|
||||
ExpansionSoF,
|
||||
ExpansionSoD,
|
||||
ExpansionUF,
|
||||
ExpansionHoT,
|
||||
ExpansionVoA,
|
||||
ExpansionRoF
|
||||
enum SpellTypeIndex : uint32 {
|
||||
spellTypeIndexNuke,
|
||||
spellTypeIndexHeal,
|
||||
spellTypeIndexRoot,
|
||||
spellTypeIndexBuff,
|
||||
spellTypeIndexEscape,
|
||||
spellTypeIndexPet,
|
||||
spellTypeIndexLifetap,
|
||||
spellTypeIndexSnare,
|
||||
spellTypeIndexDot,
|
||||
spellTypeIndexDispel,
|
||||
spellTypeIndexInCombatBuff,
|
||||
spellTypeIndexMez,
|
||||
spellTypeIndexCharm,
|
||||
spellTypeIndexSlow,
|
||||
spellTypeIndexDebuff,
|
||||
spellTypeIndexCure,
|
||||
spellTypeIndexResurrect,
|
||||
spellTypeIndexHateRedux,
|
||||
spellTypeIndexInCombatBuffSong,
|
||||
spellTypeIndexOutOfCombatBuffSong,
|
||||
spellTypeIndexPreCombatBuff,
|
||||
spellTypeIndexPreCombatBuffSong
|
||||
};
|
||||
|
||||
static const uint32 SPELL_TYPE_FIRST = spellTypeIndexNuke;
|
||||
static const uint32 SPELL_TYPE_LAST = spellTypeIndexPreCombatBuffSong;
|
||||
static const uint32 SPELL_TYPE_COUNT = SPELL_TYPE_LAST + 1;
|
||||
|
||||
// Class Constructors
|
||||
Bot(NPCType npcTypeData, Client* botOwner);
|
||||
Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double totalPlayTime, uint32 lastZoneId, NPCType npcTypeData);
|
||||
Bot(NPCType *npcTypeData, Client* botOwner);
|
||||
Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double totalPlayTime, uint32 lastZoneId, NPCType *npcTypeData);
|
||||
|
||||
//abstract virtual function implementations requird by base abstract class
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill);
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
||||
ExtraAttackOptions *opts = nullptr);
|
||||
virtual bool HasRaid() { return (GetRaid() ? true : false); }
|
||||
virtual bool HasGroup() { return (GetGroup() ? true : false); }
|
||||
@@ -273,7 +198,7 @@ public:
|
||||
static bool IsValidRaceClassCombo(uint16 r, uint8 c);
|
||||
bool IsValidName();
|
||||
static bool IsValidName(std::string& name);
|
||||
void Spawn(Client* botCharacterOwner);
|
||||
bool Spawn(Client* botCharacterOwner);
|
||||
virtual void SetLevel(uint8 in_level, bool command = false);
|
||||
virtual void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho);
|
||||
virtual bool Process();
|
||||
@@ -320,9 +245,9 @@ public:
|
||||
virtual void SetAttackTimer();
|
||||
uint32 GetClassHPFactor();
|
||||
virtual int32 CalcMaxHP();
|
||||
bool DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool &stopLogic);
|
||||
bool DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool &stopLogic);
|
||||
bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool &stopLogic);
|
||||
bool DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, EQEmu::spells::CastingSlot slot, bool &stopLogic);
|
||||
bool DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQEmu::spells::CastingSlot slot, bool &stopLogic);
|
||||
bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQEmu::spells::CastingSlot slot, bool &stopLogic);
|
||||
void SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32 color);
|
||||
void Camp(bool databaseSave = true);
|
||||
virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false, bool pet_command = false);
|
||||
@@ -335,9 +260,10 @@ public:
|
||||
void Stand();
|
||||
bool IsSitting();
|
||||
bool IsStanding();
|
||||
int GetBotWalkspeed() const { return (int)((float)_GetWalkSpeed() * 1.786f); } // 1.25 / 0.7 = 1.7857142857142857142857142857143
|
||||
int GetBotRunspeed() const { return (int)((float)_GetRunSpeed() * 1.786f); }
|
||||
bool IsBotCasterAtCombatRange(Mob *target);
|
||||
virtual int GetWalkspeed() const { return (int)((float)_GetWalkSpeed() * 1.785714f); } // 1.25 / 0.7 = 1.7857142857142857142857142857143
|
||||
virtual int GetRunspeed() const { return (int)((float)_GetRunSpeed() * 1.785714f); }
|
||||
virtual void WalkTo(float x, float y, float z);
|
||||
virtual void RunTo(float x, float y, float z);
|
||||
bool UseDiscipline(uint32 spell_id, uint32 target);
|
||||
uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets);
|
||||
bool GetNeedsCured(Mob *tar);
|
||||
@@ -404,8 +330,10 @@ public:
|
||||
bool AIHealRotation(Mob* tar, bool useFastHeals);
|
||||
bool GetPauseAI() { return _pauseAI; }
|
||||
void SetPauseAI(bool pause_flag) { _pauseAI = pause_flag; }
|
||||
uint8 GetStopMeleeLevel() { return _stopMeleeLevel; }
|
||||
void SetStopMeleeLevel(uint8 level);
|
||||
void SetGuardMode();
|
||||
|
||||
|
||||
// Mob AI Virtual Override Methods
|
||||
virtual void AI_Process();
|
||||
virtual void AI_Stop();
|
||||
@@ -421,12 +349,12 @@ public:
|
||||
virtual float GetAOERange(uint16 spell_id);
|
||||
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100);
|
||||
virtual void DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster = nullptr);
|
||||
virtual bool CastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0,
|
||||
virtual bool CastSpell(uint16 spell_id, uint16 target_id, EQEmu::spells::CastingSlot slot = EQEmu::spells::CastingSlot::Item, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0,
|
||||
uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr, uint32 aa_id = 0);
|
||||
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar);
|
||||
virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster);
|
||||
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, EQEmu::CastingSlot slot);
|
||||
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, uint32 aa_id = 0);
|
||||
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, EQEmu::spells::CastingSlot slot);
|
||||
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, EQEmu::spells::CastingSlot slot = EQEmu::spells::CastingSlot::Item, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, uint32 aa_id = 0);
|
||||
|
||||
// Bot Equipment & Inventory Class Methods
|
||||
void BotTradeSwapItem(Client* client, int16 lootSlot, const EQEmu::ItemInstance* inst, const EQEmu::ItemInstance* inst_swap, uint32 equipableSlots, std::string* errorMessage, bool swap = true);
|
||||
@@ -490,7 +418,7 @@ public:
|
||||
static BotSpell GetBestBotSpellForCure(Bot* botCaster, Mob* target);
|
||||
static BotSpell GetBestBotSpellForResistDebuff(Bot* botCaster, Mob* target);
|
||||
|
||||
static NPCType CreateDefaultNPCTypeStructForBot(std::string botName, std::string botLastName, uint8 botLevel, uint16 botRace, uint8 botClass, uint8 gender);
|
||||
static NPCType *CreateDefaultNPCTypeStructForBot(std::string botName, std::string botLastName, uint8 botLevel, uint16 botRace, uint8 botClass, uint8 gender);
|
||||
|
||||
// Static Bot Group Methods
|
||||
static bool AddBotToGroup(Bot* bot, Group* group);
|
||||
@@ -512,7 +440,7 @@ public:
|
||||
virtual bool IsBot() const { return true; }
|
||||
bool GetRangerAutoWeaponSelect() { return _rangerAutoWeaponSelect; }
|
||||
BotRoleType GetBotRole() { return _botRole; }
|
||||
BotStanceType GetBotStance() { return _botStance; }
|
||||
EQEmu::constants::StanceType GetBotStance() { return _botStance; }
|
||||
uint8 GetChanceToCastBySpellType(uint32 spellType);
|
||||
|
||||
bool IsGroupHealer() { return m_CastingRoles.GroupHealer; }
|
||||
@@ -530,11 +458,12 @@ public:
|
||||
bool IsBotCaster() { return IsCasterClass(GetClass()); }
|
||||
bool IsBotINTCaster() { return IsINTCasterClass(GetClass()); }
|
||||
bool IsBotWISCaster() { return IsWISCasterClass(GetClass()); }
|
||||
bool IsBotSpellFighter() { return IsSpellFighterClass(GetClass()); }
|
||||
bool IsBotFighter() { return IsFighterClass(GetClass()); }
|
||||
bool IsBotNonSpellFighter() { return IsNonSpellFighterClass(GetClass()); }
|
||||
bool CanHeal();
|
||||
int GetRawACNoShield(int &shield_ac);
|
||||
bool GetHasBeenSummoned() { return _hasBeenSummoned; }
|
||||
const glm::vec3 GetPreSummonLocation() const { return m_PreSummonLocation; }
|
||||
|
||||
|
||||
// new heal rotation code
|
||||
bool CreateHealRotation(uint32 cycle_duration_ms = 5000, bool fast_heals = false, bool adaptive_targeting = false, bool casting_override = false);
|
||||
bool DestroyHealRotation();
|
||||
@@ -625,12 +554,14 @@ public:
|
||||
// void SetBotOwnerCharacterID(uint32 botOwnerCharacterID) { _botOwnerCharacterID = botOwnerCharacterID; }
|
||||
void SetRangerAutoWeaponSelect(bool enable) { GetClass() == RANGER ? _rangerAutoWeaponSelect = enable : _rangerAutoWeaponSelect = false; }
|
||||
void SetBotRole(BotRoleType botRole) { _botRole = botRole; }
|
||||
void SetBotStance(BotStanceType botStance) { _botStance = ((botStance != BotStanceUnknown) ? (botStance) : (BotStancePassive)); }
|
||||
void SetBotStance(EQEmu::constants::StanceType botStance) {
|
||||
if (botStance >= EQEmu::constants::stancePassive && botStance <= EQEmu::constants::stanceBurnAE)
|
||||
_botStance = botStance;
|
||||
else
|
||||
_botStance = EQEmu::constants::stancePassive;
|
||||
}
|
||||
void SetSpellRecastTimer(int timer_index, int32 recast_delay);
|
||||
void SetDisciplineRecastTimer(int timer_index, int32 recast_delay);
|
||||
void SetHasBeenSummoned(bool s);
|
||||
void SetPreSummonLocation(const glm::vec3& location) { m_PreSummonLocation = location; }
|
||||
|
||||
void SetAltOutOfCombatBehavior(bool behavior_flag) { _altoutofcombatbehavior = behavior_flag;}
|
||||
void SetShowHelm(bool showhelm) { _showhelm = showhelm; }
|
||||
void SetBeardColor(uint8 value) { beardcolor = value; }
|
||||
@@ -654,7 +585,7 @@ public:
|
||||
virtual void BotRangedAttack(Mob* other);
|
||||
|
||||
// Publicized private functions
|
||||
static NPCType FillNPCTypeStruct(uint32 botSpellsID, std::string botName, std::string botLastName, uint8 botLevel, uint16 botRace, uint8 botClass, uint8 gender, float size, uint32 face, uint32 hairStyle, uint32 hairColor, uint32 eyeColor, uint32 eyeColor2, uint32 beardColor, uint32 beard, uint32 drakkinHeritage, uint32 drakkinTattoo, uint32 drakkinDetails, int32 hp, int32 mana, int32 mr, int32 cr, int32 dr, int32 fr, int32 pr, int32 corrup, int32 ac, uint32 str, uint32 sta, uint32 dex, uint32 agi, uint32 _int, uint32 wis, uint32 cha, uint32 attack);
|
||||
static NPCType *FillNPCTypeStruct(uint32 botSpellsID, std::string botName, std::string botLastName, uint8 botLevel, uint16 botRace, uint8 botClass, uint8 gender, float size, uint32 face, uint32 hairStyle, uint32 hairColor, uint32 eyeColor, uint32 eyeColor2, uint32 beardColor, uint32 beard, uint32 drakkinHeritage, uint32 drakkinTattoo, uint32 drakkinDetails, int32 hp, int32 mana, int32 mr, int32 cr, int32 dr, int32 fr, int32 pr, int32 corrup, int32 ac, uint32 str, uint32 sta, uint32 dex, uint32 agi, uint32 _int, uint32 wis, uint32 cha, uint32 attack);
|
||||
void BotRemoveEquipItem(int16 slot);
|
||||
void RemoveBotItemBySlot(uint32 slotID, std::string* errorMessage);
|
||||
uint32 GetTotalPlayTime();
|
||||
@@ -688,7 +619,6 @@ protected:
|
||||
virtual int32 CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint32 points, uint16 spell_id);
|
||||
virtual void PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* client);
|
||||
virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0);
|
||||
virtual float GetMaxMeleeRangeToTarget(Mob* target);
|
||||
|
||||
BotCastingRoles& GetCastingRoles() { return m_CastingRoles; }
|
||||
void SetGroupHealer(bool flag = true) { m_CastingRoles.GroupHealer = flag; }
|
||||
@@ -723,20 +653,19 @@ private:
|
||||
uint32 _lastZoneId;
|
||||
bool _rangerAutoWeaponSelect;
|
||||
BotRoleType _botRole;
|
||||
BotStanceType _botStance;
|
||||
BotStanceType _baseBotStance;
|
||||
EQEmu::constants::StanceType _botStance;
|
||||
EQEmu::constants::StanceType _baseBotStance;
|
||||
unsigned int RestRegenHP;
|
||||
unsigned int RestRegenMana;
|
||||
unsigned int RestRegenEndurance;
|
||||
Timer rest_timer;
|
||||
Timer ping_timer;
|
||||
int32 base_end;
|
||||
int32 cur_end;
|
||||
int32 max_end;
|
||||
int32 end_regen;
|
||||
uint32 timers[MaxTimer];
|
||||
bool _hasBeenSummoned;
|
||||
glm::vec3 m_PreSummonLocation;
|
||||
|
||||
|
||||
Timer evade_timer; // can be moved to pTimers at some point
|
||||
|
||||
BotCastingRoles m_CastingRoles;
|
||||
@@ -748,6 +677,7 @@ private:
|
||||
bool _altoutofcombatbehavior;
|
||||
bool _showhelm;
|
||||
bool _pauseAI;
|
||||
uint8 _stopMeleeLevel;
|
||||
|
||||
// Private "base stats" Members
|
||||
int32 _baseMR;
|
||||
@@ -788,6 +718,9 @@ private:
|
||||
bool LoadPet(); // Load and spawn bot pet if there is one
|
||||
bool SavePet(); // Save and depop bot pet if there is one
|
||||
bool DeletePet();
|
||||
|
||||
public:
|
||||
static uint8 spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQEmu::constants::STANCE_TYPE_COUNT][cntHSND];
|
||||
};
|
||||
|
||||
#endif // BOTS
|
||||
|
||||
+313
-145
@@ -59,11 +59,10 @@
|
||||
|
||||
|
||||
#include "bot_command.h"
|
||||
#include "bot_database.h"
|
||||
#include "zonedb.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "map.h"
|
||||
#include "doors.h"
|
||||
#include "pathing.h"
|
||||
#include "qglobals.h"
|
||||
#include "queryserv.h"
|
||||
#include "quest_parser_collection.h"
|
||||
@@ -1350,6 +1349,7 @@ int bot_command_init(void)
|
||||
bot_command_add("botreport", "Orders a bot to report its readiness", 0, bot_subcommand_bot_report) ||
|
||||
bot_command_add("botspawn", "Spawns a created bot", 0, bot_subcommand_bot_spawn) ||
|
||||
bot_command_add("botstance", "Changes the stance of a bot", 0, bot_subcommand_bot_stance) ||
|
||||
bot_command_add("botstopmeleelevel", "Sets the level a caster or spell-casting fighter bot will stop melee combat", 0, bot_subcommand_bot_stop_melee_level) ||
|
||||
bot_command_add("botsummon", "Summons bot(s) to your location", 0, bot_subcommand_bot_summon) ||
|
||||
bot_command_add("bottattoo", "Changes the Drakkin tattoo of a bot", 0, bot_subcommand_bot_tattoo) ||
|
||||
bot_command_add("bottogglearcher", "Toggles a archer bot between melee and ranged weapon use", 0, bot_subcommand_bot_toggle_archer) ||
|
||||
@@ -1399,6 +1399,7 @@ int bot_command_init(void)
|
||||
bot_command_add("lull", "Orders a bot to cast a pacification spell", 0, bot_command_lull) ||
|
||||
bot_command_add("mesmerize", "Orders a bot to cast a mesmerization spell", 0, bot_command_mesmerize) ||
|
||||
bot_command_add("movementspeed", "Orders a bot to cast a movement speed enhancement spell", 0, bot_command_movement_speed) ||
|
||||
bot_command_add("owneroption", "Sets options available to bot owners", 0, bot_command_owner_option) ||
|
||||
bot_command_add("pet", "Lists the available bot pet [subcommands]", 0, bot_command_pet) ||
|
||||
bot_command_add("petremove", "Orders a bot to remove its pet", 0, bot_subcommand_pet_remove) ||
|
||||
bot_command_add("petsettype", "Orders a Magician bot to use a specified pet type", 0, bot_subcommand_pet_set_type) ||
|
||||
@@ -1421,7 +1422,7 @@ int bot_command_init(void)
|
||||
}
|
||||
|
||||
std::map<std::string, std::pair<uint8, std::vector<std::string>>> bot_command_settings;
|
||||
botdb.LoadBotCommandSettings(bot_command_settings);
|
||||
database.botdb.LoadBotCommandSettings(bot_command_settings);
|
||||
|
||||
auto working_bcl = bot_command_list;
|
||||
for (auto working_bcl_iter : working_bcl) {
|
||||
@@ -1867,11 +1868,11 @@ namespace MyBots
|
||||
std::string group_name = name;
|
||||
|
||||
uint32 botgroup_id = 0;
|
||||
if (!botdb.LoadBotGroupIDForLoadBotGroup(bot_owner->CharacterID(), group_name, botgroup_id) || !botgroup_id)
|
||||
if (!database.botdb.LoadBotGroupIDForLoadBotGroup(bot_owner->CharacterID(), group_name, botgroup_id) || !botgroup_id)
|
||||
return;
|
||||
|
||||
std::map<uint32, std::list<uint32>> botgroup_list;
|
||||
if (!botdb.LoadBotGroup(group_name, botgroup_list) || botgroup_list.find(botgroup_id) == botgroup_list.end() || !botgroup_list[botgroup_id].size())
|
||||
if (!database.botdb.LoadBotGroup(group_name, botgroup_list) || botgroup_list.find(botgroup_id) == botgroup_list.end() || !botgroup_list[botgroup_id].size())
|
||||
return;
|
||||
|
||||
std::list<Bot*> selectable_bot_list;
|
||||
@@ -2403,7 +2404,7 @@ namespace ActionableBots
|
||||
continue;
|
||||
|
||||
mod_skill_value = base_skill_value;
|
||||
for (int16 index = EQEmu::legacy::EQUIPMENT_BEGIN; index <= EQEmu::legacy::EQUIPMENT_END; ++index) {
|
||||
for (int16 index = EQEmu::invslot::EQUIPMENT_BEGIN; index <= EQEmu::invslot::EQUIPMENT_END; ++index) {
|
||||
const EQEmu::ItemInstance* indexed_item = bot_iter->GetBotItem(index);
|
||||
if (indexed_item && indexed_item->GetItem()->SkillModType == skill_type)
|
||||
mod_skill_value += (base_skill_value * (((float)indexed_item->GetItem()->SkillModValue) / 100.0f));
|
||||
@@ -2605,6 +2606,7 @@ void bot_command_bot(Client *c, const Seperator *sep)
|
||||
subcommand_list.push_back("botreport");
|
||||
subcommand_list.push_back("botspawn");
|
||||
subcommand_list.push_back("botstance");
|
||||
subcommand_list.push_back("botstopmeleelevel");
|
||||
subcommand_list.push_back("botsummon");
|
||||
subcommand_list.push_back("bottogglearcher");
|
||||
subcommand_list.push_back("bottogglehelm");
|
||||
@@ -3047,13 +3049,7 @@ void bot_command_guard(Client *c, const Seperator *sep)
|
||||
|
||||
sbl.remove(nullptr);
|
||||
for (auto bot_iter : sbl) {
|
||||
bot_iter->WipeHateList();
|
||||
bot_iter->SetFollowID(0);
|
||||
if (!bot_iter->GetPet())
|
||||
continue;
|
||||
|
||||
bot_iter->GetPet()->WipeHateList();
|
||||
bot_iter->GetPet()->SetFollowID(0);
|
||||
bot_iter->SetGuardMode();
|
||||
}
|
||||
if (sbl.size() == 1)
|
||||
Bot::BotGroupSay(sbl.front(), "Guarding this position");
|
||||
@@ -3442,6 +3438,43 @@ void bot_command_movement_speed(Client *c, const Seperator *sep)
|
||||
helper_no_available_bots(c, my_bot);
|
||||
}
|
||||
|
||||
void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||
c->Message(m_usage, "usage: %s [deathmarquee | statsupdate] (argument: enable | disable | null (toggles))", sep->arg[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string owner_option = sep->arg[1];
|
||||
std::string flag = sep->arg[2];
|
||||
|
||||
if (!owner_option.compare("deathmarquee")) {
|
||||
if (!flag.compare("enable"))
|
||||
c->SetBotOptionDeathMarquee(true);
|
||||
else if (!flag.compare("disable"))
|
||||
c->SetBotOptionDeathMarquee(false);
|
||||
else
|
||||
c->SetBotOptionDeathMarquee(!c->GetBotOptionDeathMarquee());
|
||||
|
||||
database.botdb.SaveOwnerOptionDeathMarquee(c->CharacterID(), c->GetBotOptionDeathMarquee());
|
||||
c->Message(m_action, "Bot 'death marquee' is now %s.", (c->GetBotOptionDeathMarquee() == true ? "enabled" : "disabled"));
|
||||
}
|
||||
else if (!owner_option.compare("statsupdate")) {
|
||||
if (!flag.compare("enable"))
|
||||
c->SetBotOptionStatsUpdate(true);
|
||||
else if (!flag.compare("disable"))
|
||||
c->SetBotOptionStatsUpdate(false);
|
||||
else
|
||||
c->SetBotOptionStatsUpdate(!c->GetBotOptionStatsUpdate());
|
||||
|
||||
database.botdb.SaveOwnerOptionStatsUpdate(c->CharacterID(), c->GetBotOptionStatsUpdate());
|
||||
c->Message(m_action, "Bot 'stats update' is now %s.", (c->GetBotOptionStatsUpdate() == true ? "enabled" : "disabled"));
|
||||
}
|
||||
else {
|
||||
c->Message(m_fail, "Owner option '%s' is not recognized.", owner_option.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void bot_command_pet(Client *c, const Seperator *sep)
|
||||
{
|
||||
/* VS2012 code - begin */
|
||||
@@ -4207,7 +4240,7 @@ void bot_subcommand_bot_clone(Client *c, const Seperator *sep)
|
||||
std::string error_message;
|
||||
|
||||
bool available_flag = false;
|
||||
if (!botdb.QueryNameAvailablity(bot_name, available_flag)) {
|
||||
if (!database.botdb.QueryNameAvailablity(bot_name, available_flag)) {
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::QueryNameAvailablity());
|
||||
return;
|
||||
}
|
||||
@@ -4219,7 +4252,7 @@ void bot_subcommand_bot_clone(Client *c, const Seperator *sep)
|
||||
uint32 max_bot_count = RuleI(Bots, CreationLimit);
|
||||
|
||||
uint32 bot_count = 0;
|
||||
if (!botdb.QueryBotCount(c->CharacterID(), bot_count)) {
|
||||
if (!database.botdb.QueryBotCount(c->CharacterID(), bot_count)) {
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::QueryBotCount());
|
||||
return;
|
||||
}
|
||||
@@ -4229,18 +4262,18 @@ void bot_subcommand_bot_clone(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
uint32 clone_id = 0;
|
||||
if (!botdb.CreateCloneBot(c->CharacterID(), my_bot->GetBotID(), bot_name, clone_id) || !clone_id) {
|
||||
if (!database.botdb.CreateCloneBot(c->CharacterID(), my_bot->GetBotID(), bot_name, clone_id) || !clone_id) {
|
||||
c->Message(m_fail, "%s '%s'", BotDatabase::fail::CreateCloneBot(), bot_name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
int clone_stance = BotStancePassive;
|
||||
if (!botdb.LoadStance(my_bot->GetBotID(), clone_stance))
|
||||
int clone_stance = EQEmu::constants::stancePassive;
|
||||
if (!database.botdb.LoadStance(my_bot->GetBotID(), clone_stance))
|
||||
c->Message(m_fail, "%s for bot '%s'", BotDatabase::fail::LoadStance(), my_bot->GetCleanName());
|
||||
if (!botdb.SaveStance(clone_id, clone_stance))
|
||||
if (!database.botdb.SaveStance(clone_id, clone_stance))
|
||||
c->Message(m_fail, "%s for clone '%s'", BotDatabase::fail::SaveStance(), bot_name.c_str());
|
||||
|
||||
if (!botdb.CreateCloneBotInventory(c->CharacterID(), my_bot->GetBotID(), clone_id))
|
||||
if (!database.botdb.CreateCloneBotInventory(c->CharacterID(), my_bot->GetBotID(), clone_id))
|
||||
c->Message(m_fail, "%s for clone '%s'", BotDatabase::fail::CreateCloneBotInventory(), bot_name.c_str());
|
||||
|
||||
c->Message(m_action, "Bot '%s' was successfully cloned to bot '%s'", my_bot->GetCleanName(), bot_name.c_str());
|
||||
@@ -4248,12 +4281,69 @@ void bot_subcommand_bot_clone(Client *c, const Seperator *sep)
|
||||
|
||||
void bot_subcommand_bot_create(Client *c, const Seperator *sep)
|
||||
{
|
||||
const std::string msg_class = StringFormat("class: %u(WAR), %u(CLR), %u(PAL), %u(RNG), %u(SHD), %u(DRU), %u(MNK), %u(BRD), %u(ROG), %u(SHM), %u(NEC), %u(WIZ), %u(MAG), %u(ENC), %u(BST), %u(BER)",
|
||||
WARRIOR, CLERIC, PALADIN, RANGER, SHADOWKNIGHT, DRUID, MONK, BARD, ROGUE, SHAMAN, NECROMANCER, WIZARD, MAGICIAN, ENCHANTER, BEASTLORD, BERSERKER);
|
||||
const std::string msg_race = StringFormat("race: %u(HUM), %u(BAR), %u(ERU), %u(ELF), %u(HIE), %u(DEF), %u(HEF), %u(DWF), %u(TRL), %u(OGR), %u(HFL), %u(GNM), %u(IKS), %u(VAH), %u(FRG), %u(DRK)",
|
||||
HUMAN, BARBARIAN, ERUDITE, WOOD_ELF, HIGH_ELF, DARK_ELF, HALF_ELF, DWARF, TROLL, OGRE, HALFLING, GNOME, IKSAR, VAHSHIR, FROGLOK, DRAKKIN);
|
||||
const std::string msg_gender = StringFormat("gender: %u(M), %u(F)", MALE, FEMALE);
|
||||
|
||||
const std::string class_substrs[17] = { "",
|
||||
"%u(WAR)", "%u(CLR)", "%u(PAL)", "%u(RNG)",
|
||||
"%u(SHD)", "%u(DRU)", "%u(MNK)", "%u(BRD)",
|
||||
"%u(ROG)", "%u(SHM)", "%u(NEC)", "%u(WIZ)",
|
||||
"%u(MAG)", "%u(ENC)", "%u(BST)", "%u(BER)"
|
||||
};
|
||||
|
||||
const std::string race_substrs[17] = { "",
|
||||
"%u(HUM)", "%u(BAR)", "%u(ERU)", "%u(ELF)",
|
||||
"%u(HIE)", "%u(DEF)", "%u(HEF)", "%u(DWF)",
|
||||
"%u(TRL)", "%u(OGR)", "%u(HFL)", "%u(GNM)",
|
||||
"%u(IKS)", "%u(VAH)", "%u(FRG)", "%u(DRK)"
|
||||
};
|
||||
|
||||
const uint16 race_values[17] = { 0,
|
||||
HUMAN, BARBARIAN, ERUDITE, WOOD_ELF,
|
||||
HIGH_ELF, DARK_ELF, HALF_ELF, DWARF,
|
||||
TROLL, OGRE, HALFLING, GNOME,
|
||||
IKSAR, VAHSHIR, FROGLOK, DRAKKIN
|
||||
};
|
||||
|
||||
const std::string gender_substrs[2] = {
|
||||
"%u(M)", "%u(F)",
|
||||
};
|
||||
|
||||
std::string msg_class = "class:";
|
||||
std::string msg_race = "race:";
|
||||
std::string msg_gender = "gender:";
|
||||
std::string msg_separator;
|
||||
|
||||
msg_separator = " ";
|
||||
for (int i = 0; i <= 15; ++i) {
|
||||
if (((1 << i) & RuleI(Bots, AllowedClasses)) == 0)
|
||||
continue;
|
||||
|
||||
msg_class.append(const_cast<const std::string&>(msg_separator));
|
||||
msg_class.append(StringFormat(class_substrs[i + 1].c_str(), (i + 1)));
|
||||
|
||||
msg_separator = ", ";
|
||||
}
|
||||
|
||||
msg_separator = " ";
|
||||
for (int i = 0; i <= 15; ++i) {
|
||||
if (((1 << i) & RuleI(Bots, AllowedRaces)) == 0)
|
||||
continue;
|
||||
|
||||
msg_race.append(const_cast<const std::string&>(msg_separator));
|
||||
msg_race.append(StringFormat(race_substrs[i + 1].c_str(), race_values[i + 1]));
|
||||
|
||||
msg_separator = ", ";
|
||||
}
|
||||
|
||||
msg_separator = " ";
|
||||
for (int i = 0; i <= 1; ++i) {
|
||||
if (((1 << i) & RuleI(Bots, AllowedGenders)) == 0)
|
||||
continue;
|
||||
|
||||
msg_gender.append(const_cast<const std::string&>(msg_separator));
|
||||
msg_gender.append(StringFormat(gender_substrs[i].c_str(), i));
|
||||
|
||||
msg_separator = ", ";
|
||||
}
|
||||
|
||||
if (helper_command_alias_fail(c, "bot_subcommand_bot_create", sep->arg[0], "botcreate"))
|
||||
return;
|
||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||
@@ -4431,11 +4521,11 @@ void bot_subcommand_bot_dye_armor(Client *c, const Seperator *sep)
|
||||
|
||||
if (ab_type == ActionableBots::ABT_All) {
|
||||
if (dye_all) {
|
||||
if (!botdb.SaveAllArmorColors(c->CharacterID(), rgb_value))
|
||||
if (!database.botdb.SaveAllArmorColors(c->CharacterID(), rgb_value))
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::SaveAllArmorColors());
|
||||
}
|
||||
else {
|
||||
if (!botdb.SaveAllArmorColorBySlot(c->CharacterID(), slot_id, rgb_value))
|
||||
if (!database.botdb.SaveAllArmorColorBySlot(c->CharacterID(), slot_id, rgb_value))
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::SaveAllArmorColorBySlot());
|
||||
}
|
||||
}
|
||||
@@ -4584,7 +4674,7 @@ void bot_subcommand_bot_follow_distance(Client *c, const Seperator *sep)
|
||||
continue;
|
||||
|
||||
bot_iter->SetFollowDistance(bfd);
|
||||
if (ab_type != ActionableBots::ABT_All && !botdb.SaveFollowDistance(c->CharacterID(), bot_iter->GetBotID(), bfd)) {
|
||||
if (ab_type != ActionableBots::ABT_All && !database.botdb.SaveFollowDistance(c->CharacterID(), bot_iter->GetBotID(), bfd)) {
|
||||
c->Message(m_fail, "%s for '%s'", BotDatabase::fail::SaveFollowDistance(), bot_iter->GetCleanName());
|
||||
return;
|
||||
}
|
||||
@@ -4593,7 +4683,7 @@ void bot_subcommand_bot_follow_distance(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
if (ab_type == ActionableBots::ABT_All) {
|
||||
if (!botdb.SaveAllFollowDistances(c->CharacterID(), bfd)) {
|
||||
if (!database.botdb.SaveAllFollowDistances(c->CharacterID(), bfd)) {
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::SaveAllFollowDistances());
|
||||
return;
|
||||
}
|
||||
@@ -4762,7 +4852,7 @@ void bot_subcommand_bot_inspect_message(Client *c, const Seperator *sep)
|
||||
if (set_flag)
|
||||
memcpy(bot_message_struct, client_message_struct, sizeof(InspectMessage_Struct));
|
||||
|
||||
if (ab_type != ActionableBots::ABT_All && !botdb.SaveInspectMessage(bot_iter->GetBotID(), *bot_message_struct)) {
|
||||
if (ab_type != ActionableBots::ABT_All && !database.botdb.SaveInspectMessage(bot_iter->GetBotID(), *bot_message_struct)) {
|
||||
c->Message(m_fail, "%s for '%s'", BotDatabase::fail::SaveInspectMessage(), bot_iter->GetCleanName());
|
||||
return;
|
||||
}
|
||||
@@ -4776,7 +4866,7 @@ void bot_subcommand_bot_inspect_message(Client *c, const Seperator *sep)
|
||||
if (set_flag)
|
||||
memcpy(&bot_message_struct, client_message_struct, sizeof(InspectMessage_Struct));
|
||||
|
||||
if (!botdb.SaveAllInspectMessages(c->CharacterID(), bot_message_struct)) {
|
||||
if (!database.botdb.SaveAllInspectMessages(c->CharacterID(), bot_message_struct)) {
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::SaveAllInspectMessages());
|
||||
return;
|
||||
}
|
||||
@@ -4798,7 +4888,7 @@ void bot_subcommand_bot_list(Client *c, const Seperator *sep)
|
||||
return;
|
||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||
c->Message(m_usage, "usage: %s ([class] [value]) ([race] [value]) ([name] [partial-full])", sep->arg[0]);
|
||||
c->Message(m_note, "Note: filter criteria is orderless and optional");
|
||||
c->Message(m_note, "note: filter criteria is orderless and optional");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4832,7 +4922,7 @@ void bot_subcommand_bot_list(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
std::list<BotsAvailableList> bots_list;
|
||||
if (!botdb.LoadBotsList(c->CharacterID(), bots_list)) {
|
||||
if (!database.botdb.LoadBotsList(c->CharacterID(), bots_list)) {
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::LoadBotsList());
|
||||
return;
|
||||
}
|
||||
@@ -4989,7 +5079,7 @@ void bot_subcommand_bot_spawn(Client *c, const Seperator *sep)
|
||||
|
||||
if (RuleB(Bots, QuestableSpawnLimit) && !c->GetGM()) {
|
||||
int allowed_bot_count = 0;
|
||||
if (!botdb.LoadQuestableSpawnCount(c->CharacterID(), allowed_bot_count)) {
|
||||
if (!database.botdb.LoadQuestableSpawnCount(c->CharacterID(), allowed_bot_count)) {
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::LoadQuestableSpawnCount());
|
||||
return;
|
||||
}
|
||||
@@ -5010,7 +5100,7 @@ void bot_subcommand_bot_spawn(Client *c, const Seperator *sep)
|
||||
std::string bot_name = sep->arg[1];
|
||||
|
||||
uint32 bot_id = 0;
|
||||
if (!botdb.LoadBotID(c->CharacterID(), bot_name, bot_id)) {
|
||||
if (!database.botdb.LoadBotID(c->CharacterID(), bot_name, bot_id)) {
|
||||
c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadBotID(), bot_name.c_str());
|
||||
return;
|
||||
}
|
||||
@@ -5055,7 +5145,11 @@ void bot_subcommand_bot_spawn(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
my_bot->Spawn(c);
|
||||
if (!my_bot->Spawn(c)) {
|
||||
c->Message(m_fail, "Failed to spawn bot '%s' (id: %i)", bot_name.c_str(), bot_id);
|
||||
safe_delete(my_bot);
|
||||
return;
|
||||
}
|
||||
|
||||
static const char* bot_spawn_message[16] = {
|
||||
"A solid weapon is my ally!", // WARRIOR / 'generic'
|
||||
@@ -5084,29 +5178,34 @@ void bot_subcommand_bot_stance(Client *c, const Seperator *sep)
|
||||
if (helper_command_alias_fail(c, "bot_subcommand_bot_stance", sep->arg[0], "botstance"))
|
||||
return;
|
||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||
c->Message(m_usage, "usage: %s [current | value: 0-6] ([actionable: target | byname] ([actionable_name]))", sep->arg[0]);
|
||||
c->Message(m_usage, "usage: %s [current | value: 1-9] ([actionable: target | byname] ([actionable_name]))", sep->arg[0]);
|
||||
c->Message(m_note, "value: %u(%s), %u(%s), %u(%s), %u(%s), %u(%s), %u(%s), %u(%s)",
|
||||
BotStancePassive, GetBotStanceName(BotStancePassive),
|
||||
BotStanceBalanced, GetBotStanceName(BotStanceBalanced),
|
||||
BotStanceEfficient, GetBotStanceName(BotStanceEfficient),
|
||||
BotStanceReactive, GetBotStanceName(BotStanceReactive),
|
||||
BotStanceAggressive, GetBotStanceName(BotStanceAggressive),
|
||||
BotStanceBurn, GetBotStanceName(BotStanceBurn),
|
||||
BotStanceBurnAE, GetBotStanceName(BotStanceBurnAE)
|
||||
EQEmu::constants::stancePassive, EQEmu::constants::GetStanceName(EQEmu::constants::stancePassive),
|
||||
EQEmu::constants::stanceBalanced, EQEmu::constants::GetStanceName(EQEmu::constants::stanceBalanced),
|
||||
EQEmu::constants::stanceEfficient, EQEmu::constants::GetStanceName(EQEmu::constants::stanceEfficient),
|
||||
EQEmu::constants::stanceReactive, EQEmu::constants::GetStanceName(EQEmu::constants::stanceReactive),
|
||||
EQEmu::constants::stanceAggressive, EQEmu::constants::GetStanceName(EQEmu::constants::stanceAggressive),
|
||||
EQEmu::constants::stanceAssist, EQEmu::constants::GetStanceName(EQEmu::constants::stanceAssist),
|
||||
EQEmu::constants::stanceBurn, EQEmu::constants::GetStanceName(EQEmu::constants::stanceBurn),
|
||||
EQEmu::constants::stanceEfficient2, EQEmu::constants::GetStanceName(EQEmu::constants::stanceEfficient2),
|
||||
EQEmu::constants::stanceBurnAE, EQEmu::constants::GetStanceName(EQEmu::constants::stanceBurnAE)
|
||||
);
|
||||
return;
|
||||
}
|
||||
int ab_mask = (ActionableBots::ABM_Target | ActionableBots::ABM_ByName);
|
||||
|
||||
bool current_flag = false;
|
||||
auto bst = BotStanceUnknown;
|
||||
auto bst = EQEmu::constants::stanceUnknown;
|
||||
|
||||
if (!strcasecmp(sep->arg[1], "current"))
|
||||
current_flag = true;
|
||||
else if (sep->IsNumber(1))
|
||||
bst = VALIDBOTSTANCE(atoi(sep->arg[1]));
|
||||
else if (sep->IsNumber(1)) {
|
||||
bst = (EQEmu::constants::StanceType)atoi(sep->arg[1]);
|
||||
if (bst < EQEmu::constants::stanceUnknown || bst > EQEmu::constants::stanceBurnAE)
|
||||
bst = EQEmu::constants::stanceUnknown;
|
||||
}
|
||||
|
||||
if (!current_flag && bst == BotStanceUnknown) {
|
||||
if (!current_flag && bst == EQEmu::constants::stanceUnknown) {
|
||||
c->Message(m_fail, "A [current] argument or valid numeric [value] is required to use this command");
|
||||
return;
|
||||
}
|
||||
@@ -5124,10 +5223,62 @@ void bot_subcommand_bot_stance(Client *c, const Seperator *sep)
|
||||
bot_iter->Save();
|
||||
}
|
||||
|
||||
Bot::BotGroupSay(bot_iter, "My current stance is '%s' (%u)", GetBotStanceName(bot_iter->GetBotStance()), bot_iter->GetBotStance());
|
||||
Bot::BotGroupSay(
|
||||
bot_iter,
|
||||
"My current stance is '%s' (%i)",
|
||||
EQEmu::constants::GetStanceName(bot_iter->GetBotStance()),
|
||||
bot_iter->GetBotStance()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void bot_subcommand_bot_stop_melee_level(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (helper_command_alias_fail(c, "bot_subcommand_bot_stop_melee_level", sep->arg[0], "botstopmeleelevel"))
|
||||
return;
|
||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||
c->Message(m_usage, "usage: <target_bot> %s [current | reset | sync | value: 0-255]", sep->arg[0]);
|
||||
c->Message(m_note, "note: Only caster and spell-casting fighter class bots may be modified");
|
||||
c->Message(m_note, "note: Use [reset] to set stop melee level to server rule");
|
||||
c->Message(m_note, "note: Use [sync] to set stop melee level to current bot level");
|
||||
return;
|
||||
}
|
||||
|
||||
auto my_bot = ActionableBots::AsTarget_ByBot(c);
|
||||
if (!my_bot) {
|
||||
c->Message(m_fail, "You must <target> a bot that you own to use this command");
|
||||
return;
|
||||
}
|
||||
if (!IsCasterClass(my_bot->GetClass()) && !IsSpellFighterClass(my_bot->GetClass())) {
|
||||
c->Message(m_fail, "You must <target> a caster or spell-casting fighter class bot to use this command");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 sml = RuleI(Bots, CasterStopMeleeLevel);
|
||||
|
||||
if (sep->IsNumber(1)) {
|
||||
sml = atoi(sep->arg[1]);
|
||||
}
|
||||
else if (!strcasecmp(sep->arg[1], "sync")) {
|
||||
sml = my_bot->GetLevel();
|
||||
}
|
||||
else if (!strcasecmp(sep->arg[1], "current")) {
|
||||
c->Message(m_message, "My current melee stop level is %u", my_bot->GetStopMeleeLevel());
|
||||
return;
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "reset")) {
|
||||
c->Message(m_fail, "A [current] or [reset] argument, or numeric [value] is required to use this command");
|
||||
return;
|
||||
}
|
||||
// [reset] falls through with initialization value
|
||||
|
||||
my_bot->SetStopMeleeLevel(sml);
|
||||
if (!database.botdb.SaveStopMeleeLevel(c->CharacterID(), my_bot->GetBotID(), sml))
|
||||
c->Message(m_fail, "%s for '%s'", BotDatabase::fail::SaveStopMeleeLevel(), my_bot->GetCleanName());
|
||||
|
||||
c->Message(m_action, "Successfully set stop melee level for %s to %u", my_bot->GetCleanName(), sml);
|
||||
}
|
||||
|
||||
void bot_subcommand_bot_summon(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (helper_command_alias_fail(c, "bot_subcommand_bot_summon", sep->arg[0], "botsummon"))
|
||||
@@ -5146,19 +5297,19 @@ void bot_subcommand_bot_summon(Client *c, const Seperator *sep)
|
||||
if (!bot_iter)
|
||||
continue;
|
||||
|
||||
Bot::BotGroupSay(bot_iter, "Whee!");
|
||||
//Bot::BotGroupSay(bot_iter, "Whee!");
|
||||
|
||||
bot_iter->WipeHateList();
|
||||
bot_iter->SetTarget(bot_iter->GetBotOwner());
|
||||
bot_iter->Warp(glm::vec3(c->GetPosition()));
|
||||
bot_iter->SetTarget(nullptr);
|
||||
bot_iter->Teleport(c->GetPosition());
|
||||
bot_iter->DoAnim(0);
|
||||
|
||||
if (!bot_iter->HasPet())
|
||||
continue;
|
||||
|
||||
bot_iter->GetPet()->WipeHateList();
|
||||
bot_iter->GetPet()->SetTarget(bot_iter);
|
||||
bot_iter->GetPet()->Warp(glm::vec3(c->GetPosition()));
|
||||
bot_iter->GetPet()->SetTarget(nullptr);
|
||||
bot_iter->GetPet()->Teleport(c->GetPosition());
|
||||
}
|
||||
|
||||
if (sbl.size() == 1)
|
||||
@@ -5291,7 +5442,7 @@ void bot_subcommand_bot_toggle_helm(Client *c, const Seperator *sep)
|
||||
bot_iter->SetShowHelm(helm_state);
|
||||
|
||||
if (ab_type != ActionableBots::ABT_All) {
|
||||
if (!botdb.SaveHelmAppearance(c->CharacterID(), bot_iter->GetBotID(), bot_iter->GetShowHelm())) {
|
||||
if (!database.botdb.SaveHelmAppearance(c->CharacterID(), bot_iter->GetBotID(), bot_iter->GetShowHelm())) {
|
||||
c->Message(m_unknown, "%s for '%s'", bot_iter->GetCleanName());
|
||||
return;
|
||||
}
|
||||
@@ -5313,11 +5464,11 @@ void bot_subcommand_bot_toggle_helm(Client *c, const Seperator *sep)
|
||||
if (ab_type == ActionableBots::ABT_All) {
|
||||
std::string query;
|
||||
if (toggle_helm) {
|
||||
if (!botdb.ToggleAllHelmAppearances(c->CharacterID()))
|
||||
if (!database.botdb.ToggleAllHelmAppearances(c->CharacterID()))
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::ToggleAllHelmAppearances());
|
||||
}
|
||||
else {
|
||||
if (!botdb.SaveAllHelmAppearances(c->CharacterID(), helm_state))
|
||||
if (!database.botdb.SaveAllHelmAppearances(c->CharacterID(), helm_state))
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::SaveAllHelmAppearances());
|
||||
}
|
||||
|
||||
@@ -5399,7 +5550,7 @@ void bot_subcommand_bot_update(Client *c, const Seperator *sep)
|
||||
continue;
|
||||
|
||||
bot_iter->SetPetChooser(false);
|
||||
bot_iter->CalcBotStats((sbl.size() == 1));
|
||||
bot_iter->CalcBotStats(c->GetBotOptionStatsUpdate());
|
||||
bot_iter->SendAppearancePacket(AT_WhoLevel, bot_iter->GetLevel(), true, true);
|
||||
++bot_count;
|
||||
}
|
||||
@@ -5476,7 +5627,7 @@ void bot_subcommand_botgroup_add_member(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
uint32 botgroup_id = 0;
|
||||
if (!botdb.LoadBotGroupIDByMemberID(new_member->GetBotID(), botgroup_id)) {
|
||||
if (!database.botdb.LoadBotGroupIDByMemberID(new_member->GetBotID(), botgroup_id)) {
|
||||
c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadBotGroupIDByMemberID(), new_member->GetCleanName());
|
||||
return;
|
||||
}
|
||||
@@ -5506,7 +5657,7 @@ void bot_subcommand_botgroup_add_member(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
botgroup_id = 0;
|
||||
if (!botdb.LoadBotGroupIDByLeaderID(botgroup_leader->GetBotID(), botgroup_id)) {
|
||||
if (!database.botdb.LoadBotGroupIDByLeaderID(botgroup_leader->GetBotID(), botgroup_id)) {
|
||||
c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadBotGroupIDByLeaderID(), botgroup_leader->GetCleanName());
|
||||
return;
|
||||
}
|
||||
@@ -5522,14 +5673,14 @@ void bot_subcommand_botgroup_add_member(Client *c, const Seperator *sep)
|
||||
|
||||
database.SetGroupID(new_member->GetName(), group_inst->GetID(), new_member->GetBotID());
|
||||
|
||||
if (!botdb.AddMemberToBotGroup(botgroup_leader->GetBotID(), new_member->GetBotID())) {
|
||||
if (!database.botdb.AddMemberToBotGroup(botgroup_leader->GetBotID(), new_member->GetBotID())) {
|
||||
c->Message(m_fail, "%s - %s->%s", BotDatabase::fail::AddMemberToBotGroup(), new_member->GetCleanName(), botgroup_leader->GetCleanName());
|
||||
Bot::RemoveBotFromGroup(new_member, botgroup_leader->GetGroup());
|
||||
return;
|
||||
}
|
||||
|
||||
std::string botgroup_name;
|
||||
if (!botdb.LoadBotGroupNameByLeaderID(botgroup_leader->GetBotID(), botgroup_name))
|
||||
if (!database.botdb.LoadBotGroupNameByLeaderID(botgroup_leader->GetBotID(), botgroup_name))
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::LoadBotGroupNameByLeaderID());
|
||||
|
||||
c->Message(m_action, "Successfully added %s to bot-group %s", new_member->GetCleanName(), botgroup_name.c_str());
|
||||
@@ -5551,7 +5702,7 @@ void bot_subcommand_botgroup_create(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
bool extant_flag = false;
|
||||
if (!botdb.QueryBotGroupExistence(botgroup_name_arg, extant_flag)) {
|
||||
if (!database.botdb.QueryBotGroupExistence(botgroup_name_arg, extant_flag)) {
|
||||
c->Message(m_fail, "%s for '%s'", BotDatabase::fail::QueryBotGroupExistence(), botgroup_name_arg.c_str());
|
||||
return;
|
||||
}
|
||||
@@ -5581,7 +5732,7 @@ void bot_subcommand_botgroup_create(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
uint32 botgroup_id = 0;
|
||||
if (!botdb.LoadBotGroupIDByLeaderID(botgroup_leader->GetBotID(), botgroup_id)) {
|
||||
if (!database.botdb.LoadBotGroupIDByLeaderID(botgroup_leader->GetBotID(), botgroup_id)) {
|
||||
c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadBotGroupIDByLeaderID(), botgroup_leader->GetCleanName());
|
||||
return;
|
||||
}
|
||||
@@ -5591,7 +5742,7 @@ void bot_subcommand_botgroup_create(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
botgroup_id = 0;
|
||||
if (!botdb.LoadBotGroupIDByMemberID(botgroup_leader->GetBotID(), botgroup_id)) {
|
||||
if (!database.botdb.LoadBotGroupIDByMemberID(botgroup_leader->GetBotID(), botgroup_id)) {
|
||||
c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadBotGroupIDByMemberID(), botgroup_leader->GetCleanName());
|
||||
return;
|
||||
}
|
||||
@@ -5606,7 +5757,7 @@ void bot_subcommand_botgroup_create(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!botdb.CreateBotGroup(botgroup_name_arg, botgroup_leader->GetBotID())) {
|
||||
if (!database.botdb.CreateBotGroup(botgroup_name_arg, botgroup_leader->GetBotID())) {
|
||||
c->Message(m_fail, "%s '%s'", BotDatabase::fail::CreateBotGroup(), botgroup_name_arg.c_str());
|
||||
safe_delete(group_inst);
|
||||
return;
|
||||
@@ -5636,7 +5787,7 @@ void bot_subcommand_botgroup_delete(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
uint32 botgroup_id = 0;
|
||||
if (!botdb.LoadBotGroupIDForLoadBotGroup(c->CharacterID(), botgroup_name_arg, botgroup_id)) {
|
||||
if (!database.botdb.LoadBotGroupIDForLoadBotGroup(c->CharacterID(), botgroup_name_arg, botgroup_id)) {
|
||||
c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadBotGroupIDForLoadBotGroup(), botgroup_name_arg.c_str());
|
||||
return;
|
||||
}
|
||||
@@ -5646,7 +5797,7 @@ void bot_subcommand_botgroup_delete(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
uint32 leader_id = 0;
|
||||
if (!botdb.LoadLeaderIDByBotGroupID(botgroup_id, leader_id)) {
|
||||
if (!database.botdb.LoadLeaderIDByBotGroupID(botgroup_id, leader_id)) {
|
||||
c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadLeaderIDByBotGroupID(), botgroup_name_arg.c_str());
|
||||
return;
|
||||
}
|
||||
@@ -5660,7 +5811,7 @@ void bot_subcommand_botgroup_delete(Client *c, const Seperator *sep)
|
||||
MyBots::PopulateSBL_BySpawnedBots(c, sbl);
|
||||
|
||||
std::map<uint32, std::list<uint32>> member_list;
|
||||
if (!botdb.LoadBotGroup(botgroup_name_arg, member_list)) {
|
||||
if (!database.botdb.LoadBotGroup(botgroup_name_arg, member_list)) {
|
||||
c->Message(m_fail, "%s '%s'", BotDatabase::fail::LoadBotGroup(), botgroup_name_arg.c_str());
|
||||
return;
|
||||
}
|
||||
@@ -5684,7 +5835,7 @@ void bot_subcommand_botgroup_delete(Client *c, const Seperator *sep)
|
||||
Bot::RemoveBotFromGroup(group_member, group_member->GetGroup());
|
||||
}
|
||||
|
||||
if (!botdb.DeleteBotGroup(leader_id)) {
|
||||
if (!database.botdb.DeleteBotGroup(leader_id)) {
|
||||
c->Message(m_fail, "%s '%s'", BotDatabase::fail::DeleteBotGroup(), botgroup_name_arg.c_str());
|
||||
return;
|
||||
}
|
||||
@@ -5702,7 +5853,7 @@ void bot_subcommand_botgroup_list(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
std::list<std::pair<std::string, std::string>> botgroups_list;
|
||||
if (!botdb.LoadBotGroupsListByOwnerID(c->CharacterID(), botgroups_list)) {
|
||||
if (!database.botdb.LoadBotGroupsListByOwnerID(c->CharacterID(), botgroups_list)) {
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::LoadBotGroupsListByOwnerID());
|
||||
return;
|
||||
}
|
||||
@@ -5734,7 +5885,7 @@ void bot_subcommand_botgroup_load(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
bool extant_flag = false;
|
||||
if (!botdb.QueryBotGroupExistence(botgroup_name_arg, extant_flag)) {
|
||||
if (!database.botdb.QueryBotGroupExistence(botgroup_name_arg, extant_flag)) {
|
||||
c->Message(m_fail, "%s for '%s'", BotDatabase::fail::QueryBotGroupExistence(), botgroup_name_arg.c_str());
|
||||
return;
|
||||
}
|
||||
@@ -5764,13 +5915,13 @@ void bot_subcommand_botgroup_load(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
uint32 botgroup_id = 0;
|
||||
if (!botdb.LoadBotGroupIDForLoadBotGroup(c->CharacterID(), botgroup_name_arg, botgroup_id) || !botgroup_id) {
|
||||
if (!database.botdb.LoadBotGroupIDForLoadBotGroup(c->CharacterID(), botgroup_name_arg, botgroup_id) || !botgroup_id) {
|
||||
c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadBotGroupIDForLoadBotGroup(), botgroup_name_arg.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
std::map<uint32, std::list<uint32>> member_list;
|
||||
if (!botdb.LoadBotGroup(botgroup_name_arg, member_list)) {
|
||||
if (!database.botdb.LoadBotGroup(botgroup_name_arg, member_list)) {
|
||||
c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadBotGroup(), botgroup_name_arg.c_str());
|
||||
return;
|
||||
}
|
||||
@@ -5783,7 +5934,7 @@ void bot_subcommand_botgroup_load(Client *c, const Seperator *sep)
|
||||
|
||||
if (RuleB(Bots, QuestableSpawnLimit)) {
|
||||
int allowed_bot_count = 0;
|
||||
if (!botdb.LoadQuestableSpawnCount(c->CharacterID(), allowed_bot_count)) {
|
||||
if (!database.botdb.LoadQuestableSpawnCount(c->CharacterID(), allowed_bot_count)) {
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::LoadQuestableSpawnCount());
|
||||
return;
|
||||
}
|
||||
@@ -5806,23 +5957,27 @@ void bot_subcommand_botgroup_load(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
uint32 leader_id = 0;
|
||||
if (!botdb.LoadLeaderIDByBotGroupName(botgroup_name_arg, leader_id)) {
|
||||
if (!database.botdb.LoadLeaderIDByBotGroupName(botgroup_name_arg, leader_id)) {
|
||||
c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadLeaderIDByBotGroupName(), botgroup_name_arg.c_str());
|
||||
return;
|
||||
}
|
||||
if (!leader_id) {
|
||||
c->Message(m_fail, "Can not locate bot-group leader id for '%s'", botgroup_name_arg.c_str());
|
||||
c->Message(m_fail, "Cannot locate bot-group leader id for '%s'", botgroup_name_arg.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
auto botgroup_leader = Bot::LoadBot(leader_id);
|
||||
if (!botgroup_leader) {
|
||||
c->Message(m_fail, "Could not spawn bot-group leader for '%s'", botgroup_name_arg.c_str());
|
||||
c->Message(m_fail, "Could not load bot-group leader for '%s'", botgroup_name_arg.c_str());
|
||||
safe_delete(botgroup_leader);
|
||||
return;
|
||||
}
|
||||
|
||||
botgroup_leader->Spawn(c);
|
||||
if (!botgroup_leader->Spawn(c)) {
|
||||
c->Message(m_fail, "Could not spawn bot-group leader %s for '%s'", botgroup_leader->GetName(), botgroup_name_arg.c_str());
|
||||
safe_delete(botgroup_leader);
|
||||
return;
|
||||
}
|
||||
|
||||
Group* group_inst = new Group(botgroup_leader);
|
||||
|
||||
@@ -5841,7 +5996,12 @@ void bot_subcommand_botgroup_load(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
botgroup_member->Spawn(c);
|
||||
if (!botgroup_member->Spawn(c)) {
|
||||
c->Message(m_fail, "Could not spawn bot '%s' (id: %i)", botgroup_member->GetName(), member_iter);
|
||||
safe_delete(botgroup_member);
|
||||
return;
|
||||
}
|
||||
|
||||
Bot::AddBotToGroup(botgroup_member, group_inst);
|
||||
}
|
||||
|
||||
@@ -5882,7 +6042,7 @@ void bot_subcommand_botgroup_remove_member(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!botdb.RemoveMemberFromBotGroup(group_member->GetBotID())) {
|
||||
if (!database.botdb.RemoveMemberFromBotGroup(group_member->GetBotID())) {
|
||||
c->Message(m_fail, "%s - '%s'", BotDatabase::fail::RemoveMemberFromBotGroup(), group_member->GetCleanName());
|
||||
return;
|
||||
}
|
||||
@@ -6504,7 +6664,7 @@ void bot_subcommand_heal_rotation_create(Client *c, const Seperator *sep)
|
||||
bool member_fail = false;
|
||||
bool target_fail = false;
|
||||
|
||||
if (!botdb.LoadHealRotation(creator_member, member_list, target_list, load_flag, member_fail, target_fail))
|
||||
if (!database.botdb.LoadHealRotation(creator_member, member_list, target_list, load_flag, member_fail, target_fail))
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::LoadHealRotation());
|
||||
|
||||
if (!load_flag) {
|
||||
@@ -6577,7 +6737,7 @@ void bot_subcommand_heal_rotation_delete(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
if (all_flag) {
|
||||
if (botdb.DeleteAllHealRotations(c->CharacterID()))
|
||||
if (database.botdb.DeleteAllHealRotations(c->CharacterID()))
|
||||
c->Message(m_action, "Succeeded in deleting all heal rotations");
|
||||
else
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::DeleteAllHealRotations());
|
||||
@@ -6600,7 +6760,7 @@ void bot_subcommand_heal_rotation_delete(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!botdb.DeleteHealRotation(current_member->GetBotID())) {
|
||||
if (!database.botdb.DeleteHealRotation(current_member->GetBotID())) {
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::DeleteHealRotation());
|
||||
return;
|
||||
}
|
||||
@@ -6887,7 +7047,7 @@ void bot_subcommand_heal_rotation_save(Client *c, const Seperator *sep)
|
||||
|
||||
bool member_fail = false;
|
||||
bool target_fail = false;
|
||||
if (!botdb.SaveHealRotation(current_member, member_fail, target_fail)) {
|
||||
if (!database.botdb.SaveHealRotation(current_member, member_fail, target_fail)) {
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::SaveHealRotation());
|
||||
return;
|
||||
}
|
||||
@@ -7078,35 +7238,33 @@ void bot_subcommand_inventory_list(Client *c, const Seperator *sep)
|
||||
const EQEmu::ItemData* item = nullptr;
|
||||
bool is2Hweapon = false;
|
||||
|
||||
std::string item_link;
|
||||
EQEmu::SayLinkEngine linker;
|
||||
linker.SetLinkType(EQEmu::saylink::SayLinkItemInst);
|
||||
|
||||
uint32 inventory_count = 0;
|
||||
for (int i = EQEmu::legacy::EQUIPMENT_BEGIN; i <= (EQEmu::legacy::EQUIPMENT_END + 1); ++i) {
|
||||
if ((i == EQEmu::inventory::slotSecondary) && is2Hweapon)
|
||||
for (int i = EQEmu::invslot::EQUIPMENT_BEGIN; i <= EQEmu::invslot::EQUIPMENT_END; ++i) {
|
||||
if ((i == EQEmu::invslot::slotSecondary) && is2Hweapon)
|
||||
continue;
|
||||
|
||||
inst = my_bot->CastToBot()->GetBotItem(i == 22 ? EQEmu::inventory::slotPowerSource : i);
|
||||
inst = my_bot->CastToBot()->GetBotItem(i);
|
||||
if (!inst || !inst->GetItem()) {
|
||||
c->Message(m_message, "I need something for my %s (slot %i)", GetBotEquipSlotName(i), (i == 22 ? EQEmu::inventory::slotPowerSource : i));
|
||||
c->Message(m_message, "I need something for my %s (slot %i)", EQEmu::invslot::GetInvPossessionsSlotName(i), i);
|
||||
continue;
|
||||
}
|
||||
|
||||
item = inst->GetItem();
|
||||
if ((i == EQEmu::inventory::slotPrimary) && item->IsType2HWeapon()) {
|
||||
if ((i == EQEmu::invslot::slotPrimary) && item->IsType2HWeapon()) {
|
||||
is2Hweapon = true;
|
||||
}
|
||||
|
||||
linker.SetItemInst(inst);
|
||||
item_link = linker.GenerateLink();
|
||||
c->Message(m_message, "Using %s in my %s (slot %i)", item_link.c_str(), GetBotEquipSlotName(i), (i == 22 ? EQEmu::inventory::slotPowerSource : i));
|
||||
c->Message(m_message, "Using %s in my %s (slot %i)", linker.GenerateLink().c_str(), EQEmu::invslot::GetInvPossessionsSlotName(i), i);
|
||||
|
||||
++inventory_count;
|
||||
}
|
||||
|
||||
uint32 database_count = 0;
|
||||
if (!botdb.QueryInventoryCount(my_bot->GetBotID(), database_count))
|
||||
if (!database.botdb.QueryInventoryCount(my_bot->GetBotID(), database_count))
|
||||
c->Message(m_unknown, "%s", BotDatabase::fail::QueryInventoryCount());
|
||||
|
||||
if (inventory_count != database_count)
|
||||
@@ -7139,8 +7297,8 @@ void bot_subcommand_inventory_remove(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
int slotId = atoi(sep->arg[1]);
|
||||
if (!sep->IsNumber(1) || ((slotId > EQEmu::legacy::EQUIPMENT_END || slotId < EQEmu::legacy::EQUIPMENT_BEGIN) && slotId != EQEmu::inventory::slotPowerSource)) {
|
||||
c->Message(m_fail, "Valid slots are 0-21 or 9999");
|
||||
if (!sep->IsNumber(1) || (slotId > EQEmu::invslot::EQUIPMENT_END || slotId < EQEmu::invslot::EQUIPMENT_BEGIN)) {
|
||||
c->Message(m_fail, "Valid slots are 0-22");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7154,7 +7312,7 @@ void bot_subcommand_inventory_remove(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
for (int m = EQEmu::inventory::socketBegin; m < EQEmu::inventory::SocketCount; ++m) {
|
||||
for (int m = EQEmu::invaug::SOCKET_BEGIN; m <= EQEmu::invaug::SOCKET_END; ++m) {
|
||||
if (!itminst)
|
||||
break;
|
||||
|
||||
@@ -7171,7 +7329,7 @@ void bot_subcommand_inventory_remove(Client *c, const Seperator *sep)
|
||||
std::string error_message;
|
||||
if (itm) {
|
||||
c->PushItemOnCursor(*itminst, true);
|
||||
if ((slotId == EQEmu::inventory::slotRange) || (slotId == EQEmu::inventory::slotAmmo) || (slotId == EQEmu::inventory::slotPrimary) || (slotId == EQEmu::inventory::slotSecondary))
|
||||
if ((slotId == EQEmu::invslot::slotRange) || (slotId == EQEmu::invslot::slotAmmo) || (slotId == EQEmu::invslot::slotPrimary) || (slotId == EQEmu::invslot::slotSecondary))
|
||||
my_bot->SetBotArcher(false);
|
||||
|
||||
my_bot->RemoveBotItemBySlot(slotId, &error_message);
|
||||
@@ -7181,36 +7339,36 @@ void bot_subcommand_inventory_remove(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
my_bot->BotRemoveEquipItem(slotId);
|
||||
my_bot->CalcBotStats();
|
||||
my_bot->CalcBotStats(c->GetBotOptionStatsUpdate());
|
||||
}
|
||||
|
||||
switch (slotId) {
|
||||
case EQEmu::inventory::slotCharm:
|
||||
case EQEmu::inventory::slotEar1:
|
||||
case EQEmu::inventory::slotHead:
|
||||
case EQEmu::inventory::slotFace:
|
||||
case EQEmu::inventory::slotEar2:
|
||||
case EQEmu::inventory::slotNeck:
|
||||
case EQEmu::inventory::slotBack:
|
||||
case EQEmu::inventory::slotWrist1:
|
||||
case EQEmu::inventory::slotWrist2:
|
||||
case EQEmu::inventory::slotRange:
|
||||
case EQEmu::inventory::slotPrimary:
|
||||
case EQEmu::inventory::slotSecondary:
|
||||
case EQEmu::inventory::slotFinger1:
|
||||
case EQEmu::inventory::slotFinger2:
|
||||
case EQEmu::inventory::slotChest:
|
||||
case EQEmu::inventory::slotWaist:
|
||||
case EQEmu::inventory::slotPowerSource:
|
||||
case EQEmu::inventory::slotAmmo:
|
||||
c->Message(m_message, "My %s is %s unequipped", GetBotEquipSlotName(slotId), ((itm) ? ("now") : ("already")));
|
||||
case EQEmu::invslot::slotCharm:
|
||||
case EQEmu::invslot::slotEar1:
|
||||
case EQEmu::invslot::slotHead:
|
||||
case EQEmu::invslot::slotFace:
|
||||
case EQEmu::invslot::slotEar2:
|
||||
case EQEmu::invslot::slotNeck:
|
||||
case EQEmu::invslot::slotBack:
|
||||
case EQEmu::invslot::slotWrist1:
|
||||
case EQEmu::invslot::slotWrist2:
|
||||
case EQEmu::invslot::slotRange:
|
||||
case EQEmu::invslot::slotPrimary:
|
||||
case EQEmu::invslot::slotSecondary:
|
||||
case EQEmu::invslot::slotFinger1:
|
||||
case EQEmu::invslot::slotFinger2:
|
||||
case EQEmu::invslot::slotChest:
|
||||
case EQEmu::invslot::slotWaist:
|
||||
case EQEmu::invslot::slotPowerSource:
|
||||
case EQEmu::invslot::slotAmmo:
|
||||
c->Message(m_message, "My %s is %s unequipped", EQEmu::invslot::GetInvPossessionsSlotName(slotId), ((itm) ? ("now") : ("already")));
|
||||
break;
|
||||
case EQEmu::inventory::slotShoulders:
|
||||
case EQEmu::inventory::slotArms:
|
||||
case EQEmu::inventory::slotHands:
|
||||
case EQEmu::inventory::slotLegs:
|
||||
case EQEmu::inventory::slotFeet:
|
||||
c->Message(m_message, "My %s are %s unequipped", GetBotEquipSlotName(slotId), ((itm) ? ("now") : ("already")));
|
||||
case EQEmu::invslot::slotShoulders:
|
||||
case EQEmu::invslot::slotArms:
|
||||
case EQEmu::invslot::slotHands:
|
||||
case EQEmu::invslot::slotLegs:
|
||||
case EQEmu::invslot::slotFeet:
|
||||
c->Message(m_message, "My %s are %s unequipped", EQEmu::invslot::GetInvPossessionsSlotName(slotId), ((itm) ? ("now") : ("already")));
|
||||
break;
|
||||
default:
|
||||
c->Message(m_fail, "I'm soo confused...");
|
||||
@@ -7243,17 +7401,17 @@ void bot_subcommand_inventory_window(Client *c, const Seperator *sep)
|
||||
|
||||
std::string window_text;
|
||||
//std::string item_link;
|
||||
//Client::TextLink linker;
|
||||
//linker.SetLinkType(linker.linkItemInst);
|
||||
//EQEmu::SayLinkEngine linker;
|
||||
//linker.SetLinkType(EQEmu::saylink::SayLinkItemInst);
|
||||
|
||||
for (int i = EQEmu::legacy::EQUIPMENT_BEGIN; i <= (EQEmu::legacy::EQUIPMENT_END + 1); ++i) {
|
||||
for (int i = EQEmu::invslot::EQUIPMENT_BEGIN; i <= EQEmu::invslot::EQUIPMENT_END; ++i) {
|
||||
const EQEmu::ItemData* item = nullptr;
|
||||
const EQEmu::ItemInstance* inst = my_bot->CastToBot()->GetBotItem(i == 22 ? EQEmu::inventory::slotPowerSource : i);
|
||||
const EQEmu::ItemInstance* inst = my_bot->CastToBot()->GetBotItem(i);
|
||||
if (inst)
|
||||
item = inst->GetItem();
|
||||
|
||||
window_text.append("<c \"#FFFFFF\">");
|
||||
window_text.append(GetBotEquipSlotName(i == 22 ? EQEmu::inventory::slotPowerSource : i));
|
||||
window_text.append(EQEmu::invslot::GetInvPossessionsSlotName(i));
|
||||
window_text.append(": ");
|
||||
if (item) {
|
||||
//window_text.append("</c>");
|
||||
@@ -7526,7 +7684,7 @@ uint32 helper_bot_create(Client *bot_owner, std::string bot_name, uint8 bot_clas
|
||||
}
|
||||
|
||||
bool available_flag = false;
|
||||
if (!botdb.QueryNameAvailablity(bot_name, available_flag)) {
|
||||
if (!database.botdb.QueryNameAvailablity(bot_name, available_flag)) {
|
||||
bot_owner->Message(m_fail, "%s for '%s'", BotDatabase::fail::QueryNameAvailablity(), bot_name.c_str());
|
||||
return bot_id;
|
||||
}
|
||||
@@ -7535,21 +7693,40 @@ uint32 helper_bot_create(Client *bot_owner, std::string bot_name, uint8 bot_clas
|
||||
return bot_id;
|
||||
}
|
||||
|
||||
auto class_bit = GetPlayerClassBit(bot_class);
|
||||
if ((class_bit & RuleI(Bots, AllowedClasses)) == PLAYER_CLASS_UNKNOWN_BIT) {
|
||||
bot_owner->Message(m_fail, "Class '%s' bots are not allowed on this server", GetPlayerClassName(bot_class));
|
||||
return bot_id;
|
||||
}
|
||||
|
||||
auto race_bit = GetPlayerRaceBit(bot_race);
|
||||
if ((race_bit & RuleI(Bots, AllowedRaces)) == PLAYER_RACE_UNKNOWN_BIT) {
|
||||
bot_owner->Message(m_fail, "Race '%s' bots are not allowed on this server", GetPlayerRaceName(bot_class));
|
||||
return bot_id;
|
||||
}
|
||||
|
||||
if (!Bot::IsValidRaceClassCombo(bot_race, bot_class)) {
|
||||
bot_owner->Message(m_fail, "'%s'(%u):'%s'(%u) is an invalid race-class combination",
|
||||
Bot::RaceIdToString(bot_race).c_str(), bot_race, Bot::ClassIdToString(bot_class).c_str(), bot_class);
|
||||
return bot_id;
|
||||
}
|
||||
|
||||
if (bot_gender > FEMALE) {
|
||||
bot_owner->Message(m_fail, "gender: %u(M), %u(F)", MALE, FEMALE);
|
||||
if (bot_gender > FEMALE || (((1 << bot_gender) & RuleI(Bots, AllowedGenders)) == 0)) {
|
||||
if (RuleI(Bots, AllowedGenders) == 3)
|
||||
bot_owner->Message(m_fail, "gender: %u(M), %u(F)", MALE, FEMALE);
|
||||
else if (RuleI(Bots, AllowedGenders) == 2)
|
||||
bot_owner->Message(m_fail, "gender: %u(F)", FEMALE);
|
||||
else if (RuleI(Bots, AllowedGenders) == 1)
|
||||
bot_owner->Message(m_fail, "gender: %u(M)", MALE);
|
||||
else
|
||||
bot_owner->Message(m_fail, "gender: ERROR - No valid genders exist");
|
||||
return bot_id;
|
||||
}
|
||||
|
||||
uint32 max_bot_count = RuleI(Bots, CreationLimit);
|
||||
|
||||
uint32 bot_count = 0;
|
||||
if (!botdb.QueryBotCount(bot_owner->CharacterID(), bot_count)) {
|
||||
if (!database.botdb.QueryBotCount(bot_owner->CharacterID(), bot_count)) {
|
||||
bot_owner->Message(m_fail, "%s", BotDatabase::fail::QueryBotCount());
|
||||
return bot_id;
|
||||
}
|
||||
@@ -7558,16 +7735,7 @@ uint32 helper_bot_create(Client *bot_owner, std::string bot_name, uint8 bot_clas
|
||||
return bot_id;
|
||||
}
|
||||
|
||||
auto DefaultNPCTypeStruct = Bot::CreateDefaultNPCTypeStructForBot(
|
||||
bot_name.c_str(),
|
||||
"",
|
||||
bot_owner->GetLevel(),
|
||||
bot_race,
|
||||
bot_class,
|
||||
bot_gender
|
||||
);
|
||||
|
||||
auto my_bot = new Bot(DefaultNPCTypeStruct, bot_owner);
|
||||
auto my_bot = new Bot(Bot::CreateDefaultNPCTypeStructForBot(bot_name.c_str(), "", bot_owner->GetLevel(), bot_race, bot_class, bot_gender), bot_owner);
|
||||
|
||||
if (!my_bot->Save()) {
|
||||
bot_owner->Message(m_unknown, "Failed to create '%s' due to unknown cause", my_bot->GetCleanName());
|
||||
@@ -7625,7 +7793,7 @@ bool helper_cast_standard_spell(Bot* casting_bot, Mob* target_mob, int spell_id,
|
||||
if (annouce_cast)
|
||||
Bot::BotGroupSay(casting_bot, "Attempting to cast '%s' on %s", spells[spell_id].name, target_mob->GetCleanName());
|
||||
|
||||
return casting_bot->CastSpell(spell_id, target_mob->GetID(), EQEmu::CastingSlot::Gem2, -1, -1, dont_root_before);
|
||||
return casting_bot->CastSpell(spell_id, target_mob->GetID(), EQEmu::spells::CastingSlot::Gem2, -1, -1, dont_root_before);
|
||||
}
|
||||
|
||||
bool helper_command_alias_fail(Client *bot_owner, const char* command_handler, const char *alias, const char *command)
|
||||
|
||||
@@ -575,6 +575,7 @@ void bot_command_levitation(Client *c, const Seperator *sep);
|
||||
void bot_command_lull(Client *c, const Seperator *sep);
|
||||
void bot_command_mesmerize(Client *c, const Seperator *sep);
|
||||
void bot_command_movement_speed(Client *c, const Seperator *sep);
|
||||
void bot_command_owner_option(Client *c, const Seperator *sep);
|
||||
void bot_command_pet(Client *c, const Seperator *sep);
|
||||
void bot_command_pick_lock(Client *c, const Seperator *sep);
|
||||
void bot_command_pull(Client *c, const Seperator *sep);
|
||||
@@ -612,6 +613,7 @@ void bot_subcommand_bot_out_of_combat(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_report(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_spawn(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_stance(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_stop_melee_level(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_summon(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_tattoo(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_toggle_archer(Client *c, const Seperator *sep);
|
||||
|
||||
+239
-172
File diff suppressed because it is too large
Load Diff
+9
-12
@@ -22,16 +22,15 @@
|
||||
|
||||
#ifdef BOTS
|
||||
|
||||
#include "../common/dbcore.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
class Bot;
|
||||
class Client;
|
||||
struct BotsAvailableList;
|
||||
struct InspectMessage_Struct;
|
||||
|
||||
namespace EQEmu
|
||||
{
|
||||
@@ -40,15 +39,9 @@ namespace EQEmu
|
||||
}
|
||||
|
||||
|
||||
class BotDatabase : public DBcore
|
||||
class BotDatabase
|
||||
{
|
||||
public:
|
||||
BotDatabase();
|
||||
BotDatabase(const char* host, const char* user, const char* passwd, const char* database, uint32 port);
|
||||
virtual ~BotDatabase();
|
||||
|
||||
bool Connect(const char* host, const char* user, const char* passwd, const char* database, uint32 port);
|
||||
|
||||
bool LoadBotCommandSettings(std::map<std::string, std::pair<uint8, std::vector<std::string>>> &bot_command_settings);
|
||||
bool LoadBotSpellCastingChances();
|
||||
|
||||
@@ -143,6 +136,11 @@ public:
|
||||
bool CreateCloneBot(const uint32 owner_id, const uint32 bot_id, const std::string& clone_name, uint32& clone_id);
|
||||
bool CreateCloneBotInventory(const uint32 owner_id, const uint32 bot_id, const uint32 clone_id);
|
||||
|
||||
bool SaveStopMeleeLevel(const uint32 owner_id, const uint32 bot_id, const uint8 sml_value);
|
||||
|
||||
bool LoadOwnerOptions(Client *owner);
|
||||
bool SaveOwnerOptionDeathMarquee(const uint32 owner_id, const bool flag);
|
||||
bool SaveOwnerOptionStatsUpdate(const uint32 owner_id, const bool flag);
|
||||
|
||||
/* Bot bot-group functions */
|
||||
bool QueryBotGroupExistence(const std::string& botgroup_name, bool& extant_flag);
|
||||
@@ -253,6 +251,7 @@ public:
|
||||
static const char* SaveAllFollowDistances();
|
||||
static const char* CreateCloneBot();
|
||||
static const char* CreateCloneBotInventory();
|
||||
static const char* SaveStopMeleeLevel();
|
||||
|
||||
/* fail::Bot bot-group functions */
|
||||
static const char* QueryBotGroupExistence();
|
||||
@@ -290,8 +289,6 @@ public:
|
||||
std::string query;
|
||||
};
|
||||
|
||||
extern BotDatabase botdb;
|
||||
|
||||
#endif
|
||||
|
||||
#endif // BOTS
|
||||
|
||||
+83
-84
@@ -192,25 +192,24 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) {
|
||||
else {
|
||||
float hpRatioToCast = 0.0f;
|
||||
|
||||
switch(this->GetBotStance())
|
||||
{
|
||||
case BotStanceEfficient:
|
||||
case BotStanceAggressive:
|
||||
hpRatioToCast = isPrimaryHealer?90.0f:50.0f;
|
||||
break;
|
||||
case BotStanceBalanced:
|
||||
hpRatioToCast = isPrimaryHealer?95.0f:75.0f;
|
||||
break;
|
||||
case BotStanceReactive:
|
||||
hpRatioToCast = isPrimaryHealer?100.0f:90.0f;
|
||||
break;
|
||||
case BotStanceBurn:
|
||||
case BotStanceBurnAE:
|
||||
hpRatioToCast = isPrimaryHealer?75.0f:25.0f;
|
||||
break;
|
||||
default:
|
||||
hpRatioToCast = isPrimaryHealer?100.0f:0.0f;
|
||||
break;
|
||||
switch(this->GetBotStance()) {
|
||||
case EQEmu::constants::stanceEfficient:
|
||||
case EQEmu::constants::stanceAggressive:
|
||||
hpRatioToCast = isPrimaryHealer?90.0f:50.0f;
|
||||
break;
|
||||
case EQEmu::constants::stanceBalanced:
|
||||
hpRatioToCast = isPrimaryHealer?95.0f:75.0f;
|
||||
break;
|
||||
case EQEmu::constants::stanceReactive:
|
||||
hpRatioToCast = isPrimaryHealer?100.0f:90.0f;
|
||||
break;
|
||||
case EQEmu::constants::stanceBurn:
|
||||
case EQEmu::constants::stanceBurnAE:
|
||||
hpRatioToCast = isPrimaryHealer?75.0f:25.0f;
|
||||
break;
|
||||
default:
|
||||
hpRatioToCast = isPrimaryHealer?100.0f:0.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
//If we're at specified mana % or below, don't heal as hybrid
|
||||
@@ -381,23 +380,22 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) {
|
||||
{
|
||||
float manaRatioToCast = 75.0f;
|
||||
|
||||
switch(this->GetBotStance())
|
||||
{
|
||||
case BotStanceEfficient:
|
||||
manaRatioToCast = 90.0f;
|
||||
break;
|
||||
case BotStanceBalanced:
|
||||
case BotStanceAggressive:
|
||||
manaRatioToCast = 75.0f;
|
||||
break;
|
||||
case BotStanceReactive:
|
||||
case BotStanceBurn:
|
||||
case BotStanceBurnAE:
|
||||
manaRatioToCast = 50.0f;
|
||||
break;
|
||||
default:
|
||||
manaRatioToCast = 75.0f;
|
||||
break;
|
||||
switch(this->GetBotStance()) {
|
||||
case EQEmu::constants::stanceEfficient:
|
||||
manaRatioToCast = 90.0f;
|
||||
break;
|
||||
case EQEmu::constants::stanceBalanced:
|
||||
case EQEmu::constants::stanceAggressive:
|
||||
manaRatioToCast = 75.0f;
|
||||
break;
|
||||
case EQEmu::constants::stanceReactive:
|
||||
case EQEmu::constants::stanceBurn:
|
||||
case EQEmu::constants::stanceBurnAE:
|
||||
manaRatioToCast = 50.0f;
|
||||
break;
|
||||
default:
|
||||
manaRatioToCast = 75.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
//If we're at specified mana % or below, don't rune as enchanter
|
||||
@@ -461,25 +459,24 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) {
|
||||
{
|
||||
float manaRatioToCast = 75.0f;
|
||||
|
||||
switch(this->GetBotStance())
|
||||
{
|
||||
case BotStanceEfficient:
|
||||
manaRatioToCast = 90.0f;
|
||||
break;
|
||||
case BotStanceBalanced:
|
||||
manaRatioToCast = 75.0f;
|
||||
break;
|
||||
case BotStanceReactive:
|
||||
case BotStanceAggressive:
|
||||
manaRatioToCast = 50.0f;
|
||||
break;
|
||||
case BotStanceBurn:
|
||||
case BotStanceBurnAE:
|
||||
manaRatioToCast = 25.0f;
|
||||
break;
|
||||
default:
|
||||
manaRatioToCast = 50.0f;
|
||||
break;
|
||||
switch(this->GetBotStance()) {
|
||||
case EQEmu::constants::stanceEfficient:
|
||||
manaRatioToCast = 90.0f;
|
||||
break;
|
||||
case EQEmu::constants::stanceBalanced:
|
||||
manaRatioToCast = 75.0f;
|
||||
break;
|
||||
case EQEmu::constants::stanceReactive:
|
||||
case EQEmu::constants::stanceAggressive:
|
||||
manaRatioToCast = 50.0f;
|
||||
break;
|
||||
case EQEmu::constants::stanceBurn:
|
||||
case EQEmu::constants::stanceBurnAE:
|
||||
manaRatioToCast = 25.0f;
|
||||
break;
|
||||
default:
|
||||
manaRatioToCast = 50.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
//If we're at specified mana % or below, don't nuke as cleric or enchanter
|
||||
@@ -1310,7 +1307,7 @@ bool Bot::AI_EngagedCastCheck() {
|
||||
AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting.
|
||||
|
||||
uint8 botClass = GetClass();
|
||||
BotStanceType botStance = GetBotStance();
|
||||
EQEmu::constants::StanceType botStance = GetBotStance();
|
||||
bool mayGetAggro = HasOrMayGetAggro();
|
||||
|
||||
Log(Logs::Detail, Logs::AI, "Engaged autocast check triggered (BOTS). Trying to cast healing spells then maybe offensive spells.");
|
||||
@@ -2573,79 +2570,79 @@ bool Bot::CheckDisciplineRecastTimers(Bot *caster, int timer_index) {
|
||||
|
||||
uint8 Bot::GetChanceToCastBySpellType(uint32 spellType)
|
||||
{
|
||||
uint8 spell_type_index = MaxSpellTypes;
|
||||
uint8 spell_type_index = SPELL_TYPE_COUNT;
|
||||
switch (spellType) {
|
||||
case SpellType_Nuke:
|
||||
spell_type_index = SpellType_NukeIndex;
|
||||
spell_type_index = spellTypeIndexNuke;
|
||||
break;
|
||||
case SpellType_Heal:
|
||||
spell_type_index = SpellType_HealIndex;
|
||||
spell_type_index = spellTypeIndexHeal;
|
||||
break;
|
||||
case SpellType_Root:
|
||||
spell_type_index = SpellType_RootIndex;
|
||||
spell_type_index = spellTypeIndexRoot;
|
||||
break;
|
||||
case SpellType_Buff:
|
||||
spell_type_index = SpellType_BuffIndex;
|
||||
spell_type_index = spellTypeIndexBuff;
|
||||
break;
|
||||
case SpellType_Escape:
|
||||
spell_type_index = SpellType_EscapeIndex;
|
||||
spell_type_index = spellTypeIndexEscape;
|
||||
break;
|
||||
case SpellType_Pet:
|
||||
spell_type_index = SpellType_PetIndex;
|
||||
spell_type_index = spellTypeIndexPet;
|
||||
break;
|
||||
case SpellType_Lifetap:
|
||||
spell_type_index = SpellType_LifetapIndex;
|
||||
spell_type_index = spellTypeIndexLifetap;
|
||||
break;
|
||||
case SpellType_Snare:
|
||||
spell_type_index = SpellType_SnareIndex;
|
||||
spell_type_index = spellTypeIndexSnare;
|
||||
break;
|
||||
case SpellType_DOT:
|
||||
spell_type_index = SpellType_DOTIndex;
|
||||
spell_type_index = spellTypeIndexDot;
|
||||
break;
|
||||
case SpellType_Dispel:
|
||||
spell_type_index = SpellType_DispelIndex;
|
||||
spell_type_index = spellTypeIndexDispel;
|
||||
break;
|
||||
case SpellType_InCombatBuff:
|
||||
spell_type_index = SpellType_InCombatBuffIndex;
|
||||
spell_type_index = spellTypeIndexInCombatBuff;
|
||||
break;
|
||||
case SpellType_Mez:
|
||||
spell_type_index = SpellType_MezIndex;
|
||||
spell_type_index = spellTypeIndexMez;
|
||||
break;
|
||||
case SpellType_Charm:
|
||||
spell_type_index = SpellType_CharmIndex;
|
||||
spell_type_index = spellTypeIndexCharm;
|
||||
break;
|
||||
case SpellType_Slow:
|
||||
spell_type_index = SpellType_SlowIndex;
|
||||
spell_type_index = spellTypeIndexSlow;
|
||||
break;
|
||||
case SpellType_Debuff:
|
||||
spell_type_index = SpellType_DebuffIndex;
|
||||
spell_type_index = spellTypeIndexDebuff;
|
||||
break;
|
||||
case SpellType_Cure:
|
||||
spell_type_index = SpellType_CureIndex;
|
||||
spell_type_index = spellTypeIndexCure;
|
||||
break;
|
||||
case SpellType_Resurrect:
|
||||
spell_type_index = SpellType_ResurrectIndex;
|
||||
spell_type_index = spellTypeIndexResurrect;
|
||||
break;
|
||||
case SpellType_HateRedux:
|
||||
spell_type_index = SpellType_HateReduxIndex;
|
||||
spell_type_index = spellTypeIndexHateRedux;
|
||||
break;
|
||||
case SpellType_InCombatBuffSong:
|
||||
spell_type_index = SpellType_InCombatBuffSongIndex;
|
||||
spell_type_index = spellTypeIndexInCombatBuffSong;
|
||||
break;
|
||||
case SpellType_OutOfCombatBuffSong:
|
||||
spell_type_index = SpellType_OutOfCombatBuffSongIndex;
|
||||
spell_type_index = spellTypeIndexOutOfCombatBuffSong;
|
||||
break;
|
||||
case SpellType_PreCombatBuff:
|
||||
spell_type_index = SpellType_PreCombatBuffIndex;
|
||||
spell_type_index = spellTypeIndexPreCombatBuff;
|
||||
break;
|
||||
case SpellType_PreCombatBuffSong:
|
||||
spell_type_index = SpellType_PreCombatBuffSongIndex;
|
||||
spell_type_index = spellTypeIndexPreCombatBuffSong;
|
||||
break;
|
||||
default:
|
||||
spell_type_index = MaxSpellTypes;
|
||||
spell_type_index = SPELL_TYPE_COUNT;
|
||||
break;
|
||||
}
|
||||
if (spell_type_index >= MaxSpellTypes)
|
||||
if (spell_type_index >= SPELL_TYPE_COUNT)
|
||||
return 0;
|
||||
|
||||
uint8 class_index = GetClass();
|
||||
@@ -2653,11 +2650,13 @@ uint8 Bot::GetChanceToCastBySpellType(uint32 spellType)
|
||||
return 0;
|
||||
--class_index;
|
||||
|
||||
uint8 stance_index = (uint8)GetBotStance();
|
||||
if (stance_index >= MaxStances)
|
||||
EQEmu::constants::StanceType stance_type = GetBotStance();
|
||||
if (stance_type < EQEmu::constants::stancePassive || stance_type > EQEmu::constants::stanceBurnAE)
|
||||
return 0;
|
||||
|
||||
uint8 stance_index = EQEmu::constants::ConvertStanceTypeToIndex(stance_type);
|
||||
uint8 type_index = nHSND;
|
||||
|
||||
if (HasGroup()) {
|
||||
if (IsGroupHealer()/* || IsRaidHealer()*/)
|
||||
type_index |= pH;
|
||||
@@ -2669,7 +2668,7 @@ uint8 Bot::GetChanceToCastBySpellType(uint32 spellType)
|
||||
type_index |= pD;
|
||||
}
|
||||
|
||||
return botdb.GetSpellCastingChance(spell_type_index, class_index, stance_index, type_index);
|
||||
return database.botdb.GetSpellCastingChance(spell_type_index, class_index, stance_index, type_index);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+445
-547
File diff suppressed because it is too large
Load Diff
+78
-56
@@ -246,10 +246,21 @@ public:
|
||||
std::unordered_map<Mob *, float> close_mobs;
|
||||
bool is_client_moving;
|
||||
|
||||
void SetDisplayMobInfoWindow(bool display_mob_info_window);
|
||||
bool GetDisplayMobInfoWindow() const;
|
||||
|
||||
bool IsDevToolsWindowEnabled() const;
|
||||
void SetDevToolsWindowEnabled(bool dev_tools_window_enabled);
|
||||
|
||||
void SetPrimaryWeaponOrnamentation(uint32 model_id);
|
||||
void SetSecondaryWeaponOrnamentation(uint32 model_id);
|
||||
|
||||
bool GotoPlayer(std::string player_name);
|
||||
|
||||
//abstract virtual function implementations required by base abstract class
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill);
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
||||
ExtraAttackOptions *opts = nullptr);
|
||||
virtual bool HasRaid() { return (GetRaid() ? true : false); }
|
||||
virtual bool HasGroup() { return (GetGroup() ? true : false); }
|
||||
@@ -322,8 +333,8 @@ public:
|
||||
void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho);
|
||||
bool ShouldISpawnFor(Client *c) { return !GMHideMe(c) && !IsHoveringForRespawn(); }
|
||||
virtual bool Process();
|
||||
void ProcessPackets();
|
||||
void LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32 price, const EQEmu::ItemData* item, bool buying);
|
||||
void SendPacketQueue(bool Block = true);
|
||||
void QueuePacket(const EQApplicationPacket* app, bool ack_req = true, CLIENT_CONN_STATUS = CLIENT_CONNECTINGALL, eqFilterType filter=FilterNone);
|
||||
void FastQueuePacket(EQApplicationPacket** app, bool ack_req = true, CLIENT_CONN_STATUS = CLIENT_CONNECTINGALL);
|
||||
void ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_skill, const char* orig_message, const char* targetname=nullptr);
|
||||
@@ -346,7 +357,7 @@ public:
|
||||
void SetHideMe(bool hm);
|
||||
inline uint16 GetPort() const { return port; }
|
||||
bool IsDead() const { return(dead); }
|
||||
bool IsUnconscious() const { return ((cur_hp <= 0) ? true : false); }
|
||||
bool IsUnconscious() const { return ((current_hp <= 0) ? true : false); }
|
||||
inline bool IsLFP() { return LFP; }
|
||||
void UpdateLFP();
|
||||
|
||||
@@ -395,7 +406,7 @@ public:
|
||||
void SetGM(bool toggle);
|
||||
void SetPVP(bool toggle, bool message = true);
|
||||
|
||||
inline bool GetPVP() const { return m_pp.pvp != 0; }
|
||||
inline bool GetPVP(bool inc_temp = true) const { return m_pp.pvp != 0 || (inc_temp && temp_pvp); }
|
||||
inline bool GetGM() const { return m_pp.gm != 0; }
|
||||
|
||||
inline void SetBaseClass(uint32 i) { m_pp.class_=i; }
|
||||
@@ -548,10 +559,10 @@ public:
|
||||
virtual int GetCurrentBuffSlots() const;
|
||||
virtual int GetCurrentSongSlots() const;
|
||||
virtual int GetCurrentDiscSlots() const { return 1; }
|
||||
virtual int GetMaxBuffSlots() const { return EQEmu::constants::LongBuffs; }
|
||||
virtual int GetMaxSongSlots() const { return EQEmu::constants::ShortBuffs; }
|
||||
virtual int GetMaxDiscSlots() const { return EQEmu::constants::DiscBuffs; }
|
||||
virtual int GetMaxTotalSlots() const { return EQEmu::constants::TotalBuffs; }
|
||||
virtual int GetMaxBuffSlots() const { return EQEmu::spells::LONG_BUFFS; }
|
||||
virtual int GetMaxSongSlots() const { return EQEmu::spells::SHORT_BUFFS; }
|
||||
virtual int GetMaxDiscSlots() const { return EQEmu::spells::DISC_BUFFS; }
|
||||
virtual int GetMaxTotalSlots() const { return EQEmu::spells::TOTAL_BUFFS; }
|
||||
virtual uint32 GetFirstBuffSlot(bool disc, bool song);
|
||||
virtual uint32 GetLastBuffSlot(bool disc, bool song);
|
||||
virtual void InitializeBuffSlots();
|
||||
@@ -697,7 +708,9 @@ public:
|
||||
void SendGuildJoin(GuildJoin_Struct* gj);
|
||||
void RefreshGuildInfo();
|
||||
|
||||
|
||||
int GetClientMaxLevel() const { return client_max_level; }
|
||||
void SetClientMaxLevel(int max_level) { client_max_level = max_level; }
|
||||
|
||||
void CheckManaEndUpdate();
|
||||
void SendManaUpdate();
|
||||
void SendEnduranceUpdate();
|
||||
@@ -768,15 +781,21 @@ public:
|
||||
void UnmemSpell(int slot, bool update_client = true);
|
||||
void UnmemSpellBySpellID(int32 spell_id);
|
||||
void UnmemSpellAll(bool update_client = true);
|
||||
uint16 FindMemmedSpellBySlot(int slot);
|
||||
int MemmedCount();
|
||||
void ScribeSpell(uint16 spell_id, int slot, bool update_client = true);
|
||||
void UnscribeSpell(int slot, bool update_client = true);
|
||||
void UnscribeSpellAll(bool update_client = true);
|
||||
void UntrainDisc(int slot, bool update_client = true);
|
||||
void UntrainDiscAll(bool update_client = true);
|
||||
bool SpellGlobalCheck(uint16 Spell_ID, uint32 Char_ID);
|
||||
bool SpellGlobalCheck(uint16 spell_id, uint32 char_id);
|
||||
bool SpellBucketCheck(uint16 spell_id, uint32 char_id);
|
||||
uint32 GetCharMaxLevelFromQGlobal();
|
||||
uint32 GetCharMaxLevelFromBucket();
|
||||
|
||||
inline bool IsStanding() const {return (playeraction == 0);}
|
||||
inline bool IsSitting() const {return (playeraction == 1);}
|
||||
inline bool IsCrouching() const {return (playeraction == 2);}
|
||||
inline bool IsBecomeNPC() const { return npcflag; }
|
||||
inline uint8 GetBecomeNPCLevel() const { return npclevel; }
|
||||
inline void SetBecomeNPC(bool flag) { npcflag = flag; }
|
||||
@@ -788,7 +807,7 @@ public:
|
||||
#ifdef PACKET_PROFILER
|
||||
void DumpPacketProfile() { if(eqs) eqs->DumpPacketProfile(); }
|
||||
#endif
|
||||
uint32 GetEquipment(uint8 material_slot) const; // returns item id
|
||||
uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const; // returns item id
|
||||
uint32 GetEquipmentColor(uint8 material_slot) const;
|
||||
virtual void UpdateEquipmentLight() { m_Light.Type[EQEmu::lightsource::LightEquipment] = m_inv.FindBrightestLightType(); m_Light.Level[EQEmu::lightsource::LightEquipment] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightEquipment]); }
|
||||
|
||||
@@ -803,6 +822,7 @@ public:
|
||||
|
||||
void NPCSpawn(NPC *target_npc, const char *identifier, uint32 extra = 0);
|
||||
|
||||
void Disarm(Client* disarmer, int chance);
|
||||
bool BindWound(Mob* bindmob, bool start, bool fail = false);
|
||||
void SetTradeskillObject(Object* object) { m_tradeskill_object = object; }
|
||||
Object* GetTradeskillObject() { return m_tradeskill_object; }
|
||||
@@ -816,7 +836,7 @@ public:
|
||||
void ChangeTributeSettings(TributeInfo_Struct *t);
|
||||
void SendTributeTimer();
|
||||
void ToggleTribute(bool enabled);
|
||||
void SendPathPacket(std::vector<FindPerson_Point> &path);
|
||||
void SendPathPacket(const std::vector<FindPerson_Point> &path);
|
||||
|
||||
inline PTimerList &GetPTimers() { return(p_timers); }
|
||||
|
||||
@@ -850,7 +870,6 @@ public:
|
||||
void SetAATitle(const char *Title);
|
||||
void SetTitleSuffix(const char *txt);
|
||||
void MemorizeSpell(uint32 slot, uint32 spellid, uint32 scribing);
|
||||
int32 acmod();
|
||||
|
||||
// Item methods
|
||||
void EVENT_ITEM_ScriptStopReturn();
|
||||
@@ -871,10 +890,11 @@ public:
|
||||
void QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call = false);
|
||||
void PutLootInInventory(int16 slot_id, const EQEmu::ItemInstance &inst, ServerLootItem_Struct** bag_item_data = 0);
|
||||
bool AutoPutLootInInventory(EQEmu::ItemInstance& inst, bool try_worn = false, bool try_cursor = true, ServerLootItem_Struct** bag_item_data = 0);
|
||||
bool SummonItem(uint32 item_id, int16 charges = -1, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, bool attuned = false, uint16 to_slot = EQEmu::inventory::slotCursor, uint32 ornament_icon = 0, uint32 ornament_idfile = 0, uint32 ornament_hero_model = 0);
|
||||
bool SummonItem(uint32 item_id, int16 charges = -1, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, bool attuned = false, uint16 to_slot = EQEmu::invslot::slotCursor, uint32 ornament_icon = 0, uint32 ornament_idfile = 0, uint32 ornament_hero_model = 0);
|
||||
void SetStats(uint8 type,int16 set_val);
|
||||
void IncStats(uint8 type,int16 increase_val);
|
||||
void DropItem(int16 slot_id, bool recurse = true);
|
||||
void DropItemQS(EQEmu::ItemInstance* inst, bool pickup);
|
||||
|
||||
int GetItemLinkHash(const EQEmu::ItemInstance* inst); // move to ItemData..or make use of the pre-calculated database field
|
||||
|
||||
@@ -957,23 +977,7 @@ public:
|
||||
void SendRules(Client* client);
|
||||
std::list<std::string> consent_list;
|
||||
|
||||
//Anti-Cheat Stuff
|
||||
uint32 m_TimeSinceLastPositionCheck;
|
||||
float m_DistanceSinceLastPositionCheck;
|
||||
bool m_CheatDetectMoved;
|
||||
void SetShadowStepExemption(bool v);
|
||||
void SetKnockBackExemption(bool v);
|
||||
void SetPortExemption(bool v);
|
||||
void SetSenseExemption(bool v) { m_SenseExemption = v; }
|
||||
void SetAssistExemption(bool v) { m_AssistExemption = v; }
|
||||
const bool IsShadowStepExempted() const { return m_ShadowStepExemption; }
|
||||
const bool IsKnockBackExempted() const { return m_KnockBackExemption; }
|
||||
const bool IsPortExempted() const { return m_PortExemption; }
|
||||
const bool IsSenseExempted() const { return m_SenseExemption; }
|
||||
const bool IsAssistExempted() const { return m_AssistExemption; }
|
||||
const bool GetGMSpeed() const { return (gmspeed > 0); }
|
||||
void CheatDetected(CheatTypes CheatType, float x, float y, float z);
|
||||
const bool IsMQExemptedArea(uint32 zoneID, float x, float y, float z) const;
|
||||
bool CanUseReport;
|
||||
|
||||
//This is used to later set the buff duration of the spell, in slot to duration.
|
||||
@@ -1001,16 +1005,17 @@ public:
|
||||
// Task System Methods
|
||||
void LoadClientTaskState();
|
||||
void RemoveClientTaskState();
|
||||
void SendTaskActivityComplete(int TaskID, int ActivityID, int TaskIndex, int TaskIncomplete=1);
|
||||
void SendTaskFailed(int TaskID, int TaskIndex);
|
||||
void SendTaskActivityComplete(int TaskID, int ActivityID, int TaskIndex, TaskType type, int TaskIncomplete=1);
|
||||
void SendTaskFailed(int TaskID, int TaskIndex, TaskType type);
|
||||
void SendTaskComplete(int TaskIndex);
|
||||
inline ClientTaskState *GetTaskState() const { return taskstate; }
|
||||
|
||||
inline void CancelTask(int TaskIndex) { if(taskstate) taskstate->CancelTask(this, TaskIndex); }
|
||||
inline void CancelTask(int TaskIndex, TaskType type) { if(taskstate) taskstate->CancelTask(this, TaskIndex, type); }
|
||||
inline bool SaveTaskState() { return (taskmanager ? taskmanager->SaveClientState(this, taskstate) : false); }
|
||||
inline bool IsTaskStateLoaded() { return taskstate != nullptr; }
|
||||
inline bool IsTaskActive(int TaskID) { return (taskstate ? taskstate->IsTaskActive(TaskID) : false); }
|
||||
inline bool IsTaskActivityActive(int TaskID, int ActivityID) { return (taskstate ? taskstate->IsTaskActivityActive(TaskID, ActivityID) : false); }
|
||||
inline ActivityState GetTaskActivityState(int index, int ActivityID) { return (taskstate ? taskstate->GetTaskActivityState(index, ActivityID) : ActivityHidden); }
|
||||
inline ActivityState GetTaskActivityState(TaskType type, int index, int ActivityID) { return (taskstate ? taskstate->GetTaskActivityState(type, index, ActivityID) : ActivityHidden); }
|
||||
inline void UpdateTaskActivity(int TaskID, int ActivityID, int Count, bool ignore_quest_update = false) { if (taskstate) taskstate->UpdateTaskActivity(this, TaskID, ActivityID, Count, ignore_quest_update); }
|
||||
inline void ResetTaskActivity(int TaskID, int ActivityID) { if(taskstate) taskstate->ResetTaskActivity(this, TaskID, ActivityID); }
|
||||
inline void UpdateTasksOnKill(int NPCTypeID) { if(taskstate) taskstate->UpdateTasksOnKill(this, NPCTypeID); }
|
||||
@@ -1019,6 +1024,7 @@ public:
|
||||
inline bool UpdateTasksOnSpeakWith(int NPCTypeID) { if(taskstate) return taskstate->UpdateTasksOnSpeakWith(this, NPCTypeID); else return false; }
|
||||
inline bool UpdateTasksOnDeliver(std::list<EQEmu::ItemInstance*>& Items, int Cash, int NPCTypeID) { if (taskstate) return taskstate->UpdateTasksOnDeliver(this, Items, Cash, NPCTypeID); else return false; }
|
||||
inline void TaskSetSelector(Mob *mob, int TaskSetID) { if(taskmanager) taskmanager->TaskSetSelector(this, taskstate, mob, TaskSetID); }
|
||||
inline void TaskQuestSetSelector(Mob *mob, int count, int *tasks) { if(taskmanager) taskmanager->TaskQuestSetSelector(this, taskstate, mob, count, tasks); }
|
||||
inline void EnableTask(int TaskCount, int *TaskList) { if(taskstate) taskstate->EnableTask(CharacterID(), TaskCount, TaskList); }
|
||||
inline void DisableTask(int TaskCount, int *TaskList) { if(taskstate) taskstate->DisableTask(CharacterID(), TaskCount, TaskList); }
|
||||
inline bool IsTaskEnabled(int TaskID) { return (taskstate ? taskstate->IsTaskEnabled(TaskID) : false); }
|
||||
@@ -1034,9 +1040,9 @@ public:
|
||||
inline void CancelAllTasks() { if(taskstate) taskstate->CancelAllTasks(this); }
|
||||
inline int GetActiveTaskCount() { return (taskstate ? taskstate->GetActiveTaskCount() : 0); }
|
||||
inline int GetActiveTaskID(int index) { return (taskstate ? taskstate->GetActiveTaskID(index) : -1); }
|
||||
inline int GetTaskStartTime(int index) { return (taskstate ? taskstate->GetTaskStartTime(index) : -1); }
|
||||
inline bool IsTaskActivityCompleted(int index, int ActivityID) { return (taskstate ? taskstate->IsTaskActivityCompleted(index, ActivityID) : false); }
|
||||
inline int GetTaskActivityDoneCount(int ClientTaskIndex, int ActivityID) { return (taskstate ? taskstate->GetTaskActivityDoneCount(ClientTaskIndex, ActivityID) :0); }
|
||||
inline int GetTaskStartTime(TaskType type, int index) { return (taskstate ? taskstate->GetTaskStartTime(type, index) : -1); }
|
||||
inline bool IsTaskActivityCompleted(TaskType type, int index, int ActivityID) { return (taskstate ? taskstate->IsTaskActivityCompleted(type, index, ActivityID) : false); }
|
||||
inline int GetTaskActivityDoneCount(TaskType type, int ClientTaskIndex, int ActivityID) { return (taskstate ? taskstate->GetTaskActivityDoneCount(type, ClientTaskIndex, ActivityID) :0); }
|
||||
inline int GetTaskActivityDoneCountFromTaskID(int TaskID, int ActivityID) { return (taskstate ? taskstate->GetTaskActivityDoneCountFromTaskID(TaskID, ActivityID) :0); }
|
||||
inline int ActiveTasksInSet(int TaskSet) { return (taskstate ? taskstate->ActiveTasksInSet(TaskSet) :0); }
|
||||
inline int CompletedTasksInSet(int TaskSet) { return (taskstate ? taskstate->CompletedTasksInSet(TaskSet) :0); }
|
||||
@@ -1072,7 +1078,7 @@ public:
|
||||
void ClearPendingAdventureData();
|
||||
|
||||
int GetAggroCount();
|
||||
void IncrementAggroCount();
|
||||
void IncrementAggroCount(bool raid_target = false);
|
||||
void DecrementAggroCount();
|
||||
void SendPVPStats();
|
||||
void SendDisciplineTimers();
|
||||
@@ -1149,7 +1155,6 @@ public:
|
||||
inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); }
|
||||
void DragCorpses();
|
||||
inline void ClearDraggedCorpses() { DraggedCorpses.clear(); }
|
||||
inline void ResetPositionTimer() { position_timer_counter = 0; }
|
||||
void SendAltCurrencies();
|
||||
void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount);
|
||||
void AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0);
|
||||
@@ -1161,7 +1166,7 @@ public:
|
||||
void HandleLFGuildResponse(ServerPacket *pack);
|
||||
void SendLFGuildStatus();
|
||||
void SendGuildLFGuildStatus();
|
||||
inline bool XTargettingAvailable() const { return ((m_ClientVersionBit & EQEmu::versions::bit_UFAndLater) && RuleB(Character, EnableXTargetting)); }
|
||||
inline bool XTargettingAvailable() const { return ((m_ClientVersionBit & EQEmu::versions::maskUFAndLater) && RuleB(Character, EnableXTargetting)); }
|
||||
inline uint8 GetMaxXTargets() const { return MaxXTargets; }
|
||||
void SetMaxXTargets(uint8 NewMax);
|
||||
bool IsXTarget(const Mob *m) const;
|
||||
@@ -1185,7 +1190,7 @@ public:
|
||||
bool GroupFollow(Client* inviter);
|
||||
inline bool GetRunMode() const { return runmode; }
|
||||
|
||||
inline bool AggroMeterAvailable() const { return ((m_ClientVersionBit & EQEmu::versions::bit_RoF2AndLater)) && RuleB(Character, EnableAggroMeter); } // RoF untested
|
||||
inline bool AggroMeterAvailable() const { return ((m_ClientVersionBit & EQEmu::versions::maskRoF2AndLater)) && RuleB(Character, EnableAggroMeter); } // RoF untested
|
||||
inline void SetAggroMeterLock(int in) { m_aggrometer.set_lock_id(in); }
|
||||
|
||||
void ProcessAggroMeter(); // builds packet and sends
|
||||
@@ -1276,9 +1281,6 @@ public:
|
||||
int mod_food_value(const EQEmu::ItemData *item, int change);
|
||||
int mod_drink_value(const EQEmu::ItemData *item, int change);
|
||||
|
||||
void SetEngagedRaidTarget(bool value) { EngagedRaidTarget = value; }
|
||||
bool GetEngagedRaidTarget() const { return EngagedRaidTarget; }
|
||||
|
||||
void ShowNumHits(); // work around function for numhits not showing on buffs
|
||||
|
||||
void TripInterrogateInvState() { interrogateinv_flag = true; }
|
||||
@@ -1396,6 +1398,9 @@ private:
|
||||
void DoManaRegen();
|
||||
void DoStaminaHungerUpdate();
|
||||
void CalcRestState();
|
||||
// if they have aggro (AggroCount != 0) their timer is saved in m_pp.RestTimer, else we need to get current timer
|
||||
inline uint32 GetRestTimer() const { return AggroCount ? m_pp.RestTimer : rest_timer.GetRemainingTime() / 1000; }
|
||||
void UpdateRestTimer(uint32 new_timer);
|
||||
|
||||
uint32 pLastUpdate;
|
||||
uint32 pLastUpdateWZ;
|
||||
@@ -1456,6 +1461,9 @@ private:
|
||||
int Haste; //precalced value
|
||||
uint32 tmSitting; // time stamp started sitting, used for HP regen bonus added on MAY 5, 2004
|
||||
|
||||
bool display_mob_info_window;
|
||||
bool dev_tools_window_enabled;
|
||||
|
||||
int32 max_end;
|
||||
int32 current_endurance;
|
||||
|
||||
@@ -1467,6 +1475,7 @@ private:
|
||||
PetInfo m_suspendedminion; // pet data for our suspended minion.
|
||||
MercInfo m_mercinfo[MAXMERCS]; // current mercenary
|
||||
InspectMessage_Struct m_inspect_message;
|
||||
bool temp_pvp;
|
||||
|
||||
void NPCSpawn(const Seperator* sep);
|
||||
uint32 GetEXPForLevel(uint16 level);
|
||||
@@ -1493,9 +1502,6 @@ private:
|
||||
|
||||
WaterRegionType last_region_type;
|
||||
|
||||
Timer position_timer;
|
||||
uint8 position_timer_counter;
|
||||
|
||||
// this is used to try to cut back on position update reflections
|
||||
int position_update_same_count;
|
||||
|
||||
@@ -1536,7 +1542,6 @@ private:
|
||||
Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */
|
||||
|
||||
glm::vec3 m_Proximity;
|
||||
glm::vec4 last_major_update_position;
|
||||
|
||||
void BulkSendInventoryItems();
|
||||
|
||||
@@ -1563,9 +1568,6 @@ private:
|
||||
float AreaManaRegen;
|
||||
float AreaEndRegen;
|
||||
|
||||
bool EngagedRaidTarget;
|
||||
uint32 SavedRaidRestTimer;
|
||||
|
||||
std::set<uint32> zone_flags;
|
||||
|
||||
ClientTaskState *taskstate;
|
||||
@@ -1583,11 +1585,6 @@ private:
|
||||
|
||||
int XPRate;
|
||||
|
||||
bool m_ShadowStepExemption;
|
||||
bool m_KnockBackExemption;
|
||||
bool m_PortExemption;
|
||||
bool m_SenseExemption;
|
||||
bool m_AssistExemption;
|
||||
bool alternate_currency_loaded;
|
||||
std::map<uint32, uint32> alternate_currency;
|
||||
std::queue<std::pair<uint32, int32>> alternate_currency_queued_operations;
|
||||
@@ -1640,6 +1637,31 @@ private:
|
||||
|
||||
void InterrogateInventory_(bool errorcheck, Client* requester, int16 head, int16 index, const EQEmu::ItemInstance* inst, const EQEmu::ItemInstance* parent, bool log, bool silent, bool &error, int depth);
|
||||
bool InterrogateInventory_error(int16 head, int16 index, const EQEmu::ItemInstance* inst, const EQEmu::ItemInstance* parent, int depth);
|
||||
|
||||
int client_max_level;
|
||||
|
||||
#ifdef BOTS
|
||||
struct BotOwnerOptions {
|
||||
bool death_marquee;
|
||||
bool stats_update;
|
||||
};
|
||||
|
||||
BotOwnerOptions bot_owner_options;
|
||||
|
||||
const BotOwnerOptions DefaultBotOwnerOptions = {
|
||||
false, // death_marquee
|
||||
false // stats_update
|
||||
};
|
||||
|
||||
public:
|
||||
void SetBotOptionDeathMarquee(bool flag) { bot_owner_options.death_marquee = flag; }
|
||||
void SetBotOptionStatsUpdate(bool flag) { bot_owner_options.stats_update = flag; }
|
||||
|
||||
bool GetBotOptionDeathMarquee() const { return bot_owner_options.death_marquee; }
|
||||
bool GetBotOptionStatsUpdate() const { return bot_owner_options.stats_update; }
|
||||
|
||||
private:
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+123
-654
@@ -275,8 +275,9 @@ int32 Client::CalcHPRegen(bool bCombat)
|
||||
if (!skip_innate && m_pp.InnateSkills[InnateRegen] != InnateDisabled) {
|
||||
if (level >= 50) {
|
||||
++base;
|
||||
if (level >= 55)
|
||||
if (level >= 55) {
|
||||
++base;
|
||||
}
|
||||
}
|
||||
base *= 2;
|
||||
}
|
||||
@@ -290,9 +291,8 @@ int32 Client::CalcHPRegen(bool bCombat)
|
||||
// another check for IsClient && !(base + item_regen) && Cur_HP <= 0 do --base; do later
|
||||
|
||||
if (!bCombat && CanFastRegen() && (IsSitting() || CanMedOnHorse())) {
|
||||
auto fast_mod = RuleI(Character, RestRegenHP); // TODO: this is actually zone based
|
||||
auto max_hp = GetMaxHP();
|
||||
int fast_regen = 6 * (max_hp / fast_mod);
|
||||
int fast_regen = 6 * (max_hp / zone->newzone_data.FastRegenHP);
|
||||
if (base < fast_regen) // weird, but what the client is doing
|
||||
base = fast_regen;
|
||||
}
|
||||
@@ -325,14 +325,15 @@ int32 Client::CalcMaxHP()
|
||||
max_hp += spellbonuses.HP + aabonuses.HP;
|
||||
max_hp += GroupLeadershipAAHealthEnhancement();
|
||||
max_hp += max_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f);
|
||||
if (cur_hp > max_hp) {
|
||||
cur_hp = max_hp;
|
||||
if (current_hp > max_hp) {
|
||||
current_hp = max_hp;
|
||||
}
|
||||
int hp_perc_cap = spellbonuses.HPPercCap[0];
|
||||
if (hp_perc_cap) {
|
||||
int curHP_cap = (max_hp * hp_perc_cap) / 100;
|
||||
if (cur_hp > curHP_cap || (spellbonuses.HPPercCap[1] && cur_hp > spellbonuses.HPPercCap[1])) {
|
||||
cur_hp = curHP_cap;
|
||||
if (current_hp > curHP_cap || (spellbonuses.HPPercCap[1] && current_hp > spellbonuses.HPPercCap[1])) {
|
||||
|
||||
current_hp = curHP_cap;
|
||||
}
|
||||
}
|
||||
return max_hp;
|
||||
@@ -341,136 +342,137 @@ int32 Client::CalcMaxHP()
|
||||
uint32 Mob::GetClassLevelFactor()
|
||||
{
|
||||
uint32 multiplier = 0;
|
||||
uint8 mlevel = GetLevel();
|
||||
uint8 mlevel = GetLevel();
|
||||
switch (GetClass()) {
|
||||
case WARRIOR: {
|
||||
if (mlevel < 20) {
|
||||
multiplier = 220;
|
||||
}
|
||||
else if (mlevel < 30) {
|
||||
multiplier = 230;
|
||||
}
|
||||
else if (mlevel < 40) {
|
||||
multiplier = 250;
|
||||
}
|
||||
else if (mlevel < 53) {
|
||||
multiplier = 270;
|
||||
}
|
||||
else if (mlevel < 57) {
|
||||
multiplier = 280;
|
||||
}
|
||||
else if (mlevel < 60) {
|
||||
multiplier = 290;
|
||||
}
|
||||
else if (mlevel < 70) {
|
||||
multiplier = 300;
|
||||
}
|
||||
else {
|
||||
multiplier = 311;
|
||||
}
|
||||
break;
|
||||
if (mlevel < 20) {
|
||||
multiplier = 220;
|
||||
}
|
||||
else if (mlevel < 30) {
|
||||
multiplier = 230;
|
||||
}
|
||||
else if (mlevel < 40) {
|
||||
multiplier = 250;
|
||||
}
|
||||
else if (mlevel < 53) {
|
||||
multiplier = 270;
|
||||
}
|
||||
else if (mlevel < 57) {
|
||||
multiplier = 280;
|
||||
}
|
||||
else if (mlevel < 60) {
|
||||
multiplier = 290;
|
||||
}
|
||||
else if (mlevel < 70) {
|
||||
multiplier = 300;
|
||||
}
|
||||
else {
|
||||
multiplier = 311;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DRUID:
|
||||
case CLERIC:
|
||||
case SHAMAN: {
|
||||
if (mlevel < 70) {
|
||||
multiplier = 150;
|
||||
}
|
||||
else {
|
||||
multiplier = 157;
|
||||
}
|
||||
break;
|
||||
if (mlevel < 70) {
|
||||
multiplier = 150;
|
||||
}
|
||||
else {
|
||||
multiplier = 157;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BERSERKER:
|
||||
case PALADIN:
|
||||
case SHADOWKNIGHT: {
|
||||
if (mlevel < 35) {
|
||||
multiplier = 210;
|
||||
}
|
||||
else if (mlevel < 45) {
|
||||
multiplier = 220;
|
||||
}
|
||||
else if (mlevel < 51) {
|
||||
multiplier = 230;
|
||||
}
|
||||
else if (mlevel < 56) {
|
||||
multiplier = 240;
|
||||
}
|
||||
else if (mlevel < 60) {
|
||||
multiplier = 250;
|
||||
}
|
||||
else if (mlevel < 68) {
|
||||
multiplier = 260;
|
||||
}
|
||||
else {
|
||||
multiplier = 270;
|
||||
}
|
||||
break;
|
||||
if (mlevel < 35) {
|
||||
multiplier = 210;
|
||||
}
|
||||
else if (mlevel < 45) {
|
||||
multiplier = 220;
|
||||
}
|
||||
else if (mlevel < 51) {
|
||||
multiplier = 230;
|
||||
}
|
||||
else if (mlevel < 56) {
|
||||
multiplier = 240;
|
||||
}
|
||||
else if (mlevel < 60) {
|
||||
multiplier = 250;
|
||||
}
|
||||
else if (mlevel < 68) {
|
||||
multiplier = 260;
|
||||
}
|
||||
else {
|
||||
multiplier = 270;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MONK:
|
||||
case BARD:
|
||||
case ROGUE:
|
||||
case BEASTLORD: {
|
||||
if (mlevel < 51) {
|
||||
multiplier = 180;
|
||||
}
|
||||
else if (mlevel < 58) {
|
||||
multiplier = 190;
|
||||
}
|
||||
else if (mlevel < 70) {
|
||||
multiplier = 200;
|
||||
}
|
||||
else {
|
||||
multiplier = 210;
|
||||
}
|
||||
break;
|
||||
if (mlevel < 51) {
|
||||
multiplier = 180;
|
||||
}
|
||||
else if (mlevel < 58) {
|
||||
multiplier = 190;
|
||||
}
|
||||
else if (mlevel < 70) {
|
||||
multiplier = 200;
|
||||
}
|
||||
else {
|
||||
multiplier = 210;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RANGER: {
|
||||
if (mlevel < 58) {
|
||||
multiplier = 200;
|
||||
}
|
||||
else if (mlevel < 70) {
|
||||
multiplier = 210;
|
||||
}
|
||||
else {
|
||||
multiplier = 220;
|
||||
}
|
||||
break;
|
||||
if (mlevel < 58) {
|
||||
multiplier = 200;
|
||||
}
|
||||
else if (mlevel < 70) {
|
||||
multiplier = 210;
|
||||
}
|
||||
else {
|
||||
multiplier = 220;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MAGICIAN:
|
||||
case WIZARD:
|
||||
case NECROMANCER:
|
||||
case ENCHANTER: {
|
||||
if (mlevel < 70) {
|
||||
multiplier = 120;
|
||||
}
|
||||
else {
|
||||
multiplier = 127;
|
||||
}
|
||||
break;
|
||||
if (mlevel < 70) {
|
||||
multiplier = 120;
|
||||
}
|
||||
else {
|
||||
multiplier = 127;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (mlevel < 35) {
|
||||
multiplier = 210;
|
||||
}
|
||||
else if (mlevel < 45) {
|
||||
multiplier = 220;
|
||||
}
|
||||
else if (mlevel < 51) {
|
||||
multiplier = 230;
|
||||
}
|
||||
else if (mlevel < 56) {
|
||||
multiplier = 240;
|
||||
}
|
||||
else if (mlevel < 60) {
|
||||
multiplier = 250;
|
||||
}
|
||||
else {
|
||||
multiplier = 260;
|
||||
}
|
||||
break;
|
||||
if (mlevel < 35) {
|
||||
multiplier = 210;
|
||||
}
|
||||
else if (mlevel < 45) {
|
||||
multiplier = 220;
|
||||
}
|
||||
else if (mlevel < 51) {
|
||||
multiplier = 230;
|
||||
}
|
||||
else if (mlevel < 56) {
|
||||
multiplier = 240;
|
||||
}
|
||||
else if (mlevel < 60) {
|
||||
multiplier = 250;
|
||||
}
|
||||
else {
|
||||
multiplier = 260;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
@@ -552,7 +554,7 @@ int32 Client::GetRawItemAC()
|
||||
{
|
||||
int32 Total = 0;
|
||||
// this skips MainAmmo..add an '=' conditional if that slot is required (original behavior)
|
||||
for (int16 slot_id = EQEmu::legacy::EQUIPMENT_BEGIN; slot_id < EQEmu::legacy::EQUIPMENT_END; slot_id++) {
|
||||
for (int16 slot_id = EQEmu::invslot::BONUS_BEGIN; slot_id <= EQEmu::invslot::BONUS_STAT_END; slot_id++) {
|
||||
const EQEmu::ItemInstance* inst = m_inv[slot_id];
|
||||
if (inst && inst->IsClassCommon()) {
|
||||
Total += inst->GetItem()->AC;
|
||||
@@ -561,537 +563,6 @@ int32 Client::GetRawItemAC()
|
||||
return Total;
|
||||
}
|
||||
|
||||
int32 Client::acmod()
|
||||
{
|
||||
int agility = GetAGI();
|
||||
int level = GetLevel();
|
||||
if (agility < 1 || level < 1) {
|
||||
return (0);
|
||||
}
|
||||
if (agility <= 74) {
|
||||
if (agility == 1) {
|
||||
return -24;
|
||||
}
|
||||
else if (agility <= 3) {
|
||||
return -23;
|
||||
}
|
||||
else if (agility == 4) {
|
||||
return -22;
|
||||
}
|
||||
else if (agility <= 6) {
|
||||
return -21;
|
||||
}
|
||||
else if (agility <= 8) {
|
||||
return -20;
|
||||
}
|
||||
else if (agility == 9) {
|
||||
return -19;
|
||||
}
|
||||
else if (agility <= 11) {
|
||||
return -18;
|
||||
}
|
||||
else if (agility == 12) {
|
||||
return -17;
|
||||
}
|
||||
else if (agility <= 14) {
|
||||
return -16;
|
||||
}
|
||||
else if (agility <= 16) {
|
||||
return -15;
|
||||
}
|
||||
else if (agility == 17) {
|
||||
return -14;
|
||||
}
|
||||
else if (agility <= 19) {
|
||||
return -13;
|
||||
}
|
||||
else if (agility == 20) {
|
||||
return -12;
|
||||
}
|
||||
else if (agility <= 22) {
|
||||
return -11;
|
||||
}
|
||||
else if (agility <= 24) {
|
||||
return -10;
|
||||
}
|
||||
else if (agility == 25) {
|
||||
return -9;
|
||||
}
|
||||
else if (agility <= 27) {
|
||||
return -8;
|
||||
}
|
||||
else if (agility == 28) {
|
||||
return -7;
|
||||
}
|
||||
else if (agility <= 30) {
|
||||
return -6;
|
||||
}
|
||||
else if (agility <= 32) {
|
||||
return -5;
|
||||
}
|
||||
else if (agility == 33) {
|
||||
return -4;
|
||||
}
|
||||
else if (agility <= 35) {
|
||||
return -3;
|
||||
}
|
||||
else if (agility == 36) {
|
||||
return -2;
|
||||
}
|
||||
else if (agility <= 38) {
|
||||
return -1;
|
||||
}
|
||||
else if (agility <= 65) {
|
||||
return 0;
|
||||
}
|
||||
else if (agility <= 70) {
|
||||
return 1;
|
||||
}
|
||||
else if (agility <= 74) {
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
else if (agility <= 137) {
|
||||
if (agility == 75) {
|
||||
if (level <= 6) {
|
||||
return 9;
|
||||
}
|
||||
else if (level <= 19) {
|
||||
return 23;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 33;
|
||||
}
|
||||
else {
|
||||
return 39;
|
||||
}
|
||||
}
|
||||
else if (agility >= 76 && agility <= 79) {
|
||||
if (level <= 6) {
|
||||
return 10;
|
||||
}
|
||||
else if (level <= 19) {
|
||||
return 23;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 33;
|
||||
}
|
||||
else {
|
||||
return 40;
|
||||
}
|
||||
}
|
||||
else if (agility == 80) {
|
||||
if (level <= 6) {
|
||||
return 11;
|
||||
}
|
||||
else if (level <= 19) {
|
||||
return 24;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 34;
|
||||
}
|
||||
else {
|
||||
return 41;
|
||||
}
|
||||
}
|
||||
else if (agility >= 81 && agility <= 85) {
|
||||
if (level <= 6) {
|
||||
return 12;
|
||||
}
|
||||
else if (level <= 19) {
|
||||
return 25;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 35;
|
||||
}
|
||||
else {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
else if (agility >= 86 && agility <= 90) {
|
||||
if (level <= 6) {
|
||||
return 12;
|
||||
}
|
||||
else if (level <= 19) {
|
||||
return 26;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 36;
|
||||
}
|
||||
else {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
else if (agility >= 91 && agility <= 95) {
|
||||
if (level <= 6) {
|
||||
return 13;
|
||||
}
|
||||
else if (level <= 19) {
|
||||
return 26;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 36;
|
||||
}
|
||||
else {
|
||||
return 43;
|
||||
}
|
||||
}
|
||||
else if (agility >= 96 && agility <= 99) {
|
||||
if (level <= 6) {
|
||||
return 14;
|
||||
}
|
||||
else if (level <= 19) {
|
||||
return 27;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 37;
|
||||
}
|
||||
else {
|
||||
return 44;
|
||||
}
|
||||
}
|
||||
else if (agility == 100 && level >= 7) {
|
||||
if (level <= 19) {
|
||||
return 28;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 38;
|
||||
}
|
||||
else {
|
||||
return 45;
|
||||
}
|
||||
}
|
||||
else if (level <= 6) {
|
||||
return 15;
|
||||
}
|
||||
//level is >6
|
||||
else if (agility >= 101 && agility <= 105) {
|
||||
if (level <= 19) {
|
||||
return 29;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 39; // not verified
|
||||
}
|
||||
else {
|
||||
return 45;
|
||||
}
|
||||
}
|
||||
else if (agility >= 106 && agility <= 110) {
|
||||
if (level <= 19) {
|
||||
return 29;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 39; // not verified
|
||||
}
|
||||
else {
|
||||
return 46;
|
||||
}
|
||||
}
|
||||
else if (agility >= 111 && agility <= 115) {
|
||||
if (level <= 19) {
|
||||
return 30;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 40; // not verified
|
||||
}
|
||||
else {
|
||||
return 47;
|
||||
}
|
||||
}
|
||||
else if (agility >= 116 && agility <= 119) {
|
||||
if (level <= 19) {
|
||||
return 31;
|
||||
}
|
||||
else if (level <= 39) {
|
||||
return 41;
|
||||
}
|
||||
else {
|
||||
return 47;
|
||||
}
|
||||
}
|
||||
else if (level <= 19) {
|
||||
return 32;
|
||||
}
|
||||
//level is > 19
|
||||
else if (agility == 120) {
|
||||
if (level <= 39) {
|
||||
return 42;
|
||||
}
|
||||
else {
|
||||
return 48;
|
||||
}
|
||||
}
|
||||
else if (agility <= 125) {
|
||||
if (level <= 39) {
|
||||
return 42;
|
||||
}
|
||||
else {
|
||||
return 49;
|
||||
}
|
||||
}
|
||||
else if (agility <= 135) {
|
||||
if (level <= 39) {
|
||||
return 42;
|
||||
}
|
||||
else {
|
||||
return 50;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (level <= 39) {
|
||||
return 42;
|
||||
}
|
||||
else {
|
||||
return 51;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (agility <= 300) {
|
||||
if (level <= 6) {
|
||||
if (agility <= 139) {
|
||||
return (21);
|
||||
}
|
||||
else if (agility == 140) {
|
||||
return (22);
|
||||
}
|
||||
else if (agility <= 145) {
|
||||
return (23);
|
||||
}
|
||||
else if (agility <= 150) {
|
||||
return (23);
|
||||
}
|
||||
else if (agility <= 155) {
|
||||
return (24);
|
||||
}
|
||||
else if (agility <= 159) {
|
||||
return (25);
|
||||
}
|
||||
else if (agility == 160) {
|
||||
return (26);
|
||||
}
|
||||
else if (agility <= 165) {
|
||||
return (26);
|
||||
}
|
||||
else if (agility <= 170) {
|
||||
return (27);
|
||||
}
|
||||
else if (agility <= 175) {
|
||||
return (28);
|
||||
}
|
||||
else if (agility <= 179) {
|
||||
return (28);
|
||||
}
|
||||
else if (agility == 180) {
|
||||
return (29);
|
||||
}
|
||||
else if (agility <= 185) {
|
||||
return (30);
|
||||
}
|
||||
else if (agility <= 190) {
|
||||
return (31);
|
||||
}
|
||||
else if (agility <= 195) {
|
||||
return (31);
|
||||
}
|
||||
else if (agility <= 199) {
|
||||
return (32);
|
||||
}
|
||||
else if (agility <= 219) {
|
||||
return (33);
|
||||
}
|
||||
else if (agility <= 239) {
|
||||
return (34);
|
||||
}
|
||||
else {
|
||||
return (35);
|
||||
}
|
||||
}
|
||||
else if (level <= 19) {
|
||||
if (agility <= 139) {
|
||||
return (34);
|
||||
}
|
||||
else if (agility == 140) {
|
||||
return (35);
|
||||
}
|
||||
else if (agility <= 145) {
|
||||
return (36);
|
||||
}
|
||||
else if (agility <= 150) {
|
||||
return (37);
|
||||
}
|
||||
else if (agility <= 155) {
|
||||
return (37);
|
||||
}
|
||||
else if (agility <= 159) {
|
||||
return (38);
|
||||
}
|
||||
else if (agility == 160) {
|
||||
return (39);
|
||||
}
|
||||
else if (agility <= 165) {
|
||||
return (40);
|
||||
}
|
||||
else if (agility <= 170) {
|
||||
return (40);
|
||||
}
|
||||
else if (agility <= 175) {
|
||||
return (41);
|
||||
}
|
||||
else if (agility <= 179) {
|
||||
return (42);
|
||||
}
|
||||
else if (agility == 180) {
|
||||
return (43);
|
||||
}
|
||||
else if (agility <= 185) {
|
||||
return (43);
|
||||
}
|
||||
else if (agility <= 190) {
|
||||
return (44);
|
||||
}
|
||||
else if (agility <= 195) {
|
||||
return (45);
|
||||
}
|
||||
else if (agility <= 199) {
|
||||
return (45);
|
||||
}
|
||||
else if (agility <= 219) {
|
||||
return (46);
|
||||
}
|
||||
else if (agility <= 239) {
|
||||
return (47);
|
||||
}
|
||||
else {
|
||||
return (48);
|
||||
}
|
||||
}
|
||||
else if (level <= 39) {
|
||||
if (agility <= 139) {
|
||||
return (44);
|
||||
}
|
||||
else if (agility == 140) {
|
||||
return (45);
|
||||
}
|
||||
else if (agility <= 145) {
|
||||
return (46);
|
||||
}
|
||||
else if (agility <= 150) {
|
||||
return (47);
|
||||
}
|
||||
else if (agility <= 155) {
|
||||
return (47);
|
||||
}
|
||||
else if (agility <= 159) {
|
||||
return (48);
|
||||
}
|
||||
else if (agility == 160) {
|
||||
return (49);
|
||||
}
|
||||
else if (agility <= 165) {
|
||||
return (50);
|
||||
}
|
||||
else if (agility <= 170) {
|
||||
return (50);
|
||||
}
|
||||
else if (agility <= 175) {
|
||||
return (51);
|
||||
}
|
||||
else if (agility <= 179) {
|
||||
return (52);
|
||||
}
|
||||
else if (agility == 180) {
|
||||
return (53);
|
||||
}
|
||||
else if (agility <= 185) {
|
||||
return (53);
|
||||
}
|
||||
else if (agility <= 190) {
|
||||
return (54);
|
||||
}
|
||||
else if (agility <= 195) {
|
||||
return (55);
|
||||
}
|
||||
else if (agility <= 199) {
|
||||
return (55);
|
||||
}
|
||||
else if (agility <= 219) {
|
||||
return (56);
|
||||
}
|
||||
else if (agility <= 239) {
|
||||
return (57);
|
||||
}
|
||||
else {
|
||||
return (58);
|
||||
}
|
||||
}
|
||||
else { //lvl >= 40
|
||||
if (agility <= 139) {
|
||||
return (51);
|
||||
}
|
||||
else if (agility == 140) {
|
||||
return (52);
|
||||
}
|
||||
else if (agility <= 145) {
|
||||
return (53);
|
||||
}
|
||||
else if (agility <= 150) {
|
||||
return (53);
|
||||
}
|
||||
else if (agility <= 155) {
|
||||
return (54);
|
||||
}
|
||||
else if (agility <= 159) {
|
||||
return (55);
|
||||
}
|
||||
else if (agility == 160) {
|
||||
return (56);
|
||||
}
|
||||
else if (agility <= 165) {
|
||||
return (56);
|
||||
}
|
||||
else if (agility <= 170) {
|
||||
return (57);
|
||||
}
|
||||
else if (agility <= 175) {
|
||||
return (58);
|
||||
}
|
||||
else if (agility <= 179) {
|
||||
return (58);
|
||||
}
|
||||
else if (agility == 180) {
|
||||
return (59);
|
||||
}
|
||||
else if (agility <= 185) {
|
||||
return (60);
|
||||
}
|
||||
else if (agility <= 190) {
|
||||
return (61);
|
||||
}
|
||||
else if (agility <= 195) {
|
||||
return (61);
|
||||
}
|
||||
else if (agility <= 199) {
|
||||
return (62);
|
||||
}
|
||||
else if (agility <= 219) {
|
||||
return (63);
|
||||
}
|
||||
else if (agility <= 239) {
|
||||
return (64);
|
||||
}
|
||||
else {
|
||||
return (65);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
//seems about 21 agil per extra AC pt over 300...
|
||||
return (65 + ((agility - 300) / 21));
|
||||
}
|
||||
Log(Logs::Detail, Logs::Error, "Error in Client::acmod(): Agility: %i, Level: %i", agility, level);
|
||||
return 0;
|
||||
};
|
||||
|
||||
int32 Client::CalcMaxMana()
|
||||
{
|
||||
switch (GetCasterClass()) {
|
||||
@@ -1296,9 +767,8 @@ int32 Client::CalcManaRegen(bool bCombat)
|
||||
regen = regen * 100.0f * AreaManaRegen * 0.01f + 0.5f;
|
||||
|
||||
if (!bCombat && CanFastRegen() && (IsSitting() || CanMedOnHorse())) {
|
||||
auto fast_mod = RuleI(Character, RestRegenMana); // TODO: this is actually zone based
|
||||
auto max_mana = GetMaxMana();
|
||||
int fast_regen = 6 * (max_mana / fast_mod);
|
||||
int fast_regen = 6 * (max_mana / zone->newzone_data.FastRegenMana);
|
||||
if (regen < fast_regen) // weird, but what the client is doing
|
||||
regen = fast_regen;
|
||||
}
|
||||
@@ -1319,7 +789,7 @@ uint32 Client::CalcCurrentWeight()
|
||||
EQEmu::ItemInstance* ins = nullptr;
|
||||
uint32 Total = 0;
|
||||
int x;
|
||||
for (x = EQEmu::legacy::EQUIPMENT_BEGIN; x <= EQEmu::inventory::slotCursor; x++) { // include cursor or not?
|
||||
for (x = EQEmu::invslot::POSSESSIONS_BEGIN; x <= EQEmu::invslot::POSSESSIONS_END; x++) {
|
||||
TempItem = 0;
|
||||
ins = GetInv().GetItem(x);
|
||||
if (ins) {
|
||||
@@ -1329,7 +799,7 @@ uint32 Client::CalcCurrentWeight()
|
||||
Total += TempItem->Weight;
|
||||
}
|
||||
}
|
||||
for (x = EQEmu::legacy::GENERAL_BAGS_BEGIN; x <= EQEmu::legacy::GENERAL_BAGS_END; x++) { // include cursor bags or not?
|
||||
for (x = EQEmu::invbag::GENERAL_BAGS_BEGIN; x <= EQEmu::invbag::CURSOR_BAG_END; x++) {
|
||||
int TmpWeight = 0;
|
||||
TempItem = 0;
|
||||
ins = GetInv().GetItem(x);
|
||||
@@ -1342,9 +812,9 @@ uint32 Client::CalcCurrentWeight()
|
||||
if (TmpWeight > 0) {
|
||||
// this code indicates that weight redux bags can only be in the first general inventory slot to be effective...
|
||||
// is this correct? or can we scan for the highest weight redux and use that? (need client verifications)
|
||||
int bagslot = EQEmu::inventory::slotGeneral1;
|
||||
int bagslot = EQEmu::invslot::slotGeneral1;
|
||||
int reduction = 0;
|
||||
for (int m = EQEmu::legacy::GENERAL_BAGS_BEGIN + 10; m <= EQEmu::legacy::GENERAL_BAGS_END; m += 10) { // include cursor bags or not?
|
||||
for (int m = EQEmu::invbag::GENERAL_BAGS_BEGIN + EQEmu::invbag::SLOT_COUNT; m <= EQEmu::invbag::CURSOR_BAG_END; m += EQEmu::invbag::SLOT_COUNT) {
|
||||
if (x >= m) {
|
||||
bagslot += 1;
|
||||
}
|
||||
@@ -1368,7 +838,7 @@ uint32 Client::CalcCurrentWeight()
|
||||
This is the ONLY instance I have seen where the client is hard coded to particular Item IDs to set a certain property for an item. It is very odd.
|
||||
*/
|
||||
// SoD+ client has no weight for coin
|
||||
if (EQEmu::behavior::Lookup(EQEmu::versions::ConvertClientVersionToMobVersion(ClientVersion()))->CoinHasWeight) {
|
||||
if (EQEmu::behavior::StaticLookup(EQEmu::versions::ConvertClientVersionToMobVersion(ClientVersion()))->CoinHasWeight) {
|
||||
Total += (m_pp.platinum + m_pp.gold + m_pp.silver + m_pp.copper) / 4;
|
||||
}
|
||||
float Packrat = (float)spellbonuses.Packrat + (float)aabonuses.Packrat + (float)itembonuses.Packrat;
|
||||
@@ -2264,9 +1734,8 @@ int32 Client::CalcEnduranceRegen(bool bCombat)
|
||||
|
||||
int regen = base;
|
||||
if (!bCombat && CanFastRegen() && (IsSitting() || CanMedOnHorse())) {
|
||||
auto fast_mod = RuleI(Character, RestRegenEnd); // TODO: this is actually zone based
|
||||
auto max_end = GetMaxEndurance();
|
||||
int fast_regen = 6 * (max_end / fast_mod);
|
||||
int fast_regen = 6 * (max_end / zone->newzone_data.FastRegenEndurance);
|
||||
if (aa_regen < fast_regen) // weird, but what the client is doing
|
||||
aa_regen = fast_regen;
|
||||
}
|
||||
@@ -2293,12 +1762,12 @@ int Client::GetRawACNoShield(int &shield_ac) const
|
||||
{
|
||||
int ac = itembonuses.AC + spellbonuses.AC + aabonuses.AC;
|
||||
shield_ac = 0;
|
||||
const EQEmu::ItemInstance *inst = m_inv.GetItem(EQEmu::inventory::slotSecondary);
|
||||
const EQEmu::ItemInstance *inst = m_inv.GetItem(EQEmu::invslot::slotSecondary);
|
||||
if (inst) {
|
||||
if (inst->GetItem()->ItemType == EQEmu::item::ItemTypeShield) {
|
||||
ac -= inst->GetItem()->AC;
|
||||
shield_ac = inst->GetItem()->AC;
|
||||
for (uint8 i = EQEmu::inventory::socketBegin; i < EQEmu::inventory::SocketCount; i++) {
|
||||
for (uint8 i = EQEmu::invaug::SOCKET_BEGIN; i <= EQEmu::invaug::SOCKET_END; i++) {
|
||||
if (inst->GetAugment(i)) {
|
||||
ac -= inst->GetAugment(i)->GetItem()->AC;
|
||||
shield_ac += inst->GetAugment(i)->GetItem()->AC;
|
||||
|
||||
+609
-564
File diff suppressed because it is too large
Load Diff
@@ -94,6 +94,7 @@
|
||||
void Handle_OP_DeleteItem(const EQApplicationPacket *app);
|
||||
void Handle_OP_DeleteSpawn(const EQApplicationPacket *app);
|
||||
void Handle_OP_DeleteSpell(const EQApplicationPacket *app);
|
||||
void Handle_OP_Disarm(const EQApplicationPacket *app);
|
||||
void Handle_OP_DisarmTraps(const EQApplicationPacket *app);
|
||||
void Handle_OP_DoGroupLeadershipAbility(const EQApplicationPacket *app);
|
||||
void Handle_OP_DuelResponse(const EQApplicationPacket *app);
|
||||
@@ -228,6 +229,7 @@
|
||||
void Handle_OP_PurchaseLeadershipAA(const EQApplicationPacket *app);
|
||||
void Handle_OP_PVPLeaderBoardDetailsRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_PVPLeaderBoardRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_QueryUCSServerStatus(const EQApplicationPacket *app);
|
||||
void Handle_OP_RaidCommand(const EQApplicationPacket *app);
|
||||
void Handle_OP_RandomReq(const EQApplicationPacket *app);
|
||||
void Handle_OP_ReadBook(const EQApplicationPacket *app);
|
||||
|
||||
+93
-158
@@ -122,7 +122,7 @@ bool Client::Process() {
|
||||
|
||||
/* I haven't naturally updated my position in 10 seconds, updating manually */
|
||||
if (!is_client_moving && position_update_timer.Check()) {
|
||||
SendPositionUpdate();
|
||||
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
|
||||
}
|
||||
|
||||
if (mana_timer.Check())
|
||||
@@ -188,10 +188,6 @@ bool Client::Process() {
|
||||
if (IsStunned() && stunned_timer.Check())
|
||||
Mob::UnStun();
|
||||
|
||||
if (!m_CheatDetectMoved) {
|
||||
m_TimeSinceLastPositionCheck = Timer::GetCurrentTime();
|
||||
}
|
||||
|
||||
if (bardsong_timer.Check() && bardsong != 0) {
|
||||
//NOTE: this is kinda a heavy-handed check to make sure the mob still exists before
|
||||
//doing the next pulse on them...
|
||||
@@ -242,23 +238,29 @@ bool Client::Process() {
|
||||
}
|
||||
}
|
||||
|
||||
if (RuleB(Character, ActiveInvSnapshots) && time(nullptr) >= GetNextInvSnapshotTime()) {
|
||||
if (database.SaveCharacterInvSnapshot(CharacterID())) {
|
||||
SetNextInvSnapshot(RuleI(Character, InvSnapshotMinIntervalM));
|
||||
Log(Logs::Moderate, Logs::Inventory, "Successful inventory snapshot taken of %s - setting next interval for %i minute%s.",
|
||||
GetName(), RuleI(Character, InvSnapshotMinIntervalM), (RuleI(Character, InvSnapshotMinIntervalM) == 1 ? "" : "s"));
|
||||
}
|
||||
else {
|
||||
SetNextInvSnapshot(RuleI(Character, InvSnapshotMinRetryM));
|
||||
Log(Logs::Moderate, Logs::Inventory, "Failed to take inventory snapshot of %s - retrying in %i minute%s.",
|
||||
GetName(), RuleI(Character, InvSnapshotMinRetryM), (RuleI(Character, InvSnapshotMinRetryM) == 1 ? "" : "s"));
|
||||
}
|
||||
}
|
||||
|
||||
/* Build a close range list of NPC's */
|
||||
if (npc_close_scan_timer.Check()) {
|
||||
close_mobs.clear();
|
||||
|
||||
/* Force spawn updates when traveled far */
|
||||
//Force spawn updates when traveled far
|
||||
bool force_spawn_updates = false;
|
||||
float client_update_range = (RuleI(Range, ClientForceSpawnUpdateRange) * RuleI(Range, ClientForceSpawnUpdateRange));
|
||||
if (DistanceSquared(last_major_update_position, m_Position) >= client_update_range) {
|
||||
last_major_update_position = m_Position;
|
||||
force_spawn_updates = true;
|
||||
}
|
||||
|
||||
float scan_range = (RuleI(Range, ClientNPCScan) * RuleI(Range, ClientNPCScan));
|
||||
auto &mob_list = entity_list.GetMobList();
|
||||
for (auto itr = mob_list.begin(); itr != mob_list.end(); ++itr) {
|
||||
Mob* mob = itr->second;
|
||||
|
||||
float distance = DistanceSquared(m_Position, mob->GetPosition());
|
||||
if (mob->IsNPC()) {
|
||||
if (distance <= scan_range) {
|
||||
@@ -268,21 +270,9 @@ bool Client::Process() {
|
||||
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
||||
}
|
||||
}
|
||||
|
||||
if (force_spawn_updates && mob != this) {
|
||||
|
||||
if (mob->is_distance_roamer) {
|
||||
mob->SendPositionUpdateToClient(this);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (distance <= client_update_range)
|
||||
mob->SendPositionUpdateToClient(this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool may_use_attacks = false;
|
||||
/*
|
||||
Things which prevent us from attacking:
|
||||
@@ -310,7 +300,7 @@ bool Client::Process() {
|
||||
}
|
||||
|
||||
if (AutoFireEnabled()) {
|
||||
EQEmu::ItemInstance *ranged = GetInv().GetItem(EQEmu::inventory::slotRange);
|
||||
EQEmu::ItemInstance *ranged = GetInv().GetItem(EQEmu::invslot::slotRange);
|
||||
if (ranged)
|
||||
{
|
||||
if (ranged->GetItem() && ranged->GetItem()->ItemType == EQEmu::item::ItemTypeBow) {
|
||||
@@ -355,25 +345,22 @@ bool Client::Process() {
|
||||
}
|
||||
|
||||
Mob *auto_attack_target = GetTarget();
|
||||
if (auto_attack && auto_attack_target != nullptr && may_use_attacks && attack_timer.Check())
|
||||
{
|
||||
if (auto_attack && auto_attack_target != nullptr && may_use_attacks && attack_timer.Check()) {
|
||||
//check if change
|
||||
//only check on primary attack.. sorry offhand you gotta wait!
|
||||
if (aa_los_them_mob)
|
||||
{
|
||||
if (aa_los_them_mob) {
|
||||
if (auto_attack_target != aa_los_them_mob ||
|
||||
m_AutoAttackPosition.x != GetX() ||
|
||||
m_AutoAttackPosition.y != GetY() ||
|
||||
m_AutoAttackPosition.z != GetZ() ||
|
||||
m_AutoAttackTargetLocation.x != aa_los_them_mob->GetX() ||
|
||||
m_AutoAttackTargetLocation.y != aa_los_them_mob->GetY() ||
|
||||
m_AutoAttackTargetLocation.z != aa_los_them_mob->GetZ())
|
||||
{
|
||||
aa_los_them_mob = auto_attack_target;
|
||||
m_AutoAttackPosition = GetPosition();
|
||||
m_AutoAttackTargetLocation.z != aa_los_them_mob->GetZ()) {
|
||||
aa_los_them_mob = auto_attack_target;
|
||||
m_AutoAttackPosition = GetPosition();
|
||||
m_AutoAttackTargetLocation = glm::vec3(aa_los_them_mob->GetPosition());
|
||||
los_status = CheckLosFN(auto_attack_target);
|
||||
los_status_facing = IsFacingMob(aa_los_them_mob);
|
||||
los_status = CheckLosFN(auto_attack_target);
|
||||
los_status_facing = IsFacingMob(aa_los_them_mob);
|
||||
}
|
||||
// If only our heading changes, we can skip the CheckLosFN call
|
||||
// but above we still need to update los_status_facing
|
||||
@@ -382,36 +369,33 @@ bool Client::Process() {
|
||||
los_status_facing = IsFacingMob(aa_los_them_mob);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aa_los_them_mob = auto_attack_target;
|
||||
m_AutoAttackPosition = GetPosition();
|
||||
else {
|
||||
aa_los_them_mob = auto_attack_target;
|
||||
m_AutoAttackPosition = GetPosition();
|
||||
m_AutoAttackTargetLocation = glm::vec3(aa_los_them_mob->GetPosition());
|
||||
los_status = CheckLosFN(auto_attack_target);
|
||||
los_status_facing = IsFacingMob(aa_los_them_mob);
|
||||
los_status = CheckLosFN(auto_attack_target);
|
||||
los_status_facing = IsFacingMob(aa_los_them_mob);
|
||||
}
|
||||
|
||||
if (!CombatRange(auto_attack_target))
|
||||
{
|
||||
if (!CombatRange(auto_attack_target)) {
|
||||
Message_StringID(MT_TooFarAway, TARGET_TOO_FAR);
|
||||
}
|
||||
else if (auto_attack_target == this)
|
||||
{
|
||||
else if (auto_attack_target == this) {
|
||||
Message_StringID(MT_TooFarAway, TRY_ATTACKING_SOMEONE);
|
||||
}
|
||||
else if (!los_status || !los_status_facing)
|
||||
{
|
||||
else if (!los_status || !los_status_facing) {
|
||||
//you can't see your target
|
||||
}
|
||||
else if (auto_attack_target->GetHP() > -10) // -10 so we can watch people bleed in PvP
|
||||
{
|
||||
EQEmu::ItemInstance *wpn = GetInv().GetItem(EQEmu::inventory::slotPrimary);
|
||||
TryWeaponProc(wpn, auto_attack_target, EQEmu::inventory::slotPrimary);
|
||||
TriggerDefensiveProcs(auto_attack_target, EQEmu::inventory::slotPrimary, false);
|
||||
EQEmu::ItemInstance *wpn = GetInv().GetItem(EQEmu::invslot::slotPrimary);
|
||||
TryWeaponProc(wpn, auto_attack_target, EQEmu::invslot::slotPrimary);
|
||||
TriggerDefensiveProcs(auto_attack_target, EQEmu::invslot::slotPrimary, false);
|
||||
|
||||
DoAttackRounds(auto_attack_target, EQEmu::inventory::slotPrimary);
|
||||
if (CheckAATimer(aaTimerRampage))
|
||||
DoAttackRounds(auto_attack_target, EQEmu::invslot::slotPrimary);
|
||||
if (CheckAATimer(aaTimerRampage)) {
|
||||
entity_list.AEAttack(this, 30);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,39 +429,14 @@ bool Client::Process() {
|
||||
else if (auto_attack_target->GetHP() > -10) {
|
||||
CheckIncreaseSkill(EQEmu::skills::SkillDualWield, auto_attack_target, -10);
|
||||
if (CheckDualWield()) {
|
||||
EQEmu::ItemInstance *wpn = GetInv().GetItem(EQEmu::inventory::slotSecondary);
|
||||
TryWeaponProc(wpn, auto_attack_target, EQEmu::inventory::slotSecondary);
|
||||
EQEmu::ItemInstance *wpn = GetInv().GetItem(EQEmu::invslot::slotSecondary);
|
||||
TryWeaponProc(wpn, auto_attack_target, EQEmu::invslot::slotSecondary);
|
||||
|
||||
DoAttackRounds(auto_attack_target, EQEmu::inventory::slotSecondary);
|
||||
DoAttackRounds(auto_attack_target, EQEmu::invslot::slotSecondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (position_timer.Check()) {
|
||||
if (IsAIControlled())
|
||||
{
|
||||
if (!IsMoving())
|
||||
{
|
||||
animation = 0;
|
||||
m_Delta = glm::vec4(0.0f, 0.0f, 0.0f, m_Delta.w);
|
||||
SendPositionUpdate(2);
|
||||
}
|
||||
}
|
||||
|
||||
// Send a position packet every 8 seconds - if not done, other clients
|
||||
// see this char disappear after 10-12 seconds of inactivity
|
||||
if (position_timer_counter >= 36) { // Approx. 4 ticks per second
|
||||
entity_list.SendPositionUpdates(this, pLastUpdateWZ, RuleI(Range, MobPositionUpdates), GetTarget(), true);
|
||||
pLastUpdate = Timer::GetCurrentTime();
|
||||
pLastUpdateWZ = pLastUpdate;
|
||||
position_timer_counter = 0;
|
||||
}
|
||||
else {
|
||||
pLastUpdate = Timer::GetCurrentTime();
|
||||
position_timer_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
if (HasVirus()) {
|
||||
if (viral_timer.Check()) {
|
||||
viral_timer_counter++;
|
||||
@@ -622,9 +581,8 @@ bool Client::Process() {
|
||||
EQApplicationPacket *app = nullptr;
|
||||
if (!eqs->CheckState(CLOSING))
|
||||
{
|
||||
while (ret && (app = (EQApplicationPacket *)eqs->PopPacket())) {
|
||||
if (app)
|
||||
ret = HandlePacket(app);
|
||||
while (app = eqs->PopPacket()) {
|
||||
HandlePacket(app);
|
||||
safe_delete(app);
|
||||
}
|
||||
}
|
||||
@@ -777,7 +735,7 @@ void Client::BulkSendInventoryItems()
|
||||
{
|
||||
// LINKDEAD TRADE ITEMS
|
||||
// Move trade slot items back into normal inventory..need them there now for the proceeding validity checks
|
||||
for (int16 slot_id = EQEmu::legacy::TRADE_BEGIN; slot_id <= EQEmu::legacy::TRADE_END; slot_id++) {
|
||||
for (int16 slot_id = EQEmu::invslot::TRADE_BEGIN; slot_id <= EQEmu::invslot::TRADE_END; slot_id++) {
|
||||
EQEmu::ItemInstance* inst = m_inv.PopItem(slot_id);
|
||||
if(inst) {
|
||||
bool is_arrow = (inst->GetItem()->ItemType == EQEmu::item::ItemTypeArrow) ? true : false;
|
||||
@@ -803,7 +761,7 @@ void Client::BulkSendInventoryItems()
|
||||
EQEmu::OutBuffer::pos_type last_pos = ob.tellp();
|
||||
|
||||
// Possessions items
|
||||
for (int16 slot_id = EQEmu::inventory::slotBegin; slot_id < EQEmu::legacy::TYPE_POSSESSIONS_SIZE; slot_id++) {
|
||||
for (int16 slot_id = EQEmu::invslot::POSSESSIONS_BEGIN; slot_id <= EQEmu::invslot::POSSESSIONS_END; slot_id++) {
|
||||
const EQEmu::ItemInstance* inst = m_inv[slot_id];
|
||||
if (!inst)
|
||||
continue;
|
||||
@@ -816,21 +774,8 @@ void Client::BulkSendInventoryItems()
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
|
||||
// PowerSource item
|
||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) {
|
||||
const EQEmu::ItemInstance* inst = m_inv[EQEmu::inventory::slotPowerSource];
|
||||
if (inst) {
|
||||
inst->Serialize(ob, EQEmu::inventory::slotPowerSource);
|
||||
|
||||
if (ob.tellp() == last_pos)
|
||||
Log(Logs::General, Logs::Inventory, "Serialization failed on item slot %d during BulkSendInventoryItems. Item skipped.", EQEmu::inventory::slotPowerSource);
|
||||
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
}
|
||||
|
||||
// Bank items
|
||||
for (int16 slot_id = EQEmu::legacy::BANK_BEGIN; slot_id <= EQEmu::legacy::BANK_END; slot_id++) {
|
||||
for (int16 slot_id = EQEmu::invslot::BANK_BEGIN; slot_id <= EQEmu::invslot::BANK_END; slot_id++) {
|
||||
const EQEmu::ItemInstance* inst = m_inv[slot_id];
|
||||
if (!inst)
|
||||
continue;
|
||||
@@ -844,7 +789,7 @@ void Client::BulkSendInventoryItems()
|
||||
}
|
||||
|
||||
// SharedBank items
|
||||
for (int16 slot_id = EQEmu::legacy::SHARED_BANK_BEGIN; slot_id <= EQEmu::legacy::SHARED_BANK_END; slot_id++) {
|
||||
for (int16 slot_id = EQEmu::invslot::SHARED_BANK_BEGIN; slot_id <= EQEmu::invslot::SHARED_BANK_END; slot_id++) {
|
||||
const EQEmu::ItemInstance* inst = m_inv[slot_id];
|
||||
if (!inst)
|
||||
continue;
|
||||
@@ -867,7 +812,7 @@ void Client::BulkSendInventoryItems()
|
||||
void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
|
||||
const EQEmu::ItemData* handyitem = nullptr;
|
||||
uint32 numItemSlots = 80; //The max number of items passed in the transaction.
|
||||
if (m_ClientVersionBit & EQEmu::versions::bit_RoFAndLater) { // RoF+ can send 200 items
|
||||
if (m_ClientVersionBit & EQEmu::versions::maskRoFAndLater) { // RoF+ can send 200 items
|
||||
numItemSlots = 200;
|
||||
}
|
||||
const EQEmu::ItemData *item = nullptr;
|
||||
@@ -887,7 +832,7 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
|
||||
uint8 handychance = 0;
|
||||
for (itr = merlist.begin(); itr != merlist.end() && i <= numItemSlots; ++itr) {
|
||||
MerchantList ml = *itr;
|
||||
if (merch->CastToNPC()->GetMerchantProbability() > ml.probability)
|
||||
if (ml.probability != 100 && zone->random.Int(1, 100) > ml.probability)
|
||||
continue;
|
||||
|
||||
if (GetLevel() < ml.level_required)
|
||||
@@ -1134,7 +1079,7 @@ void Client::OPMemorizeSpell(const EQApplicationPacket* app)
|
||||
switch(memspell->scribing)
|
||||
{
|
||||
case memSpellScribing: { // scribing spell to book
|
||||
const EQEmu::ItemInstance* inst = m_inv[EQEmu::inventory::slotCursor];
|
||||
const EQEmu::ItemInstance* inst = m_inv[EQEmu::invslot::slotCursor];
|
||||
|
||||
if (inst && inst->IsClassCommon())
|
||||
{
|
||||
@@ -1148,7 +1093,7 @@ void Client::OPMemorizeSpell(const EQApplicationPacket* app)
|
||||
if(item && item->Scroll.Effect == (int32)(memspell->spell_id))
|
||||
{
|
||||
ScribeSpell(memspell->spell_id, memspell->slot);
|
||||
DeleteItemInInventory(EQEmu::inventory::slotCursor, 1, true);
|
||||
DeleteItemInInventory(EQEmu::invslot::slotCursor, 1, true);
|
||||
}
|
||||
else
|
||||
Message(0,"Scribing spell: inst exists but item does not or spell ids do not match.");
|
||||
@@ -1187,7 +1132,7 @@ void Client::CancelSneakHide()
|
||||
// The later clients send back a OP_Hide (this has a size but data is 0)
|
||||
// as well as OP_SpawnAppearance with AT_Invis and one with AT_Sneak
|
||||
// So we don't have to handle any of those flags
|
||||
if (ClientVersionBit() & EQEmu::versions::bit_SoFAndEarlier)
|
||||
if (ClientVersionBit() & EQEmu::versions::maskSoFAndEarlier)
|
||||
sneaking = false;
|
||||
}
|
||||
}
|
||||
@@ -1541,9 +1486,11 @@ void Client::OPGMTraining(const EQApplicationPacket *app)
|
||||
return;
|
||||
|
||||
//you can only use your own trainer, client enforces this, but why trust it
|
||||
int trains_class = pTrainer->GetClass() - (WARRIORGM - WARRIOR);
|
||||
if(GetClass() != trains_class)
|
||||
return;
|
||||
if (!RuleB(Character, AllowCrossClassTrainers)) {
|
||||
int trains_class = pTrainer->GetClass() - (WARRIORGM - WARRIOR);
|
||||
if (GetClass() != trains_class)
|
||||
return;
|
||||
}
|
||||
|
||||
//you have to be somewhat close to a trainer to be properly using them
|
||||
if(DistanceSquared(m_Position,pTrainer->GetPosition()) > USE_NPC_RANGE2)
|
||||
@@ -1594,9 +1541,11 @@ void Client::OPGMEndTraining(const EQApplicationPacket *app)
|
||||
return;
|
||||
|
||||
//you can only use your own trainer, client enforces this, but why trust it
|
||||
int trains_class = pTrainer->GetClass() - (WARRIORGM - WARRIOR);
|
||||
if(GetClass() != trains_class)
|
||||
return;
|
||||
if (!RuleB(Character, AllowCrossClassTrainers)) {
|
||||
int trains_class = pTrainer->GetClass() - (WARRIORGM - WARRIOR);
|
||||
if (GetClass() != trains_class)
|
||||
return;
|
||||
}
|
||||
|
||||
//you have to be somewhat close to a trainer to be properly using them
|
||||
if(DistanceSquared(m_Position, pTrainer->GetPosition()) > USE_NPC_RANGE2)
|
||||
@@ -1623,9 +1572,11 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app)
|
||||
return;
|
||||
|
||||
//you can only use your own trainer, client enforces this, but why trust it
|
||||
int trains_class = pTrainer->GetClass() - (WARRIORGM - WARRIOR);
|
||||
if(GetClass() != trains_class)
|
||||
return;
|
||||
if (!RuleB(Character, AllowCrossClassTrainers)) {
|
||||
int trains_class = pTrainer->GetClass() - (WARRIORGM - WARRIOR);
|
||||
if (GetClass() != trains_class)
|
||||
return;
|
||||
}
|
||||
|
||||
//you have to be somewhat close to a trainer to be properly using them
|
||||
if(DistanceSquared(m_Position, pTrainer->GetPosition()) > USE_NPC_RANGE2)
|
||||
@@ -1928,12 +1879,11 @@ void Client::DoEnduranceUpkeep() {
|
||||
SetEndurUpkeep(false);
|
||||
}
|
||||
|
||||
void Client::CalcRestState() {
|
||||
|
||||
void Client::CalcRestState()
|
||||
{
|
||||
// This method calculates rest state HP and mana regeneration.
|
||||
// The client must have been out of combat for RuleI(Character, RestRegenTimeToActivate) seconds,
|
||||
// must be sitting down, and must not have any detrimental spells affecting them.
|
||||
//
|
||||
if(!RuleB(Character, RestRegenEnabled))
|
||||
return;
|
||||
|
||||
@@ -1945,6 +1895,9 @@ void Client::CalcRestState() {
|
||||
if(!rest_timer.Check(false))
|
||||
return;
|
||||
|
||||
// so we don't have aggro, our timer has expired, we do not want this to cause issues
|
||||
m_pp.RestTimer = 0;
|
||||
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
for (unsigned int j = 0; j < buff_count; j++) {
|
||||
if(buffs[j].spellid != SPELL_UNKNOWN) {
|
||||
@@ -1955,62 +1908,44 @@ void Client::CalcRestState() {
|
||||
}
|
||||
|
||||
ooc_regen = true;
|
||||
|
||||
}
|
||||
|
||||
void Client::DoTracking()
|
||||
{
|
||||
if(TrackingID == 0)
|
||||
if (TrackingID == 0)
|
||||
return;
|
||||
|
||||
Mob *m = entity_list.GetMob(TrackingID);
|
||||
|
||||
if(!m || m->IsCorpse())
|
||||
{
|
||||
if (!m || m->IsCorpse()) {
|
||||
Message_StringID(MT_Skills, TRACK_LOST_TARGET);
|
||||
|
||||
TrackingID = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
float RelativeHeading = GetHeading() - CalculateHeadingToTarget(m->GetX(), m->GetY());
|
||||
|
||||
if(RelativeHeading < 0)
|
||||
RelativeHeading += 256;
|
||||
if (RelativeHeading < 0)
|
||||
RelativeHeading += 512;
|
||||
|
||||
if((RelativeHeading <= 16) || (RelativeHeading >= 240))
|
||||
{
|
||||
if (RelativeHeading > 480)
|
||||
Message_StringID(MT_Skills, TRACK_STRAIGHT_AHEAD, m->GetCleanName());
|
||||
}
|
||||
else if((RelativeHeading > 16) && (RelativeHeading <= 48))
|
||||
{
|
||||
Message_StringID(MT_Skills, TRACK_AHEAD_AND_TO, m->GetCleanName(), "right");
|
||||
}
|
||||
else if((RelativeHeading > 48) && (RelativeHeading <= 80))
|
||||
{
|
||||
Message_StringID(MT_Skills, TRACK_TO_THE, m->GetCleanName(), "right");
|
||||
}
|
||||
else if((RelativeHeading > 80) && (RelativeHeading <= 112))
|
||||
{
|
||||
Message_StringID(MT_Skills, TRACK_BEHIND_AND_TO, m->GetCleanName(), "right");
|
||||
}
|
||||
else if((RelativeHeading > 112) && (RelativeHeading <= 144))
|
||||
{
|
||||
Message_StringID(MT_Skills, TRACK_BEHIND_YOU, m->GetCleanName());
|
||||
}
|
||||
else if((RelativeHeading > 144) && (RelativeHeading <= 176))
|
||||
{
|
||||
Message_StringID(MT_Skills, TRACK_BEHIND_AND_TO, m->GetCleanName(), "left");
|
||||
}
|
||||
else if((RelativeHeading > 176) && (RelativeHeading <= 208))
|
||||
{
|
||||
Message_StringID(MT_Skills, TRACK_TO_THE, m->GetCleanName(), "left");
|
||||
}
|
||||
else if((RelativeHeading > 208) && (RelativeHeading < 240))
|
||||
{
|
||||
else if (RelativeHeading > 416)
|
||||
Message_StringID(MT_Skills, TRACK_AHEAD_AND_TO, m->GetCleanName(), "left");
|
||||
}
|
||||
else if (RelativeHeading > 352)
|
||||
Message_StringID(MT_Skills, TRACK_TO_THE, m->GetCleanName(), "left");
|
||||
else if (RelativeHeading > 288)
|
||||
Message_StringID(MT_Skills, TRACK_BEHIND_AND_TO, m->GetCleanName(), "left");
|
||||
else if (RelativeHeading > 224)
|
||||
Message_StringID(MT_Skills, TRACK_BEHIND_YOU, m->GetCleanName());
|
||||
else if (RelativeHeading > 160)
|
||||
Message_StringID(MT_Skills, TRACK_BEHIND_AND_TO, m->GetCleanName(), "right");
|
||||
else if (RelativeHeading > 96)
|
||||
Message_StringID(MT_Skills, TRACK_TO_THE, m->GetCleanName(), "right");
|
||||
else if (RelativeHeading > 32)
|
||||
Message_StringID(MT_Skills, TRACK_AHEAD_AND_TO, m->GetCleanName(), "right");
|
||||
else if (RelativeHeading >= 0)
|
||||
Message_StringID(MT_Skills, TRACK_STRAIGHT_AHEAD, m->GetCleanName());
|
||||
}
|
||||
|
||||
void Client::HandleRespawnFromHover(uint32 Option)
|
||||
@@ -2194,7 +2129,7 @@ void Client::ClearHover()
|
||||
entity_list.QueueClients(this, outapp, false);
|
||||
safe_delete(outapp);
|
||||
|
||||
if (IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::bit_UFAndLater)
|
||||
if (IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::maskUFAndLater)
|
||||
{
|
||||
EQApplicationPacket *outapp = MakeBuffsPacket(false);
|
||||
CastToClient()->FastQueuePacket(&outapp);
|
||||
|
||||
Regular → Executable
+2199
-760
File diff suppressed because it is too large
Load Diff
@@ -84,6 +84,7 @@ void command_deletegraveyard(Client *c, const Seperator *sep);
|
||||
void command_delpetition(Client *c, const Seperator *sep);
|
||||
void command_depop(Client *c, const Seperator *sep);
|
||||
void command_depopzone(Client *c, const Seperator *sep);
|
||||
void command_devtools(Client *c, const Seperator *sep);
|
||||
void command_details(Client *c, const Seperator *sep);
|
||||
void command_disablerecipe(Client *c, const Seperator *sep);
|
||||
void command_disarmtrap(Client *c, const Seperator *sep);
|
||||
@@ -116,6 +117,7 @@ void command_givemoney(Client *c, const Seperator *sep);
|
||||
void command_globalview(Client* c, const Seperator *sep);
|
||||
void command_gm(Client *c, const Seperator *sep);
|
||||
void command_gmspeed(Client *c, const Seperator *sep);
|
||||
void command_gmzone(Client *c, const Seperator *sep);
|
||||
void command_goto(Client *c, const Seperator *sep);
|
||||
void command_grid(Client *c, const Seperator *sep);
|
||||
void command_guild(Client *c, const Seperator *sep);
|
||||
@@ -148,10 +150,12 @@ void command_iteminfo(Client *c, const Seperator *sep);
|
||||
void command_itemsearch(Client *c, const Seperator *sep);
|
||||
void command_itemtest(Client *c, const Seperator *sep);
|
||||
void command_kick(Client *c, const Seperator *sep);
|
||||
void command_killallnpcs(Client *c, const Seperator *sep);
|
||||
void command_kill(Client *c, const Seperator *sep);
|
||||
void command_lastname(Client *c, const Seperator *sep);
|
||||
void command_level(Client *c, const Seperator *sep);
|
||||
void command_listnpcs(Client *c, const Seperator *sep);
|
||||
void command_list(Client *c, const Seperator *sep);
|
||||
void command_listpetition(Client *c, const Seperator *sep);
|
||||
void command_load_shared_memory(Client *c, const Seperator *sep);
|
||||
void command_loc(Client *c, const Seperator *sep);
|
||||
@@ -168,12 +172,14 @@ void command_merchantopenshop(Client *c, const Seperator *sep);
|
||||
void command_modifynpcstat(Client *c, const Seperator *sep);
|
||||
void command_motd(Client *c, const Seperator *sep);
|
||||
void command_movechar(Client *c, const Seperator *sep);
|
||||
void command_movement(Client *c, const Seperator *sep);
|
||||
void command_myskills(Client *c, const Seperator *sep);
|
||||
void command_mysql(Client *c, const Seperator *sep);
|
||||
void command_mysqltest(Client *c, const Seperator *sep);
|
||||
void command_mystats(Client *c, const Seperator *sep);
|
||||
void command_name(Client *c, const Seperator *sep);
|
||||
void command_netstats(Client *c, const Seperator *sep);
|
||||
void command_network(Client *c, const Seperator *sep);
|
||||
void command_npccast(Client *c, const Seperator *sep);
|
||||
void command_npcedit(Client *c, const Seperator *sep);
|
||||
void command_npcemote(Client *c, const Seperator *sep);
|
||||
@@ -205,12 +211,15 @@ void command_permagender(Client *c, const Seperator *sep);
|
||||
void command_permarace(Client *c, const Seperator *sep);
|
||||
void command_petitioninfo(Client *c, const Seperator *sep);
|
||||
void command_picklock(Client *c, const Seperator *sep);
|
||||
void command_profanity(Client *c, const Seperator *sep);
|
||||
|
||||
#ifdef EQPROFILE
|
||||
void command_profiledump(Client *c, const Seperator *sep);
|
||||
void command_profilereset(Client *c, const Seperator *sep);
|
||||
#endif
|
||||
|
||||
void command_proximity(Client *c, const Seperator *sep);
|
||||
void command_push(Client *c, const Seperator *sep);
|
||||
void command_pvp(Client *c, const Seperator *sep);
|
||||
void command_qglobal(Client *c, const Seperator *sep);
|
||||
void command_qtest(Client *c, const Seperator *sep);
|
||||
@@ -224,6 +233,7 @@ void command_reloadaa(Client *c, const Seperator *sep);
|
||||
void command_reloadallrules(Client *c, const Seperator *sep);
|
||||
void command_reloademote(Client* c, const Seperator *sep);
|
||||
void command_reloadlevelmods(Client *c, const Seperator *sep);
|
||||
void command_reloadmerchants(Client *c, const Seperator *sep);
|
||||
void command_reloadperlexportsettings(Client *c, const Seperator *sep);
|
||||
void command_reloadqst(Client *c, const Seperator *sep);
|
||||
void command_reloadstatic(Client *c, const Seperator *sep);
|
||||
@@ -239,6 +249,7 @@ void command_resetaa_timer(Client *c, const Seperator *sep);
|
||||
void command_revoke(Client *c, const Seperator *sep);
|
||||
void command_rules(Client *c, const Seperator *sep);
|
||||
void command_save(Client *c, const Seperator *sep);
|
||||
void command_scale(Client *c, const Seperator *sep);
|
||||
void command_scribespell(Client *c, const Seperator *sep);
|
||||
void command_scribespells(Client *c, const Seperator *sep);
|
||||
void command_sendop(Client *c, const Seperator *sep);
|
||||
@@ -266,10 +277,12 @@ void command_setxp(Client *c, const Seperator *sep);
|
||||
void command_showbonusstats(Client *c, const Seperator *sep);
|
||||
void command_showbuffs(Client *c, const Seperator *sep);
|
||||
void command_shownumhits(Client *c, const Seperator *sep);
|
||||
void command_shownpcgloballoot(Client *c, const Seperator *sep);
|
||||
void command_showpetspell(Client *c, const Seperator *sep);
|
||||
void command_showskills(Client *c, const Seperator *sep);
|
||||
void command_showspellslist(Client *c, const Seperator *sep);
|
||||
void command_showstats(Client *c, const Seperator *sep);
|
||||
void command_showzonegloballoot(Client *c, const Seperator *sep);
|
||||
void command_shutdown(Client *c, const Seperator *sep);
|
||||
void command_size(Client *c, const Seperator *sep);
|
||||
void command_spawn(Client *c, const Seperator *sep);
|
||||
@@ -288,6 +301,7 @@ void command_task(Client *c, const Seperator *sep);
|
||||
void command_tattoo(Client *c, const Seperator *sep);
|
||||
void command_tempname(Client *c, const Seperator *sep);
|
||||
void command_petname(Client *c, const Seperator *sep);
|
||||
void command_test(Client *c, const Seperator *sep);
|
||||
void command_testspawn(Client *c, const Seperator *sep);
|
||||
void command_testspawnkill(Client *c, const Seperator *sep);
|
||||
void command_texture(Client *c, const Seperator *sep);
|
||||
@@ -299,6 +313,7 @@ void command_titlesuffix(Client *c, const Seperator *sep);
|
||||
void command_traindisc(Client *c, const Seperator *sep);
|
||||
void command_trapinfo(Client* c, const Seperator *sep);
|
||||
void command_tune(Client *c, const Seperator *sep);
|
||||
void command_ucs(Client *c, const Seperator *sep);
|
||||
void command_undye(Client *c, const Seperator *sep);
|
||||
void command_undyeme(Client *c, const Seperator *sep);
|
||||
void command_unfreeze(Client *c, const Seperator *sep);
|
||||
@@ -313,6 +328,7 @@ void command_viewnpctype(Client *c, const Seperator *sep);
|
||||
void command_viewpetition(Client *c, const Seperator *sep);
|
||||
void command_wc(Client *c, const Seperator *sep);
|
||||
void command_weather(Client *c, const Seperator *sep);
|
||||
void command_who(Client *c, const Seperator *sep);
|
||||
void command_worldshutdown(Client *c, const Seperator *sep);
|
||||
void command_wp(Client *c, const Seperator *sep);
|
||||
void command_wpadd(Client *c, const Seperator *sep);
|
||||
|
||||
+14
-3
@@ -194,7 +194,8 @@ enum {
|
||||
CASTING_RESIST_DIFF = 43,
|
||||
COUNTER_AVOID_DAMAGE = 44,
|
||||
PROX_AGGRO = 45,
|
||||
MAX_SPECIAL_ATTACK = 46
|
||||
IMMUNE_RANGED_ATTACKS = 46,
|
||||
MAX_SPECIAL_ATTACK = 47
|
||||
};
|
||||
|
||||
typedef enum { //fear states
|
||||
@@ -205,8 +206,6 @@ typedef enum { //fear states
|
||||
fearStateStuck //I cannot move somehow...
|
||||
} FearState;
|
||||
|
||||
enum { FlyMode0 = 0, FlyMode1 = 1, Flymode2 = 2, FlyMode3 = 3 };
|
||||
|
||||
// This is actually FlyMode, from MQ2
|
||||
enum GravityBehavior {
|
||||
Ground,
|
||||
@@ -262,6 +261,17 @@ enum class LootResponse : uint8 {
|
||||
LootAll = 6 // SoD+
|
||||
};
|
||||
|
||||
enum class LootRequestType : uint8 {
|
||||
Forbidden = 0,
|
||||
GMPeek,
|
||||
GMAllowed,
|
||||
Self,
|
||||
AllowedPVE,
|
||||
AllowedPVPAll,
|
||||
AllowedPVPSingle, // can make this 'AllowedPVPVariable' and allow values between 1 and EQEmu::invtype::POSSESSIONS_SIZE
|
||||
AllowedPVPDefined,
|
||||
};
|
||||
|
||||
//this is our internal representation of the BUFF struct, can put whatever we want in it
|
||||
struct Buffs_Struct {
|
||||
uint16 spellid;
|
||||
@@ -548,6 +558,7 @@ struct StatBonuses {
|
||||
int16 FeignedCastOnChance; // Percent Value
|
||||
bool PetCommands[PET_MAXCOMMANDS]; // SPA 267
|
||||
int FeignedMinionChance; // SPA 281 base1 = chance, just like normal FD
|
||||
int GrantForage; // affects max skill of forage as well as granting non-forage classes forage
|
||||
int aura_slots;
|
||||
int trap_slots;
|
||||
bool hunger; // Song of Sustenance -- min caps to 3500
|
||||
|
||||
+250
-190
@@ -152,7 +152,8 @@ Corpse::Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NP
|
||||
in_npc->GetDeity(),in_npc->GetLevel(),in_npc->GetNPCTypeID(),in_npc->GetSize(),0,
|
||||
in_npc->GetPosition(), in_npc->GetInnateLightType(), in_npc->GetTexture(),in_npc->GetHelmTexture(),
|
||||
0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,EQEmu::TintProfile(),0xff,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
|
||||
0,0,0,0,0,0,0,0,0,0,EQEmu::TintProfile(),0xff,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
(*in_npctypedata)->use_model),
|
||||
corpse_decay_timer(in_decaytime),
|
||||
corpse_rez_timer(0),
|
||||
corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)),
|
||||
@@ -202,6 +203,8 @@ Corpse::Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NP
|
||||
|
||||
UpdateEquipmentLight();
|
||||
UpdateActiveLight();
|
||||
|
||||
loot_request_type = LootRequestType::Forbidden;
|
||||
}
|
||||
|
||||
Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
||||
@@ -256,6 +259,7 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
||||
0, // uint8 in_bracertexture,
|
||||
0, // uint8 in_handtexture,
|
||||
0, // uint8 in_legtexture,
|
||||
0,
|
||||
0 // uint8 in_feettexture,
|
||||
),
|
||||
corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)),
|
||||
@@ -322,15 +326,11 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
||||
// to go into the regular slots on the player, out of bags
|
||||
std::list<uint32> removed_list;
|
||||
|
||||
for (i = EQEmu::inventory::slotBegin; i < EQEmu::legacy::TYPE_POSSESSIONS_SIZE; ++i) {
|
||||
if (i == EQEmu::inventory::slotAmmo && client->ClientVersion() >= EQEmu::versions::ClientVersion::SoF) {
|
||||
item = client->GetInv().GetItem(EQEmu::inventory::slotPowerSource);
|
||||
if (item != nullptr) {
|
||||
if (!client->IsBecomeNPC() || (client->IsBecomeNPC() && !item->GetItem()->NoRent))
|
||||
MoveItemToCorpse(client, item, EQEmu::inventory::slotPowerSource, removed_list);
|
||||
}
|
||||
}
|
||||
|
||||
// ideally, we would start at invslot::slotGeneral1 and progress to invslot::slotCursor..
|
||||
// ..then regress and process invslot::EQUIPMENT_BEGIN through invslot::EQUIPMENT_END...
|
||||
// without additional work to database loading of player corpses, this order is not
|
||||
// currently preserved and a re-work of this processing loop is not warranted.
|
||||
for (i = EQEmu::invslot::POSSESSIONS_BEGIN; i <= EQEmu::invslot::POSSESSIONS_END; ++i) {
|
||||
item = client->GetInv().GetItem(i);
|
||||
if (item == nullptr) { continue; }
|
||||
|
||||
@@ -340,25 +340,25 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
||||
|
||||
database.TransactionBegin();
|
||||
|
||||
// I have an untested process that avoids this snarl up when all possessions inventory is removed..but this isn't broke
|
||||
// this should not be modified to include the entire range of invtype::TYPE_POSSESSIONS slots by default..
|
||||
// ..due to the possibility of 'hidden' items from client version bias..or, possibly, soul-bound items (WoW?)
|
||||
if (!removed_list.empty()) {
|
||||
std::stringstream ss("");
|
||||
ss << "DELETE FROM inventory WHERE charid=" << client->CharacterID();
|
||||
ss << " AND (";
|
||||
std::list<uint32>::const_iterator iter = removed_list.begin();
|
||||
bool first = true;
|
||||
while (iter != removed_list.end()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
ss << " OR ";
|
||||
}
|
||||
ss << "slotid=" << (*iter);
|
||||
|
||||
if (iter != removed_list.end()) {
|
||||
std::stringstream ss("");
|
||||
ss << "DELETE FROM `inventory` WHERE `charid` = " << client->CharacterID();
|
||||
ss << " AND `slotid` IN (" << (*iter);
|
||||
++iter;
|
||||
|
||||
while (iter != removed_list.end()) {
|
||||
ss << ", " << (*iter);
|
||||
++iter;
|
||||
}
|
||||
ss << ")";
|
||||
|
||||
database.QueryDatabase(ss.str().c_str());
|
||||
}
|
||||
ss << ")";
|
||||
database.QueryDatabase(ss.str().c_str());
|
||||
}
|
||||
|
||||
auto start = client->GetInv().cursor_cbegin();
|
||||
@@ -382,6 +382,8 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
||||
UpdateEquipmentLight();
|
||||
UpdateActiveLight();
|
||||
|
||||
loot_request_type = LootRequestType::Forbidden;
|
||||
|
||||
IsRezzed(false);
|
||||
Save();
|
||||
}
|
||||
@@ -404,9 +406,9 @@ void Corpse::MoveItemToCorpse(Client *client, EQEmu::ItemInstance *inst, int16 e
|
||||
|
||||
while (true) {
|
||||
if (!inst->IsClassBag()) { break; }
|
||||
if (equipSlot < EQEmu::legacy::GENERAL_BEGIN || equipSlot > EQEmu::inventory::slotCursor) { break; }
|
||||
if (equipSlot < EQEmu::invslot::GENERAL_BEGIN || equipSlot > EQEmu::invslot::slotCursor) { break; }
|
||||
|
||||
for (int16 sub_index = EQEmu::inventory::containerBegin; sub_index < EQEmu::inventory::ContainerCount; ++sub_index) {
|
||||
for (int16 sub_index = EQEmu::invbag::SLOT_BEGIN; sub_index <= EQEmu::invbag::SLOT_END; ++sub_index) {
|
||||
int16 real_bag_slot = EQEmu::InventoryProfile::CalcSlotId(equipSlot, sub_index);
|
||||
auto bag_inst = client->GetInv().GetItem(real_bag_slot);
|
||||
if (bag_inst == nullptr) { continue; }
|
||||
@@ -484,6 +486,7 @@ EQEmu::TintProfile(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0),
|
||||
corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)),
|
||||
corpse_rez_timer(RuleI(Character, CorpseResTimeMS)),
|
||||
@@ -524,6 +527,8 @@ EQEmu::TintProfile(),
|
||||
|
||||
UpdateEquipmentLight();
|
||||
UpdateActiveLight();
|
||||
|
||||
loot_request_type = LootRequestType::Forbidden;
|
||||
}
|
||||
|
||||
Corpse::~Corpse() {
|
||||
@@ -684,7 +689,7 @@ ServerLootItem_Struct* Corpse::GetItem(uint16 lootslot, ServerLootItem_Struct**
|
||||
}
|
||||
|
||||
if (sitem && bag_item_data && EQEmu::InventoryProfile::SupportsContainers(sitem->equip_slot)) {
|
||||
int16 bagstart = EQEmu::InventoryProfile::CalcSlotId(sitem->equip_slot, EQEmu::inventory::containerBegin);
|
||||
int16 bagstart = EQEmu::InventoryProfile::CalcSlotId(sitem->equip_slot, EQEmu::invbag::SLOT_BEGIN);
|
||||
|
||||
cur = itemlist.begin();
|
||||
end = itemlist.end();
|
||||
@@ -873,13 +878,16 @@ void Corpse::AllowPlayerLoot(Mob *them, uint8 slot) {
|
||||
}
|
||||
|
||||
void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* app) {
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
// Added 12/08. Started compressing loot struct on live.
|
||||
if(player_corpse_depop) {
|
||||
SendLootReqErrorPacket(client, LootResponse::SomeoneElse);
|
||||
return;
|
||||
}
|
||||
|
||||
if(IsPlayerCorpse() && corpse_db_id == 0) {
|
||||
if(IsPlayerCorpse() && !corpse_db_id) { // really should try to resave in this case
|
||||
// SendLootReqErrorPacket(client, 0);
|
||||
client->Message(13, "Warning: Corpse's dbid = 0! Corpse will not survive zone shutdown!");
|
||||
std::cout << "Error: PlayerCorpse::MakeLootRequestPackets: dbid = 0!" << std::endl;
|
||||
@@ -892,165 +900,195 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
|
||||
return;
|
||||
}
|
||||
|
||||
if(being_looted_by == 0)
|
||||
if(!being_looted_by || (being_looted_by != 0xFFFFFFFF && !entity_list.GetID(being_looted_by)))
|
||||
being_looted_by = 0xFFFFFFFF;
|
||||
|
||||
if(this->being_looted_by != 0xFFFFFFFF) {
|
||||
// lets double check....
|
||||
Entity* looter = entity_list.GetID(this->being_looted_by);
|
||||
if(looter == nullptr)
|
||||
this->being_looted_by = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
uint8 Loot_Request_Type = 1;
|
||||
bool loot_coin = false;
|
||||
std::string tmp;
|
||||
if(database.GetVariable("LootCoin", tmp))
|
||||
loot_coin = tmp[0] == 1 && tmp[1] == '\0';
|
||||
|
||||
if (DistanceSquaredNoZ(client->GetPosition(), m_Position) > 625) {
|
||||
SendLootReqErrorPacket(client, LootResponse::TooFar);
|
||||
// not sure if we need to send the packet back in this case? Didn't before!
|
||||
// Will just return for now
|
||||
return;
|
||||
}
|
||||
else if (this->being_looted_by != 0xFFFFFFFF && this->being_looted_by != client->GetID()) {
|
||||
|
||||
if (being_looted_by != 0xFFFFFFFF && being_looted_by != client->GetID()) {
|
||||
SendLootReqErrorPacket(client, LootResponse::SomeoneElse);
|
||||
Loot_Request_Type = 0;
|
||||
}
|
||||
else if (IsPlayerCorpse() && char_id == client->CharacterID()) {
|
||||
Loot_Request_Type = 2;
|
||||
}
|
||||
else if ((IsNPCCorpse() || become_npc) && CanPlayerLoot(client->CharacterID())) {
|
||||
Loot_Request_Type = 2;
|
||||
}
|
||||
else if (GetPlayerKillItem() == -1 && CanPlayerLoot(client->CharacterID())) { /* PVP loot all items, variable cash */
|
||||
Loot_Request_Type = 3;
|
||||
}
|
||||
else if (GetPlayerKillItem() == 1 && CanPlayerLoot(client->CharacterID())) { /* PVP loot 1 item, variable cash */
|
||||
Loot_Request_Type = 4;
|
||||
}
|
||||
else if (GetPlayerKillItem() > 1 && CanPlayerLoot(client->CharacterID())) { /* PVP loot 1 set item, variable cash */
|
||||
Loot_Request_Type = 5;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Loot_Request_Type == 1) {
|
||||
if (client->Admin() < 100 || !client->GetGM()) {
|
||||
SendLootReqErrorPacket(client, LootResponse::NotAtThisTime);
|
||||
// all loot session disqualifiers should occur before this point as not to interfere with any current looter
|
||||
loot_request_type = LootRequestType::Forbidden;
|
||||
|
||||
// loot_request_type is scoped to class Corpse and reset on a per-loot session basis
|
||||
if (client->GetGM()) {
|
||||
if (client->Admin() >= 100)
|
||||
loot_request_type = LootRequestType::GMAllowed;
|
||||
else
|
||||
loot_request_type = LootRequestType::GMPeek;
|
||||
}
|
||||
else {
|
||||
if (IsPlayerCorpse()) {
|
||||
if (char_id == client->CharacterID()) {
|
||||
loot_request_type = LootRequestType::Self;
|
||||
}
|
||||
else if (CanPlayerLoot(client->CharacterID())) {
|
||||
if (GetPlayerKillItem() == -1)
|
||||
loot_request_type = LootRequestType::AllowedPVPAll;
|
||||
else if (GetPlayerKillItem() == 1)
|
||||
loot_request_type = LootRequestType::AllowedPVPSingle;
|
||||
else if (GetPlayerKillItem() > 1)
|
||||
loot_request_type = LootRequestType::AllowedPVPDefined;
|
||||
}
|
||||
}
|
||||
else if ((IsNPCCorpse() || become_npc) && CanPlayerLoot(client->CharacterID())) {
|
||||
loot_request_type = LootRequestType::AllowedPVE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(Loot_Request_Type >= 2 || (Loot_Request_Type == 1 && client->Admin() >= 100 && client->GetGM())) {
|
||||
client->CommonBreakInvisible(); // we should be "all good" so lets break invis now instead of earlier before all error checking is done
|
||||
this->being_looted_by = client->GetID();
|
||||
Log(Logs::Moderate, Logs::Inventory, "MakeLootRequestPackets() LootRequestType %u for %s", loot_request_type, client->GetName());
|
||||
|
||||
if (loot_request_type == LootRequestType::Forbidden) {
|
||||
SendLootReqErrorPacket(client, LootResponse::NotAtThisTime);
|
||||
return;
|
||||
}
|
||||
|
||||
being_looted_by = client->GetID();
|
||||
client->CommonBreakInvisible(); // we should be "all good" so lets break invis now instead of earlier before all error checking is done
|
||||
|
||||
// process coin
|
||||
bool loot_coin = false;
|
||||
std::string tmp;
|
||||
if (database.GetVariable("LootCoin", tmp))
|
||||
loot_coin = (tmp[0] == 1 && tmp[1] == '\0');
|
||||
|
||||
if (loot_request_type == LootRequestType::GMPeek || loot_request_type == LootRequestType::GMAllowed) {
|
||||
client->Message(15, "This corpse contains %u platinum, %u gold, %u silver and %u copper.",
|
||||
GetPlatinum(), GetGold(), GetSilver(), GetCopper());
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_MoneyOnCorpse, sizeof(moneyOnCorpseStruct));
|
||||
moneyOnCorpseStruct* d = (moneyOnCorpseStruct*) outapp->pBuffer;
|
||||
moneyOnCorpseStruct* d = (moneyOnCorpseStruct*)outapp->pBuffer;
|
||||
|
||||
d->response = static_cast<uint8>(LootResponse::Normal);
|
||||
d->unknown1 = 0x42;
|
||||
d->unknown2 = 0xef;
|
||||
d->response = static_cast<uint8>(LootResponse::Normal);
|
||||
d->unknown1 = 0x42;
|
||||
d->unknown2 = 0xef;
|
||||
|
||||
/* Dont take the coin off if it's a gm peeking at the corpse */
|
||||
if(Loot_Request_Type == 2 || (Loot_Request_Type >= 3 && loot_coin)) {
|
||||
if(!IsPlayerCorpse() && client->IsGrouped() && client->AutoSplitEnabled() && client->GetGroup()) {
|
||||
d->copper = 0;
|
||||
d->silver = 0;
|
||||
d->gold = 0;
|
||||
d->platinum = 0;
|
||||
Group *cgroup = client->GetGroup();
|
||||
cgroup->SplitMoney(GetCopper(), GetSilver(), GetGold(), GetPlatinum(), client);
|
||||
}
|
||||
else {
|
||||
d->copper = this->GetCopper();
|
||||
d->silver = this->GetSilver();
|
||||
d->gold = this->GetGold();
|
||||
d->platinum = this->GetPlatinum();
|
||||
client->AddMoneyToPP(GetCopper(), GetSilver(), GetGold(), GetPlatinum(), false);
|
||||
}
|
||||
d->copper = 0;
|
||||
d->silver = 0;
|
||||
d->gold = 0;
|
||||
d->platinum = 0;
|
||||
|
||||
RemoveCash();
|
||||
Save();
|
||||
}
|
||||
|
||||
auto timestamps = database.GetItemRecastTimestamps(client->CharacterID());
|
||||
outapp->priority = 6;
|
||||
client->QueuePacket(outapp);
|
||||
|
||||
safe_delete(outapp);
|
||||
if(Loot_Request_Type == 5) {
|
||||
int pkitem = GetPlayerKillItem();
|
||||
const EQEmu::ItemData* item = database.GetItem(pkitem);
|
||||
EQEmu::ItemInstance* inst = database.CreateItem(item, item->MaxCharges);
|
||||
if(inst) {
|
||||
if (item->RecastDelay)
|
||||
inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0);
|
||||
client->SendItemPacket(EQEmu::legacy::CORPSE_BEGIN, inst, ItemPacketLoot);
|
||||
safe_delete(inst);
|
||||
}
|
||||
else { client->Message(13, "Could not find item number %i to send!!", GetPlayerKillItem()); }
|
||||
}
|
||||
else {
|
||||
auto outapp = new EQApplicationPacket(OP_MoneyOnCorpse, sizeof(moneyOnCorpseStruct));
|
||||
moneyOnCorpseStruct* d = (moneyOnCorpseStruct*)outapp->pBuffer;
|
||||
|
||||
client->QueuePacket(app);
|
||||
return;
|
||||
d->response = static_cast<uint8>(LootResponse::Normal);
|
||||
d->unknown1 = 0x42;
|
||||
d->unknown2 = 0xef;
|
||||
|
||||
Group* cgroup = client->GetGroup();
|
||||
|
||||
// this can be reworked into a switch and/or massaged to include specialized pve loot rules based on 'LootRequestType'
|
||||
if (!IsPlayerCorpse() && client->IsGrouped() && client->AutoSplitEnabled() && cgroup) {
|
||||
d->copper = 0;
|
||||
d->silver = 0;
|
||||
d->gold = 0;
|
||||
d->platinum = 0;
|
||||
cgroup->SplitMoney(GetCopper(), GetSilver(), GetGold(), GetPlatinum(), client);
|
||||
}
|
||||
else {
|
||||
d->copper = GetCopper();
|
||||
d->silver = GetSilver();
|
||||
d->gold = GetGold();
|
||||
d->platinum = GetPlatinum();
|
||||
client->AddMoneyToPP(GetCopper(), GetSilver(), GetGold(), GetPlatinum(), false);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
const EQEmu::ItemData* item = nullptr;
|
||||
ItemList::iterator cur,end;
|
||||
cur = itemlist.begin();
|
||||
end = itemlist.end();
|
||||
RemoveCash();
|
||||
Save();
|
||||
|
||||
int corpselootlimit = EQEmu::inventory::Lookup(EQEmu::versions::ConvertClientVersionToMobVersion(client->ClientVersion()))->InventoryTypeSize[EQEmu::inventory::typeCorpse];
|
||||
outapp->priority = 6;
|
||||
client->QueuePacket(outapp);
|
||||
|
||||
for(; cur != end; ++cur) {
|
||||
ServerLootItem_Struct* item_data = *cur;
|
||||
item_data->lootslot = 0xFFFF;
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
// Dont display the item if it's in a bag
|
||||
// process items
|
||||
auto timestamps = database.GetItemRecastTimestamps(client->CharacterID());
|
||||
|
||||
// Added cursor queue slots to corpse item visibility list. Nothing else should be making it to corpse.
|
||||
if (!IsPlayerCorpse() || item_data->equip_slot <= EQEmu::inventory::slotCursor || item_data->equip_slot == EQEmu::inventory::slotPowerSource || Loot_Request_Type >= 3 ||
|
||||
(item_data->equip_slot >= 8000 && item_data->equip_slot <= 8999)) {
|
||||
if(i < corpselootlimit) {
|
||||
item = database.GetItem(item_data->item_id);
|
||||
if(client && item) {
|
||||
EQEmu::ItemInstance* inst = database.CreateItem(item, item_data->charges, item_data->aug_1, item_data->aug_2, item_data->aug_3, item_data->aug_4, item_data->aug_5, item_data->aug_6, item_data->attuned);
|
||||
if(inst) {
|
||||
if (item->RecastDelay)
|
||||
inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0);
|
||||
// SlotGeneral1 is the corpse inventory start offset for Ti(EMu) - CORPSE_END = SlotGeneral1 + SlotCursor
|
||||
client->SendItemPacket(i + EQEmu::legacy::CORPSE_BEGIN, inst, ItemPacketLoot);
|
||||
safe_delete(inst);
|
||||
}
|
||||
if (loot_request_type == LootRequestType::AllowedPVPDefined) {
|
||||
auto pkitemid = GetPlayerKillItem();
|
||||
auto pkitem = database.GetItem(pkitemid);
|
||||
auto pkinst = database.CreateItem(pkitem, pkitem->MaxCharges);
|
||||
|
||||
item_data->lootslot = i;
|
||||
}
|
||||
}
|
||||
if (pkinst) {
|
||||
if (pkitem->RecastDelay)
|
||||
pkinst->SetRecastTimestamp(timestamps.count(pkitem->RecastType) ? timestamps.at(pkitem->RecastType) : 0);
|
||||
|
||||
i++;
|
||||
}
|
||||
Log(Logs::Detail, Logs::Inventory, "MakeLootRequestPackets() Slot %u, Item '%s'", EQEmu::invslot::CORPSE_BEGIN, pkitem->Name);
|
||||
|
||||
client->SendItemPacket(EQEmu::invslot::CORPSE_BEGIN, pkinst, ItemPacketLoot);
|
||||
safe_delete(pkinst);
|
||||
}
|
||||
else {
|
||||
Log(Logs::General, Logs::Inventory, "MakeLootRequestPackets() PlayerKillItem %i not found", pkitemid);
|
||||
|
||||
client->Message(CC_Red, "PlayerKillItem (id: %i) could not be found!", pkitemid);
|
||||
}
|
||||
|
||||
if(IsPlayerCorpse() && (char_id == client->CharacterID() || client->GetGM())) {
|
||||
if(i > corpselootlimit) {
|
||||
client->Message(15, "*** This corpse contains more items than can be displayed! ***");
|
||||
client->Message(0, "Remove items and re-loot corpse to access remaining inventory.");
|
||||
client->Message(0, "(%s contains %i additional %s.)", GetName(), (i - corpselootlimit), (i - corpselootlimit) == 1 ? "item" : "items");
|
||||
}
|
||||
client->QueuePacket(app);
|
||||
return;
|
||||
}
|
||||
|
||||
if(IsPlayerCorpse() && i == 0 && itemlist.size() > 0) { // somehow, player corpse contains items, but client doesn't see them...
|
||||
client->Message(13, "This corpse contains items that are inaccessable!");
|
||||
client->Message(15, "Contact a GM for item replacement, if necessary.");
|
||||
client->Message(15, "BUGGED CORPSE [DBID: %i, Name: %s, Item Count: %i]", GetCorpseDBID(), GetName(), itemlist.size());
|
||||
auto loot_slot = EQEmu::invslot::CORPSE_BEGIN;
|
||||
auto corpse_mask = client->GetInv().GetLookup()->CorpseBitmask;
|
||||
|
||||
for (auto item_data : itemlist) {
|
||||
// every loot session must either set all items' lootslots to 'invslot::SLOT_INVALID'
|
||||
// or to a valid enumerated client-versioned corpse slot (lootslot is not equip_slot)
|
||||
item_data->lootslot = 0xFFFF;
|
||||
|
||||
// align server and client corpse slot mappings so translators can function properly
|
||||
while (loot_slot <= EQEmu::invslot::CORPSE_END && (((uint64)1 << loot_slot) & corpse_mask) == 0)
|
||||
++loot_slot;
|
||||
|
||||
if (loot_slot > EQEmu::invslot::CORPSE_END)
|
||||
continue;
|
||||
|
||||
cur = itemlist.begin();
|
||||
end = itemlist.end();
|
||||
for(; cur != end; ++cur) {
|
||||
ServerLootItem_Struct* item_data = *cur;
|
||||
item = database.GetItem(item_data->item_id);
|
||||
Log(Logs::General, Logs::None, "Corpse Looting: %s was not sent to client loot window (corpse_dbid: %i, charname: %s(%s))", item->Name, GetCorpseDBID(), client->GetName(), client->GetGM() ? "GM" : "Owner");
|
||||
client->Message(0, "Inaccessable Corpse Item: %s", item->Name);
|
||||
}
|
||||
}
|
||||
if (IsPlayerCorpse()) {
|
||||
if (loot_request_type == LootRequestType::AllowedPVPSingle && loot_slot != EQEmu::invslot::CORPSE_BEGIN)
|
||||
continue;
|
||||
|
||||
if (item_data->equip_slot < EQEmu::invslot::POSSESSIONS_BEGIN || item_data->equip_slot > EQEmu::invslot::POSSESSIONS_END)
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto *item = database.GetItem(item_data->item_id);
|
||||
auto inst = database.CreateItem(
|
||||
item,
|
||||
item_data->charges,
|
||||
item_data->aug_1,
|
||||
item_data->aug_2,
|
||||
item_data->aug_3,
|
||||
item_data->aug_4,
|
||||
item_data->aug_5,
|
||||
item_data->aug_6,
|
||||
item_data->attuned
|
||||
);
|
||||
if (!inst)
|
||||
continue;
|
||||
|
||||
if (item->RecastDelay)
|
||||
inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0);
|
||||
|
||||
Log(Logs::Moderate, Logs::Inventory, "MakeLootRequestPackets() Slot %i, Item '%s'", loot_slot, item->Name);
|
||||
|
||||
client->SendItemPacket(loot_slot, inst, ItemPacketLoot);
|
||||
safe_delete(inst);
|
||||
|
||||
item_data->lootslot = loot_slot++;
|
||||
}
|
||||
|
||||
// Disgrace: Client seems to require that we send the packet back...
|
||||
@@ -1064,8 +1102,22 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
|
||||
|
||||
void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
{
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
auto lootitem = (LootingItem_Struct *)app->pBuffer;
|
||||
|
||||
Log(Logs::Moderate, Logs::Inventory, "LootItem() LootRequestType %u, Slot %u for %s", loot_request_type, lootitem->slot_id, client->GetName());
|
||||
|
||||
if (loot_request_type < LootRequestType::GMAllowed) { // LootRequestType::Forbidden and LootRequestType::GMPeek
|
||||
client->QueuePacket(app);
|
||||
SendEndLootErrorPacket(client);
|
||||
// unlock corpse for others
|
||||
if (IsBeingLootedBy(client))
|
||||
ResetLooter();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!loot_cooldown_timer.Check()) {
|
||||
client->QueuePacket(app);
|
||||
SendEndLootErrorPacket(client);
|
||||
@@ -1093,7 +1145,7 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
if (IsPlayerCorpse() && !CanPlayerLoot(client->CharacterID()) && !become_npc &&
|
||||
(char_id != client->CharacterID() && client->Admin() < 150)) {
|
||||
(char_id != client->CharacterID() && client->Admin() < 150)) {
|
||||
client->Message(13, "Error: This is a player corpse and you dont own it.");
|
||||
client->QueuePacket(app);
|
||||
SendEndLootErrorPacket(client);
|
||||
@@ -1108,7 +1160,7 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
if (IsPlayerCorpse() && (char_id != client->CharacterID()) && CanPlayerLoot(client->CharacterID()) &&
|
||||
GetPlayerKillItem() == 0) {
|
||||
GetPlayerKillItem() == 0) {
|
||||
client->Message(13, "Error: You cannot loot any more items from this corpse.");
|
||||
client->QueuePacket(app);
|
||||
SendEndLootErrorPacket(client);
|
||||
@@ -1123,12 +1175,13 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
memset(bag_item_data, 0, sizeof(bag_item_data));
|
||||
if (GetPlayerKillItem() > 1) {
|
||||
item = database.GetItem(GetPlayerKillItem());
|
||||
} else if (GetPlayerKillItem() == -1 || GetPlayerKillItem() == 1) {
|
||||
}
|
||||
else if (GetPlayerKillItem() == -1 || GetPlayerKillItem() == 1) {
|
||||
item_data =
|
||||
GetItem(lootitem->slot_id -
|
||||
EQEmu::legacy::CORPSE_BEGIN); // dont allow them to loot entire bags of items as pvp reward
|
||||
} else {
|
||||
item_data = GetItem(lootitem->slot_id - EQEmu::legacy::CORPSE_BEGIN, bag_item_data);
|
||||
GetItem(lootitem->slot_id); // dont allow them to loot entire bags of items as pvp reward
|
||||
}
|
||||
else {
|
||||
item_data = GetItem(lootitem->slot_id, bag_item_data);
|
||||
}
|
||||
|
||||
if (GetPlayerKillItem() <= 1 && item_data != 0) {
|
||||
@@ -1138,9 +1191,10 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
if (item != 0) {
|
||||
if (item_data) {
|
||||
inst = database.CreateItem(item, item_data ? item_data->charges : 0, item_data->aug_1,
|
||||
item_data->aug_2, item_data->aug_3, item_data->aug_4,
|
||||
item_data->aug_5, item_data->aug_6, item_data->attuned);
|
||||
} else {
|
||||
item_data->aug_2, item_data->aug_3, item_data->aug_4,
|
||||
item_data->aug_5, item_data->aug_6, item_data->attuned);
|
||||
}
|
||||
else {
|
||||
inst = database.CreateItem(item);
|
||||
}
|
||||
}
|
||||
@@ -1156,7 +1210,7 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
if (inst->IsAugmented()) {
|
||||
for (int i = EQEmu::inventory::socketBegin; i < EQEmu::inventory::SocketCount; i++) {
|
||||
for (int i = EQEmu::invaug::SOCKET_BEGIN; i <= EQEmu::invaug::SOCKET_END; i++) {
|
||||
EQEmu::ItemInstance *itm = inst->GetAugment(i);
|
||||
if (itm) {
|
||||
if (client->CheckLoreConflict(itm->GetItem())) {
|
||||
@@ -1175,7 +1229,7 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
char q_corpse_name[64];
|
||||
strcpy(q_corpse_name, corpse_name);
|
||||
snprintf(buf, 87, "%d %d %s", inst->GetItem()->ID, inst->GetCharges(),
|
||||
EntityList::RemoveNumbers(q_corpse_name));
|
||||
EntityList::RemoveNumbers(q_corpse_name));
|
||||
buf[87] = '\0';
|
||||
std::vector<EQEmu::Any> args;
|
||||
args.push_back(inst);
|
||||
@@ -1187,6 +1241,8 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
delete inst;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// do we want this to have a fail option too?
|
||||
parse->EventItem(EVENT_LOOT, client, inst, this, buf, 0);
|
||||
|
||||
@@ -1210,9 +1266,10 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
/* First add it to the looter - this will do the bag contents too */
|
||||
if (lootitem->auto_loot > 0) {
|
||||
if (!client->AutoPutLootInInventory(*inst, true, true, bag_item_data))
|
||||
client->PutLootInInventory(EQEmu::inventory::slotCursor, *inst, bag_item_data);
|
||||
} else {
|
||||
client->PutLootInInventory(EQEmu::inventory::slotCursor, *inst, bag_item_data);
|
||||
client->PutLootInInventory(EQEmu::invslot::slotCursor, *inst, bag_item_data);
|
||||
}
|
||||
else {
|
||||
client->PutLootInInventory(EQEmu::invslot::slotCursor, *inst, bag_item_data);
|
||||
}
|
||||
|
||||
/* Update any tasks that have an activity to loot this item */
|
||||
@@ -1222,22 +1279,22 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
/* Remove it from Corpse */
|
||||
if (item_data) {
|
||||
/* Delete needs to be before RemoveItem because its deletes the pointer for
|
||||
* item_data/bag_item_data */
|
||||
* item_data/bag_item_data */
|
||||
database.DeleteItemOffCharacterCorpse(this->corpse_db_id, item_data->equip_slot,
|
||||
item_data->item_id);
|
||||
item_data->item_id);
|
||||
/* Delete Item Instance */
|
||||
RemoveItem(item_data->lootslot);
|
||||
}
|
||||
|
||||
/* Remove Bag Contents */
|
||||
if (item->IsClassBag() && (GetPlayerKillItem() != -1 || GetPlayerKillItem() != 1)) {
|
||||
for (int i = EQEmu::inventory::containerBegin; i < EQEmu::inventory::ContainerCount; i++) {
|
||||
for (int i = EQEmu::invbag::SLOT_BEGIN; i <= EQEmu::invbag::SLOT_END; i++) {
|
||||
if (bag_item_data[i]) {
|
||||
/* Delete needs to be before RemoveItem because its deletes the pointer for
|
||||
* item_data/bag_item_data */
|
||||
* item_data/bag_item_data */
|
||||
database.DeleteItemOffCharacterCorpse(this->corpse_db_id,
|
||||
bag_item_data[i]->equip_slot,
|
||||
bag_item_data[i]->item_id);
|
||||
bag_item_data[i]->equip_slot,
|
||||
bag_item_data[i]->item_id);
|
||||
/* Delete Item Instance */
|
||||
RemoveItem(bag_item_data[i]);
|
||||
}
|
||||
@@ -1253,24 +1310,26 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
linker.SetLinkType(EQEmu::saylink::SayLinkItemInst);
|
||||
linker.SetItemInst(inst);
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
linker.GenerateLink();
|
||||
|
||||
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, item_link.c_str());
|
||||
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, linker.Link().c_str());
|
||||
|
||||
if (!IsPlayerCorpse()) {
|
||||
Group *g = client->GetGroup();
|
||||
if (g != nullptr) {
|
||||
g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE,
|
||||
client->GetName(), item_link.c_str());
|
||||
} else {
|
||||
client->GetName(), linker.Link().c_str());
|
||||
}
|
||||
else {
|
||||
Raid *r = client->GetRaid();
|
||||
if (r != nullptr) {
|
||||
r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE,
|
||||
client->GetName(), item_link.c_str());
|
||||
client->GetName(), linker.Link().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
SendEndLootErrorPacket(client);
|
||||
safe_delete(inst);
|
||||
return;
|
||||
@@ -1278,7 +1337,8 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
|
||||
if (IsPlayerCorpse()) {
|
||||
client->SendItemLink(inst);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
client->SendItemLink(inst, true);
|
||||
}
|
||||
|
||||
@@ -1317,13 +1377,13 @@ void Corpse::QueryLoot(Client* to) {
|
||||
cur = itemlist.begin();
|
||||
end = itemlist.end();
|
||||
|
||||
int corpselootlimit = EQEmu::inventory::Lookup(EQEmu::versions::ConvertClientVersionToMobVersion(to->ClientVersion()))->InventoryTypeSize[EQEmu::inventory::typeCorpse];
|
||||
int corpselootlimit = to->GetInv().GetLookup()->InventoryTypeSize.Corpse;
|
||||
|
||||
for(; cur != end; ++cur) {
|
||||
ServerLootItem_Struct* sitem = *cur;
|
||||
|
||||
if (IsPlayerCorpse()) {
|
||||
if (sitem->equip_slot >= EQEmu::legacy::GENERAL_BAGS_BEGIN && sitem->equip_slot <= EQEmu::legacy::CURSOR_BAG_END)
|
||||
if (sitem->equip_slot >= EQEmu::invbag::GENERAL_BAGS_BEGIN && sitem->equip_slot <= EQEmu::invbag::CURSOR_BAG_END)
|
||||
sitem->lootslot = 0xFFFF;
|
||||
else
|
||||
x < corpselootlimit ? sitem->lootslot = x : sitem->lootslot = 0xFFFF;
|
||||
@@ -1422,7 +1482,7 @@ void Corpse::Spawn() {
|
||||
safe_delete(app);
|
||||
}
|
||||
|
||||
uint32 Corpse::GetEquipment(uint8 material_slot) const {
|
||||
uint32 Corpse::GetEquippedItemFromTextureSlot(uint8 material_slot) const {
|
||||
int16 invslot;
|
||||
|
||||
if (material_slot > EQEmu::textures::LastTexture) {
|
||||
@@ -1443,7 +1503,7 @@ uint32 Corpse::GetEquipmentColor(uint8 material_slot) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
item = database.GetItem(GetEquipment(material_slot));
|
||||
item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot));
|
||||
if(item != 0) {
|
||||
return (item_tint.Slot[material_slot].UseTint ? item_tint.Slot[material_slot].Color : item->Color);
|
||||
}
|
||||
@@ -1457,8 +1517,8 @@ void Corpse::UpdateEquipmentLight()
|
||||
m_Light.Level[EQEmu::lightsource::LightEquipment] = 0;
|
||||
|
||||
for (auto iter = itemlist.begin(); iter != itemlist.end(); ++iter) {
|
||||
if (((*iter)->equip_slot < EQEmu::legacy::EQUIPMENT_BEGIN || (*iter)->equip_slot > EQEmu::legacy::EQUIPMENT_END) && (*iter)->equip_slot != EQEmu::inventory::slotPowerSource) { continue; }
|
||||
if ((*iter)->equip_slot == EQEmu::inventory::slotAmmo) { continue; }
|
||||
if ((*iter)->equip_slot < EQEmu::invslot::EQUIPMENT_BEGIN || (*iter)->equip_slot > EQEmu::invslot::EQUIPMENT_END) { continue; }
|
||||
if ((*iter)->equip_slot == EQEmu::invslot::slotAmmo) { continue; }
|
||||
|
||||
auto item = database.GetItem((*iter)->item_id);
|
||||
if (item == nullptr) { continue; }
|
||||
@@ -1469,7 +1529,7 @@ void Corpse::UpdateEquipmentLight()
|
||||
|
||||
uint8 general_light_type = 0;
|
||||
for (auto iter = itemlist.begin(); iter != itemlist.end(); ++iter) {
|
||||
if ((*iter)->equip_slot < EQEmu::legacy::GENERAL_BEGIN || (*iter)->equip_slot > EQEmu::legacy::GENERAL_END) { continue; }
|
||||
if ((*iter)->equip_slot < EQEmu::invslot::GENERAL_BEGIN || (*iter)->equip_slot > EQEmu::invslot::GENERAL_END) { continue; }
|
||||
|
||||
auto item = database.GetItem((*iter)->item_id);
|
||||
if (item == nullptr) { continue; }
|
||||
|
||||
+4
-3
@@ -53,7 +53,7 @@ class Corpse : public Mob {
|
||||
/* Corpse: General */
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) { return true; }
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) { return; }
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = true, bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) { return false; }
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = true, bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) { return false; }
|
||||
virtual bool HasRaid() { return false; }
|
||||
virtual bool HasGroup() { return false; }
|
||||
virtual Raid* GetRaid() { return 0; }
|
||||
@@ -116,7 +116,7 @@ class Corpse : public Mob {
|
||||
inline void Lock() { is_locked = true; }
|
||||
inline void UnLock() { is_locked = false; }
|
||||
inline bool IsLocked() { return is_locked; }
|
||||
inline void ResetLooter() { being_looted_by = 0xFFFFFFFF; }
|
||||
inline void ResetLooter() { being_looted_by = 0xFFFFFFFF; loot_request_type = LootRequestType::Forbidden; }
|
||||
inline bool IsBeingLooted() { return (being_looted_by != 0xFFFFFFFF); }
|
||||
inline bool IsBeingLootedBy(Client *c) { return being_looted_by == c->GetID(); }
|
||||
|
||||
@@ -126,7 +126,7 @@ class Corpse : public Mob {
|
||||
void Spawn();
|
||||
|
||||
char corpse_name[64];
|
||||
uint32 GetEquipment(uint8 material_slot) const;
|
||||
uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const;
|
||||
uint32 GetEquipmentColor(uint8 material_slot) const;
|
||||
inline int GetRezExp() { return rez_experience; }
|
||||
|
||||
@@ -161,6 +161,7 @@ private:
|
||||
Timer loot_cooldown_timer; /* Delay between loot actions on the corpse entity */
|
||||
EQEmu::TintProfile item_tint;
|
||||
|
||||
LootRequestType loot_request_type;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
#include "data_bucket.h"
|
||||
#include <utility>
|
||||
#include "../common/string_util.h"
|
||||
#include "zonedb.h"
|
||||
#include <ctime>
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
|
||||
/**
|
||||
* Persists data via bucket_name as key
|
||||
* @param bucket_key
|
||||
* @param bucket_value
|
||||
* @param expires_time
|
||||
*/
|
||||
void DataBucket::SetData(std::string bucket_key, std::string bucket_value, std::string expires_time) {
|
||||
uint64 bucket_id = DataBucket::DoesBucketExist(bucket_key);
|
||||
|
||||
std::string query;
|
||||
long long expires_time_unix = 0;
|
||||
|
||||
if (!expires_time.empty()) {
|
||||
if (isalpha(expires_time[0]) || isalpha(expires_time[expires_time.length() - 1])) {
|
||||
expires_time_unix = (long long) std::time(nullptr) + DataBucket::ParseStringTimeToInt(expires_time);
|
||||
} else {
|
||||
expires_time_unix = (long long) std::time(nullptr) + atoi(expires_time.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (bucket_id > 0) {
|
||||
std::string update_expired_time;
|
||||
if (expires_time_unix > 0) {
|
||||
update_expired_time = StringFormat(", `expires` = %lld ", expires_time_unix);
|
||||
}
|
||||
|
||||
query = StringFormat(
|
||||
"UPDATE `data_buckets` SET `value` = '%s' %s WHERE `id` = %i",
|
||||
EscapeString(bucket_value).c_str(),
|
||||
EscapeString(update_expired_time).c_str(),
|
||||
bucket_id
|
||||
);
|
||||
}
|
||||
else {
|
||||
query = StringFormat(
|
||||
"INSERT INTO `data_buckets` (`key`, `value`, `expires`) VALUES ('%s', '%s', '%lld')",
|
||||
EscapeString(bucket_key).c_str(),
|
||||
EscapeString(bucket_value).c_str(),
|
||||
expires_time_unix
|
||||
);
|
||||
}
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves data via bucket_name as key
|
||||
* @param bucket_key
|
||||
* @return
|
||||
*/
|
||||
std::string DataBucket::GetData(std::string bucket_key) {
|
||||
std::string query = StringFormat(
|
||||
"SELECT `value` from `data_buckets` WHERE `key` = '%s' AND (`expires` > %lld OR `expires` = 0) LIMIT 1",
|
||||
bucket_key.c_str(),
|
||||
(long long) std::time(nullptr)
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return std::string();
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return std::string(row[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves data expires time via bucket_name as key
|
||||
* @param bucket_key
|
||||
* @return
|
||||
*/
|
||||
std::string DataBucket::GetDataExpires(std::string bucket_key) {
|
||||
std::string query = StringFormat(
|
||||
"SELECT `expires` from `data_buckets` WHERE `key` = '%s' AND (`expires` > %lld OR `expires` = 0) LIMIT 1",
|
||||
bucket_key.c_str(),
|
||||
(long long) std::time(nullptr)
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return std::string();
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return std::string(row[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for bucket existence by bucket_name key
|
||||
* @param bucket_key
|
||||
* @return
|
||||
*/
|
||||
uint64 DataBucket::DoesBucketExist(std::string bucket_key) {
|
||||
std::string query = StringFormat(
|
||||
"SELECT `id` from `data_buckets` WHERE `key` = '%s' AND (`expires` > %lld OR `expires` = 0) LIMIT 1",
|
||||
EscapeString(bucket_key).c_str(),
|
||||
(long long) std::time(nullptr)
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
|
||||
return std::stoull(row[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes data bucket by key
|
||||
* @param bucket_key
|
||||
* @return
|
||||
*/
|
||||
bool DataBucket::DeleteData(std::string bucket_key) {
|
||||
std::string query = StringFormat(
|
||||
"DELETE FROM `data_buckets` WHERE `key` = '%s'",
|
||||
EscapeString(bucket_key).c_str()
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts string to integer for use when setting expiration times
|
||||
* @param time_string
|
||||
* @return
|
||||
*/
|
||||
uint32 DataBucket::ParseStringTimeToInt(std::string time_string)
|
||||
{
|
||||
uint32 duration = 0;
|
||||
|
||||
std::transform(time_string.begin(), time_string.end(), time_string.begin(), ::tolower);
|
||||
|
||||
if (time_string.length() < 1)
|
||||
return 0;
|
||||
|
||||
std::string time_unit = time_string;
|
||||
time_unit.erase(remove_if(time_unit.begin(), time_unit.end(), [](char c) { return !isdigit(c); }), time_unit.end());
|
||||
|
||||
uint32 unit = static_cast<uint32>(atoi(time_unit.c_str()));
|
||||
|
||||
if (time_string.find('s') != std::string::npos)
|
||||
duration = unit;
|
||||
if (time_string.find('m') != std::string::npos)
|
||||
duration = unit * 60;
|
||||
if (time_string.find('h') != std::string::npos)
|
||||
duration = unit * 3600;
|
||||
if (time_string.find('d') != std::string::npos)
|
||||
duration = unit * 86400;
|
||||
if (time_string.find('y') != std::string::npos)
|
||||
duration = unit * 31556926;
|
||||
|
||||
return duration;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Created by Akkadius on 7/7/18.
|
||||
//
|
||||
|
||||
#ifndef EQEMU_DATABUCKET_H
|
||||
#define EQEMU_DATABUCKET_H
|
||||
|
||||
|
||||
#include <string>
|
||||
#include "../common/types.h"
|
||||
|
||||
class DataBucket {
|
||||
public:
|
||||
static void SetData(std::string bucket_key, std::string bucket_value, std::string expires_time = "");
|
||||
static bool DeleteData(std::string bucket_key);
|
||||
static std::string GetData(std::string bucket_key);
|
||||
static std::string GetDataExpires(std::string bucket_key);
|
||||
private:
|
||||
static uint64 DoesBucketExist(std::string bucket_key);
|
||||
static uint32 ParseStringTimeToInt(std::string time_string);
|
||||
};
|
||||
|
||||
|
||||
#endif //EQEMU_DATABUCKET_H
|
||||
+456
-360
File diff suppressed because it is too large
Load Diff
+69
-77
@@ -16,92 +16,84 @@ struct Door;
|
||||
class Doors : public Entity
|
||||
{
|
||||
public:
|
||||
Doors(const Door* door);
|
||||
Doors(const char *dmodel, const glm::vec4& position, uint8 dopentype = 58, uint16 dsize = 100);
|
||||
~Doors();
|
||||
bool IsDoor() const { return true; }
|
||||
void HandleClick(Client* sender, uint8 trigger);
|
||||
bool Process();
|
||||
uint8 GetDoorID() { return door_id; }
|
||||
uint32 GetDoorDBID() { return db_id; }
|
||||
uint32 GetGuildID() { return guild_id; }
|
||||
uint8 GetOpenType() { return opentype; }
|
||||
char* GetDoorName() { return door_name; }
|
||||
uint32 GetDoorParam() { return door_param; }
|
||||
int GetInvertState() { return invert_state; }
|
||||
const glm::vec4& GetPosition() const{ return m_Position; }
|
||||
int GetIncline() { return incline; }
|
||||
bool triggered;
|
||||
void SetOpenState(bool st) { is_open = st; }
|
||||
bool IsDoorOpen() { return is_open; }
|
||||
|
||||
uint8 GetTriggerDoorID() { return trigger_door; }
|
||||
uint8 GetTriggerType() { return trigger_type; }
|
||||
Doors(const char *model, const glm::vec4& position, uint8 open_type = 58, uint16 size = 100);
|
||||
Doors(const Door* door);
|
||||
|
||||
uint32 GetKeyItem() { return keyitem; }
|
||||
void SetKeyItem(uint32 in) { keyitem = in; }
|
||||
uint8 GetNoKeyring() { return nokeyring; }
|
||||
void SetNoKeyring(uint8 in) { nokeyring = in; }
|
||||
uint16 GetLockpick() { return lockpick; }
|
||||
void SetLockpick(uint16 in) { lockpick = in; }
|
||||
uint16 GetSize() { return size; }
|
||||
void SetGuildID(uint32 guild_id) { this->guild_id = guild_id; }
|
||||
|
||||
uint32 GetEntityID() { return entity_id; }
|
||||
void SetEntityID(uint32 entity) { entity_id = entity; }
|
||||
|
||||
void DumpDoor();
|
||||
bool GetDisableTimer() { return disable_timer; }
|
||||
bool IsDoor() const { return true; }
|
||||
bool IsDoorOpen() { return is_open; }
|
||||
bool Process();
|
||||
bool triggered;
|
||||
char *GetDoorName() { return door_name; }
|
||||
const glm::vec4 GetDestination() const { return m_Destination; }
|
||||
const glm::vec4 &GetPosition() const { return m_Position; }
|
||||
int GetIncline() { return incline; }
|
||||
int GetInvertState() { return invert_state; }
|
||||
uint8 GetDoorID() { return door_id; }
|
||||
uint8 GetNoKeyring() { return no_key_ring; }
|
||||
uint8 GetOpenType() { return open_type; }
|
||||
uint8 GetTriggerDoorID() { return trigger_door; }
|
||||
uint8 GetTriggerType() { return trigger_type; }
|
||||
uint8 IsLDoNDoor() { return is_ldon_door; }
|
||||
uint16 GetLockpick() { return lockpick; }
|
||||
uint16 GetSize() { return size; }
|
||||
uint32 GetClientVersionMask() { return client_version_mask; }
|
||||
uint32 GetDoorDBID() { return database_id; }
|
||||
uint32 GetDoorParam() { return door_param; }
|
||||
uint32 GetEntityID() { return entity_id; }
|
||||
uint32 GetGuildID() { return guild_id; }
|
||||
uint32 GetKeyItem() { return key_item_id; }
|
||||
void CreateDatabaseEntry();
|
||||
void ForceClose(Mob *sender, bool alt_mode = false);
|
||||
void ForceOpen(Mob *sender, bool alt_mode = false);
|
||||
void HandleClick(Client *sender, uint8 trigger);
|
||||
void Open(Mob *sender, bool alt_mode = false);
|
||||
void SetDisableTimer(bool flag);
|
||||
void SetDoorName(const char *name);
|
||||
void SetEntityID(uint32 entity) { entity_id = entity; }
|
||||
void SetIncline(int in);
|
||||
void SetKeyItem(uint32 in) { key_item_id = in; }
|
||||
void SetLocation(float x, float y, float z);
|
||||
void SetLockpick(uint16 in) { lockpick = in; }
|
||||
void SetNoKeyring(uint8 in) { no_key_ring = in; }
|
||||
void SetOpenState(bool st) { is_open = st; }
|
||||
void SetOpenType(uint8 in);
|
||||
void SetPosition(const glm::vec4 &position);
|
||||
void SetSize(uint16 size);
|
||||
void ToggleState(Mob *sender);
|
||||
|
||||
uint8 IsLDoNDoor() { return is_ldon_door; }
|
||||
uint32 GetClientVersionMask() { return client_version_mask; }
|
||||
|
||||
void NPCOpen(NPC* sender, bool alt_mode=false);
|
||||
void ForceOpen(Mob *sender, bool alt_mode=false);
|
||||
void ForceClose(Mob *sender, bool alt_mode=false);
|
||||
void ToggleState(Mob *sender);
|
||||
|
||||
void SetPosition(const glm::vec4& position);
|
||||
void SetLocation(float x, float y, float z);
|
||||
void SetIncline(int in);
|
||||
void SetDoorName(const char* name);
|
||||
void SetOpenType(uint8 in);
|
||||
void SetSize(uint16 size);
|
||||
|
||||
void SetDisableTimer(bool flag);
|
||||
bool GetDisableTimer() { return disable_timer; }
|
||||
|
||||
void CreateDatabaseEntry();
|
||||
float GetX();
|
||||
float GetY();
|
||||
float GetZ();
|
||||
|
||||
private:
|
||||
|
||||
uint32 db_id;
|
||||
uint8 door_id;
|
||||
char zone_name[32];
|
||||
char door_name[32];
|
||||
uint32 database_id;
|
||||
uint8 door_id;
|
||||
char zone_name[32];
|
||||
char door_name[32];
|
||||
glm::vec4 m_Position;
|
||||
int incline;
|
||||
uint8 opentype;
|
||||
uint32 guild_id;
|
||||
uint16 lockpick;
|
||||
uint32 keyitem;
|
||||
uint8 nokeyring;
|
||||
uint8 trigger_door;
|
||||
uint8 trigger_type;
|
||||
uint32 door_param;
|
||||
uint16 size;
|
||||
int invert_state;
|
||||
uint32 entity_id;
|
||||
bool disable_timer;
|
||||
bool is_open;
|
||||
Timer close_timer;
|
||||
//Timer trigger_timer;
|
||||
|
||||
char dest_zone[16];
|
||||
int dest_instance_id;
|
||||
int incline;
|
||||
uint8 open_type;
|
||||
uint32 guild_id;
|
||||
uint16 lockpick;
|
||||
uint32 key_item_id;
|
||||
uint8 no_key_ring;
|
||||
uint8 trigger_door;
|
||||
uint8 trigger_type;
|
||||
uint32 door_param;
|
||||
uint16 size;
|
||||
int invert_state;
|
||||
uint32 entity_id;
|
||||
bool disable_timer;
|
||||
bool is_open;
|
||||
Timer close_timer;
|
||||
char destination_zone_name[16];
|
||||
int destination_instance_id;
|
||||
glm::vec4 m_Destination;
|
||||
|
||||
uint8 is_ldon_door;
|
||||
uint32 client_version_mask;
|
||||
uint8 is_ldon_door;
|
||||
uint32 client_version_mask;
|
||||
};
|
||||
#endif
|
||||
|
||||
+3
-3
@@ -643,9 +643,9 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
|
||||
}
|
||||
|
||||
if (reduced_recast > 0)
|
||||
CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast);
|
||||
CastSpell(spell_id, target, EQEmu::spells::CastingSlot::Discipline, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast);
|
||||
else{
|
||||
CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline);
|
||||
CastSpell(spell_id, target, EQEmu::spells::CastingSlot::Discipline);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -653,7 +653,7 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
|
||||
}
|
||||
else
|
||||
{
|
||||
CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline);
|
||||
CastSpell(spell_id, target, EQEmu::spells::CastingSlot::Discipline);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
+3
-3
@@ -1046,7 +1046,7 @@ void PerlembParser::ExportMobVariables(bool isPlayerQuest, bool isGlobalPlayerQu
|
||||
if (mob && npcmob && mob->IsClient()) {
|
||||
Client* client = mob->CastToClient();
|
||||
|
||||
fac = client->GetFactionLevel(client->CharacterID(), npcmob->GetID(), client->GetRace(),
|
||||
fac = client->GetFactionLevel(client->CharacterID(), npcmob->GetID(), client->GetFactionRace(),
|
||||
client->GetClass(), client->GetDeity(), npcmob->GetPrimaryFaction(), npcmob);
|
||||
}
|
||||
}
|
||||
@@ -1128,9 +1128,9 @@ void PerlembParser::ExportItemVariables(std::string &package_name, Mob *mob) {
|
||||
std::string hashname = package_name + std::string("::oncursor");
|
||||
perl->eval(std::string("%").append(hashname).append(" = ();").c_str());
|
||||
char *hi_decl = nullptr;
|
||||
int itemid = mob->CastToClient()->GetItemIDAt(30);
|
||||
int itemid = mob->CastToClient()->GetItemIDAt(EQEmu::invslot::slotCursor);
|
||||
if(!HASITEM_ISNULLITEM(itemid)) {
|
||||
MakeAnyLenString(&hi_decl, "push (@{$%s{%d}},%d);",hashname.c_str(), itemid, 30);
|
||||
MakeAnyLenString(&hi_decl, "push (@{$%s{%d}},%d);",hashname.c_str(), itemid, EQEmu::invslot::slotCursor);
|
||||
perl->eval(hi_decl);
|
||||
safe_delete_array(hi_decl);
|
||||
}
|
||||
|
||||
+1517
-1494
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -36,7 +36,7 @@ Encounter::Encounter(const char* enc_name)
|
||||
:Mob
|
||||
(
|
||||
nullptr, nullptr, 0, 0, 0, INVISIBLE_MAN, 0, BT_NoTarget, 0, 0, 0, 0, 0, glm::vec4(0,0,0,0), 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EQEmu::TintProfile(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EQEmu::TintProfile(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
)
|
||||
{
|
||||
encounter_name[0] = 0;
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ public:
|
||||
//abstract virtual function implementations required by base abstract class
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) { return true; }
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) { return; }
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
||||
ExtraAttackOptions *opts = nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+111
-192
@@ -39,6 +39,9 @@
|
||||
#include "raids.h"
|
||||
#include "string_ids.h"
|
||||
#include "worldserver.h"
|
||||
#include "water_map.h"
|
||||
#include "npc_scale_manager.h"
|
||||
#include "../common/say_link.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define snprintf _snprintf
|
||||
@@ -283,6 +286,17 @@ Bot *Entity::CastToBot()
|
||||
#endif
|
||||
return static_cast<Bot *>(this);
|
||||
}
|
||||
|
||||
const Bot *Entity::CastToBot() const
|
||||
{
|
||||
#ifdef _EQDEBUG
|
||||
if (!IsBot()) {
|
||||
std::cout << "CastToBot error" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return static_cast<const Bot *>(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
EntityList::EntityList()
|
||||
@@ -506,16 +520,16 @@ void EntityList::MobProcess()
|
||||
}
|
||||
|
||||
if(mob_dead) {
|
||||
if(mob->IsNPC()) {
|
||||
entity_list.RemoveNPC(id);
|
||||
}
|
||||
else if(mob->IsMerc()) {
|
||||
if(mob->IsMerc()) {
|
||||
entity_list.RemoveMerc(id);
|
||||
#ifdef BOTS
|
||||
}
|
||||
#ifdef BOTS
|
||||
else if(mob->IsBot()) {
|
||||
entity_list.RemoveBot(id);
|
||||
}
|
||||
#endif
|
||||
else if(mob->IsNPC()) {
|
||||
entity_list.RemoveNPC(id);
|
||||
}
|
||||
else {
|
||||
#ifdef _WINDOWS
|
||||
@@ -644,12 +658,9 @@ void EntityList::AddCorpse(Corpse *corpse, uint32 in_id)
|
||||
void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
|
||||
{
|
||||
npc->SetID(GetFreeID());
|
||||
npc->SetMerchantProbability((uint8) zone->random.Int(0, 99));
|
||||
|
||||
parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0);
|
||||
|
||||
npc->FixZ(1);
|
||||
|
||||
uint16 emoteid = npc->GetEmoteID();
|
||||
if (emoteid != 0)
|
||||
npc->DoNPCEmote(ONSPAWN, emoteid);
|
||||
@@ -687,6 +698,15 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether NPC was spawned in or out of water
|
||||
*/
|
||||
if (zone->HasMap() && zone->HasWaterMap()) {
|
||||
npc->SetSpawnedInWater(false);
|
||||
if (zone->watermap->InLiquid(npc->GetPosition())) {
|
||||
npc->SetSpawnedInWater(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EntityList::AddMerc(Merc *merc, bool SendSpawnPacket, bool dontqueue)
|
||||
@@ -1263,32 +1283,35 @@ void EntityList::SendZoneSpawns(Client *client)
|
||||
|
||||
void EntityList::SendZoneSpawnsBulk(Client *client)
|
||||
{
|
||||
NewSpawn_Struct ns;
|
||||
Mob *spawn;
|
||||
uint32 maxspawns = 100;
|
||||
NewSpawn_Struct ns{};
|
||||
Mob *spawn;
|
||||
EQApplicationPacket *app;
|
||||
|
||||
if (maxspawns > mob_list.size())
|
||||
maxspawns = mob_list.size();
|
||||
auto bzsp = new BulkZoneSpawnPacket(client, maxspawns);
|
||||
uint32 max_spawns = 100;
|
||||
|
||||
if (max_spawns > mob_list.size()) {
|
||||
max_spawns = static_cast<uint32>(mob_list.size());
|
||||
}
|
||||
|
||||
auto bulk_zone_spawn_packet = new BulkZoneSpawnPacket(client, max_spawns);
|
||||
const glm::vec4 &client_position = client->GetPosition();
|
||||
const float distance_max = (600.0 * 600.0);
|
||||
|
||||
bool delaypkt = false;
|
||||
const glm::vec4& cpos = client->GetPosition();
|
||||
const float dmax = 600.0 * 600.0;
|
||||
for (auto it = mob_list.begin(); it != mob_list.end(); ++it) {
|
||||
spawn = it->second;
|
||||
if (spawn && spawn->GetID() > 0 && spawn->Spawned()) {
|
||||
if (!spawn->ShouldISpawnFor(client))
|
||||
if (!spawn->ShouldISpawnFor(client)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#if 1
|
||||
const glm::vec4& spos = spawn->GetPosition();
|
||||
const glm::vec4 &spawn_position = spawn->GetPosition();
|
||||
|
||||
delaypkt = false;
|
||||
if (DistanceSquared(cpos, spos) > dmax || (spawn->IsClient() && (spawn->GetRace() == MINOR_ILL_OBJ || spawn->GetRace() == TREE)))
|
||||
delaypkt = true;
|
||||
bool is_delayed_packet = (
|
||||
DistanceSquared(client_position, spawn_position) > distance_max ||
|
||||
(spawn->IsClient() && (spawn->GetRace() == MINOR_ILL_OBJ || spawn->GetRace() == TREE))
|
||||
);
|
||||
|
||||
if (delaypkt) {
|
||||
if (is_delayed_packet) {
|
||||
app = new EQApplicationPacket;
|
||||
spawn->CreateSpawnPacket(app);
|
||||
client->QueuePacket(app, true, Client::CLIENT_CONNECTED);
|
||||
@@ -1297,35 +1320,38 @@ void EntityList::SendZoneSpawnsBulk(Client *client)
|
||||
else {
|
||||
memset(&ns, 0, sizeof(NewSpawn_Struct));
|
||||
spawn->FillSpawnStruct(&ns, client);
|
||||
bzsp->AddSpawn(&ns);
|
||||
bulk_zone_spawn_packet->AddSpawn(&ns);
|
||||
}
|
||||
|
||||
spawn->SendArmorAppearance(client);
|
||||
#else
|
||||
/* original code kept for spawn packet research */
|
||||
int32 race = spawn->GetRace();
|
||||
|
||||
// Illusion races on PCs don't work as a mass spawn
|
||||
// But they will work as an add_spawn AFTER CLIENT_CONNECTED.
|
||||
if (spawn->IsClient() && (race == MINOR_ILL_OBJ || race == TREE)) {
|
||||
app = new EQApplicationPacket;
|
||||
spawn->CreateSpawnPacket(app);
|
||||
client->QueuePacket(app, true, Client::CLIENT_CONNECTED);
|
||||
safe_delete(app);
|
||||
}
|
||||
else {
|
||||
memset(&ns, 0, sizeof(NewSpawn_Struct));
|
||||
spawn->FillSpawnStruct(&ns, client);
|
||||
bzsp->AddSpawn(&ns);
|
||||
}
|
||||
|
||||
// Despite being sent in the OP_ZoneSpawns packet, the client
|
||||
// does not display worn armor correctly so display it.
|
||||
spawn->SendArmorAppearance(client);
|
||||
#endif
|
||||
/**
|
||||
* Original code kept for spawn packet research
|
||||
*
|
||||
* int32 race = spawn->GetRace();
|
||||
*
|
||||
* Illusion races on PCs don't work as a mass spawn
|
||||
* But they will work as an add_spawn AFTER CLIENT_CONNECTED.
|
||||
* if (spawn->IsClient() && (race == MINOR_ILL_OBJ || race == TREE)) {
|
||||
* app = new EQApplicationPacket;
|
||||
* spawn->CreateSpawnPacket(app);
|
||||
* client->QueuePacket(app, true, Client::CLIENT_CONNECTED);
|
||||
* safe_delete(app);
|
||||
* }
|
||||
* else {
|
||||
* memset(&ns, 0, sizeof(NewSpawn_Struct));
|
||||
* spawn->FillSpawnStruct(&ns, client);
|
||||
* bzsp->AddSpawn(&ns);
|
||||
* }
|
||||
*
|
||||
* Despite being sent in the OP_ZoneSpawns packet, the client
|
||||
* does not display worn armor correctly so display it.
|
||||
* spawn->SendArmorAppearance(client);
|
||||
*/
|
||||
}
|
||||
}
|
||||
safe_delete(bzsp);
|
||||
|
||||
safe_delete(bulk_zone_spawn_packet);
|
||||
}
|
||||
|
||||
//this is a hack to handle a broken spawn struct
|
||||
@@ -1547,7 +1573,7 @@ void EntityList::QueueClientsByTarget(Mob *sender, const EQApplicationPacket *ap
|
||||
}
|
||||
}
|
||||
|
||||
void EntityList::QueueClientsByXTarget(Mob *sender, const EQApplicationPacket *app, bool iSendToSender)
|
||||
void EntityList::QueueClientsByXTarget(Mob *sender, const EQApplicationPacket *app, bool iSendToSender, EQEmu::versions::ClientVersionBitmask client_version_bits)
|
||||
{
|
||||
auto it = client_list.begin();
|
||||
while (it != client_list.end()) {
|
||||
@@ -1557,6 +1583,9 @@ void EntityList::QueueClientsByXTarget(Mob *sender, const EQApplicationPacket *a
|
||||
if (!c || ((c == sender) && !iSendToSender))
|
||||
continue;
|
||||
|
||||
if ((c->ClientVersionBit() & client_version_bits) == 0)
|
||||
continue;
|
||||
|
||||
if (!c->IsXTarget(sender))
|
||||
continue;
|
||||
|
||||
@@ -2638,56 +2667,6 @@ void EntityList::RemoveDebuffs(Mob *caster)
|
||||
}
|
||||
}
|
||||
|
||||
// Currently, a new packet is sent per entity.
|
||||
// @todo: Come back and use FLAG_COMBINED to pack
|
||||
// all updates into one packet.
|
||||
void EntityList::SendPositionUpdates(Client *client, uint32 cLastUpdate, float update_range, Entity *always_send, bool iSendEvenIfNotChanged)
|
||||
{
|
||||
update_range = (update_range * update_range);
|
||||
|
||||
EQApplicationPacket *outapp = 0;
|
||||
PlayerPositionUpdateServer_Struct *ppu = 0;
|
||||
Mob *mob = 0;
|
||||
|
||||
auto it = mob_list.begin();
|
||||
while (it != mob_list.end()) {
|
||||
|
||||
mob = it->second;
|
||||
|
||||
if (
|
||||
mob && !mob->IsCorpse()
|
||||
&& (it->second != client)
|
||||
&& (mob->IsClient() || iSendEvenIfNotChanged || (mob->LastChange() >= cLastUpdate))
|
||||
&& (it->second->ShouldISpawnFor(client))
|
||||
) {
|
||||
if (
|
||||
update_range == 0
|
||||
|| (it->second == always_send)
|
||||
|| mob->IsClient()
|
||||
|| (DistanceSquared(mob->GetPosition(), client->GetPosition()) <= update_range)
|
||||
) {
|
||||
if (mob && mob->IsClient() && mob->GetID() > 0) {
|
||||
client->QueuePacket(outapp, false, Client::CLIENT_CONNECTED);
|
||||
|
||||
if (outapp == 0) {
|
||||
outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
ppu = (PlayerPositionUpdateServer_Struct*)outapp->pBuffer;
|
||||
}
|
||||
|
||||
mob->MakeSpawnUpdate(ppu);
|
||||
|
||||
safe_delete(outapp);
|
||||
outapp = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
char *EntityList::MakeNameUnique(char *name)
|
||||
{
|
||||
bool used[300];
|
||||
@@ -2741,58 +2720,6 @@ char *EntityList::RemoveNumbers(char *name)
|
||||
return name;
|
||||
}
|
||||
|
||||
void EntityList::ListNPCs(Client* client, const char *arg1, const char *arg2, uint8 searchtype)
|
||||
{
|
||||
if (arg1 == 0)
|
||||
searchtype = 0;
|
||||
else if (arg2 == 0 && searchtype >= 2)
|
||||
searchtype = 0;
|
||||
uint32 x = 0;
|
||||
uint32 z = 0;
|
||||
char sName[36];
|
||||
|
||||
auto it = npc_list.begin();
|
||||
client->Message(0, "NPCs in the zone:");
|
||||
if (searchtype == 0) {
|
||||
while (it != npc_list.end()) {
|
||||
NPC *n = it->second;
|
||||
|
||||
client->Message(0, " %5d: %s (%.0f, %0.f, %.0f)", n->GetID(), n->GetName(), n->GetX(), n->GetY(), n->GetZ());
|
||||
x++;
|
||||
z++;
|
||||
++it;
|
||||
}
|
||||
} else if (searchtype == 1) {
|
||||
client->Message(0, "Searching by name method. (%s)",arg1);
|
||||
auto tmp = new char[strlen(arg1) + 1];
|
||||
strcpy(tmp, arg1);
|
||||
strupr(tmp);
|
||||
while (it != npc_list.end()) {
|
||||
z++;
|
||||
strcpy(sName, it->second->GetName());
|
||||
strupr(sName);
|
||||
if (strstr(sName, tmp)) {
|
||||
NPC *n = it->second;
|
||||
client->Message(0, " %5d: %s (%.0f, %.0f, %.0f)", n->GetID(), n->GetName(), n->GetX(), n->GetY(), n->GetZ());
|
||||
x++;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
safe_delete_array(tmp);
|
||||
} else if (searchtype == 2) {
|
||||
client->Message(0, "Searching by number method. (%s %s)",arg1,arg2);
|
||||
while (it != npc_list.end()) {
|
||||
z++;
|
||||
if ((it->second->GetID() >= atoi(arg1)) && (it->second->GetID() <= atoi(arg2)) && (atoi(arg1) <= atoi(arg2))) {
|
||||
client->Message(0, " %5d: %s", it->second->GetID(), it->second->GetName());
|
||||
x++;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
client->Message(0, "%d npcs listed. There is a total of %d npcs in this zone.", x, z);
|
||||
}
|
||||
|
||||
void EntityList::ListNPCCorpses(Client *client)
|
||||
{
|
||||
uint32 x = 0;
|
||||
@@ -2825,26 +2752,6 @@ void EntityList::ListPlayerCorpses(Client *client)
|
||||
client->Message(0, "%d player corpses listed.", x);
|
||||
}
|
||||
|
||||
void EntityList::FindPathsToAllNPCs()
|
||||
{
|
||||
if (!zone->pathing)
|
||||
return;
|
||||
|
||||
auto it = npc_list.begin();
|
||||
while (it != npc_list.end()) {
|
||||
glm::vec3 Node0 = zone->pathing->GetPathNodeCoordinates(0, false);
|
||||
glm::vec3 Dest(it->second->GetX(), it->second->GetY(), it->second->GetZ());
|
||||
std::deque<int> Route = zone->pathing->FindRoute(Node0, Dest);
|
||||
if (Route.empty())
|
||||
printf("Unable to find a route to %s\n", it->second->GetName());
|
||||
else
|
||||
printf("Found a route to %s\n", it->second->GetName());
|
||||
++it;
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
// returns the number of corpses deleted. A negative number indicates an error code.
|
||||
int32 EntityList::DeleteNPCCorpses()
|
||||
{
|
||||
@@ -3271,7 +3178,7 @@ void EntityList::AddHealAggro(Mob *target, Mob *caster, uint16 hate)
|
||||
}
|
||||
}
|
||||
|
||||
void EntityList::OpenDoorsNear(NPC *who)
|
||||
void EntityList::OpenDoorsNear(Mob *who)
|
||||
{
|
||||
|
||||
for (auto it = door_list.begin();it != door_list.end(); ++it) {
|
||||
@@ -3284,7 +3191,7 @@ void EntityList::OpenDoorsNear(NPC *who)
|
||||
float curdist = diff.x * diff.x + diff.y * diff.y;
|
||||
|
||||
if (diff.z * diff.z < 10 && curdist <= 100)
|
||||
cdoor->NPCOpen(who);
|
||||
cdoor->Open(who);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3443,52 +3350,54 @@ void EntityList::ProcessMove(Client *c, const glm::vec3& location)
|
||||
}
|
||||
}
|
||||
|
||||
void EntityList::ProcessMove(NPC *n, float x, float y, float z)
|
||||
{
|
||||
void EntityList::ProcessMove(NPC *n, float x, float y, float z) {
|
||||
float last_x = n->GetX();
|
||||
float last_y = n->GetY();
|
||||
float last_z = n->GetZ();
|
||||
|
||||
std::list<quest_proximity_event> events;
|
||||
|
||||
for (auto iter = area_list.begin(); iter != area_list.end(); ++iter) {
|
||||
Area& a = (*iter);
|
||||
|
||||
Area &a = (*iter);
|
||||
bool old_in = true;
|
||||
bool new_in = true;
|
||||
if (last_x < a.min_x || last_x > a.max_x ||
|
||||
last_y < a.min_y || last_y > a.max_y ||
|
||||
last_z < a.min_z || last_z > a.max_z) {
|
||||
last_y < a.min_y || last_y > a.max_y ||
|
||||
last_z < a.min_z || last_z > a.max_z) {
|
||||
old_in = false;
|
||||
}
|
||||
|
||||
if (x < a.min_x || x > a.max_x ||
|
||||
y < a.min_y || y > a.max_y ||
|
||||
z < a.min_z || z > a.max_z) {
|
||||
y < a.min_y || y > a.max_y ||
|
||||
z < a.min_z || z > a.max_z) {
|
||||
new_in = false;
|
||||
}
|
||||
|
||||
if (old_in && !new_in) {
|
||||
//were in but are no longer.
|
||||
quest_proximity_event evt;
|
||||
evt.event_id = EVENT_LEAVE_AREA;
|
||||
evt.client = nullptr;
|
||||
evt.npc = n;
|
||||
evt.area_id = a.id;
|
||||
evt.event_id = EVENT_LEAVE_AREA;
|
||||
evt.client = nullptr;
|
||||
evt.npc = n;
|
||||
evt.area_id = a.id;
|
||||
evt.area_type = a.type;
|
||||
events.push_back(evt);
|
||||
} else if (!old_in && new_in) {
|
||||
}
|
||||
else if (!old_in && new_in) {
|
||||
//were not in but now are
|
||||
quest_proximity_event evt;
|
||||
evt.event_id = EVENT_ENTER_AREA;
|
||||
evt.client = nullptr;
|
||||
evt.npc = n;
|
||||
evt.area_id = a.id;
|
||||
evt.event_id = EVENT_ENTER_AREA;
|
||||
evt.client = nullptr;
|
||||
evt.npc = n;
|
||||
evt.area_id = a.id;
|
||||
evt.area_type = a.type;
|
||||
events.push_back(evt);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto iter = events.begin(); iter != events.end(); ++iter) {
|
||||
quest_proximity_event& evt = (*iter);
|
||||
quest_proximity_event &evt = (*iter);
|
||||
std::vector<EQEmu::Any> args;
|
||||
args.push_back(&evt.area_id);
|
||||
args.push_back(&evt.area_type);
|
||||
@@ -4073,8 +3982,9 @@ Mob *EntityList::GetTargetForMez(Mob *caster)
|
||||
|
||||
void EntityList::SendZoneAppearance(Client *c)
|
||||
{
|
||||
if (!c)
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = mob_list.begin();
|
||||
while (it != mob_list.end()) {
|
||||
@@ -4089,7 +3999,7 @@ void EntityList::SendZoneAppearance(Client *c)
|
||||
cur->SendAppearancePacket(AT_Anim, cur->GetAppearanceValue(cur->GetAppearance()), false, true, c);
|
||||
}
|
||||
if (cur->GetSize() != cur->GetBaseSize()) {
|
||||
cur->SendAppearancePacket(AT_Size, (uint32)cur->GetSize(), false, true, c);
|
||||
cur->SendAppearancePacket(AT_Size, (uint32) cur->GetSize(), false, true, c);
|
||||
}
|
||||
}
|
||||
++it;
|
||||
@@ -4279,7 +4189,7 @@ void EntityList::ZoneWho(Client *c, Who_All_Struct *Who)
|
||||
WAPP2->RankMSGID = 12315;
|
||||
else if (ClientEntry->IsBuyer())
|
||||
WAPP2->RankMSGID = 6056;
|
||||
else if (ClientEntry->Admin() >= 10)
|
||||
else if (ClientEntry->Admin() >= 10 && ClientEntry->GetGM())
|
||||
WAPP2->RankMSGID = 12312;
|
||||
else
|
||||
WAPP2->RankMSGID = 0xFFFFFFFF;
|
||||
@@ -4871,3 +4781,12 @@ void EntityList::SendAlternateAdvancementStats() {
|
||||
c.second->SendAlternateAdvancementPoints();
|
||||
}
|
||||
}
|
||||
|
||||
void EntityList::ReloadMerchants() {
|
||||
for (auto it = npc_list.begin();it != npc_list.end(); ++it) {
|
||||
NPC *cur = it->second;
|
||||
if (cur->MerchantType != 0) {
|
||||
zone->LoadNewMerchantData(cur->MerchantType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-7
@@ -116,6 +116,7 @@ public:
|
||||
|
||||
#ifdef BOTS
|
||||
Bot* CastToBot();
|
||||
const Bot* CastToBot() const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
@@ -244,6 +245,7 @@ public:
|
||||
void AddArea(int id, int type, float min_x, float max_x, float min_y, float max_y, float min_z, float max_z);
|
||||
void RemoveArea(int id);
|
||||
void ClearAreas();
|
||||
void ReloadMerchants();
|
||||
void ProcessProximitySay(const char *Message, Client *c, uint8 language = 0);
|
||||
void SendAATimer(uint32 charid,UseAA_Struct* uaa);
|
||||
Doors *FindDoor(uint8 door_id);
|
||||
@@ -352,11 +354,11 @@ public:
|
||||
void QueueClientsByTarget(Mob* sender, const EQApplicationPacket* app, bool iSendToSender = true, Mob* SkipThisMob = 0, bool ackreq = true,
|
||||
bool HoTT = true, uint32 ClientVersionBits = 0xFFFFFFFF, bool inspect_buffs = false);
|
||||
|
||||
void QueueClientsByXTarget(Mob* sender, const EQApplicationPacket* app, bool iSendToSender = true);
|
||||
void QueueClientsByXTarget(Mob* sender, const EQApplicationPacket* app, bool iSendToSender = true, EQEmu::versions::ClientVersionBitmask client_version_bits = EQEmu::versions::ClientVersionBitmask::maskAllClients);
|
||||
void QueueToGroupsForNPCHealthAA(Mob* sender, const EQApplicationPacket* app);
|
||||
void QueueManaged(Mob* sender, const EQApplicationPacket* app, bool ignore_sender=false, bool ackreq = true);
|
||||
|
||||
void AEAttack(Mob *attacker, float dist, int Hand = EQEmu::inventory::slotPrimary, int count = 0, bool IsFromSpell = false);
|
||||
void AEAttack(Mob *attacker, float dist, int Hand = EQEmu::invslot::slotPrimary, int count = 0, bool IsFromSpell = false);
|
||||
void AETaunt(Client *caster, float range=0, int32 bonus_hate=0);
|
||||
void AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true, int16 resist_adjust = 0, int *max_targets = nullptr);
|
||||
void MassGroupBuff(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true);
|
||||
@@ -369,9 +371,8 @@ public:
|
||||
|
||||
void AddHealAggro(Mob* target, Mob* caster, uint16 hate);
|
||||
Mob* FindDefenseNPC(uint32 npcid);
|
||||
void OpenDoorsNear(NPC* opener);
|
||||
void OpenDoorsNear(Mob* opener);
|
||||
void UpdateWho(bool iSendFullUpdate = false);
|
||||
void SendPositionUpdates(Client* client, uint32 cLastUpdate = 0, float update_range = 0, Entity* always_send = 0, bool iSendEvenIfNotChanged = false);
|
||||
char* MakeNameUnique(char* name);
|
||||
static char* RemoveNumbers(char* name);
|
||||
void SignalMobsByNPCID(uint32 npc_type, int signal_id);
|
||||
@@ -381,10 +382,8 @@ public:
|
||||
void SendPetitionToAdmins();
|
||||
void AddLootToNPCS(uint32 item_id, uint32 count);
|
||||
|
||||
void ListNPCs(Client* client, const char* arg1 = 0, const char* arg2 = 0, uint8 searchtype = 0);
|
||||
void ListNPCCorpses(Client* client);
|
||||
void ListPlayerCorpses(Client* client);
|
||||
void FindPathsToAllNPCs();
|
||||
int32 DeleteNPCCorpses();
|
||||
int32 DeletePlayerCorpses();
|
||||
void CorpseFix(Client* c);
|
||||
@@ -416,7 +415,7 @@ public:
|
||||
|
||||
void CheckClientAggro(Client *around);
|
||||
Mob* AICheckNPCtoNPCAggro(Mob* sender, float iAggroRange, float iAssistRange);
|
||||
int GetHatedCount(Mob *attacker, Mob *exclude);
|
||||
int GetHatedCount(Mob *attacker, Mob *exclude, bool inc_gray_con);
|
||||
void AIYellForHelp(Mob* sender, Mob* attacker);
|
||||
bool AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float iRange, uint32 iSpellTypes);
|
||||
bool Merc_AICheckCloseBeneficialSpells(Merc* caster, uint8 iChance, float iRange, uint32 iSpellTypes);
|
||||
|
||||
+32
-9
@@ -512,6 +512,13 @@ void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
||||
aaexp = had_aaexp; //watch for wrap
|
||||
}
|
||||
|
||||
// AA Sanity Checking for players who set aa exp and deleveled below allowed aa level.
|
||||
if (GetLevel() <= 50 && m_epp.perAA > 0) {
|
||||
Message(15, "You are below the level allowed to gain AA Experience. AA Experience set to 0%");
|
||||
aaexp = 0;
|
||||
m_epp.perAA = 0;
|
||||
}
|
||||
|
||||
// Now update our character's normal and AA xp
|
||||
SetEXP(exp, aaexp, resexp);
|
||||
}
|
||||
@@ -677,14 +684,12 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
}
|
||||
}
|
||||
|
||||
if(RuleB(Character, PerCharacterQglobalMaxLevel)){
|
||||
uint32 MaxLevel = GetCharMaxLevelFromQGlobal();
|
||||
if(MaxLevel){
|
||||
if(GetLevel() >= MaxLevel){
|
||||
uint32 expneeded = GetEXPForLevel(MaxLevel);
|
||||
if(set_exp > expneeded) {
|
||||
set_exp = expneeded;
|
||||
}
|
||||
if (GetClientMaxLevel() > 0) {
|
||||
int client_max_level = GetClientMaxLevel();
|
||||
if (GetLevel() >= client_max_level) {
|
||||
uint32 expneeded = GetEXPForLevel(client_max_level);
|
||||
if(set_exp > expneeded) {
|
||||
set_exp = expneeded;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -831,6 +836,8 @@ void Client::SetLevel(uint8 set_level, bool command)
|
||||
SetHP(CalcMaxHP()); // Why not, lets give them a free heal
|
||||
}
|
||||
|
||||
if (RuleI(World, PVPMinLevel) > 0 && level >= RuleI(World, PVPMinLevel) && m_pp.pvp == 0) SetPVP(true);
|
||||
|
||||
DoTributeUpdate();
|
||||
SendHPUpdate();
|
||||
SetMana(CalcMaxMana());
|
||||
@@ -1121,7 +1128,23 @@ uint32 Client::GetCharMaxLevelFromQGlobal() {
|
||||
++gcount;
|
||||
}
|
||||
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 Client::GetCharMaxLevelFromBucket() {
|
||||
uint32 char_id = this->CharacterID();
|
||||
std::string query = StringFormat("SELECT value FROM data_buckets WHERE `key` = '%i-CharMaxLevel'", char_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
Log(Logs::General, Logs::Error, "Data bucket for CharMaxLevel for char ID %i failed.", char_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (results.RowCount() > 0) {
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 Client::GetRequiredAAExperience() {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#if defined(_MSC_VER)
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
#include <cmath>
|
||||
#include "fastmath.h"
|
||||
|
||||
FastMath g_Math;
|
||||
|
||||
// This should match EQ's sin/cos LUTs
|
||||
// Some values didn't match on linux, but they were the "same" float :P
|
||||
FastMath::FastMath()
|
||||
{
|
||||
int ci = 0;
|
||||
int si = 128;
|
||||
float res;
|
||||
do {
|
||||
res = std::cos(static_cast<float>(ci) * M_PI * 2 / 512);
|
||||
lut_cos[ci] = res;
|
||||
if (si == 512)
|
||||
si = 0;
|
||||
lut_sin[si] = res;
|
||||
++ci;
|
||||
++si;
|
||||
} while (ci < 512);
|
||||
|
||||
lut_sin[0] = 0.0f;
|
||||
lut_sin[128] = 1.0f;
|
||||
lut_sin[256] = 0.0f;
|
||||
lut_sin[384] = -1.0f;
|
||||
|
||||
lut_cos[0] = 1.0f;
|
||||
lut_cos[128] = 0.0f;
|
||||
lut_cos[384] = 0.0f;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef FASTMATH_H
|
||||
#define FASTMATH_H
|
||||
|
||||
class FastMath
|
||||
{
|
||||
private:
|
||||
float lut_cos[512];
|
||||
float lut_sin[512];
|
||||
|
||||
public:
|
||||
FastMath();
|
||||
|
||||
inline float FastSin(float a) { return lut_sin[static_cast<int>(a) & 0x1ff]; }
|
||||
inline float FastCos(float a) { return lut_cos[static_cast<int>(a) & 0x1ff]; }
|
||||
|
||||
};
|
||||
|
||||
#endif /* !FASTMATH_H */
|
||||
+74
-81
@@ -19,7 +19,6 @@
|
||||
#include "../common/rulesys.h"
|
||||
|
||||
#include "map.h"
|
||||
#include "pathing.h"
|
||||
#include "zone.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
@@ -32,87 +31,117 @@ extern Zone* zone;
|
||||
|
||||
//this is called whenever we are damaged to process possible fleeing
|
||||
void Mob::CheckFlee() {
|
||||
//if were allready fleeing, dont need to check more...
|
||||
if(flee_mode && currently_fleeing)
|
||||
|
||||
// if mob is dead why would you run?
|
||||
if(GetHP() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if were already fleeing, don't need to check more...
|
||||
if(flee_mode && currently_fleeing) {
|
||||
return;
|
||||
}
|
||||
|
||||
//dont bother if we are immune to fleeing
|
||||
if(GetSpecialAbility(IMMUNE_FLEEING) || spellbonuses.ImmuneToFlee)
|
||||
if(GetSpecialAbility(IMMUNE_FLEEING) || spellbonuses.ImmuneToFlee) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!flee_timer.Check())
|
||||
return; //only do all this stuff every little while, since
|
||||
//its not essential that we start running RIGHT away
|
||||
|
||||
//see if were possibly hurt enough
|
||||
float ratio = GetHPRatio();
|
||||
float fleeratio = GetSpecialAbility(FLEE_PERCENT);
|
||||
fleeratio = fleeratio > 0 ? fleeratio : RuleI(Combat, FleeHPRatio);
|
||||
|
||||
if(ratio >= fleeratio)
|
||||
// Check if Flee Timer is cleared
|
||||
if(!flee_timer.Check()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//we might be hurt enough, check con now..
|
||||
int hpratio = GetIntHPRatio();
|
||||
int fleeratio = GetSpecialAbility(FLEE_PERCENT); // if a special flee_percent exists
|
||||
Mob *hate_top = GetHateTop();
|
||||
|
||||
// Sanity Check for race conditions
|
||||
if(hate_top == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If no special flee_percent check for Gray or Other con rates
|
||||
if(GetLevelCon(hate_top->GetLevel(), GetLevel()) == CON_GRAY && fleeratio == 0 && RuleB(Combat, FleeGray) && GetLevel() <= RuleI(Combat, FleeGrayMaxLevel)) {
|
||||
fleeratio = RuleI(Combat, FleeGrayHPRatio);
|
||||
} else if(fleeratio == 0) {
|
||||
fleeratio = RuleI(Combat, FleeHPRatio );
|
||||
}
|
||||
|
||||
// Mob does not have low enough health to flee
|
||||
if(hpratio >= fleeratio) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanity Check this should never happen...
|
||||
if(!hate_top) {
|
||||
//this should never happen...
|
||||
StartFleeing();
|
||||
return;
|
||||
}
|
||||
|
||||
float other_ratio = hate_top->GetHPRatio();
|
||||
int other_ratio = hate_top->GetIntHPRatio();
|
||||
// If the Client is nearing death the NPC will not flee and instead try to kill the client.
|
||||
if(other_ratio < 20) {
|
||||
//our hate top is almost dead too... stay and fight
|
||||
return;
|
||||
}
|
||||
|
||||
//base our flee ratio on our con. this is how the
|
||||
//attacker sees the mob, since this is all we can observe
|
||||
// Flee Chance checking based on con.
|
||||
uint32 con = GetLevelCon(hate_top->GetLevel(), GetLevel());
|
||||
float run_ratio;
|
||||
int flee_chance;
|
||||
switch(con) {
|
||||
//these values are not 100% researched
|
||||
case CON_GRAY:
|
||||
run_ratio = fleeratio;
|
||||
flee_chance = 100;
|
||||
break;
|
||||
case CON_GREEN:
|
||||
run_ratio = fleeratio * 9 / 10;
|
||||
flee_chance = 90;
|
||||
break;
|
||||
case CON_LIGHTBLUE:
|
||||
run_ratio = fleeratio * 9 / 10;
|
||||
flee_chance = 90;
|
||||
break;
|
||||
case CON_BLUE:
|
||||
run_ratio = fleeratio * 8 / 10;
|
||||
flee_chance = 80;
|
||||
break;
|
||||
default:
|
||||
run_ratio = fleeratio * 7 / 10;
|
||||
flee_chance = 70;
|
||||
break;
|
||||
}
|
||||
if(ratio < run_ratio)
|
||||
{
|
||||
if (RuleB(Combat, FleeIfNotAlone) ||
|
||||
GetSpecialAbility(ALWAYS_FLEE) ||
|
||||
(!RuleB(Combat, FleeIfNotAlone) && (entity_list.GetHatedCount(hate_top, this) == 0)))
|
||||
StartFleeing();
|
||||
|
||||
// If we got here we are allowed to roll on flee chance if there is not other hated NPC's in the area.
|
||||
|
||||
if(RuleB(Combat, FleeIfNotAlone) || GetSpecialAbility(ALWAYS_FLEE) || zone->random.Roll(flee_chance) && entity_list.GetHatedCount(hate_top, this, true) == 0) {
|
||||
currently_fleeing = true;
|
||||
StartFleeing();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Mob::ProcessFlee()
|
||||
{
|
||||
|
||||
//Stop fleeing if effect is applied after they start to run.
|
||||
//When ImmuneToFlee effect fades it will turn fear back on and check if it can still flee.
|
||||
if (flee_mode && (GetSpecialAbility(IMMUNE_FLEEING) || spellbonuses.ImmuneToFlee) &&
|
||||
!spellbonuses.IsFeared && !spellbonuses.IsBlind) {
|
||||
!spellbonuses.IsFeared && !spellbonuses.IsBlind) {
|
||||
currently_fleeing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
//see if we are still dying, if so, do nothing
|
||||
float fleeratio = GetSpecialAbility(FLEE_PERCENT);
|
||||
fleeratio = fleeratio > 0 ? fleeratio : RuleI(Combat, FleeHPRatio);
|
||||
if (GetHPRatio() < fleeratio)
|
||||
int hpratio = GetIntHPRatio();
|
||||
int fleeratio = GetSpecialAbility(FLEE_PERCENT); // if a special flee_percent exists
|
||||
Mob *hate_top = GetHateTop();
|
||||
|
||||
// If no special flee_percent check for Gray or Other con rates
|
||||
if(hate_top != nullptr && GetLevelCon(hate_top->GetLevel(), GetLevel()) == CON_GRAY && fleeratio == 0 && RuleB(Combat, FleeGray)) {
|
||||
fleeratio = RuleI(Combat, FleeGrayHPRatio);
|
||||
} else if(fleeratio == 0) {
|
||||
fleeratio = RuleI(Combat, FleeHPRatio );
|
||||
}
|
||||
|
||||
// Mob is still too low. Keep Running
|
||||
if(hpratio < fleeratio) {
|
||||
return;
|
||||
}
|
||||
|
||||
//we are not dying anymore... see what we do next
|
||||
|
||||
@@ -126,55 +155,19 @@ void Mob::ProcessFlee()
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::CalculateNewFearpoint()
|
||||
{
|
||||
if(RuleB(Pathing, Fear) && zone->pathing)
|
||||
{
|
||||
int Node = zone->pathing->GetRandomPathNode();
|
||||
|
||||
glm::vec3 Loc = zone->pathing->GetPathNodeCoordinates(Node);
|
||||
|
||||
++Loc.z;
|
||||
|
||||
glm::vec3 CurrentPosition(GetX(), GetY(), GetZ());
|
||||
|
||||
std::deque<int> Route = zone->pathing->FindRoute(CurrentPosition, Loc);
|
||||
|
||||
if(!Route.empty())
|
||||
{
|
||||
m_FearWalkTarget = glm::vec3(Loc.x, Loc.y, Loc.z);
|
||||
void Mob::CalculateNewFearpoint() {
|
||||
if (RuleB(Pathing, Fear) && zone->pathing) {
|
||||
auto Node = zone->pathing->GetRandomLocation(glm::vec3(GetX(), GetY(), GetZ()));
|
||||
if (Node.x != 0.0f || Node.y != 0.0f || Node.z != 0.0f) {
|
||||
m_FearWalkTarget = Node;
|
||||
currently_fleeing = true;
|
||||
|
||||
Log(Logs::Detail, Logs::None, "Feared to node %i (%8.3f, %8.3f, %8.3f)", Node, Loc.x, Loc.y, Loc.z);
|
||||
return;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::None, "No path found to selected node. Falling through to old fear point selection.");
|
||||
}
|
||||
|
||||
int loop = 0;
|
||||
float ranx, rany, ranz;
|
||||
|
||||
currently_fleeing = true;
|
||||
while (loop < 100) //Max 100 tries
|
||||
{
|
||||
int ran = 250 - (loop*2);
|
||||
loop++;
|
||||
ranx = GetX()+zone->random.Int(0, ran-1)-zone->random.Int(0, ran-1);
|
||||
rany = GetY()+zone->random.Int(0, ran-1)-zone->random.Int(0, ran-1);
|
||||
ranz = FindGroundZ(ranx,rany);
|
||||
if (ranz == BEST_Z_INVALID)
|
||||
continue;
|
||||
float fdist = ranz - GetZ();
|
||||
if (fdist >= -12 && fdist <= 12 && CheckCoordLosNoZLeaps(GetX(),GetY(),GetZ(),ranx,rany,ranz))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (loop <= 100)
|
||||
{
|
||||
m_FearWalkTarget = glm::vec3(ranx, rany, ranz);
|
||||
Log(Logs::Detail,
|
||||
Logs::Pathing,
|
||||
"No path found to selected node during CalculateNewFearpoint.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+27
-19
@@ -153,7 +153,7 @@ uint32 ZoneDatabase::GetZoneFishing(uint32 ZoneID, uint8 skill, uint32 &npc_id,
|
||||
//we need this function to immediately determine, after we receive OP_Fishing, if we can even try to fish, otherwise we have to wait a while to get the failure
|
||||
bool Client::CanFish() {
|
||||
//make sure we still have a fishing pole on:
|
||||
const EQEmu::ItemInstance* Pole = m_inv[EQEmu::inventory::slotPrimary];
|
||||
const EQEmu::ItemInstance* Pole = m_inv[EQEmu::invslot::slotPrimary];
|
||||
int32 bslot = m_inv.HasItemByUse(EQEmu::item::ItemTypeFishingBait, 1, invWhereWorn | invWherePersonal);
|
||||
const EQEmu::ItemInstance* Bait = nullptr;
|
||||
if (bslot != INVALID_INDEX)
|
||||
@@ -180,7 +180,7 @@ bool Client::CanFish() {
|
||||
const float LineLength = RuleR(Watermap, FishingLineLength);
|
||||
int HeadingDegrees;
|
||||
|
||||
HeadingDegrees = (int) ((GetHeading()*360)/256);
|
||||
HeadingDegrees = (int) ((GetHeading()*360)/512);
|
||||
HeadingDegrees = HeadingDegrees % 360;
|
||||
|
||||
rodPosition.x = m_Position.x + RodLength * sin(HeadingDegrees * M_PI/180.0f);
|
||||
@@ -258,7 +258,7 @@ void Client::GoFish()
|
||||
Bait = m_inv.GetItem(bslot);
|
||||
|
||||
//if the bait isnt equipped, need to add its skill bonus
|
||||
if (bslot >= EQEmu::legacy::GENERAL_BEGIN && Bait != nullptr && Bait->GetItem()->SkillModType == EQEmu::skills::SkillFishing) {
|
||||
if (bslot >= EQEmu::invslot::GENERAL_BEGIN && Bait != nullptr && Bait->GetItem()->SkillModType == EQEmu::skills::SkillFishing) {
|
||||
fishing_skill += Bait->GetItem()->SkillModValue;
|
||||
}
|
||||
|
||||
@@ -277,20 +277,28 @@ void Client::GoFish()
|
||||
food_id = database.GetZoneFishing(m_pp.zone_id, fishing_skill, npc_id, npc_chance);
|
||||
|
||||
//check for add NPC
|
||||
if(npc_chance > 0 && npc_id) {
|
||||
if(npc_chance < zone->random.Int(0, 99)) {
|
||||
const NPCType* tmp = database.LoadNPCTypesData(npc_id);
|
||||
if(tmp != nullptr) {
|
||||
auto positionNPC = GetPosition();
|
||||
positionNPC.x = positionNPC.x + 3;
|
||||
auto npc = new NPC(tmp, nullptr, positionNPC, FlyMode3);
|
||||
npc->AddLootTable();
|
||||
if (npc_chance > 0 && npc_id) {
|
||||
if (zone->random.Roll(npc_chance)) {
|
||||
if (zone->CanDoCombat()) {
|
||||
const NPCType *tmp = database.LoadNPCTypesData(npc_id);
|
||||
if (tmp != nullptr) {
|
||||
auto positionNPC = GetPosition();
|
||||
positionNPC.x = positionNPC.x + 3;
|
||||
auto npc = new NPC(tmp, nullptr, positionNPC, GravityBehavior::Water);
|
||||
npc->AddLootTable();
|
||||
if (npc->DropsGlobalLoot())
|
||||
npc->CheckGlobalLootTables();
|
||||
|
||||
npc->AddToHateList(this, 1, 0, false); // no help yelling
|
||||
npc->AddToHateList(this, 1, 0, false); // no help yelling
|
||||
|
||||
entity_list.AddNPC(npc);
|
||||
entity_list.AddNPC(npc);
|
||||
|
||||
Message(MT_Emote, "You fish up a little more than you bargained for...");
|
||||
Message(MT_Emote,
|
||||
"You fish up a little more than you bargained for...");
|
||||
}
|
||||
}
|
||||
else {
|
||||
Message(MT_Emote, "You notice something lurking just below the water's surface...");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -323,12 +331,12 @@ void Client::GoFish()
|
||||
else
|
||||
{
|
||||
PushItemOnCursor(*inst);
|
||||
SendItemPacket(EQEmu::inventory::slotCursor, inst, ItemPacketLimbo);
|
||||
SendItemPacket(EQEmu::invslot::slotCursor, inst, ItemPacketLimbo);
|
||||
if(RuleB(TaskSystem, EnableTaskSystem))
|
||||
UpdateTasksForItem(ActivityFish, food_id);
|
||||
|
||||
safe_delete(inst);
|
||||
inst = m_inv.GetItem(EQEmu::inventory::slotCursor);
|
||||
inst = m_inv.GetItem(EQEmu::invslot::slotCursor);
|
||||
}
|
||||
|
||||
if(inst) {
|
||||
@@ -360,7 +368,7 @@ void Client::GoFish()
|
||||
//and then swap out items in primary slot... too lazy to fix right now
|
||||
if (zone->random.Int(0, 49) == 1) {
|
||||
Message_StringID(MT_Skills, FISHING_POLE_BROKE); //Your fishing pole broke!
|
||||
DeleteItemInInventory(EQEmu::inventory::slotPrimary, 0, true);
|
||||
DeleteItemInInventory(EQEmu::invslot::slotPrimary, 0, true);
|
||||
}
|
||||
|
||||
if (CheckIncreaseSkill(EQEmu::skills::SkillFishing, nullptr, 5))
|
||||
@@ -437,12 +445,12 @@ void Client::ForageItem(bool guarantee) {
|
||||
}
|
||||
else {
|
||||
PushItemOnCursor(*inst);
|
||||
SendItemPacket(EQEmu::inventory::slotCursor, inst, ItemPacketLimbo);
|
||||
SendItemPacket(EQEmu::invslot::slotCursor, inst, ItemPacketLimbo);
|
||||
if(RuleB(TaskSystem, EnableTaskSystem))
|
||||
UpdateTasksForItem(ActivityForage, foragedfood);
|
||||
|
||||
safe_delete(inst);
|
||||
inst = m_inv.GetItem(EQEmu::inventory::slotCursor);
|
||||
inst = m_inv.GetItem(EQEmu::invslot::slotCursor);
|
||||
}
|
||||
|
||||
if(inst) {
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
#include "global_loot_manager.h"
|
||||
#include "npc.h"
|
||||
#include "client.h"
|
||||
|
||||
std::vector<int> GlobalLootManager::GetGlobalLootTables(NPC *mob) const
|
||||
{
|
||||
// we may be able to add a cache here if performance is an issue, but for now
|
||||
// just return NRVO'd vector
|
||||
// The cache would have to be keyed by NPCType and level (for NPCs with Max Level set)
|
||||
std::vector<int> tables;
|
||||
|
||||
for (auto &e : m_entries) {
|
||||
if (e.PassesRules(mob)) {
|
||||
tables.push_back(e.GetLootTableID());
|
||||
}
|
||||
}
|
||||
|
||||
return tables;
|
||||
}
|
||||
|
||||
void GlobalLootManager::ShowZoneGlobalLoot(Client *to) const
|
||||
{
|
||||
for (auto &e : m_entries)
|
||||
to->Message(0, " %s : %d table %d", e.GetDescription().c_str(), e.GetID(), e.GetLootTableID());
|
||||
}
|
||||
|
||||
void GlobalLootManager::ShowNPCGlobalLoot(Client *to, NPC *who) const
|
||||
{
|
||||
for (auto &e : m_entries) {
|
||||
if (e.PassesRules(who))
|
||||
to->Message(0, " %s : %d table %d", e.GetDescription().c_str(), e.GetID(), e.GetLootTableID());
|
||||
}
|
||||
}
|
||||
|
||||
bool GlobalLootEntry::PassesRules(NPC *mob) const
|
||||
{
|
||||
bool bRace = false;
|
||||
bool bPassesRace = false;
|
||||
bool bBodyType = false;
|
||||
bool bPassesBodyType = false;
|
||||
bool bClass = false;
|
||||
bool bPassesClass = false;
|
||||
|
||||
for (auto &r : m_rules) {
|
||||
switch (r.type) {
|
||||
case GlobalLoot::RuleTypes::LevelMin:
|
||||
if (mob->GetLevel() < r.value)
|
||||
return false;
|
||||
break;
|
||||
case GlobalLoot::RuleTypes::LevelMax:
|
||||
if (mob->GetLevel() > r.value)
|
||||
return false;
|
||||
break;
|
||||
case GlobalLoot::RuleTypes::Raid: // value == 0 must not be raid, value != 0 must be raid
|
||||
if (mob->IsRaidTarget() && !r.value)
|
||||
return false;
|
||||
if (!mob->IsRaidTarget() && r.value)
|
||||
return false;
|
||||
break;
|
||||
case GlobalLoot::RuleTypes::Rare:
|
||||
if (mob->IsRareSpawn() && !r.value)
|
||||
return false;
|
||||
if (!mob->IsRareSpawn() && r.value)
|
||||
return false;
|
||||
break;
|
||||
case GlobalLoot::RuleTypes::Race: // can have multiple races per rule set
|
||||
bRace = true; // we must pass race
|
||||
if (mob->GetRace() == r.value)
|
||||
bPassesRace = true;
|
||||
break;
|
||||
case GlobalLoot::RuleTypes::Class: // can have multiple classes per rule set
|
||||
bClass = true; // we must pass class
|
||||
if (mob->GetClass() == r.value)
|
||||
bPassesClass = true;
|
||||
break;
|
||||
case GlobalLoot::RuleTypes::BodyType: // can have multiple bodytypes per rule set
|
||||
bBodyType = true; // we must pass BodyType
|
||||
if (mob->GetBodyType() == r.value)
|
||||
bPassesBodyType = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bRace && !bPassesRace)
|
||||
return false;
|
||||
|
||||
if (bClass && !bPassesClass)
|
||||
return false;
|
||||
|
||||
if (bBodyType && !bPassesBodyType)
|
||||
return false;
|
||||
|
||||
// we abort as early as possible if we fail a rule, so if we get here, we passed
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#ifndef GLOBAL_LOOT_MANAGER_H
|
||||
#define GLOBAL_LOOT_MANAGER_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class NPC;
|
||||
class Client;
|
||||
|
||||
namespace GlobalLoot {
|
||||
|
||||
enum class RuleTypes {
|
||||
LevelMin = 0,
|
||||
LevelMax = 1,
|
||||
Race = 2,
|
||||
Class = 3,
|
||||
BodyType = 4,
|
||||
Rare = 5,
|
||||
Raid = 6,
|
||||
Max
|
||||
};
|
||||
|
||||
struct Rule {
|
||||
RuleTypes type;
|
||||
int value;
|
||||
Rule(RuleTypes t, int v) : type(t), value(v) { }
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class GlobalLootEntry {
|
||||
int m_id;
|
||||
int m_loottable_id;
|
||||
std::string m_description;
|
||||
std::vector<GlobalLoot::Rule> m_rules;
|
||||
public:
|
||||
GlobalLootEntry(int id, int loottable, std::string des)
|
||||
: m_id(id), m_loottable_id(loottable), m_description(std::move(des))
|
||||
{ }
|
||||
bool PassesRules(NPC *mob) const;
|
||||
inline int GetLootTableID() const { return m_loottable_id; }
|
||||
inline int GetID() const { return m_id; }
|
||||
inline const std::string &GetDescription() const { return m_description; }
|
||||
inline void SetLootTableID(int in) { m_loottable_id = in; }
|
||||
inline void SetID(int in) { m_id = in; }
|
||||
inline void SetDescription(const std::string &in) { m_description = in; }
|
||||
inline void AddRule(GlobalLoot::RuleTypes rule, int value) { m_rules.emplace_back(rule, value); }
|
||||
};
|
||||
|
||||
class GlobalLootManager {
|
||||
std::vector<GlobalLootEntry> m_entries;
|
||||
|
||||
public:
|
||||
std::vector<int> GetGlobalLootTables(NPC *mob) const;
|
||||
inline void Clear() { m_entries.clear(); }
|
||||
inline void AddEntry(GlobalLootEntry &in) { m_entries.push_back(in); }
|
||||
void ShowZoneGlobalLoot(Client *to) const;
|
||||
void ShowNPCGlobalLoot(Client *to, NPC *who) const;
|
||||
};
|
||||
|
||||
#endif /* !GLOBAL_LOOT_MANAGER_H */
|
||||
+1
-1
@@ -691,7 +691,7 @@ void GuildBankManager::SendGuildBank(Client *c)
|
||||
auto &guild_bank = *Iterator;
|
||||
|
||||
// RoF+ uses a bulk list packet -- This is also how the Action 0 of older clients basically works
|
||||
if (c->ClientVersionBit() & EQEmu::versions::bit_RoFAndLater) {
|
||||
if (c->ClientVersionBit() & EQEmu::versions::maskRoFAndLater) {
|
||||
auto outapp = new EQApplicationPacket(OP_GuildBankItemList, sizeof(GuildBankItemListEntry_Struct) * 240);
|
||||
for (int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i) {
|
||||
const EQEmu::ItemData *Item = database.GetItem(guild_bank->Items.DepositArea[i].ItemID);
|
||||
|
||||
+118
-21
@@ -107,6 +107,7 @@ void HateList::SetHateAmountOnEnt(Mob* other, uint32 in_hate, uint32 in_damage)
|
||||
entity->hatelist_damage = in_damage;
|
||||
if (in_hate > 0)
|
||||
entity->stored_hate_amount = in_hate;
|
||||
entity->last_modified = Timer::GetCurrentTime();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +193,7 @@ void HateList::AddEntToHateList(Mob *in_entity, int32 in_hate, int32 in_damage,
|
||||
entity->hatelist_damage += (in_damage >= 0) ? in_damage : 0;
|
||||
entity->stored_hate_amount += in_hate;
|
||||
entity->is_entity_frenzy = in_is_entity_frenzied;
|
||||
entity->last_modified = Timer::GetCurrentTime();
|
||||
}
|
||||
else if (iAddIfNotExist) {
|
||||
entity = new struct_HateList;
|
||||
@@ -199,13 +201,13 @@ void HateList::AddEntToHateList(Mob *in_entity, int32 in_hate, int32 in_damage,
|
||||
entity->hatelist_damage = (in_damage >= 0) ? in_damage : 0;
|
||||
entity->stored_hate_amount = in_hate;
|
||||
entity->is_entity_frenzy = in_is_entity_frenzied;
|
||||
entity->oor_count = 0;
|
||||
entity->last_modified = Timer::GetCurrentTime();
|
||||
list.push_back(entity);
|
||||
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "1", 0);
|
||||
|
||||
if (in_entity->IsClient()) {
|
||||
if (hate_owner->CastToNPC()->IsRaidTarget())
|
||||
in_entity->CastToClient()->SetEngagedRaidTarget(true);
|
||||
in_entity->CastToClient()->IncrementAggroCount();
|
||||
in_entity->CastToClient()->IncrementAggroCount(hate_owner->CastToNPC()->IsRaidTarget());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -333,15 +335,6 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center, Mob *skip)
|
||||
continue;
|
||||
}
|
||||
|
||||
auto hateEntryPosition = glm::vec3(cur->entity_on_hatelist->GetX(), cur->entity_on_hatelist->GetY(), cur->entity_on_hatelist->GetZ());
|
||||
if (center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
|
||||
if (!zone->watermap->InLiquid(hateEntryPosition)) {
|
||||
skipped_count++;
|
||||
++iterator;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (cur->entity_on_hatelist->Sanctuary()) {
|
||||
if (hate == -1)
|
||||
{
|
||||
@@ -472,14 +465,6 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center, Mob *skip)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
|
||||
if(!zone->watermap->InLiquid(glm::vec3(cur->entity_on_hatelist->GetPosition()))) {
|
||||
skipped_count++;
|
||||
++iterator;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (cur->entity_on_hatelist != nullptr && ((cur->stored_hate_amount > hate) || cur->is_entity_frenzy))
|
||||
{
|
||||
top_hate = cur->entity_on_hatelist;
|
||||
@@ -536,6 +521,69 @@ Mob *HateList::GetRandomEntOnHateList()
|
||||
return (*iterator)->entity_on_hatelist;
|
||||
}
|
||||
|
||||
Mob *HateList::GetEscapingEntOnHateList() {
|
||||
// function is still in design stage
|
||||
|
||||
for (auto iter : list) {
|
||||
if (!iter->entity_on_hatelist)
|
||||
continue;
|
||||
|
||||
if (!iter->entity_on_hatelist->IsFeared())
|
||||
continue;
|
||||
|
||||
if (iter->entity_on_hatelist->IsRooted())
|
||||
continue;
|
||||
if (iter->entity_on_hatelist->IsMezzed())
|
||||
continue;
|
||||
if (iter->entity_on_hatelist->IsStunned())
|
||||
continue;
|
||||
|
||||
return iter->entity_on_hatelist;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Mob *HateList::GetEscapingEntOnHateList(Mob *center, float range, bool first) {
|
||||
// function is still in design stage
|
||||
|
||||
if (!center)
|
||||
return nullptr;
|
||||
|
||||
Mob *escaping_mob = nullptr;
|
||||
float mob_distance = 0.0f;
|
||||
|
||||
for (auto iter : list) {
|
||||
if (!iter->entity_on_hatelist)
|
||||
continue;
|
||||
|
||||
if (!iter->entity_on_hatelist->IsFeared())
|
||||
continue;
|
||||
|
||||
if (iter->entity_on_hatelist->IsRooted())
|
||||
continue;
|
||||
if (iter->entity_on_hatelist->IsMezzed())
|
||||
continue;
|
||||
if (iter->entity_on_hatelist->IsStunned())
|
||||
continue;
|
||||
|
||||
float distance_test = DistanceSquared(center->GetPosition(), iter->entity_on_hatelist->GetPosition());
|
||||
|
||||
if (range > 0.0f && distance_test > range)
|
||||
continue;
|
||||
|
||||
if (first)
|
||||
return iter->entity_on_hatelist;
|
||||
|
||||
if (distance_test > mob_distance) {
|
||||
escaping_mob = iter->entity_on_hatelist;
|
||||
mob_distance = distance_test;
|
||||
}
|
||||
}
|
||||
|
||||
return escaping_mob;
|
||||
}
|
||||
|
||||
int32 HateList::GetEntHateAmount(Mob *in_entity, bool damage)
|
||||
{
|
||||
struct_HateList *entity;
|
||||
@@ -573,12 +621,19 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption
|
||||
if (!target || !caster)
|
||||
return 0;
|
||||
|
||||
// tank will be hit ONLY if they are the only target on the hate list
|
||||
// if there is anyone else on the hate list, the tank will not be hit, even if those others aren't hit either
|
||||
if (list.size() == 1) {
|
||||
caster->ProcessAttackRounds(target, opts);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int hit_count = 0;
|
||||
// This should prevent crashes if something dies (or mainly more than 1 thing goes away)
|
||||
// This is a temp solution until the hate lists can be rewritten to not have that issue
|
||||
std::vector<uint16> id_list;
|
||||
for (auto &h : list) {
|
||||
if (h->entity_on_hatelist && h->entity_on_hatelist != caster &&
|
||||
if (h->entity_on_hatelist && h->entity_on_hatelist != caster && h->entity_on_hatelist != target &&
|
||||
caster->CombatRange(h->entity_on_hatelist))
|
||||
id_list.push_back(h->entity_on_hatelist->GetID());
|
||||
if (count != -1 && id_list.size() > count)
|
||||
@@ -646,3 +701,45 @@ void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_cent
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
void HateList::RemoveStaleEntries(int time_ms, float dist)
|
||||
{
|
||||
auto it = list.begin();
|
||||
|
||||
auto cur_time = Timer::GetCurrentTime();
|
||||
|
||||
auto dist2 = dist * dist;
|
||||
|
||||
while (it != list.end()) {
|
||||
auto m = (*it)->entity_on_hatelist;
|
||||
if (m) {
|
||||
bool remove = false;
|
||||
|
||||
if (cur_time - (*it)->last_modified > time_ms)
|
||||
remove = true;
|
||||
|
||||
if (!remove && DistanceSquaredNoZ(hate_owner->GetPosition(), m->GetPosition()) > dist2) {
|
||||
(*it)->oor_count++;
|
||||
if ((*it)->oor_count == 2)
|
||||
remove = true;
|
||||
} else if ((*it)->oor_count != 0) {
|
||||
(*it)->oor_count = 0;
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), m, "0", 0);
|
||||
|
||||
if (m->IsClient()) {
|
||||
m->CastToClient()->DecrementAggroCount();
|
||||
m->CastToClient()->RemoveXTarget(hate_owner, true);
|
||||
}
|
||||
|
||||
delete (*it);
|
||||
it = list.erase(it);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ struct struct_HateList
|
||||
int32 hatelist_damage;
|
||||
uint32 stored_hate_amount;
|
||||
bool is_entity_frenzy;
|
||||
int8 oor_count; // count on how long we've been out of range
|
||||
uint32 last_modified; // we need to remove this if it gets higher than 10 mins
|
||||
};
|
||||
|
||||
class HateList
|
||||
@@ -44,6 +46,8 @@ public:
|
||||
Mob *GetEntWithMostHateOnList(Mob *center, Mob *skip = nullptr);
|
||||
Mob *GetRandomEntOnHateList();
|
||||
Mob *GetEntWithMostHateOnList();
|
||||
Mob *GetEscapingEntOnHateList(); // returns first eligble entity
|
||||
Mob *GetEscapingEntOnHateList(Mob *center, float range = 0.0f, bool first = false);
|
||||
|
||||
bool IsEntOnHateList(Mob *mob);
|
||||
bool IsHateListEmpty();
|
||||
@@ -65,6 +69,7 @@ public:
|
||||
void SetHateOwner(Mob *new_hate_owner) { hate_owner = new_hate_owner; }
|
||||
void SpellCast(Mob *caster, uint32 spell_id, float range, Mob *ae_center = nullptr);
|
||||
void WipeHateList();
|
||||
void RemoveStaleEntries(int time_ms, float dist);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
+17
-6
@@ -169,9 +169,10 @@ bool HealRotation::ClearMemberPool()
|
||||
m_casting_target_poke = false;
|
||||
m_active_heal_target = false;
|
||||
|
||||
ClearTargetPool();
|
||||
if (!ClearTargetPool())
|
||||
Log(Logs::General, Logs::Error, "HealRotation::ClearTargetPool() failed to clear m_target_pool (size: %u)", m_target_pool.size());
|
||||
|
||||
auto clear_list = m_member_pool;
|
||||
auto clear_list = const_cast<const std::list<Bot*>&>(m_member_pool);
|
||||
for (auto member_iter : clear_list)
|
||||
member_iter->LeaveHealRotationMemberPool();
|
||||
|
||||
@@ -183,13 +184,23 @@ bool HealRotation::ClearTargetPool()
|
||||
m_hot_target = nullptr;
|
||||
m_hot_active = false;
|
||||
m_is_active = false;
|
||||
|
||||
auto clear_list = m_target_pool;
|
||||
|
||||
auto clear_list = const_cast<const std::list<Mob*>&>(m_target_pool);
|
||||
for (auto target_iter : clear_list)
|
||||
target_iter->LeaveHealRotationTargetPool();
|
||||
|
||||
m_casting_target_poke = false;
|
||||
bias_targets();
|
||||
//m_casting_target_poke = false;
|
||||
//bias_targets();
|
||||
|
||||
// strange crash point...
|
||||
// bias_targets() should be returning on m_target_pool.empty()
|
||||
// and setting this two properties as below
|
||||
m_casting_target_poke = true;
|
||||
m_active_heal_target = false;
|
||||
// instead, the list retains mob shared_ptrs and
|
||||
// attempts to process them - and crashes program
|
||||
// predominate when adaptive_healing = true
|
||||
// (shared_ptr now has a delayed gc action? this did work before...)
|
||||
|
||||
return m_target_pool.empty();
|
||||
}
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ std::map<uint16, const NPCType *> Horse::horse_types;
|
||||
LinkedList<NPCType *> horses_auto_delete;
|
||||
|
||||
Horse::Horse(Client *_owner, uint16 spell_id, const glm::vec4& position)
|
||||
: NPC(GetHorseType(spell_id), nullptr, position, FlyMode3)
|
||||
: NPC(GetHorseType(spell_id), nullptr, position, GravityBehavior::Water)
|
||||
{
|
||||
//give the horse its proper name.
|
||||
strn0cpy(name, _owner->GetCleanName(), 55);
|
||||
@@ -90,7 +90,7 @@ const NPCType *Horse::BuildHorseType(uint16 spell_id) {
|
||||
strcpy(npc_type->name, "Unclaimed_Mount"); // this should never get used
|
||||
|
||||
strcpy(npc_type->special_abilities, "19,1^20,1^24,1");
|
||||
npc_type->cur_hp = 1;
|
||||
npc_type->current_hp = 1;
|
||||
npc_type->max_hp = 1;
|
||||
npc_type->race = atoi(row[0]);
|
||||
npc_type->gender = atoi(row[1]); // Drogmor's are female horses. Yuck.
|
||||
|
||||
+487
-269
File diff suppressed because it is too large
Load Diff
+105
-24
@@ -26,6 +26,7 @@
|
||||
#include "mob.h"
|
||||
#include "npc.h"
|
||||
#include "zonedb.h"
|
||||
#include "global_loot_manager.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
@@ -37,10 +38,14 @@
|
||||
// Queries the loottable: adds item & coin to the npc
|
||||
void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* itemlist, uint32* copper, uint32* silver, uint32* gold, uint32* plat) {
|
||||
const LootTable_Struct* lts = nullptr;
|
||||
*copper = 0;
|
||||
*silver = 0;
|
||||
*gold = 0;
|
||||
*plat = 0;
|
||||
// global loot passes nullptr for these
|
||||
bool bGlobal = copper == nullptr && silver == nullptr && gold == nullptr && plat == nullptr;
|
||||
if (!bGlobal) {
|
||||
*copper = 0;
|
||||
*silver = 0;
|
||||
*gold = 0;
|
||||
*plat = 0;
|
||||
}
|
||||
|
||||
lts = database.GetLootTable(loottable_id);
|
||||
if (!lts)
|
||||
@@ -55,17 +60,19 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite
|
||||
}
|
||||
|
||||
uint32 cash = 0;
|
||||
if(max_cash > 0 && lts->avgcoin > 0 && EQEmu::ValueWithin(lts->avgcoin, min_cash, max_cash)) {
|
||||
float upper_chance = (float)(lts->avgcoin - min_cash) / (float)(max_cash - min_cash);
|
||||
float avg_cash_roll = (float)zone->random.Real(0.0, 1.0);
|
||||
if (!bGlobal) {
|
||||
if(max_cash > 0 && lts->avgcoin > 0 && EQEmu::ValueWithin(lts->avgcoin, min_cash, max_cash)) {
|
||||
float upper_chance = (float)(lts->avgcoin - min_cash) / (float)(max_cash - min_cash);
|
||||
float avg_cash_roll = (float)zone->random.Real(0.0, 1.0);
|
||||
|
||||
if(avg_cash_roll < upper_chance) {
|
||||
cash = zone->random.Int(lts->avgcoin, max_cash);
|
||||
if(avg_cash_roll < upper_chance) {
|
||||
cash = zone->random.Int(lts->avgcoin, max_cash);
|
||||
} else {
|
||||
cash = zone->random.Int(min_cash, lts->avgcoin);
|
||||
}
|
||||
} else {
|
||||
cash = zone->random.Int(min_cash, lts->avgcoin);
|
||||
cash = zone->random.Int(min_cash, max_cash);
|
||||
}
|
||||
} else {
|
||||
cash = zone->random.Int(min_cash, max_cash);
|
||||
}
|
||||
|
||||
if(cash != 0) {
|
||||
@@ -80,6 +87,7 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite
|
||||
|
||||
*copper = cash;
|
||||
}
|
||||
|
||||
uint32 global_loot_multiplier = RuleI(Zone, GlobalLootMultiplier);
|
||||
|
||||
// Do items
|
||||
@@ -255,7 +263,7 @@ void NPC::AddLootDrop(const EQEmu::ItemData *item2, ItemList* itemlist, int16 ch
|
||||
item->attuned = 0;
|
||||
item->min_level = minlevel;
|
||||
item->max_level = maxlevel;
|
||||
item->equip_slot = EQEmu::inventory::slotInvalid;
|
||||
item->equip_slot = EQEmu::invslot::SLOT_INVALID;
|
||||
|
||||
if (equipit) {
|
||||
uint8 eslot = 0xFF;
|
||||
@@ -274,7 +282,7 @@ void NPC::AddLootDrop(const EQEmu::ItemData *item2, ItemList* itemlist, int16 ch
|
||||
// it is an improvement.
|
||||
|
||||
if (!item2->NoPet) {
|
||||
for (int i = 0; !found && i < EQEmu::legacy::EQUIPMENT_SIZE; i++) {
|
||||
for (int i = EQEmu::invslot::EQUIPMENT_BEGIN; !found && i <= EQEmu::invslot::EQUIPMENT_END; i++) {
|
||||
uint32 slots = (1 << i);
|
||||
if (item2->Slots & slots) {
|
||||
if(equipment[i])
|
||||
@@ -315,7 +323,7 @@ void NPC::AddLootDrop(const EQEmu::ItemData *item2, ItemList* itemlist, int16 ch
|
||||
// @merth: IDFile size has been increased, this needs to change
|
||||
uint16 emat;
|
||||
if(item2->Material <= 0
|
||||
|| item2->Slots & (1 << EQEmu::inventory::slotPrimary | 1 << EQEmu::inventory::slotSecondary)) {
|
||||
|| (item2->Slots & ((1 << EQEmu::invslot::slotPrimary) | (1 << EQEmu::invslot::slotSecondary)))) {
|
||||
memset(newid, 0, sizeof(newid));
|
||||
for(int i=0;i<7;i++){
|
||||
if (!isalpha(item2->IDFile[i])){
|
||||
@@ -329,7 +337,7 @@ void NPC::AddLootDrop(const EQEmu::ItemData *item2, ItemList* itemlist, int16 ch
|
||||
emat = item2->Material;
|
||||
}
|
||||
|
||||
if (foundslot == EQEmu::inventory::slotPrimary) {
|
||||
if (foundslot == EQEmu::invslot::slotPrimary) {
|
||||
if (item2->Proc.Effect != 0)
|
||||
CastToMob()->AddProcToWeapon(item2->Proc.Effect, true);
|
||||
|
||||
@@ -342,7 +350,7 @@ void NPC::AddLootDrop(const EQEmu::ItemData *item2, ItemList* itemlist, int16 ch
|
||||
if (item2->IsType2HWeapon())
|
||||
SetTwoHanderEquipped(true);
|
||||
}
|
||||
else if (foundslot == EQEmu::inventory::slotSecondary
|
||||
else if (foundslot == EQEmu::invslot::slotSecondary
|
||||
&& (GetOwner() != nullptr || (CanThisClassDualWield() && zone->random.Roll(NPC_DW_CHANCE)) || (item2->Damage==0)) &&
|
||||
(item2->IsType1HWeapon() || item2->ItemType == EQEmu::item::ItemTypeShield))
|
||||
{
|
||||
@@ -353,25 +361,25 @@ void NPC::AddLootDrop(const EQEmu::ItemData *item2, ItemList* itemlist, int16 ch
|
||||
if (item2->Damage > 0)
|
||||
SendAddPlayerState(PlayerState::SecondaryWeaponEquipped);
|
||||
}
|
||||
else if (foundslot == EQEmu::inventory::slotHead) {
|
||||
else if (foundslot == EQEmu::invslot::slotHead) {
|
||||
eslot = EQEmu::textures::armorHead;
|
||||
}
|
||||
else if (foundslot == EQEmu::inventory::slotChest) {
|
||||
else if (foundslot == EQEmu::invslot::slotChest) {
|
||||
eslot = EQEmu::textures::armorChest;
|
||||
}
|
||||
else if (foundslot == EQEmu::inventory::slotArms) {
|
||||
else if (foundslot == EQEmu::invslot::slotArms) {
|
||||
eslot = EQEmu::textures::armorArms;
|
||||
}
|
||||
else if (foundslot == EQEmu::inventory::slotWrist1 || foundslot == EQEmu::inventory::slotWrist2) {
|
||||
else if (foundslot == EQEmu::invslot::slotWrist1 || foundslot == EQEmu::invslot::slotWrist2) {
|
||||
eslot = EQEmu::textures::armorWrist;
|
||||
}
|
||||
else if (foundslot == EQEmu::inventory::slotHands) {
|
||||
else if (foundslot == EQEmu::invslot::slotHands) {
|
||||
eslot = EQEmu::textures::armorHands;
|
||||
}
|
||||
else if (foundslot == EQEmu::inventory::slotLegs) {
|
||||
else if (foundslot == EQEmu::invslot::slotLegs) {
|
||||
eslot = EQEmu::textures::armorLegs;
|
||||
}
|
||||
else if (foundslot == EQEmu::inventory::slotFeet) {
|
||||
else if (foundslot == EQEmu::invslot::slotFeet) {
|
||||
eslot = EQEmu::textures::armorFeet;
|
||||
}
|
||||
|
||||
@@ -444,3 +452,76 @@ void NPC::AddLootTable(uint32 ldid) {
|
||||
database.AddLootTableToNPC(this,ldid, &itemlist, &copper, &silver, &gold, &platinum);
|
||||
}
|
||||
}
|
||||
|
||||
void NPC::CheckGlobalLootTables()
|
||||
{
|
||||
auto tables = zone->GetGlobalLootTables(this);
|
||||
|
||||
for (auto &id : tables)
|
||||
database.AddLootTableToNPC(this, id, &itemlist, nullptr, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void ZoneDatabase::LoadGlobalLoot()
|
||||
{
|
||||
auto query = StringFormat("SELECT id, loottable_id, description, min_level, max_level, rare, raid, race, "
|
||||
"class, bodytype, zone FROM global_loot WHERE enabled = 1");
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || results.RowCount() == 0)
|
||||
return;
|
||||
|
||||
// we might need this, lets not keep doing it in a loop
|
||||
auto zoneid = std::to_string(zone->GetZoneID());
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
// checking zone limits
|
||||
if (row[10]) {
|
||||
auto zones = SplitString(row[10], '|');
|
||||
|
||||
auto it = std::find(zones.begin(), zones.end(), zoneid);
|
||||
if (it == zones.end()) // not in here, skip
|
||||
continue;
|
||||
}
|
||||
|
||||
GlobalLootEntry e(atoi(row[0]), atoi(row[1]), row[2] ? row[2] : "");
|
||||
|
||||
auto min_level = atoi(row[3]);
|
||||
if (min_level)
|
||||
e.AddRule(GlobalLoot::RuleTypes::LevelMin, min_level);
|
||||
|
||||
auto max_level = atoi(row[4]);
|
||||
if (max_level)
|
||||
e.AddRule(GlobalLoot::RuleTypes::LevelMax, max_level);
|
||||
|
||||
// null is not used
|
||||
if (row[5])
|
||||
e.AddRule(GlobalLoot::RuleTypes::Rare, atoi(row[5]));
|
||||
|
||||
// null is not used
|
||||
if (row[6])
|
||||
e.AddRule(GlobalLoot::RuleTypes::Raid, atoi(row[6]));
|
||||
|
||||
if (row[7]) {
|
||||
auto races = SplitString(row[7], '|');
|
||||
|
||||
for (auto &r : races)
|
||||
e.AddRule(GlobalLoot::RuleTypes::Race, std::stoi(r));
|
||||
}
|
||||
|
||||
if (row[8]) {
|
||||
auto classes = SplitString(row[8], '|');
|
||||
|
||||
for (auto &c : classes)
|
||||
e.AddRule(GlobalLoot::RuleTypes::Class, std::stoi(c));
|
||||
}
|
||||
|
||||
if (row[9]) {
|
||||
auto bodytypes = SplitString(row[9], '|');
|
||||
|
||||
for (auto &b : bodytypes)
|
||||
e.AddRule(GlobalLoot::RuleTypes::Class, std::stoi(b));
|
||||
}
|
||||
|
||||
zone->AddGlobalLootEntry(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+38
-4
@@ -550,6 +550,16 @@ void Lua_Client::UnmemSpellAll(bool update_client) {
|
||||
self->UnmemSpellAll(update_client);
|
||||
}
|
||||
|
||||
uint16 Lua_Client::FindMemmedSpellBySlot(int slot) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->FindMemmedSpellBySlot(slot);
|
||||
}
|
||||
|
||||
int Lua_Client::MemmedCount() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->MemmedCount();
|
||||
}
|
||||
|
||||
void Lua_Client::ScribeSpell(int spell_id, int slot) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ScribeSpell(spell_id, slot);
|
||||
@@ -615,11 +625,21 @@ void Lua_Client::UntrainDiscAll(bool update_client) {
|
||||
self->UntrainDiscAll(update_client);
|
||||
}
|
||||
|
||||
bool Lua_Client::IsStanding() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->IsStanding();
|
||||
}
|
||||
|
||||
bool Lua_Client::IsSitting() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->IsSitting();
|
||||
}
|
||||
|
||||
bool Lua_Client::IsCrouching() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->IsCrouching();
|
||||
}
|
||||
|
||||
void Lua_Client::SetFeigned(bool v) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetFeigned(v);
|
||||
@@ -725,14 +745,12 @@ void Lua_Client::SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug
|
||||
self->SummonItem(item_id, charges, aug1, aug2, aug3, aug4, aug5);
|
||||
}
|
||||
|
||||
void Lua_Client::SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5,
|
||||
bool attuned) {
|
||||
void Lua_Client::SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, bool attuned) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SummonItem(item_id, charges, aug1, aug2, aug3, aug4, aug5, 0, attuned);
|
||||
}
|
||||
|
||||
void Lua_Client::SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5,
|
||||
bool attuned, int to_slot) {
|
||||
void Lua_Client::SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, bool attuned, int to_slot) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SummonItem(item_id, charges, aug1, aug2, aug3, aug4, aug5, 0, attuned, to_slot);
|
||||
}
|
||||
@@ -1488,6 +1506,16 @@ void Lua_Client::DisableAreaRegens()
|
||||
self->DisableAreaRegens();
|
||||
}
|
||||
|
||||
void Lua_Client::SetPrimaryWeaponOrnamentation(uint32 model_id) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetPrimaryWeaponOrnamentation(model_id);
|
||||
}
|
||||
|
||||
void Lua_Client::SetSecondaryWeaponOrnamentation(uint32 model_id) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetSecondaryWeaponOrnamentation(model_id);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_client() {
|
||||
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
||||
.def(luabind::constructor<>())
|
||||
@@ -1550,6 +1578,8 @@ luabind::scope lua_register_client() {
|
||||
.def("GetBindHeading", (float(Lua_Client::*)(int))&Lua_Client::GetBindHeading)
|
||||
.def("GetBindZoneID", (uint32(Lua_Client::*)(void))&Lua_Client::GetBindZoneID)
|
||||
.def("GetBindZoneID", (uint32(Lua_Client::*)(int))&Lua_Client::GetBindZoneID)
|
||||
.def("SetPrimaryWeaponOrnamentation", (void(Lua_Client::*)(uint32))&Lua_Client::SetPrimaryWeaponOrnamentation)
|
||||
.def("SetSecondaryWeaponOrnamentation", (void(Lua_Client::*)(uint32))&Lua_Client::SetSecondaryWeaponOrnamentation)
|
||||
.def("MovePC", (void(Lua_Client::*)(int,float,float,float,float))&Lua_Client::MovePC)
|
||||
.def("MovePCInstance", (void(Lua_Client::*)(int,int,float,float,float,float))&Lua_Client::MovePCInstance)
|
||||
.def("ChangeLastName", (void(Lua_Client::*)(const char *in))&Lua_Client::ChangeLastName)
|
||||
@@ -1598,6 +1628,8 @@ luabind::scope lua_register_client() {
|
||||
.def("UnmemSpellBySpellID", (void(Lua_Client::*)(int32))&Lua_Client::UnmemSpellBySpellID)
|
||||
.def("UnmemSpellAll", (void(Lua_Client::*)(void))&Lua_Client::UnmemSpellAll)
|
||||
.def("UnmemSpellAll", (void(Lua_Client::*)(bool))&Lua_Client::UnmemSpellAll)
|
||||
.def("FindMemmedSpellBySlot", (uint16(Lua_Client::*)(int))&Lua_Client::FindMemmedSpellBySlot)
|
||||
.def("MemmedCount", (int(Lua_Client::*)(void))&Lua_Client::MemmedCount)
|
||||
.def("ScribeSpell", (void(Lua_Client::*)(int,int))&Lua_Client::ScribeSpell)
|
||||
.def("ScribeSpell", (void(Lua_Client::*)(int,int,bool))&Lua_Client::ScribeSpell)
|
||||
.def("UnscribeSpell", (void(Lua_Client::*)(int))&Lua_Client::UnscribeSpell)
|
||||
@@ -1611,7 +1643,9 @@ luabind::scope lua_register_client() {
|
||||
.def("UntrainDisc", (void(Lua_Client::*)(int,bool))&Lua_Client::UntrainDisc)
|
||||
.def("UntrainDiscAll", (void(Lua_Client::*)(void))&Lua_Client::UntrainDiscAll)
|
||||
.def("UntrainDiscAll", (void(Lua_Client::*)(bool))&Lua_Client::UntrainDiscAll)
|
||||
.def("IsStanding", (bool(Lua_Client::*)(void))&Lua_Client::IsStanding)
|
||||
.def("IsSitting", (bool(Lua_Client::*)(void))&Lua_Client::IsSitting)
|
||||
.def("IsCrouching", (bool(Lua_Client::*)(void))&Lua_Client::IsCrouching)
|
||||
.def("SetFeigned", (void(Lua_Client::*)(bool))&Lua_Client::SetFeigned)
|
||||
.def("GetFeigned", (bool(Lua_Client::*)(void))&Lua_Client::GetFeigned)
|
||||
.def("AutoSplitEnabled", (bool(Lua_Client::*)(void))&Lua_Client::AutoSplitEnabled)
|
||||
|
||||
@@ -135,6 +135,8 @@ public:
|
||||
void UnmemSpellBySpellID(int32 spell_id);
|
||||
void UnmemSpellAll();
|
||||
void UnmemSpellAll(bool update_client);
|
||||
uint16 FindMemmedSpellBySlot(int slot);
|
||||
int MemmedCount();
|
||||
void ScribeSpell(int spell_id, int slot);
|
||||
void ScribeSpell(int spell_id, int slot, bool update_client);
|
||||
void UnscribeSpell(int slot);
|
||||
@@ -148,7 +150,9 @@ public:
|
||||
void UntrainDisc(int slot, bool update_client);
|
||||
void UntrainDiscAll();
|
||||
void UntrainDiscAll(bool update_client);
|
||||
bool IsStanding();
|
||||
bool IsSitting();
|
||||
bool IsCrouching();
|
||||
void SetFeigned(bool v);
|
||||
bool GetFeigned();
|
||||
bool AutoSplitEnabled();
|
||||
@@ -309,6 +313,10 @@ public:
|
||||
void DisableAreaEndRegen();
|
||||
void EnableAreaRegens(int value);
|
||||
void DisableAreaRegens();
|
||||
|
||||
|
||||
void SetPrimaryWeaponOrnamentation(uint32 model_id);
|
||||
void SetSecondaryWeaponOrnamentation(uint32 model_id);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -231,7 +231,7 @@ void Lua_EntityList::ReplaceWithTarget(Lua_Mob target, Lua_Mob new_target) {
|
||||
self->ReplaceWithTarget(target, new_target);
|
||||
}
|
||||
|
||||
void Lua_EntityList::OpenDoorsNear(Lua_NPC opener) {
|
||||
void Lua_EntityList::OpenDoorsNear(Lua_Mob opener) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->OpenDoorsNear(opener);
|
||||
}
|
||||
@@ -340,6 +340,22 @@ Lua_Client_List Lua_EntityList::GetClientList() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
Lua_Client_List Lua_EntityList::GetShuffledClientList() {
|
||||
Lua_Safe_Call_Class(Lua_Client_List);
|
||||
Lua_Client_List ret;
|
||||
auto &t_list = self->GetClientList();
|
||||
|
||||
auto iter = t_list.begin();
|
||||
while(iter != t_list.end()) {
|
||||
ret.entries.push_back(Lua_Client(iter->second));
|
||||
++iter;
|
||||
}
|
||||
|
||||
zone->random.Shuffle(ret.entries.begin(), ret.entries.end());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Lua_NPC_List Lua_EntityList::GetNPCList() {
|
||||
Lua_Safe_Call_Class(Lua_NPC_List);
|
||||
Lua_NPC_List ret;
|
||||
@@ -463,7 +479,7 @@ luabind::scope lua_register_entity_list() {
|
||||
.def("RemoveFromTargets", (void(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::RemoveFromTargets)
|
||||
.def("RemoveFromTargets", (void(Lua_EntityList::*)(Lua_Mob, bool))&Lua_EntityList::RemoveFromTargets)
|
||||
.def("ReplaceWithTarget", (void(Lua_EntityList::*)(Lua_Mob, Lua_Mob))&Lua_EntityList::ReplaceWithTarget)
|
||||
.def("OpenDoorsNear", (void(Lua_EntityList::*)(Lua_NPC))&Lua_EntityList::OpenDoorsNear)
|
||||
.def("OpenDoorsNear", (void(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::OpenDoorsNear)
|
||||
.def("MakeNameUnique", (std::string(Lua_EntityList::*)(const char*))&Lua_EntityList::MakeNameUnique)
|
||||
.def("RemoveNumbers", (std::string(Lua_EntityList::*)(const char*))&Lua_EntityList::RemoveNumbers)
|
||||
.def("SignalMobsByNPCID", (void(Lua_EntityList::*)(uint32, int))&Lua_EntityList::SignalMobsByNPCID)
|
||||
@@ -480,6 +496,7 @@ luabind::scope lua_register_entity_list() {
|
||||
.def("GetRandomClient", (Lua_Client(Lua_EntityList::*)(float, float, float, float, Lua_Client))&Lua_EntityList::GetRandomClient)
|
||||
.def("GetMobList", (Lua_Mob_List(Lua_EntityList::*)(void))&Lua_EntityList::GetMobList)
|
||||
.def("GetClientList", (Lua_Client_List(Lua_EntityList::*)(void))&Lua_EntityList::GetClientList)
|
||||
.def("GetShuffledClientList", (Lua_Client_List(Lua_EntityList::*)(void))&Lua_EntityList::GetShuffledClientList)
|
||||
.def("GetNPCList", (Lua_NPC_List(Lua_EntityList::*)(void))&Lua_EntityList::GetNPCList)
|
||||
.def("GetCorpseList", (Lua_Corpse_List(Lua_EntityList::*)(void))&Lua_EntityList::GetCorpseList)
|
||||
.def("GetObjectList", (Lua_Object_List(Lua_EntityList::*)(void))&Lua_EntityList::GetObjectList)
|
||||
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
void RemoveFromTargets(Lua_Mob mob);
|
||||
void RemoveFromTargets(Lua_Mob mob, bool RemoveFromXTargets);
|
||||
void ReplaceWithTarget(Lua_Mob target, Lua_Mob new_target);
|
||||
void OpenDoorsNear(Lua_NPC opener);
|
||||
void OpenDoorsNear(Lua_Mob opener);
|
||||
std::string MakeNameUnique(const char *name);
|
||||
std::string RemoveNumbers(const char *name);
|
||||
void SignalMobsByNPCID(uint32 npc_id, int signal);
|
||||
@@ -101,6 +101,7 @@ public:
|
||||
Lua_Client GetRandomClient(float x, float y, float z, float dist, Lua_Client exclude);
|
||||
Lua_Mob_List GetMobList();
|
||||
Lua_Client_List GetClientList();
|
||||
Lua_Client_List GetShuffledClientList();
|
||||
Lua_NPC_List GetNPCList();
|
||||
Lua_Corpse_List GetCorpseList();
|
||||
Lua_Object_List GetObjectList();
|
||||
|
||||
+168
-73
@@ -22,6 +22,7 @@
|
||||
#include "qglobals.h"
|
||||
#include "encounter.h"
|
||||
#include "lua_encounter.h"
|
||||
#include "data_bucket.h"
|
||||
|
||||
struct Events { };
|
||||
struct Factions { };
|
||||
@@ -341,6 +342,19 @@ void lua_stop_all_timers(Lua_Encounter enc) {
|
||||
quest_manager.stopalltimers(enc);
|
||||
}
|
||||
|
||||
void lua_pause_timer(const char *timer) {
|
||||
quest_manager.pausetimer(timer);
|
||||
|
||||
}
|
||||
|
||||
void lua_resume_timer(const char *timer) {
|
||||
quest_manager.resumetimer(timer);
|
||||
}
|
||||
|
||||
bool lua_is_paused_timer(const char *timer) {
|
||||
return quest_manager.ispausedtimer(timer);
|
||||
}
|
||||
|
||||
void lua_depop() {
|
||||
quest_manager.depop(0);
|
||||
}
|
||||
@@ -493,6 +507,10 @@ void lua_set_proximity(float min_x, float max_x, float min_y, float max_y, float
|
||||
quest_manager.set_proximity(min_x, max_x, min_y, max_y, min_z, max_z);
|
||||
}
|
||||
|
||||
void lua_set_proximity(float min_x, float max_x, float min_y, float max_y, float min_z, float max_z, bool say) {
|
||||
quest_manager.set_proximity(min_x, max_x, min_y, max_y, min_z, max_z, say);
|
||||
}
|
||||
|
||||
void lua_clear_proximity() {
|
||||
quest_manager.clear_proximity();
|
||||
}
|
||||
@@ -771,33 +789,59 @@ int lua_merchant_count_item(uint32 npc_id, uint32 item_id) {
|
||||
|
||||
std::string lua_item_link(int item_id) {
|
||||
char text[250] = { 0 };
|
||||
quest_manager.varlink(text, item_id);
|
||||
|
||||
return std::string(text);
|
||||
return quest_manager.varlink(text, item_id);
|
||||
}
|
||||
|
||||
std::string lua_say_link(const char *phrase, bool silent, const char *link_name) {
|
||||
char text[256] = { 0 };
|
||||
strncpy(text, phrase, 255);
|
||||
quest_manager.saylink(text, silent, link_name);
|
||||
|
||||
return std::string(text);
|
||||
return quest_manager.saylink(text, silent, link_name);
|
||||
}
|
||||
|
||||
std::string lua_say_link(const char *phrase, bool silent) {
|
||||
char text[256] = { 0 };
|
||||
strncpy(text, phrase, 255);
|
||||
quest_manager.saylink(text, silent, text);
|
||||
|
||||
return std::string(text);
|
||||
return quest_manager.saylink(text, silent, text);
|
||||
}
|
||||
|
||||
std::string lua_say_link(const char *phrase) {
|
||||
char text[256] = { 0 };
|
||||
strncpy(text, phrase, 255);
|
||||
quest_manager.saylink(text, false, text);
|
||||
|
||||
return std::string(text);
|
||||
return quest_manager.saylink(text, false, text);
|
||||
}
|
||||
|
||||
void lua_set_rule(std::string rule_name, std::string rule_value) {
|
||||
RuleManager::Instance()->SetRule(rule_name.c_str(), rule_value.c_str());
|
||||
}
|
||||
|
||||
std::string lua_get_rule(std::string rule_name) {
|
||||
std::string rule_value;
|
||||
RuleManager::Instance()->GetRule(rule_name.c_str(), rule_value);
|
||||
return rule_value;
|
||||
}
|
||||
|
||||
std::string lua_get_data(std::string bucket_key) {
|
||||
return DataBucket::GetData(bucket_key);
|
||||
}
|
||||
|
||||
std::string lua_get_data_expires(std::string bucket_key) {
|
||||
return DataBucket::GetDataExpires(bucket_key);
|
||||
}
|
||||
|
||||
void lua_set_data(std::string bucket_key, std::string bucket_value) {
|
||||
DataBucket::SetData(bucket_key, bucket_value);
|
||||
}
|
||||
|
||||
void lua_set_data(std::string bucket_key, std::string bucket_value, std::string expires_at) {
|
||||
DataBucket::SetData(bucket_key, bucket_value, expires_at);
|
||||
}
|
||||
|
||||
bool lua_delete_data(std::string bucket_key) {
|
||||
return DataBucket::DeleteData(bucket_key);
|
||||
}
|
||||
|
||||
const char *lua_get_guild_name_by_id(uint32 guild_id) {
|
||||
@@ -828,10 +872,18 @@ int lua_get_instance_id(const char *zone, uint32 version) {
|
||||
return quest_manager.GetInstanceID(zone, version);
|
||||
}
|
||||
|
||||
int lua_get_instance_id_by_char_id(const char *zone, uint32 version, uint32 char_id) {
|
||||
return quest_manager.GetInstanceIDByCharID(zone, version, char_id);
|
||||
}
|
||||
|
||||
void lua_assign_to_instance(uint32 instance_id) {
|
||||
quest_manager.AssignToInstance(instance_id);
|
||||
}
|
||||
|
||||
void lua_assign_to_instance_by_char_id(uint32 instance_id, uint32 char_id) {
|
||||
quest_manager.AssignToInstanceByCharID(instance_id, char_id);
|
||||
}
|
||||
|
||||
void lua_assign_group_to_instance(uint32 instance_id) {
|
||||
quest_manager.AssignGroupToInstance(instance_id);
|
||||
}
|
||||
@@ -844,6 +896,10 @@ void lua_remove_from_instance(uint32 instance_id) {
|
||||
quest_manager.RemoveFromInstance(instance_id);
|
||||
}
|
||||
|
||||
void lua_remove_from_instance_by_char_id(uint32 instance_id, uint32 char_id) {
|
||||
quest_manager.RemoveFromInstanceByCharID(instance_id, char_id);
|
||||
}
|
||||
|
||||
void lua_remove_all_from_instance(uint32 instance_id) {
|
||||
quest_manager.RemoveAllFromInstance(instance_id);
|
||||
}
|
||||
@@ -857,7 +913,7 @@ void lua_flag_instance_by_raid_leader(uint32 zone, uint32 version) {
|
||||
}
|
||||
|
||||
void lua_fly_mode(int flymode) {
|
||||
quest_manager.FlyMode(flymode);
|
||||
quest_manager.FlyMode(static_cast<GravityBehavior>(flymode));
|
||||
}
|
||||
|
||||
int lua_faction_value() {
|
||||
@@ -1367,7 +1423,7 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float
|
||||
luabind::adl::index_proxy<luabind::adl::object> cur = table["name"];
|
||||
LuaCreateNPCParseString(name, 64, "_");
|
||||
LuaCreateNPCParseString(lastname, 64, "");
|
||||
LuaCreateNPCParse(cur_hp, int32, 30);
|
||||
LuaCreateNPCParse(current_hp, int32, 30);
|
||||
LuaCreateNPCParse(max_hp, int32, 30);
|
||||
LuaCreateNPCParse(size, float, 6.0f);
|
||||
LuaCreateNPCParse(runspeed, float, 1.25f);
|
||||
@@ -1392,19 +1448,19 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float
|
||||
LuaCreateNPCParse(AC, uint32, 0);
|
||||
LuaCreateNPCParse(Mana, uint32, 0);
|
||||
LuaCreateNPCParse(ATK, uint32, 0);
|
||||
LuaCreateNPCParse(STR, uint32, 75);
|
||||
LuaCreateNPCParse(STA, uint32, 75);
|
||||
LuaCreateNPCParse(DEX, uint32, 75);
|
||||
LuaCreateNPCParse(AGI, uint32, 75);
|
||||
LuaCreateNPCParse(INT, uint32, 75);
|
||||
LuaCreateNPCParse(WIS, uint32, 75);
|
||||
LuaCreateNPCParse(CHA, uint32, 75);
|
||||
LuaCreateNPCParse(MR, int32, 25);
|
||||
LuaCreateNPCParse(FR, int32, 25);
|
||||
LuaCreateNPCParse(CR, int32, 25);
|
||||
LuaCreateNPCParse(PR, int32, 25);
|
||||
LuaCreateNPCParse(DR, int32, 25);
|
||||
LuaCreateNPCParse(Corrup, int32, 25);
|
||||
LuaCreateNPCParse(STR, uint32, 0);
|
||||
LuaCreateNPCParse(STA, uint32, 0);
|
||||
LuaCreateNPCParse(DEX, uint32, 0);
|
||||
LuaCreateNPCParse(AGI, uint32, 0);
|
||||
LuaCreateNPCParse(INT, uint32, 0);
|
||||
LuaCreateNPCParse(WIS, uint32, 0);
|
||||
LuaCreateNPCParse(CHA, uint32, 0);
|
||||
LuaCreateNPCParse(MR, int32, 0);
|
||||
LuaCreateNPCParse(FR, int32, 0);
|
||||
LuaCreateNPCParse(CR, int32, 0);
|
||||
LuaCreateNPCParse(PR, int32, 0);
|
||||
LuaCreateNPCParse(DR, int32, 0);
|
||||
LuaCreateNPCParse(Corrup, int32, 0);
|
||||
LuaCreateNPCParse(PhR, int32, 0);
|
||||
LuaCreateNPCParse(haircolor, uint8, 0);
|
||||
LuaCreateNPCParse(beardcolor, uint8, 0);
|
||||
@@ -1464,9 +1520,8 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float
|
||||
LuaCreateNPCParse(healscale, float, 0);
|
||||
LuaCreateNPCParse(no_target_hotkey, bool, false);
|
||||
LuaCreateNPCParse(raid_target, bool, false);
|
||||
LuaCreateNPCParse(probability, uint8, 0);
|
||||
|
||||
NPC* npc = new NPC(npc_type, nullptr, glm::vec4(x, y, z, heading), FlyMode3);
|
||||
NPC* npc = new NPC(npc_type, nullptr, glm::vec4(x, y, z, heading), GravityBehavior::Water);
|
||||
npc->GiveNPCTypeData(npc_type);
|
||||
entity_list.AddNPC(npc);
|
||||
}
|
||||
@@ -1540,6 +1595,9 @@ luabind::scope lua_register_general() {
|
||||
luabind::def("stop_timer", (void(*)(const char*, Lua_ItemInst))&lua_stop_timer),
|
||||
luabind::def("stop_timer", (void(*)(const char*, Lua_Mob))&lua_stop_timer),
|
||||
luabind::def("stop_timer", (void(*)(const char*, Lua_Encounter))&lua_stop_timer),
|
||||
luabind::def("pause_timer", (void(*)(const char*))&lua_pause_timer),
|
||||
luabind::def("resume_timer", (void(*)(const char*))&lua_resume_timer),
|
||||
luabind::def("is_paused_timer", (bool(*)(const char*))&lua_is_paused_timer),
|
||||
luabind::def("stop_all_timers", (void(*)(void))&lua_stop_all_timers),
|
||||
luabind::def("stop_all_timers", (void(*)(Lua_ItemInst))&lua_stop_all_timers),
|
||||
luabind::def("stop_all_timers", (void(*)(Lua_Mob))&lua_stop_all_timers),
|
||||
@@ -1582,6 +1640,7 @@ luabind::scope lua_register_general() {
|
||||
luabind::def("respawn", &lua_respawn),
|
||||
luabind::def("set_proximity", (void(*)(float,float,float,float))&lua_set_proximity),
|
||||
luabind::def("set_proximity", (void(*)(float,float,float,float,float,float))&lua_set_proximity),
|
||||
luabind::def("set_proximity", (void(*)(float,float,float,float,float,float,bool))&lua_set_proximity),
|
||||
luabind::def("clear_proximity", &lua_clear_proximity),
|
||||
luabind::def("enable_proximity_say", &lua_enable_proximity_say),
|
||||
luabind::def("disable_proximity_say", &lua_disable_proximity_say),
|
||||
@@ -1638,16 +1697,28 @@ luabind::scope lua_register_general() {
|
||||
luabind::def("say_link", (std::string(*)(const char*,bool,const char*))&lua_say_link),
|
||||
luabind::def("say_link", (std::string(*)(const char*,bool))&lua_say_link),
|
||||
luabind::def("say_link", (std::string(*)(const char*))&lua_say_link),
|
||||
luabind::def("set_rule", (void(*)(std::string, std::string))&lua_set_rule),
|
||||
luabind::def("get_rule", (std::string(*)(std::string))&lua_get_rule),
|
||||
luabind::def("get_data", (std::string(*)(std::string))&lua_get_data),
|
||||
luabind::def("get_data_expires", (std::string(*)(std::string))&lua_get_data_expires),
|
||||
luabind::def("set_data", (void(*)(std::string, std::string))&lua_set_data),
|
||||
luabind::def("set_data", (void(*)(std::string, std::string, std::string))&lua_set_data),
|
||||
luabind::def("delete_data", (bool(*)(std::string))&lua_delete_data),
|
||||
luabind::def("get_guild_name_by_id", &lua_get_guild_name_by_id),
|
||||
luabind::def("create_instance", &lua_create_instance),
|
||||
luabind::def("destroy_instance", &lua_destroy_instance),
|
||||
luabind::def("update_instance_timer", &lua_update_instance_timer),
|
||||
luabind::def("get_instance_id", &lua_get_instance_id),
|
||||
luabind::def("get_instance_id_by_char_id", &lua_get_instance_id_by_char_id),
|
||||
luabind::def("get_instance_timer", &lua_get_instance_timer),
|
||||
luabind::def("get_instance_timer_by_id", &lua_get_instance_timer_by_id),
|
||||
luabind::def("get_characters_in_instance", &lua_get_characters_in_instance),
|
||||
luabind::def("assign_to_instance", &lua_assign_to_instance),
|
||||
luabind::def("assign_to_instance_by_char_id", &lua_assign_to_instance_by_char_id),
|
||||
luabind::def("assign_group_to_instance", &lua_assign_group_to_instance),
|
||||
luabind::def("assign_raid_to_instance", &lua_assign_raid_to_instance),
|
||||
luabind::def("remove_from_instance", &lua_remove_from_instance),
|
||||
luabind::def("remove_from_instance_by_char_id", &lua_remove_from_instance_by_char_id),
|
||||
luabind::def("remove_all_from_instance", &lua_remove_all_from_instance),
|
||||
luabind::def("flag_instance_by_group_leader", &lua_flag_instance_by_group_leader),
|
||||
luabind::def("flag_instance_by_raid_leader", &lua_flag_instance_by_raid_leader),
|
||||
@@ -1821,51 +1892,74 @@ luabind::scope lua_register_slot() {
|
||||
return luabind::class_<Slots>("Slot")
|
||||
.enum_("constants")
|
||||
[
|
||||
luabind::value("Charm", static_cast<int>(EQEmu::inventory::slotCharm)),
|
||||
luabind::value("Ear1", static_cast<int>(EQEmu::inventory::slotEar1)),
|
||||
luabind::value("Head", static_cast<int>(EQEmu::inventory::slotHead)),
|
||||
luabind::value("Face", static_cast<int>(EQEmu::inventory::slotFace)),
|
||||
luabind::value("Ear2", static_cast<int>(EQEmu::inventory::slotEar2)),
|
||||
luabind::value("Neck", static_cast<int>(EQEmu::inventory::slotNeck)),
|
||||
luabind::value("Shoulder", static_cast<int>(EQEmu::inventory::slotShoulders)), // deprecated
|
||||
luabind::value("Shoulders", static_cast<int>(EQEmu::inventory::slotShoulders)),
|
||||
luabind::value("Arms", static_cast<int>(EQEmu::inventory::slotArms)),
|
||||
luabind::value("Back", static_cast<int>(EQEmu::inventory::slotBack)),
|
||||
luabind::value("Bracer1", static_cast<int>(EQEmu::inventory::slotWrist1)), // deprecated
|
||||
luabind::value("Wrist1", static_cast<int>(EQEmu::inventory::slotWrist1)),
|
||||
luabind::value("Bracer2", static_cast<int>(EQEmu::inventory::slotWrist2)), // deprecated
|
||||
luabind::value("Wrist2", static_cast<int>(EQEmu::inventory::slotWrist2)),
|
||||
luabind::value("Range", static_cast<int>(EQEmu::inventory::slotRange)),
|
||||
luabind::value("Hands", static_cast<int>(EQEmu::inventory::slotHands)),
|
||||
luabind::value("Primary", static_cast<int>(EQEmu::inventory::slotPrimary)),
|
||||
luabind::value("Secondary", static_cast<int>(EQEmu::inventory::slotSecondary)),
|
||||
luabind::value("Ring1", static_cast<int>(EQEmu::inventory::slotFinger1)), // deprecated
|
||||
luabind::value("Finger1", static_cast<int>(EQEmu::inventory::slotFinger1)),
|
||||
luabind::value("Ring2", static_cast<int>(EQEmu::inventory::slotFinger2)), // deprecated
|
||||
luabind::value("Finger2", static_cast<int>(EQEmu::inventory::slotFinger2)),
|
||||
luabind::value("Chest", static_cast<int>(EQEmu::inventory::slotChest)),
|
||||
luabind::value("Legs", static_cast<int>(EQEmu::inventory::slotLegs)),
|
||||
luabind::value("Feet", static_cast<int>(EQEmu::inventory::slotFeet)),
|
||||
luabind::value("Waist", static_cast<int>(EQEmu::inventory::slotWaist)),
|
||||
luabind::value("PowerSource", static_cast<int>(EQEmu::inventory::slotPowerSource)),
|
||||
luabind::value("Ammo", static_cast<int>(EQEmu::inventory::slotAmmo)),
|
||||
luabind::value("General1", static_cast<int>(EQEmu::inventory::slotGeneral1)),
|
||||
luabind::value("General2", static_cast<int>(EQEmu::inventory::slotGeneral2)),
|
||||
luabind::value("General3", static_cast<int>(EQEmu::inventory::slotGeneral3)),
|
||||
luabind::value("General4", static_cast<int>(EQEmu::inventory::slotGeneral4)),
|
||||
luabind::value("General5", static_cast<int>(EQEmu::inventory::slotGeneral5)),
|
||||
luabind::value("General6", static_cast<int>(EQEmu::inventory::slotGeneral6)),
|
||||
luabind::value("General7", static_cast<int>(EQEmu::inventory::slotGeneral7)),
|
||||
luabind::value("General8", static_cast<int>(EQEmu::inventory::slotGeneral8)),
|
||||
luabind::value("Cursor", static_cast<int>(EQEmu::inventory::slotCursor)),
|
||||
luabind::value("PersonalBegin", static_cast<int>(EQEmu::legacy::GENERAL_BEGIN)), // deprecated
|
||||
luabind::value("GeneralBegin", static_cast<int>(EQEmu::legacy::GENERAL_BEGIN)),
|
||||
luabind::value("PersonalEnd", static_cast<int>(EQEmu::legacy::GENERAL_END)), // deprecated
|
||||
luabind::value("GeneralEnd", static_cast<int>(EQEmu::legacy::GENERAL_END)),
|
||||
luabind::value("CursorEnd", 0xFFFE), // deprecated
|
||||
luabind::value("Tradeskill", static_cast<int>(EQEmu::legacy::SLOT_TRADESKILL)), // deprecated
|
||||
luabind::value("Augment", static_cast<int>(EQEmu::legacy::SLOT_AUGMENT)), // deprecated
|
||||
luabind::value("Invalid", INVALID_INDEX)
|
||||
luabind::value("Charm", static_cast<int>(EQEmu::invslot::slotCharm)),
|
||||
luabind::value("Ear1", static_cast<int>(EQEmu::invslot::slotEar1)),
|
||||
luabind::value("Head", static_cast<int>(EQEmu::invslot::slotHead)),
|
||||
luabind::value("Face", static_cast<int>(EQEmu::invslot::slotFace)),
|
||||
luabind::value("Ear2", static_cast<int>(EQEmu::invslot::slotEar2)),
|
||||
luabind::value("Neck", static_cast<int>(EQEmu::invslot::slotNeck)),
|
||||
luabind::value("Shoulders", static_cast<int>(EQEmu::invslot::slotShoulders)),
|
||||
luabind::value("Arms", static_cast<int>(EQEmu::invslot::slotArms)),
|
||||
luabind::value("Back", static_cast<int>(EQEmu::invslot::slotBack)),
|
||||
luabind::value("Wrist1", static_cast<int>(EQEmu::invslot::slotWrist1)),
|
||||
luabind::value("Wrist2", static_cast<int>(EQEmu::invslot::slotWrist2)),
|
||||
luabind::value("Range", static_cast<int>(EQEmu::invslot::slotRange)),
|
||||
luabind::value("Hands", static_cast<int>(EQEmu::invslot::slotHands)),
|
||||
luabind::value("Primary", static_cast<int>(EQEmu::invslot::slotPrimary)),
|
||||
luabind::value("Secondary", static_cast<int>(EQEmu::invslot::slotSecondary)),
|
||||
luabind::value("Finger1", static_cast<int>(EQEmu::invslot::slotFinger1)),
|
||||
luabind::value("Finger2", static_cast<int>(EQEmu::invslot::slotFinger2)),
|
||||
luabind::value("Chest", static_cast<int>(EQEmu::invslot::slotChest)),
|
||||
luabind::value("Legs", static_cast<int>(EQEmu::invslot::slotLegs)),
|
||||
luabind::value("Feet", static_cast<int>(EQEmu::invslot::slotFeet)),
|
||||
luabind::value("Waist", static_cast<int>(EQEmu::invslot::slotWaist)),
|
||||
luabind::value("PowerSource", static_cast<int>(EQEmu::invslot::slotPowerSource)),
|
||||
luabind::value("Ammo", static_cast<int>(EQEmu::invslot::slotAmmo)),
|
||||
luabind::value("General1", static_cast<int>(EQEmu::invslot::slotGeneral1)),
|
||||
luabind::value("General2", static_cast<int>(EQEmu::invslot::slotGeneral2)),
|
||||
luabind::value("General3", static_cast<int>(EQEmu::invslot::slotGeneral3)),
|
||||
luabind::value("General4", static_cast<int>(EQEmu::invslot::slotGeneral4)),
|
||||
luabind::value("General5", static_cast<int>(EQEmu::invslot::slotGeneral5)),
|
||||
luabind::value("General6", static_cast<int>(EQEmu::invslot::slotGeneral6)),
|
||||
luabind::value("General7", static_cast<int>(EQEmu::invslot::slotGeneral7)),
|
||||
luabind::value("General8", static_cast<int>(EQEmu::invslot::slotGeneral8)),
|
||||
luabind::value("General9", static_cast<int>(EQEmu::invslot::slotGeneral9)),
|
||||
luabind::value("General10", static_cast<int>(EQEmu::invslot::slotGeneral10)),
|
||||
luabind::value("Cursor", static_cast<int>(EQEmu::invslot::slotCursor)),
|
||||
luabind::value("PossessionsBegin", static_cast<int>(EQEmu::invslot::POSSESSIONS_BEGIN)),
|
||||
luabind::value("PossessionsEnd", static_cast<int>(EQEmu::invslot::POSSESSIONS_END)),
|
||||
luabind::value("EquipmentBegin", static_cast<int>(EQEmu::invslot::EQUIPMENT_BEGIN)),
|
||||
luabind::value("EquipmentEnd", static_cast<int>(EQEmu::invslot::EQUIPMENT_END)),
|
||||
luabind::value("GeneralBegin", static_cast<int>(EQEmu::invslot::GENERAL_BEGIN)),
|
||||
luabind::value("GeneralEnd", static_cast<int>(EQEmu::invslot::GENERAL_END)),
|
||||
luabind::value("GeneralBagsBegin", static_cast<int>(EQEmu::invbag::GENERAL_BAGS_BEGIN)),
|
||||
luabind::value("GeneralBagsEnd", static_cast<int>(EQEmu::invbag::GENERAL_BAGS_END)),
|
||||
luabind::value("CursorBagBegin", static_cast<int>(EQEmu::invbag::CURSOR_BAG_BEGIN)),
|
||||
luabind::value("CursorBagEnd", static_cast<int>(EQEmu::invbag::CURSOR_BAG_END)),
|
||||
luabind::value("Tradeskill", static_cast<int>(EQEmu::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE)),
|
||||
luabind::value("Augment", static_cast<int>(EQEmu::invslot::SLOT_AUGMENT_GENERIC_RETURN)), // will be revised out
|
||||
luabind::value("BankBegin", static_cast<int>(EQEmu::invslot::BANK_BEGIN)),
|
||||
luabind::value("BankEnd", static_cast<int>(EQEmu::invslot::BANK_END)),
|
||||
luabind::value("BankBagsBegin", static_cast<int>(EQEmu::invbag::BANK_BAGS_BEGIN)),
|
||||
luabind::value("BankBagsEnd", static_cast<int>(EQEmu::invbag::BANK_BAGS_END)),
|
||||
luabind::value("SharedBankBegin", static_cast<int>(EQEmu::invslot::SHARED_BANK_BEGIN)),
|
||||
luabind::value("SharedBankEnd", static_cast<int>(EQEmu::invslot::SHARED_BANK_END)),
|
||||
luabind::value("SharedBankBagsBegin", static_cast<int>(EQEmu::invbag::SHARED_BANK_BAGS_BEGIN)),
|
||||
luabind::value("SharedBankBagsEnd", static_cast<int>(EQEmu::invbag::SHARED_BANK_BAGS_END)),
|
||||
luabind::value("BagSlotBegin", static_cast<int>(EQEmu::invbag::SLOT_BEGIN)),
|
||||
luabind::value("BagSlotEnd", static_cast<int>(EQEmu::invbag::SLOT_END)),
|
||||
luabind::value("AugSocketBegin", static_cast<int>(EQEmu::invaug::SOCKET_BEGIN)),
|
||||
luabind::value("AugSocketEnd", static_cast<int>(EQEmu::invaug::SOCKET_END)),
|
||||
luabind::value("Invalid", static_cast<int>(EQEmu::invslot::SLOT_INVALID)),
|
||||
|
||||
luabind::value("Shoulder", static_cast<int>(EQEmu::invslot::slotShoulders)), // deprecated
|
||||
luabind::value("Bracer1", static_cast<int>(EQEmu::invslot::slotWrist1)), // deprecated
|
||||
luabind::value("Bracer2", static_cast<int>(EQEmu::invslot::slotWrist2)), // deprecated
|
||||
luabind::value("Ring1", static_cast<int>(EQEmu::invslot::slotFinger1)), // deprecated
|
||||
luabind::value("Ring2", static_cast<int>(EQEmu::invslot::slotFinger2)), // deprecated
|
||||
luabind::value("PersonalBegin", static_cast<int>(EQEmu::invslot::GENERAL_BEGIN)), // deprecated
|
||||
luabind::value("PersonalEnd", static_cast<int>(EQEmu::invslot::GENERAL_END)), // deprecated
|
||||
luabind::value("CursorEnd", 0xFFFE) // deprecated (not in use..and never valid vis-a-vis client behavior)
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1876,16 +1970,17 @@ luabind::scope lua_register_material() {
|
||||
luabind::value("Head", static_cast<int>(EQEmu::textures::armorHead)),
|
||||
luabind::value("Chest", static_cast<int>(EQEmu::textures::armorChest)),
|
||||
luabind::value("Arms", static_cast<int>(EQEmu::textures::armorArms)),
|
||||
luabind::value("Bracer", static_cast<int>(EQEmu::textures::armorWrist)), // deprecated
|
||||
luabind::value("Wrist", static_cast<int>(EQEmu::textures::armorWrist)),
|
||||
luabind::value("Hands", static_cast<int>(EQEmu::textures::armorHands)),
|
||||
luabind::value("Legs", static_cast<int>(EQEmu::textures::armorLegs)),
|
||||
luabind::value("Feet", static_cast<int>(EQEmu::textures::armorFeet)),
|
||||
luabind::value("Primary", static_cast<int>(EQEmu::textures::weaponPrimary)),
|
||||
luabind::value("Secondary", static_cast<int>(EQEmu::textures::weaponSecondary)),
|
||||
luabind::value("Max", static_cast<int>(EQEmu::textures::materialCount)), // deprecated
|
||||
luabind::value("Count", static_cast<int>(EQEmu::textures::materialCount)),
|
||||
luabind::value("Invalid", static_cast<int>(EQEmu::textures::materialInvalid))
|
||||
luabind::value("Invalid", static_cast<int>(EQEmu::textures::materialInvalid)),
|
||||
|
||||
luabind::value("Bracer", static_cast<int>(EQEmu::textures::armorWrist)), // deprecated
|
||||
luabind::value("Max", static_cast<int>(EQEmu::textures::materialCount)) // deprecated
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -38,10 +38,10 @@ int Lua_Inventory::PushCursor(Lua_ItemInst item) {
|
||||
return self->PushCursor(*inst);
|
||||
}
|
||||
|
||||
bool Lua_Inventory::SwapItem(int slot_a, int slot_b) {
|
||||
bool Lua_Inventory::SwapItem(int source_slot, int destination_slot) {
|
||||
Lua_Safe_Call_Bool();
|
||||
EQEmu::InventoryProfile::SwapItemFailState fail_state = EQEmu::InventoryProfile::swapInvalid;
|
||||
return self->SwapItem(slot_a, slot_b, fail_state);
|
||||
return self->SwapItem(source_slot, destination_slot, fail_state);
|
||||
}
|
||||
|
||||
bool Lua_Inventory::DeleteItem(int slot_id) {
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
Lua_ItemInst GetItem(int slot_id, int bag_slot);
|
||||
int PutItem(int slot_id, Lua_ItemInst item);
|
||||
int PushCursor(Lua_ItemInst item);
|
||||
bool SwapItem(int slot_a, int slot_b);
|
||||
bool SwapItem(int source_slot, int destination_slot);
|
||||
bool DeleteItem(int slot_id);
|
||||
bool DeleteItem(int slot_id, int quantity);
|
||||
bool CheckNoDrop(int slot_id);
|
||||
|
||||
+150
-31
@@ -267,6 +267,11 @@ void Lua_Mob::ChangeSize(double in_size, bool no_restriction) {
|
||||
self->ChangeSize(static_cast<float>(in_size), no_restriction);
|
||||
}
|
||||
|
||||
void Lua_Mob::RandomizeFeatures(bool send_illusion, bool save_variables) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->RandomizeFeatures(send_illusion, save_variables);
|
||||
}
|
||||
|
||||
void Lua_Mob::GMMove(double x, double y, double z) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->GMMove(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
|
||||
@@ -282,6 +287,16 @@ void Lua_Mob::GMMove(double x, double y, double z, double heading, bool send_upd
|
||||
self->GMMove(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(heading), send_update);
|
||||
}
|
||||
|
||||
void Lua_Mob::TryMoveAlong(float distance, float angle) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->TryMoveAlong(distance, angle);
|
||||
}
|
||||
|
||||
void Lua_Mob::TryMoveAlong(float distance, float angle, bool send) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->TryMoveAlong(distance, angle, send);
|
||||
}
|
||||
|
||||
bool Lua_Mob::HasProcs() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->HasProcs();
|
||||
@@ -307,6 +322,16 @@ bool Lua_Mob::FindBuff(int spell_id) {
|
||||
return self->FindBuff(spell_id);
|
||||
}
|
||||
|
||||
uint16 Lua_Mob::FindBuffBySlot(int slot) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->FindBuffBySlot(slot);
|
||||
}
|
||||
|
||||
uint32 Lua_Mob::BuffCount() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->BuffCount();
|
||||
}
|
||||
|
||||
bool Lua_Mob::FindType(int type) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->FindType(type);
|
||||
@@ -760,28 +785,28 @@ bool Lua_Mob::CastSpell(int spell_id, int target_id) {
|
||||
|
||||
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot));
|
||||
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::spells::CastingSlot>(slot));
|
||||
}
|
||||
|
||||
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot), cast_time);
|
||||
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::spells::CastingSlot>(slot), cast_time);
|
||||
}
|
||||
|
||||
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot), cast_time, mana_cost);
|
||||
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::spells::CastingSlot>(slot), cast_time, mana_cost);
|
||||
}
|
||||
|
||||
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot), cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot));
|
||||
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::spells::CastingSlot>(slot), cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot));
|
||||
}
|
||||
|
||||
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot, int timer,
|
||||
int timer_duration) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot), cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot),
|
||||
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::spells::CastingSlot>(slot), cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot),
|
||||
static_cast<uint32>(timer), static_cast<uint32>(timer_duration));
|
||||
}
|
||||
|
||||
@@ -790,7 +815,7 @@ bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, in
|
||||
Lua_Safe_Call_Bool();
|
||||
int16 res = resist_adjust;
|
||||
|
||||
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::CastingSlot>(slot), cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot),
|
||||
return self->CastSpell(spell_id, target_id, static_cast<EQEmu::spells::CastingSlot>(slot), cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot),
|
||||
static_cast<uint32>(timer), static_cast<uint32>(timer_duration), &res);
|
||||
}
|
||||
|
||||
@@ -801,27 +826,27 @@ bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target) {
|
||||
|
||||
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->SpellFinished(spell_id, target, static_cast<EQEmu::CastingSlot>(slot));
|
||||
return self->SpellFinished(spell_id, target, static_cast<EQEmu::spells::CastingSlot>(slot));
|
||||
}
|
||||
|
||||
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->SpellFinished(spell_id, target, static_cast<EQEmu::CastingSlot>(slot), mana_used);
|
||||
return self->SpellFinished(spell_id, target, static_cast<EQEmu::spells::CastingSlot>(slot), mana_used);
|
||||
}
|
||||
|
||||
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used, uint32 inventory_slot) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->SpellFinished(spell_id, target, static_cast<EQEmu::CastingSlot>(slot), mana_used, inventory_slot);
|
||||
return self->SpellFinished(spell_id, target, static_cast<EQEmu::spells::CastingSlot>(slot), mana_used, inventory_slot);
|
||||
}
|
||||
|
||||
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used, uint32 inventory_slot, int resist_adjust) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->SpellFinished(spell_id, target, static_cast<EQEmu::CastingSlot>(slot), mana_used, inventory_slot, resist_adjust);
|
||||
return self->SpellFinished(spell_id, target, static_cast<EQEmu::spells::CastingSlot>(slot), mana_used, inventory_slot, resist_adjust);
|
||||
}
|
||||
|
||||
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used, uint32 inventory_slot, int resist_adjust, bool proc) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->SpellFinished(spell_id, target, static_cast<EQEmu::CastingSlot>(slot), mana_used, inventory_slot, resist_adjust, proc);
|
||||
return self->SpellFinished(spell_id, target, static_cast<EQEmu::spells::CastingSlot>(slot), mana_used, inventory_slot, resist_adjust, proc);
|
||||
}
|
||||
|
||||
void Lua_Mob::SendBeginCast(int spell_id, int cast_time) {
|
||||
@@ -1114,26 +1139,24 @@ double Lua_Mob::CalculateHeadingToTarget(double in_x, double in_y) {
|
||||
return self->CalculateHeadingToTarget(static_cast<float>(in_x), static_cast<float>(in_y));
|
||||
}
|
||||
|
||||
bool Lua_Mob::CalculateNewPosition(double x, double y, double z, double speed) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->CalculateNewPosition(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(speed));
|
||||
void Lua_Mob::RunTo(double x, double y, double z) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->RunTo(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
|
||||
}
|
||||
|
||||
bool Lua_Mob::CalculateNewPosition(double x, double y, double z, double speed, bool check_z) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->CalculateNewPosition(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(speed),
|
||||
check_z);
|
||||
void Lua_Mob::WalkTo(double x, double y, double z) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->WalkTo(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
|
||||
}
|
||||
|
||||
bool Lua_Mob::CalculateNewPosition2(double x, double y, double z, double speed) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->CalculateNewPosition2(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(speed));
|
||||
void Lua_Mob::NavigateTo(double x, double y, double z) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->NavigateTo(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
|
||||
}
|
||||
|
||||
bool Lua_Mob::CalculateNewPosition2(double x, double y, double z, double speed, bool check_z) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->CalculateNewPosition2(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(speed),
|
||||
check_z);
|
||||
void Lua_Mob::StopNavigation() {
|
||||
Lua_Safe_Call_Void();
|
||||
self->StopNavigation();
|
||||
}
|
||||
|
||||
float Lua_Mob::CalculateDistance(double x, double y, double z) {
|
||||
@@ -1431,7 +1454,7 @@ void Lua_Mob::SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uin
|
||||
|
||||
void Lua_Mob::SetFlyMode(int in) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetFlyMode(in);
|
||||
self->SetFlyMode(static_cast<GravityBehavior>(in));
|
||||
}
|
||||
|
||||
void Lua_Mob::SetTexture(int in) {
|
||||
@@ -1605,6 +1628,76 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) {
|
||||
beard, aa_title, drakkin_heritage, drakkin_tattoo, drakkin_details, size);
|
||||
}
|
||||
|
||||
void Lua_Mob::ChangeRace(int in) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ChangeRace(in);
|
||||
}
|
||||
|
||||
void Lua_Mob::ChangeGender(int in) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ChangeGender(in);
|
||||
}
|
||||
|
||||
void Lua_Mob::ChangeTexture(int in) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ChangeTexture(in);
|
||||
}
|
||||
|
||||
void Lua_Mob::ChangeHelmTexture(int in) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ChangeHelmTexture(in);
|
||||
}
|
||||
|
||||
void Lua_Mob::ChangeHairColor(int in) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ChangeHairColor(in);
|
||||
}
|
||||
|
||||
void Lua_Mob::ChangeBeardColor(int in) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ChangeBeardColor(in);
|
||||
}
|
||||
|
||||
void Lua_Mob::ChangeEyeColor1(int in) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ChangeEyeColor1(in);
|
||||
}
|
||||
|
||||
void Lua_Mob::ChangeEyeColor2(int in) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ChangeEyeColor2(in);
|
||||
}
|
||||
|
||||
void Lua_Mob::ChangeHairStyle(int in) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ChangeHairStyle(in);
|
||||
}
|
||||
|
||||
void Lua_Mob::ChangeLuclinFace(int in) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ChangeLuclinFace(in);
|
||||
}
|
||||
|
||||
void Lua_Mob::ChangeBeard(int in) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ChangeBeard(in);
|
||||
}
|
||||
|
||||
void Lua_Mob::ChangeDrakkinHeritage(int in) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ChangeDrakkinHeritage(in);
|
||||
}
|
||||
|
||||
void Lua_Mob::ChangeDrakkinTattoo(int in) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ChangeDrakkinTattoo(in);
|
||||
}
|
||||
|
||||
void Lua_Mob::ChangeDrakkinDetails(int in) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ChangeDrakkinDetails(in);
|
||||
}
|
||||
|
||||
void Lua_Mob::CameraEffect(uint32 duration, uint32 intensity) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->CameraEffect(duration, intensity);
|
||||
@@ -2008,6 +2101,11 @@ int Lua_Mob::GetWeaponDamageBonus(Lua_Item weapon, bool offhand) {
|
||||
return self->GetWeaponDamageBonus(weapon, offhand);
|
||||
}
|
||||
|
||||
int Lua_Mob::GetItemStat(uint32 itemid, const char* identifier) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetItemStat(itemid, identifier);
|
||||
}
|
||||
|
||||
Lua_StatBonuses Lua_Mob::GetItemBonuses()
|
||||
{
|
||||
Lua_Safe_Call_Class(Lua_StatBonuses);
|
||||
@@ -2124,14 +2222,19 @@ luabind::scope lua_register_mob() {
|
||||
.def("DoAnim", (void(Lua_Mob::*)(int,int,bool,int))&Lua_Mob::DoAnim)
|
||||
.def("ChangeSize", (void(Lua_Mob::*)(double))&Lua_Mob::ChangeSize)
|
||||
.def("ChangeSize", (void(Lua_Mob::*)(double,bool))&Lua_Mob::ChangeSize)
|
||||
.def("RandomizeFeatures", (void(Lua_Mob::*)(bool,bool))&Lua_Mob::RandomizeFeatures)
|
||||
.def("GMMove", (void(Lua_Mob::*)(double,double,double))&Lua_Mob::GMMove)
|
||||
.def("GMMove", (void(Lua_Mob::*)(double,double,double,double))&Lua_Mob::GMMove)
|
||||
.def("GMMove", (void(Lua_Mob::*)(double,double,double,double,bool))&Lua_Mob::GMMove)
|
||||
.def("TryMoveAlong", (void(Lua_Mob::*)(float,float))&Lua_Mob::TryMoveAlong)
|
||||
.def("TryMoveAlong", (void(Lua_Mob::*)(float,float,bool))&Lua_Mob::TryMoveAlong)
|
||||
.def("HasProcs", &Lua_Mob::HasProcs)
|
||||
.def("IsInvisible", (bool(Lua_Mob::*)(void))&Lua_Mob::IsInvisible)
|
||||
.def("IsInvisible", (bool(Lua_Mob::*)(Lua_Mob))&Lua_Mob::IsInvisible)
|
||||
.def("SetInvisible", &Lua_Mob::SetInvisible)
|
||||
.def("FindBuff", &Lua_Mob::FindBuff)
|
||||
.def("FindBuffBySlot", (uint16(Lua_Mob::*)(int))&Lua_Mob::FindBuffBySlot)
|
||||
.def("BuffCount", &Lua_Mob::BuffCount)
|
||||
.def("FindType", (bool(Lua_Mob::*)(int))&Lua_Mob::FindType)
|
||||
.def("FindType", (bool(Lua_Mob::*)(int,bool))&Lua_Mob::FindType)
|
||||
.def("FindType", (bool(Lua_Mob::*)(int,bool,int))&Lua_Mob::FindType)
|
||||
@@ -2162,6 +2265,7 @@ luabind::scope lua_register_mob() {
|
||||
.def("IsWarriorClass", &Lua_Mob::IsWarriorClass)
|
||||
.def("GetHP", &Lua_Mob::GetHP)
|
||||
.def("GetMaxHP", &Lua_Mob::GetMaxHP)
|
||||
.def("GetItemStat", (int(Lua_Mob::*)(uint32,const char*))&Lua_Mob::GetItemStat)
|
||||
.def("GetItemHPBonuses", &Lua_Mob::GetItemHPBonuses)
|
||||
.def("GetSpellHPBonuses", &Lua_Mob::GetSpellHPBonuses)
|
||||
.def("GetWalkspeed", &Lua_Mob::GetWalkspeed)
|
||||
@@ -2290,10 +2394,10 @@ luabind::scope lua_register_mob() {
|
||||
.def("FaceTarget", (void(Lua_Mob::*)(Lua_Mob))&Lua_Mob::FaceTarget)
|
||||
.def("SetHeading", (void(Lua_Mob::*)(double))&Lua_Mob::SetHeading)
|
||||
.def("CalculateHeadingToTarget", (double(Lua_Mob::*)(double,double))&Lua_Mob::CalculateHeadingToTarget)
|
||||
.def("CalculateNewPosition", (bool(Lua_Mob::*)(double,double,double,double))&Lua_Mob::CalculateNewPosition)
|
||||
.def("CalculateNewPosition", (bool(Lua_Mob::*)(double,double,double,double,bool))&Lua_Mob::CalculateNewPosition)
|
||||
.def("CalculateNewPosition2", (bool(Lua_Mob::*)(double,double,double,double))&Lua_Mob::CalculateNewPosition2)
|
||||
.def("CalculateNewPosition2", (bool(Lua_Mob::*)(double,double,double,double,bool))&Lua_Mob::CalculateNewPosition2)
|
||||
.def("RunTo", (void(Lua_Mob::*)(double, double, double))&Lua_Mob::RunTo)
|
||||
.def("WalkTo", (void(Lua_Mob::*)(double, double, double))&Lua_Mob::WalkTo)
|
||||
.def("NavigateTo", (void(Lua_Mob::*)(double,double,double))&Lua_Mob::NavigateTo)
|
||||
.def("StopNavigation", (void(Lua_Mob::*)(void))&Lua_Mob::StopNavigation)
|
||||
.def("CalculateDistance", (float(Lua_Mob::*)(double,double,double))&Lua_Mob::CalculateDistance)
|
||||
.def("SendTo", (void(Lua_Mob::*)(double,double,double))&Lua_Mob::SendTo)
|
||||
.def("SendToFixZ", (void(Lua_Mob::*)(double,double,double))&Lua_Mob::SendToFixZ)
|
||||
@@ -2356,6 +2460,20 @@ luabind::scope lua_register_mob() {
|
||||
.def("SetRace", (void(Lua_Mob::*)(int))&Lua_Mob::SetRace)
|
||||
.def("SetGender", (void(Lua_Mob::*)(int))&Lua_Mob::SetGender)
|
||||
.def("SendIllusionPacket", (void(Lua_Mob::*)(luabind::adl::object))&Lua_Mob::SendIllusionPacket)
|
||||
.def("ChangeRace", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeRace)
|
||||
.def("ChangeGender", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeGender)
|
||||
.def("ChangeTexture", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeTexture)
|
||||
.def("ChangeHelmTexture", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeHelmTexture)
|
||||
.def("ChangeHairColor", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeHairColor)
|
||||
.def("ChangeBeardColor", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeBeardColor)
|
||||
.def("ChangeEyeColor1", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeEyeColor1)
|
||||
.def("ChangeEyeColor2", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeEyeColor2)
|
||||
.def("ChangeHairStyle", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeHairStyle)
|
||||
.def("ChangeLuclinFace", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeLuclinFace)
|
||||
.def("ChangeBeard", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeBeard)
|
||||
.def("ChangeDrakkinHeritage", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeDrakkinHeritage)
|
||||
.def("ChangeDrakkinTattoo", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeDrakkinTattoo)
|
||||
.def("ChangeDrakkinDetails", (void(Lua_Mob::*)(int))&Lua_Mob::ChangeDrakkinDetails)
|
||||
.def("CameraEffect", (void(Lua_Mob::*)(uint32,uint32))&Lua_Mob::CameraEffect)
|
||||
.def("CameraEffect", (void(Lua_Mob::*)(uint32,uint32,Lua_Client))&Lua_Mob::CameraEffect)
|
||||
.def("CameraEffect", (void(Lua_Mob::*)(uint32,uint32,Lua_Client,bool))&Lua_Mob::CameraEffect)
|
||||
@@ -2499,7 +2617,8 @@ luabind::scope lua_register_special_abilities() {
|
||||
luabind::value("allow_to_tank", static_cast<int>(ALLOW_TO_TANK)),
|
||||
luabind::value("ignore_root_aggro_rules", static_cast<int>(IGNORE_ROOT_AGGRO_RULES)),
|
||||
luabind::value("casting_resist_diff", static_cast<int>(CASTING_RESIST_DIFF)),
|
||||
luabind::value("counter_avoid_damage", static_cast<int>(COUNTER_AVOID_DAMAGE))
|
||||
luabind::value("counter_avoid_damage", static_cast<int>(COUNTER_AVOID_DAMAGE)),
|
||||
luabind::value("immune_ranged_attacks", static_cast<int>(IMMUNE_RANGED_ATTACKS))
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
+24
-4
@@ -71,14 +71,19 @@ public:
|
||||
void DoAnim(int anim_num, int type, bool ackreq, int filter);
|
||||
void ChangeSize(double in_size);
|
||||
void ChangeSize(double in_size, bool no_restriction);
|
||||
void RandomizeFeatures(bool send_illusion, bool save_variables);
|
||||
void GMMove(double x, double y, double z);
|
||||
void GMMove(double x, double y, double z, double heading);
|
||||
void GMMove(double x, double y, double z, double heading, bool send_update);
|
||||
void TryMoveAlong(float distance, float heading);
|
||||
void TryMoveAlong(float distance, float heading, bool send);
|
||||
bool HasProcs();
|
||||
bool IsInvisible();
|
||||
bool IsInvisible(Lua_Mob other);
|
||||
void SetInvisible(int state);
|
||||
bool FindBuff(int spell_id);
|
||||
uint16 FindBuffBySlot(int slot);
|
||||
uint32 BuffCount();
|
||||
bool FindType(int type);
|
||||
bool FindType(int type, bool offensive);
|
||||
bool FindType(int type, bool offensive, int threshold);
|
||||
@@ -238,10 +243,10 @@ public:
|
||||
void FaceTarget(Lua_Mob target);
|
||||
void SetHeading(double in);
|
||||
double CalculateHeadingToTarget(double in_x, double in_y);
|
||||
bool CalculateNewPosition(double x, double y, double z, double speed);
|
||||
bool CalculateNewPosition(double x, double y, double z, double speed, bool check_z);
|
||||
bool CalculateNewPosition2(double x, double y, double z, double speed);
|
||||
bool CalculateNewPosition2(double x, double y, double z, double speed, bool check_z);
|
||||
void RunTo(double x, double y, double z);
|
||||
void WalkTo(double x, double y, double z);
|
||||
void NavigateTo(double x, double y, double z);
|
||||
void StopNavigation();
|
||||
float CalculateDistance(double x, double y, double z);
|
||||
void SendTo(double x, double y, double z);
|
||||
void SendToFixZ(double x, double y, double z);
|
||||
@@ -304,6 +309,20 @@ public:
|
||||
void SetRace(int in);
|
||||
void SetGender(int in);
|
||||
void SendIllusionPacket(luabind::adl::object illusion);
|
||||
void ChangeRace(int in);
|
||||
void ChangeGender(int in);
|
||||
void ChangeTexture(int in);
|
||||
void ChangeHelmTexture(int in);
|
||||
void ChangeHairColor(int in);
|
||||
void ChangeBeardColor(int in);
|
||||
void ChangeEyeColor1(int in);
|
||||
void ChangeEyeColor2(int in);
|
||||
void ChangeHairStyle(int in);
|
||||
void ChangeLuclinFace(int in);
|
||||
void ChangeBeard(int in);
|
||||
void ChangeDrakkinHeritage(int in);
|
||||
void ChangeDrakkinTattoo(int in);
|
||||
void ChangeDrakkinDetails(int in);
|
||||
void CameraEffect(uint32 duration, uint32 intensity);
|
||||
void CameraEffect(uint32 duration, uint32 intensity, Lua_Client c);
|
||||
void CameraEffect(uint32 duration, uint32 intensity, Lua_Client c, bool global);
|
||||
@@ -385,6 +404,7 @@ public:
|
||||
bool IsAmnesiad();
|
||||
int32 GetMeleeMitigation();
|
||||
int GetWeaponDamageBonus(Lua_Item weapon, bool offhand);
|
||||
int GetItemStat(uint32 itemid, const char* identifier);
|
||||
Lua_StatBonuses GetItemBonuses();
|
||||
Lua_StatBonuses GetSpellBonuses();
|
||||
Lua_StatBonuses GetAABonuses();
|
||||
|
||||
+47
-22
@@ -308,14 +308,9 @@ void Lua_NPC::NextGuardPosition() {
|
||||
self->NextGuardPosition();
|
||||
}
|
||||
|
||||
void Lua_NPC::SaveGuardSpot() {
|
||||
void Lua_NPC::SaveGuardSpot(float x, float y, float z, float heading) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SaveGuardSpot();
|
||||
}
|
||||
|
||||
void Lua_NPC::SaveGuardSpot(bool clear) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SaveGuardSpot(clear);
|
||||
self->SaveGuardSpot(glm::vec4(x, y, z, heading));
|
||||
}
|
||||
|
||||
bool Lua_NPC::IsGuarding() {
|
||||
@@ -333,6 +328,36 @@ void Lua_NPC::AI_SetRoambox(float dist, float max_x, float min_x, float max_y, f
|
||||
self->AI_SetRoambox(dist, max_x, min_x, max_y, min_y, delay, mindelay);
|
||||
}
|
||||
|
||||
void Lua_NPC::SetFollowID(int id) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetFollowID(id);
|
||||
}
|
||||
|
||||
void Lua_NPC::SetFollowDistance(int dist) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetFollowDistance(dist);
|
||||
}
|
||||
|
||||
void Lua_NPC::SetFollowCanRun(bool v) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetFollowCanRun(v);
|
||||
}
|
||||
|
||||
int Lua_NPC::GetFollowID() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetFollowID();
|
||||
}
|
||||
|
||||
int Lua_NPC::GetFollowDistance() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetFollowDistance();
|
||||
}
|
||||
|
||||
bool Lua_NPC::GetFollowCanRun() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->GetFollowCanRun();
|
||||
}
|
||||
|
||||
int Lua_NPC::GetNPCSpellsID() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetNPCSpellsID();
|
||||
@@ -420,7 +445,12 @@ void Lua_NPC::ModifyNPCStat(const char *stat, const char *value) {
|
||||
|
||||
void Lua_NPC::AddAISpell(int priority, int spell_id, int type, int mana_cost, int recast_delay, int resist_adjust) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->AddSpellToNPCList(priority, spell_id, type, mana_cost, recast_delay, resist_adjust);
|
||||
self->AddSpellToNPCList(priority, spell_id, type, mana_cost, recast_delay, resist_adjust, 0, 0);
|
||||
}
|
||||
|
||||
void Lua_NPC::AddAISpell(int priority, int spell_id, int type, int mana_cost, int recast_delay, int resist_adjust, int min_hp, int max_hp) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->AddSpellToNPCList(priority, spell_id, type, mana_cost, recast_delay, resist_adjust, min_hp, max_hp);
|
||||
}
|
||||
|
||||
void Lua_NPC::RemoveAISpell(int spell_id) {
|
||||
@@ -488,16 +518,6 @@ void Lua_NPC::MerchantCloseShop() {
|
||||
self->MerchantCloseShop();
|
||||
}
|
||||
|
||||
void Lua_NPC::SetMerchantProbability(uint8 amt) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetMerchantProbability(amt);
|
||||
}
|
||||
|
||||
uint8 Lua_NPC::GetMerchantProbability() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetMerchantProbability();
|
||||
}
|
||||
|
||||
int Lua_NPC::GetRawAC() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetRawAC();
|
||||
@@ -572,11 +592,17 @@ luabind::scope lua_register_npc() {
|
||||
.def("PauseWandering", (void(Lua_NPC::*)(int))&Lua_NPC::PauseWandering)
|
||||
.def("MoveTo", (void(Lua_NPC::*)(float,float,float,float,bool))&Lua_NPC::MoveTo)
|
||||
.def("NextGuardPosition", (void(Lua_NPC::*)(void))&Lua_NPC::NextGuardPosition)
|
||||
.def("SaveGuardSpot", (void(Lua_NPC::*)(void))&Lua_NPC::SaveGuardSpot)
|
||||
.def("SaveGuardSpot", (void(Lua_NPC::*)(bool))&Lua_NPC::SaveGuardSpot)
|
||||
.def("SaveGuardSpot", (void(Lua_NPC::*)(float,float,float,float))&Lua_NPC::SaveGuardSpot)
|
||||
.def("IsGuarding", (bool(Lua_NPC::*)(void))&Lua_NPC::IsGuarding)
|
||||
.def("AI_SetRoambox", (void(Lua_NPC::*)(float,float,float,float,float))&Lua_NPC::AI_SetRoambox)
|
||||
.def("AI_SetRoambox", (void(Lua_NPC::*)(float,float,float,float,float,uint32,uint32))&Lua_NPC::AI_SetRoambox)
|
||||
.def("SetFollowID", (void(Lua_NPC::*)(int))&Lua_NPC::SetFollowID)
|
||||
.def("SetFollowDistance", (void(Lua_NPC::*)(int))&Lua_NPC::SetFollowDistance)
|
||||
.def("SetFollowCanRun", (void(Lua_NPC::*)(bool))&Lua_NPC::SetFollowCanRun)
|
||||
.def("GetFollowID", (int(Lua_NPC::*)(void))&Lua_NPC::GetFollowID)
|
||||
.def("GetFollowDistance", (int(Lua_NPC::*)(void))&Lua_NPC::GetFollowDistance)
|
||||
.def("GetFollowCanRun", (bool(Lua_NPC::*)(void))&Lua_NPC::GetFollowCanRun)
|
||||
.def("GetNPCSpellsID", (int(Lua_NPC::*)(void))&Lua_NPC::GetNPCSpellsID)
|
||||
.def("GetNPCSpellsID", (int(Lua_NPC::*)(void))&Lua_NPC::GetNPCSpellsID)
|
||||
.def("GetSpawnPointID", (int(Lua_NPC::*)(void))&Lua_NPC::GetSpawnPointID)
|
||||
.def("GetSpawnPointX", (float(Lua_NPC::*)(void))&Lua_NPC::GetSpawnPointX)
|
||||
@@ -595,6 +621,7 @@ luabind::scope lua_register_npc() {
|
||||
.def("SetSwarmTarget", (void(Lua_NPC::*)(int))&Lua_NPC::SetSwarmTarget)
|
||||
.def("ModifyNPCStat", (void(Lua_NPC::*)(const char*,const char*))&Lua_NPC::ModifyNPCStat)
|
||||
.def("AddAISpell", (void(Lua_NPC::*)(int,int,int,int,int,int))&Lua_NPC::AddAISpell)
|
||||
.def("AddAISpell", (void(Lua_NPC::*)(int,int,int,int,int,int,int,int))&Lua_NPC::AddAISpell)
|
||||
.def("RemoveAISpell", (void(Lua_NPC::*)(int))&Lua_NPC::RemoveAISpell)
|
||||
.def("SetSpellFocusDMG", (void(Lua_NPC::*)(int))&Lua_NPC::SetSpellFocusDMG)
|
||||
.def("SetSpellFocusHeal", (void(Lua_NPC::*)(int))&Lua_NPC::SetSpellFocusHeal)
|
||||
@@ -608,8 +635,6 @@ luabind::scope lua_register_npc() {
|
||||
.def("GetScore", (int(Lua_NPC::*)(void))&Lua_NPC::GetScore)
|
||||
.def("MerchantOpenShop", (void(Lua_NPC::*)(void))&Lua_NPC::MerchantOpenShop)
|
||||
.def("MerchantCloseShop", (void(Lua_NPC::*)(void))&Lua_NPC::MerchantCloseShop)
|
||||
.def("SetMerchantProbability", (void(Lua_NPC::*)(void))&Lua_NPC::SetMerchantProbability)
|
||||
.def("GetMerchantProbability", (uint8(Lua_NPC::*)(void))&Lua_NPC::GetMerchantProbability)
|
||||
.def("GetRawAC", (int(Lua_NPC::*)(void))&Lua_NPC::GetRawAC)
|
||||
.def("GetAvoidanceRating", &Lua_NPC::GetAvoidanceRating);
|
||||
}
|
||||
|
||||
+8
-4
@@ -87,11 +87,16 @@ public:
|
||||
void PauseWandering(int pause_time);
|
||||
void MoveTo(float x, float y, float z, float h, bool save);
|
||||
void NextGuardPosition();
|
||||
void SaveGuardSpot();
|
||||
void SaveGuardSpot(bool clear);
|
||||
void SaveGuardSpot(float x, float y, float z, float heading);
|
||||
bool IsGuarding();
|
||||
void AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y);
|
||||
void AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y, uint32 delay, uint32 mindelay);
|
||||
void SetFollowID(int id);
|
||||
void SetFollowDistance(int dist);
|
||||
void SetFollowCanRun(bool v);
|
||||
int GetFollowID();
|
||||
int GetFollowDistance();
|
||||
bool GetFollowCanRun();
|
||||
int GetNPCSpellsID();
|
||||
int GetSpawnPointID();
|
||||
float GetSpawnPointX();
|
||||
@@ -110,6 +115,7 @@ public:
|
||||
void SetSwarmTarget(int target);
|
||||
void ModifyNPCStat(const char *stat, const char *value);
|
||||
void AddAISpell(int priority, int spell_id, int type, int mana_cost, int recast_delay, int resist_adjust);
|
||||
void AddAISpell(int priority, int spell_id, int type, int mana_cost, int recast_delay, int resist_adjust, int min_hp, int max_hp);
|
||||
void RemoveAISpell(int spell_id);
|
||||
void SetSpellFocusDMG(int focus);
|
||||
void SetSpellFocusHeal(int focus);
|
||||
@@ -123,8 +129,6 @@ public:
|
||||
int GetScore();
|
||||
void MerchantOpenShop();
|
||||
void MerchantCloseShop();
|
||||
void SetMerchantProbability(uint8 amt);
|
||||
uint8 GetMerchantProbability();
|
||||
int GetRawAC();
|
||||
int GetAvoidanceRating();
|
||||
};
|
||||
|
||||
+16
-4
@@ -32,12 +32,12 @@ int Lua_Raid::RaidCount() {
|
||||
return self->RaidCount();
|
||||
}
|
||||
|
||||
uint32 Lua_Raid::GetGroup(const char *c) {
|
||||
int Lua_Raid::GetGroup(const char *c) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetGroup(c);
|
||||
}
|
||||
|
||||
uint32 Lua_Raid::GetGroup(Lua_Client c) {
|
||||
int Lua_Raid::GetGroup(Lua_Client c) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetGroup(c);
|
||||
}
|
||||
@@ -122,6 +122,16 @@ Lua_Client Lua_Raid::GetMember(int index) {
|
||||
return self->members[index].member;
|
||||
}
|
||||
|
||||
int Lua_Raid::GetGroupNumber(int index) {
|
||||
Lua_Safe_Call_Int();
|
||||
|
||||
if(index >= 72 || index < 0 || self->members[index].GroupNumber == RAID_GROUPLESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return self->members[index].GroupNumber;
|
||||
}
|
||||
|
||||
|
||||
luabind::scope lua_register_raid() {
|
||||
return luabind::class_<Lua_Raid>("Raid")
|
||||
@@ -132,7 +142,8 @@ luabind::scope lua_register_raid() {
|
||||
.def("CastGroupSpell", (void(Lua_Raid::*)(Lua_Mob,int,uint32))&Lua_Raid::CastGroupSpell)
|
||||
.def("GroupCount", (int(Lua_Raid::*)(uint32))&Lua_Raid::GroupCount)
|
||||
.def("RaidCount", (int(Lua_Raid::*)(void))&Lua_Raid::RaidCount)
|
||||
.def("GetGroup", (uint32(Lua_Raid::*)(const char*))&Lua_Raid::GetGroup)
|
||||
.def("GetGroup", (int(Lua_Raid::*)(const char*))&Lua_Raid::GetGroup)
|
||||
.def("GetGroup", (int(Lua_Raid::*)(Lua_Client))&Lua_Raid::GetGroup)
|
||||
.def("SplitExp", (void(Lua_Raid::*)(uint32,Lua_Mob))&Lua_Raid::SplitExp)
|
||||
.def("GetTotalRaidDamage", (uint32(Lua_Raid::*)(Lua_Mob))&Lua_Raid::GetTotalRaidDamage)
|
||||
.def("SplitMoney", (void(Lua_Raid::*)(uint32,uint32,uint32,uint32))&Lua_Raid::SplitMoney)
|
||||
@@ -146,7 +157,8 @@ luabind::scope lua_register_raid() {
|
||||
.def("TeleportGroup", (int(Lua_Raid::*)(Lua_Mob,uint32,uint32,float,float,float,float,uint32))&Lua_Raid::TeleportGroup)
|
||||
.def("TeleportRaid", (int(Lua_Raid::*)(Lua_Mob,uint32,uint32,float,float,float,float))&Lua_Raid::TeleportRaid)
|
||||
.def("GetID", (int(Lua_Raid::*)(void))&Lua_Raid::GetID)
|
||||
.def("GetMember", (Lua_Client(Lua_Raid::*)(int))&Lua_Raid::GetMember);
|
||||
.def("GetMember", (Lua_Client(Lua_Raid::*)(int))&Lua_Raid::GetMember)
|
||||
.def("GetGroupNumber", (int(Lua_Raid::*)(int))&Lua_Raid::GetGroupNumber);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+3
-2
@@ -30,8 +30,8 @@ public:
|
||||
void CastGroupSpell(Lua_Mob caster, int spell_id, uint32 group_id);
|
||||
int GroupCount(uint32 group_id);
|
||||
int RaidCount();
|
||||
uint32 GetGroup(const char *c);
|
||||
uint32 GetGroup(Lua_Client c);
|
||||
int GetGroup(const char *c);
|
||||
int GetGroup(Lua_Client c);
|
||||
void SplitExp(uint32 exp, Lua_Mob other);
|
||||
uint32 GetTotalRaidDamage(Lua_Mob other);
|
||||
void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum);
|
||||
@@ -47,6 +47,7 @@ public:
|
||||
void TeleportRaid(Lua_Mob sender, uint32 zone_id, uint32 instance_id, float x, float y, float z, float h);
|
||||
int GetID();
|
||||
Lua_Client GetMember(int index);
|
||||
int GetGroupNumber(int index);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+15
-82
@@ -1,5 +1,6 @@
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/compression.h"
|
||||
|
||||
#include "map.h"
|
||||
#include "raycast_mesh.h"
|
||||
@@ -10,83 +11,6 @@
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <zlib.h>
|
||||
|
||||
|
||||
uint32 EstimateDeflateBuffer(uint32_t len) {
|
||||
z_stream zstream;
|
||||
memset(&zstream, 0, sizeof(zstream));
|
||||
|
||||
zstream.zalloc = Z_NULL;
|
||||
zstream.zfree = Z_NULL;
|
||||
zstream.opaque = Z_NULL;
|
||||
if (deflateInit(&zstream, Z_FINISH) != Z_OK)
|
||||
return 0;
|
||||
|
||||
return deflateBound(&zstream, len);
|
||||
}
|
||||
|
||||
uint32_t DeflateData(const char *buffer, uint32_t len, char *out_buffer, uint32_t out_len_max) {
|
||||
z_stream zstream;
|
||||
memset(&zstream, 0, sizeof(zstream));
|
||||
int zerror;
|
||||
|
||||
zstream.next_in = const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(buffer));
|
||||
zstream.avail_in = len;
|
||||
zstream.zalloc = Z_NULL;
|
||||
zstream.zfree = Z_NULL;
|
||||
zstream.opaque = Z_NULL;
|
||||
deflateInit(&zstream, Z_FINISH);
|
||||
|
||||
zstream.next_out = reinterpret_cast<unsigned char*>(out_buffer);
|
||||
zstream.avail_out = out_len_max;
|
||||
zerror = deflate(&zstream, Z_FINISH);
|
||||
|
||||
if (zerror == Z_STREAM_END)
|
||||
{
|
||||
deflateEnd(&zstream);
|
||||
return (uint32_t)zstream.total_out;
|
||||
}
|
||||
else
|
||||
{
|
||||
zerror = deflateEnd(&zstream);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 InflateData(const char* buffer, uint32 len, char* out_buffer, uint32 out_len_max) {
|
||||
z_stream zstream;
|
||||
int zerror = 0;
|
||||
int i;
|
||||
|
||||
zstream.next_in = const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(buffer));
|
||||
zstream.avail_in = len;
|
||||
zstream.next_out = reinterpret_cast<unsigned char*>(out_buffer);;
|
||||
zstream.avail_out = out_len_max;
|
||||
zstream.zalloc = Z_NULL;
|
||||
zstream.zfree = Z_NULL;
|
||||
zstream.opaque = Z_NULL;
|
||||
|
||||
i = inflateInit2(&zstream, 15);
|
||||
if (i != Z_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
zerror = inflate(&zstream, Z_FINISH);
|
||||
if (zerror == Z_STREAM_END) {
|
||||
inflateEnd(&zstream);
|
||||
return zstream.total_out;
|
||||
}
|
||||
else {
|
||||
if (zerror == -4 && zstream.msg == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
zerror = inflateEnd(&zstream);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct Map::impl
|
||||
{
|
||||
@@ -268,6 +192,14 @@ bool Map::CheckLoS(glm::vec3 myloc, glm::vec3 oloc) const {
|
||||
return !imp->rm->raycast((const RmReal*)&myloc, (const RmReal*)&oloc, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
// returns true if a collision happens
|
||||
bool Map::DoCollisionCheck(glm::vec3 myloc, glm::vec3 oloc, glm::vec3 &outnorm, float &distance) const {
|
||||
if(!imp)
|
||||
return false;
|
||||
|
||||
return imp->rm->raycast((const RmReal*)&myloc, (const RmReal*)&oloc, nullptr, (RmReal *)&outnorm, (RmReal *)&distance);
|
||||
}
|
||||
|
||||
inline bool file_exists(const std::string& name) {
|
||||
std::ifstream f(name.c_str());
|
||||
return f.good();
|
||||
@@ -285,12 +217,13 @@ Map *Map::LoadMapFile(std::string file) {
|
||||
else {
|
||||
filename = Config->MapDir;
|
||||
}
|
||||
|
||||
std::transform(file.begin(), file.end(), file.begin(), ::tolower);
|
||||
filename += "/";
|
||||
filename += "/base/";
|
||||
filename += file;
|
||||
filename += ".map";
|
||||
|
||||
Log(Logs::General, Logs::Status, "Attempting to load Map File :: '%s'", filename.c_str());
|
||||
Log(Logs::General, Logs::Status, "Attempting to load Map File '%s'", filename.c_str());
|
||||
|
||||
auto m = new Map();
|
||||
if (m->Load(filename)) {
|
||||
@@ -322,7 +255,7 @@ bool Map::Load(std::string filename)
|
||||
}
|
||||
|
||||
if(version == 0x01000000) {
|
||||
Log(Logs::General, Logs::Status, "Loaded V1 Map File :: '%s'", filename.c_str());
|
||||
Log(Logs::General, Logs::Status, "Loaded V1 Map File '%s'", filename.c_str());
|
||||
bool v = LoadV1(f);
|
||||
fclose(f);
|
||||
|
||||
@@ -333,7 +266,7 @@ bool Map::Load(std::string filename)
|
||||
|
||||
return v;
|
||||
} else if(version == 0x02000000) {
|
||||
Log(Logs::General, Logs::Status, "Loaded V2 Map File :: '%s'", filename.c_str());
|
||||
Log(Logs::General, Logs::Status, "Loaded V2 Map File '%s'", filename.c_str());
|
||||
bool v = LoadV2(f);
|
||||
fclose(f);
|
||||
|
||||
@@ -451,7 +384,7 @@ bool Map::LoadV2(FILE *f) {
|
||||
|
||||
std::vector<char> buffer;
|
||||
buffer.resize(buffer_size);
|
||||
uint32 v = InflateData(&data[0], data_size, &buffer[0], buffer_size);
|
||||
uint32 v = EQEmu::InflateData(&data[0], data_size, &buffer[0], buffer_size);
|
||||
|
||||
char *buf = &buffer[0];
|
||||
uint32 vert_count;
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
bool LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const;
|
||||
bool LineIntersectsZoneNoZLeaps(glm::vec3 start, glm::vec3 end, float step_mag, glm::vec3 *result) const;
|
||||
bool CheckLoS(glm::vec3 myloc, glm::vec3 oloc) const;
|
||||
bool DoCollisionCheck(glm::vec3 myloc, glm::vec3 oloc, glm::vec3 &outnorm, float &distance) const;
|
||||
|
||||
#ifdef USE_MAP_MMFS
|
||||
bool Load(std::string filename, bool force_mmf_overwrite = false);
|
||||
|
||||
+73
-103
@@ -29,7 +29,7 @@ extern volatile bool is_zone_loaded;
|
||||
#endif
|
||||
|
||||
Merc::Merc(const NPCType* d, float x, float y, float z, float heading)
|
||||
: NPC(d, nullptr, glm::vec4(x, y, z, heading), 0, false), endupkeep_timer(1000), rest_timer(1), confidence_timer(6000), check_target_timer(2000)
|
||||
: NPC(d, nullptr, glm::vec4(x, y, z, heading), GravityBehavior::Water, false), endupkeep_timer(1000), rest_timer(1), confidence_timer(6000), check_target_timer(2000)
|
||||
{
|
||||
base_hp = d->max_hp;
|
||||
base_mana = d->Mana;
|
||||
@@ -66,7 +66,7 @@ Merc::Merc(const NPCType* d, float x, float y, float z, float heading)
|
||||
memset(equipment, 0, sizeof(equipment));
|
||||
|
||||
SetMercID(0);
|
||||
SetStance(MercStanceBalanced);
|
||||
SetStance(EQEmu::constants::stanceBalanced);
|
||||
rest_timer.Disable();
|
||||
|
||||
if (GetClass() == ROGUE)
|
||||
@@ -217,22 +217,16 @@ void Merc::CalcItemBonuses(StatBonuses* newbon) {
|
||||
|
||||
unsigned int i;
|
||||
//should not include 21 (SLOT_AMMO)
|
||||
for (i = 0; i < EQEmu::inventory::slotAmmo; i++) {
|
||||
if(equipment[i] == 0)
|
||||
for (i = EQEmu::invslot::BONUS_BEGIN; i <= EQEmu::invslot::BONUS_STAT_END; i++) {
|
||||
if (i == EQEmu::invslot::slotAmmo)
|
||||
continue;
|
||||
if (equipment[i] == 0)
|
||||
continue;
|
||||
const EQEmu::ItemData * itm = database.GetItem(equipment[i]);
|
||||
if(itm)
|
||||
if (itm)
|
||||
AddItemBonuses(itm, newbon);
|
||||
}
|
||||
|
||||
//Power Source Slot
|
||||
/*if (GetClientVersion() >= EQClientSoF)
|
||||
{
|
||||
const EQEmu::ItemInstance* inst = m_inv[MainPowerSource];
|
||||
if(inst)
|
||||
AddItemBonuses(inst, newbon);
|
||||
}*/
|
||||
|
||||
// Caps
|
||||
if(newbon->HPRegen > CalcHPRegenCap())
|
||||
newbon->HPRegen = CalcHPRegenCap();
|
||||
@@ -865,14 +859,14 @@ int32 Merc::CalcMaxHP() {
|
||||
|
||||
max_hp += max_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f);
|
||||
|
||||
if (cur_hp > max_hp)
|
||||
cur_hp = max_hp;
|
||||
if (current_hp > max_hp)
|
||||
current_hp = max_hp;
|
||||
|
||||
int hp_perc_cap = spellbonuses.HPPercCap[0];
|
||||
if(hp_perc_cap) {
|
||||
int curHP_cap = (max_hp * hp_perc_cap) / 100;
|
||||
if (cur_hp > curHP_cap || (spellbonuses.HPPercCap[1] && cur_hp > spellbonuses.HPPercCap[1]))
|
||||
cur_hp = curHP_cap;
|
||||
if (current_hp > curHP_cap || (spellbonuses.HPPercCap[1] && current_hp > spellbonuses.HPPercCap[1]))
|
||||
current_hp = curHP_cap;
|
||||
}
|
||||
|
||||
return max_hp;
|
||||
@@ -1174,11 +1168,11 @@ void Merc::CalcRestState() {
|
||||
}
|
||||
}
|
||||
|
||||
RestRegenHP = 6 * (GetMaxHP() / RuleI(Character, RestRegenHP));
|
||||
RestRegenHP = 6 * (GetMaxHP() / zone->newzone_data.FastRegenHP);
|
||||
|
||||
RestRegenMana = 6 * (GetMaxMana() / RuleI(Character, RestRegenMana));
|
||||
RestRegenMana = 6 * (GetMaxMana() / zone->newzone_data.FastRegenMana);
|
||||
|
||||
RestRegenEndurance = 6 * (GetMaxEndurance() / RuleI(Character, RestRegenEnd));
|
||||
RestRegenEndurance = 6 * (GetMaxEndurance() / zone->newzone_data.FastRegenEndurance);
|
||||
}
|
||||
|
||||
bool Merc::HasSkill(EQEmu::skills::SkillType skill_id) const {
|
||||
@@ -1277,7 +1271,7 @@ bool Merc::Process()
|
||||
//6 seconds, or whatever the rule is set to has passed, send this position to everyone to avoid ghosting
|
||||
if(!IsMoving() && !IsEngaged())
|
||||
{
|
||||
SendPosition();
|
||||
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
|
||||
if(IsSitting()) {
|
||||
if(!rest_timer.Enabled()) {
|
||||
rest_timer.Start(RuleI(Character, RestRegenTimeToActivate) * 1000);
|
||||
@@ -1303,7 +1297,7 @@ bool Merc::Process()
|
||||
_check_confidence = true;
|
||||
}
|
||||
|
||||
if (sendhpupdate_timer.Check()) {
|
||||
if (send_hp_update_timer.Check()) {
|
||||
SendHPUpdate();
|
||||
}
|
||||
|
||||
@@ -1414,7 +1408,7 @@ void Merc::AI_Process() {
|
||||
if(DivineAura())
|
||||
return;
|
||||
|
||||
int hateCount = entity_list.GetHatedCount(this, nullptr);
|
||||
int hateCount = entity_list.GetHatedCount(this, nullptr, false);
|
||||
if(GetHatedCount() < hateCount) {
|
||||
SetHatedCount(hateCount);
|
||||
|
||||
@@ -1471,29 +1465,15 @@ void Merc::AI_Process() {
|
||||
|
||||
if(moved) {
|
||||
moved = false;
|
||||
SetCurrentSpeed(0);
|
||||
StopNavigation();
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if (!CheckLosFN(GetTarget())) {
|
||||
if (RuleB(Mercs, MercsUsePathing) && zone->pathing) {
|
||||
bool WaypointChanged, NodeReached;
|
||||
|
||||
glm::vec3 Goal = UpdatePath(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(),
|
||||
GetRunspeed(), WaypointChanged, NodeReached);
|
||||
|
||||
if (WaypointChanged)
|
||||
tar_ndx = 20;
|
||||
|
||||
CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetRunspeed());
|
||||
}
|
||||
else {
|
||||
Mob* follow = entity_list.GetMob(GetFollowID());
|
||||
if (follow)
|
||||
CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), GetRunspeed());
|
||||
}
|
||||
auto Goal = GetTarget()->GetPosition();
|
||||
RunTo(Goal.x, Goal.y, Goal.z);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1527,7 +1507,7 @@ void Merc::AI_Process() {
|
||||
SetRunAnimSpeed(0);
|
||||
|
||||
if(moved) {
|
||||
SetCurrentSpeed(0);
|
||||
StopNavigation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1559,7 +1539,7 @@ void Merc::AI_Process() {
|
||||
float newZ = 0;
|
||||
FaceTarget(GetTarget());
|
||||
if (PlotPositionAroundTarget(this, newX, newY, newZ)) {
|
||||
CalculateNewPosition2(newX, newY, newZ, GetRunspeed());
|
||||
RunTo(newX, newY, newZ);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1571,7 +1551,7 @@ void Merc::AI_Process() {
|
||||
float newY = 0;
|
||||
float newZ = 0;
|
||||
if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ)) {
|
||||
CalculateNewPosition2(newX, newY, newZ, GetRunspeed());
|
||||
RunTo(newX, newY, newZ);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1582,16 +1562,16 @@ void Merc::AI_Process() {
|
||||
float newY = 0;
|
||||
float newZ = 0;
|
||||
if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ, false) && GetArchetype() != ARCHETYPE_CASTER) {
|
||||
CalculateNewPosition2(newX, newY, newZ, GetRunspeed());
|
||||
RunTo(newX, newY, newZ);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(IsMoving())
|
||||
SendPositionUpdate();
|
||||
else
|
||||
SendPosition();
|
||||
//if (IsMoving())
|
||||
// SendPositionUpdate();
|
||||
//else
|
||||
// SendPosition();
|
||||
}
|
||||
|
||||
if(!IsMercCaster() && GetTarget() && !IsStunned() && !IsMezzed() && (GetAppearance() != eaDead))
|
||||
@@ -1610,24 +1590,24 @@ void Merc::AI_Process() {
|
||||
//try main hand first
|
||||
if(attack_timer.Check())
|
||||
{
|
||||
Attack(GetTarget(), EQEmu::inventory::slotPrimary);
|
||||
Attack(GetTarget(), EQEmu::invslot::slotPrimary);
|
||||
|
||||
bool tripleSuccess = false;
|
||||
|
||||
if(GetOwner() && GetTarget() && CanThisClassDoubleAttack())
|
||||
{
|
||||
if(GetOwner()) {
|
||||
Attack(GetTarget(), EQEmu::inventory::slotPrimary, true);
|
||||
Attack(GetTarget(), EQEmu::invslot::slotPrimary, true);
|
||||
}
|
||||
|
||||
if(GetOwner() && GetTarget() && GetSpecialAbility(SPECATK_TRIPLE)) {
|
||||
tripleSuccess = true;
|
||||
Attack(GetTarget(), EQEmu::inventory::slotPrimary, true);
|
||||
Attack(GetTarget(), EQEmu::invslot::slotPrimary, true);
|
||||
}
|
||||
|
||||
//quad attack, does this belong here??
|
||||
if(GetOwner() && GetTarget() && GetSpecialAbility(SPECATK_QUAD)) {
|
||||
Attack(GetTarget(), EQEmu::inventory::slotPrimary, true);
|
||||
Attack(GetTarget(), EQEmu::invslot::slotPrimary, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1639,8 +1619,8 @@ void Merc::AI_Process() {
|
||||
if(zone->random.Roll(flurrychance))
|
||||
{
|
||||
Message_StringID(MT_NPCFlurry, YOU_FLURRY);
|
||||
Attack(GetTarget(), EQEmu::inventory::slotPrimary, false);
|
||||
Attack(GetTarget(), EQEmu::inventory::slotPrimary, false);
|
||||
Attack(GetTarget(), EQEmu::invslot::slotPrimary, false);
|
||||
Attack(GetTarget(), EQEmu::invslot::slotPrimary, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1649,7 +1629,7 @@ void Merc::AI_Process() {
|
||||
if (GetTarget() && ExtraAttackChanceBonus) {
|
||||
if(zone->random.Roll(ExtraAttackChanceBonus))
|
||||
{
|
||||
Attack(GetTarget(), EQEmu::inventory::slotPrimary, false);
|
||||
Attack(GetTarget(), EQEmu::invslot::slotPrimary, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1685,11 +1665,11 @@ void Merc::AI_Process() {
|
||||
// Max 78% of DW
|
||||
if (zone->random.Roll(DualWieldProbability))
|
||||
{
|
||||
Attack(GetTarget(), EQEmu::inventory::slotSecondary); // Single attack with offhand
|
||||
Attack(GetTarget(), EQEmu::invslot::slotSecondary); // Single attack with offhand
|
||||
|
||||
if(CanThisClassDoubleAttack()) {
|
||||
if(GetTarget() && GetTarget()->GetHP() > -10)
|
||||
Attack(GetTarget(), EQEmu::inventory::slotSecondary); // Single attack with offhand
|
||||
Attack(GetTarget(), EQEmu::invslot::slotSecondary); // Single attack with offhand
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1709,14 +1689,14 @@ void Merc::AI_Process() {
|
||||
{
|
||||
if(!IsRooted()) {
|
||||
Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", GetTarget()->GetCleanName());
|
||||
CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed());
|
||||
RunTo(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ());
|
||||
return;
|
||||
}
|
||||
|
||||
if(IsMoving())
|
||||
SendPositionUpdate();
|
||||
else
|
||||
SendPosition();
|
||||
//if(IsMoving())
|
||||
// SendPositionUpdate();
|
||||
//else
|
||||
// SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
|
||||
}
|
||||
} // end not in combat range
|
||||
|
||||
@@ -1764,27 +1744,19 @@ void Merc::AI_Process() {
|
||||
|
||||
if (follow) {
|
||||
float dist = DistanceSquared(m_Position, follow->GetPosition());
|
||||
int speed = GetRunspeed();
|
||||
bool running = true;
|
||||
|
||||
if (dist < GetFollowDistance() + 1000)
|
||||
speed = GetWalkspeed();
|
||||
running = false;
|
||||
|
||||
SetRunAnimSpeed(0);
|
||||
|
||||
if (dist > GetFollowDistance()) {
|
||||
if (RuleB(Mercs, MercsUsePathing) && zone->pathing) {
|
||||
bool WaypointChanged, NodeReached;
|
||||
|
||||
glm::vec3 Goal = UpdatePath(follow->GetX(), follow->GetY(), follow->GetZ(),
|
||||
speed, WaypointChanged, NodeReached);
|
||||
|
||||
if (WaypointChanged)
|
||||
tar_ndx = 20;
|
||||
|
||||
CalculateNewPosition2(Goal.x, Goal.y, Goal.z, speed);
|
||||
if (running) {
|
||||
RunTo(follow->GetX(), follow->GetY(), follow->GetZ());
|
||||
}
|
||||
else {
|
||||
CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), speed);
|
||||
WalkTo(follow->GetX(), follow->GetY(), follow->GetZ());
|
||||
}
|
||||
|
||||
if (rest_timer.Enabled())
|
||||
@@ -1793,7 +1765,7 @@ void Merc::AI_Process() {
|
||||
else {
|
||||
if (moved) {
|
||||
moved = false;
|
||||
SetCurrentSpeed(0);
|
||||
StopNavigation();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1819,8 +1791,7 @@ void Merc::AI_Start(int32 iMoveDelay) {
|
||||
}
|
||||
|
||||
SendTo(GetX(), GetY(), GetZ());
|
||||
SetChanged();
|
||||
SaveGuardSpot();
|
||||
SaveGuardSpot(GetPosition());
|
||||
}
|
||||
|
||||
void Merc::AI_Stop() {
|
||||
@@ -1937,7 +1908,7 @@ bool Merc::AI_IdleCastCheck() {
|
||||
|
||||
bool EntityList::Merc_AICheckCloseBeneficialSpells(Merc* caster, uint8 iChance, float iRange, uint32 iSpellTypes) {
|
||||
|
||||
if((iSpellTypes&SpellTypes_Detrimental) != 0) {
|
||||
if((iSpellTypes & SPELL_TYPES_DETRIMENTAL) != 0) {
|
||||
//according to live, you can buff and heal through walls...
|
||||
//now with PCs, this only applies if you can TARGET the target, but
|
||||
// according to Rogean, Live NPCs will just cast through walls/floors, no problem..
|
||||
@@ -2019,10 +1990,10 @@ bool Merc::AIDoSpellCast(uint16 spellid, Mob* tar, int32 mana_cost, uint32* oDon
|
||||
|| dist2 <= GetActSpellRange(spellid, spells[spellid].range)*GetActSpellRange(spellid, spells[spellid].range)) && (mana_cost <= GetMana() || GetMana() == GetMaxMana()))
|
||||
{
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
|
||||
SetMoving(false);
|
||||
|
||||
result = CastSpell(spellid, tar->GetID(), EQEmu::CastingSlot::Gem2, -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, 0);
|
||||
result = CastSpell(spellid, tar->GetID(), EQEmu::spells::CastingSlot::Gem2, -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, 0);
|
||||
|
||||
if(IsCasting() && IsSitting())
|
||||
Stand();
|
||||
@@ -2614,7 +2585,7 @@ int16 Merc::GetFocusEffect(focusType type, uint16 spell_id) {
|
||||
int16 focus_max_real = 0;
|
||||
|
||||
//item focus
|
||||
for (int x = 0; x < EQEmu::legacy::EQUIPMENT_SIZE; ++x)
|
||||
for (int x = EQEmu::invslot::EQUIPMENT_BEGIN; x <= EQEmu::invslot::EQUIPMENT_END; ++x)
|
||||
{
|
||||
TempItem = nullptr;
|
||||
if (equipment[x] == 0)
|
||||
@@ -3698,13 +3669,13 @@ MercSpell Merc::GetBestMercSpellForAENuke(Merc* caster, Mob* tar) {
|
||||
|
||||
switch(caster->GetStance())
|
||||
{
|
||||
case MercStanceBurnAE:
|
||||
case EQEmu::constants::stanceBurnAE:
|
||||
initialCastChance = 50;
|
||||
break;
|
||||
case MercStanceBalanced:
|
||||
case EQEmu::constants::stanceBalanced:
|
||||
initialCastChance = 25;
|
||||
break;
|
||||
case MercStanceBurn:
|
||||
case EQEmu::constants::stanceBurn:
|
||||
initialCastChance = 0;
|
||||
break;
|
||||
}
|
||||
@@ -3746,11 +3717,11 @@ MercSpell Merc::GetBestMercSpellForTargetedAENuke(Merc* caster, Mob* tar) {
|
||||
|
||||
switch(caster->GetStance())
|
||||
{
|
||||
case MercStanceBurnAE:
|
||||
case EQEmu::constants::stanceBurnAE:
|
||||
numTargetsCheck = 1;
|
||||
break;
|
||||
case MercStanceBalanced:
|
||||
case MercStanceBurn:
|
||||
case EQEmu::constants::stanceBalanced:
|
||||
case EQEmu::constants::stanceBurn:
|
||||
numTargetsCheck = 2;
|
||||
break;
|
||||
}
|
||||
@@ -3798,11 +3769,11 @@ MercSpell Merc::GetBestMercSpellForPBAENuke(Merc* caster, Mob* tar) {
|
||||
|
||||
switch(caster->GetStance())
|
||||
{
|
||||
case MercStanceBurnAE:
|
||||
case EQEmu::constants::stanceBurnAE:
|
||||
numTargetsCheck = 2;
|
||||
break;
|
||||
case MercStanceBalanced:
|
||||
case MercStanceBurn:
|
||||
case EQEmu::constants::stanceBalanced:
|
||||
case EQEmu::constants::stanceBurn:
|
||||
numTargetsCheck = 3;
|
||||
break;
|
||||
}
|
||||
@@ -3849,11 +3820,11 @@ MercSpell Merc::GetBestMercSpellForAERainNuke(Merc* caster, Mob* tar) {
|
||||
|
||||
switch(caster->GetStance())
|
||||
{
|
||||
case MercStanceBurnAE:
|
||||
case EQEmu::constants::stanceBurnAE:
|
||||
numTargetsCheck = 1;
|
||||
break;
|
||||
case MercStanceBalanced:
|
||||
case MercStanceBurn:
|
||||
case EQEmu::constants::stanceBalanced:
|
||||
case EQEmu::constants::stanceBurn:
|
||||
numTargetsCheck = 2;
|
||||
break;
|
||||
}
|
||||
@@ -4074,7 +4045,7 @@ bool Merc::UseDiscipline(int32 spell_id, int32 target) {
|
||||
if(IsCasting())
|
||||
InterruptSpell();
|
||||
|
||||
CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline);
|
||||
CastSpell(spell_id, target, EQEmu::spells::CastingSlot::Discipline);
|
||||
|
||||
return(true);
|
||||
}
|
||||
@@ -4389,9 +4360,8 @@ void Merc::Sit() {
|
||||
if(IsMoving()) {
|
||||
moved = false;
|
||||
// SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SendPosition();
|
||||
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
|
||||
SetMoving(false);
|
||||
tar_ndx = 0;
|
||||
}
|
||||
|
||||
SetAppearance(eaSitting);
|
||||
@@ -4979,7 +4949,7 @@ void Merc::ScaleStats(int scalepercent, bool setmax) {
|
||||
max_hp = (int)((float)base_hp * scalerate);
|
||||
base_hp = max_hp;
|
||||
if (setmax)
|
||||
cur_hp = max_hp;
|
||||
current_hp = max_hp;
|
||||
}
|
||||
|
||||
if (base_mana)
|
||||
@@ -5093,7 +5063,7 @@ void Merc::UpdateMercAppearance() {
|
||||
// Copied from Bot Code:
|
||||
uint32 itemID = 0;
|
||||
uint8 materialFromSlot = EQEmu::textures::materialInvalid;
|
||||
for (int i = EQEmu::legacy::EQUIPMENT_BEGIN; i <= EQEmu::legacy::EQUIPMENT_END; ++i) {
|
||||
for (int i = EQEmu::invslot::EQUIPMENT_BEGIN; i <= EQEmu::invslot::EQUIPMENT_END; ++i) {
|
||||
itemID = equipment[i];
|
||||
if(itemID != 0) {
|
||||
materialFromSlot = EQEmu::InventoryProfile::CalcMaterialFromSlot(i);
|
||||
@@ -5111,8 +5081,8 @@ void Merc::UpdateEquipmentLight()
|
||||
m_Light.Type[EQEmu::lightsource::LightEquipment] = 0;
|
||||
m_Light.Level[EQEmu::lightsource::LightEquipment] = 0;
|
||||
|
||||
for (int index = EQEmu::inventory::slotBegin; index < EQEmu::legacy::EQUIPMENT_SIZE; ++index) {
|
||||
if (index == EQEmu::inventory::slotAmmo) { continue; }
|
||||
for (int index = EQEmu::invslot::EQUIPMENT_BEGIN; index <= EQEmu::invslot::EQUIPMENT_END; ++index) {
|
||||
if (index == EQEmu::invslot::slotAmmo) { continue; }
|
||||
|
||||
auto item = database.GetItem(equipment[index]);
|
||||
if (item == nullptr) { continue; }
|
||||
@@ -5158,7 +5128,7 @@ bool Merc::Spawn(Client *owner) {
|
||||
|
||||
entity_list.AddMerc(this, true, true);
|
||||
|
||||
SendPosition();
|
||||
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
|
||||
|
||||
Log(Logs::General, Logs::Mercenaries, "Spawn Mercenary %s.", GetName());
|
||||
|
||||
@@ -5679,7 +5649,7 @@ void Client::SpawnMerc(Merc* merc, bool setMaxStats) {
|
||||
merc->SetSuspended(false);
|
||||
SetMerc(merc);
|
||||
merc->Unsuspend(setMaxStats);
|
||||
merc->SetStance(GetMercInfo().Stance);
|
||||
merc->SetStance((EQEmu::constants::StanceType)GetMercInfo().Stance);
|
||||
|
||||
Log(Logs::General, Logs::Mercenaries, "SpawnMerc Success for %s.", GetName());
|
||||
|
||||
|
||||
+5
-17
@@ -30,18 +30,6 @@ namespace EQEmu
|
||||
|
||||
const int MercAISpellRange = 100; // TODO: Write a method that calcs what the merc's spell range is based on spell, equipment, AA, whatever and replace this
|
||||
|
||||
enum MercStanceType {
|
||||
MercStancePassive = 1,
|
||||
MercStanceBalanced,
|
||||
MercStanceEfficient,
|
||||
MercStanceReactive,
|
||||
MercStanceAggressive,
|
||||
MercStanceAssist,
|
||||
MercStanceBurn,
|
||||
MercStanceEfficient2,
|
||||
MercStanceBurnAE
|
||||
};
|
||||
|
||||
struct MercSpell {
|
||||
uint16 spellid; // <= 0 = no spell
|
||||
uint32 type; // 0 = never, must be one (and only one) of the defined values
|
||||
@@ -66,7 +54,7 @@ public:
|
||||
//abstract virtual function implementations requird by base abstract class
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill);
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
|
||||
bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr);
|
||||
virtual bool HasRaid() { return false; }
|
||||
virtual bool HasGroup() { return (GetGroup() ? true : false); }
|
||||
@@ -175,7 +163,7 @@ public:
|
||||
uint8 GetTierID() { return _TierID; }
|
||||
uint32 GetCostFormula() { return _CostFormula; }
|
||||
uint32 GetMercNameType() { return _NameType; }
|
||||
uint32 GetStance() { return _currentStance; }
|
||||
EQEmu::constants::StanceType GetStance() { return _currentStance; }
|
||||
int GetHatedCount() { return _hatedCount; }
|
||||
|
||||
inline const uint8 GetClientVersion() const { return _OwnerClientVersion; }
|
||||
@@ -265,7 +253,7 @@ public:
|
||||
void SetMercNameType( uint8 nametype ) { _NameType = nametype; }
|
||||
void SetClientVersion(uint8 clientVersion) { _OwnerClientVersion = clientVersion; }
|
||||
void SetSuspended(bool suspended) { _suspended = suspended; }
|
||||
void SetStance( uint32 stance ) { _currentStance = stance; }
|
||||
void SetStance( EQEmu::constants::StanceType stance ) { _currentStance = stance; }
|
||||
void SetHatedCount( int count ) { _hatedCount = count; }
|
||||
|
||||
void Sit();
|
||||
@@ -293,7 +281,7 @@ protected:
|
||||
Timer evade_timer; // can be moved to pTimers at some point
|
||||
|
||||
uint16 skills[EQEmu::skills::HIGHEST_SKILL + 1];
|
||||
uint32 equipment[EQEmu::legacy::EQUIPMENT_SIZE]; //this is an array of item IDs
|
||||
uint32 equipment[EQEmu::invslot::EQUIPMENT_COUNT]; //this is an array of item IDs
|
||||
uint16 d_melee_texture1; //this is an item Material value
|
||||
uint16 d_melee_texture2; //this is an item Material value (offhand)
|
||||
uint8 prim_melee_type; //Sets the Primary Weapon attack message and animation
|
||||
@@ -385,7 +373,7 @@ private:
|
||||
uint8 _CostFormula;
|
||||
uint8 _NameType;
|
||||
uint8 _OwnerClientVersion;
|
||||
uint32 _currentStance;
|
||||
EQEmu::constants::StanceType _currentStance;
|
||||
|
||||
EQEmu::InventoryProfile m_inv;
|
||||
int32 max_end;
|
||||
|
||||
+711
-1005
File diff suppressed because it is too large
Load Diff
+221
-171
@@ -21,7 +21,7 @@
|
||||
#include "common.h"
|
||||
#include "entity.h"
|
||||
#include "hate_list.h"
|
||||
#include "pathing.h"
|
||||
#include "pathfinder_interface.h"
|
||||
#include "position.h"
|
||||
#include "aa_ability.h"
|
||||
#include "aa.h"
|
||||
@@ -49,6 +49,9 @@ class Aura;
|
||||
struct AuraRecord;
|
||||
struct NewSpawn_Struct;
|
||||
struct PlayerPositionUpdateServer_Struct;
|
||||
class MobMovementManager;
|
||||
|
||||
const int COLLISION_BOX_SIZE = 8;
|
||||
|
||||
namespace EQEmu
|
||||
{
|
||||
@@ -104,65 +107,67 @@ public:
|
||||
AuraMgr() : count(0) { }
|
||||
};
|
||||
|
||||
Mob(const char* in_name,
|
||||
const char* in_lastname,
|
||||
int32 in_cur_hp,
|
||||
int32 in_max_hp,
|
||||
uint8 in_gender,
|
||||
uint16 in_race,
|
||||
uint8 in_class,
|
||||
bodyType in_bodytype,
|
||||
uint8 in_deity,
|
||||
uint8 in_level,
|
||||
uint32 in_npctype_id,
|
||||
float in_size,
|
||||
float in_runspeed,
|
||||
const glm::vec4& position,
|
||||
uint8 in_light,
|
||||
uint8 in_texture,
|
||||
uint8 in_helmtexture,
|
||||
uint16 in_ac,
|
||||
uint16 in_atk,
|
||||
uint16 in_str,
|
||||
uint16 in_sta,
|
||||
uint16 in_dex,
|
||||
uint16 in_agi,
|
||||
uint16 in_int,
|
||||
uint16 in_wis,
|
||||
uint16 in_cha,
|
||||
uint8 in_haircolor,
|
||||
uint8 in_beardcolor,
|
||||
uint8 in_eyecolor1, // the eyecolors always seem to be the same, maybe left and right eye?
|
||||
uint8 in_eyecolor2,
|
||||
uint8 in_hairstyle,
|
||||
uint8 in_luclinface,
|
||||
uint8 in_beard,
|
||||
uint32 in_drakkin_heritage,
|
||||
uint32 in_drakkin_tattoo,
|
||||
uint32 in_drakkin_details,
|
||||
EQEmu::TintProfile in_armor_tint,
|
||||
uint8 in_aa_title,
|
||||
uint8 in_see_invis, // see through invis
|
||||
uint8 in_see_invis_undead, // see through invis vs. undead
|
||||
uint8 in_see_hide,
|
||||
uint8 in_see_improved_hide,
|
||||
int32 in_hp_regen,
|
||||
int32 in_mana_regen,
|
||||
uint8 in_qglobal,
|
||||
uint8 in_maxlevel,
|
||||
uint32 in_scalerate,
|
||||
uint8 in_armtexture,
|
||||
uint8 in_bracertexture,
|
||||
uint8 in_handtexture,
|
||||
uint8 in_legtexture,
|
||||
uint8 in_feettexture
|
||||
Mob(
|
||||
const char *in_name,
|
||||
const char *in_lastname,
|
||||
int32 in_cur_hp,
|
||||
int32 in_max_hp,
|
||||
uint8 in_gender,
|
||||
uint16 in_race,
|
||||
uint8 in_class,
|
||||
bodyType in_bodytype,
|
||||
uint8 in_deity,
|
||||
uint8 in_level,
|
||||
uint32 in_npctype_id,
|
||||
float in_size,
|
||||
float in_runspeed,
|
||||
const glm::vec4 &position,
|
||||
uint8 in_light,
|
||||
uint8 in_texture,
|
||||
uint8 in_helmtexture,
|
||||
uint16 in_ac,
|
||||
uint16 in_atk,
|
||||
uint16 in_str,
|
||||
uint16 in_sta,
|
||||
uint16 in_dex,
|
||||
uint16 in_agi,
|
||||
uint16 in_int,
|
||||
uint16 in_wis,
|
||||
uint16 in_cha,
|
||||
uint8 in_haircolor,
|
||||
uint8 in_beardcolor,
|
||||
uint8 in_eyecolor1, // the eyecolors always seem to be the same, maybe left and right eye?
|
||||
uint8 in_eyecolor2,
|
||||
uint8 in_hairstyle,
|
||||
uint8 in_luclinface,
|
||||
uint8 in_beard,
|
||||
uint32 in_drakkin_heritage,
|
||||
uint32 in_drakkin_tattoo,
|
||||
uint32 in_drakkin_details,
|
||||
EQEmu::TintProfile in_armor_tint,
|
||||
uint8 in_aa_title,
|
||||
uint8 in_see_invis, // see through invis
|
||||
uint8 in_see_invis_undead, // see through invis vs. undead
|
||||
uint8 in_see_hide,
|
||||
uint8 in_see_improved_hide,
|
||||
int32 in_hp_regen,
|
||||
int32 in_mana_regen,
|
||||
uint8 in_qglobal,
|
||||
uint8 in_maxlevel,
|
||||
uint32 in_scalerate,
|
||||
uint8 in_armtexture,
|
||||
uint8 in_bracertexture,
|
||||
uint8 in_handtexture,
|
||||
uint8 in_legtexture,
|
||||
uint8 in_feettexture,
|
||||
uint16 in_usemodel
|
||||
);
|
||||
virtual ~Mob();
|
||||
|
||||
inline virtual bool IsMob() const { return true; }
|
||||
inline virtual bool InZone() const { return true; }
|
||||
|
||||
bool is_distance_roamer;
|
||||
void DisplayInfo(Mob *mob);
|
||||
|
||||
//Somewhat sorted: needs documenting!
|
||||
|
||||
@@ -177,11 +182,12 @@ public:
|
||||
inline bool InFrontMob(Mob *other = 0, float ourx = 0.0f, float oury = 0.0f) const
|
||||
{ return (!other || other == this) ? true : MobAngle(other, ourx, oury) < 56.0f; }
|
||||
bool IsFacingMob(Mob *other); // kind of does the same as InFrontMob, but derived from client
|
||||
float HeadingAngleToMob(Mob *other); // to keep consistent with client generated messages
|
||||
float HeadingAngleToMob(Mob *other) { return HeadingAngleToMob(other->GetX(), other->GetY()); }
|
||||
float HeadingAngleToMob(float other_x, float other_y); // to keep consistent with client generated messages
|
||||
virtual void RangedAttack(Mob* other) { }
|
||||
virtual void ThrowingAttack(Mob* other) { }
|
||||
// 13 = Primary (default), 14 = secondary
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
|
||||
bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) = 0;
|
||||
void DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr);
|
||||
int MonkSpecialAttack(Mob* other, uint8 skill_used);
|
||||
@@ -233,33 +239,47 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
//Appearance
|
||||
void SendLevelAppearance();
|
||||
void SendStunAppearance();
|
||||
void SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 parm4, uint32 parm5,
|
||||
Client *specific_target=nullptr);
|
||||
void SendTargetable(bool on, Client *specific_target = nullptr);
|
||||
virtual void SendArmorAppearance(Client *one_client = nullptr);
|
||||
virtual void SendWearChange(uint8 material_slot, Client *one_client = nullptr);
|
||||
virtual void SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0,
|
||||
uint32 unknown06 = 0, uint32 unknown18 = 0);
|
||||
virtual void SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint);
|
||||
virtual void WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model = 0);
|
||||
void DoAnim(const int animnum, int type=0, bool ackreq = true, eqFilterType filter = FilterNone);
|
||||
void ProjectileAnimation(Mob* to, int item_id, bool IsArrow = false, float speed = 0,
|
||||
float angle = 0, float tilt = 0, float arc = 0, const char *IDFile = nullptr, EQEmu::skills::SkillType skillInUse = EQEmu::skills::SkillArchery);
|
||||
void ChangeSize(float in_size, bool bNoRestriction = false);
|
||||
inline uint8 SeeInvisible() const { return see_invis; }
|
||||
inline bool SeeInvisibleUndead() const { return see_invis_undead; }
|
||||
/**
|
||||
************************************************
|
||||
* Appearance
|
||||
************************************************
|
||||
*/
|
||||
|
||||
EQEmu::InternalTextureProfile mob_texture_profile = {};
|
||||
|
||||
bool IsInvisible(Mob* other = 0) const;
|
||||
|
||||
EQEmu::skills::SkillType AttackAnimation(int Hand, const EQEmu::ItemInstance* weapon, EQEmu::skills::SkillType skillinuse = EQEmu::skills::Skill1HBlunt);
|
||||
|
||||
inline bool GetSeeInvisible(uint8 see_invis);
|
||||
inline bool SeeHide() const { return see_hide; }
|
||||
inline bool SeeImprovedHide() const { return see_improved_hide; }
|
||||
bool IsInvisible(Mob* other = 0) const;
|
||||
inline bool SeeInvisibleUndead() const { return see_invis_undead; }
|
||||
inline uint8 SeeInvisible() const { return see_invis; }
|
||||
|
||||
int32 GetTextureProfileMaterial(uint8 material_slot) const;
|
||||
int32 GetTextureProfileColor(uint8 material_slot) const;
|
||||
int32 GetTextureProfileHeroForgeModel(uint8 material_slot) const;
|
||||
|
||||
virtual void SendArmorAppearance(Client *one_client = nullptr);
|
||||
virtual void SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0, uint32 unknown06 = 0, uint32 unknown18 = 0);
|
||||
virtual void SendWearChange(uint8 material_slot, Client *one_client = nullptr);
|
||||
virtual void SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint);
|
||||
virtual void WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model = 0);
|
||||
|
||||
void ChangeSize(float in_size, bool bNoRestriction = false);
|
||||
void DoAnim(const int animnum, int type=0, bool ackreq = true, eqFilterType filter = FilterNone);
|
||||
void ProjectileAnimation(Mob* to, int item_id, bool IsArrow = false, float speed = 0, float angle = 0, float tilt = 0, float arc = 0, const char *IDFile = nullptr, EQEmu::skills::SkillType skillInUse = EQEmu::skills::SkillArchery);
|
||||
void SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 parm4, uint32 parm5, Client *specific_target=nullptr);
|
||||
void SendLevelAppearance();
|
||||
void SendStunAppearance();
|
||||
void SendTargetable(bool on, Client *specific_target = nullptr);
|
||||
void SetInvisible(uint8 state);
|
||||
EQEmu::skills::SkillType AttackAnimation(int Hand, const EQEmu::ItemInstance* weapon, EQEmu::skills::SkillType skillinuse = EQEmu::skills::Skill1HBlunt);
|
||||
void SetMobTextureProfile(uint8 material_slot, uint16 texture, uint32 color = 0, uint32 hero_forge_model = 0);
|
||||
|
||||
//Song
|
||||
bool UseBardSpellLogic(uint16 spell_id = 0xffff, int slot = -1);
|
||||
bool ApplyNextBardPulse(uint16 spell_id, Mob *spell_target, EQEmu::CastingSlot slot);
|
||||
bool ApplyNextBardPulse(uint16 spell_id, Mob *spell_target, EQEmu::spells::CastingSlot slot);
|
||||
void BardPulse(uint16 spell_id, Mob *caster);
|
||||
|
||||
//Spell
|
||||
@@ -290,24 +310,24 @@ public:
|
||||
void SendSpellBarEnable(uint16 spellid);
|
||||
void ZeroCastingVars();
|
||||
virtual void SpellProcess();
|
||||
virtual bool CastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, int32 casttime = -1,
|
||||
virtual bool CastSpell(uint16 spell_id, uint16 target_id, EQEmu::spells::CastingSlot slot = EQEmu::spells::CastingSlot::Item, int32 casttime = -1,
|
||||
int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF,
|
||||
uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, int16 *resist_adjust = nullptr,
|
||||
uint32 aa_id = 0);
|
||||
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, int32 casttime = -1,
|
||||
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, EQEmu::spells::CastingSlot slot = EQEmu::spells::CastingSlot::Item, int32 casttime = -1,
|
||||
int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF,
|
||||
uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, int16 resist_adjust = 0,
|
||||
uint32 aa_id = 0);
|
||||
void CastedSpellFinished(uint16 spell_id, uint32 target_id, EQEmu::CastingSlot slot, uint16 mana_used,
|
||||
void CastedSpellFinished(uint16 spell_id, uint32 target_id, EQEmu::spells::CastingSlot slot, uint16 mana_used,
|
||||
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0);
|
||||
bool SpellFinished(uint16 spell_id, Mob *target, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, uint16 mana_used = 0,
|
||||
bool SpellFinished(uint16 spell_id, Mob *target, EQEmu::spells::CastingSlot slot = EQEmu::spells::CastingSlot::Item, uint16 mana_used = 0,
|
||||
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false, int level_override = -1);
|
||||
void SendBeginCast(uint16 spell_id, uint32 casttime);
|
||||
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect = false,
|
||||
bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false, int level_override = -1);
|
||||
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100, int level_override = -1);
|
||||
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center,
|
||||
CastAction_type &CastAction, EQEmu::CastingSlot slot, bool isproc = false);
|
||||
CastAction_type &CastAction, EQEmu::spells::CastingSlot slot, bool isproc = false);
|
||||
virtual bool CheckFizzle(uint16 spell_id);
|
||||
virtual bool CheckSpellLevelRestriction(uint16 spell_id);
|
||||
virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster);
|
||||
@@ -365,6 +385,8 @@ public:
|
||||
void DamageShield(Mob* other, bool spell_ds = false);
|
||||
int32 RuneAbsorb(int32 damage, uint16 type);
|
||||
bool FindBuff(uint16 spellid);
|
||||
uint16 FindBuffBySlot(int slot);
|
||||
uint32 BuffCount();
|
||||
bool FindType(uint16 type, bool bOffensive = false, uint16 threshold = 100);
|
||||
int16 GetBuffSlotFromType(uint16 type);
|
||||
uint16 GetSpellIDFromSlot(uint8 slot);
|
||||
@@ -405,7 +427,7 @@ public:
|
||||
bool CanFacestab() { return can_facestab; }
|
||||
void SetFacestab(bool val) { can_facestab = val; }
|
||||
virtual uint16 GetSkill(EQEmu::skills::SkillType skill_num) const { return 0; }
|
||||
virtual uint32 GetEquipment(uint8 material_slot) const { return(0); }
|
||||
virtual uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const { return(0); }
|
||||
virtual int32 GetEquipmentMaterial(uint8 material_slot) const;
|
||||
virtual int32 GetHerosForgeModel(uint8 material_slot) const;
|
||||
virtual uint32 GetEquipmentColor(uint8 material_slot) const;
|
||||
@@ -415,14 +437,15 @@ public:
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) = 0;
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill,
|
||||
bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) = 0;
|
||||
inline virtual void SetHP(int32 hp) { if (hp >= max_hp) cur_hp = max_hp; else cur_hp = hp;}
|
||||
inline virtual void SetHP(int32 hp) { if (hp >= max_hp) current_hp = max_hp; else current_hp = hp;}
|
||||
bool ChangeHP(Mob* other, int32 amount, uint16 spell_id = 0, int8 buffslot = -1, bool iBuffTic = false);
|
||||
inline void SetOOCRegen(int32 newoocregen) {oocregen = newoocregen;}
|
||||
inline void SetOOCRegen(int32 newoocregen) {ooc_regen = newoocregen;}
|
||||
virtual void Heal();
|
||||
virtual void HealDamage(uint32 ammount, Mob* caster = nullptr, uint16 spell_id = SPELL_UNKNOWN);
|
||||
virtual void SetMaxHP() { cur_hp = max_hp; }
|
||||
virtual void SetMaxHP() { current_hp = max_hp; }
|
||||
virtual inline uint16 GetBaseRace() const { return base_race; }
|
||||
virtual inline uint8 GetBaseGender() const { return base_gender; }
|
||||
virtual uint16 GetFactionRace();
|
||||
virtual inline uint16 GetDeity() const { return deity; }
|
||||
virtual EQEmu::deity::DeityTypeBit GetDeityBit() { return EQEmu::deity::ConvertDeityTypeToDeityTypeBit((EQEmu::deity::DeityType)deity); }
|
||||
inline uint16 GetRace() const { return race; }
|
||||
@@ -439,6 +462,20 @@ public:
|
||||
inline uint8 GetDrakkinHeritage() const { return drakkin_heritage; }
|
||||
inline uint8 GetDrakkinTattoo() const { return drakkin_tattoo; }
|
||||
inline uint8 GetDrakkinDetails() const { return drakkin_details; }
|
||||
inline void ChangeRace(uint16 in) { race = in; }
|
||||
inline void ChangeGender(uint8 in) { gender = in;}
|
||||
inline void ChangeTexture(uint8 in) { texture = in; }
|
||||
inline void ChangeHelmTexture(uint8 in) { helmtexture = in; }
|
||||
inline void ChangeHairColor(uint8 in) { haircolor = in; }
|
||||
inline void ChangeBeardColor(uint8 in) { beardcolor = in; }
|
||||
inline void ChangeEyeColor1(uint8 in) { eyecolor1 = in; }
|
||||
inline void ChangeEyeColor2(uint8 in) { eyecolor2 = in; }
|
||||
inline void ChangeHairStyle(uint8 in) { hairstyle = in; }
|
||||
inline void ChangeLuclinFace(uint8 in) { luclinface = in; }
|
||||
inline void ChangeBeard(uint8 in) { beard = in; }
|
||||
inline void ChangeDrakkinHeritage(uint8 in) { drakkin_heritage = in; }
|
||||
inline void ChangeDrakkinTattoo(uint8 in) { drakkin_tattoo = in; }
|
||||
inline void ChangeDrakkinDetails(uint8 in) { drakkin_details = in; }
|
||||
inline uint32 GetArmorTint(uint8 i) const { return armor_tint.Slot[(i < EQEmu::textures::materialCount) ? i : 0].Color; }
|
||||
inline uint8 GetClass() const { return class_; }
|
||||
inline uint8 GetLevel() const { return level; }
|
||||
@@ -452,8 +489,8 @@ public:
|
||||
inline Mob* GetTarget() const { return target; }
|
||||
virtual void SetTarget(Mob* mob);
|
||||
inline bool HasTargetReflection() const { return (target && target != this && target->target == this); }
|
||||
virtual inline float GetHPRatio() const { return max_hp == 0 ? 0 : ((float)cur_hp/max_hp*100); }
|
||||
virtual inline int GetIntHPRatio() const { return max_hp == 0 ? 0 : static_cast<int>(cur_hp * 100 / max_hp); }
|
||||
virtual inline float GetHPRatio() const { return max_hp == 0 ? 0 : ((float)current_hp/max_hp*100); }
|
||||
virtual inline int GetIntHPRatio() const { return max_hp == 0 ? 0 : static_cast<int>(current_hp * 100 / max_hp); }
|
||||
inline int32 GetAC() const { return AC; }
|
||||
inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK; }
|
||||
inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; }
|
||||
@@ -464,6 +501,11 @@ public:
|
||||
inline virtual int32 GetINT() const { return INT + itembonuses.INT + spellbonuses.INT; }
|
||||
inline virtual int32 GetWIS() const { return WIS + itembonuses.WIS + spellbonuses.WIS; }
|
||||
inline virtual int32 GetCHA() const { return CHA + itembonuses.CHA + spellbonuses.CHA; }
|
||||
inline virtual int32 GetHeroicMR() const { return 0; }
|
||||
inline virtual int32 GetHeroicFR() const { return 0; }
|
||||
inline virtual int32 GetHeroicDR() const { return 0; }
|
||||
inline virtual int32 GetHeroicPR() const { return 0; }
|
||||
inline virtual int32 GetHeroicCR() const { return 0; }
|
||||
inline virtual int32 GetMR() const { return MR + itembonuses.MR + spellbonuses.MR; }
|
||||
inline virtual int32 GetFR() const { return FR + itembonuses.FR + spellbonuses.FR; }
|
||||
inline virtual int32 GetDR() const { return DR + itembonuses.DR + spellbonuses.DR; }
|
||||
@@ -477,6 +519,13 @@ public:
|
||||
inline StatBonuses* GetItemBonusesPtr() { return &itembonuses; }
|
||||
inline StatBonuses* GetSpellBonusesPtr() { return &spellbonuses; }
|
||||
inline StatBonuses* GetAABonusesPtr() { return &aabonuses; }
|
||||
inline virtual int32 GetHeroicSTR() const { return 0; }
|
||||
inline virtual int32 GetHeroicSTA() const { return 0; }
|
||||
inline virtual int32 GetHeroicDEX() const { return 0; }
|
||||
inline virtual int32 GetHeroicAGI() const { return 0; }
|
||||
inline virtual int32 GetHeroicINT() const { return 0; }
|
||||
inline virtual int32 GetHeroicWIS() const { return 0; }
|
||||
inline virtual int32 GetHeroicCHA() const { return 0; }
|
||||
inline virtual int32 GetMaxSTR() const { return GetSTR(); }
|
||||
inline virtual int32 GetMaxSTA() const { return GetSTA(); }
|
||||
inline virtual int32 GetMaxDEX() const { return GetDEX(); }
|
||||
@@ -490,12 +539,13 @@ public:
|
||||
inline virtual int32 GetMaxCR() const { return 255; }
|
||||
inline virtual int32 GetMaxFR() const { return 255; }
|
||||
inline virtual int32 GetDelayDeath() const { return 0; }
|
||||
inline int32 GetHP() const { return cur_hp; }
|
||||
inline int32 GetHP() const { return current_hp; }
|
||||
inline int32 GetMaxHP() const { return max_hp; }
|
||||
virtual int32 CalcMaxHP();
|
||||
inline int32 GetMaxMana() const { return max_mana; }
|
||||
inline int32 GetMana() const { return current_mana; }
|
||||
virtual int32 GetEndurance() const { return 0; }
|
||||
virtual int32 GetMaxEndurance() const { return 0; }
|
||||
virtual void SetEndurance(int32 newEnd) { return; }
|
||||
int32 GetItemHPBonuses();
|
||||
int32 GetSpellHPBonuses();
|
||||
@@ -506,21 +556,14 @@ public:
|
||||
uint32 GetNPCTypeID() const { return npctype_id; }
|
||||
void SetNPCTypeID(uint32 npctypeid) { npctype_id = npctypeid; }
|
||||
inline const glm::vec4& GetPosition() const { return m_Position; }
|
||||
inline void SetPosition(const float x, const float y, const float z) { m_Position.x = x; m_Position.y = y; m_Position.z = z; }
|
||||
inline const float GetX() const { return m_Position.x; }
|
||||
inline const float GetY() const { return m_Position.y; }
|
||||
inline const float GetZ() const { return m_Position.z; }
|
||||
inline const float GetHeading() const { return m_Position.w; }
|
||||
inline const float GetSize() const { return size; }
|
||||
inline const float GetBaseSize() const { return base_size; }
|
||||
inline const float GetTarX() const { return m_TargetLocation.x; }
|
||||
inline const float GetTarY() const { return m_TargetLocation.y; }
|
||||
inline const float GetTarZ() const { return m_TargetLocation.z; }
|
||||
inline const float GetTarVX() const { return m_TargetV.x; }
|
||||
inline const float GetTarVY() const { return m_TargetV.y; }
|
||||
inline const float GetTarVZ() const { return m_TargetV.z; }
|
||||
inline const float GetTarVector() const { return tar_vector; }
|
||||
inline const uint8 GetTarNDX() const { return tar_ndx; }
|
||||
inline const int8 GetFlyMode() const { return flymode; }
|
||||
inline const GravityBehavior GetFlyMode() const { return flymode; }
|
||||
bool IsBoat() const;
|
||||
|
||||
//Group
|
||||
@@ -533,14 +576,12 @@ public:
|
||||
virtual inline int32 GetPrimaryFaction() const { return 0; }
|
||||
|
||||
//Movement
|
||||
void Warp(const glm::vec3& location);
|
||||
inline bool IsMoving() const { return moving; }
|
||||
virtual void SetMoving(bool move) { moving = move; m_Delta = glm::vec4(); }
|
||||
virtual void GoToBind(uint8 bindnum = 0) { }
|
||||
virtual void Gate(uint8 bindnum = 0);
|
||||
int GetWalkspeed() const { return(_GetWalkSpeed()); }
|
||||
int GetRunspeed() const { return(_GetRunSpeed()); }
|
||||
void SetCurrentSpeed(int in);
|
||||
virtual int GetWalkspeed() const { return(_GetWalkSpeed()); }
|
||||
virtual int GetRunspeed() const { return(_GetRunSpeed()); }
|
||||
int GetBaseRunspeed() const { return base_runspeed; }
|
||||
int GetBaseWalkspeed() const { return base_walkspeed; }
|
||||
int GetBaseFearSpeed() const { return base_fearspeed; }
|
||||
@@ -549,18 +590,24 @@ public:
|
||||
void SetRunning(bool val) { m_is_running = val; }
|
||||
virtual void GMMove(float x, float y, float z, float heading = 0.01, bool SendUpdate = true);
|
||||
void SetDelta(const glm::vec4& delta);
|
||||
void SetTargetDestSteps(uint8 target_steps) { tar_ndx = target_steps; }
|
||||
void SendPositionUpdateToClient(Client *client);
|
||||
void SendPositionUpdate(uint8 iSendToSelf = 0);
|
||||
void MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct* spu);
|
||||
void MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu);
|
||||
void SendPosition();
|
||||
void SentPositionPacket(float dx, float dy, float dz, float dh, int anim, bool send_to_self = false);
|
||||
void StopMoving();
|
||||
void StopMoving(float new_heading);
|
||||
void SetSpawned() { spawned = true; };
|
||||
bool Spawned() { return spawned; };
|
||||
virtual bool ShouldISpawnFor(Client *c) { return true; }
|
||||
void SetFlyMode(uint8 flymode);
|
||||
inline void Teleport(glm::vec3 NewPosition) { m_Position.x = NewPosition.x; m_Position.y = NewPosition.y;
|
||||
m_Position.z = NewPosition.z; };
|
||||
void SetFlyMode(GravityBehavior flymode);
|
||||
void Teleport(const glm::vec3 &pos);
|
||||
void Teleport(const glm::vec4 &pos);
|
||||
void TryMoveAlong(float distance, float angle, bool send = true);
|
||||
void ProcessForcedMovement();
|
||||
inline void IncDeltaX(float in) { m_Delta.x += in; }
|
||||
inline void IncDeltaY(float in) { m_Delta.y += in; }
|
||||
inline void IncDeltaZ(float in) { m_Delta.z += in; }
|
||||
inline void SetForcedMovement(int in) { ForcedMovement = in; }
|
||||
void SetHeading(float iHeading) { m_Position.w = iHeading; }
|
||||
|
||||
//AI
|
||||
static uint32 GetLevelCon(uint8 mylevel, uint8 iOtherLevel);
|
||||
@@ -587,8 +634,6 @@ public:
|
||||
void SetAssistAggro(bool value) { AssistAggro = value; if (PrimaryAggro) AssistAggro = false; }
|
||||
bool HateSummon();
|
||||
void FaceTarget(Mob* mob_to_face = 0);
|
||||
void SetHeading(float iHeading) { if(m_Position.w != iHeading) { pLastChange = Timer::GetCurrentTime();
|
||||
m_Position.w = iHeading; } }
|
||||
void WipeHateList();
|
||||
void AddFeignMemory(Client* attacker);
|
||||
void RemoveFromFeignMemory(Client* attacker);
|
||||
@@ -598,8 +643,7 @@ public:
|
||||
std::list<struct_HateList*>& GetHateList() { return hate_list.GetHateList(); }
|
||||
bool CheckLosFN(Mob* other);
|
||||
bool CheckLosFN(float posX, float posY, float posZ, float mobSize);
|
||||
inline void SetChanged() { pLastChange = Timer::GetCurrentTime(); }
|
||||
inline const uint32 LastChange() const { return pLastChange; }
|
||||
static bool CheckLosFN(glm::vec3 posWatcher, float sizeWatcher, glm::vec3 posTarget, float sizeTarget);
|
||||
inline void SetLastLosState(bool value) { last_los_check = value; }
|
||||
inline bool CheckLastLosState() const { return last_los_check; }
|
||||
|
||||
@@ -649,7 +693,7 @@ public:
|
||||
inline AuraMgr &GetAuraMgr() { return aura_mgr; } // mainly used for zone db loading/saving
|
||||
|
||||
//Procs
|
||||
void TriggerDefensiveProcs(Mob *on, uint16 hand = EQEmu::inventory::slotPrimary, bool FromSkillProc = false, int damage = 0);
|
||||
void TriggerDefensiveProcs(Mob *on, uint16 hand = EQEmu::invslot::slotPrimary, bool FromSkillProc = false, int damage = 0);
|
||||
bool AddRangedProc(uint16 spell_id, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN);
|
||||
bool RemoveRangedProc(uint16 spell_id, bool bAll = false);
|
||||
bool HasRangedProcs() const;
|
||||
@@ -668,10 +712,14 @@ public:
|
||||
virtual bool IsAttackAllowed(Mob *target, bool isSpellAttack = false);
|
||||
bool IsTargeted() const { return (targeted > 0); }
|
||||
inline void IsTargeted(int in_tar) { targeted += in_tar; if(targeted < 0) targeted = 0;}
|
||||
void SetFollowID(uint32 id) { follow = id; }
|
||||
void SetFollowID(uint32 id) { follow_id = id; }
|
||||
void SetFollowDistance(uint32 dist) { follow_dist = dist; }
|
||||
uint32 GetFollowID() const { return follow; }
|
||||
void SetFollowCanRun(bool v) { follow_run = v; }
|
||||
uint32 GetFollowID() const { return follow_id; }
|
||||
uint32 GetFollowDistance() const { return follow_dist; }
|
||||
bool GetFollowCanRun() const { return follow_run; }
|
||||
inline bool IsRareSpawn() const { return rare_spawn; }
|
||||
inline void SetRareSpawn(bool in) { rare_spawn = in; }
|
||||
|
||||
virtual void Message(uint32 type, const char* message, ...) { }
|
||||
virtual void Message_StringID(uint32 type, uint32 string_id, uint32 distance = 0) { }
|
||||
@@ -785,8 +833,10 @@ public:
|
||||
void SendAppearancePacket(uint32 type, uint32 value, bool WholeZone = true, bool iIgnoreSelf = false, Client *specific_target=nullptr);
|
||||
void SetAppearance(EmuAppearance app, bool iIgnoreSelf = true);
|
||||
inline EmuAppearance GetAppearance() const { return _appearance; }
|
||||
inline const int GetAnimation() const { return animation; }
|
||||
inline void SetAnimation(int a) { animation = a; }
|
||||
inline const uint8 GetRunAnimSpeed() const { return pRunAnimSpeed; }
|
||||
inline void SetRunAnimSpeed(int8 in) { if (pRunAnimSpeed != in) { pRunAnimSpeed = in; pLastChange = Timer::GetCurrentTime(); } }
|
||||
inline void SetRunAnimSpeed(int8 in) { pRunAnimSpeed = in; }
|
||||
bool IsDestructibleObject() { return destructibleobject; }
|
||||
void SetDestructibleObject(bool in) { destructibleobject = in; }
|
||||
|
||||
@@ -951,16 +1001,24 @@ public:
|
||||
inline bool IsBlind() { return spellbonuses.IsBlind; }
|
||||
|
||||
inline bool CheckAggro(Mob* other) {return hate_list.IsEntOnHateList(other);}
|
||||
float CalculateHeadingToTarget(float in_x, float in_y);
|
||||
bool CalculateNewPosition(float x, float y, float z, int speed, bool checkZ = false, bool calcheading = true);
|
||||
virtual bool CalculateNewPosition2(float x, float y, float z, int speed, bool checkZ = true, bool calcheading = true);
|
||||
float CalculateHeadingToTarget(float in_x, float in_y) { return HeadingAngleToMob(in_x, in_y); }
|
||||
virtual void WalkTo(float x, float y, float z);
|
||||
virtual void RunTo(float x, float y, float z);
|
||||
void NavigateTo(float x, float y, float z);
|
||||
void RotateTo(float new_heading);
|
||||
void RotateToWalking(float new_heading);
|
||||
void RotateToRunning(float new_heading);
|
||||
void StopNavigation();
|
||||
float CalculateDistance(float x, float y, float z);
|
||||
float GetGroundZ(float new_x, float new_y, float z_offset=0.0);
|
||||
void SendTo(float new_x, float new_y, float new_z);
|
||||
void SendToFixZ(float new_x, float new_y, float new_z);
|
||||
float GetZOffset() const;
|
||||
void FixZ(int32 z_find_offset = 5);
|
||||
float GetFixedZ(glm::vec3 position, int32 z_find_offset = 5);
|
||||
float GetDefaultRaceSize() const;
|
||||
void FixZ(int32 z_find_offset = 5, bool fix_client_z = false);
|
||||
float GetFixedZ(const glm::vec3 &destination, int32 z_find_offset = 5);
|
||||
virtual int GetStuckBehavior() const { return 0; }
|
||||
|
||||
void NPCSpecialAttacks(const char* parse, int permtag, bool reset = true, bool remove = false);
|
||||
inline uint32 DontHealMeBefore() const { return pDontHealMeBefore; }
|
||||
inline uint32 DontBuffMeBefore() const { return pDontBuffMeBefore; }
|
||||
@@ -1017,6 +1075,7 @@ public:
|
||||
inline bool Sanctuary() const { return spellbonuses.Sanctuary; }
|
||||
|
||||
bool HasNPCSpecialAtk(const char* parse);
|
||||
bool HasSpecialAbilities();
|
||||
int GetSpecialAbility(int ability);
|
||||
int GetSpecialAbilityParam(int ability, int param);
|
||||
void SetSpecialAbility(int ability, int level);
|
||||
@@ -1035,9 +1094,10 @@ public:
|
||||
inline glm::vec4 GetCurrentWayPoint() const { return m_CurrentWayPoint; }
|
||||
inline float GetCWPP() const { return(static_cast<float>(cur_wp_pause)); }
|
||||
inline int GetCWP() const { return(cur_wp); }
|
||||
void SetCurrentWP(uint16 waypoint) { cur_wp = waypoint; }
|
||||
void SetCurrentWP(int waypoint) { cur_wp = waypoint; }
|
||||
virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther) { return FACTION_INDIFFERENT; }
|
||||
|
||||
virtual const bool IsUnderwaterOnly() const { return false; }
|
||||
inline bool IsTrackable() const { return(trackable); }
|
||||
Timer* GetAIThinkTimer() { return AI_think_timer.get(); }
|
||||
Timer* GetAIMovementTimer() { return AI_movement_timer.get(); }
|
||||
@@ -1114,6 +1174,10 @@ public:
|
||||
int GetWeaponDamage(Mob *against, const EQEmu::ItemData *weapon_item);
|
||||
int GetWeaponDamage(Mob *against, const EQEmu::ItemInstance *weapon_item, uint32 *hate = nullptr);
|
||||
|
||||
int32 GetHPRegen() const;
|
||||
int32 GetManaRegen() const;
|
||||
|
||||
|
||||
// Bots HealRotation methods
|
||||
#ifdef BOTS
|
||||
bool IsHealRotationTarget() { return (m_target_of_heal_rotation.use_count() && m_target_of_heal_rotation.get()); }
|
||||
@@ -1135,7 +1199,6 @@ protected:
|
||||
int _GetWalkSpeed() const;
|
||||
int _GetRunSpeed() const;
|
||||
int _GetFearSpeed() const;
|
||||
virtual bool MakeNewPositionAndSendUpdate(float x, float y, float z, int speed);
|
||||
|
||||
virtual bool AI_EngagedCastCheck() { return(false); }
|
||||
virtual bool AI_PursueCastCheck() { return(false); }
|
||||
@@ -1186,14 +1249,14 @@ protected:
|
||||
int targeted;
|
||||
bool findable;
|
||||
bool trackable;
|
||||
int32 cur_hp;
|
||||
int32 current_hp;
|
||||
int32 max_hp;
|
||||
int32 base_hp;
|
||||
int32 current_mana;
|
||||
int32 max_mana;
|
||||
int32 hp_regen;
|
||||
int32 mana_regen;
|
||||
int32 oocregen;
|
||||
int32 ooc_regen;
|
||||
uint8 maxlevel;
|
||||
uint32 scalerate;
|
||||
Buffs_Struct *buffs;
|
||||
@@ -1205,9 +1268,11 @@ protected:
|
||||
uint16 ownerid;
|
||||
PetType typeofpet;
|
||||
int16 petpower;
|
||||
uint32 follow;
|
||||
uint32 follow_id;
|
||||
uint32 follow_dist;
|
||||
bool follow_run;
|
||||
bool no_target_hotkey;
|
||||
bool rare_spawn;
|
||||
|
||||
uint32 m_PlayerState;
|
||||
uint32 GetPlayerState() { return m_PlayerState; }
|
||||
@@ -1218,6 +1283,7 @@ protected:
|
||||
|
||||
uint8 gender;
|
||||
uint16 race;
|
||||
uint16 use_model;
|
||||
uint8 base_gender;
|
||||
uint16 base_race;
|
||||
uint8 class_;
|
||||
@@ -1227,10 +1293,8 @@ protected:
|
||||
uint8 level;
|
||||
uint8 orig_level;
|
||||
uint32 npctype_id;
|
||||
glm::vec4 m_Position;
|
||||
/* Used to determine when an NPC has traversed so many units - to send a zone wide pos update */
|
||||
glm::vec4 last_major_update_position;
|
||||
|
||||
glm::vec4 m_Position;
|
||||
int animation; // this is really what MQ2 calls SpeedRun just packed like (int)(SpeedRun * 40.0f)
|
||||
float base_size;
|
||||
float size;
|
||||
@@ -1243,7 +1307,6 @@ protected:
|
||||
int current_speed;
|
||||
eSpecialAttacks m_specialattacks;
|
||||
|
||||
uint32 pLastChange;
|
||||
bool held;
|
||||
bool gheld;
|
||||
bool nocast;
|
||||
@@ -1256,13 +1319,13 @@ protected:
|
||||
void TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success = false, uint16 hand = 0, bool IsDefensive = false); // hand = SlotCharm?
|
||||
bool PassLimitToSkill(uint16 spell_id, uint16 skill);
|
||||
bool PassLimitClass(uint32 Classes_, uint16 Class_);
|
||||
void TryDefensiveProc(Mob *on, uint16 hand = EQEmu::inventory::slotPrimary);
|
||||
void TryWeaponProc(const EQEmu::ItemInstance* inst, const EQEmu::ItemData* weapon, Mob *on, uint16 hand = EQEmu::inventory::slotPrimary);
|
||||
void TrySpellProc(const EQEmu::ItemInstance* inst, const EQEmu::ItemData* weapon, Mob *on, uint16 hand = EQEmu::inventory::slotPrimary);
|
||||
void TryWeaponProc(const EQEmu::ItemInstance* weapon, Mob *on, uint16 hand = EQEmu::inventory::slotPrimary);
|
||||
void TryDefensiveProc(Mob *on, uint16 hand = EQEmu::invslot::slotPrimary);
|
||||
void TryWeaponProc(const EQEmu::ItemInstance* inst, const EQEmu::ItemData* weapon, Mob *on, uint16 hand = EQEmu::invslot::slotPrimary);
|
||||
void TrySpellProc(const EQEmu::ItemInstance* inst, const EQEmu::ItemData* weapon, Mob *on, uint16 hand = EQEmu::invslot::slotPrimary);
|
||||
void TryWeaponProc(const EQEmu::ItemInstance* weapon, Mob *on, uint16 hand = EQEmu::invslot::slotPrimary);
|
||||
void ExecWeaponProc(const EQEmu::ItemInstance* weapon, uint16 spell_id, Mob *on, int level_override = -1);
|
||||
virtual float GetProcChances(float ProcBonus, uint16 hand = EQEmu::inventory::slotPrimary);
|
||||
virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 hand = EQEmu::inventory::slotPrimary, Mob *on = nullptr);
|
||||
virtual float GetProcChances(float ProcBonus, uint16 hand = EQEmu::invslot::slotPrimary);
|
||||
virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 hand = EQEmu::invslot::slotPrimary, Mob *on = nullptr);
|
||||
virtual float GetSkillProcChances(uint16 ReuseTime, uint16 hand = 0); // hand = MainCharm?
|
||||
uint16 GetWeaponSpeedbyHand(uint16 hand);
|
||||
#ifdef BOTS
|
||||
@@ -1273,8 +1336,6 @@ protected:
|
||||
void CalculateNewFearpoint();
|
||||
float FindGroundZ(float new_x, float new_y, float z_offset=0.0);
|
||||
float FindDestGroundZ(glm::vec3 dest, float z_offset=0.0);
|
||||
glm::vec3 UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChange, bool &NodeReached);
|
||||
void PrintRoute();
|
||||
|
||||
virtual float GetSympatheticProcChances(uint16 spell_id, int16 ProcRateMod, int32 ItemProcRate = 0);
|
||||
int16 GetSympatheticSpellProcRate(uint16 spell_id);
|
||||
@@ -1292,6 +1353,9 @@ protected:
|
||||
char lastname[64];
|
||||
|
||||
glm::vec4 m_Delta;
|
||||
// just locs around them to double check, if we do expand collision this should be cached on movement
|
||||
// ideally we should use real models, but this should be quick and work mostly
|
||||
glm::vec4 m_CollisionBox[COLLISION_BOX_SIZE];
|
||||
|
||||
EQEmu::LightSourceProfile m_Light;
|
||||
|
||||
@@ -1316,7 +1380,7 @@ protected:
|
||||
int attacked_count;
|
||||
bool delaytimer;
|
||||
uint16 casting_spell_targetid;
|
||||
EQEmu::CastingSlot casting_spell_slot;
|
||||
EQEmu::spells::CastingSlot casting_spell_slot;
|
||||
uint16 casting_spell_mana;
|
||||
uint32 casting_spell_inventory_slot;
|
||||
uint32 casting_spell_timer;
|
||||
@@ -1326,7 +1390,7 @@ protected:
|
||||
uint32 casting_spell_aa_id;
|
||||
bool casting_spell_checks;
|
||||
uint16 bardsong;
|
||||
EQEmu::CastingSlot bardsong_slot;
|
||||
EQEmu::spells::CastingSlot bardsong_slot;
|
||||
uint32 bardsong_target_id;
|
||||
|
||||
bool ActiveProjectileATK;
|
||||
@@ -1380,6 +1444,13 @@ protected:
|
||||
bool pseudo_rooted;
|
||||
bool endur_upkeep;
|
||||
bool degenerating_effects; // true if we have a buff that needs to be recalced every tick
|
||||
bool spawned_in_water;
|
||||
public:
|
||||
bool GetWasSpawnedInWater() const;
|
||||
|
||||
void SetSpawnedInWater(bool spawned_in_water);
|
||||
|
||||
protected:
|
||||
|
||||
// Bind wound
|
||||
Timer bindwound_timer;
|
||||
@@ -1401,13 +1472,14 @@ protected:
|
||||
std::unique_ptr<Timer> AI_think_timer;
|
||||
std::unique_ptr<Timer> AI_movement_timer;
|
||||
std::unique_ptr<Timer> AI_target_check_timer;
|
||||
bool movetimercompleted;
|
||||
int8 ForcedMovement; // push
|
||||
bool permarooted;
|
||||
std::unique_ptr<Timer> AI_scan_area_timer;
|
||||
std::unique_ptr<Timer> AI_walking_timer;
|
||||
std::unique_ptr<Timer> AI_feign_remember_timer;
|
||||
std::unique_ptr<Timer> AI_check_signal_timer;
|
||||
uint32 pLastFightingDelayMoving;
|
||||
std::unique_ptr<Timer> AI_scan_door_open_timer;
|
||||
uint32 time_until_can_move;
|
||||
HateList hate_list;
|
||||
std::set<uint32> feign_memory_list;
|
||||
// This is to keep track of mobs we cast faction mod spells on
|
||||
@@ -1419,19 +1491,15 @@ protected:
|
||||
void AddItemFactionBonus(uint32 pFactionID,int32 bonus);
|
||||
int32 GetItemFactionBonus(uint32 pFactionID);
|
||||
void ClearItemFactionBonuses();
|
||||
|
||||
void CalculateFearPosition();
|
||||
Timer hate_list_cleanup_timer;
|
||||
|
||||
bool flee_mode;
|
||||
Timer flee_timer;
|
||||
Timer fix_z_timer;
|
||||
Timer fix_z_timer_engaged;
|
||||
Timer attack_anim_timer;
|
||||
Timer position_update_melee_push_timer;
|
||||
|
||||
bool pAIControlled;
|
||||
bool roamer;
|
||||
bool logging_enabled;
|
||||
|
||||
int wandertype;
|
||||
int pausetype;
|
||||
@@ -1448,25 +1516,12 @@ protected:
|
||||
int npc_assist_cap;
|
||||
Timer assist_cap_timer; // clear assist cap so more nearby mobs can be called for help
|
||||
|
||||
|
||||
int patrol;
|
||||
glm::vec3 m_FearWalkTarget;
|
||||
bool currently_fleeing;
|
||||
|
||||
// Pathing
|
||||
//
|
||||
glm::vec3 PathingDestination;
|
||||
glm::vec3 PathingLastPosition;
|
||||
int PathingLoopCount;
|
||||
int PathingLastNodeVisited;
|
||||
std::deque<int> Route;
|
||||
LOSType PathingLOSState;
|
||||
Timer *PathingLOSCheckTimer;
|
||||
Timer *PathingRouteUpdateTimerShort;
|
||||
Timer *PathingRouteUpdateTimerLong;
|
||||
bool pause_timer_complete;
|
||||
bool DistractedFromGrid;
|
||||
int PathingTraversedNodes;
|
||||
|
||||
uint32 pDontHealMeBefore;
|
||||
uint32 pDontBuffMeBefore;
|
||||
uint32 pDontDotMeBefore;
|
||||
@@ -1485,18 +1540,11 @@ protected:
|
||||
bool pet_owner_client; //Flags regular and pets as belonging to a client
|
||||
uint32 pet_targetlock_id;
|
||||
|
||||
EGNode *_egnode; //the EG node we are in
|
||||
glm::vec3 m_TargetLocation;
|
||||
uint8 tar_ndx;
|
||||
float tar_vector;
|
||||
glm::vec3 m_TargetV;
|
||||
float test_vector;
|
||||
|
||||
glm::vec3 m_TargetRing;
|
||||
|
||||
// we might want to do this differently, we gotta do max NPC buffs ... which is 97
|
||||
uint32 m_spellHitsLeft[EQEmu::constants::TotalBuffs]; // Used to track which spells will have their numhits incremented when spell finishes casting
|
||||
int flymode;
|
||||
uint32 m_spellHitsLeft[EQEmu::spells::TOTAL_BUFFS]; // Used to track which spells will have their numhits incremented when spell finishes casting
|
||||
GravityBehavior flymode;
|
||||
bool m_targetable;
|
||||
int QGVarDuration(const char *fmt);
|
||||
void InsertQuestGlobal(int charid, int npcid, int zoneid, const char *name, const char *value, int expdate);
|
||||
@@ -1514,6 +1562,8 @@ protected:
|
||||
AuraMgr aura_mgr;
|
||||
AuraMgr trap_mgr;
|
||||
|
||||
MobMovementManager *mMovementManager;
|
||||
|
||||
private:
|
||||
void _StopSong(); //this is not what you think it is
|
||||
Mob* target;
|
||||
|
||||
+750
-663
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,548 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2018 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../common/eqemu_logsys.h"
|
||||
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/spdat.h"
|
||||
#include "../common/string_util.h"
|
||||
|
||||
#include "mob.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "zonedb.h"
|
||||
|
||||
#ifdef BOTS
|
||||
#include "bot.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Stores internal representation of mob texture by material slot
|
||||
*
|
||||
* @param material_slot
|
||||
* @param texture
|
||||
* @param color
|
||||
* @param hero_forge_model
|
||||
*/
|
||||
void Mob::SetMobTextureProfile(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model)
|
||||
{
|
||||
Log(Logs::Detail, Logs::MobAppearance,
|
||||
"Mob::SetMobTextureProfile [%s] material_slot: %u texture: %u color: %u hero_forge_model: %u",
|
||||
this->GetCleanName(),
|
||||
material_slot,
|
||||
texture,
|
||||
color,
|
||||
hero_forge_model
|
||||
);
|
||||
|
||||
switch (material_slot) {
|
||||
case EQEmu::textures::armorHead:
|
||||
mob_texture_profile.Head.Material = texture;
|
||||
mob_texture_profile.Head.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Head.Color = color;
|
||||
break;
|
||||
case EQEmu::textures::armorChest:
|
||||
mob_texture_profile.Chest.Material = texture;
|
||||
mob_texture_profile.Chest.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Chest.Color = color;
|
||||
break;
|
||||
case EQEmu::textures::armorArms:
|
||||
mob_texture_profile.Arms.Material = texture;
|
||||
mob_texture_profile.Arms.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Arms.Color = color;
|
||||
break;
|
||||
case EQEmu::textures::armorWrist:
|
||||
mob_texture_profile.Wrist.Material = texture;
|
||||
mob_texture_profile.Wrist.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Wrist.Color = color;
|
||||
break;
|
||||
case EQEmu::textures::armorHands:
|
||||
mob_texture_profile.Hands.Material = texture;
|
||||
mob_texture_profile.Hands.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Hands.Color = color;
|
||||
break;
|
||||
case EQEmu::textures::armorLegs:
|
||||
mob_texture_profile.Legs.Material = texture;
|
||||
mob_texture_profile.Legs.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Legs.Color = color;
|
||||
break;
|
||||
case EQEmu::textures::armorFeet:
|
||||
mob_texture_profile.Feet.Material = texture;
|
||||
mob_texture_profile.Feet.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Feet.Color = color;
|
||||
break;
|
||||
case EQEmu::textures::weaponPrimary:
|
||||
mob_texture_profile.Primary.Material = texture;
|
||||
mob_texture_profile.Primary.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Primary.Color = color;
|
||||
break;
|
||||
case EQEmu::textures::weaponSecondary:
|
||||
mob_texture_profile.Secondary.Material = texture;
|
||||
mob_texture_profile.Secondary.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Secondary.Color = color;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns internal representation of mob texture by material
|
||||
*
|
||||
* @param material_slot
|
||||
* @return
|
||||
*/
|
||||
int32 Mob::GetTextureProfileMaterial(uint8 material_slot) const
|
||||
{
|
||||
switch (material_slot) {
|
||||
case EQEmu::textures::armorHead:
|
||||
return mob_texture_profile.Head.Material;
|
||||
case EQEmu::textures::armorChest:
|
||||
return mob_texture_profile.Chest.Material;
|
||||
case EQEmu::textures::armorArms:
|
||||
return mob_texture_profile.Arms.Material;
|
||||
case EQEmu::textures::armorWrist:
|
||||
return mob_texture_profile.Wrist.Material;
|
||||
case EQEmu::textures::armorHands:
|
||||
return mob_texture_profile.Hands.Material;
|
||||
case EQEmu::textures::armorLegs:
|
||||
return mob_texture_profile.Legs.Material;
|
||||
case EQEmu::textures::armorFeet:
|
||||
return mob_texture_profile.Feet.Material;
|
||||
case EQEmu::textures::weaponPrimary:
|
||||
return mob_texture_profile.Primary.Material;
|
||||
case EQEmu::textures::weaponSecondary:
|
||||
return mob_texture_profile.Secondary.Material;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns internal representation of mob texture by color
|
||||
*
|
||||
* @param material_slot
|
||||
* @return
|
||||
*/
|
||||
int32 Mob::GetTextureProfileColor(uint8 material_slot) const
|
||||
{
|
||||
switch (material_slot) {
|
||||
case EQEmu::textures::armorHead:
|
||||
return mob_texture_profile.Head.Color;
|
||||
case EQEmu::textures::armorChest:
|
||||
return mob_texture_profile.Chest.Color;
|
||||
case EQEmu::textures::armorArms:
|
||||
return mob_texture_profile.Arms.Color;
|
||||
case EQEmu::textures::armorWrist:
|
||||
return mob_texture_profile.Wrist.Color;
|
||||
case EQEmu::textures::armorHands:
|
||||
return mob_texture_profile.Hands.Color;
|
||||
case EQEmu::textures::armorLegs:
|
||||
return mob_texture_profile.Legs.Color;
|
||||
case EQEmu::textures::armorFeet:
|
||||
return mob_texture_profile.Feet.Color;
|
||||
case EQEmu::textures::weaponPrimary:
|
||||
return mob_texture_profile.Primary.Color;
|
||||
case EQEmu::textures::weaponSecondary:
|
||||
return mob_texture_profile.Secondary.Color;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns internal representation of mob texture by HerosForgeModel
|
||||
*
|
||||
* @param material_slot
|
||||
* @return
|
||||
*/
|
||||
int32 Mob::GetTextureProfileHeroForgeModel(uint8 material_slot) const
|
||||
{
|
||||
switch (material_slot) {
|
||||
case EQEmu::textures::armorHead:
|
||||
return mob_texture_profile.Head.HerosForgeModel;
|
||||
case EQEmu::textures::armorChest:
|
||||
return mob_texture_profile.Chest.HerosForgeModel;
|
||||
case EQEmu::textures::armorArms:
|
||||
return mob_texture_profile.Arms.HerosForgeModel;
|
||||
case EQEmu::textures::armorWrist:
|
||||
return mob_texture_profile.Wrist.HerosForgeModel;
|
||||
case EQEmu::textures::armorHands:
|
||||
return mob_texture_profile.Hands.HerosForgeModel;
|
||||
case EQEmu::textures::armorLegs:
|
||||
return mob_texture_profile.Legs.HerosForgeModel;
|
||||
case EQEmu::textures::armorFeet:
|
||||
return mob_texture_profile.Feet.HerosForgeModel;
|
||||
case EQEmu::textures::weaponPrimary:
|
||||
return mob_texture_profile.Primary.HerosForgeModel;
|
||||
case EQEmu::textures::weaponSecondary:
|
||||
return mob_texture_profile.Secondary.HerosForgeModel;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the material or texture for a slot (leather / plate etc.)
|
||||
*
|
||||
* @param material_slot
|
||||
* @return
|
||||
*/
|
||||
int32 Mob::GetEquipmentMaterial(uint8 material_slot) const
|
||||
{
|
||||
uint32 equipment_material = 0;
|
||||
int32 ornamentation_augment_type = RuleI(Character, OrnamentationAugmentType);
|
||||
|
||||
int32 texture_profile_material = GetTextureProfileMaterial(material_slot);
|
||||
|
||||
Log(Logs::Detail, Logs::MobAppearance,
|
||||
"Mob::GetEquipmentMaterial [%s] material_slot: %u texture_profile_material: %i",
|
||||
this->clean_name,
|
||||
material_slot,
|
||||
texture_profile_material
|
||||
);
|
||||
|
||||
if (texture_profile_material > 0) {
|
||||
return texture_profile_material;
|
||||
}
|
||||
|
||||
auto item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot));
|
||||
|
||||
if (item != nullptr) {
|
||||
|
||||
/**
|
||||
* Handle primary / secondary texture
|
||||
*/
|
||||
bool is_primary_or_secondary_weapon =
|
||||
material_slot == EQEmu::textures::weaponPrimary ||
|
||||
material_slot == EQEmu::textures::weaponSecondary;
|
||||
|
||||
if (is_primary_or_secondary_weapon) {
|
||||
if (this->IsClient()) {
|
||||
|
||||
int16 inventory_slot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
|
||||
if (inventory_slot == INVALID_INDEX) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const EQEmu::ItemInstance *item_instance = CastToClient()->m_inv[inventory_slot];
|
||||
if (item_instance) {
|
||||
if (item_instance->GetOrnamentationAug(ornamentation_augment_type)) {
|
||||
item = item_instance->GetOrnamentationAug(ornamentation_augment_type)->GetItem();
|
||||
if (item && strlen(item->IDFile) > 2) {
|
||||
equipment_material = atoi(&item->IDFile[2]);
|
||||
}
|
||||
}
|
||||
else if (item_instance->GetOrnamentationIDFile()) {
|
||||
equipment_material = item_instance->GetOrnamentationIDFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (equipment_material == 0 && strlen(item->IDFile) > 2) {
|
||||
equipment_material = atoi(&item->IDFile[2]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
equipment_material = item->Material;
|
||||
}
|
||||
}
|
||||
|
||||
return equipment_material;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param material_slot
|
||||
* @return
|
||||
*/
|
||||
uint32 Mob::GetEquipmentColor(uint8 material_slot) const
|
||||
{
|
||||
const EQEmu::ItemData *item = nullptr;
|
||||
|
||||
if (armor_tint.Slot[material_slot].Color) {
|
||||
return armor_tint.Slot[material_slot].Color;
|
||||
}
|
||||
|
||||
item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot));
|
||||
if (item != nullptr) {
|
||||
return item->Color;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param material_slot
|
||||
* @return
|
||||
*/
|
||||
int32 Mob::GetHerosForgeModel(uint8 material_slot) const
|
||||
{
|
||||
uint32 hero_model = 0;
|
||||
if (material_slot >= 0 && material_slot < EQEmu::textures::weaponPrimary) {
|
||||
uint32 ornamentation_aug_type = RuleI(Character, OrnamentationAugmentType);
|
||||
|
||||
const EQEmu::ItemData *item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot));
|
||||
int16 invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
|
||||
|
||||
if (item != nullptr && invslot != INVALID_INDEX) {
|
||||
if (IsClient()) {
|
||||
const EQEmu::ItemInstance *inst = CastToClient()->m_inv[invslot];
|
||||
if (inst) {
|
||||
if (inst->GetOrnamentationAug(ornamentation_aug_type)) {
|
||||
item = inst->GetOrnamentationAug(ornamentation_aug_type)->GetItem();
|
||||
hero_model = item->HerosForgeModel;
|
||||
}
|
||||
else if (inst->GetOrnamentHeroModel()) {
|
||||
hero_model = inst->GetOrnamentHeroModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hero_model == 0) {
|
||||
hero_model = item->HerosForgeModel;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsNPC()) {
|
||||
hero_model = CastToNPC()->GetHeroForgeModel();
|
||||
|
||||
/**
|
||||
* Robes require full model number, and should only be sent to chest, arms, wrists, and legs slots
|
||||
*/
|
||||
if (hero_model > 1000 && material_slot != 1 && material_slot != 2 && material_slot != 3 &&
|
||||
material_slot != 5) {
|
||||
hero_model = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-Convert Hero Model to match the slot
|
||||
*
|
||||
* Otherwise, use the exact Model if model is > 999
|
||||
* Robes for example are 11607 to 12107 in RoF
|
||||
*/
|
||||
if (hero_model > 0 && hero_model < 1000) {
|
||||
hero_model *= 100;
|
||||
hero_model += material_slot;
|
||||
}
|
||||
|
||||
return hero_model;
|
||||
}
|
||||
|
||||
uint32 NPC::GetEquippedItemFromTextureSlot(uint8 material_slot) const
|
||||
{
|
||||
if (material_slot > 8) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16 inventory_slot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
|
||||
if (inventory_slot == INVALID_INDEX) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return equipment[inventory_slot];
|
||||
}
|
||||
|
||||
/**
|
||||
* NPCs typically use this function for sending appearance
|
||||
* @param one_client
|
||||
*/
|
||||
void Mob::SendArmorAppearance(Client *one_client)
|
||||
{
|
||||
/**
|
||||
* one_client of 0 means sent to all clients
|
||||
*
|
||||
* Despite the fact that OP_NewSpawn and OP_ZoneSpawns include the
|
||||
* armor being worn and its mats, the client doesn't update the display
|
||||
* on arrival of these packets reliably.
|
||||
*
|
||||
* Send Wear changes if mob is a PC race and item is an armor slot.
|
||||
* The other packets work for primary/secondary.
|
||||
*/
|
||||
|
||||
Log(Logs::Detail, Logs::MobAppearance, "Mob::SendArmorAppearance [%s]",
|
||||
this->GetCleanName()
|
||||
);
|
||||
|
||||
if (IsPlayerRace(race)) {
|
||||
if (!IsClient()) {
|
||||
for (uint8 i = 0; i <= EQEmu::textures::materialCount; ++i) {
|
||||
const EQEmu::ItemData *item = database.GetItem(GetEquippedItemFromTextureSlot(i));
|
||||
if (item != nullptr) {
|
||||
SendWearChange(i, one_client);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i <= EQEmu::textures::materialCount; ++i) {
|
||||
if (GetTextureProfileMaterial(i)) {
|
||||
SendWearChange(i, one_client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param material_slot
|
||||
* @param one_client
|
||||
*/
|
||||
void Mob::SendWearChange(uint8 material_slot, Client *one_client)
|
||||
{
|
||||
auto packet = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
|
||||
auto *wear_change = (WearChange_Struct *) packet->pBuffer;
|
||||
|
||||
Log(Logs::Detail, Logs::MobAppearance, "Mob::SendWearChange [%s]",
|
||||
this->GetCleanName()
|
||||
);
|
||||
|
||||
wear_change->spawn_id = GetID();
|
||||
wear_change->material = static_cast<uint32>(GetEquipmentMaterial(material_slot));
|
||||
wear_change->elite_material = IsEliteMaterialItem(material_slot);
|
||||
wear_change->hero_forge_model = static_cast<uint32>(GetHerosForgeModel(material_slot));
|
||||
|
||||
#ifdef BOTS
|
||||
if (IsBot()) {
|
||||
auto item_inst = CastToBot()->GetBotItem(EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot));
|
||||
if (item_inst)
|
||||
wear_change->color.Color = item_inst->GetColor();
|
||||
else
|
||||
wear_change->color.Color = 0;
|
||||
}
|
||||
else {
|
||||
wear_change->color.Color = GetEquipmentColor(material_slot);
|
||||
}
|
||||
#else
|
||||
wear_change->color.Color = GetEquipmentColor(material_slot);
|
||||
#endif
|
||||
|
||||
wear_change->wear_slot_id = material_slot;
|
||||
|
||||
if (!one_client) {
|
||||
entity_list.QueueClients(this, packet);
|
||||
}
|
||||
else {
|
||||
one_client->QueuePacket(packet, false, Client::CLIENT_CONNECTED);
|
||||
}
|
||||
|
||||
safe_delete(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param slot
|
||||
* @param texture
|
||||
* @param hero_forge_model
|
||||
* @param elite_material
|
||||
* @param unknown06
|
||||
* @param unknown18
|
||||
*/
|
||||
void Mob::SendTextureWC(
|
||||
uint8 slot,
|
||||
uint16 texture,
|
||||
uint32 hero_forge_model,
|
||||
uint32 elite_material,
|
||||
uint32 unknown06,
|
||||
uint32 unknown18
|
||||
)
|
||||
{
|
||||
auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
|
||||
auto *wear_change = (WearChange_Struct *) outapp->pBuffer;
|
||||
|
||||
if (this->IsClient()) {
|
||||
wear_change->color.Color = GetEquipmentColor(slot);
|
||||
}
|
||||
else {
|
||||
wear_change->color.Color = this->GetArmorTint(slot);
|
||||
}
|
||||
|
||||
wear_change->spawn_id = this->GetID();
|
||||
wear_change->material = texture;
|
||||
wear_change->wear_slot_id = slot;
|
||||
wear_change->unknown06 = unknown06;
|
||||
wear_change->elite_material = elite_material;
|
||||
wear_change->hero_forge_model = hero_forge_model;
|
||||
wear_change->unknown18 = unknown18;
|
||||
|
||||
SetMobTextureProfile(slot, texture, wear_change->color.Color, hero_forge_model);
|
||||
|
||||
entity_list.QueueClients(this, outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param material_slot
|
||||
* @param red_tint
|
||||
* @param green_tint
|
||||
* @param blue_tint
|
||||
*/
|
||||
void Mob::SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint)
|
||||
{
|
||||
uint32 color;
|
||||
color = (red_tint & 0xFF) << 16;
|
||||
color |= (green_tint & 0xFF) << 8;
|
||||
color |= (blue_tint & 0xFF);
|
||||
color |= (color) ? (0xFF << 24) : 0;
|
||||
armor_tint.Slot[material_slot].Color = color;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
|
||||
auto *wc = (WearChange_Struct *) outapp->pBuffer;
|
||||
|
||||
wc->spawn_id = this->GetID();
|
||||
wc->material = GetEquipmentMaterial(material_slot);
|
||||
wc->hero_forge_model = GetHerosForgeModel(material_slot);
|
||||
wc->color.Color = color;
|
||||
wc->wear_slot_id = material_slot;
|
||||
|
||||
SetMobTextureProfile(material_slot, texture, color);
|
||||
|
||||
entity_list.QueueClients(this, outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param material_slot
|
||||
* @param texture
|
||||
* @param color
|
||||
* @param hero_forge_model
|
||||
*/
|
||||
void Mob::WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model)
|
||||
{
|
||||
armor_tint.Slot[material_slot].Color = color;
|
||||
|
||||
/**
|
||||
* Change internal values
|
||||
*/
|
||||
SetMobTextureProfile(material_slot, texture, color, hero_forge_model);
|
||||
|
||||
/**
|
||||
* Packet update
|
||||
*/
|
||||
auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
|
||||
auto *wear_change = (WearChange_Struct *) outapp->pBuffer;
|
||||
|
||||
wear_change->spawn_id = this->GetID();
|
||||
wear_change->material = texture;
|
||||
wear_change->hero_forge_model = hero_forge_model;
|
||||
wear_change->color.Color = color;
|
||||
wear_change->wear_slot_id = material_slot;
|
||||
|
||||
entity_list.QueueClients(this, outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
@@ -0,0 +1,835 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2018 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
#include "mob.h"
|
||||
#include "../common/races.h"
|
||||
#include "../common/say_link.h"
|
||||
#include "npc_scale_manager.h"
|
||||
|
||||
std::string commify(const std::string &number)
|
||||
{
|
||||
std::string temp_string;
|
||||
|
||||
auto string_length = static_cast<int>(number.length());
|
||||
|
||||
int i = 0;
|
||||
for (i = string_length - 3; i >= 0; i -= 3) {
|
||||
if (i > 0) {
|
||||
temp_string = "," + number.substr(static_cast<unsigned long>(i), 3) + temp_string;
|
||||
}
|
||||
else {
|
||||
temp_string = number.substr(static_cast<unsigned long>(i), 3) + temp_string;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < 0) {
|
||||
temp_string = number.substr(0, static_cast<unsigned long>(3 + i)) + temp_string;
|
||||
}
|
||||
|
||||
return temp_string;
|
||||
}
|
||||
|
||||
inline std::string GetMobAttributeByString(Mob *mob, const std::string &attribute)
|
||||
{
|
||||
std::string entity_variable = "modify_stat_" + attribute;
|
||||
std::string scaling_modified;
|
||||
if (mob->GetEntityVariable(entity_variable.c_str())) {
|
||||
scaling_modified = " *";
|
||||
}
|
||||
|
||||
if (attribute == "ac") {
|
||||
if (mob->GetEntityVariable(std::string("modify_stat_max_hp").c_str())) {
|
||||
scaling_modified = " *";
|
||||
}
|
||||
|
||||
return commify(std::to_string(mob->GetAC())) + scaling_modified;
|
||||
}
|
||||
|
||||
if (attribute == "atk") {
|
||||
return std::to_string(mob->GetATK()) + scaling_modified;
|
||||
}
|
||||
|
||||
if (attribute == "end") {
|
||||
int endurance = 0;
|
||||
if (mob->IsClient()) {
|
||||
endurance = mob->CastToClient()->GetEndurance();
|
||||
}
|
||||
|
||||
return commify(std::to_string(endurance));
|
||||
}
|
||||
|
||||
if (attribute == "hp") {
|
||||
return commify(std::to_string(mob->GetHP()));
|
||||
}
|
||||
|
||||
if (attribute == "hp_min_max") {
|
||||
if (mob->GetEntityVariable(std::string("modify_stat_max_hp").c_str())) {
|
||||
scaling_modified = " *";
|
||||
}
|
||||
|
||||
return commify(std::to_string(mob->GetHP())) + scaling_modified + " / " +
|
||||
commify(std::to_string(mob->GetMaxHP())) + " (" +
|
||||
std::to_string((int) mob->GetHPRatio()) + "%)";
|
||||
}
|
||||
|
||||
if (attribute == "mana") {
|
||||
return commify(std::to_string(mob->GetMana()));
|
||||
}
|
||||
|
||||
if (attribute == "mp_min_max") {
|
||||
return commify(std::to_string(mob->GetMana())) + " / " + commify(std::to_string(mob->GetMaxMana())) + " (" +
|
||||
std::to_string((int) mob->GetManaPercent()) + "%)";
|
||||
}
|
||||
|
||||
if (attribute == "end_min_max") {
|
||||
return commify(std::to_string(mob->GetEndurance())) + " / " + commify(std::to_string(mob->GetMaxEndurance())) + " (" +
|
||||
std::to_string((int)mob->GetEndurancePercent()) + "%)";
|
||||
}
|
||||
|
||||
if (attribute == "str") {
|
||||
return commify(std::to_string(mob->GetSTR())) + scaling_modified + " / " +
|
||||
commify(std::to_string(mob->GetMaxSTR())) + " +" +
|
||||
commify(std::to_string(mob->GetHeroicSTR()));
|
||||
}
|
||||
|
||||
if (attribute == "sta") {
|
||||
return commify(std::to_string(mob->GetSTA())) + scaling_modified + " / " +
|
||||
commify(std::to_string(mob->GetMaxSTA())) + " +" +
|
||||
commify(std::to_string(mob->GetHeroicSTA()));
|
||||
}
|
||||
|
||||
if (attribute == "dex") {
|
||||
return commify(std::to_string(mob->GetDEX())) + scaling_modified + " / " +
|
||||
commify(std::to_string(mob->GetMaxDEX())) + " +" +
|
||||
commify(std::to_string(mob->GetHeroicDEX()));
|
||||
}
|
||||
|
||||
if (attribute == "agi") {
|
||||
return commify(std::to_string(mob->GetAGI())) + scaling_modified + " / " +
|
||||
commify(std::to_string(mob->GetMaxAGI())) + " +" +
|
||||
commify(std::to_string(mob->GetHeroicAGI()));
|
||||
}
|
||||
|
||||
if (attribute == "int") {
|
||||
return commify(std::to_string(mob->GetINT())) + scaling_modified + " / " +
|
||||
commify(std::to_string(mob->GetMaxINT())) + " +" +
|
||||
commify(std::to_string(mob->GetHeroicINT()));
|
||||
}
|
||||
|
||||
if (attribute == "wis") {
|
||||
return commify(std::to_string(mob->GetWIS())) + scaling_modified + " / " +
|
||||
commify(std::to_string(mob->GetMaxWIS())) + " +" +
|
||||
commify(std::to_string(mob->GetHeroicWIS()));
|
||||
}
|
||||
|
||||
if (attribute == "cha") {
|
||||
return commify(std::to_string(mob->GetCHA())) + scaling_modified + " / " +
|
||||
commify(std::to_string(mob->GetMaxCHA())) + " +" +
|
||||
commify(std::to_string(mob->GetHeroicCHA()));
|
||||
}
|
||||
|
||||
if (attribute == "mr") {
|
||||
return commify(std::to_string(mob->GetMR())) + scaling_modified + " / " +
|
||||
commify(std::to_string(mob->GetMaxMR())) + " +" +
|
||||
commify(std::to_string(mob->GetHeroicMR()));
|
||||
}
|
||||
|
||||
if (attribute == "cr") {
|
||||
return commify(std::to_string(mob->GetCR())) + scaling_modified + " / " +
|
||||
commify(std::to_string(mob->GetMaxCR())) + " +" +
|
||||
commify(std::to_string(mob->GetHeroicCR()));
|
||||
}
|
||||
|
||||
if (attribute == "fr") {
|
||||
return commify(std::to_string(mob->GetFR())) + scaling_modified + " / " +
|
||||
commify(std::to_string(mob->GetMaxFR())) + " +" +
|
||||
commify(std::to_string(mob->GetHeroicFR()));
|
||||
}
|
||||
|
||||
if (attribute == "pr") {
|
||||
return commify(std::to_string(mob->GetPR())) + scaling_modified + " / " +
|
||||
commify(std::to_string(mob->GetMaxPR())) + " +" +
|
||||
commify(std::to_string(mob->GetHeroicPR()));
|
||||
}
|
||||
|
||||
if (attribute == "dr") {
|
||||
return commify(std::to_string(mob->GetDR())) + scaling_modified + " / " +
|
||||
commify(std::to_string(mob->GetMaxDR())) + " +" +
|
||||
commify(std::to_string(mob->GetHeroicDR()));
|
||||
}
|
||||
|
||||
if (attribute == "cr") {
|
||||
return commify(std::to_string(mob->GetCR())) + scaling_modified + " / " +
|
||||
commify(std::to_string(mob->GetMaxCR())) + " +" +
|
||||
commify(std::to_string(mob->GetHeroicCR()));
|
||||
}
|
||||
|
||||
if (attribute == "pr") {
|
||||
return commify(std::to_string(mob->GetPR())) + scaling_modified + " / " +
|
||||
commify(std::to_string(mob->GetMaxPR())) + " +" +
|
||||
commify(std::to_string(mob->GetHeroicPR()));
|
||||
}
|
||||
|
||||
if (attribute == "cor") {
|
||||
return commify(std::to_string(mob->GetCorrup())) + scaling_modified;
|
||||
}
|
||||
|
||||
if (attribute == "phy") {
|
||||
return commify(std::to_string(mob->GetPhR())) + scaling_modified;
|
||||
}
|
||||
|
||||
if (attribute == "name") {
|
||||
return mob->GetCleanName();
|
||||
}
|
||||
|
||||
if (attribute == "surname") {
|
||||
std::string last_name = mob->GetLastName();
|
||||
return (last_name.length() > 0 ? mob->GetLastName() : " ");
|
||||
}
|
||||
|
||||
if (attribute == "race") {
|
||||
return GetRaceIDName(mob->GetRace());
|
||||
}
|
||||
|
||||
if (attribute == "class") {
|
||||
return GetClassIDName(mob->GetClass(), 0);
|
||||
}
|
||||
|
||||
if (attribute == "level") {
|
||||
return std::to_string(mob->GetLevel());
|
||||
}
|
||||
|
||||
if (attribute == "flymode") {
|
||||
return std::to_string(mob->GetFlyMode());
|
||||
}
|
||||
|
||||
if (attribute == "maxbuffslots") {
|
||||
return std::to_string(mob->GetMaxBuffSlots());
|
||||
}
|
||||
|
||||
if (attribute == "curbuffslots") {
|
||||
return std::to_string(mob->GetCurrentBuffSlots());
|
||||
}
|
||||
|
||||
if (attribute == "tohit") {
|
||||
return std::to_string(mob->compute_tohit(EQEmu::skills::SkillHandtoHand));
|
||||
}
|
||||
|
||||
if (attribute == "total_to_hit") {
|
||||
return std::to_string(mob->GetTotalToHit(EQEmu::skills::SkillHandtoHand, 0));
|
||||
}
|
||||
|
||||
if (attribute == "defense") {
|
||||
return std::to_string(mob->compute_defense());
|
||||
}
|
||||
|
||||
if (attribute == "total_defense") {
|
||||
return std::to_string(mob->GetTotalDefense());
|
||||
}
|
||||
|
||||
if (attribute == "offense") {
|
||||
return std::to_string(mob->offense(EQEmu::skills::SkillHandtoHand));
|
||||
}
|
||||
|
||||
if (attribute == "mitigation_ac") {
|
||||
return std::to_string(mob->GetMitigationAC());
|
||||
}
|
||||
|
||||
if (mob->IsNPC()) {
|
||||
NPC *npc = mob->CastToNPC();
|
||||
|
||||
if (attribute == "npcid") {
|
||||
return std::to_string(npc->GetNPCTypeID());
|
||||
}
|
||||
if (attribute == "texture") {
|
||||
return std::to_string(npc->GetTexture());
|
||||
}
|
||||
if (attribute == "bodytype") {
|
||||
return std::to_string(npc->GetBodyType());
|
||||
}
|
||||
if (attribute == "gender") {
|
||||
return std::to_string(npc->GetGender());
|
||||
}
|
||||
if (attribute == "size") {
|
||||
return std::to_string((int)npc->GetSize());
|
||||
}
|
||||
if (attribute == "runspeed") {
|
||||
return std::to_string((int)npc->GetRunspeed());
|
||||
}
|
||||
if (attribute == "walkspeed") {
|
||||
return std::to_string((int)npc->GetWalkspeed());
|
||||
}
|
||||
if (attribute == "spawngroup") {
|
||||
return std::to_string(npc->GetSp2());
|
||||
}
|
||||
if (attribute == "grid") {
|
||||
return std::to_string(npc->GetGrid());
|
||||
}
|
||||
if (attribute == "emote") {
|
||||
return std::to_string(npc->GetEmoteID());
|
||||
}
|
||||
if (attribute == "see_invis") {
|
||||
return std::to_string(npc->SeeInvisible());
|
||||
}
|
||||
if (attribute == "see_invis_undead") {
|
||||
return std::to_string(npc->SeeInvisibleUndead());
|
||||
}
|
||||
if (attribute == "faction") {
|
||||
return std::to_string(npc->GetNPCFactionID());
|
||||
}
|
||||
if (attribute == "loottable") {
|
||||
return std::to_string(npc->GetLoottableID());
|
||||
}
|
||||
if (attribute == "prim_skill") {
|
||||
return std::to_string(npc->GetPrimSkill());
|
||||
}
|
||||
if (attribute == "sec_skill") {
|
||||
return std::to_string(npc->GetSecSkill());
|
||||
}
|
||||
if (attribute == "melee_texture_1") {
|
||||
return std::to_string(npc->GetMeleeTexture1());
|
||||
}
|
||||
if (attribute == "melee_texture_2") {
|
||||
return std::to_string(npc->GetMeleeTexture2());
|
||||
}
|
||||
if (attribute == "aggrorange") {
|
||||
return std::to_string((int)npc->GetAggroRange());
|
||||
}
|
||||
if (attribute == "assistrange") {
|
||||
return std::to_string((int)npc->GetAssistRange());
|
||||
}
|
||||
if (attribute == "findable") {
|
||||
return std::to_string(npc->IsFindable());
|
||||
}
|
||||
if (attribute == "trackable") {
|
||||
return std::to_string(npc->IsTrackable());
|
||||
}
|
||||
if (attribute == "spells_id") {
|
||||
return std::to_string(npc->GetNPCSpellsID());
|
||||
}
|
||||
if (attribute == "roambox_min_x") {
|
||||
return std::to_string((int)npc->GetRoamboxMinX());
|
||||
}
|
||||
if (attribute == "roambox_max_x") {
|
||||
return std::to_string((int)npc->GetRoamboxMaxX());
|
||||
}
|
||||
if (attribute == "roambox_min_y") {
|
||||
return std::to_string((int)npc->GetRoamboxMinY());
|
||||
}
|
||||
if (attribute == "roambox_max_y") {
|
||||
return std::to_string((int)npc->GetRoamboxMaxY());
|
||||
}
|
||||
if (attribute == "roambox_min_delay") {
|
||||
return std::to_string((int)npc->GetRoamboxMinDelay());
|
||||
}
|
||||
if (attribute == "roambox_delay") {
|
||||
return std::to_string((int)npc->GetRoamboxDelay());
|
||||
}
|
||||
if (attribute == "roambox_distance") {
|
||||
return std::to_string((int)npc->GetRoamboxDistance());
|
||||
}
|
||||
if (attribute == "proximity_min_x") {
|
||||
return std::to_string((int)npc->GetProximityMinX());
|
||||
}
|
||||
if (attribute == "proximity_max_x") {
|
||||
return std::to_string((int)npc->GetProximityMaxX());
|
||||
}
|
||||
if (attribute == "proximity_min_y") {
|
||||
return std::to_string((int)npc->GetProximityMinY());
|
||||
}
|
||||
if (attribute == "proximity_max_y") {
|
||||
return std::to_string((int)npc->GetProximityMaxY());
|
||||
}
|
||||
if (attribute == "proximity_min_z") {
|
||||
return std::to_string((int)npc->GetProximityMinZ());
|
||||
}
|
||||
if (attribute == "proximity_max_z") {
|
||||
return std::to_string((int)npc->GetProximityMaxZ());
|
||||
}
|
||||
if (attribute == "accuracy") {
|
||||
return std::to_string((int)npc->GetAccuracyRating()) + scaling_modified;
|
||||
}
|
||||
if (attribute == "slow_mitigation") {
|
||||
if (mob->GetEntityVariable(std::string("modify_stat_slow_mitigation").c_str())) {
|
||||
scaling_modified = " *";
|
||||
}
|
||||
|
||||
return std::to_string((int)npc->GetSlowMitigation()) + scaling_modified;
|
||||
}
|
||||
if (attribute == "min_hit") {
|
||||
if (mob->GetEntityVariable(std::string("modify_stat_min_hit").c_str())) {
|
||||
scaling_modified = " *";
|
||||
}
|
||||
|
||||
return commify(std::to_string((int)npc->GetMinDMG())) + scaling_modified;
|
||||
}
|
||||
if (attribute == "max_hit") {
|
||||
if (mob->GetEntityVariable(std::string("modify_stat_max_hit").c_str())) {
|
||||
scaling_modified = " *";
|
||||
}
|
||||
|
||||
return commify(std::to_string((int)npc->GetMaxDMG())) + scaling_modified;
|
||||
}
|
||||
if (attribute == "hp_regen") {
|
||||
if (mob->GetEntityVariable(std::string("modify_stat_hp_regen").c_str())) {
|
||||
scaling_modified = " *";
|
||||
}
|
||||
|
||||
return commify(std::to_string((int)npc->GetHPRegen())) + scaling_modified;
|
||||
}
|
||||
if (attribute == "attack_delay") {
|
||||
if (mob->GetEntityVariable(std::string("modify_stat_attack_delay").c_str())) {
|
||||
scaling_modified = " *";
|
||||
}
|
||||
|
||||
return commify(std::to_string(npc->GetAttackDelay())) + scaling_modified;
|
||||
}
|
||||
if (attribute == "spell_scale") {
|
||||
if (mob->GetEntityVariable(std::string("modify_stat_spell_scale").c_str())) {
|
||||
scaling_modified = " *";
|
||||
}
|
||||
|
||||
return commify(std::to_string((int)npc->GetSpellScale())) + scaling_modified;
|
||||
}
|
||||
if (attribute == "heal_scale") {
|
||||
if (mob->GetEntityVariable(std::string("modify_stat_heal_scale").c_str())) {
|
||||
scaling_modified = " *";
|
||||
}
|
||||
|
||||
return commify(std::to_string((int)npc->GetHealScale())) + scaling_modified;
|
||||
}
|
||||
if (attribute == "avoidance") {
|
||||
return commify(std::to_string((int)npc->GetAvoidanceRating())) + scaling_modified;
|
||||
}
|
||||
|
||||
npc->GetNPCEmote(npc->GetEmoteID(), 0);
|
||||
}
|
||||
|
||||
if (mob->IsClient()) {
|
||||
Client *client = mob->CastToClient();
|
||||
|
||||
if (attribute == "shielding") {
|
||||
return commify(std::to_string((int)client->GetShielding())) + " / " +
|
||||
commify(std::to_string((int) RuleI(Character, ItemShieldingCap)));
|
||||
}
|
||||
if (attribute == "spell_shielding") {
|
||||
return commify(std::to_string((int)client->GetSpellShield())) + " / " +
|
||||
commify(std::to_string((int) RuleI(Character, ItemSpellShieldingCap)));
|
||||
}
|
||||
if (attribute == "dot_shielding") {
|
||||
return commify(std::to_string((int)client->GetDoTShield())) + " / " +
|
||||
commify(std::to_string((int) RuleI(Character, ItemDoTShieldingCap)));
|
||||
}
|
||||
if (attribute == "stun_resist") {
|
||||
return commify(std::to_string((int)client->GetStunResist())) + " / " +
|
||||
commify(std::to_string((int) RuleI(Character, ItemStunResistCap)));
|
||||
}
|
||||
if (attribute == "damage_shield") {
|
||||
return commify(std::to_string((int)client->GetDS())) + " / " +
|
||||
commify(std::to_string((int) RuleI(Character, ItemDamageShieldCap)));
|
||||
}
|
||||
if (attribute == "avoidance") {
|
||||
return commify(std::to_string((int) client->GetAvoidance())) + " / " +
|
||||
commify(std::to_string((int) RuleI(Character, ItemAvoidanceCap)));
|
||||
}
|
||||
if (attribute == "strikethrough") {
|
||||
return commify(std::to_string((int) client->GetStrikeThrough())) + " / " +
|
||||
commify(std::to_string((int) RuleI(Character, ItemStrikethroughCap)));
|
||||
}
|
||||
if (attribute == "accuracy") {
|
||||
return commify(std::to_string((int) client->GetAccuracy())) + " / " +
|
||||
commify(std::to_string((int) RuleI(Character, ItemAccuracyCap)));
|
||||
}
|
||||
if (attribute == "combat_effects") {
|
||||
return commify(std::to_string((int) client->GetCombatEffects())) + " / " +
|
||||
commify(std::to_string((int) RuleI(Character, ItemCombatEffectsCap)));
|
||||
}
|
||||
if (attribute == "heal_amount") {
|
||||
return commify(std::to_string((int) client->GetHealAmt())) + " / " +
|
||||
commify(std::to_string((int) RuleI(Character, ItemHealAmtCap)));
|
||||
}
|
||||
if (attribute == "spell_dmg") {
|
||||
return commify(std::to_string((int) client->GetSpellDmg())) + " / " +
|
||||
commify(std::to_string((int) RuleI(Character, ItemSpellDmgCap)));
|
||||
}
|
||||
if (attribute == "clairvoyance") {
|
||||
return commify(std::to_string((int) client->GetClair())) + " / " +
|
||||
commify(std::to_string((int) RuleI(Character, ItemClairvoyanceCap)));
|
||||
}
|
||||
if (attribute == "ds_mitigation") {
|
||||
return commify(std::to_string((int) client->GetDSMit())) + " / " +
|
||||
commify(std::to_string((int) RuleI(Character, ItemDSMitigationCap)));
|
||||
}
|
||||
if (attribute == "hp_regen") {
|
||||
return commify(std::to_string((int) client->GetHPRegen())) + " / " +
|
||||
commify(std::to_string((int) RuleI(Character, ItemHealthRegenCap)));
|
||||
}
|
||||
if (attribute == "mana_regen") {
|
||||
return commify(std::to_string((int) client->GetManaRegen())) + " / " +
|
||||
commify(std::to_string((int) RuleI(Character, ItemManaRegenCap)));
|
||||
}
|
||||
if (attribute == "end_regen") {
|
||||
return commify(std::to_string((int) client->CalcEnduranceRegen())) + " / " +
|
||||
commify(std::to_string((int) client->CalcEnduranceRegenCap()));
|
||||
}
|
||||
}
|
||||
|
||||
if (attribute == "type") {
|
||||
std::string entity_type = "Mob";
|
||||
|
||||
if (mob->IsCorpse()) {
|
||||
entity_type = "Corpse";
|
||||
}
|
||||
|
||||
if (mob->IsNPC()) {
|
||||
entity_type = "NPC";
|
||||
}
|
||||
|
||||
if (mob->IsClient()) {
|
||||
entity_type = "Client";
|
||||
}
|
||||
|
||||
return entity_type;
|
||||
}
|
||||
|
||||
return "null";
|
||||
}
|
||||
|
||||
inline std::string WriteDisplayInfoSection(
|
||||
Mob *mob,
|
||||
const std::string §ion_name,
|
||||
std::vector<std::string> attributes_list,
|
||||
int column_count = 3,
|
||||
bool display_section_name = false
|
||||
)
|
||||
{
|
||||
std::string text;
|
||||
|
||||
if (display_section_name) {
|
||||
text += "<c \"#FFFF66\">" + section_name + "</c><br>";
|
||||
}
|
||||
|
||||
text += "<table><tbody>";
|
||||
|
||||
int index = 0;
|
||||
bool first_row = true;
|
||||
|
||||
for (const auto &attribute : attributes_list) {
|
||||
if (index == 0) {
|
||||
if (first_row) {
|
||||
text += "<tr>\n";
|
||||
first_row = false;
|
||||
}
|
||||
else {
|
||||
text += "</tr><tr>\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string attribute_name = attribute;
|
||||
|
||||
find_replace(attribute_name, "_min_max", std::string(""));
|
||||
|
||||
/**
|
||||
* Translate attribute names with underscores
|
||||
* "total_to_hit" = "Total To Hit"
|
||||
*/
|
||||
if (attribute_name.find('_') != std::string::npos) {
|
||||
std::vector<std::string> split_string = split(attribute_name, '_');
|
||||
std::string new_attribute_name;
|
||||
for (std::string &string_value : split_string) {
|
||||
new_attribute_name += ucfirst(string_value) + " ";
|
||||
}
|
||||
attribute_name = new_attribute_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute names less than 4 characters get capitalized
|
||||
* "hp" = "HP"
|
||||
*/
|
||||
if (attribute_name.length() <= 3) {
|
||||
attribute_name = str_toupper(attribute_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute names larger than 3 characters get capitalized first letter
|
||||
* "avoidance" = "Avoidance"
|
||||
*/
|
||||
if (attribute_name.length() > 3) {
|
||||
attribute_name = ucfirst(attribute_name);
|
||||
}
|
||||
|
||||
find_replace(attribute_name, "Proximity", std::string(""));
|
||||
find_replace(attribute_name, "Roambox", std::string(""));
|
||||
|
||||
std::string attribute_value = GetMobAttributeByString(mob, attribute);
|
||||
|
||||
if (attribute_value.length() <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
text += "<td>" + attribute_name + "</td><td>" + GetMobAttributeByString(mob, attribute) + "</td>";
|
||||
|
||||
if (index == column_count) {
|
||||
index = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
text += "</tr></tbody></table>";
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
inline void NPCCommandsMenu(Client* client, NPC* npc)
|
||||
{
|
||||
std::string menu_commands;
|
||||
|
||||
if (npc->GetGrid() > 0) {
|
||||
menu_commands += "[" + EQEmu::SayLinkEngine::GenerateQuestSaylink("#grid show", false, "Grid Points") + "] ";
|
||||
}
|
||||
|
||||
if (npc->GetEmoteID() > 0) {
|
||||
std::string saylink = StringFormat("#emotesearch %u", npc->GetEmoteID());
|
||||
menu_commands += "[" + EQEmu::SayLinkEngine::GenerateQuestSaylink(saylink, false, "Emotes") + "] ";
|
||||
}
|
||||
|
||||
if (npc->GetLoottableID() > 0) {
|
||||
menu_commands += "[" + EQEmu::SayLinkEngine::GenerateQuestSaylink("#npcloot show", false, "Loot") + "] ";
|
||||
}
|
||||
|
||||
if (npc->IsProximitySet()) {
|
||||
menu_commands += "[" + EQEmu::SayLinkEngine::GenerateQuestSaylink("#proximity show", false, "Proximity") + "] ";
|
||||
}
|
||||
|
||||
if (menu_commands.length() > 0) {
|
||||
std::string dev_menu = "[" + EQEmu::SayLinkEngine::GenerateQuestSaylink("#devtools", false, "DevTools") + "] ";;
|
||||
client->Message(0, "| %s [Show Commands] %s", dev_menu.c_str(), menu_commands.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::DisplayInfo(Mob *mob)
|
||||
{
|
||||
if (!mob) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->IsClient()) {
|
||||
|
||||
std::string window_text = "<c \"#FFFF66\">*Drag window open vertically to see all</c><br>";
|
||||
|
||||
Client *client = this->CastToClient();
|
||||
|
||||
if (!client->IsDevToolsWindowEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> info_attributes = {
|
||||
"name",
|
||||
"race",
|
||||
"surname",
|
||||
"class",
|
||||
};
|
||||
window_text += WriteDisplayInfoSection(mob, "Info", info_attributes, 1, false);
|
||||
|
||||
std::vector<std::string> basic_attributes = {
|
||||
"type",
|
||||
"level",
|
||||
"hp_min_max",
|
||||
"ac",
|
||||
"mp_min_max",
|
||||
"atk",
|
||||
"end_min_max",
|
||||
};
|
||||
window_text += WriteDisplayInfoSection(mob, "Main", basic_attributes, 1, false);
|
||||
|
||||
std::vector<std::string> stat_attributes = {
|
||||
"str",
|
||||
"sta",
|
||||
"agi",
|
||||
"dex",
|
||||
"wis",
|
||||
"int",
|
||||
"cha",
|
||||
};
|
||||
window_text += WriteDisplayInfoSection(mob, "Statistics", stat_attributes, 1, false);
|
||||
|
||||
std::vector<std::string> resist_attributes = {
|
||||
"pr",
|
||||
"mr",
|
||||
"dr",
|
||||
"fr",
|
||||
"cr",
|
||||
"cor",
|
||||
"phy",
|
||||
};
|
||||
window_text += WriteDisplayInfoSection(mob, "Resists", resist_attributes, 1, false);
|
||||
|
||||
std::vector<std::string> calculations = {
|
||||
"tohit",
|
||||
"total_to_hit",
|
||||
"defense",
|
||||
"total_defense",
|
||||
"offense",
|
||||
"mitigation_ac",
|
||||
};
|
||||
window_text += WriteDisplayInfoSection(mob, "Calculations", calculations, 1, true);
|
||||
|
||||
if (mob->IsClient()) {
|
||||
std::vector<std::string> mods = {
|
||||
"hp_regen",
|
||||
"mana_regen",
|
||||
"end_regen",
|
||||
"heal_amount",
|
||||
"spell_dmg",
|
||||
"clairvoyance",
|
||||
};
|
||||
window_text += WriteDisplayInfoSection(mob, "Mods", mods, 1, true);
|
||||
|
||||
std::vector<std::string> mod_defensive = {
|
||||
"shielding",
|
||||
"spell_shielding",
|
||||
"dot_shielding",
|
||||
"stun_resist",
|
||||
"damage_shield",
|
||||
"ds_mitigation",
|
||||
"avoidance",
|
||||
};
|
||||
|
||||
window_text += WriteDisplayInfoSection(mob, "Mod Defensive", mod_defensive, 1, true);
|
||||
|
||||
std::vector<std::string> mod_offensive = {
|
||||
"strikethrough",
|
||||
"accuracy",
|
||||
"combat_effects",
|
||||
};
|
||||
window_text += WriteDisplayInfoSection(mob, "Mod Offensive", mod_offensive, 1, true);
|
||||
}
|
||||
|
||||
if (mob->IsNPC()) {
|
||||
NPC *npc = mob->CastToNPC();
|
||||
|
||||
std::vector<std::string> npc_stats = {
|
||||
"accuracy",
|
||||
"slow_mitigation",
|
||||
"min_hit",
|
||||
"max_hit",
|
||||
"hp_regen",
|
||||
"attack_delay",
|
||||
"spell_scale",
|
||||
"heal_scale",
|
||||
"avoidance",
|
||||
};
|
||||
|
||||
window_text += WriteDisplayInfoSection(mob, "NPC Stats", npc_stats, 1, true);
|
||||
|
||||
std::vector<std::string> npc_attributes = {
|
||||
"npcid",
|
||||
"texture",
|
||||
"bodytype",
|
||||
"gender",
|
||||
"size",
|
||||
"runspeed",
|
||||
"walkspeed",
|
||||
"spawngroup",
|
||||
"grid",
|
||||
"emote",
|
||||
"see_invis",
|
||||
"see_invis_undead",
|
||||
"faction",
|
||||
"loottable",
|
||||
"prim_skill",
|
||||
"sec_skill",
|
||||
"melee_texture_1",
|
||||
"melee_texture_2",
|
||||
"aggrorange",
|
||||
"assistrange",
|
||||
"findable",
|
||||
"trackable",
|
||||
"flymode",
|
||||
"spells_id",
|
||||
"curbuffslots",
|
||||
"maxbuffslots",
|
||||
};
|
||||
|
||||
window_text += WriteDisplayInfoSection(mob, "NPC Attributes", npc_attributes, 1, true);
|
||||
|
||||
/**
|
||||
* Print Roambox
|
||||
*/
|
||||
if (npc->GetRoamboxMaxX() != 0 && npc->GetRoamboxMinX() != 0) {
|
||||
std::vector<std::string> npc_roambox = {
|
||||
"roambox_min_x",
|
||||
"roambox_max_x",
|
||||
"roambox_min_y",
|
||||
"roambox_max_y",
|
||||
"roambox_min_delay",
|
||||
"roambox_delay",
|
||||
"roambox_distance",
|
||||
};
|
||||
|
||||
window_text += WriteDisplayInfoSection(mob, "Roambox", npc_roambox, 1, true);
|
||||
}
|
||||
|
||||
if (npc->proximity != nullptr) {
|
||||
std::vector<std::string> npc_proximity = {
|
||||
"proximity_min_x",
|
||||
"proximity_max_x",
|
||||
"proximity_min_y",
|
||||
"proximity_max_y",
|
||||
"proximity_min_z",
|
||||
"proximity_max_z",
|
||||
};
|
||||
|
||||
window_text += WriteDisplayInfoSection(mob, "Proximity", npc_proximity, 1, true);
|
||||
}
|
||||
|
||||
int8 npc_type = npc_scale_manager->GetNPCScalingType(npc);
|
||||
std::string npc_type_string = npc_scale_manager->GetNPCScalingTypeName(npc);
|
||||
|
||||
client->Message(
|
||||
0,
|
||||
"| # Target: %s Type: %i (%s)",
|
||||
npc->GetCleanName(),
|
||||
npc_type,
|
||||
npc_type_string.c_str());
|
||||
|
||||
NPCCommandsMenu(client, npc);
|
||||
}
|
||||
|
||||
// std::cout << "Window Length: " << window_text.length() << std::endl;
|
||||
|
||||
if (client->GetDisplayMobInfoWindow()) {
|
||||
client->SendFullPopup(
|
||||
"GM: Entity Info",
|
||||
window_text.c_str(),
|
||||
EQEmu::popupresponse::MOB_INFO_DISMISS,
|
||||
0,
|
||||
100,
|
||||
0,
|
||||
"Snooze",
|
||||
"OK"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
|
||||
class Mob;
|
||||
class Client;
|
||||
|
||||
struct RotateCommand;
|
||||
struct MovementCommand;
|
||||
struct MobMovementEntry;
|
||||
struct PlayerPositionUpdateServer_Struct;
|
||||
|
||||
enum ClientRange : int
|
||||
{
|
||||
ClientRangeNone = 0,
|
||||
ClientRangeClose = 1,
|
||||
ClientRangeMedium = 2,
|
||||
ClientRangeCloseMedium = 3,
|
||||
ClientRangeLong = 4,
|
||||
ClientRangeCloseLong = 5,
|
||||
ClientRangeMediumLong = 6,
|
||||
ClientRangeAny = 7
|
||||
};
|
||||
|
||||
enum MobMovementMode : int
|
||||
{
|
||||
MovementWalking = 0,
|
||||
MovementRunning = 1
|
||||
};
|
||||
|
||||
enum MobStuckBehavior : int
|
||||
{
|
||||
RunToTarget,
|
||||
WarpToTarget,
|
||||
TakeNoAction,
|
||||
EvadeCombat,
|
||||
MaxStuckBehavior
|
||||
};
|
||||
|
||||
class MobMovementManager
|
||||
{
|
||||
public:
|
||||
~MobMovementManager();
|
||||
void Process();
|
||||
void AddMob(Mob *m);
|
||||
void RemoveMob(Mob *m);
|
||||
void AddClient(Client *c);
|
||||
void RemoveClient(Client *c);
|
||||
|
||||
void RotateTo(Mob *who, float to, MobMovementMode mode = MovementRunning);
|
||||
void Teleport(Mob *who, float x, float y, float z, float heading);
|
||||
void NavigateTo(Mob *who, float x, float y, float z, MobMovementMode mode = MovementRunning);
|
||||
void StopNavigation(Mob *who);
|
||||
void SendCommandToClients(Mob *m, float dx, float dy, float dz, float dh, int anim, ClientRange range);
|
||||
float FixHeading(float in);
|
||||
void DumpStats(Client *to);
|
||||
void ClearStats();
|
||||
|
||||
static MobMovementManager &Get() {
|
||||
static MobMovementManager inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
private:
|
||||
MobMovementManager();
|
||||
MobMovementManager(const MobMovementManager&);
|
||||
MobMovementManager& operator=(const MobMovementManager&);
|
||||
|
||||
void FillCommandStruct(PlayerPositionUpdateServer_Struct *spu, Mob *m, float dx, float dy, float dz, float dh, int anim);
|
||||
void UpdatePath(Mob *who, float x, float y, float z, MobMovementMode mode);
|
||||
void UpdatePathGround(Mob *who, float x, float y, float z, MobMovementMode mode);
|
||||
void UpdatePathUnderwater(Mob *who, float x, float y, float z, MobMovementMode mode);
|
||||
void UpdatePathBoat(Mob *who, float x, float y, float z, MobMovementMode mode);
|
||||
void PushTeleportTo(MobMovementEntry &ent, float x, float y, float z, float heading);
|
||||
void PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mode);
|
||||
void PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mode);
|
||||
void PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mode);
|
||||
void PushStopMoving(MobMovementEntry &ent);
|
||||
void PushEvadeCombat(MobMovementEntry &ent);
|
||||
void HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mode);
|
||||
|
||||
struct Implementation;
|
||||
std::unique_ptr<Implementation> _impl;
|
||||
};
|
||||
+26
-26
@@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/eq_stream_ident.h"
|
||||
#include "../common/patches/patches.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/profanity_manager.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/platform.h"
|
||||
@@ -42,7 +43,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/spdat.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
|
||||
|
||||
#include "zone_config.h"
|
||||
#include "masterentity.h"
|
||||
#include "worldserver.h"
|
||||
@@ -52,7 +52,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "command.h"
|
||||
#ifdef BOTS
|
||||
#include "bot_command.h"
|
||||
#include "bot_database.h"
|
||||
#endif
|
||||
#include "zone_config.h"
|
||||
#include "titles.h"
|
||||
@@ -62,6 +61,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "embparser.h"
|
||||
#include "lua_parser.h"
|
||||
#include "questmgr.h"
|
||||
#include "npc_scale_manager.h"
|
||||
|
||||
#include "../common/event/event_loop.h"
|
||||
#include "../common/event/timer.h"
|
||||
@@ -104,12 +104,13 @@ npcDecayTimes_Struct npcCorpseDecayTimes[100];
|
||||
TitleManager title_manager;
|
||||
QueryServ *QServ = 0;
|
||||
TaskManager *taskmanager = 0;
|
||||
NpcScaleManager *npc_scale_manager;
|
||||
QuestParserCollection *parse = 0;
|
||||
EQEmuLogSys LogSys;
|
||||
const SPDat_Spell_Struct* spells;
|
||||
int32 SPDAT_RECORDS = -1;
|
||||
const ZoneConfig *Config;
|
||||
uint64_t frame_time = 0;
|
||||
double frame_time = 0.0;
|
||||
|
||||
void Shutdown();
|
||||
extern void MapOpcodes();
|
||||
@@ -222,7 +223,6 @@ int main(int argc, char** argv) {
|
||||
worldserver.SetLauncherName("NONE");
|
||||
}
|
||||
|
||||
|
||||
Log(Logs::General, Logs::Zone_Server, "Connecting to MySQL...");
|
||||
if (!database.Connect(
|
||||
Config->DatabaseHost.c_str(),
|
||||
@@ -234,18 +234,6 @@ int main(int argc, char** argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
if (!botdb.Connect(
|
||||
Config->DatabaseHost.c_str(),
|
||||
Config->DatabaseUsername.c_str(),
|
||||
Config->DatabasePassword.c_str(),
|
||||
Config->DatabaseDB.c_str(),
|
||||
Config->DatabasePort)) {
|
||||
Log(Logs::General, Logs::Error, "Cannot continue without a bots database connection.");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Register Log System and Settings */
|
||||
LogSys.OnLogHookCallBackZone(&Zone::GMSayHookCallBackProcess);
|
||||
database.LoadLogSettings(LogSys.log_settings);
|
||||
@@ -255,6 +243,12 @@ int main(int argc, char** argv) {
|
||||
guild_mgr.SetDatabase(&database);
|
||||
GuildBanks = nullptr;
|
||||
|
||||
/**
|
||||
* NPC Scale Manager
|
||||
*/
|
||||
npc_scale_manager = new NpcScaleManager;
|
||||
npc_scale_manager->LoadScaleData();
|
||||
|
||||
#ifdef _EQDEBUG
|
||||
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
||||
#endif
|
||||
@@ -344,6 +338,10 @@ int main(int argc, char** argv) {
|
||||
Log(Logs::General, Logs::Zone_Server, "Loading corpse timers");
|
||||
database.GetDecayTimes(npcCorpseDecayTimes);
|
||||
|
||||
Log(Logs::General, Logs::Zone_Server, "Loading profanity list");
|
||||
if (!EQEmu::ProfanityManager::LoadProfanityList(&database))
|
||||
Log(Logs::General, Logs::Error, "Loading profanity list FAILED!");
|
||||
|
||||
Log(Logs::General, Logs::Zone_Server, "Loading commands");
|
||||
int retval = command_init();
|
||||
if (retval<0)
|
||||
@@ -356,18 +354,21 @@ int main(int argc, char** argv) {
|
||||
std::string tmp;
|
||||
if (database.GetVariable("RuleSet", tmp)) {
|
||||
Log(Logs::General, Logs::Zone_Server, "Loading rule set '%s'", tmp.c_str());
|
||||
if (!RuleManager::Instance()->LoadRules(&database, tmp.c_str())) {
|
||||
if (!RuleManager::Instance()->LoadRules(&database, tmp.c_str(), false)) {
|
||||
Log(Logs::General, Logs::Error, "Failed to load ruleset '%s', falling back to defaults.", tmp.c_str());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!RuleManager::Instance()->LoadRules(&database, "default")) {
|
||||
if (!RuleManager::Instance()->LoadRules(&database, "default", false)) {
|
||||
Log(Logs::General, Logs::Zone_Server, "No rule set configured, using default rules");
|
||||
}
|
||||
else {
|
||||
Log(Logs::General, Logs::Zone_Server, "Loaded default rule set 'default'", tmp.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
EQEmu::InitializeDynamicLookups();
|
||||
Log(Logs::General, Logs::Zone_Server, "Initialized dynamic dictionary entries");
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
@@ -379,7 +380,7 @@ int main(int argc, char** argv) {
|
||||
Log(Logs::General, Logs::Zone_Server, "%d bot commands loaded", botretval);
|
||||
|
||||
Log(Logs::General, Logs::Zone_Server, "Loading bot spell casting chances");
|
||||
if (!botdb.LoadBotSpellCastingChances())
|
||||
if (!database.botdb.LoadBotSpellCastingChances())
|
||||
Log(Logs::General, Logs::Error, "Bot spell casting chances loading FAILED");
|
||||
#endif
|
||||
|
||||
@@ -447,13 +448,17 @@ int main(int argc, char** argv) {
|
||||
|
||||
//Calculate frame time
|
||||
std::chrono::time_point<std::chrono::system_clock> frame_now = std::chrono::system_clock::now();
|
||||
frame_time = std::chrono::duration_cast<std::chrono::milliseconds>(frame_now - frame_prev).count();
|
||||
frame_time = std::chrono::duration_cast<std::chrono::duration<double>>(frame_now - frame_prev).count();
|
||||
frame_prev = frame_now;
|
||||
|
||||
if (!eqsf_open && Config->ZonePort != 0) {
|
||||
Log(Logs::General, Logs::Zone_Server, "Starting EQ Network server on port %d", Config->ZonePort);
|
||||
|
||||
EQ::Net::EQStreamManagerOptions opts(Config->ZonePort, false, true);
|
||||
opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS);
|
||||
opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor);
|
||||
opts.daybreak_options.resend_delay_min = RuleI(Network, ResendDelayMinMS);
|
||||
opts.daybreak_options.resend_delay_max = RuleI(Network, ResendDelayMaxMS);
|
||||
eqsm.reset(new EQ::Net::EQStreamManager(opts));
|
||||
eqsf_open = true;
|
||||
|
||||
@@ -541,11 +546,6 @@ int main(int argc, char** argv) {
|
||||
if (previous_loaded && !current_loaded) {
|
||||
process_timer.Stop();
|
||||
process_timer.Start(1000, true);
|
||||
|
||||
if (zone && zone->GetZoneID() && zone->GetInstanceVersion()) {
|
||||
uint32 shutdown_timer = database.getZoneShutDownDelay(zone->GetZoneID(), zone->GetInstanceVersion());
|
||||
zone->StartShutdownTimer(shutdown_timer);
|
||||
}
|
||||
}
|
||||
else if (!previous_loaded && current_loaded) {
|
||||
process_timer.Stop();
|
||||
@@ -679,4 +679,4 @@ void UpdateWindowTitle(char* iNewTitle) {
|
||||
}
|
||||
SetConsoleTitle(tmp);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
+946
-663
File diff suppressed because it is too large
Load Diff
+103
-31
@@ -51,6 +51,7 @@ typedef struct {
|
||||
float min_z;
|
||||
float max_z;
|
||||
bool say;
|
||||
bool proximity_set;
|
||||
} NPCProximity;
|
||||
|
||||
struct AISpells_Struct {
|
||||
@@ -61,6 +62,8 @@ struct AISpells_Struct {
|
||||
int32 recast_delay;
|
||||
int16 priority;
|
||||
int16 resist_adjust;
|
||||
int8 min_hp; // >0 won't cast if HP is below
|
||||
int8 max_hp; // >0 won't cast if HP is above
|
||||
};
|
||||
|
||||
struct AISpellsEffects_Struct {
|
||||
@@ -104,14 +107,17 @@ public:
|
||||
static bool SpawnZoneController();
|
||||
static int8 GetAILevel(bool iForceReRead = false);
|
||||
|
||||
NPC(const NPCType* data, Spawn2* respawn, const glm::vec4& position, int iflymode, bool IsCorpse = false);
|
||||
NPC(const NPCType* npc_type_data, Spawn2* respawn, const glm::vec4& position, GravityBehavior iflymode, bool IsCorpse = false);
|
||||
|
||||
virtual ~NPC();
|
||||
|
||||
static NPC *SpawnNodeNPC(std::string name, std::string last_name, const glm::vec4 &position);
|
||||
static NPC *SpawnGridNodeNPC(std::string name, const glm::vec4 &position, uint32 grid_id, uint32 grid_number, uint32 pause);
|
||||
|
||||
//abstract virtual function implementations requird by base abstract class
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill);
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
|
||||
bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr);
|
||||
virtual bool HasRaid() { return false; }
|
||||
virtual bool HasGroup() { return false; }
|
||||
@@ -138,9 +144,6 @@ public:
|
||||
virtual void AI_Event_SpellCastFinished(bool iCastSucceeded, uint16 slot);
|
||||
|
||||
void LevelScale();
|
||||
void CalcNPCResists();
|
||||
void CalcNPCRegen();
|
||||
void CalcNPCDamage();
|
||||
|
||||
virtual void SetTarget(Mob* mob);
|
||||
virtual uint16 GetSkill(EQEmu::skills::SkillType skill_num) const { if (skill_num <= EQEmu::skills::HIGHEST_SKILL) { return skills[skill_num]; } return 0; }
|
||||
@@ -183,6 +186,7 @@ public:
|
||||
void AddItem(uint32 itemid, uint16 charges, bool equipitem = true, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0);
|
||||
void AddLootTable();
|
||||
void AddLootTable(uint32 ldid);
|
||||
void CheckGlobalLootTables();
|
||||
void DescribeAggro(Client *towho, Mob *mob, bool verbose);
|
||||
void RemoveItem(uint32 item_id, uint16 quantity = 0, uint16 slot = 0);
|
||||
void CheckMinMaxLevel(Mob *them);
|
||||
@@ -195,6 +199,7 @@ public:
|
||||
uint32 CountLoot();
|
||||
inline uint32 GetLoottableID() const { return loottable_id; }
|
||||
virtual void UpdateEquipmentLight();
|
||||
inline bool DropsGlobalLoot() const { return !skip_global_loot; }
|
||||
|
||||
inline uint32 GetCopper() const { return copper; }
|
||||
inline uint32 GetSilver() const { return silver; }
|
||||
@@ -223,9 +228,6 @@ public:
|
||||
EmuAppearance GetGuardPointAnim() const { return guard_anim; }
|
||||
void SaveGuardPointAnim(EmuAppearance anim) { guard_anim = anim; }
|
||||
|
||||
void SetFlyMode(uint8 FlyMode){ flymode=FlyMode; }
|
||||
uint32 GetFlyMode() const { return flymode; }
|
||||
|
||||
uint8 GetPrimSkill() const { return prim_melee_type; }
|
||||
uint8 GetSecSkill() const { return sec_melee_type; }
|
||||
uint8 GetRangedSkill() const { return ranged_type; }
|
||||
@@ -249,12 +251,23 @@ public:
|
||||
|
||||
void SignalNPC(int _signal_id);
|
||||
|
||||
inline int32 GetNPCFactionID() const { return npc_faction_id; }
|
||||
inline int32 GetPrimaryFaction() const { return primary_faction; }
|
||||
int32 GetNPCHate(Mob* in_ent) {return hate_list.GetEntHateAmount(in_ent);}
|
||||
bool IsOnHatelist(Mob*p) { return hate_list.IsEntOnHateList(p);}
|
||||
inline int32 GetNPCFactionID() const
|
||||
{ return npc_faction_id; }
|
||||
|
||||
void SetNPCFactionID(int32 in) { npc_faction_id = in; database.GetFactionIdsForNPC(npc_faction_id, &faction_list, &primary_faction); }
|
||||
inline int32 GetPrimaryFaction() const
|
||||
{ return primary_faction; }
|
||||
|
||||
int32 GetNPCHate(Mob *in_ent)
|
||||
{ return hate_list.GetEntHateAmount(in_ent); }
|
||||
|
||||
bool IsOnHatelist(Mob *p)
|
||||
{ return hate_list.IsEntOnHateList(p); }
|
||||
|
||||
void SetNPCFactionID(int32 in)
|
||||
{
|
||||
npc_faction_id = in;
|
||||
database.GetFactionIdsForNPC(npc_faction_id, &faction_list, &primary_faction);
|
||||
}
|
||||
|
||||
glm::vec4 m_SpawnPoint;
|
||||
|
||||
@@ -272,6 +285,7 @@ public:
|
||||
void SetTaunting(bool tog) {taunting = tog;}
|
||||
bool IsTaunting() const { return taunting; }
|
||||
void PickPocket(Client* thief);
|
||||
void Disarm(Client* client, int chance);
|
||||
void StartSwarmTimer(uint32 duration) { swarm_timer.Start(duration); }
|
||||
void AddLootDrop(const EQEmu::ItemData*dbitem, ItemList* itemlistconst, int16 charges, uint8 minlevel, uint8 maxlevel, bool equipit, bool wearchange = false, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0);
|
||||
virtual void DoClassAttacks(Mob *target);
|
||||
@@ -280,6 +294,8 @@ public:
|
||||
int32 GetNPCHPRegen() const { return hp_regen + itembonuses.HPRegen + spellbonuses.HPRegen; }
|
||||
inline const char* GetAmmoIDfile() const { return ammo_idfile; }
|
||||
|
||||
void ModifyStatsOnCharm(bool bRemoved);
|
||||
|
||||
//waypoint crap
|
||||
int GetMaxWp() const { return max_wp; }
|
||||
void DisplayWaypointInfo(Client *to);
|
||||
@@ -295,16 +311,27 @@ public:
|
||||
void MoveTo(const glm::vec4& position, bool saveguardspot);
|
||||
void GetClosestWaypoint(std::list<wplist> &wp_list, int count, const glm::vec3& location);
|
||||
|
||||
uint32 GetEquipment(uint8 material_slot) const; // returns item id
|
||||
uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const; // returns item id
|
||||
int32 GetEquipmentMaterial(uint8 material_slot) const;
|
||||
|
||||
void NextGuardPosition();
|
||||
void SaveGuardSpot(bool iClearGuardSpot = false);
|
||||
void SaveGuardSpot(const glm::vec4 &pos);
|
||||
inline bool IsGuarding() const { return(m_GuardPoint.w != 0); }
|
||||
void SaveGuardSpotCharm();
|
||||
void RestoreGuardSpotCharm();
|
||||
void AI_SetRoambox(float iDist, float iRoamDist, uint32 iDelay = 2500, uint32 iMinDelay = 2500);
|
||||
void AI_SetRoambox(float iDist, float iMaxX, float iMinX, float iMaxY, float iMinY, uint32 iDelay = 2500, uint32 iMinDelay = 2500);
|
||||
|
||||
uint16 GetMeleeTexture1() const;
|
||||
uint16 GetMeleeTexture2() const;
|
||||
|
||||
void RestoreGuardSpotCharm();
|
||||
|
||||
void AI_SetRoambox(
|
||||
float max_distance,
|
||||
float roam_distance_variance,
|
||||
uint32 delay = 2500,
|
||||
uint32 min_delay = 2500
|
||||
);
|
||||
|
||||
void AI_SetRoambox(float distance, float max_x, float min_x, float max_y, float min_y, uint32 delay = 2500, uint32 min_delay = 2500);
|
||||
|
||||
//mercenary stuff
|
||||
void LoadMercTypes();
|
||||
@@ -324,6 +351,14 @@ public:
|
||||
inline const uint32 GetNPCSpellsID() const { return npc_spells_id; }
|
||||
inline const uint32 GetNPCSpellsEffectsID() const { return npc_spells_effects_id; }
|
||||
|
||||
float GetProximityMinX();
|
||||
float GetProximityMaxX();
|
||||
float GetProximityMinY();
|
||||
float GetProximityMaxY();
|
||||
float GetProximityMinZ();
|
||||
float GetProximityMaxZ();
|
||||
bool IsProximitySet();
|
||||
|
||||
ItemList itemlist; //kathgar - why is this public? Doing other things or I would check the code
|
||||
|
||||
NPCProximity* proximity;
|
||||
@@ -340,7 +375,7 @@ public:
|
||||
void SetAvoidanceRating(int32 d) { avoidance_rating = d;}
|
||||
int32 GetRawAC() const { return AC; }
|
||||
|
||||
void ModifyNPCStat(const char *identifier, const char *newValue);
|
||||
void ModifyNPCStat(const char *identifier, const char *new_value);
|
||||
virtual void SetLevel(uint8 in_level, bool command = false);
|
||||
|
||||
bool IsLDoNTrapped() const { return (ldon_trapped); }
|
||||
@@ -367,7 +402,7 @@ public:
|
||||
/* Only allows players that killed corpse to loot */
|
||||
const bool HasPrivateCorpse() const { return NPCTypedata->private_corpse; }
|
||||
|
||||
const bool IsUnderwaterOnly() const { return NPCTypedata->underwater; }
|
||||
virtual const bool IsUnderwaterOnly() const { return NPCTypedata->underwater; }
|
||||
const char* GetRawNPCTypeName() const { return NPCTypedata->name; }
|
||||
|
||||
void ChangeLastName(const char* in_lastname);
|
||||
@@ -378,7 +413,7 @@ public:
|
||||
void NPCSlotTexture(uint8 slot, uint16 texture); // Sets new material values for slots
|
||||
|
||||
uint32 GetAdventureTemplate() const { return adventure_template_id; }
|
||||
void AddSpellToNPCList(int16 iPriority, int16 iSpellID, uint32 iType, int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust);
|
||||
void AddSpellToNPCList(int16 iPriority, int16 iSpellID, uint32 iType, int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust, int8 min_hp, int8 max_hp);
|
||||
void AddSpellEffectToNPCList(uint16 iSpellEffectID, int32 base, int32 limit, int32 max);
|
||||
void RemoveSpellFromNPCList(int16 spell_id);
|
||||
Timer *GetRefaceTimer() const { return reface_timer; }
|
||||
@@ -403,8 +438,6 @@ public:
|
||||
|
||||
uint32 GetSpawnKillCount();
|
||||
int GetScore();
|
||||
void SetMerchantProbability(uint8 amt) { probability = amt; }
|
||||
uint8 GetMerchantProbability() { return probability; }
|
||||
void mod_prespawn(Spawn2 *sp);
|
||||
int mod_npc_damage(int damage, EQEmu::skills::SkillType skillinuse, int hand, const EQEmu::ItemData* weapon, Mob* other);
|
||||
void mod_npc_killed_merit(Mob* c);
|
||||
@@ -416,12 +449,27 @@ public:
|
||||
void SetHeroForgeModel(uint32 model) { herosforgemodel = model; }
|
||||
|
||||
bool IsRaidTarget() const { return raid_target; };
|
||||
void ResetHPUpdateTimer() { sendhpupdate_timer.Start(); }
|
||||
void ResetHPUpdateTimer() { send_hp_update_timer.Start(); }
|
||||
|
||||
bool IgnoreDespawn() { return ignore_despawn; }
|
||||
|
||||
float GetRoamboxMaxX() const;
|
||||
float GetRoamboxMaxY() const;
|
||||
float GetRoamboxMinX() const;
|
||||
float GetRoamboxMinY() const;
|
||||
float GetRoamboxDistance() const;
|
||||
float GetRoamboxDestinationX() const;
|
||||
float GetRoamboxDestinationY() const;
|
||||
float GetRoamboxDestinationZ() const;
|
||||
uint32 GetRoamboxDelay() const;
|
||||
uint32 GetRoamboxMinDelay() const;
|
||||
|
||||
std::unique_ptr<Timer> AIautocastspell_timer;
|
||||
|
||||
virtual int GetStuckBehavior() const { return NPCTypedata_ours ? NPCTypedata_ours->stuck_behavior : NPCTypedata->stuck_behavior; }
|
||||
|
||||
inline bool IsSkipAutoScale() const { return skip_auto_scale; }
|
||||
|
||||
protected:
|
||||
|
||||
const NPCType* NPCTypedata;
|
||||
@@ -449,7 +497,7 @@ protected:
|
||||
Timer qglobal_purge_timer;
|
||||
|
||||
bool combat_event; //true if we are in combat, false otherwise
|
||||
Timer sendhpupdate_timer;
|
||||
Timer send_hp_update_timer;
|
||||
Timer enraged_timer;
|
||||
Timer *reface_timer;
|
||||
|
||||
@@ -459,7 +507,7 @@ protected:
|
||||
uint32* pDontCastBefore_casting_spell;
|
||||
std::vector<AISpells_Struct> AIspells;
|
||||
bool HasAISpell;
|
||||
virtual bool AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes);
|
||||
virtual bool AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes, bool bInnates = false);
|
||||
virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0);
|
||||
AISpellsVar_Struct AISpellVar;
|
||||
int16 GetFocusEffect(focusType type, uint16 spell_id);
|
||||
@@ -482,6 +530,25 @@ protected:
|
||||
int32 SpellFocusDMG;
|
||||
int32 SpellFocusHeal;
|
||||
|
||||
// stats to switch back to after charm wears off
|
||||
// could probably pick a better name, but these probably aren't taken so ...
|
||||
int default_ac;
|
||||
int default_min_dmg;
|
||||
int default_max_dmg;
|
||||
int default_attack_delay;
|
||||
int default_accuracy_rating;
|
||||
int default_avoidance_rating;
|
||||
int default_atk;
|
||||
|
||||
// when charmed, switch to these
|
||||
int charm_ac;
|
||||
int charm_min_dmg;
|
||||
int charm_max_dmg;
|
||||
int charm_attack_delay;
|
||||
int charm_accuracy_rating;
|
||||
int charm_avoidance_rating;
|
||||
int charm_atk;
|
||||
|
||||
//pet crap:
|
||||
uint16 pet_spell_id;
|
||||
bool taunting;
|
||||
@@ -504,17 +571,19 @@ protected:
|
||||
float roambox_min_x;
|
||||
float roambox_min_y;
|
||||
float roambox_distance;
|
||||
float roambox_movingto_x;
|
||||
float roambox_movingto_y;
|
||||
float roambox_destination_x;
|
||||
float roambox_destination_y;
|
||||
float roambox_destination_z;
|
||||
uint32 roambox_delay;
|
||||
uint32 roambox_min_delay;
|
||||
|
||||
uint16 skills[EQEmu::skills::HIGHEST_SKILL + 1];
|
||||
|
||||
uint32 equipment[EQEmu::legacy::EQUIPMENT_SIZE]; //this is an array of item IDs
|
||||
uint32 equipment[EQEmu::invslot::EQUIPMENT_COUNT]; //this is an array of item IDs
|
||||
|
||||
uint32 herosforgemodel; //this is the Hero Forge Armor Model (i.e 63 or 84 or 203)
|
||||
uint16 d_melee_texture1; //this is an item Material value
|
||||
uint16 d_melee_texture1;
|
||||
//this is an item Material value
|
||||
uint16 d_melee_texture2; //this is an item Material value (offhand)
|
||||
const char* ammo_idfile; //this determines projectile graphic "IT###" (see item field 'idfile')
|
||||
uint8 prim_melee_type; //Sets the Primary Weapon attack message and animation
|
||||
@@ -537,11 +606,14 @@ protected:
|
||||
std::list<MercData> mercDataList;
|
||||
|
||||
bool raid_target;
|
||||
uint8 probability;
|
||||
bool ignore_despawn; //NPCs with this set to 1 will ignore the despawn value in spawngroup
|
||||
|
||||
|
||||
|
||||
private:
|
||||
uint32 loottable_id;
|
||||
bool skip_global_loot;
|
||||
bool skip_auto_scale;
|
||||
bool p_depop;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,627 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2018 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "npc_scale_manager.h"
|
||||
#include "../common/string_util.h"
|
||||
|
||||
/**
|
||||
* @param npc
|
||||
*/
|
||||
void NpcScaleManager::ScaleNPC(NPC * npc)
|
||||
{
|
||||
if (npc->IsSkipAutoScale())
|
||||
return;
|
||||
|
||||
int8 npc_type = GetNPCScalingType(npc);
|
||||
int npc_level = npc->GetLevel();
|
||||
bool is_auto_scaled = IsAutoScaled(npc);
|
||||
|
||||
global_npc_scale scale_data = GetGlobalScaleDataForTypeLevel(npc_type, npc_level);
|
||||
|
||||
if (!scale_data.level) {
|
||||
Log(Logs::General, Logs::NPCScaling, "NPC: %s - scaling data not found for type: %i level: %i",
|
||||
npc->GetCleanName(),
|
||||
npc_type,
|
||||
npc_level
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (npc->GetAC() == 0 && is_auto_scaled) {
|
||||
npc->ModifyNPCStat("ac", std::to_string(scale_data.ac).c_str());
|
||||
}
|
||||
if (npc->GetMaxHP() == 0) {
|
||||
npc->ModifyNPCStat("max_hp", std::to_string(scale_data.hp).c_str());
|
||||
npc->Heal();
|
||||
}
|
||||
if (npc->GetAccuracyRating() == 0) {
|
||||
npc->ModifyNPCStat("accuracy", std::to_string(scale_data.accuracy).c_str());
|
||||
}
|
||||
if (npc->GetSlowMitigation() == 0) {
|
||||
npc->ModifyNPCStat("slow_mitigation", std::to_string(scale_data.slow_mitigation).c_str());
|
||||
}
|
||||
if (npc->GetATK() == 0) {
|
||||
npc->ModifyNPCStat("atk", std::to_string(scale_data.attack).c_str());
|
||||
}
|
||||
if (npc->GetSTR() == 0) {
|
||||
npc->ModifyNPCStat("str", std::to_string(scale_data.strength).c_str());
|
||||
}
|
||||
if (npc->GetSTA() == 0) {
|
||||
npc->ModifyNPCStat("sta", std::to_string(scale_data.stamina).c_str());
|
||||
}
|
||||
if (npc->GetDEX() == 0) {
|
||||
npc->ModifyNPCStat("dex", std::to_string(scale_data.dexterity).c_str());
|
||||
}
|
||||
if (npc->GetAGI() == 0) {
|
||||
npc->ModifyNPCStat("agi", std::to_string(scale_data.agility).c_str());
|
||||
}
|
||||
if (npc->GetINT() == 0) {
|
||||
npc->ModifyNPCStat("int", std::to_string(scale_data.intelligence).c_str());
|
||||
}
|
||||
if (npc->GetWIS() == 0) {
|
||||
npc->ModifyNPCStat("wis", std::to_string(scale_data.wisdom).c_str());
|
||||
}
|
||||
if (npc->GetCHA() == 0) {
|
||||
npc->ModifyNPCStat("cha", std::to_string(scale_data.charisma).c_str());
|
||||
}
|
||||
if (npc->GetMR() == 0) {
|
||||
npc->ModifyNPCStat("mr", std::to_string(scale_data.magic_resist).c_str());
|
||||
}
|
||||
if (npc->GetCR() == 0) {
|
||||
npc->ModifyNPCStat("cr", std::to_string(scale_data.cold_resist).c_str());
|
||||
}
|
||||
if (npc->GetFR() == 0) {
|
||||
npc->ModifyNPCStat("fr", std::to_string(scale_data.fire_resist).c_str());
|
||||
}
|
||||
if (npc->GetPR() == 0) {
|
||||
npc->ModifyNPCStat("pr", std::to_string(scale_data.poison_resist).c_str());
|
||||
}
|
||||
if (npc->GetDR() == 0) {
|
||||
npc->ModifyNPCStat("dr", std::to_string(scale_data.disease_resist).c_str());
|
||||
}
|
||||
if (npc->GetCorrup() == 0 && is_auto_scaled) {
|
||||
npc->ModifyNPCStat("cor", std::to_string(scale_data.corruption_resist).c_str());
|
||||
}
|
||||
if (npc->GetPhR() == 0 && is_auto_scaled) {
|
||||
npc->ModifyNPCStat("phr", std::to_string(scale_data.physical_resist).c_str());
|
||||
}
|
||||
if (npc->GetMinDMG() == 0 && npc->GetMaxDMG() == 0) {
|
||||
int min_dmg = scale_data.min_dmg;
|
||||
if (RuleB(Combat, UseNPCDamageClassLevelMods)) {
|
||||
int32 class_level_damage_mod = GetClassLevelDamageMod(npc->GetLevel(), npc->GetClass());
|
||||
min_dmg = (min_dmg * class_level_damage_mod) / 220;
|
||||
|
||||
Log(Logs::Moderate,
|
||||
Logs::NPCScaling,
|
||||
"ClassLevelDamageMod::min_dmg base: %i calc: %i",
|
||||
scale_data.min_dmg,
|
||||
min_dmg);
|
||||
}
|
||||
|
||||
npc->ModifyNPCStat("min_hit", std::to_string(min_dmg).c_str());
|
||||
}
|
||||
if (npc->GetMaxDMG() == 0) {
|
||||
int max_dmg = scale_data.max_dmg;
|
||||
if (RuleB(Combat, UseNPCDamageClassLevelMods)) {
|
||||
int32 class_level_damage_mod = GetClassLevelDamageMod(npc->GetLevel(), npc->GetClass());
|
||||
max_dmg = (scale_data.max_dmg * class_level_damage_mod) / 220;
|
||||
|
||||
Log(Logs::Moderate,
|
||||
Logs::NPCScaling,
|
||||
"ClassLevelDamageMod::max_dmg base: %i calc: %i",
|
||||
scale_data.max_dmg,
|
||||
max_dmg
|
||||
);
|
||||
}
|
||||
|
||||
npc->ModifyNPCStat("max_hit", std::to_string(max_dmg).c_str());
|
||||
}
|
||||
if (npc->GetHPRegen() == 0) {
|
||||
npc->ModifyNPCStat("hp_regen", std::to_string(scale_data.hp_regen_rate).c_str());
|
||||
}
|
||||
if (npc->GetAttackDelay() == 0) {
|
||||
npc->ModifyNPCStat("attack_delay", std::to_string(scale_data.attack_delay).c_str());
|
||||
}
|
||||
if (npc->GetSpellScale() == 0) {
|
||||
npc->ModifyNPCStat("spell_scale", std::to_string(scale_data.spell_scale).c_str());
|
||||
}
|
||||
if (npc->GetHealScale() == 0) {
|
||||
npc->ModifyNPCStat("heal_scale", std::to_string(scale_data.heal_scale).c_str());
|
||||
}
|
||||
if (!npc->HasSpecialAbilities() && is_auto_scaled) {
|
||||
npc->ModifyNPCStat("special_abilities", scale_data.special_abilities.c_str());
|
||||
}
|
||||
|
||||
if (LogSys.log_settings[Logs::NPCScaling].is_category_enabled == 1) {
|
||||
std::string scale_log;
|
||||
|
||||
for (const auto &stat : scaling_stats) {
|
||||
std::string variable = StringFormat("modify_stat_%s", stat.c_str());
|
||||
if (npc->EntityVariableExists(variable.c_str())) {
|
||||
scale_log += stat + ": " + npc->GetEntityVariable(variable.c_str()) + " ";
|
||||
}
|
||||
}
|
||||
|
||||
Log(Logs::General,
|
||||
Logs::NPCScaling,
|
||||
"(%s) level: %i type: %i Auto: %s Setting: %s",
|
||||
npc->GetCleanName(),
|
||||
npc_level,
|
||||
npc_type,
|
||||
(is_auto_scaled ? "true" : "false"),
|
||||
scale_log.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool NpcScaleManager::LoadScaleData()
|
||||
{
|
||||
auto results = database.QueryDatabase(
|
||||
"SELECT "
|
||||
"type,"
|
||||
"level,"
|
||||
"ac,"
|
||||
"hp,"
|
||||
"accuracy,"
|
||||
"slow_mitigation,"
|
||||
"attack,"
|
||||
"strength,"
|
||||
"stamina,"
|
||||
"dexterity,"
|
||||
"agility,"
|
||||
"intelligence,"
|
||||
"wisdom,"
|
||||
"charisma,"
|
||||
"magic_resist,"
|
||||
"cold_resist,"
|
||||
"fire_resist,"
|
||||
"poison_resist,"
|
||||
"disease_resist,"
|
||||
"corruption_resist,"
|
||||
"physical_resist,"
|
||||
"min_dmg,"
|
||||
"max_dmg,"
|
||||
"hp_regen_rate,"
|
||||
"attack_delay,"
|
||||
"spell_scale,"
|
||||
"heal_scale,"
|
||||
"special_abilities"
|
||||
" FROM `npc_scale_global_base`"
|
||||
);
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
global_npc_scale scale_data;
|
||||
|
||||
scale_data.type = atoi(row[0]);
|
||||
scale_data.level = atoi(row[1]);
|
||||
scale_data.ac = atoi(row[2]);
|
||||
scale_data.hp = atoi(row[3]);
|
||||
scale_data.accuracy = atoi(row[4]);
|
||||
scale_data.slow_mitigation = atoi(row[5]);
|
||||
scale_data.attack = atoi(row[6]);
|
||||
scale_data.strength = atoi(row[7]);
|
||||
scale_data.stamina = atoi(row[8]);
|
||||
scale_data.dexterity = atoi(row[9]);
|
||||
scale_data.agility = atoi(row[10]);
|
||||
scale_data.intelligence = atoi(row[11]);
|
||||
scale_data.wisdom = atoi(row[12]);
|
||||
scale_data.charisma = atoi(row[13]);
|
||||
scale_data.magic_resist = atoi(row[14]);
|
||||
scale_data.cold_resist = atoi(row[15]);
|
||||
scale_data.fire_resist = atoi(row[16]);
|
||||
scale_data.poison_resist = atoi(row[17]);
|
||||
scale_data.disease_resist = atoi(row[18]);
|
||||
scale_data.corruption_resist = atoi(row[19]);
|
||||
scale_data.physical_resist = atoi(row[20]);
|
||||
scale_data.min_dmg = atoi(row[21]);
|
||||
scale_data.max_dmg = atoi(row[22]);
|
||||
scale_data.hp_regen_rate = atoi(row[23]);
|
||||
scale_data.attack_delay = atoi(row[24]);
|
||||
scale_data.spell_scale = atoi(row[25]);
|
||||
scale_data.heal_scale = atoi(row[26]);
|
||||
|
||||
if (row[25]) {
|
||||
scale_data.special_abilities = row[27];
|
||||
}
|
||||
|
||||
npc_global_base_scaling_data.insert(
|
||||
std::make_pair(
|
||||
std::make_pair(scale_data.type, scale_data.level),
|
||||
scale_data
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Log(Logs::General, Logs::NPCScaling, "Global Base Scaling Data Loaded...");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param npc_type
|
||||
* @param npc_level
|
||||
* @return NpcScaleManager::global_npc_scale
|
||||
*/
|
||||
NpcScaleManager::global_npc_scale NpcScaleManager::GetGlobalScaleDataForTypeLevel(int8 npc_type, int npc_level)
|
||||
{
|
||||
auto iter = npc_global_base_scaling_data.find(std::make_pair(npc_type, npc_level));
|
||||
if (iter != npc_global_base_scaling_data.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param level
|
||||
* @param npc_class
|
||||
* @return
|
||||
*/
|
||||
uint32 NpcScaleManager::GetClassLevelDamageMod(uint32 level, uint32 npc_class)
|
||||
{
|
||||
uint32 multiplier = 0;
|
||||
|
||||
switch (npc_class) {
|
||||
case WARRIOR: {
|
||||
if (level < 20) {
|
||||
multiplier = 220;
|
||||
}
|
||||
else if (level < 30) {
|
||||
multiplier = 230;
|
||||
}
|
||||
else if (level < 40) {
|
||||
multiplier = 250;
|
||||
}
|
||||
else if (level < 53) {
|
||||
multiplier = 270;
|
||||
}
|
||||
else if (level < 57) {
|
||||
multiplier = 280;
|
||||
}
|
||||
else if (level < 60) {
|
||||
multiplier = 290;
|
||||
}
|
||||
else if (level < 70) {
|
||||
multiplier = 300;
|
||||
}
|
||||
else {
|
||||
multiplier = 311;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DRUID:
|
||||
case CLERIC:
|
||||
case SHAMAN: {
|
||||
if (level < 70) {
|
||||
multiplier = 150;
|
||||
}
|
||||
else {
|
||||
multiplier = 157;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BERSERKER:
|
||||
case PALADIN:
|
||||
case SHADOWKNIGHT: {
|
||||
if (level < 35) {
|
||||
multiplier = 210;
|
||||
}
|
||||
else if (level < 45) {
|
||||
multiplier = 220;
|
||||
}
|
||||
else if (level < 51) {
|
||||
multiplier = 230;
|
||||
}
|
||||
else if (level < 56) {
|
||||
multiplier = 240;
|
||||
}
|
||||
else if (level < 60) {
|
||||
multiplier = 250;
|
||||
}
|
||||
else if (level < 68) {
|
||||
multiplier = 260;
|
||||
}
|
||||
else {
|
||||
multiplier = 270;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MONK:
|
||||
case BARD:
|
||||
case ROGUE:
|
||||
case BEASTLORD: {
|
||||
if (level < 51) {
|
||||
multiplier = 180;
|
||||
}
|
||||
else if (level < 58) {
|
||||
multiplier = 190;
|
||||
}
|
||||
else if (level < 70) {
|
||||
multiplier = 200;
|
||||
}
|
||||
else {
|
||||
multiplier = 210;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RANGER: {
|
||||
if (level < 58) {
|
||||
multiplier = 200;
|
||||
}
|
||||
else if (level < 70) {
|
||||
multiplier = 210;
|
||||
}
|
||||
else {
|
||||
multiplier = 220;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MAGICIAN:
|
||||
case WIZARD:
|
||||
case NECROMANCER:
|
||||
case ENCHANTER: {
|
||||
if (level < 70) {
|
||||
multiplier = 120;
|
||||
}
|
||||
else {
|
||||
multiplier = 127;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (level < 35) {
|
||||
multiplier = 210;
|
||||
}
|
||||
else if (level < 45) {
|
||||
multiplier = 220;
|
||||
}
|
||||
else if (level < 51) {
|
||||
multiplier = 230;
|
||||
}
|
||||
else if (level < 56) {
|
||||
multiplier = 240;
|
||||
}
|
||||
else if (level < 60) {
|
||||
multiplier = 250;
|
||||
}
|
||||
else {
|
||||
multiplier = 260;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param npc
|
||||
* @return int8
|
||||
*/
|
||||
int8 NpcScaleManager::GetNPCScalingType(NPC *&npc)
|
||||
{
|
||||
std::string npc_name = npc->GetName();
|
||||
|
||||
if (npc->IsRaidTarget()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (npc->IsRareSpawn() || npc_name.find('#') != std::string::npos || isupper(npc_name[0])) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param npc
|
||||
* @return std::string
|
||||
*/
|
||||
std::string NpcScaleManager::GetNPCScalingTypeName(NPC *&npc)
|
||||
{
|
||||
int8 scaling_type = GetNPCScalingType(npc);
|
||||
|
||||
if (scaling_type == 1) {
|
||||
return "Named";
|
||||
}
|
||||
|
||||
if (npc->IsRaidTarget()) {
|
||||
return "Raid";
|
||||
}
|
||||
|
||||
return "Trash";
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines based on minimum criteria if NPC is auto scaled for certain things to be scaled like
|
||||
* special abilities. We use this so we don't blindly assume we want things to be applied
|
||||
*
|
||||
* @param npc
|
||||
* @return
|
||||
*/
|
||||
bool NpcScaleManager::IsAutoScaled(NPC *npc)
|
||||
{
|
||||
return
|
||||
(npc->GetHP() == 0 &&
|
||||
npc->GetMaxDMG() == 0 &&
|
||||
npc->GetMinDMG() == 0 &&
|
||||
npc->GetSTR() == 0 &&
|
||||
npc->GetSTA() == 0 &&
|
||||
npc->GetDEX() == 0 &&
|
||||
npc->GetAGI() == 0 &&
|
||||
npc->GetINT() == 0 &&
|
||||
npc->GetWIS() == 0 &&
|
||||
npc->GetCHA() == 0 &&
|
||||
npc->GetMR() == 0 &&
|
||||
npc->GetFR() == 0 &&
|
||||
npc->GetCR() == 0 &&
|
||||
npc->GetPR() == 0 &&
|
||||
npc->GetDR() == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if scaling data not found
|
||||
* @param npc
|
||||
* @return
|
||||
*/
|
||||
bool NpcScaleManager::ApplyGlobalBaseScalingToNPCStatically(NPC *&npc)
|
||||
{
|
||||
int8 npc_type = GetNPCScalingType(npc);
|
||||
int npc_level = npc->GetLevel();
|
||||
|
||||
global_npc_scale scale_data = GetGlobalScaleDataForTypeLevel(npc_type, npc_level);
|
||||
|
||||
if (!scale_data.level) {
|
||||
Log(
|
||||
Logs::General,
|
||||
Logs::NPCScaling,
|
||||
"NpcScaleManager::ApplyGlobalBaseScalingToNPCStatically NPC: %s - scaling data not found for type: %i level: %i",
|
||||
npc->GetCleanName(),
|
||||
npc_type,
|
||||
npc_level
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string query = StringFormat(
|
||||
"UPDATE `npc_types` SET "
|
||||
"AC = %i, "
|
||||
"hp = %i, "
|
||||
"Accuracy = %i, "
|
||||
"slow_mitigation = %i, "
|
||||
"ATK = %i, "
|
||||
"STR = %i, "
|
||||
"STA = %i, "
|
||||
"DEX = %i, "
|
||||
"AGI = %i, "
|
||||
"_INT = %i, "
|
||||
"WIS = %i, "
|
||||
"CHA = %i, "
|
||||
"MR = %i, "
|
||||
"CR = %i, "
|
||||
"FR = %i, "
|
||||
"PR = %i, "
|
||||
"DR = %i, "
|
||||
"Corrup = %i, "
|
||||
"PhR = %i, "
|
||||
"mindmg = %i, "
|
||||
"maxdmg = %i, "
|
||||
"hp_regen_rate = %i, "
|
||||
"attack_delay = %i, "
|
||||
"spellscale = %i, "
|
||||
"healscale = %i, "
|
||||
"special_abilities = '%s' "
|
||||
"WHERE `id` = %i",
|
||||
scale_data.ac,
|
||||
scale_data.hp,
|
||||
scale_data.accuracy,
|
||||
scale_data.slow_mitigation,
|
||||
scale_data.attack,
|
||||
scale_data.strength,
|
||||
scale_data.stamina,
|
||||
scale_data.dexterity,
|
||||
scale_data.agility,
|
||||
scale_data.intelligence,
|
||||
scale_data.wisdom,
|
||||
scale_data.charisma,
|
||||
scale_data.magic_resist,
|
||||
scale_data.cold_resist,
|
||||
scale_data.fire_resist,
|
||||
scale_data.poison_resist,
|
||||
scale_data.disease_resist,
|
||||
scale_data.corruption_resist,
|
||||
scale_data.physical_resist,
|
||||
scale_data.min_dmg,
|
||||
scale_data.max_dmg,
|
||||
scale_data.hp_regen_rate,
|
||||
scale_data.attack_delay,
|
||||
scale_data.spell_scale,
|
||||
scale_data.heal_scale,
|
||||
EscapeString(scale_data.special_abilities).c_str(),
|
||||
npc->GetNPCTypeID()
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if scaling data not found
|
||||
* @param npc
|
||||
* @return
|
||||
*/
|
||||
bool NpcScaleManager::ApplyGlobalBaseScalingToNPCDynamically(NPC *&npc)
|
||||
{
|
||||
int8 npc_type = GetNPCScalingType(npc);
|
||||
int npc_level = npc->GetLevel();
|
||||
|
||||
global_npc_scale scale_data = GetGlobalScaleDataForTypeLevel(npc_type, npc_level);
|
||||
|
||||
if (!scale_data.level) {
|
||||
Log(
|
||||
Logs::General,
|
||||
Logs::NPCScaling,
|
||||
"NpcScaleManager::ApplyGlobalBaseScalingToNPCDynamically NPC: %s - scaling data not found for type: %i level: %i",
|
||||
npc->GetCleanName(),
|
||||
npc_type,
|
||||
npc_level
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string query = StringFormat(
|
||||
"UPDATE `npc_types` SET "
|
||||
"AC = 0, "
|
||||
"hp = 0, "
|
||||
"Accuracy = 0, "
|
||||
"slow_mitigation = 0, "
|
||||
"ATK = 0, "
|
||||
"STR = 0, "
|
||||
"STA = 0, "
|
||||
"DEX = 0, "
|
||||
"AGI = 0, "
|
||||
"_INT = 0, "
|
||||
"WIS = 0, "
|
||||
"CHA = 0, "
|
||||
"MR = 0, "
|
||||
"CR = 0, "
|
||||
"FR = 0, "
|
||||
"PR = 0, "
|
||||
"DR = 0, "
|
||||
"Corrup = 0, "
|
||||
"PhR = 0, "
|
||||
"mindmg = 0, "
|
||||
"maxdmg = 0, "
|
||||
"hp_regen_rate = 0, "
|
||||
"attack_delay = 0, "
|
||||
"spellscale = 0, "
|
||||
"healscale = 0, "
|
||||
"special_abilities = '' "
|
||||
"WHERE `id` = %i",
|
||||
npc->GetNPCTypeID()
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2018 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_NPC_SCALE_MANAGER_H
|
||||
#define EQEMU_NPC_SCALE_MANAGER_H
|
||||
|
||||
#include "npc.h"
|
||||
|
||||
class NpcScaleManager {
|
||||
public:
|
||||
struct global_npc_scale {
|
||||
int type;
|
||||
int level;
|
||||
int ac;
|
||||
int hp;
|
||||
int accuracy;
|
||||
int slow_mitigation;
|
||||
int attack;
|
||||
int strength;
|
||||
int stamina;
|
||||
int dexterity;
|
||||
int agility;
|
||||
int intelligence;
|
||||
int wisdom;
|
||||
int charisma;
|
||||
int magic_resist;
|
||||
int cold_resist;
|
||||
int fire_resist;
|
||||
int poison_resist;
|
||||
int disease_resist;
|
||||
int corruption_resist;
|
||||
int physical_resist;
|
||||
int min_dmg;
|
||||
int max_dmg;
|
||||
int hp_regen_rate;
|
||||
int attack_delay;
|
||||
int spell_scale;
|
||||
int heal_scale;
|
||||
|
||||
std::string special_abilities;
|
||||
};
|
||||
|
||||
std::vector<std::string> scaling_stats = {
|
||||
"ac",
|
||||
"max_hp",
|
||||
"accuracy",
|
||||
"slow_mitigation",
|
||||
"atk",
|
||||
"str",
|
||||
"sta",
|
||||
"dex",
|
||||
"agi",
|
||||
"int",
|
||||
"wis",
|
||||
"cha",
|
||||
"mr",
|
||||
"cr",
|
||||
"fr",
|
||||
"pr",
|
||||
"dr",
|
||||
"cr",
|
||||
"pr",
|
||||
"min_hit",
|
||||
"max_hit",
|
||||
"hp_regen",
|
||||
"attack_delay",
|
||||
"spell_scale",
|
||||
"heal_scale",
|
||||
"special_abilities"
|
||||
};
|
||||
|
||||
void ScaleNPC(NPC * npc);
|
||||
bool IsAutoScaled(NPC * npc);
|
||||
bool LoadScaleData();
|
||||
|
||||
global_npc_scale GetGlobalScaleDataForTypeLevel(int8 npc_type, int npc_level);
|
||||
|
||||
std::map<std::pair<int, int>, global_npc_scale> npc_global_base_scaling_data;
|
||||
|
||||
int8 GetNPCScalingType(NPC * &npc);
|
||||
std::string GetNPCScalingTypeName(NPC * &npc);
|
||||
bool ApplyGlobalBaseScalingToNPCStatically(NPC * &npc);
|
||||
bool ApplyGlobalBaseScalingToNPCDynamically(NPC * &npc);
|
||||
|
||||
uint32 GetClassLevelDamageMod(uint32 level, uint32 npc_class);
|
||||
};
|
||||
|
||||
extern NpcScaleManager *npc_scale_manager;
|
||||
|
||||
#endif //EQEMU_NPC_SCALE_MANAGER_H
|
||||
+8
-6
@@ -328,7 +328,7 @@ void Object::Delete(bool reset_state)
|
||||
}
|
||||
|
||||
const EQEmu::ItemInstance* Object::GetItem(uint8 index) {
|
||||
if (index < EQEmu::legacy::TYPE_WORLD_SIZE) {
|
||||
if (index < EQEmu::invtype::WORLD_SIZE) {
|
||||
return m_inst->GetItem(index);
|
||||
}
|
||||
|
||||
@@ -366,7 +366,7 @@ void Object::Close() {
|
||||
EQEmu::ItemInstance* container = this->m_inst;
|
||||
if(container != nullptr)
|
||||
{
|
||||
for (uint8 i = EQEmu::inventory::containerBegin; i < EQEmu::inventory::ContainerCount; i++)
|
||||
for (uint8 i = EQEmu::invbag::SLOT_BEGIN; i <= EQEmu::invbag::SLOT_END; i++)
|
||||
{
|
||||
EQEmu::ItemInstance* inst = container->PopItem(i);
|
||||
if(inst != nullptr)
|
||||
@@ -522,11 +522,13 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object)
|
||||
|
||||
|
||||
// Transfer item to client
|
||||
sender->PutItemInInventory(EQEmu::inventory::slotCursor, *m_inst, false);
|
||||
sender->SendItemPacket(EQEmu::inventory::slotCursor, m_inst, ItemPacketTrade);
|
||||
sender->PutItemInInventory(EQEmu::invslot::slotCursor, *m_inst, false);
|
||||
sender->SendItemPacket(EQEmu::invslot::slotCursor, m_inst, ItemPacketTrade);
|
||||
|
||||
if(cursordelete) // delete the item if it's a duplicate lore. We have to do this because the client expects the item packet
|
||||
sender->DeleteItemInInventory(EQEmu::inventory::slotCursor);
|
||||
sender->DeleteItemInInventory(EQEmu::invslot::slotCursor);
|
||||
|
||||
sender->DropItemQS(m_inst, true);
|
||||
|
||||
if(!m_ground_spawn)
|
||||
safe_delete(m_inst);
|
||||
@@ -603,7 +605,7 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object)
|
||||
auto outapp = new EQApplicationPacket(OP_ClientReady, 0);
|
||||
sender->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
for (uint8 i = EQEmu::inventory::containerBegin; i < EQEmu::inventory::ContainerCount; i++) {
|
||||
for (uint8 i = EQEmu::invbag::SLOT_BEGIN; i <= EQEmu::invbag::SLOT_END; i++) {
|
||||
const EQEmu::ItemInstance* inst = m_inst->GetItem(i);
|
||||
if (inst) {
|
||||
//sender->GetInv().PutItem(i+4000,inst);
|
||||
|
||||
+14
-14
@@ -179,20 +179,20 @@ protected:
|
||||
void ResetState(); // Set state back to original
|
||||
void RandomSpawn(bool send_packet = false); //spawn this ground spawn at a random place
|
||||
|
||||
Object_Struct m_data; // Packet data
|
||||
EQEmu::ItemInstance* m_inst; // Item representing object
|
||||
bool m_inuse; // Currently in use by a client?
|
||||
uint32 m_id; // Database key, different than drop_id
|
||||
uint32 m_type; // Object Type, ie, forge, oven, dropped item, etc (ref: ContainerUseTypes)
|
||||
uint32 m_icon; // Icon to use for forge, oven, etc
|
||||
float m_max_x;
|
||||
float m_max_y;
|
||||
float m_min_x;
|
||||
float m_min_y;
|
||||
float m_z;
|
||||
float m_heading;
|
||||
bool m_ground_spawn;
|
||||
char m_display_name[64];
|
||||
Object_Struct m_data; // Packet data
|
||||
EQEmu::ItemInstance *m_inst; // Item representing object
|
||||
bool m_inuse; // Currently in use by a client?
|
||||
uint32 m_id; // Database key, different than drop_id
|
||||
uint32 m_type; // Object Type, ie, forge, oven, dropped item, etc (ref: ContainerUseTypes)
|
||||
uint32 m_icon; // Icon to use for forge, oven, etc
|
||||
float m_max_x;
|
||||
float m_max_y;
|
||||
float m_min_x;
|
||||
float m_min_y;
|
||||
float m_z;
|
||||
float m_heading;
|
||||
bool m_ground_spawn;
|
||||
char m_display_name[64];
|
||||
|
||||
std::map<std::string, std::string> o_EntityVariables;
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "../common/seperator.h"
|
||||
#include "client.h"
|
||||
#include "pathfinder_null.h"
|
||||
#include "pathfinder_nav_mesh.h"
|
||||
#include "pathfinder_waypoint.h"
|
||||
#include <fmt/format.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
IPathfinder *IPathfinder::Load(const std::string &zone) {
|
||||
struct stat statbuffer;
|
||||
std::string navmesh_path = fmt::format("maps/nav/{0}.nav", zone);
|
||||
if (stat(navmesh_path.c_str(), &statbuffer) == 0) {
|
||||
return new PathfinderNavmesh(navmesh_path);
|
||||
}
|
||||
|
||||
return new PathfinderNull();
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include "map.h"
|
||||
#include <list>
|
||||
|
||||
class Client;
|
||||
class Seperator;
|
||||
|
||||
enum PathingPolyFlags
|
||||
{
|
||||
PathingNormal = 1,
|
||||
PathingWater = 2,
|
||||
PathingLava = 4,
|
||||
PathingZoneLine = 8,
|
||||
PathingPvP = 16,
|
||||
PathingSlime = 32,
|
||||
PathingIce = 64,
|
||||
PathingVWater = 128,
|
||||
PathingGeneralArea = 256,
|
||||
PathingPortal = 512,
|
||||
PathingPrefer = 1024,
|
||||
PathingDisabled = 2048,
|
||||
PathingAll = 65535,
|
||||
PathingNotDisabled = PathingAll ^ PathingDisabled
|
||||
};
|
||||
|
||||
struct PathfinderOptions
|
||||
{
|
||||
PathfinderOptions() {
|
||||
flags = PathingNotDisabled;
|
||||
smooth_path = true;
|
||||
step_size = 10.0f;
|
||||
flag_cost[0] = 1.0f;
|
||||
flag_cost[1] = 3.0f;
|
||||
flag_cost[2] = 5.0f;
|
||||
flag_cost[3] = 1.0f;
|
||||
flag_cost[4] = 2.0f;
|
||||
flag_cost[5] = 2.0f;
|
||||
flag_cost[6] = 4.0f;
|
||||
flag_cost[7] = 1.0f;
|
||||
flag_cost[8] = 0.1f;
|
||||
flag_cost[9] = 0.1f;
|
||||
offset = 3.25f;
|
||||
}
|
||||
|
||||
int flags;
|
||||
bool smooth_path;
|
||||
float step_size;
|
||||
float flag_cost[10];
|
||||
float offset;
|
||||
};
|
||||
|
||||
class IPathfinder
|
||||
{
|
||||
public:
|
||||
struct IPathNode
|
||||
{
|
||||
IPathNode(const glm::vec3 &p) {
|
||||
pos = p;
|
||||
teleport = false;
|
||||
}
|
||||
|
||||
IPathNode(bool tp) {
|
||||
teleport = tp;
|
||||
}
|
||||
|
||||
glm::vec3 pos;
|
||||
bool teleport;
|
||||
};
|
||||
|
||||
typedef std::list<IPathNode> IPath;
|
||||
|
||||
IPathfinder() { }
|
||||
virtual ~IPathfinder() { }
|
||||
|
||||
virtual IPath FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, int flags = PathingNotDisabled) = 0;
|
||||
virtual IPath FindPath(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, const PathfinderOptions& opts) = 0;
|
||||
virtual glm::vec3 GetRandomLocation(const glm::vec3 &start) = 0;
|
||||
virtual void DebugCommand(Client *c, const Seperator *sep) = 0;
|
||||
|
||||
static IPathfinder *Load(const std::string &zone);
|
||||
};
|
||||
@@ -0,0 +1,565 @@
|
||||
#include <memory>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include "pathfinder_nav_mesh.h"
|
||||
#include <DetourCommon.h>
|
||||
#include <DetourNavMeshQuery.h>
|
||||
|
||||
#include "zone.h"
|
||||
#include "water_map.h"
|
||||
#include "client.h"
|
||||
#include "../common/compression.h"
|
||||
|
||||
extern Zone *zone;
|
||||
|
||||
const int MaxNavmeshNodes = 4096;
|
||||
|
||||
struct PathfinderNavmesh::Implementation
|
||||
{
|
||||
dtNavMesh *nav_mesh;
|
||||
dtNavMeshQuery *query;
|
||||
};
|
||||
|
||||
PathfinderNavmesh::PathfinderNavmesh(const std::string &path)
|
||||
{
|
||||
m_impl.reset(new Implementation());
|
||||
m_impl->nav_mesh = nullptr;
|
||||
m_impl->query = nullptr;
|
||||
Load(path);
|
||||
}
|
||||
|
||||
PathfinderNavmesh::~PathfinderNavmesh()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, int flags)
|
||||
{
|
||||
partial = false;
|
||||
|
||||
if (!m_impl->nav_mesh) {
|
||||
return IPath();
|
||||
}
|
||||
|
||||
if (!m_impl->query) {
|
||||
m_impl->query = dtAllocNavMeshQuery();
|
||||
}
|
||||
|
||||
m_impl->query->init(m_impl->nav_mesh, MaxNavmeshNodes);
|
||||
glm::vec3 current_location(start.x, start.z, start.y);
|
||||
glm::vec3 dest_location(end.x, end.z, end.y);
|
||||
|
||||
dtQueryFilter filter;
|
||||
filter.setIncludeFlags(flags);
|
||||
filter.setAreaCost(0, 1.0f); //Normal
|
||||
filter.setAreaCost(1, 3.0f); //Water
|
||||
filter.setAreaCost(2, 5.0f); //Lava
|
||||
filter.setAreaCost(4, 1.0f); //PvP
|
||||
filter.setAreaCost(5, 2.0f); //Slime
|
||||
filter.setAreaCost(6, 2.0f); //Ice
|
||||
filter.setAreaCost(7, 4.0f); //V Water (Frigid Water)
|
||||
filter.setAreaCost(8, 1.0f); //General Area
|
||||
filter.setAreaCost(9, 0.1f); //Portal
|
||||
filter.setAreaCost(10, 0.1f); //Prefer
|
||||
|
||||
dtPolyRef start_ref;
|
||||
dtPolyRef end_ref;
|
||||
glm::vec3 ext(5.0f, 100.0f, 5.0f);
|
||||
|
||||
m_impl->query->findNearestPoly(¤t_location[0], &ext[0], &filter, &start_ref, 0);
|
||||
m_impl->query->findNearestPoly(&dest_location[0], &ext[0], &filter, &end_ref, 0);
|
||||
|
||||
if (!start_ref || !end_ref) {
|
||||
return IPath();
|
||||
}
|
||||
|
||||
int npoly = 0;
|
||||
dtPolyRef path[1024] = { 0 };
|
||||
auto status = m_impl->query->findPath(start_ref, end_ref, ¤t_location[0], &dest_location[0], &filter, path, &npoly, 1024);
|
||||
|
||||
if (npoly) {
|
||||
glm::vec3 epos = dest_location;
|
||||
if (path[npoly - 1] != end_ref) {
|
||||
m_impl->query->closestPointOnPoly(path[npoly - 1], &dest_location[0], &epos[0], 0);
|
||||
partial = true;
|
||||
|
||||
auto dist = DistanceSquared(epos, current_location);
|
||||
if (dist < 10000.0f) {
|
||||
stuck = true;
|
||||
}
|
||||
}
|
||||
|
||||
float straight_path[2048 * 3];
|
||||
unsigned char straight_path_flags[2048];
|
||||
|
||||
int n_straight_polys;
|
||||
dtPolyRef straight_path_polys[2048];
|
||||
|
||||
status = m_impl->query->findStraightPath(¤t_location[0], &epos[0], path, npoly,
|
||||
straight_path, straight_path_flags,
|
||||
straight_path_polys, &n_straight_polys, 2048, DT_STRAIGHTPATH_AREA_CROSSINGS);
|
||||
|
||||
if (dtStatusFailed(status)) {
|
||||
return IPath();
|
||||
}
|
||||
|
||||
if (n_straight_polys) {
|
||||
IPath Route;
|
||||
for (int i = 0; i < n_straight_polys; ++i)
|
||||
{
|
||||
glm::vec3 node;
|
||||
node.x = straight_path[i * 3];
|
||||
node.z = straight_path[i * 3 + 1];
|
||||
node.y = straight_path[i * 3 + 2];
|
||||
|
||||
Route.push_back(node);
|
||||
|
||||
unsigned short flag = 0;
|
||||
if (dtStatusSucceed(m_impl->nav_mesh->getPolyFlags(straight_path_polys[i], &flag))) {
|
||||
if (flag & 512) {
|
||||
Route.push_back(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Route;
|
||||
}
|
||||
}
|
||||
|
||||
IPath Route;
|
||||
Route.push_back(end);
|
||||
return Route;
|
||||
}
|
||||
|
||||
IPathfinder::IPath PathfinderNavmesh::FindPath(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, const PathfinderOptions &opts)
|
||||
{
|
||||
partial = false;
|
||||
|
||||
if (!m_impl->nav_mesh) {
|
||||
return IPath();
|
||||
}
|
||||
|
||||
if (!m_impl->query) {
|
||||
m_impl->query = dtAllocNavMeshQuery();
|
||||
}
|
||||
|
||||
m_impl->query->init(m_impl->nav_mesh, MaxNavmeshNodes);
|
||||
glm::vec3 current_location(start.x, start.z, start.y);
|
||||
glm::vec3 dest_location(end.x, end.z, end.y);
|
||||
|
||||
dtQueryFilter filter;
|
||||
filter.setIncludeFlags(opts.flags);
|
||||
filter.setAreaCost(0, opts.flag_cost[0]); //Normal
|
||||
filter.setAreaCost(1, opts.flag_cost[1]); //Water
|
||||
filter.setAreaCost(2, opts.flag_cost[2]); //Lava
|
||||
filter.setAreaCost(4, opts.flag_cost[3]); //PvP
|
||||
filter.setAreaCost(5, opts.flag_cost[4]); //Slime
|
||||
filter.setAreaCost(6, opts.flag_cost[5]); //Ice
|
||||
filter.setAreaCost(7, opts.flag_cost[6]); //V Water (Frigid Water)
|
||||
filter.setAreaCost(8, opts.flag_cost[7]); //General Area
|
||||
filter.setAreaCost(9, opts.flag_cost[8]); //Portal
|
||||
filter.setAreaCost(10, opts.flag_cost[9]); //Prefer
|
||||
|
||||
static const int max_polys = 256;
|
||||
dtPolyRef start_ref;
|
||||
dtPolyRef end_ref;
|
||||
glm::vec3 ext(10.0f, 200.0f, 10.0f);
|
||||
|
||||
m_impl->query->findNearestPoly(¤t_location[0], &ext[0], &filter, &start_ref, 0);
|
||||
m_impl->query->findNearestPoly(&dest_location[0], &ext[0], &filter, &end_ref, 0);
|
||||
|
||||
if (!start_ref || !end_ref) {
|
||||
return IPath();
|
||||
}
|
||||
|
||||
int npoly = 0;
|
||||
dtPolyRef path[max_polys] = { 0 };
|
||||
m_impl->query->findPath(start_ref, end_ref, ¤t_location[0], &dest_location[0], &filter, path, &npoly, max_polys);
|
||||
|
||||
if (npoly) {
|
||||
glm::vec3 epos = dest_location;
|
||||
if (path[npoly - 1] != end_ref) {
|
||||
m_impl->query->closestPointOnPoly(path[npoly - 1], &dest_location[0], &epos[0], 0);
|
||||
partial = true;
|
||||
|
||||
auto dist = DistanceSquared(epos, current_location);
|
||||
if (dist < 10000.0f) {
|
||||
stuck = true;
|
||||
}
|
||||
}
|
||||
|
||||
int n_straight_polys;
|
||||
glm::vec3 straight_path[max_polys];
|
||||
unsigned char straight_path_flags[max_polys];
|
||||
dtPolyRef straight_path_polys[max_polys];
|
||||
|
||||
auto status = m_impl->query->findStraightPath(¤t_location[0], &epos[0], path, npoly,
|
||||
(float*)&straight_path[0], straight_path_flags,
|
||||
straight_path_polys, &n_straight_polys, 2048, DT_STRAIGHTPATH_AREA_CROSSINGS | DT_STRAIGHTPATH_ALL_CROSSINGS);
|
||||
|
||||
if (dtStatusFailed(status)) {
|
||||
return IPath();
|
||||
}
|
||||
|
||||
if (n_straight_polys) {
|
||||
if (opts.smooth_path) {
|
||||
IPath Route;
|
||||
|
||||
//Add the first point
|
||||
{
|
||||
auto &flag = straight_path_flags[0];
|
||||
if (flag & DT_STRAIGHTPATH_OFFMESH_CONNECTION) {
|
||||
auto &p = straight_path[0];
|
||||
|
||||
Route.push_back(glm::vec3(p.x, p.z, p.y));
|
||||
}
|
||||
else {
|
||||
auto &p = straight_path[0];
|
||||
|
||||
float h = 0.0f;
|
||||
if (dtStatusSucceed(GetPolyHeightOnPath(path, npoly, p, &h))) {
|
||||
p.y = h + opts.offset;
|
||||
}
|
||||
|
||||
Route.push_back(glm::vec3(p.x, p.z, p.y));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < n_straight_polys - 1; ++i)
|
||||
{
|
||||
auto &flag = straight_path_flags[i];
|
||||
|
||||
if (flag & DT_STRAIGHTPATH_OFFMESH_CONNECTION) {
|
||||
auto &poly = straight_path_polys[i];
|
||||
|
||||
auto &p2 = straight_path[i + 1];
|
||||
glm::vec3 node(p2.x, p2.z, p2.y);
|
||||
Route.push_back(node);
|
||||
|
||||
unsigned short pflag = 0;
|
||||
if (dtStatusSucceed(m_impl->nav_mesh->getPolyFlags(straight_path_polys[i], &pflag))) {
|
||||
if (pflag & 512) {
|
||||
Route.push_back(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto &p1 = straight_path[i];
|
||||
auto &p2 = straight_path[i + 1];
|
||||
auto dist = glm::distance(p1, p2);
|
||||
auto dir = glm::normalize(p2 - p1);
|
||||
float total = 0.0f;
|
||||
glm::vec3 previous_pt = p1;
|
||||
|
||||
while (total < dist) {
|
||||
glm::vec3 current_pt;
|
||||
float dist_to_move = opts.step_size;
|
||||
float ff = opts.step_size / 2.0f;
|
||||
|
||||
if (total + dist_to_move + ff >= dist) {
|
||||
current_pt = p2;
|
||||
total = dist;
|
||||
}
|
||||
else {
|
||||
total += dist_to_move;
|
||||
current_pt = p1 + dir * total;
|
||||
}
|
||||
|
||||
float h = 0.0f;
|
||||
if (dtStatusSucceed(GetPolyHeightOnPath(path, npoly, current_pt, &h))) {
|
||||
current_pt.y = h + opts.offset;
|
||||
}
|
||||
|
||||
Route.push_back(glm::vec3(current_pt.x, current_pt.z, current_pt.y));
|
||||
previous_pt = current_pt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Route;
|
||||
}
|
||||
else {
|
||||
IPath Route;
|
||||
for (int i = 0; i < n_straight_polys; ++i)
|
||||
{
|
||||
auto ¤t = straight_path[i];
|
||||
glm::vec3 node(current.x, current.z, current.y);
|
||||
Route.push_back(node);
|
||||
|
||||
unsigned short flag = 0;
|
||||
if (dtStatusSucceed(m_impl->nav_mesh->getPolyFlags(straight_path_polys[i], &flag))) {
|
||||
if (flag & 512) {
|
||||
Route.push_back(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Route;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return IPath();
|
||||
}
|
||||
|
||||
glm::vec3 PathfinderNavmesh::GetRandomLocation(const glm::vec3 &start)
|
||||
{
|
||||
if (start.x == 0.0f && start.y == 0.0)
|
||||
return glm::vec3(0.f);
|
||||
|
||||
if (!m_impl->nav_mesh) {
|
||||
return glm::vec3(0.f);
|
||||
}
|
||||
|
||||
if (!m_impl->query) {
|
||||
m_impl->query = dtAllocNavMeshQuery();
|
||||
m_impl->query->init(m_impl->nav_mesh, MaxNavmeshNodes);
|
||||
}
|
||||
|
||||
dtQueryFilter filter;
|
||||
filter.setIncludeFlags(65535U ^ 2048);
|
||||
filter.setAreaCost(0, 1.0f); //Normal
|
||||
filter.setAreaCost(1, 3.0f); //Water
|
||||
filter.setAreaCost(2, 5.0f); //Lava
|
||||
filter.setAreaCost(4, 1.0f); //PvP
|
||||
filter.setAreaCost(5, 2.0f); //Slime
|
||||
filter.setAreaCost(6, 2.0f); //Ice
|
||||
filter.setAreaCost(7, 4.0f); //V Water (Frigid Water)
|
||||
filter.setAreaCost(8, 1.0f); //General Area
|
||||
filter.setAreaCost(9, 0.1f); //Portal
|
||||
filter.setAreaCost(10, 0.1f); //Prefer
|
||||
|
||||
dtPolyRef randomRef;
|
||||
float point[3];
|
||||
|
||||
dtPolyRef start_ref;
|
||||
glm::vec3 current_location(start.x, start.z, start.y);
|
||||
glm::vec3 ext(5.0f, 100.0f, 5.0f);
|
||||
|
||||
m_impl->query->findNearestPoly(¤t_location[0], &ext[0], &filter, &start_ref, 0);
|
||||
|
||||
if (!start_ref)
|
||||
{
|
||||
return glm::vec3(0.f);
|
||||
}
|
||||
|
||||
if (dtStatusSucceed(m_impl->query->findRandomPointAroundCircle(start_ref, ¤t_location[0], 100.f, &filter, []() { return (float)zone->random.Real(0.0, 1.0); }, &randomRef, point)))
|
||||
{
|
||||
return glm::vec3(point[0], point[2], point[1]);
|
||||
}
|
||||
|
||||
return glm::vec3(0.f);
|
||||
}
|
||||
|
||||
void PathfinderNavmesh::DebugCommand(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (sep->arg[1][0] == '\0' || !strcasecmp(sep->arg[1], "help"))
|
||||
{
|
||||
c->Message(0, "#path show: Plots a path from the user to their target.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp(sep->arg[1], "show"))
|
||||
{
|
||||
if (c->GetTarget() != nullptr) {
|
||||
auto target = c->GetTarget();
|
||||
glm::vec3 start(c->GetX(), c->GetY(), c->GetZ());
|
||||
glm::vec3 end(target->GetX(), target->GetY(), target->GetZ());
|
||||
|
||||
ShowPath(c, start, end);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void PathfinderNavmesh::Clear()
|
||||
{
|
||||
if (m_impl->nav_mesh) {
|
||||
dtFreeNavMesh(m_impl->nav_mesh);
|
||||
}
|
||||
|
||||
if (m_impl->query) {
|
||||
dtFreeNavMeshQuery(m_impl->query);
|
||||
}
|
||||
}
|
||||
|
||||
void PathfinderNavmesh::Load(const std::string &path)
|
||||
{
|
||||
Clear();
|
||||
|
||||
FILE *f = fopen(path.c_str(), "rb");
|
||||
if (f) {
|
||||
char magic[9] = { 0 };
|
||||
if (fread(magic, 9, 1, f) != 1) {
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp(magic, "EQNAVMESH", 9) != 0)
|
||||
{
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t version = 0;
|
||||
if (fread(&version, sizeof(uint32_t), 1, f) != 1) {
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
|
||||
if (version != 2) {
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t data_size;
|
||||
if (fread(&data_size, sizeof(data_size), 1, f) != 1) {
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t buffer_size;
|
||||
if (fread(&buffer_size, sizeof(buffer_size), 1, f) != 1) {
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<char> data;
|
||||
data.resize(data_size);
|
||||
if (fread(&data[0], data_size, 1, f) != 1) {
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<char> buffer;
|
||||
buffer.resize(buffer_size);
|
||||
uint32_t v = EQEmu::InflateData(&data[0], data_size, &buffer[0], buffer_size);
|
||||
fclose(f);
|
||||
|
||||
char *buf = &buffer[0];
|
||||
m_impl->nav_mesh = dtAllocNavMesh();
|
||||
|
||||
uint32_t number_of_tiles = *(uint32_t*)buf;
|
||||
buf += sizeof(uint32_t);
|
||||
|
||||
dtNavMeshParams params = *(dtNavMeshParams*)buf;
|
||||
buf += sizeof(dtNavMeshParams);
|
||||
|
||||
dtStatus status = m_impl->nav_mesh->init(¶ms);
|
||||
if (dtStatusFailed(status))
|
||||
{
|
||||
dtFreeNavMesh(m_impl->nav_mesh);
|
||||
m_impl->nav_mesh = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < number_of_tiles; ++i)
|
||||
{
|
||||
uint32_t tile_ref = *(uint32_t*)buf;
|
||||
buf += sizeof(uint32_t);
|
||||
|
||||
int32_t data_size = *(uint32_t*)buf;
|
||||
buf += sizeof(uint32_t);
|
||||
|
||||
if (!tile_ref || !data_size) {
|
||||
dtFreeNavMesh(m_impl->nav_mesh);
|
||||
m_impl->nav_mesh = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned char* data = (unsigned char*)dtAlloc(data_size, DT_ALLOC_PERM);
|
||||
memcpy(data, buf, data_size);
|
||||
buf += data_size;
|
||||
|
||||
m_impl->nav_mesh->addTile(data, data_size, DT_TILE_FREE_DATA, tile_ref, 0);
|
||||
}
|
||||
|
||||
Log(Logs::General, Logs::Status, "Loaded Navmesh V%u file %s", version, path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void PathfinderNavmesh::ShowPath(Client * c, const glm::vec3 &start, const glm::vec3 &end)
|
||||
{
|
||||
auto &list = entity_list.GetNPCList();
|
||||
|
||||
for (auto &iter : list) {
|
||||
auto npc = iter.second;
|
||||
auto name = npc->GetName();
|
||||
|
||||
if (strstr(name, "PathNode") != nullptr) {
|
||||
npc->Depop();
|
||||
}
|
||||
}
|
||||
|
||||
PathfinderOptions opts;
|
||||
opts.smooth_path = true;
|
||||
opts.step_size = RuleR(Pathing, NavmeshStepSize);
|
||||
bool partial = false;
|
||||
bool stuck = false;
|
||||
auto path = FindPath(start, end, partial, stuck, opts);
|
||||
|
||||
for (auto &node : path) {
|
||||
if (!node.teleport) {
|
||||
NPC::SpawnNPC("PathNode 2253 1 0 1 2 1", glm::vec4(node.pos, 1.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dtStatus PathfinderNavmesh::GetPolyHeightNoConnections(dtPolyRef ref, const float *pos, float *height) const
|
||||
{
|
||||
auto *m_nav = m_impl->nav_mesh;
|
||||
|
||||
if (!m_nav) {
|
||||
return DT_FAILURE;
|
||||
}
|
||||
|
||||
const dtMeshTile* tile = 0;
|
||||
const dtPoly* poly = 0;
|
||||
if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly))) {
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (poly->getType() != DT_POLYTYPE_OFFMESH_CONNECTION) {
|
||||
const unsigned int ip = (unsigned int)(poly - tile->polys);
|
||||
const dtPolyDetail* pd = &tile->detailMeshes[ip];
|
||||
for (int j = 0; j < pd->triCount; ++j)
|
||||
{
|
||||
const unsigned char* t = &tile->detailTris[(pd->triBase + j) * 4];
|
||||
const float* v[3];
|
||||
for (int k = 0; k < 3; ++k)
|
||||
{
|
||||
if (t[k] < poly->vertCount)
|
||||
v[k] = &tile->verts[poly->verts[t[k]] * 3];
|
||||
else
|
||||
v[k] = &tile->detailVerts[(pd->vertBase + (t[k] - poly->vertCount)) * 3];
|
||||
}
|
||||
float h;
|
||||
if (dtClosestHeightPointTriangle(pos, v[0], v[1], v[2], h))
|
||||
{
|
||||
if (height)
|
||||
*height = h;
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
}
|
||||
|
||||
dtStatus PathfinderNavmesh::GetPolyHeightOnPath(const dtPolyRef *path, const int path_len, const glm::vec3 &pos, float *h) const
|
||||
{
|
||||
if (!path || !path_len) {
|
||||
return DT_FAILURE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < path_len; ++i) {
|
||||
dtPolyRef ref = path[i];
|
||||
|
||||
if (dtStatusSucceed(GetPolyHeightNoConnections(ref, &pos[0], h))) {
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return DT_FAILURE;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "pathfinder_interface.h"
|
||||
#include <string>
|
||||
#include <DetourNavMesh.h>
|
||||
|
||||
class PathfinderNavmesh : public IPathfinder
|
||||
{
|
||||
public:
|
||||
PathfinderNavmesh(const std::string &path);
|
||||
virtual ~PathfinderNavmesh();
|
||||
|
||||
virtual IPath FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, int flags = PathingNotDisabled);
|
||||
virtual IPath FindPath(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, const PathfinderOptions& opts);
|
||||
virtual glm::vec3 GetRandomLocation(const glm::vec3 &start);
|
||||
virtual void DebugCommand(Client *c, const Seperator *sep);
|
||||
|
||||
private:
|
||||
void Clear();
|
||||
void Load(const std::string &path);
|
||||
void ShowPath(Client *c, const glm::vec3 &start, const glm::vec3 &end);
|
||||
dtStatus GetPolyHeightNoConnections(dtPolyRef ref, const float *pos, float *height) const;
|
||||
dtStatus GetPolyHeightOnPath(const dtPolyRef *path, const int path_len, const glm::vec3 &pos, float *h) const;
|
||||
|
||||
struct Implementation;
|
||||
std::unique_ptr<Implementation> m_impl;
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "pathfinder_null.h"
|
||||
|
||||
IPathfinder::IPath PathfinderNull::FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, int flags)
|
||||
{
|
||||
partial = false;
|
||||
stuck = false;
|
||||
IPath ret;
|
||||
ret.push_back(start);
|
||||
ret.push_back(end);
|
||||
return ret;
|
||||
}
|
||||
|
||||
IPathfinder::IPath PathfinderNull::FindPath(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, const PathfinderOptions &opts)
|
||||
{
|
||||
partial = false;
|
||||
stuck = false;
|
||||
IPath ret;
|
||||
ret.push_back(start);
|
||||
ret.push_back(end);
|
||||
return ret;
|
||||
}
|
||||
|
||||
glm::vec3 PathfinderNull::GetRandomLocation(const glm::vec3 &start)
|
||||
{
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "pathfinder_interface.h"
|
||||
|
||||
class PathfinderNull : public IPathfinder
|
||||
{
|
||||
public:
|
||||
PathfinderNull() { }
|
||||
virtual ~PathfinderNull() { }
|
||||
|
||||
virtual IPath FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, int flags = PathingNotDisabled);
|
||||
virtual IPath FindPath(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, const PathfinderOptions& opts);
|
||||
virtual glm::vec3 GetRandomLocation(const glm::vec3 &start);
|
||||
virtual void DebugCommand(Client *c, const Seperator *sep) { }
|
||||
};
|
||||
@@ -0,0 +1,564 @@
|
||||
#include <boost/geometry.hpp>
|
||||
#include <boost/geometry/geometries/point.hpp>
|
||||
#include <boost/geometry/index/rtree.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/astar_search.hpp>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pathfinder_waypoint.h"
|
||||
#include "zone.h"
|
||||
#include "client.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/rulesys.h"
|
||||
|
||||
extern Zone *zone;
|
||||
|
||||
#pragma pack(1)
|
||||
struct NeighbourNode {
|
||||
int16 id;
|
||||
float distance;
|
||||
uint8 Teleport;
|
||||
int16 DoorID;
|
||||
};
|
||||
|
||||
struct PathNode {
|
||||
uint16 id;
|
||||
glm::vec3 v;
|
||||
float bestz;
|
||||
NeighbourNode Neighbours[50];
|
||||
};
|
||||
|
||||
struct PathFileHeader {
|
||||
uint32 version;
|
||||
uint32 PathNodeCount;
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
struct Edge
|
||||
{
|
||||
float distance;
|
||||
bool teleport;
|
||||
int door_id;
|
||||
};
|
||||
|
||||
struct Node
|
||||
{
|
||||
int id;
|
||||
glm::vec3 v;
|
||||
float bestz;
|
||||
std::map<int, Edge> edges;
|
||||
};
|
||||
|
||||
template <class Graph, class CostType, class NodeMap>
|
||||
class distance_heuristic : public boost::astar_heuristic<Graph, CostType>
|
||||
{
|
||||
public:
|
||||
typedef typename boost::graph_traits<Graph>::vertex_descriptor Vertex;
|
||||
|
||||
distance_heuristic(NodeMap n, Vertex goal)
|
||||
: m_node(n), m_goal(goal) {}
|
||||
CostType operator()(Vertex u)
|
||||
{
|
||||
CostType dx = m_node[m_goal].v.x - m_node[u].v.x;
|
||||
CostType dy = m_node[m_goal].v.y - m_node[u].v.y;
|
||||
CostType dz = m_node[m_goal].v.z - m_node[u].v.z;
|
||||
return ::sqrt(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
private:
|
||||
NodeMap m_node;
|
||||
Vertex m_goal;
|
||||
};
|
||||
|
||||
struct found_goal {};
|
||||
template <class Vertex>
|
||||
class astar_goal_visitor : public boost::default_astar_visitor
|
||||
{
|
||||
public:
|
||||
astar_goal_visitor(Vertex goal) : m_goal(goal) {}
|
||||
template <class Graph>
|
||||
void examine_vertex(Vertex u, Graph& g) {
|
||||
if (u == m_goal)
|
||||
throw found_goal();
|
||||
}
|
||||
private:
|
||||
Vertex m_goal;
|
||||
};
|
||||
|
||||
typedef boost::geometry::model::point<float, 3, boost::geometry::cs::cartesian> Point;
|
||||
typedef std::pair<Point, unsigned int> RTreeValue;
|
||||
typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS, boost::no_property,
|
||||
boost::property<boost::edge_weight_t, float>> GraphType;
|
||||
typedef boost::property_map<GraphType, boost::edge_weight_t>::type WeightMap;
|
||||
|
||||
struct PathfinderWaypoint::Implementation {
|
||||
bool PathFileValid;
|
||||
boost::geometry::index::rtree<RTreeValue, boost::geometry::index::quadratic<16>> Tree;
|
||||
GraphType Graph;
|
||||
std::vector<Node> Nodes;
|
||||
std::string FileName;
|
||||
};
|
||||
|
||||
PathfinderWaypoint::PathfinderWaypoint(const std::string &path)
|
||||
{
|
||||
m_impl.reset(new Implementation());
|
||||
m_impl->PathFileValid = false;
|
||||
m_impl->FileName = path;
|
||||
Load(path);
|
||||
}
|
||||
|
||||
PathfinderWaypoint::~PathfinderWaypoint()
|
||||
{
|
||||
}
|
||||
|
||||
IPathfinder::IPath PathfinderWaypoint::FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, int flags)
|
||||
{
|
||||
stuck = false;
|
||||
partial = false;
|
||||
std::vector<RTreeValue> result_start_n;
|
||||
m_impl->Tree.query(boost::geometry::index::nearest(Point(start.x, start.y, start.z), 1), std::back_inserter(result_start_n));
|
||||
if (result_start_n.size() == 0) {
|
||||
return IPath();
|
||||
}
|
||||
|
||||
std::vector<RTreeValue> result_end_n;
|
||||
m_impl->Tree.query(boost::geometry::index::nearest(Point(end.x, end.y, end.z), 1), std::back_inserter(result_end_n));
|
||||
if (result_end_n.size() == 0) {
|
||||
return IPath();
|
||||
}
|
||||
|
||||
auto &nearest_start = *result_start_n.begin();
|
||||
auto &nearest_end = *result_end_n.begin();
|
||||
|
||||
if (nearest_start.second == nearest_end.second) {
|
||||
IPath Route;
|
||||
Route.push_back(start);
|
||||
Route.push_back(end);
|
||||
return Route;
|
||||
}
|
||||
|
||||
std::vector<GraphType::vertex_descriptor> p(boost::num_vertices(m_impl->Graph));
|
||||
try {
|
||||
boost::astar_search(m_impl->Graph, nearest_start.second,
|
||||
distance_heuristic<GraphType, float, Node*>(&m_impl->Nodes[0], nearest_end.second),
|
||||
boost::predecessor_map(&p[0])
|
||||
.visitor(astar_goal_visitor<size_t>(nearest_end.second)));
|
||||
}
|
||||
catch (found_goal)
|
||||
{
|
||||
IPath Route;
|
||||
|
||||
Route.push_front(end);
|
||||
for (size_t v = nearest_end.second;; v = p[v]) {
|
||||
if (p[v] == v) {
|
||||
Route.push_front(m_impl->Nodes[v].v);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
auto &node = m_impl->Nodes[v];
|
||||
|
||||
auto iter = node.edges.find((int)p[v + 1]);
|
||||
if (iter != node.edges.end()) {
|
||||
auto &edge = iter->second;
|
||||
if (edge.teleport) {
|
||||
Route.push_front(m_impl->Nodes[v].v);
|
||||
Route.push_front(true);
|
||||
}
|
||||
else {
|
||||
Route.push_front(m_impl->Nodes[v].v);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Route.push_front(m_impl->Nodes[v].v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Route.push_front(start);
|
||||
return Route;
|
||||
}
|
||||
|
||||
return IPath();
|
||||
}
|
||||
|
||||
glm::vec3 PathfinderWaypoint::GetRandomLocation(const glm::vec3 &start)
|
||||
{
|
||||
if (m_impl->Nodes.size() > 0) {
|
||||
auto idx = zone->random.Int(0, (int)m_impl->Nodes.size() - 1);
|
||||
auto &node = m_impl->Nodes[idx];
|
||||
|
||||
return node.v;
|
||||
}
|
||||
|
||||
return glm::vec3();
|
||||
}
|
||||
|
||||
void PathfinderWaypoint::DebugCommand(Client *c, const Seperator *sep)
|
||||
{
|
||||
if(sep->arg[1][0] == '\0' || !strcasecmp(sep->arg[1], "help"))
|
||||
{
|
||||
c->Message(0, "Syntax: #path shownodes: Spawns a npc to represent every npc node.");
|
||||
c->Message(0, "#path show: Plots a path from the user to their target.");
|
||||
c->Message(0, "#path info node_id: Gives information about node info (requires shownode target).");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!strcasecmp(sep->arg[1], "shownodes"))
|
||||
{
|
||||
ShowNodes();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp(sep->arg[1], "show"))
|
||||
{
|
||||
if (c->GetTarget() != nullptr) {
|
||||
auto target = c->GetTarget();
|
||||
glm::vec3 start(c->GetX(), c->GetY(), c->GetZ());
|
||||
glm::vec3 end(target->GetX(), target->GetY(), target->GetZ());
|
||||
|
||||
ShowPath(c, start, end);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp(sep->arg[1], "reload"))
|
||||
{
|
||||
Load(m_impl->FileName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp(sep->arg[1], "info"))
|
||||
{
|
||||
NodeInfo(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void PathfinderWaypoint::Load(const std::string &filename) {
|
||||
PathFileHeader Head;
|
||||
Head.PathNodeCount = 0;
|
||||
Head.version = 2;
|
||||
|
||||
FILE *f = fopen(filename.c_str(), "rb");
|
||||
if (f) {
|
||||
char Magic[10];
|
||||
|
||||
fread(&Magic, 9, 1, f);
|
||||
|
||||
if (strncmp(Magic, "EQEMUPATH", 9))
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Bad Magic String in .path file.");
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
|
||||
fread(&Head, sizeof(Head), 1, f);
|
||||
|
||||
Log(Logs::General, Logs::Status, "Path File Header: Version %ld, PathNodes %ld",
|
||||
(long)Head.version, (long)Head.PathNodeCount);
|
||||
|
||||
if (Head.version == 2)
|
||||
{
|
||||
LoadV2(f, Head);
|
||||
return;
|
||||
}
|
||||
else if (Head.version == 3) {
|
||||
LoadV3(f, Head);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
Log(Logs::General, Logs::Error, "Unsupported path file version.");
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PathfinderWaypoint::LoadV2(FILE *f, const PathFileHeader &header)
|
||||
{
|
||||
std::unique_ptr<PathNode[]> PathNodes(new PathNode[header.PathNodeCount]);
|
||||
|
||||
fread(PathNodes.get(), sizeof(PathNode), header.PathNodeCount, f);
|
||||
|
||||
int MaxNodeID = header.PathNodeCount - 1;
|
||||
|
||||
m_impl->PathFileValid = true;
|
||||
|
||||
m_impl->Nodes.reserve(header.PathNodeCount);
|
||||
for (uint32 i = 0; i < header.PathNodeCount; ++i)
|
||||
{
|
||||
auto &n = PathNodes[i];
|
||||
Node node;
|
||||
node.id = i;
|
||||
node.v = n.v;
|
||||
node.bestz = n.bestz;
|
||||
m_impl->Nodes.push_back(node);
|
||||
}
|
||||
|
||||
auto weightmap = boost::get(boost::edge_weight, m_impl->Graph);
|
||||
for (uint32 i = 0; i < header.PathNodeCount; ++i) {
|
||||
for (uint32 j = 0; j < 50; ++j)
|
||||
{
|
||||
auto &node = m_impl->Nodes[i];
|
||||
if (PathNodes[i].Neighbours[j].id > MaxNodeID)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Path Node %i, Neighbour %i (%i) out of range.", i, j, PathNodes[i].Neighbours[j].id);
|
||||
m_impl->PathFileValid = false;
|
||||
}
|
||||
|
||||
if (PathNodes[i].Neighbours[j].id > 0) {
|
||||
Edge edge;
|
||||
edge.distance = PathNodes[i].Neighbours[j].distance;
|
||||
edge.door_id = PathNodes[i].Neighbours[j].DoorID;
|
||||
edge.teleport = PathNodes[i].Neighbours[j].Teleport;
|
||||
|
||||
node.edges[PathNodes[i].Neighbours[j].id] = edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BuildGraph();
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void PathfinderWaypoint::LoadV3(FILE *f, const PathFileHeader &header)
|
||||
{
|
||||
m_impl->Nodes.reserve(header.PathNodeCount);
|
||||
|
||||
uint32 edge_count = 0;
|
||||
fread(&edge_count, sizeof(uint32), 1, f);
|
||||
|
||||
for (uint32 i = 0; i < header.PathNodeCount; ++i)
|
||||
{
|
||||
uint32 id = 0;
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
float z = 0.0f;
|
||||
float best_z = 0.0f;
|
||||
|
||||
fread(&id, sizeof(uint32), 1, f);
|
||||
fread(&x, sizeof(float), 1, f);
|
||||
fread(&y, sizeof(float), 1, f);
|
||||
fread(&z, sizeof(float), 1, f);
|
||||
fread(&best_z, sizeof(float), 1, f);
|
||||
|
||||
Node n;
|
||||
n.id = id;
|
||||
n.bestz = best_z;
|
||||
n.v.x = x;
|
||||
n.v.y = y;
|
||||
n.v.z = z;
|
||||
|
||||
m_impl->Nodes.push_back(n);
|
||||
}
|
||||
|
||||
for (uint32 j = 0; j < edge_count; ++j) {
|
||||
uint32 from = 0;
|
||||
uint32 to = 0;
|
||||
int8 teleport = 0;
|
||||
float distance = 0.0f;
|
||||
int32 door_id = 0;
|
||||
|
||||
fread(&from, sizeof(uint32), 1, f);
|
||||
fread(&to, sizeof(uint32), 1, f);
|
||||
fread(&teleport, sizeof(int8), 1, f);
|
||||
fread(&distance, sizeof(float), 1, f);
|
||||
fread(&door_id, sizeof(int32), 1, f);
|
||||
|
||||
Edge e;
|
||||
e.teleport = teleport > 0 ? true : false;
|
||||
e.distance = distance;
|
||||
e.door_id = door_id;
|
||||
|
||||
auto &n = m_impl->Nodes[from];
|
||||
n.edges[to] = e;
|
||||
}
|
||||
|
||||
m_impl->PathFileValid = true;
|
||||
|
||||
BuildGraph();
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void PathfinderWaypoint::ShowNodes()
|
||||
{
|
||||
for (size_t i = 0; i < m_impl->Nodes.size(); ++i)
|
||||
{
|
||||
ShowNode(m_impl->Nodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void PathfinderWaypoint::ShowPath(Client *c, const glm::vec3 &start, const glm::vec3 &end)
|
||||
{
|
||||
bool partial = false;
|
||||
bool stuck = false;
|
||||
auto path = FindRoute(start, end, partial, stuck);
|
||||
std::vector<FindPerson_Point> points;
|
||||
|
||||
FindPerson_Point p;
|
||||
for (auto &node : path)
|
||||
{
|
||||
if (!node.teleport) {
|
||||
p.x = node.pos.x;
|
||||
p.y = node.pos.y;
|
||||
p.z = node.pos.z;
|
||||
|
||||
points.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
c->SendPathPacket(points);
|
||||
}
|
||||
|
||||
void PathfinderWaypoint::NodeInfo(Client *c)
|
||||
{
|
||||
if (!c->GetTarget()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ());
|
||||
if (node == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(0, "Pathing node: %i at (%.2f, %.2f, %.2f) with bestz %.2f",
|
||||
node->id, node->v.x, node->v.y, node->v.z, node->bestz);
|
||||
|
||||
for (auto &edge : node->edges) {
|
||||
c->Message(0, "id: %i, distance: %.2f, door id: %i, is teleport: %i",
|
||||
edge.first,
|
||||
edge.second.distance,
|
||||
edge.second.door_id,
|
||||
edge.second.teleport);
|
||||
}
|
||||
}
|
||||
|
||||
Node *PathfinderWaypoint::FindPathNodeByCoordinates(float x, float y, float z)
|
||||
{
|
||||
for (auto &node : m_impl->Nodes) {
|
||||
auto dist = Distance(glm::vec3(x, y, z), node.v);
|
||||
|
||||
if (dist < 0.1) {
|
||||
return &node;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PathfinderWaypoint::BuildGraph()
|
||||
{
|
||||
m_impl->Graph = GraphType();
|
||||
m_impl->Tree = boost::geometry::index::rtree<RTreeValue, boost::geometry::index::quadratic<16>>();
|
||||
|
||||
for (auto &node : m_impl->Nodes) {
|
||||
RTreeValue rtv;
|
||||
rtv.first = Point(node.v.x, node.v.y, node.v.z);
|
||||
rtv.second = node.id;
|
||||
m_impl->Tree.insert(rtv);
|
||||
boost::add_vertex(m_impl->Graph);
|
||||
}
|
||||
|
||||
//Populate edges now that we've created all the nodes
|
||||
auto weightmap = boost::get(boost::edge_weight, m_impl->Graph);
|
||||
for (auto &node : m_impl->Nodes) {
|
||||
for (auto &edge : node.edges) {
|
||||
GraphType::edge_descriptor e;
|
||||
bool inserted;
|
||||
boost::tie(e, inserted) = boost::add_edge(node.id, edge.first, m_impl->Graph);
|
||||
weightmap[e] = edge.second.distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string DigitToWord(int i)
|
||||
{
|
||||
std::string digit = std::to_string(i);
|
||||
std::string ret;
|
||||
for (size_t idx = 0; idx < digit.length(); ++idx) {
|
||||
if (!ret.empty()) {
|
||||
ret += "_";
|
||||
}
|
||||
|
||||
switch (digit[idx]) {
|
||||
case '0':
|
||||
ret += "Zero";
|
||||
break;
|
||||
case '1':
|
||||
ret += "One";
|
||||
break;
|
||||
case '2':
|
||||
ret += "Two";
|
||||
break;
|
||||
case '3':
|
||||
ret += "Three";
|
||||
break;
|
||||
case '4':
|
||||
ret += "Four";
|
||||
break;
|
||||
case '5':
|
||||
ret += "Five";
|
||||
break;
|
||||
case '6':
|
||||
ret += "Six";
|
||||
break;
|
||||
case '7':
|
||||
ret += "Seven";
|
||||
break;
|
||||
case '8':
|
||||
ret += "Eight";
|
||||
break;
|
||||
case '9':
|
||||
ret += "Nine";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PathfinderWaypoint::ShowNode(const Node &n) {
|
||||
auto npc_type = new NPCType;
|
||||
memset(npc_type, 0, sizeof(NPCType));
|
||||
|
||||
sprintf(npc_type->name, "%s", DigitToWord(n.id).c_str());
|
||||
sprintf(npc_type->lastname, "%i", n.id);
|
||||
npc_type->current_hp = 4000000;
|
||||
npc_type->max_hp = 4000000;
|
||||
npc_type->race = 2254;
|
||||
npc_type->gender = 2;
|
||||
npc_type->class_ = 9;
|
||||
npc_type->deity = 1;
|
||||
npc_type->level = 75;
|
||||
npc_type->npc_id = 0;
|
||||
npc_type->loottable_id = 0;
|
||||
npc_type->texture = 1;
|
||||
npc_type->light = 0;
|
||||
npc_type->runspeed = 0;
|
||||
npc_type->d_melee_texture1 = 1;
|
||||
npc_type->d_melee_texture2 = 1;
|
||||
npc_type->merchanttype = 1;
|
||||
npc_type->bodytype = 1;
|
||||
npc_type->show_name = true;
|
||||
|
||||
npc_type->STR = 150;
|
||||
npc_type->STA = 150;
|
||||
npc_type->DEX = 150;
|
||||
npc_type->AGI = 150;
|
||||
npc_type->INT = 150;
|
||||
npc_type->WIS = 150;
|
||||
npc_type->CHA = 150;
|
||||
|
||||
npc_type->findable = 1;
|
||||
auto position = glm::vec4(n.v.x, n.v.y, n.v.z, 0.0f);
|
||||
auto npc = new NPC(npc_type, nullptr, position, GravityBehavior::Flying);
|
||||
npc->GiveNPCTypeData(npc_type);
|
||||
|
||||
entity_list.AddNPC(npc, true, true);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "pathfinder_interface.h"
|
||||
|
||||
struct PathFileHeader;
|
||||
struct Node;
|
||||
|
||||
class PathfinderWaypoint : public IPathfinder
|
||||
{
|
||||
public:
|
||||
PathfinderWaypoint(const std::string &path);
|
||||
virtual ~PathfinderWaypoint();
|
||||
|
||||
virtual IPath FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, int flags = PathingNotDisabled);
|
||||
virtual glm::vec3 GetRandomLocation(const glm::vec3 &start);
|
||||
virtual void DebugCommand(Client *c, const Seperator *sep);
|
||||
|
||||
private:
|
||||
void Load(const std::string &filename);
|
||||
void LoadV2(FILE *f, const PathFileHeader &header);
|
||||
void LoadV3(FILE *f, const PathFileHeader &header);
|
||||
void ShowNodes();
|
||||
void ShowPath(Client *c, const glm::vec3 &start, const glm::vec3 &end);
|
||||
void NodeInfo(Client *c);
|
||||
Node *FindPathNodeByCoordinates(float x, float y, float z);
|
||||
void BuildGraph();
|
||||
void ShowNode(const Node &n);
|
||||
|
||||
struct Implementation;
|
||||
std::unique_ptr<Implementation> m_impl;
|
||||
};
|
||||
+82
-2273
File diff suppressed because it is too large
Load Diff
-111
@@ -1,111 +0,0 @@
|
||||
#ifndef PATHING_H
|
||||
#define PATHING_H
|
||||
|
||||
#include "map.h"
|
||||
#include "zone_config.h"
|
||||
#include <deque>
|
||||
|
||||
extern const ZoneConfig *Config;
|
||||
|
||||
class Client;
|
||||
class Mob;
|
||||
|
||||
#define PATHNODENEIGHBOURS 50
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct AStarNode
|
||||
{
|
||||
int PathNodeID;
|
||||
int Parent;
|
||||
float HCost;
|
||||
float GCost;
|
||||
bool Teleport;
|
||||
};
|
||||
|
||||
struct NeighbourNode {
|
||||
int16 id;
|
||||
float distance;
|
||||
uint8 Teleport;
|
||||
int16 DoorID;
|
||||
};
|
||||
|
||||
struct PathNode {
|
||||
uint16 id;
|
||||
glm::vec3 v;
|
||||
float bestz;
|
||||
NeighbourNode Neighbours[PATHNODENEIGHBOURS];
|
||||
};
|
||||
|
||||
struct PathFileHeader {
|
||||
uint32 version;
|
||||
uint32 PathNodeCount;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
struct PathNodeSortStruct
|
||||
{
|
||||
int id;
|
||||
float Distance;
|
||||
};
|
||||
|
||||
enum LOSType{ UnknownLOS, HaveLOS, NoLOS };
|
||||
|
||||
class PathManager {
|
||||
|
||||
public:
|
||||
PathManager();
|
||||
~PathManager();
|
||||
|
||||
|
||||
static PathManager *LoadPathFile(const char *ZoneName);
|
||||
bool loadPaths(FILE *fp);
|
||||
void PrintPathing();
|
||||
std::deque<int> FindRoute(glm::vec3 Start, glm::vec3 End);
|
||||
std::deque<int> FindRoute(int startID, int endID);
|
||||
|
||||
glm::vec3 GetPathNodeCoordinates(int NodeNumber, bool BestZ = true);
|
||||
bool CheckLosFN(glm::vec3 a, glm::vec3 b);
|
||||
void SpawnPathNodes();
|
||||
void MeshTest();
|
||||
void SimpleMeshTest();
|
||||
int FindNearestPathNode(glm::vec3 Position);
|
||||
bool NoHazards(glm::vec3 From, glm::vec3 To);
|
||||
bool NoHazardsAccurate(glm::vec3 From, glm::vec3 To);
|
||||
void OpenDoors(int Node1, int Node2, Mob* ForWho);
|
||||
|
||||
PathNode* FindPathNodeByCoordinates(float x, float y, float z);
|
||||
void ShowPathNodeNeighbours(Client *c);
|
||||
int GetRandomPathNode();
|
||||
|
||||
void NodeInfo(Client *c);
|
||||
int32 AddNode(float x, float y, float z, float best_z, int32 requested_id = 0); //return -1 on failure, else returns the id of this node
|
||||
bool DeleteNode(Client *c);
|
||||
bool DeleteNode(int32 id); //returns true on success, false on failure, tries to delete a node from this map
|
||||
void ConnectNodeToNode(Client *c, int32 Node2, int32 teleport = 0, int32 doorid = -1); //connects a node both ways
|
||||
void ConnectNodeToNode(int32 Node1, int32 Node2, int32 teleport = 0, int32 doorid = -1);
|
||||
void ConnectNode(Client *c, int32 Node2, int32 teleport = 0, int32 doorid = -1); //connects a node one way
|
||||
void ConnectNode(int32 Node1, int32 Node2, int32 teleport = 0, int32 doorid = -1);
|
||||
void DisconnectNodeToNode(Client *c, int32 Node2);
|
||||
void DisconnectNodeToNode(int32 Node1, int32 Node2);
|
||||
void MoveNode(Client *c);
|
||||
void DisconnectAll(Client *c);
|
||||
bool NodesConnected(PathNode *a, PathNode *b);
|
||||
void DumpPath(std::string filename);
|
||||
void ProcessNodesAndSave(std::string filename);
|
||||
void ResortConnections();
|
||||
void QuickConnect(Client *c, bool set = false);
|
||||
void SortNodes();
|
||||
|
||||
private:
|
||||
PathFileHeader Head;
|
||||
PathNode *PathNodes;
|
||||
int QuickConnectTarget;
|
||||
|
||||
int *ClosedListFlag;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+2783
-2977
File diff suppressed because it is too large
Load Diff
+269
-310
@@ -26,7 +26,9 @@
|
||||
*/
|
||||
|
||||
#include "../common/features.h"
|
||||
|
||||
#ifdef EMBPERL_XS_CLASSES
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "embperl.h"
|
||||
|
||||
@@ -41,282 +43,270 @@
|
||||
#endif
|
||||
|
||||
XS(XS_Doors_GetDoorDBID); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_GetDoorDBID)
|
||||
{
|
||||
XS(XS_Doors_GetDoorDBID) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Doors::GetDoorDBID(THIS)");
|
||||
{
|
||||
Doors * THIS;
|
||||
uint32 RETVAL;
|
||||
Doors *THIS;
|
||||
uint32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetDoorDBID();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Doors_GetDoorID); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_GetDoorID)
|
||||
{
|
||||
XS(XS_Doors_GetDoorID) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Doors::GetDoorID(THIS)");
|
||||
{
|
||||
Doors * THIS;
|
||||
uint32 RETVAL;
|
||||
Doors *THIS;
|
||||
uint32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetDoorID();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Doors_GetID); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_GetID)
|
||||
{
|
||||
XS(XS_Doors_GetID) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Doors::GetID(THIS)");
|
||||
{
|
||||
Doors * THIS;
|
||||
uint16 RETVAL;
|
||||
Doors *THIS;
|
||||
uint16 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetEntityID();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Doors_GetX); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_GetX)
|
||||
{
|
||||
XS(XS_Doors_GetX) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Doors::GetX(THIS)");
|
||||
{
|
||||
Doors * THIS;
|
||||
float RETVAL;
|
||||
Doors *THIS;
|
||||
float RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetPosition().x;
|
||||
XSprePUSH; PUSHn((double)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHn((double) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Doors_GetY); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_GetY)
|
||||
{
|
||||
XS(XS_Doors_GetY) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Doors::GetY(THIS)");
|
||||
{
|
||||
Doors * THIS;
|
||||
float RETVAL;
|
||||
Doors *THIS;
|
||||
float RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetPosition().y;
|
||||
XSprePUSH; PUSHn((double)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHn((double) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Doors_GetZ); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_GetZ)
|
||||
{
|
||||
XS(XS_Doors_GetZ) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Doors::GetZ(THIS)");
|
||||
{
|
||||
Doors * THIS;
|
||||
float RETVAL;
|
||||
Doors *THIS;
|
||||
float RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetPosition().z;
|
||||
XSprePUSH; PUSHn((double)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHn((double) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Doors_GetHeading); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_GetHeading)
|
||||
{
|
||||
XS(XS_Doors_GetHeading) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Doors::GetHeading(THIS)");
|
||||
{
|
||||
Doors * THIS;
|
||||
float RETVAL;
|
||||
Doors *THIS;
|
||||
float RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetPosition().w;
|
||||
XSprePUSH; PUSHn((double)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHn((double) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Doors_GetOpenType); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_GetOpenType)
|
||||
{
|
||||
XS(XS_Doors_GetOpenType) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Doors::GetOpenType(THIS)");
|
||||
{
|
||||
Doors * THIS;
|
||||
uint32 RETVAL;
|
||||
Doors *THIS;
|
||||
uint32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetOpenType();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Doors_GetLockpick); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_GetLockpick)
|
||||
{
|
||||
XS(XS_Doors_GetLockpick) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Doors::GetLockpick(THIS)");
|
||||
{
|
||||
Doors * THIS;
|
||||
uint32 RETVAL;
|
||||
Doors *THIS;
|
||||
uint32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetLockpick();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Doors_GetKeyItem); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_GetKeyItem)
|
||||
{
|
||||
XS(XS_Doors_GetKeyItem) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Doors::GetKeyItem(THIS)");
|
||||
{
|
||||
Doors * THIS;
|
||||
uint32 RETVAL;
|
||||
Doors *THIS;
|
||||
uint32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetKeyItem();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Doors_GetNoKeyring); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_GetNoKeyring)
|
||||
{
|
||||
XS(XS_Doors_GetNoKeyring) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Doors::GetNoKeyring(THIS, type)");
|
||||
Perl_croak(aTHX_ "Usage: Doors::GetNoKeyring(THIS, uint8 type)");
|
||||
{
|
||||
Doors * THIS;
|
||||
uint8 type = (uint8)SvUV(ST(1));
|
||||
Doors *THIS;
|
||||
uint8 type = (uint8) SvUV(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->GetNoKeyring();
|
||||
@@ -325,76 +315,71 @@ XS(XS_Doors_GetNoKeyring)
|
||||
}
|
||||
|
||||
XS(XS_Doors_GetIncline); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_GetIncline)
|
||||
{
|
||||
XS(XS_Doors_GetIncline) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Doors::GetIncline(THIS)");
|
||||
{
|
||||
Doors * THIS;
|
||||
uint32 RETVAL;
|
||||
Doors *THIS;
|
||||
uint32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetIncline();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Doors_GetSize); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_GetSize)
|
||||
{
|
||||
XS(XS_Doors_GetSize) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Doors::GetIncline(THIS)");
|
||||
{
|
||||
Doors * THIS;
|
||||
uint32 RETVAL;
|
||||
Doors *THIS;
|
||||
uint32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetSize();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
XS(XS_Doors_SetOpenType); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_SetOpenType)
|
||||
{
|
||||
XS(XS_Doors_SetOpenType) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetOpenType(THIS, type)");
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetOpenType(THIS, uint32 open_type)");
|
||||
{
|
||||
Doors * THIS;
|
||||
uint32 type = (uint32)SvUV(ST(1));
|
||||
Doors *THIS;
|
||||
uint32 type = (uint32) SvUV(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->SetOpenType(type);
|
||||
@@ -403,22 +388,20 @@ XS(XS_Doors_SetOpenType)
|
||||
}
|
||||
|
||||
XS(XS_Doors_SetLockpick); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_SetLockpick)
|
||||
{
|
||||
XS(XS_Doors_SetLockpick) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetLockpick(THIS, type)");
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetLockpick(THIS, uint32 lockpick_type)");
|
||||
{
|
||||
Doors * THIS;
|
||||
uint32 type = (uint32)SvUV(ST(1));
|
||||
Doors *THIS;
|
||||
uint32 type = (uint32) SvUV(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->SetLockpick(type);
|
||||
@@ -427,22 +410,20 @@ XS(XS_Doors_SetLockpick)
|
||||
}
|
||||
|
||||
XS(XS_Doors_SetKeyItem); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_SetKeyItem)
|
||||
{
|
||||
XS(XS_Doors_SetKeyItem) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetKeyItem(THIS, type)");
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetKeyItem(THIS, uint32 key_item_id)");
|
||||
{
|
||||
Doors * THIS;
|
||||
uint32 type = (uint32)SvUV(ST(1));
|
||||
Doors *THIS;
|
||||
uint32 type = (uint32) SvUV(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->SetKeyItem(type);
|
||||
@@ -451,22 +432,20 @@ XS(XS_Doors_SetKeyItem)
|
||||
}
|
||||
|
||||
XS(XS_Doors_SetNoKeyring); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_SetNoKeyring)
|
||||
{
|
||||
XS(XS_Doors_SetNoKeyring) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetNoKeyring(THIS, type)");
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetNoKeyring(THIS, uint8 no_key_ring)");
|
||||
{
|
||||
Doors * THIS;
|
||||
uint8 type = (uint8)SvUV(ST(1));
|
||||
Doors *THIS;
|
||||
uint8 type = (uint8) SvUV(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->SetNoKeyring(type);
|
||||
@@ -475,22 +454,20 @@ XS(XS_Doors_SetNoKeyring)
|
||||
}
|
||||
|
||||
XS(XS_Doors_SetIncline); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_SetIncline)
|
||||
{
|
||||
XS(XS_Doors_SetIncline) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetIncline(THIS, type)");
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetIncline(THIS, uint32 incline)");
|
||||
{
|
||||
Doors * THIS;
|
||||
uint32 type = (uint32)SvUV(ST(1));
|
||||
Doors *THIS;
|
||||
uint32 type = (uint32) SvUV(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->SetIncline(type);
|
||||
@@ -499,22 +476,20 @@ XS(XS_Doors_SetIncline)
|
||||
}
|
||||
|
||||
XS(XS_Doors_SetSize); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_SetSize)
|
||||
{
|
||||
XS(XS_Doors_SetSize) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetSize(THIS, size)");
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetSize(THIS, uint32 size)");
|
||||
{
|
||||
Doors * THIS;
|
||||
uint32 type = (uint32)SvUV(ST(1));
|
||||
Doors *THIS;
|
||||
uint32 type = (uint32) SvUV(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->SetSize(type);
|
||||
@@ -523,24 +498,22 @@ XS(XS_Doors_SetSize)
|
||||
}
|
||||
|
||||
XS(XS_Doors_SetLocation); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_SetLocation)
|
||||
{
|
||||
XS(XS_Doors_SetLocation) {
|
||||
dXSARGS;
|
||||
if (items != 4)
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetLocation(THIS, x, y, z)");
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetLocation(THIS, float x, float y, float z)");
|
||||
{
|
||||
Doors * THIS;
|
||||
float x = (float)SvNV(ST(1));
|
||||
float y = (float)SvNV(ST(2));
|
||||
float z = (float)SvNV(ST(3));
|
||||
Doors *THIS;
|
||||
float x = (float) SvNV(ST(1));
|
||||
float y = (float) SvNV(ST(2));
|
||||
float z = (float) SvNV(ST(3));
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->SetLocation(x, y, z);
|
||||
@@ -549,175 +522,163 @@ XS(XS_Doors_SetLocation)
|
||||
}
|
||||
|
||||
XS(XS_Doors_SetX); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_SetX)
|
||||
{
|
||||
XS(XS_Doors_SetX) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetX(THIS, XPos)");
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetX(THIS, float x)");
|
||||
{
|
||||
Doors * THIS;
|
||||
float x = (float)SvNV(ST(1));
|
||||
Doors *THIS;
|
||||
float x = (float) SvNV(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
auto position = THIS->GetPosition();
|
||||
position.x = x;
|
||||
auto position = THIS->GetPosition();
|
||||
position.x = x;
|
||||
THIS->SetPosition(position);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Doors_SetY); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_SetY)
|
||||
{
|
||||
XS(XS_Doors_SetY) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetY(THIS, YPos)");
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetY(THIS, float y)");
|
||||
{
|
||||
Doors * THIS;
|
||||
float y = (float)SvNV(ST(1));
|
||||
Doors *THIS;
|
||||
float y = (float) SvNV(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
auto position = THIS->GetPosition();
|
||||
position.y = y;
|
||||
auto position = THIS->GetPosition();
|
||||
position.y = y;
|
||||
THIS->SetPosition(position);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Doors_SetZ); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_SetZ)
|
||||
{
|
||||
XS(XS_Doors_SetZ) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetZ(THIS, ZPos)");
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetZ(THIS, float z)");
|
||||
{
|
||||
Doors * THIS;
|
||||
float z = (float)SvNV(ST(1));
|
||||
Doors *THIS;
|
||||
float z = (float) SvNV(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
auto position = THIS->GetPosition();
|
||||
position.z = z;
|
||||
position.z = z;
|
||||
THIS->SetPosition(position);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Doors_SetHeading); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_SetHeading)
|
||||
{
|
||||
XS(XS_Doors_SetHeading) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetHeading(THIS, heading)");
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetHeading(THIS, float heading)");
|
||||
{
|
||||
Doors * THIS;
|
||||
float heading = (float)SvNV(ST(1));
|
||||
Doors *THIS;
|
||||
float heading = (float) SvNV(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
auto position = THIS->GetPosition();
|
||||
position.w = heading;
|
||||
position.w = heading;
|
||||
THIS->SetPosition(position);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Doors_SetModelName); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_SetModelName)
|
||||
{
|
||||
XS(XS_Doors_SetModelName) {
|
||||
dXSARGS;
|
||||
if (items < 1 || items > 2)
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetModelName(THIS, name)");
|
||||
Perl_croak(aTHX_ "Usage: Doors::SetModelName(THIS, string name)");
|
||||
{
|
||||
Doors * THIS;
|
||||
char * name = nullptr;
|
||||
Doors *THIS;
|
||||
char *name = nullptr;
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (items > 1) { name = (char *)SvPV_nolen(ST(1)); }
|
||||
if (items > 1) { name = (char *) SvPV_nolen(ST(1)); }
|
||||
|
||||
THIS->SetDoorName(name);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
XS(XS_Doors_GetModelName); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_GetModelName)
|
||||
{
|
||||
XS(XS_Doors_GetModelName) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Doors::GetModelName(THIS)");
|
||||
{
|
||||
Doors * THIS;
|
||||
Const_char * RETVAL;
|
||||
Doors *THIS;
|
||||
Const_char *RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetDoorName();
|
||||
sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG;
|
||||
sv_setpv(TARG, RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHTARG;
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Doors_CreateDatabaseEntry); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Doors_CreateDatabaseEntry)
|
||||
{
|
||||
XS(XS_Doors_CreateDatabaseEntry) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Doors::InsertDoor(THIS)");
|
||||
{
|
||||
Doors * THIS;
|
||||
Doors *THIS;
|
||||
|
||||
if (sv_derived_from(ST(0), "Doors")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Doors *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Doors");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->CreateDatabaseEntry();
|
||||
@@ -726,52 +687,50 @@ XS(XS_Doors_CreateDatabaseEntry)
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
XS(boot_Doors); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(boot_Doors)
|
||||
{
|
||||
XS(boot_Doors) {
|
||||
dXSARGS;
|
||||
char file[256];
|
||||
strncpy(file, __FILE__, 256);
|
||||
file[255] = 0;
|
||||
|
||||
if(items != 1)
|
||||
if (items != 1)
|
||||
fprintf(stderr, "boot_quest does not take any arguments.");
|
||||
char buf[128];
|
||||
|
||||
//add the strcpy stuff to get rid of const warnings....
|
||||
|
||||
XS_VERSION_BOOTCHECK ;
|
||||
newXSproto(strcpy(buf, "GetID"),XS_Doors_GetID, file, "$");
|
||||
newXSproto(strcpy(buf, "SetModelName"),XS_Doors_SetModelName, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetModelName"),XS_Doors_GetModelName, file, "$");
|
||||
newXSproto(strcpy(buf, "GetX"),XS_Doors_GetX, file, "$");
|
||||
newXSproto(strcpy(buf, "GetY"),XS_Doors_GetY, file, "$");
|
||||
newXSproto(strcpy(buf, "GetZ"),XS_Doors_GetZ, file, "$");
|
||||
newXSproto(strcpy(buf, "GetHeading"),XS_Doors_GetHeading, file, "$");
|
||||
newXSproto(strcpy(buf, "SetX"),XS_Doors_SetX, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetY"),XS_Doors_SetY, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetZ"),XS_Doors_SetZ, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetHeading"),XS_Doors_SetHeading, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetLocation"),XS_Doors_SetLocation, file, "$$$$");
|
||||
newXSproto(strcpy(buf, "GetDoorDBID"),XS_Doors_GetDoorDBID, file, "$");
|
||||
newXSproto(strcpy(buf, "GetDoorID"),XS_Doors_GetDoorID, file, "$");
|
||||
newXSproto(strcpy(buf, "SetSize"),XS_Doors_SetSize, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetSize"),XS_Doors_GetSize, file, "$");
|
||||
newXSproto(strcpy(buf, "SetIncline"),XS_Doors_SetIncline, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetIncline"),XS_Doors_GetIncline, file, "$");
|
||||
newXSproto(strcpy(buf, "SetOpenType"),XS_Doors_SetOpenType, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetOpenType"),XS_Doors_GetOpenType, file, "$");
|
||||
newXSproto(strcpy(buf, "SetLockPick"),XS_Doors_SetLockpick, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetLockPick"),XS_Doors_GetLockpick, file, "$");
|
||||
newXSproto(strcpy(buf, "SetKeyItem"),XS_Doors_SetKeyItem, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetKeyItem"),XS_Doors_GetKeyItem, file, "$");
|
||||
newXSproto(strcpy(buf, "SetNoKeyring"),XS_Doors_SetNoKeyring, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetNoKeyring"),XS_Doors_GetNoKeyring, file, "$");
|
||||
newXSproto(strcpy(buf, "CreateDatabaseEntry"),XS_Doors_CreateDatabaseEntry, file, "$");
|
||||
XS_VERSION_BOOTCHECK;
|
||||
newXSproto(strcpy(buf, "GetID"), XS_Doors_GetID, file, "$");
|
||||
newXSproto(strcpy(buf, "SetModelName"), XS_Doors_SetModelName, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetModelName"), XS_Doors_GetModelName, file, "$");
|
||||
newXSproto(strcpy(buf, "GetX"), XS_Doors_GetX, file, "$");
|
||||
newXSproto(strcpy(buf, "GetY"), XS_Doors_GetY, file, "$");
|
||||
newXSproto(strcpy(buf, "GetZ"), XS_Doors_GetZ, file, "$");
|
||||
newXSproto(strcpy(buf, "GetHeading"), XS_Doors_GetHeading, file, "$");
|
||||
newXSproto(strcpy(buf, "SetX"), XS_Doors_SetX, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetY"), XS_Doors_SetY, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetZ"), XS_Doors_SetZ, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetHeading"), XS_Doors_SetHeading, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetLocation"), XS_Doors_SetLocation, file, "$$$$");
|
||||
newXSproto(strcpy(buf, "GetDoorDBID"), XS_Doors_GetDoorDBID, file, "$");
|
||||
newXSproto(strcpy(buf, "GetDoorID"), XS_Doors_GetDoorID, file, "$");
|
||||
newXSproto(strcpy(buf, "SetSize"), XS_Doors_SetSize, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetSize"), XS_Doors_GetSize, file, "$");
|
||||
newXSproto(strcpy(buf, "SetIncline"), XS_Doors_SetIncline, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetIncline"), XS_Doors_GetIncline, file, "$");
|
||||
newXSproto(strcpy(buf, "SetOpenType"), XS_Doors_SetOpenType, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetOpenType"), XS_Doors_GetOpenType, file, "$");
|
||||
newXSproto(strcpy(buf, "SetLockPick"), XS_Doors_SetLockpick, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetLockPick"), XS_Doors_GetLockpick, file, "$");
|
||||
newXSproto(strcpy(buf, "SetKeyItem"), XS_Doors_SetKeyItem, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetKeyItem"), XS_Doors_GetKeyItem, file, "$");
|
||||
newXSproto(strcpy(buf, "SetNoKeyring"), XS_Doors_SetNoKeyring, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetNoKeyring"), XS_Doors_GetNoKeyring, file, "$");
|
||||
newXSproto(strcpy(buf, "CreateDatabaseEntry"), XS_Doors_CreateDatabaseEntry, file, "$");
|
||||
XSRETURN_YES;
|
||||
}
|
||||
#endif //EMBPERL_XS_CLASSES
|
||||
|
||||
+803
-958
File diff suppressed because it is too large
Load Diff
+238
-277
@@ -26,7 +26,9 @@
|
||||
*/
|
||||
|
||||
#include "../common/features.h"
|
||||
|
||||
#ifdef EMBPERL_XS_CLASSES
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "embperl.h"
|
||||
|
||||
@@ -42,21 +44,19 @@
|
||||
|
||||
|
||||
XS(XS_Group_DisbandGroup); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_DisbandGroup)
|
||||
{
|
||||
XS(XS_Group_DisbandGroup) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Group::DisbandGroup(THIS)");
|
||||
{
|
||||
Group * THIS;
|
||||
Group *THIS;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->DisbandGroup();
|
||||
@@ -65,32 +65,29 @@ XS(XS_Group_DisbandGroup)
|
||||
}
|
||||
|
||||
XS(XS_Group_IsGroupMember); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_IsGroupMember)
|
||||
{
|
||||
XS(XS_Group_IsGroupMember) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Group::IsGroupMember(THIS, client)");
|
||||
{
|
||||
Group * THIS;
|
||||
bool RETVAL;
|
||||
Mob* client;
|
||||
Group *THIS;
|
||||
bool RETVAL;
|
||||
Mob *client;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (sv_derived_from(ST(1), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(1)));
|
||||
client = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(1)));
|
||||
client = INT2PTR(Mob *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "client is not of type Mob");
|
||||
if(client == nullptr)
|
||||
if (client == nullptr)
|
||||
Perl_croak(aTHX_ "client is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->IsGroupMember(client);
|
||||
@@ -101,32 +98,29 @@ XS(XS_Group_IsGroupMember)
|
||||
}
|
||||
|
||||
XS(XS_Group_CastGroupSpell); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_CastGroupSpell)
|
||||
{
|
||||
XS(XS_Group_CastGroupSpell) {
|
||||
dXSARGS;
|
||||
if (items != 3)
|
||||
Perl_croak(aTHX_ "Usage: Group::CastGroupSpell(THIS, caster, spellid)");
|
||||
Perl_croak(aTHX_ "Usage: Group::CastGroupSpell(THIS, Mob* caster, uint16 spell_id)");
|
||||
{
|
||||
Group * THIS;
|
||||
Mob* caster;
|
||||
uint16 spellid = (uint16)SvUV(ST(2));
|
||||
Group *THIS;
|
||||
Mob *caster;
|
||||
uint16 spellid = (uint16) SvUV(ST(2));
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (sv_derived_from(ST(1), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(1)));
|
||||
caster = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(1)));
|
||||
caster = INT2PTR(Mob *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "caster is not of type Mob");
|
||||
if(caster == nullptr)
|
||||
if (caster == nullptr)
|
||||
Perl_croak(aTHX_ "caster is nullptr, avoiding crash.");
|
||||
|
||||
THIS->CastGroupSpell(caster, spellid);
|
||||
@@ -135,32 +129,29 @@ XS(XS_Group_CastGroupSpell)
|
||||
}
|
||||
|
||||
XS(XS_Group_SplitExp); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_SplitExp)
|
||||
{
|
||||
XS(XS_Group_SplitExp) {
|
||||
dXSARGS;
|
||||
if (items != 3)
|
||||
Perl_croak(aTHX_ "Usage: Group::SplitExp(THIS, exp, other)");
|
||||
Perl_croak(aTHX_ "Usage: Group::SplitExp(THIS, uint32 exp, Mob* other)");
|
||||
{
|
||||
Group * THIS;
|
||||
uint32 exp = (uint32)SvUV(ST(1));
|
||||
Mob* other;
|
||||
Group *THIS;
|
||||
uint32 exp = (uint32) SvUV(ST(1));
|
||||
Mob *other;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (sv_derived_from(ST(2), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(2)));
|
||||
other = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(2)));
|
||||
other = INT2PTR(Mob *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "other is not of type Mob");
|
||||
if(other == nullptr)
|
||||
if (other == nullptr)
|
||||
Perl_croak(aTHX_ "other is nullptr, avoiding crash.");
|
||||
|
||||
THIS->SplitExp(exp, other);
|
||||
@@ -169,106 +160,98 @@ XS(XS_Group_SplitExp)
|
||||
}
|
||||
|
||||
XS(XS_Group_GroupMessage); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_GroupMessage)
|
||||
{
|
||||
XS(XS_Group_GroupMessage) {
|
||||
dXSARGS;
|
||||
if ((items != 3) && (items != 4)) // the 3 item version is kept for backwards compatability
|
||||
Perl_croak(aTHX_ "Usage: Group::GroupMessage(THIS, sender, language, message)");
|
||||
if ((items != 3) && (items != 4)) // the 3 item version is kept for backwards compatability
|
||||
Perl_croak(aTHX_ "Usage: Group::GroupMessage(THIS, Mob* sender, uint8 language, string message)");
|
||||
{
|
||||
Group * THIS;
|
||||
Mob* sender;
|
||||
uint8 language;
|
||||
char* message;
|
||||
Group *THIS;
|
||||
Mob *sender;
|
||||
uint8 language;
|
||||
char *message;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (sv_derived_from(ST(1), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(1)));
|
||||
sender = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(1)));
|
||||
sender = INT2PTR(Mob *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "sender is not of type Mob");
|
||||
if(sender == nullptr)
|
||||
if (sender == nullptr)
|
||||
Perl_croak(aTHX_ "sender is nullptr, avoiding crash.");
|
||||
|
||||
if (items == 4) {
|
||||
language = (uint8)SvUV(ST(2));
|
||||
language = (uint8) SvUV(ST(2));
|
||||
if ((language >= MAX_PP_LANGUAGE) || (language < 0))
|
||||
language = 0;
|
||||
message = (char *)SvPV_nolen(ST(3));
|
||||
message = (char *) SvPV_nolen(ST(3));
|
||||
THIS->GroupMessage(sender, language, 100, message);
|
||||
}
|
||||
else { // if no language is specificed, send it in common
|
||||
message = (char *)SvPV_nolen(ST(2));
|
||||
THIS->GroupMessage(sender,0, 100, message);
|
||||
} else { // if no language is specificed, send it in common
|
||||
message = (char *) SvPV_nolen(ST(2));
|
||||
THIS->GroupMessage(sender, 0, 100, message);
|
||||
}
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Group_GetTotalGroupDamage); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_GetTotalGroupDamage)
|
||||
{
|
||||
XS(XS_Group_GetTotalGroupDamage) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Group::GetTotalGroupDamage(THIS, other)");
|
||||
Perl_croak(aTHX_ "Usage: Group::GetTotalGroupDamage(THIS, Mob* other)");
|
||||
{
|
||||
Group * THIS;
|
||||
uint32 RETVAL;
|
||||
Group *THIS;
|
||||
uint32 RETVAL;
|
||||
dXSTARG;
|
||||
Mob* other;
|
||||
Mob *other;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (sv_derived_from(ST(1), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(1)));
|
||||
other = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(1)));
|
||||
other = INT2PTR(Mob *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "other is not of type Mob");
|
||||
if(other == nullptr)
|
||||
if (other == nullptr)
|
||||
Perl_croak(aTHX_ "other is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetTotalGroupDamage(other);
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Group_SplitMoney); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_SplitMoney)
|
||||
{
|
||||
XS(XS_Group_SplitMoney) {
|
||||
dXSARGS;
|
||||
if (items != 5)
|
||||
Perl_croak(aTHX_ "Usage: Group::SplitMoney(THIS, copper, silver, gold, platinum)");
|
||||
Perl_croak(aTHX_ "Usage: Group::SplitMoney(THIS, uint32 copper, uint32 silver, uint32 gold, uint32 platinum)");
|
||||
{
|
||||
Group * THIS;
|
||||
uint32 copper = (uint32)SvUV(ST(1));
|
||||
uint32 silver = (uint32)SvUV(ST(2));
|
||||
uint32 gold = (uint32)SvUV(ST(3));
|
||||
uint32 platinum = (uint32)SvUV(ST(4));
|
||||
Group *THIS;
|
||||
uint32 copper = (uint32) SvUV(ST(1));
|
||||
uint32 silver = (uint32) SvUV(ST(2));
|
||||
uint32 gold = (uint32) SvUV(ST(3));
|
||||
uint32 platinum = (uint32) SvUV(ST(4));
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->SplitMoney(copper, silver, gold, platinum);
|
||||
@@ -277,31 +260,28 @@ XS(XS_Group_SplitMoney)
|
||||
}
|
||||
|
||||
XS(XS_Group_SetLeader); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_SetLeader)
|
||||
{
|
||||
XS(XS_Group_SetLeader) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Group::SetLeader(THIS, newleader)");
|
||||
Perl_croak(aTHX_ "Usage: Group::SetLeader(THIS, Mob* new_leader)");
|
||||
{
|
||||
Group * THIS;
|
||||
Mob* newleader;
|
||||
Group *THIS;
|
||||
Mob *newleader;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (sv_derived_from(ST(1), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(1)));
|
||||
newleader = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(1)));
|
||||
newleader = INT2PTR(Mob *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "newleader is not of type Mob");
|
||||
if(newleader == nullptr)
|
||||
if (newleader == nullptr)
|
||||
Perl_croak(aTHX_ "newleader is nullptr, avoiding crash.");
|
||||
|
||||
THIS->SetLeader(newleader);
|
||||
@@ -310,83 +290,78 @@ XS(XS_Group_SetLeader)
|
||||
}
|
||||
|
||||
XS(XS_Group_GetLeader); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_GetLeader)
|
||||
{
|
||||
XS(XS_Group_GetLeader) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Group::GetLeader(THIS)");
|
||||
{
|
||||
Group * THIS;
|
||||
Mob * RETVAL;
|
||||
Group *THIS;
|
||||
Mob *RETVAL;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetLeader();
|
||||
ST(0) = sv_newmortal();
|
||||
sv_setref_pv(ST(0), "Mob", (void*)RETVAL);
|
||||
sv_setref_pv(ST(0), "Mob", (void *) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Group_GetLeaderName); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_GetLeaderName)
|
||||
{
|
||||
XS(XS_Group_GetLeaderName) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Group::GetLeaderName(THIS)");
|
||||
{
|
||||
Group * THIS;
|
||||
const char * RETVAL;
|
||||
Group *THIS;
|
||||
const char *RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetLeaderName();
|
||||
sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG;
|
||||
sv_setpv(TARG, RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHTARG;
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Group_SendHPPacketsTo); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_SendHPPacketsTo)
|
||||
{
|
||||
XS(XS_Group_SendHPPacketsTo) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Group::SendHPPacketsTo(THIS, newmember)");
|
||||
Perl_croak(aTHX_ "Usage: Group::SendHPPacketsTo(THIS, Mob* new_member)");
|
||||
{
|
||||
Group * THIS;
|
||||
Mob* newmember;
|
||||
Group *THIS;
|
||||
Mob *newmember;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (sv_derived_from(ST(1), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(1)));
|
||||
newmember = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(1)));
|
||||
newmember = INT2PTR(Mob *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "newmember is not of type Mob");
|
||||
if(newmember == nullptr)
|
||||
if (newmember == nullptr)
|
||||
Perl_croak(aTHX_ "newmember is nullptr, avoiding crash.");
|
||||
|
||||
THIS->SendHPManaEndPacketsTo(newmember);
|
||||
@@ -395,31 +370,28 @@ XS(XS_Group_SendHPPacketsTo)
|
||||
}
|
||||
|
||||
XS(XS_Group_SendHPPacketsFrom); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_SendHPPacketsFrom)
|
||||
{
|
||||
XS(XS_Group_SendHPPacketsFrom) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Group::SendHPPacketsFrom(THIS, newmember)");
|
||||
Perl_croak(aTHX_ "Usage: Group::SendHPPacketsFrom(THIS, Mob* new_member)");
|
||||
{
|
||||
Group * THIS;
|
||||
Mob* newmember;
|
||||
Group *THIS;
|
||||
Mob *newmember;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (sv_derived_from(ST(1), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(1)));
|
||||
newmember = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(1)));
|
||||
newmember = INT2PTR(Mob *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "newmember is not of type Mob");
|
||||
if(newmember == nullptr)
|
||||
if (newmember == nullptr)
|
||||
Perl_croak(aTHX_ "newmember is nullptr, avoiding crash.");
|
||||
|
||||
THIS->SendHPPacketsFrom(newmember);
|
||||
@@ -428,32 +400,29 @@ XS(XS_Group_SendHPPacketsFrom)
|
||||
}
|
||||
|
||||
XS(XS_Group_IsLeader); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_IsLeader)
|
||||
{
|
||||
XS(XS_Group_IsLeader) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Group::IsLeader(THIS, leadertest)");
|
||||
Perl_croak(aTHX_ "Usage: Group::IsLeader(THIS, Mob* target)");
|
||||
{
|
||||
Group * THIS;
|
||||
bool RETVAL;
|
||||
Mob* leadertest;
|
||||
Group *THIS;
|
||||
bool RETVAL;
|
||||
Mob *leadertest;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (sv_derived_from(ST(1), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(1)));
|
||||
leadertest = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(1)));
|
||||
leadertest = INT2PTR(Mob *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "leadertest is not of type Mob");
|
||||
if(leadertest == nullptr)
|
||||
if (leadertest == nullptr)
|
||||
Perl_croak(aTHX_ "leadertest is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->IsLeader(leadertest);
|
||||
@@ -464,88 +433,84 @@ XS(XS_Group_IsLeader)
|
||||
}
|
||||
|
||||
XS(XS_Group_GroupCount); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_GroupCount)
|
||||
{
|
||||
XS(XS_Group_GroupCount) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Group::GroupCount(THIS)");
|
||||
{
|
||||
Group * THIS;
|
||||
uint8 RETVAL;
|
||||
Group *THIS;
|
||||
uint8 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GroupCount();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Group_GetHighestLevel); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_GetHighestLevel)
|
||||
{
|
||||
XS(XS_Group_GetHighestLevel) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Group::GetHighestLevel(THIS)");
|
||||
{
|
||||
Group * THIS;
|
||||
uint32 RETVAL;
|
||||
Group *THIS;
|
||||
uint32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetHighestLevel();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Group_TeleportGroup); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_TeleportGroup)
|
||||
{
|
||||
XS(XS_Group_TeleportGroup) {
|
||||
dXSARGS;
|
||||
if (items != 7)
|
||||
Perl_croak(aTHX_ "Usage: Group::TeleportGroup(THIS, sender, zoneID, x, y, z, heading)");
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Group::TeleportGroup(THIS, Mob* sender, uint32 zone_id, float x, float y, float z, float heading)");
|
||||
{
|
||||
Group * THIS;
|
||||
Mob* sender;
|
||||
uint32 zoneID = (uint32)SvUV(ST(2));
|
||||
float x = (float)SvNV(ST(3));
|
||||
float y = (float)SvNV(ST(4));
|
||||
float z = (float)SvNV(ST(5));
|
||||
float heading = (float)SvNV(ST(6));
|
||||
Group *THIS;
|
||||
Mob *sender;
|
||||
uint32 zoneID = (uint32) SvUV(ST(2));
|
||||
float x = (float) SvNV(ST(3));
|
||||
float y = (float) SvNV(ST(4));
|
||||
float z = (float) SvNV(ST(5));
|
||||
float heading = (float) SvNV(ST(6));
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (sv_derived_from(ST(1), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(1)));
|
||||
sender = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(1)));
|
||||
sender = INT2PTR(Mob *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "sender is not of type Mob");
|
||||
if(sender == nullptr)
|
||||
if (sender == nullptr)
|
||||
Perl_croak(aTHX_ "sender is nullptr, avoiding crash.");
|
||||
|
||||
THIS->TeleportGroup(sender, zoneID, 0, x, y, z, heading);
|
||||
@@ -554,63 +519,60 @@ XS(XS_Group_TeleportGroup)
|
||||
}
|
||||
|
||||
XS(XS_Group_GetID); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_GetID)
|
||||
{
|
||||
XS(XS_Group_GetID) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Group::GetID(THIS)");
|
||||
{
|
||||
Group * THIS;
|
||||
uint32 RETVAL;
|
||||
Group *THIS;
|
||||
uint32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetID();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Group_GetMember);
|
||||
XS(XS_Group_GetMember)
|
||||
{
|
||||
XS(XS_Group_GetMember) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Group::GetMember(THIS, index)");
|
||||
Perl_croak(aTHX_ "Usage: Group::GetMember(THIS, int group_index)");
|
||||
{
|
||||
Group * THIS;
|
||||
Mob* member;
|
||||
Client* RETVAL = nullptr;
|
||||
Group *THIS;
|
||||
Mob *member;
|
||||
Client *RETVAL = nullptr;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(Group *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type Group");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
int index = (int)SvUV(ST(1));
|
||||
int index = (int) SvUV(ST(1));
|
||||
if (index < 0 || index > 5)
|
||||
RETVAL = nullptr;
|
||||
else {
|
||||
member = THIS->members[index];
|
||||
member = THIS->members[index];
|
||||
if (member != nullptr)
|
||||
RETVAL = member->CastToClient();
|
||||
}
|
||||
|
||||
ST(0) = sv_newmortal();
|
||||
sv_setref_pv(ST(0), "Client", (void*)RETVAL);
|
||||
ST(0) = sv_newmortal();
|
||||
sv_setref_pv(ST(0), "Client", (void *) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
@@ -619,39 +581,38 @@ XS(XS_Group_GetMember)
|
||||
extern "C"
|
||||
#endif
|
||||
XS(boot_Group); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(boot_Group)
|
||||
{
|
||||
XS(boot_Group) {
|
||||
dXSARGS;
|
||||
char file[256];
|
||||
strncpy(file, __FILE__, 256);
|
||||
file[255] = 0;
|
||||
|
||||
if(items != 1)
|
||||
if (items != 1)
|
||||
fprintf(stderr, "boot_quest does not take any arguments.");
|
||||
char buf[128];
|
||||
|
||||
//add the strcpy stuff to get rid of const warnings....
|
||||
|
||||
XS_VERSION_BOOTCHECK ;
|
||||
XS_VERSION_BOOTCHECK;
|
||||
|
||||
newXSproto(strcpy(buf, "DisbandGroup"), XS_Group_DisbandGroup, file, "$");
|
||||
newXSproto(strcpy(buf, "IsGroupMember"), XS_Group_IsGroupMember, file, "$$");
|
||||
newXSproto(strcpy(buf, "CastGroupSpell"), XS_Group_CastGroupSpell, file, "$$$");
|
||||
newXSproto(strcpy(buf, "SplitExp"), XS_Group_SplitExp, file, "$$$");
|
||||
newXSproto(strcpy(buf, "GroupMessage"), XS_Group_GroupMessage, file, "$$$");
|
||||
newXSproto(strcpy(buf, "GetTotalGroupDamage"), XS_Group_GetTotalGroupDamage, file, "$$");
|
||||
newXSproto(strcpy(buf, "SplitMoney"), XS_Group_SplitMoney, file, "$$$$$");
|
||||
newXSproto(strcpy(buf, "SetLeader"), XS_Group_SetLeader, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetLeader"), XS_Group_GetLeader, file, "$");
|
||||
newXSproto(strcpy(buf, "GetLeaderName"), XS_Group_GetLeaderName, file, "$");
|
||||
newXSproto(strcpy(buf, "SendHPPacketsTo"), XS_Group_SendHPPacketsTo, file, "$$");
|
||||
newXSproto(strcpy(buf, "SendHPPacketsFrom"), XS_Group_SendHPPacketsFrom, file, "$$");
|
||||
newXSproto(strcpy(buf, "IsLeader"), XS_Group_IsLeader, file, "$$");
|
||||
newXSproto(strcpy(buf, "GroupCount"), XS_Group_GroupCount, file, "$");
|
||||
newXSproto(strcpy(buf, "GetHighestLevel"), XS_Group_GetHighestLevel, file, "$");
|
||||
newXSproto(strcpy(buf, "TeleportGroup"), XS_Group_TeleportGroup, file, "$$$$$$$");
|
||||
newXSproto(strcpy(buf, "GetID"), XS_Group_GetID, file, "$");
|
||||
newXSproto(strcpy(buf, "GetMember"), XS_Group_GetMember, file, "$$");
|
||||
newXSproto(strcpy(buf, "DisbandGroup"), XS_Group_DisbandGroup, file, "$");
|
||||
newXSproto(strcpy(buf, "IsGroupMember"), XS_Group_IsGroupMember, file, "$$");
|
||||
newXSproto(strcpy(buf, "CastGroupSpell"), XS_Group_CastGroupSpell, file, "$$$");
|
||||
newXSproto(strcpy(buf, "SplitExp"), XS_Group_SplitExp, file, "$$$");
|
||||
newXSproto(strcpy(buf, "GroupMessage"), XS_Group_GroupMessage, file, "$$$");
|
||||
newXSproto(strcpy(buf, "GetTotalGroupDamage"), XS_Group_GetTotalGroupDamage, file, "$$");
|
||||
newXSproto(strcpy(buf, "SplitMoney"), XS_Group_SplitMoney, file, "$$$$$");
|
||||
newXSproto(strcpy(buf, "SetLeader"), XS_Group_SetLeader, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetLeader"), XS_Group_GetLeader, file, "$");
|
||||
newXSproto(strcpy(buf, "GetLeaderName"), XS_Group_GetLeaderName, file, "$");
|
||||
newXSproto(strcpy(buf, "SendHPPacketsTo"), XS_Group_SendHPPacketsTo, file, "$$");
|
||||
newXSproto(strcpy(buf, "SendHPPacketsFrom"), XS_Group_SendHPPacketsFrom, file, "$$");
|
||||
newXSproto(strcpy(buf, "IsLeader"), XS_Group_IsLeader, file, "$$");
|
||||
newXSproto(strcpy(buf, "GroupCount"), XS_Group_GroupCount, file, "$");
|
||||
newXSproto(strcpy(buf, "GetHighestLevel"), XS_Group_GetHighestLevel, file, "$");
|
||||
newXSproto(strcpy(buf, "TeleportGroup"), XS_Group_TeleportGroup, file, "$$$$$$$");
|
||||
newXSproto(strcpy(buf, "GetID"), XS_Group_GetID, file, "$");
|
||||
newXSproto(strcpy(buf, "GetMember"), XS_Group_GetMember, file, "$$");
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
|
||||
+33
-36
@@ -18,7 +18,9 @@
|
||||
|
||||
#include "../common/features.h"
|
||||
#include "client.h"
|
||||
|
||||
#ifdef EMBPERL_XS_CLASSES
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "embperl.h"
|
||||
|
||||
@@ -29,84 +31,80 @@
|
||||
#include "../common/linked_list.h"
|
||||
#include "hate_list.h"
|
||||
|
||||
#ifdef THIS /* this macro seems to leak out on some systems */
|
||||
#ifdef THIS /* this macro seems to leak out on some systems */
|
||||
#undef THIS
|
||||
#endif
|
||||
|
||||
XS(XS_HateEntry_GetEnt); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_HateEntry_GetEnt)
|
||||
{
|
||||
XS(XS_HateEntry_GetEnt) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: HateEntry::GetData(THIS)");
|
||||
{
|
||||
struct_HateList * THIS;
|
||||
Mob * RETVAL;
|
||||
struct_HateList *THIS;
|
||||
Mob *RETVAL;
|
||||
|
||||
if (sv_derived_from(ST(0), "HateEntry")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(struct_HateList *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(struct_HateList *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type tHateEntry");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->entity_on_hatelist;
|
||||
ST(0) = sv_newmortal();
|
||||
sv_setref_pv(ST(0), "Mob", (void*)RETVAL);
|
||||
sv_setref_pv(ST(0), "Mob", (void *) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_HateEntry_GetHate); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_HateEntry_GetHate)
|
||||
{
|
||||
XS(XS_HateEntry_GetHate) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: HateEntry::GetHate(THIS)");
|
||||
{
|
||||
struct_HateList * THIS;
|
||||
struct_HateList *THIS;
|
||||
int32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "HateEntry")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(struct_HateList *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(struct_HateList *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type tHateEntry");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->stored_hate_amount;
|
||||
XSprePUSH; PUSHi((IV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHi((IV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_HateEntry_GetDamage); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_HateEntry_GetDamage)
|
||||
{
|
||||
XS(XS_HateEntry_GetDamage) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: HateEntry::GetDamage(THIS)");
|
||||
{
|
||||
struct_HateList * THIS;
|
||||
struct_HateList *THIS;
|
||||
int32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "HateEntry")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(struct_HateList *,tmp);
|
||||
}
|
||||
else
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
THIS = INT2PTR(struct_HateList *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "THIS is not of type tHateEntry");
|
||||
if(THIS == nullptr)
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->hatelist_damage;
|
||||
XSprePUSH; PUSHi((IV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHi((IV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
@@ -116,24 +114,23 @@ extern "C"
|
||||
#endif
|
||||
|
||||
XS(boot_HateEntry);
|
||||
XS(boot_HateEntry)
|
||||
{
|
||||
XS(boot_HateEntry) {
|
||||
dXSARGS;
|
||||
char file[256];
|
||||
strncpy(file, __FILE__, 256);
|
||||
file[255] = 0;
|
||||
|
||||
if(items != 1)
|
||||
if (items != 1)
|
||||
fprintf(stderr, "boot_quest does not take any arguments.");
|
||||
char buf[128];
|
||||
|
||||
//add the strcpy stuff to get rid of const warnings....
|
||||
|
||||
XS_VERSION_BOOTCHECK ;
|
||||
XS_VERSION_BOOTCHECK;
|
||||
|
||||
newXSproto(strcpy(buf, "GetEnt"), XS_HateEntry_GetEnt, file, "$");
|
||||
newXSproto(strcpy(buf, "GetDamage"), XS_HateEntry_GetDamage, file, "$");
|
||||
newXSproto(strcpy(buf, "GetHate"), XS_HateEntry_GetHate, file, "$");
|
||||
newXSproto(strcpy(buf, "GetEnt"), XS_HateEntry_GetEnt, file, "$");
|
||||
newXSproto(strcpy(buf, "GetDamage"), XS_HateEntry_GetDamage, file, "$");
|
||||
newXSproto(strcpy(buf, "GetHate"), XS_HateEntry_GetHate, file, "$");
|
||||
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
+3565
-4034
File diff suppressed because it is too large
Load Diff
+959
-1159
File diff suppressed because it is too large
Load Diff
+394
-460
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user