diff --git a/config/fxdata/creature.cfg b/config/fxdata/creature.cfg index 8481b40a6e..1863a93740 100644 --- a/config/fxdata/creature.cfg +++ b/config/fxdata/creature.cfg @@ -50,6 +50,10 @@ FPActionTime = 0 FPResetTime = 0 ; Instance is activated as soon as it's selected. FPInstantCast = 0 +; Instance can be used when frozen in possession. Only works when targetting self. +FPAllowSelfCastWhileFrozen = 0 +; Instance can be used when under the Chicken spell in possession. Only works when targetting self. +FPAllowSelfCastWhenChicken = 0 ; How many game turns after using the instance creature can be spotted even if invisible. ForceVisibility = 0 ; Tooltip string ID, explaining what the instance does. @@ -256,6 +260,7 @@ FPTime = 5 FPActionTime = 3 FPResetTime = 250 FPInstantCast = 1 +FPAllowSelfCastWhileFrozen = 1 ForceVisibility = 10 TooltipTextID = 228 SymbolSprites = 408 @@ -295,6 +300,7 @@ FPTime = 5 FPActionTime = 3 FPResetTime = 250 FPInstantCast = 1 +FPAllowSelfCastWhileFrozen = 1 ForceVisibility = 10 TooltipTextID = 230 SymbolSprites = 412 @@ -314,6 +320,7 @@ FPTime = 5 FPActionTime = 3 FPResetTime = 250 FPInstantCast = 1 +FPAllowSelfCastWhileFrozen = 1 ForceVisibility = 1 TooltipTextID = 248 SymbolSprites = 414 @@ -353,6 +360,7 @@ FPTime = 5 FPActionTime = 3 FPResetTime = 200 FPInstantCast = 1 +FPAllowSelfCastWhileFrozen = 1 ForceVisibility = 1 TooltipTextID = 239 SymbolSprites = 418 @@ -372,6 +380,7 @@ FPTime = 5 FPActionTime = 3 FPResetTime = 3 FPInstantCast = 1 +FPAllowSelfCastWhileFrozen = 1 ForceVisibility = 10 TooltipTextID = 240 SymbolSprites = 420 @@ -389,6 +398,7 @@ FPTime = 5 FPActionTime = 3 FPResetTime = 500 FPInstantCast = 1 +FPAllowSelfCastWhileFrozen = 1 ForceVisibility = 3 TooltipTextID = 236 SymbolSprites = 422 @@ -544,6 +554,7 @@ FPTime = 5 FPActionTime = 3 FPResetTime = 300 FPInstantCast = 1 +FPAllowSelfCastWhileFrozen = 1 ForceVisibility = 100 TooltipTextID = 242 SymbolSprites = 434 @@ -561,6 +572,7 @@ FPTime = 5 FPActionTime = 3 FPResetTime = 250 FPInstantCast = 1 +FPAllowSelfCastWhileFrozen = 1 ForceVisibility = 1 TooltipTextID = 243 SymbolSprites = 436 @@ -580,6 +592,7 @@ FPTime = 5 FPActionTime = 3 FPResetTime = 150 FPInstantCast = 1 +FPAllowSelfCastWhileFrozen = 1 ForceVisibility = 0 TooltipTextID = 232 SymbolSprites = 438 @@ -978,6 +991,7 @@ FPTime = 6 FPActionTime = 5 FPResetTime = 600 FPInstantCast = 1 +FPAllowSelfCastWhileFrozen = 1 ForceVisibility = 30 TooltipTextID = 1080 SymbolSprites = BIRD_SPELL @@ -997,6 +1011,7 @@ FPTime = 6 FPActionTime = 5 FPResetTime = 190 FPInstantCast = 1 +FPAllowSelfCastWhileFrozen = 1 ForceVisibility = 30 TooltipTextID = 1081 SymbolSprites = SPIDERLING_SPELL @@ -1114,6 +1129,53 @@ PrimaryTarget = 3 Properties = DESTRUCTIVE MELEE_ATTACK DISPLAY_SWIPE Function = creature_fire_shot SHOT_CRIPPLE 0 +[instance55] +Name = CLEANSE +Time = 10 +ActionTime = 6 +ResetTime = 375 +FPTime = 5 +FPActionTime = 3 +FPResetTime = 300 +FPInstantCast = 1 +FPAllowSelfCastWhileFrozen = 1 +FPAllowSelfCastWhenChicken = 1 +ForceVisibility = 10 +TooltipTextID = 1067 +SymbolSprites = 798 +Graphics = CASTSPELL +Properties = SELF_BUFF +PrimaryTarget = 6 +Function = creature_cast_spell SPELL_CLEANSE 0 +;param 1 - spell flags under which the instance is allowed +ValidateSourceFunc = validate_source_even_in_prison 2560 0 +;param 1 - spell kind from which to take CleanseFlags +ValidateTargetFunc = validate_target_requires_cleansing 32 0 + +[instance56] +Name = RANGED_CLEANSE +Time = 10 +ActionTime = 6 +ResetTime = 375 +FPTime = 5 +FPActionTime = 3 +FPResetTime = 300 +FPInstantCast = 0 +FPAllowSelfCastWhileFrozen = 1 +FPAllowSelfCastWhenChicken = 1 +ForceVisibility = 30 +TooltipTextID = 1068 +SymbolSprites = 794 +Graphics = CASTSPELL +RangeMin = MIN +RangeMax = 3072 +Properties = RANGED_BUFF SELF_BUFF NEEDS_TARGET +PrimaryTarget = 6 +Function = creature_cast_spell SPELL_CLEANSE 0 +ValidateSourceFunc = validate_source_generic 2560 0 +ValidateTargetFunc = validate_target_requires_cleansing 32 0 +SearchTargetsFunc = search_target_generic 0 0 + [job0] ; Empty job, indicates no job assigned. Name = NULL diff --git a/config/fxdata/effects.toml b/config/fxdata/effects.toml index 19ab542694..5b7c0b4f4b 100644 --- a/config/fxdata/effects.toml +++ b/config/fxdata/effects.toml @@ -1514,6 +1514,24 @@ LightFlags = 1 ElementsCount = 3 AlwaysGenerate = 0 +[effect83] +Name = "EFFECT_CLEANSE" +Health = 8 +GenerationType = 1 +GenerationAccelXYRange = [16,16] +GenerationAccelZRange = [64,256] +GenerationKindRange = [124,124] +AreaAffectType = 0 +HitType = 0 +SpellEffect = 0 +Sound = 0 +AffectedByWind = 0 +LightRadius = 0 +LightIntensity = 0 +LightFlags = 0 +ElementsCount = 1 +AlwaysGenerate = 0 + # EffectGenerators. [effectGenerator0] @@ -5301,4 +5319,60 @@ TransformModel = 0 LightRadius = 1 LightIntensity = 0 LightFlags = 0 -AffectedByWind = 1 \ No newline at end of file +AffectedByWind = 1 + +[effectElement124] +Name = "EFFECTELEMENT_CLEANSE" +DrawClass = 2 +MoveType = 2 +Unanimated = 0 +Lifespan = [-1,-1] +AnimationId = 119 +SpriteSize = [96,150] +AnimateOnce = 0 +SpriteSpeed = [384,512] +AnimateOnFloor = true +Unshaded = true +Transparent = 3 +ThroughWalls = 0 +SizeChange = 0 +FallAcceleration = 0 +InertiaFloor = 0 +InertiaAir = 0 +SubeffectModel = 0 +SubeffectDelay = 0 +Movable = false +Impacts = false +TransformModel = 125 +LightRadius = 0 +LightIntensity = 0 +LightFlags = 0 +AffectedByWind = 0 + +[effectElement125] +Name = "EFFECTELEMENT_CLEANSE_DURATION" +DrawClass = 2 +MoveType = 2 +Unanimated = 0 +Lifespan = [10,15] +AnimationId = 850 +SpriteSize = [12,24] +AnimateOnce = 0 +SpriteSpeed = [384,512] +AnimateOnFloor = true +Unshaded = true +Transparent = 3 +ThroughWalls = 0 +SizeChange = 0 +FallAcceleration = 0 +InertiaFloor = 0 +InertiaAir = 0 +SubeffectModel = 0 +SubeffectDelay = 0 +Movable = false +Impacts = false +TransformModel = 0 +LightRadius = 0 +LightIntensity = 0 +LightFlags = 0 +AffectedByWind = 0 \ No newline at end of file diff --git a/config/fxdata/magic.cfg b/config/fxdata/magic.cfg index 6b571fe20b..500d6188cc 100644 --- a/config/fxdata/magic.cfg +++ b/config/fxdata/magic.cfg @@ -46,6 +46,8 @@ SpellPower = NOPOWER ; 32768: TELEPORT - If self-cast, jumps to its next objective or place to fulfill its needs. If cast on a target, jumps it to its lair or flee point. ; 65536: TIMEBOMB - Sets a countdown on the target, making it move toward enemies to explode on impact, dealing damage from the linked shot. ; 131072: WIND - Not functional on spells, exists only for immunity. +; 262144: CLEANSE - Cures effects specified in 'CleanseFlags'. +; 524288: SPELL_BLOCKS - Prevents effects from affecting the creature. Must be combined with 'CleanseFlags' to function, has no effect on its own. SpellFlags = 0 ; Spell effects to remove from the target. Use the same list as 'SpellFlags'. Accepts both names and numbers. CleanseFlags = 0 @@ -357,6 +359,21 @@ Duration = 160 SelfCasted = 1 978 1 SymbolSprites = 768 770 +[spell32] +; Cures all negative effect and blocks them for a short duration. +Name = SPELL_CLEANSE +CastAtThing = 1 +ShotModel = SHOT_RANGED_CLEANSE +SpellPower = NOPOWER +SpellFlags = SPELL_BLOCKS +AuraEffect = EFFECT_CLEANSE +AuraFrequency = 0 +AuraDuration = 10 +CleanseFlags = SLOW DISEASE CHICKEN FREEZE FEAR +Duration = 30 +SelfCasted = 1 162 1 +SymbolSprites = 796 798 + ; Shots types. [shot0] @@ -1586,6 +1603,32 @@ FrozenEffect = EFFECT_HIT_FROZEN_UNIT Properties = CAN_COLLIDE NEVER_BLOCK WIND_IMMUNE UpdateLogic = SmokeWhenFired +[shot41] +Name = SHOT_RANGED_CLEANSE +Animation = SPARKLE_CLEANSE +AnimationSize = 128 +AnimationTransparency = 3 +Size_XY = 64 +Size_Z = 64 +Health = 30 +Damage = 0 +HitType = 11 +SpellEffect = SPELL_CLEANSE +Speed = 128 +BaseExperienceGain = 256 +DestroyOnHit = 1 +TargetHitstopTurns = 6 +FiringSound = 161 +ShotSound = 0 +ShotSoundPriority = 1 +HitWaterEffect = EFFECT_DRIP_1 +HitWaterSound = 21 1 +Properties = NAVIGABLE REBOUND_IMMUNE +FireLogic = 3 +EffectAmount = 3 +Spread_XY = 50 +Spread_Z = 50 + ; Powers types. [power0] diff --git a/lang/gtext_fre.po b/lang/gtext_fre.po index 161ce84f93..d5eb043d06 100644 --- a/lang/gtext_fre.po +++ b/lang/gtext_fre.po @@ -2766,10 +2766,10 @@ msgid "" "can be rotated. Disable the warp effect for clean lines. Forced perspective " "can only be rotated 90 degrees and changes the viewing angle. LMB toggle." msgstr "" -"Type d'affichage: Alterne entre deux types de vue de la perspective. La vue " -"par défaut a des murs tordus et permet la rotation libre. Désactivez l'effet " +"Type d'affichage: Alterne entre les vues en perspective. La vue " +"par défaut a des murs tordus et permet une rotation libre. Désactivez l'effet " "de torsion pour des lignes droites. La vue forcée change l'angle de vision " -"et ne peut faire que des rotations à 90 degrés. Alterner avec le bouton " +"et ne peut pivoter que par rotations de 90 degrés. Alterner avec le bouton " "gauche de la souris." #: guitext:315 diff --git a/src/config_creature.c b/src/config_creature.c index 57b4376d5c..156283191c 100644 --- a/src/config_creature.c +++ b/src/config_creature.c @@ -106,6 +106,8 @@ const struct NamedCommand creaturetype_instance_commands[] = { {"SearchTargetsFunc", 20}, {"PostalPriority", 21}, {"NoAnimationLoop", 22}, + {"FPAllowSelfCastWhileFrozen", 23}, + {"FPAllowSelfCastWhenChicken", 24}, {NULL, 0}, }; @@ -1014,6 +1016,8 @@ TbBool parse_creaturetype_instance_blocks(char *buf, long len, const char *confi inst_inf->validate_target_func_params[0] = 0; inst_inf->validate_target_func_params[1] = 0; inst_inf->postal_priority = 0; + inst_inf->fp_allow_self_cast_while_frozen = 0; + inst_inf->fp_allow_self_cast_when_chicken = 0; } } instance_desc[INSTANCE_TYPES_MAX - 1].name = NULL; // must be null for get_id @@ -1411,6 +1415,32 @@ TbBool parse_creaturetype_instance_blocks(char *buf, long len, const char *confi COMMAND_TEXT(cmd_num), blocknamelen, blockname, config_textname); } break; + case 23: // FPALLOWSELFCASTWHILEFROZEN + if (get_conf_parameter_single(buf,&pos,len,word_buf,sizeof(word_buf)) > 0) + { + k = atoi(word_buf); + inst_inf->fp_allow_self_cast_while_frozen = (TbBool)k; + n++; + } + if (n < 1) + { + CONFWRNLOG("Couldn't read \"%s\" parameter in [%.*s] block of %s file.", + COMMAND_TEXT(cmd_num), blocknamelen, blockname, config_textname); + } + break; + case 24: // FPALLOWSELFCASTWHENCHICKEN + if (get_conf_parameter_single(buf,&pos,len,word_buf,sizeof(word_buf)) > 0) + { + k = atoi(word_buf); + inst_inf->fp_allow_self_cast_when_chicken = (TbBool)k; + n++; + } + if (n < 1) + { + CONFWRNLOG("Couldn't read \"%s\" parameter in [%.*s] block of %s file.", + COMMAND_TEXT(cmd_num), blocknamelen, blockname, config_textname); + } + break; case ccr_comment: break; case ccr_endOfFile: diff --git a/src/config_magic.c b/src/config_magic.c index e32bb1176e..74766defca 100644 --- a/src/config_magic.c +++ b/src/config_magic.c @@ -98,6 +98,7 @@ const struct NamedCommand spell_effect_flags[] = { {"TELEPORT", CSAfF_Teleport}, {"TIMEBOMB", CSAfF_Timebomb}, {"WIND", CSAfF_Wind}, + {"SPELL_BLOCKS", CSAfF_SpellBlocks}, {NULL, 0}, }; diff --git a/src/config_magic.h b/src/config_magic.h index cd599c149d..89075e7462 100644 --- a/src/config_magic.h +++ b/src/config_magic.h @@ -55,6 +55,7 @@ enum CreatureSpellAffectedFlags { CSAfF_Teleport = 0x008000, CSAfF_Timebomb = 0x010000, CSAfF_Wind = 0x020000, + CSAfF_SpellBlocks = 0x040000, }; enum SpellPropertiesFlags { diff --git a/src/console_cmd.c b/src/console_cmd.c index bfd1541d24..1585c3e653 100644 --- a/src/console_cmd.c +++ b/src/console_cmd.c @@ -2182,6 +2182,25 @@ TbBool cmd_cheat_menu(PlayerNumber plyr_idx, char * args) return true; } +TbBool cmd_chicken_creature(PlayerNumber plyr_idx, char * args) +{ + if (game.easter_eggs_enabled == false) { + targeted_message_add(MsgType_Player, plyr_idx, plyr_idx, GUI_MESSAGES_DELAY, "require 'cheat mode'"); + return false; + } + struct PlayerInfo * player = get_player(plyr_idx); + struct Thing * thing = thing_get(player->influenced_thing_idx); + if (!thing_is_creature(thing)) { + targeted_message_add(MsgType_Player, plyr_idx, plyr_idx, GUI_MESSAGES_DELAY, "no thing selected or not creature"); + return false; + } + struct PowerConfigStats *powerst = get_power_model_stats(PwrK_CHICKEN); + thing_play_sample(thing, powerst->select_sound_idx, NORMAL_PITCH, 0, 3, 0, 4, FULL_LOUDNESS); + // Not sure how to handle this yet, for now simply hardcode the intended spell kind with a number. + apply_spell_effect_to_thing(thing, 27, 8, plyr_idx); // 27 was 'SplK_Chicken' in the enum. + return true; +} + struct ConsoleCommand { const char * name; @@ -2293,6 +2312,7 @@ static const struct ConsoleCommand console_commands[] = { { "lua", cmd_lua}, { "luatypedump", cmd_luatypedump}, { "cheat.menu", cmd_cheat_menu}, + { "creature.chicken", cmd_chicken_creature}, }; static const int console_command_count = sizeof(console_commands) / sizeof(*console_commands); diff --git a/src/creature_control.h b/src/creature_control.h index 3b0c18dcaa..b40cacc7c5 100644 --- a/src/creature_control.h +++ b/src/creature_control.h @@ -194,6 +194,7 @@ struct CreatureControl { int32_t turns_at_job; short blocking_door_id; unsigned char move_flags; + unsigned long cleanse_flags; union // Union on diggers, heroes and normal creatures { diff --git a/src/creature_graphics.c b/src/creature_graphics.c index ae183bce14..85a54f908a 100644 --- a/src/creature_graphics.c +++ b/src/creature_graphics.c @@ -458,7 +458,7 @@ void update_creature_graphic_anim(struct Thing *thing) TRACE_THING(thing); struct CreatureControl* cctrl = creature_control_get_from_thing(thing); struct CreatureModelConfig* crconf = creature_stats_get_from_thing(thing); - + struct InstanceInfo* inst_inf; if ((thing->size_change & TSC_ChangeSize) != 0) { thing->size_change &= ~TSC_ChangeSize; @@ -469,19 +469,20 @@ void update_creature_graphic_anim(struct Thing *thing) } else if (!creature_under_spell_effect(thing, CSAfF_Chicken)) { + inst_inf = creature_instance_info_get(cctrl->instance_id); if (cctrl->instance_id != CrInst_NULL) { if (cctrl->instance_id == CrInst_TORTURED) { thing->rendering_flags &= ~(TRF_Transpar_Flags); } - struct InstanceInfo* inst_inf = creature_instance_info_get(cctrl->instance_id); - if (creature_under_spell_effect(thing, CSAfF_Freeze)) + if (!creature_under_spell_effect(thing, CSAfF_Freeze)) { - update_creature_anim(thing, 0, inst_inf->graphics_idx); - } else + update_creature_anim(thing, cctrl->instance_anim_step_turns, inst_inf->graphics_idx); + } + else { - update_creature_anim(thing, cctrl->instance_anim_step_turns, inst_inf->graphics_idx); + update_creature_anim(thing, 0, inst_inf->graphics_idx); } } else if ((cctrl->frozen_on_hit != 0) || creature_is_dying(thing) || creature_under_spell_effect(thing, CSAfF_Freeze)) diff --git a/src/creature_instances.c b/src/creature_instances.c index 2657006dd0..d37cf9b005 100644 --- a/src/creature_instances.c +++ b/src/creature_instances.c @@ -126,6 +126,7 @@ const struct NamedCommand creature_instances_validate_func_type[] = { {"validate_target_benefits_from_wind", 10}, {"validate_target_non_idle", 11}, {"validate_target_takes_gas_damage", 12}, + {"validate_target_requires_cleansing", 13}, {NULL, 0}, }; @@ -143,6 +144,7 @@ Creature_Validate_Func creature_instances_validate_func_list[] = { validate_target_benefits_from_wind, validate_target_non_idle, validate_target_takes_gas_damage, + validate_target_requires_cleansing, NULL, }; @@ -408,10 +410,6 @@ void process_creature_instance(struct Thing *thing) TRACE_THING(thing); cctrl = creature_control_get_from_thing(thing); SYNCDBG(19, "Starting for %s index %d instance %d", thing_model_name(thing), (int)thing->index, (int)cctrl->instance_id); - if (cctrl->instance_id != CrInst_NULL && creature_under_spell_effect(thing, CSAfF_Freeze)) - { - return; - } if (cctrl->inst_turn >= cctrl->inst_total_turns) { if (!cctrl->inst_repeat) @@ -521,7 +519,8 @@ long instf_creature_cast_spell(struct Thing *creatng, int32_t *param) // instead of creature_cast_spell_at_thing. target = thing_get(cctrl->targtng_idx); } - + // Start cooldown after spell effect activates + cctrl->instance_use_turn[cctrl->instance_id] = game.play_gameturn; if (!thing_is_invalid(target)) { creature_cast_spell_at_thing(creatng, target, spl_idx, cctrl->exp_level); @@ -530,9 +529,6 @@ long instf_creature_cast_spell(struct Thing *creatng, int32_t *param) { creature_cast_spell(creatng, spl_idx, cctrl->exp_level, cctrl->targtstl_x, cctrl->targtstl_y); } - - // Start cooldown after spell effect activates - cctrl->instance_use_turn[cctrl->instance_id] = game.play_gameturn; return 0; } @@ -1155,8 +1151,9 @@ TbBool validate_source_basic if (!creature_instance_is_available(source, inst_idx) || !creature_instance_has_reset(source, inst_idx) || - creature_under_spell_effect(source, CSAfF_Freeze) || - creature_is_fleeing_combat(source) || creature_under_spell_effect(source, CSAfF_Chicken) || + ((creature_under_spell_effect(source, CSAfF_Freeze)) && (!flag_is_set(param1, CSAfF_Freeze))) || + creature_is_fleeing_combat(source) || + ((creature_under_spell_effect(source, CSAfF_Chicken)) && (!flag_is_set(param1, CSAfF_Chicken))) || creature_is_being_unconscious(source) || creature_is_dying(source) || thing_is_picked_up(source) || creature_is_being_dropped(source) || creature_is_being_sacrificed(source) || creature_is_being_summoned(source)) @@ -1834,4 +1831,37 @@ void script_set_creature_instance(ThingModel crmodel, short slot, int instance, } } +TbBool validate_target_requires_cleansing + ( + struct Thing *source, + struct Thing *target, + CrInstance inst_idx, + int32_t param1, + int32_t param2 + ) +{ + if (!validate_target_basic(source, target, inst_idx, param1, param2) || creature_is_being_unconscious(target) || + !creature_requires_cleansing(target, param1)) + { + return false; + } + + if (source->index == target->index) + { + // Special case. The creature is always allowed to cleanse itself. + return true; + } + else + { + if (creature_is_being_tortured(target) || creature_is_kept_in_prison(target) || + creature_is_being_tortured(source) || creature_is_kept_in_prison(source) || + creature_under_spell_effect(source, CSAfF_Freeze) || creature_under_spell_effect(source, CSAfF_Chicken)) // not allowed to cleanse others (only itself) even if source param1 is set + { + return false; + } + } + + return true; +} + /******************************************************************************/ diff --git a/src/creature_instances.h b/src/creature_instances.h index 02673fb1af..2775ec1337 100644 --- a/src/creature_instances.h +++ b/src/creature_instances.h @@ -84,6 +84,9 @@ enum CreatureInstances { CrInst_RANGED_SPEED, CrInst_RANGED_ARMOUR, CrInst_RANGED_REBOUND, + CrInst_CRIPPLE, + CrInst_CLEANSE, + CrInst_RANGED_CLEANSE, CrInst_LISTEND, }; @@ -124,6 +127,8 @@ struct InstanceInfo { // Refer to creature_instances_search_targets_func_list uint8_t search_func; int32_t search_func_params[2]; + TbBool fp_allow_self_cast_while_frozen; + TbBool fp_allow_self_cast_when_chicken; }; /******************************************************************************/ @@ -179,6 +184,7 @@ TbBool validate_target_benefits_from_wind(struct Thing *source, struct Thing *ta TbBool validate_target_benefits_from_healing(struct Thing *source, struct Thing *target, CrInstance inst_idx, int32_t param1, int32_t param2); TbBool validate_target_non_idle(struct Thing* source, struct Thing* target, CrInstance inst_idx, int32_t param1, int32_t param2); TbBool validate_target_takes_gas_damage(struct Thing* source, struct Thing* target, CrInstance inst_idx, int32_t param1, int32_t param2); +TbBool validate_target_requires_cleansing(struct Thing* source, struct Thing* target, CrInstance inst_idx, int32_t param1, int32_t param2); TbBool search_target_generic(struct Thing *source, CrInstance inst_idx, ThingIndex **targets, uint16_t *found_count, int32_t param1, int32_t param2); TbBool search_target_ranged_heal(struct Thing *source, CrInstance inst_idx, ThingIndex **targets, uint16_t *found_count, int32_t param1, int32_t param2); diff --git a/src/creature_states_combt.c b/src/creature_states_combt.c index e2e908a441..305d33ae82 100644 --- a/src/creature_states_combt.c +++ b/src/creature_states_combt.c @@ -3499,4 +3499,23 @@ short creature_damage_walls(struct Thing *creatng) } +TbBool creature_requires_cleansing(const struct Thing* thing, SpellKind spell_idx) +{ + struct CreatureControl* cctrl = creature_control_get_from_thing(thing); + struct SpellConfig* spconf = get_spell_config(spell_idx); + for (long i = 0; i < CREATURE_MAX_SPELLS_CASTED_AT; i++) + { + struct CastedSpellData *cspell = &cctrl->casted_spells[i]; + struct SpellConfig* spconf2 = get_spell_config(cspell->spkind); + if (flag_is_set(spconf->cleanse_flags, spconf2->spell_flags)) + { + if (creature_under_spell_effect(thing, spconf2->spell_flags)) + { + return true; + } + } + } + return false; +} + /******************************************************************************/ diff --git a/src/creature_states_combt.h b/src/creature_states_combt.h index 8bab0955b7..61e8af0980 100644 --- a/src/creature_states_combt.h +++ b/src/creature_states_combt.h @@ -71,6 +71,7 @@ TbBool creature_has_creature_in_combat(const struct Thing *thing, const struct T TbBool set_creature_combat_state(struct Thing *fighter, struct Thing *enemy, CrAttackType attack_type); TbBool battle_with_creature_of_player(PlayerNumber plyr_idx, BattleIndex battle_id); TbBool creature_would_benefit_from_healing(const struct Thing* thing); +TbBool creature_requires_cleansing(const struct Thing* thing, SpellKind spell_idx); void reset_postal_instance_cache(); CrInstance get_postal_instance_to_use(const struct Thing *thing, unsigned long dist); diff --git a/src/creature_states_prisn.c b/src/creature_states_prisn.c index e5491fe99a..7e224e705b 100644 --- a/src/creature_states_prisn.c +++ b/src/creature_states_prisn.c @@ -128,6 +128,9 @@ short creature_arrived_at_prison(struct Thing *creatng) { clean_spell_effect(creatng, CSAfF_Invisibility); } + if (creature_under_spell_effect(creatng, CSAfF_SpellBlocks)) { + clean_spell_effect(creatng, CSAfF_SpellBlocks); + } if (creatng->light_id != 0) { light_delete_light(creatng->light_id); creatng->light_id = 0; diff --git a/src/engine_redraw.c b/src/engine_redraw.c index cb2fa7fc05..be788949fe 100644 --- a/src/engine_redraw.c +++ b/src/engine_redraw.c @@ -100,10 +100,14 @@ static void draw_creature_view_icons(struct Thing* creatng) y = MyScreenHeight - scale_ui_value_lofi(spr->SHeight * 2); } struct CreatureControl *cctrl = creature_control_get_from_thing(creatng); - struct SpellConfig *spconf; for (SpellKind spell_idx = 0; spell_idx < CREATURE_MAX_SPELLS_CASTED_AT; spell_idx++) { - spconf = get_spell_config(cctrl->casted_spells[spell_idx].spkind); + struct CastedSpellData* cspell = &cctrl->casted_spells[spell_idx]; + if (cspell->spkind == 0) + { + continue; + } + struct SpellConfig *spconf = get_spell_config(cspell->spkind); long spridx = spconf->medsym_sprite_idx; if (flag_is_set(spconf->spell_flags, CSAfF_Invisibility)) { diff --git a/src/front_input.c b/src/front_input.c index 374bc676df..b8216ec9c0 100644 --- a/src/front_input.c +++ b/src/front_input.c @@ -1910,45 +1910,42 @@ short get_creature_control_action_inputs(void) set_players_packet_action(player, PckA_SelectFPPickup, player->thing_under_hand, 0, 0, 0); } } - if (!creature_under_spell_effect(thing, CSAfF_Chicken)) + if (numkey != -1) { - if (numkey != -1) + int num_avail = 0; + for (int idx = 0; idx < LEARNED_INSTANCES_COUNT; idx++) { - int num_avail = 0; - for (int idx = 0; idx < LEARNED_INSTANCES_COUNT; idx++) + struct Thing* cthing = thing_get(player->controlled_thing_idx); + TRACE_THING(cthing); + struct CreatureModelConfig* crconf = creature_stats_get_from_thing(cthing); + int inst_id = crconf->learned_instance_id[idx]; + if (creature_instance_is_available(cthing, inst_id)) { - struct Thing* cthing = thing_get(player->controlled_thing_idx); - TRACE_THING(cthing); - struct CreatureModelConfig* crconf = creature_stats_get_from_thing(cthing); - int inst_id = crconf->learned_instance_id[idx]; - if (creature_instance_is_available(cthing, inst_id)) + if (numkey == num_avail) { - if (numkey == num_avail) - { - set_players_packet_action(player, PckA_CtrlCrtrSetInstnc, inst_id, 0, 0, 0); - break; - } - num_avail++; + set_players_packet_action(player, PckA_CtrlCrtrSetInstnc, inst_id, 0, 0, 0); + break; } + num_avail++; } } + } + + // Next/Previous instance switching + if (menu_is_active(GMnu_CREATURE_QUERY1) || menu_is_active(GMnu_CREATURE_QUERY2)) + { + struct Thing* cthing = thing_get(player->controlled_thing_idx); - // Next/Previous instance switching - if (menu_is_active(GMnu_CREATURE_QUERY1) || menu_is_active(GMnu_CREATURE_QUERY2)) + if (is_key_pressed(KC_GAMEPAD_RIGHTSHOULDER, KMod_DONTCARE)) { - struct Thing* cthing = thing_get(player->controlled_thing_idx); + clear_key_pressed(KC_GAMEPAD_RIGHTSHOULDER); + set_possession_instance(player, cthing, 1); - if (is_key_pressed(KC_GAMEPAD_RIGHTSHOULDER, KMod_DONTCARE)) - { - clear_key_pressed(KC_GAMEPAD_RIGHTSHOULDER); - set_possession_instance(player, cthing, 1); - - } - else if (is_key_pressed(KC_GAMEPAD_LEFTSHOULDER, KMod_DONTCARE)) - { - clear_key_pressed(KC_GAMEPAD_LEFTSHOULDER); - set_possession_instance(player, cthing, -1); - } + } + else if (is_key_pressed(KC_GAMEPAD_LEFTSHOULDER, KMod_DONTCARE)) + { + clear_key_pressed(KC_GAMEPAD_LEFTSHOULDER); + set_possession_instance(player, cthing, -1); } } return false; diff --git a/src/frontmenu_ingame_tabs.c b/src/frontmenu_ingame_tabs.c index 15f124ceb8..9ed82de989 100644 --- a/src/frontmenu_ingame_tabs.c +++ b/src/frontmenu_ingame_tabs.c @@ -1873,7 +1873,24 @@ void gui_area_instance_button(struct GuiButton *gbtn) LbTextDrawResized(gbtn->scr_pos_x + 52*units_per_px/16, gbtn->scr_pos_y + 9*units_per_px/16, tx_units_per_px, text); spr_idx = gbtn->sprite_idx; // Show disabled icon if instance is on cooldown or creature is frozen. - if ((!creature_instance_has_reset(ctrltng, curbtn_inst_id)) || (creature_under_spell_effect(ctrltng, CSAfF_Freeze) && (!inst_inf->instant))) + TbBool disabled; + if (!creature_instance_has_reset(ctrltng, curbtn_inst_id)) + { + disabled = true; + } + else if (creature_under_spell_effect(ctrltng, CSAfF_Freeze)) + { + disabled = inst_inf->fp_allow_self_cast_while_frozen == false; + } + else if (creature_under_spell_effect(ctrltng, CSAfF_Chicken)) + { + disabled = inst_inf->fp_allow_self_cast_when_chicken == false; + } + else + { + disabled = false; + } + if (disabled) { spr_idx++; } diff --git a/src/gui_boxmenu.c b/src/gui_boxmenu.c index 35f356c89c..1c136f5fd4 100644 --- a/src/gui_boxmenu.c +++ b/src/gui_boxmenu.c @@ -148,6 +148,7 @@ struct GuiBoxOption gui_instance_option_list[] = { {"Disease",1,NULL, gf_change_creature_instance,CrInst_CAST_SPELL_DISEASE, 0, 0, CrInst_CAST_SPELL_DISEASE, 0, 0, 0, true}, {"Chicken",1,NULL, gf_change_creature_instance,CrInst_CAST_SPELL_CHICKEN, 0, 0, CrInst_CAST_SPELL_CHICKEN, 0, 0, 0, true}, {"Time Bomb",1,NULL, gf_change_creature_instance,CrInst_CAST_SPELL_TIME_BOMB, 0, 0, CrInst_CAST_SPELL_TIME_BOMB, 0, 0, 0, true}, + {"Cleanse", 1, NULL, gf_change_creature_instance, CrInst_CLEANSE, 0, 0, CrInst_CLEANSE, 0, 0, 0, true}, {"!", 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, false}, }; diff --git a/src/packets.c b/src/packets.c index 430c218ee2..9f44d0ccec 100644 --- a/src/packets.c +++ b/src/packets.c @@ -1316,167 +1316,200 @@ TbBool can_process_creature_input(struct Thing *thing) void process_players_creature_control_packet_control(long idx) { + SYNCDBG(6,"Starting"); struct InstanceInfo *inst_inf; long i; - - SYNCDBG(6,"Starting"); struct PlayerInfo* player = get_player(idx); - struct Packet* pckt = get_packet_direct(player->packet_num); struct Thing* cctng = thing_get(player->controlled_thing_idx); - if (!can_process_creature_input(cctng)) - return; + struct Packet* pckt = get_packet_direct(player->packet_num); struct CreatureControl* ccctrl = creature_control_get_from_thing(cctng); - long speed_limit = get_creature_speed(cctng); - if ((pckt->control_flags & PCtr_MoveUp) != 0) - { - if (!creature_control_invalid(ccctrl)) - { - ccctrl->move_speed = compute_controlled_speed_increase(ccctrl->move_speed, speed_limit); - ccctrl->creature_control_flags |= CCFlg_MoveY; - } else - { - ERRORLOG("No creature to increase speed"); - } - } - if ((pckt->control_flags & PCtr_MoveDown) != 0) + ThingIndex target_idx; + if (can_process_creature_input(cctng)) { - if (!creature_control_invalid(ccctrl)) - { - ccctrl->move_speed = compute_controlled_speed_decrease(ccctrl->move_speed, speed_limit); - ccctrl->creature_control_flags |= CCFlg_MoveY; - } else + long speed_limit = get_creature_speed(cctng); + if ((pckt->control_flags & PCtr_MoveUp) != 0) { - ERRORLOG("No creature to decrease speed"); - } - } - if ((pckt->control_flags & PCtr_MoveLeft) != 0) - { - if (!creature_control_invalid(ccctrl)) - { - ccctrl->orthogn_speed = compute_controlled_speed_increase(ccctrl->orthogn_speed, speed_limit); - ccctrl->creature_control_flags |= CCFlg_MoveX; - } else - { - ERRORLOG("No creature to increase speed"); + if (!creature_control_invalid(ccctrl)) + { + ccctrl->move_speed = compute_controlled_speed_increase(ccctrl->move_speed, speed_limit); + ccctrl->creature_control_flags |= CCFlg_MoveY; + } else + { + ERRORLOG("No creature to increase speed"); + } } - } - if ((pckt->control_flags & PCtr_MoveRight) != 0) - { - if (!creature_control_invalid(ccctrl)) + if ((pckt->control_flags & PCtr_MoveDown) != 0) { - ccctrl->orthogn_speed = compute_controlled_speed_decrease(ccctrl->orthogn_speed, speed_limit); - ccctrl->creature_control_flags |= CCFlg_MoveX; - } else - { - ERRORLOG("No creature to decrease speed"); + if (!creature_control_invalid(ccctrl)) + { + ccctrl->move_speed = compute_controlled_speed_decrease(ccctrl->move_speed, speed_limit); + ccctrl->creature_control_flags |= CCFlg_MoveY; + } else + { + ERRORLOG("No creature to decrease speed"); + } } - } - if (flag_is_set(cctng->movement_flags, TMvF_Flying)) - { - MapCoord floor_height, ceiling_height; - if ((pckt->control_flags & PCtr_Ascend) != 0) + if ((pckt->control_flags & PCtr_MoveLeft) != 0) { if (!creature_control_invalid(ccctrl)) { - ccctrl->vertical_speed = compute_controlled_speed_increase(ccctrl->vertical_speed, speed_limit); - ccctrl->creature_control_flags |= CCFlg_MoveZ; - if (ccctrl->vertical_speed != 0) - { - get_floor_and_ceiling_height_under_thing_at(cctng, &cctng->mappos, &floor_height, &ceiling_height); - if ( (cctng->mappos.z.val >= floor_height) && (cctng->mappos.z.val <= ceiling_height) ) - { - ccctrl->moveaccel.z.val = distance_with_angle_to_coord_z(ccctrl->vertical_speed, 227); - } - else - { - ccctrl->moveaccel.z.val = 0; - } - } + ccctrl->orthogn_speed = compute_controlled_speed_increase(ccctrl->orthogn_speed, speed_limit); + ccctrl->creature_control_flags |= CCFlg_MoveX; } else { - ERRORLOG("No creature to ascend"); + ERRORLOG("No creature to increase speed"); } } - if ((pckt->control_flags & PCtr_Descend) != 0) + if ((pckt->control_flags & PCtr_MoveRight) != 0) { if (!creature_control_invalid(ccctrl)) { - // We want increase here, not decrease, because we don't want it angle-dependent - ccctrl->vertical_speed = compute_controlled_speed_increase(ccctrl->vertical_speed, speed_limit); - ccctrl->creature_control_flags |= CCFlg_MoveZ; - if (ccctrl->vertical_speed != 0) - { - get_floor_and_ceiling_height_under_thing_at(cctng, &cctng->mappos, &floor_height, &ceiling_height); - if ( (cctng->mappos.z.val >= floor_height) && (cctng->mappos.z.val <= ceiling_height) ) - { - ccctrl->moveaccel.z.val = distance_with_angle_to_coord_z(ccctrl->vertical_speed, 1820); - } - else - { - ccctrl->moveaccel.z.val = 0; - } - } + ccctrl->orthogn_speed = compute_controlled_speed_decrease(ccctrl->orthogn_speed, speed_limit); + ccctrl->creature_control_flags |= CCFlg_MoveX; } else { - ERRORLOG("No creature to descend"); + ERRORLOG("No creature to decrease speed"); } } - } - - if ((pckt->control_flags & PCtr_LBtnRelease) != 0) - { - i = ccctrl->active_instance_id; - if (ccctrl->instance_id == CrInst_NULL) + if (flag_is_set(cctng->movement_flags, TMvF_Flying)) { - if (creature_instance_is_available(cctng, i)) + MapCoord floor_height, ceiling_height; + if ((pckt->control_flags & PCtr_Ascend) != 0) { - if (creature_instance_has_reset(cctng, i)) + if (!creature_control_invalid(ccctrl)) { - if (!creature_under_spell_effect(cctng, CSAfF_Chicken)) + ccctrl->vertical_speed = compute_controlled_speed_increase(ccctrl->vertical_speed, speed_limit); + ccctrl->creature_control_flags |= CCFlg_MoveZ; + if (ccctrl->vertical_speed != 0) { - inst_inf = creature_instance_info_get(i); - process_player_use_instance(cctng, i, pckt); + get_floor_and_ceiling_height_under_thing_at(cctng, &cctng->mappos, &floor_height, &ceiling_height); + if ( (cctng->mappos.z.val >= floor_height) && (cctng->mappos.z.val <= ceiling_height) ) + { + ccctrl->moveaccel.z.val = distance_with_angle_to_coord_z(ccctrl->vertical_speed, 227); + } + else + { + ccctrl->moveaccel.z.val = 0; + } } + } else + { + ERRORLOG("No creature to ascend"); } } - else + if ((pckt->control_flags & PCtr_Descend) != 0) { - // cheat mode - inst_inf = creature_instance_info_get(i); - process_player_use_instance(cctng, i, pckt); + if (!creature_control_invalid(ccctrl)) + { + // We want increase here, not decrease, because we don't want it angle-dependent + ccctrl->vertical_speed = compute_controlled_speed_increase(ccctrl->vertical_speed, speed_limit); + ccctrl->creature_control_flags |= CCFlg_MoveZ; + if (ccctrl->vertical_speed != 0) + { + get_floor_and_ceiling_height_under_thing_at(cctng, &cctng->mappos, &floor_height, &ceiling_height); + if ( (cctng->mappos.z.val >= floor_height) && (cctng->mappos.z.val <= ceiling_height) ) + { + ccctrl->moveaccel.z.val = distance_with_angle_to_coord_z(ccctrl->vertical_speed, 1820); + } + else + { + ccctrl->moveaccel.z.val = 0; + } + } + } else + { + ERRORLOG("No creature to descend"); + } } } + long new_horizontal, new_vertical, new_roll; + process_first_person_look(cctng, pckt, cctng->move_angle_xy, cctng->move_angle_z, &new_horizontal, &new_vertical, &new_roll); + cctng->move_angle_xy = new_horizontal; + cctng->move_angle_z = new_vertical; + ccctrl->roll = new_roll; } - if ((pckt->control_flags & PCtr_LBtnHeld) != 0) + if ((!creature_is_dying(cctng)) && (cctng->active_state != CrSt_CreatureUnconscious)) { - // Button is held down - check whether the instance has auto-repeat - i = ccctrl->active_instance_id; - inst_inf = creature_instance_info_get(i); - if ((inst_inf->instance_property_flags & InstPF_RepeatTrigger) != 0) + TbBool allowed; + if ((pckt->control_flags & PCtr_LBtnRelease) != 0) { + i = ccctrl->active_instance_id; if (ccctrl->instance_id == CrInst_NULL) { if (creature_instance_is_available(cctng, i)) { if (creature_instance_has_reset(cctng, i)) { - process_player_use_instance(cctng, i, pckt); + target_idx = get_human_controlled_creature_target(cctng, i, pckt); + if (creature_under_spell_effect(cctng, CSAfF_Chicken)) + { + inst_inf = creature_instance_info_get(i); + allowed = inst_inf->fp_allow_self_cast_when_chicken & (cctng->index == target_idx); + } + else + { + allowed = true; + } + if (allowed) + { + if (creature_under_spell_effect(cctng, CSAfF_Freeze)) + { + inst_inf = creature_instance_info_get(i); + allowed = inst_inf->fp_allow_self_cast_while_frozen & (cctng->index == target_idx); + } + if (allowed) + { + process_player_use_instance(cctng, i, pckt); + } + } } } else { // cheat mode + inst_inf = creature_instance_info_get(i); process_player_use_instance(cctng, i, pckt); } } } + if ((pckt->control_flags & PCtr_LBtnHeld) != 0) + { + // Button is held down - check whether the instance has auto-repeat + i = ccctrl->active_instance_id; + inst_inf = creature_instance_info_get(i); + target_idx = get_human_controlled_creature_target(cctng, i, pckt); + if ((inst_inf->instance_property_flags & InstPF_RepeatTrigger) != 0) + { + if (ccctrl->instance_id == CrInst_NULL) + { + if (creature_instance_is_available(cctng, i)) + { + if (creature_instance_has_reset(cctng, i)) + { + if (creature_under_spell_effect(cctng, CSAfF_Freeze)) + { + target_idx = get_human_controlled_creature_target(cctng, i, pckt); + allowed = inst_inf->fp_allow_self_cast_while_frozen & (cctng->index == target_idx); + } + else + { + allowed = true; + } + if (allowed) + { + process_player_use_instance(cctng, i, pckt); + } + } + } + else + { + // cheat mode + process_player_use_instance(cctng, i, pckt); + } + } + } + } } - - long new_horizontal, new_vertical, new_roll; - process_first_person_look(cctng, pckt, cctng->move_angle_xy, cctng->move_angle_z, &new_horizontal, &new_vertical, &new_roll); - cctng->move_angle_xy = new_horizontal; - cctng->move_angle_z = new_vertical; - ccctrl->roll = new_roll; } void process_players_creature_control_packet_action(long plyr_idx) @@ -1521,11 +1554,34 @@ void process_players_creature_control_packet_action(long plyr_idx) { if (creature_instance_is_available(thing,i) && creature_instance_has_reset(thing, pckt->actn_par1)) { - i = pckt->actn_par1; - process_player_use_instance(thing, i, pckt); - if (plyr_idx == my_player_number) { - instant_instance_selected(i); - } + TbBool allowed; + TbBool frozen = creature_under_spell_effect(thing, CSAfF_Freeze); + TbBool chicken = creature_under_spell_effect(thing, CSAfF_Chicken); + ThingIndex target_idx = get_human_controlled_creature_target(thing, i, pckt); + if (frozen && chicken) + { + allowed = (inst_inf->fp_allow_self_cast_while_frozen & inst_inf->fp_allow_self_cast_when_chicken) && (thing->index == target_idx); + } + else if (frozen) + { + allowed = inst_inf->fp_allow_self_cast_while_frozen & (thing->index == target_idx); + } + else if (chicken) + { + allowed = inst_inf->fp_allow_self_cast_when_chicken & (thing->index == target_idx); + } + else + { + allowed = true; + } + if (allowed) + { + i = pckt->actn_par1; + process_player_use_instance(thing, i, pckt); + if (plyr_idx == my_player_number) { + instant_instance_selected(i); + } + } } } break; diff --git a/src/room_jobs.c b/src/room_jobs.c index 90c1a3d8b4..7441efeddc 100644 --- a/src/room_jobs.c +++ b/src/room_jobs.c @@ -101,6 +101,10 @@ TbBool add_creature_to_torture_room(struct Thing *creatng, const struct Room *ro { clean_spell_effect(creatng, CSAfF_Invisibility); } + if (creature_under_spell_effect(creatng, CSAfF_SpellBlocks)) + { + clean_spell_effect(creatng, CSAfF_SpellBlocks); + } if (room->owner != game.neutral_player_num) { struct Dungeon* dungeon = get_dungeon(room->owner); diff --git a/src/thing_creature.c b/src/thing_creature.c index 0a49015f4d..6efedcc1ce 100644 --- a/src/thing_creature.c +++ b/src/thing_creature.c @@ -717,6 +717,17 @@ TbBool creature_is_immune_to_spell_effect_f(const struct Thing *thing, unsigned { return false; } + if (creature_under_spell_effect(thing, CSAfF_SpellBlocks)) + { + struct CreatureControl *cctrl = creature_control_get_from_thing(thing); + if (!creature_control_invalid(cctrl)) + { + if (flag_is_set(cctrl->cleanse_flags, spell_flags)) + { + return true; + } + } + } return flag_is_set(crconf->immunity_flags, spell_flags); } @@ -1177,6 +1188,14 @@ TbBool set_thing_spell_flags_f(struct Thing *thing, SpellKind spell_idx, GameTur } affected = true; } + // Spell Blocks. + if (flag_is_set(spconf->spell_flags, CSAfF_SpellBlocks) + && (!creature_is_immune_to_spell_effect(thing, CSAfF_SpellBlocks))) + { + set_flag(cctrl->spell_flags, CSAfF_SpellBlocks); + cctrl->cleanse_flags = spconf->cleanse_flags; + affected = true; + } if (!affected) { SYNCDBG(7, "%s: No spell flags %d to set on %s index %d", func_name, (uint)spconf->spell_flags, thing_model_name(thing), (int)thing->index); @@ -1358,6 +1377,14 @@ TbBool clear_thing_spell_flags_f(struct Thing *thing, unsigned long spell_flags, // 'CSAfF_Heal' is never set but we still want to mark it cleared to free the spell slot. cleared = true; } + // Spell Blocks. + if (flag_is_set(spell_flags, CSAfF_SpellBlocks) + && (creature_under_spell_effect(thing, CSAfF_SpellBlocks))) + { + clear_flag(cctrl->spell_flags, CSAfF_SpellBlocks); + cctrl->cleanse_flags = 0; + cleared = true; + } if (!cleared) { SYNCDBG(7, "%s: No spell flags %d to clear on %s index %d", func_name, (uint)spell_flags, thing_model_name(thing), (int)thing->index); @@ -1482,12 +1509,12 @@ void apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrE } GameTurnDelta duration = get_spell_full_duration(spell_idx, spell_level); // Check for cleansing one-time effect. - if (spconf->cleanse_flags > 0 - && any_flag_is_set(spconf->cleanse_flags, cctrl->spell_flags)) + if ((spconf->cleanse_flags > 0) + && (any_flag_is_set(spconf->cleanse_flags, cctrl->spell_flags))) { clean_spell_effect(thing, spconf->cleanse_flags); - if (spconf->spell_flags == 0 - && !spell_is_continuous(spell_idx, duration)) + if ((spconf->spell_flags == 0) + && (!spell_is_continuous(spell_idx, duration))) { update_aura_effect_to_thing(thing, spell_idx); return; // Exit the function, no continuous effect to apply. @@ -1874,7 +1901,7 @@ void process_thing_spell_effects(struct Thing *thing) struct SpellConfig *spconf = get_spell_config(cspell->spkind); // Terminate the spell if its duration expires, or if the spell flags are cleared and no other continuous effects are active. if ((cspell->duration <= 0) - || ((spconf->spell_flags > 0) && !flag_is_set(cctrl->spell_flags, spconf->spell_flags) && !spell_is_continuous(cspell->spkind, cspell->duration))) + || ((spconf->spell_flags > 0) && !any_flag_is_set(cctrl->spell_flags, spconf->spell_flags) && !spell_is_continuous(cspell->spkind, cspell->duration))) { terminate_thing_spell_effect(thing, cspell->spkind); continue; @@ -3715,6 +3742,7 @@ void thing_fire_shot(struct Thing *firing, struct Thing *target, ThingModel shot shotng->shot.damage = damage; shotng->health = shotst->health; shotng->parent_idx = firing->index; + shotng->shot.target_idx = target_idx; } break; } @@ -3875,7 +3903,7 @@ ThingIndex get_human_controlled_creature_target(struct Thing *thing, CrInstance if ((inst_inf->instance_property_flags & InstPF_RangedBuff) == 0 || ((packet != NULL) && (packet->additional_packet_values & PCAdV_CrtrContrlPressed) != 0)) { - // If it doesn't has RANGED_BUFF or the Possession key (default:left shift) is pressed, + // If it doesn't have RANGED_BUFF or the Possession key (default:left shift) is pressed, // cast on the caster itself. return thing->index; } @@ -6339,7 +6367,13 @@ TngUpdateRet update_creature(struct Thing *thing) } } else { - if ((cctrl->stateblock_flags == 0) || creature_state_cannot_be_blocked(thing)) + if (creature_under_spell_effect(thing, CSAfF_Freeze)) + { + if (creature_instance_is_available(thing, CrInst_CLEANSE) && creature_instance_has_reset(thing, CrInst_CLEANSE)) { + cctrl->stopped_for_hand_turns = 0; + } + } + else if ((cctrl->stateblock_flags == 0) || creature_state_cannot_be_blocked(thing)) { if (cctrl->stopped_for_hand_turns > 0) { diff --git a/src/thing_shots.c b/src/thing_shots.c index 77127ce80f..2d9249021c 100644 --- a/src/thing_shots.c +++ b/src/thing_shots.c @@ -1791,7 +1791,7 @@ struct Thing *create_shot(struct Coord3d *pos, ThingModel model, unsigned short thing->inertia_floor = shotst->inertia_floor; thing->inertia_air = shotst->inertia_air; thing->movement_flags ^= (thing->movement_flags ^ TMvF_ZeroVerticalVelocity * shotst->soft_landing) & TMvF_ZeroVerticalVelocity; - set_thing_draw(thing, shotst->sprite_anim_idx, 256, shotst->sprite_size_max, 0, 0, ODC_Default); + set_thing_draw(thing, shotst->sprite_anim_idx, 256, shotst->sprite_size_max, 0, -1, ODC_Default); thing->rendering_flags ^= (thing->rendering_flags ^ TRF_Unshaded * shotst->unshaded) & TRF_Unshaded; thing->rendering_flags ^= thing->rendering_flags ^ ((thing->rendering_flags ^ TRF_Transpar_8 * shotst->animation_transparency) & (TRF_Transpar_Flags)); thing->rendering_flags ^= (thing->rendering_flags ^ shotst->hidden_projectile) & TRF_Invisible;