Removed that logo from this bramch aswell..
[dbw.git] / src / items.cpp
blob4b9a4a09763963a6c22b161fc5b44c11a17cb914
1 /*
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.
22 #include "CAudio.h"
23 #include "CCollision.h"
24 #include "CGame.h"
25 #include "CGameData.h"
26 #include "CGraphics.h"
27 #include "CMap.h"
28 #include "CMath.h"
29 #include "CObjective.h"
30 #include "gettext.hpp"
31 #include "items.h"
33 void addItem(int itemType, const char *name, int x, int y, const char *spriteName, int health, int value, int flags, bool randomMovement)
35 Entity *item = new Entity();
37 item->id = itemType;
38 item->setName(name);
39 item->place(x, y);
40 item->setSprites(graphics.getSprite(spriteName, true), graphics.getSprite(spriteName, true), graphics.getSprite(spriteName, true));
41 item->health = health;
42 item->value = value;
43 item->flags = ENT_INANIMATE + ENT_BOUNCES + ENT_COLLECTABLE;
45 // raise items taller than the enemy
46 int x1 = x >> BRICKSHIFT;
47 int x2 = (x + item->width - 1) >> BRICKSHIFT;
48 int y2 = (y + item->height - 1) >> BRICKSHIFT;
49 if ((map.isSolid(x1, y2)) || (map.isSolid(x2, y2)))
51 item->y = (y2 * BRICKSIZE) - item->height;
54 if (randomMovement)
56 item->setRandomVelocity();
59 item->health += rand() % 120;
61 Math::addBit(&item->flags, flags);
63 if (item->id == ITEM_MISC_INVISIBLE)
65 if ((gameData.completedWorld) || (game.skill == 3))
67 item->id = ITEM_MISC_NOSHOW;
71 map.addItem(item);
74 void dropBossItems(int x, int y)
76 if ((rand() % 5) > 0)
78 return;
81 int r = Math::rrand(ITEM_PISTOL, ITEM_DOUBLECHERRY);
83 if (player.environment == ENV_WATER)
85 r = Math::rrand(ITEM_CHERRY, ITEM_DOUBLECHERRY);
88 if ((rand() % 10) == 0)
90 r = ITEM_TRIPLECHERRY;
93 addItem(defItem[r].id, defItem[r].name, x, y, defItem[r].sprite[0]->name, 240, defItem[r].value, ENT_DYING, true);
96 void dropRandomItems(int x, int y)
98 int mapX = x >> BRICKSHIFT;
99 int mapY = y >> BRICKSHIFT;
101 if (map.isSolid(mapX, mapY))
103 return;
106 if (map.isBossMission)
108 dropBossItems(x, y);
109 return;
112 int amount = Math::rrand(1, 5);
113 int r = Math::rrand(ITEM_POINTS, ITEM_POINTS7);
115 int cherryChance = 10 + (10 * game.skill);
117 for (int i = 0 ; i < amount ; i++)
119 if ((rand() % 8) == 0)
121 r = Math::rrand(ITEM_PISTOL, ITEM_SPREAD);
124 if ((rand() % 13) == 0)
126 switch (rand() % cherryChance)
128 case 0:
129 r = ITEM_TRIPLECHERRY;
130 break;
131 case 1:
132 case 2:
133 case 3:
134 case 4:
135 case 5:
136 r = ITEM_DOUBLECHERRY;
137 break;
138 default:
139 r = ITEM_CHERRY;
140 break;
144 addItem(defItem[r].id, defItem[r].name, x, y, defItem[r].sprite[0]->name, 240, defItem[r].value, ENT_DYING, true);
146 r = Math::rrand(ITEM_POINTS, ITEM_POINTS7);
150 void dropHelperItems(int x, int y)
152 int amount = Math::rrand(1, 5);
153 int r;
155 for (int i = 0 ; i < amount ; i++)
157 r = Math::rrand(ITEM_PISTOL, ITEM_TRIPLECHERRY);
159 addItem(defItem[r].id, defItem[r].name, x, y, defItem[r].sprite[0]->name, 240, defItem[r].value, ENT_DYING, true);
163 void stealCrystal()
165 Entity *item = (Entity*)map.itemList.getHead();
167 Objective *objective = (Objective*)map.objectiveList.getHead();
169 while (objective->next != NULL)
171 objective = (Objective*)objective->next;
172 objective->completed = true;
173 objective->currentValue = objective->targetValue;
176 while (item->next != NULL)
178 item = (Entity*)item->next;
180 if (strcmp(item->name, "Reality Crystal") == 0)
182 item->dx = 0;
183 item->dy = 0;
184 Math::addBit(&item->flags, ENT_TELEPORTING);
185 addTeleportParticles(item->x + (item->width / 2), item->y + (item->height / 2), 50, SND_TELEPORT3);
186 return;
192 We have to do this to avoid items being permanently lost.
193 To ensure we drop them in a safe place we put them in the player's
194 last check point position...
196 void dropCarriedItems()
198 Entity *item = (Entity*)map.itemList.getHead();
200 while (item->next != NULL)
202 item = (Entity*)item->next;
204 if (item->owner != &player)
205 continue;
207 Math::removeBit(&item->flags, ENT_DYING);
209 item->owner = item;
210 item->health = 240;
211 item->dx = 0;
212 item->dy = -2;
213 item->x = game.checkPointX + Math::rrand(0, 6);
214 item->y = game.checkPointY;
215 item->flags = ENT_INANIMATE + ENT_BOUNCES + ENT_NOCOLLISIONS;
219 void pickUpItem(Entity *item)
221 //char string[100];
223 if (item->flags & ENT_DYING)
225 game.totalBonusesCollected++;
227 else if (item->id >= ITEM_MISC)
229 game.currentMissionItemsCollected++;
230 map.foundItems++;
233 item->health = 10;
234 item->flags = ENT_WEIGHTLESS + ENT_DYING + ENT_NOCOLLISIONS;
235 item->dx = 0;
236 item->dy = -5;
238 switch (item->id)
240 case ITEM_PISTOL:
241 case ITEM_MACHINEGUN:
242 case ITEM_LASER:
243 case ITEM_GRENADES:
244 case ITEM_SPREAD:
245 player.currentWeapon = &weapon[item->id];
246 game.currentWeapon = item->id;
247 audio.playSound(SND_GETWEAPON, CH_ITEM);
248 break;
249 case ITEM_POINTS:
250 case ITEM_POINTS2:
251 case ITEM_POINTS3:
252 case ITEM_POINTS4:
253 case ITEM_POINTS5:
254 case ITEM_POINTS6:
255 case ITEM_POINTS7:
256 game.score += item->value;
257 audio.playSound(SND_ITEM, CH_ITEM);
258 break;
259 case ITEM_CHERRY:
260 case ITEM_DOUBLECHERRY:
261 case ITEM_TRIPLECHERRY:
262 Math::limitInt(&(player.health += item->value), 0, MAX_HEALTH);
263 audio.playSound(SND_GULP + (rand() % 2), CH_ITEM);
264 break;
265 case ITEM_MISC:
266 item->owner = &player;
267 case ITEM_MISC_NOSHOW:
268 audio.playSound(SND_ITEM, CH_ITEM);
269 break;
272 if ((item->id < ITEM_POINTS) || (item->id > ITEM_POINTS7))
274 if (!map.isBossMission)
277 oh yeah, right... because "Picked up a Ancient Cog" is really good English, isn't it? It's almost
278 as bad as Medal of Honor: Frontline where it said "Picked up 3 Stick Grenade(s)"... Would it really
279 have taken that much effort to pass the item number to a function that worked out some basic grammer
280 for how many items had been picked up??! Yeah... and EA expect us to pay £45 for that! Probably the
281 worst bit about that game was that it was just fecking crap anyway!
283 std::string item_name = item->name;
284 if (item_name.find_first_of(_("aeiouAEIOU")) == 0)
285 engine.setInfoMessage(_("Picked up an") + " " + _(item_name), 0, INFO_NORMAL);
286 else
287 engine.setInfoMessage(_("Picked up a") + " " + _(item_name), 0, INFO_NORMAL);
290 checkObjectives(item->name, true);
294 bool carryingItem(const char *name)
296 Entity *item = (Entity*)map.itemList.getHead();
298 while (item->next != NULL)
300 item = (Entity*)item->next;
302 if (item->owner != &player)
303 continue;
305 if (strcmp(item->name, name) == 0)
307 item->owner = item;
308 item->health = -999;
309 return true;
313 return false;
316 void showCarriedItems()
318 int x = 0;
319 int y = 210;
320 int itemCount = 0;
322 Entity *item = (Entity*)map.itemList.getHead();
324 while (item->next != NULL)
326 item = (Entity*)item->next;
328 if (item->owner != &player)
329 continue;
331 x += (item->width + 8);
332 itemCount++;
335 x = ((640 - x) / 2);
337 item = (Entity*)map.itemList.getHead();
339 while (item->next != NULL)
341 item = (Entity*)item->next;
343 if (item->owner != &player)
344 continue;
346 graphics.blit(item->getFaceImage(), bx+x, by+y, graphics.screen, false);
348 x += (item->width + 8);
351 if (itemCount == 0)
352 graphics.drawString(_("Not carrying anything"), bx+320, by+210, TXT_CENTERED, graphics.screen);
355 void doItems()
357 Entity *item = (Entity*)map.itemList.getHead();
358 Entity *previous = item;
360 int x, y;
362 while (item->next != NULL)
364 previous = item;
366 item = (Entity*)item->next;
368 if (item->id == ITEM_MISC_INVISIBLE)
370 continue;
373 x = (int)(item->x - map.offsetX);
374 y = (int)(item->y - map.offsetY);
376 item->think();
378 if (item->flags & ENT_TELEPORTING)
380 moveEntity(item);
382 else if ((abs(x) <= (graphics.width + 160)) && (abs(y) <= (graphics.height + 120)) && (item->owner == item))
384 // Gravity
385 if (!(item->flags & ENT_WEIGHTLESS))
386 item->applyGravity();
388 if (!map.isIceLevel)
389 item->dx *= 0.98;
391 moveEntity(item);
393 if ((item->health >= 60) || ((engine.getFrameLoop() % 3) == 0))
395 graphics.blit(item->getFaceImage(), x, y, graphics.screen, false);
398 item->animate();
400 if ((player.health > 0) && (!(player.flags & ENT_TELEPORTING)))
402 if (Collision::collision(&player, item))
404 if (item->flags & ENT_COLLECTABLE)
406 pickUpItem(item);
412 if ((item->health <= 0) && (item->owner != &player))
414 map.itemList.remove(previous, item);
415 item = previous;
420 void loadDefItems()
422 if (!engine.loadData("data/defItems"))
423 graphics.showErrorAndExit(_("Couldn't load item definitions file (%s)"), "data/defItems");
425 char *token = strtok((char*)engine.dataBuffer, "\n");
427 int id;
428 char name[50];
429 char sprite[100];
430 int value;
432 while (true)
434 if (strcmp(token, "@EOF@") == 0)
435 break;
437 sscanf(token, "%d %*c %[^\"] %*c %s %d", &id, name, sprite, &value);
439 defItem[id].id = id;
440 defItem[id].setName(name);
441 defItem[id].setSprites(graphics.getSprite(sprite, true), graphics.getSprite(sprite, true), graphics.getSprite(sprite, true));
442 defItem[id].value = value;
444 token = strtok(NULL, "\n");