mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-15 00:53:23 +01:00
b0463d3c83
* spanish? * aaaagain * keep maptext * Update robot_items.dm * Update span_defines.dm * compiles * Update silicon_mob.dm * compile
236 lines
8.3 KiB
Plaintext
236 lines
8.3 KiB
Plaintext
// malfunctioning combat drones
|
|
/mob/living/basic/malf_drone
|
|
name = "combat drone"
|
|
desc = "An automated combat drone armed with state of the art weaponry and shielding."
|
|
icon_state = "drone3"
|
|
icon_living = "drone3"
|
|
icon_dead = "drone_dead"
|
|
mob_biotypes = MOB_ROBOTIC
|
|
response_disarm_continuous = "gently pushes aside the"
|
|
response_disarm_simple = "gently pushes aside the"
|
|
a_intent = INTENT_HARM
|
|
health = 200
|
|
maxHealth = 200
|
|
speed = 8
|
|
is_ranged = TRUE
|
|
ranged_burst_count = 3
|
|
ranged_burst_interval = 0.4
|
|
projectile_type = /obj/projectile/beam/immolator/weak/hitscan
|
|
projectile_sound = 'sound/weapons/laser3.ogg'
|
|
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)
|
|
minimum_survivable_temperature = 0
|
|
faction = list("malf_drone")
|
|
death_message = "suddenly breaks apart."
|
|
basic_mob_flags = DEL_ON_DEATH
|
|
advanced_bullet_dodge_chance = 25 // This will be adjusted when active, vs deactivated. Randomises on hit if it is zero.
|
|
ai_controller = /datum/ai_controller/basic_controller/simple/malf_drone
|
|
/// Is the drone passive?
|
|
var/passive = FALSE
|
|
|
|
/mob/living/basic/malf_drone/Initialize(mapload)
|
|
. = ..()
|
|
RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(create_trail))
|
|
add_language("Galactic Common")
|
|
set_default_language(GLOB.all_languages["Galactic Common"])
|
|
AddElement(/datum/element/ai_retaliate)
|
|
update_icons()
|
|
AddComponent(/datum/component/event_tracker, EVENT_DRONE)
|
|
|
|
/mob/living/basic/malf_drone/proc/create_trail(datum/source, atom/oldloc, _dir, forced)
|
|
var/turf/T = get_turf(oldloc)
|
|
if(!has_gravity(T))
|
|
new /obj/effect/particle_effect/ion_trails(T, _dir)
|
|
|
|
/mob/living/basic/malf_drone/Process_Spacemove(movement_dir = 0, continuous_move = FALSE)
|
|
return 1
|
|
|
|
/mob/living/basic/malf_drone/update_icons()
|
|
if(passive)
|
|
icon_state = "drone_dead"
|
|
else if(health / maxHealth > 0.9)
|
|
icon_state = "drone3"
|
|
else if(health / maxHealth > 0.7)
|
|
icon_state = "drone2"
|
|
else if(health / maxHealth > 0.5)
|
|
icon_state = "drone1"
|
|
else
|
|
icon_state = "drone0"
|
|
|
|
/mob/living/basic/malf_drone/adjustHealth(damage, updating_health)
|
|
do_sparks(3, 1, src)
|
|
if(!QDELETED(src))
|
|
ai_controller.set_blackboard_key(BB_MALF_DRONE_PASSIVE, FALSE)
|
|
passive = FALSE
|
|
update_icons()
|
|
if(!advanced_bullet_dodge_chance)
|
|
advanced_bullet_dodge_chance = 25
|
|
. = ..() // this will handle finding a target if there is a valid one nearby
|
|
|
|
/mob/living/basic/malf_drone/Life(seconds, times_fired)
|
|
. = ..()
|
|
if(.) // mob is alive. We check this just in case Life() can fire for qdel'ed mobs.
|
|
if(times_fired % 15 == 0) // every 15 cycles, aka 30 seconds, 50% chance to switch between modes
|
|
scramble_settings()
|
|
|
|
/mob/living/basic/malf_drone/proc/scramble_settings()
|
|
if(prob(50))
|
|
do_sparks(3, 1, src)
|
|
passive = !passive
|
|
ai_controller.set_blackboard_key(BB_MALF_DRONE_PASSIVE, passive)
|
|
if(passive)
|
|
visible_message(SPAN_NOTICE("[src] retracts several targetting vanes."))
|
|
advanced_bullet_dodge_chance = 0
|
|
ai_controller.set_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET, null)
|
|
else
|
|
visible_message(SPAN_WARNING("[src] suddenly lights up, and additional targetting vanes slide into place."))
|
|
advanced_bullet_dodge_chance = 25
|
|
ai_controller.cancel_actions()
|
|
update_icons()
|
|
|
|
/// We overide the basic effect, as malfunctioning drones are in space, and use jets to dodge. Also lets us do cool effects.
|
|
/mob/living/basic/malf_drone/advanced_bullet_dodge(mob/living/source, obj/projectile/hitting_projectile)
|
|
if(HAS_TRAIT(source, TRAIT_IMMOBILIZED))
|
|
return NONE
|
|
if(source.stat != CONSCIOUS)
|
|
return NONE
|
|
if(!prob(advanced_bullet_dodge_chance))
|
|
return NONE
|
|
|
|
source.visible_message(
|
|
SPAN_DANGER("[source]'s jets [pick("boosts", "propels", "pulses", "flares up and moves", "shudders and pushes")] it out of '[hitting_projectile]'s way!"),
|
|
SPAN_USERDANGER("You evade [hitting_projectile]!"),
|
|
)
|
|
playsound(source, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg', 'sound/effects/refill.ogg'), 75, TRUE)
|
|
if(prob(50))
|
|
addtimer(VARSET_CALLBACK(source, advanced_bullet_dodge_chance, advanced_bullet_dodge_chance), 0.25 SECONDS)
|
|
advanced_bullet_dodge_chance = 0
|
|
return ATOM_PREHIT_FAILURE
|
|
|
|
/mob/living/basic/malf_drone/emp_act(severity)
|
|
adjustHealth(100 / severity) // takes the same damage as a mining drone from emp
|
|
|
|
/mob/living/basic/malf_drone/drop_loot()
|
|
do_sparks(3, 1, src)
|
|
|
|
var/turf/T = get_turf(src)
|
|
|
|
// shards
|
|
var/obj/O = new /obj/item/shard(T)
|
|
step_to(O, get_turf(pick(view(7, src))))
|
|
if(prob(75))
|
|
O = new /obj/item/shard(T)
|
|
step_to(O, get_turf(pick(view(7, src))))
|
|
if(prob(50))
|
|
O = new /obj/item/shard(T)
|
|
step_to(O, get_turf(pick(view(7, src))))
|
|
if(prob(25))
|
|
O = new /obj/item/shard(T)
|
|
step_to(O, get_turf(pick(view(7, src))))
|
|
|
|
// rods
|
|
var/obj/item/stack/K = new /obj/item/stack/rods(T)
|
|
step_to(K, get_turf(pick(view(7, src))))
|
|
K.amount = pick(1, 2, 3, 4)
|
|
K.update_icon()
|
|
|
|
// plasteel
|
|
K = new /obj/item/stack/sheet/plasteel(T)
|
|
step_to(K, get_turf(pick(view(7, src))))
|
|
K.amount = pick(1, 2, 3, 4)
|
|
K.update_icon()
|
|
|
|
// Spawn 1-4 boards of a random type
|
|
var/num_boards = rand(1, 4)
|
|
var/list/options = subtypesof(/obj/item/circuitboard/random_tech_level)
|
|
for(var/i in 1 to num_boards)
|
|
var/obj/item/circuitboard/random_tech_level/board = pick_n_take(options)
|
|
new board(T)
|
|
|
|
// Becomes a board with a random level in the specified tech
|
|
// It's done like this so we can have a random level because we can't do this in the type declaration
|
|
/obj/item/circuitboard/random_tech_level
|
|
/// Lower bound of random tech level
|
|
var/lower_bound = 3
|
|
/// Upper bound of random tech level
|
|
var/upper_bound = 6
|
|
|
|
/obj/item/circuitboard/random_tech_level/Initialize(mapload)
|
|
. = ..()
|
|
origin_tech += "[rand(lower_bound, upper_bound)]"
|
|
|
|
/obj/item/circuitboard/random_tech_level/motherboard
|
|
name = "Drone CPU motherboard"
|
|
origin_tech = "programming="
|
|
|
|
/obj/item/circuitboard/random_tech_level/interface
|
|
name = "Drone neural interface"
|
|
origin_tech = "biotech="
|
|
|
|
/obj/item/circuitboard/random_tech_level/processor
|
|
name = "Drone suspension processor"
|
|
origin_tech = "magnets="
|
|
|
|
/obj/item/circuitboard/random_tech_level/controller
|
|
name = "Drone shielding controller"
|
|
origin_tech = "bluespace="
|
|
|
|
/obj/item/circuitboard/random_tech_level/capacitor
|
|
name = "Drone power capacitor"
|
|
origin_tech = "powerstorage="
|
|
|
|
/obj/item/circuitboard/random_tech_level/reinforcer
|
|
name = "Drone hull reinforcer"
|
|
origin_tech = "materials="
|
|
|
|
/obj/item/circuitboard/random_tech_level/autorepair
|
|
name = "Drone auto-repair system"
|
|
origin_tech = "engineering="
|
|
|
|
/obj/item/circuitboard/random_tech_level/counter
|
|
name = "Drone plasma overcharge counter"
|
|
origin_tech = "plasmatech="
|
|
|
|
/obj/item/circuitboard/random_tech_level/targeting
|
|
name = "Drone targeting circuitboard"
|
|
origin_tech = "combat="
|
|
|
|
/obj/item/circuitboard/random_tech_level/morality
|
|
name = "Corrupted drone morality core"
|
|
origin_tech = "syndicate="
|
|
|
|
/datum/ai_controller/basic_controller/simple/malf_drone
|
|
movement_delay = 2 SECONDS
|
|
blackboard = list(
|
|
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/malf_drone,
|
|
BB_AGGRO_RANGE = 7,
|
|
BB_BASIC_MOB_FLEE_DISTANCE = 3,
|
|
BB_MALF_DRONE_PASSIVE = FALSE,
|
|
)
|
|
planning_subtrees = list(
|
|
/datum/ai_planning_subtree/random_speech/malf_drone,
|
|
/datum/ai_planning_subtree/target_retaliate/check_faction,
|
|
/datum/ai_planning_subtree/simple_find_target/malf_drone,
|
|
/datum/ai_planning_subtree/maintain_distance,
|
|
/datum/ai_planning_subtree/ranged_skirmish/no_minimum,
|
|
)
|
|
|
|
/datum/ai_planning_subtree/simple_find_target/malf_drone
|
|
|
|
/datum/ai_planning_subtree/simple_find_target/malf_drone/select_behaviors(datum/ai_controller/controller, seconds_per_tick)
|
|
if(controller.blackboard[BB_MALF_DRONE_PASSIVE])
|
|
return // Only target if we're not in passive mode
|
|
return ..()
|
|
|
|
/datum/ai_planning_subtree/random_speech/malf_drone
|
|
speech_chance = 4
|
|
speak = list("ALERT.", "Hostile-ile-ile entities dee-twhoooo-wected.", "Threat parameterszzzz- szzet.", "Bring sub-sub-sub-systems uuuup to combat alert alpha-a-a.")
|
|
emote_see = list("beeps menacingly.", "whirrs threateningly.", "scans for targets.")
|
|
|
|
/datum/targeting_strategy/basic/malf_drone
|
|
|
|
/// Returns false if we're on passive mode. If we get attacked, we swap out of passive mode.
|
|
/datum/targeting_strategy/basic/malf_drone/can_attack(mob/living/living_mob, atom/target, vision_range)
|
|
if(living_mob?.ai_controller?.blackboard[BB_MALF_DRONE_PASSIVE])
|
|
return FALSE
|
|
return ..()
|