Skip to content

Commit 7d592d1

Browse files
Ben10Omintrixwraith-54321
authored andcommitted
new wizard ability and basic leaper refactor (#79237)
refactors leapers into basic mobs and adds a new ability for wizards. for 2 points wizards can buy their own leaper pet. they will get a contract which lets them pick their pet's name and color ![thefrogs](https://github.com/tgstation/tgstation/assets/138636438/8df9b893-d07d-4e51-a9fa-644830cc7a81) after they sign the contract they will get a frog statue which is used to contain the leaper. players can use this statue to release or recall the leaper into the statue. when its in the statue it will slowly regain health or even revive from the dead, but if it gets gibbed then the statue will be useless. also adds a new ai behavior for leapers which lets them go swim in water (and splash around) for a period of time. i gave this behavior to frogs and crabs too when riding the leaper, the players will get access to all its abilities, it now has new abilities, it can create frog minions that suicide bomb the enemies and it can also create a shower of poisonous structures. https://github.com/tgstation/tgstation/assets/138636438/931aa7b4-09f0-493f-bdb6-f3bdd0915b22 also when riding the leaper, players can point at walls near it so it will destroy it. alternatively players can give commands to their leapers to use abilities and to follow them if they are not riding it. wizards cant be force dismounted from their frogs, and only wizards can ride the frogs. this also removes leapers from cytology as they now are much more dangerous and have a new home refactors leapers into basic mobs, and gives more gameplay opportunities for wizards :cl: refactor: leapers have been refactored into basic mobs please report any bugs add: wizards can now summon a leaper pet removal: removes leapers from cytology /:cl:
1 parent 711c1f3 commit 7d592d1

File tree

28 files changed

+866
-366
lines changed

28 files changed

+866
-366
lines changed

code/__DEFINES/ai/monsters.dm

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,23 @@
188188
/// the bonfire we will light up
189189
#define BB_MOOK_BONFIRE_TARGET "bonfire_target"
190190

191+
//leaper keys
192+
///key holds our volley ability
193+
#define BB_LEAPER_VOLLEY "leaper_volley"
194+
///key holds our flop ability
195+
#define BB_LEAPER_FLOP "leaper_flop"
196+
///key holds our bubble ability
197+
#define BB_LEAPER_BUBBLE "leaper_bubble"
198+
///key holds our summon ability
199+
#define BB_LEAPER_SUMMON "leaper_summon"
200+
///key holds the world timer for swimming
201+
#define BB_KEY_SWIM_TIME "key_swim_time"
202+
///key holds the water or land target turf
203+
#define BB_SWIM_ALTERNATE_TURF "swim_alternate_turf"
204+
///key holds our state of swimming
205+
#define BB_CURRENTLY_SWIMMING "currently_swimming"
206+
///key holds how long we will be swimming for
207+
#define BB_KEY_SWIMMER_COOLDOWN "key_swimmer_cooldown"
191208
//gutlunch keys
192209
///the trough we will eat from
193210
#define BB_TROUGH_TARGET "trough_target"

code/__DEFINES/is_helpers.dm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ GLOBAL_LIST_INIT(turfs_openspace, typecacheof(list(
6565

6666
#define iscliffturf(A) (istype(A, /turf/open/cliff))
6767

68+
#define iswaterturf(A) (istype(A, /turf/open/water))
69+
6870
//Mobs
6971
#define isliving(A) (istype(A, /mob/living))
7072

code/__DEFINES/research.dm

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
#define CELL_LINE_TABLE_WALKING_MUSHROOM "cell_line_walking_mushroom_table"
5959
#define CELL_LINE_TABLE_QUEEN_BEE "cell_line_bee_queen_table"
6060
#define CELL_LINE_TABLE_BUTTERFLY "cell_line_butterfly_table"
61-
#define CELL_LINE_TABLE_LEAPER "cell_line_leaper_table"
6261
#define CELL_LINE_TABLE_MEGA_ARACHNID "cell_line_table_mega_arachnid"
6362

6463
//! All cell virus types

code/__DEFINES/vehicles.dm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#define UNBUCKLE_DISABLED_RIDER (1<<3)
2727
// For fireman carries, the carrying human needs an arm
2828
#define CARRIER_NEEDS_ARM (1<<4)
29+
// This rider must be our friend
30+
#define JUST_FRIEND_RIDERS (1<<5)
2931

3032
//car_traits flags
3133
///Will this car kidnap people by ramming into them?

code/_globalvars/lists/xenobiology.dm

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,9 @@ GLOBAL_LIST_INIT_TYPED(cell_line_tables, /list, list(
7373
CELL_LINE_TABLE_WALKING_MUSHROOM = list(/datum/micro_organism/cell_line/walking_mushroom = 1),
7474
CELL_LINE_TABLE_QUEEN_BEE = list(/datum/micro_organism/cell_line/queen_bee = 1),
7575
CELL_LINE_TABLE_BUTTERFLY = list(/datum/micro_organism/cell_line/butterfly = 1),
76-
CELL_LINE_TABLE_LEAPER = list(/datum/micro_organism/cell_line/leaper = 1),
7776
CELL_LINE_TABLE_MEGA_ARACHNID = list(/datum/micro_organism/cell_line/mega_arachnid = 1),
7877
CELL_LINE_TABLE_ALGAE = list(
7978
/datum/micro_organism/cell_line/frog = 2,
80-
/datum/micro_organism/cell_line/leaper = 2,
8179
/datum/micro_organism/cell_line/mega_arachnid = 1,
8280
/datum/micro_organism/cell_line/queen_bee = 1,
8381
/datum/micro_organism/cell_line/butterfly = 1,
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#define DEFAULT_TIME_SWIMMER 30 SECONDS
2+
3+
///subtree to go and swim!
4+
/datum/ai_planning_subtree/go_for_swim
5+
6+
/datum/ai_planning_subtree/go_for_swim/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
7+
if(controller.blackboard_key_exists(BB_SWIM_ALTERNATE_TURF))
8+
controller.queue_behavior(/datum/ai_behavior/travel_towards/swimming, BB_SWIM_ALTERNATE_TURF)
9+
10+
if(isnull(controller.blackboard[BB_KEY_SWIM_TIME]))
11+
controller.set_blackboard_key(BB_KEY_SWIM_TIME, DEFAULT_TIME_SWIMMER)
12+
13+
var/mob/living/living_pawn = controller.pawn
14+
var/turf/our_turf = get_turf(living_pawn)
15+
16+
// we have been taken out of water!
17+
controller.set_blackboard_key(BB_CURRENTLY_SWIMMING, iswaterturf(our_turf))
18+
19+
if(controller.blackboard[BB_KEY_SWIM_TIME] < world.time)
20+
controller.queue_behavior(/datum/ai_behavior/find_and_set/swim_alternate, BB_SWIM_ALTERNATE_TURF, /turf/open)
21+
return
22+
23+
// have some fun in the water
24+
if(controller.blackboard[BB_CURRENTLY_SWIMMING] && SPT_PROB(5, seconds_per_tick))
25+
controller.queue_behavior(/datum/ai_behavior/perform_emote, "splashes water all around!")
26+
27+
28+
///find land if its time to get out of water, otherwise find water
29+
/datum/ai_behavior/find_and_set/swim_alternate
30+
31+
/datum/ai_behavior/find_and_set/swim_alternate/search_tactic(datum/ai_controller/controller, locate_path, search_range)
32+
var/mob/living/living_pawn = controller.pawn
33+
if(QDELETED(living_pawn))
34+
return null
35+
var/look_for_land = controller.blackboard[BB_CURRENTLY_SWIMMING]
36+
var/list/possible_turfs = list()
37+
for(var/turf/possible_turf in oview(search_range, living_pawn))
38+
if(isclosedturf(possible_turf) || isspaceturf(possible_turf) || isopenspaceturf(possible_turf))
39+
continue
40+
if(possible_turf.is_blocked_turf())
41+
continue
42+
if(look_for_land == iswaterturf(possible_turf))
43+
continue
44+
possible_turfs += possible_turf
45+
46+
if(!length(possible_turfs))
47+
return null
48+
49+
return(pick(possible_turfs))
50+
51+
/datum/ai_behavior/travel_towards/swimming
52+
clear_target = TRUE
53+
54+
/datum/ai_behavior/travel_towards/swimming/finish_action(datum/ai_controller/controller, succeeded, target_key)
55+
. = ..()
56+
var/time_to_add = controller.blackboard[BB_KEY_SWIMMER_COOLDOWN] ? controller.blackboard[BB_KEY_SWIMMER_COOLDOWN] : DEFAULT_TIME_SWIMMER
57+
controller.set_blackboard_key(BB_KEY_SWIM_TIME, world.time + time_to_add )
58+
59+
#undef DEFAULT_TIME_SWIMMER
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Bombs the user after an attack
3+
*/
4+
/datum/component/explode_on_attack
5+
/// range of bomb impact
6+
var/impact_range
7+
/// should we be destroyed after the explosion?
8+
var/destroy_on_explode
9+
/// list of mobs we wont bomb on attack
10+
var/list/mob_type_dont_bomb
11+
12+
/datum/component/explode_on_attack/Initialize(impact_range = 1, destroy_on_explode = TRUE, list/mob_type_dont_bomb = list())
13+
if(!isliving(parent))
14+
return COMPONENT_INCOMPATIBLE
15+
src.impact_range = impact_range
16+
src.destroy_on_explode = destroy_on_explode
17+
src.mob_type_dont_bomb = mob_type_dont_bomb
18+
19+
/datum/component/explode_on_attack/RegisterWithParent()
20+
RegisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(bomb_target))
21+
22+
/datum/component/explode_on_attack/UnregisterFromParent()
23+
UnregisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)
24+
25+
26+
/datum/component/explode_on_attack/proc/bomb_target(mob/living/owner, atom/victim)
27+
SIGNAL_HANDLER
28+
29+
if(!isliving(victim))
30+
return
31+
32+
if(is_type_in_typecache(victim, mob_type_dont_bomb))
33+
return
34+
35+
explosion(owner, light_impact_range = impact_range, explosion_cause = src)
36+
37+
if(destroy_on_explode && owner)
38+
qdel(owner)
39+
return COMPONENT_HOSTILE_NO_ATTACK
40+

code/datums/components/pet_commands/pet_commands_basic.dm

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,22 @@
9797
parent.emote("spin")
9898
return SUBTREE_RETURN_FINISH_PLANNING
9999

100+
/**
101+
* # Pet Command: Use ability
102+
* Use an an ability that does not require any targets
103+
*/
104+
/datum/pet_command/untargetted_ability
105+
///untargetted ability we will use
106+
var/ability_key
107+
108+
/datum/pet_command/untargetted_ability/execute_action(datum/ai_controller/controller)
109+
var/datum/action/cooldown/ability = controller.blackboard[ability_key]
110+
if(!ability?.IsAvailable())
111+
return
112+
controller.queue_behavior(/datum/ai_behavior/use_mob_ability, ability_key)
113+
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
114+
return SUBTREE_RETURN_FINISH_PLANNING
115+
100116
/**
101117
* # Pet Command: Attack
102118
* Tells a pet to chase and bite the next thing you point at

code/datums/components/riding/riding.dm

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,16 @@
2626
var/list/directional_vehicle_layers = list()
2727
/// same as above but instead of layer you have a list(px, py)
2828
var/list/directional_vehicle_offsets = list()
29+
/// planes of the rider
30+
var/list/directional_rider_planes = list()
2931
/// allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence.
3032
var/list/allowed_turf_typecache
3133
/// allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence.
3234
var/list/forbid_turf_typecache
3335
/// We don't need roads where we're going if this is TRUE, allow normal movement in space tiles
3436
var/override_allow_spacemove = FALSE
37+
/// can anyone other than the rider unbuckle the rider?
38+
var/can_force_unbuckle = TRUE
3539

3640
/**
3741
* Ride check flags defined for the specific riding component types, so we know if we need arms, legs, or whatever.
@@ -55,7 +59,6 @@
5559
if(potion_boost)
5660
vehicle_move_delay = round(CONFIG_GET(number/movedelay/run_delay) * 0.85, 0.01)
5761

58-
5962
/datum/component/riding/RegisterWithParent()
6063
. = ..()
6164
RegisterSignal(parent, COMSIG_ATOM_DIR_CHANGE, PROC_REF(vehicle_turned))
@@ -66,7 +69,8 @@
6669
RegisterSignal(parent, COMSIG_BUCKLED_CAN_Z_MOVE, PROC_REF(riding_can_z_move))
6770
RegisterSignals(parent, GLOB.movement_type_addtrait_signals, PROC_REF(on_movement_type_trait_gain))
6871
RegisterSignals(parent, GLOB.movement_type_removetrait_signals, PROC_REF(on_movement_type_trait_loss))
69-
72+
if(!can_force_unbuckle)
73+
RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(force_unbuckle))
7074
/**
7175
* This proc handles all of the proc calls to things like set_vehicle_dir_layer() that a type of riding datum needs to call on creation
7276
*
@@ -81,6 +85,9 @@
8185
/datum/component/riding/proc/vehicle_mob_unbuckle(datum/source, mob/living/rider, force = FALSE)
8286
SIGNAL_HANDLER
8387

88+
handle_unbuckle(rider)
89+
90+
/datum/component/riding/proc/handle_unbuckle(mob/living/rider)
8491
var/atom/movable/movable_parent = parent
8592
restore_position(rider)
8693
unequip_buckle_inhands(rider)
@@ -100,6 +107,7 @@
100107
var/atom/movable/movable_parent = parent
101108
handle_vehicle_layer(movable_parent.dir)
102109
handle_vehicle_offsets(movable_parent.dir)
110+
handle_rider_plane(movable_parent.dir)
103111

104112
if(rider.pulling == source)
105113
rider.stop_pulling()
@@ -129,9 +137,20 @@
129137
. = AM.layer
130138
AM.layer = .
131139

140+
/datum/component/riding/proc/handle_rider_plane(dir)
141+
var/atom/movable/movable_parent = parent
142+
var/target_plane = directional_rider_planes["[dir]"]
143+
if(isnull(target_plane))
144+
return
145+
for(var/mob/buckled_mob in movable_parent.buckled_mobs)
146+
SET_PLANE_EXPLICIT(buckled_mob, target_plane, movable_parent)
147+
132148
/datum/component/riding/proc/set_vehicle_dir_layer(dir, layer)
133149
directional_vehicle_layers["[dir]"] = layer
134150

151+
/datum/component/riding/proc/set_rider_dir_plane(dir, plane)
152+
directional_rider_planes["[dir]"] = plane
153+
135154
/// This is called after the ridden atom is successfully moved and is used to handle icon stuff
136155
/datum/component/riding/proc/vehicle_moved(datum/source, oldloc, dir, forced)
137156
SIGNAL_HANDLER
@@ -146,6 +165,7 @@
146165
return // runtimed with piggy's without this, look into this more
147166
handle_vehicle_offsets(dir)
148167
handle_vehicle_layer(dir)
168+
handle_rider_plane(dir)
149169

150170
/// Turning is like moving
151171
/datum/component/riding/proc/vehicle_turned(datum/source, _old_dir, new_dir)
@@ -233,11 +253,14 @@
233253

234254
//BUCKLE HOOKS
235255
/datum/component/riding/proc/restore_position(mob/living/buckled_mob)
236-
if(buckled_mob)
237-
buckled_mob.pixel_x = buckled_mob.base_pixel_x
238-
buckled_mob.pixel_y = buckled_mob.base_pixel_y
239-
if(buckled_mob.client)
240-
buckled_mob.client.view_size.resetToDefault()
256+
if(isnull(buckled_mob))
257+
return
258+
buckled_mob.pixel_x = buckled_mob.base_pixel_x
259+
buckled_mob.pixel_y = buckled_mob.base_pixel_y
260+
var/atom/source = parent
261+
SET_PLANE_EXPLICIT(buckled_mob, initial(buckled_mob.plane), source)
262+
if(buckled_mob.client)
263+
buckled_mob.client.view_size.resetToDefault()
241264

242265
//MOVEMENT
243266
/datum/component/riding/proc/turf_check(turf/next, turf/current)
@@ -285,6 +308,13 @@
285308
SIGNAL_HANDLER
286309
return COMPONENT_RIDDEN_ALLOW_Z_MOVE
287310

311+
/datum/component/riding/proc/force_unbuckle(atom/movable/source, mob/living/living_hitter)
312+
SIGNAL_HANDLER
313+
314+
if((living_hitter in source.buckled_mobs))
315+
return
316+
return COMPONENT_CANCEL_ATTACK_CHAIN
317+
288318
/// Called when our vehicle gains a movement trait, so we can apply it to the riders
289319
/datum/component/riding/proc/on_movement_type_trait_gain(atom/movable/source, trait)
290320
SIGNAL_HANDLER

code/datums/components/riding/riding_mob.dm

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
var/can_be_driven = TRUE
66
/// If TRUE, this creature's abilities can be triggered by the rider while mounted
77
var/can_use_abilities = FALSE
8-
var/list/shared_action_buttons = list()
8+
/// list of blacklisted abilities that cant be shared
9+
var/list/blacklist_abilities = list()
910

1011
/datum/component/riding/creature/Initialize(mob/living/riding_mob, force = FALSE, ride_check_flags = NONE, potion_boost = FALSE)
1112
if(!isliving(parent))
@@ -60,6 +61,8 @@
6061
// for fireman carries, check if the ridden is stunned/restrained
6162
else if((ride_check_flags & CARRIER_NEEDS_ARM) && (HAS_TRAIT(living_parent, TRAIT_RESTRAINED) || living_parent.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB)))
6263
. = FALSE
64+
else if((ride_check_flags & JUST_FRIEND_RIDERS) && !(living_parent.faction.Find(REF(rider))))
65+
. = FALSE
6366

6467
if(. || !consequences)
6568
return
@@ -153,6 +156,7 @@
153156
for(var/mob/yeet_mob in user.buckled_mobs)
154157
force_dismount(yeet_mob, (!(user.istate & ISTATE_HARM))) // gentle on help, byeeee if not
155158

159+
156160
/// If the ridden creature has abilities, and some var yet to be made is set to TRUE, the rider will be able to control those abilities
157161
/datum/component/riding/creature/proc/setup_abilities(mob/living/rider)
158162
if(!isliving(parent))
@@ -161,6 +165,8 @@
161165
var/mob/living/ridden_creature = parent
162166

163167
for(var/datum/action/action as anything in ridden_creature.actions)
168+
if(is_type_in_list(action, blacklist_abilities))
169+
continue
164170
action.GiveAction(rider)
165171

166172
/// Takes away the riding parent's abilities from the rider
@@ -454,3 +460,35 @@
454460
set_vehicle_dir_layer(NORTH, OBJ_LAYER)
455461
set_vehicle_dir_layer(EAST, OBJ_LAYER)
456462
set_vehicle_dir_layer(WEST, OBJ_LAYER)
463+
464+
/datum/component/riding/creature/leaper
465+
can_force_unbuckle = FALSE
466+
can_use_abilities = TRUE
467+
blacklist_abilities = list(/datum/action/cooldown/toggle_seethrough)
468+
ride_check_flags = JUST_FRIEND_RIDERS
469+
470+
/datum/component/riding/creature/leaper/handle_specials()
471+
. = ..()
472+
set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(17, 46), TEXT_SOUTH = list(17,51), TEXT_EAST = list(27, 46), TEXT_WEST = list(6, 46)))
473+
set_rider_dir_plane(SOUTH, GAME_PLANE_UPPER)
474+
set_rider_dir_plane(NORTH, GAME_PLANE)
475+
set_rider_dir_plane(EAST, GAME_PLANE_UPPER)
476+
set_rider_dir_plane(WEST, GAME_PLANE_UPPER)
477+
478+
/datum/component/riding/creature/leaper/Initialize(mob/living/riding_mob, force = FALSE, ride_check_flags = NONE, potion_boost = FALSE)
479+
. = ..()
480+
RegisterSignal(riding_mob, COMSIG_MOB_POINTED, PROC_REF(attack_pointed))
481+
482+
/datum/component/riding/creature/leaper/proc/attack_pointed(mob/living/rider, atom/pointed)
483+
SIGNAL_HANDLER
484+
if(!isclosedturf(pointed))
485+
return
486+
var/mob/living/basic/basic_parent = parent
487+
if(!basic_parent.CanReach(pointed))
488+
return
489+
basic_parent.melee_attack(pointed)
490+
491+
492+
/datum/component/riding/leaper/handle_unbuckle(mob/living/rider)
493+
. = ..()
494+
UnregisterSignal(rider, COMSIG_MOB_POINTED)

0 commit comments

Comments
 (0)