Compare commits

...
38 Commits
Author SHA1 Message Date
MagicBotandClaude Opus 5.5 98f09d0713 Load Race from the race runes instead of static_rune_race
loadAllRaces builds one Race per static_rune_race row from the RACE rune with
the same id (all 26, including 2018-2021, decision: JSON); the row now only
supplies minHeight and strHeightMod, and a row without a race rune would load
from the DB with a warning. Colors stay in the DB. racebaseclass,
racehairstyle and racebeardstyle are no longer read at boot. The SQL loader
stays until task 2.11.

Value changes (decisions: JSON, D2):
- name drops the ", Male"/", Female" suffix ("Aelfborn, Male" -> "Aelfborn").
  WhoResponseMsg's split(",") and runAfterLoad's suffix strip still work;
  runAfterLoad now resolves 2019 to HalfGiant (it threw on the DB name).
- description '' -> rune_dsc blurb (unread)
- Minotaur hair 6958 -> 6598; Vampire M beard 5020170 -> 5020300
- beard style 0 dropped on Shade M/F, Minotaur, Vampire F (beard styles are
  never validated); hair 0 kept on Aracoix M/F and Shade M/F by the
  empty-hair rule
- 2018 Archon: startingPoints 0 -> 30, token 0 -> -317458791, health 0 -> 20,
  stamina 0 -> 90
- 2019 Half-Giant-Old Man: strMax 150 -> 140, dex 40/65 -> 30/75, con 60/140
  -> 50/130, spi 30/60 -> 35/80, startingPoints 20 -> 15, health/mana/stamina
  0 -> 10/5/70, baseClasses {} -> {Fighter 2500}
- 2020/2021 CSR: all stats 60/120 -> 40/100, startingPoints 0 -> 30, token
  0 -> 52803, health/mana/stamina 0 -> 40/40/10000

All other fields unchanged; final parity before the switch (scripts/p23.py):
22 creation races, 0 differences in attributes, bonuses, startingPoints,
token and base classes. The static_rune_race comparator is removed; it would
only compare the JSON with itself now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 11:02:06 -04:00
MagicBotandClaude Opus 5.5 a30a065841 Build Race from its race rune and compare every field
Adds Race(RuneTemplate, Race): start/max attributes from rune_attr_adj/
rune_max_attr_adj (min is always 0), health/mana/stamina bonus from
rune_health/mana/stamina, startingPoints = 30 - rune_creation_cost, token =
SBStringHash(rune_sub_type), name from obj_name, description from rune_dsc,
hair/beard styles from rune_hair/rune_beard (style 0 when rune_hair is empty),
and baseClasses = the creation class runes whose item_race_req names the race
sub type. minHeight/strHeightMod come from the static_rune_race row; colors,
skills, powers and effects still load from the DB by rune id. A
static_rune_race comparator checks every field against a JSON-built Race.

Offline parity (scripts/p23.py, 26 rows + racebaseclass/hairstyle/beardstyle
vs the RACE runes): the 22 creation races match in every attribute, bonus,
startingPoints, token and base class. Differences:
- name: "Aelfborn, Male" -> "Aelfborn" on every row
- hair 0 dropped by the JSON on Aracoix M/F and Shade M/F (kept by the
  empty-hair rule); beard 0 dropped on Shade M/F, Minotaur, Vampire F
- Minotaur hair 6958 -> 6598, Vampire M beard 5020170 -> 5020300
- 2018 Archon: startingPoints 0 -> 30, token 0 -> SBStringHash("Celestial"),
  health 0 -> 20, stamina 0 -> 90
- 2019 Half-Giant-Old Man: str/dex/con/spi start and max, startingPoints
  20 -> 15, health/mana/stamina 0 -> 10/5/70, baseClasses {} -> {Fighter}
- 2020/2021 CSR: stats 60/120 -> 40/100, startingPoints 0 -> 30, token 0 ->
  SBStringHash("CSR"), health/mana/stamina 0 -> 40/40/10000

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 11:01:43 -04:00
MagicBotandClaude Opus 5.5 957293165b Load PromotionClass from the promotion runes instead of static_rune_promotion
LoadAllPromotions builds one PromotionClass per promotion CLASS rune (22,
2504-2526 without 2522) and caches it, then runs the DB loader, which skips
cached ids, so only the CSR/admin rows 2901-2911 still come from
static_rune_promotion (decision: DB fallback). The world server calls it in
place of GET_ALL_PROMOTIONS; the login server now preloads promotions too, so
character load there gets the same cached objects. The SQL loader stays until
task 2.11.

Value changes: Templar 2516 manaMod 14 -> 15 (decision: JSON, D2).
description NULL -> rune_dsc blurb (unread). All other fields unchanged;
final parity before the switch (scripts/p22.py): 22 promotion rows, 0
differences in name, token, health, stamina and the 163 allowed rune tokens.
The static_rune_promotion comparator is removed; it would only compare the
JSON with itself now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:33:45 -04:00
MagicBotandClaude Opus 5.5 e91c803a32 Build PromotionClass from its class rune and compare every field
Adds PromotionClass(RuneTemplate): health/mana/stamina from rune_health/mana/
stamina, token = SBStringHash(rune_sub_type), description from rune_dsc, and
allowedRunes = the sub type tokens of the race and base class runes named in
item_race_req/item_class_req (all whitelists). Skills, powers and effects still
load from the DB by rune id (tasks 2.8, 2.9, 2.10). isPromotionRune selects the
non-creation CLASS runes that require a base class (skips 2500-2503 and Pet).
A static_rune_promotion comparator checks every field against a JSON-built
PromotionClass; rows 2901+ (TALENT runes in the JSON) report as missing.

Offline parity (scripts/p22.py, 33 rows + 163 promotionrunereq rows vs 22
promotion runes): 0 differences in name, token, health, stamina and allowed
rune tokens. Templar 2516 manaMod is 14 in the DB and 15 in the JSON.
2901-2911 have no promotion rune. description is NULL in the DB and the
rune_dsc blurb in the JSON; nothing reads PromotionClass.getDescription().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:33:08 -04:00
MagicBotandClaude Opus 5.5 992177eb0c Return the cached PromotionClass from GET_PROMOTION_CLASS
Character load and the promotion trainer re-read static_rune_promotion on every
call and replaced the cached object. They now get the object loaded at boot,
as GET_BASE_CLASS already does; the DB query is only a miss fallback.
No value changes: the cached and re-read objects hold the same row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:32:24 -04:00
MagicBotandClaude Opus 5.5 c8c322a3f5 Load BaseClass from the class runes instead of static_rune_baseclass
LoadAllBaseClasses builds one BaseClass per CLASS rune with
rune_is_standard_character_creation (2500-2503; promotions and Pet are
skipped) and caches it. Race.baseClasses picks up the cached objects through
GET_BASECLASS_FOR_RACE. The SQL loader stays until task 2.11.

Value changes: description goes from '' to the rune_dsc class blurb (unread).
All other fields unchanged; final parity before the switch (scripts/p21.py):
4 rows, 0 differences in name, attribute mods, token, health/mana/stamina mods.
The static_rune_baseclass comparator is removed; it would only compare the
JSON with itself now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:55:09 -04:00
MagicBotandClaude Opus 5.5 5acd3492ed Build BaseClass from its class rune and compare every field
Adds BaseClass(RuneTemplate): attributes from rune_attr_adj, health/mana/stamina
from rune_health/mana/stamina, token = SBStringHash(rune_sub_type), description
from rune_dsc. Skills, powers and effects still load from the DB by rune id
(tasks 2.8, 2.9, 2.10). The static_rune_baseclass comparator now checks every
field against a JSON-built BaseClass.

Offline parity (scripts/p21.py, 4 rows vs the CLASS runes with
rune_is_standard_character_creation = 2500-2503): 0 differences except
description, which is '' in the DB and the class blurb in rune_dsc. Nothing
reads BaseClass.getDescription().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:54:46 -04:00
MagicBotandClaude Opus 5.5 0283f85e87 Remove the legacy ItemTemplate and static_item_templates loader
Every reader moved to CObjectTemplate in 1.7, so the DB-loaded
engine.objects.ItemTemplate, LOAD_ITEM_TEMPLATES and linkCacheTemplates
are dead. No value changes: nothing read the legacy maps any more.
The boot log loses the legacy per-type count and the link warnings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:53:14 -04:00
MagicBotandClaude Opus 5.5 4b8430b0ba Use GameObjectType to check the ./fill target
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:44:11 -04:00
MagicBotandClaude Opus 5.5 f07f9945d7 Compare the selected warehouse by UUID in ./fill
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:42:29 -04:00
MagicBotandClaude Opus 5.5 077dcc071d Rename ./fillwarehouse to ./fill and require a selected warehouse
The command now acts on the selected building and refuses anything
whose blueprint is not a warehouse, or a warehouse that is not its
city's active one, instead of using the city the player stands in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:42:09 -04:00
MagicBotandClaude Opus 5.5 c616afa33b Add ./fillwarehouse dev command
Sets every resource in the warehouse of the city the player stands in,
either to an optional amount or, by default, to each resource's
deposit limit. Makes forge and work order testing practical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:40:01 -04:00
MagicBotandClaude Opus 5.5 1ac522a2e0 Fix /makeitem failing to persist items
MakeItemCmd left the container at NONE, which item_CREATE's cont
parameter rejects, so PERSIST returned null and addItemToInventory
threw a NullPointerException. Set the container to INVENTORY as
CreateItemCmd does, and report an error if PERSIST still fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:27:47 -04:00
MagicBotandClaude Opus 5.5 566870de79 Move the remaining legacy item template lookups to CObjectTemplate
Dev commands, BuildingManager, ChatManager, ForgeManager, NPCManager,
NPC, Warehouse, WorkOrder and ManageNPCMsg now call
CObjectTemplate.lookup instead of ItemTemplate.templates.get. Forge
production cost reads getItemResourceCosts(). Only the DB loader and
linkCacheTemplates still use the legacy class (removed in Task 1.8).

Removes the static_item_templates ParityCheck comparator. Final parity
(offline p17.py, 7586 rows): every id has a cache template, 0 item_type
differences, 0 item_resource_costs differences (84 ITEMs have costs).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 07:56:08 -04:00
MagicBotandClaude Opus 5.5 6b4e9815e0 Switch Item.template and MobLoot to CObjectTemplate
Item.template is now the cache template from CObjectTemplate.lookup
instead of the legacy DB ItemTemplate, so item.template.cacheTemplate.X
becomes item.template.X. MobLoot, LootManager, ItemManager.isTwoHanded/
isShield and CombatManager.getSwingAnimation take a CObjectTemplate.

No value changes: every getter already read the cache template through
the bridge, and the lookup resolves the same 7586 ids as
static_item_templates with the same item_type (offline parity p17.py,
0 differences).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 07:55:28 -04:00
MagicBotandClaude Opus 5.5 f39e35ac23 Apply the dual-wield damage cut only when both hands hold weapons
The 30% cut never applied: each hand was passed itself as the other
hand, and the check compared the template to ItemType.WEAPON. The
client (0x466EB0 / 0x46D200) multiplies min and max damage by 0.7 when
both held slots contain an item_type WEAPON. Value change: players
wielding two weapons now deal 70% damage per hand; single weapon,
weapon + shield and unarmed are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 07:54:02 -04:00
MagicBotandClaude Opus 5.5 70ea9b3bc9 Move the vendor mod table off the legacy item template
LOAD_TEMPLATE_MODTABLES now returns a templateID -> modTable map that
ForgeManager owns (vendorModTables). ForgeManager.forgeItem, WorkOrder
validation and the ManageNPCMsg forge item list read it through
ForgeManager.getVendorModTable(), and ItemTemplate.modTable is removed.

Values are unchanged: static_vendor_items has 5089 rows, one per
templateID, all present in static_item_templates, modTable 0-30.
Templates not in the table still read 0. The old loader stopped at the
first templateID missing from ItemTemplate.templates; there are none.
No comparator added or removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 07:37:54 -04:00
MagicBotandClaude Opus 5.5 2b4c1a73d1 Read item user power actions from the cache template
The magical name color check and loadTemplateEnchantments read
getItemUserPowerAction(). The list keeps duplicates, so the baked-in
enchantments collapse a repeated power to its last entry, as the legacy
HashMap did; applying it twice would add its name to effectNames twice and
double its share of calcMagicValue.

Offline parity (p15e.py, 7586 rows): 0 differences in the lists (power and
arguments, in order). Duplicates exist only on 81 RUNE templates (mob,
guard and siege runes, plus discipline rune 3006 Blade Weaver with two
identical AMBIDEXTERITY entries); none on ITEM or DEED.

Value changes: none. Enchantments are now applied in file order instead
of HashMap order; effects are keyed by effect id and calcMagicValue is a
sum, so the result is the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:35:38 -04:00
MagicBotandClaude Opus 5.5 a37de9fc31 Read the item power grant from the cache template
The BUCKET/POTION/SCROLL use path takes the first item_power_grant entry
in file order from getItemPowerGrant() instead of the first key of the
legacy HashMap.

Offline parity (p15e.py, 7586 rows): 0 differences in the grant lists.
The legacy HashMap order picks a different power on 664 templates, all
RUNE folder runes with item_type RUNE, which take the RUNE case and never
reach this path. Every ITEM-folder grant (scrolls, potions, bucket, rod,
gift rings) has exactly one entry and no DEED has one, so the power and
value used are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:35:19 -04:00
MagicBotandClaude Opus 5.5 81d4ab7b99 Read item skill used and mastery from the cache template
CombatManager shield checks, weapon skill/mastery lookups in
AbstractCharacter, armor defense and PlayerCharacter.validEquip read
getItemSkillUsed/getItemSkillMasteryUsed. Offline parity (p15d.py, 7586
rows): 0 mastery differences; skill used differs only where the legacy
loader blanked it.

The cache keeps "Cloth" (226 ARMOR templates), which the legacy loader
turned into "". Cloth is a placeholder in Skills.cfg that no character
has, so getArmorDefense now checks for it explicitly and still returns the
flat defense rating. No weapon uses Cloth and no power equip prereq names
it, so the other sites behave the same.

Value changes:
- 195340 Fortified Dragon Plate Helm of the Lion: skill used is the
  unresolved hash "2624663" instead of "". Defense is still the flat
  rating (no such skill), but players wearing it now hit the
  "armor equipped without the necessary skill" error log.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:29:01 -04:00
MagicBotandClaude Opus 5.5 7abc63ffc3 Read item skill requirements from the cache template
validForSkills, isShield, the guard attack rating and the NPC vendor skill
filter read getItemSkillReq. Offline parity (p15d.py, 7586 rows): 0
differences. No template lists "Cloth" in item_skill_req and none has more
than one entry, so file order vs HashMap order is moot.

Value changes: none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:28:32 -04:00
MagicBotandClaude Opus 5.5 5b3c511b55 Read item eq slots from the cache template
isTwoHanded, validForSlot, getSwingAnimation and the mob equipment set
read getItemEqSlotsOr/And, which drop the exporter's NONE. Offline parity
(p15c.py, 7586 rows): 0 differences once NONE is ignored.

Value changes:
- validForSlot: items whose only slot is NONE no longer pass for slot NONE.
- getSwingAnimation: the 7 slotless weapons (Rock 19297, Arrow 25650,
  siege ammo 29000/29010/29020/29030/29350) return the default 75 instead
  of indexing their empty left-hand anim list.
- MobBase equipment sets skip slotless items instead of keying them under
  NONE. No EQUIP booty entry references one (the 104 sets that do are ITEM
  booty sets).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:23:41 -04:00
MagicBotandClaude Opus 5.5 73947f3dc8 Drop NONE from rune and deed eq slots
Matches ItemParser, so every CObjectTemplate returns an empty slot set for
the exporter's ["NONE"] mask. All 2695 RUNE and 880 DEED templates have
["NONE"] only; nothing reads these sets yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:22:57 -04:00
MagicBotandClaude Opus 5.5 c7d8483d55 Read item race/class/disc requirements from the cache template
ValidRace/ValidClass/ValidDiscipline use the single req set plus the
restrict flag (true = blacklist, false = whitelist) instead of the legacy
req/res split. Offline parity (p15c.py, 7586 rows): 0 differences in
restrict or set for race, class and disc.

Value changes: none for equip checks. The legacy disc blacklist branch was
inverted (passed only when a listed disc was held); the new check passes
when none is held. No ITEM has a disc blacklist (only 19 RUNEs), and
ValidDiscipline has no callers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:22:36 -04:00
MagicBotandClaude Opus 5.5 0688cf231f Fix isTwoHanded always returning false
EnumSet.contains(EnumSet) is never true; use containsAll so the 350
weapons with item_eq_slots_and {LHELD, RHELD} block the other hand.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:22:09 -04:00
MagicBotandClaude Opus 5.5 6b2f000434 Read the weapon block from the cache template item_weapon
Range, speed, damage list and swing anims now come from
engine.parsers.objects.ItemTemplate.getWeapon(templateID). Non-weapons and
missing templates get an empty block, matching the legacy zero defaults.

Offline parity (scripts/p15b.py, 811 WEAPON rows vs COBJECTS/ITEM): 0
differences in speed, range, projectile, idle anim, damage list or either
anim list. No duplicate damage types exist, so sum vs first is moot; first
entry is used as before. 26 weapons (ammo, lutes, no-stats crossbows) have an
empty damage list, same as the DB. No value changes. No comparator removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:17:24 -04:00
MagicBotandClaude Opus 5.5 441a935bd9 Read armor resists from the cache template EnumMap
Resists.getArmorResists and NPCManager.applyEquipmentResists now read
cacheTemplate.getCombatAttackResist() with DamageType keys instead of the
legacy String-keyed map, and default a missing key to 0 instead of an
unboxing NPE.

Offline parity (scripts/p15a.py, all 7586 static_item_templates rows vs
the template CObjectIndex.lookup picks): 0 differences in the full
combat_attack_resist map. Every ITEM/DEED/RUNE template carries all 16
keys, so no value changes. No comparator added or removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:11:21 -04:00
MagicBotandClaude Opus 5.5 b63826a7b7 Import DeedTemplate in PlaceAssetMsgHandler
c7747467 used DeedTemplate._deeds in the deed placement check without
importing it, which broke the build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:52:22 -04:00
MagicBotandClaude Opus 5.5 2774d8a510 Read offering info and bane rank through the bridge
Shrine boons read getItemOfferingInfo() and the banestone and bane
production paths read getItemBaneRank() on template.cacheTemplate.

The legacy parser only kept item_bane_rank when ACTIONRESPONSE is
4250517122; the cache parsers always read it. Parity shows this makes
no difference: every template outside that gate has bane rank 0.

Parity (offline, scripts/p14.py, 7586 templates): 0 differences in
item_offering_info and item_bane_rank. No value changes expected.

JSON-Refactor-Plan Task 1.4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:46:14 -04:00
MagicBotandClaude Opus 5.5 9a10574e59 Read defense, bulk and primary attr from the cache ItemTemplate
item_defense_rating, item_bulk_factor and item_primary_attr are
Item-only fields, not on CObjectTemplate, so their consumers read
engine.parsers.objects.ItemTemplate._items by templateID, like the
RuneTemplate and DeedTemplate consumers. The primary attr checks
compare with == because the cache template leaves the attr null
(legacy: None) on non-weapons.

Parity (offline, scripts/p14.py, 7586 templates): 0 differences in
item_defense_rating, item_bulk_factor and item_primary_attr. Every DB
ARMOR and WEAPON template is in the ITEM folder, so both sides gate
these fields on the same templates. No value changes expected.

JSON-Refactor-Plan Task 1.4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:45:59 -04:00
MagicBotandClaude Opus 5.5 d197f62c1f Read template health, charges and flags through the bridge
Consumers of the legacy ItemTemplate combat_health_full,
item_initial_charges and item_flags now read getCombatHealthFull(),
getItemInitialCharges() and getItemFlags() on template.cacheTemplate.
No consumer read the template's combat_health_current; the
combat_health_current reads are the Item's own field.

Parity (offline, scripts/p14.py, 7586 templates): 0 differences in
combat_health_current, combat_health_full, item_initial_charges and
item_flags ("None" dropped on both sides). No value changes expected.

JSON-Refactor-Plan Task 1.4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:45:17 -04:00
MagicBotandClaude Opus 5.5 dc4a9ee08a Read item weight, value and base name through the bridge
Consumers of the legacy ItemTemplate item_wt, item_value and
item_base_name now read getItemWt(), getItemValue() and
getItemBaseName() on template.cacheTemplate.

Parity (offline, scripts/p14.py, 7586 templates): 0 differences in
item_wt, item_value and item_base_name. No value changes expected.

JSON-Refactor-Plan Task 1.4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:44:35 -04:00
MagicBotandClaude Opus 5.5 b8ac8cce3e Read item_type through the cache template bridge
Every consumer of the legacy ItemTemplate item_type now reads
template.cacheTemplate.getItemType(). Left on the legacy field: the
type count in dbItemHandler.LOAD_ITEM_TEMPLATES, which runs before the
bridge is linked. The charter checks already read DeedTemplate.

Parity (offline, static_item_templates vs the template
CObjectIndex.lookup picks, scripts/p14.py, 7586 templates: ITEM 4011,
DEED 880, RUNE 2695): 0 differences in item_type. No value changes
expected.

JSON-Refactor-Plan Task 1.4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:43:57 -04:00
MagicBotandClaude Opus 5.5 6825f94f1e Check charters through DeedTemplate
GuildCreationFinalizeHandler and UseCharterMsg now match charters by
DeedTemplate._deeds instead of the shared item_type getter, like the
other deed paths.

Value change: template 545 "Charter" (ITEM folder, CHARTER) no longer
counts as a charter. It is a base template that players can't get: its
only DB reference is static_vendor_items with vendorType 0, it has no
loot rows, and it is not in GuildCharterType.templateLookup, so guild
creation already rejected it.

JSON-Refactor-Plan Task 1.3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:47:09 -04:00
MagicBotandClaude Opus 5.5 c774746736 Read deed consumers from DeedTemplate
Deed placement (ObjectActionMsgHandler, PlaceAssetMsgHandler) reads
deed_structure_id from DeedTemplate._deeds. The deed, employment
contract and charter type checks (PlaceAssetMsgHandler,
ActivateNPCMsgHandler, GuildCreationFinalizeHandler, UseCharterMsg,
Item.serialize) read item_type through the cache template bridge.
Charters go through the shared getter rather than _deeds because
template 545 "Charter" is a CHARTER in the ITEM folder.

Parity (offline, static_item_templates vs COBJECTS, scripts/p13.py,
881 templates: all 880 DEED plus ITEM 545): 0 differences in
item_type and deed_structure_id. Every DB DEED, EMPLOYMENTCONTRACT,
PETTOTEM and FURNITUREDEED id is in the DEED folder. No value changes
expected. No pet totem or furniture deed consumer reads template
fields, so neither changes.

JSON-Refactor-Plan Task 1.3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:42:54 -04:00
MagicBotandClaude Opus 5.5 3e087bd1ac Read mob rune damage and natural attacks from RuneTemplate
AbstractCharacter mob damage/ATR and CombatManager.getNaturalAttack now
read RuneTemplate._runes instead of the legacy ItemTemplate map.

Parity (offline, static_item_templates vs COBJECTS/RUNE, 2695 runes):
0 differences in rune_min_damage, rune_max_damage, rune_attack and
rune_naturalattacks. All 2366 runes with natural attacks use the
10-value layout. No value changes expected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:35:02 -04:00
MagicBotandClaude Opus 5.5 765cb9edb6 Bridge legacy ItemTemplate to its cache template
Each engine.objects.ItemTemplate gets a cacheTemplate field, filled by
linkCacheTemplates() right after CObjectIndex.build() on both servers,
so consumers can move to CObjectTemplate one field at a time.

ParityCheck gains a static_item_templates comparator: a null bridge is
reported as missing in json, and obj_name and item_type are compared
through the interface to catch a wrong folder pick.

Import convention until the legacy class is removed (Task 1.8): the
legacy engine.objects.ItemTemplate keeps the plain import; the cache
class is always written engine.parsers.objects.ItemTemplate. Migrated
consumers should depend on CObjectTemplate instead.

JSON-Refactor-Plan Task 1.1. No consumers change; no values change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:21:47 -04:00
MagicBotandClaude Opus 5.5 4765e7993f Add shared obj/combat/item getters to CObjectTemplate
The ITEM, DEED and RUNE cache templates implement the getters for the
65 fields all three define. The Item-only fields (weapon, primary and
secondary attr, bulk, defense rating, sheath, stub flag/id) stay off the
interface. CObjectTemplate.lookup delegates to CObjectIndex.lookup.

JSON-Refactor-Plan Task 1.1 (D1). No consumers change; no values change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:20:33 -04:00
65 changed files with 1843 additions and 1093 deletions

No files matched your search

