diff --git a/config/fxdata/trapdoor.cfg b/config/fxdata/trapdoor.cfg index 6cca8a7d60..4cdf5f32e3 100644 --- a/config/fxdata/trapdoor.cfg +++ b/config/fxdata/trapdoor.cfg @@ -177,7 +177,7 @@ ActivationType = 0 EffectType = 0 ; If the trap is visible before getting triggered. Hidden = 0 -; Can the trap be triggered by activating it. Shots only. +; Can the trap be triggered by activating it. Set to 1 to activate by slap, set to 2 to make it target nearest enemy in range on slap. Slappable = 0 ; Can the trap be destroyed by shooting it. If 1 it can by any attack, 0 only by units with 'Disarm ability', -1 by nobody. Destructible = 0 diff --git a/src/config_trapdoor.c b/src/config_trapdoor.c index 6982d0afc2..45c1ec94ef 100644 --- a/src/config_trapdoor.c +++ b/src/config_trapdoor.c @@ -289,8 +289,8 @@ TbBool parse_trapdoor_trap_blocks(char *buf, long len, const char *config_textna trapst->unstable = 0; trapst->unsellable = false; trapst->notify = false; - trapst->placeonbridge = false; - trapst->placeonsubtile = false; + trapst->place_on_bridge = false; + trapst->place_on_subtile = false; // Default destroyed_effect is TngEffElm_Blast2. trapst->destroyed_effect = -39; @@ -960,7 +960,7 @@ TbBool parse_trapdoor_trap_blocks(char *buf, long len, const char *config_textna k = atoi(word_buf); if (k >= 0) { - trapst->placeonbridge = k; + trapst->place_on_bridge = k; n++; } } @@ -1111,7 +1111,7 @@ TbBool parse_trapdoor_trap_blocks(char *buf, long len, const char *config_textna k = atoi(word_buf); if (k >= 0) { - trapst->placeonsubtile = k; + trapst->place_on_subtile = k; n++; } } diff --git a/src/config_trapdoor.h b/src/config_trapdoor.h index 7019315b90..15fd7468ff 100644 --- a/src/config_trapdoor.h +++ b/src/config_trapdoor.h @@ -84,8 +84,8 @@ struct TrapConfigStats { short unstable; TbBool notify; TbBool unsellable; - TbBool placeonbridge; - TbBool placeonsubtile; + TbBool place_on_bridge; + TbBool place_on_subtile; EffectOrEffElModel destroyed_effect; }; diff --git a/src/lvl_script_commands.c b/src/lvl_script_commands.c index a5d94f00d2..1da02a1eb6 100644 --- a/src/lvl_script_commands.c +++ b/src/lvl_script_commands.c @@ -1593,8 +1593,8 @@ static void new_trap_type_check(const struct ScriptLine* scline) trapst->unstable = 0; trapst->unsellable = false; trapst->notify = false; - trapst->placeonbridge = false; - trapst->placeonsubtile = false; + trapst->place_on_bridge = false; + trapst->place_on_subtile = false; trapst->place_sound_idx = 117; trapst->trigger_sound_idx = 176; trapst->destroyed_effect = -39; @@ -1836,7 +1836,7 @@ static void set_trap_configuration_process(struct ScriptContext *context) trapst->unsellable = value; break; case 35: // PlaceOnBridge - trapst->placeonbridge = value; + trapst->place_on_bridge = value; break; case 36: // ShotOrigin trapstat->shot_shift_x = value; diff --git a/src/magic.c b/src/magic.c index b45aab1808..fdc1711890 100644 --- a/src/magic.c +++ b/src/magic.c @@ -291,7 +291,7 @@ TbBool can_cast_power_on_thing(PlayerNumber plyr_idx, const struct Thing *thing, if (thing->owner == plyr_idx) { struct TrapConfigStats *trapst; trapst = &game.conf.trapdoor_conf.trap_cfgstats[thing->model]; - if ((trapst->slappable == 1) && trap_is_active(thing)) { + if ((trapst->slappable > 0) && trap_is_active(thing)) { return true; } } diff --git a/src/packets_input.c b/src/packets_input.c index 18f3d7efca..6990a649be 100644 --- a/src/packets_input.c +++ b/src/packets_input.c @@ -631,7 +631,7 @@ TbBool process_dungeon_control_packet_dungeon_place_trap(long plyr_idx) return false; } struct TrapConfigStats *trapst = get_trap_model_stats(player->chosen_trap_kind); - player->full_slab_cursor = (trapst->placeonsubtile == false); + player->full_slab_cursor = (trapst->place_on_subtile == false); long i = tag_cursor_blocks_place_trap(player->id_number, stl_x, stl_y, player->full_slab_cursor, player->chosen_trap_kind); if ((pckt->control_flags & PCtr_LBtnClick) == 0) { diff --git a/src/player_instances.c b/src/player_instances.c index 364ba70091..f3b6372413 100644 --- a/src/player_instances.c +++ b/src/player_instances.c @@ -252,9 +252,20 @@ long pinstfe_hand_whip(struct PlayerInfo *player, long *n) break; case TCls_Trap: trapst = &game.conf.trapdoor_conf.trap_cfgstats[thing->model]; - if ((trapst->slappable == 1) && trap_is_active(thing)) + if ((trapst->slappable > 0) && trap_is_active(thing)) { - external_activate_trap_shot_at_angle(thing, player->acamera->orient_a, thing_get(player->hand_thing_idx)); + struct TrapStats* trapstat = &game.conf.trap_stats[thing->model]; + struct Thing* trgtng = INVALID_THING; + shotst = get_shot_model_stats(trapstat->created_itm_model); + if (trapst->slappable == 1) + { + external_activate_trap_shot_at_angle(thing, player->acamera->orient_a, trgtng); + } else + if (trapst->slappable == 2) + { + trgtng = get_nearest_enemy_creature_in_sight_and_range_of_trap(thing); + external_activate_trap_shot_at_angle(thing, player->acamera->orient_a, trgtng); + } } break; case TCls_Object: @@ -1195,8 +1206,7 @@ TbBool player_place_trap_at(MapSubtlCoord stl_x, MapSubtlCoord stl_y, PlayerNumb } struct TrapConfigStats* trap_cfg = get_trap_model_stats(tngmodel); struct Coord3d pos; - struct PlayerInfo* player = get_player(plyr_idx); - if (trap_cfg->placeonsubtile) + if (trap_cfg->place_on_subtile) { set_coords_to_subtile_center(&pos, stl_x, stl_y, 1); } diff --git a/src/thing_traps.c b/src/thing_traps.c index 31f0ce2010..7728c5afdd 100644 --- a/src/thing_traps.c +++ b/src/thing_traps.c @@ -72,7 +72,7 @@ TbBool trap_is_slappable(const struct Thing *thing, PlayerNumber plyr_idx) if (thing->owner == plyr_idx) { trapst = &game.conf.trapdoor_conf.trap_cfgstats[thing->model]; - return (trapst->slappable == 1) && trap_is_active(thing); + return (trapst->slappable > 0) && trap_is_active(thing); } return false; } @@ -1012,7 +1012,7 @@ unsigned long remove_traps_around_subtile(MapSubtlCoord stl_x, MapSubtlCoord stl return total; } -void external_activate_trap_shot_at_angle(struct Thing *thing, long a2, struct Thing *hand) +void external_activate_trap_shot_at_angle(struct Thing *thing, short angle, struct Thing *trgtng) { struct TrapStats* trapstat = &game.conf.trap_stats[thing->model]; if (trapstat->created_itm_model <= 0) { @@ -1022,7 +1022,7 @@ void external_activate_trap_shot_at_angle(struct Thing *thing, long a2, struct T if ((trapstat->activation_type != TrpAcT_CreatureShot) && (trapstat->activation_type != TrpAcT_HeadforTarget90)) { - activate_trap(thing, hand); + activate_trap(thing, trgtng); process_trap_charge(thing); if (thing->trap.num_shots != INFINITE_CHARGES) { @@ -1035,20 +1035,14 @@ void external_activate_trap_shot_at_angle(struct Thing *thing, long a2, struct T } return; } - struct Thing* shotng = create_shot(&thing->mappos, trapstat->created_itm_model, thing->owner); - if (thing_is_invalid(shotng)) { - return; + if (!thing_is_invalid(trgtng)) + { + thing_fire_shot(thing, trgtng, trapstat->created_itm_model, 1, trapstat->hit_type); + } + else + { + trap_fire_shot_without_target(thing, trapstat->created_itm_model, 1, angle); } - struct ShotConfigStats* shotst = get_shot_model_stats(shotng->model); - shotng->move_angle_xy = a2; - shotng->move_angle_z = 0; - struct ComponentVector cvect; - angles_to_vector(shotng->move_angle_xy, 0, shotst->speed, &cvect); - shotng->veloc_push_add.x.val += cvect.x; - shotng->veloc_push_add.y.val += cvect.y; - shotng->veloc_push_add.z.val += cvect.z; - shotng->state_flags |= TF1_PushAdd; - shotng->shot.hit_type = trapstat->hit_type; const struct ManfctrConfig* mconf = &game.conf.traps_config[thing->model]; thing->trap.rearm_turn = game.play_gameturn + mconf->shots_delay; if (thing->trap.num_shots != INFINITE_CHARGES) @@ -1065,7 +1059,7 @@ void external_activate_trap_shot_at_angle(struct Thing *thing, long a2, struct T TbBool trap_on_bridge(ThingModel trpkind) { struct TrapConfigStats* trapst = &game.conf.trapdoor_conf.trap_cfgstats[trpkind]; - return trapst->placeonbridge; + return trapst->place_on_bridge; } TbBool can_place_trap_on(PlayerNumber plyr_idx, MapSubtlCoord stl_x, MapSubtlCoord stl_y, ThingModel trpkind) @@ -1074,7 +1068,6 @@ TbBool can_place_trap_on(PlayerNumber plyr_idx, MapSubtlCoord stl_x, MapSubtlCoo MapSlabCoord slb_y = subtile_slab(stl_y); struct SlabMap* slb = get_slabmap_block(slb_x, slb_y); struct SlabAttr* slbattr = get_slab_attrs(slb); - struct PlayerInfo* player = get_player(plyr_idx); TbBool HasTrap = true; TbBool HasDoor = true; struct TrapConfigStats* trap_cfg = get_trap_model_stats(trpkind); @@ -1090,7 +1083,7 @@ TbBool can_place_trap_on(PlayerNumber plyr_idx, MapSubtlCoord stl_x, MapSubtlCoo } if ((slabmap_owner(slb) == plyr_idx) && (((slb->kind == SlbT_BRIDGE) && (trap_on_bridge(trpkind))) || (slb->kind == SlbT_CLAIMED) || (slab_is_door(slb_x, slb_y)))) { - if (trap_cfg->placeonsubtile == false) + if (trap_cfg->place_on_subtile == false) { HasTrap = slab_has_trap_on(slb_x, slb_y); HasDoor = slab_is_door(slb_x, slb_y); @@ -1126,6 +1119,102 @@ TbBool can_place_trap_on(PlayerNumber plyr_idx, MapSubtlCoord stl_x, MapSubtlCoo return false; } +void trap_fire_shot_without_target(struct Thing *firing, ThingModel shot_model, char shot_lvl, short angle_xy) +{ + struct Thing* shotng; + struct ComponentVector cvect; + struct ShotConfigStats* shotst = get_shot_model_stats(shot_model); + struct TrapStats* trapstat = &game.conf.trap_stats[firing->model]; + switch (shotst->fire_logic) + { + case ShFL_Beam: + { + struct Coord3d pos2; + long damage; + // Prepare source position + struct Coord3d pos1; + pos1.x.val = firing->mappos.x.val; + pos1.y.val = firing->mappos.y.val; + pos1.z.val = firing->mappos.z.val; + if (shotst->fire_logic == ShFL_Volley) + { + if (!firing->trap.volley_fire) + { + firing->trap.volley_fire = true; + firing->trap.volley_repeat = shotst->effect_amount - 1; // N x shots + (N - 1) x pauses and one shot is this one + firing->trap.volley_delay = shotst->effect_spacing; + firing->trap.firing_at = 0; + } + else + { + firing->trap.volley_delay = shotst->effect_spacing; + if (firing->trap.volley_repeat == 0) + return; + firing->trap.volley_repeat--; + } + } + firing->move_angle_xy = angle_xy; //visually rotates the trap + pos1.x.val += distance_with_angle_to_coord_x(trapstat->shot_shift_x, firing->move_angle_xy + LbFPMath_PI / 2); + pos1.y.val += distance_with_angle_to_coord_y(trapstat->shot_shift_x, firing->move_angle_xy + LbFPMath_PI / 2); + pos1.x.val += distance_with_angle_to_coord_x(trapstat->shot_shift_y, firing->move_angle_xy); + pos1.y.val += distance_with_angle_to_coord_y(trapstat->shot_shift_y, firing->move_angle_xy); + pos1.z.val += trapstat->shot_shift_z; + // Compute launch angles + pos2.x.val = 0; + pos2.y.val = 0; + pos2.z.val = 0; + if (((shotst->model_flags & ShMF_StrengthBased) != 0) && ((shotst->model_flags & ShMF_ReboundImmune) != 0)) + { + pos1.z.val = pos2.z.val; + } + // Compute shot damage + if (shotst->fixed_damage == 0) + { + if ((shotst->model_flags & ShMF_StrengthBased) != 0) + { + damage = calculate_melee_damage(firing); + } + else + { + damage = calculate_shot_damage(firing, shot_model); + } + } + else + { + damage = shotst->damage; + } + if (get_2d_distance(&firing->mappos, &pos2) > shotst->max_range) + { + project_point_to_wall_on_angle(&pos1, &pos2, firing->move_angle_xy, firing->move_angle_z, COORD_PER_STL, shotst->max_range/COORD_PER_STL); + } + shotng = create_shot(&pos2, shot_model, firing->owner); + if (thing_is_invalid(shotng)) + return; + draw_lightning(&pos1, &pos2, shotst->effect_spacing, shotst->effect_id); + shotng->health = shotst->health; + shotng->shot.damage = damage; + shotng->parent_idx = firing->index; + break; + } + default: + shotng = create_shot(&firing->mappos, shot_model, firing->owner); + if (thing_is_invalid(shotng)) { + return; + } + firing->move_angle_xy = angle_xy; //visually rotates the trap + shotst = get_shot_model_stats(shotng->model); + shotng->move_angle_xy = angle_xy; + shotng->move_angle_z = 0; + angles_to_vector(shotng->move_angle_xy, 0, shotst->speed, &cvect); + shotng->veloc_push_add.x.val += cvect.x; + shotng->veloc_push_add.y.val += cvect.y; + shotng->veloc_push_add.z.val += cvect.z; + shotng->state_flags |= TF1_PushAdd; + shotng->shot.hit_type = trapstat->hit_type; + break; + } +} + /******************************************************************************/ #ifdef __cplusplus } diff --git a/src/thing_traps.h b/src/thing_traps.h index 8e24c7ee88..72446dd749 100644 --- a/src/thing_traps.h +++ b/src/thing_traps.h @@ -126,7 +126,8 @@ unsigned long remove_trap(struct Thing *traptng, long *sell_value); unsigned long remove_trap_on_subtile(MapSubtlCoord stl_x, MapSubtlCoord stl_y, long *sell_value); unsigned long remove_traps_around_subtile(MapSubtlCoord stl_x, MapSubtlCoord stl_y, long *sell_value); -void external_activate_trap_shot_at_angle(struct Thing *thing, long a2, struct Thing *hand); +void external_activate_trap_shot_at_angle(struct Thing *thing, short angle, struct Thing *trgtng); +void trap_fire_shot_without_target(struct Thing *firing, ThingModel shot_model, char shot_lvl, short angle_xy); /******************************************************************************/ #ifdef __cplusplus