diff --git a/README.md b/README.md
index 154703a75..a56251c19 100644
--- a/README.md
+++ b/README.md
@@ -1,54 +1,59 @@
-EQEmu
-===
+# EQEmulator Core Server
+|Travis CI (Linux)|Appveyor (Windows) |
+|:---:|:---:|
+|[](https://travis-ci.org/EQEmu/Server) |[](https://ci.appveyor.com/project/KimLS/server/branch/master) |
-[](https://travis-ci.org/EQEmu/Server)
-[](https://ci.appveyor.com/project/KimLS/server/branch/master)
+***
-Overview
----
+**EQEmulator is a custom completely from-scratch open source server implementation for EverQuest built mostly on C++**
+ * MySQL/MariaDB is used as the database engine (over 200+ tables)
+ * Perl and LUA are both supported scripting languages for NPC/Player/Quest oriented events
+ * Open source database (Project EQ) has content up to expansion GoD (included in server installs)
+ * Game server environments and databases can be heavily customized to create all new experiences
+ * Hundreds of Quests/events created and maintained by Project EQ
-EQEmu is a custom server implementation for EverQuest
+## Server Installs
+||Windows|Linux|
+|:---:|:---:|:---:|
+|**Install Count**|||
+### > Windows
+* [Easy Install](http://wiki.eqemulator.org/p?Akkas_PEQ_Server_Installer&frm=Main#from-scratch-installation-instructions-windows)
+* [Advanced Setup](http://wiki.eqemulator.org/p?Complete_Windows-based_Server_Setup_Guide)
-Dependencies
----
+### > Debian/Ubuntu
-For Windows: http://eqemu.github.io
+> wget --no-check-certificate https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh -O install.sh && chmod 755 install.sh && ./install.sh
-Login Server dependencies for Windows/Linux/OSX: http://eqemu.github.io
+### > CentOS/Fedora
-For Debian based distros (adjust to your local flavor):
+> curl -O https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh install.sh && chmod 755 install.sh && ./install.sh
-- libmysqlclient-dev
-- libperl-dev
-- liblua5.1-0-dev (5.2 should work as well)
-- libboost-dev
+## Supported Clients
-Further instructions on building the source can be found on the
-[wiki](http://wiki.eqemulator.org/i?M=Wiki).
+|Titanium Edition|Secrets of Faydwer|Seeds of Destruction|Underfoot|Rain of Fear|
+|:---:|:---:|:---:|:---:|:---:|
+|
|
|
|
|
|
-Bug reports
----
-
-Please use the [issue tracker](https://github.com/EQEmu/Server/issues) provided by GitHub to send us bug
+## Bug Reports
+* Please use the [issue tracker](https://github.com/EQEmu/Server/issues) provided by GitHub to send us bug
reports or feature requests.
+* The [EQEmu Forums](http://www.eqemulator.org/forums/) are also a place to submit and get help with bugs.
-The [EQEmu Forums](http://www.eqemulator.org/forums/) also have forums to submit
-bugs/get help with bugs.
+## Contributions
-Contributions
----
-
-The preferred way to contribute is to fork the repo and submit a pull request on
+* The preferred way to contribute is to fork the repo and submit a pull request on
GitHub. If you need help with your changes, you can always post on the forums or
-try IRC. You can also post unified diffs (`git diff` should do the trick) on the
+try Discord. You can also post unified diffs (`git diff` should do the trick) on the
[Server Code Submissions](http://www.eqemulator.org/forums/forumdisplay.php?f=669)
forum, although pull requests will be much quicker and easier on all parties.
-Contact
----
- - **User IRC Channel**: `#eqemu` on `irc.eqemulator.net`
- - **Developer IRC Channel**: `#eqemucoders` on `irc.eqemulator.net`
+## Contact
+ - Discord Channel: https://discord.gg/QHsm7CD
+ - **User Discord Channel**: `#general`
+ - **Developer Discord Channel**: `#eqemucoders`
+
+Resources
+---
- [EQEmulator Forums](http://www.eqemulator.org/forums)
- [EQEmulator Wiki](http://wiki.eqemulator.org/i?M=Wiki)
-
diff --git a/changelog.txt b/changelog.txt
index 2aa32e8ac..b2d7c7b05 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,5 +1,9 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
+== 09/03/2016 ==
+Uleat: Changed 'Bind Wound' behavior to match the best references that I could find for post-2004 era.
+ Note: If you wish to retain the old method, source in the optional '2016_09_03_old_bind_wound_rule.sql' script file.
+
== 08/27/2016 ==
Kinglykrab: Added optional IP-based account exemptions.
- To use this system simply set World:EnableIPExemptions to true and create an entry in the ip_exemptions table.
diff --git a/common/ruletypes.h b/common/ruletypes.h
index f1898a559..7837834f9 100644
--- a/common/ruletypes.h
+++ b/common/ruletypes.h
@@ -145,6 +145,8 @@ RULE_BOOL(Character, UseStackablePickPocketing, true) // Allows stackable pickpo
RULE_BOOL(Character, EnableAvoidanceCap, false)
RULE_INT(Character, AvoidanceCap, 750) // 750 Is a pretty good value, seen people dodge all attacks beyond 1,000 Avoidance
RULE_BOOL(Character, AllowMQTarget, false) // Disables putting players in the 'hackers' list for targeting beyond the clip plane or attempting to target something untargetable
+RULE_BOOL(Character, UseOldBindWound, false) // Uses the original bind wound behavior
+
RULE_CATEGORY_END()
RULE_CATEGORY(Mercs)
diff --git a/common/servertalk.h b/common/servertalk.h
index e476d023d..b0197985f 100644
--- a/common/servertalk.h
+++ b/common/servertalk.h
@@ -193,6 +193,7 @@
#define ServerOP_QSSendQuery 0x5016
#define ServerOP_CZSignalNPC 0x5017
#define ServerOP_CZSetEntityVariableByNPCTypeID 0x5018
+#define ServerOP_WWMarquee 0x5019
/* Query Serv Generic Packet Flag/Type Enumeration */
enum { QSG_LFGuild = 0 };
@@ -1254,6 +1255,15 @@ struct CZMessagePlayer_Struct {
char Message[512];
};
+struct WWMarquee_Struct {
+ uint32 Type;
+ uint32 Priority;
+ uint32 FadeIn;
+ uint32 FadeOut;
+ uint32 Duration;
+ char Message[512];
+};
+
struct CZSetEntVarByNPCTypeID_Struct {
uint32 npctype_id;
char id[256];
diff --git a/utils/scripts/eqemu_server.pl b/utils/scripts/eqemu_server.pl
index 484c5f306..821736fef 100644
--- a/utils/scripts/eqemu_server.pl
+++ b/utils/scripts/eqemu_server.pl
@@ -24,8 +24,22 @@ $eqemu_repository_request_url = "https://raw.githubusercontent.com/EQEmu/Server/
#::: Globals
$time_stamp = strftime('%m-%d-%Y', gmtime());
$db_run_stage = 0; #::: Sets database run stage check
-if($Config{osname}=~/freebsd|linux/i){ $OS = "Linux"; }
-if($Config{osname}=~/Win|MS/i){ $OS = "Windows"; }
+if($Config{osname}=~/freebsd|linux/i){
+ $OS = "Linux";
+ $os_flavor = "";
+ if(-e "/etc/debian_version"){
+ $os_flavor = "debian";
+ }
+ elsif(-e "/etc/fedora-release"){
+ $os_flavor = "fedora_core";
+ }
+ elsif(-e "/etc/redhat-release"){
+ $os_flavor = "red_hat";
+ }
+}
+if($Config{osname}=~/Win|MS/i){
+ $OS = "Windows";
+}
$has_internet_connection = check_internet_connection();
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime();
@@ -38,9 +52,7 @@ get_mysql_path();
#::: Remove old eqemu_update.pl
if(-e "eqemu_update.pl"){
unlink("eqemu_update.pl");
-}
-#::: Create db_update working directory if not created
-mkdir('db_update');
+}
print "[Info] For EQEmu Server management utilities - run eqemu_server.pl\n" if $ARGV[0] eq "ran_from_world";
@@ -51,103 +63,292 @@ if(trim(get_mysql_result("SHOW COLUMNS FROM db_version LIKE 'Revision'")) ne ""
}
check_db_version_table();
-
check_for_world_bootup_database_update();
-if($db){
- print "[Update] MySQL Path/Location: " . $path . "\n";
- print "[Update] Binary Revision / Local: (" . $binary_database_version . " / " . $local_database_version . ")\n";
+sub urlencode {
+ my ($rv) = @_;
+ $rv =~ s/([^A-Za-z0-9])/sprintf("%%%2.2X", ord($1))/ge;
+ return $rv;
+}
+
+sub urldecode {
+ my ($rv) = @_;
+ $rv =~ s/\+/ /g;
+ $rv =~ s/%(..)/pack("c",hex($1))/ge;
+ return $rv;
+}
+
+sub analytics_insertion {
+ $event_name = urlencode($_[0]);
+ $event_data = urlencode($_[1]);
- #::: Bots
- #::: Make sure we're running a bots binary to begin with
- if(trim($db_version[2]) > 0){
- $bots_local_db_version = get_bots_db_version();
- if($bots_local_db_version > 0){
- print "[Update] (Bots) Binary Revision / Local: (" . trim($db_version[2]) . " / " . $bots_local_db_version . ")\n";
- }
+ #::: Check for internet connection before doing analytics
+ if(!$has_internet_connection || $can_see_analytics_server == -1){
+ return;
}
-
- #::: If World ran this script, and our version is up to date, continue...
- if($binary_database_version <= $local_database_version && $ARGV[0] eq "ran_from_world"){
- print "[Update] Database up to Date: Continuing World Bootup...\n";
- exit;
- }
-}
-
-if($ARGV[0] eq "remove_duplicate_rules"){
- remove_duplicate_rule_values();
- exit;
-}
-
-if($ARGV[0] eq "map_files_fetch_bulk"){
- map_files_fetch_bulk();
- exit;
-}
-
-if($ARGV[0] eq "loginserver_install_linux"){
- do_linux_login_server_setup();
- exit;
-}
-
-if($ARGV[0] eq "new_server"){
- while(1){
- print "For a new server folder install, we assume Perl and MySQL are configured\n";
- print "This will install a fresh PEQ Database, with all server assets\n";
- print "You will need to supply database credentials to get started...\n";
-
- check_for_input("MySQL User: ");
- $database_user = trim($input);
-
- check_for_input("MySQL Password: ");
- $database_password = trim($input);
-
- $check_connection = `mysql -u $database_user -p$database_password -N -B -e "SHOW PROCESSLIST" > mysqlcheck.txt`;
- $mysql_pass = 0;
- open (MYSQL_CHECK, "mysqlcheck.txt");
- while (){
- chomp;
- $o = $_;
- if($o=~/Error/i){ $mysql_pass = 0;}
- if($o=~/SHOW PROCESSLIST/i){ $mysql_pass = 1; }
+
+ #::: Check for analytics server connectivity so that the script doesn't break when its offline
+ if(!$can_see_analytics_server){
+ if($OS eq "Linux"){
+ $count = "c";
+ }
+ if($OS eq "Windows"){
+ $count = "n";
}
- close (MYSQL_CHECK);
- unlink("mysqlcheck.txt");
- if($mysql_pass == 1){
- print "Success! We have a database connection\n";
-
- check_for_input("Specify a database name: ");
- $database_name = trim($input);
-
- #::: Write install vars
- open (INSTALL_VARS, '>', 'install_variables.txt');
- print INSTALL_VARS "";
- print INSTALL_VARS "mysql_eqemu_db_name:" . $database_name . "\n";
- print INSTALL_VARS "mysql_eqemu_user:" . $database_user . "\n";
- print INSTALL_VARS "mysql_eqemu_password:" . $database_password . "\n";
- close (INSTALL_VARS);
-
- do_installer_routines();
+ if (`ping analytics.akkadius.com -$count 1 -w 500`=~/Reply from|1 received/i) {
+ $can_see_analytics_server = 1;
}
else {
- print "Authorization failed\n";
+ $can_see_analytics_server = -1;
+ }
+ }
+
+ $server_name = "";
+ if($long_name){
+ $server_name = "&server_name=" . urlencode($long_name);
+ }
+
+ if(!$extended_os){
+ if($OS eq "Linux"){
+ $extended_os = `cat /proc/version`;
+ $extended_os = trim($extended_os);
+ }
+ if($OS eq "Windows"){
+ my $output = `ver`;
+ my @os_version = split("\n", $output);
+ foreach my $val (@os_version){
+ if($val=~/Windows/i){
+ $extended_os = trim($val);
+ }
+ }
+ }
+ }
+
+ $url = "http://analytics.akkadius.com/";
+ $url .= "?api_key=24a0bde2e5bacd65bcab06a9ac40b62c";
+ $url .= "&event=" . $event_name;
+ $url .= "&event_data=" . $event_data;
+ $url .= "&OS=" . urlencode($OS);
+ $url .= "&extended_os=" . urlencode($extended_os);
+ $url .= $server_name;
+
+ # print "Calling url :: '" . $url . "'\n";
+
+ if($OS eq "Windows"){
+ eval('require LWP::UserAgent;');
+ my $ua = LWP::UserAgent->new;
+ $ua->timeout(1);
+ $ua->env_proxy;
+ my $response = $ua->get($url);
+ }
+ if($OS eq "Linux"){
+ $api_call = `curl -s "$url"`;
+ }
+}
+
+sub show_install_summary_info {
+ print "[Install] Installation complete...\n";
+ print "[Install] Server Info (Save somewhere if needed):\n";
+
+ if (-e "install_variables.txt") {
+ $file_to_open = "install_variables.txt";
+ }
+ elsif(-e "../install_variables.txt"){
+ $file_to_open = "../install_variables.txt";
+ }
+ open (INSTALL_VARS, $file_to_open);
+ while (){
+ chomp;
+ $o = $_;
+ @data = split(":", $o);
+ print " - " . $data[0] . "\t" . $data[1] . "\n";
+ }
+ close (INSTALL_VARS);
+
+ if($OS eq "Windows"){
+ print "[Install] Windows Utility Scripts:\n";
+ print " - t_start_server.bat Starts EQEmu server with 30 dynamic zones, UCS & Queryserv, dynamic zones\n";
+ print " - t_start_server_with_loginserver.bat Starts EQEmu server with 30 zones with loginserver\n";
+ print " - t_stop_server.bat Stops EQEmu Server (No warning)\n";
+ print " - t_database_backup.bat Backs up the Database to backups/ folder - do not run during server is online\n";
+ print " - t_server_crash_report.pl Will parse any zone crashes for reporting to developers\n";
+ }
+ if($OS eq "Linux"){
+ print "[Install] Linux Utility Scripts:\n";
+ print " - server_start.sh Starts EQEmu server (Quiet) with 30 dynamic zones, UCS & Queryserv, dynamic zones\n";
+ print " - server_start_dev.sh Starts EQEmu server with 10 dynamic zones, UCS & Queryserv, dynamic zones all verbose\n";
+ print " - server_stop.sh Stops EQEmu Server (No warning)\n";
+ print " - server_status.sh Prints the status of the EQEmu Server processes\n";
+ }
+
+ print "[Configure] eqemu_config.xml Edit to change server settings and name\n";
+
+ analytics_insertion("install_complete", "null");
+}
+
+sub new_server {
+ $file_count = 0;
+ opendir(DIR, ".") or die $!;
+ while (my $file = readdir(DIR)) {
+ next if ($file =~ m/^\./);
+ $file_count++;
+ }
+ closedir(DIR);
+
+ if($file_count > 1 && (!-e "install_variables.txt" && !-e "../install_variables.txt")){
+ print "[New Server] ERROR: You must run eqemu_server.pl in an empty directory\n";
+ <>;
+ exit;
+ }
+
+ if(-e "install_variables.txt" || -e "../install_variables.txt"){
+ get_installation_variables();
+ }
+
+ while(1){
+
+ $database_name = $installation_variables{"mysql_eqemu_db_name"};
+ $database_user = $installation_variables{"mysql_eqemu_user"};
+ $database_password = $installation_variables{"mysql_eqemu_password"};
+
+ if($database_name ne ""){
+ $mysql_pass = 1;
+ }
+ else {
+
+ print "\n";
+ print "[New Server] For a new server folder install, we assume Perl and MySQL are configured\n";
+ print "[New Server] This will install a fresh PEQ Database, with all server assets\n";
+ print "[New Server] You will need to supply database credentials to get started...\n\n";
+
+ check_for_input("MySQL User: ");
+ $database_user = trim($input);
+
+ check_for_input("MySQL Password: ");
+ $database_password = trim($input);
+
+ $check_connection = `mysql -u $database_user -p$database_password -N -B -e "SHOW PROCESSLIST" > mysqlcheck.txt`;
+ $mysql_pass = 0;
+ open (MYSQL_CHECK, "mysqlcheck.txt");
+ while (){
+ chomp;
+ $o = $_;
+ if($o=~/Error/i){ $mysql_pass = 0;}
+ if($o=~/SHOW PROCESSLIST/i){ $mysql_pass = 1; }
+ }
+ close (MYSQL_CHECK);
+ unlink("mysqlcheck.txt");
+ }
+
+ if($mysql_pass == 1){
+
+ if((!-e "install_variables.txt" && !-e "../install_variables.txt")){
+ print "[New Server] Success! We have a database connection\n";
+
+ check_for_input("Specify a NEW database name that PEQ will be installed to: ");
+ $database_name = trim($input);
+
+ #::: Write install vars
+ open (INSTALL_VARS, '>', 'install_variables.txt');
+ print INSTALL_VARS "";
+ print INSTALL_VARS "mysql_eqemu_db_name:" . $database_name . "\n";
+ print INSTALL_VARS "mysql_eqemu_user:" . $database_user . "\n";
+ print INSTALL_VARS "mysql_eqemu_password:" . $database_password . "\n";
+ close (INSTALL_VARS);
+ }
+ analytics_insertion("new_server::install", $database_name);
+
+ if($OS eq "Linux"){
+ build_linux_source();
+ }
+
+ do_installer_routines();
+
+ if($OS eq "Linux"){
+ print `chmod 755 *.sh`;
+ }
+
+ analytics_insertion("new_server::install_complete", $database_name . " :: Binary DB Version / Local DB Version :: " . $binary_database_version . " / " . $local_database_version);
+
+ print "[New Server] New server folder install complete\n";
+ print "[New Server] Below is your installation info:\n";
+
+ show_install_summary_info();
+
+ return;
+ }
+ else {
+ print "[New Server] MySQL authorization failed or no MySQL installed\n";
}
}
}
-if($ARGV[0] eq "installer"){
- do_installer_routines();
- exit;
+sub build_linux_source {
+
+ $build_options = $_[0];
+
+ $cmake_options = "";
+ $source_folder_post_fix = "";
+
+ if($build_options =~/bots/i){
+ $cmake_options .= " -DEQEMU_ENABLE_BOTS=ON";
+ $source_folder_post_fix = "_bots";
+ }
+
+ $current_directory = `pwd`;
+ @directories = split('/', $current_directory);
+ foreach my $val (@directories){
+ if(trim($val) ne ""){
+ $last_directory = trim($val);
+ }
+ }
+ my $eqemu_server_directory = "/home/eqemu";
+ my $source_dir = $eqemu_server_directory . '/' . $last_directory . '_source' . $source_folder_post_fix;
+
+ $current_directory = trim($current_directory);
+
+ mkdir($source_dir) if (!-e $source_dir);
+
+ # print 'server_dir: ' . $eqemu_server_directory . "\n";
+ # print 'source_dir: ' . $source_dir . "\n";
+ # print 'current_dir: \'' . $current_directory . "'\n";
+
+ chdir($source_dir);
+
+ print `git clone https://github.com/EQEmu/Server.git`;
+
+ mkdir ($source_dir . "/Server/build") if (!-e $source_dir . "/Server/build");
+ chdir ($source_dir . "/Server/build");
+
+ print "Generating CMake build files...\n";
+ if($os_flavor eq "fedora_core"){
+ print `cmake $cmake_options -DEQEMU_BUILD_LUA=ON -DLUA_INCLUDE_DIR=/usr/include/lua-5.1/ -G "Unix Makefiles" ..`;
+ }
+ else {
+ print `cmake $cmake_options -DEQEMU_BUILD_LUA=ON -G "Unix Makefiles" ..`;
+ }
+ print "Building EQEmu Server code. This will take a while.";
+
+ #::: Build
+ print `make`;
+
+ chdir ($current_directory);
+
+ print `ln -s -f $source_dir/Server/build/bin/eqlaunch .`;
+ print `ln -s -f $source_dir/Server/build/bin/export_client_files .`;
+ print `ln -s -f $source_dir/Server/build/bin/import_client_files .`;
+ print `ln -s -f $source_dir/Server/build/bin/libcommon.a .`;
+ print `ln -s -f $source_dir/Server/build/bin/libluabind.a .`;
+ print `ln -s -f $source_dir/Server/build/bin/queryserv .`;
+ print `ln -s -f $source_dir/Server/build/bin/shared_memory .`;
+ print `ln -s -f $source_dir/Server/build/bin/ucs .`;
+ print `ln -s -f $source_dir/Server/build/bin/world .`;
+ print `ln -s -f $source_dir/Server/build/bin/zone .`;
}
-if($ARGV[0] eq "db_dump_compress"){ database_dump_compress(); exit; }
-if($ARGV[0] eq "login_server_setup"){
- do_windows_login_server_setup();
- exit;
-}
-
sub do_installer_routines {
- print "[Install] Running EQEmu Server installer routines...\n";
+ print "[Install] EQEmu Server Installer... LOADING... PLEASE WAIT...\n";
#::: Make some local server directories...
mkdir('logs');
@@ -170,6 +371,7 @@ sub do_installer_routines {
get_remote_file($install_repository_request_url . "zlib1.dll", "zlib1.dll", 1);
get_remote_file($install_repository_request_url . "libmysql.dll", "libmysql.dll", 1);
}
+
map_files_fetch_bulk();
opcodes_fetch();
plugins_fetch();
@@ -198,19 +400,19 @@ sub do_installer_routines {
print "[Database] Applying Latest Database Updates...\n";
main_db_management();
+ remove_duplicate_rule_values();
+
if($OS eq "Windows"){
check_windows_firewall_rules();
do_windows_login_server_setup();
}
if($OS eq "Linux"){
do_linux_login_server_setup();
-
- print "[Install] Installation complete!\n";
}
}
sub check_for_input {
- print $_[0];
+ print "[Input] " . $_[0];
$input = ;
chomp $input;
}
@@ -226,12 +428,35 @@ sub check_for_world_bootup_database_update {
$binary_database_version = trim($db_version[1]);
$local_database_version = trim(get_mysql_result("SELECT version FROM db_version LIMIT 1"));
+ #::: Bots
+ $bots_binary_version = trim($db_version[2]);
+ if($bots_binary_version > 0){
+ $bots_local_db_version = get_bots_db_version();
+ #::: We ran world - Database needs to update, lets backup and run updates and continue world bootup
+
+ if($bots_local_db_version < $bots_binary_version && $ARGV[0] eq "ran_from_world"){
+ print "[Update] Bots Database not up to date with binaries... Automatically updating...\n";
+ print "[Update] Issuing database backup first...\n";
+ database_dump_compress();
+ print "[Update] Updating bots database...\n";
+ sleep(1);
+ bots_db_management();
+ run_database_check();
+ print "[Update] Continuing bootup\n";
+ analytics_insertion("auto database bots upgrade world", $db . " :: Binary DB Version / Local DB Version :: " . $binary_database_version . " / " . $local_database_version);
+
+ exit;
+ }
+ else {
+ print "[Update] Bots database up to Date: Continuing World Bootup...\n";
+ }
+ }
+
if($binary_database_version == $local_database_version && $ARGV[0] eq "ran_from_world"){
print "[Update] Database up to date...\n";
exit;
}
else {
-
#::: We ran world - Database needs to update, lets backup and run updates and continue world bootup
if($local_database_version < $binary_database_version && $ARGV[0] eq "ran_from_world"){
print "[Update] Database not up to date with binaries... Automatically updating...\n";
@@ -242,11 +467,13 @@ sub check_for_world_bootup_database_update {
main_db_management();
main_db_management();
print "[Update] Continuing bootup\n";
+ analytics_insertion("auto database upgrade world", $db . " :: Binary DB Version / Local DB Version :: " . $binary_database_version . " / " . $local_database_version);
+
exit;
}
#::: Make sure that we didn't pass any arugments to the script
- if(!$ARGV[0]){
+ else {
if(!$db){ print "[eqemu_server.pl] No database connection found... Running without\n"; }
show_menu_prompt();
}
@@ -254,13 +481,13 @@ sub check_for_world_bootup_database_update {
}
sub check_internet_connection {
- if($OS eq "Linux"){
+ if($OS eq "Linux"){
$count = "c";
}
if($OS eq "Windows"){
$count = "n";
}
-
+
if (`ping 8.8.8.8 -$count 1 -w 500`=~/Reply from|1 received/i) {
# print "[Update] We have a connection to the internet, continuing...\n";
return 1;
@@ -279,7 +506,7 @@ sub get_perl_version {
#::: Check Perl version
$perl_version = $^V;
$perl_version =~s/v//g;
- print "[Update] Perl Version is " . $perl_version . "\n";
+ print "[Update] Perl Version is " . $perl_version . "\n" if $debug;
if($perl_version > 5.12){
no warnings 'uninitialized';
}
@@ -287,13 +514,15 @@ sub get_perl_version {
}
sub do_self_update_check_routine {
- #::: Check Version passed from world to update script
- get_remote_file($eqemu_repository_request_url . "utils/scripts/eqemu_server.pl", "updates_staged/eqemu_server.pl", 0, 1, 1);
-
+
+ #::: Check for internet connection before updating
if(!$has_internet_connection){
print "[Update] Cannot check update without internet connection...\n";
return;
}
+
+ #::: Check for script changes :: eqemu_server.pl
+ get_remote_file($eqemu_repository_request_url . "utils/scripts/eqemu_server.pl", "updates_staged/eqemu_server.pl", 0, 1, 1);
if(-e "updates_staged/eqemu_server.pl") {
@@ -383,6 +612,11 @@ sub do_install_config_xml {
my($replace_key) = $o =~ />(\w+);
$new_key = generate_random_password(30);
$o =~ s/$replace_key/$new_key/g;
+ }
+ if($o=~/\/i){
+ my($replace_name) = $o =~ /(.*)<\/longname>/;
+ $append = '(' . generate_random_password(5) . ')';
+ $o =~ s/$replace_name/Akkas $OS PEQ Installer $append/g;
}
if($o=~/\/i && $in_database_tag){
my($replace_username) = $o =~ />(\w+);
@@ -432,18 +666,37 @@ sub fetch_utility_scripts {
}
}
+sub setup_bots {
+ if($OS eq "Windows"){
+ fetch_latest_windows_binaries_bots();
+ }
+ if($OS eq "Linux"){
+ build_linux_source("bots");
+ }
+ bots_db_management();
+ run_database_check();
+
+ print "Bots should be setup, run your server and the #bot command should be available in-game\n";
+}
+
sub show_menu_prompt {
$dc = 0;
while (1) {
- $input = trim($input);
+
+ if($ARGV[0] ne ""){
+ $input = trim($ARGV[0]);
+ }
+ else {
+ $input = trim($input);
+ }
$errored_command = 0;
if($input eq "database"){
print "\n>>> Database Menu\n\n";
print " [backup_database] Back up database to backups/ directory\n";
- print " [backup_player_tables] Back up player tables to backups/ directory\n";
+ print " [backup_player_tables] Back up player tables to backups/ directory\n";
print " [backup_database_compressed] Back up database compressed to backups/ directory\n";
print " \n";
print " [check_db_updates] Checks for database updates manually\n";
@@ -491,9 +744,11 @@ sub show_menu_prompt {
elsif($input eq "windows_server_download_bots"){ fetch_latest_windows_binaries_bots(); $dc = 1; }
elsif($input eq "fetch_dlls"){ fetch_server_dlls(); $dc = 1; }
elsif($input eq "utility_scripts"){ fetch_utility_scripts(); $dc = 1; }
- elsif($input eq "check_db_updates"){ main_db_management(); $dc = 1; }
- elsif($input eq "check_bot_db_updates"){ bots_db_management(); $dc = 1; }
+ elsif($input eq "check_db_updates"){ main_db_management(); main_db_management(); $dc = 1; }
+ elsif($input eq "check_bot_db_updates"){ bots_db_management(); run_database_check(); $dc = 1; }
elsif($input eq "setup_loginserver"){ do_windows_login_server_setup(); $dc = 1; }
+ elsif($input eq "new_server"){ new_server(); $dc = 1; }
+ elsif($input eq "setup_bots"){ setup_bots(); $dc = 1; }
elsif($input eq "exit"){
exit;
}
@@ -517,14 +772,23 @@ sub show_menu_prompt {
if($errored_command == 1){
$input = $last_menu;
}
- elsif($dc == 1){
+ elsif($dc == 1){
+ analytics_insertion("menu", trim($input));
$dc = 0;
$input = "";
}
else {
$input = <>;
}
- }
+
+ #::: If we're processing a CLI command, kill the loop
+ if($ARGV[0] ne ""){
+ analytics_insertion("cli", trim($input));
+ $input = "";
+ $ARGV[0] = "";
+ exit;
+ }
+ }
}
sub print_main_menu {
@@ -532,7 +796,10 @@ sub print_main_menu {
print ">>> EQEmu Server Main Menu >>>>>>>>>>>>\n";
print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n\n";
print " [database] Enter database management menu \n";
- print " [assets] Manage server assets \n\n";
+ print " [assets] Manage server assets \n";
+ print " [new_server] New folder EQEmu/PEQ install - Assumes MySQL/Perl installed \n";
+ print " [setup_bots] Enables bots on server - builds code and database requirements \n";
+ print "\n";
print " exit \n";
print "\n";
print "Enter a command #> ";
@@ -568,13 +835,52 @@ sub get_mysql_path {
}
sub check_for_database_dump_script{
- if(`perl db_dumper.pl`=~/Need arguments/i){
- return;
+ #::: Check for internet connection before updating
+ if(!$has_internet_connection){
+ print "[Update] Cannot check update without internet connection...\n";
+ return;
}
- else{
- print "[Database] db_dumper.pl not found... retrieving...\n";
- get_remote_file($eqemu_repository_request_url . "utils/scripts/db_dumper.pl", "db_dumper.pl");
+
+ #::: Check for script changes :: db_dumper.pl
+ get_remote_file($eqemu_repository_request_url . "utils/scripts/db_dumper.pl", "updates_staged/db_dumper.pl", 0, 1, 1);
+
+ if(-e "updates_staged/db_dumper.pl") {
+
+ my $remote_script_size = -s "updates_staged/db_dumper.pl";
+ my $local_script_size = -s "db_dumper.pl";
+
+ if($remote_script_size != $local_script_size){
+ print "[Update] Script has been updated, updating...\n";
+
+ my @files;
+ my $start_dir = "updates_staged/";
+ find(
+ sub { push @files, $File::Find::name unless -d; },
+ $start_dir
+ );
+ for my $file (@files) {
+ if($file=~/db_dumper/i){
+ $destination_file = $file;
+ $destination_file =~s/updates_staged\///g;
+ print "[Install] Installing :: " . $destination_file . "\n";
+ unlink($destination_file);
+ copy_file($file, $destination_file);
+ if($OS eq "Linux"){
+ system("chmod 755 db_dumper.pl");
+ }
+ }
+ }
+ print "[Install] Done\n";
+ }
+ else {
+ print "[Update] No script update necessary...\n";
+ }
+
+ unlink("updates_staged/db_dumper.pl");
}
+
+ return;
+
}
sub database_dump {
@@ -601,7 +907,7 @@ sub database_dump_player_tables {
print `perl db_dumper.pl database="$db" loc="backups" tables="$tables" backup_name="player_tables_export" nolock`;
print "[Database] Press any key to continue...\n";
-
+
<>; #Read from STDIN
}
@@ -762,13 +1068,11 @@ sub read_eqemu_config_xml {
my $indb = 0;
while() {
s/\r//g;
- if(//i) { $indb = 1; }
- next unless($indb == 1);
- if(/<\/database>/i) { $indb = 0; last; }
if(/(.*)<\/host>/i) { $host = $1; }
elsif(/(.*)<\/username>/i) { $user = $1; }
elsif(/(.*)<\/password>/i) { $pass = $1; }
elsif(/(.*)<\/db>/i) { $db = $1; }
+ if(/(.*)<\/longname>/i) { $long_name = $1; }
}
}
@@ -1016,11 +1320,11 @@ sub add_login_server_firewall_rules {
$val=~s/Rule Name://g;
if($val=~/EQEmu Loginserver/i && $val=~/Titanium/i){
$has_loginserver_rules_titanium = 1;
- print "Found existing rule :: " . trim($val) . "\n";
+ print "[Install] Found existing rule :: " . trim($val) . "\n";
}
if($val=~/EQEmu Loginserver/i && $val=~/SOD/i){
$has_loginserver_rules_sod = 1;
- print "Found existing rule :: " . trim($val) . "\n";
+ print "[Install] Found existing rule :: " . trim($val) . "\n";
}
}
}
@@ -1619,6 +1923,13 @@ sub get_bots_db_version{
}
sub bots_db_management{
+ if($OS eq "Windows"){
+ @db_version = split(': ', `world db_version`);
+ }
+ if($OS eq "Linux"){
+ @db_version = split(': ', `./world db_version`);
+ }
+
#::: Main Binary Database version
$binary_database_version = trim($db_version[2]);
@@ -1637,6 +1948,8 @@ sub bots_db_management{
$bots_local_db_version = get_bots_db_version();
+ $local_database_version = $bots_local_db_version;
+
run_database_check();
}
@@ -1718,13 +2031,13 @@ sub run_database_check{
@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...
- if($local_database_version > 9000){
+ if($local_database_version >= 9000){
$revision_check = $local_database_version;
}
else {
$revision_check = 1000;
if(get_mysql_result("SHOW TABLES LIKE 'character_data'") ne ""){
- $revision_check = 9000;
+ $revision_check = 8999;
}
}
@@ -1841,4 +2154,4 @@ sub generate_random_password {
map $alphanumeric[rand @alphanumeric], 0..$passwordsize;
return $randpassword;
-}
+}
\ No newline at end of file
diff --git a/utils/scripts/eqemu_update.pl b/utils/scripts/eqemu_update.pl
deleted file mode 100644
index cb94dca0a..000000000
--- a/utils/scripts/eqemu_update.pl
+++ /dev/null
@@ -1,1789 +0,0 @@
-#!/usr/bin/perl
-
-###########################################################
-#::: General EQEmu Server Administration Script
-#::: Purpose - Handles:
-#::: Automatic database versioning (bots and normal DB)
-#::: Updating server assets (binary, opcodes, maps, configuration files)
-#::: Original Author: Akkadius
-#::: Contributors: Uleat
-#::: Purpose: To upgrade databases with ease and maintain versioning
-###########################################################
-
-use Config;
-use File::Copy qw(copy);
-use POSIX qw(strftime);
-use File::Path;
-use File::Find;
-use Time::HiRes qw(usleep);
-
-#::: Variables
-$install_repository_request_url = "https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/";
-$eqemu_repository_request_url = "https://raw.githubusercontent.com/EQEmu/Server/master/";
-
-#::: Globals
-$time_stamp = strftime('%m-%d-%Y', gmtime());
-$db_run_stage = 0; #::: Sets database run stage check
-if($Config{osname}=~/freebsd|linux/i){ $OS = "Linux"; }
-if($Config{osname}=~/Win|MS/i){ $OS = "Windows"; }
-$has_internet_connection = check_internet_connection();
-($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime();
-
-#::: Check for script self update
-do_self_update_check_routine();
-get_perl_version();
-read_eqemu_config_xml();
-get_mysql_path();
-
-#::: Remove old eqemu_update.pl
-if(-e "eqemu_update.pl"){
- unlink("eqemu_update.pl");
-}
-#::: Create db_update working directory if not created
-mkdir('db_update');
-
-print "[Info] For EQEmu Server management utilities - run eqemu_server.pl\n";
-
-#::: Check if db_version table exists...
-if(trim(get_mysql_result("SHOW COLUMNS FROM db_version LIKE 'Revision'")) ne "" && $db){
- print get_mysql_result("DROP TABLE db_version");
- print "[Database] Old db_version table present, dropping...\n\n";
-}
-
-check_db_version_table();
-
-check_for_world_bootup_database_update();
-
-if($db){
- print "[Update] MySQL Path/Location: " . $path . "\n";
- print "[Update] Binary Revision / Local: (" . $binary_database_version . " / " . $local_database_version . ")\n";
-
- #::: Bots
- #::: Make sure we're running a bots binary to begin with
- if(trim($db_version[2]) > 0){
- $bots_local_db_version = get_bots_db_version();
- if($bots_local_db_version > 0){
- print "[Update] (Bots) Binary Revision / Local: (" . trim($db_version[2]) . " / " . $bots_local_db_version . ")\n";
- }
- }
-
- #::: If World ran this script, and our version is up to date, continue...
- if($binary_database_version <= $local_database_version && $ARGV[0] eq "ran_from_world"){
- print "[Update] Database up to Date: Continuing World Bootup...\n";
- exit;
- }
-}
-
-if($ARGV[0] eq "remove_duplicate_rules"){
- remove_duplicate_rule_values();
- exit;
-}
-
-if($ARGV[0] eq "map_files_fetch_bulk"){
- map_files_fetch_bulk();
- exit;
-}
-
-if($ARGV[0] eq "loginserver_install_linux"){
- do_linux_login_server_setup();
- exit;
-}
-
-if($ARGV[0] eq "installer"){
- print "[Install] Running EQEmu Server installer routines...\n";
-
- #::: Make some local server directories...
- mkdir('logs');
- mkdir('updates_staged');
- mkdir('shared');
-
- do_install_config_xml();
- read_eqemu_config_xml();
- get_installation_variables();
-
- $db_name = "peq";
- if($installation_variables{"mysql_eqemu_db_name"}){
- $db_name = $installation_variables{"mysql_eqemu_db_name"};
- }
-
- #::: Download assets
- if($OS eq "Windows"){
- fetch_latest_windows_binaries();
- get_remote_file($install_repository_request_url . "lua51.dll", "lua51.dll", 1);
- get_remote_file($install_repository_request_url . "zlib1.dll", "zlib1.dll", 1);
- get_remote_file($install_repository_request_url . "libmysql.dll", "libmysql.dll", 1);
- }
- map_files_fetch_bulk();
- opcodes_fetch();
- plugins_fetch();
- quest_files_fetch();
- lua_modules_fetch();
- fetch_utility_scripts();
-
- #::: Database Routines
- print "[Database] 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"`;
-
- #::: Get Binary DB version
- if($OS eq "Windows"){ @db_version = split(': ', `world db_version`); }
- if($OS eq "Linux"){ @db_version = split(': ', `./world db_version`); }
- $binary_database_version = trim($db_version[1]);
-
- #::: Local DB Version
- check_db_version_table();
- $local_database_version = trim(get_mysql_result("SELECT version FROM db_version LIMIT 1"));
-
- #::: Download PEQ latest
- fetch_peq_db_full();
- print "[Database] Fetching Latest Database Updates...\n";
- main_db_management();
- print "[Database] Applying Latest Database Updates...\n";
- main_db_management();
-
- if($OS eq "Windows"){
- check_windows_firewall_rules();
- do_windows_login_server_setup();
- }
- if($OS eq "Linux"){
- do_linux_login_server_setup();
-
- print "[Install] Installation complete!\n";
- }
-
- exit;
-}
-
-if($ARGV[0] eq "db_dump_compress"){ database_dump_compress(); exit; }
-if($ARGV[0] eq "login_server_setup"){
- do_windows_login_server_setup();
- exit;
-}
-
-sub check_for_world_bootup_database_update {
- if($OS eq "Windows"){
- @db_version = split(': ', `world db_version`);
- }
- if($OS eq "Linux"){
- @db_version = split(': ', `./world db_version`);
- }
-
- $binary_database_version = trim($db_version[1]);
- $local_database_version = trim(get_mysql_result("SELECT version FROM db_version LIMIT 1"));
-
- if($binary_database_version == $local_database_version && $ARGV[0] eq "ran_from_world"){
- print "[Update] Database up to date...\n";
- exit;
- }
- else {
-
- #::: We ran world - Database needs to update, lets backup and run updates and continue world bootup
- if($local_database_version < $binary_database_version && $ARGV[0] eq "ran_from_world"){
- print "[Update] Database not up to date with binaries... Automatically updating...\n";
- print "[Update] Issuing database backup first...\n";
- database_dump_compress();
- print "[Update] Updating database...\n";
- sleep(1);
- main_db_management();
- main_db_management();
- print "[Update] Continuing bootup\n";
- exit;
- }
-
- #::: Make sure that we didn't pass any arugments to the script
- if(!$ARGV[0]){
- if(!$db){ print "[eqemu_server.pl] No database connection found... Running without\n"; }
- show_menu_prompt();
- }
- }
-}
-
-sub check_internet_connection {
- if($OS eq "Linux"){
- $count = "c";
- }
- if($OS eq "Windows"){
- $count = "n";
- }
-
- if (`ping 8.8.8.8 -$count 1 -w 500`=~/Reply from|1 received/i) {
- # print "[Update] We have a connection to the internet, continuing...\n";
- return 1;
- }
- elsif (`ping 4.2.2.2 -$count 1 -w 500`=~/Reply from|1 received/i) {
- # print "[Update] We have a connection to the internet, continuing...\n";
- return 1;
- }
- else{
- print "[Update] No connection to the internet, can't check update\n";
- return;
- }
-}
-
-sub get_perl_version {
- #::: Check Perl version
- $perl_version = $^V;
- $perl_version =~s/v//g;
- print "[Update] Perl Version is " . $perl_version . "\n";
- if($perl_version > 5.12){
- no warnings 'uninitialized';
- }
- no warnings;
-}
-
-sub do_self_update_check_routine {
- #::: Check Version passed from world to update script
- get_remote_file($eqemu_repository_request_url . "utils/scripts/eqemu_server.pl", "updates_staged/eqemu_server.pl", 0, 1, 1);
-
- if(!$has_internet_connection){
- print "[Update] Cannot check update without internet connection...\n";
- return;
- }
-
- if(-e "updates_staged/eqemu_server.pl") {
-
- my $remote_script_size = -s "updates_staged/eqemu_server.pl";
- my $local_script_size = -s "eqemu_server.pl";
-
- if($remote_script_size != $local_script_size){
- print "[Update] Script has been updated, updating...\n";
-
- my @files;
- my $start_dir = "updates_staged/";
- find(
- sub { push @files, $File::Find::name unless -d; },
- $start_dir
- );
- for my $file (@files) {
- if($file=~/eqemu_server/i){
- $destination_file = $file;
- $destination_file =~s/updates_staged\///g;
- print "[Install] Installing :: " . $destination_file . "\n";
- unlink($destination_file);
- copy_file($file, $destination_file);
- if($OS eq "Linux"){
- system("chmod 755 eqemu_server.pl");
- }
- system("perl eqemu_server.pl start_from_world");
- }
- }
- print "[Install] Done\n";
- }
- else {
- print "[Update] No script update necessary...\n";
- }
-
- unlink("updates_staged/eqemu_server.pl");
- }
-}
-
-sub get_installation_variables{
- #::: Fetch installation variables before building the config
- if($OS eq "Linux"){
- open (INSTALL_VARS, "../install_variables.txt");
- }
- if($OS eq "Windows"){
- open (INSTALL_VARS, "install_variables.txt");
- }
- while (){
- chomp;
- $o = $_;
- @data = split(":", $o);
- $installation_variables{trim($data[0])} = trim($data[1]);
- }
- close (INSTALL_VARS);
-}
-
-sub do_install_config_xml {
- get_installation_variables();
-
- #::: Fetch XML template
- get_remote_file($install_repository_request_url . "eqemu_config.xml", "eqemu_config_template.xml");
-
- #::: Open new config file
- open (NEW_CONFIG, '>', 'eqemu_config.xml');
-
- $in_database_tag = 0;
-
- #::: Iterate through template and replace variables...
- open (FILE_TEMPLATE, "eqemu_config_template.xml");
- while (){
- chomp;
- $o = $_;
-
- #::: Find replace variables
-
- if($o=~/\<\!--/i){
- next;
- }
-
- if($o=~/database/i && $o=~/\<\//i){
- $in_database_tag = 0;
- }
- if($o=~/database/i){
- $in_database_tag = 1;
- }
-
- if($o=~/key/i){
- my($replace_key) = $o =~ />(\w+);
- $new_key = generate_random_password(30);
- $o =~ s/$replace_key/$new_key/g;
- }
- if($o=~/\/i && $in_database_tag){
- my($replace_username) = $o =~ />(\w+);
- $o =~ s/$replace_username/$installation_variables{"mysql_eqemu_user"}/g;
- }
- if($o=~/\/i && $in_database_tag){
- my($replace_password) = $o =~ />(\w+);
- $o =~ s/$replace_password/$installation_variables{"mysql_eqemu_password"}/g;
- }
- if($o=~/\/i){
- my($replace_db_name) = $o =~ />(\w+);
-
- #::: There is really no reason why this shouldn't be set
- if($installation_variables{"mysql_eqemu_db_name"}){
- $db_name = $installation_variables{"mysql_eqemu_db_name"};
- }
- else {
- $db_name = "peq";
- }
-
- $o =~ s/$replace_db_name/$db_name/g;
- }
- print NEW_CONFIG $o . "\n";
- }
-
- close(FILE_TEMPLATE);
- close(NEW_CONFIG);
- unlink("eqemu_config_template.xml");
-}
-
-sub fetch_utility_scripts {
- if($OS eq "Windows"){
- get_remote_file($install_repository_request_url . "t_database_backup.bat", "t_database_backup.bat");
- get_remote_file($install_repository_request_url . "t_start_server.bat", "t_start_server.bat");
- get_remote_file($install_repository_request_url . "t_start_server_with_login_server.bat", "t_start_server_with_login_server.bat");
- get_remote_file($install_repository_request_url . "t_stop_server.bat", "t_stop_server.bat");
- get_remote_file($install_repository_request_url . "t_server_crash_report.pl", "t_server_crash_report.pl");
- get_remote_file($install_repository_request_url . "win_server_launcher.pl", "win_server_launcher.pl");
- get_remote_file($install_repository_request_url . "t_start_server_with_login_server.bat", "t_start_server_with_login_server.bat");
- }
- else {
- get_remote_file($install_repository_request_url . "linux/server_launcher.pl", "server_launcher.pl");
- get_remote_file($install_repository_request_url . "linux/server_start.sh", "server_start.sh");
- get_remote_file($install_repository_request_url . "linux/server_start_dev.sh", "server_start_dev.sh");
- get_remote_file($install_repository_request_url . "linux/server_status.sh", "server_status.sh");
- get_remote_file($install_repository_request_url . "linux/server_stop.sh", "server_stop.sh");
- }
-}
-
-sub show_menu_prompt {
-
- $dc = 0;
- while (1) {
- $input = trim($input);
-
- $errored_command = 0;
-
- if($input eq "database"){
- print "\n>>> Database Menu\n\n";
- print " [backup_database] Back up database to backups/ directory\n";
- print " [backup_player_tables] Back up player tables to backups/ directory\n";
- print " [backup_database_compressed] Back up database compressed to backups/ directory\n";
- print " \n";
- print " [check_db_updates] Checks for database updates manually\n";
- print " [check_bot_db_updates] Checks for bot database updates\n";
- print " \n";
- print " [aa_tables] Downloads and installs clean slate AA data from PEQ\n";
- print " [remove_duplicate_rules] Removes duplicate rules from rule_values table\n";
- print " [drop_bots_db_schema] Removes bot database schema\n";
-
- print " \n> main - go back to main menu\n";
- print "Enter a command #> ";
- $last_menu = trim($input);
- }
- elsif($input eq "assets"){
- print "\n>>> Server Assets Menu\n\n";
- print " [maps] Download latest maps\n";
- print " [opcodes] Download opcodes (Patches for eq clients)\n";
- print " [quests] Download latest quests\n";
- print " [plugins] Download latest plugins\n";
- print " [lua_modules] Download latest lua_modules\n";
- print " [utility_scripts] Download utility scripts to run and operate the EQEmu Server\n";
- if($OS eq "Windows"){
- print ">>> Windows\n";
- print " [windows_server_download] Updates server code from latest stable\n";
- print " [windows_server_download_bots] Updates server code (bots enabled) from latest\n";
- print " [fetch_dlls] Grabs dll's needed to run windows binaries\n";
- print " [setup_loginserver] Sets up loginserver for Windows\n";
- }
- print " \n> main - go back to main menu\n";
- print "Enter a command #> ";
- $last_menu = trim($input);
- }
- elsif($input eq "backup_database"){ database_dump(); $dc = 1; }
- elsif($input eq "backup_player_tables"){ database_dump_player_tables(); $dc = 1; }
- elsif($input eq "backup_database_compressed"){ database_dump_compress(); $dc = 1; }
- elsif($input eq "drop_bots_db_schema"){ do_bots_db_schema_drop(); $dc = 1; }
- elsif($input eq "aa_tables"){ aa_fetch(); $dc = 1; }
- elsif($input eq "remove_duplicate_rules"){ remove_duplicate_rule_values(); $dc = 1; }
- elsif($input eq "maps"){ map_files_fetch_bulk(); $dc = 1; }
- elsif($input eq "opcodes"){ opcodes_fetch(); $dc = 1; }
- elsif($input eq "plugins"){ plugins_fetch(); $dc = 1; }
- elsif($input eq "quests"){ quest_files_fetch(); $dc = 1; }
- elsif($input eq "lua_modules"){ lua_modules_fetch(); $dc = 1; }
- elsif($input eq "windows_server_download"){ fetch_latest_windows_binaries(); $dc = 1; }
- elsif($input eq "windows_server_download_bots"){ fetch_latest_windows_binaries_bots(); $dc = 1; }
- elsif($input eq "fetch_dlls"){ fetch_server_dlls(); $dc = 1; }
- elsif($input eq "utility_scripts"){ fetch_utility_scripts(); $dc = 1; }
- elsif($input eq "check_db_updates"){ main_db_management(); $dc = 1; }
- elsif($input eq "check_bot_db_updates"){ bots_db_management(); $dc = 1; }
- elsif($input eq "setup_loginserver"){ do_windows_login_server_setup(); $dc = 1; }
- elsif($input eq "exit"){
- exit;
- }
- elsif($input eq "main"){
- print "Returning to main menu...\n";
- print_main_menu();
- $last_menu = trim($input);
- }
- elsif($input eq "" && $last_menu ne ""){
- $errored_command = 1;
- }
- elsif($input ne ""){
- print "Invalid command '" . $input . "'\n";
- $errored_command = 1;
- }
- else {
- print_main_menu();
- }
-
- #::: Errored command checking
- if($errored_command == 1){
- $input = $last_menu;
- }
- elsif($dc == 1){
- $dc = 0;
- $input = "";
- }
- else {
- $input = <>;
- }
- }
-}
-
-sub print_main_menu {
- print "\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n";
- print ">>> EQEmu Server Main Menu >>>>>>>>>>>>\n";
- print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n\n";
- print " [database] Enter database management menu \n";
- print " [assets] Manage server assets \n\n";
- print " exit \n";
- print "\n";
- print "Enter a command #> ";
-}
-
-sub get_mysql_path {
- if($OS eq "Windows"){
- $has_mysql_path = `echo %PATH%`;
- if($has_mysql_path=~/MySQL|MariaDB/i){
- @mysql = split(';', $has_mysql_path);
- foreach my $v (@mysql){
- if($v=~/MySQL|MariaDB/i){
- $v =~s/\n//g;
- $path = trim($v) . "/mysql";
- last;
- }
- }
- }
- }
- if($OS eq "Linux"){
- $path = `which mysql`;
- if ($path eq "") {
- $path = `which mariadb`;
- }
- $path =~s/\n//g;
- }
-
- #::: Path not found, error and exit
- if($path eq ""){
- print "[Error:eqemu_server.pl] MySQL path not found, please add the path for automatic database upgrading to continue... \n\n";
- exit;
- }
-}
-
-sub check_for_database_dump_script{
- if(`perl db_dumper.pl`=~/Need arguments/i){
- return;
- }
- else{
- print "[Database] db_dumper.pl not found... retrieving...\n";
- get_remote_file($eqemu_repository_request_url . "utils/scripts/db_dumper.pl", "db_dumper.pl");
- }
-}
-
-sub database_dump {
- check_for_database_dump_script();
- print "[Database] Performing database backup....\n";
- print `perl db_dumper.pl database="$db" loc="backups"`;
-}
-
-sub database_dump_player_tables {
- check_for_database_dump_script();
- print "[Database] Performing database backup of player tables....\n";
- get_remote_file($eqemu_repository_request_url . "utils/sql/character_table_list.txt", "backups/character_table_list.txt");
-
- $tables = "";
- open (FILE, "backups/character_table_list.txt");
- $i = 0;
- while (){
- chomp;
- $o = $_;
- $tables .= $o . ",";
- }
- $tables = substr($tables, 0, -1);
-
- print `perl db_dumper.pl database="$db" loc="backups" tables="$tables" backup_name="player_tables_export" nolock`;
-
- print "[Database] Press any key to continue...\n";
-
- <>; #Read from STDIN
-
-}
-
-sub database_dump_compress {
- check_for_database_dump_script();
- print "[Database] Performing database backup....\n";
- print `perl db_dumper.pl database="$db" loc="backups" compress`;
-}
-
-sub script_exit{
- #::: Cleanup staged folder...
- rmtree("updates_staged/");
- exit;
-}
-
-sub check_db_version_table{
- if(get_mysql_result("SHOW TABLES LIKE 'db_version'") eq "" && $db){
- print get_mysql_result("
- CREATE TABLE db_version (
- version int(11) DEFAULT '0'
- ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
- INSERT INTO db_version (version) VALUES ('1000');");
- print "[Database] Table 'db_version' does not exists.... Creating...\n\n";
- }
-}
-
-#::: Returns Tab Delimited MySQL Result from Command Line
-sub get_mysql_result{
- my $run_query = $_[0];
- if(!$db){ return; }
- if($OS eq "Windows"){ return `"$path" --host $host --user $user --password="$pass" $db -N -B -e "$run_query"`; }
- if($OS eq "Linux"){
- $run_query =~s/`//g;
- return `$path --user="$user" --host $host --password="$pass" $db -N -B -e "$run_query"`;
- }
-}
-
-sub get_mysql_result_from_file{
- my $update_file = $_[0];
- if(!$db){ return; }
- if($OS eq "Windows"){ return `"$path" --host $host --user $user --password="$pass" --force $db < $update_file`; }
- if($OS eq "Linux"){ return `"$path" --host $host --user $user --password="$pass" --force $db < $update_file`; }
-}
-
-#::: Gets Remote File based on request_url (1st Arg), and saves to destination file (2nd Arg)
-#::: Example: get_remote_file($eqemu_repository_request_url . "utils/sql/db_update_manifest.txt", "db_update/db_update_manifest.txt");
-sub get_remote_file{
- my $request_url = $_[0];
- my $destination_file = $_[1];
- my $content_type = $_[2];
- my $no_retry = $_[3];
- my $silent_download = $_[4];
-
- if(!$has_internet_connection){
- print "[Download] Cannot download without internet connection...\n";
- return;
- }
-
- #::: Build file path of the destination file so that we may check for the folder's existence and make it if necessary
-
- if($destination_file=~/\//i){
- my @directory_path = split('/', $destination_file);
- $build_path = "";
- $directory_index = 0;
- while($directory_path[$directory_index] && $directory_path[$directory_index + 1]){
- $build_path .= $directory_path[$directory_index] . "/";
- # print "checking '" . $build_path . "'\n";
- #::: If path does not exist, create the directory...
- if (!-d $build_path) {
- print "[Copy] folder doesn't exist, creating '" . $build_path . "'\n";
- mkdir($build_path);
- }
- if(!$directory_indexr_path[$directory_index + 2] && $directory_indexr_path[$directory_index + 1]){
- # print $actual_path . "\n";
- $actual_path = $build_path;
- last;
- }
- $directory_index++;
- }
- }
-
- if($OS eq "Windows"){
- #::: For non-text type requests...
- if($content_type == 1){
- $break = 0;
- while($break == 0) {
- eval "use LWP::Simple qw(getstore);";
- # use LWP::Simple qw(getstore);
- # print "request is " . $request_url . "\n";
- # print "destination file is supposed to be " . $destination_file . "\n";
- if(!getstore($request_url, $destination_file)){
- print "[Download] Error, no connection or failed request...\n\n";
- }
- # sleep(1);
- #::: Make sure the file exists before continuing...
- if(-e $destination_file) {
- $break = 1;
- print "[Download] Saved: (" . $destination_file . ") from " . $request_url . "\n" if !$silent_download;
- } else { $break = 0; }
- usleep(500);
-
- if($no_retry){
- $break = 1;
- }
- }
- }
- else{
- $break = 0;
- while($break == 0) {
- require LWP::UserAgent;
- my $ua = LWP::UserAgent->new;
- $ua->timeout(10);
- $ua->env_proxy;
- my $response = $ua->get($request_url);
- if ($response->is_success){
- open (FILE, '> ' . $destination_file . '');
- print FILE $response->decoded_content;
- close (FILE);
- }
- else {
- print "[Download] Error, no connection or failed request...\n\n";
- }
- if(-e $destination_file) {
- $break = 1;
- print "[Download] Saved: (" . $destination_file . ") from " . $request_url . "\n" if !$silent_download;
- } else { $break = 0; }
- usleep(500);
-
- if($no_retry){
- $break = 1;
- }
- }
- }
- }
- if($OS eq "Linux"){
- #::: wget -O db_update/db_update_manifest.txt https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt
- $wget = `wget --no-check-certificate --quiet -O $destination_file $request_url`;
- print "[Download] Saved: (" . $destination_file . ") from " . $request_url . "\n" if !$silent_download;
- if($wget=~/unable to resolve/i){
- print "Error, no connection or failed request...\n\n";
- #die;
- }
- }
-}
-
-#::: Trim Whitespaces
-sub trim {
- my $string = $_[0];
- $string =~ s/^\s+//;
- $string =~ s/\s+$//;
- return $string;
-}
-
-sub read_eqemu_config_xml {
- my $confile = "eqemu_config.xml"; #default
- open(F, "<$confile");
- my $indb = 0;
- while() {
- s/\r//g;
- if(//i) { $indb = 1; }
- next unless($indb == 1);
- if(/<\/database>/i) { $indb = 0; last; }
- if(/(.*)<\/host>/i) { $host = $1; }
- elsif(/(.*)<\/username>/i) { $user = $1; }
- elsif(/(.*)<\/password>/i) { $pass = $1; }
- elsif(/(.*)<\/db>/i) { $db = $1; }
- }
-}
-
-#::: Fetch Latest PEQ AA's
-sub aa_fetch{
- if(!$db){
- print "No database present, check your eqemu_config.xml for proper MySQL/MariaDB configuration...\n";
- return;
- }
-
- print "[Install] Pulling down PEQ AA Tables...\n";
- get_remote_file($eqemu_repository_request_url . "utils/sql/peq_aa_tables_post_rework.sql", "db_update/peq_aa_tables_post_rework.sql");
- print "[Install] Installing AA Tables...\n";
- print get_mysql_result_from_file("db_update/peq_aa_tables_post_rework.sql");
- print "[Install] Done...\n\n";
-}
-
-#::: Fetch Latest Opcodes
-sub opcodes_fetch{
- print "[Update] Pulling down latest opcodes...\n";
- %opcodes = (
- 1 => ["opcodes", $eqemu_repository_request_url . "utils/patches/opcodes.conf"],
- 2 => ["mail_opcodes", $eqemu_repository_request_url . "utils/patches/mail_opcodes.conf"],
- 3 => ["Titanium", $eqemu_repository_request_url . "utils/patches/patch_Titanium.conf"],
- 4 => ["Secrets of Faydwer", $eqemu_repository_request_url . "utils/patches/patch_SoF.conf"],
- 5 => ["Seeds of Destruction", $eqemu_repository_request_url . "utils/patches/patch_SoD.conf"],
- 6 => ["Underfoot", $eqemu_repository_request_url . "utils/patches/patch_UF.conf"],
- 7 => ["Rain of Fear", $eqemu_repository_request_url . "utils/patches/patch_RoF.conf"],
- 8 => ["Rain of Fear 2", $eqemu_repository_request_url . "utils/patches/patch_RoF2.conf"],
- );
- $loop = 1;
- while($opcodes{$loop}[0]){
- #::: Split the request_url by the patches folder to get the file name from request_url
- @real_file = split("patches/", $opcodes{$loop}[1]);
- $find = 0;
- while($real_file[$find]){
- $file_name = $real_file[$find];
- $find++;
- }
-
- get_remote_file($opcodes{$loop}[1], $file_name);
- $loop++;
- }
- print "[Update] Done...\n";
-}
-
-sub remove_duplicate_rule_values {
- $ruleset_id = trim(get_mysql_result("SELECT `ruleset_id` FROM `rule_sets` WHERE `name` = 'default'"));
- print "[Database] 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 "[Database] Removing duplicate : " . $values[1] . " (Ruleset (" . $values[0] . ")) matches default value of : " . $values[2] . "\n";
- get_mysql_result("DELETE FROM `rule_values` WHERE `ruleset_id` = " . $values[0] . " AND `rule_name` = '" . $values[1] . "'");
- $total_removed++;
- }
- }
-
- print "[Database] Total duplicate rules removed... " . $total_removed . "\n";
-}
-
-sub copy_file {
- $l_source_file = $_[0];
- $l_destination_file = $_[1];
- if($l_destination_file=~/\//i){
- my @directory_path = split('/', $l_destination_file);
- $build_path = "";
- $directory_index = 0;
- while($directory_path[$directory_index]){
- $build_path .= $directory_path[$directory_index] . "/";
- #::: If path does not exist, create the directory...
- if (!-d $build_path) {
- mkdir($build_path);
- }
- if(!$directory_path[$directory_index + 2] && $directory_path[$directory_index + 1]){
- # print $actual_path . "\n";
- $actual_path = $build_path;
- last;
- }
- $directory_index++;
- }
- }
- copy $l_source_file, $l_destination_file;
-}
-
-sub fetch_latest_windows_binaries {
- print "[Update] Fetching Latest Windows Binaries... \n";
- get_remote_file($install_repository_request_url . "master_windows_build.zip", "updates_staged/master_windows_build.zip", 1);
- print "[Update] Fetched Latest Windows Binaries... \n";
- print "[Update] Extracting... --- \n";
- unzip('updates_staged/master_windows_build.zip', 'updates_staged/binaries/');
- my @files;
- my $start_dir = "updates_staged/binaries";
- find(
- sub { push @files, $File::Find::name unless -d; },
- $start_dir
- );
- for my $file (@files) {
- $destination_file = $file;
- $destination_file =~s/updates_staged\/binaries\///g;
- print "[Update] Installing :: " . $destination_file . "\n";
- copy_file($file, $destination_file);
- }
- print "[Update] Done\n";
-
- rmtree('updates_staged');
-}
-
-sub fetch_latest_windows_binaries_bots {
- print "[Update] Fetching Latest Windows Binaries with Bots...\n";
- get_remote_file($install_repository_request_url . "master_windows_build_bots.zip", "updates_staged/master_windows_build_bots.zip", 1);
- print "[Update] Fetched Latest Windows Binaries with Bots...\n";
- print "[Update] Extracting...\n";
- unzip('updates_staged/master_windows_build_bots.zip', 'updates_staged/binaries/');
- my @files;
- my $start_dir = "updates_staged/binaries";
- find(
- sub { push @files, $File::Find::name unless -d; },
- $start_dir
- );
- for my $file (@files) {
- $destination_file = $file;
- $destination_file =~s/updates_staged\/binaries\///g;
- print "[Install] Installing :: " . $destination_file . "\n";
- copy_file($file, $destination_file);
- }
- print "[Update] Done...\n";
-
- rmtree('updates_staged');
-}
-
-sub do_windows_login_server_setup {
- print "[Install] Fetching Loginserver... \n";
- get_remote_file($install_repository_request_url . "login_server.zip", "updates_staged/login_server.zip", 1);
- print "[Install] Extracting... \n";
- unzip('updates_staged/login_server.zip', 'updates_staged/login_server/');
- my @files;
- my $start_dir = "updates_staged/login_server";
- find(
- sub { push @files, $File::Find::name unless -d; },
- $start_dir
- );
- for my $file (@files) {
- $destination_file = $file;
- $destination_file =~s/updates_staged\/login_server\///g;
- print "[Install] Installing :: " . $destination_file . "\n";
- copy_file($file, $destination_file);
- }
- print "[Install] Done... \n";
-
- print "[Install] Pulling down Loginserver database tables...\n";
- get_remote_file($install_repository_request_url . "login_server_tables.sql", "db_update/login_server_tables.sql");
- print "[Install] Installing Loginserver tables...\n";
- print get_mysql_result_from_file("db_update/login_server_tables.sql");
- print "[Install] Done...\n";
-
- add_login_server_firewall_rules();
-
- rmtree('updates_staged');
- rmtree('db_update');
-
- print "[Install] Press any key to continue...\n";
-
- <>; #Read from STDIN
-
-}
-
-sub do_linux_login_server_setup {
-
- for my $file (@files) {
- $destination_file = $file;
- $destination_file =~s/updates_staged\/login_server\///g;
- print "[Install] Installing :: " . $destination_file . "\n";
- copy_file($file, $destination_file);
- }
- print "\n Done... \n";
-
- print "[Install] Pulling down Loginserver database tables...\n";
- get_remote_file($install_repository_request_url . "login_server_tables.sql", "db_update/login_server_tables.sql");
- print "[Install] Installing Loginserver tables...\n";
- print get_mysql_result_from_file("db_update/login_server_tables.sql");
- print "[Install] Done...\n\n";
-
- rmtree('updates_staged');
- rmtree('db_update');
-
- get_remote_file($install_repository_request_url . "linux/login.ini", "login_template.ini");
- get_remote_file($install_repository_request_url . "linux/login_opcodes.conf", "login_opcodes.conf");
- get_remote_file($install_repository_request_url . "linux/login_opcodes.conf", "login_opcodes_sod.conf");
-
- get_installation_variables();
- my $db_name = $installation_variables{"mysql_eqemu_db_name"};
- my $db_user = $installation_variables{"mysql_eqemu_user"};
- my $db_password = $installation_variables{"mysql_eqemu_password"};
-
- #::: Open new config file
- open (NEW_CONFIG, '>', 'login.ini');
-
- #::: Iterate through template and replace variables...
- open (FILE_TEMPLATE, "login_template.ini");
- while (){
- chomp;
- $o = $_;
- #::: Find replace variables
- if($o=~/db/i){ $o = "db = " . $db_name; }
- if($o=~/user/i){ $o = "user = " . $db_user; }
- if($o=~/password/i){ $o = "password = " . $db_password; }
-
- print NEW_CONFIG $o . "\n";
- }
-
- close(FILE_TEMPLATE);
- close(NEW_CONFIG);
- unlink("login_template.ini");
-
- print "[Install] Press any key to continue...\n";
-
- <>; #Read from STDIN
-
-}
-
-sub add_login_server_firewall_rules {
- #::: Check Loginserver Firewall install for Windows
- if($OS eq "Windows"){
- $output = `netsh advfirewall firewall show rule name=all`;
- @output_buffer = split("\n", $output);
- $has_loginserver_rules_titanium = 0;
- $has_loginserver_rules_sod = 0;
- foreach my $val (@output_buffer){
- if($val=~/Rule Name/i){
- $val=~s/Rule Name://g;
- if($val=~/EQEmu Loginserver/i && $val=~/Titanium/i){
- $has_loginserver_rules_titanium = 1;
- print "Found existing rule :: " . trim($val) . "\n";
- }
- if($val=~/EQEmu Loginserver/i && $val=~/SOD/i){
- $has_loginserver_rules_sod = 1;
- print "Found existing rule :: " . trim($val) . "\n";
- }
- }
- }
-
- if($has_loginserver_rules_titanium == 0){
- print "[Install] Attempting to add EQEmu Loginserver Firewall Rules (Titanium) (TCP) port 5998 \n";
- print `netsh advfirewall firewall add rule name="EQEmu Loginserver (Titanium) (5998) TCP" dir=in action=allow protocol=TCP localport=5998`;
- print "[Install] Attempting to add EQEmu Loginserver Firewall Rules (Titanium) (UDP) port 5998 \n";
- print `netsh advfirewall firewall add rule name="EQEmu Loginserver (Titanium) (5998) UDP" dir=in action=allow protocol=UDP localport=5998`;
- }
- if($has_loginserver_rules_sod == 0){
- print "[Install] Attempting to add EQEmu Loginserver Firewall Rules (SOD+) (TCP) port 5999 \n";
- print `netsh advfirewall firewall add rule name="EQEmu Loginserver (SOD+) (5999) TCP" dir=in action=allow protocol=TCP localport=5999`;
- print "[Install] Attempting to add EQEmu Loginserver Firewall Rules (SOD+) (UDP) port 5999 \n";
- print `netsh advfirewall firewall add rule name="EQEmu Loginserver (SOD+) (5999) UDP" dir=in action=allow protocol=UDP localport=5999`;
- }
-
- print "If firewall rules don't add you must run this script (eqemu_server.pl) as administrator\n";
- print "\n";
- print "[Install] Instructions \n";
- print "[Install] In order to connect your server to the loginserver you must point your eqemu_config.xml to your local server similar to the following:\n";
- print "
-
- login.eqemulator.net
- 5998
-
-
-
-
- 127.0.0.1
- 5998
-
-
-
- ";
- print "[Install] When done, make sure your EverQuest client points to your loginserver's IP (In this case it would be 127.0.0.1) in the eqhosts.txt file\n";
- }
-}
-
-sub check_windows_firewall_rules{
- $output = `netsh advfirewall firewall show rule name=all`;
- @output_buffer = split("\n", $output);
- $has_world_rules = 0;
- $has_zone_rules = 0;
- foreach my $val (@output_buffer){
- if($val=~/Rule Name/i){
- $val=~s/Rule Name://g;
- if($val=~/EQEmu World/i){
- $has_world_rules = 1;
- print "[Install] Found existing rule :: " . trim($val) . "\n";
- }
- if($val=~/EQEmu Zone/i){
- $has_zone_rules = 1;
- print "[Install] Found existing rule :: " . trim($val) . "\n";
- }
- }
- }
-
- if($has_world_rules == 0){
- print "[Install] Attempting to add EQEmu World Firewall Rules (TCP) port 9000 \n";
- print `netsh advfirewall firewall add rule name="EQEmu World (9000) TCP" dir=in action=allow protocol=TCP localport=9000`;
- print "[Install] Attempting to add EQEmu World Firewall Rules (UDP) port 9000 \n";
- print `netsh advfirewall firewall add rule name="EQEmu World (9000) UDP" dir=in action=allow protocol=UDP localport=9000`;
- }
- if($has_zone_rules == 0){
- print "[Install] Attempting to add EQEmu Zones (7000-7500) TCP \n";
- print `netsh advfirewall firewall add rule name="EQEmu Zones (7000-7500) TCP" dir=in action=allow protocol=TCP localport=7000-7500`;
- print "[Install] Attempting to add EQEmu Zones (7000-7500) UDP \n";
- print `netsh advfirewall firewall add rule name="EQEmu Zones (7000-7500) UDP" dir=in action=allow protocol=UDP localport=7000-7500`;
- }
-}
-
-sub fetch_server_dlls{
- print "[Download] Fetching lua51.dll, zlib1.dll, libmysql.dll...\n";
- get_remote_file($install_repository_request_url . "lua51.dll", "lua51.dll", 1);
- get_remote_file($install_repository_request_url . "zlib1.dll", "zlib1.dll", 1);
- get_remote_file($install_repository_request_url . "libmysql.dll", "libmysql.dll", 1);
-}
-
-sub fetch_peq_db_full{
- print "[Install] Downloading latest PEQ Database... Please wait...\n";
- get_remote_file("http://edit.peqtgc.com/weekly/peq_beta.zip", "updates_staged/peq_beta.zip", 1);
- print "[Install] Downloaded latest PEQ Database... Extracting...\n";
- unzip('updates_staged/peq_beta.zip', 'updates_staged/peq_db/');
- my $start_dir = "updates_staged/peq_db";
- find(
- sub { push @files, $File::Find::name unless -d; },
- $start_dir
- );
- for my $file (@files) {
- $destination_file = $file;
- $destination_file =~s/updates_staged\/peq_db\///g;
- if($file=~/peqbeta|player_tables/i){
- print "[Install] DB :: Installing :: " . $destination_file . "\n";
- get_mysql_result_from_file($file);
- }
- if($file=~/eqtime/i){
- print "[Install] Installing eqtime.cfg\n";
- copy_file($file, "eqtime.cfg");
- }
- }
-}
-
-sub map_files_fetch_bulk{
- print "[Install] Fetching Latest Maps... (This could take a few minutes...)\n";
- get_remote_file("http://github.com/Akkadius/EQEmuMaps/archive/master.zip", "maps/maps.zip", 1);
- unzip('maps/maps.zip', 'maps/');
- my @files;
- my $start_dir = "maps/EQEmuMaps-master/maps";
- find(
- sub { push @files, $File::Find::name unless -d; },
- $start_dir
- );
- for my $file (@files) {
- $destination_file = $file;
- $destination_file =~s/maps\/EQEmuMaps-master\/maps\///g;
- print "[Install] Installing :: " . $destination_file . "\n";
- copy_file($file, "maps/" . $new_file);
- }
- print "[Install] Fetched Latest Maps\n";
-
- rmtree('maps/EQEmuMaps-master');
- unlink('maps/maps.zip');
-}
-
-sub map_files_fetch{
- print "[Install] Fetching Latest Maps --- \n";
-
- get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuMaps/master/!eqemu_maps_manifest.txt", "updates_staged/eqemu_maps_manifest.txt");
-
- #::: Get Data from manifest
- open (FILE, "updates_staged/eqemu_maps_manifest.txt");
- $i = 0;
- while (){
- chomp;
- $o = $_;
- @manifest_map_data = split(',', $o);
- if($manifest_map_data[0] ne ""){
- $maps_manifest[$i] = [$manifest_map_data[0], $manifest_map_data[1]];
- $i++;
- }
- }
-
- #::: Download
- $fc = 0;
- for($m = 0; $m <= $i; $m++){
- my $file_existing = $maps_manifest[$m][0];
- my $file_existing_size = (stat $file_existing)[7];
- if($file_existing_size != $maps_manifest[$m][1]){
- print "[Install] Updating: '" . $maps_manifest[$m][0] . "'\n";
- get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuMaps/master/" . $maps_manifest[$m][0], $maps_manifest[$m][0], 1);
- $fc++;
- }
- }
-
- if($fc == 0){
- print "[Install] No Map Updates found... \n\n";
- }
-}
-
-sub quest_files_fetch{
- if (!-e "updates_staged/Quests-Plugins-master/quests/") {
- print "[Update] Fetching Latest Quests --- \n";
- get_remote_file("https://github.com/EQEmu/Quests-Plugins/archive/master.zip", "updates_staged/Quests-Plugins-master.zip", 1);
- print "[Install] Fetched latest quests...\n";
- mkdir('updates_staged');
- unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/');
- }
-
- $fc = 0;
- use File::Find;
- use File::Compare;
-
- my @files;
- my $start_dir = "updates_staged/Quests-Plugins-master/quests/";
- find(
- sub { push @files, $File::Find::name unless -d; },
- $start_dir
- );
- for my $file (@files) {
- if($file=~/\.pl|\.lua|\.ext/i){
- $staged_file = $file;
- $destination_file = $file;
- $destination_file =~s/updates_staged\/Quests-Plugins-master\///g;
-
- if (!-e $destination_file) {
- copy_file($staged_file, $destination_file);
- print "[Install] Installing :: '" . $destination_file . "'\n";
- $fc++;
- }
- else{
- $directory_indexff = do_file_diff($destination_file, $staged_file);
- if($directory_indexff ne ""){
- $backup_dest = "updates_backups/" . $time_stamp . "/" . $destination_file;
-
- print $directory_indexff . "\n";
- print "[Update] File Different :: '" . $destination_file . "'\n";
- print "[Update] Do you wish to update this Quest? '" . $destination_file . "' [Yes (Enter) - No (N)] \nA backup will be found in '" . $backup_dest . "'\n";
- my $input = ;
- if($input=~/N/i){}
- else{
- #::: Make a backup
- copy_file($destination_file, $backup_dest);
- #::: Copy staged to running
- copy($staged_file, $destination_file);
- print "[Install] Installing :: '" . $destination_file . "'\n\n";
- }
- $fc++;
- }
- }
- }
- }
-
- rmtree('updates_staged');
-
- if($fc == 0){
- print "[Update] No Quest Updates found... \n\n";
- }
-}
-
-sub lua_modules_fetch {
- if (!-e "updates_staged/Quests-Plugins-master/quests/lua_modules/") {
- print "[Update] Fetching Latest LUA Modules --- \n";
- get_remote_file("https://github.com/EQEmu/Quests-Plugins/archive/master.zip", "updates_staged/Quests-Plugins-master.zip", 1);
- print "[Update] Fetched latest LUA Modules...\n";
- unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/');
- }
-
- $fc = 0;
- use File::Find;
- use File::Compare;
-
- my @files;
- my $start_dir = "updates_staged/Quests-Plugins-master/quests/lua_modules/";
- find(
- sub { push @files, $File::Find::name unless -d; },
- $start_dir
- );
- for my $file (@files) {
- if($file=~/\.pl|\.lua|\.ext/i){
- $staged_file = $file;
- $destination_file = $file;
- $destination_file =~s/updates_staged\/Quests-Plugins-master\/quests\///g;
-
- if (!-e $destination_file) {
- copy_file($staged_file, $destination_file);
- print "[Install] Installing :: '" . $destination_file . "'\n";
- $fc++;
- }
- else{
- $directory_indexff = do_file_diff($destination_file, $staged_file);
- if($directory_indexff ne ""){
- $backup_dest = "updates_backups/" . $time_stamp . "/" . $destination_file;
- print $directory_indexff . "\n";
- print "[Update] File Different :: '" . $destination_file . "'\n";
- print "[Update] Do you wish to update this LUA Module? '" . $destination_file . "' [Yes (Enter) - No (N)] \nA backup will be found in '" . $backup_dest . "'\n";
- my $input = ;
- if($input=~/N/i){}
- else{
- #::: Make a backup
- copy_file($destination_file, $backup_dest);
- #::: Copy staged to running
- copy($staged_file, $destination_file);
- print "[Install] Installing :: '" . $destination_file . "'\n\n";
- }
- $fc++;
- }
- }
- }
- }
-
- if($fc == 0){
- print "[Update] No LUA Modules Updates found... \n\n";
- }
-}
-
-sub plugins_fetch{
- if (!-e "updates_staged/Quests-Plugins-master/plugins/") {
- print "[Update] Fetching Latest Plugins\n";
- get_remote_file("https://github.com/EQEmu/Quests-Plugins/archive/master.zip", "updates_staged/Quests-Plugins-master.zip", 1);
- print "[Update] Fetched latest plugins\n";
- unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/');
- }
-
- $fc = 0;
- use File::Find;
- use File::Compare;
-
- my @files;
- my $start_dir = "updates_staged/Quests-Plugins-master/plugins/";
- find(
- sub { push @files, $File::Find::name unless -d; },
- $start_dir
- );
- for my $file (@files) {
- if($file=~/\.pl|\.lua|\.ext/i){
- $staged_file = $file;
- $destination_file = $file;
- $destination_file =~s/updates_staged\/Quests-Plugins-master\///g;
-
- if (!-e $destination_file) {
- copy_file($staged_file, $destination_file);
- print "[Install] Installing :: '" . $destination_file . "'\n";
- $fc++;
- }
- else{
- $directory_indexff = do_file_diff($destination_file, $staged_file);
- if($directory_indexff ne ""){
- $backup_dest = "updates_backups/" . $time_stamp . "/" . $destination_file;
- print $directory_indexff . "\n";
- print "[Update] File Different :: '" . $destination_file . "'\n";
- print "[Update] Do you wish to update this Plugin? '" . $destination_file . "' [Yes (Enter) - No (N)] \nA backup will be found in '" . $backup_dest . "'\n";
- my $input = ;
- if($input=~/N/i){}
- else{
- #::: Make a backup
- copy_file($destination_file, $backup_dest);
- #::: Copy staged to running
- copy($staged_file, $destination_file);
- print "[Install] Installing :: '" . $destination_file . "'\n\n";
- }
- $fc++;
- }
- }
- }
- }
-
- if($fc == 0){
- print "[Update] No Plugin Updates found... \n\n";
- }
-}
-
-sub do_file_diff{
- $file_1 = $_[0];
- $file_2 = $_[1];
- if($OS eq "Windows"){
- eval "use Text::Diff";
- $directory_indexff = diff($file_1, $file_2, { STYLE => "Unified" });
- return $directory_indexff;
- }
- if($OS eq "Linux"){
- # print 'diff -u "$file_1" "$file_2"' . "\n";
- return `diff -u "$file_1" "$file_2"`;
- }
-}
-
-sub unzip {
- $archive_to_unzip = $_[0];
- $dest_folder = $_[1];
-
- if($OS eq "Windows"){
- eval "use Archive::Zip qw( :ERROR_CODES :CONSTANTS )";
- my $zip = Archive::Zip->new();
- unless ( $zip->read($archive_to_unzip) == AZ_OK ) {
- die 'read error';
- }
- print "[Unzip] Extracting...\n";
- $zip->extractTree('', $dest_folder);
- }
- if($OS eq "Linux"){
- print `unzip -o -q "$archive_to_unzip" -d "$dest_folder"`;
- }
-}
-
-sub are_file_sizes_different{
- $file_1 = $_[0];
- $file_2 = $_[1];
- my $file_1 = (stat $file_1)[7];
- my $file_2 = (stat $file_2)[7];
- # print $file_1 . " :: " . $file_2 . "\n";
- if($file_1 != $file_2){
- return 1;
- }
- return;
-}
-
-sub do_bots_db_schema_drop{
- #"drop_bots.sql" is run before reverting database back to 'normal'
- print "[Database] Fetching drop_bots.sql...\n";
- get_remote_file($eqemu_repository_request_url . "utils/sql/git/bots/drop_bots.sql", "db_update/drop_bots.sql");
- print get_mysql_result_from_file("db_update/drop_bots.sql");
-
- print "[Database] Removing bot database tables...\n";
- print get_mysql_result("DELETE FROM `rule_values` WHERE `rule_name` LIKE 'Bots:%';");
-
- if(get_mysql_result("SHOW TABLES LIKE 'commands'") ne "" && $db){
- print get_mysql_result("DELETE FROM `commands` WHERE `command` LIKE 'bot';");
- }
-
- if(get_mysql_result("SHOW TABLES LIKE 'command_settings'") ne "" && $db){
- print get_mysql_result("DELETE FROM `command_settings` WHERE `command` LIKE 'bot';");
- }
-
- if(get_mysql_result("SHOW KEYS FROM `group_id` WHERE `Key_name` LIKE 'PRIMARY'") ne "" && $db){
- print get_mysql_result("ALTER TABLE `group_id` DROP PRIMARY KEY;");
- }
- print get_mysql_result("ALTER TABLE `group_id` ADD PRIMARY KEY (`groupid`, `charid`, `ismerc`);");
-
- if(get_mysql_result("SHOW KEYS FROM `guild_members` WHERE `Key_name` LIKE 'PRIMARY'") ne "" && $db){
- print get_mysql_result("ALTER TABLE `guild_members` DROP PRIMARY KEY;");
- }
- print get_mysql_result("ALTER TABLE `guild_members` ADD PRIMARY KEY (`char_id`);");
-
- print get_mysql_result("UPDATE `spawn2` SET `enabled` = 0 WHERE `id` IN (59297,59298);");
-
- if(get_mysql_result("SHOW COLUMNS FROM `db_version` LIKE 'bots_version'") ne "" && $db){
- print get_mysql_result("UPDATE `db_version` SET `bots_version` = 0;");
- }
- print "[Database] Done...\n";
-}
-
-sub modify_db_for_bots{
- #Called after the db bots schema (2015_09_30_bots.sql) has been loaded
- print "[Database] Modifying database for bots...\n";
- print get_mysql_result("UPDATE `spawn2` SET `enabled` = 1 WHERE `id` IN (59297,59298);");
-
- if(get_mysql_result("SHOW KEYS FROM `guild_members` WHERE `Key_name` LIKE 'PRIMARY'") ne "" && $db){
- print get_mysql_result("ALTER TABLE `guild_members` DROP PRIMARY KEY;");
- }
-
- if(get_mysql_result("SHOW KEYS FROM `group_id` WHERE `Key_name` LIKE 'PRIMARY'") ne "" && $db){
- print get_mysql_result("ALTER TABLE `group_id` DROP PRIMARY KEY;");
- }
- print get_mysql_result("ALTER TABLE `group_id` ADD PRIMARY KEY USING BTREE(`groupid`, `charid`, `name`, `ismerc`);");
-
- if(get_mysql_result("SHOW TABLES LIKE 'command_settings'") ne "" && get_mysql_result("SELECT `command` FROM `command_settings` WHERE `command` LIKE 'bot'") eq "" && $db){
- print get_mysql_result("INSERT INTO `command_settings` VALUES ('bot', '0', '');");
- }
-
- if(get_mysql_result("SHOW TABLES LIKE 'commands'") ne "" && get_mysql_result("SELECT `command` FROM `commands` WHERE `command` LIKE 'bot'") eq "" && $db){
- print get_mysql_result("INSERT INTO `commands` VALUES ('bot', '0');");
- }
-
- if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotAAExpansion'") ne "" && $db){
- print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:AAExpansion' WHERE `rule_name` LIKE 'Bots:BotAAExpansion';");
- }
- if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:AAExpansion'") eq "" && $db){
- print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:AAExpansion', '8', 'The expansion through which bots will obtain AAs');");
- }
-
- if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:CreateBotCount'") ne "" && $db){
- print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:CreationLimit' WHERE `rule_name` LIKE 'Bots:CreateBotCount';");
- }
- if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:CreationLimit'") eq "" && $db){
- print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:CreationLimit', '150', 'Number of bots that each account can create');");
- }
-
- if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotFinishBuffing'") ne "" && $db){
- print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:FinishBuffing' WHERE `rule_name` LIKE 'Bots:BotFinishBuffing';");
- }
- if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:FinishBuffing'") eq "" && $db){
- print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:FinishBuffing', 'false', 'Allow for buffs to complete even if the bot caster is out of mana. Only affects buffing out of combat.');");
- }
-
- if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotGroupBuffing'") ne "" && $db){
- print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:GroupBuffing' WHERE `rule_name` LIKE 'Bots:BotGroupBuffing';");
- }
- if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:GroupBuffing'") eq "" && $db){
- print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:GroupBuffing', 'false', 'Bots will cast single target buffs as group buffs, default is false for single. Does not make single target buffs work for MGB.');");
- }
-
- if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotManaRegen'") ne "" && $db){
- print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:ManaRegen' WHERE `rule_name` LIKE 'Bots:BotManaRegen';");
- }
- if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:ManaRegen'") eq "" && $db){
- print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:ManaRegen', '3.0', 'Adjust mana regen for bots, 1 is fast and higher numbers slow it down 3 is about the same as players.');");
- }
-
- if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotQuest'") ne "" && $db){
- print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:QuestableSpawnLimit' WHERE `rule_name` LIKE 'Bots:BotQuest';");
- }
- if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:QuestableSpawnLimit'") eq "" && $db){
- print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:QuestableSpawnLimit', 'false', 'Optional quest method to manage bot spawn limits using the quest_globals name bot_spawn_limit, see: /bazaar/Aediles_Thrall.pl');");
- }
-
- if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotSpellQuest'") ne "" && $db){
- print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:QuestableSpells' WHERE `rule_name` LIKE 'Bots:BotSpellQuest';");
- }
- if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:QuestableSpells'") eq "" && $db){
- print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:QuestableSpells', 'false', 'Anita Thrall\\\'s (Anita_Thrall.pl) Bot Spell Scriber quests.');");
- }
-
- if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:SpawnBotCount'") ne "" && $db){
- print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:SpawnLimit' WHERE `rule_name` LIKE 'Bots:SpawnBotCount';");
- }
- if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:SpawnLimit'") eq "" && $db){
- print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:SpawnLimit', '71', 'Number of bots a character can have spawned at one time, You + 71 bots is a 12 group raid');");
- }
-
- convert_existing_bot_data();
-}
-
-sub convert_existing_bot_data{
- if(get_mysql_result("SHOW TABLES LIKE 'bots'") ne "" && $db){
- print "[Database] Converting existing bot data...\n";
- print get_mysql_result("INSERT INTO `bot_data` (`bot_id`, `owner_id`, `spells_id`, `name`, `last_name`, `zone_id`, `gender`, `race`, `class`, `level`, `creation_day`, `last_spawn`, `time_spawned`, `size`, `face`, `hair_color`, `hair_style`, `beard`, `beard_color`, `eye_color_1`, `eye_color_2`, `drakkin_heritage`, `drakkin_tattoo`, `drakkin_details`, `ac`, `atk`, `hp`, `mana`, `str`, `sta`, `cha`, `dex`, `int`, `agi`, `wis`, `fire`, `cold`, `magic`, `poison`, `disease`, `corruption`) SELECT `BotID`, `BotOwnerCharacterID`, `BotSpellsID`, `Name`, `LastName`, `LastZoneId`, `Gender`, `Race`, `Class`, `BotLevel`, UNIX_TIMESTAMP(`BotCreateDate`), UNIX_TIMESTAMP(`LastSpawnDate`), `TotalPlayTime`, `Size`, `Face`, `LuclinHairColor`, `LuclinHairStyle`, `LuclinBeard`, `LuclinBeardColor`, `LuclinEyeColor`, `LuclinEyeColor2`, `DrakkinHeritage`, `DrakkinTattoo`, `DrakkinDetails`, `AC`, `ATK`, `HP`, `Mana`, `STR`, `STA`, `CHA`, `DEX`, `_INT`, `AGI`, `WIS`, `FR`, `CR`, `MR`, `PR`, `DR`, `Corrup` FROM `bots`;");
-
- print get_mysql_result("INSERT INTO `bot_inspect_messages` (`bot_id`, `inspect_message`) SELECT `BotID`, `BotInspectMessage` FROM `bots`;");
-
- print get_mysql_result("RENAME TABLE `bots` TO `bots_old`;");
- }
-
- if(get_mysql_result("SHOW TABLES LIKE 'botstances'") ne "" && $db){
- print get_mysql_result("INSERT INTO `bot_stances` (`bot_id`, `stance_id`) SELECT bs.`BotID`, bs.`StanceID` FROM `botstances` bs INNER JOIN `bot_data` bd ON bs.`BotID` = bd.`bot_id`;");
-
- print get_mysql_result("RENAME TABLE `botstances` TO `botstances_old`;");
- }
-
- if(get_mysql_result("SHOW TABLES LIKE 'bottimers'") ne "" && $db){
- print get_mysql_result("INSERT INTO `bot_timers` (`bot_id`, `timer_id`, `timer_value`) SELECT bt.`BotID`, bt.`TimerID`, bt.`Value` FROM `bottimers` bt INNER JOIN `bot_data` bd ON bt.`BotID` = bd.`bot_id`;");
-
- print get_mysql_result("RENAME TABLE `bottimers` TO `bottimers_old`;");
- }
-
- if(get_mysql_result("SHOW TABLES LIKE 'botbuffs'") ne "" && $db){
- print get_mysql_result("INSERT INTO `bot_buffs` (`buffs_index`, `bot_id`, `spell_id`, `caster_level`, `duration_formula`, `tics_remaining`, `poison_counters`, `disease_counters`, `curse_counters`, `corruption_counters`, `numhits`, `melee_rune`, `magic_rune`, `persistent`) SELECT bb.`BotBuffId`, bb.`BotId`, bb.`SpellId`, bb.`CasterLevel`, bb.`DurationFormula`, bb.`TicsRemaining`, bb.`PoisonCounters`, bb.`DiseaseCounters`, bb.`CurseCounters`, bb.`CorruptionCounters`, bb.`HitCount`, bb.`MeleeRune`, bb.`MagicRune`, bb.`Persistent` FROM `botbuffs` bb INNER JOIN `bot_data` bd ON bb.`BotId` = bd.`bot_id`;");
-
- if(get_mysql_result("SHOW COLUMNS FROM `botbuffs` LIKE 'dot_rune'") ne "" && $db){
- print get_mysql_result("UPDATE `bot_buffs` bb INNER JOIN `botbuffs` bbo ON bb.`buffs_index` = bbo.`BotBuffId` SET bb.`dot_rune` = bbo.`dot_rune` WHERE bb.`bot_id` = bbo.`BotID`;");
- }
-
- if(get_mysql_result("SHOW COLUMNS FROM `botbuffs` LIKE 'caston_x'") ne "" && $db){
- print get_mysql_result("UPDATE `bot_buffs` bb INNER JOIN `botbuffs` bbo ON bb.`buffs_index` = bbo.`BotBuffId` SET bb.`caston_x` = bbo.`caston_x` WHERE bb.`bot_id` = bbo.`BotID`;");
- }
-
- if(get_mysql_result("SHOW COLUMNS FROM `botbuffs` LIKE 'caston_y'") ne "" && $db){
- print get_mysql_result("UPDATE `bot_buffs` bb INNER JOIN `botbuffs` bbo ON bb.`buffs_index` = bbo.`BotBuffId` SET bb.`caston_y` = bbo.`caston_y` WHERE bb.`bot_id` = bbo.`BotID`;");
- }
-
- if(get_mysql_result("SHOW COLUMNS FROM `botbuffs` LIKE 'caston_z'") ne "" && $db){
- print get_mysql_result("UPDATE `bot_buffs` bb INNER JOIN `botbuffs` bbo ON bb.`buffs_index` = bbo.`BotBuffId` SET bb.`caston_z` = bbo.`caston_z` WHERE bb.`bot_id` = bbo.`BotID`;");
- }
-
- if(get_mysql_result("SHOW COLUMNS FROM `botbuffs` LIKE 'ExtraDIChance'") ne "" && $db){
- print get_mysql_result("UPDATE `bot_buffs` bb INNER JOIN `botbuffs` bbo ON bb.`buffs_index` = bbo.`BotBuffId` SET bb.`extra_di_chance` = bbo.`ExtraDIChance` WHERE bb.`bot_id` = bbo.`BotID`;");
- }
-
- print get_mysql_result("RENAME TABLE `botbuffs` TO `botbuffs_old`;");
- }
-
- if(get_mysql_result("SHOW TABLES LIKE 'botinventory'") ne "" && $db){
- print get_mysql_result("INSERT INTO `bot_inventories` (`inventories_index`, `bot_id`, `slot_id`, `item_id`, `inst_charges`, `inst_color`, `inst_no_drop`, `augment_1`, `augment_2`, `augment_3`, `augment_4`, `augment_5`) SELECT bi.`BotInventoryID`, bi.`BotID`, bi.`SlotID`, bi.`ItemID`, bi.`charges`, bi.`color`, bi.`instnodrop`, bi.`augslot1`, bi.`augslot2`, bi.`augslot3`, bi.`augslot4`, bi.`augslot5` FROM `botinventory` bi INNER JOIN `bot_data` bd ON bi.`BotID` = bd.`bot_id`;");
-
- if(get_mysql_result("SHOW COLUMNS FROM `botinventory` LIKE 'augslot6'") ne "" && $db){
- print get_mysql_result("UPDATE `bot_inventories` bi INNER JOIN `botinventory` bio ON bi.`inventories_index` = bio.`BotInventoryID` SET bi.`augment_6` = bio.`augslot6` WHERE bi.`bot_id` = bio.`BotID`;");
- }
-
- print get_mysql_result("RENAME TABLE `botinventory` TO `botinventory_old`;");
- }
-
- if(get_mysql_result("SHOW TABLES LIKE 'botpets'") ne "" && $db){
- print get_mysql_result("INSERT INTO `bot_pets` (`pets_index`, `pet_id`, `bot_id`, `name`, `mana`, `hp`) SELECT bp.`BotPetsId`, bp.`PetId`, bp.`BotId`, bp.`Name`, bp.`Mana`, bp.`HitPoints` FROM `botpets` bp INNER JOIN `bot_data` bd ON bp.`BotId` = bd.`bot_id`;");
-
- print get_mysql_result("RENAME TABLE `botpets` TO `botpets_old`;");
- }
-
- if(get_mysql_result("SHOW TABLES LIKE 'botpetbuffs'") ne "" && $db){
- print get_mysql_result("INSERT INTO `bot_pet_buffs` (`pet_buffs_index`, `pets_index`, `spell_id`, `caster_level`, `duration`) SELECT bpb.`BotPetBuffId`, bpb.`BotPetsId`, bpb.`SpellId`, bpb.`CasterLevel`, bpb.`Duration` FROM `botpetbuffs` bpb INNER JOIN `bot_pets` bp ON bpb.`BotPetsId` = bp.`pets_index`;");
-
- print get_mysql_result("RENAME TABLE `botpetbuffs` TO `botpetbuffs_old`;");
- }
-
- if(get_mysql_result("SHOW TABLES LIKE 'botpetinventory'") ne "" && $db){
- print get_mysql_result("INSERT INTO `bot_pet_inventories` (`pet_inventories_index`, `pets_index`, `item_id`) SELECT bpi.`BotPetInventoryId`, bpi.`BotPetsId`, bpi.`ItemId` FROM `botpetinventory` bpi INNER JOIN `bot_pets` bp ON bpi.`BotPetsId` = bp.`pets_index`;");
-
- print get_mysql_result("RENAME TABLE `botpetinventory` TO `botpetinventory_old`;");
- }
-
- if(get_mysql_result("SHOW TABLES LIKE 'botgroup'") ne "" && $db){
- print get_mysql_result("INSERT INTO `bot_groups` (`groups_index`, `group_leader_id`, `group_name`) SELECT bg.`BotGroupId`, bg.`BotGroupLeaderBotId`, bg.`BotGroupName` FROM `botgroup` bg INNER JOIN `bot_data` bd ON bg.`BotGroupLeaderBotId` = bd.`bot_id`;");
-
- print get_mysql_result("RENAME TABLE `botgroup` TO `botgroup_old`;");
- }
-
- if(get_mysql_result("SHOW TABLES LIKE 'botgroupmembers'") ne "" && $db){
- print get_mysql_result("INSERT INTO `bot_group_members` (`group_members_index`, `groups_index`, `bot_id`) SELECT bgm.`BotGroupMemberId`, bgm.`BotGroupId`, bgm.`BotId` FROM `botgroupmembers` bgm INNER JOIN `bot_groups` bg ON bgm.`BotGroupId` = bg.`groups_index` INNER JOIN `bot_data` bd ON bgm.`BotId` = bd.`bot_id`;");
-
- print get_mysql_result("RENAME TABLE `botgroupmembers` TO `botgroupmembers_old`;");
- }
-
- if(get_mysql_result("SHOW TABLES LIKE 'botguildmembers'") ne "" && $db){
- print get_mysql_result("INSERT INTO `bot_guild_members` (`bot_id`, `guild_id`, `rank`, `tribute_enable`, `total_tribute`, `last_tribute`, `banker`, `public_note`, `alt`) SELECT bgm.`char_id`, bgm.`guild_id`, bgm.`rank`, bgm.`tribute_enable`, bgm.`total_tribute`, bgm.`last_tribute`, bgm.`banker`, bgm.`public_note`, bgm.`alt` FROM `botguildmembers` bgm INNER JOIN `guilds` g ON bgm.`guild_id` = g.`id` INNER JOIN `bot_data` bd ON bgm.`char_id` = bd.`bot_id`;");
-
- print get_mysql_result("RENAME TABLE `botguildmembers` TO `botguildmembers_old`;");
- }
-}
-
-sub get_bots_db_version{
- #::: Check if bots_version column exists...
- if(get_mysql_result("SHOW COLUMNS FROM db_version LIKE 'bots_version'") eq "" && $db){
- print get_mysql_result("ALTER TABLE db_version ADD bots_version int(11) DEFAULT '0' AFTER version;");
- print "[Database] Column 'bots_version' does not exists.... Adding to 'db_version' table...\n\n";
- }
- $bots_local_db_version = trim(get_mysql_result("SELECT bots_version FROM db_version LIMIT 1"));
- return $bots_local_db_version;
-}
-
-sub bots_db_management{
- #::: Main Binary Database version
- $binary_database_version = trim($db_version[2]);
-
- #::: If we have stale data from main db run
- if($db_run_stage > 0 && $bots_db_management == 0){
- clear_database_runs();
- }
-
- if($binary_database_version == 0){
- print "[Database] Your server binaries (world/zone) are not compiled for bots...\n\n";
- return;
- }
-
- #::: Set on flag for running bot updates...
- $bots_db_management = 1;
-
- $bots_local_db_version = get_bots_db_version();
-
- run_database_check();
-}
-
-sub main_db_management{
- #::: If we have stale data from bots db run
- if($db_run_stage > 0 && $bots_db_management == 1){
- clear_database_runs();
- }
-
- #::: Main Binary Database version
- $binary_database_version = trim($db_version[1]);
-
- $bots_db_management = 0;
- run_database_check();
-}
-
-sub clear_database_runs{
- # print "DEBUG :: clear_database_runs\n\n";
- #::: Clear manifest data...
- %m_d = ();
- #::: Clear updates...
- @total_updates = ();
- #::: Clear stage
- $db_run_stage = 0;
-}
-
-#::: Responsible for Database Upgrade Routines
-sub run_database_check{
-
- if(!$db){
- print "No database present, check your eqemu_config.xml for proper MySQL/MariaDB configuration...\n";
- return;
- }
-
- if(!@total_updates){
- #::: Pull down bots database manifest
- if($bots_db_management == 1){
- print "[Database] Retrieving latest bots database manifest...\n";
- get_remote_file($eqemu_repository_request_url . "utils/sql/git/bots/bots_db_update_manifest.txt", "db_update/db_update_manifest.txt");
- }
- #::: Pull down mainstream database manifest
- else{
- print "[Database] Retrieving latest database manifest...\n";
- get_remote_file($eqemu_repository_request_url . "utils/sql/db_update_manifest.txt", "db_update/db_update_manifest.txt");
- }
- }
-
- #::: Run 2 - Running pending updates...
- if(@total_updates || $db_run_stage == 1){
- @total_updates = sort @total_updates;
- foreach my $val (@total_updates){
- $file_name = trim($m_d{$val}[1]);
- print "[Database] Running Update: " . $val . " - " . $file_name . "\n";
- print get_mysql_result_from_file("db_update/$file_name");
- print get_mysql_result("UPDATE db_version SET version = $val WHERE version < $val");
-
- if($bots_db_management == 1 && $val == 9000){
- modify_db_for_bots();
- }
- }
- $db_run_stage = 2;
- }
- #::: Run 1 - Initial checking of needed updates...
- else{
- print "[Database] Reading manifest...\n";
- use Data::Dumper;
- open (FILE, "db_update/db_update_manifest.txt");
- while () {
- chomp;
- $o = $_;
- if($o=~/#/i){ next; }
- @manifest = split('\|', $o);
- $m_d{$manifest[0]} = [@manifest];
- }
- #::: Setting Manifest stage...
- $db_run_stage = 1;
- }
-
- @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...
- if($local_database_version){
- $revision_check = $local_database_version;
- }
- else {
- $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...
- for($i = $binary_database_version ; $i > $revision_check; $i--){
- if(!defined($m_d{$i}[0])){ next; }
-
- $file_name = trim($m_d{$i}[1]);
- $query_check = trim($m_d{$i}[2]);
- $match_type = trim($m_d{$i}[3]);
- $match_text = trim($m_d{$i}[4]);
-
- #::: Match type update
- if($match_type eq "contains"){
- if(trim(get_mysql_result($query_check))=~/$match_text/i){
- print "[Database] missing update: " . $i . " '" . $file_name . "' \n";
- fetch_missing_db_update($i, $file_name);
- push(@total_updates, $i);
- }
- else{
- print "[Database] has update: " . $i . " - '" . $file_name . "' \n";
- }
- print_match_debug();
- print_break();
- }
- if($match_type eq "missing"){
- if(get_mysql_result($query_check)=~/$match_text/i){
- print "[Database] has update: " . $i . " - '" . $file_name . "' \n";
- next;
- }
- else{
- print "[Database] missing update: " . $i . " '" . $file_name . "' \n";
- fetch_missing_db_update($i, $file_name);
- push(@total_updates, $i);
- }
- print_match_debug();
- print_break();
- }
- if($match_type eq "empty"){
- if(get_mysql_result($query_check) eq ""){
- print "[Database] missing update: " . $i . " '" . $file_name . "' \n";
- fetch_missing_db_update($i, $file_name);
- push(@total_updates, $i);
- }
- else{
- print "[Database] has update: " . $i . " - '" . $file_name . "' \n";
- }
- print_match_debug();
- print_break();
- }
- if($match_type eq "not_empty"){
- if(get_mysql_result($query_check) ne ""){
- print "[Database] missing update: " . $i . " '" . $file_name . "' \n";
- fetch_missing_db_update($i, $file_name);
- push(@total_updates, $i);
- }
- else{
- print "[Database] has update: " . $i . " - '" . $file_name . "' \n";
- }
- print_match_debug();
- print_break();
- }
- }
- print "\n";
-
- if(scalar (@total_updates) == 0 && $db_run_stage == 2){
- print "[Database] No updates need to be run...\n";
- if($bots_db_management == 1){
- print "[Database] Setting Database to Bots Binary Version (" . $binary_database_version . ") if not already...\n\n";
- get_mysql_result("UPDATE db_version SET bots_version = $binary_database_version ");
- }
- else{
- print "[Database] Setting Database to Binary Version (" . $binary_database_version . ") if not already...\n\n";
- get_mysql_result("UPDATE db_version SET version = $binary_database_version ");
- }
-
- clear_database_runs();
- }
-}
-
-sub fetch_missing_db_update{
- $db_update = $_[0];
- $update_file = $_[1];
- if($db_update >= 9000){
- if($bots_db_management == 1){
- get_remote_file($eqemu_repository_request_url . "utils/sql/git/bots/required/" . $update_file, "db_update/" . $update_file . "");
- }
- else{
- get_remote_file($eqemu_repository_request_url . "utils/sql/git/required/" . $update_file, "db_update/" . $update_file . "");
- }
- }
- elsif($db_update >= 5000 && $db_update <= 9000){
- get_remote_file($eqemu_repository_request_url . "utils/sql/svn/" . $update_file, "db_update/" . $update_file . "");
- }
-}
-
-sub print_match_debug{
- if(!$debug){ return; }
- print " Match Type: '" . $match_type . "'\n";
- print " Match Text: '" . $match_text . "'\n";
- print " Query Check: '" . $query_check . "'\n";
- print " Result: '" . trim(get_mysql_result($query_check)) . "'\n";
-}
-
-sub print_break{
- if(!$debug){ return; }
- print "\n==============================================\n";
-}
-
-sub generate_random_password {
- my $passwordsize = shift;
- my @alphanumeric = ('a'..'z', 'A'..'Z', 0..9);
- my $randpassword = join '',
- map $alphanumeric[rand @alphanumeric], 0..$passwordsize;
-
- return $randpassword;
-}
diff --git a/utils/scripts/linux_installer/install.sh b/utils/scripts/linux_installer/install.sh
new file mode 100644
index 000000000..5d43230c5
--- /dev/null
+++ b/utils/scripts/linux_installer/install.sh
@@ -0,0 +1,202 @@
+#!/usr/bin/env bash
+
+if [[ $EUID -ne 0 ]]; then
+ echo "This script must be run as root" 1>&2
+ exit 1
+fi
+
+#::: Determine releases
+if [[ -f /etc/debian_version ]]; then
+ export OS=Debian
+elif [[ -f /etc/fedora-release ]]; then
+ export OS=fedora_core
+elif [[ -f /etc/redhat-release ]]; then
+ export OS=red_hat
+else
+ echo "This script must be run on a Debian or RedHat derivative"
+ exit 1
+fi
+
+echo "######################################################### "
+echo "#::: EverQuest Emulator Modular Installer "
+echo "#::: Installer Author: Akkadius "
+echo "#::: Installer Co-Author(s): N0ctrnl "
+echo "#::: "
+echo "#::: EQEmulator Server Software is developed and maintained "
+echo "#::: by the EQEmulator Developement team "
+echo "#::: "
+echo "#::: Everquest is a registered trademark "
+echo "#::: Daybreak Game Company LLC. "
+echo "#::: "
+echo "#::: EQEmulator is not associated or "
+echo "#::: affiliated in any way with Daybreak Game Company LLC. "
+echo "######################################################### "
+echo "#: "
+echo "######################################################### "
+echo "#::: To be installed: "
+echo "######################################################### "
+echo "- Server running folder - Will be installed to the folder you ran this script "
+echo "- MariaDB (MySQL) - Database engine "
+echo "- Perl 5.X :: Scripting language for quest engines "
+echo "- LUA Configured :: Scripting language for quest engines "
+echo "- Latest PEQ Database "
+echo "- Latest PEQ Quests "
+echo "- Latest Plugins repository "
+echo "- Maps (Latest V2) formats are loaded "
+echo "- New Path files are loaded "
+echo "- Optimized server binaries "
+echo "######################################################### "
+
+# Installation variables (Don't need to change, only for advanced users)
+
+export eqemu_server_directory=/home/eqemu
+export apt_options="-y -qq" # Set autoconfirm and silent install
+
+################################################################
+
+read -n1 -r -p "Press any key to continue..." key
+
+#::: Setting up user environment (eqemu)
+echo "First, we need to set your passwords..."
+echo "Make sure that you remember these and keep them somewhere"
+echo ""
+echo ""
+groupadd eqemu
+useradd -g eqemu -d $eqemu_server_directory eqemu
+passwd eqemu
+
+#::: Make server directory and go to it
+mkdir $eqemu_server_directory
+cd $eqemu_server_directory
+
+#::: Setup MySQL root user PW
+read -p "Enter MySQL root (Database) password: " eqemu_db_root_password
+
+#::: Write install variables (later use)
+echo "mysql_root:$eqemu_db_root_password" > install_variables.txt
+
+#::: Setup MySQL server
+read -p "Enter Database Name (single word, no special characters, lower case):" eqemu_db_name
+read -p "Enter (Database) MySQL EQEmu Server username: " eqemu_db_username
+read -p "Enter (Database) MySQL EQEmu Server password: " eqemu_db_password
+
+#::: Write install variables (later use)
+echo "mysql_eqemu_db_name:$eqemu_db_name" >> install_variables.txt
+echo "mysql_eqemu_user:$eqemu_db_username" >> install_variables.txt
+echo "mysql_eqemu_password:$eqemu_db_password" >> install_variables.txt
+
+if [[ "$OS" == "Debian" ]]; then
+ # Install pre-req packages
+ apt-get $apt_options install bash
+ apt-get $apt_options install build-essential
+ apt-get $apt_options install cmake
+ apt-get $apt_options install cpp
+ apt-get $apt_options install curl
+ apt-get $apt_options install debconf-utils
+ apt-get $apt_options install g++
+ apt-get $apt_options install gcc
+ apt-get $apt_options install git
+ apt-get $apt_options install git-core
+ apt-get $apt_options install libio-stringy-perl
+ apt-get $apt_options install liblua5.1
+ apt-get $apt_options install liblua5.1-dev
+ apt-get $apt_options install libluabind-dev
+ apt-get $apt_options install libmysql++
+ apt-get $apt_options install libperl-dev
+ apt-get $apt_options install libperl5i-perl
+ apt-get $apt_options install libwtdbomysql-dev
+ apt-get $apt_options install lua5.1
+ apt-get $apt_options install make
+ apt-get $apt_options install mariadb-client
+ apt-get $apt_options install open-vm-tools
+ apt-get $apt_options install unzip
+ apt-get $apt_options install uuid-dev
+ apt-get $apt_options install zlib-bin
+ apt-get $apt_options install zlibc
+
+ #::: Install FTP for remote FTP access
+ echo "proftpd-basic shared/proftpd/inetd_or_standalone select standalone" | debconf-set-selections
+ apt-get -y -q install proftpd
+
+ #::: Install MariaDB Server
+ export DEBIAN_FRONTEND=noninteractive
+ debconf-set-selections <<< 'mariadb-server-10.0 mysql-server/root_password password PASS'
+ debconf-set-selections <<< 'mariadb-server-10.0 mysql-server/root_password_again password PASS'
+ apt-get install -y mariadb-server
+ mysql -uroot -pPASS -e "SET PASSWORD = PASSWORD('$eqemu_db_root_password');"
+
+elif [[ "$OS" == "red_hat" ]]; then
+ # Do RedHat / CentOS stuff
+ # Add the MariaDB repository to yum
+cat < /etc/yum.repos.d/mariadb.repo
+# MariaDB 10.1 CentOS repository list - created 2016-08-20 05:42 UTC
+# http://downloads.mariadb.org/mariadb/repositories/
+[mariadb]
+name = MariaDB
+baseurl = http://yum.mariadb.org/10.1/centos7-amd64
+gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
+enabled=1
+gpgcheck=1
+EOF
+ # Install prereqs
+ yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
+ yum -y install deltarpm
+ yum -y install open-vm-tools vim cmake boost-* zlib-devel mariadb-server mariadb-client mariadb-devel mariadb-libs mariadb-compat perl-* lua* dos2unix php-mysql proftpd
+ yum -y groupinstall "Development Tools" "Basic Web Server" "Compatibility Libraries"
+
+elif [[ "$OS" == "fedora_core" ]]; then
+ # Do Fedora stuff
+ dnf -y install open-vm-tools vim cmake boost-devel zlib-devel mariadb-server mariadb-devel mariadb-libs perl perl-DBD-MySQL perl-IO-stringy perl-devel lua-devel lua-sql-mysql dos2unix php-mysql proftpd wget compat-lua-libs compat-lua-devel compat-lua perl-Time-HiRes
+ dnf -y groupinstall "Development Tools" "Basic Web Server" "C Development Tools and Libraries"
+fi
+
+if [[ "$OS" == "fedora_core" ]] || [[ "$OS" == "red_hat" ]]; then
+ # Start MariaDB server and set root password
+ echo "Starting MariaDB server..."
+ systemctl enable mariadb.service
+ systemctl start mariadb.service
+ sleep 5
+ /usr/bin/mysqladmin -u root password $eqemu_db_root_password
+fi
+
+#::: Configure game server database user
+mysql -uroot -p$eqemu_db_root_password -e "CREATE USER '$eqemu_db_username'@'localhost' IDENTIFIED BY '$eqemu_db_password';"
+mysql -uroot -p$eqemu_db_root_password -e "GRANT GRANT OPTION ON *.* TO '$eqemu_db_username'@'localhost';"
+mysql -uroot -p$eqemu_db_root_password -e "GRANT ALL ON *.* TO '$eqemu_db_username'@'localhost';"
+
+#::: Create source and server directories
+mkdir $eqemu_server_directory/source
+mkdir $eqemu_server_directory/server
+mkdir $eqemu_server_directory/server/export
+mkdir $eqemu_server_directory/server/logs
+mkdir $eqemu_server_directory/server/shared
+mkdir $eqemu_server_directory/server/maps
+
+#::: Grab loginserver dependencies
+# cd $eqemu_server_directory/source/Server/dependencies
+# if [[ "$OS" == "Debian" ]]; then
+# wget http://eqemu.github.io/downloads/ubuntu_LoginServerCrypto_x64.zip
+# unzip ubuntu_LoginServerCrypto_x64.zip
+# rm ubuntu_LoginServerCrypto_x64.zip
+# elif [[ "$OS" == "fedora_core" ]] || [[ "$OS" == "red_hat" ]]; then
+# wget http://eqemu.github.io/downloads/fedora12_LoginServerCrypto_x64.zip
+# unzip fedora12_LoginServerCrypto_x64.zip
+# rm fedora12_LoginServerCrypto_x64.zip
+# fi
+# cd $eqemu_server_directory/source/Server/build
+
+#::: Back to server directory
+cd $eqemu_server_directory/server
+wget https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_server.pl
+
+#::: Map lowercase to uppercase to avoid issues
+ln -s maps Maps
+
+#::: Notes
+
+perl $eqemu_server_directory/server/eqemu_server.pl new_server
+
+#::: Chown files
+chown eqemu:eqemu $eqemu_server_directory/ -R
+chmod 755 $eqemu_server_directory/server/*.pl
+chmod 755 $eqemu_server_directory/server/*.sh
diff --git a/utils/sql/git/optional/2016_09_03_old_bind_wound_rule.sql b/utils/sql/git/optional/2016_09_03_old_bind_wound_rule.sql
new file mode 100644
index 000000000..87791d59b
--- /dev/null
+++ b/utils/sql/git/optional/2016_09_03_old_bind_wound_rule.sql
@@ -0,0 +1 @@
+INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Character:UseOldBindWound', 'true', 'Uses the original bind wound behavior');
diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp
index abe6e0e18..9a9572f97 100644
--- a/world/zoneserver.cpp
+++ b/world/zoneserver.cpp
@@ -1312,6 +1312,7 @@ bool ZoneServer::Process() {
case ServerOP_CZSignalNPC:
case ServerOP_CZSetEntityVariableByNPCTypeID:
case ServerOP_CZSignalClient:
+ case ServerOP_WWMarquee:
case ServerOP_DepopAllPlayersCorpses:
case ServerOP_DepopPlayerCorpse:
case ServerOP_ReloadTitles:
diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp
index 2a8a0c790..1a49aaf66 100644
--- a/zone/bonuses.cpp
+++ b/zone/bonuses.cpp
@@ -2529,6 +2529,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_ImmuneFleeing:
new_bonus->ImmuneToFlee = true;
+ if (currently_fleeing) // lets update shit now instead of next tick
+ ProcessFlee();
break;
case SE_DelayDeath:
diff --git a/zone/client.cpp b/zone/client.cpp
index 59998bfdb..3a7b60eb5 100644
--- a/zone/client.cpp
+++ b/zone/client.cpp
@@ -2655,60 +2655,120 @@ bool Client::BindWound(Mob *bindmob, bool start, bool fail)
bind_out->type = 0;
CheckIncreaseSkill(EQEmu::skills::SkillBindWound, nullptr, 5);
- int maxHPBonus = spellbonuses.MaxBindWound + itembonuses.MaxBindWound +
- aabonuses.MaxBindWound;
+ if (RuleB(Character, UseOldBindWound)) {
+ int maxHPBonus = spellbonuses.MaxBindWound + itembonuses.MaxBindWound +
+ aabonuses.MaxBindWound;
- int max_percent = 50 + 10 * maxHPBonus;
+ int max_percent = 50 + maxHPBonus;
- if (GetClass() == MONK && GetSkill(EQEmu::skills::SkillBindWound) > 200) {
- max_percent = 70 + 10 * maxHPBonus;
- }
-
- max_percent = mod_bindwound_percent(max_percent, bindmob);
-
- int max_hp = bindmob->GetMaxHP() * max_percent / 100;
-
- // send bindmob new hp's
- if (bindmob->GetHP() < bindmob->GetMaxHP() && bindmob->GetHP() <= (max_hp)-1) {
- // 0.120 per skill point, 0.60 per skill level, minimum 3 max 30
- int bindhps = 3;
-
- if (GetSkill(EQEmu::skills::SkillBindWound) > 200) {
- bindhps += GetSkill(EQEmu::skills::SkillBindWound) * 4 / 10;
- }
- else if (GetSkill(EQEmu::skills::SkillBindWound) >= 10) {
- bindhps += GetSkill(EQEmu::skills::SkillBindWound) / 4;
+ if (GetClass() == MONK && GetSkill(EQEmu::skills::SkillBindWound) > 200) {
+ max_percent = 70 + maxHPBonus;
}
- // Implementation of aaMithanielsBinding is a guess (the multiplier)
- int bindBonus = spellbonuses.BindWound + itembonuses.BindWound +
+ max_percent = mod_bindwound_percent(max_percent, bindmob);
+
+ int max_hp = bindmob->GetMaxHP() * max_percent / 100;
+
+ // send bindmob new hp's
+ if (bindmob->GetHP() < bindmob->GetMaxHP() && bindmob->GetHP() <= (max_hp)-1) {
+ // 0.120 per skill point, 0.60 per skill level, minimum 3 max 30
+ int bindhps = 3;
+
+ if (GetSkill(EQEmu::skills::SkillBindWound) > 200) {
+ bindhps += GetSkill(EQEmu::skills::SkillBindWound) * 4 / 10;
+ }
+ else if (GetSkill(EQEmu::skills::SkillBindWound) >= 10) {
+ bindhps += GetSkill(EQEmu::skills::SkillBindWound) / 4;
+ }
+
+ // Implementation of aaMithanielsBinding is a guess (the multiplier)
+ int bindBonus = spellbonuses.BindWound + itembonuses.BindWound +
aabonuses.BindWound;
- bindhps += bindhps * bindBonus / 100;
+ bindhps += bindhps * bindBonus / 100;
- bindhps = mod_bindwound_hp(bindhps, bindmob);
+ bindhps = mod_bindwound_hp(bindhps, bindmob);
- // if the bind takes them above the max bindable
- // cap it at that value. Dont know if live does it this way
- // but it makes sense to me.
- int chp = bindmob->GetHP() + bindhps;
- if (chp > max_hp)
- chp = max_hp;
+ // if the bind takes them above the max bindable
+ // cap it at that value. Dont know if live does it this way
+ // but it makes sense to me.
+ int chp = bindmob->GetHP() + bindhps;
+ if (chp > max_hp)
+ chp = max_hp;
- bindmob->SetHP(chp);
- bindmob->SendHPUpdate();
- } else {
- // I dont have the real, live
- Message(15, "You cannot bind wounds above %d%% hitpoints.",
- max_percent);
- if (bindmob != this && bindmob->IsClient())
- bindmob->CastToClient()->Message(
- 15,
- "You cannot have your wounds bound above %d%% hitpoints.",
- max_percent);
- // Too many hp message goes here.
+ bindmob->SetHP(chp);
+ bindmob->SendHPUpdate();
+ }
+ else {
+ // I dont have the real, live
+ Message(15, "You cannot bind wounds above %d%% hitpoints.",
+ max_percent);
+ if (bindmob != this && bindmob->IsClient())
+ bindmob->CastToClient()->Message(
+ 15,
+ "You cannot have your wounds bound above %d%% hitpoints.",
+ max_percent);
+ // Too many hp message goes here.
+ }
}
- } else {
+ else {
+ int percent_base = 50;
+ if (GetRawSkill(EQEmu::skills::SkillBindWound) > 200) {
+ if ((GetClass() == MONK) || (GetClass() == BEASTLORD))
+ percent_base = 70;
+ else if ((GetLevel() > 50) && ((GetClass() == WARRIOR) || (GetClass() == ROGUE) || (GetClass() == CLERIC)))
+ percent_base = 70;
+ }
+
+ int percent_bonus = 0;
+ if (percent_base >= 70)
+ percent_bonus = spellbonuses.MaxBindWound + itembonuses.MaxBindWound + aabonuses.MaxBindWound;
+
+ int max_percent = percent_base + percent_bonus;
+ if (max_percent < 0)
+ max_percent = 0;
+ if (max_percent > 100)
+ max_percent = 100;
+
+ max_percent = mod_bindwound_percent(max_percent, bindmob);
+
+ int max_hp = (bindmob->GetMaxHP() * max_percent) / 100;
+ if (max_hp > bindmob->GetMaxHP())
+ max_hp = bindmob->GetMaxHP();
+
+ if (bindmob->GetHP() < bindmob->GetMaxHP() && bindmob->GetHP() < max_hp) {
+ int bindhps = 3; // base bind hp
+ if (percent_base >= 70)
+ bindhps = (GetSkill(EQEmu::skills::SkillBindWound) * 4) / 10; // 8:5 skill-to-hp ratio
+ else if (GetSkill(EQEmu::skills::SkillBindWound) >= 12)
+ bindhps = GetSkill(EQEmu::skills::SkillBindWound) / 4; // 4:1 skill-to-hp ratio
+
+ int bonus_hp_percent = 0;
+ if (percent_base >= 70)
+ bonus_hp_percent = spellbonuses.BindWound + itembonuses.BindWound + aabonuses.BindWound;
+
+ bindhps += (bindhps * bonus_hp_percent) / 100;
+
+ if (bindhps < 3)
+ bindhps = 3;
+
+ bindhps = mod_bindwound_hp(bindhps, bindmob);
+
+ bindhps += bindmob->GetHP();
+ if (bindhps > max_hp)
+ bindhps = max_hp;
+
+ bindmob->SetHP(bindhps);
+ bindmob->SendHPUpdate();
+ }
+ else {
+ Message(15, "You cannot bind wounds above %d%% hitpoints", max_percent);
+ if (bindmob != this && bindmob->IsClient())
+ bindmob->CastToClient()->Message(15, "You cannot have your wounds bound above %d%% hitpoints", max_percent);
+ }
+ }
+ }
+ else {
// Send client bind failed
if (bindmob != this)
bind_out->type = 6; // They moved
diff --git a/zone/client.h b/zone/client.h
index 472fda02d..b939221e5 100644
--- a/zone/client.h
+++ b/zone/client.h
@@ -795,6 +795,7 @@ public:
void SendClearAA();
inline uint32 GetMaxAAXP(void) const { return max_AAXP; }
inline uint32 GetAAXP() const { return m_pp.expAA; }
+ inline uint32 GetAAPercent() const { return m_epp.perAA; }
int16 CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id);
void SetAATitle(const char *Title);
void SetTitleSuffix(const char *txt);
diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp
index b9b28f0a6..adaaf3325 100644
--- a/zone/embparser_api.cpp
+++ b/zone/embparser_api.cpp
@@ -3616,6 +3616,26 @@ XS(XS__crosszonesignalnpcbynpctypeid)
XSRETURN_EMPTY;
}
+XS(XS__worldwidemarquee);
+XS(XS__worldwidemarquee)
+{
+ dXSARGS;
+ if (items != 6)
+ Perl_croak(aTHX_ "Usage: worldwidemarquee(type, priority, fadein, fadeout, duration, message)");
+
+ if (items == 6) {
+ uint32 type = (uint32)SvIV(ST(0));
+ uint32 priority = (uint32)SvIV(ST(1));
+ uint32 fadein = (uint32)SvIV(ST(2));
+ uint32 fadeout = (uint32)SvIV(ST(3));
+ uint32 duration = (uint32)SvIV(ST(4));
+ char* message = (char *)SvPV_nolen(ST(5));
+ quest_manager.WorldWideMarquee(type, priority, fadein, fadeout, duration, message);
+ }
+
+ XSRETURN_EMPTY;
+}
+
XS(XS__debug);
XS(XS__debug)
{
@@ -3749,6 +3769,7 @@ EXTERN_C XS(boot_quest)
newXS(strcpy(buf, "crosszonesignalclientbycharid"), XS__crosszonesignalclientbycharid, file);
newXS(strcpy(buf, "crosszonesignalclientbyname"), XS__crosszonesignalclientbyname, file);
newXS(strcpy(buf, "crosszonesignalnpcbynpctypeid"), XS__crosszonesignalnpcbynpctypeid, file);
+ newXS(strcpy(buf, "worldwidemarquee"), XS__worldwidemarquee, file);
newXS(strcpy(buf, "debug"), XS__debug, file);
newXS(strcpy(buf, "delglobal"), XS__delglobal, file);
newXS(strcpy(buf, "depop"), XS__depop, file);
diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp
index 6c2345856..403ca82aa 100644
--- a/zone/lua_client.cpp
+++ b/zone/lua_client.cpp
@@ -185,6 +185,11 @@ uint32 Lua_Client::GetAAExp() {
return self->GetAAXP();
}
+uint32 Lua_Client::GetAAPercent() {
+ Lua_Safe_Call_Int();
+ return self->GetAAPercent();
+}
+
uint32 Lua_Client::GetTotalSecondsPlayed() {
Lua_Safe_Call_Int();
return self->GetTotalSecondsPlayed();
@@ -1377,6 +1382,7 @@ luabind::scope lua_register_client() {
.def("GetWeight", (int(Lua_Client::*)(void))&Lua_Client::GetWeight)
.def("GetEXP", (uint32(Lua_Client::*)(void))&Lua_Client::GetEXP)
.def("GetAAExp", (uint32(Lua_Client::*)(void))&Lua_Client::GetAAExp)
+ .def("GetAAPercent", (uint32(Lua_Client::*)(void))&Lua_Client::GetAAPercent)
.def("GetTotalSecondsPlayed", (uint32(Lua_Client::*)(void))&Lua_Client::GetTotalSecondsPlayed)
.def("UpdateLDoNPoints", (void(Lua_Client::*)(int,uint32))&Lua_Client::UpdateLDoNPoints)
.def("SetDeity", (void(Lua_Client::*)(int))&Lua_Client::SetDeity)
diff --git a/zone/lua_client.h b/zone/lua_client.h
index 36ea2b8a4..a0a5a9083 100644
--- a/zone/lua_client.h
+++ b/zone/lua_client.h
@@ -63,6 +63,7 @@ public:
int GetWeight();
uint32 GetEXP();
uint32 GetAAExp();
+ uint32 GetAAPercent();
uint32 GetTotalSecondsPlayed();
void UpdateLDoNPoints(int points, uint32 theme);
void SetDeity(int v);
diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp
index d47420fe1..9f413128b 100644
--- a/zone/lua_general.cpp
+++ b/zone/lua_general.cpp
@@ -892,6 +892,10 @@ void lua_cross_zone_message_player_by_name(uint32 type, const char *player, cons
quest_manager.CrossZoneMessagePlayerByName(type, player, message);
}
+void lua_world_wide_marquee(uint32 type, uint32 priority, uint32 fadein, uint32 fadeout, uint32 duration, const char *message) {
+ quest_manager.WorldWideMarquee(type, priority, fadein, fadeout, duration, message);
+}
+
luabind::adl::object lua_get_qglobals(lua_State *L, Lua_NPC npc, Lua_Client client) {
luabind::adl::object ret = luabind::newtable(L);
@@ -1613,6 +1617,7 @@ luabind::scope lua_register_general() {
luabind::def("cross_zone_signal_client_by_char_id", &lua_cross_zone_signal_client_by_char_id),
luabind::def("cross_zone_signal_client_by_name", &lua_cross_zone_signal_client_by_name),
luabind::def("cross_zone_message_player_by_name", &lua_cross_zone_message_player_by_name),
+ luabind::def("world_wide_marquee", &lua_world_wide_marquee),
luabind::def("get_qglobals", (luabind::adl::object(*)(lua_State*,Lua_NPC,Lua_Client))&lua_get_qglobals),
luabind::def("get_qglobals", (luabind::adl::object(*)(lua_State*,Lua_Client))&lua_get_qglobals),
luabind::def("get_qglobals", (luabind::adl::object(*)(lua_State*,Lua_NPC))&lua_get_qglobals),
diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp
index 76c085714..de334d5d0 100644
--- a/zone/perl_client.cpp
+++ b/zone/perl_client.cpp
@@ -871,6 +871,32 @@ XS(XS_Client_GetAAExp)
XSRETURN(1);
}
+XS(XS_Client_GetAAPercent);
+XS(XS_Client_GetAAPercent)
+{
+ dXSARGS;
+ if (items != 1)
+ Perl_croak(aTHX_ "Usage: Client::GetAAPercent(THIS)");
+ {
+ Client* THIS;
+ uint32 RETVAL;
+ dXSTARG;
+
+ if (sv_derived_from(ST(0), "Client")) {
+ IV tmp = SvIV((SV*)SvRV(ST(0)));
+ THIS = INT2PTR(Client *,tmp);
+ }
+ else
+ Perl_croak(aTHX_ "THIS is not of type Client");
+ if(THIS == nullptr)
+ Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
+
+ RETVAL = THIS->GetAAPercent();
+ XSprePUSH; PUSHu((UV)RETVAL);
+ }
+ XSRETURN(1);
+}
+
XS(XS_Client_GetTotalSecondsPlayed); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_GetTotalSecondsPlayed)
{
@@ -6465,6 +6491,7 @@ XS(boot_Client)
newXSproto(strcpy(buf, "GetWeight"), XS_Client_GetWeight, file, "$");
newXSproto(strcpy(buf, "GetEXP"), XS_Client_GetEXP, file, "$");
newXSproto(strcpy(buf, "GetAAExp"), XS_Client_GetAAExp, file, "$");
+ newXSproto(strcpy(buf, "GetAAPercent"), XS_Client_GetAAPercent, file, "$");
newXSproto(strcpy(buf, "GetTotalSecondsPlayed"), XS_Client_GetTotalSecondsPlayed, file, "$");
newXSproto(strcpy(buf, "UpdateLDoNPoints"), XS_Client_UpdateLDoNPoints, file, "$$$");
newXSproto(strcpy(buf, "SetDeity"), XS_Client_SetDeity, file, "$$");
diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp
index 78fc2b206..5803e547c 100644
--- a/zone/questmgr.cpp
+++ b/zone/questmgr.cpp
@@ -3017,6 +3017,20 @@ void QuestManager::CrossZoneSetEntityVariableByNPCTypeID(uint32 npctype_id, cons
safe_delete(pack);
}
+void QuestManager::WorldWideMarquee(uint32 Type, uint32 Priority, uint32 FadeIn, uint32 FadeOut, uint32 Duration, const char *Message) {
+ uint32 message_len = strlen(Message) + 1;
+ auto pack = new ServerPacket(ServerOP_WWMarquee, sizeof(WWMarquee_Struct) + message_len);
+ WWMarquee_Struct* WWMS = (WWMarquee_Struct*) pack->pBuffer;
+ WWMS->Type = Type;
+ WWMS->Priority = Priority;
+ WWMS->FadeIn = FadeIn;
+ WWMS->FadeOut = FadeOut;
+ WWMS->Duration = Duration;
+ strn0cpy(WWMS->Message, Message, 512);
+ worldserver.SendPacket(pack);
+ safe_delete(pack);
+}
+
bool QuestManager::EnableRecipe(uint32 recipe_id)
{
bool success = false;
diff --git a/zone/questmgr.h b/zone/questmgr.h
index 612c7815f..10c82c1ee 100644
--- a/zone/questmgr.h
+++ b/zone/questmgr.h
@@ -252,6 +252,7 @@ public:
void CrossZoneSignalPlayerByName(const char *CharName, uint32 data);
void CrossZoneSetEntityVariableByNPCTypeID(uint32 npctype_id, const char *id, const char *m_var);
void CrossZoneMessagePlayerByName(uint32 Type, const char *CharName, const char *Message);
+ void WorldWideMarquee(uint32 Type, uint32 Priority, uint32 FadeIn, uint32 FadeOut, uint32 Duration, const char *Message);
bool EnableRecipe(uint32 recipe_id);
bool DisableRecipe(uint32 recipe_id);
void ClearNPCTypeCache(int npctype_id);
diff --git a/zone/spells.cpp b/zone/spells.cpp
index 2e99e97a9..c818c8e90 100644
--- a/zone/spells.cpp
+++ b/zone/spells.cpp
@@ -5458,8 +5458,10 @@ void Mob::SendBuffsToClient(Client *c)
EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target)
{
uint32 count = 0;
- uint32 buff_count = GetMaxTotalSlots();
- for(unsigned int i = 0; i < buff_count; ++i)
+ // for self we want all buffs, for target, we want to skip song window buffs
+ // since NPCs and pets don't have a song window, we still see it for them :P
+ uint32 buff_count = for_target ? GetMaxBuffSlots() : GetMaxTotalSlots();
+ for(int i = 0; i < buff_count; ++i)
{
if(buffs[i].spellid != SPELL_UNKNOWN)
{
@@ -5491,7 +5493,7 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target)
buff->type = 0;
uint32 index = 0;
- for(unsigned int i = 0; i < buff_count; ++i)
+ for(int i = 0; i < buff_count; ++i)
{
if(buffs[i].spellid != SPELL_UNKNOWN)
{
diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp
index 0f00ed0c5..60a4e7385 100644
--- a/zone/worldserver.cpp
+++ b/zone/worldserver.cpp
@@ -1838,6 +1838,19 @@ void WorldServer::Process() {
}
break;
}
+ case ServerOP_WWMarquee:
+ {
+ WWMarquee_Struct* WWMS = (WWMarquee_Struct*) pack->pBuffer;
+ std::list client_list;
+ entity_list.GetClientList(client_list);
+ auto iter = client_list.begin();
+ std::string Message = WWMS->Message;
+ while (iter != client_list.end()) {
+ Client* client = (*iter);
+ client->SendMarqueeMessage(WWMS->Type, WWMS->Priority, WWMS->FadeIn, WWMS->FadeOut, WWMS->Duration, Message);
+ iter++;
+ }
+ }
case ServerOP_ReloadWorld:
{
ReloadWorld_Struct* RW = (ReloadWorld_Struct*) pack->pBuffer;