/// Fügt einen Schiffs-Angreifer zum Hafen hinzu void nobHarborBuilding::AddSeaAttacker(nofAttacker * attacker) { unsigned best_distance = 0xffffffff; unsigned best_harbor_point = 0xffffffff; std::vector<unsigned> harbor_points; gwg->GetHarborPointsAroundMilitaryBuilding(attacker->GetAttackedGoal()->GetX(),attacker->GetAttackedGoal()->GetY(), &harbor_points); for(unsigned i = 0;i<harbor_points.size();++i) { unsigned tmp_distance = gwg->CalcHarborDistance(this->GetHarborPosID(),harbor_points[i]); if(tmp_distance < best_distance) { best_distance = tmp_distance; best_harbor_point = harbor_points[i]; } } // no harbor point found? tell attacker that the goal has been destroyed. if (best_harbor_point == 0xffffffff) { // TODO: true or false? AddFigure(attacker, false); attacker->AttackedGoalDestroyed(); return; } SoldierForShip sfs = { attacker, gwg->GetHarborPoint(best_harbor_point) }; soldiers_for_ships.push_back(sfs); OrderShip(); ++goods.people[attacker->GetJobType()]; }
/// People waiting for a ship have to examine their route if a road was destroyed void nobHarborBuilding::ExamineShipRouteOfPeople() { for(std::list<FigureForShip>::iterator it = figures_for_ships.begin(); it!=figures_for_ships.end();) { it->dest = it->fig->ExamineRouteBeforeShipping(); unsigned char next_dir = it->fig->GetDir(); if(next_dir == 0xff) { // No route found! // I.E. insert the worker in this harbor noFigure * fig = it->fig; it = figures_for_ships.erase(it); AddFigure(fig,false); } else if(next_dir != SHIP_DIR) { // Figure want to continue walking to its goal but not on ship anymore noFigure * fig = it->fig; it = figures_for_ships.erase(it); this->AddLeavingFigure(fig); } else // Otherwise figure want to travel by ship, do nothing! ++it; } }
/// Bestellte Figur, die sich noch inder Warteschlange befindet, kommt nicht mehr und will rausgehauen werden void nobHarborBuilding::CancelFigure(noFigure * figure) { // Merken, ob sie entfernt wurde bool removed = false; // Figur ggf. aus der List entfernen for(std::list<FigureForShip>::iterator it = figures_for_ships.begin();it!=figures_for_ships.end();++it) { if(it->fig == figure) { figures_for_ships.erase(it); removed = true; break; } } // Wurde sie entfernt? if(removed) { // Dann zu unserem Inventar hinzufügen und anschließend vernichten AddFigure(figure,false); } // An Basisklasse weiterdelegieren else nobBaseWarehouse::CancelFigure(figure); }
/// Fügt einen Schiffs-Angreifer zum Hafen hinzu void nobHarborBuilding::AddSeaAttacker(nofAttacker* attacker) { unsigned best_distance = 0xffffffff; unsigned best_harbor_point = 0xffffffff; RTTR_Assert(attacker->GetAttackedGoal()); std::vector<unsigned> harbor_points = gwg->GetHarborPointsAroundMilitaryBuilding(attacker->GetAttackedGoal()->GetPos()); for(unsigned i = 0; i < harbor_points.size(); ++i) { unsigned tmp_distance = gwg->CalcHarborDistance(this->GetHarborPosID(), harbor_points[i]); if(tmp_distance < best_distance) { best_distance = tmp_distance; best_harbor_point = harbor_points[i]; } } // no harbor to target (should not happen) or no target (might happen very very rarely not sure) if (best_harbor_point == 0xffffffff) { // notify target about noShow, notify home that soldier wont return, add to inventory attacker->SeaAttackFailedBeforeLaunch(); //set state, remove target & home RTTR_Assert(!attacker->GetAttackedGoal()); RTTR_Assert(attacker->HasNoHome()); RTTR_Assert(attacker->HasNoGoal()); AddFigure(attacker, true); return; } SoldierForShip sfs = { attacker, gwg->GetHarborPoint(best_harbor_point) }; soldiers_for_ships.push_back(sfs); inventory.visual.Add(attacker->GetJobType()); OrderShip(); }
/// Bestellte Figur, die sich noch inder Warteschlange befindet, kommt nicht mehr und will rausgehauen werden void nobBaseWarehouse::CancelFigure(noFigure* figure) { std::list<noFigure *>::iterator it = std::find(leave_house.begin(), leave_house.end(), figure); RTTR_Assert(it != leave_house.end()); // TODO: Is this true in all cases? If yes, remove the check below // Figure aus den Waiting-Wares entfernen if (it != leave_house.end()) leave_house.erase(it); AddFigure(figure, false); }
/// Erhält die Waren von einem Schiff und nimmt diese in den Warenbestand auf void nobHarborBuilding::ReceiveGoodsFromShip(std::list<noFigure*>& figures, std::list<Ware*>& wares) { // Menschen zur Ausgehliste hinzufügen for(std::list<noFigure*>::const_iterator it = figures.begin(); it != figures.end(); ++it) { (*it)->ArrivedByShip(pos); // Wenn es kein Ziel mehr hat, sprich keinen weiteren Weg, kann es direkt hier gelagert werden if((*it)->GetGoal() == this) (*it)->SetGoalToNULL(); else if(!(*it)->HasNoGoal()) { unsigned char nextDir; MapPoint next_harbor = (*it)->ExamineRouteBeforeShipping(nextDir); if (nextDir == 4) { // Increase visual count if((*it)->GetJobType() == JOB_BOATCARRIER) { inventory.visual.Add(JOB_HELPER); inventory.visual.Add(GD_BOAT); } else inventory.visual.Add((*it)->GetJobType()); AddLeavingFigure(*it); (*it)->ShipJourneyEnded(); } else if (nextDir == SHIP_DIR) { AddFigureForShip(*it, next_harbor); }else { // No or invalid path -> Store here RTTR_Assert(nextDir == 0xFF); (*it)->SetGoalToNULL(); AddDependentFigure(*it); } }else AddDependentFigure(*it); // No goal? We take it if ((*it)->HasNoGoal()) AddFigure(*it, true); } figures.clear(); // Waren zur Warteliste hinzufügen for(std::list<Ware*>::iterator it = wares.begin(); it != wares.end(); ++it) { (*it)->ShipJorneyEnded(this); AddWare(*it); } wares.clear(); }
void GameWorld::Scan(glArchivItem_Map *map) { width = map->getHeader().getWidth(); height = map->getHeader().getHeight(); lt = LandscapeType(map->getHeader().getGfxSet()); Init(); // Dummy-Hafenpos für Index 0 einfügen // ask Oliverr why! // -> I just did, the dummy is so that the harbor "0" might be used for ships with no particular destination // poc: if you ever remove this dummy go to GameWorldBase::CalcDistanceToNearestHarbor and fix the loop to include the first harbor again (think Ive seen other instances of dummyadjusted loops as well...) GameWorldBase::HarborPos dummy = {0,0}; harbor_pos.push_back(dummy); // Andere Sachen setzen for(unsigned y = 0;y<height;++y) { for(unsigned x = 0;x<width;++x) { MapNode& node = nodes[y*width+x]; node.roads[2] = node.roads[1] = node.roads[0] = 0; node.roads_real[2] = node.roads_real[1] = node.roads_real[0] = false; node.altitude = map->GetMapDataAt(MAP_ALTITUDE, x, y); // Aufpassen, dass die Terrainindizes im Rahmen liegen, ansonsten 0 nehmen, unbekanntes Terrain (Bsp. // Karte "Drachenebene") unsigned char t1 = map->GetMapDataAt(MAP_TERRAIN1, x, y), t2 = map->GetMapDataAt(MAP_TERRAIN2, x, y); // Hafenplatz? if(t1 >= 0x40 && t1 <= 0x54) { t1 -= 0x40; GameWorldBase::HarborPos p = {x,y}; node.harbor_id = harbor_pos.size(); harbor_pos.push_back(p); } else node.harbor_id = 0; node.t1 = (t1<20)?TERRAIN_INDIZES[t1]:0; node.t2 = (t2<20)?TERRAIN_INDIZES[t2]:0; node.resources = map->GetMapDataAt(MAP_RESOURCES, x, y); // Wasser? if(node.resources == 0x20 || node.resources == 0x21) { // TODO: Berge hatten komische Wasserbeeinflussung // ggf 0-4 Wasser setzen if( (node.t1 == TT_DESERT || node.t2 == TT_DESERT) || (node.t1 == TT_WATER || node.t2 == TT_WATER) ) node.resources = 0; // Kein Wasser, in der Wüste, da isses trocken! else if( (node.t1 == TT_STEPPE || node.t2 == TT_STEPPE) ) node.resources = 0x23; // 2 Wasser else if( (node.t1 == TT_SAVANNAH || node.t2 == TT_SAVANNAH) ) node.resources = 0x25; // 4 Wasser else node.resources = 0x27; // 7 Wasser } node.reserved = false; node.owner = 0; for(unsigned i = 0;i<4;++i) node.boundary_stones[i] = 0; node.sea_id = 0; // FOW-Zeug initialisieren for(unsigned i = 0;i<GameClient::inst().GetPlayerCount();++i) { switch(GameClient::inst().GetGGS().exploration) { case GlobalGameSettings::EXP_DISABLED: { node.fow[i].visibility = VIS_VISIBLE; } break; case GlobalGameSettings::EXP_CLASSIC: { node.fow[i].visibility = VIS_INVISIBLE; } break; case GlobalGameSettings::EXP_FOGOFWAR: { node.fow[i].visibility = VIS_INVISIBLE; } break; case GlobalGameSettings::EXP_FOGOFWARE_EXPLORED: { node.fow[i].visibility = VIS_FOW; } break; } node.fow[i].last_update_time = 0; node.fow[i].object = NULL; node.fow[i].roads[0] = node.fow[i].roads[1] = node.fow[i].roads[2] = 0; node.fow[i].owner = 0; for(unsigned z = 0;z<4;++z) node.fow[i].boundary_stones[z] = 0; } } } std::vector< Point<MapCoord> > headquarter_positions; // Objekte auslesen for(unsigned y = 0;y<height;++y) { for(unsigned x = 0;x<width;++x) { unsigned int pos = y*width+x; unsigned char lc = map->GetMapDataAt(MAP_LANDSCAPE, x, y); switch(map->GetMapDataAt(MAP_TYPE, x, y)) { // Player Startpos (provisorisch) case 0x80: { headquarter_positions.push_back(Point<MapCoord>(x, y)); if(lc < GAMECLIENT.GetPlayerCount()) { GetPlayer(lc)->hqx = x; GetPlayer(lc)->hqy = y; nodes[pos].obj = NULL; } } break; // Baum 1-4 case 0xC4: { if(lc >= 0x30 && lc <= 0x3D) nodes[pos].obj = new noTree(x,y,0,3); else if(lc >= 0x70 && lc <= 0x7D) nodes[pos].obj = new noTree(x,y,1,3); else if(lc >= 0xB0 && lc <= 0xBD) nodes[pos].obj = new noTree(x,y,2,3); else if(lc >= 0xF0 && lc <= 0xFD) nodes[pos].obj = new noTree(x,y,3,3); else { LOG.lprintf("Unbekannter Baum1-4 auf x=%d, y=%d: id=%d (0x%0X)\n", x, y, lc, lc); nodes[pos].obj = NULL; } } break; // Baum 5-8 case 0xC5: { if(lc >= 0x30 && lc <= 0x3D) nodes[pos].obj = new noTree(x,y,4,3); else if(lc >= 0x70 && lc <= 0x7D) nodes[pos].obj = new noTree(x,y,5,3); else if(lc >= 0xB0 && lc <= 0xBD) nodes[pos].obj = new noTree(x,y,6,3); else if(lc >= 0xF0 && lc <= 0xFD) nodes[pos].obj = new noTree(x,y,7,3); else { LOG.lprintf("Unbekannter Baum5-8 auf x=%d, y=%d: id=%d (0x%0X)\n", x, y, lc, lc); nodes[pos].obj = NULL; } } break; // Baum 9 case 0xC6: { if(lc >= 0x30 && lc <= 0x3D) nodes[pos].obj = new noTree(x,y,8,3); else { LOG.lprintf("Unbekannter Baum9 auf x=%d, y=%d: id=%d (0x%0X)\n", x, y, lc, lc); nodes[pos].obj = NULL; } } break; // Sonstiges Naturzeug ohne Funktion, nur zur Dekoration case 0xC8: { /// @todo mis0bobs unvollständig (dieses lagerzelt), 4 und 5 überhaupt nicht erwähnt // mis1bobs, 2 und 3 sind vollständig eingebaut // Objekte aus der map_?_z.lst if(lc <= 0x0A) nodes[pos].obj = new noEnvObject(x, y, 500+lc); // "wasserstein" aus der map_?_z.lst else if(lc == 0x0B) nodes[pos].obj = new noStaticObject(x, y, 500+lc); // Objekte aus der map_?_z.lst else if(lc >= 0x0C && lc <= 0x0F) nodes[pos].obj = new noEnvObject(x, y, 500+lc); // Objekte aus der map.lst else if(lc >= 0x10 && lc <= 0x14) nodes[pos].obj = new noEnvObject(x, y, 542+lc-0x10); // gestrandetes Schiff (mis0bobs, unvollständig) else if(lc == 0x15) nodes[pos].obj = new noStaticObject(x, y, (lc-0x15)*2, 0, 1); // das Tor aus der map_?_z.lst else if(lc == 0x16) nodes[pos].obj = new noStaticObject(x, y, 560, 0xFFFF, 2); // das geöffnete Tor aus map_?_z.lst else if(lc == 0x17) nodes[pos].obj = new noStaticObject(x, y, 561, 0xFFFF, 2); // Stalagmiten (mis1bobs) else if(lc >= 0x18 && lc <= 0x1E) nodes[pos].obj = new noStaticObject(x, y, (lc-0x18)*2, 1); // toter Baum (mis1bobs) else if(lc >= 0x1F && lc <= 0x20) nodes[pos].obj = new noStaticObject(x, y, 20+(lc-0x1F)*2, 1); // Gerippe (mis1bobs) else if(lc == 0x21) nodes[pos].obj = new noEnvObject(x, y, 30, 1); // Objekte aus der map.lst else if(lc >= 0x22 && lc <= 0x27) nodes[pos].obj = new noEnvObject(x, y, 550+lc-0x22); // Objekte aus der map.lst else if(lc >= 0x28 && lc <= 0x2B) nodes[pos].obj = new noEnvObject(x, y, 556+lc-0x28); // die "kaputten" Gebäuderuinen usw (mis2bobs) else if(lc >= 0x2C && lc <= 0x2D) nodes[pos].obj = new noStaticObject(x, y, (lc-0x2C)*2, 2); else if(lc == 0x2E) nodes[pos].obj = new noStaticObject(x, y, (lc-0x2C)*2, 2, 1); else if(lc == 0x2F) nodes[pos].obj = new noStaticObject(x, y, (lc-0x2C)*2, 2, 2); else if(lc == 0x30) nodes[pos].obj = new noEnvObject(x, y, (lc-0x2C)*2, 2); // der Wikinger (mis3bobs) else if(lc == 0x31) nodes[pos].obj = new noStaticObject(x, y, 0, 2); else { LOG.lprintf("Unbekanntes Naturzeug auf x=%d, y=%d: id=%d (0x%0X)\n", x, y, lc, lc); nodes[pos].obj = NULL; } } break; // Granit Typ 1 case 0xCC: { if(lc >= 0x01 && lc <= 0x06) nodes[pos].obj = new noGranite(GT_1,lc-1); else { LOG.lprintf("Unbekannter Granit1 auf x=%d, y=%d: id=%d (0x%0X)\n", x, y, lc, lc); nodes[pos].obj = NULL; } } break; // Granit Typ 2 case 0xCD: { if(lc >= 0x01 && lc <= 0x06) nodes[pos].obj = new noGranite(GT_2,lc-1); else { LOG.lprintf("Unbekannter Granit2 auf x=%d, y=%d: id=%d (0x%0X)\n", x, y, lc, lc); nodes[pos].obj = NULL; } } break; // Nichts case 0: { nodes[pos].obj = NULL; } break; default: { /*LOG.lprintf("Unbekanntes Objekt %d (0x%0X) auf x=%d, y=%d: id=%d (0x%0X)\n", map->map_type[y*width+x], map->map_type[y*width+x], x, y, lc, lc); */ nodes[pos].obj = NULL; } break; } } } // BQ mit nichts erstmal inititalisieren (HQ-Setzen berechnet diese neu und braucht sie) for(unsigned y = 0;y<height;++y) { for(unsigned x = 0;x<width;++x) { SetBQ(x,y,BQ_NOTHING); } } //random locations? -> randomize them :) if (GameClient::inst().GetGGS().random_location) { ptrdiff_t (*p_myrandom)(ptrdiff_t) = myRandom; std::random_shuffle(headquarter_positions.begin(), headquarter_positions.end(), p_myrandom); for (unsigned i = 0; i < GAMECLIENT.GetPlayerCount(); ++i) { GetPlayer(i)->hqx = headquarter_positions.at(i).x; GetPlayer(i)->hqy = headquarter_positions.at(i).y; } } // HQ setzen for(unsigned i = 0;i<GAMECLIENT.GetPlayerCount();++i) { // Existiert überhaupt ein HQ? if(GetPlayer(i)->hqx != 0xFFFF) { if(GetPlayer(i)->ps == PS_OCCUPIED || GetPlayer(i)->ps == PS_KI) { nobHQ * hq = new nobHQ(GetPlayer(i)->hqx,GetPlayer(i)->hqy,i,GetPlayer(i)->nation); SetNO(hq,GetPlayer(i)->hqx,GetPlayer(i)->hqy); GetPlayer(i)->AddWarehouse(reinterpret_cast<nobBaseWarehouse*>(hq)); } /*else GetNode(GetPlayer(i)->hqx,GetPlayer(i)->hqy).obj = 0;*/ } } // Tiere auslesen for(unsigned y = 0;y<height;++y) { for(unsigned x = 0;x<width;++x) { // Tiere setzen Species species; switch(map->GetMapDataAt(MAP_ANIMALS, x, y)) { // TODO: Welche ID ist Polarbär? case 1: species = Species(SPEC_RABBITWHITE+RANDOM.Rand(__FILE__,__LINE__,0,2)); break; // zufällige Hasenart nehmen case 2: species = SPEC_FOX; break; case 3: species = SPEC_STAG; break; case 4: species = SPEC_DEER; break; case 5: species = SPEC_DUCK; break; case 6: species = SPEC_SHEEP; break; default: species = SPEC_NOTHING; break; } if(species != SPEC_NOTHING) { noAnimal * animal = new noAnimal(species,x,y); AddFigure(animal,x,y); // Loslaufen animal->StartLiving(); } /// 4 Fische setzen if(map->GetMapDataAt(MAP_RESOURCES,y*width+x) > 0x80 && map->GetMapDataAt(MAP_RESOURCES,y*width+x) < 0x90) GetNode(x,y).resources = 0x84; } } /// Weltmeere vermessen for(unsigned y = 0;y<height;++y) { for(unsigned x = 0;x<width;++x) { // Noch kein Meer an diesem Punkt? if(!GetNode(x,y).sea_id) { // Aber trotzdem Teil eines noch nicht vermessenen Meeres? if(IsSeaPoint(x,y)) { unsigned sea_size = MeasureSea(x,y,seas.size()); seas.push_back(Sea(sea_size)); } } } } /// Die Meere herausfinden, an die die Hafenpunkte grenzen for(unsigned i = 0;i<harbor_pos.size();++i) { for(unsigned z = 0;z<6;++z) harbor_pos[i].cps[z].sea_id = IsCoastalPoint(GetXA(harbor_pos[i].x,harbor_pos[i].y,z), GetYA(harbor_pos[i].x,harbor_pos[i].y,z)); } // Nachbarn der einzelnen Hafenplätze ermitteln CalcHarborPosNeighbors(); /// Schatten und BQ berechnen for(unsigned y = 0;y<height;++y) { for(unsigned x = 0;x<width;++x) { RecalcShadow(x,y); SetBQ(x,y,GAMECLIENT.GetPlayerID()); } } /// Bei FoW und aufgedeckt müssen auch die ersten FoW-Objekte erstellt werden if(GameClient::inst().GetGGS().exploration == GlobalGameSettings::EXP_FOGOFWARE_EXPLORED) { for(unsigned y = 0;y<height;++y) { for(unsigned x = 0;x<width;++x) { // Alle Spieler durchgehen for(unsigned i = 0;i<GameClient::inst().GetPlayerCount();++i) { // An der Stelle FOW für diesen Spieler? if(GetNode(x,y).fow[i].visibility == VIS_FOW) SaveFOWNode(x,y,i); } } } } }
/// Erhält die Waren von einem Schiff und nimmt diese in den Warenbestand auf void nobHarborBuilding::ReceiveGoodsFromShip(const std::list<noFigure*> figures, const std::list<Ware*> wares) { // Menschen zur Ausgehliste hinzufügen for(std::list<noFigure*>::const_iterator it = figures.begin();it!=figures.end();++it) { if((*it)->GetJobType() == JOB_BOATCARRIER) { ++goods.people[JOB_HELPER]; ++goods.goods[GD_BOAT]; } else ++goods.people[(*it)->GetJobType()]; // Wenn es kein Ziel mehr hat, sprich keinen weiteren Weg, kann es direkt hier gelagert // werden if ((*it)->HasNoGoal() || ((*it)->GetGoal() == this)) { AddFigure(*it, false); } else { Point<MapCoord> next_harbor = (*it)->ExamineRouteBeforeShipping(); unsigned char next_dir = (*it)->GetDir(); if (next_dir == 4) { AddLeavingFigure(*it); (*it)->ShipJourneyEnded(); } else if (next_dir == SHIP_DIR) { AddFigureForShip(*it, next_harbor); } else { AddFigure(*it, false); } } } // Waren zur Warteliste hinzufügen for(std::list<Ware*>::const_iterator it = wares.begin();it!=wares.end();++it) { // Optische Warenwerte entsprechend erhöhen ++goods.goods[ConvertShields((*it)->type)]; if((*it)->ShipJorneyEnded(this)) { // Ware will die weitere Reise antreten, also muss sie zur Liste der rausgetragenen Waren // hinzugefügt werden waiting_wares.push_back(*it); } else { // Ansonsten fügen wir die Ware einfach zu unserem Inventar dazu RemoveDependentWare(*it); ++real_goods.goods[ConvertShields((*it)->type)]; players->getElement(player)->RemoveWare(*it); delete *it; } } // Ggf. neues Rausgeh-Event anmelden, was notwendig ist, wenn z.B. nur Waren zur Liste hinzugefügt wurden AddLeavingEvent(); }