mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-26 07:52:27 +00:00
Compare commits
98 Commits
web_interface
...
eqsi
| Author | SHA1 | Date | |
|---|---|---|---|
| 751e61d6e5 | |||
| 4cb7d9a352 | |||
| b04844aa94 | |||
| b15ada974f | |||
| e2587b78f5 | |||
| 06dfba3c81 | |||
| 8aa942cd27 | |||
| a9070b1327 | |||
| 745510ea75 | |||
| f6d721dd72 | |||
| 0503e85fd3 | |||
| 0232f4f672 | |||
| 56d355935b | |||
| d260bb5cd4 | |||
| 4816c1fc9a | |||
| 50469b858b | |||
| 64998a398d | |||
| 9a3af63f65 | |||
| 5679f45f5b | |||
| 66c0da85e6 | |||
| 4246e4f79b | |||
| 90dc7a4e38 | |||
| bf28354301 | |||
| 5f1141dfb1 | |||
| 5b03fba463 | |||
| 0efd0c5f73 | |||
| 2947e3f39f | |||
| 77974c83d7 | |||
| d0bb3047f0 | |||
| 739b1bfaa3 | |||
| fb308eaa01 | |||
| 7c40bcff53 | |||
| ec87656d58 | |||
| 159ba9f487 | |||
| d8fe5124ff | |||
| fa337d441e | |||
| ea1ae1a0a4 | |||
| 95ea61114a | |||
| 585e5830f7 | |||
| bfb77803d8 | |||
| 364ab42c49 | |||
| 89183cf8b7 | |||
| aaa116d97c | |||
| 4360021fc9 | |||
| b7b233d46f | |||
| 5c43f2d80e | |||
| ed9b6db369 | |||
| dd0d15e134 | |||
| 29d6817019 | |||
| 46bb559af1 | |||
| 031a37baa1 | |||
| 62a4ce76b6 | |||
| d85e6ae495 | |||
| 32c4c360bd | |||
| f2a075d432 | |||
| 2dee62c850 | |||
| db380944ac | |||
| 28c5b32624 | |||
| 6db350790e | |||
| 3f8ff1373c | |||
| d6ee505c63 | |||
| e84b2ba224 | |||
| 4de9b2c53e | |||
| 385823461b | |||
| 85c28185a2 | |||
| 25de25a777 | |||
| 357a92dfee | |||
| 35c83db432 | |||
| f7cc1053f1 | |||
| d5864aea3e | |||
| 2b2d6e1ef5 | |||
| f99523dc48 | |||
| 69913c0897 | |||
| 75694e8797 | |||
| 24856b6a2d | |||
| a70291f20f | |||
| 6e1a5eac94 | |||
| 37b87e98f4 | |||
| 55d2e9b842 | |||
| 3afc5d0890 | |||
| f6b6fcc2c5 | |||
| 5039aa07a5 | |||
| 8048239a81 | |||
| ecdc0f7096 | |||
| 2c3107fbe9 | |||
| c2b31bd6e2 | |||
| a8ba563632 | |||
| 4065df7930 | |||
| 0b06044dce | |||
| 93464e3963 | |||
| 8dd18a43a0 | |||
| afe42ccdaf | |||
| f5a7117bdf | |||
| 696c02c0f0 | |||
| 6daf207323 | |||
| f67cd057f3 | |||
| 0789d10d3e | |||
| a07149919d |
@@ -1,54 +1,59 @@
|
||||
EQEmu
|
||||
===
|
||||
# EQEmulator Core Server
|
||||
|Travis CI (Linux)|Appveyor (Windows) |
|
||||
|:---:|:---:|
|
||||
|[](https://travis-ci.org/EQEmu/Server) |[](https://ci.appveyor.com/project/KimLS/server/branch/master) |
|
||||
|
||||
[](https://travis-ci.org/EQEmu/Server)
|
||||
[](https://ci.appveyor.com/project/KimLS/server/branch/master)
|
||||
***
|
||||
|
||||
Overview
|
||||
---
|
||||
**EQEmulator is a custom completely from-scratch open source server implementation for EverQuest built mostly on C++**
|
||||
* MySQL/MariaDB is used as the database engine (over 200+ tables)
|
||||
* Perl and LUA are both supported scripting languages for NPC/Player/Quest oriented events
|
||||
* Open source database (Project EQ) has content up to expansion GoD (included in server installs)
|
||||
* Game server environments and databases can be heavily customized to create all new experiences
|
||||
* Hundreds of Quests/events created and maintained by Project EQ
|
||||
|
||||
EQEmu is a custom server implementation for EverQuest
|
||||
## Server Installs
|
||||
||Windows|Linux|
|
||||
|:---:|:---:|:---:|
|
||||
|**Install Count**|||
|
||||
### > Windows
|
||||
* [Easy Install](http://wiki.eqemulator.org/p?Akkas_PEQ_Server_Installer&frm=Main#from-scratch-installation-instructions-windows)
|
||||
* [Advanced Setup](http://wiki.eqemulator.org/p?Complete_Windows-based_Server_Setup_Guide)
|
||||
|
||||
Dependencies
|
||||
---
|
||||
### > Debian/Ubuntu
|
||||
|
||||
For Windows: http://eqemu.github.io
|
||||
> wget --no-check-certificate https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh -O install.sh && chmod 755 install.sh && ./install.sh
|
||||
|
||||
Login Server dependencies for Windows/Linux/OSX: http://eqemu.github.io
|
||||
### > CentOS/Fedora
|
||||
|
||||
For Debian based distros (adjust to your local flavor):
|
||||
> curl -O https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh install.sh && chmod 755 install.sh && ./install.sh
|
||||
|
||||
- libmysqlclient-dev
|
||||
- libperl-dev
|
||||
- liblua5.1-0-dev (5.2 should work as well)
|
||||
- libboost-dev
|
||||
## Supported Clients
|
||||
|
||||
Further instructions on building the source can be found on the
|
||||
[wiki](http://wiki.eqemulator.org/i?M=Wiki).
|
||||
|Titanium Edition|Secrets of Faydwer|Seeds of Destruction|Underfoot|Rain of Fear|
|
||||
|:---:|:---:|:---:|:---:|:---:|
|
||||
|<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
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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...
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user