Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Paul Coene 2016-01-02 09:17:09 -05:00
commit a56f17a9e5
56 changed files with 2274 additions and 766 deletions

View File

@ -1,5 +1,59 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50) EQEMu Changelog (Started on Sept 24, 2003 15:50)
------------------------------------------------------- -------------------------------------------------------
== 12/29/2015 ==
Akkadius: Implemented standardized zone controller scripts (Rule Zone, UseZoneController) Defaulted to true
- When a zone boots, it will spawn an invisible npc by the name of zone_controller
- Lua and Perl scripts can be represented with this npc as zone_controller.pl/lua
- This NPC's ID is ruled be define ZONE_CONTROLLER_NPC_ID 10
- Two EVENT's uniquely are handled with this NPC/controller (They only work with the zone_controller NPC)
- EVENT_SPAWN_ZONE :: All NPC spawns in the zone trigger the controller and pass the following variables:
$spawned_entity_id
$spawned_npc_id
- EVENT_DEATH_ZONE :: All NPC deaths in the zone trigger the controller event and pass the following variables:
$killer_id
$killer_damage
$killer_spell
$killer_skill
$killed_npc_id
== 12/28/2015 ==
Kinglykrab: Added GetInstanceTimer() to Perl and Lua.
- Added GetInstanceTimerByID(instance_id) to Perl and Lua.
- Note: If you do not provide an instance id in the method it defaults to instance id 0 and returns 0 for time remaining.
- Added UpdateZoneHeader(type, value) to Perl and Lua.
- Note: UpdateZoneHeader allows you to manipulate fog color, fog density, and many other zone header settings on the fly in Perl and Lua.
== 12/21/2015 ==
Natedog: Updated item table fields and added a few missing fields for evolving items
-DO NOT implement Heirloom items till the inventory code is fixed to allow placing NO DROP
items in your shared bank. (but item field located on items table)
-NYI - SkillModMax: Max skill point modification from the percent mods. EX:
100% 2HSlashing (Max 50) - can only increase 2hslash by 50 MAX! (item field located though)
Kinglykrab: Added GetMeleeMitigation() for NPCs and Clients in Perl and Lua.
- This allows you to check total item, spell, and AA melee mitigation contribution.
== 12/19/2015 ==
Kinglykrab: Added many methods to Perl and Lua, list below:
- SeeInvisible()
- SeeInvisibleUndead()
- SeeHide()
- SeeImprovedHide()
- GetNimbusEffect1() - returns first nimbus effect
- GetNimbusEffect2() - returns second nimbus effect
- GetNimbusEffect3() - returns third nimbus effect
- IsTargetable()
- HasShieldEquiped()
- HasTwoHandBluntEquiped()
- HasTwoHanderEquiped()
- GetHerosForgeModel() - returns int32 Hero's Forge model
- IsEliteMaterialItem() - returns uint32 Hero's Forge Model
- GetBaseSize() - returns Mob's base size
- HasOwner()
- IsPet()
- HasPet()
- IsSilenced()
- IsAmnesiad()
== 12/16/2015 == == 12/16/2015 ==
Noudess: Repaired issue with Bind Wounds on someone else. Message was not coming out on client (hold still) and a bind wounds on someone already binding their wounds would interrupt their bind and make them stand. Also removed some duplicate messaging. Noudess: Repaired issue with Bind Wounds on someone else. Message was not coming out on client (hold still) and a bind wounds on someone already binding their wounds would interrupt their bind and make them stand. Also removed some duplicate messaging.

View File

@ -24,20 +24,27 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "types.h" #include "types.h"
static const uint32 BIT_Client62 = 1; static const uint32 BIT_Client62 = 0x00000001; // 1 (unsupported - placeholder for scripts)
static const uint32 BIT_Titanium = 2;
static const uint32 BIT_SoF = 4; static const uint32 BIT_Titanium = 0x00000002; // 2
static const uint32 BIT_SoD = 8; static const uint32 BIT_SoF = 0x00000004; // 4
static const uint32 BIT_UF = 16; static const uint32 BIT_SoD = 0x00000008; // 8
static const uint32 BIT_RoF = 32; static const uint32 BIT_UF = 0x00000010; // 16
static const uint32 BIT_RoF2 = 64; static const uint32 BIT_RoF = 0x00000020; // 32
static const uint32 BIT_RoF2 = 0x00000040; // 64
static const uint32 BIT_TitaniumAndEarlier = 0x00000003; // 3
static const uint32 BIT_SoFAndEarlier = 0x00000007; // 7
static const uint32 BIT_SoDAndEarlier = 0x0000000F; // 15
static const uint32 BIT_UFAndEarlier = 0x0000001F; // 31
static const uint32 BIT_RoFAndEarlier = 0x0000003F; // 63
static const uint32 BIT_SoFAndLater = 0xFFFFFFFC; // 4294967292
static const uint32 BIT_SoDAndLater = 0xFFFFFFF8; // 4294967288
static const uint32 BIT_UFAndLater = 0xFFFFFFF0; // 4294967280
static const uint32 BIT_RoFAndLater = 0xFFFFFFE0; // 4294967264
static const uint32 BIT_RoF2AndLater = 0xFFFFFFC0; // 4294967232
static const uint32 BIT_TitaniumAndEarlier = 0x00000003;
static const uint32 BIT_SoFAndLater = 0xFFFFFFFC;
static const uint32 BIT_SoDAndLater = 0xFFFFFFF8;
static const uint32 BIT_UFAndLater = 0xFFFFFFF0;
static const uint32 BIT_RoFAndLater = 0xFFFFFFE0;
static const uint32 BIT_RoF2AndLater = 0xFFFFFFC0;
static const uint32 BIT_AllClients = 0xFFFFFFFF; static const uint32 BIT_AllClients = 0xFFFFFFFF;
enum class ClientVersion enum class ClientVersion

View File

@ -1183,21 +1183,16 @@ bool Database::CheckNameFilter(const char* name, bool surname)
{ {
std::string str_name = name; std::string str_name = name;
if(surname) // the minimum 4 is enforced by the client too
if (!name || strlen(name) < 4)
{ {
// the minimum 4 is enforced by the client too return false;
if(!name || strlen(name) < 3)
{
return false;
}
} }
else
// Given name length is enforced by the client too
if (!surname && strlen(name) > 15)
{ {
// the minimum 4 is enforced by the client too return false;
if(!name || strlen(name) < 4 || strlen(name) > 15)
{
return false;
}
} }
for (size_t i = 0; i < str_name.size(); i++) for (size_t i = 0; i < str_name.size(); i++)
@ -1564,7 +1559,7 @@ void Database::AddReport(std::string who, std::string against, std::string lines
char *escape_str = new char[lines.size()*2+1]; char *escape_str = new char[lines.size()*2+1];
DoEscapeString(escape_str, lines.c_str(), lines.size()); DoEscapeString(escape_str, lines.c_str(), lines.size());
std::string query = StringFormat("INSERT INTO reports (name, reported, reported_text) VALUES('%s', '%s', '%s')", who.c_str(), against.c_str(), escape_str); std::string query = StringFormat("INSERT INTO reports (name, reported, reported_text) VALUES('%s', '%s', '%s')", EscapeString(who).c_str(), EscapeString(against).c_str(), escape_str);
QueryDatabase(query); QueryDatabase(query);
safe_delete_array(escape_str); safe_delete_array(escape_str);
} }
@ -2182,3 +2177,42 @@ void Database::ClearInvSnapshots(bool use_rule)
std::string query = StringFormat("DELETE FROM inventory_snapshots WHERE time_index <= %lu", (unsigned long)del_time); std::string query = StringFormat("DELETE FROM inventory_snapshots WHERE time_index <= %lu", (unsigned long)del_time);
QueryDatabase(query); QueryDatabase(query);
} }
struct TimeOfDay_Struct Database::LoadTime(time_t &realtime)
{
TimeOfDay_Struct eqTime;
std::string query = StringFormat("SELECT minute,hour,day,month,year,realtime FROM eqtime limit 1");
auto results = QueryDatabase(query);
if (!results.Success() || results.RowCount() == 0)
{
Log.Out(Logs::Detail, Logs::World_Server, "Loading EQ time of day failed. Using defaults.");
eqTime.minute = 0;
eqTime.hour = 9;
eqTime.day = 1;
eqTime.month = 1;
eqTime.year = 3100;
realtime = time(0);
}
auto row = results.begin();
eqTime.minute = atoi(row[0]);
eqTime.hour = atoi(row[1]);
eqTime.day = atoi(row[2]);
eqTime.month = atoi(row[3]);
eqTime.year = atoi(row[4]);
realtime = atoi(row[5]);
return eqTime;
}
bool Database::SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year)
{
std::string query = StringFormat("UPDATE eqtime set minute = %d, hour = %d, day = %d, month = %d, year = %d, realtime = %d limit 1", minute, hour, day, month, year, time(0));
auto results = QueryDatabase(query);
return results.Success();
}

View File

@ -241,6 +241,8 @@ public:
uint8 GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16 in_level); uint8 GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16 in_level);
void AddReport(std::string who, std::string against, std::string lines); void AddReport(std::string who, std::string against, std::string lines);
struct TimeOfDay_Struct LoadTime(time_t &realtime);
bool SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year);
void ClearMerchantTemp(); void ClearMerchantTemp();
void ClearPTimers(uint32 charid); void ClearPTimers(uint32 charid);
void SetFirstLogon(uint32 CharID, uint8 firstlogon); void SetFirstLogon(uint32 CharID, uint8 firstlogon);

View File

@ -493,7 +493,7 @@ bool Database::CheckDatabaseConversions() {
/* Check for a new version of this script, the arg passed /* Check for a new version of this script, the arg passed
would have to be higher than the copy they have downloaded would have to be higher than the copy they have downloaded
locally and they will re fetch */ locally and they will re fetch */
system("perl eqemu_update.pl V 13"); system("perl eqemu_update.pl V 14");
/* Run Automatic Database Upgrade Script */ /* Run Automatic Database Upgrade Script */
system("perl eqemu_update.pl ran_from_world"); system("perl eqemu_update.pl ran_from_world");

View File

@ -254,10 +254,6 @@ void EQEmuConfig::do_files(TiXmlElement *ele)
if (text) { if (text) {
OpCodesFile = text; OpCodesFile = text;
} }
text = ParseTextBlock(ele, "eqtime", true);
if (text) {
EQTimeFile = text;
}
} }
void EQEmuConfig::do_directories(TiXmlElement *ele) void EQEmuConfig::do_directories(TiXmlElement *ele)
@ -408,9 +404,6 @@ std::string EQEmuConfig::GetByName(const std::string &var_name) const
if (var_name == "OpCodesFile") { if (var_name == "OpCodesFile") {
return (OpCodesFile); return (OpCodesFile);
} }
if (var_name == "EQTimeFile") {
return (EQTimeFile);
}
if (var_name == "MapDir") { if (var_name == "MapDir") {
return (MapDir); return (MapDir);
} }
@ -475,7 +468,6 @@ void EQEmuConfig::Dump() const
std::cout << "QSDatabasePort = " << QSDatabasePort << std::endl; std::cout << "QSDatabasePort = " << QSDatabasePort << std::endl;
std::cout << "SpellsFile = " << SpellsFile << std::endl; std::cout << "SpellsFile = " << SpellsFile << std::endl;
std::cout << "OpCodesFile = " << OpCodesFile << std::endl; std::cout << "OpCodesFile = " << OpCodesFile << std::endl;
std::cout << "EQTimeFile = " << EQTimeFile << std::endl;
std::cout << "MapDir = " << MapDir << std::endl; std::cout << "MapDir = " << MapDir << std::endl;
std::cout << "QuestDir = " << QuestDir << std::endl; std::cout << "QuestDir = " << QuestDir << std::endl;
std::cout << "PluginDir = " << PluginDir << std::endl; std::cout << "PluginDir = " << PluginDir << std::endl;

View File

@ -79,7 +79,6 @@ class EQEmuConfig : public XMLParser
// From <files/> // From <files/>
std::string SpellsFile; std::string SpellsFile;
std::string OpCodesFile; std::string OpCodesFile;
std::string EQTimeFile;
// From <directories/> // From <directories/>
std::string MapDir; std::string MapDir;
@ -154,7 +153,6 @@ class EQEmuConfig : public XMLParser
// Files // Files
SpellsFile = "spells_us.txt"; SpellsFile = "spells_us.txt";
OpCodesFile = "opcodes.conf"; OpCodesFile = "opcodes.conf";
EQTimeFile = "eqtime.cfg";
// Dirs // Dirs
MapDir = "Maps"; MapDir = "Maps";
QuestDir = "quests"; QuestDir = "quests";

View File

