mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-23 20:16:55 +01:00
Adds Kidan Ship Ruin (#32081)
* Kidan Warriors * Linters * Kidan mob AI adjustments and stat adjustments. Kidan Princess Megafauna * Bug spray vulnerability * Ragnarok props and kidan spear update * The ship * Fixes and adjustments * Map update * Linters
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
#define KIDAN_THRONEROOM "KIDAN_THRONEROOM"
|
||||
|
||||
/mob/living/basic/kidan_warrior
|
||||
name = "Kidan Warrior"
|
||||
desc = "A bulky insect-man wielding a large spear."
|
||||
icon = 'icons/mob/simple_human.dmi'
|
||||
icon_state = "kidan_warrior"
|
||||
icon_living = "kidan_warrior"
|
||||
icon_dead = "kidan_warrior_dead" // Does not actually exist. Dust on death
|
||||
mob_biotypes = MOB_ORGANIC | MOB_HUMANOID | MOB_BUG
|
||||
death_sound = 'sound/voice/scream_kidan.ogg'
|
||||
response_help_continuous = "pushes the"
|
||||
response_help_continuous = "push the"
|
||||
response_harm_continuous = "attacks"
|
||||
response_harm_simple = "attack"
|
||||
speed = 0
|
||||
harm_intent_damage = 5
|
||||
obj_damage = 40
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 20
|
||||
melee_attack_cooldown_min = 1 SECONDS
|
||||
attack_verb_continuous = "stabs"
|
||||
attack_verb_simple = "stab"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
is_ranged = TRUE
|
||||
projectile_type = /obj/projectile/bullet/reusable/magspear
|
||||
projectile_sound = 'sound/weapons/grenadelaunch.ogg'
|
||||
ranged_cooldown = 1 SECONDS
|
||||
a_intent = INTENT_HARM
|
||||
damage_coeff = list(BRUTE = 0.8, BURN = 1, TOX = 1.5, STAMINA = 0, OXY = 1)
|
||||
minimum_survivable_temperature = 0
|
||||
ai_controller = /datum/ai_controller/basic_controller/simple/kidan_warrior
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
speak_emote = list("clacks")
|
||||
blood_color = "#FB9800"
|
||||
loot = list(
|
||||
/obj/effect/decal/remains/human,
|
||||
/obj/effect/decal/cleanable/ash)
|
||||
faction = list("kidan_royalty")
|
||||
basic_mob_flags = DEL_ON_DEATH
|
||||
sentience_type = SENTIENCE_OTHER
|
||||
step_type = FOOTSTEP_MOB_SHOE
|
||||
|
||||
/mob/living/basic/kidan_warrior/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/aggro_emote, aggro_sound = 'sound/effects/Kidanclack.ogg', emote_chance = 100)
|
||||
add_language("Galactic Common")
|
||||
add_language("Chittin")
|
||||
set_default_language(GLOB.all_languages["Chittin"])
|
||||
AddComponent(/datum/component/ai_retaliate_advanced, CALLBACK(src, PROC_REF(retaliate_callback)))
|
||||
var/datum/language/lang = GLOB.all_languages["Chittin"]
|
||||
name = lang.get_random_name(gender)
|
||||
real_name = name
|
||||
if(prob(25))
|
||||
loot = list(
|
||||
/obj/effect/decal/remains/human,
|
||||
/obj/effect/decal/cleanable/ash,
|
||||
/obj/item/kidan_spear)
|
||||
|
||||
/mob/living/basic/kidan_warrior/proc/retaliate_callback(mob/living/attacker)
|
||||
if(!istype(attacker))
|
||||
return
|
||||
GLOB.kidan_shitlist += attacker
|
||||
|
||||
/mob/living/basic/kidan_warrior/ruin/death(gibbed)
|
||||
GLOB.ragnarok_kill_count += 1
|
||||
if(GLOB.ragnarok_kill_count >= 10)
|
||||
unlock_blast_doors(KIDAN_THRONEROOM)
|
||||
src.visible_message(SPAN_NOTICE("Somewhere, a heavy door has opened."))
|
||||
return ..(gibbed)
|
||||
|
||||
/mob/living/basic/kidan_warrior/ruin/proc/unlock_blast_doors(target_id_tag)
|
||||
for(var/obj/machinery/door/poddoor/P in GLOB.airlocks)
|
||||
if(P.density && P.id_tag == target_id_tag && P.z == z && !P.operating)
|
||||
P.open()
|
||||
|
||||
/datum/ai_controller/basic_controller/simple/kidan_warrior
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/kidan_warrior,
|
||||
BB_AGGRO_RANGE = 9,
|
||||
BB_SEARCH_RANGE = 10,
|
||||
BB_TARGET_MINIMUM_STAT = UNCONSCIOUS,
|
||||
)
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/ranged_skirmish/avoid_friendly,
|
||||
/datum/ai_planning_subtree/attack_obstacle_in_path,
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree,
|
||||
)
|
||||
ai_movement = /datum/ai_movement/jps
|
||||
max_target_distance = 15
|
||||
|
||||
/datum/targeting_strategy/basic/kidan_warrior
|
||||
|
||||
/datum/targeting_strategy/basic/kidan_warrior/can_attack(mob/living/living_mob, atom/the_target, vision_range)
|
||||
. = ..()
|
||||
if(!isliving(the_target))
|
||||
return .
|
||||
if(the_target in GLOB.kidan_shitlist)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/basic/kidan_warrior/throneguard
|
||||
name = "Kidan Throneguard"
|
||||
desc = "The loyal guards of Kidan nobility."
|
||||
icon_state = "kidan_throneguard"
|
||||
icon_living = "kidan_throneguard"
|
||||
damage_coeff = list(BRUTE = 0.6, BURN = 0.8, TOX = 1.5, STAMINA = 0, OXY = 1)
|
||||
melee_damage_lower = 25
|
||||
melee_damage_upper = 35
|
||||
ai_controller = /datum/ai_controller/basic_controller/simple/kidan_warrior/throneguard
|
||||
|
||||
/datum/ai_controller/basic_controller/simple/kidan_warrior/throneguard
|
||||
idle_behavior = null
|
||||
|
||||
/mob/living/basic/kidan_servant
|
||||
name = "Kidan Servant"
|
||||
desc = "A kidan who works in service of their nobility."
|
||||
icon = 'icons/mob/simple_human.dmi'
|
||||
icon_state = "kidan_servant"
|
||||
icon_living = "kidan_servant"
|
||||
icon_dead = "kidan_servant_dead" // Does not actually exist. Dust on death
|
||||
mob_biotypes = MOB_ORGANIC | MOB_HUMANOID | MOB_BUG
|
||||
death_sound = 'sound/voice/scream_kidan.ogg'
|
||||
response_help_continuous = "pushes the"
|
||||
response_help_continuous = "push the"
|
||||
response_harm_continuous = "attacks"
|
||||
response_harm_simple = "attack"
|
||||
speed = 0
|
||||
harm_intent_damage = 5
|
||||
obj_damage = 10
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 10
|
||||
melee_attack_cooldown_min = 1 SECONDS
|
||||
attack_verb_continuous = "punches"
|
||||
attack_verb_simple = "punch"
|
||||
damage_coeff = list(BRUTE = 0.8, BURN = 1, TOX = 1.5, STAMINA = 0, OXY = 1)
|
||||
minimum_survivable_temperature = 0
|
||||
ai_controller = /datum/ai_controller/basic_controller/kidan_servant
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
speak_emote = list("clacks")
|
||||
blood_color = "#FB9800"
|
||||
loot = list(
|
||||
/obj/effect/decal/remains/human,
|
||||
/obj/effect/decal/cleanable/ash)
|
||||
faction = list("kidan_royalty")
|
||||
basic_mob_flags = DEL_ON_DEATH
|
||||
sentience_type = SENTIENCE_OTHER
|
||||
step_type = FOOTSTEP_MOB_SHOE
|
||||
|
||||
/mob/living/basic/kidan_servant/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/aggro_emote, aggro_sound = 'sound/voice/scream_kidan.ogg', emote_chance = 100)
|
||||
add_language("Galactic Common")
|
||||
add_language("Chittin")
|
||||
set_default_language(GLOB.all_languages["Chittin"])
|
||||
AddComponent(/datum/component/ai_retaliate_advanced, CALLBACK(src, PROC_REF(retaliate_callback)))
|
||||
var/datum/language/lang = GLOB.all_languages["Chittin"]
|
||||
name = lang.get_random_name(gender)
|
||||
real_name = name
|
||||
var/bonus_loot_type = rand(1, 5)
|
||||
switch(bonus_loot_type)
|
||||
if(1)
|
||||
loot += /obj/item/clothing/neck/necklace/long
|
||||
if(2)
|
||||
loot += /obj/item/stack/sheet/mineral/gold
|
||||
if(3)
|
||||
loot += pick(list(/obj/item/reagent_containers/drinks/bottle/wine, /obj/item/reagent_containers/drinks/bottle/white_wine, /obj/item/reagent_containers/drinks/bottle/goldschlager))
|
||||
if(4)
|
||||
for(var/i in 1 to 9)
|
||||
loot += /obj/item/coin/gold
|
||||
if(5)
|
||||
loot += /obj/item/food/beary_pie
|
||||
|
||||
/mob/living/basic/kidan_servant/proc/retaliate_callback(mob/living/attacker)
|
||||
if(!istype(attacker))
|
||||
return
|
||||
GLOB.kidan_shitlist += attacker
|
||||
|
||||
/mob/living/basic/kidan_servant/ruin/death(gibbed)
|
||||
GLOB.ragnarok_kill_count -= 1
|
||||
return ..(gibbed)
|
||||
|
||||
/datum/ai_controller/basic_controller/kidan_servant
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/kidan_warrior,
|
||||
BB_AGGRO_RANGE = 9,
|
||||
BB_SEARCH_RANGE = 10,
|
||||
)
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree/opportunistic,
|
||||
/datum/ai_planning_subtree/flee_target,
|
||||
)
|
||||
ai_movement = /datum/ai_movement/jps
|
||||
max_target_distance = 15
|
||||
|
||||
#undef KIDAN_THRONEROOM
|
||||
@@ -0,0 +1,169 @@
|
||||
#define KIDAN_BOSS_STORAGE "KIDAN_BOSS_STORAGE"
|
||||
|
||||
/mob/living/basic/megafauna/kidan_princess
|
||||
name = "Princess Zrexx"
|
||||
desc = "One of the claimants to the throne of the shattered Kidan empire, Princess Zrexx is one of the more extreme in keeping loyal to the ways of old."
|
||||
health = 1500
|
||||
maxHealth = 1500
|
||||
gender = FEMALE
|
||||
icon = 'icons/mob/simple_human.dmi'
|
||||
icon_state = "kidan_princess"
|
||||
icon_living = "kidan_princess"
|
||||
mob_biotypes = MOB_ORGANIC | MOB_HUMANOID | MOB_BUG | MOB_EPIC
|
||||
speak_emote = list("clacks")
|
||||
death_sound = 'sound/voice/scream_kidan.ogg'
|
||||
melee_attack_cooldown_min = 0.75 SECONDS
|
||||
damage_coeff = list(BRUTE = 0.7, BURN = 0.9, TOX = 1.5, STAMINA = 0, OXY = 1)
|
||||
melee_damage_lower = 30
|
||||
melee_damage_upper = 40
|
||||
obj_damage = 80
|
||||
attack_verb_simple = "stab"
|
||||
attack_verb_continuous = "stabs"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
response_help_continuous = "hugs"
|
||||
response_help_continuous = "hug"
|
||||
response_harm_continuous = "attacks"
|
||||
response_harm_simple = "attack"
|
||||
move_force = MOVE_FORCE_NORMAL
|
||||
see_in_dark = 20 // I see you
|
||||
step_type = FOOTSTEP_MOB_SHOE
|
||||
initial_traits = list(TRAIT_NOFIRE)
|
||||
blood_color = "#FB9800"
|
||||
loot = list(
|
||||
/obj/item/kidan_princess_halberd,
|
||||
/obj/effect/decal/remains/human,
|
||||
/obj/effect/decal/cleanable/ash)
|
||||
enraged_loot = /obj/item/clothing/accessory/medal/plasma/princess
|
||||
faction = list("kidan_royalty")
|
||||
ai_controller = /datum/ai_controller/basic_controller/kidan_princess
|
||||
internal_gps = /obj/item/gps/internal/kidan_princess
|
||||
medal_type = BOSS_MEDAL_PRINCESS
|
||||
score_type = PRINCESS_SCORE
|
||||
basic_mob_flags = DEL_ON_DEATH
|
||||
sentience_type = SENTIENCE_OTHER
|
||||
step_type = FOOTSTEP_MOB_SHOE
|
||||
innate_actions = list(
|
||||
/datum/action/cooldown/mob_cooldown/kidan_princess/summon_mobs = BB_KIDAN_PRINCESS_SUMMON_MOBS_ACTION,
|
||||
/datum/action/cooldown/mob_cooldown/kidan_princess/charge = BB_KIDAN_PRINCESS_CHARGE_ACTION,
|
||||
/datum/action/cooldown/mob_cooldown/kidan_princess/stomp = BB_KIDAN_PRINCESS_STOMP_ACTION,
|
||||
/datum/action/cooldown/mob_cooldown/kidan_princess/martial_rush = BB_KIDAN_PRINCESS_RUSH_ACTION)
|
||||
/// Is our martial rush active
|
||||
var/martial_rushing = FALSE
|
||||
/// Is this mob associated with a ruin
|
||||
var/ruin_boss = FALSE
|
||||
|
||||
/obj/item/gps/internal/kidan_princess
|
||||
icon_state = null
|
||||
gpstag = "Royal Invitation"
|
||||
desc = "You've been invited aboard the Ragnarok. Will you accept?"
|
||||
|
||||
/mob/living/basic/megafauna/kidan_princess/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/aggro_emote, aggro_sound = 'sound/effects/Kidanclack.ogg', emote_chance = 100, say_list = list("You seek to challenge me? Very well! Show me your strength!"))
|
||||
add_language("Galactic Common")
|
||||
add_language("Chittin")
|
||||
set_default_language(GLOB.all_languages["Galactic Common"])
|
||||
AddComponent(/datum/component/ai_retaliate_advanced, CALLBACK(src, PROC_REF(retaliate_callback)))
|
||||
|
||||
/mob/living/basic/megafauna/kidan_princess/update_icon_state()
|
||||
. = ..()
|
||||
if(martial_rushing)
|
||||
icon_state = "kidan_princess_unarmed"
|
||||
icon_living = "kidan_princess_unarmed"
|
||||
return
|
||||
icon_state = "kidan_princess"
|
||||
icon_living = "kidan_princess"
|
||||
|
||||
/mob/living/basic/megafauna/kidan_princess/Process_Spacemove(movement_dir, continuous_move)
|
||||
return TRUE
|
||||
|
||||
/mob/living/basic/megafauna/kidan_princess/melee_attack(atom/target, list/modifiers, ignore_cooldown)
|
||||
. = ..()
|
||||
if(ismob(target) && martial_rushing)
|
||||
var/mob/victim = target
|
||||
var/atom/throw_target = get_edge_target_turf(target, get_dir(src, get_step_away(target, src)))
|
||||
victim.throw_at(throw_target, 1, 2)
|
||||
|
||||
/mob/living/basic/megafauna/kidan_princess/proc/retaliate_callback(mob/living/attacker)
|
||||
if(!istype(attacker))
|
||||
return
|
||||
GLOB.kidan_shitlist += attacker
|
||||
ai_controller.set_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET, attacker)
|
||||
if(!prob(10))
|
||||
return
|
||||
var/taunt = pick(list(
|
||||
"Is that all you can do?",
|
||||
"Yes, show me more!",
|
||||
"Show me your power!",
|
||||
"My blood spilled, bravo! Bravo!",
|
||||
"That one actually hurt a bit! Haha!",
|
||||
"Come then, strike again!",
|
||||
"Not enough! More effort! More!",
|
||||
"If I am to be a queen, then I must grow stronger!",
|
||||
"Strike me down! Prove yourself strong, so that I may grow ever stronger!",
|
||||
"Fight me!",
|
||||
"Are you worthy, or are you going to hide?",
|
||||
"Show some guts and hit me again!",
|
||||
"We fight like the ways of old! This is wonderful!"
|
||||
))
|
||||
say(taunt)
|
||||
|
||||
/mob/living/basic/megafauna/kidan_princess/devour(mob/living/L)
|
||||
if(!L)
|
||||
return FALSE
|
||||
visible_message(
|
||||
"<span class='danger'>[src] brings down her halberd, obliterating [L] with a heavy blow!</span>",
|
||||
"<span class='userdanger'>You bring down your halberd, obliterating [L] with a heavy blow!</span>")
|
||||
playsound(loc, 'sound/effects/supermatter.ogg', 50, TRUE)
|
||||
L.dust()
|
||||
return TRUE
|
||||
|
||||
/mob/living/basic/megafauna/kidan_princess/death(gibbed)
|
||||
if(can_die() && ruin_boss)
|
||||
unlock_blast_doors(KIDAN_BOSS_STORAGE)
|
||||
src.visible_message(SPAN_NOTICE("Somewhere, a heavy door has opened."))
|
||||
return ..(gibbed)
|
||||
|
||||
/mob/living/basic/megafauna/kidan_princess/proc/unlock_blast_doors(target_id_tag)
|
||||
for(var/obj/machinery/door/poddoor/P in GLOB.airlocks)
|
||||
if(P.density && P.id_tag == target_id_tag && P.z == z && !P.operating)
|
||||
P.open()
|
||||
|
||||
/mob/living/basic/megafauna/kidan_princess/ruin
|
||||
ruin_boss = TRUE
|
||||
|
||||
/mob/living/basic/megafauna/kidan_princess/enrage()
|
||||
. = ..()
|
||||
say("You DARE sully my form with such filth?!")
|
||||
melee_attack_cooldown_max = 1.25 SECONDS
|
||||
|
||||
/// Special Halberd loot
|
||||
/obj/item/kidan_princess_halberd
|
||||
name = "Zrexx's modified supermatter halberd"
|
||||
desc = "The personal weapon of the kidan princess Zrexx. Damaged in the fight, it no longer can dust, but the edge remains incredibly sharp."
|
||||
lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons_righthand.dmi'
|
||||
icon = 'icons/obj/weapons/magical_weapons.dmi'
|
||||
icon_state = "smhalberd0"
|
||||
base_icon_state = "smhalberd"
|
||||
force = 5
|
||||
sharp = TRUE
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
throwforce = 15
|
||||
toolspeed = 0.25
|
||||
attack_verb = list("cleaved", "stabbed", "whacked", "slashed", "stabbed")
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
resistance_flags = FIRE_PROOF
|
||||
|
||||
/obj/item/kidan_princess_halberd/Initialize(mapload)
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_SUPERMATTER_IMMUNE, ROUNDSTART_TRAIT) // so it can't be dusted by the SM
|
||||
AddComponent(/datum/component/forces_doors_open)
|
||||
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.25, _parryable_attack_types = ALL_ATTACK_TYPES, _parry_cooldown = (4 / 3) SECONDS, _requires_two_hands = TRUE) // 0.3333 seconds of cooldown for 75% uptime
|
||||
AddComponent(/datum/component/two_handed, force_wielded = 30, force_unwielded = force, icon_wielded = "[base_icon_state]1")
|
||||
|
||||
/obj/item/kidan_princess_halberd/update_icon_state()
|
||||
icon_state = "[base_icon_state]0"
|
||||
|
||||
#undef KIDAN_BOSS_STORAGE
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
/datum/action/cooldown/mob_cooldown/kidan_princess/summon_mobs
|
||||
name = "Summon Throneguards"
|
||||
button_icon = 'icons/mob/actions/actions_cult.dmi'
|
||||
button_icon_state = "telerune"
|
||||
desc = "Summon a pair of throneguards to protect you."
|
||||
click_to_activate = FALSE
|
||||
melee_cooldown_time = CLICK_CD_CLICK_ABILITY
|
||||
cooldown_time = 90 SECONDS
|
||||
shared_cooldown = NONE
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/kidan_princess/summon_mobs/Activate(atom/target)
|
||||
var/mob/living/basic/megafauna/kidan_princess/summoner = owner
|
||||
if(!istype(summoner))
|
||||
to_chat(owner, "<span class='warning'>I am unable to summon servants!</span>")
|
||||
return
|
||||
|
||||
var/list/all_possible_dirs = GLOB.alldirs
|
||||
for(var/i in 1 to 2)
|
||||
var/mob/living/new_mob
|
||||
var/spawn_loc = get_step(summoner, pick_n_take(all_possible_dirs))
|
||||
new_mob = new /mob/living/basic/kidan_warrior/throneguard(spawn_loc)
|
||||
do_sparks(3, TRUE, new_mob)
|
||||
summoner.say("Guards! To me!")
|
||||
StartCooldown()
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/kidan_princess/charge
|
||||
name = "Royal Charge"
|
||||
desc = "Charge forward into the fray!"
|
||||
button_icon_state = "OH_YEAAAAH"
|
||||
melee_cooldown_time = CLICK_CD_CLICK_ABILITY
|
||||
cooldown_time = 20 SECONDS
|
||||
shared_cooldown = NONE
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/kidan_princess/charge/Activate(atom/target)
|
||||
. = ..()
|
||||
var/dir_to_target = get_dir(get_turf(owner), get_turf(target))
|
||||
var/turf/T = get_step(get_turf(owner), dir_to_target)
|
||||
for(var/i in 1 to 9)
|
||||
new /obj/effect/temp_visual/dragon_swoop/space_whale(T)
|
||||
T = get_step(T, dir_to_target)
|
||||
if(ismineralturf(T))
|
||||
break
|
||||
if(iswallturf(T))
|
||||
break
|
||||
for(var/obj/structure/window/W in T.contents)
|
||||
break
|
||||
for(var/obj/machinery/door/D in T.contents)
|
||||
break
|
||||
owner.visible_message("<span class='danger'>[owner] prepares to charge!</span>")
|
||||
addtimer(CALLBACK(src, PROC_REF(charge_to), dir_to_target, 0), 0.3 SECONDS)
|
||||
StartCooldown()
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/kidan_princess/charge/proc/charge_to(move_dir, times_ran, list/hit_targets)
|
||||
if(times_ran >= 9)
|
||||
return
|
||||
var/turf/T = get_step(get_turf(owner), move_dir)
|
||||
if(ismineralturf(T))
|
||||
return
|
||||
if(iswallturf(T))
|
||||
return
|
||||
for(var/obj/structure/window/W in T.contents)
|
||||
return
|
||||
for(var/obj/machinery/door/D in T.contents)
|
||||
return
|
||||
if(T.x > world.maxx - 2 || T.x < 2) // Keep them from runtiming
|
||||
return
|
||||
if(T.y > world.maxy - 2 || T.y < 2)
|
||||
return
|
||||
owner.forceMove(T)
|
||||
playsound(owner, 'sound/effects/bang.ogg', 200, 1)
|
||||
var/throwtarget = get_edge_target_turf(owner, move_dir)
|
||||
for(var/mob/living/L in T.contents - owner)
|
||||
if(owner.faction_check_mob(L))
|
||||
continue
|
||||
owner.visible_message("<span class='danger'>[owner] slams into [L]!</span>")
|
||||
to_chat(L, "<span class='userdanger'>[owner] charges into you and smashes you away!</span>")
|
||||
L.throw_at(throwtarget, 10, 1, owner)
|
||||
L.Weaken(1 SECONDS) // Pain Train has no breaks.
|
||||
if(L in hit_targets)
|
||||
L.adjustBruteLoss(15)
|
||||
else
|
||||
hit_targets += L
|
||||
L.adjustBruteLoss(25)
|
||||
addtimer(CALLBACK(src, PROC_REF(charge_to), move_dir, (times_ran + 1), hit_targets), 0.7)
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/kidan_princess/stomp
|
||||
name = "Shockwave"
|
||||
desc = "You slam your foot into the ground sending a powerful shockwave through the station's hull, sending people flying away."
|
||||
button_icon_state = "seismic_stomp"
|
||||
click_to_activate = FALSE
|
||||
melee_cooldown_time = CLICK_CD_CLICK_ABILITY
|
||||
cooldown_time = 40 SECONDS
|
||||
shared_cooldown = NONE
|
||||
var/max_range = 8
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/kidan_princess/stomp/Activate(atom/target)
|
||||
var/mob/living/basic/megafauna/kidan_princess/princess = owner
|
||||
var/turf/T = get_turf(princess)
|
||||
playsound(T, 'sound/effects/meteorimpact.ogg', 100, TRUE)
|
||||
playsound(T, 'sound/magic/invoke_general.ogg', 300, TRUE, 5)
|
||||
princess.say("Kneel!")
|
||||
addtimer(CALLBACK(src, PROC_REF(hit_check), 1, T, princess), 0.2 SECONDS)
|
||||
new /obj/effect/temp_visual/stomp(T)
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/kidan_princess/stomp/proc/hit_check(range, turf/start_turf, mob/user, safe_targets = list())
|
||||
// gets the two outermost turfs in a ring, we get two so people cannot "walk over" the shockwave
|
||||
var/list/targets = view(range, start_turf) - view(range - 2, start_turf)
|
||||
for(var/turf/simulated/floor/flooring in targets)
|
||||
if(prob(100 - (range * 20)))
|
||||
flooring.ex_act(EXPLODE_LIGHT)
|
||||
|
||||
for(var/mob/living/L in targets)
|
||||
if(istype(L, /mob/living/basic/kidan_warrior))
|
||||
continue
|
||||
if(L in safe_targets)
|
||||
continue
|
||||
if(L.throwing) // no double hits
|
||||
continue
|
||||
if(L.move_resist > MOVE_FORCE_VERY_STRONG)
|
||||
continue
|
||||
var/throw_target = get_edge_target_turf(L, get_dir(start_turf, L))
|
||||
INVOKE_ASYNC(L, TYPE_PROC_REF(/atom/movable, throw_at), throw_target, 3, 4)
|
||||
L.KnockDown(2 SECONDS)
|
||||
L.adjustBruteLoss(20)
|
||||
safe_targets += L
|
||||
var/new_range = range + 1
|
||||
if(new_range <= max_range)
|
||||
addtimer(CALLBACK(src, PROC_REF(hit_check), new_range, start_turf, user, safe_targets), 0.2 SECONDS)
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/kidan_princess/martial_rush
|
||||
name = "Martial Rush"
|
||||
button_icon = 'icons/obj/surgery.dmi'
|
||||
button_icon_state = "sandy"
|
||||
desc = "Declare your intent to win, disgarding your halberd in favor of rapid punching attacks for ten seconds."
|
||||
click_to_activate = FALSE
|
||||
melee_cooldown_time = CLICK_CD_CLICK_ABILITY
|
||||
cooldown_time = 75 SECONDS
|
||||
shared_cooldown = NONE
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/kidan_princess/martial_rush/Activate(atom/target)
|
||||
var/mob/living/basic/megafauna/kidan_princess/princess = owner
|
||||
if(!istype(princess))
|
||||
return
|
||||
RegisterSignal(princess, COMSIG_MOVABLE_MOVED, PROC_REF(on_movement))
|
||||
princess.next_move_modifier -= 0.5
|
||||
princess.speed -= 1
|
||||
princess.attack_verb_continuous = "punches"
|
||||
princess.attack_verb_simple = "punch"
|
||||
if(princess.enraged)
|
||||
princess.melee_attack_cooldown_min = 0.2 SECONDS
|
||||
princess.melee_attack_cooldown_max = 0.3 SECONDS
|
||||
princess.melee_damage_lower = 10
|
||||
princess.melee_damage_upper = 15
|
||||
else
|
||||
princess.melee_attack_cooldown_min = 0.3 SECONDS
|
||||
princess.melee_attack_cooldown_max = 0.4 SECONDS
|
||||
princess.melee_damage_lower = 5
|
||||
princess.melee_damage_upper = 10
|
||||
princess.attack_sound ='sound/weapons/punch1.ogg'
|
||||
princess.martial_rushing = TRUE
|
||||
princess.update_icon(UPDATE_ICON_STATE)
|
||||
addtimer(CALLBACK(src, PROC_REF(end_rush)), 10 SECONDS)
|
||||
playsound(get_turf(princess), 'sound/magic/invoke_general.ogg', 300, TRUE, 5)
|
||||
princess.say("FACE ME!")
|
||||
StartCooldown()
|
||||
|
||||
/// Leaves an afterimage behind the mob when they move
|
||||
/datum/action/cooldown/mob_cooldown/kidan_princess/martial_rush/proc/on_movement(mob/living/L, atom/old_loc)
|
||||
SIGNAL_HANDLER
|
||||
if(HAS_TRAIT(L, TRAIT_IMMOBILIZED))
|
||||
return NONE
|
||||
new /obj/effect/temp_visual/decoy/mephedrone_afterimage(old_loc, L, 1.25 SECONDS)
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/kidan_princess/martial_rush/proc/end_rush()
|
||||
var/mob/living/basic/megafauna/kidan_princess/princess = owner
|
||||
if(!istype(princess))
|
||||
return
|
||||
UnregisterSignal(princess, COMSIG_MOVABLE_MOVED)
|
||||
princess.next_move_modifier = initial(princess.move_speed)
|
||||
princess.speed = initial(princess.speed)
|
||||
princess.attack_verb_continuous = initial(princess.attack_verb_continuous)
|
||||
princess.attack_verb_simple = initial(princess.attack_verb_simple)
|
||||
princess.melee_attack_cooldown_min = initial(princess.melee_attack_cooldown_min)
|
||||
if(princess.enraged)
|
||||
princess.melee_attack_cooldown_max = 1.25 SECONDS
|
||||
else
|
||||
princess.melee_attack_cooldown_max = initial(princess.melee_attack_cooldown_max)
|
||||
princess.melee_damage_lower = initial(princess.melee_damage_lower)
|
||||
princess.melee_damage_upper = initial(princess.melee_damage_upper)
|
||||
princess.attack_sound = initial(princess.attack_sound)
|
||||
princess.martial_rushing = FALSE
|
||||
princess.update_icon(UPDATE_ICON_STATE)
|
||||
@@ -0,0 +1,39 @@
|
||||
/datum/ai_controller/basic_controller/kidan_princess
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/kidan_warrior,
|
||||
BB_AGGRO_RANGE = 9,
|
||||
BB_SEARCH_RANGE = 10,
|
||||
BB_TARGET_MINIMUM_STAT = UNCONSCIOUS,
|
||||
)
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/corpses/human,
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/kidan_princess_spellcasting,
|
||||
/datum/ai_planning_subtree/attack_obstacle_in_path/walls,
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree,
|
||||
)
|
||||
ai_movement = /datum/ai_movement/jps
|
||||
interesting_dist = AI_MEGAFAUNA_INTERESTING_DIST
|
||||
max_target_distance = 15
|
||||
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/kidan_princess_spellcasting
|
||||
ability_key = BB_KIDAN_PRINCESS_CHARGE_ACTION
|
||||
/// Minimum time between any spells
|
||||
var/kidan_princess_global_spellcasting_delay = 6 SECONDS
|
||||
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/kidan_princess_spellcasting/select_behaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
if(controller.blackboard[BB_KIDAN_PRINCESS_SPELL_COOLDOWN] >= world.time)
|
||||
return
|
||||
var/list/ability_keys = list(BB_KIDAN_PRINCESS_CHARGE_ACTION, BB_KIDAN_PRINCESS_SUMMON_MOBS_ACTION, BB_KIDAN_PRINCESS_RUSH_ACTION, BB_KIDAN_PRINCESS_STOMP_ACTION)
|
||||
ability_key = pick_n_take(ability_keys)
|
||||
var/datum/action/cooldown/mob_cooldown/selected_action = controller.blackboard[ability_key]
|
||||
while(selected_action && !selected_action.IsAvailable())
|
||||
if(!ability_keys.len) // All spells are on cooldown
|
||||
return
|
||||
ability_key = pick_n_take(ability_keys)
|
||||
selected_action = controller.blackboard[ability_key]
|
||||
if(ability_key == BB_KIDAN_PRINCESS_RUSH_ACTION)
|
||||
controller.set_blackboard_key(BB_KIDAN_PRINCESS_SPELL_COOLDOWN, world.time + 16 SECONDS)
|
||||
else
|
||||
controller.set_blackboard_key(BB_KIDAN_PRINCESS_SPELL_COOLDOWN, world.time + kidan_princess_global_spellcasting_delay)
|
||||
return ..()
|
||||
Reference in New Issue
Block a user