1 /*-------------------------------------------------------------------------------
2
3 BARONY
4 File: item_usage_funcs.cpp
5 Desc: implements the functions that handle item usage (eg handle
6 potion effects, zap a staff, whatever else you can think of).
7
8 Copyright 2013-2016 (c) Turning Wheel LLC, all rights reserved.
9 See LICENSE for details.
10
11 -------------------------------------------------------------------------------*/
12
13 #include "main.hpp"
14 #include "game.hpp"
15 #include "stat.hpp"
16 #include "items.hpp"
17 #include "sound.hpp"
18 #include "entity.hpp"
19 #include "magic/magic.hpp"
20 #include "interface/interface.hpp"
21 #include "scores.hpp"
22 #include "net.hpp"
23 #include "monster.hpp"
24 #include "player.hpp"
25 #include "collision.hpp"
26 #include "scores.hpp"
27
item_PotionWater(Item * & item,Entity * entity,Entity * usedBy)28 bool item_PotionWater(Item*& item, Entity* entity, Entity* usedBy)
29 {
30 if ( !entity )
31 {
32 return false;
33 }
34
35 int skillLVL = 0;
36 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
37 {
38 Stat* usedByStats = usedBy->getStats();
39 if ( usedByStats )
40 {
41 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
42 }
43 }
44
45 node_t* node;
46 int player = -1;
47 Stat* stats;
48
49 if ( entity->behavior == &actPlayer )
50 {
51 player = entity->skill[2];
52 }
53 stats = entity->getStats();
54 if ( !stats )
55 {
56 return false;
57 }
58
59 if ( stats->amulet != NULL )
60 {
61 if ( stats->amulet->type == AMULET_STRANGULATION )
62 {
63 if ( player == clientnum )
64 {
65 messagePlayer(player, language[750]);
66 }
67 return false;
68 }
69 }
70 if ( stats->EFFECTS[EFF_VOMITING] )
71 {
72 if ( player == clientnum )
73 {
74 messagePlayer(player, language[751]);
75 }
76 return false;
77 }
78
79 if ( multiplayer != CLIENT ) // server/singleplayer
80 {
81 // play drink sound
82 if ( item->beatitude > 0 )
83 {
84 if ( stats->type == GHOUL ||
85 stats->type == LICH ||
86 stats->type == LICH_FIRE ||
87 stats->type == LICH_ICE ||
88 stats->type == SHADOW ||
89 stats->type == SKELETON ||
90 stats->type == VAMPIRE )
91 {
92 //Blessed water damages undead.
93 int damage = -(20 * item->beatitude);
94 entity->modHP(damage);
95 playSoundEntity(entity, 28, 64);
96 playSoundEntity(entity, 249, 128);
97 entity->setObituary(language[1533]);
98 }
99 else
100 {
101 if ( stats->type != AUTOMATON )
102 {
103 entity->modHP(5 * item->beatitude);
104 playSoundEntity(entity, 168, 128);
105 spawnMagicEffectParticles(entity->x, entity->y, entity->z, 169);
106 }
107 playSoundEntity(entity, 52, 64);
108 }
109 }
110 else
111 {
112 if ( stats->type == VAMPIRE )
113 {
114 entity->modHP(-5);
115 playSoundEntity(entity, 28, 64);
116 playSoundEntity(entity, 249, 128);
117 entity->setObituary(language[1533]);
118 }
119 else
120 {
121 playSoundEntity(entity, 52, 64);
122 }
123 }
124 if ( player >= 0 && player < MAXPLAYERS )
125 {
126 if ( stats && stats->EFFECTS[EFF_POLYMORPH] )
127 {
128 if ( stats->EFFECTS[EFF_POLYMORPH] )
129 {
130 entity->setEffect(EFF_POLYMORPH, false, 0, true);
131 entity->effectPolymorph = 0;
132 serverUpdateEntitySkill(entity, 50);
133
134 messagePlayer(player, language[3192]);
135 messagePlayer(player, language[3185]);
136 }
137 /*if ( stats->EFFECTS[EFF_SHAPESHIFT] )
138 {
139 entity->setEffect(EFF_SHAPESHIFT, false, 0, true);
140 entity->effectShapeshift = 0;
141 serverUpdateEntitySkill(entity, 53);
142
143 messagePlayer(player, language[3418]);
144 messagePlayer(player, language[3417]);
145 }*/
146 playSoundEntity(entity, 400, 92);
147 createParticleDropRising(entity, 593, 1.f);
148 serverSpawnMiscParticles(entity, PARTICLE_EFFECT_RISING_DROP, 593);
149 }
150 if ( stats->type == AUTOMATON )
151 {
152 Uint32 color = SDL_MapRGB(mainsurface->format, 255, 128, 0);
153 messagePlayerColor(player, color, language[3700]);
154 stats->HUNGER -= 200; //Lose boiler
155 int mpAmount = 3 + rand() % 6;
156 if ( item->beatitude > 0 )
157 {
158 mpAmount += 2 + rand() % 4;
159 }
160 players[player]->entity->modMP(mpAmount); //Raise temperature because steam.
161 serverUpdateHunger(player);
162 }
163 }
164 if ( player != clientnum )
165 {
166 consumeItem(item, player);
167 return true;
168 }
169 }
170
171 auto& camera_shakex = cameravars[player >= 0 ? player : 0].shakex;
172 auto& camera_shakey = cameravars[player >= 0 ? player : 0].shakey;
173
174 // code below is only run by the player that drank the potion.
175 // if it was thrown, then the function returns in the above code as processed by the server.
176
177 if ( item->beatitude == 0 )
178 {
179 if ( stats->type == VAMPIRE )
180 {
181 Uint32 color = SDL_MapRGB(mainsurface->format, 255, 0, 0);
182 messagePlayerColor(player, color, language[3183]);
183 camera_shakex += .1;
184 camera_shakey += 10;
185 }
186 else if ( stats->type != AUTOMATON )
187 {
188 messagePlayer(player, language[752]);
189 }
190 }
191 else if ( item->beatitude > 0 )
192 {
193 if ( stats->type == SKELETON )
194 {
195 Uint32 color = SDL_MapRGB(mainsurface->format, 255, 0, 0);
196 messagePlayerColor(player, color, language[3184]);
197 camera_shakex += .1;
198 camera_shakey += 10;
199 }
200 else if ( stats->type == GHOUL ||
201 stats->type == LICH ||
202 stats->type == LICH_FIRE ||
203 stats->type == LICH_ICE ||
204 stats->type == SHADOW ||
205 stats->type == VAMPIRE )
206 {
207 Uint32 color = SDL_MapRGB(mainsurface->format, 255, 0, 0);
208 messagePlayerColor(player, color, language[3183]);
209 camera_shakex += .1;
210 camera_shakey += 10;
211 }
212 else if ( stats->type != AUTOMATON )
213 {
214 messagePlayer(player, language[753]);
215 }
216 }
217 else if ( item->beatitude < 0 )
218 {
219 if ( stats->type == VAMPIRE )
220 {
221 Uint32 color = SDL_MapRGB(mainsurface->format, 255, 0, 0);
222 messagePlayerColor(player, color, language[3183]);
223 camera_shakex += .1;
224 camera_shakey += 10;
225 }
226 messagePlayer(player, language[755]);
227
228 // choose a random piece of worn equipment to curse!
229 int tryIndex = rand() % 8;
230 int startIndex = tryIndex;
231 int armornum = 0;
232 bool breakloop = false;
233 Item* toCurse = nullptr;
234 // curse random item.
235 while ( !toCurse && !breakloop )
236 {
237 switch ( tryIndex )
238 {
239 // intentional fall throughs...
240 case 0:
241 if ( stats->weapon != nullptr && itemCategory(stats->weapon) != POTION
242 && stats->weapon->beatitude >= 0 )
243 {
244 toCurse = stats->weapon;
245 armornum = 0;
246 break;
247 }
248 case 1:
249 if ( stats->helmet != nullptr && stats->helmet->beatitude >= 0 )
250 {
251 toCurse = stats->helmet;
252 armornum = 1;
253 break;
254 }
255 case 2:
256 if ( stats->breastplate != nullptr && stats->breastplate->beatitude >= 0 )
257 {
258 toCurse = stats->breastplate;
259 armornum = 2;
260 break;
261 }
262 case 3:
263 if ( stats->gloves != nullptr && stats->gloves->beatitude >= 0 )
264 {
265 toCurse = stats->gloves;
266 armornum = 3;
267 break;
268 }
269 case 4:
270 if ( stats->shoes != nullptr && stats->shoes->beatitude >= 0 )
271 {
272 toCurse = stats->shoes;
273 armornum = 4;
274 break;
275 }
276 case 5:
277 if ( stats->shield != nullptr && stats->shield->beatitude >= 0 )
278 {
279 toCurse = stats->shield;
280 armornum = 5;
281 break;
282 }
283 case 6:
284 if ( stats->cloak != nullptr && stats->cloak->beatitude >= 0 )
285 {
286 toCurse = stats->cloak;
287 armornum = 6;
288 break;
289 }
290 case 7:
291 if ( stats->mask != nullptr && stats->mask->beatitude >= 0 )
292 {
293 toCurse = stats->mask;
294 armornum = 7;
295 break;
296 }
297 ++tryIndex;
298 if ( tryIndex > 7 )
299 {
300 // loop back around.
301 tryIndex = 0;
302 }
303 if ( tryIndex == startIndex )
304 {
305 // couldn't find a piece of armor, break.
306 breakloop = true;
307 toCurse = nullptr;
308 break;
309 }
310 default:
311 break;
312 }
313 }
314
315 if ( toCurse )
316 {
317 if ( toCurse->beatitude <= 0 )
318 {
319 --toCurse->beatitude;
320 }
321 else
322 {
323 toCurse->beatitude = -toCurse->beatitude;
324 if ( itemCategory(toCurse) == WEAPON && stats->type == SUCCUBUS )
325 {
326 steamAchievement("BARONY_ACH_THE_WAY_YOU_LIKE_IT");
327 }
328 }
329 messagePlayer(player, language[858], toCurse->getName());
330 if ( multiplayer == CLIENT )
331 {
332 strcpy((char*)net_packet->data, "BEAT");
333 net_packet->data[4] = clientnum;
334 net_packet->data[5] = armornum;
335 net_packet->data[6] = toCurse->beatitude + 100;
336 net_packet->address.host = net_server.host;
337 net_packet->address.port = net_server.port;
338 net_packet->len = 7;
339 sendPacketSafe(net_sock, -1, net_packet, 0);
340 //messagePlayer(clientnum, "sent server: %d, %d, %d", net_packet->data[4], net_packet->data[5], net_packet->data[6]);
341 }
342 consumeItem(item, player);
343 return true;
344 }
345
346 // else randomly curse an item in the entity's inventory, item must be +0 or higher.
347 int items = 0;
348 for ( node = stats->inventory.first; node != NULL; node = node->next )
349 {
350 Item* target = (Item*)node->element;
351 if ( target && !itemIsEquipped(target, player) && itemCategory(target) != SPELL_CAT && target->beatitude >= 0 )
352 {
353 items++;
354 }
355 }
356 if ( items == 0 )
357 {
358 consumeItem(item, player);
359 return true;
360 }
361 int itemToCurse = rand() % items;
362 items = 0;
363 for ( node = stats->inventory.first; node != NULL; node = node->next )
364 {
365 Item* target = (Item*)node->element;
366 if ( target && !itemIsEquipped(target, player) && itemCategory(target) != SPELL_CAT && target->beatitude >= 0 )
367 {
368 if ( items == itemToCurse )
369 {
370 messagePlayer(player, language[858], target->getName());
371 if ( target->beatitude <= 0 )
372 {
373 --target->beatitude;
374 }
375 else
376 {
377 target->beatitude = -target->beatitude;
378 if ( itemCategory(target) == WEAPON && stats->type == SUCCUBUS )
379 {
380 steamAchievement("BARONY_ACH_THE_WAY_YOU_LIKE_IT");
381 }
382 }
383 break;
384 }
385 items++;
386 }
387 }
388 }
389 consumeItem(item, player);
390 return true;
391 }
392
item_PotionBooze(Item * & item,Entity * entity,Entity * usedBy,bool shouldConsumeItem)393 bool item_PotionBooze(Item*& item, Entity* entity, Entity* usedBy, bool shouldConsumeItem)
394 {
395 if (!entity)
396 {
397 return false;
398 }
399
400 int skillLVL = 0;
401 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
402 {
403 Stat* usedByStats = usedBy->getStats();
404 if ( usedByStats )
405 {
406 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
407 }
408 }
409
410 int player = -1;
411 Stat* stats;
412
413 if ( entity->behavior == &actPlayer )
414 {
415 player = entity->skill[2];
416 }
417 stats = entity->getStats();
418 if ( !stats )
419 {
420 return false;
421 }
422
423 if ( stats->amulet != nullptr )
424 {
425 if ( stats->amulet->type == AMULET_STRANGULATION )
426 {
427 if ( player == clientnum )
428 {
429 messagePlayer(player, language[750]);
430 }
431 return false;
432 }
433 }
434 if ( stats->EFFECTS[EFF_VOMITING] )
435 {
436 if ( player == clientnum )
437 {
438 messagePlayer(player, language[751]);
439 }
440 return false;
441 }
442 if ( multiplayer == CLIENT )
443 {
444 consumeItem(item, player);
445 return true;
446 }
447
448 messagePlayer(player, language[758]);
449 messagePlayer(player, language[759]);
450 stats->EFFECTS[EFF_DRUNK] = true;
451 if ( player >= 0 )
452 {
453 stats->EFFECTS_TIMERS[EFF_DRUNK] = 2400 + rand() % 1200;
454 if ( stats->type != GOATMAN )
455 {
456 stats->EFFECTS_TIMERS[EFF_DRUNK] = std::max(300, stats->EFFECTS_TIMERS[EFF_DRUNK] - (entity->getPER() + entity->getCON()) * 40);
457 }
458 if ( stats->EFFECTS[EFF_WITHDRAWAL] )
459 {
460 int hangoverReliefDuration = EFFECT_WITHDRAWAL_BASE_TIME; // 8 minutes
461 switch ( rand() % 3 )
462 {
463 case 0:
464 hangoverReliefDuration += (TICKS_PER_SECOND * 60 * 8); // 8 + 8 minutes
465 break;
466 case 1:
467 hangoverReliefDuration += (TICKS_PER_SECOND * 60 * 4); // 8 + 4 minutes
468 break;
469 case 2:
470 // intentional fall through
471 default:
472 break;
473 }
474 entity->setEffect(EFF_WITHDRAWAL, false, hangoverReliefDuration, true);
475 serverUpdatePlayerGameplayStats(player, STATISTICS_FUNCTIONAL, 1);
476 messagePlayerColor(player, SDL_MapRGB(mainsurface->format, 0, 255, 0), language[3250]);
477 }
478 else if ( stats->EFFECTS_TIMERS[EFF_WITHDRAWAL] > 0 && stats->EFFECTS_TIMERS[EFF_WITHDRAWAL] < EFFECT_WITHDRAWAL_BASE_TIME )
479 {
480 stats->EFFECTS_TIMERS[EFF_WITHDRAWAL] = EFFECT_WITHDRAWAL_BASE_TIME;
481 }
482 }
483 else
484 {
485 stats->EFFECTS_TIMERS[EFF_DRUNK] = 2400 + rand() % 1200;
486 }
487
488 if ( svFlags & SV_FLAG_HUNGER )
489 {
490 if ( entity->behavior == &actPlayer )
491 {
492 if ( stats->type != SKELETON && stats->type != AUTOMATON )
493 {
494 if ( stats->HUNGER < 1500 )
495 {
496 stats->HUNGER = std::min(1499, stats->HUNGER + 100);
497 }
498 }
499 if ( stats->playerRace == RACE_INSECTOID && stats->appearance == 0 )
500 {
501 stats->HUNGER += 250;
502 }
503 }
504 }
505 else
506 {
507 // hunger off.
508 if ( entity->behavior == &actPlayer && stats->playerRace == RACE_INSECTOID && stats->appearance == 0 )
509 {
510 entity->modMP(5 * (1 + item->beatitude));
511 }
512 }
513 entity->modHP(5 * (1 + item->beatitude));
514 // results of eating
515 updateHungerMessages(entity, stats, item);
516 serverUpdateEffects(player);
517
518 // play drink sound
519 playSoundEntity(entity, 52, 64);
520 playSoundEntity(entity, 168, 128);
521 spawnMagicEffectParticles(entity->x, entity->y, entity->z, 169);
522 if ( shouldConsumeItem )
523 {
524 consumeItem(item, player);
525 return true;
526 }
527 return false;
528 }
529
item_PotionJuice(Item * & item,Entity * entity,Entity * usedBy)530 bool item_PotionJuice(Item*& item, Entity* entity, Entity* usedBy)
531 {
532 if (!entity)
533 {
534 return false;
535 }
536
537 int skillLVL = 0;
538 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
539 {
540 Stat* usedByStats = usedBy->getStats();
541 if ( usedByStats )
542 {
543 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
544 }
545 }
546
547 int player = -1;
548 Stat* stats;
549
550 if ( entity->behavior == &actPlayer )
551 {
552 player = entity->skill[2];
553 }
554 stats = entity->getStats();
555 if ( !stats )
556 {
557 return false;
558 }
559
560 if ( stats->amulet != NULL )
561 {
562 if ( stats->amulet->type == AMULET_STRANGULATION )
563 {
564 if ( player == clientnum )
565 {
566 messagePlayer(player, language[750]);
567 }
568 return false;
569 }
570 }
571 if ( stats->EFFECTS[EFF_VOMITING] )
572 {
573 if ( player == clientnum )
574 {
575 messagePlayer(player, language[751]);
576 }
577 return false;
578 }
579 if ( multiplayer == CLIENT )
580 {
581 consumeItem(item, player);
582 return true;
583 }
584
585 if ( item->beatitude < 0 )
586 {
587 //Cursed effect inebriates you.
588 messagePlayer(player, language[2900]);
589 messagePlayer(player, language[758]);
590 messagePlayer(player, language[759]);
591 stats->EFFECTS[EFF_DRUNK] = true;
592 if ( player >= 0 )
593 {
594 stats->EFFECTS_TIMERS[EFF_DRUNK] = 2400 + rand() % 1200;
595 if ( stats->type != GOATMAN )
596 {
597 stats->EFFECTS_TIMERS[EFF_DRUNK] = std::max(300, stats->EFFECTS_TIMERS[EFF_DRUNK] - (entity->getPER() + entity->getCON()) * 40);
598 }
599 if ( stats->EFFECTS[EFF_WITHDRAWAL] )
600 {
601 int hangoverReliefDuration = EFFECT_WITHDRAWAL_BASE_TIME; // 8 minutes
602 switch ( rand() % 3 )
603 {
604 case 0:
605 hangoverReliefDuration += (TICKS_PER_SECOND * 60 * 8); // 8 + 8 minutes
606 break;
607 case 1:
608 hangoverReliefDuration += (TICKS_PER_SECOND * 60 * 4); // 8 + 4 minutes
609 break;
610 case 2:
611 // intentional fall through
612 default:
613 break;
614 }
615 entity->setEffect(EFF_WITHDRAWAL, false, hangoverReliefDuration, true);
616 serverUpdatePlayerGameplayStats(player, STATISTICS_FUNCTIONAL, 1);
617 messagePlayerColor(player, SDL_MapRGB(mainsurface->format, 0, 255, 0), language[3250]);
618 }
619 else if ( stats->EFFECTS_TIMERS[EFF_WITHDRAWAL] > 0 && stats->EFFECTS_TIMERS[EFF_WITHDRAWAL] < EFFECT_WITHDRAWAL_BASE_TIME )
620 {
621 stats->EFFECTS_TIMERS[EFF_WITHDRAWAL] = EFFECT_WITHDRAWAL_BASE_TIME;
622 }
623 }
624 else
625 {
626 stats->EFFECTS_TIMERS[EFF_DRUNK] = 1000 + rand() % 300;
627 }
628 entity->modHP(5);
629
630 if ( svFlags & SV_FLAG_HUNGER )
631 {
632 if ( entity->behavior == &actPlayer )
633 {
634 if ( stats->type != SKELETON && stats->type != AUTOMATON )
635 {
636 if ( stats->HUNGER < 1500 )
637 {
638 stats->HUNGER = std::min(1499, stats->HUNGER + 50);
639 }
640 }
641 if ( stats->playerRace == RACE_INSECTOID && stats->appearance == 0 )
642 {
643 stats->HUNGER += 200;
644 }
645 }
646 }
647 else
648 {
649 // hunger off.
650 if ( entity->behavior == &actPlayer && stats->playerRace == RACE_INSECTOID && stats->appearance == 0 )
651 {
652 entity->modMP(5);
653 }
654 }
655
656 serverUpdateEffects(player);
657 }
658 else
659 {
660 messagePlayer(player, language[760]);
661 entity->modHP(5 * (1 + item->beatitude));
662
663 if ( svFlags & SV_FLAG_HUNGER )
664 {
665 if ( entity->behavior == &actPlayer )
666 {
667 if ( stats->type != SKELETON && stats->type != AUTOMATON )
668 {
669 if ( stats->HUNGER < 1500 )
670 {
671 stats->HUNGER = std::min(1499, stats->HUNGER + 50);
672 }
673 }
674 if ( stats->playerRace == RACE_INSECTOID && stats->appearance == 0 )
675 {
676 stats->HUNGER += 200;
677 }
678 }
679 }
680 else
681 {
682 // hunger off.
683 if ( entity->behavior == &actPlayer && stats->playerRace == RACE_INSECTOID && stats->appearance == 0 )
684 {
685 entity->modMP(5 * (1 + item->beatitude));
686 }
687 }
688 }
689
690 // results of eating
691 updateHungerMessages(entity, stats, item);
692
693 // play drink sound
694 playSoundEntity(entity, 52, 64);
695 playSoundEntity(entity, 168, 128);
696 spawnMagicEffectParticles(entity->x, entity->y, entity->z, 169);
697 consumeItem(item, player);
698 return true;
699 }
700
item_PotionSickness(Item * & item,Entity * entity,Entity * usedBy)701 bool item_PotionSickness(Item*& item, Entity* entity, Entity* usedBy)
702 {
703 if (!entity)
704 {
705 return false;
706 }
707
708 int skillLVL = 0;
709 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
710 {
711 Stat* usedByStats = usedBy->getStats();
712 if ( usedByStats )
713 {
714 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
715 }
716 }
717
718 int player = -1;
719 Stat* stats;
720
721 if ( entity->behavior == &actPlayer )
722 {
723 player = entity->skill[2];
724 }
725 stats = entity->getStats();
726 if ( !stats )
727 {
728 return false;
729 }
730
731 auto& camera_shakex = cameravars[player >= 0 ? player : 0].shakex;
732 auto& camera_shakey = cameravars[player >= 0 ? player : 0].shakey;
733
734 if ( entity == NULL )
735 {
736 return false;
737 }
738 if ( stats->amulet != NULL )
739 {
740 if ( stats->amulet->type == AMULET_STRANGULATION )
741 {
742 if ( player == clientnum )
743 {
744 messagePlayer(player, language[750]);
745 }
746 return false;
747 }
748 }
749 if ( stats->EFFECTS[EFF_VOMITING] )
750 {
751 if ( player == clientnum )
752 {
753 messagePlayer(player, language[751]);
754 }
755 return false;
756 }
757 if ( multiplayer == CLIENT || player == 0 )
758 {
759 camera_shakex += .1;
760 camera_shakey += 10;
761 if ( multiplayer == CLIENT )
762 {
763 consumeItem(item, player);
764 return true;
765 }
766 }
767
768 int damage = (5 + 5 * abs(item->beatitude)) * potionDamageSkillMultipliers[std::min(skillLVL, 5)];
769 int chance = damage / 8;
770 if ( player >= 0 && usedBy == entity )
771 {
772 damage /= 2;
773 }
774 else
775 {
776 damage -= (rand() % (1 + chance));
777 }
778 messagePlayer(player, language[761]);
779 entity->modHP(-damage);
780 stats->EFFECTS[EFF_POISONED] = true;
781 if ( stats->type == LICH || stats->type == SHOPKEEPER || stats->type == DEVIL
782 || stats->type == MINOTAUR || stats->type == LICH_FIRE || stats->type == LICH_ICE )
783 {
784 stats->EFFECTS_TIMERS[EFF_POISONED] = TICKS_PER_SECOND * 15;
785 }
786 playSoundEntity(entity, 28, 64);
787 serverUpdateEffects(player);
788
789 // set obituary
790 entity->setObituary(language[1535]);
791
792 // play drink sound
793 playSoundEntity(entity, 52, 64);
794 consumeItem(item, player);
795 return true;
796 }
797
item_PotionConfusion(Item * & item,Entity * entity,Entity * usedBy)798 bool item_PotionConfusion(Item*& item, Entity* entity, Entity* usedBy)
799 {
800 if (!entity)
801 {
802 return false;
803 }
804
805 int skillLVL = 0;
806 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
807 {
808 Stat* usedByStats = usedBy->getStats();
809 if ( usedByStats )
810 {
811 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
812 }
813 }
814
815 int player = -1;
816 Stat* stats;
817
818 if ( entity->behavior == &actPlayer )
819 {
820 player = entity->skill[2];
821 }
822 stats = entity->getStats();
823 if ( !stats )
824 {
825 return false;
826 }
827
828 if ( stats->amulet != NULL )
829 {
830 if ( stats->amulet->type == AMULET_STRANGULATION )
831 {
832 if ( player == clientnum )
833 {
834 messagePlayer(player, language[750]);
835 }
836 return false;
837 }
838 }
839 if ( stats->EFFECTS[EFF_VOMITING] )
840 {
841 if ( player == clientnum )
842 {
843 messagePlayer(player, language[751]);
844 }
845 return false;
846 }
847 if ( multiplayer == CLIENT )
848 {
849 consumeItem(item, player);
850 return true;
851 }
852
853 messagePlayer(player, language[762]);
854 stats->EFFECTS[EFF_CONFUSED] = true;
855 if ( player >= 0 )
856 {
857 stats->EFFECTS_TIMERS[EFF_CONFUSED] = std::max(300, 1800 - (entity->getPER() + entity->getCON()) * 20);
858 }
859 else
860 {
861 stats->EFFECTS_TIMERS[EFF_CONFUSED] = 1800;
862 }
863 if ( entity->behavior == &actMonster )
864 {
865 entity->monsterTarget = 0; // monsters forget what they're doing
866 }
867 serverUpdateEffects(player);
868
869 // play drink sound
870 playSoundEntity(entity, 52, 64);
871 consumeItem(item, player);
872 return true;
873 }
874
item_PotionCureAilment(Item * & item,Entity * entity,Entity * usedBy)875 bool item_PotionCureAilment(Item*& item, Entity* entity, Entity* usedBy)
876 {
877 if (!entity)
878 {
879 return false;
880 }
881
882 int skillLVL = 0;
883 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
884 {
885 Stat* usedByStats = usedBy->getStats();
886 if ( usedByStats )
887 {
888 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
889 }
890 }
891
892 int player = -1;
893 Stat* stats;
894 int c;
895
896 if ( entity->behavior == &actPlayer )
897 {
898 player = entity->skill[2];
899 }
900 stats = entity->getStats();
901 if ( !stats )
902 {
903 return false;
904 }
905
906 if ( stats->amulet != NULL )
907 {
908 if ( stats->amulet->type == AMULET_STRANGULATION )
909 {
910 if ( player == clientnum )
911 {
912 messagePlayer(player, language[750]);
913 }
914 return false;
915 }
916 }
917 if ( stats->EFFECTS[EFF_VOMITING] )
918 {
919 if ( player == clientnum )
920 {
921 messagePlayer(player, language[751]);
922 }
923 return false;
924 }
925 if ( entity->flags[BURNING] )
926 {
927 entity->flags[BURNING] = false;
928 serverUpdateEntityFlag(entity, BURNING);
929 }
930 if ( multiplayer == CLIENT )
931 {
932 consumeItem(item, player);
933 return true;
934 }
935
936 if ( item->beatitude < 0 )
937 {
938 messagePlayer(player, language[2900]);
939 }
940
941 Uint32 color = SDL_MapRGB(mainsurface->format, 0, 255, 0);
942 messagePlayerColor(player, color, language[763]);
943 for ( c = 0; c < NUMEFFECTS; c++ ) //This does a whole lot more than just cure ailments.
944 {
945 if ( !(c == EFF_VAMPIRICAURA && stats->EFFECTS_TIMERS[c] == -2)
946 && c != EFF_WITHDRAWAL && c != EFF_SHAPESHIFT )
947 {
948 stats->EFFECTS[c] = false;
949 stats->EFFECTS_TIMERS[c] = 0;
950 }
951 }
952
953 if ( stats->EFFECTS[EFF_WITHDRAWAL] )
954 {
955 entity->setEffect(EFF_WITHDRAWAL, false, EFFECT_WITHDRAWAL_BASE_TIME, true);
956 serverUpdatePlayerGameplayStats(player, STATISTICS_FUNCTIONAL, 1);
957 }
958
959 if ( item->beatitude < 0 )
960 {
961 messagePlayer(player, language[2903]);
962 stats->EFFECTS[EFF_POISONED] = true;
963 stats->EFFECTS_TIMERS[EFF_POISONED] = std::max(200, 300 - entity->getCON() * 20);
964 }
965 else if ( item->beatitude > 0 )
966 {
967 stats->EFFECTS[EFF_HP_REGEN] = true;
968 stats->EFFECTS[EFF_MP_REGEN] = true;
969 stats->EFFECTS_TIMERS[EFF_HP_REGEN] = 4 * item->beatitude * TICKS_PER_SECOND;
970 stats->EFFECTS_TIMERS[EFF_MP_REGEN] = 4 * item->beatitude * TICKS_PER_SECOND;
971 }
972
973 serverUpdateEffects(player);
974
975 // play drink sound
976 playSoundEntity(entity, 52, 64);
977 consumeItem(item, player);
978 return true;
979 }
980
item_PotionBlindness(Item * & item,Entity * entity,Entity * usedBy)981 bool item_PotionBlindness(Item*& item, Entity* entity, Entity* usedBy)
982 {
983 if (!entity)
984 {
985 return false;
986 }
987
988 int skillLVL = 0;
989 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
990 {
991 Stat* usedByStats = usedBy->getStats();
992 if ( usedByStats )
993 {
994 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
995 }
996 }
997
998 int player = -1;
999 Stat* stats;
1000
1001 if ( entity->behavior == &actPlayer )
1002 {
1003 player = entity->skill[2];
1004 }
1005 stats = entity->getStats();
1006 if ( !stats )
1007 {
1008 return false;
1009 }
1010
1011 if ( stats->amulet != NULL )
1012 {
1013 if ( stats->amulet->type == AMULET_STRANGULATION )
1014 {
1015 if ( player == clientnum )
1016 {
1017 messagePlayer(player, language[750]);
1018 }
1019 return false;
1020 }
1021 }
1022 if ( stats->EFFECTS[EFF_VOMITING] )
1023 {
1024 if ( player == clientnum )
1025 {
1026 messagePlayer(player, language[751]);
1027 }
1028 return false;
1029 }
1030 if ( multiplayer == CLIENT )
1031 {
1032 consumeItem(item, player);
1033 return true;
1034 }
1035
1036 if ( entity->behavior == &actMonster && !entity->isBossMonster() )
1037 {
1038 entity->monsterReleaseAttackTarget();
1039 }
1040 messagePlayer(player, language[765]);
1041 stats->EFFECTS[EFF_BLIND] = true;
1042 if ( player >= 0 )
1043 {
1044 stats->EFFECTS_TIMERS[EFF_BLIND] = 660 + rand() % 480;
1045 stats->EFFECTS_TIMERS[EFF_BLIND] = std::max(300, stats->EFFECTS_TIMERS[EFF_BLIND] - (entity->getPER() + entity->getCON()) * 5);
1046 }
1047 else
1048 {
1049 entity->setEffect(EFF_BLIND, true, 660 + rand() % 240, true);
1050 }
1051 serverUpdateEffects(player);
1052
1053 // play drink sound
1054 playSoundEntity(entity, 52, 64);
1055 consumeItem(item, player);
1056 return true;
1057 }
1058
item_PotionInvisibility(Item * & item,Entity * entity,Entity * usedBy)1059 bool item_PotionInvisibility(Item*& item, Entity* entity, Entity* usedBy)
1060 {
1061 if (!entity)
1062 {
1063 return false;
1064 }
1065
1066 int skillLVL = 0;
1067 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1068 {
1069 Stat* usedByStats = usedBy->getStats();
1070 if ( usedByStats )
1071 {
1072 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1073 }
1074 }
1075
1076 int player = -1;
1077 Stat* stats;
1078
1079 if ( entity->behavior == &actPlayer )
1080 {
1081 player = entity->skill[2];
1082 }
1083 stats = entity->getStats();
1084 if ( !stats )
1085 {
1086 return false;
1087 }
1088
1089 if ( stats->amulet != NULL )
1090 {
1091 if ( stats->amulet->type == AMULET_STRANGULATION )
1092 {
1093 if ( player == clientnum )
1094 {
1095 messagePlayer(player, language[750]);
1096 }
1097 return false;
1098 }
1099 }
1100 if ( stats->EFFECTS[EFF_VOMITING] )
1101 {
1102 if ( player == clientnum )
1103 {
1104 messagePlayer(player, language[751]);
1105 }
1106 return false;
1107 }
1108 if ( multiplayer == CLIENT )
1109 {
1110 consumeItem(item, player);
1111 return true;
1112 }
1113
1114 messagePlayer(player, language[766]);
1115
1116 if ( !entity->isInvisible() )
1117 {
1118 for ( node_t* node = map.creatures->first; node != nullptr; node = node->next )
1119 {
1120 Entity* creature = (Entity*)node->element;
1121 if ( creature && creature->behavior == &actMonster && creature->monsterTarget == entity->getUID() )
1122 {
1123 if ( !creature->isBossMonster() )
1124 {
1125 //Abort if invalid creature (boss, shopkeep, etc).
1126 real_t dist = entityDist(entity, creature);
1127 if ( dist > STRIKERANGE * 3 )
1128 {
1129 // lose track of invis target.
1130 creature->monsterReleaseAttackTarget();
1131 }
1132 }
1133 }
1134 }
1135 }
1136 stats->EFFECTS[EFF_INVISIBLE] = true;
1137 stats->EFFECTS_TIMERS[EFF_INVISIBLE] = 1800 + rand() % 1800;
1138 if ( item->beatitude > 0 )
1139 {
1140 stats->EFFECTS_TIMERS[EFF_INVISIBLE] += item->beatitude * 600;
1141 }
1142 serverUpdateEffects(player);
1143
1144 // play drink sound
1145 playSoundEntity(entity, 52, 64);
1146 consumeItem(item, player);
1147 return true;
1148 }
1149
item_PotionLevitation(Item * & item,Entity * entity,Entity * usedBy)1150 bool item_PotionLevitation(Item*& item, Entity* entity, Entity* usedBy)
1151 {
1152 if (!entity)
1153 {
1154 return false;
1155 }
1156
1157 int skillLVL = 0;
1158 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1159 {
1160 Stat* usedByStats = usedBy->getStats();
1161 if ( usedByStats )
1162 {
1163 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1164 }
1165 }
1166
1167 int player = -1;
1168 Stat* stats;
1169
1170 if ( entity->behavior == &actPlayer )
1171 {
1172 player = entity->skill[2];
1173 }
1174 stats = entity->getStats();
1175 if ( !stats )
1176 {
1177 return false;
1178 }
1179
1180 if ( stats->amulet != NULL )
1181 {
1182 if ( stats->amulet->type == AMULET_STRANGULATION )
1183 {
1184 if ( player == clientnum )
1185 {
1186 messagePlayer(player, language[750]);
1187 }
1188 return false;
1189 }
1190 }
1191 if ( stats->EFFECTS[EFF_VOMITING] )
1192 {
1193 if ( player == clientnum )
1194 {
1195 messagePlayer(player, language[751]);
1196 }
1197 return false;
1198 }
1199 if ( multiplayer == CLIENT )
1200 {
1201 consumeItem(item, player);
1202 return true;
1203 }
1204
1205 if ( item->beatitude < 0 )
1206 {
1207 //Cursed effect slows you.
1208 messagePlayer(player, language[2900]);
1209 messagePlayer(player, language[2901]);
1210 stats->EFFECTS[EFF_SLOW] = true;
1211 stats->EFFECTS_TIMERS[EFF_SLOW] = 1800;
1212 }
1213 else
1214 {
1215 messagePlayer(player, language[767]);
1216 stats->EFFECTS[EFF_LEVITATING] = true;
1217 stats->EFFECTS_TIMERS[EFF_LEVITATING] = 1800 + item->beatitude * 600;
1218 }
1219 serverUpdateEffects(player);
1220
1221 // play drink sound
1222 playSoundEntity(entity, 52, 64);
1223 consumeItem(item, player);
1224 return true;
1225 }
1226
item_PotionSpeed(Item * & item,Entity * entity,Entity * usedBy)1227 bool item_PotionSpeed(Item*& item, Entity* entity, Entity* usedBy)
1228 {
1229 if (!entity)
1230 {
1231 return false;
1232 }
1233
1234 int skillLVL = 0;
1235 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1236 {
1237 Stat* usedByStats = usedBy->getStats();
1238 if ( usedByStats )
1239 {
1240 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1241 }
1242 }
1243
1244 int player = -1;
1245 Stat* stats;
1246
1247 if ( entity->behavior == &actPlayer )
1248 {
1249 player = entity->skill[2];
1250 }
1251 stats = entity->getStats();
1252 if ( !stats )
1253 {
1254 return false;
1255 }
1256
1257 if ( stats->amulet != NULL )
1258 {
1259 if ( stats->amulet->type == AMULET_STRANGULATION )
1260 {
1261 if ( player == clientnum )
1262 {
1263 messagePlayer(player, language[750]);
1264 }
1265 return false;
1266 }
1267 }
1268 if ( stats->EFFECTS[EFF_VOMITING] )
1269 {
1270 if ( player == clientnum )
1271 {
1272 messagePlayer(player, language[751]);
1273 }
1274 return false;
1275 }
1276 if ( multiplayer == CLIENT )
1277 {
1278 consumeItem(item, player);
1279 return true;
1280 }
1281
1282
1283 if ( item->beatitude < 0 )
1284 {
1285 messagePlayer(player, language[2900]);
1286 //Cursed effect slows you.
1287 if ( stats->EFFECTS[EFF_FAST] )
1288 {
1289 messagePlayer(player, language[769]);
1290 stats->EFFECTS[EFF_FAST] = false;
1291 stats->EFFECTS_TIMERS[EFF_FAST] = 0;
1292 }
1293 else
1294 {
1295 messagePlayer(player, language[2902]);
1296 stats->EFFECTS[EFF_SLOW] = true;
1297 stats->EFFECTS_TIMERS[EFF_SLOW] = 1800;
1298 }
1299 }
1300 else
1301 {
1302 if ( !stats->EFFECTS[EFF_SLOW] )
1303 {
1304 messagePlayer(player, language[768]);
1305 stats->EFFECTS[EFF_FAST] = true;
1306 stats->EFFECTS_TIMERS[EFF_FAST] += 3000;
1307 if ( item->beatitude > 0 )
1308 {
1309 stats->EFFECTS_TIMERS[EFF_FAST] += 3000 * item->beatitude;
1310 }
1311 }
1312 else
1313 {
1314 messagePlayer(player, language[769]);
1315 stats->EFFECTS[EFF_SLOW] = false;
1316 stats->EFFECTS_TIMERS[EFF_SLOW] = 0;
1317 }
1318 }
1319 serverUpdateEffects(player);
1320
1321 // play drink sound
1322 playSoundEntity(entity, 52, 64);
1323 consumeItem(item, player);
1324 return true;
1325 }
1326
item_PotionStrength(Item * & item,Entity * entity,Entity * usedBy)1327 bool item_PotionStrength(Item*& item, Entity* entity, Entity* usedBy)
1328 {
1329 if ( !entity )
1330 {
1331 return false;
1332 }
1333
1334 int skillLVL = 0;
1335 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1336 {
1337 Stat* usedByStats = usedBy->getStats();
1338 if ( usedByStats )
1339 {
1340 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1341 }
1342 }
1343
1344 int player = -1;
1345 Stat* stats;
1346
1347 if ( entity->behavior == &actPlayer )
1348 {
1349 player = entity->skill[2];
1350 }
1351 stats = entity->getStats();
1352 if ( !stats )
1353 {
1354 return false;
1355 }
1356
1357 if ( stats->amulet != NULL )
1358 {
1359 if ( stats->amulet->type == AMULET_STRANGULATION )
1360 {
1361 if ( player == clientnum )
1362 {
1363 messagePlayer(player, language[750]);
1364 }
1365 return false;
1366 }
1367 }
1368 if ( stats->EFFECTS[EFF_VOMITING] )
1369 {
1370 if ( player == clientnum )
1371 {
1372 messagePlayer(player, language[751]);
1373 }
1374 return false;
1375 }
1376 if ( multiplayer == CLIENT )
1377 {
1378 consumeItem(item, player);
1379 return true;
1380 }
1381
1382
1383 if ( item->beatitude < 0 )
1384 {
1385 messagePlayer(player, language[2900]);
1386 //Cursed effect blinds you.
1387 messagePlayer(player, language[765]);
1388 stats->EFFECTS[EFF_BLIND] = true;
1389 if ( player >= 0 )
1390 {
1391 stats->EFFECTS_TIMERS[EFF_BLIND] = 660 + rand() % 480;
1392 stats->EFFECTS_TIMERS[EFF_BLIND] = std::max(300, stats->EFFECTS_TIMERS[EFF_BLIND] - (entity->getPER() + entity->getCON()) * 5);
1393 }
1394 else
1395 {
1396 entity->setEffect(EFF_BLIND, true, 660 + rand() % 240, true);
1397 }
1398 }
1399 else
1400 {
1401 messagePlayer(player, language[3354]);
1402 stats->EFFECTS[EFF_POTION_STR] = true;
1403 stats->EFFECTS_TIMERS[EFF_POTION_STR] = 3000; // 60 seconds
1404 if ( item->beatitude > 0 )
1405 {
1406 stats->EFFECTS_TIMERS[EFF_POTION_STR] += 3000 * item->beatitude; // 60 seconds each blessing
1407 }
1408 }
1409 serverUpdateEffects(player);
1410
1411 // play drink sound
1412 playSoundEntity(entity, 52, 64);
1413 consumeItem(item, player);
1414 return true;
1415 }
1416
item_PotionAcid(Item * & item,Entity * entity,Entity * usedBy)1417 bool item_PotionAcid(Item*& item, Entity* entity, Entity* usedBy)
1418 {
1419 if (!entity)
1420 {
1421 return false;
1422 }
1423
1424 int skillLVL = 0;
1425 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1426 {
1427 Stat* usedByStats = usedBy->getStats();
1428 if ( usedByStats )
1429 {
1430 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1431 }
1432 }
1433
1434 int player = -1;
1435 Stat* stats;
1436
1437 if ( entity->behavior == &actPlayer )
1438 {
1439 player = entity->skill[2];
1440 }
1441 stats = entity->getStats();
1442 if ( !stats )
1443 {
1444 return false;
1445 }
1446
1447 auto& camera_shakex = cameravars[player >= 0 ? player : 0].shakex;
1448 auto& camera_shakey = cameravars[player >= 0 ? player : 0].shakey;
1449
1450 if ( entity == NULL )
1451 {
1452 return false;
1453 }
1454 if ( stats->amulet != NULL )
1455 {
1456 if ( stats->amulet->type == AMULET_STRANGULATION )
1457 {
1458 if ( player == clientnum )
1459 {
1460 messagePlayer(player, language[750]);
1461 }
1462 return false;
1463 }
1464 }
1465 if ( stats->EFFECTS[EFF_VOMITING] )
1466 {
1467 if ( player == clientnum )
1468 {
1469 messagePlayer(player, language[751]);
1470 }
1471 return false;
1472 }
1473 if ( multiplayer == CLIENT || player == 0 )
1474 {
1475 camera_shakex += .1;
1476 camera_shakey += 10;
1477 if ( multiplayer == CLIENT )
1478 {
1479 consumeItem(item, player);
1480 return true;
1481 }
1482 }
1483
1484 int damage = (10 + 5 * abs(item->beatitude)) * potionDamageSkillMultipliers[std::min(skillLVL, 5)];
1485 int chance = damage / 8;
1486 if ( player >= 0 && usedBy == entity )
1487 {
1488 damage /= 2;
1489 }
1490 else
1491 {
1492 damage -= (rand() % (1 + chance));
1493 }
1494 messagePlayer(player, language[770]);
1495 entity->modHP(-damage);
1496 playSoundEntity(entity, 28, 64);
1497
1498 // set obituary
1499 entity->setObituary(language[1535]);
1500
1501 // play drink sound
1502 playSoundEntity(entity, 52, 64);
1503 consumeItem(item, player);
1504 return true;
1505 }
1506
item_PotionUnstableStorm(Item * & item,Entity * entity,Entity * usedBy,Entity * thrownPotion)1507 bool item_PotionUnstableStorm(Item*& item, Entity* entity, Entity* usedBy, Entity* thrownPotion)
1508 {
1509 if ( !entity )
1510 {
1511 return false;
1512 }
1513
1514 int skillLVL = 0;
1515 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1516 {
1517 Stat* usedByStats = usedBy->getStats();
1518 if ( usedByStats )
1519 {
1520 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1521 }
1522 }
1523
1524 int player = -1;
1525 Stat* stats;
1526
1527 if ( entity->behavior == &actPlayer )
1528 {
1529 player = entity->skill[2];
1530 }
1531 stats = entity->getStats();
1532 if ( !stats )
1533 {
1534 return false;
1535 }
1536
1537 auto& camera_shakex = cameravars[player >= 0 ? player : 0].shakex;
1538 auto& camera_shakey = cameravars[player >= 0 ? player : 0].shakey;
1539
1540 if ( entity == NULL )
1541 {
1542 return false;
1543 }
1544 if ( stats->amulet != NULL )
1545 {
1546 if ( stats->amulet->type == AMULET_STRANGULATION )
1547 {
1548 if ( player == clientnum )
1549 {
1550 messagePlayer(player, language[750]);
1551 }
1552 return false;
1553 }
1554 }
1555 if ( stats->EFFECTS[EFF_VOMITING] )
1556 {
1557 if ( player == clientnum )
1558 {
1559 messagePlayer(player, language[751]);
1560 }
1561 return false;
1562 }
1563 if ( multiplayer == CLIENT || player == 0 )
1564 {
1565 if ( player == clientnum )
1566 {
1567 camera_shakex += .1;
1568 camera_shakey += 10;
1569 }
1570 if ( multiplayer == CLIENT )
1571 {
1572 consumeItem(item, player);
1573 return true;
1574 }
1575 }
1576
1577 bool playerAutomatonDrink = false;
1578 if ( item->type == POTION_FIRESTORM && !thrownPotion && usedBy && usedBy == entity
1579 && usedBy->behavior == &actPlayer && stats->type == AUTOMATON )
1580 {
1581 playerAutomatonDrink = true;
1582 }
1583
1584 int damage = (10 + 5 * abs(item->beatitude)) * potionDamageSkillMultipliers[std::min(skillLVL, 5)];
1585 int chance = damage / 8;
1586 if ( player >= 0 && usedBy == entity )
1587 {
1588 damage /= 2;
1589 }
1590 else
1591 {
1592 damage -= (rand() % (1 + chance));
1593 }
1594 if ( playerAutomatonDrink )
1595 {
1596 damage = 0;
1597 }
1598 else
1599 {
1600 messagePlayer(player, language[770]);
1601 entity->modHP(-damage);
1602 playSoundEntity(entity, 28, 64);
1603 }
1604
1605 // set obituary
1606 entity->setObituary(language[1535]);
1607
1608 real_t x = entity->x;
1609 real_t y = entity->y;
1610 if ( thrownPotion )
1611 {
1612 // rather spawn at the potion impact rather than on the hit entity's coords.
1613 x = thrownPotion->x;
1614 y = thrownPotion->y;
1615 }
1616 if ( item->type == POTION_FIRESTORM )
1617 {
1618 if ( playerAutomatonDrink )
1619 {
1620 spawnMagicTower(usedBy, x, y, SPELL_FIREBALL, nullptr);
1621 stats->HUNGER = std::min(stats->HUNGER + 1500, 1500);
1622 players[player]->entity->modMP(stats->MAXMP);
1623 Uint32 color = SDL_MapRGB(mainsurface->format, 255, 128, 0);
1624 messagePlayerColor(player, color, language[3699]); // superheats
1625 serverUpdateHunger(player);
1626 for ( int c = 0; c < 100; c++ )
1627 {
1628 Entity* entity = spawnFlame(players[player]->entity, SPRITE_FLAME);
1629 entity->sprite = 16;
1630 double vel = rand() % 10;
1631 entity->vel_x = vel * cos(entity->yaw) * cos(entity->pitch) * .1;
1632 entity->vel_y = vel * sin(entity->yaw) * cos(entity->pitch) * .1;
1633 entity->vel_z = vel * sin(entity->pitch) * .2;
1634 entity->skill[0] = 5 + rand() % 10;
1635 }
1636 }
1637 else
1638 {
1639 spawnMagicTower(usedBy, x, y, SPELL_FIREBALL, entity);
1640 }
1641 }
1642 else if ( item->type == POTION_ICESTORM )
1643 {
1644 spawnMagicTower(usedBy, x, y, SPELL_COLD, entity);
1645 }
1646 else if ( item->type == POTION_THUNDERSTORM )
1647 {
1648 spawnMagicTower(usedBy, x, y, SPELL_LIGHTNING, entity);
1649 }
1650
1651 // play drink sound
1652 playSoundEntity(entity, 52, 64);
1653 consumeItem(item, player);
1654 return true;
1655 }
1656
item_PotionParalysis(Item * & item,Entity * entity,Entity * usedBy)1657 bool item_PotionParalysis(Item*& item, Entity* entity, Entity* usedBy)
1658 {
1659 if (!entity)
1660 {
1661 return false;
1662 }
1663
1664 int skillLVL = 0;
1665 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1666 {
1667 Stat* usedByStats = usedBy->getStats();
1668 if ( usedByStats )
1669 {
1670 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1671 }
1672 }
1673
1674 int player = -1;
1675 Stat* stats;
1676
1677 if ( entity->behavior == &actPlayer )
1678 {
1679 player = entity->skill[2];
1680 }
1681 stats = entity->getStats();
1682 if ( !stats )
1683 {
1684 return false;
1685 }
1686
1687 if ( stats->amulet != NULL )
1688 {
1689 if ( stats->amulet->type == AMULET_STRANGULATION )
1690 {
1691 if ( player == clientnum )
1692 {
1693 messagePlayer(player, language[750]);
1694 }
1695 return false;
1696 }
1697 }
1698 if ( stats->EFFECTS[EFF_VOMITING] )
1699 {
1700 if ( player == clientnum )
1701 {
1702 messagePlayer(player, language[751]);
1703 }
1704 return false;
1705 }
1706 if ( multiplayer == CLIENT )
1707 {
1708 consumeItem(item, player);
1709 return true;
1710 }
1711
1712 messagePlayer(player, language[771]);
1713 int effectDuration = 0;
1714 if ( player >= 0 )
1715 {
1716 effectDuration = 420 + rand() % 180;
1717 effectDuration = std::max(300, effectDuration - (entity->getCON()) * 5);
1718 }
1719 else
1720 {
1721 effectDuration = 420 + rand() % 180;
1722 }
1723 if ( item->beatitude != 0 )
1724 {
1725 effectDuration += (abs(item->beatitude) * 100);
1726 }
1727
1728 entity->setEffect(EFF_PARALYZED, true, effectDuration, false);
1729 serverUpdateEffects(player);
1730
1731 // play drink sound
1732 playSoundEntity(entity, 52, 64);
1733 consumeItem(item, player);
1734 return true;
1735 }
1736
item_PotionHealing(Item * & item,Entity * entity,Entity * usedBy,bool shouldConsumeItem)1737 bool item_PotionHealing(Item*& item, Entity* entity, Entity* usedBy, bool shouldConsumeItem)
1738 {
1739 if (!entity)
1740 {
1741 return false;
1742 }
1743
1744 int skillLVL = 0;
1745 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1746 {
1747 Stat* usedByStats = usedBy->getStats();
1748 if ( usedByStats )
1749 {
1750 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1751 }
1752 }
1753
1754 int player = -1;
1755 Stat* stats;
1756
1757 if ( entity->behavior == &actPlayer )
1758 {
1759 player = entity->skill[2];
1760 }
1761 stats = entity->getStats();
1762 if ( !stats )
1763 {
1764 return false;
1765 }
1766
1767 if ( stats->amulet != nullptr )
1768 {
1769 if ( stats->amulet->type == AMULET_STRANGULATION )
1770 {
1771 if ( player == clientnum )
1772 {
1773 messagePlayer(player, language[750]);
1774 }
1775 return false;
1776 }
1777 }
1778 if ( stats->EFFECTS[EFF_VOMITING] )
1779 {
1780 if ( player == clientnum )
1781 {
1782 messagePlayer(player, language[751]);
1783 }
1784 return false;
1785 }
1786 if ( multiplayer == CLIENT )
1787 {
1788 consumeItem(item, player);
1789 return true;
1790 }
1791 if ( stats->HP == stats->MAXHP )
1792 {
1793 playSoundEntity(entity, 52, 64);
1794 playSoundEntity(entity, 168, 128);
1795 spawnMagicEffectParticles(entity->x, entity->y, entity->z, 169);
1796 if ( item->beatitude < 0 )
1797 {
1798 messagePlayer(player, language[2900]);
1799 messagePlayer(player, language[2903]);
1800 stats->EFFECTS[EFF_POISONED] = true;
1801 }
1802 else
1803 {
1804 messagePlayer(player, language[772]);
1805 // stop bleeding
1806 if ( stats->EFFECTS[EFF_BLEEDING] )
1807 {
1808 entity->setEffect(EFF_BLEEDING, false, 0, false);
1809 }
1810 }
1811 if ( shouldConsumeItem )
1812 {
1813 consumeItem(item, player);
1814 return true;
1815 }
1816 return false;
1817 }
1818
1819 int amount = std::max(7 + item->status, 0);
1820 int multiplier = std::max(5, item->beatitude + 5);
1821
1822 amount *= multiplier / 5.f;
1823 if ( stats->type == GOATMAN && entity->behavior == &actMonster )
1824 {
1825 amount *= GOATMAN_HEALINGPOTION_MOD; //Goatman special.
1826 stats->EFFECTS[EFF_FAST] = true;
1827 stats->EFFECTS_TIMERS[EFF_FAST] = GOATMAN_HEALING_POTION_SPEED_BOOST_DURATION;
1828 }
1829
1830 //Bonus from CON, to scale up healing potions as the game progresses.
1831 if ( stats->CON > 0 )
1832 {
1833 amount += 2 * stats->CON;
1834 }
1835
1836 if ( item->beatitude < 0 )
1837 {
1838 amount /= (std::abs(item->beatitude) * 2);
1839 }
1840
1841 int oldHP = entity->getHP();
1842
1843 entity->modHP(amount);
1844
1845 int heal = std::max(entity->getHP() - oldHP, 0);
1846 if ( heal > 0 )
1847 {
1848 serverUpdatePlayerGameplayStats(player, STATISTICS_HEAL_BOT, heal);
1849 }
1850
1851 // play drink sound
1852 playSoundEntity(entity, 52, 64);
1853 playSoundEntity(entity, 168, 128);
1854 spawnMagicEffectParticles(entity->x, entity->y, entity->z, 169);
1855 Uint32 color = SDL_MapRGB(mainsurface->format, 0, 255, 0);
1856
1857 if ( item->beatitude < 0 )
1858 {
1859 messagePlayer(player, language[2900]);
1860 messagePlayer(player, language[2903]);
1861 stats->EFFECTS[EFF_POISONED] = true;
1862 stats->EFFECTS_TIMERS[EFF_POISONED] = std::max(200, 300 - entity->getCON() * 20);
1863 }
1864 else
1865 {
1866 messagePlayerColor(player, color, language[773]);
1867 // stop bleeding
1868 if ( stats->EFFECTS[EFF_BLEEDING] )
1869 {
1870 entity->setEffect(EFF_BLEEDING, false, 0, false);
1871 }
1872 }
1873
1874 if ( shouldConsumeItem )
1875 {
1876 consumeItem(item, player);
1877 return true;
1878 }
1879 return false;
1880 }
1881
item_PotionExtraHealing(Item * & item,Entity * entity,Entity * usedBy,bool shouldConsumeItem)1882 bool item_PotionExtraHealing(Item*& item, Entity* entity, Entity* usedBy, bool shouldConsumeItem)
1883 {
1884 if (!entity)
1885 {
1886 return false;
1887 }
1888
1889 int skillLVL = 0;
1890 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1891 {
1892 Stat* usedByStats = usedBy->getStats();
1893 if ( usedByStats )
1894 {
1895 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1896 }
1897 }
1898
1899 int player = -1;
1900 Stat* stats;
1901
1902 if ( entity->behavior == &actPlayer )
1903 {
1904 player = entity->skill[2];
1905 }
1906 stats = entity->getStats();
1907 if ( !stats )
1908 {
1909 return false;
1910 }
1911
1912 if ( stats->amulet != nullptr )
1913 {
1914 if ( stats->amulet->type == AMULET_STRANGULATION )
1915 {
1916 if ( player == clientnum )
1917 {
1918 messagePlayer(player, language[750]);
1919 }
1920 return false;
1921 }
1922 }
1923 if ( stats->EFFECTS[EFF_VOMITING] )
1924 {
1925 if ( player == clientnum )
1926 {
1927 messagePlayer(player, language[751]);
1928 }
1929 return false;
1930 }
1931 if ( multiplayer == CLIENT )
1932 {
1933 consumeItem(item, player);
1934 return true;
1935 }
1936 if ( stats->HP == stats->MAXHP )
1937 {
1938 playSoundEntity(entity, 52, 64);
1939 playSoundEntity(entity, 168, 128);
1940 spawnMagicEffectParticles(entity->x, entity->y, entity->z, 169);
1941 if ( item->beatitude < 0 )
1942 {
1943 messagePlayer(player, language[2900]);
1944 messagePlayer(player, language[2903]);
1945 stats->EFFECTS[EFF_POISONED] = true;
1946 }
1947 else
1948 {
1949 messagePlayer(player, language[772]);
1950 // stop bleeding
1951 if ( stats->EFFECTS[EFF_BLEEDING] )
1952 {
1953 entity->setEffect(EFF_BLEEDING, false, 0, false);
1954 }
1955 }
1956 if ( shouldConsumeItem )
1957 {
1958 consumeItem(item, player);
1959 return true;
1960 }
1961 return false;
1962 }
1963
1964 int amount = std::max(15 + item->status, 0);
1965 int multiplier = std::max(5, item->beatitude + 5);
1966
1967 amount *= multiplier;
1968 if ( stats->type == GOATMAN && entity->behavior == &actMonster )
1969 {
1970 amount *= GOATMAN_HEALINGPOTION_MOD; //Goatman special.
1971 stats->EFFECTS[EFF_FAST] = true;
1972 stats->EFFECTS_TIMERS[EFF_FAST] = GOATMAN_HEALING_POTION_SPEED_BOOST_DURATION;
1973 }
1974
1975 //Bonus from CON, to scale up healing potions as the game progresses.
1976 if ( stats->CON > 0 )
1977 {
1978 amount += 4 * stats->CON;
1979 }
1980
1981 if ( item->beatitude < 0 )
1982 {
1983 amount /= (std::abs(item->beatitude) * 2);
1984 }
1985
1986 int oldHP = entity->getHP();
1987
1988 entity->modHP(amount);
1989
1990 int heal = std::max(entity->getHP() - oldHP, 0);
1991 if ( heal > 0 )
1992 {
1993 serverUpdatePlayerGameplayStats(player, STATISTICS_HEAL_BOT, heal);
1994 }
1995
1996 // play drink sound
1997 playSoundEntity(entity, 52, 64);
1998 playSoundEntity(entity, 168, 128);
1999 spawnMagicEffectParticles(entity->x, entity->y, entity->z, 169);
2000 Uint32 color = SDL_MapRGB(mainsurface->format, 0, 255, 0);
2001 if ( item->beatitude < 0 )
2002 {
2003 messagePlayer(player, language[2900]);
2004 messagePlayer(player, language[2903]);
2005 stats->EFFECTS[EFF_POISONED] = true;
2006 stats->EFFECTS_TIMERS[EFF_POISONED] = std::max(300, 600 - entity->getCON() * 20);
2007 }
2008 else
2009 {
2010 messagePlayerColor(player, color, language[773]);
2011 // stop bleeding
2012 if ( stats->EFFECTS[EFF_BLEEDING] )
2013 {
2014 entity->setEffect(EFF_BLEEDING, false, 0, false);
2015 }
2016 }
2017
2018 if ( shouldConsumeItem )
2019 {
2020 consumeItem(item, player);
2021 return true;
2022 }
2023 return false;
2024 }
2025
item_PotionRestoreMagic(Item * & item,Entity * entity,Entity * usedBy)2026 bool item_PotionRestoreMagic(Item*& item, Entity* entity, Entity* usedBy)
2027 {
2028 if (!entity)
2029 {
2030 return false;
2031 }
2032
2033 int skillLVL = 0;
2034 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
2035 {
2036 Stat* usedByStats = usedBy->getStats();
2037 if ( usedByStats )
2038 {
2039 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
2040 }
2041 }
2042
2043 int player = -1;
2044 Stat* stats;
2045
2046 if ( entity->behavior == &actPlayer )
2047 {
2048 player = entity->skill[2];
2049 }
2050 stats = entity->getStats();
2051 if ( !stats )
2052 {
2053 return false;
2054 }
2055
2056 if ( entity == NULL )
2057 {
2058 return false;
2059 }
2060 if ( stats->amulet != NULL )
2061 {
2062 if ( stats->amulet->type == AMULET_STRANGULATION )
2063 {
2064 if ( player == clientnum )
2065 {
2066 messagePlayer(player, language[750]);
2067 }
2068 return false;
2069 }
2070 }
2071 if ( stats->EFFECTS[EFF_VOMITING] )
2072 {
2073 if ( player == clientnum )
2074 {
2075 messagePlayer(player, language[751]);
2076 }
2077 return false;
2078 }
2079 if ( multiplayer == CLIENT )
2080 {
2081 consumeItem(item, player);
2082 return true;
2083 }
2084 if ( stats->MP == stats->MAXMP )
2085 {
2086 playSoundEntity(entity, 52, 64);
2087 if ( item->beatitude < 0 )
2088 {
2089 messagePlayer(player, language[774]);
2090 messagePlayer(player, language[2902]);
2091 stats->EFFECTS[EFF_SLOW] = true;
2092 stats->EFFECTS_TIMERS[EFF_SLOW] = 600;
2093 }
2094 else
2095 {
2096 messagePlayer(player, language[772]);
2097 }
2098 consumeItem(item, player);
2099 return true;
2100 }
2101
2102 int amount = std::max(7 + item->status, 0);
2103 int multiplier = std::max(5, item->beatitude + 5);
2104
2105 amount *= multiplier;
2106
2107 if ( stats->INT > 0 )
2108 {
2109 amount += std::min(30, 2 * stats->INT); // extra mana scaling from 1 to 15 INT, capped at +30 MP
2110 }
2111
2112 if ( item->beatitude < 0 )
2113 {
2114 amount /= (std::abs(item->beatitude) * 2);
2115 messagePlayer(player, language[774]);
2116 messagePlayer(player, language[2902]);
2117 stats->EFFECTS[EFF_SLOW] = true;
2118 stats->EFFECTS_TIMERS[EFF_SLOW] = 600;
2119 }
2120 else
2121 {
2122 messagePlayer(player, language[774]);
2123 }
2124 entity->modMP(amount);
2125
2126 if ( svFlags & SV_FLAG_HUNGER )
2127 {
2128 if ( player >= 0 && stats->playerRace == RACE_INSECTOID && stats->appearance == 0 )
2129 {
2130 Sint32 hungerPointPerMana = entity->playerInsectoidHungerValueOfManaPoint(*stats);
2131 Sint32 oldHunger = stats->HUNGER;
2132 stats->HUNGER += amount * hungerPointPerMana;
2133 stats->HUNGER = std::min(999, stats->HUNGER);
2134 updateHungerMessages(entity, stats, item);
2135 if ( player > 0 )
2136 {
2137 serverUpdateHunger(player);
2138 }
2139 }
2140 }
2141
2142 // play drink sound
2143 playSoundEntity(entity, 52, 64);
2144
2145 consumeItem(item, player);
2146 return true;
2147 }
2148
item_PotionPolymorph(Item * & item,Entity * entity,Entity * usedBy)2149 Entity* item_PotionPolymorph(Item*& item, Entity* entity, Entity* usedBy)
2150 {
2151 if ( !entity )
2152 {
2153 return nullptr;
2154 }
2155
2156 int skillLVL = 0;
2157 if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
2158 {
2159 Stat* usedByStats = usedBy->getStats();
2160 if ( usedByStats )
2161 {
2162 skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
2163 }
2164 }
2165
2166 int player = -1;
2167 Stat* stats;
2168
2169 if ( entity->behavior == &actPlayer )
2170 {
2171 player = entity->skill[2];
2172 }
2173 stats = entity->getStats();
2174 if ( !stats )
2175 {
2176 return nullptr;
2177 }
2178
2179 if ( stats->amulet != NULL )
2180 {
2181 if ( stats->amulet->type == AMULET_STRANGULATION )
2182 {
2183 if ( player == clientnum )
2184 {
2185 messagePlayer(player, language[750]);
2186 }
2187 return nullptr;
2188 }
2189 }
2190 if ( stats->EFFECTS[EFF_VOMITING] )
2191 {
2192 if ( player == clientnum )
2193 {
2194 messagePlayer(player, language[751]);
2195 }
2196 return nullptr;
2197 }
2198 if ( multiplayer == CLIENT )
2199 {
2200 consumeItem(item, player);
2201 return nullptr;
2202 }
2203
2204 // play drink sound
2205 if ( !usedBy ) // drinking rather than throwing.
2206 {
2207 playSoundEntity(entity, 52, 64);
2208 if ( player >= 0 )
2209 {
2210 messagePlayer(player, language[3190]);
2211 }
2212 }
2213 Entity* transformedEntity = nullptr;
2214
2215 if ( entity->behavior == &actMonster || entity->behavior == &actPlayer )
2216 {
2217 transformedEntity = spellEffectPolymorph(entity, stats, usedBy, false);
2218 }
2219
2220 consumeItem(item, player);
2221
2222 return transformedEntity;
2223 }
2224
item_ScrollMail(Item * item,int player)2225 void item_ScrollMail(Item* item, int player)
2226 {
2227 if (players[player] == nullptr || players[player]->entity == nullptr)
2228 {
2229 return;
2230 }
2231
2232 if ( player != clientnum )
2233 {
2234 return;
2235 }
2236
2237 if (players[player]->entity->isBlind())
2238 {
2239 messagePlayer(player, language[775]);
2240 return;
2241 }
2242
2243 if ( player == clientnum )
2244 {
2245 conductIlliterate = false;
2246 }
2247 item->identified = 1;
2248 switch ( item->appearance % 25 )
2249 {
2250 case 0:
2251 messagePlayer(player, language[776]);
2252 break;
2253 case 1:
2254 messagePlayer(player, language[780]);
2255 messagePlayer(player, language[781]);
2256 break;
2257 case 2:
2258 messagePlayer(player, language[786]);
2259 break;
2260 case 3:
2261 messagePlayer(player, language[790]);
2262 break;
2263 case 4:
2264 messagePlayer(player, language[793], language[158 + item->appearance % 26], language[184 + item->appearance % 9]);
2265 break;
2266 case 5:
2267 messagePlayer(player, language[796]);
2268 break;
2269 case 6:
2270 messagePlayer(player, language[799]);
2271 break;
2272 case 7:
2273 messagePlayer(player, language[801]);
2274 messagePlayer(player, language[802]);
2275 break;
2276 case 8:
2277 messagePlayer(player, language[807]);
2278 break;
2279 case 9:
2280 messagePlayer(player, language[811]);
2281 messagePlayer(player, language[812]);
2282 break;
2283 case 10:
2284 messagePlayer(player, language[816]);
2285 break;
2286 case 11:
2287 messagePlayer(player, language[817]);
2288 break;
2289 case 12:
2290 messagePlayer(player, language[822]);
2291 break;
2292 case 13:
2293 messagePlayer(player, language[824]);
2294 break;
2295 case 14:
2296 messagePlayer(player, language[826]);
2297 break;
2298 case 15:
2299 messagePlayer(player, language[828]);
2300 break;
2301 case 16:
2302 messagePlayer(player, language[830]);
2303 break;
2304 case 17:
2305 messagePlayer(player, language[834]);
2306 break;
2307 case 18:
2308 messagePlayer(player, language[836]);
2309 break;
2310 case 19:
2311 messagePlayer(player, language[838]);
2312 break;
2313 case 20:
2314 messagePlayer(player, language[840]);
2315 break;
2316 case 21:
2317 messagePlayer(player, language[843]);
2318 break;
2319 default:
2320 messagePlayer(player, language[846]);
2321 break;
2322 }
2323 }
2324
item_ScrollIdentify(Item * item,int player)2325 void item_ScrollIdentify(Item* item, int player)
2326 {
2327 if (players[player] == nullptr || players[player]->entity == nullptr)
2328 {
2329 return;
2330 }
2331
2332 if (player != clientnum)
2333 {
2334 return;
2335 }
2336
2337 if (players[player]->entity->isBlind())
2338 {
2339 messagePlayer(player, language[775]);
2340 return;
2341 }
2342
2343 //identifygui_mode = true;
2344 identifygui_active = true;
2345 identifygui_appraising = false;
2346 shootmode = false;
2347 openStatusScreen(GUI_MODE_INVENTORY, INVENTORY_MODE_ITEM); // Reset the GUI to the inventory.
2348
2349 if ( removecursegui_active )
2350 {
2351 closeRemoveCurseGUI();
2352 }
2353
2354 GenericGUI.closeGUI();
2355
2356 if ( openedChest[clientnum] )
2357 {
2358 openedChest[clientnum]->closeChest();
2359 }
2360
2361 //Initialize Identify GUI game controller code here.
2362 initIdentifyGUIControllerCode();
2363 }
2364
item_ScrollLight(Item * item,int player)2365 void item_ScrollLight(Item* item, int player)
2366 {
2367 int c;
2368
2369 if (players[player] == nullptr || players[player]->entity == nullptr)
2370 {
2371 return;
2372 }
2373
2374 if (multiplayer == CLIENT)
2375 {
2376 return;
2377 }
2378
2379 if (players[player]->entity->isBlind())
2380 {
2381 messagePlayer(player, language[775]);
2382 return;
2383 }
2384
2385 if ( player == clientnum )
2386 {
2387 conductIlliterate = false;
2388 }
2389 item->identified = 1;
2390 messagePlayer(player, language[848]);
2391
2392 messagePlayer(player, language[851]);
2393 lightSphereShadow(players[player]->entity->x / 16, players[player]->entity->y / 16, 8, 150);
2394
2395 // send new light info to clients
2396 if (multiplayer == SERVER)
2397 {
2398 for (c = 1; c < MAXPLAYERS; c++)
2399 {
2400 if (client_disconnected[c] == true)
2401 {
2402 continue;
2403 }
2404 strcpy((char*)net_packet->data, "LITS");
2405 SDLNet_Write16(players[player]->entity->x / 16, &net_packet->data[4]);
2406 SDLNet_Write16(players[player]->entity->y / 16, &net_packet->data[6]);
2407 SDLNet_Write16(8, &net_packet->data[8]);
2408 SDLNet_Write16(150, &net_packet->data[10]);
2409 net_packet->address.host = net_clients[c - 1].host;
2410 net_packet->address.port = net_clients[c - 1].port;
2411 net_packet->len = 12;
2412 sendPacketSafe(net_sock, -1, net_packet, c - 1);
2413 }
2414 }
2415 }
2416
item_ScrollBlank(Item * item,int player)2417 void item_ScrollBlank(Item* item, int player)
2418 {
2419 if (players[player] == nullptr || players[player]->entity == nullptr)
2420 {
2421 return;
2422 }
2423
2424 if (player != clientnum)
2425 {
2426 return;
2427 }
2428
2429 if (players[player]->entity->isBlind())
2430 {
2431 messagePlayer(player, language[775]);
2432 return;
2433 }
2434
2435 if (player == clientnum)
2436 {
2437 conductIlliterate = false;
2438 }
2439 item->identified = 1;
2440 messagePlayer(player, language[852]);
2441 }
2442
item_ScrollEnchantWeapon(Item * item,int player)2443 void item_ScrollEnchantWeapon(Item* item, int player)
2444 {
2445 if (players[player] == nullptr || players[player]->entity == nullptr)
2446 {
2447 return;
2448 }
2449
2450 if ( player != clientnum )
2451 {
2452 consumeItem(item, player);
2453 return;
2454 }
2455
2456 if (players[player]->entity->isBlind())
2457 {
2458 messagePlayer(player, language[775]);
2459 return;
2460 }
2461
2462 conductIlliterate = false;
2463
2464 item->identified = 1;
2465
2466 messagePlayer(player, language[848]);
2467
2468 Item** toEnchant = nullptr;
2469 bool hasMeleeGloves = false;
2470 if ( stats[player]->gloves )
2471 {
2472 switch ( stats[player]->gloves->type )
2473 {
2474 case BRASS_KNUCKLES:
2475 case IRON_KNUCKLES:
2476 case SPIKED_GAUNTLETS:
2477 hasMeleeGloves = true;
2478 break;
2479 default:
2480 break;
2481 }
2482 }
2483
2484 if ( stats[player]->weapon )
2485 {
2486 toEnchant = &stats[player]->weapon;
2487 }
2488 else if ( hasMeleeGloves )
2489 {
2490 toEnchant = &stats[player]->gloves;
2491 }
2492
2493 if ( toEnchant == nullptr)
2494 {
2495 messagePlayer(player, language[853]);
2496 }
2497 else
2498 {
2499 if (item->beatitude < 0)
2500 {
2501 if ( toEnchant == &stats[player]->gloves )
2502 {
2503 messagePlayer(player, language[858], (*toEnchant)->getName());
2504 }
2505 else
2506 {
2507 messagePlayer(player, language[854]);
2508 }
2509
2510 if ( (*toEnchant)->beatitude > 0 )
2511 {
2512 (*toEnchant)->beatitude = -(*toEnchant)->beatitude;
2513 if ( stats[clientnum]->type == SUCCUBUS )
2514 {
2515 steamAchievement("BARONY_ACH_THE_WAY_YOU_LIKE_IT");
2516 }
2517 }
2518 else
2519 {
2520 (*toEnchant)->beatitude -= 1;
2521 }
2522 }
2523 else
2524 {
2525 if (item->beatitude == 0)
2526 {
2527 if ( toEnchant == &stats[player]->gloves )
2528 {
2529 messagePlayer(player, language[859], (*toEnchant)->getName());
2530 }
2531 else
2532 {
2533 messagePlayer(player, language[855]);
2534 }
2535 }
2536 else
2537 {
2538 if ( toEnchant == &stats[player]->gloves )
2539 {
2540 messagePlayer(player, language[860], (*toEnchant)->getName());
2541 }
2542 else
2543 {
2544 messagePlayer(player, language[856]);
2545 }
2546 }
2547 (*toEnchant)->beatitude += 1 + item->beatitude;
2548 }
2549
2550 if ( multiplayer == CLIENT )
2551 {
2552 strcpy((char*)net_packet->data, "BEAT");
2553 net_packet->data[4] = clientnum;
2554 net_packet->data[5] = 0; // weapon index
2555 net_packet->data[6] = (*toEnchant)->beatitude + 100;
2556 net_packet->address.host = net_server.host;
2557 net_packet->address.port = net_server.port;
2558 net_packet->len = 7;
2559 sendPacketSafe(net_sock, -1, net_packet, 0);
2560 //messagePlayer(clientnum, "sent server: %d, %d, %d", net_packet->data[4], net_packet->data[5], net_packet->data[6]);
2561 }
2562 }
2563 consumeItem(item, player);
2564 }
2565
item_ScrollEnchantArmor(Item * item,int player)2566 void item_ScrollEnchantArmor(Item* item, int player)
2567 {
2568 Item* armor = nullptr;
2569 if (players[player] == nullptr || players[player]->entity == nullptr)
2570 {
2571 return;
2572 }
2573
2574 if ( !item )
2575 {
2576 return;
2577 }
2578
2579 if ( player != clientnum )
2580 {
2581 consumeItem(item, player);
2582 return;
2583 }
2584
2585 if (players[player]->entity->isBlind())
2586 {
2587 messagePlayer(player, language[775]);
2588 return;
2589 }
2590
2591 conductIlliterate = false;
2592
2593 item->identified = 1;
2594 messagePlayer(player, language[848]);
2595
2596 // choose a random piece of worn equipment to curse!
2597 int tryIndex = 1 + rand() % 7;
2598 int startIndex = tryIndex;
2599 int armornum = 0;
2600 bool breakloop = false;
2601
2602 // curse random item.
2603 while ( !armor && !breakloop )
2604 {
2605 switch ( tryIndex )
2606 {
2607 // intentional fall throughs...
2608 case 0:
2609 /*if ( stats[player]->weapon != nullptr && itemCategory(stats[player]->weapon) != POTION )
2610 {
2611 toCurse = stats[player]->weapon;
2612 armornum = 0;
2613 break;
2614 }*/
2615 case 1:
2616 if ( stats[player]->helmet != nullptr )
2617 {
2618 armor = stats[player]->helmet;
2619 armornum = 1;
2620 break;
2621 }
2622 case 2:
2623 if ( stats[player]->breastplate != nullptr )
2624 {
2625 armor = stats[player]->breastplate;
2626 armornum = 2;
2627 break;
2628 }
2629 case 3:
2630 if ( stats[player]->gloves != nullptr )
2631 {
2632 armor = stats[player]->gloves;
2633 armornum = 3;
2634 break;
2635 }
2636 case 4:
2637 if ( stats[player]->shoes != nullptr )
2638 {
2639 armor = stats[player]->shoes;
2640 armornum = 4;
2641 break;
2642 }
2643 case 5:
2644 if ( stats[player]->shield != nullptr )
2645 {
2646 armor = stats[player]->shield;
2647 armornum = 5;
2648 break;
2649 }
2650 case 6:
2651 if ( stats[player]->cloak != nullptr )
2652 {
2653 armor = stats[player]->cloak;
2654 armornum = 6;
2655 break;
2656 }
2657 case 7:
2658 if ( stats[player]->mask != nullptr )
2659 {
2660 armor = stats[player]->mask;
2661 armornum = 7;
2662 break;
2663 }
2664 ++tryIndex;
2665 if ( tryIndex > 7 )
2666 {
2667 // loop back around.
2668 tryIndex = 0;
2669 }
2670 if ( tryIndex == startIndex )
2671 {
2672 // couldn't find a piece of armor, break.
2673 breakloop = true;
2674 armor = nullptr;
2675 break;
2676 }
2677 default:
2678 break;
2679 }
2680 }
2681
2682 if (armor == nullptr)
2683 {
2684 messagePlayer(player, language[857]);
2685 }
2686 else if ( armor != nullptr )
2687 {
2688 if (item->beatitude < 0)
2689 {
2690 messagePlayer(player, language[858], armor->getName());
2691
2692 if ( armor->beatitude > 0 )
2693 {
2694 armor->beatitude = -armor->beatitude;
2695 }
2696 else
2697 {
2698 armor->beatitude -= 1;
2699 }
2700 }
2701 else
2702 {
2703 if (item->beatitude == 0)
2704 {
2705 messagePlayer(player, language[859], armor->getName());
2706 }
2707 else
2708 {
2709 messagePlayer(player, language[860], armor->getName());
2710 }
2711 armor->beatitude += 1 + item->beatitude;
2712 }
2713
2714 if ( multiplayer == CLIENT )
2715 {
2716 strcpy((char*)net_packet->data, "BEAT");
2717 net_packet->data[4] = clientnum;
2718 net_packet->data[5] = armornum;
2719 net_packet->data[6] = armor->beatitude + 100;
2720 net_packet->address.host = net_server.host;
2721 net_packet->address.port = net_server.port;
2722 net_packet->len = 7;
2723 sendPacketSafe(net_sock, -1, net_packet, 0);
2724 //messagePlayer(clientnum, "sent server: %d, %d, %d", net_packet->data[4], net_packet->data[5], net_packet->data[6]);
2725 }
2726 }
2727 consumeItem(item, player);
2728 }
2729
item_ScrollRemoveCurse(Item * item,int player)2730 void item_ScrollRemoveCurse(Item* item, int player)
2731 {
2732 if (players[player] == nullptr || players[player]->entity == nullptr)
2733 {
2734 return;
2735 }
2736
2737 if ( player != clientnum )
2738 {
2739 consumeItem(item, player);
2740 return;
2741 }
2742
2743 if (players[player]->entity->isBlind())
2744 {
2745 messagePlayer(player, language[775]);
2746 return;
2747 }
2748
2749 if (item->beatitude >= 0)
2750 {
2751 // Uncurse an item
2752 shootmode = false;
2753 openStatusScreen(GUI_MODE_INVENTORY, INVENTORY_MODE_ITEM); // Reset the GUI to the inventory.
2754 removecursegui_active = true;
2755 if ( identifygui_active )
2756 {
2757 CloseIdentifyGUI();
2758 }
2759 GenericGUI.closeGUI();
2760
2761 if ( openedChest[player] )
2762 {
2763 openedChest[player]->closeChest();
2764 }
2765
2766 initRemoveCurseGUIControllerCode();
2767 consumeItem(item, player);
2768 return;
2769 }
2770 else
2771 {
2772 // choose a random piece of worn equipment to curse!
2773 int tryIndex = rand() % 8;
2774 int startIndex = tryIndex;
2775 int armornum = 0;
2776 bool breakloop = false;
2777 Item* toCurse = nullptr;
2778 // curse random item.
2779 while ( !toCurse && !breakloop )
2780 {
2781 switch ( tryIndex )
2782 {
2783 // intentional fall throughs...
2784 case 0:
2785 if ( stats[player]->weapon != nullptr && itemCategory(stats[player]->weapon) != POTION )
2786 {
2787 toCurse = stats[player]->weapon;
2788 armornum = 0;
2789 break;
2790 }
2791 case 1:
2792 if ( stats[player]->helmet != nullptr )
2793 {
2794 toCurse = stats[player]->helmet;
2795 armornum = 1;
2796 break;
2797 }
2798 case 2:
2799 if ( stats[player]->breastplate != nullptr )
2800 {
2801 toCurse = stats[player]->breastplate;
2802 armornum = 2;
2803 break;
2804 }
2805 case 3:
2806 if ( stats[player]->gloves != nullptr )
2807 {
2808 toCurse = stats[player]->gloves;
2809 armornum = 3;
2810 break;
2811 }
2812 case 4:
2813 if ( stats[player]->shoes != nullptr )
2814 {
2815 toCurse = stats[player]->shoes;
2816 armornum = 4;
2817 break;
2818 }
2819 case 5:
2820 if ( stats[player]->shield != nullptr )
2821 {
2822 toCurse = stats[player]->shield;
2823 armornum = 5;
2824 break;
2825 }
2826 case 6:
2827 if ( stats[player]->cloak != nullptr )
2828 {
2829 toCurse = stats[player]->cloak;
2830 armornum = 6;
2831 break;
2832 }
2833 case 7:
2834 if ( stats[player]->mask != nullptr )
2835 {
2836 toCurse = stats[player]->mask;
2837 armornum = 7;
2838 break;
2839 }
2840 ++tryIndex;
2841 if ( tryIndex > 7 )
2842 {
2843 // loop back around.
2844 tryIndex = 0;
2845 }
2846 if ( tryIndex == startIndex )
2847 {
2848 // couldn't find a piece of armor, break.
2849 breakloop = true;
2850 toCurse = nullptr;
2851 break;
2852 }
2853 default:
2854 break;
2855 }
2856 }
2857 if ( toCurse )
2858 {
2859 if ( toCurse->beatitude <= 0 )
2860 {
2861 --toCurse->beatitude;
2862 }
2863 else
2864 {
2865 toCurse->beatitude = -toCurse->beatitude;
2866 if ( itemCategory(toCurse) == WEAPON && stats[clientnum]->type == SUCCUBUS )
2867 {
2868 steamAchievement("BARONY_ACH_THE_WAY_YOU_LIKE_IT");
2869 }
2870 }
2871 messagePlayer(player, language[858], toCurse->getName());
2872 if ( multiplayer == CLIENT )
2873 {
2874 strcpy((char*)net_packet->data, "BEAT");
2875 net_packet->data[4] = clientnum;
2876 net_packet->data[5] = armornum;
2877 net_packet->data[6] = toCurse->beatitude + 100;
2878 net_packet->address.host = net_server.host;
2879 net_packet->address.port = net_server.port;
2880 net_packet->len = 7;
2881 sendPacketSafe(net_sock, -1, net_packet, 0);
2882 //messagePlayer(clientnum, "sent server: %d, %d, %d", net_packet->data[4], net_packet->data[5], net_packet->data[6]);
2883 }
2884 }
2885 else
2886 {
2887 messagePlayer(player, language[862]);
2888 }
2889 }
2890 consumeItem(item, player);
2891 }
2892
item_ScrollFire(Item * item,int player)2893 bool item_ScrollFire(Item* item, int player)
2894 {
2895 if (multiplayer == CLIENT)
2896 {
2897 return false;
2898 }
2899
2900 if (players[player] == nullptr || players[player]->entity == nullptr)
2901 {
2902 return false;
2903 }
2904
2905 if (players[player]->entity->isBlind())
2906 {
2907 messagePlayer(player, language[775]);
2908 return false;
2909 }
2910
2911 if (player == clientnum)
2912 {
2913 conductIlliterate = false;
2914 }
2915
2916 if ( stats[player]->type != AUTOMATON )
2917 {
2918 serverUpdatePlayerGameplayStats(player, STATISTICS_FIRE_MAYBE_DIFFERENT, 1);
2919 }
2920
2921 item->identified = 1;
2922 if (item->beatitude < 0)
2923 {
2924 messagePlayer(player, language[863]);
2925 return false;
2926 }
2927 else
2928 {
2929 playSoundEntity(players[player]->entity, 153, 128); // "FireballExplode.ogg"
2930 messagePlayer(player, language[864]); // "The scroll erupts in a tower of flame!"
2931
2932 // Attempt to set the Player on fire
2933 players[player]->entity->SetEntityOnFire();
2934
2935 int c;
2936 for (c = 0; c < 100; c++)
2937 {
2938 Entity* entity = spawnFlame(players[player]->entity, SPRITE_FLAME);
2939 entity->sprite = 16;
2940 double vel = rand() % 10;
2941 entity->vel_x = vel * cos(entity->yaw) * cos(entity->pitch) * .1;
2942 entity->vel_y = vel * sin(entity->yaw) * cos(entity->pitch) * .1;
2943 entity->vel_z = vel * sin(entity->pitch) * .2;
2944 entity->skill[0] = 5 + rand() % 10;
2945 }
2946 return true;
2947 }
2948 return false;
2949 }
2950
item_ScrollFood(Item * item,int player)2951 void item_ScrollFood(Item* item, int player)
2952 {
2953 Item* target;
2954 node_t* node, *nextnode;
2955 int foundfood = 0;
2956
2957 if (players[player] == nullptr || players[player]->entity == nullptr)
2958 {
2959 return;
2960 }
2961
2962 // this is a CLIENT function
2963 if (player != clientnum)
2964 {
2965 return;
2966 }
2967
2968 if (players[player]->entity->isBlind())
2969 {
2970 messagePlayer(player, language[775]);
2971 return;
2972 }
2973
2974 if ( player == clientnum )
2975 {
2976 conductIlliterate = false;
2977 }
2978 item->identified = 1;
2979 messagePlayer(player, language[848]);
2980 if ( item->beatitude >= 0 )
2981 {
2982 messagePlayer(player, language[865]);
2983 dropItem(newItem(FOOD_FISH, EXCELLENT, item->beatitude, 1, rand(), true, &stats[player]->inventory), player);
2984 dropItem(newItem(FOOD_BREAD, EXCELLENT, item->beatitude, 1, rand(), true, &stats[player]->inventory), player);
2985 dropItem(newItem(FOOD_APPLE, EXCELLENT, item->beatitude, 1, rand(), true, &stats[player]->inventory), player);
2986 dropItem(newItem(FOOD_CHEESE, EXCELLENT, item->beatitude, 1, rand(), true, &stats[player]->inventory), player);
2987 dropItem(newItem(FOOD_MEAT, EXCELLENT, item->beatitude, 1, rand(), true, &stats[player]->inventory), player);
2988 return;
2989 }
2990 else
2991 {
2992 for ( node = stats[player]->inventory.first; node != NULL; node = nextnode )
2993 {
2994 nextnode = node->next;
2995 target = (Item*)node->element;
2996 if ( itemCategory(target) == FOOD )
2997 {
2998 if ( rand() % 2 == 0 ) // 50% chance of destroying that food item
2999 {
3000 consumeItem(target, player);
3001 }
3002 foundfood = 1;
3003 }
3004 }
3005 }
3006 if ( foundfood == 0 )
3007 {
3008 messagePlayer(player, language[866]);
3009 }
3010 else
3011 {
3012 messagePlayer(player, language[867]);
3013 }
3014 }
3015
item_ScrollConjureArrow(Item * item,int player)3016 void item_ScrollConjureArrow(Item* item, int player)
3017 {
3018 if ( players[player] == nullptr || players[player]->entity == nullptr )
3019 {
3020 return;
3021 }
3022
3023 // this is a CLIENT function
3024 if ( player != clientnum )
3025 {
3026 return;
3027 }
3028
3029 if ( players[player]->entity->isBlind() )
3030 {
3031 messagePlayer(player, language[775]);
3032 return;
3033 }
3034
3035 if ( player == clientnum )
3036 {
3037 conductIlliterate = false;
3038 }
3039 item->identified = 1;
3040 messagePlayer(player, language[848]);
3041 messagePlayer(player, language[3762]);
3042 ItemType type = static_cast<ItemType>(QUIVER_SILVER + rand() % 7);
3043
3044 int amount = 20 + rand() % 6;
3045 if ( item->beatitude < 0 )
3046 {
3047 amount -= (15 + rand() % 6);
3048 }
3049 else if ( item->beatitude > 0 )
3050 {
3051 amount += 20 + rand() % 6;
3052 }
3053 dropItem(newItem(type, SERVICABLE, item->beatitude, amount, ITEM_GENERATED_QUIVER_APPEARANCE, false, &stats[player]->inventory), player, false);
3054 if ( item->beatitude >= 2 )
3055 {
3056 // re-roll!
3057 type = static_cast<ItemType>(QUIVER_SILVER + rand() % 7);
3058 amount = 40 + rand() % 11;
3059 dropItem(newItem(type, SERVICABLE, item->beatitude, amount, ITEM_GENERATED_QUIVER_APPEARANCE, false, &stats[player]->inventory), player, false);
3060 }
3061 }
3062
item_ScrollMagicMapping(Item * item,int player)3063 void item_ScrollMagicMapping(Item* item, int player)
3064 {
3065 int x, y;
3066
3067 if (players[player] == nullptr || players[player]->entity == nullptr)
3068 {
3069 return;
3070 }
3071
3072 // this is a CLIENT function
3073 if (multiplayer == SERVER && player > 0)
3074 {
3075 return;
3076 }
3077
3078 if (players[player]->entity->isBlind())
3079 {
3080 messagePlayer(player, language[775]);
3081 return;
3082 }
3083
3084 if ( player == clientnum )
3085 {
3086 conductIlliterate = false;
3087 }
3088 item->identified = 1;
3089 messagePlayer(player, language[848]);
3090 if ( item->beatitude >= 0 )
3091 {
3092 messagePlayer(player, language[868]);
3093 mapLevel(player);
3094 }
3095 else
3096 {
3097 messagePlayer(player, language[869]);
3098 for ( y = 0; y < map.height; y++ )
3099 {
3100 for ( x = 0; x < map.width; x++ )
3101 {
3102 minimap[y][x] = 0;
3103 }
3104 }
3105 }
3106 }
3107
item_ScrollRepair(Item * item,int player)3108 void item_ScrollRepair(Item* item, int player)
3109 {
3110 Item* armor = nullptr;
3111 if (players[player] == nullptr || players[player]->entity == nullptr)
3112 {
3113 return;
3114 }
3115
3116 // client function only
3117 if ( player != clientnum )
3118 {
3119 consumeItem(item, player);
3120 return;
3121 }
3122
3123 if (players[player]->entity->isBlind())
3124 {
3125 messagePlayer(player, language[775]);
3126 return;
3127 }
3128
3129 conductIlliterate = false;
3130 if ( item->identified && item->beatitude >= 0 )
3131 {
3132 // quickly check if we have any items available so we don't waste our scroll
3133 bool foundRepairableItem = false;
3134 for ( node_t* node = stats[player]->inventory.first; node != nullptr; node = node->next )
3135 {
3136 Item* inventoryItem = (Item*)node->element;
3137 if ( GenericGUI.isItemRepairable(inventoryItem, item->type) )
3138 {
3139 foundRepairableItem = true;
3140 break;
3141 }
3142 }
3143 if ( !foundRepairableItem )
3144 {
3145 if ( item->type == SCROLL_REPAIR )
3146 {
3147 messagePlayer(player, language[3288]);
3148 }
3149 else if ( item->type == SCROLL_CHARGING )
3150 {
3151 messagePlayer(player, language[3731]);
3152 }
3153 return;
3154 }
3155 }
3156
3157 item->identified = true;
3158 messagePlayer(player, language[848]);
3159 if ( item->beatitude < 0 )
3160 {
3161 int tryIndex = rand() % 7;
3162 int startIndex = tryIndex;
3163 int armornum = 0;
3164 bool breakloop = false;
3165 // degrade random equipped item.
3166 while ( !armor && !breakloop )
3167 {
3168 switch ( tryIndex )
3169 {
3170 // intentional fall throughs...
3171 case 0:
3172 if ( stats[player]->weapon != nullptr && itemCategory(stats[player]->weapon) != POTION )
3173 {
3174 armor = stats[player]->weapon;
3175 armornum = 0;
3176 break;
3177 }
3178 case 1:
3179 if ( stats[player]->helmet != nullptr )
3180 {
3181 armor = stats[player]->helmet;
3182 armornum = 1;
3183 break;
3184 }
3185 case 2:
3186 if ( stats[player]->breastplate != nullptr )
3187 {
3188 armor = stats[player]->breastplate;
3189 armornum = 2;
3190 break;
3191 }
3192 case 3:
3193 if ( stats[player]->gloves != nullptr )
3194 {
3195 armor = stats[player]->gloves;
3196 armornum = 3;
3197 break;
3198 }
3199 case 4:
3200 if ( stats[player]->shoes != nullptr )
3201 {
3202 armor = stats[player]->shoes;
3203 armornum = 4;
3204 break;
3205 }
3206 case 5:
3207 if ( stats[player]->shield != nullptr )
3208 {
3209 armor = stats[player]->shield;
3210 armornum = 5;
3211 break;
3212 }
3213 case 6:
3214 if ( stats[player]->cloak != nullptr )
3215 {
3216 armor = stats[player]->cloak;
3217 armornum = 6;
3218 break;
3219 }
3220 ++tryIndex;
3221 if ( tryIndex > 6 )
3222 {
3223 // loop back around.
3224 tryIndex = 0;
3225 }
3226 if ( tryIndex == startIndex )
3227 {
3228 // couldn't find a piece of armor, break.
3229 breakloop = true;
3230 armor = nullptr;
3231 break;
3232 }
3233 default:
3234 break;
3235 }
3236 }
3237 if ( armor == nullptr )
3238 {
3239 messagePlayer(player, language[870]); // you feel a tingling sensation
3240 }
3241 else if ( armor != nullptr )
3242 {
3243 messagePlayer(player, language[871], armor->getName());
3244 if ( item->type == SCROLL_CHARGING )
3245 {
3246 armor->status = BROKEN;
3247 }
3248 else
3249 {
3250 armor->status = static_cast<Status>(std::max(armor->status - 2, static_cast<int>(BROKEN)));
3251 }
3252 if ( multiplayer == CLIENT )
3253 {
3254 strcpy((char*)net_packet->data, "REPA");
3255 net_packet->data[4] = clientnum;
3256 net_packet->data[5] = armornum;
3257 net_packet->data[6] = armor->status;
3258 net_packet->address.host = net_server.host;
3259 net_packet->address.port = net_server.port;
3260 net_packet->len = 7;
3261 sendPacketSafe(net_sock, -1, net_packet, 0);
3262
3263 //messagePlayer(clientnum, "sent server: %d, %d, %d", net_packet->data[4], net_packet->data[5], net_packet->data[6]);
3264 }
3265 if ( armor->status > BROKEN )
3266 {
3267 if ( armor->type == TOOL_CRYSTALSHARD )
3268 {
3269 messagePlayer(player, language[2350], armor->getName());
3270 }
3271 else
3272 {
3273 messagePlayer(player, language[681], armor->getName());
3274 }
3275 }
3276 else
3277 {
3278 if ( armor->type == TOOL_CRYSTALSHARD )
3279 {
3280 playSoundPlayer(player, 162, 64);
3281 messagePlayer(player, language[2351], armor->getName());
3282 }
3283 else
3284 {
3285 playSoundPlayer(player, 76, 64);
3286 messagePlayer(player, language[682], armor->getName());
3287 }
3288 }
3289 }
3290 }
3291 else
3292 {
3293 // Repair an item
3294 GenericGUI.openGUI(GUI_TYPE_REPAIR, item->beatitude, item->type);
3295 }
3296 consumeItem(item, player);
3297 }
3298
item_ScrollDestroyArmor(Item * item,int player)3299 void item_ScrollDestroyArmor(Item* item, int player)
3300 {
3301 Item* armor = nullptr;
3302 if (players[player] == nullptr || players[player]->entity == nullptr)
3303 {
3304 return;
3305 }
3306
3307 // client function only
3308 if ( player != clientnum )
3309 {
3310 consumeItem(item, player);
3311 return;
3312 }
3313
3314 if (players[player]->entity->isBlind())
3315 {
3316 messagePlayer(player, language[775]);
3317 return;
3318 }
3319
3320 conductIlliterate = false;
3321 item->identified = 1;
3322
3323 messagePlayer(player, language[848]);
3324
3325 int armornum = 0;
3326 int tryIndex = 1 + rand() % 6;
3327 int startIndex = tryIndex;
3328 bool breakloop = false;
3329 while ( !armor && !breakloop )
3330 {
3331 switch ( tryIndex )
3332 {
3333 // intentional fall throughs...
3334 case 0:
3335 // shouldn't occur
3336 /*if ( stats[player]->weapon != nullptr )
3337 {
3338 armor = stats[player]->weapon;
3339 armornum = 0;
3340 break;
3341 }*/
3342 case 1:
3343 if ( stats[player]->helmet != nullptr )
3344 {
3345 armor = stats[player]->helmet;
3346 armornum = 1;
3347 break;
3348 }
3349 case 2:
3350 if ( stats[player]->breastplate != nullptr )
3351 {
3352 armor = stats[player]->breastplate;
3353 armornum = 2;
3354 break;
3355 }
3356 case 3:
3357 if ( stats[player]->gloves != nullptr )
3358 {
3359 armor = stats[player]->gloves;
3360 armornum = 3;
3361 break;
3362 }
3363 case 4:
3364 if ( stats[player]->shoes != nullptr )
3365 {
3366 armor = stats[player]->shoes;
3367 armornum = 4;
3368 break;
3369 }
3370 case 5:
3371 if ( stats[player]->shield != nullptr )
3372 {
3373 armor = stats[player]->shield;
3374 armornum = 5;
3375 break;
3376 }
3377 case 6:
3378 if ( stats[player]->cloak != nullptr )
3379 {
3380 armor = stats[player]->cloak;
3381 armornum = 6;
3382 break;
3383 }
3384 ++tryIndex;
3385 if ( tryIndex > 6 )
3386 {
3387 // loop back around.
3388 tryIndex = 1;
3389 }
3390 if ( tryIndex == startIndex )
3391 {
3392 // couldn't find a piece of armor, break.
3393 breakloop = true;
3394 armor = nullptr;
3395 break;
3396 }
3397 default:
3398 break;
3399 }
3400 }
3401
3402 if ( armor == nullptr )
3403 {
3404 messagePlayer(player, language[873]);
3405 }
3406 else if ( armor != nullptr )
3407 {
3408 if ( item->beatitude < 0 )
3409 {
3410 messagePlayer(player, language[874], armor->getName());
3411 }
3412 else
3413 {
3414 messagePlayer(player, language[875], armor->getName());
3415
3416 armor->status = static_cast<Status>(0);
3417
3418 if ( multiplayer == CLIENT )
3419 {
3420 strcpy((char*)net_packet->data, "REPA");
3421 net_packet->data[4] = clientnum;
3422 net_packet->data[5] = armornum;
3423 net_packet->data[6] = armor->status;
3424 net_packet->address.host = net_server.host;
3425 net_packet->address.port = net_server.port;
3426 net_packet->len = 7;
3427 sendPacketSafe(net_sock, -1, net_packet, 0);
3428
3429 //messagePlayer(clientnum, "sent server: %d, %d, %d", net_packet->data[4], net_packet->data[5], net_packet->data[6]);
3430 }
3431
3432 if ( armor->status == BROKEN )
3433 {
3434 if ( armor->type == TOOL_CRYSTALSHARD )
3435 {
3436 playSoundPlayer(player, 162, 64);
3437 messagePlayer(player, language[2351], armor->getName());
3438 }
3439 else
3440 {
3441 playSoundPlayer(player, 76, 64);
3442 messagePlayer(player, language[682], armor->getName());
3443 }
3444 }
3445 }
3446 }
3447 consumeItem(item, player);
3448 }
3449
item_ScrollTeleportation(Item * item,int player)3450 void item_ScrollTeleportation(Item* item, int player)
3451 {
3452 // server only function
3453 if (players[player] == nullptr || players[player]->entity == nullptr)
3454 {
3455 return;
3456 }
3457 if (multiplayer == CLIENT)
3458 {
3459 return;
3460 }
3461
3462 if (players[player]->entity->isBlind())
3463 {
3464 if (player == clientnum)
3465 {
3466 messagePlayer(player, language[775]);
3467 }
3468 return;
3469 }
3470
3471 if (player == clientnum)
3472 {
3473 conductIlliterate = false;
3474 }
3475 item->identified = 1;
3476 messagePlayer(player, language[848]);
3477 if (item->beatitude < 0 && rand() % 2)
3478 {
3479 messagePlayer(player, language[876]);
3480 return;
3481 }
3482
3483 players[player]->entity->teleportRandom();
3484 }
3485
item_ScrollSummon(Item * item,int player)3486 void item_ScrollSummon(Item* item, int player)
3487 {
3488 // server only function
3489 if (players[player] == nullptr || players[player]->entity == nullptr)
3490 {
3491 return;
3492 }
3493 if (multiplayer == CLIENT)
3494 {
3495 return;
3496 }
3497
3498 if (players[player]->entity->isBlind())
3499 {
3500 if (player == clientnum)
3501 {
3502 messagePlayer(player, language[775]);
3503 }
3504 return;
3505 }
3506
3507 if ( player == clientnum )
3508 {
3509 conductIlliterate = false;
3510 }
3511 item->identified = 1;
3512 messagePlayer(player, language[848]);
3513
3514 playSoundEntity(players[player]->entity, 153, 64);
3515 Uint32 numCreatures = 1;
3516 Monster creature = RAT;
3517
3518 if (item->beatitude <= -2)
3519 {
3520 // spawn something really nasty
3521 numCreatures = 1;
3522 switch (rand() % 4)
3523 {
3524 case 0:
3525 creature = MINOTAUR;
3526 break;
3527 case 1:
3528 creature = DEMON;
3529 break;
3530 case 2:
3531 creature = CREATURE_IMP;
3532 break;
3533 case 3:
3534 creature = TROLL;
3535 break;
3536 }
3537 }
3538 else if (item->beatitude == -1)
3539 {
3540 // spawn moderately nasty things
3541 switch (rand() % 6)
3542 {
3543 case 0:
3544 creature = GNOME;
3545 numCreatures = rand() % 3 + 1;
3546 break;
3547 case 1:
3548 creature = SPIDER;
3549 numCreatures = rand() % 2 + 1;
3550 break;
3551 case 2:
3552 creature = SUCCUBUS;
3553 numCreatures = rand() % 2 + 1;
3554 break;
3555 case 3:
3556 creature = SCORPION;
3557 numCreatures = rand() % 2 + 1;
3558 break;
3559 case 4:
3560 creature = GHOUL;
3561 numCreatures = rand() % 2 + 1;
3562 break;
3563 case 5:
3564 creature = GOBLIN;
3565 numCreatures = rand() % 2 + 1;
3566 break;
3567 }
3568 }
3569 else if (item->beatitude == 0)
3570 {
3571 // spawn weak monster ally
3572 switch (rand() % 3)
3573 {
3574 case 0:
3575 creature = RAT;
3576 numCreatures = rand() % 3 + 1;
3577 break;
3578 case 1:
3579 creature = GHOUL;
3580 numCreatures = 1;
3581 break;
3582 case 2:
3583 creature = SLIME;
3584 numCreatures = rand() % 2 + 1;
3585 break;
3586 }
3587 }
3588 else if (item->beatitude == 1)
3589 {
3590 // spawn humans
3591 creature = HUMAN;
3592 numCreatures = rand() % 3 + 1;
3593 }
3594 else if (item->beatitude >= 2)
3595 {
3596 //Spawn many/neat allies
3597 switch (rand() % 2)
3598 {
3599 case 0:
3600 // summon zap brigadiers
3601 numCreatures = rand() % 2 + 4;
3602 creature = HUMAN;
3603 break;
3604 case 1:
3605 // summon demons
3606 numCreatures = rand() % 2 + 4;
3607 creature = DEMON;
3608 break;
3609 }
3610 }
3611
3612 int i;
3613 bool spawnedMonster = false;
3614 for (i = 0; i < numCreatures; ++i)
3615 {
3616 Entity* monster = summonMonster(creature, floor(players[player]->entity->x / 16) * 16 + 8, floor(players[player]->entity->y / 16) * 16 + 8);
3617 if ( monster )
3618 {
3619 spawnedMonster = true;
3620 if ( item->beatitude >= 2 && creature == HUMAN )
3621 {
3622 monster->skill[29] = 1; // zap brigadier
3623 }
3624 Stat* monsterStats = monster->getStats();
3625 if ( item->beatitude >= 0 && monsterStats )
3626 {
3627 monsterStats->leader_uid = players[player]->entity->getUID();
3628 monster->flags[USERFLAG2] = true;
3629 /*if ( !monsterally[HUMAN][monsterStats->type] )
3630 {
3631 }*/
3632 monster->monsterAllyIndex = player;
3633 if ( multiplayer == SERVER )
3634 {
3635 serverUpdateEntitySkill(monster, 42); // update monsterAllyIndex for clients.
3636 }
3637
3638 // update followers for this player
3639 node_t* newNode = list_AddNodeLast(&stats[player]->FOLLOWERS);
3640 newNode->deconstructor = &defaultDeconstructor;
3641 Uint32* myuid = (Uint32*) malloc(sizeof(Uint32));
3642 newNode->element = myuid;
3643 *myuid = monster->getUID();
3644
3645 // update client followers
3646 if ( player > 0 && multiplayer == SERVER )
3647 {
3648 strcpy((char*)net_packet->data, "LEAD");
3649 SDLNet_Write32((Uint32)monster->getUID(), &net_packet->data[4]);
3650 strcpy((char*)(&net_packet->data[8]), monsterStats->name);
3651 net_packet->data[8 + strlen(monsterStats->name)] = 0;
3652 net_packet->address.host = net_clients[player - 1].host;
3653 net_packet->address.port = net_clients[player - 1].port;
3654 net_packet->len = 8 + strlen(monsterStats->name) + 1;
3655 sendPacketSafe(net_sock, -1, net_packet, player - 1);
3656
3657 serverUpdateAllyStat(player, monster->getUID(), monsterStats->LVL, monsterStats->HP, monsterStats->MAXHP, monsterStats->type);
3658 }
3659
3660 if ( !FollowerMenu.recentEntity && player == clientnum )
3661 {
3662 FollowerMenu.recentEntity = monster;
3663 }
3664 }
3665 }
3666 }
3667 if ( spawnedMonster )
3668 {
3669 if ( item->beatitude < 0 )
3670 {
3671 if ( numCreatures <= 1 )
3672 {
3673 if ( creature < KOBOLD ) //Original monster count
3674 {
3675 messagePlayer(player, language[877], language[90 + creature]);
3676
3677 }
3678 else if ( creature >= KOBOLD ) //New monsters
3679 {
3680 messagePlayer(player, language[877], language[2000 + (creature - KOBOLD)]);
3681 }
3682 }
3683 else
3684 {
3685 if ( creature < KOBOLD ) //Original monster count
3686 {
3687 messagePlayer(player, language[878], language[111 + creature]);
3688
3689 }
3690 else if ( creature >= KOBOLD ) //New monsters
3691 {
3692 messagePlayer(player, language[878], language[2050 + (creature - KOBOLD)]);
3693 }
3694 }
3695 }
3696 else
3697 {
3698 if ( numCreatures <= 1 )
3699 {
3700 if ( creature < KOBOLD ) //Original monster count
3701 {
3702 messagePlayer(player, language[879], language[90 + creature]);
3703
3704 }
3705 else if ( creature >= KOBOLD ) //New monsters
3706 {
3707 messagePlayer(player, language[879], language[2000 + (creature - KOBOLD)]);
3708 }
3709 if ( item->beatitude >= 2 )
3710 {
3711 messagePlayer(player, language[880]);
3712 }
3713 }
3714 else
3715 {
3716 if ( creature < KOBOLD ) //Original monster count
3717 {
3718 messagePlayer(player, language[881], language[111 + creature]);
3719
3720 }
3721 else if ( creature >= KOBOLD ) //New monsters
3722 {
3723 messagePlayer(player, language[881], language[2050 + (creature - KOBOLD)]);
3724 }
3725 if ( item->beatitude >= 2 )
3726 {
3727 messagePlayer(player, language[882]);
3728 }
3729 }
3730 }
3731 }
3732 }
3733
item_ToolTowel(Item * & item,int player)3734 void item_ToolTowel(Item*& item, int player)
3735 {
3736 if ( player == clientnum )
3737 {
3738 messagePlayer(player, language[883]);
3739 }
3740 if ( multiplayer != CLIENT )
3741 {
3742 if ( stats[player]->EFFECTS[EFF_GREASY]
3743 || stats[player]->EFFECTS[EFF_MESSY]
3744 || stats[player]->EFFECTS[EFF_BLEEDING] )
3745 {
3746 steamAchievementClient(player, "BARONY_ACH_BRING_A_TOWEL");
3747 }
3748 stats[player]->EFFECTS[EFF_GREASY] = false;
3749 stats[player]->EFFECTS[EFF_MESSY] = false;
3750 }
3751
3752 // stop bleeding
3753 if ( stats[player]->EFFECTS[EFF_BLEEDING] )
3754 {
3755 if ( player == clientnum )
3756 {
3757 messagePlayer(player, language[884]);
3758 messagePlayer(player, language[885]);
3759 }
3760 if ( multiplayer != CLIENT )
3761 {
3762 stats[player]->EFFECTS[EFF_BLEEDING] = false;
3763 stats[player]->EFFECTS_TIMERS[EFF_BLEEDING] = 0;
3764 }
3765 consumeItem(item, player);
3766 }
3767
3768 if ( multiplayer != CLIENT )
3769 {
3770 serverUpdateEffects(player);
3771 }
3772 }
3773
item_ToolTinOpener(Item * item,int player)3774 void item_ToolTinOpener(Item* item, int player)
3775 {
3776 if (multiplayer == CLIENT)
3777 {
3778 return;
3779 }
3780
3781 messagePlayer(player, language[886]);
3782 }
3783
item_ToolMirror(Item * & item,int player)3784 void item_ToolMirror(Item*& item, int player)
3785 {
3786 if (players[player] == nullptr || players[player]->entity == nullptr)
3787 {
3788 return;
3789 }
3790
3791 if ( player == clientnum )
3792 {
3793 messagePlayer(player, language[889]);
3794 }
3795 if ( players[player]->entity->isInvisible() || (stats[player] && stats[player]->type == VAMPIRE) )
3796 {
3797 if ( player == clientnum )
3798 {
3799 messagePlayer(player, language[893]);
3800 }
3801 return;
3802 }
3803 else if ( stats[player] && stats[player]->type == AUTOMATON )
3804 {
3805 messagePlayer(player, language[3698]);
3806 }
3807
3808 if (item->beatitude > 0 && !stats[player]->EFFECTS[EFF_GREASY])
3809 {
3810 if (multiplayer != CLIENT)
3811 {
3812 players[player]->entity->teleportRandom();
3813 }
3814 }
3815 if (player != clientnum) //TODO: Hotseat? (player != clientnum || !players[player]->hotseat
3816 {
3817 return;
3818 }
3819
3820 if ( stats[player]->EFFECTS[EFF_GREASY] )
3821 {
3822 messagePlayer(player, language[887]);
3823 messagePlayer(player, language[888]);
3824 consumeItem(item, player);
3825 return;
3826 }
3827 if ( stats[player]->EFFECTS[EFF_BLIND] )
3828 {
3829 messagePlayer(player, language[892]);
3830 return;
3831 }
3832 if ( item->beatitude > 0 )
3833 {
3834 messagePlayer(player, language[890]);
3835 return;
3836 }
3837 else if ( item->beatitude < 0 )
3838 {
3839 if ( stats[player]->EFFECTS[EFF_BLIND] )
3840 {
3841 messagePlayer(player, language[892]);
3842 }
3843 else
3844 {
3845 messagePlayer(player, language[891]);
3846 }
3847 consumeItem(item, player);
3848 return;
3849 }
3850 if ( stats[player]->EFFECTS[EFF_DRUNK] )
3851 {
3852 if ( stats[player]->sex == MALE )
3853 {
3854 messagePlayer(player, language[894]);
3855 }
3856 else
3857 {
3858 messagePlayer(player, language[895]);
3859 }
3860 return;
3861 }
3862 if ( stats[player]->EFFECTS[EFF_CONFUSED] )
3863 {
3864 messagePlayer(player, language[896]);
3865 return;
3866 }
3867 if ( stats[player]->EFFECTS[EFF_POISONED] )
3868 {
3869 messagePlayer(player, language[897]);
3870 return;
3871 }
3872 if ( stats[player]->EFFECTS[EFF_VOMITING] )
3873 {
3874 messagePlayer(player, language[898]);
3875 return;
3876 }
3877 if ( stats[player]->EFFECTS[EFF_MESSY] )
3878 {
3879 messagePlayer(player, language[899]);
3880 return;
3881 }
3882 if ( stats[player]->HUNGER < 200 )
3883 {
3884 messagePlayer(player, language[900]);
3885 return;
3886 }
3887 if ( stats[player]->HUNGER < 500 )
3888 {
3889 messagePlayer(player, language[901]);
3890 return;
3891 }
3892
3893 if ( stats[player]->CHR < 2 )
3894 {
3895 messagePlayer(player, language[902]);
3896 return;
3897 }
3898 else
3899 {
3900 if ( stats[player]->sex == MALE )
3901 {
3902 messagePlayer(player, language[903]);
3903 }
3904 else
3905 {
3906 messagePlayer(player, language[904]);
3907 }
3908 return;
3909 }
3910 }
3911
item_ToolBeartrap(Item * & item,int player)3912 void item_ToolBeartrap(Item*& item, int player)
3913 {
3914 Entity* entity;
3915
3916 int u, v;
3917 if ( players[player] && players[player]->entity )
3918 {
3919 int x = std::min(std::max<unsigned int>(1, players[player]->entity->x / 16), map.width - 2);
3920 int y = std::min(std::max<unsigned int>(1, players[player]->entity->y / 16), map.height - 2);
3921 for ( u = x - 1; u <= x + 1; u++ )
3922 {
3923 for ( v = y - 1; v <= y + 1; v++ )
3924 {
3925 if ( entityInsideTile(players[player]->entity, u, v, 0) ) // no floor
3926 {
3927 if ( multiplayer != CLIENT )
3928 {
3929 messagePlayer(player, language[3035]);
3930 }
3931 return;
3932 }
3933 }
3934 }
3935 }
3936
3937 if ( multiplayer == CLIENT )
3938 {
3939 consumeItem(item, player);
3940 return;
3941 }
3942 bool failed = false;
3943 switch ( item->status )
3944 {
3945 case SERVICABLE:
3946 if ( rand() % 25 == 0 )
3947 {
3948 failed = true;
3949 }
3950 break;
3951 case WORN:
3952 if ( rand() % 10 == 0 )
3953 {
3954 failed = true;
3955 }
3956 break;
3957 case DECREPIT:
3958 if ( rand() % 4 == 0 )
3959 {
3960 failed = true;
3961 }
3962 break;
3963 default:
3964 break;
3965 }
3966 if (item->beatitude < 0 || failed)
3967 {
3968 if (player == clientnum)
3969 {
3970 messagePlayer(player, language[905]);
3971 }
3972 if (multiplayer != CLIENT)
3973 {
3974 playSoundEntity(players[player]->entity, 76, 64);
3975 }
3976 consumeItem(item, player);
3977 return;
3978 }
3979 if ( multiplayer != CLIENT )
3980 {
3981 playSoundEntity(players[player]->entity, 253, 64);
3982 }
3983 entity = newEntity(668, 1, map.entities, nullptr); //Beartrap entity.
3984 entity->behavior = &actBeartrap;
3985 entity->flags[PASSABLE] = true;
3986 entity->flags[UPDATENEEDED] = true;
3987 entity->x = players[player]->entity->x;
3988 entity->y = players[player]->entity->y;
3989 entity->z = 6.75;
3990 entity->yaw = players[player]->entity->yaw;
3991 entity->roll = -PI / 2; // flip the model
3992 entity->parent = players[player]->entity->getUID();
3993 entity->sizex = 4;
3994 entity->sizey = 4;
3995 entity->skill[11] = item->status;
3996 entity->skill[12] = item->beatitude;
3997 entity->skill[14] = item->appearance;
3998 entity->skill[15] = item->identified;
3999 entity->skill[17] = players[player]->entity->skill[2];
4000 messagePlayer(player, language[906]);
4001 consumeItem(item, player);
4002 return;
4003 }
4004
item_Food(Item * & item,int player)4005 void item_Food(Item*& item, int player)
4006 {
4007 int oldcount;
4008 int pukeChance;
4009
4010 if ( !stats[player] )
4011 {
4012 return;
4013 }
4014
4015 if ( player >= 0 && stats[player]->type == AUTOMATON )
4016 {
4017 if ( players[player] && players[player]->entity )
4018 {
4019 item_FoodAutomaton(item, player);
4020 }
4021 return;
4022 }
4023
4024 if ( player >= 0 && stats[player]->type != HUMAN && (svFlags & SV_FLAG_HUNGER) ) // hunger on
4025 {
4026 if ( stats[player]->type == SKELETON )
4027 {
4028 if ( player == clientnum )
4029 {
4030 steamAchievement("BARONY_ACH_BONEHEADED");
4031 dropItem(item, player); // client drop item
4032 messagePlayer(clientnum, language[3179]);
4033 }
4034 return;
4035 }
4036 }
4037
4038 if ( stats[player]->amulet != NULL )
4039 {
4040 if ( stats[player]->amulet->type == AMULET_STRANGULATION )
4041 {
4042 if ( player == clientnum )
4043 {
4044 messagePlayer(player, language[756]);
4045 }
4046 return;
4047 }
4048 }
4049
4050 // can't eat while vomiting
4051 if ( stats[player]->EFFECTS[EFF_VOMITING] )
4052 {
4053 if ( player == clientnum )
4054 {
4055 messagePlayer(player, language[757]);
4056 }
4057 return;
4058 }
4059
4060 if ( player == clientnum )
4061 {
4062 conductFoodless = false;
4063 if ( item->type == FOOD_MEAT || item->type == FOOD_FISH || item->type == FOOD_TOMALLEY || item->type == FOOD_BLOOD )
4064 {
4065 conductVegetarian = false;
4066 }
4067 if ( stats[player]->playerRace == RACE_SKELETON && stats[player]->appearance == 0
4068 && players[player] && players[player]->entity->effectPolymorph > NUMMONSTERS )
4069 {
4070 steamAchievement("BARONY_ACH_MUSCLE_MEMORY");
4071 }
4072 }
4073
4074 if ( multiplayer == CLIENT )
4075 {
4076 consumeItem(item, player);
4077 return;
4078 }
4079
4080 // consumption message
4081 oldcount = item->count;
4082 item->count = 1;
4083 messagePlayer(player, language[907], item->description());
4084 item->count = oldcount;
4085
4086 // eating sound
4087 if ( item->type == FOOD_BLOOD )
4088 {
4089 // play drink sound
4090 playSoundEntity(players[player]->entity, 52, 64);
4091 }
4092 else
4093 {
4094 playSoundEntity(players[player]->entity, 50 + rand() % 2, 64);
4095 }
4096
4097 // chance of rottenness
4098 switch ( item->status )
4099 {
4100 case EXCELLENT:
4101 pukeChance = 100;
4102 break;
4103 case SERVICABLE:
4104 pukeChance = 25;
4105 break;
4106 case WORN:
4107 pukeChance = 10;
4108 break;
4109 case DECREPIT:
4110 pukeChance = 4;
4111 break;
4112 default:
4113 pukeChance = 100;
4114 break;
4115 }
4116
4117 if ( players[player]
4118 && players[player]->entity && players[player]->entity->playerRequiresBloodToSustain() )
4119 {
4120 if ( item->type == FOOD_BLOOD )
4121 {
4122 pukeChance = 100;
4123 }
4124 else if ( item->type != FOOD_BLOOD )
4125 {
4126 if ( stats[player]->type == VAMPIRE )
4127 {
4128 pukeChance = 1;
4129 }
4130 }
4131 }
4132 else if ( item->type == FOOD_BLOOD )
4133 {
4134 pukeChance = 1;
4135 }
4136
4137 if ( players[player] && players[player]->entity && players[player]->entity->effectShapeshift != NOTHING )
4138 {
4139 pukeChance = 100; // shapeshifted players don't puke
4140 }
4141 if ( player >= 0 && stats[player]->type == INSECTOID )
4142 {
4143 pukeChance = 100; // insectoids can eat anything.
4144 }
4145
4146 if (((item->beatitude < 0 && item->type != FOOD_CREAMPIE) || (rand() % pukeChance == 0)) && pukeChance < 100)
4147 {
4148 if (players[player] && players[player]->entity && !(svFlags & SV_FLAG_HUNGER))
4149 {
4150 playSoundEntity(players[player]->entity, 28, 64);
4151 players[player]->entity->modHP(-5);
4152 }
4153 if ( stats[player]->type == VAMPIRE )
4154 {
4155 messagePlayer(player, language[3201]);
4156 }
4157 else if ( item->type == FOOD_BLOOD )
4158 {
4159 messagePlayer(player, language[3203]);
4160 }
4161 else
4162 {
4163 messagePlayer(player, language[908]);
4164 }
4165 if ( stats[player] && players[player] && players[player]->entity )
4166 {
4167 if ( stats[player]->type != SKELETON
4168 && players[player]->entity->effectShapeshift == NOTHING
4169 && stats[player]->type != AUTOMATON )
4170 {
4171 players[player]->entity->skill[26] = 40 + rand() % 10;
4172 }
4173 }
4174 consumeItem(item, player);
4175 return;
4176 }
4177 if ( item->beatitude < 0 && item->type == FOOD_CREAMPIE )
4178 {
4179 messagePlayer(player, language[909]);
4180 messagePlayer(player, language[910]);
4181 stats[player]->EFFECTS[EFF_MESSY] = true;
4182 stats[player]->EFFECTS_TIMERS[EFF_MESSY] = 600; // ten seconds
4183 serverUpdateEffects(player);
4184 consumeItem(item, player);
4185 return;
4186 }
4187
4188 // replenish nutrition points
4189 if ( svFlags & SV_FLAG_HUNGER )
4190 {
4191 int hungerIncrease = 10;
4192 switch ( item->type )
4193 {
4194 case FOOD_BREAD:
4195 hungerIncrease = 400;
4196 break;
4197 case FOOD_CREAMPIE:
4198 hungerIncrease = 200;
4199 break;
4200 case FOOD_CHEESE:
4201 hungerIncrease = 100;
4202 break;
4203 case FOOD_APPLE:
4204 hungerIncrease = 200;
4205 break;
4206 case FOOD_MEAT:
4207 hungerIncrease = 600;
4208 break;
4209 case FOOD_FISH:
4210 hungerIncrease = 500;
4211 break;
4212 case FOOD_TOMALLEY:
4213 hungerIncrease = 400;
4214 break;
4215 case FOOD_BLOOD:
4216 if ( players[player] && players[player]->entity
4217 && players[player]->entity->playerRequiresBloodToSustain() )
4218 {
4219 hungerIncrease = 250;
4220 }
4221 else
4222 {
4223 hungerIncrease = 10;
4224 }
4225 break;
4226 default:
4227 hungerIncrease = 10;
4228 break;
4229 }
4230 stats[player]->HUNGER += hungerIncrease;
4231 }
4232 else
4233 {
4234 if (players[player] && players[player]->entity)
4235 {
4236 players[player]->entity->modHP(5);
4237 messagePlayer(player, language[911]);
4238
4239
4240 if ( stats[player]->playerRace == RACE_INSECTOID && stats[player]->appearance == 0 )
4241 {
4242 real_t manaRegenPercent = 0.f;
4243 switch ( item->type )
4244 {
4245 case FOOD_BREAD:
4246 case FOOD_TOMALLEY:
4247 manaRegenPercent = 0.4;
4248 break;
4249 case FOOD_CREAMPIE:
4250 manaRegenPercent = 0.2;
4251 break;
4252 case FOOD_CHEESE:
4253 manaRegenPercent = 0.1;
4254 break;
4255 case FOOD_APPLE:
4256 manaRegenPercent = 0.2;
4257 break;
4258 case FOOD_MEAT:
4259 case FOOD_FISH:
4260 manaRegenPercent = 0.5;
4261 break;
4262 case FOOD_BLOOD:
4263 if ( players[player] && players[player]->entity
4264 && players[player]->entity->playerRequiresBloodToSustain() )
4265 {
4266 manaRegenPercent = 0.25;
4267 }
4268 else
4269 {
4270 manaRegenPercent = 0.1;
4271 }
4272 break;
4273 default:
4274 break;
4275 }
4276 int manaAmount = stats[player]->MAXMP * manaRegenPercent;
4277 players[player]->entity->modMP(manaAmount);
4278 }
4279 }
4280 }
4281
4282 if ( item->type == FOOD_TOMALLEY )
4283 {
4284 serverUpdatePlayerGameplayStats(player, STATISTICS_TEMPT_FATE, 1);
4285 }
4286
4287 // results of eating
4288 if ( players[player] )
4289 {
4290 updateHungerMessages(players[player]->entity, stats[player], item);
4291 }
4292 consumeItem(item, player);
4293 }
4294
item_FoodTin(Item * & item,int player)4295 void item_FoodTin(Item*& item, int player)
4296 {
4297 int oldcount;
4298 int pukeChance;
4299 bool slippery = false;
4300
4301 if ( player >= 0 && stats[player]->type == AUTOMATON )
4302 {
4303 if ( players[player] && players[player]->entity )
4304 {
4305 item_FoodAutomaton(item, player);
4306 }
4307 return;
4308 }
4309
4310 if ( player >= 0 && stats[player]->type != HUMAN && (svFlags & SV_FLAG_HUNGER) ) // hunger on
4311 {
4312 if ( stats[player]->type == SKELETON )
4313 {
4314 if ( player == clientnum )
4315 {
4316 steamAchievement("BARONY_ACH_BONEHEADED");
4317 dropItem(item, player); // client drop item
4318 messagePlayer(clientnum, language[3179]);
4319 }
4320 return;
4321 }
4322 }
4323
4324 if ( stats[player]->amulet != NULL )
4325 {
4326 if ( stats[player]->amulet->type == AMULET_STRANGULATION )
4327 {
4328 if ( player == clientnum )
4329 {
4330 messagePlayer(player, language[756]);
4331 }
4332 return;
4333 }
4334 }
4335
4336 // can't eat while vomiting
4337 if ( stats[player]->EFFECTS[EFF_VOMITING] )
4338 {
4339 if ( player == clientnum )
4340 {
4341 messagePlayer(player, language[757]);
4342 }
4343 return;
4344 }
4345
4346 if ( player == clientnum )
4347 {
4348 conductFoodless = false;
4349 conductVegetarian = false;
4350 if ( stats[player]->playerRace == RACE_SKELETON && stats[player]->appearance == 0
4351 && players[player] && players[player]->entity->effectPolymorph > NUMMONSTERS )
4352 {
4353 steamAchievement("BARONY_ACH_MUSCLE_MEMORY");
4354 }
4355 if ( stats[player]->type == GOATMAN )
4356 {
4357 steamStatisticUpdate(STEAM_STAT_IRON_GUT, STEAM_STAT_INT, 1);
4358 }
4359 }
4360
4361 if ( multiplayer == CLIENT )
4362 {
4363 consumeItem(item, player);
4364 return;
4365 }
4366
4367 // consumption message
4368 char tempstr[128] = { 0 };
4369 oldcount = item->count;
4370 item->count = 1;
4371
4372 bool hpBuff = false;
4373 bool mpBuff = false;
4374
4375 // first word
4376 int word = rand() % 16;
4377 strcpy(tempstr, language[918 + word]);
4378 if ( word == 6 || word == 15 )
4379 {
4380 slippery = true;
4381 }
4382 if ( word < 8 )
4383 {
4384 hpBuff = true;
4385 }
4386
4387 // second word
4388 word = rand() % 16;
4389 strcat(tempstr, language[934 + word]);
4390 if ( word == 1 || word == 7 || word == 8 || word == 12 )
4391 {
4392 slippery = true;
4393 }
4394 if ( word >= 8 )
4395 {
4396 mpBuff = true;
4397 }
4398
4399 // third word
4400 word = rand() % 16;
4401 strcat(tempstr, language[950 + word]);
4402 if ( word == 1 || word == 8 )
4403 {
4404 slippery = true;
4405 }
4406 if ( word == 8 )
4407 {
4408 hpBuff = true;
4409 mpBuff = true;
4410 }
4411
4412 if ( stats[player]->type == GOATMAN )
4413 {
4414 messagePlayer(player, language[3220], tempstr);
4415 }
4416 else
4417 {
4418 messagePlayer(player, language[764], tempstr);
4419 }
4420 item->count = oldcount;
4421
4422 // eating sound
4423 playSoundEntity(players[player]->entity, 50 + rand() % 2, 64);
4424
4425 serverUpdatePlayerGameplayStats(player, STATISTICS_YES_WE_CAN, 1);
4426
4427 // chance of rottenness
4428 switch ( item->status )
4429 {
4430 case EXCELLENT:
4431 pukeChance = 100;
4432 break;
4433 case SERVICABLE:
4434 pukeChance = 25;
4435 break;
4436 case WORN:
4437 pukeChance = 10;
4438 break;
4439 case DECREPIT:
4440 pukeChance = 3;
4441 break;
4442 default:
4443 pukeChance = 100;
4444 break;
4445 }
4446
4447 if ( stats[player]->type == VAMPIRE )
4448 {
4449 pukeChance = 1;
4450 }
4451 else if ( stats[player]->type == INSECTOID )
4452 {
4453 pukeChance = 100; // insectoids can eat anything.
4454 }
4455
4456 if ((item->beatitude < 0 || rand() % pukeChance == 0) && pukeChance < 100)
4457 {
4458 if (players[player] && players[player]->entity && !(svFlags & SV_FLAG_HUNGER))
4459 {
4460 players[player]->entity->modHP(-5);
4461 }
4462 if ( stats[player]->type == VAMPIRE )
4463 {
4464 messagePlayer(player, language[3201]);
4465 }
4466 else
4467 {
4468 messagePlayer(player, language[908]);
4469 }
4470
4471 if ( stats[player] && players[player] && players[player]->entity )
4472 {
4473 if ( stats[player]->type != SKELETON
4474 && players[player]->entity->effectShapeshift == NOTHING
4475 && stats[player]->type != AUTOMATON )
4476 {
4477 players[player]->entity->skill[26] = 40 + rand() % 10;
4478 }
4479 }
4480 consumeItem(item, player);
4481 return;
4482 }
4483
4484 int buffDuration = item->status * TICKS_PER_SECOND * 4; // (4 - 16 seconds)
4485 if ( item->status > WORN )
4486 {
4487 buffDuration -= rand() % ((buffDuration / 2) + 1); // 50-100% duration
4488 }
4489 else
4490 {
4491 buffDuration -= rand() % ((buffDuration / 4) + 1); // 75-100% duration
4492 }
4493
4494 // replenish nutrition points
4495 if (svFlags & SV_FLAG_HUNGER)
4496 {
4497 stats[player]->HUNGER += 600;
4498 stats[player]->EFFECTS[EFF_HP_REGEN] = hpBuff;
4499 stats[player]->EFFECTS[EFF_MP_REGEN] = mpBuff;
4500 stats[player]->EFFECTS_TIMERS[EFF_HP_REGEN] = buffDuration;
4501 stats[player]->EFFECTS_TIMERS[EFF_MP_REGEN] = buffDuration;
4502 }
4503 else
4504 {
4505 if (players[player] && players[player]->entity)
4506 {
4507 players[player]->entity->modHP(5);
4508 }
4509 messagePlayer(player, language[911]);
4510 if ( stats[player]->playerRace == RACE_INSECTOID && stats[player]->appearance == 0 )
4511 {
4512 real_t manaRegenPercent = 0.6;
4513 int manaAmount = stats[player]->MAXMP * manaRegenPercent;
4514 players[player]->entity->modMP(manaAmount);
4515 }
4516 }
4517
4518 // greasy fingers
4519 if ( slippery )
4520 {
4521 messagePlayer(player, language[966]);
4522 stats[player]->EFFECTS[EFF_GREASY] = true;
4523 stats[player]->EFFECTS_TIMERS[EFF_GREASY] = TICKS_PER_SECOND * (60 + rand() % 60); // 1-2 minutes of greasy
4524 serverUpdateEffects(player);
4525 }
4526
4527 // results of eating
4528 if ( players[player] )
4529 {
4530 updateHungerMessages(players[player]->entity, stats[player], item);
4531 }
4532
4533 if ( (hpBuff || mpBuff) && (svFlags & SV_FLAG_HUNGER) )
4534 {
4535 messagePlayer(player, language[911]);
4536 }
4537
4538 consumeItem(item, player);
4539 }
4540
item_AmuletSexChange(Item * item,int player)4541 void item_AmuletSexChange(Item* item, int player)
4542 {
4543 if ( stats[player]->amulet != NULL )
4544 {
4545 if ( !stats[player]->amulet->canUnequip(stats[player]) )
4546 {
4547 if ( player == clientnum )
4548 {
4549 if ( shouldInvertEquipmentBeatitude(stats[player]) && item->beatitude > 0 )
4550 {
4551 messagePlayer(player, language[3218]);
4552 }
4553 else
4554 {
4555 messagePlayer(player, language[1087]);
4556 }
4557 }
4558 return;
4559 }
4560 }
4561 stats[player]->amulet = NULL;
4562 stats[player]->sex = static_cast<sex_t>((stats[player]->sex == 0));
4563
4564 if ( player != clientnum )
4565 {
4566 return;
4567 }
4568 if ( stats[player]->sex == MALE )
4569 {
4570 messagePlayer(player, language[967]);
4571 }
4572 else
4573 {
4574 messagePlayer(player, language[968]);
4575 }
4576 messagePlayer(player, language[969]);
4577 }
4578
item_Spellbook(Item * & item,int player)4579 void item_Spellbook(Item*& item, int player)
4580 {
4581 node_t* node, *nextnode;
4582
4583 item->identified = true;
4584 if (player != clientnum)
4585 {
4586 return;
4587 }
4588
4589 if (players[player]->entity->isBlind())
4590 {
4591 messagePlayer(player, language[970]);
4592 return;
4593 }
4594 if ( itemIsEquipped(item, clientnum) )
4595 {
4596 messagePlayer(player, language[3460]);
4597 return;
4598 }
4599
4600 if ( players[player] && players[player]->entity )
4601 {
4602 if ( players[player]->entity->effectShapeshift != NOTHING )
4603 {
4604 messagePlayer(player, language[3445]);
4605 return;
4606 }
4607 else if ( stats[player] && (stats[player]->type == GOBLIN || (stats[player]->playerRace == RACE_GOBLIN && stats[player]->appearance == 0)) )
4608 {
4609 messagePlayer(player, language[3444]);
4610 return;
4611 }
4612 }
4613
4614 conductIlliterate = false;
4615
4616 if ( item->beatitude < 0 && !shouldInvertEquipmentBeatitude(stats[player]) )
4617 {
4618 messagePlayer(clientnum, language[971]);
4619 if ( list_Size(&spellList) > 0 && stats[player]->type != AUTOMATON )
4620 {
4621 // randomly delete a spell
4622 int spellToDelete = rand() % list_Size(&spellList);
4623 node = list_Node(&spellList, spellToDelete);
4624 spell_t* spell = (spell_t*)node->element;
4625 int spellID = spell->ID;
4626 bool deleted = false;
4627 bool rerollSpell = false;
4628
4629 // delete its accompanying spell item(s)
4630
4631 if ( client_classes[clientnum] == CLASS_SHAMAN )
4632 {
4633 // don't forget your racial spells otherwise borked.
4634 // special roll checking.
4635 if ( list_Size(&spellList) <= CLASS_SHAMAN_NUM_STARTING_SPELLS )
4636 {
4637 // no spells to delete. return early.
4638 messagePlayer(clientnum, language[973]);
4639 consumeItem(item, player);
4640 return;
4641 }
4642 spellToDelete = rand() % (list_Size(&spellList) - CLASS_SHAMAN_NUM_STARTING_SPELLS);
4643 spellToDelete += CLASS_SHAMAN_NUM_STARTING_SPELLS; // e.g 16 spells is 0 + 15, 15th index.
4644 node = list_Node(&spellList, spellToDelete);
4645 spell = (spell_t*)node->element;
4646 spellID = spell->ID;
4647 }
4648
4649 for ( node_t* node2 = stats[player]->inventory.first; node2 != NULL; node2 = nextnode )
4650 {
4651 nextnode = node2->next;
4652 Item* itemInventory = (Item*)node2->element;
4653 if ( itemInventory && itemInventory->type == SPELL_ITEM )
4654 {
4655 if ( rerollSpell )
4656 {
4657 // Unused. But if ever shapeshift form spells get added to general classes then will need this checking.
4658 //if ( itemInventory->appearance < 1000 )
4659 //{
4660 // // can delete non-shapeshift spells. let's delete this one.
4661 // spell = getSpellFromItem(itemInventory);
4662 // if ( spell )
4663 // {
4664 // spellID = spell->ID;
4665 // if ( spellID == SPELL_RAT_FORM || spellID == SPELL_SPIDER_FORM
4666 // || spellID == SPELL_TROLL_FORM || spellID == SPELL_IMP_FORM
4667 // || spellID == SPELL_REVERT_FORM )
4668 // {
4669 // continue;
4670 // }
4671 // // find the node in spellList for the ID
4672 // spellToDelete = 0;
4673 // for ( node_t* tmpNode = spellList.first; tmpNode != nullptr; tmpNode = tmpNode->next )
4674 // {
4675 // if ( tmpNode->element )
4676 // {
4677 // spell_t* tmpSpell = (spell_t*)tmpNode->element;
4678 // if ( tmpSpell && tmpSpell->ID == spellID )
4679 // {
4680 // // found the node in the list, delete this one.
4681 // node = list_Node(&spellList, spellToDelete);
4682 // list_RemoveNode(node2); // delete inventory spell.
4683 // deleted = true;
4684 // break;
4685 // }
4686 // }
4687 // ++spellToDelete;
4688 // }
4689 // if ( deleted )
4690 // {
4691 // break;
4692 // }
4693 // }
4694 //}
4695 }
4696 else if ( itemInventory->appearance == spellID )
4697 {
4698 list_RemoveNode(node2); // delete inventory spell.
4699 deleted = true;
4700 break;
4701 }
4702 }
4703 }
4704
4705 //messagePlayer(0, "%d, %d %d", rerollSpell, spellToDelete, deleted);
4706
4707 if ( !deleted )
4708 {
4709 // maybe we've got an inventory full of shapeshift spells?
4710 messagePlayer(clientnum, language[973]);
4711 consumeItem(item, player);
4712 return;
4713 }
4714 else if ( deleted )
4715 {
4716 messagePlayer(clientnum, language[972]);
4717 if ( spell == selected_spell )
4718 {
4719 selected_spell = nullptr;
4720 }
4721 for ( int i = 0; i < NUM_HOTBAR_ALTERNATES; ++i )
4722 {
4723 if ( selected_spell_alternate[i] == spell )
4724 {
4725 selected_spell_alternate[i] = nullptr;
4726 }
4727 }
4728 list_RemoveNode(node);
4729 }
4730 }
4731 else
4732 {
4733 messagePlayer(clientnum, language[973]);
4734 }
4735 consumeItem(item, player);
4736 return;
4737 }
4738 else
4739 {
4740 bool learned = false;
4741 switch ( item->type )
4742 {
4743 case SPELLBOOK_FORCEBOLT:
4744 learned = addSpell(SPELL_FORCEBOLT, player);
4745 break;
4746 case SPELLBOOK_MAGICMISSILE:
4747 learned = addSpell(SPELL_MAGICMISSILE, player);
4748 break;
4749 case SPELLBOOK_COLD:
4750 learned = addSpell(SPELL_COLD, player);
4751 break;
4752 case SPELLBOOK_FIREBALL:
4753 learned = addSpell(SPELL_FIREBALL, player);
4754 break;
4755 case SPELLBOOK_LIGHTNING:
4756 learned = addSpell(SPELL_LIGHTNING, player);
4757 break;
4758 case SPELLBOOK_REMOVECURSE:
4759 learned = addSpell(SPELL_REMOVECURSE, player);
4760 break;
4761 case SPELLBOOK_LIGHT:
4762 learned = addSpell(SPELL_LIGHT, player);
4763 break;
4764 case SPELLBOOK_IDENTIFY:
4765 learned = addSpell(SPELL_IDENTIFY, player);
4766 break;
4767 case SPELLBOOK_MAGICMAPPING:
4768 learned = addSpell(SPELL_MAGICMAPPING, player);
4769 break;
4770 case SPELLBOOK_SLEEP:
4771 learned = addSpell(SPELL_SLEEP, player);
4772 break;
4773 case SPELLBOOK_CONFUSE:
4774 learned = addSpell(SPELL_CONFUSE, player);
4775 break;
4776 case SPELLBOOK_SLOW:
4777 learned = addSpell(SPELL_SLOW, player);
4778 break;
4779 case SPELLBOOK_OPENING:
4780 learned = addSpell(SPELL_OPENING, player);
4781 break;
4782 case SPELLBOOK_LOCKING:
4783 learned = addSpell(SPELL_LOCKING, player);
4784 break;
4785 case SPELLBOOK_LEVITATION:
4786 learned = addSpell(SPELL_LEVITATION, player);
4787 break;
4788 case SPELLBOOK_INVISIBILITY:
4789 learned = addSpell(SPELL_INVISIBILITY, player);
4790 break;
4791 case SPELLBOOK_TELEPORTATION:
4792 learned = addSpell(SPELL_TELEPORTATION, player);
4793 break;
4794 case SPELLBOOK_HEALING:
4795 learned = addSpell(SPELL_HEALING, player);
4796 break;
4797 case SPELLBOOK_EXTRAHEALING:
4798 learned = addSpell(SPELL_EXTRAHEALING, player);
4799 break;
4800 case SPELLBOOK_CUREAILMENT:
4801 learned = addSpell(SPELL_CUREAILMENT, player);
4802 break;
4803 case SPELLBOOK_DIG:
4804 learned = addSpell(SPELL_DIG, player);
4805 break;
4806 case SPELLBOOK_SUMMON:
4807 learned = addSpell(SPELL_SUMMON, player);
4808 break;
4809 case SPELLBOOK_STONEBLOOD:
4810 learned = addSpell(SPELL_STONEBLOOD, player);
4811 break;
4812 case SPELLBOOK_BLEED:
4813 learned = addSpell(SPELL_BLEED, player);
4814 break;
4815 case SPELLBOOK_REFLECT_MAGIC:
4816 learned = addSpell(SPELL_REFLECT_MAGIC, player);
4817 break;
4818 case SPELLBOOK_ACID_SPRAY:
4819 learned = addSpell(SPELL_ACID_SPRAY, player);
4820 break;
4821 case SPELLBOOK_STEAL_WEAPON:
4822 learned = addSpell(SPELL_STEAL_WEAPON, player);
4823 break;
4824 case SPELLBOOK_DRAIN_SOUL:
4825 learned = addSpell(SPELL_DRAIN_SOUL, player);
4826 break;
4827 case SPELLBOOK_VAMPIRIC_AURA:
4828 learned = addSpell(SPELL_VAMPIRIC_AURA, player);
4829 break;
4830 case SPELLBOOK_CHARM_MONSTER:
4831 learned = addSpell(SPELL_CHARM_MONSTER, player);
4832 break;
4833 case SPELLBOOK_REVERT_FORM:
4834 learned = addSpell(SPELL_REVERT_FORM, player);
4835 break;
4836 case SPELLBOOK_RAT_FORM:
4837 learned = addSpell(SPELL_RAT_FORM, player);
4838 break;
4839 case SPELLBOOK_SPIDER_FORM:
4840 learned = addSpell(SPELL_SPIDER_FORM, player);
4841 break;
4842 case SPELLBOOK_TROLL_FORM:
4843 learned = addSpell(SPELL_TROLL_FORM, player);
4844 break;
4845 case SPELLBOOK_IMP_FORM:
4846 learned = addSpell(SPELL_IMP_FORM, player);
4847 break;
4848 case SPELLBOOK_SPRAY_WEB:
4849 learned = addSpell(SPELL_SPRAY_WEB, player);
4850 break;
4851 case SPELLBOOK_POISON:
4852 learned = addSpell(SPELL_POISON, player);
4853 break;
4854 case SPELLBOOK_SPEED:
4855 learned = addSpell(SPELL_SPEED, player);
4856 break;
4857 case SPELLBOOK_FEAR:
4858 learned = addSpell(SPELL_FEAR, player);
4859 break;
4860 case SPELLBOOK_STRIKE:
4861 learned = addSpell(SPELL_STRIKE, player);
4862 break;
4863 case SPELLBOOK_DETECT_FOOD:
4864 learned = addSpell(SPELL_DETECT_FOOD, player);
4865 break;
4866 case SPELLBOOK_WEAKNESS:
4867 learned = addSpell(SPELL_WEAKNESS, player);
4868 break;
4869 case SPELLBOOK_AMPLIFY_MAGIC:
4870 learned = addSpell(SPELL_AMPLIFY_MAGIC, player);
4871 break;
4872 case SPELLBOOK_SHADOW_TAG:
4873 learned = addSpell(SPELL_SHADOW_TAG, player);
4874 break;
4875 case SPELLBOOK_TELEPULL:
4876 learned = addSpell(SPELL_TELEPULL, player);
4877 break;
4878 case SPELLBOOK_DEMON_ILLU:
4879 learned = addSpell(SPELL_DEMON_ILLUSION, player);
4880 break;
4881 case SPELLBOOK_TROLLS_BLOOD:
4882 learned = addSpell(SPELL_TROLLS_BLOOD, player);
4883 break;
4884 case SPELLBOOK_SALVAGE:
4885 learned = addSpell(SPELL_SALVAGE, player);
4886 break;
4887 case SPELLBOOK_FLUTTER:
4888 learned = addSpell(SPELL_FLUTTER, player);
4889 break;
4890 case SPELLBOOK_DASH:
4891 learned = addSpell(SPELL_DASH, player);
4892 break;
4893 case SPELLBOOK_SELF_POLYMORPH:
4894 learned = addSpell(SPELL_SELF_POLYMORPH, player);
4895 break;
4896 case SPELLBOOK_9:
4897 learned = addSpell(SPELL_9, player);
4898 break;
4899 case SPELLBOOK_10:
4900 learned = addSpell(SPELL_10, player);
4901 break;
4902 default:
4903 learned = addSpell(SPELL_FORCEBOLT, player);
4904 break;
4905 }
4906
4907 if ( learned )
4908 {
4909 if ( item->type >= SPELLBOOK_RAT_FORM && item->type <= SPELLBOOK_IMP_FORM )
4910 {
4911 ItemType originalSpellbook = item->type;
4912 item->type = SPELLBOOK_REVERT_FORM;
4913 if ( !playerLearnedSpellbook(item) ) // have we learnt "revert form"?
4914 {
4915 addSpell(SPELL_REVERT_FORM, player, true); // add it.
4916 }
4917 item->type = originalSpellbook;
4918 }
4919 item->status = static_cast<Status>(item->status - 1);
4920 if ( item->status != BROKEN )
4921 {
4922 messagePlayer(player, language[2595]);
4923 }
4924 else
4925 {
4926 messagePlayer(player, language[2596]);
4927 consumeItem(item, player);
4928 }
4929
4930 if ( stats[player] && stats[player]->playerRace == RACE_INSECTOID && stats[player]->appearance == 0 )
4931 {
4932 steamStatisticUpdate(STEAM_STAT_BOOKWORM, STEAM_STAT_INT, 1);
4933 }
4934 if ( list_Size(&spellList) >= 20 )
4935 {
4936 steamAchievement("BARONY_ACH_MAGIC_MASTERY");
4937 }
4938 }
4939 }
4940 }
4941
item_FoodAutomaton(Item * & item,int player)4942 void item_FoodAutomaton(Item*& item, int player)
4943 {
4944 if ( !stats[player] || !players[player] || !players[player]->entity )
4945 {
4946 return;
4947 }
4948
4949 if ( player >= 0 && stats[player]->type != AUTOMATON )
4950 {
4951 //messagePlayer(player, "Err: You are not an Automaton!");
4952 return;
4953 }
4954
4955 if ( !itemIsConsumableByAutomaton(*item)
4956 && item->type != POTION_FIRESTORM )
4957 {
4958 return;
4959 }
4960
4961 if ( multiplayer == CLIENT )
4962 {
4963 consumeItem(item, player);
4964 return;
4965 }
4966
4967 // consumption message
4968 if ( item->type != TOOL_MAGIC_SCRAP && item->type != TOOL_METAL_SCRAP )
4969 {
4970 int oldcount = item->count;
4971 item->count = 1;
4972 messagePlayer(player, language[907], item->description());
4973 item->count = oldcount;
4974 }
4975
4976 // eating sound
4977 if ( item->type == FOOD_BLOOD || item->type == POTION_FIRESTORM )
4978 {
4979 // play drink sound
4980 playSoundEntity(players[player]->entity, 52, 64);
4981 }
4982 else
4983 {
4984 playSoundEntity(players[player]->entity, 50 + rand() % 2, 64);
4985 }
4986
4987 if ( item->beatitude < 0 && item->type == FOOD_CREAMPIE )
4988 {
4989 messagePlayer(player, language[909]);
4990 messagePlayer(player, language[910]);
4991 stats[player]->EFFECTS[EFF_MESSY] = true;
4992 stats[player]->EFFECTS_TIMERS[EFF_MESSY] = 600; // ten seconds
4993 serverUpdateEffects(player);
4994 consumeItem(item, player);
4995 return;
4996 }
4997
4998 // automaton hunger/combustion tick is every 0.6 seconds.
4999 // 600 hunger = 6 minutes
5000 // 200 hunger = 2 minutes
5001 // 100 hunger = 60 seconds.
5002 // 80 hunger = 48 seconds
5003 // 50 hunger = 30 seconds
5004 // 40 hunger = 24 seconds
5005 // 20 hunger = 12 seconds
5006 int oldHunger = stats[player]->HUNGER;
5007 Uint32 color = SDL_MapRGB(mainsurface->format, 255, 128, 0);
5008
5009 // replenish nutrition points
5010 // automaton hunger is always in effect
5011 // hunger disabled will simply add 5 HP and still add fuel to the fire.
5012 switch ( item->type )
5013 {
5014 case FOOD_BREAD:
5015 case FOOD_CREAMPIE:
5016 case FOOD_BLOOD:
5017 case FOOD_CHEESE:
5018 case FOOD_APPLE:
5019 case FOOD_TOMALLEY:
5020 case FOOD_MEAT:
5021 case FOOD_FISH:
5022 case FOOD_TIN:
5023 if ( svFlags & SV_FLAG_HUNGER )
5024 {
5025 messagePlayer(player, language[3697]); // no effect.
5026 consumeItem(item, player);
5027 return;
5028 }
5029 break;
5030 case GEM_ROCK:
5031 case GEM_GLASS:
5032 stats[player]->HUNGER += 50;
5033 break;
5034 case GEM_LUCK:
5035 case GEM_GARNET:
5036 case GEM_RUBY:
5037 case GEM_JACINTH:
5038 case GEM_AMBER:
5039 case GEM_CITRINE:
5040 case GEM_JADE:
5041 case GEM_EMERALD:
5042 case GEM_SAPPHIRE:
5043 case GEM_AQUAMARINE:
5044 case GEM_AMETHYST:
5045 case GEM_FLUORITE:
5046 case GEM_OPAL:
5047 case GEM_DIAMOND:
5048 case GEM_JETSTONE:
5049 case GEM_OBSIDIAN:
5050 stats[player]->HUNGER += 1000;
5051 players[player]->entity->modMP(10);
5052 break;
5053 case READABLE_BOOK:
5054 stats[player]->HUNGER += 400;
5055 if ( stats[player]->playerRace == RACE_AUTOMATON && stats[player]->appearance == 0 )
5056 {
5057 steamStatisticUpdateClient(player, STEAM_STAT_FASCIST, STEAM_STAT_INT, 1);
5058 }
5059 break;
5060 case SCROLL_MAIL:
5061 case SCROLL_BLANK:
5062 stats[player]->HUNGER += 200;
5063 break;
5064 case SCROLL_IDENTIFY:
5065 case SCROLL_LIGHT:
5066 case SCROLL_REMOVECURSE:
5067 case SCROLL_FOOD:
5068 case SCROLL_MAGICMAPPING:
5069 case SCROLL_REPAIR:
5070 case SCROLL_DESTROYARMOR:
5071 case SCROLL_TELEPORTATION:
5072 case SCROLL_SUMMON:
5073 case SCROLL_CONJUREARROW:
5074 case SCROLL_CHARGING:
5075 players[player]->entity->modMP(20);
5076 stats[player]->HUNGER += 600;
5077 break;
5078 case SCROLL_ENCHANTWEAPON:
5079 case SCROLL_ENCHANTARMOR:
5080 players[player]->entity->modMP(40);
5081 stats[player]->HUNGER += 600;
5082 break;
5083 case SCROLL_FIRE:
5084 {
5085 stats[player]->HUNGER += 1500;
5086 players[player]->entity->modMP(stats[player]->MAXMP);
5087 messagePlayerColor(player, color, language[3699]); // superheats
5088 if ( stats[player]->playerRace == RACE_AUTOMATON && stats[player]->appearance == 0 )
5089 {
5090 steamStatisticUpdateClient(player, STEAM_STAT_SPICY, STEAM_STAT_INT, 1);
5091 }
5092
5093 playSoundEntity(players[player]->entity, 153, 128); // "FireballExplode.ogg"
5094 for ( int c = 0; c < 100; c++ )
5095 {
5096 Entity* entity = spawnFlame(players[player]->entity, SPRITE_FLAME);
5097 entity->sprite = 16;
5098 double vel = rand() % 10;
5099 entity->vel_x = vel * cos(entity->yaw) * cos(entity->pitch) * .1;
5100 entity->vel_y = vel * sin(entity->yaw) * cos(entity->pitch) * .1;
5101 entity->vel_z = vel * sin(entity->pitch) * .2;
5102 entity->skill[0] = 5 + rand() % 10;
5103 }
5104 break;
5105 }
5106 case TOOL_METAL_SCRAP:
5107 if ( stats[player]->playerRace == RACE_AUTOMATON && stats[player]->appearance == 0 )
5108 {
5109 achievementObserver.playerAchievements[player].trashCompactor += 1;
5110 }
5111 if ( stats[player]->HUNGER > 500 )
5112 {
5113 messagePlayer(player, language[3707]); // fails to add any more heat.
5114 consumeItem(item, player);
5115 return;
5116 }
5117 else
5118 {
5119 stats[player]->HUNGER += 50;
5120 stats[player]->HUNGER = std::min(stats[player]->HUNGER, 550);
5121 }
5122 break;
5123 case TOOL_MAGIC_SCRAP:
5124 if ( stats[player]->playerRace == RACE_AUTOMATON && stats[player]->appearance == 0 )
5125 {
5126 achievementObserver.playerAchievements[player].trashCompactor += 1;
5127 }
5128 if ( stats[player]->HUNGER > 1100 )
5129 {
5130 messagePlayer(player, language[3707]); // fails to add any more heat.
5131 consumeItem(item, player);
5132 return;
5133 }
5134 else
5135 {
5136 stats[player]->HUNGER += 100;
5137 stats[player]->HUNGER = std::min(stats[player]->HUNGER, 1199);
5138 }
5139 break;
5140 default:
5141 messagePlayer(player, "Unknown food?");
5142 break;
5143 }
5144
5145 if ( itemCategory(item) == SCROLL )
5146 {
5147 if ( stats[player]->playerRace == RACE_AUTOMATON && stats[player]->appearance == 0 )
5148 {
5149 steamStatisticUpdateClient(player, STEAM_STAT_FASCIST, STEAM_STAT_INT, 1);
5150 }
5151 }
5152
5153 if ( !(svFlags & SV_FLAG_HUNGER) && oldHunger == stats[player]->HUNGER ) // ate food, hunger is disabled and did not gain heat (normal food items)
5154 {
5155 if ( players[player] && players[player]->entity )
5156 {
5157 if ( item->beatitude < 0 )
5158 {
5159 playSoundEntity(players[player]->entity, 28, 64);
5160 players[player]->entity->modHP(-5);
5161 messagePlayer(player, language[908]); // blecch! rotten food!
5162 consumeItem(item, player);
5163 return;
5164 }
5165
5166 players[player]->entity->modHP(5);
5167 }
5168 messagePlayer(player, language[911]); // mmm, tasty!
5169 }
5170
5171 stats[player]->HUNGER = std::min(stats[player]->HUNGER, 1500);
5172 // results of eating
5173 if ( stats[player]->HUNGER >= 1500 )
5174 {
5175 messagePlayerColor(player, color, language[3483]); // at capacity
5176 }
5177 else if ( stats[player]->HUNGER >= 1200 && oldHunger < 1200 )
5178 {
5179 messagePlayerColor(player, color, language[3484]);
5180 }
5181 else if ( stats[player]->HUNGER >= 600 && oldHunger < 600 )
5182 {
5183 messagePlayerColor(player, color, language[3696]);
5184 }
5185 else if ( stats[player]->HUNGER >= 300 && oldHunger < 300 )
5186 {
5187 messagePlayerColor(player, color, language[3485]);
5188 }
5189 else if ( stats[player]->HUNGER <= 300 )
5190 {
5191 messagePlayerColor(player, color, language[3486]);
5192 }
5193 else if ( oldHunger < stats[player]->HUNGER )
5194 {
5195 messagePlayer(player, language[3704]);
5196 }
5197
5198 serverUpdateHunger(player);
5199 consumeItem(item, player);
5200 }
5201
itemIsConsumableByAutomaton(const Item & item)5202 bool itemIsConsumableByAutomaton(const Item& item)
5203 {
5204 switch ( item.type )
5205 {
5206 case FOOD_BREAD:
5207 case FOOD_CREAMPIE:
5208 case FOOD_BLOOD:
5209 case FOOD_CHEESE:
5210 case FOOD_APPLE:
5211 case FOOD_TOMALLEY:
5212 case FOOD_MEAT:
5213 case FOOD_FISH:
5214 case FOOD_TIN:
5215
5216 case GEM_ROCK:
5217 case GEM_GLASS:
5218 case GEM_LUCK:
5219 case GEM_GARNET:
5220 case GEM_RUBY:
5221 case GEM_JACINTH:
5222 case GEM_AMBER:
5223 case GEM_CITRINE:
5224 case GEM_JADE:
5225 case GEM_EMERALD:
5226 case GEM_SAPPHIRE:
5227 case GEM_AQUAMARINE:
5228 case GEM_AMETHYST:
5229 case GEM_FLUORITE:
5230 case GEM_OPAL:
5231 case GEM_DIAMOND:
5232 case GEM_JETSTONE:
5233 case GEM_OBSIDIAN:
5234
5235 case READABLE_BOOK:
5236
5237 case SCROLL_MAIL:
5238 case SCROLL_BLANK:
5239 case SCROLL_IDENTIFY:
5240 case SCROLL_LIGHT:
5241 case SCROLL_ENCHANTWEAPON:
5242 case SCROLL_ENCHANTARMOR:
5243 case SCROLL_REMOVECURSE:
5244 case SCROLL_FOOD:
5245 case SCROLL_MAGICMAPPING:
5246 case SCROLL_REPAIR:
5247 case SCROLL_DESTROYARMOR:
5248 case SCROLL_TELEPORTATION:
5249 case SCROLL_SUMMON:
5250 case SCROLL_FIRE:
5251 case SCROLL_CONJUREARROW:
5252 case SCROLL_CHARGING:
5253 case TOOL_MAGIC_SCRAP:
5254 case TOOL_METAL_SCRAP:
5255 return true;
5256 break;
5257 default:
5258 return false;
5259 break;
5260 }
5261 return false;
5262 }
5263
updateHungerMessages(Entity * my,Stat * myStats,Item * eaten)5264 void updateHungerMessages(Entity* my, Stat* myStats, Item* eaten)
5265 {
5266 if ( !myStats || !eaten || !my)
5267 {
5268 return;
5269 }
5270 if ( my->behavior != &actPlayer )
5271 {
5272 return;
5273 }
5274 if ( (svFlags & SV_FLAG_HUNGER) )
5275 {
5276 if ( myStats->HUNGER <= 250 )
5277 {
5278 messagePlayer(my->skill[2], language[912]);
5279 }
5280 else if ( myStats->HUNGER < 500 )
5281 {
5282 messagePlayer(my->skill[2], language[913]);
5283 }
5284 else if ( myStats->HUNGER < 1000 )
5285 {
5286 messagePlayer(my->skill[2], language[914], eaten->getName());
5287 }
5288 else if ( myStats->HUNGER < 1500 )
5289 {
5290 messagePlayer(my->skill[2], language[915]);
5291 }
5292 else if ( myStats->HUNGER >= 1500 )
5293 {
5294 if ( my->effectShapeshift != NOTHING )
5295 {
5296 messagePlayer(my->skill[2], language[916]); // shapeshifted players don't puke
5297 }
5298 else if ( rand() % 3 )
5299 {
5300 messagePlayer(my->skill[2], language[916]);
5301 }
5302 else
5303 {
5304 messagePlayer(my->skill[2], language[917]);
5305 if ( myStats->type != SKELETON && myStats->type != AUTOMATON )
5306 {
5307 my->skill[26] = 40 + rand() % 10;
5308 }
5309 }
5310 }
5311 }
5312
5313 if ( myStats->type == INSECTOID )
5314 {
5315 myStats->HUNGER = std::min(myStats->HUNGER, 1000); // smaller hunger range.
5316 }
5317 else
5318 {
5319 myStats->HUNGER = std::min(myStats->HUNGER, 2000);
5320 }
5321 serverUpdateHunger(my->skill[2]);
5322 }