/* 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: Christoph Renner co-programmer: */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD_ENTITY #include "loading/factory.h" #include "debug.h" #include "loading/load_param.h" #include "util/loading/load_param_xml.h" #include "state.h" #include "player.h" #include "playable.h" #include "actionbox_enemy.h" ObjectListDefinition(ActionboxEnemy); CREATE_FACTORY(ActionboxEnemy); ActionboxEnemy::ActionboxEnemy(const TiXmlElement* root) { PRINTF(0)("ActionboxEnemy\n"); this->registerObject(this, ActionboxEnemy::_objectList); this->toList(OM_GROUP_00); this->isActive = true; this->pitch = 0.0f; this->dPitch = 0.0; this->maxSpeed = 30; this->acceleration = 3; this->speed = 0; this->onEscape = false; if ( root ) this->loadParams( root ); } ActionboxEnemy::~ActionboxEnemy() { } void ActionboxEnemy::loadParams(const TiXmlElement* root) { WorldEntity::loadParams( root ); } void ActionboxEnemy::tick( float dt ) { this->bFire = false; if ( !State::getPlayer() || !State::getPlayer()->getPlayable() ) return; Vector playerDir = State::getPlayer()->getPlayable()->getAbsDir().apply( Vector(1, 0, 0) ); Vector dist = this->getAbsCoor() - State::getPlayer()->getPlayable()->getAbsCoor(); bool behindPlayer = playerDir.dot( dist ) < 0; if ( behindPlayer ) return; myDir = this->getAbsDir(); myCoor = this->getAbsCoor(); this->pitch += this->dPitch*dt; while ( pitch > 2*PI ) pitch -= 2*PI; while ( pitch < 0 ) pitch += 2*PI; myDir *= qPitch.inverse(); qPitch = Quaternion( pitch, Vector( 1, 0, 0 ) ); if ( isActive && State::getActionBox() ) { ActionBox* box = State::getActionBox(); if ( box->isPointInBox( this->getAbsCoor() ) ) { attackPlayer( box, dt ); } else { moveTowardsBox( box, dt ); onEscape = false; } } myDir *= qPitch; this->setAbsDir( myDir ); this->setAbsCoor( myCoor ); } void ActionboxEnemy::attackPlayer( ActionBox * box, float dt ) { if ( !State::getPlayer() || !State::getPlayer()->getPlayable() || !box ) return; float distance = (State::getPlayer()->getPlayable()->getAbsCoor() - getAbsCoor() ).len(); if ( distance > box->getDepth()/4.0 && !onEscape ) { Vector targetPos = State::getPlayer()->getPlayable()->getAbsCoor(); Vector targetDir = State::getPlayer()->getPlayable()->getAbsCoor()-this->getAbsCoor(); moveTowards( targetPos, targetDir, dt ); if ( this->getAbsDir().apply( Vector(1, 0, 0) ).dot(targetDir) > 0.9 ) { this->bFire = true; PRINTF(0)("FIRE\n"); } } else { if ( !onEscape ) { Vector ds = this->getAbsCoor() - State::getPlayer()->getPlayable()->getAbsCoor(); float projy = box->getAbsDir().apply( Vector(0, 1, 0) ).dot( ds ); float projz = box->getAbsDir().apply( Vector(0, 0, 1) ).dot( ds ); this->escapePoint = Vector( 0, projy, projz ); this->escapePoint.normalize(); this->escapePoint*= 2*box->getWidth_2(); PRINTF(0)("ESCAPE\n"); } onEscape = true; Vector rEscapePoint = box->getAbsDir().apply(escapePoint); Vector targetPos = State::getPlayer()->getPlayable()->getAbsCoor() + rEscapePoint; Vector targetDir = State::getPlayer()->getPlayable()->getAbsCoor() + rEscapePoint - this->getAbsCoor(); moveTowards( targetPos, targetDir, dt ); } } void ActionboxEnemy::moveTowards( Vector targetPos, Vector targetDir, float dt ) { Quaternion cur = myDir; Quaternion rx( dt, Vector( 0, 0, 1 ) ); Quaternion tmp1 = cur * rx; Quaternion tmp2 = cur * rx.inverse(); Quaternion dec; if ( tmp1.apply( Vector(1, 0, 0) ).dot(targetDir) > tmp2.apply( Vector(1, 0, 0)).dot(targetDir) ) dec = tmp1; else dec = tmp2; float dp = dec.apply( Vector(1, 0, 0) ).dot(Vector(0, 1, 0)); if ( dp > -0.9 && dp < 0.9 ) { cur = dec; } Quaternion ry( dt, cur.inverse().apply( Vector( 0, 1, 0 ) ) ); tmp1 = cur * ry; tmp2 = cur * ry.inverse(); if ( tmp1.apply( Vector(1, 0, 0) ).dot(targetDir) > tmp2.apply( Vector(1, 0, 0)).dot(targetDir) ) cur = tmp1; else cur = tmp2; myDir = cur; Vector fw = cur.apply( Vector(1, 0, 0) ); this->speed += this->acceleration*dt; if ( this->speed > this->maxSpeed ) this->speed = this->maxSpeed; this->myCoor += fw*speed*dt; } void ActionboxEnemy::moveTowardsBox( ActionBox * box, float dt ) { Vector targetPos = box->getAbsCoor() + box->getAbsDir().apply( Vector( 1, 0, 0 ) )*box->getDepth()*0.66f; Vector targetDir = targetPos - myCoor; moveTowards(targetPos, targetDir, dt); } void ActionboxEnemy::draw( ) const { #if 0 Vector fw = this->getAbsDir().apply( Vector( 1, 0, 0 ) ); fw.normalize(); fw = fw * 100; Vector mp = this->getAbsCoor(); Vector op = mp + fw; Vector targetPos = State::getPlayer()->getPlayable()->getAbsCoor(); Vector dv = targetPos - this->getAbsCoor(); dv.normalize(); dv *= 100; dv += mp; Vector spUp = this->getAbsDir().inverse().apply( this->getAbsDir().apply( Vector( 0, 1, 0 ) ) ); spUp.normalize(); spUp *= 100; spUp += mp; Vector up = fw.cross( dv ); up += mp; //PRINTF(0)("DEBUG\n"); //mp.debug(); //op.debug(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glPushAttrib(GL_ENABLE_BIT); glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); glLineWidth(2.0); 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(); glColor3f(0.0, 1.0, 0.0 ); glBegin(GL_LINE_STRIP); glVertex3f(mp.x, mp.y, mp.z); glVertex3f(dv.x, dv.y, dv.z); glEnd(); glColor3f(0.0, 0.0, 1.0 ); glBegin(GL_LINE_STRIP); glVertex3f(mp.x, mp.y, mp.z); glVertex3f(up.x, up.y, up.z); glEnd(); glColor3f(1.0, 1.0, 1.0 ); glBegin(GL_LINE_STRIP); glVertex3f(mp.x, mp.y, mp.z); glVertex3f(spUp.x, spUp.y, spUp.z); glEnd(); glPopMatrix(); #endif WorldEntity::draw(); }