From 3f8d94b030009bd935e3eaf0e630ec2ab3fdef2b Mon Sep 17 00:00:00 2001 From: David Cernat Date: Tue, 3 Apr 2018 10:27:02 +0300 Subject: [PATCH 1/4] [General] Synchronize strike enchantments in combat --- apps/openmw/mwclass/creature.cpp | 16 +++++++++++++++- apps/openmw/mwclass/npc.cpp | 16 +++++++++++++++- apps/openmw/mwmp/MechanicsHelper.cpp | 9 +++++++++ components/openmw-mp/Base/BaseStructs.hpp | 1 + .../Packets/Actor/PacketActorAttack.cpp | 1 + .../Packets/Player/PacketPlayerAttack.cpp | 2 ++ 6 files changed, 43 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 6d198b261..6189a535d 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -307,6 +307,7 @@ namespace MWClass if (localAttack) { localAttack->success = true; + localAttack->usesStrikeEnchantment = false; MechanicsHelper::assignAttackTarget(localAttack, victim); } /* @@ -373,7 +374,20 @@ namespace MWClass } // Apply "On hit" enchanted weapons - MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition); + + /* + Start of tes3mp change (minor) + + Track whether the strike enchantment is successful for attacks by the + LocalPlayer or LocalActors + */ + bool appliedEnchantment = MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition); + + if (localAttack) + localAttack->usesStrikeEnchantment = appliedEnchantment; + /* + End of tes3mp change (minor) + */ } else if (isBipedal(ptr)) { diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index fbf6c6357..c2d610cc3 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -634,6 +634,7 @@ namespace MWClass if (localAttack) { localAttack->success = true; + localAttack->usesStrikeEnchantment = false; MechanicsHelper::assignAttackTarget(localAttack, victim); } /* @@ -706,7 +707,20 @@ namespace MWClass damage *= store.find("fCombatKODamageMult")->getFloat(); // Apply "On hit" enchanted weapons - MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition); + + /* + Start of tes3mp change (minor) + + Track whether the strike enchantment is successful for attacks by the + LocalPlayer or LocalActors + */ + bool appliedEnchantment = MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition); + + if (localAttack) + localAttack->usesStrikeEnchantment = appliedEnchantment; + /* + End of tes3mp change (minor) + */ MWMechanics::applyElementalShields(ptr, victim); diff --git a/apps/openmw/mwmp/MechanicsHelper.cpp b/apps/openmw/mwmp/MechanicsHelper.cpp index e0ecb0478..f61509386 100644 --- a/apps/openmw/mwmp/MechanicsHelper.cpp +++ b/apps/openmw/mwmp/MechanicsHelper.cpp @@ -195,8 +195,17 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker) } } else + { MWMechanics::blockMeleeAttack(attacker, victim, weapon, attack.damage, 1); + if (attack.usesStrikeEnchantment) + { + MWMechanics::CastSpell cast(attacker, victim, false); + cast.mHitPosition = osg::Vec3f(); + cast.cast(weapon, false); + } + } + victim.getClass().onHit(victim, attack.damage, healthdmg, weapon, attacker, osg::Vec3f(), attack.success); } diff --git a/components/openmw-mp/Base/BaseStructs.hpp b/components/openmw-mp/Base/BaseStructs.hpp index 798323c91..2d3dda43a 100644 --- a/components/openmw-mp/Base/BaseStructs.hpp +++ b/components/openmw-mp/Base/BaseStructs.hpp @@ -53,6 +53,7 @@ namespace mwmp bool pressed; bool instant; bool knockdown; + bool usesStrikeEnchantment; bool shouldSend; }; diff --git a/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp b/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp index 4ca89cdf9..57a43b8a4 100644 --- a/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp +++ b/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp @@ -25,4 +25,5 @@ void PacketActorAttack::Actor(BaseActor &actor, bool send) RW(actor.attack.block, send); RW(actor.attack.instant, send); + RW(actor.attack.usesStrikeEnchantment, send); } diff --git a/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp b/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp index bde2c9d0c..a8ad72496 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp @@ -29,4 +29,6 @@ void PacketPlayerAttack::Packet(RakNet::BitStream *bs, bool send) RW(player->attack.pressed, send); RW(player->attack.knockdown, send); RW(player->attack.block, send); + + RW(player->attack.usesStrikeEnchantment, send); } From a86c68c5a1a8e151096ff6019780eaaed4670f81 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Tue, 3 Apr 2018 14:12:27 +0300 Subject: [PATCH 2/4] [General] Add sync for ranged weapon & projectile strike enchantments --- apps/openmw/mwclass/creature.cpp | 3 +-- apps/openmw/mwclass/npc.cpp | 3 +-- apps/openmw/mwmechanics/combat.cpp | 19 ++++++++++++++ apps/openmw/mwmp/MechanicsHelper.cpp | 25 ++++++++++++++++--- components/openmw-mp/Base/BaseStructs.hpp | 3 ++- .../Packets/Actor/PacketActorAttack.cpp | 3 ++- .../Packets/Player/PacketPlayerAttack.cpp | 3 ++- 7 files changed, 48 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 6189a535d..8e59a7aa1 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -307,7 +307,6 @@ namespace MWClass if (localAttack) { localAttack->success = true; - localAttack->usesStrikeEnchantment = false; MechanicsHelper::assignAttackTarget(localAttack, victim); } /* @@ -384,7 +383,7 @@ namespace MWClass bool appliedEnchantment = MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition); if (localAttack) - localAttack->usesStrikeEnchantment = appliedEnchantment; + localAttack->applyWeaponEnchantment = appliedEnchantment; /* End of tes3mp change (minor) */ diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c2d610cc3..ee36c92ae 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -634,7 +634,6 @@ namespace MWClass if (localAttack) { localAttack->success = true; - localAttack->usesStrikeEnchantment = false; MechanicsHelper::assignAttackTarget(localAttack, victim); } /* @@ -717,7 +716,7 @@ namespace MWClass bool appliedEnchantment = MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition); if (localAttack) - localAttack->usesStrikeEnchantment = appliedEnchantment; + localAttack->applyWeaponEnchantment = appliedEnchantment; /* End of tes3mp change (minor) */ diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 91753521a..84f993996 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -290,10 +290,29 @@ namespace MWMechanics reduceWeaponCondition(damage, validVictim, weapon, attacker); // Apply "On hit" effect of the weapon & projectile + + /* + Start of tes3mp change (minor) + + Track whether the strike enchantment is successful for attacks by the + LocalPlayer or LocalActors for both their weapon and projectile + */ + mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker); + bool appliedEnchantment = applyOnStrikeEnchantment(attacker, victim, weapon, hitPosition, true); + + if (localAttack) + localAttack->applyWeaponEnchantment = appliedEnchantment; + if (weapon != projectile) appliedEnchantment = applyOnStrikeEnchantment(attacker, victim, projectile, hitPosition, true); + if (localAttack) + localAttack->applyProjectileEnchantment = appliedEnchantment; + /* + End of tes3mp change (minor) + */ + if (validVictim) { // Non-enchanted arrows shot at enemies have a chance to turn up in their inventory diff --git a/apps/openmw/mwmp/MechanicsHelper.cpp b/apps/openmw/mwmp/MechanicsHelper.cpp index f61509386..9c87e8c9b 100644 --- a/apps/openmw/mwmp/MechanicsHelper.cpp +++ b/apps/openmw/mwmp/MechanicsHelper.cpp @@ -124,6 +124,8 @@ void MechanicsHelper::resetAttack(Attack* attack) attack->success = false; attack->knockdown = false; attack->block = false; + attack->applyWeaponEnchantment = false; + attack->applyProjectileEnchantment = false; attack->target.guid = RakNet::RakNetGUID(); attack->target.refId.clear(); } @@ -170,14 +172,20 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker) if (attack.type == attack.MELEE) { MWWorld::Ptr weapon; + MWWorld::Ptr projectile; if (attacker.getClass().hasInventoryStore(attacker)) { - MWWorld::InventoryStore &inv = attacker.getClass().getInventoryStore(attacker); - MWWorld::ContainerStoreIterator weaponslot = inv.getSlot( + MWWorld::InventoryStore &inventoryStore = attacker.getClass().getInventoryStore(attacker); + MWWorld::ContainerStoreIterator weaponSlot = inventoryStore.getSlot( MWWorld::InventoryStore::Slot_CarriedRight); + MWWorld::ContainerStoreIterator projectileSlot = inventoryStore.getSlot( + MWWorld::InventoryStore::Slot_Ammunition); + + // TODO: Fix for when arrows, bolts and throwing weapons have just run out + weapon = weaponSlot != inventoryStore.end() ? *weaponSlot : MWWorld::Ptr(); + projectile = projectileSlot != inventoryStore.end() ? *projectileSlot : MWWorld::Ptr(); - weapon = ((weaponslot != inv.end()) ? *weaponslot : MWWorld::Ptr()); if (!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name()) weapon = MWWorld::Ptr(); } @@ -196,14 +204,23 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker) } else { + LOG_APPEND(Log::LOG_VERBOSE, "- weapon: %s", weapon.getCellRef().getRefId().c_str()); + MWMechanics::blockMeleeAttack(attacker, victim, weapon, attack.damage, 1); - if (attack.usesStrikeEnchantment) + if (attack.applyWeaponEnchantment) { MWMechanics::CastSpell cast(attacker, victim, false); cast.mHitPosition = osg::Vec3f(); cast.cast(weapon, false); } + + if (attack.applyProjectileEnchantment) + { + MWMechanics::CastSpell cast(attacker, victim, false); + cast.mHitPosition = osg::Vec3f(); + cast.cast(projectile, false); + } } victim.getClass().onHit(victim, attack.damage, healthdmg, weapon, attacker, osg::Vec3f(), diff --git a/components/openmw-mp/Base/BaseStructs.hpp b/components/openmw-mp/Base/BaseStructs.hpp index 2d3dda43a..0b83766f0 100644 --- a/components/openmw-mp/Base/BaseStructs.hpp +++ b/components/openmw-mp/Base/BaseStructs.hpp @@ -53,7 +53,8 @@ namespace mwmp bool pressed; bool instant; bool knockdown; - bool usesStrikeEnchantment; + bool applyWeaponEnchantment; + bool applyProjectileEnchantment; bool shouldSend; }; diff --git a/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp b/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp index 57a43b8a4..44e8d43b0 100644 --- a/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp +++ b/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp @@ -25,5 +25,6 @@ void PacketActorAttack::Actor(BaseActor &actor, bool send) RW(actor.attack.block, send); RW(actor.attack.instant, send); - RW(actor.attack.usesStrikeEnchantment, send); + RW(actor.attack.applyWeaponEnchantment, send); + RW(actor.attack.applyProjectileEnchantment, send); } diff --git a/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp b/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp index a8ad72496..75a6f4323 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp @@ -30,5 +30,6 @@ void PacketPlayerAttack::Packet(RakNet::BitStream *bs, bool send) RW(player->attack.knockdown, send); RW(player->attack.block, send); - RW(player->attack.usesStrikeEnchantment, send); + RW(player->attack.applyWeaponEnchantment, send); + RW(player->attack.applyProjectileEnchantment, send); } From 0eed05610b6ea1d44b9779325b18d38e90beefa1 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Tue, 3 Apr 2018 15:22:51 +0300 Subject: [PATCH 3/4] [Client] Fix autoequipping for creatures in WorldEvent::editContainers() --- apps/openmw/mwmp/WorldEvent.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmp/WorldEvent.cpp b/apps/openmw/mwmp/WorldEvent.cpp index cae3bcceb..5e5ad23b0 100644 --- a/apps/openmw/mwmp/WorldEvent.cpp +++ b/apps/openmw/mwmp/WorldEvent.cpp @@ -80,7 +80,7 @@ void WorldEvent::addContainerItem(mwmp::WorldObject& worldObject, const MWWorld: containerItem.enchantmentCharge = itemPtr.getCellRef().getEnchantmentCharge(); containerItem.actionCount = actionCount; - LOG_APPEND(Log::LOG_INFO, "- Adding container item %s", containerItem.refId.c_str()); + LOG_APPEND(Log::LOG_INFO, "-- Adding container item %s", containerItem.refId.c_str()); worldObject.containerItems.push_back(containerItem); } @@ -232,7 +232,12 @@ void WorldEvent::editContainers(MWWorld::CellStore* cellStore) mwmp::Main::get().getCellController()->isLocalActor(ptrFound)) { MWWorld::InventoryStore& invStore = ptrFound.getClass().getInventoryStore(ptrFound); - invStore.autoEquip(ptrFound); + + if (ptrFound.getTypeName() == typeid(ESM::NPC).name()) + invStore.autoEquip(ptrFound); + // autoEquip only works on NPCs, so use the closest alternative for creatures + else + invStore.autoEquipShield(ptrFound); } // If this container was open for us, update its view From 34be9383e5e699e48bcb95404465938841a7e3cf Mon Sep 17 00:00:00 2001 From: David Cernat Date: Thu, 5 Apr 2018 12:48:53 +0300 Subject: [PATCH 4/4] [General] Add isPlayer boolean to targets in packets --- apps/openmw/mwmp/MechanicsHelper.cpp | 20 +++++++++---------- apps/openmw/mwmp/WorldEvent.cpp | 7 ++++--- components/openmw-mp/Base/BaseStructs.hpp | 2 ++ .../Packets/Actor/PacketActorAttack.cpp | 15 +++++++++++--- .../Packets/Player/PacketPlayerAttack.cpp | 16 +++++++++++---- .../Packets/World/PacketObjectSpawn.cpp | 15 +++++++++++--- 6 files changed, 52 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwmp/MechanicsHelper.cpp b/apps/openmw/mwmp/MechanicsHelper.cpp index 9c87e8c9b..9082fea3a 100644 --- a/apps/openmw/mwmp/MechanicsHelper.cpp +++ b/apps/openmw/mwmp/MechanicsHelper.cpp @@ -86,13 +86,10 @@ Attack *MechanicsHelper::getDedicatedAttack(const MWWorld::Ptr& ptr) MWWorld::Ptr MechanicsHelper::getPlayerPtr(const Target& target) { - if (target.refId.empty()) - { - if (target.guid == mwmp::Main::get().getLocalPlayer()->guid) - return MWBase::Environment::get().getWorld()->getPlayerPtr(); - else if (PlayerList::getPlayer(target.guid) != nullptr) - return PlayerList::getPlayer(target.guid)->getPtr(); - } + if (target.guid == mwmp::Main::get().getLocalPlayer()->guid) + return MWBase::Environment::get().getWorld()->getPlayerPtr(); + else if (PlayerList::getPlayer(target.guid) != nullptr) + return PlayerList::getPlayer(target.guid)->getPtr(); return nullptr; } @@ -101,18 +98,19 @@ void MechanicsHelper::assignAttackTarget(Attack* attack, const MWWorld::Ptr& tar { if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) { + attack->target.isPlayer = true; attack->target.guid = mwmp::Main::get().getLocalPlayer()->guid; - attack->target.refId.clear(); } else if (mwmp::PlayerList::isDedicatedPlayer(target)) { + attack->target.isPlayer = true; attack->target.guid = mwmp::PlayerList::getPlayer(target)->guid; - attack->target.refId.clear(); } else { MWWorld::CellRef *targetRef = &target.getCellRef(); + attack->target.isPlayer = false; attack->target.refId = targetRef->getRefId(); attack->target.refNumIndex = targetRef->getRefNum().mIndex; attack->target.mpNum = targetRef->getMpNum(); @@ -128,6 +126,8 @@ void MechanicsHelper::resetAttack(Attack* attack) attack->applyProjectileEnchantment = false; attack->target.guid = RakNet::RakNetGUID(); attack->target.refId.clear(); + attack->target.refNumIndex = 0; + attack->target.mpNum = 0; } bool MechanicsHelper::getSpellSuccess(std::string spellId, const MWWorld::Ptr& caster) @@ -152,7 +152,7 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker) MWWorld::Ptr victim; - if (attack.target.refId.empty()) + if (attack.target.isPlayer) { if (attack.target.guid == mwmp::Main::get().getLocalPlayer()->guid) victim = MWBase::Environment::get().getWorld()->getPlayerPtr(); diff --git a/apps/openmw/mwmp/WorldEvent.cpp b/apps/openmw/mwmp/WorldEvent.cpp index 5e5ad23b0..03afd6317 100644 --- a/apps/openmw/mwmp/WorldEvent.cpp +++ b/apps/openmw/mwmp/WorldEvent.cpp @@ -338,7 +338,7 @@ void WorldEvent::spawnObjects(MWWorld::CellStore* cellStore) { MWWorld::Ptr masterPtr; - if (worldObject.master.refId.empty()) + if (worldObject.master.isPlayer) masterPtr = MechanicsHelper::getPlayerPtr(worldObject.master); else masterPtr = cellStore->searchExact(worldObject.master.refNumIndex, worldObject.master.mpNum); @@ -828,18 +828,19 @@ void WorldEvent::addObjectSpawn(const MWWorld::Ptr& ptr, const MWWorld::Ptr& mas if (master == MWBase::Environment::get().getWorld()->getPlayerPtr()) { + worldObject.master.isPlayer = true; worldObject.master.guid = mwmp::Main::get().getLocalPlayer()->guid; - worldObject.master.refId.clear(); } else if (mwmp::PlayerList::isDedicatedPlayer(master)) { + worldObject.master.isPlayer = true; worldObject.master.guid = mwmp::PlayerList::getPlayer(master)->guid; - worldObject.master.refId.clear(); } else { MWWorld::CellRef *masterRef = &master.getCellRef(); + worldObject.master.isPlayer = false; worldObject.master.refId = masterRef->getRefId(); worldObject.master.refNumIndex = masterRef->getRefNum().mIndex; worldObject.master.mpNum = masterRef->getMpNum(); diff --git a/components/openmw-mp/Base/BaseStructs.hpp b/components/openmw-mp/Base/BaseStructs.hpp index 0b83766f0..03fa30082 100644 --- a/components/openmw-mp/Base/BaseStructs.hpp +++ b/components/openmw-mp/Base/BaseStructs.hpp @@ -22,6 +22,8 @@ namespace mwmp struct Target { + bool isPlayer; + std::string refId; int refNumIndex; int mpNum; diff --git a/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp b/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp index 44e8d43b0..324f7fb84 100644 --- a/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp +++ b/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp @@ -11,9 +11,18 @@ PacketActorAttack::PacketActorAttack(RakNet::RakPeerInterface *peer) : ActorPack void PacketActorAttack::Actor(BaseActor &actor, bool send) { - RW(actor.attack.target.refNumIndex, send); - RW(actor.attack.target.mpNum, send); - RW(actor.attack.target.guid, send); + RW(actor.attack.target.isPlayer, send); + + if (actor.attack.target.isPlayer) + { + RW(actor.attack.target.guid, send); + } + else + { + RW(actor.attack.target.refId, send, 1); + RW(actor.attack.target.refNumIndex, send); + RW(actor.attack.target.mpNum, send); + } RW(actor.attack.spellId, send); RW(actor.attack.type, send); diff --git a/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp b/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp index 75a6f4323..71dbf9881 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp @@ -16,10 +16,18 @@ void PacketPlayerAttack::Packet(RakNet::BitStream *bs, bool send) { PlayerPacket::Packet(bs, send); - RW(player->attack.target.refId, send, 1); - RW(player->attack.target.refNumIndex, send); - RW(player->attack.target.mpNum, send); - RW(player->attack.target.guid, send); + RW(player->attack.target.isPlayer, send); + + if (player->attack.target.isPlayer) + { + RW(player->attack.target.guid, send); + } + else + { + RW(player->attack.target.refId, send, 1); + RW(player->attack.target.refNumIndex, send); + RW(player->attack.target.mpNum, send); + } RW(player->attack.spellId, send, 1); RW(player->attack.type, send); diff --git a/components/openmw-mp/Packets/World/PacketObjectSpawn.cpp b/components/openmw-mp/Packets/World/PacketObjectSpawn.cpp index 3716679d7..6d26990f3 100644 --- a/components/openmw-mp/Packets/World/PacketObjectSpawn.cpp +++ b/components/openmw-mp/Packets/World/PacketObjectSpawn.cpp @@ -18,8 +18,17 @@ void PacketObjectSpawn::Object(WorldObject &worldObject, bool send) if (worldObject.hasMaster) { - RW(worldObject.master.refNumIndex, send); - RW(worldObject.master.mpNum, send); - RW(worldObject.master.guid, send); + RW(worldObject.master.isPlayer, send); + + if (worldObject.master.isPlayer) + { + RW(worldObject.master.guid, send); + } + else + { + RW(worldObject.master.refId, send, 1); + RW(worldObject.master.refNumIndex, send); + RW(worldObject.master.mpNum, send); + } } }