void PathCamera::onNode(S32 node) { if (!isGhost()) onNode_callback(Con::getIntArg(node)); //.logicking >> we need to call onNode on datablock PathCameraData class, not on PathCamera if (!isGhost()) Con::executef(mDataBlock, "onNode", getIdString(), Con::getIntArg(node)); //.logicking << }
void Item::processTick(const Move* move) { Parent::processTick(move); // if (mCollisionObject && !--mCollisionTimeout) mCollisionObject = 0; // Warp to catch up to server if (delta.warpTicks > 0) { delta.warpTicks--; // Set new pos. MatrixF mat = mObjToWorld; mat.getColumn(3,&delta.pos); delta.pos += delta.warpOffset; mat.setColumn(3,delta.pos); Parent::setTransform(mat); // Backstepping delta.posVec.x = -delta.warpOffset.x; delta.posVec.y = -delta.warpOffset.y; delta.posVec.z = -delta.warpOffset.z; } else { if (isServerObject() && mAtRest && (mStatic == false && mDataBlock->sticky == false)) { if (++mAtRestCounter > csmAtRestTimer) { mAtRest = false; mAtRestCounter = 0; setMaskBits(PositionMask); } } if (!mStatic && !mAtRest && isHidden() == false) { updateVelocity(TickSec); updateWorkingCollisionSet(isGhost() ? sClientCollisionMask : sServerCollisionMask, TickSec); updatePos(isGhost() ? sClientCollisionMask : sServerCollisionMask, TickSec); } else { // Need to clear out last updatePos or warp interpolation delta.posVec.set(0,0,0); } } }
bool HoverVehicle::onNewDataBlock(GameBaseData* dptr, bool reload) { mDataBlock = dynamic_cast<HoverVehicleData*>(dptr); if (!mDataBlock || !Parent::onNewDataBlock(dptr,reload)) return false; if (isGhost()) { // Create the sounds ahead of time. This reduces runtime // costs and makes the system easier to understand. SFX_DELETE( mEngineSound ); SFX_DELETE( mFloatSound ); SFX_DELETE( mJetSound ); if ( mDataBlock->sound[HoverVehicleData::EngineSound] ) mEngineSound = SFX->createSource( mDataBlock->sound[HoverVehicleData::EngineSound], &getTransform() ); if ( !mDataBlock->sound[HoverVehicleData::FloatSound] ) mFloatSound = SFX->createSource( mDataBlock->sound[HoverVehicleData::FloatSound], &getTransform() ); if ( mDataBlock->sound[HoverVehicleData::JetSound] ) mJetSound = SFX->createSource( mDataBlock->sound[HoverVehicleData::JetSound], &getTransform() ); } // Todo: Uncomment if this is a "leaf" class scriptOnNewDataBlock(); return true; }
void Player::setAnimation(int anim) { bool curCrouching = (currentAnimation >= ANIM_CROUCH_MOVE_FIRST && currentAnimation <= ANIM_CROUCH_MOVE_LAST) || currentAnimation == ANIM_CROUCH_IDLE || currentAnimation == ANIM_CROUCH; if(anim == ANIM_CROUCH && curCrouching) return; if(anim == ANIM_STAND && !curCrouching) return; if (!myThread || !animIndex || anim < 0 || anim > NUM_ANIMS) return; if(isGhost() && data->animData[anim].soundTag != -1) TSFX::PlayAt(data->animData[anim].soundTag, getTransform(), Point3F(0, 0, 0)); myThread->SetSequence(animIndex[anim]); currentAnimation = anim; if (data->animData[currentAnimation].direction > 0) myThread->SetPosition (0); else myThread->SetPosition (0.99f); pickNewAnimation = false; }
bool Player::onAdd() { if(!Parent::onAdd()) return false; addToSet (PlayerSetId); if(isGhost()) { addToSet(SensorVisibleSetId); collisionMask = ClientCollisionMask; addToSet (SimLightSetId); addToSet (SimCameraMountSetId); lastAnimateTime = cg.currentTime; m_respawnStartTime = cg.currentTime; m_respawnEndTime = cg.currentTime + csm_respawnEffectTime; } else { collisionMask = ServerCollisionMask; } // Make we set our starting position in the container database. setPos(getPos()); lastFreeLook = prefFreeLook; return true; }
void Creature::onWalk(Direction& dir) { if(!hasCondition(CONDITION_DRUNK)) return; uint32_t r = random_range(0, 16); if(r > 4) return; switch(r) { case 0: dir = NORTH; break; case 1: dir = WEST; break; case 3: dir = SOUTH; break; case 4: dir = EAST; break; } g_game.internalCreatureSay(this, SPEAK_MONSTER_SAY, "Hicks!", isGhost()); }
void NexusFlagItem::dismount(DismountMode dismountMode) { if(isGhost()) // Server only return; if(getDatabase() == NULL) // must be in database, switching levels makes database NULL return; if(dismountMode == DISMOUNT_MOUNT_WAS_KILLED) { // Should getting shot up count as a flag drop event for statistics purposes? if(mMount && mMount->getClientInfo()) mMount->getClientInfo()->getStatistics()->mFlagDrop += mFlagCount + 1; dropFlags(mFlagCount + 1); // Drop at least one flag plus as many as the ship carries // Now delete the flag itself removeFromDatabase(false); deleteObject(); } else { GameType *gameType = getGame()->getGameType(); if(!gameType) // Crashed here once, don't know why, so I added the check return; gameType->itemDropped(mMount, this, dismountMode); // Sends messages; no flags actually dropped here; server only method dropFlags(mFlagCount); // Only dropping the flags we're carrying, not the "extra" one that comes when we die } }
void Trigger::potentialEnterObject(GameBase* enter) { if( (!mDataBlock || mDataBlock->isClientSide) && isServerObject() ) return; if( (mDataBlock && !mDataBlock->isClientSide) && isGhost() ) return; for (U32 i = 0; i < mObjects.size(); i++) { if (mObjects[i] == enter) return; } if (testObject(enter) == true) { mObjects.push_back(enter); deleteNotify(enter); if(!mEnterCommand.isEmpty()) { String command = String("%obj = ") + enter->getIdString() + ";" + mEnterCommand; Con::evaluate(command.c_str()); } if( mDataBlock ) mDataBlock->onEnterTrigger_callback( this, enter ); } }
void LineItem::setGeom(lua_State *L, S32 stackIndex) { Parent::setGeom(L, stackIndex); if(!isGhost()) s2cSetGeom(*GeomObject::getOutline()); }
void AIPlayer::updateMove(const Move* move) { if (!getControllingClient() && isGhost()) return; Parent::updateMove(move); }
void GameBase::scriptOnNewDataBlock() { // Script onNewDataBlock() must be called by the leaf class // after everything is loaded. if (mDataBlock && !isGhost()) mDataBlock->onNewDataBlock_callback( this ); }
//-------------------------------------------------------------------------- void GameBase::scriptOnAdd() { // Script onAdd() must be called by the leaf class after // everything is ready. if (mDataBlock && !isGhost()) mDataBlock->onAdd_callback( this ); }
bool NexusZone::collide(BfObject *hitObject) { if(isGhost()) return false; // From here on out, runs on server only if( ! (isShipType(hitObject->getObjectTypeNumber())) ) return false; Ship *theShip = static_cast<Ship *>(hitObject); if(theShip->mHasExploded) // Ignore collisions with exploded ships return false; GameType *gameType = getGame()->getGameType(); NexusGameType *nexusGameType = NULL; if(gameType && gameType->getGameTypeId() == NexusGame) nexusGameType = static_cast<NexusGameType *>(getGame()->getGameType()); if(nexusGameType && nexusGameType->isNexusOpen()) // Is the nexus open? nexusGameType->shipTouchNexus(theShip, this); return false; }
void GameBase::scriptOnRemove() { // Script onRemove() must be called by leaf class while // the object state is still valid. if (!isGhost() && mDataBlock) mDataBlock->onRemove_callback( this ); }
void TSStatic::reSkin() { if ( isGhost() && mShapeInstance && mSkinNameHandle.isValidString() ) { Vector<String> skins; String(mSkinNameHandle.getString()).split( ";", skins ); for (int i = 0; i < skins.size(); i++) { String oldSkin( mAppliedSkinName.c_str() ); String newSkin( skins[i] ); // Check if the skin handle contains an explicit "old" base string. This // allows all models to support skinning, even if they don't follow the // "base_xxx" material naming convention. S32 split = newSkin.find( '=' ); // "old=new" format skin? if ( split != String::NPos ) { oldSkin = newSkin.substr( 0, split ); newSkin = newSkin.erase( 0, split+1 ); } mShapeInstance->reSkin( newSkin, oldSkin ); mAppliedSkinName = newSkin; } } }
// Private helper function void NexusFlagItem::dropFlags(U32 flags) { if(!mMount.isValid()) return; // This is server only, folks -- avoids problem with adding flag on client when it doesn't really exist on server if(isGhost()) return; static const U32 MAX_DROP_FLAGS = 200; // If we drop too many flags, things just get bogged down. This limit is rarely hit. if(flags > MAX_DROP_FLAGS) { for(U32 i = MAX_DROP_FLAGS; i > 0; i--) { // By dividing and subtracting, it works by using integer divide, subtracting from "flags" left, // and the last loop is (i == 1), dropping exact amount using only limited FlagItems U32 flagValue = flags / i; getGame()->releaseFlag(mMount->getActualPos(), mMount->getActualVel(), flagValue); flags -= flagValue; } } else // Normal situation for(U32 i = 0; i < flags; i++) getGame()->releaseFlag(mMount->getActualPos(), mMount->getActualVel()); changeFlagCount(0); }
void TurretShape::updateDamageLevel() { if (!isGhost()) setDamageState((mDamage >= mDataBlock->maxDamage)? Destroyed: Enabled); if (mDamageThread) mShapeInstance->setPos(mDamageThread, mDamage / mDataBlock->destroyedLevel); }
bool survivesFire(eMonster m) { return isGhost(m) || m == moWitchWinter || m == moWitchGhost || m == moBomberbird || m == moTameBomberbird || m == moTameBomberbirdMoved || (isFriendly(m) && markOrb(itOrbWinter)) || isWorm(m) || m == moFireElemental || isDragon(m); }
void LineItem::onAddedToGame(Game *game) { Parent::onAddedToGame(game); if(!isGhost()) setScopeAlways(); }
bool survivesWater(eMonster m) { return m == moShark || m == moGreaterShark || m == moCShark || isGhost(m) || m == moWitchGhost || isBird(m) || m == moWaterElemental || m == moAirElemental || isWorm(m) || isIvy(m) || isDragon(m) || m == moTortoise; // Tortoises and Ivies survive, but don't go through water }
// Runs on client and server void NexusGameType::idle(BfObject::IdleCallPath path, U32 deltaT) { Parent::idle(path, deltaT); if(isGhost()) idle_client(deltaT); else idle_server(deltaT); }
void Turret::onPowerStateChange(GameBase* generator) { if (isGhost() == false && isPowered() == false && m_fireState == Firing) { unshoot(); } Parent::onPowerStateChange(generator); }
void Etherform::findContact(VectorF *contactNormal) { SceneObject *contactObject = NULL; Vector<SceneObject*> overlapObjects; _findContact(&contactObject, contactNormal, &overlapObjects ); // Check for triggers, corpses and items. const U32 filterMask = isGhost() ? sClientCollisionContactMask : sServerCollisionContactMask; for ( U32 i=0; i < overlapObjects.size(); i++ ) { SceneObject *obj = overlapObjects[i]; U32 objectMask = obj->getTypeMask(); if ( !( objectMask & filterMask ) ) continue; // Check: triggers, tactical zones, corpses and items... // if (objectMask & TriggerObjectType) { Trigger* pTrigger = static_cast<Trigger*>( obj ); pTrigger->potentialEnterObject(this); } else if (objectMask & TacticalZoneObjectType) { TacticalZone* pZone = static_cast<TacticalZone*>( obj ); pZone->potentialEnterObject(this); } else if (objectMask & CorpseObjectType) { // If we've overlapped the worldbounding boxes, then that's it... if ( getWorldBox().isOverlapped( obj->getWorldBox() ) ) { ShapeBase* col = static_cast<ShapeBase*>( obj ); queueCollision(col,getVelocity() - col->getVelocity()); } } else if (objectMask & ItemObjectType) { // If we've overlapped the worldbounding boxes, then that's it... Item* item = static_cast<Item*>( obj ); if ( getWorldBox().isOverlapped(item->getWorldBox()) && item->getCollisionObject() != this && !item->isHidden() ) queueCollision(item,getVelocity() - item->getVelocity()); } } mContactInfo.clear(); mContactInfo.contacted = contactObject != NULL; mContactInfo.contactObject = contactObject; if(mContactInfo.contacted) mContactInfo.contactNormal = *contactNormal; }
void Etherform::_handleCollision( const Collision &collision ) { // Track collisions if(!isGhost() && collision.object && collision.object != mContactInfo.contactObject) { queueCollision( collision.object, mVelocity - collision.object->getVelocity()); } }
//---------------------------------------------------------------------------- bool GameBase::setDataBlock(GameBaseData* dptr) { if (isGhost() || isProperlyAdded()) { if (mDataBlock != dptr) return onNewDataBlock(dptr,false); } else mDataBlock = dptr; return true; }
void SceneObject::onUnmount( SceneObject *obj, S32 node ) { clearNotify(obj); if ( !isGhost() ) { setMaskBits( MountedMask ); //onUnmount_callback( node ); } }
bool TSStatic::_createShape() { // Cleanup before we create. mCollisionDetails.clear(); mLOSDetails.clear(); SAFE_DELETE( mPhysicsRep ); SAFE_DELETE( mShapeInstance ); mAmbientThread = NULL; mShape = NULL; if (!mShapeName || mShapeName[0] == '\0') { Con::errorf( "TSStatic::_createShape() - No shape name!" ); return false; } mShapeHash = _StringTable::hashString(mShapeName); mShape = ResourceManager::get().load(mShapeName); if ( bool(mShape) == false ) { Con::errorf( "TSStatic::_createShape() - Unable to load shape: %s", mShapeName ); return false; } if ( isClientObject() && !mShape->preloadMaterialList(mShape.getPath()) && NetConnection::filesWereDownloaded() ) return false; mObjBox = mShape->bounds; resetWorldBox(); mShapeInstance = new TSShapeInstance( mShape, isClientObject() ); if( isGhost() ) { // Reapply the current skin mAppliedSkinName = ""; reSkin(); } prepCollision(); // Find the "ambient" animation if it exists S32 ambientSeq = mShape->findSequence("ambient"); if ( ambientSeq > -1 && !mAmbientThread ) mAmbientThread = mShapeInstance->addThread(); if ( mAmbientThread ) mShapeInstance->setSequence( mAmbientThread, ambientSeq, 0); return true; }
void Item::mountToShip(Ship *theShip) { TNLAssert(isGhost() || isInDatabase(), "Error, mount item not in database."); dismount(); mMount = theShip; if(theShip) theShip->mMountedItems.push_back(this); mIsMounted = true; setMaskBits(MountMask); }
void NexusZone::onAddedToGame(Game *theGame) { Parent::onAddedToGame(theGame); if(!isGhost()) setScopeAlways(); // Always visible! GameType *gameType = getGame()->getGameType(); if(gameType && gameType->getGameTypeId() == NexusGame) static_cast<NexusGameType *>(gameType)->addNexus(this); }
bool Turret::onAdd () { if (!Parent::onAdd ()) return false; if (isGhost() == false) { m_fireState = Waiting; m_beganState = wg->currentTime; } return true; }