Files
BattleBane/src/engine/net/client/handlers/ObjectActionMsgHandler.java
T
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

288 lines
12 KiB
Java

package engine.net.client.handlers;
import engine.gameManager.*;
import engine.math.Bounds;
import engine.math.Vector3fImmutable;
import engine.mbEnums;
import engine.net.Dispatch;
import engine.net.client.ClientConnection;
import engine.net.client.msg.*;
import engine.objects.*;
import engine.parsers.objects.DeedTemplate;
import engine.powers.PowersBase;
import java.util.ArrayList;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/*
* @Author:
* @Summary: Processes application protocol message which handles
* items in the character's inventory which are used. Potions, Deeds, etc.
*/
public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
// Reentrant lock for dropping banes
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public ObjectActionMsgHandler() {
super();
}
@Override
protected boolean _handleNetMsg(ClientNetMsg baseMsg, ClientConnection origin) {
// Member variable declaration
ObjectActionMsg msg;
PlayerCharacter player;
CharacterItemManager itemMan;
ArrayList<Long> comps;
Dispatch dispatch;
boolean waterbucketBypass = false;
// Member variable assignment
msg = (ObjectActionMsg) baseMsg;
player = SessionManager.getPlayerCharacter(origin);
if (player == null) {
return true;
}
itemMan = player.charItemManager;
if (itemMan == null) {
return true;
}
comps = msg.getTargetCompID();
if (comps.isEmpty()) {
return true;
}
long comp = comps.get(0);
if (((int) comp) != 0) {
Item item = Item.getFromCache((int) comp);
if (item == null) {
return true;
}
//dupe check
if (!item.validForInventory(origin, player, itemMan)) {
return true;
}
if (itemMan.doesCharOwnThisItem(item.getObjectUUID())) {
int uuid = item.templateID;
switch (item.template.item_type) {
case DEED: //buildings
//Call add building screen here, ib.getUseID() get's building ID
//if inside player city, center loc on tol. otherwise center on player.
Vector3fImmutable loc = player.getLoc();
Zone zone = ZoneManager.findSmallestZone(player.getLoc());
if (zone != null) {
if (zone.guild_zone) {
loc = zone.getLoc();
}
}
PlaceAssetMsg pam = new PlaceAssetMsg();
pam.setActionType(2);
pam.setContractID(item.getObjectUUID());
pam.setX(loc.getX() + 64); //offset grid from tol
pam.setY(loc.getY());
pam.setZ(loc.getZ() + 64); //offset grid from tol
pam.addPlacementInfo(DeedTemplate._deeds.get(item.templateID).deed_structure_id);
dispatch = Dispatch.borrow(player, pam);
DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
//itemMan.consume(item); //temporary fix for dupe.. TODO Make Item Unusable after This message is sent.
break;
case FURNITUREDEED: //furniture
//Call add furniture screen here. ib.getUseID() get's furniture ID
break;
case OFFERING:
long shrineCompID = comps.get(1);
Building shrineBuilding = BuildingManager.getBuilding((int) shrineCompID);
if (shrineBuilding == null) {
return true;
}
if (shrineBuilding.getBlueprint() != null && shrineBuilding.getBlueprint().getBuildingGroup() != mbEnums.BuildingGroup.SHRINE) {
return true;
}
if (shrineBuilding.getRank() == -1) {
return true;
}
Shrine shrine = Shrine.shrinesByBuildingUUID.get(shrineBuilding.getObjectUUID());
if (shrine == null) {
return true;
}
if (shrine.addFavor(player, item)) {
shrineBuilding.addEffectBit(1000000 << 2);
shrineBuilding.updateEffects();
shrineBuilding.removeEffectBit(1000000 << 2);
}
break;
case REALMCHARTER:
int charterType = 0;
switch (uuid) {
case 910020:
charterType = 762228431;
break;
case 910021:
charterType = -15978914;
break;
case 910022:
charterType = -600065291;
break;
}
if (Realm.claimRealm(player, charterType) == true) {
itemMan.consume(item);
}
break;
case WAND: //rod of command
long compID = comps.get(1);
int objectType = AbstractWorldObject.extractTypeID(compID).ordinal();
Mob toCommand;
if (objectType == mbEnums.GameObjectType.Mob.ordinal()) {
toCommand = Mob.getFromCache((int) compID);
} //Only Command Mob Types.
else {
return true;
}
if (toCommand == null) {
return true;
}
if (!toCommand.isSiege())
return true;
if (player.commandSiegeMinion(toCommand)) {
itemMan.consume(item);
}
break;
//ANNIVERSERY GIFT
case TREASURE:
// *** Disabled for now: Needs bootyset created
LootManager.peddleFate(player, item);
break;
case BUCKET: //water bucket
case POTION: //potions, tears of saedron
case SCROLL: //runes, petition, warrant, scrolls
if (uuid > 680069 && uuid < 680074) //Handle Charter, Deed, Petition, Warrant here
break;
if (item.template.item_bane_rank > 0) {
// Only one banestone at a time
lock.writeLock().lock();
try {
if (Bane.summonBanestone(player, origin, item.template.item_bane_rank) == true)
itemMan.consume(item);
} finally {
lock.writeLock().unlock();
}
break;
}
if (uuid == 910010) { //tears of saedron
if (comps.size() > 1)
AbstractCharacter.removeRune(player, origin, comps.get(1).intValue());
break;
}
if (item.chargesRemaining > 0) {
ArrayList<Long> tarList = msg.getTargetCompID();
AbstractWorldObject target = player;
if (tarList.size() > 1) {
long tarID = tarList.get(1);
if (tarID != 0) {
AbstractGameObject tarAgo = AbstractGameObject.getFromTypeAndID(tarID);
if (tarAgo instanceof AbstractWorldObject) {
target = (AbstractWorldObject) tarAgo;
}
}
}
// Bypass for waterbuckets
if (item.template.item_type.equals(mbEnums.ItemType.BUCKET)) {
// test for valid target type
if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter)
waterbucketBypass = true;
else {
// test distance to structure
Building targetBuilding = (Building) target;
Bounds testBounds = Bounds.borrow();
testBounds.setBounds(player.getLoc(), 25);
if (Bounds.collide(targetBuilding.getBounds(), testBounds, .1f) == false) {
ChatManager.chatSystemError(player, "Not in range of structura for to heal!");
return true;
}
}
// Send piss bucket animation
VisualUpdateMessage vum = new VisualUpdateMessage(player, 16323);
vum.configure();
DispatchManager.sendToAllInRange(player, vum);
}
if (waterbucketBypass == false) {
String powerString = item.template.item_power_grant.keySet().iterator().next();
PowersBase powerAction = PowersManager.powersBaseByIDString.get(powerString);
int powerValue = item.template.item_power_grant.get(powerString);
PowersManager.applyPower(player, target, Vector3fImmutable.ZERO, powerAction.getToken(), powerValue, true);
}
itemMan.consume(item);
} else //just remove the item at this point
itemMan.consume(item);
dispatch = Dispatch.borrow(player, msg);
DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
player.cancelOnSpell();
break;
case RUNE:
if(ApplyRuneMsg.applyRune(uuid, origin, player)) {
itemMan.consume(item);
}
break;
default: //shouldn't be here, consume item
dispatch = Dispatch.borrow(player, msg);
DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
// itemMan.consume(item);
}
} else {
// TODO log item does not belong to player
// System.out.println("Item does not belong to player");
// Cleanup duped item here
}
}
return true;
}
}