void nofBuildingWorker::TryToWork() { // Wurde die Produktion eingestellt? if(workplace->IsProductionDisabled()) { state = STATE_WAITINGFORWARES_OR_PRODUCTIONSTOPPED; // Nun arbeite ich nich mehr StartNotWorking(); } // Falls man auf Waren wartet, kann man dann anfangen zu arbeiten else if(AreWaresAvailable()) { if(ReadyForWork()) { state = STATE_WAITING1; current_ev = em->AddEvent(this, (GetGOT() == GOT_NOF_CATAPULTMAN) ? CATAPULT_WAIT1_LENGTH : JOB_CONSTS[job].wait1_length, 1); StopNotWorking(); }else { state = STATE_WAITINGFORWARES_OR_PRODUCTIONSTOPPED; } } else { state = STATE_WAITINGFORWARES_OR_PRODUCTIONSTOPPED; // Nun arbeite ich nich mehr StartNotWorking(); } }
void nofBuildingWorker::TryToWork() { // Wurde die Produktion eingestellt? if(workplace->IsProductionDisabled()) { state = STATE_WAITINGFORWARES_OR_PRODUCTIONSTOPPED; // Nun arbeite ich nich mehr StartNotWorking(); } // Falls man auf Waren wartet, kann man dann anfangen zu arbeiten // (bei Bergwerken müssen zusätzlich noch Rohstoffvorkommen vorhanden sein!) // (bei Brunnen muss ebenfalls auf Wasser geprüft werden!) // Spähturm-Erkunder arbeiten nie! // Charburner doesn't need wares for harvesting! // -> Wares are considered when calling GetPointQuality! else if( (workplace->WaresAvailable() || job == JOB_CHARBURNER) && (job != JOB_MINER || GetResources(workplace->GetBuildingType() - BLD_GRANITEMINE)) && (job != JOB_HELPER || GetResources(4)) && job != JOB_SCOUT) { state = STATE_WAITING1; current_ev = em->AddEvent(this, (GetGOT() == GOT_NOF_CATAPULTMAN) ? CATAPULT_WAIT1_LENGTH : JOB_CONSTS[job].wait1_length, 1); StopNotWorking(); } else { state = STATE_WAITINGFORWARES_OR_PRODUCTIONSTOPPED; // Nun arbeite ich nich mehr StartNotWorking(); } }
void nofBuildingWorker::Walked() { switch(state) { case STATE_ENTERBUILDING: { // Hab ich noch ne Ware in der Hand? if(ware != GD_NOTHING) { // dann war draußen kein Platz --> ist jetzt evtl Platz? state = STATE_WAITFORWARESPACE; if(workplace->GetFlag()->GetWareCount() < 8) FreePlaceAtFlag(); // Ab jetzt warten, d.h. nicht mehr arbeiten --> schlecht für die Produktivität StartNotWorking(); } else { // Anfangen zu Arbeiten TryToWork(); } } break; case STATE_CARRYOUTWARE: { // Alles weitere übernimmt nofBuildingWorker WorkingReady(); } break; default: WalkedDerived(); } }
void nofBuildingWorker::ProductionStopped() { // Wenn ich gerade warte und schon ein Arbeitsevent angemeldet habe, muss das wieder abgemeldet werden if(state == STATE_WAITING1) { em->RemoveEvent(current_ev); current_ev = 0; state = STATE_WAITINGFORWARES_OR_PRODUCTIONSTOPPED; StartNotWorking(); } }
void nofFarmhand::HandleDerivedEvent(const unsigned int id) { switch(state) { case STATE_WORK: { // fertig mit Arbeiten --> dann müssen die "Folgen des Arbeitens" ausgeführt werden WorkFinished(); // Objekt wieder freigeben gwg->GetNode(pos).reserved = false; // Wieder nach Hause gehen StartWalkingHome(); // Evtl. Sounds löschen if(was_sounding) { SOUNDMANAGER.WorkingFinished(this); was_sounding = false; } } break; case STATE_WAITING1: { // Fertig mit warten --> anfangen zu arbeiten // Die Arbeitsradien der Berufe wie in JobConst.h (ab JOB_WOODCUTTER!) const unsigned char RADIUS[7] = { 6, 7, 6, 0, 8, 2, 2 }; // Additional radius delta r which is used when a point in radius r was found // I.e. looks till radius r + delta r const unsigned ADD_RADIUS_WHEN_FOUND[7] = { 1, 1, 1, 1, 0, 1, 1}; // Anzahl der Radien, wo wir gültige Punkte gefunden haben unsigned radius_count = 0; // Available points: 1st class and 2st class std::vector< MapPoint > available_points[3]; unsigned max_radius = (job_ == JOB_CHARBURNER) ? 3 : RADIUS[job_ - JOB_WOODCUTTER]; unsigned add_radius_when_found = (job_ == JOB_CHARBURNER) ? 1 : ADD_RADIUS_WHEN_FOUND[job_ - JOB_WOODCUTTER]; bool points_found = false; bool wait = false; for(MapCoord tx = gwg->GetXA(pos, 0), r = 1; r <= max_radius; tx = gwg->GetXA(tx, pos.y, 0), ++r) { // Wurde ein Punkt in diesem Radius gefunden? bool found_in_radius = false; MapPoint t2(tx, pos.y); for(unsigned i = 2; i < 8; ++i) { for(MapCoord r2 = 0; r2 < r; t2 = gwg->GetNeighbour(t2, i % 6), ++r2) { if(IsPointAvailable(t2)) { if (!gwg->GetNode(t2).reserved) { available_points[GetPointQuality(t2) - PQ_CLASS1].push_back(MapPoint(t2)); found_in_radius = true; points_found = true; } else if (job_ == JOB_STONEMASON) { // just wait a little bit longer wait = true; } } } } // Nur die zwei ADD_RADIUS_WHEN_FOUND Radien erst einmal nehmen if(found_in_radius) { if( radius_count++ == add_radius_when_found) break; } } // Are there any objects at all? if(points_found) { // Prefer 1st class objects and use only 2nd class objects if there are no more other objects anymore MapPoint p(0, 0); for(unsigned i = 0; i < 3; ++i) { if(!available_points[i].empty()) { p = available_points[i][RANDOM.Rand(__FILE__, __LINE__, GetObjId(), available_points[i].size())]; break; } } // Als neues Ziel nehmen dest = p; state = STATE_WALKTOWORKPOINT; // Wir arbeiten jetzt workplace->is_working = true; // Punkt für uns reservieren gwg->GetNode(dest).reserved = true;; // Anfangen zu laufen (erstmal aus dem Haus raus!) StartWalking(4); StopNotWorking(); WalkingStarted(); } else if (wait) { // We have to wait, since we do not know whether there are any unreachable or reserved points where there's more to get current_ev = em->AddEvent(this, JOB_CONSTS[job_].wait1_length, 1); StartNotWorking(); } else { if(GAMECLIENT.GetPlayerID() == this->player) { if (!OutOfRessourcesMsgSent) { switch(job_) { case JOB_STONEMASON: GAMECLIENT.SendPostMessage( new ImagePostMsgWithLocation(_("No more stones in range"), PMC_GENERAL, pos, workplace->GetBuildingType(), workplace->GetNation())); OutOfRessourcesMsgSent = true; // Produktivitätsanzeige auf 0 setzen workplace->SetProductivityToZero(); break; case JOB_FISHER: GAMECLIENT.SendPostMessage( new ImagePostMsgWithLocation(_("No more fishes in range"), PMC_GENERAL, pos, workplace->GetBuildingType(), workplace->GetNation())); OutOfRessourcesMsgSent = true; // Produktivitätsanzeige auf 0 setzen workplace->SetProductivityToZero(); break; default: break; } } } // KI-Event erzeugen switch(workplace->GetBuildingType()) { case BLD_WOODCUTTER: case BLD_QUARRY: case BLD_FISHERY: GAMECLIENT.SendAIEvent(new AIEvent::Building(AIEvent::NoMoreResourcesReachable, workplace->GetPos(), workplace->GetBuildingType()), player); break; default: break; } // Weiter warten, vielleicht gibts ja später wieder mal was current_ev = em->AddEvent(this, JOB_CONSTS[job_].wait1_length, 1); StartNotWorking(); } } break; default: break; } }
void nofHunter::HandleDerivedEvent(const unsigned int id) { switch(state) { default: break; case STATE_WAITING1: { // Fertig mit warten --> anfangen zu arbeiten // in einem Quadrat um die Hütte (Kreis unnötig, da ja die Tiere sich sowieso bewegen) Tiere suchen // Unter- und Obergrenzen für das Quadrat bzw. Rechteck (nicht über Kartenränder hinauslesen) unsigned short fx,fy,lx,ly; const unsigned short SQUARE_SIZE = 19; if(x > SQUARE_SIZE) fx = x-SQUARE_SIZE; else fx = 0; if(y > SQUARE_SIZE) fy = y-SQUARE_SIZE; else fy = 0; if(x+SQUARE_SIZE < gwg->GetWidth()) lx = x+SQUARE_SIZE; else lx = gwg->GetWidth()-1; if(y+SQUARE_SIZE < gwg->GetHeight()) ly = y+SQUARE_SIZE; else ly = gwg->GetHeight()-1; // Liste mit den gefundenen Tieren list<noAnimal*> available_animals; // Durchgehen und nach Tieren suchen for(unsigned short py = fy;py<=ly;++py) { for(unsigned short px = fx;px<=lx;++px) { // Gibts hier was bewegliches? if(gwg->GetFigures(px,py).size()) { // Dann nach Tieren suchen for(list<noBase*>::iterator it = gwg->GetFigures(px,py).begin();it.valid();++it) { if((*it)->GetType() == NOP_ANIMAL) { // Ist das Tier überhaupt zum Jagen geeignet? if(!static_cast<noAnimal*>(*it)->CanHunted()) continue; // Und komme ich hin? if(gwg->FindHumanPath(x,y,static_cast<noAnimal*>(*it)->GetX(), static_cast<noAnimal*>(*it)->GetY(),MAX_HUNTING_DISTANCE) != 0xFF) // Dann nehmen wir es available_animals.push_back(static_cast<noAnimal*>(*it)); } } } } } // Gibt es überhaupt ein Tier, das ich jagen kann? if(available_animals.size()) { // Ein Tier zufällig heraussuchen animal = *available_animals[RANDOM.Rand(__FILE__,__LINE__,obj_id,available_animals.size())]; // Wir jagen es jetzt state = STATE_HUNTER_CHASING; // Wir arbeiten jetzt workplace->is_working = true; // Tier Bescheid sagen animal->BeginHunting(this); // Anfangen zu laufen (erstmal aus dem Haus raus!) StartWalking(4); StopNotWorking(); } else { // Weiter warten, vielleicht gibts ja später wieder mal was current_ev = em->AddEvent(this,JOB_CONSTS[job].wait1_length,1); //tell the ai that there is nothing left to hunt! GAMECLIENT.SendAIEvent(new AIEvent::Building(AIEvent::NoMoreResourcesReachable, workplace->GetX(), workplace->GetY(),workplace->GetBuildingType()), player); StartNotWorking(); } was_sounding = false; } break; case STATE_HUNTER_SHOOTING: { HandleStateShooting(); } break; case STATE_HUNTER_EVISCERATING: { HandleStateEviscerating(); // Evtl. Sounds löschen if(was_sounding) { SoundManager::inst().WorkingFinished(this); was_sounding = false; } } break; } }
void nofCatapultMan::HandleDerivedEvent(const unsigned int /*id*/) { switch(state) { default: break; case STATE_WAITING1: { // Fertig mit warten --> anfangen zu arbeiten // Liste von potentiellen Zielen std::vector<PossibleTarget> possibleTargets; sortedMilitaryBlds buildings = gwg->LookForMilitaryBuildings(pos, 3); for(sortedMilitaryBlds::iterator it = buildings.begin(); it != buildings.end(); ++it) { // Auch ein richtiges Militärgebäude (kein HQ usw.), if((*it)->GetGOT() == GOT_NOB_MILITARY && gwg->GetPlayer(player).IsAttackable((*it)->GetPlayer())) { // Was nicht im Nebel liegt und auch schon besetzt wurde (nicht neu gebaut)? if(gwg->GetNode((*it)->GetPos()).fow[player].visibility == VIS_VISIBLE && !static_cast<nobMilitary*>((*it))->IsNewBuilt()) { // Entfernung ausrechnen unsigned distance = gwg->CalcDistance(pos, (*it)->GetPos()); // Entfernung nicht zu hoch? if(distance < 14) { // Mit in die Liste aufnehmen possibleTargets.push_back(PossibleTarget((*it)->GetPos(), distance)); } } } } // Gibts evtl keine Ziele? if(possibleTargets.empty()) { // Weiter warten, vielleicht gibts ja später wieder mal was current_ev = GetEvMgr().AddEvent(this, CATAPULT_WAIT1_LENGTH, 1); StartNotWorking(); return; } // Waren verbrauchen workplace->ConsumeWares(); // Eins zufällig auswählen target = possibleTargets[RANDOM.Rand(__FILE__, __LINE__, GetObjId(), possibleTargets.size())]; // Get distance and direction int distX; bool targetIsRight; // We should face right (to higher x) if(target.pos.x > pos.x) { distX = target.pos.x - pos.x; targetIsRight = true; }else { distX = pos.x - target.pos.x; targetIsRight = false; } // Distance over map border is closer (max distance is size/2 due to wrap around) if(distX > gwg->GetWidth() / 2) { distX -= gwg->GetWidth() / 2; targetIsRight = !targetIsRight; // Reverse direction } // Same for Y int distY; bool targetIsDown; // We should face down (to higher y) if(target.pos.y > pos.y) { distY = target.pos.y - pos.y; targetIsDown = true; }else { distY = pos.y - target.pos.y; targetIsDown = false; } // Distance over map border is closer (max distance is size/2 due to wrap around) if(distY > gwg->GetHeight() / 2) { distY -= gwg->GetHeight() / 2; targetIsDown = !targetIsDown; // Reverse direction } // Richtung, in die sich der Katapult drehen soll, bestimmen unsigned char shooting_dir; // Y-Abstand nur unwesentlich klein --> Richtung 0 und 3 (direkt gegenüber) nehmen if(distY <= distX / 5) shooting_dir = (targetIsRight) ? 3 : 0; else { // Ansonsten noch y mit berücksichtigen und je einen der 4 Quadranten nehmen if(targetIsDown) shooting_dir = (targetIsRight) ? 4 : 5; else shooting_dir = (targetIsRight) ? 2 : 1; } // "Drehschritte" ausrechnen, da von Richtung 4 aus gedreht wird wheel_steps = int(shooting_dir) - 4; if(wheel_steps < -3) wheel_steps = 6 + wheel_steps; current_ev = GetEvMgr().AddEvent(this, 15 * (std::abs(wheel_steps) + 1), 1); state = STATE_CATAPULT_TARGETBUILDING; // wir arbeiten workplace->is_working = true; } break; case STATE_CATAPULT_TARGETBUILDING: { // Stein in Bewegung setzen // Soll das Gebäude getroffen werden (70%) bool hit = (RANDOM.Rand(__FILE__, __LINE__, GetObjId(), 99) < 70); // Radius fürs Treffen und Nicht-Treffen, (in Pixeln), nur visuell const int RADIUS_HIT = 15; // nicht nach unten hin! // Zielkoordinaten als (Map-Koordinaten!) MapPoint destMap; if(hit) { // Soll getroffen werden --> Aufschlagskoordinaten gleich dem eigentlichem Ziel destMap = target.pos; } else { // Ansonsten zufälligen Punkt rundrum heraussuchen unsigned d = RANDOM.Rand(__FILE__, __LINE__, GetObjId(), 6); destMap = gwg->GetNeighbour(target.pos, d); } unsigned char shooting_dir = (7 + wheel_steps) % 6; // Größe der Welt in Pixeln bestimmen int worldWidth = gwg->GetWidth() * TR_W; int worldHeight = gwg->GetHeight() * TR_H; // Startpunkt bestimmen Point<int> start = gwg->GetNodePos(pos) + STONE_STARTS[shooting_dir]; // (Visuellen) Aufschlagpunkt bestimmen Point<int> dest = gwg->GetNodePos(destMap); // Kartenränder beachten // Wenn Abstand kleiner is, den kürzeren Abstand über den Kartenrand wählen if(std::abs(start.x + worldWidth - dest.x) < std::abs(start.x - dest.x)) start.x += worldWidth; else if(std::abs(start.x - worldWidth - dest.x) < std::abs(start.x - dest.x)) start.x -= worldWidth; if(std::abs(start.y + worldHeight - dest.y) < std::abs(start.y - dest.y)) start.y += worldHeight; else if(std::abs(start.y - worldHeight - dest.y) < std::abs(start.y - dest.y)) start.y -= worldHeight; // Bei getroffenen den Aufschlagspunkt am Gebäude ein bisschen variieren if(hit) { dest.x += (RANDOM.Rand(__FILE__, __LINE__, GetObjId(), RADIUS_HIT * 2) - RADIUS_HIT); // hier nicht nach unten gehen, da die Tür (also Nullpunkt // ja schon ziemlich weit unten ist! dest.y -= RANDOM.Rand(__FILE__, __LINE__, GetObjId(), RADIUS_HIT); } // Stein erzeugen gwg->AddCatapultStone(new CatapultStone(target.pos, destMap, start, dest, 80)); // Katapult wieder in Ausgangslage zurückdrehen current_ev = GetEvMgr().AddEvent(this, 15 * (std::abs(wheel_steps) + 3), 1); state = STATE_CATAPULT_BACKOFF; } break; case STATE_CATAPULT_BACKOFF: { current_ev = 0; // wir arbeiten nicht mehr workplace->is_working = false; // Wieder versuchen, zu arbeiten TryToWork(); } break; } }
void nofCatapultMan::HandleDerivedEvent(const unsigned int id) { switch(state) { default: break; case STATE_WAITING1: { // Fertig mit warten --> anfangen zu arbeiten // Liste von potentiellen Zielen std::vector<PossibleTarget> pts; sortedMilitaryBlds buildings = gwg->LookForMilitaryBuildings(pos, 3); for(sortedMilitaryBlds::iterator it = buildings.begin(); it != buildings.end(); ++it) { // Auch ein richtiges Militärgebäude (kein HQ usw.), if((*it)->GetGOT() == GOT_NOB_MILITARY && GAMECLIENT.GetPlayer(player).IsPlayerAttackable((*it)->GetPlayer())) { // Was nicht im Nebel liegt und auch schon besetzt wurde (nicht neu gebaut)? if(gwg->GetNode((*it)->GetPos()).fow[player].visibility == VIS_VISIBLE && !static_cast<nobMilitary*>((*it))->IsNewBuilt()) { // Entfernung ausrechnen unsigned distance = gwg->CalcDistance(pos, (*it)->GetPos()); // Entfernung nicht zu hoch? if(distance < 14) { // Mit in die Liste aufnehmen pts.push_back(PossibleTarget((*it)->GetPos(), distance)); } } } } // Gibts evtl keine Ziele? if(pts.empty()) { // Weiter warten, vielleicht gibts ja später wieder mal was current_ev = em->AddEvent(this, CATAPULT_WAIT1_LENGTH, 1); StartNotWorking(); return; } // Waren verbrauchen workplace->ConsumeWares(); // Eins zufällig auswählen target = pts[RANDOM.Rand(__FILE__, __LINE__, GetObjId(), pts.size())]; // Richtung, in die sich der Katapult drehen soll, bestimmen unsigned char shooting_dir; // Normale X-Distanz (ohne Beachtung der Kartenränderüberquerung) unsigned x_dist = std::abs(int(target.pos.x) - int(pos.x)); // Distanzen jeweils bei Überquerung des linken und rechten Randes unsigned x_dist1 = std::abs(int(target.pos.x) - int(pos.x) + gwg->GetWidth()); unsigned x_dist2 = std::abs(int(target.pos.x) - int(pos.x) - gwg->GetWidth()); // Minimale, d.h. im Endeffekt reale Distanz unsigned min_dist_x = std::min(std::min(x_dist, x_dist1), x_dist2); // Normale Y-Distanz (ohne Beachtung der Kartenränderüberquerung) unsigned y_dist = std::abs(int(target.pos.y) - int(pos.y)); // Distanzen jeweils bei Überquerung des linken und rechten Randes unsigned y_dist1 = std::abs(int(target.pos.y) - int(pos.y) + gwg->GetHeight()); unsigned y_dist2 = std::abs(int(target.pos.y) - int(pos.y) - gwg->GetHeight()); // Minimale, d.h. im Endeffekt reale Distanz unsigned min_dist_y = std::min(std::min(y_dist, y_dist1), y_dist2); bool side_x = (pos.x < target.pos.x); if(x_dist > x_dist1 || x_dist > x_dist2) side_x = !side_x; // Wenn er über Kartengrenze schießt, Richtung umkehren bool side_y = (pos.y < target.pos.y); if(y_dist > y_dist1 || y_dist > y_dist2) side_y = !side_y; // Y-Abstand nur unwesentlich klein --> Richtung 0 und 3 (direkt gegenüber) nehmen if(min_dist_y <= min_dist_x / 5) shooting_dir = (side_x) ? 3 : 0; else { // Ansonsten noch y mit berücksichtigen und je einen der 4 Quadranten nehmen if(side_y) shooting_dir = (side_x) ? 4 : 5; else shooting_dir = (side_x) ? 2 : 1; } // "Drehschritte" ausrechnen, da von Richtung 4 aus gedreht wird wheel_steps = int(shooting_dir) - 4; if(wheel_steps < -3) wheel_steps = 6 + wheel_steps; current_ev = em->AddEvent(this, 15 * (std::abs(wheel_steps) + 1), 1); state = STATE_CATAPULT_TARGETBUILDING; // wir arbeiten workplace->is_working = true; } break; case STATE_CATAPULT_TARGETBUILDING: { // Stein in Bewegung setzen // Soll das Gebäude getroffen werden (70%) bool hit = (RANDOM.Rand(__FILE__, __LINE__, GetObjId(), 99) < 70); // Radius fürs Treffen und Nicht-Treffen, (in Pixeln), nur visuell const int RADIUS_HIT = 15; // nicht nach unten hin! // Zielkoordinaten als (Map-Koordinaten!) MapPoint destMap; if(hit) { // Soll getroffen werden --> Aufschlagskoordinaten gleich dem eigentlichem Ziel destMap = target.pos; } else { // Ansonsten zufälligen Punkt rundrum heraussuchen unsigned d = RANDOM.Rand(__FILE__, __LINE__, GetObjId(), 6); destMap = gwg->GetNeighbour(target.pos, d); } unsigned char shooting_dir = (7 + wheel_steps) % 6; // Größe der Welt in Pixeln bestimmen int world_width = gwg->GetWidth() * TR_W; int world_height = gwg->GetHeight() * TR_H; // Startpunkt bestimmen int start_x = int(gwg->GetTerrainX(pos)) + STONE_STARTS[(7 + wheel_steps) % 6 * 2]; int start_y = int(gwg->GetTerrainY(pos)) + STONE_STARTS[shooting_dir * 2 + 1]; // (Visuellen) Aufschlagpunkt bestimmen int dest_x = int(gwg->GetTerrainX(destMap)); int dest_y = int(gwg->GetTerrainY(destMap)); // Kartenränder beachten // Wenn Abstand kleiner is, den kürzeren Abstand über den Kartenrand wählen if(std::abs(start_x + world_width - dest_x) < std::abs(start_x - dest_x)) start_x += world_width; else if(std::abs(start_x - world_width - dest_x) < std::abs(start_x - dest_x)) start_x -= world_width; if(std::abs(start_y + world_height - dest_y) < std::abs(start_y - dest_y)) start_y += world_height; else if(std::abs(start_y - world_height - dest_y) < std::abs(start_y - dest_y)) start_y -= world_height; // Bei getroffenen den Aufschlagspunkt am Gebäude ein bisschen variieren if(hit) { dest_x += (RANDOM.Rand(__FILE__, __LINE__, GetObjId(), RADIUS_HIT * 2) - RADIUS_HIT); // hier nicht nach unten gehen, da die Tür (also Nullpunkt // ja schon ziemlich weit unten ist! dest_y -= RANDOM.Rand(__FILE__, __LINE__, GetObjId(), RADIUS_HIT); } // Stein erzeugen gwg->AddCatapultStone(new CatapultStone(target.pos, destMap, start_x, start_y, dest_x, dest_y, 80)); // Katapult wieder in Ausgangslage zurückdrehen current_ev = em->AddEvent(this, 15 * (std::abs(wheel_steps) + 3), 1); state = STATE_CATAPULT_BACKOFF; } break; case STATE_CATAPULT_BACKOFF: { current_ev = 0; // wir arbeiten nicht mehr workplace->is_working = false; // Wieder versuchen, zu arbeiten TryToWork(); } break; } }
void nofShipWright::HandleDerivedEvent(const unsigned int id) { switch(state) { case STATE_WAITING1: { // Herausfinden, was der Schiffsbauer als nächstes bauen soll if(dynamic_cast<nobShipYard*>(workplace)->GetMode() == nobShipYard::BOATS) // in Handwerksmanier Boote herstellen nofWorkman::HandleStateWaiting1(); else { // Verfügbare Punkte, die geeignete Plätze darstellen würden std::vector<ShipPoint> available_points; // Wege müssen immer von der Flagge aus berechnet werden MapPoint flagPos = gwg->GetNeighbour(pos, 4); for(MapCoord tx = gwg->GetXA(pos, 0), r = 1; r <= SHIPWRIGHT_RADIUS; tx = gwg->GetXA(tx, pos.y, 0), ++r) { MapPoint t2(tx, pos.y); for(unsigned i = 2; i < 8; ++i) { for(MapCoord r2 = 0; r2 < r; t2 = gwg->GetNeighbour(t2, i % 6), ++r2) { // Besitze ich noch ein Schiff, was gebaut werden muss? noBase* obj = gwg->GetNode(t2).obj; if(!obj) continue; // Schiff? if(obj->GetGOT() == GOT_SHIPBUILDINGSITE) { // Platz noch nicht reserviert und gehört das Schiff auch mir? unsigned char first_dir = 0xFF; if(!gwg->GetNode(pos).reserved && static_cast<noShipBuildingSite*>(obj)->GetPlayer() == player && (first_dir = gwg->FindHumanPath(flagPos, t2, SHIPWRIGHT_WALKING_DISTANCE)) != 0xFF) { available_points.push_back(ShipPoint(t2, first_dir)); } } } } } // Kein Schiff im Bau gefunden? Dann Plätzchen für ein neues Schiff suchen if(available_points.empty()) { for(MapCoord tx = gwg->GetXA(pos, 0), r = 1; r <= SHIPWRIGHT_RADIUS; tx = gwg->GetXA(tx, pos.y, 0), ++r) { MapPoint t2(tx, pos.y); for(unsigned i = 2; i < 8; ++i) { for(MapCoord r2 = 0; r2 < r; t2 = gwg->GetNeighbour(t2, i % 6), ++r2) { // Dieser Punkt geeignet? if(IsPointGood(t2)) { // Weg dorthin finden unsigned char first_dir = gwg->FindHumanPath(flagPos, t2, SHIPWRIGHT_WALKING_DISTANCE); if(first_dir != 0xFF) { available_points.push_back(ShipPoint(t2, first_dir)); } } } } } } // Punkte gefunden? if(!available_points.empty()) { // Einen Punkt zufällig auswählen und dorthin laufen ShipPoint p = available_points[RANDOM.Rand(__FILE__, __LINE__, obj_id, available_points.size())]; dest = p.pos; StartWalkingToShip(p.first_dir); } else { // Nichts zu arbeiten gefunden StartNotWorking(); // Weiter warten, vielleicht gibts ja später wieder mal was current_ev = em->AddEvent(this, JOB_CONSTS[job].wait1_length, 1); } } } break; case STATE_WORK: { // Sind wir an unserem Arbeitsplatz (dem Gebäude), wenn wir die Arbeit beendet haben, bauen wir nur Boote, // ansonsten sind wir an unserem Schiff und bauen große Schiffe if(workplace->GetPos() == pos) // Boote bauen nofWorkman::HandleStateWork(); else { // fertig mit Arbeiten --> dann müssen die "Folgen des Arbeitens" ausgeführt werden WorkFinished(); // Objekt wieder freigeben gwg->GetNode(pos).reserved = false; // Wieder nach Hause gehen StartWalkingHome(); // Evtl. Sounds löschen if(was_sounding) { SOUNDMANAGER.WorkingFinished(this); was_sounding = false; } } } break; case STATE_WAITING2: { // Hier ist die Sache klar, dieser State kann nur bei Handwerkern vorkommen nofWorkman::HandleStateWaiting2(); } break; default: break; } }