Пример #1
0
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();
    }
}
Пример #2
0
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();
    }
}
Пример #3
0
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();
	}
}
Пример #4
0
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();
    }
}
Пример #5
0
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;
    }
}
Пример #6
0
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;
	}
}
Пример #7
0
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;
    }
}
Пример #8
0
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;
    }
}
Пример #9
0
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;
    }
}