@ -133,72 +133,6 @@ int EQTime::SetCurrentEQTimeOfDay(TimeOfDay_Struct start_eq, time_t start_real)
return 1; return 1;
} }
//saveFile and loadFile need to use long for the save datatype...
//For some reason, ifstream/ofstream have problems with EQEmu datatypes in files.
bool EQTime::saveFile(const char *filename)
{
std::ofstream of;
of.open(filename);
if (!of)
{
Log.Out(Logs::General, Logs::Error, "EQTime::saveFile failed: Unable to open file '%s'", filename);
return false;
}
//Enable for debugging
of << EQT_VERSION << std::endl;
of << (long)eqTime.start_eqtime.day << std::endl;
of << (long)eqTime.start_eqtime.hour << std::endl;
of << (long)eqTime.start_eqtime.minute << std::endl;
of << (long)eqTime.start_eqtime.month << std::endl;
of << eqTime.start_eqtime.year << std::endl;
of << eqTime.start_realtime << std::endl;
of.close();
return true;
}
bool EQTime::loadFile(const char *filename)
{
int version=0;
long in_data=0;
std::ifstream in;
in.open(filename);
if(!in)
{
Log.Out(Logs::General, Logs::Error, "Could not load EQTime file %s", filename);
return false;
}
in >> version;
in.ignore(80, '\n');
if(version != EQT_VERSION)
{
Log.Out(Logs::General, Logs::Error, "'%s' is NOT a valid EQTime file. File version is %i, EQTime version is %i", filename, version, EQT_VERSION);
return false;
}
//in >> eqTime.start_eqtime.day;
in >> in_data;
in.ignore(80, '\n');
eqTime.start_eqtime.day = in_data;
//in >> eqTime.start_eqtime.hour;
in >> in_data;
eqTime.start_eqtime.hour = in_data;
in.ignore(80, '\n');
//in >> eqTime.start_eqtime.minute;
in >> in_data;
in.ignore(80, '\n');
eqTime.start_eqtime.minute = in_data;
//in >> eqTime.start_eqtime.month;
in >> in_data;
in.ignore(80, '\n');
eqTime.start_eqtime.month = in_data;
in >> eqTime.start_eqtime.year;
in.ignore(80, '\n');
in >> eqTime.start_realtime;
//Enable for debugging...
in.close();
return true;
}
bool EQTime::IsTimeBefore(TimeOfDay_Struct *base, TimeOfDay_Struct *test) { bool EQTime::IsTimeBefore(TimeOfDay_Struct *base, TimeOfDay_Struct *test) {
if (base->year > test->year) if (base->year > test->year)
return(true); return(true);

View File

@ -39,12 +39,6 @@ public:
static void ToString(TimeOfDay_Struct *t, std::string &str); static void ToString(TimeOfDay_Struct *t, std::string &str);
//Database functions
//bool loadDB(Database q);
//bool setDB(Database q);
bool loadFile(const char *filename);
bool saveFile(const char *filename);
private: private:
//This is our reference clock. //This is our reference clock.
eqTimeOfDay eqTime; eqTimeOfDay eqTime;

View File

@ -233,6 +233,8 @@ enum { //some random constants
#define GROUP_EXP_PER_POINT 1000 #define GROUP_EXP_PER_POINT 1000
#define RAID_EXP_PER_POINT 2000 #define RAID_EXP_PER_POINT 2000
#define ZONE_CONTROLLER_NPC_ID 10
//Some hard coded statuses from commands and other places: //Some hard coded statuses from commands and other places:
enum { enum {
minStatusToBeGM = 40, minStatusToBeGM = 40,

View File

@ -41,6 +41,7 @@ F(ac)
F(deity) F(deity)
F(skillmodvalue) F(skillmodvalue)
F(UNK033) F(UNK033)
F(skillmodmax)
F(skillmodtype) F(skillmodtype)
F(banedmgrace) F(banedmgrace)
F(banedmgamt) F(banedmgamt)
@ -172,7 +173,10 @@ F(bardlevel)
F(questitemflag) F(questitemflag)
F(svcorruption) F(svcorruption)
F(purity) F(purity)
F(evoitem)
F(evoid)
F(evolvinglevel) F(evolvinglevel)
F(evomax)
F(backstabdmg) F(backstabdmg)
F(dsmitigation) F(dsmitigation)
F(heroic_str) F(heroic_str)

View File

@ -130,6 +130,7 @@ struct Item_Struct {
uint32 Deity; // Bitmask of Deities that can equip this item uint32 Deity; // Bitmask of Deities that can equip this item
//uint32 Unk033 //uint32 Unk033
int32 SkillModValue; // % Mod to skill specified in SkillModType int32 SkillModValue; // % Mod to skill specified in SkillModType
int32 SkillModMax; // Max skill point modification
uint32 SkillModType; // Type of skill for SkillModValue to apply to uint32 SkillModType; // Type of skill for SkillModValue to apply to
uint32 BaneDmgRace; // Bane Damage Race uint32 BaneDmgRace; // Bane Damage Race
int8 BaneDmgAmt; // Bane Damage Body Amount int8 BaneDmgAmt; // Bane Damage Body Amount
@ -218,7 +219,10 @@ struct Item_Struct {
// Begin SoF Fields // Begin SoF Fields
int32 SVCorruption; int32 SVCorruption;
uint32 Purity; uint32 Purity;
uint8 EvolvingItem;
uint32 EvolvingID;
uint8 EvolvingLevel; uint8 EvolvingLevel;
uint8 EvolvingMax;
uint32 BackstabDmg; uint32 BackstabDmg;
uint32 DSMitigation; uint32 DSMitigation;
int32 HeroicStr; int32 HeroicStr;

View File

@ -5231,19 +5231,19 @@ namespace RoF
hdr.unknown044 = 0; hdr.unknown044 = 0;
hdr.unknown048 = 0; hdr.unknown048 = 0;
hdr.unknown052 = 0; hdr.unknown052 = 0;
hdr.isEvolving = item->EvolvingLevel > 0 ? 1 : 0; hdr.isEvolving = item->EvolvingItem;
ss.write((const char*)&hdr, sizeof(RoF::structs::ItemSerializationHeader)); ss.write((const char*)&hdr, sizeof(RoF::structs::ItemSerializationHeader));
if (item->EvolvingLevel > 0) { if (item->EvolvingItem > 0) {
RoF::structs::EvolvingItem evotop; RoF::structs::EvolvingItem evotop;
evotop.unknown001 = 0; evotop.unknown001 = 0;
evotop.unknown002 = 0; evotop.unknown002 = 0;
evotop.unknown003 = 0; evotop.unknown003 = 0;
evotop.unknown004 = 0; evotop.unknown004 = 0;
evotop.evoLevel = item->EvolvingLevel; evotop.evoLevel = item->EvolvingLevel;
evotop.progress = 95.512; evotop.progress = 0;
evotop.Activated = 1; evotop.Activated = 1;
evotop.evomaxlevel = 7; evotop.evomaxlevel = item->EvolvingMax;
ss.write((const char*)&evotop, sizeof(RoF::structs::EvolvingItem)); ss.write((const char*)&evotop, sizeof(RoF::structs::EvolvingItem));
} }
//ORNAMENT IDFILE / ICON //ORNAMENT IDFILE / ICON
@ -5353,7 +5353,7 @@ namespace RoF
ibs.Races = item->Races; ibs.Races = item->Races;
ibs.Deity = item->Deity; ibs.Deity = item->Deity;
ibs.SkillModValue = item->SkillModValue; ibs.SkillModValue = item->SkillModValue;
ibs.SkillModMax = 0xffffffff; ibs.SkillModMax = item->SkillModMax;
ibs.SkillModType = (int8)(item->SkillModType); ibs.SkillModType = (int8)(item->SkillModType);
ibs.SkillModExtra = 0; ibs.SkillModExtra = 0;
ibs.BaneDmgRace = item->BaneDmgRace; ibs.BaneDmgRace = item->BaneDmgRace;

View File

@ -5432,19 +5432,19 @@ namespace RoF2
hdr.unknown044 = 0; hdr.unknown044 = 0;
hdr.unknown048 = 0; hdr.unknown048 = 0;
hdr.unknown052 = 0; hdr.unknown052 = 0;
hdr.isEvolving = item->EvolvingLevel > 0 ? 1 : 0; hdr.isEvolving = item->EvolvingItem;
ss.write((const char*)&hdr, sizeof(RoF2::structs::ItemSerializationHeader)); ss.write((const char*)&hdr, sizeof(RoF2::structs::ItemSerializationHeader));
if (item->EvolvingLevel > 0) { if (item->EvolvingItem > 0) {
RoF2::structs::EvolvingItem evotop; RoF2::structs::EvolvingItem evotop;
evotop.unknown001 = 0; evotop.unknown001 = 0;
evotop.unknown002 = 0; evotop.unknown002 = 0;
evotop.unknown003 = 0; evotop.unknown003 = 0;
evotop.unknown004 = 0; evotop.unknown004 = 0;
evotop.evoLevel = item->EvolvingLevel; evotop.evoLevel = item->EvolvingLevel;
evotop.progress = 95.512; evotop.progress = 0;
evotop.Activated = 1; evotop.Activated = 1;
evotop.evomaxlevel = 7; evotop.evomaxlevel = item->EvolvingMax;
ss.write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem)); ss.write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem));
} }
//ORNAMENT IDFILE / ICON //ORNAMENT IDFILE / ICON
@ -5554,7 +5554,7 @@ namespace RoF2
ibs.Races = item->Races; ibs.Races = item->Races;
ibs.Deity = item->Deity; ibs.Deity = item->Deity;
ibs.SkillModValue = item->SkillModValue; ibs.SkillModValue = item->SkillModValue;
ibs.SkillModMax = 0xffffffff; ibs.SkillModMax = item->SkillModMax;
ibs.SkillModType = (int8)(item->SkillModType); ibs.SkillModType = (int8)(item->SkillModType);
ibs.SkillModExtra = 0; ibs.SkillModExtra = 0;
ibs.BaneDmgRace = item->BaneDmgRace; ibs.BaneDmgRace = item->BaneDmgRace;

View File

@ -3835,19 +3835,19 @@ namespace UF
hdr.unknown044 = 0; hdr.unknown044 = 0;
hdr.unknown048 = 0; hdr.unknown048 = 0;
hdr.unknown052 = 0; hdr.unknown052 = 0;
hdr.isEvolving = item->EvolvingLevel > 0 ? 1 : 0; hdr.isEvolving = item->EvolvingItem;
ss.write((const char*)&hdr, sizeof(UF::structs::ItemSerializationHeader)); ss.write((const char*)&hdr, sizeof(UF::structs::ItemSerializationHeader));
if (item->EvolvingLevel > 0) { if (item->EvolvingItem > 0) {
UF::structs::EvolvingItem evotop; UF::structs::EvolvingItem evotop;
evotop.unknown001 = 0; evotop.unknown001 = 0;
evotop.unknown002 = 0; evotop.unknown002 = 0;
evotop.unknown003 = 0; evotop.unknown003 = 0;
evotop.unknown004 = 0; evotop.unknown004 = 0;
evotop.evoLevel = item->EvolvingLevel; evotop.evoLevel = item->EvolvingLevel;
evotop.progress = 95.512; evotop.progress = 0;
evotop.Activated = 1; evotop.Activated = 1;
evotop.evomaxlevel = 7; evotop.evomaxlevel = item->EvolvingMax;
ss.write((const char*)&evotop, sizeof(UF::structs::EvolvingItem)); ss.write((const char*)&evotop, sizeof(UF::structs::EvolvingItem));
} }
//ORNAMENT IDFILE / ICON - //ORNAMENT IDFILE / ICON -
@ -3947,7 +3947,7 @@ namespace UF
ibs.Races = item->Races; ibs.Races = item->Races;
ibs.Deity = item->Deity; ibs.Deity = item->Deity;
ibs.SkillModValue = item->SkillModValue; ibs.SkillModValue = item->SkillModValue;
ibs.unknown5 = 0; ibs.SkillModMax = item->SkillModMax;
ibs.SkillModType = item->SkillModType; ibs.SkillModType = item->SkillModType;
ibs.BaneDmgRace = item->BaneDmgRace; ibs.BaneDmgRace = item->BaneDmgRace;
ibs.BaneDmgBody = item->BaneDmgBody; ibs.BaneDmgBody = item->BaneDmgBody;

View File

@ -4103,7 +4103,7 @@ struct ItemBodyStruct
uint32 Races; uint32 Races;
uint32 Deity; uint32 Deity;
int32 SkillModValue; int32 SkillModValue;
uint32 unknown5; uint32 SkillModMax;
uint32 SkillModType; uint32 SkillModType;
uint32 BaneDmgRace; uint32 BaneDmgRace;
uint32 BaneDmgBody; uint32 BaneDmgBody;

View File

@ -248,6 +248,26 @@ bool RuleManager::LoadRules(Database *database, const char *ruleset_name) {
m_activeRuleset = ruleset_id; m_activeRuleset = ruleset_id;
m_activeName = ruleset_name; m_activeName = ruleset_name;
/* Load default ruleset values first if we're loading something other than default */
if (strcasecmp(ruleset_name, "default") != 0){
std::string default_ruleset_name = "default";
int default_ruleset_id = GetRulesetID(database, default_ruleset_name.c_str());
if (default_ruleset_id < 0) {
Log.Out(Logs::Detail, Logs::Rules, "Failed to find default ruleset '%s' for load operation. Canceling.", default_ruleset_name.c_str());
return(false);
}
Log.Out(Logs::Detail, Logs::Rules, "Loading rule set '%s' (%d)", default_ruleset_name.c_str(), default_ruleset_id);
std::string query = StringFormat("SELECT rule_name, rule_value FROM rule_values WHERE ruleset_id = %d", default_ruleset_id);
auto results = database->QueryDatabase(query);
if (!results.Success())
return false;
for (auto row = results.begin(); row != results.end(); ++row)
if (!SetRule(row[0], row[1], nullptr, false))
Log.Out(Logs::Detail, Logs::Rules, "Unable to interpret rule record for %s", row[0]);
}
std::string query = StringFormat("SELECT rule_name, rule_value FROM rule_values WHERE ruleset_id=%d", ruleset_id); std::string query = StringFormat("SELECT rule_name, rule_value FROM rule_values WHERE ruleset_id=%d", ruleset_id);
auto results = database->QueryDatabase(query); auto results = database->QueryDatabase(query);
if (!results.Success()) if (!results.Success())

View File

@ -233,6 +233,7 @@ RULE_BOOL(Zone, LevelBasedEXPMods, false) // Allows you to use the level_exp_mod
RULE_INT(Zone, WeatherTimer, 600) // Weather timer when no duration is available RULE_INT(Zone, WeatherTimer, 600) // Weather timer when no duration is available
RULE_BOOL(Zone, EnableLoggedOffReplenishments, true) RULE_BOOL(Zone, EnableLoggedOffReplenishments, true)
RULE_INT(Zone, MinOfflineTimeToReplenishments, 21600) // 21600 seconds is 6 Hours RULE_INT(Zone, MinOfflineTimeToReplenishments, 21600) // 21600 seconds is 6 Hours
RULE_BOOL(Zone, UseZoneController, true) // Enables the ability to use persistent quest based zone controllers (zone_controller.pl/lua)
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Map) RULE_CATEGORY(Map)
@ -459,6 +460,8 @@ RULE_BOOL(Combat, ProjectileDmgOnImpact, true) //If enabled, projectiles (ie arr
RULE_BOOL(Combat, MeleePush, true) // enable melee push RULE_BOOL(Combat, MeleePush, true) // enable melee push
RULE_INT(Combat, MeleePushChance, 50) // (NPCs) chance the target will be pushed. Made up, 100 actually isn't that bad RULE_INT(Combat, MeleePushChance, 50) // (NPCs) chance the target will be pushed. Made up, 100 actually isn't that bad
RULE_BOOL(Combat, UseLiveCombatRounds, true) // turn this false if you don't want to worry about fixing up combat rounds for NPCs RULE_BOOL(Combat, UseLiveCombatRounds, true) // turn this false if you don't want to worry about fixing up combat rounds for NPCs
RULE_INT(Combat, NPCAssistCap, 5) // Maxiumium number of NPCs that will assist another NPC at once
RULE_INT(Combat, NPCAssistCapTimer, 6000) // Time in milliseconds a NPC will take to clear assist aggro cap space
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(NPC) RULE_CATEGORY(NPC)
@ -494,6 +497,7 @@ RULE_INT(Aggro, PetSpellAggroMod, 10)
RULE_REAL(Aggro, TunnelVisionAggroMod, 0.75) //people not currently the top hate generate this much hate on a Tunnel Vision mob RULE_REAL(Aggro, TunnelVisionAggroMod, 0.75) //people not currently the top hate generate this much hate on a Tunnel Vision mob
RULE_INT(Aggro, MaxScalingProcAggro, 400) // Set to -1 for no limit. Maxmimum amount of aggro that HP scaling SPA effect in a proc will add. RULE_INT(Aggro, MaxScalingProcAggro, 400) // Set to -1 for no limit. Maxmimum amount of aggro that HP scaling SPA effect in a proc will add.
RULE_INT(Aggro, IntAggroThreshold, 75) // Int <= this will aggro regardless of level difference. RULE_INT(Aggro, IntAggroThreshold, 75) // Int <= this will aggro regardless of level difference.
RULE_BOOL(Aggro, AllowTickPulling, false) // tick pulling is an exploit in an NPC's call for help fixed sometime in 2006 on live
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(TaskSystem) RULE_CATEGORY(TaskSystem)

View File

@ -1,6 +1,10 @@
#include <iostream> #include <iostream>
#include <cstring> #include <cstring>
#if defined(_MSC_VER) && _MSC_VER >= 1800
#include <algorithm>
#endif
#include "classes.h" #include "classes.h"
#include "eq_packet_structs.h" #include "eq_packet_structs.h"
#include "eqemu_exception.h" #include "eqemu_exception.h"
@ -802,36 +806,37 @@ bool SharedDatabase::LoadItems(const std::string &prefix) {
return true; return true;
} }
void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_item_id) { void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_item_id)
EQEmu::FixedMemoryHashSet<Item_Struct> hash(reinterpret_cast<uint8*>(data), size, items, max_item_id); {
EQEmu::FixedMemoryHashSet<Item_Struct> hash(reinterpret_cast<uint8 *>(data), size, items, max_item_id);
char ndbuffer[4]; char ndbuffer[4];
bool disableNoRent = false; bool disableNoRent = false;
if(GetVariable("disablenorent", ndbuffer, 4)) { if (GetVariable("disablenorent", ndbuffer, 4)) {
if(ndbuffer[0] == '1' && ndbuffer[1] == '\0') { if (ndbuffer[0] == '1' && ndbuffer[1] == '\0') {
disableNoRent = true; disableNoRent = true;
} }
} }
bool disableNoDrop = false; bool disableNoDrop = false;
if(GetVariable("disablenodrop", ndbuffer, 4)) { if (GetVariable("disablenodrop", ndbuffer, 4)) {
if(ndbuffer[0] == '1' && ndbuffer[1] == '\0') { if (ndbuffer[0] == '1' && ndbuffer[1] == '\0') {
disableNoDrop = true; disableNoDrop = true;
} }
} }
bool disableLoreGroup = false; bool disableLoreGroup = false;
if(GetVariable("disablelore", ndbuffer, 4)) { if (GetVariable("disablelore", ndbuffer, 4)) {
if(ndbuffer[0] == '1' && ndbuffer[1] == '\0') { if (ndbuffer[0] == '1' && ndbuffer[1] == '\0') {
disableLoreGroup = true; disableLoreGroup = true;
} }
} }
bool disableNoTransfer = false; bool disableNoTransfer = false;
if(GetVariable("disablenotransfer", ndbuffer, 4)) { if (GetVariable("disablenotransfer", ndbuffer, 4)) {
if(ndbuffer[0] == '1' && ndbuffer[1] == '\0') { if (ndbuffer[0] == '1' && ndbuffer[1] == '\0') {
disableNoTransfer = true; disableNoTransfer = true;
} }
} }
Item_Struct item; Item_Struct item;
const std::string query = "SELECT source," const std::string query = "SELECT source,"
#define F(x) "`"#x"`," #define F(x) "`"#x"`,"
@ -839,224 +844,226 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_
#undef F #undef F
"updated FROM items ORDER BY id"; "updated FROM items ORDER BY id";
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
return; return;
} }
for(auto row = results.begin(); row != results.end(); ++row) { for (auto row = results.begin(); row != results.end(); ++row) {
memset(&item, 0, sizeof(Item_Struct)); memset(&item, 0, sizeof(Item_Struct));
item.ItemClass = (uint8)atoi(row[ItemField::itemclass]); item.ItemClass = (uint8)atoi(row[ItemField::itemclass]);
strcpy(item.Name,row[ItemField::name]); strcpy(item.Name, row[ItemField::name]);
strcpy(item.Lore,row[ItemField::lore]); strcpy(item.Lore, row[ItemField::lore]);
strcpy(item.IDFile,row[ItemField::idfile]); strcpy(item.IDFile, row[ItemField::idfile]);
item.ID = (uint32)atoul(row[ItemField::id]); item.ID = (uint32)atoul(row[ItemField::id]);
item.Weight = (uint8)atoi(row[ItemField::weight]); item.Weight = (uint8)atoi(row[ItemField::weight]);
item.NoRent = disableNoRent ? (uint8)atoi("255") : (uint8)atoi(row[ItemField::norent]); item.NoRent = disableNoRent ? (uint8)atoi("255") : (uint8)atoi(row[ItemField::norent]);
item.NoDrop = disableNoDrop ? (uint8)atoi("255") : (uint8)atoi(row[ItemField::nodrop]); item.NoDrop = disableNoDrop ? (uint8)atoi("255") : (uint8)atoi(row[ItemField::nodrop]);
item.Size = (uint8)atoi(row[ItemField::size]); item.Size = (uint8)atoi(row[ItemField::size]);
item.Slots = (uint32)atoul(row[ItemField::slots]); item.Slots = (uint32)atoul(row[ItemField::slots]);
item.Price = (uint32)atoul(row[ItemField::price]); item.Price = (uint32)atoul(row[ItemField::price]);
item.Icon = (uint32)atoul(row[ItemField::icon]); item.Icon = (uint32)atoul(row[ItemField::icon]);
item.BenefitFlag = (atoul(row[ItemField::benefitflag]) != 0); item.BenefitFlag = (atoul(row[ItemField::benefitflag]) != 0);
item.Tradeskills = (atoi(row[ItemField::tradeskills])==0) ? false : true; item.Tradeskills = (atoi(row[ItemField::tradeskills]) == 0) ? false : true;
item.CR = (int8)atoi(row[ItemField::cr]); item.CR = (int8)atoi(row[ItemField::cr]);
item.DR = (int8)atoi(row[ItemField::dr]); item.DR = (int8)atoi(row[ItemField::dr]);
item.PR = (int8)atoi(row[ItemField::pr]); item.PR = (int8)atoi(row[ItemField::pr]);
item.MR = (int8)atoi(row[ItemField::mr]); item.MR = (int8)atoi(row[ItemField::mr]);
item.FR = (int8)atoi(row[ItemField::fr]); item.FR = (int8)atoi(row[ItemField::fr]);
item.AStr = (int8)atoi(row[ItemField::astr]); item.AStr = (int8)atoi(row[ItemField::astr]);
item.ASta = (int8)atoi(row[ItemField::asta]); item.ASta = (int8)atoi(row[ItemField::asta]);
item.AAgi = (int8)atoi(row[ItemField::aagi]); item.AAgi = (int8)atoi(row[ItemField::aagi]);
item.ADex = (int8)atoi(row[ItemField::adex]); item.ADex = (int8)atoi(row[ItemField::adex]);
item.ACha = (int8)atoi(row[ItemField::acha]); item.ACha = (int8)atoi(row[ItemField::acha]);
item.AInt = (int8)atoi(row[ItemField::aint]); item.AInt = (int8)atoi(row[ItemField::aint]);
item.AWis = (int8)atoi(row[ItemField::awis]); item.AWis = (int8)atoi(row[ItemField::awis]);
item.HP = (int32)atoul(row[ItemField::hp]); item.HP = (int32)atoul(row[ItemField::hp]);
item.Mana = (int32)atoul(row[ItemField::mana]); item.Mana = (int32)atoul(row[ItemField::mana]);
item.AC = (int32)atoul(row[ItemField::ac]); item.AC = (int32)atoul(row[ItemField::ac]);
item.Deity = (uint32)atoul(row[ItemField::deity]); item.Deity = (uint32)atoul(row[ItemField::deity]);
item.SkillModValue = (int32)atoul(row[ItemField::skillmodvalue]); item.SkillModValue = (int32)atoul(row[ItemField::skillmodvalue]);
item.SkillModMax = (int32)atoul(row[ItemField::skillmodmax]);
item.SkillModType = (uint32)atoul(row[ItemField::skillmodtype]);
item.BaneDmgRace = (uint32)atoul(row[ItemField::banedmgrace]);
item.BaneDmgAmt = (int8)atoi(row[ItemField::banedmgamt]);
item.BaneDmgBody = (uint32)atoul(row[ItemField::banedmgbody]);
item.Magic = (atoi(row[ItemField::magic]) == 0) ? false : true;
item.CastTime_ = (int32)atoul(row[ItemField::casttime_]);
item.ReqLevel = (uint8)atoi(row[ItemField::reqlevel]);
item.BardType = (uint32)atoul(row[ItemField::bardtype]);
item.BardValue = (int32)atoul(row[ItemField::bardvalue]);
item.Light = (int8)atoi(row[ItemField::light]);
item.Delay = (uint8)atoi(row[ItemField::delay]);
item.RecLevel = (uint8)atoi(row[ItemField::reclevel]);
item.RecSkill = (uint8)atoi(row[ItemField::recskill]);
item.ElemDmgType = (uint8)atoi(row[ItemField::elemdmgtype]);
item.ElemDmgAmt = (uint8)atoi(row[ItemField::elemdmgamt]);
item.Range = (uint8)atoi(row[ItemField::range]);
item.Damage = (uint32)atoi(row[ItemField::damage]);
item.Color = (uint32)atoul(row[ItemField::color]);
item.Classes = (uint32)atoul(row[ItemField::classes]);
item.Races = (uint32)atoul(row[ItemField::races]);
item.SkillModType = (uint32)atoul(row[ItemField::skillmodtype]); item.MaxCharges = (int16)atoi(row[ItemField::maxcharges]);
item.BaneDmgRace = (uint32)atoul(row[ItemField::banedmgrace]); item.ItemType = (uint8)atoi(row[ItemField::itemtype]);
item.BaneDmgAmt = (int8)atoi(row[ItemField::banedmgamt]);
item.BaneDmgBody = (uint32)atoul(row[ItemField::banedmgbody]);
item.Magic = (atoi(row[ItemField::magic])==0) ? false : true;
item.CastTime_ = (int32)atoul(row[ItemField::casttime_]);
item.ReqLevel = (uint8)atoi(row[ItemField::reqlevel]);
item.BardType = (uint32)atoul(row[ItemField::bardtype]);
item.BardValue = (int32)atoul(row[ItemField::bardvalue]);
item.Light = (int8)atoi(row[ItemField::light]);
item.Delay = (uint8)atoi(row[ItemField::delay]);
item.RecLevel = (uint8)atoi(row[ItemField::reclevel]);
item.RecSkill = (uint8)atoi(row[ItemField::recskill]);
item.ElemDmgType = (uint8)atoi(row[ItemField::elemdmgtype]);
item.ElemDmgAmt = (uint8)atoi(row[ItemField::elemdmgamt]);
item.Range = (uint8)atoi(row[ItemField::range]);
item.Damage = (uint32)atoi(row[ItemField::damage]);
item.Color = (uint32)atoul(row[ItemField::color]);
item.Classes = (uint32)atoul(row[ItemField::classes]);
item.Races = (uint32)atoul(row[ItemField::races]);
item.MaxCharges = (int16)atoi(row[ItemField::maxcharges]);
item.ItemType = (uint8)atoi(row[ItemField::itemtype]);
item.Material = (uint8)atoi(row[ItemField::material]); item.Material = (uint8)atoi(row[ItemField::material]);
item.HerosForgeModel = (uint32)atoi(row[ItemField::herosforgemodel]); item.HerosForgeModel = (uint32)atoi(row[ItemField::herosforgemodel]);
item.SellRate = (float)atof(row[ItemField::sellrate]); item.SellRate = (float)atof(row[ItemField::sellrate]);
item.CastTime = (uint32)atoul(row[ItemField::casttime]); item.CastTime = (uint32)atoul(row[ItemField::casttime]);
item.EliteMaterial = (uint32)atoul(row[ItemField::elitematerial]); item.EliteMaterial = (uint32)atoul(row[ItemField::elitematerial]);
item.ProcRate = (int32)atoi(row[ItemField::procrate]); item.ProcRate = (int32)atoi(row[ItemField::procrate]);
item.CombatEffects = (int8)atoi(row[ItemField::combateffects]); item.CombatEffects = (int8)atoi(row[ItemField::combateffects]);
item.Shielding = (int8)atoi(row[ItemField::shielding]); item.Shielding = (int8)atoi(row[ItemField::shielding]);
item.StunResist = (int8)atoi(row[ItemField::stunresist]); item.StunResist = (int8)atoi(row[ItemField::stunresist]);
item.StrikeThrough = (int8)atoi(row[ItemField::strikethrough]); item.StrikeThrough = (int8)atoi(row[ItemField::strikethrough]);
item.ExtraDmgSkill = (uint32)atoul(row[ItemField::extradmgskill]); item.ExtraDmgSkill = (uint32)atoul(row[ItemField::extradmgskill]);
item.ExtraDmgAmt = (uint32)atoul(row[ItemField::extradmgamt]); item.ExtraDmgAmt = (uint32)atoul(row[ItemField::extradmgamt]);
item.SpellShield = (int8)atoi(row[ItemField::spellshield]); item.SpellShield = (int8)atoi(row[ItemField::spellshield]);
item.Avoidance = (int8)atoi(row[ItemField::avoidance]); item.Avoidance = (int8)atoi(row[ItemField::avoidance]);
item.Accuracy = (int8)atoi(row[ItemField::accuracy]); item.Accuracy = (int8)atoi(row[ItemField::accuracy]);
item.CharmFileID = (uint32)atoul(row[ItemField::charmfileid]); item.CharmFileID = (uint32)atoul(row[ItemField::charmfileid]);
item.FactionMod1 = (int32)atoul(row[ItemField::factionmod1]); item.FactionMod1 = (int32)atoul(row[ItemField::factionmod1]);
item.FactionMod2 = (int32)atoul(row[ItemField::factionmod2]); item.FactionMod2 = (int32)atoul(row[ItemField::factionmod2]);
item.FactionMod3 = (int32)atoul(row[ItemField::factionmod3]); item.FactionMod3 = (int32)atoul(row[ItemField::factionmod3]);
item.FactionMod4 = (int32)atoul(row[ItemField::factionmod4]); item.FactionMod4 = (int32)atoul(row[ItemField::factionmod4]);
item.FactionAmt1 = (int32)atoul(row[ItemField::factionamt1]); item.FactionAmt1 = (int32)atoul(row[ItemField::factionamt1]);
item.FactionAmt2 = (int32)atoul(row[ItemField::factionamt2]); item.FactionAmt2 = (int32)atoul(row[ItemField::factionamt2]);
item.FactionAmt3 = (int32)atoul(row[ItemField::factionamt3]); item.FactionAmt3 = (int32)atoul(row[ItemField::factionamt3]);
item.FactionAmt4 = (int32)atoul(row[ItemField::factionamt4]); item.FactionAmt4 = (int32)atoul(row[ItemField::factionamt4]);
strcpy(item.CharmFile,row[ItemField::charmfile]); strcpy(item.CharmFile, row[ItemField::charmfile]);
item.AugType = (uint32)atoul(row[ItemField::augtype]); item.AugType = (uint32)atoul(row[ItemField::augtype]);
item.AugSlotType[0] = (uint8)atoi(row[ItemField::augslot1type]); item.AugSlotType[0] = (uint8)atoi(row[ItemField::augslot1type]);
item.AugSlotVisible[0] = (uint8)atoi(row[ItemField::augslot1visible]); item.AugSlotVisible[0] = (uint8)atoi(row[ItemField::augslot1visible]);
item.AugSlotUnk2[0] = 0; item.AugSlotUnk2[0] = 0;
item.AugSlotType[1] = (uint8)atoi(row[ItemField::augslot2type]); item.AugSlotType[1] = (uint8)atoi(row[ItemField::augslot2type]);
item.AugSlotVisible[1] = (uint8)atoi(row[ItemField::augslot2visible]); item.AugSlotVisible[1] = (uint8)atoi(row[ItemField::augslot2visible]);
item.AugSlotUnk2[1] = 0; item.AugSlotUnk2[1] = 0;
item.AugSlotType[2] = (uint8)atoi(row[ItemField::augslot3type]); item.AugSlotType[2] = (uint8)atoi(row[ItemField::augslot3type]);
item.AugSlotVisible[2] = (uint8)atoi(row[ItemField::augslot3visible]); item.AugSlotVisible[2] = (uint8)atoi(row[ItemField::augslot3visible]);
item.AugSlotUnk2[2] = 0; item.AugSlotUnk2[2] = 0;
item.AugSlotType[3] = (uint8)atoi(row[ItemField::augslot4type]); item.AugSlotType[3] = (uint8)atoi(row[ItemField::augslot4type]);
item.AugSlotVisible[3] = (uint8)atoi(row[ItemField::augslot4visible]); item.AugSlotVisible[3] = (uint8)atoi(row[ItemField::augslot4visible]);
item.AugSlotUnk2[3] = 0; item.AugSlotUnk2[3] = 0;
item.AugSlotType[4] = (uint8)atoi(row[ItemField::augslot5type]); item.AugSlotType[4] = (uint8)atoi(row[ItemField::augslot5type]);
item.AugSlotVisible[4] = (uint8)atoi(row[ItemField::augslot5visible]); item.AugSlotVisible[4] = (uint8)atoi(row[ItemField::augslot5visible]);
item.AugSlotUnk2[4] = 0; item.AugSlotUnk2[4] = 0;
item.AugSlotType[5] = (uint8)atoi(row[ItemField::augslot6type]); item.AugSlotType[5] = (uint8)atoi(row[ItemField::augslot6type]);
item.AugSlotVisible[5] = (uint8)atoi(row[ItemField::augslot6visible]); item.AugSlotVisible[5] = (uint8)atoi(row[ItemField::augslot6visible]);
item.AugSlotUnk2[5] = 0; item.AugSlotUnk2[5] = 0;
item.LDoNTheme = (uint32)atoul(row[ItemField::ldontheme]); item.LDoNTheme = (uint32)atoul(row[ItemField::ldontheme]);
item.LDoNPrice = (uint32)atoul(row[ItemField::ldonprice]); item.LDoNPrice = (uint32)atoul(row[ItemField::ldonprice]);
item.LDoNSold = (uint32)atoul(row[ItemField::ldonsold]); item.LDoNSold = (uint32)atoul(row[ItemField::ldonsold]);
item.BagType = (uint8)atoi(row[ItemField::bagtype]); item.BagType = (uint8)atoi(row[ItemField::bagtype]);
item.BagSlots = (uint8)atoi(row[ItemField::bagslots]); item.BagSlots = (uint8)std::min(atoi(row[ItemField::bagslots]), 10); // FIXME: remove when big bags supported
item.BagSize = (uint8)atoi(row[ItemField::bagsize]); item.BagSize = (uint8)atoi(row[ItemField::bagsize]);
item.BagWR = (uint8)atoi(row[ItemField::bagwr]); item.BagWR = (uint8)atoi(row[ItemField::bagwr]);
item.Book = (uint8)atoi(row[ItemField::book]); item.Book = (uint8)atoi(row[ItemField::book]);
item.BookType = (uint32)atoul(row[ItemField::booktype]); item.BookType = (uint32)atoul(row[ItemField::booktype]);
strcpy(item.Filename,row[ItemField::filename]); strcpy(item.Filename, row[ItemField::filename]);
item.BaneDmgRaceAmt = (uint32)atoul(row[ItemField::banedmgraceamt]); item.BaneDmgRaceAmt = (uint32)atoul(row[ItemField::banedmgraceamt]);
item.AugRestrict = (uint32)atoul(row[ItemField::augrestrict]); item.AugRestrict = (uint32)atoul(row[ItemField::augrestrict]);
item.LoreGroup = disableLoreGroup ? (uint8)atoi("0") : atoi(row[ItemField::loregroup]); item.LoreGroup = disableLoreGroup ? (uint8)atoi("0") : atoi(row[ItemField::loregroup]);
item.LoreFlag = item.LoreGroup!=0; item.LoreFlag = item.LoreGroup != 0;
item.PendingLoreFlag = (atoi(row[ItemField::pendingloreflag])==0) ? false : true; item.PendingLoreFlag = (atoi(row[ItemField::pendingloreflag]) == 0) ? false : true;
item.ArtifactFlag = (atoi(row[ItemField::artifactflag])==0) ? false : true; item.ArtifactFlag = (atoi(row[ItemField::artifactflag]) == 0) ? false : true;
item.SummonedFlag = (atoi(row[ItemField::summonedflag])==0) ? false : true; item.SummonedFlag = (atoi(row[ItemField::summonedflag]) == 0) ? false : true;
item.Favor = (uint32)atoul(row[ItemField::favor]); item.Favor = (uint32)atoul(row[ItemField::favor]);
item.FVNoDrop = (atoi(row[ItemField::fvnodrop])==0) ? false : true; item.FVNoDrop = (atoi(row[ItemField::fvnodrop]) == 0) ? false : true;
item.Endur = (uint32)atoul(row[ItemField::endur]); item.Endur = (uint32)atoul(row[ItemField::endur]);
item.DotShielding = (uint32)atoul(row[ItemField::dotshielding]); item.DotShielding = (uint32)atoul(row[ItemField::dotshielding]);
item.Attack = (uint32)atoul(row[ItemField::attack]); item.Attack = (uint32)atoul(row[ItemField::attack]);
item.Regen = (uint32)atoul(row[ItemField::regen]); item.Regen = (uint32)atoul(row[ItemField::regen]);
item.ManaRegen = (uint32)atoul(row[ItemField::manaregen]); item.ManaRegen = (uint32)atoul(row[ItemField::manaregen]);
item.EnduranceRegen = (uint32)atoul(row[ItemField::enduranceregen]); item.EnduranceRegen = (uint32)atoul(row[ItemField::enduranceregen]);
item.Haste = (uint32)atoul(row[ItemField::haste]); item.Haste = (uint32)atoul(row[ItemField::haste]);
item.DamageShield = (uint32)atoul(row[ItemField::damageshield]); item.DamageShield = (uint32)atoul(row[ItemField::damageshield]);
item.RecastDelay = (uint32)atoul(row[ItemField::recastdelay]); item.RecastDelay = (uint32)atoul(row[ItemField::recastdelay]);
item.RecastType = (uint32)atoul(row[ItemField::recasttype]); item.RecastType = (uint32)atoul(row[ItemField::recasttype]);
item.GuildFavor = (uint32)atoul(row[ItemField::guildfavor]); item.GuildFavor = (uint32)atoul(row[ItemField::guildfavor]);
item.AugDistiller = (uint32)atoul(row[ItemField::augdistiller]); item.AugDistiller = (uint32)atoul(row[ItemField::augdistiller]);
item.Attuneable = (atoi(row[ItemField::attuneable])==0) ? false : true; item.Attuneable = (atoi(row[ItemField::attuneable]) == 0) ? false : true;
item.NoPet = (atoi(row[ItemField::nopet])==0) ? false : true; item.NoPet = (atoi(row[ItemField::nopet]) == 0) ? false : true;
item.PointType = (uint32)atoul(row[ItemField::pointtype]); item.PointType = (uint32)atoul(row[ItemField::pointtype]);
item.PotionBelt = (atoi(row[ItemField::potionbelt])==0) ? false : true; item.PotionBelt = (atoi(row[ItemField::potionbelt]) == 0) ? false : true;
item.PotionBeltSlots = (atoi(row[ItemField::potionbeltslots])==0) ? false : true; item.PotionBeltSlots = (atoi(row[ItemField::potionbeltslots]) == 0) ? false : true;
item.StackSize = (uint16)atoi(row[ItemField::stacksize]); item.StackSize = (uint16)atoi(row[ItemField::stacksize]);
item.NoTransfer = disableNoTransfer ? false : (atoi(row[ItemField::notransfer])==0) ? false : true; item.NoTransfer = disableNoTransfer ? false : (atoi(row[ItemField::notransfer]) == 0) ? false : true;
item.Stackable = (atoi(row[ItemField::stackable])==0) ? false : true; item.Stackable = (atoi(row[ItemField::stackable]) == 0) ? false : true;
item.Click.Effect = (uint32)atoul(row[ItemField::clickeffect]); item.Click.Effect = (uint32)atoul(row[ItemField::clickeffect]);
item.Click.Type = (uint8)atoul(row[ItemField::clicktype]); item.Click.Type = (uint8)atoul(row[ItemField::clicktype]);
item.Click.Level = (uint8)atoul(row[ItemField::clicklevel]); item.Click.Level = (uint8)atoul(row[ItemField::clicklevel]);
item.Click.Level2 = (uint8)atoul(row[ItemField::clicklevel2]); item.Click.Level2 = (uint8)atoul(row[ItemField::clicklevel2]);
strcpy(item.CharmFile,row[ItemField::charmfile]); strcpy(item.CharmFile, row[ItemField::charmfile]);
item.Proc.Effect = (int32)atoul(row[ItemField::proceffect]); item.Proc.Effect = (int32)atoul(row[ItemField::proceffect]);
item.Proc.Type = (uint8)atoul(row[ItemField::proctype]); item.Proc.Type = (uint8)atoul(row[ItemField::proctype]);
item.Proc.Level = (uint8)atoul(row[ItemField::proclevel]); item.Proc.Level = (uint8)atoul(row[ItemField::proclevel]);
item.Proc.Level2 = (uint8)atoul(row[ItemField::proclevel2]); item.Proc.Level2 = (uint8)atoul(row[ItemField::proclevel2]);
item.Worn.Effect = (int32)atoul(row[ItemField::worneffect]); item.Worn.Effect = (int32)atoul(row[ItemField::worneffect]);
item.Worn.Type = (uint8)atoul(row[ItemField::worntype]); item.Worn.Type = (uint8)atoul(row[ItemField::worntype]);
item.Worn.Level = (uint8)atoul(row[ItemField::wornlevel]); item.Worn.Level = (uint8)atoul(row[ItemField::wornlevel]);
item.Worn.Level2 = (uint8)atoul(row[ItemField::wornlevel2]); item.Worn.Level2 = (uint8)atoul(row[ItemField::wornlevel2]);
item.Focus.Effect = (int32)atoul(row[ItemField::focuseffect]); item.Focus.Effect = (int32)atoul(row[ItemField::focuseffect]);
item.Focus.Type = (uint8)atoul(row[ItemField::focustype]); item.Focus.Type = (uint8)atoul(row[ItemField::focustype]);
item.Focus.Level = (uint8)atoul(row[ItemField::focuslevel]); item.Focus.Level = (uint8)atoul(row[ItemField::focuslevel]);
item.Focus.Level2 = (uint8)atoul(row[ItemField::focuslevel2]); item.Focus.Level2 = (uint8)atoul(row[ItemField::focuslevel2]);
item.Scroll.Effect = (int32)atoul(row[ItemField::scrolleffect]); item.Scroll.Effect = (int32)atoul(row[ItemField::scrolleffect]);
item.Scroll.Type = (uint8)atoul(row[ItemField::scrolltype]); item.Scroll.Type = (uint8)atoul(row[ItemField::scrolltype]);
item.Scroll.Level = (uint8)atoul(row[ItemField::scrolllevel]); item.Scroll.Level = (uint8)atoul(row[ItemField::scrolllevel]);
item.Scroll.Level2 = (uint8)atoul(row[ItemField::scrolllevel2]); item.Scroll.Level2 = (uint8)atoul(row[ItemField::scrolllevel2]);
item.Bard.Effect = (int32)atoul(row[ItemField::bardeffect]); item.Bard.Effect = (int32)atoul(row[ItemField::bardeffect]);
item.Bard.Type = (uint8)atoul(row[ItemField::bardtype]); item.Bard.Type = (uint8)atoul(row[ItemField::bardtype]);
item.Bard.Level = (uint8)atoul(row[ItemField::bardlevel]); item.Bard.Level = (uint8)atoul(row[ItemField::bardlevel]);
item.Bard.Level2 = (uint8)atoul(row[ItemField::bardlevel2]); item.Bard.Level2 = (uint8)atoul(row[ItemField::bardlevel2]);
item.QuestItemFlag = (atoi(row[ItemField::questitemflag])==0) ? false : true; item.QuestItemFlag = (atoi(row[ItemField::questitemflag]) == 0) ? false : true;
item.SVCorruption = (int32)atoi(row[ItemField::svcorruption]); item.SVCorruption = (int32)atoi(row[ItemField::svcorruption]);
item.Purity = (uint32)atoul(row[ItemField::purity]); item.Purity = (uint32)atoul(row[ItemField::purity]);
item.EvolvingLevel = (uint8)atoul(row[ItemField::evolvinglevel]); item.EvolvingItem = (uint8)atoul(row[ItemField::evoitem]);
item.BackstabDmg = (uint32)atoul(row[ItemField::backstabdmg]); item.EvolvingID = (uint8)atoul(row[ItemField::evoid]);
item.DSMitigation = (uint32)atoul(row[ItemField::dsmitigation]); item.EvolvingLevel = (uint8)atoul(row[ItemField::evolvinglevel]);
item.HeroicStr = (int32)atoi(row[ItemField::heroic_str]); item.EvolvingMax = (uint8)atoul(row[ItemField::evomax]);
item.HeroicInt = (int32)atoi(row[ItemField::heroic_int]); item.BackstabDmg = (uint32)atoul(row[ItemField::backstabdmg]);
item.HeroicWis = (int32)atoi(row[ItemField::heroic_wis]); item.DSMitigation = (uint32)atoul(row[ItemField::dsmitigation]);
item.HeroicAgi = (int32)atoi(row[ItemField::heroic_agi]); item.HeroicStr = (int32)atoi(row[ItemField::heroic_str]);
item.HeroicDex = (int32)atoi(row[ItemField::heroic_dex]); item.HeroicInt = (int32)atoi(row[ItemField::heroic_int]);
item.HeroicSta = (int32)atoi(row[ItemField::heroic_sta]); item.HeroicWis = (int32)atoi(row[ItemField::heroic_wis]);
item.HeroicCha = (int32)atoi(row[ItemField::heroic_cha]); item.HeroicAgi = (int32)atoi(row[ItemField::heroic_agi]);
item.HeroicMR = (int32)atoi(row[ItemField::heroic_mr]); item.HeroicDex = (int32)atoi(row[ItemField::heroic_dex]);
item.HeroicFR = (int32)atoi(row[ItemField::heroic_fr]); item.HeroicSta = (int32)atoi(row[ItemField::heroic_sta]);
item.HeroicCR = (int32)atoi(row[ItemField::heroic_cr]); item.HeroicCha = (int32)atoi(row[ItemField::heroic_cha]);
item.HeroicDR = (int32)atoi(row[ItemField::heroic_dr]); item.HeroicMR = (int32)atoi(row[ItemField::heroic_mr]);
item.HeroicPR = (int32)atoi(row[ItemField::heroic_pr]); item.HeroicFR = (int32)atoi(row[ItemField::heroic_fr]);
item.HeroicSVCorrup = (int32)atoi(row[ItemField::heroic_svcorrup]); item.HeroicCR = (int32)atoi(row[ItemField::heroic_cr]);
item.HealAmt = (int32)atoi(row[ItemField::healamt]); item.HeroicDR = (int32)atoi(row[ItemField::heroic_dr]);
item.SpellDmg = (int32)atoi(row[ItemField::spelldmg]); item.HeroicPR = (int32)atoi(row[ItemField::heroic_pr]);
item.LDoNSellBackRate = (uint32)atoul(row[ItemField::ldonsellbackrate]); item.HeroicSVCorrup = (int32)atoi(row[ItemField::heroic_svcorrup]);
item.ScriptFileID = (uint32)atoul(row[ItemField::scriptfileid]); item.HealAmt = (int32)atoi(row[ItemField::healamt]);
item.ExpendableArrow = (uint16)atoul(row[ItemField::expendablearrow]); item.SpellDmg = (int32)atoi(row[ItemField::spelldmg]);
item.Clairvoyance = (uint32)atoul(row[ItemField::clairvoyance]); item.LDoNSellBackRate = (uint32)atoul(row[ItemField::ldonsellbackrate]);
item.ScriptFileID = (uint32)atoul(row[ItemField::scriptfileid]);
item.ExpendableArrow = (uint16)atoul(row[ItemField::expendablearrow]);
item.Clairvoyance = (uint32)atoul(row[ItemField::clairvoyance]);
strcpy(item.ClickName,row[ItemField::clickname]); strcpy(item.ClickName, row[ItemField::clickname]);
strcpy(item.ProcName,row[ItemField::procname]); strcpy(item.ProcName, row[ItemField::procname]);
strcpy(item.WornName,row[ItemField::wornname]); strcpy(item.WornName, row[ItemField::wornname]);
strcpy(item.FocusName,row[ItemField::focusname]); strcpy(item.FocusName, row[ItemField::focusname]);
strcpy(item.ScrollName,row[ItemField::scrollname]); strcpy(item.ScrollName, row[ItemField::scrollname]);
try {
hash.insert(item.ID, item);
} catch(std::exception &ex) {
Log.Out(Logs::General, Logs::Error, "Database::LoadItems: %s", ex.what());
break;
}
}
try {
hash.insert(item.ID, item);
} catch (std::exception &ex) {
Log.Out(Logs::General, Logs::Error, "Database::LoadItems: %s", ex.what());
break;
}
}
} }
const Item_Struct* SharedDatabase::GetItem(uint32 id) { const Item_Struct* SharedDatabase::GetItem(uint32 id) {

View File

@ -30,7 +30,7 @@
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/ */
#define CURRENT_BINARY_DATABASE_VERSION 9091 #define CURRENT_BINARY_DATABASE_VERSION 9094
#ifdef BOTS #ifdef BOTS
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9000 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9000
#else #else

View File

@ -23,7 +23,7 @@ if($Config{osname}=~/linux/i){ $OS = "Linux"; }
if($Config{osname}=~/Win|MS/i){ $OS = "Windows"; } if($Config{osname}=~/Win|MS/i){ $OS = "Windows"; }
#::: If current version is less than what world is reporting, then download a new one... #::: If current version is less than what world is reporting, then download a new one...
$current_version = 13; $current_version = 14;
if($ARGV[0] eq "V"){ if($ARGV[0] eq "V"){
if($ARGV[1] > $current_version){ if($ARGV[1] > $current_version){
@ -107,6 +107,38 @@ if($path eq ""){
exit; exit;
} }
if($ARGV[0] eq "install_peq_db"){
$db_name = "peq";
if($ARGV[1]){
$db_name = $ARGV[1];
}
$db = $db_name;
#::: Database Routines
print "MariaDB :: Creating Database '" . $db_name . "'\n";
print `"$path" --host $host --user $user --password="$pass" -N -B -e "DROP DATABASE IF EXISTS $db_name;"`;
print `"$path" --host $host --user $user --password="$pass" -N -B -e "CREATE DATABASE $db_name"`;
if($OS eq "Windows"){ @db_version = split(': ', `world db_version`); }
if($OS eq "Linux"){ @db_version = split(': ', `./world db_version`); }
$bin_db_ver = trim($db_version[1]);
check_db_version_table();
$local_db_ver = trim(get_mysql_result("SELECT version FROM db_version LIMIT 1"));
fetch_peq_db_full();
print "\nFetching Latest Database Updates...\n";
main_db_management();
print "\nApplying Latest Database Updates...\n";
main_db_management();
print get_mysql_result("UPDATE `launcher` SET `dynamics` = 30 WHERE `name` = 'zone'");
}
if($ARGV[0] eq "remove_duplicate_rules"){
remove_duplicate_rule_values();
exit;
}
if($ARGV[0] eq "installer"){ if($ARGV[0] eq "installer"){
print "Running EQEmu Server installer routines...\n"; print "Running EQEmu Server installer routines...\n";
mkdir('logs'); mkdir('logs');
@ -152,6 +184,7 @@ if($ARGV[0] eq "installer"){
if($OS eq "Windows"){ if($OS eq "Windows"){
check_windows_firewall_rules(); check_windows_firewall_rules();
do_windows_login_server_setup();
} }
exit; exit;
} }
@ -251,6 +284,7 @@ sub show_menu_prompt {
11 => \&fetch_latest_windows_binaries, 11 => \&fetch_latest_windows_binaries,
12 => \&fetch_server_dlls, 12 => \&fetch_server_dlls,
13 => \&do_windows_login_server_setup, 13 => \&do_windows_login_server_setup,
14 => \&remove_duplicate_rule_values,
19 => \&do_bots_db_schema_drop, 19 => \&do_bots_db_schema_drop,
20 => \&do_update_self, 20 => \&do_update_self,
0 => \&script_exit, 0 => \&script_exit,
@ -328,6 +362,7 @@ return <<EO_MENU;
11) [Windows Server Build] :: Download Latest and Stable Server Build (Overwrites existing .exe's, includes .dll's) 11) [Windows Server Build] :: Download Latest and Stable Server Build (Overwrites existing .exe's, includes .dll's)
12) [Windows Server .dll's] :: Download Pre-Requisite Server .dll's 12) [Windows Server .dll's] :: Download Pre-Requisite Server .dll's
13) [Windows Server Loginserver Setup] :: Download and install Windows Loginserver 13) [Windows Server Loginserver Setup] :: Download and install Windows Loginserver
14) [Remove Duplicate Rule Values] :: Looks for redundant rule_values entries and removes them
19) [EQEmu DB Drop Bots Schema] :: Remove Bots schema and return database to normal state 19) [EQEmu DB Drop Bots Schema] :: Remove Bots schema and return database to normal state
20) [Update the updater] Force update this script (Redownload) 20) [Update the updater] Force update this script (Redownload)
0) Exit 0) Exit
@ -521,6 +556,33 @@ sub opcodes_fetch{
print "\nDone...\n\n"; print "\nDone...\n\n";
} }
sub remove_duplicate_rule_values{
$ruleset_id = trim(get_mysql_result("SELECT `ruleset_id` FROM `rule_sets` WHERE `name` = 'default'"));
print "Default Ruleset ID: " . $ruleset_id . "\n";
$total_removed = 0;
#::: Store Default values...
$mysql_result = get_mysql_result("SELECT * FROM `rule_values` WHERE `ruleset_id` = " . $ruleset_id);
my @lines = split("\n", $mysql_result);
foreach my $val (@lines){
my @values = split("\t", $val);
$rule_set_values{$values[1]}[0] = $values[2];
}
#::: Compare default values against other rulesets to check for duplicates...
$mysql_result = get_mysql_result("SELECT * FROM `rule_values` WHERE `ruleset_id` != " . $ruleset_id);
my @lines = split("\n", $mysql_result);
foreach my $val (@lines){
my @values = split("\t", $val);
if($values[2] == $rule_set_values{$values[1]}[0]){
print "DUPLICATE : " . $values[1] . " (Ruleset (" . $values[0] . ")) matches default value of : " . $values[2] . ", removing...\n";
get_mysql_result("DELETE FROM `rule_values` WHERE `ruleset_id` = " . $values[0] . " AND `rule_name` = '" . $values[1] . "'");
$total_removed++;
}
}
print "Total duplicate rules removed... " . $total_removed . "\n";
}
sub copy_file{ sub copy_file{
$l_source_file = $_[0]; $l_source_file = $_[0];
$l_dest_file = $_[1]; $l_dest_file = $_[1];
@ -1316,8 +1378,14 @@ sub run_database_check{
@total_updates = (); @total_updates = ();
#::: This is where we set checkpoints for where a database might be so we don't check so far back in the manifest...
$revision_check = 1000;
if(get_mysql_result("SHOW TABLES LIKE 'character_data'") ne ""){
$revision_check = 9000;
}
#::: Iterate through Manifest backwards from binary version down to local version... #::: Iterate through Manifest backwards from binary version down to local version...
for($i = $bin_db_ver; $i > 1000; $i--){ for($i = $bin_db_ver; $i > $revision_check; $i--){
if(!defined($m_d{$i}[0])){ next; } if(!defined($m_d{$i}[0])){ next; }
$file_name = trim($m_d{$i}[1]); $file_name = trim($m_d{$i}[1]);

View File

@ -0,0 +1,255 @@
#! /usr/bin/perl
########################################################################
#::: 13th floor import script
#::: Current Source: http://items.sodeq.org/download.php
#::: Authors: (Natedog, Akkadius)
########################################################################
use DBI;
use DBD::mysql;
my $database_name = "";
my $total_items = 0;
my $read_items_file = "items.txt"; #default
my $dbh = LoadMysql();
read_items_file_from_13th_floor_text();
update_items_table();
sub LoadMysql{
#::: Config Variables
my $confile = "eqemu_config.xml";
open(F, "<$confile") or die "Unable to open config: $confile\n";
my $indb = 0;
while(<F>) {
s/\r//g;
if(/<database>/i) { $indb = 1; }
next unless($indb == 1);
if(/<\/database>/i) { $indb = 0; last; }
if(/<host>(.*)<\/host>/i) { $host = $1; }
elsif(/<username>(.*)<\/username>/i) { $user = $1; }
elsif(/<password>(.*)<\/password>/i) { $pass = $1; }
elsif(/<db>(.*)<\/db>/i) { $db = $1; }
}
$database_name = $db;
#::: DATA SOURCE NAME
$dsn = "dbi:mysql:$db:localhost:3306";
#::: PERL DBI CONNECT
$connect = DBI->connect($dsn, $user, $pass);
return $connect;
}
sub read_items_file_from_13th_floor_text {
#::: Read from file and place into array
open(F, "<" . $read_items_file) or die "Unable to open itemfile: " . $read_items_file . "\n";
my @item_file_lines = <F>;
close(F);
#::: Chomp this array...
my @newitem_file_lines;
chomp($item_file_lines[0]);
@fields = split("(?<!\\\\)\\|", $item_file_lines[0]);
my $sth = $dbh->prepare("SHOW TABLES LIKE 'items_floor'");
$sth->execute();
my $has_items_floor = $sth->fetchrow_array();
#::: If we have items_floor
if ($has_items_floor eq '') {
$dbh->do("CREATE TABLE `items_floor` (`" . join("` VARCHAR(64) NOT NULL DEFAULT '', `", @fields). "` VARCHAR(64) NOT NULL DEFAULT '', UNIQUE INDEX `ID` (`id`)) COLLATE='latin1_swedish_ci' ENGINE=MyISAM");
$dbh->do("ALTER TABLE `items_floor` CHANGE `id` `id` INT(11) NOT NULL DEFAULT '0'");
printf "Database items_floor created\n";
}
#::: Create REPLACE INTO header and define worker variables...
$master_insert = "REPLACE INTO `items_floor` (" . join(",", @fields) . ") VALUES ";
$query_insert_ph = ""; #::: Used for building placeholder values in query Ex: (?, ?, ?)
@field_values = (); #::: Used for stuffing mysql field values
$query_count = 0; #::: Used for chunking query updates
$print_cycle = 0; #::: Counter for console updates
$start_time = time(); #::: Start time for import
$total_items_file = scalar(grep $_, @item_file_lines) - 1; #::: Total items in text file
#::: Iterate through each item in items.txt
for (1 .. $#item_file_lines) {
@f = split("(?<!\\\\)\\|", $item_file_lines[$_]);
#::: Build our individual prepared statement (?, ?) values in the insert_ph
#::: ?, ? placeholders will be resolved via @field_values in the execute
$query_insert_ph .= " (";
foreach (@f) {
push (@field_values, trim($_));
$query_insert_ph .= "?, ";
}
$query_insert_ph = substr($query_insert_ph, 0, -2);
$query_insert_ph .= "), ";
#::: Let's chunk our updates so we can break up the amount of individual queries
if($query_count > 500){
$query_insert_ph = substr($query_insert_ph, 0, -2);
$dbh->prepare($master_insert . " " . $query_insert_ph)->execute(@field_values);
$query_count = 0;
$query_insert_ph = "";
@field_values = ();
}
#::: Print updates to console
if($print_cycle > 25){
print "Processing (" . $read_items_file . ") :: (Items: " . $total_items . "/" . $total_items_file . ") \r";
$print_cycle = 0;
}
#::: Counters
$total_items++;
$query_count++;
$print_cycle++;
}
#::: One last processing print
print "Processing (" . $read_items_file . ") :: (Items: " . $total_items . "/" . $total_items_file . ") \r";
printf "\n" . $total_items . " items added to database... Took " . (time() - $start_time) . " second(s)... \n";
print "Flipping slots 21 and 22...";
$rows_affected = $dbh->prepare("
UPDATE `items_floor`
SET `slots` = (`slots` ^ 6291456)
WHERE (`slots` & 6291456)
IN (2097152, 4194304)")->execute();
print " Rows affected (" . $rows_affected . ")\n";
}
sub update_items_table {
#::: Keep Items table sane
$query_handle = $dbh->prepare("
ALTER TABLE `items`
MODIFY COLUMN `UNK132` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL;
");
$query_handle->execute();
my @matching_table;
my @missing_items_table;
my @missing_items_floor_table;
#::: Get columns from `items`
my $sth = $dbh->prepare("SHOW COLUMNS FROM `items`;");
$sth->execute();
my @items_table;
while (my @row = $sth->fetchrow_array()) {
push(@items_table, $row[0]);
}
#::: Get columns from `items_floor`
$sth2 = $dbh->prepare("SHOW COLUMNS FROM `items_floor`");
$sth2->execute();
my @items_floor_table;
while (my @row = $sth2->fetchrow_array()) {
push(@items_floor_table, $row[0]);
}
#::: Go through the original items table columns and line them up with what columns match on 13th floor
#::: This is so we can use the matching columns to update and insert item data into `items` table
foreach $value (@items_table) {
if ( grep( /^$value$/i, @items_floor_table ) ) {
push(@matching_table, $value);
} else {
#::: What values are we missing from EMU items table..
push(@missing_items_table, $value);
}
}
#::: What values are we missing from.. 13thFloor
foreach $value (@items_floor_table) {
if ( grep( /^$value$/i, @items_table ) ) {
#DO NOTHING...
} else {
push(@missing_items_floor_table, $value);
}
}
#::: Go through the matched columns and build our query strings...
my $items_field_list = ""; #::: Build the field list for the INSERT (field1, field2)
my $items_floor_field_list = ""; #::: What fields we will select from items_floor table to insert into items (matched columns)
my $update_fields = ""; #::: To update an existing item entry if it exists...
foreach $match (@matching_table) {
$match = lc($match);
$update_fields .= "`" . $match . "` = fi.`" . $match . "`, ";
$items_field_list .= "`" . $match . "`, ";
$items_floor_field_list .= "fi.`" . $match . "`, ";
}
#::: Trim ', ' off the ends
$update_fields = substr($update_fields, 0, -2);
$items_field_list = substr($items_field_list, 0, -2);
$items_floor_field_list = substr($items_floor_field_list, 0, -2);
#::: Mixed up fields...
$items_floor_field_list =~ s/booktype/booklang/g; #our booktype is mixed with theirs...
$update_fields =~ s/`booktype` = fi.`booktype`/`booktype` = fi.`booklang`/g;
#::: FIELDS THAT DO NOT MATCH GO HERE
my @items_add = (
"casttime_", "endur", "range", "attuneable", "evolvinglevel", "herosforgemodel", "scrolltype",
"scriptfileid", "powersourcecapacity", "augslot1unk2", "augslot2unk2", "augslot3unk2", "augslot4unk2",
"augslot5unk2", "augslot6unk2", "recskill", "book"
);
my @items_floor_add = (
"foodduration", "endurance", "therange", "attunable", "evolvl", "heroforge1", "scrolleffecttype",
"rightclickscriptid", "powersourcecap", "augslot1unk", "augslot2unk", "augslot3unk", "augslot4unk",
"augslot5unk", "augslot6unk", "reqskill", "booktype"
);
#::: Match the mis-matched fields...
my $spot = 0;
foreach $value (@items_add) {
$items_field_list .= ", `" . $value . "`";
$update_fields .= ", `" . $value . "` = fi.`" . $items_floor_add[$spot] . "`";
$spot++;
@missing_items_table = grep {$_ ne $value} @missing_items_table;
}
foreach $value (@items_floor_add) {
$items_floor_field_list .= ", fi.`" . $value . "`";
@missing_items_floor_table = grep {$_ ne $value} @missing_items_floor_table;
}
my $update_query = "
INSERT INTO items (" . $items_field_list . ")
SELECT " . $items_floor_field_list . "
FROM items_floor fi
ON DUPLICATE KEY UPDATE " . $update_fields;
#::: Print missing fields to file
my $write_file = "missing_item_fields.txt";
open(F, ">$write_file") or die "Unable to open questfile: $write_file\n";
print F "$update_query \n\n";
print F "EQEMU items Table missing fields\n";
foreach $value (@missing_items_table) {
print F "$value\n";
}
print F "\n\n13thFloor items Table missing fields\n";
foreach $value (@missing_items_floor_table) {
print F "$value\n";
}
close(F);
#::: Number of rows affected by query
$rows = $dbh->do($update_query);
#::: Update stackables
$dbh->do("UPDATE items i SET i.stackable = 1 WHERE i.stacksize > 1");
print "Added all new items to Items table (" . $rows . ")!\n";
}
sub trim($) {
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}

View File

@ -1,77 +0,0 @@
#! /usr/bin/perl
use DBI;
use Getopt::Std;
getopts('d:h');
$conf = "eqemu_config.xml";
if($opt_h) {
die "Usage: load_13thfloor_items.pl [-d path/to/eqemu_config.xml]\n";
}
if($opt_d) {
$conf = $opt_d;
}
$db = "eq";
$user = "eq";
$pass = "eq";
$host = "localhost";
open(F, "<$conf") or die "Unable to open config $conf\n";
$indb = 0;
while(<F>) {
s/\r//g;
if(/<database>/i) {
$indb = 1;
}
next unless($indb == 1);
if(/<\/database>/i) {
$indb = 0;
last;
}
if(/<host>(.*)<\/host>/i) {
$host = $1;
} elsif(/<username>(.*)<\/username>/i) {
$user = $1;
} elsif(/<password>(.*)<\/password>/i) {
$pass = $1;
} elsif(/<db>(.*)<\/db>/i) {
$db = $1;
}
}
if(!$db || !$user || !$pass || !$host) {
die "Invalid db.ini, missing one of: host, user, password, database\n";
}
$source="DBI:mysql:database=$db;host=$host";
my $dbh = DBI->connect($source, $user, $pass) || die "Could not create db handle\n";
$_=<STDIN>;
chomp();
s/'/\\'/g;
@fields=split("(?<!\\\\)\\|", $_);
%conversions = (
"itemtype" => "itemuse"
);
$insert="replace into items (".join(",",@fields).",source,updated) values ('";
$insert=~s/UNK130/potionbeltslots/;
$insert=~s/UNK133/stackable/;
#select(STDOUT); $|=1;
while(<STDIN>) {
chomp();
s/'/\\'/g;
@f=split("(?<!\\\\)\\|", $_);
$insert2=join("','",@f);
$#f--;
grep(s/\\\|/\\\\\|/g,@f);
grep(s/"/\\\\"/g,@f);
$statement=sprintf("%s%s','13THFLOOR',now())",$insert,$insert2,join('|',@f));
$dbh->do($statement);
printf("Processing: %d %s \r",$f[4],$f[1]);
++$count;
}
printf("Processed: %d items(s) \n",$count);

View File

@ -1,261 +1,261 @@
5001|1_task_system.sql 5001|1_task_system.sql|SHOW TABLES LIKE 'tasks'|empty|
# 5002|2_optional_maxclients.sql # 5002|2_optional_maxclients.sql
# 5003|14_optional_merchantlist.sql # 5003|14_optional_merchantlist.sql
5004|35_task_stepped.sql 5004|35_task_stepped.sql|SHOW COLUMNS FROM `tasks` LIKE 'stepped'|not_empty|
5005|42_task_min_maxlevel.sql 5005|42_task_min_maxlevel.sql|SHOW COLUMNS FROM `tasks` LIKE 'minlevel'|empty|
5006|55_zone_shutdowndeleay.sql 5006|55_zone_shutdowndeleay.sql|SHOW COLUMNS FROM `zone` LIKE 'shutdowndelay'|empty|
# 5007|68_optional_character_maxexplevel.sql # 5007|68_optional_character_maxexplevel.sql
# 5008|103_optional_chat_rules.sql # 5008|103_optional_chat_rules.sql
5009|104_traps.sql 5009|104_traps.sql|SHOW COLUMNS FROM `traps` LIKE 'respawn_time'|empty|
# 5010|106_optional_proc_rules.sql # 5010|106_optional_proc_rules.sql
5011|120_damageshieldtypes.sql 5011|120_damageshieldtypes.sql|SHOW TABLES LIKE 'damageshieldtypes'|empty|
5012|125_aggrozone.sql # 5012|125_aggrozone.sql
# 5013|127_optional_spell_rules.sql # 5013|127_optional_spell_rules.sql
# 5014|129_optional_shared_plat_rule.sql # 5014|129_optional_shared_plat_rule.sql
# 5015|131_optional_combat_rules.sql # 5015|131_optional_combat_rules.sql
5016|133_task_repeatable.sql 5016|133_task_repeatable.sql|SHOW COLUMNS FROM `tasks` LIKE 'repeatable'|empty|
5017|142_deathpeace_and_lifetap_aas.sql 5017|142_deathpeace_and_lifetap_aas.sql|SELECT * FROM db_version WHERE version > 5016|empty|
# 5018|158_optional_death_exp_loss.sql # 5018|158_optional_death_exp_loss.sql
5019|176_melody.sql # 5019|176_melody.sql
5020|189_character_.sql 5020|189_character_.sql|SELECT * FROM db_version WHERE version >= 5020|empty|
5021|196_trader.sql 5021|196_trader.sql|SHOW TABLES LIKE 'trader'|empty|
5022|210_undyeme.sql # 5022|210_undyeme.sql
5023|222_buyer.sql 5023|222_buyer.sql|SHOW TABLES LIKE 'buyer'|empty|
5024|226_account_limiting.sql # 5024|226_account_limiting.sql
5025|230_spells_table.sql 5025|230_spells_table.sql|SHOW TABLES LIKE 'spells_new'|empty|
5026|235_horses_table.sql 5026|235_horses_table.sql|SHOW TABLES LIKE 'horses'|empty|
5027|243_spawn_timers.sql 5027|243_spawn_timers.sql|SHOW TABLES LIKE 'respawn_times'|empty|
5028|247_mail.sql 5028|247_mail.sql|SHOW TABLES LIKE 'mail'|empty|
5029|249_chatchannels.sql 5029|249_chatchannels.sql|SHOW TABLES LIKE 'chatchannels'|empty|
5030|250_bot_spell_update.sql # 5030|250_bot_spell_update.sql
# 5031|250_optional_bot_spell_update.sql # 5031|250_optional_bot_spell_update.sql
# 5032|285_optional_bot_spell_update.sql # 5032|285_optional_bot_spell_update.sql
5033|292_augslots.sql # 5033|292_augslots.sql|SELECT * FROM db_version WHERE version >= 5033|empty|
5034|294_merchant_logging.sql 5034|294_merchant_logging.sql|SHOW COLUMNS FROM `eventlog` LIKE 'event_nid'|empty|
5035|304_faction_list.sql 5035|304_faction_list.sql|SELECT * FROM db_version WHERE version >= 5035|empty|
5036|326_aas.sql 5036|326_aas.sql|SELECT * FROM db_version WHERE version > 5035|empty|
5037|328_bot_management.sql # 5037|328_bot_management.sql
# 5038|328_optional_bot_management.sql # 5038|328_optional_bot_management.sql
5039|340_gm_ips.sql 5039|340_gm_ips.sql|SHOW TABLES LIKE 'gm_ips'|empty|
5040|356_combat.sql # 5040|356_combat.sql
5041|360_peqzone.sql # 5041|360_peqzone.sql
5042|364_ranged_dist_rule.sql # 5042|364_ranged_dist_rule.sql
5043|386_bot_save_raid.sql # 5043|386_bot_save_raid.sql
# 5044|434_optional_rest_state_rules.sql # 5044|434_optional_rest_state_rules.sql
5045|447_sof_startzone_rule.sql # 5045|447_sof_startzone_rule.sql
5046|463_altadv_vars.sql # 5046|463_altadv_vars.sql
5047|475_aa_actions.sql # 5047|475_aa_actions.sql
5048|500_spawn2_optimization.sql 5048|500_spawn2_optimization.sql|SELECT * FROM db_version WHERE version >= 5048|empty|
5049|503_bugs.sql 5049|503_bugs.sql|SHOW TABLES LIKE 'bugs'|empty|
5050|518_drakkin_npc_type_features.sql 5050|518_drakkin_npc_type_features.sql|SHOW TABLES LIKE 'bugs'|empty|
5051|524_rule_values_notes.sql 5051|524_rule_values_notes.sql|SELECT * FROM db_version WHERE version >= 5051|empty|
5052|527_npc_armor_tint.sql 5052|527_npc_armor_tint.sql|SELECT * FROM db_version WHERE version >= 5052|empty|
5053|553_saylink_table.sql 5053|553_saylink_table.sql|SHOW TABLES LIKE 'saylink'|empty|
5054|564_nokeyring.sql 5054|564_nokeyring.sql|SHOW COLUMNS FROM `doors` LIKE 'nokeyring'|empty|
5055|600_group_leadership.sql 5055|600_group_leadership.sql|SELECT * FROM db_version WHERE version >= 5055|empty|
5056|612_instance_changes.sql 5056|612_instance_changes.sql|SELECT * FROM db_version WHERE version >= 5056|empty|
5057|615_adventure_assassination.sql 5057|615_adventure_assassination.sql|SELECT * FROM db_version WHERE version >= 5057|empty|
5058|619_Adventure_Recruiter_Flavor.sql 5058|619_Adventure_Recruiter_Flavor.sql|SELECT * FROM db_version WHERE version >= 5058|empty|
5059|621_LDoNTraps.sql 5059|621_LDoNTraps.sql|SHOW TABLES LIKE 'ldon_trap_templates'|empty|
5060|633_ucs.sql 5060|633_ucs.sql|SHOW TABLES LIKE 'friends'|empty|
5061|634_TrapTemplateDefaultValue.sql 5061|634_TrapTemplateDefaultValue.sql|SHOW COLUMNS FROM `npc_types` LIKE 'trap_template'|empty|
5062|643_BotsTable.sql # 5062|643_BotsTable.sql
5063|646_archery_penalty_rule.sql # 5063|646_archery_penalty_rule.sql
5064|665_heroic_resists.sql 5064|665_heroic_resists.sql|SELECT * FROM db_version WHERE version >= 5064|empty|
5065|667_titles.sql 5065|667_titles.sql|SHOW TABLES LIKE 'titles'|empty|
5066|687_aa_table_changes.sql 5066|687_aa_table_changes.sql|SELECT * FROM db_version WHERE version >= 5066|empty|
5067|699_peqzone_rule.sql # 5067|699_peqzone_rule.sql
5068|702_aashieldblock_tint_table.sql 5068|702_aashieldblock_tint_table.sql|SHOW TABLES LIKE 'npc_types_tint'|empty|
5069|703_peqzone_rule.sql # 5069|703_peqzone_rule.sql
5070|704_rules.sql # 5070|704_rules.sql
5071|710_tint_set_naming.sql 5071|710_tint_set_naming.sql|SELECT * FROM db_version WHERE version >= 5071|empty|
5072|721_pathing_rules.sql 5072|721_pathing_rules.sql|SELECT * FROM db_version WHERE version >= 5072|empty|
5073|730_smart_delay_moving.sql # 5073|730_smart_delay_moving.sql
5074|731_rule_assist_notarget_self.sql # 5074|731_rule_assist_notarget_self.sql
5075|732_sacrifice_rules.sql # 5075|732_sacrifice_rules.sql
5076|745_slow_mitigation.sql 5076|745_slow_mitigation.sql|SELECT * FROM db_version WHERE version >= 5076|empty|
5077|754_archery_base_damage_rule.sql # 5077|754_archery_base_damage_rule.sql
5078|755_sof_altadv_vars_updates.sql 5078|755_sof_altadv_vars_updates.sql|SELECT * FROM db_version WHERE version >= 5078|empty|
5079|773_monk_rules.sql # 5079|773_monk_rules.sql
# 5080|853_optional_rule_aaexp.sql # 5080|853_optional_rule_aaexp.sql
# 5081|858_optional_rule_ip_limit_by_status.sql # 5081|858_optional_rule_ip_limit_by_status.sql
# 5082|892_optional_bots_table_mod.sql # 5082|892_optional_bots_table_mod.sql
# 5083|893_optional_bots_table_mod.sql # 5083|893_optional_bots_table_mod.sql
5084|898_npc_maxlevel_scalerate.sql 5084|898_npc_maxlevel_scalerate.sql|SHOW COLUMNS FROM `npc_types` LIKE 'maxlevel'|empty|
# 5085|902_optional_rule_snareflee.sql # 5085|902_optional_rule_snareflee.sql
5086|923_spawn2_enabled.sql 5086|923_spawn2_enabled.sql|SHOW COLUMNS FROM `spawn2` LIKE 'enabled'|empty|
5087|962_hot_zone.sql 5087|962_hot_zone.sql|SHOW COLUMNS FROM `zone` LIKE 'hotzone'|empty|
5088|964_reports.sql 5088|964_reports.sql|SHOW TABLES LIKE 'reports'|empty|
5089|971_veteran_rewards.sql 5089|971_veteran_rewards.sql|SHOW TABLES LIKE 'veteran_reward_templates'|empty|
5090|977_raid_npc_private_corpses.sql 5090|977_raid_npc_private_corpses.sql|SELECT * FROM db_version WHERE version >= 5090|empty|
5091|979_unique_spawn_by_name.sql 5091|979_unique_spawn_by_name.sql|SHOW COLUMNS FROM `npc_types` LIKE 'unique_spawn_by_name'|empty|
5092|980_account_ip.sql 5092|980_account_ip.sql|SHOW TABLES LIKE 'account_ip'|empty|
5093|1022_botadventuring.sql # 5093|1022_botadventuring.sql
5094|1027_botactives.sql # 5094|1027_botactives.sql
5095|1030_botzoningsupport.sql # 5095|1030_botzoningsupport.sql
5096|1036_botbuffs.sql # 5096|1036_botbuffs.sql
5097|1038_botpetstatepersists.sql # 5097|1038_botpetstatepersists.sql
5098|1038_grouptablesuniquecolumndefinitions.sql 5098|1038_grouptablesuniquecolumndefinitions.sql|SELECT * FROM db_version WHERE version >= 5098|empty|
5099|1039_botguilds.sql # 5099|1039_botguilds.sql
5100|1040_DeprecatedBotRaidsSystems.sql # 5100|1040_DeprecatedBotRaidsSystems.sql
5101|1057_titles.sql 5101|1057_titles.sql|SHOW TABLES LIKE 'player_titlesets'|empty|
5102|1077_botgroups.sql # 5102|1077_botgroups.sql
5103|1136_spell_globals.sql 5103|1136_spell_globals.sql|SHOW TABLES LIKE 'spell_globals'|empty|
# 5104|1144_optional_rule_return_nodrop.sql # 5104|1144_optional_rule_return_nodrop.sql
5105|1195_account_suspendeduntil.sql 5105|1195_account_suspendeduntil.sql|SELECT * FROM db_version WHERE version >= 5105|empty|
5106|1259_npc_skill_types.sql 5106|1259_npc_skill_types.sql|SHOW COLUMNS FROM `npc_types` LIKE 'prim_melee_type'|empty|
5107|1280_bot_augs.sql # 5107|1280_bot_augs.sql
# 5108|1290_optional_exp_loss_rule.sql # 5108|1290_optional_exp_loss_rule.sql
5109|1293_guild_bank.sql 5109|1293_guild_bank.sql|SHOW TABLES LIKE 'guild_bank'|empty|
5110|1379_loginserver_trusted_server.sql # 5110|1379_loginserver_trusted_server.sql
5111|1392_recipe_learning.sql 5111|1392_recipe_learning.sql|SELECT * FROM db_version WHERE version >= 5111|empty|
# 5112|1394_optional_rule_sod_hp_mana_end.sql # 5112|1394_optional_rule_sod_hp_mana_end.sql
5113|1404_faction_list.sql 5113|1404_faction_list.sql|SELECT * FROM db_version WHERE version >= 5113|empty|
# 5114|1410_optional_sod_aas_ht_and_loh.sql # 5114|1410_optional_sod_aas_ht_and_loh.sql
5115|1436_login_server_table_fix.sql # 5115|1436_login_server_table_fix.sql
5116|1446_allowrest_optional.sql # 5116|1446_allowrest_optional.sql
5117|1446_allowrest_required.sql 5117|1446_allowrest_required.sql|SELECT * FROM db_version WHERE version >= 5117|empty|
5118|1450_cvs.sql # 5118|1450_cvs.sql
5119|1451_guilds.sql 5119|1451_guilds.sql|SELECT * FROM db_version WHERE version >= 5119|empty|
5120|1498_instance_adventure.sql 5120|1498_instance_adventure.sql|SELECT * FROM db_version WHERE version >= 5120|empty|
5121|1510_global_instances.sql 5121|1510_global_instances.sql|SELECT * FROM db_version WHERE version >= 5121|empty|
5122|1511_map_path_loading.sql 5122|1511_map_path_loading.sql|SHOW COLUMNS FROM `zone` LIKE 'map_file_name'|empty|
5123|1513_zone_points.sql 5123|1513_zone_points.sql|SELECT * FROM db_version WHERE version >= 5123|empty|
5124|1519_zone_primary_key_id.sql 5124|1519_zone_primary_key_id.sql|SELECT * FROM db_version WHERE version >= 5124|empty|
5125|1542_items_table_cleanup.sql 5125|1542_items_table_cleanup.sql|SELECT * FROM db_version WHERE version >= 5125|empty|
5126|1548_nimbuseffect_required.sql 5126|1548_nimbuseffect_required.sql|SELECT * FROM db_version WHERE version >= 5126|empty|
5127|1562_instanced_spawnconditions.sql 5127|1562_instanced_spawnconditions.sql|SHOW TABLES LIKE 'spawn_condition_values'|empty|
5128|1586_waypoints_optional.sql # 5128|1586_waypoints_optional.sql
5129|1610_tradeskill_required.sql 5129|1610_tradeskill_required.sql|SELECT * FROM db_version WHERE version >= 5129|empty|
5130|1618_zone.sql 5130|1618_zone.sql|SELECT * FROM db_version WHERE version >= 5130|empty|
# 5131|1625_optional_rule_class_race_exp_bonus.sql # 5131|1625_optional_rule_class_race_exp_bonus.sql
# 5132|1672_optional_rules_respawn_window.sql # 5132|1672_optional_rules_respawn_window.sql
# 5133|1679_optional_rules_blocked_buffs.sql # 5133|1679_optional_rules_blocked_buffs.sql
5134|1696_modify_zone_and_object_tables.sql 5134|1696_modify_zone_and_object_tables.sql|SELECT * FROM db_version WHERE version >= 5134|empty|
5135|1711_account_restricted_aa.sql 5135|1711_account_restricted_aa.sql|SHOW COLUMNS FROM `account` LIKE 'time_creation'|empty|
# 5136|1717_optional_rule_bash_stun_chance.sql # 5136|1717_optional_rule_bash_stun_chance.sql
# 5137|1718_optional_rules_mod3s.sql # 5137|1718_optional_rules_mod3s.sql
# 5138|1719_optional_triggerOnCastAAs.sql # 5138|1719_optional_triggerOnCastAAs.sql
# 5139|1720_optional_sql_AAs.sql # 5139|1720_optional_sql_AAs.sql
5140|1720_required_sql_AA_effects_update.sql # 5140|1720_required_sql_AA_effects_update.sql
# 5141|1721_optional_sql_drakkin_breath_update.sql # 5141|1721_optional_sql_drakkin_breath_update.sql
5142|1721_required_sql_altadv_vars_update.sql # 5142|1721_required_sql_altadv_vars_update.sql
# 5143|1723_optional_sql_new_stats_window_rule.sql # 5143|1723_optional_sql_new_stats_window_rule.sql
5144|1723_required_sql_corruption.sql 5144|1723_required_sql_corruption.sql|SELECT * FROM db_version WHERE version >= 5144|empty|
# 5145|1736_optional_sql_feral_swipe.sql # 5145|1736_optional_sql_feral_swipe.sql
5146|1737_required_sql_rule_and_aa_update.sql # 5146|1737_required_sql_rule_and_aa_update.sql
# 5147|1746_optional_sql_bot_manaregen.sql # 5147|1746_optional_sql_bot_manaregen.sql
# 5148|1747_optional_HoT_zone_and_zonepoints.sql # 5148|1747_optional_HoT_zone_and_zonepoints.sql
# 5149|1750_optional_sql_reflect_rule.sql # 5149|1750_optional_sql_reflect_rule.sql
# 5150|1753_optional_haste_cap_rule.sql # 5150|1753_optional_haste_cap_rule.sql
5151|1753_required_sql_healing_adept_aa.sql # 5151|1753_required_sql_healing_adept_aa.sql
5152|1754_required_sql_healing_adept_aa_fix.sql # 5152|1754_required_sql_healing_adept_aa_fix.sql
5153|1755_required_sql_fear_resist_aas.sql # 5153|1755_required_sql_fear_resist_aas.sql
# 5154|1784_optional_corpsedrag_rules.sql # 5154|1784_optional_corpsedrag_rules.sql
5155|1786_required_update_to_aas.sql # 5155|1786_required_update_to_aas.sql
5156|1790_required_aa_required_level_cost.sql # 5156|1790_required_aa_required_level_cost.sql
5157|1793_resist_adjust.sql 5157|1793_resist_adjust.sql|SHOW COLUMNS FROM `npc_spells_entries` LIKE 'resist_adjust'|empty|
# 5158|1799_optional_rest_regen_endurance_rule.sql # 5158|1799_optional_rest_regen_endurance_rule.sql
5159|1802_required_doppelganger.sql 5159|1802_required_doppelganger.sql|SELECT * FROM db_version WHERE version >= 5159|empty|
5160|1803_required_tasks_xpreward_signed.sql 5160|1803_required_tasks_xpreward_signed.sql|SELECT * FROM db_version WHERE version >= 5160|empty|
5161|1804_required_ae_melee_updates.sql 5161|1804_required_ae_melee_updates.sql|SELECT * FROM db_version WHERE version >= 5161|empty|
# 5162|1809_optional_rules.sql # 5162|1809_optional_rules.sql
5163|1813_required_doppelganger_npcid_change.sql 5163|1813_required_doppelganger_npcid_change.sql|SELECT * FROM db_version WHERE version >= 5163|empty|
# 5164|1817_optional_npc_archery_bonus_rule.sql # 5164|1817_optional_npc_archery_bonus_rule.sql
# 5165|1823_optional_delay_death.sql # 5165|1823_optional_delay_death.sql
5166|1847_required_doors_dest_zone_size_32.sql 5166|1847_required_doors_dest_zone_size_32.sql|SELECT * FROM db_version WHERE version >= 5166|empty|
# 5167|1859_optional_item_casts_use_focus_rule.sql # 5167|1859_optional_item_casts_use_focus_rule.sql
# 5168|1884_optional_bot_spells_update.sql # 5168|1884_optional_bot_spells_update.sql
# 5169|1885_optional_rules_fv_pvp_expansions.sql # 5169|1885_optional_rules_fv_pvp_expansions.sql
# 5170|1889_optional_skill_cap_rule.sql # 5170|1889_optional_skill_cap_rule.sql
5171|1908_required_npc_types_definitions.sql 5171|1908_required_npc_types_definitions.sql|SHOW COLUMNS FROM `npc_types` LIKE 'attack_count'|empty|
# 5172|1926_optional_stat_cap.sql # 5172|1926_optional_stat_cap.sql
5173|1944_spawn2.sql 5173|1944_spawn2.sql|SHOW COLUMNS FROM `spawn2` LIKE 'animation'|empty|
5174|1946_doors.sql 5174|1946_doors.sql|SELECT * FROM db_version WHERE version >= 5166|empty|
# 5175|1960_optional_console_timeout_rule.sql # 5175|1960_optional_console_timeout_rule.sql
# 5176|1962_optional_guild_creation_window_rules.sql # 5176|1962_optional_guild_creation_window_rules.sql
# 5177|1963_optional_rule_live_like_focuses.sql # 5177|1963_optional_rule_live_like_focuses.sql
# 5178|1968_optional_enrage_rules.sql # 5178|1968_optional_enrage_rules.sql
# 5179|1972_optional_extradmg_item_cap.sql # 5179|1972_optional_extradmg_item_cap.sql
5180|1974_required_bot_spells_update.sql # 5180|1974_required_bot_spells_update.sql
5181|1977_underwater.sql 5181|1977_underwater.sql|SHOW COLUMNS FROM `npc_types` LIKE 'underwater'|empty|
# 5182|1998_optional_intoxication_and_looting_rules.sql # 5182|1998_optional_intoxication_and_looting_rules.sql
5183|2004_charges_alt_currency.sql 5183|2004_charges_alt_currency.sql|SHOW TABLES LIKE 'alternate_currency'|empty|
# 5184|2015_optional_specialization_training_rule.sql # 5184|2015_optional_specialization_training_rule.sql
# 5185|2016_optional_rule_bot_aa_expansion.sql # 5185|2016_optional_rule_bot_aa_expansion.sql
# 5186|2023_optional_mysqlcli.sql # 5186|2023_optional_mysqlcli.sql
# 5187|2024_optional_update_crystals.sql # 5187|2024_optional_update_crystals.sql
5188|2024_required_update.sql 5188|2024_required_update.sql|SHOW TABLES LIKE 'char_create_combinations'|empty|
5189|2057_required_discovered_items.sql 5189|2057_required_discovered_items.sql|SHOW TABLES LIKE 'discovered_items'|empty|
# 5190|2058_optional_rule_discovered_items.sql # 5190|2058_optional_rule_discovered_items.sql
5191|2062_required_version_changes.sql 5191|2062_required_version_changes.sql|SELECT * FROM db_version WHERE version >= 5191|empty|
5192|2069_required_pets.sql 5192|2069_required_pets.sql|SHOW TABLES LIKE 'pets_equipmentset'|empty|
5193|2079_player_speech.sql # 5193|2079_player_speech.sql
5194|2087_required_bots_hp_and_mana_and_spell_updates.sql # 5194|2087_required_bots_hp_and_mana_and_spell_updates.sql
5195|2098_required_zonepoint_version_changes.sql 5195|2098_required_zonepoint_version_changes.sql|SELECT * FROM db_version WHERE version >= 5195|empty|
5196|2099_required_discovered_items_account_status.sql 5196|2099_required_discovered_items_account_status.sql|SELECT * FROM db_version WHERE version >= 5196|empty|
5197|2104_required_group_roles.sql 5197|2104_required_group_roles.sql|SELECT * FROM db_version WHERE version >= 5197|empty|
5198|2107_required_bot_stances.sql # 5198|2107_required_bot_stances.sql
5199|2129_required_lfguild.sql 5199|2129_required_lfguild.sql|SHOW TABLES LIKE 'lfguild'|empty|
5200|2133_required_faction_loot_despawn.sql 5200|2133_required_faction_loot_despawn.sql|SELECT * FROM db_version WHERE version >= 5200|empty|
5201|2136_extended_targets.sql 5201|2136_extended_targets.sql|SELECT * FROM db_version WHERE version >= 5201|empty|
5202|2142_emotes.sql 5202|2142_emotes.sql|SELECT * FROM db_version WHERE version >= 5202|empty|
# 5203|2154_optional_rule_spell_procs_resists_falloff.sql # 5203|2154_optional_rule_spell_procs_resists_falloff.sql
# 5204|2156_optional_charm_break_rule.sql # 5204|2156_optional_charm_break_rule.sql
# 5205|2159_optional_defensiveproc_rules.sql # 5205|2159_optional_defensiveproc_rules.sql
5206|2164_require_bots_bottimers.sql # 5206|2164_require_bots_bottimers.sql
# 5207|2171_optional_SpecialAttackACBonus_rule.sql # 5207|2171_optional_SpecialAttackACBonus_rule.sql
# 5208|2176_optional_aa_expansion_SOF_fix.sql # 5208|2176_optional_aa_expansion_SOF_fix.sql
# 5209|2176_optional_FrenzyBonus_rule.sql # 5209|2176_optional_FrenzyBonus_rule.sql
5210|2176_required_aa_updates.sql 5210|2176_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5210|empty|
5211|2178_required_aa_updates.sql 5211|2178_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5211|empty|
# 5212|2183_optional_bot_xp_rule.sql # 5212|2183_optional_bot_xp_rule.sql
# 5213|2185_optional_NPCFlurryChacne_rule # 5213|2185_optional_NPCFlurryChacne_rule
# 5214|2185_optional_NPCFlurryChacne_rule.sql # 5214|2185_optional_NPCFlurryChacne_rule.sql
# 5215|2185_optional_NPCFlurryChance_rule.sql # 5215|2185_optional_NPCFlurryChance_rule.sql
5216|2185_required_aa_updates 5216|2185_required_aa_updates|SELECT * FROM db_version WHERE version >= 5216|empty|
5217|2185_required_aa_updates.sql 5217|2185_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5217|empty|
# 5218|2188_optional_miscspelleffect_rules # 5218|2188_optional_miscspelleffect_rules
# 5219|2188_optional_miscspelleffect_rules.sql # 5219|2188_optional_miscspelleffect_rules.sql
5220|2188_required_aa_updates # 5220|2188_required_aa_updates
5221|2188_required_aa_updates.sql 5221|2188_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5221|empty|
# 5222|2189_optional_taunt_rules # 5222|2189_optional_taunt_rules
# 5223|2189_optional_taunt_rules.sql # 5223|2189_optional_taunt_rules.sql
5224|2195_required_sharedplatupdates.sql 5224|2195_required_sharedplatupdates.sql|SELECT * FROM db_version WHERE version >= 5224|empty|
# 5225|2208_optional_aa_stacking_rule.sql # 5225|2208_optional_aa_stacking_rule.sql
# 5226|2208_optional_EnableSoulAbrasionAA.sql # 5226|2208_optional_EnableSoulAbrasionAA.sql
5227|2208_required_aa_updates.sql 5227|2208_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5227|empty|
# 5228|2209_optional_additive_bonus_rule.sql # 5228|2209_optional_additive_bonus_rule.sql
5229|2213_loot_changes.sql 5229|2213_loot_changes.sql|SELECT * FROM db_version WHERE version >= 5229|empty|
5230|2214_faction_list_mod.sql 5230|2214_faction_list_mod.sql|SHOW TABLES LIKE 'faction_list_mod'|empty|
5231|2215_required_aa_updates.sql 5231|2215_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5231|empty|
# 5232|2243_optional_char_max_level_rule.sql # 5232|2243_optional_char_max_level_rule.sql
5233|2260_probability.sql # 5233|2260_probability.sql
5234|2262_required_pet_discipline_update.sql 5234|2262_required_pet_discipline_update.sql|SELECT * FROM db_version WHERE version >= 5234|empty|
5235|2264_required_aa_updates.sql 5235|2264_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5235|empty|
5236|2268_QueryServ.sql # 5236|2268_QueryServ.sql
5237|2268_required_updates.sql 5237|2268_required_updates.sql|SELECT * FROM db_version WHERE version >= 5237|empty|
# 5238|2274_optional_rule_iplimitdisconnectall.sql # 5238|2274_optional_rule_iplimitdisconnectall.sql
# 5239|2278_optional_rule_targetableswarmpet.sql # 5239|2278_optional_rule_targetableswarmpet.sql
# 5240|2280_optional_rule_targetableswarmpet-rename.sql # 5240|2280_optional_rule_targetableswarmpet-rename.sql
5241|2283_required_npc_changes.sql 5241|2283_required_npc_changes.sql|SHOW COLUMNS FROM `npc_types` LIKE 'spellscale'|empty|
5242|2299_required_inspectmessage_fields.sql 5242|2299_required_inspectmessage_fields.sql|SELECT * FROM db_version WHERE version >= 5242|empty|
# 5243|2300_optional_loot_changes.sql # 5243|2300_optional_loot_changes.sql
5244|2304_QueryServ.sql # 5244|2304_QueryServ.sql
5245|2340_required_maxbuffslotspet.sql # 5245|2340_required_maxbuffslotspet.sql
5246|2361_QueryServ.sql # 5246|2361_QueryServ.sql
5247|2361_required_qs_rule_values.sql # 5247|2361_required_qs_rule_values.sql
5248|2370_required_aa_updates.sql 5248|2370_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5248|empty|
5249|2376_required_aa_updates.sql 5249|2376_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5249|empty|
# 5250|2380_optional_merc_data.sql 5250|2380_optional_merc_data.sql|SELECT * FROM db_version WHERE version >= 5250|empty|
# 5251|2380_optional_merc_merchant_npctypes_update.sql 5251|2380_optional_merc_merchant_npctypes_update.sql|SELECT * FROM db_version WHERE version >= 5251|empty|
# 5252|2380_optional_merc_rules.sql 5252|2380_optional_merc_rules.sql|SELECT * FROM db_version WHERE version >= 5252|empty|
5253|2383_required_group_ismerc.sql 5253|2383_required_group_ismerc.sql|SELECT * FROM db_version WHERE version >= 5253|empty|
# 5254|2428_optional_levelbasedexpmods.sql # 5254|2428_optional_levelbasedexpmods.sql
# 5255|2448_optional_stun_proc_aggro_rule.sql # 5255|2448_optional_stun_proc_aggro_rule.sql
5256|2471_required_aa_updates.sql 5256|2471_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5256|empty|
5257|2482_required_start_zones.sql 5257|2482_required_start_zones.sql|SELECT * FROM db_version WHERE version >= 5257|empty|
5258|2504_required_aa_updates.sql 5258|2504_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5258|empty|
8000|mercs.sql|SHOW TABLES LIKE 'merc_stats'|empty| 8000|mercs.sql|SHOW TABLES LIKE 'merc_stats'|empty|
9000|2013_02_18_Merc_Rules_and_Tables.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Mercs:ResurrectRadius%'|empty| 9000|2013_02_18_Merc_Rules_and_Tables.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Mercs:ResurrectRadius%'|empty|
9001|2013_02_25_Impr_HT_LT.sql|SHOW TABLES LIKE 'merc_inventory'|empty| 9001|2013_02_25_Impr_HT_LT.sql|SHOW TABLES LIKE 'merc_inventory'|empty|
@ -345,6 +345,9 @@
9089|2015_11_02_ai_idle_no_spell_recast_default_changes.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Spells:AI_IdleNoSpellMinRecast%' AND `rule_value` = '500'|not_empty| 9089|2015_11_02_ai_idle_no_spell_recast_default_changes.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Spells:AI_IdleNoSpellMinRecast%' AND `rule_value` = '500'|not_empty|
9090|2015_12_01_spell_scribe_restriction_rule.sql|SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Character:RestrictSpellScribing'|empty| 9090|2015_12_01_spell_scribe_restriction_rule.sql|SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Character:RestrictSpellScribing'|empty|
9091|2015_12_07_command_settings.sql|SHOW TABLES LIKE 'command_settings'|empty| 9091|2015_12_07_command_settings.sql|SHOW TABLES LIKE 'command_settings'|empty|
9092|2015_12_17_eqtime.sql|SHOW TABLES LIKE 'eqtime'|empty|
9093|2015_12_21_items_updates_evoitem.sql|SHOW COLUMNS FROM `items` LIKE 'evoitem'|empty|
9094|2015_12_29_quest_zone_events.sql|SELECT * FROM perl_event_export_settings WHERE event_description = 'EVENT_SPAWN_ZONE'|empty|
# Upgrade conditions: # Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not # This won't be needed after this system is implemented, but it is used database that are not

View File

@ -0,0 +1,3 @@
INSERT INTO `aa_ranks` (`id`, `upper_hotkey_sid`, `lower_hotkey_sid`, `title_sid`, `desc_sid`, `cost`, `level_req`, `spell`, `spell_type`, `recast_time`, `expansion`, `prev_id`, `next_id`) VALUES (1015, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1014, 1016);
INSERT INTO `aa_rank_effects` (`rank_id`, `slot`, `effect_id`, `base1`, `base2`) VALUES (1015, 1, 262, 40, 7), (1015, 2, 262, 40, 8), (1015, 3, 262, 40, 9), (1015, 4, 262, 40, 10), (1015, 5, 262, 40, 11);

View File

@ -0,0 +1,11 @@
DROP TABLE IF EXISTS `eqtime`;
CREATE TABLE `eqtime` (
`minute` tinyint(4) not null default 0,
`hour` tinyint(4) not null default 0,
`day` tinyint(4) not null default 0,
`month` tinyint(4) not null default 0,
`year` int(4) not null default 0,
`realtime` int(11) not null default 0
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO eqtime values (0,1,28,12,3766,1444035661);

View File

@ -0,0 +1,8 @@
ALTER TABLE `items`
ADD COLUMN `evoitem` INT(11) NOT NULL DEFAULT '0' AFTER `purity`,
ADD COLUMN `evoid` INT(11) NOT NULL DEFAULT '0' AFTER `evoitem`,
ADD COLUMN `evomax` INT(11) NOT NULL DEFAULT '0' AFTER `evolvinglevel`,
CHANGE `UNK038` `skillmodmax` INT(11) NOT NULL DEFAULT '0',
CHANGE `UNK222` `heirloom` INT(11) NOT NULL DEFAULT '0',
CHANGE `UNK235` `placeable` INT(11) NOT NULL DEFAULT '0',
CHANGE `UNK242` `epicitem` INT(11) NOT NULL DEFAULT '0';

View File

@ -0,0 +1,4 @@
INSERT INTO `perl_event_export_settings` (`event_id`, `event_description`, `export_qglobals`, `export_mob`, `export_zone`, `export_item`, `export_event`) VALUES (81, 'EVENT_SPAWN_ZONE', 0, 0, 0, 0, 1);
INSERT INTO `perl_event_export_settings` (`event_id`, `event_description`, `export_qglobals`, `export_mob`, `export_zone`, `export_item`, `export_event`) VALUES (82, 'EVENT_DEATH_ZONE', 0, 0, 0, 0, 1);
ALTER TABLE `rule_values`
MODIFY COLUMN `notes` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL AFTER `rule_value`;

View File

@ -2532,6 +2532,7 @@ INSERT INTO `aa_ranks` (`id`, `upper_hotkey_sid`, `lower_hotkey_sid`, `title_sid
(1012, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1011, 1013), (1012, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1011, 1013),
(1013, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1012, 1014), (1013, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1012, 1014),
(1014, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1013, 1015), (1014, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1013, 1015),
(1015, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1014, 1016),
(1016, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1015, -1), (1016, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1015, -1),
(1017, 1017, 1017, 1017, 1017, 6, 59, 16531, 75, 15, 15, -1, 13726), (1017, 1017, 1017, 1017, 1017, 6, 59, 16531, 75, 15, 15, -1, 13726),
(1018, 1018, 1018, 1018, 1018, 2, 63, 16455, 69, 1, 15, -1, -1), (1018, 1018, 1018, 1018, 1018, 2, 63, 16455, 69, 1, 15, -1, -1),
@ -9526,6 +9527,11 @@ INSERT INTO `aa_rank_effects` (`rank_id`, `slot`, `effect_id`, `base1`, `base2`)
(1014, 3, 262, 32, 9), (1014, 3, 262, 32, 9),
(1014, 4, 262, 32, 10), (1014, 4, 262, 32, 10),
(1014, 5, 262, 32, 11), (1014, 5, 262, 32, 11),
(1015, 1, 262, 40, 7),
(1015, 2, 262, 40, 8),
(1015, 3, 262, 40, 9),
(1015, 4, 262, 40, 10),
(1015, 5, 262, 40, 11),
(1016, 1, 262, 50, 7), (1016, 1, 262, 50, 7),
(1016, 2, 262, 50, 8), (1016, 2, 262, 50, 8),
(1016, 3, 262, 50, 9), (1016, 3, 262, 50, 9),

View File

@ -345,8 +345,13 @@ int main(int argc, char** argv) {
database.ClearMerchantTemp(); database.ClearMerchantTemp();
} }
Log.Out(Logs::General, Logs::World_Server, "Loading EQ time of day.."); Log.Out(Logs::General, Logs::World_Server, "Loading EQ time of day..");
if (!zoneserver_list.worldclock.loadFile(Config->EQTimeFile.c_str())) TimeOfDay_Struct eqTime;
Log.Out(Logs::General, Logs::World_Server, "Unable to load %s", Config->EQTimeFile.c_str()); time_t realtime;
eqTime = database.LoadTime(realtime);
zoneserver_list.worldclock.SetCurrentEQTimeOfDay(eqTime, realtime);
Timer EQTimeTimer(600000);
EQTimeTimer.Start(600000);
Log.Out(Logs::General, Logs::World_Server, "Loading launcher list.."); Log.Out(Logs::General, Logs::World_Server, "Loading launcher list..");
launcher_list.LoadList(); launcher_list.LoadList();
@ -470,6 +475,16 @@ int main(int argc, char** argv) {
database.PurgeExpiredInstances(); database.PurgeExpiredInstances();
} }
if (EQTimeTimer.Check())
{
TimeOfDay_Struct tod;
zoneserver_list.worldclock.GetCurrentEQTimeOfDay(time(0), &tod);
if (!database.SaveTime(tod.minute, tod.hour, tod.day, tod.month, tod.year))
Log.Out(Logs::General, Logs::World_Server, "Failed to save eqtime.");
else
Log.Out(Logs::Detail, Logs::World_Server, "EQTime successfully saved.");
}
//check for timeouts in other threads //check for timeouts in other threads
timeout_manager.CheckTimeouts(); timeout_manager.CheckTimeouts();
loginserverlist.Process(); loginserverlist.Process();
@ -519,8 +534,6 @@ int main(int argc, char** argv) {
void CatchSignal(int sig_num) { void CatchSignal(int sig_num) {
Log.Out(Logs::General, Logs::World_Server,"Caught signal %d",sig_num); Log.Out(Logs::General, Logs::World_Server,"Caught signal %d",sig_num);
if(zoneserver_list.worldclock.saveFile(WorldConfig::get()->EQTimeFile.c_str())==false)
Log.Out(Logs::General, Logs::World_Server,"Failed to save time file.");
RunLoops = false; RunLoops = false;
} }

View File

@ -989,8 +989,8 @@ bool ZoneServer::Process() {
Log.Out(Logs::Detail, Logs::World_Server,"Received SetWorldTime"); Log.Out(Logs::Detail, Logs::World_Server,"Received SetWorldTime");
eqTimeOfDay* newtime = (eqTimeOfDay*) pack->pBuffer; eqTimeOfDay* newtime = (eqTimeOfDay*) pack->pBuffer;
zoneserver_list.worldclock.SetCurrentEQTimeOfDay(newtime->start_eqtime, newtime->start_realtime); zoneserver_list.worldclock.SetCurrentEQTimeOfDay(newtime->start_eqtime, newtime->start_realtime);
Log.Out(Logs::Detail, Logs::World_Server,"New time = %d-%d-%d %d:%d (%d)\n", newtime->start_eqtime.year, newtime->start_eqtime.month, (int)newtime->start_eqtime.day, (int)newtime->start_eqtime.hour, (int)newtime->start_eqtime.minute, (int)newtime->start_realtime); Log.Out(Logs::Detail, Logs::World_Server, "New time = %d-%d-%d %d:%d (%d)\n", newtime->start_eqtime.year, newtime->start_eqtime.month, (int)newtime->start_eqtime.day, (int)newtime->start_eqtime.hour, (int)newtime->start_eqtime.minute, (int)newtime->start_realtime);
zoneserver_list.worldclock.saveFile(WorldConfig::get()->EQTimeFile.c_str()); database.SaveTime((int)newtime->start_eqtime.minute, (int)newtime->start_eqtime.hour, (int)newtime->start_eqtime.day, newtime->start_eqtime.month, newtime->start_eqtime.year);
zoneserver_list.SendTimeSync(); zoneserver_list.SendTimeSync();
break; break;
} }

View File

@ -431,11 +431,20 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) {
if (sender->GetPrimaryFaction() == 0 ) if (sender->GetPrimaryFaction() == 0 )
return; // well, if we dont have a faction set, we're gonna be indiff to everybody return; // well, if we dont have a faction set, we're gonna be indiff to everybody
if (sender->HasAssistAggro())
return;
for (auto it = npc_list.begin(); it != npc_list.end(); ++it) { for (auto it = npc_list.begin(); it != npc_list.end(); ++it) {
NPC *mob = it->second; NPC *mob = it->second;
if (!mob) if (!mob)
continue; continue;
if (mob->CheckAggro(attacker))
continue;
if (sender->NPCAssistCap() >= RuleI(Combat, NPCAssistCap))
break;
float r = mob->GetAssistRange(); float r = mob->GetAssistRange();
r = r * r; r = r * r;
@ -476,7 +485,8 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) {
attacker->GetName(), DistanceSquared(mob->GetPosition(), attacker->GetName(), DistanceSquared(mob->GetPosition(),
sender->GetPosition()), fabs(sender->GetZ()+mob->GetZ())); sender->GetPosition()), fabs(sender->GetZ()+mob->GetZ()));
#endif #endif
mob->AddToHateList(attacker, 1, 0, false); mob->AddToHateList(attacker, 25, 0, false);
sender->AddAssistCap();
} }
} }
} }

View File

@ -2009,15 +2009,15 @@ void NPC::Damage(Mob* other, int32 damage, uint16 spell_id, SkillUseTypes attack
} }
} }
bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack_skill) { bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attack_skill) {
Log.Out(Logs::Detail, Logs::Combat, "Fatal blow dealt by %s with %d damage, spell %d, skill %d", killerMob->GetName(), damage, spell, attack_skill); Log.Out(Logs::Detail, Logs::Combat, "Fatal blow dealt by %s with %d damage, spell %d, skill %d", killer_mob->GetName(), damage, spell, attack_skill);
Mob *oos = nullptr; Mob *oos = nullptr;
if(killerMob) { if(killer_mob) {
oos = killerMob->GetOwnerOrSelf(); oos = killer_mob->GetOwnerOrSelf();
char buffer[48] = { 0 }; char buffer[48] = { 0 };
snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast<int>(attack_skill)); snprintf(buffer, 47, "%d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
if(parse->EventNPC(EVENT_DEATH, this, oos, buffer, 0) != 0) if(parse->EventNPC(EVENT_DEATH, this, oos, buffer, 0) != 0)
{ {
if(GetHP() < 0) { if(GetHP() < 0) {
@ -2026,15 +2026,15 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
return false; return false;
} }
if(killerMob && killerMob->IsClient() && (spell != SPELL_UNKNOWN) && damage > 0) { if(killer_mob && killer_mob->IsClient() && (spell != SPELL_UNKNOWN) && damage > 0) {
char val1[20]={0}; char val1[20]={0};
entity_list.MessageClose_StringID(this, false, 100, MT_NonMelee, HIT_NON_MELEE, entity_list.MessageClose_StringID(this, false, 100, MT_NonMelee, HIT_NON_MELEE,
killerMob->GetCleanName(), GetCleanName(), ConvertArray(damage, val1)); killer_mob->GetCleanName(), GetCleanName(), ConvertArray(damage, val1));
} }
} else { } else {
char buffer[48] = { 0 }; char buffer[48] = { 0 };
snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast<int>(attack_skill)); snprintf(buffer, 47, "%d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
if(parse->EventNPC(EVENT_DEATH, this, nullptr, buffer, 0) != 0) if(parse->EventNPC(EVENT_DEATH, this, nullptr, buffer, 0) != 0)
{ {
if(GetHP() < 0) { if(GetHP() < 0) {
@ -2072,21 +2072,21 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
EQApplicationPacket* app= new EQApplicationPacket(OP_Death,sizeof(Death_Struct)); EQApplicationPacket* app= new EQApplicationPacket(OP_Death,sizeof(Death_Struct));
Death_Struct* d = (Death_Struct*)app->pBuffer; Death_Struct* d = (Death_Struct*)app->pBuffer;
d->spawn_id = GetID(); d->spawn_id = GetID();
d->killer_id = killerMob ? killerMob->GetID() : 0; d->killer_id = killer_mob ? killer_mob->GetID() : 0;
d->bindzoneid = 0; d->bindzoneid = 0;
d->spell_id = spell == SPELL_UNKNOWN ? 0xffffffff : spell; d->spell_id = spell == SPELL_UNKNOWN ? 0xffffffff : spell;
d->attack_skill = SkillDamageTypes[attack_skill]; d->attack_skill = SkillDamageTypes[attack_skill];
d->damage = damage; d->damage = damage;
app->priority = 6; app->priority = 6;
entity_list.QueueClients(killerMob, app, false); entity_list.QueueClients(killer_mob, app, false);
if(respawn2) { if(respawn2) {
respawn2->DeathReset(1); respawn2->DeathReset(1);
} }
if (killerMob) { if (killer_mob) {
if(GetClass() != LDON_TREASURE) if(GetClass() != LDON_TREASURE)
hate_list.AddEntToHateList(killerMob, damage); hate_list.AddEntToHateList(killer_mob, damage);
} }
safe_delete(app); safe_delete(app);
@ -2148,8 +2148,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
{ {
if(!IsLdonTreasure && MerchantType == 0) { if(!IsLdonTreasure && MerchantType == 0) {
kr->SplitExp((finalxp), this); kr->SplitExp((finalxp), this);
if(killerMob && (kr->IsRaidMember(killerMob->GetName()) || kr->IsRaidMember(killerMob->GetUltimateOwner()->GetName()))) if(killer_mob && (kr->IsRaidMember(killer_mob->GetName()) || kr->IsRaidMember(killer_mob->GetUltimateOwner()->GetName())))
killerMob->TrySpellOnKill(killed_level,spell); killer_mob->TrySpellOnKill(killed_level,spell);
} }
/* Send the EVENT_KILLED_MERIT event for all raid members */ /* Send the EVENT_KILLED_MERIT event for all raid members */
for (int i = 0; i < MAX_RAID_MEMBERS; i++) { for (int i = 0; i < MAX_RAID_MEMBERS; i++) {
@ -2193,8 +2193,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
{ {
if(!IsLdonTreasure && MerchantType == 0) { if(!IsLdonTreasure && MerchantType == 0) {
kg->SplitExp((finalxp), this); kg->SplitExp((finalxp), this);
if(killerMob && (kg->IsGroupMember(killerMob->GetName()) || kg->IsGroupMember(killerMob->GetUltimateOwner()->GetName()))) if(killer_mob && (kg->IsGroupMember(killer_mob->GetName()) || kg->IsGroupMember(killer_mob->GetUltimateOwner()->GetName())))
killerMob->TrySpellOnKill(killed_level,spell); killer_mob->TrySpellOnKill(killed_level,spell);
} }
/* Send the EVENT_KILLED_MERIT event and update kill tasks /* Send the EVENT_KILLED_MERIT event and update kill tasks
* for all group members */ * for all group members */
@ -2244,8 +2244,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
if(!GetOwner() || (GetOwner() && !GetOwner()->IsClient())) if(!GetOwner() || (GetOwner() && !GetOwner()->IsClient()))
{ {
give_exp_client->AddEXP((finalxp), conlevel); give_exp_client->AddEXP((finalxp), conlevel);
if(killerMob && (killerMob->GetID() == give_exp_client->GetID() || killerMob->GetUltimateOwner()->GetID() == give_exp_client->GetID())) if(killer_mob && (killer_mob->GetID() == give_exp_client->GetID() || killer_mob->GetUltimateOwner()->GetID() == give_exp_client->GetID()))
killerMob->TrySpellOnKill(killed_level,spell); killer_mob->TrySpellOnKill(killed_level,spell);
} }
} }
} }
@ -2393,20 +2393,30 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
uint16 emoteid = oos->GetEmoteID(); uint16 emoteid = oos->GetEmoteID();
if(emoteid != 0) if(emoteid != 0)
oos->CastToNPC()->DoNPCEmote(KILLEDNPC, emoteid); oos->CastToNPC()->DoNPCEmote(KILLEDNPC, emoteid);
killerMob->TrySpellOnKill(killed_level, spell); killer_mob->TrySpellOnKill(killed_level, spell);
} }
} }
WipeHateList(); WipeHateList();
p_depop = true; p_depop = true;
if(killerMob && killerMob->GetTarget() == this) //we can kill things without having them targeted if(killer_mob && killer_mob->GetTarget() == this) //we can kill things without having them targeted
killerMob->SetTarget(nullptr); //via AE effects and such.. killer_mob->SetTarget(nullptr); //via AE effects and such..
entity_list.UpdateFindableNPCState(this, true); entity_list.UpdateFindableNPCState(this, true);
char buffer[48] = { 0 }; char buffer[48] = { 0 };
snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast<int>(attack_skill)); snprintf(buffer, 47, "%d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, buffer, 0); parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, buffer, 0);
/* Zone controller process EVENT_DEATH_ZONE (Death events) */
if (RuleB(Zone, UseZoneController)) {
if (entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID) && this->GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID){
char data_pass[100] = { 0 };
snprintf(data_pass, 99, "%d %d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill), this->GetNPCTypeID());
parse->EventNPC(EVENT_DEATH_ZONE, entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID)->CastToNPC(), nullptr, data_pass, 0);
}
}
return true; return true;
} }
@ -2422,6 +2432,11 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
hate = 1; hate = 1;
} }
if (iYellForHelp)
SetPrimaryAggro(true);
else
SetAssistAggro(true);
bool wasengaged = IsEngaged(); bool wasengaged = IsEngaged();
Mob* owner = other->GetOwner(); Mob* owner = other->GetOwner();
Mob* mypet = this->GetPet(); Mob* mypet = this->GetPet();
@ -2688,16 +2703,38 @@ uint8 Mob::GetWeaponDamageBonus(const Item_Struct *weapon, bool offhand)
} }
} else { } else {
// 2h damage bonus // 2h damage bonus
int damage_bonus = 1 + (level - 28) / 3;
if (delay <= 27) if (delay <= 27)
return 1 + ((level - 28) / 3); return damage_bonus + 1;
else if (delay < 40) // Client isn't reflecting what the dev quoted, this matches better
return 1 + ((level - 28) / 3) + ((level - 30) / 5); if (level > 29) {
else if (delay < 43) int level_bonus = (level - 30) / 5 + 1;
return 2 + ((level - 28) / 3) + ((level - 30) / 5) + ((delay - 40) / 3); if (level > 50) {
else if (delay < 45) level_bonus++;
return 3 + ((level - 28) / 3) + ((level - 30) / 5) + ((delay - 40) / 3); int level_bonus2 = level - 50;
else if (delay >= 45) if (level > 67)
return 4 + ((level - 28) / 3) + ((level - 30) / 5) + ((delay - 40) / 3); level_bonus2 += 5;
else if (level > 59)
level_bonus2 += 4;
else if (level > 58)
level_bonus2 += 3;
else if (level > 56)
level_bonus2 += 2;
else if (level > 54)
level_bonus2++;
level_bonus += level_bonus2 * delay / 40;
}
damage_bonus += level_bonus;
}
if (delay >= 40) {
int delay_bonus = (delay - 40) / 3 + 1;
if (delay >= 45)
delay_bonus += 2;
else if (delay >= 43)
delay_bonus++;
damage_bonus += delay_bonus;
}
return damage_bonus;
} }
} }

View File

@ -490,6 +490,7 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
(item->SkillModValue < 0 && newbon->skillmod[item->SkillModType] > item->SkillModValue)) (item->SkillModValue < 0 && newbon->skillmod[item->SkillModType] > item->SkillModValue))
{ {
newbon->skillmod[item->SkillModType] = item->SkillModValue; newbon->skillmod[item->SkillModType] = item->SkillModValue;
newbon->skillmodmax[item->SkillModType] = item->SkillModMax;
} }
} }

View File

@ -679,7 +679,7 @@ public:
void IncreaseSkill(int skill_id, int value = 1) { if (skill_id <= HIGHEST_SKILL) { m_pp.skills[skill_id] += value; } } void IncreaseSkill(int skill_id, int value = 1) { if (skill_id <= HIGHEST_SKILL) { m_pp.skills[skill_id] += value; } }
void IncreaseLanguageSkill(int skill_id, int value = 1); void IncreaseLanguageSkill(int skill_id, int value = 1);
virtual uint16 GetSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return((itembonuses.skillmod[skill_id] > 0) ? m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100 : m_pp.skills[skill_id]); } return 0; } virtual uint16 GetSkill(SkillUseTypes skill_id) const {if (skill_id <= HIGHEST_SKILL) {return(itembonuses.skillmod[skill_id] > 0 ? (itembonuses.skillmodmax[skill_id] > 0 ? std::min(m_pp.skills[skill_id] + itembonuses.skillmodmax[skill_id], m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100) : m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100) : m_pp.skills[skill_id]);} return 0;}
uint32 GetRawSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return(m_pp.skills[skill_id]); } return 0; } uint32 GetRawSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return(m_pp.skills[skill_id]); } return 0; }
bool HasSkill(SkillUseTypes skill_id) const; bool HasSkill(SkillUseTypes skill_id) const;
bool CanHaveSkill(SkillUseTypes skill_id) const; bool CanHaveSkill(SkillUseTypes skill_id) const;

View File

@ -2925,150 +2925,292 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
return; return;
} }
// Delegate to tradeskill object to perform combine
AugmentItem_Struct* in_augment = (AugmentItem_Struct*)app->pBuffer; AugmentItem_Struct* in_augment = (AugmentItem_Struct*)app->pBuffer;
bool deleteItems = false; bool deleteItems = false;
if (GetClientVersion() >= ClientVersion::RoF) if (GetClientVersion() >= ClientVersion::RoF)
{ {
ItemInst *itemOneToPush = nullptr, *itemTwoToPush = nullptr; ItemInst *itemOneToPush = nullptr, *itemTwoToPush = nullptr;
//Message(15, "%i %i %i %i %i %i", in_augment->container_slot, in_augment->augment_slot, in_augment->container_index, in_augment->augment_index, in_augment->augment_action, in_augment->dest_inst_id); //Log.Out(Logs::DebugLevel::Moderate, Logs::Debug, "cslot: %i aslot: %i cidx: %i aidx: %i act: %i dest: %i",
// in_augment->container_slot, in_augment->augment_slot, in_augment->container_index, in_augment->augment_index, in_augment->augment_action, in_augment->dest_inst_id);
// Adding augment ItemInst *tobe_auged = nullptr, *old_aug = nullptr, *new_aug = nullptr, *aug = nullptr, *solvent = nullptr;
if (in_augment->augment_action == 0) Inventory& user_inv = GetInv();
uint16 item_slot = in_augment->container_slot;
uint16 solvent_slot = in_augment->augment_slot;
uint8 mat = Inventory::CalcMaterialFromSlot(item_slot); // for when player is augging a piece of equipment while they're wearing it
if (item_slot == INVALID_INDEX || solvent_slot == INVALID_INDEX)
{ {
ItemInst *tobe_auged = nullptr, *auged_with = nullptr; Message(13, "Error: Invalid Aug Index.");
int8 slot = -1; return;
Inventory& user_inv = GetInv(); }
uint16 slot_id = in_augment->container_slot; tobe_auged = user_inv.GetItem(item_slot);
uint16 aug_slot_id = in_augment->augment_slot; solvent = user_inv.GetItem(solvent_slot);
if (slot_id == INVALID_INDEX || aug_slot_id == INVALID_INDEX)
if (!tobe_auged)
{
Message(13, "Error: Invalid item passed for augmenting.");
return;
}
if ((in_augment->augment_action == 1) || (in_augment->augment_action == 2))
{
// Check for valid distiller if safely removing / swapping an augmentation
if (!solvent)
{ {
Message(13, "Error: Invalid Aug Index."); Log.Out(Logs::General, Logs::Error, "Player tried to safely remove an augment without a distiller.");
Message(13, "Error: Missing an augmentation distiller for safely removing this augment.");
return; return;
} }
else if (solvent->GetItem()->ItemType == ItemUseTypes::ItemTypeAugmentationDistiller)
tobe_auged = user_inv.GetItem(slot_id);
auged_with = user_inv.GetItem(MainCursor);
if (tobe_auged && auged_with)
{ {
if (((tobe_auged->IsAugmentSlotAvailable(auged_with->GetAugmentType(), in_augment->augment_index)) != -1) && old_aug = tobe_auged->GetAugment(in_augment->augment_index);
(tobe_auged->AvailableWearSlot(auged_with->GetItem()->Slots)))
if (!old_aug)
{ {
tobe_auged->PutAugment(in_augment->augment_index, *auged_with); Log.Out(Logs::General, Logs::Error, "Player tried to safely remove a nonexistent augment.");
tobe_auged->UpdateOrnamentationInfo(); Message(13, "Error: No augment found in slot %i for safely removing.", in_augment->augment_index);
return;
}
else if (solvent->GetItem()->ID != old_aug->GetItem()->AugDistiller)
{
Log.Out(Logs::General, Logs::Error, "Player tried to safely remove an augment with the wrong distiller (item %u vs expected %u).", solvent->GetItem()->ID, old_aug->GetItem()->AugDistiller);
Message(13, "Error: Wrong augmentation distiller for safely removing this augment.");
return;
}
}
else if (solvent->GetItem()->ItemType != ItemUseTypes::ItemTypePerfectedAugmentationDistiller)
{
Log.Out(Logs::General, Logs::Error, "Player tried to safely remove an augment with a non-distiller item.");
Message(13, "Error: Invalid augmentation distiller for safely removing this augment.");
return;
}
}
ItemInst *aug = tobe_auged->GetAugment(in_augment->augment_index); switch (in_augment->augment_action)
if (aug) { {
std::vector<EQEmu::Any> args; case 0: // Adding an augment
args.push_back(aug); case 2: // Swapping augment
parse->EventItem(EVENT_AUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); new_aug = user_inv.GetItem(MainCursor);
args.assign(1, tobe_auged);
parse->EventItem(EVENT_AUGMENT_INSERT, this, aug, nullptr, "", in_augment->augment_index, &args);
}
else
{
Message(13, "Error: Could not find augmentation at index %i. Aborting.", in_augment->augment_index);
return;
}
itemOneToPush = tobe_auged->Clone();
// Must push items after the items in inventory are deleted - necessary due to lore items...
if (itemOneToPush)
{
DeleteItemInInventory(slot_id, 0, true);
DeleteItemInInventory(MainCursor, 0, true);
if (PutItemInInventory(slot_id, *itemOneToPush, true))
{
CalcBonuses();
// Successfully added an augment to the item
return;
}
else
{
Message(13, "Error: No available slot for end result. Please free up the augment slot.");
}
}
else
{
Message(13, "Error in cloning item for augment. Aborted.");
}
if (!new_aug) // Shouldn't get the OP code without the augment on the user's cursor, but maybe it's h4x.
{
Log.Out(Logs::General, Logs::Error, "AugmentItem OpCode with 'Insert' or 'Swap' action received, but no augment on client's cursor.");
Message(13, "Error: No augment found on cursor for inserting.");
return;
} }
else else
{ {
Message(13, "Error: No available slot for augment in that item."); if (((tobe_auged->IsAugmentSlotAvailable(new_aug->GetAugmentType(), in_augment->augment_index)) != -1) &&
(tobe_auged->AvailableWearSlot(new_aug->GetItem()->Slots)))
{
old_aug = tobe_auged->RemoveAugment(in_augment->augment_index);
if (old_aug)
{
// An old augment was removed in order to be replaced with the new one (augment_action 2)
CalcBonuses();
std::vector<EQEmu::Any> args;
args.push_back(old_aug);
parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
args.assign(1, tobe_auged);
args.push_back(false);
parse->EventItem(EVENT_AUGMENT_REMOVE, this, old_aug, nullptr, "", in_augment->augment_index, &args);
}
tobe_auged->PutAugment(in_augment->augment_index, *new_aug);
tobe_auged->UpdateOrnamentationInfo();
aug = tobe_auged->GetAugment(in_augment->augment_index);
if (aug)
{
std::vector<EQEmu::Any> args;
args.push_back(aug);
parse->EventItem(EVENT_AUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
args.assign(1, tobe_auged);
parse->EventItem(EVENT_AUGMENT_INSERT, this, aug, nullptr, "", in_augment->augment_index, &args);
}
else
{
Message(13, "Error: Could not properly insert augmentation into augment slot %i. Aborting.", in_augment->augment_index);
return;
}
itemOneToPush = tobe_auged->Clone();
if (old_aug)
{
itemTwoToPush = old_aug->Clone();
}
// Must push items after the items in inventory are deleted - necessary due to lore items...
if (itemOneToPush)
{
DeleteItemInInventory(item_slot, 0, true);
DeleteItemInInventory(MainCursor, new_aug->IsStackable() ? 1 : 0, true);
if (solvent)
{
// Consume the augment distiller
DeleteItemInInventory(solvent_slot, solvent->IsStackable() ? 1 : 0, true);
}
if (itemTwoToPush)
{
// This is a swap. Return the old aug to the player's cursor.
if (!PutItemInInventory(MainCursor, *itemTwoToPush, true))
{
Log.Out(Logs::General, Logs::Error, "Problem returning old augment to player's cursor after augmentation swap.");
Message(15, "Error: Failed to retrieve old augment after augmentation swap!");
}
}
if (PutItemInInventory(item_slot, *itemOneToPush, true))
{
// Successfully added an augment to the item
CalcBonuses();
if (mat != _MaterialInvalid)
{
SendWearChange(mat); // Visible item augged while equipped. Send WC in case ornamentation changed.
}
}
else
{
Message(13, "Error: No available slot for end result. Please free up the augment slot.");
}
}
else
{
Message(13, "Error in cloning item for augment. Aborted.");
}
}
else
{
Message(13, "Error: No available slot for augment in that item.");
}
} }
} break;
} case 1: // Removing augment safely (distiller)
else if (in_augment->augment_action == 1) aug = tobe_auged->GetAugment(in_augment->augment_index);
{ if (aug)
ItemInst *tobe_auged = nullptr, *auged_with = nullptr;
int8 slot = -1;
Inventory& user_inv = GetInv();
uint16 slot_id = in_augment->container_slot;
uint16 aug_slot_id = in_augment->augment_slot; //it's actually solvent slot
if (slot_id == INVALID_INDEX || aug_slot_id == INVALID_INDEX)
{
Message(13, "Error: Invalid Aug Index.");
return;
}
tobe_auged = user_inv.GetItem(slot_id);
auged_with = user_inv.GetItem(aug_slot_id);
ItemInst *old_aug = nullptr;
if (!auged_with)
return;
const uint32 id = auged_with->GetID();
ItemInst *aug = tobe_auged->GetAugment(in_augment->augment_index);
if (aug) {
std::vector<EQEmu::Any> args;
args.push_back(aug);
parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
args.assign(1, tobe_auged);
args.push_back(false);
parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args);
}
else
{
Message(13, "Error: Could not find augmentation at index %i. Aborting.");
return;
}
old_aug = tobe_auged->RemoveAugment(in_augment->augment_index);
tobe_auged->UpdateOrnamentationInfo();
itemOneToPush = tobe_auged->Clone();
if (old_aug)
itemTwoToPush = old_aug->Clone();
if (itemOneToPush && itemTwoToPush && auged_with)
{
DeleteItemInInventory(slot_id, 0, true);
DeleteItemInInventory(aug_slot_id, auged_with->IsStackable() ? 1 : 0, true);
if (!PutItemInInventory(slot_id, *itemOneToPush, true))
{ {
Message(15, "Failed to remove augment properly!"); std::vector<EQEmu::Any> args;
args.push_back(aug);
parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
args.assign(1, tobe_auged);
args.push_back(false);
parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args);
}
else
{
Message(13, "Error: Could not find augmentation to remove at index %i. Aborting.", in_augment->augment_index);
return;
} }
if (PutItemInInventory(MainCursor, *itemTwoToPush, true)) old_aug = tobe_auged->RemoveAugment(in_augment->augment_index);
tobe_auged->UpdateOrnamentationInfo();
itemOneToPush = tobe_auged->Clone();
if (old_aug)
itemTwoToPush = old_aug->Clone();
if (itemOneToPush && itemTwoToPush)
{ {
// Consume the augment distiller
DeleteItemInInventory(solvent_slot, solvent->IsStackable() ? 1 : 0, true);
// Remove the augmented item
DeleteItemInInventory(item_slot, 0, true);
// Replace it with the unaugmented item
if (!PutItemInInventory(item_slot, *itemOneToPush, true))
{
Log.Out(Logs::General, Logs::Error, "Problem returning equipment item to player's inventory after safe augment removal.");
Message(15, "Error: Failed to return item after de-augmentation!");
}
CalcBonuses(); CalcBonuses();
//Message(15, "Successfully removed an augmentation!");
if (mat != _MaterialInvalid)
{
SendWearChange(mat); // Visible item augged while equipped. Send WC in case ornamentation changed.
}
// Drop the removed augment on the player's cursor
if (!PutItemInInventory(MainCursor, *itemTwoToPush, true))
{
Log.Out(Logs::General, Logs::Error, "Problem returning augment to player's cursor after safe removal.");
Message(15, "Error: Failed to return augment after removal from item!");
return;
}
} }
} break;
case 3: // Destroying augment (formerly done in birdbath/sealer with a solvent)
// RoF client does not require an augmentation solvent for destroying an augmentation in an item.
// Augments can be destroyed with a right click -> Destroy at any time.
aug = tobe_auged->GetAugment(in_augment->augment_index);
if (aug)
{
std::vector<EQEmu::Any> args;
args.push_back(aug);
parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
args.assign(1, tobe_auged);
args.push_back(true);
parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args);
}
else
{
Message(13, "Error: Could not find augmentation to remove at index %i. Aborting.");
return;
}
tobe_auged->DeleteAugment(in_augment->augment_index);
tobe_auged->UpdateOrnamentationInfo();
itemOneToPush = tobe_auged->Clone();
if (itemOneToPush)
{
DeleteItemInInventory(item_slot, 0, true);
if (!PutItemInInventory(item_slot, *itemOneToPush, true))
{
Log.Out(Logs::General, Logs::Error, "Problem returning equipment item to player's inventory after augment deletion.");
Message(15, "Error: Failed to return item after destroying augment!");
}
}
CalcBonuses();
if (mat != _MaterialInvalid)
{
SendWearChange(mat);
}
break;
default: // Unknown
Log.Out(Logs::General, Logs::Inventory, "Unrecognized augmentation action - cslot: %i aslot: %i cidx: %i aidx: %i act: %i dest: %i",
in_augment->container_slot, in_augment->augment_slot, in_augment->container_index, in_augment->augment_index, in_augment->augment_action, in_augment->dest_inst_id);
break;
} }
} }
else else
{ {
// Delegate to tradeskill object to perform combine
Object::HandleAugmentation(this, in_augment, m_tradeskill_object); Object::HandleAugmentation(this, in_augment, m_tradeskill_object);
} }
return; return;

View File

@ -278,6 +278,7 @@ struct StatBonuses {
float AggroRange; // when calculate just replace original value with this float AggroRange; // when calculate just replace original value with this
float AssistRange; float AssistRange;
int32 skillmod[HIGHEST_SKILL+1]; int32 skillmod[HIGHEST_SKILL+1];
int32 skillmodmax[HIGHEST_SKILL+1];
int effective_casting_level; int effective_casting_level;
int reflect_chance; // chance to reflect incoming spell int reflect_chance; // chance to reflect incoming spell
uint32 singingMod; uint32 singingMod;

View File

@ -114,7 +114,9 @@ const char *QuestEventSubroutines[_LargestEventID] = {
"EVENT_RESPAWN", "EVENT_RESPAWN",
"EVENT_DEATH_COMPLETE", "EVENT_DEATH_COMPLETE",
"EVENT_UNHANDLED_OPCODE", "EVENT_UNHANDLED_OPCODE",
"EVENT_TICK" "EVENT_TICK",
"EVENT_SPAWN_ZONE",
"EVENT_DEATH_ZONE",
}; };
PerlembParser::PerlembParser() : perl(nullptr) { PerlembParser::PerlembParser() : perl(nullptr) {
@ -1424,6 +1426,21 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
ExportVar(package_name.c_str(), "slotid", extradata); ExportVar(package_name.c_str(), "slotid", extradata);
break; break;
} }
case EVENT_SPAWN_ZONE: {
Seperator sep(data);
ExportVar(package_name.c_str(), "spawned_entity_id", sep.arg[0]);
ExportVar(package_name.c_str(), "spawned_npc_id", sep.arg[1]);
break;
}
case EVENT_DEATH_ZONE: {
Seperator sep(data);
ExportVar(package_name.c_str(), "killer_id", sep.arg[0]);
ExportVar(package_name.c_str(), "killer_damage", sep.arg[1]);
ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]);
ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]);
ExportVar(package_name.c_str(), "killed_npc_id", sep.arg[4]);
break;
}
default: { default: {
break; break;

View File

@ -2919,6 +2919,29 @@ XS(XS__UpdateInstanceTimer) {
XSRETURN_EMPTY; XSRETURN_EMPTY;
} }
XS(XS__GetInstanceTimer);
XS(XS__GetInstanceTimer) {
dXSARGS;
if (items != 0)
Perl_croak(aTHX_ "Usage: GetInstanceTimer()");
uint32 timer = quest_manager.GetInstanceTimer();
XSRETURN_UV(timer);
}
XS(XS__GetInstanceTimerByID);
XS(XS__GetInstanceTimerByID) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: GetInstanceTimerByID(instance_id)");
uint16 instance_id = (uint16)SvUV(ST(0));
uint32 timer = quest_manager.GetInstanceTimerByID(instance_id);
XSRETURN_UV(timer);
}
XS(XS__GetInstanceID); XS(XS__GetInstanceID);
XS(XS__GetInstanceID) { XS(XS__GetInstanceID) {
dXSARGS; dXSARGS;
@ -3614,6 +3637,19 @@ XS(XS__debug)
XSRETURN_EMPTY; XSRETURN_EMPTY;
} }
XS(XS__UpdateZoneHeader);
XS(XS__UpdateZoneHeader) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: UpdateZoneHeader(type, value)");
std::string type = (std::string)SvPV_nolen(ST(0));
std::string value = (std::string)SvPV_nolen(ST(1));
quest_manager.UpdateZoneHeader(type, value);
XSRETURN_EMPTY;
}
/* /*
This is the callback perl will look for to setup the This is the callback perl will look for to setup the
@ -3650,6 +3686,8 @@ EXTERN_C XS(boot_quest)
newXS(strcpy(buf, "CreateInstance"), XS__CreateInstance, file); newXS(strcpy(buf, "CreateInstance"), XS__CreateInstance, file);
newXS(strcpy(buf, "DestroyInstance"), XS__DestroyInstance, file); newXS(strcpy(buf, "DestroyInstance"), XS__DestroyInstance, file);
newXS(strcpy(buf, "UpdateInstanceTimer"), XS__UpdateInstanceTimer, file); newXS(strcpy(buf, "UpdateInstanceTimer"), XS__UpdateInstanceTimer, file);
newXS(strcpy(buf, "GetInstanceTimer"), XS__GetInstanceTimer, file);
newXS(strcpy(buf, "GetInstanceTimerByID"), XS__GetInstanceTimerByID, file);
newXS(strcpy(buf, "FlagInstanceByGroupLeader"), XS__FlagInstanceByGroupLeader, file); newXS(strcpy(buf, "FlagInstanceByGroupLeader"), XS__FlagInstanceByGroupLeader, file);
newXS(strcpy(buf, "FlagInstanceByRaidLeader"), XS__FlagInstanceByRaidLeader, file); newXS(strcpy(buf, "FlagInstanceByRaidLeader"), XS__FlagInstanceByRaidLeader, file);
newXS(strcpy(buf, "FlyMode"), XS__FlyMode, file); newXS(strcpy(buf, "FlyMode"), XS__FlyMode, file);
@ -3841,6 +3879,7 @@ EXTERN_C XS(boot_quest)
newXS(strcpy(buf, "untraindiscs"), XS__untraindiscs, file); newXS(strcpy(buf, "untraindiscs"), XS__untraindiscs, file);
newXS(strcpy(buf, "updatespawntimer"), XS__UpdateSpawnTimer, file); newXS(strcpy(buf, "updatespawntimer"), XS__UpdateSpawnTimer, file);
newXS(strcpy(buf, "updatetaskactivity"), XS__updatetaskactivity, file); newXS(strcpy(buf, "updatetaskactivity"), XS__updatetaskactivity, file);
newXS(strcpy(buf, "UpdateZoneHeader"), XS__UpdateZoneHeader, file);
newXS(strcpy(buf, "varlink"), XS__varlink, file); newXS(strcpy(buf, "varlink"), XS__varlink, file);
newXS(strcpy(buf, "voicetell"), XS__voicetell, file); newXS(strcpy(buf, "voicetell"), XS__voicetell, file);
newXS(strcpy(buf, "we"), XS__we, file); newXS(strcpy(buf, "we"), XS__we, file);

View File

@ -641,8 +641,18 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
{ {
npc->SetID(GetFreeID()); npc->SetID(GetFreeID());
npc->SetMerchantProbability((uint8) zone->random.Int(0, 99)); npc->SetMerchantProbability((uint8) zone->random.Int(0, 99));
parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0); parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0);
/* Zone controller process EVENT_SPAWN_ZONE */
if (RuleB(Zone, UseZoneController)) {
if (entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID) && npc->GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID){
char data_pass[100] = { 0 };
snprintf(data_pass, 99, "%d %d", npc->GetID(), npc->GetNPCTypeID());
parse->EventNPC(EVENT_SPAWN_ZONE, entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID)->CastToNPC(), nullptr, data_pass, 0);
}
}
uint16 emoteid = npc->GetEmoteID(); uint16 emoteid = npc->GetEmoteID();
if (emoteid != 0) if (emoteid != 0)
npc->DoNPCEmote(ONSPAWN, emoteid); npc->DoNPCEmote(ONSPAWN, emoteid);

View File

@ -83,7 +83,8 @@ typedef enum {
EVENT_DEATH_COMPLETE, EVENT_DEATH_COMPLETE,
EVENT_UNHANDLED_OPCODE, EVENT_UNHANDLED_OPCODE,
EVENT_TICK, EVENT_TICK,
EVENT_SPAWN_ZONE,
EVENT_DEATH_ZONE,
_LargestEventID _LargestEventID
} QuestEventID; } QuestEventID;

View File

@ -808,6 +808,14 @@ void lua_update_instance_timer(uint16 instance_id, uint32 new_duration) {
quest_manager.UpdateInstanceTimer(instance_id, new_duration); quest_manager.UpdateInstanceTimer(instance_id, new_duration);
} }
uint32 lua_get_instance_timer() {
return quest_manager.GetInstanceTimer();
}
uint32 lua_get_instance_timer_by_id(uint16 instance_id) {
return quest_manager.GetInstanceTimerByID(instance_id);
}
int lua_get_instance_id(const char *zone, uint32 version) { int lua_get_instance_id(const char *zone, uint32 version) {
return quest_manager.GetInstanceID(zone, version); return quest_manager.GetInstanceID(zone, version);
} }
@ -1296,6 +1304,10 @@ void lua_debug(std::string message, int level) {
Log.Out(static_cast<Logs::DebugLevel>(level), Logs::QuestDebug, message); Log.Out(static_cast<Logs::DebugLevel>(level), Logs::QuestDebug, message);
} }
void lua_update_zone_header(std::string type, std::string value) {
quest_manager.UpdateZoneHeader(type, value);
}
#define LuaCreateNPCParse(name, c_type, default_value) do { \ #define LuaCreateNPCParse(name, c_type, default_value) do { \
cur = table[#name]; \ cur = table[#name]; \
if(luabind::type(cur) != LUA_TNIL) { \ if(luabind::type(cur) != LUA_TNIL) { \
@ -1719,7 +1731,9 @@ luabind::scope lua_register_events() {
luabind::value("leave_area", static_cast<int>(EVENT_LEAVE_AREA)), luabind::value("leave_area", static_cast<int>(EVENT_LEAVE_AREA)),
luabind::value("death_complete", static_cast<int>(EVENT_DEATH_COMPLETE)), luabind::value("death_complete", static_cast<int>(EVENT_DEATH_COMPLETE)),
luabind::value("unhandled_opcode", static_cast<int>(EVENT_UNHANDLED_OPCODE)), luabind::value("unhandled_opcode", static_cast<int>(EVENT_UNHANDLED_OPCODE)),
luabind::value("tick", static_cast<int>(EVENT_TICK)) luabind::value("tick", static_cast<int>(EVENT_TICK)),
luabind::value("spawn_zone", static_cast<int>(EVENT_SPAWN_ZONE)),
luabind::value("death_zone", static_cast<int>(EVENT_DEATH_ZONE))
]; ];
} }

View File

@ -1881,6 +1881,106 @@ bool Lua_Mob::IsBlind() {
return self->IsBlind(); return self->IsBlind();
} }
uint8 Lua_Mob::SeeInvisible() {
Lua_Safe_Call_Int();
return self->SeeInvisible();
}
bool Lua_Mob::SeeInvisibleUndead() {
Lua_Safe_Call_Bool();
return self->SeeInvisibleUndead();
}
bool Lua_Mob::SeeHide() {
Lua_Safe_Call_Bool();
return self->SeeHide();
}
bool Lua_Mob::SeeImprovedHide() {
Lua_Safe_Call_Bool();
return self->SeeImprovedHide();
}
uint8 Lua_Mob::GetNimbusEffect1() {
Lua_Safe_Call_Int();
return self->GetNimbusEffect1();
}
uint8 Lua_Mob::GetNimbusEffect2() {
Lua_Safe_Call_Int();
return self->GetNimbusEffect2();
}
uint8 Lua_Mob::GetNimbusEffect3() {
Lua_Safe_Call_Int();
return self->GetNimbusEffect3();
}
bool Lua_Mob::IsTargetable() {
Lua_Safe_Call_Bool();
return self->IsTargetable();
}
bool Lua_Mob::HasShieldEquiped() {
Lua_Safe_Call_Bool();
return self->HasShieldEquiped();
}
bool Lua_Mob::HasTwoHandBluntEquiped() {
Lua_Safe_Call_Bool();
return self->HasTwoHandBluntEquiped();
}
bool Lua_Mob::HasTwoHanderEquipped() {
Lua_Safe_Call_Bool();
return self->HasTwoHanderEquipped();
}
uint32 Lua_Mob::GetHerosForgeModel(uint8 material_slot) {
Lua_Safe_Call_Int();
return self->GetHerosForgeModel(material_slot);
}
uint32 Lua_Mob::IsEliteMaterialItem(uint8 material_slot) {
Lua_Safe_Call_Int();
return self->IsEliteMaterialItem(material_slot);
}
float Lua_Mob::GetBaseSize() {
Lua_Safe_Call_Real();
return self->GetBaseSize();
}
bool Lua_Mob::HasOwner() {
Lua_Safe_Call_Bool();
return self->HasOwner();
}
bool Lua_Mob::IsPet() {
Lua_Safe_Call_Bool();
return self->IsPet();
}
bool Lua_Mob::HasPet() {
Lua_Safe_Call_Bool();
return self->HasPet();
}
bool Lua_Mob::IsSilenced() {
Lua_Safe_Call_Bool();
return self->IsSilenced();
}
bool Lua_Mob::IsAmnesiad() {
Lua_Safe_Call_Bool();
return self->IsAmnesiad();
}
int32 Lua_Mob::GetMeleeMitigation() {
Lua_Safe_Call_Int();
return self->GetMeleeMitigation();
}
luabind::scope lua_register_mob() { luabind::scope lua_register_mob() {
return luabind::class_<Lua_Mob, Lua_Entity>("Mob") return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
.def(luabind::constructor<>()) .def(luabind::constructor<>())
@ -2203,7 +2303,27 @@ luabind::scope lua_register_mob() {
.def("BuffFadeBySlot", (void(Lua_Mob::*)(int,bool))&Lua_Mob::BuffFadeBySlot) .def("BuffFadeBySlot", (void(Lua_Mob::*)(int,bool))&Lua_Mob::BuffFadeBySlot)
.def("CanBuffStack", (int(Lua_Mob::*)(int,int))&Lua_Mob::CanBuffStack) .def("CanBuffStack", (int(Lua_Mob::*)(int,int))&Lua_Mob::CanBuffStack)
.def("CanBuffStack", (int(Lua_Mob::*)(int,int,bool))&Lua_Mob::CanBuffStack) .def("CanBuffStack", (int(Lua_Mob::*)(int,int,bool))&Lua_Mob::CanBuffStack)
.def("SetPseudoRoot", (void(Lua_Mob::*)(bool))&Lua_Mob::SetPseudoRoot); .def("SetPseudoRoot", (void(Lua_Mob::*)(bool))&Lua_Mob::SetPseudoRoot)
.def("SeeInvisible", (uint8(Lua_Mob::*)(void))&Lua_Mob::SeeInvisible)
.def("SeeInvisibleUndead", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeInvisibleUndead)
.def("SeeHide", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeHide)
.def("SeeImprovedHide", (bool(Lua_Mob::*)(bool))&Lua_Mob::SeeImprovedHide)
.def("GetNimbusEffect1", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect1)
.def("GetNimbusEffect2", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect2)
.def("GetNimbusEffect3", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect3)
.def("IsTargetable", (bool(Lua_Mob::*)(void))&Lua_Mob::IsTargetable)
.def("HasShieldEquiped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasShieldEquiped)
.def("HasTwoHandBluntEquiped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasTwoHandBluntEquiped)
.def("HasTwoHanderEquipped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasTwoHanderEquipped)
.def("GetHerosForgeModel", (int32(Lua_Mob::*)(uint8))&Lua_Mob::GetHerosForgeModel)
.def("IsEliteMaterialItem", (uint32(Lua_Mob::*)(uint8))&Lua_Mob::IsEliteMaterialItem)
.def("GetBaseSize", (double(Lua_Mob::*)(void))&Lua_Mob::GetBaseSize)
.def("HasOwner", (bool(Lua_Mob::*)(void))&Lua_Mob::HasOwner)
.def("IsPet", (bool(Lua_Mob::*)(void))&Lua_Mob::IsPet)
.def("HasPet", (bool(Lua_Mob::*)(void))&Lua_Mob::HasPet)
.def("IsSilenced", (bool(Lua_Mob::*)(void))&Lua_Mob::IsSilenced)
.def("IsAmnesiad", (bool(Lua_Mob::*)(void))&Lua_Mob::IsAmnesiad)
.def("GetMeleeMitigation", (int32(Lua_Mob::*)(void))&Lua_Mob::GetMeleeMitigation);
} }
luabind::scope lua_register_special_abilities() { luabind::scope lua_register_special_abilities() {

View File

@ -358,6 +358,26 @@ public:
int CanBuffStack(int spell_id, int caster_level); int CanBuffStack(int spell_id, int caster_level);
int CanBuffStack(int spell_id, int caster_level, bool fail_if_overwrite); int CanBuffStack(int spell_id, int caster_level, bool fail_if_overwrite);
void SetPseudoRoot(bool in); void SetPseudoRoot(bool in);
uint8 SeeInvisible();
bool SeeInvisibleUndead();
bool SeeHide();
bool SeeImprovedHide();
uint8 GetNimbusEffect1();
uint8 GetNimbusEffect2();
uint8 GetNimbusEffect3();
bool IsTargetable();
bool HasShieldEquiped();
bool HasTwoHandBluntEquiped();
bool HasTwoHanderEquipped();
uint32 GetHerosForgeModel(uint8 material_slot);
uint32 IsEliteMaterialItem(uint8 material_slot);
float GetBaseSize();
bool HasOwner();
bool IsPet();
bool HasPet();
bool IsSilenced();
bool IsAmnesiad();
int32 GetMeleeMitigation();
}; };
#endif #endif

View File

@ -117,7 +117,9 @@ const char *LuaEvents[_LargestEventID] = {
"event_respawn", "event_respawn",
"event_death_complete", "event_death_complete",
"event_unhandled_opcode", "event_unhandled_opcode",
"event_tick" "event_tick",
"event_spawn_zone",
"event_death_zone"
}; };
extern Zone *zone; extern Zone *zone;

View File

@ -433,6 +433,9 @@ Mob::Mob(const char* in_name,
emoteid = 0; emoteid = 0;
endur_upkeep = false; endur_upkeep = false;
PrimaryAggro = false;
AssistAggro = false;
npc_assist_cap = 0;
} }
Mob::~Mob() Mob::~Mob()
@ -2693,6 +2696,8 @@ bool Mob::RemoveFromHateList(Mob* mob)
{ {
AI_Event_NoLongerEngaged(); AI_Event_NoLongerEngaged();
zone->DelAggroMob(); zone->DelAggroMob();
if (IsNPC() && !RuleB(Aggro, AllowTickPulling))
ResetAssistCap();
} }
} }
if(GetTarget() == mob) if(GetTarget() == mob)
@ -5677,3 +5682,11 @@ void Mob::SetCurrentSpeed(int in){
} }
} }
} }
int32 Mob::GetMeleeMitigation() {
int32 mitigation = 0;
mitigation += spellbonuses.MeleeMitigationEffect;
mitigation += itembonuses.MeleeMitigationEffect;
mitigation += aabonuses.MeleeMitigationEffect;
return mitigation;
}

View File

@ -504,6 +504,10 @@ public:
Mob* GetHateRandom() { return hate_list.GetRandomEntOnHateList();} Mob* GetHateRandom() { return hate_list.GetRandomEntOnHateList();}
Mob* GetHateMost() { return hate_list.GetEntWithMostHateOnList();} Mob* GetHateMost() { return hate_list.GetEntWithMostHateOnList();}
bool IsEngaged() { return(!hate_list.IsHateListEmpty()); } bool IsEngaged() { return(!hate_list.IsHateListEmpty()); }
bool HasPrimaryAggro() { return PrimaryAggro; }
bool HasAssistAggro() { return AssistAggro; }
void SetPrimaryAggro(bool value) { PrimaryAggro = value; if (value) AssistAggro = false; }
void SetAssistAggro(bool value) { AssistAggro = value; if (PrimaryAggro) AssistAggro = false; }
bool HateSummon(); bool HateSummon();
void FaceTarget(Mob* MobToFace = 0); void FaceTarget(Mob* MobToFace = 0);
void SetHeading(float iHeading) { if(m_Position.w != iHeading) { pLastChange = Timer::GetCurrentTime(); void SetHeading(float iHeading) { if(m_Position.w != iHeading) { pLastChange = Timer::GetCurrentTime();
@ -748,6 +752,7 @@ public:
inline bool GetInvul(void) { return invulnerable; } inline bool GetInvul(void) { return invulnerable; }
inline void SetExtraHaste(int Haste) { ExtraHaste = Haste; } inline void SetExtraHaste(int Haste) { ExtraHaste = Haste; }
virtual int GetHaste(); virtual int GetHaste();
int32 GetMeleeMitigation();
uint8 GetWeaponDamageBonus(const Item_Struct* weapon, bool offhand = false); uint8 GetWeaponDamageBonus(const Item_Struct* weapon, bool offhand = false);
uint16 GetDamageTable(SkillUseTypes skillinuse); uint16 GetDamageTable(SkillUseTypes skillinuse);
@ -993,6 +998,11 @@ public:
void ApplyAABonuses(const AA::Rank &rank, StatBonuses* newbon); void ApplyAABonuses(const AA::Rank &rank, StatBonuses* newbon);
bool CheckAATimer(int timer); bool CheckAATimer(int timer);
int NPCAssistCap() { return npc_assist_cap; }
void AddAssistCap() { ++npc_assist_cap; }
void DelAssistCap() { --npc_assist_cap; }
void ResetAssistCap() { npc_assist_cap = 0; }
protected: protected:
void CommonDamage(Mob* other, int32 &damage, const uint16 spell_id, const SkillUseTypes attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, int special = 0); void CommonDamage(Mob* other, int32 &damage, const uint16 spell_id, const SkillUseTypes attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, int special = 0);
static uint16 GetProcID(uint16 spell_id, uint8 effect_index); static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
@ -1293,6 +1303,11 @@ protected:
glm::vec4 m_CurrentWayPoint; glm::vec4 m_CurrentWayPoint;
int cur_wp_pause; int cur_wp_pause;
bool PrimaryAggro;
bool AssistAggro;
int npc_assist_cap;
Timer assist_cap_timer; // clear assist cap so more nearby mobs can be called for help
int patrol; int patrol;
glm::vec3 m_FearWalkTarget; glm::vec3 m_FearWalkTarget;

View File

@ -1735,8 +1735,10 @@ void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) {
if (iYellForHelp) { if (iYellForHelp) {
if(IsPet()) { if(IsPet()) {
GetOwner()->AI_Event_Engaged(attacker, iYellForHelp); GetOwner()->AI_Event_Engaged(attacker, iYellForHelp);
} else { } else if (!HasAssistAggro() && NPCAssistCap() < RuleI(Combat, NPCAssistCap)) {
entity_list.AIYellForHelp(this, attacker); entity_list.AIYellForHelp(this, attacker);
if (NPCAssistCap() > 0 && !assist_cap_timer.Enabled())
assist_cap_timer.Start(RuleI(Combat, NPCAssistCapTimer));
} }
} }
@ -1787,6 +1789,8 @@ void Mob::AI_Event_NoLongerEngaged() {
if(IsNPC()) if(IsNPC())
{ {
SetPrimaryAggro(false);
SetAssistAggro(false);
if(CastToNPC()->GetCombatEvent() && GetHP() > 0) if(CastToNPC()->GetCombatEvent() && GetHP() > 0)
{ {
if(entity_list.GetNPCByID(this->GetID())) if(entity_list.GetNPCByID(this->GetID()))

View File

@ -712,8 +712,18 @@ bool NPC::Process()
} }
//Handle assists... //Handle assists...
if(assist_timer.Check() && IsEngaged() && !Charmed()) { if (assist_cap_timer.Check()) {
if (NPCAssistCap() > 0)
DelAssistCap();
else
assist_cap_timer.Disable();
}
if (assist_timer.Check() && IsEngaged() && !Charmed() && !HasAssistAggro() &&
NPCAssistCap() < RuleI(Combat, NPCAssistCap)) {
entity_list.AIYellForHelp(this, GetTarget()); entity_list.AIYellForHelp(this, GetTarget());
if (NPCAssistCap() > 0 && !assist_cap_timer.Enabled())
assist_cap_timer.Start(RuleI(Combat, NPCAssistCapTimer));
} }
if(qGlobals) if(qGlobals)
@ -833,6 +843,53 @@ bool NPC::DatabaseCastAccepted(int spell_id) {
return false; return false;
} }
bool NPC::SpawnZoneController(){
if (!RuleB(Zone, UseZoneController))
return false;
NPCType* npc_type = new NPCType;
memset(npc_type, 0, sizeof(NPCType));
strncpy(npc_type->name, "zone_controller", 60);
npc_type->cur_hp = 2000000000;
npc_type->max_hp = 2000000000;
npc_type->hp_regen = 100000000;
npc_type->race = 240;
npc_type->gender = 2;
npc_type->class_ = 1;
npc_type->deity = 1;
npc_type->level = 200;
npc_type->npc_id = ZONE_CONTROLLER_NPC_ID;
npc_type->loottable_id = 0;
npc_type->texture = 3;
npc_type->runspeed = 0;
npc_type->d_melee_texture1 = 0;
npc_type->d_melee_texture2 = 0;
npc_type->merchanttype = 0;
npc_type->bodytype = 11;
npc_type->prim_melee_type = 28;
npc_type->sec_melee_type = 28;
npc_type->findable = 0;
npc_type->trackable = 0;
strcpy(npc_type->special_abilities, "12,1^13,1^14,1^15,1^16,1^17,1^19,1^22,1^24,1^25,1^28,1^31,1^35,1^39,1^42,1");
glm::vec4 point;
point.x = 5000;
point.y = 5000;
point.z = -5000;
NPC* npc = new NPC(npc_type, nullptr, point, FlyMode3);
npc->GiveNPCTypeData(npc_type);
entity_list.AddNPC(npc);
return true;
}
NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* client) { NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* client) {
if(spawncommand == 0 || spawncommand[0] == 0) { if(spawncommand == 0 || spawncommand[0] == 0) {
return 0; return 0;

View File

@ -96,6 +96,7 @@ class NPC : public Mob
{ {
public: public:
static NPC* SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* client = nullptr); static NPC* SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* client = nullptr);
static bool SpawnZoneController();
static int8 GetAILevel(bool iForceReRead = false); static int8 GetAILevel(bool iForceReRead = false);
NPC(const NPCType* data, Spawn2* respawn, const glm::vec4& position, int iflymode, bool IsCorpse = false); NPC(const NPCType* data, Spawn2* respawn, const glm::vec4& position, int iflymode, bool IsCorpse = false);

View File

@ -8490,6 +8490,524 @@ XS(XS_Mob_IsBlind) {
XSRETURN(1); XSRETURN(1);
} }
XS(XS_Mob_SeeInvisible);
XS(XS_Mob_SeeInvisible) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::SeeInvisible(THIS)");
{
Mob* THIS;
uint8 RETVAL;
dXSTARG;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->SeeInvisible();
XSprePUSH;
PUSHu((UV)RETVAL);
}
XSRETURN(1);
}
XS(XS_Mob_SeeInvisibleUndead);
XS(XS_Mob_SeeInvisibleUndead) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::SeeInvisibleUndead(THIS)");
{
Mob* THIS;
bool RETVAL;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->SeeInvisibleUndead();
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Mob_SeeHide);
XS(XS_Mob_SeeHide) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::SeeHide(THIS)");
{
Mob* THIS;
bool RETVAL;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->SeeHide();
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Mob_SeeImprovedHide);
XS(XS_Mob_SeeImprovedHide) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::SeeImprovedHide(THIS)");
{
Mob* THIS;
bool RETVAL;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->SeeImprovedHide();
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Mob_GetNimbusEffect1);
XS(XS_Mob_GetNimbusEffect1) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::GetNimbusEffect1(THIS)");
{
Mob* THIS;
uint8 RETVAL;
dXSTARG;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetNimbusEffect1();
XSprePUSH;
PUSHu((UV)RETVAL);
}
XSRETURN(1);
}
XS(XS_Mob_GetNimbusEffect2);
XS(XS_Mob_GetNimbusEffect2) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::GetNimbusEffect2(THIS)");
{
Mob* THIS;
uint8 RETVAL;
dXSTARG;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetNimbusEffect2();
XSprePUSH;
PUSHu((UV)RETVAL);
}
XSRETURN(1);
}
XS(XS_Mob_GetNimbusEffect3);
XS(XS_Mob_GetNimbusEffect3) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::GetNimbusEffect3(THIS)");
{
Mob* THIS;
uint8 RETVAL;
dXSTARG;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetNimbusEffect3();
XSprePUSH;
PUSHu((UV)RETVAL);
}
XSRETURN(1);
}
XS(XS_Mob_IsTargetable);
XS(XS_Mob_IsTargetable) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::IsTargetable(THIS)");
{
Mob* THIS;
bool RETVAL;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->IsTargetable();
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Mob_HasShieldEquiped);
XS(XS_Mob_HasShieldEquiped) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::HasShieldEquiped(THIS)");
{
Mob* THIS;
bool RETVAL;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->HasShieldEquiped();
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Mob_HasTwoHandBluntEquiped);
XS(XS_Mob_HasTwoHandBluntEquiped) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::HasTwoHandBluntEquiped(THIS)");
{
Mob* THIS;
bool RETVAL;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->HasTwoHandBluntEquiped();
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Mob_HasTwoHanderEquipped);
XS(XS_Mob_HasTwoHanderEquipped) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::HasTwoHanderEquipped(THIS)");
{
Mob* THIS;
bool RETVAL;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->HasTwoHanderEquipped();
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Mob_GetHerosForgeModel);
XS(XS_Mob_GetHerosForgeModel) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: Mob::GetHerosForgeModel(THIS, material_slot)");
{
Mob* THIS;
int32 RETVAL;
uint8 material_slot = (uint8)SvUV(ST(1));
dXSTARG;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetHerosForgeModel(material_slot);
XSprePUSH;
PUSHi((IV)RETVAL);
}
XSRETURN(1);
}
XS(XS_Mob_IsEliteMaterialItem);
XS(XS_Mob_IsEliteMaterialItem) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: Mob::IsEliteMaterialItem(THIS, material_slot)");
{
Mob* THIS;
uint32 RETVAL;
uint8 material_slot = (uint8)SvUV(ST(1));
dXSTARG;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->IsEliteMaterialItem(material_slot);
XSprePUSH;
PUSHu((UV)RETVAL);
}
XSRETURN(1);
}
XS(XS_Mob_GetBaseSize);
XS(XS_Mob_GetBaseSize) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::GetBaseSize(THIS)");
{
Mob* THIS;
float RETVAL;
dXSTARG;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetBaseSize();
XSprePUSH;
PUSHn((double)RETVAL);
}
XSRETURN(1);
}
XS(XS_Mob_HasOwner);
XS(XS_Mob_HasOwner) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::HasOwner(THIS)");
{
Mob* THIS;
bool RETVAL;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->HasOwner();
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Mob_IsPet);
XS(XS_Mob_IsPet) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::IsPet(THIS)");
{
Mob* THIS;
bool RETVAL;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->IsPet();
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Mob_HasPet);
XS(XS_Mob_HasPet) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::HasPet(THIS)");
{
Mob* THIS;
bool RETVAL;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->HasPet();
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Mob_IsSilenced);
XS(XS_Mob_IsSilenced) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::IsSilenced(THIS)");
{
Mob* THIS;
bool RETVAL;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->IsSilenced();
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Mob_IsAmnesiad);
XS(XS_Mob_IsAmnesiad) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::IsAmnesiad(THIS)");
{
Mob* THIS;
bool RETVAL;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->IsAmnesiad();
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Mob_GetMeleeMitigation);
XS(XS_Mob_GetMeleeMitigation) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::GetMeleeMitigation(THIS)");
{
Mob* THIS;
int32 RETVAL;
dXSTARG;
if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob*, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetMeleeMitigation();
XSprePUSH;
PUSHi((IV)RETVAL);
}
XSRETURN(1);
}
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
#endif #endif
@ -8803,6 +9321,26 @@ XS(boot_Mob)
newXSproto(strcpy(buf, "CanClassEquipItem"), XS_Mob_CanClassEquipItem, file, "$$"); newXSproto(strcpy(buf, "CanClassEquipItem"), XS_Mob_CanClassEquipItem, file, "$$");
newXSproto(strcpy(buf, "IsFeared"), XS_Mob_IsFeared, file, "$"); newXSproto(strcpy(buf, "IsFeared"), XS_Mob_IsFeared, file, "$");
newXSproto(strcpy(buf, "IsBlind"), XS_Mob_IsBlind, file, "$"); newXSproto(strcpy(buf, "IsBlind"), XS_Mob_IsBlind, file, "$");
newXSproto(strcpy(buf, "SeeInvisible"), XS_Mob_SeeInvisible, file, "$");
newXSproto(strcpy(buf, "SeeInvisibleUndead"), XS_Mob_SeeInvisibleUndead, file, "$");
newXSproto(strcpy(buf, "SeeHide"), XS_Mob_SeeHide, file, "$");
newXSproto(strcpy(buf, "SeeImprovedHide"), XS_Mob_SeeImprovedHide, file, "$");
newXSproto(strcpy(buf, "GetNimbusEffect1"), XS_Mob_GetNimbusEffect1, file, "$");
newXSproto(strcpy(buf, "GetNimbusEffect2"), XS_Mob_GetNimbusEffect2, file, "$");
newXSproto(strcpy(buf, "GetNimbusEffect3"), XS_Mob_GetNimbusEffect3, file, "$");
newXSproto(strcpy(buf, "IsTargetable"), XS_Mob_IsTargetable, file, "$");
newXSproto(strcpy(buf, "HasShieldEquiped"), XS_Mob_HasShieldEquiped, file, "$");
newXSproto(strcpy(buf, "HasTwoHandBluntEquiped"), XS_Mob_HasTwoHandBluntEquiped, file, "$");
newXSproto(strcpy(buf, "HasTwoHanderEquipped"), XS_Mob_HasTwoHanderEquipped, file, "$");
newXSproto(strcpy(buf, "GetHerosForgeModel"), XS_Mob_GetHerosForgeModel, file, "$$");
newXSproto(strcpy(buf, "IsEliteMaterialItem"), XS_Mob_IsEliteMaterialItem, file, "$$");
newXSproto(strcpy(buf, "GetBaseSize"), XS_Mob_GetBaseSize, file, "$");
newXSproto(strcpy(buf, "HasOwner"), XS_Mob_HasOwner, file, "$");
newXSproto(strcpy(buf, "IsPet"), XS_Mob_IsPet, file, "$");
newXSproto(strcpy(buf, "HasPet"), XS_Mob_HasPet, file, "$");
newXSproto(strcpy(buf, "IsSilenced"), XS_Mob_IsSilenced, file, "$");
newXSproto(strcpy(buf, "IsAmnesiad"), XS_Mob_IsAmnesiad, file, "$");
newXSproto(strcpy(buf, "GetMeleeMitigation"), XS_Mob_GetMeleeMitigation, file, "$");
XSRETURN_YES; XSRETURN_YES;
} }

View File

@ -484,10 +484,17 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string
//second look for /quests/zone/npcname.ext (precedence) //second look for /quests/zone/npcname.ext (precedence)
const NPCType *npc_type = database.LoadNPCTypesData(npcid); const NPCType *npc_type = database.LoadNPCTypesData(npcid);
if(!npc_type) { if (!npc_type && npcid != ZONE_CONTROLLER_NPC_ID) {
return nullptr; return nullptr;
} }
std::string npc_name = npc_type->name;
std::string npc_name;
if (npcid == ZONE_CONTROLLER_NPC_ID){
npc_name = "zone_controller";
}
else{
npc_name = npc_type->name;
}
int sz = static_cast<int>(npc_name.length()); int sz = static_cast<int>(npc_name.length());
for(int i = 0; i < sz; ++i) { for(int i = 0; i < sz; ++i) {
if(npc_name[i] == '`') { if(npc_name[i] == '`') {

View File

@ -2598,6 +2598,29 @@ void QuestManager::UpdateInstanceTimer(uint16 instance_id, uint32 new_duration)
} }
} }
uint32 QuestManager::GetInstanceTimer() {
if (zone && zone->GetInstanceID() > 0 && zone->GetInstanceTimer()) {
uint32 ttime = zone->GetInstanceTimer()->GetRemainingTime();
return ttime;
}
return 0;
}
uint32 QuestManager::GetInstanceTimerByID(uint16 instance_id) {
if (instance_id == 0)
return 0;
std::string query = StringFormat("SELECT ((start_time + duration) - UNIX_TIMESTAMP()) AS `remaining` FROM `instance_list` WHERE `id` = %lu", (unsigned long)instance_id);
auto results = database.QueryDatabase(query);
if (results.Success()) {
auto row = results.begin();
uint32 timer = atoi(row[0]);
return timer;
}
return 0;
}
uint16 QuestManager::GetInstanceID(const char *zone, int16 version) uint16 QuestManager::GetInstanceID(const char *zone, int16 version)
{ {
QuestManagerCurrentQuestVars(); QuestManagerCurrentQuestVars();
@ -3070,3 +3093,75 @@ std::string QuestManager::GetEncounter() const {
return ""; return "";
} }
void QuestManager::UpdateZoneHeader(std::string type, std::string value) {
if (strcasecmp(type.c_str(), "ztype") == 0)
zone->newzone_data.ztype = atoi(value.c_str());
else if (strcasecmp(type.c_str(), "fog_red") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.fog_red[i] = atoi(value.c_str());
}
} else if (strcasecmp(type.c_str(), "fog_green") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.fog_green[i] = atoi(value.c_str());
}
} else if (strcasecmp(type.c_str(), "fog_blue") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.fog_blue[i] = atoi(value.c_str());
}
} else if (strcasecmp(type.c_str(), "fog_minclip") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.fog_minclip[i] = atof(value.c_str());
}
} else if (strcasecmp(type.c_str(), "fog_maxclip") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.fog_maxclip[i] = atof(value.c_str());
}
}
else if (strcasecmp(type.c_str(), "gravity") == 0)
zone->newzone_data.gravity = atof(value.c_str());
else if (strcasecmp(type.c_str(), "time_type") == 0)
zone->newzone_data.time_type = atoi(value.c_str());
else if (strcasecmp(type.c_str(), "rain_chance") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.rain_chance[i] = atoi(value.c_str());
}
} else if (strcasecmp(type.c_str(), "rain_duration") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.rain_duration[i] = atoi(value.c_str());
}
} else if (strcasecmp(type.c_str(), "snow_chance") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.snow_chance[i] = atoi(value.c_str());
}
} else if (strcasecmp(type.c_str(), "snow_duration") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.snow_duration[i] = atoi(value.c_str());
}
}
else if (strcasecmp(type.c_str(), "sky") == 0)
zone->newzone_data.sky = atoi(value.c_str());
else if (strcasecmp(type.c_str(), "safe_x") == 0)
zone->newzone_data.safe_x = atof(value.c_str());
else if (strcasecmp(type.c_str(), "safe_y") == 0)
zone->newzone_data.safe_y = atof(value.c_str());
else if (strcasecmp(type.c_str(), "safe_z") == 0)
zone->newzone_data.safe_z = atof(value.c_str());
else if (strcasecmp(type.c_str(), "max_z") == 0)
zone->newzone_data.max_z = atof(value.c_str());
else if (strcasecmp(type.c_str(), "underworld") == 0)
zone->newzone_data.underworld = atof(value.c_str());
else if (strcasecmp(type.c_str(), "minclip") == 0)
zone->newzone_data.minclip = atof(value.c_str());
else if (strcasecmp(type.c_str(), "maxclip") == 0)
zone->newzone_data.maxclip = atof(value.c_str());
else if (strcasecmp(type.c_str(), "fog_density") == 0)
zone->newzone_data.fog_density = atof(value.c_str());
else if (strcasecmp(type.c_str(), "suspendbuffs") == 0)
zone->newzone_data.SuspendBuffs = atoi(value.c_str());
EQApplicationPacket* outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct));
memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size);
entity_list.QueueClients(0, outapp);
safe_delete(outapp);
}

View File

@ -218,6 +218,9 @@ public:
uint32 MerchantCountItem(uint32 NPCid, uint32 itemid); uint32 MerchantCountItem(uint32 NPCid, uint32 itemid);
uint16 CreateInstance(const char *zone, int16 version, uint32 duration); uint16 CreateInstance(const char *zone, int16 version, uint32 duration);
void UpdateInstanceTimer(uint16 instance_id, uint32 new_duration); void UpdateInstanceTimer(uint16 instance_id, uint32 new_duration);
void UpdateZoneHeader(std::string type, std::string value);
uint32 GetInstanceTimer();
uint32 GetInstanceTimerByID(uint16 instance_id = 0);
void DestroyInstance(uint16 instance_id); void DestroyInstance(uint16 instance_id);
uint16 GetInstanceID(const char *zone, int16 version); uint16 GetInstanceID(const char *zone, int16 version);
void AssignToInstance(uint16 instance_id); void AssignToInstance(uint16 instance_id);

View File

@ -549,6 +549,8 @@ bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spa
spawn2_list.Insert(new_spawn); spawn2_list.Insert(new_spawn);
} }
NPC::SpawnZoneController();
return true; return true;
} }

View File

@ -166,25 +166,34 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme
else else
{ {
ItemInst *old_aug = nullptr; ItemInst *old_aug = nullptr;
const uint32 id = auged_with->GetID(); bool isSolvent = auged_with->GetItem()->ItemType == ItemUseTypes::ItemTypeAugmentationSolvent;
if (!isSolvent && auged_with->GetItem()->ItemType != ItemUseTypes::ItemTypeAugmentationDistiller)
{
Log.Out(Logs::General, Logs::Error, "Player tried to remove an augment without a solvent or distiller.");
user->Message(13, "Error: Missing an augmentation solvent or distiller for removing this augment.");
return;
}
ItemInst *aug = tobe_auged->GetAugment(in_augment->augment_slot); ItemInst *aug = tobe_auged->GetAugment(in_augment->augment_slot);
if(aug) { if (aug) {
if (!isSolvent && auged_with->GetItem()->ID != aug->GetItem()->AugDistiller)
{
Log.Out(Logs::General, Logs::Error, "Player tried to safely remove an augment with the wrong distiller (item %u vs expected %u).", auged_with->GetItem()->ID, aug->GetItem()->AugDistiller);
user->Message(13, "Error: Wrong augmentation distiller for safely removing this augment.");
return;
}
std::vector<EQEmu::Any> args; std::vector<EQEmu::Any> args;
args.push_back(aug); args.push_back(aug);
parse->EventItem(EVENT_UNAUGMENT_ITEM, user, tobe_auged, nullptr, "", slot, &args); parse->EventItem(EVENT_UNAUGMENT_ITEM, user, tobe_auged, nullptr, "", slot, &args);
args.assign(1, tobe_auged); args.assign(1, tobe_auged);
bool destroyed = false; args.push_back(&isSolvent);
if(id == 40408 || id == 40409 || id == 40410) {
destroyed = true;
}
args.push_back(&destroyed);
parse->EventItem(EVENT_AUGMENT_REMOVE, user, aug, nullptr, "", slot, &args); parse->EventItem(EVENT_AUGMENT_REMOVE, user, aug, nullptr, "", slot, &args);
} }
if(id == 40408 || id == 40409 || id == 40410) if (isSolvent)
tobe_auged->DeleteAugment(in_augment->augment_slot); tobe_auged->DeleteAugment(in_augment->augment_slot);
else else
old_aug = tobe_auged->RemoveAugment(in_augment->augment_slot); old_aug = tobe_auged->RemoveAugment(in_augment->augment_slot);