/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx 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 2, or (at your option) any later version. ### File Specific: main-programmer: Patrick Boenzli co-programmer: ... */ #include "fps_player.h" #include "interactive_model.h" #include "state.h" #include "tools/camera.h" #include "player.h" #include "src/lib/util/loading/factory.h" #include "md2/md2Model.h" #include "weapons/weapon_manager.h" #include "weapons/test_gun.h" #include "weapons/turret.h" #include "weapons/cannon.h" #include "weapons/fps_sniper_rifle.h" #include "weapons/aiming_system.h" #include "aabb.h" #include "environments/bsp_entity.h" #include "key_mapper.h" #include "debug.h" #include "shared_network_data.h" #include "event_handler.h" #include "story_entity.h" ObjectListDefinition(FPSPlayer); CREATE_FACTORY(FPSPlayer); #include "script_class.h" CREATE_SCRIPTABLE_CLASS(FPSPlayer, addMethod("setAbsCoor", Executor3(&PNode::setAbsCoor)) ->addMethod("getAbsCoorX", Executor0ret(&PNode::getAbsCoorX)) ->addMethod("getAbsCoorY", Executor0ret(&PNode::getAbsCoorY)) ->addMethod("getAbsCoorZ", Executor0ret(&PNode::getAbsCoorZ)) ->addMethod("displayHUDText", Executor1(&FPSPlayer::displayHUDText)) ); /** * destructs the FPSPlayer, deletes alocated memory */ FPSPlayer::~FPSPlayer () { this->setPlayer(NULL); } /** * creates a new FPSPlayer from Xml Data * @param root the xml element containing FPSPlayer data * */ FPSPlayer::FPSPlayer(const TiXmlElement* root) { if (root != NULL) this->loadParams(root); this->updateNode(0.001); this->init(); } /** * initializes a FPSPlayer */ void FPSPlayer::init() { this->registerObject(this, FPSPlayer::_objectList); this->bLeft = false; this->bRight = false; this->bForward = false; this->bBackward = false; this->bJump = false; this->bPosBut = false; this->bFire = false; this->bFire2 = false; this->changeZoom = true; this->inZoomMode = false; this->changingZoom = false; this->xMouse = 0.0f; this->yMouse = 0.0f; this->setHealthMax(100); this->setHealth(80); this->fallVelocity = 0.0f; this->jumpAcceleration = 0.0f; this->cameraNode = new PNode(); this->cameraNode->setParent(this); this->attitude = this->getAbsDir().getAttitude(); this->heading = this->getAbsDir().getHeading(); //add events to the eventlist registerEvent(KeyMapper::PEV_FORWARD); registerEvent(KeyMapper::PEV_BACKWARD); registerEvent(KeyMapper::PEV_LEFT); registerEvent(KeyMapper::PEV_RIGHT); registerEvent(KeyMapper::PEV_FIRE1); registerEvent(KeyMapper::PEV_FIRE2); registerEvent(KeyMapper::PEV_JUMP); registerEvent(KeyMapper::PEV_CROUCH); registerEvent(KeyMapper::PEV_FIRE1); registerEvent(EV_MOUSE_MOTION); this->deadBox = NULL; // weapon manager for the fps dynamic_cast(this->getWeaponManager().getFixedTarget())->setVisibility( false); //this->aimingSystem = new AimingSystem(this); #if 1 this->getWeaponManager().changeWeaponConfig(1); this->getWeaponManager().setSlotCount(1); //this->getWeaponManager().setSlotDirection(0, Quaternion(M_PI_4*-0.55f, Vector(0,0,1))); this->getWeaponManager().setSlotCapability(0, WTYPE_ALLDIRS | WTYPE_DIRECTIONAL); /*this->getWeaponManager().setSlotDirection(1, Quaternion(M_PI_4*.5, Vector(1,0,0))); this->getWeaponManager().setSlotPosition(0, Vector(1.5, -0.7, 1.1)); this->getWeaponManager().setSlotPosition(1, Vector(5.0, 0.0, 0.0));*/ this->getWeaponManager().setParentNode(this->cameraNode); this->cameraNode->addNodeFlags(PNODE_PROHIBIT_CHILD_DELETE); this->getWeaponManager().setRotationSpeed(0); this->getWeaponManager().getFixedTarget()->setParent(this->cameraNode); this->getWeaponManager().getFixedTarget()->setParentMode(PNODE_ALL); this->getWeaponManager().getFixedTarget()->setRelCoor(10,0,0); if( true /*State::isOnline()*/ ) { weapon = new FPSSniperRifle(0); weapon->setName("testGun Right"); this->addWeapon(weapon,1, 0); weapon->toList( this->getOMListNumber() ); weapon->setParent( this->cameraNode ); weapon->setForwardDamageToParent( true ); //wpRight->requestAction( WA_ACTIVATE ); //wpRight->addChild(this->aimingSystem); //this->toList( OM_PLAYERS ); } #else FPSSniperRifle* wpRight = new FPSSniperRifle(0); wpRight->setName("testGun Right"); wpRight->toList( this->getOMListNumber() ); wpRight->setParent( &this->cameraNode ); this->weaponMan.setParentEntity( this ); this->weaponMan.setSlotCount(2); this->weaponMan.createWeaponSlot(0, 0, 0, 0, WTYPE_ALLDIRS | WTYPE_DIRECTIONAL); //this->weaponMan.createWeaponSlot(1, 0, 0, 0, WTYPE_ALLDIRS | WTYPE_DIRECTIONAL); this->weaponMan.addWeapon(wpRight, 0, 0); this->weaponMan.changeWeaponConfig(0); Playable::weaponConfigChanged(); this->weaponMan.getFixedTarget()->setParent(&this->cameraNode ); this->weaponMan.getFixedTarget()->setRelCoor( 100000,0,0 ); #endif // network registration registerVar( new SynchronizeableBool( &bLeft, &bLeft, "bLeft", PERMISSION_OWNER ) ); registerVar( new SynchronizeableBool( &bRight, &bRight, "bRight", PERMISSION_OWNER ) ); registerVar( new SynchronizeableBool( &bForward, &bForward, "bForward", PERMISSION_OWNER ) ); registerVar( new SynchronizeableBool( &bBackward, &bBackward, "bBackward", PERMISSION_OWNER ) ); registerVar( new SynchronizeableBool( &bJump, &bJump, "bJump", PERMISSION_OWNER ) ); registerVar( new SynchronizeableFloat( &heading, &heading, "heading", PERMISSION_OWNER ) ); registerVar( new SynchronizeableFloat( &attitude, &attitude, "attitude", PERMISSION_OWNER ) ); //subscribe to collision reaction this->subscribeReaction(CoRe::CREngine::CR_PHYSICS_FULL_WALK, BspEntity::staticClassID()); this->initWeapon = false; this->damageTicker = 0.0f; } /** * loads the Settings of a FPSPlayer from an XML-element. * @param root the XML-element to load the Spaceship's properties from */ void FPSPlayer::loadParams(const TiXmlElement* root) { Playable::loadParams(root); } void FPSPlayer::hit(float damage, WorldEntity* killer) { WorldEntity::hit(damage, killer); if (this->hasPlayer()) this->getCurrentPlayer()->hud().getHit(); } /** * was probabably designed for setting direction of FPSPlayer * but hey, this connot work like this, can it? */ void FPSPlayer::setPlayDirection(const Quaternion& quat, float speed) { this->attitude = this->getAbsDir().getAttitude(); this->heading = this->getAbsDir().getHeading(); } /** * Resets FPSPlayer stats and freezes its moving directions * */ void FPSPlayer::reset() { this->bLeft = false; this->bRight = false; this->bForward = false; this->bBackward = false; this->xMouse = 0.0f; this->yMouse = 0.0f; this->inZoomMode = false; this->setHealth(80); } /** * Defines what happens to camera and other important elements when changing * into FPS-view */ void FPSPlayer::enter() { dynamic_cast(this->getWeaponManager().getFixedTarget())->setVisibility( true ); State::getCameraNode()->setParentSoft(this->cameraNode); State::getCameraTargetNode()->setParentSoft(this->cameraNode); State::getCamera()->setViewMode(Camera::ViewFPS); this->getWeaponManager().getFixedTarget()->setParent(this->cameraNode); //this->getWeaponManager().getFixedTarget()->setParentMode(PNODE_ALL); //this->getWeaponManager().getFixedTarget()->setRelCoor(100,0,0); if ( !State::isOnline() ) { this->respawn(); } } /** * Defines what happens if active player leaves FPSPlayer * (basicly hides crosshair and frees camera) */ void FPSPlayer::leave() { dynamic_cast(this->getWeaponManager().getFixedTarget())->setVisibility( false); this->detachCamera(); } /** * the function called for each passing timeSnap * @param time The timespan passed since last update */ void FPSPlayer::tick (float time) { if ( deadBox != NULL ) { OrxGui::GLGuiHandler::getInstance()->tick( time ); } // Second init-step if ( !this->initWeapon ) { this->initWeapon = true; this->cameraNode->setParentMode(PNODE_ROTATE_AND_MOVE); this->getWeaponManager().getParentNode()->setParentMode(PNODE_ROTATE_AND_MOVE); this->getWeaponManager().getFixedTarget()->setParent(this->cameraNode); //this->getWeaponManager().getFixedTarget()->setParentMode(PNODE_ROTATE_AND_MOVE); State::getCamera()->setViewMode(Camera::ViewFPS); } // end of second init-step // This box represents the dimension of the used model AABB* box = this->getModelAABB(); if( box != NULL) { float f = 1.0; if( this->bCrouch ) f = 0.3*f; this->cameraNode->setRelCoor(0, box->halfLength[1] * f, 0); // this->weaponMan.setRelCoor(0, box->halfLength[1] * f, 0); // this->cameraNode.setRelCoor(10, box->halfLength[1] * f, 0); // float v = 0.1f; // unused variable //this->getWeaponManager().setSlotPosition(0, Vector(-8.0, box->halfLength[1] * v, 1.1)); //this->getWeaponManager().setSlotPosition(1, Vector(5.0, box->halfLength[1] * v, 0.0)); //this->getWeaponManager().setSlotDirection( 0, Quaternion( 0.04, Vector( 0, 0, 1 ) ) ); } /* if( this->bFire2 ) { // to change Zoom on click if( this->changeZoom ) { this->changeZoom = false; if( this->inZoomMode ) { State::getCamera()->setViewMode(Camera::ViewFPS); this->inZoomMode = false; } else { State::getCamera()->setViewMode(Camera::ViewFPSZoom); this->inZoomMode = true; } } } else { this->changeZoom = true; }*/ if( this->bFire2 ) { if( this->changeZoom ) { if( !this->inZoomMode || this->changingZoom ) { this->inZoomMode = true; this->changingZoom = true; float fovy = State::getCamera()->getFovy(); if( fovy > 30 ) State::getCamera()->setFovy( fovy - 10*time ); } else { State::getCamera()->setViewMode(Camera::ViewFPS); this->inZoomMode = false; this->changeZoom = false; } } } else { this->changeZoom = true; this->changingZoom = false; } this->getWeaponManager().tick(time); if( this->bFire) { this->getWeaponManager().fire(); } if( ( xMouse != 0 || yMouse != 0 ) && (this->getOwner() == SharedNetworkData::getInstance()->getHostID() || !State::isOnline() ) ) { xMouse *= time ; yMouse *= time ; float amount; if( this->inZoomMode ) amount = 2.; else amount = 5.; heading -= xMouse/amount; attitude-= yMouse/amount; if ( attitude > 1.95 ) attitude = 1.95; else if ( attitude < -1.07 ) attitude = -1.07; xMouse = yMouse = 0; } this->setAbsDir(Quaternion(heading, Vector(0,1,0))); this->cameraNode->setRelDir(Quaternion( attitude, Vector( 0, 0, 1 ) )); Vector velocity; if ( this->bForward ) { velocity += this->getAbsDirX(); } if ( this->bBackward ) { velocity -= this->getAbsDirX(); } if ( this->bRight ) { velocity += this->getAbsDirZ(); } if ( this->bLeft ) { velocity -= this->getAbsDirZ(); } // Uncomment this if you want your current position to be prined to the console when you press the jump button /* if( this->bJump) { printf("panicGuy:runTo( %f, %f, %f ) \n", this->getAbsCoorX(), this->getAbsCoorY(), this->getAbsCoorZ() ); this->bJump = false; }*/ int speed; if( this->bCrouch ) speed = 50; else speed = 100; velocity *= speed; if( this->getModel( 0) != NULL && this->getModel(0)->isA(InteractiveModel::staticClassID())) { if( this->bJump) { if( this->jumpAcceleration < 1.0f) { this->jumpAcceleration = 300.0f; if( ((InteractiveModel*)this->getModel(0))->getAnimation() != JUMP) ((InteractiveModel*)this->getModel(0))->setAnimation(JUMP); } } else if(velocity.len() != 0.0f) { if( this->bCrouch ) { if( ((InteractiveModel*)this->getModel(0))->getAnimation() != CROUCH_WALK) ((InteractiveModel*)this->getModel(0))->setAnimation(CROUCH_WALK); } else { if( ((InteractiveModel*)this->getModel(0))->getAnimation() != RUN) ((InteractiveModel*)this->getModel(0))->setAnimation(RUN); } } else { if( this->bCrouch ) { if( ((InteractiveModel*)this->getModel(0))->getAnimation() != CROUCH_STAND) ((InteractiveModel*)this->getModel(0))->setAnimation(CROUCH_STAND); } else { if( ((InteractiveModel*)this->getModel(0))->getAnimation() != STAND) ((InteractiveModel*)this->getModel(0))->setAnimation(STAND); } } if( this->bFire ) { if( this->bCrouch ) { if( ((InteractiveModel*)this->getModel(0))->getAnimation() != CROUCH_ATTACK) ((InteractiveModel*)this->getModel(0))->setAnimation(CROUCH_ATTACK); } else { if( ((InteractiveModel*)this->getModel(0))->getAnimation() != ATTACK) ((InteractiveModel*)this->getModel(0))->setAnimation(ATTACK); } } } velocity.y += this->jumpAcceleration; if( this->jumpAcceleration > 1.0f) this->jumpAcceleration *= pow(0.9f,time*100); // physical falling of the player if( !this->isOnGround()) { if(this->fallVelocity + 300.0F*time < 10000.0f)this->fallVelocity += 300.0f * time; velocity -= Vector(0.0, 1.0, 0.0) * this->fallVelocity; // PRINTF(0)("vel %f\n", this->fallVelocity); } else { this->fallVelocity = 0.0f; } if((velocity * time).len() < 10.0f) this->shiftCoor( velocity*time ); else { velocity.normalize(); velocity *= 10.0f; this->shiftCoor( velocity ); } if( likely(this->getModel(0) != NULL) && this->getModel(0)->isA(InteractiveModel::staticClassID())) { ((InteractiveModel*)this->getModel(0))->tick(time); } this->setOnGround(false); } /** * draws the MD2Creature after transforming it. */ void FPSPlayer::draw () const { // only draw if this entity is not the player since the player nevers sees himself if( this->getCurrentPlayer() == NULL) WorldEntity::draw(); } /** * checks events */ void FPSPlayer::process(const Event &event) { Playable::process(event); if( event.type == KeyMapper::PEV_LEFT) this->bLeft = event.bPressed; else if( event.type == KeyMapper::PEV_RIGHT) this->bRight = event.bPressed; else if( event.type == KeyMapper::PEV_FORWARD) this->bForward = event.bPressed; //this->shiftCoor(0,.1,0); else if( event.type == KeyMapper::PEV_BACKWARD) this->bBackward = event.bPressed; //this->shiftCoor(0,-.1,0); else if( event.type == KeyMapper::PEV_JUMP) this->bJump = event.bPressed; else if( event.type == KeyMapper::PEV_FIRE1) this->bFire = event.bPressed; else if( event.type == KeyMapper::PEV_FIRE2) this->bFire2 = event.bPressed; else if( event.type == KeyMapper::PEV_CROUCH) this->bCrouch = event.bPressed; else if( event.type == EV_MOUSE_MOTION) { this->xMouse += event.xRel; this->yMouse += event.yRel; } } /** * respawns FPSplayer */ void FPSPlayer::respawn( ) { if( State::isOnline()) toList( OM_PLAYERS ); this->damageTicker = 0.0f; Playable::respawn(); } /** * Kills the FPSplayer defining its killer */ void FPSPlayer::destroy( WorldEntity* killer ) { Playable::destroy( killer ); this->showDeadScreen(); myList = this->getOMListNumber(); toList( OM_DEAD ); } void FPSPlayer::displayHUDText( const std::string& message ) { State::getPlayer()->hud().notifyUser(message); } void FPSPlayer::onButtonContinue( ) { OrxGui::GLGuiHandler::getInstance()->deactivateCursor( true ); EventHandler::getInstance()->popState(); WorldEntity::reset(); toList( myList ); deadBox->hideAll(); } void FPSPlayer::onButtonExit( ) { State::getCurrentStoryEntity()->setNextStoryID( 0 ); State::getCurrentStoryEntity()->stop(); } void FPSPlayer::showDeadScreen( ) { EventHandler::getInstance()->pushState( ES_MENU ); OrxGui::GLGuiHandler::getInstance()->activateCursor(); if ( deadBox ) delete deadBox; deadBox = new OrxGui::GLGuiBox(); deadBox->setAbsCoor2D( 100, 100 ); OrxGui::GLGuiText* text = new OrxGui::GLGuiText(); text->setText( "Game Over! - You died!" ); OrxGui::GLGuiPushButton* exitButton = new OrxGui::GLGuiPushButton( "exit" ); exitButton->released.connect(this, &FPSPlayer::onButtonExit); OrxGui::GLGuiPushButton* continueButton = new OrxGui::GLGuiPushButton( "continue" ); continueButton->released.connect(this, &FPSPlayer::onButtonContinue); deadBox->pack( text ); deadBox->pack( continueButton ); deadBox->pack( exitButton ); deadBox->showAll(); }