/* * 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: Reto Luechinger */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD_ENTITY #include "adm_turret.h" #include "weapons/weapon_manager.h" #include "weapons/weapon.h" #include "lib/util/loading/factory.h" #include "world_entities/projectiles/projectile.h" #include "loading/load_param.h" #include "debug.h" #include "loading/load_param_xml.h" #include "environments/bsp_entity.h" #include "effects/explosion.h" ObjectListDefinition(AdmTurret); CREATE_FACTORY(AdmTurret); /** * Standard constructor */ AdmTurret::AdmTurret () { this->init(); } /** * destructs the turret, deletes allocated memory */ AdmTurret::~AdmTurret () { // will be deleted } /** * Constructor with XML Element */ AdmTurret::AdmTurret (const TiXmlElement* root) { this->init(); if (root != NULL) { this->loadParams(root); } } /** * XML Loader */ void AdmTurret::loadParams(const TiXmlElement* root) { if (root != NULL) { WorldEntity::loadParams(root); LoadParam(root, "target", this, AdmTurret, setTarget) .describe("The filename of the World Entity, that is to be shot at") .defaultValues(""); LoadParam(root, "type", this, AdmTurret, setType) .describe("floor|ceil"); LoadParamXML(root, "Cannons", this, AdmTurret, addCannons) .describe("add cannons to ADM"); LoadParamXML(root, "Sensor", this, AdmTurret, addSensor) .describe("add sensor to ADM"); LoadParamXML(root, "Weapon", this, AdmTurret, addWeapon) .describe("add weapon to ADM"); } // this->removeNodeFlags( PNODE_ALL ); this->addNodeFlags( PNODE_ROTATE_AND_MOVE ); this->addNodeFlags( PNODE_REPARENT_KEEP_POSITION ); //HACK this is needed to get the correct coordinates instead (0, 0, 0) this->updateNode( 0 ); if ( this->isCeil ) { Vector a = this->sensor->getRelCoor(); this->sensor->setRelCoor( -a.x, -a.y, -a.z ); a = this->cannons->getRelCoor(); this->cannons->setRelCoor( -a.x, -a.y, -a.z ); } } /** * Sets Target onto the World Entity with filename "target", given as String */ void AdmTurret::setTarget(const std::string& target) { WorldEntity* targetEntity = WorldEntity::objectList().getObject(target); if (targetEntity != NULL) { this->myTarget = targetEntity; } else { PRINTF(1)("ERROR ADMTURRET : Target %s does not exist\n", target.c_str()); } } void AdmTurret::setType( const std::string& type ) { if ( type == "floor" ) { this->isCeil = false; return; } if ( type == "ceil" ) { this->isCeil = true; return; } //invalid argument PRINTF(1)("%s is not a valid type for AdmTurret\n", type.c_str()); assert("false"); } void AdmTurret::init() { this->registerObject(this, AdmTurret::_objectList); this->setHealthMax(100); this->setHealth(100); this->bodyAngle = this->cannonAngle = 0.0f; this->isActive = true; this->range = 400; this->isCeil = false; this->playerVisible = false; this->weapon = NULL; } void AdmTurret::tick(float dt) { WorldEntity::tick(dt); if (this->weapon) this->weapon->fire(false); if ( this->getHealth() <= 0 ) { this->moveTowards( Vector(0, -1, 0), dt*2 ); } else { this->updatePlayerVisible(); //rotate sensor 2PI/sec this->sensor->setAbsDir( this->sensor->getAbsDir() * Quaternion( PI*2*dt, Vector( 0, -1, 0 ) ) ); Vector playerPos = this->myTarget->getAbsCoor() + Vector(0, 12, 0); Vector ds = playerPos - ( this->cannons->getAbsCoor() ); if ( isActive && ds.len() <= range && playerVisible ) { this->moveTowards( ds, dt); //if target within +/- 2.5 degrees of aim -> fire Vector dv1 = ds; dv1.normalize(); Vector dv2 = this->cannons->getAbsDir().apply( Vector(-1, 0, 0)); dv2.normalize(); float angle = dv1.dot(dv2); if (angle > 0.999) { if (this->weapon) this->weapon->fire(true); } } else { if ( !( isActive && ds.len() <= range ) ) this->moveTowards( Vector(0, -1, 0), dt ); } } } void AdmTurret::draw() const { WorldEntity::draw(); #if 0 glMatrixMode(GL_MODELVIEW); glPushMatrix(); glPushAttrib(GL_ENABLE_BIT); glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); glLineWidth(2.0); Vector mp = this->cannons->getAbsCoor(); Vector op = this->cannons->getAbsDir().apply( Vector(-1, 0, 0) ); op *= 100; op += mp; glColor3f(1.0, 0.0, 0.0 ); glBegin(GL_LINE_STRIP); glVertex3f(mp.x, mp.y, mp.z); glVertex3f(op.x, op.y, op.z); glEnd(); op = this->myTarget->getAbsCoor() - ( this->cannons->getAbsCoor() ); op += mp; glColor3f(0.0, 1.0, 0.0 ); glBegin(GL_LINE_STRIP); glVertex3f(mp.x, mp.y, mp.z); glVertex3f(op.x, op.y, op.z); glEnd(); glPopAttrib(); glPopMatrix(); #endif } void AdmTurret::collidesWith(WorldEntity* entity, const Vector& location) { } void AdmTurret::activate() { } void AdmTurret::deactivate() { } void AdmTurret::addCannons( const TiXmlElement * root ) { this->cannons = new DamageForwardingWorldEntity( this ); this->cannons->setParent(this); this->cannons->loadParams( root ); //this->cannons->addNodeFlags(PNODE_PROHIBIT_DELETE_WITH_PARENT); //this->cannons->addNodeFlags(PNODE_PROHIBIT_CHILD_DELETE); this->cannons->toList( getOMListNumber() ); this->cannons->setForwardDamageToParent( true ); } void AdmTurret::addWeapon( const TiXmlElement * root ) { this->weapon = new BspWeapon(getOMListNumber()); this->weapon->setParent( this->cannons ); this->weapon->loadParams(root); this->weapon->toList( getOMListNumber() ); //this->weapon->setAbsCoor( this->cannons->getAbsCoor() ); this->weapon->setAbsDir( this->weapon->getAbsDir() * Quaternion( PI, Vector(0, 1, 0) ) ); this->weapon->setForwardDamageToParent( true ); } void AdmTurret::addSensor( const TiXmlElement * root ) { this->sensor = new DamageForwardingWorldEntity( this ); this->sensor->setParent(this); this->sensor->loadParams( root ); //this->sensor->addNodeFlags(PNODE_PROHIBIT_DELETE_WITH_PARENT); //this->sensor->addNodeFlags(PNODE_PROHIBIT_CHILD_DELETE); } void AdmTurret::moveTowards( Vector targetDir, float dt ) { if ( this->cannons->getParent() != NullParent::getNullParent() ) { this->cannons->setParent( NullParent::getNullParent() ); this->cannons->shiftCoor( this->getAbsCoor() ); this->sensor->setParent( NullParent::getNullParent() ); this->sensor->shiftCoor( this->getAbsCoor() ); } targetDir.normalize(); float dAngle = dt; float bestResult = -1.0f; Quaternion bestBodyRot; Quaternion bestCannonRot; float bestBodyAngle = 0.0f; float bestCannonAngle = 0.0f; Quaternion baseRot(0, Vector(1, 0, 0)); if ( isCeil ) { baseRot = Quaternion( PI, Vector( 1, 0, 0 ) ); } for ( int dBodyAngle = -1; dBodyAngle<2; dBodyAngle++ ) { for ( int dCannonAngle = -1; dCannonAngle<2; dCannonAngle++ ) { float bodyAngle = this->bodyAngle + dBodyAngle*dAngle; float cannonAngle = this->cannonAngle + dCannonAngle*dAngle; while ( bodyAngle > 2*PI ) bodyAngle -= 2*PI; while ( bodyAngle < 0 ) bodyAngle += 2*PI; while ( cannonAngle > 2*PI ) cannonAngle -= 2*PI; while ( cannonAngle < 0 ) cannonAngle += 2*PI; Quaternion bodyRot( bodyAngle, Vector( 0, 1, 0 ) ); Quaternion cannonRot( cannonAngle, Vector( 0, 0, 1) ); bodyRot = baseRot * bodyRot; cannonRot = baseRot * cannonRot; float result = (bodyRot * cannonRot).apply( Vector( -1, 0, 0 ) ).dot( targetDir ); if ( result > bestResult ) { bestResult = result; bestBodyRot = bodyRot; bestBodyAngle = bodyAngle; bestCannonRot = cannonRot; bestCannonAngle = cannonAngle; } } } this->bodyAngle = bestBodyAngle; this->cannonAngle = bestCannonAngle; this->setAbsDir( bestBodyRot ); this->cannons->setAbsDir( bestBodyRot * bestCannonRot ); } void AdmTurret::updatePlayerVisible( ) { std::list::iterator entityIterator; // for all bsp managers check all entities Vector pos = this->cannons->getAbsCoor(); Vector dir = this->myTarget->getAbsCoor() - pos + Vector(0, 12, 0); this->playerVisible = true; for( ObjectList::const_iterator bspIterator = BspEntity::objectList().begin(); bspIterator != BspEntity::objectList().end(); bspIterator++) { float res = (dynamic_cast(*bspIterator)->getBspManager())->checkCollisionRay( pos, dir, dir.len() + 1 ); if ( res < dir.len() ) this->playerVisible = false; } } void AdmTurret::destroy( WorldEntity * killer ) { Explosion().explode(this->cannons,Vector(1,1,1)); }