Merge branch 'master' into lets_move

This commit is contained in:
KimLS 2016-01-09 01:40:54 -08:00
commit 909cbd8b97
41 changed files with 918 additions and 407 deletions

View File

@ -1,5 +1,28 @@
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 == == 12/21/2015 ==
Natedog: Updated item table fields and added a few missing fields for evolving items 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 -DO NOT implement Heirloom items till the inventory code is fixed to allow placing NO DROP

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);
} }

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

@ -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

@ -236,7 +236,7 @@ void RuleManager::SaveRules(Database *database, const char *ruleset_name) {
} }
bool RuleManager::LoadRules(Database *database, const char *ruleset_name) { bool RuleManager::LoadRules(Database *database, const char *ruleset_name) {
int ruleset_id = GetRulesetID(database, ruleset_name); int ruleset_id = GetRulesetID(database, ruleset_name);
if (ruleset_id < 0) { if (ruleset_id < 0) {
Log.Out(Logs::Detail, Logs::Rules, "Failed to find ruleset '%s' for load operation. Canceling.", ruleset_name); Log.Out(Logs::Detail, Logs::Rules, "Failed to find ruleset '%s' for load operation. Canceling.", ruleset_name);
@ -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)
@ -449,7 +450,7 @@ RULE_REAL (Combat,TauntSkillFalloff, 0.33)//For every taunt skill point that's n
RULE_BOOL (Combat,EXPFromDmgShield, false) //Determine if damage from a damage shield counts for EXP gain. RULE_BOOL (Combat,EXPFromDmgShield, false) //Determine if damage from a damage shield counts for EXP gain.
RULE_INT(Combat, MonkACBonusWeight, 15) RULE_INT(Combat, MonkACBonusWeight, 15)
RULE_INT(Combat, ClientStunLevel, 55) //This is the level where client kicks and bashes can stun the target RULE_INT(Combat, ClientStunLevel, 55) //This is the level where client kicks and bashes can stun the target
RULE_INT(Combat, QuiverWRHasteDiv, 3) //Weight Reduction is divided by this to get haste contribution for quivers RULE_INT(Combat, QuiverHasteCap, 1000) //Quiver haste cap 1000 on live for a while, currently 700 on live
RULE_BOOL(Combat, UseArcheryBonusRoll, false) //Make the 51+ archery bonus require an actual roll RULE_BOOL(Combat, UseArcheryBonusRoll, false) //Make the 51+ archery bonus require an actual roll
RULE_INT(Combat, ArcheryBonusChance, 50) RULE_INT(Combat, ArcheryBonusChance, 50)
RULE_INT(Combat, BerserkerFrenzyStart, 35) RULE_INT(Combat, BerserkerFrenzyStart, 35)
@ -461,6 +462,7 @@ RULE_INT(Combat, MeleePushChance, 50) // (NPCs) chance the target will be pushed
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, 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_INT(Combat, NPCAssistCapTimer, 6000) // Time in milliseconds a NPC will take to clear assist aggro cap space
RULE_BOOL(Combat, UseRevampHandToHand, false) // use h2h revamped dmg/delays I believe this was implemented during SoF
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(NPC) RULE_CATEGORY(NPC)

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"
@ -954,7 +958,7 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_
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]);

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 9093 #define CURRENT_BINARY_DATABASE_VERSION 9095
#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

@ -111,6 +111,14 @@ sub read_items_file_from_13th_floor_text {
print "Processing (" . $read_items_file . ") :: (Items: " . $total_items . "/" . $total_items_file . ") \r"; 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"; 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 { sub update_items_table {

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|
@ -347,6 +347,8 @@
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| 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| 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|
9095|2016_01_08_command_find_aliases.sql|SELECT * FROM `command_settings` WHERE `command` LIKE 'findaliases'|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,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

@ -0,0 +1 @@
INSERT INTO `command_settings` VALUES ('findaliases', 0, 'fa');

View File

@ -482,7 +482,7 @@ int main(int argc, char** argv) {
if (!database.SaveTime(tod.minute, tod.hour, tod.day, tod.month, tod.year)) if (!database.SaveTime(tod.minute, tod.hour, tod.day, tod.month, tod.year))
Log.Out(Logs::General, Logs::World_Server, "Failed to save eqtime."); Log.Out(Logs::General, Logs::World_Server, "Failed to save eqtime.");
else else
Log.Out(Logs::General, Logs::World_Server, "EQTime successfully saved."); Log.Out(Logs::Detail, Logs::World_Server, "EQTime successfully saved.");
} }
//check for timeouts in other threads //check for timeouts in other threads

View File

@ -846,7 +846,7 @@ int Mob::GetWeaponDamage(Mob *against, const Item_Struct *weapon_item) {
} }
else{ else{
if((GetClass() == MONK || GetClass() == BEASTLORD) && GetLevel() >= 30){ if((GetClass() == MONK || GetClass() == BEASTLORD) && GetLevel() >= 30){
dmg = GetMonkHandToHandDamage(); dmg = GetHandToHandDamage();
} }
else if(GetOwner() && GetLevel() >= RuleI(Combat, PetAttackMagicLevel)){ else if(GetOwner() && GetLevel() >= RuleI(Combat, PetAttackMagicLevel)){
//pets wouldn't actually use this but... //pets wouldn't actually use this but...
@ -868,12 +868,7 @@ int Mob::GetWeaponDamage(Mob *against, const Item_Struct *weapon_item) {
dmg = dmg <= 0 ? 1 : dmg; dmg = dmg <= 0 ? 1 : dmg;
} }
else{ else{
if(GetClass() == MONK || GetClass() == BEASTLORD){ dmg = GetHandToHandDamage();
dmg = GetMonkHandToHandDamage();
}
else{
dmg = 1;
}
} }
} }
@ -1006,7 +1001,7 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate
if((GetClass() == MONK || GetClass() == BEASTLORD)) { if((GetClass() == MONK || GetClass() == BEASTLORD)) {
if(MagicGloves || GetLevel() >= 30){ if(MagicGloves || GetLevel() >= 30){
dmg = GetMonkHandToHandDamage(); dmg = GetHandToHandDamage();
if (hate) *hate += dmg; if (hate) *hate += dmg;
} }
} }
@ -1041,13 +1036,8 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate
} }
} }
else{ else{
if(GetClass() == MONK || GetClass() == BEASTLORD){ dmg = GetHandToHandDamage();
dmg = GetMonkHandToHandDamage(); if (hate) *hate += dmg;
if (hate) *hate += dmg;
}
else{
dmg = 1;
}
} }
} }
@ -2009,15 +1999,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 +2016,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 +2062,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 +2138,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 +2183,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 +2234,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 +2383,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;
} }
@ -2693,82 +2693,140 @@ 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;
} }
} }
int Mob::GetMonkHandToHandDamage(void) int Mob::GetHandToHandDamage(void)
{ {
// Kaiyodo - Determine a monk's fist damage. Table data from www.monkly-business.com if (RuleB(Combat, UseRevampHandToHand)) {
// saved as static array - this should speed this function up considerably // everyone uses this in the revamp!
static int damage[66] = { int skill = GetSkill(SkillHandtoHand);
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int epic = 0;
99, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 46)
8, 8, 8, 8, 8, 9, 9, 9, 9, 9,10,10,10,10,10,11,11,11,11,11, epic = 280;
12,12,12,12,12,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14, if (epic > skill)
14,14,15,15,15,15 }; skill = epic;
return skill / 15 + 3;
// Have a look to see if we have epic fists on
if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652)
return(9);
else
{
int Level = GetLevel();
if (Level > 65)
return(19);
else
return damage[Level];
} }
static uint8 mnk_dmg[] = {99,
4, 4, 4, 4, 5, 5, 5, 5, 5, 6, // 1-10
6, 6, 6, 6, 7, 7, 7, 7, 7, 8, // 11-20
8, 8, 8, 8, 9, 9, 9, 9, 9, 10, // 21-30
10, 10, 10, 10, 11, 11, 11, 11, 11, 12, // 31-40
12, 12, 12, 12, 13, 13, 13, 13, 13, 14, // 41-50
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, // 51-60
14, 14}; // 61-62
static uint8 bst_dmg[] = {99,
4, 4, 4, 4, 4, 5, 5, 5, 5, 5, // 1-10
5, 6, 6, 6, 6, 6, 6, 7, 7, 7, // 11-20
7, 7, 7, 8, 8, 8, 8, 8, 8, 9, // 21-30
9, 9, 9, 9, 9, 10, 10, 10, 10, 10, // 31-40
10, 11, 11, 11, 11, 11, 11, 12, 12}; // 41-49
if (GetClass() == MONK) {
if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 50)
return 9;
if (level > 62)
return 15;
return mnk_dmg[level];
} else if (GetClass() == BEASTLORD) {
if (level > 49)
return 13;
return bst_dmg[level];
}
return 2;
} }
int Mob::GetMonkHandToHandDelay(void) int Mob::GetHandToHandDelay(void)
{ {
// Kaiyodo - Determine a monk's fist delay. Table data from www.monkly-business.com if (RuleB(Combat, UseRevampHandToHand)) {
// saved as static array - this should speed this function up considerably // everyone uses this in the revamp!
static int delayshuman[66] = { int skill = GetSkill(SkillHandtoHand);
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int epic = 0;
99,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, int iksar = 0;
36,36,36,36,36,35,35,35,35,35,34,34,34,34,34,33,33,33,33,33, if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 46)
32,32,32,32,32,31,31,31,31,31,30,30,30,29,29,29,28,28,28,27, epic = 280;
26,24,22,20,20,20 }; else if (GetRace() == IKSAR)
static int delaysiksar[66] = { iksar = 1;
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 if (epic > skill)
99,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, skill = epic;
36,36,36,36,36,36,36,36,36,36,35,35,35,35,35,34,34,34,34,34, return iksar - skill / 21 + 38;
33,33,33,33,33,32,32,32,32,32,31,31,31,30,30,30,29,29,29,28,
27,24,22,20,20,20 };
// Have a look to see if we have epic fists on
if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652)
return(16);
else
{
int Level = GetLevel();
if (GetRace() == HUMAN)
{
if (Level > 65)
return(24);
else
return delayshuman[Level];
}
else //heko: iksar table
{
if (Level > 65)
return(25);
else
return delaysiksar[Level];
}
} }
int delay = 35;
static uint8 mnk_hum_delay[] = {99,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 1-10
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 11-20
35, 35, 35, 35, 35, 35, 35, 34, 34, 34, // 21-30
34, 33, 33, 33, 33, 32, 32, 32, 32, 31, // 31-40
31, 31, 31, 30, 30, 30, 30, 29, 29, 29, // 41-50
29, 28, 28, 28, 28, 27, 27, 27, 27, 26, // 51-60
24, 22}; // 61-62
static uint8 mnk_iks_delay[] = {99,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 1-10
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 11-20
35, 35, 35, 35, 35, 35, 35, 35, 35, 34, // 21-30
34, 34, 34, 34, 34, 33, 33, 33, 33, 33, // 31-40
33, 32, 32, 32, 32, 32, 32, 31, 31, 31, // 41-50
31, 31, 31, 30, 30, 30, 30, 30, 30, 29, // 51-60
25, 23}; // 61-62
static uint8 bst_delay[] = {99,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 1-10
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 11-20
35, 35, 35, 35, 35, 35, 35, 35, 34, 34, // 21-30
34, 34, 34, 33, 33, 33, 33, 33, 32, 32, // 31-40
32, 32, 32, 31, 31, 31, 31, 31, 30, 30, // 41-50
30, 30, 30, 29, 29, 29, 29, 29, 28, 28, // 51-60
28, 28, 28, 27, 27, 27, 27, 27, 26, 26, // 61-70
26, 26, 26}; // 71-73
if (GetClass() == MONK) {
// Have a look to see if we have epic fists on
if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 50)
return 16;
int level = GetLevel();
if (level > 62)
return GetRace() == IKSAR ? 21 : 20;
return GetRace() == IKSAR ? mnk_iks_delay[level] : mnk_hum_delay[level];
} else if (GetClass() == BEASTLORD) {
int level = GetLevel();
if (level > 73)
return 25;
return bst_delay[level];
}
return 35;
} }
int32 Mob::ReduceDamage(int32 damage) int32 Mob::ReduceDamage(int32 damage)
@ -4617,28 +4675,27 @@ void Client::SetAttackTimer()
int hhe = itembonuses.HundredHands + spellbonuses.HundredHands; int hhe = itembonuses.HundredHands + spellbonuses.HundredHands;
int speed = 0; int speed = 0;
int delay = 36; int delay = 3500;
float quiver_haste = 0.0f;
//if we have no weapon.. //if we have no weapon..
if (ItemToUse == nullptr) { if (ItemToUse == nullptr)
//above checks ensure ranged weapons do not fall into here delay = 100 * GetHandToHandDelay();
// Work out if we're a monk
if (GetClass() == MONK || GetClass() == BEASTLORD)
delay = GetMonkHandToHandDelay();
} else {
//we have a weapon, use its delay
delay = ItemToUse->Delay;
if (ItemToUse->ItemType == ItemTypeBow || ItemToUse->ItemType == ItemTypeLargeThrowing)
quiver_haste = GetQuiverHaste();
}
if (RuleB(Spells, Jun182014HundredHandsRevamp))
speed = static_cast<int>(((delay / haste_mod) + ((hhe / 1000.0f) * (delay / haste_mod))) * 100);
else else
speed = static_cast<int>(((delay / haste_mod) + ((hhe / 100.0f) * delay)) * 100); //we have a weapon, use its delay
// this is probably wrong delay = 100 * ItemToUse->Delay;
if (quiver_haste > 0)
speed *= quiver_haste; speed = delay / haste_mod;
if (ItemToUse && ItemToUse->ItemType == ItemTypeBow) {
// Live actually had a bug here where they would return the non-modified attack speed
// rather than the cap ...
speed = std::max(speed - GetQuiverHaste(speed), RuleI(Combat, QuiverHasteCap));
} else {
if (RuleB(Spells, Jun182014HundredHandsRevamp))
speed = static_cast<int>(speed + ((hhe / 1000.0f) * speed));
else
speed = static_cast<int>(speed + ((hhe / 100.0f) * delay));
}
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true); TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true);
} }
} }

