2014-10-14 13:11:37 +00:00
|
|
|
|
/*
|
|
|
|
|
* This file is part of the Colobot: Gold Edition source code
|
|
|
|
|
* Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam
|
|
|
|
|
* http://epsiteс.ch; http://colobot.info; http://github.com/colobot
|
|
|
|
|
*
|
|
|
|
|
* 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://gnu.org/licenses
|
|
|
|
|
*/
|
2012-06-26 20:23:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "object/task/taskflag.h"
|
|
|
|
|
|
2013-02-16 21:37:43 +00:00
|
|
|
|
#include "math/geometry.h"
|
|
|
|
|
|
2012-09-11 21:11:34 +00:00
|
|
|
|
#include "graphics/engine/particle.h"
|
2015-06-22 19:58:58 +00:00
|
|
|
|
#include "graphics/engine/pyro_manager.h"
|
2012-09-11 21:11:34 +00:00
|
|
|
|
#include "graphics/engine/water.h"
|
2013-02-16 21:37:43 +00:00
|
|
|
|
|
2015-06-20 18:02:40 +00:00
|
|
|
|
#include "object/object_manager.h"
|
2012-06-26 20:23:05 +00:00
|
|
|
|
#include "object/motion/motionhuman.h"
|
2015-07-10 20:13:39 +00:00
|
|
|
|
#include "object/interface/carrier_object.h"
|
2012-06-26 20:23:05 +00:00
|
|
|
|
|
2013-02-16 21:37:43 +00:00
|
|
|
|
#include "physics/physics.h"
|
|
|
|
|
|
2012-06-26 20:23:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Object's constructor.
|
|
|
|
|
|
2013-02-16 21:37:43 +00:00
|
|
|
|
CTaskFlag::CTaskFlag(CObject* object) : CTask(object)
|
2012-06-26 20:23:05 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Object's destructor.
|
|
|
|
|
|
|
|
|
|
CTaskFlag::~CTaskFlag()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Management of an event.
|
|
|
|
|
|
|
|
|
|
bool CTaskFlag::EventProcess(const Event &event)
|
|
|
|
|
{
|
|
|
|
|
if ( m_bError ) return true;
|
2012-09-11 21:11:34 +00:00
|
|
|
|
if ( m_engine->GetPause() ) return true;
|
|
|
|
|
if ( event.type != EVENT_FRAME ) return true;
|
2012-06-26 20:23:05 +00:00
|
|
|
|
|
|
|
|
|
m_time += event.rTime;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Assigns the goal was achieved.
|
|
|
|
|
|
|
|
|
|
Error CTaskFlag::Start(TaskFlagOrder order, int rank)
|
|
|
|
|
{
|
|
|
|
|
Math::Vector pos, speed;
|
|
|
|
|
Error err;
|
|
|
|
|
|
|
|
|
|
m_order = order;
|
|
|
|
|
m_time = 0.0f;
|
|
|
|
|
|
|
|
|
|
m_bError = true; // operation impossible
|
2012-09-11 21:11:34 +00:00
|
|
|
|
if ( !m_physics->GetLand() )
|
2012-06-26 20:23:05 +00:00
|
|
|
|
{
|
2015-07-12 09:01:16 +00:00
|
|
|
|
pos = m_object->GetPosition();
|
2012-09-11 21:11:34 +00:00
|
|
|
|
if ( pos.y < m_water->GetLevel() ) return ERR_FLAG_WATER;
|
2012-06-26 20:23:05 +00:00
|
|
|
|
return ERR_FLAG_FLY;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-11 21:11:34 +00:00
|
|
|
|
speed = m_physics->GetMotorSpeed();
|
2012-06-26 20:23:05 +00:00
|
|
|
|
if ( speed.x != 0.0f ||
|
|
|
|
|
speed.z != 0.0f ) return ERR_FLAG_MOTOR;
|
|
|
|
|
|
2015-07-10 20:13:39 +00:00
|
|
|
|
if (IsObjectCarryingCargo(m_object)) return ERR_FLAG_BUSY;
|
2012-06-26 20:23:05 +00:00
|
|
|
|
|
|
|
|
|
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, Math::PI*0.3f, 99.9f, 0.0f, 0.5f);
|
|
|
|
|
|
|
|
|
|
return ERR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Indicates whether the action is finished.
|
|
|
|
|
|
|
|
|
|
Error CTaskFlag::IsEnded()
|
|
|
|
|
{
|
2012-09-11 21:11:34 +00:00
|
|
|
|
if ( m_engine->GetPause() ) return ERR_CONTINUE;
|
2012-06-26 20:23:05 +00:00
|
|
|
|
|
|
|
|
|
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(Math::Vector pos, ObjectType type)
|
|
|
|
|
{
|
2014-12-21 16:06:55 +00:00
|
|
|
|
std::vector<ObjectType> types;
|
|
|
|
|
if(type == OBJECT_NULL)
|
2012-06-26 20:23:05 +00:00
|
|
|
|
{
|
2014-12-21 16:06:55 +00:00
|
|
|
|
types = {OBJECT_FLAGb, OBJECT_FLAGr, OBJECT_FLAGg, OBJECT_FLAGy, OBJECT_FLAGv};
|
|
|
|
|
} else {
|
|
|
|
|
types = {type};
|
2012-06-26 20:23:05 +00:00
|
|
|
|
}
|
2014-12-21 16:06:55 +00:00
|
|
|
|
return CObjectManager::GetInstancePointer()->FindNearest(nullptr, pos, types);
|
2012-06-26 20:23:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Counts the number of existing objects.
|
|
|
|
|
|
|
|
|
|
int CTaskFlag::CountObject(ObjectType type)
|
|
|
|
|
{
|
2015-06-21 14:22:09 +00:00
|
|
|
|
int count = 0;
|
|
|
|
|
for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
|
2012-06-26 20:23:05 +00:00
|
|
|
|
{
|
2015-06-21 14:22:09 +00:00
|
|
|
|
if ( !obj->GetEnable() ) continue;
|
2012-06-26 20:23:05 +00:00
|
|
|
|
|
2015-06-21 14:22:09 +00:00
|
|
|
|
ObjectType oType = obj->GetType();
|
2012-06-26 20:23:05 +00:00
|
|
|
|
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)
|
|
|
|
|
{
|
2015-06-20 17:27:43 +00:00
|
|
|
|
ObjectType table[5] =
|
2012-06-26 20:23:05 +00:00
|
|
|
|
{
|
|
|
|
|
OBJECT_FLAGb,
|
|
|
|
|
OBJECT_FLAGr,
|
|
|
|
|
OBJECT_FLAGg,
|
|
|
|
|
OBJECT_FLAGy,
|
|
|
|
|
OBJECT_FLAGv,
|
|
|
|
|
};
|
|
|
|
|
|
2015-06-20 17:27:43 +00:00
|
|
|
|
Math::Matrix* mat = m_object->GetWorldMatrix(0);
|
|
|
|
|
Math::Vector pos = Transform(*mat, Math::Vector(4.0f, 0.0f, 0.0f));
|
2012-06-26 20:23:05 +00:00
|
|
|
|
|
2015-06-20 17:27:43 +00:00
|
|
|
|
CObject* pObj = SearchNearest(pos, OBJECT_NULL);
|
|
|
|
|
if ( pObj != nullptr )
|
2012-06-26 20:23:05 +00:00
|
|
|
|
{
|
2015-07-12 09:01:16 +00:00
|
|
|
|
float dist = Math::Distance(pos, pObj->GetPosition());
|
2012-06-26 20:23:05 +00:00
|
|
|
|
if ( dist < 10.0f )
|
|
|
|
|
{
|
|
|
|
|
return ERR_FLAG_PROXY;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-20 17:27:43 +00:00
|
|
|
|
ObjectType type = table[rank];
|
|
|
|
|
if ( CountObject(type) >= 5 )
|
2012-06-26 20:23:05 +00:00
|
|
|
|
{
|
|
|
|
|
return ERR_FLAG_CREATE;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-20 17:27:43 +00:00
|
|
|
|
float angle = 0.0f;
|
|
|
|
|
CObject* pNew = CObjectManager::GetInstancePointer()->CreateObject(pos, angle, type);
|
2012-09-27 22:05:49 +00:00
|
|
|
|
//pNew->SetZoom(0, 0.0f);
|
2012-06-26 20:23:05 +00:00
|
|
|
|
|
|
|
|
|
m_sound->Play(SOUND_WAYPOINT, pos);
|
2015-06-22 19:58:58 +00:00
|
|
|
|
m_engine->GetPyroManager()->Create(Gfx::PT_FLCREATE, pNew);
|
2012-06-26 20:23:05 +00:00
|
|
|
|
|
|
|
|
|
return ERR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Deletes a color indicator.
|
|
|
|
|
|
|
|
|
|
Error CTaskFlag::DeleteFlag()
|
|
|
|
|
{
|
2012-09-11 21:11:34 +00:00
|
|
|
|
CObject* pObj;
|
|
|
|
|
Math::Vector iPos, oPos;
|
|
|
|
|
float iAngle, angle, aLimit, dist;
|
2012-06-26 20:23:05 +00:00
|
|
|
|
|
2015-07-12 09:01:16 +00:00
|
|
|
|
iPos = m_object->GetPosition();
|
2012-09-11 21:11:34 +00:00
|
|
|
|
iAngle = m_object->GetAngleY(0);
|
2012-06-26 20:23:05 +00:00
|
|
|
|
iAngle = Math::NormAngle(iAngle); // 0..2*Math::PI
|
|
|
|
|
|
|
|
|
|
pObj = SearchNearest(iPos, OBJECT_NULL);
|
|
|
|
|
if ( pObj == 0 )
|
|
|
|
|
{
|
|
|
|
|
return ERR_FLAG_DELETE;
|
|
|
|
|
}
|
2015-07-12 09:01:16 +00:00
|
|
|
|
dist = Math::Distance(iPos, pObj->GetPosition());
|
2012-06-26 20:23:05 +00:00
|
|
|
|
if ( dist > 10.0f )
|
|
|
|
|
{
|
|
|
|
|
return ERR_FLAG_DELETE;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-12 09:01:16 +00:00
|
|
|
|
oPos = pObj->GetPosition();
|
2012-06-26 20:23:05 +00:00
|
|
|
|
angle = Math::RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
|
|
|
|
|
aLimit = 45.0f*Math::PI/180.0f;
|
|
|
|
|
if ( !Math::TestAngle(angle, iAngle-aLimit, iAngle+aLimit) )
|
|
|
|
|
{
|
|
|
|
|
return ERR_FLAG_DELETE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_sound->Play(SOUND_WAYPOINT, iPos);
|
2015-06-22 19:58:58 +00:00
|
|
|
|
|
|
|
|
|
m_engine->GetPyroManager()->Create(Gfx::PT_FLDELETE, pObj);
|
2012-06-26 20:23:05 +00:00
|
|
|
|
|
|
|
|
|
return ERR_OK;
|
|
|
|
|
}
|
|
|
|
|
|