1 /*
2  * This file is part of the Colobot: Gold Edition source code
3  * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
4  * http://epsitec.ch; http://colobot.info; http://github.com/colobot
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see http://gnu.org/licenses
18  */
19 
20 
21 #include "ui/controls/map.h"
22 
23 #include "common/image.h"
24 
25 #include "graphics/core/device.h"
26 
27 #include "graphics/engine/terrain.h"
28 #include "graphics/engine/water.h"
29 
30 #include "level/robotmain.h"
31 
32 #include "math/geometry.h"
33 
34 #include "object/interface/controllable_object.h"
35 #include "object/interface/transportable_object.h"
36 
37 #include <cstring>
38 
39 
40 namespace Ui
41 {
42 
43 // Object's constructor.
44 
CMap()45 CMap::CMap() : CControl()
46 {
47     m_main    = CRobotMain::GetInstancePointer();
48     m_terrain = m_main->GetTerrain();
49     m_water   = Gfx::CEngine::GetInstancePointer()->GetWater();
50 
51     m_bEnable  = true;
52     m_time     = 0.0f;
53     m_zoom     = 2.0f;
54     m_offset.x = 0.0f;
55     m_offset.y = 0.0f;
56     m_angle    = 0.0f;
57 
58     m_floorColor.r = 1.00f;
59     m_floorColor.g = 0.50f;
60     m_floorColor.b = 0.00f;  // orange
61 
62     m_waterColor.r = 0.00f;
63     m_waterColor.g = 0.80f;
64     m_waterColor.b = 1.00f;  // blue
65 
66     m_half = m_terrain->GetMosaicCount() * m_terrain->GetBrickCount() * m_terrain->GetBrickSize() / 2.0f;
67 
68     m_highlightRank = -1;
69     m_totalFix  = 0;
70     m_totalMove = 0;
71     m_bRadar = false;
72 
73     FlushObject();
74 
75     m_mode = 0;
76     m_bToy = false;
77     m_bDebug = false;
78 }
79 
80 // Object's destructor.
81 
~CMap()82 CMap::~CMap()
83 {
84 }
85 
86 
87 // Creates a new button.
88 
Create(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)89 bool CMap::Create(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
90 {
91     if (eventMsg == EVENT_NULL)
92         eventMsg = GetUniqueEventType();
93 
94     CControl::Create(pos, dim, icon, eventMsg);
95     return true;
96 }
97 
98 
99 // Choice of the offset, when image is displayed.
100 
SetOffset(float ox,float oy)101 void CMap::SetOffset(float ox, float oy)
102 {
103     m_offset.x = ox;
104     m_offset.y = oy;
105     m_half = m_terrain->GetMosaicCount() * m_terrain->GetBrickCount() * m_terrain->GetBrickSize() / 2.0f;
106 }
107 
108 // Choice of the global angle of rotation.
109 
SetAngle(float angle)110 void CMap::SetAngle(float angle)
111 {
112     m_angle = angle;
113 }
114 
115 // Specifies the alternate mode.
116 
SetMode(int mode)117 void CMap::SetMode(int mode)
118 {
119     m_mode = mode;
120 }
121 
122 // Specifies the type of icon for the selected object.
123 
SetToy(bool bToy)124 void CMap::SetToy(bool bToy)
125 {
126     m_bToy = bToy;
127 }
128 
SetDebug(bool bDebug)129 void CMap::SetDebug(bool bDebug)
130 {
131     m_bDebug = bDebug;
132 }
133 
134 
135 //Choice of magnification of the map.
136 
SetZoom(float value)137 void CMap::SetZoom(float value)
138 {
139     m_zoom = value;
140     m_half = m_terrain->GetMosaicCount() * m_terrain->GetBrickCount() * m_terrain->GetBrickSize() / 2.0f;
141 }
142 
GetZoom()143 float CMap::GetZoom()
144 {
145     return m_zoom;
146 }
147 
148 // Choosing a fixed offset.
149 
150 // Enables or disables the card.
151 
SetEnable(bool bEnable)152 void CMap::SetEnable(bool bEnable)
153 {
154     m_bEnable = bEnable;
155     SetState(STATE_DEAD, !bEnable);
156 }
157 
GetEnable()158 bool CMap::GetEnable()
159 {
160     return m_bEnable;
161 }
162 
163 
164 // Choosing the color of the soil.
165 
SetFloorColor(Gfx::Color color)166 void CMap::SetFloorColor(Gfx::Color color)
167 {
168     m_floorColor = color;
169 }
170 
171 // Choosing the color of the water.
172 
SetWaterColor(Gfx::Color color)173 void CMap::SetWaterColor(Gfx::Color color)
174 {
175     m_waterColor = color;
176 }
177 
178 
179 // Specifies a fixed image in place of the drawing of the relief.
180 
SetFixImage(const std::string & filename)181 void CMap::SetFixImage(const std::string& filename)
182 {
183     m_fixImage = filename;
184 }
185 
186 // Whether to use a still image.
187 
GetFixImage()188 bool CMap::GetFixImage()
189 {
190     return ! m_fixImage.empty();
191 }
192 
193 
194 // Management of an event.
195 
EventProcess(const Event & event)196 bool CMap::EventProcess(const Event &event)
197 {
198     if ( (m_state & STATE_VISIBLE) == 0 )
199         return true;
200 
201     CControl::EventProcess(event);
202 
203     if ( event.type == EVENT_FRAME )
204         m_time += event.rTime;
205 
206     if ( event.type == EVENT_MOUSE_MOVE || event.type == EVENT_MOUSE_BUTTON_DOWN || event.type == EVENT_MOUSE_BUTTON_UP )
207     {
208         if (Detect(event.mousePos))
209         {
210             m_engine->SetMouseType(Gfx::ENG_MOUSE_NORM);
211             bool inMap = false;
212             if (DetectObject(event.mousePos, inMap) != nullptr)
213                 m_engine->SetMouseType(Gfx::ENG_MOUSE_HAND);
214         }
215     }
216 
217     if (event.type == EVENT_MOUSE_BUTTON_DOWN &&
218         event.GetData<MouseButtonEventData>()->button == MOUSE_BUTTON_LEFT)
219     {
220         if ( CControl::Detect(event.mousePos) )
221         {
222             SelectObject(event.mousePos);
223             return false;
224         }
225     }
226 
227     return true;
228 }
229 
230 // Adjusts the offset to not exceed the card.
231 
AdjustOffset(Math::Point offset)232 Math::Point CMap::AdjustOffset(Math::Point offset)
233 {
234     float   limit;
235 
236     limit = m_half - m_half / m_zoom;
237     if ( offset.x < -limit )  offset.x = -limit;
238     if ( offset.x >  limit )  offset.x =  limit;
239     if ( offset.y < -limit )  offset.y = -limit;
240     if ( offset.y >  limit )  offset.y =  limit;
241 
242     return offset;
243 }
244 
245 // Indicates the object with the mouse hovers over.
246 
SetHighlight(CObject * pObj)247 void CMap::SetHighlight(CObject* pObj)
248 {
249     m_highlightRank = -1;
250     if ( m_bToy || !m_fixImage.empty())
251         return;  // card with still image?
252     if ( pObj == nullptr )
253         return;
254 
255     for (int i = 0; i < MAPMAXOBJECT; i++)
256     {
257         if ( !m_map[i].bUsed )
258             continue;
259 
260         if ( m_map[i].object == pObj )
261         {
262             m_highlightRank = i;
263             break;
264         }
265     }
266 }
267 
268 // Detects an object in the map.
269 
DetectObject(Math::Point pos,bool & bInMap)270 CObject* CMap::DetectObject(Math::Point pos, bool &bInMap)
271 {
272     float dist, min;
273     int best;
274 
275     bInMap = false;
276     if ( pos.x < m_pos.x ||
277          pos.y < m_pos.y ||
278          pos.x > m_pos.x + m_dim.x ||
279          pos.y > m_pos.y + m_dim.y )
280         return nullptr;
281 
282     bInMap = true;
283 
284     pos.x = (pos.x - m_pos.x) / m_dim.x * 256.0f;
285     pos.y = (pos.y - m_pos.y) / m_dim.y * 256.0f;  // 0..256
286     pos.x = (pos.x - 128.0f) * m_half / (m_zoom * 128.0f) + m_offset.x;
287     pos.y = (pos.y - 128.0f) * m_half / (m_zoom * 128.0f) + m_offset.y;
288 
289     min = 10000.0f;
290     best = -1;
291     for (int i = MAPMAXOBJECT - 1; i >= 0; i--)
292     {
293         if ( !m_map[i].bUsed )
294             continue;
295         if ( m_map[i].color == MAPCOLOR_BBOX  && !m_bRadar )
296             continue;
297         if ( m_map[i].color == MAPCOLOR_ALIEN && !m_bRadar )
298             continue;
299 
300         dist = Math::Point(m_map[i].pos.x - pos.x, m_map[i].pos.y - pos.y).Length();
301         if ( dist > m_half / m_zoom * 8.0f / 100.0f )
302             continue;  // too far?
303         if ( dist < min )
304         {
305             min = dist;
306             best = i;
307         }
308     }
309     if ( best == -1 )
310         return nullptr;
311     return m_map[best].object;
312 }
313 
314 // Selects an object.
315 
SelectObject(Math::Point pos)316 void CMap::SelectObject(Math::Point pos)
317 {
318     CObject *pObj;
319     bool bInMap;
320 
321     pObj = DetectObject(pos, bInMap);
322     if ( pObj != nullptr )
323         m_main->SelectObject(pObj);
324 }
325 
326 
327 // Draw the map.
328 
Draw()329 void CMap::Draw()
330 {
331     Math::Point     uv1, uv2;
332     int i;
333 
334     if ( (m_state & STATE_VISIBLE) == 0 )
335         return;
336 
337     CControl::Draw();  // draws the bottom (button)
338 
339     if ( !m_bEnable )
340         return;
341 
342     if (m_fixImage.empty() && m_map[MAPMAXOBJECT - 1].bUsed)
343         m_offset = AdjustOffset(m_map[MAPMAXOBJECT - 1].pos);
344 
345     if (m_fixImage.empty()) // drawing of the relief?
346     {
347         m_engine->SetTexture("textures/interface/map.png");
348         m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
349         uv1.x = 0.5f + (m_offset.x - (m_half / m_zoom)) / (m_half * 2.0f);
350         uv1.y = 0.5f - (m_offset.y + (m_half / m_zoom)) / (m_half * 2.0f);
351         uv2.x = 0.5f + (m_offset.x + (m_half / m_zoom)) / (m_half * 2.0f);
352         uv2.y = 0.5f - (m_offset.y - (m_half / m_zoom)) / (m_half * 2.0f);
353         DrawVertex(uv1, uv2, 0.97f);  // drawing the map
354     }
355     else // still image?
356     {
357         m_engine->LoadTexture(m_fixImage);
358         m_engine->SetTexture(m_fixImage);
359         m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
360         uv1.x = 0.0f;
361         uv1.y = 0.0f;
362         uv2.x = 1.0f;
363         uv2.y = 1.0f;
364         DrawVertex(uv1, uv2, 0.97f);  // drawing the map
365     }
366 
367     i = MAPMAXOBJECT-1;
368     if ( m_map[i].bUsed )  // selection:
369         DrawFocus(m_map[i].pos, m_map[i].dir, m_map[i].type, m_map[i].color);
370 
371     for ( i=0 ; i<m_totalFix ; i++ ) // fixed objects:
372     {
373         if ( i == m_highlightRank )
374             continue;
375         DrawObject(m_map[i].pos, m_map[i].dir, m_map[i].type, m_map[i].color, false, false);
376     }
377 
378     for ( i=MAPMAXOBJECT-2 ; i>m_totalMove ; i-- ) // moving objects:
379     {
380         if ( i == m_highlightRank )
381             continue;
382         DrawObject(m_map[i].pos, m_map[i].dir, m_map[i].type, m_map[i].color, false, false);
383     }
384 
385     i = MAPMAXOBJECT-1;
386     if ( m_map[i].bUsed && i != m_highlightRank )  // selection:
387         DrawObject(m_map[i].pos, m_map[i].dir, m_map[i].type, m_map[i].color, true, false);
388 
389     if ( m_highlightRank != -1 && m_map[m_highlightRank].bUsed )
390     {
391         i = m_highlightRank;
392         DrawObject(m_map[i].pos, m_map[i].dir, m_map[i].type, m_map[i].color, false, true);
393         DrawHighlight(m_map[i].pos);
394     }
395 }
396 
397 // Computing a point for drawFocus.
398 
MapInter(Math::Point pos,float dir)399 Math::Point CMap::MapInter(Math::Point pos, float dir)
400 {
401     Math::Point p1;
402     float   limit;
403 
404     p1.x = pos.x + 1.0f;
405     p1.y = pos.y;
406     p1 = Math::RotatePoint(pos, dir, p1);
407 
408     p1.x -= pos.x;
409     p1.y -= pos.y;
410 
411     limit = m_mapPos.x + m_mapDim.x - pos.x;
412     if ( p1.x > limit ) // exceeds the right?
413     {
414         p1.y = limit*p1.y/p1.x;
415         p1.x = limit;
416     }
417     limit = m_mapPos.y * 0.75f + m_mapDim.y * 0.75f - pos.y;
418     if ( p1.y > limit ) // exceeds the top?
419     {
420         p1.x = limit * p1.x / p1.y;
421         p1.y = limit;
422     }
423     limit = m_mapPos.x - pos.x;
424     if ( p1.x < limit ) // exceeds the left?
425     {
426         p1.y = limit * p1.y / p1.x;
427         p1.x = limit;
428     }
429 
430     limit = m_mapPos.y * 0.75f - pos.y;
431     if ( p1.y < limit ) // exceeds the bottom?
432     {
433         p1.x = limit * p1.x / p1.y;
434         p1.y = limit;
435     }
436 
437     p1.x += pos.x;
438     p1.y += pos.y;
439     return p1;
440 }
441 
442 // Draw the field of vision of the selected object.
443 
DrawFocus(Math::Point pos,float dir,ObjectType type,MapColor color)444 void CMap::DrawFocus(Math::Point pos, float dir, ObjectType type, MapColor color)
445 {
446     Math::Point p0, p1, p2, uv1, uv2, rel;
447     float   aMin, aMax, aOct, focus, a;
448     float   limit[5];
449     bool    bEnding;
450     int     quart;
451 
452     if (m_bToy || !m_fixImage.empty())  return;  // map with still image?
453     if ( color != MAPCOLOR_MOVE )  return;
454 
455     pos.x = (pos.x-m_offset.x)*(m_zoom*0.5f)/m_half+0.5f;
456     pos.y = (pos.y-m_offset.y)*(m_zoom*0.5f)/m_half+0.5f;
457 
458     if ( pos.x < 0.0f || pos.x > 1.0f ||
459          pos.y < 0.0f || pos.y > 1.0f )  return;
460 
461     rel.x = pos.x*2.0f-1.0f;
462     rel.y = pos.y*2.0f-1.0f;  // rel [-1..1]
463 
464     pos.x = m_mapPos.x+m_mapDim.x*pos.x;
465     pos.y = m_mapPos.y*0.75f+m_mapDim.y*pos.y*0.75f;
466 
467     focus = m_engine->GetFocus();
468     dir += Math::PI/2.0f;
469     aMin = Math::NormAngle(dir-Math::PI/4.0f*focus);
470     aMax = Math::NormAngle(dir+Math::PI/4.0f*focus);
471 
472     if ( aMin > aMax )
473     {
474         aMax += Math::PI*2.0f;  // aMax always after aMin
475     }
476 
477     limit[0] = Math::RotateAngle( 1.0f-rel.x,  1.0f-rel.y);  // upper/right
478     limit[1] = Math::RotateAngle(-1.0f-rel.x,  1.0f-rel.y);  // upper/left
479     limit[2] = Math::RotateAngle(-1.0f-rel.x, -1.0f-rel.y);  // lower/left
480     limit[3] = Math::RotateAngle( 1.0f-rel.x, -1.0f-rel.y);  // lower/right
481     limit[4] = limit[0]+Math::PI*2.0f;
482 
483     a = Math::NormAngle(aMin);
484     for ( quart=0 ; quart<4 ; quart++ )
485     {
486         if ( a >= limit[quart+0] &&
487              a <= limit[quart+1] )  break;
488     }
489     if ( quart == 4 )  quart = -1;
490 
491     uv1.x = 113.0f/256.0f;  // degrade green
492     uv1.y = 240.5f/256.0f;
493     uv2.x = 126.0f/256.0f;
494     uv2.y = 255.0f/256.0f;
495 
496     m_engine->SetTexture("textures/interface/button2.png");
497     m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE);
498 
499     bEnding = false;
500     do
501     {
502         quart ++;
503         aOct = limit[quart%4];
504         if ( quart >= 4 )  aOct += Math::PI*2.0f;
505         if ( aOct >= aMax - Math::VERY_SMALL_NUM )
506         {
507             aOct = aMax;
508             bEnding = true;
509         }
510 
511         p0 = pos;
512         p1 = MapInter(pos, aMin);
513         p2 = MapInter(pos, aOct);
514         p0.y /= 0.75f;
515         p1.y /= 0.75f;
516         p2.y /= 0.75f;
517         DrawTriangle(p0, p2, p1, uv1, uv2);
518 
519         aMin = aOct;
520     }
521     while ( !bEnding );
522 }
523 
524 // Draw an object.
525 
DrawObject(Math::Point pos,float dir,ObjectType type,MapColor color,bool bSelect,bool bHilite)526 void CMap::DrawObject(Math::Point pos, float dir, ObjectType type, MapColor color,
527                       bool bSelect, bool bHilite)
528 {
529     Math::Point     p1, p2, p3, p4, p5, dim, uv1, uv2;
530     bool        bOut, bUp, bDown, bLeft, bRight;
531 
532     pos.x = (pos.x-m_offset.x)*(m_zoom*0.5f)/m_half+0.5f;
533     pos.y = (pos.y-m_offset.y)*(m_zoom*0.5f)/m_half+0.5f;
534 
535     bOut = bUp = bDown = bLeft = bRight = false;
536     if ( pos.x < 0.06f )  { pos.x = 0.02f;  bOut = bLeft  = true; }
537     if ( pos.y < 0.06f )  { pos.y = 0.02f;  bOut = bDown  = true; }
538     if ( pos.x > 0.94f )  { pos.x = 0.98f;  bOut = bRight = true; }
539     if ( pos.y > 0.94f )  { pos.y = 0.98f;  bOut = bUp    = true; }
540 
541     pos.x = m_mapPos.x+m_mapDim.x*pos.x;
542     pos.y = m_mapPos.y+m_mapDim.y*pos.y;
543     dim.x = 2.0f/128.0f*0.75f;
544     dim.y = 2.0f/128.0f;
545 
546     if ( bOut )  // outside the map?
547     {
548         if ( color == MAPCOLOR_BBOX  && !m_bRadar )  return;
549         if ( color == MAPCOLOR_ALIEN && !m_bRadar )  return;
550 
551         if ( Math::Mod(m_time+(pos.x+pos.y)*4.0f, 0.6f) > 0.2f )
552         {
553             return;  // flashes
554         }
555 
556         m_engine->SetTexture("textures/interface/button2.png");
557         m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
558         if ( bUp )
559         {
560             uv1.x = 160.5f/256.0f;  // yellow triangle ^
561             uv1.y = 240.5f/256.0f;
562             uv2.x = 175.0f/256.0f;
563             uv2.y = 255.0f/256.0f;
564         }
565         if ( bDown )
566         {
567             uv1.x = 160.5f/256.0f;  // yellow triangle v
568             uv1.y = 255.0f/256.0f;
569             uv2.x = 175.0f/256.0f;
570             uv2.y = 240.5f/256.0f;
571         }
572         if ( bRight )
573         {
574             uv1.x = 176.5f/256.0f;  // yellow triangle >
575             uv1.y = 240.5f/256.0f;
576             uv2.x = 191.0f/256.0f;
577             uv2.y = 255.0f/256.0f;
578         }
579         if ( bLeft )
580         {
581             uv1.x = 191.0f/256.0f;  // yellow triangle <
582             uv1.y = 240.5f/256.0f;
583             uv2.x = 176.5f/256.0f;
584             uv2.y = 255.0f/256.0f;
585         }
586         pos.x -= dim.x/2.0f;
587         pos.y -= dim.y/2.0f;
588         DrawIcon(pos, dim, uv1, uv2);
589         return;
590     }
591 
592     if ( bSelect )
593     {
594         if ( m_bToy )
595         {
596             dim.x *= 1.2f+sinf(m_time*8.0f)*0.1f;
597             dim.y *= 1.2f+sinf(m_time*8.0f)*0.1f;
598         }
599         else
600         {
601             dim.x *= 1.2f+sinf(m_time*8.0f)*0.3f;
602             dim.y *= 1.2f+sinf(m_time*8.0f)*0.3f;
603         }
604     }
605     if ( color == MAPCOLOR_BASE ||
606          color == MAPCOLOR_FIX  ||
607          color == MAPCOLOR_MOVE )
608     {
609         if ( bHilite )
610         {
611             dim.x *= 2.2f;
612             dim.y *= 2.2f;
613         }
614         else
615         {
616             dim.x *= 0.6f;
617             dim.y *= 0.6f;
618         }
619     }
620     if ( color == MAPCOLOR_ALIEN )
621     {
622         dim.x *= 1.4f;
623         dim.y *= 1.4f;
624     }
625     if ( type == OBJECT_TEEN28 )  // bottle?
626     {
627         dim.x *= 3.0f;
628         dim.y *= 3.0f;
629         bHilite = true;
630     }
631     if ( type == OBJECT_TEEN34 )  // stone?
632     {
633         dim.x *= 2.0f;
634         dim.y *= 2.0f;
635         bHilite = true;
636     }
637 
638     if ( color == MAPCOLOR_MOVE && bSelect )
639     {
640         if ( m_bToy )
641         {
642             p1.x = pos.x;
643             p1.y = pos.y+dim.y*1.4f;
644             p1 = Math::RotatePoint(pos, dir, p1);
645             p1.x = pos.x+(p1.x-pos.x)*0.75f;
646 
647             p2.x = pos.x+dim.x*1.2f;
648             p2.y = pos.y+dim.y*0.8f;
649             p2 = Math::RotatePoint(pos, dir, p2);
650             p2.x = pos.x+(p2.x-pos.x)*0.75f;
651 
652             p3.x = pos.x+dim.x*1.2f;
653             p3.y = pos.y-dim.y*1.0f;
654             p3 = Math::RotatePoint(pos, dir, p3);
655             p3.x = pos.x+(p3.x-pos.x)*0.75f;
656 
657             p4.x = pos.x-dim.x*1.2f;
658             p4.y = pos.y-dim.y*1.0f;
659             p4 = Math::RotatePoint(pos, dir, p4);
660             p4.x = pos.x+(p4.x-pos.x)*0.75f;
661 
662             p5.x = pos.x-dim.x*1.2f;
663             p5.y = pos.y+dim.y*0.8f;
664             p5 = Math::RotatePoint(pos, dir, p5);
665             p5.x = pos.x+(p5.x-pos.x)*0.75f;
666         }
667         else
668         {
669             p1.x = pos.x;
670             p1.y = pos.y+dim.y*2.4f;
671             p1 = Math::RotatePoint(pos, dir, p1);
672             p1.x = pos.x+(p1.x-pos.x)*0.75f;
673 
674             p2.x = pos.x+dim.x*1.0f;
675             p2.y = pos.y-dim.y*1.6f;
676             p2 = Math::RotatePoint(pos, dir, p2);
677             p2.x = pos.x+(p2.x-pos.x)*0.75f;
678 
679             p3.x = pos.x-dim.x*1.0f;
680             p3.y = pos.y-dim.y*1.6f;
681             p3 = Math::RotatePoint(pos, dir, p3);
682             p3.x = pos.x+(p3.x-pos.x)*0.75f;
683         }
684     }
685 
686     pos.x -= dim.x/2.0f;
687     pos.y -= dim.y/2.0f;
688 
689     if ( color == MAPCOLOR_BASE ||
690          color == MAPCOLOR_FIX  )
691     {
692         DrawObjectIcon(pos, dim, color, type, bHilite);
693     }
694 
695     if ( color == MAPCOLOR_MOVE )
696     {
697         if ( bSelect )
698         {
699             m_engine->SetTexture("textures/interface/button2.png");
700             m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
701             if ( m_bToy )
702             {
703                 uv1.x = 164.5f/256.0f;  // black pentagon
704                 uv1.y = 228.5f/256.0f;
705                 uv2.x = 172.0f/256.0f;
706                 uv2.y = 236.0f/256.0f;
707                 DrawPenta(p1, p2, p3, p4, p5, uv1, uv2);
708             }
709             else
710             {
711                 uv1.x = 144.5f/256.0f;  // red triangle
712                 uv1.y = 240.5f/256.0f;
713                 uv2.x = 159.0f/256.0f;
714                 uv2.y = 255.0f/256.0f;
715                 DrawTriangle(p1, p2, p3, uv1, uv2);
716             }
717         }
718         DrawObjectIcon(pos, dim, color, type, bHilite);
719     }
720 
721     if ( color == MAPCOLOR_BBOX )
722     {
723         if ( m_bRadar )
724         {
725             m_engine->SetTexture("textures/interface/button2.png");
726             m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE);
727             uv1.x =  64.5f/256.0f;  // blue triangle
728             uv1.y = 240.5f/256.0f;
729             uv2.x =  79.0f/256.0f;
730             uv2.y = 255.0f/256.0f;
731             DrawIcon(pos, dim, uv1, uv2);
732         }
733     }
734 
735     if ( color == MAPCOLOR_ALIEN )
736     {
737         if ( m_bRadar )
738         {
739             DrawObjectIcon(pos, dim, color, type, true);
740         }
741     }
742 
743     if ( color == MAPCOLOR_WAYPOINTb )
744     {
745         m_engine->SetTexture("textures/interface/button2.png");
746         m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
747         uv1.x = 192.5f/256.0f;  // blue cross
748         uv1.y = 240.5f/256.0f;
749         uv2.x = 207.0f/256.0f;
750         uv2.y = 255.0f/256.0f;
751         DrawIcon(pos, dim, uv1, uv2);
752     }
753     if ( color == MAPCOLOR_WAYPOINTr )
754     {
755         m_engine->SetTexture("textures/interface/button2.png");
756         m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
757         uv1.x = 208.5f/256.0f;  // red cross
758         uv1.y = 240.5f/256.0f;
759         uv2.x = 223.0f/256.0f;
760         uv2.y = 255.0f/256.0f;
761         DrawIcon(pos, dim, uv1, uv2);
762     }
763     if ( color == MAPCOLOR_WAYPOINTg )
764     {
765         m_engine->SetTexture("textures/interface/button2.png");
766         m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
767         uv1.x = 224.5f/256.0f;  // green cross
768         uv1.y = 240.5f/256.0f;
769         uv2.x = 239.0f/256.0f;
770         uv2.y = 255.0f/256.0f;
771         DrawIcon(pos, dim, uv1, uv2);
772     }
773     if ( color == MAPCOLOR_WAYPOINTy )
774     {
775         m_engine->SetTexture("textures/interface/button2.png");
776         m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
777         uv1.x = 240.5f/256.0f;  // yellow cross
778         uv1.y = 240.5f/256.0f;
779         uv2.x = 255.0f/256.0f;
780         uv2.y = 255.0f/256.0f;
781         DrawIcon(pos, dim, uv1, uv2);
782     }
783     if ( color == MAPCOLOR_WAYPOINTv )
784     {
785         m_engine->SetTexture("textures/interface/button2.png");
786         m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
787         uv1.x = 192.5f/256.0f;  // violet cross
788         uv1.y = 224.5f/256.0f;
789         uv2.x = 207.0f/256.0f;
790         uv2.y = 239.0f/256.0f;
791         DrawIcon(pos, dim, uv1, uv2);
792     }
793 }
794 
795 // Draws the icon of an object.
796 
DrawObjectIcon(Math::Point pos,Math::Point dim,MapColor color,ObjectType type,bool bHilite)797 void CMap::DrawObjectIcon(Math::Point pos, Math::Point dim, MapColor color,
798                           ObjectType type, bool bHilite)
799 {
800     Math::Point ppos, ddim, uv1, uv2;
801     float   dp;
802     int     icon;
803 
804     dp = 0.5f/256.0f;
805 
806     m_engine->SetTexture("textures/interface/button3.png");
807     m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
808     if ( color == MAPCOLOR_MOVE )
809     {
810         uv1.x = 160.0f/256.0f;  // blue
811         uv1.y = 224.0f/256.0f;
812     }
813     else if ( color == MAPCOLOR_ALIEN )
814     {
815         uv1.x = 224.0f/256.0f;  // green
816         uv1.y = 224.0f/256.0f;
817     }
818     else
819     {
820         uv1.x = 192.0f/256.0f;  // yellow
821         uv1.y = 224.0f/256.0f;
822     }
823     uv2.x = uv1.x+32.0f/256.0f;
824     uv2.y = uv1.y+32.0f/256.0f;
825     uv1.x += dp;
826     uv1.y += dp;
827     uv2.x -= dp;
828     uv2.y -= dp;
829     DrawIcon(pos, dim, uv1, uv2);  // background colors
830 
831     if ( bHilite )
832     {
833         switch ( type )
834         {
835             case OBJECT_FACTORY:    icon = 32; break;
836             case OBJECT_DERRICK:    icon = 33; break;
837             case OBJECT_CONVERT:    icon = 34; break;
838             case OBJECT_RESEARCH:   icon = 35; break;
839             case OBJECT_STATION:    icon = 36; break;
840             case OBJECT_TOWER:      icon = 37; break;
841             case OBJECT_LABO:       icon = 38; break;
842             case OBJECT_ENERGY:     icon = 39; break;
843             case OBJECT_RADAR:      icon = 40; break;
844             case OBJECT_INFO:       icon = 44; break;
845             case OBJECT_REPAIR:     icon = 41; break;
846             case OBJECT_DESTROYER:  icon = 41; break;
847             case OBJECT_NUCLEAR:    icon = 42; break;
848             case OBJECT_PARA:       icon = 46; break;
849             case OBJECT_SAFE:       icon = 47; break;
850             case OBJECT_HUSTON:     icon = 48; break;
851             case OBJECT_TARGET1:    icon = 45; break;
852             case OBJECT_BASE:       icon = 43; break;
853             case OBJECT_HUMAN:      icon = 8; break;
854             case OBJECT_MOBILEfa:   icon = 11; break;
855             case OBJECT_MOBILEta:   icon = 10; break;
856             case OBJECT_MOBILEwa:   icon = 9; break;
857             case OBJECT_MOBILEia:   icon = 22; break;
858             case OBJECT_MOBILEfb:   icon = 2; break; // button4
859             case OBJECT_MOBILEtb:   icon = 1; break;
860             case OBJECT_MOBILEwb:   icon = 0; break;
861             case OBJECT_MOBILEib:   icon = 3; break;
862             case OBJECT_MOBILEfc:   icon = 17; break;
863             case OBJECT_MOBILEtc:   icon = 16; break;
864             case OBJECT_MOBILEwc:   icon = 15; break;
865             case OBJECT_MOBILEic:   icon = 23; break;
866             case OBJECT_MOBILEfi:   icon = 27; break;
867             case OBJECT_MOBILEti:   icon = 26; break;
868             case OBJECT_MOBILEwi:   icon = 25; break;
869             case OBJECT_MOBILEii:   icon = 28; break;
870             case OBJECT_MOBILEfs:   icon = 14; break;
871             case OBJECT_MOBILEts:   icon = 13; break;
872             case OBJECT_MOBILEws:   icon = 12; break;
873             case OBJECT_MOBILEis:   icon = 24; break;
874             case OBJECT_MOBILErt:   icon = 18; break;
875             case OBJECT_MOBILErc:   icon = 19; break;
876             case OBJECT_MOBILErr:   icon = 20; break;
877             case OBJECT_MOBILErs:   icon = 29; break;
878             case OBJECT_MOBILEsa:   icon = 21; break;
879             case OBJECT_MOBILEft:   icon =  6; break;
880             case OBJECT_MOBILEtt:   icon =  5; break;
881             case OBJECT_MOBILEwt:   icon = 30; break;
882             case OBJECT_MOBILEit:   icon =  7; break;
883             case OBJECT_MOBILErp:   icon =  9; break;
884             case OBJECT_MOBILEst:   icon = 10; break;
885             case OBJECT_MOBILEtg:   icon = 45; break;
886             case OBJECT_MOBILEdr:   icon = 48; break;
887             case OBJECT_APOLLO2:    icon = 49; break;
888             case OBJECT_MOTHER:     icon = 31; break;
889             case OBJECT_ANT:        icon = 31; break;
890             case OBJECT_SPIDER:     icon = 31; break;
891             case OBJECT_BEE:        icon = 31; break;
892             case OBJECT_WORM:       icon = 31; break;
893             case OBJECT_TEEN28:     icon = 48; break;  // bottle
894             case OBJECT_TEEN34:     icon = 48; break;  // stone
895             default:                icon = -1;
896         }
897         if ( icon == -1 )  return;
898 
899         switch ( type )
900         {
901             case OBJECT_MOBILEfb:
902             case OBJECT_MOBILEtb:
903             case OBJECT_MOBILEwb:
904             case OBJECT_MOBILEib:
905             case OBJECT_MOBILEft:
906             case OBJECT_MOBILEtt:
907             case OBJECT_MOBILEit:
908             case OBJECT_MOBILErp:
909             case OBJECT_MOBILEst:
910                 m_engine->SetTexture("textures/interface/button4.png"); break;
911             default: ; // button3.png
912         }
913 
914         m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE);
915         uv1.x = (32.0f/256.0f)*(icon%8);
916         uv1.y = (32.0f/256.0f)*(icon/8);
917         uv2.x = uv1.x+32.0f/256.0f;
918         uv2.y = uv1.y+32.0f/256.0f;
919         uv1.x += dp;
920         uv1.y += dp;
921         uv2.x -= dp;
922         uv2.y -= dp;
923         DrawIcon(pos, dim, uv1, uv2);  // icon
924     }
925 }
926 
927 // Draw the object with the mouse hovers over.
928 
DrawHighlight(Math::Point pos)929 void CMap::DrawHighlight(Math::Point pos)
930 {
931     Math::Point dim, uv1, uv2;
932 
933     if (m_bToy || !m_fixImage.empty())  return;  // map with still image?
934 
935     pos.x = (pos.x-m_offset.x)*(m_zoom*0.5f)/m_half+0.5f;
936     pos.y = (pos.y-m_offset.y)*(m_zoom*0.5f)/m_half+0.5f;
937 
938     pos.x = m_mapPos.x+m_mapDim.x*pos.x;
939     pos.y = m_mapPos.y+m_mapDim.y*pos.y;
940     dim.x = 2.0f/128.0f*0.75f;
941     dim.y = 2.0f/128.0f;
942     dim.x *= 2.0f+cosf(m_time*8.0f)*0.5f;
943     dim.y *= 2.0f+cosf(m_time*8.0f)*0.5f;
944 
945     m_engine->SetTexture("textures/interface/button2.png");
946     m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
947     uv1.x = 160.5f/256.0f;  // hilite
948     uv1.y = 224.5f/256.0f;
949     uv2.x = 175.0f/256.0f;
950     uv2.y = 239.0f/256.0f;
951     pos.x -= dim.x/2.0f;
952     pos.y -= dim.y/2.0f;
953     DrawIcon(pos, dim, uv1, uv2);
954 }
955 
956 // Draws a triangular icon.
957 
DrawTriangle(Math::Point p1,Math::Point p2,Math::Point p3,Math::Point uv1,Math::Point uv2)958 void CMap::DrawTriangle(Math::Point p1, Math::Point p2, Math::Point p3, Math::Point uv1, Math::Point uv2)
959 {
960     Gfx::CDevice* device;
961     Gfx::VertexTex2  vertex[3];  // 1 triangle
962     Math::Vector    n;
963 
964     device = m_engine->GetDevice();
965 
966     n = Math::Vector(0.0f, 0.0f, -1.0f);  // normal
967 
968     vertex[0] = Gfx::VertexTex2(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(uv1.x,uv1.y));
969     vertex[1] = Gfx::VertexTex2(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(uv1.x,uv2.y));
970     vertex[2] = Gfx::VertexTex2(Math::Vector(p3.x, p3.y, 0.0f), n, Math::Point(uv2.x,uv2.y));
971 
972     device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, vertex, 3);
973     m_engine->AddStatisticTriangle(1);
974 }
975 
976 // Draw a pentagon icon (a 5 rating, what!).
977 
DrawPenta(Math::Point p1,Math::Point p2,Math::Point p3,Math::Point p4,Math::Point p5,Math::Point uv1,Math::Point uv2)978 void CMap::DrawPenta(Math::Point p1, Math::Point p2, Math::Point p3, Math::Point p4, Math::Point p5, Math::Point uv1, Math::Point uv2)
979 {
980     Gfx::CDevice* device;
981     Gfx::VertexTex2  vertex[5];  // 1 pentagon
982     Math::Vector    n;
983 
984     device = m_engine->GetDevice();
985 
986     n = Math::Vector(0.0f, 0.0f, -1.0f);  // normal
987 
988     vertex[0] = Gfx::VertexTex2(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(uv1.x,uv1.y));
989     vertex[1] = Gfx::VertexTex2(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(uv1.x,uv2.y));
990     vertex[2] = Gfx::VertexTex2(Math::Vector(p5.x, p5.y, 0.0f), n, Math::Point(uv2.x,uv2.y));
991     vertex[3] = Gfx::VertexTex2(Math::Vector(p3.x, p3.y, 0.0f), n, Math::Point(uv2.x,uv2.y));
992     vertex[4] = Gfx::VertexTex2(Math::Vector(p4.x, p4.y, 0.0f), n, Math::Point(uv2.x,uv2.y));
993 
994     device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, vertex, 5);
995     m_engine->AddStatisticTriangle(3);
996 }
997 
998 // Draw the vertex array.
999 
DrawVertex(Math::Point uv1,Math::Point uv2,float zoom)1000 void CMap::DrawVertex(Math::Point uv1, Math::Point uv2, float zoom)
1001 {
1002     Gfx::CDevice* device;
1003     Gfx::VertexTex2  vertex[4];  // 2 triangles
1004     Math::Point     p1, p2, c;
1005     Math::Vector    n;
1006 
1007     device = m_engine->GetDevice();
1008 
1009     p1.x = m_pos.x;
1010     p1.y = m_pos.y;
1011     p2.x = m_pos.x + m_dim.x;
1012     p2.y = m_pos.y + m_dim.y;
1013 
1014     c.x = (p1.x+p2.x)/2.0f;
1015     c.y = (p1.y+p2.y)/2.0f;  // center
1016 
1017     p1.x = (p1.x-c.x)*zoom + c.x;
1018     p1.y = (p1.y-c.y)*zoom + c.y;
1019 
1020     p2.x = (p2.x-c.x)*zoom + c.x;
1021     p2.y = (p2.y-c.y)*zoom + c.y;
1022 
1023     m_mapPos   = p1;
1024     m_mapDim.x = p2.x-p1.x;
1025     m_mapDim.y = p2.y-p1.y;
1026 
1027     n = Math::Vector(0.0f, 0.0f, -1.0f);  // normal
1028 
1029     vertex[0] = Gfx::VertexTex2(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(uv1.x,uv2.y));
1030     vertex[1] = Gfx::VertexTex2(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(uv1.x,uv1.y));
1031     vertex[2] = Gfx::VertexTex2(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(uv2.x,uv2.y));
1032     vertex[3] = Gfx::VertexTex2(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(uv2.x,uv1.y));
1033 
1034     device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, vertex, 4);
1035     m_engine->AddStatisticTriangle(2);
1036 }
1037 
1038 
1039 // Updates the field in the map.
1040 
UpdateTerrain()1041 void CMap::UpdateTerrain()
1042 {
1043     if (! m_fixImage.empty()) return;  // still image?
1044 
1045     CImage img(Math::IntPoint(256, 256));
1046 
1047     float scale = m_terrain->GetReliefScale();
1048     float water = m_water->GetLevel();
1049 
1050     Gfx::Color color;
1051     color.a = 0.0f;
1052 
1053     for (int y = 0; y < 256; y++)
1054     {
1055         for (int x = 0; x < 256; x++)
1056         {
1057             Math::Vector pos;
1058             pos.x =  (static_cast<float>(x) - 128.0f) * m_half / 128.0f;
1059             pos.z = -(static_cast<float>(y) - 128.0f) * m_half / 128.0f;
1060             pos.y = 0.0f;
1061 
1062             float level;
1063 
1064             if ( pos.x >= -m_half && pos.x <= m_half &&
1065                  pos.z >= -m_half && pos.z <= m_half )
1066             {
1067                 level = m_terrain->GetFloorLevel(pos, true) / scale;
1068             }
1069             else
1070             {
1071                 level = 1000.0f;
1072             }
1073 
1074             float intensity = level / 256.0f;
1075             if (intensity < 0.0f) intensity = 0.0f;
1076             if (intensity > 1.0f) intensity = 1.0f;
1077 
1078             if (level >= water)  // on water?
1079             {
1080                 color.r = Math::Norm(m_floorColor.r + (intensity - 0.5f));
1081                 color.g = Math::Norm(m_floorColor.g + (intensity - 0.5f));
1082                 color.b = Math::Norm(m_floorColor.b + (intensity - 0.5f));
1083             }
1084             else    // underwater?
1085             {
1086                 color.r = Math::Norm(m_waterColor.r + (intensity - 0.5f));
1087                 color.g = Math::Norm(m_waterColor.g + (intensity - 0.5f));
1088                 color.b = Math::Norm(m_waterColor.b + (intensity - 0.5f));
1089             }
1090 
1091             img.SetPixel(Math::IntPoint(x, y), color);
1092         }
1093     }
1094 
1095     m_engine->DeleteTexture("interface/map.png");
1096     m_engine->LoadTexture("textures/interface/map.png", &img);
1097 }
1098 
1099 // Updates the field in the map.
1100 
UpdateTerrain(int bx,int by,int ex,int ey)1101 void CMap::UpdateTerrain(int bx, int by, int ex, int ey)
1102 {
1103     Gfx::Color   color;
1104     Math::Vector        pos;
1105     float           scale, water, level, intensity;
1106     int             x, y;
1107 
1108     if (! m_fixImage.empty())  return;  // still image?
1109 
1110     // TODO: map texture manipulation
1111     return;
1112 
1113     //if ( !m_engine->OpenImage("map.png") )  return;
1114     //m_engine->LoadImage();
1115 
1116     scale = m_terrain->GetReliefScale();
1117     water = m_water->GetLevel();
1118     color.a = 0.0f;
1119 
1120     for ( y=by ; y<ey ; y++ )
1121     {
1122         for ( x=bx ; x<ex ; x++ )
1123         {
1124             pos.x =  (static_cast<float>(x)-128.0f)*m_half/128.0f;
1125             pos.z = -(static_cast<float>(y)-128.0f)*m_half/128.0f;
1126             pos.y = 0.0f;
1127 
1128             if ( pos.x >= -m_half && pos.x <= m_half &&
1129                  pos.z >= -m_half && pos.z <= m_half )
1130             {
1131                 level = m_terrain->GetFloorLevel(pos, true)/scale;
1132             }
1133             else
1134             {
1135                 level = 1000.0f;
1136             }
1137 
1138             intensity = level/256.0f;
1139             if ( intensity < 0.0f )  intensity = 0.0f;
1140             if ( intensity > 1.0f )  intensity = 1.0f;
1141 
1142             if ( level > water )  // on water?
1143             {
1144                 color.r = m_floorColor.r + (intensity-0.5f);
1145                 color.g = m_floorColor.g + (intensity-0.5f);
1146                 color.b = m_floorColor.b + (intensity-0.5f);
1147             }
1148             else    // underwater?
1149             {
1150                 color.r = m_waterColor.r + (intensity-0.5f);
1151                 color.g = m_waterColor.g + (intensity-0.5f);
1152                 color.b = m_waterColor.b + (intensity-0.5f);
1153             }
1154 
1155             //m_engine->SetDot(x, y, color);
1156         }
1157     }
1158 
1159     //m_engine->CopyImage();  // copy the ground drawing
1160     //m_engine->CloseImage();
1161 }
1162 
1163 
1164 // Empty all objects.
1165 
FlushObject()1166 void CMap::FlushObject()
1167 {
1168     m_totalFix  = 0;  // object index fixed
1169     m_totalMove = MAPMAXOBJECT-2;  // moving vehicles index
1170     m_bRadar = m_main->GetRadar();
1171 
1172     for (int i = 0; i < MAPMAXOBJECT; i++)
1173     {
1174         m_map[i].bUsed = false;
1175     }
1176 }
1177 
1178 // Updates an object in the map.
1179 
UpdateObject(CObject * pObj)1180 void CMap::UpdateObject(CObject* pObj)
1181 {
1182     ObjectType      type;
1183     MapColor        color;
1184     Math::Vector        pos;
1185     Math::Point         ppos;
1186     float           dir;
1187 
1188     if ( !m_bEnable )  return;
1189     if ( m_totalFix >= m_totalMove )  return;  // full table?
1190 
1191     type = pObj->GetType();
1192     if ( !pObj->GetDetectable() )  return;
1193     if ( type != OBJECT_MOTHER   &&
1194          type != OBJECT_ANT      &&
1195          type != OBJECT_SPIDER   &&
1196          type != OBJECT_BEE      &&
1197          type != OBJECT_WORM     &&
1198          type != OBJECT_MOBILEtg )
1199     {
1200         if (pObj->Implements(ObjectInterfaceType::Controllable) && !dynamic_cast<CControllableObject&>(*pObj).GetSelectable()) return;
1201     }
1202     if ( pObj->GetProxyActivate() )  return;
1203     if (IsObjectBeingTransported(pObj))  return;
1204 
1205     pos  = pObj->GetPosition();
1206     dir  = -(pObj->GetRotationY()+Math::PI/2.0f);
1207 
1208     if ( m_angle != 0.0f )
1209     {
1210         ppos = RotatePoint(m_angle, Math::Point(pos.x, pos.z));
1211         pos.x = ppos.x;
1212         pos.z = ppos.y;
1213         dir += m_angle;
1214     }
1215 
1216     color = MAPCOLOR_NULL;
1217     if ( type == OBJECT_BASE )
1218     {
1219         color = MAPCOLOR_BASE;
1220     }
1221     if ( type == OBJECT_DERRICK  ||
1222          type == OBJECT_FACTORY  ||
1223          type == OBJECT_STATION  ||
1224          type == OBJECT_CONVERT  ||
1225          type == OBJECT_REPAIR   ||
1226          type == OBJECT_DESTROYER||
1227          type == OBJECT_TOWER    ||
1228          type == OBJECT_RESEARCH ||
1229          type == OBJECT_RADAR    ||
1230          type == OBJECT_INFO     ||
1231          type == OBJECT_ENERGY   ||
1232          type == OBJECT_LABO     ||
1233          type == OBJECT_NUCLEAR  ||
1234          type == OBJECT_PARA     ||
1235          type == OBJECT_SAFE     ||
1236          type == OBJECT_HUSTON   ||
1237          type == OBJECT_TARGET1  ||
1238          type == OBJECT_START    ||
1239          type == OBJECT_END      ||  // stationary object?
1240          type == OBJECT_TEEN28    ||  // bottle?
1241          type == OBJECT_TEEN34    )   // stone?
1242     {
1243         color = MAPCOLOR_FIX;
1244     }
1245     if ( type == OBJECT_BBOX ||
1246          type == OBJECT_KEYa ||
1247          type == OBJECT_KEYb ||
1248          type == OBJECT_KEYc ||
1249          type == OBJECT_KEYd )
1250     {
1251         color = MAPCOLOR_BBOX;
1252     }
1253     if ( type == OBJECT_HUMAN    ||
1254          type == OBJECT_MOBILEwa ||
1255          type == OBJECT_MOBILEta ||
1256          type == OBJECT_MOBILEfa ||
1257          type == OBJECT_MOBILEia ||
1258          type == OBJECT_MOBILEwb ||
1259          type == OBJECT_MOBILEtb ||
1260          type == OBJECT_MOBILEfb ||
1261          type == OBJECT_MOBILEib ||
1262          type == OBJECT_MOBILEwc ||
1263          type == OBJECT_MOBILEtc ||
1264          type == OBJECT_MOBILEfc ||
1265          type == OBJECT_MOBILEic ||
1266          type == OBJECT_MOBILEwi ||
1267          type == OBJECT_MOBILEti ||
1268          type == OBJECT_MOBILEfi ||
1269          type == OBJECT_MOBILEii ||
1270          type == OBJECT_MOBILEws ||
1271          type == OBJECT_MOBILEts ||
1272          type == OBJECT_MOBILEfs ||
1273          type == OBJECT_MOBILEis ||
1274          type == OBJECT_MOBILErt ||
1275          type == OBJECT_MOBILErc ||
1276          type == OBJECT_MOBILErr ||
1277          type == OBJECT_MOBILErs ||
1278          type == OBJECT_MOBILEsa ||
1279          type == OBJECT_MOBILEtg ||
1280          type == OBJECT_MOBILEwt ||
1281          type == OBJECT_MOBILEtt ||
1282          type == OBJECT_MOBILEft ||
1283          type == OBJECT_MOBILEit ||
1284          type == OBJECT_MOBILErp ||
1285          type == OBJECT_MOBILEst ||
1286          type == OBJECT_MOBILEdr ||
1287          type == OBJECT_APOLLO2  )  // moving vehicle?
1288     {
1289         color = MAPCOLOR_MOVE;
1290     }
1291     if ( type == OBJECT_ANT      ||
1292          type == OBJECT_BEE      ||
1293          type == OBJECT_WORM     ||
1294          type == OBJECT_SPIDER   )  // mobile enemy?
1295     {
1296         color = MAPCOLOR_ALIEN;
1297     }
1298     if ( type == OBJECT_WAYPOINT ||
1299          type == OBJECT_FLAGb    )
1300     {
1301         color = MAPCOLOR_WAYPOINTb;
1302     }
1303     if ( type == OBJECT_FLAGr )
1304     {
1305         color = MAPCOLOR_WAYPOINTr;
1306     }
1307     if ( type == OBJECT_FLAGg )
1308     {
1309         color = MAPCOLOR_WAYPOINTg;
1310     }
1311     if ( type == OBJECT_FLAGy )
1312     {
1313         color = MAPCOLOR_WAYPOINTy;
1314     }
1315     if ( type == OBJECT_FLAGv )
1316     {
1317         color = MAPCOLOR_WAYPOINTv;
1318     }
1319 
1320     if ( color == MAPCOLOR_NULL )  return;
1321 
1322     /*if (!m_fixImage.empty() && !m_bDebug)  // map with still image?
1323     {
1324         if ( (type == OBJECT_TEEN28 ||
1325               type == OBJECT_TEEN34 ) &&
1326              m_mode == 0 )  return;
1327 
1328         if ( type != OBJECT_TEEN28 &&
1329              type != OBJECT_TEEN34 &&
1330              color != MAPCOLOR_MOVE )  return;
1331     }*/
1332 
1333     if ( pObj->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject&>(*pObj).GetSelect() )
1334     {
1335         m_map[MAPMAXOBJECT-1].type   = type;
1336         m_map[MAPMAXOBJECT-1].object = pObj;
1337         m_map[MAPMAXOBJECT-1].color  = color;
1338         m_map[MAPMAXOBJECT-1].pos.x  = pos.x;
1339         m_map[MAPMAXOBJECT-1].pos.y  = pos.z;
1340         m_map[MAPMAXOBJECT-1].dir    = dir;
1341         m_map[MAPMAXOBJECT-1].bUsed  = true;
1342     }
1343     else
1344     {
1345         if ( color == MAPCOLOR_BASE ||
1346              color == MAPCOLOR_FIX  )
1347         {
1348             m_map[m_totalFix].type   = type;
1349             m_map[m_totalFix].object = pObj;
1350             m_map[m_totalFix].color  = color;
1351             m_map[m_totalFix].pos.x  = pos.x;
1352             m_map[m_totalFix].pos.y  = pos.z;
1353             m_map[m_totalFix].dir    = dir;
1354             m_map[m_totalFix].bUsed  = true;
1355             m_totalFix ++;
1356         }
1357         else
1358         {
1359             m_map[m_totalMove].type   = type;
1360             m_map[m_totalMove].object = pObj;
1361             m_map[m_totalMove].color  = color;
1362             m_map[m_totalMove].pos.x  = pos.x;
1363             m_map[m_totalMove].pos.y  = pos.z;
1364             m_map[m_totalMove].dir    = dir;
1365             m_map[m_totalMove].bUsed  = true;
1366             m_totalMove --;
1367         }
1368     }
1369 }
1370 
1371 }
1372