/** @file /world/world_client.cpp Implementace hlavickoveho souboru world/world_client.h @author Petr Wolf */ #include #ifndef _K_EDITOR_ #include #include #endif #include "common/rm/rminit.h" #include "common/xml/package.h" #include "common/xml/packsmall.h" #include "common/Interface.h" #include "common/Log.h" #include "ai/PathFind/pathfind.h" #include "net/netinit.h" #include "net/server.h" #include "world/world_messages.h" #include "world/typedefs.h" #include "world/world_client.h" #include "world/world_server.h" #include "world/world_handler.h" namespace World{ using namespace rm; TWorldClient * world_client[MAX_PLAYERS + 1]; TMutex world_client_mutex; /////////////////////////////////////////////////////////////////////////////// // init & destroy /////////////////////////////////////////////////////////////////////////////// TWorldClient::TWorldClient() { player_id = 0; state = WCS_EMPTY; world = new TWorld(); engine = new TWorldEngine(world); history = new TClientHistory; world_ownership = true; } TWorldClient::TWorldClient(bool world_owner) { player_id = 0; state = WCS_EMPTY; world_ownership = world_owner; if (world_owner) { world = new TWorld(); engine = new TWorldEngine(world); history = new TClientHistory; } else { world = NULL; engine = NULL; history = NULL; } } TWorldClient::~TWorldClient() { if (world && world_ownership) { delete world; world = NULL; delete engine; engine = NULL; delete history; history = NULL; } } void TWorldClient::init(PLAYER_ID id, TWorld * external_world, TWorldEngine * external_engine, TClientHistory * external_history) { // prijmu svoje id player_id = id; if (external_world) { // prejimam cizi svet world_ownership = false; // smazu docasne struktury if (world && world_ownership) { delete world; delete engine; delete history; } // prejmu cizi world = external_world; engine = external_engine; history = external_history; } else { // drzim vlastni svet world_ownership = true; // inicializace sveta world->init(); // inicializace negine engine->init(world); // registrace zprav z TCL engine->interpreter.createCommand("KSendMessage", (Tcl_CmdProc *)World::WorldClient_SendMessage); // inkluze knihoven pro TCL (spusteni inicializacniho skriptu) engine->interpreter.init(world->rules->scripts[TS_INIT]); } // svet je pripraven state = WCS_WORLD_INITIALIZED; } void TWorldClient::loadFromNet(TPackage * package) { TPackSmall * subpack; world->reset(); // nacteni hracu subpack = new TPackSmall(package->getSubtag("players", 0, NULL)); world->players.readFromXML(subpack, "player"); // nacteni mapy subpack = new TPackSmall(package->getSubtag("map", 0, NULL)); world->map.readFromXML(subpack); delete subpack; // inicializace masek viditelnosti for (TPlayerIterator pit = world->players.begin(); pit != world->players.end(); pit++) { // pro daneho hrace mam masku viditelnosti world->visibility_maps[pit->first] = new TVisibilityMap(world->map); } // nacteni map viditelnosti subpack = new TPackSmall(package->getSubtag("visibility_maps", 0, NULL)); world->visibility_maps.readFromXML(subpack); delete subpack; // nacteni kralovstvi subpack = new TPackSmall(package->getSubtag("kingdoms", 0, NULL)); world->kingdoms.readFromXML(subpack, "kingdom"); delete subpack; // nacteni mest subpack = new TPackSmall(package->getSubtag("towns", 0, NULL)); world->towns.readFromXML(subpack, "town"); delete subpack; // nacteni zivych jednotek subpack = new TPackSmall(package->getSubtag("units", 0, NULL)); world->units.readFromXML(subpack, "unit"); delete subpack; // nacteni zivych budov subpack = new TPackSmall(package->getSubtag("buildings", 0, NULL)); world->buildings.readFromXML(subpack, "building"); delete subpack; // pocasi subpack = new TPackSmall(package->getSubtag("weather", 0, NULL)); world->weather.readFromXML(subpack); delete subpack; // hrac na tahu int player_on_turn = package->getInt(PACKET_NET_GAME_START::player_on_turn, 0, NULL); world->players.setPlayerOnTurn(player_on_turn); // cislo tahu world->turn_id = package->getInt(PACKET_NET_GAME_START::turn_id, 0, NULL); // naplneni redundantnich relaci world->fillRelations(); // start historie history->init(); state = WCS_WORLD_LOADED; } void TWorldClient::saveMap(char * filename) { TRM_map_i * rmmapi = (TRM_map_i *)KSendGlobalMessage(MSG_GET_RM_MAP_I, ANNONYMOUS, BROADCAST, NULL); // 1. ulozeni dat do RM rmmapi->setHexes(world->map.save(false)); rmmapi->setLivingBuildings(world->buildings.save(false)); rmmapi->setLivingUnits(world->units.save(false)); rmmapi->setCities(world->towns.save(false)); rmmapi->setKingdoms(world->kingdoms.save(MAX_KINGDOMS + 1, false)); rmmapi->setHistoryHexes(world->visibility_maps.save(false)); // ulozeni TMapInfo TMapInfo * info; rmmapi->getMapInfo(&info, rmmapi->idOfLoadedMap()); world->players.save(info->roles); // ulozeni TStateInfo TStateInfo * state = (TStateInfo *)KMemAlloc(sizeof(TStateInfo)); state->weather = world->weather.data().state; state->duration = world->weather.data().duration; state->player_on_turn = world->players.playerIdOnTurn(); state->turn_id = world->turn_id; rmmapi->setCurrentState(state); // 2. ulozeni do souboru rmmapi->saveMap(MAP_TYPE_SAVE_GAME, filename); // 3. fiktivni nacteni rmmapi->getHexes(NULL); rmmapi->getLivingBuildings(NULL); rmmapi->getLivingUnits(NULL); rmmapi->getCities(NULL); rmmapi->getKingdoms(NULL); rmmapi->getHistoryHexes(NULL); rmmapi->getCurrentState(NULL); delete(rmmapi); } /////////////////////////////////////////////////////////////////////////////// // staticky cleny /////////////////////////////////////////////////////////////////////////////// TMessageTransceiver TWorldClient::world_client_transceiver; void TWorldClient::initWorldClient(PLAYER_ID player_id, int client_id, TWorld * world, TWorldEngine * engine, TClientHistory * history) { world_client[player_id] = new TWorldClient(world == NULL); world_client[player_id]->init(player_id, world, engine, history); // pokud pridavam hrace s nesdilenou reprezentaci sveta, pridam // na nej pointer z world_client[0] if (world == NULL) world_client[0] = world_client[player_id]; TPackage p(MSG_WORLD_CLIENT_SERVER); p.setInt(MSG_JOIN_CONFIRMATION, PACKET_WORLD::type, 0, NULL); p.setInt(player_id, PACKET_JOIN_GAME::player_id, 0, NULL); p.send(client_id, TO_SERVER, MOD_WORLD_SERVER); } void TWorldClient::destroyWorldClient(PLAYER_ID id) { delete world_client[id]; world_client[id] = NULL; } void TWorldClient::initWorldClients() { // zaregistruji do fronty zprav handler modulu world_client world_client_transceiver.fnc = WORLD_CLIENT_MSG_HANDLER; world_client_transceiver.iActived = true; world_client_transceiver.iPriority = WORLD_CLIENT_PRIORITY; world_client_transceiver.PrimaryID = MOD_WORLD_CLIENT; KRegisterGlobalTransceiver(&world_client_transceiver, MOD_WORLD_CLIENT); // vyprazdnim pole modulu for (int i = 0; i <= MAX_PLAYERS; i++) world_client[i] = NULL; } void TWorldClient::destroyWorldClients() { for (int i = 1; i <= MAX_PLAYERS; i++) { if (world_client[i]) { delete world_client[i]; world_client[i] = NULL; } } } /////////////////////////////////////////////////////////////////////////////// // client handler /////////////////////////////////////////////////////////////////////////////// RVAL WORLD_CLIENT_MSG_HANDLER(MESSAGE_ID mid, SENDER s, PARAM p) { switch (mid) { case MSG_WORLD_AI: // Komunikace s AI { } break; case MSG_WORLD_CLIENT_SERVER: // Komunikace mezi WORLD_CLIENT a WORLD_SERVER { // promenne int i; ACTION_ID action_id; ACTION_TYPE action_type; // pretypovani a nacteni hlavicky TPackage * package = (TPackage *)p; int player_id = package->getInt(PACKET_WORLD::player_id, 0, NULL); int type = package->getInt(PACKET_WORLD::type, 0, NULL); // zpracovani obsahu for (i = 1; i <= MAX_PLAYERS; i++) { if (world_client[i] && ((i == player_id) || (player_id == 0))) { // pokud mam na dane pozici klienta a zprava je pro nej, nebo pro vsechny, // tak ji zpracuji switch (type) { case MSG_SYNCHRO: //synchronizacni informace { world_client_mutex.lock(); action_id = (ACTION_ID)package->getInt(PACKET_SYNCHRO::action_id, 0, NULL); action_type = (ACTION_TYPE)package->getInt(PACKET_SYNCHRO::action_type, 0, NULL); if (world_client[i]->state == WCS_GAME_ENDED && action_type == AT_ENDGAME) { // zprava o ukonceni hry pro jiz ukoncenou hru - ignoruji break; } else if (!(((action_type == AT_GAME_START) && (world_client[i]->state >= WCS_WORLD_INITIALIZED) && (world_client[i]->state < WCS_GAME_STARTED)) || (world_client[i]->state == WCS_GAME_STARTED) )) { // zprava prisla v nevhodnou chvili - ignoruji break; } if (!world_client[i]->history->synchronized(action_id)) { // i-ty klient je vlastnikem reprezentace sveta a udalost jeste nezpracoval -> udalost zpracuji // ulozeni akce do kontejneru historie world_client[i]->history->add(action_id, new TAction(action_type)); // zpracovani udalosti switch (action_type) { case AT_GAME_START: // nacteni celeho sveta { if (world_client[i]->state >= WCS_WORLD_LOADED) { // svet uz je nahran } else { // svet jeste neni nahran world_client[i]->loadFromNet(package); // poslu zpravu GUI PACKET_LETS_GO packet; packet.rules = world_client[i]->world->rules; packet.map = & world_client[i]->world->map.data(); packet.towns = & world_client[i]->world->towns; packet.kingdoms = & world_client[i]->world->kingdoms; packet.visibility_maps = & world_client[i]->world->visibility_maps; packet.living_units = & world_client[i]->world->units; packet.corpses = & world_client[i]->world->corpses; packet.living_buildings = & world_client[i]->world->buildings; packet.ruins = & world_client[i]->world->ruins; packet.players = & world_client[i]->world->players; packet.weather = & world_client[i]->world->weather; packet.player_on_turn = world_client[i]->world->players.playerIdOnTurn(); packet.turn_id = world_client[i]->world->turn_id; // najdu hrace, kteremu se ma GUI zobrazit int player; if (world_handler->game_mode == GM_LOCAL) { player = packet.player_on_turn; } else { player = i; } packet.human_player = 0; TPlayerIterator it; for (it = world_client[i]->world->players.find(player); (packet.human_player == 0) && (it != world_client[i]->world->players.end()); it++) { if (it->second->data().client_data.type == PT_HUMAN) { packet.human_player = it->first; } } for (it = world_client[i]->world->players.begin(); (packet.human_player == 0) && (it != world_client[i]->world->players.find(player)); it++) { if (it->second->data().client_data.type == PT_HUMAN) { packet.human_player = it->first; } } // printf("LETS GO WORLD"); // todle se musi volat - reconnect KSendGlobalMessage(MSG_LETS_GO, MOD_WORLD_CLIENT, BROADCAST, &packet); } } break; case AT_ENDGAME: // konec hry { // rozeslu vsem TPacket_END_GAME packet; packet.readFromXML(package); for (int i = 0; i <= MAX_PLAYERS; i++) if (world_client[i]) world_client[i]->history->reset(); KSendGlobalMessage(MSG_END_GAME, MOD_WORLD_CLIENT, BROADCAST, &packet); } break; case AT_PLAYER_DEFEATED: // porazeni hrace { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_PLAYER_DEFEATED); // zapisu do sveta world_client[i]->world->playerDefeated(packet.defeated_player_id); WORLD_CLIENT_GUI_PACKET_SEND(MSG_PLAYER_DEFETAED); } break; case AT_UNIT_MOVE: // pohyb jednotky { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_RCT_UNIT_MOVE); // zaznamenam pohyb world_client[i]->world->unitMove(packet.unit_id, packet.path.back().hex_id, &packet.path); WORLD_CLIENT_GUI_PACKET_SEND(MSG_RCT_UNIT_MOVE); } break; case AT_UNIT_SUICIDE: // sebezniceni jednotky { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_RCT_UNIT_SUICIDE); TLivingUnit * unit = world_client[i]->world->units[packet.unit_id]; // aktualizace viditelnosti world_client[i]->world->visibilityHide(unit->data().player, packet.hidden); // zniceni jednotky world_client[i]->world->unitDied(packet.unit_id); // zaznamenam do statistik world_client[i]->world->players.unitKilled(unit->data().player); WORLD_CLIENT_GUI_PACKET_SEND(MSG_RCT_UNIT_SUICIDE); } break; case AT_BUILDING_SUICIDE: // sebezniceni budovy { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_RCT_BUILDING_SUICIDE); // zniceni budovy TLivingBuilding * building = world_client[i]->world->buildings[packet.building_id]; if (building->data().player != 0) { // odectu viditelnost budovy (pokud byla nekoho world_client[i]->world->visibilityHide(building->data().player, packet.hidden); world_client[i]->world->buildingDestroyed(packet.building_id); // zaznamenam do statistik world_client[i]->world->players.buildingDestroyed(building->data().player); } // zniceni jednotky uvnitr budovy if (packet.unit_killed) { TLivingUnit * unit = world_client[i]->world->units[packet.unit_killed]; world_client[i]->world->unitDied(packet.unit_killed); // zaznamenam do statistik world_client[i]->world->players.unitKilled(unit->data().player); } WORLD_CLIENT_GUI_PACKET_SEND(MSG_RCT_BUILDING_SUICIDE); } break; case AT_BUILDING_RECRUIT_UNIT: // vyroba jednotky { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_RCT_BUILDING_RECRUIT_UNIT); // vytvoreni nove jednotky TLivingUnit * unit = world_client[i]->world->unitCreated(packet.building_id, packet.unit_type, packet.unit_id, packet.cost); unit->self_allocated(true); // aktualizace viditelnosti world_client[i]->world->visibilityShow(unit->data().player, packet.shown); WORLD_CLIENT_GUI_PACKET_SEND(MSG_RCT_BUILDING_RECRUIT_UNIT); } break; case AT_UNIT_BUILD_START: // zahajeni stavby { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_RCT_START_BUILDING); // vytvoreni budovy TLivingBuilding * building = world_client[i]->world->buildingCreated(packet.unit_id, packet.building_type, packet.building_id, packet.location, packet.lives, packet.cost, packet.orientation); building->self_allocated(true); // aktualizace viditelnosti world_client[i]->world->visibilityShow(building->data().player, packet.shown); world_client[i]->world->visibilityHide(building->data().player, packet.hidden); WORLD_CLIENT_GUI_PACKET_SEND(MSG_RCT_START_BUILDING); } break; case AT_UNIT_BUILD_STOP: // preruseni stavby { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_RCT_STOP_BUILDING); // provedeni zmen world_client[i]->world->stopBuilding(packet.unit_id); WORLD_CLIENT_GUI_PACKET_SEND(MSG_RCT_STOP_BUILDING); } break; case AT_UNIT_REPAIR_START: // zahajeni stavby { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_RCT_REPAIR_BUILDING); // vytvoreni budovy world_client[i]->world->buildingRepaired(packet.unit_id, packet.building_id, packet.lives, packet.cost); // aktualizace viditelnosti TLivingUnit * unit = world_client[i]->world->units[packet.unit_id]; world_client[i]->world->visibilityShow(unit->data().player, packet.shown); world_client[i]->world->visibilityHide(unit->data().player, packet.hidden); WORLD_CLIENT_GUI_PACKET_SEND(MSG_RCT_REPAIR_BUILDING); } break; case AT_UNIT_ATTACK: // utok jednotky { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_RCT_UNIT_ATTACK); TIntContainer::iterator it; // vytazeni informaci o hracich ucastnicich se souboje int attacking_player_id = 0; int attacked_player_id = 0; TLivingUnit * attacker = world_client[i]->world->units[packet.attacker]; attacking_player_id = attacker->data().player; THex * hex = world_client[i]->world->map.getHexById(packet.target); if (hex->data().unit) { TLivingUnit * defender = world_client[i]->world->units[hex->data().unit]; attacked_player_id = defender->data().player; } else if (hex->data().building) { TLivingBuilding * attacked_building = world_client[i]->world->buildings[hex->data().building]; attacked_player_id = attacked_building->data().player; } // odecteni zivotu utocnika attacker->data().lives -= packet.attacker_losses; if (packet.attacker_killed) { // utocnik zemrel world_client[i]->world->visibilityHide(attacker->data().player, packet.attacker_hidden); world_client[i]->world->unitDied(packet.attacker); world_client[i]->world->players.unitKilled(attacking_player_id, attacked_player_id); } else { // utocnik nezemrel - pridam mu ztraty a zkusenosti world_client[i]->world->unitWound(packet.attacker, packet.attacker_wounds); world_client[i]->world->unitExperience(packet.attacker, packet.attacker_experience, packet.attacker_level); if (attacker->data().state == US_IDLE) attacker->data().state = US_HAS_FOUGHT; else if (attacker->data().state == US_HAS_MOVED) attacker->data().state = US_EXHAUSTED; } // odecteni zivotu napadene jednotky THex * target = world_client[i]->world->map.getHexById(packet.target); if (target->unit_id()) { TLivingUnit * defender = world_client[i]->world->units[target->unit_id()]; defender->data().lives -= packet.defender_losses; if (packet.defender_killed) { // napadena jednotka zemrela for (it = packet.defender_hidden.begin(); it != packet.defender_hidden.end(); it++) world_client[i]->world->visibility_maps[defender->data().player]->getHexById(*it).removeActual(); world_client[i]->world->unitDied(target->unit_id()); world_client[i]->world->players.unitKilled(attacked_player_id, attacking_player_id); } else { // napadena jednotka nezemrela - pridam ji zraneni a zkusenosti world_client[i]->world->unitWound(target->unit_id(), packet.defender_wounds); world_client[i]->world->unitExperience(target->unit_id(), packet.defender_experience, packet.defender_level); } } // odecteni zivotu napadene budovy if (target->building_id()) { TLivingBuilding * building = world_client[i]->world->buildings[target->building_id()]; building->data().lives -= packet.building_losses; if (packet.building_destroyed) { // napadena budova byla znicena if ((building->data().player != 0) && (target->unit_id() == 0)) { // odectu viditelnost budovy (pokud byla nekoho a pokud jsem to uz nedelal u jednotky) for (it = packet.defender_hidden.begin(); it != packet.defender_hidden.end(); it++) world_client[i]->world->visibility_maps[building->data().player]->getHexById(*it).removeActual(); } world_client[i]->world->buildingDestroyed(target->building_id()); world_client[i]->world->players.buildingDestroyed(attacked_player_id, attacking_player_id); } } WORLD_CLIENT_GUI_PACKET_SEND(MSG_RCT_UNIT_ATTACK); } break; case AT_UNIT_HEAL: // leceni jednotky { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_RCT_UNIT_HEAL); // provedeni zmen world_client[i]->world->unitHeal(packet.unit_id, packet.lives); WORLD_CLIENT_GUI_PACKET_SEND(MSG_RCT_UNIT_HEAL); } break; case AT_UNIT_RECRUIT: // doplneni jednotky (neelitni) { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_RCT_UNIT_RECRUIT); // provedeni zmen world_client[i]->world->unitRecruit(packet.unit_id, packet.lives, packet.cost, packet.level, packet.experience); WORLD_CLIENT_GUI_PACKET_SEND(MSG_RCT_UNIT_RECRUIT); } break; case AT_UNIT_RECRUIT_ELITE: // doplneni jednotky (elitni) { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_RCT_UNIT_RECRUIT_ELITE); // provedeni zmen world_client[i]->world->unitRecruitElite(packet.unit_id, packet.lives, packet.cost); WORLD_CLIENT_GUI_PACKET_SEND(MSG_RCT_UNIT_RECRUIT_ELITE); } break; case AT_BUILDING_SELL_BONUS: // prodej bonusu jednotce v budove { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_RCT_SELL_BONUS); // prodej bonusu world_client[i]->world->sellBonus(packet.building_id, packet.bonus_id, packet.cost, packet.replace); WORLD_CLIENT_GUI_PACKET_SEND(MSG_RCT_SELL_BONUS); } break; case AT_NEXT_TURN: // konec tahu case AT_NEXT_ROUND: // konec kola { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_RCT_NEXT_TURN); // zapisu do sveta TIntIterator it; world_client[0]->world->players.next(); // predani kola world_client[0]->world->nextTurn(packet.moneyGain, packet.movementPoints, packet.buildingLives, packet.unitsInterrupted); if (packet.newRound) world_client[0]->world->turn_id++; // zmena pocasi world_client[0]->world->setWeather(packet.weatherState); // dezerce jednotek for (it = packet.unitsDeserted.begin(); it != packet.unitsDeserted.end(); it++) { world_client[0]->world->unitDied(*it); world_client[0]->world->players.unitKilled(world_client[0]->world->players.playerIdOnTurn()); } // smrt jednotek for (it = packet.unitsDied.begin(); it != packet.unitsDied.end(); it++) { world_client[0]->world->unitDied(*it); world_client[0]->world->players.unitKilled(world_client[0]->world->players.playerIdOnTurn()); } // preruseni stavby for (it = packet.unitsInterrupted.begin(); it != packet.unitsInterrupted.end(); it++) world_client[0]->world->stopBuilding(*it); // zisk viditelnosti world_client[0]->world->visibilityShow(world_client[0]->world->players.playerIdOnTurn(), packet.shown); // ztrata viditelnosti world_client[0]->world->visibilityShow(world_client[0]->world->players.playerIdOnTurn(), packet.hidden); WORLD_CLIENT_GUI_PACKET_SEND(MSG_RCT_NEXT_TURN); #ifdef CLIENT_AUTOPLAY // automaticky predam tah (pokud je na tahu clovek) if ((world_client[world_client[0]->world->players.playerIdOnTurn()] != NULL) && (world_client[0]->world->players.playerOnTurn()->data().client_data.type == PT_HUMAN)) { PACKET_WORLD_GUI next_turn; next_turn.player_id = world_client[0]->world->players.playerIdOnTurn(); next_turn.type = MSG_ACT_NEXT_TURN; KSendGlobalMessage(MSG_WORLD_GUI, MOD_WORLD_CLIENT, MOD_WORLD_CLIENT, &next_turn); } #endif } break; case AT_BUILDING_OCCUPIED: // obsazeni budovy { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_BUILDING_OCCUPIED); // zmenim majitele budovy world_client[i]->world->buildings[packet.building_id]->data().player = packet.new_player_id; // aktualizuji viditelnost world_client[i]->world->visibilityHide(packet.former_player_id, packet.hidden); world_client[i]->world->visibilityShow(packet.new_player_id, packet.shown); // zaznamenam do statistik world_client[i]->world->players.buildingCaptured(packet.new_player_id, packet.former_player_id); WORLD_CLIENT_GUI_PACKET_SEND(MSG_BUILDING_OCCUPIED); } break; case AT_TOWN_OCCUPIED: // obsazeni mesta { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_TOWN_OCCUPIED); // zmenim majitele mesta world_client[i]->world->towns[packet.town_id]->data().owner = packet.new_player_id; // aktualizuji viditelnost world_client[i]->world->visibilityHide(packet.former_player_id, packet.hidden); world_client[i]->world->visibilityShow(packet.new_player_id, packet.shown); // zaznamenam do statistik world_client[i]->world->players.townCaptured(packet.new_player_id, packet.former_player_id); WORLD_CLIENT_GUI_PACKET_SEND(MSG_TOWN_OCCUPIED); } break; case AT_KINGDOM_OCCUPIED: // obsazeni kralovstvi { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_KINGDOM_OCCUPIED); // zmenim majitele kralovstvi world_client[i]->world->kingdoms[packet.kingdom_id]->data().roleid = packet.new_player_id; // zaznamenam do statistik world_client[i]->world->players.kingdomCaptured(packet.new_player_id, packet.former_player_id); WORLD_CLIENT_GUI_PACKET_SEND(MSG_KINGDOM_OCCUPIED); } break; case AT_VISIBILITY_CHANGE: // zmena viditelnosti { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_VISIBILITY_CHANGE); // prebarvim viditelnost world_client[i]->world->visibilityShow(packet.visibility_mask_player_id, packet.shown); world_client[i]->world->visibilityHide(packet.visibility_mask_player_id, packet.hidden); WORLD_CLIENT_GUI_PACKET_SEND(MSG_VISIBILITY_CHANGE); } break; case AT_DIPLOMACY_RELATION_CHANGE: // zmena v diplomatickych vztazich { WORLD_CLIENT_GUI_PACKET_INIT(TPacket_DIPLOMACY_RELATION_CHANGE); ai_ns::diplomacy_ns::TRelationship old_relationship = world_client[0]->world->players[packet.source_diplomat_world_id]->data().game_data.relations[packet.target_diplomat_world_id]->rs; ai_ns::diplomacy_ns::TRelationship old_offered_relationship = world_client[0]->world->players[packet.source_diplomat_world_id]->data().game_data.relations[packet.target_diplomat_world_id]->offeredrs; bool tell_gui = !((packet.new_relationship == old_relationship) && (packet.new_offered_relationship == packet.new_relationship) && (old_offered_relationship != packet.new_offered_relationship)); // zaznamenam zmenu world_client[i]->world->diplomacyChange(packet.source_diplomat_world_id, packet.target_diplomat_world_id, packet.new_relationship, packet.new_offered_relationship, packet.source_diplomat_penalty, packet.target_diplomat_penalty); world_client[i]->world->unlock(); if (tell_gui) KSendGlobalMessage(MSG_DIPLOMACY_RELATION_CHANGE, MOD_WORLD_CLIENT, MOD_GUI, &packet); } break; } // switch } else { // preskakuji i-teho klienta, protoze reprezentaci sveta sdili // pouze, jedna-li se o prvotni synchronizaci, posilam zpet na server potvrzeni // ze jsem zpravu prijal a predal if (action_type == AT_GAME_START) { TPackage reply(MSG_WORLD_CLIENT_SERVER); reply.setInt(MSG_GUIMAP_READY, PACKET_WORLD::type, 0, NULL); reply.setInt(i, PACKET_WORLD::player_id, 0, NULL); reply.send(world_client[0]->world->players[i]->data().client_data.client_id, TO_SERVER, MOD_WORLD_SERVER); } } // odpoved na synchronizacni balicek (krome ENDGAME) if (action_type != AT_ENDGAME) { TPackage reply(MSG_WORLD_CLIENT_SERVER); reply.setInt(MSG_SYNCHRO_CONFIRMATION, PACKET_WORLD::type, 0, NULL); reply.setInt(i, PACKET_WORLD::player_id, 0, NULL); reply.setInt(action_id, PACKET_SYNCHRO_CONFIRMATION::action_id, 0, NULL); reply.setInt(0, PACKET_SYNCHRO_CONFIRMATION::status, 0, NULL); reply.send(world_client[0]->world->players[i]->data().client_data.client_id, TO_SERVER, MOD_WORLD_SERVER); } world_client_mutex.unlock(); } break; case MSG_RCT_ERROR: // upozorneni na chybu { TPacket_ErrorResult packet; packet.player_id = player_id; packet.error = package->getInt("error", 0, NULL); KSendGlobalMessage(MSG_RCT_ERROR, MOD_WORLD_CLIENT, MOD_GUI, &packet); } break; default: // ke zprave se neznam, ukoncuji beh vyklu i = MAX_PLAYERS; // ukoncim cyklus (trochu cunarna) break; } // switch } // if } // for } // case break; case MSG_WORLD_GUI: // komunikace s GUI { // pretypovani na obecny typ a nacteni hlavicky PACKET_WORLD_GUI * msg = (PACKET_WORLD_GUI *)p; // zpracovani obsahu switch (msg->type) { // +------------------------------------------------------+ // | | // | S Y N C H R O N N I K O M U N I K A C E | // | | // +------------------------------------------------------+ case MSG_ACT_UNIT_CLICK: /// kliknuti na jednotku { PACKET_ACT_UNIT_CLICK * packet; TLivingUnit * unit; int i; TPacket_RCT_UNIT_CLICK * result = new TPacket_RCT_UNIT_CLICK(); // pretypovani na konkretni typ a ziskani jednotky try { packet = (PACKET_ACT_UNIT_CLICK *)msg; if (world_client[0]->world->units.count(packet->unit_id)) unit = world_client[0]->world->units[packet->unit_id]; else unit = NULL; } catch (std::exception) { result->status = ERR_InvalidUnitId; return result; } // je jednotka platna if (unit == NULL) { result->status = ERR_InvalidUnitId; return result; } // je jednotka moje? if (unit->data().player == msg->player_id) { // je moje // 1. informace - vsechno result->knowledge = UK_MINE; // 2. akce - podle toho, jsem-li na tahu for (i = 0; i < UNIT_ACTION_COUNT; i++) result->actions[i] = 0; if (unit->data().player == world_client[0]->world->players.playerIdOnTurn()) { // jednotka je na tahu world_client[0]->engine->getUnitActions(packet->unit_id, result->actions, result->buildings); } } else { // jednotka neni moje // 1. informace - nepratelska result->knowledge = UK_ENEMY; // 2. akce - nic for (i = 0; i < UNIT_ACTION_COUNT; i++) result->actions[i] = 0; } return result; } break; case MSG_ACT_BUILDING_CLICK: // kliknuti na budovu { PACKET_ACT_BUILDING_CLICK * packet; TLivingBuilding * building; int i; TPacket_RCT_BUILDING_CLICK * result = new TPacket_RCT_BUILDING_CLICK; // pretypovani na konkretni typ a ziskani budovy try { packet = (PACKET_ACT_BUILDING_CLICK *)msg; if (world_client[0]->world->buildings.count(packet->building_id)) building = world_client[0]->world->buildings[packet->building_id]; else building = NULL; } catch (std::exception) { result->status = ERR_InvalidBuildingId; return result; } // je budova platna if (building == NULL) { result->status = ERR_InvalidBuildingId; return result; } // je budova moje? if (building->data().player == msg->player_id) { // je moje // 1. informace -> vsechno result->knowledge = BK_MINE; // 2. akce - podle toho, jsem-li na tahu for (i = 0; i < BUILDING_ACTION_COUNT; i++) result->actions[i] = 0; if (building->data().player == world_client[0]->world->players.playerIdOnTurn()) { // budova je na tahu world_client[0]->engine->getBuildingActions(packet->building_id, result->actions, result->recruitment, result->bonuses); } } else { // jednotka neni moje result->knowledge = BK_ENEMY; for (i = 0; i < BUILDING_ACTION_COUNT; i++) result->actions[i] = 0; } return result; } break; case MSG_GET_RANGE: // ziskani rozsahu pohybu jednotky { // pretypovani na konkretni typ PACKET_GET_RANGE * packet = (PACKET_GET_RANGE *)msg; // vypocet vystupu TPacket_RET_RANGE * result = new TPacket_RET_RANGE; result->range = * world_client[0]->engine->getRange(packet->unit_id); // vraceni dosahu return result; } break; case MSG_GET_ATTACK_RANGE: // ziskani moznych cilu utoku jednotky { // pretypovani na konkretni typ PACKET_GET_ATTACK_RANGE * packet = (PACKET_GET_ATTACK_RANGE *)msg; // vypocet vystupu TPacket_RET_ATTACK_RANGE * result = new TPacket_RET_ATTACK_RANGE(); result->attack_range = world_client[0]->engine->getAttackRange(packet->unit_id); // vraceni dosahu return result; } break; case MSG_GET_BUILDING_RANGE: // ziskani moznych cilu pro stavbu { // pretypovani na konkretni typ PACKET_GET_BUILDING_RANGE * packet = (PACKET_GET_BUILDING_RANGE *)msg; // vypocet vystupu TPacket_RET_BUILDING_RANGE * result = new TPacket_RET_BUILDING_RANGE; result->locations = world_client[0]->engine->getBuildingRange(packet->unit_id, packet->building_type); // vraceni dosahu return result; } break; case MSG_GET_REPAIR_RANGE: // ziskani moznych cilu pro opravu { // pretypovani na konkretni typ PACKET_GET_REPAIR_RANGE * packet = (PACKET_GET_REPAIR_RANGE *)msg; // vypocet TPacket_RET_REPAIR_RANGE * result = new TPacket_RET_REPAIR_RANGE; result->buildings = world_client[0]->engine->getRepairRange(packet->unit_id); // vraceni dosahu return result; } break; // +------------------------------------------------------+ // | | // | A S Y N C H R O N N I K O M U N I K A C E | // | | // +------------------------------------------------------+ case MSG_ACT_NEXT_TURN: /// ukonceni tahu { TPacket_SyncResult * result = new TPacket_SyncResult(); // sestavim sitovou zpravu a predam na server TPackage package(MSG_WORLD_CLIENT_SERVER); package.setInt(MSG_NET_ACT_NEXT_TURN, PACKET_WORLD::type, 0, NULL); package.setInt(msg->player_id, PACKET_WORLD::player_id, 0, NULL); package.send(world_client[0]->world->players[msg->player_id]->data().client_data.client_id, TO_SERVER, MOD_WORLD_SERVER); return result; } break; case MSG_END_GAME_GUI: /// ukonceni hry { WORLD_CLIENT_SERVER_PACKET_INIT(PACKET_END_GAME_GUI, MSG_NET_END_GAME_GUI); package.setInt(packet->final, PACKET_NET_END_GAME_GUI::final, 0, NULL); WORLD_CLIENT_SERVER_PACKET_SEND; return result; } break; case MSG_ACT_UNIT_MOVE: // zadost o pohyb jednotky { WORLD_CLIENT_SERVER_PACKET_INIT(PACKET_ACT_UNIT_MOVE, MSG_NET_ACT_UNIT_MOVE); if (!WORLD_CLIENT_UNIT_OPERATIONAL(packet->unit_id)) result->status = ERR_InvalidInput; else { package.setInt(packet->unit_id, PACKET_NET_ACT_UNIT_MOVE::unit_id, 0, NULL); package.setInt(packet->target, PACKET_NET_ACT_UNIT_MOVE::to, 0, NULL); WORLD_CLIENT_SERVER_PACKET_SEND; } return result; } break; case MSG_ACT_UNIT_ATTACK: // utok jednotky { // navratova hodnota (dealokuje prijemce) TPacket_SyncResult * result = new TPacket_SyncResult(); // pretypovani na konkretni typ PACKET_ACT_UNIT_ATTACK * packet = (PACKET_ACT_UNIT_ATTACK *)msg; // kontrola opravneni k utoku if (!world_client[0]->world->unitOperational(packet->attacker, packet->player_id)) result->status = ERR_InvalidInput; else { // odeslani na server TPackage package(MSG_WORLD_CLIENT_SERVER); package.setInt(MSG_NET_ACT_UNIT_ATTACK, PACKET_WORLD::type, 0, NULL); package.setInt(msg->player_id, PACKET_WORLD::player_id, 0, NULL); package.setInt(packet->attacker, PACKET_NET_ACT_UNIT_ATTACK::attacker, 0, NULL); package.setInt(packet->target, PACKET_NET_ACT_UNIT_ATTACK::target, 0, NULL); package.send(world_client[0]->world->players[packet->player_id]->data().client_data.client_id, TO_SERVER, MOD_WORLD_SERVER); } return result; } break; case MSG_ACT_UNIT_SUICIDE: // sebezniceni jednotky { // navratova hodnota (dealokuje prijemce) TPacket_SyncResult * result = new TPacket_SyncResult(); // pretypovani na konkretni typ PACKET_ACT_UNIT_SUICIDE * packet = (PACKET_ACT_UNIT_SUICIDE *)msg; // kontrola opravneni if (!world_client[0]->world->unitOperational(packet->unit_id, packet->player_id)) result->status = ERR_InvalidInput; else { // odeslani na server TPackage package(MSG_WORLD_CLIENT_SERVER); package.setInt(MSG_NET_ACT_UNIT_SUICIDE, PACKET_WORLD::type, 0, NULL); package.setInt(msg->player_id, PACKET_WORLD::player_id, 0, NULL); package.setInt(packet->unit_id, PACKET_NET_ACT_UNIT_SUICIDE::unit_id, 0, NULL); package.send(world_client[0]->world->players[packet->player_id]->data().client_data.client_id, TO_SERVER, MOD_WORLD_SERVER); } return result; } break; case MSG_ACT_BUILDING_SUICIDE: // sebezniceni jednotky { // navratova hodnota (dealokuje prijemce) TPacket_SyncResult * result = new TPacket_SyncResult(); // pretypovani na konkretni typ PACKET_ACT_BUILDING_SUICIDE * packet = (PACKET_ACT_BUILDING_SUICIDE *)msg; // kontrola opravneni if (!world_client[0]->world->buildingOperational(packet->building_id, packet->player_id)) result->status = ERR_InvalidInput; else { // odeslani na server TPackage package(MSG_WORLD_CLIENT_SERVER); package.setInt(MSG_NET_ACT_BUILDING_SUICIDE, PACKET_WORLD::type, 0, NULL); package.setInt(msg->player_id, PACKET_WORLD::player_id, 0, NULL); package.setInt(packet->building_id, PACKET_NET_ACT_BUILDING_SUICIDE::building_id, 0, NULL); package.send(world_client[0]->world->players[packet->player_id]->data().client_data.client_id, TO_SERVER, MOD_WORLD_SERVER); } return result; } break; case MSG_ACT_BUILDING_RECRUIT_UNIT: // vyroba jednotky { // navratova hodnota (dealokuje prijemce) TPacket_SyncResult * result = new TPacket_SyncResult(); // pretypovani na konkretni typ PACKET_ACT_BUILDING_RECRUIT_UNIT * packet = (PACKET_ACT_BUILDING_RECRUIT_UNIT *)msg; // kontrola opravneni if (!world_client[0]->world->buildingOperational(packet->building_id, packet->player_id)) result->status = ERR_InvalidInput; else { // odeslani na server TPackage package(MSG_WORLD_CLIENT_SERVER); package.setInt(MSG_NET_ACT_BUILDING_RECRUIT_UNIT, PACKET_WORLD::type, 0, NULL); package.setInt(msg->player_id, PACKET_WORLD::player_id, 0, NULL); package.setInt(packet->unit_type, PACKET_NET_ACT_BUILDING_RECRUIT_UNIT::unit_type, 0, NULL); package.setInt(packet->building_id, PACKET_NET_ACT_BUILDING_RECRUIT_UNIT::building_id, 0, NULL); package.send(world_client[0]->world->players[packet->player_id]->data().client_data.client_id, TO_SERVER, MOD_WORLD_SERVER); } return result; } break; case MSG_ACT_START_BUILDING: // zahajeni stavby { // navratova hodnota (dealokuje prijemce) TPacket_SyncResult * result = new TPacket_SyncResult(); // pretypovani PACKET_ACT_START_BUILDING * packet = (PACKET_ACT_START_BUILDING *)msg; // kontrola if (!world_client[0]->world->unitOperational(packet->unit_id, packet->player_id)) result->status = ERR_InvalidInput; else { // odeslani na server TPackage package(MSG_WORLD_CLIENT_SERVER); package.setInt(MSG_NET_ACT_START_BUILDING, PACKET_WORLD::type, 0, NULL); package.setInt(msg->player_id, PACKET_WORLD::player_id, 0, NULL); package.setInt(packet->building_type, PACKET_NET_ACT_START_BUILDING::building_type, 0, NULL); package.setInt(packet->location, PACKET_NET_ACT_START_BUILDING::location, 0, NULL); package.setInt(packet->unit_id, PACKET_NET_ACT_START_BUILDING::unit_id, 0, NULL); package.setInt(packet->orientation, PACKET_NET_ACT_START_BUILDING::orientation, 0, NULL); package.send(world_client[0]->world->players[packet->player_id]->data().client_data.client_id, TO_SERVER, MOD_WORLD_SERVER); } return result; } break; case MSG_ACT_REPAIR_BUILDING: // zahajeni opravy { // navratova hodnota (dealokuje prijemce) TPacket_SyncResult * result = new TPacket_SyncResult(); // pretypovani PACKET_ACT_REPAIR_BUILDING * packet = (PACKET_ACT_REPAIR_BUILDING *)msg; // kontrola if (!world_client[0]->world->unitOperational(packet->unit_id, packet->player_id)) result->status = ERR_InvalidInput; else { // odeslani na server TPackage package(MSG_WORLD_CLIENT_SERVER); package.setInt(MSG_NET_ACT_REPAIR_BUILDING, PACKET_WORLD::type, 0, NULL); package.setInt(msg->player_id, PACKET_WORLD::player_id, 0, NULL); package.setInt(packet->building_id, PACKET_NET_ACT_REPAIR_BUILDING::building_id, 0, NULL); package.setInt(packet->unit_id, PACKET_NET_ACT_REPAIR_BUILDING::unit_id, 0, NULL); package.send(world_client[0]->world->players[packet->player_id]->data().client_data.client_id, TO_SERVER, MOD_WORLD_SERVER); } return result; } break; case MSG_ACT_STOP_BUILDING: // preruseni stavby { // navratova hodnota (dealokuje prijemce) TPacket_SyncResult * result = new TPacket_SyncResult(); // pretypovani PACKET_ACT_STOP_BUILDING * packet = (PACKET_ACT_STOP_BUILDING *)msg; // kontrola if (!world_client[0]->world->unitOperational(packet->unit_id, packet->player_id)) result->status = ERR_InvalidInput; else { // odeslani na server TPackage package(MSG_WORLD_CLIENT_SERVER); package.setInt(MSG_NET_ACT_STOP_BUILDING, PACKET_WORLD::type, 0, NULL); package.setInt(msg->player_id, PACKET_WORLD::player_id, 0, NULL); package.setInt(packet->unit_id, PACKET_NET_ACT_STOP_BUILDING::unit_id, 0, NULL); package.send(world_client[0]->world->players[packet->player_id]->data().client_data.client_id, TO_SERVER, MOD_WORLD_SERVER); } return result; } break; case MSG_ACT_SELL_BONUS: // prodej bonusu jednotce v budove { // navratova hodnota (dealokuje prijemce) TPacket_SyncResult * result = new TPacket_SyncResult(); // pretypovani PACKET_ACT_SELL_BONUS * packet = (PACKET_ACT_SELL_BONUS *)msg; // kontrola if (!world_client[0]->world->buildingOperational(packet->building_id, packet->player_id)) result->status = ERR_InvalidInput; else { // odeslani na server TPackage package(MSG_WORLD_CLIENT_SERVER); package.setInt(MSG_NET_ACT_SELL_BONUS, PACKET_WORLD::type, 0, NULL); package.setInt(msg->player_id, PACKET_WORLD::player_id, 0, NULL); package.setInt(packet->building_id, PACKET_NET_ACT_SELL_BONUS::building_id, 0, NULL); package.setInt(packet->bonus_id, PACKET_NET_ACT_SELL_BONUS::bonus_id, 0, NULL); package.send(world_client[0]->world->players[packet->player_id]->data().client_data.client_id, TO_SERVER, MOD_WORLD_SERVER); } return result; } break; case MSG_ACT_UNIT_HEAL: // leceni jednotky { // navratova hodnota (dealokuje prijemce) TPacket_SyncResult * result = new TPacket_SyncResult(); // pretypovani PACKET_ACT_UNIT_HEAL * packet = (PACKET_ACT_UNIT_HEAL *)msg; // kontrola if (!world_client[0]->world->unitOperational(packet->unit_id, packet->player_id)) result->status = ERR_InvalidInput; else { // odeslani na server TPackage package(MSG_WORLD_CLIENT_SERVER); package.setInt(MSG_NET_ACT_UNIT_HEAL, PACKET_WORLD::type, 0, NULL); package.setInt(msg->player_id, PACKET_WORLD::player_id, 0, NULL); package.setInt(packet->unit_id, PACKET_NET_ACT_UNIT_HEAL::unit_id, 0, NULL); package.send(world_client[0]->world->players[packet->player_id]->data().client_data.client_id, TO_SERVER, MOD_WORLD_SERVER); } return result; } break; case MSG_ACT_UNIT_RECRUIT: // doplneni jednotky (neelitni) { // navratova hodnota (dealokuje prijemce) TPacket_SyncResult * result = new TPacket_SyncResult(); // pretypovani PACKET_ACT_UNIT_RECRUIT * packet = (PACKET_ACT_UNIT_RECRUIT *)msg; // kontrola if (!world_client[0]->world->unitOperational(packet->unit_id, packet->player_id)) result->status = ERR_InvalidInput; else { // odeslani na server TPackage package(MSG_WORLD_CLIENT_SERVER); package.setInt(MSG_NET_ACT_UNIT_RECRUIT, PACKET_WORLD::type, 0, NULL); package.setInt(msg->player_id, PACKET_WORLD::player_id, 0, NULL); package.setInt(packet->unit_id, PACKET_NET_ACT_UNIT_RECRUIT::unit_id, 0, NULL); package.send(world_client[0]->world->players[packet->player_id]->data().client_data.client_id, TO_SERVER, MOD_WORLD_SERVER); } return result; } break; case MSG_ACT_UNIT_RECRUIT_ELITE: // doplneni jednotky (elitni) { // navratova hodnota (dealokuje prijemce) TPacket_SyncResult * result = new TPacket_SyncResult(); // pretypovani PACKET_ACT_UNIT_RECRUIT_ELITE * packet = (PACKET_ACT_UNIT_RECRUIT_ELITE *)msg; // kontrola if (!world_client[0]->world->unitOperational(packet->unit_id, packet->player_id)) result->status = ERR_InvalidInput; else { // odeslani na server TPackage package(MSG_WORLD_CLIENT_SERVER); package.setInt(MSG_NET_ACT_UNIT_RECRUIT_ELITE, PACKET_WORLD::type, 0, NULL); package.setInt(msg->player_id, PACKET_WORLD::player_id, 0, NULL); package.setInt(packet->unit_id, PACKET_NET_ACT_UNIT_RECRUIT_ELITE::unit_id, 0, NULL); package.send(world_client[0]->world->players[packet->player_id]->data().client_data.client_id, TO_SERVER, MOD_WORLD_SERVER); } return result; } break; case MSG_ACT_OFFER_RELATION: // nastaveni diplomatickeho vztahu { // navratova hodnota (dealokuje prijemce) TPacket_SyncResult * result = new TPacket_SyncResult(); // pretypovani PACKET_ACT_OFFER_RELATION * packet = (PACKET_ACT_OFFER_RELATION *)msg; // kontrola if (!world_client[0]->world->playerOperational(packet->player_id)) result->status = ERR_InvalidInput; else { // odeslani na server TPackage package(MSG_WORLD_CLIENT_SERVER); package.setInt(MSG_NET_ACT_OFFER_RELATION, PACKET_WORLD::type, 0, NULL); package.setInt(packet->player_id, PACKET_WORLD::player_id, 0, NULL); package.setInt(packet->offered_relationship, PACKET_NET_ACT_OFFER_RELATION::offered_relationship, 0, NULL); package.setInt(packet->source_diplomat_world_id, PACKET_NET_ACT_OFFER_RELATION::source_diplomat_world_id, 0, NULL); package.setInt(packet->target_diplomat_world_id, PACKET_NET_ACT_OFFER_RELATION::target_diplomat_world_id, 0, NULL); package.send(world_client[0]->world->players[msg->player_id]->data().client_data.client_id, TO_SERVER, MOD_WORLD_SERVER); } return result; } break; } // switch } break; case MSG_WORLD_TCL: // zpravy zasilane z TCL { PACKET_WORLD_TCL * packet = (PACKET_WORLD_TCL *)p; switch (packet->type) { case MSG_GET_HEX: // dotaz na hex (dle souradnic) { if ((packet->argc == 2) && (packet->argv[0] != NULL) && (packet->argv[1] != NULL)) { THex * hex = world_client[0]->world->map.getHexAt(atoi(packet->argv[0]), atoi(packet->argv[1])); if (hex) hex->writeToTCL(world_client[0]->engine->interpreter, packet->varName); else THROW(E_8K_TCL_Error, "Invalid hex coords"); } else return (void *)ERR_InvalidInput; } break; case MSG_GET_HEX_BY_ID: // dotaz na hex (dle ID) { if ((packet->argc == 1) && (packet->argv[0] != NULL)) { THex * hex = world_client[0]->world->map.getHexById(atoi(packet->argv[0])); if (hex) hex->writeToTCL(world_client[0]->engine->interpreter, packet->varName); else THROW(E_8K_TCL_Error, "Invalid hex coords"); } else return (void *)ERR_InvalidInput; } break; case MSG_GET_WEATHER: // dotaz na pocasi { world_client[0]->world->weather.writeToTCL(world_client[0]->engine->interpreter, packet->varName); } break; case MSG_GET_LIVING_UNIT: // dotaz na "zivou" jendotku { if ((packet->argc == 1) && (packet->argv[0] != NULL)) { int id = atoi(packet->argv[0]); if (world_client[0]->world->units.count(id)) { TLivingUnit * unit = world_client[0]->world->units[id]; unit->writeToTCL(world_client[0]->engine->interpreter, packet->varName); } else THROW(E_8K_TCL_Error, "Invalid unit ID"); } else return (void *)ERR_InvalidInput; } break; case MSG_GET_LIVING_UNITS: // dotaz na seznam jednotek { TTCL_Int_List units; TLivingUnitsIterator it; if ((packet->argc == 1) && (packet->argv[0] != NULL)) { int player_id = atoi(packet->argv[0]); // chci jednotky jen konkretniho hrace for (it = world_client[0]->world->units.begin(); it != world_client[0]->world->units.end(); it++) { if (it->second->data().player == player_id) units.push_back(it->first); } } else { // chci vsechny jednotky for (it = world_client[0]->world->units.begin(); it != world_client[0]->world->units.end(); it++) { units.push_back(it->first); } } world_client[0]->engine->interpreter.setVar(packet->varName, TVT_INT_LIST, &units); } break; case MSG_GET_LIVING_BUILDING: // dotaz na "zivou" budovu { if ((packet->argc == 1) && (packet->argv[0] != NULL)) { int id = atoi(packet->argv[0]); if (world_client[0]->world->buildings.count(id)) { TLivingBuilding * building = world_client[0]->world->buildings[id]; building->writeToTCL(world_client[0]->engine->interpreter, packet->varName); } else THROW(E_8K_TCL_Error, "Invalid building ID"); } else return (void *)ERR_InvalidInput; } break; case MSG_GET_LIVING_BUILDINGS: // dotaz na seznam budov { TTCL_Int_List buildings; TLivingBuildingsIterator it; if ((packet->argc == 1) && (packet->argv[0] != NULL)) { int player_id = atoi(packet->argv[0]); // chci budovy jen konkretniho hrace for (it = world_client[0]->world->buildings.begin(); it != world_client[0]->world->buildings.end(); it++) { if (it->second->data().player == player_id) buildings.push_back(it->first); } } else { // chci vsechny jednotky for (it = world_client[0]->world->buildings.begin(); it != world_client[0]->world->buildings.end(); it++) { buildings.push_back(it->first); } } world_client[0]->engine->interpreter.setVar(packet->varName, TVT_INT_LIST, &buildings); } break; case MSG_GET_PLAYER: // dotaz na hrace { if ((packet->argc == 1) && (packet->argv[0] != NULL)) { int id = atoi(packet->argv[0]); if (world_client[0]->world->players.count(id)) { TPlayer * player = world_client[0]->world->players[id]; player->writeToTCL(world_client[0]->engine->interpreter, packet->varName); } else THROW(E_8K_TCL_Error, "Invalid player ID"); } else return (void *)ERR_InvalidInput; } break; case MSG_GET_PLAYERS: // dotaz na seznam hracu { TTCL_Int_List players; TPlayerIterator it; for (it = world_client[0]->world->players.begin(); it != world_client[0]->world->players.end(); it++) { if (it->second->data().game_data.state == PS_ACTIVE) players.push_back(it->first); } world_client[0]->engine->interpreter.setVar(packet->varName, TVT_INT_LIST, &players); } break; case MSG_GET_KINGDOM: // dotaz na kralovstvi { if ((packet->argc == 1) && (packet->argv[0] != NULL)) { int id = atoi(packet->argv[0]); if (world_client[0]->world->kingdoms.count(id)) { TKingdom * kingdom = world_client[0]->world->kingdoms[id]; kingdom->writeToTCL(world_client[0]->engine->interpreter, packet->varName); } else THROW(E_8K_TCL_Error, "Invalid hex coords"); } else return (void *)ERR_InvalidInput; } break; case MSG_GET_KINGDOMS: // dotaz na seznam kralovstvi { TTCL_Int_List kingdoms; TKingdomsIterator it; if ((packet->argc == 1) && (packet->argv[0] != NULL)) { int player_id = atoi(packet->argv[0]); // chci kralovstvi konkretniho hrace for (it = world_client[0]->world->kingdoms.begin(); it != world_client[0]->world->kingdoms.end(); it++) { if (it->second->data().roleid == player_id) kingdoms.push_back(it->first); } } else { // chci vsechna kralovstvi for (it = world_client[0]->world->kingdoms.begin(); it != world_client[0]->world->kingdoms.end(); it++) { kingdoms.push_back(it->first); } } world_client[0]->engine->interpreter.setVar(packet->varName, TVT_INT_LIST, &kingdoms); } break; case MSG_GET_TOWN: // dotaz na mesto { if ((packet->argc == 1) && (packet->argv[0] != NULL)) { int id = atoi(packet->argv[0]); if (world_client[0]->world->towns.count(id)) { TTown * town = world_client[0]->world->towns[id]; town->writeToTCL(world_client[0]->engine->interpreter, packet->varName); } else THROW(E_8K_TCL_Error, "Invalid town ID"); } else return (void *)ERR_InvalidInput; } break; case MSG_GET_TOWNS: // dotaz na seznam mest { TTCL_Int_List towns; TTownsIterator it; THex * hex; if ((packet->argc == 1) && (packet->argv[0] != NULL)) { int kingdom_id = atoi(packet->argv[0]); // chci mesta jen konkretniho kralovstvi for (it = world_client[0]->world->towns.begin(); it != world_client[0]->world->towns.end(); it++) { // projdu si hexy mesta a pokud alespon jeden lezi na aktualnim // kralovstvi, zaradim jej do seznamu for (int i = 0; i < it->second->data().citysize; i++) { hex = world_client[0]->world->map.getHexById(it->second->data().position[i]); if (hex->data().kingdom == kingdom_id) { // mesto lezi alespon jednim hexem na aktualnim kralovstvi towns.push_back(it->first); break; } } } } else { // chci vsechna mesta for (it = world_client[0]->world->towns.begin(); it != world_client[0]->world->towns.end(); it++) { towns.push_back(it->first); } } world_client[0]->engine->interpreter.setVar(packet->varName, TVT_INT_LIST, &towns); } break; case MSG_GET_HEX_NEIGHBOUR: // dotaz na konkretni sousedni hex { if ((packet->argc == 2) && (packet->argv[0] != NULL) && (packet->argv[1] != NULL)) { int hex_id = atoi(packet->argv[0]); int orientation = atoi(packet->argv[1]); TIntContainer neighbours = world_client[0]->world->map.getNeighboursOrientation(hex_id, orientation); if (neighbours.size() > 0) { world_client[0]->engine->interpreter.setVar(packet->varName, TVT_INT_LIST, (TTCL_Int_List *)&neighbours); } else { return (void *)ERR_InvalidInput; } } else return (void *)ERR_InvalidInput; } break; case MSG_GET_HEX_NEIGHBOURS: // dotaz na seznam okolnich hexu { if ((packet->argc == 1) && (packet->argv[0] != NULL)) { int hex_id = atoi(packet->argv[0]); TIntContainer * neighbours = world_client[0]->world->map.getNeighbours(hex_id); world_client[0]->engine->interpreter.setVar(packet->varName, TVT_INT_LIST, (TTCL_Int_List *)neighbours); delete neighbours; } else { return (void *)ERR_InvalidInput; } } break; } } break; default: // ostatni nebo nespecifikovana komunikace switch (mid) { case MSG_GUIMAP_READY: // potvrzeni nahrani hry { int i; for (i = 1; i <= MAX_PLAYERS; i++) { if (world_client[i] != NULL) { TPackage reply(MSG_WORLD_CLIENT_SERVER); reply.setInt(MSG_GUIMAP_READY, PACKET_WORLD::type, 0, NULL); reply.setInt(i, PACKET_WORLD::player_id, 0, NULL); reply.send(world_client[0]->world->players[i]->data().client_data.client_id, TO_SERVER, MOD_WORLD_SERVER); break; } } } break; case MSG_SAVE_GAME: // ulozeni hry { TPacket_SyncResult * result = new TPacket_SyncResult(); PACKET_SAVE_GAME * packet = (PACKET_SAVE_GAME *)p; try { world_client[0]->saveMap(packet->filename); } catch (E_8K) { result->status = ERR_General; } return result; } break; case MSG_END_CLIENT: // vyzva k odpojeni klienta { TPacket_END_GAME packet; packet.readFromXML((TPackage *)p); for (int i = 0; i <= MAX_PLAYERS; i++) if (world_client[i]) world_client[i]->history->reset(); KSendGlobalMessage(MSG_END_GAME, MOD_WORLD_CLIENT, BROADCAST, &packet); } break; case MSG_GAME_STARTED: // zahajeni hry { if (world_client[0]->state != WCS_GAME_STARTED) { for (int i = 0; i <= MAX_PLAYERS; i++) if (world_client[i]) world_client[i]->state = WCS_GAME_STARTED; #ifdef CLIENT_AUTOPLAY // pokud hraji AUTOPLAY a zacina clovek, rovnou predam tah if ((world_client[world_client[0]->world->players.playerIdOnTurn()] != NULL) && (world_client[0]->world->players.playerOnTurn()->data().client_data.type == PT_HUMAN)) { PACKET_WORLD_GUI next_turn; next_turn.player_id = world_client[0]->world->players.playerIdOnTurn(); next_turn.type = MSG_ACT_NEXT_TURN; KSendGlobalMessage(MSG_WORLD_GUI, MOD_WORLD_CLIENT, MOD_WORLD_CLIENT, &next_turn); } #endif } break; } case MSG_END_GAME: // ukonceni hry { for (int i = 0; i <= MAX_PLAYERS; i++) if (world_client[i]) world_client[i]->state = WCS_GAME_ENDED; } break; case MSG_NET_LOST_CONNECTION: // ztrata spojeni se serverem { if (world_client[0] && world_client[0]->state >= WCS_EMPTY) { TPacket_END_GAME packet; packet.reason = ER_SHUTDOWN; packet.winner = 0; for (int i = 0; i <= MAX_PLAYERS; i++) if (world_client[i]) world_client[i]->history->reset(); KSendGlobalMessage(MSG_END_GAME, MOD_WORLD_CLIENT, BROADCAST, &packet); } } break; } // switch } // switch return NULL; }; int WorldClient_SendMessage(ClientData Data, Tcl_Interp * pInterp, int argc, char *argv[]) { void * result; PACKET_WORLD_TCL packet; // nactu typ zpravy if (argc < 3) { // nedostatecny pocet parametru return TCL_ERROR; } // pripravim packet packet.type = atoi(argv[1]); packet.varName = argv[2]; packet.argc = argc - 3; packet.argv = &argv[3]; result = KSendGlobalMessage(MSG_WORLD_TCL, 0, MOD_WORLD_CLIENT, &packet); if (result == NULL) return TCL_OK; else return TCL_ERROR; }; }//namespace