mirror of
https://github.com/EQEmu/Server.git
synced 2026-09-03 17:46:36 +00:00
merge from master
This commit is contained in:
+22
-19
@@ -1,7 +1,7 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
|
||||
SET(zone_sources
|
||||
AA.cpp
|
||||
aa.cpp
|
||||
aggro.cpp
|
||||
attack.cpp
|
||||
beacon.cpp
|
||||
@@ -16,7 +16,7 @@ SET(zone_sources
|
||||
command.cpp
|
||||
corpse.cpp
|
||||
doors.cpp
|
||||
effects.cpp
|
||||
effects.cpp
|
||||
embparser.cpp
|
||||
embparser_api.cpp
|
||||
embperl.cpp
|
||||
@@ -69,12 +69,12 @@ SET(zone_sources
|
||||
map.cpp
|
||||
merc.cpp
|
||||
mob.cpp
|
||||
MobAI.cpp
|
||||
mob_ai.cpp
|
||||
mod_functions.cpp
|
||||
net.cpp
|
||||
npc.cpp
|
||||
NpcAI.cpp
|
||||
Object.cpp
|
||||
npc_ai.cpp
|
||||
object.cpp
|
||||
oriented_bounding_box.cpp
|
||||
pathing.cpp
|
||||
perl_client.cpp
|
||||
@@ -86,17 +86,18 @@ SET(zone_sources
|
||||
perl_npc.cpp
|
||||
perl_object.cpp
|
||||
perl_perlpacket.cpp
|
||||
perl_PlayerCorpse.cpp
|
||||
perl_player_corpse.cpp
|
||||
perl_questitem.cpp
|
||||
perl_raids.cpp
|
||||
perlpacket.cpp
|
||||
petitions.cpp
|
||||
pets.cpp
|
||||
QGlobals.cpp
|
||||
qglobals.cpp
|
||||
queryserv.cpp
|
||||
questmgr.cpp
|
||||
QuestParserCollection.cpp
|
||||
quest_parser_collection.cpp
|
||||
raids.cpp
|
||||
RaycastMesh.cpp
|
||||
raycast_mesh.cpp
|
||||
spawn2.cpp
|
||||
spawn2.h
|
||||
spawngroup.cpp
|
||||
@@ -116,18 +117,18 @@ SET(zone_sources
|
||||
worldserver.cpp
|
||||
zone.cpp
|
||||
zone_logsys.cpp
|
||||
ZoneConfig.cpp
|
||||
zone_config.cpp
|
||||
zonedb.cpp
|
||||
zonedbasync.cpp
|
||||
zoning.cpp
|
||||
)
|
||||
|
||||
SET(zone_headers
|
||||
AA.h
|
||||
aa.h
|
||||
basic_functions.h
|
||||
beacon.h
|
||||
bot.h
|
||||
botStructs.h
|
||||
bot_structs.h
|
||||
client.h
|
||||
client_logs.h
|
||||
client_packet.h
|
||||
@@ -175,25 +176,27 @@ SET(zone_headers
|
||||
mob.h
|
||||
net.h
|
||||
npc.h
|
||||
NpcAI.h
|
||||
npc_ai.h
|
||||
object.h
|
||||
oriented_bounding_box.h
|
||||
pathing.h
|
||||
perlpacket.h
|
||||
petitions.h
|
||||
pets.h
|
||||
QGlobals.h
|
||||
QuestInterface.h
|
||||
qglobals.h
|
||||
quest_interface.h
|
||||
queryserv.h
|
||||
quest_interface.h
|
||||
questmgr.h
|
||||
QuestParserCollection.h
|
||||
quest_parser_collection.h
|
||||
raid.h
|
||||
raids.h
|
||||
RaycastMesh.h
|
||||
raycast_mesh.h
|
||||
skills.h
|
||||
spawn2.cpp
|
||||
spawn2.h
|
||||
spawngroup.h
|
||||
StringIDs.h
|
||||
string_ids.h
|
||||
tasks.h
|
||||
titles.h
|
||||
trap.h
|
||||
@@ -202,7 +205,7 @@ SET(zone_headers
|
||||
water_map_v2.h
|
||||
worldserver.h
|
||||
zone.h
|
||||
ZoneConfig.h
|
||||
zone_config.h
|
||||
zonedb.h
|
||||
zonedbasync.h
|
||||
zonedump.h
|
||||
|
||||
+243
-276
@@ -19,7 +19,7 @@ Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net)
|
||||
// Test 1
|
||||
|
||||
#include "../common/debug.h"
|
||||
#include "AA.h"
|
||||
#include "aa.h"
|
||||
#include "mob.h"
|
||||
#include "client.h"
|
||||
#include "groups.h"
|
||||
@@ -34,10 +34,13 @@ Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net)
|
||||
#include "../common/classes.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/logsys.h"
|
||||
#include "zonedb.h"
|
||||
#include "StringIDs.h"
|
||||
#include "string_ids.h"
|
||||
#include "queryserv.h"
|
||||
|
||||
extern QueryServ* QServ;
|
||||
|
||||
//static data arrays, really not big enough to warrant shared mem.
|
||||
AA_DBAction AA_Actions[aaHighestID][MAX_AA_ACTION_RANKS]; //[aaid][rank]
|
||||
@@ -458,7 +461,7 @@ void Client::HandleAAAction(aaID activate) {
|
||||
Escape();
|
||||
break;
|
||||
|
||||
// Don't think this code is used any longer for Bestial Alignment as the AA has a spell_id and no nonspell_action.
|
||||
// Don't think this code is used any longer for Bestial Alignment as the aa.has a spell_id and no nonspell_action.
|
||||
case aaActionBeastialAlignment:
|
||||
switch(GetBaseRace()) {
|
||||
case BARBARIAN:
|
||||
@@ -1039,16 +1042,16 @@ void Client::BuyAA(AA_Action* action)
|
||||
else
|
||||
real_cost = aa2->cost + (aa2->cost_inc * cur_level);
|
||||
|
||||
if(m_pp.aapoints >= real_cost && cur_level < aa2->max_level) {
|
||||
SetAA(aa2->id, cur_level+1);
|
||||
if (m_pp.aapoints >= real_cost && cur_level < aa2->max_level) {
|
||||
SetAA(aa2->id, cur_level + 1);
|
||||
|
||||
mlog(AA__MESSAGE, "Set AA %d to level %d", aa2->id, cur_level+1);
|
||||
mlog(AA__MESSAGE, "Set AA %d to level %d", aa2->id, cur_level + 1);
|
||||
|
||||
m_pp.aapoints -= real_cost;
|
||||
|
||||
Save();
|
||||
if ((RuleB(AA, Stacking) && (GetClientVersionBit() >= 4) && (aa2->hotkey_sid == 4294967295u))
|
||||
&& ((aa2->max_level == (cur_level+1)) && aa2->sof_next_id)){
|
||||
&& ((aa2->max_level == (cur_level + 1)) && aa2->sof_next_id)){
|
||||
SendAA(aa2->id);
|
||||
SendAA(aa2->sof_next_id);
|
||||
}
|
||||
@@ -1059,10 +1062,28 @@ void Client::BuyAA(AA_Action* action)
|
||||
|
||||
//we are building these messages ourself instead of using the stringID to work around patch discrepencies
|
||||
//these are AA_GAIN_ABILITY (410) & AA_IMPROVE (411), respectively, in both Titanium & SoF. not sure about 6.2
|
||||
if(cur_level<1)
|
||||
Message(15,"You have gained the ability \"%s\" at a cost of %d ability %s.", aa2->name, real_cost, (real_cost>1)?"points":"point");
|
||||
else
|
||||
Message(15,"You have improved %s %d at a cost of %d ability %s.", aa2->name, cur_level+1, real_cost, (real_cost>1)?"points":"point");
|
||||
|
||||
/* Initial purchase of an AA ability */
|
||||
if (cur_level < 1){
|
||||
Message(15, "You have gained the ability \"%s\" at a cost of %d ability %s.", aa2->name, real_cost, (real_cost>1) ? "points" : "point");
|
||||
|
||||
/* QS: Player_Log_AA_Purchases */
|
||||
if (RuleB(QueryServ, PlayerLogAAPurchases)){
|
||||
std::string event_desc = StringFormat("Initial AA Purchase :: aa_name:%s aa_id:%i at cost:%i in zoneid:%i instid:%i", aa2->name, aa2->id, real_cost, this->GetZoneID(), this->GetInstanceID());
|
||||
QServ->PlayerLogEvent(Player_Log_AA_Purchases, this->CharacterID(), event_desc);
|
||||
}
|
||||
}
|
||||
/* Ranked purchase of an AA ability */
|
||||
else{
|
||||
Message(15, "You have improved %s %d at a cost of %d ability %s.", aa2->name, cur_level + 1, real_cost, (real_cost > 1) ? "points" : "point");
|
||||
|
||||
/* QS: Player_Log_AA_Purchases */
|
||||
if (RuleB(QueryServ, PlayerLogAAPurchases)){
|
||||
std::string event_desc = StringFormat("Ranked AA Purchase :: aa_name:%s aa_id:%i at cost:%i in zoneid:%i instid:%i", aa2->name, aa2->id, real_cost, this->GetZoneID(), this->GetInstanceID());
|
||||
QServ->PlayerLogEvent(Player_Log_AA_Purchases, this->CharacterID(), event_desc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
SendAAStats();
|
||||
@@ -1237,7 +1258,7 @@ void Client::SendAA(uint32 id, int seq) {
|
||||
Note: There were many ways to achieve this effect - The method used proved to be the most straight forward and consistent.
|
||||
Stacking does not currently work ideally for AA's that use hotkeys, therefore they will be excluded at this time.
|
||||
|
||||
TODO: Problem with AA hotkeys - When you reach max rank of an AA tier (ie 5/5), it automatically displays the next AA in
|
||||
TODO: Problem with aa.hotkeys - When you reach max rank of an AA tier (ie 5/5), it automatically displays the next AA in
|
||||
the series and you can not transfer the hotkey to the next AA series. To the best of the my ability and through many
|
||||
different variations of coding I could not find an ideal solution to this issue.
|
||||
|
||||
@@ -1466,32 +1487,30 @@ void Zone::LoadAAs() {
|
||||
bool ZoneDatabase::LoadAAEffects2() {
|
||||
aa_effects.clear(); //start fresh
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT aaid, slot, effectid, base1, base2 FROM aa_effects ORDER BY aaid ASC, slot ASC"), errbuf, &result)) {
|
||||
int count = 0;
|
||||
while((row = mysql_fetch_row(result))!= nullptr) {
|
||||
int aaid = atoi(row[0]);
|
||||
int slot = atoi(row[1]);
|
||||
int effectid = atoi(row[2]);
|
||||
int base1 = atoi(row[3]);
|
||||
int base2 = atoi(row[4]);
|
||||
aa_effects[aaid][slot].skill_id = effectid;
|
||||
aa_effects[aaid][slot].base1 = base1;
|
||||
aa_effects[aaid][slot].base2 = base2;
|
||||
aa_effects[aaid][slot].slot = slot; //not really needed, but we'll populate it just in case
|
||||
count++;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
if (count < 1) //no results
|
||||
LogFile->write(EQEMuLog::Error, "Error loading AA Effects, none found in the database.");
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in ZoneDatabase::LoadAAEffects2 query: '%s': %s", query, errbuf);
|
||||
const std::string query = "SELECT aaid, slot, effectid, base1, base2 FROM aa_effects ORDER BY aaid ASC, slot ASC";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in ZoneDatabase::LoadAAEffects2 query: '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
if (!results.RowCount()) { //no results
|
||||
LogFile->write(EQEMuLog::Error, "Error loading AA Effects, none found in the database.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
int aaid = atoi(row[0]);
|
||||
int slot = atoi(row[1]);
|
||||
int effectid = atoi(row[2]);
|
||||
int base1 = atoi(row[3]);
|
||||
int base2 = atoi(row[4]);
|
||||
aa_effects[aaid][slot].skill_id = effectid;
|
||||
aa_effects[aaid][slot].base1 = base1;
|
||||
aa_effects[aaid][slot].base2 = base2;
|
||||
aa_effects[aaid][slot].slot = slot; //not really needed, but we'll populate it just in case
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
void Client::ResetAA(){
|
||||
@@ -1633,73 +1652,62 @@ void Client::InspectBuffs(Client* Inspector, int Rank)
|
||||
|
||||
//this really need to be renamed to LoadAAActions()
|
||||
bool ZoneDatabase::LoadAAEffects() {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
memset(AA_Actions, 0, sizeof(AA_Actions)); //I hope the compiler is smart about this size...
|
||||
|
||||
const char *query = "SELECT aaid,rank,reuse_time,spell_id,target,nonspell_action,nonspell_mana,nonspell_duration,"
|
||||
"redux_aa,redux_rate,redux_aa2,redux_rate2 FROM aa_actions";
|
||||
|
||||
if(RunQuery(query, static_cast<uint32>(strlen(query)), errbuf, &result)) {
|
||||
//safe_delete_array(query);
|
||||
int r;
|
||||
while ((row = mysql_fetch_row(result))) {
|
||||
r = 0;
|
||||
int aaid = atoi(row[r++]);
|
||||
int rank = atoi(row[r++]);
|
||||
if(aaid < 0 || aaid >= aaHighestID || rank < 0 || rank >= MAX_AA_ACTION_RANKS)
|
||||
continue;
|
||||
AA_DBAction *caction = &AA_Actions[aaid][rank];
|
||||
|
||||
caction->reuse_time = atoi(row[r++]);
|
||||
caction->spell_id = atoi(row[r++]);
|
||||
caction->target = (aaTargetType) atoi(row[r++]);
|
||||
caction->action = (aaNonspellAction) atoi(row[r++]);
|
||||
caction->mana_cost = atoi(row[r++]);
|
||||
caction->duration = atoi(row[r++]);
|
||||
caction->redux_aa = (aaID) atoi(row[r++]);
|
||||
caction->redux_rate = atoi(row[r++]);
|
||||
caction->redux_aa2 = (aaID) atoi(row[r++]);
|
||||
caction->redux_rate2 = atoi(row[r++]);
|
||||
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadAAEffects query '%s': %s", query, errbuf);;
|
||||
//safe_delete_array(query);
|
||||
const std::string query = "SELECT aaid, rank, reuse_time, spell_id, target, "
|
||||
"nonspell_action, nonspell_mana, nonspell_duration, "
|
||||
"redux_aa, redux_rate, redux_aa2, redux_rate2 FROM aa_actions";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadAAEffects query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
|
||||
int aaid = atoi(row[0]);
|
||||
int rank = atoi(row[1]);
|
||||
if(aaid < 0 || aaid >= aaHighestID || rank < 0 || rank >= MAX_AA_ACTION_RANKS)
|
||||
continue;
|
||||
AA_DBAction *caction = &AA_Actions[aaid][rank];
|
||||
|
||||
caction->reuse_time = atoi(row[2]);
|
||||
caction->spell_id = atoi(row[3]);
|
||||
caction->target = (aaTargetType) atoi(row[4]);
|
||||
caction->action = (aaNonspellAction) atoi(row[5]);
|
||||
caction->mana_cost = atoi(row[6]);
|
||||
caction->duration = atoi(row[7]);
|
||||
caction->redux_aa = (aaID) atoi(row[8]);
|
||||
caction->redux_rate = atoi(row[9]);
|
||||
caction->redux_aa2 = (aaID) atoi(row[10]);
|
||||
caction->redux_rate2 = atoi(row[11]);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//Returns the number effects an AA has when we send them to the client
|
||||
//Returns the number effects an aa.has when we send them to the client
|
||||
//For the purposes of sizing a packet because every skill does not
|
||||
//have the same number effects, they can range from none to a few depending on AA.
|
||||
//counts the # of effects by counting the different slots of an AAID in the DB.
|
||||
|
||||
//AndMetal: this may now be obsolete since we have Zone::GetTotalAALevels()
|
||||
uint8 ZoneDatabase::GetTotalAALevels(uint32 skill_id) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int total=0;
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT count(slot) from aa_effects where aaid=%i", skill_id), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
total=atoi(row[0]);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTotalAALevels '%s: %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
}
|
||||
return total;
|
||||
|
||||
std::string query = StringFormat("SELECT count(slot) FROM aa_effects WHERE aaid = %i", skill_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTotalAALevels '%s: %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
//this will allow us to count the number of effects for an AA by pulling the info from memory instead of the database. hopefully this will same some CPU cycles
|
||||
@@ -1727,59 +1735,54 @@ void ZoneDatabase::FillAAEffects(SendAA_Struct* aa_struct){
|
||||
if(!aa_struct)
|
||||
return;
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT effectid, base1, base2, slot from aa_effects where aaid=%i order by slot asc", aa_struct->id), errbuf, &result)) {
|
||||
int ndx=0;
|
||||
while((row = mysql_fetch_row(result))!=nullptr) {
|
||||
aa_struct->abilities[ndx].skill_id=atoi(row[0]);
|
||||
aa_struct->abilities[ndx].base1=atoi(row[1]);
|
||||
aa_struct->abilities[ndx].base2=atoi(row[2]);
|
||||
aa_struct->abilities[ndx].slot=atoi(row[3]);
|
||||
ndx++;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in Client::FillAAEffects query: '%s': %s", query, errbuf);
|
||||
std::string query = StringFormat("SELECT effectid, base1, base2, slot from aa_effects where aaid=%i order by slot asc", aa_struct->id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in Client::FillAAEffects query: '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row, ++index) {
|
||||
aa_struct->abilities[index].skill_id=atoi(row[0]);
|
||||
aa_struct->abilities[index].base1=atoi(row[1]);
|
||||
aa_struct->abilities[index].base2=atoi(row[2]);
|
||||
aa_struct->abilities[index].slot=atoi(row[3]);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
uint32 ZoneDatabase::CountAAs(){
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int count=0;
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT count(title_sid) from altadv_vars"), errbuf, &result)) {
|
||||
if((row = mysql_fetch_row(result))!=nullptr)
|
||||
count = atoi(row[0]);
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in ZoneDatabase::CountAAs query '%s': %s", query, errbuf);
|
||||
|
||||
const std::string query = "SELECT count(title_sid) FROM altadv_vars";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in ZoneDatabase::CountAAs query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
return count;
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);;
|
||||
}
|
||||
|
||||
uint32 ZoneDatabase::CountAAEffects(){
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int count=0;
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT count(id) from aa_effects"), errbuf, &result)) {
|
||||
if((row = mysql_fetch_row(result))!=nullptr){
|
||||
count = atoi(row[0]);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in ZoneDatabase::CountAALevels query '%s': %s", query, errbuf);
|
||||
uint32 ZoneDatabase::CountAAEffects() {
|
||||
|
||||
const std::string query = "SELECT count(id) FROM aa_effects";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in ZoneDatabase::CountAALevels query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
return count;
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
uint32 ZoneDatabase::GetSizeAA(){
|
||||
@@ -1792,164 +1795,128 @@ uint32 ZoneDatabase::GetSizeAA(){
|
||||
void ZoneDatabase::LoadAAs(SendAA_Struct **load){
|
||||
if(!load)
|
||||
return;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT skill_id from altadv_vars order by skill_id"), errbuf, &result)) {
|
||||
int skill=0,ndx=0;
|
||||
while((row = mysql_fetch_row(result))!=nullptr) {
|
||||
skill=atoi(row[0]);
|
||||
load[ndx] = GetAASkillVars(skill);
|
||||
load[ndx]->seq = ndx+1;
|
||||
ndx++;
|
||||
|
||||
std::string query = "SELECT skill_id FROM altadv_vars ORDER BY skill_id";
|
||||
auto results = QueryDatabase(query);
|
||||
if (results.Success()) {
|
||||
int skill = 0, index = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row, ++index) {
|
||||
skill = atoi(row[0]);
|
||||
load[index] = GetAASkillVars(skill);
|
||||
load[index]->seq = index+1;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in ZoneDatabase::LoadAAs query '%s': %s", query, errbuf);
|
||||
LogFile->write(EQEMuLog::Error, "Error in ZoneDatabase::LoadAAs query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
AARequiredLevelAndCost.clear();
|
||||
query = "SELECT skill_id, level, cost from aa_required_level_cost order by skill_id";
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in ZoneDatabase::LoadAAs query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT skill_id, level, cost from aa_required_level_cost order by skill_id"), errbuf, &result))
|
||||
{
|
||||
AALevelCost_Struct aalcs;
|
||||
while((row = mysql_fetch_row(result))!=nullptr)
|
||||
{
|
||||
aalcs.Level = atoi(row[1]);
|
||||
aalcs.Cost = atoi(row[2]);
|
||||
AARequiredLevelAndCost[atoi(row[0])] = aalcs;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
LogFile->write(EQEMuLog::Error, "Error in ZoneDatabase::LoadAAs query '%s': %s", query, errbuf);
|
||||
AALevelCost_Struct aalcs;
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
aalcs.Level = atoi(row[1]);
|
||||
aalcs.Cost = atoi(row[2]);
|
||||
AARequiredLevelAndCost[atoi(row[0])] = aalcs;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
SendAA_Struct* ZoneDatabase::GetAASkillVars(uint32 skill_id)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
SendAA_Struct* sendaa = nullptr;
|
||||
uchar* buffer;
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SET @row = 0"), errbuf)) { //initialize "row" variable in database for next query
|
||||
safe_delete_array(query);
|
||||
MYSQL_RES *result; //we don't really need these unless we get to this point, so why bother?
|
||||
MYSQL_ROW row;
|
||||
std::string query = "SET @row = 0"; //initialize "row" variable in database for next query
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetAASkillVars '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (RunQuery(query, MakeAnyLenString(&query,
|
||||
"SELECT "
|
||||
"a.cost, "
|
||||
"a.max_level, "
|
||||
"a.hotkey_sid, "
|
||||
"a.hotkey_sid2, "
|
||||
"a.title_sid, "
|
||||
"a.desc_sid, "
|
||||
"a.type, "
|
||||
"COALESCE(" //so we can return 0 if it's null
|
||||
"(" //this is our derived table that has the row # that we can SELECT from, because the client is stupid
|
||||
"SELECT "
|
||||
"p.prereq_index_num "
|
||||
"FROM "
|
||||
"("
|
||||
"SELECT "
|
||||
"a2.skill_id, "
|
||||
"@row := @row + 1 AS prereq_index_num "
|
||||
"FROM "
|
||||
"altadv_vars a2"
|
||||
") AS p "
|
||||
"WHERE "
|
||||
"p.skill_id = a.prereq_skill"
|
||||
"), "
|
||||
"0) AS prereq_skill_index, "
|
||||
"a.prereq_minpoints, "
|
||||
"a.spell_type, "
|
||||
"a.spell_refresh, "
|
||||
"a.classes, "
|
||||
"a.berserker, "
|
||||
"a.spellid, "
|
||||
"a.class_type, "
|
||||
"a.name, "
|
||||
"a.cost_inc, "
|
||||
"a.aa_expansion, "
|
||||
"a.special_category, "
|
||||
"a.sof_type, "
|
||||
"a.sof_cost_inc, "
|
||||
"a.sof_max_level, "
|
||||
"a.sof_next_skill, "
|
||||
"a.clientver, " // Client Version 0 = None, 1 = All, 2 = Titanium/6.2, 4 = SoF 5 = SOD 6 = UF
|
||||
"a.account_time_required, "
|
||||
"a.sof_current_level,"
|
||||
"a.sof_next_id, "
|
||||
"a.level_inc "
|
||||
" FROM altadv_vars a WHERE skill_id=%i", skill_id), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
int total_abilities = GetTotalAALevels(skill_id); //eventually we'll want to use zone->GetTotalAALevels(skill_id) since it should save queries to the DB
|
||||
int totalsize = total_abilities * sizeof(AA_Ability) + sizeof(SendAA_Struct);
|
||||
query = StringFormat("SELECT a.cost, a.max_level, a.hotkey_sid, a.hotkey_sid2, a.title_sid, a.desc_sid, a.type, "
|
||||
"COALESCE(" //So we can return 0 if it's null.
|
||||
"(" // this is our derived table that has the row #
|
||||
// that we can SELECT from, because the client is stupid.
|
||||
"SELECT p.prereq_index_num "
|
||||
"FROM (SELECT a2.skill_id, @row := @row + 1 AS prereq_index_num "
|
||||
"FROM altadv_vars a2) AS p "
|
||||
"WHERE p.skill_id = a.prereq_skill), 0) "
|
||||
"AS prereq_skill_index, a.prereq_minpoints, a.spell_type, a.spell_refresh, a.classes, "
|
||||
"a.berserker, a.spellid, a.class_type, a.name, a.cost_inc, a.aa_expansion, a.special_category, "
|
||||
"a.sof_type, a.sof_cost_inc, a.sof_max_level, a.sof_next_skill, "
|
||||
"a.clientver, " // Client Version 0 = None, 1 = All, 2 = Titanium/6.2, 4 = SoF 5 = SOD 6 = UF
|
||||
"a.account_time_required, a.sof_current_level, a.sof_next_id, a.level_inc "
|
||||
"FROM altadv_vars a WHERE skill_id=%i", skill_id);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetAASkillVars '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
buffer = new uchar[totalsize];
|
||||
memset(buffer,0,totalsize);
|
||||
sendaa = (SendAA_Struct*)buffer;
|
||||
if (results.RowCount() != 1)
|
||||
return nullptr;
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
int total_abilities = GetTotalAALevels(skill_id); //eventually we'll want to use zone->GetTotalAALevels(skill_id) since it should save queries to the DB
|
||||
int totalsize = total_abilities * sizeof(AA_Ability) + sizeof(SendAA_Struct);
|
||||
|
||||
//ATOI IS NOT UNSIGNED LONG-SAFE!!!
|
||||
SendAA_Struct* sendaa = nullptr;
|
||||
uchar* buffer;
|
||||
|
||||
sendaa->cost = atoul(row[0]);
|
||||
sendaa->cost2 = sendaa->cost;
|
||||
sendaa->max_level = atoul(row[1]);
|
||||
sendaa->hotkey_sid = atoul(row[2]);
|
||||
sendaa->id = skill_id;
|
||||
sendaa->hotkey_sid2 = atoul(row[3]);
|
||||
sendaa->title_sid = atoul(row[4]);
|
||||
sendaa->desc_sid = atoul(row[5]);
|
||||
sendaa->type = atoul(row[6]);
|
||||
sendaa->prereq_skill = atoul(row[7]);
|
||||
sendaa->prereq_minpoints = atoul(row[8]);
|
||||
sendaa->spell_type = atoul(row[9]);
|
||||
sendaa->spell_refresh = atoul(row[10]);
|
||||
sendaa->classes = static_cast<uint16>(atoul(row[11]));
|
||||
sendaa->berserker = static_cast<uint16>(atoul(row[12]));
|
||||
sendaa->last_id = 0xFFFFFFFF;
|
||||
sendaa->current_level=1;
|
||||
sendaa->spellid = atoul(row[13]);
|
||||
sendaa->class_type = atoul(row[14]);
|
||||
strcpy(sendaa->name,row[15]);
|
||||
buffer = new uchar[totalsize];
|
||||
memset(buffer,0,totalsize);
|
||||
sendaa = (SendAA_Struct*)buffer;
|
||||
|
||||
sendaa->total_abilities=total_abilities;
|
||||
if(sendaa->max_level > 1)
|
||||
sendaa->next_id=skill_id+1;
|
||||
else
|
||||
sendaa->next_id=0xFFFFFFFF;
|
||||
auto row = results.begin();
|
||||
|
||||
//ATOI IS NOT UNSIGNED LONG-SAFE!!!
|
||||
|
||||
sendaa->cost = atoul(row[0]);
|
||||
sendaa->cost2 = sendaa->cost;
|
||||
sendaa->max_level = atoul(row[1]);
|
||||
sendaa->hotkey_sid = atoul(row[2]);
|
||||
sendaa->id = skill_id;
|
||||
sendaa->hotkey_sid2 = atoul(row[3]);
|
||||
sendaa->title_sid = atoul(row[4]);
|
||||
sendaa->desc_sid = atoul(row[5]);
|
||||
sendaa->type = atoul(row[6]);
|
||||
sendaa->prereq_skill = atoul(row[7]);
|
||||
sendaa->prereq_minpoints = atoul(row[8]);
|
||||
sendaa->spell_type = atoul(row[9]);
|
||||
sendaa->spell_refresh = atoul(row[10]);
|
||||
sendaa->classes = static_cast<uint16>(atoul(row[11]));
|
||||
sendaa->berserker = static_cast<uint16>(atoul(row[12]));
|
||||
sendaa->last_id = 0xFFFFFFFF;
|
||||
sendaa->current_level=1;
|
||||
sendaa->spellid = atoul(row[13]);
|
||||
sendaa->class_type = atoul(row[14]);
|
||||
strcpy(sendaa->name,row[15]);
|
||||
|
||||
sendaa->total_abilities=total_abilities;
|
||||
if(sendaa->max_level > 1)
|
||||
sendaa->next_id=skill_id+1;
|
||||
else
|
||||
sendaa->next_id=0xFFFFFFFF;
|
||||
|
||||
sendaa->cost_inc = atoi(row[16]);
|
||||
|
||||
// Begin SoF Specific/Adjusted AA Fields
|
||||
sendaa->aa_expansion = atoul(row[17]);
|
||||
sendaa->special_category = atoul(row[18]);
|
||||
sendaa->sof_type = atoul(row[19]);
|
||||
sendaa->sof_cost_inc = atoi(row[20]);
|
||||
sendaa->sof_max_level = atoul(row[21]);
|
||||
sendaa->sof_next_skill = atoul(row[22]);
|
||||
sendaa->clientver = atoul(row[23]);
|
||||
sendaa->account_time_required = atoul(row[24]);
|
||||
|
||||
//Internal use only - not sent to client
|
||||
sendaa->sof_current_level = atoul(row[25]);
|
||||
sendaa->sof_next_id = atoul(row[26]);
|
||||
sendaa->level_inc = static_cast<uint8>(atoul(row[27]));
|
||||
|
||||
sendaa->cost_inc = atoi(row[16]);
|
||||
// Begin SoF Specific/Adjusted AA Fields
|
||||
sendaa->aa_expansion = atoul(row[17]);
|
||||
sendaa->special_category = atoul(row[18]);
|
||||
sendaa->sof_type = atoul(row[19]);
|
||||
sendaa->sof_cost_inc = atoi(row[20]);
|
||||
sendaa->sof_max_level = atoul(row[21]);
|
||||
sendaa->sof_next_skill = atoul(row[22]);
|
||||
sendaa->clientver = atoul(row[23]);
|
||||
sendaa->account_time_required = atoul(row[24]);
|
||||
//Internal use only - not sent to client
|
||||
sendaa->sof_current_level = atoul(row[25]);
|
||||
sendaa->sof_next_id = atoul(row[26]);
|
||||
sendaa->level_inc = static_cast<uint8>(atoul(row[27]));
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetAASkillVars '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
}
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetAASkillVars '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
}
|
||||
return sendaa;
|
||||
}
|
||||
|
||||
@@ -2134,7 +2134,7 @@ struct AALevelCost_Struct
|
||||
uint32 Cost;
|
||||
};
|
||||
|
||||
//assumes that no activatable AA has more than 5 ranks
|
||||
//assumes that no activatable aa.has more than 5 ranks
|
||||
#define MAX_AA_ACTION_RANKS 20
|
||||
extern AA_DBAction AA_Actions[aaHighestID][MAX_AA_ACTION_RANKS]; //[aaid][rank]
|
||||
extern std::map<uint16, AA_SwarmPet> AA_SwarmPets; //key=spell_id
|
||||
+32
-3
@@ -23,9 +23,9 @@
|
||||
#include "map.h"
|
||||
#include "../common/spdat.h"
|
||||
#include "../common/skills.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "StringIDs.h"
|
||||
#include "string_ids.h"
|
||||
#include <iostream>
|
||||
|
||||
extern Zone* zone;
|
||||
@@ -873,7 +873,34 @@ bool Mob::CombatRange(Mob* other)
|
||||
if (size_mod > 10000)
|
||||
size_mod = size_mod / 7;
|
||||
|
||||
if (DistNoRoot(*other) <= size_mod)
|
||||
float _DistNoRoot = DistNoRoot(*other);
|
||||
|
||||
if (GetSpecialAbility(NPC_CHASE_DISTANCE)){
|
||||
|
||||
bool DoLoSCheck = true;
|
||||
float max_dist = static_cast<float>(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 0));
|
||||
float min_dist = static_cast<float>(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 1));
|
||||
|
||||
if (GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 2));
|
||||
DoLoSCheck = false; //Ignore line of sight check
|
||||
|
||||
if (max_dist == 1)
|
||||
max_dist = 250.0f; //Default it to 250 if you forget to put a value
|
||||
|
||||
max_dist = max_dist * max_dist;
|
||||
|
||||
if (!min_dist)
|
||||
min_dist = size_mod; //Default to melee range
|
||||
else
|
||||
min_dist = min_dist * min_dist;
|
||||
|
||||
if ((DoLoSCheck && CheckLastLosState()) && (_DistNoRoot >= min_dist && _DistNoRoot <= max_dist))
|
||||
SetPseudoRoot(true);
|
||||
else
|
||||
SetPseudoRoot(false);
|
||||
}
|
||||
|
||||
if (_DistNoRoot <= size_mod)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -887,6 +914,8 @@ bool Mob::CheckLosFN(Mob* other) {
|
||||
if(other)
|
||||
Result = CheckLosFN(other->GetX(), other->GetY(), other->GetZ(), other->GetSize());
|
||||
|
||||
SetLastLosState(Result);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
+38
-36
@@ -29,19 +29,22 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include "masterentity.h"
|
||||
#include "NpcAI.h"
|
||||
#include "npc_ai.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/eq_constants.h"
|
||||
#include "../common/skills.h"
|
||||
#include "../common/spdat.h"
|
||||
#include "zone.h"
|
||||
#include "StringIDs.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "water_map.h"
|
||||
#include "worldserver.h"
|
||||
#include "queryserv.h"
|
||||
|
||||
extern QueryServ* QServ;
|
||||
extern WorldServer worldserver;
|
||||
|
||||
#ifdef _WINDOWS
|
||||
@@ -1455,14 +1458,14 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
|
||||
int exploss = 0;
|
||||
mlog(COMBAT__HITS, "Fatal blow dealt by %s with %d damage, spell %d, skill %d", killerMob ? killerMob->GetName() : "Unknown", damage, spell, attack_skill);
|
||||
|
||||
//
|
||||
// #1: Send death packet to everyone
|
||||
//
|
||||
/*
|
||||
#1: Send death packet to everyone
|
||||
*/
|
||||
uint8 killed_level = GetLevel();
|
||||
|
||||
SendLogoutPackets();
|
||||
|
||||
//make our become corpse packet, and queue to ourself before OP_Death.
|
||||
/* Make self become corpse packet */
|
||||
EQApplicationPacket app2(OP_BecomeCorpse, sizeof(BecomeCorpse_Struct));
|
||||
BecomeCorpse_Struct* bc = (BecomeCorpse_Struct*)app2.pBuffer;
|
||||
bc->spawn_id = GetID();
|
||||
@@ -1471,7 +1474,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
|
||||
bc->z = GetZ();
|
||||
QueuePacket(&app2);
|
||||
|
||||
// make death packet
|
||||
/* Make Death Packet */
|
||||
EQApplicationPacket app(OP_Death, sizeof(Death_Struct));
|
||||
Death_Struct* d = (Death_Struct*)app.pBuffer;
|
||||
d->spawn_id = GetID();
|
||||
@@ -1484,9 +1487,9 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
|
||||
app.priority = 6;
|
||||
entity_list.QueueClients(this, &app);
|
||||
|
||||
//
|
||||
// #2: figure out things that affect the player dying and mark them dead
|
||||
//
|
||||
/*
|
||||
#2: figure out things that affect the player dying and mark them dead
|
||||
*/
|
||||
|
||||
InterruptSpell();
|
||||
SetPet(0);
|
||||
@@ -1541,9 +1544,9 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
|
||||
//remove ourself from all proximities
|
||||
ClearAllProximities();
|
||||
|
||||
//
|
||||
// #3: exp loss and corpse generation
|
||||
//
|
||||
/*
|
||||
#3: exp loss and corpse generation
|
||||
*/
|
||||
|
||||
// figure out if they should lose exp
|
||||
if(RuleB(Character, UseDeathExpLossMult)){
|
||||
@@ -1659,27 +1662,21 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
|
||||
|
||||
LeftCorpse = true;
|
||||
}
|
||||
|
||||
// if(!IsLD())//Todo: make it so an LDed client leaves corpse if its enabled
|
||||
// MakeCorpse(exploss);
|
||||
} else {
|
||||
BuffFadeDetrimental();
|
||||
}
|
||||
|
||||
//
|
||||
// Finally, send em home
|
||||
//
|
||||
/*
|
||||
Finally, send em home
|
||||
|
||||
// we change the mob variables, not pp directly, because Save() will copy
|
||||
// from these and overwrite what we set in pp anyway
|
||||
//
|
||||
We change the mob variables, not pp directly, because Save() will copy
|
||||
from these and overwrite what we set in pp anyway
|
||||
*/
|
||||
|
||||
if(LeftCorpse && (GetClientVersionBit() & BIT_SoFAndLater) && RuleB(Character, RespawnFromHover))
|
||||
{
|
||||
ClearDraggedCorpses();
|
||||
|
||||
RespawnFromHoverTimer.Start(RuleI(Character, RespawnFromHoverTimer) * 1000);
|
||||
|
||||
ClearDraggedCorpses();
|
||||
RespawnFromHoverTimer.Start(RuleI(Character, RespawnFromHoverTimer) * 1000);
|
||||
SendRespawnBinds();
|
||||
}
|
||||
else
|
||||
@@ -1696,17 +1693,22 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
|
||||
if(r)
|
||||
r->MemberZoned(this);
|
||||
|
||||
dead_timer.Start(5000, true);
|
||||
|
||||
dead_timer.Start(5000, true);
|
||||
m_pp.zone_id = m_pp.binds[0].zoneId;
|
||||
m_pp.zoneInstance = 0;
|
||||
database.MoveCharacterToZone(this->CharacterID(), database.GetZoneName(m_pp.zone_id));
|
||||
|
||||
Save();
|
||||
|
||||
database.MoveCharacterToZone(this->CharacterID(), database.GetZoneName(m_pp.zone_id));
|
||||
Save();
|
||||
GoToDeath();
|
||||
}
|
||||
|
||||
/* QS: PlayerLogDeaths */
|
||||
if (RuleB(QueryServ, PlayerLogDeaths)){
|
||||
const char * killer_name = "";
|
||||
if (killerMob && killerMob->GetCleanName()){ killer_name = killerMob->GetCleanName(); }
|
||||
std::string event_desc = StringFormat("Died in zoneid:%i instid:%i by '%s', spellid:%i, damage:%i", this->GetZoneID(), this->GetInstanceID(), killer_name, spell, damage);
|
||||
QServ->PlayerLogEvent(Player_Log_Deaths, this->CharacterID(), event_desc);
|
||||
}
|
||||
|
||||
parse->EventPlayer(EVENT_DEATH_COMPLETE, this, buffer, 0);
|
||||
return true;
|
||||
}
|
||||
@@ -3569,12 +3571,12 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
||||
TryTriggerOnValueAmount(true);
|
||||
|
||||
//fade mez if we are mezzed
|
||||
if (IsMezzed()) {
|
||||
if (IsMezzed() && attacker) {
|
||||
mlog(COMBAT__HITS, "Breaking mez due to attack.");
|
||||
entity_list.MessageClose_StringID(this, true, 100, MT_WornOff,
|
||||
HAS_BEEN_AWAKENED, GetCleanName(), attacker->GetCleanName());
|
||||
BuffFadeByEffect(SE_Mez);
|
||||
}
|
||||
}
|
||||
|
||||
//check stun chances if bashing
|
||||
if (damage > 0 && ((skill_used == SkillBash || skill_used == SkillKick) && attacker)) {
|
||||
|
||||
+3
-3
@@ -20,13 +20,13 @@
|
||||
#include "masterentity.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/moremath.h"
|
||||
#include "../common/Item.h"
|
||||
#include "../common/item.h"
|
||||
#include "worldserver.h"
|
||||
#include "../common/skills.h"
|
||||
#include "../common/bodytypes.h"
|
||||
#include "../common/classes.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "../common/unix.h"
|
||||
#endif
|
||||
|
||||
#include "StringIDs.h"
|
||||
#include "string_ids.h"
|
||||
|
||||
void Mob::CalcBonuses()
|
||||
{
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@
|
||||
#include "bot.h"
|
||||
#include "object.h"
|
||||
#include "doors.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "../common/string_util.h"
|
||||
|
||||
extern volatile bool ZoneLoaded;
|
||||
|
||||
|
||||
+3
-3
@@ -3,15 +3,15 @@
|
||||
|
||||
#ifdef BOTS
|
||||
|
||||
#include "botStructs.h"
|
||||
#include "bot_structs.h"
|
||||
#include "mob.h"
|
||||
#include "client.h"
|
||||
#include "pets.h"
|
||||
#include "groups.h"
|
||||
#include "corpse.h"
|
||||
#include "zonedb.h"
|
||||
#include "StringIDs.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/debug.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "worldserver.h"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifdef BOTS
|
||||
|
||||
#include "bot.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
|
||||
bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) {
|
||||
|
||||
|
||||
+51
-24
@@ -49,21 +49,22 @@ extern volatile bool RunLoops;
|
||||
#include "../common/packet_functions.h"
|
||||
#include "petitions.h"
|
||||
#include "../common/serverinfo.h"
|
||||
#include "../common/ZoneNumbers.h"
|
||||
#include "../common/zone_numbers.h"
|
||||
#include "../common/moremath.h"
|
||||
#include "../common/guilds.h"
|
||||
#include "../common/breakdowns.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "forage.h"
|
||||
#include "command.h"
|
||||
#include "StringIDs.h"
|
||||
#include "NpcAI.h"
|
||||
#include "string_ids.h"
|
||||
#include "npc_ai.h"
|
||||
#include "client_logs.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "QuestParserCollection.h"
|
||||
|
||||
#include "quest_parser_collection.h"
|
||||
#include "queryserv.h"
|
||||
|
||||
extern QueryServ* QServ;
|
||||
extern EntityList entity_list;
|
||||
extern Zone* zone;
|
||||
extern volatile bool ZoneLoaded;
|
||||
@@ -629,6 +630,9 @@ bool Client::Save(uint8 iCommitNow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Mirror Character Data */
|
||||
database.StoreCharacterLookup(this->CharacterID());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -805,8 +809,8 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(RuleB(QueryServ, PlayerChatLogging)) {
|
||||
/* Logs Player Chat */
|
||||
if (RuleB(QueryServ, PlayerLogChat)) {
|
||||
ServerPacket* pack = new ServerPacket(ServerOP_Speech, sizeof(Server_Speech_Struct) + strlen(message) + 1);
|
||||
Server_Speech_Struct* sem = (Server_Speech_Struct*) pack->pBuffer;
|
||||
|
||||
@@ -841,7 +845,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
||||
|
||||
switch(chan_num)
|
||||
{
|
||||
case 0: { // GuildChat
|
||||
case 0: { /* Guild Chat */
|
||||
if (!IsInAGuild())
|
||||
Message_StringID(MT_DefaultText, GUILD_NOT_MEMBER2); //You are not a member of any guild.
|
||||
else if (!guild_mgr.CheckPermission(GuildID(), GuildRank(), GUILD_SPEAK))
|
||||
@@ -850,7 +854,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
||||
Message(0, "Error: World server disconnected");
|
||||
break;
|
||||
}
|
||||
case 2: { // GroupChat
|
||||
case 2: { /* Group Chat */
|
||||
Raid* raid = entity_list.GetRaidByClient(this);
|
||||
if(raid) {
|
||||
raid->RaidGroupSay((const char*) message, this);
|
||||
@@ -863,14 +867,14 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 15: { //raid say
|
||||
case 15: { /* Raid Say */
|
||||
Raid* raid = entity_list.GetRaidByClient(this);
|
||||
if(raid){
|
||||
raid->RaidSay((const char*) message, this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: { // Shout
|
||||
case 3: { /* Shout */
|
||||
Mob *sender = this;
|
||||
if (GetPet() && GetPet()->FindType(SE_VoiceGraft))
|
||||
sender = GetPet();
|
||||
@@ -878,7 +882,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
||||
entity_list.ChannelMessage(sender, chan_num, language, lang_skill, message);
|
||||
break;
|
||||
}
|
||||
case 4: { // Auction
|
||||
case 4: { /* Auction */
|
||||
if(RuleB(Chat, ServerWideAuction))
|
||||
{
|
||||
if(!global_channel_timer.Check())
|
||||
@@ -917,7 +921,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 5: { // OOC
|
||||
case 5: { /* OOC */
|
||||
if(RuleB(Chat, ServerWideOOC))
|
||||
{
|
||||
if(!global_channel_timer.Check())
|
||||
@@ -964,15 +968,15 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 6: // Broadcast
|
||||
case 11: { // GMSay
|
||||
case 6: /* Broadcast */
|
||||
case 11: { /* GM Say */
|
||||
if (!(admin >= 80))
|
||||
Message(0, "Error: Only GMs can use this channel");
|
||||
else if (!worldserver.SendChannelMessage(this, targetname, chan_num, 0, language, message))
|
||||
Message(0, "Error: World server disconnected");
|
||||
break;
|
||||
}
|
||||
case 7: { // Tell
|
||||
case 7: { /* Tell */
|
||||
if(!global_channel_timer.Check())
|
||||
{
|
||||
if(strlen(targetname) == 0)
|
||||
@@ -1020,7 +1024,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
||||
Message(0, "Error: World server disconnected");
|
||||
break;
|
||||
}
|
||||
case 8: { // /say
|
||||
case 8: { /* Say */
|
||||
if(message[0] == COMMAND_CHAR) {
|
||||
if(command_dispatch(this, message) == -2) {
|
||||
if(parse->PlayerHasQuestSub(EVENT_COMMAND)) {
|
||||
@@ -2237,6 +2241,15 @@ void Client::AddMoneyToPP(uint64 copper, bool updateclient){
|
||||
|
||||
void Client::AddMoneyToPP(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, bool updateclient){
|
||||
|
||||
/* Set a timestamp in an entity variable for plugin check_handin.pl in return_items
|
||||
This will stopgap players from items being returned if global_npc.pl has a catch all return_items
|
||||
*/
|
||||
struct timeval read_time;
|
||||
char buffer[50];
|
||||
gettimeofday(&read_time, 0);
|
||||
sprintf(buffer, "%li.%li \n", read_time.tv_sec, read_time.tv_usec);
|
||||
this->SetEntityVariable("Stop_Return", buffer);
|
||||
|
||||
int32 new_value = m_pp.platinum + platinum;
|
||||
if(new_value >= 0 && new_value > m_pp.platinum)
|
||||
m_pp.platinum += platinum;
|
||||
@@ -4020,13 +4033,17 @@ void Client::KeyRingAdd(uint32 item_id)
|
||||
bool bFound = KeyRingCheck(item_id);
|
||||
if(!bFound){
|
||||
sprintf(query, "INSERT INTO keyring(char_id,item_id) VALUES(%i,%i)",character_id,item_id);
|
||||
if(database.RunQuery(query, strlen(query), errbuf, 0, &affected_rows))
|
||||
{
|
||||
if(database.RunQuery(query, strlen(query), errbuf, 0, &affected_rows)) {
|
||||
Message(4,"Added to keyring.");
|
||||
|
||||
/* QS: PlayerLogKeyringAddition */
|
||||
if (RuleB(QueryServ, PlayerLogKeyringAddition)){
|
||||
std::string event_desc = StringFormat("itemid:%i in zoneid:%i instid:%i", item_id, this->GetZoneID(), this->GetInstanceID());
|
||||
QServ->PlayerLogEvent(Player_Log_Keyring_Addition, this->CharacterID(), event_desc);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
std::cerr << "Error in Doors::HandleClick query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
return;
|
||||
@@ -6924,8 +6941,18 @@ void Client::SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount)
|
||||
SendAlternateCurrencyValue(currency_id);
|
||||
}
|
||||
|
||||
void Client::AddAlternateCurrencyValue(uint32 currency_id, int32 amount)
|
||||
void Client::AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method)
|
||||
{
|
||||
|
||||
/* Added via Quest, rest of the logging methods may be done inline due to information available in that area of the code */
|
||||
if (method == 1){
|
||||
/* QS: PlayerLogAlternateCurrencyTransactions :: Cursor to Item Storage */
|
||||
if (RuleB(QueryServ, PlayerLogAlternateCurrencyTransactions)){
|
||||
std::string event_desc = StringFormat("Added via Quest :: Cursor to Item :: alt_currency_id:%i amount:%i in zoneid:%i instid:%i", currency_id, this->GetZoneID(), this->GetInstanceID());
|
||||
QServ->PlayerLogEvent(Player_Log_Alternate_Currency_Transactions, this->CharacterID(), event_desc);
|
||||
}
|
||||
}
|
||||
|
||||
if(amount == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -8268,4 +8295,4 @@ void Client::ExpeditionSay(const char *str, int ExpID) {
|
||||
|
||||
mysql_free_result(result);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -24,15 +24,15 @@ class Client;
|
||||
#include "../common/emu_opcodes.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/eq_constants.h"
|
||||
#include "../common/EQStreamIntf.h"
|
||||
#include "../common/EQPacket.h"
|
||||
#include "../common/eq_stream_intf.h"
|
||||
#include "../common/eq_packet.h"
|
||||
#include "../common/linked_list.h"
|
||||
#include "../common/extprofile.h"
|
||||
#include "../common/classes.h"
|
||||
#include "../common/races.h"
|
||||
#include "../common/deity.h"
|
||||
#include "../common/seperator.h"
|
||||
#include "../common/Item.h"
|
||||
#include "../common/item.h"
|
||||
#include "../common/guilds.h"
|
||||
#include "../common/item_struct.h"
|
||||
#include "../common/clientversions.h"
|
||||
@@ -43,9 +43,9 @@ class Client;
|
||||
#include "npc.h"
|
||||
#include "merc.h"
|
||||
#include "zone.h"
|
||||
#include "AA.h"
|
||||
#include "aa.h"
|
||||
#include "questmgr.h"
|
||||
#include "QGlobals.h"
|
||||
#include "qglobals.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
// since windows defines these within windef.h (which windows.h include)
|
||||
@@ -268,7 +268,7 @@ public:
|
||||
void TradeRequestFailed(const EQApplicationPacket* app);
|
||||
void BuyTraderItem(TraderBuy_Struct* tbs,Client* trader,const EQApplicationPacket* app);
|
||||
void TraderUpdate(uint16 slot_id,uint32 trader_id);
|
||||
void FinishTrade(Mob* with, ServerPacket* qspack = nullptr, bool finalizer = false);
|
||||
void FinishTrade(Mob* with, bool finalizer = false, void* event_entry = nullptr, std::list<void*>* event_details = nullptr);
|
||||
void SendZonePoints();
|
||||
|
||||
void SendBuyerResults(char *SearchQuery, uint32 SearchID);
|
||||
@@ -1097,7 +1097,7 @@ public:
|
||||
inline void ClearDraggedCorpses() { DraggedCorpses.clear(); }
|
||||
void SendAltCurrencies();
|
||||
void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount);
|
||||
void AddAlternateCurrencyValue(uint32 currency_id, int32 amount);
|
||||
void AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0);
|
||||
void SendAlternateCurrencyValues();
|
||||
void SendAlternateCurrencyValue(uint32 currency_id, bool send_if_null = true);
|
||||
uint32 GetAlternateCurrencyValue(uint32 currency_id) const;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/packet_functions.h"
|
||||
#include "../common/serverinfo.h"
|
||||
#include "../common/ZoneNumbers.h"
|
||||
#include "../common/zone_numbers.h"
|
||||
#include "../common/moremath.h"
|
||||
#include "../common/guilds.h"
|
||||
#include "../common/logsys.h"
|
||||
@@ -30,8 +30,8 @@
|
||||
#include "worldserver.h"
|
||||
#include "zonedb.h"
|
||||
#include "petitions.h"
|
||||
#include "StringIDs.h"
|
||||
#include "NpcAI.h"
|
||||
#include "string_ids.h"
|
||||
#include "npc_ai.h"
|
||||
|
||||
|
||||
// Return max stat value for level
|
||||
|
||||
+389
-399
File diff suppressed because it is too large
Load Diff
+26
-21
@@ -47,10 +47,10 @@
|
||||
#include "../common/packet_dump.h"
|
||||
#include "worldserver.h"
|
||||
#include "../common/packet_dump_file.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/spdat.h"
|
||||
#include "petitions.h"
|
||||
#include "NpcAI.h"
|
||||
#include "npc_ai.h"
|
||||
#include "../common/skills.h"
|
||||
#include "forage.h"
|
||||
#include "zone.h"
|
||||
@@ -58,12 +58,14 @@
|
||||
#include "../common/faction.h"
|
||||
#include "../common/crc32.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "StringIDs.h"
|
||||
#include "string_ids.h"
|
||||
#include "map.h"
|
||||
#include "guild_mgr.h"
|
||||
#include <string>
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "queryserv.h"
|
||||
|
||||
extern QueryServ* QServ;
|
||||
extern Zone* zone;
|
||||
extern volatile bool ZoneLoaded;
|
||||
extern WorldServer worldserver;
|
||||
@@ -770,38 +772,40 @@ bool Client::Process() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
//just a set of actions preformed all over in Client::Process
|
||||
/* Just a set of actions preformed all over in Client::Process */
|
||||
void Client::OnDisconnect(bool hard_disconnect) {
|
||||
if(hard_disconnect) {
|
||||
LeaveGroup();
|
||||
|
||||
LeaveGroup();
|
||||
Raid *MyRaid = entity_list.GetRaidByClient(this);
|
||||
|
||||
if (MyRaid)
|
||||
MyRaid->MemberZoned(this);
|
||||
|
||||
parse->EventPlayer(EVENT_DISCONNECT, this, "", 0);
|
||||
parse->EventPlayer(EVENT_DISCONNECT, this, "", 0);
|
||||
|
||||
/* QS: PlayerLogConnectDisconnect */
|
||||
if (RuleB(QueryServ, PlayerLogConnectDisconnect)){
|
||||
std::string event_desc = StringFormat("Disconnect :: in zoneid:%i instid:%i", this->GetZoneID(), this->GetInstanceID());
|
||||
QServ->PlayerLogEvent(Player_Log_Connect_State, this->CharacterID(), event_desc);
|
||||
}
|
||||
}
|
||||
|
||||
Mob *Other = trade->With();
|
||||
|
||||
if(Other)
|
||||
{
|
||||
mlog(TRADING__CLIENT, "Client disconnected during a trade. Returning their items.");
|
||||
|
||||
Mob *Other = trade->With();
|
||||
if(Other) {
|
||||
mlog(TRADING__CLIENT, "Client disconnected during a trade. Returning their items.");
|
||||
FinishTrade(this);
|
||||
|
||||
if(Other->IsClient())
|
||||
Other->CastToClient()->FinishTrade(Other);
|
||||
|
||||
trade->Reset();
|
||||
|
||||
/* Reset both sides of the trade */
|
||||
trade->Reset();
|
||||
Other->trade->Reset();
|
||||
}
|
||||
|
||||
database.SetFirstLogon(CharacterID(), 0); //We change firstlogon status regardless of if a player logs out to zone or not, because we only want to trigger it on their first login from world.
|
||||
|
||||
//remove ourself from all proximities
|
||||
/* Remove ourself from all proximities */
|
||||
ClearAllProximities();
|
||||
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_LogoutReply);
|
||||
@@ -983,17 +987,18 @@ 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(GetLevel() < ml.level_required) {
|
||||
if (merch->CastToNPC()->GetMerchantProbability() > ml.probability)
|
||||
continue;
|
||||
|
||||
if(GetLevel() < ml.level_required)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(ml.classes_required & (1 << (GetClass() - 1))))
|
||||
continue;
|
||||
|
||||
int32 fac = merch ? merch->GetPrimaryFaction() : 0;
|
||||
if(fac != 0 && GetModCharacterFactionLevel(fac) < ml.faction_required) {
|
||||
if(fac != 0 && GetModCharacterFactionLevel(fac) < ml.faction_required)
|
||||
continue;
|
||||
}
|
||||
|
||||
handychance = MakeRandomInt(0, merlist.size() + tmp_merlist.size() - 1 );
|
||||
|
||||
|
||||
+13
-6
@@ -47,10 +47,10 @@
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/serverinfo.h"
|
||||
#include "../common/opcodemgr.h"
|
||||
#include "../common/EQPacket.h"
|
||||
#include "../common/eq_packet.h"
|
||||
#include "../common/guilds.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
//#include "../common/servertalk.h" // for oocmute and revoke
|
||||
#include "worldserver.h"
|
||||
#include "masterentity.h"
|
||||
@@ -62,17 +62,18 @@
|
||||
#include "guild_mgr.h"
|
||||
#include "titles.h"
|
||||
#include "../common/patches/patches.h"
|
||||
#include "queryserv.h"
|
||||
|
||||
// these should be in the headers...
|
||||
extern QueryServ* QServ;
|
||||
extern WorldServer worldserver;
|
||||
extern TaskManager *taskmanager;
|
||||
void CatchSignal(int sig_num);
|
||||
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
|
||||
#include "StringIDs.h"
|
||||
#include "string_ids.h"
|
||||
#include "command.h"
|
||||
#include "QGlobals.h"
|
||||
#include "qglobals.h"
|
||||
|
||||
//struct cl_struct *commandlist; // the actual linked list of commands
|
||||
int commandcount; // how many commands we have
|
||||
@@ -588,6 +589,12 @@ int command_realdispatch(Client *c, const char *message)
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* QS: Player_Log_Issued_Commands */
|
||||
if (RuleB(QueryServ, PlayerLogIssuedCommandes)){
|
||||
std::string event_desc = StringFormat("Issued command :: '%s' in zoneid:%i instid:%i", message, c->GetZoneID(), c->GetInstanceID());
|
||||
QServ->PlayerLogEvent(Player_Log_Issued_Commands, c->CharacterID(), event_desc);
|
||||
}
|
||||
|
||||
#ifdef COMMANDS_LOGGING
|
||||
if(cur->access >= COMMANDS_LOGGING_MIN_STATUS) {
|
||||
LogFile->write(EQEMuLog::Commands, "%s (%s) used command: %s (target=%s)", c->GetName(), c->AccountName(), message, c->GetTarget()?c->GetTarget()->GetName():"NONE");
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
#define COMMAND_H
|
||||
|
||||
#include "../common/seperator.h"
|
||||
#include "../common/EQStream.h"
|
||||
#include "../common/eq_stream.h"
|
||||
#include "client.h"
|
||||
|
||||
#define COMMAND_CHAR '#'
|
||||
|
||||
+7
-6
@@ -127,7 +127,8 @@ enum {
|
||||
FLEE_PERCENT = 37,
|
||||
ALLOW_BENEFICIAL = 38,
|
||||
DISABLE_MELEE = 39,
|
||||
MAX_SPECIAL_ATTACK = 40
|
||||
NPC_CHASE_DISTANCE = 40,
|
||||
MAX_SPECIAL_ATTACK = 41
|
||||
|
||||
};
|
||||
|
||||
@@ -368,10 +369,10 @@ struct StatBonuses {
|
||||
bool NegateIfCombat; // Bool Drop buff if cast or melee
|
||||
int8 Screech; // -1 = Will be blocked if another Screech is +(1)
|
||||
int16 AlterNPCLevel; // amount of lvls +/-
|
||||
int16 AStacker[1]; // For buff stack blocking 0=Exists 1=Effect_value
|
||||
int16 BStacker[1]; // For buff stack blocking 0=Exists 1=Effect_value
|
||||
int16 CStacker[1]; // For buff stack blocking 0=Exists 1=Effect_value
|
||||
int16 DStacker[1]; // For buff stack blocking 0=Exists 1=Effect_value
|
||||
int16 AStacker[2]; // For buff stack blocking 0=Exists 1=Effect_value
|
||||
int16 BStacker[2]; // For buff stack blocking 0=Exists 1=Effect_value
|
||||
int16 CStacker[2]; // For buff stack blocking 0=Exists 1=Effect_value
|
||||
int16 DStacker[2]; // For buff stack blocking 0=Exists 1=Effect_value
|
||||
bool BerserkSPA; // berserk effect
|
||||
int16 Metabolism; // Food/drink consumption rates.
|
||||
bool Sanctuary; // Sanctuary effect, lowers place on hate list until cast on others.
|
||||
@@ -526,7 +527,7 @@ public:
|
||||
Mob* With();
|
||||
|
||||
// Add item from cursor slot to trade bucket (automatically does bag data too)
|
||||
void AddEntity(uint16 from_slot_id, uint16 trade_slot_id);
|
||||
void AddEntity(uint16 trade_slot_id, uint32 stack_size);
|
||||
|
||||
// Audit trade
|
||||
void LogTrade();
|
||||
|
||||
+3
-3
@@ -35,12 +35,12 @@ Child of the Mob class.
|
||||
|
||||
#include "masterentity.h"
|
||||
#include "../common/packet_functions.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/crc32.h"
|
||||
#include "StringIDs.h"
|
||||
#include "string_ids.h"
|
||||
#include "worldserver.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
|
||||
extern EntityList entity_list;
|
||||
extern Zone* zone;
|
||||
|
||||
+109
-130
@@ -21,11 +21,11 @@
|
||||
#include <string.h>
|
||||
#include "masterentity.h"
|
||||
#include "worldserver.h"
|
||||
#include "StringIDs.h"
|
||||
#include "string_ids.h"
|
||||
#include "zonedb.h"
|
||||
#include "../common/packet_functions.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "guild_mgr.h"
|
||||
|
||||
#define OPEN_DOOR 0x02
|
||||
@@ -253,8 +253,7 @@ void Doors::HandleClick(Client* sender, uint8 trigger)
|
||||
strcpy(tmpmsg, "Door is locked by an unknown guild");
|
||||
}
|
||||
sender->Message(4, tmpmsg);
|
||||
// safe_delete(outapp);
|
||||
// /\ possible missing line..all other 'fail' returns seem to have it
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
// a key is required or the door is locked but can be picked or both
|
||||
@@ -569,157 +568,137 @@ void Doors::DumpDoor(){
|
||||
}
|
||||
|
||||
int32 ZoneDatabase::GetDoorsCount(uint32* oMaxID, const char *zone_name, int16 version) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
query = new char[256];
|
||||
sprintf(query, "SELECT MAX(id), count(*) FROM doors WHERE zone='%s' AND (version=%u OR version=-1)", zone_name, version);
|
||||
if (RunQuery(query, strlen(query), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
row = mysql_fetch_row(result);
|
||||
if (row != nullptr && row[1] != 0) {
|
||||
int32 ret = atoi(row[1]);
|
||||
if (oMaxID) {
|
||||
if (row[0])
|
||||
*oMaxID = atoi(row[0]);
|
||||
else
|
||||
*oMaxID = 0;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
return ret;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
std::cerr << "Error in GetDoorsCount query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT MAX(id), count(*) FROM doors "
|
||||
"WHERE zone = '%s' AND (version = %u OR version = -1)",
|
||||
zone_name, version);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
std::cerr << "Error in GetDoorsCount query '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return -1;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
if (!oMaxID)
|
||||
return atoi(row[1]);
|
||||
|
||||
if (row[0])
|
||||
*oMaxID = atoi(row[0]);
|
||||
else
|
||||
*oMaxID = 0;
|
||||
|
||||
return atoi(row[1]);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32 ZoneDatabase::GetDoorsCountPlusOne(const char *zone_name, int16 version) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
uint32 oMaxID = 0;
|
||||
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
query = new char[256];
|
||||
sprintf(query, "SELECT MAX(id) FROM doors WHERE zone='%s' AND version=%u", zone_name, version);
|
||||
if (RunQuery(query, strlen(query), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
row = mysql_fetch_row(result);
|
||||
if (row != nullptr && row[1] != 0) {
|
||||
if (row[0])
|
||||
oMaxID = atoi(row[0]) + 1;
|
||||
else
|
||||
oMaxID = 0;
|
||||
mysql_free_result(result);
|
||||
return oMaxID;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
std::cerr << "Error in GetDoorsCountPlusOne query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT MAX(id) FROM doors "
|
||||
"WHERE zone = '%s' AND version = %u", zone_name, version);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
std::cerr << "Error in GetDoorsCountPlusOne query '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
if (results.RowCount() != 1)
|
||||
return -1;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
if (!row[0])
|
||||
return 0;
|
||||
|
||||
return atoi(row[0]) + 1;
|
||||
}
|
||||
|
||||
int32 ZoneDatabase::GetDoorsDBCountPlusOne(const char *zone_name, int16 version) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
|
||||
uint32 oMaxID = 0;
|
||||
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
query = new char[256];
|
||||
sprintf(query, "SELECT MAX(doorid) FROM doors WHERE zone='%s' AND (version=%u OR version=-1)", zone_name, version);
|
||||
if (RunQuery(query, strlen(query), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
row = mysql_fetch_row(result);
|
||||
if (row != nullptr && row[1] != 0) {
|
||||
if (row[0])
|
||||
oMaxID = atoi(row[0]) + 1;
|
||||
else
|
||||
oMaxID = 0;
|
||||
mysql_free_result(result);
|
||||
return oMaxID;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
std::cerr << "Error in GetDoorsCountPlusOne query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT MAX(doorid) FROM doors "
|
||||
"WHERE zone = '%s' AND (version = %u OR version = -1)",
|
||||
zone_name, version);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
std::cerr << "Error in GetDoorsCountPlusOne query '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
if (results.RowCount() != 1)
|
||||
return -1;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
if (!row[0])
|
||||
return 0;
|
||||
|
||||
return atoi(row[0]) + 1;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadDoors(int32 iDoorCount, Door *into, const char *zone_name, int16 version) {
|
||||
LogFile->write(EQEMuLog::Status, "Loading Doors from database...");
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
|
||||
// Door tmpDoor;
|
||||
MakeAnyLenString(&query, "SELECT id,doorid,zone,name,pos_x,pos_y,pos_z,heading,"
|
||||
"opentype,guild,lockpick,keyitem,nokeyring,triggerdoor,triggertype,dest_zone,dest_instance,dest_x,"
|
||||
"dest_y,dest_z,dest_heading,door_param,invert_state,incline,size,is_ldon_door,client_version_mask "
|
||||
"FROM doors WHERE zone='%s' AND (version=%u OR version=-1) ORDER BY doorid asc", zone_name, version);
|
||||
if (RunQuery(query, strlen(query), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
int32 r;
|
||||
for(r = 0; (row = mysql_fetch_row(result)); r++) {
|
||||
if(r >= iDoorCount) {
|
||||
std::cerr << "Error, Door Count of " << iDoorCount << " exceeded." << std::endl;
|
||||
break;
|
||||
}
|
||||
memset(&into[r], 0, sizeof(Door));
|
||||
into[r].db_id = atoi(row[0]);
|
||||
into[r].door_id = atoi(row[1]);
|
||||
strn0cpy(into[r].zone_name,row[2],32);
|
||||
strn0cpy(into[r].door_name,row[3],32);
|
||||
into[r].pos_x = (float)atof(row[4]);
|
||||
into[r].pos_y = (float)atof(row[5]);
|
||||
into[r].pos_z = (float)atof(row[6]);
|
||||
into[r].heading = (float)atof(row[7]);
|
||||
into[r].opentype = atoi(row[8]);
|
||||
into[r].guild_id = atoi(row[9]);
|
||||
into[r].lockpick = atoi(row[10]);
|
||||
into[r].keyitem = atoi(row[11]);
|
||||
into[r].nokeyring = atoi(row[12]);
|
||||
into[r].trigger_door = atoi(row[13]);
|
||||
into[r].trigger_type = atoi(row[14]);
|
||||
strn0cpy(into[r].dest_zone, row[15], 32);
|
||||
into[r].dest_instance_id = atoi(row[16]);
|
||||
into[r].dest_x = (float) atof(row[17]);
|
||||
into[r].dest_y = (float) atof(row[18]);
|
||||
into[r].dest_z = (float) atof(row[19]);
|
||||
into[r].dest_heading = (float) atof(row[20]);
|
||||
into[r].door_param=atoi(row[21]);
|
||||
into[r].invert_state=atoi(row[22]);
|
||||
into[r].incline=atoi(row[23]);
|
||||
into[r].size=atoi(row[24]);
|
||||
into[r].is_ldon_door=atoi(row[25]);
|
||||
into[r].client_version_mask = (uint32)strtoul(row[26], nullptr, 10);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error in DBLoadDoors query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT id, doorid, zone, name, pos_x, pos_y, pos_z, heading, "
|
||||
"opentype, guild, lockpick, keyitem, nokeyring, triggerdoor, triggertype, "
|
||||
"dest_zone, dest_instance, dest_x, dest_y, dest_z, dest_heading, "
|
||||
"door_param, invert_state, incline, size, is_ldon_door, client_version_mask "
|
||||
"FROM doors WHERE zone = '%s' AND (version = %u OR version = -1) "
|
||||
"ORDER BY doorid asc", zone_name, version);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()){
|
||||
std::cerr << "Error in DBLoadDoors query '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 rowIndex = 0;
|
||||
for(auto row = results.begin(); row != results.end(); ++row, ++rowIndex) {
|
||||
if(rowIndex >= iDoorCount) {
|
||||
std::cerr << "Error, Door Count of " << iDoorCount << " exceeded." << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
memset(&into[rowIndex], 0, sizeof(Door));
|
||||
|
||||
into[rowIndex].db_id = atoi(row[0]);
|
||||
into[rowIndex].door_id = atoi(row[1]);
|
||||
|
||||
strn0cpy(into[rowIndex].zone_name,row[2],32);
|
||||
strn0cpy(into[rowIndex].door_name,row[3],32);
|
||||
|
||||
into[rowIndex].pos_x = (float)atof(row[4]);
|
||||
into[rowIndex].pos_y = (float)atof(row[5]);
|
||||
into[rowIndex].pos_z = (float)atof(row[6]);
|
||||
into[rowIndex].heading = (float)atof(row[7]);
|
||||
into[rowIndex].opentype = atoi(row[8]);
|
||||
into[rowIndex].guild_id = atoi(row[9]);
|
||||
into[rowIndex].lockpick = atoi(row[10]);
|
||||
into[rowIndex].keyitem = atoi(row[11]);
|
||||
into[rowIndex].nokeyring = atoi(row[12]);
|
||||
into[rowIndex].trigger_door = atoi(row[13]);
|
||||
into[rowIndex].trigger_type = atoi(row[14]);
|
||||
|
||||
strn0cpy(into[rowIndex].dest_zone, row[15], 32);
|
||||
|
||||
into[rowIndex].dest_instance_id = atoi(row[16]);
|
||||
into[rowIndex].dest_x = (float) atof(row[17]);
|
||||
into[rowIndex].dest_y = (float) atof(row[18]);
|
||||
into[rowIndex].dest_z = (float) atof(row[19]);
|
||||
into[rowIndex].dest_heading = (float) atof(row[20]);
|
||||
into[rowIndex].door_param=atoi(row[21]);
|
||||
into[rowIndex].invert_state=atoi(row[22]);
|
||||
into[rowIndex].incline=atoi(row[23]);
|
||||
into[rowIndex].size=atoi(row[24]);
|
||||
into[rowIndex].is_ldon_door=atoi(row[25]);
|
||||
into[rowIndex].client_version_mask = (uint32)strtoul(row[26], nullptr, 10);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -24,11 +24,11 @@
|
||||
#include "../common/packet_functions.h"
|
||||
#include "petitions.h"
|
||||
#include "../common/serverinfo.h"
|
||||
#include "../common/ZoneNumbers.h"
|
||||
#include "../common/zone_numbers.h"
|
||||
#include "../common/moremath.h"
|
||||
#include "../common/guilds.h"
|
||||
#include "StringIDs.h"
|
||||
#include "NpcAI.h"
|
||||
#include "string_ids.h"
|
||||
#include "npc_ai.h"
|
||||
|
||||
float Client::GetActSpellRange(uint16 spell_id, float range, bool IsBard)
|
||||
{
|
||||
|
||||
+3
-3
@@ -20,13 +20,13 @@
|
||||
|
||||
#include "../common/debug.h"
|
||||
#include "../common/seperator.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/features.h"
|
||||
#include "masterentity.h"
|
||||
#include "embparser.h"
|
||||
#include "questmgr.h"
|
||||
#include "QGlobals.h"
|
||||
#include "qglobals.h"
|
||||
#include "zone.h"
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
+2
-2
@@ -20,8 +20,8 @@
|
||||
#define EQMEU_EMBPARSER_H
|
||||
#ifdef EMBPERL
|
||||
|
||||
#include "QuestParserCollection.h"
|
||||
#include "QuestInterface.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "quest_interface.h"
|
||||
#include <string>
|
||||
#include <queue>
|
||||
#include <map>
|
||||
|
||||
+35
-1
@@ -22,14 +22,16 @@
|
||||
#ifdef EMBPERL_XS
|
||||
|
||||
#include "../common/debug.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "embparser.h"
|
||||
#include "questmgr.h"
|
||||
#include "embxs.h"
|
||||
#include "entity.h"
|
||||
#include "zone.h"
|
||||
#include "queryserv.h"
|
||||
|
||||
extern Zone* zone;
|
||||
extern QueryServ* QServ;
|
||||
|
||||
/*
|
||||
|
||||
@@ -3370,6 +3372,36 @@ XS(XS__clear_npctype_cache)
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__qs_send_query);
|
||||
XS(XS__qs_send_query)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 1){
|
||||
Perl_croak(aTHX_ "Usage: qs_send_query(query)");
|
||||
}
|
||||
else{
|
||||
// char *Query = (char *)SvPV_nolen(ST(0));
|
||||
std::string Query = (std::string)SvPV_nolen(ST(0));
|
||||
QServ->SendQuery(Query);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__qs_player_event);
|
||||
XS(XS__qs_player_event)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2){
|
||||
Perl_croak(aTHX_ "Usage: qs_player_event(char_id, event_desc)");
|
||||
}
|
||||
else{
|
||||
int char_id = (int)SvIV(ST(0));
|
||||
std::string event_desc = (std::string)SvPV_nolen(ST(1));
|
||||
QServ->PlayerLogEvent(Player_Log_Quest, char_id, event_desc);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
/*
|
||||
This is the callback perl will look for to setup the
|
||||
quest package's XSUBs
|
||||
@@ -3591,6 +3623,8 @@ EXTERN_C XS(boot_quest)
|
||||
newXS(strcpy(buf, "enablerecipe"), XS__enablerecipe, file);
|
||||
newXS(strcpy(buf, "disablerecipe"), XS__disablerecipe, file);
|
||||
newXS(strcpy(buf, "clear_npctype_cache"), XS__clear_npctype_cache, file);
|
||||
newXS(strcpy(buf, "qs_send_query"), XS__qs_send_query, file);
|
||||
newXS(strcpy(buf, "qs_player_event"), XS__qs_player_event, file);
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
|
||||
+18
-3
@@ -39,11 +39,11 @@
|
||||
#include "petitions.h"
|
||||
#include "../common/spdat.h"
|
||||
#include "../common/features.h"
|
||||
#include "StringIDs.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/dbasync.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "raids.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define snprintf _snprintf
|
||||
@@ -622,6 +622,7 @@ void EntityList::AddCorpse(Corpse *corpse, uint32 in_id)
|
||||
void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
|
||||
{
|
||||
npc->SetID(GetFreeID());
|
||||
npc->SetMerchantProbability((uint8) MakeRandomInt(0, 99));
|
||||
parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0);
|
||||
|
||||
uint16 emoteid = npc->GetEmoteID();
|
||||
@@ -1597,7 +1598,7 @@ Corpse *EntityList::GetCorpseByName(const char *name)
|
||||
|
||||
Spawn2 *EntityList::GetSpawnByID(uint32 id)
|
||||
{
|
||||
if (!zone)
|
||||
if (!zone || !zone->IsLoaded())
|
||||
return nullptr;
|
||||
|
||||
LinkedListIterator<Spawn2 *> iterator(zone->spawn2_list);
|
||||
@@ -4169,6 +4170,20 @@ void EntityList::SignalAllClients(uint32 data)
|
||||
}
|
||||
}
|
||||
|
||||
uint16 EntityList::GetClientCount(){
|
||||
uint16 ClientCount = 0;
|
||||
std::list<Client*> client_list;
|
||||
entity_list.GetClientList(client_list);
|
||||
std::list<Client*>::iterator iter = client_list.begin();
|
||||
while (iter != client_list.end()) {
|
||||
Client *entry = (*iter);
|
||||
entry->GetCleanName();
|
||||
ClientCount++;
|
||||
iter++;
|
||||
}
|
||||
return ClientCount;
|
||||
}
|
||||
|
||||
void EntityList::GetMobList(std::list<Mob *> &m_list)
|
||||
{
|
||||
m_list.clear();
|
||||
|
||||
+2
-1
@@ -29,7 +29,7 @@
|
||||
#include "zonedb.h"
|
||||
#include "zonedump.h"
|
||||
#include "zonedbasync.h"
|
||||
#include "QGlobals.h"
|
||||
#include "qglobals.h"
|
||||
|
||||
class EQApplicationPacket;
|
||||
|
||||
@@ -398,6 +398,7 @@ public:
|
||||
void UpdateFindableNPCState(NPC *n, bool Remove);
|
||||
void HideCorpses(Client *c, uint8 CurrentMode, uint8 NewMode);
|
||||
|
||||
uint16 GetClientCount();
|
||||
void GetMobList(std::list<Mob*> &m_list);
|
||||
void GetNPCList(std::list<NPC*> &n_list);
|
||||
void GetMercList(std::list<Merc*> &n_list);
|
||||
|
||||
+75
-63
@@ -18,10 +18,13 @@
|
||||
#include "../common/debug.h"
|
||||
#include "../common/features.h"
|
||||
#include "masterentity.h"
|
||||
#include "StringIDs.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "queryserv.h"
|
||||
|
||||
extern QueryServ* QServ;
|
||||
|
||||
|
||||
static uint32 MaxBankedGroupLeadershipPoints(int Level)
|
||||
@@ -48,6 +51,15 @@ static uint32 MaxBankedRaidLeadershipPoints(int Level)
|
||||
|
||||
void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
||||
|
||||
/* Set a timestamp in an entity variable for plugin check_handin.pl in return_items
|
||||
This will stopgap players from items being returned if global_npc.pl has a catch all return_items
|
||||
*/
|
||||
struct timeval read_time;
|
||||
char buffer[50];
|
||||
gettimeofday(&read_time, 0);
|
||||
sprintf(buffer, "%li.%li \n", read_time.tv_sec, read_time.tv_usec);
|
||||
this->SetEntityVariable("Stop_Return", buffer);
|
||||
|
||||
uint32 add_exp = in_add_exp;
|
||||
|
||||
if(!resexp && (XPRate != 0))
|
||||
@@ -203,7 +215,6 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
return; // Must be invalid class/race
|
||||
}
|
||||
|
||||
|
||||
if ((set_exp + set_aaxp) > (m_pp.exp+m_pp.expAA)) {
|
||||
if (isrezzexp)
|
||||
this->Message_StringID(MT_Experience, REZ_REGAIN);
|
||||
@@ -279,6 +290,14 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
//Message(15, "You have gained %d skill points!!", m_pp.aapoints - last_unspentAA);
|
||||
char val1[20]={0};
|
||||
Message_StringID(MT_Experience, GAIN_ABILITY_POINT,ConvertArray(m_pp.aapoints, val1),m_pp.aapoints == 1 ? "" : "(s)"); //You have gained an ability point! You now have %1 ability point%2.
|
||||
|
||||
/* QS: PlayerLogAARate */
|
||||
if (RuleB(QueryServ, PlayerLogAARate)){
|
||||
int add_points = (m_pp.aapoints - last_unspentAA);
|
||||
std::string query = StringFormat("INSERT INTO `qs_player_aa_rate_hourly` (char_id, aa_count, hour_time) VALUES (%i, %i, UNIX_TIMESTAMP() - MOD(UNIX_TIMESTAMP(), 3600)) ON DUPLICATE KEY UPDATE `aa_count` = `aa_count` + %i", this->CharacterID(), add_points, add_points);
|
||||
QServ->SendQuery(query.c_str());
|
||||
}
|
||||
|
||||
//Message(15, "You now have %d skill points available to spend.", m_pp.aapoints);
|
||||
}
|
||||
|
||||
@@ -290,12 +309,10 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
if(check_level > maxlevel) {
|
||||
check_level = maxlevel;
|
||||
|
||||
if(RuleB(Character, KeepLevelOverMax))
|
||||
{
|
||||
if(RuleB(Character, KeepLevelOverMax)) {
|
||||
set_exp = GetEXPForLevel(GetLevel()+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
set_exp = GetEXPForLevel(maxlevel);
|
||||
}
|
||||
}
|
||||
@@ -305,8 +322,7 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
if(MaxLevel){
|
||||
if(GetLevel() >= MaxLevel){
|
||||
uint32 expneeded = GetEXPForLevel(MaxLevel);
|
||||
if(set_exp > expneeded)
|
||||
{
|
||||
if(set_exp > expneeded) {
|
||||
set_exp = expneeded;
|
||||
}
|
||||
}
|
||||
@@ -318,11 +334,11 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
if (GetLevel() == check_level-1){
|
||||
Message_StringID(MT_Experience, GAIN_LEVEL,ConvertArray(check_level,val1));
|
||||
SendLevelAppearance();
|
||||
//Message(15, "You have gained a level! Welcome to level %i!", check_level);
|
||||
/* Message(15, "You have gained a level! Welcome to level %i!", check_level); */
|
||||
}
|
||||
if (GetLevel() == check_level){
|
||||
Message_StringID(MT_Experience, LOSE_LEVEL,ConvertArray(check_level,val1));
|
||||
//Message(15, "You lost a level! You are now level %i!", check_level);
|
||||
/* Message(15, "You lost a level! You are now level %i!", check_level); */
|
||||
}
|
||||
else
|
||||
Message(15, "Welcome to level %i!", check_level);
|
||||
@@ -343,8 +359,7 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
//If were at max level then stop gaining experience if we make it to the cap
|
||||
if(GetLevel() == maxlevel - 1){
|
||||
uint32 expneeded = GetEXPForLevel(maxlevel);
|
||||
if(set_exp > expneeded)
|
||||
{
|
||||
if(set_exp > expneeded) {
|
||||
set_exp = expneeded;
|
||||
}
|
||||
}
|
||||
@@ -396,15 +411,13 @@ void Client::SetLevel(uint8 set_level, bool command)
|
||||
|
||||
level = set_level;
|
||||
|
||||
if(IsRaidGrouped())
|
||||
{
|
||||
if(IsRaidGrouped()) {
|
||||
Raid *r = this->GetRaid();
|
||||
if(r){
|
||||
r->UpdateLevel(GetName(), set_level);
|
||||
}
|
||||
}
|
||||
if(set_level > m_pp.level2)
|
||||
{
|
||||
if(set_level > m_pp.level2) {
|
||||
if(m_pp.level2 == 0)
|
||||
m_pp.points += 5;
|
||||
else
|
||||
@@ -414,6 +427,18 @@ void Client::SetLevel(uint8 set_level, bool command)
|
||||
}
|
||||
if(set_level > m_pp.level) {
|
||||
parse->EventPlayer(EVENT_LEVEL_UP, this, "", 0);
|
||||
/* QS: PlayerLogLevels */
|
||||
if (RuleB(QueryServ, PlayerLogLevels)){
|
||||
std::string event_desc = StringFormat("Leveled UP :: to Level:%i from Level:%i in zoneid:%i instid:%i", set_level, m_pp.level, this->GetZoneID(), this->GetInstanceID());
|
||||
QServ->PlayerLogEvent(Player_Log_Levels, this->CharacterID(), event_desc);
|
||||
}
|
||||
}
|
||||
else if (set_level < m_pp.level){
|
||||
/* QS: PlayerLogLevels */
|
||||
if (RuleB(QueryServ, PlayerLogLevels)){
|
||||
std::string event_desc = StringFormat("Leveled DOWN :: to Level:%i from Level:%i in zoneid:%i instid:%i", set_level, m_pp.level, this->GetZoneID(), this->GetInstanceID());
|
||||
QServ->PlayerLogEvent(Player_Log_Levels, this->CharacterID(), event_desc);
|
||||
}
|
||||
}
|
||||
|
||||
m_pp.level = set_level;
|
||||
@@ -423,34 +448,34 @@ void Client::SetLevel(uint8 set_level, bool command)
|
||||
lu->exp = 0;
|
||||
}
|
||||
else {
|
||||
float tmpxp = (float) ( (float) m_pp.exp - GetEXPForLevel( GetLevel() )) /
|
||||
( (float) GetEXPForLevel(GetLevel()+1) - GetEXPForLevel(GetLevel()));
|
||||
float tmpxp = (float) ( (float) m_pp.exp - GetEXPForLevel( GetLevel() )) / ( (float) GetEXPForLevel(GetLevel()+1) - GetEXPForLevel(GetLevel()));
|
||||
lu->exp = (uint32)(330.0f * tmpxp);
|
||||
}
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
this->SendAppearancePacket(AT_WhoLevel, set_level); // who level change
|
||||
|
||||
LogFile->write(EQEMuLog::Normal,"Setting Level for %s to %i", GetName(), set_level);
|
||||
LogFile->write(EQEMuLog::Normal,"Setting Level for %s to %i", GetName(), set_level);
|
||||
|
||||
CalcBonuses();
|
||||
if(!RuleB(Character, HealOnLevel))
|
||||
{
|
||||
|
||||
if(!RuleB(Character, HealOnLevel)) {
|
||||
int mhp = CalcMaxHP();
|
||||
if(GetHP() > mhp)
|
||||
SetHP(mhp);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
SetHP(CalcMaxHP()); // Why not, lets give them a free heal
|
||||
}
|
||||
|
||||
DoTributeUpdate();
|
||||
DoTributeUpdate();
|
||||
SendHPUpdate();
|
||||
SetMana(CalcMaxMana());
|
||||
UpdateWho();
|
||||
if(GetMerc())
|
||||
UpdateMercLevel();
|
||||
|
||||
if(GetMerc())
|
||||
UpdateMercLevel();
|
||||
|
||||
Save();
|
||||
}
|
||||
|
||||
@@ -499,23 +524,13 @@ uint32 Client::GetEXPForLevel(uint16 check_level)
|
||||
uint32 finalxp = uint32(base * mod);
|
||||
finalxp = mod_client_xp_for_level(finalxp, check_level);
|
||||
|
||||
return(finalxp);
|
||||
return finalxp;
|
||||
}
|
||||
|
||||
void Client::AddLevelBasedExp(uint8 exp_percentage, uint8 max_level) {
|
||||
|
||||
if (exp_percentage > 100)
|
||||
{
|
||||
exp_percentage = 100;
|
||||
}
|
||||
|
||||
if (!max_level || GetLevel() < max_level)
|
||||
{
|
||||
max_level = GetLevel();
|
||||
}
|
||||
|
||||
uint32 newexp = GetEXP() + ((GetEXPForLevel(max_level + 1) - GetEXPForLevel(max_level)) * exp_percentage / 100);
|
||||
|
||||
void Client::AddLevelBasedExp(uint8 exp_percentage, uint8 max_level) {
|
||||
if (exp_percentage > 100) { exp_percentage = 100; }
|
||||
if (!max_level || GetLevel() < max_level) { max_level = GetLevel(); }
|
||||
uint32 newexp = GetEXP() + ((GetEXPForLevel(max_level + 1) - GetEXPForLevel(max_level)) * exp_percentage / 100);
|
||||
SetEXP(newexp, GetAAXP());
|
||||
}
|
||||
|
||||
@@ -657,28 +672,25 @@ void Client::SendLeadershipEXPUpdate() {
|
||||
}
|
||||
|
||||
uint32 Client::GetCharMaxLevelFromQGlobal() {
|
||||
QGlobalCache *char_c = nullptr;
|
||||
char_c = this->GetQGlobals();
|
||||
|
||||
QGlobalCache *char_c = nullptr;
|
||||
char_c = this->GetQGlobals();
|
||||
std::list<QGlobal> globalMap;
|
||||
uint32 ntype = 0;
|
||||
|
||||
std::list<QGlobal> globalMap;
|
||||
uint32 ntype = 0;
|
||||
if(char_c) {
|
||||
QGlobalCache::Combine(globalMap, char_c->GetBucket(), ntype, this->CharacterID(), zone->GetZoneID());
|
||||
}
|
||||
|
||||
if(char_c)
|
||||
{
|
||||
QGlobalCache::Combine(globalMap, char_c->GetBucket(), ntype, this->CharacterID(), zone->GetZoneID());
|
||||
}
|
||||
std::list<QGlobal>::iterator iter = globalMap.begin();
|
||||
uint32 gcount = 0;
|
||||
while(iter != globalMap.end()) {
|
||||
if((*iter).name.compare("CharMaxLevel") == 0){
|
||||
return atoi((*iter).value.c_str());
|
||||
}
|
||||
++iter;
|
||||
++gcount;
|
||||
}
|
||||
|
||||
std::list<QGlobal>::iterator iter = globalMap.begin();
|
||||
uint32 gcount = 0;
|
||||
while(iter != globalMap.end())
|
||||
{
|
||||
if((*iter).name.compare("CharMaxLevel") == 0){
|
||||
return atoi((*iter).value.c_str());
|
||||
}
|
||||
++iter;
|
||||
++gcount;
|
||||
}
|
||||
|
||||
return false; // Default is false
|
||||
return false;
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
#include <cstdlib>
|
||||
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "map.h"
|
||||
#include "zone.h"
|
||||
#include "pathing.h"
|
||||
|
||||
+58
-68
@@ -30,9 +30,9 @@
|
||||
#include "npc.h"
|
||||
#include "water_map.h"
|
||||
#include "titles.h"
|
||||
#include "StringIDs.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/rulesys.h"
|
||||
|
||||
#include "zonedb.h"
|
||||
@@ -40,7 +40,7 @@
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
|
||||
//max number of items which can be in the foraging table
|
||||
//for a given zone.
|
||||
@@ -85,12 +85,7 @@ CREATE TABLE fishing (
|
||||
|
||||
// This allows EqEmu to have zone specific foraging - BoB
|
||||
uint32 ZoneDatabase::GetZoneForage(uint32 ZoneID, uint8 skill) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
uint8 index = 0;
|
||||
uint32 item[FORAGE_ITEM_LIMIT];
|
||||
uint32 chance[FORAGE_ITEM_LIMIT];
|
||||
uint32 ret;
|
||||
@@ -100,31 +95,32 @@ uint32 ZoneDatabase::GetZoneForage(uint32 ZoneID, uint8 skill) {
|
||||
}
|
||||
|
||||
uint32 chancepool = 0;
|
||||
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT itemid,chance FROM forage WHERE zoneid= '%i' and level <= '%i' LIMIT %i", ZoneID, skill, FORAGE_ITEM_LIMIT), errbuf, &result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
while ((row = mysql_fetch_row(result)) && (index < FORAGE_ITEM_LIMIT)) {
|
||||
item[index] = atoi(row[0]);
|
||||
chance[index] = atoi(row[1])+chancepool;
|
||||
LogFile->write(EQEMuLog::Error, "Possible Forage: %d with a %d chance", item[index], chance[index]);
|
||||
chancepool = chance[index];
|
||||
index++;
|
||||
}
|
||||
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in Forage query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT itemid, chance FROM "
|
||||
"forage WHERE zoneid = '%i' and level <= '%i' "
|
||||
"LIMIT %i", ZoneID, skill, FORAGE_ITEM_LIMIT);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in Forage query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 index = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row, ++index) {
|
||||
if (index >= FORAGE_ITEM_LIMIT)
|
||||
break;
|
||||
|
||||
item[index] = atoi(row[0]);
|
||||
chance[index] = atoi(row[1]) + chancepool;
|
||||
LogFile->write(EQEMuLog::Error, "Possible Forage: %d with a %d chance", item[index], chance[index]);
|
||||
chancepool = chance[index];
|
||||
}
|
||||
|
||||
|
||||
if(chancepool == 0 || index < 1)
|
||||
return(0);
|
||||
return 0;
|
||||
|
||||
if(index == 1) {
|
||||
return(item[0]);
|
||||
return item[0];
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
@@ -143,12 +139,6 @@ LogFile->write(EQEMuLog::Error, "Possible Forage: %d with a %d chance", item[ind
|
||||
|
||||
uint32 ZoneDatabase::GetZoneFishing(uint32 ZoneID, uint8 skill, uint32 &npc_id, uint8 &npc_chance)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
uint8 index = 0;
|
||||
uint32 item[50];
|
||||
uint32 chance[50];
|
||||
uint32 npc_ids[50];
|
||||
@@ -161,44 +151,44 @@ uint32 ZoneDatabase::GetZoneFishing(uint32 ZoneID, uint8 skill, uint32 &npc_id,
|
||||
chance[c]=0;
|
||||
}
|
||||
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT itemid,chance,npc_id,npc_chance FROM fishing WHERE (zoneid= '%i' || zoneid = 0) and skill_level <= '%i'",ZoneID, skill ), errbuf, &result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
while ((row = mysql_fetch_row(result))&&(index<50)) {
|
||||
item[index] = atoi(row[0]);
|
||||
chance[index] = atoi(row[1])+chancepool;
|
||||
chancepool = chance[index];
|
||||
|
||||
npc_ids[index] = atoi(row[2]);
|
||||
npc_chances[index] = atoi(row[3]);
|
||||
index++;
|
||||
}
|
||||
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
std::cerr << "Error in Fishing query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT itemid, chance, npc_id, npc_chance "
|
||||
"FROM fishing WHERE (zoneid = '%i' || zoneid = 0) AND skill_level <= '%i'",
|
||||
ZoneID, skill);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
std::cerr << "Error in Fishing query '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 index = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row, ++index) {
|
||||
if (index >= 50)
|
||||
break;
|
||||
|
||||
item[index] = atoi(row[0]);
|
||||
chance[index] = atoi(row[1])+chancepool;
|
||||
chancepool = chance[index];
|
||||
|
||||
npc_ids[index] = atoi(row[2]);
|
||||
npc_chances[index] = atoi(row[3]);
|
||||
}
|
||||
|
||||
npc_id = 0;
|
||||
npc_chance = 0;
|
||||
if (index>0) {
|
||||
uint32 random = MakeRandomInt(1, chancepool);
|
||||
for (int i = 0; i < index; i++)
|
||||
{
|
||||
if (random <= chance[i])
|
||||
{
|
||||
ret = item[i];
|
||||
npc_id = npc_ids[i];
|
||||
npc_chance = npc_chances[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
if (index <= 0)
|
||||
return 0;
|
||||
|
||||
uint32 random = MakeRandomInt(1, chancepool);
|
||||
for (int i = 0; i < index; i++)
|
||||
{
|
||||
if (random > chance[i])
|
||||
continue;
|
||||
|
||||
ret = item[i];
|
||||
npc_id = npc_ids[i];
|
||||
npc_chance = npc_chances[i];
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+6
-7
@@ -17,10 +17,10 @@
|
||||
*/
|
||||
#include "../common/debug.h"
|
||||
#include "masterentity.h"
|
||||
#include "NpcAI.h"
|
||||
#include "npc_ai.h"
|
||||
#include "../common/packet_functions.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "worldserver.h"
|
||||
extern EntityList entity_list;
|
||||
extern WorldServer worldserver;
|
||||
@@ -193,11 +193,10 @@ void Group::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinu
|
||||
|
||||
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||
if (members[i] != nullptr && members[i]->IsClient()) { // If Group Member is Client
|
||||
Client *c = members[i]->CastToClient();
|
||||
//I could not get MoneyOnCorpse to work, so we use this
|
||||
c->AddMoneyToPP(cpsplit, spsplit, gpsplit, ppsplit, true);
|
||||
|
||||
c->Message(2, msg.c_str());
|
||||
Client *c = members[i]->CastToClient();
|
||||
//I could not get MoneyOnCorpse to work, so we use this
|
||||
c->AddMoneyToPP(cpsplit, spsplit, gpsplit, ppsplit, true);
|
||||
c->Message(2, msg.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -25,13 +25,13 @@
|
||||
#include "../common/packet_functions.h"
|
||||
#include "petitions.h"
|
||||
#include "../common/serverinfo.h"
|
||||
#include "../common/ZoneNumbers.h"
|
||||
#include "../common/zone_numbers.h"
|
||||
#include "../common/moremath.h"
|
||||
#include "../common/guilds.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "StringIDs.h"
|
||||
#include "NpcAI.h"
|
||||
#include "string_ids.h"
|
||||
#include "npc_ai.h"
|
||||
|
||||
extern WorldServer worldserver;
|
||||
|
||||
|
||||
+157
-247
@@ -20,7 +20,7 @@
|
||||
#include "zonedb.h"
|
||||
#include "worldserver.h"
|
||||
#include "../common/servertalk.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "client.h"
|
||||
#include "entity.h"
|
||||
|
||||
@@ -644,104 +644,66 @@ GuildBankManager::~GuildBankManager()
|
||||
}
|
||||
}
|
||||
|
||||
bool GuildBankManager::Load(uint32 GuildID)
|
||||
bool GuildBankManager::Load(uint32 guildID)
|
||||
{
|
||||
const char *LoadQuery = "SELECT `area`, `slot`, `itemid`, `qty`, `donator`, `permissions`, `whofor` from `guild_bank` "
|
||||
"WHERE `guildid` = %i";
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char* query = 0;
|
||||
|
||||
MYSQL_RES *result;
|
||||
|
||||
MYSQL_ROW row;
|
||||
|
||||
if(database.RunQuery(query, MakeAnyLenString(&query, LoadQuery, GuildID), errbuf, &result))
|
||||
{
|
||||
GuildBank *Bank = new GuildBank;
|
||||
|
||||
Bank->GuildID = GuildID;
|
||||
|
||||
for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i)
|
||||
Bank->Items.MainArea[i].ItemID = 0;
|
||||
|
||||
for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i)
|
||||
Bank->Items.DepositArea[i].ItemID = 0;
|
||||
|
||||
char Donator[64], WhoFor[64];
|
||||
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
int Area = atoi(row[0]);
|
||||
|
||||
int Slot = atoi(row[1]);
|
||||
|
||||
int ItemID = atoi(row[2]);
|
||||
|
||||
int Qty = atoi(row[3]);
|
||||
|
||||
if(row[4])
|
||||
strn0cpy(Donator, row[4], sizeof(Donator));
|
||||
else
|
||||
Donator[0] = '\0';
|
||||
|
||||
int Permissions = atoi(row[5]);
|
||||
|
||||
if(row[6])
|
||||
strn0cpy(WhoFor, row[6], sizeof(WhoFor));
|
||||
else
|
||||
WhoFor[0] = '\0';
|
||||
|
||||
if(Area == GuildBankMainArea)
|
||||
{
|
||||
if((Slot >= 0) && (Slot < GUILD_BANK_MAIN_AREA_SIZE))
|
||||
{
|
||||
Bank->Items.MainArea[Slot].ItemID = ItemID;
|
||||
|
||||
Bank->Items.MainArea[Slot].Quantity = Qty;
|
||||
|
||||
strn0cpy(Bank->Items.MainArea[Slot].Donator, Donator, sizeof(Donator));
|
||||
|
||||
Bank->Items.MainArea[Slot].Permissions = Permissions;
|
||||
|
||||
strn0cpy(Bank->Items.MainArea[Slot].WhoFor, WhoFor, sizeof(WhoFor));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if((Slot >= 0 ) && (Slot < GUILD_BANK_DEPOSIT_AREA_SIZE))
|
||||
{
|
||||
Bank->Items.DepositArea[Slot].ItemID = ItemID;
|
||||
|
||||
Bank->Items.DepositArea[Slot].Quantity = Qty;
|
||||
|
||||
strn0cpy(Bank->Items.DepositArea[Slot].Donator, Donator, sizeof(Donator));
|
||||
|
||||
Bank->Items.DepositArea[Slot].Permissions = Permissions;
|
||||
|
||||
strn0cpy(Bank->Items.DepositArea[Slot].WhoFor, WhoFor, sizeof(WhoFor));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
mysql_free_result(result);
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
Banks.push_back(Bank);
|
||||
}
|
||||
else
|
||||
{
|
||||
_log(GUILDS__BANK_ERROR, "Error Loading guild bank: %s, %s", query, errbuf);
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
std::string query = StringFormat("SELECT `area`, `slot`, `itemid`, `qty`, `donator`, `permissions`, `whofor` "
|
||||
"FROM `guild_bank` WHERE `guildid` = %i", guildID);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
_log(GUILDS__BANK_ERROR, "Error Loading guild bank: %s, %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
GuildBank *bank = new GuildBank;
|
||||
|
||||
bank->GuildID = guildID;
|
||||
|
||||
for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i)
|
||||
bank->Items.MainArea[i].ItemID = 0;
|
||||
|
||||
for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i)
|
||||
bank->Items.DepositArea[i].ItemID = 0;
|
||||
|
||||
char donator[64], whoFor[64];
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
int area = atoi(row[0]);
|
||||
int slot = atoi(row[1]);
|
||||
int itemID = atoi(row[2]);
|
||||
int qty = atoi(row[3]);
|
||||
|
||||
if(row[4])
|
||||
strn0cpy(donator, row[4], sizeof(donator));
|
||||
else
|
||||
donator[0] = '\0';
|
||||
|
||||
int permissions = atoi(row[5]);
|
||||
|
||||
if(row[6])
|
||||
strn0cpy(whoFor, row[6], sizeof(whoFor));
|
||||
else
|
||||
whoFor[0] = '\0';
|
||||
|
||||
if(slot < 0 ||
|
||||
((area != GuildBankMainArea || slot >= GUILD_BANK_MAIN_AREA_SIZE) ||
|
||||
(area == GuildBankMainArea || slot >= GUILD_BANK_DEPOSIT_AREA_SIZE)))
|
||||
continue;
|
||||
|
||||
bank->Items.MainArea[slot].ItemID = itemID;
|
||||
bank->Items.MainArea[slot].Quantity = qty;
|
||||
|
||||
strn0cpy(bank->Items.MainArea[slot].Donator, donator, sizeof(donator));
|
||||
|
||||
bank->Items.MainArea[slot].Permissions = permissions;
|
||||
|
||||
strn0cpy(bank->Items.MainArea[slot].WhoFor, whoFor, sizeof(whoFor));
|
||||
}
|
||||
|
||||
Banks.push_back(bank);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuildBankManager::IsLoaded(uint32 GuildID)
|
||||
@@ -973,156 +935,127 @@ bool GuildBankManager::AddItem(uint32 GuildID, uint8 Area, uint32 ItemID, int32
|
||||
return true;
|
||||
}
|
||||
|
||||
int GuildBankManager::Promote(uint32 GuildID, int SlotID)
|
||||
int GuildBankManager::Promote(uint32 guildID, int slotID)
|
||||
{
|
||||
if((SlotID < 0) || (SlotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1)))
|
||||
if((slotID < 0) || (slotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1)))
|
||||
return -1;
|
||||
|
||||
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID);
|
||||
auto iter = GetGuildBank(guildID);
|
||||
|
||||
if(Iterator == Banks.end())
|
||||
{
|
||||
if(iter == Banks.end())
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((*Iterator)->Items.DepositArea[SlotID].ItemID == 0)
|
||||
{
|
||||
if((*iter)->Items.DepositArea[slotID].ItemID == 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int MainSlot = -1;
|
||||
int mainSlot = -1;
|
||||
|
||||
for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i)
|
||||
if((*Iterator)->Items.MainArea[i].ItemID == 0)
|
||||
{
|
||||
MainSlot = i;
|
||||
|
||||
if((*iter)->Items.MainArea[i].ItemID == 0) {
|
||||
mainSlot = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if(MainSlot == -1)
|
||||
if(mainSlot == -1)
|
||||
return -1;
|
||||
|
||||
(*iter)->Items.MainArea[mainSlot].ItemID = (*iter)->Items.DepositArea[slotID].ItemID;
|
||||
(*iter)->Items.MainArea[mainSlot].Quantity = (*iter)->Items.DepositArea[slotID].Quantity;
|
||||
(*iter)->Items.MainArea[mainSlot].Permissions = (*iter)->Items.DepositArea[slotID].Permissions;
|
||||
|
||||
(*Iterator)->Items.MainArea[MainSlot].ItemID = (*Iterator)->Items.DepositArea[SlotID].ItemID;
|
||||
|
||||
(*Iterator)->Items.MainArea[MainSlot].Quantity = (*Iterator)->Items.DepositArea[SlotID].Quantity;
|
||||
|
||||
strn0cpy((*Iterator)->Items.MainArea[MainSlot].Donator, (*Iterator)->Items.DepositArea[SlotID].Donator, sizeof((*Iterator)->Items.MainArea[MainSlot].Donator));
|
||||
(*Iterator)->Items.MainArea[MainSlot].Permissions = (*Iterator)->Items.DepositArea[SlotID].Permissions;
|
||||
|
||||
strn0cpy((*Iterator)->Items.MainArea[MainSlot].WhoFor, (*Iterator)->Items.DepositArea[SlotID].WhoFor, sizeof((*Iterator)->Items.MainArea[MainSlot].WhoFor));
|
||||
|
||||
const char *Query="UPDATE `guild_bank` SET `area` = 1, `slot` = %i WHERE `guildid` = %i AND `area` = 0 AND `slot` = %i LIMIT 1";
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char* query = 0;
|
||||
|
||||
if(!database.RunQuery(query, MakeAnyLenString(&query, Query, MainSlot, GuildID, SlotID), errbuf))
|
||||
{
|
||||
_log(GUILDS__BANK_ERROR, "error promoting item: %s : %s", query, errbuf);
|
||||
|
||||
safe_delete_array(query);
|
||||
strn0cpy((*iter)->Items.MainArea[mainSlot].Donator, (*iter)->Items.DepositArea[slotID].Donator, sizeof((*iter)->Items.MainArea[mainSlot].Donator));
|
||||
strn0cpy((*iter)->Items.MainArea[mainSlot].WhoFor, (*iter)->Items.DepositArea[slotID].WhoFor, sizeof((*iter)->Items.MainArea[mainSlot].WhoFor));
|
||||
|
||||
std::string query = StringFormat("UPDATE `guild_bank` SET `area` = 1, `slot` = %i "
|
||||
"WHERE `guildid` = %i AND `area` = 0 AND `slot` = %i "
|
||||
"LIMIT 1", mainSlot, guildID, slotID);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(GUILDS__BANK_ERROR, "error promoting item: %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
(*iter)->Items.DepositArea[slotID].ItemID = 0;
|
||||
|
||||
(*Iterator)->Items.DepositArea[SlotID].ItemID = 0;
|
||||
|
||||
const Item_Struct *Item = database.GetItem((*Iterator)->Items.MainArea[MainSlot].ItemID);
|
||||
const Item_Struct *Item = database.GetItem((*iter)->Items.MainArea[mainSlot].ItemID);
|
||||
|
||||
GuildBankItemUpdate_Struct gbius;
|
||||
|
||||
if(!Item->Stackable)
|
||||
gbius.Init(GuildBankItemUpdate, 1, MainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, 0, 0, 0);
|
||||
gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, 0, 0, 0);
|
||||
else
|
||||
{
|
||||
if((*Iterator)->Items.MainArea[MainSlot].Quantity == Item->StackSize)
|
||||
gbius.Init(GuildBankItemUpdate, 1, MainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
||||
(*Iterator)->Items.MainArea[MainSlot].Quantity, 0, 0, 0);
|
||||
if((*iter)->Items.MainArea[mainSlot].Quantity == Item->StackSize)
|
||||
gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
||||
(*iter)->Items.MainArea[mainSlot].Quantity, 0, 0, 0);
|
||||
else
|
||||
gbius.Init(GuildBankItemUpdate, 1, MainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
||||
(*Iterator)->Items.MainArea[MainSlot].Quantity, 0, 1, 0);
|
||||
gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
||||
(*iter)->Items.MainArea[mainSlot].Quantity, 0, 1, 0);
|
||||
}
|
||||
|
||||
strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName));
|
||||
|
||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID);
|
||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID);
|
||||
|
||||
gbius.Init(GuildBankItemUpdate, 1, SlotID, GuildBankDepositArea, 0, 0, 0, 0, 0, 0, 0);
|
||||
gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankDepositArea, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID);
|
||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID);
|
||||
|
||||
return MainSlot;
|
||||
return mainSlot;
|
||||
}
|
||||
|
||||
void GuildBankManager::SetPermissions(uint32 GuildID, uint16 SlotID, uint32 Permissions, const char *MemberName)
|
||||
void GuildBankManager::SetPermissions(uint32 guildID, uint16 slotID, uint32 permissions, const char *memberName)
|
||||
{
|
||||
if((SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)))
|
||||
if((slotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)))
|
||||
return;
|
||||
|
||||
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID);
|
||||
auto iter = GetGuildBank(guildID);
|
||||
|
||||
if(Iterator == Banks.end())
|
||||
if(iter == Banks.end())
|
||||
return;
|
||||
|
||||
if((*iter)->Items.MainArea[slotID].ItemID == 0)
|
||||
return;
|
||||
|
||||
std::string query = StringFormat("UPDATE `guild_bank` SET `permissions` = %i, `whofor` = '%s' "
|
||||
"WHERE `guildid` = %i AND `area` = 1 AND `slot` = %i LIMIT 1",
|
||||
permissions, memberName, guildID, slotID);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
{
|
||||
_log(GUILDS__BANK_ERROR, "error changing permissions: %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if((*Iterator)->Items.MainArea[SlotID].ItemID == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
(*iter)->Items.MainArea[slotID].Permissions = permissions;
|
||||
|
||||
const char *Query="UPDATE `guild_bank` SET `permissions` = %i, `whofor` = '%s' WHERE `guildid` = %i AND `area` = 1 AND `slot` = %i LIMIT 1";
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char* query = 0;
|
||||
|
||||
if(!database.RunQuery(query, MakeAnyLenString(&query, Query, Permissions, MemberName, GuildID, SlotID), errbuf))
|
||||
{
|
||||
_log(GUILDS__BANK_ERROR, "error changing permissions: %s : %s", query, errbuf);
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
(*Iterator)->Items.MainArea[SlotID].Permissions = Permissions;
|
||||
|
||||
if(Permissions == GuildBankSingleMember)
|
||||
strn0cpy((*Iterator)->Items.MainArea[SlotID].WhoFor, MemberName, sizeof((*Iterator)->Items.MainArea[SlotID].WhoFor));
|
||||
if(permissions == GuildBankSingleMember)
|
||||
strn0cpy((*iter)->Items.MainArea[slotID].WhoFor, memberName, sizeof((*iter)->Items.MainArea[slotID].WhoFor));
|
||||
else
|
||||
(*Iterator)->Items.MainArea[SlotID].WhoFor[0] = '\0';
|
||||
(*iter)->Items.MainArea[slotID].WhoFor[0] = '\0';
|
||||
|
||||
|
||||
const Item_Struct *Item = database.GetItem((*Iterator)->Items.MainArea[SlotID].ItemID);
|
||||
const Item_Struct *Item = database.GetItem((*iter)->Items.MainArea[slotID].ItemID);
|
||||
|
||||
GuildBankItemUpdate_Struct gbius;
|
||||
|
||||
if(!Item->Stackable)
|
||||
gbius.Init(GuildBankItemUpdate, 1, SlotID, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, (*Iterator)->Items.MainArea[SlotID].Permissions, 0, 0);
|
||||
gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, (*iter)->Items.MainArea[slotID].Permissions, 0, 0);
|
||||
else
|
||||
{
|
||||
if((*Iterator)->Items.MainArea[SlotID].Quantity == Item->StackSize)
|
||||
gbius.Init(GuildBankItemUpdate, 1, SlotID, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
||||
(*Iterator)->Items.MainArea[SlotID].Quantity, (*Iterator)->Items.MainArea[SlotID].Permissions, 0, 0);
|
||||
if((*iter)->Items.MainArea[slotID].Quantity == Item->StackSize)
|
||||
gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
||||
(*iter)->Items.MainArea[slotID].Quantity, (*iter)->Items.MainArea[slotID].Permissions, 0, 0);
|
||||
else
|
||||
gbius.Init(GuildBankItemUpdate, 1, SlotID, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
||||
(*Iterator)->Items.MainArea[SlotID].Quantity, (*Iterator)->Items.MainArea[SlotID].Permissions, 1, 0);
|
||||
gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
||||
(*iter)->Items.MainArea[slotID].Quantity, (*iter)->Items.MainArea[slotID].Permissions, 1, 0);
|
||||
}
|
||||
|
||||
|
||||
strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName));
|
||||
|
||||
strn0cpy(gbius.WhoFor, (*Iterator)->Items.MainArea[SlotID].WhoFor, sizeof(gbius.WhoFor));
|
||||
strn0cpy(gbius.WhoFor, (*iter)->Items.MainArea[slotID].WhoFor, sizeof(gbius.WhoFor));
|
||||
|
||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID);
|
||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID);
|
||||
}
|
||||
|
||||
ItemInst* GuildBankManager::GetItem(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity)
|
||||
@@ -1208,90 +1141,73 @@ std::list<GuildBank*>::iterator GuildBankManager::GetGuildBank(uint32 GuildID)
|
||||
return Iterator;
|
||||
}
|
||||
|
||||
bool GuildBankManager::DeleteItem(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity)
|
||||
bool GuildBankManager::DeleteItem(uint32 guildID, uint16 area, uint16 slotID, uint32 quantity)
|
||||
{
|
||||
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID);
|
||||
auto iter = GetGuildBank(guildID);
|
||||
|
||||
if(Iterator == Banks.end())
|
||||
if(iter == Banks.end())
|
||||
return false;
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char* query = 0;
|
||||
|
||||
GuildBankItem* BankArea = nullptr;
|
||||
|
||||
if(Area == GuildBankMainArea)
|
||||
if(area == GuildBankMainArea)
|
||||
{
|
||||
if(SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1))
|
||||
if(slotID > (GUILD_BANK_MAIN_AREA_SIZE - 1))
|
||||
return false;
|
||||
|
||||
BankArea = &(*Iterator)->Items.MainArea[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(SlotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1))
|
||||
BankArea = &(*iter)->Items.MainArea[0];
|
||||
} else {
|
||||
if(slotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1))
|
||||
return false;
|
||||
|
||||
BankArea = &(*Iterator)->Items.DepositArea[0];
|
||||
BankArea = &(*iter)->Items.DepositArea[0];
|
||||
}
|
||||
|
||||
bool deleted = true;
|
||||
|
||||
bool Deleted = true;
|
||||
|
||||
const Item_Struct *Item = database.GetItem(BankArea[SlotID].ItemID);
|
||||
|
||||
if(!Item->Stackable || (Quantity >= BankArea[SlotID].Quantity))
|
||||
{
|
||||
const char *Query = "DELETE from `guild_bank` where `guildid` = %i AND `area` = %i AND `slot` = %i LIMIT 1";
|
||||
|
||||
if(!database.RunQuery(query, MakeAnyLenString(&query, Query, GuildID, Area, SlotID), errbuf))
|
||||
{
|
||||
_log(GUILDS__BANK_ERROR, "Delete item failed. %s : %s", query, errbuf);
|
||||
|
||||
safe_delete_array(query);
|
||||
const Item_Struct *Item = database.GetItem(BankArea[slotID].ItemID);
|
||||
|
||||
if(!Item->Stackable || (quantity >= BankArea[slotID].Quantity)) {
|
||||
std::string query = StringFormat("DELETE FROM `guild_bank` WHERE `guildid` = %i "
|
||||
"AND `area` = %i AND `slot` = %i LIMIT 1",
|
||||
guildID, area, slotID);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
_log(GUILDS__BANK_ERROR, "Delete item failed. %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
BankArea[SlotID].ItemID = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *Query = "UPDATE `guild_bank` SET `qty` = %i where `guildid` = %i AND `area` = %i AND `slot` = %i LIMIT 1";
|
||||
|
||||
if(!database.RunQuery(query, MakeAnyLenString(&query, Query, BankArea[SlotID].Quantity - Quantity,
|
||||
GuildID, Area, SlotID), errbuf))
|
||||
{
|
||||
_log(GUILDS__BANK_ERROR, "Update item failed. %s : %s", query, errbuf);
|
||||
|
||||
safe_delete_array(query);
|
||||
BankArea[slotID].ItemID = 0;
|
||||
|
||||
} else {
|
||||
std::string query = StringFormat("UPDATE `guild_bank` SET `qty` = %i WHERE `guildid` = %i "
|
||||
"AND `area` = %i AND `slot` = %i LIMIT 1",
|
||||
BankArea[slotID].Quantity - quantity, guildID, area, slotID);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
_log(GUILDS__BANK_ERROR, "Update item failed. %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
BankArea[slotID].Quantity -= quantity;
|
||||
|
||||
BankArea[SlotID].Quantity -= Quantity;
|
||||
|
||||
Deleted = false;
|
||||
deleted = false;
|
||||
}
|
||||
|
||||
GuildBankItemUpdate_Struct gbius;
|
||||
|
||||
if(!Deleted)
|
||||
if(!deleted)
|
||||
{
|
||||
gbius.Init(GuildBankItemUpdate, 1, SlotID, Area, 1, Item->ID, Item->Icon, BankArea[SlotID].Quantity, BankArea[SlotID].Permissions, 1, 0);
|
||||
gbius.Init(GuildBankItemUpdate, 1, slotID, area, 1, Item->ID, Item->Icon, BankArea[slotID].Quantity, BankArea[slotID].Permissions, 1, 0);
|
||||
|
||||
strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName));
|
||||
|
||||
strn0cpy(gbius.WhoFor, BankArea[SlotID].WhoFor, sizeof(gbius.WhoFor));
|
||||
strn0cpy(gbius.WhoFor, BankArea[slotID].WhoFor, sizeof(gbius.WhoFor));
|
||||
}
|
||||
else
|
||||
gbius.Init(GuildBankItemUpdate, 1, SlotID, Area, 0, 0, 0, 0, 0, 0, 0);
|
||||
gbius.Init(GuildBankItemUpdate, 1, slotID, area, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID);
|
||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -1422,26 +1338,20 @@ bool GuildBankManager::SplitStack(uint32 GuildID, uint16 SlotID, uint32 Quantity
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuildBankManager::UpdateItemQuantity(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity)
|
||||
void GuildBankManager::UpdateItemQuantity(uint32 guildID, uint16 area, uint16 slotID, uint32 quantity)
|
||||
{
|
||||
// Helper method for MergeStacks. Assuming all passed parameters are valid.
|
||||
//
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char* query = 0;
|
||||
|
||||
const char *Query = "UPDATE `guild_bank` SET `qty` = %i where `guildid` = %i AND `area` = %i AND `slot` = %i LIMIT 1";
|
||||
|
||||
if(!database.RunQuery(query, MakeAnyLenString(&query, Query, Quantity, GuildID, Area, SlotID), errbuf))
|
||||
{
|
||||
_log(GUILDS__BANK_ERROR, "Update item quantity failed. %s : %s", query, errbuf);
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
std::string query = StringFormat("UPDATE `guild_bank` SET `qty` = %i "
|
||||
"WHERE `guildid` = %i AND `area` = %i "
|
||||
"AND `slot` = %i LIMIT 1",
|
||||
quantity, guildID, area, slotID);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
_log(GUILDS__BANK_ERROR, "Update item quantity failed. %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
bool GuildBankManager::AllowedToWithdraw(uint32 GuildID, uint16 Area, uint16 SlotID, const char *Name)
|
||||
|
||||
+3
-3
@@ -23,9 +23,9 @@
|
||||
#include <list>
|
||||
#include "masterentity.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "hate_list.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "zone.h"
|
||||
#include "water_map.h"
|
||||
|
||||
@@ -311,7 +311,7 @@ Mob *HateList::GetTop(Mob *center)
|
||||
}
|
||||
}
|
||||
|
||||
if (cur->ent->Sanctuary()) {
|
||||
if (cur->ent->Sanctuary()) {
|
||||
if(hate == -1)
|
||||
{
|
||||
top = cur->ent;
|
||||
|
||||
+43
-62
@@ -18,9 +18,9 @@
|
||||
|
||||
#include "../common/debug.h"
|
||||
#include "masterentity.h"
|
||||
#include "../common/Item.h"
|
||||
#include "../common/item.h"
|
||||
#include "../common/linked_list.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include "worldserver.h"
|
||||
@@ -67,70 +67,51 @@ const NPCType *Horse::GetHorseType(uint16 spell_id) {
|
||||
|
||||
const NPCType *Horse::BuildHorseType(uint16 spell_id) {
|
||||
|
||||
const char* FileName = spells[spell_id].teleport_zone;
|
||||
const char* fileName = spells[spell_id].teleport_zone;
|
||||
|
||||
char mount_color = 0;
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "SELECT race,gender,texture,mountspeed FROM horses WHERE filename='%s'", FileName), errbuf, &result)) {
|
||||
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
|
||||
NPCType* npc_type = new NPCType;
|
||||
memset(npc_type, 0, sizeof(NPCType));
|
||||
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->max_hp = 1;
|
||||
npc_type->race = atoi(row[0]);
|
||||
npc_type->gender = atoi(row[1]); // Drogmor's are female horses. Yuck.
|
||||
npc_type->class_ = 1;
|
||||
npc_type->deity= 1;
|
||||
npc_type->level = 1;
|
||||
npc_type->npc_id = 0;
|
||||
npc_type->loottable_id = 0;
|
||||
npc_type->texture = atoi(row[2]);
|
||||
npc_type->helmtexture = atoi(row[2]);
|
||||
npc_type->runspeed = atof(row[3]);
|
||||
|
||||
mount_color = atoi(row[2]);
|
||||
|
||||
npc_type->light = 0;
|
||||
npc_type->STR = 75;
|
||||
npc_type->STA = 75;
|
||||
npc_type->DEX = 75;
|
||||
npc_type->AGI = 75;
|
||||
npc_type->INT = 75;
|
||||
npc_type->WIS = 75;
|
||||
npc_type->CHA = 75;
|
||||
|
||||
horses_auto_delete.Insert(npc_type);
|
||||
|
||||
mysql_free_result(result);
|
||||
return(npc_type);
|
||||
}
|
||||
else {
|
||||
LogFile->write(EQEMuLog::Error, "No Database entry for mount: %s, check the horses table", FileName);
|
||||
//Message(13, "Unable to find data for mount %s", FileName);
|
||||
safe_delete_array(query);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
return nullptr;
|
||||
}
|
||||
else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in Mount query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT race, gender, texture, mountspeed FROM horses WHERE filename = '%s'", fileName);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in Mount query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1) {
|
||||
LogFile->write(EQEMuLog::Error, "No Database entry for mount: %s, check the horses table", fileName);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
NPCType* npc_type = new NPCType;
|
||||
memset(npc_type, 0, sizeof(NPCType));
|
||||
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->max_hp = 1;
|
||||
npc_type->race = atoi(row[0]);
|
||||
npc_type->gender = atoi(row[1]); // Drogmor's are female horses. Yuck.
|
||||
npc_type->class_ = 1;
|
||||
npc_type->deity= 1;
|
||||
npc_type->level = 1;
|
||||
npc_type->npc_id = 0;
|
||||
npc_type->loottable_id = 0;
|
||||
npc_type->texture = atoi(row[2]); // mount color
|
||||
npc_type->helmtexture = atoi(row[2]); // mount color
|
||||
npc_type->runspeed = atof(row[3]);
|
||||
|
||||
npc_type->light = 0;
|
||||
npc_type->STR = 75;
|
||||
npc_type->STA = 75;
|
||||
npc_type->DEX = 75;
|
||||
npc_type->AGI = 75;
|
||||
npc_type->INT = 75;
|
||||
npc_type->WIS = 75;
|
||||
npc_type->CHA = 75;
|
||||
horses_auto_delete.Insert(npc_type);
|
||||
|
||||
return npc_type;
|
||||
}
|
||||
|
||||
void Client::SummonHorse(uint16 spell_id) {
|
||||
|
||||
+24
-16
@@ -25,14 +25,14 @@
|
||||
#include "../common/packet_functions.h"
|
||||
#include "petitions.h"
|
||||
#include "../common/serverinfo.h"
|
||||
#include "../common/ZoneNumbers.h"
|
||||
#include "../common/zone_numbers.h"
|
||||
#include "../common/moremath.h"
|
||||
#include "../common/guilds.h"
|
||||
#include "../common/logsys.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "StringIDs.h"
|
||||
#include "NpcAI.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "string_ids.h"
|
||||
#include "npc_ai.h"
|
||||
#include "quest_parser_collection.h"
|
||||
extern WorldServer worldserver;
|
||||
|
||||
// @merth: this needs to be touched up
|
||||
@@ -200,6 +200,15 @@ bool Client::CheckLoreConflict(const Item_Struct* item) {
|
||||
}
|
||||
|
||||
bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, bool attuned, uint16 to_slot) {
|
||||
/* Set a timestamp in an entity variable for plugin check_handin.pl in return_items
|
||||
This will stopgap players from items being returned if global_npc.pl has a catch all return_items
|
||||
*/
|
||||
struct timeval read_time;
|
||||
char buffer[50];
|
||||
gettimeofday(&read_time, 0);
|
||||
sprintf(buffer, "%li.%li \n", read_time.tv_sec, read_time.tv_usec);
|
||||
this->SetEntityVariable("Recieved_Item", buffer);
|
||||
|
||||
// TODO: update calling methods and script apis to handle a failure return
|
||||
|
||||
const Item_Struct* item = database.GetItem(item_id);
|
||||
@@ -813,25 +822,24 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update)
|
||||
return database.SaveCursor(CharacterID(), s, e);
|
||||
}
|
||||
|
||||
bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update)
|
||||
{
|
||||
bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update) {
|
||||
mlog(INVENTORY__SLOTS, "Putting item %s (%d) into slot %d", inst.GetItem()->Name, inst.GetItem()->ID, slot_id);
|
||||
|
||||
if (slot_id == MainCursor)
|
||||
{
|
||||
return PushItemOnCursor(inst,client_update);
|
||||
}
|
||||
return PushItemOnCursor(inst, client_update);
|
||||
else
|
||||
m_inv.PutItem(slot_id, inst);
|
||||
|
||||
if (client_update) {
|
||||
SendItemPacket(slot_id, &inst, (slot_id == MainCursor) ? ItemPacketSummonItem : ItemPacketTrade);
|
||||
}
|
||||
if (client_update)
|
||||
SendItemPacket(slot_id, &inst, ((slot_id == MainCursor) ? ItemPacketSummonItem : ItemPacketTrade));
|
||||
|
||||
if (slot_id == MainCursor) {
|
||||
std::list<ItemInst*>::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end();
|
||||
std::list<ItemInst*>::const_iterator s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
||||
return database.SaveCursor(this->CharacterID(), s, e);
|
||||
} else
|
||||
}
|
||||
else {
|
||||
return database.SaveInventory(this->CharacterID(), &inst, slot_id);
|
||||
}
|
||||
|
||||
CalcBonuses();
|
||||
}
|
||||
@@ -1530,7 +1538,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
// Also sends trade information to other client of trade session
|
||||
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
|
||||
|
||||
trade->AddEntity(src_slot_id, dst_slot_id);
|
||||
trade->AddEntity(dst_slot_id, move_in->number_in_stack);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
#include "npc.h"
|
||||
#include "masterentity.h"
|
||||
#include "zonedb.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#ifdef _WINDOWS
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -1134,7 +1134,7 @@ void Lua_Client::Signal(uint32 id) {
|
||||
|
||||
void Lua_Client::AddAlternateCurrencyValue(uint32 currency, int amount) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->AddAlternateCurrencyValue(currency, amount);
|
||||
self->AddAlternateCurrencyValue(currency, amount, 1);
|
||||
}
|
||||
|
||||
void Lua_Client::SendWebLink(const char *site) {
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
#include "lua_client.h"
|
||||
#include "lua_npc.h"
|
||||
#include "lua_entity_list.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "questmgr.h"
|
||||
#include "QGlobals.h"
|
||||
#include "qglobals.h"
|
||||
#include "../common/timer.h"
|
||||
|
||||
struct Events { };
|
||||
|
||||
+12
-1
@@ -442,6 +442,15 @@ 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();
|
||||
}
|
||||
|
||||
luabind::scope lua_register_npc() {
|
||||
return luabind::class_<Lua_NPC, Lua_Mob>("NPC")
|
||||
@@ -532,7 +541,9 @@ luabind::scope lua_register_npc() {
|
||||
.def("GetSpawnKillCount", (int(Lua_NPC::*)(void))&Lua_NPC::GetSpawnKillCount)
|
||||
.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("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);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -114,6 +114,8 @@ public:
|
||||
int GetScore();
|
||||
void MerchantOpenShop();
|
||||
void MerchantCloseShop();
|
||||
void SetMerchantProbability(uint8 amt);
|
||||
uint8 GetMerchantProbability();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
#define _EQE_LUA_PARSER_H
|
||||
#ifdef LUA_EQEMU
|
||||
|
||||
#include "QuestParserCollection.h"
|
||||
#include "QuestInterface.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "quest_interface.h"
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
#include <luabind/luabind.hpp>
|
||||
#include <luabind/object.hpp>
|
||||
|
||||
#include "QuestParserCollection.h"
|
||||
#include "QuestInterface.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "quest_interface.h"
|
||||
|
||||
#include "masterentity.h"
|
||||
#include "../common/seperator.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "lua_item.h"
|
||||
#include "lua_iteminst.h"
|
||||
#include "lua_entity.h"
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
#include "../common/debug.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "map.h"
|
||||
#include "RaycastMesh.h"
|
||||
#include "raycast_mesh.h"
|
||||
#include "zone.h"
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
|
||||
+92
-99
@@ -1,17 +1,17 @@
|
||||
#include "merc.h"
|
||||
#include "masterentity.h"
|
||||
#include "NpcAI.h"
|
||||
#include "npc_ai.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/eq_constants.h"
|
||||
#include "../common/skills.h"
|
||||
#include "../common/spdat.h"
|
||||
#include "zone.h"
|
||||
#include "StringIDs.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "water_map.h"
|
||||
|
||||
extern volatile bool ZoneLoaded;
|
||||
@@ -2773,7 +2773,7 @@ int16 Merc::GetFocusEffect(focusType type, uint16 spell_id) {
|
||||
|
||||
|
||||
int32 Merc::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
|
||||
|
||||
if (spells[spell_id].targettype == ST_Self)
|
||||
return value;
|
||||
|
||||
@@ -2784,9 +2784,9 @@ int32 Merc::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
|
||||
int chance = RuleI(Spells, BaseCritChance);
|
||||
chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance;
|
||||
|
||||
|
||||
if (chance > 0){
|
||||
|
||||
|
||||
int32 ratio = RuleI(Spells, BaseCritRatio); //Critical modifier is applied from spell effects only. Keep at 100 for live like criticals.
|
||||
|
||||
if (MakeRandomInt(1,100) <= chance){
|
||||
@@ -2801,29 +2801,29 @@ int32 Merc::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
}
|
||||
|
||||
ratio += RuleI(Spells, WizCritRatio); //Default is zero
|
||||
|
||||
|
||||
if (Critical){
|
||||
|
||||
value = value_BaseEffect*ratio/100;
|
||||
value = value_BaseEffect*ratio/100;
|
||||
|
||||
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
|
||||
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
|
||||
|
||||
value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
|
||||
|
||||
if (target) {
|
||||
value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
|
||||
value -= target->GetFcDamageAmtIncoming(this, spell_id);
|
||||
value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
|
||||
value -= target->GetFcDamageAmtIncoming(this, spell_id);
|
||||
}
|
||||
|
||||
value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100;
|
||||
value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100;
|
||||
|
||||
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
|
||||
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
|
||||
|
||||
if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
|
||||
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100;
|
||||
|
||||
value = (value * GetSpellScale() / 100);
|
||||
|
||||
value = (value * GetSpellScale() / 100);
|
||||
|
||||
entity_list.MessageClose_StringID(this, false, 100, MT_SpellCrits,
|
||||
OTHER_CRIT_BLAST, GetName(), itoa(-value));
|
||||
|
||||
@@ -2832,30 +2832,30 @@ int32 Merc::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
}
|
||||
|
||||
value = value_BaseEffect;
|
||||
|
||||
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
|
||||
|
||||
|
||||
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
|
||||
|
||||
value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
|
||||
|
||||
if (target) {
|
||||
value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100;
|
||||
value -= target->GetFcDamageAmtIncoming(this, spell_id);
|
||||
value -= target->GetFcDamageAmtIncoming(this, spell_id);
|
||||
}
|
||||
|
||||
value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id);
|
||||
value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id);
|
||||
|
||||
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
|
||||
|
||||
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
|
||||
|
||||
if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
|
||||
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value);
|
||||
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value);
|
||||
|
||||
value = (value * GetSpellScale() / 100);
|
||||
|
||||
value = (value * GetSpellScale() / 100);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int32 Merc::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
|
||||
|
||||
|
||||
if (target == nullptr)
|
||||
target = this;
|
||||
|
||||
@@ -2863,37 +2863,37 @@ int32 Merc::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
|
||||
int16 chance = 0;
|
||||
int8 modifier = 1;
|
||||
bool Critical = false;
|
||||
|
||||
value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);
|
||||
|
||||
|
||||
value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);
|
||||
|
||||
value = value_BaseEffect;
|
||||
|
||||
value += int(value_BaseEffect*GetFocusEffect(focusImprovedHeal, spell_id)/100);
|
||||
|
||||
value += int(value_BaseEffect*GetFocusEffect(focusImprovedHeal, spell_id)/100);
|
||||
|
||||
// Instant Heals
|
||||
if(spells[spell_id].buffduration < 1) {
|
||||
|
||||
chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance;
|
||||
chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance;
|
||||
|
||||
chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id);
|
||||
|
||||
chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id);
|
||||
|
||||
if (spellbonuses.CriticalHealDecay)
|
||||
chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay);
|
||||
|
||||
chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay);
|
||||
|
||||
if(chance && (MakeRandomInt(0,99) < chance)) {
|
||||
Critical = true;
|
||||
modifier = 2; //At present time no critical heal amount modifier SPA exists.
|
||||
}
|
||||
|
||||
|
||||
value *= modifier;
|
||||
value += GetFocusEffect(focusFcHealAmtCrit, spell_id) * modifier;
|
||||
value += GetFocusEffect(focusFcHealAmt, spell_id);
|
||||
value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id);
|
||||
|
||||
value += GetFocusEffect(focusFcHealAmtCrit, spell_id) * modifier;
|
||||
value += GetFocusEffect(focusFcHealAmt, spell_id);
|
||||
value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id);
|
||||
|
||||
if(itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
|
||||
value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier;
|
||||
|
||||
value += value*target->GetHealRate(spell_id, this)/100;
|
||||
value += value*target->GetHealRate(spell_id, this)/100;
|
||||
|
||||
if (Critical)
|
||||
entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), value);
|
||||
@@ -2903,14 +2903,14 @@ int32 Merc::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
|
||||
|
||||
//Heal over time spells. [Heal Rate and Additional Healing effects do not increase this value]
|
||||
else {
|
||||
|
||||
chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime;
|
||||
|
||||
chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id);
|
||||
|
||||
chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime;
|
||||
|
||||
chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id);
|
||||
|
||||
if (spellbonuses.CriticalRegenDecay)
|
||||
chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay);
|
||||
|
||||
|
||||
if(chance && (MakeRandomInt(0,99) < chance))
|
||||
return (value * 2);
|
||||
}
|
||||
@@ -5851,71 +5851,64 @@ void Client::SendMercAssignPacket(uint32 entityID, uint32 unk01, uint32 unk02) {
|
||||
FastQueuePacket(&outapp);
|
||||
}
|
||||
|
||||
void NPC::LoadMercTypes(){
|
||||
std::string errorMessage;
|
||||
char* Query = 0;
|
||||
char TempErrorMessageBuffer[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES* DatasetResult;
|
||||
MYSQL_ROW DataRow;
|
||||
void NPC::LoadMercTypes() {
|
||||
|
||||
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT DISTINCT MTyp.dbstring, MTyp.clientversion FROM merc_merchant_entries MME, merc_merchant_template_entries MMTE, merc_types MTyp, merc_templates MTem WHERE MME.merchant_id = %i AND MME.merc_merchant_template_id = MMTE.merc_merchant_template_id AND MMTE.merc_template_id = MTem.merc_template_id AND MTem.merc_type_id = MTyp.merc_type_id;", GetNPCTypeID()), TempErrorMessageBuffer, &DatasetResult)) {
|
||||
errorMessage = std::string(TempErrorMessageBuffer);
|
||||
}
|
||||
else {
|
||||
while(DataRow = mysql_fetch_row(DatasetResult)) {
|
||||
MercType tempMercType;
|
||||
std::string query = StringFormat("SELECT DISTINCT MTyp.dbstring, MTyp.clientversion "
|
||||
"FROM merc_merchant_entries MME, merc_merchant_template_entries MMTE, "
|
||||
"merc_types MTyp, merc_templates MTem "
|
||||
"WHERE MME.merchant_id = %i "
|
||||
"AND MME.merc_merchant_template_id = MMTE.merc_merchant_template_id "
|
||||
"AND MMTE.merc_template_id = MTem.merc_template_id "
|
||||
"AND MTem.merc_type_id = MTyp.merc_type_id;", GetNPCTypeID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in NPC::LoadMercTypes()");
|
||||
return;
|
||||
}
|
||||
|
||||
tempMercType.Type = atoi(DataRow[0]);
|
||||
tempMercType.ClientVersion = atoi(DataRow[1]);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
MercType tempMercType;
|
||||
|
||||
mercTypeList.push_back(tempMercType);
|
||||
}
|
||||
tempMercType.Type = atoi(row[0]);
|
||||
tempMercType.ClientVersion = atoi(row[1]);
|
||||
|
||||
mysql_free_result(DatasetResult);
|
||||
mercTypeList.push_back(tempMercType);
|
||||
}
|
||||
|
||||
safe_delete_array(Query);
|
||||
Query = 0;
|
||||
|
||||
if(!errorMessage.empty()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in NPC::LoadMercTypes()");
|
||||
}
|
||||
}
|
||||
|
||||
void NPC::LoadMercs(){
|
||||
|
||||
std::string errorMessage;
|
||||
char* Query = 0;
|
||||
char TempErrorMessageBuffer[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES* DatasetResult;
|
||||
MYSQL_ROW DataRow;
|
||||
std::string query = StringFormat("SELECT DISTINCT MTem.merc_template_id, MTyp.dbstring AS merc_type_id, "
|
||||
"MTem.dbstring AS merc_subtype_id, 0 AS CostFormula, "
|
||||
"CASE WHEN MTem.clientversion > MTyp.clientversion "
|
||||
"THEN MTem.clientversion "
|
||||
"ELSE MTyp.clientversion END AS clientversion, MTem.merc_npc_type_id "
|
||||
"FROM merc_merchant_entries MME, merc_merchant_template_entries MMTE, "
|
||||
"merc_types MTyp, merc_templates MTem "
|
||||
"WHERE MME.merchant_id = %i AND "
|
||||
"MME.merc_merchant_template_id = MMTE.merc_merchant_template_id "
|
||||
"AND MMTE.merc_template_id = MTem.merc_template_id "
|
||||
"AND MTem.merc_type_id = MTyp.merc_type_id;", GetNPCTypeID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in NPC::LoadMercTypes()");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT DISTINCT MTem.merc_template_id, MTyp.dbstring AS merc_type_id, MTem.dbstring AS merc_subtype_id, 0 AS CostFormula, CASE WHEN MTem.clientversion > MTyp.clientversion then MTem.clientversion ELSE MTyp.clientversion END AS clientversion, MTem.merc_npc_type_id FROM merc_merchant_entries MME, merc_merchant_template_entries MMTE, merc_types MTyp, merc_templates MTem WHERE MME.merchant_id = %i AND MME.merc_merchant_template_id = MMTE.merc_merchant_template_id AND MMTE.merc_template_id = MTem.merc_template_id AND MTem.merc_type_id = MTyp.merc_type_id;", GetNPCTypeID()), TempErrorMessageBuffer, &DatasetResult)) {
|
||||
errorMessage = std::string(TempErrorMessageBuffer);
|
||||
}
|
||||
else {
|
||||
while(DataRow = mysql_fetch_row(DatasetResult)) {
|
||||
MercData tempMerc;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
MercData tempMerc;
|
||||
|
||||
tempMerc.MercTemplateID = atoi(DataRow[0]);
|
||||
tempMerc.MercType = atoi(DataRow[1]);
|
||||
tempMerc.MercSubType = atoi(DataRow[2]);
|
||||
tempMerc.CostFormula = atoi(DataRow[3]);
|
||||
tempMerc.ClientVersion = atoi(DataRow[4]);
|
||||
tempMerc.NPCID = atoi(DataRow[5]);
|
||||
tempMerc.MercTemplateID = atoi(row[0]);
|
||||
tempMerc.MercType = atoi(row[1]);
|
||||
tempMerc.MercSubType = atoi(row[2]);
|
||||
tempMerc.CostFormula = atoi(row[3]);
|
||||
tempMerc.ClientVersion = atoi(row[4]);
|
||||
tempMerc.NPCID = atoi(row[5]);
|
||||
|
||||
mercDataList.push_back(tempMerc);
|
||||
}
|
||||
|
||||
mysql_free_result(DatasetResult);
|
||||
mercDataList.push_back(tempMerc);
|
||||
}
|
||||
|
||||
safe_delete_array(Query);
|
||||
Query = 0;
|
||||
|
||||
if(!errorMessage.empty()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in NPC::LoadMercTypes()");
|
||||
}
|
||||
}
|
||||
|
||||
int NPC::GetNumMercTypes(uint32 clientVersion)
|
||||
|
||||
+58
-79
@@ -18,10 +18,10 @@
|
||||
#include "../common/debug.h"
|
||||
#include "masterentity.h"
|
||||
#include "../common/spdat.h"
|
||||
#include "StringIDs.h"
|
||||
#include "string_ids.h"
|
||||
#include "worldserver.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "../common/string_util.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <math.h>
|
||||
@@ -183,6 +183,7 @@ Mob::Mob(const char* in_name,
|
||||
has_MGB = false;
|
||||
has_ProjectIllusion = false;
|
||||
SpellPowerDistanceMod = 0;
|
||||
last_los_check = false;
|
||||
|
||||
if(in_aa_title>0)
|
||||
aa_title = in_aa_title;
|
||||
@@ -311,7 +312,7 @@ Mob::Mob(const char* in_name,
|
||||
shielder[m].shielder_id = 0;
|
||||
shielder[m].shielder_bonus = 0;
|
||||
}
|
||||
|
||||
|
||||
destructibleobject = false;
|
||||
wandertype=0;
|
||||
pausetype=0;
|
||||
@@ -341,6 +342,7 @@ Mob::Mob(const char* in_name,
|
||||
viral_spells[i] = 0;
|
||||
}
|
||||
pStandingPetOrder = SPO_Follow;
|
||||
pseudo_rooted = false;
|
||||
|
||||
see_invis = in_see_invis;
|
||||
see_invis_undead = in_see_invis_undead != 0;
|
||||
@@ -893,7 +895,7 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
ns->spawn.invis = (invisible || hidden) ? 1 : 0; // TODO: load this before spawning players
|
||||
ns->spawn.NPC = IsClient() ? 0 : 1;
|
||||
ns->spawn.IsMercenary = (IsMerc() || no_target_hotkey) ? 1 : 0;
|
||||
|
||||
|
||||
ns->spawn.petOwnerId = ownerid;
|
||||
|
||||
ns->spawn.haircolor = haircolor;
|
||||
@@ -2392,7 +2394,7 @@ bool Mob::HateSummon() {
|
||||
{
|
||||
if(summon_level == 1) {
|
||||
entity_list.MessageClose(this, true, 500, MT_Say, "%s says,'You will not evade me, %s!' ", GetCleanName(), target->GetCleanName() );
|
||||
|
||||
|
||||
if (target->IsClient()) {
|
||||
target->CastToClient()->MovePC(zone->GetZoneID(), zone->GetInstanceID(), x_pos, y_pos, z_pos, target->GetHeading(), 0, SummonPC);
|
||||
}
|
||||
@@ -2404,12 +2406,12 @@ bool Mob::HateSummon() {
|
||||
target->CastToBot()->SetPreSummonX(target->GetX());
|
||||
target->CastToBot()->SetPreSummonY(target->GetY());
|
||||
target->CastToBot()->SetPreSummonZ(target->GetZ());
|
||||
|
||||
|
||||
}
|
||||
#endif //BOTS
|
||||
target->GMMove(x_pos, y_pos, z_pos, target->GetHeading());
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
} else if(summon_level == 2) {
|
||||
entity_list.MessageClose(this, true, 500, MT_Say, "%s says,'You will not evade me, %s!'", GetCleanName(), target->GetCleanName());
|
||||
@@ -3040,7 +3042,7 @@ void Mob::TriggerDefensiveProcs(const ItemInst* weapon, Mob *on, uint16 hand, in
|
||||
case (-1):
|
||||
skillinuse = SkillBlock;
|
||||
break;
|
||||
|
||||
|
||||
case (-2):
|
||||
skillinuse = SkillParry;
|
||||
break;
|
||||
@@ -3273,7 +3275,7 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP
|
||||
|
||||
if (!spellbonuses.TriggerOnValueAmount)
|
||||
return;
|
||||
|
||||
|
||||
if (spellbonuses.TriggerOnValueAmount){
|
||||
|
||||
int buff_count = GetMaxTotalSlots();
|
||||
@@ -3294,15 +3296,15 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP
|
||||
if (IsHP){
|
||||
if ((base2 >= 500 && base2 <= 520) && GetHPRatio() < (base2 - 500)*5)
|
||||
use_spell = true;
|
||||
|
||||
|
||||
else if (base2 = 1004 && GetHPRatio() < 80)
|
||||
use_spell = true;
|
||||
}
|
||||
|
||||
else if (IsMana){
|
||||
if ( (base2 = 521 && GetManaRatio() < 20) || (base2 = 523 && GetManaRatio() < 40))
|
||||
if ( (base2 = 521 && GetManaRatio() < 20) || (base2 = 523 && GetManaRatio() < 40))
|
||||
use_spell = true;
|
||||
|
||||
|
||||
else if (base2 = 38311 && GetManaRatio() < 10)
|
||||
use_spell = true;
|
||||
}
|
||||
@@ -3322,7 +3324,7 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP
|
||||
|
||||
if (use_spell){
|
||||
SpellFinished(spells[spell_id].base[i], this, 10, 0, -1, spells[spell_id].ResistDiff);
|
||||
|
||||
|
||||
if(!TryFadeEffect(e))
|
||||
BuffFadeBySlot(e);
|
||||
}
|
||||
@@ -3382,7 +3384,7 @@ int32 Mob::GetVulnerability(Mob* caster, uint32 spell_id, uint32 ticsremaining)
|
||||
|
||||
if (!caster)
|
||||
return 0;
|
||||
|
||||
|
||||
int32 value = 0;
|
||||
|
||||
//Apply innate vulnerabilities
|
||||
@@ -3395,7 +3397,7 @@ int32 Mob::GetVulnerability(Mob* caster, uint32 spell_id, uint32 ticsremaining)
|
||||
|
||||
//Apply spell derived vulnerabilities
|
||||
if (spellbonuses.FocusEffects[focusSpellVulnerability]){
|
||||
|
||||
|
||||
int32 tmp_focus = 0;
|
||||
int tmp_buffslot = -1;
|
||||
|
||||
@@ -3456,15 +3458,15 @@ int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used)
|
||||
}
|
||||
|
||||
int16 Mob::GetHealRate(uint16 spell_id, Mob* caster) {
|
||||
|
||||
|
||||
int16 heal_rate = 0;
|
||||
|
||||
heal_rate += itembonuses.HealRate + spellbonuses.HealRate + aabonuses.HealRate;
|
||||
heal_rate += GetFocusIncoming(focusFcHealPctIncoming, SE_FcHealPctIncoming, caster, spell_id);
|
||||
heal_rate += itembonuses.HealRate + spellbonuses.HealRate + aabonuses.HealRate;
|
||||
heal_rate += GetFocusIncoming(focusFcHealPctIncoming, SE_FcHealPctIncoming, caster, spell_id);
|
||||
|
||||
if(heal_rate < -99)
|
||||
heal_rate = -99;
|
||||
|
||||
|
||||
return heal_rate;
|
||||
}
|
||||
|
||||
@@ -3474,7 +3476,7 @@ bool Mob::TryFadeEffect(int slot)
|
||||
{
|
||||
for(int i = 0; i < EFFECT_COUNT; i++)
|
||||
{
|
||||
if (spells[buffs[slot].spellid].effectid[i] == SE_CastOnFadeEffectAlways ||
|
||||
if (spells[buffs[slot].spellid].effectid[i] == SE_CastOnFadeEffectAlways ||
|
||||
spells[buffs[slot].spellid].effectid[i] == SE_CastOnRuneFadeEffect)
|
||||
{
|
||||
uint16 spell_id = spells[buffs[slot].spellid].base[i];
|
||||
@@ -3532,7 +3534,7 @@ void Mob::TrySympatheticProc(Mob *target, uint32 spell_id)
|
||||
else
|
||||
SpellFinished(focus_trigger, target, 10, 0, -1, spells[focus_trigger].ResistDiff);
|
||||
}
|
||||
|
||||
|
||||
CheckNumHitsRemaining(NUMHIT_MatchingSpells, 0, focus_spell);
|
||||
}
|
||||
}
|
||||
@@ -3928,36 +3930,26 @@ void Mob::TarGlobal(const char *varname, const char *value, const char *duration
|
||||
}
|
||||
|
||||
void Mob::DelGlobal(const char *varname) {
|
||||
// delglobal(varname)
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
|
||||
int qgZoneid=zone->GetZoneID();
|
||||
int qgCharid=0;
|
||||
int qgNpcid=0;
|
||||
|
||||
if (this->IsNPC())
|
||||
{
|
||||
qgNpcid = this->GetNPCTypeID();
|
||||
}
|
||||
|
||||
if (this->IsClient())
|
||||
{
|
||||
qgCharid = this->CastToClient()->CharacterID();
|
||||
}
|
||||
else
|
||||
{
|
||||
qgCharid = -qgNpcid; // make char id negative npc id as a fudge
|
||||
}
|
||||
|
||||
if (!database.RunQuery(query,
|
||||
MakeAnyLenString(&query,
|
||||
"DELETE FROM quest_globals WHERE name='%s'"
|
||||
" && (npcid=0 || npcid=%i) && (charid=0 || charid=%i) && (zoneid=%i || zoneid=0)",
|
||||
varname,qgNpcid,qgCharid,qgZoneid),errbuf))
|
||||
{
|
||||
//_log(QUESTS, "DelGlobal error deleting %s : %s", varname, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("DELETE FROM quest_globals "
|
||||
"WHERE name='%s' && (npcid=0 || npcid=%i) "
|
||||
"&& (charid=0 || charid=%i) "
|
||||
"&& (zoneid=%i || zoneid=0)",
|
||||
varname, qgNpcid, qgCharid, qgZoneid);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
|
||||
if(zone)
|
||||
{
|
||||
@@ -3980,33 +3972,22 @@ void Mob::DelGlobal(const char *varname) {
|
||||
// Inserts global variable into quest_globals table
|
||||
void Mob::InsertQuestGlobal(int charid, int npcid, int zoneid, const char *varname, const char *varvalue, int duration) {
|
||||
|
||||
char *query = 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
// Make duration string either "unix_timestamp(now()) + xxx" or "NULL"
|
||||
std::stringstream duration_ss;
|
||||
|
||||
if (duration == INT_MAX)
|
||||
{
|
||||
duration_ss << "NULL";
|
||||
}
|
||||
else
|
||||
{
|
||||
duration_ss << "unix_timestamp(now()) + " << duration;
|
||||
}
|
||||
|
||||
//NOTE: this should be escaping the contents of arglist
|
||||
//npcwise a malicious script can arbitrarily alter the DB
|
||||
uint32 last_id = 0;
|
||||
if (!database.RunQuery(query, MakeAnyLenString(&query,
|
||||
"REPLACE INTO quest_globals (charid, npcid, zoneid, name, value, expdate)"
|
||||
"VALUES (%i, %i, %i, '%s', '%s', %s)",
|
||||
charid, npcid, zoneid, varname, varvalue, duration_ss.str().c_str()
|
||||
), errbuf))
|
||||
{
|
||||
//_log(QUESTS, "SelGlobal error inserting %s : %s", varname, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("REPLACE INTO quest_globals "
|
||||
"(charid, npcid, zoneid, name, value, expdate)"
|
||||
"VALUES (%i, %i, %i, '%s', '%s', %s)",
|
||||
charid, npcid, zoneid, varname, varvalue, duration_ss.str().c_str());
|
||||
database.QueryDatabase(query);
|
||||
|
||||
if(zone)
|
||||
{
|
||||
@@ -4032,14 +4013,12 @@ void Mob::InsertQuestGlobal(int charid, int npcid, int zoneid, const char *varna
|
||||
qgu->npc_id = npcid;
|
||||
qgu->char_id = charid;
|
||||
qgu->zone_id = zoneid;
|
||||
|
||||
if(duration == INT_MAX)
|
||||
{
|
||||
qgu->expdate = 0xFFFFFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
qgu->expdate = Timer::GetTimeSeconds() + duration;
|
||||
}
|
||||
|
||||
strcpy((char*)qgu->name, varname);
|
||||
strcpy((char*)qgu->value, varvalue);
|
||||
qgu->id = last_id;
|
||||
@@ -4362,7 +4341,7 @@ int16 Mob::GetSkillDmgAmt(uint16 skill)
|
||||
}
|
||||
|
||||
void Mob::MeleeLifeTap(int32 damage) {
|
||||
|
||||
|
||||
int16 lifetap_amt = 0;
|
||||
lifetap_amt = spellbonuses.MeleeLifetap + itembonuses.MeleeLifetap + aabonuses.MeleeLifetap
|
||||
+ spellbonuses.Vampirism + itembonuses.Vampirism + aabonuses.Vampirism;
|
||||
@@ -4371,7 +4350,7 @@ void Mob::MeleeLifeTap(int32 damage) {
|
||||
|
||||
lifetap_amt = damage * lifetap_amt / 100;
|
||||
mlog(COMBAT__DAMAGE, "Melee lifetap healing for %d damage.", damage);
|
||||
|
||||
|
||||
if (lifetap_amt > 0)
|
||||
HealDamage(lifetap_amt); //Heal self for modified damage amount.
|
||||
else
|
||||
@@ -4383,9 +4362,9 @@ bool Mob::TryReflectSpell(uint32 spell_id)
|
||||
{
|
||||
if (!spells[spell_id].reflectable)
|
||||
return false;
|
||||
|
||||
|
||||
int chance = itembonuses.reflect_chance + spellbonuses.reflect_chance + aabonuses.reflect_chance;
|
||||
|
||||
|
||||
if(chance && MakeRandomInt(0, 99) < chance)
|
||||
return true;
|
||||
|
||||
@@ -4403,12 +4382,12 @@ void Mob::SpellProjectileEffect()
|
||||
}
|
||||
|
||||
Mob* target = entity_list.GetMobID(projectile_target_id[i]);
|
||||
|
||||
|
||||
float dist = 0;
|
||||
|
||||
if (target)
|
||||
|
||||
if (target)
|
||||
dist = target->CalculateDistance(projectile_x[i], projectile_y[i], projectile_z[i]);
|
||||
|
||||
|
||||
int increment_end = 0;
|
||||
increment_end = (dist / 10) - 1; //This pretty accurately determines end time for speed for 1.5 and timer of 250 ms
|
||||
|
||||
@@ -4681,7 +4660,7 @@ void Mob::SlowMitigation(Mob* caster)
|
||||
else if ((GetSlowMitigation() >= 74) && (GetSlowMitigation() < 101))
|
||||
caster->Message_StringID(MT_SpellFailure, SLOW_SLIGHTLY_SUCCESSFUL);
|
||||
|
||||
else if (GetSlowMitigation() > 100)
|
||||
else if (GetSlowMitigation() > 100)
|
||||
caster->Message_StringID(MT_SpellFailure, SPELL_OPPOSITE_EFFECT);
|
||||
}
|
||||
}
|
||||
@@ -4758,10 +4737,10 @@ bool Mob::PassLimitToSkill(uint16 spell_id, uint16 skill) {
|
||||
}
|
||||
|
||||
uint16 Mob::GetWeaponSpeedbyHand(uint16 hand) {
|
||||
|
||||
|
||||
uint16 weapon_speed = 0;
|
||||
switch (hand) {
|
||||
|
||||
|
||||
case 13:
|
||||
weapon_speed = attack_timer.GetDuration();
|
||||
break;
|
||||
@@ -4784,7 +4763,7 @@ int8 Mob::GetDecayEffectValue(uint16 spell_id, uint16 spelleffect) {
|
||||
if (!IsValidSpell(spell_id))
|
||||
return false;
|
||||
|
||||
int spell_level = spells[spell_id].classes[(GetClass()%16) - 1];
|
||||
int spell_level = spells[spell_id].classes[(GetClass()%16) - 1];
|
||||
int effect_value = 0;
|
||||
int lvlModifier = 100;
|
||||
|
||||
@@ -4793,16 +4772,16 @@ int8 Mob::GetDecayEffectValue(uint16 spell_id, uint16 spelleffect) {
|
||||
if (IsValidSpell(buffs[slot].spellid)){
|
||||
for (int i = 0; i < EFFECT_COUNT; i++){
|
||||
if(spells[buffs[slot].spellid].effectid[i] == spelleffect) {
|
||||
|
||||
int critchance = spells[buffs[slot].spellid].base[i];
|
||||
|
||||
int critchance = spells[buffs[slot].spellid].base[i];
|
||||
int decay = spells[buffs[slot].spellid].base2[i];
|
||||
int lvldiff = spell_level - spells[buffs[slot].spellid].max[i];
|
||||
|
||||
int lvldiff = spell_level - spells[buffs[slot].spellid].max[i];
|
||||
|
||||
if(lvldiff > 0 && decay > 0)
|
||||
{
|
||||
lvlModifier -= decay*lvldiff;
|
||||
lvlModifier -= decay*lvldiff;
|
||||
if (lvlModifier > 0){
|
||||
critchance = (critchance*lvlModifier)/100;
|
||||
critchance = (critchance*lvlModifier)/100;
|
||||
effect_value += critchance;
|
||||
}
|
||||
}
|
||||
@@ -4813,7 +4792,7 @@ int8 Mob::GetDecayEffectValue(uint16 spell_id, uint16 spelleffect) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return effect_value;
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -464,6 +464,8 @@ public:
|
||||
bool CheckLosFN(float posX, float posY, float posZ, float mobSize);
|
||||
inline void SetChanged() { pLastChange = Timer::GetCurrentTime(); }
|
||||
inline const uint32 LastChange() const { return pLastChange; }
|
||||
inline void SetLastLosState(bool value) { last_los_check = value; }
|
||||
inline bool CheckLastLosState() const { return last_los_check; }
|
||||
|
||||
//Quest
|
||||
void QuestReward(Client *c = nullptr, uint32 silver = 0, uint32 gold = 0, uint32 platinum = 0);
|
||||
@@ -752,7 +754,8 @@ public:
|
||||
inline const bool IsRooted() const { return rooted || permarooted; }
|
||||
inline const bool HasVirus() const { return has_virus; }
|
||||
int GetSnaredAmount();
|
||||
|
||||
inline const bool IsPseudoRooted() const { return pseudo_rooted; }
|
||||
inline void SetPseudoRoot(bool prState) { pseudo_rooted = prState; }
|
||||
|
||||
int GetCurWp() { return cur_wp; }
|
||||
|
||||
@@ -1119,6 +1122,8 @@ protected:
|
||||
bool has_MGB;
|
||||
bool has_ProjectIllusion;
|
||||
int16 SpellPowerDistanceMod;
|
||||
bool last_los_check;
|
||||
bool pseudo_rooted;
|
||||
|
||||
// Bind wound
|
||||
Timer bindwound_timer;
|
||||
|
||||
+221
-223
@@ -23,15 +23,15 @@
|
||||
#include <algorithm>
|
||||
#include "npc.h"
|
||||
#include "masterentity.h"
|
||||
#include "NpcAI.h"
|
||||
#include "npc_ai.h"
|
||||
#include "map.h"
|
||||
#include "../common/moremath.h"
|
||||
#include "StringIDs.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/features.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "water_map.h"
|
||||
|
||||
extern EntityList entity_list;
|
||||
@@ -541,13 +541,40 @@ void NPC::AI_Start(uint32 iMoveDelay) {
|
||||
void Mob::AI_Stop() {
|
||||
if (!IsAIControlled())
|
||||
return;
|
||||
|
||||
pAIControlled = false;
|
||||
|
||||
safe_delete(AIthink_timer);
|
||||
safe_delete(AIwalking_timer);
|
||||
safe_delete(AImovement_timer);
|
||||
safe_delete(AItarget_check_timer)
|
||||
safe_delete(AItarget_check_timer);
|
||||
safe_delete(AIscanarea_timer);
|
||||
safe_delete(AIfeignremember_timer);
|
||||
safe_delete(PathingLOSCheckTimer);
|
||||
safe_delete(PathingRouteUpdateTimerShort);
|
||||
safe_delete(PathingRouteUpdateTimerLong);
|
||||
|
||||
attack_timer.Disable();
|
||||
attack_dw_timer.Disable();
|
||||
ranged_timer.Disable();
|
||||
tic_timer.Disable();
|
||||
mana_timer.Disable();
|
||||
spellend_timer.Disable();
|
||||
projectile_timer.Disable();
|
||||
rewind_timer.Disable();
|
||||
bindwound_timer.Disable();
|
||||
stunned_timer.Disable();
|
||||
spun_timer.Disable();
|
||||
bardsong_timer.Disable();
|
||||
gravity_timer.Disable();
|
||||
viral_timer.Disable();
|
||||
flee_timer.Disable();
|
||||
|
||||
for (int sat = 0; sat < MAX_SPECIAL_ATTACK; ++sat) {
|
||||
if (SpecialAbilities[sat].timer)
|
||||
SpecialAbilities[sat].timer->Disable();
|
||||
}
|
||||
|
||||
hate_list.Wipe();
|
||||
}
|
||||
|
||||
@@ -1181,7 +1208,7 @@ void Mob::AI_Process() {
|
||||
|
||||
if (GetSpecialAbility(SPECATK_FLURRY)) {
|
||||
int flurry_chance = GetSpecialAbilityParam(SPECATK_FLURRY, 0);
|
||||
flurry_chance = flurry_chance > 0 ? flurry_chance : RuleI(Combat, NPCFlurryChance);
|
||||
flurry_chance = flurry_chance > 0 ? flurry_chance : RuleI(Combat, NPCFlurryChance);
|
||||
|
||||
if (MakeRandomInt(0, 99) < flurry_chance) {
|
||||
ExtraAttackOptions opts;
|
||||
@@ -1215,16 +1242,16 @@ void Mob::AI_Process() {
|
||||
|
||||
if (IsPet() || (IsNPC() && CastToNPC()->GetSwarmOwner())) {
|
||||
Mob *owner = nullptr;
|
||||
|
||||
|
||||
if (IsPet())
|
||||
owner = GetOwner();
|
||||
else
|
||||
else
|
||||
owner = entity_list.GetMobID(CastToNPC()->GetSwarmOwner());
|
||||
|
||||
|
||||
if (owner) {
|
||||
int16 flurry_chance = owner->aabonuses.PetFlurry +
|
||||
owner->spellbonuses.PetFlurry + owner->itembonuses.PetFlurry;
|
||||
|
||||
|
||||
if (flurry_chance && (MakeRandomInt(0, 99) < flurry_chance))
|
||||
Flurry(nullptr);
|
||||
}
|
||||
@@ -1569,11 +1596,7 @@ void Mob::AI_Process() {
|
||||
//Do Ranged attack here
|
||||
if(doranged)
|
||||
{
|
||||
int attacks = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 0);
|
||||
attacks = attacks > 0 ? attacks : 1;
|
||||
for(int i = 0; i < attacks; ++i) {
|
||||
RangedAttack(target);
|
||||
}
|
||||
RangedAttack(target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1604,7 +1627,7 @@ void NPC::AI_DoMovement() {
|
||||
roambox_movingto_x -= movex * 2;
|
||||
if (roambox_movingto_y > roambox_max_y || roambox_movingto_y < roambox_min_y)
|
||||
roambox_movingto_y -= movey * 2;
|
||||
//New coord is still invalid, ignore distance and just pick a new random coord.
|
||||
//New coord is still invalid, ignore distance and just pick a new random coord.
|
||||
//If we're here we may have a roambox where one side is shorter than the specified distance. Commons, Wkarana, etc.
|
||||
if (roambox_movingto_x > roambox_max_x || roambox_movingto_x < roambox_min_x)
|
||||
roambox_movingto_x = MakeRandomFloat(roambox_min_x+1,roambox_max_x-1);
|
||||
@@ -2406,7 +2429,7 @@ bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) {
|
||||
}
|
||||
|
||||
//If any casting variables are defined in the current list, ignore those in the parent list.
|
||||
if (spell_list->fail_recast || spell_list->engaged_no_sp_recast_min || spell_list->engaged_no_sp_recast_max
|
||||
if (spell_list->fail_recast || spell_list->engaged_no_sp_recast_min || spell_list->engaged_no_sp_recast_max
|
||||
|| spell_list->engaged_beneficial_self_chance || spell_list->engaged_beneficial_other_chance || spell_list->engaged_detrimental_chance
|
||||
|| spell_list->pursue_no_sp_recast_min || spell_list->pursue_no_sp_recast_max || spell_list->pursue_detrimental_chance
|
||||
|| spell_list->idle_no_sp_recast_min || spell_list->idle_no_sp_recast_max || spell_list->idle_beneficial_chance) {
|
||||
@@ -2457,7 +2480,7 @@ bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) {
|
||||
AISpellVar.idle_no_sp_recast_min = (_idle_no_sp_recast_min) ? _idle_no_sp_recast_min : RuleI(Spells, AI_IdleNoSpellMinRecast);
|
||||
AISpellVar.idle_no_sp_recast_max = (_idle_no_sp_recast_max) ? _idle_no_sp_recast_max : RuleI(Spells, AI_IdleNoSpellMaxRecast);
|
||||
AISpellVar.idle_beneficial_chance = (_idle_beneficial_chance) ? _idle_beneficial_chance : RuleI(Spells, AI_IdleBeneficialChance);
|
||||
|
||||
|
||||
if (AIspells.size() == 0)
|
||||
AIautocastspell_timer->Disable();
|
||||
else
|
||||
@@ -2469,12 +2492,12 @@ bool NPC::AI_AddNPCSpellsEffects(uint32 iDBSpellsEffectsID) {
|
||||
|
||||
npc_spells_effects_id = iDBSpellsEffectsID;
|
||||
AIspellsEffects.clear();
|
||||
|
||||
if (iDBSpellsEffectsID == 0)
|
||||
|
||||
if (iDBSpellsEffectsID == 0)
|
||||
return false;
|
||||
|
||||
|
||||
DBnpcspellseffects_Struct* spell_effects_list = database.GetNPCSpellsEffects(iDBSpellsEffectsID);
|
||||
|
||||
|
||||
if (!spell_effects_list) {
|
||||
return false;
|
||||
}
|
||||
@@ -2502,9 +2525,9 @@ bool NPC::AI_AddNPCSpellsEffects(uint32 iDBSpellsEffectsID) {
|
||||
if (parentlist) {
|
||||
for (i=0; i<parentlist->numentries; i++) {
|
||||
if (GetLevel() >= parentlist->entries[i].minlevel && GetLevel() <= parentlist->entries[i].maxlevel && parentlist->entries[i].spelleffectid > 0) {
|
||||
if (!IsSpellEffectInList(spell_effects_list, parentlist->entries[i].spelleffectid, parentlist->entries[i].base,
|
||||
if (!IsSpellEffectInList(spell_effects_list, parentlist->entries[i].spelleffectid, parentlist->entries[i].base,
|
||||
parentlist->entries[i].limit, parentlist->entries[i].max))
|
||||
{
|
||||
{
|
||||
AddSpellEffectToNPCList(parentlist->entries[i].spelleffectid,
|
||||
parentlist->entries[i].base, parentlist->entries[i].limit,
|
||||
parentlist->entries[i].max);
|
||||
@@ -2528,10 +2551,10 @@ void NPC::ApplyAISpellEffects(StatBonuses* newbon)
|
||||
{
|
||||
if (!AI_HasSpellsEffects())
|
||||
return;
|
||||
|
||||
|
||||
for(int i=0; i < AIspellsEffects.size(); i++)
|
||||
{
|
||||
ApplySpellsBonuses(0, 0, newbon, 0, false, 0,-1,
|
||||
ApplySpellsBonuses(0, 0, newbon, 0, false, 0,-1,
|
||||
true, AIspellsEffects[i].spelleffectid, AIspellsEffects[i].base, AIspellsEffects[i].limit,AIspellsEffects[i].max);
|
||||
}
|
||||
|
||||
@@ -2541,10 +2564,10 @@ void NPC::ApplyAISpellEffects(StatBonuses* newbon)
|
||||
// adds a spell to the list, taking into account priority and resorting list as needed.
|
||||
void NPC::AddSpellEffectToNPCList(uint16 iSpellEffectID, int32 base, int32 limit, int32 max)
|
||||
{
|
||||
|
||||
|
||||
if(!iSpellEffectID)
|
||||
return;
|
||||
|
||||
|
||||
HasAISpellEffects = true;
|
||||
AISpellsEffects_Struct t;
|
||||
|
||||
@@ -2627,7 +2650,7 @@ void NPC::AISpellsList(Client *c)
|
||||
|
||||
DBnpcspells_Struct* ZoneDatabase::GetNPCSpells(uint32 iDBSpellsID) {
|
||||
if (iDBSpellsID == 0)
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
if (!npc_spells_cache) {
|
||||
npc_spells_maxid = GetMaxNPCSpellsID();
|
||||
@@ -2640,144 +2663,134 @@ DBnpcspells_Struct* ZoneDatabase::GetNPCSpells(uint32 iDBSpellsID) {
|
||||
}
|
||||
|
||||
if (iDBSpellsID > npc_spells_maxid)
|
||||
return 0;
|
||||
return nullptr;
|
||||
if (npc_spells_cache[iDBSpellsID]) { // it's in the cache, easy =)
|
||||
return npc_spells_cache[iDBSpellsID];
|
||||
}
|
||||
|
||||
else if (!npc_spells_loadtried[iDBSpellsID]) { // no reason to ask the DB again if we have failed once already
|
||||
npc_spells_loadtried[iDBSpellsID] = true;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, parent_list, attack_proc, proc_chance, range_proc, rproc_chance, defensive_proc, dproc_chance, fail_recast, engaged_no_sp_recast_min, engaged_no_sp_recast_max, engaged_b_self_chance, engaged_b_other_chance, engaged_d_chance, pursue_no_sp_recast_min, pursue_no_sp_recast_max, pursue_d_chance, idle_no_sp_recast_min, idle_no_sp_recast_max, idle_b_chance from npc_spells where id=%d", iDBSpellsID), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
uint32 tmpparent_list = atoi(row[1]);
|
||||
uint16 tmpattack_proc = atoi(row[2]);
|
||||
uint8 tmpproc_chance = atoi(row[3]);
|
||||
uint16 tmprange_proc = atoi(row[4]);
|
||||
int16 tmprproc_chance = atoi(row[5]);
|
||||
uint16 tmpdefensive_proc = atoi(row[6]);
|
||||
int16 tmpdproc_chance = atoi(row[7]);
|
||||
uint32 tmppfail_recast = atoi(row[8]);
|
||||
uint32 tmpengaged_no_sp_recast_min = atoi(row[9]);
|
||||
uint32 tmpengaged_no_sp_recast_max = atoi(row[10]);
|
||||
uint8 tmpengaged_b_self_chance = atoi(row[11]);
|
||||
uint8 tmpengaged_b_other_chance = atoi(row[12]);
|
||||
uint8 tmpengaged_d_chance = atoi(row[13]);
|
||||
uint32 tmppursue_no_sp_recast_min = atoi(row[14]);
|
||||
uint32 tmppursue_no_sp_recast_max = atoi(row[15]);
|
||||
uint8 tmppursue_d_chance = atoi(row[16]);
|
||||
uint32 tmpidle_no_sp_recast_min = atoi(row[17]);
|
||||
uint32 tmpidle_no_sp_recast_max = atoi(row[18]);
|
||||
uint8 tmpidle_b_chance = atoi(row[19]);
|
||||
mysql_free_result(result);
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT spellid, type, minlevel, maxlevel, manacost, recast_delay, priority, resist_adjust from npc_spells_entries where npc_spells_id=%d ORDER BY minlevel", iDBSpellsID), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
uint32 tmpSize = sizeof(DBnpcspells_Struct) + (sizeof(DBnpcspells_entries_Struct) * mysql_num_rows(result));
|
||||
npc_spells_cache[iDBSpellsID] = (DBnpcspells_Struct*) new uchar[tmpSize];
|
||||
memset(npc_spells_cache[iDBSpellsID], 0, tmpSize);
|
||||
npc_spells_cache[iDBSpellsID]->parent_list = tmpparent_list;
|
||||
npc_spells_cache[iDBSpellsID]->attack_proc = tmpattack_proc;
|
||||
npc_spells_cache[iDBSpellsID]->proc_chance = tmpproc_chance;
|
||||
npc_spells_cache[iDBSpellsID]->range_proc = tmprange_proc;
|
||||
npc_spells_cache[iDBSpellsID]->rproc_chance = tmpdproc_chance;
|
||||
npc_spells_cache[iDBSpellsID]->defensive_proc = tmpdefensive_proc;
|
||||
npc_spells_cache[iDBSpellsID]->dproc_chance = tmpdproc_chance;
|
||||
npc_spells_cache[iDBSpellsID]->fail_recast = tmppfail_recast;
|
||||
npc_spells_cache[iDBSpellsID]->engaged_no_sp_recast_min = tmpengaged_no_sp_recast_min;
|
||||
npc_spells_cache[iDBSpellsID]->engaged_no_sp_recast_max = tmpengaged_no_sp_recast_max;
|
||||
npc_spells_cache[iDBSpellsID]->engaged_beneficial_self_chance = tmpengaged_b_self_chance;
|
||||
npc_spells_cache[iDBSpellsID]->engaged_beneficial_other_chance = tmpengaged_b_other_chance;
|
||||
npc_spells_cache[iDBSpellsID]->engaged_detrimental_chance = tmpengaged_d_chance;
|
||||
npc_spells_cache[iDBSpellsID]->pursue_no_sp_recast_min = tmppursue_no_sp_recast_min;
|
||||
npc_spells_cache[iDBSpellsID]->pursue_no_sp_recast_max = tmppursue_no_sp_recast_max;
|
||||
npc_spells_cache[iDBSpellsID]->pursue_detrimental_chance = tmppursue_d_chance;
|
||||
npc_spells_cache[iDBSpellsID]->idle_no_sp_recast_min = tmpidle_no_sp_recast_min;
|
||||
npc_spells_cache[iDBSpellsID]->idle_no_sp_recast_max = tmpidle_no_sp_recast_max;
|
||||
npc_spells_cache[iDBSpellsID]->idle_beneficial_chance = tmpidle_b_chance;
|
||||
npc_spells_cache[iDBSpellsID]->numentries = mysql_num_rows(result);
|
||||
int j = 0;
|
||||
while ((row = mysql_fetch_row(result))) {
|
||||
int spell_id = atoi(row[0]);
|
||||
npc_spells_cache[iDBSpellsID]->entries[j].spellid = spell_id;
|
||||
npc_spells_cache[iDBSpellsID]->entries[j].type = atoi(row[1]);
|
||||
npc_spells_cache[iDBSpellsID]->entries[j].minlevel = atoi(row[2]);
|
||||
npc_spells_cache[iDBSpellsID]->entries[j].maxlevel = atoi(row[3]);
|
||||
npc_spells_cache[iDBSpellsID]->entries[j].manacost = atoi(row[4]);
|
||||
npc_spells_cache[iDBSpellsID]->entries[j].recast_delay = atoi(row[5]);
|
||||
npc_spells_cache[iDBSpellsID]->entries[j].priority = atoi(row[6]);
|
||||
if(row[7])
|
||||
{
|
||||
npc_spells_cache[iDBSpellsID]->entries[j].resist_adjust = atoi(row[7]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(IsValidSpell(spell_id))
|
||||
{
|
||||
npc_spells_cache[iDBSpellsID]->entries[j].resist_adjust = spells[spell_id].ResistDiff;
|
||||
}
|
||||
}
|
||||
j++;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
return npc_spells_cache[iDBSpellsID];
|
||||
}
|
||||
else {
|
||||
std::cerr << "Error in AddNPCSpells query1 '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mysql_free_result(result);
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cerr << "Error in AddNPCSpells query1 '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
return 0;
|
||||
}
|
||||
std::string query = StringFormat("SELECT id, parent_list, attack_proc, proc_chance, "
|
||||
"range_proc, rproc_chance, defensive_proc, dproc_chance, "
|
||||
"fail_recast, engaged_no_sp_recast_min, engaged_no_sp_recast_max, "
|
||||
"engaged_b_self_chance, engaged_b_other_chance, engaged_d_chance, "
|
||||
"pursue_no_sp_recast_min, pursue_no_sp_recast_max, "
|
||||
"pursue_d_chance, idle_no_sp_recast_min, idle_no_sp_recast_max, "
|
||||
"idle_b_chance FROM npc_spells WHERE id=%d", iDBSpellsID);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
std::cerr << "Error in AddNPCSpells query1 '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
if (results.RowCount() != 1)
|
||||
return nullptr;
|
||||
|
||||
auto row = results.begin();
|
||||
uint32 tmpparent_list = atoi(row[1]);
|
||||
uint16 tmpattack_proc = atoi(row[2]);
|
||||
uint8 tmpproc_chance = atoi(row[3]);
|
||||
uint16 tmprange_proc = atoi(row[4]);
|
||||
int16 tmprproc_chance = atoi(row[5]);
|
||||
uint16 tmpdefensive_proc = atoi(row[6]);
|
||||
int16 tmpdproc_chance = atoi(row[7]);
|
||||
uint32 tmppfail_recast = atoi(row[8]);
|
||||
uint32 tmpengaged_no_sp_recast_min = atoi(row[9]);
|
||||
uint32 tmpengaged_no_sp_recast_max = atoi(row[10]);
|
||||
uint8 tmpengaged_b_self_chance = atoi(row[11]);
|
||||
uint8 tmpengaged_b_other_chance = atoi(row[12]);
|
||||
uint8 tmpengaged_d_chance = atoi(row[13]);
|
||||
uint32 tmppursue_no_sp_recast_min = atoi(row[14]);
|
||||
uint32 tmppursue_no_sp_recast_max = atoi(row[15]);
|
||||
uint8 tmppursue_d_chance = atoi(row[16]);
|
||||
uint32 tmpidle_no_sp_recast_min = atoi(row[17]);
|
||||
uint32 tmpidle_no_sp_recast_max = atoi(row[18]);
|
||||
uint8 tmpidle_b_chance = atoi(row[19]);
|
||||
|
||||
query = StringFormat("SELECT spellid, type, minlevel, maxlevel, "
|
||||
"manacost, recast_delay, priority, resist_adjust "
|
||||
"FROM npc_spells_entries "
|
||||
"WHERE npc_spells_id=%d ORDER BY minlevel", iDBSpellsID);
|
||||
results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
{
|
||||
std::cerr << "Error in AddNPCSpells query1 '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32 tmpSize = sizeof(DBnpcspells_Struct) + (sizeof(DBnpcspells_entries_Struct) * results.RowCount());
|
||||
npc_spells_cache[iDBSpellsID] = (DBnpcspells_Struct*) new uchar[tmpSize];
|
||||
memset(npc_spells_cache[iDBSpellsID], 0, tmpSize);
|
||||
npc_spells_cache[iDBSpellsID]->parent_list = tmpparent_list;
|
||||
npc_spells_cache[iDBSpellsID]->attack_proc = tmpattack_proc;
|
||||
npc_spells_cache[iDBSpellsID]->proc_chance = tmpproc_chance;
|
||||
npc_spells_cache[iDBSpellsID]->range_proc = tmprange_proc;
|
||||
npc_spells_cache[iDBSpellsID]->rproc_chance = tmpdproc_chance;
|
||||
npc_spells_cache[iDBSpellsID]->defensive_proc = tmpdefensive_proc;
|
||||
npc_spells_cache[iDBSpellsID]->dproc_chance = tmpdproc_chance;
|
||||
npc_spells_cache[iDBSpellsID]->fail_recast = tmppfail_recast;
|
||||
npc_spells_cache[iDBSpellsID]->engaged_no_sp_recast_min = tmpengaged_no_sp_recast_min;
|
||||
npc_spells_cache[iDBSpellsID]->engaged_no_sp_recast_max = tmpengaged_no_sp_recast_max;
|
||||
npc_spells_cache[iDBSpellsID]->engaged_beneficial_self_chance = tmpengaged_b_self_chance;
|
||||
npc_spells_cache[iDBSpellsID]->engaged_beneficial_other_chance = tmpengaged_b_other_chance;
|
||||
npc_spells_cache[iDBSpellsID]->engaged_detrimental_chance = tmpengaged_d_chance;
|
||||
npc_spells_cache[iDBSpellsID]->pursue_no_sp_recast_min = tmppursue_no_sp_recast_min;
|
||||
npc_spells_cache[iDBSpellsID]->pursue_no_sp_recast_max = tmppursue_no_sp_recast_max;
|
||||
npc_spells_cache[iDBSpellsID]->pursue_detrimental_chance = tmppursue_d_chance;
|
||||
npc_spells_cache[iDBSpellsID]->idle_no_sp_recast_min = tmpidle_no_sp_recast_min;
|
||||
npc_spells_cache[iDBSpellsID]->idle_no_sp_recast_max = tmpidle_no_sp_recast_max;
|
||||
npc_spells_cache[iDBSpellsID]->idle_beneficial_chance = tmpidle_b_chance;
|
||||
npc_spells_cache[iDBSpellsID]->numentries = results.RowCount();
|
||||
|
||||
int entryIndex = 0;
|
||||
for (row = results.begin(); row != results.end(); ++row, ++entryIndex)
|
||||
{
|
||||
int spell_id = atoi(row[0]);
|
||||
npc_spells_cache[iDBSpellsID]->entries[entryIndex].spellid = spell_id;
|
||||
npc_spells_cache[iDBSpellsID]->entries[entryIndex].type = atoi(row[1]);
|
||||
npc_spells_cache[iDBSpellsID]->entries[entryIndex].minlevel = atoi(row[2]);
|
||||
npc_spells_cache[iDBSpellsID]->entries[entryIndex].maxlevel = atoi(row[3]);
|
||||
npc_spells_cache[iDBSpellsID]->entries[entryIndex].manacost = atoi(row[4]);
|
||||
npc_spells_cache[iDBSpellsID]->entries[entryIndex].recast_delay = atoi(row[5]);
|
||||
npc_spells_cache[iDBSpellsID]->entries[entryIndex].priority = atoi(row[6]);
|
||||
|
||||
if(row[7])
|
||||
npc_spells_cache[iDBSpellsID]->entries[entryIndex].resist_adjust = atoi(row[7]);
|
||||
else if(IsValidSpell(spell_id))
|
||||
npc_spells_cache[iDBSpellsID]->entries[entryIndex].resist_adjust = spells[spell_id].ResistDiff;
|
||||
}
|
||||
|
||||
return npc_spells_cache[iDBSpellsID];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32 ZoneDatabase::GetMaxNPCSpellsID() {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT max(id) from npc_spells"), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
uint32 ret = 0;
|
||||
if (row[0])
|
||||
ret = atoi(row[0]);
|
||||
mysql_free_result(result);
|
||||
return ret;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
std::cerr << "Error in GetMaxNPCSpellsID query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
std::string query = "SELECT max(id) from npc_spells";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
std::cerr << "Error in GetMaxNPCSpellsID query '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
if (!row[0])
|
||||
return 0;
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
DBnpcspellseffects_Struct* ZoneDatabase::GetNPCSpellsEffects(uint32 iDBSpellsEffectsID) {
|
||||
if (iDBSpellsEffectsID == 0)
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
if (!npc_spellseffects_cache) {
|
||||
npc_spellseffects_maxid = GetMaxNPCSpellsEffectsID();
|
||||
@@ -2790,89 +2803,74 @@ DBnpcspellseffects_Struct* ZoneDatabase::GetNPCSpellsEffects(uint32 iDBSpellsEff
|
||||
}
|
||||
|
||||
if (iDBSpellsEffectsID > npc_spellseffects_maxid)
|
||||
return 0;
|
||||
if (npc_spellseffects_cache[iDBSpellsEffectsID]) { // it's in the cache, easy =)
|
||||
return nullptr;
|
||||
|
||||
if (npc_spellseffects_cache[iDBSpellsEffectsID]) // it's in the cache, easy =)
|
||||
return npc_spellseffects_cache[iDBSpellsEffectsID];
|
||||
}
|
||||
|
||||
else if (!npc_spellseffects_loadtried[iDBSpellsEffectsID]) { // no reason to ask the DB again if we have failed once already
|
||||
npc_spellseffects_loadtried[iDBSpellsEffectsID] = true;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
if (npc_spellseffects_loadtried[iDBSpellsEffectsID])
|
||||
return nullptr;
|
||||
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, parent_list from npc_spells_effects where id=%d", iDBSpellsEffectsID), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
uint32 tmpparent_list = atoi(row[1]);
|
||||
mysql_free_result(result);
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT spell_effect_id, minlevel, maxlevel,se_base, se_limit, se_max from npc_spells_effects_entries where npc_spells_effects_id=%d ORDER BY minlevel", iDBSpellsEffectsID), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
uint32 tmpSize = sizeof(DBnpcspellseffects_Struct) + (sizeof(DBnpcspellseffects_entries_Struct) * mysql_num_rows(result));
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID] = (DBnpcspellseffects_Struct*) new uchar[tmpSize];
|
||||
memset(npc_spellseffects_cache[iDBSpellsEffectsID], 0, tmpSize);
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->parent_list = tmpparent_list;
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->numentries = mysql_num_rows(result);
|
||||
int j = 0;
|
||||
while ((row = mysql_fetch_row(result))) {
|
||||
int spell_effect_id = atoi(row[0]);
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->entries[j].spelleffectid = spell_effect_id;
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->entries[j].minlevel = atoi(row[1]);
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->entries[j].maxlevel = atoi(row[2]);
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->entries[j].base = atoi(row[3]);
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->entries[j].limit = atoi(row[4]);
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->entries[j].max = atoi(row[5]);
|
||||
j++;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
return npc_spellseffects_cache[iDBSpellsEffectsID];
|
||||
}
|
||||
else {
|
||||
std::cerr << "Error in AddNPCSpells query1 '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mysql_free_result(result);
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cerr << "Error in AddNPCSpells query1 '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
npc_spellseffects_loadtried[iDBSpellsEffectsID] = true;
|
||||
|
||||
std::string query = StringFormat("SELECT id, parent_list FROM npc_spells_effects WHERE id=%d", iDBSpellsEffectsID);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
std::cerr << "Error in AddNPCSpells query1 '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return nullptr;
|
||||
|
||||
auto row = results.begin();
|
||||
uint32 tmpparent_list = atoi(row[1]);
|
||||
|
||||
query = StringFormat("SELECT spell_effect_id, minlevel, "
|
||||
"maxlevel,se_base, se_limit, se_max "
|
||||
"FROM npc_spells_effects_entries "
|
||||
"WHERE npc_spells_effects_id = %d ORDER BY minlevel", iDBSpellsEffectsID);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return nullptr;
|
||||
|
||||
uint32 tmpSize = sizeof(DBnpcspellseffects_Struct) + (sizeof(DBnpcspellseffects_entries_Struct) * results.RowCount());
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID] = (DBnpcspellseffects_Struct*) new uchar[tmpSize];
|
||||
memset(npc_spellseffects_cache[iDBSpellsEffectsID], 0, tmpSize);
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->parent_list = tmpparent_list;
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->numentries = results.RowCount();
|
||||
|
||||
int entryIndex = 0;
|
||||
for (row = results.begin(); row != results.end(); ++row, ++entryIndex)
|
||||
{
|
||||
int spell_effect_id = atoi(row[0]);
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->entries[entryIndex].spelleffectid = spell_effect_id;
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->entries[entryIndex].minlevel = atoi(row[1]);
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->entries[entryIndex].maxlevel = atoi(row[2]);
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->entries[entryIndex].base = atoi(row[3]);
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->entries[entryIndex].limit = atoi(row[4]);
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->entries[entryIndex].max = atoi(row[5]);
|
||||
}
|
||||
|
||||
return npc_spellseffects_cache[iDBSpellsEffectsID];
|
||||
}
|
||||
|
||||
uint32 ZoneDatabase::GetMaxNPCSpellsEffectsID() {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT max(id) from npc_spells_effects"), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
uint32 ret = 0;
|
||||
if (row[0])
|
||||
ret = atoi(row[0]);
|
||||
mysql_free_result(result);
|
||||
return ret;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
std::cerr << "Error in GetMaxNPCSpellsEffectsID query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
std::string query = "SELECT max(id) FROM npc_spells_effects";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
std::cerr << "Error in GetMaxNPCSpellsEffectsID query '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
if (!row[0])
|
||||
return 0;
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "mob.h"
|
||||
#include "client.h"
|
||||
#include "worldserver.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "event_codes.h"
|
||||
#include "embparser.h"
|
||||
#include <string>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "mob.h"
|
||||
#include "client.h"
|
||||
#include "worldserver.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "event_codes.h"
|
||||
#include "embparser.h"
|
||||
#include <string>
|
||||
|
||||
+16
-12
@@ -22,20 +22,20 @@
|
||||
#include "../common/features.h"
|
||||
#include "../common/queue.h"
|
||||
#include "../common/timer.h"
|
||||
#include "../common/EQStream.h"
|
||||
#include "../common/EQStreamFactory.h"
|
||||
#include "../common/eq_stream.h"
|
||||
#include "../common/eq_stream_factory.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/Mutex.h"
|
||||
#include "../common/mutex.h"
|
||||
#include "../common/version.h"
|
||||
#include "../common/EQEMuError.h"
|
||||
#include "../common/eqemu_error.h"
|
||||
#include "../common/packet_dump_file.h"
|
||||
#include "../common/opcodemgr.h"
|
||||
#include "../common/guilds.h"
|
||||
#include "../common/EQStreamIdent.h"
|
||||
#include "../common/eq_stream_ident.h"
|
||||
#include "../common/patches/patches.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/platform.h"
|
||||
#include "../common/crash.h"
|
||||
#include "../common/ipc_mutex.h"
|
||||
@@ -43,18 +43,19 @@
|
||||
#include "../common/eqemu_exception.h"
|
||||
#include "../common/spdat.h"
|
||||
|
||||
#include "ZoneConfig.h"
|
||||
#include "zone_config.h"
|
||||
#include "masterentity.h"
|
||||
#include "worldserver.h"
|
||||
#include "net.h"
|
||||
#include "zone.h"
|
||||
#include "queryserv.h"
|
||||
#include "command.h"
|
||||
#include "ZoneConfig.h"
|
||||
#include "zone_config.h"
|
||||
#include "titles.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "tasks.h"
|
||||
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "embparser.h"
|
||||
#include "lua_parser.h"
|
||||
#include "client_logs.h"
|
||||
@@ -98,6 +99,7 @@ npcDecayTimes_Struct npcCorpseDecayTimes[100];
|
||||
TitleManager title_manager;
|
||||
DBAsyncFinishedQueue MTdbafq;
|
||||
DBAsync *dbasync = nullptr;
|
||||
QueryServ *QServ = 0;
|
||||
TaskManager *taskmanager = 0;
|
||||
QuestParserCollection *parse = 0;
|
||||
|
||||
@@ -114,6 +116,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
const char *zone_name;
|
||||
|
||||
QServ = new QueryServ;
|
||||
|
||||
if(argc == 3) {
|
||||
worldserver.SetLauncherName(argv[2]);
|
||||
worldserver.SetLaunchedName(argv[1]);
|
||||
@@ -622,7 +626,7 @@ void LoadSpells(EQEmu::MemoryMappedFile **mmf) {
|
||||
SPDAT_RECORDS = records;
|
||||
}
|
||||
|
||||
|
||||
/* Update Window Title with relevant information */
|
||||
void UpdateWindowTitle(char* iNewTitle) {
|
||||
#ifdef _WINDOWS
|
||||
char tmp[500];
|
||||
@@ -634,7 +638,7 @@ void UpdateWindowTitle(char* iNewTitle) {
|
||||
#if defined(GOTFRAGS) || defined(_EQDEBUG)
|
||||
snprintf(tmp, sizeof(tmp), "%i: %s, %i clients, %i", ZoneConfig::get()->ZonePort, zone->GetShortName(), numclients, getpid());
|
||||
#else
|
||||
snprintf(tmp, sizeof(tmp), "%i: %s, %i clients", ZoneConfig::get()->ZonePort, zone->GetShortName(), numclients);
|
||||
snprintf(tmp, sizeof(tmp), "%s :: clients: %i inst_id: %i inst_ver: %i :: port: %i", zone->GetShortName(), numclients, zone->GetInstanceID(), zone->GetInstanceVersion(), ZoneConfig::get()->ZonePort);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
||||
+4
-4
@@ -40,10 +40,10 @@
|
||||
#include "../common/spdat.h"
|
||||
#include "../common/bodytypes.h"
|
||||
#include "spawngroup.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "StringIDs.h"
|
||||
#include "string_ids.h"
|
||||
|
||||
//#define SPELLQUEUE //Use only if you want to be spammed by spell testing
|
||||
|
||||
@@ -52,7 +52,7 @@ extern Zone* zone;
|
||||
extern volatile bool ZoneLoaded;
|
||||
extern EntityList entity_list;
|
||||
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
|
||||
NPC::NPC(const NPCType* d, Spawn2* in_respawn, float x, float y, float z, float heading, int iflymode, bool IsCorpse)
|
||||
: Mob(d->name,
|
||||
|
||||
+4
-1
@@ -29,7 +29,7 @@ class NPC;
|
||||
#include "spawn2.h"
|
||||
#include "../common/loottable.h"
|
||||
#include "zonedump.h"
|
||||
#include "QGlobals.h"
|
||||
#include "qglobals.h"
|
||||
#include "../common/rulesys.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
@@ -390,6 +390,8 @@ 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, SkillUseTypes skillinuse, int hand, const Item_Struct* weapon, Mob* other);
|
||||
void mod_npc_killed_merit(Mob* c);
|
||||
@@ -504,6 +506,7 @@ protected:
|
||||
std::list<MercData> mercDataList;
|
||||
|
||||
bool raid_target;
|
||||
uint8 probability;
|
||||
|
||||
private:
|
||||
uint32 loottable_id;
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
#include "zonedb.h"
|
||||
#include "../common/packet_functions.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/features.h"
|
||||
#include "StringIDs.h"
|
||||
#include "string_ids.h"
|
||||
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
|
||||
const char DEFAULT_OBJECT_NAME[] = "IT63_ACTORDEF";
|
||||
const char DEFAULT_OBJECT_NAME_SUFFIX[] = "_ACTORDEF";
|
||||
@@ -560,9 +560,6 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object)
|
||||
// Add new Zone Object (theoretically only called for items dropped to ground)
|
||||
uint32 ZoneDatabase::AddObject(uint32 type, uint32 icon, const Object_Struct& object, const ItemInst* inst)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
|
||||
uint32 database_id = 0;
|
||||
uint32 item_id = 0;
|
||||
int16 charges = 0;
|
||||
@@ -577,35 +574,30 @@ uint32 ZoneDatabase::AddObject(uint32 type, uint32 icon, const Object_Struct& ob
|
||||
char* object_name = new char[len];
|
||||
DoEscapeString(object_name, object.object_name, strlen(object.object_name));
|
||||
|
||||
// Construct query
|
||||
uint32 len_query = MakeAnyLenString(&query,
|
||||
"insert into object (zoneid, xpos, ypos, zpos, heading, itemid, charges, objectname, "
|
||||
"type, icon) values (%i, %f, %f, %f, %f, %i, %i, '%s', %i, %i)",
|
||||
object.zone_id, object.x, object.y, object.z, object.heading,
|
||||
item_id, charges, object_name, type, icon);
|
||||
|
||||
// Save new record for object
|
||||
if (!RunQuery(query, len_query, errbuf, nullptr, nullptr, &database_id)) {
|
||||
LogFile->write(EQEMuLog::Error, "Unable to insert object: %s", errbuf);
|
||||
}
|
||||
else {
|
||||
// Save container contents, if container
|
||||
if (inst && inst->IsType(ItemClassContainer)) {
|
||||
SaveWorldContainer(object.zone_id, database_id, inst);
|
||||
}
|
||||
// Save new record for object
|
||||
std::string query = StringFormat("INSERT INTO object "
|
||||
"(zoneid, xpos, ypos, zpos, heading, "
|
||||
"itemid, charges, objectname, type, icon) "
|
||||
"values (%i, %f, %f, %f, %f, %i, %i, '%s', %i, %i)",
|
||||
object.zone_id, object.x, object.y, object.z, object.heading,
|
||||
item_id, charges, object_name, type, icon);
|
||||
safe_delete_array(object_name);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Unable to insert object: %s", results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
safe_delete_array(object_name);
|
||||
safe_delete_array(query);
|
||||
// Save container contents, if container
|
||||
if (inst && inst->IsType(ItemClassContainer))
|
||||
SaveWorldContainer(object.zone_id, database_id, inst);
|
||||
|
||||
return database_id;
|
||||
}
|
||||
|
||||
// Update information about existing object in database
|
||||
void ZoneDatabase::UpdateObject(uint32 id, uint32 type, uint32 icon, const Object_Struct& object, const ItemInst* inst)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
|
||||
uint32 item_id = 0;
|
||||
int16 charges = 0;
|
||||
|
||||
@@ -619,77 +611,63 @@ void ZoneDatabase::UpdateObject(uint32 id, uint32 type, uint32 icon, const Objec
|
||||
char* object_name = new char[len];
|
||||
DoEscapeString(object_name, object.object_name, strlen(object.object_name));
|
||||
|
||||
// Construct query
|
||||
uint32 len_query = MakeAnyLenString(&query,
|
||||
"update object set zoneid=%i, xpos=%f, ypos=%f, zpos=%f, heading=%f, "
|
||||
"itemid=%i, charges=%i, objectname='%s', type=%i, icon=%i where id=%i",
|
||||
object.zone_id, object.x, object.y, object.z, object.heading,
|
||||
item_id, charges, object_name, type, icon, id);
|
||||
|
||||
// Save new record for object
|
||||
if (!RunQuery(query, len_query, errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Unable to update object: %s", errbuf);
|
||||
}
|
||||
else {
|
||||
// Save container contents, if container
|
||||
if (inst && inst->IsType(ItemClassContainer)) {
|
||||
SaveWorldContainer(object.zone_id, id, inst);
|
||||
}
|
||||
std::string query = StringFormat("UPDATE object SET "
|
||||
"zoneid = %i, xpos = %f, ypos = %f, zpos = %f, heading = %f, "
|
||||
"itemid = %i, charges = %i, objectname = '%s', type = %i, icon = %i "
|
||||
"WHERE id = %i",
|
||||
object.zone_id, object.x, object.y, object.z, object.heading,
|
||||
item_id, charges, object_name, type, icon, id);
|
||||
safe_delete_array(object_name);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Unable to update object: %s", results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
safe_delete_array(object_name);
|
||||
safe_delete_array(query);
|
||||
// Save container contents, if container
|
||||
if (inst && inst->IsType(ItemClassContainer))
|
||||
SaveWorldContainer(object.zone_id, id, inst);
|
||||
}
|
||||
Ground_Spawns* ZoneDatabase::LoadGroundSpawns(uint32 zone_id, int16 version, Ground_Spawns* gs){
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT max_x,max_y,max_z,min_x,min_y,heading,name,item,max_allowed,respawn_timer from ground_spawns where zoneid=%i and (version=%u OR version=-1) limit 50", zone_id, version), errbuf, &result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
int i=0;
|
||||
while( (row=mysql_fetch_row(result) ) ) {
|
||||
gs->spawn[i].max_x=atof(row[0]);
|
||||
gs->spawn[i].max_y=atof(row[1]);
|
||||
gs->spawn[i].max_z=atof(row[2]);
|
||||
gs->spawn[i].min_x=atof(row[3]);
|
||||
gs->spawn[i].min_y=atof(row[4]);
|
||||
gs->spawn[i].heading=atof(row[5]);
|
||||
strcpy(gs->spawn[i].name,row[6]);
|
||||
gs->spawn[i].item=atoi(row[7]);
|
||||
gs->spawn[i].max_allowed=atoi(row[8]);
|
||||
gs->spawn[i].respawntimer=atoi(row[9]);
|
||||
i++;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
std::cerr << "Error in LoadGroundSpawns query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
Ground_Spawns* ZoneDatabase::LoadGroundSpawns(uint32 zone_id, int16 version, Ground_Spawns* gs) {
|
||||
|
||||
std::string query = StringFormat("SELECT max_x, max_y, max_z, "
|
||||
"min_x, min_y, heading, name, "
|
||||
"item, max_allowed, respawn_timer "
|
||||
"FROM ground_spawns "
|
||||
"WHERE zoneid = %i AND (version = %u OR version = -1) "
|
||||
"LIMIT 50", zone_id, version);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
std::cerr << "Error in LoadGroundSpawns query '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return gs;
|
||||
}
|
||||
|
||||
int spawnIndex=0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row, ++spawnIndex) {
|
||||
gs->spawn[spawnIndex].max_x=atof(row[0]);
|
||||
gs->spawn[spawnIndex].max_y=atof(row[1]);
|
||||
gs->spawn[spawnIndex].max_z=atof(row[2]);
|
||||
gs->spawn[spawnIndex].min_x=atof(row[3]);
|
||||
gs->spawn[spawnIndex].min_y=atof(row[4]);
|
||||
gs->spawn[spawnIndex].heading=atof(row[5]);
|
||||
strcpy(gs->spawn[spawnIndex].name,row[6]);
|
||||
gs->spawn[spawnIndex].item=atoi(row[7]);
|
||||
gs->spawn[spawnIndex].max_allowed=atoi(row[8]);
|
||||
gs->spawn[spawnIndex].respawntimer=atoi(row[9]);
|
||||
}
|
||||
return gs;
|
||||
}
|
||||
|
||||
void ZoneDatabase::DeleteObject(uint32 id)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
|
||||
// Construct query
|
||||
uint32 len_query = MakeAnyLenString(&query,
|
||||
"delete from object where id=%i", id);
|
||||
|
||||
// Save new record for object
|
||||
if (!RunQuery(query, len_query, errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Unable to delete object: %s", errbuf);
|
||||
// delete record of object
|
||||
std::string query = StringFormat("DELETE FROM object WHERE id = %i", id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Unable to delete object: %s", results.ErrorMessage().c_str());
|
||||
}
|
||||
//else {
|
||||
// Delete contained items, if any
|
||||
// DeleteWorldContainer(id);
|
||||
//}
|
||||
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
uint32 Object::GetDBID()
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
#include "../common/linked_list.h"
|
||||
#include "../common/emu_opcodes.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/Item.h"
|
||||
#include "../common/item.h"
|
||||
#include "client.h"
|
||||
#include "mob.h"
|
||||
#include "npc.h"
|
||||
|
||||
+3
-3
@@ -67,12 +67,12 @@ extern volatile bool ZoneLoaded;
|
||||
|
||||
#include "../common/queue.h"
|
||||
#include "../common/timer.h"
|
||||
#include "../common/EQStream.h"
|
||||
#include "../common/eq_stream.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/Mutex.h"
|
||||
#include "../common/mutex.h"
|
||||
#include "../common/version.h"
|
||||
#include "../common/files.h"
|
||||
#include "../common/EQEMuError.h"
|
||||
#include "../common/eqemu_error.h"
|
||||
#include "../common/packet_dump_file.h"
|
||||
|
||||
#include "masterentity.h"
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
#include <fstream>
|
||||
#include "pathing.h"
|
||||
#include "water_map.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "doors.h"
|
||||
#include "client.h"
|
||||
#include "zone.h"
|
||||
|
||||
+37
-2
@@ -1259,7 +1259,24 @@ XS(XS_Client_MovePC)
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->MovePC(zoneID, x, y, z, heading);
|
||||
if (THIS->IsClient()) {
|
||||
THIS->MovePC(zoneID, x, y, z, heading);
|
||||
}
|
||||
else {
|
||||
if (THIS->IsMerc())
|
||||
_log(CLIENT__ERROR, "Perl(XS_Client_MovePC) attempted to process a type Merc reference");
|
||||
else if (THIS->IsNPC())
|
||||
_log(CLIENT__ERROR, "Perl(XS_Client_MovePC) attempted to process a type NPC reference");
|
||||
#ifdef BOTS
|
||||
else if (THIS->IsBot())
|
||||
_log(CLIENT__ERROR, "Perl(XS_Client_MovePC) attempted to process a type Bot reference");
|
||||
#endif
|
||||
else
|
||||
_log(CLIENT__ERROR, "Perl(XS_Client_MovePC) attempted to process an Unknown type reference");
|
||||
|
||||
Perl_croak(aTHX_ "THIS is not of type Client");
|
||||
}
|
||||
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
@@ -1288,7 +1305,25 @@ XS(XS_Client_MovePCInstance)
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->MovePC(zoneID, instanceID, x, y, z, heading);
|
||||
if (THIS->IsClient()) {
|
||||
THIS->MovePC(zoneID, instanceID, x, y, z, heading);
|
||||
}
|
||||
else {
|
||||
if (THIS->IsMerc())
|
||||
_log(CLIENT__ERROR, "Perl(XS_Client_MovePCInstance) attempted to process a type Merc reference");
|
||||
else if (THIS->IsNPC())
|
||||
_log(CLIENT__ERROR, "Perl(XS_Client_MovePCInstance) attempted to process a type NPC reference");
|
||||
#ifdef BOTS
|
||||
else if (THIS->IsBot())
|
||||
_log(CLIENT__ERROR, "Perl(XS_Client_MovePCInstance) attempted to process a type Bot reference");
|
||||
#endif
|
||||
else
|
||||
_log(CLIENT__ERROR, "Perl(XS_Client_MovePCInstance) attempted to process an Unknown type reference");
|
||||
|
||||
Perl_croak(aTHX_ "THIS is not of type Client");
|
||||
|
||||
Perl_croak(aTHX_ "THIS is not of type Client");
|
||||
}
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
@@ -2145,6 +2145,54 @@ XS(XS_NPC_GetScore)
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_NPC_SetMerchantProbability);
|
||||
XS(XS_NPC_SetMerchantProbability) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: NPC::SetMerchantProbability(THIS, Probability)");
|
||||
{
|
||||
NPC *THIS;
|
||||
uint8 Probability = (uint8)SvIV(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "NPC")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(NPC *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type NPC");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->SetMerchantProbability(Probability);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_NPC_GetMerchantProbability);
|
||||
XS(XS_NPC_GetMerchantProbability) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: NPC::GetMerchantProbability(THIS)");
|
||||
{
|
||||
NPC *THIS;
|
||||
uint8 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "NPC")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(NPC *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type NPC");
|
||||
if(THIS == NULL)
|
||||
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetMerchantProbability();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
@@ -2243,6 +2291,8 @@ XS(boot_NPC)
|
||||
newXSproto(strcpy(buf, "GetAccuracyRating"), XS_NPC_GetAccuracyRating, file, "$");
|
||||
newXSproto(strcpy(buf, "GetSpawnKillCount"), XS_NPC_GetSpawnKillCount, file, "$");
|
||||
newXSproto(strcpy(buf, "GetScore"), XS_NPC_GetScore, file, "$");
|
||||
newXSproto(strcpy(buf, "SetMerchantProbability"), XS_NPC_SetMerchantProbability, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetMerchantProbability"), XS_NPC_GetMerchantProbability, file, "$");
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#undef seed
|
||||
#endif
|
||||
|
||||
#include "../common/Item.h"
|
||||
#include "../common/item.h"
|
||||
|
||||
#ifdef THIS /* this macro seems to leak out on some systems */
|
||||
#undef THIS
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
#include "entity.h"
|
||||
#include "../common/opcodemgr.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/misc_functions.h"
|
||||
|
||||
PerlPacket::PerlPacket(const char *opcode, uint32 length) {
|
||||
SetOpcode(opcode);
|
||||
|
||||
+66
-71
@@ -32,7 +32,7 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/packet_functions.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/packet_dump_file.h"
|
||||
@@ -216,100 +216,95 @@ void PetitionList::UpdatePetition(Petition* pet) {
|
||||
}
|
||||
|
||||
void ZoneDatabase::DeletePetitionFromDB(Petition* wpet) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
uint32 affected_rows = 0;
|
||||
uint8 checkedout = 0;
|
||||
if (wpet->CheckedOut()) checkedout = 0;
|
||||
else checkedout = 1;
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE from petitions where petid = %i", wpet->GetID()), errbuf, 0, &affected_rows)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in DeletePetitionFromDB query '%s': %s", query, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
return;
|
||||
std::string query = StringFormat("DELETE FROM petitions WHERE petid = %i", wpet->GetID());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error in DeletePetitionFromDB query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
|
||||
}
|
||||
|
||||
void ZoneDatabase::UpdatePetitionToDB(Petition* wpet) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
uint32 affected_rows = 0;
|
||||
uint8 checkedout = 0;
|
||||
if (wpet->CheckedOut()) checkedout = 1;
|
||||
else checkedout = 0;
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE petitions set gmtext = '%s', lastgm = '%s', urgency = %i, checkouts = %i, unavailables = %i, ischeckedout = %i where petid = %i", wpet->GetGMText(), wpet->GetLastGM(), wpet->GetUrgency(), wpet->GetCheckouts(), wpet->GetUnavails(), checkedout, wpet->GetID()), errbuf, 0, &affected_rows)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in UpdatePetitionToDB query '%s': %s", query, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
return;
|
||||
|
||||
std::string query = StringFormat("UPDATE petitions SET gmtext = '%s', lastgm = '%s', urgency = %i, "
|
||||
"checkouts = %i, unavailables = %i, ischeckedout = %i "
|
||||
"WHERE petid = %i",
|
||||
wpet->GetGMText(), wpet->GetLastGM(), wpet->GetUrgency(),
|
||||
wpet->GetCheckouts(), wpet->GetUnavails(),
|
||||
wpet->CheckedOut() ? 1: 0, wpet->GetID());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error in UpdatePetitionToDB query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ZoneDatabase::InsertPetitionToDB(Petition* wpet)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
uint32 affected_rows = 0;
|
||||
uint8 checkedout = 0;
|
||||
if (wpet->CheckedOut())
|
||||
checkedout = 1;
|
||||
else
|
||||
checkedout = 0;
|
||||
|
||||
uint32 len = strlen(wpet->GetPetitionText());
|
||||
char* petitiontext = new char[2*len+1];
|
||||
memset(petitiontext, 0, 2*len+1);
|
||||
DoEscapeString(petitiontext, wpet->GetPetitionText(), len);
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO petitions (petid, charname, accountname, lastgm, petitiontext, zone, urgency, charclass, charrace, charlevel, checkouts, unavailables, ischeckedout, senttime, gmtext) values (%i,'%s','%s','%s','%s',%i,%i,%i,%i,%i,%i,%i,%i,%i, '%s')", wpet->GetID(), wpet->GetCharName(), wpet->GetAccountName(), wpet->GetLastGM(), petitiontext, wpet->GetZone(), wpet->GetUrgency(), wpet->GetCharClass(), wpet->GetCharRace(), wpet->GetCharLevel(), wpet->GetCheckouts(), wpet->GetUnavails(), checkedout, wpet->GetSentTime(), wpet->GetGMText()), errbuf, 0, &affected_rows)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in InsertPetitionToDB query '%s': %s", query, errbuf);
|
||||
|
||||
std::string query = StringFormat("INSERT INTO petitions "
|
||||
"(petid, charname, accountname, lastgm, "
|
||||
"petitiontext, zone, urgency, charclass, "
|
||||
"charrace, charlevel, checkouts, unavailables, "
|
||||
"ischeckedout, senttime, gmtext) "
|
||||
"VALUES (%i, '%s', '%s', '%s', '%s', "
|
||||
"%i, %i, %i, %i, %i, "
|
||||
"%i, %i, %i, %i, '%s')",
|
||||
wpet->GetID(), wpet->GetCharName(), wpet->GetAccountName(), wpet->GetLastGM(),
|
||||
petitiontext, wpet->GetZone(), wpet->GetUrgency(), wpet->GetCharClass(),
|
||||
wpet->GetCharRace(), wpet->GetCharLevel(), wpet->GetCheckouts(), wpet->GetUnavails(),
|
||||
wpet->CheckedOut()? 1: 0, wpet->GetSentTime(), wpet->GetGMText());
|
||||
safe_delete_array(petitiontext);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in InsertPetitionToDB query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
safe_delete_array(petitiontext);
|
||||
safe_delete_array(query);
|
||||
#if EQDEBUG >= 5
|
||||
LogFile->write(EQEMuLog::Debug, "New petition created");
|
||||
#endif
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
void ZoneDatabase::RefreshPetitionsFromDB()
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
Petition* newpet;
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT petid, charname, accountname, lastgm, petitiontext, zone, urgency, charclass, charrace, charlevel, checkouts, unavailables, ischeckedout, senttime, gmtext from petitions order by petid"), errbuf, &result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
while ((row = mysql_fetch_row(result))) {
|
||||
newpet = new Petition(atoi(row[0]));
|
||||
newpet->SetCName(row[1]);
|
||||
newpet->SetAName(row[2]);
|
||||
newpet->SetLastGM(row[3]);
|
||||
newpet->SetPetitionText(row[4]);
|
||||
newpet->SetZone(atoi(row[5]));
|
||||
newpet->SetUrgency(atoi(row[6]));
|
||||
newpet->SetClass(atoi(row[7]));
|
||||
newpet->SetRace(atoi(row[8]));
|
||||
newpet->SetLevel(atoi(row[9]));
|
||||
newpet->SetCheckouts(atoi(row[10]));
|
||||
newpet->SetUnavails(atoi(row[11]));
|
||||
newpet->SetSentTime2(atol(row[13]));
|
||||
newpet->SetGMText(row[14]);
|
||||
std::cout << "Petition " << row[0] << " pettime = " << newpet->GetSentTime() << std::endl;
|
||||
if (atoi(row[12]) == 1) newpet->SetCheckedOut(true);
|
||||
else newpet->SetCheckedOut(false);
|
||||
petition_list.AddPetition(newpet);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in RefreshPetitionsFromDB query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
std::string query = "SELECT petid, charname, accountname, lastgm, petitiontext, "
|
||||
"zone, urgency, charclass, charrace, charlevel, checkouts, "
|
||||
"unavailables, ischeckedout, senttime, gmtext "
|
||||
"FROM petitions ORDER BY petid";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in RefreshPetitionsFromDB query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
newpet = new Petition(atoi(row[0]));
|
||||
newpet->SetCName(row[1]);
|
||||
newpet->SetAName(row[2]);
|
||||
newpet->SetLastGM(row[3]);
|
||||
newpet->SetPetitionText(row[4]);
|
||||
newpet->SetZone(atoi(row[5]));
|
||||
newpet->SetUrgency(atoi(row[6]));
|
||||
newpet->SetClass(atoi(row[7]));
|
||||
newpet->SetRace(atoi(row[8]));
|
||||
newpet->SetLevel(atoi(row[9]));
|
||||
newpet->SetCheckouts(atoi(row[10]));
|
||||
newpet->SetUnavails(atoi(row[11]));
|
||||
newpet->SetSentTime2(atol(row[13]));
|
||||
newpet->SetGMText(row[14]);
|
||||
|
||||
if (atoi(row[12]) == 1)
|
||||
newpet->SetCheckedOut(true);
|
||||
else
|
||||
newpet->SetCheckedOut(false);
|
||||
petition_list.AddPetition(newpet);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -22,8 +22,8 @@
|
||||
#include "../common/types.h"
|
||||
#include "zonedb.h"
|
||||
#include "client.h"
|
||||
#include "../common/Mutex.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/mutex.h"
|
||||
#include "../common/misc_functions.h"
|
||||
|
||||
class Petition
|
||||
{
|
||||
|
||||
+88
-117
@@ -20,13 +20,13 @@
|
||||
#include "masterentity.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/moremath.h"
|
||||
#include "../common/Item.h"
|
||||
#include "../common/item.h"
|
||||
#include "zonedb.h"
|
||||
#include "worldserver.h"
|
||||
#include "../common/skills.h"
|
||||
#include "../common/bodytypes.h"
|
||||
#include "../common/classes.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "pets.h"
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "../common/unix.h"
|
||||
#endif
|
||||
|
||||
#include "StringIDs.h"
|
||||
#include "string_ids.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// pet related functions
|
||||
@@ -362,31 +362,34 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
||||
|
||||
// handle monster summoning pet appearance
|
||||
if(record.monsterflag) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result = nullptr;
|
||||
MYSQL_ROW row = nullptr;
|
||||
uint32 monsterid;
|
||||
|
||||
uint32 monsterid = 0;
|
||||
|
||||
// get a random npc id from the spawngroups assigned to this zone
|
||||
if (database.RunQuery(query, MakeAnyLenString(&query,
|
||||
"SELECT npcID FROM (spawnentry INNER JOIN spawn2 ON spawn2.spawngroupID = spawnentry.spawngroupID) "
|
||||
"INNER JOIN npc_types ON npc_types.id = spawnentry.npcID "
|
||||
"WHERE spawn2.zone = '%s' AND npc_types.bodytype NOT IN (11, 33, 66, 67) "
|
||||
"AND npc_types.race NOT IN (0,1,2,3,4,5,6,7,8,9,10,11,12,44,55,67,71,72,73,77,78,81,90,92,93,94,106,112,114,127,128,130,139,141,183,236,237,238,239,254,266,329,330,378,379,380,381,382,383,404,522) "
|
||||
"ORDER BY RAND() LIMIT 1", zone->GetShortName()), errbuf, &result))
|
||||
{
|
||||
row = mysql_fetch_row(result);
|
||||
if (row)
|
||||
monsterid = atoi(row[0]);
|
||||
else
|
||||
monsterid = 567; // since we don't have any monsters, just make it look like an earth pet for now
|
||||
}
|
||||
else { // if the database query failed
|
||||
LogFile->write(EQEMuLog::Error, "Error querying database for monster summoning pet in zone %s (%s)", zone->GetShortName(), errbuf);
|
||||
monsterid = 567;
|
||||
auto query = StringFormat("SELECT npcID "
|
||||
"FROM (spawnentry INNER JOIN spawn2 ON spawn2.spawngroupID = spawnentry.spawngroupID) "
|
||||
"INNER JOIN npc_types ON npc_types.id = spawnentry.npcID "
|
||||
"WHERE spawn2.zone = '%s' AND npc_types.bodytype NOT IN (11, 33, 66, 67) "
|
||||
"AND npc_types.race NOT IN (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 44, "
|
||||
"55, 67, 71, 72, 73, 77, 78, 81, 90, 92, 93, 94, 106, 112, 114, 127, 128, "
|
||||
"130, 139, 141, 183, 236, 237, 238, 239, 254, 266, 329, 330, 378, 379, "
|
||||
"380, 381, 382, 383, 404, 522) "
|
||||
"ORDER BY RAND() LIMIT 1", zone->GetShortName());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
// if the database query failed
|
||||
LogFile->write(EQEMuLog::Error, "Error querying database for monster summoning pet in zone %s (%s)", zone->GetShortName(), results.ErrorMessage().c_str());
|
||||
}
|
||||
|
||||
if (results.RowCount() != 0) {
|
||||
auto row = results.begin();
|
||||
monsterid = atoi(row[0]);
|
||||
}
|
||||
|
||||
// since we don't have any monsters, just make it look like an earth pet for now
|
||||
if (monsterid == 0)
|
||||
monsterid = 567;
|
||||
|
||||
// give the summoned pet the attributes of the monster we found
|
||||
const NPCType* monster = database.GetNPCType(monsterid);
|
||||
if(monster) {
|
||||
@@ -396,12 +399,9 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
||||
npc_type->gender = monster->gender;
|
||||
npc_type->luclinface = monster->luclinface;
|
||||
npc_type->helmtexture = monster->helmtexture;
|
||||
}
|
||||
else {
|
||||
} else
|
||||
LogFile->write(EQEMuLog::Error, "Error loading NPC data for monster summoning pet (NPC ID %d)", monsterid);
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
//this takes ownership of the npc_type data
|
||||
@@ -450,46 +450,35 @@ bool ZoneDatabase::GetPetEntry(const char *pet_type, PetRecord *into) {
|
||||
}
|
||||
|
||||
bool ZoneDatabase::GetPoweredPetEntry(const char *pet_type, int16 petpower, PetRecord *into) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
uint32 querylen = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
std::string query;
|
||||
|
||||
if (petpower <= 0) {
|
||||
querylen = MakeAnyLenString(&query,
|
||||
"SELECT npcID, temp, petpower, petcontrol, petnaming, monsterflag, equipmentset FROM pets "
|
||||
"WHERE type='%s' AND petpower<=0", pet_type);
|
||||
}
|
||||
else {
|
||||
querylen = MakeAnyLenString(&query,
|
||||
"SELECT npcID, temp, petpower, petcontrol, petnaming, monsterflag, equipmentset FROM pets "
|
||||
"WHERE type='%s' AND petpower<=%d ORDER BY petpower DESC LIMIT 1", pet_type, petpower);
|
||||
}
|
||||
if (petpower <= 0)
|
||||
query = StringFormat("SELECT npcID, temp, petpower, petcontrol, petnaming, monsterflag, equipmentset "
|
||||
"FROM pets WHERE type='%s' AND petpower<=0", pet_type);
|
||||
else
|
||||
query = StringFormat("SELECT npcID, temp, petpower, petcontrol, petnaming, monsterflag, equipmentset "
|
||||
"FROM pets WHERE type='%s' AND petpower<=%d ORDER BY petpower DESC LIMIT 1",
|
||||
pet_type, petpower);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetPoweredPetEntry query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (RunQuery(query, querylen, errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
if (results.RowCount() != 1)
|
||||
return false;
|
||||
|
||||
into->npc_type = atoi(row[0]);
|
||||
into->temporary = atoi(row[1]);
|
||||
into->petpower = atoi(row[2]);
|
||||
into->petcontrol = atoi(row[3]);
|
||||
into->petnaming = atoi(row[4]);
|
||||
into->monsterflag = atoi(row[5]);
|
||||
into->equipmentset = atoi(row[6]);
|
||||
auto row = results.begin();
|
||||
|
||||
mysql_free_result(result);
|
||||
return(true);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetPoweredPetEntry query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
}
|
||||
return(false);
|
||||
into->npc_type = atoi(row[0]);
|
||||
into->temporary = atoi(row[1]);
|
||||
into->petpower = atoi(row[2]);
|
||||
into->petcontrol = atoi(row[3]);
|
||||
into->petnaming = atoi(row[4]);
|
||||
into->monsterflag = atoi(row[5]);
|
||||
into->equipmentset = atoi(row[6]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Mob* Mob::GetPet() {
|
||||
@@ -657,11 +646,6 @@ bool ZoneDatabase::GetBasePetItems(int32 equipmentset, uint32 *items) {
|
||||
// A slot will only get an item put in it if it is empty. That way
|
||||
// an equipmentset can overload a slot for the set(s) it includes.
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
uint32 querylen = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int depth = 0;
|
||||
int32 curset = equipmentset;
|
||||
int32 nextset = -1;
|
||||
@@ -673,56 +657,43 @@ bool ZoneDatabase::GetBasePetItems(int32 equipmentset, uint32 *items) {
|
||||
// query pets_equipmentset_entries with the set_id and loop over
|
||||
// all of the result rows. Check if we have something in the slot
|
||||
// already. If no, add the item id to the equipment array.
|
||||
|
||||
while (curset >= 0 && depth < 5) {
|
||||
if (RunQuery(query,
|
||||
MakeAnyLenString(&query, "SELECT nested_set FROM pets_equipmentset WHERE set_id='%s'", curset),
|
||||
errbuf, &result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
nextset = atoi(row[0]);
|
||||
mysql_free_result(result);
|
||||
|
||||
if (RunQuery(query,
|
||||
MakeAnyLenString(&query, "SELECT slot, item_id FROM pets_equipmentset_entries WHERE set_id='%s'", curset),
|
||||
errbuf, &result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
slot = atoi(row[0]);
|
||||
if (slot >= EmuConstants::EQUIPMENT_SIZE)
|
||||
continue;
|
||||
if (items[slot] == 0)
|
||||
items[slot] = atoi(row[1]);
|
||||
}
|
||||
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetBasePetItems query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
}
|
||||
curset = nextset;
|
||||
depth++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// invalid set reference, it doesn't exist
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetBasePetItems equipment set '%d' does not exist", curset);
|
||||
mysql_free_result(result);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetBasePetItems query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT nested_set FROM pets_equipmentset WHERE set_id = '%s'", curset);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetBasePetItems query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
} // end while
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1) {
|
||||
// invalid set reference, it doesn't exist
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetBasePetItems equipment set '%d' does not exist", curset);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
nextset = atoi(row[0]);
|
||||
|
||||
query = StringFormat("SELECT slot, item_id FROM pets_equipmentset_entries WHERE set_id='%s'", curset);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetBasePetItems query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
else {
|
||||
for (row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
slot = atoi(row[0]);
|
||||
|
||||
if (slot >= EmuConstants::EQUIPMENT_SIZE)
|
||||
continue;
|
||||
|
||||
if (items[slot] == 0)
|
||||
items[slot] = atoi(row[1]);
|
||||
}
|
||||
}
|
||||
|
||||
curset = nextset;
|
||||
depth++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "../common/debug.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "QGlobals.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "qglobals.h"
|
||||
#include "masterentity.h"
|
||||
#include "zone.h"
|
||||
#include "zonedb.h"
|
||||
@@ -51,7 +51,7 @@ void QGlobalCache::Combine(std::list<QGlobal> &cacheA, std::list<QGlobal> cacheB
|
||||
|
||||
void QGlobalCache::GetQGlobals(std::list<QGlobal> &globals, NPC *n, Client *c, Zone *z) {
|
||||
globals.clear();
|
||||
|
||||
|
||||
QGlobalCache *npc_c = nullptr;
|
||||
QGlobalCache *char_c = nullptr;
|
||||
QGlobalCache *zone_c = nullptr;
|
||||
@@ -139,75 +139,39 @@ void QGlobalCache::PurgeExpiredGlobals()
|
||||
|
||||
void QGlobalCache::LoadByNPCID(uint32 npcID)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (database.RunQuery(query, MakeAnyLenString(&query, "select name, charid, npcid, zoneid, value, expdate"
|
||||
" from quest_globals where npcid = %d", npcID), errbuf, &result))
|
||||
{
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
AddGlobal(0, QGlobal(std::string(row[0]), atoi(row[1]), atoi(row[2]), atoi(row[3]), row[4], row[5]?atoi(row[5]):0xFFFFFFFF));
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT name, charid, npcid, zoneid, value, expdate "
|
||||
"FROM quest_globals WHERE npcid = %d", npcID);
|
||||
LoadBy(query);
|
||||
}
|
||||
|
||||
void QGlobalCache::LoadByCharID(uint32 charID)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (database.RunQuery(query, MakeAnyLenString(&query, "select name, charid, npcid, zoneid, value, expdate from"
|
||||
" quest_globals where charid = %d && npcid = 0", charID), errbuf, &result))
|
||||
{
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
AddGlobal(0, QGlobal(std::string(row[0]), atoi(row[1]), atoi(row[2]), atoi(row[3]), row[4], row[5]?atoi(row[5]):0xFFFFFFFF));
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT name, charid, npcid, zoneid, value, expdate "
|
||||
"FROM quest_globals WHERE charid = %d && npcid = 0", charID);
|
||||
LoadBy(query);
|
||||
}
|
||||
|
||||
void QGlobalCache::LoadByZoneID(uint32 zoneID)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (database.RunQuery(query, MakeAnyLenString(&query, "select name, charid, npcid, zoneid, value, expdate from quest_globals"
|
||||
" where zoneid = %d && npcid = 0 && charid = 0", zoneID), errbuf, &result))
|
||||
{
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
AddGlobal(0, QGlobal(std::string(row[0]), atoi(row[1]), atoi(row[2]), atoi(row[3]), row[4], row[5]?atoi(row[5]):0xFFFFFFFF));
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT name, charid, npcid, zoneid, value, expdate "
|
||||
"FROM quest_globals WHERE zoneid = %d && npcid = 0 && charid = 0", zoneID);
|
||||
LoadBy(query);
|
||||
}
|
||||
|
||||
void QGlobalCache::LoadByGlobalContext()
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
std::string query = "SELECT name, charid, npcid, zoneid, value, expdate "
|
||||
"FROM quest_globals WHERE zoneid = 0 && npcid = 0 && charid = 0";
|
||||
LoadBy(query);
|
||||
}
|
||||
|
||||
void QGlobalCache::LoadBy(const std::string query)
|
||||
{
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
AddGlobal(0, QGlobal(std::string(row[0]), atoi(row[1]), atoi(row[2]), atoi(row[3]), row[4], row[5]? atoi(row[5]): 0xFFFFFFFF));
|
||||
|
||||
if (database.RunQuery(query, MakeAnyLenString(&query, "select name, charid, npcid, zoneid, value, expdate from quest_globals"
|
||||
" where zoneid = 0 && npcid = 0 && charid = 0"), errbuf, &result))
|
||||
{
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
AddGlobal(0, QGlobal(std::string(row[0]), atoi(row[1]), atoi(row[2]), atoi(row[3]), row[4], row[5]?atoi(row[5]):0xFFFFFFFF));
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
}
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
void LoadByZoneID(uint32 zoneID); //zone
|
||||
void LoadByGlobalContext(); //zone
|
||||
protected:
|
||||
void LoadBy(const std::string query);
|
||||
std::list<QGlobal> qGlobalBucket;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
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/debug.h"
|
||||
#include "../common/servertalk.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "queryserv.h"
|
||||
#include "worldserver.h"
|
||||
#include "net.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
extern WorldServer worldserver;
|
||||
extern QueryServ* QServ;
|
||||
|
||||
QueryServ::QueryServ(){
|
||||
}
|
||||
|
||||
QueryServ::~QueryServ(){
|
||||
}
|
||||
|
||||
void QueryServ::SendQuery(std::string Query)
|
||||
{
|
||||
ServerPacket* pack = new ServerPacket(ServerOP_QSSendQuery, Query.length() + 5);
|
||||
pack->WriteUInt32(Query.length()); /* Pack Query String Size so it can be dynamically broken out at queryserv */
|
||||
pack->WriteString(Query.c_str()); /* Query */
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
void QueryServ::PlayerLogEvent(int Event_Type, int Character_ID, std::string Event_Desc)
|
||||
{
|
||||
std::string query = StringFormat(
|
||||
"INSERT INTO `qs_player_events` (event, char_id, event_desc, time) VALUES (%i, %i, '%s', UNIX_TIMESTAMP(now()))",
|
||||
Event_Type, Character_ID, EscapeString(Event_Desc).c_str());
|
||||
SendQuery(query);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef QUERYSERV_ZONE_H
|
||||
#define QUERYSERV_ZONE_H
|
||||
|
||||
|
||||
/*
|
||||
enum PlayerGenericLogEventTypes
|
||||
These Enums are for the generic logging table that are not complex and require more advanced logic
|
||||
*/
|
||||
|
||||
enum PlayerGenericLogEventTypes {
|
||||
Player_Log_Quest = 1,
|
||||
Player_Log_Zoning,
|
||||
Player_Log_Deaths,
|
||||
Player_Log_Connect_State,
|
||||
Player_Log_Levels,
|
||||
Player_Log_Keyring_Addition,
|
||||
Player_Log_QGlobal_Update,
|
||||
Player_Log_Task_Updates,
|
||||
Player_Log_AA_Purchases,
|
||||
Player_Log_Trade_Skill_Events,
|
||||
Player_Log_Issued_Commands,
|
||||
Player_Log_Money_Transactions,
|
||||
Player_Log_Alternate_Currency_Transactions,
|
||||
};
|
||||
|
||||
|
||||
class QueryServ{
|
||||
public:
|
||||
QueryServ();
|
||||
~QueryServ();
|
||||
void SendQuery(std::string Query);
|
||||
void PlayerLogEvent(int Event_Type, int Character_ID, std::string Event_Desc);
|
||||
};
|
||||
|
||||
#endif /* QUERYSERV_ZONE_H */
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "../common/unix.h"
|
||||
#endif
|
||||
|
||||
#include "Quest.h"
|
||||
#include "quest.h"
|
||||
|
||||
pquest_entry Quest::m_pQuests;
|
||||
int Quest::m_nQuests;
|
||||
@@ -17,10 +17,10 @@
|
||||
*/
|
||||
|
||||
#include "../common/debug.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/features.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "QuestInterface.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "quest_interface.h"
|
||||
#include "zone.h"
|
||||
#include "questmgr.h"
|
||||
|
||||
@@ -600,9 +600,8 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string
|
||||
}
|
||||
|
||||
QuestInterface *QuestParserCollection::GetQIByPlayerQuest(std::string &filename) {
|
||||
|
||||
if(!zone)
|
||||
return nullptr;
|
||||
if(!zone || !zone->IsLoaded())
|
||||
return nullptr;
|
||||
|
||||
//first look for /quests/zone/player_v[instance_version].ext (precedence)
|
||||
filename = "quests/";
|
||||
@@ -20,10 +20,10 @@
|
||||
#define _EQE_QUESTPARSERCOLLECTION_H
|
||||
|
||||
#include "../common/types.h"
|
||||
#include "../common/Item.h"
|
||||
#include "../common/item.h"
|
||||
|
||||
#include "masterentity.h"
|
||||
#include "QuestInterface.h"
|
||||
#include "quest_interface.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
+58
-60
@@ -67,20 +67,20 @@ And then at then end of embparser.cpp, add:
|
||||
#include "zonedb.h"
|
||||
#include "../common/spdat.h"
|
||||
#include "../common/packet_functions.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "spawn2.h"
|
||||
#include "zone.h"
|
||||
#include "event_codes.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "QGlobals.h"
|
||||
#include "QuestParserCollection.h"
|
||||
|
||||
#include "qglobals.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "queryserv.h"
|
||||
#ifdef BOTS
|
||||
#include "bot.h"
|
||||
#endif
|
||||
|
||||
|
||||
extern QueryServ* QServ;
|
||||
extern Zone* zone;
|
||||
extern WorldServer worldserver;
|
||||
extern EntityList entity_list;
|
||||
@@ -172,8 +172,7 @@ void QuestManager::EndQuest() {
|
||||
cur = QTimerList.erase(cur);
|
||||
else
|
||||
++cur;
|
||||
}
|
||||
|
||||
}
|
||||
run.owner->Depop();
|
||||
}
|
||||
quests_running_.pop();
|
||||
@@ -1294,33 +1293,29 @@ void QuestManager::setglobal(const char *varname, const char *newvalue, int opti
|
||||
int qgNpcid = owner->GetNPCTypeID();
|
||||
|
||||
/* options value determines the availability of global variables to NPCs when a quest begins
|
||||
------------------------------------------------------------------
|
||||
value npcid player zone
|
||||
------------------------------------------------------------------
|
||||
0 this this this
|
||||
1 all this this
|
||||
2 this all this
|
||||
3 all all this
|
||||
4 this this all
|
||||
5 all this all
|
||||
6 this all all
|
||||
7 all all all
|
||||
------------------------------------------------------------------
|
||||
value npcid player zone
|
||||
------------------------------------------------------------------
|
||||
0 this this this
|
||||
1 all this this
|
||||
2 this all this
|
||||
3 all all this
|
||||
4 this this all
|
||||
5 all this all
|
||||
6 this all all
|
||||
7 all all all
|
||||
*/
|
||||
if (initiator && initiator->IsClient()) // some events like waypoint and spawn don't have a player involved
|
||||
{
|
||||
qgCharid=initiator->CharacterID();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (initiator && initiator->IsClient()){ // some events like waypoint and spawn don't have a player involved
|
||||
qgCharid=initiator->CharacterID();
|
||||
}
|
||||
else {
|
||||
qgCharid=-qgNpcid; // make char id negative npc id as a fudge
|
||||
}
|
||||
if (options < 0 || options > 7)
|
||||
{
|
||||
if (options < 0 || options > 7) {
|
||||
std::cerr << "Invalid options for global var " << varname << " using defaults" << std::endl;
|
||||
} // default = 0 (only this npcid,player and zone)
|
||||
else
|
||||
{
|
||||
else {
|
||||
if (options & 1)
|
||||
qgNpcid=0;
|
||||
if (options & 2)
|
||||
@@ -1330,30 +1325,32 @@ void QuestManager::setglobal(const char *varname, const char *newvalue, int opti
|
||||
}
|
||||
|
||||
InsertQuestGlobal(qgCharid, qgNpcid, qgZoneid, varname, newvalue, QGVarDuration(duration));
|
||||
|
||||
/* QS: PlayerLogQGlobalUpdate */
|
||||
if (RuleB(QueryServ, PlayerLogQGlobalUpdate) && qgCharid && qgCharid > 0 && initiator && initiator->IsClient()){
|
||||
std::string event_desc = StringFormat("Update :: qglobal:%s to qvalue:%s zoneid:%i instid:%i", varname, newvalue, initiator->GetZoneID(), initiator->GetInstanceID());
|
||||
QServ->PlayerLogEvent(Player_Log_QGlobal_Update, qgCharid, event_desc);
|
||||
}
|
||||
}
|
||||
|
||||
/* Inserts global variable into quest_globals table */
|
||||
int QuestManager::InsertQuestGlobal(
|
||||
int charid, int npcid, int zoneid,
|
||||
const char *varname, const char *varvalue,
|
||||
int duration)
|
||||
{
|
||||
int QuestManager::InsertQuestGlobal(int charid, int npcid, int zoneid, const char *varname, const char *varvalue, int duration) {
|
||||
char *query = 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
// Make duration string either "unix_timestamp(now()) + xxx" or "NULL"
|
||||
std::stringstream duration_ss;
|
||||
if (duration == INT_MAX)
|
||||
{
|
||||
std::stringstream duration_ss;
|
||||
if (duration == INT_MAX) {
|
||||
duration_ss << "NULL";
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
duration_ss << "unix_timestamp(now()) + " << duration;
|
||||
}
|
||||
|
||||
//NOTE: this should be escaping the contents of arglist
|
||||
//npcwise a malicious script can arbitrarily alter the DB
|
||||
/*
|
||||
NOTE: this should be escaping the contents of arglist
|
||||
npcwise a malicious script can arbitrarily alter the DB
|
||||
*/
|
||||
uint32 last_id = 0;
|
||||
if (!database.RunQuery(query, MakeAnyLenString(&query,
|
||||
"REPLACE INTO quest_globals (charid, npcid, zoneid, name, value, expdate)"
|
||||
@@ -1365,9 +1362,8 @@ int QuestManager::InsertQuestGlobal(
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
if(zone)
|
||||
{
|
||||
//first delete our global
|
||||
if(zone) {
|
||||
/* Delete existing qglobal data and update zone processes */
|
||||
ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct));
|
||||
ServerQGlobalDelete_Struct *qgd = (ServerQGlobalDelete_Struct*)pack->pBuffer;
|
||||
qgd->npc_id = npcid;
|
||||
@@ -1383,18 +1379,16 @@ int QuestManager::InsertQuestGlobal(
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
|
||||
//then create a new one with the new id
|
||||
/* Create new qglobal data and update zone processes */
|
||||
pack = new ServerPacket(ServerOP_QGlobalUpdate, sizeof(ServerQGlobalUpdate_Struct));
|
||||
ServerQGlobalUpdate_Struct *qgu = (ServerQGlobalUpdate_Struct*)pack->pBuffer;
|
||||
qgu->npc_id = npcid;
|
||||
qgu->char_id = charid;
|
||||
qgu->zone_id = zoneid;
|
||||
if(duration == INT_MAX)
|
||||
{
|
||||
if(duration == INT_MAX) {
|
||||
qgu->expdate = 0xFFFFFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
qgu->expdate = Timer::GetTimeSeconds() + duration;
|
||||
}
|
||||
strcpy((char*)qgu->name, varname);
|
||||
@@ -1420,8 +1414,7 @@ int QuestManager::InsertQuestGlobal(
|
||||
return 0;
|
||||
}
|
||||
|
||||
void QuestManager::targlobal(const char *varname, const char *value, const char *duration, int qgNpcid, int qgCharid, int qgZoneid)
|
||||
{
|
||||
void QuestManager::targlobal(const char *varname, const char *value, const char *duration, int qgNpcid, int qgCharid, int qgZoneid) {
|
||||
InsertQuestGlobal(qgCharid, qgNpcid, qgZoneid, varname, value, QGVarDuration(duration));
|
||||
}
|
||||
|
||||
@@ -1432,15 +1425,24 @@ void QuestManager::delglobal(const char *varname) {
|
||||
int qgZoneid=zone->GetZoneID();
|
||||
int qgCharid=0;
|
||||
int qgNpcid=owner->GetNPCTypeID();
|
||||
|
||||
|
||||
|
||||
if (initiator && initiator->IsClient()) // some events like waypoint and spawn don't have a player involved
|
||||
{
|
||||
qgCharid=initiator->CharacterID();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
else {
|
||||
qgCharid=-qgNpcid; // make char id negative npc id as a fudge
|
||||
}
|
||||
|
||||
/* QS: PlayerLogQGlobalUpdate */
|
||||
if (RuleB(QueryServ, PlayerLogQGlobalUpdate) && qgCharid && qgCharid > 0 && initiator && initiator->IsClient()){
|
||||
std::string event_desc = StringFormat("Deleted :: qglobal:%s zoneid:%i instid:%i", varname, initiator->GetZoneID(), initiator->GetInstanceID());
|
||||
QServ->PlayerLogEvent(Player_Log_QGlobal_Update, qgCharid, event_desc);
|
||||
}
|
||||
|
||||
if (!database.RunQuery(query,
|
||||
MakeAnyLenString(&query,
|
||||
"DELETE FROM quest_globals WHERE name='%s'"
|
||||
@@ -1451,8 +1453,7 @@ void QuestManager::delglobal(const char *varname) {
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
if(zone)
|
||||
{
|
||||
if(zone) {
|
||||
ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct));
|
||||
ServerQGlobalDelete_Struct *qgu = (ServerQGlobalDelete_Struct*)pack->pBuffer;
|
||||
|
||||
@@ -1701,17 +1702,14 @@ void QuestManager::showgrid(int grid) {
|
||||
pts.push_back(pt);
|
||||
|
||||
// Retrieve all waypoints for this grid
|
||||
if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `x`,`y`,`z` FROM grid_entries WHERE `gridid`=%i AND `zoneid`=%i ORDER BY `number`",grid,zone->GetZoneID()),errbuf,&result))
|
||||
{
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `x`,`y`,`z` FROM grid_entries WHERE `gridid`=%i AND `zoneid`=%i ORDER BY `number`",grid,zone->GetZoneID()),errbuf,&result)) {
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
pt.x = atof(row[0]);
|
||||
pt.y = atof(row[1]);
|
||||
pt.z = atof(row[2]);
|
||||
pts.push_back(pt);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
|
||||
mysql_free_result(result);
|
||||
initiator->SendPathPacket(pts);
|
||||
}
|
||||
else // DB query error!
|
||||
|
||||
+2
-2
@@ -17,10 +17,10 @@
|
||||
*/
|
||||
#include "../common/debug.h"
|
||||
#include "masterentity.h"
|
||||
#include "NpcAI.h"
|
||||
#include "npc_ai.h"
|
||||
#include "../common/packet_functions.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "worldserver.h"
|
||||
extern EntityList entity_list;
|
||||
extern WorldServer worldserver;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "RaycastMesh.h"
|
||||
#include "raycast_mesh.h"
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
+248
-290
@@ -16,7 +16,7 @@
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "../common/debug.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
#include <stdlib.h>
|
||||
#include "spawn2.h"
|
||||
#include "entity.h"
|
||||
@@ -354,96 +354,86 @@ void Spawn2::DeathReset(bool realdeath)
|
||||
}
|
||||
|
||||
bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spawn2_list, int16 version, uint32 repopdelay) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
const char *zone_name = database.GetZoneName(zoneid);
|
||||
|
||||
MakeAnyLenString(&query, "SELECT id, spawngroupID, x, y, z, heading, respawntime, variance, pathgrid, _condition, cond_value, enabled, animation FROM spawn2 WHERE zone='%s' AND version=%u", zone_name, version);
|
||||
if (RunQuery(query, strlen(query), errbuf, &result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
Spawn2* newSpawn = 0;
|
||||
|
||||
bool perl_enabled = atoi(row[11]) == 1 ? true : false;
|
||||
uint32 spawnLeft = (GetSpawnTimeLeft(atoi(row[0]), zone->GetInstanceID()) * 1000);
|
||||
newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atoi(row[6]), atoi(row[7]), spawnLeft, atoi(row[8]), atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12]));
|
||||
spawn2_list.Insert( newSpawn );
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile->write(EQEMuLog::Error, "Error in PopulateZoneLists query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT id, spawngroupID, x, y, z, heading, "
|
||||
"respawntime, variance, pathgrid, _condition, "
|
||||
"cond_value, enabled, animation FROM spawn2 "
|
||||
"WHERE zone = '%s' AND version = %u",
|
||||
zone_name, version);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in PopulateZoneLists query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
Spawn2* newSpawn = 0;
|
||||
|
||||
bool perl_enabled = atoi(row[11]) == 1? true: false;
|
||||
uint32 spawnLeft = (GetSpawnTimeLeft(atoi(row[0]), zone->GetInstanceID()) * 1000);
|
||||
newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]),
|
||||
atof(row[5]), atoi(row[6]), atoi(row[7]), spawnLeft, atoi(row[8]),
|
||||
atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12]));
|
||||
|
||||
spawn2_list.Insert(newSpawn);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Spawn2* ZoneDatabase::LoadSpawn2(LinkedList<Spawn2*> &spawn2_list, uint32 spawn2id, uint32 timeleft) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, spawngroupID, x, y, z, heading, respawntime, variance, pathgrid, _condition, cond_value, enabled, animation FROM spawn2 WHERE id=%i", spawn2id), errbuf, &result)) {
|
||||
if (mysql_num_rows(result) == 1)
|
||||
{
|
||||
row = mysql_fetch_row(result);
|
||||
bool perl_enabled = atoi(row[11]) == 1 ? true : false;
|
||||
Spawn2* newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atoi(row[6]), atoi(row[7]), timeleft, atoi(row[8]), atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12]));
|
||||
spawn2_list.Insert( newSpawn );
|
||||
mysql_free_result(result);
|
||||
safe_delete_array(query);
|
||||
return newSpawn;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
std::string query = StringFormat("SELECT id, spawngroupID, x, y, z, heading, "
|
||||
"respawntime, variance, pathgrid, _condition, "
|
||||
"cond_value, enabled, animation FROM spawn2 "
|
||||
"WHERE id = %i", spawn2id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawn2 query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawn2 query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
return 0;
|
||||
if (results.RowCount() != 1) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawn2 query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
bool perl_enabled = atoi(row[11]) == 1 ? true : false;
|
||||
|
||||
Spawn2* newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]),
|
||||
atof(row[5]), atoi(row[6]), atoi(row[7]), timeleft, atoi(row[8]),
|
||||
atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12]));
|
||||
|
||||
spawn2_list.Insert(newSpawn);
|
||||
|
||||
return newSpawn;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::CreateSpawn2(Client *c, uint32 spawngroup, const char* zone, float heading, float x, float y, float z, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value)
|
||||
bool ZoneDatabase::CreateSpawn2(Client *client, uint32 spawngroup, const char* zone, float heading, float x, float y, float z, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char *query = 0;
|
||||
uint32 affected_rows = 0;
|
||||
|
||||
// if(GetInverseXY()==1) {
|
||||
// float temp=x;
|
||||
// x=y;
|
||||
// y=temp;
|
||||
// }
|
||||
if (RunQuery(query, MakeAnyLenString(&query,
|
||||
"INSERT INTO spawn2 (spawngroupID,zone,x,y,z,heading,respawntime,variance,_condition,cond_value) Values (%i, '%s', %f, %f, %f, %f, %i, %i, %u, %i)",
|
||||
spawngroup, zone, x, y, z, heading, respawn, variance, condition, cond_value
|
||||
), errbuf, 0, &affected_rows)) {
|
||||
safe_delete_array(query);
|
||||
if (affected_rows == 1) {
|
||||
if(c) c->LogSQL(query);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in CreateSpawn2 query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("INSERT INTO spawn2 (spawngroupID, zone, x, y, z, heading, "
|
||||
"respawntime, variance, _condition, cond_value) "
|
||||
"VALUES (%i, '%s', %f, %f, %f, %f, %i, %i, %u, %i)",
|
||||
spawngroup, zone, x, y, z, heading,
|
||||
respawn, variance, condition, cond_value);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in CreateSpawn2 query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
if (results.RowsAffected() != 1)
|
||||
return false;
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 Zone::CountSpawn2() {
|
||||
@@ -671,177 +661,159 @@ void SpawnConditionManager::ExecEvent(SpawnEvent &event, bool send_update) {
|
||||
}
|
||||
|
||||
void SpawnConditionManager::UpdateDBEvent(SpawnEvent &event) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
int len;
|
||||
|
||||
SpawnCondition cond;
|
||||
len = MakeAnyLenString(&query,
|
||||
"UPDATE spawn_events SET "
|
||||
"next_minute=%d, next_hour=%d, next_day=%d, next_month=%d, "
|
||||
"next_year=%d, enabled=%d, strict=%d "
|
||||
"WHERE id=%d",
|
||||
event.next.minute, event.next.hour, event.next.day, event.next.month,
|
||||
event.next.year, event.enabled?1:0, event.strict?1:0,event.id
|
||||
);
|
||||
if(!database.RunQuery(query, len, errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Unable to update spawn event '%s': %s\n", query, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("UPDATE spawn_events SET "
|
||||
"next_minute = %d, next_hour = %d, "
|
||||
"next_day = %d, next_month = %d, "
|
||||
"next_year = %d, enabled = %d, "
|
||||
"strict = %d WHERE id = %d",
|
||||
event.next.minute, event.next.hour,
|
||||
event.next.day, event.next.month,
|
||||
event.next.year, event.enabled? 1: 0,
|
||||
event.strict? 1: 0, event.id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to update spawn event '%s': %s\n", query.c_str(), results.ErrorMessage().c_str());
|
||||
|
||||
}
|
||||
|
||||
void SpawnConditionManager::UpdateDBCondition(const char* zone_name, uint32 instance_id, uint16 cond_id, int16 value) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
int len;
|
||||
|
||||
SpawnCondition cond;
|
||||
len = MakeAnyLenString(&query,
|
||||
"REPLACE INTO spawn_condition_values (id, value, zone, instance_id) VALUES(%u, %u, '%s', %u)",
|
||||
cond_id, value, zone_name, instance_id
|
||||
);
|
||||
if(!database.RunQuery(query, len, errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Unable to update spawn condition '%s': %s\n", query, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("REPLACE INTO spawn_condition_values "
|
||||
"(id, value, zone, instance_id) "
|
||||
"VALUES( %u, %u, '%s', %u)",
|
||||
cond_id, value, zone_name, instance_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to update spawn condition '%s': %s\n", query.c_str(), results.ErrorMessage().c_str());
|
||||
|
||||
}
|
||||
|
||||
bool SpawnConditionManager::LoadDBEvent(uint32 event_id, SpawnEvent &event, std::string &zone_name) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int len;
|
||||
|
||||
bool ret = false;
|
||||
|
||||
len = MakeAnyLenString(&query,
|
||||
"SELECT id,cond_id,period,next_minute,next_hour,next_day,next_month,next_year,enabled,action,argument,strict,zone "
|
||||
"FROM spawn_events WHERE id=%d", event_id);
|
||||
if (database.RunQuery(query, len, errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
if((row = mysql_fetch_row(result))) {
|
||||
event.id = atoi(row[0]);
|
||||
event.condition_id = atoi(row[1]);
|
||||
event.period = atoi(row[2]);
|
||||
|
||||
event.next.minute = atoi(row[3]);
|
||||
event.next.hour = atoi(row[4]);
|
||||
event.next.day = atoi(row[5]);
|
||||
event.next.month = atoi(row[6]);
|
||||
event.next.year = atoi(row[7]);
|
||||
|
||||
event.enabled = atoi(row[8])==0?false:true;
|
||||
event.action = (SpawnEvent::Action) atoi(row[9]);
|
||||
event.argument = atoi(row[10]);
|
||||
event.strict = atoi(row[11])==0?false:true;
|
||||
zone_name = row[12];
|
||||
|
||||
std::string t;
|
||||
EQTime::ToString(&event.next, t);
|
||||
_log(SPAWNS__CONDITIONS, "(LoadDBEvent) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d. Will trigger at %s",
|
||||
event.enabled?"enabled":"disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict, t.c_str());
|
||||
|
||||
ret = true;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadDBEvent query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT id, cond_id, period, "
|
||||
"next_minute, next_hour, next_day, "
|
||||
"next_month, next_year, enabled, "
|
||||
"action, argument, strict, zone "
|
||||
"FROM spawn_events WHERE id = %d", event_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadDBEvent query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
return(ret);
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
return false;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
event.id = atoi(row[0]);
|
||||
event.condition_id = atoi(row[1]);
|
||||
event.period = atoi(row[2]);
|
||||
|
||||
event.next.minute = atoi(row[3]);
|
||||
event.next.hour = atoi(row[4]);
|
||||
event.next.day = atoi(row[5]);
|
||||
event.next.month = atoi(row[6]);
|
||||
event.next.year = atoi(row[7]);
|
||||
|
||||
event.enabled = atoi(row[8]) != 0;
|
||||
event.action = (SpawnEvent::Action) atoi(row[9]);
|
||||
event.argument = atoi(row[10]);
|
||||
event.strict = atoi(row[11]) != 0;
|
||||
zone_name = row[12];
|
||||
|
||||
std::string timeAsString;
|
||||
EQTime::ToString(&event.next, timeAsString);
|
||||
|
||||
_log(SPAWNS__CONDITIONS, "(LoadDBEvent) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d. Will trigger at %s", event.enabled? "enabled": "disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict, timeAsString.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 instance_id)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int len;
|
||||
|
||||
//clear out old stuff..
|
||||
spawn_conditions.clear();
|
||||
|
||||
//load spawn conditions
|
||||
SpawnCondition cond;
|
||||
len = MakeAnyLenString(&query, "SELECT id, onchange, value FROM spawn_conditions WHERE zone='%s'", zone_name);
|
||||
if (database.RunQuery(query, len, errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
cond.condition_id = atoi(row[0]);
|
||||
cond.value = atoi(row[2]);
|
||||
cond.on_change = (SpawnCondition::OnChange) atoi(row[1]);
|
||||
spawn_conditions[cond.condition_id] = cond;
|
||||
|
||||
_log(SPAWNS__CONDITIONS, "Loaded spawn condition %d with value %d and on_change %d", cond.condition_id, cond.value, cond.on_change);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
|
||||
std::string query = StringFormat("SELECT id, onchange, value "
|
||||
"FROM spawn_conditions "
|
||||
"WHERE zone = '%s'", zone_name);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
//load spawn conditions
|
||||
SpawnCondition cond;
|
||||
|
||||
cond.condition_id = atoi(row[0]);
|
||||
cond.value = atoi(row[2]);
|
||||
cond.on_change = (SpawnCondition::OnChange) atoi(row[1]);
|
||||
spawn_conditions[cond.condition_id] = cond;
|
||||
|
||||
_log(SPAWNS__CONDITIONS, "Loaded spawn condition %d with value %d and on_change %d", cond.condition_id, cond.value, cond.on_change);
|
||||
}
|
||||
|
||||
//load values
|
||||
len = MakeAnyLenString(&query, "SELECT id, value FROM spawn_condition_values WHERE zone='%s' and instance_id=%u", zone_name, instance_id);
|
||||
if (database.RunQuery(query, len, errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
std::map<uint16, SpawnCondition>::iterator iter = spawn_conditions.find(atoi(row[0]));
|
||||
if(iter != spawn_conditions.end())
|
||||
{
|
||||
iter->second.value = atoi(row[1]);
|
||||
}
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
query = StringFormat("SELECT id, value FROM spawn_condition_values "
|
||||
"WHERE zone = '%s' AND instance_id = %u",
|
||||
zone_name, instance_id);
|
||||
results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
spawn_conditions.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
auto iter = spawn_conditions.find(atoi(row[0]));
|
||||
|
||||
if(iter != spawn_conditions.end())
|
||||
iter->second.value = atoi(row[1]);
|
||||
}
|
||||
|
||||
//load spawn events
|
||||
SpawnEvent event;
|
||||
len = MakeAnyLenString(&query,
|
||||
"SELECT id,cond_id,period,next_minute,next_hour,next_day,next_month,next_year,enabled,action,argument,strict "
|
||||
"FROM spawn_events WHERE zone='%s'", zone_name);
|
||||
if (database.RunQuery(query, len, errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
event.id = atoi(row[0]);
|
||||
event.condition_id = atoi(row[1]);
|
||||
event.period = atoi(row[2]);
|
||||
if(event.period == 0) {
|
||||
LogFile->write(EQEMuLog::Error, "Refusing to load spawn event #%d because it has a period of 0\n", event.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
event.next.minute = atoi(row[3]);
|
||||
event.next.hour = atoi(row[4]);
|
||||
event.next.day = atoi(row[5]);
|
||||
event.next.month = atoi(row[6]);
|
||||
event.next.year = atoi(row[7]);
|
||||
|
||||
event.enabled = atoi(row[8])==0?false:true;
|
||||
event.action = (SpawnEvent::Action) atoi(row[9]);
|
||||
event.argument = atoi(row[10]);
|
||||
event.strict = atoi(row[11])==0?false:true;
|
||||
spawn_events.push_back(event);
|
||||
|
||||
_log(SPAWNS__CONDITIONS, "(LoadSpawnConditions) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d",
|
||||
event.enabled?"enabled":"disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions events query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
query = StringFormat("SELECT id, cond_id, period, next_minute, next_hour, "
|
||||
"next_day, next_month, next_year, enabled, action, argument, strict "
|
||||
"FROM spawn_events WHERE zone = '%s'", zone_name);
|
||||
results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions events query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
SpawnEvent event;
|
||||
|
||||
event.id = atoi(row[0]);
|
||||
event.condition_id = atoi(row[1]);
|
||||
event.period = atoi(row[2]);
|
||||
|
||||
if(event.period == 0) {
|
||||
LogFile->write(EQEMuLog::Error, "Refusing to load spawn event #%d because it has a period of 0\n", event.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
event.next.minute = atoi(row[3]);
|
||||
event.next.hour = atoi(row[4]);
|
||||
event.next.day = atoi(row[5]);
|
||||
event.next.month = atoi(row[6]);
|
||||
event.next.year = atoi(row[7]);
|
||||
|
||||
event.enabled = atoi(row[8])==0?false:true;
|
||||
event.action = (SpawnEvent::Action) atoi(row[9]);
|
||||
event.argument = atoi(row[10]);
|
||||
event.strict = atoi(row[11])==0?false:true;
|
||||
|
||||
spawn_events.push_back(event);
|
||||
|
||||
_log(SPAWNS__CONDITIONS, "(LoadSpawnConditions) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d", event.enabled? "enabled": "disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict);
|
||||
}
|
||||
|
||||
//now we need to catch up on events that happened while we were away
|
||||
//and use them to alter just the condition variables.
|
||||
@@ -855,18 +827,14 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in
|
||||
TimeOfDay_Struct tod;
|
||||
zone->zone_time.getEQTimeOfDay(&tod);
|
||||
|
||||
std::vector<SpawnEvent>::iterator cur,end;
|
||||
cur = spawn_events.begin();
|
||||
end = spawn_events.end();
|
||||
bool ran;
|
||||
for(; cur != end; ++cur) {
|
||||
for(auto cur = spawn_events.begin(); cur != spawn_events.end(); ++cur) {
|
||||
SpawnEvent &cevent = *cur;
|
||||
|
||||
bool StrictCheck = false;
|
||||
if(cevent.strict &&
|
||||
cevent.next.hour == tod.hour &&
|
||||
cevent.next.day == tod.day &&
|
||||
cevent.next.month == tod.month &&
|
||||
if(cevent.strict &&
|
||||
cevent.next.hour == tod.hour &&
|
||||
cevent.next.day == tod.day &&
|
||||
cevent.next.month == tod.month &&
|
||||
cevent.next.year == tod.year)
|
||||
StrictCheck = true;
|
||||
|
||||
@@ -874,43 +842,42 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in
|
||||
if(!cevent.enabled || !StrictCheck)
|
||||
SetCondition(zone->GetShortName(), zone->GetInstanceID(),cevent.condition_id,0);
|
||||
|
||||
if(cevent.enabled)
|
||||
{
|
||||
//watch for special case of all 0s, which means to reset next to now
|
||||
if(cevent.next.year == 0 && cevent.next.month == 0 && cevent.next.day == 0 && cevent.next.hour == 0 && cevent.next.minute == 0) {
|
||||
_log(SPAWNS__CONDITIONS, "Initial next trigger time set for spawn event %d", cevent.id);
|
||||
memcpy(&cevent.next, &tod, sizeof(cevent.next));
|
||||
//add one period
|
||||
EQTime::AddMinutes(cevent.period, &cevent.next);
|
||||
//save it in the db.
|
||||
UpdateDBEvent(cevent);
|
||||
continue; //were done with this event.
|
||||
}
|
||||
if(!cevent.enabled)
|
||||
continue;
|
||||
|
||||
ran = false;
|
||||
while(EQTime::IsTimeBefore(&tod, &cevent.next)) {
|
||||
_log(SPAWNS__CONDITIONS, "Catch up triggering on event %d", cevent.id);
|
||||
//this event has been triggered.
|
||||
//execute the event
|
||||
if(!cevent.strict || StrictCheck)
|
||||
ExecEvent(cevent, false);
|
||||
|
||||
//add the period of the event to the trigger time
|
||||
EQTime::AddMinutes(cevent.period, &cevent.next);
|
||||
ran = true;
|
||||
}
|
||||
//only write it out if the event actually ran
|
||||
if(ran) {
|
||||
//save the event in the DB
|
||||
UpdateDBEvent(cevent);
|
||||
}
|
||||
}
|
||||
//watch for special case of all 0s, which means to reset next to now
|
||||
if(cevent.next.year == 0 && cevent.next.month == 0 && cevent.next.day == 0 && cevent.next.hour == 0 && cevent.next.minute == 0) {
|
||||
_log(SPAWNS__CONDITIONS, "Initial next trigger time set for spawn event %d", cevent.id);
|
||||
memcpy(&cevent.next, &tod, sizeof(cevent.next));
|
||||
//add one period
|
||||
EQTime::AddMinutes(cevent.period, &cevent.next);
|
||||
//save it in the db.
|
||||
UpdateDBEvent(cevent);
|
||||
continue; //were done with this event.
|
||||
}
|
||||
|
||||
bool ran = false;
|
||||
while(EQTime::IsTimeBefore(&tod, &cevent.next)) {
|
||||
_log(SPAWNS__CONDITIONS, "Catch up triggering on event %d", cevent.id);
|
||||
//this event has been triggered.
|
||||
//execute the event
|
||||
if(!cevent.strict || StrictCheck)
|
||||
ExecEvent(cevent, false);
|
||||
|
||||
//add the period of the event to the trigger time
|
||||
EQTime::AddMinutes(cevent.period, &cevent.next);
|
||||
ran = true;
|
||||
}
|
||||
|
||||
//only write it out if the event actually ran
|
||||
if(ran)
|
||||
UpdateDBEvent(cevent); //save the event in the DB
|
||||
}
|
||||
|
||||
//now our event timers are all up to date, find our closest event.
|
||||
FindNearestEvent();
|
||||
|
||||
return(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SpawnConditionManager::FindNearestEvent() {
|
||||
@@ -926,7 +893,7 @@ void SpawnConditionManager::FindNearestEvent() {
|
||||
if(cevent.enabled)
|
||||
{
|
||||
//see if this event is before our last nearest
|
||||
if(EQTime::IsTimeBefore(&next_event, &cevent.next))
|
||||
if(EQTime::IsTimeBefore(&next_event, &cevent.next))
|
||||
{
|
||||
memcpy(&next_event, &cevent.next, sizeof(next_event));
|
||||
next_id = cevent.id;
|
||||
@@ -1162,37 +1129,28 @@ int16 SpawnConditionManager::GetCondition(const char *zone_short, uint32 instanc
|
||||
}
|
||||
|
||||
SpawnCondition &cond = condi->second;
|
||||
return(cond.value);
|
||||
} else {
|
||||
//this is a remote spawn condition, grab it from the DB
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int len;
|
||||
|
||||
int16 value;
|
||||
|
||||
//load spawn conditions
|
||||
SpawnCondition cond;
|
||||
len = MakeAnyLenString(&query, "SELECT value FROM spawn_condition_values WHERE zone='%s' AND instance_id=%u AND id=%d",
|
||||
zone_short, instance_id, condition_id);
|
||||
if (database.RunQuery(query, len, errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
if((row = mysql_fetch_row(result))) {
|
||||
value = atoi(row[0]);
|
||||
} else {
|
||||
_log(SPAWNS__CONDITIONS, "Unable to load remote condition %d from zone %s in Get request.", condition_id, zone_short);
|
||||
value = 0; //dunno a better thing to do...
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
_log(SPAWNS__CONDITIONS, "Unable to query remote condition %d from zone %s in Get request.", condition_id, zone_short);
|
||||
safe_delete_array(query);
|
||||
value = 0; //dunno a better thing to do...
|
||||
}
|
||||
return(value);
|
||||
return cond.value;
|
||||
}
|
||||
|
||||
//this is a remote spawn condition, grab it from the DB
|
||||
//load spawn conditions
|
||||
std::string query = StringFormat("SELECT value FROM spawn_condition_values "
|
||||
"WHERE zone = '%s' AND instance_id = %u AND id = %d",
|
||||
zone_short, instance_id, condition_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(SPAWNS__CONDITIONS, "Unable to query remote condition %d from zone %s in Get request.", condition_id, zone_short);
|
||||
return 0; //dunno a better thing to do...
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
_log(SPAWNS__CONDITIONS, "Unable to load remote condition %d from zone %s in Get request.", condition_id, zone_short);
|
||||
return 0; //dunno a better thing to do...
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
bool SpawnConditionManager::Check(uint16 condition, int16 min_value) {
|
||||
|
||||
+75
-93
@@ -23,13 +23,12 @@
|
||||
#include <iostream>
|
||||
#include "../common/types.h"
|
||||
#include "zonedb.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/string_util.h"
|
||||
|
||||
extern EntityList entity_list;
|
||||
|
||||
SpawnEntry::SpawnEntry( uint32 in_NPCType, int in_chance, uint8 in_npc_spawn_limit )
|
||||
{
|
||||
SpawnEntry::SpawnEntry( uint32 in_NPCType, int in_chance, uint8 in_npc_spawn_limit ) {
|
||||
NPCType = in_NPCType;
|
||||
chance = in_chance;
|
||||
npc_spawn_limit = in_npc_spawn_limit;
|
||||
@@ -57,7 +56,6 @@ uint32 SpawnGroup::GetNPCType() {
|
||||
int npcType = 0;
|
||||
int totalchance = 0;
|
||||
|
||||
//check limits on this spawn group and npc type
|
||||
if(!entity_list.LimitCheckGroup(id, group_spawn_limit))
|
||||
return(0);
|
||||
|
||||
@@ -68,7 +66,6 @@ uint32 SpawnGroup::GetNPCType() {
|
||||
for(; cur != end; ++cur) {
|
||||
SpawnEntry *se = *cur;
|
||||
|
||||
//check limits on this spawn group and npc type
|
||||
if(!entity_list.LimitCheckType(se->NPCType, se->npc_spawn_limit))
|
||||
continue;
|
||||
|
||||
@@ -93,7 +90,6 @@ uint32 SpawnGroup::GetNPCType() {
|
||||
roll -= se->chance;
|
||||
}
|
||||
}
|
||||
//CODER implement random table
|
||||
return npcType;
|
||||
}
|
||||
|
||||
@@ -144,106 +140,92 @@ bool SpawnGroupList::RemoveSpawnGroup(uint32 in_id) {
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadSpawnGroups(const char* zone_name, uint16 version, SpawnGroupList* spawn_group_list) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
// CODER new spawn code
|
||||
query = 0;
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT DISTINCT(spawngroupID), spawngroup.name, spawngroup.spawn_limit, spawngroup.dist, spawngroup.max_x, spawngroup.min_x, spawngroup.max_y, spawngroup.min_y, spawngroup.delay, spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay FROM spawn2,spawngroup WHERE spawn2.spawngroupID=spawngroup.ID and spawn2.version=%u and zone='%s'", version, zone_name), errbuf, &result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11]));
|
||||
spawn_group_list->AddSpawnGroup(newSpawnGroup);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error2 in PopulateZoneLists query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT DISTINCT(spawngroupID), spawngroup.name, spawngroup.spawn_limit, "
|
||||
"spawngroup.dist, spawngroup.max_x, spawngroup.min_x, "
|
||||
"spawngroup.max_y, spawngroup.min_y, spawngroup.delay, "
|
||||
"spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay "
|
||||
"FROM spawn2, spawngroup WHERE spawn2.spawngroupID = spawngroup.ID "
|
||||
"AND spawn2.version = %u and zone = '%s'", version, zone_name);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query '%s' ", query.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
query = 0;
|
||||
if (RunQuery(query, MakeAnyLenString(&query,
|
||||
"SELECT DISTINCT spawnentry.spawngroupID, npcid, chance, "
|
||||
"npc_types.spawn_limit AS sl "
|
||||
"FROM spawnentry, spawn2, npc_types "
|
||||
"WHERE spawnentry.npcID=npc_types.id AND spawnentry.spawngroupID=spawn2.spawngroupID "
|
||||
"AND zone='%s'", zone_name), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0);
|
||||
SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0]));
|
||||
if (sg)
|
||||
sg->AddSpawnEntry(newSpawnEntry);
|
||||
else
|
||||
std::cout << "Error in SpawngroupID: " << row[0] << std::endl;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error3 in PopulateZoneLists query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
SpawnGroup* newSpawnGroup = new SpawnGroup(atoi(row[0]), row[1], atoi(row[2]), atof(row[3]),
|
||||
atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]),
|
||||
atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11]));
|
||||
spawn_group_list->AddSpawnGroup(newSpawnGroup);
|
||||
}
|
||||
|
||||
query = StringFormat("SELECT DISTINCT spawnentry.spawngroupID, npcid, chance, "
|
||||
"npc_types.spawn_limit AS sl "
|
||||
"FROM spawnentry, spawn2, npc_types "
|
||||
"WHERE spawnentry.npcID=npc_types.id "
|
||||
"AND spawnentry.spawngroupID = spawn2.spawngroupID "
|
||||
"AND zone = '%s'", zone_name);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query '%'", query.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0);
|
||||
SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0]));
|
||||
|
||||
if (!sg) {
|
||||
_log(ZONE__SPAWNS, "Error in LoadSpawnGroups %s ", query.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
sg->AddSpawnEntry(newSpawnEntry);
|
||||
}
|
||||
|
||||
// CODER end new spawn code
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_group_list) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
|
||||
// CODER new spawn code
|
||||
query = 0;
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT DISTINCT spawngroup.id, spawngroup.name, spawngroup.spawn_limit, spawngroup.dist, spawngroup.max_x, spawngroup.min_x, spawngroup.max_y, spawngroup.min_y, spawngroup.delay, spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay FROM spawngroup WHERE spawngroup.ID='%i'", spawngroupid), errbuf, &result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11]));
|
||||
spawn_group_list->AddSpawnGroup(newSpawnGroup);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error2 in PopulateZoneLists query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT DISTINCT(spawngroup.id), spawngroup.name, spawngroup.spawn_limit, "
|
||||
"spawngroup.dist, spawngroup.max_x, spawngroup.min_x, "
|
||||
"spawngroup.max_y, spawngroup.min_y, spawngroup.delay, "
|
||||
"spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay "
|
||||
"FROM spawngroup WHERE spawngroup.ID = '%i'", spawngroupid);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query %s", query.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
SpawnGroup* newSpawnGroup = new SpawnGroup(atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11]));
|
||||
spawn_group_list->AddSpawnGroup(newSpawnGroup);
|
||||
}
|
||||
|
||||
query = StringFormat("SELECT DISTINCT(spawnentry.spawngroupID), spawnentry.npcid, "
|
||||
"spawnentry.chance, spawngroup.spawn_limit FROM spawnentry, spawngroup "
|
||||
"WHERE spawnentry.spawngroupID = '%i' AND spawngroup.spawn_limit = '0' "
|
||||
"ORDER BY chance", spawngroupid);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(ZONE__SPAWNS, "Error3 in PopulateZoneLists query '%s'", query.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
query = 0;
|
||||
if (RunQuery(query, MakeAnyLenString(&query,
|
||||
"SELECT DISTINCT spawnentry.spawngroupID, spawnentry.npcid, spawnentry.chance, spawngroup.spawn_limit FROM spawnentry,spawngroup WHERE spawnentry.spawngroupID='%i' AND spawngroup.spawn_limit='0' ORDER by chance", spawngroupid), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0);
|
||||
SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0]));
|
||||
if (sg)
|
||||
sg->AddSpawnEntry(newSpawnEntry);
|
||||
else
|
||||
std::cout << "Error in SpawngroupID: " << row[0] << std::endl;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error3 in PopulateZoneLists query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
return false;
|
||||
}
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0);
|
||||
SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0]));
|
||||
if (!sg) {
|
||||
_log(ZONE__SPAWNS, "Error in SpawngroupID: %s ", row[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
sg->AddSpawnEntry(newSpawnEntry);
|
||||
}
|
||||
|
||||
// CODER end new spawn code
|
||||
return true;
|
||||
}
|
||||
|
||||
+178
-231
@@ -23,13 +23,11 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "masterentity.h"
|
||||
#include "StringIDs.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/rulesys.h"
|
||||
|
||||
|
||||
|
||||
|
||||
int Mob::GetKickDamage() {
|
||||
int multiple=(GetLevel()*100/5);
|
||||
multiple += 100;
|
||||
@@ -64,11 +62,9 @@ int Mob::GetBashDamage() {
|
||||
}
|
||||
|
||||
void Mob::ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg) {
|
||||
|
||||
int item_slot = -1;
|
||||
//1: Apply bonus from AC (BOOT/SHIELD/HANDS) est. 40AC=6dmg
|
||||
if (IsClient()){
|
||||
|
||||
switch (skill){
|
||||
|
||||
case SkillFlyingKick:
|
||||
@@ -112,10 +108,8 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
|
||||
if(hate_override > -1)
|
||||
hate = hate_override;
|
||||
|
||||
if(skill == SkillBash)
|
||||
{
|
||||
if(IsClient())
|
||||
{
|
||||
if(skill == SkillBash){
|
||||
if(IsClient()){
|
||||
ItemInst *item = CastToClient()->GetInv().GetItem(MainSecondary);
|
||||
if(item)
|
||||
{
|
||||
@@ -186,6 +180,10 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
|
||||
|
||||
CombatAbility_Struct* ca_atk = (CombatAbility_Struct*) app->pBuffer;
|
||||
|
||||
/* Check to see if actually have skill */
|
||||
if (!MaxSkill(static_cast<SkillUseTypes>(ca_atk->m_skill)))
|
||||
return;
|
||||
|
||||
if(GetTarget()->GetID() != ca_atk->m_target)
|
||||
return; //invalid packet.
|
||||
|
||||
@@ -274,8 +272,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ca_atk->m_atk == 100) && (ca_atk->m_skill == SkillFrenzy))
|
||||
{
|
||||
if ((ca_atk->m_atk == 100) && (ca_atk->m_skill == SkillFrenzy)){
|
||||
CheckIncreaseSkill(SkillFrenzy, GetTarget(), 10);
|
||||
int AtkRounds = 3;
|
||||
int skillmod = 100*GetSkill(SkillFrenzy)/MaxSkill(SkillFrenzy);
|
||||
@@ -311,8 +308,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch(GetClass())
|
||||
{
|
||||
switch(GetClass()){
|
||||
case BERSERKER:
|
||||
case WARRIOR:
|
||||
case RANGER:
|
||||
@@ -384,8 +380,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
|
||||
}
|
||||
|
||||
ReuseTime = (ReuseTime*HasteMod)/100;
|
||||
if(ReuseTime > 0)
|
||||
{
|
||||
if(ReuseTime > 0){
|
||||
p_timers.Start(pTimerCombatAbility, ReuseTime);
|
||||
}
|
||||
}
|
||||
@@ -403,8 +398,7 @@ int Mob::MonkSpecialAttack(Mob* other, uint8 unchecked_type)
|
||||
SkillUseTypes skill_type; //to avoid casting... even though it "would work"
|
||||
uint8 itemslot = MainFeet;
|
||||
|
||||
switch(unchecked_type)
|
||||
{
|
||||
switch(unchecked_type){
|
||||
case SkillFlyingKick:{
|
||||
skill_type = SkillFlyingKick;
|
||||
max_dmg = ((GetSTR()+GetSkill(skill_type)) * RuleI(Combat, FlyingKickBonus) / 100) + 35;
|
||||
@@ -484,8 +478,7 @@ int Mob::MonkSpecialAttack(Mob* other, uint8 unchecked_type)
|
||||
else
|
||||
ht = ndamage = MakeRandomInt(min_dmg, max_dmg);
|
||||
}
|
||||
else
|
||||
{
|
||||
else{
|
||||
ht = max_dmg;
|
||||
}
|
||||
}
|
||||
@@ -535,7 +528,6 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
|
||||
|
||||
RogueBackstab(other,false,ReuseTime);
|
||||
if (level > 54) {
|
||||
|
||||
if(IsClient() && CastToClient()->CheckDoubleAttack(false))
|
||||
{
|
||||
if(other->GetHP() > 0)
|
||||
@@ -619,12 +611,10 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
|
||||
}
|
||||
|
||||
// determine minimum hits
|
||||
if (level < 51)
|
||||
{
|
||||
if (level < 51) {
|
||||
min_hit = (level*15/10);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
// Trumpcard: Replaced switch statement with formula calc. This will give minhit increases all the way to 65.
|
||||
min_hit = (level * ( level*5 - 105)) / 100;
|
||||
}
|
||||
@@ -636,8 +626,7 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
|
||||
if(min_damage){
|
||||
ndamage = min_hit;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
if (max_hit < min_hit)
|
||||
max_hit = min_hit;
|
||||
|
||||
@@ -645,7 +634,6 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
|
||||
ndamage = max_hit;
|
||||
else
|
||||
ndamage = MakeRandomInt(min_hit, max_hit);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -792,28 +780,24 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
|
||||
return;
|
||||
}
|
||||
|
||||
SendItemAnimation(GetTarget(), AmmoItem, SkillArchery);
|
||||
|
||||
SendItemAnimation(GetTarget(), AmmoItem, SkillArchery);
|
||||
DoArcheryAttackDmg(GetTarget(), RangeWeapon, Ammo);
|
||||
|
||||
//EndlessQuiver AA base1 = 100% Chance to avoid consumption arrow.
|
||||
int ChanceAvoidConsume = aabonuses.ConsumeProjectile + itembonuses.ConsumeProjectile + spellbonuses.ConsumeProjectile;
|
||||
|
||||
if (!ChanceAvoidConsume || (ChanceAvoidConsume < 100 && MakeRandomInt(0,99) > ChanceAvoidConsume)){
|
||||
|
||||
if (!ChanceAvoidConsume || (ChanceAvoidConsume < 100 && MakeRandomInt(0,99) > ChanceAvoidConsume)){
|
||||
DeleteItemInInventory(ammo_slot, 1, true);
|
||||
mlog(COMBAT__RANGED, "Consumed one arrow from slot %d", ammo_slot);
|
||||
} else {
|
||||
mlog(COMBAT__RANGED, "Endless Quiver prevented ammo consumption.");
|
||||
}
|
||||
|
||||
CheckIncreaseSkill(SkillArchery, GetTarget(), -15);
|
||||
|
||||
CheckIncreaseSkill(SkillArchery, GetTarget(), -15);
|
||||
CommonBreakInvisible();
|
||||
}
|
||||
|
||||
void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const ItemInst* Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime)
|
||||
{
|
||||
void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const ItemInst* Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime) {
|
||||
if (!CanDoSpecialAttack(other))
|
||||
return;
|
||||
|
||||
@@ -842,8 +826,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
|
||||
if (focus) //From FcBaseEffects
|
||||
WDmg += WDmg*focus/100;
|
||||
|
||||
if((WDmg > 0) || (ADmg > 0))
|
||||
{
|
||||
if((WDmg > 0) || (ADmg > 0)) {
|
||||
if(WDmg < 0)
|
||||
WDmg = 0;
|
||||
if(ADmg < 0)
|
||||
@@ -944,8 +927,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
|
||||
}
|
||||
|
||||
//try proc on hits and misses
|
||||
if((RangeWeapon != nullptr) && GetTarget() && other && !other->HasDied())
|
||||
{
|
||||
if((RangeWeapon != nullptr) && GetTarget() && other && !other->HasDied()){
|
||||
TryWeaponProc(RangeWeapon, other, MainRange);
|
||||
}
|
||||
|
||||
@@ -965,126 +947,134 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
|
||||
|
||||
void NPC::RangedAttack(Mob* other)
|
||||
{
|
||||
|
||||
if (!other)
|
||||
return;
|
||||
//make sure the attack and ranged timers are up
|
||||
//if the ranged timer is disabled, then they have no ranged weapon and shouldent be attacking anyhow
|
||||
if((attack_timer.Enabled() && !attack_timer.Check(false)) || (ranged_timer.Enabled() && !ranged_timer.Check()))
|
||||
{
|
||||
if((attack_timer.Enabled() && !attack_timer.Check(false)) || (ranged_timer.Enabled() && !ranged_timer.Check())){
|
||||
mlog(COMBAT__RANGED, "Archery canceled. Timer not up. Attack %d, ranged %d", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime());
|
||||
return;
|
||||
}
|
||||
|
||||
//if we have SPECATK_RANGED_ATK set then we range attack without weapon or ammo
|
||||
const Item_Struct* weapon = nullptr;
|
||||
const Item_Struct* ammo = nullptr;
|
||||
if(!GetSpecialAbility(SPECATK_RANGED_ATK))
|
||||
{
|
||||
//find our bow and ammo return if we can't find them...
|
||||
if(!CheckLosFN(other))
|
||||
return;
|
||||
}
|
||||
|
||||
int sa_min_range = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 0); //Min Range of NPC attack
|
||||
int sa_max_range = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 1); //Max Range of NPC attack
|
||||
int attacks = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 0);
|
||||
attacks = attacks > 0 ? attacks : 1;
|
||||
for(int i = 0; i < attacks; ++i) {
|
||||
|
||||
float min_range = static_cast<float>(RuleI(Combat, MinRangedAttackDist));
|
||||
float max_range = 250; // needs to be longer than 200(most spells)
|
||||
|
||||
if (sa_max_range)
|
||||
max_range = static_cast<float>(sa_max_range);
|
||||
|
||||
if (sa_min_range)
|
||||
min_range = static_cast<float>(sa_min_range);
|
||||
|
||||
mlog(COMBAT__RANGED, "Calculated bow range to be %.1f", max_range);
|
||||
max_range *= max_range;
|
||||
if(DistNoRootNoZ(*other) > max_range) {
|
||||
mlog(COMBAT__RANGED, "Ranged attack out of range...%.2f vs %.2f", DistNoRootNoZ(*other), max_range);
|
||||
//target is out of range, client does a message
|
||||
return;
|
||||
}
|
||||
else if(DistNoRootNoZ(*other) < (min_range * min_range))
|
||||
return;
|
||||
|
||||
|
||||
if(!other || !IsAttackAllowed(other) ||
|
||||
IsCasting() ||
|
||||
DivineAura() ||
|
||||
IsStunned() ||
|
||||
IsFeared() ||
|
||||
IsMezzed() ||
|
||||
(GetAppearance() == eaDead)){
|
||||
return;
|
||||
}
|
||||
|
||||
SkillUseTypes skillinuse = SkillArchery;
|
||||
skillinuse = static_cast<SkillUseTypes>(GetRangedSkill());
|
||||
|
||||
if(!ammo && !GetAmmoIDfile())
|
||||
ammo = database.GetItem(8005);
|
||||
|
||||
if(ammo)
|
||||
SendItemAnimation(other, ammo, SkillArchery);
|
||||
else
|
||||
ProjectileAnimation(other, 0,false,0,0,0,0,GetAmmoIDfile(),skillinuse);
|
||||
|
||||
FaceTarget(other);
|
||||
|
||||
if (!other->CheckHitChance(this, skillinuse, MainRange, GetSpecialAbilityParam(SPECATK_RANGED_ATK, 2)))
|
||||
{
|
||||
mlog(COMBAT__RANGED, "Ranged attack missed %s.", other->GetName());
|
||||
other->Damage(this, 0, SPELL_UNKNOWN, skillinuse);
|
||||
}
|
||||
else
|
||||
{
|
||||
int16 WDmg = GetWeaponDamage(other, weapon);
|
||||
int16 ADmg = GetWeaponDamage(other, ammo);
|
||||
int32 TotalDmg = 0;
|
||||
if(WDmg > 0 || ADmg > 0)
|
||||
//if we have SPECATK_RANGED_ATK set then we range attack without weapon or ammo
|
||||
const Item_Struct* weapon = nullptr;
|
||||
const Item_Struct* ammo = nullptr;
|
||||
if(!GetSpecialAbility(SPECATK_RANGED_ATK))
|
||||
{
|
||||
mlog(COMBAT__RANGED, "Ranged attack hit %s.", other->GetName());
|
||||
|
||||
int32 MaxDmg = max_dmg * RuleR(Combat, ArcheryNPCMultiplier); // should add a field to npc_types
|
||||
int32 MinDmg = min_dmg * RuleR(Combat, ArcheryNPCMultiplier);
|
||||
|
||||
if(RuleB(Combat, UseIntervalAC))
|
||||
TotalDmg = MaxDmg;
|
||||
else
|
||||
TotalDmg = MakeRandomInt(MinDmg, MaxDmg);
|
||||
|
||||
TotalDmg += TotalDmg * GetSpecialAbilityParam(SPECATK_RANGED_ATK, 3) / 100; //Damage modifier
|
||||
|
||||
other->AvoidDamage(this, TotalDmg, false);
|
||||
other->MeleeMitigation(this, TotalDmg, MinDmg);
|
||||
if (TotalDmg > 0)
|
||||
CommonOutgoingHitSuccess(other, TotalDmg, skillinuse);
|
||||
//find our bow and ammo return if we can't find them...
|
||||
return;
|
||||
}
|
||||
|
||||
int sa_min_range = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 4); //Min Range of NPC attack
|
||||
int sa_max_range = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 1); //Max Range of NPC attack
|
||||
|
||||
float min_range = static_cast<float>(RuleI(Combat, MinRangedAttackDist));
|
||||
float max_range = 250; // needs to be longer than 200(most spells)
|
||||
|
||||
if (sa_max_range)
|
||||
max_range = static_cast<float>(sa_max_range);
|
||||
|
||||
if (sa_min_range)
|
||||
min_range = static_cast<float>(sa_min_range);
|
||||
|
||||
mlog(COMBAT__RANGED, "Calculated bow range to be %.1f", max_range);
|
||||
max_range *= max_range;
|
||||
if(DistNoRootNoZ(*other) > max_range) {
|
||||
mlog(COMBAT__RANGED, "Ranged attack out of range...%.2f vs %.2f", DistNoRootNoZ(*other), max_range);
|
||||
//target is out of range, client does a message
|
||||
return;
|
||||
}
|
||||
else if(DistNoRootNoZ(*other) < (min_range * min_range))
|
||||
return;
|
||||
|
||||
|
||||
if(!other || !IsAttackAllowed(other) ||
|
||||
IsCasting() ||
|
||||
DivineAura() ||
|
||||
IsStunned() ||
|
||||
IsFeared() ||
|
||||
IsMezzed() ||
|
||||
(GetAppearance() == eaDead)){
|
||||
return;
|
||||
}
|
||||
|
||||
SkillUseTypes skillinuse = SkillArchery;
|
||||
skillinuse = static_cast<SkillUseTypes>(GetRangedSkill());
|
||||
|
||||
if(!ammo && !GetAmmoIDfile())
|
||||
ammo = database.GetItem(8005);
|
||||
|
||||
if(ammo)
|
||||
SendItemAnimation(other, ammo, SkillArchery);
|
||||
else
|
||||
ProjectileAnimation(other, 0,false,0,0,0,0,GetAmmoIDfile(),skillinuse);
|
||||
|
||||
FaceTarget(other);
|
||||
|
||||
if (!other->CheckHitChance(this, skillinuse, MainRange, GetSpecialAbilityParam(SPECATK_RANGED_ATK, 2)))
|
||||
{
|
||||
mlog(COMBAT__RANGED, "Ranged attack missed %s.", other->GetName());
|
||||
other->Damage(this, 0, SPELL_UNKNOWN, skillinuse);
|
||||
}
|
||||
else
|
||||
TotalDmg = -5;
|
||||
{
|
||||
int16 WDmg = GetWeaponDamage(other, weapon);
|
||||
int16 ADmg = GetWeaponDamage(other, ammo);
|
||||
int32 TotalDmg = 0;
|
||||
if(WDmg > 0 || ADmg > 0)
|
||||
{
|
||||
mlog(COMBAT__RANGED, "Ranged attack hit %s.", other->GetName());
|
||||
|
||||
int32 MaxDmg = max_dmg * RuleR(Combat, ArcheryNPCMultiplier); // should add a field to npc_types
|
||||
int32 MinDmg = min_dmg * RuleR(Combat, ArcheryNPCMultiplier);
|
||||
|
||||
if (TotalDmg > 0)
|
||||
other->AddToHateList(this, TotalDmg, 0, false);
|
||||
else
|
||||
other->AddToHateList(this, 0, 0, false);
|
||||
if(RuleB(Combat, UseIntervalAC))
|
||||
TotalDmg = MaxDmg;
|
||||
else
|
||||
TotalDmg = MakeRandomInt(MinDmg, MaxDmg);
|
||||
|
||||
other->Damage(this, TotalDmg, SPELL_UNKNOWN, skillinuse);
|
||||
TotalDmg += TotalDmg * GetSpecialAbilityParam(SPECATK_RANGED_ATK, 3) / 100; //Damage modifier
|
||||
|
||||
other->AvoidDamage(this, TotalDmg, false);
|
||||
other->MeleeMitigation(this, TotalDmg, MinDmg);
|
||||
if (TotalDmg > 0)
|
||||
CommonOutgoingHitSuccess(other, TotalDmg, skillinuse);
|
||||
}
|
||||
|
||||
if (TotalDmg > 0 && HasSkillProcSuccess() && GetTarget() && !other->HasDied())
|
||||
TrySkillProc(other, skillinuse, 0, true, MainRange);
|
||||
else
|
||||
TotalDmg = -5;
|
||||
|
||||
if (TotalDmg > 0)
|
||||
other->AddToHateList(this, TotalDmg, 0, false);
|
||||
else
|
||||
other->AddToHateList(this, 0, 0, false);
|
||||
|
||||
other->Damage(this, TotalDmg, SPELL_UNKNOWN, skillinuse);
|
||||
|
||||
if (TotalDmg > 0 && HasSkillProcSuccess() && GetTarget() && !other->HasDied())
|
||||
TrySkillProc(other, skillinuse, 0, true, MainRange);
|
||||
}
|
||||
|
||||
//try proc on hits and misses
|
||||
if(other && !other->HasDied())
|
||||
TrySpellProc(nullptr, (const Item_Struct*)nullptr, other, MainRange);
|
||||
|
||||
if (HasSkillProcs() && other && !other->HasDied())
|
||||
TrySkillProc(other, skillinuse, 0, false, MainRange);
|
||||
|
||||
CommonBreakInvisible();
|
||||
}
|
||||
|
||||
//try proc on hits and misses
|
||||
if(other && !other->HasDied())
|
||||
TrySpellProc(nullptr, (const Item_Struct*)nullptr, other, MainRange);
|
||||
|
||||
if (HasSkillProcs() && other && !other->HasDied())
|
||||
TrySkillProc(other, skillinuse, 0, false, MainRange);
|
||||
|
||||
CommonBreakInvisible();
|
||||
}
|
||||
|
||||
uint16 Mob::GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg)
|
||||
{
|
||||
|
||||
uint16 Mob::GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg) {
|
||||
uint16 MaxDmg = (((2 * wDmg) * GetDamageTable(SkillThrowing)) / 100);
|
||||
|
||||
if (MaxDmg == 0)
|
||||
@@ -1096,8 +1086,7 @@ uint16 Mob::GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg)
|
||||
TotalDmg = MakeRandomInt(1, MaxDmg);
|
||||
|
||||
minDmg = 1;
|
||||
if(GetLevel() > 25)
|
||||
{
|
||||
if(GetLevel() > 25){
|
||||
TotalDmg += ((GetLevel()-25)/3);
|
||||
minDmg += ((GetLevel()-25)/3);
|
||||
minDmg += minDmg * GetMeleeMinDamageMod_SE(SkillThrowing) / 100;
|
||||
@@ -1190,9 +1179,8 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51
|
||||
|
||||
//consume ammo
|
||||
DeleteItemInInventory(ammo_slot, 1, true);
|
||||
CheckIncreaseSkill(SkillThrowing, GetTarget());
|
||||
|
||||
CommonBreakInvisible();
|
||||
CheckIncreaseSkill(SkillThrowing, GetTarget());
|
||||
CommonBreakInvisible();
|
||||
}
|
||||
|
||||
void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item_Struct* item, uint16 weapon_damage, int16 chance_mod,int16 focus, int ReuseTime)
|
||||
@@ -1222,8 +1210,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
|
||||
if (GetClass() == ROGUE && (BehindMob(other, GetX(), GetY())))
|
||||
Assassinate_Dmg = TryAssassinate(other, SkillThrowing, ranged_timer.GetDuration());
|
||||
|
||||
if(WDmg > 0)
|
||||
{
|
||||
if(WDmg > 0){
|
||||
int minDmg = 1;
|
||||
uint16 MaxDmg = GetThrownDamage(WDmg, TotalDmg, minDmg);
|
||||
|
||||
@@ -1313,8 +1300,7 @@ void Mob::SendItemAnimation(Mob *to, const Item_Struct *item, SkillUseTypes skil
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, float angle, float tilt, float arc, const char *IDFile, SkillUseTypes skillInUse) {
|
||||
|
||||
void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, float angle, float tilt, float arc, const char *IDFile, SkillUseTypes skillInUse) {
|
||||
if (!to)
|
||||
return;
|
||||
|
||||
@@ -1448,17 +1434,11 @@ void NPC::DoClassAttacks(Mob *target) {
|
||||
break;
|
||||
case MONK: case MONKGM: {
|
||||
uint8 satype = SkillKick;
|
||||
if(level > 29) {
|
||||
satype = SkillFlyingKick;
|
||||
} else if(level > 24) {
|
||||
satype = SkillDragonPunch;
|
||||
} else if(level > 19) {
|
||||
satype = SkillEagleStrike;
|
||||
} else if(level > 9) {
|
||||
satype = SkillTigerClaw;
|
||||
} else if(level > 4) {
|
||||
satype = SkillRoundKick;
|
||||
}
|
||||
if(level > 29) { satype = SkillFlyingKick; }
|
||||
else if(level > 24) { satype = SkillDragonPunch; }
|
||||
else if(level > 19) { satype = SkillEagleStrike; }
|
||||
else if(level > 9) { satype = SkillTigerClaw; }
|
||||
else if(level > 4) { satype = SkillRoundKick; }
|
||||
reuse = MonkSpecialAttack(target, satype);
|
||||
|
||||
reuse *= 1000;
|
||||
@@ -1467,8 +1447,7 @@ void NPC::DoClassAttacks(Mob *target) {
|
||||
}
|
||||
case WARRIOR: case WARRIORGM:{
|
||||
if(level >= RuleI(Combat, NPCBashKickLevel)){
|
||||
if(MakeRandomInt(0, 100) > 25) //tested on live, warrior mobs both kick and bash, kick about 75% of the time, casting doesn't seem to make a difference.
|
||||
{
|
||||
if(MakeRandomInt(0, 100) > 25){ //tested on live, warrior mobs both kick and bash, kick about 75% of the time, casting doesn't seem to make a difference.
|
||||
DoAnim(animKick);
|
||||
int32 dmg = 0;
|
||||
|
||||
@@ -1489,8 +1468,7 @@ void NPC::DoClassAttacks(Mob *target) {
|
||||
DoSpecialAttackDamage(target, SkillKick, dmg, 1, -1, reuse);
|
||||
did_attack = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
DoAnim(animTailRake);
|
||||
int32 dmg = 0;
|
||||
|
||||
@@ -1513,8 +1491,7 @@ void NPC::DoClassAttacks(Mob *target) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BERSERKER: case BERSERKERGM:
|
||||
{
|
||||
case BERSERKER: case BERSERKERGM:{
|
||||
int AtkRounds = 3;
|
||||
int32 max_dmg = 26 + ((GetLevel()-6) * 2);
|
||||
int32 min_dmg = 0;
|
||||
@@ -1530,8 +1507,7 @@ void NPC::DoClassAttacks(Mob *target) {
|
||||
|
||||
reuse = FrenzyReuseTime * 1000;
|
||||
|
||||
while(AtkRounds > 0) {
|
||||
|
||||
while(AtkRounds > 0) {
|
||||
if (GetTarget() && (AtkRounds == 1 || MakeRandomInt(0,100) < 75)){
|
||||
DoSpecialAttackDamage(GetTarget(), SkillFrenzy, max_dmg, min_dmg, -1 , reuse, true);
|
||||
}
|
||||
@@ -1569,8 +1545,7 @@ void NPC::DoClassAttacks(Mob *target) {
|
||||
}
|
||||
case CLERIC: case CLERICGM: //clerics can bash too.
|
||||
case SHADOWKNIGHT: case SHADOWKNIGHTGM:
|
||||
case PALADIN: case PALADINGM:
|
||||
{
|
||||
case PALADIN: case PALADINGM:{
|
||||
if(level >= RuleI(Combat, NPCBashKickLevel)){
|
||||
DoAnim(animTailRake);
|
||||
int32 dmg = 0;
|
||||
@@ -1610,8 +1585,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
return;
|
||||
|
||||
//check range for all these abilities, they are all close combat stuff
|
||||
if(!CombatRange(ca_target))
|
||||
{
|
||||
if(!CombatRange(ca_target)){
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1633,10 +1607,8 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
|
||||
uint16 skill_to_use = -1;
|
||||
|
||||
if (skill == -1){
|
||||
|
||||
switch(GetClass())
|
||||
{
|
||||
if (skill == -1){
|
||||
switch(GetClass()){
|
||||
case WARRIOR:
|
||||
case RANGER:
|
||||
case BEASTLORD:
|
||||
@@ -1687,14 +1659,11 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
if(skill_to_use == -1)
|
||||
return;
|
||||
|
||||
if(skill_to_use == SkillBash)
|
||||
{
|
||||
if (ca_target!=this)
|
||||
{
|
||||
if(skill_to_use == SkillBash) {
|
||||
if (ca_target!=this) {
|
||||
DoAnim(animTailRake);
|
||||
|
||||
if(GetWeaponDamage(ca_target, GetInv().GetItem(MainSecondary)) <= 0 &&
|
||||
GetWeaponDamage(ca_target, GetInv().GetItem(MainShoulders)) <= 0){
|
||||
if(GetWeaponDamage(ca_target, GetInv().GetItem(MainSecondary)) <= 0 && GetWeaponDamage(ca_target, GetInv().GetItem(MainShoulders)) <= 0){
|
||||
dmg = -5;
|
||||
}
|
||||
else{
|
||||
@@ -1715,16 +1684,14 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
|
||||
DoSpecialAttackDamage(ca_target, SkillBash, dmg, 1,-1,ReuseTime);
|
||||
|
||||
if(ReuseTime > 0 && !IsRiposte)
|
||||
{
|
||||
if(ReuseTime > 0 && !IsRiposte) {
|
||||
p_timers.Start(pTimerCombatAbility, ReuseTime);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(skill_to_use == SkillFrenzy)
|
||||
{
|
||||
if(skill_to_use == SkillFrenzy){
|
||||
CheckIncreaseSkill(SkillFrenzy, GetTarget(), 10);
|
||||
int AtkRounds = 3;
|
||||
int skillmod = 100*GetSkill(SkillFrenzy)/MaxSkill(SkillFrenzy);
|
||||
@@ -1758,10 +1725,8 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
return;
|
||||
}
|
||||
|
||||
if(skill_to_use == SkillKick)
|
||||
{
|
||||
if(ca_target!=this)
|
||||
{
|
||||
if(skill_to_use == SkillKick){
|
||||
if(ca_target!=this){
|
||||
DoAnim(animKick);
|
||||
|
||||
if(GetWeaponDamage(ca_target, GetInv().GetItem(MainFeet)) <= 0){
|
||||
@@ -1785,12 +1750,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
}
|
||||
}
|
||||
|
||||
if(skill_to_use == SkillFlyingKick ||
|
||||
skill_to_use == SkillDragonPunch ||
|
||||
skill_to_use == SkillEagleStrike ||
|
||||
skill_to_use == SkillTigerClaw ||
|
||||
skill_to_use == SkillRoundKick)
|
||||
{
|
||||
if(skill_to_use == SkillFlyingKick || skill_to_use == SkillDragonPunch || skill_to_use == SkillEagleStrike || skill_to_use == SkillTigerClaw || skill_to_use == SkillRoundKick) {
|
||||
ReuseTime = MonkSpecialAttack(ca_target, skill_to_use) - 1;
|
||||
MonkSpecialAttack(ca_target, skill_to_use);
|
||||
|
||||
@@ -1804,8 +1764,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick };
|
||||
MonkSpecialAttack(ca_target, MonkSPA[MakeRandomInt(0,4)]);
|
||||
|
||||
int TripleChance = 25;
|
||||
|
||||
int TripleChance = 25;
|
||||
if (bDoubleSpecialAttack > 100)
|
||||
TripleChance += TripleChance*(100-bDoubleSpecialAttack)/100;
|
||||
|
||||
@@ -1815,8 +1774,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
}
|
||||
}
|
||||
|
||||
if(skill_to_use == SkillBackstab)
|
||||
{
|
||||
if(skill_to_use == SkillBackstab){
|
||||
ReuseTime = BackstabReuseTime-1;
|
||||
|
||||
if (IsRiposte)
|
||||
@@ -1826,8 +1784,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
}
|
||||
|
||||
ReuseTime = (ReuseTime*HasteMod)/100;
|
||||
if(ReuseTime > 0 && !IsRiposte)
|
||||
{
|
||||
if(ReuseTime > 0 && !IsRiposte){
|
||||
p_timers.Start(pTimerCombatAbility, ReuseTime);
|
||||
}
|
||||
}
|
||||
@@ -1894,8 +1851,7 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) {
|
||||
|
||||
tauntchance /= 100.0f;
|
||||
|
||||
if (tauntchance > MakeRandomFloat(0, 1)) {
|
||||
|
||||
if (tauntchance > MakeRandomFloat(0, 1)) {
|
||||
if (hate_top && hate_top != this){
|
||||
newhate = (who->GetNPCHate(hate_top) - who->GetNPCHate(this)) + 1;
|
||||
who->CastToNPC()->AddToHateList(this, newhate);
|
||||
@@ -1917,8 +1873,7 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) {
|
||||
|
||||
if (HasSkillProcs())
|
||||
TrySkillProc(who, SkillTaunt, TauntReuseTime*1000);
|
||||
|
||||
|
||||
|
||||
if (Success && HasSkillProcSuccess())
|
||||
TrySkillProc(who, SkillTaunt, TauntReuseTime*1000, true);
|
||||
}
|
||||
@@ -1939,8 +1894,7 @@ void Mob::InstillDoubt(Mob *who) {
|
||||
if(!CombatRange(who))
|
||||
return;
|
||||
|
||||
if(IsClient())
|
||||
{
|
||||
if(IsClient()) {
|
||||
CastToClient()->CheckIncreaseSkill(SkillIntimidation, who, 10);
|
||||
}
|
||||
|
||||
@@ -1970,14 +1924,12 @@ void Mob::InstillDoubt(Mob *who) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) {
|
||||
|
||||
uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) {
|
||||
//Only works on YOUR target.
|
||||
if(defender && (defender->GetBodyType() == BT_Humanoid) && !defender->IsClient()
|
||||
&& (skillInUse == SkillArchery) && (GetTarget() == defender)) {
|
||||
|
||||
uint32 HeadShot_Dmg = aabonuses.HeadShot[1] + spellbonuses.HeadShot[1] + itembonuses.HeadShot[1];
|
||||
|
||||
uint32 HeadShot_Dmg = aabonuses.HeadShot[1] + spellbonuses.HeadShot[1] + itembonuses.HeadShot[1];
|
||||
uint8 HeadShot_Level = 0; //Get Highest Headshot Level
|
||||
HeadShot_Level = aabonuses.HSLevel;
|
||||
if (HeadShot_Level < spellbonuses.HSLevel)
|
||||
@@ -1985,8 +1937,7 @@ uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) {
|
||||
else if (HeadShot_Level < itembonuses.HSLevel)
|
||||
HeadShot_Level = itembonuses.HSLevel;
|
||||
|
||||
if(HeadShot_Dmg && HeadShot_Level && (defender->GetLevel() <= HeadShot_Level)){
|
||||
|
||||
if(HeadShot_Dmg && HeadShot_Level && (defender->GetLevel() <= HeadShot_Level)){
|
||||
float ProcChance = GetSpecialProcChances(MainRange);
|
||||
if(ProcChance > MakeRandomFloat(0,1))
|
||||
return HeadShot_Dmg;
|
||||
@@ -2079,7 +2030,7 @@ float Mob::GetAssassinateProcChances(uint16 ReuseTime)
|
||||
ProcChance += ProcChance * ProcBonus / 100.0f;
|
||||
|
||||
} else {
|
||||
/*Kayen: Unable to find data on old proc rate of assassinate, no idea if our formula is real or made up.*/
|
||||
/* Kayen: Unable to find data on old proc rate of assassinate, no idea if our formula is real or made up. */
|
||||
ProcChance = (10 + (static_cast<float>(mydex/10) + static_cast<float>(itembonuses.HeroicDEX /10)))/100.0f;
|
||||
|
||||
}
|
||||
@@ -2092,8 +2043,10 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
||||
if (!CanDoSpecialAttack(other))
|
||||
return;
|
||||
|
||||
//For spells using skill value 98 (feral swipe ect) server sets this to 67 automatically.
|
||||
//Kayen: This is unlikely to be completely accurate but use OFFENSE skill value for these effects.
|
||||
/*
|
||||
For spells using skill value 98 (feral swipe ect) server sets this to 67 automatically.
|
||||
Kayen: This is unlikely to be completely accurate but use OFFENSE skill value for these effects.
|
||||
*/
|
||||
if (skillinuse == SkillBegging)
|
||||
skillinuse = SkillOffense;
|
||||
|
||||
@@ -2102,8 +2055,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
||||
int Hand = MainPrimary;
|
||||
if (hate == 0 && weapon_damage > 1) hate = weapon_damage;
|
||||
|
||||
if(weapon_damage > 0){
|
||||
|
||||
if(weapon_damage > 0){
|
||||
if (focus) //From FcBaseEffects
|
||||
weapon_damage += weapon_damage*focus/100;
|
||||
|
||||
@@ -2113,12 +2065,10 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
||||
}
|
||||
|
||||
int32 min_hit = 1;
|
||||
int32 max_hit = (2*weapon_damage*GetDamageTable(skillinuse)) / 100;
|
||||
|
||||
if(GetLevel() >= 28 && IsWarriorClass() )
|
||||
{
|
||||
int ucDamageBonus = GetWeaponDamageBonus((const Item_Struct*) nullptr );
|
||||
int32 max_hit = (2 * weapon_damage*GetDamageTable(skillinuse)) / 100;
|
||||
|
||||
if(GetLevel() >= 28 && IsWarriorClass() ) {
|
||||
int ucDamageBonus = GetWeaponDamageBonus((const Item_Struct*) nullptr );
|
||||
min_hit += (int) ucDamageBonus;
|
||||
max_hit += (int) ucDamageBonus;
|
||||
hate += ucDamageBonus;
|
||||
@@ -2137,8 +2087,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
||||
}
|
||||
}
|
||||
|
||||
ApplySpecialAttackMod(skillinuse, max_hit, min_hit);
|
||||
|
||||
ApplySpecialAttackMod(skillinuse, max_hit, min_hit);
|
||||
min_hit += min_hit * GetMeleeMinDamageMod_SE(skillinuse) / 100;
|
||||
|
||||
if(max_hit < min_hit)
|
||||
@@ -2199,8 +2148,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
||||
TrySkillProc(other, skillinuse, ReuseTime, true);
|
||||
}
|
||||
|
||||
bool Mob::CanDoSpecialAttack(Mob *other)
|
||||
{
|
||||
bool Mob::CanDoSpecialAttack(Mob *other) {
|
||||
//Make sure everything is valid before doing any attacks.
|
||||
if (!other) {
|
||||
SetTarget(nullptr);
|
||||
@@ -2210,8 +2158,7 @@ bool Mob::CanDoSpecialAttack(Mob *other)
|
||||
if(!GetTarget())
|
||||
SetTarget(other);
|
||||
|
||||
if ((other == nullptr || ((IsClient() && CastToClient()->dead) || (other->IsClient() && other->CastToClient()->dead))
|
||||
|| HasDied() || (!IsAttackAllowed(other)))) {
|
||||
if ((other == nullptr || ((IsClient() && CastToClient()->dead) || (other->IsClient() && other->CastToClient()->dead)) || HasDied() || (!IsAttackAllowed(other)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+11
-11
@@ -20,7 +20,7 @@
|
||||
#include "masterentity.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/moremath.h"
|
||||
#include "../common/Item.h"
|
||||
#include "../common/item.h"
|
||||
#include "worldserver.h"
|
||||
#include "../common/skills.h"
|
||||
#include "../common/bodytypes.h"
|
||||
@@ -33,8 +33,8 @@
|
||||
#include "../common/unix.h"
|
||||
#endif
|
||||
|
||||
#include "StringIDs.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "string_ids.h"
|
||||
#include "quest_parser_collection.h"
|
||||
|
||||
extern Zone* zone;
|
||||
extern volatile bool ZoneLoaded;
|
||||
@@ -4761,24 +4761,24 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
|
||||
case SE_LimitSpellClass:
|
||||
if(focus_spell.base[i] < 0) { //Exclude
|
||||
if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellClass));
|
||||
if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellClass))
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LimitInclude[12] = true;
|
||||
if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellClass)); //Include
|
||||
if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellClass)) //Include
|
||||
LimitInclude[13] = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case SE_LimitSpellSubclass:
|
||||
if(focus_spell.base[i] < 0) { //Exclude
|
||||
if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellSubclass));
|
||||
if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellSubclass))
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LimitInclude[14] = true;
|
||||
if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellSubclass)); //Include
|
||||
if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellSubclass)) //Include
|
||||
LimitInclude[15] = true;
|
||||
}
|
||||
break;
|
||||
@@ -5093,7 +5093,7 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) {
|
||||
|
||||
if (IsValidSpell(proc_spellid)){
|
||||
|
||||
ProcChance = GetSympatheticProcChances(spell_id, spells[TempItem->Focus.Effect].base[0], TempItemAug->ProcRate);
|
||||
ProcChance = GetSympatheticProcChances(spell_id, spells[TempItemAug->Focus.Effect].base[0], TempItemAug->ProcRate);
|
||||
|
||||
if(MakeRandomFloat(0, 1) <= ProcChance)
|
||||
SympatheticProcList.push_back(proc_spellid);
|
||||
@@ -6470,4 +6470,4 @@ void Mob::CalcSpellPowerDistanceMod(uint16 spell_id, float range, Mob* caster)
|
||||
|
||||
SetSpellPowerDistanceMod(static_cast<int>(mod));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+79
-91
@@ -71,13 +71,13 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
#include "masterentity.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/moremath.h"
|
||||
#include "../common/Item.h"
|
||||
#include "../common/item.h"
|
||||
#include "worldserver.h"
|
||||
#include "../common/skills.h"
|
||||
#include "../common/bodytypes.h"
|
||||
#include "../common/classes.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -90,8 +90,8 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
#include "../common/packet_dump_file.h"
|
||||
#endif
|
||||
|
||||
#include "StringIDs.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "string_ids.h"
|
||||
#include "quest_parser_collection.h"
|
||||
|
||||
extern Zone* zone;
|
||||
extern volatile bool ZoneLoaded;
|
||||
@@ -1252,7 +1252,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
|
||||
}
|
||||
}
|
||||
|
||||
if(IsClient()) {
|
||||
if(IsClient()) {
|
||||
CheckNumHitsRemaining(NUMHIT_MatchingSpells);
|
||||
TrySympatheticProc(target, spell_id);
|
||||
}
|
||||
@@ -1378,7 +1378,7 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
mlog(AA__MESSAGE, "Project Illusion overwrote target caster: %s spell id: %d was ON", GetName(), spell_id);
|
||||
targetType = ST_GroupClientAndPet;
|
||||
}
|
||||
|
||||
|
||||
if (spell_target && !spell_target->PassCastRestriction(true, spells[spell_id].CastRestriction)){
|
||||
Message_StringID(13,SPELL_NEED_TAR);
|
||||
return false;
|
||||
@@ -1386,16 +1386,16 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
|
||||
//Must be out of combat. (If Beneficial checks casters combat state, Deterimental checks targets)
|
||||
if (!spells[spell_id].InCombat && spells[spell_id].OutofCombat){
|
||||
if (IsDetrimentalSpell(spell_id)) {
|
||||
if ( (spell_target->IsNPC() && spell_target->IsEngaged()) ||
|
||||
if (IsDetrimentalSpell(spell_id)) {
|
||||
if ( (spell_target->IsNPC() && spell_target->IsEngaged()) ||
|
||||
(spell_target->IsClient() && spell_target->CastToClient()->GetAggroCount())){
|
||||
Message_StringID(13,SPELL_NO_EFFECT); //Unsure correct string
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
else if (IsBeneficialSpell(spell_id)) {
|
||||
if ( (IsNPC() && IsEngaged()) ||
|
||||
else if (IsBeneficialSpell(spell_id)) {
|
||||
if ( (IsNPC() && IsEngaged()) ||
|
||||
(IsClient() && CastToClient()->GetAggroCount())){
|
||||
if (IsDiscipline(spell_id))
|
||||
Message_StringID(13,NO_ABILITY_IN_COMBAT);
|
||||
@@ -1409,16 +1409,16 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
|
||||
//Must be in combat. (If Beneficial checks casters combat state, Deterimental checks targets)
|
||||
else if (spells[spell_id].InCombat && !spells[spell_id].OutofCombat){
|
||||
if (IsDetrimentalSpell(spell_id)) {
|
||||
if ( (spell_target->IsNPC() && !spell_target->IsEngaged()) ||
|
||||
if (IsDetrimentalSpell(spell_id)) {
|
||||
if ( (spell_target->IsNPC() && !spell_target->IsEngaged()) ||
|
||||
(spell_target->IsClient() && !spell_target->CastToClient()->GetAggroCount())){
|
||||
Message_StringID(13,SPELL_NO_EFFECT); //Unsure correct string
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
else if (IsBeneficialSpell(spell_id)) {
|
||||
if ( (IsNPC() && !IsEngaged()) ||
|
||||
else if (IsBeneficialSpell(spell_id)) {
|
||||
if ( (IsNPC() && !IsEngaged()) ||
|
||||
(IsClient() && !CastToClient()->GetAggroCount())){
|
||||
if (IsDiscipline(spell_id))
|
||||
Message_StringID(13,NO_ABILITY_OUT_OF_COMBAT);
|
||||
@@ -1782,10 +1782,10 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
|
||||
case ST_PetMaster:
|
||||
{
|
||||
|
||||
|
||||
Mob *owner = nullptr;
|
||||
|
||||
if (IsPet())
|
||||
|
||||
if (IsPet())
|
||||
owner = GetOwner();
|
||||
else if ((IsNPC() && CastToNPC()->GetSwarmOwner()))
|
||||
owner = entity_list.GetMobID(CastToNPC()->GetSwarmOwner());
|
||||
@@ -1975,7 +1975,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
if (!TrySpellProjectile(spell_target, spell_id))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
else if(!SpellOnTarget(spell_id, spell_target, false, true, resist_adjust, false)) {
|
||||
if(IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id)) {
|
||||
// Prevent mana usage/timers being set for beneficial buffs
|
||||
@@ -2143,7 +2143,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
{
|
||||
if(CheckLosFN((*iter)) || spells[spell_id].npc_no_los){
|
||||
(*iter)->CalcSpellPowerDistanceMod(spell_id, 0, this);
|
||||
SpellOnTarget(spell_id, spell_target, false, true, resist_adjust);
|
||||
SpellOnTarget(spell_id, (*iter), false, true, resist_adjust);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2723,7 +2723,7 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
|
||||
if ((effect2 == SE_BStacker) && (!IsCastonFadeDurationSpell(spellid1) && buffs[buffslot].ticsremaining != 1 && IsEffectInSpell(spellid1, SE_CStacker)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (spellbonuses.DStacker[0]) {
|
||||
if ((effect2 == SE_DStacker) && (sp2.effectid[i] <= spellbonuses.DStacker[1]))
|
||||
return -1;
|
||||
@@ -2775,7 +2775,7 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
|
||||
mlog(SPELLS__STACKING, "%s (%d) blocks effect %d on slot %d below %d, but we do not have that effect on that slot. Ignored.",
|
||||
sp1.name, spellid1, blocked_effect, blocked_slot, blocked_below_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mlog(SPELLS__STACKING, "%s (%d) and %s (%d) appear to be in the same line, skipping Stacking Overwrite/Blocking checks",
|
||||
@@ -3564,7 +3564,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
if(spell_effectiveness == 0 || !IsPartialCapableSpell(spell_id) )
|
||||
{
|
||||
mlog(SPELLS__RESISTS, "Spell %d was completely resisted by %s", spell_id, spelltar->GetName());
|
||||
|
||||
|
||||
if (spells[spell_id].resisttype == RESIST_PHYSICAL){
|
||||
Message_StringID(MT_SpellFailure, PHYSICAL_RESIST_FAIL,spells[spell_id].name);
|
||||
spelltar->Message_StringID(MT_SpellFailure, YOU_RESIST, spells[spell_id].name);
|
||||
@@ -3707,7 +3707,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
|
||||
TrySpellTrigger(spelltar, spell_id);
|
||||
TryApplyEffect(spelltar, spell_id);
|
||||
|
||||
|
||||
if (spelltar->IsAIControlled() && IsDetrimentalSpell(spell_id) && !IsHarmonySpell(spell_id)) {
|
||||
int32 aggro_amount = CheckAggroAmount(spell_id, isproc);
|
||||
mlog(SPELLS__CASTING, "Spell %d cast on %s generated %d hate", spell_id, spelltar->GetName(), aggro_amount);
|
||||
@@ -3733,7 +3733,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
safe_delete(action_packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// cause the effects to the target
|
||||
if(!spelltar->SpellEffect(this, spell_id, spell_effectiveness))
|
||||
{
|
||||
@@ -3746,11 +3746,11 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (IsDetrimentalSpell(spell_id)) {
|
||||
|
||||
|
||||
CheckNumHitsRemaining(NUMHIT_OutgoingSpells);
|
||||
|
||||
|
||||
if (spelltar)
|
||||
spelltar->CheckNumHitsRemaining(NUMHIT_IncomingSpells);
|
||||
}
|
||||
@@ -4408,7 +4408,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
|
||||
if (CharismaCheck)
|
||||
{
|
||||
/*
|
||||
/*
|
||||
Charisma ONLY effects the initial resist check when charm is cast with 10 CHA = -1 Resist mod up to 255 CHA (min ~ 75 cha)
|
||||
Charisma less than ~ 75 gives a postive modifier to resist checks at approximate ratio of -10 CHA = +6 Resist.
|
||||
Mez spells do same initial resist check as a above.
|
||||
@@ -4470,7 +4470,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
if (CharmTick) {
|
||||
|
||||
int min_charmbreakchance = ((100/RuleI(Spells, CharmBreakCheckChance))/66 * 100)*2;
|
||||
|
||||
|
||||
if (resist_chance < min_charmbreakchance)
|
||||
resist_chance = min_charmbreakchance;
|
||||
}
|
||||
@@ -4965,68 +4965,56 @@ int Client::FindSpellBookSlotBySpellID(uint16 spellid) {
|
||||
return -1; //default
|
||||
}
|
||||
|
||||
bool Client::SpellGlobalCheck(uint16 Spell_ID, uint16 Char_ID) {
|
||||
bool Client::SpellGlobalCheck(uint16 spell_ID, uint16 char_ID) {
|
||||
|
||||
std::string Spell_Global_Name;
|
||||
int Spell_Global_Value;
|
||||
int Global_Value;
|
||||
std::string spell_Global_Name;
|
||||
int spell_Global_Value;
|
||||
int global_Value;
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "SELECT qglobal, value FROM spell_globals WHERE spellid=%i", Spell_ID), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
Spell_Global_Name = row[0];
|
||||
Spell_Global_Value = atoi(row[1]);
|
||||
|
||||
mysql_free_result(result);
|
||||
|
||||
if (Spell_Global_Name.empty()) { // If the entry in the spell_globals table has nothing set for the qglobal name
|
||||
return true;
|
||||
}
|
||||
else if (database.RunQuery(query,MakeAnyLenString(&query, "SELECT value FROM quest_globals WHERE charid=%i AND name='%s'", Char_ID, Spell_Global_Name.c_str()), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
|
||||
Global_Value = atoi(row[0]);
|
||||
mysql_free_result(result);
|
||||
if (Global_Value == Spell_Global_Value) { // If the values match from both tables, allow the spell to be scribed
|
||||
return true;
|
||||
}
|
||||
else if (Global_Value > Spell_Global_Value) { // Check if the qglobal value is greater than the require spellglobal value
|
||||
return true;
|
||||
}
|
||||
else // If no matching result found in qglobals, don't scribe this spell
|
||||
{
|
||||
LogFile->write(EQEMuLog::Error, "Char ID: %i Spell_globals Name: '%s' Value: '%i' did not match QGlobal Value: '%i' for Spell ID %i", Char_ID, Spell_Global_Name.c_str(), Spell_Global_Value, Global_Value, Spell_ID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
LogFile->write(EQEMuLog::Error, "Char ID: %i does not have the Qglobal Name: '%s' for Spell ID %i", Char_ID, Spell_Global_Name.c_str(), Spell_ID);
|
||||
safe_delete_array(query);
|
||||
}
|
||||
else
|
||||
LogFile->write(EQEMuLog::Error, "Spell ID %i query of spell_globals with Name: '%s' Value: '%i' failed", Spell_ID, Spell_Global_Name.c_str(), Spell_Global_Value);
|
||||
}
|
||||
else {
|
||||
return true; // Spell ID isn't listed in the spells_global table, so it is not restricted from scribing
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
LogFile->write(EQEMuLog::Error, "Error while querying Spell ID %i spell_globals table query '%s': %s", Spell_ID, query, errbuf);
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT qglobal, value FROM spell_globals "
|
||||
"WHERE spellid = %i", spell_ID);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error while querying Spell ID %i spell_globals table query '%s': %s", spell_ID, query.c_str(), results.ErrorMessage().c_str());
|
||||
return false; // Query failed, so prevent spell from scribing just in case
|
||||
}
|
||||
return false; // Default is false
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return true; // Spell ID isn't listed in the spells_global table, so it is not restricted from scribing
|
||||
|
||||
auto row = results.begin();
|
||||
spell_Global_Name = row[0];
|
||||
spell_Global_Value = atoi(row[1]);
|
||||
|
||||
if (spell_Global_Name.empty())
|
||||
return true; // If the entry in the spell_globals table has nothing set for the qglobal name
|
||||
|
||||
query = StringFormat("SELECT value FROM quest_globals "
|
||||
"WHERE charid = %i AND name = '%s'",
|
||||
char_ID, spell_Global_Name.c_str());
|
||||
results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Spell ID %i query of spell_globals with Name: '%s' Value: '%i' failed", spell_ID, spell_Global_Name.c_str(), spell_Global_Value);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1) {
|
||||
LogFile->write(EQEMuLog::Error, "Char ID: %i does not have the Qglobal Name: '%s' for Spell ID %i", char_ID, spell_Global_Name.c_str(), spell_ID);
|
||||
return false;
|
||||
}
|
||||
|
||||
row = results.begin();
|
||||
|
||||
global_Value = atoi(row[0]);
|
||||
|
||||
if (global_Value == spell_Global_Value)
|
||||
return true; // If the values match from both tables, allow the spell to be scribed
|
||||
else if (global_Value > spell_Global_Value)
|
||||
return true; // Check if the qglobal value is greater than the require spellglobal value
|
||||
|
||||
// If no matching result found in qglobals, don't scribe this spell
|
||||
LogFile->write(EQEMuLog::Error, "Char ID: %i Spell_globals Name: '%s' Value: '%i' did not match QGlobal Value: '%i' for Spell ID %i", char_ID, spell_Global_Name.c_str(), spell_Global_Value, global_Value, spell_ID);
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO get rid of this
|
||||
@@ -5081,7 +5069,7 @@ bool Mob::FindType(uint16 type, bool bOffensive, uint16 threshold) {
|
||||
}
|
||||
|
||||
bool Mob::IsCombatProc(uint16 spell_id) {
|
||||
|
||||
|
||||
if (RuleB(Spells, FocusCombatProcs))
|
||||
return false;
|
||||
|
||||
@@ -5092,7 +5080,7 @@ bool Mob::IsCombatProc(uint16 spell_id) {
|
||||
{
|
||||
|
||||
for (int i = 0; i < MAX_PROCS; i++){
|
||||
if (PermaProcs[i].spellID == spell_id || SpellProcs[i].spellID == spell_id
|
||||
if (PermaProcs[i].spellID == spell_id || SpellProcs[i].spellID == spell_id
|
||||
|| RangedProcs[i].spellID == spell_id){
|
||||
return true;
|
||||
}
|
||||
@@ -5150,7 +5138,7 @@ bool Mob::AddDefensiveProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id
|
||||
{
|
||||
if(spell_id == SPELL_UNKNOWN)
|
||||
return(false);
|
||||
|
||||
|
||||
int i;
|
||||
for (i = 0; i < MAX_PROCS; i++) {
|
||||
if (DefensiveProcs[i].spellID == SPELL_UNKNOWN) {
|
||||
|
||||
+20
-12
@@ -27,24 +27,23 @@ Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net)
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "masterentity.h"
|
||||
#include "../common/features.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "mob.h"
|
||||
#include "queryserv.h"
|
||||
|
||||
extern QueryServ* QServ;
|
||||
|
||||
TaskManager::TaskManager() {
|
||||
|
||||
for(int i=0; i<MAXTASKS; i++)
|
||||
Tasks[i] = nullptr;
|
||||
|
||||
|
||||
}
|
||||
|
||||
TaskManager::~TaskManager() {
|
||||
|
||||
for(int i=0; i<MAXTASKS; i++) {
|
||||
if(Tasks[i] != nullptr) {
|
||||
for(int j=0; j<Tasks[i]->ActivityCount; j++) {
|
||||
@@ -61,11 +60,8 @@ TaskManager::~TaskManager() {
|
||||
}
|
||||
|
||||
bool TaskManager::LoadTaskSets() {
|
||||
|
||||
|
||||
const char *TaskSetQuery = "SELECT `id`, `taskid` from `tasksets` WHERE `id` > 0 AND `id` < %i "
|
||||
"AND `taskid` >= 0 AND `taskid` < %i ORDER BY `id`, `taskid` ASC";
|
||||
|
||||
const char *ERR_MYSQLERROR = "[TASKS]Error in TaskManager::LoadTaskSets: %s";
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
@@ -1984,12 +1980,17 @@ void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int T
|
||||
// Inform the client the task has been updated, both by a chat message
|
||||
c->Message(0, "Your task '%s' has been updated.", Task->Title);
|
||||
|
||||
if(Task->Activity[ActivityID].GoalMethod != METHODQUEST)
|
||||
{
|
||||
if(Task->Activity[ActivityID].GoalMethod != METHODQUEST) {
|
||||
char buf[24];
|
||||
snprintf(buf, 23, "%d %d", ActiveTasks[TaskIndex].TaskID, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID);
|
||||
buf[23] = '\0';
|
||||
parse->EventPlayer(EVENT_TASK_STAGE_COMPLETE, c, buf, 0);
|
||||
|
||||
/* QS: PlayerLogTaskUpdates :: Update */
|
||||
if (RuleB(QueryServ, PlayerLogTaskUpdates)){
|
||||
std::string event_desc = StringFormat("Task Stage Complete :: taskid:%i activityid:%i donecount:%i in zoneid:%i instid:%i", ActiveTasks[TaskIndex].TaskID, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID, ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount, c->GetZoneID(), c->GetInstanceID());
|
||||
QServ->PlayerLogEvent(Player_Log_Task_Updates, c->CharacterID(), event_desc);
|
||||
}
|
||||
}
|
||||
|
||||
// If this task is now complete, the Completed tasks will have been
|
||||
@@ -2001,6 +2002,12 @@ void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int T
|
||||
buf[23] = '\0';
|
||||
parse->EventPlayer(EVENT_TASK_COMPLETE, c, buf, 0);
|
||||
|
||||
/* QS: PlayerLogTaskUpdates :: Complete */
|
||||
if (RuleB(QueryServ, PlayerLogTaskUpdates)){
|
||||
std::string event_desc = StringFormat("Task Complete :: taskid:%i activityid:%i donecount:%i in zoneid:%i instid:%i", ActiveTasks[TaskIndex].TaskID, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID, ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount, c->GetZoneID(), c->GetInstanceID());
|
||||
QServ->PlayerLogEvent(Player_Log_Task_Updates, c->CharacterID(), event_desc);
|
||||
}
|
||||
|
||||
taskmanager->SendCompletedTasksToClient(c, this);
|
||||
c->SendTaskActivityComplete(ActiveTasks[TaskIndex].TaskID, 0, TaskIndex, false);
|
||||
taskmanager->SaveClientState(c, this);
|
||||
@@ -2010,6 +2017,7 @@ void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int T
|
||||
// If Experience and/or cash rewards are set, reward them from the task even if RewardMethod is METHODQUEST
|
||||
RewardTask(c, Task);
|
||||
//RemoveTask(c, TaskIndex);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "masterentity.h"
|
||||
#include "titles.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "worldserver.h"
|
||||
|
||||
extern WorldServer worldserver;
|
||||
|
||||
+58
-38
@@ -29,11 +29,14 @@
|
||||
#include "../common/packet_functions.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "titles.h"
|
||||
#include "StringIDs.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "queryserv.h"
|
||||
|
||||
extern QueryServ* QServ;
|
||||
|
||||
static const SkillUseTypes TradeskillUnknown = Skill1HBlunt; /* an arbitrary non-tradeskill */
|
||||
|
||||
@@ -928,20 +931,20 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
|
||||
_log(TRADESKILLS__TRACE, "...Bonusstat: %d , INT: %d , WIS: %d , DEX: %d , STR: %d", bonusstat , GetINT() , GetWIS() , GetDEX() , GetSTR());
|
||||
|
||||
float res = MakeRandomFloat(0, 99);
|
||||
int AAChance = 0;
|
||||
int aa_chance = 0;
|
||||
|
||||
//AA modifiers
|
||||
//can we do this with nested switches?
|
||||
if(spec->tradeskill == SkillAlchemy){
|
||||
switch(GetAA(aaAlchemyMastery)){
|
||||
case 1:
|
||||
AAChance = 10;
|
||||
aa_chance = 10;
|
||||
break;
|
||||
case 2:
|
||||
AAChance = 25;
|
||||
aa_chance = 25;
|
||||
break;
|
||||
case 3:
|
||||
AAChance = 50;
|
||||
aa_chance = 50;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -949,13 +952,13 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
|
||||
if(spec->tradeskill == SkillJewelryMaking){
|
||||
switch(GetAA(aaJewelCraftMastery)){
|
||||
case 1:
|
||||
AAChance = 10;
|
||||
aa_chance = 10;
|
||||
break;
|
||||
case 2:
|
||||
AAChance = 25;
|
||||
aa_chance = 25;
|
||||
break;
|
||||
case 3:
|
||||
AAChance = 50;
|
||||
aa_chance = 50;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -964,13 +967,13 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
|
||||
if (spec->tradeskill == SkillBlacksmithing) {
|
||||
switch(GetAA(aaBlacksmithingMastery)) {
|
||||
case 1:
|
||||
AAChance = 10;
|
||||
aa_chance = 10;
|
||||
break;
|
||||
case 2:
|
||||
AAChance = 25;
|
||||
aa_chance = 25;
|
||||
break;
|
||||
case 3:
|
||||
AAChance = 50;
|
||||
aa_chance = 50;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -978,13 +981,13 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
|
||||
if (spec->tradeskill == SkillBaking) {
|
||||
switch(GetAA(aaBakingMastery)) {
|
||||
case 1:
|
||||
AAChance = 10;
|
||||
aa_chance = 10;
|
||||
break;
|
||||
case 2:
|
||||
AAChance = 25;
|
||||
aa_chance = 25;
|
||||
break;
|
||||
case 3:
|
||||
AAChance = 50;
|
||||
aa_chance = 50;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -992,13 +995,13 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
|
||||
if (spec->tradeskill == SkillBrewing) {
|
||||
switch(GetAA(aaBrewingMastery)) {
|
||||
case 1:
|
||||
AAChance = 10;
|
||||
aa_chance = 10;
|
||||
break;
|
||||
case 2:
|
||||
AAChance = 25;
|
||||
aa_chance = 25;
|
||||
break;
|
||||
case 3:
|
||||
AAChance = 50;
|
||||
aa_chance = 50;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1006,13 +1009,13 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
|
||||
if (spec->tradeskill == SkillFletching) {
|
||||
switch(GetAA(aaFletchingMastery2)) {
|
||||
case 1:
|
||||
AAChance = 10;
|
||||
aa_chance = 10;
|
||||
break;
|
||||
case 2:
|
||||
AAChance = 25;
|
||||
aa_chance = 25;
|
||||
break;
|
||||
case 3:
|
||||
AAChance = 50;
|
||||
aa_chance = 50;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1020,13 +1023,13 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
|
||||
if (spec->tradeskill == SkillPottery) {
|
||||
switch(GetAA(aaPotteryMastery)) {
|
||||
case 1:
|
||||
AAChance = 10;
|
||||
aa_chance = 10;
|
||||
break;
|
||||
case 2:
|
||||
AAChance = 25;
|
||||
aa_chance = 25;
|
||||
break;
|
||||
case 3:
|
||||
AAChance = 50;
|
||||
aa_chance = 50;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1034,13 +1037,13 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
|
||||
if (spec->tradeskill == SkillTailoring) {
|
||||
switch(GetAA(aaTailoringMastery)) {
|
||||
case 1:
|
||||
AAChance = 10;
|
||||
aa_chance = 10;
|
||||
break;
|
||||
case 2:
|
||||
AAChance = 25;
|
||||
aa_chance = 25;
|
||||
break;
|
||||
case 3:
|
||||
AAChance = 50;
|
||||
aa_chance = 50;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1048,26 +1051,26 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
|
||||
if (spec->tradeskill == SkillResearch) {
|
||||
switch(GetAA(aaArcaneTongues)) {
|
||||
case 1:
|
||||
AAChance = 10;
|
||||
aa_chance = 10;
|
||||
break;
|
||||
case 2:
|
||||
AAChance = 25;
|
||||
aa_chance = 25;
|
||||
break;
|
||||
case 3:
|
||||
AAChance = 50;
|
||||
aa_chance = 50;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
chance = mod_tradeskill_chance(chance, spec);
|
||||
|
||||
if (((spec->tradeskill==75) || GetGM() || (chance > res)) || MakeRandomInt(0, 99) < AAChance){
|
||||
if (((spec->tradeskill==75) || GetGM() || (chance > res)) || MakeRandomInt(0, 99) < aa_chance){
|
||||
success_modifier = 1;
|
||||
|
||||
if(over_trivial < 0)
|
||||
CheckIncreaseTradeskill(bonusstat, stat_modifier, skillup_modifier, success_modifier, spec->tradeskill);
|
||||
|
||||
Message_StringID(4,TRADESKILL_SUCCEED,spec->name.c_str());
|
||||
Message_StringID(4, TRADESKILL_SUCCEED, spec->name.c_str());
|
||||
|
||||
_log(TRADESKILLS__TRACE, "Tradeskill success");
|
||||
|
||||
@@ -1076,16 +1079,24 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
|
||||
//should we check this crap?
|
||||
SummonItem(itr->first, itr->second);
|
||||
item = database.GetItem(itr->first);
|
||||
if (this->GetGroup())
|
||||
{
|
||||
entity_list.MessageGroup(this,true,MT_Skills,"%s has successfully fashioned %s!",GetName(),item->Name);
|
||||
if (this->GetGroup()) {
|
||||
entity_list.MessageGroup(this, true, MT_Skills, "%s has successfully fashioned %s!", GetName(), item->Name);
|
||||
}
|
||||
|
||||
/* QS: Player_Log_Trade_Skill_Events */
|
||||
if (RuleB(QueryServ, PlayerLogTradeSkillEvents)){
|
||||
std::string event_desc = StringFormat("Success :: fashioned recipe_id:%i tskillid:%i trivial:%i chance:%4.2f in zoneid:%i instid:%i", spec->recipe_id, spec->tradeskill, spec->trivial, chance, this->GetZoneID(), this->GetInstanceID());
|
||||
QServ->PlayerLogEvent(Player_Log_Trade_Skill_Events, this->CharacterID(), event_desc);
|
||||
}
|
||||
|
||||
if(RuleB(TaskSystem, EnableTaskSystem))
|
||||
UpdateTasksForItem(ActivityTradeSkill, itr->first, itr->second);
|
||||
++itr;
|
||||
}
|
||||
return(true);
|
||||
} else {
|
||||
}
|
||||
/* Tradeskill Fail */
|
||||
else {
|
||||
success_modifier = 2; // Halves the chance
|
||||
|
||||
if(over_trivial < 0)
|
||||
@@ -1097,6 +1108,13 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
|
||||
if (this->GetGroup())
|
||||
{
|
||||
entity_list.MessageGroup(this,true,MT_Skills,"%s was unsuccessful in %s tradeskill attempt.",GetName(),this->GetGender() == 0 ? "his" : this->GetGender() == 1 ? "her" : "its");
|
||||
|
||||
}
|
||||
|
||||
/* QS: Player_Log_Trade_Skill_Events */
|
||||
if (RuleB(QueryServ, PlayerLogTradeSkillEvents)){
|
||||
std::string event_desc = StringFormat("Failed :: recipe_id:%i tskillid:%i trivial:%i chance:%4.2f in zoneid:%i instid:%i", spec->recipe_id, spec->tradeskill, spec->trivial, chance, this->GetZoneID(), this->GetInstanceID());
|
||||
QServ->PlayerLogEvent(Player_Log_Trade_Skill_Events, this->CharacterID(), event_desc);
|
||||
}
|
||||
|
||||
itr = spec->onfail.begin();
|
||||
@@ -1106,6 +1124,8 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
|
||||
++itr;
|
||||
}
|
||||
|
||||
/* Salvage Item rolls */
|
||||
|
||||
// Rolls on each item, is possible to return everything
|
||||
int SalvageChance = aabonuses.SalvageChance + itembonuses.SalvageChance + spellbonuses.SalvageChance;
|
||||
// Skip check if not a normal TS or if a quest recipe these should be nofail, but check amyways
|
||||
|
||||
+517
-218
@@ -17,12 +17,15 @@
|
||||
*/
|
||||
#include "../common/debug.h"
|
||||
#include "masterentity.h"
|
||||
#include "StringIDs.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "worldserver.h"
|
||||
#include "queryserv.h"
|
||||
|
||||
extern WorldServer worldserver;
|
||||
extern QueryServ* QServ;
|
||||
|
||||
// The maximum amount of a single bazaar/barter transaction expressed in copper.
|
||||
// Equivalent to 2 Million plat
|
||||
@@ -71,8 +74,9 @@ void Trade::Start(uint32 mob_id, bool initiate_with)
|
||||
}
|
||||
|
||||
// Add item from a given slot to trade bucket (automatically does bag data too)
|
||||
void Trade::AddEntity(uint16 from_slot_id, uint16 trade_slot_id)
|
||||
{
|
||||
void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) {
|
||||
// TODO: review for inventory saves / consider changing return type to bool so failure can be passed to desync handler
|
||||
|
||||
if (!owner || !owner->IsClient()) {
|
||||
// This should never happen
|
||||
LogFile->write(EQEMuLog::Debug, "Programming error: NPC's should not call Trade::AddEntity()");
|
||||
@@ -87,45 +91,56 @@ void Trade::AddEntity(uint16 from_slot_id, uint16 trade_slot_id)
|
||||
|
||||
// Item always goes into trade bucket from cursor
|
||||
Client* client = owner->CastToClient();
|
||||
const ItemInst* inst = client->GetInv().GetItem(MainCursor);
|
||||
ItemInst* inst = client->GetInv().GetItem(MainCursor);
|
||||
|
||||
if (!inst) {
|
||||
client->Message(13, "Error: Could not find item on your cursor!");
|
||||
return;
|
||||
}
|
||||
|
||||
_log(TRADING__HOLDER, "%s added item '%s' to trade slot %i", owner->GetName(), inst->GetItem()->Name, trade_slot_id);
|
||||
|
||||
ItemInst* inst2 = client->GetInv().GetItem(trade_slot_id);
|
||||
int new_charges = 0;
|
||||
if (!inst2 || !inst2->GetItem()) {
|
||||
// Send all item data to other client
|
||||
SendItemData(inst, trade_slot_id);
|
||||
// Move item on cursor to the trade slots
|
||||
client->PutItemInInventory(trade_slot_id, *inst);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (client->GetInv().GetItem(MainCursor)->GetID() != client->GetInv().GetItem(trade_slot_id)->GetID()) {
|
||||
|
||||
// it looks like the original code attempted to allow stacking...
|
||||
// (it just didn't handle partial stack move actions -U)
|
||||
if (stack_size > 0) {
|
||||
if (!inst->IsStackable() || !inst2 || !inst2->GetItem() || (inst->GetID() != inst2->GetID()) || (stack_size > inst->GetCharges())) {
|
||||
client->Kick();
|
||||
return;
|
||||
}
|
||||
new_charges = (inst2->GetCharges()+inst->GetCharges());
|
||||
if (new_charges < inst2->GetItem()->StackSize)
|
||||
{
|
||||
inst2->SetCharges(new_charges);
|
||||
new_charges = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_charges = inst->GetCharges()-(inst2->GetItem()->StackSize-inst2->GetCharges()); //Leftover charges = charges - difference
|
||||
|
||||
uint32 _stack_size = 0;
|
||||
|
||||
if ((stack_size + inst2->GetCharges()) > inst2->GetItem()->StackSize) {
|
||||
_stack_size = (stack_size + inst2->GetCharges()) - inst->GetItem()->StackSize;
|
||||
inst2->SetCharges(inst2->GetItem()->StackSize);
|
||||
}
|
||||
else {
|
||||
_stack_size = inst->GetCharges() - stack_size;
|
||||
inst2->SetCharges(stack_size + inst2->GetCharges());
|
||||
}
|
||||
|
||||
_log(TRADING__HOLDER, "%s added partial item '%s' stack (qty: %i) to trade slot %i", owner->GetName(), inst->GetItem()->Name, stack_size, trade_slot_id);
|
||||
|
||||
if (_stack_size > 0)
|
||||
inst->SetCharges(_stack_size);
|
||||
else
|
||||
client->DeleteItemInInventory(MainCursor);
|
||||
|
||||
SendItemData(inst2, trade_slot_id);
|
||||
}
|
||||
if (new_charges > 0)
|
||||
client->GetInv().GetItem(from_slot_id)->SetCharges(new_charges);
|
||||
else
|
||||
client->DeleteItemInInventory(from_slot_id);//, (ItemInst&)trade_inst);
|
||||
else {
|
||||
if (inst2 && inst2->GetID()) {
|
||||
client->Kick();
|
||||
return;
|
||||
}
|
||||
|
||||
SendItemData(inst, trade_slot_id);
|
||||
|
||||
_log(TRADING__HOLDER, "%s added item '%s' to trade slot %i", owner->GetName(), inst->GetItem()->Name, trade_slot_id);
|
||||
|
||||
client->PutItemInInventory(trade_slot_id, *inst);
|
||||
client->DeleteItemInInventory(MainCursor);
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve mob the owner is trading with
|
||||
@@ -304,200 +319,464 @@ void Trade::DumpTrade()
|
||||
#endif
|
||||
|
||||
void Client::ResetTrade() {
|
||||
const Item_Struct* TempItem = 0;
|
||||
ItemInst* ins;
|
||||
int x;
|
||||
AddMoneyToPP(trade->cp, trade->sp, trade->gp, trade->pp, true);
|
||||
for(x = EmuConstants::TRADE_BEGIN; x <= EmuConstants::TRADE_END; x++)
|
||||
{
|
||||
TempItem = 0;
|
||||
ins = GetInv().GetItem(x);
|
||||
if (ins)
|
||||
TempItem = ins->GetItem();
|
||||
if (TempItem)
|
||||
{
|
||||
bool is_arrow = (TempItem->ItemType == ItemTypeArrow) ? true : false;
|
||||
int freeslotid = GetInv().FindFreeSlot(ins->IsType(ItemClassContainer), true, TempItem->Size, is_arrow);
|
||||
if (freeslotid == INVALID_INDEX)
|
||||
{
|
||||
DropInst(ins);
|
||||
|
||||
// step 1: process bags
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
const ItemInst* inst = m_inv[trade_slot];
|
||||
|
||||
if (inst && inst->IsType(ItemClassContainer)) {
|
||||
int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst);
|
||||
|
||||
if (free_slot != INVALID_INDEX) {
|
||||
PutItemInInventory(free_slot, *inst);
|
||||
SendItemPacket(free_slot, inst, ItemPacketTrade);
|
||||
}
|
||||
else
|
||||
{
|
||||
PutItemInInventory(freeslotid, *ins);
|
||||
SendItemPacket(freeslotid, ins, ItemPacketTrade);
|
||||
else {
|
||||
DropInst(inst);
|
||||
}
|
||||
DeleteItemInInventory(x);
|
||||
|
||||
DeleteItemInInventory(trade_slot);
|
||||
}
|
||||
}
|
||||
|
||||
// step 2a: process stackables
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
ItemInst* inst = GetInv().GetItem(trade_slot);
|
||||
|
||||
if (inst && inst->IsStackable()) {
|
||||
while (true) {
|
||||
// there's no built-in safety check against an infinite loop..but, it should break on one of the conditional checks
|
||||
int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst);
|
||||
|
||||
if ((free_slot == MainCursor) || (free_slot == INVALID_INDEX))
|
||||
break;
|
||||
|
||||
ItemInst* partial_inst = GetInv().GetItem(free_slot);
|
||||
|
||||
if (!partial_inst)
|
||||
break;
|
||||
|
||||
if (partial_inst->GetID() != inst->GetID()) {
|
||||
_log(TRADING__ERROR, "Client::ResetTrade() - an incompatible location reference was returned by Inventory::FindFreeSlotForTradeItem()");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ((partial_inst->GetCharges() + inst->GetCharges()) > partial_inst->GetItem()->StackSize) {
|
||||
int16 new_charges = (partial_inst->GetCharges() + inst->GetCharges()) - partial_inst->GetItem()->StackSize;
|
||||
|
||||
partial_inst->SetCharges(partial_inst->GetItem()->StackSize);
|
||||
inst->SetCharges(new_charges);
|
||||
}
|
||||
else {
|
||||
partial_inst->SetCharges(partial_inst->GetCharges() + inst->GetCharges());
|
||||
inst->SetCharges(0);
|
||||
}
|
||||
|
||||
PutItemInInventory(free_slot, *partial_inst);
|
||||
SendItemPacket(free_slot, partial_inst, ItemPacketTrade);
|
||||
|
||||
if (inst->GetCharges() == 0) {
|
||||
DeleteItemInInventory(trade_slot);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// step 2b: adjust trade stack bias
|
||||
// (if any partial stacks exist before the final stack, FindFreeSlotForTradeItem() will return that slot in step 3 and an overwrite will occur)
|
||||
for (int16 trade_slot = EmuConstants::TRADE_END; trade_slot >= EmuConstants::TRADE_BEGIN; --trade_slot) {
|
||||
ItemInst* inst = GetInv().GetItem(trade_slot);
|
||||
|
||||
if (inst && inst->IsStackable()) {
|
||||
for (int16 bias_slot = EmuConstants::TRADE_BEGIN; bias_slot <= EmuConstants::TRADE_END; ++bias_slot) {
|
||||
if (bias_slot >= trade_slot)
|
||||
break;
|
||||
|
||||
ItemInst* bias_inst = GetInv().GetItem(bias_slot);
|
||||
|
||||
if (!bias_inst || (bias_inst->GetID() != inst->GetID()) || (bias_inst->GetCharges() >= bias_inst->GetItem()->StackSize))
|
||||
continue;
|
||||
|
||||
if ((bias_inst->GetCharges() + inst->GetCharges()) > bias_inst->GetItem()->StackSize) {
|
||||
int16 new_charges = (bias_inst->GetCharges() + inst->GetCharges()) - bias_inst->GetItem()->StackSize;
|
||||
|
||||
bias_inst->SetCharges(bias_inst->GetItem()->StackSize);
|
||||
inst->SetCharges(new_charges);
|
||||
}
|
||||
else {
|
||||
bias_inst->SetCharges(bias_inst->GetCharges() + inst->GetCharges());
|
||||
inst->SetCharges(0);
|
||||
}
|
||||
|
||||
if (inst->GetCharges() == 0) {
|
||||
DeleteItemInInventory(trade_slot);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// step 3: process everything else
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
const ItemInst* inst = m_inv[trade_slot];
|
||||
|
||||
if (inst) {
|
||||
int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst);
|
||||
|
||||
if (free_slot != INVALID_INDEX) {
|
||||
PutItemInInventory(free_slot, *inst);
|
||||
SendItemPacket(free_slot, inst, ItemPacketTrade);
|
||||
}
|
||||
else {
|
||||
DropInst(inst);
|
||||
}
|
||||
|
||||
DeleteItemInInventory(trade_slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer) {
|
||||
|
||||
void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, std::list<void*>* event_details) {
|
||||
if(tradingWith && tradingWith->IsClient()) {
|
||||
Client* other = tradingWith->CastToClient();
|
||||
QSPlayerLogTrade_Struct* qs_audit = nullptr;
|
||||
bool qs_log = false;
|
||||
|
||||
if(other) {
|
||||
mlog(TRADING__CLIENT, "Finishing trade with client %s", other->GetName());
|
||||
|
||||
int16 slot_id;
|
||||
const Item_Struct* item = nullptr;
|
||||
QSPlayerLogTrade_Struct* qsaudit = nullptr;
|
||||
bool QSPLT = false;
|
||||
|
||||
this->AddMoneyToPP(other->trade->cp, other->trade->sp, other->trade->gp, other->trade->pp, true);
|
||||
|
||||
// step 0: pre-processing
|
||||
// QS code
|
||||
if(qspack && RuleB(QueryServ, PlayerLogTrades)) {
|
||||
qsaudit = (QSPlayerLogTrade_Struct*) qspack->pBuffer;
|
||||
QSPLT = true;
|
||||
if (RuleB(QueryServ, PlayerLogTrades) && event_entry && event_details) {
|
||||
qs_audit = (QSPlayerLogTrade_Struct*)event_entry;
|
||||
qs_log = true;
|
||||
|
||||
if (finalizer) {
|
||||
qs_audit->char2_id = this->character_id;
|
||||
|
||||
if(finalizer) { qsaudit->char2_id = this->character_id; }
|
||||
else { qsaudit->char1_id = this->character_id; }
|
||||
qs_audit->char2_money.platinum = this->trade->pp;
|
||||
qs_audit->char2_money.gold = this->trade->gp;
|
||||
qs_audit->char2_money.silver = this->trade->sp;
|
||||
qs_audit->char2_money.copper = this->trade->cp;
|
||||
}
|
||||
else {
|
||||
qs_audit->char1_id = this->character_id;
|
||||
|
||||
qs_audit->char1_money.platinum = this->trade->pp;
|
||||
qs_audit->char1_money.gold = this->trade->gp;
|
||||
qs_audit->char1_money.silver = this->trade->sp;
|
||||
qs_audit->char1_money.copper = this->trade->cp;
|
||||
}
|
||||
}
|
||||
|
||||
// Move each trade slot into free inventory slot
|
||||
for(int16 i = EmuConstants::TRADE_BEGIN; i <= EmuConstants::TRADE_END; i++){
|
||||
const ItemInst* inst = m_inv[i];
|
||||
uint16 parent_offset = 0;
|
||||
// step 1: process bags
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
const ItemInst* inst = m_inv[trade_slot];
|
||||
|
||||
if(inst == nullptr) { continue; }
|
||||
if (inst && inst->IsType(ItemClassContainer)) {
|
||||
mlog(TRADING__CLIENT, "Giving container %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, trade_slot, other->GetName());
|
||||
|
||||
mlog(TRADING__CLIENT, "Giving %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, i, other->GetName());
|
||||
// TODO: need to check bag items/augments for no drop..everything for attuned...
|
||||
if (inst->GetItem()->NoDrop != 0 || Admin() >= RuleI(Character, MinStatusForNoDropExemptions) || RuleI(World, FVNoDropFlag) == 1 || other == this) {
|
||||
int16 free_slot = other->GetInv().FindFreeSlotForTradeItem(inst);
|
||||
|
||||
/// Log Player Trades through QueryServ if Rule Enabled
|
||||
if(QSPLT) {
|
||||
uint16 item_count = qsaudit->char1_count + qsaudit->char2_count;
|
||||
parent_offset = item_count;
|
||||
if (free_slot != INVALID_INDEX) {
|
||||
if (other->PutItemInInventory(free_slot, *inst, true)) {
|
||||
mlog(TRADING__CLIENT, "Container %s (%d) successfully transferred, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
if (qs_log) {
|
||||
QSTradeItems_Struct* detail = new QSTradeItems_Struct;
|
||||
|
||||
qsaudit->items[item_count].from_id = this->character_id;
|
||||
qsaudit->items[item_count].from_slot = i;
|
||||
qsaudit->items[item_count].to_id = other->CharacterID();
|
||||
qsaudit->items[item_count].to_slot = 0;
|
||||
qsaudit->items[item_count].item_id = inst->GetID();
|
||||
qsaudit->items[item_count].charges = inst->GetCharges();
|
||||
qsaudit->items[item_count].aug_1 = inst->GetAugmentItemID(1);
|
||||
qsaudit->items[item_count].aug_2 = inst->GetAugmentItemID(2);
|
||||
qsaudit->items[item_count].aug_3 = inst->GetAugmentItemID(3);
|
||||
qsaudit->items[item_count].aug_4 = inst->GetAugmentItemID(4);
|
||||
qsaudit->items[item_count].aug_5 = inst->GetAugmentItemID(5);
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = trade_slot;
|
||||
detail->to_id = other->CharacterID();
|
||||
detail->to_slot = free_slot;
|
||||
detail->item_id = inst->GetID();
|
||||
detail->charges = 1;
|
||||
detail->aug_1 = inst->GetAugmentItemID(1);
|
||||
detail->aug_2 = inst->GetAugmentItemID(2);
|
||||
detail->aug_3 = inst->GetAugmentItemID(3);
|
||||
detail->aug_4 = inst->GetAugmentItemID(4);
|
||||
detail->aug_5 = inst->GetAugmentItemID(5);
|
||||
|
||||
if(finalizer) { qsaudit->char2_count++; }
|
||||
else { qsaudit->char1_count++; }
|
||||
event_details->push_back(detail);
|
||||
|
||||
if (finalizer)
|
||||
qs_audit->char2_count += detail->charges;
|
||||
else
|
||||
qs_audit->char1_count += detail->charges;
|
||||
|
||||
if(inst->IsType(ItemClassContainer)) {
|
||||
// Pseudo-Slot ID's are generated based on how the db saves bag items...
|
||||
for(uint8 j = SUB_BEGIN; j < inst->GetItem()->BagSlots; j++) {
|
||||
const ItemInst* baginst = inst->GetItem(j);
|
||||
//for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) {
|
||||
for (uint8 sub_slot = SUB_BEGIN; (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++sub_slot) { // this is to catch ALL items
|
||||
const ItemInst* bag_inst = inst->GetItem(sub_slot);
|
||||
|
||||
if(baginst == nullptr) { continue; }
|
||||
if (bag_inst) {
|
||||
detail = new QSTradeItems_Struct;
|
||||
|
||||
int16 k=Inventory::CalcSlotId(i, j);
|
||||
item_count = qsaudit->char1_count + qsaudit->char2_count;
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = Inventory::CalcSlotId(trade_slot, sub_slot);
|
||||
detail->to_id = other->CharacterID();
|
||||
detail->to_slot = Inventory::CalcSlotId(free_slot, sub_slot);
|
||||
detail->item_id = bag_inst->GetID();
|
||||
detail->charges = (!bag_inst->IsStackable() ? 1 : bag_inst->GetCharges());
|
||||
detail->aug_1 = bag_inst->GetAugmentItemID(1);
|
||||
detail->aug_2 = bag_inst->GetAugmentItemID(2);
|
||||
detail->aug_3 = bag_inst->GetAugmentItemID(3);
|
||||
detail->aug_4 = bag_inst->GetAugmentItemID(4);
|
||||
detail->aug_5 = bag_inst->GetAugmentItemID(5);
|
||||
|
||||
qsaudit->items[item_count].from_id = this->character_id;
|
||||
qsaudit->items[item_count].from_slot = k;
|
||||
qsaudit->items[item_count].to_id = other->CharacterID();
|
||||
qsaudit->items[item_count].to_slot = 0;
|
||||
qsaudit->items[item_count].item_id = baginst->GetID();
|
||||
qsaudit->items[item_count].charges = baginst->GetCharges();
|
||||
qsaudit->items[item_count].aug_1 = baginst->GetAugmentItemID(1);
|
||||
qsaudit->items[item_count].aug_2 = baginst->GetAugmentItemID(2);
|
||||
qsaudit->items[item_count].aug_3 = baginst->GetAugmentItemID(3);
|
||||
qsaudit->items[item_count].aug_4 = baginst->GetAugmentItemID(4);
|
||||
qsaudit->items[item_count].aug_5 = baginst->GetAugmentItemID(5);
|
||||
event_details->push_back(detail);
|
||||
|
||||
if(finalizer) { qsaudit->char2_count++; }
|
||||
else { qsaudit->char1_count++; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inst->GetItem()->NoDrop != 0 || Admin() >= RuleI(Character, MinStatusForNoDropExemptions) || RuleI(World, FVNoDropFlag) == 1 || other == this) {
|
||||
bool is_arrow = (inst->GetItem()->ItemType == ItemTypeArrow) ? true : false;
|
||||
slot_id = other->GetInv().FindFreeSlot(inst->IsType(ItemClassContainer), true, inst->GetItem()->Size, is_arrow);
|
||||
|
||||
mlog(TRADING__CLIENT, "Trying to put %s (%d) into slot %d", inst->GetItem()->Name, inst->GetItem()->ID, slot_id);
|
||||
|
||||
if(other->PutItemInInventory(slot_id, *inst, true)) {
|
||||
mlog(TRADING__CLIENT, "Item %s (%d) successfully transfered, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
|
||||
if(QSPLT) {
|
||||
qsaudit->items[parent_offset].to_slot = slot_id;
|
||||
|
||||
if(inst->IsType(ItemClassContainer)) {
|
||||
for(uint8 bagslot_idx = SUB_BEGIN; bagslot_idx < inst->GetItem()->BagSlots; bagslot_idx++) {
|
||||
const ItemInst* bag_inst = inst->GetItem(bagslot_idx);
|
||||
|
||||
if(bag_inst == nullptr) { continue; }
|
||||
int16 to_bagslot_id = Inventory::CalcSlotId(slot_id, bagslot_idx);
|
||||
|
||||
qsaudit->items[++parent_offset].to_slot = to_bagslot_id;
|
||||
if (finalizer)
|
||||
qs_audit->char2_count += detail->charges;
|
||||
else
|
||||
qs_audit->char1_count += detail->charges;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "Transfer of container %s (%d) to %s failed, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName());
|
||||
PushItemOnCursor(*inst, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "%s's inventory is full, returning container %s (%d) to giver.", other->GetName(), inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
PushItemOnCursor(*inst, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "Container %s (%d) is NoDrop, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
PushItemOnCursor(*inst, true);
|
||||
mlog(TRADING__ERROR, "Unable to give item %d (%d) to %s, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName());
|
||||
|
||||
if(QSPLT) {
|
||||
qsaudit->items[parent_offset].to_id = this->character_id;
|
||||
qsaudit->items[parent_offset].to_slot = MainCursor;
|
||||
|
||||
if(inst->IsType(ItemClassContainer)) {
|
||||
for(uint8 bagslot_idx = SUB_BEGIN; bagslot_idx < inst->GetItem()->BagSlots; bagslot_idx++) {
|
||||
const ItemInst* bag_inst = inst->GetItem(bagslot_idx);
|
||||
|
||||
if(bag_inst == nullptr) { continue; }
|
||||
int16 to_bagslot_id = Inventory::CalcSlotId(MainCursor, bagslot_idx);
|
||||
|
||||
qsaudit->items[++parent_offset].to_id = this->character_id;
|
||||
qsaudit->items[parent_offset].to_slot = to_bagslot_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeleteItemInInventory(i);
|
||||
DeleteItemInInventory(trade_slot);
|
||||
}
|
||||
else {
|
||||
PushItemOnCursor(*inst, true);
|
||||
DeleteItemInInventory(i);
|
||||
}
|
||||
|
||||
if(QSPLT) {
|
||||
qsaudit->items[parent_offset].to_id = this->character_id;
|
||||
qsaudit->items[parent_offset].to_slot = MainCursor;
|
||||
// step 2a: process stackables
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
ItemInst* inst = GetInv().GetItem(trade_slot);
|
||||
|
||||
if(inst->IsType(ItemClassContainer)) {
|
||||
for(uint8 bagslot_idx = SUB_BEGIN; bagslot_idx < inst->GetItem()->BagSlots; bagslot_idx++) {
|
||||
const ItemInst* bag_inst = inst->GetItem(bagslot_idx);
|
||||
if (inst && inst->IsStackable()) {
|
||||
while (true) {
|
||||
// there's no built-in safety check against an infinite loop..but, it should break on one of the conditional checks
|
||||
int16 partial_slot = other->GetInv().FindFreeSlotForTradeItem(inst);
|
||||
|
||||
if(bag_inst == nullptr) { continue; }
|
||||
int16 to_bagslot_id = Inventory::CalcSlotId(MainCursor, bagslot_idx);
|
||||
if ((partial_slot == MainCursor) || (partial_slot == INVALID_INDEX))
|
||||
break;
|
||||
|
||||
qsaudit->items[++parent_offset].to_id = this->character_id;
|
||||
qsaudit->items[parent_offset].to_slot = to_bagslot_id;
|
||||
ItemInst* partial_inst = other->GetInv().GetItem(partial_slot);
|
||||
|
||||
if (!partial_inst)
|
||||
break;
|
||||
|
||||
if (partial_inst->GetID() != inst->GetID()) {
|
||||
_log(TRADING__ERROR, "Client::ResetTrade() - an incompatible location reference was returned by Inventory::FindFreeSlotForTradeItem()");
|
||||
break;
|
||||
}
|
||||
|
||||
int16 old_charges = inst->GetCharges();
|
||||
int16 partial_charges = partial_inst->GetCharges();
|
||||
|
||||
if ((partial_inst->GetCharges() + inst->GetCharges()) > partial_inst->GetItem()->StackSize) {
|
||||
int16 new_charges = (partial_inst->GetCharges() + inst->GetCharges()) - partial_inst->GetItem()->StackSize;
|
||||
|
||||
partial_inst->SetCharges(partial_inst->GetItem()->StackSize);
|
||||
inst->SetCharges(new_charges);
|
||||
}
|
||||
else {
|
||||
partial_inst->SetCharges(partial_inst->GetCharges() + inst->GetCharges());
|
||||
inst->SetCharges(0);
|
||||
}
|
||||
|
||||
mlog(TRADING__CLIENT, "Transferring partial stack %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, trade_slot, other->GetName());
|
||||
|
||||
if (other->PutItemInInventory(partial_slot, *partial_inst, true)) {
|
||||
mlog(TRADING__CLIENT, "Partial stack %s (%d) successfully transferred, deleting %i charges from trade slot.",
|
||||
inst->GetItem()->Name, inst->GetItem()->ID, (old_charges - inst->GetCharges()));
|
||||
if (qs_log) {
|
||||
QSTradeItems_Struct* detail = new QSTradeItems_Struct;
|
||||
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = trade_slot;
|
||||
detail->to_id = other->CharacterID();
|
||||
detail->to_slot = partial_slot;
|
||||
detail->item_id = inst->GetID();
|
||||
detail->charges = (old_charges - inst->GetCharges());
|
||||
detail->aug_1 = 0;
|
||||
detail->aug_2 = 0;
|
||||
detail->aug_3 = 0;
|
||||
detail->aug_4 = 0;
|
||||
detail->aug_5 = 0;
|
||||
|
||||
event_details->push_back(detail);
|
||||
|
||||
if (finalizer)
|
||||
qs_audit->char2_count += detail->charges;
|
||||
else
|
||||
qs_audit->char1_count += detail->charges;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "Transfer of partial stack %s (%d) to %s failed, returning %i charges to trade slot.",
|
||||
inst->GetItem()->Name, inst->GetItem()->ID, other->GetName(), (old_charges - inst->GetCharges()));
|
||||
|
||||
inst->SetCharges(old_charges);
|
||||
partial_inst->SetCharges(partial_charges);
|
||||
break;
|
||||
}
|
||||
|
||||
if (inst->GetCharges() == 0) {
|
||||
DeleteItemInInventory(trade_slot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Money - look into how NPC's receive cash
|
||||
this->AddMoneyToPP(other->trade->cp, other->trade->sp, other->trade->gp, other->trade->pp, true);
|
||||
// step 2b: adjust trade stack bias
|
||||
// (if any partial stacks exist before the final stack, FindFreeSlotForTradeItem() will return that slot in step 3 and an overwrite will occur)
|
||||
for (int16 trade_slot = EmuConstants::TRADE_END; trade_slot >= EmuConstants::TRADE_BEGIN; --trade_slot) {
|
||||
ItemInst* inst = GetInv().GetItem(trade_slot);
|
||||
|
||||
// This is currently setup to show character offers, not receipts
|
||||
if(QSPLT) {
|
||||
if(finalizer) {
|
||||
qsaudit->char2_money.platinum = this->trade->pp;
|
||||
qsaudit->char2_money.gold = this->trade->gp;
|
||||
qsaudit->char2_money.silver = this->trade->sp;
|
||||
qsaudit->char2_money.copper = this->trade->cp;
|
||||
if (inst && inst->IsStackable()) {
|
||||
for (int16 bias_slot = EmuConstants::TRADE_BEGIN; bias_slot <= EmuConstants::TRADE_END; ++bias_slot) {
|
||||
if (bias_slot >= trade_slot)
|
||||
break;
|
||||
|
||||
ItemInst* bias_inst = GetInv().GetItem(bias_slot);
|
||||
|
||||
if (!bias_inst || (bias_inst->GetID() != inst->GetID()) || (bias_inst->GetCharges() >= bias_inst->GetItem()->StackSize))
|
||||
continue;
|
||||
|
||||
int16 old_charges = inst->GetCharges();
|
||||
|
||||
if ((bias_inst->GetCharges() + inst->GetCharges()) > bias_inst->GetItem()->StackSize) {
|
||||
int16 new_charges = (bias_inst->GetCharges() + inst->GetCharges()) - bias_inst->GetItem()->StackSize;
|
||||
|
||||
bias_inst->SetCharges(bias_inst->GetItem()->StackSize);
|
||||
inst->SetCharges(new_charges);
|
||||
}
|
||||
else {
|
||||
bias_inst->SetCharges(bias_inst->GetCharges() + inst->GetCharges());
|
||||
inst->SetCharges(0);
|
||||
}
|
||||
|
||||
if (qs_log) {
|
||||
QSTradeItems_Struct* detail = new QSTradeItems_Struct;
|
||||
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = trade_slot;
|
||||
detail->to_id = this->character_id;
|
||||
detail->to_slot = bias_slot;
|
||||
detail->item_id = inst->GetID();
|
||||
detail->charges = (old_charges - inst->GetCharges());
|
||||
detail->aug_1 = 0;
|
||||
detail->aug_2 = 0;
|
||||
detail->aug_3 = 0;
|
||||
detail->aug_4 = 0;
|
||||
detail->aug_5 = 0;
|
||||
|
||||
event_details->push_back(detail);
|
||||
}
|
||||
|
||||
if (inst->GetCharges() == 0) {
|
||||
DeleteItemInInventory(trade_slot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
qsaudit->char1_money.platinum = this->trade->pp;
|
||||
qsaudit->char1_money.gold = this->trade->gp;
|
||||
qsaudit->char1_money.silver = this->trade->sp;
|
||||
qsaudit->char1_money.copper = this->trade->cp;
|
||||
}
|
||||
|
||||
// step 3: process everything else
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
const ItemInst* inst = m_inv[trade_slot];
|
||||
|
||||
if (inst) {
|
||||
mlog(TRADING__CLIENT, "Giving item %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, trade_slot, other->GetName());
|
||||
|
||||
// TODO: need to check bag items/augments for no drop..everything for attuned...
|
||||
if (inst->GetItem()->NoDrop != 0 || Admin() >= RuleI(Character, MinStatusForNoDropExemptions) || RuleI(World, FVNoDropFlag) == 1 || other == this) {
|
||||
int16 free_slot = other->GetInv().FindFreeSlotForTradeItem(inst);
|
||||
|
||||
if (free_slot != INVALID_INDEX) {
|
||||
if (other->PutItemInInventory(free_slot, *inst, true)) {
|
||||
mlog(TRADING__CLIENT, "Item %s (%d) successfully transferred, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
if (qs_log) {
|
||||
QSTradeItems_Struct* detail = new QSTradeItems_Struct;
|
||||
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = trade_slot;
|
||||
detail->to_id = other->CharacterID();
|
||||
detail->to_slot = free_slot;
|
||||
detail->item_id = inst->GetID();
|
||||
detail->charges = (!inst->IsStackable() ? 1 : inst->GetCharges());
|
||||
detail->aug_1 = inst->GetAugmentItemID(1);
|
||||
detail->aug_2 = inst->GetAugmentItemID(2);
|
||||
detail->aug_3 = inst->GetAugmentItemID(3);
|
||||
detail->aug_4 = inst->GetAugmentItemID(4);
|
||||
detail->aug_5 = inst->GetAugmentItemID(5);
|
||||
|
||||
event_details->push_back(detail);
|
||||
|
||||
if (finalizer)
|
||||
qs_audit->char2_count += detail->charges;
|
||||
else
|
||||
qs_audit->char1_count += detail->charges;
|
||||
|
||||
// 'step 3' should never really see containers..but, just in case...
|
||||
//for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) {
|
||||
for (uint8 sub_slot = SUB_BEGIN; (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++sub_slot) { // this is to catch ALL items
|
||||
const ItemInst* bag_inst = inst->GetItem(sub_slot);
|
||||
|
||||
if (bag_inst) {
|
||||
detail = new QSTradeItems_Struct;
|
||||
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = trade_slot;
|
||||
detail->to_id = other->CharacterID();
|
||||
detail->to_slot = free_slot;
|
||||
detail->item_id = bag_inst->GetID();
|
||||
detail->charges = (!bag_inst->IsStackable() ? 1 : bag_inst->GetCharges());
|
||||
detail->aug_1 = bag_inst->GetAugmentItemID(1);
|
||||
detail->aug_2 = bag_inst->GetAugmentItemID(2);
|
||||
detail->aug_3 = bag_inst->GetAugmentItemID(3);
|
||||
detail->aug_4 = bag_inst->GetAugmentItemID(4);
|
||||
detail->aug_5 = bag_inst->GetAugmentItemID(5);
|
||||
|
||||
event_details->push_back(detail);
|
||||
|
||||
if (finalizer)
|
||||
qs_audit->char2_count += detail->charges;
|
||||
else
|
||||
qs_audit->char1_count += detail->charges;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "Transfer of Item %s (%d) to %s failed, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName());
|
||||
PushItemOnCursor(*inst, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "%s's inventory is full, returning item %s (%d) to giver.", other->GetName(), inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
PushItemOnCursor(*inst, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "Item %s (%d) is NoDrop, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
PushItemOnCursor(*inst, true);
|
||||
}
|
||||
|
||||
DeleteItemInInventory(trade_slot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,62 +784,72 @@ void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer)
|
||||
}
|
||||
}
|
||||
else if(tradingWith && tradingWith->IsNPC()) {
|
||||
QSPlayerLogHandin_Struct* qsaudit = nullptr;
|
||||
bool QSPLH = false;
|
||||
QSPlayerLogHandin_Struct* qs_audit = nullptr;
|
||||
bool qs_log = false;
|
||||
|
||||
// QS code
|
||||
if(qspack && RuleB(QueryServ, PlayerLogTrades)) {
|
||||
if(RuleB(QueryServ, PlayerLogTrades) && event_entry && event_details) {
|
||||
// Currently provides only basic functionality. Calling method will also
|
||||
// need to be modified before item returns and rewards can be logged. -U
|
||||
qsaudit = (QSPlayerLogHandin_Struct*) qspack->pBuffer;
|
||||
QSPLH = true;
|
||||
qs_audit = (QSPlayerLogHandin_Struct*)event_entry;
|
||||
qs_log = true;
|
||||
|
||||
qsaudit->quest_id = 0;
|
||||
qsaudit->char_id = character_id;
|
||||
qsaudit->char_money.platinum = trade->pp;
|
||||
qsaudit->char_money.gold = trade->gp;
|
||||
qsaudit->char_money.silver = trade->sp;
|
||||
qsaudit->char_money.copper = trade->cp;
|
||||
qsaudit->char_count = 0;
|
||||
qsaudit->npc_id = tradingWith->GetNPCTypeID();
|
||||
qsaudit->npc_money.platinum = 0;
|
||||
qsaudit->npc_money.gold = 0;
|
||||
qsaudit->npc_money.silver = 0;
|
||||
qsaudit->npc_money.copper = 0;
|
||||
qsaudit->npc_count = 0;
|
||||
qs_audit->quest_id = 0;
|
||||
qs_audit->char_id = character_id;
|
||||
qs_audit->char_money.platinum = trade->pp;
|
||||
qs_audit->char_money.gold = trade->gp;
|
||||
qs_audit->char_money.silver = trade->sp;
|
||||
qs_audit->char_money.copper = trade->cp;
|
||||
qs_audit->char_count = 0;
|
||||
qs_audit->npc_id = tradingWith->GetNPCTypeID();
|
||||
qs_audit->npc_money.platinum = 0;
|
||||
qs_audit->npc_money.gold = 0;
|
||||
qs_audit->npc_money.silver = 0;
|
||||
qs_audit->npc_money.copper = 0;
|
||||
qs_audit->npc_count = 0;
|
||||
}
|
||||
|
||||
if(QSPLH) { // This can be incoporated below when revisions are made -U
|
||||
for(int16 slot_id = EmuConstants::TRADE_BEGIN; slot_id <= EmuConstants::TRADE_NPC_END; slot_id++) {
|
||||
const ItemInst* trade_inst = m_inv[slot_id];
|
||||
if(qs_log) { // This can be incorporated below when revisions are made -U
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_NPC_END; ++trade_slot) {
|
||||
const ItemInst* trade_inst = m_inv[trade_slot];
|
||||
|
||||
if(trade_inst) {
|
||||
strcpy(qsaudit->items[qsaudit->char_count].action_type, "HANDIN");
|
||||
QSHandinItems_Struct* detail = new QSHandinItems_Struct;
|
||||
|
||||
qsaudit->items[qsaudit->char_count].char_slot = slot_id;
|
||||
qsaudit->items[qsaudit->char_count].item_id = trade_inst->GetID();
|
||||
qsaudit->items[qsaudit->char_count].charges = trade_inst->GetCharges();
|
||||
qsaudit->items[qsaudit->char_count].aug_1 = trade_inst->GetAugmentItemID(1);
|
||||
qsaudit->items[qsaudit->char_count].aug_2 = trade_inst->GetAugmentItemID(2);
|
||||
qsaudit->items[qsaudit->char_count].aug_3 = trade_inst->GetAugmentItemID(3);
|
||||
qsaudit->items[qsaudit->char_count].aug_4 = trade_inst->GetAugmentItemID(4);
|
||||
qsaudit->items[qsaudit->char_count++].aug_5 = trade_inst->GetAugmentItemID(5);
|
||||
strcpy(detail->action_type, "HANDIN");
|
||||
|
||||
detail->char_slot = trade_slot;
|
||||
detail->item_id = trade_inst->GetID();
|
||||
detail->charges = (!trade_inst->IsStackable() ? 1 : trade_inst->GetCharges());
|
||||
detail->aug_1 = trade_inst->GetAugmentItemID(1);
|
||||
detail->aug_2 = trade_inst->GetAugmentItemID(2);
|
||||
detail->aug_3 = trade_inst->GetAugmentItemID(3);
|
||||
detail->aug_4 = trade_inst->GetAugmentItemID(4);
|
||||
detail->aug_5 = trade_inst->GetAugmentItemID(5);
|
||||
|
||||
event_details->push_back(detail);
|
||||
qs_audit->char_count += detail->charges;
|
||||
|
||||
if(trade_inst->IsType(ItemClassContainer)) {
|
||||
for(uint8 bag_idx = SUB_BEGIN; bag_idx < trade_inst->GetItem()->BagSlots; bag_idx++) {
|
||||
const ItemInst* trade_baginst = trade_inst->GetItem(bag_idx);
|
||||
for (uint8 sub_slot = SUB_BEGIN; sub_slot < trade_inst->GetItem()->BagSlots; ++sub_slot) {
|
||||
const ItemInst* trade_baginst = trade_inst->GetItem(sub_slot);
|
||||
|
||||
if(trade_baginst) {
|
||||
strcpy(qsaudit->items[qsaudit->char_count].action_type, "HANDIN");
|
||||
detail = new QSHandinItems_Struct;
|
||||
|
||||
qsaudit->items[qsaudit->char_count].char_slot = Inventory::CalcSlotId(slot_id, bag_idx);
|
||||
qsaudit->items[qsaudit->char_count].item_id = trade_baginst->GetID();
|
||||
qsaudit->items[qsaudit->char_count].charges = trade_baginst->GetCharges();
|
||||
qsaudit->items[qsaudit->char_count].aug_1 = trade_baginst->GetAugmentItemID(1);
|
||||
qsaudit->items[qsaudit->char_count].aug_2 = trade_baginst->GetAugmentItemID(2);
|
||||
qsaudit->items[qsaudit->char_count].aug_3 = trade_baginst->GetAugmentItemID(3);
|
||||
qsaudit->items[qsaudit->char_count].aug_4 = trade_baginst->GetAugmentItemID(4);
|
||||
qsaudit->items[qsaudit->char_count++].aug_5 = trade_baginst->GetAugmentItemID(5);
|
||||
strcpy(detail->action_type, "HANDIN");
|
||||
|
||||
detail->char_slot = Inventory::CalcSlotId(trade_slot, sub_slot);
|
||||
detail->item_id = trade_baginst->GetID();
|
||||
detail->charges = (!trade_inst->IsStackable() ? 1 : trade_inst->GetCharges());
|
||||
detail->aug_1 = trade_baginst->GetAugmentItemID(1);
|
||||
detail->aug_2 = trade_baginst->GetAugmentItemID(2);
|
||||
detail->aug_3 = trade_baginst->GetAugmentItemID(3);
|
||||
detail->aug_4 = trade_baginst->GetAugmentItemID(4);
|
||||
detail->aug_5 = trade_baginst->GetAugmentItemID(5);
|
||||
|
||||
event_details->push_back(detail);
|
||||
qs_audit->char_count += detail->charges;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -623,6 +912,16 @@ void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer)
|
||||
if(UpdateTasksOnDeliver(items, Cash, tradingWith->GetNPCTypeID())) {
|
||||
if(!tradingWith->IsMoving())
|
||||
tradingWith->FaceTarget(this);
|
||||
|
||||
/* Set a timestamp in an entity variable for plugin check_handin.pl in return_items
|
||||
This will stopgap players from items being returned if global_npc.pl has a catch all return_items
|
||||
*/
|
||||
struct timeval read_time;
|
||||
char buffer[50];
|
||||
gettimeofday(&read_time, 0);
|
||||
sprintf(buffer, "%li.%li \n", read_time.tv_sec, read_time.tv_usec);
|
||||
this->SetEntityVariable("Stop_Return", buffer);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+30
-39
@@ -20,8 +20,8 @@
|
||||
#include "entity.h"
|
||||
#include "masterentity.h"
|
||||
#include "../common/spdat.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/string_util.h"
|
||||
|
||||
/*
|
||||
|
||||
@@ -262,45 +262,36 @@ Mob* EntityList::GetTrapTrigger(Trap* trap) {
|
||||
|
||||
//todo: rewrite this to not need direct access to trap members.
|
||||
bool ZoneDatabase::LoadTraps(const char* zonename, int16 version) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
// int char_num = 0;
|
||||
unsigned long* lengths;
|
||||
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id,x,y,z,effect,effectvalue,effectvalue2,skill,maxzdiff,radius,chance,message,respawn_time,respawn_var,level FROM traps WHERE zone='%s' AND version=%u", zonename, version), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
lengths = mysql_fetch_lengths(result);
|
||||
Trap* trap = new Trap();
|
||||
trap->trap_id = atoi(row[0]);
|
||||
trap->x = atof(row[1]);
|
||||
trap->y = atof(row[2]);
|
||||
trap->z = atof(row[3]);
|
||||
trap->effect = atoi(row[4]);
|
||||
trap->effectvalue = atoi(row[5]);
|
||||
trap->effectvalue2 = atoi(row[6]);
|
||||
trap->skill = atoi(row[7]);
|
||||
trap->maxzdiff = atof(row[8]);
|
||||
trap->radius = atof(row[9]);
|
||||
trap->chance = atoi(row[10]);
|
||||
trap->message = row[11];
|
||||
trap->respawn_time = atoi(row[12]);
|
||||
trap->respawn_var = atoi(row[13]);
|
||||
trap->level = atoi(row[14]);
|
||||
entity_list.AddTrap(trap);
|
||||
trap->CreateHiddenTrigger();
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadTraps query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, "
|
||||
"maxzdiff, radius, chance, message, respawn_time, respawn_var, level "
|
||||
"FROM traps WHERE zone='%s' AND version=%u", zonename, version);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadTraps query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
Trap* trap = new Trap();
|
||||
trap->trap_id = atoi(row[0]);
|
||||
trap->x = atof(row[1]);
|
||||
trap->y = atof(row[2]);
|
||||
trap->z = atof(row[3]);
|
||||
trap->effect = atoi(row[4]);
|
||||
trap->effectvalue = atoi(row[5]);
|
||||
trap->effectvalue2 = atoi(row[6]);
|
||||
trap->skill = atoi(row[7]);
|
||||
trap->maxzdiff = atof(row[8]);
|
||||
trap->radius = atof(row[9]);
|
||||
trap->chance = atoi(row[10]);
|
||||
trap->message = row[11];
|
||||
trap->respawn_time = atoi(row[12]);
|
||||
trap->respawn_var = atoi(row[13]);
|
||||
trap->level = atoi(row[14]);
|
||||
entity_list.AddTrap(trap);
|
||||
trap->CreateHiddenTrigger();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+43
-51
@@ -20,7 +20,7 @@
|
||||
#include "../common/features.h"
|
||||
#include "masterentity.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
@@ -378,68 +378,60 @@ void Client::SendGuildTributes() {
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadTributes() {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
TributeData t;
|
||||
memset(&t.tiers, 0, sizeof(t.tiers));
|
||||
t.tier_count = 0;
|
||||
TributeData tributeData;
|
||||
memset(&tributeData.tiers, 0, sizeof(tributeData.tiers));
|
||||
tributeData.tier_count = 0;
|
||||
|
||||
tribute_list.clear();
|
||||
|
||||
const char *query = "SELECT id,name,descr,unknown,isguild FROM tributes";
|
||||
if (RunQuery(query, strlen(query), errbuf, &result)) {
|
||||
int r;
|
||||
while ((row = mysql_fetch_row(result))) {
|
||||
r = 0;
|
||||
uint32 id = atoul(row[r++]);
|
||||
t.name = row[r++];
|
||||
t.description = row[r++];
|
||||
t.unknown = strtoul(row[r++], nullptr, 10);
|
||||
t.is_guild = atol(row[r++])==0?false:true;
|
||||
|
||||
tribute_list[id] = t;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadTributes first query '%s': %s", query, errbuf);
|
||||
const std::string query = "SELECT id, name, descr, unknown, isguild FROM tributes";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadTributes first query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
uint32 id = atoul(row[0]);
|
||||
tributeData.name = row[1];
|
||||
tributeData.description = row[2];
|
||||
tributeData.unknown = strtoul(row[3], nullptr, 10);
|
||||
tributeData.is_guild = atol(row[4]) == 0? false: true;
|
||||
|
||||
const char *query2 = "SELECT tribute_id,level,cost,item_id FROM tribute_levels ORDER BY tribute_id,level";
|
||||
if (RunQuery(query2, strlen(query2), errbuf, &result)) {
|
||||
int r;
|
||||
while ((row = mysql_fetch_row(result))) {
|
||||
r = 0;
|
||||
uint32 id = atoul(row[r++]);
|
||||
tribute_list[id] = tributeData;
|
||||
}
|
||||
|
||||
if(tribute_list.count(id) != 1) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadTributes: unknown tribute %lu in tribute_levels", (unsigned long)id);
|
||||
continue;
|
||||
}
|
||||
|
||||
TributeData &cur = tribute_list[id];
|
||||
|
||||
if(cur.tier_count >= MAX_TRIBUTE_TIERS) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadTributes: on tribute %lu: more tiers defined than permitted", (unsigned long)id);
|
||||
continue;
|
||||
}
|
||||
|
||||
TributeLevel_Struct &s = cur.tiers[cur.tier_count];
|
||||
|
||||
s.level = atoul(row[r++]);
|
||||
s.cost = atoul(row[r++]);
|
||||
s.tribute_item_id = atoul(row[r++]);
|
||||
cur.tier_count++;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadTributes level query '%s': %s", query, errbuf);
|
||||
const std::string query2 = "SELECT tribute_id, level, cost, item_id FROM tribute_levels ORDER BY tribute_id, level";
|
||||
results = QueryDatabase(query2);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadTributes level query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
uint32 id = atoul(row[0]);
|
||||
|
||||
if(tribute_list.count(id) != 1) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadTributes: unknown tribute %lu in tribute_levels", (unsigned long)id);
|
||||
continue;
|
||||
}
|
||||
|
||||
TributeData &cur = tribute_list[id];
|
||||
|
||||
if(cur.tier_count >= MAX_TRIBUTE_TIERS) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadTributes: on tribute %lu: more tiers defined than permitted", (unsigned long)id);
|
||||
continue;
|
||||
}
|
||||
|
||||
TributeLevel_Struct &s = cur.tiers[cur.tier_count];
|
||||
|
||||
s.level = atoul(row[1]);
|
||||
s.cost = atoul(row[2]);
|
||||
s.tribute_item_id = atoul(row[3]);
|
||||
cur.tier_count++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+288
-365
@@ -24,16 +24,16 @@
|
||||
#include <math.h>
|
||||
#include "npc.h"
|
||||
#include "masterentity.h"
|
||||
#include "NpcAI.h"
|
||||
#include "npc_ai.h"
|
||||
#include "map.h"
|
||||
#include "water_map.h"
|
||||
#include "../common/moremath.h"
|
||||
#include "StringIDs.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/features.h"
|
||||
#include "QuestParserCollection.h"
|
||||
#include "quest_parser_collection.h"
|
||||
|
||||
struct wp_distance
|
||||
{
|
||||
@@ -869,97 +869,78 @@ void NPC::AssignWaypoints(int32 grid) {
|
||||
return;
|
||||
}
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
bool GridErr = false, WPErr = false;
|
||||
Waypoints.clear();
|
||||
roamer = false;
|
||||
|
||||
// Retrieve the wander and pause types for this grid
|
||||
if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `type`,`type2` FROM `grid` WHERE `id`=%i AND `zoneid`=%i",grid,zone->GetZoneID()),errbuf, &result))
|
||||
{
|
||||
if((row = mysql_fetch_row(result)))
|
||||
{
|
||||
if(row[0] != 0)
|
||||
wandertype = atoi(row[0]);
|
||||
else
|
||||
wandertype = 0;
|
||||
if(row[1] != 0)
|
||||
pausetype = atoi(row[1]);
|
||||
else
|
||||
pausetype = 0;
|
||||
}
|
||||
else // No grid record found in this zone for the given ID
|
||||
GridErr = true;
|
||||
mysql_free_result(result);
|
||||
std::string query = StringFormat("SELECT `type`, `type2` FROM `grid` WHERE `id` = %i AND `zoneid` = %i", grid, zone->GetZoneID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "MySQL Error while trying to assign grid %u to mob %s: %s", grid, name, results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
else // DB query error!
|
||||
{
|
||||
GridErr = true;
|
||||
LogFile->write(EQEMuLog::Error, "MySQL Error while trying to assign grid %u to mob %s: %s", grid, name, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
if(!GridErr)
|
||||
{
|
||||
this->CastToNPC()->SetGrid(grid); // Assign grid number
|
||||
if (results.RowCount() == 0)
|
||||
return;
|
||||
|
||||
// Retrieve all waypoints for this grid
|
||||
if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `x`,`y`,`z`,`pause`,`heading` FROM grid_entries WHERE `gridid`=%i AND `zoneid`=%i ORDER BY `number`",grid,zone->GetZoneID()),errbuf,&result))
|
||||
{
|
||||
roamer = true;
|
||||
max_wp = -1; // Initialize it; will increment it for each waypoint successfully added to the list
|
||||
auto row = results.begin();
|
||||
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
if(row[0] != 0 && row[1] != 0 && row[2] != 0 && row[3] != 0)
|
||||
{
|
||||
wplist newwp;
|
||||
newwp.index = ++max_wp;
|
||||
newwp.x = atof(row[0]);
|
||||
newwp.y = atof(row[1]);
|
||||
newwp.z = atof(row[2]);
|
||||
wandertype = atoi(row[0]);
|
||||
pausetype = atoi(row[1]);
|
||||
|
||||
if(zone->HasMap() && RuleB(Map, FixPathingZWhenLoading) )
|
||||
{
|
||||
if(!RuleB(Watermap, CheckWaypointsInWaterWhenLoading) || !zone->HasWaterMap() ||
|
||||
(zone->HasWaterMap() && !zone->watermap->InWater(newwp.x, newwp.y, newwp.z)))
|
||||
{
|
||||
Map::Vertex dest(newwp.x, newwp.y, newwp.z);
|
||||
|
||||
float newz = zone->zonemap->FindBestZ(dest, nullptr);
|
||||
this->CastToNPC()->SetGrid(grid); // Assign grid number
|
||||
|
||||
if( (newz > -2000) && ABS(newz-dest.z) < RuleR(Map, FixPathingZMaxDeltaLoading))
|
||||
newwp.z = newz + 1;
|
||||
}
|
||||
}
|
||||
// Retrieve all waypoints for this grid
|
||||
query = StringFormat("SELECT `x`,`y`,`z`,`pause`,`heading` "
|
||||
"FROM grid_entries WHERE `gridid` = %i AND `zoneid` = %i "
|
||||
"ORDER BY `number`", grid, zone->GetZoneID());
|
||||
results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "MySQL Error while trying to assign waypoints from grid %u to mob %s: %s", grid, name, results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
roamer = true;
|
||||
max_wp = 0; // Initialize it; will increment it for each waypoint successfully added to the list
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row, ++max_wp)
|
||||
{
|
||||
wplist newwp;
|
||||
newwp.index = max_wp;
|
||||
newwp.x = atof(row[0]);
|
||||
newwp.y = atof(row[1]);
|
||||
newwp.z = atof(row[2]);
|
||||
|
||||
if(zone->HasMap() && RuleB(Map, FixPathingZWhenLoading) )
|
||||
{
|
||||
if(!RuleB(Watermap, CheckWaypointsInWaterWhenLoading) || !zone->HasWaterMap() ||
|
||||
(zone->HasWaterMap() && !zone->watermap->InWater(newwp.x, newwp.y, newwp.z)))
|
||||
{
|
||||
Map::Vertex dest(newwp.x, newwp.y, newwp.z);
|
||||
|
||||
float newz = zone->zonemap->FindBestZ(dest, nullptr);
|
||||
|
||||
if( (newz > -2000) && ABS(newz-dest.z) < RuleR(Map, FixPathingZMaxDeltaLoading))
|
||||
newwp.z = newz + 1;
|
||||
}
|
||||
}
|
||||
|
||||
newwp.pause = atoi(row[3]);
|
||||
newwp.heading = atof(row[4]);
|
||||
Waypoints.push_back(newwp);
|
||||
}
|
||||
|
||||
newwp.pause = atoi(row[3]);
|
||||
newwp.heading = atof(row[4]);
|
||||
Waypoints.push_back(newwp);
|
||||
}
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else // DB query error!
|
||||
{
|
||||
WPErr = true;
|
||||
LogFile->write(EQEMuLog::Error, "MySQL Error while trying to assign waypoints from grid %u to mob %s: %s", grid, name, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
} // end if (!GridErr)
|
||||
if(Waypoints.size() < 2) {
|
||||
roamer = false;
|
||||
} else if(!GridErr && !WPErr) {
|
||||
UpdateWaypoint(0);
|
||||
SetWaypointPause();
|
||||
if (wandertype == 1 || wandertype == 2 || wandertype == 5)
|
||||
CalculateNewWaypoint();
|
||||
} else {
|
||||
roamer = false;
|
||||
}
|
||||
|
||||
UpdateWaypoint(0);
|
||||
SetWaypointPause();
|
||||
|
||||
if (wandertype == 1 || wandertype == 2 || wandertype == 5)
|
||||
CalculateNewWaypoint();
|
||||
|
||||
}
|
||||
|
||||
void Mob::SendTo(float new_x, float new_y, float new_z) {
|
||||
@@ -1049,159 +1030,123 @@ int ZoneDatabase::GetHighestGrid(uint32 zoneid) {
|
||||
}
|
||||
|
||||
uint8 ZoneDatabase::GetGridType2(uint32 grid, uint16 zoneid) {
|
||||
char *query = 0;
|
||||
char errbuff[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int type2 = 0;
|
||||
if (RunQuery(query, MakeAnyLenString(&query,"SELECT type2 from grid where id = %i and zoneid = %i",grid,zoneid),errbuff,&result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
type2 = atoi( row[0] );
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetGridType2 query '%s': %s", query, errbuff);
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
return(type2);
|
||||
int type2 = 0;
|
||||
std::string query = StringFormat("SELECT type2 FROM grid WHERE id = %i AND zoneid = %i", grid, zoneid);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetGridType2 query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
bool ZoneDatabase::GetWaypoints(uint32 grid, uint16 zoneid, uint32 num, wplist* wp) {
|
||||
char *query = 0;
|
||||
char errbuff[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
if (RunQuery(query, MakeAnyLenString(&query,"SELECT x, y, z, pause, heading from grid_entries where gridid = %i and number = %i and zoneid = %i",grid,num,zoneid),errbuff,&result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
if ( wp ) {
|
||||
wp->x = atof( row[0] );
|
||||
wp->y = atof( row[1] );
|
||||
wp->z = atof( row[2] );
|
||||
wp->pause = atoi( row[3] );
|
||||
wp->heading = atof( row[4] );
|
||||
}
|
||||
mysql_free_result(result);
|
||||
return true;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetWaypoints query '%s': %s", query, errbuff);
|
||||
safe_delete_array(query);
|
||||
}
|
||||
return false;
|
||||
|
||||
if (wp == nullptr)
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat("SELECT x, y, z, pause, heading FROM grid_entries "
|
||||
"WHERE gridid = %i AND number = %i AND zoneid = %i", grid, num, zoneid);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetWaypoints query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return false;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
wp->x = atof(row[0]);
|
||||
wp->y = atof(row[1]);
|
||||
wp->z = atof(row[2]);
|
||||
wp->pause = atoi(row[3]);
|
||||
wp->heading = atof(row[4]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZoneDatabase::AssignGrid(Client *client, float x, float y, uint32 grid)
|
||||
{
|
||||
char *query = 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int matches = 0, fuzzy = 0, spawn2id = 0;
|
||||
uint32 affected_rows;
|
||||
float dbx = 0, dby = 0;
|
||||
|
||||
// looks like most of the stuff in spawn2 is straight integers
|
||||
// so let's try that first
|
||||
if(!RunQuery(
|
||||
query,
|
||||
MakeAnyLenString(
|
||||
&query,
|
||||
"SELECT id,x,y FROM spawn2 WHERE zone='%s' AND x=%i AND y=%i",
|
||||
zone->GetShortName(), (int)x, (int)y
|
||||
),
|
||||
errbuf,
|
||||
&result
|
||||
)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error querying spawn2 '%s': '%s'", query, errbuf);
|
||||
return;
|
||||
std::string query = StringFormat("SELECT id, x, y FROM spawn2 WHERE zone = '%s' AND x = %i AND y = %i",
|
||||
zone->GetShortName(), (int)x, (int)y);
|
||||
auto results = QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error querying spawn2 '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
// how much it's allowed to be off by
|
||||
#define _GASSIGN_TOLERANCE 1.0
|
||||
if(!(matches = mysql_num_rows(result))) // try a fuzzy match if that didn't find it
|
||||
if(results.RowCount() == 0) // try a fuzzy match if that didn't find it
|
||||
{
|
||||
mysql_free_result(result);
|
||||
if(!RunQuery(
|
||||
query,
|
||||
MakeAnyLenString(
|
||||
&query,
|
||||
"SELECT id,x,y FROM spawn2 WHERE zone='%s' AND "
|
||||
"ABS( ABS(x) - ABS(%f) ) < %f AND "
|
||||
"ABS( ABS(y) - ABS(%f) ) < %f",
|
||||
zone->GetShortName(), x, _GASSIGN_TOLERANCE, y, _GASSIGN_TOLERANCE
|
||||
),
|
||||
errbuf,
|
||||
&result
|
||||
)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error querying fuzzy spawn2 '%s': '%s'", query, errbuf);
|
||||
query = StringFormat("SELECT id,x,y FROM spawn2 WHERE zone='%s' AND "
|
||||
"ABS( ABS(x) - ABS(%f) ) < %f AND "
|
||||
"ABS( ABS(y) - ABS(%f) ) < %f",
|
||||
zone->GetShortName(), x, _GASSIGN_TOLERANCE, y, _GASSIGN_TOLERANCE);
|
||||
results = QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error querying fuzzy spawn2 '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
fuzzy = 1;
|
||||
if(!(matches = mysql_num_rows(result)))
|
||||
mysql_free_result(result);
|
||||
matches = results.RowCount();
|
||||
}
|
||||
if(matches)
|
||||
|
||||
if (matches == 0) {
|
||||
client->Message(0, "ERROR: Unable to assign grid - can't find it in spawn2");
|
||||
return;
|
||||
}
|
||||
|
||||
if(matches == 1)
|
||||
{
|
||||
if(matches > 1)
|
||||
{
|
||||
client->Message(0, "ERROR: Unable to assign grid - multiple spawn2 rows match");
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
row = mysql_fetch_row(result);
|
||||
spawn2id = atoi(row[0]);
|
||||
dbx = atof(row[1]);
|
||||
dby = atof(row[2]);
|
||||
if(!RunQuery(
|
||||
query,
|
||||
MakeAnyLenString(
|
||||
&query,
|
||||
"UPDATE spawn2 SET pathgrid = %d WHERE id = %d", grid, spawn2id
|
||||
),
|
||||
errbuf,
|
||||
&result,
|
||||
&affected_rows
|
||||
)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error updating spawn2 '%s': '%s'", query, errbuf);
|
||||
return;
|
||||
}
|
||||
if(affected_rows == 1)
|
||||
{
|
||||
if(client) client->LogSQL(query);
|
||||
if(fuzzy)
|
||||
{
|
||||
float difference;
|
||||
difference = sqrtf(pow(fabs(x-dbx),2) + pow(fabs(y-dby),2));
|
||||
client->Message(0,
|
||||
"Grid assign: spawn2 id = %d updated - fuzzy match: deviation %f",
|
||||
spawn2id, difference
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
client->Message(0, "Grid assign: spawn2 id = %d updated - exact match", spawn2id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
client->Message(0, "ERROR: found spawn2 id %d but the update query failed", spawn2id);
|
||||
}
|
||||
}
|
||||
client->Message(0, "ERROR: Unable to assign grid - multiple spawn2 rows match");
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
spawn2id = atoi(row[0]);
|
||||
dbx = atof(row[1]);
|
||||
dby = atof(row[2]);
|
||||
|
||||
query = StringFormat("UPDATE spawn2 SET pathgrid = %d WHERE id = %d", grid, spawn2id);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
{
|
||||
client->Message(0, "ERROR: Unable to assign grid - can't find it in spawn2");
|
||||
}
|
||||
LogFile->write(EQEMuLog::Error, "Error updating spawn2 '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (results.RowsAffected() != 1) {
|
||||
client->Message(0, "ERROR: found spawn2 id %d but the update query failed", spawn2id);
|
||||
return;
|
||||
}
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
if(!fuzzy) {
|
||||
client->Message(0, "Grid assign: spawn2 id = %d updated - exact match", spawn2id);
|
||||
return;
|
||||
}
|
||||
|
||||
float difference = sqrtf(pow(fabs(x - dbx) , 2) + pow(fabs(y - dby), 2));
|
||||
client->Message(0, "Grid assign: spawn2 id = %d updated - fuzzy match: deviation %f", spawn2id, difference);
|
||||
}
|
||||
|
||||
/******************
|
||||
@@ -1211,53 +1156,57 @@ void ZoneDatabase::AssignGrid(Client *client, float x, float y, uint32 grid)
|
||||
* type,type2: The type and type2 values for the grid being created (ignored if grid is being deleted)
|
||||
* zoneid: The ID number of the zone the grid is being created/deleted in
|
||||
*/
|
||||
void ZoneDatabase::ModifyGrid(Client *client, bool remove, uint32 id, uint8 type, uint8 type2, uint16 zoneid) {
|
||||
|
||||
void ZoneDatabase::ModifyGrid(Client *c, bool remove, uint32 id, uint8 type, uint8 type2, uint16 zoneid) {
|
||||
char *query = 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
if (!remove)
|
||||
{
|
||||
if(!RunQuery(query, MakeAnyLenString(&query,"INSERT INTO grid(id,zoneid,type,type2) VALUES(%i,%i,%i,%i)",id,zoneid,type,type2), errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error creating grid entry '%s': '%s'", query, errbuf);
|
||||
} else {
|
||||
if(c) c->LogSQL(query);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("INSERT INTO grid(id, zoneid, type, type2) "
|
||||
"VALUES (%i, %i, %i, %i)", id, zoneid, type, type2);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error creating grid entry '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!RunQuery(query, MakeAnyLenString(&query,"DELETE FROM grid where id=%i",id), errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error deleting grid '%s': '%s'", query, errbuf);
|
||||
} else {
|
||||
if(c) c->LogSQL(query);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
query = 0;
|
||||
if(!RunQuery(query, MakeAnyLenString(&query,"DELETE FROM grid_entries WHERE zoneid=%i AND gridid=%i",zoneid,id), errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error deleting grid entries '%s': '%s'", query, errbuf);
|
||||
} else {
|
||||
if(c) c->LogSQL(query);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
}
|
||||
} /*** END ZoneDatabase::ModifyGrid() ***/
|
||||
|
||||
std::string query = StringFormat("DELETE FROM grid where id=%i", id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error deleting grid '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
else if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
query = StringFormat("DELETE FROM grid_entries WHERE zoneid = %i AND gridid = %i", zoneid, id);
|
||||
results = QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error deleting grid entries '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
else if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* AddWP - Adds a new waypoint to a specific grid for a specific zone.
|
||||
*/
|
||||
|
||||
void ZoneDatabase::AddWP(Client *c, uint32 gridid, uint32 wpnum, float xpos, float ypos, float zpos, uint32 pause, uint16 zoneid, float heading)
|
||||
void ZoneDatabase::AddWP(Client *client, uint32 gridid, uint32 wpnum, float xpos, float ypos, float zpos, uint32 pause, uint16 zoneid, float heading)
|
||||
{
|
||||
char *query = 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
if(!RunQuery(query,MakeAnyLenString(&query,"INSERT INTO grid_entries (gridid,zoneid,`number`,x,y,z,pause,heading) values (%i,%i,%i,%f,%f,%f,%i,%f)",gridid,zoneid,wpnum,xpos,ypos,zpos,pause,heading), errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error adding waypoint '%s': '%s'", query, errbuf);
|
||||
} else {
|
||||
if(c) c->LogSQL(query);
|
||||
std::string query = StringFormat("INSERT INTO grid_entries (gridid, zoneid, `number`, x, y, z, pause, heading) "
|
||||
"VALUES (%i, %i, %i, %f, %f, %f, %i, %f)",
|
||||
gridid, zoneid, wpnum, xpos, ypos, zpos, pause, heading);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error adding waypoint '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
} /*** END ZoneDatabase::AddWP() ***/
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
}
|
||||
|
||||
|
||||
/**********
|
||||
@@ -1270,19 +1219,20 @@ void ZoneDatabase::AddWP(Client *c, uint32 gridid, uint32 wpnum, float xpos, flo
|
||||
* wp_num: The number of the waypoint being deleted
|
||||
* zoneid: The ID number of the zone that contains the waypoint being deleted
|
||||
*/
|
||||
|
||||
void ZoneDatabase::DeleteWaypoint(Client *c, uint32 grid_num, uint32 wp_num, uint16 zoneid)
|
||||
void ZoneDatabase::DeleteWaypoint(Client *client, uint32 grid_num, uint32 wp_num, uint16 zoneid)
|
||||
{
|
||||
char *query=0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
if(!RunQuery(query, MakeAnyLenString(&query,"DELETE FROM grid_entries where gridid=%i and zoneid=%i and `number`=%i",grid_num,zoneid,wp_num), errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error deleting waypoint '%s': '%s'", query, errbuf);
|
||||
} else {
|
||||
if(c) c->LogSQL(query);
|
||||
std::string query = StringFormat("DELETE FROM grid_entries WHERE "
|
||||
"gridid = %i AND zoneid = %i AND `number` = %i",
|
||||
grid_num, zoneid, wp_num);
|
||||
auto results = QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error deleting waypoint '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
} /*** END ZoneDatabase::DeleteWaypoint() ***/
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
}
|
||||
|
||||
|
||||
/******************
|
||||
@@ -1292,139 +1242,112 @@ void ZoneDatabase::DeleteWaypoint(Client *c, uint32 grid_num, uint32 wp_num, uin
|
||||
* Returns 0 if the function didn't have to create a new grid. If the function had to create a new grid for the spawn, then the ID of
|
||||
* the created grid is returned.
|
||||
*/
|
||||
uint32 ZoneDatabase::AddWPForSpawn(Client *client, uint32 spawn2id, float xpos, float ypos, float zpos, uint32 pause, int type1, int type2, uint16 zoneid, float heading) {
|
||||
|
||||
uint32 ZoneDatabase::AddWPForSpawn(Client *c, uint32 spawn2id, float xpos, float ypos, float zpos, uint32 pause, int type1, int type2, uint16 zoneid, float heading) {
|
||||
char *query = 0;
|
||||
uint32 grid_num, // The grid number the spawn is assigned to (if spawn has no grid, will be the grid number we end up creating)
|
||||
next_wp_num; // The waypoint number we should be assigning to the new waypoint
|
||||
bool CreatedNewGrid; // Did we create a new grid in this function?
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
uint32 grid_num; // The grid number the spawn is assigned to (if spawn has no grid, will be the grid number we end up creating)
|
||||
uint32 next_wp_num; // The waypoint number we should be assigning to the new waypoint
|
||||
bool createdNewGrid; // Did we create a new grid in this function?
|
||||
|
||||
// See what grid number our spawn is assigned
|
||||
if(RunQuery(query, MakeAnyLenString(&query,"SELECT pathgrid FROM spawn2 WHERE id=%i",spawn2id),errbuf,&result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
if(mysql_num_rows(result) > 0)
|
||||
{
|
||||
row = mysql_fetch_row(result);
|
||||
grid_num = atoi(row[0]);
|
||||
}
|
||||
else // This spawn ID was not found in the `spawn2` table
|
||||
return 0;
|
||||
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else { // Query error
|
||||
LogFile->write(EQEMuLog::Error, "Error setting pathgrid '%s': '%s'", query, errbuf);
|
||||
std::string query = StringFormat("SELECT pathgrid FROM spawn2 WHERE id = %i", spawn2id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
// Query error
|
||||
LogFile->write(EQEMuLog::Error, "Error setting pathgrid '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (grid_num == 0) // Our spawn doesn't have a grid assigned to it -- we need to create a new grid and assign it to the spawn
|
||||
{
|
||||
CreatedNewGrid = true;
|
||||
if((grid_num = GetFreeGrid(zoneid)) == 0) // There are no grids for the current zone -- create Grid #1
|
||||
grid_num = 1;
|
||||
if (results.RowCount() == 0)
|
||||
return 0;
|
||||
|
||||
if(!RunQuery(query, MakeAnyLenString(&query,"insert into grid set id='%i',zoneid= %i, type='%i', type2='%i'",grid_num,zoneid,type1,type2), errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error adding grid '%s': '%s'", query, errbuf);
|
||||
} else {
|
||||
if(c) c->LogSQL(query);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
auto row = results.begin();
|
||||
grid_num = atoi(row[0]);
|
||||
|
||||
query = 0;
|
||||
if(!RunQuery(query, MakeAnyLenString(&query,"update spawn2 set pathgrid='%i' where id='%i'",grid_num,spawn2id), errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error updating spawn2 pathing '%s': '%s'", query, errbuf);
|
||||
} else {
|
||||
if(c) c->LogSQL(query);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
if (grid_num == 0)
|
||||
{ // Our spawn doesn't have a grid assigned to it -- we need to create a new grid and assign it to the spawn
|
||||
createdNewGrid = true;
|
||||
grid_num = GetFreeGrid(zoneid);
|
||||
if(grid_num == 0) // There are no grids for the current zone -- create Grid #1
|
||||
grid_num = 1;
|
||||
|
||||
query = StringFormat("INSERT INTO grid SET id = '%i', zoneid = %i, type ='%i', type2 = '%i'",
|
||||
grid_num, zoneid, type1, type2);
|
||||
results = QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error adding grid '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
else if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
query = StringFormat("UPDATE spawn2 SET pathgrid = '%i' WHERE id = '%i'", grid_num, spawn2id);
|
||||
results = QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error updating spawn2 pathing '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
else if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
}
|
||||
else // NPC had a grid assigned to it
|
||||
CreatedNewGrid = false;
|
||||
|
||||
createdNewGrid = false;
|
||||
|
||||
// Find out what the next waypoint is for this grid
|
||||
query = 0;
|
||||
if(RunQuery(query, MakeAnyLenString(&query,"SELECT max(`number`) FROM grid_entries WHERE zoneid='%i' AND gridid='%i'",zoneid,grid_num),errbuf,&result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
row = mysql_fetch_row(result);
|
||||
if(row[0] != 0)
|
||||
next_wp_num = atoi(row[0]) + 1;
|
||||
else // No waypoints in this grid yet
|
||||
next_wp_num = 1;
|
||||
query = StringFormat("SELECT max(`number`) FROM grid_entries WHERE zoneid = '%i' AND gridid = '%i'", zoneid, grid_num);
|
||||
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else { // Query error
|
||||
LogFile->write(EQEMuLog::Error, "Error getting next waypoint id '%s': '%s'", query, errbuf);
|
||||
if(!results.Success()) { // Query error
|
||||
LogFile->write(EQEMuLog::Error, "Error getting next waypoint id '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
query = 0;
|
||||
if(!RunQuery(query, MakeAnyLenString(&query,"INSERT INTO grid_entries(gridid,zoneid,`number`,x,y,z,pause,heading) VALUES (%i,%i,%i,%f,%f,%f,%i,%f)",grid_num,zoneid,next_wp_num,xpos,ypos,zpos,pause,heading), errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error adding grid entry '%s': '%s'", query, errbuf);
|
||||
} else {
|
||||
if(c) c->LogSQL(query);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
row = results.begin();
|
||||
if(row[0] != 0)
|
||||
next_wp_num = atoi(row[0]) + 1;
|
||||
else // No waypoints in this grid yet
|
||||
next_wp_num = 1;
|
||||
|
||||
if(CreatedNewGrid)
|
||||
return grid_num;
|
||||
|
||||
return 0;
|
||||
} /*** END ZoneDatabase::AddWPForSpawn() ***/
|
||||
query = StringFormat("INSERT INTO grid_entries(gridid, zoneid, `number`, x, y, z, pause, heading) "
|
||||
"VALUES (%i, %i, %i, %f, %f, %f, %i, %f)",
|
||||
grid_num, zoneid, next_wp_num, xpos, ypos, zpos, pause, heading);
|
||||
results = QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error adding grid entry '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
else if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
return createdNewGrid? grid_num: 0;
|
||||
}
|
||||
|
||||
uint32 ZoneDatabase::GetFreeGrid(uint16 zoneid) {
|
||||
char *query = 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
if (RunQuery(query, MakeAnyLenString(&query,"SELECT max(id) from grid where zoneid = %i",zoneid),errbuf,&result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
uint32 tmp=0;
|
||||
if (row[0])
|
||||
tmp = atoi(row[0]);
|
||||
mysql_free_result(result);
|
||||
tmp++;
|
||||
return tmp;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
|
||||
std::string query = StringFormat("SELECT max(id) FROM grid WHERE zoneid = %i", zoneid);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetFreeGrid query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetFreeGrid query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
}
|
||||
return 0;
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
uint32 freeGridID = 1;
|
||||
freeGridID = atoi(row[0]) + 1;
|
||||
|
||||
return freeGridID;
|
||||
}
|
||||
|
||||
int ZoneDatabase::GetHighestWaypoint(uint32 zoneid, uint32 gridid) {
|
||||
char *query = 0;
|
||||
char errbuff[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int res = 0;
|
||||
if (RunQuery(query, MakeAnyLenString(&query,
|
||||
"SELECT COALESCE(MAX(number), 0) FROM grid_entries WHERE zoneid = %i AND gridid = %i",
|
||||
zoneid, gridid),errbuff,&result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
res = atoi( row[0] );
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetHighestWaypoint query '%s': %s", query, errbuff);
|
||||
safe_delete_array(query);
|
||||
|
||||
std::string query = StringFormat("SELECT COALESCE(MAX(number), 0) FROM grid_entries "
|
||||
"WHERE zoneid = %i AND gridid = %i", zoneid, gridid);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetHighestWaypoint query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return(res);
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
void NPC::SaveGuardSpotCharm()
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include "worldserver.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "zonedb.h"
|
||||
#include "zone.h"
|
||||
#include "entity.h"
|
||||
@@ -45,12 +45,12 @@
|
||||
#include "petitions.h"
|
||||
#include "../common/packet_functions.h"
|
||||
#include "../common/md5.h"
|
||||
#include "ZoneConfig.h"
|
||||
#include "StringIDs.h"
|
||||
#include "zone_config.h"
|
||||
#include "string_ids.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "titles.h"
|
||||
#include "QGlobals.h"
|
||||
#include "qglobals.h"
|
||||
|
||||
|
||||
extern EntityList entity_list;
|
||||
|
||||
+446
-550
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -18,7 +18,7 @@
|
||||
#ifndef ZONE_H
|
||||
#define ZONE_H
|
||||
|
||||
#include "../common/Mutex.h"
|
||||
#include "../common/mutex.h"
|
||||
#include "../common/linked_list.h"
|
||||
#include "../common/types.h"
|
||||
#include "../common/eqtime.h"
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "spawn2.h"
|
||||
#include "tasks.h"
|
||||
#include "pathing.h"
|
||||
#include "QGlobals.h"
|
||||
#include "qglobals.h"
|
||||
#include <unordered_map>
|
||||
|
||||
class Map;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "../common/debug.h"
|
||||
#include "ZoneConfig.h"
|
||||
#include "zone_config.h"
|
||||
|
||||
ZoneConfig *ZoneConfig::_zone_config = nullptr;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#ifndef __ZoneConfig_H
|
||||
#define __ZoneConfig_H
|
||||
|
||||
#include "../common/EQEmuConfig.h"
|
||||
#include "../common/eqemu_config.h"
|
||||
|
||||
class ZoneConfig : public EQEmuConfig {
|
||||
public:
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
#include "../common/debug.h"
|
||||
#include "../common/logsys.h"
|
||||
#include "../common/BasePacket.h"
|
||||
#include "../common/base_packet.h"
|
||||
#include "mob.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
+10
-2
@@ -1,7 +1,7 @@
|
||||
|
||||
#include "zonedb.h"
|
||||
#include "../common/Item.h"
|
||||
#include "../common/StringUtil.h"
|
||||
#include "../common/item.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/extprofile.h"
|
||||
#include "../common/guilds.h"
|
||||
#include "../common/rulesys.h"
|
||||
@@ -2526,3 +2526,11 @@ bool ZoneDatabase::GetFactionIdsForNPC(uint32 nfl_id, std::list<struct NPCFactio
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZoneDatabase::StoreCharacterLookup(uint32 char_id) {
|
||||
std::string c_lookup = StringFormat("REPLACE INTO `character_lookup` (id, account_id, `name`, timelaston, x, y, z, zonename, zoneid, instanceid, pktime, groupid, class, `level`, lfp, lfg, mailkey, xtargets, firstlogon, inspectmessage)"
|
||||
" SELECT id, account_id, `name`, timelaston, x, y, z, zonename, zoneid, instanceid, pktime, groupid, class, `level`, lfp, lfg, mailkey, xtargets, firstlogon, inspectmessage"
|
||||
" FROM `character_` "
|
||||
" WHERE `id` = %i ", char_id);
|
||||
QueryDatabase(c_lookup);
|
||||
}
|
||||
|
||||
@@ -246,6 +246,7 @@ public:
|
||||
/*
|
||||
* General Character Related Stuff
|
||||
*/
|
||||
void StoreCharacterLookup(uint32 char_id);
|
||||
bool GetAccountInfoForLogin_result(MySQLRequestResult results, int16* admin = 0, char* account_name = 0,
|
||||
uint32* lsaccountid = 0, uint8* gmspeed = 0, bool* revoked = 0, bool* gmhideme = nullptr,
|
||||
uint32* account_creation = 0);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user