View File

@ -6236,31 +6236,44 @@ float Bot::GetProcChances(float ProcBonus, uint16 hand) {
return ProcChance; return ProcChance;
} }
int Bot::GetMonkHandToHandDamage(void) { int Bot::GetHandToHandDamage(void) {
static int damage[66] = { if (RuleB(Combat, UseRevampHandToHand)) {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 // everyone uses this in the revamp!
99, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, int skill = GetSkill(SkillHandtoHand);
8, 8, 8, 8, 8, 9, 9, 9, 9, 9,10,10,10,10,10,11,11,11,11,11, int epic = 0;
12,12,12,12,12,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14, if (CastToNPC()->GetEquipment(MaterialHands) == 10652 && GetLevel() > 46)
14,14,15,15,15,15 }; epic = 280;
if (epic > skill)
skill = epic;
return skill / 15 + 3;
}
uint32 botWeaponId = INVALID_ID; static uint8 mnk_dmg[] = {99,
botWeaponId = CastToNPC()->GetEquipment(MaterialHands); 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, // 1-10
if(botWeaponId == 10652) 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, // 11-20
8, 8, 8, 8, 9, 9, 9, 9, 9, 10, // 21-30
10, 10, 10, 10, 11, 11, 11, 11, 11, 12, // 31-40
12, 12, 12, 12, 13, 13, 13, 13, 13, 14, // 41-50
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, // 51-60
14, 14}; // 61-62
static uint8 bst_dmg[] = {99,
4, 4, 4, 4, 4, 5, 5, 5, 5, 5, // 1-10
5, 6, 6, 6, 6, 6, 6, 7, 7, 7, // 11-20
7, 7, 7, 8, 8, 8, 8, 8, 8, 9, // 21-30
9, 9, 9, 9, 9, 10, 10, 10, 10, 10, // 31-40
10, 11, 11, 11, 11, 11, 11, 12, 12}; // 41-49
if (GetClass() == MONK) {
if (CastToNPC()->GetEquipment(MaterialHands) == 10652 && GetLevel() > 50)
return 9; return 9;
else { if (level > 62)
int Level = GetLevel(); return 15;
if(Level > 65) return mnk_dmg[level];
return 19; } else if (GetClass() == BEASTLORD) {
else if (level > 49)
return damage[Level]; return 13;
} return bst_dmg[level];
}
int Level = GetLevel(); return 2;
if (Level > 65)
return 19;
else
return damage[Level];
} }
bool Bot::TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse) { bool Bot::TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse) {
@ -7012,8 +7025,7 @@ void Bot::SetAttackTimer() {
int speed = 0; int speed = 0;
int delay = 36; int delay = 36;
if (ItemToUse == nullptr) { if (ItemToUse == nullptr) {
if ((GetClass() == MONK) || (GetClass() == BEASTLORD)) delay = GetHandToHandDelay();
delay = GetMonkHandToHandDelay();
} else { } else {
delay = ItemToUse->Delay; delay = ItemToUse->Delay;
} }

View File

@ -171,7 +171,7 @@ public:
uint16 BotGetSpellType(int spellslot) { return AIspells[spellslot].type; } uint16 BotGetSpellType(int spellslot) { return AIspells[spellslot].type; }
uint16 BotGetSpellPriority(int spellslot) { return AIspells[spellslot].priority; } uint16 BotGetSpellPriority(int spellslot) { return AIspells[spellslot].priority; }
virtual float GetProcChances(float ProcBonus, uint16 hand); virtual float GetProcChances(float ProcBonus, uint16 hand);
virtual int GetMonkHandToHandDamage(void); virtual int GetHandToHandDamage(void);
virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse); virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse);
virtual void DoRiposte(Mob* defender); virtual void DoRiposte(Mob* defender);
inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK + ((GetSTR() + GetSkill(SkillOffense)) * 9 / 10); } inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK + ((GetSTR() + GetSkill(SkillOffense)) * 9 / 10); }

