/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ #include "plAvatarSDLModifier.h" #include "plArmatureMod.h" #include "plAvatar/plArmatureMod.h" #include "plAvatar/plAvBrainGeneric.h" #include "plAvatar/plAvBrainClimb.h" #include "plAvatar/plAvBrainDrive.h" #include "plAvatar/plAnimStage.h" #include "plAvatar/plAvCallbackAction.h" #include "pnSceneObject/plSceneObject.h" #include "pnMessage/plSDLModifierMsg.h" #include "plSDL/plSDL.h" #include "plNetClient/plNetClientMgr.h" #include "pnAsyncCore/pnAsyncCore.h" // static vars char plAvatarPhysicalSDLModifier::kStrPosition[] = "position"; char plAvatarPhysicalSDLModifier::kStrRotation[] = "rotation"; char plAvatarPhysicalSDLModifier::kStrSubworld[] = "subworld"; char plAvatarSDLModifier::kStrBrainStack[] = "brainStack"; char plAvatarSDLModifier::kStrInvisibilityLevel[] = "invisibilityLevel"; char plAvatarSDLModifier::StandardStageVarNames::kStrName[]="name"; char plAvatarSDLModifier::StandardStageVarNames::kStrNumLoops[]="numLoops"; char plAvatarSDLModifier::StandardStageVarNames::kStrForward[]="forward"; char plAvatarSDLModifier::StandardStageVarNames::kStrBackward[]="backward"; char plAvatarSDLModifier::StandardStageVarNames::kStrStageAdvance[]="stageAdvance"; char plAvatarSDLModifier::StandardStageVarNames::kStrStageRegress[]="stageRegress"; char plAvatarSDLModifier::StandardStageVarNames::kStrNotifyEnter[]="notifyEnter"; char plAvatarSDLModifier::StandardStageVarNames::kStrNotifyLoop[]="notifyLoop"; char plAvatarSDLModifier::StandardStageVarNames::kStrNotifyStageAdvance[]="notifyStageAdvance"; char plAvatarSDLModifier::StandardStageVarNames::kStrNotifyStageRegress[]="notifyStageRegress"; char plAvatarSDLModifier::StandardStageVarNames::kStrUseGlobalCoords[]="useGlobalCoords"; char plAvatarSDLModifier::StandardStageVarNames::kStrLocalTime[]="localTime"; char plAvatarSDLModifier::StandardStageVarNames::kStrCurrentLoop[]="currentLoop"; char plAvatarSDLModifier::StandardStageVarNames::kStrIsAttached[]="isAttached"; char plAvatarSDLModifier::GenericBrainVarNames::kStrStages[]="stages"; char plAvatarSDLModifier::GenericBrainVarNames::kStrCurrentStage[]="currentStage"; char plAvatarSDLModifier::GenericBrainVarNames::kStrCallbackRcvr[]="callbackRcvr"; char plAvatarSDLModifier::GenericBrainVarNames::kStrMovingForward[]="movingForward"; char plAvatarSDLModifier::GenericBrainVarNames::kStrExitFlags[]="exitFlags"; char plAvatarSDLModifier::GenericBrainVarNames::kStrType[]="type"; char plAvatarSDLModifier::GenericBrainVarNames::kStrMode[]="mode"; char plAvatarSDLModifier::GenericBrainVarNames::kStrFadeIn[]="fadeIn"; char plAvatarSDLModifier::GenericBrainVarNames::kStrFadeOut[]="fadeOut"; char plAvatarSDLModifier::GenericBrainVarNames::kStrMoveMode[]="moveMode"; char plAvatarSDLModifier::GenericBrainVarNames::kStrBodyUsage[]="bodyUsage"; char plAvatarSDLModifier::ClimbBrainVarNames::kStrCurMode[]="curMode"; char plAvatarSDLModifier::ClimbBrainVarNames::kStrNextMode[]="nextMode"; char plAvatarSDLModifier::ClimbBrainVarNames::kStrAllowedDirections[]="allowedDirections"; char plAvatarSDLModifier::ClimbBrainVarNames::kStrAllowedDismounts[]="allowedDismounts"; char plAvatarSDLModifier::ClimbBrainVarNames::kStrVertProbeLength[]="vertProbeLength"; char plAvatarSDLModifier::ClimbBrainVarNames::kStrHorizProbeLength[]="horizProbeLength"; char plAvatarSDLModifier::ClimbBrainVarNames::kStrCurStageAttached[]="curStageAttached"; char plAvatarSDLModifier::ClimbBrainVarNames::kStrCurStage[]="curStage"; char plAvatarSDLModifier::ClimbBrainVarNames::kStrCurStageTime[]="curStageTime"; char plAvatarSDLModifier::ClimbBrainVarNames::kStrCurStageStrength[]="curStageStrength"; char plAvatarSDLModifier::ClimbBrainVarNames::kStrExitStageAttached[]="exitStageAttached"; char plAvatarSDLModifier::ClimbBrainVarNames::kStrExitStage[]="exitStage"; char plAvatarSDLModifier::ClimbBrainVarNames::kStrExitStageTime[]="exitStageTime"; char plAvatarSDLModifier::ClimbBrainVarNames::kStrExitStageStrength[]="exitStageStrength"; char plAvatarSDLModifier::BrainUnionVarNames::kGenericBrain[]="fGenericBrain"; char plAvatarSDLModifier::BrainUnionVarNames::kClimbBrain[]="fClimbBrain"; char plAvatarSDLModifier::BrainUnionVarNames::kDriveBrain[]="fDriveBrain"; void plAvatarPhysicalSDLModifier::ISetCurrentStateFrom(const plStateDataRecord* srcState) { plSceneObject* sObj = GetTarget(); hsAssert(sObj, "plAvatarPhysicalSDLModifier, nil target"); if(sObj) { const plArmatureMod* kAvMod = (plArmatureMod*)sObj->GetModifierByType(plArmatureMod::Index()); plArmatureMod * avMod = const_cast(kAvMod); if(avMod && !avMod->GetCurrentBrain()->IsRunningTask()) { plAvBrainGeneric* genBrain = plAvBrainGeneric::ConvertNoRef(avMod->GetCurrentBrain()); if (genBrain && (genBrain->GetType() == plAvBrainGeneric::kLadder || genBrain->GetType() == plAvBrainGeneric::kSit || genBrain->GetType() == plAvBrainGeneric::kSitOnGround)) return; plSimpleStateVariable* worldVar = srcState->FindVar(kStrSubworld); if (worldVar->IsDirty() && avMod->fController) { plKey worldKey; worldVar->Get(&worldKey); avMod->fController->SetSubworld(worldKey); } plSimpleStateVariable* rotVar = srcState->FindVar(kStrRotation); plSimpleStateVariable* posVar = srcState->FindVar(kStrPosition); if ((rotVar->IsDirty() || posVar->IsDirty()) && avMod->GetController()) { hsPoint3 pos; hsScalar zRot; posVar->Get(&pos.fX); rotVar->Get(&zRot); avMod->GetController()->SetState(pos, zRot); } } } } void plAvatarPhysicalSDLModifier::IPutCurrentStateIn(plStateDataRecord* dstState) { plSceneObject* sObj = GetTarget(); hsAssert(sObj, "plAvatarPhysicalSDLModifier, nil target"); const plArmatureMod* kAvMod = (plArmatureMod*)sObj->GetModifierByType(plArmatureMod::Index()); plArmatureMod * avMod = const_cast(kAvMod); hsAssert(avMod, "nil avMod"); if(avMod && avMod->GetController()) { hsPoint3 pos; hsScalar zRot; avMod->GetController()->GetState(pos, zRot); dstState->FindVar(kStrRotation)->Set(zRot); dstState->FindVar(kStrPosition)->Set(&pos.fX); dstState->FindVar(kStrSubworld)->Set(avMod->GetWorldKey()); } } // ISetCurrentStateFrom --------------------------------------------------------- void plAvatarSDLModifier::ISetCurrentStateFrom(const plStateDataRecord* srcState) { plSceneObject* sObj = GetTarget(); hsAssert(sObj, "plAvatarSDLModifier, nil target"); if(sObj) { const plArmatureMod* kAvMod = (plArmatureMod*)sObj->GetModifierByType(plArmatureMod::Index()); plArmatureMod * avMod = const_cast(kAvMod); if(avMod) { ISetBaseAvatarStateFrom(avMod, srcState); // right now we're just going to destroy all the non-standard brains // and rebuild them from the incoming synch state // This is acceptable because we should only receive this state when // we're loading another player for the first time after entering an age. int brainCount = avMod->GetBrainCount(); if(brainCount > 1) { // remove all non-default brains for(int i = 0; i < brainCount - 1; i++) { plArmatureBrain* current = avMod->GetCurrentBrain(); avMod->PopBrain(); delete current; } } plSDStateVariable* brainsVar = srcState->FindSDVar(kStrBrainStack); if (brainsVar->IsUsed()) { int nBrains = brainsVar->GetCount(); for(int i = 0; i < nBrains; i++) { // get the record containing the brain union structure plStateDataRecord* brainUnion = brainsVar->GetStateDataRecord(i); // get the (one element) generic brain list, if populated plSDStateVariable *genBrainListVar = brainUnion->FindSDVar(BrainUnionVarNames::kGenericBrain); if(genBrainListVar->IsUsed() && genBrainListVar->GetCount() > 0) { // get the state for the generic brain from the list (there's only allowed to be one per list plStateDataRecord *genBrainVar = genBrainListVar->GetStateDataRecord(0); ISetGenericBrainFrom(avMod, genBrainVar); } else { // get the (one element) climb brain list, if populated plSDStateVariable *climbBrainListVar = brainUnion->FindSDVar(BrainUnionVarNames::kClimbBrain); if(climbBrainListVar->IsUsed() && climbBrainListVar->GetCount() > 0) { // TEMP: Not read/writing the climb brain until it gets an overhaul // get the state for the climb brain from the list (there's only allowed to be one per list //plStateDataRecord *climbBrainVar = climbBrainListVar->GetStateDataRecord(0); //ISetClimbBrainFrom(avMod, climbBrainVar); } else { // get the (one element) drive brain list, if populated plSDStateVariable *driveBrainListVar = brainUnion->FindSDVar(BrainUnionVarNames::kDriveBrain); if(driveBrainListVar->IsUsed() && driveBrainListVar->GetCount() > 0) { // get the state for the drive brain from the list (there's only allowed to be one per list plStateDataRecord *driveBrainVar = driveBrainListVar->GetStateDataRecord(0); ISetDriveBrainFrom(avMod, driveBrainVar); } } } } } } } } // IPutCurrentStateIn --------------------------------------------------- // ------------------ void plAvatarSDLModifier::IPutCurrentStateIn(plStateDataRecord* dstState) { plSceneObject* sObj = GetTarget(); hsAssert(sObj, "plAvatarSDLModifier, nil target"); const plArmatureMod* kAvMod = (plArmatureMod*)sObj->GetModifierByType(plArmatureMod::Index()); plArmatureMod * avMod = const_cast(kAvMod); hsAssert(avMod, "nil avMod"); if(avMod) { IPutBaseAvatarStateIn(avMod, dstState); // create a brainUnion nested record plSDStateVariable* brainUnionArray = dstState->FindSDVar(plAvatarSDLModifier::kStrBrainStack); int nBrains = avMod->GetBrainCount(); brainUnionArray->Resize(nBrains - 1); // we skip the base brain for (int i = 1; i < nBrains; i++) { plStateDataRecord *brainUnion = brainUnionArray->GetStateDataRecord(i - 1); // create (or get) a nested array of climbBrain records (we'll only populate the first) plSDStateVariable* climbStateVar = brainUnion->FindSDVar(plAvatarSDLModifier::BrainUnionVarNames::kClimbBrain); climbStateVar->Resize(0); // create (or get) a nested array of genbrain records (we'll only populate the first) plSDStateVariable *genStateVar = brainUnion->FindSDVar(plAvatarSDLModifier::BrainUnionVarNames::kGenericBrain); genStateVar->Resize(0); // create (or get) a nested array of driveBrain records (we'll only populate the first) plSDStateVariable* driveStateVar = brainUnion->FindSDVar(plAvatarSDLModifier::BrainUnionVarNames::kDriveBrain); driveStateVar->Resize(0); plArmatureBrain *brain = avMod->GetBrain(i); if (plAvBrainClimb *climbBrain = plAvBrainClimb::ConvertNoRef(brain)) { // TEMP: Not read/writing the climb brain until it gets an overhaul //climbStateVar->Resize(1); //IPutClimbBrainIn(avMod, climbBrain, climbStateVar->GetStateDataRecord(0)); } else if(plAvBrainGeneric *genBrain = plAvBrainGeneric::ConvertNoRef(brain)) { genStateVar->Resize(1); // put the brain into the first slot in the array IPutGenericBrainIn(avMod, genBrain, genStateVar->GetStateDataRecord(0)); } else if (plAvBrainDrive *driveBrain = plAvBrainDrive::ConvertNoRef(brain)) { driveStateVar->Resize(1); IPutDriveBrainIn(avMod, driveBrain, driveStateVar->GetStateDataRecord(0)); } } } } void plAvatarSDLModifier::IPutClimbBrainIn(plArmatureMod *avMod, plAvBrainClimb *brain, plStateDataRecord* dstState) { brain->SaveToSDL(dstState); } void plAvatarSDLModifier::ISetClimbBrainFrom(plArmatureMod *avMod, const plStateDataRecord* srcState) { plAvBrainClimb *climbBrain = TRACKED_NEW plAvBrainClimb(); avMod->PushBrain(climbBrain); climbBrain->LoadFromSDL(srcState); } void plAvatarSDLModifier::IPutDriveBrainIn(plArmatureMod *avMod, plAvBrainDrive *brain, plStateDataRecord* dstState) { dstState->FindVar("unUsed")->Set(0); } void plAvatarSDLModifier::ISetDriveBrainFrom(plArmatureMod *avMod, const plStateDataRecord* src) { plAvBrainDrive *driveBrain = TRACKED_NEW plAvBrainDrive(); avMod->PushBrain(driveBrain); } // IPutGenericBrainIn -------------------------------------------------------------------------- void plAvatarSDLModifier::IPutGenericBrainIn(plArmatureMod * avMod, plAvBrainGeneric *genBrain, plStateDataRecord* dstState) { // get state of the brain: dstState->FindVar(GenericBrainVarNames::kStrCurrentStage)->Set(genBrain->GetCurStageNum()); dstState->FindVar(GenericBrainVarNames::kStrMovingForward)->Set(genBrain->GetForward()); dstState->FindVar(GenericBrainVarNames::kStrCallbackRcvr)->Set(genBrain->GetRecipient()); dstState->FindVar(GenericBrainVarNames::kStrExitFlags)->Set((int)genBrain->GetExitFlags()); dstState->FindVar(GenericBrainVarNames::kStrType)->Set((int)genBrain->GetType()); dstState->FindVar(GenericBrainVarNames::kStrMode)->Set((int)genBrain->GetMode()); dstState->FindVar(GenericBrainVarNames::kStrFadeIn)->Set(genBrain->GetFadeIn()); dstState->FindVar(GenericBrainVarNames::kStrFadeOut)->Set(genBrain->GetFadeOut()); dstState->FindVar(GenericBrainVarNames::kStrMoveMode)->Set((int)genBrain->GetMoveMode()); dstState->FindVar(GenericBrainVarNames::kStrBodyUsage)->Set((int)genBrain->GetBodyUsage()); // let's fill in the stages int stageCount = genBrain->GetStageCount(); plSDStateVariable* stagesVar = dstState->FindSDVar(GenericBrainVarNames::kStrStages); stagesVar->Resize(stageCount); for(int i = 0; i < stageCount; i++) { plAnimStage *stage = genBrain->GetStage(i); IPutStageIn(avMod, stage, stagesVar->GetStateDataRecord(i)); } } // ISetGenericBrainFrom ------------------------------------------------------------------------------- bool plAvatarSDLModifier::ISetGenericBrainFrom(plArmatureMod *avMod, const plStateDataRecord* srcState) { int i; hsBool success = true; int numStages=0; plSDStateVariable* stagesVar = srcState->FindSDVar(GenericBrainVarNames::kStrStages); if (stagesVar->IsUsed()) { numStages = stagesVar->GetCount(); if (!numStages) return false; } plAnimStageVec * stages = TRACKED_NEW plAnimStageVec(); for (int j = 0; j < numStages; j++) { plStateDataRecord* stageState = stagesVar->GetStateDataRecord(j); plAnimStage *newStage = IGetStageFrom(avMod, stageState); if (!newStage) success = false; stages->push_back(newStage); } int curStage; srcState->FindVar(GenericBrainVarNames::kStrCurrentStage)->Get(&curStage); if (curStage >= numStages) success = false; plKey callbackRcvr; srcState->FindVar(GenericBrainVarNames::kStrCallbackRcvr)->Get(&callbackRcvr); int exitFlags; srcState->FindVar(GenericBrainVarNames::kStrExitFlags)->Get(&exitFlags); if (exitFlags >= plAvBrainGeneric::kExitMaxFlag) success = false; int type; srcState->FindVar(GenericBrainVarNames::kStrType)->Get(&type); if (type >= plAvBrainGeneric::kNumBrainTypes) success = false; int mode; srcState->FindVar(GenericBrainVarNames::kStrMode)->Get(&mode); if (mode >= plAvBrainGeneric::kMaxMode) success = false; float fadeIn, fadeOut; srcState->FindVar(GenericBrainVarNames::kStrFadeIn)->Get(&fadeIn); srcState->FindVar(GenericBrainVarNames::kStrFadeOut)->Get(&fadeOut); int moveMode; srcState->FindVar(GenericBrainVarNames::kStrMoveMode)->Get(&moveMode); if (moveMode >= plAvBrainGeneric::kMaxMoveMode) success = false; int bodyUsage; srcState->FindVar(GenericBrainVarNames::kStrBodyUsage)->Get(&bodyUsage); if (bodyUsage >= plAGAnim::kBodyMax) success = false; if (!success) { for (i = 0; i < numStages; i++) { plAnimStage *s = (*stages)[i]; (*stages)[i] = nil; delete s; } delete stages; return false; } plAvBrainGeneric *newBrain = TRACKED_NEW plAvBrainGeneric(stages, nil, nil, callbackRcvr, exitFlags, fadeIn, fadeOut, static_cast(moveMode)); newBrain->SetType(static_cast(type)); newBrain->SetBodyUsage(static_cast(bodyUsage)); newBrain->SetCurStageNum(curStage); avMod->PushBrain(newBrain); return true; } // IGetStageFrom ---------------------------------------------------------------------------------------- plAnimStage * plAvatarSDLModifier::IGetStageFrom(plArmatureMod *avMod, const plStateDataRecord* srcState) { UInt32 notifyFlags=0; bool notifyEnter, notifyLoop, notifyAdv, notifyRegress; if (srcState->FindVar(StandardStageVarNames::kStrNotifyEnter)->Get(¬ifyEnter)) if(notifyEnter) notifyFlags &= plAnimStage::kNotifyEnter; if (srcState->FindVar(StandardStageVarNames::kStrNotifyLoop)->Get(¬ifyLoop)) if(notifyLoop) notifyFlags &= plAnimStage::kNotifyLoop; if (srcState->FindVar(StandardStageVarNames::kStrNotifyStageAdvance)->Get(¬ifyAdv)) if(notifyAdv) notifyFlags &= plAnimStage::kNotifyAdvance; if (srcState->FindVar(StandardStageVarNames::kStrNotifyStageRegress)->Get(¬ifyRegress)) if(notifyRegress) notifyFlags &= plAnimStage::kNotifyRegress; bool useLocal; if (srcState->FindVar(StandardStageVarNames::kStrUseGlobalCoords)->Get(&useLocal)) useLocal = !useLocal; char name[32]; srcState->FindVar(StandardStageVarNames::kStrName)->Get(name); plAGAnim *anim = avMod->FindCustomAnim(name); if (!anim) return nil; int fwd, bwd, adv, reg; srcState->FindVar(StandardStageVarNames::kStrForward)->Get(&fwd); if (fwd >= plAnimStage::kForwardMax) return nil; srcState->FindVar(StandardStageVarNames::kStrBackward)->Get(&bwd); if (bwd >= plAnimStage::kBackMax) return nil; srcState->FindVar(StandardStageVarNames::kStrStageAdvance)->Get(&adv); if (adv >= plAnimStage::kAdvanceMax) return nil; srcState->FindVar(StandardStageVarNames::kStrStageRegress)->Get(®); if (reg >= plAnimStage::kRegressMax) return nil; int numLoops; srcState->FindVar(StandardStageVarNames::kStrNumLoops)->Get(&numLoops); float localTime; srcState->FindVar(StandardStageVarNames::kStrLocalTime)->Get(&localTime); int curLoop; srcState->FindVar(StandardStageVarNames::kStrCurrentLoop)->Get(&curLoop); if (curLoop > numLoops && numLoops > 0) // numLoops == -1 means infinite looping return nil; bool isAttached; srcState->FindVar(StandardStageVarNames::kStrIsAttached)->Get(&isAttached); // ***!!! need to capture "advanceTo" and "regressTo" values!!! bool hackAdvanceToWrong = false, hackRegressToWrong = false; plAnimStage *newStage = TRACKED_NEW plAnimStage(name, (UInt8)notifyFlags, static_cast(fwd), static_cast(bwd), static_cast(adv), static_cast(reg), numLoops, hackAdvanceToWrong, 0, hackRegressToWrong, 0); newStage->SetLocalTime(localTime); newStage->SetLoopValue(curLoop); newStage->SetIsAttached(isAttached); return newStage; } // IPutStageIn --------------------------------------------------------------------------------------------- bool plAvatarSDLModifier::IPutStageIn(plArmatureMod *avMod, plAnimStage *stage, plStateDataRecord* dstState) { if(stage) { dstState->FindVar(StandardStageVarNames::kStrName)->Set(stage->GetAnimName()); dstState->FindVar(StandardStageVarNames::kStrNumLoops)->Set(stage->GetNumLoops()); dstState->FindVar(StandardStageVarNames::kStrForward)->Set((int)stage->GetForwardType()); dstState->FindVar(StandardStageVarNames::kStrBackward)->Set((int)stage->GetBackType()); dstState->FindVar(StandardStageVarNames::kStrStageAdvance)->Set((int)stage->GetAdvanceType()); dstState->FindVar(StandardStageVarNames::kStrStageRegress)->Set((int)stage->GetRegressType()); UInt32 notifies = stage->GetNotifyFlags(); dstState->FindVar(StandardStageVarNames::kStrNotifyEnter)->Set((notifies & plAnimStage::kNotifyEnter) ? true : false); dstState->FindVar(StandardStageVarNames::kStrNotifyLoop)->Set((notifies & plAnimStage::kNotifyLoop) ? true : false); dstState->FindVar(StandardStageVarNames::kStrNotifyStageAdvance)->Set((notifies & plAnimStage::kNotifyAdvance) ? true : false); dstState->FindVar(StandardStageVarNames::kStrNotifyStageRegress)->Set((notifies & plAnimStage::kNotifyRegress) ? true : false); // XXX dstState->FindVar(StandardStageVarNames::kStrUseGlobalCoords)->Set(stage->GetIsLocal()); dstState->FindVar(StandardStageVarNames::kStrLocalTime)->Set(stage->GetLocalTime()); //dstState->FindVar(StandardStageVarNames::kStrLength)->Set(0.0f); // NOT CURRENTLY USED // Well, if we're not using it, why are we still dirtying it and sending it across? Commented out. dstState->FindVar(StandardStageVarNames::kStrCurrentLoop)->Set(stage->GetLoopValue()); dstState->FindVar(StandardStageVarNames::kStrIsAttached)->Set(stage->GetIsAttached()); return true; } return false; } // IPutBaseAvatarStateIn ------------------------------------------------------------------------- void plAvatarSDLModifier::IPutBaseAvatarStateIn(plArmatureMod *avMod, plStateDataRecord* dstState) { if (avMod->GetStealthLevel() > 0) LogMsg(kLogDebug, "plAvatarSDLModifier::IPutBaseAvatarStateIn - Stealth level being set greater than zero"); dstState->FindVar(kStrInvisibilityLevel)->Set(avMod->GetStealthLevel()); } // ISetBaseAvatarStateFrom ------------------------------------------------------------------------------- void plAvatarSDLModifier::ISetBaseAvatarStateFrom(plArmatureMod *avMod, const plStateDataRecord* srcState) { // invisibility if (!avMod->IsLocallyOwned()) { int invisLevel; srcState->FindVar(kStrInvisibilityLevel)->Get(&invisLevel); if (invisLevel > 0) LogMsg(kLogDebug, "plAvatarSDLModifier::ISetBaseAvatarStateFrom - Stealth level greater than zero"); plNetClientMgr::GetInstance()->MakeCCRInvisible(avMod->GetTarget(0)->GetKey(), invisLevel); } }