/* 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: */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD_ENTITY #include "util/loading/factory.h" #include "util/loading/load_param.h" #include "interactive_model.h" #include "md2/md2Model.h" #include "sound_buffer.h" #include "loading/resource_manager.h" #include "generic_npc.h" #include "animation/animation3d.h" using namespace std; CREATE_FACTORY(GenericNPC, CL_GENERIC_NPC); #include "script_class.h" CREATE_SCRIPTABLE_CLASS(GenericNPC, CL_GENERIC_NPC, //addMethod("walkTo", ExecutorLua7ret(&GenericNPC::walkTo)) addMethod("walkTo", ExecutorLua3ret(&GenericNPC::walkTo)) ); /** * constructor */ GenericNPC::GenericNPC(const TiXmlElement* root) : NPC(root) { this->init(); if (root != NULL) this->loadParams(root); } GenericNPC::GenericNPC() : NPC(NULL) { } /** * deconstructor */ GenericNPC::~GenericNPC () { if( this->currentAnim != NULL) delete this->currentAnim; } /** * initializing the npc enity */ void GenericNPC::init() { this->setClassID(CL_GENERIC_NPC, "GenericNPC"); this->toList(OM_GROUP_00); if (this->soundBuffer != NULL) ResourceManager::getInstance()->unload(this->soundBuffer); this->soundBuffer = (OrxSound::SoundBuffer*)ResourceManager::getInstance()->load("sound/rain.wav", WAV); // collision reaction registration // this->subscribeReaction(CREngine::CR_PHYSICS_GROUND_WALK, CL_BSP_ENTITY); } /** * loads the Settings of a MD2Creature from an XML-element. * @param root the XML-element to load the MD2Creature's properties from */ void GenericNPC::loadParams(const TiXmlElement* root) { NPC::loadParams(root); } /** * sets the animation of this npc * @param anumationIndex: the animation index * @param anumPlaybackMode: the playback mode */ void GenericNPC::setAnimation(int animationIndex, int animPlaybackMode) { if( likely(this->getModel(0) != NULL)) ((InteractiveModel*)this->getModel(0))->setAnimation(animationIndex, animPlaybackMode); } /** * sets the animation of this npc * @param anumationIndex: the animation index * @param anumPlaybackMode: the playback mode */ void GenericNPC::playAnimation(int animationIndex, int animPlaybackMode) { if( likely(this->getModel(0) != NULL)) ((InteractiveModel*)this->getModel(0))->setAnimation(animationIndex, animPlaybackMode); } /** * play a sound * @param filename: name of the file */ void GenericNPC::playSound(std::string filename) { } /** * walt to * @param coordinate: coordinate to go to */ float GenericNPC::walkTo(float x, float y, float z, float qu, float qx, float qy, float qz) { Vector destCoor = Vector(x, y, z); Quaternion destDir = Quaternion(Vector(qx, qy, qz), qu); // check if this is the current goal if( this->destCoor != destCoor || this->destDir != destDir) { this->destCoor = destCoor; this->destDir = destDir; float time = 10.0f; if( this->currentAnim != NULL) delete this->currentAnim; this->currentAnim = new Animation3D(this); this->currentAnim->addKeyFrame(this->getAbsCoor(), this->getAbsDir(), 0.1f, ANIM_LINEAR, ANIM_LINEAR); this->currentAnim->addKeyFrame(this->destCoor, this->destDir, time, ANIM_LINEAR, ANIM_LINEAR); this->currentAnim->addKeyFrame(this->getAbsCoor(), this->getAbsDir(), time, ANIM_LINEAR, ANIM_LINEAR); this->currentAnim->addKeyFrame(this->destCoor, this->destDir, time, ANIM_LINEAR, ANIM_LINEAR); this->currentAnim->setInfinity(ANIM_INF_CONSTANT); this->currentAnim->play(); this->setAnimation(RUN, MD2_ANIM_LOOP); } // calculate the distance Vector distance = this->getAbsCoor() - this->destCoor; return distance.len(); } /** * walk to a specific place with direction * * @param x: x coordinate to go to * @param y: y coordinate to go to * @param z: z coordinate to go to * * without turning itself */ float GenericNPC::walkTo(float x, float y, float z) { Quaternion q = this->getAbsDir(); //printf("%s moving to %f, %f, %f \n",this->getName(),x,y,z); return this->walkTo(x, y, z, q.w, q.v.x, q.v.y, q.v.z); } /** * walk to a specific place with direction * * @param x: x coordinate to go to * @param y: y coordinate to go to * @param qu: angle to rotate * @param qx: x coordinate of rotation vector * @param qy: y coordinate of rotation vector * @param qz: z coordinate of rotation vector * */ float GenericNPC::walkTo(float x, float y, float qu, float qx, float qy, float qz) { return this->walkTo(x, y, 0.0f, qu, qx, qy, qz); } /** * walk to a specific place with direction * * @param coor: vector place * @param dir: direction * */ float GenericNPC::walkTo(const Vector& coor, const Quaternion& dir) { return this->walkTo(coor.x, coor.y, coor.z, dir.w, dir.v.x, dir.v.y, dir.v.z); } /** * run to a specific place with direction * * @param x: x coordinate to go to * @param y: y coordinate to go to * @param z: z coordinate to go to * @param qu: angle to rotate * @param qx: x coordinate of rotation vector * @param qy: y coordinate of rotation vector * @param qz: z coordinate of rotation vector * */ float GenericNPC::runTo(float x, float y, float z, float qu, float qx, float qy, float qz) { Vector destCoor = Vector(x, y, z); Quaternion destDir = Quaternion(Vector(qx, qy, qz), qu); // check if this is the current goal if( this->destCoor != destCoor || this->destDir != destDir) { this->destCoor = destCoor; this->destDir = destDir; float time = 5.0f; if( this->currentAnim != NULL) delete this->currentAnim; this->currentAnim = new Animation3D(this); this->currentAnim->addKeyFrame(this->getAbsCoor(), this->getAbsDir(), 0.1f, ANIM_LINEAR, ANIM_LINEAR); this->currentAnim->addKeyFrame(this->destCoor, this->destDir, time, ANIM_LINEAR, ANIM_LINEAR); this->currentAnim->addKeyFrame(this->getAbsCoor(), this->getAbsDir(), time, ANIM_LINEAR, ANIM_LINEAR); this->currentAnim->addKeyFrame(this->destCoor, this->destDir, time, ANIM_LINEAR, ANIM_LINEAR); this->currentAnim->setInfinity(ANIM_INF_CONSTANT); this->currentAnim->play(); this->setAnimation(RUN, MD2_ANIM_LOOP); } // calculate the distance Vector distance = this->getAbsCoor() - this->destCoor; return distance.len(); } /** * run to a specific place with direction * * @param x: x coordinate to go to * @param y: y coordinate to go to * @param qu: angle to rotate * @param qx: x coordinate of rotation vector * @param qy: y coordinate of rotation vector * @param qz: z coordinate of rotation vector * */ float GenericNPC::runTo(float x, float y, float qu, float qx, float qy, float qz) { this->runTo(x, y, 0.0f, qu, qx, qy, qz); } /** * run to a specific place with direction * * @param coor: vector place * @param dir: direction * */ float GenericNPC::runTo(const Vector& coordinate, const Quaternion& dir) { this->runTo(coordinate.x, coordinate.y, coordinate.z, dir.w, dir.v.x, dir.v.y, dir.v.z); } /** * crouch to a specific place with direction * * @param x: x coordinate to go to * @param y: y coordinate to go to * @param z: z coordinate to go to * @param qu: angle to rotate * @param qx: x coordinate of rotation vector * @param qy: y coordinate of rotation vector * @param qz: z coordinate of rotation vector * */ float GenericNPC::crouchTo(float x, float y, float z, float qu, float qx, float qy, float qz) { Vector destCoor = Vector(x, y, z); Quaternion destDir = Quaternion(Vector(qx, qy, qz), qu); // check if this is the current goal if( this->destCoor != destCoor || this->destDir != destDir) { this->destCoor = destCoor; this->destDir = destDir; float time = 5.0f; if( this->currentAnim != NULL) delete this->currentAnim; this->currentAnim = new Animation3D(this); this->currentAnim->addKeyFrame(this->getAbsCoor(), this->getAbsDir(), 0.1f, ANIM_LINEAR, ANIM_LINEAR); this->currentAnim->addKeyFrame(this->destCoor, this->destDir, time, ANIM_LINEAR, ANIM_LINEAR); this->currentAnim->addKeyFrame(this->getAbsCoor(), this->getAbsDir(), time, ANIM_LINEAR, ANIM_LINEAR); this->currentAnim->addKeyFrame(this->destCoor, this->destDir, time, ANIM_LINEAR, ANIM_LINEAR); this->currentAnim->setInfinity(ANIM_INF_CONSTANT); this->currentAnim->play(); this->setAnimation(CROUCH_WALK, MD2_ANIM_LOOP); } // calculate the distance Vector distance = this->getAbsCoor() - this->destCoor; return distance.len(); } /** * couch to a specific place with direction * * @param x: x coordinate to go to * @param y: y coordinate to go to * @param qu: angle to rotate * @param qx: x coordinate of rotation vector * @param qy: y coordinate of rotation vector * @param qz: z coordinate of rotation vector * */ float GenericNPC::crouchTo(float x, float y, float qu, float qx, float qy, float qz) { this->crouchTo(x, y, 0.0f, qu, qx, qy, qz); } /** * crouch to a specific place with direction * * @param coor: vector place * @param dir: direction * */ float GenericNPC::crouchTo(const Vector& coordinate, const Quaternion& dir) { this->crouchTo(coordinate.x, coordinate.y, coordinate.z, dir.w, dir.v.x, dir.v.y, dir.v.z); } /** * stops the generic animation */ void GenericNPC::stop() { if( this->currentAnim != NULL) { this->currentAnim->stop(); delete this->currentAnim; this->currentAnim = NULL; this->setAnimation(STAND, MD2_ANIM_LOOP); } } /** * lookat a world entity * @param worldEntity: the worldentity to look at */ float GenericNPC::lookAt(WorldEntity* worldEntity) {} /** * talk to a world entity and play a sound/music/voice * @param worldEntity: entity * @param dialogNr: sound nr to be played (from the xml load tags) */ float GenericNPC::talkTo(WorldEntity* worldEntity, int dialogNr) {} /** * world entity to shoot at if there is any weapon on the npc * @param entity: entity to shoot entity */ void GenericNPC::shootAt(WorldEntity* entity) {} /** * tick this world entity * @param time: time in seconds expirded since the last tick */ void GenericNPC::tick (float time) { if( likely(this->getModel(0) != NULL)) ((InteractiveModel*)this->getModel(0))->tick(time); // tick this animation if( this->currentAnim != NULL) this->currentAnim->tick(time); } void GenericNPC::destroy() { int randi = (int)(5.0f * (float)rand()/(float)RAND_MAX); if( randi == 1) this->setAnimation(DEATH_FALLBACK, MD2_ANIM_ONCE); else if( randi == 2) this->setAnimation(DEATH_FALLFORWARD, MD2_ANIM_ONCE); else if( randi == 3) this->setAnimation(DEATH_FALLBACKSLOW, MD2_ANIM_ONCE); else if( randi == 4) this->setAnimation(CROUCH_DEATH, MD2_ANIM_ONCE); else this->setAnimation(DEATH_FALLBACK, MD2_ANIM_ONCE); }