View File

@ -6803,7 +6803,8 @@ void Client::SendStatsWindow(Client* client, bool use_window)
/* AC */ indP << "<c \"#CCFF00\">AC: " << CalcAC() << "</c><br>" << /* AC */ indP << "<c \"#CCFF00\">AC: " << CalcAC() << "</c><br>" <<
/* AC2 */ indP << "- Mit: " << GetACMit() << " | Avoid: " << GetACAvoid() << " | Spell: " << spellbonuses.AC << " | Shield: " << shield_ac << "<br>" << /* AC2 */ indP << "- Mit: " << GetACMit() << " | Avoid: " << GetACAvoid() << " | Spell: " << spellbonuses.AC << " | Shield: " << shield_ac << "<br>" <<
/* Haste */ indP << "<c \"#CCFF00\">Haste: " << GetHaste() << "</c><br>" << /* Haste */ indP << "<c \"#CCFF00\">Haste: " << GetHaste() << "</c><br>" <<
/* Haste2 */ indP << " - Item: " << itembonuses.haste << " + Spell: " << (spellbonuses.haste + spellbonuses.hastetype2) << " (Cap: " << RuleI(Character, HasteCap) << ") | Over: " << (spellbonuses.hastetype3 + ExtraHaste) << "<br><br>" << /* Haste2 */ indP << " - Item: " << itembonuses.haste << " + Spell: " << (spellbonuses.haste + spellbonuses.hastetype2) << " (Cap: " << RuleI(Character, HasteCap) << ") | Over: " << (spellbonuses.hastetype3 + ExtraHaste) << "<br>" <<
/* RunSpeed*/ indP << "<c \"#CCFF00\">Runspeed: " << GetRunspeed() << "</c><br>" <<
/* RegenLbl */ indL << indS << "Regen<br>" << indS << indP << indP << " Base | Items (Cap) " << indP << " | Spell | A.A.s | Total<br>" << /* RegenLbl */ indL << indS << "Regen<br>" << indS << indP << indP << " Base | Items (Cap) " << indP << " | Spell | A.A.s | Total<br>" <<
/* Regen */ regen_string << "<br>" << /* Regen */ regen_string << "<br>" <<
/* Stats */ stat_field << "<br><br>" << /* Stats */ stat_field << "<br><br>" <<
@ -8355,21 +8356,19 @@ void Client::ShowNumHits()
return; return;
} }
float Client::GetQuiverHaste() int Client::GetQuiverHaste(int delay)
{ {
float quiver_haste = 0; const ItemInst *pi = nullptr;
for (int r = EmuConstants::GENERAL_BEGIN; r <= EmuConstants::GENERAL_END; r++) { for (int r = EmuConstants::GENERAL_BEGIN; r <= EmuConstants::GENERAL_END; r++) {
const ItemInst *pi = GetInv().GetItem(r); pi = GetInv().GetItem(r);
if (!pi) if (pi && pi->IsType(ItemClassContainer) && pi->GetItem()->BagType == BagTypeQuiver &&
continue; pi->GetItem()->BagWR > 0)
if (pi->IsType(ItemClassContainer) && pi->GetItem()->BagType == BagTypeQuiver) { break;
float temp_wr = (pi->GetItem()->BagWR / RuleI(Combat, QuiverWRHasteDiv)); if (r == EmuConstants::GENERAL_END)
quiver_haste = std::max(temp_wr, quiver_haste); // we will get here if we don't find a valid quiver
} return 0;
} }
if (quiver_haste > 0) return (pi->GetItem()->BagWR * 0.0025f * delay) + 1;
quiver_haste = 1.0f / (1.0f + static_cast<float>(quiver_haste) / 100.0f);
return quiver_haste;
} }
void Client::SendColoredText(uint32 color, std::string message) void Client::SendColoredText(uint32 color, std::string message)

