Merge remote-tracking branch 'upstream/master' into dynamicport
This commit is contained in:
@@ -111,6 +111,19 @@
|
||||
sigil_name = "Sigil of Submission"
|
||||
var/glow_type = /obj/effect/temp_visual/ratvar/sigil/submission
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/Crossed(atom/movable/AM)
|
||||
. = ..()
|
||||
if(istype(AM, /obj/item/aicard))
|
||||
var/obj/item/aicard/cardy = AM
|
||||
if(!cardy.AI)
|
||||
return
|
||||
var/mob/living/silicon/ai/aiconvert = cardy.AI
|
||||
if(aiconvert.stat > stat_affected)
|
||||
return
|
||||
if(is_servant_of_ratvar(aiconvert) || !(aiconvert.mind || aiconvert.has_status_effect(STATUS_EFFECT_SIGILMARK)))
|
||||
return
|
||||
sigil_effects(aiconvert)
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/sigil_effects(mob/living/L)
|
||||
var/turf/T = get_turf(src)
|
||||
var/has_sigil = FALSE
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
/datum/antagonist/ninja
|
||||
name = "Ninja"
|
||||
antagpanel_category = "Ninja"
|
||||
job_rank = ROLE_NINJA
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
threat = 8
|
||||
var/helping_station = FALSE
|
||||
var/give_objectives = TRUE
|
||||
var/give_equipment = TRUE
|
||||
|
||||
/datum/antagonist/ninja/threat()
|
||||
return helping_station ? -(..()) : ..()
|
||||
|
||||
/datum/antagonist/ninja/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
update_ninja_icons_added(M)
|
||||
|
||||
/datum/antagonist/ninja/remove_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
update_ninja_icons_removed(M)
|
||||
|
||||
/datum/antagonist/ninja/proc/equip_space_ninja(mob/living/carbon/human/H = owner.current)
|
||||
return H.equipOutfit(/datum/outfit/ninja)
|
||||
|
||||
/datum/antagonist/ninja/proc/addMemories()
|
||||
antag_memory += "I am an elite mercenary assassin of the mighty Spider Clan. A <font color='red'><B>SPACE NINJA</B></font>!<br>"
|
||||
antag_memory += "Surprise is my weapon. Shadows are my armor. Without them, I am nothing. (//initialize your suit by clicking the initialize UI button, to use abilities like stealth)!<br>"
|
||||
antag_memory += "Officially, [helping_station?"Nanotrasen":"The Syndicate"] are my employer.<br>"
|
||||
|
||||
/datum/antagonist/ninja/proc/addObjectives(quantity = 6)
|
||||
var/list/possible_targets = list()
|
||||
for(var/datum/mind/M in SSticker.minds)
|
||||
if(M.current && M.current.stat != DEAD)
|
||||
if(ishuman(M.current))
|
||||
if(M.special_role)
|
||||
possible_targets[M] = 0 //bad-guy
|
||||
else if(M.assigned_role in GLOB.command_positions)
|
||||
possible_targets[M] = 1 //good-guy
|
||||
|
||||
var/list/possible_objectives = list(1,2,3,4)
|
||||
|
||||
while(objectives.len < quantity)
|
||||
switch(pick_n_take(possible_objectives))
|
||||
if(1) //research
|
||||
var/datum/objective/download/O = new /datum/objective/download()
|
||||
O.owner = owner
|
||||
O.gen_amount_goal()
|
||||
objectives += O
|
||||
|
||||
if(2) //steal
|
||||
var/datum/objective/steal/special/O = new /datum/objective/steal/special()
|
||||
O.owner = owner
|
||||
O.find_target()
|
||||
objectives += O
|
||||
|
||||
if(3) //protect/kill
|
||||
if(!possible_targets.len) continue
|
||||
var/index = rand(1,possible_targets.len)
|
||||
var/datum/mind/M = possible_targets[index]
|
||||
var/is_bad_guy = possible_targets[M]
|
||||
possible_targets.Cut(index,index+1)
|
||||
|
||||
if(is_bad_guy ^ helping_station) //kill (good-ninja + bad-guy or bad-ninja + good-guy)
|
||||
var/datum/objective/assassinate/once/O = new /datum/objective/assassinate()
|
||||
O.owner = owner
|
||||
O.target = M
|
||||
O.explanation_text = "Slay \the [M.current.real_name], the [M.assigned_role]. You may let [M.p_they()] live, if they come back from death."
|
||||
objectives += O
|
||||
else //protect
|
||||
var/datum/objective/protect/O = new /datum/objective/protect()
|
||||
O.owner = owner
|
||||
O.target = M
|
||||
O.explanation_text = "Protect \the [M.current.real_name], the [M.assigned_role], from harm."
|
||||
objectives += O
|
||||
if(4) //flavor
|
||||
var/datum/objective/flavor/O = helping_station ? new /datum/objective/flavor/ninja_helping : new /datum/objective/flavor/ninja_syndie
|
||||
O.owner = owner
|
||||
O.forge_objective()
|
||||
objectives += O
|
||||
else
|
||||
break
|
||||
var/datum/objective/O = new /datum/objective/survive()
|
||||
O.owner = owner
|
||||
objectives += O
|
||||
|
||||
/proc/remove_ninja(mob/living/L)
|
||||
if(!L || !L.mind)
|
||||
return FALSE
|
||||
var/datum/antagonist/datum = L.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
datum.on_removal()
|
||||
return TRUE
|
||||
|
||||
/proc/is_ninja(mob/living/M)
|
||||
return M && M.mind && M.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
|
||||
|
||||
/datum/antagonist/ninja/greet()
|
||||
SEND_SOUND(owner.current, sound('sound/effects/ninja_greeting.ogg'))
|
||||
to_chat(owner.current, "I am an elite mercenary assassin of the mighty Spider Clan. A <font color='red'><B>SPACE NINJA</B></font>!")
|
||||
to_chat(owner.current, "Surprise is my weapon. Shadows are my armor. Without them, I am nothing. (//initialize your suit by right clicking on it, to use abilities like stealth)!")
|
||||
to_chat(owner.current, "Officially, [helping_station?"Nanotrasen":"The Syndicate"] are my employer.")
|
||||
owner.announce_objectives()
|
||||
return
|
||||
|
||||
/datum/antagonist/ninja/on_gain()
|
||||
if(give_objectives)
|
||||
addObjectives()
|
||||
addMemories()
|
||||
if(give_equipment)
|
||||
equip_space_ninja(owner.current)
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/ninja/admin_add(datum/mind/new_owner,mob/admin)
|
||||
var/adj
|
||||
switch(input("What kind of ninja?", "Ninja") as null|anything in list("Random","Syndicate","Nanotrasen","No objectives"))
|
||||
if("Random")
|
||||
helping_station = pick(TRUE,FALSE)
|
||||
adj = ""
|
||||
if("Syndicate")
|
||||
helping_station = FALSE
|
||||
adj = "syndie"
|
||||
if("Nanotrasen")
|
||||
helping_station = TRUE
|
||||
adj = "friendly"
|
||||
if("No objectives")
|
||||
give_objectives = FALSE
|
||||
adj = "objectiveless"
|
||||
else
|
||||
return
|
||||
new_owner.assigned_role = ROLE_NINJA
|
||||
new_owner.special_role = ROLE_NINJA
|
||||
new_owner.add_antag_datum(src)
|
||||
message_admins("[key_name_admin(admin)] has [adj] ninja'ed [new_owner.current].")
|
||||
log_admin("[key_name(admin)] has [adj] ninja'ed [new_owner.current].")
|
||||
|
||||
/datum/antagonist/ninja/proc/update_ninja_icons_added(var/mob/living/carbon/human/ninja)
|
||||
var/datum/atom_hud/antag/ninjahud = GLOB.huds[ANTAG_HUD_NINJA]
|
||||
ninjahud.join_hud(ninja)
|
||||
set_antag_hud(ninja, "ninja")
|
||||
|
||||
/datum/antagonist/ninja/proc/update_ninja_icons_removed(var/mob/living/carbon/human/ninja)
|
||||
var/datum/atom_hud/antag/ninjahud = GLOB.huds[ANTAG_HUD_NINJA]
|
||||
ninjahud.leave_hud(ninja)
|
||||
set_antag_hud(ninja, null)
|
||||
@@ -68,6 +68,11 @@
|
||||
desc = "An integrated tracking device, jury-rigged to search for living Syndicate operatives."
|
||||
flags_1 = NONE
|
||||
|
||||
/obj/item/pinpointer/spider_cyborg // Cyborg pinpointers just look for a random space ninja.
|
||||
name = "cyborg spider clan pinpointer"
|
||||
desc = "An integrated tracking device, jury-rigged to search for living Spider Clan members."
|
||||
flags_1 = NONE
|
||||
|
||||
|
||||
/obj/item/pinpointer/syndicate_cyborg/Initialize()
|
||||
. = ..()
|
||||
@@ -85,3 +90,20 @@
|
||||
if(closest_operative)
|
||||
target = closest_operative
|
||||
..()
|
||||
|
||||
/obj/item/pinpointer/spider_cyborg/Initialize()
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_NODROP, CYBORG_ITEM_TRAIT)
|
||||
|
||||
/obj/item/pinpointer/spider_cyborg/scan_for_target()
|
||||
target = null
|
||||
var/list/possible_targets = list()
|
||||
var/turf/here = get_turf(src)
|
||||
for(var/V in get_antag_minds(/datum/antagonist/ninja))
|
||||
var/datum/mind/M = V
|
||||
if(ishuman(M.current) && M.current.stat != DEAD)
|
||||
possible_targets |= M.current
|
||||
var/mob/living/closest_weeaboo = get_closest_atom(/mob/living/carbon/human, possible_targets, here)
|
||||
if(closest_weeaboo)
|
||||
target = closest_weeaboo
|
||||
..()
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
healable = 0
|
||||
environment_smash = ENVIRONMENT_SMASH_STRUCTURES
|
||||
obj_damage = 50
|
||||
melee_damage_lower = 22.5 // reduced from 30 to 22.5 with wounds since they get big buffs to slicing wounds
|
||||
melee_damage_upper = 22.5
|
||||
wound_bonus = -10
|
||||
melee_damage_lower = 30 // buffed back to 30, the wounds don't do much
|
||||
melee_damage_upper = 30
|
||||
wound_bonus = 0
|
||||
bare_wound_bonus = 0
|
||||
sharpness = SHARP_EDGED
|
||||
see_in_dark = 8
|
||||
@@ -49,17 +49,13 @@
|
||||
Pulling a dead or unconscious mob while you enter a pool will pull them in with you, allowing you to feast and regain your health. \
|
||||
You move quickly upon leaving a pool of blood, but the material world will soon sap your strength and leave you sluggish. \
|
||||
You gain strength the more attacks you land on live humanoids, though this resets when you return to the blood zone. You can also \
|
||||
launch a devastating slam attack with ctrl+shift+click, capable of smashing bones in one strike.</B>"
|
||||
launch a devastating slam attack, capable of smashing bones in one strike.</B>"
|
||||
|
||||
loot = list(/obj/effect/decal/cleanable/blood, \
|
||||
/obj/effect/decal/cleanable/blood/innards, \
|
||||
/obj/item/organ/heart/demon)
|
||||
del_on_death = 1
|
||||
deathmessage = "screams in anger as it collapses into a puddle of viscera!"
|
||||
// How long it takes for the alt-click slam attack to come off cooldown
|
||||
var/slam_cooldown_time = 45 SECONDS
|
||||
// The actual instance var for the cooldown
|
||||
var/slam_cooldown = 0
|
||||
// How many times we have hit humanoid targets since we last bloodcrawled, scaling wounding power
|
||||
var/current_hitstreak = 0
|
||||
// How much both our wound_bonus and bare_wound_bonus go up per hitstreak hit
|
||||
@@ -70,37 +66,56 @@
|
||||
var/list/consumed_mobs = list()
|
||||
//buffs only happen when hearts are eaten, so this needs to be kept track separately
|
||||
var/consumed_buff = 0
|
||||
//slam mode for action button
|
||||
var/slam_mode = FALSE
|
||||
var/datum/action/cooldown/slam
|
||||
|
||||
/mob/living/simple_animal/slaughter/Initialize()
|
||||
..()
|
||||
var/obj/effect/proc_holder/spell/bloodcrawl/bloodspell = new
|
||||
AddSpell(bloodspell)
|
||||
slam = new /datum/action/cooldown/slam
|
||||
slam.Grant(src)
|
||||
if(istype(loc, /obj/effect/dummy/phased_mob/slaughter))
|
||||
bloodspell.phased = TRUE
|
||||
|
||||
/mob/living/simple_animal/slaughter/CtrlShiftClickOn(atom/A)
|
||||
if(!isliving(A))
|
||||
return ..()
|
||||
if(slam_cooldown + slam_cooldown_time > world.time)
|
||||
to_chat(src, "<span class='warning'>Your slam ability is still on cooldown!</span>")
|
||||
return
|
||||
if(!isopenturf(loc))
|
||||
to_chat(src, "<span class='warning'>You need to be on open flooring to do that!")
|
||||
return
|
||||
/datum/action/cooldown/slam
|
||||
name = "Slaughter Slam"
|
||||
desc = "Launch enemies and break bones in one strike."
|
||||
icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
|
||||
background_icon_state = "bg_demon"
|
||||
button_icon_state = "slam"
|
||||
cooldown_time = 45 SECONDS
|
||||
|
||||
face_atom(A)
|
||||
var/mob/living/victim = A
|
||||
victim.take_bodypart_damage(brute=20, wound_bonus=wound_bonus) // don't worry, there's more punishment when they hit something
|
||||
visible_message("<span class='danger'>[src] slams into [victim] with monstrous strength!</span>", "<span class='danger'>You slam into [victim] with monstrous strength!</span>", ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[src] slams into you with monstrous strength, sending you flying like a ragdoll!</span>")
|
||||
var/turf/yeet_target = get_edge_target_turf(victim, dir)
|
||||
victim.throw_at(yeet_target, 10, 5, src)
|
||||
slam_cooldown = world.time
|
||||
log_combat(src, victim, "slaughter slammed")
|
||||
/datum/action/cooldown/slam/Trigger()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
var/mob/living/simple_animal/slaughter/user = owner
|
||||
user.slam_mode = !user.slam_mode
|
||||
to_chat(user, user.slam_mode ? "Ready to slam!" : "Maybe not now.")
|
||||
|
||||
/mob/living/simple_animal/slaughter/UnarmedAttack(atom/A, proximity)
|
||||
if(iscarbon(A))
|
||||
var/mob/living/carbon/target = A
|
||||
if(slam_mode)
|
||||
if(!isopenturf(loc))
|
||||
to_chat(src, "<span class='warning'>You need to be on open flooring to do that!")
|
||||
return
|
||||
face_atom(A)
|
||||
var/mob/living/victim = A
|
||||
var/body_pick = pick(BODY_ZONE_CHEST, BODY_ZONE_HEAD, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_ARM, BODY_ZONE_R_LEG)
|
||||
var/datum/wound/blunt/critical/wound_major = new
|
||||
var/obj/item/bodypart/body_wound = victim.get_bodypart(body_pick)
|
||||
wound_major.apply_wound(body_wound)
|
||||
visible_message("<span class='danger'>[src] slams into [victim] with monstrous strength!</span>", "<span class='danger'>You slam into [victim] with monstrous strength!</span>", ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[src] slams into you with monstrous strength, sending you flying like a ragdoll!</span>")
|
||||
var/turf/yeet_target = get_edge_target_turf(victim, dir)
|
||||
victim.throw_at(yeet_target, 10, 14, src)
|
||||
slam_mode = FALSE
|
||||
slam.StartCooldown()
|
||||
log_combat(src, victim, "slaughter slammed")
|
||||
|
||||
if(target.stat != DEAD && target.mind && current_hitstreak < wound_bonus_hitstreak_max)
|
||||
current_hitstreak++
|
||||
wound_bonus += wound_bonus_per_hit
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/datum/antagonist/ninja
|
||||
name = "Space Ninja"
|
||||
antagpanel_category = "Space Ninja"
|
||||
job_rank = ROLE_NINJA
|
||||
antag_hud_type = ANTAG_HUD_NINJA
|
||||
antag_hud_name = "space_ninja"
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
///Whether or not this ninja will obtain objectives
|
||||
var/give_objectives = TRUE
|
||||
///Whether or not this ninja receives the standard equipment
|
||||
var/give_equipment = TRUE
|
||||
|
||||
/proc/is_ninja(mob/living/M)
|
||||
return M && M.mind && M.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
|
||||
/datum/antagonist/ninja/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/ninja = mob_override || owner.current
|
||||
add_antag_hud(antag_hud_type, antag_hud_name, ninja)
|
||||
|
||||
/datum/antagonist/ninja/remove_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/ninja = mob_override || owner.current
|
||||
remove_antag_hud(antag_hud_type, ninja)
|
||||
|
||||
/**
|
||||
* Proc that equips the space ninja outfit on a given individual. By default this is the owner of the antagonist datum.
|
||||
*
|
||||
* Proc that equips the space ninja outfit on a given individual. By default this is the owner of the antagonist datum.
|
||||
* Arguments:
|
||||
* * ninja - The human to receive the gear
|
||||
* * Returns a proc call on the given human which will equip them with all the gear.
|
||||
*/
|
||||
/datum/antagonist/ninja/proc/equip_space_ninja(mob/living/carbon/human/ninja = owner.current)
|
||||
return ninja.equipOutfit(/datum/outfit/ninja)
|
||||
|
||||
/**
|
||||
* Proc that adds the proper memories to the antag datum
|
||||
*
|
||||
* Proc that adds the ninja starting memories to the owner of the antagonist datum.
|
||||
*/
|
||||
/datum/antagonist/ninja/proc/addMemories()
|
||||
antag_memory += "I am an elite mercenary of the mighty Spider Clan. A <font color='red'><B>SPACE NINJA</B></font>!<br>"
|
||||
antag_memory += "Surprise is my weapon. Shadows are my armor. Without them, I am nothing. (//initialize your suit by clicking the initialize UI button, to use abilities like stealth)!<br>"
|
||||
|
||||
/datum/objective/cyborg_hijack
|
||||
explanation_text = "Use your gloves to convert at least one cyborg to aide you in sabotaging the station."
|
||||
|
||||
/datum/objective/door_jack
|
||||
///How many doors that need to be opened using the gloves to pass the objective
|
||||
var/doors_required = 0
|
||||
|
||||
/datum/objective/plant_explosive
|
||||
var/area/detonation_location
|
||||
|
||||
/datum/objective/security_scramble
|
||||
explanation_text = "Use your gloves on a security console to set everyone to arrest at least once. Note that the AI will be alerted once you begin!"
|
||||
|
||||
/datum/objective/terror_message
|
||||
explanation_text = "Use your gloves on a communication console in order to bring another threat to the station. Note that the AI will be alerted once you begin!"
|
||||
|
||||
/**
|
||||
* Proc that adds all the ninja's objectives to the antag datum.
|
||||
*
|
||||
* Proc that adds all the ninja's objectives to the antag datum. Called when the datum is gained.
|
||||
*/
|
||||
/datum/antagonist/ninja/proc/addObjectives()
|
||||
//Cyborg Hijack: Flag set to complete in the DrainAct in ninjaDrainAct.dm
|
||||
var/datum/objective/hijack = new /datum/objective/cyborg_hijack()
|
||||
objectives += hijack
|
||||
|
||||
//Research stealing
|
||||
var/datum/objective/download/research = new /datum/objective/download()
|
||||
research.owner = owner
|
||||
research.gen_amount_goal()
|
||||
objectives += research
|
||||
|
||||
//Door jacks, flag will be set to complete on when the last door is hijacked
|
||||
var/datum/objective/door_jack/doorobjective = new /datum/objective/door_jack()
|
||||
doorobjective.doors_required = rand(15,40)
|
||||
doorobjective.explanation_text = "Use your gloves to doorjack [doorobjective.doors_required] airlocks on the station."
|
||||
objectives += doorobjective
|
||||
|
||||
//Explosive plant, the bomb will register its completion on priming
|
||||
var/datum/objective/plant_explosive/bombobjective = new /datum/objective/plant_explosive()
|
||||
for(var/sanity in 1 to 100) // 100 checks at most.
|
||||
var/area/selected_area = pick(GLOB.sortedAreas)
|
||||
if(!is_station_level(selected_area.z) || !selected_area.area_flags == VALID_TERRITORY)
|
||||
continue
|
||||
bombobjective.detonation_location = selected_area
|
||||
break
|
||||
if(bombobjective.detonation_location)
|
||||
bombobjective.explanation_text = "Detonate your starter bomb in [bombobjective.detonation_location]. Note that the bomb will not work anywhere else!"
|
||||
objectives += bombobjective
|
||||
|
||||
//Security Scramble, set to complete upon using your gloves on a security console
|
||||
var/datum/objective/securityobjective = new /datum/objective/security_scramble()
|
||||
objectives += securityobjective
|
||||
|
||||
//Message of Terror, set to complete upon using your gloves a communication console
|
||||
var/datum/objective/communicationobjective = new /datum/objective/terror_message()
|
||||
objectives += communicationobjective
|
||||
|
||||
//Survival until end
|
||||
var/datum/objective/survival = new /datum/objective/survive()
|
||||
survival.owner = owner
|
||||
objectives += survival
|
||||
|
||||
/datum/antagonist/ninja/greet()
|
||||
SEND_SOUND(owner.current, sound('sound/effects/ninja_greeting.ogg'))
|
||||
to_chat(owner.current, "I am an elite mercenary of the mighty Spider Clan. A <font color='red'><B>SPACE NINJA</B></font>!")
|
||||
to_chat(owner.current, "Surprise is my weapon. Shadows are my armor. Without them, I am nothing. (//initialize your suit by right clicking on it, to use abilities like stealth)!")
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/antagonist/ninja/on_gain()
|
||||
if(give_objectives)
|
||||
addObjectives()
|
||||
addMemories()
|
||||
if(give_equipment)
|
||||
equip_space_ninja(owner.current)
|
||||
|
||||
owner.current.mind.assigned_role = ROLE_NINJA
|
||||
owner.current.mind.special_role = ROLE_NINJA
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/ninja/admin_add(datum/mind/new_owner,mob/admin)
|
||||
new_owner.assigned_role = ROLE_NINJA
|
||||
new_owner.special_role = ROLE_NINJA
|
||||
new_owner.add_antag_datum(src)
|
||||
message_admins("[key_name_admin(admin)] has ninja'ed [key_name_admin(new_owner)].")
|
||||
log_admin("[key_name(admin)] has ninja'ed [key_name(new_owner)].")
|
||||
Reference in New Issue
Block a user