summaryrefslogtreecommitdiffstats
path: root/src/object/task
diff options
context:
space:
mode:
Diffstat (limited to 'src/object/task')
-rw-r--r--src/object/task/task.cpp109
-rw-r--r--src/object/task/task.h89
-rw-r--r--src/object/task/taskadvance.cpp159
-rw-r--r--src/object/task/taskadvance.h59
-rw-r--r--src/object/task/taskbuild.cpp822
-rw-r--r--src/object/task/taskbuild.h93
-rw-r--r--src/object/task/taskfire.cpp398
-rw-r--r--src/object/task/taskfire.h61
-rw-r--r--src/object/task/taskfireant.cpp227
-rw-r--r--src/object/task/taskfireant.h72
-rw-r--r--src/object/task/taskflag.cpp321
-rw-r--r--src/object/task/taskflag.h66
-rw-r--r--src/object/task/taskgoto.cpp2352
-rw-r--r--src/object/task/taskgoto.h167
-rw-r--r--src/object/task/taskgungoal.cpp161
-rw-r--r--src/object/task/taskgungoal.h57
-rw-r--r--src/object/task/taskinfo.cpp233
-rw-r--r--src/object/task/taskinfo.h57
-rw-r--r--src/object/task/taskmanager.cpp291
-rw-r--r--src/object/task/taskmanager.h77
-rw-r--r--src/object/task/taskmanip.cpp1398
-rw-r--r--src/object/task/taskmanip.h109
-rw-r--r--src/object/task/taskpen.cpp304
-rw-r--r--src/object/task/taskpen.h77
-rw-r--r--src/object/task/taskrecover.cpp431
-rw-r--r--src/object/task/taskrecover.h75
-rw-r--r--src/object/task/taskreset.cpp345
-rw-r--r--src/object/task/taskreset.h73
-rw-r--r--src/object/task/tasksearch.cpp334
-rw-r--r--src/object/task/tasksearch.h79
-rw-r--r--src/object/task/taskshield.cpp573
-rw-r--r--src/object/task/taskshield.h94
-rw-r--r--src/object/task/taskspiderexplo.cpp124
-rw-r--r--src/object/task/taskspiderexplo.h53
-rw-r--r--src/object/task/tasktake.cpp612
-rw-r--r--src/object/task/tasktake.h85
-rw-r--r--src/object/task/taskterraform.cpp429
-rw-r--r--src/object/task/taskterraform.h72
-rw-r--r--src/object/task/taskturn.cpp147
-rw-r--r--src/object/task/taskturn.h55
-rw-r--r--src/object/task/taskwait.cpp89
-rw-r--r--src/object/task/taskwait.h53
42 files changed, 11482 insertions, 0 deletions
diff --git a/src/object/task/task.cpp b/src/object/task/task.cpp
new file mode 100644
index 0000000..6b8222e
--- /dev/null
+++ b/src/object/task/task.cpp
@@ -0,0 +1,109 @@
+// * 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/.
+
+// task.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "d3dengine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "light.h"
+#include "particule.h"
+#include "terrain.h"
+#include "water.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "motion.h"
+#include "camera.h"
+#include "sound.h"
+#include "robotmain.h"
+#include "displaytext.h"
+#include "task.h"
+
+
+
+
+// Object's constructor.
+
+CTask::CTask(CInstanceManager* iMan, CObject* object)
+{
+ m_iMan = iMan;
+
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_light = (CLight*)m_iMan->SearchInstance(CLASS_LIGHT);
+ m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE);
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+ m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER);
+ m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA);
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+ m_displayText = (CDisplayText*)m_iMan->SearchInstance(CLASS_DISPLAYTEXT);
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+
+ m_object = object;
+ m_physics = m_object->RetPhysics();
+ m_brain = m_object->RetBrain();
+ m_motion = m_object->RetMotion();
+}
+
+// Object's destructor.
+
+CTask::~CTask()
+{
+}
+
+
+// Management of an event.
+
+BOOL CTask::EventProcess(const Event &event)
+{
+ return TRUE;
+}
+
+
+// Indicates whether the action is finished.
+
+Error CTask::IsEnded()
+{
+ return ERR_STOP;
+}
+
+
+// Indicates whether the action is pending.
+
+BOOL CTask::IsBusy()
+{
+ return TRUE;
+}
+
+
+// Suddenly ends the current action.
+
+BOOL CTask::Abort()
+{
+ return TRUE;
+}
+
+
diff --git a/src/object/task/task.h b/src/object/task/task.h
new file mode 100644
index 0000000..f5685ef
--- /dev/null
+++ b/src/object/task/task.h
@@ -0,0 +1,89 @@
+// * 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/.
+
+// task.h
+
+#ifndef _TASK_H_
+#define _TASK_H_
+
+
+#include "misc.h"
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CEngine;
+class CLight;
+class CParticule;
+class CTerrain;
+class CWater;
+class CCamera;
+class CBrain;
+class CPhysics;
+class CMotion;
+class CObject;
+class CRobotMain;
+class CDisplayText;
+class CSound;
+
+
+#define TAKE_DIST 6.0f // distance to an object to pick it
+#define TAKE_DIST_OTHER 1.5f // additional distance if on friend
+
+//?#define ARM_NEUTRAL_ANGLE1 155.0f*PI/180.0f
+//?#define ARM_NEUTRAL_ANGLE2 -125.0f*PI/180.0f
+//?#define ARM_NEUTRAL_ANGLE3 -45.0f*PI/180.0f
+#define ARM_NEUTRAL_ANGLE1 110.0f*PI/180.0f
+#define ARM_NEUTRAL_ANGLE2 -130.0f*PI/180.0f
+#define ARM_NEUTRAL_ANGLE3 -50.0f*PI/180.0f
+
+#define ARM_STOCK_ANGLE1 110.0f*PI/180.0f
+#define ARM_STOCK_ANGLE2 -100.0f*PI/180.0f
+#define ARM_STOCK_ANGLE3 -70.0f*PI/180.0f
+
+
+class CTask
+{
+public:
+ CTask(CInstanceManager* iMan, CObject* object);
+ virtual ~CTask();
+
+ virtual BOOL EventProcess(const Event &event);
+ virtual Error IsEnded();
+ virtual BOOL IsBusy();
+ virtual BOOL Abort();
+
+protected:
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CLight* m_light;
+ CParticule* m_particule;
+ CTerrain* m_terrain;
+ CWater* m_water;
+ CCamera* m_camera;
+ CMotion* m_motion;
+ CBrain* m_brain;
+ CPhysics* m_physics;
+ CObject* m_object;
+ CRobotMain* m_main;
+ CDisplayText* m_displayText;
+ CSound* m_sound;
+};
+
+
+#endif //_TASK_H_
diff --git a/src/object/task/taskadvance.cpp b/src/object/task/taskadvance.cpp
new file mode 100644
index 0000000..7860cb2
--- /dev/null
+++ b/src/object/task/taskadvance.cpp
@@ -0,0 +1,159 @@
+// * 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/.
+
+// taskadvance.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "d3dengine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "task.h"
+#include "taskadvance.h"
+
+
+
+
+// Object's constructor.
+
+CTaskAdvance::CTaskAdvance(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+}
+
+// Object's destructor.
+
+CTaskAdvance::~CTaskAdvance()
+{
+}
+
+
+// Management of an event.
+
+BOOL CTaskAdvance::EventProcess(const Event &event)
+{
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_fixTime += event.rTime;
+
+ // 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
+ m_bError = TRUE;
+ return TRUE;
+ }
+
+ m_timeLimit -= event.rTime;
+ return TRUE;
+}
+
+
+// Assigns the goal was achieved.
+
+Error CTaskAdvance::Start(float length)
+{
+ m_direction = (length>=0.0f)?1.0f:-1.0f;
+ m_totalLength = Abs(length);
+ m_advanceLength = m_physics->RetLinLength(length);
+ m_startPos = m_object->RetPosition(0);
+ m_lastDist = 0.0f;
+ m_fixTime = 0.0f;
+
+ m_timeLimit = m_physics->RetLinTimeLength(m_totalLength, m_direction)*3.0f;
+ if ( m_timeLimit < 2.0f ) m_timeLimit = 2.0f;
+
+ m_physics->SetMotorSpeedX(m_direction*1.0f); // forward/backward
+ m_physics->SetMotorSpeedY(0.0f);
+ m_physics->SetMotorSpeedZ(0.0f);
+
+ m_bError = FALSE;
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskAdvance::IsEnded()
+{
+ D3DVECTOR pos;
+ float length;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+
+ if ( m_bError )
+ {
+ return ERR_STOP;
+ }
+
+ if ( m_timeLimit < 0.0f )
+ {
+ m_physics->SetMotorSpeedX(0.0f);
+ return ERR_MOVE_IMPOSSIBLE;
+ }
+
+ pos = m_object->RetPosition(0);
+ length = Length2d(pos, m_startPos);
+
+ if ( length > m_lastDist ) // forward?
+ {
+ m_fixTime = 0.0f;
+ }
+ else // still stands?
+ {
+ if ( m_fixTime > 1.0f ) // for more than a second?
+ {
+ m_physics->SetMotorSpeedX(0.0f);
+ return ERR_MOVE_IMPOSSIBLE;
+ }
+ }
+ m_lastDist = length;
+
+ if ( length >= m_totalLength )
+ {
+ m_physics->SetMotorSpeedX(0.0f);
+ m_physics->SetLinMotionX(MO_CURSPEED, 0.0f);
+
+ if ( length != 0.0f )
+ {
+ pos = m_startPos+((pos-m_startPos)*m_totalLength/length);
+ m_object->SetPosition(0, pos);
+ }
+ return ERR_STOP;
+ }
+
+ if ( length >= m_advanceLength )
+ {
+ m_physics->SetMotorSpeedX(m_direction*0.1f);
+ }
+ return ERR_CONTINUE;
+}
+
+
diff --git a/src/object/task/taskadvance.h b/src/object/task/taskadvance.h
new file mode 100644
index 0000000..284cf12
--- /dev/null
+++ b/src/object/task/taskadvance.h
@@ -0,0 +1,59 @@
+// * 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/.
+
+// taskadvance.h
+
+#ifndef _TASKADVANCE_H_
+#define _TASKADVANCE_H_
+
+
+#include "misc.h"
+#include "d3dengine.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+class CTaskAdvance : public CTask
+{
+public:
+ CTaskAdvance(CInstanceManager* iMan, CObject* object);
+ ~CTaskAdvance();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(float length);
+ Error IsEnded();
+
+protected:
+
+protected:
+ float m_totalLength;
+ float m_advanceLength;
+ float m_direction;
+ float m_timeLimit;
+ D3DVECTOR m_startPos;
+ float m_lastDist;
+ float m_fixTime;
+ BOOL m_bError;
+};
+
+
+#endif //_TASKADVANCE_H_
diff --git a/src/object/task/taskbuild.cpp b/src/object/task/taskbuild.cpp
new file mode 100644
index 0000000..cc1303b
--- /dev/null
+++ b/src/object/task/taskbuild.cpp
@@ -0,0 +1,822 @@
+// * 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/.
+
+// taskbuild.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "d3dengine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "light.h"
+#include "particule.h"
+#include "terrain.h"
+#include "water.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "auto.h"
+#include "camera.h"
+#include "motion.h"
+#include "motionhuman.h"
+#include "robotmain.h"
+#include "sound.h"
+#include "displaytext.h"
+#include "task.h"
+#include "taskbuild.h"
+
+
+
+
+// Object's constructor.
+
+CTaskBuild::CTaskBuild(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ int i;
+
+ CTask::CTask(iMan, object);
+
+ m_type = OBJECT_DERRICK;
+ m_time = 0.0f;
+ m_soundChannel = -1;
+
+ for ( i=0 ; i<TBMAXLIGHT ; i++ )
+ {
+ m_lightRank[i] = -1;
+ }
+}
+
+// Object's destructor.
+
+CTaskBuild::~CTaskBuild()
+{
+ int i;
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ for ( i=0 ; i<TBMAXLIGHT ; i++ )
+ {
+ if ( m_lightRank[i] == -1 ) continue;
+ m_light->DeleteLight(m_lightRank[i]);
+ }
+}
+
+
+// Creates a building.
+
+BOOL CTaskBuild::CreateBuilding(D3DVECTOR pos, float angle)
+{
+ m_building = new CObject(m_iMan);
+ if ( !m_building->CreateBuilding(pos, angle, 0.0f, m_type, 0.0f) )
+ {
+ delete m_building;
+ m_building = 0;
+ return FALSE;
+ }
+ m_building->UpdateMapping();
+ m_building->SetLock(TRUE); // not yet usable
+
+ if ( m_type == OBJECT_DERRICK ) m_buildingHeight = 35.0f;
+ if ( m_type == OBJECT_FACTORY ) m_buildingHeight = 28.0f;
+ if ( m_type == OBJECT_REPAIR ) m_buildingHeight = 30.0f;
+ if ( m_type == OBJECT_STATION ) m_buildingHeight = 13.0f;
+ if ( m_type == OBJECT_CONVERT ) m_buildingHeight = 20.0f;
+ if ( m_type == OBJECT_TOWER ) m_buildingHeight = 30.0f;
+ if ( m_type == OBJECT_RESEARCH ) m_buildingHeight = 22.0f;
+ if ( m_type == OBJECT_RADAR ) m_buildingHeight = 19.0f;
+ if ( m_type == OBJECT_ENERGY ) m_buildingHeight = 20.0f;
+ if ( m_type == OBJECT_LABO ) m_buildingHeight = 16.0f;
+ if ( m_type == OBJECT_NUCLEAR ) m_buildingHeight = 40.0f;
+ if ( m_type == OBJECT_PARA ) m_buildingHeight = 68.0f;
+ if ( m_type == OBJECT_INFO ) m_buildingHeight = 19.0f;
+ m_buildingHeight *= 0.25f;
+
+ m_buildingPos = m_building->RetPosition(0);
+ m_buildingPos.y -= m_buildingHeight;
+ m_building->SetPosition(0, m_buildingPos);
+ return TRUE;
+}
+
+// Creates lights for the effects.
+
+void CTaskBuild::CreateLight()
+{
+ D3DLIGHT7 light;
+ D3DCOLORVALUE color;
+ D3DVECTOR center, pos, dir;
+ FPOINT c, p;
+ float angle;
+ int i;
+
+ if ( !m_engine->RetLightMode() ) return;
+
+ center = m_metal->RetPosition(0);
+
+ angle = 0;
+ for ( i=0 ; i<TBMAXLIGHT ; i++ )
+ {
+ m_lightRank[i] = m_light->CreateLight();
+ if ( m_lightRank[i] == -1 ) continue;
+
+ c.x = center.x;
+ c.y = center.z;
+ p.x = center.x+40.0f;
+ p.y = center.z;
+ p = RotatePoint(c, angle, p);
+ pos.x = p.x;
+ pos.z = p.y;
+ pos.y = center.y+40.0f;
+ dir = center-pos;
+
+ ZeroMemory( &light, sizeof(light) );
+ light.dltType = D3DLIGHT_SPOT;
+ light.dcvDiffuse.r = 0.0f;
+ light.dcvDiffuse.g = 0.0f;
+ light.dcvDiffuse.b = 0.0f; // white (invisible)
+ light.dvPosition.x = pos.x;
+ light.dvPosition.y = pos.y;
+ light.dvPosition.z = pos.z;
+ light.dvDirection.x = dir.x;
+ light.dvDirection.y = dir.y;
+ light.dvDirection.z = dir.z;
+ light.dvRange = D3DLIGHT_RANGE_MAX;
+ light.dvFalloff = 1.0f;
+ light.dvAttenuation0 = 1.0f;
+ light.dvAttenuation1 = 0.0f;
+ light.dvAttenuation2 = 0.0f;
+ light.dvTheta = 0.0f;
+ light.dvPhi = PI/4.0f;
+ m_light->SetLight(m_lightRank[i], light);
+
+ color.r = -1.0f;
+ color.g = -1.0f;
+ color.b = -0.5f; // violet
+ color.a = 0.0f;
+ m_light->SetLightColor(m_lightRank[i], color);
+ m_light->SetLightColorSpeed(m_lightRank[i], 1.0f/((1.0f/m_speed)*0.25f));
+
+ angle += (PI*2.0f)/TBMAXLIGHT;
+ }
+
+ m_bBlack = FALSE;
+}
+
+// Switches the lights from black to white.
+
+void CTaskBuild::BlackLight()
+{
+ D3DCOLORVALUE color;
+ int i;
+
+ for ( i=0 ; i<TBMAXLIGHT ; i++ )
+ {
+ if ( m_lightRank[i] == -1 ) continue;
+
+ color.r = 0.0f;
+ color.g = 0.0f;
+ color.b = 0.0f; // white (invisible)
+ color.a = 0.0f;
+ m_light->SetLightColor(m_lightRank[i], color);
+ m_light->SetLightColorSpeed(m_lightRank[i], 1.0f/((1.0f/m_speed)*0.75f));
+ }
+
+ m_bBlack = TRUE;
+}
+
+// Management of an event.
+
+BOOL CTaskBuild::EventProcess(const Event &event)
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, dir, speed;
+ FPOINT dim;
+ float a, g, cirSpeed, dist, linSpeed;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ m_time += event.rTime;
+
+ m_progress += event.rTime*m_speed; // other advance
+
+ if ( m_phase == TBP_TURN ) // preliminary rotation?
+ {
+ a = m_object->RetAngleY(0);
+ g = m_angleY;
+ cirSpeed = 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
+ return TRUE;
+ }
+
+ if ( m_phase == TBP_MOVE ) // preliminary forward/backward?
+ {
+ dist = Length(m_object->RetPosition(0), m_metal->RetPosition(0));
+ linSpeed = 0.0f;
+ if ( dist > 30.0f ) linSpeed = 1.0f;
+ if ( dist < 30.0f ) linSpeed = -1.0f;
+ m_physics->SetMotorSpeedX(linSpeed); // forward/backward
+ return TRUE;
+ }
+
+ if ( m_phase == TBP_RECEDE ) // terminal back?
+ {
+ m_physics->SetMotorSpeedX(-1.0f); // back
+ return TRUE;
+ }
+
+ if ( m_phase == TBP_TAKE ) // takes gun?
+ {
+ return TRUE;
+ }
+
+ if ( m_phase == TBP_PREP ) // prepares?
+ {
+ return TRUE;
+ }
+
+ if ( m_phase == TBP_TERM ) // ends?
+ {
+ return TRUE;
+ }
+
+ if ( !m_bBuild ) // building to build?
+ {
+ m_bBuild = TRUE;
+
+ pos = m_metal->RetPosition(0);
+ a = m_object->RetAngleY(0);
+ if ( !CreateBuilding(pos, a+PI) )
+ {
+ m_metal->SetLock(FALSE); // usable again
+ m_motion->SetAction(-1);
+ m_object->SetObjectParent(14, 0);
+ m_object->SetPosition(14, D3DVECTOR(-1.5f, 0.3f, -1.35f));
+ m_object->SetAngleZ(14, PI);
+ m_camera->FlushEffect();
+ Abort();
+ m_bError = TRUE;
+ m_displayText->DisplayError(ERR_TOOMANY, m_object->RetPosition(0));
+ return FALSE;
+ }
+ CreateLight();
+ }
+
+ pos = m_buildingPos;
+ pos.y += m_buildingHeight*m_progress;
+ m_building->SetPosition(0, pos); // the building rises
+
+ m_building->SetZoom(0, m_progress*0.75f+0.25f);
+ m_metal->SetZoom(0, 1.0f-m_progress);
+
+ a = (2.0f-2.0f*m_progress);
+ if ( a > 1.0f ) a = 1.0f;
+ dir.x = (Rand()-0.5f)*a*0.1f;
+ dir.z = (Rand()-0.5f)*a*0.1f;
+ dir.y = (Rand()-0.5f)*a*0.1f;
+ m_building->SetCirVibration(dir);
+
+ if ( !m_bBlack && m_progress >= 0.25f )
+ {
+ BlackLight();
+ }
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_metal->RetPosition(0);
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ speed.y = Rand()*10.0f;
+ dim.x = Rand()*6.0f+4.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIFIRE);
+
+ pos = D3DVECTOR(0.0f, 0.5f, 0.0f);
+ mat = m_object->RetWorldMatrix(14);
+ pos = Transform(*mat, pos);
+ speed = m_metal->RetPosition(0);
+ speed.x += (Rand()-0.5f)*5.0f;
+ speed.z += (Rand()-0.5f)*5.0f;
+ speed -= pos;
+ dim.x = 2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIFIREZ);
+
+ if ( Rand() < 0.3f )
+ {
+ m_sound->Play(SOUND_BUILD, m_object->RetPosition(0), 0.5f, 1.0f*Rand()*1.5f);
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Assigns the goal was achieved.
+
+Error CTaskBuild::Start(ObjectType type)
+{
+ D3DVECTOR pos, speed, pv, pm;
+ Error err;
+ float iAngle, oAngle;
+
+ m_type = type;
+ m_lastParticule = 0.0f;
+ m_progress = 0.0f;
+
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+ oAngle = iAngle;
+
+ m_bError = TRUE; // operation impossible
+
+ pos = m_object->RetPosition(0);
+ if ( pos.y < m_water->RetLevel() ) return ERR_BUILD_WATER;
+
+ if ( !m_physics->RetLand() ) return ERR_BUILD_FLY;
+
+ speed = m_physics->RetMotorSpeed();
+ if ( speed.x != 0.0f ||
+ speed.z != 0.0f ) return ERR_BUILD_MOTOR;
+
+ if ( m_object->RetFret() != 0 ) return ERR_MANIP_BUSY;
+
+ m_metal = SearchMetalObject(oAngle, 2.0f, 100.0f, PI*0.25f, err);
+ if ( err == ERR_BUILD_METALNEAR && m_metal != 0 )
+ {
+ err = FlatFloor();
+ if ( err != ERR_OK ) return err;
+ return ERR_BUILD_METALNEAR;
+ }
+ if ( err != ERR_OK ) return err;
+
+ err = FlatFloor();
+ if ( err != ERR_OK ) return err;
+
+ m_metal->SetLock(TRUE); // not usable
+ m_camera->StartCentering(m_object, PI*0.15f, 99.9f, 0.0f, 1.0f);
+
+ m_phase = TBP_TURN; // rotation necessary preliminary
+ m_angleY = oAngle; // angle was reached
+
+ pv = m_object->RetPosition(0);
+ pv.y += 8.3f;
+ pm = m_metal->RetPosition(0);
+ m_angleZ = RotateAngle(Length2d(pv, pm), Abs(pv.y-pm.y));
+
+ m_physics->SetFreeze(TRUE); // it does not move
+
+ m_bBuild = FALSE; // not yet built
+ m_bError = FALSE; // ok
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskBuild::IsEnded()
+{
+ CAuto* automat;
+ float angle, dist, time;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_phase == TBP_TURN ) // preliminary rotation?
+ {
+ angle = m_object->RetAngleY(0);
+ angle = NormAngle(angle); // 0..2*PI
+
+ if ( TestAngle(angle, m_angleY-PI*0.01f, m_angleY+PI*0.01f) )
+ {
+ m_physics->SetMotorSpeedZ(0.0f);
+
+ dist = Length(m_object->RetPosition(0), m_metal->RetPosition(0));
+ if ( dist > 30.0f )
+ {
+ time = m_physics->RetLinTimeLength(dist-30.0f, 1.0f);
+ m_speed = 1.0f/time;
+ }
+ else
+ {
+ time = m_physics->RetLinTimeLength(30.0f-dist, -1.0f);
+ m_speed = 1.0f/time;
+ }
+ m_phase = TBP_MOVE;
+ m_progress = 0.0f;
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TBP_MOVE ) // preliminary forward/backward?
+ {
+ dist = Length(m_object->RetPosition(0), m_metal->RetPosition(0));
+
+ if ( dist >= 25.0f && dist <= 35.0f )
+ {
+ m_physics->SetMotorSpeedX(0.0f);
+ m_motion->SetAction(MHS_GUN); // takes gun
+
+ m_phase = TBP_TAKE;
+ m_speed = 1.0f/1.0f;
+ m_progress = 0.0f;
+ }
+ else
+ {
+ if ( m_progress > 1.0f ) // timeout?
+ {
+ m_metal->SetLock(FALSE); // usable again
+ if ( dist < 30.0f ) return ERR_BUILD_METALNEAR;
+ else return ERR_BUILD_METALAWAY;
+ }
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TBP_TAKE ) // takes gun
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_motion->SetAction(MHS_FIRE); // shooting position
+ m_object->SetObjectParent(14, 4);
+ m_object->SetPosition(14, D3DVECTOR(0.6f, 0.1f, 0.3f));
+ m_object->SetAngleZ(14, 0.0f);
+
+ m_phase = TBP_PREP;
+ m_speed = 1.0f/1.0f;
+ m_progress = 0.0f;
+ }
+
+ if ( m_phase == TBP_PREP ) // prepares?
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_soundChannel = m_sound->Play(SOUND_TREMBLE, m_object->RetPosition(0), 0.0f, 1.0f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.7f, 1.0f, 1.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.7f, 1.5f, 7.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.5f, 2.0f, SOPER_STOP);
+
+ m_camera->StartEffect(CE_VIBRATION, m_metal->RetPosition(0), 1.0f);
+
+ m_phase = TBP_BUILD;
+ m_speed = 1.0f/10.f; // duration of 10s
+ m_progress = 0.0f;
+ }
+
+ if ( m_phase == TBP_BUILD ) // construction?
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ DeleteMark(m_metal->RetPosition(0), 20.0f);
+
+ m_metal->DeleteObject(); // removes the metal
+ delete m_metal;
+ m_metal = 0;
+
+ m_building->SetZoom(0, 1.0f);
+ m_building->SetCirVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_building->SetLock(FALSE); // building usable
+ m_main->CreateShortcuts();
+ m_displayText->DisplayError(INFO_BUILD, m_buildingPos, 10.0f, 50.0f);
+
+ automat = m_building->RetAuto();
+ if ( automat != 0 )
+ {
+ automat->Init();
+ }
+
+ m_motion->SetAction(MHS_GUN); // hands gun
+ m_phase = TBP_TERM;
+ m_speed = 1.0f/1.0f;
+ m_progress = 0.0f;
+ }
+
+ if ( m_phase == TBP_TERM ) // rotation terminale ?
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_motion->SetAction(-1);
+ m_object->SetObjectParent(14, 0);
+ m_object->SetPosition(14, D3DVECTOR(-1.5f, 0.3f, -1.35f));
+ m_object->SetAngleZ(14, PI);
+
+ if ( m_type == OBJECT_FACTORY ||
+ m_type == OBJECT_RESEARCH ||
+ m_type == OBJECT_NUCLEAR )
+ {
+
+ m_phase = TBP_RECEDE;
+ m_speed = 1.0f/1.5f;
+ m_progress = 0.0f;
+ }
+ }
+
+ if ( m_phase == TBP_RECEDE ) // back?
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_physics->SetMotorSpeedX(0.0f);
+ }
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Suddenly ends the current action.
+
+BOOL CTaskBuild::Abort()
+{
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ m_camera->StopCentering(m_object, 2.0f);
+ m_physics->SetFreeze(FALSE); // is moving again
+ return TRUE;
+}
+
+
+// Checks whether the terrain is fairly flat
+// and if there is not too close to another object.
+
+Error CTaskBuild::FlatFloor()
+{
+ CObject *pObj;
+ ObjectType type;
+ D3DVECTOR center, pos, oPos, bPos;
+ FPOINT c, p;
+ float radius, max, oRadius, bRadius, angle, dist;
+ int i, j;
+ BOOL bLittleFlat, bBase;
+
+ radius = 0.0f;
+ if ( m_type == OBJECT_DERRICK ) radius = 5.0f;
+ if ( m_type == OBJECT_FACTORY ) radius = 15.0f;
+ if ( m_type == OBJECT_REPAIR ) radius = 12.0f;
+ if ( m_type == OBJECT_STATION ) radius = 12.0f;
+ if ( m_type == OBJECT_CONVERT ) radius = 12.0f;
+ if ( m_type == OBJECT_TOWER ) radius = 7.0f;
+ if ( m_type == OBJECT_RESEARCH ) radius = 10.0f;
+ if ( m_type == OBJECT_RADAR ) radius = 5.0f;
+ if ( m_type == OBJECT_ENERGY ) radius = 8.0f;
+ if ( m_type == OBJECT_LABO ) radius = 12.0f;
+ if ( m_type == OBJECT_NUCLEAR ) radius = 20.0f;
+ if ( m_type == OBJECT_PARA ) radius = 20.0f;
+ if ( m_type == OBJECT_INFO ) radius = 5.0f;
+ if ( radius == 0.0f ) return ERR_GENERIC;
+
+ center = m_metal->RetPosition(0);
+ angle = m_terrain->RetFineSlope(center);
+ bLittleFlat = ( angle < FLATLIMIT );
+
+ max = m_terrain->RetFlatZoneRadius(center, radius);
+ if ( max < radius ) // area too small?
+ {
+ if ( bLittleFlat )
+ {
+ m_main->SetShowLimit(1, PARTILIMIT3, m_metal, center, max, 10.0f);
+ }
+ return bLittleFlat?ERR_BUILD_FLATLIT:ERR_BUILD_FLAT;
+ }
+
+ max = 100000.0f;
+ bBase = FALSE;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue; // inactive?
+ if ( pObj->RetTruck() != 0 ) continue; // object transported?
+ if ( pObj == m_metal ) continue;
+ if ( pObj == m_object ) continue;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_BASE )
+ {
+ oPos = pObj->RetPosition(0);
+ dist = Length(center, oPos)-80.0f;
+ if ( dist < max )
+ {
+ max = dist;
+ bPos = oPos;
+ bRadius = oRadius;
+ bBase = TRUE;
+ }
+ }
+ else
+ {
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ dist = Length(center, oPos)-oRadius;
+ if ( dist < max )
+ {
+ max = dist;
+ bPos = oPos;
+ bRadius = oRadius;
+ bBase = FALSE;
+ }
+ }
+ }
+ }
+ if ( max < radius )
+ {
+ m_main->SetShowLimit(1, PARTILIMIT2, m_metal, center, max, 10.0f);
+ if ( bRadius < 2.0f ) bRadius = 2.0f;
+ m_main->SetShowLimit(2, PARTILIMIT3, m_metal, bPos, bRadius, 10.0f);
+ return bBase?ERR_BUILD_BASE:ERR_BUILD_BUSY;
+ }
+
+ max = 100000.0f;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue; // inactive?
+ if ( pObj->RetTruck() != 0 ) continue; // object transported?
+ if ( pObj == m_metal ) continue;
+ if ( pObj == m_object ) continue;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_DERRICK ||
+ type == OBJECT_FACTORY ||
+ type == OBJECT_STATION ||
+ type == OBJECT_CONVERT ||
+ type == OBJECT_REPAIR ||
+ type == OBJECT_TOWER ||
+ type == OBJECT_RESEARCH ||
+ type == OBJECT_RADAR ||
+ type == OBJECT_ENERGY ||
+ type == OBJECT_LABO ||
+ type == OBJECT_NUCLEAR ||
+ type == OBJECT_START ||
+ type == OBJECT_END ||
+ type == OBJECT_INFO ||
+ type == OBJECT_PARA ||
+ type == OBJECT_SAFE ||
+ type == OBJECT_HUSTON ) // building?
+ {
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ dist = Length(center, oPos)-oRadius;
+ if ( dist < max )
+ {
+ max = dist;
+ bPos = oPos;
+ bRadius = oRadius;
+ }
+ }
+ }
+ }
+ if ( max-BUILDMARGIN < radius )
+ {
+ m_main->SetShowLimit(1, PARTILIMIT2, m_metal, center, max-BUILDMARGIN, 10.0f);
+ m_main->SetShowLimit(2, PARTILIMIT3, m_metal, bPos, bRadius+BUILDMARGIN, 10.0f);
+ return bBase?ERR_BUILD_BASE:ERR_BUILD_NARROW;
+ }
+
+ return ERR_OK;
+}
+
+// Seeks the nearest metal object.
+
+CObject* CTaskBuild::SearchMetalObject(float &angle, float dMin, float dMax,
+ float aLimit, Error &err)
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR iPos, oPos;
+ ObjectType type;
+ float min, iAngle, a, aa, aBest, distance, magic;
+ int i;
+ BOOL bMetal;
+
+ iPos = m_object->RetPosition(0);
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+
+ min = 1000000.0f;
+ pBest = 0;
+ bMetal = FALSE;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue; // objet inactive?
+ if ( pObj->RetTruck() != 0 ) continue; // object transported?
+
+ type = pObj->RetType();
+ if ( type != OBJECT_METAL ) continue;
+
+ bMetal = TRUE; // metal exists
+
+ oPos = pObj->RetPosition(0);
+ distance = Length(oPos, iPos);
+ a = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW!
+
+ if ( distance > dMax ) continue;
+ if ( !TestAngle(a, iAngle-aLimit, iAngle+aLimit) ) continue;
+
+ if ( distance < dMin )
+ {
+ err = ERR_BUILD_METALNEAR; // too close
+ return pObj;
+ }
+
+ aa = Abs(a-iAngle);
+ if ( aa > PI ) aa = PI*2.0f-aa;
+ magic = distance*aa;
+
+ if ( magic < min )
+ {
+ min = magic;
+ aBest = a;
+ pBest = pObj;
+ }
+ }
+
+ if ( pBest == 0 )
+ {
+ if ( bMetal ) err = ERR_BUILD_METALAWAY; // too far
+ else err = ERR_BUILD_METALINEX; // non-existent
+ }
+ else
+ {
+ angle = aBest;
+ err = ERR_OK;
+ }
+ return pBest;
+}
+
+// Destroys all the close marks.
+
+void CTaskBuild::DeleteMark(D3DVECTOR pos, float radius)
+{
+ CObject* pObj;
+ D3DVECTOR oPos;
+ ObjectType type;
+ float distance;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_MARKSTONE &&
+ type != OBJECT_MARKURANIUM &&
+ type != OBJECT_MARKKEYa &&
+ type != OBJECT_MARKKEYb &&
+ type != OBJECT_MARKKEYc &&
+ type != OBJECT_MARKKEYd &&
+ type != OBJECT_MARKPOWER ) continue;
+
+ oPos = pObj->RetPosition(0);
+ distance = Length(oPos, pos);
+ if ( distance <= radius )
+ {
+ pObj->DeleteObject(); // removes the mark
+ delete pObj;
+ i --;
+ }
+ }
+}
+
diff --git a/src/object/task/taskbuild.h b/src/object/task/taskbuild.h
new file mode 100644
index 0000000..75a44f7
--- /dev/null
+++ b/src/object/task/taskbuild.h
@@ -0,0 +1,93 @@
+// * 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/.
+
+// taskbuild.h
+
+#ifndef _TASKBUILD_H_
+#define _TASKBUILD_H_
+
+
+#include "misc.h"
+#include "object.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+
+
+
+#define BUILDMARGIN 16.0f
+#define TBMAXLIGHT 4
+
+
+enum TaskBuildPhase
+{
+ TBP_TURN = 1, // turns
+ TBP_MOVE = 2, // forward/backward
+ TBP_TAKE = 3, // takes gun
+ TBP_PREP = 4, // prepares
+ TBP_BUILD = 5, // builds
+ TBP_TERM = 6, // ends
+ TBP_RECEDE = 7, // back terminal
+};
+
+
+
+class CTaskBuild : public CTask
+{
+public:
+ CTaskBuild(CInstanceManager* iMan, CObject* object);
+ ~CTaskBuild();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(ObjectType type);
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ Error FlatFloor();
+ BOOL CreateBuilding(D3DVECTOR pos, float angle);
+ void CreateLight();
+ void BlackLight();
+ CObject* SearchMetalObject(float &angle, float dMin, float dMax, float aLimit, Error &err);
+ void DeleteMark(D3DVECTOR pos, float radius);
+
+protected:
+ ObjectType m_type; // type of construction
+ CObject* m_metal; // transforms metal object
+ CObject* m_power; // the vehicle battery
+ CObject* m_building; // building built
+ TaskBuildPhase m_phase; // phase of the operation
+ BOOL m_bError; // TRUE -> operation impossible
+ BOOL m_bBuild; // TRUE -> building built
+ BOOL m_bBlack; // TRUE -> lights black -> white
+ float m_time; // absolute time
+ float m_lastParticule; // time of generation last particle
+ float m_progress; // progression (0..1)
+ float m_speed; // speed of progression
+ float m_angleY; // rotation angle of the vehicle
+ float m_angleZ; // angle of rotation of the gun
+ D3DVECTOR m_buildingPos; // initial position of the building
+ float m_buildingHeight; // height of the building
+ int m_lightRank[TBMAXLIGHT];// lights for the effects
+ int m_soundChannel;
+};
+
+
+#endif //_TASKBUILD_H_
diff --git a/src/object/task/taskfire.cpp b/src/object/task/taskfire.cpp
new file mode 100644
index 0000000..4fc0af5
--- /dev/null
+++ b/src/object/task/taskfire.cpp
@@ -0,0 +1,398 @@
+// * 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/.
+
+// taskfire.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "sound.h"
+#include "task.h"
+#include "taskfire.h"
+
+
+
+#define ENERGY_FIRE (0.25f/2.5f) // energy consumed/shot
+#define ENERGY_FIREr (0.25f/1.5f) // energy consumed/ray
+#define ENERGY_FIREi (0.10f/2.5f) // energy consumed/organic
+
+
+// Object's constructor.
+
+CTaskFire::CTaskFire(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+ m_soundChannel = -1;
+}
+
+// Object's destructor.
+
+CTaskFire::~CTaskFire()
+{
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+}
+
+
+// Management of an event.
+
+BOOL CTaskFire::EventProcess(const Event &event)
+{
+ CObject* power;
+ CPhysics* physics;
+ D3DMATRIX* mat;
+ D3DVECTOR pos, speed, dir, vib;
+ ObjectType type;
+ FPOINT dim;
+ float energy, fire;
+ int i, channel;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ m_time += event.rTime;
+ m_lastSound -= event.rTime;
+ m_progress += event.rTime*m_speed;
+
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ energy = power->RetEnergy();
+ if ( m_bOrganic ) fire = ENERGY_FIREi;
+ else if ( m_bRay ) fire = ENERGY_FIREr;
+ else fire = ENERGY_FIRE;
+ energy -= event.rTime*fire/power->RetCapacity();
+ power->SetEnergy(energy);
+ }
+
+ if ( m_lastParticule+0.05f <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ if ( m_bOrganic )
+ {
+ mat = m_object->RetWorldMatrix(1); // insect-cannon
+
+ for ( i=0 ; i<6 ; i++ )
+ {
+ pos = D3DVECTOR(0.0f, 2.5f, 0.0f);
+ pos = Transform(*mat, pos);
+
+ speed = D3DVECTOR(200.0f, 0.0f, 0.0f);
+
+ physics = m_object->RetPhysics();
+ if ( physics != 0 )
+ {
+ speed += physics->RetLinMotion(MO_REASPEED);
+ }
+
+ speed.x += (Rand()-0.5f)*10.0f;
+ speed.y += (Rand()-0.5f)*20.0f;
+ speed.z += (Rand()-0.5f)*30.0f;
+ speed = Transform(*mat, speed);
+ speed -= pos;
+
+ dim.x = Rand()*0.5f+0.5f;
+ dim.y = dim.x;
+
+ channel = m_particule->CreateParticule(pos, speed, dim, PARTIGUN4, 0.8f, 0.0f, 0.0f);
+ m_particule->SetObjectFather(channel, m_object);
+ }
+ }
+ else if ( m_bRay )
+ {
+ mat = m_object->RetWorldMatrix(2); // cannon
+
+ for ( i=0 ; i<4 ; i++ )
+ {
+ pos = D3DVECTOR(4.0f, 0.0f, 0.0f);
+ pos.y += (rand()%3-1)*1.5f;
+ pos.z += (rand()%3-1)*1.5f;
+ pos = Transform(*mat, pos);
+
+ speed = D3DVECTOR(200.0f, 0.0f, 0.0f);
+ speed.x += (Rand()-0.5f)*6.0f;
+ speed.y += (Rand()-0.5f)*12.0f;
+ speed.z += (Rand()-0.5f)*12.0f;
+ speed = Transform(*mat, speed);
+ speed -= pos;
+
+ dim.x = 1.0f;
+ dim.y = dim.x;
+ channel = m_particule->CreateTrack(pos, speed, dim, PARTITRACK11,
+ 2.0f, 200.0f, 0.5f, 1.0f);
+ m_particule->SetObjectFather(channel, m_object);
+
+ speed = D3DVECTOR(5.0f, 0.0f, 0.0f);
+ speed.x += (Rand()-0.5f)*1.0f;
+ speed.y += (Rand()-0.5f)*2.0f;
+ speed.z += (Rand()-0.5f)*2.0f;
+ speed = Transform(*mat, speed);
+ speed -= pos;
+ speed.y += 5.0f;
+
+ dim.x = 2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE2, 2.0f, 0.0f, 0.5f);
+ }
+ }
+ else
+ {
+ type = m_object->RetType();
+
+ if ( type == OBJECT_MOBILErc )
+ {
+ mat = m_object->RetWorldMatrix(2); // cannon
+ }
+ else
+ {
+ mat = m_object->RetWorldMatrix(1); // cannon
+ }
+
+ for ( i=0 ; i<3 ; i++ )
+ {
+ if ( type == OBJECT_MOBILErc )
+ {
+ pos = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ }
+ else
+ {
+ pos = D3DVECTOR(3.0f, 1.0f, 0.0f);
+ }
+ pos.y += (Rand()-0.5f)*1.0f;
+ pos.z += (Rand()-0.5f)*1.0f;
+ pos = Transform(*mat, pos);
+
+ speed = D3DVECTOR(200.0f, 0.0f, 0.0f);
+
+ physics = m_object->RetPhysics();
+ if ( physics != 0 )
+ {
+ speed += physics->RetLinMotion(MO_REASPEED);
+ }
+
+ speed.x += (Rand()-0.5f)*3.0f;
+ speed.y += (Rand()-0.5f)*6.0f;
+ speed.z += (Rand()-0.5f)*6.0f;
+ speed = Transform(*mat, speed);
+ speed -= pos;
+
+ dim.x = Rand()*0.7f+0.7f;
+ dim.y = dim.x;
+
+ channel = m_particule->CreateParticule(pos, speed, dim, PARTIGUN1, 0.8f, 0.0f, 0.0f);
+ m_particule->SetObjectFather(channel, m_object);
+ }
+
+ if ( type != OBJECT_MOBILErc &&
+ m_progress > 0.3f )
+ {
+ pos = D3DVECTOR(-1.0f, 1.0f, 0.0f);
+ pos.y += (Rand()-0.5f)*0.4f;
+ pos.z += (Rand()-0.5f)*0.4f;
+ pos = Transform(*mat, pos);
+
+ speed = D3DVECTOR(-4.0f, 0.0f, 0.0f);
+ speed.x += (Rand()-0.5f)*2.0f;
+ speed.y += (Rand()-0.2f)*4.0f;
+ speed.z += (Rand()-0.5f)*4.0f;
+ speed = Transform(*mat, speed);
+ speed -= pos;
+
+ dim.x = Rand()*1.2f+1.2f;
+ dim.y = dim.x;
+
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f, 0.0f, 0.0f);
+//? m_particule->CreateParticule(pos, speed, dim, PARTISMOKE2, 4.0f, 0.0f, 0.0f);
+ }
+ }
+
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ if ( m_progress < 0.1f )
+ {
+ dir.z = (PI*0.04f)*(m_progress*10.0f);
+ }
+ else if ( m_progress < 0.9f )
+ {
+ dir.z = (PI*0.04f);
+ }
+ else
+ {
+ dir.z = (PI*0.04f)*(1.0f-(m_progress-0.9f)*10.0f);
+ }
+ m_object->SetInclinaison(dir);
+
+ vib.x = (Rand()-0.5f)*0.01f;
+ vib.y = (Rand()-0.5f)*0.02f;
+ vib.z = (Rand()-0.5f)*0.02f;
+ m_object->SetCirVibration(vib);
+
+ vib.x = (Rand()-0.5f)*0.20f;
+ vib.y = (Rand()-0.5f)*0.05f;
+ vib.z = (Rand()-0.5f)*0.20f;
+ m_object->SetLinVibration(vib);
+ }
+
+ if ( m_bRay && m_lastSound <= 0.0f )
+ {
+ m_lastSound = Rand()*0.4f+0.4f;
+ m_sound->Play(SOUND_FIREp, m_object->RetPosition(0));
+ }
+
+ return TRUE;
+}
+
+
+// Assigns the goal was achieved.
+
+Error CTaskFire::Start(float delay)
+{
+ CObject* power;
+ D3DVECTOR pos, goal, speed;
+ float energy, fire;
+ ObjectType type;
+
+ m_bError = TRUE; // operation impossible
+
+ type = m_object->RetType();
+ if ( 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_MOBILErc ) return ERR_FIRE_VEH;
+
+//? if ( !m_physics->RetLand() ) return ERR_FIRE_FLY;
+
+ speed = m_physics->RetMotorSpeed();
+//? if ( speed.x != 0.0f ||
+//? speed.z != 0.0f ) return ERR_FIRE_MOTOR;
+
+ m_bRay = (type == OBJECT_MOBILErc);
+
+ m_bOrganic = FALSE;
+ if ( type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii )
+ {
+ m_bOrganic = TRUE;
+ }
+
+ if ( delay == 0.0f )
+ {
+ if ( m_bRay ) delay = 1.2f;
+ else delay = 2.0f;
+ }
+ m_delay = delay;
+
+ power = m_object->RetPower();
+ if ( power == 0 ) return ERR_FIRE_ENERGY;
+ energy = power->RetEnergy();
+ if ( m_bOrganic ) fire = m_delay*ENERGY_FIREi;
+ else if ( m_bRay ) fire = m_delay*ENERGY_FIREr;
+ else fire = m_delay*ENERGY_FIRE;
+ if ( energy < fire/power->RetCapacity()+0.05f ) return ERR_FIRE_ENERGY;
+
+ m_speed = 1.0f/m_delay;
+ m_progress = 0.0f;
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+ m_lastSound = 0.0f;
+ m_bError = FALSE; // ok
+
+//? m_camera->StartCentering(m_object, PI*0.15f, 99.9f, 0.0f, 1.0f);
+
+ if ( m_bOrganic )
+ {
+ m_soundChannel = m_sound->Play(SOUND_FIREi, m_object->RetPosition(0), 1.0f, 1.0f, TRUE);
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, m_delay, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 0.5f, SOPER_STOP);
+ }
+ }
+ else if ( m_bRay )
+ {
+ }
+ else
+ {
+ m_soundChannel = m_sound->Play(SOUND_FIRE, m_object->RetPosition(0), 1.0f, 1.0f, TRUE);
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, m_delay, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 0.5f, SOPER_STOP);
+ }
+ }
+
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskFire::IsEnded()
+{
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Suddenly ends the current action.
+
+BOOL CTaskFire::Abort()
+{
+ m_object->SetInclinaison(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_object->SetCirVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_object->SetLinVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+//? m_camera->StopCentering(m_object, 1.0f);
+ return TRUE;
+}
+
diff --git a/src/object/task/taskfire.h b/src/object/task/taskfire.h
new file mode 100644
index 0000000..af371b2
--- /dev/null
+++ b/src/object/task/taskfire.h
@@ -0,0 +1,61 @@
+// * 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/.
+
+// taskfire.h
+
+#ifndef _TASKFIRE_H_
+#define _TASKTIRE_H_
+
+
+#include "misc.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+class CTaskFire : public CTask
+{
+public:
+ CTaskFire(CInstanceManager* iMan, CObject* object);
+ ~CTaskFire();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(float delay);
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+
+protected:
+ float m_delay;
+ float m_progress;
+ BOOL m_bError;
+ BOOL m_bRay;
+ BOOL m_bOrganic;
+ float m_time;
+ float m_speed;
+ float m_lastParticule;
+ float m_lastSound;
+ int m_soundChannel;
+};
+
+
+#endif //_TASKFIRE_H_
diff --git a/src/object/task/taskfireant.cpp b/src/object/task/taskfireant.cpp
new file mode 100644
index 0000000..2c47adf
--- /dev/null
+++ b/src/object/task/taskfireant.cpp
@@ -0,0 +1,227 @@
+// * 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/.
+
+// taskfireant.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "motion.h"
+#include "motionant.h"
+#include "task.h"
+#include "taskfireant.h"
+
+
+
+
+// Object's constructor.
+
+CTaskFireAnt::CTaskFireAnt(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_phase = TFA_NULL;
+}
+
+// Object's destructor.
+
+CTaskFireAnt::~CTaskFireAnt()
+{
+}
+
+
+// Management of an event.
+
+BOOL CTaskFireAnt::EventProcess(const Event &event)
+{
+ D3DVECTOR dir, vib;
+ float a, g, cirSpeed;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ if ( m_object->RetFixed() ) // insect on its back?
+ {
+ m_bError = TRUE;
+ return FALSE;
+ }
+
+ m_time += event.rTime;
+ m_progress += event.rTime*m_speed;
+
+ if ( m_phase == TFA_TURN ) // preliminary rotation?
+ {
+ a = m_object->RetAngleY(0);
+ g = m_angle;
+ cirSpeed = Direction(a, g)*2.0f;
+ if ( cirSpeed > 2.0f ) cirSpeed = 2.0f;
+ if ( cirSpeed < -2.0f ) cirSpeed = -2.0f;
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // turns left/right
+ }
+
+ return TRUE;
+}
+
+
+// Assigns the goal was achieved.
+
+Error CTaskFireAnt::Start(D3DVECTOR impact)
+{
+ D3DVECTOR pos;
+ ObjectType type;
+
+ m_impact = impact;
+
+ m_bError = TRUE; // operation impossible
+ if ( !m_physics->RetLand() ) return ERR_FIRE_VEH;
+
+ type = m_object->RetType();
+ if ( type != OBJECT_ANT ) return ERR_FIRE_VEH;
+
+ // Insect on its back?
+ if ( m_object->RetFixed() ) return ERR_FIRE_VEH;
+
+ m_physics->SetMotorSpeed(D3DVECTOR(0.0f, 0.0f, 0.0f));
+
+ pos = m_object->RetPosition(0);
+ m_angle = RotateAngle(m_impact.x-pos.x, pos.z-m_impact.z); // CW !
+
+ m_phase = TFA_TURN;
+ m_speed = 1.0f/1.0f;
+ m_progress = 0.0f;
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+ m_bError = FALSE; // ok
+ m_bFire = FALSE; // once!
+
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskFireAnt::IsEnded()
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float angle, dist;
+ int i, channel;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+ if ( m_object->RetFixed() ) return ERR_STOP; // insect on its back?
+
+ if ( m_phase == TFA_TURN ) // rotation ?
+ {
+ angle = m_object->RetAngleY(0);
+ angle = NormAngle(angle); // 0..2*PI
+ if ( !TestAngle(angle, m_angle-PI*0.05f, m_angle+PI*0.05f) ) return ERR_CONTINUE;
+
+ m_physics->SetMotorSpeedZ(0.0f); // rotation ended
+
+ m_phase = TFA_PREPARE;
+//? m_speed = 1.0f/1.5f;
+ m_speed = 1.0f/0.4f;
+ m_progress = 0.0f;
+//? m_motion->SetAction(MAS_PREPARE, 1.5f);
+ m_motion->SetAction(MAS_PREPARE, 0.4f);
+ }
+
+ if ( m_phase == TFA_PREPARE ) // preparation?
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_phase = TFA_FIRE;
+//? m_speed = 1.0f/2.0f;
+ m_speed = 1.0f/0.5f;
+ m_progress = 0.0f;
+//? m_motion->SetAction(MAS_FIRE, 2.0f);
+ m_motion->SetAction(MAS_FIRE, 0.5f);
+ }
+
+ if ( m_phase == TFA_FIRE ) // shooting?
+ {
+ if ( m_progress > 0.75f && !m_bFire )
+ {
+ m_bFire = TRUE; // once
+
+ for ( i=0 ; i<20 ; i++ )
+ {
+ pos = D3DVECTOR(-2.5f, -0.7f, 0.0f);
+ mat = m_object->RetWorldMatrix(2);
+ pos = Transform(*mat, pos);
+ dist = Length(pos, m_impact);
+ speed = m_impact-pos;
+ speed.x += (Rand()-0.5f)*dist*1.2f;
+ speed.y += (Rand()-0.5f)*dist*0.4f+50.0f;
+ speed.z += (Rand()-0.5f)*dist*1.2f;
+ dim.x = 1.0f;
+ dim.y = dim.x;
+ channel = m_particule->CreateParticule(pos, speed, dim, PARTIGUN2, 2.0f, 100.0f, 0.0f);
+ m_particule->SetObjectFather(channel, m_object);
+ }
+ }
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_phase = TFA_TERMINATE;
+//? m_speed = 1.0f/0.9f;
+ m_speed = 1.0f/0.4f;
+ m_progress = 0.0f;
+//? m_motion->SetAction(MAS_TERMINATE, 0.9f);
+ m_motion->SetAction(MAS_TERMINATE, 0.4f);
+ }
+
+ if ( m_phase == TFA_TERMINATE ) // ends?
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_phase = TFA_NULL;
+ m_speed = 1.0f/1.0f;
+ m_progress = 0.0f;
+ }
+
+ Abort();
+ return ERR_STOP;
+}
+
+
+// Suddenly ends the current action.
+
+BOOL CTaskFireAnt::Abort()
+{
+ m_motion->SetAction(-1);
+ return TRUE;
+}
+
diff --git a/src/object/task/taskfireant.h b/src/object/task/taskfireant.h
new file mode 100644
index 0000000..2504241
--- /dev/null
+++ b/src/object/task/taskfireant.h
@@ -0,0 +1,72 @@
+// * 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/.
+
+// taskfireant.h
+
+#ifndef _TASKFIREANT_H_
+#define _TASKTIREANT_H_
+
+
+#include "d3dengine.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskFireAnt
+{
+ TFA_NULL = 0, // nothing to do
+ TFA_TURN = 1, // turns
+ TFA_PREPARE = 2, // prepares shooting position
+ TFA_FIRE = 3, // shooting
+ TFA_TERMINATE = 4, // ends shooting position
+};
+
+
+
+class CTaskFireAnt : public CTask
+{
+public:
+ CTaskFireAnt(CInstanceManager* iMan, CObject* object);
+ ~CTaskFireAnt();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(D3DVECTOR impact);
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+
+protected:
+ D3DVECTOR m_impact;
+ TaskFireAnt m_phase;
+ float m_progress;
+ float m_speed;
+ float m_angle;
+ BOOL m_bError;
+ BOOL m_bFire;
+ float m_time;
+ float m_lastParticule;
+};
+
+
+#endif //_TASKFIREANT_H_
diff --git a/src/object/task/taskflag.cpp b/src/object/task/taskflag.cpp
new file mode 100644
index 0000000..b965d08
--- /dev/null
+++ b/src/object/task/taskflag.cpp
@@ -0,0 +1,321 @@
+// * 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/.
+
+// taskflag.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "d3dengine.h"
+#include "d3dmath.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "terrain.h"
+#include "water.h"
+#include "object.h"
+#include "pyro.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "motion.h"
+#include "motionhuman.h"
+#include "sound.h"
+#include "task.h"
+#include "taskflag.h"
+
+
+
+
+
+// Object's constructor.
+
+CTaskFlag::CTaskFlag(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+}
+
+// Object's destructor.
+
+CTaskFlag::~CTaskFlag()
+{
+}
+
+
+// Management of an event.
+
+BOOL CTaskFlag::EventProcess(const Event &event)
+{
+ if ( m_bError ) return TRUE;
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_time += event.rTime;
+
+ return TRUE;
+}
+
+
+
+// Assigns the goal was achieved.
+
+Error CTaskFlag::Start(TaskFlagOrder order, int rank)
+{
+ D3DVECTOR pos, speed;
+ Error err;
+
+ m_order = order;
+ m_time = 0.0f;
+
+ m_bError = TRUE; // operation impossible
+ if ( !m_physics->RetLand() )
+ {
+ pos = m_object->RetPosition(0);
+ if ( pos.y < m_water->RetLevel() ) return ERR_FLAG_WATER;
+ return ERR_FLAG_FLY;
+ }
+
+ speed = m_physics->RetMotorSpeed();
+ if ( speed.x != 0.0f ||
+ speed.z != 0.0f ) return ERR_FLAG_MOTOR;
+
+ if ( m_object->RetFret() != 0 ) return ERR_FLAG_BUSY;
+
+ if ( order == TFL_CREATE )
+ {
+ err = CreateFlag(rank);
+ if ( err != ERR_OK ) return err;
+ }
+
+ if ( order == TFL_DELETE )
+ {
+ err = DeleteFlag();
+ if ( err != ERR_OK ) return err;
+ }
+
+ m_bError = FALSE;
+
+ m_motion->SetAction(MHS_FLAG); // sets/removes flag
+ m_camera->StartCentering(m_object, PI*0.3f, 99.9f, 0.0f, 0.5f);
+
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskFlag::IsEnded()
+{
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+
+ if ( m_bError ) return ERR_STOP;
+ if ( m_time < 2.0f ) return ERR_CONTINUE;
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Suddenly ends the current action.
+
+BOOL CTaskFlag::Abort()
+{
+ m_motion->SetAction(-1);
+ m_camera->StopCentering(m_object, 2.0f);
+ return TRUE;
+}
+
+
+
+// Returns the closest object to a given position.
+
+CObject* CTaskFlag::SearchNearest(D3DVECTOR pos, ObjectType type)
+{
+ ObjectType oType;
+ CObject *pObj, *pBest;
+ D3DVECTOR oPos;
+ float min, dist;
+ int i;
+
+ min = 100000.0f;
+ pBest = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetEnable() ) continue;
+
+ oType = pObj->RetType();
+ if ( type == OBJECT_NULL )
+ {
+ if ( oType != OBJECT_FLAGb &&
+ oType != OBJECT_FLAGr &&
+ oType != OBJECT_FLAGg &&
+ oType != OBJECT_FLAGy &&
+ oType != OBJECT_FLAGv ) continue;
+ }
+ else
+ {
+ if ( oType != type ) continue;
+ }
+
+ oPos = pObj->RetPosition(0);
+ dist = Length2d(oPos, pos);
+ if ( dist < min )
+ {
+ min = dist;
+ pBest = pObj;
+ }
+ }
+ return pBest;
+}
+
+// Counts the number of existing objects.
+
+int CTaskFlag::CountObject(ObjectType type)
+{
+ ObjectType oType;
+ CObject *pObj;
+ D3DVECTOR oPos;
+ int i, count;
+
+ count = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetEnable() ) continue;
+
+ oType = pObj->RetType();
+ if ( type == OBJECT_NULL )
+ {
+ if ( oType != OBJECT_FLAGb &&
+ oType != OBJECT_FLAGr &&
+ oType != OBJECT_FLAGg &&
+ oType != OBJECT_FLAGy &&
+ oType != OBJECT_FLAGv ) continue;
+ }
+ else
+ {
+ if ( oType != type ) continue;
+ }
+
+ count ++;
+ }
+ return count;
+}
+
+// Creates a color indicator.
+
+Error CTaskFlag::CreateFlag(int rank)
+{
+ CObject* pObj;
+ CObject* pNew;
+ CPyro* pyro;
+ D3DMATRIX* mat;
+ D3DVECTOR pos;
+ float dist;
+ int i;
+
+ ObjectType table[5] =
+ {
+ OBJECT_FLAGb,
+ OBJECT_FLAGr,
+ OBJECT_FLAGg,
+ OBJECT_FLAGy,
+ OBJECT_FLAGv,
+ };
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = Transform(*mat, D3DVECTOR(4.0f, 0.0f, 0.0f));
+
+ pObj = SearchNearest(pos, OBJECT_NULL);
+ if ( pObj != 0 )
+ {
+ dist = Length(pos, pObj->RetPosition(0));
+ if ( dist < 10.0f )
+ {
+ return ERR_FLAG_PROXY;
+ }
+ }
+
+ i = rank;
+ if ( CountObject(table[i]) >= 5 )
+ {
+ return ERR_FLAG_CREATE;
+ }
+
+ pNew = new CObject(m_iMan);
+ if ( !pNew->CreateFlag(pos, 0.0f, table[i]) )
+ {
+ delete pNew;
+ return ERR_TOOMANY;
+ }
+ pNew->SetZoom(0, 0.0f);
+
+ m_sound->Play(SOUND_WAYPOINT, pos);
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_FLCREATE, pNew);
+
+ return ERR_OK;
+}
+
+// Deletes a color indicator.
+
+Error CTaskFlag::DeleteFlag()
+{
+ CObject* pObj;
+ CPyro* pyro;
+ D3DVECTOR iPos, oPos;
+ float iAngle, angle, aLimit, dist;
+
+ iPos = m_object->RetPosition(0);
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+
+ pObj = SearchNearest(iPos, OBJECT_NULL);
+ if ( pObj == 0 )
+ {
+ return ERR_FLAG_DELETE;
+ }
+ dist = Length(iPos, pObj->RetPosition(0));
+ if ( dist > 10.0f )
+ {
+ return ERR_FLAG_DELETE;
+ }
+
+ oPos = pObj->RetPosition(0);
+ angle = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+ aLimit = 45.0f*PI/180.0f;
+ if ( !TestAngle(angle, iAngle-aLimit, iAngle+aLimit) )
+ {
+ return ERR_FLAG_DELETE;
+ }
+
+ m_sound->Play(SOUND_WAYPOINT, iPos);
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_FLDELETE, pObj);
+
+ return ERR_OK;
+}
+
diff --git a/src/object/task/taskflag.h b/src/object/task/taskflag.h
new file mode 100644
index 0000000..aa979f8
--- /dev/null
+++ b/src/object/task/taskflag.h
@@ -0,0 +1,66 @@
+// * 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/.
+// taskflag.h
+
+#ifndef _TASKFLAG_H_
+#define _TASKFLAG_H_
+
+
+#include "misc.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskFlagOrder
+{
+ TFL_CREATE = 0, // sets
+ TFL_DELETE = 1, // removes
+};
+
+
+
+class CTaskFlag : public CTask
+{
+public:
+ CTaskFlag(CInstanceManager* iMan, CObject* object);
+ ~CTaskFlag();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(TaskFlagOrder order, int rank);
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ Error CreateFlag(int rank);
+ Error DeleteFlag();
+ CObject* SearchNearest(D3DVECTOR pos, ObjectType type);
+ int CountObject(ObjectType type);
+
+protected:
+ TaskFlagOrder m_order;
+ float m_time;
+ BOOL m_bError;
+};
+
+
+#endif //_TASKFLAG_H_
diff --git a/src/object/task/taskgoto.cpp b/src/object/task/taskgoto.cpp
new file mode 100644
index 0000000..a6c836f
--- /dev/null
+++ b/src/object/task/taskgoto.cpp
@@ -0,0 +1,2352 @@
+// * 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
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "d3dengine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "terrain.h"
+#include "water.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "task.h"
+#include "taskgoto.h"
+
+
+
+#define FLY_DIST_GROUND 80.0f // minimum distance to remain on the ground
+#define FLY_DEF_HEIGHT 50.0f // default flying height
+#define BM_DIM_STEP 5.0f
+
+
+
+
+// Object's constructor.
+
+CTaskGoto::CTaskGoto(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_bmArray = 0;
+}
+
+// Object's destructor.
+
+CTaskGoto::~CTaskGoto()
+{
+ BitmapClose();
+}
+
+
+// Management of an event.
+
+BOOL CTaskGoto::EventProcess(const Event &event)
+{
+ D3DVECTOR pos, goal;
+ FPOINT 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 = Length(rot.x, rot.y);
+ rot.x /= dist;
+ rot.y /= dist;
+
+ a = m_object->RetAngleY(0);
+ g = RotateAngle(rot.x, -rot.y); // CW !
+ a = Direction(a, g)*1.0f;
+ cirSpeed = a;
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ a = NormAngle(a);
+ if ( a > PI*0.5f && a < 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
+ D3DVECTOR min, max;
+ min = pos;
+ max = m_goal;
+ if ( min.x > max.x ) Swap(min.x, max.x);
+ if ( min.z > max.z ) 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
+ D3DVECTOR min, max;
+ min = pos;
+ max = m_goal;
+ if ( min.x > max.x ) Swap(min.x, max.x);
+ if ( min.z > max.z ) 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 = Length2d(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 = 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 = Length(rot.x, rot.y);
+ rot.x /= dist;
+ rot.y /= dist;
+
+ a = m_object->RetAngleY(0);
+ g = RotateAngle(rot.x, -rot.y); // CW !
+ cirSpeed = 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)*Abs(cirSpeed);
+
+//? if ( dist < 20.0f && Abs(cirSpeed) >= 0.5f )
+ if ( Abs(cirSpeed) >= 0.2f )
+ {
+ linSpeed = 0.0f; // turns first, then advance
+ }
+
+ dist = Length2d(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 = RotateAngle(rot.x, -rot.y); // CW !
+ cirSpeed = 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 = Length2d(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 = RotateAngle(m_goal.x-pos.x, pos.z-m_goal.z); // CW !
+ cirSpeed = Direction(a, g)*1.0f;
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ dist = Length2d(m_goal, pos);
+ linSpeed = dist/(m_physics->RetLinStopLength()*1.5f);
+ if ( linSpeed > 1.0f ) linSpeed = 1.0f;
+
+ if ( dist < 20.0f && Abs(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 = Length(rot.x, rot.y);
+ 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 = RotateAngle(rot.x, -rot.y); // CW !
+ cirSpeed = 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 = Length2d(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)*Abs(cirSpeed);
+
+ if ( dist < 20.0f && Abs(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 = 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(D3DVECTOR &impact)
+{
+ CObject* pObj;
+ CObject* pBest = 0;
+ D3DVECTOR 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 = Length2d(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;
+ D3DVECTOR 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 = Length(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(D3DVECTOR goal, float altitude,
+ TaskGotoGoal goalMode, TaskGotoCrash crashMode)
+{
+ D3DVECTOR 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 = Length2d(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 = Length2d(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
+ D3DVECTOR min, max;
+ min = m_object->RetPosition(0);
+ max = m_goal;
+ if ( min.x > max.x ) Swap(min.x, max.x);
+ if ( min.z > max.z ) 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()
+{
+ D3DVECTOR 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 ( Abs(pos.x - m_bmPoints[m_bmIndex].x) < limit &&
+ Abs(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 = 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 = Length2d(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 ( Abs(pos.x - m_goal.x) < limit &&
+ Abs(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 = 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 = NormAngle(m_object->RetAngleY(0));
+ limit = 0.02f;
+ if ( m_bApprox ) limit = 0.10f;
+ if ( Abs(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(Abs(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 = PI/2.0f; // 90 deegres to the right
+ else angle = -PI/2.0f; // 90 deegres to the left
+ m_angle = NormAngle(m_object->RetAngleY(0)+angle);
+ m_phase = TGP_CRTURN;
+//? m_phase = TGP_ADVANCE;
+ }
+ }
+
+ if ( m_phase == TGP_CRTURN ) // turns after collision?
+ {
+ angle = NormAngle(m_object->RetAngleY(0));
+ limit = 0.1f;
+ if ( Abs(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 ( Length(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 = -PI;
+ if ( m_crashMode == TGC_LEFTRIGHT ) angle = PI;
+ if ( m_crashMode == TGC_RIGHT ) angle = PI/2.0f;
+ if ( m_crashMode == TGC_LEFT ) angle = -PI/2.0f;
+ m_angle = NormAngle(m_object->RetAngleY(0)+angle);
+ m_phase = TGP_CLTURN;
+ }
+ }
+
+ if ( m_phase == TGP_CLTURN ) // turns after collision?
+ {
+ angle = NormAngle(m_object->RetAngleY(0));
+ limit = 0.1f;
+ if ( Abs(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 ( Length(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 = Length(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(D3DVECTOR pos, float margin)
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR 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 = Length2d(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, D3DVECTOR &pos, float &distance)
+{
+ ObjectType type;
+ Character* character;
+ D3DMATRIX* mat;
+ D3DVECTOR 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 = Length(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 = Length(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(D3DVECTOR &pos, float margin, float &distance)
+{
+ CObject* pObj;
+ D3DVECTOR 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 = Length2d(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, D3DVECTOR &pos,
+ BOOL bTake, float distance, float &suppl)
+{
+ ObjectType type;
+ D3DMATRIX* mat;
+
+ pos = D3DVECTOR(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(D3DVECTOR &pos, float &delay)
+{
+ CObject *pObj, *pObstacle;
+ D3DVECTOR 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 = Length2d(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(FPOINT &dir)
+{
+#if 0
+ D3DVECTOR iPos, oPos;
+ FPOINT 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 = Length(oPos, m_goalObject);
+ if ( dist <= 1.0f ) continue;
+
+ pObj->GetGlobalSphere(oPos, oRadius);
+ oRadius += iRadius+m_physics->RetLinStopLength()*1.1f;
+ dist = Length2d(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;
+ D3DVECTOR iPos, oPos;
+ FPOINT 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 = Length(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 = Length(oPos, m_goal);
+ if ( dist <= 1.0f ) continue; // on purpose?
+
+ oRadius += iRadius+addi;
+ dist = Length2d(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;
+ D3DVECTOR 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 = Length2d(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()
+{
+ D3DVECTOR min, max;
+
+ BitmapOpen();
+ BitmapObject();
+
+ min = m_object->RetPosition(0);
+ max = m_goal;
+ if ( min.x > max.x ) Swap(min.x, max.x);
+ if ( min.z > max.z ) 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 D3DVECTOR &start, const D3DVECTOR &goal,
+ float goalRadius)
+{
+ float step, len;
+ int nbIter;
+
+ m_bmStep ++;
+
+ len = Length2d(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*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 D3DVECTOR &prevPos, const D3DVECTOR &curPos,
+ const D3DVECTOR &goalPos, float goalRadius,
+ float angle, int nbDiv, float step,
+ int i, int nbIter)
+{
+ D3DVECTOR 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 ( Length2d(curPos, goalPos)-goalRadius <= step )
+ {
+ if ( goalRadius == 0.0f )
+ {
+ newPos = goalPos;
+ }
+ else
+ {
+ newPos = BeamPoint(curPos, goalPos, 0, Length2d(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.
+
+D3DVECTOR CTaskGoto::BeamPoint(const D3DVECTOR &startPoint,
+ const D3DVECTOR &goalPoint,
+ float angle, float step)
+{
+ D3DVECTOR resPoint;
+ float goalAngle;
+
+ goalAngle = 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 D3DVECTOR &min, const D3DVECTOR &max,
+ const D3DVECTOR &start, const D3DVECTOR &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 ) Swap(minx, maxx);
+ if ( miny > maxy ) 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 D3DVECTOR &start, const D3DVECTOR &goal,
+ float stepAngle, BOOL bSecond)
+{
+ D3DVECTOR pos, inc;
+ float dist, step;
+ float distNoB2;
+ int i, max, x, y;
+
+ if ( m_bmArray == 0 ) return TRUE;
+
+ dist = Length2d(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;
+ D3DVECTOR 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 D3DVECTOR &min, const D3DVECTOR &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;
+ D3DVECTOR p;
+ float aLimit, angle, h;
+ int x, y;
+ BOOL bAcceptWater, bFly;
+
+ if ( minx > maxx ) Swap(minx, maxx);
+ if ( miny > maxy ) 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*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*PI/180.0f;
+ }
+
+ if ( type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEts ) // caterpillars?
+ {
+ aLimit = 35.0f*PI/180.0f;
+ }
+
+ if ( type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ) // large caterpillars?
+ {
+ aLimit = 35.0f*PI/180.0f;
+ }
+
+ if ( type == OBJECT_MOBILEsa ) // submarine caterpillars?
+ {
+ aLimit = 35.0f*PI/180.0f;
+ bAcceptWater = TRUE;
+ }
+
+ if ( type == OBJECT_MOBILEdr ) // designer caterpillars?
+ {
+ aLimit = 35.0f*PI/180.0f;
+ }
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEft ) // flying?
+ {
+ aLimit = 15.0f*PI/180.0f;
+ bFly = TRUE;
+ }
+
+ if ( type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILEii ) // insect legs?
+ {
+ aLimit = 60.0f*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 D3DVECTOR &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 = Length((float)(ix-cx), (float)(iy-cy));
+ if ( d > r ) continue;
+ BitmapSetDot(0, ix, iy);
+ }
+ }
+}
+
+// Removes a circle in the bitmap.
+
+void CTaskGoto::BitmapClearCircle(const D3DVECTOR &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 = Length((float)(ix-cx), (float)(iy-cy));
+ 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);
+}
+
+
diff --git a/src/object/task/taskgoto.h b/src/object/task/taskgoto.h
new file mode 100644
index 0000000..be54286
--- /dev/null
+++ b/src/object/task/taskgoto.h
@@ -0,0 +1,167 @@
+// * 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.h
+
+#ifndef _TASKGOTO_H_
+#define _TASKGOTO_H_
+
+
+#include "misc.h"
+#include "d3dengine.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+#define MAXPOINTS 500
+
+
+
+enum TaskGotoGoal
+{
+ TGG_DEFAULT = -1, // default mode
+ TGG_STOP = 0, // goes to destination pausing with precision
+ TGG_EXPRESS = 1, // goes to destination without stopping
+};
+
+enum TaskGotoCrash
+{
+ TGC_DEFAULT = -1, // default mode
+ TGC_HALT = 0, // stops if collision
+ TGC_RIGHTLEFT = 1, // right-left
+ TGC_LEFTRIGHT = 2, // left-right
+ TGC_LEFT = 3, // left
+ TGC_RIGHT = 4, // right
+ TGC_BEAM = 5, // algorithm "sunlight"
+};
+
+
+enum TaskGotoPhase
+{
+ TGP_ADVANCE = 1, // advance
+ TGP_LAND = 2, // landed
+ TGP_TURN = 3, // turns to finish
+ TGP_MOVE = 4, // advance to finish
+ TGP_CRWAIT = 5, // waits after collision
+ TGP_CRTURN = 6, // turns right after collision
+ TGP_CRADVANCE = 7, // advance to the right after collision
+ TGP_CLWAIT = 8, // waits after collision
+ TGP_CLTURN = 9, // turns left after collision
+ TGP_CLADVANCE = 10, // advance to the left after collision
+ TGP_BEAMLEAK = 11, // beam: leak (leaking)
+ TGP_BEAMSEARCH = 12, // beam: search
+ TGP_BEAMWCOLD = 13, // beam: expects cool reactor
+ TGP_BEAMUP = 14, // beam: off
+ TGP_BEAMGOTO = 15, // beam: goto dot list
+ TGP_BEAMDOWN = 16, // beam: landed
+};
+
+
+
+class CTaskGoto : public CTask
+{
+public:
+ CTaskGoto(CInstanceManager* iMan, CObject* object);
+ ~CTaskGoto();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(D3DVECTOR goal, float altitude, TaskGotoGoal goalMode, TaskGotoCrash crashMode);
+ Error IsEnded();
+
+protected:
+ CObject* WormSearch(D3DVECTOR &impact);
+ void WormFrame(float rTime);
+ CObject* SearchTarget(D3DVECTOR pos, float margin);
+ BOOL AdjustTarget(CObject* pObj, D3DVECTOR &pos, float &distance);
+ BOOL AdjustBuilding(D3DVECTOR &pos, float margin, float &distance);
+ BOOL GetHotPoint(CObject *pObj, D3DVECTOR &pos, BOOL bTake, float distance, float &suppl);
+ BOOL LeakSearch(D3DVECTOR &pos, float &delay);
+ void ComputeRepulse(FPOINT &dir);
+ void ComputeFlyingRepulse(float &dir);
+
+ int BeamShortcut();
+ void BeamStart();
+ void BeamInit();
+ Error BeamSearch(const D3DVECTOR &start, const D3DVECTOR &goal, float goalRadius);
+ Error BeamExplore(const D3DVECTOR &prevPos, const D3DVECTOR &curPos, const D3DVECTOR &goalPos, float goalRadius, float angle, int nbDiv, float step, int i, int nbIter);
+ D3DVECTOR BeamPoint(const D3DVECTOR &startPoint, const D3DVECTOR &goalPoint, float angle, float step);
+
+ void BitmapDebug(const D3DVECTOR &min, const D3DVECTOR &max, const D3DVECTOR &start, const D3DVECTOR &goal);
+ BOOL BitmapTestLine(const D3DVECTOR &start, const D3DVECTOR &goal, float stepAngle, BOOL bSecond);
+ void BitmapObject();
+ void BitmapTerrain(const D3DVECTOR &min, const D3DVECTOR &max);
+ void BitmapTerrain(int minx, int miny, int maxx, int maxy);
+ BOOL BitmapOpen();
+ BOOL BitmapClose();
+ void BitmapSetCircle(const D3DVECTOR &pos, float radius);
+ void BitmapClearCircle(const D3DVECTOR &pos, float radius);
+ void BitmapSetDot(int rank, int x, int y);
+ void BitmapClearDot(int rank, int x, int y);
+ BOOL BitmapTestDot(int rank, int x, int y);
+
+protected:
+ D3DVECTOR m_goal;
+ D3DVECTOR m_goalObject;
+ float m_angle;
+ float m_altitude;
+ TaskGotoCrash m_crashMode;
+ TaskGotoGoal m_goalMode;
+ TaskGotoPhase m_phase;
+ int m_try;
+ Error m_error;
+ BOOL m_bTake;
+ float m_stopLength; // braking distance
+ float m_time;
+ D3DVECTOR m_pos;
+ BOOL m_bWorm;
+ BOOL m_bApprox;
+ float m_wormLastTime;
+ float m_lastDistance;
+
+ int m_bmSize; // width or height of the table
+ int m_bmOffset; // m_bmSize/2
+ int m_bmLine; // increment line m_bmSize/8
+ unsigned char* m_bmArray; // bit table
+ int m_bmMinX, m_bmMinY;
+ int m_bmMaxX, m_bmMaxY;
+ int m_bmTotal; // number of points in m_bmPoints
+ int m_bmIndex; // index in m_bmPoints
+ D3DVECTOR m_bmPoints[MAXPOINTS+2];
+ char m_bmIter[MAXPOINTS+2];
+ int m_bmIterCounter;
+ CObject* m_bmFretObject;
+ float m_bmFinalMove; // final advance distance
+ float m_bmFinalDist; // effective distance to advance
+ D3DVECTOR m_bmFinalPos; // initial position before advance
+ float m_bmTimeLimit;
+ int m_bmStep;
+ D3DVECTOR m_bmWatchDogPos;
+ float m_bmWatchDogTime;
+ D3DVECTOR m_leakPos; // initial position leak
+ float m_leakDelay;
+ float m_leakTime;
+ BOOL m_bLeakRecede;
+};
+
+
+#endif //_TASKGOTO_H_
diff --git a/src/object/task/taskgungoal.cpp b/src/object/task/taskgungoal.cpp
new file mode 100644
index 0000000..7178d6c
--- /dev/null
+++ b/src/object/task/taskgungoal.cpp
@@ -0,0 +1,161 @@
+// * 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/.
+
+// taskgungoal.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "d3dengine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "object.h"
+#include "sound.h"
+#include "task.h"
+#include "taskgungoal.h"
+
+
+
+
+// Object's constructor.
+
+CTaskGunGoal::CTaskGunGoal(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+}
+
+// Object's destructor.
+
+CTaskGunGoal::~CTaskGunGoal()
+{
+}
+
+
+// Management of an event.
+
+BOOL CTaskGunGoal::EventProcess(const Event &event)
+{
+ float dir;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+
+ if ( m_progress < 1.0f )
+ {
+ dir = m_initialDirV + (m_finalDirV-m_initialDirV)*m_progress;
+ }
+ else
+ {
+ dir = m_finalDirV;
+ }
+ m_object->SetGunGoalV(dir);
+
+ if ( m_progress < 1.0f )
+ {
+ dir = m_initialDirH + (m_finalDirH-m_initialDirH)*m_progress;
+ }
+ else
+ {
+ dir = m_finalDirH;
+ }
+ m_object->SetGunGoalH(dir);
+
+ return TRUE;
+}
+
+
+// Assigns the goal was achieved.
+
+Error CTaskGunGoal::Start(float dirV, float dirH)
+{
+ float speedV, speedH;
+ int i;
+
+ m_initialDirV = m_object->RetGunGoalV();
+ m_object->SetGunGoalV(dirV);
+ m_finalDirV = m_object->RetGunGoalV(); // possible direction
+ m_object->SetGunGoalV(m_initialDirV); // gives initial direction
+
+ if ( m_finalDirV == m_initialDirV )
+ {
+ speedV = 100.0f;
+ }
+ else
+ {
+ speedV = 1.0f/(Abs(m_finalDirV-m_initialDirV)*1.0f);
+ }
+
+ m_initialDirH = m_object->RetGunGoalH();
+ m_object->SetGunGoalH(dirH);
+ m_finalDirH = m_object->RetGunGoalH(); // possible direction
+ m_object->SetGunGoalH(m_initialDirH); // gives initial direction
+
+ if ( m_finalDirH == m_initialDirH )
+ {
+ speedH = 100.0f;
+ }
+ else
+ {
+ speedH = 1.0f/(Abs(m_finalDirH-m_initialDirH)*1.0f);
+ }
+
+ m_speed = Min(speedV, speedH);
+
+ if ( m_finalDirV != m_initialDirV ||
+ m_finalDirH != m_initialDirH )
+ {
+ i = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.3f, 1.5f, TRUE);
+ m_sound->AddEnvelope(i, 0.3f, 1.5f, 1.0f/m_speed, SOPER_STOP);
+ }
+
+ m_progress = 0.0f;
+
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskGunGoal::IsEnded()
+{
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+
+ if ( m_initialDirV == m_finalDirV &&
+ m_initialDirH == m_finalDirH ) return ERR_STOP;
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_object->SetGunGoalV(m_finalDirV);
+ m_object->SetGunGoalH(m_finalDirH);
+ Abort();
+ return ERR_STOP;
+}
+
+// Suddenly ends the current action.
+
+BOOL CTaskGunGoal::Abort()
+{
+ return TRUE;
+}
+
diff --git a/src/object/task/taskgungoal.h b/src/object/task/taskgungoal.h
new file mode 100644
index 0000000..4b6cbc7
--- /dev/null
+++ b/src/object/task/taskgungoal.h
@@ -0,0 +1,57 @@
+// * 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/.
+
+// taskgungoal.h
+
+#ifndef _TASKGUNGOAL_H_
+#define _TASKGUNGOAL_H_
+
+
+#include "misc.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+class CTaskGunGoal : public CTask
+{
+public:
+ CTaskGunGoal(CInstanceManager* iMan, CObject* object);
+ ~CTaskGunGoal();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(float dirV, float dirH);
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+
+protected:
+ float m_progress;
+ float m_speed;
+ float m_initialDirV; // initial direction
+ float m_finalDirV; // direction to reach
+ float m_initialDirH; // initial direction
+ float m_finalDirH; // direction to reach
+};
+
+
+#endif //_TASKGUNGOAL_H_
diff --git a/src/object/task/taskinfo.cpp b/src/object/task/taskinfo.cpp
new file mode 100644
index 0000000..51deb79
--- /dev/null
+++ b/src/object/task/taskinfo.cpp
@@ -0,0 +1,233 @@
+// * 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/.
+
+// taskinfo.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "sound.h"
+#include "auto.h"
+#include "autoinfo.h"
+#include "task.h"
+#include "taskinfo.h"
+
+
+
+
+// Object's constructor.
+
+CTaskInfo::CTaskInfo(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+}
+
+// Object's destructor.
+
+CTaskInfo::~CTaskInfo()
+{
+}
+
+
+// Management of an event.
+
+BOOL CTaskInfo::EventProcess(const Event &event)
+{
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ m_progress += event.rTime*m_speed; // other advance
+ m_time += event.rTime;
+
+ return TRUE;
+}
+
+
+// Assigns the goal was achieved.
+
+Error CTaskInfo::Start(char *name, float value, float power, BOOL bSend)
+{
+ CObject* pInfo;
+ CAutoInfo* pAuto;
+ D3DVECTOR pos, goal;
+ Info info;
+ int i, total, op;
+
+ m_bError = TRUE;
+ m_object->SetInfoReturn(NAN);
+
+ pInfo = SearchInfo(power); // seeks terminal
+ if ( pInfo == 0 )
+ {
+ return ERR_INFO_NULL;
+ }
+
+ pAuto = (CAutoInfo*)pInfo->RetAuto();
+ if ( pAuto == 0 )
+ {
+ return ERR_INFO_NULL;
+ }
+
+ op = 1; // transmission impossible
+ if ( bSend ) // send?
+ {
+ total = pInfo->RetInfoTotal();
+ for ( i=0 ; i<total ; i++ )
+ {
+ info = pInfo->RetInfo(i);
+ if ( strcmp(info.name, name) == 0 )
+ {
+ info.value = value;
+ pInfo->SetInfo(i, info);
+ break;
+ }
+ }
+ if ( i == total )
+ {
+ if ( total < OBJECTMAXINFO )
+ {
+ strcpy(info.name, name);
+ info.value = value;
+ pInfo->SetInfo(total, info);
+ op = 2; // start of reception (for terminal)
+ }
+ }
+ else
+ {
+ op = 2; // start of reception (for terminal)
+ }
+ }
+ else // receive?
+ {
+ total = pInfo->RetInfoTotal();
+ for ( i=0 ; i<total ; i++ )
+ {
+ info = pInfo->RetInfo(i);
+ if ( strcmp(info.name, name) == 0 )
+ {
+ m_object->SetInfoReturn(info.value);
+ break;
+ }
+ }
+ if ( i < total )
+ {
+ op = 0; // beginning of transmission (for terminal)
+ }
+ }
+
+ pAuto->Start(op);
+
+ if ( op == 0 ) // transmission?
+ {
+ pos = pInfo->RetPosition(0);
+ pos.y += 9.5f;
+ goal = m_object->RetPosition(0);
+ goal.y += 4.0f;
+ m_particule->CreateRay(pos, goal, PARTIRAY3, FPOINT(2.0f, 2.0f), 1.0f);
+ }
+ if ( op == 2 ) // reception?
+ {
+ goal = pInfo->RetPosition(0);
+ goal.y += 9.5f;
+ pos = m_object->RetPosition(0);
+ pos.y += 4.0f;
+ m_particule->CreateRay(pos, goal, PARTIRAY3, FPOINT(2.0f, 2.0f), 1.0f);
+ }
+
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ m_time = 0.0f;
+
+ m_bError = FALSE; // ok
+
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskInfo::IsEnded()
+{
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+ m_progress = 0.0f;
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Suddenly ends the current action.
+
+BOOL CTaskInfo::Abort()
+{
+ return TRUE;
+}
+
+
+// Seeks the nearest information terminal.
+
+CObject* CTaskInfo::SearchInfo(float power)
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR iPos, oPos;
+ ObjectType type;
+ float dist, min;
+ int i;
+
+ iPos = m_object->RetPosition(0);
+
+ min = 100000.0f;
+ pBest = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_INFO ) continue;
+
+ if ( !pObj->RetActif() ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, iPos);
+ if ( dist > power ) continue; // too far?
+ if ( dist < min )
+ {
+ min = dist;
+ pBest = pObj;
+ }
+ }
+
+ return pBest;
+}
+
diff --git a/src/object/task/taskinfo.h b/src/object/task/taskinfo.h
new file mode 100644
index 0000000..26b2071
--- /dev/null
+++ b/src/object/task/taskinfo.h
@@ -0,0 +1,57 @@
+// * 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/.
+
+// taskinfo.h
+
+#ifndef _TASKINFO_H_
+#define _TASKINFO_H_
+
+
+#include "misc.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+class CTaskInfo : public CTask
+{
+public:
+ CTaskInfo(CInstanceManager* iMan, CObject* object);
+ ~CTaskInfo();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(char *name, float value, float power, BOOL bSend);
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ CObject* SearchInfo(float power);
+
+protected:
+ float m_progress;
+ float m_speed;
+ float m_time;
+ BOOL m_bError;
+};
+
+
+#endif //_TASKINFO_H_
diff --git a/src/object/task/taskmanager.cpp b/src/object/task/taskmanager.cpp
new file mode 100644
index 0000000..ffc0d05
--- /dev/null
+++ b/src/object/task/taskmanager.cpp
@@ -0,0 +1,291 @@
+// * 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/.
+
+// taskmanager.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "d3dengine.h"
+#include "misc.h"
+#include "iman.h"
+#include "event.h"
+#include "object.h"
+#include "task.h"
+#include "taskwait.h"
+#include "taskadvance.h"
+#include "taskturn.h"
+#include "taskgoto.h"
+#include "tasktake.h"
+#include "taskmanip.h"
+#include "taskflag.h"
+#include "taskbuild.h"
+#include "tasksearch.h"
+#include "taskterraform.h"
+#include "taskpen.h"
+#include "taskrecover.h"
+#include "taskshield.h"
+#include "taskinfo.h"
+#include "taskfire.h"
+#include "taskfireant.h"
+#include "taskgungoal.h"
+#include "taskspiderexplo.h"
+#include "taskreset.h"
+#include "taskmanager.h"
+
+
+
+
+// Object's constructor.
+
+CTaskManager::CTaskManager(CInstanceManager* iMan, CObject* object)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_TASKMANAGER, this, 100);
+
+ m_task = 0;
+ m_object = object;
+ m_bPilot = FALSE;
+}
+
+// Object's destructor.
+
+CTaskManager::~CTaskManager()
+{
+ delete m_task;
+}
+
+
+
+// Waits for a while.
+
+Error CTaskManager::StartTaskWait(float time)
+{
+ m_task = new CTaskWait(m_iMan, m_object);
+ return ((CTaskWait*)m_task)->Start(time);
+}
+
+// Advance straight ahead a certain distance.
+
+Error CTaskManager::StartTaskAdvance(float length)
+{
+ m_task = new CTaskAdvance(m_iMan, m_object);
+ return ((CTaskAdvance*)m_task)->Start(length);
+}
+
+// Turns through an certain angle.
+
+Error CTaskManager::StartTaskTurn(float angle)
+{
+ m_task = new CTaskTurn(m_iMan, m_object);
+ return ((CTaskTurn*)m_task)->Start(angle);
+}
+
+// Reaches a given position.
+
+Error CTaskManager::StartTaskGoto(D3DVECTOR pos, float altitude, TaskGotoGoal goalMode, TaskGotoCrash crashMode)
+{
+ m_task = new CTaskGoto(m_iMan, m_object);
+ return ((CTaskGoto*)m_task)->Start(pos, altitude, goalMode, crashMode);
+}
+
+// Move the manipulator arm.
+
+Error CTaskManager::StartTaskTake()
+{
+ m_task = new CTaskTake(m_iMan, m_object);
+ return ((CTaskTake*)m_task)->Start();
+}
+
+// Move the manipulator arm.
+
+Error CTaskManager::StartTaskManip(TaskManipOrder order, TaskManipArm arm)
+{
+ m_task = new CTaskManip(m_iMan, m_object);
+ return ((CTaskManip*)m_task)->Start(order, arm);
+}
+
+// Puts or removes a flag.
+
+Error CTaskManager::StartTaskFlag(TaskFlagOrder order, int rank)
+{
+ m_task = new CTaskFlag(m_iMan, m_object);
+ return ((CTaskFlag*)m_task)->Start(order, rank);
+}
+
+// Builds a building.
+
+Error CTaskManager::StartTaskBuild(ObjectType type)
+{
+ m_task = new CTaskBuild(m_iMan, m_object);
+ return ((CTaskBuild*)m_task)->Start(type);
+}
+
+// Probe the ground.
+
+Error CTaskManager::StartTaskSearch()
+{
+ m_task = new CTaskSearch(m_iMan, m_object);
+ return ((CTaskSearch*)m_task)->Start();
+}
+
+// Reads an information terminal.
+
+Error CTaskManager::StartTaskInfo(char *name, float value, float power, BOOL bSend)
+{
+ m_task = new CTaskInfo(m_iMan, m_object);
+ return ((CTaskInfo*)m_task)->Start(name, value, power, bSend);
+}
+
+// Terraforms the ground.
+
+Error CTaskManager::StartTaskTerraform()
+{
+ m_task = new CTaskTerraform(m_iMan, m_object);
+ return ((CTaskTerraform*)m_task)->Start();
+}
+
+// Changes the pencil.
+
+Error CTaskManager::StartTaskPen(BOOL bDown, int color)
+{
+ m_task = new CTaskPen(m_iMan, m_object);
+ return ((CTaskPen*)m_task)->Start(bDown, color);
+}
+
+// Recovers a ruin.
+
+Error CTaskManager::StartTaskRecover()
+{
+ m_task = new CTaskRecover(m_iMan, m_object);
+ return ((CTaskRecover*)m_task)->Start();
+}
+
+// Deploys the shield.
+
+Error CTaskManager::StartTaskShield(TaskShieldMode mode, float delay)
+{
+ if ( mode == TSM_UP )
+ {
+ m_task = new CTaskShield(m_iMan, m_object);
+ return ((CTaskShield*)m_task)->Start(mode, delay);
+ }
+ if ( mode == TSM_DOWN && m_task != 0 )
+ {
+ return ((CTaskShield*)m_task)->Start(mode, delay);
+ }
+ if ( mode == TSM_UPDATE && m_task != 0 )
+ {
+ return ((CTaskShield*)m_task)->Start(mode, delay);
+ }
+ return ERR_GENERIC;
+}
+
+// Shoots.
+
+Error CTaskManager::StartTaskFire(float delay)
+{
+ m_bPilot = TRUE;
+ m_task = new CTaskFire(m_iMan, m_object);
+ return ((CTaskFire*)m_task)->Start(delay);
+}
+
+// Shoots with the ant.
+
+Error CTaskManager::StartTaskFireAnt(D3DVECTOR impact)
+{
+ m_task = new CTaskFireAnt(m_iMan, m_object);
+ return ((CTaskFireAnt*)m_task)->Start(impact);
+}
+
+// Adjusts higher.
+
+Error CTaskManager::StartTaskGunGoal(float dirV, float dirH)
+{
+ m_task = new CTaskGunGoal(m_iMan, m_object);
+ return ((CTaskGunGoal*)m_task)->Start(dirV, dirH);
+}
+
+// Suicide of the spider.
+
+Error CTaskManager::StartTaskSpiderExplo()
+{
+ m_task = new CTaskSpiderExplo(m_iMan, m_object);
+ return ((CTaskSpiderExplo*)m_task)->Start();
+}
+
+// Reset.
+
+Error CTaskManager::StartTaskReset(D3DVECTOR goal, D3DVECTOR angle)
+{
+ m_task = new CTaskReset(m_iMan, m_object);
+ return ((CTaskReset*)m_task)->Start(goal, angle);
+}
+
+
+
+
+
+// Management of an event.
+
+BOOL CTaskManager::EventProcess(const Event &event)
+{
+ if ( m_task == 0 ) return FALSE;
+ return m_task->EventProcess(event);
+}
+
+
+// Indicates whether the action is finished.
+
+Error CTaskManager::IsEnded()
+{
+ if ( m_task == 0 ) return ERR_GENERIC;
+ return m_task->IsEnded();
+}
+
+
+// Indicates whether the action is pending.
+
+BOOL CTaskManager::IsBusy()
+{
+ if ( m_task == 0 ) return FALSE;
+ return m_task->IsBusy();
+}
+
+
+// Indicates whether it is possible to control the robot
+// during the execution of the current task.
+
+BOOL CTaskManager::IsPilot()
+{
+ return m_bPilot;
+}
+
+
+// Suddenly ends the current action.
+
+BOOL CTaskManager::Abort()
+{
+ if ( m_task == 0 ) return FALSE;
+ return m_task->Abort();
+}
+
+
diff --git a/src/object/task/taskmanager.h b/src/object/task/taskmanager.h
new file mode 100644
index 0000000..2c6c21f
--- /dev/null
+++ b/src/object/task/taskmanager.h
@@ -0,0 +1,77 @@
+// * 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/.
+
+// taskmanager.h
+
+#ifndef _TASKMANAGER_H_
+#define _TASKMANAGER_H_
+
+#include "misc.h"
+#include "object.h"
+#include "taskmanip.h"
+#include "taskgoto.h"
+#include "taskshield.h"
+#include "taskflag.h"
+
+
+class CInstanceManager;
+class CTask;
+
+
+
+class CTaskManager
+{
+public:
+ CTaskManager(CInstanceManager* iMan, CObject* object);
+ ~CTaskManager();
+
+ Error StartTaskWait(float time);
+ Error StartTaskAdvance(float length);
+ Error StartTaskTurn(float angle);
+ Error StartTaskGoto(D3DVECTOR pos, float altitude, TaskGotoGoal goalMode, TaskGotoCrash crashMode);
+ Error StartTaskTake();
+ Error StartTaskManip(TaskManipOrder order, TaskManipArm arm);
+ Error StartTaskFlag(TaskFlagOrder order, int rank);
+ Error StartTaskBuild(ObjectType type);
+ Error StartTaskSearch();
+ Error StartTaskInfo(char *name, float value, float power, BOOL bSend);
+ Error StartTaskTerraform();
+ Error StartTaskPen(BOOL bDown, int color);
+ Error StartTaskRecover();
+ Error StartTaskShield(TaskShieldMode mode, float delay);
+ Error StartTaskFire(float delay);
+ Error StartTaskFireAnt(D3DVECTOR impact);
+ Error StartTaskGunGoal(float dirV, float dirH);
+ Error StartTaskSpiderExplo();
+ Error StartTaskReset(D3DVECTOR goal, D3DVECTOR angle);
+
+ BOOL EventProcess(const Event &event);
+ Error IsEnded();
+ BOOL IsBusy();
+ BOOL IsPilot();
+ BOOL Abort();
+
+protected:
+
+protected:
+ CInstanceManager* m_iMan;
+ CTask* m_task;
+ CObject* m_object;
+ BOOL m_bPilot;
+};
+
+
+#endif //_TASKMANAGER_H_
diff --git a/src/object/task/taskmanip.cpp b/src/object/task/taskmanip.cpp
new file mode 100644
index 0000000..672b96e
--- /dev/null
+++ b/src/object/task/taskmanip.cpp
@@ -0,0 +1,1398 @@
+// * 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/.
+
+// taskmanip.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "d3dengine.h"
+#include "d3dmath.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "terrain.h"
+#include "object.h"
+#include "pyro.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "sound.h"
+#include "robotmain.h"
+#include "task.h"
+#include "taskmanip.h"
+
+
+//?#define MARGIN_FRONT 2.0f
+//?#define MARGIN_BACK 2.0f
+//?#define MARGIN_FRIEND 2.0f
+//?#define MARGIN_BEE 5.0f
+#define MARGIN_FRONT 4.0f //OK 1.9
+#define MARGIN_BACK 4.0f //OK 1.9
+#define MARGIN_FRIEND 4.0f //OK 1.9
+#define MARGIN_BEE 5.0f //OK 1.9
+
+
+
+
+// Object's constructor.
+
+CTaskManip::CTaskManip(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_arm = TMA_NEUTRAL;
+ m_hand = TMH_OPEN;
+}
+
+// Object's destructor.
+
+CTaskManip::~CTaskManip()
+{
+}
+
+
+// Management of an event.
+
+BOOL CTaskManip::EventProcess(const Event &event)
+{
+ D3DVECTOR pos;
+ float angle, a, g, cirSpeed, progress;
+ int i;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ if ( m_bBee ) // bee?
+ {
+ return TRUE;
+ }
+
+ if ( m_bTurn ) // preliminary rotation?
+ {
+ a = m_object->RetAngleY(0);
+ g = m_angle;
+ cirSpeed = Direction(a, g)*1.0f;
+ if ( m_physics->RetType() == TYPE_FLYING ) // flying on the ground?
+ {
+ cirSpeed *= 4.0f; // more fishing
+ }
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // turns left / right
+ return TRUE;
+ }
+
+ if ( m_move != 0 ) // preliminary advance?
+ {
+ m_timeLimit -= event.rTime;
+ m_physics->SetMotorSpeedX(m_move); // forward/backward
+ return TRUE;
+ }
+
+ m_progress += event.rTime*m_speed; // others advance
+ progress = m_progress;
+ if ( progress > 1.0f ) progress = 1.0f;
+
+ if ( m_bSubm ) // submarine?
+ {
+ if ( m_order == TMO_GRAB )
+ {
+ if ( m_step == 0 ) // fall?
+ {
+ pos = m_object->RetPosition(1);
+ pos.y = 3.0f-progress*2.0f;
+ m_object->SetPosition(1, pos);
+ }
+ if ( m_step == 1 ) // farm?
+ {
+ pos = m_object->RetPosition(2);
+ pos.z = -1.5f+progress*0.5f;
+ m_object->SetPosition(2, pos);
+
+ pos = m_object->RetPosition(3);
+ pos.z = 1.5f-progress*0.5f;
+ m_object->SetPosition(3, pos);
+ }
+ if ( m_step == 2 ) // up?
+ {
+ pos = m_object->RetPosition(1);
+ pos.y = 3.0f-(1.0f-progress)*2.0f;
+ m_object->SetPosition(1, pos);
+ }
+ }
+ else
+ {
+ if ( m_step == 0 ) // fall?
+ {
+ pos = m_object->RetPosition(1);
+ pos.y = 3.0f-progress*2.0f;
+ m_object->SetPosition(1, pos);
+ }
+ if ( m_step == 1 ) // farm?
+ {
+ pos = m_object->RetPosition(2);
+ pos.z = -1.5f+(1.0f-progress)*0.5f;
+ m_object->SetPosition(2, pos);
+
+ pos = m_object->RetPosition(3);
+ pos.z = 1.5f-(1.0f-progress)*0.5f;
+ m_object->SetPosition(3, pos);
+ }
+ if ( m_step == 2 ) // up?
+ {
+ pos = m_object->RetPosition(1);
+ pos.y = 3.0f-(1.0f-progress)*2.0f;
+ m_object->SetPosition(1, pos);
+ }
+ }
+ }
+ else
+ {
+ for ( i=0 ; i<5 ; i++ )
+ {
+ angle = (m_finalAngle[i]-m_initialAngle[i])*progress;
+ angle += m_initialAngle[i];
+ m_object->SetAngleZ(i+1, angle);
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Initializes the initial and final angles.
+
+void CTaskManip::InitAngle()
+{
+ CObject* power;
+ float max, energy;
+ int i;
+
+ if ( m_bSubm || m_bBee ) return;
+
+ if ( m_arm == TMA_NEUTRAL ||
+ m_arm == TMA_GRAB )
+ {
+ m_finalAngle[0] = ARM_NEUTRAL_ANGLE1; // arm
+ m_finalAngle[1] = ARM_NEUTRAL_ANGLE2; // forearm
+ m_finalAngle[2] = ARM_NEUTRAL_ANGLE3; // hand
+ }
+ if ( m_arm == TMA_STOCK )
+ {
+ m_finalAngle[0] = ARM_STOCK_ANGLE1; // arm
+ m_finalAngle[1] = ARM_STOCK_ANGLE2; // forearm
+ m_finalAngle[2] = ARM_STOCK_ANGLE3; // hand
+ }
+ if ( m_arm == TMA_FFRONT )
+ {
+ m_finalAngle[0] = 35.0f*PI/180.0f; // arm
+ m_finalAngle[1] = -95.0f*PI/180.0f; // forearm
+ m_finalAngle[2] = -27.0f*PI/180.0f; // hand
+ }
+ if ( m_arm == TMA_FBACK )
+ {
+ m_finalAngle[0] = 145.0f*PI/180.0f; // arm
+ m_finalAngle[1] = 95.0f*PI/180.0f; // forearm
+ m_finalAngle[2] = 27.0f*PI/180.0f; // hand
+ }
+ if ( m_arm == TMA_POWER )
+ {
+ m_finalAngle[0] = 95.0f*PI/180.0f; // arm
+ m_finalAngle[1] = 125.0f*PI/180.0f; // forearm
+ m_finalAngle[2] = 50.0f*PI/180.0f; // hand
+ }
+ if ( m_arm == TMA_OTHER )
+ {
+ if ( m_height <= 3.0f )
+ {
+ m_finalAngle[0] = 55.0f*PI/180.0f; // arm
+ m_finalAngle[1] = -90.0f*PI/180.0f; // forearm
+ m_finalAngle[2] = -35.0f*PI/180.0f; // hand
+ }
+ else
+ {
+ m_finalAngle[0] = 70.0f*PI/180.0f; // arm
+ m_finalAngle[1] = -90.0f*PI/180.0f; // forearm
+ m_finalAngle[2] = -50.0f*PI/180.0f; // hand
+ }
+ }
+
+ if ( m_hand == TMH_OPEN ) // open clamp?
+ {
+ m_finalAngle[3] = -PI*0.10f; // clamp close
+ m_finalAngle[4] = PI*0.10f; // clamp remote
+ }
+ if ( m_hand == TMH_CLOSE ) // clamp closed?
+ {
+ m_finalAngle[3] = PI*0.05f; // clamp close
+ m_finalAngle[4] = -PI*0.05f; // clamp remote
+ }
+
+ for ( i=0 ; i<5 ; i++ )
+ {
+ m_initialAngle[i] = m_object->RetAngleZ(i+1);
+ }
+
+ max = 0.0f;
+ for ( i=0 ; i<5 ; i++ )
+ {
+ max = Max(max, Abs(m_initialAngle[i] - m_finalAngle[i]));
+ }
+ m_speed = (PI*1.0f)/max;
+ if ( m_speed > 3.0f ) m_speed = 3.0f; // piano, ma non troppo (?)
+
+ energy = 0.0f;
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ energy = power->RetEnergy();
+ }
+
+ if ( energy == 0.0f )
+ {
+ m_speed *= 0.7f; // slower if more energy!
+ }
+}
+
+
+// Tests whether an object is compatible with the operation TMA_OTHER.
+
+BOOL TestFriend(ObjectType oType, ObjectType fType)
+{
+ if ( oType == OBJECT_ENERGY )
+ {
+ return ( fType == OBJECT_METAL );
+ }
+ if ( oType == OBJECT_LABO )
+ {
+ return ( fType == OBJECT_BULLET );
+ }
+ if ( oType == OBJECT_NUCLEAR )
+ {
+ return ( fType == OBJECT_URANIUM );
+ }
+
+ return ( fType == OBJECT_POWER ||
+ fType == OBJECT_ATOMIC );
+}
+
+// Assigns the goal was achieved.
+
+Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
+{
+ ObjectType type;
+ CObject *front, *other, *power;
+ CPyro *pyro;
+ float iAngle, dist, len;
+ float fDist, fAngle, oDist, oAngle, oHeight;
+ D3DVECTOR pos, fPos, oPos;
+
+ m_arm = arm;
+ m_height = 0.0f;
+ m_step = 0;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.5f;
+
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+ oAngle = iAngle;
+
+ m_bError = TRUE; // operation impossible
+
+ if ( m_arm != TMA_FFRONT &&
+ m_arm != TMA_FBACK &&
+ m_arm != TMA_POWER &&
+ m_arm != TMA_GRAB ) return ERR_MANIP_VEH;
+
+ m_physics->SetMotorSpeed(D3DVECTOR(0.0f, 0.0f, 0.0f));
+
+ type = m_object->RetType();
+ if ( type == OBJECT_BEE ) // bee?
+ {
+ if ( m_object->RetFret() == 0 )
+ {
+ if ( !m_physics->RetLand() ) return ERR_MANIP_FLY;
+
+ other = SearchTakeUnderObject(m_targetPos, MARGIN_BEE);
+ if ( other == 0 ) return ERR_MANIP_NIL;
+ m_object->SetFret(other); // takes the ball
+ other->SetTruck(m_object);
+ other->SetTruckPart(0); // taken with the base
+ other->SetPosition(0, D3DVECTOR(0.0f, -3.0f, 0.0f));
+ }
+ else
+ {
+ other = m_object->RetFret(); // other = ball
+ m_object->SetFret(0); // lick the ball
+ other->SetTruck(0);
+ pos = m_object->RetPosition(0);
+ pos.y -= 3.0f;
+ other->SetPosition(0, pos);
+
+ pos = m_object->RetPosition(0);
+ pos.y += 2.0f;
+ m_object->SetPosition(0, pos); // against the top of jump
+
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_FALL, other); // the ball falls
+ }
+
+ m_bBee = TRUE;
+ m_bError = FALSE; // ok
+ return ERR_OK;
+ }
+ m_bBee = FALSE;
+
+ m_bSubm = ( type == OBJECT_MOBILEsa ); // submarine?
+
+ if ( m_arm == TMA_GRAB ) // takes immediately?
+ {
+ TruckTakeObject();
+ Abort();
+ return ERR_OK;
+ }
+
+ m_energy = 0.0f;
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ m_energy = power->RetEnergy();
+ }
+
+ if ( !m_physics->RetLand() ) return ERR_MANIP_FLY;
+
+ if ( type != OBJECT_MOBILEfa &&
+ type != OBJECT_MOBILEta &&
+ type != OBJECT_MOBILEwa &&
+ type != OBJECT_MOBILEia &&
+ type != OBJECT_MOBILEsa ) return ERR_MANIP_VEH;
+
+ if ( m_bSubm ) // submarine?
+ {
+ m_arm = TMA_FFRONT; // only possible in front!
+ }
+
+ m_move = 0.0f; // advance not necessary
+ m_angle = iAngle;
+
+ if ( order == TMO_AUTO )
+ {
+ if ( m_object->RetFret() == 0 )
+ {
+ m_order = TMO_GRAB;
+ }
+ else
+ {
+ m_order = TMO_DROP;
+ }
+ }
+ else
+ {
+ m_order = order;
+ }
+
+ if ( m_order == TMO_GRAB && m_object->RetFret() != 0 )
+ {
+ return ERR_MANIP_BUSY;
+ }
+ if ( m_order == TMO_DROP && m_object->RetFret() == 0 )
+ {
+ return ERR_MANIP_EMPTY;
+ }
+
+//? speed = m_physics->RetMotorSpeed();
+//? if ( speed.x != 0.0f ||
+//? speed.z != 0.0f ) return ERR_MANIP_MOTOR;
+
+ if ( m_order == TMO_GRAB )
+ {
+ if ( m_arm == TMA_FFRONT )
+ {
+ front = SearchTakeFrontObject(TRUE, fPos, fDist, fAngle);
+ other = SearchOtherObject(TRUE, oPos, oDist, oAngle, oHeight);
+
+ if ( front != 0 && fDist < oDist )
+ {
+ m_targetPos = fPos;
+ m_angle = fAngle;
+ m_move = 1.0f; // advance required
+ }
+ else if ( other != 0 && oDist < fDist )
+ {
+ if ( other->RetPower() == 0 ) return ERR_MANIP_NIL;
+ m_targetPos = oPos;
+ m_angle = oAngle;
+ m_height = oHeight;
+ m_move = 1.0f; // advance required
+ m_arm = TMA_OTHER;
+ }
+ else
+ {
+ return ERR_MANIP_NIL;
+ }
+ m_main->HideDropZone(front); // hides buildable area
+ }
+ if ( m_arm == TMA_FBACK )
+ {
+ if ( SearchTakeBackObject(TRUE, m_targetPos, fDist, m_angle) == 0 )
+ {
+ return ERR_MANIP_NIL;
+ }
+ m_angle += PI;
+ m_move = -1.0f; // back necessary
+ }
+ if ( m_arm == TMA_POWER )
+ {
+ if ( m_object->RetPower() == 0 ) return ERR_MANIP_NIL;
+ }
+ }
+
+ if ( m_order == TMO_DROP )
+ {
+ if ( m_arm == TMA_FFRONT )
+ {
+ other = SearchOtherObject(TRUE, oPos, oDist, oAngle, oHeight);
+ if ( other != 0 && other->RetPower() == 0 )
+ {
+ m_targetPos = oPos;
+ m_angle = oAngle;
+ m_height = oHeight;
+ m_move = 1.0f; // advance required
+ m_arm = TMA_OTHER;
+ }
+ else
+ {
+ if ( !IsFreeDeposeObject(D3DVECTOR(TAKE_DIST, 0.0f, 0.0f)) ) return ERR_MANIP_OCC;
+ }
+ }
+ if ( m_arm == TMA_FBACK )
+ {
+ if ( !IsFreeDeposeObject(D3DVECTOR(-TAKE_DIST, 0.0f, 0.0f)) ) return ERR_MANIP_OCC;
+ }
+ if ( m_arm == TMA_POWER )
+ {
+ if ( m_object->RetPower() != 0 ) return ERR_MANIP_OCC;
+ }
+ }
+
+ dist = Length(m_object->RetPosition(0), m_targetPos);
+ len = dist-TAKE_DIST;
+ if ( m_arm == TMA_OTHER ) len -= TAKE_DIST_OTHER;
+ if ( len < 0.0f ) len = 0.0f;
+ if ( m_arm == TMA_FBACK ) len = -len;
+ m_advanceLength = dist-m_physics->RetLinLength(len);
+ if ( dist <= m_advanceLength+0.2f ) m_move = 0.0f; // not necessary to advance
+
+ if ( m_energy == 0.0f ) m_move = 0.0f;
+
+ if ( m_move != 0.0f ) // forward or backward?
+ {
+ m_timeLimit = m_physics->RetLinTimeLength(Abs(len))*1.5f;
+ if ( m_timeLimit < 0.5f ) m_timeLimit = 0.5f;
+ }
+
+ if ( m_object->RetFret() == 0 ) // not carrying anything?
+ {
+ m_hand = TMH_OPEN; // open clamp
+ }
+ else
+ {
+ m_hand = TMH_CLOSE; // closed clamp
+ }
+
+ InitAngle();
+
+ if ( iAngle == m_angle || m_energy == 0.0f )
+ {
+ m_bTurn = FALSE; // preliminary rotation unnecessary
+ SoundManip(1.0f/m_speed);
+ }
+ else
+ {
+ m_bTurn = TRUE; // preliminary rotation necessary
+ }
+
+ if ( m_bSubm )
+ {
+ m_camera->StartCentering(m_object, PI*0.8f, 99.9f, 0.0f, 0.5f);
+ }
+
+ m_physics->SetFreeze(TRUE); // it does not move
+
+ m_bError = FALSE; // ok
+ return ERR_OK;
+}
+
+// Indicates whether the action is complete.
+
+Error CTaskManip::IsEnded()
+{
+ CObject* fret;
+ D3DVECTOR pos;
+ float angle, dist;
+ int i;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_bBee ) // bee?
+ {
+ return ERR_STOP;
+ }
+
+ if ( m_bTurn ) // preliminary rotation?
+ {
+ angle = m_object->RetAngleY(0);
+ angle = NormAngle(angle); // 0..2*PI
+
+ if ( TestAngle(angle, m_angle-PI*0.01f, m_angle+PI*0.01f) )
+ {
+ m_bTurn = FALSE; // rotation ended
+ m_physics->SetMotorSpeedZ(0.0f);
+ if ( m_move == 0.0f )
+ {
+ SoundManip(1.0f/m_speed);
+ }
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_move != 0.0f ) // preliminary advance?
+ {
+ if ( m_timeLimit <= 0.0f )
+ {
+//OK 1.9
+ dist = Length(m_object->RetPosition(0), m_targetPos);
+ if ( dist <= m_advanceLength + 2.0f )
+ {
+ m_move = 0.0f; // advance ended
+ m_physics->SetMotorSpeedX(0.0f);
+ SoundManip(1.0f/m_speed);
+ return ERR_CONTINUE;
+ }
+ else
+ {
+//EOK 1.9
+ m_move = 0.0f; // advance ended
+ m_physics->SetMotorSpeedX(0.0f); // stops
+ Abort();
+ return ERR_STOP;
+ }
+ }
+
+ dist = Length(m_object->RetPosition(0), m_targetPos);
+ if ( dist <= m_advanceLength )
+ {
+ m_move = 0.0f; // advance ended
+ m_physics->SetMotorSpeedX(0.0f);
+ SoundManip(1.0f/m_speed);
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+ m_progress = 0.0f;
+
+ if ( !m_bSubm )
+ {
+ for ( i=0 ; i<5 ; i++ )
+ {
+ m_object->SetAngleZ(i+1, m_finalAngle[i]);
+ }
+ }
+ m_step ++;
+
+ if ( m_order == TMO_GRAB )
+ {
+ if ( m_step == 1 )
+ {
+ if ( m_bSubm ) m_speed = 1.0f/0.7f;
+ m_hand = TMH_CLOSE; // closes the clamp to take
+ InitAngle();
+ SoundManip(1.0f/m_speed, 0.8f, 1.5f);
+ return ERR_CONTINUE;
+ }
+ if ( m_step == 2 )
+ {
+ if ( m_bSubm ) m_speed = 1.0f/1.5f;
+ if ( !TruckTakeObject() &&
+ m_object->RetFret() == 0 )
+ {
+ m_hand = TMH_OPEN; // reopens the clamp
+ m_arm = TMA_NEUTRAL;
+ InitAngle();
+ SoundManip(1.0f/m_speed, 0.8f, 1.5f);
+ }
+ else
+ {
+ if ( (m_arm == TMA_OTHER ||
+ m_arm == TMA_POWER ) &&
+ (m_fretType == OBJECT_POWER ||
+ m_fretType == OBJECT_ATOMIC ) )
+ {
+ m_sound->Play(SOUND_POWEROFF, m_object->RetPosition(0));
+ }
+ m_arm = TMA_STOCK;
+ InitAngle();
+ SoundManip(1.0f/m_speed);
+ }
+ return ERR_CONTINUE;
+ }
+ }
+
+ if ( m_order == TMO_DROP )
+ {
+ if ( m_step == 1 )
+ {
+ if ( m_bSubm ) m_speed = 1.0f/0.7f;
+ fret = m_object->RetFret();
+ if ( TruckDeposeObject() )
+ {
+ if ( (m_arm == TMA_OTHER ||
+ m_arm == TMA_POWER ) &&
+ (m_fretType == OBJECT_POWER ||
+ m_fretType == OBJECT_ATOMIC ) )
+ {
+ m_sound->Play(SOUND_POWERON, m_object->RetPosition(0));
+ }
+ if ( fret != 0 && m_fretType == OBJECT_METAL && m_arm == TMA_FFRONT )
+ {
+ m_main->ShowDropZone(fret, m_object); // shows buildable area
+ }
+ m_hand = TMH_OPEN; // opens the clamp to deposit
+ SoundManip(1.0f/m_speed, 0.8f, 1.5f);
+ }
+ InitAngle();
+ return ERR_CONTINUE;
+ }
+ if ( m_step == 2 )
+ {
+ if ( m_bSubm ) m_speed = 1.0f/1.5f;
+ m_arm = TMA_NEUTRAL;
+ InitAngle();
+ SoundManip(1.0f/m_speed);
+ return ERR_CONTINUE;
+ }
+ }
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Suddenly ends the current action.
+
+BOOL CTaskManip::Abort()
+{
+ int i;
+
+ if ( m_object->RetFret() == 0 ) // not carrying anything?
+ {
+ m_hand = TMH_OPEN; // open clamp
+ m_arm = TMA_NEUTRAL;
+ }
+ else
+ {
+ m_hand = TMH_CLOSE; // closed clamp
+ m_arm = TMA_STOCK;
+ }
+ InitAngle();
+
+ if ( !m_bSubm )
+ {
+ for ( i=0 ; i<5 ; i++ )
+ {
+ m_object->SetAngleZ(i+1, m_finalAngle[i]);
+ }
+ }
+
+ m_camera->StopCentering(m_object, 2.0f);
+ m_physics->SetFreeze(FALSE); // is moving again
+ return TRUE;
+}
+
+
+// Seeks the object below to take (for bees).
+
+CObject* CTaskManip::SearchTakeUnderObject(D3DVECTOR &pos, float dLimit)
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR iPos, oPos;
+ ObjectType type;
+ float min, distance;
+ int i;
+
+ iPos = m_object->RetPosition(0);
+
+ min = 1000000.0f;
+ pBest = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+
+ if ( type != OBJECT_FRET &&
+ type != OBJECT_STONE &&
+ type != OBJECT_URANIUM &&
+ type != OBJECT_BULLET &&
+ type != OBJECT_METAL &&
+ type != OBJECT_POWER &&
+ type != OBJECT_ATOMIC &&
+ type != OBJECT_BBOX &&
+ type != OBJECT_KEYa &&
+ type != OBJECT_KEYb &&
+ type != OBJECT_KEYc &&
+ type != OBJECT_KEYd &&
+ type != OBJECT_TNT ) continue;
+
+ if ( pObj->RetTruck() != 0 ) continue; // object transported?
+ if ( pObj->RetLock() ) continue;
+ if ( pObj->RetZoomY(0) != 1.0f ) continue;
+
+ oPos = pObj->RetPosition(0);
+ distance = Length(oPos, iPos);
+ if ( distance <= dLimit &&
+ distance < min )
+ {
+ min = distance;
+ pBest = pObj;
+ }
+ }
+ if ( pBest != 0 )
+ {
+ pos = pBest->RetPosition(0);
+ }
+ return pBest;
+}
+
+// Seeks the object in front to take.
+
+CObject* CTaskManip::SearchTakeFrontObject(BOOL bAdvance, D3DVECTOR &pos,
+ float &distance, float &angle)
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR iPos, oPos;
+ ObjectType type;
+ float min, iAngle, bAngle, aLimit, dLimit, f;
+ int i;
+
+ iPos = m_object->RetPosition(0);
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+
+ if ( bAdvance && m_energy > 0.0f )
+ {
+ aLimit = 60.0f*PI/180.0f;
+ dLimit = MARGIN_FRONT+10.0f;
+ }
+ else
+ {
+//? aLimit = 7.0f*PI/180.0f;
+ aLimit = 15.0f*PI/180.0f; //OK 1.9
+ dLimit = MARGIN_FRONT;
+ }
+
+ min = 1000000.0f;
+ pBest = 0;
+ bAngle = 0.0f;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+
+ if ( type != OBJECT_FRET &&
+ type != OBJECT_STONE &&
+ type != OBJECT_URANIUM &&
+ type != OBJECT_BULLET &&
+ type != OBJECT_METAL &&
+ type != OBJECT_POWER &&
+ type != OBJECT_ATOMIC &&
+ 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 ) continue;
+
+ if ( pObj->RetTruck() != 0 ) continue; // object transported?
+ if ( pObj->RetLock() ) continue;
+ if ( pObj->RetZoomY(0) != 1.0f ) continue;
+
+ oPos = pObj->RetPosition(0);
+ distance = Abs(Length(oPos, iPos)-TAKE_DIST);
+ f = 1.0f-distance/50.0f;
+ if ( f < 0.5f ) f = 0.5f;
+
+ angle = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+ if ( !TestAngle(angle, iAngle-aLimit*f, iAngle+aLimit*f) ) continue;
+
+ if ( distance < -dLimit ||
+ distance > dLimit ) continue;
+
+ if ( distance < min )
+ {
+ min = distance;
+ pBest = pObj;
+ bAngle = angle;
+ }
+ }
+ if ( pBest == 0 )
+ {
+ distance = 1000000.0f;
+ angle = 0.0f;
+ }
+ else
+ {
+ pos = pBest->RetPosition(0);
+ distance = min;
+ angle = bAngle;
+ }
+ return pBest;
+}
+
+// Seeks the object back to take.
+
+CObject* CTaskManip::SearchTakeBackObject(BOOL bAdvance, D3DVECTOR &pos,
+ float &distance, float &angle)
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR iPos, oPos;
+ ObjectType type;
+ float min, iAngle, bAngle, aLimit, dLimit, f;
+ int i;
+
+ iPos = m_object->RetPosition(0);
+ iAngle = m_object->RetAngleY(0)+PI;
+ iAngle = NormAngle(iAngle); // 0..2*PI
+
+ if ( bAdvance && m_energy > 0.0f )
+ {
+ aLimit = 60.0f*PI/180.0f;
+ dLimit = MARGIN_BACK+5.0f;
+ }
+ else
+ {
+ aLimit = 7.0f*PI/180.0f;
+ dLimit = MARGIN_BACK;
+ }
+
+ min = 1000000.0f;
+ pBest = 0;
+ bAngle = 0.0f;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+
+ if ( type != OBJECT_FRET &&
+ type != OBJECT_STONE &&
+ type != OBJECT_URANIUM &&
+ type != OBJECT_BULLET &&
+ type != OBJECT_METAL &&
+ type != OBJECT_POWER &&
+ type != OBJECT_ATOMIC &&
+ 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 ) continue;
+
+ if ( pObj->RetTruck() != 0 ) continue; // object transported?
+ if ( pObj->RetLock() ) continue;
+ if ( pObj->RetZoomY(0) != 1.0f ) continue;
+
+ oPos = pObj->RetPosition(0);
+ distance = Abs(Length(oPos, iPos)-TAKE_DIST);
+ f = 1.0f-distance/50.0f;
+ if ( f < 0.5f ) f = 0.5f;
+
+ angle = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+ if ( !TestAngle(angle, iAngle-aLimit*f, iAngle+aLimit*f) ) continue;
+
+ if ( distance < -dLimit ||
+ distance > dLimit ) continue;
+
+ if ( distance < min )
+ {
+ min = distance;
+ pBest = pObj;
+ bAngle = angle;
+ }
+ }
+ if ( pBest == 0 )
+ {
+ distance = 1000000.0f;
+ angle = 0.0f;
+ }
+ else
+ {
+ pos = pBest->RetPosition(0);
+ distance = min;
+ angle = bAngle;
+ }
+ return pBest;
+}
+
+// Seeks the robot or building on which it wants to put a battery or or other object.
+
+CObject* CTaskManip::SearchOtherObject(BOOL bAdvance, D3DVECTOR &pos,
+ float &distance, float &angle,
+ float &height)
+{
+ Character* character;
+ CObject* pObj;
+ CObject* pPower;
+ D3DMATRIX* mat;
+ D3DVECTOR iPos, oPos;
+ ObjectType type, powerType;
+ float iAngle, iRad, oAngle, oLimit, aLimit, dLimit;
+ int i;
+
+ distance = 1000000.0f;
+ angle = 0.0f;
+
+ if ( m_bSubm ) return 0; // impossible with the submarine
+
+ if ( !m_object->GetCrashSphere(0, iPos, iRad) ) return 0;
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+
+ if ( bAdvance && m_energy > 0.0f )
+ {
+ aLimit = 60.0f*PI/180.0f;
+ dLimit = MARGIN_FRIEND+10.0f;
+ }
+ else
+ {
+ aLimit = 7.0f*PI/180.0f;
+ dLimit = MARGIN_FRIEND;
+ }
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue; // yourself?
+
+ type = pObj->RetType();
+ if ( type != OBJECT_MOBILEfa &&
+ type != OBJECT_MOBILEta &&
+ type != OBJECT_MOBILEwa &&
+ type != OBJECT_MOBILEia &&
+ 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_MOBILEfs &&
+ type != OBJECT_MOBILEts &&
+ type != OBJECT_MOBILEws &&
+ type != OBJECT_MOBILEis &&
+ 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_TOWER &&
+ type != OBJECT_RESEARCH &&
+ type != OBJECT_ENERGY &&
+ type != OBJECT_LABO &&
+ type != OBJECT_NUCLEAR ) continue;
+
+ pPower = pObj->RetPower();
+ if ( pPower != 0 )
+ {
+ if ( pPower->RetLock() ) continue;
+ if ( pPower->RetZoomY(0) != 1.0f ) continue;
+
+ powerType = pPower->RetType();
+ if ( powerType == OBJECT_NULL ||
+ powerType == OBJECT_FIX ) continue;
+ }
+
+ mat = pObj->RetWorldMatrix(0);
+ character = pObj->RetCharacter();
+ oPos = Transform(*mat, character->posPower);
+
+ oAngle = pObj->RetAngleY(0);
+ if ( type == OBJECT_TOWER ||
+ type == OBJECT_RESEARCH )
+ {
+ oLimit = 45.0f*PI/180.0f;
+ }
+ else if ( type == OBJECT_ENERGY )
+ {
+ oLimit = 90.0f*PI/180.0f;
+ }
+ else if ( type == OBJECT_LABO )
+ {
+ oLimit = 120.0f*PI/180.0f;
+ }
+ else if ( type == OBJECT_NUCLEAR )
+ {
+ oLimit = 45.0f*PI/180.0f;
+ }
+ else
+ {
+ oLimit = 45.0f*PI/180.0f;
+ oAngle += PI; // is behind
+ }
+ oAngle = NormAngle(oAngle); // 0..2*PI
+ angle = RotateAngle(iPos.x-oPos.x, oPos.z-iPos.z); // CW !
+ if ( !TestAngle(angle, oAngle-oLimit, oAngle+oLimit) ) continue;
+
+ distance = Abs(Length(oPos, iPos)-TAKE_DIST);
+ if ( distance <= dLimit )
+ {
+ angle = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+ if ( TestAngle(angle, iAngle-aLimit, iAngle+aLimit) )
+ {
+ character = pObj->RetCharacter();
+ height = character->posPower.y;
+ pos = oPos;
+ return pObj;
+ }
+ }
+ }
+
+ distance = 1000000.0f;
+ angle = 0.0f;
+ return 0;
+}
+
+// Takes the object placed in front.
+
+BOOL CTaskManip::TruckTakeObject()
+{
+ CObject* fret;
+ CObject* other;
+ D3DMATRIX matRotate;
+ D3DVECTOR pos;
+ float angle, dist;
+
+ if ( m_arm == TMA_GRAB ) // takes immediately?
+ {
+ fret = m_object->RetFret();
+ if ( fret == 0 ) return FALSE; // nothing to take?
+ m_fretType = fret->RetType();
+
+ if ( m_object->RetType() == OBJECT_HUMAN ||
+ m_object->RetType() == OBJECT_TECH )
+ {
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(4); // takes with the hand
+
+ fret->SetPosition(0, D3DVECTOR(1.7f, -0.5f, 1.1f));
+ fret->SetAngleY(0, 0.1f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.8f);
+ }
+ else if ( m_bSubm )
+ {
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(2); // takes with the right claw
+
+ pos = D3DVECTOR(1.1f, -1.0f, 1.0f); // relative
+ fret->SetPosition(0, pos);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleY(0, 0.0f);
+ fret->SetAngleZ(0, 0.0f);
+ }
+ else
+ {
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(3); // takes with the hand
+
+ pos = D3DVECTOR(4.7f, 0.0f, 0.0f); // relative to the hand (lem4)
+ fret->SetPosition(0, pos);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, PI/2.0f);
+ fret->SetAngleY(0, 0.0f);
+ }
+
+ m_object->SetFret(fret); // takes
+ }
+
+ if ( m_arm == TMA_FFRONT ) // takes on the ground in front?
+ {
+ fret = SearchTakeFrontObject(FALSE, pos, dist, angle);
+ if ( fret == 0 ) return FALSE; // nothing to take?
+ m_fretType = fret->RetType();
+
+ if ( m_bSubm )
+ {
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(2); // takes with the right claw
+
+ pos = D3DVECTOR(1.1f, -1.0f, 1.0f); // relative
+ fret->SetPosition(0, pos);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleY(0, 0.0f);
+ fret->SetAngleZ(0, 0.0f);
+ }
+ else
+ {
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(3); // takes with the hand
+
+ pos = D3DVECTOR(4.7f, 0.0f, 0.0f); // relative to the hand (lem4)
+ fret->SetPosition(0, pos);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, PI/2.0f);
+ fret->SetAngleY(0, 0.0f);
+ }
+
+ m_object->SetFret(fret); // takes
+ }
+
+ if ( m_arm == TMA_FBACK ) // takes on the ground behind?
+ {
+ fret = SearchTakeBackObject(FALSE, pos, dist, angle);
+ if ( fret == 0 ) return FALSE; // nothing to take?
+ m_fretType = fret->RetType();
+
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(3); // takes with the hand
+
+ pos = D3DVECTOR(4.7f, 0.0f, 0.0f); // relative to the hand (lem4)
+ fret->SetPosition(0, pos);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, PI/2.0f);
+ fret->SetAngleY(0, 0.0f);
+
+ m_object->SetFret(fret); // takes
+ }
+
+ if ( m_arm == TMA_POWER ) // takes battery in the back?
+ {
+ fret = m_object->RetPower();
+ if ( fret == 0 ) return FALSE; // no battery?
+ m_fretType = fret->RetType();
+
+ pos = D3DVECTOR(4.7f, 0.0f, 0.0f); // relative to the hand (lem4)
+ fret->SetPosition(0, pos);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, PI/2.0f);
+ fret->SetAngleY(0, 0.0f);
+ fret->SetTruckPart(3); // takes with the hand
+
+ m_object->SetPower(0);
+ m_object->SetFret(fret); // takes
+ }
+
+ if ( m_arm == TMA_OTHER ) // battery takes from friend?
+ {
+ other = SearchOtherObject(FALSE, pos, dist, angle, m_height);
+ if ( other == 0 ) return FALSE;
+
+ fret = other->RetPower();
+ if ( fret == 0 ) return FALSE; // the other does not have a battery?
+ m_fretType = fret->RetType();
+
+ other->SetPower(0);
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(3); // takes with the hand
+
+ pos = D3DVECTOR(4.7f, 0.0f, 0.0f); // relative to the hand (lem4)
+ fret->SetPosition(0, pos);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, PI/2.0f);
+ fret->SetAngleY(0, 0.0f);
+
+ m_object->SetFret(fret); // takes
+ }
+
+ return TRUE;
+}
+
+// Deposes the object taken.
+
+BOOL CTaskManip::TruckDeposeObject()
+{
+ Character* character;
+ CObject* fret;
+ CObject* other;
+ D3DMATRIX* mat;
+ D3DVECTOR pos;
+ float angle, dist;
+
+ if ( m_arm == TMA_FFRONT ) // deposits on the ground in front?
+ {
+ fret = m_object->RetFret();
+ if ( fret == 0 ) return FALSE; // nothing transported?
+ m_fretType = fret->RetType();
+
+ mat = fret->RetWorldMatrix(0);
+ pos = Transform(*mat, D3DVECTOR(0.0f, 1.0f, 0.0f));
+ m_terrain->MoveOnFloor(pos);
+ fret->SetPosition(0, pos);
+ fret->SetAngleY(0, m_object->RetAngleY(0)+PI/2.0f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.0f);
+ fret->FloorAdjust(); // plate well on the ground
+
+ fret->SetTruck(0);
+ m_object->SetFret(0); // deposit
+ }
+
+ if ( m_arm == TMA_FBACK ) // deposited on the ground behind?
+ {
+ fret = m_object->RetFret();
+ if ( fret == 0 ) return FALSE; // nothing transported?
+ m_fretType = fret->RetType();
+
+ mat = fret->RetWorldMatrix(0);
+ pos = Transform(*mat, D3DVECTOR(0.0f, 1.0f, 0.0f));
+ m_terrain->MoveOnFloor(pos);
+ fret->SetPosition(0, pos);
+ fret->SetAngleY(0, m_object->RetAngleY(0)+PI/2.0f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.0f);
+
+ fret->SetTruck(0);
+ m_object->SetFret(0); // deposit
+ }
+
+ if ( m_arm == TMA_POWER ) // deposits battery in the back?
+ {
+ fret = m_object->RetFret();
+ if ( fret == 0 ) return FALSE; // nothing transported?
+ m_fretType = fret->RetType();
+
+ if ( m_object->RetPower() != 0 ) return FALSE;
+
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(0); // carried by the base
+
+ character = m_object->RetCharacter();
+ fret->SetPosition(0, character->posPower);
+ fret->SetAngleY(0, 0.0f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.0f);
+
+ m_object->SetPower(fret); // uses
+ m_object->SetFret(0);
+ }
+
+ if ( m_arm == TMA_OTHER ) // deposits battery on friend?
+ {
+ other = SearchOtherObject(FALSE, pos, dist, angle, m_height);
+ if ( other == 0 ) return FALSE;
+
+ fret = other->RetPower();
+ if ( fret != 0 ) return FALSE; // the other already has a battery?
+
+ fret = m_object->RetFret();
+ if ( fret == 0 ) return FALSE;
+ m_fretType = fret->RetType();
+
+ other->SetPower(fret);
+ fret->SetTruck(other);
+
+ character = other->RetCharacter();
+ fret->SetPosition(0, character->posPower);
+ fret->SetAngleY(0, 0.0f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.0f);
+ fret->SetTruckPart(0); // carried by the base
+
+ m_object->SetFret(0); // deposit
+ }
+
+ return TRUE;
+}
+
+// Seeks if a location allows to deposit an object.
+
+BOOL CTaskManip::IsFreeDeposeObject(D3DVECTOR pos)
+{
+ CObject* pObj;
+ D3DMATRIX* mat;
+ D3DVECTOR iPos, oPos;
+ float oRadius;
+ int i, j;
+
+ mat = m_object->RetWorldMatrix(0);
+ iPos = Transform(*mat, pos);
+
+ 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; // inactive?
+ if ( pObj->RetTruck() != 0 ) continue; // object transported?
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ if ( Length(iPos, oPos)-(oRadius+1.0f) < 2.0f )
+ {
+ return FALSE; // location occupied
+ }
+ }
+ }
+ return TRUE; // location free
+}
+
+// Plays the sound of the manipulator arm.
+
+void CTaskManip::SoundManip(float time, float amplitude, float frequency)
+{
+ int i;
+
+ i = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.0f, 0.3f*frequency, TRUE);
+ m_sound->AddEnvelope(i, 0.5f*amplitude, 1.0f*frequency, 0.1f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.5f*amplitude, 1.0f*frequency, time-0.1f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.0f, 0.3f*frequency, 0.1f, SOPER_STOP);
+}
+
diff --git a/src/object/task/taskmanip.h b/src/object/task/taskmanip.h
new file mode 100644
index 0000000..bc746cf
--- /dev/null
+++ b/src/object/task/taskmanip.h
@@ -0,0 +1,109 @@
+// * 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/.
+
+// taskmanip.h
+
+#ifndef _TASKMANIP_H_
+#define _TASKMANIP_H_
+
+
+#include "task.h"
+#include "misc.h"
+#include "d3dengine.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskManipOrder
+{
+ TMO_AUTO = 0, // deposits or takes automatically
+ TMO_GRAB = 1, // takes an object
+ TMO_DROP = 2, // deposits the object
+};
+
+enum TaskManipArm
+{
+ TMA_NEUTRAL = 1, // empty arm at rest
+ TMA_STOCK = 2, // right arm resting
+ TMA_FFRONT = 3, // arm on the ground
+ TMA_FBACK = 4, // arm behind the robot
+ TMA_POWER = 5, // arm behind the robot
+ TMA_OTHER = 6, // arm behind a friend robot
+ TMA_GRAB = 7, // takes immediately
+};
+
+enum TaskManipHand
+{
+ TMH_OPEN = 1, // open clamp
+ TMH_CLOSE = 2, // closed clamp
+};
+
+
+
+class CTaskManip : public CTask
+{
+public:
+ CTaskManip(CInstanceManager* iMan, CObject* object);
+ ~CTaskManip();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(TaskManipOrder order, TaskManipArm arm);
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ void InitAngle();
+ CObject* SearchTakeUnderObject(D3DVECTOR &pos, float dLimit);
+ CObject* SearchTakeFrontObject(BOOL bAdvance, D3DVECTOR &pos, float &distance, float &angle);
+ CObject* SearchTakeBackObject(BOOL bAdvance, D3DVECTOR &pos, float &distance, float &angle);
+ CObject* SearchOtherObject(BOOL bAdvance, D3DVECTOR &pos, float &distance, float &angle, float &height);
+ BOOL TruckTakeObject();
+ BOOL TruckDeposeObject();
+ BOOL IsFreeDeposeObject(D3DVECTOR pos);
+ void SoundManip(float time, float amplitude=1.0f, float frequency=1.0f);
+
+protected:
+ TaskManipOrder m_order;
+ TaskManipArm m_arm;
+ TaskManipHand m_hand;
+ int m_step;
+ float m_speed;
+ float m_progress;
+ float m_initialAngle[5];
+ float m_finalAngle[5];
+ float m_height;
+ float m_advanceLength;
+ float m_energy;
+ BOOL m_bError;
+ BOOL m_bTurn;
+ BOOL m_bSubm;
+ BOOL m_bBee;
+ float m_angle;
+ float m_move;
+ D3DVECTOR m_targetPos;
+ float m_timeLimit;
+ ObjectType m_fretType;
+};
+
+
+#endif //_TASKMANIP_H_
diff --git a/src/object/task/taskpen.cpp b/src/object/task/taskpen.cpp
new file mode 100644
index 0000000..7d95f21
--- /dev/null
+++ b/src/object/task/taskpen.cpp
@@ -0,0 +1,304 @@
+// * 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/.
+
+// taskpen.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "sound.h"
+#include "motion.h"
+#include "motionant.h"
+#include "motionspider.h"
+#include "task.h"
+#include "taskpen.h"
+
+
+
+// Object's constructor.
+
+CTaskPen::CTaskPen(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+}
+
+// Object's destructor.
+
+CTaskPen::~CTaskPen()
+{
+}
+
+
+// Management of an event.
+
+BOOL CTaskPen::EventProcess(const Event &event)
+{
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ int i;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ if ( m_delay == 0.0f )
+ {
+ m_progress = 1.0f;
+ }
+ else
+ {
+ m_progress += event.rTime*(1.0f/m_delay); // others advance
+ if ( m_progress > 1.0f ) m_progress = 1.0f;
+ }
+
+ m_time += event.rTime;
+
+ if ( m_phase == TPP_UP ) // back the pencil
+ {
+ i = AngleToRank(m_object->RetAngleY(1));
+ pos = m_object->RetPosition(10+i);
+ pos.y = -3.2f*(1.0f-m_progress);
+ m_object->SetPosition(10+i, pos);
+ }
+
+ if ( m_phase == TPP_TURN ) // turns the carousel?
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_supportPos;
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ speed.x = (Rand()-0.5f)*3.0f;
+ speed.z = (Rand()-0.5f)*3.0f;
+ speed.y = Rand()*2.0f;
+ dim.x = Rand()*1.5f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE3, 4.0f);
+ }
+
+ m_object->SetAngleY(1, m_oldAngle+(m_newAngle-m_oldAngle)*m_progress);
+ }
+
+ if ( m_phase == TPP_DOWN ) // down the pencil?
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_supportPos;
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ speed.x = (Rand()-0.5f)*3.0f;
+ speed.z = (Rand()-0.5f)*3.0f;
+ speed.y = Rand()*5.0f;
+ dim.x = Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIVAPOR, 4.0f);
+ }
+
+ i = AngleToRank(m_object->RetAngleY(1));
+ pos = m_object->RetPosition(10+i);
+ if ( m_timeDown == 0.0f )
+ {
+ pos.y = 0.0f;
+ }
+ else
+ {
+ pos.y = -3.2f*Bounce(Min(m_progress*1.8f, 1.0f));
+ }
+ m_object->SetPosition(10+i, pos);
+ }
+
+ return TRUE;
+}
+
+
+// Assigns the goal has achieved.
+
+Error CTaskPen::Start(BOOL bDown, int color)
+{
+ D3DVECTOR pos;
+ D3DMATRIX* mat;
+ ObjectType type;
+ int i;
+
+ m_bError = TRUE; // operation impossible
+
+ type = m_object->RetType();
+ if ( type != OBJECT_MOBILEdr ) return ERR_FIRE_VEH;
+
+ m_bError = FALSE; // ok
+
+ m_oldAngle = m_object->RetAngleY(1);
+ m_newAngle = ColorToAngle(color);
+
+ i = AngleToRank(m_oldAngle);
+ pos = m_object->RetPosition(10+i);
+
+ if ( pos.y == 0.0f ) // pencil at the top?
+ {
+ m_timeUp = 0.0f;
+ }
+ else // pencil on the bottom?
+ {
+ m_timeUp = 1.0f; // must rise up
+ }
+
+ if ( bDown ) // must go down ?
+ {
+ m_timeDown = 0.7f;
+ }
+ else
+ {
+ m_timeDown = 0.0f;
+ }
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(-3.0f, 7.0f, 0.0f);
+ pos = Transform(*mat, pos); // position of carousel
+ m_supportPos = pos;
+
+ m_phase = TPP_UP;
+ m_progress = 0.0f;
+ m_delay = m_timeUp;
+ m_time = 0.0f;
+
+ if ( m_timeUp > 0.0f )
+ {
+ SoundManip(m_timeUp, 1.0f, 0.5f);
+ }
+
+ m_lastParticule = 0.0f;
+
+//? m_camera->StartCentering(m_object, PI*0.60f, 99.9f, 5.0f, 0.5f);
+
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskPen::IsEnded()
+{
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+ m_progress = 0.0f;
+
+ if ( m_phase == TPP_UP )
+ {
+ m_phase = TPP_TURN;
+ m_progress = 0.0f;
+ m_delay = Abs(m_oldAngle-m_newAngle)/PI;
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+ if ( m_delay > 0.0f )
+ {
+ SoundManip(m_delay, 1.0f, 1.0f);
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TPP_TURN )
+ {
+ m_sound->Play(SOUND_PSHHH2, m_supportPos, 1.0f, 1.4f);
+ m_phase = TPP_DOWN;
+ m_progress = 0.0f;
+ m_delay = m_timeDown;
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+ return ERR_CONTINUE;
+ }
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Suddenly ends the current action.
+
+BOOL CTaskPen::Abort()
+{
+//? m_camera->StopCentering(m_object, 0.5f);
+ return TRUE;
+}
+
+
+// Plays the sound of the manipulator arm.
+
+void CTaskPen::SoundManip(float time, float amplitude, float frequency)
+{
+ int i;
+
+ i = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.0f, 0.3f*frequency, TRUE);
+ m_sound->AddEnvelope(i, 0.5f*amplitude, 1.0f*frequency, 0.1f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.5f*amplitude, 1.0f*frequency, time-0.1f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.0f, 0.3f*frequency, 0.1f, SOPER_STOP);
+}
+
+
+// Converting a angle to number of pencil.
+
+int CTaskPen::AngleToRank(float angle)
+{
+//? return (int)(angle/(-45.0f*PI/180.0f));
+ angle = -angle;
+ angle += (45.0f*PI/180.0f)/2.0f;
+ return (int)(angle/(45.0f*PI/180.0f));
+}
+
+// Converting a color to the angle of carousel of pencils.
+
+float CTaskPen::ColorToAngle(int color)
+{
+ return -45.0f*PI/180.0f*ColorToRank(color);
+}
+
+// Converting a color number to the pencil (0 .. 7).
+
+int CTaskPen::ColorToRank(int color)
+{
+ if ( color == 8 ) return 1; // yellow
+ if ( color == 7 ) return 2; // orange
+ if ( color == 5 ) return 2; // pink
+ if ( color == 4 ) return 3; // red
+ if ( color == 6 ) return 4; // purple
+ if ( color == 14 ) return 5; // blue
+ if ( color == 15 ) return 5; // light blue
+ if ( color == 12 ) return 6; // green
+ if ( color == 13 ) return 6; // light green
+ if ( color == 10 ) return 7; // brown
+ if ( color == 9 ) return 7; // beige
+ return 0; // black
+}
+
diff --git a/src/object/task/taskpen.h b/src/object/task/taskpen.h
new file mode 100644
index 0000000..752a52d
--- /dev/null
+++ b/src/object/task/taskpen.h
@@ -0,0 +1,77 @@
+// * 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/.
+
+// taskpen.h
+
+#ifndef _TASKSPEN_H_
+#define _TASKSPEN_H_
+
+
+#include "d3dengine.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskPenPhase
+{
+ TPP_UP = 1, // rises the pencil
+ TPP_TURN = 2, // turns the carousel
+ TPP_DOWN = 3, // descends the pencil
+};
+
+
+
+class CTaskPen : public CTask
+{
+public:
+ CTaskPen(CInstanceManager* iMan, CObject* object);
+ ~CTaskPen();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(BOOL bDown, int color);
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ void SoundManip(float time, float amplitude, float frequency);
+ int AngleToRank(float angle);
+ float ColorToAngle(int color);
+ int ColorToRank(int color);
+
+protected:
+ BOOL m_bError;
+ TaskPenPhase m_phase;
+ float m_progress;
+ float m_delay;
+ float m_time;
+ float m_lastParticule;
+ D3DVECTOR m_supportPos;
+
+ float m_timeUp;
+ float m_oldAngle;
+ float m_newAngle;
+ float m_timeDown;
+};
+
+
+#endif //_TASKSPEN_H_
diff --git a/src/object/task/taskrecover.cpp b/src/object/task/taskrecover.cpp
new file mode 100644
index 0000000..1284bb5
--- /dev/null
+++ b/src/object/task/taskrecover.cpp
@@ -0,0 +1,431 @@
+// * 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/.
+
+// taskrecover.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "sound.h"
+#include "displaytext.h"
+#include "task.h"
+#include "taskrecover.h"
+
+
+#define ENERGY_RECOVER 0.25f // energy consumed by recovery
+#define RECOVER_DIST 11.8f
+
+
+
+// Object's constructor.
+
+CTaskRecover::CTaskRecover(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_ruin = 0;
+ m_soundChannel = -1;
+}
+
+// Object's constructor.
+
+CTaskRecover::~CTaskRecover()
+{
+}
+
+
+// Management of an event.
+
+BOOL CTaskRecover::EventProcess(const Event &event)
+{
+ CObject* power;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float a, g, cirSpeed, angle, energy, dist, linSpeed;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ if ( m_phase == TRP_TURN ) // preliminary rotation?
+ {
+ a = m_object->RetAngleY(0);
+ g = m_angle;
+ cirSpeed = 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
+ return TRUE;
+ }
+
+ m_progress += event.rTime*m_speed; // others advance
+ m_time += event.rTime;
+
+ if ( m_phase == TRP_DOWN )
+ {
+ angle = Prop(126, -10, m_progress);
+ m_object->SetAngleZ(2, angle);
+ m_object->SetAngleZ(4, angle);
+
+ angle = Prop(-144, 0, m_progress);
+ m_object->SetAngleZ(3, angle);
+ m_object->SetAngleZ(5, angle);
+ }
+
+ if ( m_phase == TRP_MOVE ) // preliminary forward/backward?
+ {
+ dist = Length(m_object->RetPosition(0), m_ruin->RetPosition(0));
+ linSpeed = 0.0f;
+ if ( dist > RECOVER_DIST ) linSpeed = 1.0f;
+ if ( dist < RECOVER_DIST ) linSpeed = -1.0f;
+ m_physics->SetMotorSpeedX(linSpeed); // forward/backward
+ return TRUE;
+ }
+
+ if ( m_phase == TRP_OPER )
+ {
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ energy = power->RetEnergy();
+ power->SetEnergy(energy-ENERGY_RECOVER*event.rTime*m_speed);
+ }
+
+ speed.x = (Rand()-0.5f)*0.1f*m_progress;
+ speed.y = (Rand()-0.5f)*0.1f*m_progress;
+ speed.z = (Rand()-0.5f)*0.1f*m_progress;
+ m_ruin->SetCirVibration(speed);
+
+ if ( m_progress >= 0.75f )
+ {
+ m_ruin->SetZoom(0, 1.0f-(m_progress-0.75f)/0.25f);
+ }
+
+ if ( m_progress > 0.5f && m_progress < 0.8f )
+ {
+ m_metal->SetZoom(0, (m_progress-0.5f)/0.3f);
+ }
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.02f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_recoverPos;
+ pos.x += (Rand()-0.5f)*8.0f*(1.0f-m_progress);
+ pos.z += (Rand()-0.5f)*8.0f*(1.0f-m_progress);
+ pos.y -= 4.0f;
+ speed.x = (Rand()-0.5f)*0.0f;
+ speed.z = (Rand()-0.5f)*0.0f;
+ speed.y = Rand()*15.0f;
+ dim.x = Rand()*2.0f+1.5f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIRECOVER, 1.0f, 0.0f, 0.0f);
+ }
+ }
+
+ if ( m_phase == TRP_UP )
+ {
+ angle = Prop(-10, 126, m_progress);
+ m_object->SetAngleZ(2, angle);
+ m_object->SetAngleZ(4, angle);
+
+ angle = Prop(0, -144, m_progress);
+ m_object->SetAngleZ(3, angle);
+ m_object->SetAngleZ(5, angle);
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.02f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_recoverPos;
+ pos.y -= 4.0f;
+ speed.x = (Rand()-0.5f)*0.0f;
+ speed.z = (Rand()-0.5f)*0.0f;
+ speed.y = Rand()*15.0f;
+ dim.x = Rand()*2.0f+1.5f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIRECOVER, 1.0f, 0.0f, 0.0f);
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Assigns the goal was achieved.
+
+Error CTaskRecover::Start()
+{
+ CObject* power;
+ D3DMATRIX* mat;
+ D3DVECTOR pos, iPos, oPos;
+ float energy;
+
+ ObjectType type;
+
+ m_bError = TRUE; // operation impossible
+ if ( !m_physics->RetLand() ) return ERR_RECOVER_VEH;
+
+ type = m_object->RetType();
+ if ( type != OBJECT_MOBILErr ) return ERR_RECOVER_VEH;
+
+ power = m_object->RetPower();
+ if ( power == 0 ) return ERR_RECOVER_ENERGY;
+ energy = power->RetEnergy();
+ if ( energy < ENERGY_RECOVER/power->RetCapacity()+0.05f ) return ERR_RECOVER_ENERGY;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(RECOVER_DIST, 3.3f, 0.0f);
+ pos = Transform(*mat, pos); // position in front
+ m_recoverPos = pos;
+
+ m_ruin = SearchRuin();
+ if ( m_ruin == 0 ) return ERR_RECOVER_NULL;
+ m_ruin->SetLock(TRUE); // ruin no longer usable
+
+ iPos = m_object->RetPosition(0);
+ oPos = m_ruin->RetPosition(0);
+ m_angle = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+
+ m_metal = 0;
+
+ m_phase = TRP_TURN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+
+ m_bError = FALSE; // ok
+
+ m_camera->StartCentering(m_object, PI*0.85f, 99.9f, 10.0f, 3.0f);
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskRecover::IsEnded()
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, speed, goal;
+ FPOINT dim;
+ float angle, dist, time;
+ int i;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_phase == TRP_TURN ) // preliminary rotation?
+ {
+ angle = m_object->RetAngleY(0);
+ angle = NormAngle(angle); // 0..2*PI
+
+ if ( TestAngle(angle, m_angle-PI*0.01f, m_angle+PI*0.01f) )
+ {
+ m_physics->SetMotorSpeedZ(0.0f);
+
+ dist = Length(m_object->RetPosition(0), m_ruin->RetPosition(0));
+ if ( dist > RECOVER_DIST )
+ {
+ time = m_physics->RetLinTimeLength(dist-RECOVER_DIST, 1.0f);
+ m_speed = 1.0f/time;
+ }
+ else
+ {
+ time = m_physics->RetLinTimeLength(RECOVER_DIST-dist, -1.0f);
+ m_speed = 1.0f/time;
+ }
+ m_phase = TRP_MOVE;
+ m_progress = 0.0f;
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TRP_MOVE ) // preliminary advance?
+ {
+ dist = Length(m_object->RetPosition(0), m_ruin->RetPosition(0));
+
+ if ( dist >= RECOVER_DIST-1.0f &&
+ dist <= RECOVER_DIST+1.0f )
+ {
+ m_physics->SetMotorSpeedX(0.0f);
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(RECOVER_DIST, 3.3f, 0.0f);
+ pos = Transform(*mat, pos); // position in front
+ m_recoverPos = pos;
+
+ i = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.0f, 0.9f, TRUE);
+ m_sound->AddEnvelope(i, 1.0f, 1.5f, 0.3f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 1.0f, 1.5f, 1.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.0f, 0.9f, 0.3f, SOPER_STOP);
+
+ m_phase = TRP_DOWN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.5f;
+ m_time = 0.0f;
+ }
+ else
+ {
+ if ( m_progress > 1.0f ) // timeout?
+ {
+ m_ruin->SetLock(FALSE); // usable again
+ m_camera->StopCentering(m_object, 2.0f);
+ return ERR_RECOVER_NULL;
+ }
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+ m_progress = 0.0f;
+
+ if ( m_phase == TRP_DOWN )
+ {
+ m_metal = new CObject(m_iMan);
+ if ( !m_metal->CreateResource(m_recoverPos, 0.0f, OBJECT_METAL) )
+ {
+ delete m_metal;
+ m_metal = 0;
+ Abort();
+ m_bError = TRUE;
+ m_displayText->DisplayError(ERR_TOOMANY, m_object);
+ return ERR_STOP;
+ }
+ m_metal->SetLock(TRUE); // metal not yet usable
+ m_metal->SetZoom(0, 0.0f);
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(RECOVER_DIST, 3.1f, 3.9f);
+ pos = Transform(*mat, pos);
+ goal = D3DVECTOR(RECOVER_DIST, 3.1f, -3.9f);
+ goal = Transform(*mat, goal);
+ m_particule->CreateRay(pos, goal, PARTIRAY2,
+ FPOINT(2.0f, 2.0f), 8.0f);
+
+ m_soundChannel = m_sound->Play(SOUND_RECOVER, m_ruin->RetPosition(0), 0.0f, 1.0f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.6f, 1.0f, 2.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.6f, 1.0f, 4.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.7f, 2.0f, SOPER_STOP);
+
+ m_phase = TRP_OPER;
+ m_speed = 1.0f/8.0f;
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TRP_OPER )
+ {
+ m_metal->SetZoom(0, 1.0f);
+
+ m_ruin->DeleteObject(); // destroys the ruin
+ delete m_ruin;
+ m_ruin = 0;
+
+ m_soundChannel = -1;
+
+ i = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.0f, 0.9f, TRUE);
+ m_sound->AddEnvelope(i, 1.0f, 1.5f, 0.3f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 1.0f, 1.5f, 1.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.0f, 0.9f, 0.3f, SOPER_STOP);
+
+ m_phase = TRP_UP;
+ m_speed = 1.0f/1.5f;
+ return ERR_CONTINUE;
+ }
+
+ m_metal->SetLock(FALSE); // metal usable
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Suddenly ends the current action.
+
+BOOL CTaskRecover::Abort()
+{
+ m_object->SetAngleZ(2, 126.0f*PI/180.0f);
+ m_object->SetAngleZ(4, 126.0f*PI/180.0f);
+ m_object->SetAngleZ(3, -144.0f*PI/180.0f);
+ m_object->SetAngleZ(5, -144.0f*PI/180.0f); // rest
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ m_camera->StopCentering(m_object, 2.0f);
+ return TRUE;
+}
+
+
+// Seeks if a ruin is in front of the vehicle.
+
+CObject* CTaskRecover::SearchRuin()
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR oPos;
+ ObjectType type;
+ float dist, min;
+ int i;
+
+ pBest = 0;
+ min = 100000.0f;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_RUINmobilew1 ||
+ type == OBJECT_RUINmobilew2 ||
+ type == OBJECT_RUINmobilet1 ||
+ type == OBJECT_RUINmobilet2 ||
+ type == OBJECT_RUINmobiler1 ||
+ type == OBJECT_RUINmobiler2 ) // vehicle in ruin?
+ {
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, m_recoverPos);
+ if ( dist > 40.0f ) continue;
+
+ if ( dist < min )
+ {
+ min = dist;
+ pBest = pObj;
+ }
+ }
+
+ }
+ return pBest;
+}
+
diff --git a/src/object/task/taskrecover.h b/src/object/task/taskrecover.h
new file mode 100644
index 0000000..cc2adce
--- /dev/null
+++ b/src/object/task/taskrecover.h
@@ -0,0 +1,75 @@
+// * 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/.
+
+// taskrecover.h
+
+#ifndef _TASKSRECOVER_H_
+#define _TASKSRECOVER_H_
+
+
+#include "d3dengine.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskRecoverPhase
+{
+ TRP_TURN = 1, // turns
+ TRP_MOVE = 2, // advance
+ TRP_DOWN = 3, // descends
+ TRP_OPER = 4, // operates
+ TRP_UP = 5, // back
+};
+
+
+
+class CTaskRecover : public CTask
+{
+public:
+ CTaskRecover(CInstanceManager* iMan, CObject* object);
+ ~CTaskRecover();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start();
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ CObject* SearchRuin();
+
+protected:
+ TaskRecoverPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_time;
+ float m_angle;
+ float m_lastParticule;
+ BOOL m_bError;
+ CObject* m_ruin;
+ CObject* m_metal;
+ D3DVECTOR m_recoverPos;
+ int m_soundChannel;
+};
+
+
+#endif //_TASKSRECOVER_H_
diff --git a/src/object/task/taskreset.cpp b/src/object/task/taskreset.cpp
new file mode 100644
index 0000000..a626c02
--- /dev/null
+++ b/src/object/task/taskreset.cpp
@@ -0,0 +1,345 @@
+// * 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/.
+
+// taskreset.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "d3dengine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "sound.h"
+#include "robotmain.h"
+#include "task.h"
+#include "taskreset.h"
+
+
+
+#define RESET_DELAY_ZOOM 0.7f
+#define RESET_DELAY_MOVE 0.7f
+
+
+
+
+// Object's constructor.
+
+CTaskReset::CTaskReset(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+}
+
+// Object's destructor.
+
+CTaskReset::~CTaskReset()
+{
+}
+
+
+// Management of an event.
+
+BOOL CTaskReset::EventProcess(const Event &event)
+{
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float angle, duration;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ m_time += event.rTime;
+ m_progress += event.rTime*m_speed;
+
+ if ( m_phase == TRSP_ZOUT )
+ {
+ angle = m_iAngle;
+ angle += powf(m_progress*5.0f, 2.0f); // accelerates
+ m_object->SetAngleY(0, angle);
+ m_object->SetZoom(0, 1.0f-m_progress);
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_begin;
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 5.0f+Rand()*5.0f;
+ dim.x = Rand()*2.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGLINTb, 2.0f);
+
+ pos = m_begin;
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ speed.y = Rand()*10.0f;
+ speed *= 1.0f-m_progress*0.5f;
+ pos += speed*1.5f;
+ speed = -speed;
+ dim.x = 0.6f;
+ dim.y = dim.x;
+ pos.y += dim.y;
+ duration = Rand()*1.5f+1.5f;
+ m_particule->CreateTrack(pos, speed, dim, PARTITRACK6,
+ duration, 0.0f,
+ duration*0.9f, 0.7f);
+ }
+ }
+
+ if ( m_phase == TRSP_MOVE )
+ {
+ pos = m_begin+(m_goal-m_begin)*m_progress;
+ m_object->SetPosition(0, pos);
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 2.0f+Rand()*2.0f;
+ dim.x = Rand()*2.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGLINTb, 2.0f);
+ }
+ }
+
+ if ( m_phase == TRSP_ZIN )
+ {
+ angle = m_angle.y;
+ angle += -powf((1.0f-m_progress)*5.0f, 2.0f); // slows
+ m_object->SetAngleY(0, angle);
+ m_object->SetZoom(0, m_progress);
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_goal;
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 5.0f+Rand()*5.0f;
+ dim.x = Rand()*2.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGLINTb, 2.0f);
+
+ pos = m_goal;
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ speed.y = Rand()*10.0f;
+ speed *= 0.5f+m_progress*0.5f;
+ dim.x = 0.6f;
+ dim.y = dim.x;
+ pos.y += dim.y;
+ duration = Rand()*1.5f+1.5f;
+ m_particule->CreateTrack(pos, speed, dim, PARTITRACK6,
+ duration, 0.0f,
+ duration*0.9f, 0.7f);
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Assigns the goal was achieved.
+// A positive angle makes a turn right.
+
+Error CTaskReset::Start(D3DVECTOR goal, D3DVECTOR angle)
+{
+ CObject* fret;
+ int i;
+
+ fret = m_object->RetFret();
+ if ( fret != 0 && fret->RetResetCap() == RESET_MOVE )
+ {
+ fret->SetTruck(0);
+ m_object->SetFret(0); // does nothing
+ }
+
+ if ( !m_main->RetNiceReset() ) // quick return?
+ {
+ m_object->SetPosition(0, goal);
+ m_object->SetAngle(0, angle);
+ m_brain->RunProgram(m_object->RetResetRun());
+
+ m_bError = FALSE;
+ return ERR_OK;
+ }
+
+ m_begin = m_object->RetPosition(0);
+ m_goal = goal;
+ m_angle = angle;
+
+ if ( SearchVehicle() ) // starting location occupied?
+ {
+ m_bError = TRUE;
+ return ERR_RESET_NEAR;
+ }
+
+ m_iAngle = m_object->RetAngleY(0);
+ m_time = 0.0f;
+ m_phase = TRSP_ZOUT;
+ m_speed = 1.0f/RESET_DELAY_ZOOM;
+ m_progress = 0.0f;
+ m_lastParticule = 0.0f;
+
+ m_object->SetResetBusy(TRUE);
+
+ i = m_sound->Play(SOUND_GGG, m_begin, 1.0f, 2.0f, TRUE);
+ m_sound->AddEnvelope(i, 0.0f, 0.5f, RESET_DELAY_ZOOM, SOPER_STOP);
+
+ m_bError = FALSE;
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskReset::IsEnded()
+{
+ CObject* power;
+ float dist;
+ int i;
+
+ if ( !m_main->RetNiceReset() ) // quick return?
+ {
+ return ERR_STOP;
+ }
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ if ( m_phase == TRSP_ZOUT )
+ {
+ dist = Length(m_begin, m_goal);
+ m_phase = TRSP_MOVE;
+ m_speed = 1.0f/(dist*RESET_DELAY_MOVE/100.0f);
+ m_progress = 0.0f;
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TRSP_MOVE )
+ {
+ m_object->SetPosition(0, m_goal);
+ m_object->SetAngle(0, m_angle);
+
+ i = m_sound->Play(SOUND_GGG, m_goal, 1.0f, 0.5f, TRUE);
+ m_sound->AddEnvelope(i, 0.0f, 2.0f, RESET_DELAY_ZOOM, SOPER_STOP);
+
+ m_phase = TRSP_ZIN;
+ m_speed = 1.0f/RESET_DELAY_ZOOM;
+ m_progress = 0.0f;
+ return ERR_CONTINUE;
+ }
+
+ m_object->SetAngle(0, m_angle);
+ m_object->SetZoom(0, 1.0f);
+
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ power->SetEnergy(power->RetCapacity()); // refueling
+ }
+
+ m_brain->RunProgram(m_object->RetResetRun());
+ m_object->SetResetBusy(FALSE);
+ return ERR_STOP;
+}
+
+
+// Seeks if a vehicle is too close.
+
+BOOL CTaskReset::SearchVehicle()
+{
+ CObject* pObj;
+ D3DVECTOR oPos;
+ ObjectType type;
+ float oRadius, dist;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_HUMAN &&
+ type != OBJECT_TECH &&
+ type != OBJECT_MOBILEfa &&
+ type != OBJECT_MOBILEta &&
+ type != OBJECT_MOBILEwa &&
+ type != OBJECT_MOBILEia &&
+ 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_MOBILEfs &&
+ type != OBJECT_MOBILEts &&
+ type != OBJECT_MOBILEws &&
+ type != OBJECT_MOBILEis &&
+ 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 &&
+ type != OBJECT_MOTHER &&
+ type != OBJECT_ANT &&
+ type != OBJECT_SPIDER &&
+ type != OBJECT_BEE &&
+ type != OBJECT_WORM ) continue;
+
+ if ( !pObj->GetCrashSphere(0, oPos, oRadius) ) continue;
+ dist = Length(oPos, m_goal)-oRadius;
+
+ if ( dist < 5.0f ) return TRUE;
+ }
+
+ return FALSE;
+}
+
diff --git a/src/object/task/taskreset.h b/src/object/task/taskreset.h
new file mode 100644
index 0000000..a866d1f
--- /dev/null
+++ b/src/object/task/taskreset.h
@@ -0,0 +1,73 @@
+// * 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/.
+
+// taskreset.h
+
+#ifndef _TASKRESET_H_
+#define _TASKRESET_H_
+
+
+#include "misc.h"
+#include "d3dengine.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskResetPhase
+{
+ TRSP_ZOUT = 1, // disappears
+ TRSP_MOVE = 2, // moves
+ TRSP_ZIN = 3, // reappears
+};
+
+
+
+class CTaskReset : public CTask
+{
+public:
+ CTaskReset(CInstanceManager* iMan, CObject* object);
+ ~CTaskReset();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(D3DVECTOR goal, D3DVECTOR angle);
+ Error IsEnded();
+
+protected:
+ BOOL SearchVehicle();
+
+protected:
+ D3DVECTOR m_begin;
+ D3DVECTOR m_goal;
+ D3DVECTOR m_angle;
+
+ TaskResetPhase m_phase;
+ BOOL m_bError;
+ float m_time;
+ float m_speed;
+ float m_progress;
+ float m_lastParticule; // time of generation last particle
+ float m_iAngle;
+};
+
+
+#endif //_TASKRESET_H_
diff --git a/src/object/task/tasksearch.cpp b/src/object/task/tasksearch.cpp
new file mode 100644
index 0000000..8857e35
--- /dev/null
+++ b/src/object/task/tasksearch.cpp
@@ -0,0 +1,334 @@
+// * 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/.
+
+// tasksearch.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "sound.h"
+#include "displaytext.h"
+#include "task.h"
+#include "tasksearch.h"
+
+
+
+
+// Object's constructor.
+
+CTaskSearch::CTaskSearch(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_hand = TSH_UP;
+}
+
+// Object's destructor.
+
+CTaskSearch::~CTaskSearch()
+{
+}
+
+
+// Management of an event.
+
+BOOL CTaskSearch::EventProcess(const Event &event)
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float angle;
+ int i;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ m_progress += event.rTime*m_speed; // others advance
+ m_time += event.rTime;
+
+ if ( m_phase == TSP_DOWN ||
+ m_phase == TSP_UP )
+ {
+ for ( i=0 ; i<3 ; i++ )
+ {
+ angle = (m_finalAngle[i]-m_initialAngle[i])*m_progress;
+ angle += m_initialAngle[i];
+ m_object->SetAngleZ(i+1, angle);
+ }
+ }
+
+ if ( m_phase == TSP_SEARCH &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(6.5f, 0.2f, 0.0f);
+ pos = Transform(*mat, pos); // sensor position
+
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ speed.y = 0.0f;
+ dim.x = Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGAS);
+ }
+
+ return TRUE;
+}
+
+
+// Initializes the initial and final angles.
+
+void CTaskSearch::InitAngle()
+{
+ int i;
+
+ if ( m_hand == TSH_UP )
+ {
+ m_finalAngle[0] = 110.0f*PI/180.0f; // arm
+ m_finalAngle[1] = -110.0f*PI/180.0f; // forearm
+ m_finalAngle[2] = -65.0f*PI/180.0f; // sensor
+ }
+ if ( m_hand == TSH_DOWN )
+ {
+ m_finalAngle[0] = 25.0f*PI/180.0f; // arm
+ m_finalAngle[1] = -70.0f*PI/180.0f; // forearm
+ m_finalAngle[2] = -45.0f*PI/180.0f; // sensor
+ }
+
+ for ( i=0 ; i<3 ; i++ )
+ {
+ m_initialAngle[i] = m_object->RetAngleZ(i+1);
+ }
+}
+
+
+// Assigns the goal was achieved.
+
+Error CTaskSearch::Start()
+{
+ ObjectType type;
+ D3DVECTOR speed;
+ int i;
+
+ m_bError = TRUE;
+ if ( !m_physics->RetLand() ) return ERR_SEARCH_FLY;
+
+ speed = m_physics->RetMotorSpeed();
+ if ( speed.x != 0.0f ||
+ speed.z != 0.0f ) return ERR_SEARCH_MOTOR;
+
+ type = m_object->RetType();
+ if ( type != OBJECT_MOBILEfs &&
+ type != OBJECT_MOBILEts &&
+ type != OBJECT_MOBILEws &&
+ type != OBJECT_MOBILEis ) return ERR_SEARCH_VEH;
+
+ m_hand = TSH_DOWN;
+ m_phase = TSP_DOWN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+
+ InitAngle();
+ m_bError = FALSE; // ok
+
+ m_camera->StartCentering(m_object, PI*0.50f, 99.9f, 0.0f, 1.0f);
+
+ i = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.0f, 0.3f, TRUE);
+ m_sound->AddEnvelope(i, 0.5f, 1.0f, 0.1f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.5f, 1.0f, 0.9f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.0f, 0.3f, 0.1f, SOPER_STOP);
+
+ m_physics->SetFreeze(TRUE); // it does not move
+
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskSearch::IsEnded()
+{
+ int i;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+ m_progress = 0.0f;
+
+ if ( m_phase == TSP_DOWN ||
+ m_phase == TSP_UP )
+ {
+ for ( i=0 ; i<3 ; i++ )
+ {
+ m_object->SetAngleZ(i+1, m_finalAngle[i]);
+ }
+ }
+
+ if ( m_phase == TSP_DOWN )
+ {
+ m_sound->Play(SOUND_REPAIR, m_object->RetPosition(0));
+
+ m_phase = TSP_SEARCH;
+ m_speed = 1.0f/4.0f;
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TSP_SEARCH )
+ {
+ CreateMark();
+
+ m_hand = TSH_UP;
+ InitAngle();
+
+ i = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.0f, 0.3f, TRUE);
+ m_sound->AddEnvelope(i, 0.5f, 1.0f, 0.1f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.5f, 1.0f, 0.9f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.0f, 0.3f, 0.1f, SOPER_STOP);
+
+ m_phase = TSP_UP;
+ m_speed = 1.0f/1.0f;
+ return ERR_CONTINUE;
+ }
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Suddenly ends the current action.
+
+BOOL CTaskSearch::Abort()
+{
+ m_camera->StopCentering(m_object, 2.0f);
+ m_physics->SetFreeze(FALSE); // is moving again
+ return TRUE;
+}
+
+
+// Creates a mark if possible.
+
+BOOL CTaskSearch::CreateMark()
+{
+ CObject* fret;
+ ObjectType type;
+ D3DMATRIX* mat;
+ D3DVECTOR pos;
+ TerrainRes res;
+ Error info;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(7.5f, 0.0f, 0.0f);
+ pos = Transform(*mat, pos); // sensor position
+
+ res = m_terrain->RetResource(pos);
+ if ( res == TR_NULL ) return FALSE;
+
+ type = OBJECT_NULL;
+ if ( res == TR_STONE )
+ {
+ type = OBJECT_MARKSTONE;
+ info = INFO_MARKSTONE;
+ }
+ if ( res == TR_URANIUM )
+ {
+ type = OBJECT_MARKURANIUM;
+ info = INFO_MARKURANIUM;
+ }
+ if ( res == TR_POWER )
+ {
+ type = OBJECT_MARKPOWER;
+ info = INFO_MARKPOWER;
+ }
+ if ( res == TR_KEYa )
+ {
+ type = OBJECT_MARKKEYa;
+ info = INFO_MARKKEYa;
+ }
+ if ( res == TR_KEYb )
+ {
+ type = OBJECT_MARKKEYb;
+ info = INFO_MARKKEYb;
+ }
+ if ( res == TR_KEYc )
+ {
+ type = OBJECT_MARKKEYc;
+ info = INFO_MARKKEYc;
+ }
+ if ( res == TR_KEYd )
+ {
+ type = OBJECT_MARKKEYd;
+ info = INFO_MARKKEYd;
+ }
+ if ( type == OBJECT_NULL ) return FALSE;
+
+//? DeleteMark(type);
+
+ fret = new CObject(m_iMan);
+ if ( !fret->CreateResource(pos, 0.0f, type) )
+ {
+ delete fret;
+ m_displayText->DisplayError(ERR_TOOMANY, m_object);
+ return FALSE;
+ }
+
+ m_displayText->DisplayError(info, pos, 5.0f, 50.0f); // displays the message
+
+ return TRUE;
+}
+
+// Destroys the marks of a given type.
+
+void CTaskSearch::DeleteMark(ObjectType type)
+{
+ CObject* pObj;
+ D3DVECTOR oPos;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( type == pObj->RetType() )
+ {
+ pObj->DeleteObject(); // removes the mark
+ delete pObj;
+ break;
+ }
+ }
+}
+
+
diff --git a/src/object/task/tasksearch.h b/src/object/task/tasksearch.h
new file mode 100644
index 0000000..80970e1
--- /dev/null
+++ b/src/object/task/tasksearch.h
@@ -0,0 +1,79 @@
+// * 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/.
+
+// tasksearch.h
+
+#ifndef _TASKSEARCH_H_
+#define _TASKSEARCH_H_
+
+
+#include "misc.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskSearchHand
+{
+ TSH_UP = 1, // sensor at the top
+ TSH_DOWN = 2, // sensor at the bottom
+};
+
+enum TaskSearchPhase
+{
+ TSP_DOWN = 1, // descends
+ TSP_SEARCH = 2, // seeks
+ TSP_UP = 3, // rises
+};
+
+
+
+class CTaskSearch : public CTask
+{
+public:
+ CTaskSearch(CInstanceManager* iMan, CObject* object);
+ ~CTaskSearch();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start();
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ void InitAngle();
+ BOOL CreateMark();
+ void DeleteMark(ObjectType type);
+
+protected:
+ TaskSearchHand m_hand;
+ TaskSearchPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_time;
+ float m_lastParticule;
+ float m_initialAngle[3];
+ float m_finalAngle[3];
+ BOOL m_bError;
+};
+
+
+#endif //_TASKSEARCH_H_
diff --git a/src/object/task/taskshield.cpp b/src/object/task/taskshield.cpp
new file mode 100644
index 0000000..9269c4b
--- /dev/null
+++ b/src/object/task/taskshield.cpp
@@ -0,0 +1,573 @@
+// * 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/.
+
+// taskshield.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "light.h"
+#include "sound.h"
+#include "task.h"
+#include "taskshield.h"
+
+
+#define ENERGY_TIME 20.0f // maximum duration if full battery
+
+
+
+// Object's constructor.
+
+CTaskShield::CTaskShield(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_rankSphere = -1;
+ m_soundChannel = -1;
+ m_effectLight = -1;
+}
+
+// Object's destructor.
+
+CTaskShield::~CTaskShield()
+{
+ Abort();
+}
+
+
+// Management of an event.
+
+BOOL CTaskShield::EventProcess(const Event &event)
+{
+ CObject* power;
+ D3DMATRIX* mat;
+ D3DMATRIX matrix;
+ D3DVECTOR pos, speed, goal, angle;
+ D3DCOLORVALUE color;
+ FPOINT dim;
+ float energy;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ m_progress += event.rTime*m_speed; // others advance
+ m_time += event.rTime;
+ m_delay -= event.rTime;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(7.0f, 15.0f, 0.0f);
+ pos = Transform(*mat, pos); // sphere position
+ m_shieldPos = pos;
+
+ if ( m_rankSphere != -1 )
+ {
+ m_particule->SetPosition(m_rankSphere, m_shieldPos);
+ dim.x = RetRadius();
+ dim.y = dim.x;
+ m_particule->SetDimension(m_rankSphere, dim);
+ }
+
+ if ( m_phase == TS_UP1 )
+ {
+ pos.x = 7.0f;
+ pos.y = 4.5f+Bounce(m_progress)*3.0f;
+ pos.z = 0.0f;
+ m_object->SetPosition(2, pos);
+ }
+
+ if ( m_phase == TS_UP2 )
+ {
+ pos.x = 0.0f;
+ pos.y = 1.0f+Bounce(m_progress)*3.0f;
+ pos.z = 0.0f;
+ m_object->SetPosition(3, pos);
+ }
+
+ if ( m_phase == TS_SHIELD )
+ {
+ energy = (1.0f/ENERGY_TIME)*event.rTime;
+ energy *= RetRadius()/RADIUS_SHIELD_MAX;
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ power->SetEnergy(power->RetEnergy()-energy/power->RetCapacity());
+ }
+ m_energyUsed += energy;
+
+ if ( m_soundChannel == -1 )
+ {
+ m_soundChannel = m_sound->Play(SOUND_SHIELD, m_shieldPos, 0.5f, 0.5f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 2.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 1.0f, SOPER_LOOP);
+ }
+ else
+ {
+ m_sound->Position(m_soundChannel, m_shieldPos);
+ }
+
+ pos = m_shieldPos;
+ pos.y += RetRadius()*(2.0f+sinf(m_time*9.0f)*0.2f);
+ if ( m_effectLight == -1 )
+ {
+ CreateLight(pos);
+ }
+ else
+ {
+ m_light->SetLightPos(m_effectLight, pos);
+
+ color.r = 0.0f+sinf(m_time*33.2f)*0.2f;
+ color.g = 0.5f+sinf(m_time*20.0f)*0.5f;
+ color.b = 0.5f+sinf(m_time*21.3f)*1.0f;
+ color.a = 0.0f;
+ m_light->SetLightColor(m_effectLight, color);
+ }
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_shieldPos;
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ speed.x = (Rand()-0.5f)*0.0f;
+ speed.z = (Rand()-0.5f)*0.0f;
+ speed.y = Rand()*15.0f;
+ dim.x = Rand()*6.0f+4.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLUE, 1.0f, 0.0f, 0.0f);
+ }
+
+ if ( m_lastRay+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastRay = m_time;
+
+ pos = m_shieldPos;
+ dim.x = RetRadius()/20.0f;
+ dim.y = dim.x;
+ angle.x = (Rand()-0.5f)*PI*1.2f;
+ angle.y = 0.0f;
+ angle.z = (Rand()-0.5f)*PI*1.2f;
+ MatRotateXZY(matrix, angle);
+ goal = Transform(matrix, D3DVECTOR(0.0f, RetRadius()-dim.x, 0.0f));
+ goal += pos;
+ m_particule->CreateRay(pos, goal, PARTIRAY2, dim, 0.3f);
+ }
+
+ if ( m_lastIncrease+0.2f <= m_time )
+ {
+ m_lastIncrease = m_time;
+ IncreaseShield();
+ }
+ }
+
+ if ( m_phase == TS_SMOKE )
+ {
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.5f, 0.5f, 2.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_shieldPos;
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ speed.x = (Rand()-0.5f)*3.0f;
+ speed.z = (Rand()-0.5f)*3.0f;
+ speed.y = (Rand()-0.5f)*3.0f;
+ dim.x = Rand()*1.5f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE3, 4.0f);
+ }
+ }
+
+ if ( m_phase == TS_DOWN1 )
+ {
+ pos.x = 0.0f;
+ pos.y = 1.0f+(1.0f-Bounce(m_progress))*3.0f;
+ pos.z = 0.0f;
+ m_object->SetPosition(3, pos);
+ }
+
+ if ( m_phase == TS_DOWN2 )
+ {
+ pos.x = 7.0f;
+ pos.y = 4.5f+(1.0f-Bounce(m_progress))*3.0f;
+ pos.z = 0.0f;
+ m_object->SetPosition(2, pos);
+ }
+
+ return TRUE;
+}
+
+
+// Deploys the shield.
+// The period is only useful with TSM_UP!
+
+Error CTaskShield::Start(TaskShieldMode mode, float delay)
+{
+ CObject* power;
+ D3DMATRIX* mat;
+ D3DVECTOR pos, iPos, oPos, speed;
+ ObjectType type;
+ float energy;
+
+ if ( mode == TSM_DOWN )
+ {
+ return Stop();
+ }
+
+ if ( mode == TSM_UPDATE )
+ {
+ if ( m_object->RetSelect() )
+ {
+ m_brain->UpdateInterface();
+ }
+ return ERR_OK;
+ }
+
+ type = m_object->RetType();
+ if ( type != OBJECT_MOBILErs ) return ERR_SHIELD_VEH;
+
+ m_bError = TRUE; // operation impossible
+ if ( !m_physics->RetLand() ) return ERR_SHIELD_VEH;
+
+ power = m_object->RetPower();
+ if ( power == 0 ) return ERR_SHIELD_ENERGY;
+ energy = power->RetEnergy();
+ if ( energy == 0.0f ) return ERR_SHIELD_ENERGY;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(7.0f, 15.0f, 0.0f);
+ pos = Transform(*mat, pos); // sphere position
+ m_shieldPos = pos;
+
+ m_sound->Play(SOUND_PSHHH2, m_shieldPos, 1.0f, 0.7f);
+
+ m_phase = TS_UP1;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ m_time = 0.0f;
+ m_delay = delay;
+ m_lastParticule = 0.0f;
+ m_lastRay = 0.0f;
+ m_lastIncrease = 0.0f;
+ m_energyUsed = 0.0f;
+
+ m_bError = FALSE; // ok
+
+ if ( m_object->RetSelect() )
+ {
+ m_brain->UpdateInterface();
+ }
+//? m_camera->StartCentering(m_object, PI*0.85f, -PI*0.15f, RetRadius()+40.0f, 3.0f);
+ return ERR_OK;
+}
+
+// Returns the shield.
+
+Error CTaskShield::Stop()
+{
+ float time;
+
+ if ( m_phase == TS_SHIELD )
+ {
+ m_object->SetShieldRadius(0.0f);
+
+ if ( m_rankSphere != -1 )
+ {
+ m_particule->SetPhase(m_rankSphere, PARPHEND, 3.0f);
+ m_rankSphere = -1;
+ }
+
+ if ( m_effectLight != -1 )
+ {
+ m_light->DeleteLight(m_effectLight);
+ m_effectLight = -1;
+ }
+
+ time = m_energyUsed*4.0f;
+ if ( time < 1.0f ) time = 1.0f;
+ if ( time > 4.0f ) time = 4.0f;
+
+ m_phase = TS_SMOKE;
+ m_speed = 1.0f/time;
+
+ m_camera->StopCentering(m_object, 4.0f);
+
+ if ( m_object->RetSelect() )
+ {
+ m_brain->UpdateInterface();
+ }
+ return ERR_CONTINUE;
+ }
+
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskShield::IsEnded()
+{
+ CObject* power;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float energy;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_phase == TS_SHIELD )
+ {
+ m_object->SetShieldRadius(RetRadius());
+
+ power = m_object->RetPower();
+ if ( power == 0 )
+ {
+ energy = 0.0f;
+ }
+ else
+ {
+ energy = power->RetEnergy();
+ }
+
+ if ( energy == 0.0f || m_delay <= 0.0f )
+ {
+ Stop();
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+ m_progress = 0.0f;
+
+ if ( m_phase == TS_UP1 )
+ {
+ pos.x = 7.0f;
+ pos.y = 4.5f+3.0f;
+ pos.z = 0.0f;
+ m_object->SetPosition(2, pos);
+
+ m_sound->Play(SOUND_PSHHH2, m_shieldPos, 1.0f, 1.0f);
+
+ m_phase = TS_UP2;
+ m_speed = 1.0f/0.8f;
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TS_UP2 )
+ {
+ pos.x = 0.0f;
+ pos.y = 1.0f+3.0f;
+ pos.z = 0.0f;
+ m_object->SetPosition(3, pos);
+
+ m_object->SetShieldRadius(RetRadius());
+
+ pos = m_shieldPos;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = RetRadius();
+ dim.y = dim.x;
+ m_rankSphere = m_particule->CreateParticule(pos, speed, dim, PARTISPHERE3, 2.0f, 0.0f, 0.0f);
+
+ m_phase = TS_SHIELD;
+ m_speed = 1.0f/999.9f;
+
+ if ( m_object->RetSelect() )
+ {
+ m_brain->UpdateInterface();
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TS_SMOKE )
+ {
+ m_sound->Play(SOUND_PSHHH2, m_shieldPos, 1.0f, 1.0f);
+
+ m_phase = TS_DOWN1;
+ m_speed = 1.0f/0.8f;
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TS_DOWN1 )
+ {
+ m_sound->Play(SOUND_PSHHH2, m_shieldPos, 1.0f, 0.7f);
+
+ m_phase = TS_DOWN2;
+ m_speed = 1.0f/1.0f;
+ return ERR_CONTINUE;
+ }
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Indicates whether the action is pending.
+
+BOOL CTaskShield::IsBusy()
+{
+ if ( m_phase == TS_SHIELD )
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// Suddenly ends the current action.
+
+BOOL CTaskShield::Abort()
+{
+ D3DVECTOR pos;
+
+ m_object->SetShieldRadius(0.0f);
+
+ pos.x = 7.0f;
+ pos.y = 4.5f;
+ pos.z = 0.0f;
+ m_object->SetPosition(2, pos);
+
+ pos.x = 0.0f;
+ pos.y = 1.0f;
+ pos.z = 0.0f;
+ m_object->SetPosition(3, pos);
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.5f, 0.5f, 2.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ if ( m_rankSphere != -1 )
+ {
+ m_particule->SetPhase(m_rankSphere, PARPHEND, 3.0f);
+ m_rankSphere = -1;
+ }
+
+ if ( m_effectLight != -1 )
+ {
+ m_light->DeleteLight(m_effectLight);
+ m_effectLight = -1;
+ }
+
+ m_camera->StopCentering(m_object, 2.0f);
+ return TRUE;
+}
+
+
+// Creates the light to accompany a pyrotechnic effect.
+
+BOOL CTaskShield::CreateLight(D3DVECTOR pos)
+{
+ D3DLIGHT7 light;
+
+ if ( !m_engine->RetLightMode() ) return TRUE;
+
+ ZeroMemory( &light, sizeof(light) );
+ light.dltType = D3DLIGHT_SPOT;
+ light.dcvDiffuse.r = 0.0f;
+ light.dcvDiffuse.g = 1.0f;
+ light.dcvDiffuse.b = 2.0f;
+ light.dvPosition.x = pos.x;
+ light.dvPosition.y = pos.y;
+ light.dvPosition.z = pos.z;
+ light.dvDirection.x = 0.0f;
+ light.dvDirection.y = -1.0f; // against the bottom
+ light.dvDirection.z = 0.0f;
+ light.dvRange = D3DLIGHT_RANGE_MAX;
+ light.dvFalloff = 1.0f;
+ light.dvAttenuation0 = 1.0f;
+ light.dvAttenuation1 = 0.0f;
+ light.dvAttenuation2 = 0.0f;
+ light.dvTheta = 0.0f;
+ light.dvPhi = PI/4.0f;
+
+ m_effectLight = m_light->CreateLight();
+ if ( m_effectLight == -1 ) return FALSE;
+
+ m_light->SetLight(m_effectLight, light);
+ m_light->SetLightIntensity(m_effectLight, 1.0f);
+
+ return TRUE;
+}
+
+
+// Repaired the shielded objects within the sphere of the shield.
+
+void CTaskShield::IncreaseShield()
+{
+ ObjectType type;
+ CObject* pObj;
+ D3DVECTOR oPos;
+ float dist, shield;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_MOTHER ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_BEE ||
+ type == OBJECT_WORM ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, m_shieldPos);
+ if ( dist <= RetRadius()+10.0f )
+ {
+ shield = pObj->RetShield();
+ shield += 0.1f;
+ if ( shield > 1.0f ) shield = 1.0f;
+ pObj->SetShield(shield);
+ }
+ }
+}
+
+
+// Returns the radius of the shield.
+
+float CTaskShield::RetRadius()
+{
+ return RADIUS_SHIELD_MIN + (RADIUS_SHIELD_MAX-RADIUS_SHIELD_MIN)*m_object->RetParam();
+}
+
+
+
diff --git a/src/object/task/taskshield.h b/src/object/task/taskshield.h
new file mode 100644
index 0000000..8ec2d05
--- /dev/null
+++ b/src/object/task/taskshield.h
@@ -0,0 +1,94 @@
+// * 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/.
+
+// taskshield.h
+
+#ifndef _TASKSHIELD_H_
+#define _TASKSHIELD_H_
+
+
+#include "misc.h"
+#include "d3dengine.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+#define RADIUS_SHIELD_MIN 40.0f // minimal radius of the protected zone
+#define RADIUS_SHIELD_MAX 100.0f // maximal radius of the protected zone
+
+
+enum TaskShieldPhase
+{
+ TS_UP1 = 1, // up
+ TS_UP2 = 2, // up
+ TS_SHIELD = 3, // shield deployed
+ TS_SMOKE = 4, // smoke
+ TS_DOWN1 = 5, // down
+ TS_DOWN2 = 6, // down
+};
+
+enum TaskShieldMode
+{
+ TSM_UP = 1, // deploys shield
+ TSM_DOWN = 2, // returns the shield
+ TSM_UPDATE = 3, // radius change
+};
+
+
+
+class CTaskShield : public CTask
+{
+public:
+ CTaskShield(CInstanceManager* iMan, CObject* object);
+ ~CTaskShield();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(TaskShieldMode mode, float delay);
+ Error IsEnded();
+ BOOL IsBusy();
+ BOOL Abort();
+
+protected:
+ Error Stop();
+ BOOL CreateLight(D3DVECTOR pos);
+ void IncreaseShield();
+ float RetRadius();
+
+protected:
+ TaskShieldPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_time;
+ float m_delay;
+ float m_lastParticule;
+ float m_lastRay;
+ float m_lastIncrease;
+ float m_energyUsed;
+ BOOL m_bError;
+ D3DVECTOR m_shieldPos;
+ int m_rankSphere;
+ int m_soundChannel;
+ int m_effectLight;
+};
+
+
+#endif //_TASKSHIELD_H_
diff --git a/src/object/task/taskspiderexplo.cpp b/src/object/task/taskspiderexplo.cpp
new file mode 100644
index 0000000..b655fe6
--- /dev/null
+++ b/src/object/task/taskspiderexplo.cpp
@@ -0,0 +1,124 @@
+// * 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/.
+
+// taskspiderexplo.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "d3dengine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "object.h"
+#include "physics.h"
+#include "pyro.h"
+#include "motion.h"
+#include "motionspider.h"
+#include "task.h"
+#include "taskspiderexplo.h"
+
+
+
+
+// Object's constructor.
+
+CTaskSpiderExplo::CTaskSpiderExplo(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_time = 0.0f;
+ m_bError = FALSE;
+}
+
+// Object's destructor.
+
+CTaskSpiderExplo::~CTaskSpiderExplo()
+{
+}
+
+
+// Management of an event.
+
+BOOL CTaskSpiderExplo::EventProcess(const Event &event)
+{
+ 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_bError = TRUE;
+ return TRUE;
+ }
+
+ m_time += event.rTime;
+
+ return TRUE;
+}
+
+
+// Assigns the goal was achieved.
+
+Error CTaskSpiderExplo::Start()
+{
+ m_motion->SetAction(MSS_EXPLO, 1.0f); // swells abdominal
+ m_time = 0.0f;
+
+ m_physics->SetMotorSpeedX(0.0f); // stops the advance
+ m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
+
+ m_bError = FALSE;
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskSpiderExplo::IsEnded()
+{
+ CPyro* pyro;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+
+ if ( m_bError )
+ {
+ Abort();
+ return ERR_STOP;
+ }
+
+ if ( m_time < 1.0f ) return ERR_CONTINUE;
+
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_SPIDER, m_object); // the spider explodes (suicide)
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Suddenly ends the current action.
+
+BOOL CTaskSpiderExplo::Abort()
+{
+ return TRUE;
+}
+
diff --git a/src/object/task/taskspiderexplo.h b/src/object/task/taskspiderexplo.h
new file mode 100644
index 0000000..fb7f5f6
--- /dev/null
+++ b/src/object/task/taskspiderexplo.h
@@ -0,0 +1,53 @@
+// * 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/.
+
+// taskspiderexplo.h
+
+#ifndef _TASKSPIDEREXPLO_H_
+#define _TASKSPIDEREXPLO_H_
+
+
+#include "misc.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+class CTaskSpiderExplo : public CTask
+{
+public:
+ CTaskSpiderExplo(CInstanceManager* iMan, CObject* object);
+ ~CTaskSpiderExplo();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start();
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+
+protected:
+ float m_time;
+ BOOL m_bError;
+};
+
+
+#endif //_TASKSPIDEREXPLO_H_
diff --git a/src/object/task/tasktake.cpp b/src/object/task/tasktake.cpp
new file mode 100644
index 0000000..35de2b7
--- /dev/null
+++ b/src/object/task/tasktake.cpp
@@ -0,0 +1,612 @@
+// * 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/.
+
+// tasktake.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "d3dengine.h"
+#include "d3dmath.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "water.h"
+#include "camera.h"
+#include "motion.h"
+#include "motionhuman.h"
+#include "sound.h"
+#include "robotmain.h"
+#include "task.h"
+#include "tasktake.h"
+
+
+
+
+// Object's constructor.
+
+CTaskTake::CTaskTake(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+
+ m_arm = TTA_NEUTRAL;
+}
+
+// Object's destructor.
+
+CTaskTake::~CTaskTake()
+{
+}
+
+
+// Management of an event.
+
+BOOL CTaskTake::EventProcess(const Event &event)
+{
+ float a, g, cirSpeed;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ if ( m_bTurn ) // preliminary rotation?
+ {
+ a = m_object->RetAngleY(0);
+ g = m_angle;
+ cirSpeed = Direction(a, g)*2.0f;
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // turns left / right
+ return TRUE;
+ }
+
+ m_progress += event.rTime*m_speed; // others advance
+
+ m_physics->SetMotorSpeed(D3DVECTOR(0.0f, 0.0f, 0.0f)); // immobile!
+
+ return TRUE;
+}
+
+
+// Assigns the goal was achieved.
+
+Error CTaskTake::Start()
+{
+ ObjectType type;
+ CObject* other;
+ float iAngle, oAngle, h;
+ D3DVECTOR pos;
+
+ m_height = 0.0f;
+ m_step = 0;
+ m_progress = 0.0f;
+
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+ oAngle = iAngle;
+
+ m_bError = TRUE; // operation impossible
+ if ( !m_physics->RetLand() )
+ {
+ pos = m_object->RetPosition(0);
+ h = m_water->RetLevel(m_object);
+ if ( pos.y < h ) return ERR_MANIP_WATER; // impossible under water
+ return ERR_MANIP_FLY;
+ }
+
+ type = m_object->RetType();
+ if ( type != OBJECT_HUMAN &&
+ type != OBJECT_TECH ) return ERR_MANIP_VEH;
+
+ m_physics->SetMotorSpeed(D3DVECTOR(0.0f, 0.0f, 0.0f));
+
+ if ( m_object->RetFret() == 0 )
+ {
+ m_order = TTO_TAKE;
+ }
+ else
+ {
+ m_order = TTO_DEPOSE;
+ }
+
+ if ( m_order == TTO_TAKE )
+ {
+ pos = m_object->RetPosition(0);
+ h = m_water->RetLevel(m_object);
+ if ( pos.y < h ) return ERR_MANIP_WATER; // impossible under water
+
+ other = SearchFriendObject(oAngle, 1.5f, PI*0.50f);
+ if ( other != 0 && other->RetPower() != 0 )
+ {
+ type = other->RetPower()->RetType();
+ if ( type == OBJECT_URANIUM ) return ERR_MANIP_RADIO;
+ if ( type != OBJECT_FRET &&
+ type != OBJECT_STONE &&
+ type != OBJECT_BULLET &&
+ type != OBJECT_METAL &&
+ type != OBJECT_POWER &&
+ type != OBJECT_ATOMIC &&
+ type != OBJECT_BBOX &&
+ type != OBJECT_KEYa &&
+ type != OBJECT_KEYb &&
+ type != OBJECT_KEYc &&
+ type != OBJECT_KEYd &&
+ type != OBJECT_TNT ) return ERR_MANIP_FRIEND;
+//? m_camera->StartCentering(m_object, PI*0.3f, -PI*0.1f, 0.0f, 0.8f);
+ m_arm = TTA_FRIEND;
+ }
+ else
+ {
+ other = SearchTakeObject(oAngle, 1.5f, PI*0.45f);
+ if ( other == 0 ) return ERR_MANIP_NIL;
+ type = other->RetType();
+ if ( type == OBJECT_URANIUM ) return ERR_MANIP_RADIO;
+//? m_camera->StartCentering(m_object, PI*0.3f, 99.9f, 0.0f, 0.8f);
+ m_arm = TTA_FFRONT;
+ m_main->HideDropZone(other); // hides buildable area
+ }
+ }
+
+ if ( m_order == TTO_DEPOSE )
+ {
+//? speed = m_physics->RetMotorSpeed();
+//? if ( speed.x != 0.0f ||
+//? speed.z != 0.0f ) return ERR_MANIP_MOTOR;
+
+ other = SearchFriendObject(oAngle, 1.5f, PI*0.50f);
+ if ( other != 0 && other->RetPower() == 0 )
+ {
+//? m_camera->StartCentering(m_object, PI*0.3f, -PI*0.1f, 0.0f, 0.8f);
+ m_arm = TTA_FRIEND;
+ }
+ else
+ {
+ if ( !IsFreeDeposeObject(D3DVECTOR(2.5f, 0.0f, 0.0f)) ) return ERR_MANIP_OCC;
+//? m_camera->StartCentering(m_object, PI*0.3f, 99.9f, 0.0f, 0.8f);
+ m_arm = TTA_FFRONT;
+ }
+ }
+
+ m_bTurn = TRUE; // preliminary rotation necessary
+ m_angle = oAngle; // angle was reached
+
+ m_physics->SetFreeze(TRUE); // it does not move
+
+ m_bError = FALSE; // ok
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskTake::IsEnded()
+{
+ CObject* fret;
+ float angle;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_bTurn ) // preliminary rotation?
+ {
+ angle = m_object->RetAngleY(0);
+ angle = NormAngle(angle); // 0..2*PI
+
+ if ( TestAngle(angle, m_angle-PI*0.01f, m_angle+PI*0.01f) )
+ {
+ m_bTurn = FALSE; // rotation ended
+ m_physics->SetMotorSpeedZ(0.0f);
+
+ if ( m_arm == TTA_FFRONT )
+ {
+ m_motion->SetAction(MHS_TAKE, 0.2f); // will decrease
+ }
+ if ( m_arm == TTA_FRIEND )
+ {
+ if ( m_height <= 3.0f )
+ {
+ m_motion->SetAction(MHS_TAKEOTHER, 0.2f); // will decrease
+ }
+ else
+ {
+ m_motion->SetAction(MHS_TAKEHIGH, 0.2f); // will decrease
+ }
+ }
+ m_progress = 0.0f;
+ m_speed = 1.0f/0.6f;
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+ m_progress = 0.0f;
+
+ m_step ++;
+
+ if ( m_order == TTO_TAKE )
+ {
+ if ( m_step == 1 )
+ {
+ if ( TruckTakeObject() )
+ {
+ if ( m_arm == TTA_FRIEND &&
+ (m_fretType == OBJECT_POWER ||
+ m_fretType == OBJECT_ATOMIC ) )
+ {
+ m_sound->Play(SOUND_POWEROFF, m_object->RetPosition(0));
+ }
+ }
+ m_motion->SetAction(MHS_UPRIGHT, 0.4f); // gets up
+ m_progress = 0.0f;
+ m_speed = 1.0f/0.8f;
+ m_camera->StopCentering(m_object, 0.8f);
+ return ERR_CONTINUE;
+ }
+ }
+
+ if ( m_order == TTO_DEPOSE )
+ {
+ if ( m_step == 1 )
+ {
+ fret = m_object->RetFret();
+ TruckDeposeObject();
+ if ( m_arm == TTA_FRIEND &&
+ (m_fretType == OBJECT_POWER ||
+ m_fretType == OBJECT_ATOMIC ) )
+ {
+ m_sound->Play(SOUND_POWERON, m_object->RetPosition(0));
+ }
+ if ( fret != 0 && m_fretType == OBJECT_METAL && m_arm == TTA_FFRONT )
+ {
+ m_main->ShowDropZone(fret, m_object); // shows buildable area
+ }
+ m_motion->SetAction(-1); // gets up
+ m_progress = 0.0f;
+ m_speed = 1.0f/0.4f;
+ m_camera->StopCentering(m_object, 0.8f);
+ return ERR_CONTINUE;
+ }
+ }
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Suddenly ends the current action.
+
+BOOL CTaskTake::Abort()
+{
+ m_motion->SetAction(-1);
+ m_camera->StopCentering(m_object, 0.8f);
+ m_physics->SetFreeze(FALSE); // is moving again
+ return TRUE;
+}
+
+
+// Seeks the object to take in front.
+
+CObject* CTaskTake::SearchTakeObject(float &angle,
+ float dLimit, float aLimit)
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR iPos, oPos;
+ ObjectType type;
+ float min, iAngle, bAngle, a, distance;
+ int i;
+
+ iPos = m_object->RetPosition(0);
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+
+ min = 1000000.0f;
+ pBest = 0;
+ bAngle = 0.0f;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+
+ if ( type != OBJECT_FRET &&
+ type != OBJECT_STONE &&
+ type != OBJECT_URANIUM &&
+ type != OBJECT_BULLET &&
+ type != OBJECT_METAL &&
+ type != OBJECT_POWER &&
+ type != OBJECT_ATOMIC &&
+ type != OBJECT_BBOX &&
+ type != OBJECT_KEYa &&
+ type != OBJECT_KEYb &&
+ type != OBJECT_KEYc &&
+ type != OBJECT_KEYd &&
+ type != OBJECT_TNT ) continue;
+
+ if ( pObj->RetTruck() != 0 ) continue; // object transported?
+ if ( pObj->RetLock() ) continue;
+ if ( pObj->RetZoomY(0) != 1.0f ) continue;
+
+ oPos = pObj->RetPosition(0);
+ distance = Length(oPos, iPos);
+ if ( distance >= 4.0f-dLimit &&
+ distance <= 4.0f+dLimit )
+ {
+ angle = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+ if ( TestAngle(angle, iAngle-aLimit, iAngle+aLimit) )
+ {
+ a = Abs(angle-iAngle);
+ if ( a > PI ) a = PI*2.0f-a;
+ if ( a < min )
+ {
+ min = a;
+ pBest = pObj;
+ bAngle = angle;
+ }
+ }
+ }
+ }
+ angle = bAngle;
+ return pBest;
+}
+
+// Seeks the robot on which you want take or put a battery.
+
+CObject* CTaskTake::SearchFriendObject(float &angle,
+ float dLimit, float aLimit)
+{
+ Character* character;
+ CObject* pObj;
+ CObject* pPower;
+ D3DMATRIX* mat;
+ D3DVECTOR iPos, oPos;
+ ObjectType type, powerType;
+ float iAngle, iRad, distance;
+ int i;
+
+ if ( !m_object->GetCrashSphere(0, iPos, iRad) ) return 0;
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue; // yourself?
+
+ type = pObj->RetType();
+ if ( type != OBJECT_MOBILEfa &&
+ type != OBJECT_MOBILEta &&
+ type != OBJECT_MOBILEwa &&
+ type != OBJECT_MOBILEia &&
+ 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_MOBILEfs &&
+ type != OBJECT_MOBILEts &&
+ type != OBJECT_MOBILEws &&
+ type != OBJECT_MOBILEis &&
+ 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_TOWER &&
+ type != OBJECT_RESEARCH &&
+ type != OBJECT_ENERGY &&
+ type != OBJECT_LABO &&
+ type != OBJECT_NUCLEAR ) continue;
+
+ pPower = pObj->RetPower();
+ if ( pPower != 0 )
+ {
+ if ( pPower->RetLock() ) continue;
+ if ( pPower->RetZoomY(0) != 1.0f ) continue;
+
+ powerType = pPower->RetType();
+ if ( powerType == OBJECT_NULL ||
+ powerType == OBJECT_FIX ) continue;
+ }
+
+ mat = pObj->RetWorldMatrix(0);
+ character = pObj->RetCharacter();
+ oPos = Transform(*mat, character->posPower);
+
+ distance = Abs(Length(oPos, iPos) - (iRad+1.0f));
+ if ( distance <= dLimit )
+ {
+ angle = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+ if ( TestAngle(angle, iAngle-aLimit, iAngle+aLimit) )
+ {
+ character = pObj->RetCharacter();
+ m_height = character->posPower.y;
+ return pObj;
+ }
+ }
+ }
+
+ return 0;
+}
+
+// Takes the object in front.
+
+BOOL CTaskTake::TruckTakeObject()
+{
+ CObject* fret;
+ CObject* other;
+ D3DMATRIX matRotate;
+ float angle;
+
+ if ( m_arm == TTA_FFRONT ) // takes on the ground in front?
+ {
+//? fret = SearchTakeObject(angle, 1.5f, PI*0.04f);
+ fret = SearchTakeObject(angle, 1.5f, PI*0.15f); //OK 1.9
+ if ( fret == 0 ) return FALSE; // rien � prendre ?
+ m_fretType = fret->RetType();
+
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(4); // takes with the hand
+
+//? fret->SetPosition(0, D3DVECTOR(2.2f, -1.0f, 1.1f));
+ fret->SetPosition(0, D3DVECTOR(1.7f, -0.5f, 1.1f));
+ fret->SetAngleY(0, 0.1f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.8f);
+
+ m_object->SetFret(fret); // takes
+ }
+
+ if ( m_arm == TTA_FRIEND ) // takes friend's battery?
+ {
+ other = SearchFriendObject(angle, 1.5f, PI*0.04f);
+ if ( other == 0 ) return FALSE;
+
+ fret = other->RetPower();
+ if ( fret == 0 ) return FALSE; // the other does not have a battery?
+ m_fretType = fret->RetType();
+
+ other->SetPower(0);
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(4); // takes with the hand
+
+//? fret->SetPosition(0, D3DVECTOR(2.2f, -1.0f, 1.1f));
+ fret->SetPosition(0, D3DVECTOR(1.7f, -0.5f, 1.1f));
+ fret->SetAngleY(0, 0.1f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.8f);
+
+ m_object->SetFret(fret); // takes
+ }
+
+ return TRUE;
+}
+
+// Deposes the object taken.
+
+BOOL CTaskTake::TruckDeposeObject()
+{
+ Character* character;
+ CObject* fret;
+ CObject* other;
+ D3DMATRIX* mat;
+ D3DVECTOR pos;
+ float angle;
+
+ if ( m_arm == TTA_FFRONT ) // deposes on the ground in front?
+ {
+ fret = m_object->RetFret();
+ if ( fret == 0 ) return FALSE; // does nothing?
+ m_fretType = fret->RetType();
+
+ mat = fret->RetWorldMatrix(0);
+ pos = Transform(*mat, D3DVECTOR(-0.5f, 1.0f, 0.0f));
+ m_terrain->MoveOnFloor(pos);
+ fret->SetPosition(0, pos);
+ fret->SetAngleY(0, m_object->RetAngleY(0)+PI/2.0f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.0f);
+ fret->FloorAdjust(); // plate well on the ground
+
+ fret->SetTruck(0);
+ m_object->SetFret(0); // deposit
+ }
+
+ if ( m_arm == TTA_FRIEND ) // deposes battery on friends?
+ {
+ other = SearchFriendObject(angle, 1.5f, PI*0.04f);
+ if ( other == 0 ) return FALSE;
+
+ fret = other->RetPower();
+ if ( fret != 0 ) return FALSE; // the other already has a battery?
+
+ fret = m_object->RetFret();
+ if ( fret == 0 ) return FALSE;
+ m_fretType = fret->RetType();
+
+ other->SetPower(fret);
+ fret->SetTruck(other);
+
+ character = other->RetCharacter();
+ fret->SetPosition(0, character->posPower);
+ fret->SetAngleY(0, 0.0f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.0f);
+ fret->SetTruckPart(0); // carried by the base
+
+ m_object->SetFret(0); // deposit
+ }
+
+ return TRUE;
+}
+
+// Seeks if a location allows to deposit an object.
+
+BOOL CTaskTake::IsFreeDeposeObject(D3DVECTOR pos)
+{
+ CObject* pObj;
+ D3DMATRIX* mat;
+ D3DVECTOR iPos, oPos;
+ float oRadius;
+ int i, j;
+
+ mat = m_object->RetWorldMatrix(0);
+ iPos = Transform(*mat, pos);
+
+ 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; // inactive?
+ if ( pObj->RetTruck() != 0 ) continue; // object transported?
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ if ( Length(iPos, oPos)-(oRadius+1.0f) < 1.0f )
+ {
+ return FALSE; // location occupied
+ }
+ }
+ }
+ return TRUE; // location free
+}
+
+
diff --git a/src/object/task/tasktake.h b/src/object/task/tasktake.h
new file mode 100644
index 0000000..80b8736
--- /dev/null
+++ b/src/object/task/tasktake.h
@@ -0,0 +1,85 @@
+// * 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/.
+
+// tasktake.h
+
+#ifndef _TASKTAKE_H_
+#define _TASKTAKE_H_
+
+
+#include "misc.h"
+#include "object.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskTakeOrder
+{
+ TTO_TAKE = 1, // takes an object
+ TTO_DEPOSE = 2, // deposes the object
+};
+
+enum TaskTakeArm
+{
+ TTA_NEUTRAL = 1, // empty arm at rest
+ TTA_FFRONT = 2, // arm on the ground
+ TTA_FRIEND = 3, // arm behind a friend robot
+};
+
+
+
+class CTaskTake : public CTask
+{
+public:
+ CTaskTake(CInstanceManager* iMan, CObject* object);
+ ~CTaskTake();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start();
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ CObject* SearchTakeObject(float &angle, float dLimit, float aLimit);
+ CObject* SearchFriendObject(float &angle, float dLimit, float aLimit);
+ BOOL TruckTakeObject();
+ BOOL TruckDeposeObject();
+ BOOL IsFreeDeposeObject(D3DVECTOR pos);
+
+protected:
+ CTerrain* m_terrain;
+
+ TaskTakeOrder m_order;
+ TaskTakeArm m_arm;
+ int m_step;
+ float m_speed;
+ float m_progress;
+ float m_height;
+ BOOL m_bError;
+ BOOL m_bTurn;
+ float m_angle;
+ ObjectType m_fretType;
+};
+
+
+#endif //_TASKTAKE_H_
diff --git a/src/object/task/taskterraform.cpp b/src/object/task/taskterraform.cpp
new file mode 100644
index 0000000..e2f75fc
--- /dev/null
+++ b/src/object/task/taskterraform.cpp
@@ -0,0 +1,429 @@
+// * 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/.
+
+// taskterraform.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "language.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "pyro.h"
+#include "brain.h"
+#include "camera.h"
+#include "sound.h"
+#include "motion.h"
+#include "motionant.h"
+#include "motionspider.h"
+#include "task.h"
+#include "taskterraform.h"
+
+
+#define ENERGY_TERRA 0.40f // energy consumed by blow
+#define ACTION_RADIUS 400.0f
+
+
+
+// Object's constructor.
+
+CTaskTerraform::CTaskTerraform(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+ m_lastParticule = 0.0f;
+ m_soundChannel = -1;
+}
+
+// Object's destructor.
+
+CTaskTerraform::~CTaskTerraform()
+{
+}
+
+
+// Management of an event.
+
+BOOL CTaskTerraform::EventProcess(const Event &event)
+{
+ CObject* power;
+ D3DMATRIX* mat;
+ D3DVECTOR pos, dir, speed;
+ FPOINT dim;
+ float energy;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ m_progress += event.rTime*m_speed; // others advance
+ m_time += event.rTime;
+
+ if ( m_phase == TTP_CHARGE )
+ {
+ if ( m_soundChannel == -1 )
+ {
+#if _TEEN
+ m_soundChannel = m_sound->Play(SOUND_GGG, m_object->RetPosition(0), 1.0f, 0.5f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 2.0f, 1.5f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.5f, 0.5f, SOPER_STOP);
+#else
+ m_soundChannel = m_sound->Play(SOUND_GGG, m_object->RetPosition(0), 1.0f, 0.5f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 2.0f, 4.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.5f, 0.5f, SOPER_STOP);
+#endif
+ }
+
+ dir.x = 0.0f;
+ dir.y = (Rand()-0.5f)*0.2f*m_progress;
+ dir.z = 0.0f;
+ m_object->SetCirVibration(dir);
+
+ m_object->SetZoom(0, 1.0f+m_progress*0.2f);
+
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ power->SetZoom(0, 1.0f+m_progress*1.0f);
+
+ energy = power->RetEnergy();
+ energy -= event.rTime*ENERGY_TERRA/power->RetCapacity()/4.0f;
+ if ( energy < 0.0f ) energy = 0.0f;
+ power->SetEnergy(energy);
+ }
+ }
+
+ if ( m_phase == TTP_DOWN )
+ {
+ pos.x = 9.0f;
+#if _TEEN
+ pos.y = 4.0f-m_progress*4.0f;
+#else
+ pos.y = 4.0f-m_progress*5.8f;
+#endif
+ pos.z = 0.0f;
+ m_object->SetPosition(2, pos);
+ }
+
+ if ( m_phase == TTP_UP )
+ {
+ pos.x = 9.0f;
+#if _TEEN
+ pos.y = 4.0f-(1.0f-m_progress)*4.0f;
+#else
+ pos.y = 4.0f-(1.0f-m_progress)*5.8f;
+#endif
+ pos.z = 0.0f;
+ m_object->SetPosition(2, pos);
+ }
+
+ dir.x = 0.0f;
+ dir.y = 0.0f;
+ dir.z = 0.0f;
+ pos = m_object->RetPosition(2);
+ if ( pos.y < 0.0f )
+ {
+ dir.z = -atanf((pos.y/2.0f)/9.0f);
+ }
+ m_object->SetInclinaison(dir);
+
+ if ( m_time-m_lastParticule >= m_engine->ParticuleAdapt(0.05f) )
+ {
+ m_lastParticule = m_time;
+
+ mat = m_object->RetWorldMatrix(0);
+
+ if ( m_phase == TTP_CHARGE )
+ {
+ // Battery.
+ pos = D3DVECTOR(-6.0f, 5.5f+2.0f*m_progress, 0.0f);
+ pos.x += (Rand()-0.5f)*1.0f;
+ pos.z += (Rand()-0.5f)*1.0f;
+ pos = Transform(*mat, pos);
+ speed.x = (Rand()-0.5f)*6.0f*(1.0f+m_progress*4.0f);
+ speed.z = (Rand()-0.5f)*6.0f*(1.0f+m_progress*4.0f);
+ speed.y = 6.0f+Rand()*4.0f*(1.0f+m_progress*2.0f);
+ dim.x = 0.5f+1.5f*m_progress;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLITZ, 2.0f, 20.0f);
+ }
+
+ if ( m_phase != TTP_CHARGE )
+ {
+ // Left grid.
+ pos = D3DVECTOR(-1.0f, 5.8f, 3.5f);
+ pos.x += (Rand()-0.5f)*1.0f;
+ pos.z += (Rand()-0.5f)*1.0f;
+ pos = Transform(*mat, pos);
+ speed.x = Rand()*4.0f;
+ speed.z = Rand()*2.0f;
+ speed.y = 2.5f+Rand()*1.0f;
+ speed = Transform(*mat, speed);
+ speed -= m_object->RetPosition(0);
+ dim.x = Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE1, 3.0f);
+
+ // Right grid.
+ pos = D3DVECTOR(-1.0f, 5.8f, -3.5f);
+ pos.x += (Rand()-0.5f)*1.0f;
+ pos.z += (Rand()-0.5f)*1.0f;
+ pos = Transform(*mat, pos);
+ speed.x = Rand()*4.0f;
+ speed.z = -Rand()*2.0f;
+ speed.y = 2.5f+Rand()*1.0f;
+ speed = Transform(*mat, speed);
+ speed -= m_object->RetPosition(0);
+ dim.x = Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE1, 3.0f);
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Assigns the goal was achieved.
+
+Error CTaskTerraform::Start()
+{
+ CObject* power;
+ D3DMATRIX* mat;
+ D3DVECTOR pos, speed;
+ float energy;
+
+ ObjectType type;
+
+ m_bError = TRUE; // operation impossible
+ if ( !m_physics->RetLand() ) return ERR_TERRA_VEH;
+
+ type = m_object->RetType();
+ if ( type != OBJECT_MOBILErt ) return ERR_TERRA_VEH;
+
+ power = m_object->RetPower();
+ if ( power == 0 ) return ERR_TERRA_ENERGY;
+ energy = power->RetEnergy();
+ if ( energy < ENERGY_TERRA/power->RetCapacity()+0.05f ) return ERR_TERRA_ENERGY;
+
+ speed = m_physics->RetMotorSpeed();
+ if ( speed.x != 0.0f ||
+ speed.z != 0.0f ) return ERR_MANIP_MOTOR;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(9.0f, 0.0f, 0.0f);
+ pos = Transform(*mat, pos); // battery position
+ m_terraPos = pos;
+
+ m_phase = TTP_CHARGE;
+ m_progress = 0.0f;
+#if _TEEN
+ m_speed = 1.0f/1.5f;
+#else
+ m_speed = 1.0f/4.0f;
+#endif
+ m_time = 0.0f;
+
+ m_bError = FALSE; // ok
+
+ m_camera->StartCentering(m_object, PI*0.35f, 99.9f, 20.0f, 2.0f);
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskTerraform::IsEnded()
+{
+ CObject* power;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float dist, duration;
+ int i, max;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+ m_progress = 0.0f;
+
+ if ( m_phase == TTP_CHARGE )
+ {
+#if _TEEN
+ Terraform(); // changes the terrain.
+#endif
+
+ m_phase = TTP_DOWN;
+ m_speed = 1.0f/0.2f;
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TTP_DOWN )
+ {
+#if !_TEEN
+ Terraform(); // changes the terrain.
+#endif
+
+ m_object->SetCirVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_object->SetZoom(0, 1.0f);
+
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ power->SetZoom(0, 1.0f);
+ }
+
+ max= (int)(50.0f*m_engine->RetParticuleDensity());
+ for ( i=0 ; i<max ; i++ )
+ {
+ pos.x = m_terraPos.x+(Rand()-0.5f)*80.0f;
+ pos.z = m_terraPos.z+(Rand()-0.5f)*80.0f;
+ pos.y = m_terraPos.y;
+ m_terrain->MoveOnFloor(pos);
+ dist = Length(pos, m_terraPos);
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 2.0f+(40.0f-dist)/(1.0f+Rand()*4.0f);
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f);
+
+ pos = m_terraPos;
+ speed.x = (Rand()-0.5f)*40.0f;
+ speed.z = (Rand()-0.5f)*40.0f;
+ speed.y = Rand()*15.0f+15.0f;
+ dim.x = 0.6f;
+ dim.y = dim.x;
+ pos.y += dim.y;
+ duration = Rand()*3.0f+3.0f;
+ m_particule->CreateTrack(pos, speed, dim, PARTITRACK5,
+ duration, Rand()*10.0f+15.0f,
+ duration*0.2f, 1.0f);
+ }
+
+ m_phase = TTP_TERRA;
+ m_speed = 1.0f/2.0f;
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TTP_TERRA )
+ {
+ m_phase = TTP_UP;
+ m_speed = 1.0f/1.0f;
+ return ERR_CONTINUE;
+ }
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Suddenly ends the current action.
+
+BOOL CTaskTerraform::Abort()
+{
+ CObject* power;
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.5f, 0.3f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ m_object->SetPosition(2, D3DVECTOR(9.0f, 4.0f, 0.0f));
+ m_object->SetInclinaison(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_object->SetCirVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_object->SetZoom(0, 1.0f);
+
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ power->SetZoom(0, 1.0f);
+ }
+
+ m_camera->StopCentering(m_object, 2.0f);
+ return TRUE;
+}
+
+
+// Returns all the close ants and spiders.
+
+BOOL CTaskTerraform::Terraform()
+{
+ CObject* pObj;
+ CBrain* brain;
+ CMotion* motion;
+ CPyro* pyro;
+ ObjectType type;
+ float dist;
+ int i;
+
+ m_camera->StartEffect(CE_TERRAFORM, m_terraPos, 1.0f);
+
+ m_sound->Play(SOUND_THUMP, m_terraPos);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_NULL ) continue;
+
+ if ( type == OBJECT_TEEN34 ) // stone?
+ {
+ dist = Length(m_terraPos, pObj->RetPosition(0));
+ if ( dist > 20.0f ) continue;
+
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_FRAGT, pObj);
+ }
+ else
+ {
+ motion = pObj->RetMotion();
+ if ( motion == 0 ) continue;
+
+ dist = Length(m_terraPos, pObj->RetPosition(0));
+ if ( dist > ACTION_RADIUS ) continue;
+
+ if ( type == OBJECT_ANT )
+ {
+ brain = pObj->RetBrain();
+ if ( brain != 0 ) brain->StopTask();
+ motion->SetAction(MAS_BACK1, 0.8f+Rand()*0.3f);
+ pObj->SetFixed(TRUE); // not moving
+ }
+ if ( type == OBJECT_SPIDER )
+ {
+ brain = pObj->RetBrain();
+ if ( brain != 0 ) brain->StopTask();
+ motion->SetAction(MSS_BACK1, 0.8f+Rand()*0.3f);
+ pObj->SetFixed(TRUE); // not moving
+ }
+ }
+ }
+
+ return TRUE;
+}
+
diff --git a/src/object/task/taskterraform.h b/src/object/task/taskterraform.h
new file mode 100644
index 0000000..254e363
--- /dev/null
+++ b/src/object/task/taskterraform.h
@@ -0,0 +1,72 @@
+// * 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/.
+
+// taskterraform.h
+
+#ifndef _TASKSTERRAFORM_H_
+#define _TASKSTERRAFORM_H_
+
+
+#include "misc.h"
+#include "d3dengine.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskTerraPhase
+{
+ TTP_CHARGE = 1, // charge of energy
+ TTP_DOWN = 2, // down
+ TTP_TERRA = 3, // strike
+ TTP_UP = 4, // up
+};
+
+
+
+class CTaskTerraform : public CTask
+{
+public:
+ CTaskTerraform(CInstanceManager* iMan, CObject* object);
+ ~CTaskTerraform();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start();
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ BOOL Terraform();
+
+protected:
+ TaskTerraPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_time;
+ float m_lastParticule;
+ int m_soundChannel;
+ BOOL m_bError;
+ D3DVECTOR m_terraPos;
+};
+
+
+#endif //_TASKSTERRAFORM_H_
diff --git a/src/object/task/taskturn.cpp b/src/object/task/taskturn.cpp
new file mode 100644
index 0000000..832f523
--- /dev/null
+++ b/src/object/task/taskturn.cpp
@@ -0,0 +1,147 @@
+// * 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/.
+
+// taskturn.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "d3dengine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "task.h"
+#include "taskturn.h"
+
+
+
+
+// Object's constructor.
+
+CTaskTurn::CTaskTurn(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+}
+
+// Object's destructor.
+
+CTaskTurn::~CTaskTurn()
+{
+}
+
+
+// Management of an event.
+
+BOOL CTaskTurn::EventProcess(const Event &event)
+{
+ 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
+ m_bError = TRUE;
+ return TRUE;
+ }
+
+ return TRUE;
+}
+
+
+// Assigns the goal was achieved.
+// A positive angle is turning right.
+
+Error CTaskTurn::Start(float angle)
+{
+ m_startAngle = m_object->RetAngleY(0);
+ m_finalAngle = m_startAngle+angle;
+
+ if ( angle < 0.0f )
+ {
+ m_angle = angle+m_physics->RetCirStopLength();
+ m_physics->SetMotorSpeedZ(-1.0f); // turns left
+ m_bLeft = TRUE;
+ }
+ else
+ {
+ m_angle = angle-m_physics->RetCirStopLength();
+ m_physics->SetMotorSpeedZ(1.0f); // turns right
+ m_bLeft = FALSE;
+ }
+ m_physics->SetMotorSpeedX(0.0f);
+ m_physics->SetMotorSpeedY(0.0f);
+
+ m_bError = FALSE;
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskTurn::IsEnded()
+{
+ float angle;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+
+ if ( m_bError )
+ {
+ return ERR_STOP;
+ }
+
+ angle = m_object->RetAngleY(0);
+
+ if ( m_bLeft )
+ {
+ if ( angle <= m_startAngle+m_angle )
+ {
+ m_physics->SetMotorSpeedZ(0.0f);
+//? m_physics->SetCirMotionY(MO_MOTSPEED, 0.0f);
+ m_physics->SetCirMotionY(MO_CURSPEED, 0.0f);
+//? m_physics->SetCirMotionY(MO_REASPEED, 0.0f);
+ m_object->SetAngleY(0, m_finalAngle);
+ return ERR_STOP;
+ }
+ }
+ else
+ {
+ if ( angle >= m_startAngle+m_angle )
+ {
+ m_physics->SetMotorSpeedZ(0.0f);
+//? m_physics->SetCirMotionY(MO_MOTSPEED, 0.0f);
+ m_physics->SetCirMotionY(MO_CURSPEED, 0.0f);
+//? m_physics->SetCirMotionY(MO_REASPEED, 0.0f);
+ m_object->SetAngleY(0, m_finalAngle);
+ return ERR_STOP;
+ }
+ }
+
+ return ERR_CONTINUE;
+}
+
+
diff --git a/src/object/task/taskturn.h b/src/object/task/taskturn.h
new file mode 100644
index 0000000..abaef57
--- /dev/null
+++ b/src/object/task/taskturn.h
@@ -0,0 +1,55 @@
+// * 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/.
+
+// taskturn.h
+
+#ifndef _TASKTURN_H_
+#define _TASKTURN_H_
+
+
+#include "misc.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+class CTaskTurn : public CTask
+{
+public:
+ CTaskTurn(CInstanceManager* iMan, CObject* object);
+ ~CTaskTurn();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(float angle);
+ Error IsEnded();
+
+protected:
+
+protected:
+ float m_angle;
+ float m_startAngle;
+ float m_finalAngle;
+ BOOL m_bLeft;
+ BOOL m_bError;
+};
+
+
+#endif //_TASKTURN_H_
diff --git a/src/object/task/taskwait.cpp b/src/object/task/taskwait.cpp
new file mode 100644
index 0000000..af06383
--- /dev/null
+++ b/src/object/task/taskwait.cpp
@@ -0,0 +1,89 @@
+// * 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/.
+
+// taskwait.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "d3dengine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "task.h"
+#include "taskwait.h"
+
+
+
+
+// Object's constructor.
+
+CTaskWait::CTaskWait(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+}
+
+// Object's destructor.
+
+CTaskWait::~CTaskWait()
+{
+}
+
+
+// Management of an event.
+
+BOOL CTaskWait::EventProcess(const Event &event)
+{
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_passTime += event.rTime;
+ m_bEnded = (m_passTime >= m_waitTime);
+ return TRUE;
+}
+
+
+// Assigns the goal was achieved.
+
+Error CTaskWait::Start(float time)
+{
+ m_waitTime = time; // duration to wait
+ m_passTime = 0.0f; // time elapsed
+ m_bEnded = FALSE;
+ return ERR_OK;
+}
+
+// Indicates whether the action is finished.
+
+Error CTaskWait::IsEnded()
+{
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bEnded ) return ERR_STOP;
+ return ERR_CONTINUE;
+}
+
+
diff --git a/src/object/task/taskwait.h b/src/object/task/taskwait.h
new file mode 100644
index 0000000..e8ba2b6
--- /dev/null
+++ b/src/object/task/taskwait.h
@@ -0,0 +1,53 @@
+// * 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/.
+
+// taskwait.h
+
+#ifndef _TASKWAIT_H_
+#define _TASKWAIT_H_
+
+
+#include "misc.h"
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+class CTaskWait : public CTask
+{
+public:
+ CTaskWait(CInstanceManager* iMan, CObject* object);
+ ~CTaskWait();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(float time);
+ Error IsEnded();
+
+protected:
+
+protected:
+ float m_waitTime;
+ float m_passTime;
+ BOOL m_bEnded;
+};
+
+
+#endif //_TASKWAIT_H_