-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathalchemy.c
3422 lines (3063 loc) · 102 KB
/
alchemy.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* Alchemy subsystems for the alchemist class */
/* Gicker aka Stephen Squires, July 2019 */
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "spells.h"
#include "handler.h"
#include "db.h"
#include "constants.h"
#include "interpreter.h"
#include "dg_scripts.h"
#include "modify.h"
#include "feats.h"
#include "class.h"
#include "mud_event.h"
#include "assign_wpn_armor.h"
#include "domains_schools.h"
#include "spell_prep.h"
#include "alchemy.h"
#include "actions.h"
#include "act.h"
#include "fight.h"
#include "evolutions.h"
// external functions
int attack_roll(struct char_data *ch, struct char_data *victim, int attack_type, int is_touch, int attack_number);
int damage(struct char_data *ch, struct char_data *victim, int dam, int w_type, int dam_type, int offhand);
int is_player_grouped(struct char_data *target, struct char_data *group);
const char *alchemical_discovery_names[NUM_ALC_DISCOVERIES] = {
"normal bomb",
"acid bomb",
"blinding bomb",
"boneshard bomb",
"celestial poisons",
"chameleon",
"cognatogen",
"concussive bomb",
"confusion bomb",
"dispelling bomb",
"elemental mutagen",
"enhance potion",
"extend potion",
"fast bombs",
"fire brand",
"force bomb",
"frost bomb",
"grand cognatogen",
"grand inspiring cognatogen",
"grand mutagen",
"greater cognatogen",
"greater inspiring cognatogen",
"greater mutagen",
"healing bomb",
"curing touch",
"holy bomb",
"immolation bomb",
"infuse mutagen",
"infusion",
"inspiring cognatogen",
"malignant poison",
"poison bomb",
"precise bomb",
"preserve organs",
"profane bomb",
"psychokinetic tincture",
"shock bomb",
"spontaneous healing",
"sticky bombs",
"stink bomb",
"sunlight bomb",
"tanglefoot bomb",
"vestigial arm",
"wings"};
const char *alchemical_discovery_descriptions[NUM_ALC_DISCOVERIES] = {
"Deals 1d6/rank fire damage.",
"Deals 1d6/rank acid damage with additional 1d6 damage 1 round later.",
"Chance to blind direct target, and dazzle splash targets.",
"Deals 1d6/rank piercing damage, and direct targets can take 1d4 bleed damage.",
"Your poisons affect Undead and Evil Outsiders",
"Bonus to stealth checks, +4 at first then +8 at alchemist level 10.",
"Can use a mutagen to improve mental abilities instead of physical ones. +4 to selected mental ability, and -2 to associated physical ability, plus +2 natural armor bonus. Uses 'swallow' command.",
"Deals 1d4/rank sonic damage with chance to deafen.",
"Chance to make direct targets confused, damage is reduced by 2d6, minimum of 1d6.",
"Chance to dispel magic on direct target. Does no damage.",
"Can apply mutagen benefits to elemental resitance and an associated skill check bonus. Uses 'swallow' command.",
"increases the caster level on any quaffed potion to the alchemist's class level.",
"Any potions quaffed last twice as long.",
"Can make or throw bombs with a move action instead of a standard action.",
"Allows use of a bomb that makes your wielded weapons flaming, and and alchemist level 10, also flaming burst.",
"Deals 1d4/rank force damage with direct targets possibly being knocked prone.",
"Deals 1d6/rank frost damage with direct targets having a chance to be staggered.",
"As cognatogen but ability bonus is +8 for one ability, +6 for another and +4 for the third, plus natural ac is +4",
"As inspiring cognatogen but +4 dodge AC, +4 reflex saves, but with -6 to strength and consistution. Also includes some skill bonuses.",
"As mutagen, but +6 natural armor, +8 to one physical ability, +6 to a second and +4 to the third. Uses 'swallow' command.",
"As cognatogen but +4 natural AC and +6 to one mental ability, and +4 to a second.",
"As inspiring cognatogen, but +2 dodge ac, +2 reflex saves and -4 to strength and constitution, plus some bonuses to certain skills.",
"As mutagen, but +6 to one ability and +4 to a second. -2 to associated abilities. +4 natural ac. Uses 'swallow' command.",
"Heals target 1d4/rank.",
"As spontaneous healing discovery, but can heal the amount to another creature as a swift action. Also increases maximum healing total to 5x Alchemist level.",
"Deals 1d6/rank holy damage. Evil targets may be staggered. Neutral targets take 1/2 damage and good ones take none.",
"Deals 1d6+int mod fire damage each round for # of rounds equal to # of bomb ranks.",
"Reduces the penalties associated with mutagens and cognatogens by 1. Uses 'swallow' command.",
"Allows others to benefit from extracts",
"+2 dodge ac, -2 strength and constitution, +1 to attack rolls and weapon damage.",
"Increases save DCs of alchemist's poisons by +4, and increases duration by 50 percent.",
"Deals 1d4/level poison damage to all in room, as well as secondary poison damage to all if AoE Bombs enabled.",
"+2 to attack rolls with bombs.",
"25 percent chance of nullifying any critical hit or sneak attack against the alchemist.",
"Deals 1d6/rank unholy damage. Good targets may be staggered. Neutral targets take 1/2 damage and evil ones take none.",
"For every 4 alchemist levels, this tincture bestows a single spirit that gives the alchemist a cumulative +1 "
"bonus to deflection ac, up to a maximum of 5 at alchemist level 20. The alchemist can 'launch' one spirit per round "
"which will make the target frightened if a mind-affecting fear save is failed. Uses the 'psychokinetic' command.",
"Deals 1d6/rank electricity damage with chance to dazzle direct targets for 1d4 rounds.",
"Can heal self 5 hp once per round as a free action, for a total healing amount of alchemist level x2. Uses the curingtouch command.",
"Causes damage dealing bombs to deal an extra round of splash damage, and causes affect causing bombs to last an additional round.",
"Makes all targets nauseated on failed save for 1 round / bomb rank",
"Deals 1d6/rank radiant damage, chance to blind, Undead take +2 damage/bomb rank and are staggered on failed save.",
"Chance to entangle those caught in effect.",
"Grows a third arm from torso which acts as an additional hand for most purposes.",
"Alchemist grows wings that will allow him to fly as per the fly spell (fly/land)."};
const char *grand_alchemical_discovery_names[NUM_GR_ALC_DISCOVERIES] = {
"none",
"awakened intellect",
"fast healing",
"poison touch",
"true mutagen"};
const char *grand_alchemical_discovery_descriptions[NUM_GR_ALC_DISCOVERIES] = {
"none",
"Your base intelligence raises by 2 permanently",
"Heal 5 hp per round permanently",
"Is able to poison others with a touch (poisontouch command)",
"Mutagens now bestow +8 to natural ac, str, dex and con, while -2 to int, wis and cha. Cognatogens, Inspiring Cognatogens and Elemental Mutagens are also improved."};
const char *bomb_types[NUM_BOMB_TYPES] = {
"none",
"normal",
"acid",
"blinding",
"boneshard",
"concussive",
"confusion",
"dispelling",
"fire-brand",
"force",
"frost",
"healing",
"holy",
"immolation",
"poison",
"profane",
"shock",
"stink",
"sunlight",
"tanglefoot"};
const char *bomb_descriptions[NUM_BOMB_TYPES] = {
"",
"Deals 1d6/rank fire damage.",
"Deals 1d6/rank acid damage with additional 1d6 damage 1 round later.",
"Chance to blind direct target, and dazzle splash targets.",
"Deals 1d6/rank piercing damage, and direct targets can take 1d4 bleed damage.",
"Deals 1d4/rank sonic damage with chance to deafen.",
"Chance to make direct targets confused, damage is reduced by 2d6, minimum of 1d6.",
"Chance to dispel magic on direct target. Does no damage.",
"Makes wielded weapons flaming, and flaming burst at alc level 10.",
"Deals 1d4/rank force damage with direct targets possibly being knocked prone.",
"Deals 1d6/rank frost damage with direct targets having a chance to be staggered.",
"Heals target 1d4/rank.",
"Deals 1d6/rank holy damage. Evil targets may be staggered. Neutral targets take 1/2 damage and good ones take none.",
"Deals 1d6+int mod fire damage each round for # of rounds equal to # of bomb ranks.",
"Kills weak creatures outright and deals 1d4 consitution damage continuously until suiccessful fortitude save.",
"Deals 1d6/rank unholy damage. Good targets may be staggered. Neutral targets take 1/2 damage and evil ones take none.",
"Deals 1d6/rank electricity damage with chance to dazzle direct targets for 1d4 rounds.",
"Makes all targets nauseated on failed save for 1 round / bomb rank",
"Deals 1d6/rank radiant damage, chance to blind, Undead take +2 damage/bomb rank and are staggered on failed save.",
"Chance to entangle those caught in effect."};
const char *discovery_requisites[NUM_ALC_DISCOVERIES] = {
"none", // none
"none", // acid
"alchemist level 8", // blinding
"none", // boneshard
"alchemist level 8", // celestial poisons
"none", // chameleon
"none", // cognatogen
"alchemist level 6", // concussive bomb
"alchemist level 8", // confusion bomb
"alchemist level 6", // dispelling bomb
"none", // elemental mutagen
"none", // enhance potion
"none", // extend potion
"alchemist level 8", // fast bombs
"none", // fire branks
"alchemist level 8", // force bomb
"none", // frost bomb
"alchemist level 16, greater cognatogen", // grand cognatogen
"alchemist level 16, greater inspiring cognatogen", // grand inspiring cognatogen
"alchemist level 16, greater mutagen", // grand mutagen
"alchemist level 12, cognatogen", // greater cognatogen
"alchemist level 12, inspiring cognatogen", // greater inpisiring cognatogen
"alchemist level 12", // greater mutagen
"none", // healing bomb
"alchemist level 6, spontaneous healing", // curing touch
"alchemist level 8", // holy bomb
"alchemist level 3", // immolation bomb
"none", // infuse mutagen
"none", // infusion
"none", // inspiring cognatogen
"alchemist level 10", // malignant poison
"alchemist level 12", // poison bomb
"none", // precise bomb
"none", // preserve organs
"alchemist level 8", // profane bomb
"alchemist level 4", // psychokinetic tincture
"none", // shock bomb
"none", // spontaneous healing
"alchemist level 10", // sticky bomb
"none", // stink bomb
"alchemist level 10, blinding bomb", // sunlight bomb
"none", // tanglefoot bomb
"alchemist level 9", // vestigial arm
"alchemist level 6" // wings
};
const char *bomb_requisites[NUM_BOMB_TYPES] = {
"none", // not a bomb
"none", // normal bomb
"none", // acid bomb
"8 ranks in alchemist class", // blinding bomb
"none", // boneshard bomb
"6 ranks in alchemist class", // concussive bomb
"8 ranks in alchemist class", // confusion bomb
"6 ranks in alchemist class", // dispelling bomb
"none", // fire brand
"8 ranks in alchemist class", // force bomb
"none", // frost bomb
"6 ranks in alchemist class, spontaneous healing discovery", // healing bomb
"8 ranks in alchemist class", // holy bomb
"3 ranks in alchemist class", // immolation bomb
"12 ranks in alchemist class", // poison bomb
"8 ranks in alchemist class", // profane bomb
"none", // shock bomb
"none", // stink bomb
"10 ranks in alchemist class, blinding bomb", // sunlight bomb
"none" // tanglefoot bomb
};
const char *bomb_damage_messages[NUM_BOMB_TYPES][3] = {
{"", "", ""}, // none bomb
{ // Normal
"$n tosses a bomb that explodes in flames all around you.",
"You toss a bomb that explodes in flames all around $N",
"$n tosses a bomb that explodes in flames all around $N"},
{// Acid
"$n tosses a bomb that explodes, sprayingn acid all over you.",
"You toss a bomb that explodes, spraying acid all over $N.",
"$n tosses a bomb that explodes, spraying acid all over $N"},
{"$n tosses a bomb that explodes in a bright flash of light in front of you!",
"You toss a bomb that explodes in a bright flash of light in front of $N!",
"$n tosses a bomb that explodes in a bright flash of light in front of $N!"},
{// Boneshard
"$n tosses a bomb at you that explodes in a spray of tiny bone shards!",
"You toss a bomb at $N that explodes in a spray of tiny bone shards!",
"$n tosses a bomb at $N that explodes in a spray of tiny bone shards!"},
{// concussive
"$n tosses a bomb at you that explodes with powerful shock waves.",
"You toss a bomb at $N that explodes with powerful shock waves.",
"$n tosses a bomb at $N that explodes with powerful shock waves."},
{// confusion
"$n tosses a bomb at you that explodes into searing and disorienting particles.",
"You toss a bomb at $N that explodes into searing and disorienting particles.",
"$n tosses a bomb at $N that explodes into searing and disorienting particles."},
{// dispelling
"$n tosses a bomb at you that explodes with waves of magic-nullifying energy.",
"You toss a bomb at $N that explodes with waves of magic-nullifying energy.",
"$n tosses a bomb at $N that explodes with waves of magic-nullifying energy."},
{// fire brand
"$n tosses a bomb at $s feet, lighting $s weapons aflame.",
"You toss a bomb at your feet, lighting your weapons aflame.",
"$n tosses a bomb at $s feet, lighting $s weapons aflame."},
{// force
"$n tosses a bomb at you that explodes with staggering force.",
"You toss a bomb at $N that explodes with staggering force.",
"$n tosses a bomb at $N that explodes with staggering force."},
{// frost
"$n tosses a bomb at you that explodes with paralyzing cold.",
"You toss a bomb at $N that explodes with paralyzing cold.",
"$n tosses a bomb at $N that explodes with paralyzing cold."},
{// healing
"$n tosses a bomb at you that fills you with healing warmth.",
"You toss a bomb at $N that fills $M with healing warmth.",
"$n tosses a bomb at $N that fills $M with healing warmth."},
{// holy
"$n tosses a bomb at you that explodes in radiant light.",
"You toss a bomb at $N that explodes in radiant light.",
"$n tosses a bomb at $N that explodes in radiant light."},
{
// immolation
"$n tosses a bomb at you that explodes in a ball of bubbling magma.",
"You toss a bomb at $N that explodes in a ball of bubbling magma.",
"$n tosses a bomb at $N that explodes in a ball of bubbling magma.",
},
{// poison
"$n tosses a bomb at you that explodes in a cloud of poisonous, killing gas.",
"You toss a bomb at $N that explodes in a cloud of poisonous, killing gas.",
"$n tosses a bomb at $N that explodes in a cloud of poisonous, killing gas."},
{// profane
"$n tosses a bomb at you that explodes in a wave of debilitaing unholy power.",
"You toss a bomb at $N that explodes in a wave of debilitaing unholy power.",
"$n tosses a bomb at $N that explodes in a wave of debilitaing unholy power."},
{// shock
"$n tosses a bomb at you that explodes in dozens of streaking lightning bolts.",
"You toss a bomb at $N that explodes in dozens of streaking lightning bolts.",
"$n tosses a bomb at $N that explodes in dozens of streaking lightning bolts."},
{// stink
"$n tosses a bomb at you that explodes in a cloud of nauseating gas.",
"You toss a bomb at $N that explodes in a cloud of nauseating gas.",
"$n tosses a bomb at $N that explodes in a cloud of nauseating gas."},
{// sunlight
"$n tosses a bomb at you that explodes in brilliant flash of radiant energy.",
"You toss a bomb at $N that explodes in brilliant flash of radiant energy.",
"$n tosses a bomb at $N that explodes in brilliant flash of radiant energy."},
{// tanglefoot
"$n tosses a bomb at you that explodes in several globs of sticky goo.",
"You toss a bomb at $N that explodes in several globs of sticky goo.",
"$n tosses a bomb at $N that explodes in several globs of sticky goo."}};
int num_of_bombs_preparable(struct char_data *ch)
{
/* dummy check */
if (!ch)
return 0;
int num = 0;
num += CLASS_LEVEL(ch, CLASS_ALCHEMIST);
num += GET_REAL_INT_BONUS(ch);
return num;
}
int num_of_bombs_prepared(struct char_data *ch)
{
/* dummy check */
if (!ch)
return 0;
int i = 0,
num_prepped = 0;
for (i = 0; i < num_of_bombs_preparable(ch); i++)
{
if (GET_BOMB(ch, i) == BOMB_NONE)
continue;
num_prepped++;
}
return num_prepped;
}
int discovery_to_bomb_type(int discovery)
{
switch (discovery)
{
case ALC_DISC_NONE:
return BOMB_NORMAL;
case ALC_DISC_ACID_BOMBS:
return BOMB_ACID;
case ALC_DISC_BLINDING_BOMBS:
return BOMB_BLINDING;
case ALC_DISC_BONESHARD_BOMBS:
return BOMB_BONESHARD;
case ALC_DISC_CONCUSSIVE_BOMBS:
return BOMB_CONCUSSIVE;
case ALC_DISC_CONFUSION_BOMBS:
return BOMB_CONFUSION;
case ALC_DISC_DISPELLING_BOMBS:
return BOMB_DISPELLING;
case ALC_DISC_FIRE_BRAND:
return BOMB_FIRE_BRAND;
case ALC_DISC_FORCE_BOMBS:
return BOMB_FORCE;
case ALC_DISC_FROST_BOMBS:
return BOMB_FROST;
case ALC_DISC_HEALING_BOMBS:
return BOMB_HEALING;
case ALC_DISC_HOLY_BOMBS:
return BOMB_HOLY;
case ALC_DISC_IMMOLATION_BOMBS:
return BOMB_IMMOLATION;
case ALC_DISC_POISON_BOMBS:
return BOMB_POISON;
case ALC_DISC_PROFANE_BOMBS:
return BOMB_PROFANE;
case ALC_DISC_SHOCK_BOMBS:
return BOMB_SHOCK;
case ALC_DISC_STINK_BOMBS:
return BOMB_STINK;
case ALC_DISC_SUNLIGHT_BOMBS:
return BOMB_SUNLIGHT;
case ALC_DISC_TANGLEFOOT_BOMBS:
return BOMB_TANGLEFOOT;
default:
return -1;
}
return -1;
}
int bomb_type_to_discovery(int bomb)
{
switch (bomb)
{
case BOMB_NORMAL:
return ALC_DISC_NONE;
case BOMB_ACID:
return ALC_DISC_ACID_BOMBS;
case BOMB_BLINDING:
return ALC_DISC_BLINDING_BOMBS;
case BOMB_BONESHARD:
return ALC_DISC_BONESHARD_BOMBS;
case BOMB_CONCUSSIVE:
return ALC_DISC_CONCUSSIVE_BOMBS;
case BOMB_CONFUSION:
return ALC_DISC_CONFUSION_BOMBS;
case BOMB_DISPELLING:
return ALC_DISC_DISPELLING_BOMBS;
case BOMB_FIRE_BRAND:
return ALC_DISC_FIRE_BRAND;
case BOMB_FORCE:
return ALC_DISC_FORCE_BOMBS;
case BOMB_FROST:
return ALC_DISC_FROST_BOMBS;
case BOMB_HEALING:
return ALC_DISC_HEALING_BOMBS;
case BOMB_HOLY:
return ALC_DISC_HOLY_BOMBS;
case BOMB_IMMOLATION:
return ALC_DISC_IMMOLATION_BOMBS;
case BOMB_POISON:
return ALC_DISC_POISON_BOMBS;
case BOMB_PROFANE:
return ALC_DISC_PROFANE_BOMBS;
case BOMB_SHOCK:
return ALC_DISC_SHOCK_BOMBS;
case BOMB_STINK:
return ALC_DISC_STINK_BOMBS;
case BOMB_SUNLIGHT:
return ALC_DISC_SUNLIGHT_BOMBS;
case BOMB_TANGLEFOOT:
return ALC_DISC_TANGLEFOOT_BOMBS;
default:
return -1;
}
return -1;
}
int find_open_bomb_slot(struct char_data *ch)
{
/* dummy check */
if (!ch)
return -1;
int i = 0;
for (i = 0; i < num_of_bombs_preparable(ch); i++)
{
if (ch->player_specials->saved.bombs[i] != BOMB_NONE)
continue;
return i;
}
return -1;
}
void list_bomb_types_known(struct char_data *ch)
{
/* dummy check */
if (!ch)
return;
int i = 0, j = 0;
send_to_char(ch, "%-20s - %s\r\n", "normal", bomb_descriptions[0]);
for (i = 0; i < NUM_ALC_DISCOVERIES; i++)
{
j = discovery_to_bomb_type(i);
if (KNOWS_DISCOVERY(ch, i) && j != -1)
{
send_to_char(ch, "%-20s - %s\r\n", bomb_types[j], bomb_descriptions[j]);
}
}
return;
}
ACMD(do_bombs)
{
/* dummy check */
if (!ch)
return;
if (!HAS_FEAT(ch, FEAT_BOMBS))
{
send_to_char(ch, "You do not know anything about making to tossing bombs.\r\n");
return;
}
skip_spaces_c(&argument);
if (!*argument)
{
send_to_char(ch, "Would you like to 'toss' a bomb, 'discard' a bomb, 'list' your bombs or 'make' a bomb?\r\n");
return;
}
char ccmd[100], // toss, list or make
scmd[100], // second half for next two
slot[10], // which bomb slot to toss or make
spec[100]; // either target name for toss or discovery type for make
int i = 0, // used for various calculations/loops
bSlot = 0, // what bomb slot is being referenced
type = 0; // the type of bomb to use
struct char_data *target = NULL;
half_chop_c(argument, ccmd, sizeof(ccmd), scmd, sizeof(scmd));
if (is_abbrev(ccmd, "toss"))
{
if (!*scmd)
{
send_to_char(ch, "You need to supply a bomb type and optionally a target as well.\r\n");
return;
}
two_arguments(scmd, slot, sizeof(slot), spec, sizeof(spec));
if (!*slot)
{
send_to_char(ch, "You need to specify a bomb type. You must have prepared these already using the 'bomb make' command.\r\n");
return;
}
if (GET_LEVEL(ch) < LVL_IMMORT)
{
for (i = 0; i < num_of_bombs_preparable(ch); i++)
{
if (is_abbrev(slot, bomb_types[GET_BOMB(ch, i)]))
{
type = GET_BOMB(ch, i);
bSlot = i;
break;
}
}
if (i >= num_of_bombs_preparable(ch))
{
send_to_char(ch, "You don't have any %s bombs prepared.\r\n", slot);
return;
}
}
else // imms can throw any bomb as often as they like
{
for (i = 0; i < NUM_BOMB_TYPES; i++)
{
if (is_abbrev(slot, bomb_types[i]))
{
type = i;
bSlot = i;
break;
}
}
if (i >= NUM_BOMB_TYPES)
{
send_to_char(ch, "That is not a valid bomb type.\r\n");
return;
}
}
if (*spec)
{
if (!(target = get_char_vis(ch, spec, NULL, FIND_CHAR_ROOM)))
{
send_to_char(ch, "%s", CONFIG_NOPERSON);
return;
}
}
if (!target && !FIGHTING(ch))
{
send_to_char(ch, "If you are not in combat, you need to specify a target.\r\n");
return;
}
if (!target && FIGHTING(ch))
{
switch (type)
{
case BOMB_HEALING:
case BOMB_FIRE_BRAND:
target = ch;
break;
default:
target = FIGHTING(ch);
break;
}
}
if (target == ch)
{
switch (type)
{
case BOMB_HEALING:
case BOMB_FIRE_BRAND:
case BOMB_DISPELLING:
break; // these are ok. ^^^
default: // these aren't >>>
send_to_char(ch, "You cannot throw a harmful bomb at yourself.");
return;
}
}
if (!is_player_grouped(ch, target) && !IS_NPC(target) && !pvp_ok(ch, target, false))
{
switch (type)
{
case BOMB_HEALING:
break; // these are ok. ^^^
default: // these aren't >>>
send_to_char(ch, "You cannot throw a harmful bomb at a player if you or they are not flagged as pvp.");
return;
}
}
if (is_player_grouped(ch, target))
{
switch (type)
{
case BOMB_HEALING:
case BOMB_FIRE_BRAND:
case BOMB_DISPELLING:
break; // these are ok. ^^^
default: // these aren't >>>
send_to_char(ch, "You cannot use that type of bomb on party members.");
return;
}
}
if (!is_action_available(ch, KNOWS_DISCOVERY(ch, ALC_DISC_FAST_BOMBS) ? ACTION_MOVE : ACTION_STANDARD, TRUE))
return;
if (!target)
target = FIGHTING(ch);
if (bomb_is_friendly(type) || attack_roll(ch, target, ATTACK_TYPE_RANGED, TRUE, 1) >= 0)
{
// we hit!
perform_bomb_effect(ch, target, type);
}
else
{
// we missed :(
send_to_char(ch, "You throw a bomb, but it misses its intended target.\r\n");
act("$n throws a bomb, but it misses its intended target and explodes a safe distance away.", TRUE, ch, 0, 0, TO_ROOM);
// we want to start combat if not already in combat
if (!FIGHTING(target))
{
hit(target, ch, TYPE_UNDEFINED, DAM_RESERVED_DBC, 0, FALSE);
}
}
// let's remove the bomb they just tossed
GET_BOMB(ch, bSlot) = BOMB_NONE;
save_char(ch, 0);
if (KNOWS_DISCOVERY(ch, ALC_DISC_FAST_BOMBS))
USE_MOVE_ACTION(ch);
else
USE_STANDARD_ACTION(ch);
return;
}
else if (is_abbrev(ccmd, "make"))
{
if (num_of_bombs_prepared(ch) >= num_of_bombs_preparable(ch))
{
send_to_char(ch, "You cannot create any more bombs. Please use 'bombs discard' to open up some slots, or use the bombs in battle using 'bombs toss'\r\n");
return;
}
if ((bSlot = find_open_bomb_slot(ch)) == -1)
{
send_to_char(ch, "There seems to be an error. Please inform a staff member with error code BOMB_ERR_1.\r\n");
return;
}
if (!*scmd)
{
send_to_char(ch, "You need to supply the type of bomb you want to make. You know the following:\r\n");
list_bomb_types_known(ch);
return;
}
for (i = 1; i < NUM_BOMB_TYPES; i++)
{
if (is_abbrev(scmd, bomb_types[i]))
{
if (i != BOMB_NORMAL)
if (!KNOWS_DISCOVERY(ch, bomb_type_to_discovery(i)))
continue;
type = i;
break;
}
}
if (i >= NUM_BOMB_TYPES)
{
send_to_char(ch, "That is not a valid bomb type, or you don't know how to make that kind of bombs. Here's a list of bomb types you know how to make:\r\n");
list_bomb_types_known(ch);
return;
}
if (!is_action_available(ch, KNOWS_DISCOVERY(ch, ALC_DISC_FAST_BOMBS) ? ACTION_MOVE : ACTION_STANDARD, TRUE))
return;
ch->player_specials->saved.bombs[bSlot] = type;
send_to_char(ch, "You've successfully created a %s bomb.\r\n",
bomb_types[type]);
save_char(ch, 0);
if (KNOWS_DISCOVERY(ch, ALC_DISC_FAST_BOMBS))
USE_MOVE_ACTION(ch);
else
USE_STANDARD_ACTION(ch);
// we want to add a cooldown event here at some point
return;
}
else if (is_abbrev(ccmd, "list"))
{
int num_bombs[NUM_BOMB_TYPES];
int open_slots = 0;
for (i = 0; i < NUM_BOMB_TYPES; i++)
num_bombs[i] = BOMB_NONE;
send_to_char(ch, "You have prepared the following bombs:\r\n");
for (i = 0; i < num_of_bombs_preparable(ch); i++)
{
if (GET_BOMB(ch, i) != BOMB_NONE)
num_bombs[GET_BOMB(ch, i)]++;
else
open_slots++;
}
for (i = 0; i < NUM_BOMB_TYPES; i++)
{
if (num_bombs[i] > 0)
{
send_to_char(ch, "x%2d: %-12s - %s\r\n", num_bombs[i], bomb_types[i], bomb_descriptions[i]);
}
}
send_to_char(ch, "Open Bomb Slots: %d\r\n", open_slots);
return;
}
else if (is_abbrev(ccmd, "discard"))
{
if (!*scmd)
{
send_to_char(ch, "You need to specify which bomb type you want to discard.\r\n"
"Type 'bombs list' too see your available bombs.\r\n");
return;
}
for (i = 0; i < num_of_bombs_preparable(ch); i++)
{
if (is_abbrev(scmd, bomb_types[GET_BOMB(ch, i)]))
{
type = GET_BOMB(ch, i);
bSlot = i;
break;
}
}
if (i >= num_of_bombs_preparable(ch))
{
send_to_char(ch, "You don't have any %s bombs prepared.\r\n", scmd);
return;
}
if (GET_BOMB(ch, bSlot) == BOMB_NONE)
{
send_to_char(ch, "There is no bomb of that type to discard.\r\n"
"Type 'bombs list' too see your available slots.\r\n");
return;
}
send_to_char(ch, "You have discarded a %s bomb.\r\n", bomb_types[GET_BOMB(ch, bSlot)]);
GET_BOMB(ch, bSlot) = 0;
save_char(ch, 0);
return;
}
else
{ // no match on ccmd variable
send_to_char(ch, "Would you like to 'toss' a bomb, 'discard' a bomb, 'list' your bombs or 'make' a bomb?\r\n");
}
}
void perform_bomb_effect(struct char_data *ch, struct char_data *victim, int bomb_type)
{
/* dummy check */
if (!ch || !victim)
return;
switch (bomb_type)
{
case BOMB_NORMAL:
send_bomb_direct_message(ch, victim, bomb_type);
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
send_bomb_splash_message(ch, victim, bomb_type);
perform_bomb_direct_damage(ch, victim, bomb_type); // fire damage
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
perform_bomb_splash_damage(ch, victim, bomb_type); // fire damage
break;
case BOMB_ACID:
send_bomb_direct_message(ch, victim, bomb_type);
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
send_bomb_splash_message(ch, victim, bomb_type);
perform_bomb_direct_damage(ch, victim, bomb_type); // acid damage
perform_bomb_direct_effect(ch, victim, bomb_type); // DoT acid effect
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
perform_bomb_splash_damage(ch, victim, bomb_type); // acid damage
break;
case BOMB_BLINDING:
send_bomb_direct_message(ch, victim, bomb_type);
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
send_bomb_splash_message(ch, victim, bomb_type);
perform_bomb_direct_effect(ch, victim, bomb_type); // blind
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
perform_bomb_splash_effect(ch, victim, bomb_type); // dazzle
break;
case BOMB_BONESHARD:
send_bomb_direct_message(ch, victim, bomb_type);
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
send_bomb_splash_message(ch, victim, bomb_type);
perform_bomb_direct_damage(ch, victim, bomb_type); // piercing damage
perform_bomb_direct_effect(ch, victim, bomb_type); // DoT bleed effect
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
perform_bomb_splash_damage(ch, victim, bomb_type); // piercing damage
break;
case BOMB_CONCUSSIVE:
send_bomb_direct_message(ch, victim, bomb_type);
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
send_bomb_splash_message(ch, victim, bomb_type);
perform_bomb_direct_damage(ch, victim, bomb_type); // sonic damage
perform_bomb_direct_effect(ch, victim, bomb_type); // deafen
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
perform_bomb_splash_damage(ch, victim, bomb_type); // sonic damage
break;
case BOMB_CONFUSION:
send_bomb_direct_message(ch, victim, bomb_type);
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
send_bomb_splash_message(ch, victim, bomb_type);
perform_bomb_direct_damage(ch, victim, bomb_type); // reduced fire damage
perform_bomb_direct_effect(ch, victim, bomb_type); // confusion
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
perform_bomb_splash_damage(ch, victim, bomb_type); // reduced fire damage
break;
case BOMB_DISPELLING:
send_bomb_direct_message(ch, victim, bomb_type);
perform_bomb_spell_effect(ch, victim, bomb_type); // dispel magic
break;
case BOMB_FIRE_BRAND:
send_bomb_direct_message(ch, victim, bomb_type);
perform_bomb_self_effect(ch, victim, bomb_type); // make weapons flaming and flaming burst (at lvl 10)
break;
case BOMB_FORCE:
send_bomb_direct_message(ch, victim, bomb_type);
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
send_bomb_splash_message(ch, victim, bomb_type);
perform_bomb_direct_damage(ch, victim, bomb_type); // reduced force damage
perform_bomb_direct_effect(ch, victim, bomb_type); // knock prone
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
perform_bomb_splash_damage(ch, victim, bomb_type); // reduced force damage
break;
case BOMB_FROST:
send_bomb_direct_message(ch, victim, bomb_type);
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
send_bomb_splash_message(ch, victim, bomb_type);
perform_bomb_direct_damage(ch, victim, bomb_type); // cold damage
perform_bomb_direct_effect(ch, victim, bomb_type); // staggered
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
perform_bomb_splash_damage(ch, victim, bomb_type); // cold damage
break;
case BOMB_HEALING:
send_bomb_direct_message(ch, victim, bomb_type);
perform_bomb_direct_healing(ch, victim, bomb_type); // healing
break;
case BOMB_HOLY:
send_bomb_direct_message(ch, victim, bomb_type);
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
send_bomb_splash_message(ch, victim, bomb_type);
perform_bomb_direct_damage(ch, victim, bomb_type); // holy damage
perform_bomb_direct_effect(ch, victim, bomb_type); // evil victs are staggered
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
perform_bomb_splash_damage(ch, victim, bomb_type); // holy damage
break;
case BOMB_IMMOLATION:
send_bomb_direct_message(ch, victim, bomb_type);
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
send_bomb_splash_message(ch, victim, bomb_type);
perform_bomb_direct_damage(ch, victim, bomb_type); // reduced fire damage
perform_bomb_direct_effect(ch, victim, bomb_type); // DoT effect
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
perform_bomb_splash_damage(ch, victim, bomb_type); // reduced fire damage
break;
case BOMB_POISON:
send_bomb_direct_message(ch, victim, bomb_type);
perform_bomb_spell_effect(ch, victim, bomb_type); // cloudkill
break;
case BOMB_PROFANE:
send_bomb_direct_message(ch, victim, bomb_type);
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
send_bomb_splash_message(ch, victim, bomb_type);
perform_bomb_direct_damage(ch, victim, bomb_type); // unholy damage
perform_bomb_direct_effect(ch, victim, bomb_type); // good victs are staggered
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
perform_bomb_splash_damage(ch, victim, bomb_type); // unholy damage
break;
case BOMB_SHOCK:
send_bomb_direct_message(ch, victim, bomb_type);
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
send_bomb_splash_message(ch, victim, bomb_type);
perform_bomb_direct_damage(ch, victim, bomb_type); // electricity damage
perform_bomb_direct_effect(ch, victim, bomb_type); // dazzled
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
perform_bomb_splash_damage(ch, victim, bomb_type); // electricity damage
break;
case BOMB_STINK:
send_bomb_direct_message(ch, victim, bomb_type);
perform_bomb_spell_effect(ch, victim, bomb_type); // stinking cloud
break;
case BOMB_SUNLIGHT:
send_bomb_direct_message(ch, victim, bomb_type);
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
send_bomb_splash_message(ch, victim, bomb_type);
perform_bomb_direct_damage(ch, victim, bomb_type); // fire damage, +2 damage per die for undead and oozes
perform_bomb_direct_effect(ch, victim, bomb_type); // blind, undead sensitive to sunlight staggered
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
{
perform_bomb_splash_damage(ch, victim, bomb_type); // fire damage, +2 damage per die for undead and oozes
perform_bomb_splash_effect(ch, victim, bomb_type); // dazzle
}
break;
case BOMB_TANGLEFOOT:
send_bomb_direct_message(ch, victim, bomb_type);
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
send_bomb_splash_message(ch, victim, bomb_type);
perform_bomb_direct_effect(ch, victim, bomb_type); // entangled
if (PRF_FLAGGED(ch, PRF_AOE_BOMBS))
perform_bomb_splash_effect(ch, victim, bomb_type); // entangled
break;
}
if (KNOWS_DISCOVERY(ch, ALC_DISC_STICKY_BOMBS))
{
add_sticky_bomb_effect(ch, victim, bomb_type);
}
}
void send_bomb_direct_message(struct char_data *ch, struct char_data *victim, int bomb_type)
{
/* dummy check */
if (!ch || !victim)
return;
char buf[200];
snprintf(buf, sizeof(buf), "%s", bomb_damage_messages[bomb_type][1]);
act(buf, FALSE, ch, 0, victim, TO_CHAR);
if (ch == victim)
{