Merge branch 'master' into event_loop

This commit is contained in:
KimLS 2016-09-10 22:19:39 -07:00
commit 8a73f50601
21 changed files with 891 additions and 1989 deletions

View File

@ -1,54 +1,59 @@
EQEmu
===
# EQEmulator Core Server
|Travis CI (Linux)|Appveyor (Windows) |
|:---:|:---:|
|[![Linux CI](https://travis-ci.org/EQEmu/Server.svg?branch=master)](https://travis-ci.org/EQEmu/Server) |[![Windows CI](https://ci.appveyor.com/api/projects/status/d0cvokm7u732v8vl/branch/master?svg=true)](https://ci.appveyor.com/project/KimLS/server/branch/master) |
[![Linux CI](https://travis-ci.org/EQEmu/Server.svg?branch=master)](https://travis-ci.org/EQEmu/Server)
[![Windows CI](https://ci.appveyor.com/api/projects/status/d0cvokm7u732v8vl/branch/master?svg=true)](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 Install Count](http://analytics.akkadius.com/?install_count&windows_count)|![Linux Install Count](http://analytics.akkadius.com/?install_count&linux_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|
|:---:|:---:|:---:|:---:|:---:|
|<img src="http://i.imgur.com/hrwDxoM.jpg" height="150">|<img src="http://i.imgur.com/cRDW5tn.png" height="150">|<img src="http://i.imgur.com/V48kuVn.jpg" height="150">|<img src="http://i.imgur.com/IJQ0XMa.jpg" height="150">|<img src="http://i.imgur.com/OMpHkKa.png" height="100">|
Bug reports
---
Please use the [issue tracker](https://github.com/EQEmu/Server/issues) provided by GitHub to send us bug
## Bug Reports <img src="http://i.imgur.com/daf1Vjw.png" height="20">
* 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 <img src="http://image.flaticon.com/icons/png/512/25/25231.png" width="20">
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 <img src="http://gamerescape.com/wp-content/uploads/2015/06/discord.png" height="20">
- 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)

View File

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

View File

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

View File

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

View File

@ -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 (<MYSQL_CHECK>){
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 (<INSTALL_VARS>){
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 (<MYSQL_CHECK>){
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 = <STDIN>;
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=~/\<longname\>/i){
my($replace_name) = $o =~ /<longname>(.*)<\/longname>/;
$append = '(' . generate_random_password(5) . ')';
$o =~ s/$replace_name/Akkas $OS PEQ Installer $append/g;
}
if($o=~/\<username\>/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(<F>) {
s/\r//g;
if(/<database>/i) { $indb = 1; }
next unless($indb == 1);
if(/<\/database>/i) { $indb = 0; last; }
if(/<host>(.*)<\/host>/i) { $host = $1; }
elsif(/<username>(.*)<\/username>/i) { $user = $1; }
elsif(/<password>(.*)<\/password>/i) { $pass = $1; }
elsif(/<db>(.*)<\/db>/i) { $db = $1; }
if(/<longname>(.*)<\/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;
}
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -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');

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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, "$$");

View File

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

View File

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

View File

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

View File

@ -1838,6 +1838,19 @@ void WorldServer::Process() {
}
break;
}
case ServerOP_WWMarquee:
{
WWMarquee_Struct* WWMS = (WWMarquee_Struct*) pack->pBuffer;
std::list<Client*> 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;