/* 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: Christian Meyer */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD_ENTITY #include "executor/executor.h" #include "player.h" #include "track_manager.h" #include "objModel.h" #include "resource_manager.h" #include "factory.h" #include "weapons/weapon_manager.h" #include "weapons/test_gun.h" #include "weapons/turret.h" #include "weapons/cannon.h" #include "list.h" #include "event_handler.h" #include "event.h" using namespace std; CREATE_FACTORY(Player, CL_PLAYER); #define UP 0 #define DOWN 1 #define RIGHT 2 #define LEFT 3 #define TIME 4 /** * creates a new Player * @param isFree if the player is free */ Player::Player() { this->init(); } /** * loads a Players information from a specified file. * @param fileName the name of the File to load the player from (absolute path) */ Player::Player(const char* fileName) { this->init(); TiXmlDocument doc(fileName); if(!doc.LoadFile()) { PRINTF(2)("Loading file %s failed for player.\n", fileName); return; } this->loadParams(doc.RootElement()); } /** * creates a new Player from Xml Data * @param root the xml element containing player data @todo add more parameters to load */ Player::Player(const TiXmlElement* root) { this->init(); if (root != NULL) this->loadParams(root); //weapons: Weapon* wpRight = new TestGun(0); wpRight->setName("testGun Right"); Weapon* wpLeft = new TestGun(1); wpLeft->setName("testGun Left"); Weapon* cannon = dynamic_cast(Factory::getFirst()->fabricate(CL_CANNON)); cannon->setName("BFG"); this->weaponMan->addWeapon(wpLeft, 1, 0); this->weaponMan->addWeapon(wpRight,1 ,1); this->weaponMan->addWeapon(cannon, 0, 6); //this->weaponMan->addWeapon(turret, 3, 0); this->weaponMan->changeWeaponConfig(1); } /** * destructs the player, deletes alocated memory */ Player::~Player () { /* do not delete the weapons, they are contained in the pnode tree and will be deleted there. this only frees the memory allocated to save the list. */ delete this->weaponMan; if( this->outData) delete[] this->outData; if( this->inData) delete[] this->inData; } //#include "glgui_pushbutton.h" /** * initializes a Player */ void Player::init() { // this->setRelDir(Quaternion(M_PI, Vector(1,0,0))); this->setClassID(CL_PLAYER, "Player"); PRINTF(4)("PLAYER INIT\n"); travelSpeed = 15.0; bUp = bDown = bLeft = bRight = bAscend = bDescend = false; bFire = false; acceleration = 10.0; // GLGuiButton* button = new GLGuiPushButton(); // button->show(); // button->setLabel("orxonox"); // button->setBindNode(this); this->weaponMan = new WeaponManager(this); this->weaponMan->setSlotCount(7); this->weaponMan->setSlotPosition(0, Vector(-2.6, .1, -3.0)); this->weaponMan->setSlotCapability(0, WTYPE_ALLDIRS | WTYPE_DIRECTIONAL); this->weaponMan->setSlotPosition(1, Vector(-2.6, .1, 3.0)); this->weaponMan->setSlotCapability(1, WTYPE_ALLDIRS | WTYPE_DIRECTIONAL); this->weaponMan->setSlotPosition(2, Vector(-1.5, .5, -.5)); this->weaponMan->setSlotDirection(2, Quaternion(-M_PI_4*.5, Vector(1,0,0))); this->weaponMan->setSlotPosition(3, Vector(-1.5, .5, .5)); this->weaponMan->setSlotDirection(3, Quaternion(M_PI_4*.5, Vector(1,0,0))); this->weaponMan->setSlotPosition(4, Vector(-1.5, -.5, .5)); this->weaponMan->setSlotDirection(4, Quaternion(-M_PI_4*.5+M_PI, Vector(1,0,0))); this->weaponMan->setSlotPosition(5, Vector(-1.5, -.5, -.5)); this->weaponMan->setSlotDirection(5, Quaternion(+M_PI_4*.5-M_PI, Vector(1,0,0))); // this->weaponMan->setSlotPosition(6, Vector(-1, 0.0, 0)); this->weaponMan->setSlotCapability(6, WTYPE_ALLDIRS | WTYPE_DIRECTIONAL); // // this->weaponMan->setSlotPosition(8, Vector(-2.5, -0.3, -2.0)); // this->weaponMan->setSlotDirection(8, Quaternion(-M_PI, Vector(1,0,0))); // // this->weaponMan->setSlotPosition(9, Vector(-2.5, -0.3, 2.0)); // this->weaponMan->setSlotDirection(9, Quaternion(+M_PI, Vector(1,0,0)));: this->outBufferLength = 100; this->outLength = 0; this->recLength = 0; this->inBufferLength = 100; this->inLength = 0; this->sentLength = 0; this->outData = new byte[this->outBufferLength]; this->inData = new byte[this->inBufferLength]; } /** * loads the Settings of a Player from an XML-element. * @param root the XML-element to load the Player's properties from */ void Player::loadParams(const TiXmlElement* root) { static_cast(this)->loadParams(root); } /** * adds a weapon to the weapon list of player * @param weapon to add */ void Player::addWeapon(Weapon* weapon) { this->weaponMan->addWeapon(weapon); } /** * removes a weapon from the player * @param weapon to remove */ void Player::removeWeapon(Weapon* weapon) { this->weaponMan->removeWeapon(weapon); } /** * effect that occurs after the player is spawned */ void Player::postSpawn () { //setCollision(new CollisionCluster(1.0, Vector(0,0,0))); } /** * the action occuring if the player left the game */ void Player::leftWorld () {} WorldEntity* ref = NULL; /** * this function is called, when two entities collide * @param entity: the world entity with whom it collides * * Implement behaviour like damage application or other miscellaneous collision stuff in this function */ void Player::collidesWith(WorldEntity* entity, const Vector& location) { if (entity->isA(CL_TURRET_POWER_UP) && entity != ref) { this->ADDWEAPON(); ref = entity; } // PRINTF(3)("collision %s vs %s @ (%f,%f,%f)\n", this->getClassName(), entity->getClassName(), location.x, location.y, location.z); } /** * draws the player after transforming him. */ void Player::draw () const { glMatrixMode(GL_MODELVIEW); glPushMatrix(); /* translate */ glTranslatef (this->getAbsCoor ().x, this->getAbsCoor ().y, this->getAbsCoor ().z); /* rotate */ Vector tmpRot = this->getAbsDir().getSpacialAxis(); glRotatef (this->getAbsDir().getSpacialAxisAngle(), tmpRot.x, tmpRot.y, tmpRot.z ); this->model->draw(); glPopMatrix(); this->weaponMan->draw(); //this->debug(0); } /** * the function called for each passing timeSnap * @param time The timespan passed since last update */ void Player::tick (float time) { // player controlled movement this->move(time); this->weaponMan->tick(time); // weapon system manipulation this->weaponAction(); } /** * action if player moves * @param time the timeslice since the last frame */ void Player::move (float time) { Vector accel(0.0, 0.0, 0.0); Vector rot(0.0, 0.0, 0.0); float rotVal = 0.0; /* FIXME: calculating the direction and orthDirection every timeSlice is redundant! save it somewhere */ /* calculate the direction in which the craft is heading */ Vector direction (1.0, 0.0, 0.0); //direction = this->absDirection.apply (direction); Vector orthDirection (0.0, 0.0, 1.0); //orthDirection = orthDirection.cross (direction); if( this->outLength >= this->outBufferLength) return; if( this->bUp || this->bDown || this->bRight || this->bLeft) { this->outData[this->outLength++] = TIME; this->outData[this->outLength++] = (byte)(lround(time * 100.0f)); PRINTF(0)("Writing TIME = %i, or %f\n", this->outData[this->outLength-1], time); } if( this->bUp && this->getRelCoor().x < 20) { accel += direction; this->outData[this->outLength++] = UP; } if( this->bDown && this->getRelCoor().x > -5) { accel -= direction; this->outData[this->outLength++] = DOWN; } if( this->bLeft && TrackManager::getInstance()->getWidth() > -this->getRelCoor().z*2) { accel -=(orthDirection); rot +=Vector(1,0,0); rotVal -= .4; this->outData[this->outLength++] = LEFT; } if( this->bRight && TrackManager::getInstance()->getWidth() > this->getRelCoor().z*2) { accel += orthDirection; rot += Vector(1,0,0); rotVal += .4; this->outData[this->outLength++] = RIGHT; } if (this->bAscend ) { accel += Vector(0,1,0); rot += Vector(0,0,1); rotVal += .4; } if (this->bDescend ) { accel -= Vector(0,1,0); rot += Vector(0,0,1); rotVal -= .4; } Vector move = accel * time *acceleration; /* if (accel.z < 0) this->setRelDirSoft(Quaternion(-.4, accel), 5); else if (accel.z > 0) this->setRelDirSoft(Quaternion(.4, accel), 5); else*/ rot.normalize(); this->setRelDirSoft(Quaternion(rotVal, rot), 5); this->shiftCoor (move); } /** * weapon manipulation by the player */ void Player::weaponAction() { if( this->bFire) { this->weaponMan->fire(); } } /** * @todo switch statement ?? */ void Player::process(const Event &event) { if( event.type == KeyMapper::PEV_UP) this->bUp = event.bPressed; else if( event.type == KeyMapper::PEV_DOWN) this->bDown = event.bPressed; else if( event.type == KeyMapper::PEV_RIGHT) this->bRight= event.bPressed; else if( event.type == KeyMapper::PEV_LEFT) this->bLeft = event.bPressed; else if( event.type == KeyMapper::PEV_FIRE1) this->bFire = event.bPressed; else if( event.type == KeyMapper::PEV_NEXT_WEAPON && event.bPressed) this->weaponMan->nextWeaponConfig();//if( !event.bPressed) this->bWeaponChange = !this->bWeaponChange; else if ( event.type == KeyMapper::PEV_PREVIOUS_WEAPON && event.bPressed) this->weaponMan->previousWeaponConfig(); else if( event.type == SDLK_PAGEUP) this->bAscend = event.bPressed; //this->shiftCoor(0,.1,0); else if( event.type == SDLK_PAGEDOWN) this->bDescend = event.bPressed; //this->shiftCoor(0,-.1,0); } #include "weapons/aiming_turret.h" // FIXME THIS MIGHT BE CONSIDERED EITHER A FEATURE, OR A BUG void Player::ADDWEAPON() { Weapon* turret = NULL; if ((float)rand()/RAND_MAX < .1) { //if (this->weaponMan->hasFreeSlot(2, WTYPE_TURRET)) { turret = new Turret(); this->weaponMan->addWeapon(turret, 2); this->weaponMan->changeWeaponConfig(2); } } else { //if (this->weaponMan->hasFreeSlot(3)) { turret = new AimingTurret(); this->weaponMan->addWeapon(turret, 3); this->weaponMan->changeWeaponConfig(3); } } if(turret != NULL) { turret->setName("Turret"); turret->setStateDuration(WS_SHOOTING, (float)rand()/RAND_MAX*.5+.1); } } /** * write data to Synchronizeable */ void Player::writeBytes(const byte* data, int length) { PRINTF(0)("Player: got %i bytes of data\n", length); this->inLength = length; /* bytes: | 0 | 1 | CODE DIST CODE: 0 : Up 1 : Down 2 : Right 3 : Left 4 : TIME DIST: Coordinate diff multiplied by 100 and casted to a byte: byte a = (byte)(x * 100) */ float time = 0.0f; Vector accel(0.0, 0.0, 0.0); Vector direction (1.0, 0.0, 0.0); Vector orthDirection (0.0, 0.0, 1.0); byte code = 0; /* iterate through all bytes */ for( int i = 0; i < length; i++) { code = data[i]; /* is it a time code? */ if( code == TIME) { /* is it the first time */ if( time > 0.0f ) { /* apply movement */ Vector move = accel * time; if (accel.z < 0) this->setRelDirSoft(Quaternion(-.4, Vector(1,0,0)), 5); else if (accel.z > 0) this->setRelDirSoft(Quaternion(.4, Vector(1,0,0)), 5); else this->setRelDirSoft(Quaternion(0, Vector(1,0,0)), 5); this->shiftCoor (move); } /* read out new movement */ time = (float)(data[++i] / 100.0f); PRINTF(0)("Got time: %f msec\n", time); } else if( code == UP && this->getRelCoor().x < 20) accel = accel+(direction*acceleration); else if( code == DOWN && this->getRelCoor().x > -5) accel = accel -(direction*acceleration); else if( code == LEFT && TrackManager::getInstance()->getWidth() > -this->getRelCoor().z*2) accel = accel - (orthDirection*acceleration); else if( code == RIGHT && TrackManager::getInstance()->getWidth() > this->getRelCoor().z*2) accel = accel + (orthDirection*acceleration); } /* and debug output */ this->writeDebug(); } /** * read data from Synchronizeable */ int Player::readBytes(byte* data) { PRINTF(0)("Player: sent %i bytes of data\n", this->sentLength); /* copy data */ for( int i = 0; i < this->outLength; ++i) data[i] = this->outData[i]; /* debug msg */ this->readDebug(); int length = this->outLength; this->outLength = 0; /* return the length of the test */ return length; } void Player::writeDebug() const { } void Player::readDebug() const { }