Compare commits

..

117 Commits

Author SHA1 Message Date
Chris Miles ea9b7841d4 [Release] 22.48.0 (#4200) 2024-03-23 00:24:01 -05:00
Alex King 8826d7b927 [Rules] Add World:Rules Rule (#4194)
* [Rules] Add World:Rules Rule

# Notes
- Adds `World:Rules` rule to take the place of the variables table value.

* Update client.cpp

* Update client.cpp
2024-03-23 00:01:27 -05:00
JJ e4157f0221 [Bug Fix] Fix reusing timers (#4199)
Fixes regression from #4099 where timers that were reused were not getting changed with their updated times
2024-03-23 00:01:15 -05:00
Alex King 66cc947b2a [Quest API] Add Restore Methods for Health, Mana, and Endurance to Perl/Lua (#4179)
* [Quest API] Add Restore Methods for Health, Mana, and Endurance to Perl/Lua

- Add `$mob->RestoreEndurance()`.
- Add `$mob->RestoreHealth()`.
- Add `$mob->RestoreMana()`.

- Add `mob:RestoreEndurance()`.
- Add `mob:RestoreHealth()`.
- Add `mob:RestoreMana()`.

- Allows operators to easily restore a mob to full health, mana, or endurance.
- `RestoreHealth` is just a more verbosely named `Heal`.
- Convert spots in source to use these short hands instead of directly using `SetEndurance(GetMaxEndurance())`, `SetHP(GetMaxHP())`, or `SetMana(GetMaxMana())`.

* Update mob.h

* Update mob.h
2024-03-22 23:53:35 -05:00
hg 5bfd8f5da2 [Tradeskills] Implement learning recipes from books (#4170)
This uses the book scribe button to learn recipes in SoF+ clients. For
Titanium clients the button is not available so a workaround will need
to be added later.

Note live gives no feedback when scribing books (at least those tested).
2024-03-22 23:50:06 -05:00
Chris Miles 96830b4a19 [Loot] Fix issue with nested data being loaded multiple times (#4192)
* [Loot] Fix issue with nested data being loaded multiple times

* Update zone_loot.cpp

* Fix #lootsim printout

* Update loot.cpp
2024-03-22 23:49:23 -05:00
Alex King 4bf60a6522 [Bug Fix] Fix ScaleNPC() in Perl (#4196)
# Notes
- We were not passing `override_special_abilities` in the right parameter slot.
- Default `always_scale` to `true` when using the Perl/Lua method.
2024-03-22 23:36:30 -05:00
JJ 16cb7364e8 [Misc] Windows preprocessor define in crash.cpp (#4191) 2024-03-22 23:27:31 -05:00
Alex King f5050ab5dc [Bug Fix] Fix range_percent (#4197)
# Notes
- This was uninitialized and was getting bogus values.
2024-03-22 16:17:38 -04:00
Alex King e32cbf19ee [Bug Fix] Fix #serverrules Command (#4193)
* [Bug Fix] Fix #serverrules Command

# Notes
- This command was effectively disabled as it was not included nor was the command itself defined within a `command_add`

* Update command.cpp
2024-03-20 03:31:49 -04:00
Alex King ee12a7ad2e [Bug Fix] Fix EVENT_KILLED_MERIT firing before NPC removal (#4185)
* [Bug Fix] Fix EVENT_KILLED_MERIT firing before NPC removal

# Notes
- NPCs were parsing this event too early and anything that checked if they were still alive in `EVENT_KILLED_MERIT` would show them still alive because of this.

# Image

* Code cleanup

* Update client.h

* Add GetRaidOrGroupOrSelf() to Perl/Lua

* Update to luabind::object, fix logic per comments.

* Fix

* Fix per comments.
2024-03-17 17:32:44 -04:00
Alex King e5bdbc4f1e [Bug Fix] Fix Bot Cloning (#4186)
# Notes
- We were not setting `inventories_index` to `0` so it was trying to use the pre-existing unique identifier, causing the query to fail.
2024-03-16 23:09:57 -04:00
Alex King f829a99e6d [Quest API] Add RemoveAlternateCurrencyValue() to Perl/Lua (#4190)
# Perl
- Add `$client->RemoveAlternateCurrencyValue(currency_id, amount)`.

# Lua
- Add `client:RemoveAlternateCurrencyValue(currency_id, amount)`.

# Notes
- Allows operators to more easily remove alternate currencies, returns a `bool`, `false` if failed`, `true` if succeeded.
- Added `Zone::DoesAlternateCurrencyExist` that will reject setting, removing, or adding  to a currency that does not exist.
2024-03-16 23:09:51 -04:00
Alex King 82aa6a1587 [Bug Fix] Fix Proximity Say (#4189)
# Notes
- Without setting `HaveProximitySays` to `true` along with if `n->proximity->say` NPCs will not respond to proximity say stuff.
2024-03-14 20:26:30 -04:00
Alex King 161c13f457 [Quest API] Add Buff Support to Perl/Lua (#4182)
* [Quest API] Add Buff Support to Perl/Lua

- Add `$mob->GetCasterID()`.
- Add `$mob->GetCasterLevel()`.
- Add `$mob->GetCasterName()`.
- Add `$mob->GetCastOnX()`.
- Add `$mob->GetCastOnY()`.
- Add `$mob->GetCastOnZ()`.
- Add `$mob->GetCounters()`.
- Add `$mob->GetDOTRune()`.
- Add `$mob->GetExtraDIChance()`.
- Add `$mob->GetInstrumentModi()`.
- Add `$mob->GetMagicRune()`.
- Add `$mob->GetMeleeRune()`.
- Add `$mob->GetNumberOfHits()`.
- Add `$mob->GetRootBreakChanc()`.
- Add `$mob->GetSpellID()`.
- Add `$mob->GetTicsRemaining()`.
- Add `$mob->GetVirusSpreadTim()`.
- Add `$mob->IsCasterClient()`.
- Add `$mob->IsPersistentBuff()`.
- Add `$mob->SendsClientUpdate()`.

- Add `mob:GetCasterID()`.
- Add `mob:GetCasterLevel()`.
- Add `mob:GetCasterName()`.
- Add `mob:GetCastOnX()`.
- Add `mob:GetCastOnY()`.
- Add `mob:GetCastOnZ()`.
- Add `mob:GetCounters()`.
- Add `mob:GetDOTRune()`.
- Add `mob:GetExtraDIChance()`.
- Add `mob:GetInstrumentModi()`.
- Add `mob:GetMagicRune()`.
- Add `mob:GetMeleeRune()`.
- Add `mob:GetNumberOfHits()`.
- Add `mob:GetRootBreakChanc()`.
- Add `mob:GetSpellID()`.
- Add `mob:GetTicsRemaining()`.
- Add `mob:GetVirusSpreadTim()`.
- Add `mob:IsCasterClient()`.
- Add `mob:IsPersistentBuff()`.
- Add `mob:SendsClientUpdate()`.

- Adds support for `Buffs_Struct` to Perl/Lua.
- Allows operators to read a mob's buff data directly to determine caster, melee rune, etc.

* Fix GetCasterID() to proper data type.

* Remove Lua_Buffs, return table instead.

* Cleanup
2024-03-13 23:38:15 -04:00
Alex King b29c26becb [Bug Fix] Fix GetLeaderName() for Groups (#4184)
* [Bug Fix] Fix GetLeaderName() for Groups

# Notes
- We were getting bogus data in this.
- Made it its own method.

* Remove ExpeditionRequest::GetGroupLeaderName()
2024-03-13 21:52:02 -04:00
Alex King e48dae2392 [Quest API] Add Silent Saylink Methods to Perl/Lua (#4177)
# Perl
- Add `quest::silent_saylink(text)`.
- Add `quest::silent_saylink(text, link_name)`.

# Lua
- Add `eq.silent_say_link(text)`.
- Add `eq.silent_say_link(text, link_name)`.

# Notes
- Allows operators to more easily use silent saylinks without an optional silent parameter in the traditional saylink methods.
- Sets `silent` parameter default to `false` so we do not need to pass `false` when we are not using a a silent saylink.
- Changes all places that used `EQ::SayLinkEngine::GenerateQuestSaylink` to `Saylink::Create` where possible.
- Removed `questmgr` method that is no longer necessary.
- Cleaned up Lua methods to use the strings directly instead of building one out.
2024-03-13 20:27:44 -04:00
Alex King 4b83a96f64 [Bug Fix] Fix Empty Groups When Removing Bots (#4178)
# Notes
- We were checking for the incorrect value, meaning you could end up in an empty group.
2024-03-13 20:27:38 -04:00
Alex King 95cc22ffbb [Quest API] Add GetDeityName() to Perl/Lua (#4180)
# Perl
- Add `$mob->GetDeityName()`.

# Lua
- Add `mob:GetDeityName()`.

# Notes
- Allows operators to get a mob's deity name.
2024-03-13 20:27:31 -04:00
nytmyr 6ca11256c6 [Bots] IsValidTarget Crash Fix (#4187)
* [Bots] IsValidTarget crash fix

This addresses crashes related to IsValidTarget on multiple servers.

Unsure of the exact reason if anyone can explain why changing from const bool to bool in this situation fixes the problem.

Is it because the const is somehow crashing on a bad pointer or is it attempting to be force changed?

* Update bot.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2024-03-12 12:34:27 -04:00
Alex King d94493468c [Bug Fix] Fix Mob::CalculateDistance(mob) Typo (#4183)
# Notes
- Was using `GetX()` for all parts of the calculation, meaning it would produce incorrect values.
- Part of [this](https://github.com/EQEmu/Server/pull/3455/files#diff-94a8e3b04f001e4f74ce2da8404cbce7653146d963a3b93be6536505035ce96dR602-R607).
2024-03-09 22:20:02 -05:00
Alex King 957b4f8821 [Bug Fix] Fix Crash in ClientList::GetCLEIP (#4173)
* [Bug Fix] Fix Crash in ClientList::GetCLEIP

# Notes
- We were not validating pointer when moving to next iterator.

# Crashes
https://spire.akkadius.com/dev/release/22.46.1?id=19955
https://spire.akkadius.com/dev/release/22.46.1?id=19948
https://spire.akkadius.com/dev/release/22.46.0?id=19945

* Update clientlist.cpp

* Update clientlist.cpp
2024-03-09 19:47:58 -05:00
Alex King 5013459824 [Hot Fix] Add bool return to fix Client::RemoveAAPoints (#4176)
# Notes
- Was missing the `return true;` at the bottom.
2024-03-09 10:07:13 -05:00
Alex King 94af2843e3 [Cleanup] Cleanup Zone Get Methods (#4169)
# Notes
- Utilize `GetZoneVersionWithFallback` to shorten methods and reduce duplicate code.
2024-03-08 21:22:11 -05:00
Alex King 3bfb148bdc [Quest API] Add RemoveAAPoints() and AA Loss Event to Perl/Lua (#4174)
* [Quest API] Add RemoveAAPoints() and AA Loss Event to Perl/Lua

# Perl
- Add `$client->RemoveAAPoints(points)`.
- Add `EVENT_AA_LOSS`, exports `$aa_lost`.

# Lua
- Add `client:RemoveAAPoints(points)`.
- Add `event_aa_loss`, exports `e.aa_lost`.

# Notes
- Allows operators to more easily remove AA Points.
- Has a bool return type that will return false if the player does not have enough AA Points to complete the removal.

* Update client.cpp
2024-03-08 21:20:33 -05:00
MortimerGreenwald 96370e0298 [Bug Fix] An Update to Xtarget to exclude Bot owned Temp/Swarm Pets (#4172)
* An Update to Xtarget to exclude Bot owned Temp/Swarm Pets

* Missing a parentheses

* Cleaned up logic.
2024-03-08 15:29:53 -05:00
nytmyr fef5108b0d [Bots] Move BotGroupSay to Pet Response (#4171)
* [Bots] Move BotGroupSay messages to PetResponse filter to reduce spam

* Cleanup raid checks

* Group cleanup
2024-03-08 11:46:50 -05:00
Alex King 6f883566f6 [Bug Fix] Fix Default Value in rule_values table (#4166)
# Notes
- Some versions of SQL do not allow a default value for text fields.
2024-03-07 16:41:41 -05:00
nytmyr 45b1501c8a [Quest API] Add DeleteBot() to Perl/Lua (#4167)
### Perl
- Add $bot->DeleteBot().
```
sub EVENT_SAY {
	if ($text =~/#deletebot/i && $client->Admin() >= 100) {
		my @bot_list = $entity_list->GetBotList();

		foreach $ent (@bot_list) {
			if ($ent) {
				quest::shout("Deleting " . $ent->GetCleanName());
				$ent->DeleteBot();
				$ent->Camp(0);
			}
		}
	}
}
```
### Lua
- Add bot:DeleteBot().
```
function event_say(e)
	if(e.message:findi("#deletebot")) then
		local bot_list = eq.get_entity_list():GetBotList();

		for ent in bot_list.entries do
			if (ent) then
				e.self:Message(7,"Deleting " .. ent:GetCleanName() .. "");
				ent:DeleteBot();
				ent:Camp(false);
			end
		end
	end
end
```
### Notes
- Allows operators to delete bots.
2024-03-07 06:08:17 -05:00
Akkadius 7e94f0ac72 [Release] 22.47.0 2024-03-05 22:18:16 -06:00
Chris Miles 2aa19f4cae [Release] 22.47.0 (#4164) 2024-03-05 22:04:35 -06:00
Mitch Freeman 805829f15d [Crash Fix] Added a guild_mgr check (#4163)
* CrashFix and Cleanup

* Formatting, add safe_delete

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2024-03-05 22:00:08 -06:00
Alex King 2c2a8cdb63 [Bug Fix] Fix Character EXP Modifiers default (#4161)
# Notes
- The `-1.0f` was causing these modifiers to be set to `0.0` and when people would enable them they would get no experience.
- We now use the zone based grabbed methods when setting which will default to a value of `1.0f` if there is not a value found.
2024-03-05 21:54:07 -06:00
Chris Miles ee3d02bac6 [Zoning] Zone routing adjustment (#4162) 2024-03-05 21:53:07 -06:00
Alex King b90139bd9a [Feature] Adjust String-based Rules Length (#4138) 2024-03-05 21:52:34 -06:00
catapultam-habeo e6a3d5e1c5 [Bug Fix] Prevent NPE when creating DZ using ad-hoc version IDs (#4141)
* initial commit

* corrected based on hgtw feedback
2024-03-05 18:21:04 -05:00
Alex King 74f1eac401 [Bug Fix] Fix Spawns Not Parsing Quest on Zone Bootup (#4149)
* Update zone.cpp

* Fix

---------

Co-authored-by: Natedog2012 <jwalters_06@yahoo.com>
2024-03-05 18:20:42 -05:00
JJ 1be9b2cdfd [Bug Fix] Fix typo when updating spawn events in spawn condition manager (#4160) 2024-03-05 05:44:38 -05:00
Mitch Freeman add0a8dddf [Bug Fix] Add id to the guild_bank table (#4155)
* Add id to guild_bank table

Add id as a primary key to guild_bank

* Remove content schema update flag
2024-03-04 19:02:35 -05:00
catapultam-habeo 8c226054e7 [Feature] Adds rules to control level requirements for Double Backstab, Assassinate, and Double Bowshot (#29) (#4159)
Co-authored-by: mute <natanx@gmail.com>
2024-03-04 18:41:25 -05:00
Mitch Freeman b4605f77e3 [Crash Fix] Goto Command could crash using Developer Tools (#4158) 2024-03-03 22:33:12 -05:00
Mitch Freeman 74a63daf7e [Crash Fix] Groundspawn Memory Corruption (#4157) 2024-03-03 22:32:29 -05:00
Alex King 8ee7910569 [Quest API] Add IsAlwaysAggro() to Perl/Lua (#4152)
- Add `$mob->IsAlwaysAggro()`.

- Add `mob:IsAlwaysAggro()`.

- Allows operators to determine if a mob is set to always aggro.
2024-03-03 20:40:20 -05:00
Alex King b766a79c11 [Quest API] Add GetHeroicStrikethrough() to Perl/Lua (#4150)
- Add `$mob->GetHeroicStrikethrough()`.

- Add `mob:GetHeroicStrikethrough()`.

- Allows operators to get a mob's Heroic Strikethrough.
2024-03-03 13:05:01 -05:00
Alex King 5e3b6d363a [Quest API] Add IsBoat()/IsControllableBoat() to Perl/Lua (#4151)
- Add `$mob->IsBoat()`.
- Add `$mob->IsControllableBoat()`.

- Add `mob:IsBoat()`.
- Add `mob:IsControllableBoat()`.

- Allows operators to determine if a mob is a boat or a controllable boat.
2024-03-03 12:34:21 -05:00
Alex King b2fc59878a [Quest API] Add IsDestructibleObject() to Perl/Lua (#4153)
# Perl
- Add `$mob-.IsDestructibleObject()`.

# Lua
- Add `mob:IsDestructibleObject()`.

# Notes
- Allows operators to determine if a mob is a destructible object.
2024-03-03 11:43:54 -05:00
JJ 4896688ac5 [Release] 22.46.1 (#4148)
### Fixes

* Change `UnburyCorpse` to use repository methods ([#4147](https://github.com/EQEmu/Server/pull/4147)) @joligario 2024-03-03
2024-03-02 19:56:29 -05:00
JJ 0385ed8526 [Bug Fix] Change UnburyCorpse to use repository methods (#4147) 2024-03-02 19:23:43 -05:00
Chris Miles 9974aaff57 [Release] 22.46.0 (#4146) 2024-03-02 15:21:32 -06:00
Chris Miles b6c3e549da [Zone] Zone Routing Improvements (#4142)
* Routing changes

* Update world_content_service.cpp

* Cleanup routing logic

* Tweaks
2024-03-02 15:19:42 -06:00
Alex King 70ee95efc0 [Quest API] Add Bot Special Attacks for Immune Aggro/Damage (#4108)
* [Quest API] Add Bot Special Attacks for Immune Aggro/Damage

# Notes
- Adds `IMMUNE_AGGRO_BOT` and `IMMUNE_DAMAGE_BOT` for uses in special abilities.

* Cleanup

* Update attack.cpp
2024-03-02 15:19:31 -06:00
Alex King 1d38e473d7 [Bug Fix] GetBotNameByID Temporary Reference Warning (#4145)
# Notes
- We were getting a warning for returning `std::string()` from this method as it's a temporary reference.
- Change from `const std::string&` to `const std::string` to avoid this.
```
/home/eqemu/source/zone/bot_database.cpp: In member function ‘const std::string& BotDatabase::GetBotNameByID(uint32)’:
/home/eqemu/source/zone/bot_database.cpp:2374:25: warning: returning reference to temporary [-Wreturn-local-addr]
 2374 |         return e.bot_id ? e.name : std::string();
```
2024-03-02 15:18:57 -06:00
Alex King 1aa3a4b11a [Bug Fix] Fix Bots/Bot Pets ending up on XTargets (#4132)
* [XTargets]

* Update eqemu_logsys.h

* Update client.cpp

* Update table column

* Undo unnecessary commit
2024-03-02 15:18:37 -06:00
Mitch Freeman 398ecbc8cf [Bug Fix] Update FreeGuildID Routine (#4143)
Updates the routine to determine a free guild id on guild creation
2024-03-02 15:17:28 -06:00
Mitch Freeman c4613e1b0f [Crash Fix] Update to location of qGlobals initialization (#4144) 2024-03-02 15:16:51 -06:00
catapultam-habeo 3003a59955 [Feature] Exempt a zone from IP-limit checks. (#4137)
* Exempt zone from IP checks

* [Feature] Add Support for String-based Rules

# Notes
- Add support for string-based rules.

# Images

* convert to comma-seperated list

* Forgot to convert the zone to a string

* Update lua_general.cpp

* fixed rule name

* use the local string methods instead

* I think this will work as desired without the extra condition

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2024-03-01 23:11:34 -05:00
Paul Coene 0c582cc4f9 [Bug Fix] Cleanup NPC Mana Tap Logic (#4134)
* [Bug Fix] Cleanup NPC Mana Tap Logic

Mana Tap rule logic was invalid - Cleaned up and simplified, either we care about npc mana or we dont.

* Updated for bypass all rule

* Change so melee targets get blocked even with requiremana rule off

---------

Co-authored-by: Trust <fryguy503@gmail.com>
2024-03-01 22:48:50 -05:00
Mitch Freeman 69c42510ca [Crash Fix] Raid::UpdateGroupAAs (#4139)
Added checks to potentially resolve a crash situation with raids and group AAs.
2024-03-01 22:46:16 -05:00
JJ 79c8858ec8 [Bug Fix] Use std::clamp for Mob::ChangeSize (#4140)
Helper template was not deducing float for lower/upper values allowing invalid sizes
Limit to sane values of 1-255 unrestricted and 3-15 for clients and pets
2024-03-01 22:46:00 -05:00
Alex King c3d8d423fe [Commands] Add #fish Command (#4136)
* [Commands] Add #fish Command

# Notes
- Adds `#fish` command.
- Allows operators to simulate fishing to see what they would get, consumes no bait.

* `use_bait`

* Update fish.cpp
2024-02-29 21:24:16 -05:00
Alex King 1cbda61891 [Bug Fix] Fix issue with NPC Secondary Textures (#4129)
* [Bug Fix] Fix issue with NPC heads

# Notes
- We were overwriting head material within this secondary loop which caused NPC's heads to show their body texture in some places or no texture if their `showhelm` was not flagged.

# Images

* Update mob.cpp

* Update mob.cpp

* Update mob.cpp
2024-02-29 20:45:54 -05:00
JJ 8d12a5b1b1 [Release] 22.45.1 (#4135)
### Character Creation

* Improved Random Name Generator ([#4081](https://github.com/EQEmu/Server/pull/4081)) @catapultam-habeo 2024-02-27

### Code

* Fix Server Rules Documentation Generation ([#4125](https://github.com/EQEmu/Server/pull/4125)) @Kinglykrab 2024-02-26
* Remove unnecessary stoptimer logs ([#4128](https://github.com/EQEmu/Server/pull/4128)) @Kinglykrab 2024-02-28

### Commands

* Add `#forage` command ([#4133](https://github.com/EQEmu/Server/pull/4133)) @joligario 2024-02-29

### Crash

* Fix crash issue during database dump ([#4127](https://github.com/EQEmu/Server/pull/4127)) @Akkadius 2024-02-29

### Crash Fix

* D20 crash if mitigation average resulted in 0 ([#4131](https://github.com/EQEmu/Server/pull/4131)) @nytmyr 2024-02-29

### Fixes

* Fix forage returning first result from table ([#4130](https://github.com/EQEmu/Server/pull/4130)) @nytmyr 2024-02-29
* Who /all displays incorrect guild name ([#4123](https://github.com/EQEmu/Server/pull/4123)) @neckkola 2024-02-25

### Quest API

* Add Pet Owner Methods to Perl/Lua ([#4115](https://github.com/EQEmu/Server/pull/4115)) @Kinglykrab 2024-02-25
2024-02-29 18:22:40 -05:00
JJ 182327b385 [Commands] Add #forage command (#4133) 2024-02-28 20:43:14 -05:00
Chris Miles aa0ca88d9d [Crash] Fix crash issue during database dump (#4127) 2024-02-28 20:36:06 -05:00
nytmyr 103a37e762 [Crash Fix] D20 crash if mitigation average resulted in 0 (#4131) 2024-02-28 20:35:56 -05:00
nytmyr 34f19489d0 [Hotfix] Fix forage returning first result from table (#4130)
Forage was not properly incrementing the total chance of items when more than one was found and would result in the final chance roll being based off the last item found rather than the total. This would cause the first item returned to be chosen in most cases when the chances are the same in the table.
2024-02-28 20:34:40 -05:00
Alex King c001060429 [Cleanup] Remove unnecessary stoptimer logs (#4128)
# Notes
- These logs were for testing and are unnecessary.
- They cause a lot of spam for servers using `Info` logs.
2024-02-27 21:35:51 -05:00
catapultam-habeo 89be55254e [Character Creation] Improved Random Name Generator (#4081)
* test against vanilla branch

* use existing methods to validate name instead of raw sql

* Revert "use existing methods to validate name instead of raw sql"

This reverts commit 43750c6f4f.

* ReserveName doesn't work like that. Oops. Well, check against Name Filter at least.

* That db access condition was wrong.

* that isn't how CheckNameFilter works, either.

* apply editorconfig w/ trivial change

* Actually apply editorconfig changes.
2024-02-26 23:15:40 -06:00
Alex King 2da6190950 [Cleanup] Fix Server Rules Documentation Generation (#4125)
# Notes
- These spaces prevented the docs server rules generator from parsing these rules.
2024-02-26 18:36:12 -05:00
Mitch Freeman d5e024cc02 [Bug Fix] Who /all displays incorrect guild name (#4123)
Issue: guild creation routine does not update world memory holding guild details until the player zones.

Between the creation of a new guild, and a guild member zones, a /who all displays 'Invalid Guild' instead of the actual guild name.
2024-02-25 18:14:28 -05:00
Alex King 35fe38cd09 [Quest API] Add Pet Owner Methods to Perl/Lua (#4115)
* [Quest API] Add Pet Owner Methods to Perl/Lua

- Add `$mob->IsPetOwnerBot()`.
- Add `$mob->IsPetOwnerClient()`.
- Add `$mob->IsPetOwnerNPC()`.

- Add `mob:IsPetOwnerBot()`.
- Add `mob:IsPetOwnerClient()`.
- Add `mob:IsPetOwnerNPC()`.

- Allows operators to use these short hands instead of doing a `GetOwner() && GetOwner()->IsClient()`.

* Update npc.cpp
2024-02-25 00:38:34 -05:00
Chris Miles eb3664a444 [Release] 22.45.0 (#4121) 2024-02-24 23:06:37 -06:00
Alex King a244509d63 [Quest API] Export Combat Record to Death Events (#4112)
# Perl
- Add `$combat_start_time`, `$combat_end_time`, `$damage_received`, and `$healing_received` to death events for NPCs.

# Lua
- Add `e.combat_start_time`, `e.combat_end_time`, `e.damage_received`, and `e.healing_received` to death events for NPCs.

# Notes
- Allows operators to hook in to the combat record logic so they can log the start and end of combat as well as the damage/healing received over the course of the fight.
2024-02-24 22:57:49 -06:00
Alex King 873c128f46 [Bug Fix] Fix Bot Weapons with No Races (#4110)
# Notes
- Bot weapons that have no races were not causing damage and saying the target was invulnerable because we were not checking the `Bots:AllowBotEquipAnyRaceGear` rule.
2024-02-24 22:55:40 -06:00
Alex King 8314f2348c [Quest API] Add Bot Methods to Perl/Lua (#4113)
* [Quest API] Add Bot Methods to Perl/Lua

# Perl
- Add `quest::GetBotClassByID(bot_id)`.
- Add `quest::GetBotGenderByID(bot_id)`.
- Add `quest::GetBotIDsByCharacterID(character_id)`.
- Add `quest::GetBotIDsByCharacterID(character_id, class_id)`.
- Add `quest::GetBotLevelByID(bot_id)`.
- Add `quest::GetBotNameByID(bot_id)`.
- Add `quest::GetBotRaceByID(bot_id)`.

# Lua
- Add `eq.get_bot_class_by_id(bot_id)`.
- Add `eq.get_bot_gender_by_id(bot_id)`.
- Add `eq.get_bot_ids_by_character_id(character_id)`.
- Add `eq.get_bot_ids_by_character_id(character_id, class_id)`.
- Add `eq.get_bot_level_by_id(bot_id)`.
- Add `eq.get_bot_name_by_id(bot_id)`.
- Add `eq.get_bot_race_by_id(bot_id)`.

# Notes
- Allows operators to get a list of a player's bot IDs, get a bot's class, gender, level, name, and race.

* Update bot_database.cpp
2024-02-24 22:53:21 -06:00
Alex King 29720f95ed [Quest API] Add GetAugmentIDs() to Perl/Lua (#4114)
# Perl
- Add `$questitem->GetAugmentIDs()`.

# Lua
- Add `iteminst:GetAugmentIDs()`.

# Notes
- Allows operators to get a list of augment IDs from an item instance directly without using the inventory method.
2024-02-24 22:52:07 -06:00
Alex King a478fd2600 [Quest API] Add GetNPCSpellsEffectsID() to Perl/Lua (#4117)
# Perl
- Add `$npc->GetNPCSpellsEffectsID()`.

# Lua
- Add `npc:GetNPCSpellsEffectsID()`.

# Notes
- Allows operator's to get an NPC's spell effects ID.
2024-02-24 22:51:37 -06:00
Alex King f57c37e9c5 [Quest API] Add Pet Methods to Perl/Lua (#4116)
* [Quest API] Add Pet Methods to Perl/Lua

# Perl
- Add `$mob->IsAnimation()`.
- Add `$mob->IsCharmed()`.
- Add `$mob->IsFamiliar()`.
- Add `$mob->IsTargetLockPet()`.

# Lua
- Add `mob:IsAnimation()`.
- Add `mob:IsCharmed()`.
- Add `mob:IsFamiliar()`.
- Add `mob:IsTargetLockPet()`.

# Notes
- These methods were not exported and could be useful for operators.

* Update perl_mob.cpp
2024-02-24 22:51:21 -06:00
Mitch Freeman b9fb4babba [Guilds] Fixes for Guild Bank (#4120)
Updates guild bank functionality
- Allows QTY 100 in guild bank
- Removes bug when deposit area is full and a UF or RoF2 client attempts to deposit another item
- Attempt to deposit a nodrop item in RoF2 creates a dupe situation
2024-02-24 22:50:14 -06:00
Mitch Freeman c2e4082045 [Bug Fix] Crash on Ubuntu 22.04 (#4119)
Ubuntu 22.04 as of Feb 25 2024 was crashing when sending guild tributes on zone in.  Issue was caused by an overrun on string copies.
Updated to use strn0cpy, crash was resolved.
2024-02-24 22:46:42 -06:00
Paul Coene e1dee55ecd [Beacon] Revert a few lines of PR #4024 that broke beacons (#4118) 2024-02-24 16:18:17 -05:00
JJ 1632ff04b0 [Repositories] Update zone base repository from #4084 (#4111) 2024-02-22 21:39:31 -05:00
Fryguy 873209dbc0 [Bug Fix] Fix hotzone string error (#4109)
The Strings entry was from a newer client. Moved text to a raw message.
2024-02-22 17:15:22 -05:00
Mitch Freeman a00b2eb382 [Bug Fix] Added additional Guild-related crash checks (#4105) 2024-02-21 19:44:05 -05:00
Alex King 67d8250b1c [Quest API] Add Hatelist Count Methods to Perl/Lua (#4106)
# Perl
- Add `$mob->GetHateListCount()`.# Perl
- Add `$mob->GetHateListCount()`.
- Add `$mob->GetHateListBotCount()`.
- Add `$mob->GetHateListClientCount()`.
- Add `$mob->GetHateListNPCCount()`.

# Lua
- Add `mob:GetHateListCount()`.
- Add `mob:GetHateListBotCount()`.
- Add `mob:GetHateListClientCount()`.
- Add `mob:GetHateListNPCCount()`.

# Notes
- Allows operators to more easily get a total entity count of a Mob's hate list, can do an overall count, or specifically bots, clients, or NPCs.
2024-02-20 22:39:57 -06:00
Alex King f505c2cfd2 [Feature] Add Augments to Starting Items for Bots/Players (#4100)
* [Feature] Add Augments to Starting Items for Bots/Players

- Adds support for augments to `bot_starting_items` and `starting_items`.
- Will allow operators to kit bots/players out with augmented gear from the start if they so choose.

* Update database_update_manifest.cpp

* Update client.cpp
2024-02-20 22:23:22 -06:00
Fryguy a221e50cc2 [Bug Fix] Add safety check to SummonAllCharacterCorpses. (#4107)
Should prevent an empty vector from being passed to the repository.
2024-02-20 22:21:56 -06:00
JJ 32c5d4d9f6 [Database] Add content_database flag for zone changes (#4104) 2024-02-20 18:03:12 -05:00
Paul Coene ce4716e9a5 [Factions] Fix issue with npcedit and cached factions (#4103)
* [Factions] Fix issue with npcedit and cached factions

* Load no matter what
2024-02-20 17:47:44 -05:00
JJ a99ce4fbdb [Bug Fix] Revert 2df7d19 (#4101)
* [Bug Fix] Revert https://github.com/EQEmu/Server/commit/2df7d19f975cb21dd4eb7d6c7d40656cf58ed138
This change breaks lich-type spells as seen in #4098. Per comment on original change, also don't see where Runes come into play.

* Revert invis change

* [Bug Fix] Correct Rune damage check location for invis break.

Correct the location of the CommonBreakInvis for runes. Appologize for the incorrect location. Thank you JJ for pointing me to the PR that caused the issue.

---------

Co-authored-by: Trust <fryguy503@gmail.com>
2024-02-19 22:35:32 -06:00
JJ dcfc54d408 [Logs] Fix log in BaseGuildManager::IsGuildLeader() (#4102)
Looks like typos created invalid escapes
2024-02-19 22:34:52 -06:00
Alex King c13ec5a06d [Repositories] Cleanup and Convert Character Creation to Repositories (#4053)
* [Repositories] Cleanup and Convert Character Creation to Repositories

# Notes
- Converts `Database::GetCharacterID()`, `Database::SaveCharacterCreate()`, and `Client::OPCharCreate` to repositories.
- Cleanup a spot we were doing a queries in a loop.

* Cleanup

* Update database.cpp

* Update database.cpp
2024-02-19 20:45:18 -06:00
Chris Miles d182fc3613 [Expansions] Zone Expansion Version Routing (#4084)
* Expansion version routing

* CheckForImproperContentFiles rule

* Update world_content_service.cpp

* Update client.cpp

* Update client.cpp

* Update CheckForImproperContentFiles

* Remove nek pok check

* Remove file checking

* Remove

* Command and dev tools menu tweaks

* Update world_content_service.cpp

* Update world_content_service.cpp

* Update version path

* Update content_filter_criteria.h

* Update content_filter_criteria.h

* Update quest_parser_collection.cpp

* Update comments

* PR feedback

* Update client_packet.cpp

* Remove notes column for display cleanliness
2024-02-19 20:35:17 -06:00
Alex King 5a89fcfb78 [Quest API] Add Entity Variable Events to Perl/Lua (#4092)
* [Quest API] Add Entity Variable Events to Perl/Lua

- Add `EVENT_ENTITY_VARIABLE_DELETE`.
- Add `EVENT_ENTITY_VARIABLE_SET`.
- Add `EVENT_ENTITY_VARIABLE_UPDATE`.
- All export `$variable_name` and `$variable_value`.

- Add `event_entity_variable_delete`.
- Add `event_entity_variable_set`.
- Add `event_entity_variable_update`.
- All export `e.variable_name` and `e.variable_value`.

- Allows operators to perform operations when entity variables are cleared, deleted, set, or updated.

* Update mob.cpp

* Cleanup.

* Cleanup

* Update mob.cpp

* Update lua_general.cpp

* Update embparser_api.cpp
2024-02-19 20:34:33 -06:00
Alex King db3601c25c [Quest API] Add Timer Events to Perl/Lua (#4099)
* [Quest API] Add Timer Events to Perl/Lua

# DRAFT

* Cleanup
2024-02-19 03:51:16 -06:00
Alex King 137a9f835a [Quest API] Add spell cast methods to Lua (#4096)
# Notes
- Add `eq.cast_spell(spell_id)` and `eq.self_cast(spell_id)` to Lua.
- Lua did not have a `quest::castspell(spell_id)` or `quest::selfcast(spell_id)` equivalent, so this adds them.
2024-02-19 02:35:30 -06:00
Alex King 4ad46b54df [Bug Fix] Fix Sympathetic Procs for Bots/Mercenariess (#4086)
# Notes
- Bots and Mercenaries were being rejected at the top of this method despite us allowing them to use this method where it's called.
2024-02-19 02:21:47 -06:00
Alex King 3f46210639 [Bots] Cleanup empty bot_commands files (#4095)
* [Bots] Cleanup empty `bot_commands` files

# Notes
- These files were part of the conversion of bot commands to individual files, these commands are part of overarching commands and therefore do not have their own files.
- These were not removed when initially committed.

* Update bot_command.cpp

* Update bot_command.cpp
2024-02-19 02:19:56 -06:00
Alex King 6ec63969bb [Bug Fix] Fix issue with IsEntOnHateList (#4097)
# Notes
- We were not validating pointer in `IsEntOnHateList()`.
2024-02-19 01:52:19 -06:00
JJ 767846f7e5 [Bug Fix] Aura effect spell id from #3964 (#4094)
Auras were trying to cast another aura spell vice the spell effect
2024-02-18 17:13:32 -05:00
Fryguy 04bb9bf39c [Feature] Hot Zone Bonus XP Notice (#4091)
When in Hotzones, a bonus XP notice will let players know the hotzone is enabled.
2024-02-18 11:24:01 -05:00
Mitch Freeman e6df5be1ed [Bug Fix] Update database_schema to add guild_permissions (#4085)
* Update database_schema to add guild_permissions

* Reordered
2024-02-16 18:09:18 -05:00
hg 6bb2f97b74 [Code] Update fmt to 10.2.1 (#4071)
This fixes MSVC compile warnings for stdext::checked_array_iterator
which were deprecated in STL for VS 2022 17.8:

https://github.com/microsoft/STL/wiki/Changelog#vs-2022-178
2024-02-16 00:29:04 -06:00
hg 86f39743fc [Quest API] Add tracebacks to Lua error messages (#4079)
This adds an error msg handler for lua calls to add a stack trace to
error messages. Lua 5.1 does not have luaL_traceback like luajit and lua
5.2+ so debug.traceback() is used directly as the msg handler.

The traceback will add more detail to errors than just logging package
and event names. Exceptions in C++ binds and luabind errors will now
show script context instead of just the error message.

e.g., for a luabind overload error:

  No matching overload found, candidates:
  void signal(int,int,int)
  void signal(int,int)
  stack traceback:
    [C]: in function 'signal'
    quests/arena/player.lua:10: in function 'somefn'
    quests/arena/player.lua:27: in function <quests/arena/player.lua:17>
2024-02-16 00:27:37 -06:00
Alex King 447fc026a8 [Repositories] Convert Zone Flags to Repositories (#4077)
# Notes
- Converts `ClearZoneFlag()`, `LoadZoneFlags()`, and `SetZoneFlag()` to repositories.
2024-02-16 00:27:08 -06:00
Chris Miles 7408df933c [Database] Remove "item_tick" from database schema per https://github.com/EQEmu/Server/pull/3985 (#4083) 2024-02-16 00:23:23 -06:00
JJ 2f59e70c6b [Bug Fix] Fix manifest check on base_data change (#4082) 2024-02-15 19:04:26 -05:00
Alex King eb8514eea8 [Bug Fix] Fix fix_z Query (#4080)
# Notes
- This query was not working properly due to using backticks instead of single quotes.
2024-02-15 11:51:07 -05:00
Alex King f498bac574 [Bug Fix] Fix ObjectContentsRepository using content_db (#4076)
# Notes
- `*this` was using content database, causing this not to work on servers using sharded databases.
2024-02-14 18:34:43 -05:00
Alex King 9a0b3a4c36 [Bug Fix] Fix #wpadd Query (#4078)
# Notes
- `GetNextWaypoint()` was getting a null value and crashing in `Strings::ToInt()`.
2024-02-14 18:28:31 -05:00
Chris Miles 34ea870717 [Opcodes] Fix opcode reloading (#4075) 2024-02-13 19:40:23 -05:00
Alex King d68c1a7a6c [Quest API] Add IsInAGuild() to Perl/Lua (#4066)
# Perl
- Add `$client->IsInAGuild()`.

# Lua
- Add `client:IsInAGuild()`.

# Notes
- Allows operators to more accurately tell if a player is in a group.
- `GuildID()` returns `uint32` max value if the player isn't in a guild so conditions using it must check for a value over a certain point, this is just a bool that simplifies that logic.
2024-02-13 19:27:43 -05:00
Akkadius c50100fcdb [Hotfix] Fix issues where we're using the wrong database pointers 2024-02-12 21:41:52 -06:00
JJ 20cdc1e63d [Release] 22.44.4 (#4074)
### Fixes

* Fix ClearSpawnTimers() ([#4073](https://github.com/EQEmu/Server/pull/4073)) @Kinglykrab 2024-02-13
2024-02-12 20:34:40 -06:00
Alex King 43c7523ee1 [Hotfix] Fix ClearSpawnTimers() (#4073)
# Notes
- This wasn't a part of my other pull request.
- We were clearing `spawn2_list` before using it in `ClearSpawnTimers()`.
2024-02-12 21:12:30 -05:00
JJ e060d97798 [Release] 22.44.3 (#4072)
### Fixes

* Fix Issue with ClearSpawnTimers() ([#4070](https://github.com/EQEmu/Server/pull/4070)) @Kinglykrab 2024-02-13
2024-02-12 19:20:04 -06:00
Alex King 435b6142b8 [Bug Fix] Fix Issue with ClearSpawnTimers() (#4070)
# Notes
- We were using the improper ID for this and not checking if the vector was empty before using.
2024-02-12 20:00:45 -05:00
157 changed files with 6246 additions and 3059 deletions
+272
View File
@@ -1,3 +1,275 @@
## [22.48.0] 3/23/2024
### Bots
* IsValidTarget Crash Fix ([#4187](https://github.com/EQEmu/Server/pull/4187)) @nytmyr 2024-03-12
* Move BotGroupSay to Pet Response ([#4171](https://github.com/EQEmu/Server/pull/4171)) @nytmyr 2024-03-08
### Code
* Cleanup Zone Get Methods ([#4169](https://github.com/EQEmu/Server/pull/4169)) @Kinglykrab 2024-03-09
### Fixes
* An Update to Xtarget to exclude Bot owned Temp/Swarm Pets ([#4172](https://github.com/EQEmu/Server/pull/4172)) @MortimerGreenwald 2024-03-08
* Fix #serverrules Command ([#4193](https://github.com/EQEmu/Server/pull/4193)) @Kinglykrab 2024-03-20
* Fix Bot Cloning ([#4186](https://github.com/EQEmu/Server/pull/4186)) @Kinglykrab 2024-03-17
* Fix Crash in ClientList::GetCLEIP ([#4173](https://github.com/EQEmu/Server/pull/4173)) @Kinglykrab 2024-03-10
* Fix Default Value in `rule_values` table ([#4166](https://github.com/EQEmu/Server/pull/4166)) @Kinglykrab 2024-03-07
* Fix EVENT_KILLED_MERIT firing before NPC removal ([#4185](https://github.com/EQEmu/Server/pull/4185)) @Kinglykrab 2024-03-17
* Fix Empty Groups When Removing Bots ([#4178](https://github.com/EQEmu/Server/pull/4178)) @Kinglykrab 2024-03-14
* Fix GetLeaderName() for Groups ([#4184](https://github.com/EQEmu/Server/pull/4184)) @Kinglykrab 2024-03-14
* Fix Mob::CalculateDistance(mob) Typo ([#4183](https://github.com/EQEmu/Server/pull/4183)) @Kinglykrab 2024-03-10
* Fix Proximity Say ([#4189](https://github.com/EQEmu/Server/pull/4189)) @Kinglykrab 2024-03-15
* Fix ScaleNPC() in Perl ([#4196](https://github.com/EQEmu/Server/pull/4196)) @Kinglykrab 2024-03-23
* Fix range_percent ([#4197](https://github.com/EQEmu/Server/pull/4197)) @Kinglykrab 2024-03-22
* Fix reusing timers ([#4199](https://github.com/EQEmu/Server/pull/4199)) @joligario 2024-03-23
### Hot Fix
* Add bool return to fix Client::RemoveAAPoints ([#4176](https://github.com/EQEmu/Server/pull/4176)) @Kinglykrab 2024-03-09
### Loot
* Fix issue with nested data being loaded multiple times ([#4192](https://github.com/EQEmu/Server/pull/4192)) @Akkadius 2024-03-23
### Misc
* Windows preprocessor define in crash.cpp ([#4191](https://github.com/EQEmu/Server/pull/4191)) @joligario 2024-03-23
### Quest API
* Add Buff Support to Perl/Lua ([#4182](https://github.com/EQEmu/Server/pull/4182)) @Kinglykrab 2024-03-14
* Add DeleteBot() to Perl/Lua ([#4167](https://github.com/EQEmu/Server/pull/4167)) @nytmyr 2024-03-07
* Add GetDeityName() to Perl/Lua ([#4180](https://github.com/EQEmu/Server/pull/4180)) @Kinglykrab 2024-03-14
* Add RemoveAAPoints() and AA Loss Event to Perl/Lua ([#4174](https://github.com/EQEmu/Server/pull/4174)) @Kinglykrab 2024-03-09
* Add RemoveAlternateCurrencyValue() to Perl/Lua ([#4190](https://github.com/EQEmu/Server/pull/4190)) @Kinglykrab 2024-03-17
* Add Restore Methods for Health, Mana, and Endurance to Perl/Lua ([#4179](https://github.com/EQEmu/Server/pull/4179)) @Kinglykrab 2024-03-23
* Add Silent Saylink Methods to Perl/Lua ([#4177](https://github.com/EQEmu/Server/pull/4177)) @Kinglykrab 2024-03-14
### Rules
* Add World:Rules Rule ([#4194](https://github.com/EQEmu/Server/pull/4194)) @Kinglykrab 2024-03-23
### Tradeskills
* Implement learning recipes from books ([#4170](https://github.com/EQEmu/Server/pull/4170)) @hgtw 2024-03-23
## [22.47.0] 3/5/2024
### Crash Fix
* Added a guild_mgr check ([#4163](https://github.com/EQEmu/Server/pull/4163)) @neckkola 2024-03-06
* Goto Command could crash using Developer Tools ([#4158](https://github.com/EQEmu/Server/pull/4158)) @neckkola 2024-03-04
* Groundspawn Memory Corruption ([#4157](https://github.com/EQEmu/Server/pull/4157)) @neckkola 2024-03-04
* Update to location of qGlobals initialization ([#4144](https://github.com/EQEmu/Server/pull/4144)) @neckkola 2024-03-02
### Feature
* Adds rules to control level requirements for Double Backstab, Assassinate, and Double Bowshot (#4159) ([#29](https://github.com/EQEmu/Server/pull/29)) @catapultam-habeo 2024-03-04
* Adjust String-based Rules Length ([#4138](https://github.com/EQEmu/Server/pull/4138)) @Kinglykrab 2024-03-06
* Exempt a zone from IP-limit checks. ([#4137](https://github.com/EQEmu/Server/pull/4137)) @catapultam-habeo 2024-03-02
### Fixes
* Add id to the guild_bank table ([#4155](https://github.com/EQEmu/Server/pull/4155)) @neckkola 2024-03-05
* Fix Bots/Bot Pets ending up on XTargets ([#4132](https://github.com/EQEmu/Server/pull/4132)) @Kinglykrab 2024-03-02
* Fix Character EXP Modifiers default ([#4161](https://github.com/EQEmu/Server/pull/4161)) @Kinglykrab 2024-03-06
* Fix Spawns Not Parsing Quest on Zone Bootup ([#4149](https://github.com/EQEmu/Server/pull/4149)) @Kinglykrab 2024-03-05
* Fix typo when updating spawn events in spawn condition manager ([#4160](https://github.com/EQEmu/Server/pull/4160)) @joligario 2024-03-05
* GetBotNameByID Temporary Reference Warning ([#4145](https://github.com/EQEmu/Server/pull/4145)) @Kinglykrab 2024-03-02
* Prevent NPE when creating DZ using ad-hoc version IDs ([#4141](https://github.com/EQEmu/Server/pull/4141)) @catapultam-habeo 2024-03-05
* Update FreeGuildID Routine ([#4143](https://github.com/EQEmu/Server/pull/4143)) @neckkola 2024-03-02
### Quest API
* Add Bot Special Attacks for Immune Aggro/Damage ([#4108](https://github.com/EQEmu/Server/pull/4108)) @Kinglykrab 2024-03-02
* Add GetHeroicStrikethrough() to Perl/Lua ([#4150](https://github.com/EQEmu/Server/pull/4150)) @Kinglykrab 2024-03-03
* Add IsAlwaysAggro() to Perl/Lua ([#4152](https://github.com/EQEmu/Server/pull/4152)) @Kinglykrab 2024-03-04
* Add IsBoat()/IsControllableBoat() to Perl/Lua ([#4151](https://github.com/EQEmu/Server/pull/4151)) @Kinglykrab 2024-03-03
* Add IsDestructibleObject() to Perl/Lua ([#4153](https://github.com/EQEmu/Server/pull/4153)) @Kinglykrab 2024-03-03
### Zone
* Zone Routing Improvements ([#4142](https://github.com/EQEmu/Server/pull/4142)) @Akkadius 2024-03-02
### Zoning
* Zone routing adjustment ([#4162](https://github.com/EQEmu/Server/pull/4162)) @Akkadius 2024-03-06
## [22.46.1] 3/2/2024
### Fixes
* Change `UnburyCorpse` to use repository methods ([#4147](https://github.com/EQEmu/Server/pull/4147)) @joligario 2024-03-03
## [22.46.0] 3/2/2024
### Commands
* Add #fish Command ([#4136](https://github.com/EQEmu/Server/pull/4136)) @Kinglykrab 2024-03-01
### Crash Fix
* Raid::UpdateGroupAAs ([#4139](https://github.com/EQEmu/Server/pull/4139)) @neckkola 2024-03-02
* Update to location of qGlobals initialization ([#4144](https://github.com/EQEmu/Server/pull/4144)) @neckkola 2024-03-02
### Feature
* Exempt a zone from IP-limit checks. ([#4137](https://github.com/EQEmu/Server/pull/4137)) @catapultam-habeo 2024-03-02
### Fixes
* Cleanup NPC Mana Tap Logic ([#4134](https://github.com/EQEmu/Server/pull/4134)) @noudess 2024-03-02
* Fix Bots/Bot Pets ending up on XTargets ([#4132](https://github.com/EQEmu/Server/pull/4132)) @Kinglykrab 2024-03-02
* Fix issue with NPC Secondary Textures ([#4129](https://github.com/EQEmu/Server/pull/4129)) @Kinglykrab 2024-03-01
* GetBotNameByID Temporary Reference Warning ([#4145](https://github.com/EQEmu/Server/pull/4145)) @Kinglykrab 2024-03-02
* Update FreeGuildID Routine ([#4143](https://github.com/EQEmu/Server/pull/4143)) @neckkola 2024-03-02
* Use std::clamp for Mob::ChangeSize ([#4140](https://github.com/EQEmu/Server/pull/4140)) @joligario 2024-03-02
### Quest API
* Add Bot Special Attacks for Immune Aggro/Damage ([#4108](https://github.com/EQEmu/Server/pull/4108)) @Kinglykrab 2024-03-02
### Zone
* Zone Routing Improvements ([#4142](https://github.com/EQEmu/Server/pull/4142)) @Akkadius 2024-03-02
## [22.45.1] 2/29/2024
### Character Creation
* Improved Random Name Generator ([#4081](https://github.com/EQEmu/Server/pull/4081)) @catapultam-habeo 2024-02-27
### Code
* Fix Server Rules Documentation Generation ([#4125](https://github.com/EQEmu/Server/pull/4125)) @Kinglykrab 2024-02-26
* Remove unnecessary stoptimer logs ([#4128](https://github.com/EQEmu/Server/pull/4128)) @Kinglykrab 2024-02-28
### Commands
* Add `#forage` command ([#4133](https://github.com/EQEmu/Server/pull/4133)) @joligario 2024-02-29
### Crash
* Fix crash issue during database dump ([#4127](https://github.com/EQEmu/Server/pull/4127)) @Akkadius 2024-02-29
### Crash Fix
* D20 crash if mitigation average resulted in 0 ([#4131](https://github.com/EQEmu/Server/pull/4131)) @nytmyr 2024-02-29
### Fixes
* Fix forage returning first result from table ([#4130](https://github.com/EQEmu/Server/pull/4130)) @nytmyr 2024-02-29
* Who /all displays incorrect guild name ([#4123](https://github.com/EQEmu/Server/pull/4123)) @neckkola 2024-02-25
### Quest API
* Add Pet Owner Methods to Perl/Lua ([#4115](https://github.com/EQEmu/Server/pull/4115)) @Kinglykrab 2024-02-25
## [22.45.0] 2/24/2024
### Beacon
* Revert a few lines of PR #4024 that broke beacons ([#4118](https://github.com/EQEmu/Server/pull/4118)) @noudess 2024-02-24
### Bots
* Cleanup empty `bot_commands` files ([#4095](https://github.com/EQEmu/Server/pull/4095)) @Kinglykrab 2024-02-19
* Remove Alt Combat Functionality ([#4067](https://github.com/EQEmu/Server/pull/4067)) @Kinglykrab 2024-02-12
### Code
* Update fmt to 10.2.1 ([#4071](https://github.com/EQEmu/Server/pull/4071)) @hgtw 2024-02-16
* Use explicit conversions for enum formatting ([#4064](https://github.com/EQEmu/Server/pull/4064)) @hgtw 2024-02-12
### Database
* Add content_database flag for zone changes ([#4104](https://github.com/EQEmu/Server/pull/4104)) @joligario 2024-02-20
* Remove "item_tick" from database schema per https://github.com/EQEmu/Server/pull/3985 ([#4083](https://github.com/EQEmu/Server/pull/4083)) @Akkadius 2024-02-16
### Expansions
* Zone Expansion Version Routing ([#4084](https://github.com/EQEmu/Server/pull/4084)) @Akkadius 2024-02-20
### Factions
* Fix issue with npcedit and cached factions ([#4103](https://github.com/EQEmu/Server/pull/4103)) @noudess 2024-02-20
### Feature
* Add Augments to Starting Items for Bots/Players ([#4100](https://github.com/EQEmu/Server/pull/4100)) @Kinglykrab 2024-02-21
* Hot Zone Bonus XP Notice ([#4091](https://github.com/EQEmu/Server/pull/4091)) @fryguy503 2024-02-18
### Fixes
* Add safety check to SummonAllCharacterCorpses. ([#4107](https://github.com/EQEmu/Server/pull/4107)) @fryguy503 2024-02-21
* Added additional Guild-related crash checks ([#4105](https://github.com/EQEmu/Server/pull/4105)) @neckkola 2024-02-22
* Aura effect spell id from #3964 ([#4094](https://github.com/EQEmu/Server/pull/4094)) @joligario 2024-02-18
* Crash on Ubuntu 22.04 ([#4119](https://github.com/EQEmu/Server/pull/4119)) @neckkola 2024-02-25
* Fix #wpadd Query ([#4078](https://github.com/EQEmu/Server/pull/4078)) @Kinglykrab 2024-02-14
* Fix Bot Weapons with No Races ([#4110](https://github.com/EQEmu/Server/pull/4110)) @Kinglykrab 2024-02-25
* Fix ClearSpawnTimers() ([#4073](https://github.com/EQEmu/Server/pull/4073)) @Kinglykrab 2024-02-13
* Fix Issue with ClearSpawnTimers() ([#4070](https://github.com/EQEmu/Server/pull/4070)) @Kinglykrab 2024-02-13
* Fix ObjectContentsRepository using content_db ([#4076](https://github.com/EQEmu/Server/pull/4076)) @Kinglykrab 2024-02-14
* Fix Sympathetic Procs for Bots/Mercenariess ([#4086](https://github.com/EQEmu/Server/pull/4086)) @Kinglykrab 2024-02-19
* Fix fix_z Query ([#4080](https://github.com/EQEmu/Server/pull/4080)) @Kinglykrab 2024-02-15
* Fix hotzone string error ([#4109](https://github.com/EQEmu/Server/pull/4109)) @fryguy503 2024-02-22
* Fix issue with IsEntOnHateList ([#4097](https://github.com/EQEmu/Server/pull/4097)) @Kinglykrab 2024-02-19
* Fix manifest check on `base_data` change ([#4082](https://github.com/EQEmu/Server/pull/4082)) @joligario 2024-02-16
* Revert 2df7d19 ([#4101](https://github.com/EQEmu/Server/pull/4101)) @joligario 2024-02-20
* Update database_schema to add guild_permissions ([#4085](https://github.com/EQEmu/Server/pull/4085)) @neckkola 2024-02-16
### Guilds
* Fixes for Guild Bank ([#4120](https://github.com/EQEmu/Server/pull/4120)) @neckkola 2024-02-25
### Logs
* Fix log in BaseGuildManager::IsGuildLeader() ([#4102](https://github.com/EQEmu/Server/pull/4102)) @joligario 2024-02-20
### Opcodes
* Fix opcode reloading ([#4075](https://github.com/EQEmu/Server/pull/4075)) @Akkadius 2024-02-14
### Quest API
* Add Bot Methods to Perl/Lua ([#4113](https://github.com/EQEmu/Server/pull/4113)) @Kinglykrab 2024-02-25
* Add Entity Variable Events to Perl/Lua ([#4092](https://github.com/EQEmu/Server/pull/4092)) @Kinglykrab 2024-02-20
* Add GetAugmentIDs() to Perl/Lua ([#4114](https://github.com/EQEmu/Server/pull/4114)) @Kinglykrab 2024-02-25
* Add GetNPCSpellsEffectsID() to Perl/Lua ([#4117](https://github.com/EQEmu/Server/pull/4117)) @Kinglykrab 2024-02-25
* Add Hatelist Count Methods to Perl/Lua ([#4106](https://github.com/EQEmu/Server/pull/4106)) @Kinglykrab 2024-02-21
* Add IsInAGuild() to Perl/Lua ([#4066](https://github.com/EQEmu/Server/pull/4066)) @Kinglykrab 2024-02-14
* Add Pet Methods to Perl/Lua ([#4116](https://github.com/EQEmu/Server/pull/4116)) @Kinglykrab 2024-02-25
* Add Timer Events to Perl/Lua ([#4099](https://github.com/EQEmu/Server/pull/4099)) @Kinglykrab 2024-02-19
* Add spell cast methods to Lua ([#4096](https://github.com/EQEmu/Server/pull/4096)) @Kinglykrab 2024-02-19
* Add tracebacks to Lua error messages ([#4079](https://github.com/EQEmu/Server/pull/4079)) @hgtw 2024-02-16
* Export Combat Record to Death Events ([#4112](https://github.com/EQEmu/Server/pull/4112)) @Kinglykrab 2024-02-25
### Repositories
* Cleanup and Convert Character Creation to Repositories ([#4053](https://github.com/EQEmu/Server/pull/4053)) @Kinglykrab 2024-02-20
* Convert Zone Flags to Repositories ([#4077](https://github.com/EQEmu/Server/pull/4077)) @Kinglykrab 2024-02-16
* Update `zone` base repository from #4084 ([#4111](https://github.com/EQEmu/Server/pull/4111)) @joligario 2024-02-23
## [22.44.5] - 2/12/2024
### Fixes
* [Hotfix] Fix issues where we're using the wrong database pointers @Akkadius
## [22.44.4] - 2/12/2024
### Fixes
* Fix ClearSpawnTimers() ([#4073](https://github.com/EQEmu/Server/pull/4073)) @Kinglykrab 2024-02-13
## [22.44.3] - 2/12/2024
### Fixes
* Fix Issue with ClearSpawnTimers() ([#4070](https://github.com/EQEmu/Server/pull/4070)) @Kinglykrab 2024-02-13
## [22.44.2] - 2/12/2024
### Bots
+144 -25
View File
@@ -1,28 +1,11 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "world_content_service.h"
#include <utility>
#include <glm/vec3.hpp>
#include "../database.h"
#include "../rulesys.h"
#include "../eqemu_logsys.h"
#include "../repositories/content_flags_repository.h"
#include "../repositories/instance_list_repository.h"
WorldContentService::WorldContentService()
@@ -119,7 +102,7 @@ std::vector<std::string> WorldContentService::GetContentFlagsDisabled()
/**
* @param content_flags
*/
void WorldContentService::SetContentFlags(const std::vector<ContentFlagsRepository::ContentFlags>& content_flags)
void WorldContentService::SetContentFlags(const std::vector<ContentFlagsRepository::ContentFlags> &content_flags)
{
WorldContentService::content_flags = content_flags;
}
@@ -167,14 +150,14 @@ bool WorldContentService::DoesPassContentFiltering(const ContentFlags &f)
}
// if we don't have any enabled flag in enabled flags, we fail
for (const auto& flag: Strings::Split(f.content_flags)) {
for (const auto &flag: Strings::Split(f.content_flags)) {
if (!Strings::Contains(GetContentFlagsEnabled(), flag)) {
return false;
}
}
// if we don't have any disabled flag in disabled flags, we fail
for (const auto& flag: Strings::Split(f.content_flags_disabled)) {
for (const auto &flag: Strings::Split(f.content_flags_disabled)) {
if (!Strings::Contains(GetContentFlagsDisabled(), flag)) {
return false;
}
@@ -195,11 +178,13 @@ void WorldContentService::ReloadContentFlags()
LogInfo(
"Loaded content flag [{}] [{}]",
f.flag_name,
(f.enabled ? "Enabled" : "Disabled")
(f.enabled ? "enabled" : "disabled")
);
}
SetContentFlags(set_content_flags);
LoadZones();
LoadStaticGlobalZoneInstances();
}
Database *WorldContentService::GetDatabase() const
@@ -214,6 +199,18 @@ WorldContentService *WorldContentService::SetDatabase(Database *database)
return this;
}
Database *WorldContentService::GetContentDatabase() const
{
return m_content_database;
}
WorldContentService *WorldContentService::SetContentDatabase(Database *database)
{
WorldContentService::m_content_database = database;
return this;
}
void WorldContentService::SetContentFlag(const std::string &content_flag_name, bool enabled)
{
auto flags = ContentFlagsRepository::GetWhere(
@@ -238,3 +235,125 @@ void WorldContentService::SetContentFlag(const std::string &content_flag_name, b
ReloadContentFlags();
}
// HandleZoneRoutingMiddleware is meant to handle content and context aware zone routing
//
// example # 1
// lavastorm (pre-don) version 0 (classic)
// lavastorm (don) version 1
// we want to route players to the correct version of lavastorm based on the current server side expansion
// in order to do that the simplest and cleanest way we intercept the zoning process and route players to an "instance" of the zone
// the reason why we're doing this is because all of the zoning logic already is handled by two keys "zone_id" and "instance_id"
// we can leverage static, never expires instances to handle this but to the client they don't see it any other way than a public normal zone
// scripts handle all the same way, you don't have to think about instances, the middleware will handle the magic
// the versions of zones are represented by two zone entries that have potentially different min/max expansion and/or different content flags
// we decide to route the client to the correct version of the zone based on the current server side expansion
void WorldContentService::HandleZoneRoutingMiddleware(ZoneChange_Struct *zc)
{
auto r = FindZone(zc->zoneID, zc->instanceID);
if (r.zone_id == 0) {
return;
}
zc->instanceID = r.instance.id;
}
// LoadStaticGlobalZoneInstances loads all static global zone instances
// these are zones that are never set to expire and are global
// these are used commonly in v1/v2/v3 versions of the same zone for expansion routing
WorldContentService * WorldContentService::LoadStaticGlobalZoneInstances()
{
m_zone_instances = InstanceListRepository::GetWhere(*GetDatabase(), fmt::format("never_expires = 1 AND is_global = 1"));
LogInfo("Loaded [{}] zone_instances", m_zone_instances.size());
return this;
}
// LoadZones sets the zones for the world content service
// this is used for zone routing middleware
// we pull the zone list from the zone repository and feed from the zone store for now
// we're holding a copy in the content service - but we're talking 250kb of data in memory to handle routing of zoning
WorldContentService * WorldContentService::LoadZones()
{
m_zones = ZoneRepository::All(*GetContentDatabase());
LogInfo("Loaded [{}] zones", m_zones.size());
return this;
}
// FindZone is critical to the zone routing middleware and any logic that needs to route players to the correct zone
// era contextual routing, multiple version of zones, etc
WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id, uint32 instance_id)
{
// if there's an active dynamic instance, we don't need to route
if (instance_id > 0) {
auto inst = InstanceListRepository::FindOne(*GetDatabase(), instance_id);
if (inst.id != 0 && !inst.is_global && !inst.never_expires) {
return WorldContentService::FindZoneResult{
.zone_id = 0,
};
}
}
for (auto &z: m_zones) {
if (z.zoneidnumber == zone_id) {
auto f = ContentFlags{
.min_expansion = z.min_expansion,
.max_expansion = z.max_expansion,
.content_flags = z.content_flags,
.content_flags_disabled = z.content_flags_disabled
};
if (DoesPassContentFiltering(f)) {
LogInfo(
"Attempting to route player to zone [{}] ({}) version [{}] long_name [{}]",
z.short_name,
z.zoneidnumber,
z.version,
z.long_name
);
// first pass, explicit match on public static global zone instances
for (auto &i: m_zone_instances) {
if (i.zone == zone_id && i.version == z.version) {
LogInfo(
"Routed player to instance [{}] of zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
i.id,
z.short_name,
z.zoneidnumber,
z.version,
z.long_name,
i.notes
);
return WorldContentService::FindZoneResult{
.zone_id = static_cast<uint32>(z.zoneidnumber),
.instance = i,
.zone = z
};
}
}
LogInfo(
"Routed player to non-instance zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
z.short_name,
z.zoneidnumber,
z.version,
z.long_name,
z.note
);
return WorldContentService::FindZoneResult{
.zone_id = static_cast<uint32>(z.zoneidnumber),
.instance = InstanceListRepository::NewEntity(),
.zone = z
};
}
}
}
return WorldContentService::FindZoneResult{.zone_id = 0};
}
+21 -20
View File
@@ -1,29 +1,11 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef EQEMU_WORLD_CONTENT_SERVICE_H
#define EQEMU_WORLD_CONTENT_SERVICE_H
#include <string>
#include <vector>
#include "../repositories/content_flags_repository.h"
#include "../repositories/zone_repository.h"
#include "../repositories/instance_list_repository.h"
class Database;
@@ -182,14 +164,33 @@ public:
WorldContentService * SetDatabase(Database *database);
Database *GetDatabase() const;
WorldContentService * SetContentDatabase(Database *database);
Database *GetContentDatabase() const;
void SetContentFlag(const std::string &content_flag_name, bool enabled);
void HandleZoneRoutingMiddleware(ZoneChange_Struct *zc);
struct FindZoneResult {
uint32 zone_id = 0;
InstanceListRepository::InstanceList instance;
ZoneRepository::Zone zone;
};
FindZoneResult FindZone(uint32 zone_id, uint32 instance_id);
private:
int current_expansion{};
std::vector<ContentFlagsRepository::ContentFlags> content_flags;
// reference to database
Database *m_database;
Database *m_content_database;
// holds a record of the zone table from the database
std::vector<ZoneRepository::Zone> m_zones = {};
WorldContentService *LoadStaticGlobalZoneInstances();
std::vector<InstanceListRepository::InstanceList> m_zone_instances;
WorldContentService * LoadZones();
};
extern WorldContentService content_service;
+1 -1
View File
@@ -15,7 +15,7 @@
#include <cstdio>
#include <vector>
#if WINDOWS
#ifdef _WINDOWS
#define popen _popen
#endif
+185 -340
View File
@@ -30,6 +30,11 @@
#include <string.h>
#include "../common/repositories/account_repository.h"
#include "../common/repositories/character_bind_repository.h"
#include "../common/repositories/character_data_repository.h"
#include "../common/repositories/character_languages_repository.h"
#include "../common/repositories/character_leadership_abilities_repository.h"
#include "../common/repositories/character_skills_repository.h"
// Disgrace: for windows compile
#ifdef _WINDOWS
@@ -454,363 +459,185 @@ bool Database::DeleteCharacter(char *character_name)
bool Database::SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct *pp)
{
std::string query = StringFormat(
"REPLACE INTO `character_data` ("
"id,"
"account_id,"
"`name`,"
"last_name,"
"gender,"
"race,"
"class,"
"`level`,"
"deity,"
"birthday,"
"last_login,"
"time_played,"
"pvp_status,"
"level2,"
"anon,"
"gm,"
"intoxication,"
"hair_color,"
"beard_color,"
"eye_color_1,"
"eye_color_2,"
"hair_style,"
"beard,"
"ability_time_seconds,"
"ability_number,"
"ability_time_minutes,"
"ability_time_hours,"
"title,"
"suffix,"
"exp,"
"points,"
"mana,"
"cur_hp,"
"str,"
"sta,"
"cha,"
"dex,"
"`int`,"
"agi,"
"wis,"
"face,"
"y,"
"x,"
"z,"
"heading,"
"pvp2,"
"pvp_type,"
"autosplit_enabled,"
"zone_change_count,"
"drakkin_heritage,"
"drakkin_tattoo,"
"drakkin_details,"
"toxicity,"
"hunger_level,"
"thirst_level,"
"ability_up,"
"zone_id,"
"zone_instance,"
"leadership_exp_on,"
"ldon_points_guk,"
"ldon_points_mir,"
"ldon_points_mmc,"
"ldon_points_ruj,"
"ldon_points_tak,"
"ldon_points_available,"
"tribute_time_remaining,"
"show_helm,"
"career_tribute_points,"
"tribute_points,"
"tribute_active,"
"endurance,"
"group_leadership_exp,"
"raid_leadership_exp,"
"group_leadership_points,"
"raid_leadership_points,"
"air_remaining,"
"pvp_kills,"
"pvp_deaths,"
"pvp_current_points,"
"pvp_career_points,"
"pvp_best_kill_streak,"
"pvp_worst_death_streak,"
"pvp_current_kill_streak,"
"aa_points_spent,"
"aa_exp,"
"aa_points,"
"group_auto_consent,"
"raid_auto_consent,"
"guild_auto_consent,"
"RestTimer) "
"VALUES ("
"%u," // id
"%u," // account_id
"'%s'," // `name`
"'%s'," // last_name
"%u," // gender
"%u," // race
"%u," // class
"%u," // `level`
"%u," // deity
"%u," // birthday
"%u," // last_login
"%u," // time_played
"%u," // pvp_status
"%u," // level2
"%u," // anon
"%u," // gm
"%u," // intoxication
"%u," // hair_color
"%u," // beard_color
"%u," // eye_color_1
"%u," // eye_color_2
"%u," // hair_style
"%u," // beard
"%u," // ability_time_seconds
"%u," // ability_number
"%u," // ability_time_minutes
"%u," // ability_time_hours
"'%s'," // title
"'%s'," // suffix
"%u," // exp
"%u," // points
"%u," // mana
"%u," // cur_hp
"%u," // str
"%u," // sta
"%u," // cha
"%u," // dex
"%u," // `int`
"%u," // agi
"%u," // wis
"%u," // face
"%f," // y
"%f," // x
"%f," // z
"%f," // heading
"%u," // pvp2
"%u," // pvp_type
"%u," // autosplit_enabled
"%u," // zone_change_count
"%u," // drakkin_heritage
"%u," // drakkin_tattoo
"%u," // drakkin_details
"%i," // toxicity
"%i," // hunger_level
"%i," // thirst_level
"%u," // ability_up
"%u," // zone_id
"%u," // zone_instance
"%u," // leadership_exp_on
"%u," // ldon_points_guk
"%u," // ldon_points_mir
"%u," // ldon_points_mmc
"%u," // ldon_points_ruj
"%u," // ldon_points_tak
"%u," // ldon_points_available
"%u," // tribute_time_remaining
"%u," // show_helm
"%u," // career_tribute_points
"%u," // tribute_points
"%u," // tribute_active
"%u," // endurance
"%u," // group_leadership_exp
"%u," // raid_leadership_exp
"%u," // group_leadership_point
"%u," // raid_leadership_points
"%u," // air_remaining
"%u," // pvp_kills
"%u," // pvp_deaths
"%u," // pvp_current_points
"%u," // pvp_career_points
"%u," // pvp_best_kill_streak
"%u," // pvp_worst_death_streak
"%u," // pvp_current_kill_strea
"%u," // aa_points_spent
"%u," // aa_exp
"%u," // aa_points
"%u," // group_auto_consent
"%u," // raid_auto_consent
"%u," // guild_auto_consent
"%u" // RestTimer
")",
character_id, // " id, "
account_id, // " account_id, "
Strings::Escape(pp->name).c_str(), // " `name`, "
Strings::Escape(pp->last_name).c_str(), // " last_name, "
pp->gender, // " gender, "
pp->race, // " race, "
pp->class_, // " class, "
pp->level, // " `level`, "
pp->deity, // " deity, "
pp->birthday, // " birthday, "
pp->lastlogin, // " last_login, "
pp->timePlayedMin, // " time_played, "
pp->pvp, // " pvp_status, "
pp->level2, // " level2, "
pp->anon, // " anon, "
pp->gm, // " gm, "
pp->intoxication, // " intoxication, "
pp->haircolor, // " hair_color, "
pp->beardcolor, // " beard_color, "
pp->eyecolor1, // " eye_color_1, "
pp->eyecolor2, // " eye_color_2, "
pp->hairstyle, // " hair_style, "
pp->beard, // " beard, "
pp->ability_time_seconds, // " ability_time_seconds, "
pp->ability_number, // " ability_number, "
pp->ability_time_minutes, // " ability_time_minutes, "
pp->ability_time_hours, // " ability_time_hours, "
Strings::Escape(pp->title).c_str(), // " title, "
Strings::Escape(pp->suffix).c_str(), // " suffix, "
pp->exp, // " exp, "
pp->points, // " points, "
pp->mana, // " mana, "
pp->cur_hp, // " cur_hp, "
pp->STR, // " str, "
pp->STA, // " sta, "
pp->CHA, // " cha, "
pp->DEX, // " dex, "
pp->INT, // " `int`, "
pp->AGI, // " agi, "
pp->WIS, // " wis, "
pp->face, // " face, "
pp->y, // " y, "
pp->x, // " x, "
pp->z, // " z, "
pp->heading, // " heading, "
pp->pvp2, // " pvp2, "
pp->pvptype, // " pvp_type, "
pp->autosplit, // " autosplit_enabled, "
pp->zone_change_count, // " zone_change_count, "
pp->drakkin_heritage, // " drakkin_heritage, "
pp->drakkin_tattoo, // " drakkin_tattoo, "
pp->drakkin_details, // " drakkin_details, "
pp->toxicity, // " toxicity, "
pp->hunger_level, // " hunger_level, "
pp->thirst_level, // " thirst_level, "
pp->ability_up, // " ability_up, "
pp->zone_id, // " zone_id, "
pp->zoneInstance, // " zone_instance, "
pp->leadAAActive, // " leadership_exp_on, "
pp->ldon_points_guk, // " ldon_points_guk, "
pp->ldon_points_mir, // " ldon_points_mir, "
pp->ldon_points_mmc, // " ldon_points_mmc, "
pp->ldon_points_ruj, // " ldon_points_ruj, "
pp->ldon_points_tak, // " ldon_points_tak, "
pp->ldon_points_available, // " ldon_points_available, "
pp->tribute_time_remaining, // " tribute_time_remaining, "
pp->showhelm, // " show_helm, "
pp->career_tribute_points, // " career_tribute_points, "
pp->tribute_points, // " tribute_points, "
pp->tribute_active, // " tribute_active, "
pp->endurance, // " endurance, "
pp->group_leadership_exp, // " group_leadership_exp, "
pp->raid_leadership_exp, // " raid_leadership_exp, "
pp->group_leadership_points, // " group_leadership_points, "
pp->raid_leadership_points, // " raid_leadership_points, "
pp->air_remaining, // " air_remaining, "
pp->PVPKills, // " pvp_kills, "
pp->PVPDeaths, // " pvp_deaths, "
pp->PVPCurrentPoints, // " pvp_current_points, "
pp->PVPCareerPoints, // " pvp_career_points, "
pp->PVPBestKillStreak, // " pvp_best_kill_streak, "
pp->PVPWorstDeathStreak, // " pvp_worst_death_streak, "
pp->PVPCurrentKillStreak, // " pvp_current_kill_streak, "
pp->aapoints_spent, // " aa_points_spent, "
pp->expAA, // " aa_exp, "
pp->aapoints, // " aa_points, "
pp->groupAutoconsent, // " group_auto_consent, "
pp->raidAutoconsent, // " raid_auto_consent, "
pp->guildAutoconsent, // " guild_auto_consent, "
pp->RestTimer // " RestTimer) "
);
QueryDatabase(query);
auto c = CharacterDataRepository::NewEntity();
/* Save Bind Points */
query = StringFormat(
"REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)"
" VALUES (%u, %u, %u, %f, %f, %f, %f, %i), "
"(%u, %u, %u, %f, %f, %f, %f, %i), "
"(%u, %u, %u, %f, %f, %f, %f, %i), "
"(%u, %u, %u, %f, %f, %f, %f, %i), "
"(%u, %u, %u, %f, %f, %f, %f, %i)",
character_id, pp->binds[0].zone_id, 0, pp->binds[0].x, pp->binds[0].y, pp->binds[0].z, pp->binds[0].heading, 0,
character_id, pp->binds[1].zone_id, 0, pp->binds[1].x, pp->binds[1].y, pp->binds[1].z, pp->binds[1].heading, 1,
character_id, pp->binds[2].zone_id, 0, pp->binds[2].x, pp->binds[2].y, pp->binds[2].z, pp->binds[2].heading, 2,
character_id, pp->binds[3].zone_id, 0, pp->binds[3].x, pp->binds[3].y, pp->binds[3].z, pp->binds[3].heading, 3,
character_id, pp->binds[4].zone_id, 0, pp->binds[4].x, pp->binds[4].y, pp->binds[4].z, pp->binds[4].heading, 4
);
QueryDatabase(query);
c.id = character_id;
c.account_id = account_id;
c.name = pp->name;
c.last_name = pp->last_name;
c.gender = pp->gender;
c.race = pp->race;
c.class_ = pp->class_;
c.level = pp->level;
c.deity = pp->deity;
c.birthday = pp->birthday;
c.last_login = pp->lastlogin;
c.time_played = pp->timePlayedMin;
c.pvp_status = pp->pvp;
c.level2 = pp->level2;
c.anon = pp->anon;
c.gm = pp->gm;
c.intoxication = pp->intoxication;
c.hair_color = pp->haircolor;
c.beard_color = pp->beardcolor;
c.eye_color_1 = pp->eyecolor1;
c.eye_color_2 = pp->eyecolor2;
c.hair_style = pp->hairstyle;
c.beard = pp->beard;
c.ability_time_seconds = pp->ability_time_seconds;
c.ability_number = pp->ability_number;
c.ability_time_minutes = pp->ability_time_minutes;
c.ability_time_hours = pp->ability_time_hours;
c.title = pp->title;
c.suffix = pp->suffix;
c.exp = pp->exp;
c.points = pp->points;
c.mana = pp->mana;
c.cur_hp = pp->cur_hp;
c.str = pp->STR;
c.sta = pp->STA;
c.cha = pp->CHA;
c.dex = pp->DEX;
c.int_ = pp->INT;
c.agi = pp->AGI;
c.wis = pp->WIS;
c.face = pp->face;
c.y = pp->y;
c.x = pp->x;
c.z = pp->z;
c.heading = pp->heading;
c.pvp2 = pp->pvp2;
c.pvp_type = pp->pvptype;
c.autosplit_enabled = pp->autosplit;
c.zone_change_count = pp->zone_change_count;
c.drakkin_heritage = pp->drakkin_heritage;
c.drakkin_tattoo = pp->drakkin_tattoo;
c.drakkin_details = pp->drakkin_details;
c.toxicity = pp->toxicity;
c.hunger_level = pp->hunger_level;
c.thirst_level = pp->thirst_level;
c.ability_up = pp->ability_up;
c.zone_id = pp->zone_id;
c.zone_instance = pp->zoneInstance;
c.leadership_exp_on = pp->leadAAActive;
c.ldon_points_guk = pp->ldon_points_guk;
c.ldon_points_mir = pp->ldon_points_mir;
c.ldon_points_mmc = pp->ldon_points_mmc;
c.ldon_points_ruj = pp->ldon_points_ruj;
c.ldon_points_tak = pp->ldon_points_tak;
c.ldon_points_available = pp->ldon_points_available;
c.tribute_time_remaining = pp->tribute_time_remaining;
c.show_helm = pp->showhelm;
c.career_tribute_points = pp->career_tribute_points;
c.tribute_points = pp->tribute_points;
c.tribute_active = pp->tribute_active;
c.endurance = pp->endurance;
c.group_leadership_exp = pp->group_leadership_exp;
c.raid_leadership_exp = pp->raid_leadership_exp;
c.group_leadership_points = pp->group_leadership_points;
c.raid_leadership_points = pp->raid_leadership_points;
c.air_remaining = pp->air_remaining;
c.pvp_kills = pp->PVPKills;
c.pvp_deaths = pp->PVPDeaths;
c.pvp_current_points = pp->PVPCurrentPoints;
c.pvp_career_points = pp->PVPCareerPoints;
c.pvp_best_kill_streak = pp->PVPBestKillStreak;
c.pvp_worst_death_streak = pp->PVPWorstDeathStreak;
c.pvp_current_kill_streak = pp->PVPCurrentKillStreak;
c.aa_points_spent = pp->aapoints_spent;
c.aa_exp = pp->expAA;
c.aa_points = pp->aapoints;
c.group_auto_consent = pp->groupAutoconsent;
c.raid_auto_consent = pp->raidAutoconsent;
c.guild_auto_consent = pp->guildAutoconsent;
c.RestTimer = pp->RestTimer;
CharacterDataRepository::ReplaceOne(*this, c);
std::vector<CharacterBindRepository::CharacterBind> character_binds;
character_binds.reserve(5);
auto b = CharacterBindRepository::NewEntity();
b.id = character_id;
for (uint8 slot_id = 0; slot_id < 5; slot_id++) {
b.zone_id = pp->binds[slot_id].zone_id;
b.x = pp->binds[slot_id].x;
b.y = pp->binds[slot_id].y;
b.z = pp->binds[slot_id].z;
b.heading = pp->binds[slot_id].heading;
b.slot = slot_id;
character_binds.emplace_back(b);
}
CharacterBindRepository::ReplaceMany(*this, character_binds);
/* HoTT Ability */
if (RuleB(Character, GrantHoTTOnCreate)) {
query = StringFormat(
"INSERT INTO `character_leadership_abilities` (id, slot, `rank`) VALUES (%u, %i, %i)",
character_id,
14,
1
CharacterLeadershipAbilitiesRepository::InsertOne(
*this,
CharacterLeadershipAbilitiesRepository::CharacterLeadershipAbilities{
.id = character_id,
.slot = LeadershipAbilitySlot::HealthOfTargetsTarget,
.rank_ = 1
}
);
QueryDatabase(query);
}
/* Save Skills */
int firstquery = 0;
for (int i = 0; i < MAX_PP_SKILL; i++) {
if (pp->skills[i] > 0) {
if (firstquery != 1) {
firstquery = 1;
query = StringFormat(
"REPLACE INTO `character_skills` (id, skill_id, value) VALUES (%u, %u, %u)",
character_id,
i,
pp->skills[i]
);
} else {
query = query + StringFormat(", (%u, %u, %u)", character_id, i, pp->skills[i]);
}
}
}
QueryDatabase(query);
std::vector<CharacterSkillsRepository::CharacterSkills> character_skills;
/* Save Language */
firstquery = 0;
for (int i = 0; i < MAX_PP_LANGUAGE; i++) {
if (pp->languages[i] > 0) {
if (firstquery != 1) {
firstquery = 1;
query = StringFormat(
"REPLACE INTO `character_languages` (id, lang_id, value) VALUES (%u, %u, %u)",
character_id,
i,
pp->languages[i]
);
} else {
query = query + StringFormat(", (%u, %u, %u)", character_id, i, pp->languages[i]);
character_skills.reserve(MAX_PP_SKILL);
for (uint16 slot_id = 0; slot_id < MAX_PP_SKILL; slot_id++) {
character_skills.emplace_back(
CharacterSkillsRepository::CharacterSkills{
.id = character_id,
.skill_id = slot_id,
.value = static_cast<uint16_t>(pp->skills[slot_id])
}
}
);
}
QueryDatabase(query);
CharacterSkillsRepository::ReplaceMany(*this, character_skills);
std::vector<CharacterLanguagesRepository::CharacterLanguages> character_languages;
character_languages.reserve(MAX_PP_LANGUAGE);
for (uint16 slot_id = 0; slot_id < MAX_PP_LANGUAGE; slot_id++) {
character_languages.emplace_back(
CharacterLanguagesRepository::CharacterLanguages{
.id = character_id,
.lang_id = slot_id,
.value = static_cast<uint16_t>(pp->languages[slot_id])
}
);
}
CharacterLanguagesRepository::ReplaceMany(*this, character_languages);
return true;
}
uint32 Database::GetCharacterID(const char *name) {
const auto query = fmt::format(
"SELECT `id` FROM `character_data` WHERE `name` = '{}'",
Strings::Escape(name)
uint32 Database::GetCharacterID(const std::string& name)
{
const auto& l = CharacterDataRepository::GetWhere(
*this,
fmt::format(
"`name` = '{}'",
Strings::Escape(name)
)
);
auto results = QueryDatabase(query);
if (!results.Success() || !results.RowCount()) {
if (l.empty()) {
return 0;
}
auto row = results.begin();
return Strings::ToUnsignedInt(row[0]);
auto e = l.front();
return e.id;
}
/*
@@ -1562,6 +1389,24 @@ void Database::SetGroupLeaderName(uint32 gid, const char* name) {
}
}
std::string Database::GetGroupLeaderName(uint32 group_id)
{
const std::string& query = fmt::format(
"SELECT `leadername` FROM `group_leaders` WHERE `gid` = {}",
group_id
);
auto results = QueryDatabase(query);
if (!results.Success() || !results.RowCount()) {
return std::string();
}
auto row = results.begin();
return row[0];
}
char *Database::GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank, char* assist, char* puller, char *marknpc, char *mentoree, int *mentor_percent, GroupLeadershipAA_Struct* GLAA)
{
std::string query = StringFormat("SELECT `leadername`, `maintank`, `assist`, `puller`, `marknpc`, `mentoree`, `mentor_percent`, `leadershipaa` FROM `group_leaders` WHERE `gid` = %lu",(unsigned long)gid);
+3 -1
View File
@@ -125,7 +125,7 @@ public:
uint32 GetAccountIDByChar(const char* charname, uint32* oCharID = 0);
uint32 GetAccountIDByChar(uint32 char_id);
uint32 GetAccountIDByName(std::string account_name, std::string loginserver, int16* status = 0, uint32* lsid = 0);
uint32 GetCharacterID(const char *name);
uint32 GetCharacterID(const std::string& name);
uint32 GetCharacterInfo(std::string character_name, uint32 *account_id, uint32 *zone_id, uint32 *instance_id);
uint32 GetGuildIDByCharID(uint32 char_id);
uint32 GetGroupIDByCharID(uint32 char_id);
@@ -205,6 +205,8 @@ public:
std::string GetGroupLeaderForLogin(std::string character_name);
char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr);
std::string GetGroupLeaderName(uint32 group_id);
uint32 GetGroupID(const char* name);
void ClearGroup(uint32 gid = 0);
+6 -1
View File
@@ -575,7 +575,12 @@ void DatabaseDumpService::RemoveSqlBackup()
{
std::string file = fmt::format("{}.sql", GetDumpFileNameWithPath());
if (File::Exists(file)) {
std::filesystem::remove(file);
try {
std::filesystem::remove(file);
}
catch (std::exception &e) {
LogError("std::filesystem::remove err [{}]", e.what());
}
}
RemoveCredentialsFile();
+70 -2
View File
@@ -5247,7 +5247,7 @@ MODIFY COLUMN `name` varchar(200) CHARACTER SET latin1 COLLATE latin1_swedish_ci
ManifestEntry{
.version = 9257,
.description = "2024_01_16_ground_spawns_fix_z.sql",
.check = "SHOW COLUMNS FROM `ground_spawns` LIKE `fix_z`",
.check = "SHOW COLUMNS FROM `ground_spawns` LIKE 'fix_z'",
.condition = "empty",
.match = "",
.sql = R"(
@@ -5259,7 +5259,7 @@ ADD COLUMN `fix_z` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 AFTER `respawn_timer`;
ManifestEntry{
.version = 9258,
.description = "2024_02_04_base_data.sql",
.check = "SHOW COLUMNS FROM `base_data` LIKE `hp_regen`",
.check = "SHOW COLUMNS FROM `base_data` LIKE 'hp_regen'",
.condition = "empty",
.match = "",
.sql = R"(
@@ -5365,6 +5365,74 @@ ALTER TABLE `character_corpses` MODIFY COLUMN `time_of_death` datetime NOT NULL
.sql = R"(
ALTER TABLE `object_contents` MODIFY COLUMN `droptime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP;
)"
},
ManifestEntry{
.version = 9263,
.description = "2024_02_16_rearrange_zone_columns.sql",
.check = "show columns from zone like 'note'",
.condition = "missing",
.match = "varchar(200)",
.sql = R"(
ALTER TABLE `zone`
MODIFY COLUMN `id` int(10) NOT NULL AUTO_INCREMENT FIRST,
MODIFY COLUMN `zoneidnumber` int(4) NOT NULL DEFAULT 0 AFTER `id`,
MODIFY COLUMN `version` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `zoneidnumber`,
MODIFY COLUMN `short_name` varchar(32) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL AFTER `version`,
MODIFY COLUMN `long_name` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL AFTER `short_name`,
MODIFY COLUMN `min_status` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `long_name`,
MODIFY COLUMN `note` varchar(200) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL AFTER `map_file_name`,
MODIFY COLUMN `min_expansion` tinyint(4) NOT NULL DEFAULT -1 AFTER `note`,
MODIFY COLUMN `max_expansion` tinyint(4) NOT NULL DEFAULT -1 AFTER `min_expansion`,
MODIFY COLUMN `content_flags` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL AFTER `max_expansion`,
MODIFY COLUMN `content_flags_disabled` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL AFTER `content_flags`,
MODIFY COLUMN `expansion` tinyint(3) NOT NULL DEFAULT 0 AFTER `content_flags_disabled`,
MODIFY COLUMN `file_name` varchar(16) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL AFTER `expansion`,
MODIFY COLUMN `safe_x` float NOT NULL DEFAULT 0 AFTER `file_name`,
MODIFY COLUMN `safe_y` float NOT NULL DEFAULT 0 AFTER `safe_x`,
MODIFY COLUMN `safe_z` float NOT NULL DEFAULT 0 AFTER `safe_y`,
MODIFY COLUMN `safe_heading` float NOT NULL DEFAULT 0 AFTER `safe_z`;
)",
.content_schema_update = true
},
ManifestEntry{
.version = 9264,
.description = "2024_02_18_starting_items_augments.sql",
.check = "SHOW COLUMNS FROM `starting_items` LIKE 'augment_one'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `starting_items`
ADD COLUMN `augment_one` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `item_charges`,
ADD COLUMN `augment_two` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_one`,
ADD COLUMN `augment_three` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_two`,
ADD COLUMN `augment_four` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_three`,
ADD COLUMN `augment_five` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_four`,
ADD COLUMN `augment_six` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_five`;
)",
.content_schema_update = true
},
ManifestEntry{
.version = 9265,
.description = "2024_03_03_add_id_to_guild_bank.sql",
.check = "SHOW COLUMNS FROM `guild_bank` LIKE 'id'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `guild_bank`
ADD COLUMN `id` INT UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
ADD PRIMARY KEY (`id`);
)",
},
ManifestEntry{
.version = 9266,
.description = "2024_03_02_rule_values_rule_value_length.sql",
.check = "SHOW COLUMNS FROM `rule_values` LIKE 'rule_value'",
.condition = "contains",
.match = "varchar(30)",
.sql = R"(
ALTER TABLE `rule_values`
MODIFY COLUMN `rule_value` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL AFTER `rule_name`;
)"
}
// -- template; copy/paste this when you need to create a new entry
// ManifestEntry{
@@ -123,6 +123,22 @@ ALTER TABLE `bot_pets` DROP FOREIGN KEY `FK_bot_pets_1`;
ALTER TABLE `bot_pet_buffs` DROP FOREIGN KEY `FK_bot_pet_buffs_1`;
ALTER TABLE `bot_pet_inventories` DROP FOREIGN KEY `FK_bot_pet_inventories_1`;
ALTER TABLE `bot_stances` DROP FOREIGN KEY `FK_bot_stances_1`;
)"
},
ManifestEntry{
.version = 9043,
.description = "2024_02_18_bot_starting_items_augments.sql",
.check = "SHOW COLUMNS FROM `bot_starting_items` LIKE 'augment_one'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `bot_starting_items`
ADD COLUMN `augment_one` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `item_charges`,
ADD COLUMN `augment_two` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_one`,
ADD COLUMN `augment_three` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_two`,
ADD COLUMN `augment_four` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_three`,
ADD COLUMN `augment_five` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_four`,
ADD COLUMN `augment_six` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_five`;
)"
}
// -- template; copy/paste this when you need to create a new entry
+1 -1
View File
@@ -146,6 +146,7 @@ namespace DatabaseSchema {
"friends",
"guild_bank",
"guild_members",
"guild_permissions",
"guild_ranks",
"guild_relations",
"guild_tributes",
@@ -333,7 +334,6 @@ namespace DatabaseSchema {
"group_leaders",
"instance_list",
"ip_exemptions",
"item_tick",
"lfguild",
"merc_buffs",
"merchantlist_temp",
+2
View File
@@ -698,6 +698,8 @@ const std::map<uint32, std::string>& EQ::constants::GetSpecialAbilityMap()
{ IMMUNE_OPEN, "Immune to Open" },
{ IMMUNE_ASSASSINATE, "Immune to Assassinate" },
{ IMMUNE_HEADSHOT, "Immune to Headshot" },
{ IMMUNE_AGGRO_BOT, "Immune to Bot Aggro" },
{ IMMUNE_DAMAGE_BOT, "Immune to Bot Damage" },
};
return special_ability_map;
+3 -1
View File
@@ -656,7 +656,9 @@ enum {
IMMUNE_OPEN = 53,
IMMUNE_ASSASSINATE = 54,
IMMUNE_HEADSHOT = 55,
MAX_SPECIAL_ATTACK = 56
IMMUNE_AGGRO_BOT = 56,
IMMUNE_DAMAGE_BOT = 57,
MAX_SPECIAL_ATTACK = 58
};
+4
View File
@@ -1127,4 +1127,8 @@ namespace RaidLootType {
constexpr uint32 EntireRaid = 4;
}
namespace LeadershipAbilitySlot {
constexpr uint16 HealthOfTargetsTarget = 14;
}
#endif /*COMMON_EQ_CONSTANTS_H*/
+2
View File
@@ -141,6 +141,7 @@ namespace Logs {
Zoning,
EqTime,
Corpses,
XTargets,
MaxCategoryID /* Don't Remove this */
};
@@ -241,6 +242,7 @@ namespace Logs {
"Zoning",
"EqTime",
"Corpses",
"XTargets"
};
}
+10
View File
@@ -834,6 +834,16 @@
OutF(LogSys, Logs::Detail, Logs::Corpses, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogXTargets(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::XTargets))\
OutF(LogSys, Logs::General, Logs::XTargets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogXTargetsDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::XTargets))\
OutF(LogSys, Logs::Detail, Logs::XTargets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define Log(debug_level, log_category, message, ...) do {\
if (LogSys.IsLogEnabled(debug_level, log_category))\
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
+8 -35
View File
@@ -342,41 +342,14 @@ bool BaseGuildManager::_StoreGuildDB(uint32 guild_id)
return true;
}
uint32 BaseGuildManager::_GetFreeGuildID()
{
GuildsRepository::DeleteWhere(*m_db, "`name` = ''");
GuildsRepository::Guilds out;
out.id = 0;
out.leader = 0;
out.minstatus = 0;
out.tribute = 0;
out.name = "";
out.motd = "";
out.motd_setter = "";
out.url = "";
out.channel = "";
auto last_insert_id = GuildsRepository::InsertOne(*m_db, out);
if (last_insert_id.id > 0) {
LogGuilds("Located a free guild ID [{}] in the database", last_insert_id.id);
return last_insert_id.id;
}
LogGuilds("Unable to find a free guild ID in the database");
return GUILD_NONE;
}
uint32 BaseGuildManager::CreateGuild(std::string name, uint32 leader_char_id)
{
uint32 guild_id = UpdateDbCreateGuild(name, leader_char_id);
if (guild_id == GUILD_NONE) {
return (GUILD_NONE);
}
//RefreshGuild(guild_id);
//SendGuildRefresh(guild_id, true, false, false, false);
//SendCharRefresh(GUILD_NONE, guild_id, leader_char_id);
uint32 guild_id = UpdateDbCreateGuild(name, leader_char_id);
if (guild_id == GUILD_NONE) {
return (GUILD_NONE);
}
return guild_id;
return guild_id;
}
bool BaseGuildManager::DeleteGuild(uint32 guild_id)
@@ -539,8 +512,8 @@ bool BaseGuildManager::SetPublicNote(uint32 charid, std::string public_note)
uint32 BaseGuildManager::UpdateDbCreateGuild(std::string name, uint32 leader)
{
auto new_id = _GetFreeGuildID();
if (new_id == GUILD_NONE) {
auto new_id = GuildsRepository::GetMaxId(*m_db) + 1;
if (!new_id) {
return GUILD_NONE;
}
@@ -1090,7 +1063,7 @@ bool BaseGuildManager::IsGuildLeader(uint32 guild_id, uint32 char_id) const
LogGuilds("Check leader for char [{}]: invalid guild", char_id);
return (false); //invalid guild
}
LogGuilds("Check leader for guild [{}]\, char [{}]\: leader id=[{}]", guild_id, char_id, res->second->leader);
LogGuilds("Check leader for guild [{}], char [{}]: leader id=[{}]", guild_id, char_id, res->second->leader);
return (char_id == res->second->leader);
}
+12 -3
View File
@@ -75,9 +75,18 @@ class BaseGuildManager
virtual ~BaseGuildManager();
//this must be called before doing anything else with this object
void SetDatabase(Database *db)
BaseGuildManager * SetDatabase(Database *db)
{
m_db = db;
return this;
}
BaseGuildManager * SetContentDatabase(Database *db)
{
m_content_db = db;
return this;
}
bool LoadGuilds();
@@ -194,11 +203,11 @@ class BaseGuildManager
std::map<uint32, GuildInfo *> m_guilds; //we own the pointers in this map
void ClearGuilds(); //clears internal structure
Database *m_db; //we do not own this
Database *m_db;
Database *m_content_db;
bool _StoreGuildDB(uint32 guild_id);
GuildInfo* _CreateGuild(uint32 guild_id, std::string guild_name, uint32 leader_char_id, uint8 minstatus, std::string guild_motd, std::string motd_setter, std::string Channel, std::string URL, uint32 favour);
uint32 _GetFreeGuildID();
GuildsRepository::Guilds CreateGuildRepoFromGuildInfo(uint32 guild_id, BaseGuildManager::GuildInfo& in);
};
#endif /*GUILD_BASE_H_*/
+11
View File
@@ -1801,6 +1801,17 @@ uint32 EQ::ItemInstance::GetItemGuildFavor() const
return 0;
}
std::vector<uint32> EQ::ItemInstance::GetAugmentIDs() const
{
std::vector<uint32> augments;
for (uint8 slot_id = invaug::SOCKET_BEGIN; slot_id <= invaug::SOCKET_END; slot_id++) {
augments.push_back(GetAugment(slot_id) ? GetAugmentItemID(slot_id) : 0);
}
return augments;
}
//
// class EvolveInfo
//
+1
View File
@@ -300,6 +300,7 @@ namespace EQ
int GetItemHeroicCorrup(bool augments = false) const;
int GetItemHaste(bool augments = false) const;
uint32 GetItemGuildFavor() const;
std::vector<uint32> GetAugmentIDs() const;
protected:
//////////////////////////
@@ -24,6 +24,12 @@ public:
uint32_t classes;
uint32_t item_id;
uint8_t item_charges;
uint32_t augment_one;
uint32_t augment_two;
uint32_t augment_three;
uint32_t augment_four;
uint32_t augment_five;
uint32_t augment_six;
uint8_t min_status;
int32_t slot_id;
int8_t min_expansion;
@@ -45,6 +51,12 @@ public:
"classes",
"item_id",
"item_charges",
"augment_one",
"augment_two",
"augment_three",
"augment_four",
"augment_five",
"augment_six",
"min_status",
"slot_id",
"min_expansion",
@@ -62,6 +74,12 @@ public:
"classes",
"item_id",
"item_charges",
"augment_one",
"augment_two",
"augment_three",
"augment_four",
"augment_five",
"augment_six",
"min_status",
"slot_id",
"min_expansion",
@@ -113,6 +131,12 @@ public:
e.classes = 0;
e.item_id = 0;
e.item_charges = 1;
e.augment_one = 0;
e.augment_two = 0;
e.augment_three = 0;
e.augment_four = 0;
e.augment_five = 0;
e.augment_six = 0;
e.min_status = 0;
e.slot_id = -1;
e.min_expansion = -1;
@@ -160,12 +184,18 @@ public:
e.classes = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.item_charges = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 1;
e.min_status = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
e.slot_id = row[6] ? static_cast<int32_t>(atoi(row[6])) : -1;
e.min_expansion = row[7] ? static_cast<int8_t>(atoi(row[7])) : -1;
e.max_expansion = row[8] ? static_cast<int8_t>(atoi(row[8])) : -1;
e.content_flags = row[9] ? row[9] : "";
e.content_flags_disabled = row[10] ? row[10] : "";
e.augment_one = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augment_two = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_three = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_four = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_five = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_six = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.min_status = row[11] ? static_cast<uint8_t>(strtoul(row[11], nullptr, 10)) : 0;
e.slot_id = row[12] ? static_cast<int32_t>(atoi(row[12])) : -1;
e.min_expansion = row[13] ? static_cast<int8_t>(atoi(row[13])) : -1;
e.max_expansion = row[14] ? static_cast<int8_t>(atoi(row[14])) : -1;
e.content_flags = row[15] ? row[15] : "";
e.content_flags_disabled = row[16] ? row[16] : "";
return e;
}
@@ -203,12 +233,18 @@ public:
v.push_back(columns[2] + " = " + std::to_string(e.classes));
v.push_back(columns[3] + " = " + std::to_string(e.item_id));
v.push_back(columns[4] + " = " + std::to_string(e.item_charges));
v.push_back(columns[5] + " = " + std::to_string(e.min_status));
v.push_back(columns[6] + " = " + std::to_string(e.slot_id));
v.push_back(columns[7] + " = " + std::to_string(e.min_expansion));
v.push_back(columns[8] + " = " + std::to_string(e.max_expansion));
v.push_back(columns[9] + " = '" + Strings::Escape(e.content_flags) + "'");
v.push_back(columns[10] + " = '" + Strings::Escape(e.content_flags_disabled) + "'");
v.push_back(columns[5] + " = " + std::to_string(e.augment_one));
v.push_back(columns[6] + " = " + std::to_string(e.augment_two));
v.push_back(columns[7] + " = " + std::to_string(e.augment_three));
v.push_back(columns[8] + " = " + std::to_string(e.augment_four));
v.push_back(columns[9] + " = " + std::to_string(e.augment_five));
v.push_back(columns[10] + " = " + std::to_string(e.augment_six));
v.push_back(columns[11] + " = " + std::to_string(e.min_status));
v.push_back(columns[12] + " = " + std::to_string(e.slot_id));
v.push_back(columns[13] + " = " + std::to_string(e.min_expansion));
v.push_back(columns[14] + " = " + std::to_string(e.max_expansion));
v.push_back(columns[15] + " = '" + Strings::Escape(e.content_flags) + "'");
v.push_back(columns[16] + " = '" + Strings::Escape(e.content_flags_disabled) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -235,6 +271,12 @@ public:
v.push_back(std::to_string(e.classes));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.min_status));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.min_expansion));
@@ -275,6 +317,12 @@ public:
v.push_back(std::to_string(e.classes));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.min_status));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.min_expansion));
@@ -319,12 +367,18 @@ public:
e.classes = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.item_charges = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 1;
e.min_status = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
e.slot_id = row[6] ? static_cast<int32_t>(atoi(row[6])) : -1;
e.min_expansion = row[7] ? static_cast<int8_t>(atoi(row[7])) : -1;
e.max_expansion = row[8] ? static_cast<int8_t>(atoi(row[8])) : -1;
e.content_flags = row[9] ? row[9] : "";
e.content_flags_disabled = row[10] ? row[10] : "";
e.augment_one = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augment_two = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_three = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_four = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_five = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_six = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.min_status = row[11] ? static_cast<uint8_t>(strtoul(row[11], nullptr, 10)) : 0;
e.slot_id = row[12] ? static_cast<int32_t>(atoi(row[12])) : -1;
e.min_expansion = row[13] ? static_cast<int8_t>(atoi(row[13])) : -1;
e.max_expansion = row[14] ? static_cast<int8_t>(atoi(row[14])) : -1;
e.content_flags = row[15] ? row[15] : "";
e.content_flags_disabled = row[16] ? row[16] : "";
all_entries.push_back(e);
}
@@ -354,12 +408,18 @@ public:
e.classes = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.item_charges = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 1;
e.min_status = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
e.slot_id = row[6] ? static_cast<int32_t>(atoi(row[6])) : -1;
e.min_expansion = row[7] ? static_cast<int8_t>(atoi(row[7])) : -1;
e.max_expansion = row[8] ? static_cast<int8_t>(atoi(row[8])) : -1;
e.content_flags = row[9] ? row[9] : "";
e.content_flags_disabled = row[10] ? row[10] : "";
e.augment_one = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augment_two = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_three = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_four = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_five = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_six = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.min_status = row[11] ? static_cast<uint8_t>(strtoul(row[11], nullptr, 10)) : 0;
e.slot_id = row[12] ? static_cast<int32_t>(atoi(row[12])) : -1;
e.min_expansion = row[13] ? static_cast<int8_t>(atoi(row[13])) : -1;
e.max_expansion = row[14] ? static_cast<int8_t>(atoi(row[14])) : -1;
e.content_flags = row[15] ? row[15] : "";
e.content_flags_disabled = row[16] ? row[16] : "";
all_entries.push_back(e);
}
@@ -439,6 +499,12 @@ public:
v.push_back(std::to_string(e.classes));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.min_status));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.min_expansion));
@@ -472,6 +538,12 @@ public:
v.push_back(std::to_string(e.classes));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.min_status));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.min_expansion));
@@ -26,6 +26,12 @@ public:
std::string zone_id_list;
uint32_t item_id;
uint8_t item_charges;
uint32_t augment_one;
uint32_t augment_two;
uint32_t augment_three;
uint32_t augment_four;
uint32_t augment_five;
uint32_t augment_six;
int32_t status;
int32_t inventory_slot;
int8_t min_expansion;
@@ -49,6 +55,12 @@ public:
"zone_id_list",
"item_id",
"item_charges",
"augment_one",
"augment_two",
"augment_three",
"augment_four",
"augment_five",
"augment_six",
"status",
"inventory_slot",
"min_expansion",
@@ -68,6 +80,12 @@ public:
"zone_id_list",
"item_id",
"item_charges",
"augment_one",
"augment_two",
"augment_three",
"augment_four",
"augment_five",
"augment_six",
"status",
"inventory_slot",
"min_expansion",
@@ -121,6 +139,12 @@ public:
e.zone_id_list = "";
e.item_id = 0;
e.item_charges = 1;
e.augment_one = 0;
e.augment_two = 0;
e.augment_three = 0;
e.augment_four = 0;
e.augment_five = 0;
e.augment_six = 0;
e.status = 0;
e.inventory_slot = -1;
e.min_expansion = -1;
@@ -170,12 +194,18 @@ public:
e.zone_id_list = row[4] ? row[4] : "";
e.item_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.item_charges = row[6] ? static_cast<uint8_t>(strtoul(row[6], nullptr, 10)) : 1;
e.status = row[7] ? static_cast<int32_t>(atoi(row[7])) : 0;
e.inventory_slot = row[8] ? static_cast<int32_t>(atoi(row[8])) : -1;
e.min_expansion = row[9] ? static_cast<int8_t>(atoi(row[9])) : -1;
e.max_expansion = row[10] ? static_cast<int8_t>(atoi(row[10])) : -1;
e.content_flags = row[11] ? row[11] : "";
e.content_flags_disabled = row[12] ? row[12] : "";
e.augment_one = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_two = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_three = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_four = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.augment_five = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.augment_six = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
e.status = row[13] ? static_cast<int32_t>(atoi(row[13])) : 0;
e.inventory_slot = row[14] ? static_cast<int32_t>(atoi(row[14])) : -1;
e.min_expansion = row[15] ? static_cast<int8_t>(atoi(row[15])) : -1;
e.max_expansion = row[16] ? static_cast<int8_t>(atoi(row[16])) : -1;
e.content_flags = row[17] ? row[17] : "";
e.content_flags_disabled = row[18] ? row[18] : "";
return e;
}
@@ -215,12 +245,18 @@ public:
v.push_back(columns[4] + " = '" + Strings::Escape(e.zone_id_list) + "'");
v.push_back(columns[5] + " = " + std::to_string(e.item_id));
v.push_back(columns[6] + " = " + std::to_string(e.item_charges));
v.push_back(columns[7] + " = " + std::to_string(e.status));
v.push_back(columns[8] + " = " + std::to_string(e.inventory_slot));
v.push_back(columns[9] + " = " + std::to_string(e.min_expansion));
v.push_back(columns[10] + " = " + std::to_string(e.max_expansion));
v.push_back(columns[11] + " = '" + Strings::Escape(e.content_flags) + "'");
v.push_back(columns[12] + " = '" + Strings::Escape(e.content_flags_disabled) + "'");
v.push_back(columns[7] + " = " + std::to_string(e.augment_one));
v.push_back(columns[8] + " = " + std::to_string(e.augment_two));
v.push_back(columns[9] + " = " + std::to_string(e.augment_three));
v.push_back(columns[10] + " = " + std::to_string(e.augment_four));
v.push_back(columns[11] + " = " + std::to_string(e.augment_five));
v.push_back(columns[12] + " = " + std::to_string(e.augment_six));
v.push_back(columns[13] + " = " + std::to_string(e.status));
v.push_back(columns[14] + " = " + std::to_string(e.inventory_slot));
v.push_back(columns[15] + " = " + std::to_string(e.min_expansion));
v.push_back(columns[16] + " = " + std::to_string(e.max_expansion));
v.push_back(columns[17] + " = '" + Strings::Escape(e.content_flags) + "'");
v.push_back(columns[18] + " = '" + Strings::Escape(e.content_flags_disabled) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -249,6 +285,12 @@ public:
v.push_back("'" + Strings::Escape(e.zone_id_list) + "'");
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.status));
v.push_back(std::to_string(e.inventory_slot));
v.push_back(std::to_string(e.min_expansion));
@@ -291,6 +333,12 @@ public:
v.push_back("'" + Strings::Escape(e.zone_id_list) + "'");
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.status));
v.push_back(std::to_string(e.inventory_slot));
v.push_back(std::to_string(e.min_expansion));
@@ -337,12 +385,18 @@ public:
e.zone_id_list = row[4] ? row[4] : "";
e.item_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.item_charges = row[6] ? static_cast<uint8_t>(strtoul(row[6], nullptr, 10)) : 1;
e.status = row[7] ? static_cast<int32_t>(atoi(row[7])) : 0;
e.inventory_slot = row[8] ? static_cast<int32_t>(atoi(row[8])) : -1;
e.min_expansion = row[9] ? static_cast<int8_t>(atoi(row[9])) : -1;
e.max_expansion = row[10] ? static_cast<int8_t>(atoi(row[10])) : -1;
e.content_flags = row[11] ? row[11] : "";
e.content_flags_disabled = row[12] ? row[12] : "";
e.augment_one = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_two = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_three = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_four = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.augment_five = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.augment_six = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
e.status = row[13] ? static_cast<int32_t>(atoi(row[13])) : 0;
e.inventory_slot = row[14] ? static_cast<int32_t>(atoi(row[14])) : -1;
e.min_expansion = row[15] ? static_cast<int8_t>(atoi(row[15])) : -1;
e.max_expansion = row[16] ? static_cast<int8_t>(atoi(row[16])) : -1;
e.content_flags = row[17] ? row[17] : "";
e.content_flags_disabled = row[18] ? row[18] : "";
all_entries.push_back(e);
}
@@ -374,12 +428,18 @@ public:
e.zone_id_list = row[4] ? row[4] : "";
e.item_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.item_charges = row[6] ? static_cast<uint8_t>(strtoul(row[6], nullptr, 10)) : 1;
e.status = row[7] ? static_cast<int32_t>(atoi(row[7])) : 0;
e.inventory_slot = row[8] ? static_cast<int32_t>(atoi(row[8])) : -1;
e.min_expansion = row[9] ? static_cast<int8_t>(atoi(row[9])) : -1;
e.max_expansion = row[10] ? static_cast<int8_t>(atoi(row[10])) : -1;
e.content_flags = row[11] ? row[11] : "";
e.content_flags_disabled = row[12] ? row[12] : "";
e.augment_one = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_two = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_three = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_four = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.augment_five = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.augment_six = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
e.status = row[13] ? static_cast<int32_t>(atoi(row[13])) : 0;
e.inventory_slot = row[14] ? static_cast<int32_t>(atoi(row[14])) : -1;
e.min_expansion = row[15] ? static_cast<int8_t>(atoi(row[15])) : -1;
e.max_expansion = row[16] ? static_cast<int8_t>(atoi(row[16])) : -1;
e.content_flags = row[17] ? row[17] : "";
e.content_flags_disabled = row[18] ? row[18] : "";
all_entries.push_back(e);
}
@@ -461,6 +521,12 @@ public:
v.push_back("'" + Strings::Escape(e.zone_id_list) + "'");
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.status));
v.push_back(std::to_string(e.inventory_slot));
v.push_back(std::to_string(e.min_expansion));
@@ -496,6 +562,12 @@ public:
v.push_back("'" + Strings::Escape(e.zone_id_list) + "'");
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.status));
v.push_back(std::to_string(e.inventory_slot));
v.push_back(std::to_string(e.min_expansion));
@@ -0,0 +1,392 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_ZONE_FLAGS_REPOSITORY_H
#define EQEMU_BASE_ZONE_FLAGS_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseZoneFlagsRepository {
public:
struct ZoneFlags {
int32_t charID;
int32_t zoneID;
};
static std::string PrimaryKey()
{
return std::string("charID");
}
static std::vector<std::string> Columns()
{
return {
"charID",
"zoneID",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"charID",
"zoneID",
};
}
static std::string ColumnsRaw()
{
return std::string(Strings::Implode(", ", Columns()));
}
static std::string SelectColumnsRaw()
{
return std::string(Strings::Implode(", ", SelectColumns()));
}
static std::string TableName()
{
return std::string("zone_flags");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static ZoneFlags NewEntity()
{
ZoneFlags e{};
e.charID = 0;
e.zoneID = 0;
return e;
}
static ZoneFlags GetZoneFlags(
const std::vector<ZoneFlags> &zone_flagss,
int zone_flags_id
)
{
for (auto &zone_flags : zone_flagss) {
if (zone_flags.charID == zone_flags_id) {
return zone_flags;
}
}
return NewEntity();
}
static ZoneFlags FindOne(
Database& db,
int zone_flags_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
zone_flags_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
ZoneFlags e{};
e.charID = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.zoneID = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int zone_flags_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
zone_flags_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const ZoneFlags &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[0] + " = " + std::to_string(e.charID));
v.push_back(columns[1] + " = " + std::to_string(e.zoneID));
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.charID
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static ZoneFlags InsertOne(
Database& db,
ZoneFlags e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.charID));
v.push_back(std::to_string(e.zoneID));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
Strings::Implode(",", v)
)
);
if (results.Success()) {
e.charID = results.LastInsertedID();
return e;
}
e = NewEntity();
return e;
}
static int InsertMany(
Database& db,
const std::vector<ZoneFlags> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.charID));
v.push_back(std::to_string(e.zoneID));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseInsert(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<ZoneFlags> All(Database& db)
{
std::vector<ZoneFlags> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
ZoneFlags e{};
e.charID = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.zoneID = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<ZoneFlags> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<ZoneFlags> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {}",
BaseSelect(),
where_filter
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
ZoneFlags e{};
e.charID = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.zoneID = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const ZoneFlags &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.charID));
v.push_back(std::to_string(e.zoneID));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<ZoneFlags> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.charID));
v.push_back(std::to_string(e.zoneID));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_ZONE_FLAGS_REPOSITORY_H
File diff suppressed because it is too large Load Diff
@@ -59,6 +59,24 @@ public:
return NewEntity();
}
// insert with ON DUPLICATE KEY UPDATE to leave rows that exist unchanged
static int InsertUpdateMany(Database& db, const std::vector<CharRecipeList>& entries)
{
std::vector<std::string> values;
values.reserve(entries.size());
for (const auto& e: entries)
{
values.emplace_back(fmt::format("({},{},{})", e.char_id, e.recipe_id, e.madecount));
}
auto results = db.QueryDatabase(fmt::format(
"INSERT INTO {0} (char_id, recipe_id, madecount) VALUES {1} ON DUPLICATE KEY UPDATE {2}={2}",
TableName(), fmt::join(values, ","), PrimaryKey()));
return results.Success() ? results.RowsAffected() : 0;
}
};
#endif //EQEMU_CHAR_RECIPE_LIST_REPOSITORY_H
@@ -213,23 +213,23 @@ public:
const glm::vec4& position
)
{
auto results = db.QueryDatabase(
fmt::format(
"UPDATE `{}` SET `is_buried` = 0, `zone_id` = {}, `instance_id` = {}, `x` = {:.2f}, `y` = {:.2f}, `z` = {:.2f}, `heading` = {:.2f}, `time_of_death` = {}, `was_at_graveyard` = 0 WHERE `{}` = {}",
TableName(),
zone_id,
instance_id,
position.x,
position.y,
position.z,
position.w,
std::time(nullptr),
PrimaryKey(),
corpse_id
)
);
auto corpse = FindOne(db, corpse_id);
return results.Success() ? results.RowsAffected() : 0;
if (corpse.id == 0) {
return 0;
}
corpse.is_buried = 0;
corpse.zone_id = zone_id;
corpse.instance_id = instance_id;
corpse.x = position.x;
corpse.y = position.y;
corpse.z = position.z;
corpse.heading = position.w;
corpse.time_of_death = time(nullptr);
corpse.was_at_graveyard = 0;
return UpdateOne(db, corpse);
}
};
@@ -74,9 +74,11 @@ public:
};
}
const auto& m = l.front();
return EXPModifier{
.aa_modifier = l[0].aa_modifier,
.exp_modifier = l[0].exp_modifier
.aa_modifier = m.aa_modifier,
.exp_modifier = m.exp_modifier
};
}
@@ -103,7 +103,7 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT MAX(`number`) FROM `{}` WHERE `zoneid` = {} AND `gridid` = {}",
"SELECT COALESCE(MAX(`number`), 0) FROM `{}` WHERE `zoneid` = {} AND `gridid` = {}",
TableName(),
zone_id,
grid_id
@@ -0,0 +1,50 @@
#ifndef EQEMU_ZONE_FLAGS_REPOSITORY_H
#define EQEMU_ZONE_FLAGS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_zone_flags_repository.h"
class ZoneFlagsRepository: public BaseZoneFlagsRepository {
public:
/**
* This file was auto generated and can be modified and extended upon
*
* Base repository methods are automatically
* generated in the "base" version of this repository. The base repository
* is immutable and to be left untouched, while methods in this class
* are used as extension methods for more specific persistence-layer
* accessors or mutators.
*
* Base Methods (Subject to be expanded upon in time)
*
* Note: Not all tables are designed appropriately to fit functionality with all base methods
*
* InsertOne
* UpdateOne
* DeleteOne
* FindOne
* GetWhere(std::string where_filter)
* DeleteWhere(std::string where_filter)
* InsertMany
* All
*
* Example custom methods in a repository
*
* ZoneFlagsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* ZoneFlagsRepository::GetWhereNeverExpires()
* ZoneFlagsRepository::GetWhereXAndY()
* ZoneFlagsRepository::DeleteWhereXAndY()
*
* Most of the above could be covered by base methods, but if you as a developer
* find yourself re-using logic for other parts of the code, its best to just make a
* method that can be re-used easily elsewhere especially if it can use a base repository
* method and encapsulate filters there
*/
// Custom extended repository methods here
};
#endif //EQEMU_ZONE_FLAGS_REPOSITORY_H
+35 -5
View File
@@ -34,8 +34,8 @@ const char *RuleManager::s_categoryNames[_CatCount + 1] = {
"InvalidCategory"
};
const RuleManager::RuleInfo RuleManager::s_RuleInfo[IntRuleCount + RealRuleCount + BoolRuleCount + 1] = {
/* this is done in three steps so we can reliably get to them by index*/
const RuleManager::RuleInfo RuleManager::s_RuleInfo[IntRuleCount + RealRuleCount + BoolRuleCount + StringRuleCount + 1] = {
/* this is done in three steps, so we can reliably get to them by index*/
#define RULE_INT(category_name, rule_name, default_value, notes) \
{ #category_name ":" #rule_name, Category__##category_name, IntRule, Int__##rule_name, notes },
#include "ruletypes.h"
@@ -45,6 +45,9 @@ const RuleManager::RuleInfo RuleManager::s_RuleInfo[IntRuleCount + RealRuleCount
#define RULE_BOOL(category_name, rule_name, default_value, notes) \
{ #category_name ":" #rule_name, Category__##category_name, BoolRule, Bool__##rule_name, notes },
#include "ruletypes.h"
#define RULE_STRING(category_name, rule_name, default_value, notes) \
{ #category_name ":" #rule_name, Category__##category_name, StringRule, String__##rule_name, notes },
#include "ruletypes.h"
{ "Invalid Rule", _CatCount, IntRule }
};
@@ -114,6 +117,9 @@ bool RuleManager::GetRule(const std::string &rule_name, std::string &rule_value)
case BoolRule:
rule_value = m_RuleBoolValues[index] ? "true" : "false";
break;
case StringRule:
rule_value = m_RuleStringValues[index];
break;
}
return true;
@@ -152,6 +158,10 @@ bool RuleManager::SetRule(const std::string &rule_name, const std::string &rule_
m_RuleBoolValues[index] = static_cast<uint32>(Strings::ToBool(rule_value));
LogRules("Set rule [{}] to value [{}]", rule_name, m_RuleBoolValues[index] == 1 ? "true" : "false");
break;
case StringRule:
m_RuleStringValues[index] = rule_value;
LogRules("Set rule [{}] to value [{}]", rule_name, rule_value);
break;
}
if (db_save) {
@@ -215,11 +225,13 @@ std::string RuleManager::_GetRuleName(RuleType type, uint16 index) {
return s_RuleInfo[index + IntRuleCount].name;
case BoolRule:
return s_RuleInfo[index + IntRuleCount + RealRuleCount].name;
case StringRule:
return s_RuleInfo[index + IntRuleCount + RealRuleCount + StringRuleCount].name;
default:
break;
}
return s_RuleInfo[IntRuleCount + RealRuleCount + BoolRuleCount].name;
return s_RuleInfo[IntRuleCount + RealRuleCount + BoolRuleCount + StringRuleCount].name;
}
//assumes index is valid!
@@ -231,11 +243,13 @@ const std::string &RuleManager::_GetRuleNotes(RuleType type, uint16 index) {
return s_RuleInfo[index + IntRuleCount].notes;
case BoolRule:
return s_RuleInfo[index + IntRuleCount + RealRuleCount].notes;
case StringRule:
return s_RuleInfo[index + IntRuleCount + RealRuleCount + StringRuleCount].notes;
default:
break;
}
return s_RuleInfo[IntRuleCount + RealRuleCount + BoolRuleCount].notes;
return s_RuleInfo[IntRuleCount + RealRuleCount + BoolRuleCount + StringRuleCount].notes;
}
bool RuleManager::LoadRules(Database *db, const std::string &rule_set_name, bool reload) {
@@ -343,6 +357,10 @@ void RuleManager::SaveRules(Database *db, const std::string &rule_set_name) {
for (i = 0; i < BoolRuleCount; i++) {
_SaveRule(db, BoolRule, i);
}
for (i = 0; i < StringRuleCount; i++) {
_SaveRule(db, StringRule, i);
}
}
void RuleManager::_SaveRule(Database *db, RuleType type, uint16 index) {
@@ -367,6 +385,9 @@ void RuleManager::_SaveRule(Database *db, RuleType type, uint16 index) {
case BoolRule:
rule_value = m_RuleBoolValues[index] ? "true" : "false";
break;
case StringRule:
rule_value = m_RuleStringValues[index];
break;
}
const auto& rule_notes = _GetRuleNotes(type, index);
@@ -446,6 +467,10 @@ bool RuleManager::UpdateInjectedRules(Database *db, const std::string &rule_set_
rule_data[r.name].first = fmt::format("{}", m_RuleBoolValues[r.rule_index] ? "true" : "false");
rule_data[r.name].second = &r.notes;
break;
case StringRule:
rule_data[r.name].first = m_RuleStringValues[r.rule_index];
rule_data[r.name].second = &r.notes;
break;
default:
break;
}
@@ -552,7 +577,7 @@ bool RuleManager::RestoreRuleNotes(Database *db)
}
}
return s_RuleInfo[IntRuleCount + RealRuleCount + BoolRuleCount];
return s_RuleInfo[IntRuleCount + RealRuleCount + BoolRuleCount + StringRuleCount];
}(e.rule_name);
if (Strings::Contains(rule.name, e.rule_name)) {
@@ -617,3 +642,8 @@ bool RuleManager::GetBoolRule(RuleManager::BoolType t) const
{
return m_RuleBoolValues[t] == 1;
}
std::string RuleManager::GetStringRule(RuleManager::StringType t) const
{
return m_RuleStringValues[t];
}
+45 -25
View File
@@ -23,6 +23,7 @@
* - RuleI(category, rule) -> fetch an integer rule's value
* - RuleR(category, rule) -> fetch a real (float) rule's value
* - RuleB(category, rule) -> fetch a boolean/flag rule's value
* - RuleS(category, rule) -> fetch a string rule's value
*
*/
@@ -35,6 +36,8 @@
RuleManager::Instance()->GetRealRule( RuleManager::Real__##rule_name )
#define RuleB(category_name, rule_name) \
RuleManager::Instance()->GetBoolRule( RuleManager::Bool__##rule_name )
#define RuleS(category_name, rule_name) \
RuleManager::Instance()->GetStringRule( RuleManager::String__##rule_name )
#include <vector>
@@ -81,6 +84,17 @@ public:
static const int BoolRuleCount = static_cast<int>(_BoolRuleCount);
typedef enum {
#define RULE_STRING(category_name, rule_name, default_value, notes) \
String__##rule_name,
#include "ruletypes.h"
_StringRuleCount
} StringType;
static const int StringRuleCount = static_cast<int>(_StringRuleCount);
typedef enum {
#define RULE_CATEGORY(category_name) \
Category__##category_name,
@@ -99,45 +113,49 @@ public:
static const IntType InvalidInt = _IntRuleCount;
static const RealType InvalidReal = _RealRuleCount;
static const BoolType InvalidBool = _BoolRuleCount;
static const StringType InvalidString = _StringRuleCount;
static const CategoryType InvalidCategory = _CatCount;
static const uint32 RulesCount = IntRuleCount + RealRuleCount + BoolRuleCount;
static const uint32 RulesCount = IntRuleCount + RealRuleCount + BoolRuleCount + StringRuleCount;
//fetch routines, you should generally use the Rule* macros instead of this
int GetIntRule(IntType t) const;
float GetRealRule(RealType t) const;
bool GetBoolRule(BoolType t) const;
std::string GetStringRule(StringType t) const;
//management routines
static std::string GetRuleName(IntType t) { return s_RuleInfo[static_cast<int>(t)].name; }
static std::string GetRuleName(RealType t) { return s_RuleInfo[static_cast<int>(t) + IntRuleCount].name; }
static std::string GetRuleName(BoolType t) { return s_RuleInfo[static_cast<int>(t) + IntRuleCount + RealRuleCount].name; }
static const std::string &GetRuleNotes(IntType t) { return s_RuleInfo[static_cast<int>(t)].notes; }
static const std::string &GetRuleNotes(RealType t) { return s_RuleInfo[static_cast<int>(t) + IntRuleCount].notes; }
static const std::string &GetRuleNotes(BoolType t) { return s_RuleInfo[static_cast<int>(t) + IntRuleCount + RealRuleCount].notes; }
static std::string GetRuleName(StringType t) { return s_RuleInfo[static_cast<int>(t) + IntRuleCount + RealRuleCount + StringRuleCount].name; }
static const std::string& GetRuleNotes(IntType t) { return s_RuleInfo[static_cast<int>(t)].notes; }
static const std::string& GetRuleNotes(RealType t) { return s_RuleInfo[static_cast<int>(t) + IntRuleCount].notes; }
static const std::string& GetRuleNotes(BoolType t) { return s_RuleInfo[static_cast<int>(t) + IntRuleCount + RealRuleCount].notes; }
static const std::string& GetRuleNotes(StringType t) { return s_RuleInfo[static_cast<int>(t) + IntRuleCount + RealRuleCount + StringRuleCount].notes; }
static uint32 CountRules() { return RulesCount; }
static CategoryType FindCategory(const std::string &category_name);
bool ListRules(const std::string &category_name, std::vector <std::string> &l);
bool ListCategories(std::vector <std::string> &l);
bool GetRule(const std::string &rule_name, std::string &rule_value);
static CategoryType FindCategory(const std::string& category_name);
bool ListRules(const std::string& category_name, std::vector<std::string>& l);
bool ListCategories(std::vector<std::string>& l);
bool GetRule(const std::string& rule_name, std::string& rule_value);
bool SetRule(
const std::string &rule_name,
const std::string &rule_value,
Database *db = nullptr,
const std::string& rule_name,
const std::string& rule_value,
Database* db = nullptr,
bool db_save = false,
bool reload = false
);
int GetActiveRulesetID() const { return m_activeRuleset; }
std::string GetActiveRuleset() const { return m_activeName; }
static bool ListRulesets(Database *db, std::map<int, std::string> &l);
static bool ListRulesets(Database* db, std::map<int, std::string>& l);
void ResetRules(bool reload = false);
bool LoadRules(Database *db, const std::string &rule_set_name, bool reload = false);
void SaveRules(Database *db, const std::string &rule_set_name);
bool UpdateInjectedRules(Database *db, const std::string &rule_set_name, bool quiet_update = false);
bool UpdateOrphanedRules(Database *db, bool quiet_update = false);
bool RestoreRuleNotes(Database *db);
bool LoadRules(Database* db, const std::string& rule_set_name, bool reload = false);
void SaveRules(Database* db, const std::string& rule_set_name);
bool UpdateInjectedRules(Database* db, const std::string& rule_set_name, bool quiet_update = false);
bool UpdateOrphanedRules(Database* db, bool quiet_update = false);
bool RestoreRuleNotes(Database* db);
private:
RuleManager();
@@ -147,21 +165,23 @@ private:
int m_activeRuleset;
std::string m_activeName;
int m_RuleIntValues[IntRuleCount];
float m_RuleRealValues[RealRuleCount];
uint32 m_RuleBoolValues[BoolRuleCount];
int m_RuleIntValues[IntRuleCount];
float m_RuleRealValues[RealRuleCount];
uint32 m_RuleBoolValues[BoolRuleCount];
std::string m_RuleStringValues[StringRuleCount];
typedef enum {
IntRule,
RealRule,
BoolRule
BoolRule,
StringRule
} RuleType;
static bool _FindRule(const std::string &rule_name, RuleType &type_into, uint16 &index_into);
static bool _FindRule(const std::string& rule_name, RuleType& type_into, uint16& index_into);
static std::string _GetRuleName(RuleType type, uint16 index);
static const std::string &_GetRuleNotes(RuleType type, uint16 index);
static int _FindOrCreateRuleset(Database *db, const std::string &rule_set_name);
void _SaveRule(Database *db, RuleType type, uint16 index);
static const std::string& _GetRuleNotes(RuleType type, uint16 index);
static int _FindOrCreateRuleset(Database* db, const std::string& rule_set_name);
void _SaveRule(Database* db, RuleType type, uint16 index);
static const char* s_categoryNames[];
typedef struct {
+15 -4
View File
@@ -28,6 +28,9 @@
#ifndef RULE_BOOL
#define RULE_BOOL(cat, rule, default_value, notes)
#endif
#ifndef RULE_STRING
#define RULE_STRING(cat, rule, default_value, notes)
#endif
#ifndef RULE_CATEGORY_END
#define RULE_CATEGORY_END()
#endif
@@ -48,10 +51,10 @@ RULE_BOOL(Character, DeathKeepLevel, false, "Players can not drop below 0% exper
RULE_BOOL(Character, UseDeathExpLossMult, false, "Setting to control whether DeathExpLossMultiplier or the code default is used: (Level x Level / 18.0) x 12000")
RULE_BOOL(Character, UseOldRaceRezEffects, false, "Older clients had ID 757 for races with high starting STR, but it doesn't seem used anymore")
RULE_INT(Character, CorpseDecayTime, 604800000, "Time after which the corpse decays (milliseconds) DEFAULT: 604800000 (7 Days)")
RULE_INT( Character, EmptyCorpseDecayTime, 10800000, "Time after which an empty corpse decays (milliseconds) DEFAULT: 10800000 (3 Hours)")
RULE_INT(Character, EmptyCorpseDecayTime, 10800000, "Time after which an empty corpse decays (milliseconds) DEFAULT: 10800000 (3 Hours)")
RULE_INT(Character, CorpseResTime, 10800000, "Time after which the corpse can no longer be resurrected (milliseconds) DEFAULT: 10800000 (3 Hours)")
RULE_INT( Character, DuelCorpseResTime, 600000, "Time before cant res corpse after a duel (milliseconds) DEFAULT: 600000 (10 Minutes)")
RULE_INT( Character, CorpseOwnerOnlineTime, 30000, "How often corpse will check if its owner is online DEFAULT: 30000 (30 Seconds)")
RULE_INT(Character, DuelCorpseResTime, 600000, "Time before cant res corpse after a duel (milliseconds) DEFAULT: 600000 (10 Minutes)")
RULE_INT(Character, CorpseOwnerOnlineTime, 30000, "How often corpse will check if its owner is online DEFAULT: 30000 (30 Seconds)")
RULE_BOOL(Character, LeaveCorpses, true, "Setting whether you leave a corpse behind")
RULE_BOOL(Character, LeaveNakedCorpses, false, "Setting whether you leave a corpse without items")
RULE_INT(Character, MaxDraggedCorpses, 2, "Maximum number of corpses you can drag at once")
@@ -324,6 +327,9 @@ RULE_INT(World, MaximumQuestErrors, 30, "Changes the maximum number of quest err
RULE_INT(World, BootHour, 0, "Sets the in-game hour world will set when it first boots. 0-24 are valid options, where 0 disables this rule")
RULE_BOOL(World, UseItemLinksForKeyRing, false, "Uses item links for Key Ring Listing instead of item name")
RULE_BOOL(World, UseOldShadowKnightClassExport, true, "Disable to have Shadowknight show as Shadow Knight (live-like)")
RULE_STRING(World, IPExemptionZones, "", "Comma-delimited list of zones to exclude from IP-limit checks. Empty string to disable.")
RULE_STRING(World, MOTD, "", "Server MOTD sent on login, change from empty to have this be used instead of variables table 'motd' value")
RULE_STRING(World, Rules, "", "Server Rules, change from empty to have this be used instead of variables table 'rules' value, lines are pipe (|) separated, example: A|B|C")
RULE_CATEGORY_END()
RULE_CATEGORY(Zone)
@@ -495,6 +501,7 @@ RULE_BOOL(Spells, EvacClearCharmPet, false, "Enable to have evac in zone clear c
RULE_BOOL(Spells, ManaTapsRequireNPCMana, false, "Enabling will require target to have mana to tap. Default off as many npc's are caster class with 0 mana and need fixed.")
RULE_INT(Spells, HarmTouchCritRatio, 200, "Harmtouch crit bonus, on top of BaseCritRatio")
RULE_BOOL(Spells, UseClassicSpellFocus, false, "Enabling will tell the server to handle random focus damage as classic spell imports lack the limit values.")
RULE_BOOL(Spells, ManaTapsOnAnyClass, false, "Enabling this will allow you to cast mana taps on any class, this will bypass ManaTapsRequireNPCMana rule.")
RULE_CATEGORY_END()
RULE_CATEGORY(Combat)
@@ -521,6 +528,7 @@ RULE_REAL(Combat, BaseProcChance, 0.035, "Base chance for procs")
RULE_REAL(Combat, ProcDexDivideBy, 11000, "Divisor for the probability of a proc increased by dexterity")
RULE_INT(Combat, MinRangedAttackDist, 25, "Minimum Distance to use Ranged Attacks")
RULE_BOOL(Combat, ArcheryBonusRequiresStationary, true, "does the 2x archery bonus chance require a stationary npc")
RULE_INT(Combat, ArcheryBonusLevelRequirement, 51, "Level requirement when the 2x archery bonus will be enabled. The default is 51.")
RULE_REAL(Combat, ArcheryNPCMultiplier, 1.0, "Value is multiplied by the regular dmg to get the archery dmg")
RULE_BOOL(Combat, AssistNoTargetSelf, true, "When assisting a target that does not have a target: true = target self, false = leave target as was before assist (false = live like)")
RULE_INT(Combat, MaxRampageTargets, 3, "Maximum number of people hit with rampage")
@@ -569,10 +577,12 @@ RULE_BOOL(Combat, NPCsUseFrontalStunImmunityClasses, false, "Enable or disable N
RULE_INT(Combat, FrontalStunImmunityRaces, 512, "Bitmask for Races than have frontal stun immunity, Ogre (512) only by default.")
RULE_BOOL(Combat, NPCsUseFrontalStunImmunityRaces, true, "Enable or disable NPCs using frontal stun immunity Races from Combat:FrontalStunImmunityRaces, true by default.")
RULE_BOOL(Combat, AssassinateOnlyHumanoids, true, "Enable or disable Assassinate only being allowed on Humanoids, true by default.")
RULE_INT(Combat, AssassinateLevelRequirement, 60, "Level requirement to enable assassinate attempts on backstabs. The default is 60.")
RULE_BOOL(Combat, HeadshotOnlyHumanoids, true, "Enable or disable Headshot only being allowed on Humanoids, true by default.")
RULE_BOOL(Combat, EnableWarriorShielding, true, "Enable or disable Warrior Shielding Ability (/shield), true by default.")
RULE_BOOL(Combat, BackstabIgnoresElemental, false, "Enable or disable Elemental weapon damage affecting backstab damage, false by default.")
RULE_BOOL(Combat, BackstabIgnoresBane, false, "Enable or disable Bane weapon damage affecting backstab damage, false by default.")
RULE_INT(Combat, DoubleBackstabLevelRequirement, 55, "Level requirement to enable double backstab attempts. The default is 55.")
RULE_BOOL(Combat, SummonMeleeRange, true, "Enable or disable summoning of a player when already in melee range of the summoner.")
RULE_BOOL(Combat, WaterMatchRequiredForAutoFireLoS, true, "Enable/Disable the requirement of both the attacker/victim being both in or out of water for AutoFire LoS to pass.")
RULE_INT(Combat, ExtraAllowedKickClassesBitmask, 0, "Bitmask for allowing extra classes beyond Warrior, Ranger, Beastlord, and Berserker to kick, No Extra Classes (0) by default")
@@ -890,7 +900,7 @@ RULE_INT(Expansion, AutoGrantAAExpansion, -1, "Expansion to auto grant AAs up to
RULE_CATEGORY_END()
RULE_CATEGORY(Instances)
RULE_INT(Instances, ReservedInstances, 30, "Number of instance IDs which are reserved for globals. This value should not be changed while a server is running")
RULE_INT(Instances, ReservedInstances, 100, "Number of instance IDs which are reserved for globals. This value should not be changed while a server is running")
RULE_BOOL(Instances, RecycleInstanceIds, true, "Setting whether free instance IDs should be recycled to prevent them from gradually running out at 32k")
RULE_INT(Instances, GuildHallExpirationDays, 90, "Amount of days before a Guild Hall instance expires")
RULE_CATEGORY_END()
@@ -950,4 +960,5 @@ RULE_CATEGORY_END()
#undef RULE_INT
#undef RULE_REAL
#undef RULE_BOOL
#undef RULE_STRING
#undef RULE_CATEGORY_END
+4 -3
View File
@@ -348,7 +348,7 @@ std::string EQ::SayLinkEngine::InjectSaylinksIfNotExist(const char *message)
if (ch != startpos)
{
std::string str(startpos, ch - startpos);
new_message += EQ::SayLinkEngine::GenerateQuestSaylink(str, false, str);
new_message += Saylink::Create(str);
}
in_bracket_state = false;
}
@@ -417,11 +417,12 @@ SaylinkRepository::Saylink EQ::SayLinkEngine::GetOrSaveSaylink(std::string sayli
return {};
}
std::string Saylink::Create(const std::string &saylink_text, bool silent, const std::string &link_name)
std::string Saylink::Create(const std::string& saylink_text, bool silent, const std::string& link_name)
{
return EQ::SayLinkEngine::GenerateQuestSaylink(saylink_text, silent, (link_name.empty() ? saylink_text : link_name));
}
std::string Saylink::Silent(const std::string &saylink_text, const std::string &link_name) {
std::string Saylink::Silent(const std::string& saylink_text, const std::string& link_name)
{
return EQ::SayLinkEngine::GenerateQuestSaylink(saylink_text, true, (link_name.empty() ? saylink_text : link_name));
}
+1 -1
View File
@@ -130,7 +130,7 @@ namespace EQ
class Saylink {
public:
static std::string Create(const std::string &saylink_text, bool silent, const std::string &link_name = "");
static std::string Create(const std::string &saylink_text, bool silent = false, const std::string &link_name = "");
static std::string Silent(const std::string &saylink_text, const std::string &link_name = "");
};
+17 -2
View File
@@ -461,7 +461,13 @@ bool SharedDatabase::SetStartingItems(
{
const EQ::ItemData *item_data;
const auto &l = StartingItemsRepository::All(*this);
const auto& l = StartingItemsRepository::GetWhere(
*this,
fmt::format(
"TRUE {}",
ContentFilterCriteria::apply()
)
);
if (l.empty()) {
return false;
@@ -515,7 +521,16 @@ bool SharedDatabase::SetStartingItems(
continue;
}
const auto *inst = CreateBaseItem(item_data, item_charges);
const auto* inst = CreateItem(
item_data,
item_charges,
e.augment_one,
e.augment_two,
e.augment_three,
e.augment_four,
e.augment_five,
e.augment_six
);
if (slot < EQ::invslot::slotCharm) {
slot = inv->FindFreeSlot(false, false);
+3 -3
View File
@@ -25,7 +25,7 @@
// Build variables
// these get injected during the build pipeline
#define CURRENT_VERSION "22.44.2-dev" // always append -dev to the current version for custom-builds
#define CURRENT_VERSION "22.48.0-dev" // always append -dev to the current version for custom-builds
#define LOGIN_VERSION "0.8.0"
#define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__
@@ -42,8 +42,8 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9262
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9042
#define CURRENT_BINARY_DATABASE_VERSION 9266
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9043
#endif
+225 -891
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "eqemu-server",
"version": "22.44.2",
"version": "22.48.0",
"repository": {
"type": "git",
"url": "https://github.com/EQEmu/Server.git"
+1
View File
@@ -168,6 +168,7 @@ int main(int argc, char **argv)
content_service.SetCurrentExpansion(RuleI(Expansion, CurrentExpansion));
content_service.SetDatabase(&database)
->SetContentDatabase(&content_db)
->SetExpansionContext()
->ReloadContentFlags();
+5 -5
View File
@@ -56,7 +56,7 @@ void Adventure::AddPlayer(std::string character_name, bool add_client_to_instanc
{
if(!PlayerExists(character_name))
{
int32 character_id = database.GetCharacterID(character_name.c_str());
int32 character_id = database.GetCharacterID(character_name);
if(character_id && add_client_to_instance)
{
database.AddClientToInstance(instance_id, character_id);
@@ -72,7 +72,7 @@ void Adventure::RemovePlayer(std::string character_name)
{
if((*iter).compare(character_name) == 0)
{
int32 character_id = database.GetCharacterID(character_name.c_str());
int32 character_id = database.GetCharacterID(character_name);
if (character_id)
{
database.RemoveClientFromInstance(instance_id, character_id);
@@ -312,7 +312,7 @@ void Adventure::Finished(AdventureWinStatus ws)
}
zoneserver_list.SendPacket(current->zone(), current->instance(), pack);
database.UpdateAdventureStatsEntry(database.GetCharacterID((*iter).c_str()), GetTemplate()->theme, (ws != AWS_Lose) ? true : false);
database.UpdateAdventureStatsEntry(database.GetCharacterID((*iter)), GetTemplate()->theme, (ws != AWS_Lose) ? true : false);
delete pack;
}
else
@@ -337,7 +337,7 @@ void Adventure::Finished(AdventureWinStatus ws)
afe.points = 0;
}
adventure_manager.AddFinishedEvent(afe);
database.UpdateAdventureStatsEntry(database.GetCharacterID((*iter).c_str()), GetTemplate()->theme, (ws != AWS_Lose) ? true : false);
database.UpdateAdventureStatsEntry(database.GetCharacterID((*iter)), GetTemplate()->theme, (ws != AWS_Lose) ? true : false);
}
}
else
@@ -363,7 +363,7 @@ void Adventure::Finished(AdventureWinStatus ws)
}
adventure_manager.AddFinishedEvent(afe);
database.UpdateAdventureStatsEntry(database.GetCharacterID((*iter).c_str()), GetTemplate()->theme, (ws != AWS_Lose) ? true : false);
database.UpdateAdventureStatsEntry(database.GetCharacterID((*iter)), GetTemplate()->theme, (ws != AWS_Lose) ? true : false);
}
++iter;
}
+197 -208
View File
@@ -50,7 +50,9 @@
#include "../common/zone_store.h"
#include "../common/repositories/account_repository.h"
#include "../common/repositories/player_event_logs_repository.h"
#include "../common/repositories/inventory_repository.h"
#include "../common/events/player_event_logs.h"
#include "../common/content/world_content_service.h"
#include <iostream>
#include <iomanip>
@@ -598,79 +600,63 @@ bool Client::HandleNameApprovalPacket(const EQApplicationPacket *app)
}
bool Client::HandleGenerateRandomNamePacket(const EQApplicationPacket *app) {
// creates up to a 10 char name
char vowels[18]="aeiouyaeiouaeioe";
char cons[48]="bcdfghjklmnpqrstvwxzybcdgklmnprstvwbcdgkpstrkd";
char rndname[17]="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
char paircons[33]="ngrkndstshthphsktrdrbrgrfrclcr";
int rndnum=emu_random.Int(0, 75),n=1;
bool dlc=false;
bool vwl=false;
bool dbl=false;
if (rndnum>63)
{ // rndnum is 0 - 75 where 64-75 is cons pair, 17-63 is cons, 0-16 is vowel
rndnum=(rndnum-61)*2; // name can't start with "ng" "nd" or "rk"
rndname[0]=paircons[rndnum];
rndname[1]=paircons[rndnum+1];
n=2;
}
else if (rndnum>16)
{
rndnum-=17;
rndname[0]=cons[rndnum];
}
else
{
rndname[0]=vowels[rndnum];
vwl=true;
}
int namlen=emu_random.Int(5, 10);
for (int i=n;i<namlen;i++)
{
dlc=false;
if (vwl) //last char was a vowel
{ // so pick a cons or cons pair
rndnum=emu_random.Int(0, 62);
if (rndnum>46)
{ // pick a cons pair
if (i>namlen-3) // last 2 chars in name?
{ // name can only end in cons pair "rk" "st" "sh" "th" "ph" "sk" "nd" or "ng"
rndnum=emu_random.Int(0, 7)*2;
}
else
{ // pick any from the set
rndnum=(rndnum-47)*2;
}
rndname[i]=paircons[rndnum];
rndname[i+1]=paircons[rndnum+1];
dlc=true; // flag keeps second letter from being doubled below
i+=1;
}
else
{ // select a single cons
rndname[i]=cons[rndnum];
char newName[17] = {0};
bool unique = false;
while (!unique) {
std::string cons = "bcdfghjklmnpqrstvwxyz";
std::string vows = "aeou";
std::string allVows = "aeiou";
std::vector<std::string> endPhon = {"a", "e", "i", "o", "u", "os", "as", "us", "is", "y", "an", "en", "in", "on", "un"};
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> lenDist(5, 10);
std::uniform_int_distribution<int> firstCharDist(0, 1);
std::uniform_int_distribution<int> consDist(0, cons.size() - 1);
std::uniform_int_distribution<int> vowDist(0, vows.size() - 1);
std::uniform_int_distribution<int> allVowDist(0, allVows.size() - 1);
std::uniform_int_distribution<int> endPhonDist(0, endPhon.size() - 1);
int len = 0;
memset(newName, 0, sizeof(newName));
if (firstCharDist(gen) == 0) {
newName[len++] = vows[vowDist(gen)];
newName[len++] = cons[consDist(gen)];
} else {
newName[len++] = cons[consDist(gen)];
newName[len++] = allVows[allVowDist(gen)];
}
newName[0] = toupper(newName[0]);
while (len < lenDist(gen) - 1) {
if (len % 2 == 0) {
newName[len++] = cons[consDist(gen)];
} else {
newName[len++] = allVows[allVowDist(gen)];
}
}
else
{ // select a vowel
rndname[i]=vowels[emu_random.Int(0, 16)];
std::string end = endPhon[endPhonDist(gen)];
for (char c : end) {
if (len < 10) newName[len++] = c;
}
vwl=!vwl;
if (!dbl && !dlc)
{ // one chance at double letters in name
if (!emu_random.Int(0, i+9)) // chances decrease towards end of name
{
rndname[i+1]=rndname[i];
dbl=true;
i+=1;
if (database.CheckNameFilter(newName)) {
std::string query = StringFormat("SELECT `name` FROM `character_data` WHERE `name` = '%s'", newName);
auto res = database.QueryDatabase(query);
if (res.Success() && res.RowCount() == 0) {
unique = true;
}
}
}
rndname[0]=toupper(rndname[0]);
NameGeneration_Struct* ngs = (NameGeneration_Struct*)app->pBuffer;
memset(ngs->name,0,64);
strcpy(ngs->name,rndname);
memset(ngs->name, 0, 64);
strcpy(ngs->name, newName);
QueuePacket(app);
return true;
@@ -786,6 +772,18 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
return true;
}
auto r = content_service.FindZone(zone_id, instance_id);
if (r.zone_id && r.instance.id != instance_id) {
LogInfo(
"Zone [{}] has been remapped to instance_id [{}] from instance_id [{}] for client [{}]",
r.zone.short_name,
r.instance.id,
instance_id,
char_name
);
instance_id = r.instance.id;
}
// Make sure this account owns this character
if (temporary_account_id != account_id) {
LogInfo("Account [{}] does not own the character named [{}] from account [{}]", account_id, char_name, temporary_account_id);
@@ -902,14 +900,19 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
}
auto outapp = new EQApplicationPacket(OP_MOTD);
std::string motd_message;
if (database.GetVariable("MOTD", motd_message)) {
outapp->size = motd_message.length() + 1;
std::string motd = RuleS(World, MOTD);
if (!motd.empty()) {
outapp->size = motd.length() + 1;
outapp->pBuffer = new uchar[outapp->size];
memset(outapp->pBuffer, 0, outapp->size);
strcpy((char*)outapp->pBuffer, motd_message.c_str());
strcpy((char*) outapp->pBuffer, motd.c_str());
} else if (database.GetVariable("MOTD", motd)) {
outapp->size = motd.length() + 1;
outapp->pBuffer = new uchar[outapp->size];
memset(outapp->pBuffer, 0, outapp->size);
strcpy((char*) outapp->pBuffer, motd.c_str());
} else { // Null Message of the Day. :)
outapp->size = 1;
outapp->size = 1;
outapp->pBuffer = new uchar[outapp->size];
outapp->pBuffer[0] = 0;
}
@@ -1613,10 +1616,18 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
inv.SetInventoryVersion(EQ::versions::ConvertClientVersionBitToClientVersion(m_ClientVersionBit));
inv.SetGMInventory(false); // character cannot have gm flag at this point
time_t bday = time(nullptr);
time_t bday = time(nullptr);
in_addr in;
int stats_sum = cc->STR + cc->STA + cc->AGI + cc->DEX + cc->WIS + cc->INT + cc->CHA;
const uint32 stats_sum = (
cc->AGI +
cc->CHA +
cc->DEX +
cc->INT +
cc->STA +
cc->STR +
cc->WIS
);
in.s_addr = GetIP();
@@ -1629,7 +1640,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
);
LogInfo("Name [{}]", name);
LogInfo(
"Race [{}] Class [{}] Gender [{}] Deity [{}] Start zone [{}] Tutorial [{}]",
"race [{}] class [{}] gender [{}] deity [{}] start_zone [{}] tutorial [{}]",
cc->race,
cc->class_,
cc->gender,
@@ -1637,21 +1648,20 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
cc->start_zone,
cc->tutorial ? "true" : "false"
);
LogInfo("STR STA AGI DEX WIS INT CHA Total");
LogInfo(
" [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}]",
cc->STR,
cc->STA,
"AGI [{}] CHA [{}] DEX [{}] INT [{}] STA [{}] STR [{}] WIS [{}] Total [{}]",
cc->AGI,
cc->DEX,
cc->WIS,
cc->INT,
cc->CHA,
cc->DEX,
cc->INT,
cc->STA,
cc->STR,
cc->WIS,
stats_sum
);
LogInfo("Face [{}] Eye colors [{}] [{}]", cc->face, cc->eyecolor1, cc->eyecolor2);
LogInfo("Hairstyle [{}] Haircolor [{}]", cc->hairstyle, cc->haircolor);
LogInfo("Beard [{}] Beardcolor [{}]", cc->beard, cc->beardcolor);
LogInfo("Face [{}] Eye Colors [{}] [{}]", cc->face, cc->eyecolor1, cc->eyecolor2);
LogInfo("Hair [{}] Hair Color [{}]", cc->hairstyle, cc->haircolor);
LogInfo("Beard [{}] Beard Color [{}]", cc->beard, cc->beardcolor);
/* Validate the char creation struct */
if (m_ClientVersionBit & EQ::versions::maskSoFAndLater) {
@@ -1669,39 +1679,39 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
/* Convert incoming cc_s to the new PlayerProfile_Struct */
memset(&pp, 0, sizeof(PlayerProfile_Struct)); // start building the profile
strn0cpy(pp.name, name, 63);
strn0cpy(pp.name, name, sizeof(pp.name));
pp.race = cc->race;
pp.class_ = cc->class_;
pp.gender = cc->gender;
pp.deity = cc->deity;
pp.STR = cc->STR;
pp.STA = cc->STA;
pp.AGI = cc->AGI;
pp.DEX = cc->DEX;
pp.WIS = cc->WIS;
pp.INT = cc->INT;
pp.CHA = cc->CHA;
pp.face = cc->face;
pp.eyecolor1 = cc->eyecolor1;
pp.eyecolor2 = cc->eyecolor2;
pp.hairstyle = cc->hairstyle;
pp.haircolor = cc->haircolor;
pp.beard = cc->beard;
pp.beardcolor = cc->beardcolor;
pp.drakkin_heritage = cc->drakkin_heritage;
pp.drakkin_tattoo = cc->drakkin_tattoo;
pp.drakkin_details = cc->drakkin_details;
pp.birthday = bday;
pp.lastlogin = bday;
pp.level = 1;
pp.points = 5;
pp.cur_hp = 1000; // 1k hp during dev only
pp.hunger_level = 6000;
pp.thirst_level = 6000;
pp.race = cc->race;
pp.class_ = cc->class_;
pp.gender = cc->gender;
pp.deity = cc->deity;
pp.STR = cc->STR;
pp.STA = cc->STA;
pp.AGI = cc->AGI;
pp.DEX = cc->DEX;
pp.WIS = cc->WIS;
pp.INT = cc->INT;
pp.CHA = cc->CHA;
pp.face = cc->face;
pp.eyecolor1 = cc->eyecolor1;
pp.eyecolor2 = cc->eyecolor2;
pp.hairstyle = cc->hairstyle;
pp.haircolor = cc->haircolor;
pp.beard = cc->beard;
pp.beardcolor = cc->beardcolor;
pp.drakkin_heritage = cc->drakkin_heritage;
pp.drakkin_tattoo = cc->drakkin_tattoo;
pp.drakkin_details = cc->drakkin_details;
pp.birthday = bday;
pp.lastlogin = bday;
pp.level = 1;
pp.points = 5;
pp.cur_hp = 1000;
pp.hunger_level = 6000;
pp.thirst_level = 6000;
/* Set default skills for everybody */
pp.skills[EQ::skills::SkillSwimming] = RuleI(Skills, SwimmingStartValue);
pp.skills[EQ::skills::SkillSwimming] = RuleI(Skills, SwimmingStartValue);
pp.skills[EQ::skills::SkillSenseHeading] = RuleI(Skills, SenseHeadingStartValue);
/* Set Racial and Class specific language and skills */
@@ -1710,13 +1720,12 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
SetClassStartingSkills(&pp);
SetClassLanguages(&pp);
// strcpy(pp.servername, WorldConfig::get()->ShortName.c_str());
memset(pp.spell_book, std::numeric_limits<uint8>::max(), (sizeof(uint32) * EQ::spells::SPELLBOOK_SIZE));
memset(pp.mem_spells, std::numeric_limits<uint8>::max(), (sizeof(uint32) * EQ::spells::SPELL_GEM_COUNT));
memset(pp.spell_book, 0xFF, (sizeof(uint32) * EQ::spells::SPELLBOOK_SIZE));
memset(pp.mem_spells, 0xFF, (sizeof(uint32) * EQ::spells::SPELL_GEM_COUNT));
for (auto& buff : pp.buffs)
buff.spellid = 0xFFFF;
for (auto& b : pp.buffs) {
b.spellid = std::numeric_limits<uint16>::max();
}
/* If server is PVP by default, make all character set to it. */
pp.pvp = database.GetServerType() == 1 ? 1 : 0;
@@ -1728,56 +1737,38 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
pp.zone_id = RuleI(World, SoFStartZoneID);
cc->start_zone = pp.zone_id;
}
}
else {
} else {
LogInfo("Found [TitaniumStartZoneID] rule setting [{}]", RuleI(World, TitaniumStartZoneID));
if (RuleI(World, TitaniumStartZoneID) > 0) { /* if there's a startzone variable put them in there */
pp.zone_id = RuleI(World, TitaniumStartZoneID);
pp.zone_id = RuleI(World, TitaniumStartZoneID);
cc->start_zone = pp.zone_id;
}
}
/* use normal starting zone logic to either get defaults, or if startzone was set, load that from the db table.*/
bool ValidStartZone = content_db.GetStartZone(&pp, cc, m_ClientVersionBit & EQ::versions::maskTitaniumAndEarlier);
if (!ValidStartZone){
/* use normal starting zone logic to either get defaults, or if startzone was set, load that from the db table.*/
const bool is_valid_start_zone = content_db.GetStartZone(&pp, cc, m_ClientVersionBit & EQ::versions::maskTitaniumAndEarlier);
if (!is_valid_start_zone){
return false;
}
/* just in case */
if (!pp.zone_id) {
pp.zone_id = 1; // qeynos
pp.zone_id = Zones::QEYNOS;
pp.x = pp.y = pp.z = -1;
}
/* Set Home Binds -- yep, all of them */
pp.binds[1].zone_id = pp.zone_id;
pp.binds[1].x = pp.x;
pp.binds[1].y = pp.y;
pp.binds[1].z = pp.z;
pp.binds[1].heading = pp.heading;
pp.binds[2].zone_id = pp.zone_id;
pp.binds[2].x = pp.x;
pp.binds[2].y = pp.y;
pp.binds[2].z = pp.z;
pp.binds[2].heading = pp.heading;
pp.binds[3].zone_id = pp.zone_id;
pp.binds[3].x = pp.x;
pp.binds[3].y = pp.y;
pp.binds[3].z = pp.z;
pp.binds[3].heading = pp.heading;
pp.binds[4].zone_id = pp.zone_id;
pp.binds[4].x = pp.x;
pp.binds[4].y = pp.y;
pp.binds[4].z = pp.z;
pp.binds[4].heading = pp.heading;
for (uint8 slot_id = 1; slot_id < 5; slot_id++) {
pp.binds[slot_id].zone_id = pp.zone_id;
pp.binds[slot_id].x = pp.x;
pp.binds[slot_id].y = pp.y;
pp.binds[slot_id].z = pp.z;
pp.binds[slot_id].heading = pp.heading;
}
/* Overrides if we have the tutorial flag set! */
if (cc->tutorial && RuleB(World, EnableTutorialButton)) {
pp.zone_id = RuleI(World, TutorialZoneID);
auto z = GetZone(pp.zone_id);
if (z) {
pp.x = z->safe_x;
@@ -1787,17 +1778,17 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
}
/* Will either be the same as home or tutorial if enabled. */
if(RuleB(World, StartZoneSameAsBindOnCreation)) {
if (RuleB(World, StartZoneSameAsBindOnCreation)) {
pp.binds[0].zone_id = pp.zone_id;
pp.binds[0].x = pp.x;
pp.binds[0].y = pp.y;
pp.binds[0].z = pp.z;
pp.binds[0].x = pp.x;
pp.binds[0].y = pp.y;
pp.binds[0].z = pp.z;
pp.binds[0].heading = pp.heading;
}
if (GetZone(pp.zone_id)) {
LogInfo(
"Current location [{}] [{}] [{:.2f}] [{:.2f}] [{:.2f}] [{:.2f}]",
"Current location zone_short_name [{}] zone_id [{}] x [{:.2f}] y [{:.2f}] z [{:.2f}] heading [{:.2f}]",
ZoneName(pp.zone_id),
pp.zone_id,
pp.x,
@@ -1809,37 +1800,34 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
if (GetZone(pp.binds[0].zone_id)) {
LogInfo(
"Bind location [{}] [{}] [{:.2f}] [{:.2f}] [{:.2f}]",
"Bind location zone_short_name [{}] zone_id [{}] x [{:.2f}] y [{:.2f}] z [{:.2f}] heading [{:.2f}]",
ZoneName(pp.binds[0].zone_id),
pp.binds[0].zone_id,
pp.binds[0].x,
pp.binds[0].y,
pp.binds[0].z
pp.binds[0].z,
pp.binds[4].heading
);
}
if (GetZone(pp.binds[4].zone_id)) {
LogInfo(
"Home location [{}] [{}] [{:.2f}] [{:.2f}] [{:.2f}]",
"Home location zone_short_name [{}] zone_id [{}] x [{:.2f}] y [{:.2f}] z [{:.2f}] heading [{:.2f}]",
ZoneName(pp.binds[4].zone_id),
pp.binds[4].zone_id,
pp.binds[4].x,
pp.binds[4].y,
pp.binds[4].z
pp.binds[4].z,
pp.binds[4].heading
);
}
/* Starting Items inventory */
content_db.SetStartingItems(&pp, &inv, pp.race, pp.class_, pp.deity, pp.zone_id, pp.name, GetAdmin());
// now we give the pp and the inv we made to StoreCharacter
// to see if we can store it
if (!StoreCharacter(GetAccountID(), &pp, &inv)) {
LogInfo("Character creation failed: [{}]", pp.name);
return false;
}
LogInfo("Character creation successful: [{}]", pp.name);
return true;
const bool success = StoreCharacter(GetAccountID(), &pp, &inv);
LogInfo("Character creation {} for [{}]", success ? "succeeded" : "failed", pp.name);
return success;
}
// returns true if the request is ok, false if there's an error
@@ -2312,56 +2300,57 @@ bool Client::StoreCharacter(
EQ::InventoryProfile *p_inventory_profile
)
{
uint32 character_id = 0;
char zone[50];
character_id = database.GetCharacterID(p_player_profile_struct->name);
const uint32 character_id = database.GetCharacterID(p_player_profile_struct->name);
if (!character_id) {
LogError("StoreCharacter: no character id");
return false;
}
const char *zone_name = ZoneName(p_player_profile_struct->zone_id);
if (zone_name == nullptr) {
/* Zone not in the DB, something to prevent crash... */
strn0cpy(zone, "qeynos", 49);
p_player_profile_struct->zone_id = 1;
}
else {
strn0cpy(zone, zone_name, 49);
const std::string& zone_name = zone_store.GetZoneName(p_player_profile_struct->zone_id, true);
if (Strings::EqualFold(zone_name, "UNKNOWN")) {
p_player_profile_struct->zone_id = Zones::QEYNOS;
}
database.SaveCharacterCreate(character_id, account_id, p_player_profile_struct);
std::string invquery;
for (int16 i = EQ::invslot::EQUIPMENT_BEGIN; i <= EQ::invbag::BANK_BAGS_END;) {
const EQ::ItemInstance *new_inventory_item = p_inventory_profile->GetItem(i);
if (new_inventory_item) {
invquery = StringFormat(
"INSERT INTO `inventory` (charid, slotid, itemid, charges, color) VALUES (%u, %i, %u, %i, %u)",
character_id,
i,
new_inventory_item->GetItem()->ID,
new_inventory_item->GetCharges(),
new_inventory_item->GetColor()
);
std::vector<InventoryRepository::Inventory> v;
auto results = database.QueryDatabase(invquery);
auto e = InventoryRepository::NewEntity();
e.charid = character_id;
for (int16 slot_id = EQ::invslot::EQUIPMENT_BEGIN; slot_id <= EQ::invbag::BANK_BAGS_END;) {
const auto inst = p_inventory_profile->GetItem(slot_id);
if (inst) {
e.slotid = slot_id;
e.itemid = inst->GetItem()->ID;
e.charges = inst->GetCharges();
e.color = inst->GetColor();
e.augslot1 = inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN);
e.augslot2 = inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN + 1);
e.augslot3 = inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN + 2);
e.augslot4 = inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN + 3);
e.augslot5 = inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN + 4);
e.augslot6 = inst->GetAugmentItemID(EQ::invaug::SOCKET_END);
v.emplace_back(e);
}
if (i == EQ::invslot::slotCursor) {
i = EQ::invbag::GENERAL_BAGS_BEGIN;
if (slot_id == EQ::invslot::slotCursor) {
slot_id = EQ::invbag::GENERAL_BAGS_BEGIN;
continue;
} else if (slot_id == EQ::invbag::CURSOR_BAG_END) {
slot_id = EQ::invslot::BANK_BEGIN;
continue;
} else if (slot_id == EQ::invslot::BANK_END) {
slot_id = EQ::invbag::BANK_BAGS_BEGIN;
continue;
}
else if (i == EQ::invbag::CURSOR_BAG_END) {
i = EQ::invslot::BANK_BEGIN;
continue;
}
else if (i == EQ::invslot::BANK_END) {
i = EQ::invbag::BANK_BAGS_BEGIN;
continue;
}
i++;
slot_id++;
}
if (!v.empty()) {
InventoryRepository::InsertMany(database, v);
}
return true;
@@ -2388,7 +2377,7 @@ void Client::RecordPossibleHack(const std::string& message)
}
}
void Client::SendGuildTributeFavorAndTimer(uint32 favor, uint32 time_remaining)
void Client::SendGuildTributeFavorAndTimer(uint32 favor, uint32 time_remaining)
{
auto cle = GetCLE();
if (!cle) {
+17
View File
@@ -94,8 +94,25 @@ void ClientList::GetCLEIP(uint32 in_ip) {
int count = 0;
iterator.Reset();
const auto& zones = Strings::Split(RuleS(World, IPExemptionZones), ",");
while (iterator.MoreElements()) {
cle = iterator.GetData();
if (!zones.empty() && cle->zone()) {
auto it = std::ranges::find_if(
zones,
[cle](const auto& z) {
return Strings::ToUnsignedInt(z) == cle->zone();
}
);
if (it != zones.end()) {
iterator.Advance();
continue;
}
}
if (
cle->GetIP() == in_ip &&
(
+1
View File
@@ -142,6 +142,7 @@ std::vector<Reload> reload_types = {
Reload{.command = "base_data", .opcode = ServerOP_ReloadBaseData, .desc = "Base Data"},
Reload{.command = "blocked_spells", .opcode = ServerOP_ReloadBlockedSpells, .desc = "Blocked Spells"},
Reload{.command = "commands", .opcode = ServerOP_ReloadCommands, .desc = "Commands"},
Reload{.command = "content_flags", .opcode = ServerOP_ReloadContentFlags, .desc = "Content Flags"},
Reload{.command = "data_buckets_cache", .opcode = ServerOP_ReloadDataBucketsCache, .desc = "Data Buckets Cache"},
Reload{.command = "doors", .opcode = ServerOP_ReloadDoors, .desc = "Doors"},
Reload{.command = "dztemplates", .opcode = ServerOP_ReloadDzTemplates, .desc = "Dynamic Zone Templates"},
+5
View File
@@ -188,6 +188,11 @@ int main(int argc, char **argv)
RegisterConsoleFunctions(console);
}
content_service.SetDatabase(&database)
->SetContentDatabase(&content_db)
->SetExpansionContext()
->ReloadContentFlags();
std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
server_connection = std::make_unique<EQ::Net::ServertalkServer>();
+22 -3
View File
@@ -230,13 +230,23 @@ void WorldGuildManager::ProcessZonePacket(ServerPacket *pack) {
case ServerOP_GuildChannel:
case ServerOP_GuildURL:
case ServerOP_GuildMemberRemove:
case ServerOP_GuildMemberAdd:
case ServerOP_GuildSendGuildList:
case ServerOP_GuildMembersList:
{
zoneserver_list.SendPacketToBootedZones(pack);
break;
}
case ServerOP_GuildMemberAdd:
{
auto in = (ServerOP_GuildMessage_Struct *)pack->pBuffer;
auto guild = GetGuildByGuildID(in->guild_id);
if (!guild) {
BaseGuildManager::RefreshGuild(in->guild_id);
}
zoneserver_list.SendPacketToBootedZones(pack);
break;
}
default:
LogGuilds("Unknown packet {:#04x} received from zone??", pack->opcode);
break;
@@ -325,7 +335,7 @@ bool WorldGuildManager::LoadTributes()
tribute_list.clear();
auto tributes = TributesRepository::All(*m_db);
auto tributes = TributesRepository::All(*m_content_db);
for (auto const& t : tributes) {
td.name = t.name;
td.description = t.descr;
@@ -336,7 +346,7 @@ bool WorldGuildManager::LoadTributes()
LogInfo("Loaded [{}] tributes", Strings::Commify(tributes.size()));
auto tribute_levels = TributeLevelsRepository::GetWhere(*m_db, "TRUE ORDER BY tribute_id, level");
auto tribute_levels = TributeLevelsRepository::GetWhere(*m_content_db, "TRUE ORDER BY tribute_id, level");
for (auto const& t : tribute_levels) {
uint32 id = t.tribute_id;
@@ -369,6 +379,10 @@ bool WorldGuildManager::LoadTributes()
bool WorldGuildManager::RefreshGuild(uint32 guild_id)
{
auto temp_guild = GetGuildByGuildID(guild_id);
if (!temp_guild) {
return false;
}
BaseGuildManager::GuildInfo temp_guild_detail;
if (temp_guild) {
@@ -389,6 +403,11 @@ bool WorldGuildManager::RefreshGuild(uint32 guild_id)
LogGuilds("Found guild id [{}]. Loading details.....", db_guild.id);
_CreateGuild(db_guild.id, db_guild.name, db_guild.leader, db_guild.minstatus, db_guild.motd, db_guild.motd_setter, db_guild.channel, db_guild.url, db_guild.favor);
auto guild = GetGuildByGuildID(guild_id);
if (!guild) {
LogError("Error refreshing guild id {}", guild_id);
return false;
}
auto where_filter = fmt::format("guild_id = '{}'", guild_id);
auto guild_ranks = GuildRanksRepository::GetWhere(*m_db, where_filter);
for (auto const& r : guild_ranks) {
+2 -1
View File
@@ -264,7 +264,7 @@ bool WorldBoot::DatabaseLoadRoutines(int argc, char **argv)
}
}
guild_mgr.SetDatabase(&database);
guild_mgr.SetDatabase(&database)->SetContentDatabase(&content_db);
LogInfo("Purging expired data buckets");
database.PurgeAllDeletedDataBuckets();
@@ -381,6 +381,7 @@ bool WorldBoot::DatabaseLoadRoutines(int argc, char **argv)
LogInfo("Initializing [WorldContentService]");
content_service.SetDatabase(&database)
->SetContentDatabase(&content_db)
->SetExpansionContext()
->ReloadContentFlags();
+2 -1
View File
@@ -1100,7 +1100,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
}
auto smotd = (ServerMotd_Struct*) pack->pBuffer;
database.SetVariable("MOTD", smotd->motd);
RuleManager::Instance()->SetRule("MOTD", smotd->motd, &database, true, true);
zoneserver_list.SendPacket(pack);
break;
}
@@ -1367,6 +1367,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
}
case ServerOP_ReloadOpcodes: {
ReloadAllPatches();
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_CZDialogueWindow:
+3
View File
@@ -51,6 +51,7 @@ SET(zone_sources
loot.cpp
lua_bot.cpp
lua_bit.cpp
lua_buff.cpp
lua_corpse.cpp
lua_client.cpp
lua_door.cpp
@@ -105,6 +106,7 @@ SET(zone_sources
pathfinder_null.cpp
pathing.cpp
perl_bot.cpp
perl_buff.cpp
perl_client.cpp
perl_doors.cpp
perl_entity.cpp
@@ -207,6 +209,7 @@ SET(zone_headers
horse.h
lua_bot.h
lua_bit.h
lua_buff.h
lua_client.h
lua_corpse.h
lua_door.h
+25 -15
View File
@@ -621,28 +621,38 @@ bool Mob::IsAttackAllowed(Mob *target, bool isSpellAttack)
// NPC *npc1, *npc2;
int reverse;
if(!zone->CanDoCombat())
return false;
// some special cases
if(!target)
return false;
if(this == target) // you can attack yourself
return true;
if(target->GetSpecialAbility(NO_HARM_FROM_CLIENT)){
if (!zone->CanDoCombat()) {
return false;
}
if (target->GetSpecialAbility(IMMUNE_DAMAGE_CLIENT) && IsClient())
// some special cases
if (!target) {
return false;
}
if (target->GetSpecialAbility(IMMUNE_DAMAGE_NPC) && IsNPC())
return false;
if (this == target) { // you can attack yourself
return true;
}
if (target->IsHorse())
if (target->GetSpecialAbility(NO_HARM_FROM_CLIENT)) {
return false;
}
if (IsBot() && target->GetSpecialAbility(IMMUNE_DAMAGE_BOT)) {
return false;
}
if (IsClient() && target->GetSpecialAbility(IMMUNE_DAMAGE_CLIENT)) {
return false;
}
if (IsNPC() && target->GetSpecialAbility(IMMUNE_DAMAGE_NPC)) {
return false;
}
if (target->IsHorse()) {
return false;
}
// can't damage own pet (applies to everthing)
Mob *target_owner = target->GetOwner();
+79 -54
View File
@@ -1005,7 +1005,7 @@ double Mob::RollD20(int offense, int mitigation)
auto atk_roll = zone->random.Roll0(offense + 5);
auto def_roll = zone->random.Roll0(mitigation + 5);
int avg = (offense + mitigation + 10) / 2;
int avg = std::max(1, (offense + mitigation + 10) / 2);
int index = std::max(0, (atk_roll - def_roll) + (avg / 2));
index = EQ::Clamp((index * 20) / avg, 0, 19);
@@ -1164,14 +1164,27 @@ int64 Mob::GetWeaponDamage(Mob *against, const EQ::ItemInstance *weapon_item, in
// check for items being illegally attained
if (weapon_item) {
if (!weapon_item->GetItem())
if (!weapon_item->GetItem()) {
return 0;
}
if (weapon_item->GetItemRequiredLevel(true) > GetLevel())
if (weapon_item->GetItemRequiredLevel(true) > GetLevel()) {
return 0;
}
if (!weapon_item->IsEquipable(GetBaseRace(), GetClass()))
if (!weapon_item->IsClassEquipable(GetClass())) {
return 0;
}
if (
!weapon_item->IsRaceEquipable(GetBaseRace()) &&
(
!IsBot() ||
(IsBot() && !RuleB(Bots, AllowBotEquipAnyRaceGear))
)
) {
return 0;
}
}
if (against->GetSpecialAbility(IMMUNE_MELEE_NONMAGICAL)) {
@@ -1674,13 +1687,6 @@ bool Mob::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
}
}
//used by complete heal and #heal
void Mob::Heal()
{
SetMaxHP();
SendHPUpdate();
}
void Client::Damage(Mob* other, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable, int8 buffslot, bool iBuffTic, eSpecialAttacks special)
{
if (dead || IsCorpse())
@@ -2605,12 +2611,6 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
}
if (m.member) {
m.member->RecordKilledNPCEvent(this);
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_KILLED_MERIT)) {
parse->EventNPC(EVENT_KILLED_MERIT, this, m.member, "killed", 0);
}
if (RuleB(NPC, EnableMeritBasedFaction)) {
m.member->SetFactionLevel(
m.member->CharacterID(),
@@ -2670,18 +2670,11 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
}
}
/* Send the EVENT_KILLED_MERIT event and update kill tasks
* for all group members */
/* Update kill tasks for all group members */
for (const auto& m : killer_group->members) {
if (m && m->IsClient()) {
Client* c = m->CastToClient();
c->RecordKilledNPCEvent(this);
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_KILLED_MERIT)) {
parse->EventNPC(EVENT_KILLED_MERIT, this, c, "killed", 0);
}
if (RuleB(NPC, EnableMeritBasedFaction)) {
c->SetFactionLevel(
c->CharacterID(),
@@ -2743,13 +2736,6 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
}
}
/* Send the EVENT_KILLED_MERIT event */
give_exp_client->RecordKilledNPCEvent(this);
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_KILLED_MERIT)) {
parse->EventNPC(EVENT_KILLED_MERIT, this, give_exp_client, "killed", 0);
}
if (RuleB(NPC, EnableMeritBasedFaction)) {
give_exp_client->SetFactionLevel(
give_exp_client->CharacterID(),
@@ -2978,14 +2964,29 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
m_combat_record.Stop();
if (give_exp_client && !IsCorpse()) {
const auto& v = give_exp_client->GetRaidOrGroupOrSelf(true);
for (const auto& m : v) {
m->CastToClient()->RecordKilledNPCEvent(this);
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_KILLED_MERIT)) {
parse->EventNPC(EVENT_KILLED_MERIT, this, m, "killed", 0);
}
}
}
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_DEATH_COMPLETE)) {
const auto& export_string = fmt::format(
"{} {} {} {} {}",
"{} {} {} {} {} {} {} {} {}",
killer_mob ? killer_mob->GetID() : 0,
damage,
spell,
static_cast<int>(attack_skill),
entity_id
entity_id,
m_combat_record.GetStartTime(),
m_combat_record.GetEndTime(),
m_combat_record.GetDamageReceived(),
m_combat_record.GetHealingReceived()
);
std::vector<std::any> args = { corpse };
@@ -2996,12 +2997,16 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
// Zone controller process EVENT_DEATH_ZONE (Death events)
if (parse->HasQuestSub(ZONE_CONTROLLER_NPC_ID, EVENT_DEATH_ZONE)) {
const auto& export_string = fmt::format(
"{} {} {} {} {}",
"{} {} {} {} {} {} {} {} {}",
killer_mob ? killer_mob->GetID() : 0,
damage,
spell,
static_cast<int>(attack_skill),
entity_id
entity_id,
m_combat_record.GetStartTime(),
m_combat_record.GetEndTime(),
m_combat_record.GetDamageReceived(),
m_combat_record.GetHealingReceived()
);
std::vector<std::any> args = { corpse, this };
@@ -3070,26 +3075,37 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
TryTriggerOnCastRequirement();
}
if (IsClient() && !IsAIControlled())
if (IsClient() && !IsAIControlled()) {
return;
}
if (IsFamiliar() || GetSpecialAbility(IMMUNE_AGGRO))
if (IsFamiliar() || GetSpecialAbility(IMMUNE_AGGRO)) {
return;
}
if (GetSpecialAbility(IMMUNE_AGGRO_NPC) && other->IsNPC())
if (other->IsBot() && GetSpecialAbility(IMMUNE_AGGRO_BOT)) {
return;
}
if (GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && other->IsClient())
if (other->IsClient() && GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) {
return;
}
if (IsValidSpell(spell_id) && IsNoDetrimentalSpellAggroSpell(spell_id))
if (other->IsNPC() && GetSpecialAbility(IMMUNE_AGGRO_NPC)) {
return;
}
if (other == myowner)
if (IsValidSpell(spell_id) && IsNoDetrimentalSpellAggroSpell(spell_id)) {
return;
}
if (other->GetSpecialAbility(IMMUNE_AGGRO_ON))
if (other == myowner) {
return;
}
if (other->GetSpecialAbility(IMMUNE_AGGRO_ON)) {
return;
}
if (GetSpecialAbility(NPC_TUNNELVISION)) {
int tv_mod = GetSpecialAbilityParam(NPC_TUNNELVISION, 0);
@@ -3173,8 +3189,9 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
// owner must get on list, but he's not actually gained any hate yet
if (
!owner->GetSpecialAbility(IMMUNE_AGGRO) &&
!(GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && owner->IsClient()) &&
!(GetSpecialAbility(IMMUNE_AGGRO_NPC) && owner->IsNPC())
!(owner->IsBot() && GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
!(owner->IsClient() && GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
!(owner->IsNPC() && GetSpecialAbility(IMMUNE_AGGRO_NPC))
) {
if (owner->IsClient() && !CheckAggro(owner)) {
owner->CastToClient()->AddAutoXTarget(this);
@@ -3188,8 +3205,9 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
if (
!mypet->IsFamiliar() &&
!mypet->GetSpecialAbility(IMMUNE_AGGRO) &&
!(mypet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && IsClient()) &&
!(mypet->GetSpecialAbility(IMMUNE_AGGRO_NPC) && IsNPC())
!(IsBot() && mypet->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
!(IsClient() && mypet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
!(IsNPC() && mypet->GetSpecialAbility(IMMUNE_AGGRO_NPC))
) {
mypet->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
}
@@ -3198,8 +3216,9 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
if (
myowner->IsAIControlled() &&
!myowner->GetSpecialAbility(IMMUNE_AGGRO) &&
!(GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && myowner->IsClient()) &&
!(GetSpecialAbility(IMMUNE_AGGRO_NPC) && myowner->IsNPC())
!(myowner->IsBot() && GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
!(myowner->IsClient() && GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
!(myowner->IsNPC() && GetSpecialAbility(IMMUNE_AGGRO_NPC))
) {
myowner->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
}
@@ -4039,8 +4058,9 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
!pet->GetSpecialAbility(IMMUNE_AGGRO) &&
!pet->IsEngaged() &&
attacker &&
!(pet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && attacker->IsClient()) &&
!(pet->GetSpecialAbility(IMMUNE_AGGRO_NPC) && attacker->IsNPC()) &&
!(attacker->IsBot() && pet->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
!(attacker->IsClient() && pet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
!(attacker->IsNPC() && pet->GetSpecialAbility(IMMUNE_AGGRO_NPC)) &&
attacker != this &&
!attacker->IsCorpse() &&
!pet->IsGHeld() &&
@@ -4071,6 +4091,10 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
//see if any runes want to reduce this damage
if (!IsValidSpell(spell_id)) {
if (IsClient()) {
CommonBreakInvisible();
}
damage = ReduceDamage(damage);
LogCombat("Melee Damage reduced to [{}]", damage);
damage = ReduceAllDamage(damage);
@@ -4102,8 +4126,9 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
TryTriggerThreshHold(damage, SE_TriggerSpellThreshold, attacker);
}
if (IsClient()) {
CommonBreakInvisible();
if (IsClient() && CastToClient()->sneaking) {
CastToClient()->sneaking = false;
SendAppearancePacket(AppearanceType::Sneak, 0);
}
if (attacker && attacker->IsClient() && attacker->CastToClient()->sneaking) {
@@ -6168,7 +6193,7 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
if (headshot > 0) {
hit.damage_done = headshot;
}
else if (GetClass() == Class::Ranger && GetLevel() > 50) { // no double dmg on headshot
else if (GetClass() == Class::Ranger && GetLevel() >= RuleI(Combat, ArcheryBonusLevelRequirement)) { // no double dmg on headshot
if ((defender->IsNPC() && !defender->IsMoving() && !defender->IsRooted()) || !RuleB(Combat, ArcheryBonusRequiresStationary)) {
hit.damage_done *= 2;
MessageString(Chat::MeleeCrit, BOW_DOUBLE_DAMAGE);
+2 -2
View File
@@ -942,12 +942,12 @@ bool ZoneDatabase::GetAuraEntry(uint16 spell_id, AuraRecord& r)
return false;
}
auto e = l.front();
auto& e = l.front();
strn0cpy(r.name, e.name.c_str(), sizeof(r.name));
r.npc_type = e.npc_type;
r.spell_id = spell_id;
r.spell_id = e.spell_id;
r.distance = e.distance * e.distance;
r.aura_type = e.aura_type;
r.spawn_type = e.spawn_type;
+4 -6
View File
@@ -140,11 +140,8 @@ bool Beacon::Process()
if (caster && spell_iterations-- && max_targets) {
// NPCs should never be affected by an AE they cast. PB AEs shouldn't affect caster either
// I don't think any other cases that get here matter
const bool affect_caster = (
!caster->IsNPC() &&
!caster->IsAIControlled() &&
spells[spell_id].target_type != ST_AECaster
);
const bool affect_caster = (!caster->IsNPC() && !caster->IsAIControlled()) &&
spells[spell_id].target_type != ST_AECaster;
entity_list.AESpell(caster, this, spell_id, affect_caster, resist_adjust, &max_targets);
} else {
// spell is done casting, or caster disappeared
@@ -172,7 +169,8 @@ void Beacon::AELocationSpell(Mob *caster, uint16 cast_spell_id, int16 in_resist_
caster_id = caster->GetID();
spell_id = cast_spell_id;
resist_adjust = in_resist_adjust;
spell_iterations = ((spells[spell_id].aoe_duration / 2500) < 1) ? 1 : spell_iterations;
spell_iterations = spells[spell_id].aoe_duration / 2500;
spell_iterations = spell_iterations < 1 ? 1 : spell_iterations; // at least 1
if (spells[spell_id].aoe_max_targets) {
max_targets = spells[spell_id].aoe_max_targets;
+64 -14
View File
@@ -2684,16 +2684,19 @@ bool Bot::IsValidTarget(
return false;
}
const bool valid_target_state = (
HOLDING ||
bool invalid_target_state = false;
if (HOLDING ||
!tar->IsNPC() ||
tar->IsMezzed() ||
lo_distance > leash_distance ||
tar_distance > leash_distance
);
const bool valid_target = !GetAttackingFlag() && !CheckLosFN(tar) && !leash_owner->CheckLosFN(tar);
tar_distance > leash_distance ||
(!GetAttackingFlag() && !CheckLosFN(tar) && !leash_owner->CheckLosFN(tar)) ||
!IsAttackAllowed(tar)
) {
invalid_target_state = true;
}
if (valid_target_state || valid_target || !IsAttackAllowed(tar)) {
if (invalid_target_state) {
// Normally, we wouldn't want to do this without class checks..but, too many issues can arise if we let enchanter animation pets run rampant
if (HasPet()) {
GetPet()->RemoveFromHateList(tar);
@@ -3630,7 +3633,7 @@ bool Bot::RemoveBotFromGroup(Bot* bot, Group* group) {
if (group->DelMember(bot)) {
group->DelMemberOOZ(bot->GetName());
database.SetGroupID(bot->GetCleanName(), 0, bot->GetBotID());
if (group->GroupCount() < 1) {
if (group->GroupCount() < 2) {
group->DisbandGroup();
}
}
@@ -7640,18 +7643,58 @@ void Bot::SetDefaultBotStance() {
_botStance = defaultStance;
}
void Bot::BotGroupSay(Mob *speaker, const char *msg, ...) {
void Bot::BotGroupSay(Mob* speaker, const char* msg, ...) {
char buf[1000];
va_list ap;
va_start(ap, msg);
vsnprintf(buf, 1000, msg, ap);
va_end(ap);
if (speaker->HasGroup()) {
Group *g = speaker->GetGroup();
if (g)
g->GroupMessage(speaker->CastToMob(), Language::CommonTongue, Language::MaxValue, buf);
} else
speaker->Say("%s", buf);
if (speaker->IsRaidGrouped()) {
Raid* r = entity_list.GetRaidByBotName(speaker->GetName());
if (r) {
for (const auto& m : r->members) {
if (m.member && !m.is_bot) {
m.member->FilteredMessageString(
speaker,
Chat::PetResponse,
FilterSocials,
GENERIC_SAY,
speaker->GetCleanName(),
buf
);
}
}
}
}
else if (speaker->HasGroup()) {
Group* g = speaker->GetGroup();
if (g) {
for (auto& m : g->members) {
if (m && !m->IsBot()) {
m->FilteredMessageString(
speaker,
Chat::PetResponse,
FilterSocials,
GENERIC_SAY,
speaker->GetCleanName(),
buf
);
}
}
}
}
else {
//speaker->Say("%s", buf);
speaker->GetOwner()->FilteredMessageString(
speaker,
Chat::PetResponse,
FilterSocials,
GENERIC_SAY,
speaker->GetCleanName(),
buf
);
}
}
bool Bot::UseDiscipline(uint32 spell_id, uint32 target) {
@@ -8527,10 +8570,17 @@ void Bot::AddBotStartingItems(uint16 race_id, uint8 class_id)
(CanRaceEquipItem(e.item_id) || RuleB(Bots, AllowBotEquipAnyRaceGear))
) {
auto i = BotInventoriesRepository::NewEntity();
i.bot_id = GetBotID();
i.slot_id = e.slot_id;
i.item_id = e.item_id;
i.inst_charges = e.item_charges;
i.augment_1 = e.augment_one;
i.augment_2 = e.augment_two;
i.augment_3 = e.augment_three;
i.augment_4 = e.augment_four;
i.augment_5 = e.augment_five;
i.augment_6 = e.augment_six;
v.emplace_back(i);
}
-12
View File
@@ -2143,23 +2143,19 @@ bool helper_spell_list_fail(Client *bot_owner, bcst_list* spell_list, BCEnum::Sp
#include "bot_commands/escape.cpp"
#include "bot_commands/find_aliases.cpp"
#include "bot_commands/follow.cpp"
#include "bot_commands/follow_distance.cpp"
#include "bot_commands/guard.cpp"
#include "bot_commands/heal_rotation.cpp"
#include "bot_commands/help.cpp"
#include "bot_commands/hold.cpp"
#include "bot_commands/identify.cpp"
#include "bot_commands/inspect_message.cpp"
#include "bot_commands/inventory.cpp"
#include "bot_commands/invisibility.cpp"
#include "bot_commands/item_use.cpp"
#include "bot_commands/levitation.cpp"
#include "bot_commands/list.cpp"
#include "bot_commands/lull.cpp"
#include "bot_commands/mesmerize.cpp"
#include "bot_commands/movement_speed.cpp"
#include "bot_commands/name.cpp"
#include "bot_commands/out_of_combat.cpp"
#include "bot_commands/owner_option.cpp"
#include "bot_commands/pet.cpp"
#include "bot_commands/pick_lock.cpp"
@@ -2167,26 +2163,18 @@ bool helper_spell_list_fail(Client *bot_owner, bcst_list* spell_list, BCEnum::Sp
#include "bot_commands/precombat.cpp"
#include "bot_commands/pull.cpp"
#include "bot_commands/release.cpp"
#include "bot_commands/report.cpp"
#include "bot_commands/resistance.cpp"
#include "bot_commands/resurrect.cpp"
#include "bot_commands/rune.cpp"
#include "bot_commands/send_home.cpp"
#include "bot_commands/size.cpp"
#include "bot_commands/spell.cpp"
#include "bot_commands/stance.cpp"
#include "bot_commands/stop_melee_level.cpp"
#include "bot_commands/suffix.cpp"
#include "bot_commands/summon.cpp"
#include "bot_commands/summon_corpse.cpp"
#include "bot_commands/surname.cpp"
#include "bot_commands/suspend.cpp"
#include "bot_commands/taunt.cpp"
#include "bot_commands/teleport.cpp"
#include "bot_commands/timer.cpp"
#include "bot_commands/toggle_archer.cpp"
#include "bot_commands/toggle_helm.cpp"
#include "bot_commands/track.cpp"
#include "bot_commands/update.cpp"
#include "bot_commands/view_combos.cpp"
#include "bot_commands/water_breathing.cpp"
-1
View File
@@ -1 +0,0 @@
#include "../bot_command.h"
-1
View File
@@ -1 +0,0 @@
#include "../bot_command.h"
-1
View File
@@ -1 +0,0 @@
#include "../bot_command.h"
-1
View File
@@ -1 +0,0 @@
#include "../bot_command.h"
-1
View File
@@ -1 +0,0 @@
#include "../bot_command.h"
-1
View File
@@ -1 +0,0 @@
#include "../bot_command.h"
-1
View File
@@ -1 +0,0 @@
#include "../bot_command.h"
-1
View File
@@ -1 +0,0 @@
#include "../bot_command.h"
-1
View File
@@ -1 +0,0 @@
#include "../bot_command.h"
-1
View File
@@ -1 +0,0 @@
#include "../bot_command.h"
-1
View File
@@ -1 +0,0 @@
#include "../bot_command.h"
-1
View File
@@ -1 +0,0 @@
#include "../bot_command.h"
+64 -1
View File
@@ -1788,7 +1788,8 @@ bool BotDatabase::CreateCloneBotInventory(const uint32 bot_id, const uint32 clon
}
for (auto& e : l) {
e.bot_id = clone_id;
e.inventories_index = 0;
e.bot_id = clone_id;
}
return BotInventoriesRepository::InsertMany(database, l);
@@ -2318,3 +2319,65 @@ bool BotDatabase::SaveBotCasterRange(const uint32 bot_id, const uint32 bot_caste
return BotDataRepository::UpdateOne(database, e);
}
const uint8 BotDatabase::GetBotClassByID(const uint32 bot_id)
{
const auto& e = BotDataRepository::FindOne(database, bot_id);
return e.bot_id ? e.class_ : Class::None;
}
const uint8 BotDatabase::GetBotGenderByID(const uint32 bot_id)
{
const auto& e = BotDataRepository::FindOne(database, bot_id);
return e.bot_id ? e.gender : Gender::Neuter;
}
std::vector<uint32> BotDatabase::GetBotIDsByCharacterID(const uint32 character_id, uint8 class_id)
{
std::vector<uint32> v;
const auto& l = BotDataRepository::GetWhere(
database,
fmt::format(
"`owner_id` = {}{}",
character_id,
(
class_id ?
fmt::format(
" AND `class` = {}",
class_id
) :
""
)
)
);
for (const auto& e : l) {
v.push_back(e.bot_id);
}
return v;
}
const uint8 BotDatabase::GetBotLevelByID(const uint32 bot_id)
{
const auto& e = BotDataRepository::FindOne(database, bot_id);
return e.bot_id ? e.level : 0;
}
const std::string BotDatabase::GetBotNameByID(const uint32 bot_id)
{
const auto& e = BotDataRepository::FindOne(database, bot_id);
return e.bot_id ? e.name : std::string();
}
const uint16 BotDatabase::GetBotRaceByID(const uint32 bot_id)
{
const auto& e = BotDataRepository::FindOne(database, bot_id);
return e.bot_id ? e.race : Race::Doug;
}
+7
View File
@@ -160,6 +160,13 @@ public:
uint32 GetRaceClassBitmask(uint32 bot_race);
const uint8 GetBotClassByID(const uint32 bot_id);
const uint8 GetBotGenderByID(const uint32 bot_id);
std::vector<uint32> GetBotIDsByCharacterID(const uint32 character_id, uint8 class_id = Class::None);
const uint8 GetBotLevelByID(const uint32 bot_id);
const std::string GetBotNameByID(const uint32 bot_id);
const uint16 GetBotRaceByID(const uint32 bot_id);
class fail {
public:
/* fail::Bot functions */
+223 -49
View File
@@ -68,9 +68,11 @@ extern volatile bool RunLoops;
#include "../common/repositories/discovered_items_repository.h"
#include "../common/repositories/inventory_repository.h"
#include "../common/repositories/keyring_repository.h"
#include "../common/repositories/tradeskill_recipe_repository.h"
#include "../common/events/player_events.h"
#include "../common/events/player_event_logs.h"
#include "dialogue_window.h"
#include "../common/zone_store.h"
extern QueryServ* QServ;
@@ -283,6 +285,7 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
PendingSacrifice = false;
controlling_boat_id = 0;
controlled_mob_id = 0;
qGlobals = nullptr;
if (!RuleB(Character, PerCharacterQglobalMaxLevel) && !RuleB(Character, PerCharacterBucketMaxLevel)) {
SetClientMaxLevel(0);
@@ -310,7 +313,6 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
aa_los_them_mob = nullptr;
los_status = false;
los_status_facing = false;
qGlobals = nullptr;
HideCorpseMode = HideCorpseNone;
PendingGuildInvitation = false;
@@ -2293,29 +2295,23 @@ void Client::ReadBook(BookRequest_Struct *book) {
BookText_Struct *out = (BookText_Struct *) outapp->pBuffer;
out->window = book->window;
if (ClientVersion() >= EQ::versions::ClientVersion::SoF) {
// SoF+ need to look up book type for the output message.
const EQ::ItemInstance *inst = nullptr;
if (book->invslot <= EQ::invbag::GENERAL_BAGS_END)
{
inst = m_inv[book->invslot];
}
if(inst)
out->type = inst->GetItem()->Book;
else
out->type = book->type;
}
else {
out->type = book->type;
}
out->type = book->type;
out->invslot = book->invslot;
out->target_id = book->target_id;
out->can_cast = 0; // todo: implement
out->can_scribe = 0; // todo: implement
out->can_scribe = false;
if (ClientVersion() >= EQ::versions::ClientVersion::SoF && book->invslot <= EQ::invbag::GENERAL_BAGS_END)
{
const EQ::ItemInstance* inst = m_inv[book->invslot];
if (inst && inst->GetItem())
{
auto recipe = TradeskillRecipeRepository::GetWhere(content_db,
fmt::format("learned_by_item_id = {} LIMIT 1", inst->GetItem()->ID));
out->type = inst->GetItem()->Book;
out->can_scribe = !recipe.empty();
}
}
memcpy(out->booktext, booktxt2.c_str(), length);
@@ -3790,14 +3786,12 @@ void Client::GetRaidAAs(RaidLeadershipAA_Struct *into) const {
void Client::EnteringMessages(Client* client)
{
std::string rules;
if (database.GetVariable("Rules", rules)) {
uint8 flag = database.GetAgreementFlag(client->AccountID());
std::string rules = RuleS(World, Rules);
if (!rules.empty() || database.GetVariable("Rules", rules)) {
const uint8 flag = database.GetAgreementFlag(client->AccountID());
if (!flag) {
auto rules_link = Saylink::Silent(
"#serverrules",
"rules"
);
const std::string& rules_link = Saylink::Silent("#serverrules", "rules");
client->Message(
Chat::White,
@@ -3814,9 +3808,9 @@ void Client::EnteringMessages(Client* client)
void Client::SendRules()
{
std::string rules;
std::string rules = RuleS(World, Rules);
if (!database.GetVariable("Rules", rules)) {
if (rules.empty() && !database.GetVariable("Rules", rules)) {
return;
}
@@ -6284,7 +6278,17 @@ void Client::SendZonePoints()
zp->zpe[i].z = data->target_z;
zp->zpe[i].heading = data->target_heading;
zp->zpe[i].zoneid = data->target_zone_id;
zp->zpe[i].zoneinstance = data->target_zone_instance;
// if the target zone is the same as the current zone, use the instance of the current zone
// if we don't use the same instance_id that the client was sent, the client will forcefully
// issue a zone change request when they should be simply moving to a different point in the same zone
// because the client will think the zone point target is different from the current instance
auto target_instance = data->target_zone_instance;
if (data->target_zone_id == zone->GetZoneID() && data->target_zone_instance == 0) {
target_instance = zone->GetInstanceID();
}
zp->zpe[i].zoneinstance = target_instance;
i++;
}
iterator.Advance();
@@ -6609,13 +6613,72 @@ void Client::SendAltCurrencies() {
void Client::SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount)
{
if (!zone->DoesAlternateCurrencyExist(currency_id)) {
return;
}
const uint32 current_amount = alternate_currency[currency_id];
const bool is_gain = new_amount > current_amount;
const uint32 change_amount = is_gain ? (new_amount - current_amount) : (current_amount - new_amount);
if (!change_amount) {
return;
}
alternate_currency[currency_id] = new_amount;
database.UpdateAltCurrencyValue(CharacterID(), currency_id, new_amount);
SendAlternateCurrencyValue(currency_id);
QuestEventID event_id = is_gain ? EVENT_ALT_CURRENCY_GAIN : EVENT_ALT_CURRENCY_LOSS;
if (parse->PlayerHasQuestSub(event_id)) {
const std::string &export_string = fmt::format(
"{} {} {}",
currency_id,
change_amount,
new_amount
);
parse->EventPlayer(event_id, this, export_string, 0);
}
}
bool Client::RemoveAlternateCurrencyValue(uint32 currency_id, uint32 amount)
{
if (!amount || !zone->DoesAlternateCurrencyExist(currency_id)) {
return false;
}
const uint32 current_amount = alternate_currency[currency_id];
if (current_amount < amount) {
return false;
}
const uint32 new_amount = (current_amount - amount);
alternate_currency[currency_id] = new_amount;
if (parse->PlayerHasQuestSub(EVENT_ALT_CURRENCY_LOSS)) {
const std::string &export_string = fmt::format(
"{} {} {}",
currency_id,
amount,
new_amount
);
parse->EventPlayer(EVENT_ALT_CURRENCY_LOSS, this, export_string, 0);
}
return true;
}
int Client::AddAlternateCurrencyValue(uint32 currency_id, int amount, bool is_scripted)
{
if (!zone->DoesAlternateCurrencyExist(currency_id)) {
return 0;
}
/* Added via Quest, rest of the logging methods may be done inline due to information available in that area of the code */
if (is_scripted) {
/* QS: PlayerLogAlternateCurrencyTransactions :: Cursor to Item Storage */
@@ -6654,7 +6717,6 @@ int Client::AddAlternateCurrencyValue(uint32 currency_id, int amount, bool is_sc
SendAlternateCurrencyValue(currency_id);
QuestEventID event_id = amount > 0 ? EVENT_ALT_CURRENCY_GAIN : EVENT_ALT_CURRENCY_LOSS;
if (parse->PlayerHasQuestSub(event_id)) {
const std::string &export_string = fmt::format(
"{} {} {}",
@@ -6695,6 +6757,10 @@ void Client::SendAlternateCurrencyValue(uint32 currency_id, bool send_if_null)
uint32 Client::GetAlternateCurrencyValue(uint32 currency_id) const
{
if (!zone->DoesAlternateCurrencyExist(currency_id)) {
return 0;
}
auto iter = alternate_currency.find(currency_id);
return iter == alternate_currency.end() ? 0 : (*iter).second;
@@ -6764,23 +6830,36 @@ void Client::UpdateClientXTarget(Client *c)
// IT IS NOT SAFE TO CALL THIS IF IT'S NOT INITIAL AGGRO
void Client::AddAutoXTarget(Mob *m, bool send)
{
if (m->IsBot() || ((m->IsPet() || m->IsTempPet()) && m->IsPetOwnerBot())) {
return;
}
m_activeautohatermgr->increment_count(m);
if (!XTargettingAvailable() || !XTargetAutoAddHaters || IsXTarget(m))
if (!XTargettingAvailable() || !XTargetAutoAddHaters || IsXTarget(m)) {
return;
}
for(int i = 0; i < GetMaxXTargets(); ++i)
{
if((XTargets[i].Type == Auto) && (XTargets[i].ID == 0))
{
for (int i = 0; i < GetMaxXTargets(); ++i) {
if (XTargets[i].Type == Auto && XTargets[i].ID == 0) {
XTargets[i].ID = m->GetID();
if (send) // if we don't send we're bulk sending updates later on
if (send) { // if we don't send we're bulk sending updates later on
SendXTargetPacket(i, m);
else
} else {
XTargets[i].dirty = true;
}
break;
}
}
LogXTargets(
"Adding [{}] to [{}] ({}) XTargets",
m->GetCleanName(),
GetCleanName(),
GetID()
);
}
void Client::RemoveXTarget(Mob *m, bool OnlyAutoSlots)
@@ -6789,15 +6868,23 @@ void Client::RemoveXTarget(Mob *m, bool OnlyAutoSlots)
// now we may need to clean up our CurrentTargetNPC entries
for (int i = 0; i < GetMaxXTargets(); ++i) {
if (XTargets[i].Type == CurrentTargetNPC && XTargets[i].ID == m->GetID()) {
XTargets[i].Type = Auto;
XTargets[i].ID = 0;
XTargets[i].Type = Auto;
XTargets[i].ID = 0;
XTargets[i].dirty = true;
}
}
auto r = GetRaid();
if (r) {
r->UpdateRaidXTargets();
}
LogXTargets(
"Removing [{}] from [{}] ({}) XTargets",
m->GetCleanName(),
GetCleanName(),
GetID()
);
}
void Client::UpdateXTargetType(XTargetType Type, Mob *m, const char *Name)
@@ -9108,6 +9195,7 @@ void Client::ShowDevToolsMenu()
*/
menu_show += Saylink::Silent("#showzonepoints", "Zone Points");
menu_show += " | " + Saylink::Silent("#showzonegloballoot", "Zone Global Loot");
menu_show += " | " + Saylink::Silent("#show content_flags", "Content Flags");
/**
* Reload
@@ -9165,14 +9253,6 @@ void Client::ShowDevToolsMenu()
Message(Chat::White, "Developer Tools Menu");
Message(
Chat::White,
fmt::format(
"Current Expansion | {}",
content_service.GetCurrentExpansionName()
).c_str()
);
Message(
Chat::White,
fmt::format(
@@ -9288,6 +9368,36 @@ void Client::ShowDevToolsMenu()
);
SendChatLineBreak();
Message(
Chat::White,
fmt::format(
"Current Expansion | {} ({})",
content_service.GetCurrentExpansionName(),
content_service.GetCurrentExpansion()
).c_str()
);
auto z = GetZoneVersionWithFallback(zone->GetZoneID(), zone->GetInstanceVersion());
if (z) {
Message(
Chat::White,
fmt::format(
"Current Zone | [{}] ({}) version [{}] instance_id [{}] min/max expansion ({}/{}) content_flags [{}]",
z->short_name,
z->long_name,
z->version,
zone->GetInstanceID(),
z->min_expansion,
z->max_expansion,
z->content_flags
).c_str()
);
}
SendChatLineBreak();
}
void Client::SendChatLineBreak(uint16 color) {
@@ -11418,6 +11528,39 @@ void Client::SetLockSavePosition(bool lock_save_position)
Client::m_lock_save_position = lock_save_position;
}
void Client::SetAAPoints(uint32 points)
{
const uint32 current_points = m_pp.aapoints;
m_pp.aapoints = points;
QuestEventID event_id = points > current_points ? EVENT_AA_GAIN : EVENT_AA_LOSS;
const uint32 change = event_id == EVENT_AA_GAIN ? points - current_points : current_points - points;
if (parse->PlayerHasQuestSub(event_id)) {
parse->EventPlayer(event_id, this, std::to_string(change), 0);
}
SendAlternateAdvancementStats();
}
bool Client::RemoveAAPoints(uint32 points)
{
if (m_pp.aapoints < points) {
return false;
}
m_pp.aapoints -= points;
if (parse->PlayerHasQuestSub(EVENT_AA_LOSS)) {
parse->EventPlayer(EVENT_AA_LOSS, this, std::to_string(points), 0);
}
SendAlternateAdvancementStats();
return true;
}
void Client::AddAAPoints(uint32 points)
{
m_pp.aapoints += points;
@@ -12170,3 +12313,34 @@ int Client::GetEXPPercentage()
return static_cast<int>(std::round(scaled * 100.0 / 330.0)); // unscaled pct
}
std::vector<Mob*> Client::GetRaidOrGroupOrSelf(bool clients_only)
{
std::vector<Mob*> v;
if (IsRaidGrouped()) {
Raid* r = GetRaid();
if (r) {
for (const auto& m : r->members) {
if (m.member && (!m.is_bot || !clients_only)) {
v.emplace_back(m.member);
}
}
}
} else if (IsGrouped()) {
Group* g = GetGroup();
if (g) {
for (const auto& m : g->members) {
if (m && (m->IsClient() || !clients_only)) {
v.emplace_back(m);
}
}
}
} else {
v.emplace_back(this);
}
return v;
}
+7 -2
View File
@@ -272,6 +272,8 @@ public:
int GetQuiverHaste(int delay);
void DoAttackRounds(Mob *target, int hand, bool IsFromSpell = false);
std::vector<Mob*> GetRaidOrGroupOrSelf(bool clients_only = false);
void AI_Init();
void AI_Start(uint32 iMoveDelay = 0);
void AI_Stop();
@@ -348,6 +350,7 @@ public:
int GetRecipeMadeCount(uint32 recipe_id);
bool HasRecipeLearned(uint32 recipe_id);
bool CanIncreaseTradeskill(EQ::skills::SkillType tradeskill);
void ScribeRecipes(uint32_t item_id) const;
bool GetRevoked() const { return revoked; }
void SetRevoked(bool rev) { revoked = rev; }
@@ -933,8 +936,9 @@ public:
void ResetAlternateAdvancementTimers();
void ResetOnDeathAlternateAdvancement();
void SetAAPoints(uint32 points) { m_pp.aapoints = points; SendAlternateAdvancementStats(); }
void SetAAPoints(uint32 points);
void AddAAPoints(uint32 points);
bool RemoveAAPoints(uint32 points);
int GetAAPoints() { return m_pp.aapoints; }
int GetSpentAA() { return m_pp.aapoints_spent; }
uint32 GetRequiredAAExperience();
@@ -1090,7 +1094,7 @@ public:
void SetPEQZoneFlag(uint32 zone_id);
bool CanFish();
void GoFish();
void GoFish(bool guarantee = false, bool use_bait = true);
void ForageItem(bool guarantee = false);
//Calculate vendor price modifier based on CHA: (reverse==selling)
float CalcPriceMod(Mob* other = 0, bool reverse = false);
@@ -1539,6 +1543,7 @@ public:
void SendAltCurrencies();
void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount);
int AddAlternateCurrencyValue(uint32 currency_id, int amount, bool is_scripted = false);
bool RemoveAlternateCurrencyValue(uint32 currency_id, uint32 amount);
void SendAlternateCurrencyValues();
void SendAlternateCurrencyValue(uint32 currency_id, bool send_if_null = true);
uint32 GetAlternateCurrencyValue(uint32 currency_id) const;
+18 -13
View File
@@ -954,7 +954,6 @@ void Client::CompleteConnect()
heroforge_wearchange_timer.Start(250);
RecordStats();
AutoGrantAAPoints();
// enforce some rules..
@@ -4169,10 +4168,11 @@ void Client::Handle_OP_BookButton(const EQApplicationPacket* app)
BookButton_Struct* book = reinterpret_cast<BookButton_Struct*>(app->pBuffer);
const EQ::ItemInstance* const inst = GetInv().GetItem(book->invslot);
if (inst && inst->GetItem()->Book)
if (inst && inst->GetItem())
{
// todo: if scribe book learn recipes and delete book from inventory
// todo: if cast book use its spell on target and delete book from inventory (unless reusable?)
// todo: cast spell button (unknown if anything on live uses this)
ScribeRecipes(inst->GetItem()->ID);
DeleteItemInInventory(book->invslot, 1, true);
}
EQApplicationPacket outapp(OP_FinishWindow, 0);
@@ -7760,15 +7760,6 @@ void Client::Handle_OP_GuildBank(const EQApplicationPacket *app)
case GuildBankDeposit: // Deposit Item
{
if (GuildBanks->IsAreaFull(GuildID(), GuildBankDepositArea))
{
MessageString(Chat::Red, GUILD_BANK_FULL);
GuildBankDepositAck(true, sentAction);
return;
}
EQ::ItemInstance *CursorItemInst = GetInv().GetItem(EQ::invslot::slotCursor);
bool Allowed = true;
@@ -7784,6 +7775,18 @@ void Client::Handle_OP_GuildBank(const EQApplicationPacket *app)
const EQ::ItemData* CursorItem = CursorItemInst->GetItem();
if (GuildBanks->IsAreaFull(GuildID(), GuildBankDepositArea))
{
MessageString(Chat::Red, GUILD_BANK_FULL);
GuildBankDepositAck(true, sentAction);
if (ClientVersion() >= EQ::versions::ClientVersion::RoF) {
GetInv().PopItem(EQ::invslot::slotCursor);
PushItemOnCursor(CursorItem, true);
}
return;
}
if (!CursorItem->NoDrop || CursorItemInst->IsAttuned())
{
Allowed = false;
@@ -7811,6 +7814,7 @@ void Client::Handle_OP_GuildBank(const EQApplicationPacket *app)
GuildBankDepositAck(true, sentAction);
if (ClientVersion() >= EQ::versions::ClientVersion::RoF) {
GetInv().PopItem(EQ::invslot::slotCursor);
PushItemOnCursor(CursorItem, true);
}
return;
@@ -17138,3 +17142,4 @@ void Client::Handle_OP_GuildTributeDonatePlat(const EQApplicationPacket *app)
RequestGuildFavorAndTimer(GuildID());
}
}
+7 -7
View File
@@ -1064,15 +1064,15 @@ void Client::OPRezzAnswer(uint32 Action, uint32 SpellID, uint16 ZoneID, uint16 I
);
SpellOnTarget(resurrection_sickness_spell_id, this);
} else if (SpellID == SPELL_DIVINE_REZ) {
SetHP(GetMaxHP());
SetMana(GetMaxMana());
SetEndurance(GetMaxEndurance());
RestoreHealth();
RestoreMana();
RestoreEndurance();
} else {
SetHP(GetMaxHP() / 20);
SetMana(GetMaxMana() / 20);
SetEndurance(GetMaxEndurance() / 20);
}
if(spells[SpellID].base_value[0] < 100 && spells[SpellID].base_value[0] > 0 && PendingRezzXP > 0) {
SetEXP(((int)(GetEXP()+((float)((PendingRezzXP / 100) * spells[SpellID].base_value[0])))),
GetAAXP(),true);
@@ -2177,9 +2177,9 @@ void Client::HandleRespawnFromHover(uint32 Option)
FastQueuePacket(&outapp);
CalcBonuses();
SetHP(GetMaxHP());
SetMana(GetMaxMana());
SetEndurance(GetMaxEndurance());
RestoreHealth();
RestoreMana();
RestoreEndurance();
m_Position.x = chosen->x;
m_Position.y = chosen->y;
+20
View File
@@ -71,3 +71,23 @@ float CombatRecord::GetHealedReceivedPerSecond() const
double time_in_combat = TimeInCombat();
return time_in_combat > 0 ? (m_heal_received / time_in_combat) : m_heal_received;
}
time_t CombatRecord::GetStartTime() const
{
return m_start_time;
}
time_t CombatRecord::GetEndTime() const
{
return m_end_time;
}
int64 CombatRecord::GetDamageReceived() const
{
return m_damage_received;
}
int64 CombatRecord::GetHealingReceived() const
{
return m_heal_received;
}
+4
View File
@@ -14,6 +14,10 @@ public:
double TimeInCombat() const;
float GetDamageReceivedPerSecond() const;
float GetHealedReceivedPerSecond() const;
time_t GetStartTime() const;
time_t GetEndTime() const;
int64 GetDamageReceived() const;
int64 GetHealingReceived() const;
private:
std::string m_mob_name;
time_t m_start_time = 0;
+6
View File
@@ -131,8 +131,10 @@ int command_init(void)
command_add("feature", "Change your or your target's feature's temporarily", AccountStatus::QuestTroupe, command_feature) ||
command_add("size", "Change your targets size (alias of #feature size)", AccountStatus::QuestTroupe, command_feature) ||
command_add("find", "Search command used to find various things", AccountStatus::Guide, command_find) ||
command_add("fish", "Fish for an item", AccountStatus::QuestTroupe, command_fish) ||
command_add("fixmob", "[race|gender|texture|helm|face|hair|haircolor|beard|beardcolor|heritage|tattoo|detail] [next|prev] - Manipulate appearance of your target", AccountStatus::QuestTroupe, command_fixmob) ||
command_add("flagedit", "Edit zone flags on your target. Use #flagedit help for more info.", AccountStatus::GMAdmin, command_flagedit) ||
command_add("forage", "Forage an item", AccountStatus::QuestTroupe, command_forage) ||
command_add("gearup", "Developer tool to quickly equip yourself or your target", AccountStatus::GMMgmt, command_gearup) ||
command_add("giveitem", "[itemid] [charges] - Summon an item onto your target's cursor. Charges are optional.", AccountStatus::GMMgmt, command_giveitem) ||
command_add("givemoney", "[Platinum] [Gold] [Silver] [Copper] - Gives specified amount of money to you or your player target", AccountStatus::GMMgmt, command_givemoney) ||
@@ -206,6 +208,7 @@ int command_init(void)
command_add("scribespells", "[Max level] [Min level] - Scribe all spells for you or your player target that are usable by them, up to level specified. (may freeze client for a few seconds)", AccountStatus::GMLeadAdmin, command_scribespells) ||
command_add("sendzonespawns", "Refresh spawn list for all clients in zone", AccountStatus::GMLeadAdmin, command_sendzonespawns) ||
command_add("sensetrap", "Analog for ldon sense trap for the newer clients since we still don't have it working.", AccountStatus::Player, command_sensetrap) ||
command_add("serverrules", "Show server rules", AccountStatus::Player, command_serverrules) ||
command_add("set", "Set command used to set various things", AccountStatus::Guide, command_set) ||
command_add("show", "Show command used to show various things", AccountStatus::Guide, command_show) ||
command_add("shutdown", "Shut this zone process down", AccountStatus::GMLeadAdmin, command_shutdown) ||
@@ -822,8 +825,10 @@ void command_bot(Client *c, const Seperator *sep)
#include "gm_commands/faction.cpp"
#include "gm_commands/feature.cpp"
#include "gm_commands/find.cpp"
#include "gm_commands/fish.cpp"
#include "gm_commands/fixmob.cpp"
#include "gm_commands/flagedit.cpp"
#include "gm_commands/forage.cpp"
#include "gm_commands/gearup.cpp"
#include "gm_commands/giveitem.cpp"
#include "gm_commands/givemoney.cpp"
@@ -893,6 +898,7 @@ void command_bot(Client *c, const Seperator *sep)
#include "gm_commands/scribespells.cpp"
#include "gm_commands/sendzonespawns.cpp"
#include "gm_commands/sensetrap.cpp"
#include "gm_commands/serverrules.cpp"
#include "gm_commands/set.cpp"
#include "gm_commands/show.cpp"
#include "gm_commands/shutdown.cpp"
+2
View File
@@ -83,8 +83,10 @@ void command_faction(Client *c, const Seperator *sep);
void command_faction_association(Client *c, const Seperator *sep);
void command_feature(Client *c, const Seperator *sep);
void command_find(Client *c, const Seperator *sep);
void command_fish(Client* c, const Seperator* sep);
void command_fixmob(Client *c, const Seperator *sep);
void command_flagedit(Client *c, const Seperator *sep);
void command_forage(Client* c, const Seperator* sep);
void command_gearup(Client *c, const Seperator *sep);
void command_giveitem(Client *c, const Seperator *sep);
void command_givemoney(Client *c, const Seperator *sep);
+2 -1
View File
@@ -826,7 +826,8 @@ struct ExtraAttackOptions {
armor_pen_percent(0.0f), armor_pen_flat(0),
crit_percent(1.0f), crit_flat(0.0f),
hate_percent(1.0f), hate_flat(0), hit_chance(0),
melee_damage_bonus_flat(0), skilldmgtaken_bonus_flat(0)
melee_damage_bonus_flat(0), skilldmgtaken_bonus_flat(0),
range_percent(0)
{ }
float damage_percent;
+1 -1
View File
@@ -334,7 +334,7 @@ void DialogueWindow::Render(Client *c, std::string markdown)
if (responses.size() > 1) {
for (auto &r: responses) {
bracket_responses.emplace_back(
fmt::format("[{}]", Saylink::Create(r, false))
fmt::format("[{}]", Saylink::Create(r))
);
}
}
+9
View File
@@ -73,6 +73,15 @@ Doors::Doors(const DoorsRepository::Doors &door) :
m_door_param = door.door_param;
m_size = door.size;
m_invert_state = door.invert_state;
// if the target zone is the same as the current zone, use the instance of the current zone
// if we don't use the same instance_id that the client was sent, the client will forcefully
// issue a zone change request when they should be simply moving to a different point in the same zone
// because the client will think the zone point target is different from the current instance
if (door.dest_zone == zone->GetShortName() && m_destination_instance_id == 0) {
m_destination_instance_id = zone->GetInstanceID();
}
m_destination_instance_id = door.dest_instance;
m_is_ldon_door = door.is_ldon_door;
m_dz_switch_id = door.dz_switch_id;
+53 -1
View File
@@ -56,6 +56,7 @@ void perl_register_doors();
void perl_register_expedition();
void perl_register_expedition_lock_messages();
void perl_register_bot();
void perl_register_buff();
#endif // EMBPERL_XS_CLASSES
#endif // EMBPERL_XS
@@ -193,6 +194,14 @@ const char* QuestEventSubroutines[_LargestEventID] = {
"EVENT_ALT_CURRENCY_LOSS",
"EVENT_CRYSTAL_GAIN",
"EVENT_CRYSTAL_LOSS",
"EVENT_TIMER_PAUSE",
"EVENT_TIMER_RESUME",
"EVENT_TIMER_START",
"EVENT_TIMER_STOP",
"EVENT_ENTITY_VARIABLE_DELETE",
"EVENT_ENTITY_VARIABLE_SET",
"EVENT_ENTITY_VARIABLE_UPDATE",
"EVENT_AA_LOSS",
// Add new events before these or Lua crashes
"EVENT_SPELL_EFFECT_BOT",
@@ -1167,6 +1176,7 @@ void PerlembParser::MapFunctions()
perl_register_expedition();
perl_register_expedition_lock_messages();
perl_register_bot();
perl_register_buff();
#endif // EMBPERL_XS_CLASSES
}
@@ -1668,11 +1678,21 @@ void PerlembParser::ExportEventVariables(
break;
}
case EVENT_TIMER: {
case EVENT_TIMER:
case EVENT_TIMER_STOP: {
ExportVar(package_name.c_str(), "timer", data);
break;
}
case EVENT_TIMER_PAUSE:
case EVENT_TIMER_RESUME:
case EVENT_TIMER_START: {
Seperator sep(data);
ExportVar(package_name.c_str(), "timer", sep.arg[0]);
ExportVar(package_name.c_str(), "duration", sep.arg[1]);
break;
}
case EVENT_SIGNAL: {
ExportVar(package_name.c_str(), "signal", data);
break;
@@ -2007,6 +2027,13 @@ void PerlembParser::ExportEventVariables(
ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]);
ExportVar(package_name.c_str(), "killed_entity_id", sep.arg[4]);
if (sep.arg[5]) {
ExportVar(package_name.c_str(), "combat_start_time", sep.arg[5]);
ExportVar(package_name.c_str(), "combat_end_time", sep.arg[6]);
ExportVar(package_name.c_str(), "damage_received", sep.arg[7]);
ExportVar(package_name.c_str(), "healing_received", sep.arg[8]);
}
if (extra_pointers && extra_pointers->size() >= 1) {
Corpse* corpse = std::any_cast<Corpse*>(extra_pointers->at(0));
if (corpse) {
@@ -2249,6 +2276,11 @@ void PerlembParser::ExportEventVariables(
break;
}
case EVENT_AA_LOSS: {
ExportVar(package_name.c_str(), "aa_lost", data);
break;
}
case EVENT_AA_EXP_GAIN: {
ExportVar(package_name.c_str(), "aa_exp_gained", data);
break;
@@ -2409,6 +2441,26 @@ void PerlembParser::ExportEventVariables(
break;
}
case EVENT_ENTITY_VARIABLE_DELETE:
case EVENT_ENTITY_VARIABLE_SET: {
if (extra_pointers && extra_pointers->size() == 2) {
ExportVar(package_name.c_str(), "variable_name", std::any_cast<std::string>(extra_pointers->at(0)).c_str());
ExportVar(package_name.c_str(), "variable_value", std::any_cast<std::string>(extra_pointers->at(1)).c_str());
}
break;
}
case EVENT_ENTITY_VARIABLE_UPDATE: {
if (extra_pointers && extra_pointers->size() == 3) {
ExportVar(package_name.c_str(), "variable_name", std::any_cast<std::string>(extra_pointers->at(0)).c_str());
ExportVar(package_name.c_str(), "old_value", std::any_cast<std::string>(extra_pointers->at(1)).c_str());
ExportVar(package_name.c_str(), "new_value", std::any_cast<std::string>(extra_pointers->at(2)).c_str());
}
break;
}
default: {
break;
}
+116 -23
View File
@@ -313,12 +313,12 @@ int Perl__getinventoryslotid(std::string identifier)
return result;
}
void Perl__castspell(int spell_id, int target_id)
void Perl__castspell(uint16 spell_id, uint16 target_id)
{
quest_manager.castspell(spell_id, target_id);
}
void Perl__selfcast(int spell_id)
void Perl__selfcast(uint16 spell_id)
{
quest_manager.selfcast(spell_id);
}
@@ -353,47 +353,67 @@ void Perl__zoneraid(const char* zone_name)
quest_manager.ZoneRaid(zone_name);
}
bool Perl__hastimer(const char* timer_name)
bool Perl__hastimer(std::string timer_name)
{
return quest_manager.hastimer(timer_name);
}
bool Perl__ispausedtimer(const char* timer_name)
bool Perl__ispausedtimer(std::string timer_name)
{
return quest_manager.ispausedtimer(timer_name);
}
uint32_t Perl__getremainingtimeMS(const char* timer_name)
uint32_t Perl__getremainingtimeMS(std::string timer_name)
{
return quest_manager.getremainingtimeMS(timer_name);
}
uint32_t Perl__gettimerdurationMS(const char* timer_name)
uint32_t Perl__gettimerdurationMS(std::string timer_name)
{
return quest_manager.gettimerdurationMS(timer_name);
}
void Perl__settimer(const char* timer_name, int seconds)
void Perl__settimer(std::string timer_name, uint32 seconds)
{
quest_manager.settimer(timer_name, seconds);
}
void Perl__settimerMS(const char* timer_name, int milliseconds)
void Perl__settimer(std::string timer_name, uint32 seconds, Mob* m)
{
quest_manager.settimer(timer_name, seconds, m);
}
void Perl__settimer(std::string timer_name, uint32 seconds, EQ::ItemInstance* inst)
{
quest_manager.settimerMS(timer_name, seconds * 1000, inst);
}
void Perl__settimerMS(std::string timer_name, uint32 milliseconds)
{
quest_manager.settimerMS(timer_name, milliseconds);
}
void Perl__pausetimer(const char* timer_name)
void Perl__settimerMS(std::string timer_name, uint32 milliseconds, Mob* m)
{
quest_manager.settimerMS(timer_name, milliseconds, m);
}
void Perl__settimerMS(std::string timer_name, uint32 milliseconds, EQ::ItemInstance* inst)
{
quest_manager.settimerMS(timer_name, milliseconds, inst);
}
void Perl__pausetimer(std::string timer_name)
{
quest_manager.pausetimer(timer_name);
}
void Perl__resumetimer(const char* timer_name)
void Perl__resumetimer(std::string timer_name)
{
quest_manager.resumetimer(timer_name);
}
void Perl__stoptimer(const char* timer_name)
void Perl__stoptimer(std::string timer_name)
{
quest_manager.stoptimer(timer_name);
}
@@ -1634,20 +1654,19 @@ void Perl__FlagInstanceByRaidLeader(uint32 zone, uint16 version)
quest_manager.FlagInstanceByRaidLeader(zone, version);
}
std::string Perl__saylink(const char* text)
std::string Perl__saylink(std::string text)
{
// const cast is safe since, target api doesn't modify it
return quest_manager.saylink(const_cast<char*>(text), false, text);
return Saylink::Create(text);
}
std::string Perl__saylink(const char* text, bool silent)
std::string Perl__saylink(std::string text, bool silent)
{
return quest_manager.saylink(const_cast<char*>(text), silent, text);
return Saylink::Create(text, silent);
}
std::string Perl__saylink(const char* text, bool silent, const char* link_name)
std::string Perl__saylink(std::string text, bool silent, std::string link_name)
{
return quest_manager.saylink(const_cast<char*>(text), silent, link_name);
return Saylink::Create(text, silent, link_name);
}
std::string Perl__getcharnamebyid(uint32 char_id)
@@ -5762,6 +5781,67 @@ std::string Perl__convert_money_to_string(perl::hash table)
return Strings::Money(platinum, gold, silver, copper);
}
uint8 Perl__GetBotClassByID(uint32 bot_id)
{
return database.botdb.GetBotClassByID(bot_id);
}
uint8 Perl__GetBotGenderByID(uint32 bot_id)
{
return database.botdb.GetBotGenderByID(bot_id);
}
perl::array Perl__GetBotIDsByCharacterID(uint32 character_id)
{
perl::array result;
const auto bot_ids = database.botdb.GetBotIDsByCharacterID(character_id);
for (int i = 0; i < bot_ids.size(); i++) {
result.push_back(bot_ids[i]);
}
return result;
}
perl::array Perl__GetBotIDsByCharacterID(uint32 character_id, uint8 class_id)
{
perl::array result;
const auto bot_ids = database.botdb.GetBotIDsByCharacterID(character_id, class_id);
for (int i = 0; i < bot_ids.size(); i++) {
result.push_back(bot_ids[i]);
}
return result;
}
uint8 Perl__GetBotLevelByID(uint32 bot_id)
{
return database.botdb.GetBotLevelByID(bot_id);
}
std::string Perl__GetBotNameByID(uint32 bot_id)
{
return database.botdb.GetBotNameByID(bot_id);
}
uint16 Perl__GetBotRaceByID(uint32 bot_id)
{
return database.botdb.GetBotRaceByID(bot_id);
}
std::string Perl__silent_saylink(std::string text)
{
return Saylink::Silent(text);
}
std::string Perl__silent_saylink(std::string text, std::string link_name)
{
return Saylink::Silent(text, link_name);
}
void perl_register_quest()
{
perl::interpreter perl(PERL_GET_THX);
@@ -5792,6 +5872,13 @@ void perl_register_quest()
package.add("FlagInstanceByGroupLeader", &Perl__FlagInstanceByGroupLeader);
package.add("FlagInstanceByRaidLeader", &Perl__FlagInstanceByRaidLeader);
package.add("FlyMode", &Perl__FlyMode);
package.add("GetBotClassByID", &Perl__GetBotClassByID);
package.add("GetBotGenderByID", &Perl__GetBotGenderByID);
package.add("GetBotIDsByCharacterID", (perl::array(*)(uint32))&Perl__GetBotIDsByCharacterID);
package.add("GetBotIDsByCharacterID", (perl::array(*)(uint32, uint8))&Perl__GetBotIDsByCharacterID);
package.add("GetBotLevelByID", &Perl__GetBotLevelByID);
package.add("GetBotNameByID", &Perl__GetBotNameByID);
package.add("GetBotRaceByID", &Perl__GetBotRaceByID);
package.add("GetCharactersInInstance", &Perl__GetCharactersInInstance);
package.add("GetInstanceID", &Perl__GetInstanceID);
package.add("GetInstanceIDByCharID", &Perl__GetInstanceIDByCharID);
@@ -6566,9 +6653,9 @@ void perl_register_quest()
package.add("say", (void(*)(const char*, uint8, int))&Perl__say);
package.add("say", (void(*)(const char*, uint8, int, int))&Perl__say);
package.add("say", (void(*)(const char*, uint8, int, int, int))&Perl__say);
package.add("saylink", (std::string(*)(const char*))&Perl__saylink);
package.add("saylink", (std::string(*)(const char*, bool))&Perl__saylink);
package.add("saylink", (std::string(*)(const char*, bool, const char*))&Perl__saylink);
package.add("saylink", (std::string(*)(std::string))&Perl__saylink);
package.add("saylink", (std::string(*)(std::string, bool))&Perl__saylink);
package.add("saylink", (std::string(*)(std::string, bool, std::string))&Perl__saylink);
package.add("scribespells", (int(*)(int))&Perl__scribespells);
package.add("scribespells", (int(*)(int, int))&Perl__scribespells);
package.add("secondstotime", &Perl__secondstotime);
@@ -6606,8 +6693,12 @@ void perl_register_quest()
package.add("settarget", &Perl__settarget);
package.add("settime", (void(*)(int, int))&Perl__settime);
package.add("settime", (void(*)(int, int, bool))&Perl__settime);
package.add("settimer", &Perl__settimer);
package.add("settimerMS", &Perl__settimerMS);
package.add("settimer", (void(*)(std::string, uint32))&Perl__settimer);
package.add("settimer", (void(*)(std::string, uint32, EQ::ItemInstance*))&Perl__settimer);
package.add("settimer", (void(*)(std::string, uint32, Mob*))&Perl__settimer);
package.add("settimerMS", (void(*)(std::string, uint32))&Perl__settimerMS);
package.add("settimerMS", (void(*)(std::string, uint32, EQ::ItemInstance*))&Perl__settimerMS);
package.add("settimerMS", (void(*)(std::string, uint32, Mob*))&Perl__settimerMS);
package.add("sfollow", &Perl__sfollow);
package.add("shout", &Perl__shout);
package.add("shout2", &Perl__shout2);
@@ -6616,6 +6707,8 @@ void perl_register_quest()
package.add("signal", (void(*)(int, int))&Perl__signal);
package.add("signalwith", (void(*)(int, int))&Perl__signalwith);
package.add("signalwith", (void(*)(int, int, int))&Perl__signalwith);
package.add("silent_saylink", (std::string(*)(std::string))&Perl__silent_saylink);
package.add("silent_saylink", (std::string(*)(std::string, std::string))&Perl__silent_saylink);
package.add("snow", &Perl__snow);
package.add("spawn", &Perl__spawn);
package.add("spawn2", &Perl__spawn2);
+7 -5
View File
@@ -2152,7 +2152,7 @@ Group *EntityList::GetGroupByLeaderName(const char *leader)
iterator = group_list.begin();
while (iterator != group_list.end()) {
if (!strcmp((*iterator)->GetLeaderName(), leader))
if (!strcmp((*iterator)->GetLeaderName().c_str(), leader))
return *iterator;
++iterator;
}
@@ -4379,8 +4379,9 @@ void EntityList::AddTempPetsToHateList(Mob *owner, Mob* other, bool bFrenzy)
if (n->GetSwarmInfo()->owner_id == owner->GetID()) {
if (
!n->GetSpecialAbility(IMMUNE_AGGRO) &&
!(n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && other->IsClient()) &&
!(n->GetSpecialAbility(IMMUNE_AGGRO_NPC) && other->IsNPC())
!(other->IsBot() && n->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
!(other->IsClient() && n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
!(other->IsNPC() && n->GetSpecialAbility(IMMUNE_AGGRO_NPC))
) {
n->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
}
@@ -4405,8 +4406,9 @@ void EntityList::AddTempPetsToHateListOnOwnerDamage(Mob *owner, Mob* attacker, i
attacker != n &&
!n->IsEngaged() &&
!n->GetSpecialAbility(IMMUNE_AGGRO) &&
!(n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && attacker->IsClient()) &&
!(n->GetSpecialAbility(IMMUNE_AGGRO_NPC) && attacker->IsNPC()) &&
!(attacker->IsBot() && n->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
!(attacker->IsClient() && n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
!(attacker->IsNPC() && n->GetSpecialAbility(IMMUNE_AGGRO_NPC)) &&
!attacker->IsTrap() &&
!attacker->IsCorpse()
) {
+8
View File
@@ -135,6 +135,14 @@ typedef enum {
EVENT_ALT_CURRENCY_LOSS,
EVENT_CRYSTAL_GAIN,
EVENT_CRYSTAL_LOSS,
EVENT_TIMER_PAUSE,
EVENT_TIMER_RESUME,
EVENT_TIMER_START,
EVENT_TIMER_STOP,
EVENT_ENTITY_VARIABLE_DELETE,
EVENT_ENTITY_VARIABLE_SET,
EVENT_ENTITY_VARIABLE_UPDATE,
EVENT_AA_LOSS,
// Add new events before these or Lua crashes
EVENT_SPELL_EFFECT_BOT,
+20 -10
View File
@@ -625,19 +625,29 @@ void Client::SetEXP(uint64 set_exp, uint64 set_aaxp, bool isrezzexp) {
else MessageString(Chat::Experience, REZ_REGAIN);
} else {
if (membercount > 1) {
if (RuleI(Character, ShowExpValues) > 0)
if (RuleI(Character, ShowExpValues) > 0) {
Message(Chat::Experience, "You have gained %s party experience! %s", exp_amount_message.c_str(), exp_percent_message.c_str());
else MessageString(Chat::Experience, GAIN_GROUPXP);
}
else if (IsRaidGrouped()) {
if (RuleI(Character, ShowExpValues) > 0)
} else if (zone->IsHotzone()) {
Message(Chat::Experience, "You gain party experience (with a bonus)!");
} else {
MessageString(Chat::Experience, GAIN_GROUPXP);
}
} else if (IsRaidGrouped()) {
if (RuleI(Character, ShowExpValues) > 0) {
Message(Chat::Experience, "You have gained %s raid experience! %s", exp_amount_message.c_str(), exp_percent_message.c_str());
else MessageString(Chat::Experience, GAIN_RAIDEXP);
}
else {
if (RuleI(Character, ShowExpValues) > 0)
} else if (zone->IsHotzone()) {
Message(Chat::Experience, "You gained raid experience (with a bonus)!");
} else {
MessageString(Chat::Experience, GAIN_RAIDEXP);
}
} else {
if (RuleI(Character, ShowExpValues) > 0) {
Message(Chat::Experience, "You have gained %s experience! %s", exp_amount_message.c_str(), exp_percent_message.c_str());
else MessageString(Chat::Experience, GAIN_XP);
} else if (zone->IsHotzone()) {
Message(Chat::Experience, "You gain experience (with a bonus)!");
} else {
MessageString(Chat::Experience, GAIN_XP);
}
}
}
}
+3 -3
View File
@@ -1161,7 +1161,7 @@ void Expedition::AddLockoutByCharacterName(
{
if (!character_name.empty())
{
uint32_t character_id = database.GetCharacterID(character_name.c_str());
uint32_t character_id = database.GetCharacterID(character_name);
AddLockoutByCharacterID(character_id, expedition_name, event_name, seconds, uuid);
}
}
@@ -1180,7 +1180,7 @@ bool Expedition::HasLockoutByCharacterName(
{
if (!character_name.empty())
{
uint32_t character_id = database.GetCharacterID(character_name.c_str());
uint32_t character_id = database.GetCharacterID(character_name);
return HasLockoutByCharacterID(character_id, expedition_name, event_name);
}
return false;
@@ -1214,7 +1214,7 @@ void Expedition::RemoveLockoutsByCharacterName(
{
if (!character_name.empty())
{
uint32_t character_id = database.GetCharacterID(character_name.c_str());
uint32_t character_id = database.GetCharacterID(character_name);
RemoveLockoutsByCharacterID(character_id, expedition_name, event_name);
}
}
+2 -9
View File
@@ -125,8 +125,8 @@ bool ExpeditionRequest::CanGroupRequest(Group* group)
}
// Group::GetLeaderName() is broken if group formed across zones, ask database instead
m_leader_name = m_leader ? m_leader->GetName() : GetGroupLeaderName(group->GetID()); // group->GetLeaderName();
m_leader_id = m_leader ? m_leader->CharacterID() : database.GetCharacterID(m_leader_name.c_str());
m_leader_name = m_leader ? m_leader->GetName() : group->GetLeaderName();
m_leader_id = m_leader ? m_leader->CharacterID() : database.GetCharacterID(m_leader_name);
std::vector<std::string> member_names;
member_names.emplace_back(m_leader_name); // leader always added first
@@ -148,13 +148,6 @@ bool ExpeditionRequest::CanGroupRequest(Group* group)
return CanMembersJoin(member_names);
}
std::string ExpeditionRequest::GetGroupLeaderName(uint32_t group_id)
{
char leader_name_buffer[64] = { 0 };
database.GetGroupLeadershipInfo(group_id, leader_name_buffer);
return std::string(leader_name_buffer);
}
bool ExpeditionRequest::CanMembersJoin(const std::vector<std::string>& member_names)
{
if (member_names.empty())
-1
View File
@@ -54,7 +54,6 @@ private:
bool CanRaidRequest(Raid* raid);
bool CanGroupRequest(Group* group);
bool CheckMembersForConflicts(const std::vector<std::string>& member_names);
std::string GetGroupLeaderName(uint32_t group_id);
bool IsPlayerCountValidated();
bool SaveLeaderLockouts(const std::vector<ExpeditionLockoutTimer>& leader_lockouts);
void SendLeaderMemberInExpedition(const std::string& member_name, bool is_solo);
+7 -5
View File
@@ -89,7 +89,7 @@ uint32 ZoneDatabase::LoadForage(uint32 zone_id, uint8 skill_level)
}
forage_items[count] = e.Itemid;
forage_chances[count] = e.chance;
forage_chances[count] = e.chance + current_chance;
current_chance = forage_chances[count];
@@ -257,7 +257,7 @@ bool Client::CanFish() {
return true;
}
void Client::GoFish()
void Client::GoFish(bool guarantee, bool use_bait)
{
//TODO: generate a message if we're already fishing
@@ -306,7 +306,7 @@ void Client::GoFish()
fishing_skill = 100+((fishing_skill-100)/2);
}
if (zone->random.Int(0,175) < fishing_skill) {
if (guarantee || zone->random.Int(0,175) < fishing_skill) {
uint32 food_id = 0;
//25% chance to fish an item.
@@ -343,8 +343,10 @@ void Client::GoFish()
}
}
//consume bait, should we always consume bait on success?
DeleteItemInInventory(bslot, 1, true); //do we need client update?
if (use_bait) {
//consume bait, should we always consume bait on success?
DeleteItemInInventory(bslot, 1, true); //do we need client update?
}
if(food_id == 0) {
int index = zone->random.Int(0, MAX_COMMON_FISH_IDS-1);
+6
View File
@@ -0,0 +1,6 @@
#include "../client.h"
void command_fish(Client *c, const Seperator *sep)
{
c->GoFish(true, false);
}
+6
View File
@@ -0,0 +1,6 @@
#include "../client.h"
void command_forage(Client *c, const Seperator *sep)
{
c->ForageItem(true);
}
+2 -1
View File
@@ -3,6 +3,7 @@
void command_goto(Client *c, const Seperator *sep)
{
std::string arg1 = sep->arg[1];
std::string arg4 = sep->arg[4];
bool goto_via_target_no_args = sep->arg[1][0] == '\0' && c->GetTarget();
bool goto_via_player_name = !sep->IsNumber(1) && !arg1.empty();
@@ -52,7 +53,7 @@ void command_goto(Client *c, const Seperator *sep)
Strings::ToFloat(sep->arg[1]),
Strings::ToFloat(sep->arg[2]),
Strings::ToFloat(sep->arg[3]),
(sep->arg[4] ? Strings::ToFloat(sep->arg[4]) : c->GetHeading())
(!arg4.empty() ? Strings::ToFloat(sep->arg[4]) : c->GetHeading())
);
}
else {
+2 -2
View File
@@ -80,7 +80,7 @@ void command_instance(Client *c, const Seperator *sep)
std::string character_name = sep->arg[3];
uint16 instance_id = static_cast<uint16>(Strings::ToUnsignedInt(sep->arg[2]));
uint32 character_id = database.GetCharacterID(character_name.c_str());
uint32 character_id = database.GetCharacterID(character_name);
if (instance_id <= 0 || character_id <= 0) {
c->Message(Chat::White, "You must enter a valid Instance ID and player name.");
return;
@@ -270,7 +270,7 @@ void command_instance(Client *c, const Seperator *sep)
std::string character_name = sep->arg[3];
uint16 instance_id = static_cast<uint16>(Strings::ToUnsignedInt(sep->arg[2]));
uint32 character_id = database.GetCharacterID(character_name.c_str());
uint32 character_id = database.GetCharacterID(character_name);
if (instance_id <= 0 || character_id <= 0) {
c->Message(Chat::White, "You must enter a valid Instance ID and player name.");
return;
+4 -4
View File
@@ -82,7 +82,7 @@ void command_logs(Client *c, const Seperator *sep)
}
gmsay.emplace_back(
EQ::SayLinkEngine::GenerateQuestSaylink(
Saylink::Create(
fmt::format("#logs set gmsay {} {}", index, i), false, std::to_string(i)
)
);
@@ -96,7 +96,7 @@ void command_logs(Client *c, const Seperator *sep)
}
file.emplace_back(
EQ::SayLinkEngine::GenerateQuestSaylink(
Saylink::Create(
fmt::format("#logs set file {} {}", index, i), false, std::to_string(i)
)
);
@@ -110,7 +110,7 @@ void command_logs(Client *c, const Seperator *sep)
}
console.emplace_back(
EQ::SayLinkEngine::GenerateQuestSaylink(
Saylink::Create(
fmt::format("#logs set console {} {}", index, i), false, std::to_string(i)
)
);
@@ -124,7 +124,7 @@ void command_logs(Client *c, const Seperator *sep)
}
discord.emplace_back(
EQ::SayLinkEngine::GenerateQuestSaylink(
Saylink::Create(
fmt::format("#logs set discord {} {}", index, i), false, std::to_string(i)
)
);
+2 -2
View File
@@ -116,13 +116,13 @@ void command_lootsim(Client *c, const Seperator *sep)
c->Message(Chat::White, fmt::format("# Global Loot Table ID [{}]", id).c_str());
c->SendChatLineBreak();
loot_table = zone->GetLootTable(loottable_id);
loot_table = zone->GetLootTable(id);
if (!loot_table) {
c->Message(Chat::Red, fmt::format("Global Loot table not found [{}]", id).c_str());
continue;
}
le = zone->GetLootTableEntries(loottable_id);
le = zone->GetLootTableEntries(id);
// translate above for loop using loot_table_entries
for (auto &e: le) {
+1 -1
View File
@@ -13,7 +13,7 @@ void command_movechar(Client *c, const Seperator *sep)
database.GetCharNameByID(Strings::ToUnsignedInt(sep->arg[1])) :
sep->arg[1]
);
const uint32 character_id = database.GetCharacterID(character_name.c_str());
const uint32 character_id = database.GetCharacterID(character_name);
if (!character_id) {
c->Message(
Chat::White,
+1 -1
View File
@@ -7,7 +7,7 @@ void SetHPFull(Client *c, const Seperator *sep)
t = c->GetTarget();
}
t->Heal();
t->RestoreHealth();
c->Message(
Chat::White,
+2
View File
@@ -5,6 +5,7 @@
#include "show/buffs.cpp"
#include "show/buried_corpse_count.cpp"
#include "show/client_version_summary.cpp"
#include "show/content_flags.cpp"
#include "show/currencies.cpp"
#include "show/distance.cpp"
#include "show/emotes.cpp"
@@ -64,6 +65,7 @@ void command_show(Client *c, const Seperator *sep)
Cmd{.cmd = "buffs", .u = "buffs", .fn = ShowBuffs, .a = {"#showbuffs"}},
Cmd{.cmd = "buried_corpse_count", .u = "buried_corpse_count", .fn = ShowBuriedCorpseCount, .a = {"#getplayerburiedcorpsecount"}},
Cmd{.cmd = "client_version_summary", .u = "client_version_summary", .fn = ShowClientVersionSummary, .a = {"#cvs"}},
Cmd{.cmd = "content_flags", .u = "content_flags", .fn = ShowContentFlags, .a = {"#showcontentflags"}},
Cmd{.cmd = "currencies", .u = "currencies", .fn = ShowCurrencies, .a = {"#viewcurrencies"}},
Cmd{.cmd = "distance", .u = "distance", .fn = ShowDistance, .a = {"#distance"}},
Cmd{.cmd = "emotes", .u = "emotes", .fn = ShowEmotes, .a = {"#emoteview"}},
+30
View File
@@ -0,0 +1,30 @@
#include "../../client.h"
#include "../../dialogue_window.h"
void ShowContentFlags(Client *c, const Seperator *sep)
{
Client *t = c;
if (c->GetTarget() && c->GetTarget()->IsClient()) {
t = c->GetTarget()->CastToClient();
}
std::string flags = DialogueWindow::TableRow(
DialogueWindow::TableCell("id") +
DialogueWindow::TableCell("flag_name") +
DialogueWindow::TableCell("enabled")
);
for (auto &f: ContentFlagsRepository::All(database)) {
flags += DialogueWindow::TableRow(
DialogueWindow::TableCell(std::to_string(f.id)) +
DialogueWindow::TableCell(f.flag_name) +
DialogueWindow::TableCell(
f.enabled ?
DialogueWindow::ColorMessage("forest_green", "yes") :
DialogueWindow::ColorMessage("red", "no")
)
);
}
c->SendPopupToClient("Server Content Flag Settings", DialogueWindow::Table(flags).c_str());
}
+1 -1
View File
@@ -16,7 +16,7 @@ void command_summon(Client *c, const Seperator *sep)
if (arguments == 1) {
std::string character_name = sep->arg[1];
auto character_id = database.GetCharacterID(character_name.c_str());
auto character_id = database.GetCharacterID(character_name);
if (!character_id) {
c->Message(
Chat::White,
+7 -9
View File
@@ -620,7 +620,7 @@ bool Group::DelMemberOOZ(const char *Name) {
if(!strcasecmp(Name, membername[i]))
// This shouldn't be called if the member is in this zone.
if(!members[i]) {
if(!strncmp(GetLeaderName(), Name, 64))
if(!strncmp(GetLeaderName().c_str(), Name, 64))
{
//TODO: Transfer leadership if leader disbands OOZ.
UpdateGroupAAs();
@@ -703,7 +703,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender)
}
}
if (!GetLeaderName())
if (GetLeaderName().empty())
{
DisbandGroup();
return true;
@@ -1676,7 +1676,7 @@ void Group::NotifyMainTank(Client *c, uint8 toggle)
strn0cpy(grs->Name1, MainTankName.c_str(), sizeof(grs->Name1));
strn0cpy(grs->Name2, GetLeaderName(), sizeof(grs->Name2));
strn0cpy(grs->Name2, GetLeaderName().c_str(), sizeof(grs->Name2));
grs->RoleNumber = 1;
@@ -1729,7 +1729,7 @@ void Group::NotifyMainAssist(Client *c, uint8 toggle)
strn0cpy(grs->Name1, MainAssistName.c_str(), sizeof(grs->Name1));
strn0cpy(grs->Name2, GetLeaderName(), sizeof(grs->Name2));
strn0cpy(grs->Name2, GetLeaderName().c_str(), sizeof(grs->Name2));
grs->RoleNumber = 2;
@@ -1771,7 +1771,7 @@ void Group::NotifyPuller(Client *c, uint8 toggle)
strn0cpy(grs->Name1, PullerName.c_str(), sizeof(grs->Name1));
strn0cpy(grs->Name2, GetLeaderName(), sizeof(grs->Name2));
strn0cpy(grs->Name2, GetLeaderName().c_str(), sizeof(grs->Name2));
grs->RoleNumber = 3;
@@ -2511,8 +2511,6 @@ bool Group::IsLeader(const char* name) {
return false;
}
std::string Group::GetGroupLeaderName(uint32 group_id) {
char leader_name_buffer[64] = { 0 };
database.GetGroupLeadershipInfo(group_id, leader_name_buffer);
return std::string(leader_name_buffer);
std::string Group::GetLeaderName() {
return database.GetGroupLeaderName(GetID());
}

Some files were not shown because too many files have changed in this diff Show More