+9 -35
View File
@@ -16,8 +16,6 @@ import engine.mbEnums.ItemType;
import engine.objects.AbstractCharacter; import engine.objects.AbstractCharacter;
import engine.objects.CharacterItemManager; import engine.objects.CharacterItemManager;
import engine.objects.Item; import engine.objects.Item;
import engine.objects.ItemTemplate;
import org.json.JSONObject;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.Connection; import java.sql.Connection;
@@ -177,47 +175,23 @@ public class dbItemHandler extends dbHandlerBase {
return itemList; return itemList;
} }
public void LOAD_ITEM_TEMPLATES() { public HashMap<Integer, Integer> LOAD_TEMPLATE_MODTABLES() {
HashMap<ItemType, Integer> templateTCountMap = new HashMap<>(); HashMap<Integer, Integer> modTables = new HashMap<>();
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_item_templates`;");
ResultSet rs = preparedStatement.executeQuery()) {
while (rs.next()) {
int templateID = rs.getInt("id");
JSONObject jsonObject = new JSONObject(rs.getString("template"));
ItemTemplate itemTemplate = new ItemTemplate(jsonObject);
itemTemplate.template_id = templateID;
ItemTemplate.templates.put(templateID, itemTemplate);
templateTCountMap.merge(itemTemplate.item_type, 1, Integer::sum);
}
Logger.info(templateTCountMap.toString());
} catch (Exception e) {
Logger.error(e);
}
}
public void LOAD_TEMPLATE_MODTABLES() {
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_vendor_items`;"); PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_vendor_items`;");
ResultSet rs = preparedStatement.executeQuery()) { ResultSet rs = preparedStatement.executeQuery()) {
while (rs.next()) { while (rs.next())
int templateID = rs.getInt("templateID"); modTables.put(rs.getInt("templateID"), rs.getInt("modTable"));
int modTable = rs.getInt("modTable");
ItemTemplate template = ItemTemplate.templates.get(templateID);
template.modTable = modTable;
}
} catch (Exception e) { } catch (Exception e) {
Logger.error(e); Logger.error(e);
} }
Logger.info("read: " + modTables.size());
return modTables;
} }
public Item GET_ITEM(final int itemUUID) { public Item GET_ITEM(final int itemUUID) {
@@ -325,7 +299,7 @@ public class dbItemHandler extends dbHandlerBase {
for (Item item : inventory) { for (Item item : inventory) {
if (item.template.item_type.equals(ItemType.GOLD)) if (item.template.getItemType().equals(ItemType.GOLD))
continue; continue;
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
@@ -474,7 +448,7 @@ public class dbItemHandler extends dbHandlerBase {
*/ */
public boolean UPDATE_GOLD(final Item item, int newValue, int oldValue) { public boolean UPDATE_GOLD(final Item item, int newValue, int oldValue) {
if (!item.template.item_type.equals(ItemType.GOLD)) if (!item.template.getItemType().equals(ItemType.GOLD))
return false; return false;
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
@@ -554,7 +528,7 @@ public class dbItemHandler extends dbHandlerBase {
// Write 0 if we will not modify the value from template // Write 0 if we will not modify the value from template
if (value == item.template.item_value) if (value == item.template.getItemValue())
value = 0; value = 0;
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
@@ -50,7 +50,15 @@ public class dbPromotionClassHandler extends dbHandlerBase {
public PromotionClass GET_PROMOTION_CLASS(final int objectUUID) { public PromotionClass GET_PROMOTION_CLASS(final int objectUUID) {
PromotionClass promotionClass = null; PromotionClass promotionClass;
if (objectUUID == 0)
return null;
promotionClass = (PromotionClass) DbManager.getFromCache(mbEnums.GameObjectType.PromotionClass, objectUUID);
if (promotionClass != null)
return promotionClass;
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_rune_promotion` WHERE `ID` = ?")) { PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_rune_promotion` WHERE `ID` = ?")) {
+3 -3
View File
@@ -15,8 +15,8 @@ import engine.gameManager.DbManager;
import engine.mbEnums; import engine.mbEnums;
import engine.objects.AbstractGameObject; import engine.objects.AbstractGameObject;
import engine.objects.Item; import engine.objects.Item;
import engine.objects.ItemTemplate;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import engine.parsers.objects.CObjectTemplate;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
/** /**
@@ -38,7 +38,7 @@ public class CreateItemCmd extends AbstractDevCmd {
} }
int templateID = Integer.parseInt(words[0]); int templateID = Integer.parseInt(words[0]);
ItemTemplate template = ItemTemplate.templates.get(templateID); CObjectTemplate template = CObjectTemplate.lookup(templateID);
if (template == null) { if (template == null) {
ChatManager.chatSystemInfo(playerCharacter, "No such template found."); ChatManager.chatSystemInfo(playerCharacter, "No such template found.");
@@ -51,7 +51,7 @@ public class CreateItemCmd extends AbstractDevCmd {
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
if (!playerCharacter.charItemManager.hasRoomInventory(template.item_wt)) { if (!playerCharacter.charItemManager.hasRoomInventory(template.getItemWt())) {
ChatManager.chatSystemInfo(playerCharacter, "You are encumbered!."); ChatManager.chatSystemInfo(playerCharacter, "You are encumbered!.");
break; break;
} }
+106
View File
@@ -0,0 +1,106 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.devcmd.cmds;
import engine.devcmd.AbstractDevCmd;
import engine.gameManager.ChatManager;
import engine.gameManager.DbManager;
import engine.mbEnums;
import engine.objects.AbstractGameObject;
import engine.objects.Building;
import engine.objects.City;
import engine.objects.PlayerCharacter;
import engine.objects.Warehouse;
import java.util.HashMap;
public class FillCmd extends AbstractDevCmd {
public FillCmd() {
super("fill");
}
@Override
protected void _doCmd(PlayerCharacter pc, String[] words,
AbstractGameObject target) {
Building building;
City city;
Warehouse warehouse;
int amount = Integer.MAX_VALUE;
HashMap<mbEnums.ResourceType, Integer> oldResources;
if (words.length > 1) {
this.sendUsage(pc);
return;
}
if (words.length == 1 && !words[0].isEmpty()) {
try {
amount = Integer.parseInt(words[0]);
} catch (NumberFormatException e) {
throwbackError(pc, "Amount must be a number, " + words[0] + " is invalid");
return;
}
if (amount < 0) {
throwbackError(pc, "Amount must be 0 or more");
return;
}
}
if (target == null || target.getObjectType() != mbEnums.GameObjectType.Building) {
throwbackError(pc, "Select a warehouse");
return;
}
building = (Building) target;
if (building.getBlueprint() == null || building.getBlueprint().getBuildingGroup() != mbEnums.BuildingGroup.WAREHOUSE) {
throwbackError(pc, "Selected building is not a warehouse");
return;
}
city = building.getCity();
if (city == null || city.warehouse == null || city.warehouse.building == null
|| city.warehouse.building.getObjectUUID() != building.getObjectUUID()) {
throwbackError(pc, "Selected warehouse is not the active warehouse of a city");
return;
}
warehouse = city.warehouse;
oldResources = new HashMap<>(warehouse.resources);
for (mbEnums.ResourceType resourceType : mbEnums.ResourceType.values())
warehouse.resources.put(resourceType, Math.min(amount, resourceType.deposit_limit));
if (!DbManager.WarehouseQueries.UPDATE_WAREHOUSE(warehouse)) {
warehouse.resources.putAll(oldResources);
throwbackError(pc, "Failed to update the warehouse in the database");
return;
}
ChatManager.chatSayInfo(pc, "Filled the " + city.getCityName() + " warehouse"
+ (amount == Integer.MAX_VALUE ? " to each deposit limit" : " with " + amount + " of each resource (capped at the deposit limit)"));
}
@Override
protected String _getHelpString() {
return "Sets every resource in the selected warehouse";
}
@Override
protected String _getUsageString() {
return "' ./fill [amount]' with a warehouse selected (no amount fills each resource to its deposit limit)";
}
}
+6 -5
View File
@@ -18,6 +18,7 @@ import engine.mbEnums.BuildingGroup;
import engine.mbEnums.GameObjectType; import engine.mbEnums.GameObjectType;
import engine.mbEnums.TargetColor; import engine.mbEnums.TargetColor;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import engine.util.StringUtils; import engine.util.StringUtils;
import java.text.DecimalFormat; import java.text.DecimalFormat;
@@ -507,17 +508,17 @@ public class InfoCmd extends AbstractDevCmd {
case Item: //intentional passthrough case Item: //intentional passthrough
case MobLoot: case MobLoot:
Item item = (Item) target; Item item = (Item) target;
ItemTemplate template = ItemTemplate.templates.get(item.templateID); CObjectTemplate template = CObjectTemplate.lookup(item.templateID);
output += StringUtils.addWS("Template: " + template.template_id, 20); output += StringUtils.addWS("Template: " + template.getTemplateId(), 20);
output += "Weight: " + template.item_wt; output += "Weight: " + template.getItemWt();
output += newline; output += newline;
DecimalFormat df = new DecimalFormat("###,###,###,###,##0"); DecimalFormat df = new DecimalFormat("###,###,###,###,##0");
output += StringUtils.addWS("Qty: " output += StringUtils.addWS("Qty: "
+ df.format(item.getNumOfItems()), 20); + df.format(item.getNumOfItems()), 20);
output += "Charges: " + (byte) item.chargesRemaining output += "Charges: " + (byte) item.chargesRemaining
+ '/' + item.template.item_initial_charges; + '/' + item.template.getItemInitialCharges();
output += newline; output += newline;
output += "Name: " + template.item_base_name; output += "Name: " + template.getItemBaseName();
output += newline; output += newline;
output += item.getContainerInfo(); output += item.getContainerInfo();
+15 -7
View File
@@ -11,9 +11,11 @@ package engine.devcmd.cmds;
import engine.devcmd.AbstractDevCmd; import engine.devcmd.AbstractDevCmd;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.mbEnums.ItemContainerType;
import engine.mbEnums.ItemType; import engine.mbEnums.ItemType;
import engine.mbEnums.OwnerType; import engine.mbEnums.OwnerType;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
/** /**
@@ -59,17 +61,17 @@ public class MakeItemCmd extends AbstractDevCmd {
} }
int templateID; int templateID;
ItemTemplate template; CObjectTemplate template;
try { try {
templateID = Integer.parseInt(words[0]); templateID = Integer.parseInt(words[0]);
template = ItemTemplate.templates.get(templateID); template = CObjectTemplate.lookup(templateID);
if (template == null) { if (template == null) {
throwbackError(pc, "No item template with id " + words[0]); throwbackError(pc, "No item template with id " + words[0]);
return; return;
} }
if (template.item_type == ItemType.GOLD) { if (template.getItemType() == ItemType.GOLD) {
this.throwbackInfo(pc, "use /addgold to add gold."); this.throwbackInfo(pc, "use /addgold to add gold.");
return; return;
} }
@@ -131,7 +133,7 @@ public class MakeItemCmd extends AbstractDevCmd {
return; return;
} }
} }
template = ItemTemplate.templates.get(templateID); template = CObjectTemplate.lookup(templateID);
if (template == null) { if (template == null) {
throwbackError(pc, "Unable to find template " + templateID); throwbackError(pc, "Unable to find template " + templateID);
@@ -139,8 +141,8 @@ public class MakeItemCmd extends AbstractDevCmd {
} }
if ((numItems > 1) if ((numItems > 1)
&& (template.item_type.equals(ItemType.RESOURCE) == false) && (template.getItemType().equals(ItemType.RESOURCE) == false)
&& (template.item_type.equals(ItemType.OFFERING)) == false) && (template.getItemType().equals(ItemType.OFFERING)) == false)
numItems = 1; numItems = 1;
CharacterItemManager cim = pc.charItemManager; CharacterItemManager cim = pc.charItemManager;
@@ -154,7 +156,7 @@ public class MakeItemCmd extends AbstractDevCmd {
for (int i = 0; i < quantity; i++) { for (int i = 0; i < quantity; i++) {
int weight = template.item_wt; int weight = template.getItemWt();
if (!cim.hasRoomInventory(weight)) { if (!cim.hasRoomInventory(weight)) {
throwbackError(pc, "Not enough room in inventory for any more of this item. " + i + " produced."); throwbackError(pc, "Not enough room in inventory for any more of this item. " + i + " produced.");
@@ -168,6 +170,7 @@ public class MakeItemCmd extends AbstractDevCmd {
Item item = new Item(templateID); Item item = new Item(templateID);
item.ownerID = pc.getObjectUUID(); item.ownerID = pc.getObjectUUID();
item.ownerType = OwnerType.PlayerCharacter; item.ownerType = OwnerType.PlayerCharacter;
item.containerType = ItemContainerType.INVENTORY;
if (numItems > 1) if (numItems > 1)
item.setNumOfItems(numItems); item.setNumOfItems(numItems);
@@ -179,6 +182,11 @@ public class MakeItemCmd extends AbstractDevCmd {
return; return;
} }
if (item == null) {
throwbackError(pc, "DB error 2: Unable to create item " + templateID + ".");
return;
}
//create prefix //create prefix
if (!prefix.isEmpty()) if (!prefix.isEmpty())
item.addPermanentEnchantmentForDev(prefix, 0); item.addPermanentEnchantmentForDev(prefix, 0);
+3 -2
View File
@@ -11,6 +11,7 @@ package engine.devcmd.cmds;
import engine.devcmd.AbstractDevCmd; import engine.devcmd.AbstractDevCmd;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import java.util.ArrayList; import java.util.ArrayList;
@@ -52,8 +53,8 @@ public class PrintBankCmd extends AbstractDevCmd {
throwbackInfo(pc, "Bank for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')'); throwbackInfo(pc, "Bank for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')');
for (Item item : list) { for (Item item : list) {
ItemTemplate template = ItemTemplate.templates.get(item.templateID); CObjectTemplate template = CObjectTemplate.lookup(item.templateID);
throwbackInfo(pc, " " + template.item_base_name + ", count: " + item.getNumOfItems()); throwbackInfo(pc, " " + template.getItemBaseName() + ", count: " + item.getNumOfItems());
} }
Item gold = cim.getGoldBank(); Item gold = cim.getGoldBank();
+3 -2
View File
@@ -13,6 +13,7 @@ import engine.devcmd.AbstractDevCmd;
import engine.gameManager.ChatManager; import engine.gameManager.ChatManager;
import engine.mbEnums.GameObjectType; import engine.mbEnums.GameObjectType;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import engine.powers.effectmodifiers.AbstractEffectModifier; import engine.powers.effectmodifiers.AbstractEffectModifier;
public class PrintBonusesCmd extends AbstractDevCmd { public class PrintBonusesCmd extends AbstractDevCmd {
@@ -33,8 +34,8 @@ public class PrintBonusesCmd extends AbstractDevCmd {
if (target instanceof Item) { if (target instanceof Item) {
type = "Item"; type = "Item";
tar = (Item) target; tar = (Item) target;
ItemTemplate template = ItemTemplate.templates.get(((Item) tar).templateID); CObjectTemplate template = CObjectTemplate.lookup(((Item) tar).templateID);
name = template.item_base_name; name = template.getItemBaseName();
} else if (target instanceof AbstractCharacter) { } else if (target instanceof AbstractCharacter) {
tar = (AbstractCharacter) target; tar = (AbstractCharacter) target;
name = ((AbstractCharacter) tar).getFirstName(); name = ((AbstractCharacter) tar).getFirstName();
+3 -3
View File
@@ -66,7 +66,7 @@ public class PrintEquipCmd extends AbstractDevCmd {
throwbackInfo(pc, "Equip for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')'); throwbackInfo(pc, "Equip for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')');
for (mbEnums.EquipSlotType slot : tarMob.charItemManager.equipped.keySet()) { for (mbEnums.EquipSlotType slot : tarMob.charItemManager.equipped.keySet()) {
Item equip = tarMob.charItemManager.equipped.get(slot); Item equip = tarMob.charItemManager.equipped.get(slot);
throwbackInfo(pc, equip.templateID + " : " + equip.template.item_base_name + ", slot: " + slot); throwbackInfo(pc, equip.templateID + " : " + equip.template.getItemBaseName() + ", slot: " + slot);
} }
return; return;
} }
@@ -76,7 +76,7 @@ public class PrintEquipCmd extends AbstractDevCmd {
throwbackInfo(pc, "Equip for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')'); throwbackInfo(pc, "Equip for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')');
for (mbEnums.EquipSlotType slot : tarMob.charItemManager.equipped.keySet()) { for (mbEnums.EquipSlotType slot : tarMob.charItemManager.equipped.keySet()) {
Item equip = tarMob.charItemManager.equipped.get(slot); Item equip = tarMob.charItemManager.equipped.get(slot);
throwbackInfo(pc, equip.templateID + " : " + equip.template.item_base_name + ", slot: " + slot); throwbackInfo(pc, equip.templateID + " : " + equip.template.getItemBaseName() + ", slot: " + slot);
} }
return; return;
} }
@@ -87,7 +87,7 @@ public class PrintEquipCmd extends AbstractDevCmd {
for (mbEnums.EquipSlotType slot : list.keySet()) { for (mbEnums.EquipSlotType slot : list.keySet()) {
Item item = list.get(slot); Item item = list.get(slot);
throwbackInfo(pc, " " + item.template.item_base_name + ", slot: " + slot); throwbackInfo(pc, " " + item.template.getItemBaseName() + ", slot: " + slot);
} }
} }
@@ -12,6 +12,7 @@ package engine.devcmd.cmds;
import engine.devcmd.AbstractDevCmd; import engine.devcmd.AbstractDevCmd;
import engine.mbEnums.ItemType; import engine.mbEnums.ItemType;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
@@ -75,18 +76,18 @@ public class PrintInventoryCmd extends AbstractDevCmd {
int goldCount = 0; int goldCount = 0;
for (Item item : inventory) { for (Item item : inventory) {
ItemTemplate template = ItemTemplate.templates.get(item.templateID); CObjectTemplate template = CObjectTemplate.lookup(item.templateID);
if (item.template.item_type.equals(ItemType.GOLD) == false) { if (item.template.getItemType().equals(ItemType.GOLD) == false) {
String chargeInfo = ""; String chargeInfo = "";
int chargeMax = template.item_initial_charges; int chargeMax = template.getItemInitialCharges();
if (chargeMax > 0) { if (chargeMax > 0) {
int charges = item.chargesRemaining; int charges = item.chargesRemaining;
chargeInfo = " charges: " + charges + '/' + chargeMax; chargeInfo = " charges: " + charges + '/' + chargeMax;
} }
throwbackInfo(pc, " " + template.item_base_name + ", count: " + item.getNumOfItems() + chargeInfo); throwbackInfo(pc, " " + template.getItemBaseName() + ", count: " + item.getNumOfItems() + chargeInfo);
} else } else
goldCount += item.getNumOfItems(); goldCount += item.getNumOfItems();
} }
+3 -2
View File
@@ -11,6 +11,7 @@ package engine.devcmd.cmds;
import engine.devcmd.AbstractDevCmd; import engine.devcmd.AbstractDevCmd;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import java.util.ArrayList; import java.util.ArrayList;
@@ -50,8 +51,8 @@ public class PrintVaultCmd extends AbstractDevCmd {
ArrayList<Item> list = cim.getVault(); ArrayList<Item> list = cim.getVault();
throwbackInfo(pc, "Vault for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')'); throwbackInfo(pc, "Vault for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')');
for (Item item : list) { for (Item item : list) {
ItemTemplate template = ItemTemplate.templates.get(item.templateID); CObjectTemplate template = CObjectTemplate.lookup(item.templateID);
throwbackInfo(pc, " " + template.item_base_name + ", count: " + item.getNumOfItems()); throwbackInfo(pc, " " + template.getItemBaseName() + ", count: " + item.getNumOfItems());
} }
Item gold = cim.getGoldVault(); Item gold = cim.getGoldVault();
if (gold != null) if (gold != null)
+4 -3
View File
@@ -5,6 +5,7 @@ import engine.gameManager.LootManager;
import engine.gameManager.ZoneManager; import engine.gameManager.ZoneManager;
import engine.loot.BootySetEntry; import engine.loot.BootySetEntry;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
@@ -34,10 +35,10 @@ public class SimulateBootyCmd extends AbstractDevCmd {
if (mob.bootySet != 0) { if (mob.bootySet != 0) {
for (BootySetEntry entry : LootManager._bootySetMap.get(mob.bootySet)) { for (BootySetEntry entry : LootManager._bootySetMap.get(mob.bootySet)) {
ItemTemplate template = ItemTemplate.templates.get(entry.templateID); CObjectTemplate template = CObjectTemplate.lookup(entry.templateID);
if (template != null) if (template != null)
output += "[" + entry.bootyType + "] " + template.item_base_name + " [Chance] " + entry.dropChance + newline; output += "[" + entry.bootyType + "] " + template.getItemBaseName() + " [Chance] " + entry.dropChance + newline;
} }
} }
@@ -57,7 +58,7 @@ public class SimulateBootyCmd extends AbstractDevCmd {
try { try {
mob.loadInventory(); mob.loadInventory();
for (Item lootItem : mob.charItemManager.getInventory()) { for (Item lootItem : mob.charItemManager.getInventory()) {
switch (lootItem.template.item_type) { switch (lootItem.template.getItemType()) {
case EMPLOYMENTCONTRACT: //CONTRACT case EMPLOYMENTCONTRACT: //CONTRACT
Contracts.add(lootItem); Contracts.add(lootItem);
break; break;
+6 -5
View File
@@ -22,6 +22,7 @@ import engine.mbEnums.BuildingGroup;
import engine.mbEnums.GameObjectType; import engine.mbEnums.GameObjectType;
import engine.net.client.msg.ErrorPopupMsg; import engine.net.client.msg.ErrorPopupMsg;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@@ -199,12 +200,12 @@ public enum BuildingManager {
return false; return false;
} }
ItemTemplate template = ItemTemplate.templates.get(1705032); // Elan Stone CObjectTemplate template = CObjectTemplate.lookup(1705032); // Elan Stone
if (!player.charItemManager.hasRoomInventory(template.item_wt)) if (!player.charItemManager.hasRoomInventory(template.getItemWt()))
return false; return false;
if (!ItemManager.MakeItemForPlayer(template.template_id, player, amount)) if (!ItemManager.MakeItemForPlayer(template.getTemplateId(), player, amount))
return false; return false;
shrine.setFavors(0); shrine.setFavors(0);
@@ -218,12 +219,12 @@ public enum BuildingManager {
for (mbEnums.ResourceType resourceType : EnumSet.allOf(mbEnums.ResourceType.class)) { for (mbEnums.ResourceType resourceType : EnumSet.allOf(mbEnums.ResourceType.class)) {
ItemTemplate resourceTemplate = ItemTemplate.templates.get(resourceType.templateID); CObjectTemplate resourceTemplate = CObjectTemplate.lookup(resourceType.templateID);
if (resourceTemplate == null) if (resourceTemplate == null)
continue; continue;
if (!player.charItemManager.hasRoomInventory(resourceTemplate.item_wt)) { if (!player.charItemManager.hasRoomInventory(resourceTemplate.getItemWt())) {
ChatManager.chatSystemInfo(player, "You can not carry any more of that item."); ChatManager.chatSystemInfo(player, "You can not carry any more of that item.");
return false; return false;
} }
+4 -3
View File
@@ -22,6 +22,7 @@ import engine.net.client.ClientConnection;
import engine.net.client.handlers.ClientAdminCommandMsgHandler; import engine.net.client.handlers.ClientAdminCommandMsgHandler;
import engine.net.client.msg.chat.*; import engine.net.client.msg.chat.*;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import engine.server.world.WorldServer; import engine.server.world.WorldServer;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@@ -535,12 +536,12 @@ public enum ChatManager {
if (item != null) //Steal if (item != null) //Steal
if (success) { if (success) {
String name = ""; String name = "";
if (item.template.item_type.equals(mbEnums.ItemType.GOLD)) if (item.template.getItemType().equals(mbEnums.ItemType.GOLD))
name = amount + " gold "; name = amount + " gold ";
else { else {
String vowels = "aeiou"; String vowels = "aeiou";
ItemTemplate template = ItemTemplate.templates.get(item.templateID); CObjectTemplate template = CObjectTemplate.lookup(item.templateID);
String iName = template.item_base_name; String iName = template.getItemBaseName();
if (iName.length() > 0) if (iName.length() > 0)
if (vowels.indexOf(iName.substring(0, 1).toLowerCase()) >= 0) if (vowels.indexOf(iName.substring(0, 1).toLowerCase()) >= 0)
name = "an " + iName + ' '; name = "an " + iName + ' ';
+33 -30
View File
@@ -18,6 +18,8 @@ import engine.net.client.msg.PowerProjectileMsg;
import engine.net.client.msg.TargetedActionMsg; import engine.net.client.msg.TargetedActionMsg;
import engine.net.client.msg.UpdateStateMsg; import engine.net.client.msg.UpdateStateMsg;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import engine.parsers.objects.RuneTemplate;
import engine.powers.DamageShield; import engine.powers.DamageShield;
import engine.powers.effectmodifiers.AbstractEffectModifier; import engine.powers.effectmodifiers.AbstractEffectModifier;
import engine.powers.effectmodifiers.WeaponProcEffectModifier; import engine.powers.effectmodifiers.WeaponProcEffectModifier;
@@ -92,25 +94,25 @@ public enum CombatManager {
return; return;
} }
if (mainWeapon == null && offWeapon != null && !offWeapon.template.item_skill_used.equals("Block")) { if (mainWeapon == null && offWeapon != null && !offWeapon.template.getItemSkillUsed().equals("Block")) {
//swing left hand only //swing left hand only
processAttack(attacker, target, mbEnums.EquipSlotType.LHELD); processAttack(attacker, target, mbEnums.EquipSlotType.LHELD);
return; return;
} }
if (mainWeapon == null && offWeapon != null && offWeapon.template.item_skill_used.equals("Block")) { if (mainWeapon == null && offWeapon != null && offWeapon.template.getItemSkillUsed().equals("Block")) {
//no weapon equipped with a shield, punch with one hand //no weapon equipped with a shield, punch with one hand
processAttack(attacker, target, mbEnums.EquipSlotType.RHELD); processAttack(attacker, target, mbEnums.EquipSlotType.RHELD);
return; return;
} }
if (mainWeapon != null && offWeapon != null && offWeapon.template.item_skill_used.equals("Block")) { if (mainWeapon != null && offWeapon != null && offWeapon.template.getItemSkillUsed().equals("Block")) {
//one weapon equipped with a shield, swing with one hand //one weapon equipped with a shield, swing with one hand
processAttack(attacker, target, mbEnums.EquipSlotType.RHELD); processAttack(attacker, target, mbEnums.EquipSlotType.RHELD);
return; return;
} }
if (mainWeapon != null && offWeapon != null && !offWeapon.template.item_skill_used.equals("Block")) { if (mainWeapon != null && offWeapon != null && !offWeapon.template.getItemSkillUsed().equals("Block")) {
//two weapons equipped, swing both hands //two weapons equipped, swing both hands
processAttack(attacker, target, mbEnums.EquipSlotType.RHELD); processAttack(attacker, target, mbEnums.EquipSlotType.RHELD);
if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter))
@@ -146,7 +148,7 @@ public enum CombatManager {
if (bonus != null) if (bonus != null)
rangeMod += bonus.getFloatPercentAll(mbEnums.ModType.WeaponRange, mbEnums.SourceType.None); rangeMod += bonus.getFloatPercentAll(mbEnums.ModType.WeaponRange, mbEnums.SourceType.None);
attackRange += weapon.template.item_weapon_max_range * rangeMod; attackRange += engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_max_range * rangeMod;
} else if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) { } else if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) {
//unarmed mob, add the natural attack range from its rune (0 for most melee mobs) //unarmed mob, add the natural attack range from its rune (0 for most melee mobs)
@@ -211,7 +213,7 @@ public enum CombatManager {
if (weapon != null) { if (weapon != null) {
float wepSpeed = (int) (weapon.template.item_weapon_wepspeed); float wepSpeed = (int) (engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_wepspeed);
if (weapon.getBonusPercent(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None) != 0f) //add weapon speed bonus if (weapon.getBonusPercent(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None) != 0f) //add weapon speed bonus
wepSpeed *= (1 + weapon.getBonus(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None)); wepSpeed *= (1 + weapon.getBonus(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None));
@@ -270,13 +272,13 @@ public enum CombatManager {
if (weapon != null && !attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) { if (weapon != null && !attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) {
//check if Out of Stamina //check if Out of Stamina
if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) { if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) {
if (attacker.getStamina() < (weapon.template.item_wt / 3f)) { if (attacker.getStamina() < (weapon.template.getItemWt() / 3f)) {
//set auto attack job //set auto attack job
setAutoAttackJob(attacker, slot, delay); setAutoAttackJob(attacker, slot, delay);
return; return;
} }
} }
float stam = weapon.template.item_wt / 3f; float stam = weapon.template.getItemWt() / 3f;
stam = (stam < 1) ? 1 : stam; stam = (stam < 1) ? 1 : stam;
attacker.modifyStamina(-(stam), attacker, true); attacker.modifyStamina(-(stam), attacker, true);
} else } else
@@ -416,7 +418,7 @@ public enum CombatManager {
if (((Mob) attacker).isSiege()) if (((Mob) attacker).isSiege())
damageType = mbEnums.DamageType.SIEGE; damageType = mbEnums.DamageType.SIEGE;
} else { } else {
damageType = (mbEnums.DamageType) attacker.charItemManager.getEquipped().get(slot).template.item_weapon_damage.keySet().toArray()[0]; damageType = engine.parsers.objects.ItemTemplate.getWeapon(attacker.charItemManager.getEquipped().get(slot).templateID).weapon_damage.get(0).damage_type;
} }
//get resists //get resists
@@ -577,13 +579,14 @@ public enum CombatManager {
target.setCombatTarget(attacker); target.setCombatTarget(attacker);
} }
public static int getSwingAnimation(ItemTemplate wb, DeferredPowerJob dpj, mbEnums.EquipSlotType slot) { public static int getSwingAnimation(CObjectTemplate wb, DeferredPowerJob dpj, mbEnums.EquipSlotType slot) {
//No weapon, return default animation //No weapon, return default animation
if (wb == null) if (wb == null)
return 75; return 75;
int token; int token;
engine.parsers.objects.ItemTemplate.Weapon weapon = engine.parsers.objects.ItemTemplate.getWeapon(wb.getTemplateId());
if (dpj != null) { if (dpj != null) {
@@ -594,7 +597,7 @@ public enum CombatManager {
} }
//Item has no equipment slots and should not try to return an animation, return default instead //Item has no equipment slots and should not try to return an animation, return default instead
if (wb.item_eq_slots_or == null || wb.item_eq_slots_or.isEmpty()) { if (wb.getItemEqSlotsOr().isEmpty()) {
return 75; return 75;
} }
@@ -603,18 +606,18 @@ public enum CombatManager {
int random; int random;
//Item can only be equipped in one slot, return animation for that slot //Item can only be equipped in one slot, return animation for that slot
if (wb.item_eq_slots_or.size() == 1) { if (wb.getItemEqSlotsOr().size() == 1) {
if (wb.item_eq_slots_or.iterator().next().equals(mbEnums.EquipSlotType.RHELD)) { if (wb.getItemEqSlotsOr().iterator().next().equals(mbEnums.EquipSlotType.RHELD)) {
anim = wb.weapon_attack_anim_right.get(0)[0]; anim = weapon.weapon_attack_anim_right.get(0)[0];
if (dpj != null) { if (dpj != null) {
random = ThreadLocalRandom.current().nextInt(wb.weapon_attack_anim_right.size()); random = ThreadLocalRandom.current().nextInt(weapon.weapon_attack_anim_right.size());
anim = wb.weapon_attack_anim_right.get(random)[0]; anim = weapon.weapon_attack_anim_right.get(random)[0];
} }
} else { } else {
anim = wb.weapon_attack_anim_left.get(0)[0]; anim = weapon.weapon_attack_anim_left.get(0)[0];
if (dpj != null) { if (dpj != null) {
random = ThreadLocalRandom.current().nextInt(wb.weapon_attack_anim_left.size()); random = ThreadLocalRandom.current().nextInt(weapon.weapon_attack_anim_left.size());
anim = wb.weapon_attack_anim_left.get(random)[0]; anim = weapon.weapon_attack_anim_left.get(random)[0];
} }
} }
return anim; return anim;
@@ -622,16 +625,16 @@ public enum CombatManager {
//Item can be equipped in either hand, and should have animation sets for each hand //Item can be equipped in either hand, and should have animation sets for each hand
if (slot.equals(mbEnums.EquipSlotType.RHELD)) { if (slot.equals(mbEnums.EquipSlotType.RHELD)) {
anim = wb.weapon_attack_anim_right.get(0)[0]; anim = weapon.weapon_attack_anim_right.get(0)[0];
if (dpj != null) { if (dpj != null) {
random = ThreadLocalRandom.current().nextInt(wb.weapon_attack_anim_right.size()); random = ThreadLocalRandom.current().nextInt(weapon.weapon_attack_anim_right.size());
anim = wb.weapon_attack_anim_right.get(random)[0]; anim = weapon.weapon_attack_anim_right.get(random)[0];
} }
} else { } else {
anim = wb.weapon_attack_anim_left.get(0)[0]; anim = weapon.weapon_attack_anim_left.get(0)[0];
if (dpj != null) { if (dpj != null) {
random = ThreadLocalRandom.current().nextInt(wb.weapon_attack_anim_left.size()); random = ThreadLocalRandom.current().nextInt(weapon.weapon_attack_anim_left.size());
anim = wb.weapon_attack_anim_left.get(random)[0]; anim = weapon.weapon_attack_anim_left.get(random)[0];
} }
} }
return anim; return anim;
@@ -713,7 +716,7 @@ public enum CombatManager {
// Mobs use their mobbase rune, players use their race rune. // Mobs use their mobbase rune, players use their race rune.
int runeID; int runeID;
ItemTemplate rune; RuneTemplate rune;
int hand = slot.equals(mbEnums.EquipSlotType.LHELD) ? 2 : 1; int hand = slot.equals(mbEnums.EquipSlotType.LHELD) ? 2 : 1;
switch (attacker.getObjectType()) { switch (attacker.getObjectType()) {
@@ -727,18 +730,18 @@ public enum CombatManager {
return null; return null;
} }
rune = ItemTemplate.templates.get(runeID); rune = RuneTemplate._runes.get(runeID);
if (rune == null || rune.rune_natural_attacks.isEmpty()) if (rune == null || rune.rune_naturalattacks.isEmpty())
return null; return null;
for (float[] attack : rune.rune_natural_attacks) for (float[] attack : rune.rune_naturalattacks)
if (attack.length > 3 && (int) attack[3] == hand) if (attack.length > 3 && (int) attack[3] == hand)
return attack; return attack;
// No entry for this hand, fall back to the first natural attack // No entry for this hand, fall back to the first natural attack
return rune.rune_natural_attacks.get(0); return rune.rune_naturalattacks.get(0);
} }
public static int calculatePetDamage(AbstractCharacter agent) { public static int calculatePetDamage(AbstractCharacter agent) {
@@ -101,6 +101,7 @@ public enum DevCmdManager {
DevCmdManager.registerDevCmd(new SetAdminRuneCmd()); DevCmdManager.registerDevCmd(new SetAdminRuneCmd());
DevCmdManager.registerDevCmd(new SetInvulCmd()); DevCmdManager.registerDevCmd(new SetInvulCmd());
DevCmdManager.registerDevCmd(new MakeItemCmd()); DevCmdManager.registerDevCmd(new MakeItemCmd());
DevCmdManager.registerDevCmd(new FillCmd());
DevCmdManager.registerDevCmd(new SetSubRaceCmd()); DevCmdManager.registerDevCmd(new SetSubRaceCmd());
// Admin // Admin
+16 -9
View File
@@ -15,8 +15,8 @@ import engine.mbEnums;
import engine.net.client.msg.ItemProductionMsg; import engine.net.client.msg.ItemProductionMsg;
import engine.objects.City; import engine.objects.City;
import engine.objects.Item; import engine.objects.Item;
import engine.objects.ItemTemplate;
import engine.objects.NPC; import engine.objects.NPC;
import engine.parsers.objects.CObjectTemplate;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@@ -49,6 +49,9 @@ public enum ForgeManager implements Runnable {
public static final ConcurrentHashMap<NPC, ConcurrentHashMap.KeySetView<WorkOrder, Boolean>> vendorWorkOrderLookup = new ConcurrentHashMap<>(); public static final ConcurrentHashMap<NPC, ConcurrentHashMap.KeySetView<WorkOrder, Boolean>> vendorWorkOrderLookup = new ConcurrentHashMap<>();
public static final ConcurrentHashMap<Item, WorkOrder> itemWorkOrderLookup = new ConcurrentHashMap<>(); public static final ConcurrentHashMap<Item, WorkOrder> itemWorkOrderLookup = new ConcurrentHashMap<>();
// Server-only data from static_vendor_items; the client templates have no mod table.
public static HashMap<Integer, Integer> vendorModTables = new HashMap<>();
public static void start() { public static void start() {
Thread forgeManager; Thread forgeManager;
@@ -222,12 +225,12 @@ public enum ForgeManager implements Runnable {
// Calculate production cost for a single run of the workOrder // Calculate production cost for a single run of the workOrder
HashMap<mbEnums.ResourceType, Integer> production_cost = new HashMap<>(); HashMap<mbEnums.ResourceType, Integer> production_cost = new HashMap<>();
ItemTemplate template = ItemTemplate.templates.get(workOrder.templateID); CObjectTemplate template = CObjectTemplate.lookup(workOrder.templateID);
// Add gold and resource costs from template // Add gold and resource costs from template
production_cost.put(mbEnums.ResourceType.GOLD, template.item_value); production_cost.put(mbEnums.ResourceType.GOLD, template.getItemValue());
production_cost.putAll(template.item_resource_cost); production_cost.putAll(template.getItemResourceCosts());
// Calculate cost of prefix and suffix // Calculate cost of prefix and suffix
@@ -248,8 +251,8 @@ public enum ForgeManager implements Runnable {
// Create new virtual item from specified template // Create new virtual item from specified template
ItemTemplate template = ItemTemplate.templates.get(workOrder.templateID);
Item forgedItem = new Item(workOrder.templateID); Item forgedItem = new Item(workOrder.templateID);
int modTable = getVendorModTable(workOrder.templateID);
// forgedItem gets a negative id; a virtual item which is not persisted // forgedItem gets a negative id; a virtual item which is not persisted
@@ -264,13 +267,13 @@ public enum ForgeManager implements Runnable {
// Assign a prefix and suffix to this item if random rolled // Assign a prefix and suffix to this item if random rolled
if (workOrder.prefixToken == 0 && workOrder.vendor.getItemModTable().contains((template.modTable))) if (workOrder.prefixToken == 0 && workOrder.vendor.getItemModTable().contains(modTable))
forgedItem.prefixToken = calcRandomMod(workOrder.vendor, mbEnums.ItemModType.PREFIX, template.modTable); forgedItem.prefixToken = calcRandomMod(workOrder.vendor, mbEnums.ItemModType.PREFIX, modTable);
else else
forgedItem.prefixToken = workOrder.prefixToken; forgedItem.prefixToken = workOrder.prefixToken;
if (workOrder.suffixToken == 0 && workOrder.vendor.getItemModTable().contains((template.modTable))) if (workOrder.suffixToken == 0 && workOrder.vendor.getItemModTable().contains(modTable))
forgedItem.suffixToken = calcRandomMod(workOrder.vendor, mbEnums.ItemModType.SUFFIX, template.modTable); forgedItem.suffixToken = calcRandomMod(workOrder.vendor, mbEnums.ItemModType.SUFFIX, modTable);
else else
forgedItem.suffixToken = workOrder.suffixToken; forgedItem.suffixToken = workOrder.suffixToken;
@@ -364,6 +367,10 @@ public enum ForgeManager implements Runnable {
DbManager.WarehouseQueries.WRITE_WORKORDER(workOrder); DbManager.WarehouseQueries.WRITE_WORKORDER(workOrder);
} }
public static int getVendorModTable(int templateID) {
return vendorModTables.getOrDefault(templateID, 0);
}
public static int calcRandomMod(NPC vendor, mbEnums.ItemModType itemModType, int modTable) { public static int calcRandomMod(NPC vendor, mbEnums.ItemModType itemModType, int modTable) {
// Random prefix or suffix token based on item.template.modtable // Random prefix or suffix token based on item.template.modtable
+1 -1
View File
@@ -307,7 +307,7 @@ public enum GroupManager {
return false; return false;
} }
if (!item.template.item_type.equals(mbEnums.ItemType.GOLD)) //only split goldItem if (!item.template.getItemType().equals(mbEnums.ItemType.GOLD)) //only split goldItem
return false; return false;
Group group = getGroup(pc); Group group = getGroup(pc);
+35 -54
View File
@@ -2,6 +2,7 @@ package engine.gameManager;
import engine.mbEnums; import engine.mbEnums;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@@ -21,66 +22,46 @@ public enum ItemManager {
public static final AtomicInteger lastNegativeID = new AtomicInteger(0); public static final AtomicInteger lastNegativeID = new AtomicInteger(0);
// restrict true: the set is a blacklist; false: a whitelist. An empty set allows everyone.
public static Boolean ValidRace(Item item, mbEnums.MonsterType race) { public static Boolean ValidRace(Item item, mbEnums.MonsterType race) {
if (item.template.item_race_req.isEmpty() && item.template.item_race_res.isEmpty()) EnumSet<mbEnums.MonsterType> races = item.template.getItemRaceReq();
boolean restrict = item.template.getItemRaceReqRestrict();
if (races.isEmpty())
return true; return true;
if (item.template.item_race_req.isEmpty() == false) return races.contains(race) != restrict;
if (item.template.item_race_req.contains(race))
return true;
if (item.template.item_race_res.isEmpty() == false)
if (item.template.item_race_res.contains(race) == false)
return true;
return false;
} }
public static Boolean ValidClass(Item item, mbEnums.ClassType base, mbEnums.ClassType profession) { public static Boolean ValidClass(Item item, mbEnums.ClassType base, mbEnums.ClassType profession) {
// Early exit if no entry EnumSet<mbEnums.ClassType> classes = item.template.getItemClassReq();
boolean restrict = item.template.getItemClassReqRestrict();
boolean listed;
if (item.template.item_class_req.isEmpty() && item.template.item_class_res.isEmpty()) if (classes.isEmpty())
return true; return true;
if (item.template.item_class_req.isEmpty() == false) listed = classes.contains(base) || classes.contains(profession);
if (item.template.item_class_req.contains(base) || item.template.item_class_req.contains(profession))
return true;
if (item.template.item_class_res.isEmpty() == false) return listed != restrict;
if (item.template.item_class_res.contains(base) == false && item.template.item_class_res.contains(profession) == false)
return true;
return false;
} }
public static Boolean ValidDiscipline(Item item, EnumSet<mbEnums.DisciplineType> discs) { public static Boolean ValidDiscipline(Item item, EnumSet<mbEnums.DisciplineType> discs) {
// Early exit if no entry EnumSet<mbEnums.DisciplineType> disciplines = item.template.getItemDiscReq();
boolean restrict = item.template.getItemDiscReqRestrict();
EnumSet<mbEnums.DisciplineType> workSet;
if (item.template.item_disc_req.isEmpty() && item.template.item_disc_res.isEmpty()) if (disciplines.isEmpty())
return true; return true;
EnumSet<mbEnums.DisciplineType> workSet = EnumSet.copyOf(discs); workSet = EnumSet.copyOf(discs);
workSet.retainAll(disciplines);
if (item.template.item_disc_req.isEmpty() == false) { return workSet.isEmpty() == restrict;
workSet.retainAll(item.template.item_disc_req);
if (workSet.isEmpty() == false)
return true;
}
if (item.template.item_disc_res.isEmpty() == false) {
workSet.retainAll(item.template.item_disc_res);
if (workSet.isEmpty() == false)
return true;
}
return false;
} }
public static Boolean canCharacterEquip(Item item, AbstractCharacter character) { public static Boolean canCharacterEquip(Item item, AbstractCharacter character) {
@@ -91,12 +72,12 @@ public enum ItemManager {
CharacterSkill characterSkill; CharacterSkill characterSkill;
if (item.template.item_skill_required.isEmpty()) if (item.template.getItemSkillReq().isEmpty())
return true; return true;
for (String skillRequired : item.template.item_skill_required.keySet()) { for (String skillRequired : item.template.getItemSkillReq().keySet()) {
int required_value = item.template.item_skill_required.get(skillRequired); int required_value = item.template.getItemSkillReq().get(skillRequired);
characterSkill = skills.get(skillRequired); characterSkill = skills.get(skillRequired);
if (characterSkill == null) if (characterSkill == null)
@@ -112,31 +93,31 @@ public enum ItemManager {
public static boolean isTwoHanded(Item item) { public static boolean isTwoHanded(Item item) {
if (!item.template.item_type.equals(mbEnums.ItemType.WEAPON)) if (!item.template.getItemType().equals(mbEnums.ItemType.WEAPON))
return false; return false;
return item.template.item_eq_slots_and.contains(EnumSet.of(mbEnums.EquipSlotType.LHELD, mbEnums.EquipSlotType.RHELD)); return item.template.getItemEqSlotsAnd().containsAll(EnumSet.of(mbEnums.EquipSlotType.LHELD, mbEnums.EquipSlotType.RHELD));
} }
public static boolean isTwoHanded(ItemTemplate template) { public static boolean isTwoHanded(CObjectTemplate template) {
if (!template.item_type.equals(mbEnums.ItemType.WEAPON)) if (!template.getItemType().equals(mbEnums.ItemType.WEAPON))
return false; return false;
return template.item_eq_slots_and.contains(EnumSet.of(mbEnums.EquipSlotType.LHELD, mbEnums.EquipSlotType.RHELD)); return template.getItemEqSlotsAnd().containsAll(EnumSet.of(mbEnums.EquipSlotType.LHELD, mbEnums.EquipSlotType.RHELD));
} }
public static boolean isShield(Item item) { public static boolean isShield(Item item) {
if (item.template.item_skill_required.containsKey("Block")) if (item.template.getItemSkillReq().containsKey("Block"))
return true; return true;
return false; return false;
} }
public static boolean isShield(ItemTemplate template) { public static boolean isShield(CObjectTemplate template) {
if (template.item_skill_required.containsKey("Block")) if (template.getItemSkillReq().containsKey("Block"))
return true; return true;
return false; return false;
@@ -150,7 +131,7 @@ public enum ItemManager {
return false; return false;
//Item not valid for slot //Item not valid for slot
if (item.template.item_eq_slots_or.contains(slot) == false) if (item.template.getItemEqSlotsOr().contains(slot) == false)
return false; return false;
// Slot is taken // Slot is taken
@@ -165,7 +146,7 @@ public enum ItemManager {
(slot == mbEnums.EquipSlotType.RHELD && equipped.get(mbEnums.EquipSlotType.LHELD) != null))) (slot == mbEnums.EquipSlotType.RHELD && equipped.get(mbEnums.EquipSlotType.LHELD) != null)))
return false; return false;
if (item.template.item_type.equals(mbEnums.ItemType.WEAPON)) if (item.template.getItemType().equals(mbEnums.ItemType.WEAPON))
if (equipped.get(slot) != null && equipped.get(slot).equals(item) == false) if (equipped.get(slot) != null && equipped.get(slot).equals(item) == false)
return false; return false;
@@ -197,7 +178,7 @@ public enum ItemManager {
//players can't wear 0 value items. //players can't wear 0 value items.
return item.template.item_value != 0 || Kit.IsNoobGear(item.templateID); return item.template.getItemValue() != 0 || Kit.IsNoobGear(item.templateID);
} }
+9 -8
View File
@@ -13,6 +13,7 @@ import engine.mbEnums;
import engine.net.client.msg.ErrorPopupMsg; import engine.net.client.msg.ErrorPopupMsg;
import engine.net.client.msg.chat.ChatSystemMsg; import engine.net.client.msg.chat.ChatSystemMsg;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.util.ArrayList; import java.util.ArrayList;
@@ -91,8 +92,8 @@ public enum LootManager {
//lastly, check mobs inventory for godly or disc runes to send a server announcement //lastly, check mobs inventory for godly or disc runes to send a server announcement
for (Item item : mob.getInventory()) { for (Item item : mob.getInventory()) {
if ((item.templateID > 2499 && item.templateID <= 3050) || item.template.item_base_name.toLowerCase().contains("of the gods")) { if ((item.templateID > 2499 && item.templateID <= 3050) || item.template.getItemBaseName().toLowerCase().contains("of the gods")) {
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mob.getName() + " in " + mob.getParentZone().zoneName + " has found the " + item.template.item_base_name + ". Are you tough enough to take it?"); ChatSystemMsg chatMsg = new ChatSystemMsg(null, mob.getName() + " in " + mob.getParentZone().zoneName + " has found the " + item.template.getItemBaseName() + ". Are you tough enough to take it?");
chatMsg.setMessageType(10); chatMsg.setMessageType(10);
chatMsg.setChannel(mbEnums.ChatChannelType.SYSTEM.getChannelID()); chatMsg.setChannel(mbEnums.ChatChannelType.SYSTEM.getChannelID());
DispatchManager.dispatchMsgToAll(chatMsg); DispatchManager.dispatchMsgToAll(chatMsg);
@@ -179,12 +180,12 @@ public enum LootManager {
if (itemUUID == 0) if (itemUUID == 0)
return null; return null;
if (ItemTemplate.templates.get(itemUUID).item_type.equals(mbEnums.ItemType.RESOURCE)) { if (CObjectTemplate.lookup(itemUUID).getItemType().equals(mbEnums.ItemType.RESOURCE)) {
int amount = ThreadLocalRandom.current().nextInt(tableRow.minSpawn, tableRow.maxSpawn + 1); int amount = ThreadLocalRandom.current().nextInt(tableRow.minSpawn, tableRow.maxSpawn + 1);
return new MobLoot(mob, ItemTemplate.templates.get(itemUUID), amount, false); return new MobLoot(mob, CObjectTemplate.lookup(itemUUID), amount, false);
} }
outItem = new MobLoot(mob, ItemTemplate.templates.get(itemUUID), false); outItem = new MobLoot(mob, CObjectTemplate.lookup(itemUUID), false);
if (selectedRow.pModTable != 0) if (selectedRow.pModTable != 0)
try { try {
@@ -374,7 +375,7 @@ public enum LootManager {
if (chanceRoll > bse.dropChance) if (chanceRoll > bse.dropChance)
return; return;
MobLoot lootItem = new MobLoot(mob, ItemTemplate.templates.get(bse.templateID), true); MobLoot lootItem = new MobLoot(mob, CObjectTemplate.lookup(bse.templateID), true);
if (lootItem != null) if (lootItem != null)
mob.charItemManager.addItemToInventory(lootItem); mob.charItemManager.addItemToInventory(lootItem);
@@ -422,14 +423,14 @@ public enum LootManager {
//create the item from the table, quantity is always 1 //create the item from the table, quantity is always 1
MobLoot winnings = new MobLoot(playerCharacter, ItemTemplate.templates.get(selectedItem.templateID), 1, false); MobLoot winnings = new MobLoot(playerCharacter, CObjectTemplate.lookup(selectedItem.templateID), 1, false);
if (winnings == null) if (winnings == null)
return; return;
//early exit if the inventory of the player will not old the item //early exit if the inventory of the player will not old the item
if (itemMan.hasRoomInventory(winnings.template.item_wt) == false) { if (itemMan.hasRoomInventory(winnings.template.getItemWt()) == false) {
ErrorPopupMsg.sendErrorPopup(playerCharacter, 21); ErrorPopupMsg.sendErrorPopup(playerCharacter, 21);
return; return;
} }
+26 -21
View File
@@ -19,12 +19,14 @@ import engine.net.client.ClientConnection;
import engine.net.client.msg.ErrorPopupMsg; import engine.net.client.msg.ErrorPopupMsg;
import engine.net.client.msg.PetMsg; import engine.net.client.msg.PetMsg;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
import engine.powers.RuneSkillAdjustEntry; import engine.powers.RuneSkillAdjustEntry;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
@@ -315,26 +317,26 @@ public enum NPCManager {
//has main hand weapon //has main hand weapon
Item weapon = guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD); Item weapon = guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD);
if (weapon.template.item_primary_attr.equals(mbEnums.AttributeType.Strength)) if (engine.parsers.objects.ItemTemplate._items.get(weapon.templateID).item_primary_attr == mbEnums.AttributeType.Strength)
primaryStat = guard.getStatStrCurrent(); primaryStat = guard.getStatStrCurrent();
else else
primaryStat = guard.getStatDexCurrent(); primaryStat = guard.getStatDexCurrent();
guard.minDamageHandOne = (int) ((guard.mobBase.getDamageMin() + weapon.template.item_weapon_damage.values().iterator().next()[0]) * rankModifier) + primaryStat; guard.minDamageHandOne = (int) ((guard.mobBase.getDamageMin() + engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_damage.get(0).damage_min) * rankModifier) + primaryStat;
guard.maxDamageHandOne = (int) ((guard.mobBase.getDamageMax() + weapon.template.item_weapon_damage.values().iterator().next()[1]) * rankModifier) + primaryStat; guard.maxDamageHandOne = (int) ((guard.mobBase.getDamageMax() + engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_damage.get(0).damage_max) * rankModifier) + primaryStat;
guard.speedHandOne = weapon.template.item_weapon_wepspeed; guard.speedHandOne = engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_wepspeed;
guard.rangeHandOne = weapon.template.item_weapon_max_range; guard.rangeHandOne = engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_max_range;
} else if (guard.charItemManager.equipped.containsKey(mbEnums.EquipSlotType.LHELD) && !ItemManager.isShield(guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template)) { } else if (guard.charItemManager.equipped.containsKey(mbEnums.EquipSlotType.LHELD) && !ItemManager.isShield(guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template)) {
//has off hand weapon //has off hand weapon
Item weapon = guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD); Item weapon = guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD);
if (weapon.template.item_primary_attr.equals(mbEnums.AttributeType.Strength)) if (engine.parsers.objects.ItemTemplate._items.get(weapon.templateID).item_primary_attr == mbEnums.AttributeType.Strength)
primaryStat = guard.getStatStrCurrent(); primaryStat = guard.getStatStrCurrent();
else else
primaryStat = guard.getStatDexCurrent(); primaryStat = guard.getStatDexCurrent();
guard.minDamageHandOne = (int) ((guard.mobBase.getDamageMin() + weapon.template.item_weapon_damage.values().iterator().next()[0]) * rankModifier) + primaryStat; guard.minDamageHandOne = (int) ((guard.mobBase.getDamageMin() + engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_damage.get(0).damage_min) * rankModifier) + primaryStat;
guard.maxDamageHandOne = (int) ((guard.mobBase.getDamageMax() + weapon.template.item_weapon_damage.values().iterator().next()[1]) * rankModifier) + primaryStat; guard.maxDamageHandOne = (int) ((guard.mobBase.getDamageMax() + engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_damage.get(0).damage_max) * rankModifier) + primaryStat;
guard.speedHandOne = weapon.template.item_weapon_wepspeed; guard.speedHandOne = engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_wepspeed;
guard.rangeHandOne = weapon.template.item_weapon_max_range; guard.rangeHandOne = engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_max_range;
} else { } else {
primaryStat = guard.getStatStrCurrent(); primaryStat = guard.getStatStrCurrent();
guard.minDamageHandOne = (int) ((guard.mobBase.getDamageMin()) * rankModifier) + primaryStat; guard.minDamageHandOne = (int) ((guard.mobBase.getDamageMin()) * rankModifier) + primaryStat;
@@ -352,8 +354,8 @@ public enum NPCManager {
int baseDef = guard.mobBase.getDefenseRating(); int baseDef = guard.mobBase.getDefenseRating();
int armorDefense = 0; int armorDefense = 0;
for (Item equipped : guard.charItemManager.equipped.values()) for (Item equipped : guard.charItemManager.equipped.values())
if (equipped.template.item_type.equals(mbEnums.ItemType.ARMOR) || ItemManager.isShield(equipped.template)) if (equipped.template.getItemType().equals(mbEnums.ItemType.ARMOR) || ItemManager.isShield(equipped.template))
armorDefense += equipped.template.item_defense_rating; armorDefense += engine.parsers.objects.ItemTemplate._items.get(equipped.templateID).item_defense_rating;
guard.defenseRating = dexterity + baseDef + armorDefense; guard.defenseRating = dexterity + baseDef + armorDefense;
} }
@@ -361,9 +363,9 @@ public enum NPCManager {
int strength = guard.getStatStrCurrent(); int strength = guard.getStatStrCurrent();
int baseAtr = guard.mobBase.getAttackRating(); int baseAtr = guard.mobBase.getAttackRating();
if (guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD) != null) if (guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD) != null)
guard.atrHandOne = baseAtr + (int) ((strength * 0.5f) + ((int) guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD).template.item_skill_required.values().toArray()[0] * 4) + ((int) guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD).template.item_skill_required.values().toArray()[0] * 3)); guard.atrHandOne = baseAtr + (int) ((strength * 0.5f) + ((int) guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD).template.getItemSkillReq().values().toArray()[0] * 4) + ((int) guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD).template.getItemSkillReq().values().toArray()[0] * 3));
else if (guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD) != null && !ItemManager.isShield(guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template)) else if (guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD) != null && !ItemManager.isShield(guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template))
guard.atrHandTwo = baseAtr + (int) ((strength * 0.5f) + ((int) guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template.item_skill_required.values().toArray()[0] * 4) + ((int) guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template.item_skill_required.values().toArray()[0] * 3)); guard.atrHandTwo = baseAtr + (int) ((strength * 0.5f) + ((int) guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template.getItemSkillReq().values().toArray()[0] * 4) + ((int) guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template.getItemSkillReq().values().toArray()[0] * 3));
else else
guard.atrHandOne = baseAtr; guard.atrHandOne = baseAtr;
} }
@@ -438,14 +440,17 @@ public enum NPCManager {
public static void applyEquipmentResists(Mob mob) { public static void applyEquipmentResists(Mob mob) {
EnumMap<mbEnums.DamageType, Float> armorResists;
if (mob.charItemManager.equipped.isEmpty()) if (mob.charItemManager.equipped.isEmpty())
return; return;
for (Item equipped : mob.charItemManager.equipped.values()) { for (Item equipped : mob.charItemManager.equipped.values()) {
if (equipped.template.item_type.equals(mbEnums.ItemType.ARMOR)) { if (equipped.template.getItemType().equals(mbEnums.ItemType.ARMOR)) {
mob.resists.setResist(mbEnums.DamageType.SLASHING, mob.resists.getResist(mbEnums.DamageType.SLASHING, 0) + equipped.template.combat_attack_resist.get("SLASHING")); armorResists = equipped.template.getCombatAttackResist();
mob.resists.setResist(mbEnums.DamageType.CRUSHING, mob.resists.getResist(mbEnums.DamageType.CRUSHING, 0) + equipped.template.combat_attack_resist.get("CRUSHING")); mob.resists.setResist(mbEnums.DamageType.SLASHING, mob.resists.getResist(mbEnums.DamageType.SLASHING, 0) + armorResists.getOrDefault(mbEnums.DamageType.SLASHING, 0f));
mob.resists.setResist(mbEnums.DamageType.PIERCING, mob.resists.getResist(mbEnums.DamageType.PIERCING, 0) + equipped.template.combat_attack_resist.get("PIERCING")); mob.resists.setResist(mbEnums.DamageType.CRUSHING, mob.resists.getResist(mbEnums.DamageType.CRUSHING, 0) + armorResists.getOrDefault(mbEnums.DamageType.CRUSHING, 0f));
mob.resists.setResist(mbEnums.DamageType.PIERCING, mob.resists.getResist(mbEnums.DamageType.PIERCING, 0) + armorResists.getOrDefault(mbEnums.DamageType.PIERCING, 0f));
} }
} }
} }
@@ -541,14 +546,14 @@ public enum NPCManager {
public static long calcRollingDuration(NPC vendor, int templateID) { public static long calcRollingDuration(NPC vendor, int templateID) {
ItemTemplate template = ItemTemplate.templates.get(templateID); CObjectTemplate template = CObjectTemplate.lookup(templateID);
float rollingDuration; float rollingDuration;
if (template == null) if (template == null)
return 0; return 0;
if (template.item_bane_rank > 0) if (template.getItemBaneRank() > 0)
return (long) (template.item_bane_rank * 60 * 60 * 3 * 1000 * Float.parseFloat(ConfigManager.MB_PRODUCTION_RATE.getValue())); return (long) (template.getItemBaneRank() * 60 * 60 * 3 * 1000 * Float.parseFloat(ConfigManager.MB_PRODUCTION_RATE.getValue()));
if (vendor.building == null) if (vendor.building == null)
return 600; return 600;
+3 -3
View File
@@ -2255,12 +2255,12 @@ public enum PowersManager {
if (pb.targetItem()) if (pb.targetItem())
return true; return true;
// TODO add these checks later // TODO add these checks later
else if (pb.targetArmor() && item.template.item_type.equals(ItemType.ARMOR)) else if (pb.targetArmor() && item.template.getItemType().equals(ItemType.ARMOR))
return true; return true;
else if (pb.targetJewelry() && item.template.item_type.equals(ItemType.JEWELRY)) else if (pb.targetJewelry() && item.template.getItemType().equals(ItemType.JEWELRY))
return true; return true;
else else
return pb.targetWeapon() && item.template.item_type.equals(ItemType.WEAPON); return pb.targetWeapon() && item.template.getItemType().equals(ItemType.WEAPON);
} // How did we get here? all valid targets have been covered } // How did we get here? all valid targets have been covered
else else
return false; return false;
+4 -4
View File
@@ -12,9 +12,9 @@ import engine.gameManager.DbManager;
import engine.gameManager.ForgeManager; import engine.gameManager.ForgeManager;
import engine.mbEnums; import engine.mbEnums;
import engine.objects.Item; import engine.objects.Item;
import engine.objects.ItemTemplate;
import engine.objects.NPC; import engine.objects.NPC;
import engine.objects.Warehouse; import engine.objects.Warehouse;
import engine.parsers.objects.CObjectTemplate;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
@@ -127,16 +127,16 @@ public class WorkOrder implements Delayed {
int validation_result = 0; int validation_result = 0;
ItemTemplate template = ItemTemplate.templates.get(workOrder.templateID); CObjectTemplate template = CObjectTemplate.lookup(workOrder.templateID);
if (workOrder.vendor.getBuilding() == null) if (workOrder.vendor.getBuilding() == null)
return 58; //58: The formula is beyond the means of this facility return 58; //58: The formula is beyond the means of this facility
if (!workOrder.vendor.charItemManager.hasRoomInventory(template.item_wt)) if (!workOrder.vendor.charItemManager.hasRoomInventory(template.getItemWt()))
return 30; //30: That person cannot carry that item return 30; //30: That person cannot carry that item
if ((workOrder.prefixToken != 0 || workOrder.suffixToken != 0) && if ((workOrder.prefixToken != 0 || workOrder.suffixToken != 0) &&
!workOrder.vendor.getItemModTable().contains((template.modTable))) !workOrder.vendor.getItemModTable().contains(ForgeManager.getVendorModTable(workOrder.templateID)))
return 59; //59: This hireling does not have this formula return 59; //59: This hireling does not have this formula
if (!Warehouse.calcCostOverrun(workOrder).isEmpty()) if (!Warehouse.calcCostOverrun(workOrder).isEmpty())
@@ -46,7 +46,7 @@ public class ActivateNPCMsgHandler extends AbstractClientMsgHandler {
// Filter hirelings by slot type // Filter hirelings by slot type
for (Item hirelings : player.getInventory()) { for (Item hirelings : player.getInventory()) {
if (hirelings.template.item_type.equals(ItemType.EMPLOYMENTCONTRACT)) { if (hirelings.template.getItemType().equals(ItemType.EMPLOYMENTCONTRACT)) {
contract = DbManager.ContractQueries.GET_CONTRACT(hirelings.templateID); contract = DbManager.ContractQueries.GET_CONTRACT(hirelings.templateID);
@@ -78,7 +78,7 @@ public class AddItemToTradeWindowMsgHandler extends AbstractClientMsgHandler {
if (!item.validForInventory(source.getClientConnection(), source, source.charItemManager)) if (!item.validForInventory(source.getClientConnection(), source, source.charItemManager))
return false; return false;
if (!tradingWith.hasRoomTrade(item.template.item_wt)) { if (!tradingWith.hasRoomTrade(item.template.getItemWt())) {
dispatch = Dispatch.borrow(source, msg); dispatch = Dispatch.borrow(source, msg);
DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.PRIMARY); DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.PRIMARY);
return false; return false;
@@ -24,6 +24,7 @@ import engine.net.client.msg.guild.GuildInfoMsg;
import engine.objects.Guild; import engine.objects.Guild;
import engine.objects.Item; import engine.objects.Item;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import engine.parsers.objects.DeedTemplate;
import engine.util.StringUtils; import engine.util.StringUtils;
public class GuildCreationFinalizeHandler extends AbstractClientMsgHandler { public class GuildCreationFinalizeHandler extends AbstractClientMsgHandler {
@@ -42,6 +43,7 @@ public class GuildCreationFinalizeHandler extends AbstractClientMsgHandler {
Guild playerGuild; Guild playerGuild;
Item charter; Item charter;
DeedTemplate charterDeed;
Dispatch dispatch; Dispatch dispatch;
msg = (GuildCreationFinalizeMsg) baseMsg; msg = (GuildCreationFinalizeMsg) baseMsg;
@@ -65,7 +67,9 @@ public class GuildCreationFinalizeHandler extends AbstractClientMsgHandler {
// Item must be a valid charterType (type 10 in db) // Item must be a valid charterType (type 10 in db)
if (charter == null || (charter.template.item_type.equals(ItemType.CHARTER) == false)) { charterDeed = DeedTemplate._deeds.get(charter.templateID);
if (charterDeed == null || (charterDeed.item_type.equals(ItemType.CHARTER) == false)) {
ErrorPopupMsg.sendErrorPopup(player, GuildManager.NO_CHARTER_FOUND); ErrorPopupMsg.sendErrorPopup(player, GuildManager.NO_CHARTER_FOUND);
return true; return true;
} }
@@ -238,10 +238,10 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
if (targetItem == null) if (targetItem == null)
return; return;
if (targetItem.template.item_type.equals(ItemType.GOLD)) if (targetItem.template.getItemType().equals(ItemType.GOLD))
return; return;
if (!vendor.charItemManager.hasRoomInventory(targetItem.template.item_wt)) { if (!vendor.charItemManager.hasRoomInventory(targetItem.template.getItemWt())) {
ErrorPopupMsg.sendErrorPopup(player, 21); ErrorPopupMsg.sendErrorPopup(player, 21);
return; return;
} }
@@ -319,7 +319,7 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
if (targetItem == null) if (targetItem == null)
continue; continue;
if (targetItem.template.item_type.equals(ItemType.GOLD)) if (targetItem.template.getItemType().equals(ItemType.GOLD))
return; return;
if (!vendor.charItemManager.doesCharOwnThisItem(targetItem.getObjectUUID())) if (!vendor.charItemManager.doesCharOwnThisItem(targetItem.getObjectUUID()))
@@ -328,14 +328,14 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
if (!vendor.charItemManager.inventoryContains(targetItem)) if (!vendor.charItemManager.inventoryContains(targetItem))
continue; continue;
itemValue = targetItem.template.item_value; itemValue = targetItem.template.getItemValue();
if (vendor.getBuilding().getStrongboxValue() + itemValue > vendor.getBuilding().getMaxGold()) { if (vendor.getBuilding().getStrongboxValue() + itemValue > vendor.getBuilding().getMaxGold()) {
ErrorPopupMsg.sendErrorPopup(player, 201); ErrorPopupMsg.sendErrorPopup(player, 201);
break; break;
} }
switch (targetItem.template.item_type) { switch (targetItem.template.getItemType()) {
case EMPLOYMENTCONTRACT: case EMPLOYMENTCONTRACT:
case CHARTER: case CHARTER:
case DEED: case DEED:
@@ -465,13 +465,13 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
if (targetItem == null) if (targetItem == null)
return; return;
if (targetItem.template.item_type.equals(ItemType.GOLD)) if (targetItem.template.getItemType().equals(ItemType.GOLD))
return; return;
if (!vendor.charItemManager.inventoryContains(targetItem)) if (!vendor.charItemManager.inventoryContains(targetItem))
return; return;
if (!player.charItemManager.hasRoomInventory(targetItem.template.item_wt)) if (!player.charItemManager.hasRoomInventory(targetItem.template.getItemWt()))
return; return;
player.charItemManager.buyFromNPC(targetItem, vendor); player.charItemManager.buyFromNPC(targetItem, vendor);
@@ -161,7 +161,7 @@ public class LootMsgHandler extends AbstractClientMsgHandler {
if (itemRet == null) if (itemRet == null)
return true; return true;
if (item.template.item_type.equals(mbEnums.ItemType.GOLD)) { if (item.template.getItemType().equals(mbEnums.ItemType.GOLD)) {
// this is done to prevent the temporary goldItem item // this is done to prevent the temporary goldItem item
// (from the mob) from appearing in player's inventory. // (from the mob) from appearing in player's inventory.
// It also updates the goldItem quantity display // It also updates the goldItem quantity display
@@ -187,7 +187,7 @@ public class LootMsgHandler extends AbstractClientMsgHandler {
//TODO send group loot message if player is grouped and visible //TODO send group loot message if player is grouped and visible
Group group = GroupManager.getGroup(player); Group group = GroupManager.getGroup(player);
if (group != null && group.getSplitGold() && (item.template.item_type.equals(mbEnums.ItemType.GOLD) == false)) { if (group != null && group.getSplitGold() && (item.template.getItemType().equals(mbEnums.ItemType.GOLD) == false)) {
String name = item.getName(); String name = item.getName();
String text = player.getFirstName() + " has looted " + name + '.'; String text = player.getFirstName() + " has looted " + name + '.';
ChatManager.chatGroupInfoCanSee(player, text); ChatManager.chatGroupInfoCanSee(player, text);
@@ -202,7 +202,7 @@ public class LootMsgHandler extends AbstractClientMsgHandler {
if (itemRet == null) if (itemRet == null)
return true; return true;
if (item.template.item_type.equals(mbEnums.ItemType.GOLD)) { if (item.template.getItemType().equals(mbEnums.ItemType.GOLD)) {
// this is done to prevent the temporary goldItem item // this is done to prevent the temporary goldItem item
// (from the mob) from appearing in player's inventory. // (from the mob) from appearing in player's inventory.
// It also updates the goldItem quantity display // It also updates the goldItem quantity display
@@ -241,7 +241,7 @@ public class LootMsgHandler extends AbstractClientMsgHandler {
//TODO send group loot message if player is grouped and visible //TODO send group loot message if player is grouped and visible
Group group = GroupManager.getGroup(player); Group group = GroupManager.getGroup(player);
if (group != null && group.getSplitGold() && (item.template.item_type.equals(mbEnums.ItemType.GOLD) == false)) { if (group != null && group.getSplitGold() && (item.template.getItemType().equals(mbEnums.ItemType.GOLD) == false)) {
String name = item.getName(); String name = item.getName();
String text = player.getFirstName() + " has looted " + name + '.'; String text = player.getFirstName() + " has looted " + name + '.';
ChatManager.chatGroupInfoCanSee(player, text); ChatManager.chatGroupInfoCanSee(player, text);
@@ -8,6 +8,7 @@ import engine.net.Dispatch;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.msg.*; import engine.net.client.msg.*;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.DeedTemplate;
import engine.powers.PowersBase; import engine.powers.PowersBase;
import java.util.ArrayList; import java.util.ArrayList;
@@ -78,7 +79,7 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
int uuid = item.templateID; int uuid = item.templateID;
switch (item.template.item_type) { switch (item.template.getItemType()) {
case DEED: //buildings case DEED: //buildings
//Call add building screen here, ib.getUseID() get's building ID //Call add building screen here, ib.getUseID() get's building ID
@@ -99,7 +100,7 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
pam.setX(loc.getX() + 64); //offset grid from tol pam.setX(loc.getX() + 64); //offset grid from tol
pam.setY(loc.getY()); pam.setY(loc.getY());
pam.setZ(loc.getZ() + 64); //offset grid from tol pam.setZ(loc.getZ() + 64); //offset grid from tol
pam.addPlacementInfo(item.template.deed_structure_id); pam.addPlacementInfo(DeedTemplate._deeds.get(item.templateID).deed_structure_id);
dispatch = Dispatch.borrow(player, pam); dispatch = Dispatch.borrow(player, pam);
DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
@@ -187,14 +188,14 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
if (uuid > 680069 && uuid < 680074) //Handle Charter, Deed, Petition, Warrant here if (uuid > 680069 && uuid < 680074) //Handle Charter, Deed, Petition, Warrant here
break; break;
if (item.template.item_bane_rank > 0) { if (item.template.getItemBaneRank() > 0) {
// Only one banestone at a time // Only one banestone at a time
lock.writeLock().lock(); lock.writeLock().lock();
try { try {
if (Bane.summonBanestone(player, origin, item.template.item_bane_rank) == true) if (Bane.summonBanestone(player, origin, item.template.getItemBaneRank()) == true)
itemMan.consume(item); itemMan.consume(item);
} finally { } finally {
lock.writeLock().unlock(); lock.writeLock().unlock();
@@ -225,7 +226,7 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
// Bypass for waterbuckets // Bypass for waterbuckets
if (item.template.item_type.equals(mbEnums.ItemType.BUCKET)) { if (item.template.getItemType().equals(mbEnums.ItemType.BUCKET)) {
// test for valid target type // test for valid target type
if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter) if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter)
@@ -250,10 +251,9 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
} }
if (waterbucketBypass == false) { if (waterbucketBypass == false) {
String powerString = item.template.item_power_grant.keySet().iterator().next(); engine.parsers.objects.PowerGrant powerGrant = item.template.getItemPowerGrant().get(0);
PowersBase powerAction = PowersManager.powersBaseByIDString.get(powerString); PowersBase powerAction = PowersManager.powersBaseByIDString.get(powerGrant.power_type);
int powerValue = item.template.item_power_grant.get(powerString); PowersManager.applyPower(player, target, Vector3fImmutable.ZERO, powerAction.getToken(), powerGrant.power_value, true);
PowersManager.applyPower(player, target, Vector3fImmutable.ZERO, powerAction.getToken(), powerValue, true);
} }
itemMan.consume(item); itemMan.consume(item);
} else //just remove the item at this point } else //just remove the item at this point
@@ -18,6 +18,7 @@ import engine.net.client.msg.ErrorPopupMsg;
import engine.net.client.msg.PlaceAssetMsg; import engine.net.client.msg.PlaceAssetMsg;
import engine.net.client.msg.PlaceAssetMsg.PlacementInfo; import engine.net.client.msg.PlaceAssetMsg.PlacementInfo;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.DeedTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@@ -356,8 +357,8 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
Item contract = null; Item contract = null;
for (Item inventoryItem : playerCharacter.getInventory()) { for (Item inventoryItem : playerCharacter.getInventory()) {
if (inventoryItem.template.item_type.equals(ItemType.DEED) && if (inventoryItem.template.getItemType().equals(ItemType.DEED) &&
inventoryItem.template.deed_structure_id == buildingList.getBlueprintUUID()) { DeedTemplate._deeds.get(inventoryItem.templateID).deed_structure_id == buildingList.getBlueprintUUID()) {
contract = inventoryItem; contract = inventoryItem;
break; break;
} }
@@ -85,7 +85,7 @@ public class RepairMsgHandler extends AbstractClientMsgHandler {
//make sure item is damaged and not destroyed //make sure item is damaged and not destroyed
short dur = (short) toRepair.combat_health_current; short dur = (short) toRepair.combat_health_current;
short max = (short) toRepair.template.combat_health_full; short max = (short) toRepair.template.getCombatHealthFull();
//account for durability modifications //account for durability modifications
@@ -68,7 +68,7 @@ public class TransferItemFromBankMsgHandler extends AbstractClientMsgHandler {
return true; return true;
; ;
if (item.template.item_type.equals(mbEnums.ItemType.GOLD)) { if (item.template.getItemType().equals(mbEnums.ItemType.GOLD)) {
if (!itemManager.moveGoldToInventory(item, msg.getNumItems())) if (!itemManager.moveGoldToInventory(item, msg.getNumItems()))
return true; return true;
@@ -85,7 +85,7 @@ public class TransferItemFromBankMsgHandler extends AbstractClientMsgHandler {
// Not gold, process update here // Not gold, process update here
if (!itemManager.hasRoomInventory(item.template.item_wt)) if (!itemManager.hasRoomInventory(item.template.getItemWt()))
return true; return true;
if (itemManager.moveItemToInventory(item) == false) if (itemManager.moveItemToInventory(item) == false)
@@ -65,7 +65,7 @@ public class TransferItemToBankMsgHandler extends AbstractClientMsgHandler {
return true; return true;
if (item.containerType == mbEnums.ItemContainerType.INVENTORY && itemManager.isBankOpen()) if (item.containerType == mbEnums.ItemContainerType.INVENTORY && itemManager.isBankOpen())
if (item.template.item_type.equals(mbEnums.ItemType.GOLD)) { if (item.template.getItemType().equals(mbEnums.ItemType.GOLD)) {
if (!itemManager.moveGoldToBank(item, msg.getNumItems())) if (!itemManager.moveGoldToBank(item, msg.getNumItems()))
return true; return true;
UpdateGoldMsg goldMes = new UpdateGoldMsg(player); UpdateGoldMsg goldMes = new UpdateGoldMsg(player);
@@ -76,7 +76,7 @@ public class TransferItemToBankMsgHandler extends AbstractClientMsgHandler {
} else { } else {
if (!itemManager.hasRoomBank(item.template.item_wt)) if (!itemManager.hasRoomBank(item.template.getItemWt()))
return true; return true;
if (!itemManager.moveItemToBank(item)) if (!itemManager.moveItemToBank(item))
@@ -86,7 +86,7 @@ public class VendorBuyMsgHandler extends AbstractClientMsgHandler {
if (me.objectUUID == vendorBuyMsg.getItemID()) { if (me.objectUUID == vendorBuyMsg.getItemID()) {
//test room available for item //test room available for item
if (!itemMan.hasRoomInventory(me.template.item_wt)) if (!itemMan.hasRoomInventory(me.template.getItemWt()))
return true; return true;
int cost = me.getValue(); int cost = me.getValue();
@@ -148,10 +148,10 @@ public class VendorBuyMsgHandler extends AbstractClientMsgHandler {
//test room available for item //test room available for item
if (!itemMan.hasRoomInventory(vendorItem.template.item_wt)) if (!itemMan.hasRoomInventory(vendorItem.template.getItemWt()))
return true; return true;
int cost = vendorItem.template.item_value; int cost = vendorItem.template.getItemValue();
if (vendorItem.flags.contains(mbEnums.ItemFlags.Identified) || vendorItem.isCustomValue()) if (vendorItem.flags.contains(mbEnums.ItemFlags.Identified) || vendorItem.isCustomValue())
cost = vendorItem.magicValue; cost = vendorItem.magicValue;
@@ -94,7 +94,7 @@ public class VendorSellMsgHandler extends AbstractClientMsgHandler {
return true; return true;
if (npc.getParentZone() != null && npc.getParentZone().playerCityUUID != 0) if (npc.getParentZone() != null && npc.getParentZone().playerCityUUID != 0)
if (!npc.charItemManager.hasRoomInventory(sell.template.item_wt)) { if (!npc.charItemManager.hasRoomInventory(sell.template.getItemWt())) {
ErrorPopupMsg.sendErrorPopup(player, 21); ErrorPopupMsg.sendErrorPopup(player, 21);
return true; return true;
} }
@@ -104,7 +104,7 @@ public class VendorSellMsgHandler extends AbstractClientMsgHandler {
//get goldItem cost to sell //get goldItem cost to sell
cost = (int) (sell.template.item_value * (sell.combat_health_current / sell.template.combat_health_full)); cost = (int) (sell.template.getItemValue() * (sell.combat_health_current / sell.template.getCombatHealthFull()));
float bargain = player.getBargain(); float bargain = player.getBargain();
float profit = npc.getBuyPercent(player) + bargain; float profit = npc.getBuyPercent(player) + bargain;
+9 -7
View File
@@ -19,6 +19,7 @@ import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.Protocol; import engine.net.Protocol;
import engine.objects.*; import engine.objects.*;
import engine.parsers.objects.CObjectTemplate;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.Period; import org.joda.time.Period;
import org.joda.time.Seconds; import org.joda.time.Seconds;
@@ -420,17 +421,18 @@ public class ManageNPCMsg extends ClientNetMsg {
writer.putInt(rollableSet.size()); writer.putInt(rollableSet.size());
for (int templateID : rollableSet) { for (int templateID : rollableSet) {
ItemTemplate template = ItemTemplate.templates.get(templateID); CObjectTemplate template = CObjectTemplate.lookup(templateID);
int modTable = ForgeManager.getVendorModTable(templateID);
writer.put((byte) 1); writer.put((byte) 1);
writer.putInt(0); writer.putInt(0);
writer.putInt(templateID); //itemID writer.putInt(templateID); //itemID
writer.putInt(template.item_value); writer.putInt(template.getItemValue());
writer.putInt(600); writer.putInt(600);
writer.put((byte) 1); writer.put((byte) 1);
writer.put((byte) template.modTable); writer.put((byte) modTable);
writer.put((byte) template.modTable); writer.put((byte) modTable);
writer.put((byte) template.modTable); writer.put((byte) modTable);
writer.put((byte) template.modTable);//EffectItemType writer.put((byte) modTable);//EffectItemType
} }
ArrayList<Item> cooking = NPCManager.getAllCookingForVendor(npc); ArrayList<Item> cooking = NPCManager.getAllCookingForVendor(npc);
@@ -444,7 +446,7 @@ public class ManageNPCMsg extends ClientNetMsg {
writer.putInt(0); writer.putInt(0);
writer.putInt(item.templateID); writer.putInt(item.templateID);
writer.putInt(item.template.item_value); writer.putInt(item.template.getItemValue());
long timeLife = item.getDateToUpgrade() - System.currentTimeMillis(); long timeLife = item.getDateToUpgrade() - System.currentTimeMillis();
@@ -54,7 +54,7 @@ public class UpdateInventoryMsg extends ClientNetMsg {
for (Item item : list) { for (Item item : list) {
if (item.template.item_type.equals(ItemType.GOLD)) { if (item.template.getItemType().equals(ItemType.GOLD)) {
if (item.getNumOfItems() == 0) if (item.getNumOfItems() == 0)
continue; continue;
} }
+6 -1
View File
@@ -16,6 +16,7 @@ import engine.net.ByteBufferWriter;
import engine.net.Protocol; import engine.net.Protocol;
import engine.objects.Item; import engine.objects.Item;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import engine.parsers.objects.DeedTemplate;
public class UseCharterMsg extends ClientNetMsg { public class UseCharterMsg extends ClientNetMsg {
@@ -61,9 +62,13 @@ public class UseCharterMsg extends ClientNetMsg {
public void configure() { public void configure() {
DeedTemplate charterDeed;
if (close) { if (close) {
for (Item i : player.getInventory()) { for (Item i : player.getInventory()) {
if (i.template.item_type.equals(ItemType.CHARTER)) { charterDeed = DeedTemplate._deeds.get(i.templateID);
if (charterDeed != null && charterDeed.item_type.equals(ItemType.CHARTER)) {
charterUUID = i.getObjectUUID(); charterUUID = i.getObjectUUID();
break; break;
} }
@@ -156,7 +156,7 @@ public class VendorBuyWindowMsg extends ClientNetMsg {
for (Item item : inventory) { for (Item item : inventory) {
if (item.getOwnerID() != ownerID) if (item.getOwnerID() != ownerID)
continue; continue;
if (item.template.item_type.equals(ItemType.GOLD)) { if (item.template.getItemType().equals(ItemType.GOLD)) {
if (item.getNumOfItems() == 0) if (item.getNumOfItems() == 0)
continue; continue;
} }
+39 -38
View File
@@ -29,6 +29,8 @@ import engine.net.Dispatch;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.msg.ApplyRuneMsg; import engine.net.client.msg.ApplyRuneMsg;
import engine.net.client.msg.UpdateStateMsg; import engine.net.client.msg.UpdateStateMsg;
import engine.parsers.objects.CObjectTemplate;
import engine.parsers.objects.RuneTemplate;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
import engine.powers.PowersBase; import engine.powers.PowersBase;
import engine.powers.effectmodifiers.AbstractEffectModifier; import engine.powers.effectmodifiers.AbstractEffectModifier;
@@ -652,11 +654,11 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
AssignDefenseValue(abstractCharacter); AssignDefenseValue(abstractCharacter);
// calculate atr and damage for each hand // calculate atr and damage for each hand
ConcurrentHashMap<EquipSlotType, Item> equipped = abstractCharacter.charItemManager.getEquipped(); ConcurrentHashMap<EquipSlotType, Item> equipped = abstractCharacter.charItemManager.getEquipped();
AssignDamageAtrForPlayers(abstractCharacter, equipped.get(EquipSlotType.RHELD), true, equipped.get(EquipSlotType.RHELD)); AssignDamageAtrForPlayers(abstractCharacter, equipped.get(EquipSlotType.RHELD), true, equipped.get(EquipSlotType.LHELD));
AssignDamageAtrForPlayers(abstractCharacter, equipped.get(EquipSlotType.LHELD), false, equipped.get(EquipSlotType.LHELD)); AssignDamageAtrForPlayers(abstractCharacter, equipped.get(EquipSlotType.LHELD), false, equipped.get(EquipSlotType.RHELD));
if (abstractCharacter.getObjectType().equals(GameObjectType.Mob)) { if (abstractCharacter.getObjectType().equals(GameObjectType.Mob)) {
Mob mob = (Mob) abstractCharacter; Mob mob = (Mob) abstractCharacter;
ItemTemplate rune = ItemTemplate.templates.get(mob.loadID); RuneTemplate rune = RuneTemplate._runes.get(mob.loadID);
float minDamage = mob.mobBase.getDamageMin(); float minDamage = mob.mobBase.getDamageMin();
float maxDamage = mob.mobBase.getDamageMax(); float maxDamage = mob.mobBase.getDamageMax();
int attackRating = mob.mobBase.getAttackRating(); int attackRating = mob.mobBase.getAttackRating();
@@ -691,16 +693,17 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
// make sure weapon exists // make sure weapon exists
boolean noWeapon = false; boolean noWeapon = false;
ItemTemplate weaponTemplate = null; CObjectTemplate weaponTemplate = null;
engine.parsers.objects.ItemTemplate.Damage damage;
if (weapon == null) if (weapon == null)
noWeapon = true; noWeapon = true;
else { else {
ItemTemplate itemTemplate = weapon.template; CObjectTemplate itemTemplate = weapon.template;
if (itemTemplate == null) if (itemTemplate == null)
noWeapon = true; noWeapon = true;
else if (!weapon.template.item_type.equals(ItemType.WEAPON)) { else if (!weapon.template.getItemType().equals(ItemType.WEAPON)) {
defaultAtrAndDamage(abstractCharacter, mainHand); defaultAtrAndDamage(abstractCharacter, mainHand);
return; return;
} else } else
@@ -717,7 +720,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
if (noWeapon) { if (noWeapon) {
if (mainHand) { if (mainHand) {
Item off = abstractCharacter.charItemManager.getEquipped().get(EquipSlotType.LHELD); Item off = abstractCharacter.charItemManager.getEquipped().get(EquipSlotType.LHELD);
if (off != null && off.template != null && off.template.item_type.equals(ItemType.WEAPON)) if (off != null && off.template != null && off.template.getItemType().equals(ItemType.WEAPON))
abstractCharacter.rangeHandOne = 10 * (1 + (abstractCharacter.statStrBase / 600)); // Set abstractCharacter.rangeHandOne = 10 * (1 + (abstractCharacter.statStrBase / 600)); // Set
// to // to
// no // no
@@ -750,9 +753,9 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
} else { } else {
if (mainHand) if (mainHand)
abstractCharacter.rangeHandOne = weapon.template.item_weapon_max_range * (1 + (abstractCharacter.statStrBase / 600)); abstractCharacter.rangeHandOne = engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_max_range * (1 + (abstractCharacter.statStrBase / 600));
else else
abstractCharacter.rangeHandTwo = weapon.template.item_weapon_max_range * (1 + (abstractCharacter.statStrBase / 600)); abstractCharacter.rangeHandTwo = engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_max_range * (1 + (abstractCharacter.statStrBase / 600));
if (abstractCharacter.bonuses != null) { if (abstractCharacter.bonuses != null) {
float range_bonus = 1 + abstractCharacter.bonuses.getFloatPercentAll(ModType.WeaponRange, SourceType.None); float range_bonus = 1 + abstractCharacter.bonuses.getFloatPercentAll(ModType.WeaponRange, SourceType.None);
@@ -764,20 +767,20 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
} }
skillPercentage = getModifiedAmount(abstractCharacter.skills.get(weapon.template.item_skill_used)); skillPercentage = getModifiedAmount(abstractCharacter.skills.get(weapon.template.getItemSkillUsed()));
masteryPercentage = getModifiedAmount(abstractCharacter.skills.get(weaponTemplate.item_skill_mastery_used)); masteryPercentage = getModifiedAmount(abstractCharacter.skills.get(weaponTemplate.getItemSkillMasteryUsed()));
if (masteryPercentage == 0f) if (masteryPercentage == 0f)
mastDam = 0f; mastDam = 0f;
// mastDam = CharacterSkill.getQuickMastery(this, wb.getMastery()); // mastDam = CharacterSkill.getQuickMastery(this, wb.getMastery());
else else
mastDam = masteryPercentage; mastDam = masteryPercentage;
int[] damages = (int[]) weaponTemplate.item_weapon_damage.values().toArray()[0]; damage = engine.parsers.objects.ItemTemplate.getWeapon(weapon.templateID).weapon_damage.get(0);
min = damages[0]; min = damage.damage_min;
max = damages[1]; max = damage.damage_max;
strBased = weaponTemplate.item_primary_attr.equals(AttributeType.Strength); strBased = engine.parsers.objects.ItemTemplate._items.get(weapon.templateID).item_primary_attr == AttributeType.Strength;
} }
if (abstractCharacter.effects != null && abstractCharacter.effects.containsKey("DeathShroud")) if (abstractCharacter.effects != null && abstractCharacter.effects.containsKey("DeathShroud"))
@@ -826,7 +829,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
//calculate speed //calculate speed
if (weaponTemplate != null) if (weaponTemplate != null)
speed = weaponTemplate.item_weapon_wepspeed; speed = engine.parsers.objects.ItemTemplate.getWeapon(weaponTemplate.getTemplateId()).weapon_wepspeed;
else else
speed = 20f; //unarmed attack speed speed = 20f; //unarmed attack speed
if (weapon != null) if (weapon != null)
@@ -881,16 +884,13 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
max *= percentMaxDamage; max *= percentMaxDamage;
} }
//if duel wielding, cut damage by 30% // Client (0x466EB0 sets char+0xD0C, 0x46D200 applies it): 30% cut only when both hands hold a WEAPON.
if (otherHand != null) { if (!noWeapon && otherHand != null && otherHand.template != null
ItemTemplate ibo = otherHand.template; && otherHand.template.getItemType().equals(ItemType.WEAPON)) {
if (ibo != null && otherHand.template.equals(ItemType.WEAPON)) {
min *= 0.7f; min *= 0.7f;
max *= 0.7f; max *= 0.7f;
} }
}
// calculate damage // calculate damage
float minDamage; float minDamage;
@@ -955,7 +955,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
if (ItemManager.isShield(shield) == false) if (ItemManager.isShield(shield) == false)
return 0; return 0;
ItemTemplate template = shield.template; CObjectTemplate template = shield.template;
if (template == null) if (template == null)
return 0; return 0;
@@ -969,7 +969,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
} else } else
skillMod = blockSkill.getModifiedAmount(); skillMod = blockSkill.getModifiedAmount();
float def = template.item_defense_rating; float def = engine.parsers.objects.ItemTemplate._items.get(shield.templateID).item_defense_rating;
//apply item defense bonuses //apply item defense bonuses
@@ -991,29 +991,30 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
if (armor == null) if (armor == null)
return 0; return 0;
ItemTemplate template = armor.template; CObjectTemplate template = armor.template;
if (template == null) if (template == null)
return 0; return 0;
if (!armor.template.item_type.equals(ItemType.ARMOR)) if (!armor.template.getItemType().equals(ItemType.ARMOR))
return 0; return 0;
if (armor.template.item_skill_used.isEmpty()) // "Cloth" is a placeholder in Skills.cfg (token 0) that no character learns
return template.item_defense_rating; if (armor.template.getItemSkillUsed().isEmpty() || armor.template.getItemSkillUsed().equals("Cloth"))
return engine.parsers.objects.ItemTemplate._items.get(armor.templateID).item_defense_rating;
CharacterSkill armorSkill = abstractCharacter.skills.get(armor.template.item_skill_used); CharacterSkill armorSkill = abstractCharacter.skills.get(armor.template.getItemSkillUsed());
if (abstractCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) && armorSkill == null) { if (abstractCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) && armorSkill == null) {
Logger.error("Player " + abstractCharacter.getObjectUUID() Logger.error("Player " + abstractCharacter.getObjectUUID()
+ " has armor equipped without the nescessary skill to equip it"); + " has armor equipped without the nescessary skill to equip it");
return template.item_defense_rating; return engine.parsers.objects.ItemTemplate._items.get(armor.templateID).item_defense_rating;
} }
if (armorSkill == null) if (armorSkill == null)
return template.item_defense_rating; // Mobiles do not have armor skills @TODO return engine.parsers.objects.ItemTemplate._items.get(armor.templateID).item_defense_rating; // Mobiles do not have armor skills @TODO
float def = template.item_defense_rating; float def = engine.parsers.objects.ItemTemplate._items.get(armor.templateID).item_defense_rating;
//apply item defense bonuses //apply item defense bonuses
@@ -1031,7 +1032,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
private static float getWeaponDefense(AbstractCharacter abstractCharacter, ConcurrentHashMap<EquipSlotType, Item> equipped) { private static float getWeaponDefense(AbstractCharacter abstractCharacter, ConcurrentHashMap<EquipSlotType, Item> equipped) {
Item weapon = equipped.get(EquipSlotType.RHELD); Item weapon = equipped.get(EquipSlotType.RHELD);
ItemTemplate weaponTemplate = null; CObjectTemplate weaponTemplate = null;
CharacterSkill skill, mastery; CharacterSkill skill, mastery;
float val = 0; float val = 0;
boolean unarmed = false; boolean unarmed = false;
@@ -1052,8 +1053,8 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
skill = abstractCharacter.skills.get("Unarmed Combat"); skill = abstractCharacter.skills.get("Unarmed Combat");
mastery = abstractCharacter.skills.get("Unarmed Combat Mastery"); mastery = abstractCharacter.skills.get("Unarmed Combat Mastery");
} else { } else {
skill = abstractCharacter.skills.get(weapon.template.item_skill_used); skill = abstractCharacter.skills.get(weapon.template.getItemSkillUsed());
mastery = abstractCharacter.skills.get(weaponTemplate.item_skill_mastery_used); mastery = abstractCharacter.skills.get(weaponTemplate.getItemSkillMasteryUsed());
} }
if (skill != null) if (skill != null)
@@ -1088,7 +1089,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
for (Item item : equipped.values()) { for (Item item : equipped.values()) {
ItemTemplate ib = item.template; CObjectTemplate ib = item.template;
if (ib == null) if (ib == null)
continue; continue;
@@ -1507,9 +1508,9 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
} }
float range = 8; float range = 8;
if ((this).charItemManager.equipped.get(EquipSlotType.RHELD) != null) { if ((this).charItemManager.equipped.get(EquipSlotType.RHELD) != null) {
range = ((Mob) this).charItemManager.equipped.get(EquipSlotType.RHELD).template.item_weapon_max_range; range = engine.parsers.objects.ItemTemplate.getWeapon(((Mob) this).charItemManager.equipped.get(EquipSlotType.RHELD).templateID).weapon_max_range;
} else if (((Mob) this).charItemManager.equipped.get(EquipSlotType.LHELD) != null) { } else if (((Mob) this).charItemManager.equipped.get(EquipSlotType.LHELD) != null) {
range = ((Mob) this).charItemManager.equipped.get(EquipSlotType.LHELD).template.item_weapon_max_range; range = engine.parsers.objects.ItemTemplate.getWeapon(((Mob) this).charItemManager.equipped.get(EquipSlotType.LHELD).templateID).weapon_max_range;
} else { } else {
// Unarmed: use the rune natural attack range when it has one (e.g. Gasser 150), not clamped. // Unarmed: use the rune natural attack range when it has one (e.g. Gasser 150), not clamped.
+3 -3
View File
@@ -172,7 +172,7 @@ public class Account extends AbstractGameObject {
this.vault = DbManager.ItemQueries.GET_ITEMS_FOR_ACCOUNT(this.getObjectUUID()); this.vault = DbManager.ItemQueries.GET_ITEMS_FOR_ACCOUNT(this.getObjectUUID());
for (Item item : this.vault) { for (Item item : this.vault) {
if (item.template.item_type.equals(mbEnums.ItemType.GOLD)) { if (item.template.getItemType().equals(mbEnums.ItemType.GOLD)) {
this.vaultGold = item; this.vaultGold = item;
} }
} }
@@ -216,7 +216,7 @@ public class Account extends AbstractGameObject {
return; return;
if (item.containerType == mbEnums.ItemContainerType.INVENTORY && player.charItemManager.isVaultOpen()) { if (item.containerType == mbEnums.ItemContainerType.INVENTORY && player.charItemManager.isVaultOpen()) {
if (!player.charItemManager.hasRoomVault(item.template.item_wt)) { if (!player.charItemManager.hasRoomVault(item.template.getItemWt())) {
ItemToVaultMsgHandler.forceTransferFromVaultToInventory(msg, origin, "There is no room in your vault."); ItemToVaultMsgHandler.forceTransferFromVaultToInventory(msg, origin, "There is no room in your vault.");
return; return;
} }
@@ -262,7 +262,7 @@ public class Account extends AbstractGameObject {
return; return;
if (item.containerType == mbEnums.ItemContainerType.VAULT && itemManager.isVaultOpen()) { if (item.containerType == mbEnums.ItemContainerType.VAULT && itemManager.isVaultOpen()) {
if (!itemManager.hasRoomInventory(item.template.item_wt)) { if (!itemManager.hasRoomInventory(item.template.getItemWt())) {
ItemFromVaultMsgHandler.forceTransferFromInventoryToVault(msg, origin, "There is no room in your inventory."); ItemFromVaultMsgHandler.forceTransferFromInventoryToVault(msg, origin, "There is no room in your inventory.");
return; return;
} }
+39 -1
View File
@@ -10,7 +10,11 @@
package engine.objects; package engine.objects;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.mbEnums;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.parsers.objects.RuneTemplate;
import engine.util.Hasher;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@@ -104,8 +108,42 @@ public class BaseClass extends AbstractGameObject {
} }
/**
* Rune Template Constructor
*/
public BaseClass(RuneTemplate rune) {
super(rune.template_id);
this.name = rune.obj_name;
this.description = rune.rune_dsc;
this.strMod = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Strength, 0).byteValue();
this.dexMod = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Dexterity, 0).byteValue();
this.conMod = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Constitution, 0).byteValue();
this.intMod = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Intelligence, 0).byteValue();
this.spiMod = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Spirit, 0).byteValue();
this.token = Hasher.SBStringHash(rune.rune_sub_type);
this.healthMod = rune.rune_health;
this.manaMod = rune.rune_mana;
this.staminaMod = rune.rune_stamina;
this.skillsGranted = DbManager.SkillReqQueries.GET_REQS_FOR_RUNE(this.getObjectUUID());
this.powersGranted = PowerReq.getPowerReqsForRune(this.getObjectUUID());
this.effectsList = (DbManager.MobBaseQueries.GET_RUNEBASE_EFFECTS(this.getObjectUUID()));
}
public static void LoadAllBaseClasses() { public static void LoadAllBaseClasses() {
DbManager.BaseClassQueries.GET_ALL_BASE_CLASSES();
int loadedCount = 0;
// Promotion classes and the Pet class are also CLASS runes, but not standard creation runes
for (RuneTemplate rune : RuneTemplate._runes.values()) {
if (rune.rune_type != mbEnums.RuneType.CLASS || !rune.rune_is_standard_character_creation)
continue;
DbManager.addToCache(new BaseClass(rune));
loadedCount++;
}
Logger.info("Loaded " + loadedCount + " base classes from runes");
} }
public static void serializeForClientMsg(BaseClass baseClass, ByteBufferWriter writer) { public static void serializeForClientMsg(BaseClass baseClass, ByteBufferWriter writer) {
+34 -33
View File
@@ -17,6 +17,7 @@ import engine.mbEnums.ItemType;
import engine.net.Dispatch; import engine.net.Dispatch;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.msg.*; import engine.net.client.msg.*;
import engine.parsers.objects.CObjectTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@@ -130,19 +131,19 @@ public class CharacterItemManager {
this.equipped.put(i.equipSlot, i); this.equipped.put(i.equipSlot, i);
break; break;
case BANK: case BANK:
if (i.template.item_type.equals(ItemType.GOLD)) if (i.template.getItemType().equals(ItemType.GOLD))
this.goldBank = i; this.goldBank = i;
else if (this.bank.contains(i) == false) else if (this.bank.contains(i) == false)
this.bank.add(i); this.bank.add(i);
break; break;
case INVENTORY: case INVENTORY:
if (i.template.item_type.equals(ItemType.GOLD)) if (i.template.getItemType().equals(ItemType.GOLD))
this.goldInventory = i; this.goldInventory = i;
else if (this.inventory.contains(i) == false) else if (this.inventory.contains(i) == false)
this.inventory.add(i); this.inventory.add(i);
break; break;
case VAULT: case VAULT:
if (i.template.item_type.equals(ItemType.GOLD)) if (i.template.getItemType().equals(ItemType.GOLD))
this.goldVault = i; this.goldVault = i;
else if (this.vault.contains(i) == false) else if (this.vault.contains(i) == false)
this.vault.add(i); this.vault.add(i);
@@ -175,13 +176,13 @@ public class CharacterItemManager {
this.equipped.put(i.equipSlot, i); this.equipped.put(i.equipSlot, i);
break; break;
case BANK: case BANK:
if (i.template.item_type.equals(ItemType.GOLD)) if (i.template.getItemType().equals(ItemType.GOLD))
this.goldBank = i; this.goldBank = i;
else if (this.bank.contains(i) == false) else if (this.bank.contains(i) == false)
this.bank.add(i); this.bank.add(i);
break; break;
case INVENTORY: case INVENTORY:
if (i.template.item_type.equals(ItemType.GOLD)) if (i.template.getItemType().equals(ItemType.GOLD))
this.goldInventory = i; this.goldInventory = i;
else if (this.inventory.contains(i) == false) else if (this.inventory.contains(i) == false)
this.inventory.add(i); this.inventory.add(i);
@@ -511,7 +512,7 @@ public class CharacterItemManager {
if (i == null) if (i == null)
return false; return false;
if (i.template.item_type.equals(ItemType.GOLD)) { if (i.template.getItemType().equals(ItemType.GOLD)) {
if (this.getGoldInventory() != null) { if (this.getGoldInventory() != null) {
if (i.getObjectUUID() == this.getGoldInventory().getObjectUUID()) if (i.getObjectUUID() == this.getGoldInventory().getObjectUUID())
this.goldInventory = null; this.goldInventory = null;
@@ -541,7 +542,7 @@ public class CharacterItemManager {
} }
private synchronized boolean junk(Item i, boolean updateInventory) { private synchronized boolean junk(Item i, boolean updateInventory) {
if (i.template.item_type.equals(ItemType.GOLD)) { if (i.template.getItemType().equals(ItemType.GOLD)) {
if (this.getGoldInventory().getObjectUUID() == i.getObjectUUID()) if (this.getGoldInventory().getObjectUUID() == i.getObjectUUID())
if (DbManager.ItemQueries.UPDATE_GOLD(i, 0)) { if (DbManager.ItemQueries.UPDATE_GOLD(i, 0)) {
this.getGoldInventory().setNumOfItems(0); this.getGoldInventory().setNumOfItems(0);
@@ -596,7 +597,7 @@ public class CharacterItemManager {
if (equippedContains(item)) { if (equippedContains(item)) {
fromEquip = true; fromEquip = true;
if (item.template.item_type.equals(ItemType.GOLD)) if (item.template.getItemType().equals(ItemType.GOLD))
this.absCharacter.cancelOnUnEquip(); this.absCharacter.cancelOnUnEquip();
} }
@@ -814,7 +815,7 @@ public class CharacterItemManager {
// This removes ingame item from inventory for loot. // This removes ingame item from inventory for loot.
private synchronized boolean removeItemFromInventory(Item i) { private synchronized boolean removeItemFromInventory(Item i) {
if (i.template.item_type.equals(ItemType.GOLD)) { if (i.template.getItemType().equals(ItemType.GOLD)) {
if (i.getObjectUUID() != this.getGoldInventory().getObjectUUID()) if (i.getObjectUUID() != this.getGoldInventory().getObjectUUID())
return false; return false;
if (!DbManager.ItemQueries.UPDATE_GOLD(this.goldInventory, 0)) { if (!DbManager.ItemQueries.UPDATE_GOLD(this.goldInventory, 0)) {
@@ -837,7 +838,7 @@ public class CharacterItemManager {
// This adds item to inventory for loot. Validity checks already handled // This adds item to inventory for loot. Validity checks already handled
public synchronized boolean addItemToInventory(Item i) { public synchronized boolean addItemToInventory(Item i) {
if (i.template.item_type.equals(ItemType.GOLD)) if (i.template.getItemType().equals(ItemType.GOLD))
if (this.absCharacter.getObjectType() == GameObjectType.Mob) { if (this.absCharacter.getObjectType() == GameObjectType.Mob) {
if (this.goldInventory == null) if (this.goldInventory == null)
loadGoldItems(); loadGoldItems();
@@ -856,7 +857,7 @@ public class CharacterItemManager {
this.itemIDtoType.put(i.getObjectUUID(), i.getObjectType().ordinal()); this.itemIDtoType.put(i.getObjectUUID(), i.getObjectType().ordinal());
if (i.template != null) if (i.template != null)
this.inventoryWeight += i.template.item_wt; this.inventoryWeight += i.template.getItemWt();
return true; return true;
} }
@@ -1041,7 +1042,7 @@ public class CharacterItemManager {
if (npc.getContractID() >= 1900 && npc.getContractID() <= 1906) if (npc.getContractID() >= 1900 && npc.getContractID() <= 1906)
eatItem = true; eatItem = true;
if (itemToSell.template.item_type.equals(ItemType.POTION)) if (itemToSell.template.getItemType().equals(ItemType.POTION))
eatItem = true; eatItem = true;
if (eatItem) { if (eatItem) {
@@ -1085,14 +1086,14 @@ public class CharacterItemManager {
synchronized (this) { synchronized (this) {
synchronized (itemMan) { synchronized (itemMan) {
ItemTemplate template = purchasedItem.template; CObjectTemplate template = purchasedItem.template;
if (template == null) if (template == null)
return false; return false;
//test inventory is not full //test inventory is not full
if (!hasRoomInventory(template.item_wt)) if (!hasRoomInventory(template.getItemWt()))
return false; return false;
if (!itemMan.inventory.contains(purchasedItem)) if (!itemMan.inventory.contains(purchasedItem))
@@ -1105,8 +1106,8 @@ public class CharacterItemManager {
// Reset value // Reset value
purchasedItem.value = (int) (purchasedItem.template.item_value * (purchasedItem.combat_health_current / purchasedItem.template.combat_health_full)); purchasedItem.value = (int) (purchasedItem.template.getItemValue() * (purchasedItem.combat_health_current / purchasedItem.template.getCombatHealthFull()));
purchasedItem.magicValue = purchasedItem.template.item_value + purchasedItem.calcMagicValue(); purchasedItem.magicValue = purchasedItem.template.getItemValue() + purchasedItem.calcMagicValue();
// db transfer successfully, remove from this character // db transfer successfully, remove from this character
// skip this check if this is a mobLoot item (which is not in any inventory) // skip this check if this is a mobLoot item (which is not in any inventory)
@@ -1184,9 +1185,9 @@ public class CharacterItemManager {
synchronized (lockFirst) { synchronized (lockFirst) {
synchronized (lockSecond) { synchronized (lockSecond) {
// make sure current player has item in inventory // make sure current player has item in inventory
if (lootItem.template.item_type.equals(ItemType.GOLD) && lootItem.getObjectUUID() != this.getGoldInventory().getObjectUUID() && !(this.absCharacter.getObjectType().equals(GameObjectType.Mob))) if (lootItem.template.getItemType().equals(ItemType.GOLD) && lootItem.getObjectUUID() != this.getGoldInventory().getObjectUUID() && !(this.absCharacter.getObjectType().equals(GameObjectType.Mob)))
return null; return null;
else if (!this.inventory.contains(lootItem) && !this.equipped.containsValue(lootItem) && !lootItem.template.item_type.equals(ItemType.GOLD)) else if (!this.inventory.contains(lootItem) && !this.equipped.containsValue(lootItem) && !lootItem.template.getItemType().equals(ItemType.GOLD))
return null; return null;
// get weight of item // get weight of item
@@ -1194,13 +1195,13 @@ public class CharacterItemManager {
if (lootItem.template == null) if (lootItem.template == null)
return null; return null;
int weight = lootItem.template.item_wt; int weight = lootItem.template.getItemWt();
// make sure lootingPlayer has room for item // make sure lootingPlayer has room for item
if (!lootItem.template.item_type.equals(ItemType.GOLD) && !looterItems.hasRoomInventory(weight)) if (!lootItem.template.getItemType().equals(ItemType.GOLD) && !looterItems.hasRoomInventory(weight))
return null; return null;
if (lootItem.template.item_type.equals(ItemType.GOLD)) if (lootItem.template.getItemType().equals(ItemType.GOLD))
if (amount != -1) { //from steal if (amount != -1) { //from steal
int total = lootItem.getNumOfItems(); int total = lootItem.getNumOfItems();
amount = (amount > total) ? total : amount; amount = (amount > total) ? total : amount;
@@ -1263,19 +1264,19 @@ public class CharacterItemManager {
* Delegates * Delegates
*/ */
public synchronized boolean bankContains(Item item) { public synchronized boolean bankContains(Item item) {
if (item.template.item_type.equals(ItemType.GOLD)) if (item.template.getItemType().equals(ItemType.GOLD))
return (this.getGoldBank() != null && this.goldBank.getObjectUUID() == item.getObjectUUID()); return (this.getGoldBank() != null && this.goldBank.getObjectUUID() == item.getObjectUUID());
return bank.contains(item); return bank.contains(item);
} }
public synchronized boolean inventoryContains(Item item) { public synchronized boolean inventoryContains(Item item) {
if (item.template.item_type.equals(ItemType.GOLD)) if (item.template.getItemType().equals(ItemType.GOLD))
return (this.getGoldInventory() != null && this.goldInventory.getObjectUUID() == item.getObjectUUID()); return (this.getGoldInventory() != null && this.goldInventory.getObjectUUID() == item.getObjectUUID());
return inventory.contains(item); return inventory.contains(item);
} }
public synchronized boolean vaultContains(Item item) { public synchronized boolean vaultContains(Item item) {
if (item.template.item_type.equals(ItemType.GOLD)) if (item.template.getItemType().equals(ItemType.GOLD))
return (this.getGoldVault() != null && this.goldVault.getObjectUUID() == item.getObjectUUID()); return (this.getGoldVault() != null && this.goldVault.getObjectUUID() == item.getObjectUUID());
return this.account.getVault().contains(item); return this.account.getVault().contains(item);
} }
@@ -1518,13 +1519,13 @@ public class CharacterItemManager {
item.zeroItem(); item.zeroItem();
item.containerType = mbEnums.ItemContainerType.INVENTORY; item.containerType = mbEnums.ItemContainerType.INVENTORY;
if (item.template.item_type.equals(ItemType.GOLD)) if (item.template.getItemType().equals(ItemType.GOLD))
//only add gold item once //only add gold item once
if (!corpse.hasGold()) if (!corpse.hasGold())
corpse.setHasGold(true); corpse.setHasGold(true);
newInventory.add(item); newInventory.add(item);
} else //item } else //item
if (item.template.item_type.equals(ItemType.GOLD)) { if (item.template.getItemType().equals(ItemType.GOLD)) {
int amt = item.getNumOfItems(); int amt = item.getNumOfItems();
item.setNumOfItems(0); item.setNumOfItems(0);
MobLoot ml = new MobLoot(this.absCharacter, amt); MobLoot ml = new MobLoot(this.absCharacter, amt);
@@ -1676,7 +1677,7 @@ public class CharacterItemManager {
if (item == null) if (item == null)
continue; continue;
weight += item.template.item_wt; weight += item.template.getItemWt();
} }
return weight; return weight;
} }
@@ -1696,7 +1697,7 @@ public class CharacterItemManager {
this.bankWeight = 0; this.bankWeight = 0;
for (Item item : this.bank) { for (Item item : this.bank) {
if (item.template != null) if (item.template != null)
this.bankWeight += item.template.item_wt; this.bankWeight += item.template.getItemWt();
} }
} }
@@ -1707,7 +1708,7 @@ public class CharacterItemManager {
while (it.hasNext()) { while (it.hasNext()) {
Item item = it.next(); Item item = it.next();
if (item.template != null) if (item.template != null)
this.equipWeight += item.template.item_wt; this.equipWeight += item.template.getItemWt();
} }
} }
@@ -1715,7 +1716,7 @@ public class CharacterItemManager {
this.inventoryWeight = 0; this.inventoryWeight = 0;
for (Item item : this.inventory) { for (Item item : this.inventory) {
if (item.template != null) if (item.template != null)
this.inventoryWeight += item.template.item_wt; this.inventoryWeight += item.template.getItemWt();
} }
} }
@@ -1723,7 +1724,7 @@ public class CharacterItemManager {
this.vaultWeight = 0; this.vaultWeight = 0;
for (Item item : this.vault) { for (Item item : this.vault) {
if (item.template != null) if (item.template != null)
this.vaultWeight += item.template.item_wt; this.vaultWeight += item.template.getItemWt();
} }
} }
@@ -1755,7 +1756,7 @@ public class CharacterItemManager {
return; return;
if (!item.moveItemToInventory(player)) if (!item.moveItemToInventory(player))
Logger.error("templateL " + item.template.template_id); Logger.error("templateL " + item.template.getTemplateId());
// remove it from other lists: // remove it from other lists:
this.remItemFromLists(item); this.remItemFromLists(item);
@@ -1932,7 +1933,7 @@ public class CharacterItemManager {
return; return;
//don't damage noob gear, hair or beards. //don't damage noob gear, hair or beards.
if (item.template.combat_health_full == 0) if (item.template.getCombatHealthFull() == 0)
return; return;
if (!item.isCanDestroy()) if (!item.isCanDestroy())
+3 -3
View File
@@ -296,14 +296,14 @@ public class Corpse extends AbstractWorldObject {
//get weight of item //get weight of item
int weight = item.template.item_wt; int weight = item.template.getItemWt();
//make sure looter has room for item //make sure looter has room for item
if (item.template.item_type.equals(ItemType.GOLD) == false && !looterItems.hasRoomInventory(weight)) if (item.template.getItemType().equals(ItemType.GOLD) == false && !looterItems.hasRoomInventory(weight))
return null; return null;
//attempt to transfer item in db //attempt to transfer item in db
if (item.template.item_type.equals(ItemType.GOLD)) { if (item.template.getItemType().equals(ItemType.GOLD)) {
if (!looterItems.moveGoldToInventory(item, item.getNumOfItems())) if (!looterItems.moveGoldToInventory(item, item.getNumOfItems()))
return null; return null;
} else if (!item.moveItemToInventory(looter)) } else if (!item.moveItemToInventory(looter))
+30 -23
View File
@@ -20,6 +20,8 @@ import engine.net.ByteBufferWriter;
import engine.net.Dispatch; import engine.net.Dispatch;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.msg.DeleteItemMsg; import engine.net.client.msg.DeleteItemMsg;
import engine.parsers.objects.CObjectTemplate;
import engine.parsers.objects.UserPowerAction;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
import engine.powers.effectmodifiers.AbstractEffectModifier; import engine.powers.effectmodifiers.AbstractEffectModifier;
import engine.powers.poweractions.AbstractPowerAction; import engine.powers.poweractions.AbstractPowerAction;
@@ -31,6 +33,7 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
@@ -55,7 +58,7 @@ public class Item extends AbstractWorldObject {
public int templateID; public int templateID;
private long dateToUpgrade; private long dateToUpgrade;
public int magicValue; public int magicValue;
public ItemTemplate template; public CObjectTemplate template;
public String name = ""; public String name = "";
public int prefixToken; // Forge support public int prefixToken; // Forge support
public int suffixToken; // Forge support public int suffixToken; // Forge support
@@ -68,14 +71,14 @@ public class Item extends AbstractWorldObject {
public Item(int templateID) { public Item(int templateID) {
super(); super();
this.templateID = templateID; this.templateID = templateID;
this.template = ItemTemplate.templates.get(templateID); this.template = CObjectTemplate.lookup(templateID);
this.chargesRemaining = this.template.item_initial_charges; this.chargesRemaining = this.template.getItemInitialCharges();
this.combat_health_current = this.template.combat_health_full; this.combat_health_current = this.template.getCombatHealthFull();
this.equipSlot = EquipSlotType.NONE; this.equipSlot = EquipSlotType.NONE;
this.containerType = ItemContainerType.NONE; this.containerType = ItemContainerType.NONE;
this.numberOfItems = 1; this.numberOfItems = 1;
this.flags.addAll(this.template.item_flags); this.flags.addAll(this.template.getItemFlags());
this.value = this.template.item_value; this.value = this.template.getItemValue();
this.magicValue = this.value + calcMagicValue(); this.magicValue = this.value + calcMagicValue();
loadTemplateEnchantments(); loadTemplateEnchantments();
} }
@@ -87,7 +90,7 @@ public class Item extends AbstractWorldObject {
super(rs); super(rs);
this.templateID = rs.getInt("templateID"); this.templateID = rs.getInt("templateID");
this.template = ItemTemplate.templates.get(this.templateID); this.template = CObjectTemplate.lookup(this.templateID);
if (this.template == null) if (this.template == null)
Logger.error("Null template of " + this.templateID); Logger.error("Null template of " + this.templateID);
@@ -166,7 +169,7 @@ public class Item extends AbstractWorldObject {
this.value = rs.getInt("value"); this.value = rs.getInt("value");
if (this.value == 0) { if (this.value == 0) {
this.value = this.template.item_value; this.value = this.template.getItemValue();
this.magicValue = this.value + calcMagicValue(); this.magicValue = this.value + calcMagicValue();
} else } else
this.magicValue = this.value; // Value was overridden in vendor inventory this.magicValue = this.value; // Value was overridden in vendor inventory
@@ -238,7 +241,7 @@ public class Item extends AbstractWorldObject {
writer.putString(item.name); // Unknown. pad? writer.putString(item.name); // Unknown. pad?
writer.put((byte) 1); // End Datablock byte writer.put((byte) 1); // End Datablock byte
writer.putFloat(item.template.combat_health_full); writer.putFloat(item.template.getCombatHealthFull());
writer.putFloat((float) item.combat_health_current); writer.putFloat((float) item.combat_health_current);
writer.put((byte) 1); // End Datablock byte writer.put((byte) 1); // End Datablock byte
@@ -255,7 +258,7 @@ public class Item extends AbstractWorldObject {
} else } else
writer.putInt(item.numberOfItems); // Amount of gold writer.putInt(item.numberOfItems); // Amount of gold
} else } else
writer.putInt(item.template.item_value); writer.putInt(item.template.getItemValue());
writer.putInt(item.getValue()); writer.putInt(item.getValue());
@@ -288,7 +291,7 @@ public class Item extends AbstractWorldObject {
writer.putInt(36); //Magical, blue name writer.putInt(36); //Magical, blue name
else else
writer.putInt(40); //Magical, unidentified writer.putInt(40); //Magical, unidentified
else if (item.template.item_user_power_action.size() > 0) else if (item.template.getItemUserPowerAction().isEmpty() == false)
writer.putInt(36); //Magical, blue name writer.putInt(36); //Magical, blue name
else else
writer.putInt(4); //Non-Magical, grey name writer.putInt(4); //Non-Magical, grey name
@@ -298,7 +301,7 @@ public class Item extends AbstractWorldObject {
writer.put((byte) 0); writer.put((byte) 0);
if (item.template.item_type.equals(ItemType.EMPLOYMENTCONTRACT) == false) { if (item.template.getItemType().equals(ItemType.EMPLOYMENTCONTRACT) == false) {
writer.putShort((short) 0); writer.putShort((short) 0);
return; return;
} }
@@ -463,7 +466,7 @@ public class Item extends AbstractWorldObject {
int serialized = 0; int serialized = 0;
for (Item item : list) { for (Item item : list) {
if (item.template.item_type.equals(ItemType.GOLD)) if (item.template.getItemType().equals(ItemType.GOLD))
if (item.numberOfItems == 0) if (item.numberOfItems == 0)
continue; continue;
try { try {
@@ -497,7 +500,7 @@ public class Item extends AbstractWorldObject {
int serialized = 0; int serialized = 0;
for (Item item : list) { for (Item item : list) {
if (item.template.item_type.equals(ItemType.GOLD)) if (item.template.getItemType().equals(ItemType.GOLD))
if (item.numberOfItems == 0) if (item.numberOfItems == 0)
continue; continue;
try { try {
@@ -931,12 +934,16 @@ public class Item extends AbstractWorldObject {
private void loadTemplateEnchantments() { private void loadTemplateEnchantments() {
EffectsBase effect; EffectsBase effect;
LinkedHashMap<String, int[]> templateEnchantments = new LinkedHashMap<>();
if (ConfigManager.serverType.equals(mbEnums.ServerType.LOGINSERVER)) if (ConfigManager.serverType.equals(mbEnums.ServerType.LOGINSERVER))
return; return;
// Duplicate powers collapse to the last entry; applying one twice would double its magic value.
for (UserPowerAction userPowerAction : this.template.getItemUserPowerAction())
templateEnchantments.put(userPowerAction.power, userPowerAction.arguments);
for (String effectID : this.template.item_user_power_action.keySet()) { for (String effectID : templateEnchantments.keySet()) {
effect = PowersManager.getEffectByIDString(effectID); effect = PowersManager.getEffectByIDString(effectID);
@@ -946,7 +953,7 @@ public class Item extends AbstractWorldObject {
} }
AbstractPowerAction apa = PowersManager.getPowerActionByIDString(effect.getIDString()); AbstractPowerAction apa = PowersManager.getPowerActionByIDString(effect.getIDString());
apa.applyBakedInStatsForItem(this, this.template.item_user_power_action.get(effectID)[0]); apa.applyBakedInStatsForItem(this, templateEnchantments.get(effectID)[0]);
} }
} }
@@ -955,7 +962,7 @@ public class Item extends AbstractWorldObject {
// No enchantments for negative id items in the db. Early exit. // No enchantments for negative id items in the db. Early exit.
if (this.objectUUID < 0) { if (this.objectUUID < 0) {
this.magicValue = this.template.item_value + calcMagicValue(); this.magicValue = this.template.getItemValue() + calcMagicValue();
return; return;
} }
@@ -971,8 +978,8 @@ public class Item extends AbstractWorldObject {
// Value is overridden the db // Value is overridden the db
if (this.value == this.template.item_value) if (this.value == this.template.getItemValue())
this.magicValue = this.template.item_value + calcMagicValue(); this.magicValue = this.template.getItemValue() + calcMagicValue();
} }
public void addPermanentEnchantment(String enchantID, int rank) { public void addPermanentEnchantment(String enchantID, int rank) {
@@ -1116,11 +1123,11 @@ public class Item extends AbstractWorldObject {
else else
modifiedValue = this.value; modifiedValue = this.value;
if (this.template.item_initial_charges > 0) if (this.template.getItemInitialCharges() > 0)
modifiedValue = modifiedValue * (this.chargesRemaining / this.template.item_initial_charges); modifiedValue = modifiedValue * (this.chargesRemaining / this.template.getItemInitialCharges());
if (this.template.combat_health_full > 0) if (this.template.getCombatHealthFull() > 0)
modifiedValue = (int) (modifiedValue * (this.combat_health_current / this.template.combat_health_full)); modifiedValue = (int) (modifiedValue * (this.combat_health_current / this.template.getCombatHealthFull()));
return modifiedValue; return modifiedValue;
} }
-649
View File
@@ -1,649 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.objects;
import engine.math.Vector3fImmutable;
import engine.mbEnums;
import org.json.JSONArray;
import org.json.JSONObject;
import org.pmw.tinylog.Logger;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
public class ItemTemplate {
// MB Dev Notes:
// This class parses JSON data generated by mbEditor Pro 2.1.
// Cache definitions are loaded for ItemType.ITEM, ItemType,DEED
// and ItemType.RUNE.
//
// Exported JSON data is stored in db table static_item_templates
// and can be easily mass updated using tooling available on the Wiki.
//
// Always read never write!
// Use copies of fields to avoid side effects.
// Global template lookup
public static HashMap<Integer, ItemTemplate> templates = new HashMap<>();
public int template_id;
// Template Properties
public String obj_name;
public boolean obj_pickable;
public Vector3fImmutable obj_scale;
public Vector3fImmutable obj_forward_vector;
public Vector3fImmutable obj_default_alignment;
public int obj_render_object;
public int obj_icon;
public final HashMap<String, String> obj_sparse_data = new HashMap<>();
public float combat_health_current;
public float combat_health_full;
public final HashMap<String, Float> combat_attack_resist = new HashMap<>();
public mbEnums.ItemType item_type;
public int item_eq_slots_value;
public boolean item_eq_slots_type;
public final EnumSet<mbEnums.EquipSlotType> item_eq_slots_or = EnumSet.noneOf(mbEnums.EquipSlotType.class);
public final EnumSet<mbEnums.EquipSlotType> item_eq_slots_and = EnumSet.noneOf(mbEnums.EquipSlotType.class);
public boolean item_takeable;
public int item_value;
public int item_wt;
public float item_passive_defense_mod;
public String item_base_name;
public String item_dsc;
public int item_render_object_female;
public float item_health_full;
public String item_skill_used = "";
public String item_skill_mastery_used = "";
public int item_parry_anim_id;
public float item_bulk_factor;
public final HashMap<mbEnums.ShrineType, Integer> item_offering_info = new HashMap<>();
public int item_defense_rating;
public float item_weapon_wepspeed;
public float item_weapon_max_range;
public int item_weapon_projectile_id;
public float item_weapon_projectile_speed;
public int item_weapon_combat_idle_anim;
public final HashMap<mbEnums.DamageType, int[]> item_weapon_damage = new HashMap<>();
public final ArrayList<int[]> weapon_attack_anim_right = new ArrayList<>();
public final ArrayList<int[]> weapon_attack_anim_left = new ArrayList<>();
public mbEnums.AttributeType item_primary_attr = mbEnums.AttributeType.None;
public mbEnums.AttributeType item_secondary_attr = mbEnums.AttributeType.None;
public final EnumSet<mbEnums.ItemFlags> item_flags = EnumSet.noneOf(mbEnums.ItemFlags.class);
public final EnumSet<mbEnums.ItemUseFlags> item_use_flags = EnumSet.noneOf(mbEnums.ItemUseFlags.class);
public int item_initial_charges;
public final HashMap<String, Integer> item_skill_required = new HashMap<>();
public final EnumSet<mbEnums.MonsterType> item_race_req = EnumSet.noneOf(mbEnums.MonsterType.class);
public final EnumSet<mbEnums.MonsterType> item_race_res = EnumSet.noneOf(mbEnums.MonsterType.class);
public final EnumSet<mbEnums.ClassType> item_class_req = EnumSet.noneOf(mbEnums.ClassType.class);
public final EnumSet<mbEnums.ClassType> item_class_res = EnumSet.noneOf(mbEnums.ClassType.class);
public final EnumSet<mbEnums.DisciplineType> item_disc_req = EnumSet.noneOf(mbEnums.DisciplineType.class);
public final EnumSet<mbEnums.DisciplineType> item_disc_res = EnumSet.noneOf(mbEnums.DisciplineType.class);
public int item_level_req;
public mbEnums.SexType item_sex_req;
// Lossy: some runes list the same power several times with different
// arguments (a step table, e.g. PET_DISC). Only the last entry is kept.
// engine.parsers.objects.RuneTemplate keeps the full list.
public final HashMap<String, int[]> item_user_power_action = new HashMap<>();
public final HashMap<String, Integer> item_power_grant = new HashMap<>();
// Lossy: some runes carry up to 35 power_actions entries per power
// (a step table, e.g. HNT-031). Only the first entry is kept.
// engine.parsers.objects.RuneTemplate keeps the full list.
public final HashMap<String, int[]> item_power_action = new HashMap<>();
public final HashMap<mbEnums.ResourceType, Integer> item_resource_cost = new HashMap<>();
public int modTable;
public int deed_type;
public int deed_furniture_id;
public int deed_target_id;
public int deed_employment;
public int deed_start_rank;
public int deed_name_lookup;
public boolean deed_indoors;
public boolean deed_is_fortress;
public float deed_namelookup_val;
public boolean deed_custom_city;
public int deed_structure_id;
public final HashMap<mbEnums.AttributeType, Integer> rune_attr_adj = new HashMap<>();
public final HashMap<mbEnums.AttributeType, Integer> rune_max_attr_adj = new HashMap<>();
public final HashMap<String, Integer> rune_skill_grant = new HashMap<>();
public final HashMap<String, Integer> skill_granted_skills = new HashMap<>();
public final HashMap<String, Integer> power_granted_skills = new HashMap<>();
public String rune_type;
public String rune_sub_type;
public boolean rune_is_standard_character_creation = false;
public int rune_creation_cost;
public int rune_rank;
public int rune_pracs_per_level;
public float rune_exp_req_to_level;
public mbEnums.SexType rune_sex;
public int rune_class_icon;
public int rune_health;
public int rune_mana;
public int rune_stamina;
public float rune_min_damage;
public float rune_max_damage;
public int rune_attack;
public int rune_defense;
public int rune_level;
public final HashMap<mbEnums.MovementType, Float> rune_speed = new HashMap<>();
public int rune_group_type;
public boolean rune_group_is_faction = false;
public boolean rune_group_is_guild = false;
public String rune_dsc;
public String rune_fx_txt;
public final EnumSet<mbEnums.MobBehaviourType> rune_group_tactics = EnumSet.noneOf(mbEnums.MobBehaviourType.class);
public final EnumSet<mbEnums.MobBehaviourType> rune_group_role_set = EnumSet.noneOf(mbEnums.MobBehaviourType.class);
public boolean rune_renderable = false;
public int rune_natural_power_attack;
// One float[] per rune_naturalattacks entry. Same "attack info" struct as a weapon (verified in IDA, see
// MBDATA/docs/client-map.md): [0] attack speed (WEPSPEED), [1] range (MAXRANGE), [2] unknown int,
// [3] equip slot (1 = RHELD, 2 = LHELD), [4] projectile template id, [5] projectile speed, [6] swing anim,
// [7] damage type, [8] min damage, [9] max damage
public final ArrayList<float[]> rune_natural_attacks = new ArrayList<>();
public final HashMap<String, String> rune_sparse_data = new HashMap<>();
public final HashMap<String, int[]> rune_skill_adj = new HashMap<>();
public final EnumSet<mbEnums.MonsterType> rune_enemy_monster_types = EnumSet.noneOf(mbEnums.MonsterType.class);
public final EnumSet<mbEnums.MonsterType> rune_not_enemy_monster_types = EnumSet.noneOf(mbEnums.MonsterType.class);
public final ArrayList<Integer> rune_groupee_monster_types = new ArrayList<>();
public final ArrayList<Integer> rune_helper_monster_types = new ArrayList<>();
public int item_bane_rank;
public ItemTemplate(JSONObject jsonObject) {
try {
// Reading a String
obj_name = jsonObject.getString("obj_name");
// Reading a boolean
obj_pickable = jsonObject.getBoolean("obj_pickable");
// Reading floats from an array (note always check for empty arrays)
JSONArray scaleData = jsonObject.getJSONArray("obj_scale");
if (scaleData.isEmpty() == false)
obj_scale = new Vector3fImmutable(scaleData.getFloat(0), scaleData.getFloat(1),
scaleData.getFloat(2));
JSONArray forwardVector = jsonObject.getJSONArray("obj_forward_vector");
if (forwardVector.isEmpty() == false)
obj_forward_vector = new Vector3fImmutable(forwardVector.getFloat(0), forwardVector.getFloat(1),
forwardVector.getFloat(2));
JSONArray defaultAlignment = jsonObject.getJSONArray("obj_default_alignment");
if (defaultAlignment.isEmpty() == false)
obj_default_alignment = new Vector3fImmutable(defaultAlignment.getFloat(0), defaultAlignment.getFloat(1),
defaultAlignment.getFloat(2));
// Reading an integer value
obj_render_object = jsonObject.getInt("obj_render_object");
obj_icon = jsonObject.getInt("obj_icon");
JSONObject obj_sparse_json = jsonObject.getJSONObject("obj_sparse_data");
for (String sparseType : obj_sparse_json.keySet()) {
Object sparseValue = obj_sparse_json.get(sparseType);
obj_sparse_data.put(sparseType, sparseValue.toString());
}
// Banes are defined by their sparse data field
if (obj_sparse_data.get("ACTIONRESPONSE") != null)
if (obj_sparse_data.get("ACTIONRESPONSE").equals("4250517122"))
item_bane_rank = jsonObject.getInt("item_bane_rank");
// Reading float values
combat_health_current = jsonObject.getFloat("combat_health_current");
combat_health_full = jsonObject.getFloat("combat_health_full");
// Reading a hashmap of floats
JSONObject resist_json = jsonObject.getJSONObject("combat_attack_resist");
for (String resistType : resist_json.keySet()) {
float resistValue = resist_json.getFloat(resistType);
combat_attack_resist.put(resistType, resistValue);
}
// Parsing an enum
item_type = mbEnums.ItemType.valueOf(jsonObject.getString("item_type"));
item_eq_slots_value = jsonObject.getInt("item_eq_slots_value");
item_eq_slots_type = jsonObject.getBoolean("item_eq_slots_type");
// Parsing an enumset
JSONArray eq_slots_or = jsonObject.getJSONArray("item_eq_slots_or");
if (eq_slots_or.isEmpty() == false)
for (Object o : eq_slots_or)
item_eq_slots_or.add(mbEnums.EquipSlotType.valueOf((String) o));
JSONArray eq_slots_and = jsonObject.getJSONArray("item_eq_slots_and");
if (eq_slots_and.isEmpty() == false)
for (Object o : eq_slots_and)
item_eq_slots_and.add(mbEnums.EquipSlotType.valueOf((String) o));
item_takeable = jsonObject.getBoolean("item_takeable");
item_value = (jsonObject.getInt("item_value"));
item_wt = jsonObject.getInt("item_wt");
item_passive_defense_mod = jsonObject.getFloat("item_passive_defense_mod");
item_base_name = jsonObject.getString("item_base_name");
item_dsc = jsonObject.getString("item_dsc");
item_render_object_female = jsonObject.getInt("item_render_object_female");
item_health_full = jsonObject.getFloat("item_health_full");
Object skill_used = jsonObject.get("item_skill_used");
if (skill_used instanceof String) {
if (skill_used.equals("Cloth") == false)
item_skill_used = (String) skill_used;
}
Object mastery_used = jsonObject.get("item_skill_mastery_used");
if (mastery_used instanceof String)
item_skill_mastery_used = (String) mastery_used;
item_parry_anim_id = jsonObject.getInt("item_parry_anim_id");
// Reading offering data
JSONArray offering_data = jsonObject.getJSONArray("item_offering_info");
for (Object entry : offering_data) {
JSONObject offering_entry = (JSONObject) entry;
String offering_type = offering_entry.getString("offering_type").replaceAll("-", "");
int offering_value = offering_entry.getInt("offering_value");
item_offering_info.put(mbEnums.ShrineType.valueOf(offering_type), offering_value);
}
// Fields only present for ARMOR
if (item_type.equals(mbEnums.ItemType.ARMOR)) {
item_bulk_factor = jsonObject.getFloat("item_bulk_factor");
item_defense_rating = jsonObject.getInt("item_defense_rating");
}
// Fields only present for WEAPON
if (item_type.equals(mbEnums.ItemType.WEAPON)) {
JSONObject item_weapon = jsonObject.getJSONObject("item_weapon");
item_weapon_wepspeed = item_weapon.getFloat("weapon_wepspeed");
item_weapon_max_range = item_weapon.getFloat("weapon_max_range");
item_weapon_projectile_id = item_weapon.getInt("weapon_projectile_id");
item_weapon_projectile_speed = item_weapon.getFloat("weapon_projectile_speed");
item_weapon_combat_idle_anim = item_weapon.getInt("weapon_combat_idle_anim");
JSONArray weapon_damage = item_weapon.getJSONArray("weapon_damage");
if (weapon_damage.isEmpty() == false)
for (Object o : weapon_damage) {
JSONObject damage_entry = (JSONObject) o;
mbEnums.DamageType damageType = mbEnums.DamageType.getDamageType(damage_entry.getString("damage_type"));
int min = damage_entry.getInt("damage_min");
int max = damage_entry.getInt("damage_max");
int[] minMax = {min, max};
item_weapon_damage.put(damageType, minMax);
}
JSONArray attack_anim_right = item_weapon.getJSONArray("weapon_attack_anim_right");
if (attack_anim_right.isEmpty() == false)
for (Object o : attack_anim_right) {
JSONArray animationEntry = (JSONArray) o;
int animation = animationEntry.getInt(0);
int duration = animationEntry.getInt(1);
weapon_attack_anim_right.add(new int[]{animation, duration});
}
JSONArray attack_anim_left = item_weapon.getJSONArray("weapon_attack_anim_left");
if (attack_anim_left.isEmpty() == false)
for (Object o : attack_anim_left) {
JSONArray animationEntry = (JSONArray) o;
int animation = animationEntry.getInt(0);
int duration = animationEntry.getInt(1);
weapon_attack_anim_left.add(new int[]{animation, duration});
}
item_primary_attr = mbEnums.AttributeType.valueOf(jsonObject.getString("item_primary_attr"));
item_secondary_attr = mbEnums.AttributeType.valueOf(jsonObject.getString("item_secondary_attr"));
}
JSONArray itemflags = jsonObject.getJSONArray("item_flags");
if (itemflags.isEmpty() == false)
for (Object o : itemflags) {
String flag = (String) o;
if (flag.equals("None") == false)
item_flags.add(mbEnums.ItemFlags.valueOf((String) o));
}
JSONArray itemUseflags = jsonObject.getJSONArray("item_use_flags");
if (itemUseflags.isEmpty() == false)
for (Object o : itemUseflags)
item_use_flags.add(mbEnums.ItemUseFlags.valueOf((String) o));
item_initial_charges = jsonObject.getInt("item_initial_charges");
JSONArray skill_required = jsonObject.getJSONArray("item_skill_req");
if (skill_required.isEmpty() == false)
for (Object o : skill_required) {
JSONObject skill_req = (JSONObject) o;
String skill_type = skill_req.getString("skill_type");
int skill_level = skill_req.getInt("skill_level");
if (skill_type.equals("Cloth") == false)
item_skill_required.put(skill_type, skill_level);
}
JSONObject race_required = jsonObject.getJSONObject("item_race_req");
boolean restrict = race_required.getBoolean("restrict");
JSONArray races = race_required.getJSONArray("races");
if (races.isEmpty() == false)
for (Object o : races) {
String race = (String) o;
race = race.replaceAll("\\s", "");
race = race.replaceAll(",", "");
race = race.replaceAll("-", "");
if (restrict)
item_race_res.add(mbEnums.MonsterType.valueOf(race));
else
item_race_req.add(mbEnums.MonsterType.valueOf(race));
}
JSONObject class_required = jsonObject.getJSONObject("item_class_req");
restrict = class_required.getBoolean("restrict");
JSONArray classes = class_required.getJSONArray("classes");
if (classes.isEmpty() == false)
for (Object o : classes) {
String classEntry = (String) o;
classEntry = classEntry.replaceAll("\\s", "");
classEntry = classEntry.replaceAll(",", "");
if (restrict)
item_class_res.add(mbEnums.ClassType.valueOf(classEntry));
else
item_class_req.add(mbEnums.ClassType.valueOf(classEntry));
}
JSONObject disc_required = jsonObject.getJSONObject("item_disc_req");
restrict = disc_required.getBoolean("restrict");
JSONArray discs = disc_required.getJSONArray("discs");
if (discs.isEmpty() == false)
for (Object o : discs) {
String disc = (String) o;
disc = disc.replaceAll("\\s", "");
disc = disc.replaceAll(",", "");
if (restrict)
item_disc_res.add(mbEnums.DisciplineType.valueOf(disc));
else
item_disc_req.add(mbEnums.DisciplineType.valueOf(disc));
}
item_level_req = jsonObject.getInt("item_level_req");
item_sex_req = mbEnums.SexType.valueOf(jsonObject.getString("item_sex_req"));
JSONArray userPowerActions = jsonObject.getJSONArray("item_user_power_action");
if (userPowerActions.isEmpty() == false)
for (Object o : userPowerActions) {
JSONObject powerActionEntry = (JSONObject) o;
String power = powerActionEntry.getString("power");
JSONArray args = powerActionEntry.getJSONArray("arguments");
int[] arguments = {args.getInt(0), args.getInt(1)};
item_user_power_action.put(power, arguments);
}
JSONArray powerGrantsArray = jsonObject.getJSONArray("item_power_grant");
if (powerGrantsArray.isEmpty() == false) {
for (Object grantArrayEntry : powerGrantsArray) {
JSONObject powerGrantEntry = (JSONObject) grantArrayEntry;
String power_type = powerGrantEntry.getString("power_type");
int power_value = powerGrantEntry.getInt("power_value");
item_power_grant.put(power_type, power_value);
JSONArray skill_granted_array = powerGrantEntry.getJSONArray("power_granted_skills");
for (Object skillGrantEntry : skill_granted_array) {
JSONArray skill_entry = (JSONArray) skillGrantEntry;
String skill_type = skill_entry.getString(0);
int skill_level = skill_entry.getInt(1);
power_granted_skills.put(skill_type, skill_level);
}
}
}
JSONArray item_power_actions = jsonObject.getJSONArray("item_power_action");
if (item_power_actions.isEmpty() == false)
for (Object o : item_power_actions) {
JSONObject powerActionEntry = (JSONObject) o;
String power = powerActionEntry.getString("power_type");
JSONArray power_actions = powerActionEntry.getJSONArray("power_actions");
JSONObject argument_entry = power_actions.getJSONObject(0);
JSONArray power_args = argument_entry.getJSONArray("power_arguments");
int[] power_arguments = {power_args.getInt(0), power_args.getInt(1)};
item_power_action.put(power, power_arguments);
}
JSONArray resource_costs = jsonObject.getJSONArray("item_resource_costs");
if (resource_costs.isEmpty() == false)
for (Object o : resource_costs) {
JSONObject resource_entry = (JSONObject) o;
mbEnums.ResourceType resource_type = mbEnums.ResourceType.valueOf(resource_entry.getString("resource_type").toUpperCase());
int resource_value = resource_entry.getInt("resource_value");
item_resource_cost.put(resource_type, resource_value);
}
// Deed related fields
if (item_type.equals(mbEnums.ItemType.DEED)) {
deed_type = jsonObject.getInt("deed_type");
deed_furniture_id = jsonObject.getInt("deed_furniture_id");
deed_target_id = jsonObject.getInt("deed_target_id");
deed_employment = jsonObject.getInt("deed_employment");
deed_start_rank = jsonObject.getInt("deed_start_rank");
deed_name_lookup = jsonObject.getInt("deed_name_lookup");
deed_indoors = jsonObject.getBoolean("deed_indoors");
deed_is_fortress = jsonObject.getBoolean("deed_is_fortress");
deed_namelookup_val = jsonObject.getFloat("deed_namelookup_val");
deed_custom_city = jsonObject.getBoolean("deed_custom_city");
deed_structure_id = jsonObject.getInt("deed_structure_id");
}
if (item_type.equals(mbEnums.ItemType.RUNE)) {
rune_type = jsonObject.getString("rune_type");
Object subType = jsonObject.get("rune_sub_type");
if (subType instanceof String)
rune_sub_type = (String) subType;
rune_is_standard_character_creation = jsonObject.getBoolean("rune_is_standard_character_creation");
rune_creation_cost = jsonObject.getInt("rune_creation_cost");
rune_rank = jsonObject.getInt("rune_rank");
rune_pracs_per_level = jsonObject.getInt("rune_pracs_per_level");
rune_exp_req_to_level = jsonObject.getFloat("rune_exp_req_to_level");
rune_sex = mbEnums.SexType.valueOf(jsonObject.getString("rune_sex"));
rune_class_icon = jsonObject.getInt("rune_class_icon");
rune_health = jsonObject.getInt("rune_health");
rune_mana = jsonObject.getInt("rune_mana");
rune_stamina = jsonObject.getInt("rune_stamina");
rune_min_damage = jsonObject.getFloat("rune_min_damage");
rune_max_damage = jsonObject.getFloat("rune_max_damage");
rune_attack = jsonObject.getInt("rune_attack");
rune_defense = jsonObject.getInt("rune_defense");
rune_level = jsonObject.getInt("rune_level");
JSONObject rune_speed_json = jsonObject.getJSONObject("rune_speed");
for (String key : rune_speed_json.keySet()) {
mbEnums.MovementType movementType = mbEnums.MovementType.valueOf(key);
float speed = rune_speed_json.getFloat(key);
rune_speed.put(movementType, speed);
}
JSONObject rune_group = jsonObject.getJSONObject("rune_group");
rune_group_type = rune_group.getInt("group_type");
rune_group_is_faction = rune_group.getBoolean("group_is_faction");
rune_group_is_guild = rune_group.getBoolean("group_is_guild");
rune_dsc = jsonObject.getString("rune_dsc");
rune_fx_txt = jsonObject.getString("rune_fx_txt");
long group_tactics_bitvector = jsonObject.getLong("rune_group_tactics");
rune_group_tactics.addAll(mbEnums.fromLong(group_tactics_bitvector, mbEnums.MobBehaviourType.class));
long group_role_bitvector = jsonObject.getLong("rune_group_role_set");
rune_group_role_set.addAll(mbEnums.fromLong(group_role_bitvector, mbEnums.MobBehaviourType.class));
JSONArray enemy_types_json = jsonObject.getJSONArray("rune_enemy_monster_types");
for (Object o : enemy_types_json) {
String enemy = (String) o;
enemy = enemy.replaceAll("-", "");
mbEnums.MonsterType monsterType = mbEnums.MonsterType.valueOf(enemy);
rune_enemy_monster_types.add(monsterType);
}
JSONArray not_enemy_types_json = jsonObject.getJSONArray("rune_not_enemy_monster_types");
for (Object o : not_enemy_types_json) {
String notenemy = (String) o;
notenemy = notenemy.replaceAll("-", "");
mbEnums.MonsterType monsterType = mbEnums.MonsterType.valueOf(notenemy);
rune_not_enemy_monster_types.add(monsterType);
}
JSONArray groupee_types_json = jsonObject.getJSONArray("rune_groupee_monster_types");
for (Object o : groupee_types_json) {
int groupeeId = (int) o;
rune_groupee_monster_types.add(groupeeId);
}
JSONArray helper_types_json = jsonObject.getJSONArray("rune_helper_monster_types");
for (Object o : helper_types_json) {
int helperId = (int) o;
rune_helper_monster_types.add(helperId);
}
rune_renderable = jsonObject.getBoolean("rune_renderable");
rune_natural_power_attack = jsonObject.getInt("rune_natural_power_attack");
if (jsonObject.has("rune_naturalattacks")) {
JSONArray natural_attacks_json = jsonObject.getJSONArray("rune_naturalattacks");
for (Object attackEntry : natural_attacks_json) {
JSONArray attackArray = (JSONArray) attackEntry;
float[] attack = new float[attackArray.length()];
for (int i = 0; i < attackArray.length(); i++)
attack[i] = attackArray.getFloat(i);
rune_natural_attacks.add(attack);
}
}
JSONObject rune_sparse_json = jsonObject.getJSONObject("rune_sparse_data");
for (String sparseType : rune_sparse_json.keySet()) {
Object sparseValue = rune_sparse_json.get(sparseType);
rune_sparse_data.put(sparseType, sparseValue.toString());
}
JSONArray skill_adj_json = (JSONArray) jsonObject.get("rune_skill_adj");
for (Object skillEntry : skill_adj_json) {
JSONObject skill = (JSONObject) skillEntry;
String typeString = skill.getString("skill_type");
JSONArray adjArray = skill.getJSONArray("skill_adjusts");
for (Object adjustList : adjArray) {
JSONArray adjustEntry = (JSONArray) adjustList;
int[] adjust = {adjustEntry.getInt(0), adjustEntry.getInt(1)};
rune_skill_adj.put(typeString, adjust);
}
}
JSONArray attr_adj_json = jsonObject.getJSONArray("rune_attr_adj");
for (Object attributeEntry : attr_adj_json) {
JSONObject attribute = (JSONObject) attributeEntry;
String typeString = attribute.getString("attr_type");
mbEnums.AttributeType attributeType = mbEnums.AttributeType.valueOf(typeString);
int attributeValue = attribute.getInt("attr_value");
rune_attr_adj.put(attributeType, attributeValue);
}
JSONArray max_attr_adj_json = jsonObject.getJSONArray("rune_max_attr_adj");
for (Object attributeEntry : max_attr_adj_json) {
JSONObject attribute = (JSONObject) attributeEntry;
String typeString = attribute.getString("attr_type");
mbEnums.AttributeType attributeType = mbEnums.AttributeType.valueOf(typeString);
int attributeValue = attribute.getInt("attr_value");
rune_max_attr_adj.put(attributeType, attributeValue);
}
JSONArray skill_grant_json = jsonObject.getJSONArray("rune_skill_grant");
if (skill_grant_json.isEmpty() == false)
for (Object runeSkillEntry : skill_grant_json) {
JSONObject skill_granted = (JSONObject) runeSkillEntry;
String typeString = skill_granted.getString("skill_type");
int skill_level = skill_granted.getInt("skill_value");
rune_skill_grant.put(typeString, skill_level);
JSONArray skill_granted_array = skill_granted.getJSONArray("skill_granted_skills");
for (Object skillGrantEntry : skill_granted_array) {
JSONArray skill_entry = (JSONArray) skillGrantEntry;
typeString = skill_entry.getString(0);
skill_level = skill_entry.getInt(1);
skill_granted_skills.put(typeString, skill_level);
}
}
}
} catch (Exception e) {
Logger.error(obj_name + ":" + e);
}
}
}
+5 -1
View File
@@ -127,9 +127,13 @@ public class MobBase extends AbstractGameObject {
for (BootySetEntry equipmentSetEntry : equipList) { for (BootySetEntry equipmentSetEntry : equipList) {
Item item = new Item(equipmentSetEntry.templateID); Item item = new Item(equipmentSetEntry.templateID);
if (item.template.getItemEqSlotsOr().isEmpty())
continue;
item.objectUUID = ItemManager.lastNegativeID.decrementAndGet(); item.objectUUID = ItemManager.lastNegativeID.decrementAndGet();
item.drop_chance = equipmentSetEntry.dropChance; item.drop_chance = equipmentSetEntry.dropChance;
item.equipSlot = item.template.item_eq_slots_or.iterator().next(); item.equipSlot = item.template.getItemEqSlotsOr().iterator().next();
equip.put(item.equipSlot, item); equip.put(item.equipSlot, item);
} }
+7 -6
View File
@@ -15,6 +15,7 @@ import engine.gameManager.PowersManager;
import engine.mbEnums; import engine.mbEnums;
import engine.mbEnums.ItemType; import engine.mbEnums.ItemType;
import engine.mbEnums.OwnerType; import engine.mbEnums.OwnerType;
import engine.parsers.objects.CObjectTemplate;
import engine.powers.poweractions.AbstractPowerAction; import engine.powers.poweractions.AbstractPowerAction;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@@ -30,22 +31,22 @@ public final class MobLoot extends Item {
private String prefix = ""; private String prefix = "";
private String suffix = ""; private String suffix = "";
public MobLoot(AbstractCharacter mob, ItemTemplate template, boolean noSteal) { public MobLoot(AbstractCharacter mob, CObjectTemplate template, boolean noSteal) {
this(mob, template, 0, noSteal); this(mob, template, 0, noSteal);
} }
public MobLoot(AbstractCharacter mob, int qtyOfGold) { public MobLoot(AbstractCharacter mob, int qtyOfGold) {
this(mob, ItemTemplate.templates.get(mbEnums.ResourceType.GOLD.templateID), qtyOfGold, false); this(mob, CObjectTemplate.lookup(mbEnums.ResourceType.GOLD.templateID), qtyOfGold, false);
} }
public MobLoot(AbstractCharacter mob, ItemTemplate template, int quantity, boolean noSteal) { public MobLoot(AbstractCharacter mob, CObjectTemplate template, int quantity, boolean noSteal) {
super(template.template_id); super(template.getTemplateId());
this.ownerType = OwnerType.Mob; this.ownerType = OwnerType.Mob;
this.ownerID = mob.getObjectUUID(); this.ownerID = mob.getObjectUUID();
this.objectUUID = generateId(); this.objectUUID = generateId();
if (quantity == 0 && template.item_type == ItemType.RESOURCE) if (quantity == 0 && template.getItemType() == ItemType.RESOURCE)
quantity = 1; quantity = 1;
if (quantity > 0) if (quantity > 0)
@@ -105,7 +106,7 @@ public final class MobLoot extends Item {
if (isDeleted) if (isDeleted)
return null; return null;
if (this.template.item_type.equals(ItemType.GOLD)) if (this.template.getItemType().equals(ItemType.GOLD))
return null; return null;
Item item = this; Item item = this;
+6 -5
View File
@@ -23,6 +23,7 @@ import engine.net.ByteBufferWriter;
import engine.net.Dispatch; import engine.net.Dispatch;
import engine.net.client.msg.PetMsg; import engine.net.client.msg.PetMsg;
import engine.net.client.msg.PlaceAssetMsg; import engine.net.client.msg.PlaceAssetMsg;
import engine.parsers.objects.CObjectTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@@ -961,15 +962,15 @@ public class NPC extends AbstractCharacter {
maxSkill = 110; maxSkill = 110;
break; break;
} }
ItemTemplate itemTemplate; CObjectTemplate itemTemplate;
int skillRequired = 0; int skillRequired = 0;
for (Integer itemID : fullItemList) { for (Integer itemID : fullItemList) {
itemTemplate = ItemTemplate.templates.get(itemID); itemTemplate = CObjectTemplate.lookup(itemID);
if (itemTemplate.item_skill_required.values().iterator().hasNext()) if (itemTemplate.getItemSkillReq().values().iterator().hasNext())
skillRequired = itemTemplate.item_skill_required.values().iterator().next(); skillRequired = itemTemplate.getItemSkillReq().values().iterator().next();
boolean exclude = skillRequired == 0 && ItemTemplate.templates.get(itemID).item_type.equals(ItemType.WEAPON); boolean exclude = skillRequired == 0 && CObjectTemplate.lookup(itemID).getItemType().equals(ItemType.WEAPON);
if (skillRequired <= maxSkill && !exclude) if (skillRequired <= maxSkill && !exclude)
filteredItemList.add(itemID); filteredItemList.add(itemID);
} }
+12 -11
View File
@@ -32,6 +32,7 @@ import engine.net.Dispatch;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.msg.*; import engine.net.client.msg.*;
import engine.net.client.msg.login.CommitNewCharacterMsg; import engine.net.client.msg.login.CommitNewCharacterMsg;
import engine.parsers.objects.CObjectTemplate;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import engine.server.login.LoginServer; import engine.server.login.LoginServer;
@@ -1353,10 +1354,10 @@ public class PlayerCharacter extends AbstractCharacter {
public static float getDexPenalty(Item armor) { public static float getDexPenalty(Item armor) {
if (armor == null) if (armor == null)
return 0f; return 0f;
ItemTemplate ab = armor.template; CObjectTemplate ab = armor.template;
if (ab == null) if (ab == null)
return 0f; return 0f;
return ab.item_bulk_factor; return engine.parsers.objects.ItemTemplate._items.get(armor.templateID).item_bulk_factor;
} }
public static void InitializeSkillsOnLoad(PlayerCharacter pc) { public static void InitializeSkillsOnLoad(PlayerCharacter pc) {
@@ -2816,15 +2817,15 @@ public class PlayerCharacter extends AbstractCharacter {
if (item == null) if (item == null)
return false; return false;
ItemTemplate ib = item.template; CObjectTemplate ib = item.template;
if (ib != null) { if (ib != null) {
if ((item.template.item_type.equals(ItemType.WEAPON)) if ((item.template.getItemType().equals(ItemType.WEAPON))
&& (item.template.item_skill_used.equals(type) || ib.item_skill_mastery_used.equals(type))) && (item.template.getItemSkillUsed().equals(type) || ib.getItemSkillMasteryUsed().equals(type)))
return true; return true;
return (item.template.item_type.equals(ItemType.ARMOR)) return (item.template.getItemType().equals(ItemType.ARMOR))
&& (item.template.item_skill_used.equals(type)); && (item.template.getItemSkillUsed().equals(type));
} }
return false; return false;
@@ -3768,8 +3769,8 @@ public class PlayerCharacter extends AbstractCharacter {
ConcurrentHashMap<EquipSlotType, Item> equipped = this.charItemManager.getEquipped(); ConcurrentHashMap<EquipSlotType, Item> equipped = this.charItemManager.getEquipped();
Item off = equipped.get(EquipSlotType.LHELD); Item off = equipped.get(EquipSlotType.LHELD);
Item main = equipped.get(EquipSlotType.RHELD); Item main = equipped.get(EquipSlotType.RHELD);
ItemTemplate wbMain = null; CObjectTemplate wbMain = null;
ItemTemplate wbOff = null; CObjectTemplate wbOff = null;
if (main != null) if (main != null)
wbMain = main.template; wbMain = main.template;
if (off != null) if (off != null)
@@ -3791,8 +3792,8 @@ public class PlayerCharacter extends AbstractCharacter {
this.bonuses.setBool(ModType.Parry, SourceType.None, false); this.bonuses.setBool(ModType.Parry, SourceType.None, false);
if ((this.baseClass != null && this.baseClass.getObjectUUID() == 2500) if ((this.baseClass != null && this.baseClass.getObjectUUID() == 2500)
|| (this.promotionClass != null && this.promotionClass.getObjectUUID() == 2520)) || (this.promotionClass != null && this.promotionClass.getObjectUUID() == 2520))
if (wbMain == null || wbMain.item_weapon_max_range < MBServerStatics.RANGED_WEAPON_RANGE) if (wbMain == null || engine.parsers.objects.ItemTemplate.getWeapon(wbMain.getTemplateId()).weapon_max_range < MBServerStatics.RANGED_WEAPON_RANGE)
if (wbOff == null || wbOff.item_weapon_max_range < MBServerStatics.RANGED_WEAPON_RANGE) if (wbOff == null || engine.parsers.objects.ItemTemplate.getWeapon(wbOff.getTemplateId()).weapon_max_range < MBServerStatics.RANGED_WEAPON_RANGE)
this.bonuses.setBool(ModType.Parry, SourceType.None, true); this.bonuses.setBool(ModType.Parry, SourceType.None, true);
} }
+78
View File
@@ -10,8 +10,13 @@
package engine.objects; package engine.objects;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.mbEnums;
import engine.mbEnums.GameObjectType; import engine.mbEnums.GameObjectType;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.parsers.cache.CObjectIndex;
import engine.parsers.objects.RuneTemplate;
import engine.util.Hasher;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@@ -103,6 +108,79 @@ public class PromotionClass extends AbstractGameObject {
} }
/**
* Rune Template Constructor
*/
public PromotionClass(RuneTemplate rune) {
super(rune.template_id);
this.name = rune.obj_name;
this.description = rune.rune_dsc;
this.token = Hasher.SBStringHash(rune.rune_sub_type);
this.healthMod = rune.rune_health;
this.manaMod = rune.rune_mana;
this.staminaMod = rune.rune_stamina;
this.allowedRunes = getAllowedRuneTokens(rune);
this.skillsGranted = DbManager.SkillReqQueries.GET_REQS_FOR_RUNE(this.getObjectUUID());
this.powersGranted = PowerReq.getPowerReqsForRune(this.getObjectUUID());
this.effectsGranted = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE(this.getObjectUUID());
this.effectsGrantedFighter = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2500);
this.effectsGrantedHealer = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2501);
this.effectsGrantedRogue = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2502);
this.effectsGrantedMage = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2503);
this.effectsList = DbManager.MobBaseQueries.GET_RUNEBASE_EFFECTS(this.getObjectUUID());
}
// Promotions are the CLASS runes that require a base class; this skips the creation classes and Pet 2522.
public static boolean isPromotionRune(RuneTemplate rune) {
return rune.rune_type == mbEnums.RuneType.CLASS && !rune.rune_is_standard_character_creation
&& !rune.item_class_req.isEmpty();
}
// Race and base class tokens are SBStringHash(rune_sub_type) of the runes named in the req lists.
// Every promotion rune's lists are whitelists (restrict false).
private static ArrayList<Integer> getAllowedRuneTokens(RuneTemplate rune) {
ArrayList<Integer> tokens = new ArrayList<>();
Integer classRuneId;
int token;
for (mbEnums.MonsterType race : rune.item_race_req)
for (int raceRuneId : CObjectIndex.getRaceRuneIds(race)) {
token = Hasher.SBStringHash(RuneTemplate._runes.get(raceRuneId).rune_sub_type);
if (!tokens.contains(token))
tokens.add(token);
}
for (mbEnums.ClassType classType : rune.item_class_req) {
classRuneId = CObjectIndex.getClassRuneId(classType);
if (classRuneId != null)
tokens.add(Hasher.SBStringHash(RuneTemplate._runes.get(classRuneId).rune_sub_type));
}
return tokens;
}
public static void LoadAllPromotions() {
int loadedCount = 0;
for (RuneTemplate rune : RuneTemplate._runes.values()) {
if (!isPromotionRune(rune))
continue;
DbManager.addToCache(new PromotionClass(rune));
loadedCount++;
}
Logger.info("Loaded " + loadedCount + " promotion classes from runes");
// The CSR/admin rows 2901+ have no promotion rune; the DB loader skips ids already cached
DbManager.PromotionQueries.GET_ALL_PROMOTIONS();
}
public static void serializeForClientMsg(PromotionClass promotionClass, ByteBufferWriter writer) { public static void serializeForClientMsg(PromotionClass promotionClass, ByteBufferWriter writer) {
writer.putInt(3); // For BaseClass writer.putInt(3); // For BaseClass
writer.putInt(0); // Pad writer.putInt(0); // Pad
+106 -1
View File
@@ -13,7 +13,11 @@ import engine.gameManager.DbManager;
import engine.mbEnums; import engine.mbEnums;
import engine.mbEnums.RaceType; import engine.mbEnums.RaceType;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.parsers.cache.CacheParserUtil;
import engine.parsers.objects.RuneTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import engine.util.Hasher;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@@ -27,6 +31,9 @@ public class Race {
private static ConcurrentHashMap<Integer, Race> _raceByID = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); private static ConcurrentHashMap<Integer, Race> _raceByID = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
// Creation points before the race rune's rune_creation_cost is taken off
private static final int STARTING_POINT_POOL = 30;
private final String name; private final String name;
private final String description; private final String description;
private final int raceRuneID; private final int raceRuneID;
@@ -107,8 +114,106 @@ public class Race {
} }
/**
* Rune Template Constructor
* minHeight and strHeightMod are server-only and come from the static_rune_race row.
*/
public Race(RuneTemplate rune, Race dbRace) {
this.raceRuneID = rune.template_id;
this.raceType = mbEnums.RaceType.getRaceTypebyRuneID(raceRuneID);
this.name = rune.obj_name;
this.description = rune.rune_dsc;
this.strStart = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Strength, 0).shortValue();
this.strMin = 0;
this.strMax = rune.rune_max_attr_adj.getOrDefault(mbEnums.AttributeType.Strength, 0).shortValue();
this.dexStart = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Dexterity, 0).shortValue();
this.dexMin = 0;
this.dexMax = rune.rune_max_attr_adj.getOrDefault(mbEnums.AttributeType.Dexterity, 0).shortValue();
this.conStart = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Constitution, 0).shortValue();
this.conMin = 0;
this.conMax = rune.rune_max_attr_adj.getOrDefault(mbEnums.AttributeType.Constitution, 0).shortValue();
this.intStart = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Intelligence, 0).shortValue();
this.intMin = 0;
this.intMax = rune.rune_max_attr_adj.getOrDefault(mbEnums.AttributeType.Intelligence, 0).shortValue();
this.spiStart = rune.rune_attr_adj.getOrDefault(mbEnums.AttributeType.Spirit, 0).shortValue();
this.spiMin = 0;
this.spiMax = rune.rune_max_attr_adj.getOrDefault(mbEnums.AttributeType.Spirit, 0).shortValue();
this.token = Hasher.SBStringHash(rune.rune_sub_type);
this.healthBonus = (short) rune.rune_health;
this.manaBonus = (short) rune.rune_mana;
this.staminaBonus = (short) rune.rune_stamina;
this.startingPoints = (byte) (STARTING_POINT_POOL - rune.rune_creation_cost);
this.minHeight = dbRace.minHeight;
this.strHeightMod = dbRace.strHeightMod;
this.hairStyles = new HashSet<>(rune.rune_hair);
this.beardStyles = new HashSet<>(rune.rune_beard);
this.skinColors = DbManager.RaceQueries.SKIN_COLOR_FOR_RACE(raceRuneID);
this.beardColors = DbManager.RaceQueries.BEARD_COLORS_FOR_RACE(raceRuneID);
this.hairColors = DbManager.RaceQueries.HAIR_COLORS_FOR_RACE(raceRuneID);
this.baseClasses = getBaseClassesForRace(rune);
this.skillsGranted = DbManager.SkillReqQueries.GET_REQS_FOR_RUNE(raceRuneID);
this.powersGranted = PowerReq.getPowerReqsForRune(raceRuneID);
this.effectsList = DbManager.MobBaseQueries.GET_RUNEBASE_EFFECTS(this.raceRuneID);
// Races without hair styles (Aracoix, Shade) select style 0, which creation validates
if (this.hairStyles.isEmpty())
this.hairStyles.add(0);
}
// Base classes are the creation class runes whose item_race_req names this race's sub type.
// Every creation class rune's race list is a whitelist (restrict false).
private static ArrayList<BaseClass> getBaseClassesForRace(RuneTemplate rune) {
ArrayList<BaseClass> baseClasses = new ArrayList<>();
mbEnums.MonsterType monsterType;
BaseClass baseClass;
monsterType = CacheParserUtil.readEnum(mbEnums.MonsterType.class, rune.rune_sub_type, rune.template_id, "rune_sub_type");
for (RuneTemplate classRune : RuneTemplate._runes.values()) {
if (classRune.rune_type != mbEnums.RuneType.CLASS || !classRune.rune_is_standard_character_creation)
continue;
if (!classRune.item_race_req.contains(monsterType))
continue;
baseClass = DbManager.BaseClassQueries.GET_BASE_CLASS(classRune.template_id);
if (baseClass != null)
baseClasses.add(baseClass);
}
return baseClasses;
}
// Iterates the static_rune_race rows: no rune field separates 2018-2021 from the mob race runes,
// and each row still holds the server-only heights.
public static void loadAllRaces() { public static void loadAllRaces() {
Race._raceByID = DbManager.RaceQueries.LOAD_ALL_RACES();
ConcurrentHashMap<Integer, Race> dbRaces;
ConcurrentHashMap<Integer, Race> races;
RuneTemplate rune;
dbRaces = DbManager.RaceQueries.LOAD_ALL_RACES();
races = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
for (Race dbRace : dbRaces.values()) {
rune = RuneTemplate._runes.get(dbRace.raceRuneID);
if (rune == null || rune.rune_type != mbEnums.RuneType.RACE) {
Logger.warn("Race " + dbRace.raceRuneID + " has no race rune; loaded from static_rune_race");
races.put(dbRace.raceRuneID, dbRace);
continue;
}
races.put(dbRace.raceRuneID, new Race(rune, dbRace));
}
Race._raceByID = races;
Logger.info("Loaded " + races.size() + " races from runes");
} }
public static Race getRace(int id) { public static Race getRace(int id) {
+8 -4
View File
@@ -19,6 +19,7 @@ import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.EnumMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@@ -159,13 +160,16 @@ public class Resists {
private static float[] getArmorResists(Item armor, float[] phys) { private static float[] getArmorResists(Item armor, float[] phys) {
EnumMap<mbEnums.DamageType, Float> armorResists;
if (armor == null) if (armor == null)
return phys; return phys;
if (armor.template.item_type.equals(mbEnums.ItemType.ARMOR)) { if (armor.template.getItemType().equals(mbEnums.ItemType.ARMOR)) {
phys[0] += armor.template.combat_attack_resist.get("SLASHING"); armorResists = armor.template.getCombatAttackResist();
phys[1] += armor.template.combat_attack_resist.get("CRUSHING"); phys[0] += armorResists.getOrDefault(mbEnums.DamageType.SLASHING, 0f);
phys[2] += armor.template.combat_attack_resist.get("PIERCING"); phys[1] += armorResists.getOrDefault(mbEnums.DamageType.CRUSHING, 0f);
phys[2] += armorResists.getOrDefault(mbEnums.DamageType.PIERCING, 0f);
} }
return phys; return phys;
+2 -2
View File
@@ -256,13 +256,13 @@ public class Shrine extends AbstractWorldObject implements Comparable<Shrine> {
if (!boonOwner.charItemManager.doesCharOwnThisItem(boonItem.getObjectUUID())) if (!boonOwner.charItemManager.doesCharOwnThisItem(boonItem.getObjectUUID()))
return false; return false;
for (ShrineType boonShrineType : boonItem.template.item_offering_info.keySet()) { for (ShrineType boonShrineType : boonItem.template.getItemOfferingInfo().keySet()) {
if (boonShrineType != shrineType) if (boonShrineType != shrineType)
continue; continue;
//Same Shrine Type, add favors and stop loop. //Same Shrine Type, add favors and stop loop.
int amount = boonItem.template.item_offering_info.get(boonShrineType) * boonItem.getNumOfItems(); int amount = boonItem.template.getItemOfferingInfo().get(boonShrineType) * boonItem.getNumOfItems();
int oldAmount = this.favors; int oldAmount = this.favors;
if (!DbManager.ShrineQueries.updateFavors(this, this.favors + amount, oldAmount)) { if (!DbManager.ShrineQueries.updateFavors(this, this.favors + amount, oldAmount)) {
+7 -6
View File
@@ -17,6 +17,7 @@ import engine.mbEnums;
import engine.net.Dispatch; import engine.net.Dispatch;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.msg.*; import engine.net.client.msg.*;
import engine.parsers.objects.CObjectTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.json.JSONArray; import org.json.JSONArray;
@@ -304,10 +305,10 @@ public class Warehouse {
return false; return false;
} }
if (resource.template.item_type.equals(mbEnums.ItemType.GOLD)) if (resource.template.getItemType().equals(mbEnums.ItemType.GOLD))
resourceType = mbEnums.ResourceType.GOLD; resourceType = mbEnums.ResourceType.GOLD;
else else
resourceType = mbEnums.ResourceType.valueOf(ItemTemplate.templates.get(resource.templateID).item_base_name.toUpperCase()); resourceType = mbEnums.ResourceType.valueOf(CObjectTemplate.lookup(resource.templateID).getItemBaseName().toUpperCase());
if (transaction) if (transaction)
AddTransactionToWarehouse(warehouse, playerCharacter.getObjectType(), playerCharacter.getObjectUUID(), mbEnums.TransactionType.DEPOSIT, resourceType, amount); AddTransactionToWarehouse(warehouse, playerCharacter.getObjectType(), playerCharacter.getObjectUUID(), mbEnums.TransactionType.DEPOSIT, resourceType, amount);
@@ -418,7 +419,7 @@ public class Warehouse {
if (playerCharacter == null) if (playerCharacter == null)
return false; return false;
ItemTemplate template = ItemTemplate.templates.get(resourceType.templateID); CObjectTemplate template = CObjectTemplate.lookup(resourceType.templateID);
if (warehouse.resources.get(resourceType) == null) if (warehouse.resources.get(resourceType) == null)
return false; return false;
@@ -432,7 +433,7 @@ public class Warehouse {
return false; return false;
if (addToInventory) if (addToInventory)
if (!itemMan.hasRoomInventory(template.item_wt)) { if (!itemMan.hasRoomInventory(template.getItemWt())) {
ChatManager.chatSystemInfo(playerCharacter, "You can not carry any more of that item."); ChatManager.chatSystemInfo(playerCharacter, "You can not carry any more of that item.");
return false; return false;
} }
@@ -501,7 +502,7 @@ public class Warehouse {
if (playerCharacter == null) if (playerCharacter == null)
return false; return false;
ItemTemplate template = ItemTemplate.templates.get(resourceType.templateID); CObjectTemplate template = CObjectTemplate.lookup(resourceType.templateID);
if (template == null) if (template == null)
return false; return false;
@@ -517,7 +518,7 @@ public class Warehouse {
if (itemMan == null) if (itemMan == null)
return false; return false;
if (!itemMan.hasRoomInventory(template.item_wt)) { if (!itemMan.hasRoomInventory(template.getItemWt())) {
ChatManager.chatSystemInfo(playerCharacter, "You can not carry any more of that item."); ChatManager.chatSystemInfo(playerCharacter, "You can not carry any more of that item.");
return false; return false;
} }
+6
View File
@@ -97,8 +97,14 @@ public class DeedParser {
deed.item_type = CacheParserUtil.readEnum(mbEnums.ItemType.class, deedJson.getString("item_type"), templateId, "item_type"); deed.item_type = CacheParserUtil.readEnum(mbEnums.ItemType.class, deedJson.getString("item_type"), templateId, "item_type");
deed.item_eq_slots_value = deedJson.getInt("item_eq_slots_value"); deed.item_eq_slots_value = deedJson.getInt("item_eq_slots_value");
deed.item_eq_slots_type = deedJson.getBoolean("item_eq_slots_type"); deed.item_eq_slots_type = deedJson.getBoolean("item_eq_slots_type");
// The exporter writes ["NONE"] for an empty slot mask
deed.item_eq_slots_or.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, deedJson.getJSONArray("item_eq_slots_or"), templateId, "item_eq_slots_or")); deed.item_eq_slots_or.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, deedJson.getJSONArray("item_eq_slots_or"), templateId, "item_eq_slots_or"));
deed.item_eq_slots_or.remove(mbEnums.EquipSlotType.NONE);
deed.item_eq_slots_and.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, deedJson.getJSONArray("item_eq_slots_and"), templateId, "item_eq_slots_and")); deed.item_eq_slots_and.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, deedJson.getJSONArray("item_eq_slots_and"), templateId, "item_eq_slots_and"));
deed.item_eq_slots_and.remove(mbEnums.EquipSlotType.NONE);
deed.item_takeable = deedJson.getBoolean("item_takeable"); deed.item_takeable = deedJson.getBoolean("item_takeable");
deed.item_value = deedJson.getInt("item_value"); deed.item_value = deedJson.getInt("item_value");
deed.item_wt = deedJson.getInt("item_wt"); deed.item_wt = deedJson.getInt("item_wt");
-34
View File
@@ -9,16 +9,10 @@
package engine.parsers.cache; package engine.parsers.cache;
import engine.gameManager.ConfigManager; import engine.gameManager.ConfigManager;
import engine.gameManager.DbManager;
import engine.mbEnums;
import engine.objects.AbstractGameObject;
import engine.objects.BaseClass;
import engine.parsers.objects.RuneTemplate;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer; import java.util.function.Consumer;
// Dev-only check that compares DB-built objects with the cache JSON before a loader is switched. // Dev-only check that compares DB-built objects with the cache JSON before a loader is switched.
@@ -34,10 +28,6 @@ public class ParityCheck {
private int differenceCount = 0; private int differenceCount = 0;
private int missingCount = 0; private int missingCount = 0;
static {
register("static_rune_baseclass", ParityCheck::compareBaseClasses);
}
private ParityCheck(String table) { private ParityCheck(String table) {
this.table = table; this.table = table;
} }
@@ -91,28 +81,4 @@ public class ParityCheck {
differenceCount++; differenceCount++;
Logger.warn("Parity: " + table + "/" + id + "/" + field + ": db=" + dbValue + " json=" + jsonValue); Logger.warn("Parity: " + table + "/" + id + "/" + field + ": db=" + dbValue + " json=" + jsonValue);
} }
private static void compareBaseClasses(ParityCheck check) {
ConcurrentHashMap<Integer, AbstractGameObject> cache;
BaseClass baseClass;
RuneTemplate rune;
cache = DbManager.getMap(mbEnums.GameObjectType.BaseClass);
if (cache == null) {
Logger.warn("Parity: static_rune_baseclass: no BaseClass objects loaded");
return;
}
for (AbstractGameObject cached : cache.values()) {
baseClass = (BaseClass) cached;
rune = RuneTemplate._runes.get(baseClass.getObjectUUID());
if (!check.compareRow(baseClass.getObjectUUID(), rune))
continue;
check.compareField(baseClass.getObjectUUID(), "name", baseClass.getName(), rune.obj_name);
}
}
} }
+6
View File
@@ -112,8 +112,14 @@ public class RuneParser {
rune.item_type = CacheParserUtil.readEnum(mbEnums.ItemType.class, runeJson.getString("item_type"), templateId, "item_type"); rune.item_type = CacheParserUtil.readEnum(mbEnums.ItemType.class, runeJson.getString("item_type"), templateId, "item_type");
rune.item_eq_slots_value = runeJson.getInt("item_eq_slots_value"); rune.item_eq_slots_value = runeJson.getInt("item_eq_slots_value");
rune.item_eq_slots_type = runeJson.getBoolean("item_eq_slots_type"); rune.item_eq_slots_type = runeJson.getBoolean("item_eq_slots_type");
// The exporter writes ["NONE"] for an empty slot mask
rune.item_eq_slots_or.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, runeJson.getJSONArray("item_eq_slots_or"), templateId, "item_eq_slots_or")); rune.item_eq_slots_or.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, runeJson.getJSONArray("item_eq_slots_or"), templateId, "item_eq_slots_or"));
rune.item_eq_slots_or.remove(mbEnums.EquipSlotType.NONE);
rune.item_eq_slots_and.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, runeJson.getJSONArray("item_eq_slots_and"), templateId, "item_eq_slots_and")); rune.item_eq_slots_and.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, runeJson.getJSONArray("item_eq_slots_and"), templateId, "item_eq_slots_and"));
rune.item_eq_slots_and.remove(mbEnums.EquipSlotType.NONE);
rune.item_takeable = runeJson.getBoolean("item_takeable"); rune.item_takeable = runeJson.getBoolean("item_takeable");
rune.item_value = runeJson.getInt("item_value"); rune.item_value = runeJson.getInt("item_value");
rune.item_wt = runeJson.getInt("item_wt"); rune.item_wt = runeJson.getInt("item_wt");
@@ -8,8 +8,92 @@
package engine.parsers.objects; package engine.parsers.objects;
import engine.math.Vector3fImmutable;
import engine.mbEnums;
import engine.parsers.cache.CObjectIndex;
import org.json.JSONArray;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
// Common type for ITEM, DEED and RUNE cache templates, which share one id space. // Common type for ITEM, DEED and RUNE cache templates, which share one id space.
// Shared obj_/combat_/item_ getters arrive with JSON-Refactor-Plan Task 1.1. // Getters cover only the obj_/combat_/item_ fields all three define (JSON-Refactor-Plan D1).
// Returned collections are the template's own; never modify them.
public interface CObjectTemplate { public interface CObjectTemplate {
static CObjectTemplate lookup(int templateId) {
return CObjectIndex.lookup(templateId);
}
int getTemplateId();
String getObjName();
boolean getObjPickable();
float getObjGravity();
float getObjCullDistance();
Vector3fImmutable getObjScale();
int getObjRenderObject();
boolean getObjDoubleFusion();
Vector3fImmutable getObjForwardVector();
String getObjTrackingName();
float getObjMaxTrackingDistance();
int getObjIcon();
float getObjGravityF();
LinkedHashMap<String, Integer> getObjSoundEvents();
JSONArray getObjArcHardpointList();
HashMap<String, String> getObjSparseData();
int getObjRenderObjectLowDetail();
Vector3fImmutable getObjDefaultAlignment();
String getObjSoundTable();
float getCombatHealthCurrent();
float getCombatHealthFull();
EnumMap<mbEnums.DamageType, Float> getCombatAttackResist();
JSONArray getCombatPowers();
mbEnums.ItemType getItemType();
int getItemEqSlotsValue();
boolean getItemEqSlotsType();
EnumSet<mbEnums.EquipSlotType> getItemEqSlotsOr();
EnumSet<mbEnums.EquipSlotType> getItemEqSlotsAnd();
boolean getItemTakeable();
int getItemValue();
int getItemWt();
float getItemPassiveDefenseMod();
String getItemBaseName();
String getItemDsc();
int getItemRenderObjectFemale();
float getItemHealthFull();
String getItemSkillUsed();
String getItemSkillMasteryUsed();
int getItemParryAnimId();
EnumMap<mbEnums.ShrineType, Integer> getItemOfferingInfo();
EnumSet<mbEnums.ItemFlags> getItemFlags();
EnumSet<mbEnums.ItemUseFlags> getItemUseFlags();
int getItemPostItemId();
int getItemInitialCharges();
int getItemBookArcana();
LinkedHashMap<String, Integer> getItemSkillReq();
boolean getItemRaceReqRestrict();
EnumSet<mbEnums.MonsterType> getItemRaceReq();
boolean getItemClassReqRestrict();
EnumSet<mbEnums.ClassType> getItemClassReq();
boolean getItemDiscReqRestrict();
EnumSet<mbEnums.DisciplineType> getItemDiscReq();
EnumMap<mbEnums.AttributeType, Integer> getItemAttrReq();
int getItemLevelReq();
int getItemRankReq();
mbEnums.SexType getItemSexReq();
ArrayList<UserPowerAction> getItemUserPowerAction();
ArrayList<PowerGrant> getItemPowerGrant();
LinkedHashMap<String, ArrayList<int[]>> getItemPowerAction();
boolean getItemSheathable();
boolean getItemHasStub();
EnumMap<mbEnums.ShrineType, Integer> getItemOfferingAdjustments();
EnumMap<mbEnums.ResourceType, Integer> getItemResourceCosts();
int getItemBaneRank();
boolean getItemIgnoreSavedActions();
} }
@@ -119,4 +119,329 @@ public class DeedTemplate implements CObjectTemplate {
public float deed_namelookup_val; public float deed_namelookup_val;
public boolean deed_custom_city; public boolean deed_custom_city;
public int deed_structure_id; public int deed_structure_id;
@Override
public int getTemplateId() {
return template_id;
}
@Override
public String getObjName() {
return obj_name;
}
@Override
public boolean getObjPickable() {
return obj_pickable;
}
@Override
public float getObjGravity() {
return obj_gravity;
}
@Override
public float getObjCullDistance() {
return obj_cull_distance;
}
@Override
public Vector3fImmutable getObjScale() {
return obj_scale;
}
@Override
public int getObjRenderObject() {
return obj_render_object;
}
@Override
public boolean getObjDoubleFusion() {
return obj_double_fusion;
}
@Override
public Vector3fImmutable getObjForwardVector() {
return obj_forward_vector;
}
@Override
public String getObjTrackingName() {
return obj_tracking_name;
}
@Override
public float getObjMaxTrackingDistance() {
return obj_max_tracking_distance;
}
@Override
public int getObjIcon() {
return obj_icon;
}
@Override
public float getObjGravityF() {
return obj_gravity_f;
}
@Override
public LinkedHashMap<String, Integer> getObjSoundEvents() {
return obj_sound_events;
}
@Override
public JSONArray getObjArcHardpointList() {
return obj_arc_hardpoint_list;
}
@Override
public HashMap<String, String> getObjSparseData() {
return obj_sparse_data;
}
@Override
public int getObjRenderObjectLowDetail() {
return obj_render_object_low_detail;
}
@Override
public Vector3fImmutable getObjDefaultAlignment() {
return obj_default_alignment;
}
@Override
public String getObjSoundTable() {
return obj_sound_table;
}
@Override
public float getCombatHealthCurrent() {
return combat_health_current;
}
@Override
public float getCombatHealthFull() {
return combat_health_full;
}
@Override
public EnumMap<mbEnums.DamageType, Float> getCombatAttackResist() {
return combat_attack_resist;
}
@Override
public JSONArray getCombatPowers() {
return combat_powers;
}
@Override
public mbEnums.ItemType getItemType() {
return item_type;
}
@Override
public int getItemEqSlotsValue() {
return item_eq_slots_value;
}
@Override
public boolean getItemEqSlotsType() {
return item_eq_slots_type;
}
@Override
public EnumSet<mbEnums.EquipSlotType> getItemEqSlotsOr() {
return item_eq_slots_or;
}
@Override
public EnumSet<mbEnums.EquipSlotType> getItemEqSlotsAnd() {
return item_eq_slots_and;
}
@Override
public boolean getItemTakeable() {
return item_takeable;
}
@Override
public int getItemValue() {
return item_value;
}
@Override
public int getItemWt() {
return item_wt;
}
@Override
public float getItemPassiveDefenseMod() {
return item_passive_defense_mod;
}
@Override
public String getItemBaseName() {
return item_base_name;
}
@Override
public String getItemDsc() {
return item_dsc;
}
@Override
public int getItemRenderObjectFemale() {
return item_render_object_female;
}
@Override
public float getItemHealthFull() {
return item_health_full;
}
@Override
public String getItemSkillUsed() {
return item_skill_used;
}
@Override
public String getItemSkillMasteryUsed() {
return item_skill_mastery_used;
}
@Override
public int getItemParryAnimId() {
return item_parry_anim_id;
}
@Override
public EnumMap<mbEnums.ShrineType, Integer> getItemOfferingInfo() {
return item_offering_info;
}
@Override
public EnumSet<mbEnums.ItemFlags> getItemFlags() {
return item_flags;
}
@Override
public EnumSet<mbEnums.ItemUseFlags> getItemUseFlags() {
return item_use_flags;
}
@Override
public int getItemPostItemId() {
return item_post_item_id;
}
@Override
public int getItemInitialCharges() {
return item_initial_charges;
}
@Override
public int getItemBookArcana() {
return item_book_arcana;
}
@Override
public LinkedHashMap<String, Integer> getItemSkillReq() {
return item_skill_req;
}
@Override
public boolean getItemRaceReqRestrict() {
return item_race_req_restrict;
}
@Override
public EnumSet<mbEnums.MonsterType> getItemRaceReq() {
return item_race_req;
}
@Override
public boolean getItemClassReqRestrict() {
return item_class_req_restrict;
}
@Override
public EnumSet<mbEnums.ClassType> getItemClassReq() {
return item_class_req;
}
@Override
public boolean getItemDiscReqRestrict() {
return item_disc_req_restrict;
}
@Override
public EnumSet<mbEnums.DisciplineType> getItemDiscReq() {
return item_disc_req;
}
@Override
public EnumMap<mbEnums.AttributeType, Integer> getItemAttrReq() {
return item_attr_req;
}
@Override
public int getItemLevelReq() {
return item_level_req;
}
@Override
public int getItemRankReq() {
return item_rank_req;
}
@Override
public mbEnums.SexType getItemSexReq() {
return item_sex_req;
}
@Override
public ArrayList<UserPowerAction> getItemUserPowerAction() {
return item_user_power_action;
}
@Override
public ArrayList<PowerGrant> getItemPowerGrant() {
return item_power_grant;
}
@Override
public LinkedHashMap<String, ArrayList<int[]>> getItemPowerAction() {
return item_power_action;
}
@Override
public boolean getItemSheathable() {
return item_sheathable;
}
@Override
public boolean getItemHasStub() {
return item_has_stub;
}
@Override
public EnumMap<mbEnums.ShrineType, Integer> getItemOfferingAdjustments() {
return item_offering_adjustments;
}
@Override
public EnumMap<mbEnums.ResourceType, Integer> getItemResourceCosts() {
return item_resource_costs;
}
@Override
public int getItemBaneRank() {
return item_bane_rank;
}
@Override
public boolean getItemIgnoreSavedActions() {
return item_ignore_saved_actions;
}
} }
+340 -4
View File
@@ -25,14 +25,15 @@ import java.util.LinkedHashMap;
// Values are kept as the client defines them: no req/res splitting, // Values are kept as the client defines them: no req/res splitting,
// no defaults substituted. Strings with a matching enum in mbEnums // no defaults substituted. Strings with a matching enum in mbEnums
// are stored as that enum; everything else stays a String. // are stored as that enum; everything else stays a String.
// // Read only once loaded.
// Not to be confused with engine.objects.ItemTemplate, which is loaded
// from the database. Read only once loaded.
public class ItemTemplate implements CObjectTemplate { public class ItemTemplate implements CObjectTemplate {
public static HashMap<Integer, ItemTemplate> _items = new HashMap<>(); public static HashMap<Integer, ItemTemplate> _items = new HashMap<>();
// Legacy templates zero-filled the weapon block on non-weapons; held shields and the like rely on it.
private static final Weapon NO_WEAPON = new Weapon();
public int template_id; public int template_id;
// obj_ // obj_
@@ -138,6 +139,341 @@ public class ItemTemplate implements CObjectTemplate {
public int item_bane_rank; public int item_bane_rank;
public boolean item_ignore_saved_actions; public boolean item_ignore_saved_actions;
@Override
public int getTemplateId() {
return template_id;
}
@Override
public String getObjName() {
return obj_name;
}
@Override
public boolean getObjPickable() {
return obj_pickable;
}
@Override
public float getObjGravity() {
return obj_gravity;
}
@Override
public float getObjCullDistance() {
return obj_cull_distance;
}
@Override
public Vector3fImmutable getObjScale() {
return obj_scale;
}
@Override
public int getObjRenderObject() {
return obj_render_object;
}
@Override
public boolean getObjDoubleFusion() {
return obj_double_fusion;
}
@Override
public Vector3fImmutable getObjForwardVector() {
return obj_forward_vector;
}
@Override
public String getObjTrackingName() {
return obj_tracking_name;
}
@Override
public float getObjMaxTrackingDistance() {
return obj_max_tracking_distance;
}
@Override
public int getObjIcon() {
return obj_icon;
}
@Override
public float getObjGravityF() {
return obj_gravity_f;
}
@Override
public LinkedHashMap<String, Integer> getObjSoundEvents() {
return obj_sound_events;
}
@Override
public JSONArray getObjArcHardpointList() {
return obj_arc_hardpoint_list;
}
@Override
public HashMap<String, String> getObjSparseData() {
return obj_sparse_data;
}
@Override
public int getObjRenderObjectLowDetail() {
return obj_render_object_low_detail;
}
@Override
public Vector3fImmutable getObjDefaultAlignment() {
return obj_default_alignment;
}
@Override
public String getObjSoundTable() {
return obj_sound_table;
}
@Override
public float getCombatHealthCurrent() {
return combat_health_current;
}
@Override
public float getCombatHealthFull() {
return combat_health_full;
}
@Override
public EnumMap<mbEnums.DamageType, Float> getCombatAttackResist() {
return combat_attack_resist;
}
@Override
public JSONArray getCombatPowers() {
return combat_powers;
}
@Override
public mbEnums.ItemType getItemType() {
return item_type;
}
@Override
public int getItemEqSlotsValue() {
return item_eq_slots_value;
}
@Override
public boolean getItemEqSlotsType() {
return item_eq_slots_type;
}
@Override
public EnumSet<mbEnums.EquipSlotType> getItemEqSlotsOr() {
return item_eq_slots_or;
}
@Override
public EnumSet<mbEnums.EquipSlotType> getItemEqSlotsAnd() {
return item_eq_slots_and;
}
@Override
public boolean getItemTakeable() {
return item_takeable;
}
@Override
public int getItemValue() {
return item_value;
}
@Override
public int getItemWt() {
return item_wt;
}
@Override
public float getItemPassiveDefenseMod() {
return item_passive_defense_mod;
}
@Override
public String getItemBaseName() {
return item_base_name;
}
@Override
public String getItemDsc() {
return item_dsc;
}
@Override
public int getItemRenderObjectFemale() {
return item_render_object_female;
}
@Override
public float getItemHealthFull() {
return item_health_full;
}
@Override
public String getItemSkillUsed() {
return item_skill_used;
}
@Override
public String getItemSkillMasteryUsed() {
return item_skill_mastery_used;
}
@Override
public int getItemParryAnimId() {
return item_parry_anim_id;
}
@Override
public EnumMap<mbEnums.ShrineType, Integer> getItemOfferingInfo() {
return item_offering_info;
}
@Override
public EnumSet<mbEnums.ItemFlags> getItemFlags() {
return item_flags;
}
@Override
public EnumSet<mbEnums.ItemUseFlags> getItemUseFlags() {
return item_use_flags;
}
@Override
public int getItemPostItemId() {
return item_post_item_id;
}
@Override
public int getItemInitialCharges() {
return item_initial_charges;
}
@Override
public int getItemBookArcana() {
return item_book_arcana;
}
@Override
public LinkedHashMap<String, Integer> getItemSkillReq() {
return item_skill_req;
}
@Override
public boolean getItemRaceReqRestrict() {
return item_race_req_restrict;
}
@Override
public EnumSet<mbEnums.MonsterType> getItemRaceReq() {
return item_race_req;
}
@Override
public boolean getItemClassReqRestrict() {
return item_class_req_restrict;
}
@Override
public EnumSet<mbEnums.ClassType> getItemClassReq() {
return item_class_req;
}
@Override
public boolean getItemDiscReqRestrict() {
return item_disc_req_restrict;
}
@Override
public EnumSet<mbEnums.DisciplineType> getItemDiscReq() {
return item_disc_req;
}
@Override
public EnumMap<mbEnums.AttributeType, Integer> getItemAttrReq() {
return item_attr_req;
}
@Override
public int getItemLevelReq() {
return item_level_req;
}
@Override
public int getItemRankReq() {
return item_rank_req;
}
@Override
public mbEnums.SexType getItemSexReq() {
return item_sex_req;
}
@Override
public ArrayList<UserPowerAction> getItemUserPowerAction() {
return item_user_power_action;
}
@Override
public ArrayList<PowerGrant> getItemPowerGrant() {
return item_power_grant;
}
@Override
public LinkedHashMap<String, ArrayList<int[]>> getItemPowerAction() {
return item_power_action;
}
@Override
public boolean getItemSheathable() {
return item_sheathable;
}
@Override
public boolean getItemHasStub() {
return item_has_stub;
}
@Override
public EnumMap<mbEnums.ShrineType, Integer> getItemOfferingAdjustments() {
return item_offering_adjustments;
}
@Override
public EnumMap<mbEnums.ResourceType, Integer> getItemResourceCosts() {
return item_resource_costs;
}
@Override
public int getItemBaneRank() {
return item_bane_rank;
}
@Override
public boolean getItemIgnoreSavedActions() {
return item_ignore_saved_actions;
}
public static Weapon getWeapon(int templateID) {
ItemTemplate template = _items.get(templateID);
if (template == null || template.item_weapon == null)
return NO_WEAPON;
return template.item_weapon;
}
// item_weapon (ArcAttackInfo_LoadWeapon, sb.exe 0x61FA60). // item_weapon (ArcAttackInfo_LoadWeapon, sb.exe 0x61FA60).
public static class Weapon { public static class Weapon {
@@ -149,7 +485,7 @@ public class ItemTemplate implements CObjectTemplate {
public int weapon_combat_idle_anim; public int weapon_combat_idle_anim;
public final ArrayList<Damage> weapon_damage = new ArrayList<>(); public final ArrayList<Damage> weapon_damage = new ArrayList<>();
// [animation, duration] pairs in file order; names from engine.objects.ItemTemplate, not the client. // [animation, duration] pairs in file order; names from the old static_item_templates export, not the client.
public final ArrayList<int[]> weapon_attack_anim_right = new ArrayList<>(); public final ArrayList<int[]> weapon_attack_anim_right = new ArrayList<>();
public final ArrayList<int[]> weapon_attack_anim_left = new ArrayList<>(); public final ArrayList<int[]> weapon_attack_anim_left = new ArrayList<>();
} }
+326 -1
View File
@@ -141,7 +141,7 @@ public class RuneTemplate implements CObjectTemplate {
public String rune_dsc; public String rune_dsc;
public String rune_fx_txt; public String rune_fx_txt;
// Bit vectors. The existing ItemTemplate decodes these as MobBehaviourType. // Bit vectors. The old static_item_templates export decoded these as MobBehaviourType.
public long rune_group_tactics; public long rune_group_tactics;
public long rune_group_role_set; public long rune_group_role_set;
@@ -191,6 +191,331 @@ public class RuneTemplate implements CObjectTemplate {
public int rune_natural_power_attack; public int rune_natural_power_attack;
public final HashMap<String, String> rune_sparse_data = new HashMap<>(); public final HashMap<String, String> rune_sparse_data = new HashMap<>();
@Override
public int getTemplateId() {
return template_id;
}
@Override
public String getObjName() {
return obj_name;
}
@Override
public boolean getObjPickable() {
return obj_pickable;
}
@Override
public float getObjGravity() {
return obj_gravity;
}
@Override
public float getObjCullDistance() {
return obj_cull_distance;
}
@Override
public Vector3fImmutable getObjScale() {
return obj_scale;
}
@Override
public int getObjRenderObject() {
return obj_render_object;
}
@Override
public boolean getObjDoubleFusion() {
return obj_double_fusion;
}
@Override
public Vector3fImmutable getObjForwardVector() {
return obj_forward_vector;
}
@Override
public String getObjTrackingName() {
return obj_tracking_name;
}
@Override
public float getObjMaxTrackingDistance() {
return obj_max_tracking_distance;
}
@Override
public int getObjIcon() {
return obj_icon;
}
@Override
public float getObjGravityF() {
return obj_gravity_f;
}
@Override
public LinkedHashMap<String, Integer> getObjSoundEvents() {
return obj_sound_events;
}
@Override
public JSONArray getObjArcHardpointList() {
return obj_arc_hardpoint_list;
}
@Override
public HashMap<String, String> getObjSparseData() {
return obj_sparse_data;
}
@Override
public int getObjRenderObjectLowDetail() {
return obj_render_object_low_detail;
}
@Override
public Vector3fImmutable getObjDefaultAlignment() {
return obj_default_alignment;
}
@Override
public String getObjSoundTable() {
return obj_sound_table;
}
@Override
public float getCombatHealthCurrent() {
return combat_health_current;
}
@Override
public float getCombatHealthFull() {
return combat_health_full;
}
@Override
public EnumMap<mbEnums.DamageType, Float> getCombatAttackResist() {
return combat_attack_resist;
}
@Override
public JSONArray getCombatPowers() {
return combat_powers;
}
@Override
public mbEnums.ItemType getItemType() {
return item_type;
}
@Override
public int getItemEqSlotsValue() {
return item_eq_slots_value;
}
@Override
public boolean getItemEqSlotsType() {
return item_eq_slots_type;
}
@Override
public EnumSet<mbEnums.EquipSlotType> getItemEqSlotsOr() {
return item_eq_slots_or;
}
@Override
public EnumSet<mbEnums.EquipSlotType> getItemEqSlotsAnd() {
return item_eq_slots_and;
}
@Override
public boolean getItemTakeable() {
return item_takeable;
}
@Override
public int getItemValue() {
return item_value;
}
@Override
public int getItemWt() {
return item_wt;
}
@Override
public float getItemPassiveDefenseMod() {
return item_passive_defense_mod;
}
@Override
public String getItemBaseName() {
return item_base_name;
}
@Override
public String getItemDsc() {
return item_dsc;
}
@Override
public int getItemRenderObjectFemale() {
return item_render_object_female;
}
@Override
public float getItemHealthFull() {
return item_health_full;
}
@Override
public String getItemSkillUsed() {
return item_skill_used;
}
@Override
public String getItemSkillMasteryUsed() {
return item_skill_mastery_used;
}
@Override
public int getItemParryAnimId() {
return item_parry_anim_id;
}
@Override
public EnumMap<mbEnums.ShrineType, Integer> getItemOfferingInfo() {
return item_offering_info;
}
@Override
public EnumSet<mbEnums.ItemFlags> getItemFlags() {
return item_flags;
}
@Override
public EnumSet<mbEnums.ItemUseFlags> getItemUseFlags() {
return item_use_flags;
}
@Override
public int getItemPostItemId() {
return item_post_item_id;
}
@Override
public int getItemInitialCharges() {
return item_initial_charges;
}
@Override
public int getItemBookArcana() {
return item_book_arcana;
}
@Override
public LinkedHashMap<String, Integer> getItemSkillReq() {
return item_skill_req;
}
@Override
public boolean getItemRaceReqRestrict() {
return item_race_req_restrict;
}
@Override
public EnumSet<mbEnums.MonsterType> getItemRaceReq() {
return item_race_req;
}
@Override
public boolean getItemClassReqRestrict() {
return item_class_req_restrict;
}
@Override
public EnumSet<mbEnums.ClassType> getItemClassReq() {
return item_class_req;
}
@Override
public boolean getItemDiscReqRestrict() {
return item_disc_req_restrict;
}
@Override
public EnumSet<mbEnums.DisciplineType> getItemDiscReq() {
return item_disc_req;
}
@Override
public EnumMap<mbEnums.AttributeType, Integer> getItemAttrReq() {
return item_attr_req;
}
@Override
public int getItemLevelReq() {
return item_level_req;
}
@Override
public int getItemRankReq() {
return item_rank_req;
}
@Override
public mbEnums.SexType getItemSexReq() {
return item_sex_req;
}
@Override
public ArrayList<UserPowerAction> getItemUserPowerAction() {
return item_user_power_action;
}
@Override
public ArrayList<PowerGrant> getItemPowerGrant() {
return item_power_grant;
}
@Override
public LinkedHashMap<String, ArrayList<int[]>> getItemPowerAction() {
return item_power_action;
}
@Override
public boolean getItemSheathable() {
return item_sheathable;
}
@Override
public boolean getItemHasStub() {
return item_has_stub;
}
@Override
public EnumMap<mbEnums.ShrineType, Integer> getItemOfferingAdjustments() {
return item_offering_adjustments;
}
@Override
public EnumMap<mbEnums.ResourceType, Integer> getItemResourceCosts() {
return item_resource_costs;
}
@Override
public int getItemBaneRank() {
return item_bane_rank;
}
@Override
public boolean getItemIgnoreSavedActions() {
return item_ignore_saved_actions;
}
// One entry of rune_skill_grant; same layout as PowerGrant. // One entry of rune_skill_grant; same layout as PowerGrant.
// skill_monster_types is empty in every RUNE file, so it is kept as raw JSON. // skill_monster_types is empty in every RUNE file, so it is kept as raw JSON.
@@ -63,7 +63,7 @@ public class StealPowerAction extends AbstractPowerAction {
//called to get amount of gold to steal between 0 and max gold //called to get amount of gold to steal between 0 and max gold
protected static int getAmountToSteal(Item item) { protected static int getAmountToSteal(Item item) {
if (item.template.item_type.equals(ItemType.GOLD)) { if (item.template.getItemType().equals(ItemType.GOLD)) {
int amount = item.getNumOfItems(); int amount = item.getNumOfItems();
@@ -159,7 +159,7 @@ public class StealPowerAction extends AbstractPowerAction {
if (myCIM == null || ownerCIM == null) if (myCIM == null || ownerCIM == null)
return; return;
if (tar.template.item_type.equals(ItemType.GOLD)) { if (tar.template.getItemType().equals(ItemType.GOLD)) {
//stealing gold //stealing gold
if (!myCIM.transferGoldToMyInventory((AbstractCharacter) owner, amount)) if (!myCIM.transferGoldToMyInventory((AbstractCharacter) owner, amount))
return; return;
+4 -6
View File
@@ -26,6 +26,7 @@ import engine.parsers.cache.DeedParser;
import engine.parsers.cache.ItemParser; import engine.parsers.cache.ItemParser;
import engine.parsers.cache.RuneParser; import engine.parsers.cache.RuneParser;
import engine.parsers.objects.DeedTemplate; import engine.parsers.objects.DeedTemplate;
import engine.parsers.objects.ItemTemplate;
import engine.parsers.objects.RuneTemplate; import engine.parsers.objects.RuneTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import engine.server.world.WorldServer; import engine.server.world.WorldServer;
@@ -287,9 +288,6 @@ public class LoginServer {
Logger.info("Initializing Database layer"); Logger.info("Initializing Database layer");
initDatabaseLayer(); initDatabaseLayer();
Logger.info("Loading Item Templates");
DbManager.ItemQueries.LOAD_ITEM_TEMPLATES();
Logger.info("Loading Deed Templates"); Logger.info("Loading Deed Templates");
DeedTemplate._deeds = DeedParser.parseDeedFolder(); DeedTemplate._deeds = DeedParser.parseDeedFolder();
@@ -306,11 +304,10 @@ public class LoginServer {
exit(1); exit(1);
} }
// Qualified: engine.objects.ItemTemplate is the database-loaded class
Logger.info("Loading Cache Item Templates"); Logger.info("Loading Cache Item Templates");
engine.parsers.objects.ItemTemplate._items = ItemParser.parseItemFolder(); ItemTemplate._items = ItemParser.parseItemFolder();
if (engine.parsers.objects.ItemTemplate._items == null || engine.parsers.objects.ItemTemplate._items.isEmpty()) { if (ItemTemplate._items == null || ItemTemplate._items.isEmpty()) {
Logger.error("ABORT! Cache item templates failed to load!"); Logger.error("ABORT! Cache item templates failed to load!");
exit(1); exit(1);
} }
@@ -337,6 +334,7 @@ public class LoginServer {
RuneBaseAttribute.LoadAllAttributes(); RuneBaseAttribute.LoadAllAttributes();
RuneBase.LoadAllRuneBases(); RuneBase.LoadAllRuneBases();
BaseClass.LoadAllBaseClasses(); BaseClass.LoadAllBaseClasses();
PromotionClass.LoadAllPromotions();
Race.loadAllRaces(); Race.loadAllRaces();
RuneBaseEffect.LoadRuneBaseEffects(); RuneBaseEffect.LoadRuneBaseEffects();
+6 -9
View File
@@ -37,6 +37,7 @@ import engine.parsers.cache.ItemParser;
import engine.parsers.cache.ParityCheck; import engine.parsers.cache.ParityCheck;
import engine.parsers.cache.RuneParser; import engine.parsers.cache.RuneParser;
import engine.parsers.objects.DeedTemplate; import engine.parsers.objects.DeedTemplate;
import engine.parsers.objects.ItemTemplate;
import engine.parsers.objects.RuneTemplate; import engine.parsers.objects.RuneTemplate;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import engine.util.MapLoader; import engine.util.MapLoader;
@@ -304,11 +305,8 @@ public class WorldServer {
Logger.info("Initializing MeshBounds"); Logger.info("Initializing MeshBounds");
MeshBounds.InitializeBuildingBounds(); MeshBounds.InitializeBuildingBounds();
Logger.info("Loading Item Templates"); Logger.info("Loading vendor modTables");
DbManager.ItemQueries.LOAD_ITEM_TEMPLATES(); ForgeManager.vendorModTables = DbManager.ItemQueries.LOAD_TEMPLATE_MODTABLES();
Logger.info("Back fill template modTables");
DbManager.ItemQueries.LOAD_TEMPLATE_MODTABLES();
Logger.info("Loading Deed Templates"); Logger.info("Loading Deed Templates");
DeedTemplate._deeds = DeedParser.parseDeedFolder(); DeedTemplate._deeds = DeedParser.parseDeedFolder();
@@ -326,11 +324,10 @@ public class WorldServer {
exit(1); exit(1);
} }
// Qualified: engine.objects.ItemTemplate is the database-loaded class
Logger.info("Loading Cache Item Templates"); Logger.info("Loading Cache Item Templates");
engine.parsers.objects.ItemTemplate._items = ItemParser.parseItemFolder(); ItemTemplate._items = ItemParser.parseItemFolder();
if (engine.parsers.objects.ItemTemplate._items == null || engine.parsers.objects.ItemTemplate._items.isEmpty()) { if (ItemTemplate._items == null || ItemTemplate._items.isEmpty()) {
Logger.error("ABORT! Cache item templates failed to load!"); Logger.error("ABORT! Cache item templates failed to load!");
exit(1); exit(1);
} }
@@ -339,7 +336,7 @@ public class WorldServer {
CObjectIndex.build(); CObjectIndex.build();
Logger.info("Loading PromotionClasses"); Logger.info("Loading PromotionClasses");
DbManager.PromotionQueries.GET_ALL_PROMOTIONS(); PromotionClass.LoadAllPromotions();
Logger.info("Loading NPC and Mob Rune Sets"); Logger.info("Loading NPC and Mob Rune Sets");
NPCManager._runeSetMap = dbNPCHandler.LOAD_RUNES_FOR_NPC_AND_MOBS(); NPCManager._runeSetMap = dbNPCHandler.LOAD_RUNES_FOR_NPC_AND_MOBS();