1 /*
2  * effects.c
3  * Copyright (C) 2009-2020 Joachim de Groot <jdegroot@web.de>
4  *
5  * NLarn is free software: you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * NLarn is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  * See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <glib.h>
20 #include <string.h>
21 
22 #include "cJSON.h"
23 #include "effects.h"
24 #include "game.h"
25 #include "extdefs.h"
26 #include "random.h"
27 
28 static const effect_data effects[ET_MAX] =
29 {
30     /*
31         name "name" duration amount desc
32         msg_start
33         msg_stop
34         msg_start_monster
35         msg_stop_monster
36         var_duration var_amount inc_duration inc_amount
37     */
38 
39     {
40         ET_NONE, "ET_NONE", 0, 0, NULL,
41         NULL, NULL, NULL, NULL,
42         FALSE, FALSE, FALSE, FALSE
43     },
44 
45     {
46         ET_INC_CON, "ET_INC_CON", 1, 1, NULL,
47         "You have a greater intestinal constitution!",
48         NULL, NULL, NULL,
49         FALSE, FALSE, FALSE, TRUE
50     },
51 
52     {
53         ET_INC_DEX, "ET_INC_DEX", 1, 1, NULL,
54         "You feel skilful!",
55         "Your dextrousness returns to normal.",
56         NULL, NULL,
57         FALSE, FALSE, FALSE, TRUE
58     },
59 
60     {
61         ET_INC_INT, "ET_INC_INT", 1, 1, NULL,
62         "You feel clever!",
63         "You are not so smart anymore.",
64         NULL, NULL,
65         FALSE, FALSE, FALSE, TRUE
66     },
67 
68     {
69         ET_INC_STR, "ET_INC_STR", 1, 1, NULL,
70         "Your muscles are stronger!",
71         "Your strength returns to normal.",
72         NULL, NULL,
73         FALSE, FALSE, FALSE, TRUE
74     },
75 
76     {
77         ET_INC_WIS, "ET_INC_WIS", 1, 1, NULL,
78         "You feel more self-confident!",
79         NULL, NULL, NULL,
80         FALSE, FALSE, FALSE, TRUE
81     },
82 
83     {
84         ET_INC_RND, "ET_INC_RND", 1, 1, NULL,
85         NULL, NULL, NULL, NULL,
86         FALSE, FALSE, FALSE, FALSE
87     },
88 
89     {
90         ET_INC_DAMAGE, "ET_INC_DAMAGE", 100, 10, NULL,
91         NULL, NULL, NULL, NULL,
92         TRUE, TRUE, FALSE, TRUE
93     },
94 
95     {
96         ET_INC_HP_MAX, "ET_INC_HP_MAX", 1, 5 /* % */, NULL,
97         "You feel healthy!",
98         NULL, NULL, NULL,
99         FALSE, FALSE, FALSE, FALSE
100     },
101 
102     {
103         ET_INC_MP_MAX, "ET_INC_MP_MAX", 1, 5 /* % */, NULL,
104         "You feel energetic!",
105         NULL, NULL, NULL,
106         FALSE, FALSE, FALSE, FALSE
107     },
108 
109     {
110         ET_INC_HP_REGEN, "ET_INC_HP_REGEN", 0, 1, NULL,
111         NULL, NULL, NULL, NULL,
112         FALSE, FALSE, FALSE, FALSE
113     },
114 
115     {
116         ET_INC_MP_REGEN, "ET_INC_MP_REGEN", 0, 1, NULL,
117         NULL, NULL, NULL, NULL,
118         FALSE, FALSE, FALSE, FALSE
119     },
120 
121     {
122         ET_INC_LEVEL, "ET_INC_LEVEL", 1, 1, NULL,
123         "You feel much more skilful!",
124         NULL, NULL, NULL,
125         FALSE, FALSE, FALSE, FALSE
126     },
127 
128     {
129         ET_INC_EXP, "ET_INC_EXP", 1, 0, NULL,
130         "You feel experienced.",
131         NULL, NULL, NULL,
132         FALSE, FALSE, FALSE, FALSE
133     },
134 
135     {
136         ET_RESIST_FIRE, "ET_RESIST_FIRE", 0, 25, NULL,
137         "You feel a chill run up your spine!",
138         NULL, NULL, NULL,
139         FALSE, FALSE, FALSE, TRUE
140     },
141 
142     {
143         ET_RESIST_COLD, "ET_RESIST_COLD", 0, 25, NULL,
144         NULL, NULL, NULL, NULL,
145         FALSE, FALSE, FALSE, TRUE
146     },
147 
148     {
149         ET_RESIST_MAGIC, "ET_RESIST_MAGIC", 0, 25, NULL,
150         NULL, NULL, NULL, NULL,
151         FALSE, FALSE, FALSE, TRUE
152     },
153 
154     {
155         ET_PROTECTION, "ET_PROTECTION", 250, 3, "protected",
156         "You feel protected!", "Your protection wanes.",
157         NULL, NULL,
158         TRUE, FALSE, TRUE, FALSE
159     },
160 
161     {
162         ET_STEALTH, "ET_STEALTH", 250, TRUE, "stealthy",
163         "You start to move stealthily.",
164         "You're not stealthy anymore.",
165         NULL, NULL,
166         TRUE, FALSE, TRUE, FALSE
167     },
168 
169     {
170         ET_AWARENESS, "ET_AWARENESS", 250, 3, "aware",
171         "You become aware of your surroundings.",
172         "You are no longer aware of your surroundings.",
173         NULL, NULL,
174         TRUE, FALSE, TRUE, FALSE
175     },
176 
177     {
178         ET_SPEED, "ET_SPEED", 250, 25, "fast",
179         "You are suddenly moving much faster.",
180         "You feel yourself slow down.",
181         "The %s seems to move much faster.",
182         "The %s suddenly slows down.",
183         TRUE, FALSE, FALSE, TRUE
184     },
185 
186     {
187         ET_HEROISM, "ET_HEROISM", 250, 5, NULL,
188         "WOW!!! You feel Super-fantastic!!!",
189         "You return to normal. How sad!",
190         "The %s looks more perilous!",
191         "The %s looks less perilous.",
192         FALSE, FALSE, FALSE, FALSE
193     },
194 
195     {
196         ET_INVISIBILITY, "ET_INVISIBILITY", 250, TRUE, "invisible",
197         "Suddenly you can't see yourself!",
198         "You are no longer invisible.",
199         "The %s disappears.",
200         NULL,
201         TRUE, FALSE, TRUE, FALSE
202     },
203 
204     {
205         ET_INVULNERABILITY, "ET_INVULNERABILITY", 250, 10, "invulnerable",
206         NULL, NULL, NULL, NULL,
207         TRUE, FALSE, TRUE, FALSE
208     },
209 
210     {
211         ET_INFRAVISION, "ET_INFRAVISION", 250, TRUE, "infravision",
212         "Your vision sharpens.",
213         "Your vision returns to normal.",
214         "The %s seems more observant.",
215         "The %s seems less observant.",
216         TRUE, FALSE, TRUE, FALSE
217     },
218 
219     {
220         ET_ENLIGHTENMENT, "ET_ENLIGHTENMENT", 250, 8, "enlightened",
221         "You have been granted enlightenment!",
222         "You are no longer enlightened.",
223         NULL, NULL,
224         TRUE, FALSE, TRUE, FALSE
225     },
226 
227     {
228         ET_REFLECTION, "ET_REFLECTION", 400, TRUE, "reflection",
229         NULL, NULL, NULL, NULL,
230         TRUE, FALSE, TRUE, FALSE
231     },
232 
233     {
234         ET_DETECT_MONSTER, "ET_DETECT_MONSTER", 10, TRUE, NULL,
235         "You sense the presence of monsters.",
236         NULL, NULL, NULL,
237         FALSE, FALSE, TRUE, FALSE
238     },
239 
240     {
241         ET_HOLD_MONSTER, "ET_HOLD_MONSTER", 30, TRUE, "held",
242         NULL, NULL,
243         "The %s seems to freeze.",
244         "The %s can move again.",
245         TRUE, FALSE, FALSE, FALSE
246     },
247 
248     {
249         ET_SCARED, "ET_SCARED", 250, TRUE, "scared",
250         NULL, NULL,
251         "The %s is very afraid.",
252         "The %s is no longer scared.",
253         TRUE, FALSE, TRUE, FALSE
254     },
255 
256     {
257         ET_CHARM_MONSTER, "ET_CHARM_MONSTER", 50, TRUE, "charmed",
258         NULL, NULL,
259         "The %s is awestruck at your magnificence!",
260         "The %s is no longer impressed.",
261         TRUE, FALSE, TRUE, FALSE
262     },
263 
264     {
265         ET_INC_HP, "ET_INC_HP", 1, 20 /* % */, NULL,
266         "You feel better.",
267         NULL,
268         "The %s looks better.",
269         NULL,
270         FALSE, TRUE, FALSE, FALSE
271     },
272 
273     {
274         ET_MAX_HP, "ET_MAX_HP", 1, 100 /* % */, NULL,
275         "You are completely healed.",
276         NULL,
277         "The %s looks completely healed.",
278         NULL,
279         FALSE, FALSE, FALSE, FALSE
280     },
281 
282     {
283         ET_INC_MP, "ET_INC_MP", 1, 20 /* % */, NULL,
284         "Magical energies course through your body.",
285         NULL,
286         "The %s seems to regain energy.",
287         NULL,
288         FALSE, TRUE, FALSE, FALSE
289     },
290 
291     {
292         ET_MAX_MP, "ET_MAX_MP", 1, 100 /* % */, NULL,
293         "You feel much more powerful.",
294         NULL,
295         "The %s looks much more powerful.",
296         NULL,
297         FALSE, FALSE, FALSE, FALSE
298     },
299 
300     {
301         ET_CANCELLATION, "ET_CANCELLATION", 250, TRUE, "cancellation",
302         NULL, NULL, NULL, NULL,
303         TRUE, FALSE, TRUE, FALSE
304     },
305 
306     {
307         ET_UNDEAD_PROTECTION, "ET_UNDEAD_PROTECTION", 400, TRUE, "undead protection",
308         "You feel safe in the dark.",
309         NULL, NULL, NULL,
310         TRUE, FALSE, TRUE, FALSE
311     },
312 
313     {
314         ET_SPIRIT_PROTECTION, "ET_SPIRIT_PROTECTION", 400, TRUE, "spirit protection",
315         "You feel a protecting force.",
316         NULL, NULL, NULL,
317         TRUE, FALSE, TRUE, FALSE
318     },
319 
320     {
321         ET_LIFE_PROTECTION, "ET_LIFE_PROTECTION", 2500, TRUE, "life protection",
322         "You've never felt so safe.",
323         "You feel less safe than before.",
324         NULL, NULL,
325         FALSE, FALSE, FALSE, FALSE
326     },
327 
328     {
329         ET_NOTHEFT, "ET_NOTHEFT", 400, TRUE, "theft protection",
330         NULL, NULL, NULL, NULL,
331         TRUE, FALSE, TRUE, FALSE
332     },
333 
334     {
335         ET_SUSTAINMENT, "ET_SUSTAINMENT", 400, TRUE, "sustainment",
336         NULL, NULL, NULL, NULL,
337         TRUE, FALSE, TRUE, FALSE
338     },
339 
340     {
341         ET_TIMESTOP, "ET_TIMESTOP", 20, TRUE, "time stop",
342         NULL, NULL, NULL, NULL,
343         TRUE, FALSE, TRUE, FALSE
344     },
345 
346     {
347         ET_WALL_WALK, "ET_WALL_WALK", 20, TRUE, "wall-walk",
348         "You can now walk through walls.",
349         "You can no longer walk through walls.",
350         NULL, NULL,
351         TRUE, FALSE, TRUE, FALSE
352     },
353 
354     {
355         ET_LEVITATION, "ET_LEVITATION", 20, TRUE, "levitation",
356         "You start to float in the air!",
357         "You gently sink to the ground.",
358         "The %s starts to float in the air!",
359         "The %s gently sinks to the ground.",
360         TRUE, FALSE, TRUE, FALSE
361     },
362 
363     {
364         ET_DEC_CON, "ET_DEC_CON", 1, 1, NULL,
365         "You feel incapacitated.",
366         "You feel tougher.",
367         NULL, NULL,
368         FALSE, FALSE, TRUE, TRUE
369     },
370 
371     {
372         ET_DEC_DEX, "ET_DEC_DEX", 1, 1, NULL,
373         "You feel clumsy.",
374         "Your dexterousness returns.",
375         NULL, NULL,
376         FALSE, FALSE, TRUE, TRUE
377     },
378 
379     {
380         ET_DEC_INT, "ET_DEC_INT", 1, 1, NULL,
381         "You feel imbecile.",
382         "Your intelligence returns.",
383         NULL, NULL,
384         FALSE, FALSE, TRUE, TRUE
385     },
386 
387     {
388         ET_DEC_STR, "ET_DEC_STR", 1, 1, NULL,
389         "You are weaker.",
390         "You regain your strength.",
391         NULL, NULL,
392         FALSE, FALSE, TRUE, TRUE
393     },
394 
395     {
396         ET_DEC_WIS, "ET_DEC_WIS", 1, 1, NULL,
397         "You feel ignorant.",
398         "You feel less ignorant.",
399         NULL, NULL,
400         FALSE, FALSE, TRUE, TRUE
401     },
402 
403     {
404         ET_DEC_RND, "ET_DEC_RND", 1, 1, NULL,
405         NULL, NULL, NULL, NULL,
406         FALSE, FALSE, FALSE, FALSE
407     },
408 
409     {
410         ET_AGGRAVATE_MONSTER, "ET_AGGRAVATE_MONSTER", 500, TRUE, "aggravating",
411         "You sense rising anger.",
412         NULL, NULL, NULL,
413         TRUE, FALSE, TRUE, FALSE
414     },
415 
416     {
417         ET_SLEEP, "ET_SLEEP", 25, TRUE, "sleeping",
418         "You fall asleep.",
419         "You wake up.",
420         "The %s falls asleep.",
421         "The %s wakes up.",
422         TRUE, FALSE, FALSE, FALSE
423     },
424 
425     {
426         ET_DIZZINESS, "ET_DIZZINESS", 250, 5, "dizzy",
427         "You're dizzy and weak!",
428         "You're no longer dizzy.",
429         "The %s looks dizzy and weak.",
430         "The %s no longer looks dizzy.",
431         TRUE, FALSE, FALSE, FALSE
432     },
433 
434     {
435         ET_SICKNESS, "ET_SICKNESS", 250, 10, "sick",
436         "You feel a sickness coming on.",
437         "You now feel better.",
438         NULL, NULL,
439         TRUE, TRUE, TRUE, TRUE
440     },
441 
442     {
443         ET_BLINDNESS, "ET_BLINDNESS", 250, TRUE, "blind",
444         "You can't see anything!",
445         "The blindness lifts.",
446         "The %s seems to be blinded.",
447         "Looks like the %s can see again.",
448         TRUE, FALSE, FALSE, FALSE
449     },
450 
451     {
452         ET_CLUMSINESS, "ET_CLUMSINESS", 250, TRUE, "clumsy",
453         "You begin to lose hand to eye coordination!",
454         "You're less awkward now.",
455         NULL, NULL,
456         TRUE, FALSE, FALSE, FALSE
457     },
458 
459     {
460         ET_ITCHING, "ET_ITCHING", 100, TRUE, "itching",
461         "You feel an irritation spread over your skin!",
462         "The irritation subsides.",
463         NULL, NULL,
464         TRUE, FALSE, FALSE, FALSE
465     },
466 
467     {
468         ET_CONFUSION, "ET_CONFUSION", 25, TRUE, "confused",
469         "You are confused.",
470         "You regain your senses.",
471         "The %s looks confused.",
472         "The %s seems to have regained it's senses.",
473         TRUE, FALSE, FALSE, FALSE
474     },
475 
476     {
477         ET_PARALYSIS, "ET_PARALYSIS", 25, TRUE, "paralysed",
478         "You are paralysed.",
479         "You can move again.",
480         NULL, NULL,
481         TRUE, FALSE, FALSE, FALSE
482     },
483 
484     {
485         ET_POISON, "ET_POISON", 300, 1, "poisoned",
486         NULL, /* message is shown in player_damage_take */
487         "You are cured.",
488         "The %s looks poisoned.",
489         "The %s looks cured.",
490         TRUE, FALSE, TRUE, TRUE
491     },
492 
493     {
494         ET_AMNESIA, "ET_AMNESIA", 1, 0, NULL,
495         NULL, NULL, NULL, NULL,
496         FALSE, FALSE, FALSE, FALSE
497     },
498 
499     {
500         ET_SLOWNESS, "ET_SLOWNESS", 250, 25, "slow",
501         "You feel yourself slow down.",
502         "You are moving faster again.",
503         "The %s slows down.",
504         "The %s seems to move much faster.",
505         TRUE, FALSE, FALSE, TRUE
506     },
507 
508     {
509         ET_BURDENED, "ET_BURDENED", 0, 25, "burdened",
510         "You are burdened.",
511         "You are no longer burdened.",
512         NULL, NULL,
513         FALSE, FALSE, FALSE, FALSE
514     },
515 
516     {
517         ET_OVERSTRAINED, "ET_OVERSTRAINED", 0, TRUE, "overload",
518         "You are overloaded!",
519         "You are no longer overloaded.",
520         NULL, NULL,
521         FALSE, FALSE, FALSE, FALSE
522     },
523 
524     {
525         ET_TRAPPED, "ET_TRAPPED", 10, TRUE, "trapped",
526         NULL,
527         "You are no longer trapped!",
528         NULL,
529         "The %s climbs out of the pit!",
530         TRUE, FALSE, TRUE, FALSE
531     },
532 };
533 
effect_new(effect_t type)534 effect *effect_new(effect_t type)
535 {
536     effect *ne;
537 
538     g_assert(type > ET_NONE && type < ET_MAX);
539 
540     ne = g_malloc0(sizeof(effect));
541     ne->type = type;
542     ne->start = game_turn(nlarn);
543 
544     /* determine effect duration */
545     if (effects[type].var_duration)
546     {
547         ne->turns = divert(effects[type].duration, 10);
548     }
549     else
550     {
551         ne->turns = effects[type].duration;
552     }
553 
554     /* determine effect amount */
555     if (effects[type].var_amount)
556     {
557         ne->amount = divert(effects[type].amount, 10);
558     }
559     else
560     {
561         ne->amount = effects[type].amount;
562     }
563 
564     /* register effect */
565     ne->oid = game_effect_register(nlarn, ne);
566 
567     return ne;
568 }
569 
effect_copy(effect * e)570 effect *effect_copy(effect *e)
571 {
572     effect *ne;
573 
574     g_assert(e != NULL);
575 
576     ne = g_malloc(sizeof(effect));
577     memcpy(ne, e, sizeof(effect));
578 
579     /* register copy with game */
580     ne->oid = game_effect_register(nlarn, ne);
581 
582     return ne;
583 }
584 
effect_destroy(effect * e)585 void effect_destroy(effect *e)
586 {
587     g_assert(e != NULL);
588 
589     /* unregister effect */
590     game_effect_unregister(nlarn, e->oid);
591 
592     g_free(e);
593 }
594 
effect_serialize(gpointer oid,effect * e,cJSON * root)595 void effect_serialize(gpointer oid, effect *e, cJSON *root)
596 {
597     cJSON *eval;
598 
599     cJSON_AddItemToArray(root, eval = cJSON_CreateObject());
600 
601     cJSON_AddNumberToObject(eval,"oid", GPOINTER_TO_UINT(oid));
602     cJSON_AddNumberToObject(eval,"type", e->type);
603     cJSON_AddNumberToObject(eval,"start", e->start);
604     cJSON_AddNumberToObject(eval,"turns", e->turns);
605     cJSON_AddNumberToObject(eval,"amount", e->amount);
606 
607     if (e->item)
608     {
609         cJSON_AddNumberToObject(eval,"item", GPOINTER_TO_UINT(e->item));
610     }
611 }
612 
effect_deserialize(cJSON * eser,game * g)613 effect *effect_deserialize(cJSON *eser, game *g)
614 {
615     effect *e;
616     guint oid;
617     cJSON *itm;
618 
619     e = g_malloc0(sizeof(effect));
620 
621     oid = cJSON_GetObjectItem(eser, "oid")->valueint;
622     e->oid =  GUINT_TO_POINTER(oid);
623 
624     e->type = cJSON_GetObjectItem(eser, "type")->valueint;
625     e->start = cJSON_GetObjectItem(eser, "start")->valueint;
626     e->turns = cJSON_GetObjectItem(eser, "turns")->valueint;
627     e->amount = cJSON_GetObjectItem(eser, "amount")->valueint;
628 
629     if ((itm = cJSON_GetObjectItem(eser, "item")))
630     {
631         e->item = GUINT_TO_POINTER(itm->valueint);
632     }
633 
634     /* add effect to game */
635     g_hash_table_insert(g->effects, e->oid, e);
636 
637     /* increase max_id to match used ids */
638     if (g->effect_max_id < oid)
639     {
640         g->effect_max_id = oid;
641     }
642 
643     return e;
644 }
645 
effects_serialize(GPtrArray * effs)646 cJSON *effects_serialize(GPtrArray *effs)
647 {
648     cJSON *eser = cJSON_CreateArray();
649 
650     for (guint idx = 0; idx < effs->len; idx++)
651     {
652         gpointer eff_oid = g_ptr_array_index(effs, idx);
653         cJSON_AddItemToArray(eser, cJSON_CreateNumber(GPOINTER_TO_UINT(eff_oid)));
654     }
655 
656     return eser;
657 }
658 
effects_deserialize(cJSON * eser)659 GPtrArray *effects_deserialize(cJSON *eser)
660 {
661     GPtrArray *effs = g_ptr_array_new();
662 
663     for (int idx = 0; idx < cJSON_GetArraySize(eser); idx++)
664     {
665         cJSON *effser = cJSON_GetArrayItem(eser, idx);
666         guint oid = effser->valueint;
667         g_ptr_array_add(effs, GUINT_TO_POINTER(oid));
668     }
669 
670     return effs;
671 }
672 
effect_type_name(effect_t type)673 const char *effect_type_name(effect_t type)
674 {
675     g_assert(type < ET_MAX);
676     return effects[type].name;
677 }
678 
effect_type_amount(effect_t type)679 int effect_type_amount(effect_t type)
680 {
681     g_assert(type < ET_MAX);
682     return effects[type].amount;
683 }
684 
effect_type_duration(effect_t type)685 guint effect_type_duration(effect_t type)
686 {
687     g_assert(type < ET_MAX);
688     return effects[type].duration;
689 }
690 
effect_type_inc_duration(effect_t type)691 gboolean effect_type_inc_duration(effect_t type)
692 {
693     g_assert(type < ET_MAX);
694     return effects[type].inc_duration;
695 }
696 
effect_type_inc_amount(effect_t type)697 gboolean effect_type_inc_amount(effect_t type)
698 {
699     g_assert(type < ET_MAX);
700     return effects[type].inc_amount;
701 }
702 
effect_get_desc(effect * e)703 const char *effect_get_desc(effect *e)
704 {
705     g_assert(e != NULL && e->type > ET_NONE && e->type < ET_MAX);
706     return effects[e->type].desc;
707 }
708 
effect_get_msg_start(effect * e)709 const char *effect_get_msg_start(effect *e)
710 {
711     g_assert(e != NULL && e->type > ET_NONE && e->type < ET_MAX);
712     return effects[e->type].msg_start;
713 }
714 
effect_get_msg_stop(effect * e)715 const char *effect_get_msg_stop(effect *e)
716 {
717     g_assert(e != NULL && e->type > ET_NONE && e->type < ET_MAX);
718     return effects[e->type].msg_stop;
719 }
720 
effect_get_msg_m_start(effect * e)721 const char *effect_get_msg_m_start(effect *e)
722 {
723     g_assert(e != NULL && e->type > ET_NONE && e->type < ET_MAX);
724     return effects[e->type].msg_start_monster;
725 }
726 
effect_get_msg_m_stop(effect * e)727 const char *effect_get_msg_m_stop(effect *e)
728 {
729     g_assert(e != NULL && e->type > ET_NONE && e->type < ET_MAX);
730     return effects[e->type].msg_stop_monster;
731 }
732 
effect_get_amount(effect * e)733 int effect_get_amount(effect *e)
734 {
735     g_assert (e != NULL);
736     return e->amount;
737 }
738 
effect_add(GPtrArray * ea,effect * ne)739 effect *effect_add(GPtrArray *ea, effect *ne)
740 {
741     effect *e;
742 
743     g_assert(ea != NULL && ne != NULL);
744 
745     /* check for existing effects unless the effect belongs to an item */
746     if (!ne->item && (e = effect_get(ea, ne->type)))
747     {
748         gboolean modified_existing = FALSE;
749 
750         /* if the effect's duration can be extended, reset it */
751         if (effects[e->type].inc_duration)
752         {
753             e->turns = max(e->turns, ne->turns);
754             modified_existing = TRUE;
755         }
756 
757         /* if the effect's amount can be extended, do so */
758         if (effects[e->type].inc_amount)
759         {
760             e->amount += ne->amount;
761             modified_existing = TRUE;
762         }
763 
764         effect_destroy(ne);
765 
766         if (modified_existing == TRUE)
767         {
768             return e;
769         }
770         else
771         {
772             return NULL;
773         }
774     }
775     else
776     {
777         g_ptr_array_add(ea, ne->oid);
778         return ne;
779     }
780 }
781 
effect_del(GPtrArray * ea,effect * e)782 int effect_del(GPtrArray *ea, effect *e)
783 {
784     g_assert(ea != NULL && e != NULL);
785     return g_ptr_array_remove_fast(ea, e->oid);
786 }
787 
effect_get(GPtrArray * ea,effect_t type)788 effect *effect_get(GPtrArray *ea, effect_t type)
789 {
790     g_assert(ea != NULL && type > ET_NONE && type < ET_MAX);
791 
792     for (guint idx = 0; idx < ea->len; idx++)
793     {
794         gpointer effect_id = g_ptr_array_index(ea, idx);
795         effect *e = game_effect_get(nlarn, effect_id);
796 
797         /* do not return effects caused by items */
798         if ((e->type == type) && (e->item == NULL))
799         {
800             return e;
801         }
802     }
803 
804     return NULL;
805 }
806 
effect_query(GPtrArray * ea,effect_t type)807 int effect_query(GPtrArray *ea, effect_t type)
808 {
809     int amount = 0;
810 
811     g_assert(ea != NULL && type > ET_NONE && type < ET_MAX);
812 
813     for (guint idx = 0; idx < ea->len; idx++)
814     {
815         gpointer effect_id = g_ptr_array_index(ea, idx);
816         effect *e = game_effect_get(nlarn, effect_id);
817 
818         if (e->type == type) amount += e->amount;
819     }
820 
821     return amount;
822 }
823 
effect_expire(effect * e)824 int effect_expire(effect *e)
825 {
826     g_assert(e != NULL);
827 
828     if (e->turns > 1)
829     {
830         e->turns--;
831     }
832     else if (e->turns != 0)
833     {
834         e->turns = -1;
835     }
836 
837     return e->turns;
838 }
839