Compare commits

...

98 Commits

Author SHA1 Message Date
KimLS 751e61d6e5 Converted all the EQStreams into EQStreamInterfaces, dear god help us. 2016-09-24 22:43:29 -07:00
Michael Cook (mackal) 4cb7d9a352 Remove ability for charmed NPCs from summoning
These rules do not appear to be true on live
They also don't look to have ever been true?
2016-09-22 00:32:01 -04:00
Michael Cook (mackal) b04844aa94 Fix merge [skip ci] 2016-09-21 23:54:51 -04:00
Akkadius b15ada974f Merge pull request #555 from noudess/master
Task experience based on % of level did not take into effect hell level rule
2016-09-18 20:38:08 -05:00
Paul Coene e2587b78f5 Merge remote-tracking branch 'upstream/master'
Conflicts:
	changelog.txt
2016-09-18 21:32:09 -04:00
Akkadius 06dfba3c81 Merge pull request #557 from KinglyKrab/master
Added quest global support for zone_controller.
2016-09-14 15:34:16 -05:00
Kinglykrab 8aa942cd27 Added quest global support for zone_controller. 2016-09-14 16:31:52 -04:00
Akkadius a9070b1327 Merge pull request #556 from KinglyKrab/master
#summon will now work when you are in an instance.
2016-09-12 01:42:53 -05:00
Akkadius 745510ea75 Massive overhaul of the update system and EQEmu Server management utility framework
(known as eqemu_update.pl) now known as eqemu_server.pl
	- eqemu_server.pl is now a general EQEmu Server management utiltiy framework that can be used
		to extend to many purposes. It's main purpose is to simplify server management
	- eqemu_server.pl changes:
		- Menu has been completely changed, instead of a number based (enter number and hit enter)
		you now type commands within the menu (Ex: 'database')
		- Handles last mile installation for Windows Servers (See Github Readme)
		- Handles last mile installation for Linux Servers (See Github Readme)
			- Ubuntu
			- Debian
			- Fedora
			- CentOS
		- Now checks for Internet connection before performing web requests
		- Database:
			- Regular schema updates now happen automatically, if new binaries present updated
				database schema changes, script will backup first, auto update database, and continue
				world bootup
			- Regular bots database schema changes now happen automatically similarily to the above
			- Database checks can also be ran manually via the script menu
		- CLI Arguments
			- Arguments passed to eqemu_server.pl can execute the same name-based operations that
				are present in the interactive menu
					- Example: "perl eqemu_server.pl opcodes" will download opcodes
					- Example: "perl eqemu_server.pl backup_player_tables" will backup and export player tables
		- Bots
			- Bots can now be automatically setup in Linux or Windows via the 'setup_bots' command
				- Windows will auto download binaries and install, along with installing bots db schema
				- Linxu will auto compile binaries and install, along with installings bots db schema
		- Utility scripts
			- Linux now has the following utility scripts for download, available via menu 'utility_scripts'
				and via Linux default install:
					- server_launcher.pl
					- server_start_dev.sh
					- server_start.sh
					- server_status.sh
					- server_stop.sh
		- Usage analytics
			- eqemu_server.pl now collects usage analytics, this is very helpful for our developers
				- Example: We can see how many installs have been performed:
					https://github.com/EQEmu/Server#server-installs
				- This helps us see how often certain utilities are used as well
		- Console Messages
			- All script messages have been prefixed with a bracket action Ex: [Update] [Database] [Info]
				to be more consistent with our log conventions
		- 'New Server' Utility
			- Running 'new_server' from the main menu or 'perl eqemu_server.pl new_server' while in
				a completely new folder with just the script present, will allow a server operator
				to initiate a full clean PEQ install in that folder. Pulling down all assets and
				installing a PEQ database with the name the server operator gives the prompts in the
				script
2016-09-12 01:31:35 -05:00
Kinglykrab f6d721dd72 #summon will now work when you are in an instance. 2016-09-11 19:25:41 -04:00
Paul Coene 0503e85fd3 Updated changelog 2016-09-10 14:26:47 -04:00
Paul Coene 0232f4f672 Merge remote-tracking branch 'upstream/master' 2016-09-10 14:21:59 -04:00
Paul Coene 56d355935b Fix task experience by level % to take into account hell level rule. 2016-09-10 14:21:19 -04:00
Natedog2012 d260bb5cd4 Merge pull request #554 from KinglyKrab/master
Added support for server-wide marquee messages.
2016-09-10 10:10:18 -07:00
Kinglykrab 4816c1fc9a Added support for server-wide marquee messages. 2016-09-09 23:59:23 -04:00
Michael Cook (mackal) 50469b858b Merge pull request #553 from KinglyKrab/master
Added GetAAPercent() to Perl and Lua.
2016-09-08 22:08:47 -04:00
Kinglykrab 64998a398d Added GetAAPercent() to Perl and Lua. 2016-09-08 21:59:15 -04:00
Akkadius 9a3af63f65 Update readme [skip ci] 2016-09-07 15:10:16 -05:00
Akkadius 5679f45f5b Update readme [skip ci] 2016-09-07 12:45:14 -05:00
Akkadius 66c0da85e6 Take out Linux source build from the install.sh file since eqemu_server.pl is flexibly taking care of it 2016-09-06 22:51:29 -05:00
Akkadius 4246e4f79b Fix linux installs when in new_server routine [skip ci] 2016-09-06 22:44:37 -05:00
Akkadius 90dc7a4e38 Fix linux installs [skip ci] 2016-09-06 22:36:50 -05:00
Akkadius bf28354301 Upload Linux installer for Debian/Ubuntu/CentOS/Fedora utils/scripts/linux_installer/install.sh [skip ci] 2016-09-06 22:14:14 -05:00
Akkadius 5f1141dfb1 eqemu_server.pl - Auto update bots database on world bootup if bots enabled [skip ci] 2016-09-06 22:04:38 -05:00
Akkadius 5b03fba463 Update eqemu_server.pl - Fix windows installs [skip ci] 2016-09-06 20:04:21 -05:00
Akkadius 0efd0c5f73 Update eqemu_server.pl [skip ci] 2016-09-05 15:26:12 -05:00
Akkadius 2947e3f39f Update eqemu_server.pl [skip ci] 2016-09-05 02:33:18 -05:00
Akkadius 77974c83d7 Update eqemu_server.pl [skip ci] 2016-09-05 02:31:28 -05:00
Michael Cook (mackal) d0bb3047f0 Let's fix the fear pathing flags right away after SE_ImmuneFleeing
This speeds up the response to spells like Call of Challenge
Before it would fix the flags the next tick, which makes the spell
mostly useless
2016-09-04 20:59:39 -04:00
Michael Cook (mackal) 739b1bfaa3 Fix target buffs showing PC songs 2016-09-03 21:54:59 -04:00
Uleat fb308eaa01 Rule-based update to 'Bind Wound' behavior 2016-09-03 17:08:48 -04:00
Michael Cook (mackal) 7c40bcff53 Fix enrage for NPC classes that can't ripo 2016-09-02 18:16:09 -04:00
Akkadius ec87656d58 Add rule Spells:NPCInnateProcOverride, defaults to true 2016-09-01 01:05:06 -05:00
Uleat 159ba9f487 Fix for BotDatabase::SaveEquipmentColor crash 2016-08-31 23:02:16 -04:00
Michael Cook (mackal) d8fe5124ff Fix some spell set loading issues 2016-08-29 19:23:40 -04:00
Michael Cook (mackal) fa337d441e Use StopCasting when we send SPELL_RECAST error 2016-08-29 14:08:22 -04:00
Michael Cook (mackal) ea1ae1a0a4 Use StopCasting instead of Interrupt on SpellFinished failure
Most of these failures already show a message, live doesn't double
up on failure message + interrupt message, so lets not

There are a few logic error returns, but those really shouldn't happen
2016-08-29 13:27:42 -04:00
Michael Cook (mackal) 95ea61114a Merge pull request #551 from N0ctrnl/patch-1
Added rule to allow MQ2 targeting without filling up the hackers table
2016-08-28 17:34:19 -04:00
Kurt Gilpin 585e5830f7 Update client_packet.cpp 2016-08-28 12:23:59 -05:00
Kurt Gilpin bfb77803d8 Update client_packet.cpp 2016-08-28 07:03:00 -05:00
Kurt Gilpin 364ab42c49 Add rule to ignore MQ2 targeting 2016-08-28 07:00:20 -05:00
Michael Cook (mackal) 89183cf8b7 clang-format LoadZoneObjects 2016-08-27 22:26:44 -04:00
Michael Cook (mackal) aaa116d97c Add support for object display names
Ex. Kejek Forge in Stonebrunt Mountains
2016-08-27 22:24:08 -04:00
Michael Cook (mackal) 4360021fc9 Merge pull request #550 from KinglyKrab/master
World:EnableIPExemptions should be false by default. (Woops.)
2016-08-27 21:45:17 -04:00
Kinglykrab b7b233d46f World:EnableIPExemptions should be false by default. (Woops.) 2016-08-27 21:44:04 -04:00
Akkadius 5c43f2d80e Merge pull request #549 from KinglyKrab/master
Fixed quantity in merchant purchase.
2016-08-27 16:59:58 -05:00
Kinglykrab ed9b6db369 Added optional IP-based account exemptions. 2016-08-27 17:49:04 -04:00
Akkadius dd0d15e134 More testing [skip ci] 2016-08-27 03:20:22 -05:00
Akkadius 29d6817019 More testing [skip ci] 2016-08-27 03:19:33 -05:00
Akkadius 46bb559af1 Updated db_dumper.pl script print output formats [skip ci] 2016-08-27 01:41:09 -05:00
Akkadius 031a37baa1 Set eqemu_server.pl to check database manifest for only updates that are higher than the local database version - this will prevent false previous match conditions [skip ci] 2016-08-27 01:25:22 -05:00
Akkadius 62a4ce76b6 Merge branch 'master' of https://github.com/EQEmu/Server 2016-08-27 01:23:23 -05:00
Akkadius d85e6ae495 Set eqemu_server.pl to check database manifest for only updates that are higher than the local database version - this will prevent false previous match conditions [skip ci] 2016-08-27 01:23:03 -05:00
Akkadius 32c4c360bd Add IsHorse to default false in Mob constructor 2016-08-27 01:21:23 -05:00
Akkadius f2a075d432 Keep eqemu_server.pl from chown'ing the script to a pre-fixed user [skip ci] 2016-08-27 00:52:48 -05:00
Akkadius 2dee62c850 Refactor didn't save (oops) 2016-08-27 00:47:55 -05:00
Akkadius db380944ac Prevent horses (player mounts) from being depopped during a #repop 2016-08-27 00:46:45 -05:00
Kinglykrab 28c5b32624 Modified quantity in Merchant_Sell_Struct to be uint32 in accordance with Merchant_Purchase_Struct. This will allow you to buy stacks of items beyond 255. (Tested with a stack of 1,000 Arrows.) 2016-08-26 18:46:22 -04:00
Akkadius 6db350790e Merge branch 'master' of https://github.com/EQEmu/Server 2016-08-26 15:02:43 -05:00
Akkadius 3f8ff1373c Fix script call issue [skip ci] 2016-08-26 15:02:12 -05:00
Akkadius d6ee505c63 Merge pull request #548 from Natedog2012/master
Add TiltX and TiltY manipulation to objects (Perl)
2016-08-26 14:28:28 -05:00
Akkadius e84b2ba224 Merge pull request #546 from noudess/master
Mobs that path and then despawn do so whether zone idle or active
2016-08-26 14:26:50 -05:00
Natedog2012 4de9b2c53e Add TiltX and TiltY manipulation to objects (Perl)
Translate OP_GroundSpawn for Titanium

