Files
commandergenius/project/jni/application/gemrb/src/plugins/FXOpcodes/FXOpcodes.cpp
2010-12-14 09:47:29 +00:00

6473 lines
217 KiB
C++

/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "ie_feats.h" //cannot avoid declaring these
#include "opcode_params.h"
#include "overlays.h"
#include "strrefs.h"
#include "win32def.h"
#include "Audio.h"
#include "DisplayMessage.h"
#include "EffectQueue.h"
#include "Game.h"
#include "GameData.h"
#include "Interface.h"
#include "Projectile.h" //needs for clearair
#include "Spell.h" //needed for fx_cast_spell feedback
#include "TileMap.h" //needs for knock!
#include "damages.h"
#include "GameScript/GSUtils.h" //needs for MoveBetweenAreasCore
#include "GUI/GameControl.h"
#include "Scriptable/Actor.h"
#include "PolymorphCache.h" // fx_polymorph
#include "Scriptable/PCStatStruct.h" //fx_polymorph (action definitions)
//FIXME: find a way to handle portrait icons better
#define PI_CONFUSED 3
#define PI_BERSERK 4
#define PI_POISONED 6
#define PI_HELD 13
#define PI_SLEEP 14
#define PI_BLESS 17
#define PI_PANIC 36
#define PI_HASTED 38
#define PI_FATIGUE 39
#define PI_SLOWED 41
#define PI_HOPELESS 44
#define PI_LEVELDRAIN 53
#define PI_FEEBLEMIND 54
#define PI_STUN 55
#define PI_AID 57
#define PI_HOLY 59
#define PI_BOUNCE 65
#define PI_BOUNCE2 67
#define PI_BLOODRAGE 76 //iwd2
#define PI_MAZE 78
#define PI_PRISON 79
#define PI_STONESKIN 80
#define PI_DEAFNESS 83 //iwd2
#define PI_SEQUENCER 92
#define PI_BLUR 109
#define PI_IMPROVEDHASTE 110
#define PI_SPELLTRAP 117
#define PI_CSHIELD 162
#define PI_CSHIELD2 163
static ieResRef *casting_glows = NULL;
static int cgcount = -1;
static ieResRef *spell_hits = NULL;
static bool enhanced_effects = false;
static int shcount = -1;
static int *spell_abilities = NULL;
static ieDword splabcount = 0;
static int *polymorph_stats = NULL;
static int polystatcount = 0;
static bool pstflags = false;
//the original engine stores the colors in sprklclr.2da in a different order
static ScriptedAnimation default_spell_hit;
int fx_ac_vs_damage_type_modifier (Scriptable* Owner, Actor* target, Effect* fx);//00
int fx_attacks_per_round_modifier (Scriptable* Owner, Actor* target, Effect* fx);//01
int fx_cure_sleep_state (Scriptable* Owner, Actor* target, Effect* fx);//02
int fx_set_berserk_state (Scriptable* Owner, Actor* target, Effect* fx);//03
int fx_cure_berserk_state (Scriptable* Owner, Actor* target, Effect* fx);//04
int fx_set_charmed_state (Scriptable* Owner, Actor* target, Effect* fx);//05
int fx_charisma_modifier (Scriptable* Owner, Actor* target, Effect* fx);//06
int fx_set_color_gradient (Scriptable* Owner, Actor* target, Effect* fx);//07
int fx_set_color_rgb (Scriptable* Owner, Actor* target, Effect* fx);//08
int fx_set_color_rgb_global (Scriptable* Owner, Actor* target, Effect* fx);//08
int fx_set_color_pulse_rgb (Scriptable* Owner, Actor* target, Effect* fx);//09
int fx_set_color_pulse_rgb_global (Scriptable* Owner, Actor* target, Effect* fx);//09
int fx_constitution_modifier (Scriptable* Owner, Actor* target, Effect* fx);//0a
int fx_cure_poisoned_state (Scriptable* Owner, Actor* target, Effect* fx);//0b
int fx_damage (Scriptable* Owner, Actor* target, Effect* fx);//0c
int fx_death (Scriptable* Owner, Actor* target, Effect* fx);//0d
int fx_cure_frozen_state (Scriptable* Owner, Actor* target, Effect* fx);//0e
int fx_dexterity_modifier (Scriptable* Owner, Actor* target, Effect* fx);//0f
int fx_set_hasted_state (Scriptable* Owner, Actor* target, Effect* fx);//10
int fx_current_hp_modifier (Scriptable* Owner, Actor* target, Effect* fx);//11
int fx_maximum_hp_modifier (Scriptable* Owner, Actor* target, Effect* fx);//12
int fx_intelligence_modifier (Scriptable* Owner, Actor* target, Effect* fx);//13
int fx_set_invisible_state (Scriptable* Owner, Actor* target, Effect* fx);//14
int fx_lore_modifier (Scriptable* Owner, Actor* target, Effect* fx);//15
int fx_luck_modifier (Scriptable* Owner, Actor* target, Effect* fx);//16
int fx_morale_modifier (Scriptable* Owner, Actor* target, Effect* fx);//17
int fx_set_panic_state (Scriptable* Owner, Actor* target, Effect* fx);//18
int fx_set_poisoned_state (Scriptable* Owner, Actor* target, Effect* fx);//19
int fx_remove_curse (Scriptable* Owner, Actor* target, Effect* fx);//1a
int fx_acid_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//1b
int fx_cold_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//1c
int fx_electricity_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//1d
int fx_fire_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//1e
int fx_magic_damage_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//1f
int fx_cure_dead_state (Scriptable* Owner, Actor* target, Effect* fx);//20
int fx_save_vs_death_modifier (Scriptable* Owner, Actor* target, Effect* fx);//21
int fx_save_vs_wands_modifier (Scriptable* Owner, Actor* target, Effect* fx);//22
int fx_save_vs_poly_modifier (Scriptable* Owner, Actor* target, Effect* fx);//23
int fx_save_vs_breath_modifier (Scriptable* Owner, Actor* target, Effect* fx);//24
int fx_save_vs_spell_modifier (Scriptable* Owner, Actor* target, Effect* fx);//25
int fx_set_silenced_state (Scriptable* Owner, Actor* target, Effect* fx);//26
int fx_set_unconscious_state (Scriptable* Owner, Actor* target, Effect* fx);//27
int fx_set_slowed_state (Scriptable* Owner, Actor* target, Effect* fx);//28
int fx_sparkle(Scriptable* Owner, Actor* target, Effect* fx);//29
int fx_bonus_wizard_spells (Scriptable* Owner, Actor* target, Effect* fx);//2a
int fx_cure_petrified_state (Scriptable* Owner, Actor* target, Effect* fx);//2b
int fx_strength_modifier (Scriptable* Owner, Actor* target, Effect* fx);//2c
int fx_set_stun_state (Scriptable* Owner, Actor* target, Effect* fx);//2d
int fx_cure_stun_state (Scriptable* Owner, Actor* target, Effect* fx);//2e
int fx_cure_invisible_state (Scriptable* Owner, Actor* target, Effect* fx);//2f
int fx_cure_silenced_state (Scriptable* Owner, Actor* target, Effect* fx);//30
int fx_wisdom_modifier (Scriptable* Owner, Actor* target, Effect* fx);//31
int fx_brief_rgb (Scriptable* Owner, Actor* target, Effect* fx);//32
int fx_darken_rgb (Scriptable* Owner, Actor* target, Effect* fx);//33
int fx_glow_rgb (Scriptable* Owner, Actor* target, Effect* fx);//34
int fx_animation_id_modifier (Scriptable* Owner, Actor* target, Effect* fx);//35
int fx_to_hit_modifier (Scriptable* Owner, Actor* target, Effect* fx);//36
int fx_kill_creature_type (Scriptable* Owner, Actor* target, Effect* fx);//37
int fx_alignment_invert (Scriptable* Owner, Actor* target, Effect* fx);//38
int fx_alignment_change (Scriptable* Owner, Actor* target, Effect* fx);//39
int fx_dispel_effects (Scriptable* Owner, Actor* target, Effect* fx);//3a
int fx_stealth_modifier (Scriptable* Owner, Actor* target, Effect* fx);//3b
int fx_miscast_magic_modifier (Scriptable* Owner, Actor* target, Effect* fx);//3c
int fx_alchemy_modifier (Scriptable* Owner, Actor* target, Effect* fx);//3d
int fx_bonus_priest_spells (Scriptable* Owner, Actor* target, Effect* fx);//3e
int fx_set_infravision_state (Scriptable* Owner, Actor* target, Effect* fx);//3f
int fx_cure_infravision_state (Scriptable* Owner, Actor* target, Effect* fx);//40
int fx_set_blur_state (Scriptable* Owner, Actor* target, Effect* fx);//41
int fx_transparency_modifier (Scriptable* Owner, Actor* target, Effect* fx);//42
int fx_summon_creature (Scriptable* Owner, Actor* target, Effect* fx);//43
int fx_unsummon_creature (Scriptable* Owner, Actor* target, Effect* fx);//44
int fx_set_nondetection_state (Scriptable* Owner, Actor* target, Effect* fx);//45
int fx_cure_nondetection_state (Scriptable* Owner, Actor* target, Effect* fx);//46
int fx_sex_modifier (Scriptable* Owner, Actor* target, Effect* fx);//47
int fx_ids_modifier (Scriptable* Owner, Actor* target, Effect* fx);//48
int fx_damage_bonus_modifier (Scriptable* Owner, Actor* target, Effect* fx);//49
int fx_set_blind_state (Scriptable* Owner, Actor* target, Effect* fx);//4a
int fx_cure_blind_state (Scriptable* Owner, Actor* target, Effect* fx);//4b
int fx_set_feebleminded_state (Scriptable* Owner, Actor* target, Effect* fx);//4c
int fx_cure_feebleminded_state (Scriptable* Owner, Actor* target, Effect* fx);//4d
int fx_set_diseased_state (Scriptable* Owner, Actor* target, Effect*fx);//4e
int fx_cure_diseased_state (Scriptable* Owner, Actor* target, Effect* fx);//4f
int fx_set_deaf_state (Scriptable* Owner, Actor* target, Effect* fx); //50
int fx_set_deaf_state_iwd2 (Scriptable* Owner, Actor* target, Effect* fx); //50
int fx_cure_deaf_state (Scriptable* Owner, Actor* target, Effect* fx);//51
int fx_set_ai_script (Scriptable* Owner, Actor* target, Effect*fx);//52
int fx_protection_from_projectile (Scriptable* Owner, Actor* target, Effect*fx);//53
int fx_magical_fire_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//54
int fx_magical_cold_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//55
int fx_slashing_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//56
int fx_crushing_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//57
int fx_piercing_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//58
int fx_missiles_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//59
int fx_open_locks_modifier (Scriptable* Owner, Actor* target, Effect* fx);//5a
int fx_find_traps_modifier (Scriptable* Owner, Actor* target, Effect* fx);//5b
int fx_pick_pockets_modifier (Scriptable* Owner, Actor* target, Effect* fx);//5c
int fx_fatigue_modifier (Scriptable* Owner, Actor* target, Effect* fx);//5d
int fx_intoxication_modifier (Scriptable* Owner, Actor* target, Effect* fx);//5e
int fx_tracking_modifier (Scriptable* Owner, Actor* target, Effect* fx);//5f
int fx_level_modifier (Scriptable* Owner, Actor* target, Effect* fx);//60
int fx_strength_bonus_modifier (Scriptable* Owner, Actor* target, Effect* fx);//61
int fx_set_regenerating_state (Scriptable* Owner, Actor* target, Effect* fx);//62
int fx_spell_duration_modifier (Scriptable* Owner, Actor* target, Effect* fx);///63
int fx_generic_effect (Scriptable* Owner, Actor* target, Effect* fx);//64 protection from creature is a generic effect
int fx_protection_opcode(Scriptable* Owner, Actor* target, Effect* fx); //65
int fx_protection_spelllevel (Scriptable* Owner, Actor* target, Effect* fx); //66
int fx_change_name (Scriptable* Owner, Actor* target, Effect* fx);//67
int fx_experience_modifier (Scriptable* Owner, Actor* target, Effect* fx);//68
int fx_gold_modifier (Scriptable* Owner, Actor* target, Effect* fx);//69
int fx_morale_break_modifier (Scriptable* Owner, Actor* target, Effect* fx);//6a
int fx_portrait_change (Scriptable* Owner, Actor* target, Effect* fx);//6b
int fx_reputation_modifier (Scriptable* Owner, Actor* target, Effect* fx);//6c
int fx_hold_creature_no_icon (Scriptable* Owner, Actor* target, Effect* fx);//6d
//int fx_retreat_from (Scriptable* Owner, Actor* target, Effect* fx);//6e reused
int fx_create_magic_item (Scriptable* Owner, Actor* target, Effect* fx);//6f
int fx_remove_item (Scriptable* Owner, Actor* target, Effect* fx);//70
int fx_equip_item (Scriptable* Owner, Actor* target, Effect* fx);//71
int fx_dither (Scriptable* Owner, Actor* target, Effect* fx);//72
int fx_detect_alignment (Scriptable* Owner, Actor* target, Effect* fx);//73
//int fx_cure_improved_invisible_state (Scriptable* Owner, Actor* target, Effect* fx);//74 (2f)
int fx_reveal_area (Scriptable* Owner, Actor* target, Effect* fx);//75
int fx_reveal_creatures (Scriptable* Owner, Actor* target, Effect* fx);//76
int fx_mirror_image (Scriptable* Owner, Actor* target, Effect* fx);//77
int fx_immune_to_weapon (Scriptable* Owner, Actor* target, Effect* fx);//78
int fx_visual_animation_effect (Scriptable* Owner, Actor* target, Effect* fx);//79 unknown
int fx_create_inventory_item (Scriptable* Owner, Actor* target, Effect* fx);//7a
int fx_remove_inventory_item (Scriptable* Owner, Actor* target, Effect* fx);//7b
int fx_dimension_door (Scriptable* Owner, Actor* target, Effect* fx);//7c
int fx_knock (Scriptable* Owner, Actor* target, Effect* fx);//7d
int fx_movement_modifier (Scriptable* Owner, Actor* target, Effect* fx);//7e
int fx_monster_summoning (Scriptable* Owner, Actor* target, Effect* fx);//7f
int fx_set_confused_state (Scriptable* Owner, Actor* target, Effect* fx);//80
int fx_set_aid_state (Scriptable* Owner, Actor* target, Effect* fx);//81
int fx_set_bless_state (Scriptable* Owner, Actor* target, Effect* fx);//82
int fx_set_chant_state (Scriptable* Owner, Actor* target, Effect* fx);//83
int fx_set_holy_state (Scriptable* Owner, Actor* target, Effect* fx);//84
int fx_luck_non_cumulative (Scriptable* Owner, Actor* target, Effect* fx);//85
int fx_luck_cumulative (Scriptable* Owner, Actor* target, Effect* fx);//85
int fx_set_petrified_state (Scriptable* Owner, Actor* target, Effect* fx);//86
int fx_polymorph (Scriptable* Owner, Actor* target, Effect* fx);//87
int fx_force_visible (Scriptable* Owner, Actor* target, Effect* fx);//88
int fx_set_chantbad_state (Scriptable* Owner, Actor* target, Effect* fx);//89
int fx_animation_stance (Scriptable* Owner, Actor* target, Effect* fx);//8a
int fx_display_string (Scriptable* Owner, Actor* target, Effect* fx);//8b
int fx_casting_glow (Scriptable* Owner, Actor* target, Effect* fx);//8c
int fx_visual_spell_hit (Scriptable* Owner, Actor* target, Effect* fx);//8d
int fx_display_portrait_icon (Scriptable* Owner, Actor* target, Effect* fx);//8e
int fx_create_item_in_slot (Scriptable* Owner, Actor* target, Effect* fx);//8f
int fx_disable_button (Scriptable* Owner, Actor* target, Effect* fx);//90
int fx_disable_spellcasting (Scriptable* Owner, Actor* target, Effect* fx);//91
int fx_cast_spell (Scriptable* Owner, Actor* target, Effect *fx);//92
int fx_learn_spell (Scriptable* Owner, Actor* target, Effect *fx);//93
int fx_cast_spell_point (Scriptable* Owner, Actor* target, Effect *fx);//94
int fx_identify (Scriptable* Owner, Actor* target, Effect *fx);//95
int fx_find_traps (Scriptable* Owner, Actor* target, Effect *fx);//96
int fx_replace_creature (Scriptable* Owner, Actor* target, Effect *fx);//97
int fx_play_movie (Scriptable* Owner, Actor* target, Effect* fx);//98
int fx_set_sanctuary_state (Scriptable* Owner, Actor* target, Effect* fx);//99
int fx_set_entangle_state (Scriptable* Owner, Actor* target, Effect* fx);//9a
int fx_set_minorglobe_state (Scriptable* Owner, Actor* target, Effect* fx);//9b
int fx_set_shieldglobe_state (Scriptable* Owner, Actor* target, Effect* fx);//9c
int fx_set_web_state (Scriptable* Owner, Actor* target, Effect* fx);//9d
int fx_set_grease_state (Scriptable* Owner, Actor* target, Effect* fx);//9e
int fx_mirror_image_modifier (Scriptable* Owner, Actor* target, Effect* fx);//9f
int fx_cure_sanctuary_state (Scriptable* Owner, Actor* target, Effect* fx);//a0
int fx_cure_panic_state (Scriptable* Owner, Actor* target, Effect* fx);//a1
int fx_cure_hold_state (Scriptable* Owner, Actor* target, Effect* fx);//a2 //cures 175
int fx_cure_slow_state (Scriptable* Owner, Actor* target, Effect* fx);//a3
int fx_cure_intoxication (Scriptable* Owner, Actor* target, Effect* fx);//a4
int fx_pause_target (Scriptable* Owner, Actor* target, Effect* fx);//a5
int fx_magic_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//a6
int fx_missile_to_hit_modifier (Scriptable* Owner, Actor* target, Effect* fx);//a7
int fx_remove_creature (Scriptable* Owner, Actor* target, Effect* fx);//a8
int fx_disable_portrait_icon (Scriptable* Owner, Actor* target, Effect* fx);//a9
int fx_damage_animation (Scriptable* Owner, Actor* target, Effect* fx);//aa
int fx_add_innate (Scriptable* Owner, Actor* target, Effect* fx);//ab
int fx_remove_spell (Scriptable* Owner, Actor* target, Effect* fx);//ac
int fx_poison_resistance_modifier (Scriptable* Owner, Actor* target, Effect* fx);//ad
int fx_playsound (Scriptable* Owner, Actor* target, Effect* fx);//ae
int fx_hold_creature (Scriptable* Owner, Actor* target, Effect* fx);//af
// this function is exactly the same as 0x7e fx_movement_modifier (in bg2 at least)//b0
int fx_apply_effect (Scriptable* Owner, Actor* target, Effect* fx);//b1
//b2 //hitbonus against creature (generic_effect)
//b3 //damagebonus against creature (generic effect)
//b4 //restrict item (generic effect)
//b5 //restrict itemtype (generic effect)
int fx_apply_effect_item (Scriptable* Owner, Actor* target, Effect* fx);//b6
int fx_apply_effect_item_type (Scriptable* Owner, Actor* target, Effect* fx);//b7
int fx_dontjump_modifier (Scriptable* Owner, Actor* target, Effect* fx);//b8
// this function is exactly the same as 0xaf hold_creature (in bg2 at least) //b9
int fx_move_to_area (Scriptable* Owner, Actor* target, Effect* fx);//ba
int fx_local_variable (Scriptable* Owner, Actor* target, Effect* fx);//bb
int fx_auracleansing_modifier (Scriptable* Owner, Actor* target, Effect* fx);//bc
int fx_castingspeed_modifier (Scriptable* Owner, Actor* target, Effect* fx);//bd
int fx_attackspeed_modifier (Scriptable* Owner, Actor* target, Effect* fx);//be
int fx_castinglevel_modifier (Scriptable* Owner, Actor* target, Effect* fx);//bf
int fx_find_familiar (Scriptable* Owner, Actor* target, Effect* fx);//c0
int fx_see_invisible_modifier (Scriptable* Owner, Actor* target, Effect* fx);//c1
int fx_ignore_dialogpause_modifier (Scriptable* Owner, Actor* target, Effect* fx);//c2
int fx_familiar_constitution_loss (Scriptable* Owner, Actor* target, Effect* fx);//c3
int fx_familiar_marker (Scriptable* Owner, Actor* target, Effect* fx);//c4
int fx_bounce_projectile (Scriptable* Owner, Actor* target, Effect* fx);//c5
int fx_bounce_opcode (Scriptable* Owner, Actor* target, Effect* fx);//c6
int fx_bounce_spelllevel (Scriptable* Owner, Actor* target, Effect* fx);//c7
int fx_bounce_spelllevel_dec (Scriptable* Owner, Actor* target, Effect* fx);//c8
int fx_protection_spelllevel_dec (Scriptable* Owner, Actor* target, Effect* fx);//c9
int fx_bounce_school (Scriptable* Owner, Actor* target, Effect* fx);//ca
int fx_bounce_secondary_type (Scriptable* Owner, Actor* target, Effect* fx);//cb
int fx_protection_school (Scriptable* Owner, Actor* target, Effect* fx); //cc
int fx_protection_secondary_type (Scriptable* Owner, Actor* target, Effect* fx); //cd
int fx_resist_spell (Scriptable* Owner, Actor* target, Effect* fx);//ce
int fx_resist_spell_dec (Scriptable* Owner, Actor* target, Effect* fx);//??
int fx_bounce_spell (Scriptable* Owner, Actor* target, Effect* fx);//cf
int fx_bounce_spell_dec (Scriptable* Owner, Actor* target, Effect* fx);//??
int fx_minimum_hp_modifier (Scriptable* Owner, Actor* target, Effect* fx);//d0
int fx_power_word_kill (Scriptable* Owner, Actor* target, Effect* fx);//d1
int fx_power_word_stun (Scriptable* Owner, Actor* target, Effect* fx);//d2
int fx_imprisonment (Scriptable* Owner, Actor* target, Effect* fx);//d3
int fx_freedom (Scriptable* Owner, Actor* target, Effect* fx);//d4
int fx_maze (Scriptable* Owner, Actor* target, Effect* fx);//d5
int fx_select_spell (Scriptable* Owner, Actor* target, Effect* fx);//d6
int fx_play_visual_effect (Scriptable* Owner, Actor* target, Effect* fx); //d7
int fx_leveldrain_modifier (Scriptable* Owner, Actor* target, Effect* fx);//d8
int fx_power_word_sleep (Scriptable* Owner, Actor* target, Effect* fx);//d9
int fx_stoneskin_modifier (Scriptable* Owner, Actor* target, Effect* fx);//da
//db ac vs creature type (general effect)
int fx_dispel_school (Scriptable* Owner, Actor* target, Effect* fx);//dc
int fx_dispel_secondary_type (Scriptable* Owner, Actor* target, Effect* fx);//dd
int fx_teleport_field (Scriptable* Owner, Actor* target, Effect* fx);//de
int fx_protection_school_dec (Scriptable* Owner, Actor* target, Effect* fx);//df
int fx_cure_leveldrain (Scriptable* Owner, Actor* target, Effect* fx);//e0
int fx_reveal_magic (Scriptable* Owner, Actor* target, Effect* fx);//e1
int fx_protection_secondary_type_dec (Scriptable* Owner, Actor* target, Effect* fx);//e2
int fx_bounce_school_dec (Scriptable* Owner, Actor* target, Effect* fx);//e3
int fx_bounce_secondary_type_dec (Scriptable* Owner, Actor* target, Effect* fx);//e4
int fx_dispel_school_one (Scriptable* Owner, Actor* target, Effect* fx);//e5
int fx_dispel_secondary_type_one (Scriptable* Owner, Actor* target, Effect* fx);//e6
int fx_timestop (Scriptable* Owner, Actor* target, Effect* fx);//e7
int fx_cast_spell_on_condition (Scriptable* Owner, Actor* target, Effect* fx);//e8
int fx_proficiency (Scriptable* Owner, Actor* target, Effect* fx);//e9
int fx_create_contingency (Scriptable* Owner, Actor* target, Effect* fx);//ea
int fx_wing_buffet (Scriptable* Owner, Actor* target, Effect* fx);//eb
int fx_puppet_master (Scriptable* Owner, Actor* target, Effect* fx);//ec
int fx_puppet_marker (Scriptable* Owner, Actor* target, Effect* fx);//ed
int fx_disintegrate (Scriptable* Owner, Actor* target, Effect* fx);//ee
int fx_farsee (Scriptable* Owner, Actor* target, Effect* fx);//ef
int fx_remove_portrait_icon (Scriptable* Owner, Actor* target, Effect* fx);//f0
//f1 control creature (see charm)
int fx_cure_confused_state (Scriptable* Owner, Actor* target, Effect* fx);//f2
int fx_drain_items (Scriptable* Owner, Actor* target, Effect* fx);//f3
int fx_drain_spells (Scriptable* Owner, Actor* target, Effect* fx);//f4
int fx_checkforberserk_modifier (Scriptable* Owner, Actor* target, Effect* fx);//f5
int fx_berserkstage1_modifier (Scriptable* Owner, Actor* target, Effect* fx);//f6
int fx_berserkstage2_modifier (Scriptable* Owner, Actor* target, Effect* fx);//f7
//int fx_melee_effect (Scriptable* Owner, Actor* target, Effect* fx);//f8
//int fx_ranged_effect (Scriptable* Owner, Actor* target, Effect* fx);//f9
int fx_damageluck_modifier (Scriptable* Owner, Actor* target, Effect* fx);//fa
int fx_change_bardsong (Scriptable* Owner, Actor* target, Effect* fx);//fb
int fx_set_area_effect (Scriptable* Owner, Actor* target, Effect* fx);//fc (set trap)
int fx_set_map_note (Scriptable* Owner, Actor* target, Effect* fx);//fd
int fx_remove_map_note (Scriptable* Owner, Actor* target, Effect* fx);//fe
int fx_create_item_days (Scriptable* Owner, Actor* target, Effect* fx);//ff
int fx_store_spell_sequencer (Scriptable* Owner, Actor* target, Effect* fx);//0x100
int fx_create_spell_sequencer (Scriptable* Owner, Actor* target, Effect* fx);//101
int fx_activate_spell_sequencer (Scriptable* Owner, Actor* target, Effect* fx);//102
int fx_spelltrap (Scriptable* Owner, Actor* target, Effect* fx);//103
int fx_crash (Scriptable* Owner, Actor* target, Effect* fx);//104, disabled
int fx_restore_spell_level (Scriptable* Owner, Actor* target, Effect* fx);//105
int fx_visual_range_modifier (Scriptable* Owner, Actor* target, Effect* fx);//106
int fx_backstab_modifier (Scriptable* Owner, Actor* target, Effect* fx);//107
int fx_drop_weapon (Scriptable* Owner, Actor* target, Effect* fx);//108
int fx_modify_global_variable (Scriptable* Owner, Actor* target, Effect* fx);//109
int fx_remove_immunity (Scriptable* Owner, Actor* target, Effect* fx);//10a
int fx_protection_from_string (Scriptable* Owner, Actor* target, Effect* fx);//10b
int fx_explore_modifier (Scriptable* Owner, Actor* target, Effect* fx);//10c
int fx_screenshake (Scriptable* Owner, Actor* target, Effect* fx);//10d
int fx_unpause_caster (Scriptable* Owner, Actor* target, Effect* fx);//10e
int fx_avatar_removal (Scriptable* Owner, Actor* target, Effect* fx);//10f
int fx_apply_effect_repeat (Scriptable* Owner, Actor* target, Effect* fx);//110
int fx_remove_projectile (Scriptable* Owner, Actor* target, Effect* fx);//111
int fx_teleport_to_target (Scriptable* Owner, Actor* target, Effect* fx);//112
int fx_hide_in_shadows_modifier (Scriptable* Owner, Actor* target, Effect* fx);//113
int fx_detect_illusion_modifier (Scriptable* Owner, Actor* target, Effect* fx);//114
int fx_set_traps_modifier (Scriptable* Owner, Actor* target, Effect* fx);//115
int fx_to_hit_bonus_modifier (Scriptable* Owner, Actor* target, Effect* fx);//116
int fx_renable_button (Scriptable* Owner, Actor* target, Effect* fx);//117
int fx_force_surge_modifier (Scriptable* Owner, Actor* target, Effect* fx);//118
int fx_wild_surge_modifier (Scriptable* Owner, Actor* target, Effect* fx);//119
int fx_scripting_state (Scriptable* Owner, Actor* target, Effect* fx);//11a
int fx_apply_effect_curse (Scriptable* Owner, Actor* target, Effect* fx);//11b
int fx_melee_to_hit_modifier (Scriptable* Owner, Actor* target, Effect* fx);//11c
int fx_melee_damage_modifier (Scriptable* Owner, Actor* target, Effect* fx);//11d
int fx_missile_damage_modifier (Scriptable* Owner, Actor* target, Effect* fx);//11e
int fx_no_circle_state (Scriptable* Owner, Actor* target, Effect* fx);//11f
int fx_fist_to_hit_modifier (Scriptable* Owner, Actor* target, Effect* fx);//120
int fx_fist_damage_modifier (Scriptable* Owner, Actor* target, Effect* fx);//121
int fx_title_modifier (Scriptable* Owner, Actor* target, Effect* fx);//122
int fx_disable_overlay_modifier (Scriptable* Owner, Actor* target, Effect* fx);//123
int fx_no_backstab_modifier (Scriptable* Owner, Actor* target, Effect* fx);//124
int fx_offscreenai_modifier (Scriptable* Owner, Actor* target, Effect* fx);//125
int fx_existance_delay_modifier (Scriptable* Owner, Actor* target, Effect* fx);//126
int fx_disable_chunk_modifier (Scriptable* Owner, Actor* target, Effect* fx);//127
int fx_protection_from_animation (Scriptable* Owner, Actor* target, Effect* fx);//128
int fx_protection_from_turn (Scriptable* Owner, Actor* target, Effect* fx);//129
int fx_cutscene2 (Scriptable* Owner, Actor* target, Effect* fx);//12a
int fx_chaos_shield_modifier (Scriptable* Owner, Actor* target, Effect* fx);//12b
int fx_npc_bump (Scriptable* Owner, Actor* target, Effect* fx);//12c
int fx_critical_hit_modifier (Scriptable* Owner, Actor* target, Effect* fx);//12d
int fx_can_use_any_item_modifier (Scriptable* Owner, Actor* target, Effect* fx);//12e
int fx_always_backstab_modifier (Scriptable* Owner, Actor* target, Effect* fx);//12f
int fx_mass_raise_dead (Scriptable* Owner, Actor* target, Effect* fx);//130
int fx_left_to_hit_modifier (Scriptable* Owner, Actor* target, Effect* fx);//131
int fx_right_to_hit_modifier (Scriptable* Owner, Actor* target, Effect* fx);//132
int fx_reveal_tracks (Scriptable* Owner, Actor* target, Effect* fx);//133
int fx_protection_from_tracking (Scriptable* Owner, Actor* target, Effect* fx);//134
int fx_modify_local_variable (Scriptable* Owner, Actor* target, Effect* fx);//135
int fx_timeless_modifier (Scriptable* Owner, Actor* target, Effect* fx);//136
int fx_generate_wish (Scriptable* Owner, Actor* target, Effect* fx);//137
//138 see fx_crash
//139 HLA generic effect
int fx_golem_stoneskin_modifier (Scriptable* Owner, Actor* target, Effect* fx);//13a
int fx_avatar_removal_modifier (Scriptable* Owner, Actor* target, Effect* fx);//13b
int fx_magical_rest (Scriptable* Owner, Actor* target, Effect* fx);//13c
//int fx_improved_haste_state (Scriptable* Owner, Actor* target, Effect* fx);//13d same as haste
int fx_unknown (Scriptable* Owner, Actor* target, Effect* fx);//???
// FIXME: Make this an ordered list, so we could use bsearch!
static EffectRef effectnames[] = {
{ "*Crash*", fx_crash, -1 },
{ "AcidResistanceModifier", fx_acid_resistance_modifier, -1 },
{ "ACVsCreatureType", fx_generic_effect, -1 }, //0xdb
{ "ACVsDamageTypeModifier", fx_ac_vs_damage_type_modifier, -1 },
{ "ACVsDamageTypeModifier2", fx_ac_vs_damage_type_modifier, -1 }, // used in IWD
{ "AidNonCumulative", fx_set_aid_state, -1 },
{ "AIIdentifierModifier", fx_ids_modifier, -1 },
{ "AlchemyModifier", fx_alchemy_modifier, -1 },
{ "Alignment:Change", fx_alignment_change, -1 },
{ "Alignment:Invert", fx_alignment_invert, -1 },
{ "AlwaysBackstab", fx_always_backstab_modifier, -1 },
{ "AnimationIDModifier", fx_animation_id_modifier, -1 },
{ "AnimationStateChange", fx_animation_stance, -1 },
{ "ApplyEffect", fx_apply_effect, -1 },
{ "ApplyEffectCurse", fx_apply_effect_curse, -1 },
{ "ApplyEffectItem", fx_apply_effect_item, -1 },
{ "ApplyEffectItemType", fx_apply_effect_item_type, -1 },
{ "ApplyEffectRepeat", fx_apply_effect_repeat, -1 },
{ "CutScene2", fx_cutscene2, -1 },
{ "AttackSpeedModifier", fx_attackspeed_modifier, -1 },
{ "AttacksPerRoundModifier", fx_attacks_per_round_modifier, -1 },
{ "AuraCleansingModifier", fx_auracleansing_modifier, -1 },
{ "AvatarRemoval", fx_avatar_removal, -1 }, //unknown
{ "AvatarRemovalModifier", fx_avatar_removal_modifier, -1 },
{ "BackstabModifier", fx_backstab_modifier, -1 },
{ "BerserkStage1Modifier", fx_berserkstage1_modifier, -1},
{ "BerserkStage2Modifier", fx_berserkstage2_modifier, -1},
{ "BlessNonCumulative", fx_set_bless_state, -1 },
{ "Bounce:School", fx_bounce_school, -1 },
{ "Bounce:SchoolDec", fx_bounce_school_dec, -1 },
{ "Bounce:SecondaryType", fx_bounce_secondary_type, -1 },
{ "Bounce:SecondaryTypeDec", fx_bounce_secondary_type_dec, -1 },
{ "Bounce:Spell", fx_bounce_spell, -1 },
{ "Bounce:SpellDec", fx_bounce_spell_dec, -1 },
{ "Bounce:SpellLevel", fx_bounce_spelllevel, -1},
{ "Bounce:SpellLevelDec", fx_bounce_spelllevel_dec, -1},
{ "Bounce:Opcode", fx_bounce_opcode, -1 },
{ "Bounce:Projectile", fx_bounce_projectile, -1 },
{ "CantUseItem", fx_generic_effect, -1 },
{ "CantUseItemType", fx_generic_effect, -1 },
{ "CanUseAnyItem", fx_can_use_any_item_modifier, -1 },
{ "CastFromList", fx_select_spell, -1 },
{ "CastingGlow", fx_casting_glow, -1 },
{ "CastingGlow2", fx_casting_glow, -1 }, //used in iwd
{ "CastingLevelModifier", fx_castinglevel_modifier, -1 },
{ "CastingSpeedModifier", fx_castingspeed_modifier, -1 },
{ "CastSpellOnCondition", fx_cast_spell_on_condition, -1 },
{ "ChangeBardSong", fx_change_bardsong, -1 },
{ "ChangeName", fx_change_name, -1 },
{ "ChantBadNonCumulative", fx_set_chantbad_state, -1 },
{ "ChantNonCumulative", fx_set_chant_state, -1 },
{ "ChaosShieldModifier", fx_chaos_shield_modifier, -1 },
{ "CharismaModifier", fx_charisma_modifier, -1 },
{ "CheckForBerserkModifier", fx_checkforberserk_modifier, -1},
{ "ColdResistanceModifier", fx_cold_resistance_modifier, -1 },
{ "Color:BriefRGB", fx_brief_rgb, -1},
{ "Color:GlowRGB", fx_glow_rgb, -1},
{ "Color:DarkenRGB", fx_darken_rgb, -1},
{ "Color:SetPalette", fx_set_color_gradient, -1 },
{ "Color:SetRGB", fx_set_color_rgb, -1 },
{ "Color:SetRGBGlobal", fx_set_color_rgb_global, -1 }, //08
{ "Color:PulseRGB", fx_set_color_pulse_rgb, -1 }, //9
{ "Color:PulseRGBGlobal", fx_set_color_pulse_rgb_global, -1 }, //9
{ "ConstitutionModifier", fx_constitution_modifier, -1 },
{ "ControlCreature", fx_set_charmed_state, -1 }, //0xf1 same as charm
{ "CreateContingency", fx_create_contingency, -1 },
{ "CriticalHitModifier", fx_critical_hit_modifier, -1 },
{ "CrushingResistanceModifier", fx_crushing_resistance_modifier, -1 },
{ "Cure:Berserk", fx_cure_berserk_state, -1 },
{ "Cure:Blind", fx_cure_blind_state, -1 },
{ "Cure:CasterHold", fx_unpause_caster, -1 },
{ "Cure:Confusion", fx_cure_confused_state, -1 },
{ "Cure:Deafness", fx_cure_deaf_state, -1 },
{ "Cure:Death", fx_cure_dead_state, -1 },
{ "Cure:Defrost", fx_cure_frozen_state, -1 },
{ "Cure:Disease", fx_cure_diseased_state, -1 },
{ "Cure:Feeblemind", fx_cure_feebleminded_state, -1 },
{ "Cure:Hold", fx_cure_hold_state, -1 },
{ "Cure:Imprisonment", fx_freedom, -1 },
{ "Cure:Infravision", fx_cure_infravision_state, -1 },
{ "Cure:Intoxication", fx_cure_intoxication, -1 }, //0xa4 (iwd2 has this working)
{ "Cure:Invisible", fx_cure_invisible_state, -1 }, //0x2f
{ "Cure:Invisible2", fx_cure_invisible_state, -1 }, //0x74
//{ "Cure:ImprovedInvisible", fx_cure_improved_invisible_state, -1 },
{ "Cure:LevelDrain", fx_cure_leveldrain, -1}, //restoration
{ "Cure:Nondetection", fx_cure_nondetection_state, -1 },
{ "Cure:Panic", fx_cure_panic_state, -1 },
{ "Cure:Petrification", fx_cure_petrified_state, -1 },
{ "Cure:Poison", fx_cure_poisoned_state, -1 },
{ "Cure:Sanctuary", fx_cure_sanctuary_state, -1 },
{ "Cure:Silence", fx_cure_silenced_state, -1 },
{ "Cure:Sleep", fx_cure_sleep_state, -1 },
{ "Cure:Stun", fx_cure_stun_state, -1 },
{ "CurrentHPModifier", fx_current_hp_modifier, -1 },
{ "Damage", fx_damage, -1 },
{ "DamageAnimation", fx_damage_animation, -1 },
{ "DamageBonusModifier", fx_damage_bonus_modifier, -1 },
{ "DamageLuckModifier", fx_damageluck_modifier, -1 },
{ "DamageVsCreature", fx_generic_effect, -1 },
{ "Death", fx_death, -1 },
{ "Death2", fx_death, -1 }, //(iwd2 effect)
{ "Death3", fx_death, -1 }, //(iwd2 effect too, Banish)
{ "DetectAlignment", fx_detect_alignment, -1 },
{ "DetectIllusionsModifier", fx_detect_illusion_modifier, -1 },
{ "DexterityModifier", fx_dexterity_modifier, -1 },
{ "DimensionDoor", fx_dimension_door, -1 },
{ "DisableButton", fx_disable_button, -1 }, //sets disable button flag
{ "DisableChunk", fx_disable_chunk_modifier, -1 },
{ "DisableOverlay", fx_disable_overlay_modifier, -1 },
{ "DisableCasting", fx_disable_spellcasting, -1 },
{ "Disintegrate", fx_disintegrate, -1 },
{ "DispelEffects", fx_dispel_effects, -1 },
{ "DispelSchool", fx_dispel_school, -1 },
{ "DispelSchoolOne", fx_dispel_school_one, -1 },
{ "DispelSecondaryType", fx_dispel_secondary_type, -1 },
{ "DispelSecondaryTypeOne", fx_dispel_secondary_type_one, -1 },
{ "DisplayString", fx_display_string, -1 },
{ "Dither", fx_dither, -1 },
{ "DontJumpModifier", fx_dontjump_modifier, -1 },
{ "DrainItems", fx_drain_items, -1 },
{ "DrainSpells", fx_drain_spells, -1 },
{ "DropWeapon", fx_drop_weapon, -1 },
{ "ElectricityResistanceModifier", fx_electricity_resistance_modifier, -1 },
{ "ExistanceDelayModifier", fx_existance_delay_modifier , -1 }, //unknown
{ "ExperienceModifier", fx_experience_modifier, -1 },
{ "ExploreModifier", fx_explore_modifier, -1 },
{ "FamiliarBond", fx_familiar_constitution_loss, -1 },
{ "FamiliarMarker", fx_familiar_marker, -1},
{ "Farsee", fx_farsee, -1},
{ "FatigueModifier", fx_fatigue_modifier, -1 },
{ "FindFamiliar", fx_find_familiar, -1 },
{ "FindTraps", fx_find_traps, -1 },
{ "FindTrapsModifier", fx_find_traps_modifier, -1 },
{ "FireResistanceModifier", fx_fire_resistance_modifier, -1 },
{ "FistDamageModifier", fx_fist_damage_modifier, -1 },
{ "FistHitModifier", fx_fist_to_hit_modifier, -1 },
{ "ForceSurgeModifier", fx_force_surge_modifier, -1 },
{ "ForceVisible", fx_force_visible, -1 }, //not invisible but improved invisible
{ "FreeAction", fx_cure_slow_state, -1},
{ "GenerateWish", fx_generate_wish, -1},
{ "GoldModifier", fx_gold_modifier, -1 },
{ "HideInShadowsModifier", fx_hide_in_shadows_modifier, -1},
{ "HLA", fx_generic_effect, -1},
{ "HolyNonCumulative", fx_set_holy_state, -1 },
{ "Icon:Disable", fx_disable_portrait_icon, -1 },
{ "Icon:Display", fx_display_portrait_icon, -1 },
{ "Icon:Remove", fx_remove_portrait_icon, -1 },
{ "Identify", fx_identify, -1 },
{ "IgnoreDialogPause", fx_ignore_dialogpause_modifier, -1 },
{ "IntelligenceModifier", fx_intelligence_modifier, -1 },
{ "IntoxicationModifier", fx_intoxication_modifier, -1 },
{ "InvisibleDetection", fx_see_invisible_modifier, -1 },
{ "Item:CreateDays", fx_create_item_days, -1 },
{ "Item:CreateInSlot", fx_create_item_in_slot, -1 },
{ "Item:CreateInventory", fx_create_inventory_item, -1 },
{ "Item:CreateMagic", fx_create_magic_item, -1 },
{ "Item:Equip", fx_equip_item, -1 }, //71
{ "Item:Remove", fx_remove_item, -1 }, //70
{ "Item:RemoveInventory", fx_remove_inventory_item, -1 },
{ "KillCreatureType", fx_kill_creature_type, -1 },
{ "LevelModifier", fx_level_modifier, -1 },
{ "LevelDrainModifier", fx_leveldrain_modifier, -1 },
{ "LoreModifier", fx_lore_modifier, -1 },
{ "LuckModifier", fx_luck_modifier, -1 },
{ "LuckCumulative", fx_luck_cumulative, -1 },
{ "LuckNonCumulative", fx_luck_non_cumulative, -1 },
{ "MagicalColdResistanceModifier", fx_magical_cold_resistance_modifier, -1 },
{ "MagicalFireResistanceModifier", fx_magical_fire_resistance_modifier, -1 },
{ "MagicalRest", fx_magical_rest, -1 },
{ "MagicDamageResistanceModifier", fx_magic_damage_resistance_modifier, -1 },
{ "MagicResistanceModifier", fx_magic_resistance_modifier, -1 },
{ "MassRaiseDead", fx_mass_raise_dead, -1 },
{ "MaximumHPModifier", fx_maximum_hp_modifier, -1 },
{ "Maze", fx_maze, -1},
{ "MeleeDamageModifier", fx_melee_damage_modifier, -1 },
{ "MeleeHitModifier", fx_melee_to_hit_modifier, -1 },
{ "MinimumHPModifier", fx_minimum_hp_modifier, -1 },
{ "MiscastMagicModifier", fx_miscast_magic_modifier, -1 },
{ "MissileDamageModifier", fx_missile_damage_modifier, -1 },
{ "MissileHitModifier", fx_missile_to_hit_modifier, -1 },
{ "MissilesResistanceModifier", fx_missiles_resistance_modifier, -1 },
{ "MirrorImage", fx_mirror_image, -1 },
{ "MirrorImageModifier", fx_mirror_image_modifier, -1 },
{ "ModifyGlobalVariable", fx_modify_global_variable, -1 },
{ "ModifyLocalVariable", fx_modify_local_variable, -1 },
{ "MonsterSummoning", fx_monster_summoning, -1 },
{ "MoraleBreakModifier", fx_morale_break_modifier, -1 },
{ "MoraleModifier", fx_morale_modifier, -1 },
{ "MovementRateModifier", fx_movement_modifier, -1 }, //fast (7e)
{ "MovementRateModifier2", fx_movement_modifier, -1 },//slow (b0)
{ "MovementRateModifier3", fx_movement_modifier, -1 },//forced (IWD - 10a)
{ "MovementRateModifier4", fx_movement_modifier, -1 },//slow (IWD2 - 1b9)
{ "MoveToArea", fx_move_to_area, -1 }, //0xba
{ "NoCircleState", fx_no_circle_state, -1 },
{ "NPCBump", fx_npc_bump, -1 },
{ "OffscreenAIModifier", fx_offscreenai_modifier, -1 },
{ "OffhandHitModifier", fx_left_to_hit_modifier, -1 },
{ "OpenLocksModifier", fx_open_locks_modifier, -1 },
{ "Overlay:Entangle", fx_set_entangle_state, -1 },
{ "Overlay:Grease", fx_set_grease_state, -1 },
{ "Overlay:MinorGlobe", fx_set_minorglobe_state, -1 },
{ "Overlay:Sanctuary", fx_set_sanctuary_state, -1 },
{ "Overlay:ShieldGlobe", fx_set_shieldglobe_state, -1 },
{ "Overlay:Web", fx_set_web_state, -1 },
{ "PauseTarget", fx_pause_target, -1 }, //also known as casterhold
{ "PickPocketsModifier", fx_pick_pockets_modifier, -1 },
{ "PiercingResistanceModifier", fx_piercing_resistance_modifier, -1 },
{ "PlayMovie", fx_play_movie, -1 },
{ "PlaySound", fx_playsound, -1 },
{ "PlayVisualEffect", fx_play_visual_effect, -1 },
{ "PoisonResistanceModifier", fx_poison_resistance_modifier, -1 },
{ "Polymorph", fx_polymorph, -1},
{ "PortraitChange", fx_portrait_change, -1 },
{ "PowerWordKill", fx_power_word_kill, -1 },
{ "PowerWordSleep", fx_power_word_sleep, -1 },
{ "PowerWordStun", fx_power_word_stun, -1 },
{ "PriestSpellSlotsModifier", fx_bonus_priest_spells, -1 },
{ "Proficiency", fx_proficiency, -1 },
// { "Protection:Animation", fx_protection_from_animation, -1 },
{ "Protection:Animation", fx_generic_effect, -1 },
{ "Protection:Backstab", fx_no_backstab_modifier, -1 },
{ "Protection:Creature", fx_generic_effect, -1 },
{ "Protection:Opcode", fx_protection_opcode, -1 },
{ "Protection:Opcode2", fx_protection_opcode, -1 },
{ "Protection:Projectile",fx_protection_from_projectile, -1},
{ "Protection:School",fx_generic_effect,-1},//overlay?
{ "Protection:SchoolDec",fx_protection_school_dec,-1},//overlay?
{ "Protection:SecondaryType",fx_protection_secondary_type,-1},//overlay?
{ "Protection:SecondaryTypeDec",fx_protection_secondary_type_dec,-1},//overlay?
{ "Protection:Spell",fx_resist_spell,-1},//overlay?
{ "Protection:SpellDec",fx_resist_spell_dec,-1},//overlay?
{ "Protection:SpellLevel",fx_protection_spelllevel,-1},//overlay?
{ "Protection:SpellLevelDec",fx_protection_spelllevel_dec,-1},//overlay?
{ "Protection:String", fx_generic_effect, -1 },
{ "Protection:Tracking", fx_protection_from_tracking, -1 },
{ "Protection:Turn", fx_protection_from_turn, -1},
{ "Protection:Weapons", fx_immune_to_weapon, -1},
{ "PuppetMarker", fx_puppet_marker, -1},
{ "ProjectImage", fx_puppet_master, -1},
{ "Reveal:Area", fx_reveal_area, -1 },
{ "Reveal:Creatures", fx_reveal_creatures, -1 },
{ "Reveal:Magic", fx_reveal_magic, -1 },
{ "Reveal:Tracks", fx_reveal_tracks, -1 },
{ "RemoveCurse", fx_remove_curse, -1 },
{ "RemoveImmunity", fx_remove_immunity, -1 },
{ "RemoveMapNote", fx_remove_map_note, -1 },
{ "RemoveProjectile", fx_remove_projectile, -1 }, //removes effects from actor and area
{ "RenableButton", fx_renable_button, -1 }, //removes disable button flag
{ "RemoveCreature", fx_remove_creature, -1 },
{ "ReplaceCreature", fx_replace_creature, -1 },
{ "ReputationModifier", fx_reputation_modifier, -1 },
{ "RestoreSpells", fx_restore_spell_level, -1 },
{ "RightHitModifier", fx_right_to_hit_modifier, -1 },
{ "SaveVsBreathModifier", fx_save_vs_breath_modifier, -1 },
{ "SaveVsDeathModifier", fx_save_vs_death_modifier, -1 },
{ "SaveVsPolyModifier", fx_save_vs_poly_modifier, -1 },
{ "SaveVsSpellsModifier", fx_save_vs_spell_modifier, -1 },
{ "SaveVsWandsModifier", fx_save_vs_wands_modifier, -1 },
{ "ScreenShake", fx_screenshake, -1 },
{ "ScriptingState", fx_scripting_state, -1 },
{ "Sequencer:Activate", fx_activate_spell_sequencer, -1 },
{ "Sequencer:Create", fx_create_spell_sequencer, -1 },
{ "Sequencer:Store", fx_store_spell_sequencer, -1 },
{ "SetAIScript", fx_set_ai_script, -1 },
{ "SetMapNote", fx_set_map_note, -1 },
{ "SetMeleeEffect", fx_generic_effect, -1 },
{ "SetRangedEffect", fx_generic_effect, -1 },
{ "SetTrap", fx_set_area_effect, -1 },
{ "SetTrapsModifier", fx_set_traps_modifier, -1 },
{ "SexModifier", fx_sex_modifier, -1 },
{ "SlashingResistanceModifier", fx_slashing_resistance_modifier, -1 },
{ "Sparkle", fx_sparkle, -1 },
{ "SpellDurationModifier", fx_spell_duration_modifier, -1 },
{ "Spell:Add", fx_add_innate, -1 },
{ "Spell:Cast", fx_cast_spell, -1 },
{ "Spell:CastPoint", fx_cast_spell_point, -1 },
{ "Spell:Learn", fx_learn_spell, -1 },
{ "Spell:Remove", fx_remove_spell, -1 },
{ "Spelltrap",fx_spelltrap , -1 }, //overlay: spmagglo
{ "State:Berserk", fx_set_berserk_state, -1 },
{ "State:Blind", fx_set_blind_state, -1 },
{ "State:Blur", fx_set_blur_state, -1 },
{ "State:Charmed", fx_set_charmed_state, -1 }, //0x05
{ "State:Confused", fx_set_confused_state, -1 },
{ "State:Deafness", fx_set_deaf_state, -1 },
{ "State:DeafnessIWD2", fx_set_deaf_state_iwd2, -1 }, //this is a modified version
{ "State:Diseased", fx_set_diseased_state, -1 },
{ "State:Feeblemind", fx_set_feebleminded_state, -1 },
{ "State:Hasted", fx_set_hasted_state, -1 },
{ "State:Haste2", fx_set_hasted_state, -1 },
{ "State:Hold", fx_hold_creature, -1 }, //175 (doesn't work in original iwd2)
{ "State:Hold2", fx_hold_creature, -1 },//185 (doesn't work in original iwd2)
{ "State:Hold3", fx_hold_creature, -1 },//109 iwd2
{ "State:HoldNoIcon", fx_hold_creature_no_icon, -1 }, //109
{ "State:HoldNoIcon2", fx_hold_creature_no_icon, -1 }, //0xfb (iwd/iwd2)
{ "State:HoldNoIcon3", fx_hold_creature_no_icon, -1 }, //0x1a8 (iwd2)
{ "State:Imprisonment", fx_imprisonment, -1 },
{ "State:Infravision", fx_set_infravision_state, -1 },
{ "State:Invisible", fx_set_invisible_state, -1 }, //both invis or improved invis
{ "State:Nondetection", fx_set_nondetection_state, -1 },
{ "State:Panic", fx_set_panic_state, -1 },
{ "State:Petrification", fx_set_petrified_state, -1 },
{ "State:Poisoned", fx_set_poisoned_state, -1 },
{ "State:Regenerating", fx_set_regenerating_state, -1 },
{ "State:Silenced", fx_set_silenced_state, -1 },
{ "State:Helpless", fx_set_unconscious_state, -1 },
{ "State:Sleep", fx_set_unconscious_state, -1},
{ "State:Slowed", fx_set_slowed_state, -1 },
{ "State:Stun", fx_set_stun_state, -1 },
{ "StealthModifier", fx_stealth_modifier, -1 },
{ "StoneSkinModifier", fx_stoneskin_modifier, -1 },
{ "StoneSkin2Modifier", fx_golem_stoneskin_modifier, -1 },
{ "StrengthModifier", fx_strength_modifier, -1 },
{ "StrengthBonusModifier", fx_strength_bonus_modifier, -1 },
{ "SummonCreature", fx_summon_creature, -1 },
{ "RandomTeleport", fx_teleport_field, -1 },
{ "TeleportToTarget", fx_teleport_to_target, -1 },
{ "TimelessState", fx_timeless_modifier, -1 },
{ "Timestop", fx_timestop, -1},
{ "TitleModifier", fx_title_modifier, -1 },
{ "ToHitModifier", fx_to_hit_modifier, -1 },
{ "ToHitBonusModifier", fx_to_hit_bonus_modifier, -1 },
{ "ToHitVsCreature", fx_generic_effect, -1 },
{ "TrackingModifier", fx_tracking_modifier, -1 },
{ "TransparencyModifier", fx_transparency_modifier, -1 },
{ "Unknown", fx_unknown, -1},
{ "Unlock", fx_knock, -1 }, //open doors/containers
{ "UnsummonCreature", fx_unsummon_creature, -1 },
{ "Variable:StoreLocalVariable", fx_local_variable, -1 },
{ "VisualAnimationEffect", fx_visual_animation_effect, -1 }, //unknown
{ "VisualRangeModifier", fx_visual_range_modifier, -1 },
{ "VisualSpellHit", fx_visual_spell_hit, -1 },
{ "WildSurgeModifier", fx_wild_surge_modifier, -1 },
{ "WingBuffet", fx_wing_buffet, -1 },
{ "WisdomModifier", fx_wisdom_modifier, -1 },
{ "WizardSpellSlotsModifier", fx_bonus_wizard_spells, -1 },
{ NULL, NULL, 0 },
};
static void Cleanup()
{
core->FreeResRefTable(casting_glows, cgcount);
core->FreeResRefTable(spell_hits, shcount);
if(spell_abilities) free(spell_abilities);
spell_abilities=NULL;
if(polymorph_stats) free(polymorph_stats);
polymorph_stats=NULL;
}
void RegisterCoreOpcodes()
{
core->RegisterOpcodes( sizeof( effectnames ) / sizeof( EffectRef ) - 1, effectnames );
enhanced_effects=!!core->HasFeature(GF_ENHANCED_EFFECTS);
pstflags=!!core->HasFeature(GF_PST_STATE_FLAGS);
default_spell_hit.SequenceFlags|=IE_VVC_BAM;
}
static inline void SetGradient(Actor *target, ieDword gradient)
{
gradient |= (gradient <<16);
gradient |= (gradient <<8);
for(int i=0;i<7;i++) {
STAT_SET(IE_COLORS+i, gradient);
}
}
static inline void HandleBonus(Actor *target, int stat, int mod, int mode)
{
if (mode==FX_DURATION_INSTANT_PERMANENT) {
if (target->IsReverseToHit()) {
BASE_SUB( stat, mod );
} else {
BASE_ADD( stat, mod );
}
return;
}
if (target->IsReverseToHit()) {
STAT_SUB( stat, mod );
} else {
STAT_ADD( stat, mod );
}
}
//whoseeswho:
#define ENEMY_SEES_ORIGIN 1
#define ORIGIN_SEES_ENEMY 2
inline Actor *GetNearestEnemyOf(Map *map, Actor *origin, int whoseeswho)
{
//determining the allegiance of the origin
int type = GetGroup(origin);
//neutral has no enemies
if (type==2) {
return NULL;
}
Targets *tgts = new Targets();
int i = map->GetActorCount(true);
Actor *ac;
while (i--) {
ac=map->GetActor(i,true);
int distance = Distance(ac, origin);
if (whoseeswho&ENEMY_SEES_ORIGIN) {
if (!CanSee(ac, origin, true, GA_NO_DEAD)) {
continue;
}
}
if (whoseeswho&ORIGIN_SEES_ENEMY) {
if (!CanSee(ac, origin, true, GA_NO_DEAD)) {
continue;
}
}
if (type) { //origin is PC
if (ac->GetStat(IE_EA) >= EA_EVILCUTOFF) {
tgts->AddTarget(ac, distance, GA_NO_DEAD);
}
}
else {
if (ac->GetStat(IE_EA) <= EA_GOODCUTOFF) {
tgts->AddTarget(ac, distance, GA_NO_DEAD);
}
}
}
ac = (Actor *) tgts->GetTarget(0, ST_ACTOR);
delete tgts;
return ac;
}
inline Scriptable *GetCaster(Scriptable *Owner, Effect *fx) {
if (fx->FirstApply) {
fx->CasterID = Owner ? Owner->GetGlobalID() : 0;
return Owner;
} else {
return core->GetGame()->GetActorByGlobalID(fx->CasterID);
}
return NULL;
}
//resurrect code used in many places
void Resurrect(Scriptable *Owner, Actor *target, Effect *fx, Point &p)
{
Scriptable *caster = GetCaster(Owner, fx);
if (!caster) {
caster = Owner; // IE stores the enemyally in the effect instead
}
Map *area = caster->GetCurrentArea();
if (area && target->GetCurrentArea()!=area) {
MoveBetweenAreasCore(target, area->GetScriptName(), p, fx->Parameter2, true);
}
target->Resurrect();
}
// handles the percentage damage spread over time by converting it to absolute damage
inline void HandlePercentageDamage(Effect *fx, Actor *target) {
if (fx->Parameter2 == RPD_PERCENT && fx->FirstApply) {
// distribute the damage to one second intervals
int seconds = (fx->Duration - core->GetGame()->GameTime) / AI_UPDATE_TIME;
fx->Parameter1 = target->GetStat(IE_MAXHITPOINTS) * fx->Parameter1 / 100 / seconds;
}
}
// Effect opcodes
// 0x00 ACVsDamageTypeModifier
int fx_ac_vs_damage_type_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
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 );
//check level was pulled outside as a common functionality
//CHECK_LEVEL();
// it is a bitmask
int type = fx->Parameter2;
if (type == 0) {
HandleBonus(target, IE_ARMORCLASS, fx->Parameter1, fx->TimingMode);
return FX_PERMANENT;
}
//convert to signed so -1 doesn't turn to an astronomical number
if (type == 16) {
if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
if ((signed)BASE_GET( IE_ARMORCLASS) > (signed)fx->Parameter1) {
BASE_SET( IE_ARMORCLASS, fx->Parameter1 );
}
} else {
if ((signed)STAT_GET( IE_ARMORCLASS) > (signed)fx->Parameter1) {
STAT_SET( IE_ARMORCLASS, fx->Parameter1 );
}
}
return FX_INSERT;
}
//the original engine did work with the combination of these bits
//but since it crashed, we are not bound to the same rules
if (type & 1) {
HandleBonus(target, IE_ACCRUSHINGMOD, fx->Parameter1, fx->TimingMode);
}
if (type & 2) {
HandleBonus(target, IE_ACMISSILEMOD, fx->Parameter1, fx->TimingMode);
}
if (type & 4) {
HandleBonus(target, IE_ACPIERCINGMOD, fx->Parameter1, fx->TimingMode);
}
if (type & 8) {
HandleBonus(target, IE_ACSLASHINGMOD, fx->Parameter1, fx->TimingMode);
}
return FX_PERMANENT;
}
// 0x01 AttacksPerRoundModifier
int fx_attacks_per_round_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_attacks_per_round_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
int tmp = (signed) fx->Parameter1;
if (fx->Parameter2!=2) {
if (tmp>10) tmp=10;
else if (tmp<-10) tmp=-10;
tmp <<= 1;
if (tmp>10) tmp-=11;
else if (tmp<-10) tmp+=11;
}
if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
BASE_MOD_VAR(IE_NUMBEROFATTACKS, tmp);
} else {
STAT_MOD_VAR(IE_NUMBEROFATTACKS, tmp);
}
return FX_PERMANENT;
}
// 0x02 Cure:Sleep (Awaken)
// this effect clears the STATE_SLEEP (1) bit, but clearing it alone wouldn't remove the
// unconscious effect, which is combined with STATE_HELPLESS (0x20+1)
static EffectRef fx_set_sleep_state_ref={"State:Helpless",NULL,-1};
//this reference is used by many other effects
static EffectRef fx_display_portrait_icon_ref={"Icon:Display",NULL,-1};
int fx_cure_sleep_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_sleep_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
BASE_STATE_CURE( STATE_SLEEP );
target->fxqueue.RemoveAllEffects(fx_set_sleep_state_ref);
target->fxqueue.RemoveAllEffectsWithParam(fx_display_portrait_icon_ref, PI_SLEEP);
return FX_NOT_APPLIED;
}
// 0x03 State:Berserk
// this effect sets the STATE_BERSERK bit, but bg2 actually ignores the bit
int fx_set_berserk_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_berserk_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
// atleast how and bg2 allow this to only work on pcs
if (!core->HasFeature(GF_3ED_RULES) && !target->InParty) {
return FX_NOT_APPLIED;
}
if (fx->FirstApply) {
target->inventory.EquipBestWeapon(EQUIP_MELEE);
}
if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
BASE_STATE_SET( STATE_BERSERK );
} else {
STATE_SET( STATE_BERSERK );
}
switch(fx->Parameter2) {
case 1: //always berserk
target->SetSpellState(SS_BERSERK);
default:
target->AddPortraitIcon(PI_BERSERK);
break;
case 2: //blood rage
target->SetSpellState(SS_BERSERK);
//immunity to effects:
//5 charm
//0x11 heal
//0x18 panic
//0x27 sleep
//0x2d stun
//0x6d hold
//0x80 confusion
//400 hopelessness
//
target->SetSpellState(SS_BLOODRAGE);
target->SetSpellState(SS_NOHPINFO);
target->SetColorMod(0xff, RGBModifier::ADD, 15, 128, 0, 0);
target->AddPortraitIcon(PI_BLOODRAGE);
break;
}
return FX_PERMANENT;
}
// 0x04 Cure:Berserk
// this effect clears the STATE_BERSERK (2) bit, but bg2 actually ignores the bit
// it also removes effect 04
static EffectRef fx_set_berserk_state_ref={"State:Berserk",NULL,-1};
int fx_cure_berserk_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_berserk_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
BASE_STATE_CURE( STATE_BERSERK );
target->fxqueue.RemoveAllEffects(fx_set_berserk_state_ref);
return FX_NOT_APPLIED;
}
// 0x05 State:Charmed
// 0xf1 ControlCreature (iwd2)
int fx_set_charmed_state (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_charmed_state (%2d): General: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//blood rage berserking gives immunity to charm (in iwd2)
if (target->HasSpellState(SS_BLOODRAGE)) {
return FX_NOT_APPLIED;
}
//protection from evil gives immunity to charm (in iwd2)
if (target->HasSpellState(SS_PROTFROMEVIL)) {
return FX_NOT_APPLIED;
}
if (fx->Parameter1 && (STAT_GET(IE_GENERAL)!=fx->Parameter1)) {
return FX_NOT_APPLIED;
}
Scriptable *caster = GetCaster(Owner, fx);
if (!caster) caster = Owner; // IE stores the enemyally in the effect instead
bool enemyally = true;
if (caster->Type==ST_ACTOR) {
enemyally = ((Actor *) caster)->GetStat(IE_EA)>EA_GOODCUTOFF; //or evilcutoff?
}
switch (fx->Parameter2) {
case 0: //charmed (target neutral after charm)
if (fx->FirstApply) {
displaymsg->DisplayConstantStringName(STR_CHARMED, 0xf0f0f0, target);
}
case 1000:
break;
case 1: //charmed (target hostile after charm)
if (fx->FirstApply) {
displaymsg->DisplayConstantStringName(STR_CHARMED, 0xf0f0f0, target);
}
case 1001:
if (!target->InParty) {
target->SetBaseNoPCF(IE_EA, EA_ENEMY);
}
break;
case 2: //dire charmed (target neutral after charm)
if (fx->FirstApply) {
displaymsg->DisplayConstantStringName(STR_DIRECHARMED, 0xf0f0f0, target);
}
case 1002:
break;
case 3: //dire charmed (target hostile after charm)
if (fx->FirstApply) {
displaymsg->DisplayConstantStringName(STR_DIRECHARMED, 0xf0f0f0, target);
}
case 1003:
if (!target->InParty) {
target->SetBaseNoPCF(IE_EA, EA_ENEMY);
}
break;
case 4: //controlled by cleric
if (fx->FirstApply) {
displaymsg->DisplayConstantStringName(STR_CONTROLLED, 0xf0f0f0, target);
}
case 1004:
if (!target->InParty) {
target->SetBaseNoPCF(IE_EA, EA_ENEMY);
}
break;
case 5: //thrall (typo comes from original engine doc)
if (fx->FirstApply) {
displaymsg->DisplayConstantStringName(STR_CHARMED, 0xf0f0f0, target);
}
case 1005:
STAT_SET(IE_EA, EA_ENEMY );
STAT_SET(IE_THRULLCHARM, 1);
return FX_PERMANENT;
}
STATE_SET( STATE_CHARMED );
STAT_SET_PCF( IE_EA, enemyally?EA_ENEMY:EA_CHARMED );
//don't stick if permanent
return FX_PERMANENT;
}
// 0x06 CharismaModifier
int fx_charisma_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_charisma_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
BASE_MOD( IE_CHR );
} else {
STAT_MOD( IE_CHR );
}
return FX_PERMANENT;
}
// 0x07 Color:SetPalette
// this effect might not work in pst, they don't have separate weapon slots
int fx_set_color_gradient (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_color_gradient (%2d): Gradient: %d, Location: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
EffectQueue::HackColorEffects(target, fx);
target->SetColor( fx->Parameter2, fx->Parameter1 );
return FX_APPLIED;
}
// 08 Color:SetRGB
int fx_set_color_rgb (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_color_rgb (%2d): RGB: %x, Location: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
EffectQueue::HackColorEffects(target, fx);
ieDword location = fx->Parameter2 & 0xff;
target->SetColorMod(location, RGBModifier::ADD, -1, fx->Parameter1 >> 8,
fx->Parameter1 >> 16, fx->Parameter1 >> 24);
return FX_APPLIED;
}
// 08 Color:SetRGBGlobal
int fx_set_color_rgb_global (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_color_rgb_global (%2d): RGB: %x, Location: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
target->SetColorMod(0xff, RGBModifier::ADD, -1, fx->Parameter1 >> 8,
fx->Parameter1 >> 16, fx->Parameter1 >> 24);
return FX_APPLIED;
}
// 09 Color:PulseRGB
int fx_set_color_pulse_rgb (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_color_pulse_rgb (%2d): RGB: %x, Location: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
EffectQueue::HackColorEffects(target, fx);
ieDword location = fx->Parameter2 & 0xff;
int speed = (fx->Parameter2 >> 16) & 0xFF;
target->SetColorMod(location, RGBModifier::ADD, speed,
fx->Parameter1 >> 8, fx->Parameter1 >> 16,
fx->Parameter1 >> 24);
return FX_APPLIED;
}
// 09 Color:PulseRGBGlobal (pst variant)
int fx_set_color_pulse_rgb_global (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_color_pulse_rgb_global (%2d): RGB: %x, Location: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
int speed = (fx->Parameter2 >> 16) & 0xFF;
target->SetColorMod(0xff, RGBModifier::ADD, speed,
fx->Parameter1 >> 8, fx->Parameter1 >> 16,
fx->Parameter1 >> 24);
return FX_APPLIED;
}
// 0x0A ConstitutionModifier
int fx_constitution_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_constitution_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
BASE_MOD( IE_CON );
} else {
STAT_MOD( IE_CON );
}
return FX_PERMANENT;
}
// 0x0B Cure:Poison
static EffectRef fx_poisoned_state_ref={"State:Poisoned",NULL,-1};
int fx_cure_poisoned_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_poisoned_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//all three steps are present in bg2 and iwd2
BASE_STATE_CURE( STATE_POISONED );
target->fxqueue.RemoveAllEffects( fx_poisoned_state_ref );
target->fxqueue.RemoveAllEffectsWithParam(fx_display_portrait_icon_ref, PI_POISONED);
return FX_NOT_APPLIED;
}
// 0x0c Damage
// this is a very important effect
int fx_damage (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_damage (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//save for half damage type
ieDword damagetype = fx->Parameter2>>16;
ieDword modtype = fx->Parameter2&3;
if (modtype==3) {
modtype&=~3;
}
Scriptable *caster = GetCaster(Owner, fx);
target->Damage(fx->Parameter1, damagetype, caster, modtype);
//this effect doesn't stick
return FX_NOT_APPLIED;
}
// 0x0d Death
int fx_death (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_death (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
ieDword damagetype = 0;
switch (fx->Parameter2) {
case 1:
BASE_STATE_SET(STATE_D4); //not sure, should be charred
damagetype = DAMAGE_FIRE;
break;
case 2:
damagetype = DAMAGE_CRUSHING;
break;
case 4:
damagetype = DAMAGE_CRUSHING;
break;
case 8:
damagetype = DAMAGE_CRUSHING|DAMAGE_CHUNKING;
break;
case 16:
BASE_STATE_SET(STATE_PETRIFIED);
damagetype = DAMAGE_CRUSHING;
break;
case 32:
BASE_STATE_SET(STATE_FROZEN);
damagetype = DAMAGE_COLD;
break;
case 64:
BASE_STATE_SET(STATE_PETRIFIED);
damagetype = DAMAGE_CRUSHING|DAMAGE_CHUNKING;
break;
case 128:
BASE_STATE_SET(STATE_FROZEN);
damagetype = DAMAGE_COLD|DAMAGE_CHUNKING;
break;
case 256:
damagetype = DAMAGE_ELECTRICITY;
break;
case 512:
default:
damagetype = DAMAGE_ACID;
}
target->Damage(0, damagetype, Owner);
//death has damage type too
target->Die(Owner);
//this effect doesn't stick
return FX_NOT_APPLIED;
}
// 0xE Cure:Defrost
int fx_cure_frozen_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_frozen_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
BASE_STATE_CURE( STATE_FROZEN );
return FX_NOT_APPLIED;
}
// 0x0F DexterityModifier
#define CSA_DEX 0
#define CSA_STR 1
#define CSA_CNT 2
int SpellAbilityDieRoll(Actor *target, int which)
{
if (which>=CSA_CNT) return 6;
ieDword cls = STAT_GET(IE_CLASS);
if (!spell_abilities) {
AutoTable tab("clssplab");
if (!tab) {
spell_abilities = (int *) malloc(sizeof(int)*CSA_CNT);
for (int ab=0;ab<CSA_CNT;ab++) {
spell_abilities[ab*splabcount]=6;
}
splabcount=1;
return 6;
}
splabcount = tab->GetRowCount();
spell_abilities=(int *) malloc(sizeof(int)*splabcount*CSA_CNT);
for (int ab=0;ab<CSA_CNT;ab++) {
for (ieDword i=0;i<splabcount;i++) {
spell_abilities[ab*splabcount+i]=atoi(tab->QueryField(i,ab));
}
}
}
if (cls>=splabcount) cls=0;
return spell_abilities[which*splabcount+cls];
}
int fx_dexterity_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_dexterity_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
////how cat's grace: value is based on class
if (fx->Parameter2==3) {
fx->Parameter1 = core->Roll(1,SpellAbilityDieRoll(target,0),0);
fx->Parameter2 = 0;
}
if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
BASE_MOD( IE_DEX );
} else {
STAT_MOD( IE_DEX );
}
return FX_PERMANENT;
}
static EffectRef fx_set_slow_state_ref={"State:Slowed",NULL,-1};
// 0x10 State:Hasted
// this function removes slowed state, or sets hasted state
int fx_set_hasted_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_hasted_state (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
target->fxqueue.RemoveAllEffects(fx_set_slow_state_ref);
target->fxqueue.RemoveAllEffectsWithParam( fx_display_portrait_icon_ref, PI_SLOWED );
if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
BASE_STATE_CURE( STATE_SLOWED );
BASE_STATE_SET( STATE_HASTED );
} else {
STATE_CURE( STATE_SLOWED );
STATE_SET( STATE_HASTED );
}
target->NewStat(IE_MOVEMENTRATE, 200, MOD_PERCENT);
switch (fx->Parameter2) {
case 0: //normal haste
target->AddPortraitIcon(PI_HASTED);
STAT_SET(IE_IMPROVEDHASTE,0);
STAT_SET(IE_ATTACKNUMBERDOUBLE,0);
STAT_ADD(IE_NUMBEROFATTACKS, 2);
// -2 initiative bonus
STAT_ADD(IE_PHYSICALSPEED, 2);
break;
case 1://improved haste
target->AddPortraitIcon(PI_IMPROVEDHASTE);
STAT_SET(IE_IMPROVEDHASTE,1);
STAT_SET(IE_ATTACKNUMBERDOUBLE,0);
target->NewStat(IE_NUMBEROFATTACKS, 200, MOD_PERCENT);
// -2 initiative bonus
STAT_ADD(IE_PHYSICALSPEED, 2);
break;
case 2://speed haste only
target->AddPortraitIcon(PI_HASTED);
STAT_SET(IE_IMPROVEDHASTE,0);
STAT_SET(IE_ATTACKNUMBERDOUBLE,1);
break;
}
return FX_PERMANENT;
}
// 0x11 CurrentHPModifier
int fx_current_hp_modifier (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_current_hp_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (fx->Parameter2&0x10000) {
Point p(fx->PosX, fx->PosY);
Resurrect(Owner, target, fx, p);
}
if (fx->Parameter2&0x20000) {
target->fxqueue.RemoveAllNonPermanentEffects();
}
//Cannot heal bloodrage
if (target->HasSpellState(SS_BLOODRAGE)) {
return FX_NOT_APPLIED;
}
//current hp percent is relative to modified max hp
switch(fx->Parameter2&0xffff) {
case MOD_ADDITIVE:
case MOD_ABSOLUTE:
target->NewBase( IE_HITPOINTS, fx->Parameter1, fx->Parameter2&0xffff);
break;
case MOD_PERCENT:
target->NewBase( IE_HITPOINTS, target->GetSafeStat(IE_MAXHITPOINTS)*fx->Parameter1/100, MOD_ABSOLUTE);
}
//never stay permanent
return FX_NOT_APPLIED;
}
// 0x12 MaximumHPModifier
// 0 and 3 differ in that 3 doesn't modify current hitpoints
// 1,4 and 2,5 are analogous to them, but with different modifiers
int fx_maximum_hp_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_maximum_hp_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (STATE_GET( STATE_DEAD|STATE_PETRIFIED|STATE_FROZEN) ) {
return FX_NOT_APPLIED;
}
bool base = fx->TimingMode==FX_DURATION_INSTANT_PERMANENT;
switch (fx->Parameter2) {
case 0:
// random value Parameter1 is set by level_check in EffectQueue
if (base) {
BASE_ADD( IE_MAXHITPOINTS, fx->Parameter1 );
BASE_ADD( IE_HITPOINTS, fx->Parameter1 );
} else {
STAT_ADD( IE_MAXHITPOINTS, fx->Parameter1 );
if (fx->FirstApply) {
BASE_ADD( IE_HITPOINTS, fx->Parameter1 );
}
}
break;
case 3: // no current hp bonus
// random value Parameter1 is set by level_check in EffectQueue
if (base) {
BASE_ADD( IE_MAXHITPOINTS, fx->Parameter1 );
} else {
STAT_ADD( IE_MAXHITPOINTS, fx->Parameter1 );
}
break;
case 1: // with current hp bonus, but unimplemented in the original
case 4:
if (base) {
BASE_SET( IE_MAXHITPOINTS, fx->Parameter1 );
} else {
STAT_SET( IE_MAXHITPOINTS, fx->Parameter1 );
}
break;
case 2:
if (base) {
BASE_MUL(IE_MAXHITPOINTS, fx->Parameter1 );
BASE_MUL(IE_HITPOINTS, fx->Parameter1 );
} else {
target->NewStat( IE_MAXHITPOINTS, target->GetStat(IE_MAXHITPOINTS)*fx->Parameter1/100, MOD_ABSOLUTE);
if (fx->FirstApply) {
target->NewBase( IE_HITPOINTS, target->GetSafeStat(IE_HITPOINTS)*fx->Parameter1/100, MOD_ABSOLUTE);
}
}
break;
case 5: // no current hp bonus
if (base) {
BASE_MUL( IE_MAXHITPOINTS, fx->Parameter1 );
} else {
STAT_MUL( IE_MAXHITPOINTS, fx->Parameter1 );
}
break;
}
return FX_PERMANENT;
}
// 0x13 IntelligenceModifier
int fx_intelligence_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_intelligence_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
BASE_MOD( IE_INT );
} else {
STAT_MOD( IE_INT );
}
return FX_PERMANENT;
}
// 0x14 State:Invisible
// this is more complex, there is a half-invisibility state
// and there is a hidden state
int fx_set_invisible_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
switch (fx->Parameter2) {
case 0:
if (pstflags) {
STATE_SET( STATE_PST_INVIS );
} else {
STATE_SET( STATE_INVISIBLE );
}
STAT_ADD(IE_TOHIT, 4);
break;
case 1:
STATE_SET( STATE_INVIS2 );
HandleBonus(target, IE_ARMORCLASS, 4, fx->TimingMode);
break;
default:
break;
}
ieDword Trans = fx->Parameter4;
if (fx->Parameter3) {
if (Trans>=240) {
fx->Parameter3=0;
} else {
Trans+=16;
}
} else {
if (Trans<=32) {
fx->Parameter3=1;
} else {
Trans-=16;
}
}
fx->Parameter4=Trans;
STAT_SET( IE_TRANSLUCENT, Trans);
return FX_APPLIED;
}
// 0x15 LoreModifier
int fx_lore_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_lore_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_LORE );
return FX_APPLIED;
}
// 0x16 LuckModifier
int fx_luck_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_luck_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_LUCK );
STAT_MOD( IE_DAMAGELUCK );
return FX_APPLIED;
}
// 0x17 MoraleModifier
int fx_morale_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_morale_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_MORALE );
return FX_APPLIED;
}
// 0x18 State:Panic
int fx_set_panic_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_panic_state (%2d)\n", fx->Opcode );
if (target->HasSpellState(SS_BLOODRAGE)) {
return FX_NOT_APPLIED;
}
if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
BASE_STATE_SET( STATE_PANIC );
} else {
STATE_SET( STATE_PANIC );
}
if (enhanced_effects) {
target->AddPortraitIcon(PI_PANIC);
}
return FX_PERMANENT;
}
// 0x19 State:Poisoned
int fx_set_poisoned_state (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_poisoned_state (%2d): Damage: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//apparently this bit isn't set, but then why is it here
//this requires a little research
STATE_SET( STATE_POISONED );
//also this effect is executed every update
ieDword damage;
int tmp = fx->Parameter1;
HandlePercentageDamage(fx, target);
switch(fx->Parameter2) {
case RPD_ROUNDS:
tmp *= core->Time.round_sec;
damage = 1;
break;
case RPD_TURNS:
tmp *= core->Time.turn_sec;
damage = 1;
break;
case RPD_SECONDS:
damage = 1;
break;
case RPD_PERCENT: // handled in HandlePercentageDamage
case RPD_POINTS:
tmp = 1; // hit points per second
damage = fx->Parameter1;
break;
default:
tmp = 1;
damage = 1;
break;
}
// all damage is at most per-second
tmp *= AI_UPDATE_TIME;
if (tmp && (core->GetGame()->GameTime%tmp)) {
return FX_APPLIED;
}
Scriptable *caster = GetCaster(Owner, fx);
//percent
target->Damage(damage, DAMAGE_POISON, caster);
return FX_APPLIED;
}
// 0x1a RemoveCurse
static EffectRef fx_apply_effect_curse_ref={"ApplyEffectCurse",NULL,-1};
static EffectRef fx_pst_jumble_curse_ref={"JumbleCurse",NULL,-1};
// gemrb extension: if the resource field is filled, it will remove curse only from the specified item
int fx_remove_curse (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_remove_curse (%2d): Resource: %s Type: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
switch(fx->Parameter2)
{
case 1:
//this is pst specific
target->fxqueue.RemoveAllEffects(fx_pst_jumble_curse_ref);
break;
default:
Inventory *inv = &target->inventory;
int i = target->inventory.GetSlotCount();
while(i--) {
//does this slot need unequipping
if (core->QuerySlotEffects(i) ) {
if (fx->Resource[0] && strnicmp(inv->GetSlotItem(i)->ItemResRef, fx->Resource,8) ) {
continue;
}
if (!(inv->GetItemFlag(i)&IE_INV_ITEM_CURSED)) {
continue;
}
inv->ChangeItemFlag(i, IE_INV_ITEM_CURSED, BM_NAND);
if (inv->UnEquipItem(i,true)) {
CREItem *tmp = inv->RemoveItem(i);
if(inv->AddSlotItem(tmp,-3)!=ASI_SUCCESS) {
//if the item couldn't be placed in the inventory, then put it back to the original slot
inv->SetSlotItem(tmp,i);
//and drop it in the area. (If there is no area, then the item will stay in the inventory)
target->DropItem(i,0);
}
}
}
}
target->fxqueue.RemoveAllEffects(fx_apply_effect_curse_ref);
}
//this is an instant effect
return FX_NOT_APPLIED;
}
// 0x1b AcidResistanceModifier
int fx_acid_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_acid_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_RESISTACID );
return FX_APPLIED;
}
// 0x1c ColdResistanceModifier
int fx_cold_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cold_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_RESISTCOLD );
return FX_APPLIED;
}
// 0x1d ElectricityResistanceModifier
int fx_electricity_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_electricity_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_RESISTELECTRICITY );
return FX_APPLIED;
}
// 0x1e FireResistanceModifier
int fx_fire_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_fire_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_RESISTFIRE );
return FX_APPLIED;
}
// 0x1f MagicDamageResistanceModifier
int fx_magic_damage_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_magic_damage_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_MAGICDAMAGERESISTANCE );
return FX_APPLIED;
}
// 0x20 Cure:Death
int fx_cure_dead_state (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_dead_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
Point p(fx->PosX, fx->PosY);
Resurrect(Owner, target, fx, p);
return FX_NOT_APPLIED;
}
// 0x21 SaveVsDeathModifier
int fx_save_vs_death_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_save_vs_death_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
HandleBonus( target, IE_SAVEVSDEATH, fx->Parameter1, fx->TimingMode );
return FX_APPLIED;
}
// 0x22 SaveVsWandsModifier
int fx_save_vs_wands_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_save_vs_wands_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
HandleBonus( target, IE_SAVEVSWANDS, fx->Parameter1, fx->TimingMode );
return FX_APPLIED;
}
// 0x23 SaveVsPolyModifier
int fx_save_vs_poly_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_save_vs_poly_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
HandleBonus( target, IE_SAVEVSPOLY, fx->Parameter1, fx->TimingMode );
return FX_APPLIED;
}
// 0x24 SaveVsBreathModifier
int fx_save_vs_breath_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_save_vs_breath_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
HandleBonus( target, IE_SAVEVSBREATH, fx->Parameter1, fx->TimingMode );
return FX_APPLIED;
}
// 0x25 SaveVsSpellsModifier
int fx_save_vs_spell_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_save_vs_spell_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
HandleBonus( target, IE_SAVEVSSPELL, fx->Parameter1, fx->TimingMode );
return FX_APPLIED;
}
// 0x26 State:Silenced
int fx_set_silenced_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_silenced_state (%2d)\n", fx->Opcode );
STATE_SET( STATE_SILENCED );
return FX_APPLIED;
}
static EffectRef fx_animation_stance_ref = {"AnimationStateChange",NULL,-1};
// 0x27 State:Helpless
// this effect sets both bits, but 'awaken' only removes the sleep bit
// FIXME: this is probably a persistent effect
int fx_set_unconscious_state (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_unconscious_state (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
if (target->HasSpellState(SS_BLOODRAGE)) {
return FX_NOT_APPLIED;
}
if (fx->FirstApply) {
Effect *newfx;
newfx = EffectQueue::CreateEffectCopy(fx, fx_animation_stance_ref, 0, IE_ANI_SLEEP);
core->ApplyEffect(newfx, target, Owner);
delete newfx;
}
if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
BASE_STATE_SET( STATE_HELPLESS | STATE_SLEEP ); //don't awaken on damage
} else {
STATE_SET( STATE_HELPLESS | STATE_SLEEP ); //don't awaken on damage
if (fx->Parameter2) {
target->SetSpellState(SS_NOAWAKE);
}
target->AddPortraitIcon(PI_SLEEP);
}
return FX_PERMANENT;
}
// 0x28 State:Slowed
// this function removes hasted state, or sets slowed state
static EffectRef fx_set_haste_state_ref={"State:Hasted",NULL,-1};
int fx_set_slowed_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_slowed_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//iwd2 free action or aegis disables this effect
if (target->HasSpellState(SS_FREEACTION)) return FX_NOT_APPLIED;
if (target->HasSpellState(SS_AEGIS)) return FX_NOT_APPLIED;
if (STATE_GET(STATE_HASTED) ) {
BASE_STATE_CURE( STATE_HASTED );
target->fxqueue.RemoveAllEffects( fx_set_haste_state_ref );
target->fxqueue.RemoveAllEffectsWithParam( fx_display_portrait_icon_ref, PI_HASTED );
} else {
STATE_SET( STATE_SLOWED );
target->AddPortraitIcon(PI_SLOWED);
// halve apr and speed
STAT_MUL(IE_NUMBEROFATTACKS, 50);
STAT_MUL(IE_MOVEMENTRATE, 50);
}
return FX_PERMANENT;
}
// 0x29 Sparkle
int fx_sparkle (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_sparkle (%2d): Sparkle colour: %d ; Sparkle type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (!target) {
return FX_NOT_APPLIED;
}
Map *map = target->GetCurrentArea();
if (!map) {
return FX_APPLIED;
}
Point p(fx->PosX, fx->PosY);
map->Sparkle( fx->Duration, fx->Parameter1, fx->Parameter2, p, fx->Parameter3);
return FX_NOT_APPLIED;
}
// 0x2A WizardSpellSlotsModifier
int fx_bonus_wizard_spells (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_bonus_wizard_spells (%2d): Spell Add: %d ; Spell Level: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
int i=1;
//if param2 is 0, then double spells up to param1
if(!fx->Parameter2) {
for (unsigned int j=0;j<fx->Parameter1 && j<MAX_SPELL_LEVEL;j++) {
target->spellbook.SetMemorizableSpellsCount(0, IE_SPELL_TYPE_WIZARD, j, true);
}
return FX_APPLIED;
}
//HoW specific
//if param2 is 0x200, then double spells at param1
if (fx->Parameter2==0x200) {
unsigned int j = fx->Parameter1-1;
if (j<MAX_SPELL_LEVEL) {
target->spellbook.SetMemorizableSpellsCount(0, IE_SPELL_TYPE_WIZARD, j, true);
}
}
for(unsigned int j=0;j<MAX_SPELL_LEVEL;j++) {
if (fx->Parameter2&i) {
target->spellbook.SetMemorizableSpellsCount(fx->Parameter1, IE_SPELL_TYPE_WIZARD, j, true);
}
i<<=1;
}
return FX_APPLIED;
}
// 0x2B Cure:Petrification
int fx_cure_petrified_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_petrified_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
BASE_STATE_CURE( STATE_PETRIFIED );
return FX_NOT_APPLIED;
}
// 0x2C StrengthModifier
int fx_strength_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_strength_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
////how strength: value is based on class
if (fx->Parameter2==3) {
fx->Parameter1 = core->Roll(1,SpellAbilityDieRoll(target,1),0);
fx->Parameter2 = 0;
}
if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
BASE_MOD( IE_STR );
} else {
STAT_MOD( IE_STR );
}
return FX_PERMANENT;
}
// 0x2D State:Stun
int power_word_stun_iwd2(Actor *target, Effect *fx)
{
int hp = BASE_GET(IE_HITPOINTS);
if (hp>150) return FX_NOT_APPLIED;
int stuntime;
if (hp>100) stuntime = core->Roll(1,4,0);
else if (hp>50) stuntime = core->Roll(2,4,0);
else stuntime = core->Roll(4,4,0);
fx->Parameter2 = 0;
fx->TimingMode = FX_DURATION_ABSOLUTE;
fx->Duration = stuntime*6*core->Time.round_size + core->GetGame()->GameTime;
STATE_SET( STATE_STUNNED );
target->AddPortraitIcon(PI_STUN);
return FX_APPLIED;
}
int fx_set_stun_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_stun_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//actually the original engine just skips this effect if the target is dead
if ( STATE_GET(STATE_DEAD) ) {
return FX_NOT_APPLIED;
}
//this is an IWD extension
if (target->HasSpellState(SS_BLOODRAGE)) {
return FX_NOT_APPLIED;
}
if (fx->Parameter2==2) {
//don't reroll the duration next time we get here
if (fx->FirstApply) {
return power_word_stun_iwd2(target, fx);
}
}
STATE_SET( STATE_STUNNED );
target->AddPortraitIcon(PI_STUN);
if (fx->Parameter2==1) {
target->SetSpellState(SS_AWAKE);
}
return FX_APPLIED;
}
// 0x2E Cure:Stun
static EffectRef fx_set_stun_state_ref={"State:Stun",NULL,-1};
static EffectRef fx_hold_creature_no_icon_ref={"State:HoldNoIcon",NULL,-1};
int fx_cure_stun_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_stun_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
BASE_STATE_CURE( STATE_STUNNED );
target->fxqueue.RemoveAllEffects(fx_set_stun_state_ref);
target->fxqueue.RemoveAllEffects(fx_hold_creature_no_icon_ref);
target->fxqueue.RemoveAllEffectsWithParam(fx_display_portrait_icon_ref, PI_HELD);
target->fxqueue.RemoveAllEffectsWithParam(fx_display_portrait_icon_ref, PI_HOPELESS);
return FX_NOT_APPLIED;
}
// 0x2F Cure:Invisible
// 0x74 Cure:Invisible2
static EffectRef fx_set_invisible_state_ref={"State:Invisible",NULL,-1};
int fx_cure_invisible_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_invisible_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (!STATE_GET(STATE_NONDET)) {
if (pstflags) {
BASE_STATE_CURE( STATE_PST_INVIS );
} else {
BASE_STATE_CURE( STATE_INVISIBLE | STATE_INVIS2 );
}
target->fxqueue.RemoveAllEffects(fx_set_invisible_state_ref);
}
return FX_NOT_APPLIED;
}
// 0x30 Cure:Silence
static EffectRef fx_set_silenced_state_ref={"State:Silenced",NULL,-1};
int fx_cure_silenced_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_silenced_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
BASE_STATE_CURE( STATE_SILENCED );
target->fxqueue.RemoveAllEffects(fx_set_silenced_state_ref);
return FX_NOT_APPLIED;
}
// 0x31 WisdomModifier
int fx_wisdom_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_wisdom_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
BASE_MOD( IE_WIS );
} else {
STAT_MOD( IE_WIS );
}
return FX_PERMANENT;
}
// 0x32 Color:BriefRGB
int fx_brief_rgb (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_brief_rgb (%2d): RGB: %d, Location and speed: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
int speed = (fx->Parameter2 >> 16) & 0xff;
target->SetColorMod(0xff, RGBModifier::ADD, speed,
fx->Parameter1 >> 8, fx->Parameter1 >> 16,
fx->Parameter1 >> 24, 0);
return FX_NOT_APPLIED;
}
// 0x33 Color:DarkenRGB
int fx_darken_rgb (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_darken_rgb (%2d): RGB: %d, Location and speed: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
EffectQueue::HackColorEffects(target, fx);
ieDword location = fx->Parameter2 & 0xff;
target->SetColorMod(location, RGBModifier::TINT, -1, fx->Parameter1 >> 8,
fx->Parameter1 >> 16, fx->Parameter1 >> 24);
return FX_APPLIED;
}
// 0x34 Color:GlowRGB
int fx_glow_rgb (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_glow_rgb (%2d): RGB: %d, Location and speed: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
EffectQueue::HackColorEffects(target, fx);
ieDword location = fx->Parameter2 & 0xff;
target->SetColorMod(location, RGBModifier::BRIGHTEN, -1,
fx->Parameter1 >> 8, fx->Parameter1 >> 16,
fx->Parameter1 >> 24);
return FX_APPLIED;
}
// 0x35 AnimationIDModifier
static EffectRef fx_animation_id_modifier_ref={"AnimationIDModifier",NULL,-1};
int fx_animation_id_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_animation_id_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
switch (fx->Parameter2) {
case 0: //non permanent animation change
default:
STAT_SET( IE_ANIMATION_ID, fx->Parameter1 );
return FX_APPLIED;
case 1: //remove any non permanent change
target->fxqueue.RemoveAllEffects(fx_animation_id_modifier_ref);
//return FX_NOT_APPLIED;
//intentionally passing through (perma change removes previous changes)
case 2: //permanent animation id change
target->SetBaseNoPCF(IE_ANIMATION_ID, fx->Parameter1);
return FX_NOT_APPLIED;
}
}
// 0x36 ToHitModifier
int fx_to_hit_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_to_hit_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
HandleBonus( target, IE_TOHIT, fx->Parameter1, fx->TimingMode );
return FX_APPLIED;
}
// 0x37 KillCreatureType
static EffectRef fx_death_ref={"Death",NULL,-1};
int fx_kill_creature_type (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_kill_creature_type (%2d): Value: %d, IDS: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (EffectQueue::match_ids( target, fx->Parameter2, fx->Parameter1) ) {
//convert it to a death opcode or apply the new effect?
fx->Opcode = EffectQueue::ResolveEffect(fx_death_ref);
fx->TimingMode = FX_DURATION_INSTANT_PERMANENT;
fx->Parameter1 = 0;
fx->Parameter2 = 4;
return FX_APPLIED;
}
//doesn't stick
return FX_NOT_APPLIED;
}
// 0x38 Alignment:Invert
//switch good to evil and evil to good
//also switch chaotic to lawful and vice versa
//gemrb extension: param2 actually controls which parts should be reversed
// 0 - switch both (as original)
// 1 - switch good and evil
// 2 - switch lawful and chaotic
static int al_switch_both[16]={0,0x33,0x32,0x31,0,0x23,0x22,0x21,0,0x13,0x12,0x11};
static int al_switch_law[16]={0,0x31,0x32,0x33,0,0x21,0x22,0x23,0,0x11,0x12,0x13};
static int al_switch_good[16]={0,0x13,0x12,0x11,0,0x23,0x22,0x21,0,0x33,0x32,0x31};
int fx_alignment_invert (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_alignment_invert (%2d)\n", fx->Opcode );
register ieDword newalign = target->GetStat( IE_ALIGNMENT );
//compress the values. GNE is the first 2 bits originally
//LNC is the 4/5. bits.
newalign = (newalign & AL_GE_MASK) | ((newalign & AL_LC_MASK)>>2);
switch (fx->Parameter2) {
default:
newalign = al_switch_both[newalign];
break;
case 1: //switch good/evil
newalign = al_switch_good[newalign];
break;
case 2:
newalign = al_switch_law[newalign];
break;
}
STAT_SET( IE_ALIGNMENT, newalign );
return FX_APPLIED;
}
// 0x39 Alignment:Change
int fx_alignment_change (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_alignment_change (%2d): Value: %d\n", fx->Opcode, fx->Parameter2 );
STAT_SET( IE_ALIGNMENT, fx->Parameter2 );
return FX_APPLIED;
}
// 0x3a DispelEffects
int fx_dispel_effects (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_dispel_effects (%2d): Value: %d, IDS: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
ieResRef Removed;
ieDword level;
switch (fx->Parameter2) {
case 0:
default:
level = 0xffffffff;
break;
case 1:
//same level: 50% success, each diff modifies it by 5%
level = core->Roll(1,20,fx->Power-10);
if (level>=0x80000000) level = 0;
break;
case 2:
//same level: 50% success, each diff modifies it by 5%
level = core->Roll(1,20,fx->Parameter1-10);
if (level>=0x80000000) level = 0;
break;
}
//if signed would it be negative?
target->fxqueue.RemoveLevelEffects(Removed, level, RL_DISPELLABLE, 0);
return FX_NOT_APPLIED;
}
// 0x3B StealthModifier
int fx_stealth_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_stealth_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_STEALTH );
return FX_APPLIED;
}
// 0x3C MiscastMagicModifier
int fx_miscast_magic_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_miscast_magic_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
switch (fx->Parameter2) {
case 3:
STAT_SET( IE_DEADMAGIC, 1);
case 0:
STAT_SET( IE_SPELLFAILUREMAGE, fx->Parameter1);
break;
case 4:
STAT_SET( IE_DEADMAGIC, 1);
case 1:
STAT_SET( IE_SPELLFAILUREPRIEST, fx->Parameter1);
break;
case 5:
STAT_SET( IE_DEADMAGIC, 1);
case 2:
STAT_SET( IE_SPELLFAILUREINNATE, fx->Parameter1);
break;
default:
return FX_NOT_APPLIED;
}
return FX_APPLIED;
}
// 0x3D AlchemyModifier
// this crashes in bg2 due to assertion failure (disabled intentionally)
// and in iwd it doesn't really follow the stat_mod convention (quite lame)
int fx_alchemy_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_alchemy_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
switch(fx->Parameter2) {
case 0:
STAT_ADD( IE_ALCHEMY, fx->Parameter1 );
break;
case 1:
STAT_SET( IE_ALCHEMY, fx->Parameter1 );
break;
case 2:
STAT_SET( IE_ALCHEMY, 100 );
break;
}
return FX_APPLIED;
}
// 0x3E PriestSpellSlotsModifier
int fx_bonus_priest_spells (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_bonus_priest_spells (%2d): Spell Add: %d ; Spell Level: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
int i=1;
//if param2 is 0, then double spells up to param1
if(!fx->Parameter2) {
for (unsigned int j=0;j<fx->Parameter1 && j<MAX_SPELL_LEVEL;j++) {
target->spellbook.SetMemorizableSpellsCount(0, IE_SPELL_TYPE_PRIEST, j, true);
}
return FX_APPLIED;
}
//HoW specific
//if param2 is 0x200, then double spells at param1
if (fx->Parameter2==0x200) {
unsigned int j = fx->Parameter1-1;
target->spellbook.SetMemorizableSpellsCount(fx->Parameter1, IE_SPELL_TYPE_PRIEST, j, true);
return FX_APPLIED;
}
for(unsigned int j=0;j<MAX_SPELL_LEVEL;j++) {
if (fx->Parameter2&i) {
target->spellbook.SetMemorizableSpellsCount(fx->Parameter1, IE_SPELL_TYPE_PRIEST, j, true);
}
i<<=1;
}
return FX_APPLIED;
}
// 0x3F State:Infravision
int fx_set_infravision_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_infravision_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STATE_SET( STATE_INFRA );
return FX_APPLIED;
}
// 0x40 Cure:Infravision
static EffectRef fx_set_infravision_state_ref={"State:Infravision",NULL,-1};
int fx_cure_infravision_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_infravision_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
BASE_STATE_CURE( STATE_INFRA );
target->fxqueue.RemoveAllEffects(fx_set_infravision_state_ref);
return FX_NOT_APPLIED;
}
// 0x41 State:Blur
int fx_set_blur_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_blur_state (%2d)\n", fx->Opcode );
//death stops this effect
if (STATE_GET( STATE_DEAD) ) {
return FX_NOT_APPLIED;
}
if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
BASE_STATE_SET( STATE_BLUR );
} else {
STATE_SET( STATE_BLUR );
}
//iwd2 specific
if (enhanced_effects) {
target->AddPortraitIcon(PI_BLUR);
}
return FX_PERMANENT;
}
// 0x42 TransparencyModifier
int fx_transparency_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_transparency_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//maybe this needs some timing
switch (fx->Parameter2) {
case 1: //fade in
if (fx->Parameter1<255) {
if (core->GetGame()->GameTime%2) {
fx->Parameter1++;
}
}
break;
case 2://fade out
if (fx->Parameter1) {
if (core->GetGame()->GameTime%2) {
fx->Parameter1--;
}
}
break;
}
STAT_MOD( IE_TRANSLUCENT );
return FX_APPLIED;
}
// 0x43 SummonCreature
static int eamods[]={EAM_ALLY,EAM_ALLY,EAM_DEFAULT,EAM_ALLY,EAM_DEFAULT,EAM_ENEMY,EAM_ALLY};
int fx_summon_creature (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_summon_creature (%2d): ResRef:%s Anim:%s Type: %d\n", fx->Opcode, fx->Resource, fx->Resource2, fx->Parameter2 );
if (!target) {
return FX_NOT_APPLIED;
}
if (!target->GetCurrentArea()) {
return FX_APPLIED;
}
//summon creature (resource), play vvc (resource2)
//creature's lastsummoner is Owner
//creature's target is target
//position of appearance is target's pos
int eamod = -1;
if (fx->Parameter2<6){
eamod = eamods[fx->Parameter2];
}
//the monster should appear near the effect position
Point p(fx->PosX, fx->PosY);
Effect *newfx = EffectQueue::CreateUnsummonEffect(fx);
core->SummonCreature(fx->Resource, fx->Resource2, Owner, target, p, eamod, 0, newfx);
delete newfx;
return FX_NOT_APPLIED;
}
// 0x44 UnsummonCreature
int fx_unsummon_creature (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_unsummon_creature (%2d)\n", fx->Opcode );
//to be compatible with the original engine, unsummon doesn't work with PC's
//but it works on anything else
if (!target->InParty) {
//play the vanish animation
ScriptedAnimation* sca = gamedata->GetScriptedAnimation(fx->Resource, false);
if (sca) {
sca->XPos+=target->Pos.x;
sca->YPos+=target->Pos.y;
target->GetCurrentArea()->AddVVCell(sca);
}
//remove the creature
target->DestroySelf();
}
return FX_NOT_APPLIED;
}
// 0x45 State:Nondetection
int fx_set_nondetection_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_nondetection_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STATE_SET( STATE_NONDET );
return FX_APPLIED;
}
// 0x46 Cure:Nondetection
static EffectRef fx_set_nondetection_state_ref={"State:Nondetection",NULL,-1};
int fx_cure_nondetection_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_nondetection_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
BASE_STATE_CURE( STATE_NONDET );
target->fxqueue.RemoveAllEffects(fx_set_nondetection_state_ref);
return FX_NOT_APPLIED;
}
// 0x47 SexModifier
int fx_sex_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_sex_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
ieDword value;
if (fx->Parameter2) {
value = fx->Parameter1;
} else {
if (STAT_GET(IE_SEX_CHANGED)) {
return FX_NOT_APPLIED;
}
STAT_SET( IE_SEX_CHANGED, 1);
value = STAT_GET(IE_SEX);
if (value==SEX_MALE) {
value = SEX_FEMALE;
} else {
value = SEX_MALE;
}
}
STAT_SET( IE_SEX, value );
return FX_APPLIED;
}
// 0x48 AIIdentifierModifier
int fx_ids_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_ids_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
switch (fx->Parameter2) {
case 0:
STAT_SET(IE_EA, fx->Parameter1);
break;
case 1:
STAT_SET(IE_GENERAL, fx->Parameter1);
break;
case 2:
STAT_SET(IE_RACE, fx->Parameter1);
break;
case 3:
STAT_SET(IE_CLASS, fx->Parameter1);
break;
case 4:
STAT_SET(IE_SPECIFIC, fx->Parameter1);
break;
case 5:
STAT_SET(IE_SEX, fx->Parameter1);
break;
case 6:
STAT_SET(IE_ALIGNMENT, fx->Parameter1);
break;
default:
return FX_NOT_APPLIED;
}
//not sure, need a check if this action could be permanent
return FX_APPLIED;
}
// 0x49 DamageBonusModifier
int fx_damage_bonus_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_damage_bonus_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_DAMAGEBONUS );
return FX_APPLIED;
}
// 0x4a State:Blind
int fx_set_blind_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_blind_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//don't do this effect twice (bug exists in BG2, but fixed in IWD2)
if (!STATE_GET(STATE_BLIND)) {
STATE_SET( STATE_BLIND );
//the feat normally exists only in IWD2, but won't hurt
if (!target->GetFeat(FEAT_BLIND_FIGHT)) {
STAT_SUB (IE_TOHIT, 10); // all other tohit stats are treated as bonuses
}
}
return FX_APPLIED;
}
// 0x4b Cure:Blind
static EffectRef fx_set_blind_state_ref={"State:Blind",NULL,-1};
int fx_cure_blind_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_blind_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
BASE_STATE_CURE( STATE_BLIND );
target->fxqueue.RemoveAllEffects(fx_set_blind_state_ref);
return FX_NOT_APPLIED;
}
// 0x4c State:Feeblemind
int fx_set_feebleminded_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_feebleminded_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STATE_SET( STATE_FEEBLE );
STAT_SET( IE_INT, 3);
if (enhanced_effects) {
target->AddPortraitIcon(PI_FEEBLEMIND);
}
return FX_APPLIED;
}
// 0x4d Cure:Feeblemind
static EffectRef fx_set_feebleminded_state_ref={"State:Feeblemind",NULL,-1};
int fx_cure_feebleminded_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_feebleminded_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
BASE_STATE_CURE( STATE_FEEBLE );
target->fxqueue.RemoveAllEffects(fx_set_feebleminded_state_ref);
target->fxqueue.RemoveAllEffectsWithParam(fx_display_portrait_icon_ref, PI_FEEBLEMIND);
return FX_NOT_APPLIED;
}
// 0x4e State:Diseased
int fx_set_diseased_state (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_diseased_state (%2d): Damage: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (STATE_GET(STATE_DEAD|STATE_PETRIFIED|STATE_FROZEN) ) {
return FX_NOT_APPLIED;
}
//setting damage to 0 because not all types do damage
ieDword damage = 0;
HandlePercentageDamage(fx, target);
switch(fx->Parameter2) {
case RPD_SECONDS:
damage = 1;
if (fx->Parameter1 && (core->GetGame()->GameTime%(fx->Parameter1*AI_UPDATE_TIME))) {
return FX_APPLIED;
}
break;
case RPD_PERCENT: // handled in HandlePercentageDamage
case RPD_POINTS:
damage = fx->Parameter1;
// per second
if (core->GetGame()->GameTime%AI_UPDATE_TIME) {
return FX_APPLIED;
}
break;
case RPD_STR: //strength
STAT_ADD(IE_STR, fx->Parameter1);
break;
case RPD_DEX: //dex
STAT_ADD(IE_DEX, fx->Parameter1);
break;
case RPD_CON: //con
STAT_ADD(IE_CON, fx->Parameter1);
break;
case RPD_INT: //int
STAT_ADD(IE_INT, fx->Parameter1);
break;
case RPD_WIS: //wis
STAT_ADD(IE_WIS, fx->Parameter1);
break;
case RPD_CHA: //cha
STAT_ADD(IE_CHR, fx->Parameter1);
break;
case RPD_SLOW: //slow
break;
default:
damage = 1;
break;
}
//percent
Scriptable *caster = GetCaster(Owner, fx);
if (damage) {
target->Damage(damage, DAMAGE_POISON, caster);
}
return FX_APPLIED;
}
// 0x4f Cure:Disease
static EffectRef fx_diseased_state_ref={"State:Diseased",NULL,-1};
int fx_cure_diseased_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_diseased_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//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
target->fxqueue.RemoveAllEffects( fx_diseased_state_ref ); //this is what actually happens in bg2
return FX_NOT_APPLIED;
}
// 0x50 State:Deafness
// gemrb extension: modifiable amount
// none of the engines care about stacking
int fx_set_deaf_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_deaf_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//gemrb fix
if (target->SetSpellState(SS_DEAF)) return FX_APPLIED;
if (!fx->Parameter1) {
fx->Parameter1 = 50;
}
STAT_ADD(IE_SPELLFAILUREMAGE, fx->Parameter1);
if (!fx->Parameter2) {
fx->Parameter1 = 50;
}
STAT_ADD(IE_SPELLFAILUREPRIEST, fx->Parameter2);
EXTSTATE_SET(EXTSTATE_DEAF); //iwd1/how needs this
if (enhanced_effects) {
target->AddPortraitIcon(PI_DEAFNESS);
}
return FX_APPLIED;
}
int fx_set_deaf_state_iwd2 (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_deaf_state_iwd2 (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//gemrb fix
if (target->SetSpellState(SS_DEAF)) return FX_APPLIED;
if (!fx->Parameter1) {
//this is a bad hack
fx->Parameter1 = 20;
}
STAT_ADD(IE_SPELLFAILUREMAGE, fx->Parameter1);
if (!fx->Parameter2) {
fx->Parameter1 = 20;
}
STAT_ADD(IE_SPELLFAILUREPRIEST, fx->Parameter2);
EXTSTATE_SET(EXTSTATE_DEAF); //iwd1/how needs this
target->AddPortraitIcon(PI_DEAFNESS); //iwd2 specific
return FX_APPLIED;
}
// 0x51 Cure:Deafness
static EffectRef fx_deaf_state_ref={"State:Deafness",NULL,-1};
static EffectRef fx_deaf_state_iwd2_ref={"State:DeafnessIWD2",NULL,-1};
//removes the deafness effect
int fx_cure_deaf_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_deaf_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
target->fxqueue.RemoveAllEffects(fx_deaf_state_ref);
target->fxqueue.RemoveAllEffects(fx_deaf_state_iwd2_ref);
return FX_NOT_APPLIED;
}
// 0x52 SetAIScript
int fx_set_ai_script (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_ai_state (%2d): Resource: %s, Type: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
target->SetScript (fx->Resource, fx->Parameter2);
return FX_NOT_APPLIED;
}
// 0x53 Protection:Projectile
int fx_protection_from_projectile (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_protection_from_projectile (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_BIT_OR( IE_IMMUNITY, IMM_PROJECTILE);
return FX_APPLIED;
}
// 0x54 MagicalFireResistanceModifier
int fx_magical_fire_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_magical_fire_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_RESISTMAGICFIRE );
return FX_APPLIED;
}
// 0x55 MagicalColdResistanceModifier
int fx_magical_cold_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_magical_cold_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_RESISTMAGICCOLD );
return FX_APPLIED;
}
// 0x56 SlashingResistanceModifier
int fx_slashing_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_slashing_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_RESISTSLASHING );
return FX_APPLIED;
}
// 0x57 CrushingResistanceModifier
int fx_crushing_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_crushing_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_RESISTCRUSHING );
return FX_APPLIED;
}
// 0x58 PiercingResistanceModifier
int fx_piercing_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_piercing_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_RESISTPIERCING );
return FX_APPLIED;
}
// 0x59 MissilesResistanceModifier
int fx_missiles_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_missiles_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_RESISTMISSILE );
return FX_APPLIED;
}
// 0x5A OpenLocksModifier
int fx_open_locks_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_open_locks_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_LOCKPICKING );
return FX_APPLIED;
}
// 0x5B FindTrapsModifier
int fx_find_traps_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_find_traps_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_TRAPS );
return FX_APPLIED;
}
// 0x5C PickPocketsModifier
int fx_pick_pockets_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_pick_pockets_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_PICKPOCKET );
return FX_APPLIED;
}
// 0x5D FatigueModifier
int fx_fatigue_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_fatigue_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_FATIGUE );
// TODO: fatigue has a negative effect on luck -> add fatigmod.2da support
return FX_APPLIED;
}
// 0x5E IntoxicationModifier
int fx_intoxication_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_intoxication_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_INTOXICATION );
return FX_APPLIED;
}
// 0x5F TrackingModifier
int fx_tracking_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_tracking_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_TRACKING );
return FX_APPLIED;
}
// 0x60 LevelModifier
int fx_level_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_level_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_LEVEL );
return FX_APPLIED;
}
// 0x61 StrengthBonusModifier
int fx_strength_bonus_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_strength_bonus_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_STREXTRA );
return FX_APPLIED;
}
// 0x62 State:Regenerating
int fx_set_regenerating_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_regenerating_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
int damage;
int tmp = fx->Parameter1;
ieDword gameTime = core->GetGame()->GameTime;
ieDword nextHeal;
if (!fx->Parameter3) {
//hack to ensure our first call gets through
nextHeal = gameTime-1;
} else {
nextHeal = fx->Parameter3;
}
//we can have multiple calls at the same gameTime, so we
//just go to gameTime+1 to ensure one call
if (nextHeal>=gameTime) return FX_APPLIED;
HandlePercentageDamage(fx, target);
switch(fx->Parameter2) {
case RPD_TURNS: //restore param3 hp every param1 turns
tmp *= core->Time.rounds_per_turn;
//fall
case RPD_ROUNDS: //restore param3 hp every param1 rounds
tmp *= core->Time.round_sec;
//fall
case RPD_SECONDS: //restore param3 hp every param1 seconds
fx->Parameter3 = nextHeal + tmp*AI_UPDATE_TIME;
damage = 1;
break;
case RPD_PERCENT: // handled in HandlePercentageDamage
case RPD_POINTS: //restore param1 hp every second? that's crazy!
damage = fx->Parameter1;
fx->Parameter3 = nextHeal + AI_UPDATE_TIME;
break;
default:
fx->Parameter3 = nextHeal + AI_UPDATE_TIME;
damage = 1;
break;
}
//This should take care of the change of the modified stat
//So there is no need to do anything else here other than increasing
//the base current hp
target->NewBase(IE_HITPOINTS, damage, MOD_ADDITIVE);
return FX_APPLIED;
}
// 0x63 SpellDurationModifier
int fx_spell_duration_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_spell_duration_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
switch (fx->Parameter2) {
case 0:
STAT_SET( IE_SPELLDURATIONMODMAGE, fx->Parameter1);
break;
case 1:
STAT_SET( IE_SPELLDURATIONMODPRIEST, fx->Parameter1);
break;
default:
return FX_NOT_APPLIED;
}
return FX_APPLIED;
}
// 0x64 Protection:Creature
int fx_generic_effect (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
{
if (0) printf( "fx_generic_effect (%2d): Param1: %d, Param2: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
return FX_APPLIED;
}
// 0x65 Protection:Opcode
int fx_protection_opcode (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_protection_opcode (%2d): Opcode: %d\n", fx->Opcode, fx->Parameter2 );
STAT_BIT_OR(IE_IMMUNITY, IMM_OPCODE);
return FX_APPLIED;
}
// 0x66 Protection:SpellLevel
int fx_protection_spelllevel (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_protection_spelllevel (%2d) Level: %d\n", fx->Opcode, fx->Parameter1);
int value = fx->Parameter1;
if (value<9) {
STAT_BIT_OR(IE_MINORGLOBE, 1<<value);
STAT_BIT_OR(IE_IMMUNITY, IMM_LEVEL);
return FX_APPLIED;
}
return FX_NOT_APPLIED;
}
// 0x67 ChangeName
int fx_change_name (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_change_name_modifier (%2d): StrRef: %d\n", fx->Opcode, fx->Parameter1 );
target->SetName(fx->Parameter1, 0);
return FX_NOT_APPLIED;
}
// 0x68 ExperienceModifier
int fx_experience_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_experience_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//i believe this has mode too
target->AddExperience (fx->Parameter1);
return FX_NOT_APPLIED;
}
// 0x69 GoldModifier
//in BG2 this effect subtracts gold when type is MOD_ADDITIVE
//no one uses it, though. To keep the function, the default branch will do the subtraction
int fx_gold_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_gold_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (!target->InParty) {
STAT_MOD( IE_GOLD );
return FX_NOT_APPLIED;
}
ieDword gold;
Game *game = core->GetGame();
//for party members, the gold is stored in the game object
switch( fx->Parameter2) {
case MOD_ADDITIVE:
gold = fx->Parameter1;
break;
case MOD_ABSOLUTE:
gold = fx->Parameter1-game->PartyGold;
break;
case MOD_PERCENT:
gold = game->PartyGold*fx->Parameter1/100-game->PartyGold;
break;
default:
gold = (ieDword) -fx->Parameter1;
break;
}
game->AddGold (gold);
return FX_NOT_APPLIED;
}
// 0x6a MoraleBreakModifier
int fx_morale_break_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_morale_break_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD(IE_MORALEBREAK);
return FX_PERMANENT; //permanent morale break doesn't stick
}
// 0x6b PortraitChange
int fx_portrait_change (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_portrait_change (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
target->SetPortrait( fx->Resource, fx->Parameter2);
return FX_NOT_APPLIED;
}
// 0x6c ReputationModifier
int fx_reputation_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_reputation_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD(IE_REPUTATION);
return FX_NOT_APPLIED; //needs testing
}
// 0x6d --> see later
// 0x6e works only in PST, reused for turning undead
// 0x6f Item:CreateMagic
static EffectRef fx_remove_item_ref={"Item:Remove",NULL,-1};
int fx_create_magic_item (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
//charge count is incorrect
target->inventory.SetSlotItemRes(fx->Resource, target->inventory.GetMagicSlot(),fx->Parameter1,fx->Parameter3,fx->Parameter4);
//equip the weapon
target->inventory.SetEquippedSlot(target->inventory.GetMagicSlot()-target->inventory.GetWeaponSlot(), 0);
if ((fx->TimingMode&0xff) == FX_DURATION_INSTANT_LIMITED) {
//if this effect has expiration, then it will remain as a remove_item
//on the effect queue, inheriting all the parameters
fx->Opcode=EffectQueue::ResolveEffect(fx_remove_item_ref);
fx->TimingMode=FX_DURATION_DELAY_PERMANENT;
return FX_APPLIED;
}
return FX_NOT_APPLIED;
}
// 0x70 Item:Remove
int fx_remove_item (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
//will destroy the first item
if (target->inventory.DestroyItem(fx->Resource,0,1)) {
target->ReinitQuickSlots();
}
return FX_NOT_APPLIED;
}
// 0x71 Item:Equip
int fx_equip_item (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
int eff = core->QuerySlotEffects( fx->Parameter2 );
switch(eff) {
case SLOT_EFFECT_NONE:
case SLOT_EFFECT_MELEE:
target->inventory.SetEquippedSlot( fx->Parameter2, fx->Parameter1 );
break;
default:
target->inventory.EquipItem( fx->Parameter2 );
break;
}
target->ReinitQuickSlots();
return FX_NOT_APPLIED;
}
// 0x72 Dither
int fx_dither (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
{
if (0) printf( "fx_dither (%2d): Value: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//this effect doesn't work in any engine versions
return FX_NOT_APPLIED;
}
// 0x73 DetectAlignment
//gemrb extension: chaotic/lawful detection
int fx_detect_alignment (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
ieDword msk;
ieDword stat;
static int ge[] = {AL_EVIL, AL_GE_NEUTRAL, AL_GOOD, AL_CHAOTIC, AL_LC_NEUTRAL, AL_LAWFUL};
msk = ge[fx->Parameter2];
if (fx->Parameter2<3) {
//0,1,2 -> 3,2,1
stat = target->GetStat(IE_ALIGNMENT)&AL_GE_MASK;
}
else {
//3,4,5 -> 0x30, 0x20, 0x10
stat = target->GetStat(IE_ALIGNMENT)&AL_LC_MASK;
}
if (stat != msk) return FX_NOT_APPLIED;
ieDword color = fx->Parameter1;
switch (msk) {
case AL_EVIL:
if (!color) color = 0xff0000;
displaymsg->DisplayConstantStringName(STR_EVIL, color, target);
//glow red
target->SetColorMod(0xff, RGBModifier::ADD, 30, 0xff, 0, 0, 0);
break;
case AL_GOOD:
if (!color) color = 0xff00;
displaymsg->DisplayConstantStringName(STR_GOOD, color, target);
//glow green
target->SetColorMod(0xff, RGBModifier::ADD, 30, 0, 0xff, 0, 0);
break;
case AL_GE_NEUTRAL:
if (!color) color = 0xff;
displaymsg->DisplayConstantStringName(STR_GE_NEUTRAL, color, target);
//glow blue
target->SetColorMod(0xff, RGBModifier::ADD, 30, 0, 0, 0xff, 0);
break;
case AL_CHAOTIC:
if (!color) color = 0xff00ff;
displaymsg->DisplayConstantStringName(STR_CHAOTIC, color, target);
//glow purple
target->SetColorMod(0xff, RGBModifier::ADD, 30, 0xff, 0, 0xff, 0);
break;
case AL_LAWFUL:
if (!color) color = 0xffffff;
displaymsg->DisplayConstantStringName(STR_LAWFUL, color, target);
//glow white
target->SetColorMod(0xff, RGBModifier::ADD, 30, 0xff, 0xff, 0xff, 0);
break;
case AL_LC_NEUTRAL:
if (!color) color = 0xff;
displaymsg->DisplayConstantStringName(STR_LC_NEUTRAL, color, target);
//glow blue
target->SetColorMod(0xff, RGBModifier::ADD, 30, 0, 0, 0xff, 0);
break;
}
return FX_NOT_APPLIED;
}
// 0x74 Cure:Invisible2 (see 0x2f)
// 0x75 Reveal:Area
// 0 reveal whole area
// 1 reveal area in pattern
int fx_reveal_area (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_reveal_area (%2d): Value: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
Map *map = target->GetCurrentArea();
if (!map) {
return FX_APPLIED;
}
if (fx->Parameter2) {
map->Explore(fx->Parameter1);
} else {
map->Explore(-1);
}
return FX_NOT_APPLIED;
}
// 0x76 Reveal:Creatures
int fx_reveal_creatures (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
{
if (0) printf( "fx_reveal_creatures (%2d): Value: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//reveals creatures (not working in original IE)
return FX_NOT_APPLIED;
}
// 0x77 MirrorImage
static EffectRef fx_mirror_image_modifier_ref={"MirrorImageModifier",NULL,-1};
int fx_mirror_image (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_mirror_image (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
ieDword images;
if (fx->Parameter2) {
images = 1; //reflection
}
else {
// the original uses only IE_LEVEL, but that can be awefully bad in
// the case of dual- and multiclasses
unsigned int level = target->GetMageLevel();
if (!level) level = target->GetSorcererLevel();
if (!level) level = target->GetBardLevel();
if (!level) level = target->GetStat(IE_LEVEL);
// 2-8 mirror images
images = level/3 + 2;
if (images > 8) images = 8;
}
Effect *fx2 = target->fxqueue.HasEffect(fx_mirror_image_modifier_ref);
if (fx2) {
//update old effect with our numbers if our numbers are more
if (fx2->Parameter1<images) {
fx2->Parameter1=images;
}
if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT) {
fx2->TimingMode = FX_DURATION_INSTANT_PERMANENT;
}
return FX_NOT_APPLIED;
}
fx->Opcode = EffectQueue::ResolveEffect(fx_mirror_image_modifier_ref);
fx->Parameter1=images;
//parameter2 could be 0 or 1 (mirror image or reflection)
//execute the translated effect
return fx_mirror_image_modifier(Owner, target, fx);
}
// 0x78 Protection:Weapons
int fx_immune_to_weapon (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
{
if (0) printf( "fx_immune_to_weapon (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (!fx->FirstApply) return FX_APPLIED;
int level;
ieDword mask, value;
level = -1;
mask = 0;
value = 0;
switch(fx->Parameter2) {
case 0: //enchantment level
level = fx->Parameter1;
break;
case 1: //all magical weapons
value = IE_INV_ITEM_MAGICAL;
//fallthrough
case 2: //all nonmagical weapons
mask = IE_INV_ITEM_MAGICAL;
break;
case 3: //all silver weapons
value = IE_INV_ITEM_SILVER;
//fallthrough
case 4: //all non silver weapons
mask = IE_INV_ITEM_SILVER;
break;
case 5:
value = IE_INV_ITEM_SILVER;
mask = IE_INV_ITEM_SILVER;
level = 0;
break;
case 6: //all twohanded
value = IE_INV_ITEM_TWOHANDED;
//fallthrough
case 7: //all not twohanded
mask = IE_INV_ITEM_TWOHANDED;
break;
case 8: //all twohanded
value = IE_INV_ITEM_CURSED;
//fallthrough
case 9: //all not twohanded
mask = IE_INV_ITEM_CURSED;
break;
case 10: //all twohanded
value = IE_INV_ITEM_COLDIRON;
//fallthrough
case 11: //all not twohanded
mask = IE_INV_ITEM_COLDIRON;
break;
case 12:
mask = fx->Parameter1;
case 13:
value = fx->Parameter1;
break;
default:;
}
fx->Parameter1 = (ieDword) level; //putting the corrected value back
fx->Parameter3 = mask;
fx->Parameter4 = value;
return FX_APPLIED;
}
// 0x79 VisualAnimationEffect (unknown)
int fx_visual_animation_effect (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
{
//this is an unknown effect
if (0) printf( "fx_visual_animation_effect (%2d)\n", fx->Opcode );
return FX_NOT_APPLIED;
}
// 0x7a Item:CreateInventory
static EffectRef fx_remove_inventory_item_ref={"Item:RemoveInventory",NULL,-1};
int fx_create_inventory_item (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_create_inventory_item (%2d)\n", fx->Opcode );
target->inventory.AddSlotItemRes( fx->Resource, SLOT_ONLYINVENTORY, fx->Parameter1, fx->Parameter3, fx->Parameter4 );
if ((fx->TimingMode&0xff) == FX_DURATION_INSTANT_LIMITED) {
//if this effect has expiration, then it will remain as a remove_item
//on the effect queue, inheriting all the parameters
fx->Opcode=EffectQueue::ResolveEffect(fx_remove_inventory_item_ref);
fx->TimingMode=FX_DURATION_DELAY_PERMANENT;
return FX_APPLIED;
}
return FX_NOT_APPLIED;
}
// 0x7b Item:RemoveInventory
int fx_remove_inventory_item (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_remove_inventory_item (%2d)\n", fx->Opcode );
//FIXME: now equipped items are only wielded weapons
//why would it not let equipped items to be destructed?
target->inventory.DestroyItem(fx->Resource,IE_INV_ITEM_EQUIPPED,1);
return FX_NOT_APPLIED;
}
// 0x7c DimensionDoor
// iwd2 has several options
int fx_dimension_door (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_dimension_door (%2d) Type:%d\n", fx->Opcode, fx->Parameter2 );
Point p;
switch(fx->Parameter2)
{
case 0: //target to point
p.x=fx->PosX;
p.y=fx->PosY;
break;
case 1: //owner to target
if (Owner->Type!=ST_ACTOR) {
return FX_NOT_APPLIED;
}
p=target->Pos;
target = (Actor *) Owner;
break;
case 2: //target to saved location
p.x=STAT_GET(IE_SAVEDXPOS);
p.x=STAT_GET(IE_SAVEDYPOS);
target->SetOrientation(STAT_GET(IE_SAVEDFACE), false);
break;
case 3: //owner swapped with target
if (Owner->Type!=ST_ACTOR) {
return FX_NOT_APPLIED;
}
p=target->Pos;
target->SetPosition(Owner->Pos, true, 0);
target = (Actor *) Owner;
break;
}
target->SetPosition(p, true, 0 );
return FX_NOT_APPLIED;
}
// 0x7d Unlock
int fx_knock (Scriptable* Owner, Actor* /*target*/, Effect* fx)
{
if (0) printf( "fx_knock (%2d) [%d.%d]\n", fx->Opcode, fx->PosX, fx->PosY );
Map *map = Owner->GetCurrentArea();
if (!map) {
return FX_NOT_APPLIED;
}
Point p(fx->PosX, fx->PosY);
printf("KNOCK Pos: %d.%d\n", fx->PosX, fx->PosY);
Door *door = map->TMap->GetDoorByPosition(p);
if (door) {
printf("Got a door\n");
if (door->LockDifficulty<100) {
door->SetDoorLocked(false, true);
}
return FX_NOT_APPLIED;
}
Container *container = map->TMap->GetContainerByPosition(p);
if (container) {
printf("Got a container\n");
if(container->LockDifficulty<100) {
container->SetContainerLocked(false);
}
return FX_NOT_APPLIED;
}
return FX_NOT_APPLIED;
}
// 0x7e MovementRateModifier
// 0xb0 MovementRateModifier2
int fx_movement_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_movement_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//iwd2 freeaction disables only 0xb0, who cares
if (target->HasSpellState(SS_FREEACTION)) return FX_NOT_APPLIED;
//iwd2 aegis doesn't protect against grease/acid fog slowness, but that is
//definitely a bug
if (target->HasSpellState(SS_AEGIS)) return FX_NOT_APPLIED;
STAT_MOD(IE_MOVEMENTRATE);
return FX_APPLIED;
}
#define FX_MS 10
static const ieResRef monster_summoning_2da[FX_MS]={"MONSUM01","MONSUM02","MONSUM03",
"ANISUM01","ANISUM02", "MONSUM01", "MONSUM02","MONSUM03","ANISUM01","ANISUM02"};
// 0x7f MonsterSummoning
int fx_monster_summoning (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_monster_summoning (%2d): Number: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//check the summoning limit?
if (!Owner) {
return FX_NOT_APPLIED;
}
if (!Owner->GetCurrentArea()) {
return FX_APPLIED;
}
//get monster resref from 2da determined by fx->Resource or fx->Parameter2
//the only addition to the original engine is that fx->Resource can be
//used to specify a 2da (if parameter2 is >= 10)
ieResRef monster;
ieResRef hit;
ieResRef areahit;
ieResRef table;
int level = fx->Parameter1;
if (fx->Parameter2>=FX_MS) {
if (fx->Resource[0]) {
strnuprcpy(table, fx->Resource, 8);
} else {
strnuprcpy(table, "ANISUM03", 8);
}
} else {
strnuprcpy(table, monster_summoning_2da[fx->Parameter2], 8);
}
core->GetResRefFrom2DA(monster_summoning_2da[fx->Parameter2], monster, hit, areahit);
if (!hit[0]) {
strnuprcpy(hit,fx->Resource2,8);
}
if (!areahit[0]) {
strnuprcpy(areahit,fx->Resource3,8);
}
//the monster should appear near the effect position
Point p(fx->PosX, fx->PosY);
Effect *newfx = EffectQueue::CreateUnsummonEffect(fx);
//The hostile flag should cover these cases, all else is arbitrary
//0,1,2,3,4 - friendly to target
//5,6,7,8,9 - hostile to target
//10 - friendly to target
int eamod;
if (fx->Parameter2>=5 && fx->Parameter2<=9) {
eamod = EAM_ENEMY;
}
else {
eamod = EAM_ALLY;
}
//caster may be important here (Source), even if currently the EA modifiers
//don't use it
Scriptable *caster = GetCaster(Owner, fx);
core->SummonCreature(monster, hit, caster, target, p, eamod, level, newfx);
delete newfx;
return FX_NOT_APPLIED;
}
// 0x80 State:Confused
int fx_set_confused_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_confused_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (target->HasSpellState(SS_BLOODRAGE)) {
return FX_NOT_APPLIED;
}
if (fx->TimingMode==FX_DURATION_DELAY_PERMANENT) {
BASE_STATE_SET( STATE_CONFUSED );
} else {
STATE_SET( STATE_CONFUSED );
}
//NOTE: iwd2 is also unable to display the portrait icon
//for permanent confusion
if (enhanced_effects) {
target->AddPortraitIcon(PI_CONFUSED);
}
return FX_PERMANENT;
}
// 0x81 AidNonCumulative
int fx_set_aid_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_aid_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (!fx->Parameter2) {
fx->Parameter2=core->Roll(fx->Parameter1,8,0);
}
if (STATE_GET (STATE_AID) ) //aid is non cumulative
return FX_NOT_APPLIED;
STATE_SET( STATE_AID );
target->SetSpellState(SS_AID);
STAT_ADD( IE_MAXHITPOINTS, fx->Parameter2);
//This better happens after increasing maxhitpoints
if (fx->FirstApply) {
BASE_ADD( IE_HITPOINTS, fx->Parameter1);
}
STAT_ADD( IE_SAVEVSDEATH, fx->Parameter1);
STAT_ADD( IE_SAVEVSWANDS, fx->Parameter1);
STAT_ADD( IE_SAVEVSPOLY, fx->Parameter1);
STAT_ADD( IE_SAVEVSBREATH, fx->Parameter1);
STAT_ADD( IE_SAVEVSSPELL, fx->Parameter1);
//bless effect too?
STAT_ADD( IE_TOHIT, fx->Parameter1);
STAT_ADD( IE_MORALEBREAK, fx->Parameter1);
if (enhanced_effects) {
target->AddPortraitIcon(PI_AID);
target->SetColorMod(0xff, RGBModifier::ADD, 30, 50, 50, 50);
}
return FX_APPLIED;
}
// 0x82 BlessNonCumulative
static EffectRef fx_bane_ref={"Bane",NULL,-1};
int fx_set_bless_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_bless_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (STATE_GET (STATE_BLESS) ) //bless is non cumulative
return FX_NOT_APPLIED;
//do this once
target->fxqueue.RemoveAllEffects(fx_bane_ref);
STATE_SET( STATE_BLESS );
target->SetSpellState(SS_BLESS);
STAT_ADD( IE_TOHIT, fx->Parameter1);
STAT_ADD( IE_MORALEBREAK, fx->Parameter1);
if (enhanced_effects) {
target->AddPortraitIcon(PI_BLESS);
target->SetColorMod(0xff, RGBModifier::ADD, 30, 0xc0, 0x80, 0);
}
return FX_APPLIED;
}
// 0x83 ChantNonCumulative
int fx_set_chant_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_chant_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (STATE_GET (STATE_CHANT) ) //chant is non cumulative
return FX_NOT_APPLIED;
STATE_SET( STATE_CHANT );
target->SetSpellState(SS_GOODCHANT);
STAT_ADD( IE_LUCK, fx->Parameter1 );
return FX_APPLIED;
}
// 0x84 HolyNonCumulative
int fx_set_holy_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_holy_state (%2d): Modifier: %d\n", fx->Opcode, fx->Parameter1 );
if (STATE_GET (STATE_HOLY) ) //holy power is non cumulative
return FX_NOT_APPLIED;
STATE_SET( STATE_HOLY );
//setting the spell state to be compatible with iwd2
target->SetSpellState(SS_HOLYMIGHT);
STAT_ADD( IE_STR, fx->Parameter1);
STAT_ADD( IE_CON, fx->Parameter1);
STAT_ADD( IE_DEX, fx->Parameter1);
if (enhanced_effects) {
target->AddPortraitIcon(PI_HOLY);
target->SetColorMod(0xff, RGBModifier::ADD, 30, 0x80, 0x80, 0x80);
}
return FX_APPLIED;
}
// 0x85 LuckNonCumulative
int fx_luck_non_cumulative (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_luck_non_cumulative (%2d): Modifier: %d\n", fx->Opcode, fx->Parameter1);
if (STATE_GET (STATE_LUCK) ) //this luck is non cumulative
return FX_NOT_APPLIED;
STATE_SET( STATE_LUCK );
target->SetSpellState(SS_LUCK);
STAT_ADD( IE_LUCK, fx->Parameter1 );
STAT_ADD( IE_DAMAGELUCK, fx->Parameter1 );
return FX_APPLIED;
}
// 0x85 LuckCumulative (iwd2)
int fx_luck_cumulative (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_luck_cumulative (%2d): Modifier: %d\n", fx->Opcode, fx->Parameter1);
target->SetSpellState(SS_LUCK);
STAT_ADD( IE_LUCK, fx->Parameter1 );
STAT_ADD( IE_DAMAGELUCK, fx->Parameter1 );
return FX_APPLIED;
}
// 0x86 State:Petrification
int fx_set_petrified_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_petrified_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
BASE_STATE_SET( STATE_PETRIFIED );
return FX_NOT_APPLIED; //permanent effect
}
// 0x87 Polymorph
static EffectRef fx_polymorph_ref={"Polymorph",NULL,-1};
void CopyPolymorphStats(Actor *source, Actor *target)
{
int i;
if(!polymorph_stats) {
AutoTable tab("polystat");
if (!tab) {
polymorph_stats = (int *) malloc(0);
polystatcount=0;
return;
}
polystatcount = tab->GetRowCount();
polymorph_stats=(int *) malloc(sizeof(int)*polystatcount);
for (i=0;i<polystatcount;i++) {
polymorph_stats[i]=core->TranslateStat(tab->QueryField(i,0));
}
}
assert(target->polymorphCache);
if (!target->polymorphCache->stats) {
target->polymorphCache->stats = new ieDword[polystatcount];
}
for(i=0;i<polystatcount;i++) {
target->polymorphCache->stats[i] = source->Modified[polymorph_stats[i]];
}
}
int fx_polymorph (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_polymorph_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (!gamedata->Exists(fx->Resource,IE_CRE_CLASS_ID)) {
//kill all polymorph effects
target->fxqueue.RemoveAllEffectsWithParam(fx_polymorph_ref, fx->Parameter2);
//destroy the magic item slot
target->inventory.RemoveItem(target->inventory.GetMagicSlot() );
return FX_NOT_APPLIED;
}
// to avoid repeatedly loading the file or keeping all the data around
// wasting memory, we keep a PolymorphCache object around, with only
// the data we need from the polymorphed creature
bool cached = true;
if (!target->polymorphCache) {
cached = false;
target->polymorphCache = new PolymorphCache();
}
if (!cached || strnicmp(fx->Resource,target->polymorphCache->Resource,sizeof(fx->Resource))) {
Actor *newCreature = gamedata->GetCreature(fx->Resource,0);
//I don't know how could this happen, existance of the resource was already checked
if (!newCreature) {
return FX_NOT_APPLIED;
}
memcpy(target->polymorphCache->Resource, fx->Resource, sizeof(fx->Resource));
CopyPolymorphStats(newCreature, target);
delete newCreature;
}
//copy all polymorphed stats
if(!fx->Parameter2) {
STAT_SET( IE_POLYMORPHED, 1 );
//disable mage and cleric spells (see IE_CASTING doc above)
STAT_BIT_OR(IE_CASTING, 6);
STAT_BIT_OR(IE_DISABLEDBUTTON, (1<<ACT_CAST)|(1<<ACT_QSPELL1)|(1<<ACT_QSPELL2)|(1<<ACT_QSPELL3) );
}
for(int i=0;i<polystatcount;i++) {
//copy only the animation ID
if (fx->Parameter2 && polymorph_stats[i] != IE_ANIMATION_ID) continue;
target->SetStat(polymorph_stats[i], target->polymorphCache->stats[i], 1);
}
return FX_APPLIED;
}
// 0x88 ForceVisible
int fx_force_visible (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_force_visible (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (pstflags) {
BASE_STATE_CURE(STATE_PST_INVIS);
} else {
BASE_STATE_CURE(STATE_INVISIBLE);
}
target->fxqueue.RemoveAllEffectsWithParam(fx_set_invisible_state_ref,0);
target->fxqueue.RemoveAllEffectsWithParam(fx_set_invisible_state_ref,2);
return FX_NOT_APPLIED;
}
// 0x89 ChantBadNonCumulative
int fx_set_chantbad_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_chantbad_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (STATE_GET (STATE_CHANTBAD) ) //chant is non cumulative
return FX_NOT_APPLIED;
STATE_SET( STATE_CHANTBAD );
target->SetSpellState(SS_BADCHANT);
STAT_SUB( IE_LUCK, fx->Parameter1 );
return FX_APPLIED;
}
// 0x8A AnimationStateChange
int fx_animation_stance (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_animation_stance (%2d): Stance: %d\n", fx->Opcode, fx->Parameter2 );
//this effect works only on living actors
if ( !STATE_GET(STATE_DEAD) ) {
target->SetStance(fx->Parameter2);
}
return FX_NOT_APPLIED;
}
// 0x8B DisplayString
// gemrb extension: rgb colour for displaystring
static EffectRef fx_protection_from_display_string_ref={"Protection:String",NULL,-1};
int fx_display_string (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_display_string (%2d): StrRef: %d\n", fx->Opcode, fx->Parameter1 );
if (!target->fxqueue.HasEffectWithParamPair(fx_protection_from_display_string_ref, fx->Parameter1, 0) ) {
displaymsg->DisplayStringName(fx->Parameter1, fx->Parameter2?fx->Parameter2:0xffffff, target, IE_STR_SOUND|IE_STR_SPEECH);
}
return FX_NOT_APPLIED;
}
// 0x8c CastingGlow
static const int ypos_by_direction[16]={10,10,10,0,-10,-10,-10,-10,-10,-10,-10,-10,0,10,10,10};
static const int xpos_by_direction[16]={0,-10,-12,-14,-16,-14,-12,-10,0,10,12,14,16,14,12,10};
int fx_casting_glow (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_casting_glow (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
if (cgcount<0) {
cgcount = core->ReadResRefTable("cgtable",casting_glows);
}
//remove effect if map is not loaded
Map *map = target->GetCurrentArea();
if (!map) {
return FX_NOT_APPLIED;
}
if (fx->Parameter2<(ieDword) cgcount) {
ScriptedAnimation *sca = gamedata->GetScriptedAnimation(casting_glows[fx->Parameter2], false);
//remove effect if animation doesn't exist
if (!sca) {
return FX_NOT_APPLIED;
}
//12 is just an approximate value to set the height of the casting glow
//based on the avatar's size
int heightmod = target->GetAnims()->GetCircleSize()*12;
sca->XPos+=fx->PosX+xpos_by_direction[target->GetOrientation()];
sca->YPos+=fx->PosY+ypos_by_direction[target->GetOrientation()];
sca->ZPos+=heightmod;
sca->SetBlend();
if (fx->Duration) {
sca->SetDefaultDuration(fx->Duration-core->GetGame()->GameTime);
} else {
sca->SetDefaultDuration(10000);
}
map->AddVVCell(sca);
}
return FX_NOT_APPLIED;
}
//0x8d VisualSpellHit
int fx_visual_spell_hit (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_visual_spell_hit (%2d): Target: %d Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (shcount<0) {
shcount = core->ReadResRefTable("shtable",spell_hits);
}
//remove effect if map is not loaded
Map *map = target->GetCurrentArea();
if (!map) {
return FX_NOT_APPLIED;
}
if (fx->Parameter2<(ieDword) shcount) {
ScriptedAnimation *sca = gamedata->GetScriptedAnimation(spell_hits[fx->Parameter2], false);
//remove effect if animation doesn't exist
if (!sca) {
return FX_NOT_APPLIED;
}
if (fx->Parameter1) {
sca->XPos+=target->Pos.x;
sca->YPos+=target->Pos.y;
} else {
sca->XPos+=fx->PosX;
sca->YPos+=fx->PosY;
}
if (fx->Parameter2<32) {
int tmp = fx->Parameter2>>2;
if (tmp) {
sca->SetFullPalette(tmp);
}
}
sca->SetBlend();
sca->PlayOnce();
map->AddVVCell(sca);
} else {
printf("fx_visual_spell_hit: Unhandled Type: %d\n", fx->Parameter2);
}
return FX_NOT_APPLIED;
}
//0x8e Icon:Display
int fx_display_portrait_icon (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_display_string (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
target->AddPortraitIcon(fx->Parameter2);
return FX_APPLIED;
}
//0x8f Item:CreateInSlot
int fx_create_item_in_slot (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_create_item_in_slot (%2d): Button: %d\n", fx->Opcode, fx->Parameter2 );
//create item and set it in target's slot
target->inventory.SetSlotItemRes( fx->Resource, core->QuerySlot(fx->Parameter2), fx->Parameter1, fx->Parameter3, fx->Parameter4 );
if ((fx->TimingMode&0xff) == FX_DURATION_INSTANT_LIMITED) {
//convert it to a destroy item
fx->Opcode=EffectQueue::ResolveEffect(fx_remove_item_ref);
fx->TimingMode=FX_DURATION_DELAY_PERMANENT;
return FX_APPLIED;
}
return FX_NOT_APPLIED;
}
// 0x90 DisableButton
// different in iwd2 and the rest (maybe also in how: 0-7?)
int fx_disable_button (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_disable_button (%2d): Button: %d\n", fx->Opcode, fx->Parameter2 );
// iwd2 has a flexible action bar, so there are more possible parameter values
// only values 0-5 match the bg2 constants (which map to ACT_*)
// FIXME: support disabling all iwd2 buttons
if (target->spellbook.IsIWDSpellBook()) {
if (fx->Parameter2 < 6) STAT_BIT_OR( IE_DISABLEDBUTTON, 1<<fx->Parameter2 );
} else {
STAT_BIT_OR( IE_DISABLEDBUTTON, 1<<fx->Parameter2 );
}
if (fx->FirstApply && target->GetStat(IE_EA) < EA_CONTROLLABLE) {
core->SetEventFlag(EF_ACTION);
}
return FX_APPLIED;
}
//0x91 DisableSpellCasting
//bg2: (-1 item), 0 - mage, 1 - cleric, 2 - innate, 3 - class
//iwd2: (-1 item), 0 - all, 1 - mage+cleric, 2 - mage, 3 - cleric , 4 - innate,( 5 - class)
/*internal representation of disabled spells in IE_CASTING (bitfield):
1 - items (SPIT)
2 - cleric (SPPR)
4 - mage (SPWI)
8 - innate (SPIN)
16 - class (SPCL)
*/
static ieDword dsc_bits_iwd2[7]={1, 14, 6, 2, 4, 8, 16};
static ieDword dsc_bits_bg2[7]={1, 4, 2, 8, 16, 14, 6};
int fx_disable_spellcasting (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_disable_spellcasting (%2d): Button: %d\n", fx->Opcode, fx->Parameter2 );
bool display_warning = false;
ieDword tmp = fx->Parameter2+1;
//IWD2 Style spellbook
if (target->spellbook.IsIWDSpellBook()) {
switch(fx->Parameter2) {
case 0: // all
case 1: // mage and cleric
case 2: // mage
if (target->spellbook.GetKnownSpellsCount(IE_IWD2_SPELL_BARD, 0)) display_warning = true;
if (target->spellbook.GetKnownSpellsCount(IE_IWD2_SPELL_SORCEROR, 0)) display_warning = true;
if (target->spellbook.GetKnownSpellsCount(IE_IWD2_SPELL_WIZARD, 0)) display_warning = true;
break;
}
if (tmp<7) {
STAT_BIT_OR(IE_CASTING, dsc_bits_iwd2[tmp] );
}
} else { // bg2
if (fx->Parameter2 == 0) {
if (target->spellbook.GetKnownSpellsCount(IE_SPELL_TYPE_WIZARD, 0)) display_warning = true;
}
//-1-> 1 (item)
//0 -> 4 (mage)
//1 -> 2 (cleric)
//2 -> 8 (innate)
//3 -> 16 (class)
if (tmp<31) {
STAT_BIT_OR(IE_CASTING, dsc_bits_bg2[tmp] );
}
}
if (fx->FirstApply && display_warning && target->GetStat(IE_EA) < EA_CONTROLLABLE) {
displaymsg->DisplayConstantStringName(STR_DISABLEDMAGE, 0xff0000, target);
core->SetEventFlag(EF_ACTION);
}
return FX_APPLIED;
}
//0x92 Spell:Cast
int fx_cast_spell (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_cast_spell (%2d): Resource:%s Mode: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
if (fx->Parameter2) {
//apply spell on target
core->ApplySpell(fx->Resource, target, Owner, fx->Power);
// give feedback: Caster - spellname : target
char tmp[100];
Spell *spl = gamedata->GetSpell(fx->Resource);
if (spl) {
snprintf(tmp, sizeof(tmp), "%s : %s", core->GetString(spl->SpellName), target->GetName(-1));
displaymsg->DisplayStringName(tmp, 0xffffff, Owner);
}
} else {
//cast spell on target
Owner->CastSpell(fx->Resource, target, false);
//actually finish casting (if this is not good enough, use an action???)
Owner->CastSpellEnd(fx->Resource);
}
return FX_NOT_APPLIED;
}
// 0x93 Spell:Learn
int fx_learn_spell (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_learn_spell (%2d): Resource:%s Mode: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
//parameter1 is unused, gemrb lets you to make it not give XP
//probably we should also let this via a game flag if we want
//full compatibility with bg1
target->LearnSpell(fx->Resource, fx->Parameter2^LS_ADDXP);
return FX_NOT_APPLIED;
}
// 0x94 Spell:CastSpellPoint
int fx_cast_spell_point (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_cast_spell_point (%2d): Resource:%s Mode: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
Owner->CastSpellPoint(fx->Resource, target->Pos, false);
//actually finish casting (if this is not good enough, use an action???)
Owner->CastSpellPointEnd(fx->Resource);
return FX_NOT_APPLIED;
}
// 0x95 Identify
int fx_identify (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_identify (%2d): Resource:%s Mode: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
if (target->InParty) {
BASE_SET (IE_IDENTIFYMODE, 1);
core->SetEventFlag(EF_IDENTIFY);
}
return FX_NOT_APPLIED;
}
// 0x96 FindTraps
// (actually, in bg2 the effect targets area objects and the range is implemented
// by the inareans projectile) - inanimate, area, no sprite
// TODO: effects should target inanimates using different code
// 0 - detect traps automatically
// 1 - detect traps by skill
// 2 - detect secret doors automatically
// 3 - detect secret doors by luck
int fx_find_traps (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_find_traps (%2d)\n", fx->Opcode );
//reveal trapped containers, doors, triggers that are in the visible range
ieDword range = target->GetStat(IE_VISUALRANGE)*10;
ieDword skill;
bool detecttraps = true;
switch(fx->Parameter2) {
case 1:
skill = target->GetStat(IE_TRAPS);
break; //find traps
case 3:
//detect secret doors
skill = target->LuckyRoll(1,100,0);
detecttraps = false;
break;
case 2:
detecttraps = false;
default:
//automatic find traps
skill = 256;
break;
}
TileMap *TMap = target->GetCurrentArea()->TMap;
int Count = 0;
while (true) {
Door* door = TMap->GetDoor( Count++ );
if (!door)
break;
if (Distance(door->Pos, target->Pos)<range) {
if (detecttraps) {
//when was door trap noticed
door->DetectTrap(skill);
}
door->TryDetectSecret(skill);
}
}
if (!detecttraps) {
return FX_NOT_APPLIED;
}
Count = 0;
while (true) {
Container* container = TMap->GetContainer( Count++ );
if (!container)
break;
if (Distance(container->Pos, target->Pos)<range) {
//when was door trap noticed
container->DetectTrap(skill);
}
}
Count = 0;
while (true) {
InfoPoint* trap = TMap->GetInfoPoint( Count++ );
if (!trap)
break;
if (Distance(trap->Pos, target->Pos)<range) {
//when was door trap noticed
trap->DetectTrap(skill);
}
}
return FX_NOT_APPLIED;
}
// 0x97 ReplaceCreature
int fx_replace_creature (Scriptable* Owner, Actor* target, Effect *fx)
{
if (0) printf( "fx_replace_creature (%2d): Resource: %s\n", fx->Opcode, fx->Resource );
//this safeguard exists in the original engine too
if (!gamedata->Exists(fx->Resource,IE_CRE_CLASS_ID)) {
return FX_NOT_APPLIED;
}
//the monster should appear near the effect position? (unsure)
Point p(fx->PosX, fx->PosY);
//remove old creature
switch(fx->Parameter2) {
case 0: //remove silently
target->DestroySelf();
break;
case 1: //chunky death
target->NewBase(IE_HITPOINTS,(ieDword) -100, MOD_ABSOLUTE);
target->Die(Owner);
break;
case 2: //normal death
target->Die(Owner);
break;
default:;
}
//create replacement; should we be passing the target instead of NULL?
//noooo, don't unsummon replacement creatures! - fuzzie
//Effect *newfx = EffectQueue::CreateUnsummonEffect(fx);
core->SummonCreature(fx->Resource, fx->Resource2, Owner, NULL,p, EAM_DEFAULT,-1, NULL, 0);
//delete newfx;
return FX_NOT_APPLIED;
}
// 0x98 PlayMovie
int fx_play_movie (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
{
if (0) printf( "fx_play_movie (%2d): Resource: %s\n", fx->Opcode, fx->Resource );
core->PlayMovie (fx->Resource);
return FX_NOT_APPLIED;
}
// 0x99 Overlay:Sanctuary
#define ICE_GRADIENT 71
static const ieDword fullwhite[7]={ICE_GRADIENT,ICE_GRADIENT,ICE_GRADIENT,ICE_GRADIENT,ICE_GRADIENT,ICE_GRADIENT,ICE_GRADIENT};
int fx_set_sanctuary_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
//iwd and bg are a bit different, but we solve the whole stuff in a single opcode
if (0) printf( "fx_set_sanctuary_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (target->HasSpellState(SS_SANCTUARY)) return FX_NOT_APPLIED;
if (!fx->Parameter2) {
fx->Parameter2=1;
}
//this effect needs the pcf run immediately
STAT_SET_PCF( IE_SANCTUARY, fx->Parameter2);
//a rare event, but this effect gives more in bg2 than in iwd2
//so we use this flag
if (!enhanced_effects)
{
target->SetLockedPalette(fullwhite);
}
return FX_APPLIED;
}
// 0x9a Overlay:Entangle
int fx_set_entangle_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_entangle_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//iwd2 effects that disable entangle
if (target->HasSpellState(SS_FREEACTION)) return FX_NOT_APPLIED;
if (target->HasSpellState(SS_AEGIS)) return FX_NOT_APPLIED;
if (!fx->Parameter2) {
fx->Parameter2=1;
}
STAT_SET_PCF( IE_ENTANGLE, fx->Parameter2);
return FX_APPLIED;
}
// 0x9b Overlay:MinorGlobe
int fx_set_minorglobe_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_minorglobe_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//the resisted levels are stored in minor globe (bit 2-)
//the globe effect is stored in the first bit
STAT_BIT_OR_PCF( IE_MINORGLOBE, 1);
return FX_APPLIED;
}
// 0x9c Overlay:ShieldGlobe
int fx_set_shieldglobe_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_shieldglobe_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//the shield vanishes on dead
if (STATE_GET(STATE_DEAD) ) {
return FX_NOT_APPLIED;
}
STAT_SET_PCF( IE_SHIELDGLOBE, 1);
return FX_APPLIED;
}
// 0x9d Overlay:Web
int fx_set_web_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_web_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//iwd2 effects that disable web
if (target->HasSpellState(SS_FREEACTION)) return FX_NOT_APPLIED;
if (target->HasSpellState(SS_AEGIS)) return FX_NOT_APPLIED;
target->SetSpellState(SS_WEB);
//attack penalty in IWD2
STAT_SET_PCF( IE_WEB, 1);
STAT_SET(IE_MOVEMENTRATE, 0); //
return FX_APPLIED;
}
// 0x9e Overlay:Grease
int fx_set_grease_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_grease_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//iwd2 effects that disable grease
if (target->HasSpellState(SS_FREEACTION)) return FX_NOT_APPLIED;
if (target->HasSpellState(SS_AEGIS)) return FX_NOT_APPLIED;
target->SetSpellState(SS_GREASE);
STAT_SET_PCF( IE_GREASE, 1);
//the movement rate is set by separate opcodes in all engines
return FX_APPLIED;
}
// 0x9f MirrorImageModifier
int fx_mirror_image_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_mirror_image_modifier (%2d): Mod: %d\n", fx->Opcode, fx->Parameter1 );
if (STATE_GET(STATE_DEAD) ) {
return FX_NOT_APPLIED;
}
if (!fx->Parameter1) {
return FX_NOT_APPLIED;
}
if (pstflags) {
STATE_SET( STATE_PST_MIRROR );
}
else {
STATE_SET( STATE_MIRROR );
}
if (fx->Parameter2) {
target->SetSpellState(SS_REFLECTION);
} else {
target->SetSpellState(SS_MIRRORIMAGE);
}
//actually, there is no such stat in the original IE
STAT_SET( IE_MIRRORIMAGES, fx->Parameter1);
return FX_APPLIED;
}
// 0xa0 Cure:Sanctuary
static EffectRef fx_sanctuary_state_ref={"Overlay:Sanctuary",NULL,-1};
int fx_cure_sanctuary_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_sanctuary_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_SET( IE_SANCTUARY, 0);
target->fxqueue.RemoveAllEffects(fx_sanctuary_state_ref);
return FX_NOT_APPLIED;
}
// 0xa1 Cure:Panic
static EffectRef fx_set_panic_state_ref={"State:Panic",NULL,-1};
int fx_cure_panic_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_panic_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
BASE_STATE_CURE( STATE_PANIC );
target->fxqueue.RemoveAllEffects(fx_set_panic_state_ref);
return FX_NOT_APPLIED;
}
// 0xa2 Cure:Hold
static EffectRef fx_hold_creature_ref={"State:Hold",NULL,-1};
int fx_cure_hold_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_hold_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//note that this effect doesn't remove 185 (another hold effect)
target->fxqueue.RemoveAllEffects( fx_hold_creature_ref );
target->fxqueue.RemoveAllEffects(fx_hold_creature_no_icon_ref);
target->fxqueue.RemoveAllEffectsWithParam(fx_display_portrait_icon_ref, PI_HELD);
return FX_NOT_APPLIED;
}
// 0xa3 FreeAction
static EffectRef fx_movement_modifier_ref={"MovementRateModifier2",NULL,-1};
int fx_cure_slow_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_slow_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
target->fxqueue.RemoveAllEffects( fx_movement_modifier_ref );
// STATE_CURE( STATE_SLOWED );
return FX_NOT_APPLIED;
}
// 0xa4 Cure:Intoxication
static EffectRef fx_intoxication_ref={"IntoxicationModifier",NULL,-1};
int fx_cure_intoxication (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_intoxication (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
target->fxqueue.RemoveAllEffects( fx_intoxication_ref );
BASE_SET(IE_INTOXICATION,0);
return FX_NOT_APPLIED;
}
// 0xa5 PauseTarget
int fx_pause_target (Scriptable* /*Owner*/, Actor * target, Effect* fx)
{
if (0) printf( "fx_pause_target (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_CASTERHOLD );
return FX_PERMANENT;
}
// 0xa6 MagicResistanceModifier
int fx_magic_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_magic_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_RESISTMAGIC );
return FX_APPLIED;
}
// 0xa7 MissileHitModifier
int fx_missile_to_hit_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_missile_to_hit_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_MISSILEHITBONUS );
return FX_APPLIED;
}
// 0xa8 RemoveCreature
// removes targeted creature
// removes creature specified by resource key (gemrb extension)
int fx_remove_creature (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_remove_creature (%2d)\n", fx->Opcode);
Map *map = target->GetCurrentArea();
Actor *actor = target;
if (fx->Resource[0]) {
actor = map->GetActorByResource(fx->Resource);
}
if (actor) {
//leaveparty will be handled automagically
//plot critical items are not handled, shall we?
actor->DestroySelf();
}
return FX_NOT_APPLIED;
}
// 0xa9 Icon:Disable
int fx_disable_portrait_icon (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_disable_portrait_icon (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
target->DisablePortraitIcon(fx->Parameter2);
return FX_APPLIED;
}
// 0xaa DamageAnimation
int fx_damage_animation (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_damage_animation (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//Parameter1 is a gemrb extension
target->PlayDamageAnimation(fx->Parameter2, !fx->Parameter1);
return FX_NOT_APPLIED;
}
// 0xab Spell:Add
int fx_add_innate (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_add_innate (%2d): Resource: %s Mode: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
target->LearnSpell(fx->Resource, fx->Parameter2^LS_MEMO);
//this is an instant, so it shouldn't stick
return FX_NOT_APPLIED;
}
// 0xac Spell:Remove
//gemrb extension: deplete spell by resref
int fx_remove_spell (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_remove_spell (%2d): Resource: %s Type:%d\n", fx->Opcode, fx->Resource, fx->Parameter2);
switch (fx->Parameter2) {
default:
target->spellbook.RemoveSpell(fx->Resource);
break;
case 1: //forget all spells of Resource
do {} while(target->spellbook.HaveSpell( fx->Resource, HS_DEPLETE ));
break;
case 2: //forget x spells of resource
while( fx->Parameter1--) {
target->spellbook.HaveSpell( fx->Resource, HS_DEPLETE );
}
break;
}
//this is an instant, so it shouldn't stick
return FX_NOT_APPLIED;
}
// 0xad PoisonResistanceModifier
int fx_poison_resistance_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_poison_resistance_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_RESISTPOISON );
return FX_APPLIED;
}
//0xae PlaySound
int fx_playsound (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_playsound (%s)", fx->Resource );
//this is probably inaccurate
if (target) {
core->GetAudioDrv()->Play(fx->Resource, target->Pos.x, target->Pos.y);
} else {
core->GetAudioDrv()->Play(fx->Resource);
}
//this is an instant, it shouldn't stick
return FX_NOT_APPLIED;
}
//0x6d State:Hold3
//0xfb State:Hold4
int fx_hold_creature_no_icon (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_hold_creature_no_icon (%2d): Value: %d, IDS: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//actually the original engine just skips this effect if the target is dead
if ( STATE_GET(STATE_DEAD) ) {
return FX_NOT_APPLIED;
}
if (!EffectQueue::match_ids( target, fx->Parameter2, fx->Parameter1) ) {
//if the ids don't match, the effect doesn't stick
return FX_NOT_APPLIED;
}
target->SetSpellState(SS_HELD);
STAT_SET( IE_HELD, 1);
return FX_APPLIED;
}
//0xaf State:Hold
//0xb9 State:Hold2
//(0x6d/0x1a8 for iwd2)
int fx_hold_creature (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_hold_creature (%2d): Value: %d, IDS: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//actually the original engine just skips this effect if the target is dead
if ( STATE_GET(STATE_DEAD) ) {
return FX_NOT_APPLIED;
}
//iwd2 free action or blood rage disables this effect
if (target->HasSpellState(SS_FREEACTION)) return FX_NOT_APPLIED;
if (target->HasSpellState(SS_BLOODRAGE)) return FX_NOT_APPLIED;
if (target->HasSpellState(SS_AEGIS)) return FX_NOT_APPLIED;
if (!EffectQueue::match_ids( target, fx->Parameter2, fx->Parameter1) ) {
//if the ids don't match, the effect doesn't stick
return FX_NOT_APPLIED;
}
target->SetSpellState(SS_HELD);
STAT_SET( IE_HELD, 1);
target->AddPortraitIcon(PI_HELD);
return FX_APPLIED;
}
//0xb0 see: fx_movement_modifier
//0xb1 ApplyEffect
int fx_apply_effect (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_apply_effect (%2d) %s", fx->Opcode, fx->Resource );
//this effect executes a file effect in place of this effect
//the file effect inherits the target and the timingmode, but gets
//a new chance to roll percents
int ret = FX_NOT_APPLIED;
if (!target) {
return ret;
}
if (EffectQueue::match_ids( target, fx->Parameter2, fx->Parameter1) ) {
Point p(fx->PosX, fx->PosY);
//apply effect, if the effect is a goner, then kill
//this effect too
Effect *newfx = core->GetEffect(fx->Resource, fx->Power, p);
if (newfx) {
Effect *myfx = new Effect;
memcpy(myfx, newfx, sizeof(Effect));
myfx->random_value = core->Roll(1,100,-1);
myfx->Target = FX_TARGET_PRESET;
myfx->TimingMode = fx->TimingMode;
myfx->Duration = fx->Duration;
myfx->CasterID = fx->CasterID;
ret = target->fxqueue.ApplyEffect(target, myfx, fx->FirstApply, !fx->Parameter3);
fx->Parameter3 = 1;
delete myfx;
}
//newfx is a borrowed reference don't delete it
}
return ret;
}
//0xb2 hitbonus generic effect ToHitVsCreature
//0xb3 damagebonus generic effect DamageVsCreature
// b4 can't use item (resource) generic effect CantUseItem
// b5 can't use itemtype (resource) generic effect CantUseItemType
// b6 generic effect ApplyEffectItem
int fx_apply_effect_item (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf("fx_apply_effect_item (%2d) (%.8s)\n", fx->Opcode, fx->Resource);
if (target->inventory.HasItem(fx->Resource, 0) ) {
core->ApplySpell(fx->Resource2, target, Owner, fx->Parameter1);
return FX_NOT_APPLIED;
}
return FX_APPLIED;
}
// b7 generic effect ApplyEffectItemType
int fx_apply_effect_item_type (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf("fx_apply_effect_item (%2d), Type: %d\n", fx->Opcode, fx->Parameter2);
if (target->inventory.HasItemType(fx->Parameter2) ) {
core->ApplySpell(fx->Resource, target, Owner, fx->Parameter1);
return FX_NOT_APPLIED;
}
return FX_APPLIED;
}
// b8 DontJumpModifier
int fx_dontjump_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_dontjump_modifier (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_SET( IE_DONOTJUMP, fx->Parameter2 );
return FX_APPLIED;
}
//0xb9 see above: fx_hold_creature
//0xba MoveToArea
int fx_move_to_area (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_move_to_area (%2d) %s", fx->Opcode, fx->Resource );
//delay effect until the target has finished the previous move to an area
//hopefully this fixes an evil bug
Map *map = target->GetCurrentArea();
if (!map || !map->HasActor(target)) {
//stay around for the next evaluation
return FX_APPLIED;
}
Point p(fx->PosX,fx->PosY);
MoveBetweenAreasCore(target, fx->Resource, p, fx->Parameter2, true);
//this effect doesn't stick
return FX_NOT_APPLIED;
}
// 0xbb Variable:StoreLocalVariable
int fx_local_variable (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
//this is a hack, the variable name spreads across the resources
if (0) printf( "fx_local_variable (%2d) %s=%d", fx->Opcode, fx->Resource, fx->Parameter1 );
target->locals->SetAt(fx->Resource, fx->Parameter1);
//local variable effects are not applied, they will be resaved though
return FX_NOT_APPLIED;
}
// 0xbc AuraCleansingModifier
int fx_auracleansing_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_auracleansing_modifier (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_SET( IE_AURACLEANSING, fx->Parameter2 );
return FX_APPLIED;
}
// 0xbd CastingSpeedModifier
int fx_castingspeed_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_castingspeed_modifier (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_MOD( IE_MENTALSPEED );
return FX_APPLIED;
}
// 0xbe PhysicalSpeedModifier
int fx_attackspeed_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_attackspeed_modifier (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_MOD( IE_PHYSICALSPEED );
return FX_APPLIED;
}
// 0xbf CastingLevelModifier
int fx_castinglevel_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_castinglevel_modifier (%2d) Value:%d Type:%d", fx->Opcode, fx->Parameter1, fx->Parameter2 );
switch (fx->Parameter2) {
case 0:
STAT_SET( IE_CASTINGLEVELBONUSMAGE, fx->Parameter1 );
break;
case 1:
STAT_SET( IE_CASTINGLEVELBONUSCLERIC, fx->Parameter1 );
break;
default:
return FX_NOT_APPLIED;
}
return FX_APPLIED;
}
// 0xc0 FindFamiliar
// param2 = 1 alignment is in param1
// param2 = 2 resource used
#define FAMILIAR_NORMAL 0
#define FAMILIAR_ALIGNMENT 1
#define FAMILIAR_RESOURCE 2
static EffectRef fx_familiar_constitution_loss_ref={"FamiliarBond",NULL,-1};
static EffectRef fx_familiar_marker_ref={"FamiliarMarker",NULL,-1};
static EffectRef fx_maximum_hp_modifier_ref={"MaximumHPModifier",NULL,-1};
int fx_find_familiar (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_find_familiar (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
if (!target) {
return FX_NOT_APPLIED;
}
if (!target->GetCurrentArea()) {
return FX_APPLIED;
}
if (fx->Parameter2!=FAMILIAR_RESOURCE) {
ieDword alignment;
if (fx->Parameter2==FAMILIAR_ALIGNMENT) {
alignment = fx->Parameter1;
} else {
alignment = target->GetStat(IE_ALIGNMENT);
alignment = ((alignment&AL_LC_MASK)>>4)*3+(alignment&AL_GE_MASK)-4;
}
if (alignment>8) {
return FX_NOT_APPLIED;
}
memcpy(fx->Resource, core->GetGame()->Familiars[alignment],sizeof(ieResRef) );
fx->Parameter2=FAMILIAR_RESOURCE;
}
//summon familiar with fx->Resource
Actor *fam = gamedata->GetCreature(fx->Resource);
if (!fam) {
return FX_NOT_APPLIED;
}
fam->SetBase(IE_EA, EA_FAMILIAR);
fam->LastSummoner = Owner->GetGlobalID();
Map *map = target->GetCurrentArea();
map->AddActor(fam);
Point p(fx->PosX, fx->PosY);
fam->SetPosition(p, true, 0);
fam->RefreshEffects(NULL);
if (fx->Resource2[0]) {
ScriptedAnimation* vvc = gamedata->GetScriptedAnimation(fx->Resource2, false);
if (vvc) {
//This is the final position of the summoned creature
//not the original target point
vvc->XPos=fam->Pos.x;
vvc->YPos=fam->Pos.y;
//force vvc to play only once
vvc->PlayOnce();
map->AddVVCell( vvc );
}
}
//Make the familiar an NPC (MoveGlobal needs this)
core->GetGame()->AddNPC(fam);
//Add some essential effects
Effect *newfx = EffectQueue::CreateEffect(fx_familiar_constitution_loss_ref, fam->GetBase(IE_HITPOINTS)/2, 0, FX_DURATION_INSTANT_PERMANENT);
core->ApplyEffect(newfx, fam, fam);
delete newfx;
newfx = EffectQueue::CreateEffect(fx_familiar_marker_ref, 0, 0, FX_DURATION_INSTANT_PERMANENT);
core->ApplyEffect(newfx, fam, fam);
delete newfx;
//maximum hp bonus of half the familiar's hp
newfx = EffectQueue::CreateEffect(fx_maximum_hp_modifier_ref, fam->GetBase(IE_HITPOINTS)/2, MOD_ADDITIVE, FX_DURATION_INSTANT_PERMANENT);
core->ApplyEffect(newfx, (Actor *) Owner, Owner);
delete newfx;
return FX_NOT_APPLIED;
}
// 0xc1 InvisibleDetection
int fx_see_invisible_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_see_invisible_modifier (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_SET( IE_SEEINVISIBLE, fx->Parameter2 );
return FX_APPLIED;
}
// 0xc2 IgnoreDialogPause
int fx_ignore_dialogpause_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_ignore_dialogpause_modifier (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_SET( IE_IGNOREDIALOGPAUSE, fx->Parameter2 );
return FX_APPLIED;
}
//0xc3 FamiliarBond
//when this effect's target dies it should incur damage on protagonist
static EffectRef fx_damage_opcode_ref={"Damage",NULL,-1};
static EffectRef fx_constitution_modifier_ref={"ConstitutionModifier",NULL,-1};
int fx_familiar_constitution_loss (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_familiar_constitution_loss (%2d): Loss: %d\n", fx->Opcode,(signed) fx->Parameter1 );
if (! (STAT_GET(IE_STATE_ID)&STATE_NOSAVE)) {
return FX_APPLIED;
}
Effect *newfx;
//familiar died
Actor *master = core->GetGame()->FindPC(1);
if (!master) return FX_NOT_APPLIED;
//lose 1 point of constitution
newfx = EffectQueue::CreateEffect(fx_constitution_modifier_ref, (ieDword) -1, MOD_ADDITIVE, FX_DURATION_INSTANT_PERMANENT);
core->ApplyEffect(newfx, master, master);
delete newfx;
//remove the maximum hp bonus
newfx = EffectQueue::CreateEffect(fx_maximum_hp_modifier_ref, (ieDword) -fx->Parameter1, 3, FX_DURATION_INSTANT_PERMANENT);
core->ApplyEffect(newfx, master, master);
delete newfx;
//damage for half of the familiar's hitpoints
newfx = EffectQueue::CreateEffect(fx_damage_opcode_ref, fx->Parameter1, DAMAGE_CRUSHING, FX_DURATION_INSTANT_PERMANENT);
core->ApplyEffect(newfx, master, master);
delete newfx;
return FX_NOT_APPLIED;
}
//0xc4 FamiliarMarker
int fx_familiar_marker (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_familiar_marker (%2d)\n", fx->Opcode );
if (! (STAT_GET(IE_STATE_ID)&STATE_NOSAVE)) {
//TODO: where to disable familiar?
//core->GetGame()->WeatherBits|=1;
return FX_APPLIED;
}
//TODO: enable familiar?
//core->GetGame()->WeatherBits&=~1;
return FX_NOT_APPLIED;
}
// 0xc5 Bounce:Projectile
int fx_bounce_projectile (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_bounce_projectile (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_BIT_OR( IE_BOUNCE, BNC_PROJECTILE );
return FX_APPLIED;
}
// 0xc6 Bounce:Opcode
int fx_bounce_opcode (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_bounce_opcode (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_BIT_OR( IE_BOUNCE, BNC_OPCODE );
target->AddPortraitIcon(PI_BOUNCE2);
return FX_APPLIED;
}
// 0xc7 Bounce:SpellLevel
int fx_bounce_spelllevel (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_bounce_spellevel (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_BIT_OR( IE_BOUNCE, BNC_LEVEL );
target->AddPortraitIcon(PI_BOUNCE2);
return FX_APPLIED;
}
// 0xc8 Bounce:SpellLevelDec
int fx_bounce_spelllevel_dec (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_bounce_spellevel_dec (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_BIT_OR( IE_BOUNCE, BNC_LEVEL_DEC );
target->AddPortraitIcon(PI_BOUNCE);
return FX_APPLIED;
}
//0xc9 Protection:SpellLevelDec
int fx_protection_spelllevel_dec (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_protection_spelllevel_dec (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_BIT_OR( IE_IMMUNITY, IMM_LEVEL_DEC );
target->AddPortraitIcon(PI_BOUNCE2);
return FX_APPLIED;
}
//0xca Bounce:School
int fx_bounce_school (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_bounce_school (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_BIT_OR( IE_BOUNCE, BNC_SCHOOL );
target->AddPortraitIcon(PI_BOUNCE2);
return FX_APPLIED;
}
// 0xcb Bounce:SecondaryType
int fx_bounce_secondary_type (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_bounce_secondary_type (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_BIT_OR( IE_BOUNCE, BNC_SECTYPE );
target->AddPortraitIcon(PI_BOUNCE2);
return FX_APPLIED;
}
// 0xcc //resist school
int fx_protection_school (Scriptable* /*Owner*/, Actor* target, Effect *fx)
{
if (0) printf( "fx_protection_school (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_BIT_OR( IE_IMMUNITY, IMM_SCHOOL);
return FX_APPLIED;
}
// 0xcd //resist sectype
int fx_protection_secondary_type (Scriptable* /*Owner*/, Actor* target, Effect *fx)
{
if (0) printf( "fx_protection_secondary_type (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_BIT_OR( IE_IMMUNITY, IMM_SECTYPE);
return FX_APPLIED;
}
//0xce Protection:Spell
int fx_resist_spell (Scriptable* /*Owner*/, Actor* target, Effect *fx)
{
if (0) printf( "fx_resist_spell (%2d): Resource: %s\n", fx->Opcode, fx->Resource );
if (strnicmp(fx->Resource,fx->Source,sizeof(fx->Resource)) ) {
STAT_BIT_OR( IE_IMMUNITY, IMM_RESOURCE);
return FX_APPLIED;
}
//this has effect only on first apply, it will stop applying the spell
return FX_ABORT;
}
// ??? Protection:SpellDec
int fx_resist_spell_dec (Scriptable* /*Owner*/, Actor* target, Effect *fx)
{
if (0) printf( "fx_resist_spell_dec (%2d): Resource: %s\n", fx->Opcode, fx->Resource );
if (strnicmp(fx->Resource,fx->Source,sizeof(fx->Resource)) ) {
STAT_BIT_OR( IE_IMMUNITY, IMM_RESOURCE_DEC);
return FX_APPLIED;
}
//this has effect only on first apply, it will stop applying the spell
return FX_ABORT;
}
// 0xcf Bounce:Spell
int fx_bounce_spell (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_bounce_spell (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_BIT_OR( IE_BOUNCE, BNC_RESOURCE );
return FX_APPLIED;
}
// ??? Bounce:SpellDec
int fx_bounce_spell_dec (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_bounce_spell (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_BIT_OR( IE_BOUNCE, BNC_RESOURCE_DEC );
return FX_APPLIED;
}
// 0xd0 MinimumHPModifier
// the original engine didn't allow modifying of this stat
// it allowed only setting it, and only by one instance
int fx_minimum_hp_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_minimum_hp_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_MINHITPOINTS );
return FX_APPLIED;
}
//0xd1 PowerWordKill
int fx_power_word_kill (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_power_word_kill (%2d): HP: %d Stat: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
ieDword limit = 60;
if (fx->Parameter1) {
limit = fx->Parameter1;
}
//normally this would work only with hitpoints
//but why not add some extra features
ieDword stat = target->GetStat (fx->Parameter2&0xffff);
if (stat < limit) {
target->Die( Owner );
}
return FX_NOT_APPLIED;
}
//0xd2 PowerWordStun
int fx_power_word_stun (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_power_word_stun (%2d): HP: %d Stat: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
ieDword limit = 90;
if (fx->Parameter1) {
limit = fx->Parameter1;
}
//normally this would work only with hitpoints
//but why not add some extra features
ieDword stat = target->GetStat (fx->Parameter2&0xffff);
ieDword x = fx->Parameter2>>16; //dice sides
if (stat > limit) {
return FX_NOT_APPLIED;
}
//recalculate delay
stat = (stat * 3 + limit - 1) / limit;
//delay will be calculated as 1dx/2dx/3dx
//depending on the current hitpoints (or the stat in param2)
stat = core->Roll(stat,x?x:4,0) * core->Time.round_size;
fx->Duration = core->GetGame()->GameTime+stat;
fx->TimingMode = FX_DURATION_ABSOLUTE;
fx->Opcode = EffectQueue::ResolveEffect(fx_set_stun_state_ref);
return fx_set_stun_state(Owner,target,fx);
}
//0xd3 State:Imprisonment (avatar removal plus portrait icon)
int fx_imprisonment (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_inprisonment (%2d)\n", fx->Opcode );
target->SetMCFlag(MC_HIDDEN, BM_OR);
target->AddPortraitIcon(PI_PRISON);
return FX_APPLIED;
}
//0xd4 Cure:Imprisonment
static EffectRef fx_imprisonment_ref={"Imprisonment",NULL,-1};
static EffectRef fx_maze_ref={"Maze",NULL,-1};
int fx_freedom (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_freedom (%2d)\n", fx->Opcode );
target->fxqueue.RemoveAllEffects( fx_imprisonment_ref );
target->fxqueue.RemoveAllEffects( fx_maze_ref );
return FX_NOT_APPLIED;
}
//0xd5 Maze
int fx_maze (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_maze (%2d)\n", fx->Opcode );
target->SetMCFlag(MC_HIDDEN, BM_OR);
target->AddPortraitIcon(PI_MAZE);
return FX_APPLIED;
}
//0xd6 CastFromList
int fx_select_spell (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
{
if (0) printf( "fx_select_spell (%2d) %d\n", fx->Opcode, fx->Parameter2 );
//if parameter2==0 -> cast spells from 2da (all spells listed in 2da)
//if parameter2==1 -> cast spells from book (all known spells, no need of memorize)
return FX_NOT_APPLIED;
}
// 0xd7 PlayVisualEffect
static EffectRef fx_protection_from_animation_ref={"Protection:Animation",NULL,-1};
int fx_play_visual_effect (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_play_visual_effect (%2d): Resource: %s Type: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
//this is in the original engine (dead actors lose this effect)
if (STATE_GET( STATE_DEAD) ) {
return FX_NOT_APPLIED;
}
//delay action until area is loaded to avoid crash
Map *map = target->GetCurrentArea();
if (!map) return FX_APPLIED;
//if it is sticky, don't add it if it is already played
if (fx->Parameter2) {
ScriptedAnimation *vvc = target->GetVVCCell(fx->Resource);
if (vvc) {
vvc->active = true;
return FX_APPLIED;
}
}
if (target->fxqueue.HasEffectWithResource(fx_protection_from_animation_ref,fx->Resource)) {
//effect supressed by opcode 0x128
return FX_APPLIED;
}
ScriptedAnimation* sca = gamedata->GetScriptedAnimation(fx->Resource, false);
//don't crash on nonexistent resources
if (!sca) {
return FX_NOT_APPLIED;
}
if (fx->TimingMode!=FX_DURATION_INSTANT_PERMANENT) {
sca->SetDefaultDuration(fx->Duration-core->GetGame()->GameTime);
}
if (fx->Parameter2 == 1) {
//play over target (sticky)
sca->effect_owned = true;
target->AddVVCell( sca );
return FX_APPLIED;
}
//not sticky
if (fx->Parameter2 == 2 || !target) {
sca->XPos = fx->PosX;
sca->YPos = fx->PosY;
} else {
sca->XPos = target->Pos.x;
sca->YPos = target->Pos.y;
}
sca->PlayOnce();
map->AddVVCell( sca );
return FX_NOT_APPLIED;
}
//d8 LevelDrainModifier
static EffectRef fx_leveldrain_ref={"LevelDrainModifier",NULL,-1};
// FIXME: BG2 level drain uses parameter3 to decrease the MaxHp, and parameter4 to decrease level. (unset)
int fx_leveldrain_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_leveldrain_modifier (%2d): Mod: %d\n", fx->Opcode, fx->Parameter1 );
//never subtract more than the maximum hitpoints
ieDword x = STAT_GET(IE_MAXHITPOINTS)-1;
if (fx->Parameter1*4<x) {
x=fx->Parameter1*4;
}
STAT_ADD(IE_LEVELDRAIN, fx->Parameter1);
STAT_SUB(IE_MAXHITPOINTS, x);
STAT_SUB(IE_SAVEVSDEATH, fx->Parameter1);
STAT_SUB(IE_SAVEVSWANDS, fx->Parameter1);
STAT_SUB(IE_SAVEVSPOLY, fx->Parameter1);
STAT_SUB(IE_SAVEVSBREATH, fx->Parameter1);
STAT_SUB(IE_SAVEVSSPELL, fx->Parameter1);
target->AddPortraitIcon(PI_LEVELDRAIN);
//decrease current hitpoints on first apply
if (fx->FirstApply) {
//current hitpoints don't have base/modified, only current
BASE_SUB(IE_HITPOINTS, x);
}
// TODO: lore, thieving
return FX_APPLIED;
}
//d9 PowerWordSleep
static EffectRef fx_sleep_ref={"State:Sleep",NULL,-1};
int fx_power_word_sleep (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_power_word_sleep (%2d): HP: %d Stat: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
ieDword limit = 20;
if (fx->Parameter1) {
limit = fx->Parameter1;
}
ieDword stat = target->GetStat (fx->Parameter2&0xffff);
ieDword x = fx->Parameter2>>16; //rounds
if (!x) x = 5;
if (stat>limit) {
return FX_NOT_APPLIED;
}
//translate this effect to a normal sleep effect
//recalculate delay
fx->Duration = core->GetGame()->GameTime+x*core->Time.round_size;
fx->TimingMode = FX_DURATION_ABSOLUTE;
fx->Opcode = EffectQueue::ResolveEffect(fx_sleep_ref);
fx->Parameter2=0;
return fx_set_unconscious_state(Owner,target,fx);
}
// 0xda StoneSkinModifier
int fx_stoneskin_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_stoneskin_modifier (%2d): Mod: %d\n", fx->Opcode, fx->Parameter1 );
if (!fx->Parameter1) {
return FX_NOT_APPLIED;
}
//dead actors lose this effect
if (STATE_GET( STATE_DEAD) ) {
return FX_NOT_APPLIED;
}
//this is the bg2 style stoneskin, not normally using spell states
//but this way we can support hybrid games
if (fx->Parameter2) {
target->SetSpellState(SS_IRONSKIN);
//gradient for iron skins?
} else {
target->SetSpellState(SS_STONESKIN);
SetGradient(target, 14);
}
STAT_SET(IE_STONESKINS, fx->Parameter1);
target->AddPortraitIcon(PI_STONESKIN);
return FX_APPLIED;
}
//0xdb ac vs creature type (general effect)
//0xdc DispelSchool
int fx_dispel_school (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
ieResRef Removed;
if (0) printf( "fx_dispel_school (%2d): Level: %d Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
target->fxqueue.RemoveLevelEffects(Removed, fx->Parameter1, RL_MATCHSCHOOL, fx->Parameter2);
return FX_NOT_APPLIED;
}
//0xdd DispelSecondaryType
int fx_dispel_secondary_type (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
ieResRef Removed;
if (0) printf( "fx_dispel_secondary_type (%2d): Level: %d Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
target->fxqueue.RemoveLevelEffects(Removed, fx->Parameter1, RL_MATCHSECTYPE, fx->Parameter2);
return FX_NOT_APPLIED;
}
//0xde RandomTeleport
int fx_teleport_field (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_teleport_field (%2d): Distance: %d\n", fx->Opcode, fx->Parameter1 );
Map *map = target->GetCurrentArea();
if (!map) {
return FX_NOT_APPLIED;
}
//the origin is the effect's target point
Point p(fx->PosX+core->Roll(1,fx->Parameter1*2,-(signed) (fx->Parameter1)),
fx->PosY+core->Roll(1,fx->Parameter1*2,-(signed) (fx->Parameter1)) );
target->SetPosition( p, true, 0);
return FX_NOT_APPLIED;
}
//0xdf //Protection:SchoolDec
int fx_protection_school_dec (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_protection_school_dec (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
if (fx->Parameter1) {
STAT_BIT_OR( IE_IMMUNITY, IMM_SCHOOL_DEC );
return FX_APPLIED;
}
return FX_NOT_APPLIED;
}
//0xe0 Cure:LevelDrain
int fx_cure_leveldrain (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_leveldrain (%2d)\n", fx->Opcode );
//all level drain removed at once???
//if not, then find old effect, remove a number
target->fxqueue.RemoveAllEffects( fx_leveldrain_ref );
return FX_NOT_APPLIED;
}
//0xe1 Reveal:Magic
//gemrb special: speed and color are custom
int fx_reveal_magic (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_reveal_magic (%2d)\n", fx->Opcode );
if (target->fxqueue.HasAnyDispellableEffect()) {
if (!fx->Parameter1) {
fx->Parameter1=0xff00; //blue
}
int speed = (fx->Parameter2 >> 16) & 0xFF;
if (!speed) speed=30;
target->SetColorMod(0xff, RGBModifier::ADD, speed,
fx->Parameter1 >> 8, fx->Parameter1 >> 16,
fx->Parameter1 >> 24, 0);
}
return FX_NOT_APPLIED;
}
//0xe2 Protection:SecondaryTypeDec
int fx_protection_secondary_type_dec (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_protection_secondary_type_dec (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
if (fx->Parameter1) {
STAT_BIT_OR( IE_IMMUNITY, IMM_SECTYPE_DEC );
return FX_APPLIED;
}
return FX_NOT_APPLIED;
}
//0xe3 Bounce:SchoolDecrement
int fx_bounce_school_dec (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_bounce_school_dec (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_BIT_OR( IE_BOUNCE, BNC_SCHOOL_DEC );
target->AddPortraitIcon(PI_BOUNCE2);
return FX_APPLIED;
}
//0xe4 Bounce:SecondaryTypeDecrement
int fx_bounce_secondary_type_dec (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_bounce_secondary_type_dec (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
STAT_BIT_OR( IE_BOUNCE, BNC_SECTYPE_DEC );
target->AddPortraitIcon(PI_BOUNCE2);
return FX_APPLIED;
}
//0xe5 DispelSchoolOne
int fx_dispel_school_one (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
ieResRef Removed;
if (0) printf( "fx_dispel_school_one (%2d): Level: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
target->fxqueue.RemoveLevelEffects(Removed, fx->Parameter1, RL_MATCHSCHOOL|RL_REMOVEFIRST, fx->Parameter2);
return FX_NOT_APPLIED;
}
//0xe6 DispelSecondaryTypeOne
int fx_dispel_secondary_type_one (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
ieResRef Removed;
if (0) printf( "fx_dispel_secondary_type_one (%2d): Level: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
target->fxqueue.RemoveLevelEffects(Removed, fx->Parameter1, RL_MATCHSECTYPE|RL_REMOVEFIRST, fx->Parameter2);
return FX_NOT_APPLIED;
}
//0xe7 Timestop
int fx_timestop (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_timestop (%2d)\n", fx->Opcode);
core->GetGame()->TimeStop(target, fx->Duration);
return FX_NOT_APPLIED;
}
//0xe8 CastSpellOnCondition
int fx_cast_spell_on_condition (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_cast_spell_on_condition (%2d): Target: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (fx->FirstApply && fx->Parameter3) {
target->spellbook.HaveSpell( fx->Resource, HS_DEPLETE );
target->spellbook.HaveSpell( fx->Resource2, HS_DEPLETE );
target->spellbook.HaveSpell( fx->Resource3, HS_DEPLETE );
target->spellbook.HaveSpell( fx->Resource4, HS_DEPLETE );
}
//get subject of check
Actor *actor = NULL;
Map *map = target->GetCurrentArea();
switch(fx->Parameter1) {
//self
case 0: actor = target; break;
//last attacker
case 1: actor = map->GetActorByGlobalID(target->LastHitter); break;
//nearest enemy
//fix this!
//case 2: actor = map->GetActorByGlobalID(target->LastSeen); break;
case 2: actor = GetNearestEnemyOf(map, target, 0); break;
//nearest creature
case 3: actor = map->GetActorByGlobalID(target->LastSeen); break;
}
if (!actor) {
return FX_APPLIED;
}
int condition;
//check condition
switch(fx->Parameter2) {
case COND_GOTHIT: //on hit
condition = target->LastDamage;
break;
case COND_NEAR: //
condition = PersonalDistance(actor, target)<30;
break;
case COND_HP_HALF:
condition = actor->GetBase(IE_HITPOINTS)<actor->GetStat(IE_MAXHITPOINTS)/2;
break;
case COND_HP_QUART:
condition = actor->GetBase(IE_HITPOINTS)<actor->GetStat(IE_MAXHITPOINTS)/4;
break;
case COND_HP_LOW:
condition = actor->GetBase(IE_HITPOINTS)<actor->GetStat(IE_MAXHITPOINTS)/10;
break;
case COND_HELPLESS:
condition = actor->GetStat(IE_STATE_ID) & STATE_CANTMOVE;
break;
case COND_POISONED:
condition = actor->GetStat(IE_STATE_ID) & STATE_POISONED;
break;
case COND_ATTACKED: // once per round
condition = actor->LastHitter;
break;
case COND_NEAR4: // closer than 4'
condition = PersonalDistance(actor, target)<4;
break;
case COND_NEAR10: // closer than 10'
condition = PersonalDistance(actor, target)<10;
break;
case COND_EVERYROUND:
condition = 1;
break;
case COND_TOOKDAMAGE:
condition = actor->LastDamage;
break;
default:
condition = 0;
}
if (condition) {
core->ApplySpell(fx->Resource, actor, Owner, fx->Power);
core->ApplySpell(fx->Resource2, actor, Owner, fx->Power);
core->ApplySpell(fx->Resource3, actor, Owner, fx->Power);
core->ApplySpell(fx->Resource4, actor, Owner, fx->Power);
if (fx->Parameter3) {
return FX_NOT_APPLIED;
}
}
return FX_APPLIED;
}
// 0xe9 Proficiency
int fx_proficiency (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_proficiency (%2d): Value: %d, Stat: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (fx->Parameter2>=MAX_STATS) return FX_NOT_APPLIED;
//this opcode works only if the previous value was smaller
if (STAT_GET(fx->Parameter2)<fx->Parameter1) {
STAT_SET (fx->Parameter2, fx->Parameter1);
}
return FX_APPLIED;
}
// 0xea CreateContingency
static EffectRef fx_contingency_ref={"CastSpellOnCondition",NULL,-1};
int fx_create_contingency (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_create_contingency (%2d): Level: %d, Count: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (target->fxqueue.HasEffectWithSource(fx_contingency_ref, fx->Source)) {
displaymsg->DisplayConstantStringName(STR_CONTDUP, 0xf0f0f0, target);
return FX_NOT_APPLIED;
}
if (target->InParty) {
Variables *dict = core->GetDictionary();
dict->SetAt( "P0", target->InParty );
dict->SetAt( "P1", fx->Parameter1 );
dict->SetAt( "P2", fx->Parameter2 );
core->SetEventFlag(EF_SEQUENCER);
}
return FX_NOT_APPLIED;
}
#define WB_AWAY 0
#define WB_TOWARDS 1
#define WB_FIXDIR 2
#define WB_OWNDIR 3
#define WB_AWAYOWNDIR 4
// 0xeb WingBuffet
int fx_wing_buffet (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_wing_buffet (%2d): Value: %d, Stat: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//create movement in actor
ieDword dir;
switch(fx->Parameter2) {
case WB_AWAY:
default:
dir = GetOrient(Owner->Pos, target->Pos);
break;
case WB_TOWARDS:
dir = GetOrient(target->Pos, Owner->Pos);
break;
case WB_FIXDIR:
dir = fx->Parameter3;
break;
case WB_OWNDIR:
dir = target->GetOrientation();
break;
case WB_AWAYOWNDIR:
dir = target->GetOrientation()^8;
break;
}
//could be GL_REBOUND too :)
//add effect to alter target's stance
target->MoveLine( fx->Parameter1, GL_NORMAL, dir );
return FX_NOT_APPLIED;
}
// 0xec ProjectImage
static EffectRef fx_puppetmarker_ref={"PuppetMarker",NULL,-1};
int fx_puppet_master (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
const char * resref = NULL;
if (0) printf( "fx_puppet_master (%2d): Value: %d, Stat: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_SET (IE_PUPPETMASTERTYPE, fx->Parameter1);
//copyself doesn't copy scripts, so the script clearing code is not needed
Actor *copy = target->CopySelf(fx->Parameter2 == 1);
Effect *newfx = EffectQueue::CreateUnsummonEffect(fx);
if (newfx) {
core->ApplyEffect(newfx, copy, copy);
delete newfx;
}
ieResRef script;
//intentionally 7, to leave room for the last letter
strnlwrcpy(script,target->GetScript(SCR_CLASS),7);
//no need of buffer defense as long as you don't mess with the 7 above
strcat(script,"m");
//if the caster is inparty, the script is turned off by the AI disable flag
copy->SetScript(script, SCR_CLASS, target->InParty!=0);
switch(fx->Parameter2)
{
case 1:
resref = "mislead";
//set the gender to illusionary, so ids matching will work
copy->SetBase(IE_SEX, SEX_ILLUSION);
copy->SetBase(IE_MAXHITPOINTS, copy->GetBase(IE_MAXHITPOINTS)/2);
break;
case 2:
resref = "projimg";
copy->SetBase(IE_SEX, SEX_ILLUSION);
break;
case 3:
resref = "simulacr";
// healable level drain
// FIXME: second generation simulacri are supposedly at a different level:
// level = original caster - caster / 2; eg. lvl 32 -> 16 -> 24 -> 20 -> 22 -> 21
newfx = EffectQueue::CreateEffect(fx_leveldrain_ref, copy->GetXPLevel(1)/2, 0, FX_DURATION_INSTANT_PERMANENT);
if (newfx) {
core->ApplyEffect(newfx, copy, copy);
delete newfx;
}
break;
default:
resref = fx->Resource;
break;
}
if (resref[0]) {
core->ApplySpell(resref,copy,copy,0);
}
//FIXME: parameter1 is unsure, but something similar to what the original engine has there
newfx = EffectQueue::CreateEffectCopy(fx, fx_puppetmarker_ref, target->InParty-1, fx->Parameter2);
if (newfx) {
core->ApplyEffect(newfx, copy, copy);
delete newfx;
}
return FX_NOT_APPLIED;
}
// 0xed PuppetMarker
int fx_puppet_marker (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_puppet_marker (%2d): Value: %d, Stat: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//actually the Type is in parameter2 and the ID is in parameter1
//but for some reason the defines are in the opposite order
STAT_SET (IE_PUPPETTYPE, fx->Parameter1); //cb4 - the ID of the controller
STAT_SET (IE_PUPPETID, fx->Parameter2); //cb8 - the control type
return FX_APPLIED;
}
// 0xee Disintegrate
int fx_disintegrate (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_disintegrate (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (EffectQueue::match_ids( target, fx->Parameter2, fx->Parameter1) ) {
//convert it to a death opcode or apply the new effect?
fx->Opcode = EffectQueue::ResolveEffect(fx_death_ref);
fx->TimingMode = FX_DURATION_INSTANT_PERMANENT;
fx->Parameter1 = 0;
fx->Parameter2 = 0x200;
return FX_APPLIED;
}
return FX_NOT_APPLIED;
}
// 0xef Farsee
// 1 view not explored sections too
// 2 param1=range (otherwise visualrange)
// 4 point already set (otherwise use gui)
// 8 use line of sight
#define FS_UNEXPLORED 1
#define FS_VISUALRANGE 2
#define FS_HASPOINT 4
#define FS_LOS 8
int fx_farsee (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_farsee (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
Map *map = target->GetCurrentArea();
if (!map) {
return FX_APPLIED;
}
if (!(fx->Parameter2&FS_VISUALRANGE)) {
fx->Parameter1=STAT_GET(IE_VISUALRANGE);
fx->Parameter2|=FS_VISUALRANGE;
}
if (target->InParty) {
//don't start graphical interface if actor isn't in party
if (!(fx->Parameter2&FS_HASPOINT)) {
//start graphical interface
//it will do all the rest of the opcode
//using RevealMap guiscript action
core->EventFlag|=EF_SHOWMAP;
return FX_NOT_APPLIED;
}
}
Point p(fx->PosX, fx->PosY);
//don't explore unexplored points
if (!(fx->Parameter2&FS_UNEXPLORED)) {
if (!map->IsVisible(p, 1)) {
return FX_NOT_APPLIED;
}
}
map->ExploreMapChunk(p, fx->Parameter1, fx->Parameter2&FS_LOS);
return FX_NOT_APPLIED;
}
// 0xf0 Icon:Remove
int fx_remove_portrait_icon (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_remove_portrait_icon (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
target->fxqueue.RemoveAllEffectsWithParam( fx_display_portrait_icon_ref, fx->Parameter2 );
return FX_NOT_APPLIED;
}
// 0xf1 control creature (same as charm)
// 0xF2 Cure:Confusion
static EffectRef fx_confused_state_ref={"State:Confused",NULL,-1};
int fx_cure_confused_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_cure_confused_state (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
BASE_STATE_CURE( STATE_CONFUSED );
target->fxqueue.RemoveAllEffects(fx_confused_state_ref);
return FX_NOT_APPLIED;
}
// 0xf3 DrainItems (this is disabled in ToB)
int fx_drain_items (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_drain_items (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
ieDword i=fx->Parameter1;
while (i--) {
//deplete magic item = 0
//deplete weapon = 1
target->inventory.DepleteItem(fx->Parameter2);
}
return FX_NOT_APPLIED;
}
// 0xf4 DrainSpells
int fx_drain_spells (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_drain_spells (%2d): Count: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
ieDword i=fx->Parameter1;
if (fx->Parameter2) {
while(i--) {
if (!target->spellbook.DepleteSpell(IE_SPELL_TYPE_PRIEST)) {
break;
}
}
return FX_NOT_APPLIED;
}
while(i--) {
if (!target->spellbook.DepleteSpell(IE_SPELL_TYPE_WIZARD)) {
break;
}
}
return FX_NOT_APPLIED;
}
// 0xf5 CheckForBerserk
int fx_checkforberserk_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_checkforberserk_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_SET( IE_CHECKFORBERSERK, fx->Parameter2 );
return FX_APPLIED;
}
// 0xf6 BerserkStage1Modifier
int fx_berserkstage1_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_berserkstage1_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_SET( IE_BERSERKSTAGE1, fx->Parameter2 );
return FX_APPLIED;
}
// 0xf7 BerserkStage2Modifier
int fx_berserkstage2_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_berserkstage2_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_SET( IE_BERSERKSTAGE2, fx->Parameter2 );
STATE_SET (STATE_BERSERK);
return FX_APPLIED;
}
// 0xf8 set melee effect
// adds effect to melee attacks (for monks, asssasins, fighter hlas, ...)
// it is cumulative
// 0xf9 set missile effect
// adds effect to ranged attacks (archers, ...)
// it is cumulative
// 0xfa DamageLuckModifier
int fx_damageluck_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_damageluck_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_DAMAGELUCK );
return FX_APPLIED;
}
// 0xfb BardSong
int fx_change_bardsong (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_change_bardsong (%2d): %s\n", fx->Opcode, fx->Resource);
memcpy(target->BardSong, fx->Resource, 8);
return FX_APPLIED;
}
// 0xfc SetTrap
int fx_set_area_effect (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_trap (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
ieDword skill, roll;
Map *map;
map = target->GetCurrentArea();
if (!map) return FX_NOT_APPLIED;
proIterator iter;
//check if trap count is over an amount (only saved traps count)
//actually, only projectiles in trigger phase should count here
if (map->GetTrapCount(iter)>6) {
displaymsg->DisplayConstantStringName(STR_NOMORETRAP, 0xf0f0f0, target);
return FX_NOT_APPLIED;
}
//check if we are under attack
if (GetNearestEnemyOf(map, target, ORIGIN_SEES_ENEMY|ENEMY_SEES_ORIGIN)) {
displaymsg->DisplayConstantStringName(STR_MAYNOTSETTRAP, 0xf0f0f0, target);
return FX_NOT_APPLIED;
}
if (Owner->Type==ST_ACTOR) {
skill = ((Actor *)Owner)->GetStat(IE_SETTRAPS);
roll = core->Roll(1,100,0);
} else {
roll=0;
skill=0;
}
if (roll>skill) {
//failure
displaymsg->DisplayConstantStringName(STR_SNAREFAILED, 0xf0f0f0, target);
//TODO check luck and do some damage effect on target
return FX_NOT_APPLIED;
}
//success
displaymsg->DisplayConstantStringName(STR_SNARESUCCEED, 0xf0f0f0, target);
Owner->CastSpellPoint(fx->Resource, target->Pos, false);
return FX_NOT_APPLIED;
}
// 0xfd SetMapNote
int fx_set_map_note (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_map_note (%2d): StrRef: %d Color: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
Scriptable *marker = target?target:Owner;
Map *map = marker->GetCurrentArea();
if (!map) return FX_APPLIED; //delay effect
Point p(fx->PosX, fx->PosY);
char *text = core->GetString(fx->Parameter1, 0);
map->AddMapNote(p, fx->Parameter2, text, fx->Parameter1);
return FX_NOT_APPLIED;
}
// 0xfe RemoveMapNote
int fx_remove_map_note (Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_remove_map_note (%2d)\n", fx->Opcode);
Scriptable *marker = target?target:Owner;
Map *map = marker->GetCurrentArea();
if (!map) return FX_APPLIED; //delay effect
Point p(fx->PosX, fx->PosY);
map->RemoveMapNote(p);
return FX_NOT_APPLIED;
}
// 0xff Item:CreateDays
int fx_create_item_days (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_create_item_days (%2d)\n", fx->Opcode );
target->inventory.AddSlotItemRes( fx->Resource, SLOT_ONLYINVENTORY, fx->Parameter1, fx->Parameter3, fx->Parameter4 );
if ((fx->TimingMode&0xff) == FX_DURATION_INSTANT_LIMITED) {
//if this effect has expiration, then it will remain as a remove_item
//on the effect queue, inheriting all the parameters
//duration needs a hack (recalculate it for days)
//no idea if this multiplier is ok
fx->Duration+=(fx->Duration-core->GetGame()->GameTime)*2400;
fx->Opcode=EffectQueue::ResolveEffect(fx_remove_inventory_item_ref);
fx->TimingMode=FX_DURATION_DELAY_PERMANENT;
return FX_APPLIED;
}
return FX_NOT_APPLIED;
}
// 0x100 Sequencer:Store
int fx_store_spell_sequencer(Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_store_spell_sequencer (%2d)\n", fx->Opcode );
//just display the spell sequencer portrait icon
target->AddPortraitIcon(PI_SEQUENCER);
if (fx->FirstApply && fx->Parameter3) {
target->spellbook.HaveSpell( fx->Resource, HS_DEPLETE );
target->spellbook.HaveSpell( fx->Resource2, HS_DEPLETE );
target->spellbook.HaveSpell( fx->Resource3, HS_DEPLETE );
target->spellbook.HaveSpell( fx->Resource4, HS_DEPLETE );
}
return FX_APPLIED;
}
// 0x101 Sequencer:Create
static EffectRef fx_spell_sequencer_active_ref={"Sequencer:Store",NULL,-1};
int fx_create_spell_sequencer(Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_create_spell_sequencer (%2d): Level: %d, Count: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (target->fxqueue.HasEffectWithSource(fx_spell_sequencer_active_ref, fx->Source)) {
displaymsg->DisplayConstantStringName(STR_SEQDUP, 0xf0f0f0, target);
return FX_NOT_APPLIED;
}
//just a call to activate the spell sequencer creation gui
if (target->InParty) {
Variables *dict = core->GetDictionary();
dict->SetAt( "P0", target->InParty );
dict->SetAt( "P1", fx->Parameter1 ); //maximum level
dict->SetAt( "P2", fx->Parameter2 | (2<<16) ); //count and target type
core->SetEventFlag(EF_SEQUENCER);
}
return FX_NOT_APPLIED;
}
// 0x102 Sequencer:Activate
int fx_activate_spell_sequencer(Scriptable* Owner, Actor* target, Effect* fx)
{
if (0) printf( "fx_activate_spell_sequencer (%2d): Resource: %s\n", fx->Opcode, fx->Resource );
if (Owner->Type!=ST_ACTOR) {
return FX_NOT_APPLIED;
}
Effect *sequencer = ((Actor *) Owner)->fxqueue.HasEffect(fx_spell_sequencer_active_ref);
if (sequencer) {
//cast 1-4 spells stored in the spell sequencer
core->ApplySpell(sequencer->Resource, target, Owner, fx->Power);
core->ApplySpell(sequencer->Resource2, target, Owner, fx->Power);
core->ApplySpell(sequencer->Resource3, target, Owner, fx->Power);
core->ApplySpell(sequencer->Resource4, target, Owner, fx->Power);
//remove the spell sequencer store effect
sequencer->TimingMode=FX_DURATION_JUST_EXPIRED;
}
return FX_NOT_APPLIED;
}
// 0x103 SpellTrap (Protection:SpellLevelDec + recall spells)
int fx_spelltrap(Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_spelltrap (%2d): Count: %d, Level: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (fx->Parameter3) {
target->RestoreSpellLevel(fx->Parameter3, 0);
fx->Parameter3=0;
}
if (fx->Parameter1<=0) {
//gone down to zero
return FX_NOT_APPLIED;
}
target->SetOverlay(OV_SPELLTRAP);
target->AddPortraitIcon(PI_SPELLTRAP);
return FX_APPLIED;
}
//0x104 Crash104
//0x138 Crash138
int fx_crash (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
{
if (0) printf( "fx_crash (%2d): Param1: %d, Param2: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
return FX_NOT_APPLIED;
}
// 0x105 RestoreSpells
int fx_restore_spell_level(Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_restore_spell_level (%2d): Level: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
target->RestoreSpellLevel(fx->Parameter1, fx->Parameter2);
return FX_NOT_APPLIED;
}
// 0x106 VisualRangeModifier
int fx_visual_range_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_visual_range_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_VISUALRANGE );
return FX_APPLIED;
}
// 0x107 BackstabModifier
int fx_backstab_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_visual_range_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//this is how it is done in the original engine, i don't know why they would do this
//ctrl-r would probably remove it otherwise
//Why they didn't fix it in the spell/item is beyond me
if (fx->TimingMode==FX_DURATION_INSTANT_PERMANENT)
fx->TimingMode=FX_DURATION_INSTANT_PERMANENT_AFTER_BONUSES;
STAT_MOD( IE_BACKSTABDAMAGEMULTIPLIER );
return FX_APPLIED;
}
// 0x108 DropWeapon
int fx_drop_weapon (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (fx->Resource[0]) {
target->DropItem(fx->Resource, 0);
return FX_NOT_APPLIED;
}
switch (fx->Parameter2) {
case 0:
target->DropItem(-1, 0);
break;
case 1:
target->DropItem(target->inventory.GetEquippedSlot(), 0);
break;
default:
target->DropItem(fx->Parameter1, 0);
break;
}
return FX_NOT_APPLIED;
}
// 0x109 ModifyGlobalVariable
int fx_modify_global_variable (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
{
Game *game = core->GetGame();
//convert it to internal variable format
if (!fx->IsVariable) {
char *poi=fx->Resource+8;
memmove(poi, fx->Resource2,8);
poi+=8;
memmove(poi, fx->Resource3,8);
poi+=8;
memmove(poi, fx->Resource4,8);
fx->IsVariable=1;
}
//hack for IWD
if (!fx->Resource[0]) {
strnuprcpy(fx->Resource,"RETURN_TO_LONELYWOOD",32);
}
if (0) printf( "fx_modify_global_variable (%2d): Variable: %s Value: %d Type: %d\n", fx->Opcode, fx->Resource, fx->Parameter1, fx->Parameter2 );
if (fx->Parameter2) {
ieDword var = 0;
//use resource memory area as variable name
game->locals->Lookup(fx->Resource, var);
game->locals->SetAt(fx->Resource, var+fx->Parameter1);
} else {
game->locals->SetAt(fx->Resource, fx->Parameter1);
}
return FX_NOT_APPLIED;
}
// 0x10a RemoveImmunity
EffectRef immunity_effect_ref={"Protection:Spell",NULL,-1};
int fx_remove_immunity(Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_remove_immunity (%2d): %s\n", fx->Opcode, fx->Resource );
target->fxqueue.RemoveAllEffectsWithResource(immunity_effect_ref, fx->Resource);
return FX_NOT_APPLIED;
}
// 0x10b protection from display string is a generic effect
// 0x10c ExploreModifier
int fx_explore_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_explore_modifier (%2d)\n", fx->Opcode );
if (fx->Parameter2) {
//gemrb modifier
STAT_SET (IE_EXPLORE, fx->Parameter1);
} else {
STAT_SET (IE_EXPLORE, 1);
}
return FX_APPLIED;
}
// 0x10d ScreenShake
int fx_screenshake (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
{
if (0) printf( "fx_screenshake (%2d): Strength: %d\n", fx->Opcode, fx->Parameter1 );
core->timer->SetScreenShake( fx->Parameter1, fx->Parameter1, 1);
return FX_APPLIED;
}
// 0x10e Cure:CasterHold
static EffectRef fx_pause_caster_modifier_ref={"PauseTarget",NULL,-1};
int fx_unpause_caster (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_unpause_caster (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
target->fxqueue.RemoveAllEffects(fx_pause_caster_modifier_ref);
return FX_NOT_APPLIED;
}
// 0x10f AvatarRemoval
// 0x104 AvatarRemoval (iwd)
int fx_avatar_removal (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_avatar_removal (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//FIXME: this is a permanent irreversible effect in IWD
//if it is different in bg2, then create another effect
//bg2 calls this SummonDisable
BASE_SET(IE_AVATARREMOVAL, 1);
return FX_NOT_APPLIED;
}
/* note/TODO from Taimon:
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.
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.
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.
*/
static EffectRef fx_apply_effect_repeat_ref = {"ApplyEffectRepeat", NULL, -1};
// 0x110 ApplyEffectRepeat
int fx_apply_effect_repeat (Scriptable* Owner, Actor* target, Effect* fx)
{
ieDword i; //moved here because msvc6 cannot handle it otherwise
if (0) printf( "fx_apply_effect_repeat (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
Point p(fx->PosX, fx->PosY);
Effect *newfx = core->GetEffect(fx->Resource, fx->Power, p);
//core->GetEffect is a borrowed reference, don't delete it
if (!newfx) {
return FX_NOT_APPLIED;
}
// don't apply the effect if a similar one is already applied with a shorter duration
Effect *oldfx = target->fxqueue.HasEffect(fx_apply_effect_repeat_ref);
if (oldfx && oldfx->Duration < fx->Duration) {
return FX_NOT_APPLIED;
}
switch (fx->Parameter2) {
case 0: //once per second
case 1: //crash???
if (!(core->GetGame()->GameTime%AI_UPDATE_TIME)) {
core->ApplyEffect(newfx, target, Owner);
}
break;
case 2://param1 times every second
if (!(core->GetGame()->GameTime%AI_UPDATE_TIME)) {
for (i=0;i<fx->Parameter1;i++) {
core->ApplyEffect(newfx, target, Owner);
}
}
break;
case 3: //once every Param1 second
if (fx->Parameter1 && (core->GetGame()->GameTime%fx->Parameter1)) {
core->ApplyEffect(newfx, target, Owner);
}
break;
case 4: //param3 times every Param1 second
if (fx->Parameter1 && (core->GetGame()->GameTime%fx->Parameter1)) {
for (i=0;i<fx->Parameter3;i++) {
core->ApplyEffect(newfx, target, Owner);
}
}
break;
}
return FX_APPLIED;
}
// 0x111 RemoveProjectile
int fx_remove_projectile (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
//the list is now cached by Interface, no need of freeing it
ieDword *projectilelist;
//instant effect
if (0) printf( "fx_remove_projectile (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (!target) return FX_NOT_APPLIED;
Map *area = target->GetCurrentArea();
if (!area) return FX_NOT_APPLIED;
switch (fx->Parameter2) {
case 0: //standard bg2
projectilelist = core->GetListFrom2DA("clearair");
break;
case 1: //you can give a 2da for projectile list (gemrb)
projectilelist = core->GetListFrom2DA(fx->Resource);
break;
case 2: //or you can give one single projectile in param1 (gemrb)
projectilelist = (ieDword *) malloc(2*sizeof(ieDword));
projectilelist[0]=1;
projectilelist[1]=fx->Parameter1;
break;
default:
return FX_NOT_APPLIED;
}
//The first element is the counter, so don't decrease the counter here
Point p(fx->PosX, fx->PosY);
int i = projectilelist[0];
while(i) {
ieDword projectile = projectilelist[i];
proIterator piter;
size_t cnt = area->GetProjectileCount(piter);
while( cnt--) {
Projectile *pro = *piter;
if ((pro->GetType()==projectile) && pro->PointInRadius(p) ) {
pro->Cleanup();
}
}
if (target) {
target->fxqueue.RemoveAllEffectsWithProjectile(projectile);
}
i--;
}
//this one was constructed by us
if (fx->Parameter2==2) free(projectilelist);
return FX_NOT_APPLIED;
}
// 0x112 TeleportToTarget
int fx_teleport_to_target (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_teleport_to_target (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (STATE_GET(STATE_DEAD)) {
return FX_NOT_APPLIED;
}
Map *map = target->GetCurrentArea();
if (map) {
Actor *victim = map->GetActorByGlobalID(target->LastAttacker);
if (victim) {
target->SetPosition( victim->Pos, true, 0 );
}
}
return FX_NOT_APPLIED;
}
// 0x113 HideInShadowsModifier
int fx_hide_in_shadows_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_hide_in_shadows_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_HIDEINSHADOWS );
return FX_APPLIED;
}
// 0x114 DetectIllusionsModifier
int fx_detect_illusion_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_detect_illusion_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_DETECTILLUSIONS );
return FX_APPLIED;
}
// 0x115 SetTrapsModifier
int fx_set_traps_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_set_traps_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_SETTRAPS );
return FX_APPLIED;
}
// 0x116 ToHitBonusModifier
int fx_to_hit_bonus_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_to_hit_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
HandleBonus( target, IE_HITBONUS, fx->Parameter1, fx->TimingMode );
return FX_APPLIED;
}
// 0x117 RenableButton
static EffectRef fx_disable_button_ref={"DisableButton",NULL,-1};
int fx_renable_button (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
//removes the disable button effect
if (0) printf( "fx_renable_button (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
target->fxqueue.RemoveAllEffectsWithParam( fx_disable_button_ref, fx->Parameter2 );
return FX_NOT_APPLIED;
}
// 0x118 ForceSurgeModifier
int fx_force_surge_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_force_surge_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_FORCESURGE );
return FX_APPLIED;
}
// 0x119 WildSurgeModifier
int fx_wild_surge_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_wild_surge_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_SURGEMOD );
return FX_APPLIED;
}
// 0x11a ScriptingState
int fx_scripting_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_scripting_state (%2d): Value: %d, Stat: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//original engine didn't check boundaries, causing crashes
//we allow only positive indices (some extra stats are still addressable)
if (fx->Parameter2>100) {
return FX_NOT_APPLIED;
}
//original engine used only single byte value, we allow full dword
STAT_SET( IE_SCRIPTINGSTATE1+fx->Parameter2, fx->Parameter1 );
return FX_APPLIED;
}
// 0x11b ApplyEffectCurse
int fx_apply_effect_curse (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_apply_effect_curse (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//this effect executes a file effect in place of this effect
//the file effect inherits the target and the timingmode, but gets
//a new chance to roll percents
int ret = FX_NOT_APPLIED;
if (!target) {
return ret;
}
if (EffectQueue::match_ids( target, fx->Parameter2, fx->Parameter1) ) {
Point p(fx->PosX, fx->PosY);
//apply effect, if the effect is a goner, then kill
//this effect too
Effect *newfx = core->GetEffect(fx->Resource, fx->Power, p);
if (newfx) {
Effect *myfx = new Effect;
memcpy(myfx, newfx, sizeof(Effect));
myfx->random_value = fx->random_value;
myfx->TimingMode=fx->TimingMode;
myfx->Duration=fx->Duration;
myfx->Target = FX_TARGET_PRESET;
myfx->CasterID = fx->CasterID;
ret = target->fxqueue.ApplyEffect(target, myfx, fx->FirstApply, 0);
delete myfx;
}
//newfx is a borrowed reference don't delete it
}
return ret;
}
// 0x11c MeleeHitModifier
int fx_melee_to_hit_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_melee_to_hit_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_MELEETOHIT );
return FX_APPLIED;
}
// 0x11d MeleeDamageModifier
int fx_melee_damage_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_melee_damage_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_MELEEDAMAGE );
return FX_APPLIED;
}
// 0x11e MissileDamageModifier
int fx_missile_damage_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_missile_damage_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_MISSILEDAMAGE );
return FX_APPLIED;
}
// 0x11f NoCircleState
int fx_no_circle_state (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_missile_damage_modifier (%2d)\n", fx->Opcode);
STAT_SET( IE_NOCIRCLE, 1 );
return FX_APPLIED;
}
// 0x120 FistHitModifier
int fx_fist_to_hit_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_fist_to_hit_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_FISTHIT );
return FX_APPLIED;
}
// 0x121 FistDamageModifier
int fx_fist_damage_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_fist_damage_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_FISTDAMAGE );
return FX_APPLIED;
}
//0x122 TitleModifier
int fx_title_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_fist_damage_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
if (fx->Parameter2) {
STAT_SET( IE_TITLE2, fx->Parameter1 );
} else {
STAT_SET( IE_TITLE1, fx->Parameter1 );
}
return FX_APPLIED;
}
//0x123 DisableOverlay
//FIXME: which overlay is disabled?
//if one of the overlays marked by sanctuary, then
//make the bit correspond to it
int fx_disable_overlay_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_disable_overlay_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_SET( IE_DISABLEOVERLAY, fx->Parameter1 );
return FX_APPLIED;
}
//0x124 Protection:Backstab (bg2)
//0x11f Protection:Backstab (how, iwd2)
//3 different games, 3 different methods of flagging this
int fx_no_backstab_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_no_backstab_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//bg2
STAT_SET( IE_DISABLEBACKSTAB, fx->Parameter1 );
//how
EXTSTATE_SET(EXTSTATE_NO_BACKSTAB);
//iwd2
target->SetSpellState(SS_NOBACKSTAB);
return FX_APPLIED;
}
//0x125 OffscreenAIModifier
int fx_offscreenai_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_offscreenai_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_SET( IE_ENABLEOFFSCREENAI, fx->Parameter1 );
target->Activate();
return FX_APPLIED;
}
//0x126 ExistanceDelayModifier
int fx_existance_delay_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_existance_delay_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_SET( IE_EXISTANCEDELAY, fx->Parameter1 );
return FX_APPLIED;
}
//0x127 DisableChunk
int fx_disable_chunk_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_disable_chunk_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_SET( IE_DISABLECHUNKING, fx->Parameter1 );
return FX_APPLIED;
}
#if 0
//This is done differently in the original engine, and THIS may not even work
//0x128 Protection:Animation
int fx_protection_from_animation (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_protection_from_animation (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//remove vvc from actor if active
target->RemoveVVCell(fx->Resource, false);
return FX_APPLIED;
}
#endif
//0x129 Protection:Turn
int fx_protection_from_turn (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_non_interruptible_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_SET( IE_NOTURNABLE, fx->Parameter1 );
return FX_APPLIED;
}
//0x12a CutScene2
//runs a predetermined script in cutscene mode
int fx_cutscene2 (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
{
Game *game;
ieResRef resref;
if (0) printf( "fx_cutscene2 (%2d): Type: %d\n", fx->Opcode, fx->Parameter2 );
if (core->InCutSceneMode()) return FX_NOT_APPLIED;
game = core->GetGame();
if (!game) return FX_NOT_APPLIED;
game->ClearPlaneLocations();
for (int i = 0; i < game->GetPartySize(false); i++) {
Actor* act = game->GetPC( i, false );
GAMLocationEntry *gle = game->GetPlaneLocationEntry(i);
if (act && gle) {
gle->Pos = act->Pos;
memcpy(gle->AreaResRef, act->Area, 9);
}
}
core->SetCutSceneMode(true);
//GemRB enhancement: allow a custom resource
if (fx->Parameter2) {
strnlwrcpy(resref,fx->Resource, 8);
} else {
strnlwrcpy(resref,"cut250a",8);
}
GameScript* gs = new GameScript( resref, game );
gs->EvaluateAllBlocks();
delete( gs );
return FX_NOT_APPLIED;
}
//0x12b ChaosShieldModifier
int fx_chaos_shield_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_chaos_shield_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_ADD( IE_CHAOSSHIELD, fx->Parameter1 );
if (fx->Parameter2) {
target->AddPortraitIcon(PI_CSHIELD); //162
} else {
target->AddPortraitIcon(PI_CSHIELD2); //163
}
return FX_APPLIED;
}
//0x12c NPCBump
int fx_npc_bump (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_npc_bump (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
//unknown effect, but known stat position
STAT_MOD( IE_NPCBUMP );
return FX_APPLIED;
}
//0x12d CriticalHitModifier
int fx_critical_hit_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_critical_hit_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_CRITICALHITBONUS );
return FX_APPLIED;
}
// 0x12e CanUseAnyItem
int fx_can_use_any_item_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_can_use_any_item_modifier (%2d): Value: %d\n", fx->Opcode, fx->Parameter2 );
STAT_SET( IE_CANUSEANYITEM, fx->Parameter2 );
return FX_APPLIED;
}
// 0x12f AlwaysBackstab
int fx_always_backstab_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_always_backstab_modifier (%2d): Value: %d\n", fx->Opcode, fx->Parameter2 );
STAT_SET( IE_ALWAYSBACKSTAB, fx->Parameter2 );
return FX_APPLIED;
}
// 0x130 MassRaiseDead
int fx_mass_raise_dead (Scriptable* Owner, Actor* /*target*/, Effect* fx)
{
if (0) printf( "fx_mass_raise_dead (%2d)\n", fx->Opcode );
Game *game=core->GetGame();
int i=game->GetPartySize(false);
Point p(fx->PosX,fx->PosY);
while (i--) {
Actor *actor=game->GetPC(i,false);
Resurrect(Owner, actor, fx, p);
}
return FX_NOT_APPLIED;
}
// 0x131 OffhandHitModifier
int fx_left_to_hit_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_left_to_hit_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_HITBONUSLEFT );
return FX_APPLIED;
}
// 0x132 RightHitModifier
int fx_right_to_hit_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_right_to_hit_modifier (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_HITBONUSRIGHT );
return FX_APPLIED;
}
// 0x133 Reveal:Tracks
int fx_reveal_tracks (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_reveal_tracks (%2d): Distance: %d\n", fx->Opcode, fx->Parameter1 );
Map *map = target->GetCurrentArea();
if (!map) return FX_APPLIED;
if (!fx->Parameter2) {
fx->Parameter2=1;
//write tracks.2da entry
if (map->DisplayTrackString(target)) {
return FX_NOT_APPLIED;
}
}
GameControl *gc = core->GetGameControl();
if (gc) {
//highlight all living creatures (not in party, but within range)
gc->SetTracker(target, fx->Parameter1);
}
return FX_APPLIED;
}
// 0x134 Protection:Tracking
int fx_protection_from_tracking (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_protection_from_tracking (%2d): Mod: %d, Type: %d\n", fx->Opcode, fx->Parameter1, fx->Parameter2 );
STAT_MOD( IE_NOTRACKING ); //highlight creature???
return FX_APPLIED;
}
// 0x135 ModifyLocalVariable
int fx_modify_local_variable (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
//convert it to internal variable format
if (!fx->IsVariable) {
char *poi = fx->Resource+8;
memmove(poi, fx->Resource2, 8);
poi+=8;
memmove(poi, fx->Resource3, 8);
poi+=8;
memmove(poi, fx->Resource4, 8);
fx->IsVariable=1;
}
if (0) printf( "fx_modify_local_variable (%2d): %s, Mod: %d\n", fx->Opcode, fx->Resource, fx->Parameter2 );
if (fx->Parameter2) {
ieDword var = 0;
//use resource memory area as variable name
target->locals->Lookup(fx->Resource, var);
target->locals->SetAt(fx->Resource, var+fx->Parameter1);
} else {
target->locals->SetAt(fx->Resource, fx->Parameter1);
}
return FX_NOT_APPLIED;
}
// 0x136 TimelessState
int fx_timeless_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_timeless_modifier (%2d): Mod: %d\n", fx->Opcode, fx->Parameter2 );
STAT_SET(IE_DISABLETIMESTOP, fx->Parameter2);
return FX_APPLIED;
}
//0x137 GenerateWish
#define WISHCOUNT 25
static int wishlevels[WISHCOUNT]={10,10,10,10,0,10,0,15,0,0,0,0,0,0,15,0,0,
17,9,17,17,9,9,9,0};
int fx_generate_wish (Scriptable* Owner, Actor* target, Effect* fx)
{
ieResRef spl;
if (0) printf( "fx_generate_wish (%2d): Mod: %d\n", fx->Opcode, fx->Parameter2 );
int tmp = core->Roll(1,WISHCOUNT,0);
sprintf(spl,"SPWISH%02d",tmp);
core->ApplySpell(spl, target, Owner, wishlevels[tmp-1]);
return FX_NOT_APPLIED;
}
//0x138 //see fx_crash, this effect is not fully enabled in original bg2/tob
int fx_immunity_sequester (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_immunity_sequester (%2d): Mod: %d\n", fx->Opcode, fx->Parameter2 );
//this effect is supposed to provide immunity against sequester (maze/etc?)
STAT_SET(IE_NOSEQUESTER, fx->Parameter2);
return FX_APPLIED;
}
//0x139 //HLA generic effect
//0x13a StoneSkin2Modifier
int fx_golem_stoneskin_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_golem_stoneskin_modifier (%2d): Mod: %d\n", fx->Opcode, fx->Parameter1 );
if (!fx->Parameter1) {
return FX_NOT_APPLIED;
}
//dead actors lose this effect
if (STATE_GET( STATE_DEAD) ) {
return FX_NOT_APPLIED;
}
STAT_SET(IE_STONESKINSGOLEM, fx->Parameter1);
SetGradient(target, 14);
return FX_APPLIED;
}
// 0x13b AvatarRemovalModifier (also 0x104 iwd)
int fx_avatar_removal_modifier (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_avatar_removal_modifier (%2d): Mod: %d\n", fx->Opcode, fx->Parameter2 );
STAT_SET(IE_AVATARREMOVAL, fx->Parameter2);
return FX_APPLIED;
}
// 0x13c MagicalRest (also 0x124 iwd)
int fx_magical_rest (Scriptable* /*Owner*/, Actor* target, Effect* fx)
{
if (0) printf( "fx_magical_rest (%2d)\n", fx->Opcode );
//instant, full rest
target->Rest(0);
target->fxqueue.RemoveAllEffectsWithParam(fx_display_portrait_icon_ref, PI_FATIGUE);
return FX_NOT_APPLIED;
}
// 0x13d ImprovedHaste (See 0x10 Haste)
// unknown
int fx_unknown (Scriptable* /*Owner*/, Actor* /*target*/, Effect* fx)
{
printf( "fx_unknown (%2d): P1: %d P2: %d ResRef: %s\n", fx->Opcode, fx->Parameter1, fx->Parameter2, fx->Resource );
return FX_NOT_APPLIED;
}
#include "plugindef.h"
GEMRB_PLUGIN(0x1AAA040A, "Effect opcodes for core games")
PLUGIN_INITIALIZER(RegisterCoreOpcodes)
PLUGIN_CLEANUP(Cleanup)
END_PLUGIN()