View File

@ -226,7 +226,7 @@ public:
virtual inline bool IsBerserk() { return berserk; } virtual inline bool IsBerserk() { return berserk; }
virtual int32 GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating); virtual int32 GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating);
virtual void SetAttackTimer(); virtual void SetAttackTimer();
float GetQuiverHaste(); int GetQuiverHaste(int delay);
void DoAttackRounds(Mob *target, int hand, bool IsFromSpell = false); void DoAttackRounds(Mob *target, int hand, bool IsFromSpell = false);
void AI_Init(); void AI_Init();

View File

@ -58,8 +58,8 @@ int32 Client::GetMaxResist() const
{ {
int level = GetLevel(); int level = GetLevel();
int32 base = 500; int32 base = 500;
if (level > 60) { if (level > 65) {
base += ((level - 60) * 5); base += ((level - 65) * 5);
} }
return base; return base;
} }

View File

@ -194,6 +194,7 @@ int command_init(void)
command_add("enablerecipe", "[recipe_id] - Enables a recipe using the recipe id.", 80, command_enablerecipe) || command_add("enablerecipe", "[recipe_id] - Enables a recipe using the recipe id.", 80, command_enablerecipe) ||
command_add("equipitem", "[slotid(0-21)] - Equip the item on your cursor into the specified slot", 50, command_equipitem) || command_add("equipitem", "[slotid(0-21)] - Equip the item on your cursor into the specified slot", 50, command_equipitem) ||
command_add("face", "- Change the face of your target", 80, command_face) || command_add("face", "- Change the face of your target", 80, command_face) ||
command_add("findaliases", "[search term]- Searches for available command aliases, by alias or command", 0, command_findaliases) ||
command_add("findnpctype", "[search criteria] - Search database NPC types", 100, command_findnpctype) || command_add("findnpctype", "[search criteria] - Search database NPC types", 100, command_findnpctype) ||
command_add("findspell", "[searchstring] - Search for a spell", 50, command_findspell) || command_add("findspell", "[searchstring] - Search for a spell", 50, command_findspell) ||
command_add("findzone", "[search criteria] - Search database zones", 100, command_findzone) || command_add("findzone", "[search criteria] - Search database zones", 100, command_findzone) ||
@ -4945,6 +4946,38 @@ void command_face(Client *c, const Seperator *sep)
} }
} }
void command_findaliases(Client *c, const Seperator *sep)
{
if (!sep->arg[1][0]) {
c->Message(0, "Usage: #findaliases [alias | command]");
return;
}
std::map<std::string, std::string>::iterator find_iter = commandaliases.find(sep->arg[1]);
if (find_iter == commandaliases.end()) {
c->Message(15, "No commands or aliases match '%s'", sep->arg[1]);
return;
}
std::map<std::string, CommandRecord *>::iterator command_iter = commandlist.find(find_iter->second);
if (find_iter->second.empty() || command_iter == commandlist.end()) {
c->Message(0, "An unknown condition occurred...");
return;
}
c->Message(0, "Available command aliases for '%s':", command_iter->first.c_str());
int commandaliasesshown = 0;
for (std::map<std::string, std::string>::iterator alias_iter = commandaliases.begin(); alias_iter != commandaliases.end(); ++alias_iter) {
if (strcasecmp(find_iter->second.c_str(), alias_iter->second.c_str()) || c->Admin() < command_iter->second->access)
continue;
c->Message(0, "%c%s", COMMAND_CHAR, alias_iter->first.c_str());
++commandaliasesshown;
}
c->Message(0, "%d command alias%s listed.", commandaliasesshown, commandaliasesshown != 1 ? "es" : "");
}
void command_details(Client *c, const Seperator *sep) void command_details(Client *c, const Seperator *sep)
{ {
Mob *target=c->GetTarget(); Mob *target=c->GetTarget();

View File

@ -94,6 +94,7 @@ void command_emoteview(Client* c, const Seperator *sep);
void command_enablerecipe(Client *c, const Seperator *sep); void command_enablerecipe(Client *c, const Seperator *sep);
void command_equipitem(Client *c, const Seperator *sep); void command_equipitem(Client *c, const Seperator *sep);
void command_face(Client *c, const Seperator *sep); void command_face(Client *c, const Seperator *sep);
void command_findaliases(Client *c, const Seperator *sep);
void command_findnpctype(Client *c, const Seperator *sep); void command_findnpctype(Client *c, const Seperator *sep);
void command_findspell(Client *c, const Seperator *sep); void command_findspell(Client *c, const Seperator *sep);
void command_findzone(Client *c, const Seperator *sep); void command_findzone(Client *c, const Seperator *sep);

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

@ -1023,14 +1023,14 @@ int Lua_Mob::GetHaste() {
return self->GetHaste(); return self->GetHaste();
} }
int Lua_Mob::GetMonkHandToHandDamage() { int Lua_Mob::GetHandToHandDamage() {
Lua_Safe_Call_Int(); Lua_Safe_Call_Int();
return self->GetMonkHandToHandDamage(); return self->GetHandToHandDamage();
} }
int Lua_Mob::GetMonkHandToHandDelay() { int Lua_Mob::GetHandToHandDelay() {
Lua_Safe_Call_Int(); Lua_Safe_Call_Int();
return self->GetMonkHandToHandDelay(); return self->GetHandToHandDelay();
} }
void Lua_Mob::Mesmerize() { void Lua_Mob::Mesmerize() {
@ -2165,8 +2165,8 @@ luabind::scope lua_register_mob() {
.def("GetInvul", (bool(Lua_Mob::*)(void))&Lua_Mob::GetInvul) .def("GetInvul", (bool(Lua_Mob::*)(void))&Lua_Mob::GetInvul)
.def("SetExtraHaste", (void(Lua_Mob::*)(int))&Lua_Mob::SetExtraHaste) .def("SetExtraHaste", (void(Lua_Mob::*)(int))&Lua_Mob::SetExtraHaste)
.def("GetHaste", (int(Lua_Mob::*)(void))&Lua_Mob::GetHaste) .def("GetHaste", (int(Lua_Mob::*)(void))&Lua_Mob::GetHaste)
.def("GetMonkHandToHandDamage", (int(Lua_Mob::*)(void))&Lua_Mob::GetMonkHandToHandDamage) .def("GetHandToHandDamage", (int(Lua_Mob::*)(void))&Lua_Mob::GetHandToHandDamage)
.def("GetMonkHandToHandDelay", (int(Lua_Mob::*)(void))&Lua_Mob::GetMonkHandToHandDelay) .def("GetHandToHandDelay", (int(Lua_Mob::*)(void))&Lua_Mob::GetHandToHandDelay)
.def("Mesmerize", (void(Lua_Mob::*)(void))&Lua_Mob::Mesmerize) .def("Mesmerize", (void(Lua_Mob::*)(void))&Lua_Mob::Mesmerize)
.def("IsMezzed", (bool(Lua_Mob::*)(void))&Lua_Mob::IsMezzed) .def("IsMezzed", (bool(Lua_Mob::*)(void))&Lua_Mob::IsMezzed)
.def("IsEnraged", (bool(Lua_Mob::*)(void))&Lua_Mob::IsEnraged) .def("IsEnraged", (bool(Lua_Mob::*)(void))&Lua_Mob::IsEnraged)
@ -2303,7 +2303,7 @@ 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::*)(void))&Lua_Mob::SetPseudoRoot) .def("SetPseudoRoot", (void(Lua_Mob::*)(bool))&Lua_Mob::SetPseudoRoot)
.def("SeeInvisible", (uint8(Lua_Mob::*)(void))&Lua_Mob::SeeInvisible) .def("SeeInvisible", (uint8(Lua_Mob::*)(void))&Lua_Mob::SeeInvisible)
.def("SeeInvisibleUndead", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeInvisibleUndead) .def("SeeInvisibleUndead", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeInvisibleUndead)
.def("SeeHide", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeHide) .def("SeeHide", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeHide)

View File

@ -217,8 +217,8 @@ public:
bool GetInvul(); bool GetInvul();
void SetExtraHaste(int haste); void SetExtraHaste(int haste);
int GetHaste(); int GetHaste();
int GetMonkHandToHandDamage(); int GetHandToHandDamage();
int GetMonkHandToHandDelay(); int GetHandToHandDelay();
void Mesmerize(); void Mesmerize();
bool IsMezzed(); bool IsMezzed();
bool IsEnraged(); bool IsEnraged();

View File

@ -428,6 +428,11 @@ float Lua_NPC::GetAttackSpeed() {
return self->GetAttackSpeed(); return self->GetAttackSpeed();
} }
int Lua_NPC::GetAttackDelay() {
Lua_Safe_Call_Int();
return self->GetAttackDelay();
}
int Lua_NPC::GetAccuracyRating() { int Lua_NPC::GetAccuracyRating() {
Lua_Safe_Call_Int(); Lua_Safe_Call_Int();
return self->GetAccuracyRating(); return self->GetAccuracyRating();
@ -550,6 +555,7 @@ luabind::scope lua_register_npc() {
.def("GetSpellFocusHeal", (void(Lua_NPC::*)(int))&Lua_NPC::GetSpellFocusHeal) .def("GetSpellFocusHeal", (void(Lua_NPC::*)(int))&Lua_NPC::GetSpellFocusHeal)
.def("GetSlowMitigation", (int(Lua_NPC::*)(void))&Lua_NPC::GetSlowMitigation) .def("GetSlowMitigation", (int(Lua_NPC::*)(void))&Lua_NPC::GetSlowMitigation)
.def("GetAttackSpeed", (float(Lua_NPC::*)(void))&Lua_NPC::GetAttackSpeed) .def("GetAttackSpeed", (float(Lua_NPC::*)(void))&Lua_NPC::GetAttackSpeed)
.def("GetAttackDelay", (int(Lua_NPC::*)(void))&Lua_NPC::GetAttackDelay)
.def("GetAccuracyRating", (int(Lua_NPC::*)(void))&Lua_NPC::GetAccuracyRating) .def("GetAccuracyRating", (int(Lua_NPC::*)(void))&Lua_NPC::GetAccuracyRating)
.def("GetSpawnKillCount", (int(Lua_NPC::*)(void))&Lua_NPC::GetSpawnKillCount) .def("GetSpawnKillCount", (int(Lua_NPC::*)(void))&Lua_NPC::GetSpawnKillCount)
.def("GetScore", (int(Lua_NPC::*)(void))&Lua_NPC::GetScore) .def("GetScore", (int(Lua_NPC::*)(void))&Lua_NPC::GetScore)

View File

@ -111,6 +111,7 @@ public:
int GetSpellFocusHeal(); int GetSpellFocusHeal();
float GetSlowMitigation(); float GetSlowMitigation();
float GetAttackSpeed(); float GetAttackSpeed();
int GetAttackDelay();
int GetAccuracyRating(); int GetAccuracyRating();
int GetSpawnKillCount(); int GetSpawnKillCount();
int GetScore(); int GetScore();

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

@ -756,7 +756,7 @@ public:
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);
virtual int GetMonkHandToHandDamage(void); virtual int GetHandToHandDamage(void);
bool CanThisClassDoubleAttack(void) const; bool CanThisClassDoubleAttack(void) const;
bool CanThisClassTripleAttack() const; bool CanThisClassTripleAttack() const;
@ -766,7 +766,7 @@ public:
bool CanThisClassParry(void) const; bool CanThisClassParry(void) const;
bool CanThisClassBlock(void) const; bool CanThisClassBlock(void) const;
int GetMonkHandToHandDelay(void); int GetHandToHandDelay(void);
uint32 GetClassLevelFactor(); uint32 GetClassLevelFactor();
void Mesmerize(); void Mesmerize();
inline bool IsMezzed() const { return mezzed; } inline bool IsMezzed() const { return mezzed; }

View File

@ -843,6 +843,54 @@ 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->size = .1;
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 = 3000;
point.y = 1000;
point.z = 500;
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

@ -4721,12 +4721,12 @@ XS(XS_Mob_GetHaste)
XSRETURN(1); XSRETURN(1);
} }
XS(XS_Mob_GetMonkHandToHandDamage); /* prototype to pass -Wmissing-prototypes */ XS(XS_Mob_GetHandToHandDamage); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_GetMonkHandToHandDamage) XS(XS_Mob_GetHandToHandDamage)
{ {
dXSARGS; dXSARGS;
if (items != 1) if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::GetMonkHandToHandDamage(THIS)"); Perl_croak(aTHX_ "Usage: Mob::GetHandToHandDamage(THIS)");
{ {
Mob * THIS; Mob * THIS;
int RETVAL; int RETVAL;
@ -4741,7 +4741,7 @@ XS(XS_Mob_GetMonkHandToHandDamage)
if(THIS == nullptr) if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetMonkHandToHandDamage(); RETVAL = THIS->GetHandToHandDamage();
XSprePUSH; PUSHi((IV)RETVAL); XSprePUSH; PUSHi((IV)RETVAL);
} }
XSRETURN(1); XSRETURN(1);
@ -4877,12 +4877,12 @@ XS(XS_Mob_CanThisClassParry)
XSRETURN(1); XSRETURN(1);
} }
XS(XS_Mob_GetMonkHandToHandDelay); /* prototype to pass -Wmissing-prototypes */ XS(XS_Mob_GetHandToHandDelay); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_GetMonkHandToHandDelay) XS(XS_Mob_GetHandToHandDelay)
{ {
dXSARGS; dXSARGS;
if (items != 1) if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::GetMonkHandToHandDelay(THIS)"); Perl_croak(aTHX_ "Usage: Mob::GetHandToHandDelay(THIS)");
{ {
Mob * THIS; Mob * THIS;
int RETVAL; int RETVAL;
@ -4897,7 +4897,7 @@ XS(XS_Mob_GetMonkHandToHandDelay)
if(THIS == nullptr) if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetMonkHandToHandDelay(); RETVAL = THIS->GetHandToHandDelay();
XSprePUSH; PUSHi((IV)RETVAL); XSprePUSH; PUSHi((IV)RETVAL);
} }
XSRETURN(1); XSRETURN(1);
@ -9192,13 +9192,13 @@ XS(boot_Mob)
newXSproto(strcpy(buf, "GetInvul"), XS_Mob_GetInvul, file, "$"); newXSproto(strcpy(buf, "GetInvul"), XS_Mob_GetInvul, file, "$");
newXSproto(strcpy(buf, "SetExtraHaste"), XS_Mob_SetExtraHaste, file, "$$"); newXSproto(strcpy(buf, "SetExtraHaste"), XS_Mob_SetExtraHaste, file, "$$");
newXSproto(strcpy(buf, "GetHaste"), XS_Mob_GetHaste, file, "$"); newXSproto(strcpy(buf, "GetHaste"), XS_Mob_GetHaste, file, "$");
newXSproto(strcpy(buf, "GetMonkHandToHandDamage"), XS_Mob_GetMonkHandToHandDamage, file, "$"); newXSproto(strcpy(buf, "GetHandToHandDamage"), XS_Mob_GetHandToHandDamage, file, "$");
newXSproto(strcpy(buf, "CanThisClassDoubleAttack"), XS_Mob_CanThisClassDoubleAttack, file, "$"); newXSproto(strcpy(buf, "CanThisClassDoubleAttack"), XS_Mob_CanThisClassDoubleAttack, file, "$");
newXSproto(strcpy(buf, "CanThisClassDualWield"), XS_Mob_CanThisClassDualWield, file, "$"); newXSproto(strcpy(buf, "CanThisClassDualWield"), XS_Mob_CanThisClassDualWield, file, "$");
newXSproto(strcpy(buf, "CanThisClassRiposte"), XS_Mob_CanThisClassRiposte, file, "$"); newXSproto(strcpy(buf, "CanThisClassRiposte"), XS_Mob_CanThisClassRiposte, file, "$");
newXSproto(strcpy(buf, "CanThisClassDodge"), XS_Mob_CanThisClassDodge, file, "$"); newXSproto(strcpy(buf, "CanThisClassDodge"), XS_Mob_CanThisClassDodge, file, "$");
newXSproto(strcpy(buf, "CanThisClassParry"), XS_Mob_CanThisClassParry, file, "$"); newXSproto(strcpy(buf, "CanThisClassParry"), XS_Mob_CanThisClassParry, file, "$");
newXSproto(strcpy(buf, "GetMonkHandToHandDelay"), XS_Mob_GetMonkHandToHandDelay, file, "$"); newXSproto(strcpy(buf, "GetHandToHandDelay"), XS_Mob_GetHandToHandDelay, file, "$");
newXSproto(strcpy(buf, "GetClassLevelFactor"), XS_Mob_GetClassLevelFactor, file, "$"); newXSproto(strcpy(buf, "GetClassLevelFactor"), XS_Mob_GetClassLevelFactor, file, "$");
newXSproto(strcpy(buf, "Mesmerize"), XS_Mob_Mesmerize, file, "$"); newXSproto(strcpy(buf, "Mesmerize"), XS_Mob_Mesmerize, file, "$");
newXSproto(strcpy(buf, "IsMezzed"), XS_Mob_IsMezzed, file, "$"); newXSproto(strcpy(buf, "IsMezzed"), XS_Mob_IsMezzed, file, "$");

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

@ -1268,6 +1268,14 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
} }
} }
// we're done casting, now try to apply the spell
if( !SpellFinished(spell_id, spell_target, slot, mana_used, inventory_slot, resist_adjust) )
{
Log.Out(Logs::Detail, Logs::Spells, "Casting of %d canceled: SpellFinished returned false.", spell_id);
InterruptSpell();
return;
}
if(IsClient()) { if(IsClient()) {
CheckNumHitsRemaining(NumHit::MatchingSpells); CheckNumHitsRemaining(NumHit::MatchingSpells);
TrySympatheticProc(target, spell_id); TrySympatheticProc(target, spell_id);
@ -1277,14 +1285,6 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
TryTriggerOnCast(spell_id, 0); TryTriggerOnCast(spell_id, 0);
// we're done casting, now try to apply the spell
if( !SpellFinished(spell_id, spell_target, slot, mana_used, inventory_slot, resist_adjust) )
{
Log.Out(Logs::Detail, Logs::Spells, "Casting of %d canceled: SpellFinished returned false.", spell_id);
InterruptSpell();
return;
}
if(DeleteChargeFromSlot >= 0) if(DeleteChargeFromSlot >= 0)
CastToClient()->DeleteItemInInventory(DeleteChargeFromSlot, 1, true); CastToClient()->DeleteItemInInventory(DeleteChargeFromSlot, 1, true);
@ -5310,6 +5310,7 @@ void Client::SendBuffDurationPacket(Buffs_Struct &buff)
EQApplicationPacket* outapp; EQApplicationPacket* outapp;
outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffFade_Struct)); outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffFade_Struct));
SpellBuffFade_Struct* sbf = (SpellBuffFade_Struct*) outapp->pBuffer; SpellBuffFade_Struct* sbf = (SpellBuffFade_Struct*) outapp->pBuffer;
int index;
sbf->entityid = GetID(); sbf->entityid = GetID();
sbf->slot = 2; sbf->slot = 2;
@ -5317,6 +5318,19 @@ void Client::SendBuffDurationPacket(Buffs_Struct &buff)
sbf->slotid = 0; sbf->slotid = 0;
sbf->level = buff.casterlevel > 0 ? buff.casterlevel : GetLevel(); sbf->level = buff.casterlevel > 0 ? buff.casterlevel : GetLevel();
// We really don't know what to send as sbf->effect.
// The code used to send level (and still does for cases we don't know)
//
// The fixes below address known issues with sending level in this field.
// Typically, when the packet is sent, or when the user
// next does something on the UI that causes an update (like opening a
// pack), the stats updated by the spell in question get corrupted.
//
// The values were determined by trial and error. I could not find a
// pattern or find a field in spells_new that would work.
sbf->effect=sbf->level;
if (IsEffectInSpell(buff.spellid, SE_TotalHP)) if (IsEffectInSpell(buff.spellid, SE_TotalHP))
{ {
// If any of the lower 6 bits are set, the GUI changes MAX_HP AGAIN. // If any of the lower 6 bits are set, the GUI changes MAX_HP AGAIN.
@ -5327,25 +5341,45 @@ void Client::SendBuffDurationPacket(Buffs_Struct &buff)
else if (IsEffectInSpell(buff.spellid, SE_CurrentHP)) else if (IsEffectInSpell(buff.spellid, SE_CurrentHP))
{ {
// This is mostly a problem when we try and update duration on a // This is mostly a problem when we try and update duration on a
// dot or a hp->mana conversion. Zero cancels the effect, any // dot or a hp->mana conversion. Zero cancels the effect
// other value has the GUI doing that value at the same time server // Sending teh actual change again seems to work.
// is doing theirs. This makes the two match. index = GetSpellEffectIndex(buff.spellid, SE_CurrentHP);
int index = GetSpellEffectIndex(buff.spellid, SE_CurrentHP);
sbf->effect = abs(spells[buff.spellid].base[index]); sbf->effect = abs(spells[buff.spellid].base[index]);
} }
else if (IsEffectInSpell(buff.spellid, SE_SeeInvis)) else if (IsEffectInSpell(buff.spellid, SE_SeeInvis))
{ {
// Wish I knew what this sbf->effect field was trying to tell // 10 seems to not break SeeInvis spells. Level,
// the client. 10 seems to not break SeeInvis spells. Level,
// which is what the old client sends breaks the client at at // which is what the old client sends breaks the client at at
// least level 9, maybe more. // least level 9, maybe more.
sbf->effect = 10; sbf->effect = 10;
} }
else else if (IsEffectInSpell(buff.spellid, SE_ArmorClass) ||
IsEffectInSpell(buff.spellid, SE_ResistFire) ||
IsEffectInSpell(buff.spellid, SE_ResistCold) ||
IsEffectInSpell(buff.spellid, SE_ResistPoison) ||
IsEffectInSpell(buff.spellid, SE_ResistDisease) ||
IsEffectInSpell(buff.spellid, SE_ResistMagic) ||
IsEffectInSpell(buff.spellid, SE_STR) ||
IsEffectInSpell(buff.spellid, SE_STA) ||
IsEffectInSpell(buff.spellid, SE_DEX) ||
IsEffectInSpell(buff.spellid, SE_WIS) ||
IsEffectInSpell(buff.spellid, SE_INT) ||
IsEffectInSpell(buff.spellid, SE_AGI))
{ {
// Default to what old code did until we find a better fix for // This seems to work. Previosly stats got corrupted when sending
// other spell lines. // level.
sbf->effect=sbf->level; sbf->effect = 46;
}
else if (IsEffectInSpell(buff.spellid, SE_CHA))
{
index = GetSpellEffectIndex(buff.spellid, SE_CHA);
sbf->effect = abs(spells[buff.spellid].base[index]);
// Only use this valie if its not a spacer.
if (sbf->effect != 0)
{
// Same as other stats, need this to prevent a double update.
sbf->effect = 46;
}
} }
sbf->bufffade = 0; sbf->bufffade = 0;