TickHook: Fix crash when TickHook isn't set.
[gemrb.git] / gemrb / plugins / FXOpcodes / FXOpcodes.cpp
blob20376774d067c13ffe3e041c2f51602f06e7cfb0
1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "ie_feats.h" //cannot avoid declaring these
22 #include "opcode_params.h"
23 #include "overlays.h"
24 #include "strrefs.h"
25 #include "win32def.h"
27 #include "Audio.h"
28 #include "DisplayMessage.h"
29 #include "EffectQueue.h"
30 #include "Game.h"
31 #include "GameData.h"
32 #include "Interface.h"
33 #include "Projectile.h" //needs for clearair
34 #include "Spell.h" //needed for fx_cast_spell feedback
35 #include "TileMap.h" //needs for knock!
36 #include "damages.h"
37 #include "GameScript/GSUtils.h" //needs for MoveBetweenAreasCore
38 #include "GUI/GameControl.h"
39 #include "Scriptable/Actor.h"
40 #include "PolymorphCache.h" // fx_polymorph
41 #include "Scriptable/PCStatStruct.h" //fx_polymorph (action definitions)
43 //FIXME: find a way to handle portrait icons better
44 #define PI_CONFUSED 3
45 #define PI_BERSERK 4
46 #define PI_POISONED 6
47 #define PI_HELD 13
48 #define PI_SLEEP 14
49 #define PI_BLESS 17
50 #define PI_PANIC 36
51 #define PI_HASTED 38
52 #define PI_FATIGUE 39
53 #define PI_SLOWED 41
54 #define PI_HOPELESS 44
55 #define PI_LEVELDRAIN 53
56 #define PI_FEEBLEMIND 54
57 #define PI_STUN 55
58 #define PI_AID 57
59 #define PI_HOLY 59
60 #define PI_BOUNCE 65
61 #define PI_BOUNCE2 67
63 #define PI_BLOODRAGE 76 //iwd2
64 #define PI_MAZE 78
65 #define PI_PRISON 79
66 #define PI_STONESKIN 80
67 #define PI_DEAFNESS 83 //iwd2
68 #define PI_SEQUENCER 92
69 #define PI_BLUR 109
70 #define PI_IMPROVEDHASTE 110
71 #define PI_SPELLTRAP 117
72 #define PI_CSHIELD 162
73 #define PI_CSHIELD2 163
75 static ieResRef *casting_glows = NULL;
76 static int cgcount = -1;
77 static ieResRef *spell_hits = NULL;
78 static bool enhanced_effects = false;
79 static int shcount = -1;
80 static int *spell_abilities = NULL;
81 static ieDword splabcount = 0;
82 static int *polymorph_stats = NULL;
83 static int polystatcount = 0;
84 static bool pstflags = false;
86 //the original engine stores the colors in sprklclr.2da in a different order
88 static ScriptedAnimation default_spell_hit;
90 int fx_ac_vs_damage_type_modifier (Scriptable* Owner, Actor* target, Effect* fx);//00
91 int fx_attacks_per_round_modifier (Scriptable* Owner, Actor* target, Effect* fx);//01
92 int fx_cure_sleep_state (Scriptable* Owner, Actor* target, Effect* fx);//02
93 int fx_set_berserk_state (Scriptable* Owner, Actor* target, Effect* fx);//03
94 int fx_cure_berserk_state (Scriptable* Owner, Actor* target, Effect* fx);//04
95 int fx_set_charmed_state (Scriptable* Owner, Actor* target, Effect* fx);//05
96 int fx_charisma_modifier (Scriptable* Owner, Actor* target, Effect* fx);//06
97 int fx_set_color_gradient (Scriptable* Owner, Actor* target, Effect* fx);//07
98 int fx_set_color_rgb (Scriptable* Owner, Actor* target, Effect* fx);//08
99 int fx_set_color_rgb_global (Scriptable* Owner, Actor* target, Effect* fx);//08
100 int fx_set_color_pulse_rgb (Scriptable* Owner, Actor* target, Effect* fx);//09
101 int fx_set_color_pulse_rgb_global (Scriptable* Owner, Actor* target, Effect* fx);//09
102 int fx_constitution_modifier (Scriptable* Owner, Actor* target, Effect* fx);//0a
103 int fx_cure_poisoned_state (Scriptable* Owner, Actor* target, Effect* fx);//0b
104 int fx_damage (Scriptable* Owner, Actor* target, Effect* fx);//0c
105 int fx_death (Scriptable* Owner, Actor* target, Effect* fx);//0d
106 int fx_cure_frozen_state (Scriptable* Owner, Actor* target, Effect* fx);//0e
107 int fx_dexterity_modifier (Scriptable* Owner, Actor* target, Effect* fx);//0f
108 int fx_set_hasted_state (Scriptable* Owner, Actor* target, Effect* fx);//10
109 int fx_current_hp_modifier (Scriptable* Owner, Actor* target, Effect* fx);//11
110 int fx_maximum_hp_modifier (Scriptable* Owner, Actor* target, Effect* fx);//12
111 int fx_intelligence_modifier (Scriptable* Owner, Actor* target, Effect* fx);//13
112 int fx_set_invisible_state (Scriptable* Owner, Actor* target, Effect* fx);//14
113 int fx_lore_modifier (Scriptable* Owner, Actor* target, Effect* fx);//15
114 int fx_luck_modifier (Scriptable* Owner, Actor* target, Effect* fx);//16
115 int fx_morale_modifier (Scriptable* Owner, Actor* target, Effect* fx);//17
116 int fx_set_panic_state (Scriptable* Owner, Actor* target, Effect* fx);//18
117 int fx_set_poisoned_state (Scriptable* Owner, Actor* target, Effect* fx);//19
118 int fx_remove_curse (Scriptable* Owner, Actor* target, Effect* fx);//1a
119 int fx_acid_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//1b
120 int fx_cold_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//1c
121 int fx_electricity_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//1d
122 int fx_fire_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//1e
123 int fx_magic_damage_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//1f
124 int fx_cure_dead_state (Scriptable* Owner, Actor* target, Effect* fx);//20
125 int fx_save_vs_death_modifier (Scriptable* Owner, Actor* target, Effect* fx);//21
126 int fx_save_vs_wands_modifier (Scriptable* Owner, Actor* target, Effect* fx);//22
127 int fx_save_vs_poly_modifier (Scriptable* Owner, Actor* target, Effect* fx);//23
128 int fx_save_vs_breath_modifier (Scriptable* Owner, Actor* target, Effect* fx);//24
129 int fx_save_vs_spell_modifier (Scriptable* Owner, Actor* target, Effect* fx);//25
130 int fx_set_silenced_state (Scriptable* Owner, Actor* target, Effect* fx);//26
131 int fx_set_unconscious_state (Scriptable* Owner, Actor* target, Effect* fx);//27
132 int fx_set_slowed_state (Scriptable* Owner, Actor* target, Effect* fx);//28
133 int fx_sparkle(Scriptable* Owner, Actor* target, Effect* fx);//29
134 int fx_bonus_wizard_spells (Scriptable* Owner, Actor* target, Effect* fx);//2a
135 int fx_cure_petrified_state (Scriptable* Owner, Actor* target, Effect* fx);//2b
136 int fx_strength_modifier (Scriptable* Owner, Actor* target, Effect* fx);//2c
137 int fx_set_stun_state (Scriptable* Owner, Actor* target, Effect* fx);//2d
138 int fx_cure_stun_state (Scriptable* Owner, Actor* target, Effect* fx);//2e
139 int fx_cure_invisible_state (Scriptable* Owner, Actor* target, Effect* fx);//2f
140 int fx_cure_silenced_state (Scriptable* Owner, Actor* target, Effect* fx);//30
141 int fx_wisdom_modifier (Scriptable* Owner, Actor* target, Effect* fx);//31
142 int fx_brief_rgb (Scriptable* Owner, Actor* target, Effect* fx);//32
143 int fx_darken_rgb (Scriptable* Owner, Actor* target, Effect* fx);//33
144 int fx_glow_rgb (Scriptable* Owner, Actor* target, Effect* fx);//34
145 int fx_animation_id_modifier (Scriptable* Owner, Actor* target, Effect* fx);//35
146 int fx_to_hit_modifier (Scriptable* Owner, Actor* target, Effect* fx);//36
147 int fx_kill_creature_type (Scriptable* Owner, Actor* target, Effect* fx);//37
148 int fx_alignment_invert (Scriptable* Owner, Actor* target, Effect* fx);//38
149 int fx_alignment_change (Scriptable* Owner, Actor* target, Effect* fx);//39
150 int fx_dispel_effects (Scriptable* Owner, Actor* target, Effect* fx);//3a
151 int fx_stealth_modifier (Scriptable* Owner, Actor* target, Effect* fx);//3b
152 int fx_miscast_magic_modifier (Scriptable* Owner, Actor* target, Effect* fx);//3c
153 int fx_alchemy_modifier (Scriptable* Owner, Actor* target, Effect* fx);//3d
154 int fx_bonus_priest_spells (Scriptable* Owner, Actor* target, Effect* fx);//3e
155 int fx_set_infravision_state (Scriptable* Owner, Actor* target, Effect* fx);//3f
156 int fx_cure_infravision_state (Scriptable* Owner, Actor* target, Effect* fx);//40
157 int fx_set_blur_state (Scriptable* Owner, Actor* target, Effect* fx);//41
158 int fx_transparency_modifier (Scriptable* Owner, Actor* target, Effect* fx);//42
159 int fx_summon_creature (Scriptable* Owner, Actor* target, Effect* fx);//43
160 int fx_unsummon_creature (Scriptable* Owner, Actor* target, Effect* fx);//44
161 int fx_set_nondetection_state (Scriptable* Owner, Actor* target, Effect* fx);//45
162 int fx_cure_nondetection_state (Scriptable* Owner, Actor* target, Effect* fx);//46
163 int fx_sex_modifier (Scriptable* Owner, Actor* target, Effect* fx);//47
164 int fx_ids_modifier (Scriptable* Owner, Actor* target, Effect* fx);//48
165 int fx_damage_bonus_modifier (Scriptable* Owner, Actor* target, Effect* fx);//49
166 int fx_set_blind_state (Scriptable* Owner, Actor* target, Effect* fx);//4a
167 int fx_cure_blind_state (Scriptable* Owner, Actor* target, Effect* fx);//4b
168 int fx_set_feebleminded_state (Scriptable* Owner, Actor* target, Effect* fx);//4c
169 int fx_cure_feebleminded_state (Scriptable* Owner, Actor* target, Effect* fx);//4d
170 int fx_set_diseased_state (Scriptable* Owner, Actor* target, Effect*fx);//4e
171 int fx_cure_diseased_state (Scriptable* Owner, Actor* target, Effect* fx);//4f
172 int fx_set_deaf_state (Scriptable* Owner, Actor* target, Effect* fx); //50
173 int fx_set_deaf_state_iwd2 (Scriptable* Owner, Actor* target, Effect* fx); //50
174 int fx_cure_deaf_state (Scriptable* Owner, Actor* target, Effect* fx);//51
175 int fx_set_ai_script (Scriptable* Owner, Actor* target, Effect*fx);//52
176 int fx_protection_from_projectile (Scriptable* Owner, Actor* target, Effect*fx);//53
177 int fx_magical_fire_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//54
178 int fx_magical_cold_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//55
179 int fx_slashing_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//56
180 int fx_crushing_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//57
181 int fx_piercing_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//58
182 int fx_missiles_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//59
183 int fx_open_locks_modifier (Scriptable* Owner, Actor* target, Effect* fx);//5a
184 int fx_find_traps_modifier (Scriptable* Owner, Actor* target, Effect* fx);//5b
185 int fx_pick_pockets_modifier (Scriptable* Owner, Actor* target, Effect* fx);//5c
186 int fx_fatigue_modifier (Scriptable* Owner, Actor* target, Effect* fx);//5d
187 int fx_intoxication_modifier (Scriptable* Owner, Actor* target, Effect* fx);//5e
188 int fx_tracking_modifier (Scriptable* Owner, Actor* target, Effect* fx);//5f
189 int fx_level_modifier (Scriptable* Owner, Actor* target, Effect* fx);//60
190 int fx_strength_bonus_modifier (Scriptable* Owner, Actor* target, Effect* fx);//61
191 int fx_set_regenerating_state (Scriptable* Owner, Actor* target, Effect* fx);//62
192 int fx_spell_duration_modifier (Scriptable* Owner, Actor* target, Effect* fx);///63
193 int fx_generic_effect (Scriptable* Owner, Actor* target, Effect* fx);//64 protection from creature is a generic effect
194 int fx_protection_opcode(Scriptable* Owner, Actor* target, Effect* fx); //65
195 int fx_protection_spelllevel (Scriptable* Owner, Actor* target, Effect* fx); //66
196 int fx_change_name (Scriptable* Owner, Actor* target, Effect* fx);//67
197 int fx_experience_modifier (Scriptable* Owner, Actor* target, Effect* fx);//68
198 int fx_gold_modifier (Scriptable* Owner, Actor* target, Effect* fx);//69
199 int fx_morale_break_modifier (Scriptable* Owner, Actor* target, Effect* fx);//6a
200 int fx_portrait_change (Scriptable* Owner, Actor* target, Effect* fx);//6b
201 int fx_reputation_modifier (Scriptable* Owner, Actor* target, Effect* fx);//6c
202 int fx_hold_creature_no_icon (Scriptable* Owner, Actor* target, Effect* fx);//6d
203 //int fx_retreat_from (Scriptable* Owner, Actor* target, Effect* fx);//6e reused
204 int fx_create_magic_item (Scriptable* Owner, Actor* target, Effect* fx);//6f
205 int fx_remove_item (Scriptable* Owner, Actor* target, Effect* fx);//70
206 int fx_equip_item (Scriptable* Owner, Actor* target, Effect* fx);//71
207 int fx_dither (Scriptable* Owner, Actor* target, Effect* fx);//72
208 int fx_detect_alignment (Scriptable* Owner, Actor* target, Effect* fx);//73
209 //int fx_cure_improved_invisible_state (Scriptable* Owner, Actor* target, Effect* fx);//74 (2f)
210 int fx_reveal_area (Scriptable* Owner, Actor* target, Effect* fx);//75
211 int fx_reveal_creatures (Scriptable* Owner, Actor* target, Effect* fx);//76
212 int fx_mirror_image (Scriptable* Owner, Actor* target, Effect* fx);//77
213 int fx_immune_to_weapon (Scriptable* Owner, Actor* target, Effect* fx);//78
214 int fx_visual_animation_effect (Scriptable* Owner, Actor* target, Effect* fx);//79 unknown
215 int fx_create_inventory_item (Scriptable* Owner, Actor* target, Effect* fx);//7a
216 int fx_remove_inventory_item (Scriptable* Owner, Actor* target, Effect* fx);//7b
217 int fx_dimension_door (Scriptable* Owner, Actor* target, Effect* fx);//7c
218 int fx_knock (Scriptable* Owner, Actor* target, Effect* fx);//7d
219 int fx_movement_modifier (Scriptable* Owner, Actor* target, Effect* fx);//7e
220 int fx_monster_summoning (Scriptable* Owner, Actor* target, Effect* fx);//7f
221 int fx_set_confused_state (Scriptable* Owner, Actor* target, Effect* fx);//80
222 int fx_set_aid_state (Scriptable* Owner, Actor* target, Effect* fx);//81
223 int fx_set_bless_state (Scriptable* Owner, Actor* target, Effect* fx);//82
224 int fx_set_chant_state (Scriptable* Owner, Actor* target, Effect* fx);//83
225 int fx_set_holy_state (Scriptable* Owner, Actor* target, Effect* fx);//84
226 int fx_luck_non_cumulative (Scriptable* Owner, Actor* target, Effect* fx);//85
227 int fx_luck_cumulative (Scriptable* Owner, Actor* target, Effect* fx);//85
228 int fx_set_petrified_state (Scriptable* Owner, Actor* target, Effect* fx);//86
229 int fx_polymorph (Scriptable* Owner, Actor* target, Effect* fx);//87
230 int fx_force_visible (Scriptable* Owner, Actor* target, Effect* fx);//88
231 int fx_set_chantbad_state (Scriptable* Owner, Actor* target, Effect* fx);//89
232 int fx_animation_stance (Scriptable* Owner, Actor* target, Effect* fx);//8a
233 int fx_display_string (Scriptable* Owner, Actor* target, Effect* fx);//8b
234 int fx_casting_glow (Scriptable* Owner, Actor* target, Effect* fx);//8c
235 int fx_visual_spell_hit (Scriptable* Owner, Actor* target, Effect* fx);//8d
236 int fx_display_portrait_icon (Scriptable* Owner, Actor* target, Effect* fx);//8e
237 int fx_create_item_in_slot (Scriptable* Owner, Actor* target, Effect* fx);//8f
238 int fx_disable_button (Scriptable* Owner, Actor* target, Effect* fx);//90
239 int fx_disable_spellcasting (Scriptable* Owner, Actor* target, Effect* fx);//91
240 int fx_cast_spell (Scriptable* Owner, Actor* target, Effect *fx);//92
241 int fx_learn_spell (Scriptable* Owner, Actor* target, Effect *fx);//93
242 int fx_cast_spell_point (Scriptable* Owner, Actor* target, Effect *fx);//94
243 int fx_identify (Scriptable* Owner, Actor* target, Effect *fx);//95
244 int fx_find_traps (Scriptable* Owner, Actor* target, Effect *fx);//96
245 int fx_replace_creature (Scriptable* Owner, Actor* target, Effect *fx);//97
246 int fx_play_movie (Scriptable* Owner, Actor* target, Effect* fx);//98
247 int fx_set_sanctuary_state (Scriptable* Owner, Actor* target, Effect* fx);//99
248 int fx_set_entangle_state (Scriptable* Owner, Actor* target, Effect* fx);//9a
249 int fx_set_minorglobe_state (Scriptable* Owner, Actor* target, Effect* fx);//9b
250 int fx_set_shieldglobe_state (Scriptable* Owner, Actor* target, Effect* fx);//9c
251 int fx_set_web_state (Scriptable* Owner, Actor* target, Effect* fx);//9d
252 int fx_set_grease_state (Scriptable* Owner, Actor* target, Effect* fx);//9e
253 int fx_mirror_image_modifier (Scriptable* Owner, Actor* target, Effect* fx);//9f
254 int fx_cure_sanctuary_state (Scriptable* Owner, Actor* target, Effect* fx);//a0
255 int fx_cure_panic_state (Scriptable* Owner, Actor* target, Effect* fx);//a1
256 int fx_cure_hold_state (Scriptable* Owner, Actor* target, Effect* fx);//a2 //cures 175
257 int fx_cure_slow_state (Scriptable* Owner, Actor* target, Effect* fx);//a3
258 int fx_cure_intoxication (Scriptable* Owner, Actor* target, Effect* fx);//a4
259 int fx_pause_target (Scriptable* Owner, Actor* target, Effect* fx);//a5
260 int fx_magic_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//a6
261 int fx_missile_to_hit_modifier (Scriptable* Owner, Actor* target, Effect* fx);//a7
262 int fx_remove_creature (Scriptable* Owner, Actor* target, Effect* fx);//a8
263 int fx_disable_portrait_icon (Scriptable* Owner, Actor* target, Effect* fx);//a9
264 int fx_damage_animation (Scriptable* Owner, Actor* target, Effect* fx);//aa
265 int fx_add_innate (Scriptable* Owner, Actor* target, Effect* fx);//ab
266 int fx_remove_spell (Scriptable* Owner, Actor* target, Effect* fx);//ac
267 int fx_poison_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//ad
268 int fx_playsound (Scriptable* Owner, Actor* target, Effect* fx);//ae
269 int fx_hold_creature (Scriptable* Owner, Actor* target, Effect* fx);//af
270 // this function is exactly the same as 0x7e fx_movement_modifier (in bg2 at least)//b0
271 int fx_apply_effect (Scriptable* Owner, Actor* target, Effect* fx);//b1
272 //b2 //hitbonus against creature (generic_effect)
273 //b3 //damagebonus against creature (generic effect)
274 //b4 //restrict item (generic effect)
275 //b5 //restrict itemtype (generic effect)
276 int fx_apply_effect_item (Scriptable* Owner, Actor* target, Effect* fx);//b6
277 int fx_apply_effect_item_type (Scriptable* Owner, Actor* target, Effect* fx);//b7
278 int fx_dontjump_modifier (Scriptable* Owner, Actor* target, Effect* fx);//b8
279 // this function is exactly the same as 0xaf hold_creature (in bg2 at least) //b9
280 int fx_move_to_area (Scriptable* Owner, Actor* target, Effect* fx);//ba
281 int fx_local_variable (Scriptable* Owner, Actor* target, Effect* fx);//bb
282 int fx_auracleansing_modifier (Scriptable* Owner, Actor* target, Effect* fx);//bc
283 int fx_castingspeed_modifier (Scriptable* Owner, Actor* target, Effect* fx);//bd
284 int fx_attackspeed_modifier (Scriptable* Owner, Actor* target, Effect* fx);//be
285 int fx_castinglevel_modifier (Scriptable* Owner, Actor* target, Effect* fx);//bf
286 int fx_find_familiar (Scriptable* Owner, Actor* target, Effect* fx);//c0
287 int fx_see_invisible_modifier (Scriptable* Owner, Actor* target, Effect* fx);//c1
288 int fx_ignore_dialogpause_modifier (Scriptable* Owner, Actor* target, Effect* fx);//c2
289 int fx_familiar_constitution_loss (Scriptable* Owner, Actor* target, Effect* fx);//c3
290 int fx_familiar_marker (Scriptable* Owner, Actor* target, Effect* fx);//c4
291 int fx_bounce_projectile (Scriptable* Owner, Actor* target, Effect* fx);//c5
292 int fx_bounce_opcode (Scriptable* Owner, Actor* target, Effect* fx);//c6
293 int fx_bounce_spelllevel (Scriptable* Owner, Actor* target, Effect* fx);//c7
294 int fx_bounce_spelllevel_dec (Scriptable* Owner, Actor* target, Effect* fx);//c8
295 int fx_protection_spelllevel_dec (Scriptable* Owner, Actor* target, Effect* fx);//c9
296 int fx_bounce_school (Scriptable* Owner, Actor* target, Effect* fx);//ca
297 int fx_bounce_secondary_type (Scriptable* Owner, Actor* target, Effect* fx);//cb
298 int fx_protection_school (Scriptable* Owner, Actor* target, Effect* fx); //cc
299 int fx_protection_secondary_type (Scriptable* Owner, Actor* target, Effect* fx); //cd
300 int fx_resist_spell (Scriptable* Owner, Actor* target, Effect* fx);//ce
301 int fx_resist_spell_dec (Scriptable* Owner, Actor* target, Effect* fx);//??
302 int fx_bounce_spell (Scriptable* Owner, Actor* target, Effect* fx);//cf
303 int fx_bounce_spell_dec (Scriptable* Owner, Actor* target, Effect* fx);//??
304 int fx_minimum_hp_modifier (Scriptable* Owner, Actor* target, Effect* fx);//d0
305 int fx_power_word_kill (Scriptable* Owner, Actor* target, Effect* fx);//d1
306 int fx_power_word_stun (Scriptable* Owner, Actor* target, Effect* fx);//d2
307 int fx_imprisonment (Scriptable* Owner, Actor* target, Effect* fx);//d3
308 int fx_freedom (Scriptable* Owner, Actor* target, Effect* fx);//d4
309 int fx_maze (Scriptable* Owner, Actor* target, Effect* fx);//d5
310 int fx_select_spell (Scriptable* Owner, Actor* target, Effect* fx);//d6
311 int fx_play_visual_effect (Scriptable* Owner, Actor* target, Effect* fx); //d7
312 int fx_leveldrain_modifier (Scriptable* Owner, Actor* target, Effect* fx);//d8
313 int fx_power_word_sleep (Scriptable* Owner, Actor* target, Effect* fx);//d9
314 int fx_stoneskin_modifier (Scriptable* Owner, Actor* target, Effect* fx);//da
315 //db ac vs creature type (general effect)
316 int fx_dispel_school (Scriptable* Owner, Actor* target, Effect* fx);//dc
317 int fx_dispel_secondary_type (Scriptable* Owner, Actor* target, Effect* fx);//dd
318 int fx_teleport_field (Scriptable* Owner, Actor* target, Effect* fx);//de
319 int fx_protection_school_dec (Scriptable* Owner, Actor* target, Effect* fx);//df
320 int fx_cure_leveldrain (Scriptable* Owner, Actor* target, Effect* fx);//e0
321 int fx_reveal_magic (Scriptable* Owner, Actor* target, Effect* fx);//e1
322 int fx_protection_secondary_type_dec (Scriptable* Owner, Actor* target, Effect* fx);//e2
323 int fx_bounce_school_dec (Scriptable* Owner, Actor* target, Effect* fx);//e3
324 int fx_bounce_secondary_type_dec (Scriptable* Owner, Actor* target, Effect* fx);//e4
325 int fx_dispel_school_one (Scriptable* Owner, Actor* target, Effect* fx);//e5
326 int fx_dispel_secondary_type_one (Scriptable* Owner, Actor* target, Effect* fx);//e6
327 int fx_timestop (Scriptable* Owner, Actor* target, Effect* fx);//e7
328 int fx_cast_spell_on_condition (Scriptable* Owner, Actor* target, Effect* fx);//e8
329 int fx_proficiency (Scriptable* Owner, Actor* target, Effect* fx);//e9
330 int fx_create_contingency (Scriptable* Owner, Actor* target, Effect* fx);//ea
331 int fx_wing_buffet (Scriptable* Owner, Actor* target, Effect* fx);//eb
332 int fx_puppet_master (Scriptable* Owner, Actor* target, Effect* fx);//ec
333 int fx_puppet_marker (Scriptable* Owner, Actor* target, Effect* fx);//ed
334 int fx_disintegrate (Scriptable* Owner, Actor* target, Effect* fx);//ee
335 int fx_farsee (Scriptable* Owner, Actor* target, Effect* fx);//ef
336 int fx_remove_portrait_icon (Scriptable* Owner, Actor* target, Effect* fx);//f0
337 //f1 control creature (see charm)
338 int fx_cure_confused_state (Scriptable* Owner, Actor* target, Effect* fx);//f2
339 int fx_drain_items (Scriptable* Owner, Actor* target, Effect* fx);//f3
340 int fx_drain_spells (Scriptable* Owner, Actor* target, Effect* fx);//f4
341 int fx_checkforberserk_modifier (Scriptable* Owner, Actor* target, Effect* fx);//f5
342 int fx_berserkstage1_modifier (Scriptable* Owner, Actor* target, Effect* fx);//f6
343 int fx_berserkstage2_modifier (Scriptable* Owner, Actor* target, Effect* fx);//f7
344 //int fx_melee_effect (Scriptable* Owner, Actor* target, Effect* fx);//f8
345 //int fx_ranged_effect (Scriptable* Owner, Actor* target, Effect* fx);//f9
346 int fx_damageluck_modifier (Scriptable* Owner, Actor* target, Effect* fx);//fa
347 int fx_change_bardsong (Scriptable* Owner, Actor* target, Effect* fx);//fb
348 int fx_set_area_effect (Scriptable* Owner, Actor* target, Effect* fx);//fc (set trap)
349 int fx_set_map_note (Scriptable* Owner, Actor* target, Effect* fx);//fd
350 int fx_remove_map_note (Scriptable* Owner, Actor* target, Effect* fx);//fe
351 int fx_create_item_days (Scriptable* Owner, Actor* target, Effect* fx);//ff
352 int fx_store_spell_sequencer (Scriptable* Owner, Actor* target, Effect* fx);//0x100
353 int fx_create_spell_sequencer (Scriptable* Owner, Actor* target, Effect* fx);//101
354 int fx_activate_spell_sequencer (Scriptable* Owner, Actor* target, Effect* fx);//102
355 int fx_spelltrap (Scriptable* Owner, Actor* target, Effect* fx);//103
356 int fx_crash (Scriptable* Owner, Actor* target, Effect* fx);//104, disabled
357 int fx_restore_spell_level (Scriptable* Owner, Actor* target, Effect* fx);//105
358 int fx_visual_range_modifier (Scriptable* Owner, Actor* target, Effect* fx);//106
359 int fx_backstab_modifier (Scriptable* Owner, Actor* target, Effect* fx);//107
360 int fx_drop_weapon (Scriptable* Owner, Actor* target, Effect* fx);//108
361 int fx_modify_global_variable (Scriptable* Owner, Actor* target, Effect* fx);//109
362 int fx_remove_immunity (Scriptable* Owner, Actor* target, Effect* fx);//10a
363 int fx_protection_from_string (Scriptable* Owner, Actor* target, Effect* fx);//10b
364 int fx_explore_modifier (Scriptable* Owner, Actor* target, Effect* fx);//10c
365 int fx_screenshake (Scriptable* Owner, Actor* target, Effect* fx);//10d
366 int fx_unpause_caster (Scriptable* Owner, Actor* target, Effect* fx);//10e
367 int fx_avatar_removal (Scriptable* Owner, Actor* target, Effect* fx);//10f
368 int fx_apply_effect_repeat (Scriptable* Owner, Actor* target, Effect* fx);//110
369 int fx_remove_projectile (Scriptable* Owner, Actor* target, Effect* fx);//111
370 int fx_teleport_to_target (Scriptable* Owner, Actor* target, Effect* fx);//112
371 int fx_hide_in_shadows_modifier (Scriptable* Owner, Actor* target, Effect* fx);//113
372 int fx_detect_illusion_modifier (Scriptable* Owner, Actor* target, Effect* fx);//114
373 int fx_set_traps_modifier (Scriptable* Owner, Actor* target, Effect* fx);//115
374 int fx_to_hit_bonus_modifier (Scriptable* Owner, Actor* target, Effect* fx);//116
375 int fx_renable_button (Scriptable* Owner, Actor* target, Effect* fx);//117
376 int fx_force_surge_modifier (Scriptable* Owner, Actor* target, Effect* fx);//118
377 int fx_wild_surge_modifier (Scriptable* Owner, Actor* target, Effect* fx);//119
378 int fx_scripting_state (Scriptable* Owner, Actor* target, Effect* fx);//11a
379 int fx_apply_effect_curse (Scriptable* Owner, Actor* target, Effect* fx);//11b
380 int fx_melee_to_hit_modifier (Scriptable* Owner, Actor* target, Effect* fx);//11c
381 int fx_melee_damage_modifier (Scriptable* Owner, Actor* target, Effect* fx);//11d
382 int fx_missile_damage_modifier (Scriptable* Owner, Actor* target, Effect* fx);//11e
383 int fx_no_circle_state (Scriptable* Owner, Actor* target, Effect* fx);//11f
384 int fx_fist_to_hit_modifier (Scriptable* Owner, Actor* target, Effect* fx);//120
385 int fx_fist_damage_modifier (Scriptable* Owner, Actor* target, Effect* fx);//121
386 int fx_title_modifier (Scriptable* Owner, Actor* target, Effect* fx);//122
387 int fx_disable_overlay_modifier (Scriptable* Owner, Actor* target, Effect* fx);//123
388 int fx_no_backstab_modifier (Scriptable* Owner, Actor* target, Effect* fx);//124
389 int fx_offscreenai_modifier (Scriptable* Owner, Actor* target, Effect* fx);//125
390 int fx_existance_delay_modifier (Scriptable* Owner, Actor* target, Effect* fx);//126
391 int fx_disable_chunk_modifier (Scriptable* Owner, Actor* target, Effect* fx);//127
392 int fx_protection_from_animation (Scriptable* Owner, Actor* target, Effect* fx);//128
393 int fx_protection_from_turn (Scriptable* Owner, Actor* target, Effect* fx);//129
394 int fx_cutscene2 (Scriptable* Owner, Actor* target, Effect* fx);//12a
395 int fx_chaos_shield_modifier (Scriptable* Owner, Actor* target, Effect* fx);//12b
396 int fx_npc_bump (Scriptable* Owner, Actor* target, Effect* fx);//12c
397 int fx_critical_hit_modifier (Scriptable* Owner, Actor* target, Effect* fx);//12d
398 int fx_can_use_any_item_modifier (Scriptable* Owner, Actor* target, Effect* fx);//12e
399 int fx_always_backstab_modifier (Scriptable* Owner, Actor* target, Effect* fx);//12f
400 int fx_mass_raise_dead (Scriptable* Owner, Actor* target, Effect* fx);//130
401 int fx_left_to_hit_modifier (Scriptable* Owner, Actor* target, Effect* fx);//131
402 int fx_right_to_hit_modifier (Scriptable* Owner, Actor* target, Effect* fx);//132
403 int fx_reveal_tracks (Scriptable* Owner, Actor* target, Effect* fx);//133
404 int fx_protection_from_tracking (Scriptable* Owner, Actor* target, Effect* fx);//134
405 int fx_modify_local_variable (Scriptable* Owner, Actor* target, Effect* fx);//135
406 int fx_timeless_modifier (Scriptable* Owner, Actor* target, Effect* fx);//136
407 int fx_generate_wish (Scriptable* Owner, Actor* target, Effect* fx);//137
408 //138 see fx_crash
409 //139 HLA generic effect
410 int fx_golem_stoneskin_modifier (Scriptable* Owner, Actor* target, Effect* fx);//13a
411 int fx_avatar_removal_modifier (Scriptable* Owner, Actor* target, Effect* fx);//13b
412 int fx_magical_rest (Scriptable* Owner, Actor* target, Effect* fx);//13c
413 //int fx_improved_haste_state (Scriptable* Owner, Actor* target, Effect* fx);//13d same as haste
415 int fx_unknown (Scriptable* Owner, Actor* target, Effect* fx);//???
417 // FIXME: Make this an ordered list, so we could use bsearch!
418 static EffectRef effectnames[] = {
419 { "*Crash*", fx_crash, -1 },
420 { "AcidResistanceModifier", fx_acid_resistance_modifier, -1 },
421 { "ACVsCreatureType", fx_generic_effect, -1 }, //0xdb
422 { "ACVsDamageTypeModifier", fx_ac_vs_damage_type_modifier, -1 },
423 { "ACVsDamageTypeModifier2", fx_ac_vs_damage_type_modifier, -1 }, // used in IWD
424 { "AidNonCumulative", fx_set_aid_state, -1 },
425 { "AIIdentifierModifier", fx_ids_modifier, -1 },
426 { "AlchemyModifier", fx_alchemy_modifier, -1 },
427 { "Alignment:Change", fx_alignment_change, -1 },
428 { "Alignment:Invert", fx_alignment_invert, -1 },
429 { "AlwaysBackstab", fx_always_backstab_modifier, -1 },
430 { "AnimationIDModifier", fx_animation_id_modifier, -1 },
431 { "AnimationStateChange", fx_animation_stance, -1 },
432 { "ApplyEffect", fx_apply_effect, -1 },
433 { "ApplyEffectCurse", fx_apply_effect_curse, -1 },
434 { "ApplyEffectItem", fx_apply_effect_item, -1 },
435 { "ApplyEffectItemType", fx_apply_effect_item_type, -1 },
436 { "ApplyEffectRepeat", fx_apply_effect_repeat, -1 },
437 { "CutScene2", fx_cutscene2, -1 },
438 { "AttackSpeedModifier", fx_attackspeed_modifier, -1 },
439 { "AttacksPerRoundModifier", fx_attacks_per_round_modifier, -1 },
440 { "AuraCleansingModifier", fx_auracleansing_modifier, -1 },
441 { "AvatarRemoval", fx_avatar_removal, -1 }, //unknown
442 { "AvatarRemovalModifier", fx_avatar_removal_modifier, -1 },
443 { "BackstabModifier", fx_backstab_modifier, -1 },
444 { "BerserkStage1Modifier", fx_berserkstage1_modifier, -1},
445 { "BerserkStage2Modifier", fx_berserkstage2_modifier, -1},
446 { "BlessNonCumulative", fx_set_bless_state, -1 },
447 { "Bounce:School", fx_bounce_school, -1 },
448 { "Bounce:SchoolDec", fx_bounce_school_dec, -1 },
449 { "Bounce:SecondaryType", fx_bounce_secondary_type, -1 },
450 { "Bounce:SecondaryTypeDec", fx_bounce_secondary_type_dec, -1 },
451 { "Bounce:Spell", fx_bounce_spell, -1 },
452 { "Bounce:SpellDec", fx_bounce_spell_dec, -1 },
453 { "Bounce:SpellLevel", fx_bounce_spelllevel, -1},
454 { "Bounce:SpellLevelDec", fx_bounce_spelllevel_dec, -1},
455 { "Bounce:Opcode", fx_bounce_opcode, -1 },
456 { "Bounce:Projectile", fx_bounce_projectile, -1 },
457 { "CantUseItem", fx_generic_effect, -1 },
458 { "CantUseItemType", fx_generic_effect, -1 },
459 { "CanUseAnyItem", fx_can_use_any_item_modifier, -1 },
460 { "CastFromList", fx_select_spell, -1 },
461 { "CastingGlow", fx_casting_glow, -1 },
462 { "CastingGlow2", fx_casting_glow, -1 }, //used in iwd
463 { "CastingLevelModifier", fx_castinglevel_modifier, -1 },
464 { "CastingSpeedModifier", fx_castingspeed_modifier, -1 },
465 { "CastSpellOnCondition", fx_cast_spell_on_condition, -1 },
466 { "ChangeBardSong", fx_change_bardsong, -1 },
467 { "ChangeName", fx_change_name, -1 },
468 { "ChantBadNonCumulative", fx_set_chantbad_state, -1 },
469 { "ChantNonCumulative", fx_set_chant_state, -1 },
470 { "ChaosShieldModifier", fx_chaos_shield_modifier, -1 },
471 { "CharismaModifier", fx_charisma_modifier, -1 },
472 { "CheckForBerserkModifier", fx_checkforberserk_modifier, -1},
473 { "ColdResistanceModifier", fx_cold_resistance_modifier, -1 },
474 { "Color:BriefRGB", fx_brief_rgb, -1},
475 { "Color:GlowRGB", fx_glow_rgb, -1},
476 { "Color:DarkenRGB", fx_darken_rgb, -1},
477 { "Color:SetPalette", fx_set_color_gradient, -1 },
478 { "Color:SetRGB", fx_set_color_rgb, -1 },
479 { "Color:SetRGBGlobal", fx_set_color_rgb_global, -1 }, //08
480 { "Color:PulseRGB", fx_set_color_pulse_rgb, -1 }, //9
481 { "Color:PulseRGBGlobal", fx_set_color_pulse_rgb_global, -1 }, //9
482 { "ConstitutionModifier", fx_constitution_modifier, -1 },
483 { "ControlCreature", fx_set_charmed_state, -1 }, //0xf1 same as charm
484 { "CreateContingency", fx_create_contingency, -1 },
485 { "CriticalHitModifier", fx_critical_hit_modifier, -1 },
486 { "CrushingResistanceModifier", fx_crushing_resistance_modifier, -1 },
487 { "Cure:Berserk", fx_cure_berserk_state, -1 },
488 { "Cure:Blind", fx_cure_blind_state, -1 },
489 { "Cure:CasterHold", fx_unpause_caster, -1 },
490 { "Cure:Confusion", fx_cure_confused_state, -1 },
491 { "Cure:Deafness", fx_cure_deaf_state, -1 },
492 { "Cure:Death", fx_cure_dead_state, -1 },
493 { "Cure:Defrost", fx_cure_frozen_state, -1 },
494 { "Cure:Disease", fx_cure_diseased_state, -1 },
495 { "Cure:Feeblemind", fx_cure_feebleminded_state, -1 },
496 { "Cure:Hold", fx_cure_hold_state, -1 },
497 { "Cure:Imprisonment", fx_freedom, -1 },
498 { "Cure:Infravision", fx_cure_infravision_state, -1 },
499 { "Cure:Intoxication", fx_cure_intoxication, -1 }, //0xa4 (iwd2 has this working)
500 { "Cure:Invisible", fx_cure_invisible_state, -1 }, //0x2f
501 { "Cure:Invisible2", fx_cure_invisible_state, -1 }, //0x74
502 //{ "Cure:ImprovedInvisible", fx_cure_improved_invisible_state, -1 },
503 { "Cure:LevelDrain", fx_cure_leveldrain, -1}, //restoration
504 { "Cure:Nondetection", fx_cure_nondetection_state, -1 },
505 { "Cure:Panic", fx_cure_panic_state, -1 },
506 { "Cure:Petrification", fx_cure_petrified_state, -1 },
507 { "Cure:Poison", fx_cure_poisoned_state, -1 },
508 { "Cure:Sanctuary", fx_cure_sanctuary_state, -1 },
509 { "Cure:Silence", fx_cure_silenced_state, -1 },
510 { "Cure:Sleep", fx_cure_sleep_state, -1 },
511 { "Cure:Stun", fx_cure_stun_state, -1 },
512 { "CurrentHPModifier", fx_current_hp_modifier, -1 },
513 { "Damage", fx_damage, -1 },
514 { "DamageAnimation", fx_damage_animation, -1 },
515 { "DamageBonusModifier", fx_damage_bonus_modifier, -1 },
516 { "DamageLuckModifier", fx_damageluck_modifier, -1 },
517 { "DamageVsCreature", fx_generic_effect, -1 },
518 { "Death", fx_death, -1 },
519 { "Death2", fx_death, -1 }, //(iwd2 effect)
520 { "Death3", fx_death, -1 }, //(iwd2 effect too, Banish)
521 { "DetectAlignment", fx_detect_alignment, -1 },
522 { "DetectIllusionsModifier", fx_detect_illusion_modifier, -1 },
523 { "DexterityModifier", fx_dexterity_modifier, -1 },
524 { "DimensionDoor", fx_dimension_door, -1 },
525 { "DisableButton", fx_disable_button, -1 }, //sets disable button flag
526 { "DisableChunk", fx_disable_chunk_modifier, -1 },
527 { "DisableOverlay", fx_disable_overlay_modifier, -1 },
528 { "DisableCasting", fx_disable_spellcasting, -1 },
529 { "Disintegrate", fx_disintegrate, -1 },
530 { "DispelEffects", fx_dispel_effects, -1 },
531 { "DispelSchool", fx_dispel_school, -1 },
532 { "DispelSchoolOne", fx_dispel_school_one, -1 },
533 { "DispelSecondaryType", fx_dispel_secondary_type, -1 },
534 { "DispelSecondaryTypeOne", fx_dispel_secondary_type_one, -1 },
535 { "DisplayString", fx_display_string, -1 },
536 { "Dither", fx_dither, -1 },
537 { "DontJumpModifier", fx_dontjump_modifier, -1 },
538 { "DrainItems", fx_drain_items, -1 },
539 { "DrainSpells", fx_drain_spells, -1 },
540 { "DropWeapon", fx_drop_weapon, -1 },
541 { "ElectricityResistanceModifier", fx_electricity_resistance_modifier, -1 },
542 { "ExistanceDelayModifier", fx_existance_delay_modifier , -1 }, //unknown
543 { "ExperienceModifier", fx_experience_modifier, -1 },
544 { "ExploreModifier", fx_explore_modifier, -1 },
545 { "FamiliarBond", fx_familiar_constitution_loss, -1 },
546 { "FamiliarMarker", fx_familiar_marker, -1},
547 { "Farsee", fx_farsee, -1},
548 { "FatigueModifier", fx_fatigue_modifier, -1 },
549 { "FindFamiliar", fx_find_familiar, -1 },
550 { "FindTraps", fx_find_traps, -1 },
551 { "FindTrapsModifier", fx_find_traps_modifier, -1 },
552 { "FireResistanceModifier", fx_fire_resistance_modifier, -1 },
553 { "FistDamageModifier", fx_fist_damage_modifier, -1 },
554 { "FistHitModifier", fx_fist_to_hit_modifier, -1 },
555 { "ForceSurgeModifier", fx_force_surge_modifier, -1 },
556 { "ForceVisible", fx_force_visible, -1 }, //not invisible but improved invisible
557 { "FreeAction", fx_cure_slow_state, -1},
558 { "GenerateWish", fx_generate_wish, -1},
559 { "GoldModifier", fx_gold_modifier, -1 },
560 { "HideInShadowsModifier", fx_hide_in_shadows_modifier, -1},
561 { "HLA", fx_generic_effect, -1},
562 { "HolyNonCumulative", fx_set_holy_state, -1 },
563 { "Icon:Disable", fx_disable_portrait_icon, -1 },
564 { "Icon:Display", fx_display_portrait_icon, -1 },
565 { "Icon:Remove", fx_remove_portrait_icon, -1 },
566 { "Identify", fx_identify, -1 },
567 { "IgnoreDialogPause", fx_ignore_dialogpause_modifier, -1 },
568 { "IntelligenceModifier", fx_intelligence_modifier, -1 },
569 { "IntoxicationModifier", fx_intoxication_modifier, -1 },
570 { "InvisibleDetection", fx_see_invisible_modifier, -1 },
571 { "Item:CreateDays", fx_create_item_days, -1 },
572 { "Item:CreateInSlot", fx_create_item_in_slot, -1 },
573 { "Item:CreateInventory", fx_create_inventory_item, -1 },
574 { "Item:CreateMagic", fx_create_magic_item, -1 },
575 { "Item:Equip", fx_equip_item, -1 }, //71
576 { "Item:Remove", fx_remove_item, -1 }, //70
577 { "Item:RemoveInventory", fx_remove_inventory_item, -1 },
578 { "KillCreatureType", fx_kill_creature_type, -1 },
579 { "LevelModifier", fx_level_modifier, -1 },
580 { "LevelDrainModifier", fx_leveldrain_modifier, -1 },
581 { "LoreModifier", fx_lore_modifier, -1 },
582 { "LuckModifier", fx_luck_modifier, -1 },
583 { "LuckCumulative", fx_luck_cumulative, -1 },
584 { "LuckNonCumulative", fx_luck_non_cumulative, -1 },
585 { "MagicalColdResistanceModifier", fx_magical_cold_resistance_modifier, -1 },
586 { "MagicalFireResistanceModifier", fx_magical_fire_resistance_modifier, -1 },
587 { "MagicalRest", fx_magical_rest, -1 },
588 { "MagicDamageResistanceModifier", fx_magic_damage_resistance_modifier, -1 },
589 { "MagicResistanceModifier", fx_magic_resistance_modifier, -1 },
590 { "MassRaiseDead", fx_mass_raise_dead, -1 },
591 { "MaximumHPModifier", fx_maximum_hp_modifier, -1 },
592 { "Maze", fx_maze, -1},
593 { "MeleeDamageModifier", fx_melee_damage_modifier, -1 },
594 { "MeleeHitModifier", fx_melee_to_hit_modifier, -1 },
595 { "MinimumHPModifier", fx_minimum_hp_modifier, -1 },
596 { "MiscastMagicModifier", fx_miscast_magic_modifier, -1 },
597 { "MissileDamageModifier", fx_missile_damage_modifier, -1 },
598 { "MissileHitModifier", fx_missile_to_hit_modifier, -1 },
599 { "MissilesResistanceModifier", fx_missiles_resistance_modifier, -1 },
600 { "MirrorImage", fx_mirror_image, -1 },
601 { "MirrorImageModifier", fx_mirror_image_modifier, -1 },
602 { "ModifyGlobalVariable", fx_modify_global_variable, -1 },
603 { "ModifyLocalVariable", fx_modify_local_variable, -1 },
604 { "MonsterSummoning", fx_monster_summoning, -1 },
605 { "MoraleBreakModifier", fx_morale_break_modifier, -1 },
606 { "MoraleModifier", fx_morale_modifier, -1 },
607 { "MovementRateModifier", fx_movement_modifier, -1 }, //fast (7e)
608 { "MovementRateModifier2", fx_movement_modifier, -1 },//slow (b0)
609 { "MovementRateModifier3", fx_movement_modifier, -1 },//forced (IWD - 10a)
610 { "MovementRateModifier4", fx_movement_modifier, -1 },//slow (IWD2 - 1b9)
611 { "MoveToArea", fx_move_to_area, -1 }, //0xba
612 { "NoCircleState", fx_no_circle_state, -1 },
613 { "NPCBump", fx_npc_bump, -1 },
614 { "OffscreenAIModifier", fx_offscreenai_modifier, -1 },
615 { "OffhandHitModifier", fx_left_to_hit_modifier, -1 },
616 { "OpenLocksModifier", fx_open_locks_modifier, -1 },
617 { "Overlay:Entangle", fx_set_entangle_state, -1 },
618 { "Overlay:Grease", fx_set_grease_state, -1 },
619 { "Overlay:MinorGlobe", fx_set_minorglobe_state, -1 },
620 { "Overlay:Sanctuary", fx_set_sanctuary_state, -1 },
621 { "Overlay:ShieldGlobe", fx_set_shieldglobe_state, -1 },
622 { "Overlay:Web", fx_set_web_state, -1 },
623 { "PauseTarget", fx_pause_target, -1 }, //also known as casterhold
624 { "PickPocketsModifier", fx_pick_pockets_modifier, -1 },
625 { "PiercingResistanceModifier", fx_piercing_resistance_modifier, -1 },
626 { "PlayMovie", fx_play_movie, -1 },
627 { "PlaySound", fx_playsound, -1 },
628 { "PlayVisualEffect", fx_play_visual_effect, -1 },
629 { "PoisonResistanceModifier", fx_poison_resistance_modifier, -1 },
630 { "Polymorph", fx_polymorph, -1},
631 { "PortraitChange", fx_portrait_change, -1 },
632 { "PowerWordKill", fx_power_word_kill, -1 },
633 { "PowerWordSleep", fx_power_word_sleep, -1 },
634 { "PowerWordStun", fx_power_word_stun, -1 },
635 { "PriestSpellSlotsModifier", fx_bonus_priest_spells, -1 },
636 { "Proficiency", fx_proficiency, -1 },
637 // { "Protection:Animation", fx_protection_from_animation, -1 },
638 { "Protection:Animation", fx_generic_effect, -1 },
639 { "Protection:Backstab", fx_no_backstab_modifier, -1 },
640 { "Protection:Creature", fx_generic_effect, -1 },
641 { "Protection:Opcode", fx_protection_opcode, -1 },
642 { "Protection:Opcode2", fx_protection_opcode, -1 },
643 { "Protection:Projectile",fx_protection_from_projectile, -1},
644 { "Protection:School",fx_generic_effect,-1},//overlay?
645 { "Protection:SchoolDec",fx_protection_school_dec,-1},//overlay?
646 { "Protection:SecondaryType",fx_protection_secondary_type,-1},//overlay?
647 { "Protection:SecondaryTypeDec",fx_protection_secondary_type_dec,-1},//overlay?
648 { "Protection:Spell",fx_resist_spell,-1},//overlay?
649 { "Protection:SpellDec",fx_resist_spell_dec,-1},//overlay?
650 { "Protection:SpellLevel",fx_protection_spelllevel,-1},//overlay?
651 { "Protection:SpellLevelDec",fx_protection_spelllevel_dec,-1},//overlay?
652 { "Protection:String", fx_generic_effect, -1 },
653 { "Protection:Tracking", fx_protection_from_tracking, -1 },
654 { "Protection:Turn", fx_protection_from_turn, -1},
655 { "Protection:Weapons", fx_immune_to_weapon, -1},
656 { "PuppetMarker", fx_puppet_marker, -1},
657 { "ProjectImage", fx_puppet_master, -1},
658 { "Reveal:Area", fx_reveal_area, -1 },
659 { "Reveal:Creatures", fx_reveal_creatures, -1 },
660 { "Reveal:Magic", fx_reveal_magic, -1 },
661 { "Reveal:Tracks", fx_reveal_tracks, -1 },
662 { "RemoveCurse", fx_remove_curse, -1 },
663 { "RemoveImmunity", fx_remove_immunity, -1 },
664 { "RemoveMapNote", fx_remove_map_note, -1 },
665 { "RemoveProjectile", fx_remove_projectile, -1 }, //removes effects from actor and area
666 { "RenableButton", fx_renable_button, -1 }, //removes disable button flag
667 { "RemoveCreature", fx_remove_creature, -1 },
668 { "ReplaceCreature", fx_replace_creature, -1 },
669 { "ReputationModifier", fx_reputation_modifier, -1 },
670 { "RestoreSpells", fx_restore_spell_level, -1 },
671 { "RightHitModifier", fx_right_to_hit_modifier, -1 },
672 { "SaveVsBreathModifier", fx_save_vs_breath_modifier, -1 },
673 { "SaveVsDeathModifier", fx_save_vs_death_modifier, -1 },
674 { "SaveVsPolyModifier", fx_save_vs_poly_modifier, -1 },
675 { "SaveVsSpellsModifier", fx_save_vs_spell_modifier, -1 },
676 { "SaveVsWandsModifier", fx_save_vs_wands_modifier, -1 },
677 { "ScreenShake", fx_screenshake, -1 },
678 { "ScriptingState", fx_scripting_state, -1 },
679 { "Sequencer:Activate", fx_activate_spell_sequencer, -1 },
680 { "Sequencer:Create", fx_create_spell_sequencer, -1 },
681 { "Sequencer:Store", fx_store_spell_sequencer, -1 },
682 { "SetAIScript", fx_set_ai_script, -1 },
683 { "SetMapNote", fx_set_map_note, -1 },
684 { "SetMeleeEffect", fx_generic_effect, -1 },
685 { "SetRangedEffect", fx_generic_effect, -1 },
686 { "SetTrap", fx_set_area_effect, -1 },
687 { "SetTrapsModifier", fx_set_traps_modifier, -1 },
688 { "SexModifier", fx_sex_modifier, -1 },
689 { "SlashingResistanceModifier", fx_slashing_resistance_modifier, -1 },
690 { "Sparkle", fx_sparkle, -1 },
691 { "SpellDurationModifier", fx_spell_duration_modifier, -1 },
692 { "Spell:Add", fx_add_innate, -1 },
693 { "Spell:Cast", fx_cast_spell, -1 },
694 { "Spell:CastPoint", fx_cast_spell_point, -1 },
695 { "Spell:Learn", fx_learn_spell, -1 },
696 { "Spell:Remove", fx_remove_spell, -1 },
697 { "Spelltrap",fx_spelltrap , -1 }, //overlay: spmagglo
698 { "State:Berserk", fx_set_berserk_state, -1 },
699 { "State:Blind", fx_set_blind_state, -1 },
700 { "State:Blur", fx_set_blur_state, -1 },
701 { "State:Charmed", fx_set_charmed_state, -1 }, //0x05
702 { "State:Confused", fx_set_confused_state, -1 },
703 { "State:Deafness", fx_set_deaf_state, -1 },
704 { "State:DeafnessIWD2", fx_set_deaf_state_iwd2, -1 }, //this is a modified version
705 { "State:Diseased", fx_set_diseased_state, -1 },
706 { "State:Feeblemind", fx_set_feebleminded_state, -1 },
707 { "State:Hasted", fx_set_hasted_state, -1 },
708 { "State:Haste2", fx_set_hasted_state, -1 },
709 { "State:Hold", fx_hold_creature, -1 }, //175 (doesn't work in original iwd2)
710 { "State:Hold2", fx_hold_creature, -1 },//185 (doesn't work in original iwd2)
711 { "State:Hold3", fx_hold_creature, -1 },//109 iwd2
712 { "State:HoldNoIcon", fx_hold_creature_no_icon, -1 }, //109
713 { "State:HoldNoIcon2", fx_hold_creature_no_icon, -1 }, //0xfb (iwd/iwd2)
714 { "State:HoldNoIcon3", fx_hold_creature_no_icon, -1 }, //0x1a8 (iwd2)
715 { "State:Imprisonment", fx_imprisonment, -1 },
716 { "State:Infravision", fx_set_infravision_state, -1 },
717 { "State:Invisible", fx_set_invisible_state, -1 }, //both invis or improved invis
718 { "State:Nondetection", fx_set_nondetection_state, -1 },
719 { "State:Panic", fx_set_panic_state, -1 },
720 { "State:Petrification", fx_set_petrified_state, -1 },
721 { "State:Poisoned", fx_set_poisoned_state, -1 },
722 { "State:Regenerating", fx_set_regenerating_state, -1 },
723 { "State:Silenced", fx_set_silenced_state, -1 },
724 { "State:Helpless", fx_set_unconscious_state, -1 },
725 { "State:Sleep", fx_set_unconscious_state, -1},
726 { "State:Slowed", fx_set_slowed_state, -1 },
727 { "State:Stun", fx_set_stun_state, -1 },
728 { "StealthModifier", fx_stealth_modifier, -1 },
729 { "StoneSkinModifier", fx_stoneskin_modifier, -1 },
730 { "StoneSkin2Modifier", fx_golem_stoneskin_modifier, -1 },
731 { "StrengthModifier", fx_strength_modifier, -1 },
732 { "StrengthBonusModifier", fx_strength_bonus_modifier, -1 },
733 { "SummonCreature", fx_summon_creature, -1 },
734 { "RandomTeleport", fx_teleport_field, -1 },
735 { "TeleportToTarget", fx_teleport_to_target, -1 },
736 { "TimelessState", fx_timeless_modifier, -1 },
737 { "Timestop", fx_timestop, -1},
738 { "TitleModifier", fx_title_modifier, -1 },
739 { "ToHitModifier", fx_to_hit_modifier, -1 },
740 { "ToHitBonusModifier", fx_to_hit_bonus_modifier, -1 },
741 { "ToHitVsCreature", fx_generic_effect, -1 },
742 { "TrackingModifier", fx_tracking_modifier, -1 },
743 { "TransparencyModifier", fx_transparency_modifier, -1 },
744 { "Unknown", fx_unknown, -1},
745 { "Unlock", fx_knock, -1 }, //open doors/containers
746 { "UnsummonCreature", fx_unsummon_creature, -1 },
747 { "Variable:StoreLocalVariable", fx_local_variable, -1 },
748 { "VisualAnimationEffect", fx_visual_animation_effect, -1 }, //unknown
749 { "VisualRangeModifier", fx_visual_range_modifier, -1 },
750 { "VisualSpellHit", fx_visual_spell_hit, -1 },
751 { "WildSurgeModifier", fx_wild_surge_modifier, -1 },
752 { "WingBuffet", fx_wing_buffet, -1 },
753 { "WisdomModifier", fx_wisdom_modifier, -1 },
754 { "WizardSpellSlotsModifier", fx_bonus_wizard_spells, -1 },
755 { NULL, NULL, 0 },
758 static void Cleanup()
760 core->FreeResRefTable(casting_glows, cgcount);
761 core->FreeResRefTable(spell_hits, shcount);
762 if(spell_abilities) free(spell_abilities);
763 spell_abilities=NULL;
764 if(polymorph_stats) free(polymorph_stats);
765 polymorph_stats=NULL;
768 void RegisterCoreOpcodes()
770 core->RegisterOpcodes( sizeof( effectnames ) / sizeof( EffectRef ) - 1, effectnames );
771 enhanced_effects=!!core->HasFeature(GF_ENHANCED_EFFECTS);
772 pstflags=!!core->HasFeature(GF_PST_STATE_FLAGS);
773 default_spell_hit.SequenceFlags|=IE_VVC_BAM;
777 static inline void SetGradient(Actor *target, ieDword gradient)
779 gradient |= (gradient <<16);
780 gradient |= (gradient <<8);
781 for(int i=0;i<7;i++) {
782 STAT_SET(IE_COLORS+i, gradient);
786 static inline void HandleBonus(Actor *target, int stat, int mod, int mode)
788 if (mode==FX_DURATION_INSTANT_PERMANENT) {
789 if (target->IsReverseToHit()) {
790 BASE_SUB( stat, mod );
791 } else {
792 BASE_ADD( stat, mod );
794 return;
796 if (target->IsReverseToHit()) {
797 STAT_SUB( stat, mod );
798 } else {
799 STAT_ADD( stat, mod );
803 //whoseeswho:
804 #define ENEMY_SEES_ORIGIN 1
805 #define ORIGIN_SEES_ENEMY 2
807 inline Actor *GetNearestEnemyOf(Map *map, Actor *origin, int whoseeswho)
809 //determining the allegiance of the origin
810 int type = GetGroup(origin);
812 //neutral has no enemies
813 if (type==2) {
814 return NULL;
817 Targets *tgts = new Targets();
819 int i = map->GetActorCount(true);
820 Actor *ac;
821 while (i--) {
822 ac=map->GetActor(i,true);
823 int distance = Distance(ac, origin);
824 if (whoseeswho&ENEMY_SEES_ORIGIN) {
825 if (!CanSee(ac, origin, true, GA_NO_DEAD)) {
826 continue;
829 if (whoseeswho&ORIGIN_SEES_ENEMY) {
830 if (!CanSee(ac, origin, true, GA_NO_DEAD)) {
831 continue;
835 if (type) { //origin is PC
836 if (ac->GetStat(IE_EA) >= EA_EVILCUTOFF) {
837 tgts->AddTarget(ac, distance, GA_NO_DEAD);
840 else {
841 if (ac->GetStat(IE_EA) <= EA_GOODCUTOFF) {
842 tgts->AddTarget(ac, distance, GA_NO_DEAD);
846 ac = (Actor *) tgts->GetTarget(0, ST_ACTOR);
847 delete tgts;
848 return ac;
851 inline Scriptable *GetCaster(Scriptable *Owner, Effect *fx) {
852 if (fx->FirstApply) {
853 fx->CasterID = Owner ? Owner->GetGlobalID() : 0;
854 return Owner;
855 } else {
856 return core->GetGame()->GetActorByGlobalID(fx->CasterID);
858 return NULL;
861 //resurrect code used in many places
862 void Resurrect(Scriptable *Owner, Actor *target, Effect *fx, Point &p)
864 Scriptable *caster = GetCaster(Owner, fx);
865 if (!caster) {
866 caster = Owner; // IE stores the enemyally in the effect instead
868 Map *area = caster->GetCurrentArea();
870 if (area && target->GetCurrentArea()!=area) {
871 MoveBetweenAreasCore(target, area->GetScriptName(), p, fx->Parameter2, true);
873 target->Resurrect();
877 // handles the percentage damage spread over time by converting it to absolute damage
878 inline void HandlePercentageDamage(Effect *fx, Actor *target) {
879 if (fx->Parameter2 == RPD_PERCENT && fx->FirstApply) {
880 // distribute the damage to one second intervals
881 int seconds = (fx->Duration - core->GetGame()->GameTime) / AI_UPDATE_TIME;
882 fx->Parameter1 = target->GetStat(IE_MAXHITPOINTS) * fx->Parameter1 / 100 / seconds;
885 // Effect opcodes
887 // 0x00 ACVsDamageTypeModifier
888 int fx_ac_vs_damage_type_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
890 if (0) printf( "fx_ac_vs_damage_type_modifier (%2d): AC Modif: %d ; Type: %d ; MinLevel: %d ; MaxLevel: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2, (int) fx->DiceSides, (int) fx->DiceThrown );
891 //check level was pulled outside as a common functionality
892 //CHECK_LEVEL();
894 // it is a bitmask
895 int type = fx->Parameter2;
896 if (type == 0) {
897 HandleBonus(target, IE_ARMORCLASS, fx->Parameter1, fx->TimingMode);
898 return FX_PERMANENT;
901 //convert to signed so -1 doesn't turn to an astronomical number
902 if (type == 16) {
903 if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
904 if ((signed)BASE_GET( IE_ARMORCLASS) > (signed)fx->Parameter1) {
905 BASE_SET( IE_ARMORCLASS, fx->Parameter1 );
907 } else {
908 if ((signed)STAT_GET( IE_ARMORCLASS) > (signed)fx->Parameter1) {
909 STAT_SET( IE_ARMORCLASS, fx->Parameter1 );
912 return FX_INSERT;
915 //the original engine did work with the combination of these bits
916 //but since it crashed, we are not bound to the same rules
917 if (type & 1) {
918 HandleBonus(target, IE_ACCRUSHINGMOD, fx->Parameter1, fx->TimingMode);
920 if (type & 2) {
921 HandleBonus(target, IE_ACMISSILEMOD, fx->Parameter1, fx->TimingMode);
923 if (type & 4) {
924 HandleBonus(target, IE_ACPIERCINGMOD, fx->Parameter1, fx->TimingMode);
926 if (type & 8) {
927 HandleBonus(target, IE_ACSLASHINGMOD, fx->Parameter1, fx->TimingMode);
930 return FX_PERMANENT;
933 // 0x01 AttacksPerRoundModifier
934 int fx_attacks_per_round_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
936 if (0) printf( "fx_attacks_per_round_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
937 int tmp = (signed) fx->Parameter1;
938 if (fx->Parameter2!=2) {
939 if (tmp>10) tmp=10;
940 else if (tmp<-10) tmp=-10;
941 tmp <<= 1;
942 if (tmp>10) tmp-=11;
943 else if (tmp<-10) tmp+=11;
946 if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
947 BASE_MOD_VAR(IE_NUMBEROFATTACKS, tmp);
948 } else {
949 STAT_MOD_VAR(IE_NUMBEROFATTACKS, tmp);
951 return FX_PERMANENT;
954 // 0x02 Cure:Sleep (Awaken)
955 // this effect clears the STATE_SLEEP (1) bit, but clearing it alone wouldn't remove the
956 // unconscious effect, which is combined with STATE_HELPLESS (0x20+1)
957 static EffectRef fx_set_sleep_state_ref={"State:Helpless",NULL,-1};
958 //this reference is used by many other effects
959 static EffectRef fx_display_portrait_icon_ref={"Icon:Display",NULL,-1};
961 int fx_cure_sleep_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
963 if (0) printf( "fx_cure_sleep_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
964 BASE_STATE_CURE( STATE_SLEEP );
965 target->fxqueue.RemoveAllEffects(fx_set_sleep_state_ref);
966 target->fxqueue.RemoveAllEffectsWithParam(fx_display_portrait_icon_ref, PI_SLEEP);
967 return FX_NOT_APPLIED;
970 // 0x03 State:Berserk
971 // this effect sets the STATE_BERSERK bit, but bg2 actually ignores the bit
972 int fx_set_berserk_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
974 if (0) printf( "fx_set_berserk_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
975 // atleast how and bg2 allow this to only work on pcs
976 if (!core->HasFeature(GF_3ED_RULES) && !target->InParty) {
977 return FX_NOT_APPLIED;
980 if (fx->FirstApply) {
981 target->inventory.EquipBestWeapon(EQUIP_MELEE);
984 if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
985 BASE_STATE_SET( STATE_BERSERK );
986 } else {
987 STATE_SET( STATE_BERSERK );
990 switch(fx->Parameter2) {
991 case 1: //always berserk
992 target->SetSpellState(SS_BERSERK);
993 default:
994 target->AddPortraitIcon(PI_BERSERK);
995 break;
996 case 2: //blood rage
997 target->SetSpellState(SS_BERSERK);
998 //immunity to effects:
999 //5 charm
1000 //0x11 heal
1001 //0x18 panic
1002 //0x27 sleep
1003 //0x2d stun
1004 //0x6d hold
1005 //0x80 confusion
1006 //400 hopelessness
1008 target->SetSpellState(SS_BLOODRAGE);
1009 target->SetSpellState(SS_NOHPINFO);
1010 target->SetColorMod(0xff, RGBModifier::ADD, 15, 128, 0, 0);
1011 target->AddPortraitIcon(PI_BLOODRAGE);
1012 break;
1014 return FX_PERMANENT;
1017 // 0x04 Cure:Berserk
1018 // this effect clears the STATE_BERSERK (2) bit, but bg2 actually ignores the bit
1019 // it also removes effect 04
1020 static EffectRef fx_set_berserk_state_ref={"State:Berserk",NULL,-1};
1022 int fx_cure_berserk_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1024 if (0) printf( "fx_cure_berserk_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1025 BASE_STATE_CURE( STATE_BERSERK );
1026 target->fxqueue.RemoveAllEffects(fx_set_berserk_state_ref);
1027 return FX_NOT_APPLIED;
1030 // 0x05 State:Charmed
1031 // 0xf1 ControlCreature (iwd2)
1032 int fx_set_charmed_state (Scriptable* Owner, Actor* target, Effect* fx)
1034 if (0) printf( "fx_set_charmed_state (%2d): General: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1036 //blood rage berserking gives immunity to charm (in iwd2)
1037 if (target->HasSpellState(SS_BLOODRAGE)) {
1038 return FX_NOT_APPLIED;
1041 //protection from evil gives immunity to charm (in iwd2)
1042 if (target->HasSpellState(SS_PROTFROMEVIL)) {
1043 return FX_NOT_APPLIED;
1046 if (fx->Parameter1 && (STAT_GET(IE_GENERAL)!=fx->Parameter1)) {
1047 return FX_NOT_APPLIED;
1050 Scriptable *caster = GetCaster(Owner, fx);
1051 if (!caster) caster = Owner; // IE stores the enemyally in the effect instead
1052 bool enemyally = true;
1053 if (caster->Type==ST_ACTOR) {
1054 enemyally = ((Actor *) caster)->GetStat(IE_EA)>EA_GOODCUTOFF; //or evilcutoff?
1057 switch (fx->Parameter2) {
1058 case 0: //charmed (target neutral after charm)
1059 if (fx->FirstApply) {
1060 displaymsg->DisplayConstantStringName(STR_CHARMED, 0xf0f0f0, target);
1062 case 1000:
1063 break;
1064 case 1: //charmed (target hostile after charm)
1065 if (fx->FirstApply) {
1066 displaymsg->DisplayConstantStringName(STR_CHARMED, 0xf0f0f0, target);
1068 case 1001:
1069 if (!target->InParty) {
1070 target->SetBaseNoPCF(IE_EA, EA_ENEMY);
1072 break;
1073 case 2: //dire charmed (target neutral after charm)
1074 if (fx->FirstApply) {
1075 displaymsg->DisplayConstantStringName(STR_DIRECHARMED, 0xf0f0f0, target);
1077 case 1002:
1078 break;
1079 case 3: //dire charmed (target hostile after charm)
1080 if (fx->FirstApply) {
1081 displaymsg->DisplayConstantStringName(STR_DIRECHARMED, 0xf0f0f0, target);
1083 case 1003:
1084 if (!target->InParty) {
1085 target->SetBaseNoPCF(IE_EA, EA_ENEMY);
1087 break;
1088 case 4: //controlled by cleric
1089 if (fx->FirstApply) {
1090 displaymsg->DisplayConstantStringName(STR_CONTROLLED, 0xf0f0f0, target);
1092 case 1004:
1093 if (!target->InParty) {
1094 target->SetBaseNoPCF(IE_EA, EA_ENEMY);
1096 break;
1097 case 5: //thrall (typo comes from original engine doc)
1098 if (fx->FirstApply) {
1099 displaymsg->DisplayConstantStringName(STR_CHARMED, 0xf0f0f0, target);
1101 case 1005:
1102 STAT_SET(IE_EA, EA_ENEMY );
1103 STAT_SET(IE_THRULLCHARM, 1);
1104 return FX_PERMANENT;
1107 STATE_SET( STATE_CHARMED );
1108 STAT_SET_PCF( IE_EA, enemyally?EA_ENEMY:EA_CHARMED );
1109 //don't stick if permanent
1110 return FX_PERMANENT;
1113 // 0x06 CharismaModifier
1114 int fx_charisma_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1116 if (0) printf( "fx_charisma_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1118 if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
1119 BASE_MOD( IE_CHR );
1120 } else {
1121 STAT_MOD( IE_CHR );
1123 return FX_PERMANENT;
1126 // 0x07 Color:SetPalette
1127 // this effect might not work in pst, they don't have separate weapon slots
1128 int fx_set_color_gradient (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1130 if (0) printf( "fx_set_color_gradient (%2d): Gradient: %d, Location: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1131 EffectQueue::HackColorEffects(target, fx);
1132 target->SetColor( fx->Parameter2, fx->Parameter1 );
1133 return FX_APPLIED;
1136 // 08 Color:SetRGB
1137 int fx_set_color_rgb (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1139 if (0) printf( "fx_set_color_rgb (%2d): RGB: %x, Location: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1140 EffectQueue::HackColorEffects(target, fx);
1141 ieDword location = fx->Parameter2 & 0xff;
1142 target->SetColorMod(location, RGBModifier::ADD, -1, fx->Parameter1 >> 8,
1143 fx->Parameter1 >> 16, fx->Parameter1 >> 24);
1145 return FX_APPLIED;
1147 // 08 Color:SetRGBGlobal
1148 int fx_set_color_rgb_global (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1150 if (0) printf( "fx_set_color_rgb_global (%2d): RGB: %x, Location: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1152 target->SetColorMod(0xff, RGBModifier::ADD, -1, fx->Parameter1 >> 8,
1153 fx->Parameter1 >> 16, fx->Parameter1 >> 24);
1155 return FX_APPLIED;
1158 // 09 Color:PulseRGB
1159 int fx_set_color_pulse_rgb (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1161 if (0) printf( "fx_set_color_pulse_rgb (%2d): RGB: %x, Location: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1162 EffectQueue::HackColorEffects(target, fx);
1163 ieDword location = fx->Parameter2 & 0xff;
1164 int speed = (fx->Parameter2 >> 16) & 0xFF;
1165 target->SetColorMod(location, RGBModifier::ADD, speed,
1166 fx->Parameter1 >> 8, fx->Parameter1 >> 16,
1167 fx->Parameter1 >> 24);
1169 return FX_APPLIED;
1172 // 09 Color:PulseRGBGlobal (pst variant)
1173 int fx_set_color_pulse_rgb_global (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1175 if (0) printf( "fx_set_color_pulse_rgb_global (%2d): RGB: %x, Location: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1177 int speed = (fx->Parameter2 >> 16) & 0xFF;
1178 target->SetColorMod(0xff, RGBModifier::ADD, speed,
1179 fx->Parameter1 >> 8, fx->Parameter1 >> 16,
1180 fx->Parameter1 >> 24);
1182 return FX_APPLIED;
1185 // 0x0A ConstitutionModifier
1186 int fx_constitution_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1188 if (0) printf( "fx_constitution_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1190 if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
1191 BASE_MOD( IE_CON );
1192 } else {
1193 STAT_MOD( IE_CON );
1195 return FX_PERMANENT;
1198 // 0x0B Cure:Poison
1199 static EffectRef fx_poisoned_state_ref={"State:Poisoned",NULL,-1};
1201 int fx_cure_poisoned_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1203 if (0) printf( "fx_cure_poisoned_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1204 //all three steps are present in bg2 and iwd2
1205 BASE_STATE_CURE( STATE_POISONED );
1206 target->fxqueue.RemoveAllEffects( fx_poisoned_state_ref );
1207 target->fxqueue.RemoveAllEffectsWithParam(fx_display_portrait_icon_ref, PI_POISONED);
1208 return FX_NOT_APPLIED;
1211 // 0x0c Damage
1212 // this is a very important effect
1213 int fx_damage (Scriptable* Owner, Actor* target, Effect* fx)
1215 if (0) printf( "fx_damage (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1216 //save for half damage type
1217 ieDword damagetype = fx->Parameter2>>16;
1218 ieDword modtype = fx->Parameter2&3;
1219 if (modtype==3) {
1220 modtype&=~3;
1222 Scriptable *caster = GetCaster(Owner, fx);
1224 target->Damage(fx->Parameter1, damagetype, caster, modtype);
1225 //this effect doesn't stick
1226 return FX_NOT_APPLIED;
1229 // 0x0d Death
1230 int fx_death (Scriptable* Owner, Actor* target, Effect* fx)
1232 if (0) printf( "fx_death (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1233 ieDword damagetype = 0;
1234 switch (fx->Parameter2) {
1235 case 1:
1236 BASE_STATE_SET(STATE_D4); //not sure, should be charred
1237 damagetype = DAMAGE_FIRE;
1238 break;
1239 case 2:
1240 damagetype = DAMAGE_CRUSHING;
1241 break;
1242 case 4:
1243 damagetype = DAMAGE_CRUSHING;
1244 break;
1245 case 8:
1246 damagetype = DAMAGE_CRUSHING|DAMAGE_CHUNKING;
1247 break;
1248 case 16:
1249 BASE_STATE_SET(STATE_PETRIFIED);
1250 damagetype = DAMAGE_CRUSHING;
1251 break;
1252 case 32:
1253 BASE_STATE_SET(STATE_FROZEN);
1254 damagetype = DAMAGE_COLD;
1255 break;
1256 case 64:
1257 BASE_STATE_SET(STATE_PETRIFIED);
1258 damagetype = DAMAGE_CRUSHING|DAMAGE_CHUNKING;
1259 break;
1260 case 128:
1261 BASE_STATE_SET(STATE_FROZEN);
1262 damagetype = DAMAGE_COLD|DAMAGE_CHUNKING;
1263 break;
1264 case 256:
1265 damagetype = DAMAGE_ELECTRICITY;
1266 break;
1267 case 512:
1269 default:
1270 damagetype = DAMAGE_ACID;
1272 target->Damage(0, damagetype, Owner);
1273 //death has damage type too
1274 target->Die(Owner);
1275 //this effect doesn't stick
1276 return FX_NOT_APPLIED;
1279 // 0xE Cure:Defrost
1280 int fx_cure_frozen_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1282 if (0) printf( "fx_cure_frozen_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1283 BASE_STATE_CURE( STATE_FROZEN );
1284 return FX_NOT_APPLIED;
1287 // 0x0F DexterityModifier
1289 #define CSA_DEX 0
1290 #define CSA_STR 1
1291 #define CSA_CNT 2
1292 int SpellAbilityDieRoll(Actor *target, int which)
1294 if (which>=CSA_CNT) return 6;
1296 ieDword cls = STAT_GET(IE_CLASS);
1297 if (!spell_abilities) {
1298 AutoTable tab("clssplab");
1299 if (!tab) {
1300 spell_abilities = (int *) malloc(sizeof(int)*CSA_CNT);
1301 for (int ab=0;ab<CSA_CNT;ab++) {
1302 spell_abilities[ab*splabcount]=6;
1304 splabcount=1;
1305 return 6;
1307 splabcount = tab->GetRowCount();
1308 spell_abilities=(int *) malloc(sizeof(int)*splabcount*CSA_CNT);
1309 for (int ab=0;ab<CSA_CNT;ab++) {
1310 for (ieDword i=0;i<splabcount;i++) {
1311 spell_abilities[ab*splabcount+i]=atoi(tab->QueryField(i,ab));
1315 if (cls>=splabcount) cls=0;
1316 return spell_abilities[which*splabcount+cls];
1319 int fx_dexterity_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1321 if (0) printf( "fx_dexterity_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1323 ////how cat's grace: value is based on class
1324 if (fx->Parameter2==3) {
1325 fx->Parameter1 = core->Roll(1,SpellAbilityDieRoll(target,0),0);
1326 fx->Parameter2 = 0;
1329 if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
1330 BASE_MOD( IE_DEX );
1331 } else {
1332 STAT_MOD( IE_DEX );
1334 return FX_PERMANENT;
1337 static EffectRef fx_set_slow_state_ref={"State:Slowed",NULL,-1};
1338 // 0x10 State:Hasted
1339 // this function removes slowed state, or sets hasted state
1340 int fx_set_hasted_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1342 if (0) printf( "fx_set_hasted_state (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
1343 target->fxqueue.RemoveAllEffects(fx_set_slow_state_ref);
1344 target->fxqueue.RemoveAllEffectsWithParam( fx_display_portrait_icon_ref, PI_SLOWED );
1345 if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
1346 BASE_STATE_CURE( STATE_SLOWED );
1347 BASE_STATE_SET( STATE_HASTED );
1348 } else {
1349 STATE_CURE( STATE_SLOWED );
1350 STATE_SET( STATE_HASTED );
1352 target->NewStat(IE_MOVEMENTRATE, 200, MOD_PERCENT);
1353 switch (fx->Parameter2) {
1354 case 0: //normal haste
1355 target->AddPortraitIcon(PI_HASTED);
1356 STAT_SET(IE_IMPROVEDHASTE,0);
1357 STAT_SET(IE_ATTACKNUMBERDOUBLE,0);
1358 STAT_ADD(IE_NUMBEROFATTACKS, 2);
1359 // -2 initiative bonus
1360 STAT_ADD(IE_PHYSICALSPEED, 2);
1361 break;
1362 case 1://improved haste
1363 target->AddPortraitIcon(PI_IMPROVEDHASTE);
1364 STAT_SET(IE_IMPROVEDHASTE,1);
1365 STAT_SET(IE_ATTACKNUMBERDOUBLE,0);
1366 target->NewStat(IE_NUMBEROFATTACKS, 200, MOD_PERCENT);
1367 // -2 initiative bonus
1368 STAT_ADD(IE_PHYSICALSPEED, 2);
1369 break;
1370 case 2://speed haste only
1371 target->AddPortraitIcon(PI_HASTED);
1372 STAT_SET(IE_IMPROVEDHASTE,0);
1373 STAT_SET(IE_ATTACKNUMBERDOUBLE,1);
1374 break;
1377 return FX_PERMANENT;
1380 // 0x11 CurrentHPModifier
1381 int fx_current_hp_modifier (Scriptable* Owner, Actor* target, Effect* fx)
1383 if (0) printf( "fx_current_hp_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1385 if (fx->Parameter2&0x10000) {
1386 Point p(fx->PosX, fx->PosY);
1387 Resurrect(Owner, target, fx, p);
1389 if (fx->Parameter2&0x20000) {
1390 target->fxqueue.RemoveAllNonPermanentEffects();
1392 //Cannot heal bloodrage
1393 if (target->HasSpellState(SS_BLOODRAGE)) {
1394 return FX_NOT_APPLIED;
1397 //current hp percent is relative to modified max hp
1398 switch(fx->Parameter2&0xffff) {
1399 case MOD_ADDITIVE:
1400 case MOD_ABSOLUTE:
1401 target->NewBase( IE_HITPOINTS, fx->Parameter1, fx->Parameter2&0xffff);
1402 break;
1403 case MOD_PERCENT:
1404 target->NewBase( IE_HITPOINTS, target->GetSafeStat(IE_MAXHITPOINTS)*fx->Parameter1/100, MOD_ABSOLUTE);
1406 //never stay permanent
1407 return FX_NOT_APPLIED;
1410 // 0x12 MaximumHPModifier
1411 // 0 and 3 differ in that 3 doesn't modify current hitpoints
1412 // 1,4 and 2,5 are analogous to them, but with different modifiers
1413 int fx_maximum_hp_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1415 if (0) printf( "fx_maximum_hp_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1417 if (STATE_GET( STATE_DEAD|STATE_PETRIFIED|STATE_FROZEN) ) {
1418 return FX_NOT_APPLIED;
1421 bool base = fx->TimingMode==FX_DURATION_INSTANT_PERMANENT;
1423 switch (fx->Parameter2) {
1424 case 0:
1425 // random value Parameter1 is set by level_check in EffectQueue
1426 if (base) {
1427 BASE_ADD( IE_MAXHITPOINTS, fx->Parameter1 );
1428 BASE_ADD( IE_HITPOINTS, fx->Parameter1 );
1429 } else {
1430 STAT_ADD( IE_MAXHITPOINTS, fx->Parameter1 );
1431 if (fx->FirstApply) {
1432 BASE_ADD( IE_HITPOINTS, fx->Parameter1 );
1435 break;
1436 case 3: // no current hp bonus
1437 // random value Parameter1 is set by level_check in EffectQueue
1438 if (base) {
1439 BASE_ADD( IE_MAXHITPOINTS, fx->Parameter1 );
1440 } else {
1441 STAT_ADD( IE_MAXHITPOINTS, fx->Parameter1 );
1443 break;
1444 case 1: // with current hp bonus, but unimplemented in the original
1445 case 4:
1446 if (base) {
1447 BASE_SET( IE_MAXHITPOINTS, fx->Parameter1 );
1448 } else {
1449 STAT_SET( IE_MAXHITPOINTS, fx->Parameter1 );
1451 break;
1452 case 2:
1453 if (base) {
1454 BASE_MUL(IE_MAXHITPOINTS, fx->Parameter1 );
1455 BASE_MUL(IE_HITPOINTS, fx->Parameter1 );
1456 } else {
1457 target->NewStat( IE_MAXHITPOINTS, target->GetStat(IE_MAXHITPOINTS)*fx->Parameter1/100, MOD_ABSOLUTE);
1458 if (fx->FirstApply) {
1459 target->NewBase( IE_HITPOINTS, target->GetSafeStat(IE_HITPOINTS)*fx->Parameter1/100, MOD_ABSOLUTE);
1462 break;
1463 case 5: // no current hp bonus
1464 if (base) {
1465 BASE_MUL( IE_MAXHITPOINTS, fx->Parameter1 );
1466 } else {
1467 STAT_MUL( IE_MAXHITPOINTS, fx->Parameter1 );
1469 break;
1471 return FX_PERMANENT;
1474 // 0x13 IntelligenceModifier
1475 int fx_intelligence_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1477 if (0) printf( "fx_intelligence_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1479 if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
1480 BASE_MOD( IE_INT );
1481 } else {
1482 STAT_MOD( IE_INT );
1484 return FX_PERMANENT;
1487 // 0x14 State:Invisible
1488 // this is more complex, there is a half-invisibility state
1489 // and there is a hidden state
1490 int fx_set_invisible_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1492 switch (fx->Parameter2) {
1493 case 0:
1494 if (pstflags) {
1495 STATE_SET( STATE_PST_INVIS );
1496 } else {
1497 STATE_SET( STATE_INVISIBLE );
1499 STAT_ADD(IE_TOHIT, 4);
1500 break;
1501 case 1:
1502 STATE_SET( STATE_INVIS2 );
1503 HandleBonus(target, IE_ARMORCLASS, 4, fx->TimingMode);
1504 break;
1505 default:
1506 break;
1508 ieDword Trans = fx->Parameter4;
1509 if (fx->Parameter3) {
1510 if (Trans>=240) {
1511 fx->Parameter3=0;
1512 } else {
1513 Trans+=16;
1515 } else {
1516 if (Trans<=32) {
1517 fx->Parameter3=1;
1518 } else {
1519 Trans-=16;
1522 fx->Parameter4=Trans;
1523 STAT_SET( IE_TRANSLUCENT, Trans);
1524 return FX_APPLIED;
1527 // 0x15 LoreModifier
1528 int fx_lore_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1530 if (0) printf( "fx_lore_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1532 STAT_MOD( IE_LORE );
1533 return FX_APPLIED;
1536 // 0x16 LuckModifier
1537 int fx_luck_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1539 if (0) printf( "fx_luck_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1541 STAT_MOD( IE_LUCK );
1542 STAT_MOD( IE_DAMAGELUCK );
1543 return FX_APPLIED;
1546 // 0x17 MoraleModifier
1547 int fx_morale_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1549 if (0) printf( "fx_morale_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1551 STAT_MOD( IE_MORALE );
1552 return FX_APPLIED;
1555 // 0x18 State:Panic
1556 int fx_set_panic_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1558 if (0) printf( "fx_set_panic_state (%2d)\n", fx->Opcode );
1560 if (target->HasSpellState(SS_BLOODRAGE)) {
1561 return FX_NOT_APPLIED;
1564 if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
1565 BASE_STATE_SET( STATE_PANIC );
1566 } else {
1567 STATE_SET( STATE_PANIC );
1569 if (enhanced_effects) {
1570 target->AddPortraitIcon(PI_PANIC);
1572 return FX_PERMANENT;
1575 // 0x19 State:Poisoned
1576 int fx_set_poisoned_state (Scriptable* Owner, Actor* target, Effect* fx)
1578 if (0) printf( "fx_set_poisoned_state (%2d): Damage: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1579 //apparently this bit isn't set, but then why is it here
1580 //this requires a little research
1581 STATE_SET( STATE_POISONED );
1582 //also this effect is executed every update
1583 ieDword damage;
1584 int tmp = fx->Parameter1;
1586 HandlePercentageDamage(fx, target);
1588 switch(fx->Parameter2) {
1589 case RPD_ROUNDS:
1590 tmp *= core->Time.round_sec;
1591 damage = 1;
1592 break;
1593 case RPD_TURNS:
1594 tmp *= core->Time.turn_sec;
1595 damage = 1;
1596 break;
1597 case RPD_SECONDS:
1598 damage = 1;
1599 break;
1600 case RPD_PERCENT: // handled in HandlePercentageDamage
1601 case RPD_POINTS:
1602 tmp = 1; // hit points per second
1603 damage = fx->Parameter1;
1604 break;
1605 default:
1606 tmp = 1;
1607 damage = 1;
1608 break;
1611 // all damage is at most per-second
1612 tmp *= AI_UPDATE_TIME;
1613 if (tmp && (core->GetGame()->GameTime%tmp)) {
1614 return FX_APPLIED;
1617 Scriptable *caster = GetCaster(Owner, fx);
1619 //percent
1620 target->Damage(damage, DAMAGE_POISON, caster);
1621 return FX_APPLIED;
1624 // 0x1a RemoveCurse
1625 static EffectRef fx_apply_effect_curse_ref={"ApplyEffectCurse",NULL,-1};
1626 static EffectRef fx_pst_jumble_curse_ref={"JumbleCurse",NULL,-1};
1628 // gemrb extension: if the resource field is filled, it will remove curse only from the specified item
1629 int fx_remove_curse (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1631 if (0) printf( "fx_remove_curse (%2d): Resource: %s Type: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
1633 switch(fx->Parameter2)
1635 case 1:
1636 //this is pst specific
1637 target->fxqueue.RemoveAllEffects(fx_pst_jumble_curse_ref);
1638 break;
1639 default:
1640 Inventory *inv = &target->inventory;
1641 int i = target->inventory.GetSlotCount();
1642 while(i--) {
1643 //does this slot need unequipping
1644 if (core->QuerySlotEffects(i) ) {
1645 if (fx->Resource[0] && strnicmp(inv->GetSlotItem(i)->ItemResRef, fx->Resource,8) ) {
1646 continue;
1648 if (!(inv->GetItemFlag(i)&IE_INV_ITEM_CURSED)) {
1649 continue;
1651 inv->ChangeItemFlag(i, IE_INV_ITEM_CURSED, BM_NAND);
1652 if (inv->UnEquipItem(i,true)) {
1653 CREItem *tmp = inv->RemoveItem(i);
1654 if(inv->AddSlotItem(tmp,-3)!=ASI_SUCCESS) {
1655 //if the item couldn't be placed in the inventory, then put it back to the original slot
1656 inv->SetSlotItem(tmp,i);
1657 //and drop it in the area. (If there is no area, then the item will stay in the inventory)
1658 target->DropItem(i,0);
1663 target->fxqueue.RemoveAllEffects(fx_apply_effect_curse_ref);
1666 //this is an instant effect
1667 return FX_NOT_APPLIED;
1670 // 0x1b AcidResistanceModifier
1671 int fx_acid_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1673 if (0) printf( "fx_acid_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1675 STAT_MOD( IE_RESISTACID );
1676 return FX_APPLIED;
1679 // 0x1c ColdResistanceModifier
1680 int fx_cold_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1682 if (0) printf( "fx_cold_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1684 STAT_MOD( IE_RESISTCOLD );
1685 return FX_APPLIED;
1688 // 0x1d ElectricityResistanceModifier
1689 int fx_electricity_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1691 if (0) printf( "fx_electricity_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1693 STAT_MOD( IE_RESISTELECTRICITY );
1694 return FX_APPLIED;
1697 // 0x1e FireResistanceModifier
1698 int fx_fire_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1700 if (0) printf( "fx_fire_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1702 STAT_MOD( IE_RESISTFIRE );
1703 return FX_APPLIED;
1706 // 0x1f MagicDamageResistanceModifier
1707 int fx_magic_damage_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1709 if (0) printf( "fx_magic_damage_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1711 STAT_MOD( IE_MAGICDAMAGERESISTANCE );
1712 return FX_APPLIED;
1715 // 0x20 Cure:Death
1716 int fx_cure_dead_state (Scriptable* Owner, Actor* target, Effect* fx)
1718 if (0) printf( "fx_cure_dead_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1719 Point p(fx->PosX, fx->PosY);
1720 Resurrect(Owner, target, fx, p);
1721 return FX_NOT_APPLIED;
1724 // 0x21 SaveVsDeathModifier
1725 int fx_save_vs_death_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1727 if (0) printf( "fx_save_vs_death_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1729 HandleBonus( target, IE_SAVEVSDEATH, fx->Parameter1, fx->TimingMode );
1730 return FX_APPLIED;
1733 // 0x22 SaveVsWandsModifier
1734 int fx_save_vs_wands_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1736 if (0) printf( "fx_save_vs_wands_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1738 HandleBonus( target, IE_SAVEVSWANDS, fx->Parameter1, fx->TimingMode );
1739 return FX_APPLIED;
1742 // 0x23 SaveVsPolyModifier
1743 int fx_save_vs_poly_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1745 if (0) printf( "fx_save_vs_poly_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1747 HandleBonus( target, IE_SAVEVSPOLY, fx->Parameter1, fx->TimingMode );
1748 return FX_APPLIED;
1751 // 0x24 SaveVsBreathModifier
1752 int fx_save_vs_breath_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1754 if (0) printf( "fx_save_vs_breath_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1756 HandleBonus( target, IE_SAVEVSBREATH, fx->Parameter1, fx->TimingMode );
1757 return FX_APPLIED;
1760 // 0x25 SaveVsSpellsModifier
1761 int fx_save_vs_spell_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1763 if (0) printf( "fx_save_vs_spell_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1765 HandleBonus( target, IE_SAVEVSSPELL, fx->Parameter1, fx->TimingMode );
1766 return FX_APPLIED;
1769 // 0x26 State:Silenced
1770 int fx_set_silenced_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1772 if (0) printf( "fx_set_silenced_state (%2d)\n", fx->Opcode );
1773 STATE_SET( STATE_SILENCED );
1774 return FX_APPLIED;
1777 static EffectRef fx_animation_stance_ref = {"AnimationStateChange",NULL,-1};
1779 // 0x27 State:Helpless
1780 // this effect sets both bits, but 'awaken' only removes the sleep bit
1781 // FIXME: this is probably a persistent effect
1782 int fx_set_unconscious_state (Scriptable* Owner, Actor* target, Effect* fx)
1784 if (0) printf( "fx_set_unconscious_state (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
1786 if (target->HasSpellState(SS_BLOODRAGE)) {
1787 return FX_NOT_APPLIED;
1790 if (fx->FirstApply) {
1791 Effect *newfx;
1793 newfx = EffectQueue::CreateEffectCopy(fx, fx_animation_stance_ref, 0, IE_ANI_SLEEP);
1794 core->ApplyEffect(newfx, target, Owner);
1796 delete newfx;
1799 if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
1800 BASE_STATE_SET( STATE_HELPLESS | STATE_SLEEP ); //don't awaken on damage
1801 } else {
1802 STATE_SET( STATE_HELPLESS | STATE_SLEEP ); //don't awaken on damage
1803 if (fx->Parameter2) {
1804 target->SetSpellState(SS_NOAWAKE);
1806 target->AddPortraitIcon(PI_SLEEP);
1808 return FX_PERMANENT;
1811 // 0x28 State:Slowed
1812 // this function removes hasted state, or sets slowed state
1813 static EffectRef fx_set_haste_state_ref={"State:Hasted",NULL,-1};
1815 int fx_set_slowed_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1817 if (0) printf( "fx_set_slowed_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1819 //iwd2 free action or aegis disables this effect
1820 if (target->HasSpellState(SS_FREEACTION)) return FX_NOT_APPLIED;
1821 if (target->HasSpellState(SS_AEGIS)) return FX_NOT_APPLIED;
1823 if (STATE_GET(STATE_HASTED) ) {
1824 BASE_STATE_CURE( STATE_HASTED );
1825 target->fxqueue.RemoveAllEffects( fx_set_haste_state_ref );
1826 target->fxqueue.RemoveAllEffectsWithParam( fx_display_portrait_icon_ref, PI_HASTED );
1827 } else {
1828 STATE_SET( STATE_SLOWED );
1829 target->AddPortraitIcon(PI_SLOWED);
1830 // halve apr and speed
1831 STAT_MUL(IE_NUMBEROFATTACKS, 50);
1832 STAT_MUL(IE_MOVEMENTRATE, 50);
1834 return FX_PERMANENT;
1837 // 0x29 Sparkle
1838 int fx_sparkle (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1840 if (0) printf( "fx_sparkle (%2d): Sparkle colour: %d ; Sparkle type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1841 if (!target) {
1842 return FX_NOT_APPLIED;
1845 Map *map = target->GetCurrentArea();
1846 if (!map) {
1847 return FX_APPLIED;
1849 Point p(fx->PosX, fx->PosY);
1851 map->Sparkle( fx->Duration, fx->Parameter1, fx->Parameter2, p, fx->Parameter3);
1852 return FX_NOT_APPLIED;
1855 // 0x2A WizardSpellSlotsModifier
1856 int fx_bonus_wizard_spells (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1858 if (0) printf( "fx_bonus_wizard_spells (%2d): Spell Add: %d ; Spell Level: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1860 int i=1;
1861 //if param2 is 0, then double spells up to param1
1862 if(!fx->Parameter2) {
1863 for (unsigned int j=0;j<fx->Parameter1 && j<MAX_SPELL_LEVEL;j++) {
1864 target->spellbook.SetMemorizableSpellsCount(0, IE_SPELL_TYPE_WIZARD, j, true);
1866 return FX_APPLIED;
1868 //HoW specific
1869 //if param2 is 0x200, then double spells at param1
1870 if (fx->Parameter2==0x200) {
1871 unsigned int j = fx->Parameter1-1;
1872 if (j<MAX_SPELL_LEVEL) {
1873 target->spellbook.SetMemorizableSpellsCount(0, IE_SPELL_TYPE_WIZARD, j, true);
1877 for(unsigned int j=0;j<MAX_SPELL_LEVEL;j++) {
1878 if (fx->Parameter2&i) {
1879 target->spellbook.SetMemorizableSpellsCount(fx->Parameter1, IE_SPELL_TYPE_WIZARD, j, true);
1881 i<<=1;
1883 return FX_APPLIED;
1886 // 0x2B Cure:Petrification
1887 int fx_cure_petrified_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1889 if (0) printf( "fx_cure_petrified_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1890 BASE_STATE_CURE( STATE_PETRIFIED );
1891 return FX_NOT_APPLIED;
1894 // 0x2C StrengthModifier
1895 int fx_strength_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1897 if (0) printf( "fx_strength_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1899 ////how strength: value is based on class
1900 if (fx->Parameter2==3) {
1901 fx->Parameter1 = core->Roll(1,SpellAbilityDieRoll(target,1),0);
1902 fx->Parameter2 = 0;
1905 if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
1906 BASE_MOD( IE_STR );
1907 } else {
1908 STAT_MOD( IE_STR );
1910 return FX_PERMANENT;
1913 // 0x2D State:Stun
1914 int power_word_stun_iwd2(Actor *target, Effect *fx)
1916 int hp = BASE_GET(IE_HITPOINTS);
1917 if (hp>150) return FX_NOT_APPLIED;
1918 int stuntime;
1919 if (hp>100) stuntime = core->Roll(1,4,0);
1920 else if (hp>50) stuntime = core->Roll(2,4,0);
1921 else stuntime = core->Roll(4,4,0);
1922 fx->Parameter2 = 0;
1923 fx->TimingMode = FX_DURATION_ABSOLUTE;
1924 fx->Duration = stuntime*6*core->Time.round_size + core->GetGame()->GameTime;
1925 STATE_SET( STATE_STUNNED );
1926 target->AddPortraitIcon(PI_STUN);
1927 return FX_APPLIED;
1930 int fx_set_stun_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1932 if (0) printf( "fx_set_stun_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1934 //actually the original engine just skips this effect if the target is dead
1935 if ( STATE_GET(STATE_DEAD) ) {
1936 return FX_NOT_APPLIED;
1939 //this is an IWD extension
1940 if (target->HasSpellState(SS_BLOODRAGE)) {
1941 return FX_NOT_APPLIED;
1944 if (fx->Parameter2==2) {
1945 //don't reroll the duration next time we get here
1946 if (fx->FirstApply) {
1947 return power_word_stun_iwd2(target, fx);
1950 STATE_SET( STATE_STUNNED );
1951 target->AddPortraitIcon(PI_STUN);
1952 if (fx->Parameter2==1) {
1953 target->SetSpellState(SS_AWAKE);
1955 return FX_APPLIED;
1958 // 0x2E Cure:Stun
1959 static EffectRef fx_set_stun_state_ref={"State:Stun",NULL,-1};
1960 static EffectRef fx_hold_creature_no_icon_ref={"State:HoldNoIcon",NULL,-1};
1962 int fx_cure_stun_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1964 if (0) printf( "fx_cure_stun_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1965 BASE_STATE_CURE( STATE_STUNNED );
1966 target->fxqueue.RemoveAllEffects(fx_set_stun_state_ref);
1967 target->fxqueue.RemoveAllEffects(fx_hold_creature_no_icon_ref);
1968 target->fxqueue.RemoveAllEffectsWithParam(fx_display_portrait_icon_ref, PI_HELD);
1969 target->fxqueue.RemoveAllEffectsWithParam(fx_display_portrait_icon_ref, PI_HOPELESS);
1970 return FX_NOT_APPLIED;
1973 // 0x2F Cure:Invisible
1974 // 0x74 Cure:Invisible2
1975 static EffectRef fx_set_invisible_state_ref={"State:Invisible",NULL,-1};
1977 int fx_cure_invisible_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1979 if (0) printf( "fx_cure_invisible_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1980 if (!STATE_GET(STATE_NONDET)) {
1981 if (pstflags) {
1982 BASE_STATE_CURE( STATE_PST_INVIS );
1983 } else {
1984 BASE_STATE_CURE( STATE_INVISIBLE | STATE_INVIS2 );
1986 target->fxqueue.RemoveAllEffects(fx_set_invisible_state_ref);
1988 return FX_NOT_APPLIED;
1991 // 0x30 Cure:Silence
1992 static EffectRef fx_set_silenced_state_ref={"State:Silenced",NULL,-1};
1994 int fx_cure_silenced_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
1996 if (0) printf( "fx_cure_silenced_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
1997 BASE_STATE_CURE( STATE_SILENCED );
1998 target->fxqueue.RemoveAllEffects(fx_set_silenced_state_ref);
1999 return FX_NOT_APPLIED;
2002 // 0x31 WisdomModifier
2003 int fx_wisdom_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2005 if (0) printf( "fx_wisdom_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2007 if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
2008 BASE_MOD( IE_WIS );
2009 } else {
2010 STAT_MOD( IE_WIS );
2012 return FX_PERMANENT;
2015 // 0x32 Color:BriefRGB
2016 int fx_brief_rgb (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2018 if (0) printf( "fx_brief_rgb (%2d): RGB: %d, Location and speed: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2020 int speed = (fx->Parameter2 >> 16) & 0xff;
2021 target->SetColorMod(0xff, RGBModifier::ADD, speed,
2022 fx->Parameter1 >> 8, fx->Parameter1 >> 16,
2023 fx->Parameter1 >> 24, 0);
2025 return FX_NOT_APPLIED;
2028 // 0x33 Color:DarkenRGB
2029 int fx_darken_rgb (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2031 if (0) printf( "fx_darken_rgb (%2d): RGB: %d, Location and speed: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2032 EffectQueue::HackColorEffects(target, fx);
2033 ieDword location = fx->Parameter2 & 0xff;
2034 target->SetColorMod(location, RGBModifier::TINT, -1, fx->Parameter1 >> 8,
2035 fx->Parameter1 >> 16, fx->Parameter1 >> 24);
2036 return FX_APPLIED;
2039 // 0x34 Color:GlowRGB
2040 int fx_glow_rgb (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2042 if (0) printf( "fx_glow_rgb (%2d): RGB: %d, Location and speed: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2043 EffectQueue::HackColorEffects(target, fx);
2044 ieDword location = fx->Parameter2 & 0xff;
2045 target->SetColorMod(location, RGBModifier::BRIGHTEN, -1,
2046 fx->Parameter1 >> 8, fx->Parameter1 >> 16,
2047 fx->Parameter1 >> 24);
2049 return FX_APPLIED;
2052 // 0x35 AnimationIDModifier
2053 static EffectRef fx_animation_id_modifier_ref={"AnimationIDModifier",NULL,-1};
2055 int fx_animation_id_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2057 if (0) printf( "fx_animation_id_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2059 switch (fx->Parameter2) {
2060 case 0: //non permanent animation change
2061 default:
2062 STAT_SET( IE_ANIMATION_ID, fx->Parameter1 );
2063 return FX_APPLIED;
2064 case 1: //remove any non permanent change
2065 target->fxqueue.RemoveAllEffects(fx_animation_id_modifier_ref);
2066 //return FX_NOT_APPLIED;
2067 //intentionally passing through (perma change removes previous changes)
2068 case 2: //permanent animation id change
2069 target->SetBaseNoPCF(IE_ANIMATION_ID, fx->Parameter1);
2070 return FX_NOT_APPLIED;
2074 // 0x36 ToHitModifier
2075 int fx_to_hit_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2077 if (0) printf( "fx_to_hit_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2079 HandleBonus( target, IE_TOHIT, fx->Parameter1, fx->TimingMode );
2080 return FX_APPLIED;
2083 // 0x37 KillCreatureType
2084 static EffectRef fx_death_ref={"Death",NULL,-1};
2086 int fx_kill_creature_type (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2088 if (0) printf( "fx_kill_creature_type (%2d): Value: %d, IDS: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2089 if (EffectQueue::match_ids( target, fx->Parameter2, fx->Parameter1) ) {
2090 //convert it to a death opcode or apply the new effect?
2091 fx->Opcode = EffectQueue::ResolveEffect(fx_death_ref);
2092 fx->TimingMode = FX_DURATION_INSTANT_PERMANENT;
2093 fx->Parameter1 = 0;
2094 fx->Parameter2 = 4;
2095 return FX_APPLIED;
2097 //doesn't stick
2098 return FX_NOT_APPLIED;
2101 // 0x38 Alignment:Invert
2102 //switch good to evil and evil to good
2103 //also switch chaotic to lawful and vice versa
2104 //gemrb extension: param2 actually controls which parts should be reversed
2105 // 0 - switch both (as original)
2106 // 1 - switch good and evil
2107 // 2 - switch lawful and chaotic
2109 static int al_switch_both[16]={0,0x33,0x32,0x31,0,0x23,0x22,0x21,0,0x13,0x12,0x11};
2110 static int al_switch_law[16]={0,0x31,0x32,0x33,0,0x21,0x22,0x23,0,0x11,0x12,0x13};
2111 static int al_switch_good[16]={0,0x13,0x12,0x11,0,0x23,0x22,0x21,0,0x33,0x32,0x31};
2112 int fx_alignment_invert (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2114 if (0) printf( "fx_alignment_invert (%2d)\n", fx->Opcode );
2115 register ieDword newalign = target->GetStat( IE_ALIGNMENT );
2116 //compress the values. GNE is the first 2 bits originally
2117 //LNC is the 4/5. bits.
2118 newalign = (newalign & AL_GE_MASK) | ((newalign & AL_LC_MASK)>>2);
2119 switch (fx->Parameter2) {
2120 default:
2121 newalign = al_switch_both[newalign];
2122 break;
2123 case 1: //switch good/evil
2124 newalign = al_switch_good[newalign];
2125 break;
2126 case 2:
2127 newalign = al_switch_law[newalign];
2128 break;
2130 STAT_SET( IE_ALIGNMENT, newalign );
2131 return FX_APPLIED;
2134 // 0x39 Alignment:Change
2135 int fx_alignment_change (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2137 if (0) printf( "fx_alignment_change (%2d): Value: %d\n", fx->Opcode, fx->Parameter2 );
2138 STAT_SET( IE_ALIGNMENT, fx->Parameter2 );
2139 return FX_APPLIED;
2142 // 0x3a DispelEffects
2143 int fx_dispel_effects (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2145 if (0) printf( "fx_dispel_effects (%2d): Value: %d, IDS: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2146 ieResRef Removed;
2147 ieDword level;
2149 switch (fx->Parameter2) {
2150 case 0:
2151 default:
2152 level = 0xffffffff;
2153 break;
2154 case 1:
2155 //same level: 50% success, each diff modifies it by 5%
2156 level = core->Roll(1,20,fx->Power-10);
2157 if (level>=0x80000000) level = 0;
2158 break;
2159 case 2:
2160 //same level: 50% success, each diff modifies it by 5%
2161 level = core->Roll(1,20,fx->Parameter1-10);
2162 if (level>=0x80000000) level = 0;
2163 break;
2165 //if signed would it be negative?
2166 target->fxqueue.RemoveLevelEffects(Removed, level, RL_DISPELLABLE, 0);
2167 return FX_NOT_APPLIED;
2170 // 0x3B StealthModifier
2171 int fx_stealth_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2173 if (0) printf( "fx_stealth_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2175 STAT_MOD( IE_STEALTH );
2176 return FX_APPLIED;
2179 // 0x3C MiscastMagicModifier
2180 int fx_miscast_magic_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2182 if (0) printf( "fx_miscast_magic_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2184 switch (fx->Parameter2) {
2185 case 3:
2186 STAT_SET( IE_DEADMAGIC, 1);
2187 case 0:
2188 STAT_SET( IE_SPELLFAILUREMAGE, fx->Parameter1);
2189 break;
2190 case 4:
2191 STAT_SET( IE_DEADMAGIC, 1);
2192 case 1:
2193 STAT_SET( IE_SPELLFAILUREPRIEST, fx->Parameter1);
2194 break;
2195 case 5:
2196 STAT_SET( IE_DEADMAGIC, 1);
2197 case 2:
2198 STAT_SET( IE_SPELLFAILUREINNATE, fx->Parameter1);
2199 break;
2200 default:
2201 return FX_NOT_APPLIED;
2203 return FX_APPLIED;
2206 // 0x3D AlchemyModifier
2207 // this crashes in bg2 due to assertion failure (disabled intentionally)
2208 // and in iwd it doesn't really follow the stat_mod convention (quite lame)
2209 int fx_alchemy_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2211 if (0) printf( "fx_alchemy_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2213 switch(fx->Parameter2) {
2214 case 0:
2215 STAT_ADD( IE_ALCHEMY, fx->Parameter1 );
2216 break;
2217 case 1:
2218 STAT_SET( IE_ALCHEMY, fx->Parameter1 );
2219 break;
2220 case 2:
2221 STAT_SET( IE_ALCHEMY, 100 );
2222 break;
2224 return FX_APPLIED;
2227 // 0x3E PriestSpellSlotsModifier
2228 int fx_bonus_priest_spells (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2230 if (0) printf( "fx_bonus_priest_spells (%2d): Spell Add: %d ; Spell Level: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2232 int i=1;
2233 //if param2 is 0, then double spells up to param1
2234 if(!fx->Parameter2) {
2235 for (unsigned int j=0;j<fx->Parameter1 && j<MAX_SPELL_LEVEL;j++) {
2236 target->spellbook.SetMemorizableSpellsCount(0, IE_SPELL_TYPE_PRIEST, j, true);
2238 return FX_APPLIED;
2241 //HoW specific
2242 //if param2 is 0x200, then double spells at param1
2243 if (fx->Parameter2==0x200) {
2244 unsigned int j = fx->Parameter1-1;
2245 target->spellbook.SetMemorizableSpellsCount(fx->Parameter1, IE_SPELL_TYPE_PRIEST, j, true);
2246 return FX_APPLIED;
2249 for(unsigned int j=0;j<MAX_SPELL_LEVEL;j++) {
2250 if (fx->Parameter2&i) {
2251 target->spellbook.SetMemorizableSpellsCount(fx->Parameter1, IE_SPELL_TYPE_PRIEST, j, true);
2253 i<<=1;
2255 return FX_APPLIED;
2258 // 0x3F State:Infravision
2259 int fx_set_infravision_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2261 if (0) printf( "fx_set_infravision_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2262 STATE_SET( STATE_INFRA );
2263 return FX_APPLIED;
2266 // 0x40 Cure:Infravision
2267 static EffectRef fx_set_infravision_state_ref={"State:Infravision",NULL,-1};
2269 int fx_cure_infravision_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2271 if (0) printf( "fx_cure_infravision_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2272 BASE_STATE_CURE( STATE_INFRA );
2273 target->fxqueue.RemoveAllEffects(fx_set_infravision_state_ref);
2274 return FX_NOT_APPLIED;
2277 // 0x41 State:Blur
2278 int fx_set_blur_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2280 if (0) printf( "fx_set_blur_state (%2d)\n", fx->Opcode );
2281 //death stops this effect
2282 if (STATE_GET( STATE_DEAD) ) {
2283 return FX_NOT_APPLIED;
2285 if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
2286 BASE_STATE_SET( STATE_BLUR );
2287 } else {
2288 STATE_SET( STATE_BLUR );
2290 //iwd2 specific
2291 if (enhanced_effects) {
2292 target->AddPortraitIcon(PI_BLUR);
2294 return FX_PERMANENT;
2297 // 0x42 TransparencyModifier
2298 int fx_transparency_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2300 if (0) printf( "fx_transparency_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2302 //maybe this needs some timing
2303 switch (fx->Parameter2) {
2304 case 1: //fade in
2305 if (fx->Parameter1<255) {
2306 if (core->GetGame()->GameTime%2) {
2307 fx->Parameter1++;
2310 break;
2311 case 2://fade out
2312 if (fx->Parameter1) {
2313 if (core->GetGame()->GameTime%2) {
2314 fx->Parameter1--;
2317 break;
2319 STAT_MOD( IE_TRANSLUCENT );
2320 return FX_APPLIED;
2323 // 0x43 SummonCreature
2325 static int eamods[]={EAM_ALLY,EAM_ALLY,EAM_DEFAULT,EAM_ALLY,EAM_DEFAULT,EAM_ENEMY,EAM_ALLY};
2327 int fx_summon_creature (Scriptable* Owner, Actor* target, Effect* fx)
2329 if (0) printf( "fx_summon_creature (%2d): ResRef:%s Anim:%s Type: %d\n", fx->Opcode, fx->Resource, fx->Resource2, fx->Parameter2 );
2330 if (!target) {
2331 return FX_NOT_APPLIED;
2334 if (!target->GetCurrentArea()) {
2335 return FX_APPLIED;
2338 //summon creature (resource), play vvc (resource2)
2339 //creature's lastsummoner is Owner
2340 //creature's target is target
2341 //position of appearance is target's pos
2342 int eamod = -1;
2343 if (fx->Parameter2<6){
2344 eamod = eamods[fx->Parameter2];
2347 //the monster should appear near the effect position
2348 Point p(fx->PosX, fx->PosY);
2350 Effect *newfx = EffectQueue::CreateUnsummonEffect(fx);
2351 core->SummonCreature(fx->Resource, fx->Resource2, Owner, target, p, eamod, 0, newfx);
2352 delete newfx;
2353 return FX_NOT_APPLIED;
2356 // 0x44 UnsummonCreature
2357 int fx_unsummon_creature (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2359 if (0) printf( "fx_unsummon_creature (%2d)\n", fx->Opcode );
2361 //to be compatible with the original engine, unsummon doesn't work with PC's
2362 //but it works on anything else
2363 if (!target->InParty) {
2364 //play the vanish animation
2365 ScriptedAnimation* sca = gamedata->GetScriptedAnimation(fx->Resource, false);
2366 if (sca) {
2367 sca->XPos+=target->Pos.x;
2368 sca->YPos+=target->Pos.y;
2369 target->GetCurrentArea()->AddVVCell(sca);
2371 //remove the creature
2372 target->DestroySelf();
2374 return FX_NOT_APPLIED;
2377 // 0x45 State:Nondetection
2378 int fx_set_nondetection_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2380 if (0) printf( "fx_set_nondetection_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2381 STATE_SET( STATE_NONDET );
2382 return FX_APPLIED;
2385 // 0x46 Cure:Nondetection
2386 static EffectRef fx_set_nondetection_state_ref={"State:Nondetection",NULL,-1};
2388 int fx_cure_nondetection_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2390 if (0) printf( "fx_cure_nondetection_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2391 BASE_STATE_CURE( STATE_NONDET );
2392 target->fxqueue.RemoveAllEffects(fx_set_nondetection_state_ref);
2393 return FX_NOT_APPLIED;
2396 // 0x47 SexModifier
2397 int fx_sex_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2399 if (0) printf( "fx_sex_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2400 ieDword value;
2401 if (fx->Parameter2) {
2402 value = fx->Parameter1;
2403 } else {
2404 if (STAT_GET(IE_SEX_CHANGED)) {
2405 return FX_NOT_APPLIED;
2407 STAT_SET( IE_SEX_CHANGED, 1);
2408 value = STAT_GET(IE_SEX);
2409 if (value==SEX_MALE) {
2410 value = SEX_FEMALE;
2411 } else {
2412 value = SEX_MALE;
2415 STAT_SET( IE_SEX, value );
2416 return FX_APPLIED;
2419 // 0x48 AIIdentifierModifier
2420 int fx_ids_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2422 if (0) printf( "fx_ids_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2423 switch (fx->Parameter2) {
2424 case 0:
2425 STAT_SET(IE_EA, fx->Parameter1);
2426 break;
2427 case 1:
2428 STAT_SET(IE_GENERAL, fx->Parameter1);
2429 break;
2430 case 2:
2431 STAT_SET(IE_RACE, fx->Parameter1);
2432 break;
2433 case 3:
2434 STAT_SET(IE_CLASS, fx->Parameter1);
2435 break;
2436 case 4:
2437 STAT_SET(IE_SPECIFIC, fx->Parameter1);
2438 break;
2439 case 5:
2440 STAT_SET(IE_SEX, fx->Parameter1);
2441 break;
2442 case 6:
2443 STAT_SET(IE_ALIGNMENT, fx->Parameter1);
2444 break;
2445 default:
2446 return FX_NOT_APPLIED;
2448 //not sure, need a check if this action could be permanent
2449 return FX_APPLIED;
2452 // 0x49 DamageBonusModifier
2453 int fx_damage_bonus_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2455 if (0) printf( "fx_damage_bonus_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2457 STAT_MOD( IE_DAMAGEBONUS );
2458 return FX_APPLIED;
2461 // 0x4a State:Blind
2462 int fx_set_blind_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2464 if (0) printf( "fx_set_blind_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2466 //don't do this effect twice (bug exists in BG2, but fixed in IWD2)
2467 if (!STATE_GET(STATE_BLIND)) {
2468 STATE_SET( STATE_BLIND );
2469 //the feat normally exists only in IWD2, but won't hurt
2470 if (!target->GetFeat(FEAT_BLIND_FIGHT)) {
2471 STAT_SUB (IE_TOHIT, 10); // all other tohit stats are treated as bonuses
2474 return FX_APPLIED;
2477 // 0x4b Cure:Blind
2478 static EffectRef fx_set_blind_state_ref={"State:Blind",NULL,-1};
2480 int fx_cure_blind_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2482 if (0) printf( "fx_cure_blind_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2483 BASE_STATE_CURE( STATE_BLIND );
2484 target->fxqueue.RemoveAllEffects(fx_set_blind_state_ref);
2485 return FX_NOT_APPLIED;
2488 // 0x4c State:Feeblemind
2489 int fx_set_feebleminded_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2491 if (0) printf( "fx_set_feebleminded_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2492 STATE_SET( STATE_FEEBLE );
2493 STAT_SET( IE_INT, 3);
2494 if (enhanced_effects) {
2495 target->AddPortraitIcon(PI_FEEBLEMIND);
2497 return FX_APPLIED;
2500 // 0x4d Cure:Feeblemind
2501 static EffectRef fx_set_feebleminded_state_ref={"State:Feeblemind",NULL,-1};
2503 int fx_cure_feebleminded_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2505 if (0) printf( "fx_cure_feebleminded_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2506 BASE_STATE_CURE( STATE_FEEBLE );
2507 target->fxqueue.RemoveAllEffects(fx_set_feebleminded_state_ref);
2508 target->fxqueue.RemoveAllEffectsWithParam(fx_display_portrait_icon_ref, PI_FEEBLEMIND);
2509 return FX_NOT_APPLIED;
2512 // 0x4e State:Diseased
2513 int fx_set_diseased_state (Scriptable* Owner, Actor* target, Effect* fx)
2515 if (0) printf( "fx_set_diseased_state (%2d): Damage: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2516 if (STATE_GET(STATE_DEAD|STATE_PETRIFIED|STATE_FROZEN) ) {
2517 return FX_NOT_APPLIED;
2520 //setting damage to 0 because not all types do damage
2521 ieDword damage = 0;
2523 HandlePercentageDamage(fx, target);
2525 switch(fx->Parameter2) {
2526 case RPD_SECONDS:
2527 damage = 1;
2528 if (fx->Parameter1 && (core->GetGame()->GameTime%(fx->Parameter1*AI_UPDATE_TIME))) {
2529 return FX_APPLIED;
2531 break;
2532 case RPD_PERCENT: // handled in HandlePercentageDamage
2533 case RPD_POINTS:
2534 damage = fx->Parameter1;
2535 // per second
2536 if (core->GetGame()->GameTime%AI_UPDATE_TIME) {
2537 return FX_APPLIED;
2539 break;
2540 case RPD_STR: //strength
2541 STAT_ADD(IE_STR, fx->Parameter1);
2542 break;
2543 case RPD_DEX: //dex
2544 STAT_ADD(IE_DEX, fx->Parameter1);
2545 break;
2546 case RPD_CON: //con
2547 STAT_ADD(IE_CON, fx->Parameter1);
2548 break;
2549 case RPD_INT: //int
2550 STAT_ADD(IE_INT, fx->Parameter1);
2551 break;
2552 case RPD_WIS: //wis
2553 STAT_ADD(IE_WIS, fx->Parameter1);
2554 break;
2555 case RPD_CHA: //cha
2556 STAT_ADD(IE_CHR, fx->Parameter1);
2557 break;
2558 case RPD_SLOW: //slow
2559 break;
2560 default:
2561 damage = 1;
2562 break;
2564 //percent
2565 Scriptable *caster = GetCaster(Owner, fx);
2567 if (damage) {
2568 target->Damage(damage, DAMAGE_POISON, caster);
2570 return FX_APPLIED;
2574 // 0x4f Cure:Disease
2575 static EffectRef fx_diseased_state_ref={"State:Diseased",NULL,-1};
2577 int fx_cure_diseased_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2579 if (0) printf( "fx_cure_diseased_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2580 //STATE_CURE( STATE_DISEASED ); //the bit flagged as disease is actually the active state. so this is even more unlikely to be used as advertised
2581 target->fxqueue.RemoveAllEffects( fx_diseased_state_ref ); //this is what actually happens in bg2
2582 return FX_NOT_APPLIED;
2585 // 0x50 State:Deafness
2586 // gemrb extension: modifiable amount
2587 // none of the engines care about stacking
2588 int fx_set_deaf_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2590 if (0) printf( "fx_set_deaf_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2592 //gemrb fix
2593 if (target->SetSpellState(SS_DEAF)) return FX_APPLIED;
2595 if (!fx->Parameter1) {
2596 fx->Parameter1 = 50;
2598 STAT_ADD(IE_SPELLFAILUREMAGE, fx->Parameter1);
2599 if (!fx->Parameter2) {
2600 fx->Parameter1 = 50;
2602 STAT_ADD(IE_SPELLFAILUREPRIEST, fx->Parameter2);
2603 EXTSTATE_SET(EXTSTATE_DEAF); //iwd1/how needs this
2604 if (enhanced_effects) {
2605 target->AddPortraitIcon(PI_DEAFNESS);
2607 return FX_APPLIED;
2610 int fx_set_deaf_state_iwd2 (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2612 if (0) printf( "fx_set_deaf_state_iwd2 (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2614 //gemrb fix
2615 if (target->SetSpellState(SS_DEAF)) return FX_APPLIED;
2617 if (!fx->Parameter1) {
2618 //this is a bad hack
2619 fx->Parameter1 = 20;
2621 STAT_ADD(IE_SPELLFAILUREMAGE, fx->Parameter1);
2622 if (!fx->Parameter2) {
2623 fx->Parameter1 = 20;
2625 STAT_ADD(IE_SPELLFAILUREPRIEST, fx->Parameter2);
2626 EXTSTATE_SET(EXTSTATE_DEAF); //iwd1/how needs this
2627 target->AddPortraitIcon(PI_DEAFNESS); //iwd2 specific
2628 return FX_APPLIED;
2631 // 0x51 Cure:Deafness
2632 static EffectRef fx_deaf_state_ref={"State:Deafness",NULL,-1};
2633 static EffectRef fx_deaf_state_iwd2_ref={"State:DeafnessIWD2",NULL,-1};
2635 //removes the deafness effect
2636 int fx_cure_deaf_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2638 if (0) printf( "fx_cure_deaf_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2640 target->fxqueue.RemoveAllEffects(fx_deaf_state_ref);
2641 target->fxqueue.RemoveAllEffects(fx_deaf_state_iwd2_ref);
2642 return FX_NOT_APPLIED;
2645 // 0x52 SetAIScript
2646 int fx_set_ai_script (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2648 if (0) printf( "fx_set_ai_state (%2d): Resource: %s, Type: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
2649 target->SetScript (fx->Resource, fx->Parameter2);
2650 return FX_NOT_APPLIED;
2653 // 0x53 Protection:Projectile
2654 int fx_protection_from_projectile (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2656 if (0) printf( "fx_protection_from_projectile (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
2657 STAT_BIT_OR( IE_IMMUNITY, IMM_PROJECTILE);
2658 return FX_APPLIED;
2661 // 0x54 MagicalFireResistanceModifier
2662 int fx_magical_fire_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2664 if (0) printf( "fx_magical_fire_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2666 STAT_MOD( IE_RESISTMAGICFIRE );
2667 return FX_APPLIED;
2670 // 0x55 MagicalColdResistanceModifier
2671 int fx_magical_cold_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2673 if (0) printf( "fx_magical_cold_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2675 STAT_MOD( IE_RESISTMAGICCOLD );
2676 return FX_APPLIED;
2679 // 0x56 SlashingResistanceModifier
2680 int fx_slashing_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2682 if (0) printf( "fx_slashing_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2684 STAT_MOD( IE_RESISTSLASHING );
2685 return FX_APPLIED;
2688 // 0x57 CrushingResistanceModifier
2689 int fx_crushing_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2691 if (0) printf( "fx_crushing_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2693 STAT_MOD( IE_RESISTCRUSHING );
2694 return FX_APPLIED;
2697 // 0x58 PiercingResistanceModifier
2698 int fx_piercing_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2700 if (0) printf( "fx_piercing_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2702 STAT_MOD( IE_RESISTPIERCING );
2703 return FX_APPLIED;
2706 // 0x59 MissilesResistanceModifier
2707 int fx_missiles_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2709 if (0) printf( "fx_missiles_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2711 STAT_MOD( IE_RESISTMISSILE );
2712 return FX_APPLIED;
2715 // 0x5A OpenLocksModifier
2716 int fx_open_locks_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2718 if (0) printf( "fx_open_locks_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2720 STAT_MOD( IE_LOCKPICKING );
2721 return FX_APPLIED;
2724 // 0x5B FindTrapsModifier
2725 int fx_find_traps_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2727 if (0) printf( "fx_find_traps_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2729 STAT_MOD( IE_TRAPS );
2730 return FX_APPLIED;
2733 // 0x5C PickPocketsModifier
2734 int fx_pick_pockets_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2736 if (0) printf( "fx_pick_pockets_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2738 STAT_MOD( IE_PICKPOCKET );
2739 return FX_APPLIED;
2742 // 0x5D FatigueModifier
2743 int fx_fatigue_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2745 if (0) printf( "fx_fatigue_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2747 STAT_MOD( IE_FATIGUE );
2748 // TODO: fatigue has a negative effect on luck -> add fatigmod.2da support
2749 return FX_APPLIED;
2752 // 0x5E IntoxicationModifier
2753 int fx_intoxication_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2755 if (0) printf( "fx_intoxication_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2757 STAT_MOD( IE_INTOXICATION );
2758 return FX_APPLIED;
2761 // 0x5F TrackingModifier
2762 int fx_tracking_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2764 if (0) printf( "fx_tracking_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2766 STAT_MOD( IE_TRACKING );
2767 return FX_APPLIED;
2770 // 0x60 LevelModifier
2771 int fx_level_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2773 if (0) printf( "fx_level_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2775 STAT_MOD( IE_LEVEL );
2776 return FX_APPLIED;
2779 // 0x61 StrengthBonusModifier
2780 int fx_strength_bonus_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2782 if (0) printf( "fx_strength_bonus_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2784 STAT_MOD( IE_STREXTRA );
2785 return FX_APPLIED;
2788 // 0x62 State:Regenerating
2789 int fx_set_regenerating_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2791 if (0) printf( "fx_set_regenerating_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2792 int damage;
2793 int tmp = fx->Parameter1;
2794 ieDword gameTime = core->GetGame()->GameTime;
2795 ieDword nextHeal;
2797 if (!fx->Parameter3) {
2798 //hack to ensure our first call gets through
2799 nextHeal = gameTime-1;
2800 } else {
2801 nextHeal = fx->Parameter3;
2804 //we can have multiple calls at the same gameTime, so we
2805 //just go to gameTime+1 to ensure one call
2806 if (nextHeal>=gameTime) return FX_APPLIED;
2808 HandlePercentageDamage(fx, target);
2810 switch(fx->Parameter2) {
2811 case RPD_TURNS: //restore param3 hp every param1 turns
2812 tmp *= core->Time.rounds_per_turn;
2813 //fall
2814 case RPD_ROUNDS: //restore param3 hp every param1 rounds
2815 tmp *= core->Time.round_sec;
2816 //fall
2817 case RPD_SECONDS: //restore param3 hp every param1 seconds
2818 fx->Parameter3 = nextHeal + tmp*AI_UPDATE_TIME;
2819 damage = 1;
2820 break;
2821 case RPD_PERCENT: // handled in HandlePercentageDamage
2822 case RPD_POINTS: //restore param1 hp every second? that's crazy!
2823 damage = fx->Parameter1;
2824 fx->Parameter3 = nextHeal + AI_UPDATE_TIME;
2825 break;
2826 default:
2827 fx->Parameter3 = nextHeal + AI_UPDATE_TIME;
2828 damage = 1;
2829 break;
2832 //This should take care of the change of the modified stat
2833 //So there is no need to do anything else here other than increasing
2834 //the base current hp
2835 target->NewBase(IE_HITPOINTS, damage, MOD_ADDITIVE);
2836 return FX_APPLIED;
2838 // 0x63 SpellDurationModifier
2839 int fx_spell_duration_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2841 if (0) printf( "fx_spell_duration_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2843 switch (fx->Parameter2) {
2844 case 0:
2845 STAT_SET( IE_SPELLDURATIONMODMAGE, fx->Parameter1);
2846 break;
2847 case 1:
2848 STAT_SET( IE_SPELLDURATIONMODPRIEST, fx->Parameter1);
2849 break;
2850 default:
2851 return FX_NOT_APPLIED;
2853 return FX_APPLIED;
2855 // 0x64 Protection:Creature
2856 int fx_generic_effect (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
2858 if (0) printf( "fx_generic_effect (%2d): Param1: %d, Param2: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2859 return FX_APPLIED;
2862 // 0x65 Protection:Opcode
2863 int fx_protection_opcode (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2865 if (0) printf( "fx_protection_opcode (%2d): Opcode: %d\n", fx->Opcode, fx->Parameter2 );
2866 STAT_BIT_OR(IE_IMMUNITY, IMM_OPCODE);
2867 return FX_APPLIED;
2870 // 0x66 Protection:SpellLevel
2871 int fx_protection_spelllevel (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2873 if (0) printf( "fx_protection_spelllevel (%2d) Level: %d\n", fx->Opcode, fx->Parameter1);
2875 int value = fx->Parameter1;
2876 if (value<9) {
2877 STAT_BIT_OR(IE_MINORGLOBE, 1<<value);
2878 STAT_BIT_OR(IE_IMMUNITY, IMM_LEVEL);
2879 return FX_APPLIED;
2881 return FX_NOT_APPLIED;
2884 // 0x67 ChangeName
2885 int fx_change_name (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2887 if (0) printf( "fx_change_name_modifier (%2d): StrRef: %d\n", fx->Opcode, fx->Parameter1 );
2888 target->SetName(fx->Parameter1, 0);
2889 return FX_NOT_APPLIED;
2892 // 0x68 ExperienceModifier
2893 int fx_experience_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2895 if (0) printf( "fx_experience_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2896 //i believe this has mode too
2897 target->AddExperience (fx->Parameter1);
2898 return FX_NOT_APPLIED;
2901 // 0x69 GoldModifier
2902 //in BG2 this effect subtracts gold when type is MOD_ADDITIVE
2903 //no one uses it, though. To keep the function, the default branch will do the subtraction
2904 int fx_gold_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2906 if (0) printf( "fx_gold_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2907 if (!target->InParty) {
2908 STAT_MOD( IE_GOLD );
2909 return FX_NOT_APPLIED;
2911 ieDword gold;
2912 Game *game = core->GetGame();
2913 //for party members, the gold is stored in the game object
2914 switch( fx->Parameter2) {
2915 case MOD_ADDITIVE:
2916 gold = fx->Parameter1;
2917 break;
2918 case MOD_ABSOLUTE:
2919 gold = fx->Parameter1-game->PartyGold;
2920 break;
2921 case MOD_PERCENT:
2922 gold = game->PartyGold*fx->Parameter1/100-game->PartyGold;
2923 break;
2924 default:
2925 gold = (ieDword) -fx->Parameter1;
2926 break;
2928 game->AddGold (gold);
2929 return FX_NOT_APPLIED;
2932 // 0x6a MoraleBreakModifier
2933 int fx_morale_break_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2935 if (0) printf( "fx_morale_break_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2936 STAT_MOD(IE_MORALEBREAK);
2937 return FX_PERMANENT; //permanent morale break doesn't stick
2940 // 0x6b PortraitChange
2941 int fx_portrait_change (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2943 if (0) printf( "fx_portrait_change (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2944 target->SetPortrait( fx->Resource, fx->Parameter2);
2945 return FX_NOT_APPLIED;
2948 // 0x6c ReputationModifier
2949 int fx_reputation_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2951 if (0) printf( "fx_reputation_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
2952 STAT_MOD(IE_REPUTATION);
2953 return FX_NOT_APPLIED; //needs testing
2956 // 0x6d --> see later
2958 // 0x6e works only in PST, reused for turning undead
2960 // 0x6f Item:CreateMagic
2962 static EffectRef fx_remove_item_ref={"Item:Remove",NULL,-1};
2964 int fx_create_magic_item (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2966 //charge count is incorrect
2967 target->inventory.SetSlotItemRes(fx->Resource, target->inventory.GetMagicSlot(),fx->Parameter1,fx->Parameter3,fx->Parameter4);
2968 //equip the weapon
2969 target->inventory.SetEquippedSlot(target->inventory.GetMagicSlot()-target->inventory.GetWeaponSlot(), 0);
2970 if ((fx->TimingMode&0xff) == FX_DURATION_INSTANT_LIMITED) {
2971 //if this effect has expiration, then it will remain as a remove_item
2972 //on the effect queue, inheriting all the parameters
2973 fx->Opcode=EffectQueue::ResolveEffect(fx_remove_item_ref);
2974 fx->TimingMode=FX_DURATION_DELAY_PERMANENT;
2975 return FX_APPLIED;
2977 return FX_NOT_APPLIED;
2980 // 0x70 Item:Remove
2981 int fx_remove_item (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2983 //will destroy the first item
2984 if (target->inventory.DestroyItem(fx->Resource,0,1)) {
2985 target->ReinitQuickSlots();
2987 return FX_NOT_APPLIED;
2990 // 0x71 Item:Equip
2991 int fx_equip_item (Scriptable* /*Owner*/, Actor* target, Effect* fx)
2993 int eff = core->QuerySlotEffects( fx->Parameter2 );
2994 switch(eff) {
2995 case SLOT_EFFECT_NONE:
2996 case SLOT_EFFECT_MELEE:
2997 target->inventory.SetEquippedSlot( fx->Parameter2, fx->Parameter1 );
2998 break;
2999 default:
3000 target->inventory.EquipItem( fx->Parameter2 );
3001 break;
3003 target->ReinitQuickSlots();
3004 return FX_NOT_APPLIED;
3007 // 0x72 Dither
3008 int fx_dither (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
3010 if (0) printf( "fx_dither (%2d): Value: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
3011 //this effect doesn't work in any engine versions
3012 return FX_NOT_APPLIED;
3015 // 0x73 DetectAlignment
3016 //gemrb extension: chaotic/lawful detection
3017 int fx_detect_alignment (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3019 ieDword msk;
3020 ieDword stat;
3021 static int ge[] = {AL_EVIL, AL_GE_NEUTRAL, AL_GOOD, AL_CHAOTIC, AL_LC_NEUTRAL, AL_LAWFUL};
3023 msk = ge[fx->Parameter2];
3024 if (fx->Parameter2<3) {
3025 //0,1,2 -> 3,2,1
3026 stat = target->GetStat(IE_ALIGNMENT)&AL_GE_MASK;
3028 else {
3029 //3,4,5 -> 0x30, 0x20, 0x10
3030 stat = target->GetStat(IE_ALIGNMENT)&AL_LC_MASK;
3032 if (stat != msk) return FX_NOT_APPLIED;
3034 ieDword color = fx->Parameter1;
3035 switch (msk) {
3036 case AL_EVIL:
3037 if (!color) color = 0xff0000;
3038 displaymsg->DisplayConstantStringName(STR_EVIL, color, target);
3039 //glow red
3040 target->SetColorMod(0xff, RGBModifier::ADD, 30, 0xff, 0, 0, 0);
3041 break;
3042 case AL_GOOD:
3043 if (!color) color = 0xff00;
3044 displaymsg->DisplayConstantStringName(STR_GOOD, color, target);
3045 //glow green
3046 target->SetColorMod(0xff, RGBModifier::ADD, 30, 0, 0xff, 0, 0);
3047 break;
3048 case AL_GE_NEUTRAL:
3049 if (!color) color = 0xff;
3050 displaymsg->DisplayConstantStringName(STR_GE_NEUTRAL, color, target);
3051 //glow blue
3052 target->SetColorMod(0xff, RGBModifier::ADD, 30, 0, 0, 0xff, 0);
3053 break;
3054 case AL_CHAOTIC:
3055 if (!color) color = 0xff00ff;
3056 displaymsg->DisplayConstantStringName(STR_CHAOTIC, color, target);
3057 //glow purple
3058 target->SetColorMod(0xff, RGBModifier::ADD, 30, 0xff, 0, 0xff, 0);
3059 break;
3060 case AL_LAWFUL:
3061 if (!color) color = 0xffffff;
3062 displaymsg->DisplayConstantStringName(STR_LAWFUL, color, target);
3063 //glow white
3064 target->SetColorMod(0xff, RGBModifier::ADD, 30, 0xff, 0xff, 0xff, 0);
3065 break;
3066 case AL_LC_NEUTRAL:
3067 if (!color) color = 0xff;
3068 displaymsg->DisplayConstantStringName(STR_LC_NEUTRAL, color, target);
3069 //glow blue
3070 target->SetColorMod(0xff, RGBModifier::ADD, 30, 0, 0, 0xff, 0);
3071 break;
3073 return FX_NOT_APPLIED;
3076 // 0x74 Cure:Invisible2 (see 0x2f)
3078 // 0x75 Reveal:Area
3079 // 0 reveal whole area
3080 // 1 reveal area in pattern
3081 int fx_reveal_area (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3083 if (0) printf( "fx_reveal_area (%2d): Value: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
3084 Map *map = target->GetCurrentArea();
3085 if (!map) {
3086 return FX_APPLIED;
3089 if (fx->Parameter2) {
3090 map->Explore(fx->Parameter1);
3091 } else {
3092 map->Explore(-1);
3094 return FX_NOT_APPLIED;
3097 // 0x76 Reveal:Creatures
3098 int fx_reveal_creatures (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
3100 if (0) printf( "fx_reveal_creatures (%2d): Value: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
3101 //reveals creatures (not working in original IE)
3102 return FX_NOT_APPLIED;
3105 // 0x77 MirrorImage
3106 static EffectRef fx_mirror_image_modifier_ref={"MirrorImageModifier",NULL,-1};
3108 int fx_mirror_image (Scriptable* Owner, Actor* target, Effect* fx)
3110 if (0) printf( "fx_mirror_image (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
3111 ieDword images;
3113 if (fx->Parameter2) {
3114 images = 1; //reflection
3116 else {
3117 // the original uses only IE_LEVEL, but that can be awefully bad in
3118 // the case of dual- and multiclasses
3119 unsigned int level = target->GetMageLevel();
3120 if (!level) level = target->GetSorcererLevel();
3121 if (!level) level = target->GetBardLevel();
3122 if (!level) level = target->GetStat(IE_LEVEL);
3123 // 2-8 mirror images
3124 images = level/3 + 2;
3125 if (images > 8) images = 8;
3128 Effect *fx2 = target->fxqueue.HasEffect(fx_mirror_image_modifier_ref);
3129 if (fx2) {
3130 //update old effect with our numbers if our numbers are more
3131 if (fx2->Parameter1<images) {
3132 fx2->Parameter1=images;
3134 if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
3135 fx2->TimingMode = FX_DURATION_INSTANT_PERMANENT;
3137 return FX_NOT_APPLIED;
3139 fx->Opcode = EffectQueue::ResolveEffect(fx_mirror_image_modifier_ref);
3140 fx->Parameter1=images;
3141 //parameter2 could be 0 or 1 (mirror image or reflection)
3142 //execute the translated effect
3143 return fx_mirror_image_modifier(Owner, target, fx);
3146 // 0x78 Protection:Weapons
3147 int fx_immune_to_weapon (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
3149 if (0) printf( "fx_immune_to_weapon (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
3150 if (!fx->FirstApply) return FX_APPLIED;
3152 int level;
3153 ieDword mask, value;
3155 level = -1;
3156 mask = 0;
3157 value = 0;
3158 switch(fx->Parameter2) {
3159 case 0: //enchantment level
3160 level = fx->Parameter1;
3161 break;
3162 case 1: //all magical weapons
3163 value = IE_INV_ITEM_MAGICAL;
3164 //fallthrough
3165 case 2: //all nonmagical weapons
3166 mask = IE_INV_ITEM_MAGICAL;
3167 break;
3168 case 3: //all silver weapons
3169 value = IE_INV_ITEM_SILVER;
3170 //fallthrough
3171 case 4: //all non silver weapons
3172 mask = IE_INV_ITEM_SILVER;
3173 break;
3174 case 5:
3175 value = IE_INV_ITEM_SILVER;
3176 mask = IE_INV_ITEM_SILVER;
3177 level = 0;
3178 break;
3179 case 6: //all twohanded
3180 value = IE_INV_ITEM_TWOHANDED;
3181 //fallthrough
3182 case 7: //all not twohanded
3183 mask = IE_INV_ITEM_TWOHANDED;
3184 break;
3185 case 8: //all twohanded
3186 value = IE_INV_ITEM_CURSED;
3187 //fallthrough
3188 case 9: //all not twohanded
3189 mask = IE_INV_ITEM_CURSED;
3190 break;
3191 case 10: //all twohanded
3192 value = IE_INV_ITEM_COLDIRON;
3193 //fallthrough
3194 case 11: //all not twohanded
3195 mask = IE_INV_ITEM_COLDIRON;
3196 break;
3197 case 12:
3198 mask = fx->Parameter1;
3199 case 13:
3200 value = fx->Parameter1;
3201 break;
3202 default:;
3205 fx->Parameter1 = (ieDword) level; //putting the corrected value back
3206 fx->Parameter3 = mask;
3207 fx->Parameter4 = value;
3208 return FX_APPLIED;
3211 // 0x79 VisualAnimationEffect (unknown)
3212 int fx_visual_animation_effect (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
3214 //this is an unknown effect
3215 if (0) printf( "fx_visual_animation_effect (%2d)\n", fx->Opcode );
3216 return FX_NOT_APPLIED;
3219 // 0x7a Item:CreateInventory
3220 static EffectRef fx_remove_inventory_item_ref={"Item:RemoveInventory",NULL,-1};
3222 int fx_create_inventory_item (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3224 if (0) printf( "fx_create_inventory_item (%2d)\n", fx->Opcode );
3225 target->inventory.AddSlotItemRes( fx->Resource, SLOT_ONLYINVENTORY, fx->Parameter1, fx->Parameter3, fx->Parameter4 );
3226 if ((fx->TimingMode&0xff) == FX_DURATION_INSTANT_LIMITED) {
3227 //if this effect has expiration, then it will remain as a remove_item
3228 //on the effect queue, inheriting all the parameters
3229 fx->Opcode=EffectQueue::ResolveEffect(fx_remove_inventory_item_ref);
3230 fx->TimingMode=FX_DURATION_DELAY_PERMANENT;
3231 return FX_APPLIED;
3233 return FX_NOT_APPLIED;
3236 // 0x7b Item:RemoveInventory
3237 int fx_remove_inventory_item (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3239 if (0) printf( "fx_remove_inventory_item (%2d)\n", fx->Opcode );
3240 //FIXME: now equipped items are only wielded weapons
3241 //why would it not let equipped items to be destructed?
3242 target->inventory.DestroyItem(fx->Resource,IE_INV_ITEM_EQUIPPED,1);
3243 return FX_NOT_APPLIED;
3246 // 0x7c DimensionDoor
3247 // iwd2 has several options
3248 int fx_dimension_door (Scriptable* Owner, Actor* target, Effect* fx)
3250 if (0) printf( "fx_dimension_door (%2d) Type:%d\n", fx->Opcode, fx->Parameter2 );
3251 Point p;
3253 switch(fx->Parameter2)
3255 case 0: //target to point
3256 p.x=fx->PosX;
3257 p.y=fx->PosY;
3258 break;
3259 case 1: //owner to target
3260 if (Owner->Type!=ST_ACTOR) {
3261 return FX_NOT_APPLIED;
3263 p=target->Pos;
3264 target = (Actor *) Owner;
3265 break;
3266 case 2: //target to saved location
3267 p.x=STAT_GET(IE_SAVEDXPOS);
3268 p.x=STAT_GET(IE_SAVEDYPOS);
3269 target->SetOrientation(STAT_GET(IE_SAVEDFACE), false);
3270 break;
3271 case 3: //owner swapped with target
3272 if (Owner->Type!=ST_ACTOR) {
3273 return FX_NOT_APPLIED;
3275 p=target->Pos;
3276 target->SetPosition(Owner->Pos, true, 0);
3277 target = (Actor *) Owner;
3278 break;
3280 target->SetPosition(p, true, 0 );
3281 return FX_NOT_APPLIED;
3284 // 0x7d Unlock
3285 int fx_knock (Scriptable* Owner, Actor* /*target*/, Effect* fx)
3287 if (0) printf( "fx_knock (%2d) [%d.%d]\n", fx->Opcode, fx->PosX, fx->PosY );
3288 Map *map = Owner->GetCurrentArea();
3289 if (!map) {
3290 return FX_NOT_APPLIED;
3292 Point p(fx->PosX, fx->PosY);
3294 printf("KNOCK Pos: %d.%d\n", fx->PosX, fx->PosY);
3295 Door *door = map->TMap->GetDoorByPosition(p);
3296 if (door) {
3297 printf("Got a door\n");
3298 if (door->LockDifficulty<100) {
3299 door->SetDoorLocked(false, true);
3301 return FX_NOT_APPLIED;
3303 Container *container = map->TMap->GetContainerByPosition(p);
3304 if (container) {
3305 printf("Got a container\n");
3306 if(container->LockDifficulty<100) {
3307 container->SetContainerLocked(false);
3309 return FX_NOT_APPLIED;
3311 return FX_NOT_APPLIED;
3314 // 0x7e MovementRateModifier
3315 // 0xb0 MovementRateModifier2
3316 int fx_movement_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3318 if (0) printf( "fx_movement_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
3320 //iwd2 freeaction disables only 0xb0, who cares
3321 if (target->HasSpellState(SS_FREEACTION)) return FX_NOT_APPLIED;
3322 //iwd2 aegis doesn't protect against grease/acid fog slowness, but that is
3323 //definitely a bug
3324 if (target->HasSpellState(SS_AEGIS)) return FX_NOT_APPLIED;
3326 STAT_MOD(IE_MOVEMENTRATE);
3327 return FX_APPLIED;
3330 #define FX_MS 10
3331 static const ieResRef monster_summoning_2da[FX_MS]={"MONSUM01","MONSUM02","MONSUM03",
3332 "ANISUM01","ANISUM02", "MONSUM01", "MONSUM02","MONSUM03","ANISUM01","ANISUM02"};
3334 // 0x7f MonsterSummoning
3335 int fx_monster_summoning (Scriptable* Owner, Actor* target, Effect* fx)
3337 if (0) printf( "fx_monster_summoning (%2d): Number: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
3338 //check the summoning limit?
3339 if (!Owner) {
3340 return FX_NOT_APPLIED;
3343 if (!Owner->GetCurrentArea()) {
3344 return FX_APPLIED;
3347 //get monster resref from 2da determined by fx->Resource or fx->Parameter2
3348 //the only addition to the original engine is that fx->Resource can be
3349 //used to specify a 2da (if parameter2 is >= 10)
3350 ieResRef monster;
3351 ieResRef hit;
3352 ieResRef areahit;
3353 ieResRef table;
3354 int level = fx->Parameter1;
3356 if (fx->Parameter2>=FX_MS) {
3357 if (fx->Resource[0]) {
3358 strnuprcpy(table, fx->Resource, 8);
3359 } else {
3360 strnuprcpy(table, "ANISUM03", 8);
3362 } else {
3363 strnuprcpy(table, monster_summoning_2da[fx->Parameter2], 8);
3365 core->GetResRefFrom2DA(monster_summoning_2da[fx->Parameter2], monster, hit, areahit);
3367 if (!hit[0]) {
3368 strnuprcpy(hit,fx->Resource2,8);
3370 if (!areahit[0]) {
3371 strnuprcpy(areahit,fx->Resource3,8);
3374 //the monster should appear near the effect position
3375 Point p(fx->PosX, fx->PosY);
3377 Effect *newfx = EffectQueue::CreateUnsummonEffect(fx);
3378 //The hostile flag should cover these cases, all else is arbitrary
3379 //0,1,2,3,4 - friendly to target
3380 //5,6,7,8,9 - hostile to target
3381 //10 - friendly to target
3383 int eamod;
3384 if (fx->Parameter2>=5 && fx->Parameter2<=9) {
3385 eamod = EAM_ENEMY;
3387 else {
3388 eamod = EAM_ALLY;
3391 //caster may be important here (Source), even if currently the EA modifiers
3392 //don't use it
3393 Scriptable *caster = GetCaster(Owner, fx);
3394 core->SummonCreature(monster, hit, caster, target, p, eamod, level, newfx);
3395 delete newfx;
3396 return FX_NOT_APPLIED;
3399 // 0x80 State:Confused
3400 int fx_set_confused_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3402 if (0) printf( "fx_set_confused_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
3404 if (target->HasSpellState(SS_BLOODRAGE)) {
3405 return FX_NOT_APPLIED;
3408 if (fx->TimingMode==FX_DURATION_DELAY_PERMANENT) {
3409 BASE_STATE_SET( STATE_CONFUSED );
3410 } else {
3411 STATE_SET( STATE_CONFUSED );
3413 //NOTE: iwd2 is also unable to display the portrait icon
3414 //for permanent confusion
3415 if (enhanced_effects) {
3416 target->AddPortraitIcon(PI_CONFUSED);
3418 return FX_PERMANENT;
3421 // 0x81 AidNonCumulative
3422 int fx_set_aid_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3424 if (0) printf( "fx_set_aid_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
3425 if (!fx->Parameter2) {
3426 fx->Parameter2=core->Roll(fx->Parameter1,8,0);
3428 if (STATE_GET (STATE_AID) ) //aid is non cumulative
3429 return FX_NOT_APPLIED;
3430 STATE_SET( STATE_AID );
3431 target->SetSpellState(SS_AID);
3432 STAT_ADD( IE_MAXHITPOINTS, fx->Parameter2);
3433 //This better happens after increasing maxhitpoints
3434 if (fx->FirstApply) {
3435 BASE_ADD( IE_HITPOINTS, fx->Parameter1);
3437 STAT_ADD( IE_SAVEVSDEATH, fx->Parameter1);
3438 STAT_ADD( IE_SAVEVSWANDS, fx->Parameter1);
3439 STAT_ADD( IE_SAVEVSPOLY, fx->Parameter1);
3440 STAT_ADD( IE_SAVEVSBREATH, fx->Parameter1);
3441 STAT_ADD( IE_SAVEVSSPELL, fx->Parameter1);
3442 //bless effect too?
3443 STAT_ADD( IE_TOHIT, fx->Parameter1);
3444 STAT_ADD( IE_MORALEBREAK, fx->Parameter1);
3445 if (enhanced_effects) {
3446 target->AddPortraitIcon(PI_AID);
3447 target->SetColorMod(0xff, RGBModifier::ADD, 30, 50, 50, 50);
3449 return FX_APPLIED;
3452 // 0x82 BlessNonCumulative
3454 static EffectRef fx_bane_ref={"Bane",NULL,-1};
3456 int fx_set_bless_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3458 if (0) printf( "fx_set_bless_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
3460 if (STATE_GET (STATE_BLESS) ) //bless is non cumulative
3461 return FX_NOT_APPLIED;
3463 //do this once
3464 target->fxqueue.RemoveAllEffects(fx_bane_ref);
3466 STATE_SET( STATE_BLESS );
3467 target->SetSpellState(SS_BLESS);
3468 STAT_ADD( IE_TOHIT, fx->Parameter1);
3469 STAT_ADD( IE_MORALEBREAK, fx->Parameter1);
3470 if (enhanced_effects) {
3471 target->AddPortraitIcon(PI_BLESS);
3472 target->SetColorMod(0xff, RGBModifier::ADD, 30, 0xc0, 0x80, 0);
3474 return FX_APPLIED;
3476 // 0x83 ChantNonCumulative
3477 int fx_set_chant_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3479 if (0) printf( "fx_set_chant_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
3481 if (STATE_GET (STATE_CHANT) ) //chant is non cumulative
3482 return FX_NOT_APPLIED;
3483 STATE_SET( STATE_CHANT );
3484 target->SetSpellState(SS_GOODCHANT);
3485 STAT_ADD( IE_LUCK, fx->Parameter1 );
3486 return FX_APPLIED;
3489 // 0x84 HolyNonCumulative
3490 int fx_set_holy_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3492 if (0) printf( "fx_set_holy_state (%2d): Modifier: %d\n", fx->Opcode, fx->Parameter1 );
3494 if (STATE_GET (STATE_HOLY) ) //holy power is non cumulative
3495 return FX_NOT_APPLIED;
3496 STATE_SET( STATE_HOLY );
3497 //setting the spell state to be compatible with iwd2
3498 target->SetSpellState(SS_HOLYMIGHT);
3499 STAT_ADD( IE_STR, fx->Parameter1);
3500 STAT_ADD( IE_CON, fx->Parameter1);
3501 STAT_ADD( IE_DEX, fx->Parameter1);
3502 if (enhanced_effects) {
3503 target->AddPortraitIcon(PI_HOLY);
3504 target->SetColorMod(0xff, RGBModifier::ADD, 30, 0x80, 0x80, 0x80);
3506 return FX_APPLIED;
3509 // 0x85 LuckNonCumulative
3510 int fx_luck_non_cumulative (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3512 if (0) printf( "fx_luck_non_cumulative (%2d): Modifier: %d\n", fx->Opcode, fx->Parameter1);
3514 if (STATE_GET (STATE_LUCK) ) //this luck is non cumulative
3515 return FX_NOT_APPLIED;
3516 STATE_SET( STATE_LUCK );
3517 target->SetSpellState(SS_LUCK);
3518 STAT_ADD( IE_LUCK, fx->Parameter1 );
3519 STAT_ADD( IE_DAMAGELUCK, fx->Parameter1 );
3520 return FX_APPLIED;
3523 // 0x85 LuckCumulative (iwd2)
3524 int fx_luck_cumulative (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3526 if (0) printf( "fx_luck_cumulative (%2d): Modifier: %d\n", fx->Opcode, fx->Parameter1);
3528 target->SetSpellState(SS_LUCK);
3529 STAT_ADD( IE_LUCK, fx->Parameter1 );
3530 STAT_ADD( IE_DAMAGELUCK, fx->Parameter1 );
3531 return FX_APPLIED;
3534 // 0x86 State:Petrification
3535 int fx_set_petrified_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3537 if (0) printf( "fx_set_petrified_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
3539 BASE_STATE_SET( STATE_PETRIFIED );
3540 return FX_NOT_APPLIED; //permanent effect
3543 // 0x87 Polymorph
3544 static EffectRef fx_polymorph_ref={"Polymorph",NULL,-1};
3546 void CopyPolymorphStats(Actor *source, Actor *target)
3548 int i;
3550 if(!polymorph_stats) {
3551 AutoTable tab("polystat");
3552 if (!tab) {
3553 polymorph_stats = (int *) malloc(0);
3554 polystatcount=0;
3555 return;
3557 polystatcount = tab->GetRowCount();
3558 polymorph_stats=(int *) malloc(sizeof(int)*polystatcount);
3559 for (i=0;i<polystatcount;i++) {
3560 polymorph_stats[i]=core->TranslateStat(tab->QueryField(i,0));
3564 assert(target->polymorphCache);
3566 if (!target->polymorphCache->stats) {
3567 target->polymorphCache->stats = new ieDword[polystatcount];
3570 for(i=0;i<polystatcount;i++) {
3571 target->polymorphCache->stats[i] = source->Modified[polymorph_stats[i]];
3575 int fx_polymorph (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3577 if (0) printf( "fx_set_polymorph_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
3579 if (!gamedata->Exists(fx->Resource,IE_CRE_CLASS_ID)) {
3580 //kill all polymorph effects
3581 target->fxqueue.RemoveAllEffectsWithParam(fx_polymorph_ref, fx->Parameter2);
3582 //destroy the magic item slot
3583 target->inventory.RemoveItem(target->inventory.GetMagicSlot() );
3584 return FX_NOT_APPLIED;
3587 // to avoid repeatedly loading the file or keeping all the data around
3588 // wasting memory, we keep a PolymorphCache object around, with only
3589 // the data we need from the polymorphed creature
3590 bool cached = true;
3591 if (!target->polymorphCache) {
3592 cached = false;
3593 target->polymorphCache = new PolymorphCache();
3595 if (!cached || strnicmp(fx->Resource,target->polymorphCache->Resource,sizeof(fx->Resource))) {
3596 Actor *newCreature = gamedata->GetCreature(fx->Resource,0);
3598 //I don't know how could this happen, existance of the resource was already checked
3599 if (!newCreature) {
3600 return FX_NOT_APPLIED;
3603 memcpy(target->polymorphCache->Resource, fx->Resource, sizeof(fx->Resource));
3604 CopyPolymorphStats(newCreature, target);
3606 delete newCreature;
3609 //copy all polymorphed stats
3610 if(!fx->Parameter2) {
3611 STAT_SET( IE_POLYMORPHED, 1 );
3612 //disable mage and cleric spells (see IE_CASTING doc above)
3613 STAT_BIT_OR(IE_CASTING, 6);
3614 STAT_BIT_OR(IE_DISABLEDBUTTON, (1<<ACT_CAST)|(1<<ACT_QSPELL1)|(1<<ACT_QSPELL2)|(1<<ACT_QSPELL3) );
3617 for(int i=0;i<polystatcount;i++) {
3618 //copy only the animation ID
3619 if (fx->Parameter2 && polymorph_stats[i] != IE_ANIMATION_ID) continue;
3621 target->SetStat(polymorph_stats[i], target->polymorphCache->stats[i], 1);
3624 return FX_APPLIED;
3627 // 0x88 ForceVisible
3628 int fx_force_visible (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3630 if (0) printf( "fx_force_visible (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
3632 if (pstflags) {
3633 BASE_STATE_CURE(STATE_PST_INVIS);
3634 } else {
3635 BASE_STATE_CURE(STATE_INVISIBLE);
3637 target->fxqueue.RemoveAllEffectsWithParam(fx_set_invisible_state_ref,0);
3638 target->fxqueue.RemoveAllEffectsWithParam(fx_set_invisible_state_ref,2);
3639 return FX_NOT_APPLIED;
3642 // 0x89 ChantBadNonCumulative
3643 int fx_set_chantbad_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3645 if (0) printf( "fx_set_chantbad_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
3647 if (STATE_GET (STATE_CHANTBAD) ) //chant is non cumulative
3648 return FX_NOT_APPLIED;
3649 STATE_SET( STATE_CHANTBAD );
3650 target->SetSpellState(SS_BADCHANT);
3651 STAT_SUB( IE_LUCK, fx->Parameter1 );
3652 return FX_APPLIED;
3655 // 0x8A AnimationStateChange
3656 int fx_animation_stance (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3658 if (0) printf( "fx_animation_stance (%2d): Stance: %d\n", fx->Opcode, fx->Parameter2 );
3660 //this effect works only on living actors
3661 if ( !STATE_GET(STATE_DEAD) ) {
3662 target->SetStance(fx->Parameter2);
3664 return FX_NOT_APPLIED;
3667 // 0x8B DisplayString
3668 // gemrb extension: rgb colour for displaystring
3669 static EffectRef fx_protection_from_display_string_ref={"Protection:String",NULL,-1};
3671 int fx_display_string (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3673 if (0) printf( "fx_display_string (%2d): StrRef: %d\n", fx->Opcode, fx->Parameter1 );
3674 if (!target->fxqueue.HasEffectWithParamPair(fx_protection_from_display_string_ref, fx->Parameter1, 0) ) {
3675 displaymsg->DisplayStringName(fx->Parameter1, fx->Parameter2?fx->Parameter2:0xffffff, target, IE_STR_SOUND|IE_STR_SPEECH);
3677 return FX_NOT_APPLIED;
3680 // 0x8c CastingGlow
3681 static const int ypos_by_direction[16]={10,10,10,0,-10,-10,-10,-10,-10,-10,-10,-10,0,10,10,10};
3682 static const int xpos_by_direction[16]={0,-10,-12,-14,-16,-14,-12,-10,0,10,12,14,16,14,12,10};
3684 int fx_casting_glow (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3686 if (0) printf( "fx_casting_glow (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
3687 if (cgcount<0) {
3688 cgcount = core->ReadResRefTable("cgtable",casting_glows);
3690 //remove effect if map is not loaded
3691 Map *map = target->GetCurrentArea();
3692 if (!map) {
3693 return FX_NOT_APPLIED;
3696 if (fx->Parameter2<(ieDword) cgcount) {
3697 ScriptedAnimation *sca = gamedata->GetScriptedAnimation(casting_glows[fx->Parameter2], false);
3698 //remove effect if animation doesn't exist
3699 if (!sca) {
3700 return FX_NOT_APPLIED;
3702 //12 is just an approximate value to set the height of the casting glow
3703 //based on the avatar's size
3704 int heightmod = target->GetAnims()->GetCircleSize()*12;
3705 sca->XPos+=fx->PosX+xpos_by_direction[target->GetOrientation()];
3706 sca->YPos+=fx->PosY+ypos_by_direction[target->GetOrientation()];
3707 sca->ZPos+=heightmod;
3708 sca->SetBlend();
3709 if (fx->Duration) {
3710 sca->SetDefaultDuration(fx->Duration-core->GetGame()->GameTime);
3711 } else {
3712 sca->SetDefaultDuration(10000);
3714 map->AddVVCell(sca);
3716 return FX_NOT_APPLIED;
3719 //0x8d VisualSpellHit
3720 int fx_visual_spell_hit (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3722 if (0) printf( "fx_visual_spell_hit (%2d): Target: %d Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
3723 if (shcount<0) {
3724 shcount = core->ReadResRefTable("shtable",spell_hits);
3726 //remove effect if map is not loaded
3727 Map *map = target->GetCurrentArea();
3728 if (!map) {
3729 return FX_NOT_APPLIED;
3731 if (fx->Parameter2<(ieDword) shcount) {
3732 ScriptedAnimation *sca = gamedata->GetScriptedAnimation(spell_hits[fx->Parameter2], false);
3733 //remove effect if animation doesn't exist
3734 if (!sca) {
3735 return FX_NOT_APPLIED;
3737 if (fx->Parameter1) {
3738 sca->XPos+=target->Pos.x;
3739 sca->YPos+=target->Pos.y;
3740 } else {
3741 sca->XPos+=fx->PosX;
3742 sca->YPos+=fx->PosY;
3744 if (fx->Parameter2<32) {
3745 int tmp = fx->Parameter2>>2;
3746 if (tmp) {
3747 sca->SetFullPalette(tmp);
3750 sca->SetBlend();
3751 sca->PlayOnce();
3752 map->AddVVCell(sca);
3753 } else {
3754 printf("fx_visual_spell_hit: Unhandled Type: %d\n", fx->Parameter2);
3756 return FX_NOT_APPLIED;
3759 //0x8e Icon:Display
3760 int fx_display_portrait_icon (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3762 if (0) printf( "fx_display_string (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
3763 target->AddPortraitIcon(fx->Parameter2);
3764 return FX_APPLIED;
3767 //0x8f Item:CreateInSlot
3768 int fx_create_item_in_slot (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3770 if (0) printf( "fx_create_item_in_slot (%2d): Button: %d\n", fx->Opcode, fx->Parameter2 );
3771 //create item and set it in target's slot
3772 target->inventory.SetSlotItemRes( fx->Resource, core->QuerySlot(fx->Parameter2), fx->Parameter1, fx->Parameter3, fx->Parameter4 );
3773 if ((fx->TimingMode&0xff) == FX_DURATION_INSTANT_LIMITED) {
3774 //convert it to a destroy item
3775 fx->Opcode=EffectQueue::ResolveEffect(fx_remove_item_ref);
3776 fx->TimingMode=FX_DURATION_DELAY_PERMANENT;
3777 return FX_APPLIED;
3779 return FX_NOT_APPLIED;
3782 // 0x90 DisableButton
3783 // different in iwd2 and the rest (maybe also in how: 0-7?)
3784 int fx_disable_button (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3786 if (0) printf( "fx_disable_button (%2d): Button: %d\n", fx->Opcode, fx->Parameter2 );
3788 // iwd2 has a flexible action bar, so there are more possible parameter values
3789 // only values 0-5 match the bg2 constants (which map to ACT_*)
3790 // FIXME: support disabling all iwd2 buttons
3791 if (target->spellbook.IsIWDSpellBook()) {
3792 if (fx->Parameter2 < 6) STAT_BIT_OR( IE_DISABLEDBUTTON, 1<<fx->Parameter2 );
3793 } else {
3794 STAT_BIT_OR( IE_DISABLEDBUTTON, 1<<fx->Parameter2 );
3797 if (fx->FirstApply && target->GetStat(IE_EA) < EA_CONTROLLABLE) {
3798 core->SetEventFlag(EF_ACTION);
3800 return FX_APPLIED;
3803 //0x91 DisableSpellCasting
3804 //bg2: (-1 item), 0 - mage, 1 - cleric, 2 - innate, 3 - class
3805 //iwd2: (-1 item), 0 - all, 1 - mage+cleric, 2 - mage, 3 - cleric , 4 - innate,( 5 - class)
3807 /*internal representation of disabled spells in IE_CASTING (bitfield):
3808 1 - items (SPIT)
3809 2 - cleric (SPPR)
3810 4 - mage (SPWI)
3811 8 - innate (SPIN)
3812 16 - class (SPCL)
3815 static ieDword dsc_bits_iwd2[7]={1, 14, 6, 2, 4, 8, 16};
3816 static ieDword dsc_bits_bg2[7]={1, 4, 2, 8, 16, 14, 6};
3817 int fx_disable_spellcasting (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3819 if (0) printf( "fx_disable_spellcasting (%2d): Button: %d\n", fx->Opcode, fx->Parameter2 );
3821 bool display_warning = false;
3822 ieDword tmp = fx->Parameter2+1;
3824 //IWD2 Style spellbook
3825 if (target->spellbook.IsIWDSpellBook()) {
3826 switch(fx->Parameter2) {
3827 case 0: // all
3828 case 1: // mage and cleric
3829 case 2: // mage
3830 if (target->spellbook.GetKnownSpellsCount(IE_IWD2_SPELL_BARD, 0)) display_warning = true;
3831 if (target->spellbook.GetKnownSpellsCount(IE_IWD2_SPELL_SORCEROR, 0)) display_warning = true;
3832 if (target->spellbook.GetKnownSpellsCount(IE_IWD2_SPELL_WIZARD, 0)) display_warning = true;
3833 break;
3835 if (tmp<7) {
3836 STAT_BIT_OR(IE_CASTING, dsc_bits_iwd2[tmp] );
3838 } else { // bg2
3839 if (fx->Parameter2 == 0) {
3840 if (target->spellbook.GetKnownSpellsCount(IE_SPELL_TYPE_WIZARD, 0)) display_warning = true;
3842 //-1-> 1 (item)
3843 //0 -> 4 (mage)
3844 //1 -> 2 (cleric)
3845 //2 -> 8 (innate)
3846 //3 -> 16 (class)
3847 if (tmp<31) {
3848 STAT_BIT_OR(IE_CASTING, dsc_bits_bg2[tmp] );
3851 if (fx->FirstApply && display_warning && target->GetStat(IE_EA) < EA_CONTROLLABLE) {
3852 displaymsg->DisplayConstantStringName(STR_DISABLEDMAGE, 0xff0000, target);
3853 core->SetEventFlag(EF_ACTION);
3855 return FX_APPLIED;
3858 //0x92 Spell:Cast
3859 int fx_cast_spell (Scriptable* Owner, Actor* target, Effect* fx)
3861 if (0) printf( "fx_cast_spell (%2d): Resource:%s Mode: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
3862 if (fx->Parameter2) {
3863 //apply spell on target
3864 core->ApplySpell(fx->Resource, target, Owner, fx->Power);
3866 // give feedback: Caster - spellname : target
3867 char tmp[100];
3868 Spell *spl = gamedata->GetSpell(fx->Resource);
3869 if (spl) {
3870 snprintf(tmp, sizeof(tmp), "%s : %s", core->GetString(spl->SpellName), target->GetName(-1));
3871 displaymsg->DisplayStringName(tmp, 0xffffff, Owner);
3873 } else {
3874 //cast spell on target
3875 Owner->CastSpell(fx->Resource, target, false);
3876 //actually finish casting (if this is not good enough, use an action???)
3877 Owner->CastSpellEnd(fx->Resource);
3879 return FX_NOT_APPLIED;
3882 // 0x93 Spell:Learn
3883 int fx_learn_spell (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3885 if (0) printf( "fx_learn_spell (%2d): Resource:%s Mode: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
3886 //parameter1 is unused, gemrb lets you to make it not give XP
3887 //probably we should also let this via a game flag if we want
3888 //full compatibility with bg1
3889 target->LearnSpell(fx->Resource, fx->Parameter2^LS_ADDXP);
3890 return FX_NOT_APPLIED;
3892 // 0x94 Spell:CastSpellPoint
3893 int fx_cast_spell_point (Scriptable* Owner, Actor* target, Effect* fx)
3895 if (0) printf( "fx_cast_spell_point (%2d): Resource:%s Mode: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
3896 Owner->CastSpellPoint(fx->Resource, target->Pos, false);
3897 //actually finish casting (if this is not good enough, use an action???)
3898 Owner->CastSpellPointEnd(fx->Resource);
3899 return FX_NOT_APPLIED;
3902 // 0x95 Identify
3903 int fx_identify (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3905 if (0) printf( "fx_identify (%2d): Resource:%s Mode: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
3906 if (target->InParty) {
3907 BASE_SET (IE_IDENTIFYMODE, 1);
3908 core->SetEventFlag(EF_IDENTIFY);
3910 return FX_NOT_APPLIED;
3912 // 0x96 FindTraps
3913 // (actually, in bg2 the effect targets area objects and the range is implemented
3914 // by the inareans projectile) - inanimate, area, no sprite
3915 // TODO: effects should target inanimates using different code
3916 // 0 - detect traps automatically
3917 // 1 - detect traps by skill
3918 // 2 - detect secret doors automatically
3919 // 3 - detect secret doors by luck
3920 int fx_find_traps (Scriptable* /*Owner*/, Actor* target, Effect* fx)
3922 if (0) printf( "fx_find_traps (%2d)\n", fx->Opcode );
3923 //reveal trapped containers, doors, triggers that are in the visible range
3924 ieDword range = target->GetStat(IE_VISUALRANGE)*10;
3925 ieDword skill;
3926 bool detecttraps = true;
3928 switch(fx->Parameter2) {
3929 case 1:
3930 skill = target->GetStat(IE_TRAPS);
3931 break; //find traps
3932 case 3:
3933 //detect secret doors
3934 skill = target->LuckyRoll(1,100,0);
3935 detecttraps = false;
3936 break;
3937 case 2:
3938 detecttraps = false;
3939 default:
3940 //automatic find traps
3941 skill = 256;
3942 break;
3945 TileMap *TMap = target->GetCurrentArea()->TMap;
3947 int Count = 0;
3948 while (true) {
3949 Door* door = TMap->GetDoor( Count++ );
3950 if (!door)
3951 break;
3952 if (Distance(door->Pos, target->Pos)<range) {
3953 if (detecttraps) {
3954 //when was door trap noticed
3955 door->DetectTrap(skill);
3957 door->TryDetectSecret(skill);
3961 if (!detecttraps) {
3962 return FX_NOT_APPLIED;
3965 Count = 0;
3966 while (true) {
3967 Container* container = TMap->GetContainer( Count++ );
3968 if (!container)
3969 break;
3970 if (Distance(container->Pos, target->Pos)<range) {
3971 //when was door trap noticed
3972 container->DetectTrap(skill);
3977 Count = 0;
3978 while (true) {
3979 InfoPoint* trap = TMap->GetInfoPoint( Count++ );
3980 if (!trap)
3981 break;
3982 if (Distance(trap->Pos, target->Pos)<range) {
3983 //when was door trap noticed
3984 trap->DetectTrap(skill);
3988 return FX_NOT_APPLIED;
3991 // 0x97 ReplaceCreature
3992 int fx_replace_creature (Scriptable* Owner, Actor* target, Effect *fx)
3994 if (0) printf( "fx_replace_creature (%2d): Resource: %s\n", fx->Opcode, fx->Resource );
3996 //this safeguard exists in the original engine too
3997 if (!gamedata->Exists(fx->Resource,IE_CRE_CLASS_ID)) {
3998 return FX_NOT_APPLIED;
4001 //the monster should appear near the effect position? (unsure)
4002 Point p(fx->PosX, fx->PosY);
4004 //remove old creature
4005 switch(fx->Parameter2) {
4006 case 0: //remove silently
4007 target->DestroySelf();
4008 break;
4009 case 1: //chunky death
4010 target->NewBase(IE_HITPOINTS,(ieDword) -100, MOD_ABSOLUTE);
4011 target->Die(Owner);
4012 break;
4013 case 2: //normal death
4014 target->Die(Owner);
4015 break;
4016 default:;
4018 //create replacement; should we be passing the target instead of NULL?
4019 //noooo, don't unsummon replacement creatures! - fuzzie
4020 //Effect *newfx = EffectQueue::CreateUnsummonEffect(fx);
4021 core->SummonCreature(fx->Resource, fx->Resource2, Owner, NULL,p, EAM_DEFAULT,-1, NULL, 0);
4022 //delete newfx;
4023 return FX_NOT_APPLIED;
4026 // 0x98 PlayMovie
4027 int fx_play_movie (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
4029 if (0) printf( "fx_play_movie (%2d): Resource: %s\n", fx->Opcode, fx->Resource );
4030 core->PlayMovie (fx->Resource);
4031 return FX_NOT_APPLIED;
4033 // 0x99 Overlay:Sanctuary
4034 #define ICE_GRADIENT 71
4036 static const ieDword fullwhite[7]={ICE_GRADIENT,ICE_GRADIENT,ICE_GRADIENT,ICE_GRADIENT,ICE_GRADIENT,ICE_GRADIENT,ICE_GRADIENT};
4038 int fx_set_sanctuary_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4040 //iwd and bg are a bit different, but we solve the whole stuff in a single opcode
4041 if (0) printf( "fx_set_sanctuary_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4042 if (target->HasSpellState(SS_SANCTUARY)) return FX_NOT_APPLIED;
4043 if (!fx->Parameter2) {
4044 fx->Parameter2=1;
4046 //this effect needs the pcf run immediately
4047 STAT_SET_PCF( IE_SANCTUARY, fx->Parameter2);
4048 //a rare event, but this effect gives more in bg2 than in iwd2
4049 //so we use this flag
4050 if (!enhanced_effects)
4052 target->SetLockedPalette(fullwhite);
4054 return FX_APPLIED;
4057 // 0x9a Overlay:Entangle
4058 int fx_set_entangle_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4060 if (0) printf( "fx_set_entangle_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4062 //iwd2 effects that disable entangle
4063 if (target->HasSpellState(SS_FREEACTION)) return FX_NOT_APPLIED;
4064 if (target->HasSpellState(SS_AEGIS)) return FX_NOT_APPLIED;
4066 if (!fx->Parameter2) {
4067 fx->Parameter2=1;
4069 STAT_SET_PCF( IE_ENTANGLE, fx->Parameter2);
4070 return FX_APPLIED;
4073 // 0x9b Overlay:MinorGlobe
4074 int fx_set_minorglobe_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4076 if (0) printf( "fx_set_minorglobe_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4077 //the resisted levels are stored in minor globe (bit 2-)
4078 //the globe effect is stored in the first bit
4079 STAT_BIT_OR_PCF( IE_MINORGLOBE, 1);
4080 return FX_APPLIED;
4083 // 0x9c Overlay:ShieldGlobe
4084 int fx_set_shieldglobe_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4086 if (0) printf( "fx_set_shieldglobe_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4087 //the shield vanishes on dead
4088 if (STATE_GET(STATE_DEAD) ) {
4089 return FX_NOT_APPLIED;
4091 STAT_SET_PCF( IE_SHIELDGLOBE, 1);
4092 return FX_APPLIED;
4095 // 0x9d Overlay:Web
4096 int fx_set_web_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4098 if (0) printf( "fx_set_web_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4100 //iwd2 effects that disable web
4101 if (target->HasSpellState(SS_FREEACTION)) return FX_NOT_APPLIED;
4102 if (target->HasSpellState(SS_AEGIS)) return FX_NOT_APPLIED;
4104 target->SetSpellState(SS_WEB);
4105 //attack penalty in IWD2
4106 STAT_SET_PCF( IE_WEB, 1);
4107 STAT_SET(IE_MOVEMENTRATE, 0); //
4108 return FX_APPLIED;
4111 // 0x9e Overlay:Grease
4112 int fx_set_grease_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4114 if (0) printf( "fx_set_grease_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4116 //iwd2 effects that disable grease
4117 if (target->HasSpellState(SS_FREEACTION)) return FX_NOT_APPLIED;
4118 if (target->HasSpellState(SS_AEGIS)) return FX_NOT_APPLIED;
4120 target->SetSpellState(SS_GREASE);
4121 STAT_SET_PCF( IE_GREASE, 1);
4122 //the movement rate is set by separate opcodes in all engines
4123 return FX_APPLIED;
4126 // 0x9f MirrorImageModifier
4127 int fx_mirror_image_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4129 if (0) printf( "fx_mirror_image_modifier (%2d): Mod: %d\n", fx->Opcode, fx->Parameter1 );
4130 if (STATE_GET(STATE_DEAD) ) {
4131 return FX_NOT_APPLIED;
4133 if (!fx->Parameter1) {
4134 return FX_NOT_APPLIED;
4136 if (pstflags) {
4137 STATE_SET( STATE_PST_MIRROR );
4139 else {
4140 STATE_SET( STATE_MIRROR );
4142 if (fx->Parameter2) {
4143 target->SetSpellState(SS_REFLECTION);
4144 } else {
4145 target->SetSpellState(SS_MIRRORIMAGE);
4147 //actually, there is no such stat in the original IE
4148 STAT_SET( IE_MIRRORIMAGES, fx->Parameter1);
4149 return FX_APPLIED;
4152 // 0xa0 Cure:Sanctuary
4153 static EffectRef fx_sanctuary_state_ref={"Overlay:Sanctuary",NULL,-1};
4155 int fx_cure_sanctuary_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4157 if (0) printf( "fx_cure_sanctuary_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4158 STAT_SET( IE_SANCTUARY, 0);
4159 target->fxqueue.RemoveAllEffects(fx_sanctuary_state_ref);
4160 return FX_NOT_APPLIED;
4163 // 0xa1 Cure:Panic
4164 static EffectRef fx_set_panic_state_ref={"State:Panic",NULL,-1};
4166 int fx_cure_panic_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4168 if (0) printf( "fx_cure_panic_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4169 BASE_STATE_CURE( STATE_PANIC );
4170 target->fxqueue.RemoveAllEffects(fx_set_panic_state_ref);
4171 return FX_NOT_APPLIED;
4174 // 0xa2 Cure:Hold
4175 static EffectRef fx_hold_creature_ref={"State:Hold",NULL,-1};
4177 int fx_cure_hold_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4179 if (0) printf( "fx_cure_hold_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4180 //note that this effect doesn't remove 185 (another hold effect)
4181 target->fxqueue.RemoveAllEffects( fx_hold_creature_ref );
4182 target->fxqueue.RemoveAllEffects(fx_hold_creature_no_icon_ref);
4183 target->fxqueue.RemoveAllEffectsWithParam(fx_display_portrait_icon_ref, PI_HELD);
4184 return FX_NOT_APPLIED;
4187 // 0xa3 FreeAction
4188 static EffectRef fx_movement_modifier_ref={"MovementRateModifier2",NULL,-1};
4190 int fx_cure_slow_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4192 if (0) printf( "fx_cure_slow_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4193 target->fxqueue.RemoveAllEffects( fx_movement_modifier_ref );
4194 // STATE_CURE( STATE_SLOWED );
4195 return FX_NOT_APPLIED;
4198 // 0xa4 Cure:Intoxication
4199 static EffectRef fx_intoxication_ref={"IntoxicationModifier",NULL,-1};
4201 int fx_cure_intoxication (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4203 if (0) printf( "fx_cure_intoxication (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4204 target->fxqueue.RemoveAllEffects( fx_intoxication_ref );
4205 BASE_SET(IE_INTOXICATION,0);
4206 return FX_NOT_APPLIED;
4209 // 0xa5 PauseTarget
4210 int fx_pause_target (Scriptable* /*Owner*/, Actor * target, Effect* fx)
4212 if (0) printf( "fx_pause_target (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4214 STAT_MOD( IE_CASTERHOLD );
4215 return FX_PERMANENT;
4218 // 0xa6 MagicResistanceModifier
4219 int fx_magic_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4221 if (0) printf( "fx_magic_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4223 STAT_MOD( IE_RESISTMAGIC );
4224 return FX_APPLIED;
4227 // 0xa7 MissileHitModifier
4228 int fx_missile_to_hit_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4230 if (0) printf( "fx_missile_to_hit_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4232 STAT_MOD( IE_MISSILEHITBONUS );
4233 return FX_APPLIED;
4236 // 0xa8 RemoveCreature
4237 // removes targeted creature
4238 // removes creature specified by resource key (gemrb extension)
4239 int fx_remove_creature (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4241 if (0) printf( "fx_remove_creature (%2d)\n", fx->Opcode);
4242 Map *map = target->GetCurrentArea();
4243 Actor *actor = target;
4245 if (fx->Resource[0]) {
4246 actor = map->GetActorByResource(fx->Resource);
4249 if (actor) {
4250 //leaveparty will be handled automagically
4251 //plot critical items are not handled, shall we?
4252 actor->DestroySelf();
4254 return FX_NOT_APPLIED;
4257 // 0xa9 Icon:Disable
4258 int fx_disable_portrait_icon (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4260 if (0) printf( "fx_disable_portrait_icon (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4261 target->DisablePortraitIcon(fx->Parameter2);
4262 return FX_APPLIED;
4265 // 0xaa DamageAnimation
4266 int fx_damage_animation (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4268 if (0) printf( "fx_damage_animation (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4270 //Parameter1 is a gemrb extension
4271 target->PlayDamageAnimation(fx->Parameter2, !fx->Parameter1);
4272 return FX_NOT_APPLIED;
4275 // 0xab Spell:Add
4276 int fx_add_innate (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4278 if (0) printf( "fx_add_innate (%2d): Resource: %s Mode: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
4279 target->LearnSpell(fx->Resource, fx->Parameter2^LS_MEMO);
4280 //this is an instant, so it shouldn't stick
4281 return FX_NOT_APPLIED;
4284 // 0xac Spell:Remove
4285 //gemrb extension: deplete spell by resref
4286 int fx_remove_spell (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4288 if (0) printf( "fx_remove_spell (%2d): Resource: %s Type:%d\n", fx->Opcode, fx->Resource, fx->Parameter2);
4289 switch (fx->Parameter2) {
4290 default:
4291 target->spellbook.RemoveSpell(fx->Resource);
4292 break;
4293 case 1: //forget all spells of Resource
4294 do {} while(target->spellbook.HaveSpell( fx->Resource, HS_DEPLETE ));
4295 break;
4296 case 2: //forget x spells of resource
4297 while( fx->Parameter1--) {
4298 target->spellbook.HaveSpell( fx->Resource, HS_DEPLETE );
4300 break;
4302 //this is an instant, so it shouldn't stick
4303 return FX_NOT_APPLIED;
4306 // 0xad PoisonResistanceModifier
4307 int fx_poison_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4309 if (0) printf( "fx_poison_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4311 STAT_MOD( IE_RESISTPOISON );
4312 return FX_APPLIED;
4315 //0xae PlaySound
4316 int fx_playsound (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4318 if (0) printf( "fx_playsound (%s)", fx->Resource );
4319 //this is probably inaccurate
4320 if (target) {
4321 core->GetAudioDrv()->Play(fx->Resource, target->Pos.x, target->Pos.y);
4322 } else {
4323 core->GetAudioDrv()->Play(fx->Resource);
4325 //this is an instant, it shouldn't stick
4326 return FX_NOT_APPLIED;
4329 //0x6d State:Hold3
4330 //0xfb State:Hold4
4331 int fx_hold_creature_no_icon (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4333 if (0) printf( "fx_hold_creature_no_icon (%2d): Value: %d, IDS: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4335 //actually the original engine just skips this effect if the target is dead
4336 if ( STATE_GET(STATE_DEAD) ) {
4337 return FX_NOT_APPLIED;
4340 if (!EffectQueue::match_ids( target, fx->Parameter2, fx->Parameter1) ) {
4341 //if the ids don't match, the effect doesn't stick
4342 return FX_NOT_APPLIED;
4344 target->SetSpellState(SS_HELD);
4345 STAT_SET( IE_HELD, 1);
4346 return FX_APPLIED;
4349 //0xaf State:Hold
4350 //0xb9 State:Hold2
4351 //(0x6d/0x1a8 for iwd2)
4352 int fx_hold_creature (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4354 if (0) printf( "fx_hold_creature (%2d): Value: %d, IDS: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4356 //actually the original engine just skips this effect if the target is dead
4357 if ( STATE_GET(STATE_DEAD) ) {
4358 return FX_NOT_APPLIED;
4361 //iwd2 free action or blood rage disables this effect
4362 if (target->HasSpellState(SS_FREEACTION)) return FX_NOT_APPLIED;
4363 if (target->HasSpellState(SS_BLOODRAGE)) return FX_NOT_APPLIED;
4364 if (target->HasSpellState(SS_AEGIS)) return FX_NOT_APPLIED;
4366 if (!EffectQueue::match_ids( target, fx->Parameter2, fx->Parameter1) ) {
4367 //if the ids don't match, the effect doesn't stick
4368 return FX_NOT_APPLIED;
4370 target->SetSpellState(SS_HELD);
4371 STAT_SET( IE_HELD, 1);
4372 target->AddPortraitIcon(PI_HELD);
4373 return FX_APPLIED;
4375 //0xb0 see: fx_movement_modifier
4377 //0xb1 ApplyEffect
4378 int fx_apply_effect (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4380 if (0) printf( "fx_apply_effect (%2d) %s", fx->Opcode, fx->Resource );
4382 //this effect executes a file effect in place of this effect
4383 //the file effect inherits the target and the timingmode, but gets
4384 //a new chance to roll percents
4385 int ret = FX_NOT_APPLIED;
4386 if (!target) {
4387 return ret;
4389 if (EffectQueue::match_ids( target, fx->Parameter2, fx->Parameter1) ) {
4390 Point p(fx->PosX, fx->PosY);
4392 //apply effect, if the effect is a goner, then kill
4393 //this effect too
4394 Effect *newfx = core->GetEffect(fx->Resource, fx->Power, p);
4395 if (newfx) {
4396 Effect *myfx = new Effect;
4397 memcpy(myfx, newfx, sizeof(Effect));
4398 myfx->random_value = core->Roll(1,100,-1);
4399 myfx->Target = FX_TARGET_PRESET;
4400 myfx->TimingMode = fx->TimingMode;
4401 myfx->Duration = fx->Duration;
4402 myfx->CasterID = fx->CasterID;
4403 ret = target->fxqueue.ApplyEffect(target, myfx, fx->FirstApply, !fx->Parameter3);
4404 fx->Parameter3 = 1;
4405 delete myfx;
4407 //newfx is a borrowed reference don't delete it
4409 return ret;
4412 //0xb2 hitbonus generic effect ToHitVsCreature
4413 //0xb3 damagebonus generic effect DamageVsCreature
4414 // b4 can't use item (resource) generic effect CantUseItem
4415 // b5 can't use itemtype (resource) generic effect CantUseItemType
4417 // b6 generic effect ApplyEffectItem
4418 int fx_apply_effect_item (Scriptable* Owner, Actor* target, Effect* fx)
4420 if (0) printf("fx_apply_effect_item (%2d) (%.8s)\n", fx->Opcode, fx->Resource);
4421 if (target->inventory.HasItem(fx->Resource, 0) ) {
4422 core->ApplySpell(fx->Resource2, target, Owner, fx->Parameter1);
4423 return FX_NOT_APPLIED;
4425 return FX_APPLIED;
4428 // b7 generic effect ApplyEffectItemType
4429 int fx_apply_effect_item_type (Scriptable* Owner, Actor* target, Effect* fx)
4431 if (0) printf("fx_apply_effect_item (%2d), Type: %d\n", fx->Opcode, fx->Parameter2);
4432 if (target->inventory.HasItemType(fx->Parameter2) ) {
4433 core->ApplySpell(fx->Resource, target, Owner, fx->Parameter1);
4434 return FX_NOT_APPLIED;
4436 return FX_APPLIED;
4439 // b8 DontJumpModifier
4440 int fx_dontjump_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4442 if (0) printf( "fx_dontjump_modifier (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4443 STAT_SET( IE_DONOTJUMP, fx->Parameter2 );
4444 return FX_APPLIED;
4447 //0xb9 see above: fx_hold_creature
4449 //0xba MoveToArea
4450 int fx_move_to_area (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4452 if (0) printf( "fx_move_to_area (%2d) %s", fx->Opcode, fx->Resource );
4453 //delay effect until the target has finished the previous move to an area
4454 //hopefully this fixes an evil bug
4455 Map *map = target->GetCurrentArea();
4456 if (!map || !map->HasActor(target)) {
4457 //stay around for the next evaluation
4458 return FX_APPLIED;
4460 Point p(fx->PosX,fx->PosY);
4461 MoveBetweenAreasCore(target, fx->Resource, p, fx->Parameter2, true);
4462 //this effect doesn't stick
4463 return FX_NOT_APPLIED;
4466 // 0xbb Variable:StoreLocalVariable
4467 int fx_local_variable (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4469 //this is a hack, the variable name spreads across the resources
4470 if (0) printf( "fx_local_variable (%2d) %s=%d", fx->Opcode, fx->Resource, fx->Parameter1 );
4471 target->locals->SetAt(fx->Resource, fx->Parameter1);
4472 //local variable effects are not applied, they will be resaved though
4473 return FX_NOT_APPLIED;
4476 // 0xbc AuraCleansingModifier
4477 int fx_auracleansing_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4479 if (0) printf( "fx_auracleansing_modifier (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4480 STAT_SET( IE_AURACLEANSING, fx->Parameter2 );
4481 return FX_APPLIED;
4484 // 0xbd CastingSpeedModifier
4485 int fx_castingspeed_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4487 if (0) printf( "fx_castingspeed_modifier (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4488 STAT_MOD( IE_MENTALSPEED );
4489 return FX_APPLIED;
4492 // 0xbe PhysicalSpeedModifier
4493 int fx_attackspeed_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4495 if (0) printf( "fx_attackspeed_modifier (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4496 STAT_MOD( IE_PHYSICALSPEED );
4497 return FX_APPLIED;
4500 // 0xbf CastingLevelModifier
4501 int fx_castinglevel_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4503 if (0) printf( "fx_castinglevel_modifier (%2d) Value:%d Type:%d", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4504 switch (fx->Parameter2) {
4505 case 0:
4506 STAT_SET( IE_CASTINGLEVELBONUSMAGE, fx->Parameter1 );
4507 break;
4508 case 1:
4509 STAT_SET( IE_CASTINGLEVELBONUSCLERIC, fx->Parameter1 );
4510 break;
4511 default:
4512 return FX_NOT_APPLIED;
4514 return FX_APPLIED;
4517 // 0xc0 FindFamiliar
4518 // param2 = 1 alignment is in param1
4519 // param2 = 2 resource used
4520 #define FAMILIAR_NORMAL 0
4521 #define FAMILIAR_ALIGNMENT 1
4522 #define FAMILIAR_RESOURCE 2
4524 static EffectRef fx_familiar_constitution_loss_ref={"FamiliarBond",NULL,-1};
4525 static EffectRef fx_familiar_marker_ref={"FamiliarMarker",NULL,-1};
4526 static EffectRef fx_maximum_hp_modifier_ref={"MaximumHPModifier",NULL,-1};
4528 int fx_find_familiar (Scriptable* Owner, Actor* target, Effect* fx)
4530 if (0) printf( "fx_find_familiar (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4532 if (!target) {
4533 return FX_NOT_APPLIED;
4536 if (!target->GetCurrentArea()) {
4537 return FX_APPLIED;
4540 if (fx->Parameter2!=FAMILIAR_RESOURCE) {
4541 ieDword alignment;
4543 if (fx->Parameter2==FAMILIAR_ALIGNMENT) {
4544 alignment = fx->Parameter1;
4545 } else {
4546 alignment = target->GetStat(IE_ALIGNMENT);
4547 alignment = ((alignment&AL_LC_MASK)>>4)*3+(alignment&AL_GE_MASK)-4;
4549 if (alignment>8) {
4550 return FX_NOT_APPLIED;
4552 memcpy(fx->Resource, core->GetGame()->Familiars[alignment],sizeof(ieResRef) );
4553 fx->Parameter2=FAMILIAR_RESOURCE;
4556 //summon familiar with fx->Resource
4557 Actor *fam = gamedata->GetCreature(fx->Resource);
4558 if (!fam) {
4559 return FX_NOT_APPLIED;
4561 fam->SetBase(IE_EA, EA_FAMILIAR);
4562 fam->LastSummoner = Owner->GetGlobalID();
4564 Map *map = target->GetCurrentArea();
4565 map->AddActor(fam);
4566 Point p(fx->PosX, fx->PosY);
4567 fam->SetPosition(p, true, 0);
4568 fam->RefreshEffects(NULL);
4570 if (fx->Resource2[0]) {
4571 ScriptedAnimation* vvc = gamedata->GetScriptedAnimation(fx->Resource2, false);
4572 if (vvc) {
4573 //This is the final position of the summoned creature
4574 //not the original target point
4575 vvc->XPos=fam->Pos.x;
4576 vvc->YPos=fam->Pos.y;
4577 //force vvc to play only once
4578 vvc->PlayOnce();
4579 map->AddVVCell( vvc );
4583 //Make the familiar an NPC (MoveGlobal needs this)
4584 core->GetGame()->AddNPC(fam);
4586 //Add some essential effects
4587 Effect *newfx = EffectQueue::CreateEffect(fx_familiar_constitution_loss_ref, fam->GetBase(IE_HITPOINTS)/2, 0, FX_DURATION_INSTANT_PERMANENT);
4588 core->ApplyEffect(newfx, fam, fam);
4589 delete newfx;
4591 newfx = EffectQueue::CreateEffect(fx_familiar_marker_ref, 0, 0, FX_DURATION_INSTANT_PERMANENT);
4592 core->ApplyEffect(newfx, fam, fam);
4593 delete newfx;
4595 //maximum hp bonus of half the familiar's hp
4596 newfx = EffectQueue::CreateEffect(fx_maximum_hp_modifier_ref, fam->GetBase(IE_HITPOINTS)/2, MOD_ADDITIVE, FX_DURATION_INSTANT_PERMANENT);
4597 core->ApplyEffect(newfx, (Actor *) Owner, Owner);
4598 delete newfx;
4600 return FX_NOT_APPLIED;
4603 // 0xc1 InvisibleDetection
4604 int fx_see_invisible_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4606 if (0) printf( "fx_see_invisible_modifier (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4607 STAT_SET( IE_SEEINVISIBLE, fx->Parameter2 );
4608 return FX_APPLIED;
4611 // 0xc2 IgnoreDialogPause
4612 int fx_ignore_dialogpause_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4614 if (0) printf( "fx_ignore_dialogpause_modifier (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4615 STAT_SET( IE_IGNOREDIALOGPAUSE, fx->Parameter2 );
4616 return FX_APPLIED;
4619 //0xc3 FamiliarBond
4620 //when this effect's target dies it should incur damage on protagonist
4621 static EffectRef fx_damage_opcode_ref={"Damage",NULL,-1};
4622 static EffectRef fx_constitution_modifier_ref={"ConstitutionModifier",NULL,-1};
4624 int fx_familiar_constitution_loss (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4626 if (0) printf( "fx_familiar_constitution_loss (%2d): Loss: %d\n", fx->Opcode,(signed) fx->Parameter1 );
4627 if (! (STAT_GET(IE_STATE_ID)&STATE_NOSAVE)) {
4628 return FX_APPLIED;
4630 Effect *newfx;
4631 //familiar died
4632 Actor *master = core->GetGame()->FindPC(1);
4633 if (!master) return FX_NOT_APPLIED;
4635 //lose 1 point of constitution
4636 newfx = EffectQueue::CreateEffect(fx_constitution_modifier_ref, (ieDword) -1, MOD_ADDITIVE, FX_DURATION_INSTANT_PERMANENT);
4637 core->ApplyEffect(newfx, master, master);
4638 delete newfx;
4640 //remove the maximum hp bonus
4641 newfx = EffectQueue::CreateEffect(fx_maximum_hp_modifier_ref, (ieDword) -fx->Parameter1, 3, FX_DURATION_INSTANT_PERMANENT);
4642 core->ApplyEffect(newfx, master, master);
4643 delete newfx;
4645 //damage for half of the familiar's hitpoints
4646 newfx = EffectQueue::CreateEffect(fx_damage_opcode_ref, fx->Parameter1, DAMAGE_CRUSHING, FX_DURATION_INSTANT_PERMANENT);
4647 core->ApplyEffect(newfx, master, master);
4648 delete newfx;
4650 return FX_NOT_APPLIED;
4653 //0xc4 FamiliarMarker
4654 int fx_familiar_marker (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4656 if (0) printf( "fx_familiar_marker (%2d)\n", fx->Opcode );
4657 if (! (STAT_GET(IE_STATE_ID)&STATE_NOSAVE)) {
4658 //TODO: where to disable familiar?
4659 //core->GetGame()->WeatherBits|=1;
4660 return FX_APPLIED;
4662 //TODO: enable familiar?
4663 //core->GetGame()->WeatherBits&=~1;
4664 return FX_NOT_APPLIED;
4667 // 0xc5 Bounce:Projectile
4668 int fx_bounce_projectile (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4670 if (0) printf( "fx_bounce_projectile (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4671 STAT_BIT_OR( IE_BOUNCE, BNC_PROJECTILE );
4672 return FX_APPLIED;
4675 // 0xc6 Bounce:Opcode
4676 int fx_bounce_opcode (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4678 if (0) printf( "fx_bounce_opcode (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4679 STAT_BIT_OR( IE_BOUNCE, BNC_OPCODE );
4680 target->AddPortraitIcon(PI_BOUNCE2);
4681 return FX_APPLIED;
4684 // 0xc7 Bounce:SpellLevel
4685 int fx_bounce_spelllevel (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4687 if (0) printf( "fx_bounce_spellevel (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4688 STAT_BIT_OR( IE_BOUNCE, BNC_LEVEL );
4689 target->AddPortraitIcon(PI_BOUNCE2);
4690 return FX_APPLIED;
4693 // 0xc8 Bounce:SpellLevelDec
4694 int fx_bounce_spelllevel_dec (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4696 if (0) printf( "fx_bounce_spellevel_dec (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4697 STAT_BIT_OR( IE_BOUNCE, BNC_LEVEL_DEC );
4698 target->AddPortraitIcon(PI_BOUNCE);
4699 return FX_APPLIED;
4702 //0xc9 Protection:SpellLevelDec
4703 int fx_protection_spelllevel_dec (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4705 if (0) printf( "fx_protection_spelllevel_dec (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4706 STAT_BIT_OR( IE_IMMUNITY, IMM_LEVEL_DEC );
4707 target->AddPortraitIcon(PI_BOUNCE2);
4708 return FX_APPLIED;
4711 //0xca Bounce:School
4712 int fx_bounce_school (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4714 if (0) printf( "fx_bounce_school (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4715 STAT_BIT_OR( IE_BOUNCE, BNC_SCHOOL );
4716 target->AddPortraitIcon(PI_BOUNCE2);
4717 return FX_APPLIED;
4720 // 0xcb Bounce:SecondaryType
4721 int fx_bounce_secondary_type (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4723 if (0) printf( "fx_bounce_secondary_type (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4724 STAT_BIT_OR( IE_BOUNCE, BNC_SECTYPE );
4725 target->AddPortraitIcon(PI_BOUNCE2);
4726 return FX_APPLIED;
4729 // 0xcc //resist school
4730 int fx_protection_school (Scriptable* /*Owner*/, Actor* target, Effect *fx)
4732 if (0) printf( "fx_protection_school (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4733 STAT_BIT_OR( IE_IMMUNITY, IMM_SCHOOL);
4734 return FX_APPLIED;
4737 // 0xcd //resist sectype
4738 int fx_protection_secondary_type (Scriptable* /*Owner*/, Actor* target, Effect *fx)
4740 if (0) printf( "fx_protection_secondary_type (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4741 STAT_BIT_OR( IE_IMMUNITY, IMM_SECTYPE);
4742 return FX_APPLIED;
4745 //0xce Protection:Spell
4746 int fx_resist_spell (Scriptable* /*Owner*/, Actor* target, Effect *fx)
4748 if (0) printf( "fx_resist_spell (%2d): Resource: %s\n", fx->Opcode, fx->Resource );
4749 if (strnicmp(fx->Resource,fx->Source,sizeof(fx->Resource)) ) {
4750 STAT_BIT_OR( IE_IMMUNITY, IMM_RESOURCE);
4751 return FX_APPLIED;
4753 //this has effect only on first apply, it will stop applying the spell
4754 return FX_ABORT;
4757 // ??? Protection:SpellDec
4758 int fx_resist_spell_dec (Scriptable* /*Owner*/, Actor* target, Effect *fx)
4760 if (0) printf( "fx_resist_spell_dec (%2d): Resource: %s\n", fx->Opcode, fx->Resource );
4761 if (strnicmp(fx->Resource,fx->Source,sizeof(fx->Resource)) ) {
4762 STAT_BIT_OR( IE_IMMUNITY, IMM_RESOURCE_DEC);
4763 return FX_APPLIED;
4765 //this has effect only on first apply, it will stop applying the spell
4766 return FX_ABORT;
4769 // 0xcf Bounce:Spell
4770 int fx_bounce_spell (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4772 if (0) printf( "fx_bounce_spell (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4773 STAT_BIT_OR( IE_BOUNCE, BNC_RESOURCE );
4774 return FX_APPLIED;
4777 // ??? Bounce:SpellDec
4778 int fx_bounce_spell_dec (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4780 if (0) printf( "fx_bounce_spell (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
4781 STAT_BIT_OR( IE_BOUNCE, BNC_RESOURCE_DEC );
4782 return FX_APPLIED;
4785 // 0xd0 MinimumHPModifier
4786 // the original engine didn't allow modifying of this stat
4787 // it allowed only setting it, and only by one instance
4788 int fx_minimum_hp_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4790 if (0) printf( "fx_minimum_hp_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4792 STAT_MOD( IE_MINHITPOINTS );
4793 return FX_APPLIED;
4796 //0xd1 PowerWordKill
4797 int fx_power_word_kill (Scriptable* Owner, Actor* target, Effect* fx)
4799 if (0) printf( "fx_power_word_kill (%2d): HP: %d Stat: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4800 ieDword limit = 60;
4802 if (fx->Parameter1) {
4803 limit = fx->Parameter1;
4805 //normally this would work only with hitpoints
4806 //but why not add some extra features
4807 ieDword stat = target->GetStat (fx->Parameter2&0xffff);
4809 if (stat < limit) {
4810 target->Die( Owner );
4812 return FX_NOT_APPLIED;
4815 //0xd2 PowerWordStun
4816 int fx_power_word_stun (Scriptable* Owner, Actor* target, Effect* fx)
4818 if (0) printf( "fx_power_word_stun (%2d): HP: %d Stat: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4819 ieDword limit = 90;
4821 if (fx->Parameter1) {
4822 limit = fx->Parameter1;
4824 //normally this would work only with hitpoints
4825 //but why not add some extra features
4826 ieDword stat = target->GetStat (fx->Parameter2&0xffff);
4827 ieDword x = fx->Parameter2>>16; //dice sides
4829 if (stat > limit) {
4830 return FX_NOT_APPLIED;
4832 //recalculate delay
4833 stat = (stat * 3 + limit - 1) / limit;
4834 //delay will be calculated as 1dx/2dx/3dx
4835 //depending on the current hitpoints (or the stat in param2)
4836 stat = core->Roll(stat,x?x:4,0) * core->Time.round_size;
4837 fx->Duration = core->GetGame()->GameTime+stat;
4838 fx->TimingMode = FX_DURATION_ABSOLUTE;
4839 fx->Opcode = EffectQueue::ResolveEffect(fx_set_stun_state_ref);
4840 return fx_set_stun_state(Owner,target,fx);
4843 //0xd3 State:Imprisonment (avatar removal plus portrait icon)
4844 int fx_imprisonment (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4846 if (0) printf( "fx_inprisonment (%2d)\n", fx->Opcode );
4847 target->SetMCFlag(MC_HIDDEN, BM_OR);
4848 target->AddPortraitIcon(PI_PRISON);
4849 return FX_APPLIED;
4852 //0xd4 Cure:Imprisonment
4853 static EffectRef fx_imprisonment_ref={"Imprisonment",NULL,-1};
4854 static EffectRef fx_maze_ref={"Maze",NULL,-1};
4856 int fx_freedom (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4858 if (0) printf( "fx_freedom (%2d)\n", fx->Opcode );
4859 target->fxqueue.RemoveAllEffects( fx_imprisonment_ref );
4860 target->fxqueue.RemoveAllEffects( fx_maze_ref );
4861 return FX_NOT_APPLIED;
4864 //0xd5 Maze
4865 int fx_maze (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4867 if (0) printf( "fx_maze (%2d)\n", fx->Opcode );
4868 target->SetMCFlag(MC_HIDDEN, BM_OR);
4869 target->AddPortraitIcon(PI_MAZE);
4870 return FX_APPLIED;
4873 //0xd6 CastFromList
4874 int fx_select_spell (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
4876 if (0) printf( "fx_select_spell (%2d) %d\n", fx->Opcode, fx->Parameter2 );
4877 //if parameter2==0 -> cast spells from 2da (all spells listed in 2da)
4878 //if parameter2==1 -> cast spells from book (all known spells, no need of memorize)
4879 return FX_NOT_APPLIED;
4882 // 0xd7 PlayVisualEffect
4883 static EffectRef fx_protection_from_animation_ref={"Protection:Animation",NULL,-1};
4884 int fx_play_visual_effect (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4886 if (0) printf( "fx_play_visual_effect (%2d): Resource: %s Type: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
4888 //this is in the original engine (dead actors lose this effect)
4889 if (STATE_GET( STATE_DEAD) ) {
4890 return FX_NOT_APPLIED;
4893 //delay action until area is loaded to avoid crash
4894 Map *map = target->GetCurrentArea();
4895 if (!map) return FX_APPLIED;
4897 //if it is sticky, don't add it if it is already played
4898 if (fx->Parameter2) {
4899 ScriptedAnimation *vvc = target->GetVVCCell(fx->Resource);
4900 if (vvc) {
4901 vvc->active = true;
4902 return FX_APPLIED;
4906 if (target->fxqueue.HasEffectWithResource(fx_protection_from_animation_ref,fx->Resource)) {
4907 //effect supressed by opcode 0x128
4909 return FX_APPLIED;
4913 ScriptedAnimation* sca = gamedata->GetScriptedAnimation(fx->Resource, false);
4915 //don't crash on nonexistent resources
4916 if (!sca) {
4917 return FX_NOT_APPLIED;
4920 if (fx->TimingMode!=FX_DURATION_INSTANT_PERMANENT) {
4921 sca->SetDefaultDuration(fx->Duration-core->GetGame()->GameTime);
4923 if (fx->Parameter2 == 1) {
4924 //play over target (sticky)
4925 sca->effect_owned = true;
4926 target->AddVVCell( sca );
4927 return FX_APPLIED;
4930 //not sticky
4931 if (fx->Parameter2 == 2 || !target) {
4932 sca->XPos = fx->PosX;
4933 sca->YPos = fx->PosY;
4934 } else {
4935 sca->XPos = target->Pos.x;
4936 sca->YPos = target->Pos.y;
4938 sca->PlayOnce();
4939 map->AddVVCell( sca );
4940 return FX_NOT_APPLIED;
4943 //d8 LevelDrainModifier
4945 static EffectRef fx_leveldrain_ref={"LevelDrainModifier",NULL,-1};
4947 // FIXME: BG2 level drain uses parameter3 to decrease the MaxHp, and parameter4 to decrease level. (unset)
4948 int fx_leveldrain_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
4950 if (0) printf( "fx_leveldrain_modifier (%2d): Mod: %d\n", fx->Opcode, fx->Parameter1 );
4952 //never subtract more than the maximum hitpoints
4953 ieDword x = STAT_GET(IE_MAXHITPOINTS)-1;
4954 if (fx->Parameter1*4<x) {
4955 x=fx->Parameter1*4;
4957 STAT_ADD(IE_LEVELDRAIN, fx->Parameter1);
4958 STAT_SUB(IE_MAXHITPOINTS, x);
4959 STAT_SUB(IE_SAVEVSDEATH, fx->Parameter1);
4960 STAT_SUB(IE_SAVEVSWANDS, fx->Parameter1);
4961 STAT_SUB(IE_SAVEVSPOLY, fx->Parameter1);
4962 STAT_SUB(IE_SAVEVSBREATH, fx->Parameter1);
4963 STAT_SUB(IE_SAVEVSSPELL, fx->Parameter1);
4964 target->AddPortraitIcon(PI_LEVELDRAIN);
4965 //decrease current hitpoints on first apply
4966 if (fx->FirstApply) {
4967 //current hitpoints don't have base/modified, only current
4968 BASE_SUB(IE_HITPOINTS, x);
4970 // TODO: lore, thieving
4971 return FX_APPLIED;
4974 //d9 PowerWordSleep
4975 static EffectRef fx_sleep_ref={"State:Sleep",NULL,-1};
4977 int fx_power_word_sleep (Scriptable* Owner, Actor* target, Effect* fx)
4979 if (0) printf( "fx_power_word_sleep (%2d): HP: %d Stat: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
4980 ieDword limit = 20;
4982 if (fx->Parameter1) {
4983 limit = fx->Parameter1;
4986 ieDword stat = target->GetStat (fx->Parameter2&0xffff);
4987 ieDword x = fx->Parameter2>>16; //rounds
4988 if (!x) x = 5;
4990 if (stat>limit) {
4991 return FX_NOT_APPLIED;
4993 //translate this effect to a normal sleep effect
4994 //recalculate delay
4995 fx->Duration = core->GetGame()->GameTime+x*core->Time.round_size;
4996 fx->TimingMode = FX_DURATION_ABSOLUTE;
4997 fx->Opcode = EffectQueue::ResolveEffect(fx_sleep_ref);
4998 fx->Parameter2=0;
4999 return fx_set_unconscious_state(Owner,target,fx);
5002 // 0xda StoneSkinModifier
5003 int fx_stoneskin_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5005 if (0) printf( "fx_stoneskin_modifier (%2d): Mod: %d\n", fx->Opcode, fx->Parameter1 );
5006 if (!fx->Parameter1) {
5007 return FX_NOT_APPLIED;
5010 //dead actors lose this effect
5011 if (STATE_GET( STATE_DEAD) ) {
5012 return FX_NOT_APPLIED;
5015 //this is the bg2 style stoneskin, not normally using spell states
5016 //but this way we can support hybrid games
5017 if (fx->Parameter2) {
5018 target->SetSpellState(SS_IRONSKIN);
5019 //gradient for iron skins?
5020 } else {
5021 target->SetSpellState(SS_STONESKIN);
5022 SetGradient(target, 14);
5024 STAT_SET(IE_STONESKINS, fx->Parameter1);
5025 target->AddPortraitIcon(PI_STONESKIN);
5026 return FX_APPLIED;
5029 //0xdb ac vs creature type (general effect)
5030 //0xdc DispelSchool
5031 int fx_dispel_school (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5033 ieResRef Removed;
5035 if (0) printf( "fx_dispel_school (%2d): Level: %d Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5036 target->fxqueue.RemoveLevelEffects(Removed, fx->Parameter1, RL_MATCHSCHOOL, fx->Parameter2);
5037 return FX_NOT_APPLIED;
5039 //0xdd DispelSecondaryType
5040 int fx_dispel_secondary_type (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5042 ieResRef Removed;
5044 if (0) printf( "fx_dispel_secondary_type (%2d): Level: %d Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5045 target->fxqueue.RemoveLevelEffects(Removed, fx->Parameter1, RL_MATCHSECTYPE, fx->Parameter2);
5046 return FX_NOT_APPLIED;
5049 //0xde RandomTeleport
5050 int fx_teleport_field (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5052 if (0) printf( "fx_teleport_field (%2d): Distance: %d\n", fx->Opcode, fx->Parameter1 );
5054 Map *map = target->GetCurrentArea();
5055 if (!map) {
5056 return FX_NOT_APPLIED;
5058 //the origin is the effect's target point
5059 Point p(fx->PosX+core->Roll(1,fx->Parameter1*2,-(signed) (fx->Parameter1)),
5060 fx->PosY+core->Roll(1,fx->Parameter1*2,-(signed) (fx->Parameter1)) );
5062 target->SetPosition( p, true, 0);
5063 return FX_NOT_APPLIED;
5066 //0xdf //Protection:SchoolDec
5067 int fx_protection_school_dec (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5069 if (0) printf( "fx_protection_school_dec (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
5070 if (fx->Parameter1) {
5071 STAT_BIT_OR( IE_IMMUNITY, IMM_SCHOOL_DEC );
5072 return FX_APPLIED;
5074 return FX_NOT_APPLIED;
5077 //0xe0 Cure:LevelDrain
5079 int fx_cure_leveldrain (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5081 if (0) printf( "fx_cure_leveldrain (%2d)\n", fx->Opcode );
5082 //all level drain removed at once???
5083 //if not, then find old effect, remove a number
5084 target->fxqueue.RemoveAllEffects( fx_leveldrain_ref );
5085 return FX_NOT_APPLIED;
5088 //0xe1 Reveal:Magic
5089 //gemrb special: speed and color are custom
5090 int fx_reveal_magic (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5092 if (0) printf( "fx_reveal_magic (%2d)\n", fx->Opcode );
5093 if (target->fxqueue.HasAnyDispellableEffect()) {
5094 if (!fx->Parameter1) {
5095 fx->Parameter1=0xff00; //blue
5098 int speed = (fx->Parameter2 >> 16) & 0xFF;
5099 if (!speed) speed=30;
5100 target->SetColorMod(0xff, RGBModifier::ADD, speed,
5101 fx->Parameter1 >> 8, fx->Parameter1 >> 16,
5102 fx->Parameter1 >> 24, 0);
5104 return FX_NOT_APPLIED;
5107 //0xe2 Protection:SecondaryTypeDec
5108 int fx_protection_secondary_type_dec (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5110 if (0) printf( "fx_protection_secondary_type_dec (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
5111 if (fx->Parameter1) {
5112 STAT_BIT_OR( IE_IMMUNITY, IMM_SECTYPE_DEC );
5113 return FX_APPLIED;
5115 return FX_NOT_APPLIED;
5118 //0xe3 Bounce:SchoolDecrement
5119 int fx_bounce_school_dec (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5121 if (0) printf( "fx_bounce_school_dec (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
5122 STAT_BIT_OR( IE_BOUNCE, BNC_SCHOOL_DEC );
5123 target->AddPortraitIcon(PI_BOUNCE2);
5124 return FX_APPLIED;
5127 //0xe4 Bounce:SecondaryTypeDecrement
5128 int fx_bounce_secondary_type_dec (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5130 if (0) printf( "fx_bounce_secondary_type_dec (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
5131 STAT_BIT_OR( IE_BOUNCE, BNC_SECTYPE_DEC );
5132 target->AddPortraitIcon(PI_BOUNCE2);
5133 return FX_APPLIED;
5136 //0xe5 DispelSchoolOne
5137 int fx_dispel_school_one (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5139 ieResRef Removed;
5141 if (0) printf( "fx_dispel_school_one (%2d): Level: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5142 target->fxqueue.RemoveLevelEffects(Removed, fx->Parameter1, RL_MATCHSCHOOL|RL_REMOVEFIRST, fx->Parameter2);
5143 return FX_NOT_APPLIED;
5146 //0xe6 DispelSecondaryTypeOne
5147 int fx_dispel_secondary_type_one (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5149 ieResRef Removed;
5151 if (0) printf( "fx_dispel_secondary_type_one (%2d): Level: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5152 target->fxqueue.RemoveLevelEffects(Removed, fx->Parameter1, RL_MATCHSECTYPE|RL_REMOVEFIRST, fx->Parameter2);
5153 return FX_NOT_APPLIED;
5156 //0xe7 Timestop
5157 int fx_timestop (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5159 if (0) printf( "fx_timestop (%2d)\n", fx->Opcode);
5160 core->GetGame()->TimeStop(target, fx->Duration);
5161 return FX_NOT_APPLIED;
5164 //0xe8 CastSpellOnCondition
5165 int fx_cast_spell_on_condition (Scriptable* Owner, Actor* target, Effect* fx)
5167 if (0) printf( "fx_cast_spell_on_condition (%2d): Target: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5169 if (fx->FirstApply && fx->Parameter3) {
5170 target->spellbook.HaveSpell( fx->Resource, HS_DEPLETE );
5171 target->spellbook.HaveSpell( fx->Resource2, HS_DEPLETE );
5172 target->spellbook.HaveSpell( fx->Resource3, HS_DEPLETE );
5173 target->spellbook.HaveSpell( fx->Resource4, HS_DEPLETE );
5176 //get subject of check
5177 Actor *actor = NULL;
5178 Map *map = target->GetCurrentArea();
5179 switch(fx->Parameter1) {
5180 //self
5181 case 0: actor = target; break;
5182 //last attacker
5183 case 1: actor = map->GetActorByGlobalID(target->LastHitter); break;
5184 //nearest enemy
5185 //fix this!
5186 //case 2: actor = map->GetActorByGlobalID(target->LastSeen); break;
5187 case 2: actor = GetNearestEnemyOf(map, target, 0); break;
5188 //nearest creature
5189 case 3: actor = map->GetActorByGlobalID(target->LastSeen); break;
5191 if (!actor) {
5192 return FX_APPLIED;
5194 int condition;
5195 //check condition
5196 switch(fx->Parameter2) {
5197 case COND_GOTHIT: //on hit
5198 condition = target->LastDamage;
5199 break;
5200 case COND_NEAR: //
5201 condition = PersonalDistance(actor, target)<30;
5202 break;
5203 case COND_HP_HALF:
5204 condition = actor->GetBase(IE_HITPOINTS)<actor->GetStat(IE_MAXHITPOINTS)/2;
5205 break;
5206 case COND_HP_QUART:
5207 condition = actor->GetBase(IE_HITPOINTS)<actor->GetStat(IE_MAXHITPOINTS)/4;
5208 break;
5209 case COND_HP_LOW:
5210 condition = actor->GetBase(IE_HITPOINTS)<actor->GetStat(IE_MAXHITPOINTS)/10;
5211 break;
5212 case COND_HELPLESS:
5213 condition = actor->GetStat(IE_STATE_ID) & STATE_CANTMOVE;
5214 break;
5215 case COND_POISONED:
5216 condition = actor->GetStat(IE_STATE_ID) & STATE_POISONED;
5217 break;
5218 case COND_ATTACKED: // once per round
5219 condition = actor->LastHitter;
5220 break;
5221 case COND_NEAR4: // closer than 4'
5222 condition = PersonalDistance(actor, target)<4;
5223 break;
5224 case COND_NEAR10: // closer than 10'
5225 condition = PersonalDistance(actor, target)<10;
5226 break;
5227 case COND_EVERYROUND:
5228 condition = 1;
5229 break;
5230 case COND_TOOKDAMAGE:
5231 condition = actor->LastDamage;
5232 break;
5233 default:
5234 condition = 0;
5237 if (condition) {
5238 core->ApplySpell(fx->Resource, actor, Owner, fx->Power);
5239 core->ApplySpell(fx->Resource2, actor, Owner, fx->Power);
5240 core->ApplySpell(fx->Resource3, actor, Owner, fx->Power);
5241 core->ApplySpell(fx->Resource4, actor, Owner, fx->Power);
5242 if (fx->Parameter3) {
5243 return FX_NOT_APPLIED;
5246 return FX_APPLIED;
5249 // 0xe9 Proficiency
5250 int fx_proficiency (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5252 if (0) printf( "fx_proficiency (%2d): Value: %d, Stat: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5254 if (fx->Parameter2>=MAX_STATS) return FX_NOT_APPLIED;
5256 //this opcode works only if the previous value was smaller
5257 if (STAT_GET(fx->Parameter2)<fx->Parameter1) {
5258 STAT_SET (fx->Parameter2, fx->Parameter1);
5260 return FX_APPLIED;
5263 // 0xea CreateContingency
5264 static EffectRef fx_contingency_ref={"CastSpellOnCondition",NULL,-1};
5266 int fx_create_contingency (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5268 if (0) printf( "fx_create_contingency (%2d): Level: %d, Count: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5270 if (target->fxqueue.HasEffectWithSource(fx_contingency_ref, fx->Source)) {
5271 displaymsg->DisplayConstantStringName(STR_CONTDUP, 0xf0f0f0, target);
5272 return FX_NOT_APPLIED;
5275 if (target->InParty) {
5276 Variables *dict = core->GetDictionary();
5278 dict->SetAt( "P0", target->InParty );
5279 dict->SetAt( "P1", fx->Parameter1 );
5280 dict->SetAt( "P2", fx->Parameter2 );
5281 core->SetEventFlag(EF_SEQUENCER);
5283 return FX_NOT_APPLIED;
5286 #define WB_AWAY 0
5287 #define WB_TOWARDS 1
5288 #define WB_FIXDIR 2
5289 #define WB_OWNDIR 3
5290 #define WB_AWAYOWNDIR 4
5292 // 0xeb WingBuffet
5293 int fx_wing_buffet (Scriptable* Owner, Actor* target, Effect* fx)
5295 if (0) printf( "fx_wing_buffet (%2d): Value: %d, Stat: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5296 //create movement in actor
5298 ieDword dir;
5299 switch(fx->Parameter2) {
5300 case WB_AWAY:
5301 default:
5302 dir = GetOrient(Owner->Pos, target->Pos);
5303 break;
5304 case WB_TOWARDS:
5305 dir = GetOrient(target->Pos, Owner->Pos);
5306 break;
5307 case WB_FIXDIR:
5308 dir = fx->Parameter3;
5309 break;
5310 case WB_OWNDIR:
5311 dir = target->GetOrientation();
5312 break;
5313 case WB_AWAYOWNDIR:
5314 dir = target->GetOrientation()^8;
5315 break;
5317 //could be GL_REBOUND too :)
5318 //add effect to alter target's stance
5319 target->MoveLine( fx->Parameter1, GL_NORMAL, dir );
5320 return FX_NOT_APPLIED;
5323 // 0xec ProjectImage
5325 static EffectRef fx_puppetmarker_ref={"PuppetMarker",NULL,-1};
5327 int fx_puppet_master (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5329 const char * resref = NULL;
5331 if (0) printf( "fx_puppet_master (%2d): Value: %d, Stat: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5332 STAT_SET (IE_PUPPETMASTERTYPE, fx->Parameter1);
5334 //copyself doesn't copy scripts, so the script clearing code is not needed
5335 Actor *copy = target->CopySelf(fx->Parameter2 == 1);
5337 Effect *newfx = EffectQueue::CreateUnsummonEffect(fx);
5338 if (newfx) {
5339 core->ApplyEffect(newfx, copy, copy);
5340 delete newfx;
5343 ieResRef script;
5345 //intentionally 7, to leave room for the last letter
5346 strnlwrcpy(script,target->GetScript(SCR_CLASS),7);
5347 //no need of buffer defense as long as you don't mess with the 7 above
5348 strcat(script,"m");
5349 //if the caster is inparty, the script is turned off by the AI disable flag
5350 copy->SetScript(script, SCR_CLASS, target->InParty!=0);
5352 switch(fx->Parameter2)
5354 case 1:
5355 resref = "mislead";
5356 //set the gender to illusionary, so ids matching will work
5357 copy->SetBase(IE_SEX, SEX_ILLUSION);
5358 copy->SetBase(IE_MAXHITPOINTS, copy->GetBase(IE_MAXHITPOINTS)/2);
5359 break;
5360 case 2:
5361 resref = "projimg";
5362 copy->SetBase(IE_SEX, SEX_ILLUSION);
5363 break;
5364 case 3:
5365 resref = "simulacr";
5366 // healable level drain
5367 // FIXME: second generation simulacri are supposedly at a different level:
5368 // level = original caster - caster / 2; eg. lvl 32 -> 16 -> 24 -> 20 -> 22 -> 21
5369 newfx = EffectQueue::CreateEffect(fx_leveldrain_ref, copy->GetXPLevel(1)/2, 0, FX_DURATION_INSTANT_PERMANENT);
5370 if (newfx) {
5371 core->ApplyEffect(newfx, copy, copy);
5372 delete newfx;
5374 break;
5375 default:
5376 resref = fx->Resource;
5377 break;
5379 if (resref[0]) {
5380 core->ApplySpell(resref,copy,copy,0);
5383 //FIXME: parameter1 is unsure, but something similar to what the original engine has there
5384 newfx = EffectQueue::CreateEffectCopy(fx, fx_puppetmarker_ref, target->InParty-1, fx->Parameter2);
5385 if (newfx) {
5386 core->ApplyEffect(newfx, copy, copy);
5387 delete newfx;
5389 return FX_NOT_APPLIED;
5392 // 0xed PuppetMarker
5393 int fx_puppet_marker (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5395 if (0) printf( "fx_puppet_marker (%2d): Value: %d, Stat: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5396 //actually the Type is in parameter2 and the ID is in parameter1
5397 //but for some reason the defines are in the opposite order
5398 STAT_SET (IE_PUPPETTYPE, fx->Parameter1); //cb4 - the ID of the controller
5399 STAT_SET (IE_PUPPETID, fx->Parameter2); //cb8 - the control type
5400 return FX_APPLIED;
5403 // 0xee Disintegrate
5404 int fx_disintegrate (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5406 if (0) printf( "fx_disintegrate (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5407 if (EffectQueue::match_ids( target, fx->Parameter2, fx->Parameter1) ) {
5408 //convert it to a death opcode or apply the new effect?
5409 fx->Opcode = EffectQueue::ResolveEffect(fx_death_ref);
5410 fx->TimingMode = FX_DURATION_INSTANT_PERMANENT;
5411 fx->Parameter1 = 0;
5412 fx->Parameter2 = 0x200;
5413 return FX_APPLIED;
5415 return FX_NOT_APPLIED;
5418 // 0xef Farsee
5419 // 1 view not explored sections too
5420 // 2 param1=range (otherwise visualrange)
5421 // 4 point already set (otherwise use gui)
5422 // 8 use line of sight
5423 #define FS_UNEXPLORED 1
5424 #define FS_VISUALRANGE 2
5425 #define FS_HASPOINT 4
5426 #define FS_LOS 8
5428 int fx_farsee (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5430 if (0) printf( "fx_farsee (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5431 Map *map = target->GetCurrentArea();
5432 if (!map) {
5433 return FX_APPLIED;
5436 if (!(fx->Parameter2&FS_VISUALRANGE)) {
5437 fx->Parameter1=STAT_GET(IE_VISUALRANGE);
5438 fx->Parameter2|=FS_VISUALRANGE;
5441 if (target->InParty) {
5442 //don't start graphical interface if actor isn't in party
5443 if (!(fx->Parameter2&FS_HASPOINT)) {
5444 //start graphical interface
5445 //it will do all the rest of the opcode
5446 //using RevealMap guiscript action
5447 core->EventFlag|=EF_SHOWMAP;
5448 return FX_NOT_APPLIED;
5452 Point p(fx->PosX, fx->PosY);
5454 //don't explore unexplored points
5455 if (!(fx->Parameter2&FS_UNEXPLORED)) {
5456 if (!map->IsVisible(p, 1)) {
5457 return FX_NOT_APPLIED;
5460 map->ExploreMapChunk(p, fx->Parameter1, fx->Parameter2&FS_LOS);
5461 return FX_NOT_APPLIED;
5464 // 0xf0 Icon:Remove
5465 int fx_remove_portrait_icon (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5467 if (0) printf( "fx_remove_portrait_icon (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
5468 target->fxqueue.RemoveAllEffectsWithParam( fx_display_portrait_icon_ref, fx->Parameter2 );
5469 return FX_NOT_APPLIED;
5471 // 0xf1 control creature (same as charm)
5473 // 0xF2 Cure:Confusion
5474 static EffectRef fx_confused_state_ref={"State:Confused",NULL,-1};
5476 int fx_cure_confused_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5478 if (0) printf( "fx_cure_confused_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5479 BASE_STATE_CURE( STATE_CONFUSED );
5480 target->fxqueue.RemoveAllEffects(fx_confused_state_ref);
5481 return FX_NOT_APPLIED;
5484 // 0xf3 DrainItems (this is disabled in ToB)
5485 int fx_drain_items (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5487 if (0) printf( "fx_drain_items (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5488 ieDword i=fx->Parameter1;
5489 while (i--) {
5490 //deplete magic item = 0
5491 //deplete weapon = 1
5492 target->inventory.DepleteItem(fx->Parameter2);
5494 return FX_NOT_APPLIED;
5496 // 0xf4 DrainSpells
5497 int fx_drain_spells (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5499 if (0) printf( "fx_drain_spells (%2d): Count: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5500 ieDword i=fx->Parameter1;
5501 if (fx->Parameter2) {
5502 while(i--) {
5503 if (!target->spellbook.DepleteSpell(IE_SPELL_TYPE_PRIEST)) {
5504 break;
5507 return FX_NOT_APPLIED;
5509 while(i--) {
5510 if (!target->spellbook.DepleteSpell(IE_SPELL_TYPE_WIZARD)) {
5511 break;
5514 return FX_NOT_APPLIED;
5516 // 0xf5 CheckForBerserk
5517 int fx_checkforberserk_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5519 if (0) printf( "fx_checkforberserk_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5520 STAT_SET( IE_CHECKFORBERSERK, fx->Parameter2 );
5521 return FX_APPLIED;
5523 // 0xf6 BerserkStage1Modifier
5524 int fx_berserkstage1_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5526 if (0) printf( "fx_berserkstage1_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5527 STAT_SET( IE_BERSERKSTAGE1, fx->Parameter2 );
5528 return FX_APPLIED;
5530 // 0xf7 BerserkStage2Modifier
5531 int fx_berserkstage2_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5533 if (0) printf( "fx_berserkstage2_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5534 STAT_SET( IE_BERSERKSTAGE2, fx->Parameter2 );
5535 STATE_SET (STATE_BERSERK);
5536 return FX_APPLIED;
5539 // 0xf8 set melee effect
5540 // adds effect to melee attacks (for monks, asssasins, fighter hlas, ...)
5541 // it is cumulative
5543 // 0xf9 set missile effect
5544 // adds effect to ranged attacks (archers, ...)
5545 // it is cumulative
5547 // 0xfa DamageLuckModifier
5548 int fx_damageluck_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5550 if (0) printf( "fx_damageluck_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5551 STAT_MOD( IE_DAMAGELUCK );
5552 return FX_APPLIED;
5555 // 0xfb BardSong
5557 int fx_change_bardsong (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5559 if (0) printf( "fx_change_bardsong (%2d): %s\n", fx->Opcode, fx->Resource);
5560 memcpy(target->BardSong, fx->Resource, 8);
5561 return FX_APPLIED;
5564 // 0xfc SetTrap
5565 int fx_set_area_effect (Scriptable* Owner, Actor* target, Effect* fx)
5567 if (0) printf( "fx_set_trap (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5568 ieDword skill, roll;
5569 Map *map;
5571 map = target->GetCurrentArea();
5572 if (!map) return FX_NOT_APPLIED;
5574 proIterator iter;
5576 //check if trap count is over an amount (only saved traps count)
5577 //actually, only projectiles in trigger phase should count here
5578 if (map->GetTrapCount(iter)>6) {
5579 displaymsg->DisplayConstantStringName(STR_NOMORETRAP, 0xf0f0f0, target);
5580 return FX_NOT_APPLIED;
5583 //check if we are under attack
5584 if (GetNearestEnemyOf(map, target, ORIGIN_SEES_ENEMY|ENEMY_SEES_ORIGIN)) {
5585 displaymsg->DisplayConstantStringName(STR_MAYNOTSETTRAP, 0xf0f0f0, target);
5586 return FX_NOT_APPLIED;
5589 if (Owner->Type==ST_ACTOR) {
5590 skill = ((Actor *)Owner)->GetStat(IE_SETTRAPS);
5591 roll = core->Roll(1,100,0);
5592 } else {
5593 roll=0;
5594 skill=0;
5597 if (roll>skill) {
5598 //failure
5599 displaymsg->DisplayConstantStringName(STR_SNAREFAILED, 0xf0f0f0, target);
5600 //TODO check luck and do some damage effect on target
5601 return FX_NOT_APPLIED;
5603 //success
5604 displaymsg->DisplayConstantStringName(STR_SNARESUCCEED, 0xf0f0f0, target);
5605 Owner->CastSpellPoint(fx->Resource, target->Pos, false);
5606 return FX_NOT_APPLIED;
5609 // 0xfd SetMapNote
5610 int fx_set_map_note (Scriptable* Owner, Actor* target, Effect* fx)
5612 if (0) printf( "fx_set_map_note (%2d): StrRef: %d Color: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5613 Scriptable *marker = target?target:Owner;
5614 Map *map = marker->GetCurrentArea();
5615 if (!map) return FX_APPLIED; //delay effect
5616 Point p(fx->PosX, fx->PosY);
5617 char *text = core->GetString(fx->Parameter1, 0);
5618 map->AddMapNote(p, fx->Parameter2, text, fx->Parameter1);
5619 return FX_NOT_APPLIED;
5622 // 0xfe RemoveMapNote
5623 int fx_remove_map_note (Scriptable* Owner, Actor* target, Effect* fx)
5625 if (0) printf( "fx_remove_map_note (%2d)\n", fx->Opcode);
5626 Scriptable *marker = target?target:Owner;
5627 Map *map = marker->GetCurrentArea();
5628 if (!map) return FX_APPLIED; //delay effect
5629 Point p(fx->PosX, fx->PosY);
5630 map->RemoveMapNote(p);
5631 return FX_NOT_APPLIED;
5634 // 0xff Item:CreateDays
5635 int fx_create_item_days (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5637 if (0) printf( "fx_create_item_days (%2d)\n", fx->Opcode );
5638 target->inventory.AddSlotItemRes( fx->Resource, SLOT_ONLYINVENTORY, fx->Parameter1, fx->Parameter3, fx->Parameter4 );
5639 if ((fx->TimingMode&0xff) == FX_DURATION_INSTANT_LIMITED) {
5640 //if this effect has expiration, then it will remain as a remove_item
5641 //on the effect queue, inheriting all the parameters
5642 //duration needs a hack (recalculate it for days)
5643 //no idea if this multiplier is ok
5644 fx->Duration+=(fx->Duration-core->GetGame()->GameTime)*2400;
5645 fx->Opcode=EffectQueue::ResolveEffect(fx_remove_inventory_item_ref);
5646 fx->TimingMode=FX_DURATION_DELAY_PERMANENT;
5647 return FX_APPLIED;
5649 return FX_NOT_APPLIED;
5652 // 0x100 Sequencer:Store
5653 int fx_store_spell_sequencer(Scriptable* /*Owner*/, Actor* target, Effect* fx)
5655 if (0) printf( "fx_store_spell_sequencer (%2d)\n", fx->Opcode );
5656 //just display the spell sequencer portrait icon
5657 target->AddPortraitIcon(PI_SEQUENCER);
5658 if (fx->FirstApply && fx->Parameter3) {
5659 target->spellbook.HaveSpell( fx->Resource, HS_DEPLETE );
5660 target->spellbook.HaveSpell( fx->Resource2, HS_DEPLETE );
5661 target->spellbook.HaveSpell( fx->Resource3, HS_DEPLETE );
5662 target->spellbook.HaveSpell( fx->Resource4, HS_DEPLETE );
5664 return FX_APPLIED;
5667 // 0x101 Sequencer:Create
5668 static EffectRef fx_spell_sequencer_active_ref={"Sequencer:Store",NULL,-1};
5670 int fx_create_spell_sequencer(Scriptable* /*Owner*/, Actor* target, Effect* fx)
5672 if (0) printf( "fx_create_spell_sequencer (%2d): Level: %d, Count: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5673 if (target->fxqueue.HasEffectWithSource(fx_spell_sequencer_active_ref, fx->Source)) {
5674 displaymsg->DisplayConstantStringName(STR_SEQDUP, 0xf0f0f0, target);
5675 return FX_NOT_APPLIED;
5677 //just a call to activate the spell sequencer creation gui
5678 if (target->InParty) {
5679 Variables *dict = core->GetDictionary();
5681 dict->SetAt( "P0", target->InParty );
5682 dict->SetAt( "P1", fx->Parameter1 ); //maximum level
5683 dict->SetAt( "P2", fx->Parameter2 | (2<<16) ); //count and target type
5684 core->SetEventFlag(EF_SEQUENCER);
5686 return FX_NOT_APPLIED;
5689 // 0x102 Sequencer:Activate
5691 int fx_activate_spell_sequencer(Scriptable* Owner, Actor* target, Effect* fx)
5693 if (0) printf( "fx_activate_spell_sequencer (%2d): Resource: %s\n", fx->Opcode, fx->Resource );
5694 if (Owner->Type!=ST_ACTOR) {
5695 return FX_NOT_APPLIED;
5698 Effect *sequencer = ((Actor *) Owner)->fxqueue.HasEffect(fx_spell_sequencer_active_ref);
5699 if (sequencer) {
5700 //cast 1-4 spells stored in the spell sequencer
5701 core->ApplySpell(sequencer->Resource, target, Owner, fx->Power);
5702 core->ApplySpell(sequencer->Resource2, target, Owner, fx->Power);
5703 core->ApplySpell(sequencer->Resource3, target, Owner, fx->Power);
5704 core->ApplySpell(sequencer->Resource4, target, Owner, fx->Power);
5705 //remove the spell sequencer store effect
5706 sequencer->TimingMode=FX_DURATION_JUST_EXPIRED;
5708 return FX_NOT_APPLIED;
5711 // 0x103 SpellTrap (Protection:SpellLevelDec + recall spells)
5712 int fx_spelltrap(Scriptable* /*Owner*/, Actor* target, Effect* fx)
5714 if (0) printf( "fx_spelltrap (%2d): Count: %d, Level: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5715 if (fx->Parameter3) {
5716 target->RestoreSpellLevel(fx->Parameter3, 0);
5717 fx->Parameter3=0;
5719 if (fx->Parameter1<=0) {
5720 //gone down to zero
5721 return FX_NOT_APPLIED;
5723 target->SetOverlay(OV_SPELLTRAP);
5724 target->AddPortraitIcon(PI_SPELLTRAP);
5725 return FX_APPLIED;
5728 //0x104 Crash104
5729 //0x138 Crash138
5730 int fx_crash (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
5732 if (0) printf( "fx_crash (%2d): Param1: %d, Param2: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5733 return FX_NOT_APPLIED;
5736 // 0x105 RestoreSpells
5737 int fx_restore_spell_level(Scriptable* /*Owner*/, Actor* target, Effect* fx)
5739 if (0) printf( "fx_restore_spell_level (%2d): Level: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5740 target->RestoreSpellLevel(fx->Parameter1, fx->Parameter2);
5741 return FX_NOT_APPLIED;
5743 // 0x106 VisualRangeModifier
5744 int fx_visual_range_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5746 if (0) printf( "fx_visual_range_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5747 STAT_MOD( IE_VISUALRANGE );
5748 return FX_APPLIED;
5751 // 0x107 BackstabModifier
5752 int fx_backstab_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5754 if (0) printf( "fx_visual_range_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5755 //this is how it is done in the original engine, i don't know why they would do this
5756 //ctrl-r would probably remove it otherwise
5757 //Why they didn't fix it in the spell/item is beyond me
5758 if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT)
5759 fx->TimingMode=FX_DURATION_INSTANT_PERMANENT_AFTER_BONUSES;
5760 STAT_MOD( IE_BACKSTABDAMAGEMULTIPLIER );
5761 return FX_APPLIED;
5764 // 0x108 DropWeapon
5765 int fx_drop_weapon (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5767 if (fx->Resource[0]) {
5768 target->DropItem(fx->Resource, 0);
5769 return FX_NOT_APPLIED;
5771 switch (fx->Parameter2) {
5772 case 0:
5773 target->DropItem(-1, 0);
5774 break;
5775 case 1:
5776 target->DropItem(target->inventory.GetEquippedSlot(), 0);
5777 break;
5778 default:
5779 target->DropItem(fx->Parameter1, 0);
5780 break;
5782 return FX_NOT_APPLIED;
5784 // 0x109 ModifyGlobalVariable
5785 int fx_modify_global_variable (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
5787 Game *game = core->GetGame();
5788 //convert it to internal variable format
5789 if (!fx->IsVariable) {
5790 char *poi=fx->Resource+8;
5791 memmove(poi, fx->Resource2,8);
5792 poi+=8;
5793 memmove(poi, fx->Resource3,8);
5794 poi+=8;
5795 memmove(poi, fx->Resource4,8);
5796 fx->IsVariable=1;
5799 //hack for IWD
5800 if (!fx->Resource[0]) {
5801 strnuprcpy(fx->Resource,"RETURN_TO_LONELYWOOD",32);
5804 if (0) printf( "fx_modify_global_variable (%2d): Variable: %s Value: %d Type: %d\n", fx->Opcode, fx->Resource, fx->Parameter1, fx->Parameter2 );
5805 if (fx->Parameter2) {
5806 ieDword var = 0;
5807 //use resource memory area as variable name
5808 game->locals->Lookup(fx->Resource, var);
5809 game->locals->SetAt(fx->Resource, var+fx->Parameter1);
5810 } else {
5811 game->locals->SetAt(fx->Resource, fx->Parameter1);
5813 return FX_NOT_APPLIED;
5815 // 0x10a RemoveImmunity
5816 EffectRef immunity_effect_ref={"Protection:Spell",NULL,-1};
5818 int fx_remove_immunity(Scriptable* /*Owner*/, Actor* target, Effect* fx)
5820 if (0) printf( "fx_remove_immunity (%2d): %s\n", fx->Opcode, fx->Resource );
5821 target->fxqueue.RemoveAllEffectsWithResource(immunity_effect_ref, fx->Resource);
5822 return FX_NOT_APPLIED;
5825 // 0x10b protection from display string is a generic effect
5826 // 0x10c ExploreModifier
5827 int fx_explore_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5829 if (0) printf( "fx_explore_modifier (%2d)\n", fx->Opcode );
5830 if (fx->Parameter2) {
5831 //gemrb modifier
5832 STAT_SET (IE_EXPLORE, fx->Parameter1);
5833 } else {
5834 STAT_SET (IE_EXPLORE, 1);
5836 return FX_APPLIED;
5838 // 0x10d ScreenShake
5839 int fx_screenshake (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
5841 if (0) printf( "fx_screenshake (%2d): Strength: %d\n", fx->Opcode, fx->Parameter1 );
5842 core->timer->SetScreenShake( fx->Parameter1, fx->Parameter1, 1);
5843 return FX_APPLIED;
5846 // 0x10e Cure:CasterHold
5847 static EffectRef fx_pause_caster_modifier_ref={"PauseTarget",NULL,-1};
5849 int fx_unpause_caster (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5851 if (0) printf( "fx_unpause_caster (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5852 target->fxqueue.RemoveAllEffects(fx_pause_caster_modifier_ref);
5853 return FX_NOT_APPLIED;
5855 // 0x10f AvatarRemoval
5856 // 0x104 AvatarRemoval (iwd)
5857 int fx_avatar_removal (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5859 if (0) printf( "fx_avatar_removal (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5860 //FIXME: this is a permanent irreversible effect in IWD
5861 //if it is different in bg2, then create another effect
5862 //bg2 calls this SummonDisable
5863 BASE_SET(IE_AVATARREMOVAL, 1);
5864 return FX_NOT_APPLIED;
5867 /* note/TODO from Taimon:
5868 What happens at a lower level is that the engine recreates the entire stats on some changes to the creature. The application of an effect to the creature is one such change.
5869 Since the repeating effects are stored in a list inside those stats, they are being recreated every ai update, if there has been an effect application.
5870 The repeating effect itself internally uses a counter to store how often it has been called. And when this counter equals the period it fires of the effect. When the list is being recreated all those counters are lost.
5872 static EffectRef fx_apply_effect_repeat_ref = {"ApplyEffectRepeat", NULL, -1};
5873 // 0x110 ApplyEffectRepeat
5874 int fx_apply_effect_repeat (Scriptable* Owner, Actor* target, Effect* fx)
5876 ieDword i; //moved here because msvc6 cannot handle it otherwise
5878 if (0) printf( "fx_apply_effect_repeat (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5880 Point p(fx->PosX, fx->PosY);
5881 Effect *newfx = core->GetEffect(fx->Resource, fx->Power, p);
5882 //core->GetEffect is a borrowed reference, don't delete it
5883 if (!newfx) {
5884 return FX_NOT_APPLIED;
5887 // don't apply the effect if a similar one is already applied with a shorter duration
5888 Effect *oldfx = target->fxqueue.HasEffect(fx_apply_effect_repeat_ref);
5889 if (oldfx && oldfx->Duration < fx->Duration) {
5890 return FX_NOT_APPLIED;
5893 switch (fx->Parameter2) {
5894 case 0: //once per second
5895 case 1: //crash???
5896 if (!(core->GetGame()->GameTime%AI_UPDATE_TIME)) {
5897 core->ApplyEffect(newfx, target, Owner);
5899 break;
5900 case 2://param1 times every second
5901 if (!(core->GetGame()->GameTime%AI_UPDATE_TIME)) {
5902 for (i=0;i<fx->Parameter1;i++) {
5903 core->ApplyEffect(newfx, target, Owner);
5906 break;
5907 case 3: //once every Param1 second
5908 if (fx->Parameter1 && (core->GetGame()->GameTime%fx->Parameter1)) {
5909 core->ApplyEffect(newfx, target, Owner);
5911 break;
5912 case 4: //param3 times every Param1 second
5913 if (fx->Parameter1 && (core->GetGame()->GameTime%fx->Parameter1)) {
5914 for (i=0;i<fx->Parameter3;i++) {
5915 core->ApplyEffect(newfx, target, Owner);
5918 break;
5920 return FX_APPLIED;
5923 // 0x111 RemoveProjectile
5924 int fx_remove_projectile (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5926 //the list is now cached by Interface, no need of freeing it
5927 ieDword *projectilelist;
5929 //instant effect
5930 if (0) printf( "fx_remove_projectile (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5932 if (!target) return FX_NOT_APPLIED;
5933 Map *area = target->GetCurrentArea();
5934 if (!area) return FX_NOT_APPLIED;
5936 switch (fx->Parameter2) {
5937 case 0: //standard bg2
5938 projectilelist = core->GetListFrom2DA("clearair");
5939 break;
5940 case 1: //you can give a 2da for projectile list (gemrb)
5941 projectilelist = core->GetListFrom2DA(fx->Resource);
5942 break;
5943 case 2: //or you can give one single projectile in param1 (gemrb)
5944 projectilelist = (ieDword *) malloc(2*sizeof(ieDword));
5945 projectilelist[0]=1;
5946 projectilelist[1]=fx->Parameter1;
5947 break;
5948 default:
5949 return FX_NOT_APPLIED;
5951 //The first element is the counter, so don't decrease the counter here
5952 Point p(fx->PosX, fx->PosY);
5954 int i = projectilelist[0];
5956 while(i) {
5957 ieDword projectile = projectilelist[i];
5958 proIterator piter;
5960 size_t cnt = area->GetProjectileCount(piter);
5961 while( cnt--) {
5962 Projectile *pro = *piter;
5963 if ((pro->GetType()==projectile) && pro->PointInRadius(p) ) {
5964 pro->Cleanup();
5967 if (target) {
5968 target->fxqueue.RemoveAllEffectsWithProjectile(projectile);
5970 i--;
5972 //this one was constructed by us
5973 if (fx->Parameter2==2) free(projectilelist);
5974 return FX_NOT_APPLIED;
5977 // 0x112 TeleportToTarget
5978 int fx_teleport_to_target (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5980 if (0) printf( "fx_teleport_to_target (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5981 if (STATE_GET(STATE_DEAD)) {
5982 return FX_NOT_APPLIED;
5985 Map *map = target->GetCurrentArea();
5986 if (map) {
5987 Actor *victim = map->GetActorByGlobalID(target->LastAttacker);
5988 if (victim) {
5989 target->SetPosition( victim->Pos, true, 0 );
5992 return FX_NOT_APPLIED;
5994 // 0x113 HideInShadowsModifier
5995 int fx_hide_in_shadows_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
5997 if (0) printf( "fx_hide_in_shadows_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
5998 STAT_MOD( IE_HIDEINSHADOWS );
5999 return FX_APPLIED;
6001 // 0x114 DetectIllusionsModifier
6002 int fx_detect_illusion_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6004 if (0) printf( "fx_detect_illusion_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6005 STAT_MOD( IE_DETECTILLUSIONS );
6006 return FX_APPLIED;
6008 // 0x115 SetTrapsModifier
6009 int fx_set_traps_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6011 if (0) printf( "fx_set_traps_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6012 STAT_MOD( IE_SETTRAPS );
6013 return FX_APPLIED;
6015 // 0x116 ToHitBonusModifier
6016 int fx_to_hit_bonus_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6018 if (0) printf( "fx_to_hit_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6019 HandleBonus( target, IE_HITBONUS, fx->Parameter1, fx->TimingMode );
6020 return FX_APPLIED;
6023 // 0x117 RenableButton
6024 static EffectRef fx_disable_button_ref={"DisableButton",NULL,-1};
6026 int fx_renable_button (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6028 //removes the disable button effect
6029 if (0) printf( "fx_renable_button (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
6030 target->fxqueue.RemoveAllEffectsWithParam( fx_disable_button_ref, fx->Parameter2 );
6031 return FX_NOT_APPLIED;
6033 // 0x118 ForceSurgeModifier
6034 int fx_force_surge_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6036 if (0) printf( "fx_force_surge_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6037 STAT_MOD( IE_FORCESURGE );
6038 return FX_APPLIED;
6041 // 0x119 WildSurgeModifier
6042 int fx_wild_surge_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6044 if (0) printf( "fx_wild_surge_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6045 STAT_MOD( IE_SURGEMOD );
6046 return FX_APPLIED;
6049 // 0x11a ScriptingState
6050 int fx_scripting_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6052 if (0) printf( "fx_scripting_state (%2d): Value: %d, Stat: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6054 //original engine didn't check boundaries, causing crashes
6055 //we allow only positive indices (some extra stats are still addressable)
6056 if (fx->Parameter2>100) {
6057 return FX_NOT_APPLIED;
6059 //original engine used only single byte value, we allow full dword
6060 STAT_SET( IE_SCRIPTINGSTATE1+fx->Parameter2, fx->Parameter1 );
6061 return FX_APPLIED;
6064 // 0x11b ApplyEffectCurse
6065 int fx_apply_effect_curse (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6067 if (0) printf( "fx_apply_effect_curse (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6069 //this effect executes a file effect in place of this effect
6070 //the file effect inherits the target and the timingmode, but gets
6071 //a new chance to roll percents
6072 int ret = FX_NOT_APPLIED;
6073 if (!target) {
6074 return ret;
6077 if (EffectQueue::match_ids( target, fx->Parameter2, fx->Parameter1) ) {
6078 Point p(fx->PosX, fx->PosY);
6080 //apply effect, if the effect is a goner, then kill
6081 //this effect too
6082 Effect *newfx = core->GetEffect(fx->Resource, fx->Power, p);
6083 if (newfx) {
6084 Effect *myfx = new Effect;
6085 memcpy(myfx, newfx, sizeof(Effect));
6086 myfx->random_value = fx->random_value;
6087 myfx->TimingMode=fx->TimingMode;
6088 myfx->Duration=fx->Duration;
6089 myfx->Target = FX_TARGET_PRESET;
6090 myfx->CasterID = fx->CasterID;
6091 ret = target->fxqueue.ApplyEffect(target, myfx, fx->FirstApply, 0);
6092 delete myfx;
6094 //newfx is a borrowed reference don't delete it
6096 return ret;
6099 // 0x11c MeleeHitModifier
6100 int fx_melee_to_hit_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6102 if (0) printf( "fx_melee_to_hit_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6103 STAT_MOD( IE_MELEETOHIT );
6104 return FX_APPLIED;
6107 // 0x11d MeleeDamageModifier
6108 int fx_melee_damage_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6110 if (0) printf( "fx_melee_damage_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6111 STAT_MOD( IE_MELEEDAMAGE );
6112 return FX_APPLIED;
6115 // 0x11e MissileDamageModifier
6116 int fx_missile_damage_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6118 if (0) printf( "fx_missile_damage_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6119 STAT_MOD( IE_MISSILEDAMAGE );
6120 return FX_APPLIED;
6123 // 0x11f NoCircleState
6124 int fx_no_circle_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6126 if (0) printf( "fx_missile_damage_modifier (%2d)\n", fx->Opcode);
6127 STAT_SET( IE_NOCIRCLE, 1 );
6128 return FX_APPLIED;
6131 // 0x120 FistHitModifier
6132 int fx_fist_to_hit_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6134 if (0) printf( "fx_fist_to_hit_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6135 STAT_MOD( IE_FISTHIT );
6136 return FX_APPLIED;
6139 // 0x121 FistDamageModifier
6140 int fx_fist_damage_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6142 if (0) printf( "fx_fist_damage_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6143 STAT_MOD( IE_FISTDAMAGE );
6144 return FX_APPLIED;
6146 //0x122 TitleModifier
6147 int fx_title_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6149 if (0) printf( "fx_fist_damage_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6150 if (fx->Parameter2) {
6151 STAT_SET( IE_TITLE2, fx->Parameter1 );
6152 } else {
6153 STAT_SET( IE_TITLE1, fx->Parameter1 );
6155 return FX_APPLIED;
6157 //0x123 DisableOverlay
6158 //FIXME: which overlay is disabled?
6159 //if one of the overlays marked by sanctuary, then
6160 //make the bit correspond to it
6161 int fx_disable_overlay_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6163 if (0) printf( "fx_disable_overlay_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6164 STAT_SET( IE_DISABLEOVERLAY, fx->Parameter1 );
6165 return FX_APPLIED;
6167 //0x124 Protection:Backstab (bg2)
6168 //0x11f Protection:Backstab (how, iwd2)
6169 //3 different games, 3 different methods of flagging this
6170 int fx_no_backstab_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6172 if (0) printf( "fx_no_backstab_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6173 //bg2
6174 STAT_SET( IE_DISABLEBACKSTAB, fx->Parameter1 );
6175 //how
6176 EXTSTATE_SET(EXTSTATE_NO_BACKSTAB);
6177 //iwd2
6178 target->SetSpellState(SS_NOBACKSTAB);
6179 return FX_APPLIED;
6181 //0x125 OffscreenAIModifier
6182 int fx_offscreenai_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6184 if (0) printf( "fx_offscreenai_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6185 STAT_SET( IE_ENABLEOFFSCREENAI, fx->Parameter1 );
6186 target->Activate();
6187 return FX_APPLIED;
6189 //0x126 ExistanceDelayModifier
6190 int fx_existance_delay_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6192 if (0) printf( "fx_existance_delay_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6193 STAT_SET( IE_EXISTANCEDELAY, fx->Parameter1 );
6194 return FX_APPLIED;
6196 //0x127 DisableChunk
6197 int fx_disable_chunk_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6199 if (0) printf( "fx_disable_chunk_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6200 STAT_SET( IE_DISABLECHUNKING, fx->Parameter1 );
6201 return FX_APPLIED;
6203 #if 0
6204 //This is done differently in the original engine, and THIS may not even work
6205 //0x128 Protection:Animation
6206 int fx_protection_from_animation (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6208 if (0) printf( "fx_protection_from_animation (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6209 //remove vvc from actor if active
6210 target->RemoveVVCell(fx->Resource, false);
6211 return FX_APPLIED;
6213 #endif
6215 //0x129 Protection:Turn
6216 int fx_protection_from_turn (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6218 if (0) printf( "fx_non_interruptible_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6219 STAT_SET( IE_NOTURNABLE, fx->Parameter1 );
6220 return FX_APPLIED;
6222 //0x12a CutScene2
6223 //runs a predetermined script in cutscene mode
6224 int fx_cutscene2 (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
6226 Game *game;
6227 ieResRef resref;
6229 if (0) printf( "fx_cutscene2 (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
6230 if (core->InCutSceneMode()) return FX_NOT_APPLIED;
6231 game = core->GetGame();
6232 if (!game) return FX_NOT_APPLIED;
6234 game->ClearPlaneLocations();
6235 for (int i = 0; i < game->GetPartySize(false); i++) {
6236 Actor* act = game->GetPC( i, false );
6237 GAMLocationEntry *gle = game->GetPlaneLocationEntry(i);
6238 if (act && gle) {
6239 gle->Pos = act->Pos;
6240 memcpy(gle->AreaResRef, act->Area, 9);
6244 core->SetCutSceneMode(true);
6246 //GemRB enhancement: allow a custom resource
6247 if (fx->Parameter2) {
6248 strnlwrcpy(resref,fx->Resource, 8);
6249 } else {
6250 strnlwrcpy(resref,"cut250a",8);
6253 GameScript* gs = new GameScript( resref, game );
6254 gs->EvaluateAllBlocks();
6255 delete( gs );
6256 return FX_NOT_APPLIED;
6258 //0x12b ChaosShieldModifier
6259 int fx_chaos_shield_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6261 if (0) printf( "fx_chaos_shield_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6262 STAT_ADD( IE_CHAOSSHIELD, fx->Parameter1 );
6263 if (fx->Parameter2) {
6264 target->AddPortraitIcon(PI_CSHIELD); //162
6265 } else {
6266 target->AddPortraitIcon(PI_CSHIELD2); //163
6268 return FX_APPLIED;
6270 //0x12c NPCBump
6271 int fx_npc_bump (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6273 if (0) printf( "fx_npc_bump (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6274 //unknown effect, but known stat position
6275 STAT_MOD( IE_NPCBUMP );
6276 return FX_APPLIED;
6278 //0x12d CriticalHitModifier
6279 int fx_critical_hit_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6281 if (0) printf( "fx_critical_hit_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6282 STAT_MOD( IE_CRITICALHITBONUS );
6283 return FX_APPLIED;
6285 // 0x12e CanUseAnyItem
6286 int fx_can_use_any_item_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6288 if (0) printf( "fx_can_use_any_item_modifier (%2d): Value: %d\n", fx->Opcode, fx->Parameter2 );
6290 STAT_SET( IE_CANUSEANYITEM, fx->Parameter2 );
6291 return FX_APPLIED;
6294 // 0x12f AlwaysBackstab
6295 int fx_always_backstab_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6297 if (0) printf( "fx_always_backstab_modifier (%2d): Value: %d\n", fx->Opcode, fx->Parameter2 );
6299 STAT_SET( IE_ALWAYSBACKSTAB, fx->Parameter2 );
6300 return FX_APPLIED;
6303 // 0x130 MassRaiseDead
6304 int fx_mass_raise_dead (Scriptable* Owner, Actor* /*target*/, Effect* fx)
6306 if (0) printf( "fx_mass_raise_dead (%2d)\n", fx->Opcode );
6308 Game *game=core->GetGame();
6310 int i=game->GetPartySize(false);
6311 Point p(fx->PosX,fx->PosY);
6312 while (i--) {
6313 Actor *actor=game->GetPC(i,false);
6314 Resurrect(Owner, actor, fx, p);
6316 return FX_NOT_APPLIED;
6319 // 0x131 OffhandHitModifier
6320 int fx_left_to_hit_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6322 if (0) printf( "fx_left_to_hit_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6324 STAT_MOD( IE_HITBONUSLEFT );
6325 return FX_APPLIED;
6328 // 0x132 RightHitModifier
6329 int fx_right_to_hit_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6331 if (0) printf( "fx_right_to_hit_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6333 STAT_MOD( IE_HITBONUSRIGHT );
6334 return FX_APPLIED;
6337 // 0x133 Reveal:Tracks
6338 int fx_reveal_tracks (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6340 if (0) printf( "fx_reveal_tracks (%2d): Distance: %d\n", fx->Opcode, fx->Parameter1 );
6341 Map *map = target->GetCurrentArea();
6342 if (!map) return FX_APPLIED;
6343 if (!fx->Parameter2) {
6344 fx->Parameter2=1;
6345 //write tracks.2da entry
6346 if (map->DisplayTrackString(target)) {
6347 return FX_NOT_APPLIED;
6350 GameControl *gc = core->GetGameControl();
6351 if (gc) {
6352 //highlight all living creatures (not in party, but within range)
6353 gc->SetTracker(target, fx->Parameter1);
6355 return FX_APPLIED;
6358 // 0x134 Protection:Tracking
6359 int fx_protection_from_tracking (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6361 if (0) printf( "fx_protection_from_tracking (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
6363 STAT_MOD( IE_NOTRACKING ); //highlight creature???
6364 return FX_APPLIED;
6366 // 0x135 ModifyLocalVariable
6367 int fx_modify_local_variable (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6369 //convert it to internal variable format
6370 if (!fx->IsVariable) {
6371 char *poi = fx->Resource+8;
6372 memmove(poi, fx->Resource2, 8);
6373 poi+=8;
6374 memmove(poi, fx->Resource3, 8);
6375 poi+=8;
6376 memmove(poi, fx->Resource4, 8);
6377 fx->IsVariable=1;
6379 if (0) printf( "fx_modify_local_variable (%2d): %s, Mod: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
6380 if (fx->Parameter2) {
6381 ieDword var = 0;
6382 //use resource memory area as variable name
6383 target->locals->Lookup(fx->Resource, var);
6384 target->locals->SetAt(fx->Resource, var+fx->Parameter1);
6385 } else {
6386 target->locals->SetAt(fx->Resource, fx->Parameter1);
6388 return FX_NOT_APPLIED;
6391 // 0x136 TimelessState
6392 int fx_timeless_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6394 if (0) printf( "fx_timeless_modifier (%2d): Mod: %d\n", fx->Opcode, fx->Parameter2 );
6395 STAT_SET(IE_DISABLETIMESTOP, fx->Parameter2);
6396 return FX_APPLIED;
6399 //0x137 GenerateWish
6400 #define WISHCOUNT 25
6401 static int wishlevels[WISHCOUNT]={10,10,10,10,0,10,0,15,0,0,0,0,0,0,15,0,0,
6402 17,9,17,17,9,9,9,0};
6404 int fx_generate_wish (Scriptable* Owner, Actor* target, Effect* fx)
6406 ieResRef spl;
6408 if (0) printf( "fx_generate_wish (%2d): Mod: %d\n", fx->Opcode, fx->Parameter2 );
6409 int tmp = core->Roll(1,WISHCOUNT,0);
6410 sprintf(spl,"SPWISH%02d",tmp);
6411 core->ApplySpell(spl, target, Owner, wishlevels[tmp-1]);
6412 return FX_NOT_APPLIED;
6414 //0x138 //see fx_crash, this effect is not fully enabled in original bg2/tob
6415 int fx_immunity_sequester (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6417 if (0) printf( "fx_immunity_sequester (%2d): Mod: %d\n", fx->Opcode, fx->Parameter2 );
6418 //this effect is supposed to provide immunity against sequester (maze/etc?)
6419 STAT_SET(IE_NOSEQUESTER, fx->Parameter2);
6420 return FX_APPLIED;
6423 //0x139 //HLA generic effect
6424 //0x13a StoneSkin2Modifier
6425 int fx_golem_stoneskin_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6427 if (0) printf( "fx_golem_stoneskin_modifier (%2d): Mod: %d\n", fx->Opcode, fx->Parameter1 );
6428 if (!fx->Parameter1) {
6429 return FX_NOT_APPLIED;
6431 //dead actors lose this effect
6432 if (STATE_GET( STATE_DEAD) ) {
6433 return FX_NOT_APPLIED;
6436 STAT_SET(IE_STONESKINSGOLEM, fx->Parameter1);
6437 SetGradient(target, 14);
6438 return FX_APPLIED;
6441 // 0x13b AvatarRemovalModifier (also 0x104 iwd)
6442 int fx_avatar_removal_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6444 if (0) printf( "fx_avatar_removal_modifier (%2d): Mod: %d\n", fx->Opcode, fx->Parameter2 );
6445 STAT_SET(IE_AVATARREMOVAL, fx->Parameter2);
6446 return FX_APPLIED;
6449 // 0x13c MagicalRest (also 0x124 iwd)
6450 int fx_magical_rest (Scriptable* /*Owner*/, Actor* target, Effect* fx)
6452 if (0) printf( "fx_magical_rest (%2d)\n", fx->Opcode );
6453 //instant, full rest
6454 target->Rest(0);
6455 target->fxqueue.RemoveAllEffectsWithParam(fx_display_portrait_icon_ref, PI_FATIGUE);
6456 return FX_NOT_APPLIED;
6459 // 0x13d ImprovedHaste (See 0x10 Haste)
6460 // unknown
6461 int fx_unknown (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
6463 printf( "fx_unknown (%2d): P1: %d P2: %d ResRef: %s\n", fx->Opcode, fx->Parameter1, fx->Parameter2, fx->Resource );
6464 return FX_NOT_APPLIED;
6467 #include "plugindef.h"
6469 GEMRB_PLUGIN(0x1AAA040A, "Effect opcodes for core games")
6470 PLUGIN_INITIALIZER(RegisterCoreOpcodes)
6471 PLUGIN_CLEANUP(Cleanup)
6472 END_PLUGIN()