diff options
author | Piotr Dziwinski <piotrdz@gmail.com> | 2012-06-26 22:37:26 +0200 |
---|---|---|
committer | Piotr Dziwinski <piotrdz@gmail.com> | 2012-06-26 22:37:26 +0200 |
commit | 6a059b437dca706a72233a57ba4c22011aba6dde (patch) | |
tree | 4d4bbef5e19bbde38ccd173c661377cdc9167ba7 /src/object/task/taskgoto.cpp | |
parent | b696edaed3e21839315d639590402e22f90fe195 (diff) | |
parent | bf06998ece3ba9d47b595e3761beba54b3793036 (diff) | |
download | colobot-6a059b437dca706a72233a57ba4c22011aba6dde.tar.gz colobot-6a059b437dca706a72233a57ba4c22011aba6dde.tar.bz2 colobot-6a059b437dca706a72233a57ba4c22011aba6dde.zip |
Merge branch 'dev-opengl' into dev
Diffstat (limited to 'src/object/task/taskgoto.cpp')
-rw-r--r-- | src/object/task/taskgoto.cpp | 4682 |
1 files changed, 2341 insertions, 2341 deletions
diff --git a/src/object/task/taskgoto.cpp b/src/object/task/taskgoto.cpp index 5ab248c..a3b1515 100644 --- a/src/object/task/taskgoto.cpp +++ b/src/object/task/taskgoto.cpp @@ -1,2341 +1,2341 @@ -// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// * GNU General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.
-
-// taskgoto.cpp
-
-
-#include <stdio.h>
-
-#include "object/task/taskgoto.h"
-
-#include "common/event.h"
-#include "common/iman.h"
-#include "old/terrain.h"
-#include "old/water.h"
-#include "math/geometry.h"
-#include "physics/physics.h"
-
-
-
-const float FLY_DIST_GROUND = 80.0f; // minimum distance to remain on the ground
-const float FLY_DEF_HEIGHT = 50.0f; // default flying height
-const float BM_DIM_STEP = 5.0f;
-
-
-
-
-// Object's constructor.
-
-CTaskGoto::CTaskGoto(CInstanceManager* iMan, CObject* object)
- : CTask(iMan, object)
-{
- m_bmArray = 0;
-}
-
-// Object's destructor.
-
-CTaskGoto::~CTaskGoto()
-{
- BitmapClose();
-}
-
-
-// Management of an event.
-
-bool CTaskGoto::EventProcess(const Event &event)
-{
- Math::Vector pos, goal;
- Math::Point rot, repulse;
- float a, g, dist, linSpeed, cirSpeed, h, hh, factor, dir;
- Error ret;
-
- if ( m_engine->RetPause() ) return true;
- if ( event.event != EVENT_FRAME ) return true;
-
- // Momentarily stationary object (ant on the back)?
- if ( m_object->RetFixed() )
- {
- m_physics->SetMotorSpeedX(0.0f); // stops the advance
- m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
- return true;
- }
-
- if ( m_error != ERR_OK ) return false;
-
- if ( m_bWorm )
- {
- WormFrame(event.rTime);
- }
-
- if ( m_phase == TGP_BEAMLEAK ) // leak?
- {
- m_leakTime += event.rTime;
-
- pos = m_object->RetPosition(0);
-
- rot.x = m_leakPos.x-pos.x;
- rot.y = m_leakPos.z-pos.z;
- dist = Math::Point(rot.x, rot.y).Length();
- rot.x /= dist;
- rot.y /= dist;
-
- a = m_object->RetAngleY(0);
- g = Math::RotateAngle(rot.x, -rot.y); // CW !
- a = Math::Direction(a, g)*1.0f;
- cirSpeed = a;
- if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
- if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
-
- a = Math::NormAngle(a);
- if ( a > Math::PI*0.5f && a < Math::PI*1.5f )
- {
- linSpeed = 1.0f; // obstacle behind -> advance
- cirSpeed = -cirSpeed;
- }
- else
- {
- linSpeed = -1.0f; // obstacle in front -> back
- }
-
- if ( m_bLeakRecede )
- {
- linSpeed = -1.0f;
- cirSpeed = 0.0f;
- }
-
- m_physics->SetMotorSpeedZ(cirSpeed); // turns left / right
- m_physics->SetMotorSpeedX(linSpeed); // advance
- return true;
- }
-
- if ( m_phase == TGP_BEAMSEARCH ) // search path?
- {
- if ( m_bmStep == 0 )
- {
- // Frees the area around the departure.
- BitmapClearCircle(m_object->RetPosition(0), BM_DIM_STEP*1.8f);
- }
-
- pos = m_object->RetPosition(0);
-
- if ( m_bmFretObject == 0 )
- {
- goal = m_goal;
- dist = 0.0f;
- }
- else
- {
- goal = m_goalObject;
- dist = TAKE_DIST+2.0f;
- if ( m_bmFretObject->RetType() == OBJECT_BASE ) dist = 12.0f;
- }
-
- ret = BeamSearch(pos, goal, dist);
- if ( ret == ERR_OK )
- {
-#if 0
- Math::Vector min, max;
- min = pos;
- max = m_goal;
- if ( min.x > max.x ) Math::Swap(min.x, max.x);
- if ( min.z > max.z ) Math::Swap(min.z, max.z);
- min.x -= 50.0f;
- min.z -= 50.0f;
- max.x += 50.0f;
- max.z += 50.0f;
- BitmapDebug(min, max, m_object->RetPosition(0), m_goal);
-#endif
- if ( m_physics->RetLand() ) m_phase = TGP_BEAMWCOLD;
- else m_phase = TGP_BEAMGOTO;
- m_bmIndex = 0;
- m_bmWatchDogPos = m_object->RetPosition(0);
- m_bmWatchDogTime = 0.0f;
- }
- if ( ret == ERR_GOTO_IMPOSSIBLE || ret == ERR_GOTO_ITER )
- {
-#if 0
- Math::Vector min, max;
- min = pos;
- max = m_goal;
- if ( min.x > max.x ) Math::Swap(min.x, max.x);
- if ( min.z > max.z ) Math::Swap(min.z, max.z);
- min.x -= 50.0f;
- min.z -= 50.0f;
- max.x += 50.0f;
- max.z += 50.0f;
- BitmapDebug(min, max, m_object->RetPosition(0), m_goal);
-#endif
- m_error = ret;
- return false;
- }
- return true;
- }
-
- if ( m_phase == TGP_BEAMWCOLD ) // expects cooled reactor?
- {
- return true;
- }
-
- if ( m_phase == TGP_BEAMUP ) // off?
- {
- m_physics->SetMotorSpeedY(1.0f); // up
- return true;
- }
-
- if ( m_phase == TGP_BEAMGOTO ) // goto dot list? (?)
- {
- if ( m_physics->RetCollision() ) // collision?
- {
- m_physics->SetCollision(false); // there's more
- }
-
- pos = m_object->RetPosition(0);
-
- if ( m_physics->RetType() == TYPE_FLYING && m_altitude == 0.0f )
- {
- if ( m_physics->RetLand() )
- {
- m_physics->SetMotorSpeedY(0.0f);
- }
- else
- {
- m_physics->SetMotorSpeedY(-1.0f);
- }
- }
-
- if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f )
- {
- goal = m_bmPoints[m_bmIndex];
- goal.y = pos.y;
- h = m_terrain->RetFloorHeight(goal, true, true);
- dist = Math::DistanceProjected(pos, goal);
- if ( dist != 0.0f ) // anticipates?
- {
- linSpeed = m_physics->RetLinMotionX(MO_REASPEED);
- linSpeed /= m_physics->RetLinMotionX(MO_ADVSPEED);
- goal.x = pos.x + (goal.x-pos.x)*linSpeed*20.0f/dist;
- goal.z = pos.z + (goal.z-pos.z)*linSpeed*20.0f/dist;
- }
- goal.y = pos.y;
- hh = m_terrain->RetFloorHeight(goal, true, true);
- h = Math::Min(h, hh);
- linSpeed = 0.0f;
- if ( h < m_altitude-1.0f )
- {
- linSpeed = 0.2f+((m_altitude-1.0f)-h)*0.1f; // up
- if ( linSpeed > 1.0f ) linSpeed = 1.0f;
- }
- if ( h > m_altitude+1.0f )
- {
- linSpeed = -0.2f; // down
- }
- m_physics->SetMotorSpeedY(linSpeed);
- }
-
- rot.x = m_bmPoints[m_bmIndex].x-pos.x;
- rot.y = m_bmPoints[m_bmIndex].z-pos.z;
- dist = Math::Point(rot.x, rot.y).Length();
- rot.x /= dist;
- rot.y /= dist;
-
- a = m_object->RetAngleY(0);
- g = Math::RotateAngle(rot.x, -rot.y); // CW !
- cirSpeed = Math::Direction(a, g)*2.0f;
- if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
- if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
- if ( dist < 4.0f ) cirSpeed *= dist/4.0f; // so close -> turns less
-
- if ( m_bmIndex == m_bmTotal ) // last point?
- {
- linSpeed = dist/(m_physics->RetLinStopLength()*1.5f);
- if ( linSpeed > 1.0f ) linSpeed = 1.0f;
- }
- else
- {
- linSpeed = 1.0f; // dark without stopping
- }
-
- linSpeed *= 1.0f-(1.0f-0.3f)*fabs(cirSpeed);
-
-//? if ( dist < 20.0f && fabs(cirSpeed) >= 0.5f )
- if ( fabs(cirSpeed) >= 0.2f )
- {
- linSpeed = 0.0f; // turns first, then advance
- }
-
- dist = Math::DistanceProjected(pos, m_bmWatchDogPos);
- if ( dist < 1.0f && linSpeed != 0.0f )
- {
- m_bmWatchDogTime += event.rTime;
- }
- else
- {
- m_bmWatchDogTime = 0.0f;
- m_bmWatchDogPos = pos;
- }
-
- if ( m_bmWatchDogTime >= 1.0f ) // immobile for a long time?
- {
- m_physics->SetMotorSpeedX(0.0f); // stops the advance
- m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
- BeamStart(); // we start all
- return true;
- }
-
- m_physics->SetMotorSpeedZ(cirSpeed); // turns left / right
- m_physics->SetMotorSpeedX(linSpeed); // advance
- return true;
- }
-
- if ( m_phase == TGP_BEAMDOWN ) // landed?
- {
- m_physics->SetMotorSpeedY(-0.5f); // tomb
- return true;
- }
-
- if ( m_phase == TGP_LAND ) // landed?
- {
- m_physics->SetMotorSpeedY(-0.5f); // tomb
- return true;
- }
-
- if ( m_goalMode == TGG_EXPRESS )
- {
- if ( m_crashMode == TGC_HALT )
- {
- if ( m_physics->RetCollision() ) // collision?
- {
- m_physics->SetCollision(false); // there's more
- m_error = ERR_STOP;
- return true;
- }
- }
-
- pos = m_object->RetPosition(0);
-
- if ( m_altitude > 0.0f )
- {
- h = m_terrain->RetFloorHeight(pos, true, true);
- linSpeed = 0.0f;
- if ( h < m_altitude )
- {
- linSpeed = 0.1f; // up
- }
- if ( h > m_altitude )
- {
- linSpeed = -0.2f; // down
- }
- m_physics->SetMotorSpeedY(linSpeed);
- }
-
- rot.x = m_goal.x-pos.x;
- rot.y = m_goal.z-pos.z;
- a = m_object->RetAngleY(0);
- g = Math::RotateAngle(rot.x, -rot.y); // CW !
- cirSpeed = Math::Direction(a, g)*1.0f;
- if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
- if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
-
- m_physics->SetMotorSpeedZ(cirSpeed); // turns left / right
- m_physics->SetMotorSpeedX(1.0f); // advance
- return true;
- }
-
- if ( m_phase != TGP_TURN &&
- m_physics->RetType() == TYPE_FLYING &&
- m_altitude > 0.0f )
- {
- pos = m_object->RetPosition(0);
- dist = Math::DistanceProjected(m_goal, pos);
- factor = (dist-20.0f)/20.0f;
- if ( factor < 0.0f ) factor = 0.0f;
- if ( factor > 1.0f ) factor = 1.0f;
-
- h = m_terrain->RetFloorHeight(m_object->RetPosition(0), true, true);
- linSpeed = 0.0f;
- if ( h < (m_altitude-0.5f)*factor && factor == 1.0f )
- {
- linSpeed = 0.1f; // up
- }
- if ( h > m_altitude*factor )
- {
- linSpeed = -0.2f; // down
- }
- ComputeFlyingRepulse(dir);
- linSpeed += dir*0.2f;
-
- m_physics->SetMotorSpeedY(linSpeed);
- }
-
- if ( m_phase == TGP_ADVANCE ) // going towards the goal?
- {
- if ( m_physics->RetCollision() ) // collision?
- {
- m_physics->SetCollision(false); // there's more
- m_time = 0.0f;
- m_phase = TGP_CRWAIT;
- return true;
- }
-
-#if 0
- pos = m_object->RetPosition(0);
- a = m_object->RetAngleY(0);
- g = Math::RotateAngle(m_goal.x-pos.x, pos.z-m_goal.z); // CW !
- cirSpeed = Math::Direction(a, g)*1.0f;
- if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
- if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
-
- dist = Math::DistanceProjected(m_goal, pos);
- linSpeed = dist/(m_physics->RetLinStopLength()*1.5f);
- if ( linSpeed > 1.0f ) linSpeed = 1.0f;
-
- if ( dist < 20.0f && fabs(cirSpeed) >= 0.5f )
- {
- linSpeed = 0.0f; // turns first, then advance
- }
-#else
- pos = m_object->RetPosition(0);
-
- rot.x = m_goal.x-pos.x;
- rot.y = m_goal.z-pos.z;
- dist = Math::Point(rot.x, rot.y).Length();
- rot.x /= dist;
- rot.y /= dist;
-
- ComputeRepulse(repulse);
- rot.x += repulse.x*2.0f;
- rot.y += repulse.y*2.0f;
-
- a = m_object->RetAngleY(0);
- g = Math::RotateAngle(rot.x, -rot.y); // CW !
- cirSpeed = Math::Direction(a, g)*1.0f;
-//? if ( m_physics->RetType() == TYPE_FLYING &&
-//? m_physics->RetLand() ) // flying on the ground?
-//? {
-//? cirSpeed *= 4.0f; // more fishing
-//? }
- if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
- if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
-
- dist = Math::DistanceProjected(m_goal, pos);
- linSpeed = dist/(m_physics->RetLinStopLength()*1.5f);
-//? if ( m_physics->RetType() == TYPE_FLYING &&
-//? m_physics->RetLand() ) // flying on the ground?
-//? {
-//? linSpeed *= 8.0f; // more fishing
-//? }
- if ( linSpeed > 1.0f ) linSpeed = 1.0f;
-
- linSpeed *= 1.0f-(1.0f-0.3f)*fabs(cirSpeed);
-
- if ( dist < 20.0f && fabs(cirSpeed) >= 0.5f )
- {
- linSpeed = 0.0f; // turns first, then advance
- }
-#endif
-
- m_physics->SetMotorSpeedZ(cirSpeed); // turns left / right
- m_physics->SetMotorSpeedX(linSpeed); // advance
- }
-
- if ( m_phase == TGP_TURN || // turns to the object?
- m_phase == TGP_CRTURN || // turns after collision?
- m_phase == TGP_CLTURN ) // turns after collision?
- {
- a = m_object->RetAngleY(0);
- g = m_angle;
- cirSpeed = Math::Direction(a, g)*1.0f;
- if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
- if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
-
- m_physics->SetMotorSpeedZ(cirSpeed); // turns left / right
- }
-
- if ( m_phase == TGP_CRWAIT || // waits after collision?
- m_phase == TGP_CLWAIT ) // waits after collision?
- {
- m_time += event.rTime;
- m_physics->SetMotorSpeedX(0.0f); // stops the advance
- m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
- }
-
- if ( m_phase == TGP_CRADVANCE ) // advance after collision?
- {
- if ( m_physics->RetCollision() ) // collision?
- {
- m_physics->SetCollision(false); // there's more
- m_time = 0.0f;
- m_phase = TGP_CLWAIT;
- return true;
- }
- m_physics->SetMotorSpeedX(0.5f); // advance mollo
- }
-
- if ( m_phase == TGP_CLADVANCE ) // advance after collision?
- {
- if ( m_physics->RetCollision() ) // collision?
- {
- m_physics->SetCollision(false); // there's more
- m_time = 0.0f;
- m_phase = TGP_CRWAIT;
- return true;
- }
- m_physics->SetMotorSpeedX(0.5f); // advance mollo
- }
-
- if ( m_phase == TGP_MOVE ) // final advance?
- {
- m_bmTimeLimit -= event.rTime;
- m_physics->SetMotorSpeedX(1.0f);
- }
-
- return true;
-}
-
-
-// Sought a target for the worm.
-
-CObject* CTaskGoto::WormSearch(Math::Vector &impact)
-{
- CObject* pObj;
- CObject* pBest = 0;
- Math::Vector iPos, oPos;
- ObjectType oType;
- float distance, min, radius;
- int i;
-
- iPos = m_object->RetPosition(0);
- min = 1000000.0f;
-
- for ( i=0 ; i<1000000 ; i++ )
- {
- pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
- if ( pObj == 0 ) break;
-
- oType = pObj->RetType();
- if ( oType != OBJECT_MOBILEfa &&
- oType != OBJECT_MOBILEta &&
- oType != OBJECT_MOBILEwa &&
- oType != OBJECT_MOBILEia &&
- oType != OBJECT_MOBILEfc &&
- oType != OBJECT_MOBILEtc &&
- oType != OBJECT_MOBILEwc &&
- oType != OBJECT_MOBILEic &&
- oType != OBJECT_MOBILEfi &&
- oType != OBJECT_MOBILEti &&
- oType != OBJECT_MOBILEwi &&
- oType != OBJECT_MOBILEii &&
- oType != OBJECT_MOBILEfs &&
- oType != OBJECT_MOBILEts &&
- oType != OBJECT_MOBILEws &&
- oType != OBJECT_MOBILEis &&
- oType != OBJECT_MOBILErt &&
- oType != OBJECT_MOBILErc &&
- oType != OBJECT_MOBILErr &&
- oType != OBJECT_MOBILErs &&
- oType != OBJECT_MOBILEsa &&
- oType != OBJECT_MOBILEtg &&
- oType != OBJECT_MOBILEft &&
- oType != OBJECT_MOBILEtt &&
- oType != OBJECT_MOBILEwt &&
- oType != OBJECT_MOBILEit &&
- oType != OBJECT_MOBILEdr &&
- oType != OBJECT_DERRICK &&
- oType != OBJECT_STATION &&
- oType != OBJECT_FACTORY &&
- oType != OBJECT_REPAIR &&
- oType != OBJECT_DESTROYER &&
- oType != OBJECT_CONVERT &&
- oType != OBJECT_TOWER &&
- oType != OBJECT_RESEARCH &&
- oType != OBJECT_RADAR &&
- oType != OBJECT_INFO &&
- oType != OBJECT_ENERGY &&
- oType != OBJECT_LABO &&
- oType != OBJECT_NUCLEAR &&
- oType != OBJECT_PARA &&
- oType != OBJECT_SAFE &&
- oType != OBJECT_HUSTON ) continue;
-
- if ( pObj->RetVirusMode() ) continue; // object infected?
-
- if ( !pObj->GetCrashSphere(0, oPos, radius) ) continue;
- distance = Math::DistanceProjected(oPos, iPos);
- if ( distance < min )
- {
- min = distance;
- pBest = pObj;
- }
- }
- if ( pBest == 0 ) return 0;
-
- impact = pBest->RetPosition(0);
- return pBest;
-}
-
-// Contaminate objects near the worm.
-
-void CTaskGoto::WormFrame(float rTime)
-{
- CObject* pObj;
- Math::Vector impact, pos;
- float dist;
-
- m_wormLastTime += rTime;
-
- if ( m_wormLastTime >= 0.5f )
- {
- m_wormLastTime = 0.0f;
-
- pObj = WormSearch(impact);
- if ( pObj != 0 )
- {
- pos = m_object->RetPosition(0);
- dist = Math::Distance(pos, impact);
- if ( dist <= 15.0f )
- {
- pObj->SetVirusMode(true); // bam, infected!
- }
- }
- }
-}
-
-
-
-// Assigns the goal was achieved.
-// "dist" is the distance that needs to go far to make a deposit or object.
-
-Error CTaskGoto::Start(Math::Vector goal, float altitude,
- TaskGotoGoal goalMode, TaskGotoCrash crashMode)
-{
- Math::Vector pos;
- CObject* target;
- ObjectType type;
- float dist;
- int x, y;
-
- type = m_object->RetType();
-
- if ( goalMode == TGG_DEFAULT )
- {
- goalMode = TGG_STOP;
- if ( type == OBJECT_MOTHER ||
- type == OBJECT_ANT ||
- type == OBJECT_SPIDER ||
- type == OBJECT_WORM )
- {
- goalMode = TGG_EXPRESS;
- }
- }
-
- if ( crashMode == TGC_DEFAULT )
- {
-//? crashMode = TGC_RIGHTLEFT;
- crashMode = TGC_BEAM;
- if ( type == OBJECT_MOTHER ||
- type == OBJECT_ANT ||
- type == OBJECT_SPIDER ||
- type == OBJECT_WORM ||
- type == OBJECT_BEE )
- {
- crashMode = TGC_HALT;
- }
- }
-
- m_altitude = altitude;
- m_goalMode = goalMode;
- m_crashMode = crashMode;
- m_goalObject = goal;
- m_goal = goal;
-
- m_bTake = false;
- m_phase = TGP_ADVANCE;
- m_error = ERR_OK;
- m_try = 0;
- m_bmFretObject = 0;
- m_bmFinalMove = 0.0f;
-
- pos = m_object->RetPosition(0);
- dist = Math::DistanceProjected(pos, m_goal);
- if ( dist < 10.0f && m_crashMode == TGC_BEAM )
- {
- m_crashMode = TGC_RIGHTLEFT;
- }
-
- m_bWorm = false;
- if ( type == OBJECT_WORM )
- {
- m_bWorm = true;
- m_wormLastTime = 0.0f;
- }
-
- m_bApprox = false;
- if ( type == OBJECT_HUMAN ||
- type == OBJECT_TECH ||
- type == OBJECT_MOTHER ||
- type == OBJECT_ANT ||
- type == OBJECT_SPIDER ||
- type == OBJECT_BEE ||
- type == OBJECT_WORM ||
- type == OBJECT_MOBILErt ||
- type == OBJECT_MOBILErc ||
- type == OBJECT_MOBILErr ||
- type == OBJECT_MOBILErs )
- {
- m_bApprox = true;
- }
-
- if ( !m_bApprox && m_crashMode != TGC_BEAM )
- {
- target = SearchTarget(goal, 1.0f);
- if ( target != 0 )
- {
- m_goal = target->RetPosition(0);
- dist = 0.0f;
- if ( !AdjustBuilding(m_goal, 1.0f, dist) )
- {
- dist = 0.0f;
- AdjustTarget(target, m_goal, dist);
- }
- m_bTake = true; // object was taken on arrival (final rotation)
- }
- }
-
- m_lastDistance = 1000.0f;
- m_physics->SetCollision(false);
-
- if ( m_crashMode == TGC_BEAM ) // with the algorithm of rays?
- {
- target = SearchTarget(goal, 1.0f);
- if ( target != 0 )
- {
- m_goal = target->RetPosition(0);
- dist = 4.0f;
- if ( AdjustBuilding(m_goal, 1.0f, dist) )
- {
- m_bmFinalMove = dist;
- }
- else
- {
- dist = 4.0f;
- if ( AdjustTarget(target, m_goal, dist) )
- {
- m_bmFretObject = target; // cargo on the ground
- }
- else
- {
- m_bmFinalMove = dist;
- }
- }
- m_bTake = true; // object was taken on arrival (final rotation)
- }
-
- if ( m_physics->RetType() == TYPE_FLYING && m_altitude == 0.0f )
- {
- pos = m_object->RetPosition(0);
- dist = Math::DistanceProjected(pos, m_goal);
- if ( dist > FLY_DIST_GROUND ) // over 20 meters?
- {
- m_altitude = FLY_DEF_HEIGHT; // default altitude
- }
- }
-
- BeamStart();
-
- if ( m_bmFretObject == 0 )
- {
- x = (int)((m_goal.x+1600.0f)/BM_DIM_STEP);
- y = (int)((m_goal.z+1600.0f)/BM_DIM_STEP);
- if ( BitmapTestDot(0, x, y) ) // arrival occupied?
- {
-#if 0
- Math::Vector min, max;
- min = m_object->RetPosition(0);
- max = m_goal;
- if ( min.x > max.x ) Math::Swap(min.x, max.x);
- if ( min.z > max.z ) Math::Swap(min.z, max.z);
- min.x -= 50.0f;
- min.z -= 50.0f;
- max.x += 50.0f;
- max.z += 50.0f;
- BitmapDebug(min, max, m_object->RetPosition(0), m_goal);
-#endif
- m_error = ERR_GOTO_BUSY;
- return m_error;
- }
- }
- }
-
- return ERR_OK;
-}
-
-// Indicates whether the action is finished.
-
-Error CTaskGoto::IsEnded()
-{
- Math::Vector pos;
- float limit, angle, dist, h, level;
-
- if ( m_engine->RetPause() ) return ERR_CONTINUE;
- if ( m_error != ERR_OK ) return m_error;
-
- pos = m_object->RetPosition(0);
-
- if ( m_phase == TGP_BEAMLEAK ) // leak?
- {
- if ( m_leakTime >= m_leakDelay )
- {
- m_physics->SetMotorSpeedX(0.0f); // stops the advance
- m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
- BeamInit();
- m_phase = TGP_BEAMSEARCH; // will seek the path
- }
- return ERR_CONTINUE;
- }
-
- if ( m_phase == TGP_BEAMSEARCH ) // search path?
- {
- return ERR_CONTINUE;
- }
-
- if ( m_phase == TGP_BEAMWCOLD ) // expects cool reactor?
- {
- if ( m_altitude != 0.0f &&
- m_physics->RetReactorRange() < 1.0f ) return ERR_CONTINUE;
- m_phase = TGP_BEAMUP;
- }
-
- if ( m_phase == TGP_BEAMUP ) // off?
- {
- if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f )
- {
- level = m_terrain->RetFloorLevel(pos, true, true);
- h = level+m_altitude-20.0f;
- limit = m_terrain->RetFlyingMaxHeight();
- if ( h > limit ) h = limit;
- if ( pos.y < h-1.0f ) return ERR_CONTINUE;
-
- m_physics->SetMotorSpeedY(0.0f); // stops the ascent
- }
- m_phase = TGP_BEAMGOTO;
- }
-
- if ( m_phase == TGP_BEAMGOTO ) // goto dot list ?
- {
- if ( m_altitude != 0.0f &&
- m_physics->RetReactorRange() < 0.1f ) // overheating?
- {
- m_physics->SetMotorSpeedX(0.0f); // stops the advance
- m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
- m_physics->SetMotorSpeedY(-1.0f); // tomb
- m_phase = TGP_BEAMWCOLD;
- return ERR_CONTINUE;
- }
-
- if ( m_physics->RetLand() ) // on the ground?
- {
- limit = 1.0f;
- }
- else // in flight?
- {
- limit = 2.0f;
- if ( m_bmIndex < m_bmTotal ) limit *= 2.0f; // intermediate point
- }
- if ( m_bApprox ) limit = 2.0f;
-
- if ( fabs(pos.x - m_bmPoints[m_bmIndex].x) < limit &&
- fabs(pos.z - m_bmPoints[m_bmIndex].z) < limit )
- {
- m_physics->SetMotorSpeedX(0.0f); // stops the advance
- m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
-
- m_bmIndex = BeamShortcut();
-
- if ( m_bmIndex > m_bmTotal )
- {
- m_phase = TGP_BEAMDOWN;
- }
- }
- }
-
- if ( m_phase == TGP_BEAMDOWN ) // landed?
- {
- if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f )
- {
- if ( !m_physics->RetLand() ) return ERR_CONTINUE;
- m_physics->SetMotorSpeedY(0.0f); // stops the descent
-
- m_altitude = 0.0f;
- m_phase = TGP_BEAMGOTO; // advance finely on the ground to finish
- m_bmIndex = m_bmTotal;
- return ERR_CONTINUE;
- }
-
- if ( m_bTake )
- {
- m_angle = Math::RotateAngle(m_goalObject.x-pos.x, pos.z-m_goalObject.z);
- m_phase = TGP_TURN;
- }
- else
- {
- m_physics->SetMotorSpeedX(0.0f); // stops the advance
- m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
- return ERR_STOP;
- }
- }
-
- if ( m_goalMode == TGG_EXPRESS )
- {
- dist = Math::DistanceProjected(m_goal, pos);
- if ( dist < 10.0f && dist > m_lastDistance )
- {
- return ERR_STOP;
- }
- m_lastDistance = dist;
- }
-
- if ( m_phase == TGP_ADVANCE ) // going towards the goal?
- {
- if ( m_physics->RetLand() ) limit = 0.1f; // on the ground
- else limit = 1.0f; // flying
- if ( m_bApprox ) limit = 2.0f;
-
- if ( fabs(pos.x - m_goal.x) < limit &&
- fabs(pos.z - m_goal.z) < limit )
- {
- m_physics->SetMotorSpeedX(0.0f); // stops the advance
- m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
- m_phase = TGP_LAND;
- }
- }
-
- if ( m_phase == TGP_LAND ) // landed?
- {
- if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f )
- {
- if ( !m_physics->RetLand() ) return ERR_CONTINUE;
- m_physics->SetMotorSpeedY(0.0f);
- }
-
- if ( m_bTake )
- {
- m_angle = Math::RotateAngle(m_goalObject.x-pos.x, pos.z-m_goalObject.z);
- m_phase = TGP_TURN;
- }
- else
- {
- return ERR_STOP;
- }
- }
-
- if ( m_phase == TGP_TURN ) // turns to the object?
- {
- angle = Math::NormAngle(m_object->RetAngleY(0));
- limit = 0.02f;
- if ( m_bApprox ) limit = 0.10f;
- if ( fabs(angle-m_angle) < limit )
- {
- m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
- if ( m_bmFinalMove == 0.0f ) return ERR_STOP;
-
- m_bmFinalPos = m_object->RetPosition(0);
- m_bmFinalDist = m_physics->RetLinLength(m_bmFinalMove);
- m_bmTimeLimit = m_physics->RetLinTimeLength(fabs(m_bmFinalMove))*1.5f;
- if ( m_bmTimeLimit < 0.5f ) m_bmTimeLimit = 0.5f;
- m_phase = TGP_MOVE;
- }
- }
-
- if ( m_phase == TGP_CRWAIT ) // waits after collision?
- {
- if ( m_crashMode == TGC_HALT )
- {
- m_physics->SetMotorSpeedX(0.0f); // stops the advance
- m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
- m_error = ERR_GENERIC;
- return m_error;
- }
- if ( m_time >= 1.0f )
- {
- if ( m_crashMode == TGC_RIGHTLEFT ||
- m_crashMode == TGC_RIGHT ) angle = Math::PI/2.0f; // 90 deegres to the right
- else angle = -Math::PI/2.0f; // 90 deegres to the left
- m_angle = Math::NormAngle(m_object->RetAngleY(0)+angle);
- m_phase = TGP_CRTURN;
-//? m_phase = TGP_ADVANCE;
- }
- }
-
- if ( m_phase == TGP_CRTURN ) // turns after collision?
- {
- angle = Math::NormAngle(m_object->RetAngleY(0));
- limit = 0.1f;
- if ( fabs(angle-m_angle) < limit )
- {
- m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
- m_pos = pos;
- m_phase = TGP_CRADVANCE;
- }
- }
-
- if ( m_phase == TGP_CRADVANCE ) // advance after collision?
- {
- if ( Math::Distance(pos, m_pos) >= 5.0f )
- {
- m_phase = TGP_ADVANCE;
- }
- }
-
- if ( m_phase == TGP_CLWAIT ) // waits after collision?
- {
- if ( m_time >= 1.0f )
- {
- if ( m_crashMode == TGC_RIGHTLEFT ) angle = -Math::PI;
- if ( m_crashMode == TGC_LEFTRIGHT ) angle = Math::PI;
- if ( m_crashMode == TGC_RIGHT ) angle = Math::PI/2.0f;
- if ( m_crashMode == TGC_LEFT ) angle = -Math::PI/2.0f;
- m_angle = Math::NormAngle(m_object->RetAngleY(0)+angle);
- m_phase = TGP_CLTURN;
- }
- }
-
- if ( m_phase == TGP_CLTURN ) // turns after collision?
- {
- angle = Math::NormAngle(m_object->RetAngleY(0));
- limit = 0.1f;
- if ( fabs(angle-m_angle) < limit )
- {
- m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
- m_pos = pos;
- m_phase = TGP_CLADVANCE;
- }
- }
-
- if ( m_phase == TGP_CLADVANCE ) // advance after collision?
- {
- if ( Math::Distance(pos, m_pos) >= 10.0f )
- {
- m_phase = TGP_ADVANCE;
- m_try ++;
- }
- }
-
- if ( m_phase == TGP_MOVE ) // final advance?
- {
- if ( m_bmTimeLimit <= 0.0f )
- {
- m_physics->SetMotorSpeedX(0.0f); // stops
- Abort();
- return ERR_STOP;
- }
-
- dist = Math::Distance(m_bmFinalPos, m_object->RetPosition(0));
- if ( dist < m_bmFinalDist ) return ERR_CONTINUE;
- m_physics->SetMotorSpeedX(0.0f); // stops the advance
- return ERR_STOP;
- }
-
- return ERR_CONTINUE;
-}
-
-
-// Tries the object is the target position.
-
-CObject* CTaskGoto::SearchTarget(Math::Vector pos, float margin)
-{
- CObject *pObj, *pBest;
- Math::Vector oPos;
- float dist, min;
- int i;
-
- pBest = 0;
- min = 1000000.0f;
- for ( i=0 ; i<1000000 ; i++ )
- {
- pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
- if ( pObj == 0 ) break;
-
- if ( !pObj->RetActif() ) continue;
- if ( pObj->RetTruck() != 0 ) continue; // object transtorted?
-
- oPos = pObj->RetPosition(0);
- dist = Math::DistanceProjected(pos, oPos);
-
- if ( dist <= margin && dist <= min )
- {
- min = dist;
- pBest = pObj;
- }
- }
-
- return pBest;
-}
-
-// Adjusts the target as a function of the object.
-// Returns true if it is cargo laying on the ground, which can be approached from any site.
-
-bool CTaskGoto::AdjustTarget(CObject* pObj, Math::Vector &pos, float &distance)
-{
- ObjectType type;
- Character* character;
- Math::Matrix* mat;
- Math::Vector goal;
- float dist, suppl;
-
- type = m_object->RetType();
- if ( type == OBJECT_BEE ||
- type == OBJECT_WORM )
- {
- pos = pObj->RetPosition(0);
- return false; // single approach
- }
-
- type = pObj->RetType();
-
- if ( type == OBJECT_FRET ||
- type == OBJECT_STONE ||
- type == OBJECT_URANIUM ||
- type == OBJECT_METAL ||
- type == OBJECT_POWER ||
- type == OBJECT_ATOMIC ||
- type == OBJECT_BULLET ||
- type == OBJECT_BBOX ||
- type == OBJECT_KEYa ||
- type == OBJECT_KEYb ||
- type == OBJECT_KEYc ||
- type == OBJECT_KEYd ||
- type == OBJECT_TNT ||
- type == OBJECT_SCRAP1 ||
- type == OBJECT_SCRAP2 ||
- type == OBJECT_SCRAP3 ||
- type == OBJECT_SCRAP4 ||
- type == OBJECT_SCRAP5 ||
- type == OBJECT_BOMB ||
- type == OBJECT_RUINmobilew1 ||
- type == OBJECT_RUINmobilew2 ||
- type == OBJECT_RUINmobilet1 ||
- type == OBJECT_RUINmobilet2 ||
- type == OBJECT_RUINmobiler1 ||
- type == OBJECT_RUINmobiler2 )
- {
- pos = m_object->RetPosition(0);
- goal = pObj->RetPosition(0);
- dist = Math::Distance(goal, pos);
- pos = (pos-goal)*(TAKE_DIST+distance)/dist + goal;
- return true; // approach from all sites
- }
-
- if ( type == OBJECT_BASE )
- {
- pos = m_object->RetPosition(0);
- goal = pObj->RetPosition(0);
- dist = Math::Distance(goal, pos);
- pos = (pos-goal)*(TAKE_DIST+distance)/dist + goal;
- return true; // approach from all sites
- }
-
- if ( type == OBJECT_MOBILEfa ||
- type == OBJECT_MOBILEta ||
- type == OBJECT_MOBILEwa ||
- type == OBJECT_MOBILEia ||
- type == OBJECT_MOBILEfs ||
- type == OBJECT_MOBILEts ||
- type == OBJECT_MOBILEws ||
- type == OBJECT_MOBILEis ||
- type == OBJECT_MOBILEfc ||
- type == OBJECT_MOBILEtc ||
- type == OBJECT_MOBILEwc ||
- type == OBJECT_MOBILEic ||
- type == OBJECT_MOBILEfi ||
- type == OBJECT_MOBILEti ||
- type == OBJECT_MOBILEwi ||
- type == OBJECT_MOBILEii ||
- type == OBJECT_MOBILErt ||
- type == OBJECT_MOBILErc ||
- type == OBJECT_MOBILErr ||
- type == OBJECT_MOBILErs ||
- type == OBJECT_MOBILEsa ||
- type == OBJECT_MOBILEtg ||
- type == OBJECT_MOBILEft ||
- type == OBJECT_MOBILEtt ||
- type == OBJECT_MOBILEwt ||
- type == OBJECT_MOBILEit ||
- type == OBJECT_MOBILEdr )
- {
- character = pObj->RetCharacter();
- pos = character->posPower;
- pos.x -= TAKE_DIST+TAKE_DIST_OTHER+distance;
- mat = pObj->RetWorldMatrix(0);
- pos = Transform(*mat, pos);
- return false; // single approach
- }
-
- if ( GetHotPoint(pObj, goal, true, distance, suppl) )
- {
- pos = goal;
- distance += suppl;
- return false; // single approach
- }
-
- pos = pObj->RetPosition(0);
- distance = 0.0f;
- return false; // single approach
-}
-
-// If you are on an object produced by a building (ore produced by derrick),
-// changes the position by report the building.
-
-bool CTaskGoto::AdjustBuilding(Math::Vector &pos, float margin, float &distance)
-{
- CObject* pObj;
- Math::Vector oPos;
- float dist, suppl;
- int i;
-
- for ( i=0 ; i<1000000 ; i++ )
- {
- pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
- if ( pObj == 0 ) break;
-
- if ( !pObj->RetActif() ) continue;
- if ( pObj->RetTruck() != 0 ) continue; // object transported?
-
- if ( !GetHotPoint(pObj, oPos, false, 0.0f, suppl) ) continue;
- dist = Math::DistanceProjected(pos, oPos);
- if ( dist <= margin )
- {
- GetHotPoint(pObj, pos, true, distance, suppl);
- distance += suppl;
- return true;
- }
- }
- return false;
-}
-
-// Returns the item or product or pose is something on a building.
-
-bool CTaskGoto::GetHotPoint(CObject *pObj, Math::Vector &pos,
- bool bTake, float distance, float &suppl)
-{
- ObjectType type;
- Math::Matrix* mat;
-
- pos = Math::Vector(0.0f, 0.0f, 0.0f);
- suppl = 0.0f;
- type = pObj->RetType();
-
- if ( type == OBJECT_DERRICK )
- {
- mat = pObj->RetWorldMatrix(0);
- pos.x += 8.0f;
- if ( bTake && distance != 0.0f ) suppl = 4.0f;
- if ( bTake ) pos.x += TAKE_DIST+distance+suppl;
- pos = Transform(*mat, pos);
- return true;
- }
-
- if ( type == OBJECT_CONVERT )
- {
- mat = pObj->RetWorldMatrix(0);
- pos.x += 0.0f;
- if ( bTake && distance != 0.0f ) suppl = 4.0f;
- if ( bTake ) pos.x += TAKE_DIST+distance+suppl;
- pos = Transform(*mat, pos);
- return true;
- }
-
- if ( type == OBJECT_RESEARCH )
- {
- mat = pObj->RetWorldMatrix(0);
- pos.x += 10.0f;
- if ( bTake && distance != 0.0f ) suppl = 2.5f;
- if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance+suppl;
- pos = Transform(*mat, pos);
- return true;
- }
-
- if ( type == OBJECT_ENERGY )
- {
- mat = pObj->RetWorldMatrix(0);
- pos.x += 6.0f;
- if ( bTake && distance != 0.0f ) suppl = 6.0f;
- if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance;
- pos = Transform(*mat, pos);
- return true;
- }
-
- if ( type == OBJECT_TOWER )
- {
- mat = pObj->RetWorldMatrix(0);
- pos.x += 5.0f;
- if ( bTake && distance != 0.0f ) suppl = 4.0f;
- if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance+suppl;
- pos = Transform(*mat, pos);
- return true;
- }
-
- if ( type == OBJECT_LABO )
- {
- mat = pObj->RetWorldMatrix(0);
- pos.x += 6.0f;
- if ( bTake && distance != 0.0f ) suppl = 6.0f;
- if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance;
- pos = Transform(*mat, pos);
- return true;
- }
-
- if ( type == OBJECT_NUCLEAR )
- {
- mat = pObj->RetWorldMatrix(0);
- pos.x += 22.0f;
- if ( bTake && distance != 0.0f ) suppl = 4.0f;
- if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance+suppl;
- pos = Transform(*mat, pos);
- return true;
- }
-
- if ( type == OBJECT_FACTORY )
- {
- mat = pObj->RetWorldMatrix(0);
- pos.x += 4.0f;
- if ( bTake && distance != 0.0f ) suppl = 6.0f;
- if ( bTake ) pos.x += TAKE_DIST+distance+suppl;
- pos = Transform(*mat, pos);
- return true;
- }
-
- if ( type == OBJECT_STATION )
- {
- mat = pObj->RetWorldMatrix(0);
- pos.x += 4.0f;
- if ( bTake && distance != 0.0f ) suppl = 4.0f;
- if ( bTake ) pos.x += distance;
- pos = Transform(*mat, pos);
- return true;
- }
-
- if ( type == OBJECT_REPAIR )
- {
- mat = pObj->RetWorldMatrix(0);
- pos.x += 4.0f;
- if ( bTake && distance != 0.0f ) suppl = 4.0f;
- if ( bTake ) pos.x += distance;
- pos = Transform(*mat, pos);
- return true;
- }
-
- if ( type == OBJECT_DESTROYER )
- {
- mat = pObj->RetWorldMatrix(0);
- pos.x += 0.0f;
- if ( bTake && distance != 0.0f ) suppl = 4.0f;
- if ( bTake ) pos.x += TAKE_DIST+distance+suppl;
- pos = Transform(*mat, pos);
- return true;
- }
-
- if ( type == OBJECT_PARA && m_physics->RetType() == TYPE_FLYING )
- {
- mat = pObj->RetWorldMatrix(0);
- if ( bTake && distance != 0.0f ) suppl = 20.0f;
- if ( bTake ) pos.x += distance+suppl;
- pos = Transform(*mat, pos);
- return true;
- }
-
- suppl = 0.0f;
- return false;
-}
-
-
-// Seeks an object too close that he must flee.
-
-bool CTaskGoto::LeakSearch(Math::Vector &pos, float &delay)
-{
- CObject *pObj, *pObstacle;
- Math::Vector iPos, oPos, bPos;
- float iRadius, oRadius, bRadius, dist, min, dir;
- int i, j;
-
- if ( !m_physics->RetLand() ) return false; // in flight?
-
- m_object->GetCrashSphere(0, iPos, iRadius);
-
- min = 100000.0f;
- bRadius = 0.0f;
- for ( i=0 ; i<1000000 ; i++ )
- {
- pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
- if ( pObj == 0 ) break;
-
- if ( pObj == m_object ) continue;
- if ( !pObj->RetActif() ) continue;
- if ( pObj->RetTruck() != 0 ) continue; // object transported?
-
- j = 0;
- while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
- {
- dist = Math::DistanceProjected(oPos, iPos);
- if ( dist < min )
- {
- min = dist;
- bPos = oPos;
- bRadius = oRadius;
- pObstacle = pObj;
- }
- }
- }
- if ( min > iRadius+bRadius+4.0f ) return false;
-
- m_bLeakRecede = false;
-
- dist = 4.0f;
- dir = 1.0f;
- if ( pObstacle->RetType() == OBJECT_FACTORY )
- {
- dist = 16.0f;
- dir = -1.0f;
- m_bLeakRecede = true; // simply recoils
- }
-
- pos = bPos;
- delay = m_physics->RetLinTimeLength(dist, dir);
- return true;
-}
-
-
-// Calculates the force of repulsion due to obstacles.
-// The vector length rendered is between 0 and 1.
-
-void CTaskGoto::ComputeRepulse(Math::Point &dir)
-{
-#if 0
- Math::Vector iPos, oPos;
- Math::Point repulse;
- CObject *pObj;
- float dist, iRadius, oRadius;
- int i;
-
- dir.x = 0.0f;
- dir.y = 0.0f;
-
- m_object->GetCrashSphere(0, iPos, iRadius);
-
- for ( i=0 ; i<1000000 ; i++ )
- {
- pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
- if ( pObj == 0 ) break;
-
- if ( pObj == m_object ) continue;
- if ( pObj->RetTruck() != 0 ) continue;
-
- oPos = pObj->RetPosition(0);
- dist = Math::Distance(oPos, m_goalObject);
- if ( dist <= 1.0f ) continue;
-
- pObj->GetGlobalSphere(oPos, oRadius);
- oRadius += iRadius+m_physics->RetLinStopLength()*1.1f;
- dist = Math::DistanceProjected(oPos, iPos);
- if ( dist <= oRadius )
- {
- repulse.x = iPos.x-oPos.x;
- repulse.y = iPos.z-oPos.z;
-
-//? dist = 0.2f-(0.2f*dist/oRadius);
- dist = powf(dist/oRadius, 2.0f);
- dist = 0.2f-0.2f*dist;
- repulse.x *= dist;
- repulse.y *= dist;
-//? repulse.x /= dist;
-//? repulse.y /= dist;
-
- dir.x += repulse.x;
- dir.y += repulse.y;
- }
- }
-#else
- ObjectType iType, oType;
- Math::Vector iPos, oPos;
- Math::Point repulse;
- CObject *pObj;
- float gDist, add, addi, fac, dist, iRadius, oRadius;
- int i, j;
- bool bAlien;
-
- dir.x = 0.0f;
- dir.y = 0.0f;
-
- // The worm goes everywhere and through everything!
- iType = m_object->RetType();
- if ( iType == OBJECT_WORM ) return;
-
- m_object->GetCrashSphere(0, iPos, iRadius);
- gDist = Math::Distance(iPos, m_goal);
-
- add = m_physics->RetLinStopLength()*1.1f; // braking distance
- fac = 2.0f;
-
- if ( iType == OBJECT_MOBILEwa ||
- iType == OBJECT_MOBILEwc ||
- iType == OBJECT_MOBILEwi ||
- iType == OBJECT_MOBILEws ||
- iType == OBJECT_MOBILEwt ) // wheels?
- {
- add = 5.0f;
- fac = 1.5f;
- }
- if ( iType == OBJECT_MOBILEta ||
- iType == OBJECT_MOBILEtc ||
- iType == OBJECT_MOBILEti ||
- iType == OBJECT_MOBILEts ||
- iType == OBJECT_MOBILEtt ||
- iType == OBJECT_MOBILEdr ) // caterpillars?
- {
- add = 4.0f;
- fac = 1.5f;
- }
- if ( iType == OBJECT_MOBILEfa ||
- iType == OBJECT_MOBILEfc ||
- iType == OBJECT_MOBILEfi ||
- iType == OBJECT_MOBILEfs ||
- iType == OBJECT_MOBILEft ) // flying?
- {
- if ( m_physics->RetLand() )
- {
- add = 5.0f;
- fac = 1.5f;
- }
- else
- {
- add = 10.0f;
- fac = 1.5f;
- }
- }
- if ( iType == OBJECT_MOBILEia ||
- iType == OBJECT_MOBILEic ||
- iType == OBJECT_MOBILEii ||
- iType == OBJECT_MOBILEis ||
- iType == OBJECT_MOBILEit ) // legs?
- {
- add = 4.0f;
- fac = 1.5f;
- }
- if ( iType == OBJECT_BEE ) // wasp?
- {
- if ( m_physics->RetLand() )
- {
- add = 3.0f;
- fac = 1.5f;
- }
- else
- {
- add = 5.0f;
- fac = 1.5f;
- }
- }
-
- bAlien = false;
- if ( iType == OBJECT_MOTHER ||
- iType == OBJECT_ANT ||
- iType == OBJECT_SPIDER ||
- iType == OBJECT_BEE ||
- iType == OBJECT_WORM )
- {
- bAlien = true;
- }
-
- for ( i=0 ; i<1000000 ; i++ )
- {
- pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
- if ( pObj == 0 ) break;
-
- if ( pObj == m_object ) continue;
- if ( pObj->RetTruck() != 0 ) continue;
-
- oType = pObj->RetType();
-
- if ( oType == OBJECT_WORM ) continue;
-
- if ( bAlien )
- {
- if ( oType == OBJECT_STONE ||
- oType == OBJECT_URANIUM ||
- oType == OBJECT_METAL ||
- oType == OBJECT_POWER ||
- oType == OBJECT_ATOMIC ||
- oType == OBJECT_BULLET ||
- oType == OBJECT_BBOX ||
- oType == OBJECT_KEYa ||
- oType == OBJECT_KEYb ||
- oType == OBJECT_KEYc ||
- oType == OBJECT_KEYd ||
- oType == OBJECT_TNT ||
- oType == OBJECT_SCRAP1 ||
- oType == OBJECT_SCRAP2 ||
- oType == OBJECT_SCRAP3 ||
- oType == OBJECT_SCRAP4 ||
- oType == OBJECT_SCRAP5 ||
- oType == OBJECT_BOMB ||
- (oType >= OBJECT_PLANT0 &&
- oType <= OBJECT_PLANT19 ) ||
- (oType >= OBJECT_MUSHROOM0 &&
- oType <= OBJECT_MUSHROOM9 ) ) continue;
- }
-
- addi = add;
- if ( iType == OBJECT_BEE &&
- oType == OBJECT_BEE )
- {
- addi = 2.0f; // between wasps, do not annoy too much
- }
-
- j = 0;
- while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
- {
- if ( oPos.y-oRadius > iPos.y+iRadius ) continue;
- if ( oPos.y+oRadius < iPos.y-iRadius ) continue;
-
- dist = Math::Distance(oPos, m_goal);
- if ( dist <= 1.0f ) continue; // on purpose?
-
- oRadius += iRadius+addi;
- dist = Math::DistanceProjected(oPos, iPos);
- if ( dist > gDist ) continue; // beyond the goal?
- if ( dist <= oRadius )
- {
- repulse.x = iPos.x-oPos.x;
- repulse.y = iPos.z-oPos.z;
-
- dist = powf(dist/oRadius, fac);
- dist = 0.2f-0.2f*dist;
- repulse.x *= dist;
- repulse.y *= dist;
-
- dir.x += repulse.x;
- dir.y += repulse.y;
- }
- }
- }
-#endif
-}
-
-// Calculates the force of vertical repulsion according to barriers.
-// The vector length is made​between -1 and 1.
-
-void CTaskGoto::ComputeFlyingRepulse(float &dir)
-{
- ObjectType oType;
- Math::Vector iPos, oPos;
- CObject *pObj;
- float add, fac, dist, iRadius, oRadius, repulse;
- int i, j;
-
- m_object->GetCrashSphere(0, iPos, iRadius);
-
- add = 0.0f;
- fac = 1.5f;
- dir = 0.0f;
-
- for ( i=0 ; i<1000000 ; i++ )
- {
- pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
- if ( pObj == 0 ) break;
-
- if ( pObj == m_object ) continue;
- if ( pObj->RetTruck() != 0 ) continue;
-
- oType = pObj->RetType();
-
- if ( oType == OBJECT_WORM ) continue;
-
- j = 0;
- while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
- {
- oRadius += iRadius+add;
- dist = Math::DistanceProjected(oPos, iPos);
- if ( dist <= oRadius )
- {
- repulse = iPos.y-oPos.y;
-
- dist = powf(dist/oRadius, fac);
- dist = 0.2f-0.2f*dist;
- repulse *= dist;
-
- dir += repulse;
- }
- }
- }
-
- if ( dir < -1.0f ) dir = -1.0f;
- if ( dir > 1.0f ) dir = 1.0f;
-}
-
-
-
-// Among all of the following, seek if there is one allowing to go directly to the crow flies.
-// If yes, skip all the unnecessary intermediate points.
-
-int CTaskGoto::BeamShortcut()
-{
- int i;
-
- for ( i=m_bmTotal ; i>=m_bmIndex+2 ; i-- ) // tries from the last
- {
- if ( BitmapTestLine(m_bmPoints[m_bmIndex], m_bmPoints[i], 0.0f, false) )
- {
- return i; // bingo, found
- }
- }
-
- return m_bmIndex+1; // simply goes to the next
-}
-
-// That's the big start.
-
-void CTaskGoto::BeamStart()
-{
- Math::Vector min, max;
-
- BitmapOpen();
- BitmapObject();
-
- min = m_object->RetPosition(0);
- max = m_goal;
- if ( min.x > max.x ) Math::Swap(min.x, max.x);
- if ( min.z > max.z ) Math::Swap(min.z, max.z);
- min.x -= 10.0f*BM_DIM_STEP;
- min.z -= 10.0f*BM_DIM_STEP;
- max.x += 10.0f*BM_DIM_STEP;
- max.z += 10.0f*BM_DIM_STEP;
- BitmapTerrain(min, max);
-
- if ( LeakSearch(m_leakPos, m_leakDelay) )
- {
- m_phase = TGP_BEAMLEAK; // must first leak
- m_leakTime = 0.0f;
- }
- else
- {
- m_physics->SetMotorSpeedX(0.0f); // stops the advance
- m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
- BeamInit();
- m_phase = TGP_BEAMSEARCH; // will seek the path
- }
-}
-
-// Initialization before the first BeamSearch.
-
-void CTaskGoto::BeamInit()
-{
- int i;
-
- for ( i=0 ; i<MAXPOINTS ; i++ )
- {
- m_bmIter[i] = -1;
- }
- m_bmStep = 0;
-}
-
-// Calculates points and passes to go from start to goal.
-// Returns:
-// ERR_OK if it's good
-// ERR_GOTO_IMPOSSIBLE if impossible
-// ERR_GOTO_ITER if aborts because too many recursions
-// ERR_CONTINUE if not done yet
-// goalRadius: distance at which we must approach the goal
-
-Error CTaskGoto::BeamSearch(const Math::Vector &start, const Math::Vector &goal,
- float goalRadius)
-{
- float step, len;
- int nbIter;
-
- m_bmStep ++;
-
- len = Math::DistanceProjected(start, goal);
- step = len/5.0f;
- if ( step < BM_DIM_STEP*2.1f ) step = BM_DIM_STEP*2.1f;
- if ( step > 20.0f ) step = 20.0f;
- nbIter = 200; // in order not to lower the framerate
- m_bmIterCounter = 0;
- return BeamExplore(start, start, goal, goalRadius, 165.0f*Math::PI/180.0f, 22, step, 0, nbIter);
-}
-
-// prevPos: previous position
-// curPos: current position
-// goalPos: position that seeks to achieve
-// angle: angle to the goal we explores
-// nbDiv: number of subdivisions being done with angle
-// step length of a step
-// i number of recursions made
-// nbIter maximum number of iterations you have the right to make before temporarily interrupt
-
-Error CTaskGoto::BeamExplore(const Math::Vector &prevPos, const Math::Vector &curPos,
- const Math::Vector &goalPos, float goalRadius,
- float angle, int nbDiv, float step,
- int i, int nbIter)
-{
- Math::Vector newPos;
- Error ret;
- int iDiv, iClear, iLar;
-
- iLar = 0;
- if ( i >= MAXPOINTS ) return ERR_GOTO_ITER; // too many recursions
-
- if ( m_bmIter[i] == -1 )
- {
- m_bmIter[i] = 0;
-
- if ( i == 0 )
- {
- m_bmPoints[i] = curPos;
- }
- else
- {
- if ( !BitmapTestLine(prevPos, curPos, angle/nbDiv, true) ) return ERR_GOTO_IMPOSSIBLE;
-
- m_bmPoints[i] = curPos;
-
- if ( Math::DistanceProjected(curPos, goalPos)-goalRadius <= step )
- {
- if ( goalRadius == 0.0f )
- {
- newPos = goalPos;
- }
- else
- {
- newPos = BeamPoint(curPos, goalPos, 0, Math::DistanceProjected(curPos, goalPos)-goalRadius);
- }
- if ( BitmapTestLine(curPos, newPos, angle/nbDiv, false) )
- {
- m_bmPoints[i+1] = newPos;
- m_bmTotal = i+1;
- return ERR_OK;
- }
- }
- }
- }
-
- if ( iLar >= m_bmIter[i] )
- {
- newPos = BeamPoint(curPos, goalPos, 0, step);
- ret = BeamExplore(curPos, newPos, goalPos, goalRadius, angle, nbDiv, step, i+1, nbIter);
- if ( ret != ERR_GOTO_IMPOSSIBLE ) return ret;
- m_bmIter[i] = iLar+1;
- for ( iClear=i+1 ; iClear<=MAXPOINTS ; iClear++ ) m_bmIter[iClear] = -1;
- m_bmIterCounter ++;
- if ( m_bmIterCounter >= nbIter ) return ERR_CONTINUE;
- }
- iLar ++;
-
- for ( iDiv=1 ; iDiv<=nbDiv ; iDiv++ )
- {
- if ( iLar >= m_bmIter[i] )
- {
- newPos = BeamPoint(curPos, goalPos, angle*iDiv/nbDiv, step);
- ret = BeamExplore(curPos, newPos, goalPos, goalRadius, angle, nbDiv, step, i+1, nbIter);
- if ( ret != ERR_GOTO_IMPOSSIBLE ) return ret;
- m_bmIter[i] = iLar+1;
- for ( iClear=i+1 ; iClear<=MAXPOINTS ; iClear++ ) m_bmIter[iClear] = -1;
- m_bmIterCounter ++;
- if ( m_bmIterCounter >= nbIter ) return ERR_CONTINUE;
- }
- iLar ++;
-
- if ( iLar >= m_bmIter[i] )
- {
- newPos = BeamPoint(curPos, goalPos, -angle*iDiv/nbDiv, step);
- ret = BeamExplore(curPos, newPos, goalPos, goalRadius, angle, nbDiv, step, i+1, nbIter);
- if ( ret != ERR_GOTO_IMPOSSIBLE ) return ret;
- m_bmIter[i] = iLar+1;
- for ( iClear=i+1 ; iClear<=MAXPOINTS ; iClear++ ) m_bmIter[iClear] = -1;
- m_bmIterCounter ++;
- if ( m_bmIterCounter >= nbIter ) return ERR_CONTINUE;
- }
- iLar ++;
- }
-
- return ERR_GOTO_IMPOSSIBLE;
-}
-
-// Is a right "start-goal". Calculates the point located at the distance "step"
-// from the point "start" and an angle "angle" with the right.
-
-Math::Vector CTaskGoto::BeamPoint(const Math::Vector &startPoint,
- const Math::Vector &goalPoint,
- float angle, float step)
-{
- Math::Vector resPoint;
- float goalAngle;
-
- goalAngle = Math::RotateAngle(goalPoint.x-startPoint.x, goalPoint.z-startPoint.z);
-
- resPoint.x = startPoint.x + cosf(goalAngle+angle)*step;
- resPoint.z = startPoint.z + sinf(goalAngle+angle)*step;
- resPoint.y = 0.0f;
-
- return resPoint;
-}
-
-// Displays a bitmap part.
-
-void CTaskGoto::BitmapDebug(const Math::Vector &min, const Math::Vector &max,
- const Math::Vector &start, const Math::Vector &goal)
-{
- int minx, miny, maxx, maxy, x, y, i ,n;
- char s[2000];
-
- minx = (int)((min.x+1600.0f)/BM_DIM_STEP);
- miny = (int)((min.z+1600.0f)/BM_DIM_STEP);
- maxx = (int)((max.x+1600.0f)/BM_DIM_STEP);
- maxy = (int)((max.z+1600.0f)/BM_DIM_STEP);
-
- if ( minx > maxx ) Math::Swap(minx, maxx);
- if ( miny > maxy ) Math::Swap(miny, maxy);
-
- OutputDebugString("Bitmap :\n");
- for ( y=miny ; y<=maxy ; y++ )
- {
- s[0] = 0;
- for ( x=minx ; x<=maxx ; x++ )
- {
- n = -1;
- for ( i=0 ; i<=m_bmTotal ; i++ )
- {
- if ( x == (int)((m_bmPoints[i].x+1600.0f)/BM_DIM_STEP) &&
- y == (int)((m_bmPoints[i].z+1600.0f)/BM_DIM_STEP) )
- {
- n = i;
- break;
- }
- }
-
- if ( BitmapTestDot(0, x,y) )
- {
- strcat(s, "o");
- }
- else
- {
- if ( BitmapTestDot(1, x,y) )
- {
- strcat(s, "-");
- }
- else
- {
- strcat(s, ".");
- }
- }
-
- if ( x == (int)((start.x+1600.0f)/BM_DIM_STEP) &&
- y == (int)((start.z+1600.0f)/BM_DIM_STEP) )
- {
- strcat(s, "s");
- }
- else
- if ( x == (int)((goal.x+1600.0f)/BM_DIM_STEP) &&
- y == (int)((goal.z+1600.0f)/BM_DIM_STEP) )
- {
- strcat(s, "g");
- }
- else
- if ( n != -1 )
- {
- char ss[2];
- ss[0] = 'A'+n;
- ss[1] = 0;
- strcat(s, ss);
- }
- else
- {
- strcat(s, " ");
- }
- }
- strcat(s, "\n");
- OutputDebugString(s);
- }
-}
-
-// Tests if a path along a straight line is possible.
-
-bool CTaskGoto::BitmapTestLine(const Math::Vector &start, const Math::Vector &goal,
- float stepAngle, bool bSecond)
-{
- Math::Vector pos, inc;
- float dist, step;
- float distNoB2;
- int i, max, x, y;
-
- if ( m_bmArray == 0 ) return true;
-
- dist = Math::DistanceProjected(start, goal);
- if ( dist == 0.0f ) return true;
- step = BM_DIM_STEP*0.5f;
-
- inc.x = (goal.x-start.x)*step/dist;
- inc.z = (goal.z-start.z)*step/dist;
-
- pos = start;
-
- if ( bSecond )
- {
- x = (int)((pos.x+1600.0f)/BM_DIM_STEP);
- y = (int)((pos.z+1600.0f)/BM_DIM_STEP);
- BitmapSetDot(1, x, y); // puts the flag as the starting point
- }
-
- max = (int)(dist/step);
- if ( max == 0 ) max = 1;
- distNoB2 = BM_DIM_STEP*sqrtf(2.0f)/sinf(stepAngle);
- for ( i=0 ; i<max ; i++ )
- {
- if ( i == max-1 )
- {
- pos = goal; // tests the point of arrival
- }
- else
- {
- pos.x += inc.x;
- pos.z += inc.z;
- }
-
- x = (int)((pos.x+1600.0f)/BM_DIM_STEP);
- y = (int)((pos.z+1600.0f)/BM_DIM_STEP);
-
- if ( bSecond )
- {
- if ( i > 2 && BitmapTestDot(1, x, y) ) return false;
-
- if ( step*(i+1) > distNoB2 && i < max-2 )
- {
- BitmapSetDot(1, x, y);
- }
- }
-
- if ( BitmapTestDot(0, x, y) ) return false;
- }
- return true;
-}
-
-// Adds the objects in the bitmap.
-
-void CTaskGoto::BitmapObject()
-{
- CObject *pObj;
- ObjectType type;
- Math::Vector iPos, oPos;
- float iRadius, oRadius, h;
- int i, j;
-
- m_object->GetCrashSphere(0, iPos, iRadius);
-
- for ( i=0 ; i<1000000 ; i++ )
- {
- pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
- if ( pObj == 0 ) break;
-
- type = pObj->RetType();
-
- if ( pObj == m_object ) continue;
- if ( pObj == m_bmFretObject ) continue;
- if ( pObj->RetTruck() != 0 ) continue;
-
- h = m_terrain->RetFloorLevel(pObj->RetPosition(0), false);
- if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f )
- {
- h += m_altitude;
- }
-
- j = 0;
- while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
- {
- if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f ) // flying?
- {
- if ( oPos.y-oRadius > h+8.0f ||
- oPos.y+oRadius < h-8.0f ) continue;
- }
- else // crawling?
- {
- if ( oPos.y-oRadius > h+8.0f ) continue;
- }
-
- if ( type == OBJECT_PARA ) oRadius -= 2.0f;
- BitmapSetCircle(oPos, oRadius+iRadius+4.0f);
- }
- }
-}
-
-// Adds a section of land in the bitmap.
-
-void CTaskGoto::BitmapTerrain(const Math::Vector &min, const Math::Vector &max)
-{
- int minx, miny, maxx, maxy;
-
- minx = (int)((min.x+1600.0f)/BM_DIM_STEP);
- miny = (int)((min.z+1600.0f)/BM_DIM_STEP);
- maxx = (int)((max.x+1600.0f)/BM_DIM_STEP);
- maxy = (int)((max.z+1600.0f)/BM_DIM_STEP);
-
- BitmapTerrain(minx, miny, maxx, maxy);
-}
-
-// Adds a section of land in the bitmap.
-
-void CTaskGoto::BitmapTerrain(int minx, int miny, int maxx, int maxy)
-{
- ObjectType type;
- Math::Vector p;
- float aLimit, angle, h;
- int x, y;
- bool bAcceptWater, bFly;
-
- if ( minx > maxx ) Math::Swap(minx, maxx);
- if ( miny > maxy ) Math::Swap(miny, maxy);
-
- if ( minx < 0 ) minx = 0;
- if ( miny < 0 ) miny = 0;
- if ( maxx > m_bmSize-1 ) maxx = m_bmSize-1;
- if ( maxy > m_bmSize-1 ) maxy = m_bmSize-1;
-
- if ( minx > m_bmMinX ) minx = m_bmMinX;
- if ( miny > m_bmMinY ) miny = m_bmMinY;
- if ( maxx < m_bmMaxX ) maxx = m_bmMaxX;
- if ( maxy < m_bmMaxY ) maxy = m_bmMaxY;
-
- if ( minx >= m_bmMinX && maxx <= m_bmMaxX &&
- miny >= m_bmMinY && maxy <= m_bmMaxY ) return;
-
- aLimit = 20.0f*Math::PI/180.0f;
- bAcceptWater = false;
- bFly = false;
-
- type = m_object->RetType();
-
- if ( type == OBJECT_MOBILEwa ||
- type == OBJECT_MOBILEwc ||
- type == OBJECT_MOBILEws ||
- type == OBJECT_MOBILEwi ||
- type == OBJECT_MOBILEwt ||
- type == OBJECT_MOBILEtg ) // wheels?
- {
- aLimit = 20.0f*Math::PI/180.0f;
- }
-
- if ( type == OBJECT_MOBILEta ||
- type == OBJECT_MOBILEtc ||
- type == OBJECT_MOBILEti ||
- type == OBJECT_MOBILEts ) // caterpillars?
- {
- aLimit = 35.0f*Math::PI/180.0f;
- }
-
- if ( type == OBJECT_MOBILErt ||
- type == OBJECT_MOBILErc ||
- type == OBJECT_MOBILErr ||
- type == OBJECT_MOBILErs ) // large caterpillars?
- {
- aLimit = 35.0f*Math::PI/180.0f;
- }
-
- if ( type == OBJECT_MOBILEsa ) // submarine caterpillars?
- {
- aLimit = 35.0f*Math::PI/180.0f;
- bAcceptWater = true;
- }
-
- if ( type == OBJECT_MOBILEdr ) // designer caterpillars?
- {
- aLimit = 35.0f*Math::PI/180.0f;
- }
-
- if ( type == OBJECT_MOBILEfa ||
- type == OBJECT_MOBILEfc ||
- type == OBJECT_MOBILEfs ||
- type == OBJECT_MOBILEfi ||
- type == OBJECT_MOBILEft ) // flying?
- {
- aLimit = 15.0f*Math::PI/180.0f;
- bFly = true;
- }
-
- if ( type == OBJECT_MOBILEia ||
- type == OBJECT_MOBILEic ||
- type == OBJECT_MOBILEis ||
- type == OBJECT_MOBILEii ) // insect legs?
- {
- aLimit = 60.0f*Math::PI/180.0f;
- }
-
- for ( y=miny ; y<=maxy ; y++ )
- {
- for ( x=minx ; x<=maxx ; x++ )
- {
- if ( x >= m_bmMinX && x <= m_bmMaxX &&
- y >= m_bmMinY && y <= m_bmMaxY ) continue;
-
- p.x = x*BM_DIM_STEP-1600.0f;
- p.z = y*BM_DIM_STEP-1600.0f;
-
- if ( bFly ) // flying robot?
- {
- h = m_terrain->RetFloorLevel(p, true);
- if ( h >= m_terrain->RetFlyingMaxHeight()-5.0f )
- {
- BitmapSetDot(0, x, y);
- }
- continue;
- }
-
- if ( !bAcceptWater ) // not going underwater?
- {
- h = m_terrain->RetFloorLevel(p, true);
- if ( h < m_water->RetLevel()-2.0f ) // under water (*)?
- {
-//? BitmapSetDot(0, x, y);
- BitmapSetCircle(p, BM_DIM_STEP*1.0f);
- continue;
- }
- }
-
- angle = m_terrain->RetFineSlope(p);
- if ( angle > aLimit )
- {
- BitmapSetDot(0, x, y);
- }
- }
- }
-
- m_bmMinX = minx;
- m_bmMinY = miny;
- m_bmMaxX = maxx;
- m_bmMaxY = maxy; // expanded rectangular area
-}
-
-// (*) Accepts that a robot is 50cm under water, for example Tropica 3!
-
-// Opens an empty bitmap.
-
-bool CTaskGoto::BitmapOpen()
-{
- BitmapClose();
-
- m_bmSize = (int)(3200.0f/BM_DIM_STEP);
- m_bmArray = (unsigned char*)malloc(m_bmSize*m_bmSize/8*2);
- ZeroMemory(m_bmArray, m_bmSize*m_bmSize/8*2);
-
- m_bmOffset = m_bmSize/2;
- m_bmLine = m_bmSize/8;
-
- m_bmMinX = m_bmSize; // non-existent rectangular area
- m_bmMinY = m_bmSize;
- m_bmMaxX = 0;
- m_bmMaxY = 0;
-
- return true;
-}
-
-// Closes the bitmap.
-
-bool CTaskGoto::BitmapClose()
-{
- free(m_bmArray);
- m_bmArray = 0;
- return true;
-}
-
-// Puts a circle in the bitmap.
-
-void CTaskGoto::BitmapSetCircle(const Math::Vector &pos, float radius)
-{
- float d, r;
- int cx, cy, ix, iy;
-
- cx = (int)((pos.x+1600.0f)/BM_DIM_STEP);
- cy = (int)((pos.z+1600.0f)/BM_DIM_STEP);
- r = radius/BM_DIM_STEP;
-
- for ( iy=cy-(int)r ; iy<=cy+(int)r ; iy++ )
- {
- for ( ix=cx-(int)r ; ix<=cx+(int)r ; ix++ )
- {
- d = Math::Point((float)(ix-cx), (float)(iy-cy)).Length();
- if ( d > r ) continue;
- BitmapSetDot(0, ix, iy);
- }
- }
-}
-
-// Removes a circle in the bitmap.
-
-void CTaskGoto::BitmapClearCircle(const Math::Vector &pos, float radius)
-{
- float d, r;
- int cx, cy, ix, iy;
-
- cx = (int)((pos.x+1600.0f)/BM_DIM_STEP);
- cy = (int)((pos.z+1600.0f)/BM_DIM_STEP);
- r = radius/BM_DIM_STEP;
-
- for ( iy=cy-(int)r ; iy<=cy+(int)r ; iy++ )
- {
- for ( ix=cx-(int)r ; ix<=cx+(int)r ; ix++ )
- {
- d = Math::Point((float)(ix-cx), (float)(iy-cy)).Length();
- if ( d > r ) continue;
- BitmapClearDot(0, ix, iy);
- }
- }
-}
-
-// Makes a point in the bitmap.
-// x:y: 0..m_bmSize-1
-
-void CTaskGoto::BitmapSetDot(int rank, int x, int y)
-{
- if ( x < 0 || x >= m_bmSize ||
- y < 0 || y >= m_bmSize ) return;
-
- m_bmArray[rank*m_bmLine*m_bmSize + m_bmLine*y + x/8] |= (1<<x%8);
-}
-
-// Removes a point in the bitmap.
-// x:y: 0..m_bmSize-1
-
-void CTaskGoto::BitmapClearDot(int rank, int x, int y)
-{
- if ( x < 0 || x >= m_bmSize ||
- y < 0 || y >= m_bmSize ) return;
-
- m_bmArray[rank*m_bmLine*m_bmSize + m_bmLine*y + x/8] &= ~(1<<x%8);
-}
-
-// Tests a point in the bitmap.
-// x:y: 0..m_bmSize-1
-
-bool CTaskGoto::BitmapTestDot(int rank, int x, int y)
-{
- if ( x < 0 || x >= m_bmSize ||
- y < 0 || y >= m_bmSize ) return false;
-
- if ( x < m_bmMinX || x > m_bmMaxX ||
- y < m_bmMinY || y > m_bmMaxY )
- {
- BitmapTerrain(x-10,y-10, x+10,y+10); // remade a layer
- }
-
- return m_bmArray[rank*m_bmLine*m_bmSize + m_bmLine*y + x/8] & (1<<x%8);
-}
-
-
+// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +// taskgoto.cpp + + +#include <stdio.h> + +#include "object/task/taskgoto.h" + +#include "common/event.h" +#include "common/iman.h" +#include "old/terrain.h" +#include "old/water.h" +#include "math/geometry.h" +#include "physics/physics.h" + + + +const float FLY_DIST_GROUND = 80.0f; // minimum distance to remain on the ground +const float FLY_DEF_HEIGHT = 50.0f; // default flying height +const float BM_DIM_STEP = 5.0f; + + + + +// Object's constructor. + +CTaskGoto::CTaskGoto(CInstanceManager* iMan, CObject* object) + : CTask(iMan, object) +{ + m_bmArray = 0; +} + +// Object's destructor. + +CTaskGoto::~CTaskGoto() +{ + BitmapClose(); +} + + +// Management of an event. + +bool CTaskGoto::EventProcess(const Event &event) +{ + Math::Vector pos, goal; + Math::Point rot, repulse; + float a, g, dist, linSpeed, cirSpeed, h, hh, factor, dir; + Error ret; + + if ( m_engine->RetPause() ) return true; + if ( event.event != EVENT_FRAME ) return true; + + // Momentarily stationary object (ant on the back)? + if ( m_object->RetFixed() ) + { + m_physics->SetMotorSpeedX(0.0f); // stops the advance + m_physics->SetMotorSpeedZ(0.0f); // stops the rotation + return true; + } + + if ( m_error != ERR_OK ) return false; + + if ( m_bWorm ) + { + WormFrame(event.rTime); + } + + if ( m_phase == TGP_BEAMLEAK ) // leak? + { + m_leakTime += event.rTime; + + pos = m_object->RetPosition(0); + + rot.x = m_leakPos.x-pos.x; + rot.y = m_leakPos.z-pos.z; + dist = Math::Point(rot.x, rot.y).Length(); + rot.x /= dist; + rot.y /= dist; + + a = m_object->RetAngleY(0); + g = Math::RotateAngle(rot.x, -rot.y); // CW ! + a = Math::Direction(a, g)*1.0f; + cirSpeed = a; + if ( cirSpeed > 1.0f ) cirSpeed = 1.0f; + if ( cirSpeed < -1.0f ) cirSpeed = -1.0f; + + a = Math::NormAngle(a); + if ( a > Math::PI*0.5f && a < Math::PI*1.5f ) + { + linSpeed = 1.0f; // obstacle behind -> advance + cirSpeed = -cirSpeed; + } + else + { + linSpeed = -1.0f; // obstacle in front -> back + } + + if ( m_bLeakRecede ) + { + linSpeed = -1.0f; + cirSpeed = 0.0f; + } + + m_physics->SetMotorSpeedZ(cirSpeed); // turns left / right + m_physics->SetMotorSpeedX(linSpeed); // advance + return true; + } + + if ( m_phase == TGP_BEAMSEARCH ) // search path? + { + if ( m_bmStep == 0 ) + { + // Frees the area around the departure. + BitmapClearCircle(m_object->RetPosition(0), BM_DIM_STEP*1.8f); + } + + pos = m_object->RetPosition(0); + + if ( m_bmFretObject == 0 ) + { + goal = m_goal; + dist = 0.0f; + } + else + { + goal = m_goalObject; + dist = TAKE_DIST+2.0f; + if ( m_bmFretObject->RetType() == OBJECT_BASE ) dist = 12.0f; + } + + ret = BeamSearch(pos, goal, dist); + if ( ret == ERR_OK ) + { +#if 0 + Math::Vector min, max; + min = pos; + max = m_goal; + if ( min.x > max.x ) Math::Swap(min.x, max.x); + if ( min.z > max.z ) Math::Swap(min.z, max.z); + min.x -= 50.0f; + min.z -= 50.0f; + max.x += 50.0f; + max.z += 50.0f; + BitmapDebug(min, max, m_object->RetPosition(0), m_goal); +#endif + if ( m_physics->RetLand() ) m_phase = TGP_BEAMWCOLD; + else m_phase = TGP_BEAMGOTO; + m_bmIndex = 0; + m_bmWatchDogPos = m_object->RetPosition(0); + m_bmWatchDogTime = 0.0f; + } + if ( ret == ERR_GOTO_IMPOSSIBLE || ret == ERR_GOTO_ITER ) + { +#if 0 + Math::Vector min, max; + min = pos; + max = m_goal; + if ( min.x > max.x ) Math::Swap(min.x, max.x); + if ( min.z > max.z ) Math::Swap(min.z, max.z); + min.x -= 50.0f; + min.z -= 50.0f; + max.x += 50.0f; + max.z += 50.0f; + BitmapDebug(min, max, m_object->RetPosition(0), m_goal); +#endif + m_error = ret; + return false; + } + return true; + } + + if ( m_phase == TGP_BEAMWCOLD ) // expects cooled reactor? + { + return true; + } + + if ( m_phase == TGP_BEAMUP ) // off? + { + m_physics->SetMotorSpeedY(1.0f); // up + return true; + } + + if ( m_phase == TGP_BEAMGOTO ) // goto dot list? (?) + { + if ( m_physics->RetCollision() ) // collision? + { + m_physics->SetCollision(false); // there's more + } + + pos = m_object->RetPosition(0); + + if ( m_physics->RetType() == TYPE_FLYING && m_altitude == 0.0f ) + { + if ( m_physics->RetLand() ) + { + m_physics->SetMotorSpeedY(0.0f); + } + else + { + m_physics->SetMotorSpeedY(-1.0f); + } + } + + if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f ) + { + goal = m_bmPoints[m_bmIndex]; + goal.y = pos.y; + h = m_terrain->RetFloorHeight(goal, true, true); + dist = Math::DistanceProjected(pos, goal); + if ( dist != 0.0f ) // anticipates? + { + linSpeed = m_physics->RetLinMotionX(MO_REASPEED); + linSpeed /= m_physics->RetLinMotionX(MO_ADVSPEED); + goal.x = pos.x + (goal.x-pos.x)*linSpeed*20.0f/dist; + goal.z = pos.z + (goal.z-pos.z)*linSpeed*20.0f/dist; + } + goal.y = pos.y; + hh = m_terrain->RetFloorHeight(goal, true, true); + h = Math::Min(h, hh); + linSpeed = 0.0f; + if ( h < m_altitude-1.0f ) + { + linSpeed = 0.2f+((m_altitude-1.0f)-h)*0.1f; // up + if ( linSpeed > 1.0f ) linSpeed = 1.0f; + } + if ( h > m_altitude+1.0f ) + { + linSpeed = -0.2f; // down + } + m_physics->SetMotorSpeedY(linSpeed); + } + + rot.x = m_bmPoints[m_bmIndex].x-pos.x; + rot.y = m_bmPoints[m_bmIndex].z-pos.z; + dist = Math::Point(rot.x, rot.y).Length(); + rot.x /= dist; + rot.y /= dist; + + a = m_object->RetAngleY(0); + g = Math::RotateAngle(rot.x, -rot.y); // CW ! + cirSpeed = Math::Direction(a, g)*2.0f; + if ( cirSpeed > 1.0f ) cirSpeed = 1.0f; + if ( cirSpeed < -1.0f ) cirSpeed = -1.0f; + if ( dist < 4.0f ) cirSpeed *= dist/4.0f; // so close -> turns less + + if ( m_bmIndex == m_bmTotal ) // last point? + { + linSpeed = dist/(m_physics->RetLinStopLength()*1.5f); + if ( linSpeed > 1.0f ) linSpeed = 1.0f; + } + else + { + linSpeed = 1.0f; // dark without stopping + } + + linSpeed *= 1.0f-(1.0f-0.3f)*fabs(cirSpeed); + +//? if ( dist < 20.0f && fabs(cirSpeed) >= 0.5f ) + if ( fabs(cirSpeed) >= 0.2f ) + { + linSpeed = 0.0f; // turns first, then advance + } + + dist = Math::DistanceProjected(pos, m_bmWatchDogPos); + if ( dist < 1.0f && linSpeed != 0.0f ) + { + m_bmWatchDogTime += event.rTime; + } + else + { + m_bmWatchDogTime = 0.0f; + m_bmWatchDogPos = pos; + } + + if ( m_bmWatchDogTime >= 1.0f ) // immobile for a long time? + { + m_physics->SetMotorSpeedX(0.0f); // stops the advance + m_physics->SetMotorSpeedZ(0.0f); // stops the rotation + BeamStart(); // we start all + return true; + } + + m_physics->SetMotorSpeedZ(cirSpeed); // turns left / right + m_physics->SetMotorSpeedX(linSpeed); // advance + return true; + } + + if ( m_phase == TGP_BEAMDOWN ) // landed? + { + m_physics->SetMotorSpeedY(-0.5f); // tomb + return true; + } + + if ( m_phase == TGP_LAND ) // landed? + { + m_physics->SetMotorSpeedY(-0.5f); // tomb + return true; + } + + if ( m_goalMode == TGG_EXPRESS ) + { + if ( m_crashMode == TGC_HALT ) + { + if ( m_physics->RetCollision() ) // collision? + { + m_physics->SetCollision(false); // there's more + m_error = ERR_STOP; + return true; + } + } + + pos = m_object->RetPosition(0); + + if ( m_altitude > 0.0f ) + { + h = m_terrain->RetFloorHeight(pos, true, true); + linSpeed = 0.0f; + if ( h < m_altitude ) + { + linSpeed = 0.1f; // up + } + if ( h > m_altitude ) + { + linSpeed = -0.2f; // down + } + m_physics->SetMotorSpeedY(linSpeed); + } + + rot.x = m_goal.x-pos.x; + rot.y = m_goal.z-pos.z; + a = m_object->RetAngleY(0); + g = Math::RotateAngle(rot.x, -rot.y); // CW ! + cirSpeed = Math::Direction(a, g)*1.0f; + if ( cirSpeed > 1.0f ) cirSpeed = 1.0f; + if ( cirSpeed < -1.0f ) cirSpeed = -1.0f; + + m_physics->SetMotorSpeedZ(cirSpeed); // turns left / right + m_physics->SetMotorSpeedX(1.0f); // advance + return true; + } + + if ( m_phase != TGP_TURN && + m_physics->RetType() == TYPE_FLYING && + m_altitude > 0.0f ) + { + pos = m_object->RetPosition(0); + dist = Math::DistanceProjected(m_goal, pos); + factor = (dist-20.0f)/20.0f; + if ( factor < 0.0f ) factor = 0.0f; + if ( factor > 1.0f ) factor = 1.0f; + + h = m_terrain->RetFloorHeight(m_object->RetPosition(0), true, true); + linSpeed = 0.0f; + if ( h < (m_altitude-0.5f)*factor && factor == 1.0f ) + { + linSpeed = 0.1f; // up + } + if ( h > m_altitude*factor ) + { + linSpeed = -0.2f; // down + } + ComputeFlyingRepulse(dir); + linSpeed += dir*0.2f; + + m_physics->SetMotorSpeedY(linSpeed); + } + + if ( m_phase == TGP_ADVANCE ) // going towards the goal? + { + if ( m_physics->RetCollision() ) // collision? + { + m_physics->SetCollision(false); // there's more + m_time = 0.0f; + m_phase = TGP_CRWAIT; + return true; + } + +#if 0 + pos = m_object->RetPosition(0); + a = m_object->RetAngleY(0); + g = Math::RotateAngle(m_goal.x-pos.x, pos.z-m_goal.z); // CW ! + cirSpeed = Math::Direction(a, g)*1.0f; + if ( cirSpeed > 1.0f ) cirSpeed = 1.0f; + if ( cirSpeed < -1.0f ) cirSpeed = -1.0f; + + dist = Math::DistanceProjected(m_goal, pos); + linSpeed = dist/(m_physics->RetLinStopLength()*1.5f); + if ( linSpeed > 1.0f ) linSpeed = 1.0f; + + if ( dist < 20.0f && fabs(cirSpeed) >= 0.5f ) + { + linSpeed = 0.0f; // turns first, then advance + } +#else + pos = m_object->RetPosition(0); + + rot.x = m_goal.x-pos.x; + rot.y = m_goal.z-pos.z; + dist = Math::Point(rot.x, rot.y).Length(); + rot.x /= dist; + rot.y /= dist; + + ComputeRepulse(repulse); + rot.x += repulse.x*2.0f; + rot.y += repulse.y*2.0f; + + a = m_object->RetAngleY(0); + g = Math::RotateAngle(rot.x, -rot.y); // CW ! + cirSpeed = Math::Direction(a, g)*1.0f; +//? if ( m_physics->RetType() == TYPE_FLYING && +//? m_physics->RetLand() ) // flying on the ground? +//? { +//? cirSpeed *= 4.0f; // more fishing +//? } + if ( cirSpeed > 1.0f ) cirSpeed = 1.0f; + if ( cirSpeed < -1.0f ) cirSpeed = -1.0f; + + dist = Math::DistanceProjected(m_goal, pos); + linSpeed = dist/(m_physics->RetLinStopLength()*1.5f); +//? if ( m_physics->RetType() == TYPE_FLYING && +//? m_physics->RetLand() ) // flying on the ground? +//? { +//? linSpeed *= 8.0f; // more fishing +//? } + if ( linSpeed > 1.0f ) linSpeed = 1.0f; + + linSpeed *= 1.0f-(1.0f-0.3f)*fabs(cirSpeed); + + if ( dist < 20.0f && fabs(cirSpeed) >= 0.5f ) + { + linSpeed = 0.0f; // turns first, then advance + } +#endif + + m_physics->SetMotorSpeedZ(cirSpeed); // turns left / right + m_physics->SetMotorSpeedX(linSpeed); // advance + } + + if ( m_phase == TGP_TURN || // turns to the object? + m_phase == TGP_CRTURN || // turns after collision? + m_phase == TGP_CLTURN ) // turns after collision? + { + a = m_object->RetAngleY(0); + g = m_angle; + cirSpeed = Math::Direction(a, g)*1.0f; + if ( cirSpeed > 1.0f ) cirSpeed = 1.0f; + if ( cirSpeed < -1.0f ) cirSpeed = -1.0f; + + m_physics->SetMotorSpeedZ(cirSpeed); // turns left / right + } + + if ( m_phase == TGP_CRWAIT || // waits after collision? + m_phase == TGP_CLWAIT ) // waits after collision? + { + m_time += event.rTime; + m_physics->SetMotorSpeedX(0.0f); // stops the advance + m_physics->SetMotorSpeedZ(0.0f); // stops the rotation + } + + if ( m_phase == TGP_CRADVANCE ) // advance after collision? + { + if ( m_physics->RetCollision() ) // collision? + { + m_physics->SetCollision(false); // there's more + m_time = 0.0f; + m_phase = TGP_CLWAIT; + return true; + } + m_physics->SetMotorSpeedX(0.5f); // advance mollo + } + + if ( m_phase == TGP_CLADVANCE ) // advance after collision? + { + if ( m_physics->RetCollision() ) // collision? + { + m_physics->SetCollision(false); // there's more + m_time = 0.0f; + m_phase = TGP_CRWAIT; + return true; + } + m_physics->SetMotorSpeedX(0.5f); // advance mollo + } + + if ( m_phase == TGP_MOVE ) // final advance? + { + m_bmTimeLimit -= event.rTime; + m_physics->SetMotorSpeedX(1.0f); + } + + return true; +} + + +// Sought a target for the worm. + +CObject* CTaskGoto::WormSearch(Math::Vector &impact) +{ + CObject* pObj; + CObject* pBest = 0; + Math::Vector iPos, oPos; + ObjectType oType; + float distance, min, radius; + int i; + + iPos = m_object->RetPosition(0); + min = 1000000.0f; + + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + oType = pObj->RetType(); + if ( oType != OBJECT_MOBILEfa && + oType != OBJECT_MOBILEta && + oType != OBJECT_MOBILEwa && + oType != OBJECT_MOBILEia && + oType != OBJECT_MOBILEfc && + oType != OBJECT_MOBILEtc && + oType != OBJECT_MOBILEwc && + oType != OBJECT_MOBILEic && + oType != OBJECT_MOBILEfi && + oType != OBJECT_MOBILEti && + oType != OBJECT_MOBILEwi && + oType != OBJECT_MOBILEii && + oType != OBJECT_MOBILEfs && + oType != OBJECT_MOBILEts && + oType != OBJECT_MOBILEws && + oType != OBJECT_MOBILEis && + oType != OBJECT_MOBILErt && + oType != OBJECT_MOBILErc && + oType != OBJECT_MOBILErr && + oType != OBJECT_MOBILErs && + oType != OBJECT_MOBILEsa && + oType != OBJECT_MOBILEtg && + oType != OBJECT_MOBILEft && + oType != OBJECT_MOBILEtt && + oType != OBJECT_MOBILEwt && + oType != OBJECT_MOBILEit && + oType != OBJECT_MOBILEdr && + oType != OBJECT_DERRICK && + oType != OBJECT_STATION && + oType != OBJECT_FACTORY && + oType != OBJECT_REPAIR && + oType != OBJECT_DESTROYER && + oType != OBJECT_CONVERT && + oType != OBJECT_TOWER && + oType != OBJECT_RESEARCH && + oType != OBJECT_RADAR && + oType != OBJECT_INFO && + oType != OBJECT_ENERGY && + oType != OBJECT_LABO && + oType != OBJECT_NUCLEAR && + oType != OBJECT_PARA && + oType != OBJECT_SAFE && + oType != OBJECT_HUSTON ) continue; + + if ( pObj->RetVirusMode() ) continue; // object infected? + + if ( !pObj->GetCrashSphere(0, oPos, radius) ) continue; + distance = Math::DistanceProjected(oPos, iPos); + if ( distance < min ) + { + min = distance; + pBest = pObj; + } + } + if ( pBest == 0 ) return 0; + + impact = pBest->RetPosition(0); + return pBest; +} + +// Contaminate objects near the worm. + +void CTaskGoto::WormFrame(float rTime) +{ + CObject* pObj; + Math::Vector impact, pos; + float dist; + + m_wormLastTime += rTime; + + if ( m_wormLastTime >= 0.5f ) + { + m_wormLastTime = 0.0f; + + pObj = WormSearch(impact); + if ( pObj != 0 ) + { + pos = m_object->RetPosition(0); + dist = Math::Distance(pos, impact); + if ( dist <= 15.0f ) + { + pObj->SetVirusMode(true); // bam, infected! + } + } + } +} + + + +// Assigns the goal was achieved. +// "dist" is the distance that needs to go far to make a deposit or object. + +Error CTaskGoto::Start(Math::Vector goal, float altitude, + TaskGotoGoal goalMode, TaskGotoCrash crashMode) +{ + Math::Vector pos; + CObject* target; + ObjectType type; + float dist; + int x, y; + + type = m_object->RetType(); + + if ( goalMode == TGG_DEFAULT ) + { + goalMode = TGG_STOP; + if ( type == OBJECT_MOTHER || + type == OBJECT_ANT || + type == OBJECT_SPIDER || + type == OBJECT_WORM ) + { + goalMode = TGG_EXPRESS; + } + } + + if ( crashMode == TGC_DEFAULT ) + { +//? crashMode = TGC_RIGHTLEFT; + crashMode = TGC_BEAM; + if ( type == OBJECT_MOTHER || + type == OBJECT_ANT || + type == OBJECT_SPIDER || + type == OBJECT_WORM || + type == OBJECT_BEE ) + { + crashMode = TGC_HALT; + } + } + + m_altitude = altitude; + m_goalMode = goalMode; + m_crashMode = crashMode; + m_goalObject = goal; + m_goal = goal; + + m_bTake = false; + m_phase = TGP_ADVANCE; + m_error = ERR_OK; + m_try = 0; + m_bmFretObject = 0; + m_bmFinalMove = 0.0f; + + pos = m_object->RetPosition(0); + dist = Math::DistanceProjected(pos, m_goal); + if ( dist < 10.0f && m_crashMode == TGC_BEAM ) + { + m_crashMode = TGC_RIGHTLEFT; + } + + m_bWorm = false; + if ( type == OBJECT_WORM ) + { + m_bWorm = true; + m_wormLastTime = 0.0f; + } + + m_bApprox = false; + if ( type == OBJECT_HUMAN || + type == OBJECT_TECH || + type == OBJECT_MOTHER || + type == OBJECT_ANT || + type == OBJECT_SPIDER || + type == OBJECT_BEE || + type == OBJECT_WORM || + type == OBJECT_MOBILErt || + type == OBJECT_MOBILErc || + type == OBJECT_MOBILErr || + type == OBJECT_MOBILErs ) + { + m_bApprox = true; + } + + if ( !m_bApprox && m_crashMode != TGC_BEAM ) + { + target = SearchTarget(goal, 1.0f); + if ( target != 0 ) + { + m_goal = target->RetPosition(0); + dist = 0.0f; + if ( !AdjustBuilding(m_goal, 1.0f, dist) ) + { + dist = 0.0f; + AdjustTarget(target, m_goal, dist); + } + m_bTake = true; // object was taken on arrival (final rotation) + } + } + + m_lastDistance = 1000.0f; + m_physics->SetCollision(false); + + if ( m_crashMode == TGC_BEAM ) // with the algorithm of rays? + { + target = SearchTarget(goal, 1.0f); + if ( target != 0 ) + { + m_goal = target->RetPosition(0); + dist = 4.0f; + if ( AdjustBuilding(m_goal, 1.0f, dist) ) + { + m_bmFinalMove = dist; + } + else + { + dist = 4.0f; + if ( AdjustTarget(target, m_goal, dist) ) + { + m_bmFretObject = target; // cargo on the ground + } + else + { + m_bmFinalMove = dist; + } + } + m_bTake = true; // object was taken on arrival (final rotation) + } + + if ( m_physics->RetType() == TYPE_FLYING && m_altitude == 0.0f ) + { + pos = m_object->RetPosition(0); + dist = Math::DistanceProjected(pos, m_goal); + if ( dist > FLY_DIST_GROUND ) // over 20 meters? + { + m_altitude = FLY_DEF_HEIGHT; // default altitude + } + } + + BeamStart(); + + if ( m_bmFretObject == 0 ) + { + x = (int)((m_goal.x+1600.0f)/BM_DIM_STEP); + y = (int)((m_goal.z+1600.0f)/BM_DIM_STEP); + if ( BitmapTestDot(0, x, y) ) // arrival occupied? + { +#if 0 + Math::Vector min, max; + min = m_object->RetPosition(0); + max = m_goal; + if ( min.x > max.x ) Math::Swap(min.x, max.x); + if ( min.z > max.z ) Math::Swap(min.z, max.z); + min.x -= 50.0f; + min.z -= 50.0f; + max.x += 50.0f; + max.z += 50.0f; + BitmapDebug(min, max, m_object->RetPosition(0), m_goal); +#endif + m_error = ERR_GOTO_BUSY; + return m_error; + } + } + } + + return ERR_OK; +} + +// Indicates whether the action is finished. + +Error CTaskGoto::IsEnded() +{ + Math::Vector pos; + float limit, angle, dist, h, level; + + if ( m_engine->RetPause() ) return ERR_CONTINUE; + if ( m_error != ERR_OK ) return m_error; + + pos = m_object->RetPosition(0); + + if ( m_phase == TGP_BEAMLEAK ) // leak? + { + if ( m_leakTime >= m_leakDelay ) + { + m_physics->SetMotorSpeedX(0.0f); // stops the advance + m_physics->SetMotorSpeedZ(0.0f); // stops the rotation + BeamInit(); + m_phase = TGP_BEAMSEARCH; // will seek the path + } + return ERR_CONTINUE; + } + + if ( m_phase == TGP_BEAMSEARCH ) // search path? + { + return ERR_CONTINUE; + } + + if ( m_phase == TGP_BEAMWCOLD ) // expects cool reactor? + { + if ( m_altitude != 0.0f && + m_physics->RetReactorRange() < 1.0f ) return ERR_CONTINUE; + m_phase = TGP_BEAMUP; + } + + if ( m_phase == TGP_BEAMUP ) // off? + { + if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f ) + { + level = m_terrain->RetFloorLevel(pos, true, true); + h = level+m_altitude-20.0f; + limit = m_terrain->RetFlyingMaxHeight(); + if ( h > limit ) h = limit; + if ( pos.y < h-1.0f ) return ERR_CONTINUE; + + m_physics->SetMotorSpeedY(0.0f); // stops the ascent + } + m_phase = TGP_BEAMGOTO; + } + + if ( m_phase == TGP_BEAMGOTO ) // goto dot list ? + { + if ( m_altitude != 0.0f && + m_physics->RetReactorRange() < 0.1f ) // overheating? + { + m_physics->SetMotorSpeedX(0.0f); // stops the advance + m_physics->SetMotorSpeedZ(0.0f); // stops the rotation + m_physics->SetMotorSpeedY(-1.0f); // tomb + m_phase = TGP_BEAMWCOLD; + return ERR_CONTINUE; + } + + if ( m_physics->RetLand() ) // on the ground? + { + limit = 1.0f; + } + else // in flight? + { + limit = 2.0f; + if ( m_bmIndex < m_bmTotal ) limit *= 2.0f; // intermediate point + } + if ( m_bApprox ) limit = 2.0f; + + if ( fabs(pos.x - m_bmPoints[m_bmIndex].x) < limit && + fabs(pos.z - m_bmPoints[m_bmIndex].z) < limit ) + { + m_physics->SetMotorSpeedX(0.0f); // stops the advance + m_physics->SetMotorSpeedZ(0.0f); // stops the rotation + + m_bmIndex = BeamShortcut(); + + if ( m_bmIndex > m_bmTotal ) + { + m_phase = TGP_BEAMDOWN; + } + } + } + + if ( m_phase == TGP_BEAMDOWN ) // landed? + { + if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f ) + { + if ( !m_physics->RetLand() ) return ERR_CONTINUE; + m_physics->SetMotorSpeedY(0.0f); // stops the descent + + m_altitude = 0.0f; + m_phase = TGP_BEAMGOTO; // advance finely on the ground to finish + m_bmIndex = m_bmTotal; + return ERR_CONTINUE; + } + + if ( m_bTake ) + { + m_angle = Math::RotateAngle(m_goalObject.x-pos.x, pos.z-m_goalObject.z); + m_phase = TGP_TURN; + } + else + { + m_physics->SetMotorSpeedX(0.0f); // stops the advance + m_physics->SetMotorSpeedZ(0.0f); // stops the rotation + return ERR_STOP; + } + } + + if ( m_goalMode == TGG_EXPRESS ) + { + dist = Math::DistanceProjected(m_goal, pos); + if ( dist < 10.0f && dist > m_lastDistance ) + { + return ERR_STOP; + } + m_lastDistance = dist; + } + + if ( m_phase == TGP_ADVANCE ) // going towards the goal? + { + if ( m_physics->RetLand() ) limit = 0.1f; // on the ground + else limit = 1.0f; // flying + if ( m_bApprox ) limit = 2.0f; + + if ( fabs(pos.x - m_goal.x) < limit && + fabs(pos.z - m_goal.z) < limit ) + { + m_physics->SetMotorSpeedX(0.0f); // stops the advance + m_physics->SetMotorSpeedZ(0.0f); // stops the rotation + m_phase = TGP_LAND; + } + } + + if ( m_phase == TGP_LAND ) // landed? + { + if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f ) + { + if ( !m_physics->RetLand() ) return ERR_CONTINUE; + m_physics->SetMotorSpeedY(0.0f); + } + + if ( m_bTake ) + { + m_angle = Math::RotateAngle(m_goalObject.x-pos.x, pos.z-m_goalObject.z); + m_phase = TGP_TURN; + } + else + { + return ERR_STOP; + } + } + + if ( m_phase == TGP_TURN ) // turns to the object? + { + angle = Math::NormAngle(m_object->RetAngleY(0)); + limit = 0.02f; + if ( m_bApprox ) limit = 0.10f; + if ( fabs(angle-m_angle) < limit ) + { + m_physics->SetMotorSpeedZ(0.0f); // stops the rotation + if ( m_bmFinalMove == 0.0f ) return ERR_STOP; + + m_bmFinalPos = m_object->RetPosition(0); + m_bmFinalDist = m_physics->RetLinLength(m_bmFinalMove); + m_bmTimeLimit = m_physics->RetLinTimeLength(fabs(m_bmFinalMove))*1.5f; + if ( m_bmTimeLimit < 0.5f ) m_bmTimeLimit = 0.5f; + m_phase = TGP_MOVE; + } + } + + if ( m_phase == TGP_CRWAIT ) // waits after collision? + { + if ( m_crashMode == TGC_HALT ) + { + m_physics->SetMotorSpeedX(0.0f); // stops the advance + m_physics->SetMotorSpeedZ(0.0f); // stops the rotation + m_error = ERR_GENERIC; + return m_error; + } + if ( m_time >= 1.0f ) + { + if ( m_crashMode == TGC_RIGHTLEFT || + m_crashMode == TGC_RIGHT ) angle = Math::PI/2.0f; // 90 deegres to the right + else angle = -Math::PI/2.0f; // 90 deegres to the left + m_angle = Math::NormAngle(m_object->RetAngleY(0)+angle); + m_phase = TGP_CRTURN; +//? m_phase = TGP_ADVANCE; + } + } + + if ( m_phase == TGP_CRTURN ) // turns after collision? + { + angle = Math::NormAngle(m_object->RetAngleY(0)); + limit = 0.1f; + if ( fabs(angle-m_angle) < limit ) + { + m_physics->SetMotorSpeedZ(0.0f); // stops the rotation + m_pos = pos; + m_phase = TGP_CRADVANCE; + } + } + + if ( m_phase == TGP_CRADVANCE ) // advance after collision? + { + if ( Math::Distance(pos, m_pos) >= 5.0f ) + { + m_phase = TGP_ADVANCE; + } + } + + if ( m_phase == TGP_CLWAIT ) // waits after collision? + { + if ( m_time >= 1.0f ) + { + if ( m_crashMode == TGC_RIGHTLEFT ) angle = -Math::PI; + if ( m_crashMode == TGC_LEFTRIGHT ) angle = Math::PI; + if ( m_crashMode == TGC_RIGHT ) angle = Math::PI/2.0f; + if ( m_crashMode == TGC_LEFT ) angle = -Math::PI/2.0f; + m_angle = Math::NormAngle(m_object->RetAngleY(0)+angle); + m_phase = TGP_CLTURN; + } + } + + if ( m_phase == TGP_CLTURN ) // turns after collision? + { + angle = Math::NormAngle(m_object->RetAngleY(0)); + limit = 0.1f; + if ( fabs(angle-m_angle) < limit ) + { + m_physics->SetMotorSpeedZ(0.0f); // stops the rotation + m_pos = pos; + m_phase = TGP_CLADVANCE; + } + } + + if ( m_phase == TGP_CLADVANCE ) // advance after collision? + { + if ( Math::Distance(pos, m_pos) >= 10.0f ) + { + m_phase = TGP_ADVANCE; + m_try ++; + } + } + + if ( m_phase == TGP_MOVE ) // final advance? + { + if ( m_bmTimeLimit <= 0.0f ) + { + m_physics->SetMotorSpeedX(0.0f); // stops + Abort(); + return ERR_STOP; + } + + dist = Math::Distance(m_bmFinalPos, m_object->RetPosition(0)); + if ( dist < m_bmFinalDist ) return ERR_CONTINUE; + m_physics->SetMotorSpeedX(0.0f); // stops the advance + return ERR_STOP; + } + + return ERR_CONTINUE; +} + + +// Tries the object is the target position. + +CObject* CTaskGoto::SearchTarget(Math::Vector pos, float margin) +{ + CObject *pObj, *pBest; + Math::Vector oPos; + float dist, min; + int i; + + pBest = 0; + min = 1000000.0f; + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + if ( !pObj->RetActif() ) continue; + if ( pObj->RetTruck() != 0 ) continue; // object transtorted? + + oPos = pObj->RetPosition(0); + dist = Math::DistanceProjected(pos, oPos); + + if ( dist <= margin && dist <= min ) + { + min = dist; + pBest = pObj; + } + } + + return pBest; +} + +// Adjusts the target as a function of the object. +// Returns true if it is cargo laying on the ground, which can be approached from any site. + +bool CTaskGoto::AdjustTarget(CObject* pObj, Math::Vector &pos, float &distance) +{ + ObjectType type; + Character* character; + Math::Matrix* mat; + Math::Vector goal; + float dist, suppl; + + type = m_object->RetType(); + if ( type == OBJECT_BEE || + type == OBJECT_WORM ) + { + pos = pObj->RetPosition(0); + return false; // single approach + } + + type = pObj->RetType(); + + if ( type == OBJECT_FRET || + type == OBJECT_STONE || + type == OBJECT_URANIUM || + type == OBJECT_METAL || + type == OBJECT_POWER || + type == OBJECT_ATOMIC || + type == OBJECT_BULLET || + type == OBJECT_BBOX || + type == OBJECT_KEYa || + type == OBJECT_KEYb || + type == OBJECT_KEYc || + type == OBJECT_KEYd || + type == OBJECT_TNT || + type == OBJECT_SCRAP1 || + type == OBJECT_SCRAP2 || + type == OBJECT_SCRAP3 || + type == OBJECT_SCRAP4 || + type == OBJECT_SCRAP5 || + type == OBJECT_BOMB || + type == OBJECT_RUINmobilew1 || + type == OBJECT_RUINmobilew2 || + type == OBJECT_RUINmobilet1 || + type == OBJECT_RUINmobilet2 || + type == OBJECT_RUINmobiler1 || + type == OBJECT_RUINmobiler2 ) + { + pos = m_object->RetPosition(0); + goal = pObj->RetPosition(0); + dist = Math::Distance(goal, pos); + pos = (pos-goal)*(TAKE_DIST+distance)/dist + goal; + return true; // approach from all sites + } + + if ( type == OBJECT_BASE ) + { + pos = m_object->RetPosition(0); + goal = pObj->RetPosition(0); + dist = Math::Distance(goal, pos); + pos = (pos-goal)*(TAKE_DIST+distance)/dist + goal; + return true; // approach from all sites + } + + if ( type == OBJECT_MOBILEfa || + type == OBJECT_MOBILEta || + type == OBJECT_MOBILEwa || + type == OBJECT_MOBILEia || + type == OBJECT_MOBILEfs || + type == OBJECT_MOBILEts || + type == OBJECT_MOBILEws || + type == OBJECT_MOBILEis || + type == OBJECT_MOBILEfc || + type == OBJECT_MOBILEtc || + type == OBJECT_MOBILEwc || + type == OBJECT_MOBILEic || + type == OBJECT_MOBILEfi || + type == OBJECT_MOBILEti || + type == OBJECT_MOBILEwi || + type == OBJECT_MOBILEii || + type == OBJECT_MOBILErt || + type == OBJECT_MOBILErc || + type == OBJECT_MOBILErr || + type == OBJECT_MOBILErs || + type == OBJECT_MOBILEsa || + type == OBJECT_MOBILEtg || + type == OBJECT_MOBILEft || + type == OBJECT_MOBILEtt || + type == OBJECT_MOBILEwt || + type == OBJECT_MOBILEit || + type == OBJECT_MOBILEdr ) + { + character = pObj->RetCharacter(); + pos = character->posPower; + pos.x -= TAKE_DIST+TAKE_DIST_OTHER+distance; + mat = pObj->RetWorldMatrix(0); + pos = Transform(*mat, pos); + return false; // single approach + } + + if ( GetHotPoint(pObj, goal, true, distance, suppl) ) + { + pos = goal; + distance += suppl; + return false; // single approach + } + + pos = pObj->RetPosition(0); + distance = 0.0f; + return false; // single approach +} + +// If you are on an object produced by a building (ore produced by derrick), +// changes the position by report the building. + +bool CTaskGoto::AdjustBuilding(Math::Vector &pos, float margin, float &distance) +{ + CObject* pObj; + Math::Vector oPos; + float dist, suppl; + int i; + + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + if ( !pObj->RetActif() ) continue; + if ( pObj->RetTruck() != 0 ) continue; // object transported? + + if ( !GetHotPoint(pObj, oPos, false, 0.0f, suppl) ) continue; + dist = Math::DistanceProjected(pos, oPos); + if ( dist <= margin ) + { + GetHotPoint(pObj, pos, true, distance, suppl); + distance += suppl; + return true; + } + } + return false; +} + +// Returns the item or product or pose is something on a building. + +bool CTaskGoto::GetHotPoint(CObject *pObj, Math::Vector &pos, + bool bTake, float distance, float &suppl) +{ + ObjectType type; + Math::Matrix* mat; + + pos = Math::Vector(0.0f, 0.0f, 0.0f); + suppl = 0.0f; + type = pObj->RetType(); + + if ( type == OBJECT_DERRICK ) + { + mat = pObj->RetWorldMatrix(0); + pos.x += 8.0f; + if ( bTake && distance != 0.0f ) suppl = 4.0f; + if ( bTake ) pos.x += TAKE_DIST+distance+suppl; + pos = Transform(*mat, pos); + return true; + } + + if ( type == OBJECT_CONVERT ) + { + mat = pObj->RetWorldMatrix(0); + pos.x += 0.0f; + if ( bTake && distance != 0.0f ) suppl = 4.0f; + if ( bTake ) pos.x += TAKE_DIST+distance+suppl; + pos = Transform(*mat, pos); + return true; + } + + if ( type == OBJECT_RESEARCH ) + { + mat = pObj->RetWorldMatrix(0); + pos.x += 10.0f; + if ( bTake && distance != 0.0f ) suppl = 2.5f; + if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance+suppl; + pos = Transform(*mat, pos); + return true; + } + + if ( type == OBJECT_ENERGY ) + { + mat = pObj->RetWorldMatrix(0); + pos.x += 6.0f; + if ( bTake && distance != 0.0f ) suppl = 6.0f; + if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance; + pos = Transform(*mat, pos); + return true; + } + + if ( type == OBJECT_TOWER ) + { + mat = pObj->RetWorldMatrix(0); + pos.x += 5.0f; + if ( bTake && distance != 0.0f ) suppl = 4.0f; + if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance+suppl; + pos = Transform(*mat, pos); + return true; + } + + if ( type == OBJECT_LABO ) + { + mat = pObj->RetWorldMatrix(0); + pos.x += 6.0f; + if ( bTake && distance != 0.0f ) suppl = 6.0f; + if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance; + pos = Transform(*mat, pos); + return true; + } + + if ( type == OBJECT_NUCLEAR ) + { + mat = pObj->RetWorldMatrix(0); + pos.x += 22.0f; + if ( bTake && distance != 0.0f ) suppl = 4.0f; + if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance+suppl; + pos = Transform(*mat, pos); + return true; + } + + if ( type == OBJECT_FACTORY ) + { + mat = pObj->RetWorldMatrix(0); + pos.x += 4.0f; + if ( bTake && distance != 0.0f ) suppl = 6.0f; + if ( bTake ) pos.x += TAKE_DIST+distance+suppl; + pos = Transform(*mat, pos); + return true; + } + + if ( type == OBJECT_STATION ) + { + mat = pObj->RetWorldMatrix(0); + pos.x += 4.0f; + if ( bTake && distance != 0.0f ) suppl = 4.0f; + if ( bTake ) pos.x += distance; + pos = Transform(*mat, pos); + return true; + } + + if ( type == OBJECT_REPAIR ) + { + mat = pObj->RetWorldMatrix(0); + pos.x += 4.0f; + if ( bTake && distance != 0.0f ) suppl = 4.0f; + if ( bTake ) pos.x += distance; + pos = Transform(*mat, pos); + return true; + } + + if ( type == OBJECT_DESTROYER ) + { + mat = pObj->RetWorldMatrix(0); + pos.x += 0.0f; + if ( bTake && distance != 0.0f ) suppl = 4.0f; + if ( bTake ) pos.x += TAKE_DIST+distance+suppl; + pos = Transform(*mat, pos); + return true; + } + + if ( type == OBJECT_PARA && m_physics->RetType() == TYPE_FLYING ) + { + mat = pObj->RetWorldMatrix(0); + if ( bTake && distance != 0.0f ) suppl = 20.0f; + if ( bTake ) pos.x += distance+suppl; + pos = Transform(*mat, pos); + return true; + } + + suppl = 0.0f; + return false; +} + + +// Seeks an object too close that he must flee. + +bool CTaskGoto::LeakSearch(Math::Vector &pos, float &delay) +{ + CObject *pObj, *pObstacle; + Math::Vector iPos, oPos, bPos; + float iRadius, oRadius, bRadius, dist, min, dir; + int i, j; + + if ( !m_physics->RetLand() ) return false; // in flight? + + m_object->GetCrashSphere(0, iPos, iRadius); + + min = 100000.0f; + bRadius = 0.0f; + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + if ( pObj == m_object ) continue; + if ( !pObj->RetActif() ) continue; + if ( pObj->RetTruck() != 0 ) continue; // object transported? + + j = 0; + while ( pObj->GetCrashSphere(j++, oPos, oRadius) ) + { + dist = Math::DistanceProjected(oPos, iPos); + if ( dist < min ) + { + min = dist; + bPos = oPos; + bRadius = oRadius; + pObstacle = pObj; + } + } + } + if ( min > iRadius+bRadius+4.0f ) return false; + + m_bLeakRecede = false; + + dist = 4.0f; + dir = 1.0f; + if ( pObstacle->RetType() == OBJECT_FACTORY ) + { + dist = 16.0f; + dir = -1.0f; + m_bLeakRecede = true; // simply recoils + } + + pos = bPos; + delay = m_physics->RetLinTimeLength(dist, dir); + return true; +} + + +// Calculates the force of repulsion due to obstacles. +// The vector length rendered is between 0 and 1. + +void CTaskGoto::ComputeRepulse(Math::Point &dir) +{ +#if 0 + Math::Vector iPos, oPos; + Math::Point repulse; + CObject *pObj; + float dist, iRadius, oRadius; + int i; + + dir.x = 0.0f; + dir.y = 0.0f; + + m_object->GetCrashSphere(0, iPos, iRadius); + + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + if ( pObj == m_object ) continue; + if ( pObj->RetTruck() != 0 ) continue; + + oPos = pObj->RetPosition(0); + dist = Math::Distance(oPos, m_goalObject); + if ( dist <= 1.0f ) continue; + + pObj->GetGlobalSphere(oPos, oRadius); + oRadius += iRadius+m_physics->RetLinStopLength()*1.1f; + dist = Math::DistanceProjected(oPos, iPos); + if ( dist <= oRadius ) + { + repulse.x = iPos.x-oPos.x; + repulse.y = iPos.z-oPos.z; + +//? dist = 0.2f-(0.2f*dist/oRadius); + dist = powf(dist/oRadius, 2.0f); + dist = 0.2f-0.2f*dist; + repulse.x *= dist; + repulse.y *= dist; +//? repulse.x /= dist; +//? repulse.y /= dist; + + dir.x += repulse.x; + dir.y += repulse.y; + } + } +#else + ObjectType iType, oType; + Math::Vector iPos, oPos; + Math::Point repulse; + CObject *pObj; + float gDist, add, addi, fac, dist, iRadius, oRadius; + int i, j; + bool bAlien; + + dir.x = 0.0f; + dir.y = 0.0f; + + // The worm goes everywhere and through everything! + iType = m_object->RetType(); + if ( iType == OBJECT_WORM ) return; + + m_object->GetCrashSphere(0, iPos, iRadius); + gDist = Math::Distance(iPos, m_goal); + + add = m_physics->RetLinStopLength()*1.1f; // braking distance + fac = 2.0f; + + if ( iType == OBJECT_MOBILEwa || + iType == OBJECT_MOBILEwc || + iType == OBJECT_MOBILEwi || + iType == OBJECT_MOBILEws || + iType == OBJECT_MOBILEwt ) // wheels? + { + add = 5.0f; + fac = 1.5f; + } + if ( iType == OBJECT_MOBILEta || + iType == OBJECT_MOBILEtc || + iType == OBJECT_MOBILEti || + iType == OBJECT_MOBILEts || + iType == OBJECT_MOBILEtt || + iType == OBJECT_MOBILEdr ) // caterpillars? + { + add = 4.0f; + fac = 1.5f; + } + if ( iType == OBJECT_MOBILEfa || + iType == OBJECT_MOBILEfc || + iType == OBJECT_MOBILEfi || + iType == OBJECT_MOBILEfs || + iType == OBJECT_MOBILEft ) // flying? + { + if ( m_physics->RetLand() ) + { + add = 5.0f; + fac = 1.5f; + } + else + { + add = 10.0f; + fac = 1.5f; + } + } + if ( iType == OBJECT_MOBILEia || + iType == OBJECT_MOBILEic || + iType == OBJECT_MOBILEii || + iType == OBJECT_MOBILEis || + iType == OBJECT_MOBILEit ) // legs? + { + add = 4.0f; + fac = 1.5f; + } + if ( iType == OBJECT_BEE ) // wasp? + { + if ( m_physics->RetLand() ) + { + add = 3.0f; + fac = 1.5f; + } + else + { + add = 5.0f; + fac = 1.5f; + } + } + + bAlien = false; + if ( iType == OBJECT_MOTHER || + iType == OBJECT_ANT || + iType == OBJECT_SPIDER || + iType == OBJECT_BEE || + iType == OBJECT_WORM ) + { + bAlien = true; + } + + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + if ( pObj == m_object ) continue; + if ( pObj->RetTruck() != 0 ) continue; + + oType = pObj->RetType(); + + if ( oType == OBJECT_WORM ) continue; + + if ( bAlien ) + { + if ( oType == OBJECT_STONE || + oType == OBJECT_URANIUM || + oType == OBJECT_METAL || + oType == OBJECT_POWER || + oType == OBJECT_ATOMIC || + oType == OBJECT_BULLET || + oType == OBJECT_BBOX || + oType == OBJECT_KEYa || + oType == OBJECT_KEYb || + oType == OBJECT_KEYc || + oType == OBJECT_KEYd || + oType == OBJECT_TNT || + oType == OBJECT_SCRAP1 || + oType == OBJECT_SCRAP2 || + oType == OBJECT_SCRAP3 || + oType == OBJECT_SCRAP4 || + oType == OBJECT_SCRAP5 || + oType == OBJECT_BOMB || + (oType >= OBJECT_PLANT0 && + oType <= OBJECT_PLANT19 ) || + (oType >= OBJECT_MUSHROOM0 && + oType <= OBJECT_MUSHROOM9 ) ) continue; + } + + addi = add; + if ( iType == OBJECT_BEE && + oType == OBJECT_BEE ) + { + addi = 2.0f; // between wasps, do not annoy too much + } + + j = 0; + while ( pObj->GetCrashSphere(j++, oPos, oRadius) ) + { + if ( oPos.y-oRadius > iPos.y+iRadius ) continue; + if ( oPos.y+oRadius < iPos.y-iRadius ) continue; + + dist = Math::Distance(oPos, m_goal); + if ( dist <= 1.0f ) continue; // on purpose? + + oRadius += iRadius+addi; + dist = Math::DistanceProjected(oPos, iPos); + if ( dist > gDist ) continue; // beyond the goal? + if ( dist <= oRadius ) + { + repulse.x = iPos.x-oPos.x; + repulse.y = iPos.z-oPos.z; + + dist = powf(dist/oRadius, fac); + dist = 0.2f-0.2f*dist; + repulse.x *= dist; + repulse.y *= dist; + + dir.x += repulse.x; + dir.y += repulse.y; + } + } + } +#endif +} + +// Calculates the force of vertical repulsion according to barriers. +// The vector length is made​between -1 and 1. + +void CTaskGoto::ComputeFlyingRepulse(float &dir) +{ + ObjectType oType; + Math::Vector iPos, oPos; + CObject *pObj; + float add, fac, dist, iRadius, oRadius, repulse; + int i, j; + + m_object->GetCrashSphere(0, iPos, iRadius); + + add = 0.0f; + fac = 1.5f; + dir = 0.0f; + + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + if ( pObj == m_object ) continue; + if ( pObj->RetTruck() != 0 ) continue; + + oType = pObj->RetType(); + + if ( oType == OBJECT_WORM ) continue; + + j = 0; + while ( pObj->GetCrashSphere(j++, oPos, oRadius) ) + { + oRadius += iRadius+add; + dist = Math::DistanceProjected(oPos, iPos); + if ( dist <= oRadius ) + { + repulse = iPos.y-oPos.y; + + dist = powf(dist/oRadius, fac); + dist = 0.2f-0.2f*dist; + repulse *= dist; + + dir += repulse; + } + } + } + + if ( dir < -1.0f ) dir = -1.0f; + if ( dir > 1.0f ) dir = 1.0f; +} + + + +// Among all of the following, seek if there is one allowing to go directly to the crow flies. +// If yes, skip all the unnecessary intermediate points. + +int CTaskGoto::BeamShortcut() +{ + int i; + + for ( i=m_bmTotal ; i>=m_bmIndex+2 ; i-- ) // tries from the last + { + if ( BitmapTestLine(m_bmPoints[m_bmIndex], m_bmPoints[i], 0.0f, false) ) + { + return i; // bingo, found + } + } + + return m_bmIndex+1; // simply goes to the next +} + +// That's the big start. + +void CTaskGoto::BeamStart() +{ + Math::Vector min, max; + + BitmapOpen(); + BitmapObject(); + + min = m_object->RetPosition(0); + max = m_goal; + if ( min.x > max.x ) Math::Swap(min.x, max.x); + if ( min.z > max.z ) Math::Swap(min.z, max.z); + min.x -= 10.0f*BM_DIM_STEP; + min.z -= 10.0f*BM_DIM_STEP; + max.x += 10.0f*BM_DIM_STEP; + max.z += 10.0f*BM_DIM_STEP; + BitmapTerrain(min, max); + + if ( LeakSearch(m_leakPos, m_leakDelay) ) + { + m_phase = TGP_BEAMLEAK; // must first leak + m_leakTime = 0.0f; + } + else + { + m_physics->SetMotorSpeedX(0.0f); // stops the advance + m_physics->SetMotorSpeedZ(0.0f); // stops the rotation + BeamInit(); + m_phase = TGP_BEAMSEARCH; // will seek the path + } +} + +// Initialization before the first BeamSearch. + +void CTaskGoto::BeamInit() +{ + int i; + + for ( i=0 ; i<MAXPOINTS ; i++ ) + { + m_bmIter[i] = -1; + } + m_bmStep = 0; +} + +// Calculates points and passes to go from start to goal. +// Returns: +// ERR_OK if it's good +// ERR_GOTO_IMPOSSIBLE if impossible +// ERR_GOTO_ITER if aborts because too many recursions +// ERR_CONTINUE if not done yet +// goalRadius: distance at which we must approach the goal + +Error CTaskGoto::BeamSearch(const Math::Vector &start, const Math::Vector &goal, + float goalRadius) +{ + float step, len; + int nbIter; + + m_bmStep ++; + + len = Math::DistanceProjected(start, goal); + step = len/5.0f; + if ( step < BM_DIM_STEP*2.1f ) step = BM_DIM_STEP*2.1f; + if ( step > 20.0f ) step = 20.0f; + nbIter = 200; // in order not to lower the framerate + m_bmIterCounter = 0; + return BeamExplore(start, start, goal, goalRadius, 165.0f*Math::PI/180.0f, 22, step, 0, nbIter); +} + +// prevPos: previous position +// curPos: current position +// goalPos: position that seeks to achieve +// angle: angle to the goal we explores +// nbDiv: number of subdivisions being done with angle +// step length of a step +// i number of recursions made +// nbIter maximum number of iterations you have the right to make before temporarily interrupt + +Error CTaskGoto::BeamExplore(const Math::Vector &prevPos, const Math::Vector &curPos, + const Math::Vector &goalPos, float goalRadius, + float angle, int nbDiv, float step, + int i, int nbIter) +{ + Math::Vector newPos; + Error ret; + int iDiv, iClear, iLar; + + iLar = 0; + if ( i >= MAXPOINTS ) return ERR_GOTO_ITER; // too many recursions + + if ( m_bmIter[i] == -1 ) + { + m_bmIter[i] = 0; + + if ( i == 0 ) + { + m_bmPoints[i] = curPos; + } + else + { + if ( !BitmapTestLine(prevPos, curPos, angle/nbDiv, true) ) return ERR_GOTO_IMPOSSIBLE; + + m_bmPoints[i] = curPos; + + if ( Math::DistanceProjected(curPos, goalPos)-goalRadius <= step ) + { + if ( goalRadius == 0.0f ) + { + newPos = goalPos; + } + else + { + newPos = BeamPoint(curPos, goalPos, 0, Math::DistanceProjected(curPos, goalPos)-goalRadius); + } + if ( BitmapTestLine(curPos, newPos, angle/nbDiv, false) ) + { + m_bmPoints[i+1] = newPos; + m_bmTotal = i+1; + return ERR_OK; + } + } + } + } + + if ( iLar >= m_bmIter[i] ) + { + newPos = BeamPoint(curPos, goalPos, 0, step); + ret = BeamExplore(curPos, newPos, goalPos, goalRadius, angle, nbDiv, step, i+1, nbIter); + if ( ret != ERR_GOTO_IMPOSSIBLE ) return ret; + m_bmIter[i] = iLar+1; + for ( iClear=i+1 ; iClear<=MAXPOINTS ; iClear++ ) m_bmIter[iClear] = -1; + m_bmIterCounter ++; + if ( m_bmIterCounter >= nbIter ) return ERR_CONTINUE; + } + iLar ++; + + for ( iDiv=1 ; iDiv<=nbDiv ; iDiv++ ) + { + if ( iLar >= m_bmIter[i] ) + { + newPos = BeamPoint(curPos, goalPos, angle*iDiv/nbDiv, step); + ret = BeamExplore(curPos, newPos, goalPos, goalRadius, angle, nbDiv, step, i+1, nbIter); + if ( ret != ERR_GOTO_IMPOSSIBLE ) return ret; + m_bmIter[i] = iLar+1; + for ( iClear=i+1 ; iClear<=MAXPOINTS ; iClear++ ) m_bmIter[iClear] = -1; + m_bmIterCounter ++; + if ( m_bmIterCounter >= nbIter ) return ERR_CONTINUE; + } + iLar ++; + + if ( iLar >= m_bmIter[i] ) + { + newPos = BeamPoint(curPos, goalPos, -angle*iDiv/nbDiv, step); + ret = BeamExplore(curPos, newPos, goalPos, goalRadius, angle, nbDiv, step, i+1, nbIter); + if ( ret != ERR_GOTO_IMPOSSIBLE ) return ret; + m_bmIter[i] = iLar+1; + for ( iClear=i+1 ; iClear<=MAXPOINTS ; iClear++ ) m_bmIter[iClear] = -1; + m_bmIterCounter ++; + if ( m_bmIterCounter >= nbIter ) return ERR_CONTINUE; + } + iLar ++; + } + + return ERR_GOTO_IMPOSSIBLE; +} + +// Is a right "start-goal". Calculates the point located at the distance "step" +// from the point "start" and an angle "angle" with the right. + +Math::Vector CTaskGoto::BeamPoint(const Math::Vector &startPoint, + const Math::Vector &goalPoint, + float angle, float step) +{ + Math::Vector resPoint; + float goalAngle; + + goalAngle = Math::RotateAngle(goalPoint.x-startPoint.x, goalPoint.z-startPoint.z); + + resPoint.x = startPoint.x + cosf(goalAngle+angle)*step; + resPoint.z = startPoint.z + sinf(goalAngle+angle)*step; + resPoint.y = 0.0f; + + return resPoint; +} + +// Displays a bitmap part. + +void CTaskGoto::BitmapDebug(const Math::Vector &min, const Math::Vector &max, + const Math::Vector &start, const Math::Vector &goal) +{ + int minx, miny, maxx, maxy, x, y, i ,n; + char s[2000]; + + minx = (int)((min.x+1600.0f)/BM_DIM_STEP); + miny = (int)((min.z+1600.0f)/BM_DIM_STEP); + maxx = (int)((max.x+1600.0f)/BM_DIM_STEP); + maxy = (int)((max.z+1600.0f)/BM_DIM_STEP); + + if ( minx > maxx ) Math::Swap(minx, maxx); + if ( miny > maxy ) Math::Swap(miny, maxy); + + OutputDebugString("Bitmap :\n"); + for ( y=miny ; y<=maxy ; y++ ) + { + s[0] = 0; + for ( x=minx ; x<=maxx ; x++ ) + { + n = -1; + for ( i=0 ; i<=m_bmTotal ; i++ ) + { + if ( x == (int)((m_bmPoints[i].x+1600.0f)/BM_DIM_STEP) && + y == (int)((m_bmPoints[i].z+1600.0f)/BM_DIM_STEP) ) + { + n = i; + break; + } + } + + if ( BitmapTestDot(0, x,y) ) + { + strcat(s, "o"); + } + else + { + if ( BitmapTestDot(1, x,y) ) + { + strcat(s, "-"); + } + else + { + strcat(s, "."); + } + } + + if ( x == (int)((start.x+1600.0f)/BM_DIM_STEP) && + y == (int)((start.z+1600.0f)/BM_DIM_STEP) ) + { + strcat(s, "s"); + } + else + if ( x == (int)((goal.x+1600.0f)/BM_DIM_STEP) && + y == (int)((goal.z+1600.0f)/BM_DIM_STEP) ) + { + strcat(s, "g"); + } + else + if ( n != -1 ) + { + char ss[2]; + ss[0] = 'A'+n; + ss[1] = 0; + strcat(s, ss); + } + else + { + strcat(s, " "); + } + } + strcat(s, "\n"); + OutputDebugString(s); + } +} + +// Tests if a path along a straight line is possible. + +bool CTaskGoto::BitmapTestLine(const Math::Vector &start, const Math::Vector &goal, + float stepAngle, bool bSecond) +{ + Math::Vector pos, inc; + float dist, step; + float distNoB2; + int i, max, x, y; + + if ( m_bmArray == 0 ) return true; + + dist = Math::DistanceProjected(start, goal); + if ( dist == 0.0f ) return true; + step = BM_DIM_STEP*0.5f; + + inc.x = (goal.x-start.x)*step/dist; + inc.z = (goal.z-start.z)*step/dist; + + pos = start; + + if ( bSecond ) + { + x = (int)((pos.x+1600.0f)/BM_DIM_STEP); + y = (int)((pos.z+1600.0f)/BM_DIM_STEP); + BitmapSetDot(1, x, y); // puts the flag as the starting point + } + + max = (int)(dist/step); + if ( max == 0 ) max = 1; + distNoB2 = BM_DIM_STEP*sqrtf(2.0f)/sinf(stepAngle); + for ( i=0 ; i<max ; i++ ) + { + if ( i == max-1 ) + { + pos = goal; // tests the point of arrival + } + else + { + pos.x += inc.x; + pos.z += inc.z; + } + + x = (int)((pos.x+1600.0f)/BM_DIM_STEP); + y = (int)((pos.z+1600.0f)/BM_DIM_STEP); + + if ( bSecond ) + { + if ( i > 2 && BitmapTestDot(1, x, y) ) return false; + + if ( step*(i+1) > distNoB2 && i < max-2 ) + { + BitmapSetDot(1, x, y); + } + } + + if ( BitmapTestDot(0, x, y) ) return false; + } + return true; +} + +// Adds the objects in the bitmap. + +void CTaskGoto::BitmapObject() +{ + CObject *pObj; + ObjectType type; + Math::Vector iPos, oPos; + float iRadius, oRadius, h; + int i, j; + + m_object->GetCrashSphere(0, iPos, iRadius); + + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + type = pObj->RetType(); + + if ( pObj == m_object ) continue; + if ( pObj == m_bmFretObject ) continue; + if ( pObj->RetTruck() != 0 ) continue; + + h = m_terrain->RetFloorLevel(pObj->RetPosition(0), false); + if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f ) + { + h += m_altitude; + } + + j = 0; + while ( pObj->GetCrashSphere(j++, oPos, oRadius) ) + { + if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f ) // flying? + { + if ( oPos.y-oRadius > h+8.0f || + oPos.y+oRadius < h-8.0f ) continue; + } + else // crawling? + { + if ( oPos.y-oRadius > h+8.0f ) continue; + } + + if ( type == OBJECT_PARA ) oRadius -= 2.0f; + BitmapSetCircle(oPos, oRadius+iRadius+4.0f); + } + } +} + +// Adds a section of land in the bitmap. + +void CTaskGoto::BitmapTerrain(const Math::Vector &min, const Math::Vector &max) +{ + int minx, miny, maxx, maxy; + + minx = (int)((min.x+1600.0f)/BM_DIM_STEP); + miny = (int)((min.z+1600.0f)/BM_DIM_STEP); + maxx = (int)((max.x+1600.0f)/BM_DIM_STEP); + maxy = (int)((max.z+1600.0f)/BM_DIM_STEP); + + BitmapTerrain(minx, miny, maxx, maxy); +} + +// Adds a section of land in the bitmap. + +void CTaskGoto::BitmapTerrain(int minx, int miny, int maxx, int maxy) +{ + ObjectType type; + Math::Vector p; + float aLimit, angle, h; + int x, y; + bool bAcceptWater, bFly; + + if ( minx > maxx ) Math::Swap(minx, maxx); + if ( miny > maxy ) Math::Swap(miny, maxy); + + if ( minx < 0 ) minx = 0; + if ( miny < 0 ) miny = 0; + if ( maxx > m_bmSize-1 ) maxx = m_bmSize-1; + if ( maxy > m_bmSize-1 ) maxy = m_bmSize-1; + + if ( minx > m_bmMinX ) minx = m_bmMinX; + if ( miny > m_bmMinY ) miny = m_bmMinY; + if ( maxx < m_bmMaxX ) maxx = m_bmMaxX; + if ( maxy < m_bmMaxY ) maxy = m_bmMaxY; + + if ( minx >= m_bmMinX && maxx <= m_bmMaxX && + miny >= m_bmMinY && maxy <= m_bmMaxY ) return; + + aLimit = 20.0f*Math::PI/180.0f; + bAcceptWater = false; + bFly = false; + + type = m_object->RetType(); + + if ( type == OBJECT_MOBILEwa || + type == OBJECT_MOBILEwc || + type == OBJECT_MOBILEws || + type == OBJECT_MOBILEwi || + type == OBJECT_MOBILEwt || + type == OBJECT_MOBILEtg ) // wheels? + { + aLimit = 20.0f*Math::PI/180.0f; + } + + if ( type == OBJECT_MOBILEta || + type == OBJECT_MOBILEtc || + type == OBJECT_MOBILEti || + type == OBJECT_MOBILEts ) // caterpillars? + { + aLimit = 35.0f*Math::PI/180.0f; + } + + if ( type == OBJECT_MOBILErt || + type == OBJECT_MOBILErc || + type == OBJECT_MOBILErr || + type == OBJECT_MOBILErs ) // large caterpillars? + { + aLimit = 35.0f*Math::PI/180.0f; + } + + if ( type == OBJECT_MOBILEsa ) // submarine caterpillars? + { + aLimit = 35.0f*Math::PI/180.0f; + bAcceptWater = true; + } + + if ( type == OBJECT_MOBILEdr ) // designer caterpillars? + { + aLimit = 35.0f*Math::PI/180.0f; + } + + if ( type == OBJECT_MOBILEfa || + type == OBJECT_MOBILEfc || + type == OBJECT_MOBILEfs || + type == OBJECT_MOBILEfi || + type == OBJECT_MOBILEft ) // flying? + { + aLimit = 15.0f*Math::PI/180.0f; + bFly = true; + } + + if ( type == OBJECT_MOBILEia || + type == OBJECT_MOBILEic || + type == OBJECT_MOBILEis || + type == OBJECT_MOBILEii ) // insect legs? + { + aLimit = 60.0f*Math::PI/180.0f; + } + + for ( y=miny ; y<=maxy ; y++ ) + { + for ( x=minx ; x<=maxx ; x++ ) + { + if ( x >= m_bmMinX && x <= m_bmMaxX && + y >= m_bmMinY && y <= m_bmMaxY ) continue; + + p.x = x*BM_DIM_STEP-1600.0f; + p.z = y*BM_DIM_STEP-1600.0f; + + if ( bFly ) // flying robot? + { + h = m_terrain->RetFloorLevel(p, true); + if ( h >= m_terrain->RetFlyingMaxHeight()-5.0f ) + { + BitmapSetDot(0, x, y); + } + continue; + } + + if ( !bAcceptWater ) // not going underwater? + { + h = m_terrain->RetFloorLevel(p, true); + if ( h < m_water->RetLevel()-2.0f ) // under water (*)? + { +//? BitmapSetDot(0, x, y); + BitmapSetCircle(p, BM_DIM_STEP*1.0f); + continue; + } + } + + angle = m_terrain->RetFineSlope(p); + if ( angle > aLimit ) + { + BitmapSetDot(0, x, y); + } + } + } + + m_bmMinX = minx; + m_bmMinY = miny; + m_bmMaxX = maxx; + m_bmMaxY = maxy; // expanded rectangular area +} + +// (*) Accepts that a robot is 50cm under water, for example Tropica 3! + +// Opens an empty bitmap. + +bool CTaskGoto::BitmapOpen() +{ + BitmapClose(); + + m_bmSize = (int)(3200.0f/BM_DIM_STEP); + m_bmArray = (unsigned char*)malloc(m_bmSize*m_bmSize/8*2); + ZeroMemory(m_bmArray, m_bmSize*m_bmSize/8*2); + + m_bmOffset = m_bmSize/2; + m_bmLine = m_bmSize/8; + + m_bmMinX = m_bmSize; // non-existent rectangular area + m_bmMinY = m_bmSize; + m_bmMaxX = 0; + m_bmMaxY = 0; + + return true; +} + +// Closes the bitmap. + +bool CTaskGoto::BitmapClose() +{ + free(m_bmArray); + m_bmArray = 0; + return true; +} + +// Puts a circle in the bitmap. + +void CTaskGoto::BitmapSetCircle(const Math::Vector &pos, float radius) +{ + float d, r; + int cx, cy, ix, iy; + + cx = (int)((pos.x+1600.0f)/BM_DIM_STEP); + cy = (int)((pos.z+1600.0f)/BM_DIM_STEP); + r = radius/BM_DIM_STEP; + + for ( iy=cy-(int)r ; iy<=cy+(int)r ; iy++ ) + { + for ( ix=cx-(int)r ; ix<=cx+(int)r ; ix++ ) + { + d = Math::Point((float)(ix-cx), (float)(iy-cy)).Length(); + if ( d > r ) continue; + BitmapSetDot(0, ix, iy); + } + } +} + +// Removes a circle in the bitmap. + +void CTaskGoto::BitmapClearCircle(const Math::Vector &pos, float radius) +{ + float d, r; + int cx, cy, ix, iy; + + cx = (int)((pos.x+1600.0f)/BM_DIM_STEP); + cy = (int)((pos.z+1600.0f)/BM_DIM_STEP); + r = radius/BM_DIM_STEP; + + for ( iy=cy-(int)r ; iy<=cy+(int)r ; iy++ ) + { + for ( ix=cx-(int)r ; ix<=cx+(int)r ; ix++ ) + { + d = Math::Point((float)(ix-cx), (float)(iy-cy)).Length(); + if ( d > r ) continue; + BitmapClearDot(0, ix, iy); + } + } +} + +// Makes a point in the bitmap. +// x:y: 0..m_bmSize-1 + +void CTaskGoto::BitmapSetDot(int rank, int x, int y) +{ + if ( x < 0 || x >= m_bmSize || + y < 0 || y >= m_bmSize ) return; + + m_bmArray[rank*m_bmLine*m_bmSize + m_bmLine*y + x/8] |= (1<<x%8); +} + +// Removes a point in the bitmap. +// x:y: 0..m_bmSize-1 + +void CTaskGoto::BitmapClearDot(int rank, int x, int y) +{ + if ( x < 0 || x >= m_bmSize || + y < 0 || y >= m_bmSize ) return; + + m_bmArray[rank*m_bmLine*m_bmSize + m_bmLine*y + x/8] &= ~(1<<x%8); +} + +// Tests a point in the bitmap. +// x:y: 0..m_bmSize-1 + +bool CTaskGoto::BitmapTestDot(int rank, int x, int y) +{ + if ( x < 0 || x >= m_bmSize || + y < 0 || y >= m_bmSize ) return false; + + if ( x < m_bmMinX || x > m_bmMaxX || + y < m_bmMinY || y > m_bmMaxY ) + { + BitmapTerrain(x-10,y-10, x+10,y+10); // remade a layer + } + + return m_bmArray[rank*m_bmLine*m_bmSize + m_bmLine*y + x/8] & (1<<x%8); +} + + |