/* Copyright (C) 1998 Pyrosoft Inc. (www.pyrosoftgames.com), Matthew Bogue 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "ObjectiveInterface.hpp" #include #include #include #include #include #include #include "MapInterface.hpp" #include "PlayerInterface.hpp" #include "Util/FileSystem.hpp" #include "Util/Exception.hpp" #include "Util/FileStream.hpp" #include "Util/Log.hpp" #include "Outpost.hpp" #include "GameConfig.hpp" #include "ObjectiveNetMessage.hpp" #include "TerminalNetMesg.hpp" #include "NetPacket.hpp" #include "Server.hpp" std::vector ObjectiveInterface::objective_list; unsigned long ObjectiveInterface::objective_position_enum_list_size; unsigned long ObjectiveInterface::objective_position_enum_index; PlayerID ObjectiveInterface::objective_position_enum_player_id; NetMessageEncoder ObjectiveInterface::message_encoder; SDL_mutex* ObjectiveInterface::mutex = 0; void ObjectiveInterface::cleanUpObjectiveList() { std::vector::iterator i; for(i = objective_list.begin(); i != objective_list.end(); i++) { delete *i; } objective_list.clear(); } void ObjectiveInterface::cleanUp() { cleanUpObjectiveList(); } void ObjectiveInterface::resetLogic() { cleanUpObjectiveList(); } static inline std::string readToken(std::istream& in, std::string tokenname) { if(in.eof()) throw std::runtime_error("file too short."); // skip whitespace characters and comments char c; do { in.get(c); if(c == '#') { // comment till end of line do { in.get(c); } while(!in.eof() && c != '\n'); } } while(!in.eof() && isspace(c)); if(in.eof()) throw std::runtime_error("file too short."); // read token std::string token; while(!in.eof() && !isspace(c)) { token += c; in.get(c); } if(token != tokenname) { std::stringstream msg; msg << "Expected token '" << tokenname << "' got '" << token << "'."; throw std::runtime_error(msg.str()); } while(!in.eof() && isspace(c)) in.get(c); // read token contents std::string result; while(!in.eof() && c != '\n') { result += c; in.get(c); } return result; } void ObjectiveInterface::loadObjectiveList(const char *file_path) { int objective_count = 0; try { IFileStream in(file_path); cleanUpObjectiveList(); std::string objectivecount = readToken(in, "ObjectiveCount:"); std::stringstream ss(objectivecount); ss >> objective_count; size_t loc_x, loc_y; size_t world_x, world_y; std::string name; cleanUpObjectiveList(); for (int objective_index = 0; objective_index < objective_count; objective_index++ ) { Objective *objective_obj; name = readToken(in, "Name:"); std::string location = readToken(in, "Location:"); std::stringstream ss(location); ss >> loc_x >> loc_y; MapInterface::mapXYtoPointXY( loc_x, loc_y, &world_x, &world_y ); objective_obj = new Outpost(objective_index, iXY(world_x, world_y), BoundBox( -48, -32, 48, 32 ) ); strcpy(objective_obj->objective_state.name, name.c_str()); objective_list.push_back(objective_obj); } // ** for } catch(std::exception& e) { throw Exception("Error while reading outpost definition '%s': %s", file_path, e.what()); } } unsigned char ObjectiveInterface::quearyObjectiveLocationStatus(iXY &loc, uint16_t player_id, Objective **objective_ptr ) { std::vector::iterator i; for(i = objective_list.begin(); i != objective_list.end(); i++) { ObjectiveState *objective_state = & ((*i)->objective_state); if ( objective_state->selection_box.contains( loc ) == true ) { if ( objective_state->occupation_status == _occupation_status_occupied ) { if (objective_state->occupying_player->getID() == player_id) { *objective_ptr = *i; return( _player_occupied_objective_found ); } // ** if else { *objective_ptr = *i; return( _enemy_occupied_objective_found ); } // ** else } // ** if else { *objective_ptr = *i; return( _unoccupied_objective_found ); } // ** else } // ** if } // ** if return( _no_objective_found ); } void ObjectiveInterface::processTerminalNetPacket(const NetPacket* packet) { const NetMessage* message = packet->getNetMessage(); const ObjectiveMessage* objectiveMessage = 0; switch(message->message_id) { case _net_message_id_term_unit_gen: { const TerminalOutpostUnitGenRequest* request = (const TerminalOutpostUnitGenRequest*) message; objectiveMessage = &(request->unit_gen_request); break; } case _net_message_id_term_output_loc: { const TerminalOutpostOutputLocRequest* request = (const TerminalOutpostOutputLocRequest*) message; objectiveMessage = &(request->output_loc_request); break; } default: LOGGER.warning( "Unknown objective terminal message (id %u, player %u)", message->message_id, packet->fromID); return; } const PlayerState* player = PlayerInterface::getPlayerByNetworkID(packet->fromID); if(!player) { LOGGER.warning("Couldn't find player for packet from NetworkID %u.", packet->fromID); return; } sendMessage(objectiveMessage, player); } void ObjectiveInterface::sendMessage(const ObjectiveMessage* message, const PlayerState* player) { if(message->getObjectiveID() >= objective_list.size()) { LOGGER.warning("Received malformed objective message: id out of range"); return; } Objective* objective = objective_list[message->getObjectiveID()]; if(player && objective->objective_state.occupying_player != player) { LOGGER.warning( "Terminal message from player %u for objective %u not allowed.", player->getID(), message->getObjectiveID()); return; } objective_list[message->getObjectiveID()]->processMessage(message); } void ObjectiveInterface::processNetMessages(const NetMessage* message) { switch(message->message_id) { case _net_message_id_occupation_status_update: { const ObjectiveOccupationUpdate *occupation_update = (const ObjectiveOccupationUpdate*) message; sendMessage( &(occupation_update->status_update) ); break; } case _net_message_id_objective_sync: { const ObjectiveSyncMesg* sync_mesg = (const ObjectiveSyncMesg*) message; sendMessage( &(sync_mesg->sync_data) ); break; } default: LOGGER.warning("Unknown Objective Message received (id %d)", message->message_id); break; } } void ObjectiveInterface::updateObjectiveStatus() { std::vector::iterator i; for(i = objective_list.begin(); i != objective_list.end(); i++) { (*i)->updateStatus(); } } void ObjectiveInterface::offloadGraphics( SpriteSorter &sorter ) { std::vector::iterator i; for(i = objective_list.begin(); i != objective_list.end(); i++) { (*i)->offloadGraphics(sorter); } } bool ObjectiveInterface::testRuleObjectiveOccupationRatio( uint16_t player_index, float precentage) { size_t occupation_ratio = (size_t) ( ((float) objective_list.size()) * precentage + 0.999); if (occupation_ratio == 0) occupation_ratio = 1; std::vector::iterator i; size_t occupied = 0; for(i = objective_list.begin(); i != objective_list.end(); i++) { ObjectiveState *objective_state = & ((*i)->objective_state); if(objective_state->occupation_status == _occupation_status_occupied) { uint16_t occuping_player_index = objective_state->occupying_player->getID(); if ( occuping_player_index == player_index ) { occupied++; } else if (PlayerInterface::isAllied( occuping_player_index, player_index) && PlayerInterface::isAllied(player_index, occuping_player_index)) { occupied++; } } } if(occupied >= occupation_ratio) return true; return false; } void ObjectiveInterface::disownPlayerObjectives(uint16_t player_id) { DisownPlayerObjective disown_player_objective; for(uint16_t i = 0; i < objective_list.size(); i++) { disown_player_objective.set(i, player_id); sendMessage(&disown_player_objective); } } ObjectiveState* ObjectiveInterface::getObjectiveState( short objective_id ) { return & (objective_list.at(objective_id)->objective_state); } OutpostStatus ObjectiveInterface::getOutpostStatus( short objective_id ) { OutpostStatus outpost_status; Outpost *outpost_ptr = dynamic_cast (objective_list.at(objective_id)); assert(outpost_ptr != 0); outpost_ptr->getOutpostStatus( outpost_status ); return outpost_status; } void ObjectiveInterface::startObjectivePositionEnumeration() { objective_position_enum_index = 0; objective_position_enum_list_size = objective_list.size(); objective_position_enum_player_id = PlayerInterface::getLocalPlayerID(); } bool ObjectiveInterface::objectivePositionEnumeration(iRect *objective_rect, unsigned char *objective_disposition, int *objective_id) { ObjectiveState *objective_state; if( objective_position_enum_index < objective_position_enum_list_size ) { objective_state = &(objective_list[ objective_position_enum_index ]->objective_state); (*objective_rect) = objective_state->area.getAbsRect( objective_state->location ); if( objective_id != 0 ) { (*objective_id) = objective_position_enum_index; } if ( objective_state->occupation_status == _occupation_status_occupied ) { if ( objective_position_enum_player_id.getIndex() != objective_state->occupying_player->getID() ) { if (PlayerInterface::isAllied(objective_state->occupying_player->getID() , objective_position_enum_player_id.getIndex()) ) { (*objective_disposition) = _objective_disposition_allie; } else { (*objective_disposition) = _objective_disposition_enemy; } } else { (*objective_disposition) = _objective_disposition_player; } } else { (*objective_disposition) = _objective_disposition_unoccupied; } objective_position_enum_index++; return true; } return false; } void ObjectiveInterface::syncObjectives(PlayerID connect_player) { ObjectiveSyncMesg sync_mesg; NetMessageEncoder* encoder = new NetMessageEncoder(connect_player); std::vector::iterator i; for(i = objective_list.begin(); i != objective_list.end(); ++i) { (*i)->getSyncData( sync_mesg.sync_data ); encoder->encodeMessage(&sync_mesg, sizeof(ObjectiveSyncMesg)); } encoder->sendEncodedMessage(); } void ObjectiveInterface::updatePlayerObjectiveCounts() { if(mutex == 0) { // little race condition... mutex = SDL_CreateMutex(); } SDL_mutexP(mutex); unsigned long player_index, player_count; PlayerState *player_state = 0; player_count = PlayerInterface::getMaxPlayers(); for( player_index = 0; player_index < player_count; player_index++ ) { player_state = PlayerInterface::getPlayerState( (unsigned short) player_index ); player_state->setObjectivesHeld( 0 ); } std::vector::iterator i; for(i = objective_list.begin(); i != objective_list.end(); i++) { ObjectiveState *objective_state = & ((*i)->objective_state); if( objective_state->occupation_status == _occupation_status_occupied ) { objective_state->occupying_player->incObjectivesHeld(); } } SDL_mutexV(mutex); } int ObjectiveInterface::getObjectiveLimit() { float percentage = (float) gameconfig->objectiveoccupationpercentage / 100.0; int wincount = (int) ( ((float) getObjectiveCount()) * percentage + 0.999); if(wincount == 0) wincount = 1; return wincount; }