colobot/src/ui/controls/map.cpp

1372 lines
38 KiB
C++

/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.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
*/
#include "ui/controls/map.h"
#include "common/image.h"
#include "graphics/core/device.h"
#include "graphics/engine/terrain.h"
#include "graphics/engine/water.h"
#include "level/robotmain.h"
#include "math/geometry.h"
#include "object/interface/controllable_object.h"
#include "object/interface/transportable_object.h"
#include <cstring>
namespace Ui
{
// Object's constructor.
CMap::CMap() : CControl()
{
m_main = CRobotMain::GetInstancePointer();
m_terrain = m_main->GetTerrain();
m_water = Gfx::CEngine::GetInstancePointer()->GetWater();
m_bEnable = true;
m_time = 0.0f;
m_zoom = 2.0f;
m_offset.x = 0.0f;
m_offset.y = 0.0f;
m_angle = 0.0f;
m_floorColor.r = 1.00f;
m_floorColor.g = 0.50f;
m_floorColor.b = 0.00f; // orange
m_waterColor.r = 0.00f;
m_waterColor.g = 0.80f;
m_waterColor.b = 1.00f; // blue
m_half = m_terrain->GetMosaicCount() * m_terrain->GetBrickCount() * m_terrain->GetBrickSize() / 2.0f;
m_highlightRank = -1;
m_totalFix = 0;
m_totalMove = 0;
m_bRadar = false;
FlushObject();
m_mode = 0;
m_bToy = false;
m_bDebug = false;
}
// Object's destructor.
CMap::~CMap()
{
}
// Creates a new button.
bool CMap::Create(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
{
if (eventMsg == EVENT_NULL)
eventMsg = GetUniqueEventType();
CControl::Create(pos, dim, icon, eventMsg);
return true;
}
// Choice of the offset, when image is displayed.
void CMap::SetOffset(float ox, float oy)
{
m_offset.x = ox;
m_offset.y = oy;
m_half = m_terrain->GetMosaicCount() * m_terrain->GetBrickCount() * m_terrain->GetBrickSize() / 2.0f;
}
// Choice of the global angle of rotation.
void CMap::SetAngle(float angle)
{
m_angle = angle;
}
// Specifies the alternate mode.
void CMap::SetMode(int mode)
{
m_mode = mode;
}
// Specifies the type of icon for the selected object.
void CMap::SetToy(bool bToy)
{
m_bToy = bToy;
}
void CMap::SetDebug(bool bDebug)
{
m_bDebug = bDebug;
}
//Choice of magnification of the map.
void CMap::SetZoom(float value)
{
m_zoom = value;
m_half = m_terrain->GetMosaicCount() * m_terrain->GetBrickCount() * m_terrain->GetBrickSize() / 2.0f;
}
float CMap::GetZoom()
{
return m_zoom;
}
// Choosing a fixed offset.
// Enables or disables the card.
void CMap::SetEnable(bool bEnable)
{
m_bEnable = bEnable;
SetState(STATE_DEAD, !bEnable);
}
bool CMap::GetEnable()
{
return m_bEnable;
}
// Choosing the color of the soil.
void CMap::SetFloorColor(Gfx::Color color)
{
m_floorColor = color;
}
// Choosing the color of the water.
void CMap::SetWaterColor(Gfx::Color color)
{
m_waterColor = color;
}
// Specifies a fixed image in place of the drawing of the relief.
void CMap::SetFixImage(const std::string& filename)
{
m_fixImage = filename;
}
// Whether to use a still image.
bool CMap::GetFixImage()
{
return ! m_fixImage.empty();
}
// Management of an event.
bool CMap::EventProcess(const Event &event)
{
if ( (m_state & STATE_VISIBLE) == 0 )
return true;
CControl::EventProcess(event);
if ( event.type == EVENT_FRAME )
m_time += event.rTime;
if ( event.type == EVENT_MOUSE_MOVE || event.type == EVENT_MOUSE_BUTTON_DOWN || event.type == EVENT_MOUSE_BUTTON_UP )
{
if (Detect(event.mousePos))
{
m_engine->SetMouseType(Gfx::ENG_MOUSE_NORM);
bool inMap = false;
if (DetectObject(event.mousePos, inMap) != nullptr)
m_engine->SetMouseType(Gfx::ENG_MOUSE_HAND);
}
}
if (event.type == EVENT_MOUSE_BUTTON_DOWN &&
event.GetData<MouseButtonEventData>()->button == MOUSE_BUTTON_LEFT)
{
if ( CControl::Detect(event.mousePos) )
{
SelectObject(event.mousePos);
return false;
}
}
return true;
}
// Adjusts the offset to not exceed the card.
Math::Point CMap::AdjustOffset(Math::Point offset)
{
float limit;
limit = m_half - m_half / m_zoom;
if ( offset.x < -limit ) offset.x = -limit;
if ( offset.x > limit ) offset.x = limit;
if ( offset.y < -limit ) offset.y = -limit;
if ( offset.y > limit ) offset.y = limit;
return offset;
}
// Indicates the object with the mouse hovers over.
void CMap::SetHighlight(CObject* pObj)
{
m_highlightRank = -1;
if ( m_bToy || !m_fixImage.empty())
return; // card with still image?
if ( pObj == nullptr )
return;
for (int i = 0; i < MAPMAXOBJECT; i++)
{
if ( !m_map[i].bUsed )
continue;
if ( m_map[i].object == pObj )
{
m_highlightRank = i;
break;
}
}
}
// Detects an object in the map.
CObject* CMap::DetectObject(Math::Point pos, bool &bInMap)
{
float dist, min;
int best;
bInMap = false;
if ( pos.x < m_pos.x ||
pos.y < m_pos.y ||
pos.x > m_pos.x + m_dim.x ||
pos.y > m_pos.y + m_dim.y )
return nullptr;
bInMap = true;
pos.x = (pos.x - m_pos.x) / m_dim.x * 256.0f;
pos.y = (pos.y - m_pos.y) / m_dim.y * 256.0f; // 0..256
pos.x = (pos.x - 128.0f) * m_half / (m_zoom * 128.0f) + m_offset.x;
pos.y = (pos.y - 128.0f) * m_half / (m_zoom * 128.0f) + m_offset.y;
min = 10000.0f;
best = -1;
for (int i = MAPMAXOBJECT - 1; i >= 0; i--)
{
if ( !m_map[i].bUsed )
continue;
if ( m_map[i].color == MAPCOLOR_BBOX && !m_bRadar )
continue;
if ( m_map[i].color == MAPCOLOR_ALIEN && !m_bRadar )
continue;
dist = Math::Point(m_map[i].pos.x - pos.x, m_map[i].pos.y - pos.y).Length();
if ( dist > m_half / m_zoom * 8.0f / 100.0f )
continue; // too far?
if ( dist < min )
{
min = dist;
best = i;
}
}
if ( best == -1 )
return nullptr;
return m_map[best].object;
}
// Selects an object.
void CMap::SelectObject(Math::Point pos)
{
CObject *pObj;
bool bInMap;
pObj = DetectObject(pos, bInMap);
if ( pObj != nullptr )
m_main->SelectObject(pObj);
}
// Draw the map.
void CMap::Draw()
{
Math::Point uv1, uv2;
int i;
if ( (m_state & STATE_VISIBLE) == 0 )
return;
CControl::Draw(); // draws the bottom (button)
if ( !m_bEnable )
return;
if (m_fixImage.empty() && m_map[MAPMAXOBJECT - 1].bUsed)
m_offset = AdjustOffset(m_map[MAPMAXOBJECT - 1].pos);
if (m_fixImage.empty()) // drawing of the relief?
{
m_engine->SetTexture("textures/interface/map.png");
m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
uv1.x = 0.5f + (m_offset.x - (m_half / m_zoom)) / (m_half * 2.0f);
uv1.y = 0.5f - (m_offset.y + (m_half / m_zoom)) / (m_half * 2.0f);
uv2.x = 0.5f + (m_offset.x + (m_half / m_zoom)) / (m_half * 2.0f);
uv2.y = 0.5f - (m_offset.y - (m_half / m_zoom)) / (m_half * 2.0f);
DrawVertex(uv1, uv2, 0.97f); // drawing the map
}
else // still image?
{
m_engine->LoadTexture(m_fixImage);
m_engine->SetTexture(m_fixImage);
m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
uv1.x = 0.0f;
uv1.y = 0.0f;
uv2.x = 1.0f;
uv2.y = 1.0f;
DrawVertex(uv1, uv2, 0.97f); // drawing the map
}
i = MAPMAXOBJECT-1;
if ( m_map[i].bUsed ) // selection:
DrawFocus(m_map[i].pos, m_map[i].dir, m_map[i].type, m_map[i].color);
for ( i=0 ; i<m_totalFix ; i++ ) // fixed objects:
{
if ( i == m_highlightRank )
continue;
DrawObject(m_map[i].pos, m_map[i].dir, m_map[i].type, m_map[i].color, false, false);
}
for ( i=MAPMAXOBJECT-2 ; i>m_totalMove ; i-- ) // moving objects:
{
if ( i == m_highlightRank )
continue;
DrawObject(m_map[i].pos, m_map[i].dir, m_map[i].type, m_map[i].color, false, false);
}
i = MAPMAXOBJECT-1;
if ( m_map[i].bUsed && i != m_highlightRank ) // selection:
DrawObject(m_map[i].pos, m_map[i].dir, m_map[i].type, m_map[i].color, true, false);
if ( m_highlightRank != -1 && m_map[m_highlightRank].bUsed )
{
i = m_highlightRank;
DrawObject(m_map[i].pos, m_map[i].dir, m_map[i].type, m_map[i].color, false, true);
DrawHighlight(m_map[i].pos);
}
}
// Computing a point for drawFocus.
Math::Point CMap::MapInter(Math::Point pos, float dir)
{
Math::Point p1;
float limit;
p1.x = pos.x + 1.0f;
p1.y = pos.y;
p1 = Math::RotatePoint(pos, dir, p1);
p1.x -= pos.x;
p1.y -= pos.y;
limit = m_mapPos.x + m_mapDim.x - pos.x;
if ( p1.x > limit ) // exceeds the right?
{
p1.y = limit*p1.y/p1.x;
p1.x = limit;
}
limit = m_mapPos.y * 0.75f + m_mapDim.y * 0.75f - pos.y;
if ( p1.y > limit ) // exceeds the top?
{
p1.x = limit * p1.x / p1.y;
p1.y = limit;
}
limit = m_mapPos.x - pos.x;
if ( p1.x < limit ) // exceeds the left?
{
p1.y = limit * p1.y / p1.x;
p1.x = limit;
}
limit = m_mapPos.y * 0.75f - pos.y;
if ( p1.y < limit ) // exceeds the bottom?
{
p1.x = limit * p1.x / p1.y;
p1.y = limit;
}
p1.x += pos.x;
p1.y += pos.y;
return p1;
}
// Draw the field of vision of the selected object.
void CMap::DrawFocus(Math::Point pos, float dir, ObjectType type, MapColor color)
{
Math::Point p0, p1, p2, uv1, uv2, rel;
float aMin, aMax, aOct, focus, a;
float limit[5];
bool bEnding;
int quart;
if (m_bToy || !m_fixImage.empty()) return; // map with still image?
if ( color != MAPCOLOR_MOVE ) return;
pos.x = (pos.x-m_offset.x)*(m_zoom*0.5f)/m_half+0.5f;
pos.y = (pos.y-m_offset.y)*(m_zoom*0.5f)/m_half+0.5f;
if ( pos.x < 0.0f || pos.x > 1.0f ||
pos.y < 0.0f || pos.y > 1.0f ) return;
rel.x = pos.x*2.0f-1.0f;
rel.y = pos.y*2.0f-1.0f; // rel [-1..1]
pos.x = m_mapPos.x+m_mapDim.x*pos.x;
pos.y = m_mapPos.y*0.75f+m_mapDim.y*pos.y*0.75f;
focus = m_engine->GetFocus();
dir += Math::PI/2.0f;
aMin = Math::NormAngle(dir-Math::PI/4.0f*focus);
aMax = Math::NormAngle(dir+Math::PI/4.0f*focus);
if ( aMin > aMax )
{
aMax += Math::PI*2.0f; // aMax always after aMin
}
limit[0] = Math::RotateAngle( 1.0f-rel.x, 1.0f-rel.y); // upper/right
limit[1] = Math::RotateAngle(-1.0f-rel.x, 1.0f-rel.y); // upper/left
limit[2] = Math::RotateAngle(-1.0f-rel.x, -1.0f-rel.y); // lower/left
limit[3] = Math::RotateAngle( 1.0f-rel.x, -1.0f-rel.y); // lower/right
limit[4] = limit[0]+Math::PI*2.0f;
a = Math::NormAngle(aMin);
for ( quart=0 ; quart<4 ; quart++ )
{
if ( a >= limit[quart+0] &&
a <= limit[quart+1] ) break;
}
if ( quart == 4 ) quart = -1;
uv1.x = 113.0f/256.0f; // degrade green
uv1.y = 240.5f/256.0f;
uv2.x = 126.0f/256.0f;
uv2.y = 255.0f/256.0f;
m_engine->SetTexture("textures/interface/button2.png");
m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE);
bEnding = false;
do
{
quart ++;
aOct = limit[quart%4];
if ( quart >= 4 ) aOct += Math::PI*2.0f;
if ( aOct >= aMax - Math::VERY_SMALL_NUM )
{
aOct = aMax;
bEnding = true;
}
p0 = pos;
p1 = MapInter(pos, aMin);
p2 = MapInter(pos, aOct);
p0.y /= 0.75f;
p1.y /= 0.75f;
p2.y /= 0.75f;
DrawTriangle(p0, p2, p1, uv1, uv2);
aMin = aOct;
}
while ( !bEnding );
}
// Draw an object.
void CMap::DrawObject(Math::Point pos, float dir, ObjectType type, MapColor color,
bool bSelect, bool bHilite)
{
Math::Point p1, p2, p3, p4, p5, dim, uv1, uv2;
bool bOut, bUp, bDown, bLeft, bRight;
pos.x = (pos.x-m_offset.x)*(m_zoom*0.5f)/m_half+0.5f;
pos.y = (pos.y-m_offset.y)*(m_zoom*0.5f)/m_half+0.5f;
bOut = bUp = bDown = bLeft = bRight = false;
if ( pos.x < 0.06f ) { pos.x = 0.02f; bOut = bLeft = true; }
if ( pos.y < 0.06f ) { pos.y = 0.02f; bOut = bDown = true; }
if ( pos.x > 0.94f ) { pos.x = 0.98f; bOut = bRight = true; }
if ( pos.y > 0.94f ) { pos.y = 0.98f; bOut = bUp = true; }
pos.x = m_mapPos.x+m_mapDim.x*pos.x;
pos.y = m_mapPos.y+m_mapDim.y*pos.y;
dim.x = 2.0f/128.0f*0.75f;
dim.y = 2.0f/128.0f;
if ( bOut ) // outside the map?
{
if ( color == MAPCOLOR_BBOX && !m_bRadar ) return;
if ( color == MAPCOLOR_ALIEN && !m_bRadar ) return;
if ( Math::Mod(m_time+(pos.x+pos.y)*4.0f, 0.6f) > 0.2f )
{
return; // flashes
}
m_engine->SetTexture("textures/interface/button2.png");
m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
if ( bUp )
{
uv1.x = 160.5f/256.0f; // yellow triangle ^
uv1.y = 240.5f/256.0f;
uv2.x = 175.0f/256.0f;
uv2.y = 255.0f/256.0f;
}
if ( bDown )
{
uv1.x = 160.5f/256.0f; // yellow triangle v
uv1.y = 255.0f/256.0f;
uv2.x = 175.0f/256.0f;
uv2.y = 240.5f/256.0f;
}
if ( bRight )
{
uv1.x = 176.5f/256.0f; // yellow triangle >
uv1.y = 240.5f/256.0f;
uv2.x = 191.0f/256.0f;
uv2.y = 255.0f/256.0f;
}
if ( bLeft )
{
uv1.x = 191.0f/256.0f; // yellow triangle <
uv1.y = 240.5f/256.0f;
uv2.x = 176.5f/256.0f;
uv2.y = 255.0f/256.0f;
}
pos.x -= dim.x/2.0f;
pos.y -= dim.y/2.0f;
DrawIcon(pos, dim, uv1, uv2);
return;
}
if ( bSelect )
{
if ( m_bToy )
{
dim.x *= 1.2f+sinf(m_time*8.0f)*0.1f;
dim.y *= 1.2f+sinf(m_time*8.0f)*0.1f;
}
else
{
dim.x *= 1.2f+sinf(m_time*8.0f)*0.3f;
dim.y *= 1.2f+sinf(m_time*8.0f)*0.3f;
}
}
if ( color == MAPCOLOR_BASE ||
color == MAPCOLOR_FIX ||
color == MAPCOLOR_MOVE )
{
if ( bHilite )
{
dim.x *= 2.2f;
dim.y *= 2.2f;
}
else
{
dim.x *= 0.6f;
dim.y *= 0.6f;
}
}
if ( color == MAPCOLOR_ALIEN )
{
dim.x *= 1.4f;
dim.y *= 1.4f;
}
if ( type == OBJECT_TEEN28 ) // bottle?
{
dim.x *= 3.0f;
dim.y *= 3.0f;
bHilite = true;
}
if ( type == OBJECT_TEEN34 ) // stone?
{
dim.x *= 2.0f;
dim.y *= 2.0f;
bHilite = true;
}
if ( color == MAPCOLOR_MOVE && bSelect )
{
if ( m_bToy )
{
p1.x = pos.x;
p1.y = pos.y+dim.y*1.4f;
p1 = Math::RotatePoint(pos, dir, p1);
p1.x = pos.x+(p1.x-pos.x)*0.75f;
p2.x = pos.x+dim.x*1.2f;
p2.y = pos.y+dim.y*0.8f;
p2 = Math::RotatePoint(pos, dir, p2);
p2.x = pos.x+(p2.x-pos.x)*0.75f;
p3.x = pos.x+dim.x*1.2f;
p3.y = pos.y-dim.y*1.0f;
p3 = Math::RotatePoint(pos, dir, p3);
p3.x = pos.x+(p3.x-pos.x)*0.75f;
p4.x = pos.x-dim.x*1.2f;
p4.y = pos.y-dim.y*1.0f;
p4 = Math::RotatePoint(pos, dir, p4);
p4.x = pos.x+(p4.x-pos.x)*0.75f;
p5.x = pos.x-dim.x*1.2f;
p5.y = pos.y+dim.y*0.8f;
p5 = Math::RotatePoint(pos, dir, p5);
p5.x = pos.x+(p5.x-pos.x)*0.75f;
}
else
{
p1.x = pos.x;
p1.y = pos.y+dim.y*2.4f;
p1 = Math::RotatePoint(pos, dir, p1);
p1.x = pos.x+(p1.x-pos.x)*0.75f;
p2.x = pos.x+dim.x*1.0f;
p2.y = pos.y-dim.y*1.6f;
p2 = Math::RotatePoint(pos, dir, p2);
p2.x = pos.x+(p2.x-pos.x)*0.75f;
p3.x = pos.x-dim.x*1.0f;
p3.y = pos.y-dim.y*1.6f;
p3 = Math::RotatePoint(pos, dir, p3);
p3.x = pos.x+(p3.x-pos.x)*0.75f;
}
}
pos.x -= dim.x/2.0f;
pos.y -= dim.y/2.0f;
if ( color == MAPCOLOR_BASE ||
color == MAPCOLOR_FIX )
{
DrawObjectIcon(pos, dim, color, type, bHilite);
}
if ( color == MAPCOLOR_MOVE )
{
if ( bSelect )
{
m_engine->SetTexture("textures/interface/button2.png");
m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
if ( m_bToy )
{
uv1.x = 164.5f/256.0f; // black pentagon
uv1.y = 228.5f/256.0f;
uv2.x = 172.0f/256.0f;
uv2.y = 236.0f/256.0f;
DrawPenta(p1, p2, p3, p4, p5, uv1, uv2);
}
else
{
uv1.x = 144.5f/256.0f; // red triangle
uv1.y = 240.5f/256.0f;
uv2.x = 159.0f/256.0f;
uv2.y = 255.0f/256.0f;
DrawTriangle(p1, p2, p3, uv1, uv2);
}
}
DrawObjectIcon(pos, dim, color, type, bHilite);
}
if ( color == MAPCOLOR_BBOX )
{
if ( m_bRadar )
{
m_engine->SetTexture("textures/interface/button2.png");
m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE);
uv1.x = 64.5f/256.0f; // blue triangle
uv1.y = 240.5f/256.0f;
uv2.x = 79.0f/256.0f;
uv2.y = 255.0f/256.0f;
DrawIcon(pos, dim, uv1, uv2);
}
}
if ( color == MAPCOLOR_ALIEN )
{
if ( m_bRadar )
{
DrawObjectIcon(pos, dim, color, type, true);
}
}
if ( color == MAPCOLOR_WAYPOINTb )
{
m_engine->SetTexture("textures/interface/button2.png");
m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
uv1.x = 192.5f/256.0f; // blue cross
uv1.y = 240.5f/256.0f;
uv2.x = 207.0f/256.0f;
uv2.y = 255.0f/256.0f;
DrawIcon(pos, dim, uv1, uv2);
}
if ( color == MAPCOLOR_WAYPOINTr )
{
m_engine->SetTexture("textures/interface/button2.png");
m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
uv1.x = 208.5f/256.0f; // red cross
uv1.y = 240.5f/256.0f;
uv2.x = 223.0f/256.0f;
uv2.y = 255.0f/256.0f;
DrawIcon(pos, dim, uv1, uv2);
}
if ( color == MAPCOLOR_WAYPOINTg )
{
m_engine->SetTexture("textures/interface/button2.png");
m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
uv1.x = 224.5f/256.0f; // green cross
uv1.y = 240.5f/256.0f;
uv2.x = 239.0f/256.0f;
uv2.y = 255.0f/256.0f;
DrawIcon(pos, dim, uv1, uv2);
}
if ( color == MAPCOLOR_WAYPOINTy )
{
m_engine->SetTexture("textures/interface/button2.png");
m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
uv1.x = 240.5f/256.0f; // yellow cross
uv1.y = 240.5f/256.0f;
uv2.x = 255.0f/256.0f;
uv2.y = 255.0f/256.0f;
DrawIcon(pos, dim, uv1, uv2);
}
if ( color == MAPCOLOR_WAYPOINTv )
{
m_engine->SetTexture("textures/interface/button2.png");
m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
uv1.x = 192.5f/256.0f; // violet cross
uv1.y = 224.5f/256.0f;
uv2.x = 207.0f/256.0f;
uv2.y = 239.0f/256.0f;
DrawIcon(pos, dim, uv1, uv2);
}
}
// Draws the icon of an object.
void CMap::DrawObjectIcon(Math::Point pos, Math::Point dim, MapColor color,
ObjectType type, bool bHilite)
{
Math::Point ppos, ddim, uv1, uv2;
float dp;
int icon;
dp = 0.5f/256.0f;
m_engine->SetTexture("textures/interface/button3.png");
m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
if ( color == MAPCOLOR_MOVE )
{
uv1.x = 160.0f/256.0f; // blue
uv1.y = 224.0f/256.0f;
}
else if ( color == MAPCOLOR_ALIEN )
{
uv1.x = 224.0f/256.0f; // green
uv1.y = 224.0f/256.0f;
}
else
{
uv1.x = 192.0f/256.0f; // yellow
uv1.y = 224.0f/256.0f;
}
uv2.x = uv1.x+32.0f/256.0f;
uv2.y = uv1.y+32.0f/256.0f;
uv1.x += dp;
uv1.y += dp;
uv2.x -= dp;
uv2.y -= dp;
DrawIcon(pos, dim, uv1, uv2); // background colors
if ( bHilite )
{
switch ( type )
{
case OBJECT_FACTORY: icon = 32; break;
case OBJECT_DERRICK: icon = 33; break;
case OBJECT_CONVERT: icon = 34; break;
case OBJECT_RESEARCH: icon = 35; break;
case OBJECT_STATION: icon = 36; break;
case OBJECT_TOWER: icon = 37; break;
case OBJECT_LABO: icon = 38; break;
case OBJECT_ENERGY: icon = 39; break;
case OBJECT_RADAR: icon = 40; break;
case OBJECT_INFO: icon = 44; break;
case OBJECT_REPAIR: icon = 41; break;
case OBJECT_DESTROYER: icon = 41; break;
case OBJECT_NUCLEAR: icon = 42; break;
case OBJECT_PARA: icon = 46; break;
case OBJECT_SAFE: icon = 47; break;
case OBJECT_HUSTON: icon = 48; break;
case OBJECT_TARGET1: icon = 45; break;
case OBJECT_BASE: icon = 43; break;
case OBJECT_HUMAN: icon = 8; break;
case OBJECT_MOBILEfa: icon = 11; break;
case OBJECT_MOBILEta: icon = 10; break;
case OBJECT_MOBILEwa: icon = 9; break;
case OBJECT_MOBILEia: icon = 22; break;
case OBJECT_MOBILEfb: icon = 2; break; // button4
case OBJECT_MOBILEtb: icon = 1; break;
case OBJECT_MOBILEwb: icon = 0; break;
case OBJECT_MOBILEib: icon = 3; break;
case OBJECT_MOBILEfc: icon = 17; break;
case OBJECT_MOBILEtc: icon = 16; break;
case OBJECT_MOBILEwc: icon = 15; break;
case OBJECT_MOBILEic: icon = 23; break;
case OBJECT_MOBILEfi: icon = 27; break;
case OBJECT_MOBILEti: icon = 26; break;
case OBJECT_MOBILEwi: icon = 25; break;
case OBJECT_MOBILEii: icon = 28; break;
case OBJECT_MOBILEfs: icon = 14; break;
case OBJECT_MOBILEts: icon = 13; break;
case OBJECT_MOBILEws: icon = 12; break;
case OBJECT_MOBILEis: icon = 24; break;
case OBJECT_MOBILErt: icon = 18; break;
case OBJECT_MOBILErc: icon = 19; break;
case OBJECT_MOBILErr: icon = 20; break;
case OBJECT_MOBILErs: icon = 29; break;
case OBJECT_MOBILEsa: icon = 21; break;
case OBJECT_MOBILEft: icon = 6; break;
case OBJECT_MOBILEtt: icon = 5; break;
case OBJECT_MOBILEwt: icon = 30; break;
case OBJECT_MOBILEit: icon = 7; break;
case OBJECT_MOBILErp: icon = 9; break;
case OBJECT_MOBILEst: icon = 10; break;
case OBJECT_MOBILEtg: icon = 45; break;
case OBJECT_MOBILEdr: icon = 48; break;
case OBJECT_APOLLO2: icon = 49; break;
case OBJECT_MOTHER: icon = 31; break;
case OBJECT_ANT: icon = 31; break;
case OBJECT_SPIDER: icon = 31; break;
case OBJECT_BEE: icon = 31; break;
case OBJECT_WORM: icon = 31; break;
case OBJECT_TEEN28: icon = 48; break; // bottle
case OBJECT_TEEN34: icon = 48; break; // stone
default: icon = -1;
}
if ( icon == -1 ) return;
switch ( type )
{
case OBJECT_MOBILEfb:
case OBJECT_MOBILEtb:
case OBJECT_MOBILEwb:
case OBJECT_MOBILEib:
case OBJECT_MOBILEft:
case OBJECT_MOBILEtt:
case OBJECT_MOBILEit:
case OBJECT_MOBILErp:
case OBJECT_MOBILEst:
m_engine->SetTexture("textures/interface/button4.png"); break;
default: ; // button3.png
}
m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE);
uv1.x = (32.0f/256.0f)*(icon%8);
uv1.y = (32.0f/256.0f)*(icon/8);
uv2.x = uv1.x+32.0f/256.0f;
uv2.y = uv1.y+32.0f/256.0f;
uv1.x += dp;
uv1.y += dp;
uv2.x -= dp;
uv2.y -= dp;
DrawIcon(pos, dim, uv1, uv2); // icon
}
}
// Draw the object with the mouse hovers over.
void CMap::DrawHighlight(Math::Point pos)
{
Math::Point dim, uv1, uv2;
if (m_bToy || !m_fixImage.empty()) return; // map with still image?
pos.x = (pos.x-m_offset.x)*(m_zoom*0.5f)/m_half+0.5f;
pos.y = (pos.y-m_offset.y)*(m_zoom*0.5f)/m_half+0.5f;
pos.x = m_mapPos.x+m_mapDim.x*pos.x;
pos.y = m_mapPos.y+m_mapDim.y*pos.y;
dim.x = 2.0f/128.0f*0.75f;
dim.y = 2.0f/128.0f;
dim.x *= 2.0f+cosf(m_time*8.0f)*0.5f;
dim.y *= 2.0f+cosf(m_time*8.0f)*0.5f;
m_engine->SetTexture("textures/interface/button2.png");
m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
uv1.x = 160.5f/256.0f; // hilite
uv1.y = 224.5f/256.0f;
uv2.x = 175.0f/256.0f;
uv2.y = 239.0f/256.0f;
pos.x -= dim.x/2.0f;
pos.y -= dim.y/2.0f;
DrawIcon(pos, dim, uv1, uv2);
}
// Draws a triangular icon.
void CMap::DrawTriangle(Math::Point p1, Math::Point p2, Math::Point p3, Math::Point uv1, Math::Point uv2)
{
Gfx::CDevice* device;
Gfx::VertexTex2 vertex[3]; // 1 triangle
Math::Vector n;
device = m_engine->GetDevice();
n = Math::Vector(0.0f, 0.0f, -1.0f); // normal
vertex[0] = Gfx::VertexTex2(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(uv1.x,uv1.y));
vertex[1] = Gfx::VertexTex2(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(uv1.x,uv2.y));
vertex[2] = Gfx::VertexTex2(Math::Vector(p3.x, p3.y, 0.0f), n, Math::Point(uv2.x,uv2.y));
device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, vertex, 3);
m_engine->AddStatisticTriangle(1);
}
// Draw a pentagon icon (a 5 rating, what!).
void CMap::DrawPenta(Math::Point p1, Math::Point p2, Math::Point p3, Math::Point p4, Math::Point p5, Math::Point uv1, Math::Point uv2)
{
Gfx::CDevice* device;
Gfx::VertexTex2 vertex[5]; // 1 pentagon
Math::Vector n;
device = m_engine->GetDevice();
n = Math::Vector(0.0f, 0.0f, -1.0f); // normal
vertex[0] = Gfx::VertexTex2(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(uv1.x,uv1.y));
vertex[1] = Gfx::VertexTex2(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(uv1.x,uv2.y));
vertex[2] = Gfx::VertexTex2(Math::Vector(p5.x, p5.y, 0.0f), n, Math::Point(uv2.x,uv2.y));
vertex[3] = Gfx::VertexTex2(Math::Vector(p3.x, p3.y, 0.0f), n, Math::Point(uv2.x,uv2.y));
vertex[4] = Gfx::VertexTex2(Math::Vector(p4.x, p4.y, 0.0f), n, Math::Point(uv2.x,uv2.y));
device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, vertex, 5);
m_engine->AddStatisticTriangle(3);
}
// Draw the vertex array.
void CMap::DrawVertex(Math::Point uv1, Math::Point uv2, float zoom)
{
Gfx::CDevice* device;
Gfx::VertexTex2 vertex[4]; // 2 triangles
Math::Point p1, p2, c;
Math::Vector n;
device = m_engine->GetDevice();
p1.x = m_pos.x;
p1.y = m_pos.y;
p2.x = m_pos.x + m_dim.x;
p2.y = m_pos.y + m_dim.y;
c.x = (p1.x+p2.x)/2.0f;
c.y = (p1.y+p2.y)/2.0f; // center
p1.x = (p1.x-c.x)*zoom + c.x;
p1.y = (p1.y-c.y)*zoom + c.y;
p2.x = (p2.x-c.x)*zoom + c.x;
p2.y = (p2.y-c.y)*zoom + c.y;
m_mapPos = p1;
m_mapDim.x = p2.x-p1.x;
m_mapDim.y = p2.y-p1.y;
n = Math::Vector(0.0f, 0.0f, -1.0f); // normal
vertex[0] = Gfx::VertexTex2(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(uv1.x,uv2.y));
vertex[1] = Gfx::VertexTex2(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(uv1.x,uv1.y));
vertex[2] = Gfx::VertexTex2(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(uv2.x,uv2.y));
vertex[3] = Gfx::VertexTex2(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(uv2.x,uv1.y));
device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, vertex, 4);
m_engine->AddStatisticTriangle(2);
}
// Updates the field in the map.
void CMap::UpdateTerrain()
{
if (! m_fixImage.empty()) return; // still image?
CImage img(Math::IntPoint(256, 256));
float scale = m_terrain->GetReliefScale();
float water = m_water->GetLevel();
Gfx::Color color;
color.a = 0.0f;
for (int y = 0; y < 256; y++)
{
for (int x = 0; x < 256; x++)
{
Math::Vector pos;
pos.x = (static_cast<float>(x) - 128.0f) * m_half / 128.0f;
pos.z = -(static_cast<float>(y) - 128.0f) * m_half / 128.0f;
pos.y = 0.0f;
float level;
if ( pos.x >= -m_half && pos.x <= m_half &&
pos.z >= -m_half && pos.z <= m_half )
{
level = m_terrain->GetFloorLevel(pos, true) / scale;
}
else
{
level = 1000.0f;
}
float intensity = level / 256.0f;
if (intensity < 0.0f) intensity = 0.0f;
if (intensity > 1.0f) intensity = 1.0f;
if (level >= water) // on water?
{
color.r = Math::Norm(m_floorColor.r + (intensity - 0.5f));
color.g = Math::Norm(m_floorColor.g + (intensity - 0.5f));
color.b = Math::Norm(m_floorColor.b + (intensity - 0.5f));
}
else // underwater?
{
color.r = Math::Norm(m_waterColor.r + (intensity - 0.5f));
color.g = Math::Norm(m_waterColor.g + (intensity - 0.5f));
color.b = Math::Norm(m_waterColor.b + (intensity - 0.5f));
}
img.SetPixel(Math::IntPoint(x, y), color);
}
}
m_engine->DeleteTexture("interface/map.png");
m_engine->LoadTexture("textures/interface/map.png", &img);
}
// Updates the field in the map.
void CMap::UpdateTerrain(int bx, int by, int ex, int ey)
{
Gfx::Color color;
Math::Vector pos;
float scale, water, level, intensity;
int x, y;
if (! m_fixImage.empty()) return; // still image?
// TODO: map texture manipulation
return;
//if ( !m_engine->OpenImage("map.png") ) return;
//m_engine->LoadImage();
scale = m_terrain->GetReliefScale();
water = m_water->GetLevel();
color.a = 0.0f;
for ( y=by ; y<ey ; y++ )
{
for ( x=bx ; x<ex ; x++ )
{
pos.x = (static_cast<float>(x)-128.0f)*m_half/128.0f;
pos.z = -(static_cast<float>(y)-128.0f)*m_half/128.0f;
pos.y = 0.0f;
if ( pos.x >= -m_half && pos.x <= m_half &&
pos.z >= -m_half && pos.z <= m_half )
{
level = m_terrain->GetFloorLevel(pos, true)/scale;
}
else
{
level = 1000.0f;
}
intensity = level/256.0f;
if ( intensity < 0.0f ) intensity = 0.0f;
if ( intensity > 1.0f ) intensity = 1.0f;
if ( level > water ) // on water?
{
color.r = m_floorColor.r + (intensity-0.5f);
color.g = m_floorColor.g + (intensity-0.5f);
color.b = m_floorColor.b + (intensity-0.5f);
}
else // underwater?
{
color.r = m_waterColor.r + (intensity-0.5f);
color.g = m_waterColor.g + (intensity-0.5f);
color.b = m_waterColor.b + (intensity-0.5f);
}
//m_engine->SetDot(x, y, color);
}
}
//m_engine->CopyImage(); // copy the ground drawing
//m_engine->CloseImage();
}
// Empty all objects.
void CMap::FlushObject()
{
m_totalFix = 0; // object index fixed
m_totalMove = MAPMAXOBJECT-2; // moving vehicles index
m_bRadar = m_main->GetRadar();
for (int i = 0; i < MAPMAXOBJECT; i++)
{
m_map[i].bUsed = false;
}
}
// Updates an object in the map.
void CMap::UpdateObject(CObject* pObj)
{
ObjectType type;
MapColor color;
Math::Vector pos;
Math::Point ppos;
float dir;
if ( !m_bEnable ) return;
if ( m_totalFix >= m_totalMove ) return; // full table?
type = pObj->GetType();
if ( !pObj->GetDetectable() ) return;
if ( type != OBJECT_MOTHER &&
type != OBJECT_ANT &&
type != OBJECT_SPIDER &&
type != OBJECT_BEE &&
type != OBJECT_WORM &&
type != OBJECT_MOBILEtg )
{
if (pObj->Implements(ObjectInterfaceType::Controllable) && !dynamic_cast<CControllableObject&>(*pObj).GetSelectable()) return;
}
if ( pObj->GetProxyActivate() ) return;
if (IsObjectBeingTransported(pObj)) return;
pos = pObj->GetPosition();
dir = -(pObj->GetRotationY()+Math::PI/2.0f);
if ( m_angle != 0.0f )
{
ppos = RotatePoint(m_angle, Math::Point(pos.x, pos.z));
pos.x = ppos.x;
pos.z = ppos.y;
dir += m_angle;
}
color = MAPCOLOR_NULL;
if ( type == OBJECT_BASE )
{
color = MAPCOLOR_BASE;
}
if ( type == OBJECT_DERRICK ||
type == OBJECT_FACTORY ||
type == OBJECT_STATION ||
type == OBJECT_CONVERT ||
type == OBJECT_REPAIR ||
type == OBJECT_DESTROYER||
type == OBJECT_TOWER ||
type == OBJECT_RESEARCH ||
type == OBJECT_RADAR ||
type == OBJECT_INFO ||
type == OBJECT_ENERGY ||
type == OBJECT_LABO ||
type == OBJECT_NUCLEAR ||
type == OBJECT_PARA ||
type == OBJECT_SAFE ||
type == OBJECT_HUSTON ||
type == OBJECT_TARGET1 ||
type == OBJECT_START ||
type == OBJECT_END || // stationary object?
type == OBJECT_TEEN28 || // bottle?
type == OBJECT_TEEN34 ) // stone?
{
color = MAPCOLOR_FIX;
}
if ( type == OBJECT_BBOX ||
type == OBJECT_KEYa ||
type == OBJECT_KEYb ||
type == OBJECT_KEYc ||
type == OBJECT_KEYd )
{
color = MAPCOLOR_BBOX;
}
if ( type == OBJECT_HUMAN ||
type == OBJECT_MOBILEwa ||
type == OBJECT_MOBILEta ||
type == OBJECT_MOBILEfa ||
type == OBJECT_MOBILEia ||
type == OBJECT_MOBILEwb ||
type == OBJECT_MOBILEtb ||
type == OBJECT_MOBILEfb ||
type == OBJECT_MOBILEib ||
type == OBJECT_MOBILEwc ||
type == OBJECT_MOBILEtc ||
type == OBJECT_MOBILEfc ||
type == OBJECT_MOBILEic ||
type == OBJECT_MOBILEwi ||
type == OBJECT_MOBILEti ||
type == OBJECT_MOBILEfi ||
type == OBJECT_MOBILEii ||
type == OBJECT_MOBILEws ||
type == OBJECT_MOBILEts ||
type == OBJECT_MOBILEfs ||
type == OBJECT_MOBILEis ||
type == OBJECT_MOBILErt ||
type == OBJECT_MOBILErc ||
type == OBJECT_MOBILErr ||
type == OBJECT_MOBILErs ||
type == OBJECT_MOBILEsa ||
type == OBJECT_MOBILEtg ||
type == OBJECT_MOBILEwt ||
type == OBJECT_MOBILEtt ||
type == OBJECT_MOBILEft ||
type == OBJECT_MOBILEit ||
type == OBJECT_MOBILErp ||
type == OBJECT_MOBILEst ||
type == OBJECT_MOBILEdr ||
type == OBJECT_APOLLO2 ) // moving vehicle?
{
color = MAPCOLOR_MOVE;
}
if ( type == OBJECT_ANT ||
type == OBJECT_BEE ||
type == OBJECT_WORM ||
type == OBJECT_SPIDER ) // mobile enemy?
{
color = MAPCOLOR_ALIEN;
}
if ( type == OBJECT_WAYPOINT ||
type == OBJECT_FLAGb )
{
color = MAPCOLOR_WAYPOINTb;
}
if ( type == OBJECT_FLAGr )
{
color = MAPCOLOR_WAYPOINTr;
}
if ( type == OBJECT_FLAGg )
{
color = MAPCOLOR_WAYPOINTg;
}
if ( type == OBJECT_FLAGy )
{
color = MAPCOLOR_WAYPOINTy;
}
if ( type == OBJECT_FLAGv )
{
color = MAPCOLOR_WAYPOINTv;
}
if ( color == MAPCOLOR_NULL ) return;
/*if (!m_fixImage.empty() && !m_bDebug) // map with still image?
{
if ( (type == OBJECT_TEEN28 ||
type == OBJECT_TEEN34 ) &&
m_mode == 0 ) return;
if ( type != OBJECT_TEEN28 &&
type != OBJECT_TEEN34 &&
color != MAPCOLOR_MOVE ) return;
}*/
if ( pObj->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject&>(*pObj).GetSelect() )
{
m_map[MAPMAXOBJECT-1].type = type;
m_map[MAPMAXOBJECT-1].object = pObj;
m_map[MAPMAXOBJECT-1].color = color;
m_map[MAPMAXOBJECT-1].pos.x = pos.x;
m_map[MAPMAXOBJECT-1].pos.y = pos.z;
m_map[MAPMAXOBJECT-1].dir = dir;
m_map[MAPMAXOBJECT-1].bUsed = true;
}
else
{
if ( color == MAPCOLOR_BASE ||
color == MAPCOLOR_FIX )
{
m_map[m_totalFix].type = type;
m_map[m_totalFix].object = pObj;
m_map[m_totalFix].color = color;
m_map[m_totalFix].pos.x = pos.x;
m_map[m_totalFix].pos.y = pos.z;
m_map[m_totalFix].dir = dir;
m_map[m_totalFix].bUsed = true;
m_totalFix ++;
}
else
{
m_map[m_totalMove].type = type;
m_map[m_totalMove].object = pObj;
m_map[m_totalMove].color = color;
m_map[m_totalMove].pos.x = pos.x;
m_map[m_totalMove].pos.y = pos.z;
m_map[m_totalMove].dir = dir;
m_map[m_totalMove].bUsed = true;
m_totalMove --;
}
}
}
}