#perl plugin http://wiki.eqemulator.org/i?Module=Pastebin&Paste=u9IbA6Ql
2016-08-26 06:39:39 -07:00
Akkadius 385823461b Update eqemu_server.pl [skip ci] 2016-08-25 18:30:04 -05:00
Akkadius 85c28185a2 Update eqemu_server.pl - Add internet connection checks for people who are using EQEmu locally [skip ci] 2016-08-25 18:01:17 -05:00
Akkadius 25de25a777 Update eqemu_server.pl - Add internet connection checks for people using EQEmu locally [skip ci] 2016-08-25 18:00:13 -05:00
Akkadius 357a92dfee Update eqemu_server.pl [skip ci] 2016-08-25 16:46:34 -05:00
Akkadius 35c83db432 eqemu_server.pl - Run script after self upgrade regardless of OS [skip ci] 2016-08-25 16:43:35 -05:00
Akkadius f7cc1053f1 eqemu_server.pl - Update regardless of run condition [skip ci] 2016-08-25 16:39:35 -05:00
Akkadius d5864aea3e Few more adjustments [skip ci] 2016-08-25 16:36:48 -05:00
Akkadius 2b2d6e1ef5 Less fail [skip ci] 2016-08-25 16:33:50 -05:00
Akkadius f99523dc48 Migration to new EQEmu Server management script interface 2016-08-25 16:32:21 -05:00
Akkadius 69913c0897 Update eqemu_server.pl [skip ci] - More cleanup 2016-08-25 15:01:59 -05:00
Akkadius 75694e8797 Update eqemu_server.pl [skip ci] Testing self update 2016-08-25 13:00:57 -05:00
Akkadius 24856b6a2d Update eqemu_server.pl [skip ci] Testing self update 2016-08-25 12:56:30 -05:00
Akkadius a70291f20f Update eqemu_server.pl [skip ci] 2016-08-25 12:50:26 -05:00
Akkadius 6e1a5eac94 Update eqemu_server.pl [skip ci] 2016-08-25 12:17:24 -05:00
Akkadius 37b87e98f4 Update eqemu_server.pl [skip ci] 2016-08-25 01:18:03 -05:00
Michael Cook (mackal) 55d2e9b842 Only correct spell slots when we're sending to self
This will fix display issues with lots of buffs on NPCs
2016-08-24 23:15:31 -04:00
Akkadius 3afc5d0890 Update eqemu_server.pl [skip ci] 2016-08-24 21:03:23 -05:00
Akkadius f6b6fcc2c5 Update eqemu_server.pl 2016-08-24 20:38:56 -05:00
Paul Coene 5039aa07a5 updated changelog 2016-08-23 14:50:29 -04:00
Paul Coene 8048239a81 Merge remote-tracking branch 'upstream/master' 2016-08-23 13:55:52 -04:00
Paul Coene ecdc0f7096 Fixed so mobs that depop at end of pathgrid still path and depop
whiel zones are empty.  This makes these mobs no longer always appear
at start locations for the 1st person in a zone after long idle.
2016-08-23 13:54:51 -04:00
Akkadius 2c3107fbe9 Uploading initial eqemu_server.pl (was eqemu_update.pl) to start deprecrating of eqemu_update.pl and re-working of the structure of the script, more to come. 2016-08-22 16:07:44 -05:00
Michael Cook (mackal) c2b31bd6e2 Fix EVENT_ATTACK crash (thanks image)
Note: I guess we need to check if it's null in the actual quest too
2016-08-21 20:26:54 -04:00
Akkadius a8ba563632 Update eqemu_update.pl [skip ci] 2016-08-20 23:50:59 -05:00
Akkadius 4065df7930 Update eqemu_update.pl [skip ci]
Add option 21) Dump DB Player tables (Exports to backups\player_tables_export_(date).sql)
Player table list is referenced/maintained in utils/sql/character_table_list.txt
2016-08-20 23:49:51 -05:00
Akkadius 0b06044dce Update db_dumper [skip ci]
Fix issues with file name output when no compression is set
Add option to set backup_name="backup_name" to prefix backup outputs
2016-08-20 23:47:53 -05:00
Akkadius 93464e3963 Remove duplicate table [skip ci] 2016-08-20 23:32:01 -05:00
Akkadius 8dd18a43a0 Update db_dumper [skip ci] 2016-08-20 23:31:34 -05:00
Akkadius afe42ccdaf Update db_dumper.pl 2016-08-20 23:23:17 -05:00
Akkadius f5a7117bdf Add character_table_list.txt for database backup script reference 2016-08-20 23:13:16 -05:00
Michael Cook (mackal) 696c02c0f0 Move instrument mod outside of the EFFECT lop in SpellEffect 2016-08-20 14:30:54 -04:00
Akkadius 6daf207323 Quick test 2016-08-19 16:31:46 -05:00
Michael Cook (mackal) f67cd057f3 Fix issue with linked spell timers 2016-08-18 21:09:02 -04:00
Michael Cook (mackal) 0789d10d3e Add logging message for setting linked reuse 2016-08-18 20:51:58 -04:00
Akkadius a07149919d Pets now don't actually spawn until the player has fully entered the zone (Live-like) 2016-08-18 17:28:32 -05:00
80 changed files with 3658 additions and 2141 deletions
+39 -34
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)
+228 -134
View File
@@ -1,5 +1,99 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
== 09/12/2016 ==
Akkadius: Massive overhaul of the update system and EQEmu Server management utility framework
(known as eqemu_update.pl) now known as eqemu_server.pl
- eqemu_server.pl is now a general EQEmu Server management utiltiy framework that can be used
to extend to many purposes. It's main purpose is to simplify server management
- eqemu_server.pl changes:
- Menu has been completely changed, instead of a number based (enter number and hit enter)
you now type commands within the menu (Ex: 'database')
- Handles last mile installation for Windows Servers (See Github Readme)
- Handles last mile installation for Linux Servers (See Github Readme)
- Ubuntu
- Debian
- Fedora
- CentOS
- Now checks for Internet connection before performing web requests
- Database:
- Regular schema updates now happen automatically, if new binaries present updated
database schema changes, script will backup first, auto update database, and continue
world bootup
- Regular bots database schema changes now happen automatically similarily to the above
- Database checks can also be ran manually via the script menu
- CLI Arguments
- Arguments passed to eqemu_server.pl can execute the same name-based operations that
are present in the interactive menu
- Example: "perl eqemu_server.pl opcodes" will download opcodes
- Example: "perl eqemu_server.pl backup_player_tables" will backup and export player tables
- Bots
- Bots can now be automatically setup in Linux or Windows via the 'setup_bots' command
- Windows will auto download binaries and install, along with installing bots db schema
- Linxu will auto compile binaries and install, along with installings bots db schema
- Utility scripts
- Linux now has the following utility scripts for download, available via menu 'utility_scripts'
and via Linux default install:
- server_launcher.pl
- server_start_dev.sh
- server_start.sh
- server_status.sh
- server_stop.sh
- Usage analytics
- eqemu_server.pl now collects usage analytics, this is very helpful for our developers
- Example: We can see how many installs have been performed:
https://github.com/EQEmu/Server#server-installs
- This helps us see how often certain utilities are used as well
- Console Messages
- All script messages have been prefixed with a bracket action Ex: [Update] [Database] [Info]
to be more consistent with our log conventions
- 'New Server' Utility
- Running 'new_server' from the main menu or 'perl eqemu_server.pl new_server' while in
a completely new folder with just the script present, will allow a server operator
to initiate a full clean PEQ install in that folder. Pulling down all assets and
installing a PEQ database with the name the server operator gives the prompts in the
script
== 09/10/2016 ==
noudess: Task system experience based on a % of a level did not take into
account the hell levels rule. Now it does.
== 09/04/2016 (Changes over past few months) ==
Akkadius: Fixed an issue where clients would crash with health marquee's
Akkadius: Fixed issues with NPC's "ghosting" when they path
Akkadius: Overhauled worldserver logging
Akkadius: Pets now don't actually spawn until the player has fully entered the zone (Live-like)
demonstar/KLS: Adjusted some background workings on how spell buff tics are synced with the client
Uleat: Optimizations to map loading and zone times
Uleat/Akkadius: Fixed bandolier exploit where you could equip a 2H and Shield
mackal: Re-worked spell re-use timer logic
mackal: Source optimizations all over, crash fixes
mackal: Fixed some issues with illusions on zoning
mackal: Fixed some client DOT stacking bugs
mackal: Invis will now break on AA spell casts and item cast
mackal: Changed how Loot response code works
mackal: Implemented 3 additional spell gems with (Mnemonic Retention)
mackal: Instant spells now have instrument mods
mackal: Rate limit character saves
mackal: Made it so items no longer do TGB (Live-like) Rule implemented to disable
mackal: Set pet buffs limit to 30
== 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.
- Example: exemption_ip of IP 192.168.1.4 in ip_exemptions with exemption_amount of 1 will allow only 1 account to login from IP 192.168.1.4.
- Note: If there is no exemption, the amount of accounts logged in from a singular IP will default to World:MaxClientsPerIP
== 08/23/2016 ==
noudess: Force mobs on a depop @ end pathgrid to still do this on idle zones.
This makes them be more random after a zone is idle, rather than always showing
up at start point when 1st person logs into an idle zone. Much more like live.
I dion't think this will be much of a performance problem. Once they path and
depop, no mkore cpu usage.
== 08/14/2016 ==
mackal: Implement Linked Spell Reuse Timers
- For whatever reason this is a bit unfriendly, but that's how it is on live.
@@ -395,10 +489,10 @@ mackal: Reworked the activated avoidace skills (riposte, dodge, etc) based on de
Also riposte immunity from the increase riposte chance spell effect.
== 7/2/2015 ==
KLS/Demonstar55: AA system has been rewritten fixing a ton of bugs and extending functionality while making it easier to create new AA points.
KLS/Demonstar55: New tables are needed and so older data will need to be migrated to the new system.
KLS/Demonstar55: The SQL saves the old aa points spent/avail/character_alt_abilities data if any server ops want to do something different than PEQ did with it.
KLS/Demonstar55: Will try to get a wiki entry written up next week some time explaining the system but it's really not hard to follow the db tables in the meantime.
KLS/mackal: AA system has been rewritten fixing a ton of bugs and extending functionality while making it easier to create new AA points.
KLS/mackal: New tables are needed and so older data will need to be migrated to the new system.
KLS/mackal: The SQL saves the old aa points spent/avail/character_alt_abilities data if any server ops want to do something different than PEQ did with it.
KLS/mackal: Will try to get a wiki entry written up next week some time explaining the system but it's really not hard to follow the db tables in the meantime.
== 7/1/2015 ==
Akkadius: Fix an issue where emote messages would overflow the buffer of 256 by increasing the size and changing some of the initialization
@@ -428,7 +522,7 @@ Akkadius: Added DB ver 9082 with update to add npc_types texture columns if tabl
Uleat: Added null-term declaration for character names in ENCODE(OP_CharInfo) - where appropriate
== 05/20/2015 ==
demonstar55: Bard instrument mods should be more consistent with live. Zoning will keep instrument mod for long duration buffs (selo's)
mackal: Bard instrument mods should be more consistent with live. Zoning will keep instrument mod for long duration buffs (selo's)
Still need to have procs/doom effects to inherit the instrument mods from their source buff/whatever
== 05/18/2015 ==
@@ -438,7 +532,7 @@ KLS: Changed how fishing locates water to hopefully be a bit more accurate at th
Uleat: Added check to EntityList::CheckSpawnQueue() to bypass dereference if returned iterator is npc_list.end() - should fix the debug assertion failure crash
== 04/30/2015 ==
demonstar55: Implement mob and client melee push
mackal: Implement mob and client melee push
You can set Combat:MeleePush to false to turn off or change Combat:MeleePushChance to increase the chance an NPC can be pushed
PCs are always pushed, need to do more testing to verify.
@@ -492,7 +586,7 @@ Uleat: Fix for RoF+ clients showing active 'Return Home' button when action is n
Noudess: Starting erudites that were supposed to start in paineel were landing in erudin on Titanium. Fixed to be paineel.
== 02/20/2015 ==
demonstar55: Implement claims for RoF/RoF2 (should no longer crash the client!)
mackal: Implement claims for RoF/RoF2 (should no longer crash the client!)
- fixed bugs related to claims for the rest of the clients (woo infinite loops)
== 02/18/2015 ==
@@ -511,7 +605,7 @@ Notes:
== 02/16/2015 ==
Trevius: (RoF2) Bazaar Trading (Buying/Selling) is now fully functional. Bazaar (/bazaar) search is not yet functional.
demonstar55: (RoF2) Send the bard focus effects, note custom servers will need to fix their items, server side we still use the old system, but RoF2 wasn't showing anything with not sending focus, so send them
mackal: (RoF2) Send the bard focus effects, note custom servers will need to fix their items, server side we still use the old system, but RoF2 wasn't showing anything with not sending focus, so send them
== 02/14/2015 ==
Trevius: (RoF2) Bazaar is now partially functional. RoF2 clients can start/end trader mode and other clients can purchase from them. No other functionality yet.
@@ -561,7 +655,7 @@ Akkadius: Implement Packet logs with dumps
See: http://wiki.eqemulator.org/p?Logging_System_Overhaul#packet-logging-levels
== 02/01/2015 ==
demonstar55: Add quest debugging to lua
mackal: Add quest debugging to lua
eq.debug("Test debug level implicit 1")
eq.debug("Test debug level explicit 1", 1)
eq.debug("Test debug level explicit 2", 2)
@@ -754,7 +848,7 @@ Trevius: Finished lining up the RoF2 Player Profile Struct. Zone times are now
Trevius: Fixed zoning after death for RoF2.
== 12/17/2014 ==
demonstar55: Use vectors for route stuff, should be more CPU cache friendly so faster
mackal: Use vectors for route stuff, should be more CPU cache friendly so faster
Secrets: EQStream changes as recommended by a community member in private.
== 12/15/2014 ==
@@ -764,7 +858,7 @@ Trevius: Player Corpses now saved attuned settings for Items.
Required SQL: utils/sql/git/required/2014_12_15_multiple_table_updates.sql
== 12/13/2014 ==
demonstar55: Fix guild rank spam on zone (needed to be in OP_PP).
mackal: Fix guild rank spam on zone (needed to be in OP_PP).
Trevius: (RoF+) Implemented Armor Ornamentation using Hero's Forge Armor Models. To use, create an ornamentation augment and set the herosforgemodel field in the items table.
Trevius: (RoF+) Added command #heromodel (#hm for short) - Usage: #heromodel [hero forge model] [ [slot] ] (example: #heromodel 63)
@@ -772,11 +866,11 @@ Be sure to run this or there will be item loss:
Required SQL: utils/sql/git/required/2014_12_13_inventory_table_update.sql
== 12/12/2014 ==
demonstar55: Add special attack 42, Ignore Root Aggro Rules. This allows you to root a mob and have them still use the normal aggro rules (so they will attack the one with most hate, not closest)
mackal: Add special attack 42, Ignore Root Aggro Rules. This allows you to root a mob and have them still use the normal aggro rules (so they will attack the one with most hate, not closest)
== 12/09/2014 ==
Trevius: (RoF+) Implemented Hero's Forge Armor Models for Items. To use, set herosforgemodel field in the item table to a model number such as 63 (for example).
demonstar55: SoF+ swarm pets will no longer be F8able (without a hack!)
mackal: SoF+ swarm pets will no longer be F8able (without a hack!)
== 12/08/2014 ==
Secrets: Added a feature that allows an EQ client to log in directly to World without having to enter the LoginServer, provided the 'password' field is set in WorldServer.
@@ -822,10 +916,10 @@ Trevius: Mercenaries now Dismiss, Suspend, Unsuspend, and Die correctly.
Trevius: Mercenaries can now zone once again.
== 11/17/2014 ==
demonstar55: Correct OP_AugmentInfo reply. This fixes RoF display issue with Adventurer's Stone. Still issues with UF/SoF/SoD though.
mackal: Correct OP_AugmentInfo reply. This fixes RoF display issue with Adventurer's Stone. Still issues with UF/SoF/SoD though.
== 11/16/2014 ==
demonstar55: fix size issue with ControlBoat_Struct and exploit fix in OP_BoardBoat
mackal: fix size issue with ControlBoat_Struct and exploit fix in OP_BoardBoat
Akkadius: Implemented Automatic Database update and versioning system
Akkadius: Created database revision define, this is located in version.h in common #define CURRENT_BINARY_DATABASE_VERSION 9057
@@ -902,12 +996,12 @@ Optional SQL: utils/sql/git/optional/2014_11_15_SwarmPetTargetLock.sql
== 11/14/2014 ==
Secrets: Identified object size and solidtype as flags. Exported them as functions to Perl.
demonstar55: Don't use the hack for charms that doesn't work on RoF
demonstar55: UF too
demonstar55: Tit
demonstar55: SoF
demonstar55: SoD
demonstar55: 62 (untested)
mackal: Don't use the hack for charms that doesn't work on RoF
mackal: UF too
mackal: Tit
mackal: SoF
mackal: SoD
mackal: 62 (untested)
== 11/13/2014 ==
Kayen: Implemented target type (44) 'Beams' (which projects an AE infront of caster with a specified length and width).
@@ -933,7 +1027,7 @@ JJ: Implement new Live-like faction adjustment message using rule Client:UseLive
Optional SQL: utils/sql/git/optional/2014_11_09_LiveFactionMessages.sql
== 11/06/2014 ==
demonstar55: Tracking default sort will now be correct order
mackal: Tracking default sort will now be correct order
Trevius: Fixed dynamic merchant list loading. Allows any merchant to be used in any zone.
== 11/03/2014 ==
@@ -957,17 +1051,17 @@ Uleat: Added Client::InterrogateInventory(). Can be invoked by #interrogateinv a
Uleat: Fix for stacking items in a world object..added a new command option: #peekinv world - will show world container contents, if one is in use by target.
== 10/20/2014 ==
demonstar55: Inspect Buffs rank 1 will now show NPC buffs in target window (SoD+)
mackal: Inspect Buffs rank 1 will now show NPC buffs in target window (SoD+)
== 10/19/2014 ==
Uleat: Updated command #peekinv to display item links properly in RoF clients
demonstar55: Group Mentoring in raids
demonstar55: Inspect Buffs (text only version) works in raid groups
demonstar55: Make use of the Inspect Buffs op/packet. 62 SOL until someone finds its op
mackal: Group Mentoring in raids
mackal: Inspect Buffs (text only version) works in raid groups
mackal: Make use of the Inspect Buffs op/packet. 62 SOL until someone finds its op
== 10/18/2014==
demonstar55: Implement group mentor, sharing leadership exp (SoF+ only)
demonstar55: Add gaining of group leadership while in raids
mackal: Implement group mentor, sharing leadership exp (SoF+ only)
mackal: Add gaining of group leadership while in raids
== 10/16/2014 ==
Uleat: Fixed the auto-conversion view naming error and renamed the views in the script files. Added a fix sql for databases that auto-converted.
@@ -980,7 +1074,7 @@ Notes: I modifed the behavior of both load and drop bots to fail on the first op
a few altered tables back to their original state - as of the date in the file.
== 10/13/2014 ==
demonstar55: Partially implement leadership and raids
mackal: Partially implement leadership and raids
Currently working: client side only effects and stat bonuses.
Not working: Mark NPC, and other stuff that need extra server side support
Currently only UF tested (Tit and 62 may just work, others need packet work)
@@ -989,7 +1083,7 @@ demonstar55: Partially implement leadership and raids
Akkadius: Fix for LDON Character Stat load
== 10/11/2014 ==
demonstar55: Implement Raid MOTD for UF
mackal: Implement Raid MOTD for UF
Don't forget 2014_10_11_RaidMOTD.sql!
== 10/09/2014 ==
@@ -1002,7 +1096,7 @@ previously and/or manually changed code, or just have a need for it to re-run, c
** This will only work if you haven't deleted your `character_old` table **
== 10/07/2014 ==
demonstar55: Identified tutorial flag in all charcreate packets, reworked logic to correctly set homes binds
mackal: Identified tutorial flag in all charcreate packets, reworked logic to correctly set homes binds
== 10/05/2014 ==
Uleat: Added Server<->Corpse slot translators needed for re-enumeration (inactive until phased in)
@@ -1020,13 +1114,13 @@ Uleat: First round of Ti/6.2 translators added - needed for re-enumeration
== 10/01/2014 ==
Kayen: Exported to PERL $client->SendColoredText(color, msg)
demonstar55: Exported SendColoredText to lua
mackal: Exported SendColoredText to lua
== 09/30/2014 ==
Uleat: Implemented click-casting from bag slots for clients that natively support it (RoF)
== 09/28/2014 ==
demonstar55: Add support for post June 18, 2014 Hundred Hands Effect spells (they changed the formula and stuff)
mackal: Add support for post June 18, 2014 Hundred Hands Effect spells (they changed the formula and stuff)
set Spells:Jun182014HundredHandsRevamp to true if you're using a spell file from June 18, 2014+
== 09/27/2014 ==
@@ -1035,15 +1129,15 @@ Note: identifier is the stat field in spells_new, slot is used for certain effec
Example $mob->GetSpellStat(121, "range"); //Returns spell range
Example $mob->GetSpellStat(121, "effectid", 1); //Returns the the value of effectid1
This will allow you to pull almost all the data for any spell in quest files.
demonstar55: Move the client's SetAttackTimer to the end of Client::CalcBonuses to keep the haste in sync
demonstar55: Correct haste/slow "stacking" rules
demonstar55: Correct SE_AttackSpeed4 to respect unslowable
demonstar55: Make the haste be between 1-225 like the client (<100 = slow, >100 = haste) to ...
demonstar55: Correct Hundred Hands effect and use formula provided by devs
mackal: Move the client's SetAttackTimer to the end of Client::CalcBonuses to keep the haste in sync
mackal: Correct haste/slow "stacking" rules
mackal: Correct SE_AttackSpeed4 to respect unslowable
mackal: Make the haste be between 1-225 like the client (<100 = slow, >100 = haste) to ...
mackal: Correct Hundred Hands effect and use formula provided by devs
== 09/24/2014 ==
Uleat: Re-ordered server opcodes and handlers to give them some predictability of location (I need this for the inventory re-enumeration.)
demonstar55: Added helper function bool EQEmu::IsTradeskill(uint32 skill)
mackal: Added helper function bool EQEmu::IsTradeskill(uint32 skill)
== 09/23/2014 ==
Kayen: Spell recourse effects will now be applied AFTER the base spells effects have been applied (consistent with live).
@@ -1152,46 +1246,46 @@ Akkadius: Player Profile Blob to Database Conversion
ORDER BY DATA DESC;
== 09/20/2014 ==
demonstar55: Fix crash in SendEnterWorld on illegally long names
demonstar55: The client only lets you enter 15 characters for your name (UF at least)
demonstar55: Add rule Spells:SHDProcIDOffByOne for pre-UF spell file, set to true, UF+ set to false
mackal: Fix crash in SendEnterWorld on illegally long names
mackal: The client only lets you enter 15 characters for your name (UF at least)
mackal: Add rule Spells:SHDProcIDOffByOne for pre-UF spell file, set to true, UF+ set to false
KLS: #suspend and #ban now have required messages to record the reason for the ban/suspension.
== 09/19/2014 ==
demonstar55: Added Client::Tell_StringID (used in tell queue messages)
demonstar55: Tell queues (and offline) messages now show correctly
demonstar55: Fix starting with capital check
mackal: Added Client::Tell_StringID (used in tell queue messages)
mackal: Tell queues (and offline) messages now show correctly
mackal: Fix starting with capital check
== 09/18/2014==
demonstar55: Implement tell queues
mackal: Implement tell queues
Currently set to a limit of 20 by default (World:TellQueueSize) I was unable to hit the limit on live though (100+)
The required SQL nukes the old tell queue table, which may or may not be in your DB
Optional SQL adds the rule to the DB to allow easy of change
Note: this does not play well with multiple sessions with the same name on (crash and relog and have multiple sessions) but normal tells don't play well either
== 09/16/2014 ==
demonstar55: Implement spell formula 137 (BER AA Desperation)
mackal: Implement spell formula 137 (BER AA Desperation)
Uleat (NateDog): Fix for LoadBuffs() crash when a spell with a non-persistent Illusion effect was loaded.
demonstar55: Fix some effect calcs + implement more (derived from the client)
mackal: Fix some effect calcs + implement more (derived from the client)
== 09/15/2014 ==
Kayen: Nimbus effects will now be reapplied after zoning and will be removed when associated buff fades.
== 09/13/2014 ==
demonstar55: Fix rogues not having Thieves' Cant
mackal: Fix rogues not having Thieves' Cant
== 09/09/2014 ==
demonstar55: Incrase Mob kick/bash timer by 3
mackal: Incrase Mob kick/bash timer by 3
see: http://www.eqemulator.org/forums/showthread.php?t=38734
demonstar55: Fix slow effect on NPC special attack reuse timers
mackal: Fix slow effect on NPC special attack reuse timers
see: http://www.eqemulator.org/forums/showthread.php?t=38734
demonstar55: Slow fixes to bots!
demonstar55: Revamped how NPC attack rate is set
mackal: Slow fixes to bots!
mackal: Revamped how NPC attack rate is set
SQL: 2014_09_09_attack_delay.sql
demonstar55: Added attackdelay to #npcedit
mackal: Added attackdelay to #npcedit
== 09/08/2014 ==
demonstar55: Fix slow calc
mackal: Fix slow calc
see: http://www.eqemulator.org/forums/showthread.php?t=38734
== 09/07/2014 ==
@@ -1202,18 +1296,18 @@ Uleat: Tweaked 'Smart' trading code to return main slots before sub slots in sta
== 09/05/2014 ==
Uleat: Fix for cursor item loss when zoning. (Thanks to the other devs who traced and fixed the 'macro' issue!)
demonstar55: Fix size getting nuked with lua's SendIllusionPacket
mackal: Fix size getting nuked with lua's SendIllusionPacket
== 09/03/2014 ==
Secrets: Identified the routines needed to augment items in RoF. Currently, only Insert and Remove are supported. Swap and Destroy do not work due to missing functions related to the cursor.
demonstar55: Added work around command to show numhits on your buffs (#shownumhits)
mackal: Added work around command to show numhits on your buffs (#shownumhits)
Uleat: Fix for timer issue introduced by Zone::ShutDown() fix.
== 09/02/2014 ==
Secrets: Identified OP_GuildPromote for RoF clients.
Secrets: Fixed promotion, demotion, transferring a leader and displaying of client ranks in the Rain of Fear client. The rain of fear client, as such, will only have 3 ranks like the other clients, but supports a theoretical 8 ranks later.
Secrets/Akkadius: Fixed an issue involving character name lookup in the new DB code.
demonstar55: crash fix checking DivineAura in hate_list.cpp
mackal: crash fix checking DivineAura in hate_list.cpp
Secrets: Reverted some code that got in the main branch that shouldn't have gotten there.
Uleat: Changed #loc to report the same precision as /loc for Cartesians
@@ -1224,7 +1318,7 @@ KLS: Fixed a few quest related inconsistencies.
KLS: Added Lua EntityList::ChannelMessage(from, type, msg, language)
== 08/30/2014 ==
demonstar55: (noudess) Merchants should be more descriptive of why they don't sell to you
mackal: (noudess) Merchants should be more descriptive of why they don't sell to you
== 08/26/2014 ==
Uleat: Implemented 'Smart' Player Trade transfers. Trades are processed by containers, stackables and then all remaining. QueryServ logs have been updated to match these transactions.
@@ -1602,7 +1696,7 @@ Optional SQL: utils/sql/git/optional/2014_04_03_SpellProjectileRules.sql
Note: The rules in this SQL are for setting the item id for the graphic used by the projectile on different clients.
== 04/01/2014 ==
demonstar55: Implemented ability for a merchant to open and close shop.
mackal: Implemented ability for a merchant to open and close shop.
Lua quest functions: e.self:MerchantOpenShop() and e.self:MerchantCloseShop()
GM Commands: #merchant_open_shop (short: #open_shop) and #merchant_close_shop (short: #close_shop)
default to status 100, just in case you need to force the merchants status
@@ -1668,7 +1762,7 @@ Kayen: Revision to lull/harmony/pacification code to be consistent with live bas
which if 'resisted' will cause the caster to gain aggro.
== 03/05/2014 ==
demonstar55: Corrected rogue's evade to be single target
mackal: Corrected rogue's evade to be single target
sorvani: fixed crash issue 119
== 03/04/2014 ==
@@ -1683,7 +1777,7 @@ Kayen: Revision to root code to be consistent with live based on extensive perso
Optional SQL: utils/sql/git/optional/2014_03_04_RootRule.sql
== 03/03/2014 ==
demonstar55: Implemented deadly strikes and gave rogues higher innate throwing crit chance
mackal: Implemented deadly strikes and gave rogues higher innate throwing crit chance
New rules: Combat:RogueCritThrowingChance, Combat:RogueDeadlyStrikeChance, Combat:RogueDeadlyStrikeMod
Defaults should give fairly close to live results
@@ -1695,7 +1789,7 @@ Kayen: Revision to charm code to be consistent with live based on extensive pers
Optional SQL: utils/sql/git/optional/2014_03_02_CharmRules.sql
demonstar55: Melee Crits, HoTs, DoTs messages should now be filtered correctly on all clients.
mackal: Melee Crits, HoTs, DoTs messages should now be filtered correctly on all clients.
Clients that also support seeing others DoTs will now see them if they don't filter them
note: some newer clients have a 'mine only' option for HoTs but it functions the same as show
@@ -1747,7 +1841,7 @@ Sorvani: Renamed the instance_lockout and instance_lockout_player tables to inst
Required SQL: utils/sql/git/2014_02_13_Rename_instance_lockout_tables.sql
== 02/10/2014 ==
demonstar55 (Secrets): Re-wrote the entity list to be a std::map. This should be used for direct entityID lookups and is noticably faster performance-wise. Also should result in less nil pointers potentially.
mackal (Secrets): Re-wrote the entity list to be a std::map. This should be used for direct entityID lookups and is noticably faster performance-wise. Also should result in less nil pointers potentially.
Secrets: Fixed a crash issue that could occur on #repop related to quest timers.
Kayen: Divine Arbiration and other similar spell effects will now utilize a spell range check.
Kayen: Revised how heal amount is calculated to properly incorporate all current focus effects/bonuses.
@@ -1778,14 +1872,14 @@ Kayen: Implemented SE_FfLimitUseType (focus limit to numhits type)
== 01/20/2014 ==
cavedude: Live-Like weather system (Thanks to robregen for figuring it out!)
demonstar55: Implemented not_extendable spell flag
demonstar55: Moved Spell Casting Reinforcement to DB
demonstar55: Moved Mez Mastery to DB
mackal: Implemented not_extendable spell flag
mackal: Moved Spell Casting Reinforcement to DB
mackal: Moved Mez Mastery to DB
Kayen: Complete revision of the numhits systems to utilize 'numhits type' field in spell file.
== 01/18/2014 ==
sorvani: Implemented for Lua eq.get_characters_in_instance(uint16 instance_id), return a Lua HashTable
demonstar55: NPCs will now cast their charms.
mackal: NPCs will now cast their charms.
== 01/13/2014 ==
Kayen: Numerous minor fixes to spell effects.
@@ -1805,19 +1899,19 @@ Kayen: Implemented SE_LimitRace (Limits to spells cast by a certain race)
Kayen: Implemented SE_FcMute (silences casting of spells that contain specific spell effects) ie silence only heals
== 01/09/2014 ==
demonstar55: Add pet size preservation like live (zone, camp, etc)
mackal: Add pet size preservation like live (zone, camp, etc)
== 01/07/2014 ==
demonstar55: Moved pet can attack check to before it tries to attack, which is more live like.
mackal: Moved pet can attack check to before it tries to attack, which is more live like.
== 01/03/2014 ==
demonstar55: Crash prevention for emote.
mackal: Crash prevention for emote.
== 01/02/2014 ==
demonstar55: Stuns from beneficial spells (Harvest) ignore immunity
mackal: Stuns from beneficial spells (Harvest) ignore immunity
== 12/26/2013 ==
demonstar55: Added classes_required to merchantlist (same bitmask as items)
mackal: Added classes_required to merchantlist (same bitmask as items)
== 12/24/2013 ==
Secrets (Akkadius): Perl $client->SilentMessage("Message"); addition, this is a pre-req for a Perl plugin I've shared with EQEmu. This function essentially mimics a player speaking with an NPC - which is used in popup window responses
@@ -1838,14 +1932,14 @@ Kayen: Implemented SE_TriggerOnAmountValue (Trigger spell if HP/Mana/End bellow
Kayen: Fix to SE_BlockNextSpellFocus to make it functional again.
== 12/15/2013 ==
demonstar55: Moved the blocked buff check down so we get spell effects like on live
mackal: Moved the blocked buff check down so we get spell effects like on live
Kayen: Implemented SE_ReduceHealing (Reduces amount of healing on target by X amount)
Kayen: Implemented SE_CastonFocusEffect (Triggers spell as part of a focus, when that focus effect is used)
Kayen: Implemented SE_IncreaseHitDmgTaken (Effect is triggered when X amount of damage is taken)
Kayen: More fixes for various spell triggers/procs to now properly use their resist modifier.
== 12/14/2013 ==
demonstar55: Blocked buffs shouldn't fail, they should just not be applied.
mackal: Blocked buffs shouldn't fail, they should just not be applied.
JJ: Changed enable/disable recipe to confirm change made.
== 12/13/2013 ==
@@ -1856,52 +1950,52 @@ Kayen: Fix for various spell triggers/procs to now properly use their resist mod
Kayen: Fix to mob->ModSkillDmgTaken(skill_num, value), setting value to -1 will now properly effect all skills.
== 12/11/2013 ==
demonstar55: Fixed issue with crippling blow from berserker frenzy not actually doing anything
demonstar55: Fix haste caps
mackal: Fixed issue with crippling blow from berserker frenzy not actually doing anything
mackal: Fix haste caps
== 12/04/2013 ==
demonstar55: Fixed SpellType_Charm case in AICastSpell
mackal: Fixed SpellType_Charm case in AICastSpell
== 12/03/2013 ==
demonstar55: Added #showspellslist to view a mobs spell list
demonstar55: Fix procing off of unattackable things
mackal: Added #showspellslist to view a mobs spell list
mackal: Fix procing off of unattackable things
== 12/02/2013 ==
JJ: Bandaid fix to CopyCharacter function.
== 11/29/2013 ==
demonstar55: Stacking issues should be resolved now, probably could be optimized more, but went from 3 loops that do stuff to 3 where only 2 really does stuff and one breaks early in most cases, so slightly better
mackal: Stacking issues should be resolved now, probably could be optimized more, but went from 3 loops that do stuff to 3 where only 2 really does stuff and one breaks early in most cases, so slightly better
== 11/23/2013 ==
Secrets: Fixed an issue related to a zone crash where the count of the abilities in an AA was 0, leading to a size 0 buffer issue.
== 11/19/2013 ==
Secrets: Fixed an issue with two zone crashes reported on PEQ related to the buff restrictions code and AAs.
demonstar55: Partially make use of dot_stacking_exempt (case when it's 1 is implemented, -1 case isn't)
mackal: Partially make use of dot_stacking_exempt (case when it's 1 is implemented, -1 case isn't)
== 11/18/2013 ==
demonstar55: Added assistradius to npc_types, defaults to aggroradius if set to 0 (old behaviour)
mackal: Added assistradius to npc_types, defaults to aggroradius if set to 0 (old behaviour)
== 11/17/2013 ==
Sorvani: fixed leash and tether special abilities to use the specified range correctly.
demonstar55: Rewrote the Mob::_GetMovementSpeed fix an issue that arose from the change on 11/11
mackal: Rewrote the Mob::_GetMovementSpeed fix an issue that arose from the change on 11/11
- Added the rule Character:BaseRunSpeedCap (default 158) so people can customize what their runspeed cap is. Hardcapped to 225 so stuff doesn't get too crazy.
== 11/16/2013 ==
Leere: Fixed the drinking message for auto-consume, it will again correctly show up for forced consumption instead.
demonstar55: Added Mob::DoCastingChecks() which will check for various fail conditions while the casting bar is up. This is called after Mob::DoCastSpell() starts the casting and before it returns.
mackal: Added Mob::DoCastingChecks() which will check for various fail conditions while the casting bar is up. This is called after Mob::DoCastSpell() starts the casting and before it returns.
== 11/15/2013 ==
demonstar55: Fixed Mob::CalcFocusEffect()'s SE_LimitEffect
mackal: Fixed Mob::CalcFocusEffect()'s SE_LimitEffect
Leere: Fixed a stacking issue for SE_StackingCommand_Block
== 11/13/2013 ==
demonstar55: Implemented bard song effect cap. You can set the base cap with the rule Character:BaseInstrumentSoftCap, defaults to 36 or "3.6" as it is sometimes referred to.
demonstar55: Fix Echo of Taelosia and Ayonae's Tutelage to increase the mod cap instead of further improving the instrument mod
demonstar55: Implemented Singing/Instrument Mastery as an AA bonus.
mackal: Implemented bard song effect cap. You can set the base cap with the rule Character:BaseInstrumentSoftCap, defaults to 36 or "3.6" as it is sometimes referred to.
mackal: Fix Echo of Taelosia and Ayonae's Tutelage to increase the mod cap instead of further improving the instrument mod
mackal: Implemented Singing/Instrument Mastery as an AA bonus.
== 11/11/2013 ==
demonstar55: Changed the way walk speed is calculated to allow mobs to have their walk speed equal a 100% movement reduction
mackal: Changed the way walk speed is calculated to allow mobs to have their walk speed equal a 100% movement reduction
== 11/09/2013 ==
Leere: Fixed Bard mana regen, they now only are affected by items and AA.
@@ -1951,50 +2045,50 @@ Uleat: Converted SkillType typedef enumeration to SkillUseTypes enumeration - So
Uleat: Prepped the client patch files for larger skill buffer size (not active)
== 10/24/2013 ==
demonstar55: Fix some memory leaks in Mob::SpellOnTarget
mackal: Fix some memory leaks in Mob::SpellOnTarget
== 10/21/2013 ==
demonstar55: Changed GetMinLevel return 0 for more cases that EQ uses for some reason ...
demonstar55: Added buff level restrictions, set the Spells:BuffLevelRestrictions to false to have the old behavior.
mackal: Changed GetMinLevel return 0 for more cases that EQ uses for some reason ...
mackal: Added buff level restrictions, set the Spells:BuffLevelRestrictions to false to have the old behavior.
== 10/18/2013 ==
Uleat: Expanded the 'Bag Type' enumeration to include all known values. Also, set in place additional 'Bag Type' to 'Skill Type' conversions. Some of these will need to be verified before activation.
Uleat: Cleaned up some unused enumerations to show a move towards standardization. More to come...
== 10/12/2013 ==
demonstar55: Allow Titanium and lower clients to enter Tutorial zone from character select
mackal: Allow Titanium and lower clients to enter Tutorial zone from character select
Bad_Captain: Fixed merc crash issue by updating special_abilities & vwMercNpcTypes (Sorvani).
Bad_Captain: Bots- added out of combat bard songs & #bot bardoutofcombat on|off command to turn them on/off.
== 10/11/2013 ==
JJ: (demonstar55) Allow use of Go Home button when Tutorial still selected in RoF.
JJ: (mackal) Allow use of Go Home button when Tutorial still selected in RoF.
== 10/10/2013 ==
Secrets: Fixed zone shutdown (or #reloadqst) reinitalization of Perl. This should allow for Perl 5.14 and later to work on Windows under the new quest system.
demonstar55: Beneficial single target buffs shouldn't have their mana/timers set if they fail to cast after the Mob::SpellOnTarget call in Mob::SpellFinished
mackal: Beneficial single target buffs shouldn't have their mana/timers set if they fail to cast after the Mob::SpellOnTarget call in Mob::SpellFinished
JJ: Revert change to EnterWorldPacket introduced on 22 April 2013 to fix inability to enter Tutorial or Go Home from character select screen.
== 10/09/2013 ==
demonstar55: Fixed some more instances of the AA timer being eaten
mackal: Fixed some more instances of the AA timer being eaten
== 10/08/2013 ==
demonstar55: Added IsBuffSpell(spell_id) that will return true if the spell has a duration, so would end up in effects/song/discs etc windows on the client
demonstar55: Replaced instances of using CalcBuffDuration to determine if a spell was a buff with IsBuffSpell
demonstar55: Removed Mob::HasBuffIcon since it was doing what IsBuffSpell does in a more convoluted way with a rather misleading name
demonstar55: Fixed issues that arose from the 10/03/2013 change
mackal: Added IsBuffSpell(spell_id) that will return true if the spell has a duration, so would end up in effects/song/discs etc windows on the client
mackal: Replaced instances of using CalcBuffDuration to determine if a spell was a buff with IsBuffSpell
mackal: Removed Mob::HasBuffIcon since it was doing what IsBuffSpell does in a more convoluted way with a rather misleading name
mackal: Fixed issues that arose from the 10/03/2013 change
== 10/05/2013 ==
Sorvani: fixed issue with stackable items being created with 0 charges cause by fix to SummonItems
== 10/03/2013 ==
demonstar55: Fix when the random +1 tick is added to nerf extension focus effects to where they should be
mackal: Fix when the random +1 tick is added to nerf extension focus effects to where they should be
== 09/30/2013 ==
Sorvani: Changed SummonItem to only summon an item with max charges when said default value is present and not on zero charges
demonstar55: Fixed issue with #showstats showing your level for a bunch of values
mackal: Fixed issue with #showstats showing your level for a bunch of values
== 09/13/2013 ==
demonstar55: Add support for /pet hold on and /pet hold off (UF and RoF)
mackal: Add support for /pet hold on and /pet hold off (UF and RoF)
== 08/29/2013 ==
KLS: Removed Common Profiler and Zone Profiler. They're well past outdated status and are just code bloat.
@@ -2140,8 +2234,8 @@ KLS: Perl now will (like lua) keep track of the values you return from EVENT_*.
KLS: Exported eq.follow(entity_id, [distance]) and eq.stop_follow() to lua.
== 07/01/2013 ==
demonstar55: Fix Monster Summoning related to giants/cyclops
demonstar55: Prevent Monster Summoning from summoning a portal in bothunder
mackal: Fix Monster Summoning related to giants/cyclops
mackal: Prevent Monster Summoning from summoning a portal in bothunder
KLS: Merge of lua branch to master
See: http://www.eqemulator.org/forums/showthread.php?t=37008 for more detailed information on what is added.
Upgrade notes:
@@ -2209,35 +2303,35 @@ JJ: Fixed rare case where heals from buffs could go negative.
Derision: Moved entity_list.Clear() prior to destruction of Perl objects in zone shutdown as I was seeing a segfault due to attempts to call EVENT_HATE_LIST as mobs were being destroyed.
== 04/09/2013 ==
demonstar55: Realized I was an idiot, changed salvage script to be better
mackal: Realized I was an idiot, changed salvage script to be better
optional SQL: 2013_04_09_SalvageCleanOld.sql - run if ran old script
== 04/08/2013 ==
demonstar55: Implemented Salvage AA
mackal: Implemented Salvage AA
required SQL: 2013_04_08_Salvage.sql
script: generate_salvage.py - will generate the entries for some exceptions for salvage returns.
== 04/04/2013 ==
demonstar55: Implemented SE_ForageAdditionalItems as a bonus
mackal: Implemented SE_ForageAdditionalItems as a bonus
required SQL: 2013_04_04_NaturesBounty.sql
== 04/03/2013 ==
demonstar55: Overloaded Mob::Say_StringID with the option to provide a message type
demonstar55: Switched rest of the Pet Messages to MT_PetResponse (Leader commands intentionally left the old way)
mackal: Overloaded Mob::Say_StringID with the option to provide a message type
mackal: Switched rest of the Pet Messages to MT_PetResponse (Leader commands intentionally left the old way)
== 04/2/2013 ==
Bad_Captain: Fixed Merc lack of use of heal over time spells (causing excessive healing).
Bad_Captain: Fixed pet mitigation/AC issues.
== 04/01/2013 ==
demonstar55: AA reuse timers now start when you hit the button and are reset upon failure
demonstar55: Instant Cast bard AAs can now be used while singing a song
mackal: AA reuse timers now start when you hit the button and are reset upon failure
mackal: Instant Cast bard AAs can now be used while singing a song
== 03/30/2013 ==
demonstar55: Fixed most of the pet talking, all use StringIDs now. Pet now informs you when it taunts.
mackal: Fixed most of the pet talking, all use StringIDs now. Pet now informs you when it taunts.
== 03/23/2013 ==
demonstar55: Fix issues with escape not always working and fixed SE_FadingMemories to have the message since the message isn't part of the spell data.
mackal: Fix issues with escape not always working and fixed SE_FadingMemories to have the message since the message isn't part of the spell data.
Escape now uses just the spell and not the AA Actoin
Fading Memories now only uses the AA Action to eat mana
@@ -2247,7 +2341,7 @@ Bad_Captain: Added checks before dismissing merc to prevent possible bugged merc
Bad_Captain: Merged in Secret's merc memory leak fixes.
== 03/20/2013 ==
demonstar55: Fixed stacking issues with SE_Limit* (ex. Unholy Aura Discipline and Aura of Reverence)
mackal: Fixed stacking issues with SE_Limit* (ex. Unholy Aura Discipline and Aura of Reverence)
== 03/18/2013 ==
Bad_Captain: Fixed zone crash due to merc focus effects & tribute.
@@ -2310,7 +2404,7 @@ KLS: Changed how shared memory works:
af4t: Add Touch of the Wicked AA redux to SK Improved Harm Touch and Leech Touch.
== 02/22/2013 ==
demonstar55: Mobs will now be removed from XTargets when they get back to their way point, should be last instance of XTarget mobs not clearing when they are not aggroed anymore
mackal: Mobs will now be removed from XTargets when they get back to their way point, should be last instance of XTarget mobs not clearing when they are not aggroed anymore
== 02/19/2013 ==
Derision: World should no longer crash if the start_zone query fails at character creation.
@@ -2319,7 +2413,7 @@ Derision: World should no longer crash if the start_zone query fails at characte
Bad_Captain: Moved merc save to merc table, save merc buffs, added cure and rez spells to healer merc.
JJ: Chat garbled for drunk characters.
Derision: Charmed pets should no longer be targettable with F8. Charmed pets no longer get a surname of Soandso's Pet.
demonstar55: Added potionbelt tool tip
mackal: Added potionbelt tool tip
KLS: Added EVENT_DEATH to Player Quests
REQUIRED SQL: 2013_02_18_Merc_Rules_and_Tables.sql
@@ -2331,8 +2425,8 @@ Derision: Client version is now returned by the stream proxy as a number.
Derision: Fixed bug where BecomeTrader packets were only being sent to the Trader, not all other clients in the bazaar.
== 02/16/2013 ==
demonstar55: Fix AA reuse timer calc
demonstar55: Remove old filters and change all remaining old to new (Also fix Auction filtering out OOC as well due to incorrect define)
mackal: Fix AA reuse timer calc
mackal: Remove old filters and change all remaining old to new (Also fix Auction filtering out OOC as well due to incorrect define)
== 02/12/2013 ==
Kayen: AA fix
@@ -2343,7 +2437,7 @@ REQUIRED SQL: utils/sql/svn/2504_required_aa_updates.sql
Derision: RoF: Added ENCODE for OP_BeginCast (fixes no sound during spell casting). Corrected OP_DeleteSpell.
== 02/10/2013 ==
JJ: (demonstar55) Language skill up should use proper function.
JJ: (mackal) Language skill up should use proper function.
JJ: SetLanguageSkill now updates client immediately. Both functions do proper limit checks.
Added two missing languages. Skill level 0 in a spoken language now shows 'in an unknown tongue'.
JJ: Initial implementation of a GarbleMessage function and implemented for languages. Can be shared with drunk speaking.
@@ -2379,7 +2473,7 @@ Trevius: RoF: Turning on Trader mode in bazaar now works, but no further trader
Akkadius: Fixed an issue where global_npc.pl was not initializing (initially)
== 01/31/2013 ==
cavedude00: (demonstar55) Rune aggro fix
cavedude00: (mackal) Rune aggro fix
cavedude00: (Drajor) Tradeskill skillneeded fix.
== 01/30/2013 ==
@@ -2413,7 +2507,7 @@ Bad_Captain: Mercs - Initial spell casting AI committed.
KLS: Added crash logging for Windows builds.
Trevius: Mercenaries now despawn when a player camps out or disconnects in any way.
Trevius: Players with a Mercenary spawned can now be invited to and join another group with their mercenary.
Sorvani: (Demonstar55): Moved stunproc rule implmentation to catch all cases
Sorvani: (mackal): Moved stunproc rule implmentation to catch all cases
OPTIONAL SQL: utils/sql/svn/mercs.sql -- rerun for updated merc stats & merc spell lists
@@ -2864,9 +2958,9 @@ references:
http://www.eqemulator.org/forums/showthread.php?t=35629 - CSD Bugged Corpse Patch
http://www.eqemulator.org/forums/showthread.php?t=35699 - CSD Bandolier Patch
cavedude: (demonstar55) Damage shields by default will no longer count towards EXP gain. (Rule also added to change this behaviour.)
cavedude: (demonstar55) Extended targets should now clear when aggro is lost using skills.
cavedude: (demonstar55) AAs with shorter reuse timers should now reset if the cast failed (interrupted.)
cavedude: (mackal) Damage shields by default will no longer count towards EXP gain. (Rule also added to change this behaviour.)
cavedude: (mackal) Extended targets should now clear when aggro is lost using skills.
cavedude: (mackal) AAs with shorter reuse timers should now reset if the cast failed (interrupted.)
KLS: Fixed a cause of raids disbanding on zoning.
OPTIONAL SQL: INSERT INTO `rule_values` VALUES (1, 'Combat:EXPFromDmgShield', 'false', 'Determine if damage from a damage shield counts for EXP gain.');
@@ -3243,7 +3337,7 @@ Kayen: Implemented Perl Mob Quest Object GetModVulnerability(resist type) - Retu
Optional SQL: utils/sql/svn/2154_optional_rule_spell_procs_resists_falloff.sql
==06/22/2012==
Secrets: (demonstar55) Spells now display to all clients and can be filtered as such.
Secrets: (mackal) Spells now display to all clients and can be filtered as such.
Secrets: Damage Shields now go to the proper filter, and do not show the non-melee damage to everyone.
==06/03/2012==
@@ -5398,10 +5492,10 @@ WildcardX: *BOTS* Bots can now be invited and disbanded from your group by simpl
WildcardX: *BOTS* Tweak to the bots total play time calculation to make it more accurate.
KLS: Added #path meshtest simple to do a faster search on errant path nodes.
KLS: Modified the accurate hazard code to make automatic path maps with more accurate info that requires less manual editing afterward.
cavedude: (demonstar55) Pets will now be amiable to their owners, indifferent to all else.
cavedude: (demonstar55) Added $client->KeyRingCheck() and $client->KeyRingAdd() to allow Perl to manipulate the keyring.
cavedude: (demonstar55) Casting an invis spell on a player that already has a similar type invis spell will no longer drop the existing buff.
cavedude: (demonstar55) Corrected message string for heal spells.
cavedude: (mackal) Pets will now be amiable to their owners, indifferent to all else.
cavedude: (mackal) Added $client->KeyRingCheck() and $client->KeyRingAdd() to allow Perl to manipulate the keyring.
cavedude: (mackal) Casting an invis spell on a player that already has a similar type invis spell will no longer drop the existing buff.
cavedude: (mackal) Corrected message string for heal spells.
cavedude: Added rule to determine at what HP a fleeing NPC will halt due to being snared.
==08/07/2009==
@@ -6037,7 +6131,7 @@ KLS: Fixed the /bug structure and updated the table to be more useful.
Required SQL: .\utils\sql\svn\503_bugs.sql
==05/11/2009==
demonstar55: Added a function to allow Perl to check augments within items.
mackal: Added a function to allow Perl to check augments within items.
cavedude: Increased bind wound skill up speed some.
KLS: Fix for potentially dangerous typo in spawn conditions code.
KLS: Removed some non-functioning but still taking up database resources database code.
@@ -6338,7 +6432,7 @@ cavedude: Removed the USE_RACE_CLASS_XP_MODS define as it was outdated and horri
cavedude: Added group XP bonus. The larger the group, the higher the XP gain.
cavedude: Added XP bonus for Warrior, Rogue, and Halfling.
cavedude: Corrected ZEM for AAs.
cavedude: (Thanks to demonstar55) Pet Affinity will no longer effect charmed pets.
cavedude: (Thanks to mackal) Pet Affinity will no longer effect charmed pets.
cavedude: (realityincarnate) Bard songs that require instruments will now require them.
Please note: XP gain has pretty much been overhauled. You may need tweak the multiplier rules for your server.
@@ -6472,7 +6566,7 @@ AndMetal: Augments are now visible when linking items.
Trevius: SoF - Adjusted the new Item Structure to align more fields
Trevius: SoF - Added OP_Consume and OP_LootRequest opcodes
cavedude00: (AndMetal) AAs now use skill_id instead of index for prereqs.
cavedude00: (demonstar55) Implemented Improved Instrument Mastery, Improved Singing Mastery, and Echo of Taelosia AAs.
cavedude00: (mackal) Implemented Improved Instrument Mastery, Improved Singing Mastery, and Echo of Taelosia AAs.
cavedude00: Created Combat:ChanceToHitDivideBy rule and increased default value to 1250.
Required and Optional SQL: utils/sql/svn/326_aas.sql
KLS: SoF - Fix for item slots in bags.
+24
View File
@@ -2136,3 +2136,27 @@ bool Database::SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year
return results.Success();
}
int Database::GetIPExemption(std::string account_ip) {
std::string query = StringFormat("SELECT `exemption_amount` FROM `ip_exemptions` WHERE `exemption_ip` = '%s'", account_ip.c_str());
auto results = QueryDatabase(query);
if (results.Success() && results.RowCount() > 0) {
auto row = results.begin();
return atoi(row[0]);
}
return RuleI(World, MaxClientsPerIP);
}
int Database::GetInstanceID(uint32 char_id, uint32 zone_id) {
std::string query = StringFormat("SELECT instance_list.id FROM instance_list INNER JOIN instance_list_player ON instance_list.id = instance_list_player.id WHERE instance_list.zone = '%i' AND instance_list_player.charid = '%i'", zone_id, char_id);
auto results = QueryDatabase(query);
if (results.Success() && results.RowCount() > 0) {
auto row = results.begin();
return atoi(row[0]);;
}
return 0;
}
+4
View File
@@ -186,6 +186,10 @@ public:
void GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus);
void SetAgreementFlag(uint32 acctid);
int GetIPExemption(std::string account_ip);
int GetInstanceID(uint32 char_id, uint32 zone_id);
/* Groups */
+6 -19
View File
@@ -472,31 +472,18 @@ bool Database::CheckDatabaseConversions() {
CheckDatabaseConvertPPDeblob();
CheckDatabaseConvertCorpseDeblob();
/* Fetch Automatic Upgrade Script */
if (!std::ifstream("eqemu_update.pl")){
/* Fetch EQEmu Server script */
if (!std::ifstream("eqemu_server.pl")){
std::cout << "Pulling down automatic database upgrade script..." << std::endl;
#ifdef _WIN32
system("perl -MLWP::UserAgent -e \"require LWP::UserAgent; my $ua = LWP::UserAgent->new; $ua->timeout(10); $ua->env_proxy; my $response = $ua->get('https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_update.pl'); if ($response->is_success){ open(FILE, '> eqemu_update.pl'); print FILE $response->decoded_content; close(FILE); }\"");
system("perl -MLWP::UserAgent -e \"require LWP::UserAgent; my $ua = LWP::UserAgent->new; $ua->timeout(10); $ua->env_proxy; my $response = $ua->get('https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_server.pl'); if ($response->is_success){ open(FILE, '> eqemu_server.pl'); print FILE $response->decoded_content; close(FILE); }\"");
#else
system("wget --no-check-certificate -O eqemu_update.pl https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_update.pl");
system("wget --no-check-certificate -O eqemu_server.pl https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_server.pl");
#endif
}
/*
Automatic (Database) Upgrade Script
Script: eqemu_update.pl V 1 - the number that world passes to the script will
force the script to check for a newer version to update itself with
eqemu_update.pl ran_from_world - won't bring up a menu if your database versions match
eqemu_update.pl - ran standalone will bring up a menu prompt
*/
/* Check for a new version of this script, the arg passed
would have to be higher than the copy they have downloaded
locally and they will re fetch */
system("perl eqemu_update.pl V 14");
/* Run Automatic Database Upgrade Script */
system("perl eqemu_update.pl ran_from_world");
/* Run EQEmu Server script (Checks for database updates) */
system("perl eqemu_server.pl ran_from_world");
return true;
}
+14 -13
View File
@@ -1934,8 +1934,7 @@ struct Merchant_Sell_Struct {
/*004*/ uint32 playerid; // Player's entity id
/*008*/ uint32 itemslot;
uint32 unknown12;
/*016*/ uint8 quantity; // Already sold
/*017*/ uint8 Unknown016[3];
/*016*/ uint32 quantity;
/*020*/ uint32 price;
};
struct Merchant_Purchase_Struct {
@@ -2509,23 +2508,25 @@ struct BookRequest_Struct {
*/
struct Object_Struct {
/*00*/ uint32 linked_list_addr[2];// They are, get this, prev and next, ala linked list
/*08*/ uint16 size; //
/*08*/ float size; //
/*10*/ uint16 solidtype; //
/*12*/ uint32 drop_id; // Unique object id for zone
/*16*/ uint16 zone_id; // Redudant, but: Zone the object appears in
/*18*/ uint16 zone_instance; //
/*20*/ uint32 unknown020; //
/*24*/ uint32 unknown024; //
/*28*/ float heading; // heading
/*32*/ float z; // z coord
/*36*/ float x; // x coord
/*40*/ float y; // y coord
/*44*/ char object_name[32]; // Name of object, usually something like IT63_ACTORDEF
/*76*/ uint32 unknown076; //
/*80*/ uint32 object_type; // Type of object, not directly translated to OP_OpenObject
/*84*/ uint32 unknown084; //set to 0xFF
/*88*/ uint32 spawn_id; // Spawn Id of client interacting with object
/*92*/
/*28*/ float tilt_x;
/*32*/ float tilt_y;
/*36*/ float heading; // heading
/*40*/ float z; // z coord
/*44*/ float x; // x coord
/*76*/ float y; // y coord
/*80*/ char object_name[32]; // Name of object, usually something like IT63_ACTORDEF
/*84*/ uint32 unknown076; //
/*88*/ uint32 object_type; // Type of object, not directly translated to OP_OpenObject
/*92*/ uint32 unknown084; //set to 0xFF
uint32 spawn_id; // Spawn Id of client interacting with object
};
// 01 = generic drop, 02 = armor, 19 = weapon
//[13:40] and 0xff seems to be indicative of the tradeskill/openable items that end up returning the old style item type in the OP_OpenObject
+4 -16
View File
@@ -241,7 +241,7 @@ class EQStream : public EQStreamInterface {
virtual bool CheckState(EQStreamState state) { return GetState() == state; }
virtual std::string Describe() const { return("Direct EQStream"); }
void SetOpcodeManager(OpcodeManager **opm) { OpMgr = opm; }
virtual void SetOpcodeManager(OpcodeManager **opm) { OpMgr = opm; }
void CheckTimeout(uint32 now, uint32 timeout=30);
bool HasOutgoingData();
@@ -250,13 +250,13 @@ class EQStream : public EQStreamInterface {
void Write(int eq_fd);
// whether or not the stream has been assigned (we passed our stream match)
void SetActive(bool val) { streamactive = val; }
virtual void SetActive(bool val) { streamactive = val; }
//
inline bool IsInUse() { bool flag; MInUse.lock(); flag=(active_users>0); MInUse.unlock(); return flag; }
inline void PutInUse() { MInUse.lock(); active_users++; MInUse.unlock(); }
inline EQStreamState GetState() { EQStreamState s; MState.lock(); s=State; MState.unlock(); return s; }
virtual EQStreamState GetState() { EQStreamState s; MState.lock(); s=State; MState.unlock(); return s; }
static SeqOrder CompareSequence(uint16 expected_seq , uint16 seq);
@@ -306,19 +306,7 @@ class EQStream : public EQStreamInterface {
const uint64 GetPacketsReceived() { return received_packet_count; }
//used for dynamic stream identification
class Signature {
public:
//this object could get more complicated if needed...
uint16 ignore_eq_opcode; //0=dont ignore
uint16 first_eq_opcode;
uint32 first_length; //0=dont check length
};
typedef enum {
MatchNotReady,
MatchSuccessful,
MatchFailed
} MatchState;
MatchState CheckSignature(const Signature *sig);
virtual MatchState CheckSignature(const Signature *sig);
};
+3 -3
View File
@@ -26,7 +26,7 @@ EQStreamIdentifier::~EQStreamIdentifier() {
}
}
void EQStreamIdentifier::RegisterPatch(const EQStream::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs) {
void EQStreamIdentifier::RegisterPatch(const EQStreamInterface::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs) {
auto p = new Patch;
p->signature = sig;
p->name = name;
@@ -144,7 +144,7 @@ void EQStreamIdentifier::Process() {
} //end foreach stream
}
void EQStreamIdentifier::AddStream(std::shared_ptr<EQStream> &eqs) {
void EQStreamIdentifier::AddStream(std::shared_ptr<EQStreamInterface> &eqs) {
m_streams.push_back(Record(eqs));
eqs = nullptr;
}
@@ -157,7 +157,7 @@ EQStreamInterface *EQStreamIdentifier::PopIdentified() {
return(res);
}
EQStreamIdentifier::Record::Record(std::shared_ptr<EQStream> s)
EQStreamIdentifier::Record::Record(std::shared_ptr<EQStreamInterface> s)
: stream(std::move(s)),
expire(STREAM_IDENT_WAIT_MS)
{
+5 -5
View File
@@ -18,11 +18,11 @@ public:
~EQStreamIdentifier();
//registration interface.
void RegisterPatch(const EQStream::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs);
void RegisterPatch(const EQStreamInterface::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs);
//main processing interface
void Process();
void AddStream(std::shared_ptr<EQStream> &eqs);
void AddStream(std::shared_ptr<EQStreamInterface> &eqs);
EQStreamInterface *PopIdentified();
protected:
@@ -31,7 +31,7 @@ protected:
class Patch {
public:
std::string name;
EQStream::Signature signature;
EQStreamInterface::Signature signature;
OpcodeManager ** opcodes;
const StructStrategy *structs;
};
@@ -40,8 +40,8 @@ protected:
//pending streams..
class Record {
public:
Record(std::shared_ptr<EQStream> s);
std::shared_ptr<EQStream> stream; //we own this
Record(std::shared_ptr<EQStreamInterface> s);
std::shared_ptr<EQStreamInterface> stream; //we own this
Timer expire;
};
std::vector<Record> m_streams; //we own these objects, and the streams contained in them.
+18
View File
@@ -15,11 +15,25 @@ typedef enum {
} EQStreamState;
class EQApplicationPacket;
class OpcodeManager;
class EQStreamInterface {
public:
virtual ~EQStreamInterface() {}
class Signature {
public:
//this object could get more complicated if needed...
uint16 ignore_eq_opcode; //0=dont ignore
uint16 first_eq_opcode;
uint32 first_length; //0=dont check length
};
typedef enum {
MatchNotReady,
MatchSuccessful,
MatchFailed
} MatchState;
virtual void QueuePacket(const EQApplicationPacket *p, bool ack_req=true) = 0;
virtual void FastQueuePacket(EQApplicationPacket **p, bool ack_req=true) = 0;
virtual EQApplicationPacket *PopPacket() = 0;
@@ -30,6 +44,10 @@ public:
virtual uint16 GetRemotePort() const = 0;
virtual bool CheckState(EQStreamState state) = 0;
virtual std::string Describe() const = 0;
virtual void SetActive(bool val) { }
virtual MatchState CheckSignature(const Signature *sig) { return MatchFailed; }
virtual EQStreamState GetState() = 0;
virtual void SetOpcodeManager(OpcodeManager **opm) = 0;
virtual const uint32 GetBytesSent() const { return 0; }
virtual const uint32 GetBytesRecieved() const { return 0; }
+11 -1
View File
@@ -5,7 +5,7 @@
#include "struct_strategy.h"
EQStreamProxy::EQStreamProxy(std::shared_ptr<EQStream> &stream, const StructStrategy *structs, OpcodeManager **opcodes)
EQStreamProxy::EQStreamProxy(std::shared_ptr<EQStreamInterface> &stream, const StructStrategy *structs, OpcodeManager **opcodes)
: m_stream(stream),
m_structs(structs),
m_opcodes(opcodes)
@@ -26,6 +26,16 @@ const EQEmu::versions::ClientVersion EQStreamProxy::ClientVersion() const
return m_structs->ClientVersion();
}
EQStreamState EQStreamProxy::GetState()
{
return m_stream->GetState();
}
void EQStreamProxy::SetOpcodeManager(OpcodeManager **opm)
{
return m_stream->SetOpcodeManager(opm);
}
void EQStreamProxy::QueuePacket(const EQApplicationPacket *p, bool ack_req) {
if(p == nullptr)
return;
+5 -3
View File
@@ -14,7 +14,7 @@ class EQApplicationPacket;
class EQStreamProxy : public EQStreamInterface {
public:
//takes ownership of the stream.
EQStreamProxy(std::shared_ptr<EQStream> &stream, const StructStrategy *structs, OpcodeManager **opcodes);
EQStreamProxy(std::shared_ptr<EQStreamInterface> &stream, const StructStrategy *structs, OpcodeManager **opcodes);
virtual ~EQStreamProxy();
//EQStreamInterface:
@@ -29,6 +29,8 @@ public:
virtual bool CheckState(EQStreamState state);
virtual std::string Describe() const;
virtual const EQEmu::versions::ClientVersion ClientVersion() const;
virtual EQStreamState GetState();
virtual void SetOpcodeManager(OpcodeManager **opm);
virtual const uint32 GetBytesSent() const;
virtual const uint32 GetBytesRecieved() const;
@@ -36,8 +38,8 @@ public:
virtual const uint32 GetBytesRecvPerSecond() const;
protected:
std::shared_ptr<EQStream> const m_stream; //we own this stream object.
const StructStrategy *const m_structs; //we do not own this object.
std::shared_ptr<EQStreamInterface> const m_stream; //we own this stream object.
const StructStrategy *const m_structs; //we do not own this object.
//this is a pointer to a pointer to make it less likely that a packet will
//reference an invalid opcode manager when they are being reloaded.
OpcodeManager **const m_opcodes; //we do not own this object.
+3 -1
View File
@@ -83,6 +83,7 @@ namespace Logs {
Server_Client_Packet_With_Dump,
Client_Server_Packet_With_Dump,
Login_Server,
Client_Login,
MaxCategoryID /* Don't Remove this*/
};
@@ -131,7 +132,8 @@ namespace Logs {
"Packet :: Client -> Server Unhandled",
"Packet :: Server -> Client (Dump)",
"Packet :: Client -> Server (Dump)",
"Login Server"
"Login Server",
"Client Login"
};
}
+8 -7
View File
@@ -87,7 +87,7 @@ namespace RoF
//ok, now we have what we need to register.
EQStream::Signature signature;
EQStreamInterface::Signature signature;
std::string pname;
//register our world signature.
@@ -477,10 +477,11 @@ namespace RoF
for (uint16 i = 0; i < emu->count; ++i)
{
uint16 buffslot = emu->entries[i].buff_slot;
// Not sure if this is needs amending for RoF yet.
if (emu->entries[i].buff_slot >= 25)
{
buffslot += 17;
if (emu->type == 0) { // only correct for self packets
if (emu->entries[i].buff_slot >= 25)
buffslot += 17;
if (buffslot == 54)
buffslot = 62;
}
__packet->WriteUInt32(buffslot);
@@ -986,8 +987,8 @@ namespace RoF
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->drop_id); // Some unique id
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Same for all objects in the zone
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->heading);
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // X tilt
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Y tilt
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->tilt_x); // X tilt
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->tilt_y); // Y tilt
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->size != 0 && (float)emu->size < 5000.f ? (float)((float)emu->size / 100.0f) : 1.f ); // This appears to be the size field. Hackish logic because some PEQ DB items were corrupt.
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->y);
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->x);
+11 -12
View File
@@ -87,7 +87,7 @@ namespace RoF2
//ok, now we have what we need to register.
EQStream::Signature signature;
EQStreamInterface::Signature signature;
std::string pname;
//register our world signature.
@@ -549,16 +549,15 @@ namespace RoF2
for (uint16 i = 0; i < emu->count; ++i)
{
uint16 buffslot = emu->entries[i].buff_slot;
// Not sure if this is needs amending for RoF2 yet.
if (emu->entries[i].buff_slot >= 25)
{
buffslot += 17;
if (emu->type == 0) { // only correct for self packets
if (emu->entries[i].buff_slot >= 25)
buffslot += 17;
// TODO: We should really just deal with these "server side"
// so we can have clients not limited to other clients.
// This fixes discs, songs were changed to 20
if (buffslot == 54)
buffslot = 62;
}
// TODO: We should really just deal with these "server side"
// so we can have clients not limited to other clients.
// This fixes discs, songs were changed to 20
if (buffslot == 54)
buffslot = 62;
__packet->WriteUInt32(buffslot);
__packet->WriteUInt32(emu->entries[i].spell_id);
@@ -1063,8 +1062,8 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->drop_id); // Some unique id
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Same for all objects in the zone
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->heading);
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // X tilt
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Y tilt
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->tilt_x); // X tilt
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->tilt_y); // Y tilt
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->size != 0 && (float)emu->size < 5000.f ? (float)((float)emu->size / 100.0f) : 1.f ); // This appears to be the size field. Hackish logic because some PEQ DB items were corrupt.
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->y);
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->x);
+4 -2
View File
@@ -83,7 +83,7 @@ namespace SoD
//ok, now we have what we need to register.
EQStream::Signature signature;
EQStreamInterface::Signature signature;
std::string pname;
//register our world signature.
@@ -3246,8 +3246,10 @@ namespace SoD
DECODE_LENGTH_EXACT(structs::LoadSpellSet_Struct);
SETUP_DIRECT_DECODE(LoadSpellSet_Struct, structs::LoadSpellSet_Struct);
for (uint32 i = 0; i < MAX_PP_MEMSPELL; ++i)
for (int i = 0; i < structs::MAX_PP_MEMSPELL; ++i)
emu->spell[i] = eq->spell[i];
for (int i = structs::MAX_PP_MEMSPELL; i < MAX_PP_MEMSPELL; ++i)
emu->spell[i] = 0xFFFFFFFF;
FINISH_DIRECT_DECODE();
}
+1 -2
View File
@@ -1880,8 +1880,7 @@ struct Merchant_Sell_Struct {
/*004*/ uint32 playerid; // Player's entity id
/*008*/ uint32 itemslot;
/*012*/ uint32 unknown12;
/*016*/ uint8 quantity; // Already sold
/*017*/ uint8 Unknown017[3];
/*016*/ uint32 quantity;
/*020*/ uint32 Unknown020;
/*024*/ uint32 price;
/*028*/ uint32 pricehighorderbits; // It appears the price is 64 bits in SoD+
+16 -1
View File
@@ -83,7 +83,7 @@ namespace SoF
//ok, now we have what we need to register.
EQStream::Signature signature;
EQStreamInterface::Signature signature;
std::string pname;
//register our world signature.
@@ -2623,6 +2623,21 @@ namespace SoF
FINISH_DIRECT_DECODE();
}
DECODE(OP_LoadSpellSet)
{
DECODE_LENGTH_EXACT(structs::LoadSpellSet_Struct);
SETUP_DIRECT_DECODE(LoadSpellSet_Struct, structs::LoadSpellSet_Struct);
for (int i = 0; i < structs::MAX_PP_MEMSPELL; ++i)
IN(spell[i]);
for (int i = structs::MAX_PP_MEMSPELL; i < MAX_PP_MEMSPELL; ++i)
emu->spell[i] = 0xFFFFFFFF;
IN(unknown);
FINISH_DIRECT_DECODE();
}
DECODE(OP_LootItem)
{
DECODE_LENGTH_EXACT(structs::LootingItem_Struct);
+1
View File
@@ -111,6 +111,7 @@ D(OP_GroupFollow2)
D(OP_InspectRequest)
D(OP_ItemLinkClick)
D(OP_ItemVerifyRequest)
D(OP_LoadSpellSet)
D(OP_LootItem)
D(OP_MoveItem)
D(OP_PetCommands)
+6 -2
View File
@@ -1859,8 +1859,7 @@ struct Merchant_Sell_Struct {
/*004*/ uint32 playerid; // Player's entity id
/*008*/ uint32 itemslot;
uint32 unknown12;
/*016*/ uint8 quantity; // Already sold
/*017*/ uint8 Unknown016[3];
/*016*/ uint32 quantity;
/*020*/ uint32 price;
};
struct Merchant_Purchase_Struct {
@@ -3729,6 +3728,11 @@ struct AnnoyingZoneUnknown_Struct {
uint32 value; //always 4
};
struct LoadSpellSet_Struct {
uint32 spell[MAX_PP_MEMSPELL];
uint32 unknown;
};
struct BlockedBuffs_Struct {
/*000*/ uint8 unknown000[80];
/*080*/ uint8 unknown081;
+1 -1
View File
@@ -17,5 +17,5 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define E(x) static void Encode_##x(EQApplicationPacket **p, std::shared_ptr<EQStream> dest, bool ack_req);
#define E(x) static void Encode_##x(EQApplicationPacket **p, std::shared_ptr<EQStreamInterface> dest, bool ack_req);
#define D(x) static void Decode_##x(EQApplicationPacket *p);
+1 -1
View File
@@ -17,7 +17,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define ENCODE(x) void Strategy::Encode_##x(EQApplicationPacket **p, std::shared_ptr<EQStream> dest, bool ack_req)
#define ENCODE(x) void Strategy::Encode_##x(EQApplicationPacket **p, std::shared_ptr<EQStreamInterface> dest, bool ack_req)
#define DECODE(x) void Strategy::Decode_##x(EQApplicationPacket *__packet)
#define StructDist(in, f1, f2) (uint32(&in->f2)-uint32(&in->f1))
+56 -1
View File
@@ -82,7 +82,7 @@ namespace Titanium
//ok, now we have what we need to register.
EQStream::Signature signature;
EQStreamInterface::Signature signature;
std::string pname;
//register our world signature.
@@ -595,6 +595,46 @@ namespace Titanium
dest->FastQueuePacket(&in, ack_req);
}
ENCODE(OP_GroundSpawn)
{
// We are not encoding the spawn_id field here, but it doesn't appear to matter.
//
EQApplicationPacket *in = *p;
*p = nullptr;
//store away the emu struct
unsigned char *__emu_buffer = in->pBuffer;
Object_Struct *emu = (Object_Struct *)__emu_buffer;
in->size = strlen(emu->object_name) + sizeof(structs::Object_Struct) - 1;
in->pBuffer = new unsigned char[in->size];
structs::Object_Struct *eq = (structs::Object_Struct *) in->pBuffer;
eq->drop_id = emu->drop_id;
eq->heading = emu->heading;
eq->linked_list_addr[0] = 0;
eq->linked_list_addr[1] = 0;
strcpy(eq->object_name, emu->object_name);
eq->object_type = emu->object_type;
eq->spawn_id = 0;
eq->unknown008[0] = 0;
eq->unknown008[1] = 0;
eq->unknown020 = 0;
eq->unknown024 = 0;
eq->unknown076 = 0;
eq->unknown084 = 0xffffffff;
eq->z = emu->z;
eq->x = emu->x;
eq->y = emu->y;
eq->zone_id = emu->zone_id;
eq->zone_instance = emu->zone_instance;
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
}
ENCODE(OP_GuildMemberList)
{
//consume the packet
@@ -1938,6 +1978,21 @@ namespace Titanium
FINISH_DIRECT_DECODE();
}
DECODE(OP_LoadSpellSet)
{
DECODE_LENGTH_EXACT(structs::LoadSpellSet_Struct);
SETUP_DIRECT_DECODE(LoadSpellSet_Struct, structs::LoadSpellSet_Struct);
for (int i = 0; i < structs::MAX_PP_MEMSPELL; ++i)
IN(spell[i]);
for (int i = structs::MAX_PP_MEMSPELL; i < MAX_PP_MEMSPELL; ++i)
emu->spell[i] = 0xFFFFFFFF;
IN(unknown);
FINISH_DIRECT_DECODE();
}
DECODE(OP_LootItem)
{
DECODE_LENGTH_EXACT(structs::LootingItem_Struct);
+2
View File
@@ -40,6 +40,7 @@ E(OP_DzLeaderStatus)
E(OP_DzMemberList)
E(OP_Emote)
E(OP_FormattedMessage)
E(OP_GroundSpawn)
E(OP_GuildMemberLevelUpdate)
E(OP_GuildMemberList)
E(OP_Illusion)
@@ -88,6 +89,7 @@ D(OP_InspectAnswer)
D(OP_InspectRequest)
D(OP_ItemLinkClick)
D(OP_LFGuild)
D(OP_LoadSpellSet)
D(OP_LootItem)
D(OP_MoveItem)
D(OP_PetCommands)
+6 -2
View File
@@ -1657,8 +1657,7 @@ struct Merchant_Sell_Struct {
/*004*/ uint32 playerid; // Player's entity id
/*008*/ uint32 itemslot;
uint32 unknown12;
/*016*/ uint8 quantity; // Already sold
/*017*/ uint8 Unknown016[3];
/*016*/ uint32 quantity;
/*020*/ uint32 price;
};
struct Merchant_Purchase_Struct {
@@ -3229,6 +3228,11 @@ struct AnnoyingZoneUnknown_Struct {
uint32 value; //always 4
};
struct LoadSpellSet_Struct {
uint32 spell[MAX_PP_MEMSPELL];
uint32 unknown;
};
struct ApplyPoison_Struct {
uint32 inventorySlot;
uint32 success;
+8 -10
View File
@@ -83,7 +83,7 @@ namespace UF
//ok, now we have what we need to register.
EQStream::Signature signature;
EQStreamInterface::Signature signature;
std::string pname;
//register our world signature.
@@ -410,13 +410,11 @@ namespace UF
for (uint16 i = 0; i < emu->count; ++i)
{
uint16 buffslot = emu->entries[i].buff_slot;
if (emu->entries[i].buff_slot >= 25 && emu->entries[i].buff_slot < 37)
{
buffslot += 5;
}
else if (emu->entries[i].buff_slot >= 37)
{
buffslot += 14;
if (emu->type == 0) { // only correct for self packets
if (emu->entries[i].buff_slot >= 25 && emu->entries[i].buff_slot < 37)
buffslot += 5;
else if (emu->entries[i].buff_slot >= 37)
buffslot += 14;
}
__packet->WriteUInt32(buffslot);
@@ -877,8 +875,8 @@ namespace UF
// This next field is actually a float. There is a groundspawn in freeportwest (sack of money sitting on some barrels) which requires this
// field to be set to (float)255.0 to appear at all, and also the size field below to be 5, to be the correct size. I think SoD has the same
// issue.
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); //X tilt
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); //Y tilt
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->tilt_x); //X tilt
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->tilt_y); //Y tilt
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->size != 0 && (float)emu->size < 5000.f ? (float)((float)emu->size / 100.0f) : 1.f ); // This appears to be the size field. Hackish logic because some PEQ DB items were corrupt.
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->y);
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->x);
+4 -6
View File
@@ -847,7 +847,7 @@ struct BindStruct {
*/
static const uint32 MAX_PP_LANGUAGE = 25; //
static const uint32 MAX_PP_SPELLBOOK = 720; // Confirmed 60 pages on Underfoot now
static const uint32 MAX_PP_MEMSPELL = 10; //was 9 now 10 on Underfoot
static const uint32 MAX_PP_MEMSPELL = 12; //was 9 now 10 on Underfoot
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
static const uint32 MAX_PP_AA_ARRAY = 300; //was 299
static const uint32 MAX_GROUP_MEMBERS = 6;
@@ -917,7 +917,7 @@ struct PlayerProfile_Struct
/*00160*/ uint32 deity; // deity
/*00164*/ uint32 intoxication; // Alcohol level (in ticks till sober?)
/*00168*/ uint32 spellSlotRefresh[MAX_PP_MEMSPELL]; // Refresh time (millis) - 4 Octets Each
/*00208*/ uint8 unknown00208[14]; // Seen 00 00 00 00 00 00 00 00 00 00 00 00 02 01
/*00208*/ uint8 unknown00208[6]; // Seen 00 00 00 00 00 00 00 00 00 00 00 00 02 01
/*00222*/ uint32 abilitySlotRefresh;
/*00226*/ uint8 haircolor; // Player hair color
/*00227*/ uint8 beardcolor; // Player beard color
@@ -945,7 +945,7 @@ struct PlayerProfile_Struct
/*04217*/ uint8 unknown04217[147]; // was [175]
/*04364*/ uint32 spell_book[MAX_PP_SPELLBOOK]; // List of the Spells in spellbook 720 = 90 pages [2880] was [1920]
/*07244*/ uint32 mem_spells[MAX_PP_MEMSPELL]; // List of spells memorized
/*07284*/ uint8 unknown07284[28]; //#### uint8 unknown04396[32]; in Titanium ####[28]
/*07284*/ uint8 unknown07284[20]; //#### uint8 unknown04396[32]; in Titanium ####[28]
/*07312*/ uint32 platinum; // Platinum Pieces on player
/*07316*/ uint32 gold; // Gold Pieces on player
/*07320*/ uint32 silver; // Silver Pieces on player
@@ -1921,8 +1921,7 @@ struct Merchant_Sell_Struct {
/*004*/ uint32 playerid; // Player's entity id
/*008*/ uint32 itemslot;
/*012*/ uint32 unknown12;
/*016*/ uint8 quantity; // Already sold
/*017*/ uint8 Unknown017[3];
/*016*/ uint32 quantity;
/*020*/ uint32 Unknown020;
/*024*/ uint32 price;
/*028*/ uint32 pricehighorderbits; // It appears the price is 64 bits in Underfoot+
@@ -3929,7 +3928,6 @@ struct AnnoyingZoneUnknown_Struct {
struct LoadSpellSet_Struct {
uint8 spell[MAX_PP_MEMSPELL]; // 0 if no action
uint16 unknown2; // is this two more spell gems?
uint32 unknown; // there seems to be an extra field in this packet...
};
+6
View File
@@ -144,6 +144,9 @@ RULE_BOOL(Character, RestrictSpellScribing, false) // Restricts spell scribing t
RULE_BOOL(Character, UseStackablePickPocketing, true) // Allows stackable pickpocketed items to stack instead of only being allowed in empty inventory slots
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)
@@ -205,6 +208,7 @@ RULE_INT(World, ExemptMaxClientsStatus, -1) // Exempt accounts from the MaxClien
RULE_INT(World, AddMaxClientsPerIP, -1) // Maximum number of clients allowed to connect per IP address if account status is < ExemptMaxClientsStatus. Default value: -1 (feature disabled)
RULE_INT(World, AddMaxClientsStatus, -1) // Accounts with status >= this rule will be allowed to use the amount of accounts defined in the AddMaxClientsPerIP. Default value: -1 (feature disabled)
RULE_BOOL(World, MaxClientsSetByStatus, false) // If True, IP Limiting will be set to the status on the account as long as the status is > MaxClientsPerIP
RULE_BOOL(World, EnableIPExemptions, false) // If True, ip_exemptions table is used, if there is no entry for the IP it will default to RuleI(World, MaxClientsPerIP)
RULE_BOOL(World, ClearTempMerchantlist, true) // Clears temp merchant items when world boots.
RULE_BOOL(World, DeleteStaleCorpeBackups, true) // Deletes stale corpse backups older than 2 weeks.
RULE_INT(World, AccountSessionLimit, -1) //Max number of characters allowed on at once from a single account (-1 is disabled)
@@ -252,6 +256,7 @@ RULE_INT(Zone, WeatherTimer, 600) // Weather timer when no duration is available
RULE_BOOL(Zone, EnableLoggedOffReplenishments, true)
RULE_INT(Zone, MinOfflineTimeToReplenishments, 21600) // 21600 seconds is 6 Hours
RULE_BOOL(Zone, UseZoneController, true) // Enables the ability to use persistent quest based zone controllers (zone_controller.pl/lua)
RULE_BOOL(Zone, EnableZoneControllerGlobals, false) // Enables the ability to use quest globals with the zone controller NPC
RULE_CATEGORY_END()
RULE_CATEGORY(Map)
@@ -382,6 +387,7 @@ RULE_BOOL(Spells, AlwaysSendTargetsBuffs, false) // ignore LAA level if true
RULE_BOOL(Spells, FlatItemExtraSpellAmt, false) // allow SpellDmg stat to affect all spells, regardless of cast time/cooldown/etc
RULE_BOOL(Spells, IgnoreSpellDmgLvlRestriction, false) // ignore the 5 level spread on applying SpellDmg
RULE_BOOL(Spells, AllowItemTGB, false) // TGB doesn't work with items on live, custom servers want it though
RULE_BOOL(Spells, NPCInnateProcOverride, true) // NPC innate procs override the target type to single target.
RULE_CATEGORY_END()
RULE_CATEGORY(Combat)
+10
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];
+3 -3
View File
@@ -18,7 +18,7 @@ StructStrategy::StructStrategy() {
}
}
void StructStrategy::Encode(EQApplicationPacket **p, std::shared_ptr<EQStream> dest, bool ack_req) const {
void StructStrategy::Encode(EQApplicationPacket **p, std::shared_ptr<EQStreamInterface> dest, bool ack_req) const {
if((*p)->GetOpcodeBypass() != 0) {
PassEncoder(p, dest, ack_req);
return;
@@ -36,7 +36,7 @@ void StructStrategy::Decode(EQApplicationPacket *p) const {
}
void StructStrategy::ErrorEncoder(EQApplicationPacket **in_p, std::shared_ptr<EQStream> dest, bool ack_req) {
void StructStrategy::ErrorEncoder(EQApplicationPacket **in_p, std::shared_ptr<EQStreamInterface> dest, bool ack_req) {
EQApplicationPacket *p = *in_p;
*in_p = nullptr;
@@ -50,7 +50,7 @@ void StructStrategy::ErrorDecoder(EQApplicationPacket *p) {
p->SetOpcode(OP_Unknown);
}
void StructStrategy::PassEncoder(EQApplicationPacket **p, std::shared_ptr<EQStream> dest, bool ack_req) {
void StructStrategy::PassEncoder(EQApplicationPacket **p, std::shared_ptr<EQStreamInterface> dest, bool ack_req) {
dest->FastQueuePacket(p, ack_req);
}
+5 -5
View File
@@ -2,7 +2,7 @@
#define STRUCTSTRATEGY_H_
class EQApplicationPacket;
class EQStream;
class EQStreamInterface;
#include "emu_opcodes.h"
#include "emu_versions.h"
@@ -12,7 +12,7 @@ class EQStream;
class StructStrategy {
public:
//the encoder takes ownership of the supplied packet, and may enqueue multiple resulting packets into the stream
typedef void(*Encoder)(EQApplicationPacket **p, std::shared_ptr<EQStream> dest, bool ack_req);
typedef void(*Encoder)(EQApplicationPacket **p, std::shared_ptr<EQStreamInterface> dest, bool ack_req);
//the decoder may only edit the supplied packet, producing a single packet for eqemu to consume.
typedef void (*Decoder)(EQApplicationPacket *p);
@@ -20,7 +20,7 @@ public:
virtual ~StructStrategy() {}
//this method takes an eqemu struct, and enqueues the produced structs into the stream.
void Encode(EQApplicationPacket **p, std::shared_ptr<EQStream> dest, bool ack_req) const;
void Encode(EQApplicationPacket **p, std::shared_ptr<EQStreamInterface> dest, bool ack_req) const;
//this method takes an EQ wire struct, and converts it into an eqemu struct
void Decode(EQApplicationPacket *p) const;
@@ -30,10 +30,10 @@ public:
protected:
//some common coders:
//Print an error saying unknown struct/opcode and drop it
static void ErrorEncoder(EQApplicationPacket **p, std::shared_ptr<EQStream> dest, bool ack_req);
static void ErrorEncoder(EQApplicationPacket **p, std::shared_ptr<EQStreamInterface> dest, bool ack_req);
static void ErrorDecoder(EQApplicationPacket *p);
//pass the packet through without modification (emu == EQ) (default)
static void PassEncoder(EQApplicationPacket **p, std::shared_ptr<EQStream> dest, bool ack_req);
static void PassEncoder(EQApplicationPacket **p, std::shared_ptr<EQStreamInterface> dest, bool ack_req);
static void PassDecoder(EQApplicationPacket *p);
Encoder encoders[_maxEmuOpcode];
+1 -1
View File
@@ -30,7 +30,7 @@
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9097
#define CURRENT_BINARY_DATABASE_VERSION 9100
#ifdef BOTS
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9008
#else
+1 -1
View File
@@ -24,7 +24,7 @@
extern EQEmuLogSys Log;
extern LoginServer server;
Client::Client(std::shared_ptr<EQStream> c, LSClientVersion v)
Client::Client(std::shared_ptr<EQStreamInterface> c, LSClientVersion v)
{
connection = c;
version = v;
+3 -3
View File
@@ -59,7 +59,7 @@ public:
/**
* Constructor, sets our connection to c and version to v
*/
Client(std::shared_ptr<EQStream> c, LSClientVersion v);
Client(std::shared_ptr<EQStreamInterface> c, LSClientVersion v);
/**
* Destructor.
@@ -129,11 +129,11 @@ public:
/**
* Gets the connection for this client.
*/
std::shared_ptr<EQStream> GetConnection() { return connection; }
std::shared_ptr<EQStreamInterface> GetConnection() { return connection; }
EQEmu::Random random;
private:
std::shared_ptr<EQStream> connection;
std::shared_ptr<EQStreamInterface> connection;
LSClientVersion version;
LSClientStatus status;
+3 -3
View File
@@ -95,7 +95,7 @@ ClientManager::~ClientManager()
void ClientManager::Process()
{
ProcessDisconnect();
std::shared_ptr<EQStream> cur = titanium_stream->Pop();
std::shared_ptr<EQStreamInterface> cur = titanium_stream->Pop();
while(cur)
{
struct in_addr in;
@@ -142,8 +142,8 @@ void ClientManager::ProcessDisconnect()
list<Client*>::iterator iter = clients.begin();
while(iter != clients.end())
{
std::shared_ptr<EQStream> c = (*iter)->GetConnection();
if(c->CheckClosed())
std::shared_ptr<EQStreamInterface> c = (*iter)->GetConnection();
if(c->CheckState(CLOSED))
{
Log.Out(Logs::General, Logs::Login_Server, "Client disconnected from the server, removing client.");
delete (*iter);
+3 -3
View File
@@ -485,7 +485,7 @@ Clientlist::Clientlist(int ChatPort) {
}
}
Client::Client(std::shared_ptr<EQStream> eqs) {
Client::Client(std::shared_ptr<EQStreamInterface> eqs) {
ClientStream = eqs;
@@ -574,7 +574,7 @@ void Clientlist::CheckForStaleConnections(Client *c) {
void Clientlist::Process()
{
std::shared_ptr<EQStream> eqs;
std::shared_ptr<EQStreamInterface> eqs;
while ((eqs = chatsf->Pop())) {
struct in_addr in;
@@ -592,7 +592,7 @@ void Clientlist::Process()
auto it = ClientChatConnections.begin();
while (it != ClientChatConnections.end()) {
(*it)->AccountUpdate();
if ((*it)->ClientStream->CheckClosed()) {
if ((*it)->ClientStream->CheckState(CLOSED)) {
struct in_addr in;
in.s_addr = (*it)->ClientStream->GetRemoteIP();
+2 -2
View File
@@ -84,10 +84,10 @@ struct CharacterEntry {
class Client {
public:
Client(std::shared_ptr<EQStream> eqs);
Client(std::shared_ptr<EQStreamInterface> eqs);
~Client();
std::shared_ptr<EQStream> ClientStream;
std::shared_ptr<EQStreamInterface> ClientStream;
void AddCharacter(int CharID, const char *CharacterName, int Level);
void ClearCharacters() { Characters.clear(); }
void SendMailBoxes();
+70 -48
View File
@@ -1,7 +1,7 @@
#!/usr/bin/perl
############################################################
#::: Script: DB_Dumper.pl
#::: Script: db_dumper.pl
#::: Purpose: Utility to easily manage database backups and compress.
#::: Export Individual DB Tables...
#::: Export specific databases...
@@ -24,16 +24,17 @@ if($Config{osname}=~/linux/i){ $OS = "Linux"; }
if($Config{osname}=~/Win|MS/i){ $OS = "Windows"; }
if(!$ARGV[0]){
print "\nERROR! Need arguments\n\n";
print "\nERROR! Need arguments\n";
print "#::: Help :::#\n";
print "######################################################\n\n";
print "######################################################\n";
print "Arguments\n";
print " loc=\"C:\\File Location\" - File path location to backup...\n";
print " database=\"dbname\" - Manually specify databasename, default is database in eqemu_config.xml\n";
print " tables=\"table1,table2,table3\" - Manually specify tables, default is to dump all tables from database\n";
print " compress - Compress Database with 7-ZIP, will fallback to WinRAR depending on what is installed (Must be installed to default program dir)...\n";
print " nolock - Does not lock tables, meant for backuping while the server is running..\n";
print ' Example: perl DB_Dumper.pl Loc="E:\Backups"' . "\n\n";
print " backup_name=\"name\" - Sets database backup prefix name\n";
print ' Example: perl DB_Dumper.pl Loc="E:\Backups"' . "\n";
print "######################################################\n";
exit;
}
@@ -56,7 +57,7 @@ while(<F>) {
}
$Debug = 0;
print "Arguments\n" if $Debug;
print "[db_dumper.pl] Arguments\n" if $Debug;
$n = 0;
while($ARGV[$n]){
print $n . ': ' . $ARGV[$n] . "\n" if $Debug;
@@ -64,17 +65,22 @@ while($ARGV[$n]){
$no_lock = 1;
}
if($ARGV[$n]=~/compress/i){
print "Compression SET\n";
print "[db_dumper.pl] Compression SET\n";
$Compress = 1;
}
if($ARGV[$n]=~/database=/i){
@DB_NAME = split('=', $ARGV[$n]);
print "Database is " . $DB_NAME[1] . "\n";
print "[db_dumper.pl] Database is " . $DB_NAME[1] . "\n";
$db = $DB_NAME[1];
}
if($ARGV[$n]=~/backup_name=/i){
@data = split('=', $ARGV[$n]);
print "[db_dumper.pl] Backup Name is " . $data[1] . "\n";
$backup_name = $data[1];
}
if($ARGV[$n]=~/loc=/i){
@B_LOC = split('=', $ARGV[$n]);
print "Backup Directory: " . $B_LOC[1] . "\n";
@backup_location = split('=', $ARGV[$n]);
print "[db_dumper.pl] Backup Directory: " . $backup_location[1] . "\n";
}
if($ARGV[$n]=~/tables=/i){
@Tables = split('=', $ARGV[$n]); @TList = split(',', $Tables[1]);
@@ -83,23 +89,23 @@ while($ARGV[$n]){
$t_tables_l .= $tables . "_";
$t_tables_p .= $tables . "\n";
}
print "Backing up tables: \n\n############################\n" . $t_tables_p . "############################\n\n";
print "[db_dumper.pl] Backing up tables: \n############################\n" . $t_tables_p . "############################\n";
}
$n++;
}
#::: Check for Backup Directory existence, if doesn't exist then create...
if (-d $B_LOC[1]) {
print "Directory currently exists... Adding files to it...\n\n";
if (-d $backup_location[1]) {
print "[db_dumper.pl] Directory currently exists... Adding files to it...\n";
}
elsif($B_LOC[1] ne ""){
print "Directory does NOT exist! Creating...\n\n";
mkdir($B_LOC[1]) or die 'Failed to create folder, maybe created the folder manually at "' . $B_LOC[1]. '" ?';
elsif($backup_location[1] ne ""){
print "[db_dumper.pl] Directory does NOT exist! Creating...\n";
mkdir($backup_location[1]) or die 'Failed to create folder, maybe created the folder manually at "' . $backup_location[1]. '" ?';
}
else{
print "No save location specified... Saving to folder script is running in...\n";
print "[db_dumper.pl] No save location specified... Saving to folder script is running in...\n";
}
if($B_LOC[1] ne ""){
if($backup_location[1] ne ""){
if($OS eq "Windows"){ $file_app = "\\"; }
if($OS eq "Linux"){ $file_app = "/"; }
}
@@ -108,96 +114,112 @@ else {
}
if($t_tables ne ""){
$tables_f_l = substr($t_tables_l, 0, 20) . '...';
$target_file = '' . $tables_f_l . '_' . $date . '';
print "Performing table based backup...\n";
$tables_f_l = substr($t_tables_l, 0, 20) . '-';
if($backup_name){
$target_file = $backup_name . '_' . $date . '';
}
else {
$target_file = '' . $tables_f_l . '_' . $date . '';
}
print "[db_dumper.pl] Performing table based backup...\n";
#::: Backup Database...
print "Backing up Database " . $db . "... \n\n";
print "[db_dumper.pl] Backing up Database " . $db . "... \n";
if($no_lock == 1){
$added_parameters .= " --skip-lock-tables ";
}
$cmd = 'mysqldump -u' . $user . ' --host ' . $host . ' ' . $added_parameters . ' --max_allowed_packet=512M --password="' . $pass . '" ' . $db . ' ' . $t_tables . ' > "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql"';
$cmd = 'mysqldump -u' . $user . ' --host ' . $host . ' ' . $added_parameters . ' --max_allowed_packet=512M --password="' . $pass . '" ' . $db . ' ' . $t_tables . ' > "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql"';
printcmd($cmd);
system($cmd);
}
else{ #::: Entire DB Backup
$target_file = '' . $db . '_' . $date . '';
if($backup_name){
$target_file = $backup_name . '_' . $db . '_' . $date . '';
}
else {
$target_file = '' . $db . '_' . $date . '';
}
#::: Backup Database...
print "Backing up Database " . $db . "... \n\n";
print "[db_dumper.pl] Backing up Database " . $db . "... \n";
if($no_lock == 1){
$added_parameters .= " --skip-lock-tables ";
}
$cmd = 'mysqldump -u' . $user . ' --host ' . $host . ' ' . $added_parameters . ' --max_allowed_packet=512M --password="' . $pass . '" ' . $db . ' > "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql"';
$cmd = 'mysqldump -u' . $user . ' --host ' . $host . ' ' . $added_parameters . ' --max_allowed_packet=512M --password="' . $pass . '" ' . $db . ' > "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql"';
printcmd($cmd);
system($cmd);
}
#::: Get File Size
$fileloc = '' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql';
$fileloc = '' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql';
$filesize = -s $fileloc;
if($filesize < 1000){ print "\n" . 'Error occurred... exiting...' . "\n\n"; exit; }
print "Backup DONE... DB Backup File Size '" . $filesize . "' (" . get_filesize_str($fileloc) . ")\n\n";
if($filesize < 1000){ print "[db_dumper.pl] " . 'Error occurred... exiting...' . "\n"; exit; }
print "[db_dumper.pl] Backup DONE... DB Backup File Size '" . $filesize . "' (" . get_filesize_str($fileloc) . ")\n";
#::: WinRar Get, check compression flag
if($Compress == 1){
if($OS eq "Windows"){
if(-d $localdrive . "\\Program Files\\7-Zip"){
print " ::: You have 7-Zip installed as 64 Bit...\n\n";
print "[db_dumper.pl] ::: You have 7-Zip installed as 64 Bit...\n";
$S_ZIP = $localdrive . "\\Program Files\\7-Zip";
}
elsif(-d $localdrive . "\\Program Files (x86)\\7-Zip"){
print " ::: You have 7-Zip installed as 32 Bit...\n\n";
print "[db_dumper.pl] ::: You have 7-Zip installed as 32 Bit...\n";
$S_ZIP = $localdrive . "\\Program Files (x86)\\7-Zip";
}
elsif(-d $localdrive . "\\Program Files (x86)\\WinRAR"){
print " ::: You have WinRAR installed as 32 Bit...\n\n";
print "[db_dumper.pl] ::: You have WinRAR installed as 32 Bit...\n";
$WinRar = $localdrive . "\\Program Files (x86)\\WinRAR";
}
elsif(-d $localdrive . "\\Program Files\\WinRAR"){
print " ::: You have WinRAR installed as 64 Bit...\n\n";
print "[db_dumper.pl] ::: You have WinRAR installed as 64 Bit...\n";
$WinRar = $localdrive . "\\Program Files\\WinRAR";
}
else{
print "No WinRAR installed... Will not compress...\n";
print "[db_dumper.pl] No WinRAR installed... Will not compress...\n";
}
if($S_ZIP ne ""){
print "Compressing Database with 7-ZIP... \n\n";
$cmd = '"' . $S_ZIP . '\\7z" a -t7z -m0=lzma -mx=9 "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.7z" "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql" ';
print "[db_dumper.pl] Compressing Database with 7-ZIP... \n";
$cmd = '"' . $S_ZIP . '\\7z" a -t7z -m0=lzma -mx=9 "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.7z" "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" ';
printcmd($cmd);
system($cmd);
print "\nDeleting RAW .sql Dump... \n\n";
$cmd = 'del "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql" ';
print "[db_dumper.pl] \nDeleting RAW .sql Dump... \n";
$cmd = 'del "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" ';
printcmd($cmd);
system($cmd);
$final_file = $target_file . ".7z";
}
elsif($WinRar ne ""){
print "Compressing Database with WinRAR... \n";
$cmd = '"' . $WinRar . '\\rar" a "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.rar" "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql" ';
print "[db_dumper.pl] Compressing Database with WinRAR... \n";
$cmd = '"' . $WinRar . '\\rar" a "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.rar" "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" ';
printcmd($cmd);
system($cmd);
print "\nDeleting RAW .sql Dump... \n\n";
$cmd = 'del "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql" ';
print "[db_dumper.pl] \nDeleting RAW .sql Dump... \n";
$cmd = 'del "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" ';
printcmd($cmd);
system($cmd);
$final_file = $target_file . ".rar";
}
}
if($OS eq "Linux"){
print "Compressing Database with Tarball... \n";
$cmd = 'tar -zcvf "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.tar.gz" "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql" ';
print "[db_dumper.pl] Compressing Database with Tarball... \n";
$cmd = 'tar -zcvf "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.tar.gz" "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" ';
printcmd($cmd);
system($cmd);
print "\nDeleting RAW .sql Dump... \n\n";
$cmd = 'rm "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql" ';
print "[db_dumper.pl] \nDeleting RAW .sql Dump... \n";
$cmd = 'rm "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" ';
printcmd($cmd);
system($cmd);
$final_file = $target_file . ".tar.gz";
}
}
else {
$final_file = $target_file . ".sql";
}
#::: Get Final File Location for display
if($B_LOC[1] ne ""){ $final_loc = $B_LOC[1] . '' . $file_app . ""; }
if($backup_location[1] ne ""){ $final_loc = $backup_location[1] . '' . $file_app . ""; }
else{
if($OS eq "Windows"){
$final_loc = `echo %cd%`;
@@ -207,10 +229,10 @@ else{
}
}
print "Final file located: " . $final_loc . "" . $final_file . "\n\n";
print "[db_dumper.pl] Final file located: " . $final_loc . "" . $final_file . "\n";
sub printcmd{
print "--- CMD --- \n" . $_[0] . "\n" . $linesep . "\n\n";
print "[db_dumper.pl] Command [" . $_[0] . "]\n";
}
sub get_filesize_str{
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+202
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
+33
View File
@@ -0,0 +1,33 @@
adventure_stats
char_recipe_list
character_activities
character_alt_currency
character_alternate_abilities
character_bandolier
character_bind
character_currency
character_data
character_disciplines
character_enabledtasks
character_inspect_messages
character_languages
character_leadership_abilities
character_material
character_memmed_spells
character_potionbelt
character_skills
character_spells
character_tribute
completed_tasks
faction_values
friends
guild_members
instance_list_player
inventory
keyring
mail
player_titlesets
quest_globals
timers
titles
zone_flags
+3
View File
@@ -351,6 +351,9 @@
9095|2016_01_08_command_find_aliases.sql|SELECT * FROM `command_settings` WHERE `command` LIKE 'findaliases'|empty|
9096|2016_03_05_secondary_recall.sql|SHOW COLUMNS FROM `character_bind` LIKE 'slot'|empty|
9097|2016_07_03_npc_class_as_last_name.sql|SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'NPC:UseClassAsLastName'|empty|
9098|2016_08_26_object_size_tilt.sql|SHOW COLUMNS FROM `object` LIKE 'size'|empty|
9099|2016_08_27_ip_exemptions.sql|SHOW TABLES LIKE 'ip_exemptions'|empty|
9100|2016_08_27_object_display_name.sql|SHOW COLUMNS FROM `object` LIKE 'display_name'|empty|
# Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not
@@ -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');
@@ -0,0 +1,4 @@
ALTER TABLE `object`
ADD COLUMN `size` FLOAT NOT NULL DEFAULT '100' AFTER `unknown84`,
ADD COLUMN `tilt_x` FLOAT NOT NULL DEFAULT '0' AFTER `size`,
ADD COLUMN `tilt_y` FLOAT NOT NULL DEFAULT '0' AFTER `tilt_x`;
@@ -0,0 +1,14 @@
-- IP Exemptions table structure
DROP TABLE IF EXISTS `ip_exemptions`;
CREATE TABLE `ip_exemptions` (
`exemption_id` int(11) NOT NULL AUTO_INCREMENT,
`exemption_ip` varchar(255) DEFAULT NULL,
`exemption_amount` int(11) DEFAULT NULL,
PRIMARY KEY (`exemption_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
-- Rule Value Entry, Default to false
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES ('1', 'World:EnableIPExemptions', 'false', 'notation');
-- Logging Category Entry
INSERT INTO `logsys_categories` (`log_category_id`, `log_category_description`, `log_to_console`, `log_to_file`, `log_to_gmsay`) VALUES ('44', 'Client Login', '1', '1', '1');
@@ -0,0 +1 @@
ALTER TABLE `object` ADD COLUMN `display_name` VARCHAR(64);
+1 -1
View File
@@ -722,7 +722,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
return true;
}
if (RuleI(World, MaxClientsPerIP) >= 0) {
if (RuleB(World, EnableIPExemptions) || RuleI(World, MaxClientsPerIP) >= 0) {
client_list.GetCLEIP(this->GetIP()); //Check current CLE Entry IPs against incoming connection
}
+51 -53
View File
@@ -29,6 +29,7 @@
#include "../common/classes.h"
#include "../common/packet_dump.h"
#include "wguild_mgr.h"
#include "../common/misc.h"
#include <set>
@@ -142,7 +143,6 @@ void ClientList::EnforceSessionLimit(uint32 iLSAccountID) {
//Check current CLE Entry IPs against incoming connection
void ClientList::GetCLEIP(uint32 iIP) {
ClientListEntry* countCLEIPs = 0;
LinkedListIterator<ClientListEntry*> iterator(clientlist);
@@ -150,64 +150,62 @@ void ClientList::GetCLEIP(uint32 iIP) {
iterator.Reset();
while(iterator.MoreElements()) {
countCLEIPs = iterator.GetData();
// If the IP matches, and the connection admin status is below the exempt status,
// or exempt status is less than 0 (no-one is exempt)
if ((countCLEIPs->GetIP() == iIP) &&
((countCLEIPs->Admin() < (RuleI(World, ExemptMaxClientsStatus))) ||
(RuleI(World, ExemptMaxClientsStatus) < 0))) {
// Increment the occurences of this IP address
IPInstances++;
// If the number of connections exceeds the lower limit
if (IPInstances > (RuleI(World, MaxClientsPerIP))) {
// If MaxClientsSetByStatus is set to True, override other IP Limit Rules
if (RuleB(World, MaxClientsSetByStatus)) {
// The IP Limit is set by the status of the account if status > MaxClientsPerIP
if (IPInstances > countCLEIPs->Admin()) {
if(RuleB(World, IPLimitDisconnectAll)) {
countCLEIPs = iterator.GetData();
if ((countCLEIPs->GetIP() == iIP) && ((countCLEIPs->Admin() < (RuleI(World, ExemptMaxClientsStatus))) || (RuleI(World, ExemptMaxClientsStatus) < 0))) { // If the IP matches, and the connection admin status is below the exempt status, or exempt status is less than 0 (no-one is exempt)
IPInstances++; // Increment the occurences of this IP address
Log.Out(Logs::General, Logs::Client_Login, "Account ID: %i Account Name: %s IP: %s.", countCLEIPs->LSID(), countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str());
if (RuleB(World, EnableIPExemptions)) {
Log.Out(Logs::General, Logs::Client_Login, "Account ID: %i Account Name: %s IP: %s IP Instances: %i Max IP Instances: %i", countCLEIPs->LSID(), countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str(), IPInstances, database.GetIPExemption(long2ip(countCLEIPs->GetIP()).c_str()));
if (IPInstances > database.GetIPExemption(long2ip(countCLEIPs->GetIP()).c_str())) {
if(RuleB(World, IPLimitDisconnectAll)) {
Log.Out(Logs::General, Logs::Client_Login, "Disconnect: All accounts on IP %s", long2ip(countCLEIPs->GetIP()).c_str());
DisconnectByIP(iIP);
return;
} else {
Log.Out(Logs::General, Logs::Client_Login, "Disconnect: Account %s on IP %s.", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str());
countCLEIPs->SetOnline(CLE_Status_Offline);
iterator.RemoveCurrent();
continue;
}
}
} else {
if (IPInstances > (RuleI(World, MaxClientsPerIP))) { // If the number of connections exceeds the lower limit
if (RuleB(World, MaxClientsSetByStatus)) { // If MaxClientsSetByStatus is set to True, override other IP Limit Rules
Log.Out(Logs::General, Logs::Client_Login, "Account ID: %i Account Name: %s IP: %s IP Instances: %i Max IP Instances: %i", countCLEIPs->LSID(), countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str(), IPInstances, countCLEIPs->Admin());
if (IPInstances > countCLEIPs->Admin()) { // The IP Limit is set by the status of the account if status > MaxClientsPerIP
if(RuleB(World, IPLimitDisconnectAll)) {
Log.Out(Logs::General, Logs::Client_Login, "Disconnect: All accounts on IP %s", long2ip(countCLEIPs->GetIP()).c_str());
DisconnectByIP(iIP);
return;
} else {
Log.Out(Logs::General, Logs::Client_Login, "Disconnect: Account %s on IP %s.", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str());
countCLEIPs->SetOnline(CLE_Status_Offline); // Remove the connection
iterator.RemoveCurrent();
continue;
}
}
} else if ((countCLEIPs->Admin() < RuleI(World, AddMaxClientsStatus)) || (RuleI(World, AddMaxClientsStatus) < 0)) { // Else if the Admin status of the connection is not eligible for the higher limit, or there is no higher limit (AddMaxClientStatus < 0)
if(RuleB(World, IPLimitDisconnectAll)) {
Log.Out(Logs::General, Logs::Client_Login, "Disconnect: All accounts on IP %s", long2ip(countCLEIPs->GetIP()).c_str());
DisconnectByIP(iIP);
return;
} else {
// Remove the connection
countCLEIPs->SetOnline(CLE_Status_Offline);
Log.Out(Logs::General, Logs::Client_Login, "Disconnect: Account %s on IP %s.", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str());
countCLEIPs->SetOnline(CLE_Status_Offline); // Remove the connection
iterator.RemoveCurrent();
continue;
}
} else if (IPInstances > RuleI(World, AddMaxClientsPerIP)) { // else they are eligible for the higher limit, but if they exceed that
if(RuleB(World, IPLimitDisconnectAll)) {
Log.Out(Logs::General, Logs::Client_Login, "Disconnect: All accounts on IP %s", long2ip(countCLEIPs->GetIP()).c_str());
DisconnectByIP(iIP);
return;
} else {
Log.Out(Logs::General, Logs::Client_Login, "Disconnect: Account %s on IP %s.", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str());
countCLEIPs->SetOnline(CLE_Status_Offline); // Remove the connection
iterator.RemoveCurrent();
continue;
}
}
}
// Else if the Admin status of the connection is not eligible for the higher limit,
// or there is no higher limit (AddMaxClientStatus<0)
else if ((countCLEIPs->Admin() < (RuleI(World, AddMaxClientsStatus)) ||
(RuleI(World, AddMaxClientsStatus) < 0))) {
if(RuleB(World, IPLimitDisconnectAll)) {
DisconnectByIP(iIP);
return;
} else {
// Remove the connection
countCLEIPs->SetOnline(CLE_Status_Offline);
iterator.RemoveCurrent();
continue;
}
}
// else they are eligible for the higher limit, but if they exceed that
else if (IPInstances > RuleI(World, AddMaxClientsPerIP)) {
if(RuleB(World, IPLimitDisconnectAll)) {
DisconnectByIP(iIP);
return;
} else {
// Remove the connection
countCLEIPs->SetOnline(CLE_Status_Offline);
iterator.RemoveCurrent();
continue;
}
}
}
+1 -1
View File
@@ -412,7 +412,7 @@ int main(int argc, char** argv) {
Timer InterserverTimer(INTERSERVER_TIMER); // does MySQL pings and auto-reconnect
InterserverTimer.Trigger();
uint8 ReconnectCounter = 100;
std::shared_ptr<EQStream> eqs;
std::shared_ptr<EQStreamInterface> eqs;
EmuTCPConnection* tcpc;
EQStreamInterface *eqsi;
+1
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:
+2 -2
View File
@@ -373,7 +373,7 @@ bool Mob::AvoidDamage(Mob *other, int32 &damage, int hand)
// riposte -- it may seem crazy, but if the attacker has SPA 173 on them, they are immune to Ripo
bool ImmuneRipo = attacker->aabonuses.RiposteChance || attacker->spellbonuses.RiposteChance || attacker->itembonuses.RiposteChance;
// Need to check if we have something in MainHand to actually attack with (or fists)
if (hand != EQEmu::legacy::SlotRange && CanThisClassRiposte() && InFront && !ImmuneRipo) {
if (hand != EQEmu::legacy::SlotRange && (CanThisClassRiposte() || IsEnraged()) && InFront && !ImmuneRipo) {
if (IsEnraged()) {
damage = -3;
Log.Out(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack.");
@@ -1800,7 +1800,7 @@ void NPC::Damage(Mob* other, int32 damage, uint16 spell_id, EQEmu::skills::Skill
//handle EVENT_ATTACK. Resets after we have not been attacked for 12 seconds
if(attacked_timer.Check())
{
Log.Out(Logs::Detail, Logs::Combat, "Triggering EVENT_ATTACK due to attack by %s", other->GetName());
Log.Out(Logs::Detail, Logs::Combat, "Triggering EVENT_ATTACK due to attack by %s", other ? other->GetName() : "nullptr");
parse->EventNPC(EVENT_ATTACK, this, other, "", 0);
}
attacked_timer.Start(CombatEventTimer_expire);
+2
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:
+2 -2
View File
@@ -1317,8 +1317,8 @@ bool BotDatabase::SaveEquipmentColor(const uint32 bot_id, const int16 slot_id, c
" WHERE `bot_id` = '%u'"
" %s",
rgb,
where_clause.c_str(),
bot_id
bot_id,
where_clause.c_str()
);
auto results = QueryDatabase(query);
if (!results.Success())
+104 -44
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
+2 -1
View File
@@ -207,7 +207,7 @@ struct ClientReward
class ClientFactory {
public:
Client *MakeClient(std::shared_ptr<EQStream> ieqs);
Client *MakeClient(std::shared_ptr<EQStreamInterface> ieqs);
};
class Client : public Mob
@@ -796,6 +796,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);
+26 -21
View File
@@ -502,6 +502,27 @@ void Client::CompleteConnect()
SetDuelTarget(0);
SetDueling(false);
database.LoadPetInfo(this);
/*
This was moved before the spawn packets are sent
in hopes that it adds more consistency...
Remake pet
*/
if (m_petinfo.SpellID > 1 && !GetPet() && m_petinfo.SpellID <= SPDAT_RECORDS) {
MakePoweredPet(m_petinfo.SpellID, spells[m_petinfo.SpellID].teleport_zone, m_petinfo.petpower, m_petinfo.Name, m_petinfo.size);
if (GetPet() && GetPet()->IsNPC()) {
NPC *pet = GetPet()->CastToNPC();
pet->SetPetState(m_petinfo.Buffs, m_petinfo.Items);
pet->CalcBonuses();
pet->SetHP(m_petinfo.HP);
pet->SetMana(m_petinfo.Mana);
}
m_petinfo.SpellID = 0;
}
/* Moved here so it's after where we load the pet data. */
if (!GetAA(aaPersistentMinion))
memset(&m_suspendedminion, 0, sizeof(PetInfo));
EnteringMessages(this);
LoadZoneFlags();
@@ -1628,27 +1649,6 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
if (m_pp.RestTimer)
rest_timer.Start(m_pp.RestTimer * 1000);
database.LoadPetInfo(this);
/*
This was moved before the spawn packets are sent
in hopes that it adds more consistency...
Remake pet
*/
if (m_petinfo.SpellID > 1 && !GetPet() && m_petinfo.SpellID <= SPDAT_RECORDS) {
MakePoweredPet(m_petinfo.SpellID, spells[m_petinfo.SpellID].teleport_zone, m_petinfo.petpower, m_petinfo.Name, m_petinfo.size);
if (GetPet() && GetPet()->IsNPC()) {
NPC *pet = GetPet()->CastToNPC();
pet->SetPetState(m_petinfo.Buffs, m_petinfo.Items);
pet->CalcBonuses();
pet->SetHP(m_petinfo.HP);
pet->SetMana(m_petinfo.Mana);
}
m_petinfo.SpellID = 0;
}
/* Moved here so it's after where we load the pet data. */
if (!GetAA(aaPersistentMinion))
memset(&m_suspendedminion, 0, sizeof(PetInfo));
/* Server Zone Entry Packet */
outapp = new EQApplicationPacket(OP_ZoneEntry, sizeof(ServerZoneEntry_Struct));
ServerZoneEntry_Struct* sze = (ServerZoneEntry_Struct*)outapp->pBuffer;
@@ -13093,6 +13093,11 @@ void Client::Handle_OP_TargetCommand(const EQApplicationPacket *app)
GetTarget()->IsTargeted(1);
return;
}
else if (RuleB(Character, AllowMQTarget))
{
GetTarget()->IsTargeted(1);
return;
}
else if (IsAssistExempted())
{
GetTarget()->IsTargeted(1);
+1
View File
@@ -1007,6 +1007,7 @@ void command_summon(Client *c, const Seperator *sep)
szp->x_pos = c->GetX(); // May need to add a factor of 8 in here..
szp->y_pos = c->GetY();
szp->z_pos = c->GetZ();
szp->instance_id = zone->GetInstanceID();
worldserver.SendPacket(pack);
safe_delete(pack);
}
+21
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);
+13 -6
View File
@@ -478,14 +478,18 @@ void EntityList::MobProcess()
size_t sz = mob_list.size();
#ifdef IDLE_WHEN_EMPTY
// spawn_events can cause spawns and deaths while zone empty.
// At the very least, process that.
if (numclients < 1) {
mob_dead = mob->CastToNPC()->GetDepop();
}
else {
if (numclients > 0 ||
mob->GetWanderType() == 4 || mob->GetWanderType() == 6) {
// Normal processing, or assuring that spawns that should
// path and depop do that. Otherwise all of these type mobs
// will be up and at starting positions when idle zone wakes up.
mob_dead = !mob->Process();
}
else {
// spawn_events can cause spawns and deaths while zone empty.
// At the very least, process that.
mob_dead = mob->CastToNPC()->GetDepop();
}
#else
mob_dead = !mob->Process();
#endif
@@ -2506,6 +2510,9 @@ void EntityList::Depop(bool StartSpawnTimer)
if (own && own->IsClient())
continue;
if (pnpc->IsHorse)
continue;
if (pnpc->IsFindable())
UpdateFindableNPCState(pnpc, true);
+27 -4
View File
@@ -705,10 +705,33 @@ uint32 Client::GetEXPForLevel(uint16 check_level)
return finalxp;
}
void Client::AddLevelBasedExp(uint8 exp_percentage, uint8 max_level) {
if (exp_percentage > 100) { exp_percentage = 100; }
if (!max_level || GetLevel() < max_level) { max_level = GetLevel(); }
uint32 newexp = GetEXP() + ((GetEXPForLevel(max_level + 1) - GetEXPForLevel(max_level)) * exp_percentage / 100);
void Client::AddLevelBasedExp(uint8 exp_percentage, uint8 max_level)
{
uint32 award;
uint32 xp_for_level;
if (exp_percentage > 100)
{
exp_percentage = 100;
}
if (!max_level || GetLevel() < max_level)
{
max_level = GetLevel();
}
xp_for_level = GetEXPForLevel(max_level + 1) - GetEXPForLevel(max_level);
award = xp_for_level * exp_percentage / 100;
if(RuleB(Zone, LevelBasedEXPMods))
{
if(zone->level_exp_mod[GetLevel()].ExpMod)
{
award *= zone->level_exp_mod[GetLevel()].ExpMod;
}
}
uint32 newexp = GetEXP() + award;
SetEXP(newexp, GetAAXP());
}
+2
View File
@@ -36,6 +36,8 @@ Horse::Horse(Client *_owner, uint16 spell_id, const glm::vec4& position)
strn0cpy(name, _owner->GetCleanName(), 55);
strcat(name,"`s_Mount00");
IsHorse = true;
owner = _owner;
}
+6
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)
+1
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);
+5
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),
+6 -5
View File
@@ -289,6 +289,9 @@ Mob::Mob(const char* in_name,
logging_enabled = false;
isgrouped = false;
israidgrouped = false;
IsHorse = false;
entity_id_being_looted = 0;
_appearance = eaStanding;
pRunAnimSpeed = 0;
@@ -2581,14 +2584,12 @@ bool Mob::PlotPositionAroundTarget(Mob* target, float &x_dest, float &y_dest, fl
bool Mob::HateSummon() {
// check if mob has ability to summon
// 97% is the offical % that summoning starts on live, not 94
// if the mob can summon and is charmed, it can only summon mobs it has LoS to
Mob* mob_owner = nullptr;
if(GetOwnerID())
mob_owner = entity_list.GetMob(GetOwnerID());
if (IsCharmed())
return false;
int summon_level = GetSpecialAbility(SPECATK_SUMMON);
if(summon_level == 1 || summon_level == 2) {
if(!GetTarget() || (mob_owner && mob_owner->IsClient() && !CheckLosFN(GetTarget()))) {
if(!GetTarget()) {
return false;
}
} else {
+3
View File
@@ -847,6 +847,7 @@ public:
inline void SetFocused(bool nState) { focused = nState; }
inline const bool IsFocused() const { return focused; }
inline const bool IsRoamer() const { return roamer; }
inline const int GetWanderType() const { return wandertype; }
inline const bool IsRooted() const { return rooted || permarooted; }
inline const bool HasVirus() const { return has_virus; }
int GetSnaredAmount();
@@ -1404,6 +1405,8 @@ protected:
std::unordered_map<uint32, std::pair<uint32, uint32>> aa_ranks;
Timer aa_timers[aaTimerMax];
bool IsHorse;
private:
void _StopSong(); //this is not what you think it is
Mob* target;
+3 -1
View File
@@ -2364,7 +2364,9 @@ bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) {
if (IsValidSpell(attack_proc_spell)) {
AddProcToWeapon(attack_proc_spell, true, proc_chance);
innate_proc_spell_id = attack_proc_spell;
if(RuleB(Spells, NPCInnateProcOverride))
innate_proc_spell_id = attack_proc_spell;
}
if (IsValidSpell(range_proc_spell))
+1 -1
View File
@@ -425,7 +425,7 @@ int main(int argc, char** argv) {
Timer quest_timers(100);
UpdateWindowTitle();
bool worldwasconnected = worldserver.Connected();
std::shared_ptr<EQStream> eqss;
std::shared_ptr<EQStreamInterface> eqss;
EQStreamInterface *eqsi;
uint8 IDLEZONEUPDATE = 200;
uint8 ZONEUPDATE = 10;
+4
View File
@@ -872,6 +872,10 @@ bool NPC::SpawnZoneController(){
npc_type->merchanttype = 0;
npc_type->bodytype = 11;
if (RuleB(Zone, EnableZoneControllerGlobals)) {
npc_type->qglobal = true;
}
npc_type->prim_melee_type = 28;
npc_type->sec_melee_type = 28;
+53 -4
View File
@@ -63,6 +63,9 @@ Object::Object(uint32 id, uint32 type, uint32 icon, const Object_Struct& object,
// Set drop_id to zero - it will be set when added to zone with SetID()
m_data.drop_id = 0;
m_data.size = object.size;
m_data.tilt_x = object.tilt_x;
m_data.tilt_y = object.tilt_y;
}
//creating a re-ocurring ground spawn.
@@ -540,6 +543,7 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object)
coa->drop_id = click_object->drop_id;
coa->player_id = click_object->player_id;
coa->icon = m_icon;
strn0cpy(coa->object_name, m_display_name, 64);
//if this is not the main user, send them a close and a message
if (user == nullptr || user == sender) {
@@ -653,10 +657,12 @@ void ZoneDatabase::UpdateObject(uint32 id, uint32 type, uint32 icon, const Objec
// Save new record for object
std::string query = StringFormat("UPDATE object SET "
"zoneid = %i, xpos = %f, ypos = %f, zpos = %f, heading = %f, "
"itemid = %i, charges = %i, objectname = '%s', type = %i, icon = %i "
"itemid = %i, charges = %i, objectname = '%s', type = %i, icon = %i, "
"size = %f, tilt_x = %f, tilt_y = %f "
"WHERE id = %i",
object.zone_id, object.x, object.y, object.z, object.heading,
item_id, charges, object_name, type, icon, id);
item_id, charges, object_name, type, icon,
object.size, object.tilt_x, object.tilt_y, id);
safe_delete_array(object_name);
auto results = QueryDatabase(query);
if (!results.Success()) {
@@ -750,6 +756,16 @@ float Object::GetHeadingData()
return this->m_data.heading;
}
float Object::GetTiltX()
{
return this->m_data.tilt_x;
}
float Object::GetTiltY()
{
return this->m_data.tilt_y;
}
void Object::SetX(float pos)
{
this->m_data.x = pos;
@@ -778,6 +794,39 @@ void Object::SetY(float pos)
safe_delete(app2);
}
void Object::SetTiltX(float pos)
{
this->m_data.tilt_x = pos;
auto app = new EQApplicationPacket();
auto app2 = new EQApplicationPacket();
this->CreateDeSpawnPacket(app);
this->CreateSpawnPacket(app2);
entity_list.QueueClients(0, app);
entity_list.QueueClients(0, app2);
safe_delete(app);
safe_delete(app2);
}
void Object::SetTiltY(float pos)
{
this->m_data.tilt_y = pos;
auto app = new EQApplicationPacket();
auto app2 = new EQApplicationPacket();
this->CreateDeSpawnPacket(app);
this->CreateSpawnPacket(app2);
entity_list.QueueClients(0, app);
entity_list.QueueClients(0, app2);
safe_delete(app);
safe_delete(app2);
}
void Object::SetDisplayName(const char *in_name)
{
strn0cpy(m_display_name, in_name, 64);
}
void Object::Depop()
{
auto app = new EQApplicationPacket();
@@ -828,7 +877,7 @@ void Object::SetModelName(const char* modelname)
safe_delete(app2);
}
void Object::SetSize(uint16 size)
void Object::SetSize(float size)
{
m_data.size = size;
auto app = new EQApplicationPacket();
@@ -854,7 +903,7 @@ void Object::SetSolidType(uint16 solidtype)
safe_delete(app2);
}
uint16 Object::GetSize()
float Object::GetSize()
{
return m_data.size;
}
+9 -2
View File
@@ -154,12 +154,18 @@ public:
void SetX(float pos);
void SetY(float pos);
void SetZ(float pos);
void SetTiltX(float pos);
void SetTiltY(float pos);
float GetTiltX();
float GetTiltY();
void SetModelName(const char* modelname);
const char* GetModelName();
uint16 GetSize();
void SetSize(uint16 size);
float GetSize();
void SetSize(float size);
uint16 GetSolidType();
void SetSolidType(uint16 size);
void SetDisplayName(const char *in_name);
const char *GetDisplayName() const { return m_display_name; }
const char* GetEntityVariable(const char *id);
void SetEntityVariable(const char *id, const char *m_var);
@@ -182,6 +188,7 @@ protected:
float m_z;
float m_heading;
bool m_ground_spawn;
char m_display_name[64];
std::map<std::string, std::string> o_EntityVariables;
+27
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, "$$");
+107 -3
View File
@@ -968,7 +968,7 @@ XS(XS_Object_GetSize)
Perl_croak(aTHX_ "Usage: Object::GetSize(THIS)");
{
Object * THIS;
uint16 RETVAL;
float RETVAL;
dXSTARG;
if (sv_derived_from(ST(0), "Object")) {
@@ -981,7 +981,7 @@ XS(XS_Object_GetSize)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetSize();
XSprePUSH; PUSHu((UV)RETVAL);
XSprePUSH; PUSHn((double)RETVAL);
}
XSRETURN(1);
}
@@ -995,7 +995,7 @@ XS(XS_Object_SetSize)
Perl_croak(aTHX_ "Usage: Object::SetSize(THIS, type)");
{
Object * THIS;
uint16 size = (uint16)SvUV(ST(1));
float size = (float)SvNV(ST(1));
if (sv_derived_from(ST(0), "Object")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
@@ -1011,6 +1011,106 @@ XS(XS_Object_SetSize)
XSRETURN_EMPTY;
}
XS(XS_Object_SetTiltX); /* prototype to pass -Wmissing-prototypes */
XS(XS_Object_SetTiltX)
{
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: Object::SetTiltX(THIS, pos)");
{
Object * THIS;
float pos = (float)SvNV(ST(1));
if (sv_derived_from(ST(0), "Object")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Object *,tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Object");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
THIS->SetTiltX(pos);
}
XSRETURN_EMPTY;
}
XS(XS_Object_SetTiltY); /* prototype to pass -Wmissing-prototypes */
XS(XS_Object_SetTiltY)
{
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: Object::SetTiltY(THIS, pos)");
{
Object * THIS;
float pos = (float)SvNV(ST(1));
if (sv_derived_from(ST(0), "Object")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Object *,tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Object");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
THIS->SetTiltY(pos);
}
XSRETURN_EMPTY;
}
XS(XS_Object_GetTiltX); /* prototype to pass -Wmissing-prototypes */
XS(XS_Object_GetTiltX)
{
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Object::GetSize(THIS)");
{
Object * THIS;
float RETVAL;
dXSTARG;
if (sv_derived_from(ST(0), "Object")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Object *,tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Object");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetTiltX();
XSprePUSH; PUSHn((double)RETVAL);
}
XSRETURN(1);
}
XS(XS_Object_GetTiltY); /* prototype to pass -Wmissing-prototypes */
XS(XS_Object_GetTiltY)
{
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Object::GetSize(THIS)");
{
Object * THIS;
float RETVAL;
dXSTARG;
if (sv_derived_from(ST(0), "Object")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Object *,tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Object");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetTiltY();
XSprePUSH; PUSHn((double)RETVAL);
}
XSRETURN(1);
}
#ifdef __cplusplus
extern "C"
#endif
@@ -1066,6 +1166,10 @@ XS(boot_Object)
newXSproto(strcpy(buf, "GetSolidType"),XS_Object_GetSolidType, file, "$");
newXSproto(strcpy(buf, "SetSize"),XS_Object_SetSize, file, "$$");
newXSproto(strcpy(buf, "GetSize"),XS_Object_GetSize, file, "$");
newXSproto(strcpy(buf, "SetTiltX"),XS_Object_SetTiltX, file, "$$");
newXSproto(strcpy(buf, "SetTiltY"),XS_Object_SetTiltY, file, "$");
newXSproto(strcpy(buf, "GetTiltX"),XS_Object_GetTiltX, file, "$$");
newXSproto(strcpy(buf, "GetTiltY"),XS_Object_GetTiltY, file, "$");
XSRETURN_YES;
}
#endif //EMBPERL_XS_CLASSES
+14
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;
+1
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);
+3 -3
View File
@@ -194,6 +194,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
bool SE_SpellTrigger_HasCast = false;
// if buff slot, use instrument mod there, otherwise calc it
uint32 instrument_mod = buffslot > -1 ? buffs[buffslot].instrument_mod : caster ? caster->GetInstrumentMod(spell_id) : 10;
// iterate through the effects in the spell
for (i = 0; i < EFFECT_COUNT; i++)
{
@@ -201,9 +203,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
continue;
effect = spell.effectid[i];
// if buff slot, use instrument mod there, otherwise calc it
uint32 inst = buffslot > -1 ? buffs[buffslot].instrument_mod : caster ? caster->GetInstrumentMod(spell_id) : 10;
effect_value = CalcSpellEffectValue(spell_id, i, caster_level, inst, caster ? caster : this);
effect_value = CalcSpellEffectValue(spell_id, i, caster_level, instrument_mod, caster ? caster : this);
if(spell_id == SPELL_LAY_ON_HANDS && caster && caster->GetAA(aaImprovedLayOnHands))
effect_value = GetMaxHP();
+13 -8
View File
@@ -928,7 +928,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
//should we issue a message or send them a spell gem packet?
Message_StringID(13, SPELL_RECAST);
Log.Out(Logs::Detail, Logs::Spells, "Casting of %d canceled: spell reuse timer not expired", spell_id);
InterruptSpell();
StopCasting();
return;
}
}
@@ -942,7 +942,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
if(!CastToClient()->GetPTimers().Expired(&database, (pTimerItemStart + itm->GetItem()->RecastType), false)) {
Message_StringID(13, SPELL_RECAST);
Log.Out(Logs::Detail, Logs::Spells, "Casting of %d canceled: item spell reuse timer not expired", spell_id);
InterruptSpell();
StopCasting();
return;
}
}
@@ -1271,7 +1271,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
if(!CastToClient()->GetPTimers().Expired(&database, (pTimerItemStart + recasttype), false)) {
Message_StringID(13, SPELL_RECAST);
Log.Out(Logs::Detail, Logs::Spells, "Casting of %d canceled: item spell reuse timer not expired", spell_id);
InterruptSpell();
StopCasting();
return;
}
else
@@ -1310,7 +1310,9 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
if( !SpellFinished(spell_id, spell_target, slot, mana_used, inventory_slot, resist_adjust) )
{
Log.Out(Logs::Detail, Logs::Spells, "Casting of %d canceled: SpellFinished returned false.", spell_id);
InterruptSpell();
// most of the cases we return false have a message already or are logic errors that shouldn't happen
// if there are issues I guess we can do something else, but this should work
StopCasting();
return;
}
@@ -5456,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)
{
@@ -5489,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)
{
@@ -5727,6 +5731,7 @@ void Client::SetLinkedSpellReuseTimer(uint32 timer_id, uint32 duration)
{
if (timer_id > 19)
return;
Log.Out(Logs::Detail, Logs::Spells, "Setting Linked Spell Reuse %d for %d", timer_id, duration);
GetPTimers().Start(pTimerLinkedSpellReuseStart + timer_id, duration);
auto outapp = new EQApplicationPacket(OP_LinkedReuse, sizeof(LinkedSpellReuseTimer_Struct));
auto lr = (LinkedSpellReuseTimer_Struct *)outapp->pBuffer;
@@ -5740,6 +5745,6 @@ bool Client::IsLinkedSpellReuseTimerReady(uint32 timer_id)
{
if (timer_id > 19)
return true;
return GetPTimers().Expired(&database, pTimerLinkedSpellReuseStart + timer_id);
return GetPTimers().Expired(&database, pTimerLinkedSpellReuseStart + timer_id, false);
}
+25 -1
View File
@@ -543,7 +543,18 @@ void WorldServer::Process() {
else {
SendEmoteMessage(szp->adminname, 0, 0, "Summoning %s to %s %1.1f, %1.1f, %1.1f", szp->name, szp->zone, szp->x_pos, szp->y_pos, szp->z_pos);
}
client->MovePC(database.GetZoneID(szp->zone), szp->instance_id, szp->x_pos, szp->y_pos, szp->z_pos, client->GetHeading(), szp->ignorerestrictions, GMSummon);
if (!szp->instance_id) {
client->MovePC(database.GetZoneID(szp->zone), szp->instance_id, szp->x_pos, szp->y_pos, szp->z_pos, client->GetHeading(), szp->ignorerestrictions, GMSummon);
} else {
if (database.GetInstanceID(client->CharacterID(), database.GetZoneID(szp->zone)) == 0) {
client->AssignToInstance(szp->instance_id);
client->MovePC(database.GetZoneID(szp->zone), szp->instance_id, szp->x_pos, szp->y_pos, szp->z_pos, client->GetHeading(), szp->ignorerestrictions, GMSummon);
} else {
client->RemoveFromInstance(database.GetInstanceID(client->CharacterID(), database.GetZoneID(szp->zone)));
client->AssignToInstance(szp->instance_id);
client->MovePC(database.GetZoneID(szp->zone), szp->instance_id, szp->x_pos, szp->y_pos, szp->z_pos, client->GetHeading(), szp->ignorerestrictions, GMSummon);
}
}
}
break;
}
@@ -1838,6 +1849,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;
+110 -107
View File
@@ -157,126 +157,129 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) {
}
//this really loads the objects into entity_list
bool Zone::LoadZoneObjects() {
std::string query = StringFormat("SELECT id, zoneid, xpos, ypos, zpos, heading, "
"itemid, charges, objectname, type, icon, unknown08, "
"unknown10, unknown20, unknown24, unknown76 fROM object "
"WHERE zoneid = %i AND (version = %u OR version = -1)",
zoneid, instanceversion);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
Log.Out(Logs::General, Logs::Error, "Error Loading Objects from DB: %s",results.ErrorMessage().c_str());
bool Zone::LoadZoneObjects()
{
std::string query =
StringFormat("SELECT id, zoneid, xpos, ypos, zpos, heading, itemid, charges, objectname, type, icon, "
"unknown08, unknown10, unknown20, unknown24, unknown76, size, tilt_x, tilt_y, display_name "
"FROM object WHERE zoneid = %i AND (version = %u OR version = -1)",
zoneid, instanceversion);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
Log.Out(Logs::General, Logs::Error, "Error Loading Objects from DB: %s",
results.ErrorMessage().c_str());
return false;
}
Log.Out(Logs::General, Logs::Status, "Loading Objects from DB...");
for (auto row = results.begin(); row != results.end(); ++row) {
if (atoi(row[9]) == 0)
{
// Type == 0 - Static Object
const char* shortname = database.GetZoneName(atoi(row[1]), false); // zoneid -> zone_shortname
if (!shortname)
continue;
Door d;
memset(&d, 0, sizeof(d));
strn0cpy(d.zone_name, shortname, sizeof(d.zone_name));
d.db_id = 1000000000 + atoi(row[0]); // Out of range of normal use for doors.id
d.door_id = -1; // Client doesn't care if these are all the same door_id
d.pos_x = atof(row[2]); // xpos
d.pos_y = atof(row[3]); // ypos
d.pos_z = atof(row[4]); // zpos
d.heading = atof(row[5]); // heading
strn0cpy(d.door_name, row[8], sizeof(d.door_name)); // objectname
// Strip trailing "_ACTORDEF" if present. Client won't accept it for doors.
int len = strlen(d.door_name);
if ((len > 9) && (memcmp(&d.door_name[len - 9], "_ACTORDEF", 10) == 0))
d.door_name[len - 9] = '\0';
memcpy(d.dest_zone, "NONE", 5);
if ((d.size = atoi(row[11])) == 0) // unknown08 = optional size percentage
d.size = 100;
switch (d.opentype = atoi(row[12])) // unknown10 = optional request_nonsolid (0 or 1 or experimental number)
{
case 0:
d.opentype = 31;
break;
case 1:
d.opentype = 9;
break;
}
d.incline = atoi(row[13]); // unknown20 = optional model incline value
d.client_version_mask = 0xFFFFFFFF; //We should load the mask from the zone.
auto door = new Doors(&d);
entity_list.AddDoor(door);
}
Object_Struct data = {0};
uint32 id = 0;
uint32 icon = 0;
uint32 type = 0;
uint32 itemid = 0;
uint32 idx = 0;
int16 charges = 0;
Log.Out(Logs::General, Logs::Status, "Loading Objects from DB...");
for (auto row = results.begin(); row != results.end(); ++row) {
if (atoi(row[9]) == 0) {
// Type == 0 - Static Object
const char *shortname = database.GetZoneName(atoi(row[1]), false); // zoneid -> zone_shortname
id = (uint32)atoi(row[0]);
data.zone_id = atoi(row[1]);
data.x = atof(row[2]);
data.y = atof(row[3]);
data.z = atof(row[4]);
data.heading = atof(row[5]);
if (!shortname)
continue;
Door d;
memset(&d, 0, sizeof(d));
strn0cpy(d.zone_name, shortname, sizeof(d.zone_name));
d.db_id = 1000000000 + atoi(row[0]); // Out of range of normal use for doors.id
d.door_id = -1; // Client doesn't care if these are all the same door_id
d.pos_x = atof(row[2]); // xpos
d.pos_y = atof(row[3]); // ypos
d.pos_z = atof(row[4]); // zpos
d.heading = atof(row[5]); // heading
strn0cpy(d.door_name, row[8], sizeof(d.door_name)); // objectname
// Strip trailing "_ACTORDEF" if present. Client won't accept it for doors.
int len = strlen(d.door_name);
if ((len > 9) && (memcmp(&d.door_name[len - 9], "_ACTORDEF", 10) == 0))
d.door_name[len - 9] = '\0';
memcpy(d.dest_zone, "NONE", 5);
if ((d.size = atoi(row[11])) == 0) // unknown08 = optional size percentage
d.size = 100;
switch (d.opentype = atoi(row[12])) // unknown10 = optional request_nonsolid (0 or 1 or experimental number)
{
case 0:
d.opentype = 31;
break;
case 1:
d.opentype = 9;
break;
}
d.incline = atoi(row[13]); // unknown20 = optional model incline value
d.client_version_mask = 0xFFFFFFFF; // We should load the mask from the zone.
auto door = new Doors(&d);
entity_list.AddDoor(door);
}
Object_Struct data = {0};
uint32 id = 0;
uint32 icon = 0;
uint32 type = 0;
uint32 itemid = 0;
uint32 idx = 0;
int16 charges = 0;
id = (uint32)atoi(row[0]);
data.zone_id = atoi(row[1]);
data.x = atof(row[2]);
data.y = atof(row[3]);
data.z = atof(row[4]);
data.heading = atof(row[5]);
itemid = (uint32)atoi(row[6]);
charges = (int16)atoi(row[7]);
strcpy(data.object_name, row[8]);
type = (uint8)atoi(row[9]);
icon = (uint32)atoi(row[10]);
charges = (int16)atoi(row[7]);
strcpy(data.object_name, row[8]);
type = (uint8)atoi(row[9]);
icon = (uint32)atoi(row[10]);
data.object_type = type;
data.linked_list_addr[0] = 0;
data.linked_list_addr[1] = 0;
data.size = (uint32)atoi(row[11]);
data.solidtype = (uint32)atoi(row[12]);
data.unknown020 = (uint32)atoi(row[13]);
data.unknown024 = (uint32)atoi(row[14]);
data.unknown076 = (uint32)atoi(row[15]);
data.unknown084 = 0;
data.linked_list_addr[1] = 0;
ItemInst* inst = nullptr;
//FatherNitwit: this dosent seem to work...
//tradeskill containers do not have an itemid of 0... at least what I am seeing
if (itemid == 0) {
// Generic tradeskill container
inst = new ItemInst(ItemInstWorldContainer);
}
else {
// Groundspawn object
inst = database.CreateItem(itemid);
}
data.solidtype = (uint32)atoi(row[12]);
data.unknown020 = (uint32)atoi(row[13]);
data.unknown024 = (uint32)atoi(row[14]);
data.unknown076 = (uint32)atoi(row[15]);
data.size = atof(row[16]);
data.tilt_x = atof(row[17]);
data.tilt_y = atof(row[18]);
data.unknown084 = 0;
//Father Nitwit's fix... not perfect...
if(inst == nullptr && type != OT_DROPPEDITEM) {
inst = new ItemInst(ItemInstWorldContainer);
}
ItemInst *inst = nullptr;
// FatherNitwit: this dosent seem to work...
// tradeskill containers do not have an itemid of 0... at least what I am seeing
if (itemid == 0) {
// Generic tradeskill container
inst = new ItemInst(ItemInstWorldContainer);
} else {
// Groundspawn object
inst = database.CreateItem(itemid);
}
// Load child objects if container
// Father Nitwit's fix... not perfect...
if (inst == nullptr && type != OT_DROPPEDITEM) {
inst = new ItemInst(ItemInstWorldContainer);
}
// Load child objects if container
if (inst && inst->IsType(EQEmu::item::ItemClassBag)) {
database.LoadWorldContainer(id, inst);
}
database.LoadWorldContainer(id, inst);
}
auto object = new Object(id, type, icon, data, inst);
entity_list.AddObject(object, false);
if (type == OT_DROPPEDITEM && itemid != 0)
entity_list.RemoveObject(object->GetID());
auto object = new Object(id, type, icon, data, inst);
object->SetDisplayName(row[19]);
entity_list.AddObject(object, false);
if (type == OT_DROPPEDITEM && itemid != 0)
entity_list.RemoveObject(object->GetID());
safe_delete(inst);
}
safe_delete(inst);
}
return true;
}