2 Copyright © 2004 Parallel Realities
3 Copyright © 2007-2008 Kővágó Zoltán <DirtY.iCE.hu@gmail.com>
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 See the GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #include "CGraphics.h"
28 #include "CRadarBlip.h"
30 #include "gettext.hpp"
35 map
.offsetX
= (int)(engine
.playerPosX
) - bx
;
36 map
.offsetY
= (int)(engine
.playerPosY
) - by
;
38 Math::limitInt(&(map
.offsetX
), 0, ((MAPWIDTH
- 40) * BRICKSIZE
));
39 Math::limitInt(&(map
.offsetY
), 0, ((MAPHEIGHT
- 30) * BRICKSIZE
));
47 int mapx
= map
.offsetX
>> BRICKSHIFT
;
48 int mapy
= map
.offsetY
>> BRICKSHIFT
;
51 int xtimes
= (graphics
.width
/ 32) + (graphics
.width
% 32 ? 2 : 1);
52 int ytimes
= (graphics
.height
/ 32) + (graphics
.width
% 32 ? 2 : 1);
54 for (int x
= 0; (x
< xtimes
) && ((mapx
+ x
) < MAPWIDTH
); x
++)
56 for (int y
= 0; (y
< ytimes
) && ((mapy
+ y
) < MAPHEIGHT
); y
++)
58 brick
= map
.data
[mapx
+ x
][mapy
+ y
];
60 r
.x
= ((x
* BRICKSIZE
) - (map
.offsetX
& BRICKSIZE
- 1));
61 r
.y
= ((y
* BRICKSIZE
) - (map
.offsetY
& BRICKSIZE
- 1));
62 r
.w
= r
.h
= BRICKSIZE
;
64 if ((brick
>= MAP_BREAKABLE
) && (brick
< MAP_WATERANIM
))
66 graphics
.blit(graphics
.tile
[brick
], r
.x
, r
.y
, graphics
.screen
, false);
69 if ((brick
>= MAP_NORESET
) && (brick
< MAP_DECORATION
))
71 graphics
.drawRect(r
.x
, r
.y
, 32, 4, graphics
.yellow
, graphics
.screen
);
78 void drawMapTopLayer()
82 int offsetX
= map
.offsetX
;
83 int offsetY
= map
.offsetY
;
85 Math::limitInt(&offsetX
, 0, ((MAPWIDTH
- 40) * BRICKSIZE
));
86 Math::limitInt(&offsetY
, 0, ((MAPHEIGHT
- 30) * BRICKSIZE
));
88 int mapx
= offsetX
>> BRICKSHIFT
;
89 int mapy
= offsetY
>> BRICKSHIFT
;
93 int xtimes
= (graphics
.width
/ 32) + (graphics
.width
% 32 ? 2 : 1);
94 int ytimes
= (graphics
.height
/ 32) + (graphics
.width
% 32 ? 2 : 1);
96 for (int x
= 0; (x
< xtimes
) && ((mapx
+ x
) < MAPWIDTH
); x
++)
98 for (int y
= 0; (y
< ytimes
) && ((mapy
+ y
) < MAPHEIGHT
); y
++)
100 r
.x
= ((x
* BRICKSIZE
) - (offsetX
& BRICKSIZE
- 1));
101 r
.y
= ((y
* BRICKSIZE
) - (offsetY
& BRICKSIZE
- 1));
102 r
.w
= r
.h
= BRICKSIZE
;
104 brick
= map
.data
[mapx
+ x
][mapy
+ y
];
111 if ((brick
< MAP_BREAKABLE
) || (brick
>= MAP_WATERANIM
))
113 if (brick
== MAP_WATER
)
115 if (map
.data
[mapx
+ x
][mapy
+ y
+ 1] >= MAP_BREAKABLE
)
117 addBubble((mapx
+ x
) * BRICKSIZE
, (mapy
+ y
) * BRICKSIZE
);
121 if (brick
== MAP_WATERANIM
)
123 brick
= graphics
.getWaterAnim();
125 else if (brick
== MAP_SLIME
)
127 brick
= graphics
.getSlimeAnim();
129 else if ((brick
>= MAP_LAVAANIM
) && (brick
< MAP_TOPLAYER
))
131 map
.data
[mapx
+ x
][mapy
+ y
] = graphics
.getLavaAnim(brick
);
132 brick
= map
.data
[mapx
+ x
][mapy
+ y
];
135 graphics
.blit(graphics
.tile
[brick
], r
.x
, r
.y
, graphics
.screen
, false);
141 void addBlips(List
*blipList
, int mapX
, int mapY
, int type
)
149 blipType
= graphics
.getSprite("MIAArrow", true);
150 ent
= (Entity
*)map
.miaList
.getHead();
153 blipType
= graphics
.getSprite("ItemArrow", true);
154 ent
= (Entity
*)map
.itemList
.getHead();
157 blipType
= graphics
.getSprite("EnemyArrow", true);
158 ent
= (Entity
*)map
.enemyList
.getHead();
167 while (ent
->next
!= NULL
)
169 ent
= (Entity
*)ent
->next
;
171 if (ent
->health
<= 0)
176 if (!requiredEnemy(ent
->name
))
185 if ((ent
->id
< ITEM_MISC
) || (ent
->id
== ITEM_MISC_INVISIBLE
))
191 x
= (int)(ent
->x
+ ent
->width
) >> BRICKSHIFT
;
192 y
= (int)(ent
->y
+ ent
->height
) >> BRICKSHIFT
;
200 if ((x
>= 165) && (y
>= 125) && (x
<= 475) && (y
<= 355))
202 blip
= new RadarBlip();
203 blip
->set(x
, y
, type
);
204 blipList
->add (blip
);
209 graphics
.blit(blipType
->image
[0], bx
+ 220 + (type
* 50), by
+ 100, graphics
.screen
, true);
211 graphics
.blit(blipType
->image
[1], bx
+ 510, by
+ 140 + (type
* 50), graphics
.screen
, true);
213 graphics
.blit(blipType
->image
[2], bx
+ 220 + (type
* 50), by
+ 380, graphics
.screen
, true);
215 graphics
.blit(blipType
->image
[3], bx
+ 125, by
+ 140 + (type
* 50), graphics
.screen
, true);
220 void addMiniMapDoors(SDL_Surface
*panel
, int mapX
, int mapY
)
222 Train
*train
= (Train
*)map
.trainList
.getHead();
225 int width
, height
, color
;
227 while (train
->next
!= NULL
)
229 train
= (Train
*)train
->next
;
233 color
= graphics
.white
;
235 x
= (int)train
->x
>> BRICKSHIFT
;
237 y
= (int)train
->y
>> BRICKSHIFT
;
239 if ((x
>= mapX
) && (x
<= mapX
+ 64) && (y
>= mapY
) && (y
<= mapY
+ 48))
244 if (train
->type
== TR_TRAIN
)
248 else if ((train
->type
>= TR_SLIDEDOOR
) && (train
->type
<= TR_BRONZE_SLIDEDOOR
))
260 case TR_GOLD_SLIDEDOOR
:
261 color
= graphics
.yellow
;
265 case TR_SILVER_SLIDEDOOR
:
266 color
= graphics
.grey
;
270 case TR_BRONZE_SLIDEDOOR
:
271 color
= SDL_MapRGB(graphics
.screen
->format
, 0xff, 0x99, 0x00);
276 case TR_LOCKED_SLIDEDOOR
:
277 color
= SDL_MapRGB(graphics
.screen
->format
, 0xff, 0x00, 0xff);
281 graphics
.drawRect(x
* 5, y
* 5, width
, height
, color
, panel
);
286 void showMap(int centerX
, int centerY
)
296 int minX
= (map
.limitLeft
>> BRICKSHIFT
);
297 int maxX
= (map
.limitRight
>> BRICKSHIFT
) - 44;
298 int minY
= (map
.limitUp
>> BRICKSHIFT
);
299 int maxY
= (map
.limitDown
>> BRICKSHIFT
) - 33;
301 Math::limitInt(&x1
, minX
, maxX
);
302 Math::limitInt(&x2
, minX
, maxX
);
303 Math::limitInt(&y1
, minY
, maxY
);
304 Math::limitInt(&y2
, minY
, maxY
);
306 SDL_FillRect(graphics
.screen
, NULL
, graphics
.black
);
307 graphics
.updateScreen();
309 SDL_Surface
*panel
= graphics
.createSurface(320, 240);
310 SDL_Surface
*background
= graphics
.loadImage("gfx/main/mapBackground.png");
311 SDL_SetAlpha(background
, SDL_SRCALPHA
|SDL_RLEACCEL
, 128);
313 graphics
.blit(background
, 0, 0, panel
, false);
315 int color
= graphics
.black
;
317 for (int y
= 0 ; y
< 48 ; y
++)
319 for (int x
= 0 ; x
< 64 ; x
++)
321 if (map
.data
[x1
+ x
][y1
+ y
] == MAP_WATER
)
323 graphics
.drawRect(x
* 5, y
* 5, 5, 5, graphics
.blue
, panel
);
328 addMiniMapDoors(panel
, x1
, y1
);
330 for (int y
= 0 ; y
< 48 ; y
++)
332 for (int x
= 0 ; x
< 64 ; x
++)
336 if (map
.data
[x1
+ x
][y1
+ y
] == MAP_AIR
)
340 else if (map
.data
[x1
+ x
][y1
+ y
] == MAP_WATER
)
344 else if (map
.data
[x1
+ x
][y1
+ y
] == MAP_SLIME
)
346 color
= graphics
.green
;
348 else if (map
.data
[x1
+ x
][y1
+ y
] == MAP_LAVA
)
350 color
= graphics
.red
;
352 else if (map
.data
[x1
+ x
][y1
+ y
] >= MAP_DECORATION
)
356 if (map
.data
[x1
+ x
][y1
+ y
- 1] == MAP_WATER
)
358 color
= graphics
.blue
;
360 else if (map
.data
[x1
+ x
][y1
+ y
+ 1] == MAP_WATER
)
362 color
= graphics
.blue
;
365 else if (map
.data
[x1
+ x
][y1
+ y
] < MAP_WATERANIM
)
367 color
= graphics
.darkGreen
;
372 graphics
.drawRect(x
* 5, y
* 5, 5, 5, color
, panel
);
377 SDL_Surface
* tmp_bckg
= graphics
.background
;
378 graphics
.background
= background
;
379 graphics
.drawBackground();
380 graphics
.background
= tmp_bckg
;
381 SDL_FreeSurface(background
);
385 RadarBlip
*blip
= new RadarBlip();
386 blip
->set(160 + ((centerX
- x1
) * 5), 120 + ((centerY
- y1
) * 5), 0);
389 addBlips(&blipList
, x1
, y1
, 1);
390 addBlips(&blipList
, x1
, y1
, 2);
391 addBlips(&blipList
, x1
, y1
, 3);
393 Sprite
*enemySignal
= graphics
.getSprite("EnemySignal", true);
394 Sprite
*miaSignal
= graphics
.getSprite("MIASignal", true);
395 Sprite
*bobSignal
= graphics
.getSprite("BobSignal", true);
396 Sprite
*itemSignal
= graphics
.getSprite("ItemSignal", true);
398 graphics
.setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
399 graphics
.setFontSize(3);
400 graphics
.drawString(game
.stageName
, bx
+ 320, by
+ 30, TXT_CENTERED
, graphics
.screen
);
402 graphics
.setFontSize(0);
404 graphics
.drawRect(bx
+ 160, by
+ 414, 7, 7, graphics
.yellow
, graphics
.white
, graphics
.screen
);
405 graphics
.drawString(_("MIAs"), bx
+ 175, by
+ 410, TXT_LEFT
, graphics
.screen
);
407 graphics
.drawRect(bx
+ 290, by
+ 414, 7, 7, graphics
.blue
, graphics
.white
, graphics
.screen
);
408 graphics
.drawString(_("Items"), bx
+ 320, by
+ 417, TXT_CENTERED
, graphics
.screen
);
410 graphics
.drawRect(bx
+ 415, by
+ 414, 7, 7, graphics
.red
, graphics
.white
, graphics
.screen
);
411 graphics
.drawString(_("Enemies"), bx
+ 480, by
+ 410, TXT_RIGHT
, graphics
.screen
);
413 graphics
.setFontSize(1);
414 sprintf(string
, "%s - %.2d:%.2d:%.2d", _("Mission Time").c_str(), game
.currentMissionHours
, game
.currentMissionMinutes
, game
.currentMissionSeconds
);
415 graphics
.drawString(string
, bx
+ 320, by
+ 60, TXT_CENTERED
, graphics
.screen
);
416 graphics
.drawString(_("Press Button to Continue..."), bx
+ 320, by
+ 450, TXT_CENTERED
, graphics
.screen
);
424 graphics
.updateScreen();
425 graphics
.animateSprites();
427 graphics
.drawRect(bx
+ 160, by
+ 120, 320, 240, graphics
.black
, graphics
.white
, graphics
.screen
);
428 graphics
.blit(panel
, bx
+ 160, by
+ 120, graphics
.screen
, false);
430 if ((engine
.isKey(KEY_MAP
)) || (engine
.isKey(KEY_PAUSE
)) || (engine
.keyState
[SDLK_ESCAPE
]))
435 blip
= (RadarBlip
*)blipList
.getHead();
437 while (blip
->next
!= NULL
)
439 blip
= (RadarBlip
*)blip
->next
;
444 graphics
.blit(bobSignal
->getCurrentFrame(), bx
+ blip
->x
, by
+ blip
->y
, graphics
.screen
, true);
447 graphics
.blit(miaSignal
->getCurrentFrame(), bx
+ blip
->x
, by
+ blip
->y
, graphics
.screen
, true);
450 graphics
.blit(itemSignal
->getCurrentFrame(), bx
+ blip
->x
, by
+ blip
->y
, graphics
.screen
, true);
453 graphics
.blit(enemySignal
->getCurrentFrame(), bx
+ blip
->x
, by
+ blip
->y
, graphics
.screen
, true);
463 SDL_FillRect(graphics
.screen
, NULL
, graphics
.black
);
464 graphics
.updateScreen();
470 void evaluateMapAttribute(Entity
*ent
, int mapAttribute
)
472 switch (mapAttribute
)
477 case MAP_AIR_CEILING_1
:
478 mapAttribute
= MAP_AIR
;
481 if (map
.isCavesTileset
)
483 mapAttribute
= MAP_AIR
;
486 case MAP_AIR_CEILING_2
:
487 if (map
.isGrasslandsTileset
)
489 mapAttribute
= MAP_AIR
;
491 else if (map
.isCavesTileset
)
493 mapAttribute
= MAP_WATER
;
497 if (map
.isCavesTileset
)
499 mapAttribute
= MAP_WATER
;
504 switch (mapAttribute
)
507 if ((ent
->environment
!= ENV_AIR
) && (!(ent
->flags
& ENT_INANIMATE
)))
509 if (!(ent
->flags
& ENT_SWIMS
))
513 ent
->dy
= PLAYER_JUMP_SPEED
;
518 if ((ent
== &player
) && ((game
.hasAquaLung
) || (engine
.cheatExtras
)))
520 player
.setSprites(graphics
.getSprite("BobRight", true), graphics
.getSprite("BobLeft", true), graphics
.getSprite("BobSpin", true));
524 ent
->environment
= ENV_AIR
;
528 audio
.playSound(SND_WATEROUT
, CH_TOUCH
);
531 ent
->checkEnvironment();
541 ent
->falling
= false;
543 if (ent
->environment
== ENV_AIR
)
545 audio
.playSound(SND_WATERIN
, CH_TOUCH
);
546 if ((mapAttribute
== MAP_SLIME
) || (mapAttribute
== MAP_LAVA
))
550 // On ice levels water is harmful (because it's very very cold!)
551 if ((map
.isIceLevel
) && (mapAttribute
== MAP_WATER
))
553 mapAttribute
= MAP_LAVA
;
557 if (mapAttribute
== MAP_WATER
)
559 ent
->environment
= ENV_WATER
;
560 if ((ent
== &player
) && ((game
.hasAquaLung
) || (engine
.cheatExtras
)))
562 player
.setSprites(graphics
.getSprite("AquaBobRight", true), graphics
.getSprite("AquaBobLeft", true), graphics
.getSprite("AquaBobSpin", true));
565 else if (mapAttribute
== MAP_SLIME
)
567 ent
->environment
= ENV_SLIME
;
569 else if (mapAttribute
== MAP_LAVA
)
571 ent
->environment
= ENV_LAVA
;
577 void raiseWaterLevel()
579 if (map
.waterLevel
== map
.requiredWaterLevel
)
584 int y
= (int)map
.waterLevel
;
586 if ((int)map
.waterLevel
!= map
.requiredWaterLevel
)
588 for (int x
= 0 ; x
< MAPWIDTH
; x
++)
590 if ((map
.data
[x
][y
] == MAP_AIR
) || (map
.isLiquid(x
, y
)))
592 map
.data
[x
][y
] = MAP_WATER
;
595 if ((map
.data
[x
][y
] >= MAP_DECORATION
) && (map
.data
[x
][y
] <= MAP_WATERANIM
))
597 map
.data
[x
][y
] = MAP_WATER
;
600 if (map
.data
[x
][y
] >= MAP_TOPLAYER
)
602 map
.data
[x
][y
] = MAP_WATER
;
605 if (map
.data
[x
][y
- 1] >= MAP_TOPLAYER
)
607 map
.data
[x
][y
] = MAP_WATER
;
610 if ((map
.data
[x
][y
- 1] == MAP_AIR
) || (map
.isLiquid(x
, y
- 1)))
612 map
.data
[x
][y
- 1] = MAP_WATERANIM
;
615 if ((map
.data
[x
][y
- 1] >= MAP_DECORATION
) && (map
.data
[x
][y
- 1] <= MAP_WATERANIM
))
617 map
.data
[x
][y
- 1] = MAP_WATERANIM
;
621 map
.waterLevel
-= 0.1;
623 int x
= (int)(player
.x
+ player
.dx
) >> BRICKSHIFT
;
624 int y
= (int)(player
.y
+ player
.height
- 1) >> BRICKSHIFT
;
626 int mapAttribute
= map
.data
[x
][y
];
628 if ((mapAttribute
== MAP_WATER
) && (player
.environment
== MAP_AIR
))
630 evaluateMapAttribute(&player
, mapAttribute
);
637 map
.windChangeTime
--;
639 if (map
.windChangeTime
<= 0)
643 if (Math::rrand(0, 1) == 0)
644 map
.windPower
= Math::rrand(-3, 3);
647 map
.windChangeTime
= Math::rrand(60, 600);
653 void parseMapDataLine(char *line
, int y
)
660 sscanf(line
, "%d", &tileIndex
);
662 map
.data
[x
][y
] = tileIndex
;
679 bool loadMapData(char *filename
)
683 if (!engine
.loadData(filename
))
684 graphics
.showErrorAndExit(_("The requested map '%s' was not found."), filename
);
686 char *token
= strtok((char*)engine
.dataBuffer
, "\n");
687 parseMapDataLine(token
, 0);
693 token
= strtok(NULL
, "\n");
695 parseMapDataLine(token
, y
);