/* 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: Christian Meyer co-programmer: Patrick Boenzli */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_COMMAND_NODE #include "command_node.h" #include "keynames.h" #include "ini_parser.h" #include "world_entity.h" #include "game_loader.h" #include "world.h" #include "list.h" #include "orxonox.h" #include #include #include using namespace std; /** \brief constructs a CommandNode to handle remote input \param ID: unique denumerator to identify the node in the network */ CommandNode::CommandNode (int ID) { this->bound = new tList(); this->aliases = NULL; this->netID = ID; this->bLocalInput = false; this->bEnabled = true; this->world = NULL; } /** \brief constructs a CommandNode to handle local input \param filename: The path and name of the file to load the key bindings from */ CommandNode::CommandNode (char* filename = DEFAULT_KEYBIND_FILE) { this->aliases = NULL; this->bLocalInput = true; this->netID = 0; this->bound = new tList(); this->bEnabled = true; this->world = NULL; this->loadBindings (filename); } /** \brief removes the CommandNode from memory */ CommandNode::~CommandNode () { if( aliases != NULL) free (aliases); if( bound != NULL) delete bound; /* \todo should this delete bound? dangerous FIX */ } /** \brief this resets the command node deleting all data contained in the command node to fill it up again \todo coppling to different game-entities \todo reset/destroy has to be redesigned */ void CommandNode::reset() { this->bound->destroy(); //this->bound = NULL; /* \todo this produces a NULLpointer error.. FIX */ this->bEnabled = false; this->world = NULL; } void CommandNode::enable(bool bEnabled) { this->bEnabled = bEnabled; } /** \brief adds Node to a GameWorld this is usefull, if you want to catch events in a world class. usualy this is done automaticaly via GameLoader. Reset it via CommandNode::reset() */ void CommandNode::addToWorld(World* world) { this->world = world; } /** \brief loads new key bindings from a file \param filename: The path and name of the file to load the bindings from */ void CommandNode::loadBindings (char* filename) { FILE* stream; PRINTF(4)("Loading key bindings from %s\n", filename); if( filename == NULL) filename = DEFAULT_KEYBIND_FILE; // remove old bindings if present if( aliases != NULL) { free (aliases); aliases = NULL; } // create parser IniParser parser (filename); if( parser.getSection ("Bindings") == -1) { PRINTF(1)("Could not find key bindings in %s\n", filename); return; } // allocate empty lookup table aliases = (KeyBindings*) calloc (1, sizeof (KeyBindings)); char namebuf[256]; char valuebuf[256]; memset (namebuf, 0, 256); memset (valuebuf, 0, 256); int* index; while( parser.nextVar (namebuf, valuebuf) != -1) { index = nameToIndex (namebuf); switch( index[0]) { case 0: PRINTF(4)("Key binding %d(%s) set to %s\n", index[1], SDLKToKeyname( index[1]), valuebuf); strcpy (aliases->keys[index[1]], valuebuf); break; case 1: PRINTF(4)("Button binding %d(%s) set to %s\n", index[1], SDLBToButtonname( index[1]), valuebuf); strcpy (aliases->buttons[index[1]], valuebuf); break; default: break; } memset (namebuf, 0, 256); memset (valuebuf, 0, 256); } } /** \brief binds a WorldEntity to the CommandNode \param entity: Pointer to the entity to bind */ void CommandNode::bind (WorldEntity* entity) { bound->add (entity); } /** \brief removes an entity from the list of the CommandNode \param entity: Pointer to the entity to relese */ void CommandNode::unbind (WorldEntity* entity) { bound->remove (entity); } int* CommandNode::nameToIndex (char* name) { coord[0] = -1; coord[1] = -1; int c; if( (c = keynameToSDLK (name)) != -1) { coord[1] = c; coord[0] = 0; } if( (c = buttonnameToSDLB (name)) != -1) { coord[1] = c; coord[0] = 1; } return coord; } /** \brief tells the CommandNode to run through all pending events and relay them accordingly */ void CommandNode::process () { if( this->bEnabled) { if( bLocalInput) processLocal (); else processNetwork (); } } void CommandNode::processLocal () { SDL_Event event; Command cmd; while( SDL_PollEvent (&event)) { PRINTF(3)("CommandNode::processLocal() =========================got Event\n"); memset (cmd.cmd, 0, CMD_LENGHT); switch( event.type) { case SDL_KEYDOWN: strcpy (cmd.cmd, aliases->keys[event.key.keysym.sym]); cmd.bUp = false; if( strlen (cmd.cmd) > 0) relay(&cmd); break; case SDL_KEYUP: strcpy( cmd.cmd, aliases->keys[event.key.keysym.sym]); cmd.bUp = true; if( strlen (cmd.cmd) > 0) relay(&cmd); break; case SDL_MOUSEMOTION: strcpy( cmd.cmd, "cursor"); cmd.x = event.motion.x; cmd.y = event.motion.y; cmd.xrel = event.motion.xrel; cmd.yrel = event.motion.yrel; break; case SDL_MOUSEBUTTONUP: strcpy( cmd.cmd, aliases->buttons[event.button.button]); cmd.bUp = true; if( strlen (cmd.cmd) > 0) relay(&cmd); break; case SDL_MOUSEBUTTONDOWN: strcpy( cmd.cmd, aliases->buttons[event.button.button]); cmd.bUp = false; if( strlen (cmd.cmd) > 0) relay(&cmd); break; case SDL_JOYAXISMOTION: case SDL_JOYBALLMOTION: case SDL_JOYHATMOTION: case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: break; default: Orxonox *orx = Orxonox::getInstance(); orx->eventHandler(&event); break; } } } void CommandNode::processNetwork () { } void CommandNode::relay (Command* cmd) { Orxonox *orx = Orxonox::getInstance(); if( orx->systemCommand (cmd)) return; GameLoader* gl = GameLoader::getInstance(); if( gl->worldCommand(cmd)) return; if( bLocalInput) sendOverNetwork (cmd); if( this->world->command(cmd)) return; WorldEntity* entity = bound->enumerate(); while( entity != NULL) { entity->command (cmd); /*no absorbtion of command! strange*/ entity = bound->nextElement(); } } /** \brief sets the network identifier of the CommandNode \param ID: the new ID to use */ void CommandNode::setNetID (int ID) { netID = ID; } void CommandNode::sendOverNetwork (Command* cmd) { }