From ef440a4b5f0ef73bc39d387647c9512d2970fd85 Mon Sep 17 00:00:00 2001 From: Neerti Date: Sun, 14 Oct 2018 07:08:21 -0400 Subject: [PATCH] Finishes the other mechs and fixes bug in AI threaten code. --- code/game/objects/structures/loot_piles.dm | 36 ++++++++++++- .../ai/aI_holder_subtypes/simple_mob_ai.dm | 20 ++++--- code/modules/ai/ai_holder_communication.dm | 17 ++++-- code/modules/ai/ai_holder_targeting.dm | 12 +++++ code/modules/mob/living/living_defense.dm | 1 - .../mob/living/simple_mob/appearance.dm | 8 ++- .../mob/living/simple_mob/simple_mob.dm | 6 ++- .../mechanical/mecha/adv_dark_gygax.dm | 10 ++-- .../subtypes/mechanical/mecha/durand.dm | 53 +++++++++++++++++++ .../subtypes/mechanical/mecha/gygax.dm | 27 ++-------- .../subtypes/mechanical/mecha/hoverpod.dm | 2 +- .../subtypes/mechanical/mecha/marauder.dm | 44 +++++++++++++++ .../subtypes/mechanical/mecha/mecha.dm | 23 +++++++- .../subtypes/mechanical/mecha/odysseus.dm | 4 +- .../subtypes/mechanical/mecha/phazon.dm | 22 ++++++++ .../subtypes/mechanical/mecha/ripley.dm | 6 +-- polaris.dme | 3 ++ 17 files changed, 242 insertions(+), 52 deletions(-) create mode 100644 code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/durand.dm create mode 100644 code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/marauder.dm create mode 100644 code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/phazon.dm diff --git a/code/game/objects/structures/loot_piles.dm b/code/game/objects/structures/loot_piles.dm index 55853f3ffe..44f11b73fe 100644 --- a/code/game/objects/structures/loot_piles.dm +++ b/code/game/objects/structures/loot_piles.dm @@ -574,6 +574,7 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh icon = 'icons/mecha/mecha.dmi' icon_state = "engineering_pod-broken" density = TRUE + anchored = FALSE // In case a dead mecha-mob dies in a bad spot. chance_uncommon = 20 chance_rare = 10 @@ -615,7 +616,7 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh /obj/structure/loot_pile/mecha/ripley name = "ripley wreckage" desc = "The ruins of some unfortunate ripley. Perhaps something is salvageable." - icon_states_to_use = list("ripley-broken", "firefighter-broken", "ripley-broken-old") + icon_state = "ripley-broken" common_loot = list( /obj/random/tool, @@ -649,6 +650,12 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh /obj/item/mecha_parts/mecha_equipment/weapon/energy/flamer/rigged ) +/obj/structure/loot_pile/mecha/ripley/firefighter + icon_state = "firefighter-broken" + +/obj/structure/loot_pile/mecha/ripley/random_sprite + icon_states_to_use = list("ripley-broken", "firefighter-broken", "ripley-broken-old") + //Death-Ripley, same common, but more combat-exosuit-based /obj/structure/loot_pile/mecha/deathripley name = "strange ripley wreckage" @@ -719,6 +726,14 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh /obj/item/mecha_parts/mecha_equipment/shocker ) +/obj/structure/loot_pile/mecha/odysseus/murdysseus + icon_state = "murdysseus-broken" + +/obj/structure/loot_pile/mecha/hoverpod + name = "hoverpod wreckage" + desc = "The ruins of some unfortunate hoverpod. Perhaps something is salvageable." + icon_state = "engineering_pod" + /obj/structure/loot_pile/mecha/gygax name = "gygax wreckage" desc = "The ruins of some unfortunate gygax. Perhaps something is salvageable." @@ -768,6 +783,9 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh icon_scale = 1.5 pixel_y = 8 +/obj/structure/loot_pile/mecha/gygax/medgax + icon_state = "medgax-broken" + /obj/structure/loot_pile/mecha/durand name = "durand wreckage" desc = "The ruins of some unfortunate durand. Perhaps something is salvageable." @@ -808,6 +826,22 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy ) +/obj/structure/loot_pile/mecha/marauder + name = "marauder wreckage" + desc = "The ruins of some unfortunate marauder. Perhaps something is salvagable." + icon_state = "marauder-broken" + // Todo: Better loot. + +/obj/structure/loot_pile/mecha/marauder/seraph + name = "seraph wreckage" + desc = "The ruins of some unfortunate seraph. Perhaps something is salvagable." + icon_state = "seraph-broken" + +/obj/structure/loot_pile/mecha/marauder/mauler + name = "mauler wreckage" + desc = "The ruins of some unfortunate mauler. Perhaps something is salvagable." + icon_state = "mauler-broken" + /obj/structure/loot_pile/mecha/phazon name = "phazon wreckage" desc = "The ruins of some unfortunate phazon. Perhaps something is salvageable." diff --git a/code/modules/ai/aI_holder_subtypes/simple_mob_ai.dm b/code/modules/ai/aI_holder_subtypes/simple_mob_ai.dm index 35ab94d53c..9c3c329aa0 100644 --- a/code/modules/ai/aI_holder_subtypes/simple_mob_ai.dm +++ b/code/modules/ai/aI_holder_subtypes/simple_mob_ai.dm @@ -102,27 +102,31 @@ // The mob has three special attacks, based on the current intent. // This AI choose the appropiate intent for the situation, and tries to ensure it doesn't kill itself by firing missiles at its feet. /datum/ai_holder/simple_mob/intentional/adv_dark_gygax - var/closest_safest_distance = 3 // Stay this many tiles away when using missiles or mini-singulo to avoid hitting ourselves. - var/closest_desired_distance = 2 // Otherwise run up to them to be able to potentially shock or punch them. + conserve_ammo = TRUE // Might help avoid 'I shoot the wall forever' cheese. + var/closest_desired_distance = 1 // Otherwise run up to them to be able to potentially shock or punch them. + var/electric_defense_radius = 3 // How big to assume electric defense's area is. var/microsingulo_radius = 3 // Same but for microsingulo pull. var/rocket_explosive_radius = 2 // Explosion radius for the rockets. + var/electric_defense_threshold = 2 // How many non-targeted people are needed in close proximity before electric defense is viable. + var/microsingulo_threshold = 2 // Similar to above, but uses an area around the target. + // Used to control the mob's positioning based on which special attack it has done. // Note that the intent will not change again until the next special attack is about to happen. /datum/ai_holder/simple_mob/intentional/adv_dark_gygax/on_engagement(atom/A) // Make the AI backpeddle if using an AoE special attack. var/list/risky_intents = list(I_GRAB, I_HURT) // Mini-singulo and missiles. - var/closest_distance = 1 if(holder.a_intent in risky_intents) + var/closest_distance = 1 switch(holder.a_intent) // Plus one just in case. if(I_HURT) closest_distance = rocket_explosive_radius + 1 if(I_GRAB) closest_distance = microsingulo_radius + 1 - if(get_dist(holder, A) <= closest_safest_distance) - holder.IMove(get_step_away(holder, A, closest_safest_distance)) + if(get_dist(holder, A) <= closest_distance) + holder.IMove(get_step_away(holder, A, closest_distance)) // Otherwise get up close and personal. else if(get_dist(holder, A) > closest_desired_distance) @@ -146,14 +150,14 @@ tally++ // Should we shock them? - if(tally >= 2 || get_dist(target, holder) <= electric_defense_radius) + if(tally >= electric_defense_threshold || get_dist(target, holder) <= electric_defense_radius) holder.a_intent = I_DISARM return // Otherwise they're a fair distance away and we're not getting mobbed up close. // See if we should use missiles or microsingulo. tally = 0 // Let's recycle the var. - for(var/mob/living/L in hearers(3, target)) + for(var/mob/living/L in hearers(microsingulo_radius, target)) if(holder == L) continue if(L.IIsAlly(holder)) @@ -163,7 +167,7 @@ tally++ // Lots of people means minisingulo would be more useful. - if(tally >= 2) + if(tally >= microsingulo_threshold) holder.a_intent = I_GRAB else // Otherwise use rockets. holder.a_intent = I_HURT diff --git a/code/modules/ai/ai_holder_communication.dm b/code/modules/ai/ai_holder_communication.dm index bd82a7ec1a..57947738c0 100644 --- a/code/modules/ai/ai_holder_communication.dm +++ b/code/modules/ai/ai_holder_communication.dm @@ -5,7 +5,8 @@ var/threatening = FALSE // If the mob actually gave the warning, checked so it doesn't constantly yell every tick. var/threaten_delay = 3 SECONDS // How long a 'threat' lasts, until actual fighting starts. If null, the mob never starts the fight but still does the threat. var/threaten_timeout = 1 MINUTE // If the mob threatens someone, they leave, and then come back before this timeout period, the mob escalates to fighting immediately. - var/last_conflict_time = null // Last occurance of threatening or fighting being used, in world.time. + var/last_conflict_time = null // Last occurance of fighting being used, in world.time. + var/last_threaten_time = null // Ditto but only for threats. var/speak_chance = 0 // Probability that the mob talks (this is 'X in 200' chance since even 1/100 is pretty noisy) var/reacts = 0 // Reacts to some things being said. @@ -14,11 +15,13 @@ /datum/ai_holder/proc/should_threaten() if(!threaten) return FALSE // We don't negotiate. + if(target in attackers) + return FALSE // They (or someone like them) attacked us before, escalate immediately. if(!will_threaten(target)) return FALSE // Pointless to threaten an animal, a mindless drone, or an object. if(stance in STANCES_COMBAT) return FALSE // We're probably already fighting or recently fought if not in these stances. - if(last_conflict_time && threaten_delay && last_conflict_time + threaten_timeout > world.time) + if(last_threaten_time && threaten_delay && last_conflict_time + threaten_timeout > world.time) return FALSE // We threatened someone recently, so lets show them we mean business. return TRUE // Lets give them a chance to choose wisely and walk away. @@ -27,7 +30,7 @@ if(!threatening) // First tick. threatening = TRUE - last_conflict_time = world.time + last_threaten_time = world.time if(holder.say_list) holder.say(safepick(holder.say_list.say_threaten)) @@ -35,8 +38,14 @@ playsound(target.loc, holder.say_list.threaten_sound, 50, 1) // Actual aim-mode also does that so at least it's consistant. else // Otherwise we are waiting for them to go away or to wait long enough for escalate. if(target in list_targets()) // Are they still visible? + var/should_escalate = FALSE - if(threaten_delay && last_conflict_time + threaten_delay < world.time) // Waited too long. + if(threaten_delay && last_threaten_time + threaten_delay < world.time) // Waited too long. + should_escalate = TRUE + else if(last_conflict_time + threaten_timeout > world.time) // We got attacked while threatening them. + should_escalate = TRUE + + if(should_escalate) threatening = FALSE set_stance(STANCE_APPROACH) if(holder.say_list) diff --git a/code/modules/ai/ai_holder_targeting.dm b/code/modules/ai/ai_holder_targeting.dm index 10ab1eda71..acb3da2309 100644 --- a/code/modules/ai/ai_holder_targeting.dm +++ b/code/modules/ai/ai_holder_targeting.dm @@ -15,6 +15,9 @@ var/lose_target_time = 0 // world.time when a target was lost. var/lose_target_timeout = 5 SECONDS // How long until a mob 'times out' and stops trying to find the mob that disappeared. + var/list/attackers = list() // List of strings of names of people who attacked us before in our life. + // This uses strings and not refs to allow for disguises, and to avoid needing to use weakrefs. + // A lot of this is based off of /TG/'s AI code. // Step 1, find out what we can see. @@ -202,6 +205,7 @@ return FALSE if(target) // Already fighting someone. Switching every time we get hit would impact our combat performance. ai_log("react_to_attack() : Was attacked by [attacker], but we already have a target.", AI_LOG_TRACE) + on_attacked(attacker) // So we attack immediately and not threaten. return FALSE if(stance == STANCE_SLEEP) // If we're asleep, try waking up if someone's wailing on us. @@ -209,8 +213,16 @@ go_wake() ai_log("react_to_attack() : Was attacked by [attacker].", AI_LOG_INFO) + on_attacked(attacker) // So we attack immediately and not threaten. return give_target(attacker) // Also handles setting the appropiate stance. +// Sets a few vars so mobs that threaten will react faster to an attacker or someone who attacked them before. +/datum/ai_holder/proc/on_attacked(atom/movable/AM) + last_conflict_time = world.time + if(isliving(AM)) + var/mob/living/L = AM + attackers |= L.name + // Causes targeting to prefer targeting the taunter if possible. // This generally occurs if more than one option is within striking distance, including the taunter. // Otherwise the default filter will prefer the closest target. diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 091a4346b3..0b294af295 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -336,7 +336,6 @@ // End BS12 momentum-transfer code. /mob/living/attack_generic(var/mob/user, var/damage, var/attack_message) - if(!damage) return diff --git a/code/modules/mob/living/simple_mob/appearance.dm b/code/modules/mob/living/simple_mob/appearance.dm index 0acff529ec..05f758d7c4 100644 --- a/code/modules/mob/living/simple_mob/appearance.dm +++ b/code/modules/mob/living/simple_mob/appearance.dm @@ -7,6 +7,9 @@ add_overlay(modifier_overlay) + if(!icon_living) // Prevent the mob from turning invisible if icon_living is null. + icon_living = initial(icon_state) + //Awake and normal if((stat == CONSCIOUS) && (!icon_rest || !resting || !incapacitated(INCAPACITATION_DISABLED) )) icon_state = icon_living @@ -30,7 +33,10 @@ add_overlay(l_hand_sprite) if(has_eye_glow) - add_eyes() + if(icon_state != icon_living) + remove_eyes() + else + add_eyes() // appearance = ma diff --git a/code/modules/mob/living/simple_mob/simple_mob.dm b/code/modules/mob/living/simple_mob/simple_mob.dm index cb115a345f..72848dbc87 100644 --- a/code/modules/mob/living/simple_mob/simple_mob.dm +++ b/code/modules/mob/living/simple_mob/simple_mob.dm @@ -159,8 +159,6 @@ if(has_eye_glow) add_eyes() - if(!icon_living) - icon_living = icon_state return ..() @@ -177,6 +175,10 @@ remove_eyes() return ..() +/mob/living/simple_mob/death() + update_icon() + ..() + //Client attached /mob/living/simple_mob/Login() diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/adv_dark_gygax.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/adv_dark_gygax.dm index 0ebb501e38..4a754cb8c4 100644 --- a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/adv_dark_gygax.dm +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/adv_dark_gygax.dm @@ -1,7 +1,8 @@ // Stronger than a regular Dark Gygax, this one has three special attacks, based on intents. // First special attack launches three arcing rockets at the current target. -// Second special attack fires a side weapon that rapidly pumps out blue energy blasts at nearby enemies for a few seconds. -// Third special attack TBD. +// Second special attack fires a projectile that creates a short-lived microsingularity that pulls in everything nearby. Magboots can protect from this. +// Third special attack creates a dangerous electric field that causes escalating electric damage, before emitting a tesla shock and blinding anyone looking at the mecha. +// The AI will choose one every ten seconds. /mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced name = "advanced dark gygax" desc = "An experimental exosuit that utilizes advanced materials to allow for greater protection while still being lightweight and fast. \ @@ -13,6 +14,7 @@ maxHealth = 450 deflect_chance = 25 + has_repair_droid = TRUE armor = list( "melee" = 50, "bullet" = 50, @@ -26,6 +28,7 @@ special_attack_min_range = 1 special_attack_max_range = 7 special_attack_cooldown = 10 SECONDS + projectiletype = /obj/item/projectile/force_missile var/obj/effect/overlay/energy_ball/energy_ball = null /mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced/Destroy() @@ -47,6 +50,7 @@ #define ELECTRIC_ZAP_POWER 20000 // Charges a tesla shot, while emitting a dangerous electric field. The exosuit is immune to electric damage while this is ongoing. +// It also briefly blinds anyone looking directly at the mech without flash protection. /mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced/proc/electric_defense(atom/target) set waitfor = FALSE @@ -163,4 +167,4 @@ /obj/effect/temporary_effect/pulse/microsingulo/on_pulse() for(var/atom/A in range(pull_radius, src)) - A.singularity_pull(src, pull_strength) \ No newline at end of file + A.singularity_pull(src, pull_strength) diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/durand.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/durand.dm new file mode 100644 index 0000000000..a29616a9bc --- /dev/null +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/durand.dm @@ -0,0 +1,53 @@ +// Durands are slow, tanky, beefy, and hit really hard. +// They can also root themselves to become even tankier. +// The AI doesn't do this currently. + +/mob/living/simple_mob/mechanical/mecha/combat/durand + name = "durand" + desc = "An aging combat exosuit utilized by many corporations. It was originally developed to fight in the First Contact War." + icon_state = "durand" + movement_cooldown = 10 + wreckage = /obj/structure/loot_pile/mecha/durand + + maxHealth = 400 + deflect_chance = 20 + armor = list( + "melee" = 50, + "bullet" = 35, + "laser" = 15, + "energy" = 10, + "bomb" = 20, + "bio" = 100, + "rad" = 100 + ) + melee_damage_lower = 40 + melee_damage_upper = 40 + base_attack_cooldown = 2 SECONDS + projectiletype = /obj/item/projectile/beam/heavylaser + + var/defense_mode = FALSE + var/defense_deflect = 35 + +/mob/living/simple_mob/mechanical/mecha/combat/durand/proc/set_defense_mode(new_mode) + defense_mode = new_mode + deflect_chance = defense_mode ? defense_deflect : initial(deflect_chance) + to_chat(src, span("notice", "You [defense_mode ? "en" : "dis"]able defense mode.")) + +/mob/living/simple_mob/mechanical/mecha/combat/durand/SelfMove(turf/n, direct) + if(defense_mode) + to_chat(src, span("warning", "You are in defense mode, you cannot move.")) + return FALSE + return ..() + +// So players can toggle it too. +/mob/living/simple_mob/mechanical/mecha/combat/durand/verb/toggle_defense_mode() + set name = "Toggle Defense Mode" + set desc = "Toggles a special mode which makes you unable to move but become more resilient." + set category = "Abilities" + + set_defense_mode(!defense_mode) + +// Variant that starts in defense mode, perhaps for PoIs. +/mob/living/simple_mob/mechanical/mecha/combat/durand/defensive/initialize() + set_defense_mode(TRUE) + return ..() diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/gygax.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/gygax.dm index 524dd4f394..4e0cc0cb3d 100644 --- a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/gygax.dm +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/gygax.dm @@ -5,7 +5,7 @@ name = "gygax" desc = "A lightweight, security exosuit. Popular among private and corporate security." icon_state = "gygax" - movement_cooldown = 5 + movement_cooldown = 0 wreckage = /obj/structure/loot_pile/mecha/gygax maxHealth = 300 @@ -37,6 +37,7 @@ maxHealth = 400 deflect_chance = 25 + has_repair_droid = TRUE armor = list( "melee" = 40, "bullet" = 40, @@ -47,32 +48,10 @@ "rad" = 100 ) - - - - /mob/living/simple_mob/mechanical/mecha/combat/gygax/medgax name = "medgax" desc = "An unorthodox fusion of the Gygax and Odysseus exosuits, this one is fast, sturdy, and carries a wide array of \ potent chemicals and delivery mechanisms. The doctor is in!" icon_state = "medgax" - wreckage = /obj/effect/decal/mecha_wreckage/gygax/medgax + wreckage = /obj/structure/loot_pile/mecha/gygax/medgax - -/* - desc = "A lightweight, security exosuit. Popular among private and corporate security." - name = "Gygax" - icon_state = "gygax" - initial_icon = "gygax" - step_in = 3 - dir_in = 1 //Facing North. - health = 300 - maxhealth = 300 - deflect_chance = 15 - damage_absorption = list("brute"=0.75,"fire"=1,"bullet"=0.8,"laser"=0.7,"energy"=0.85,"bomb"=1) - max_temperature = 25000 - infra_luminosity = 6 - var/overload = 0 - var/overload_coeff = 2 - wreckage = /obj/effect/decal/mecha_wreckage/gygax -*/ \ No newline at end of file diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/hoverpod.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/hoverpod.dm index e4bc57d6c4..29f102b9b9 100644 --- a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/hoverpod.dm +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/hoverpod.dm @@ -4,7 +4,7 @@ desc = "Stubby and round, this space-capable craft is an ancient favorite. It has a jury-rigged welder-laser." icon_state = "engineering_pod" movement_sound = 'sound/machines/hiss.ogg' - wreckage = /obj/effect/decal/mecha_wreckage/hoverpod + wreckage = /obj/structure/loot_pile/mecha/hoverpod maxHealth = 150 hovering = TRUE // Can fly. diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/marauder.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/marauder.dm new file mode 100644 index 0000000000..b4fa89c005 --- /dev/null +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/marauder.dm @@ -0,0 +1,44 @@ +// Marauders are even tougher than Durands. + +/mob/living/simple_mob/mechanical/mecha/combat/marauder + name = "marauder" + desc = "A heavy-duty, combat exosuit, developed after the Durand model. This is rarely found among civilian populations." + icon_state = "marauder" + movement_cooldown = 5 + wreckage = /obj/structure/loot_pile/mecha/marauder + + maxHealth = 500 + deflect_chance = 25 + sight = SEE_SELF | SEE_MOBS + armor = list( + "melee" = 50, + "bullet" = 55, + "laser" = 40, + "energy" = 30, + "bomb" = 30, + "bio" = 100, + "rad" = 100 + ) + melee_damage_lower = 45 + melee_damage_upper = 45 + base_attack_cooldown = 2 SECONDS + projectiletype = /obj/item/projectile/beam/heavylaser + + +// Slightly stronger, used to allow comdoms to frontline without dying instantly, I guess. +/mob/living/simple_mob/mechanical/mecha/combat/marauder/seraph + name = "seraph" + desc = "A heavy-duty, combat/command exosuit. This one is specialized towards housing important commanders such as high-ranking \ + military personnel. It's stronger than the regular Marauder model, but not by much." + icon_state = "seraph" + wreckage = /obj/structure/loot_pile/mecha/marauder/seraph + health = 550 + melee_damage_lower = 55 // The real version hits this hard apparently. Ouch. + melee_damage_upper = 55 + + +/mob/living/simple_mob/mechanical/mecha/combat/marauder/mauler + name = "mauler" + desc = "A heavy duty, combat exosuit that is based off of the Marauder model." + icon_state = "mauler" + wreckage = /obj/structure/loot_pile/mecha/marauder/mauler diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/mecha.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/mecha.dm index 2a5d10ed02..7aa24bdf74 100644 --- a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/mecha.dm +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/mecha.dm @@ -9,7 +9,7 @@ faction = "syndicate" movement_cooldown = 5 - movement_sound = 'sound/mecha/mechstep.ogg' + movement_sound = "mechstep" // This gets fed into playsound(), which can also take strings as a 'group' of sound files. turn_sound = 'sound/mecha/mechturn.ogg' maxHealth = 300 mob_size = MOB_LARGE @@ -37,18 +37,23 @@ var/wreckage = /obj/effect/decal/mecha_wreckage/gygax/dark var/pilot_type = null // Set to spawn a pilot when destroyed. Setting this also makes the mecha vulnerable to things that affect sentient minds. var/deflect_chance = 10 // Chance to outright stop an attack, just like a normal exosuit. + var/has_repair_droid = FALSE // If true, heals 2 damage every tick and gets a repair droid overlay. /mob/living/simple_mob/mechanical/mecha/initialize() sparks = new (src) sparks.set_up(3, 1, src) + sparks.attach(src) if(!pilot_type) - name = "autonomous [initial(name)] drone" + name = "autonomous [initial(name)]" desc = "[initial(desc)] It appears to be piloted by a drone intelligence." else say_list_type = /datum/say_list/merc + if(has_repair_droid) + update_icon() + return ..() /mob/living/simple_mob/mechanical/mecha/Destroy() @@ -71,6 +76,20 @@ qdel(src) // Then delete us since we don't actually have a body. +/mob/living/simple_mob/mechanical/mecha/handle_special() + if(has_repair_droid) + adjustBruteLoss(-2) + adjustFireLoss(-2) + adjustToxLoss(-2) + adjustOxyLoss(-2) + adjustCloneLoss(-2) + ..() + +/mob/living/simple_mob/mechanical/mecha/update_icon() + ..() // Cuts everything else, so do that first. + if(has_repair_droid) + add_overlay(image(icon = 'icons/mecha/mecha_equipment.dmi', icon_state = "repair_droid")) + /mob/living/simple_mob/mechanical/mecha/bullet_act() . = ..() sparks.start() diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/odysseus.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/odysseus.dm index 0123255896..245bd54193 100644 --- a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/odysseus.dm +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/odysseus.dm @@ -6,7 +6,7 @@ name = "odysseus" desc = "These exosuits are developed and produced by Vey-Med. This one has a syringe gun." icon_state = "odysseus" - wreckage = /obj/effect/decal/mecha_wreckage/odysseus + wreckage = /obj/structure/loot_pile/mecha/odysseus maxHealth = 120 movement_cooldown = 0 @@ -28,7 +28,7 @@ // Resprite of the regular one, perhaps for merc PoIs. /mob/living/simple_mob/mechanical/mecha/odysseus/murdysseus icon_state = "murdysseus" - wreckage = /obj/effect/decal/mecha_wreckage/odysseus/murdysseus + wreckage = /obj/structure/loot_pile/mecha/odysseus/murdysseus /mob/living/simple_mob/mechanical/mecha/odysseus/murdysseus/manned pilot_type = /mob/living/simple_mob/humanoid/merc/ranged diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/phazon.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/phazon.dm new file mode 100644 index 0000000000..ebbe80ecf4 --- /dev/null +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/phazon.dm @@ -0,0 +1,22 @@ +// Phazons are weird. + +/mob/living/simple_mob/mechanical/mecha/combat/phazon + name = "phazon" + desc = "An extremly enigmatic exosuit." + icon_state = "phazon" + movement_cooldown = 5 + wreckage = /obj/structure/loot_pile/mecha/phazon + + maxHealth = 200 + deflect_chance = 30 + armor = list( + "melee" = 30, + "bullet" = 30, + "laser" = 30, + "energy" = 30, + "bomb" = 30, + "bio" = 100, + "rad" = 100 + ) + projectiletype = /obj/item/projectile/energy/declone + diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/ripley.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/ripley.dm index ad7292a9ba..8372363ea0 100644 --- a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/ripley.dm +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/ripley.dm @@ -5,7 +5,7 @@ name = "\improper APLU ripley" desc = "Autonomous Power Loader Unit. The workhorse of the exosuit world. This one has big drill." icon_state = "ripley" - wreckage = /obj/effect/decal/mecha_wreckage/ripley + wreckage = /obj/structure/loot_pile/mecha/ripley maxHealth = 200 @@ -32,7 +32,7 @@ name = "\improper APLU firefighter" desc = "A standard APLU chassis, refitted with additional thermal protection and cistern. This one has a big drill." icon_state = "firefighter" - wreckage = /obj/effect/decal/mecha_wreckage/ripley/firefighter + wreckage = /obj/structure/loot_pile/mecha/ripley/firefighter maxHealth = 250 heat_resist = 1 @@ -54,7 +54,7 @@ name = "\improper DEATH-RIPLEY" desc = "OH SHIT RUN!!! IT HAS A KILL CLAMP!" icon_state = "deathripley" - wreckage = /obj/effect/decal/mecha_wreckage/ripley/deathripley + wreckage = /obj/structure/loot_pile/mecha/deathripley melee_damage_lower = 0 melee_damage_upper = 0 diff --git a/polaris.dme b/polaris.dme index d3d6bead3f..127d67a249 100644 --- a/polaris.dme +++ b/polaris.dme @@ -2016,9 +2016,12 @@ #include "code\modules\mob\living\simple_mob\subtypes\mechanical\hivebot\ranged_damage.dm" #include "code\modules\mob\living\simple_mob\subtypes\mechanical\hivebot\support.dm" #include "code\modules\mob\living\simple_mob\subtypes\mechanical\hivebot\tank.dm" +#include "code\modules\mob\living\simple_mob\subtypes\mechanical\mecha\adv_dark_gygax.dm" #include "code\modules\mob\living\simple_mob\subtypes\mechanical\mecha\combat_mecha.dm" +#include "code\modules\mob\living\simple_mob\subtypes\mechanical\mecha\durand.dm" #include "code\modules\mob\living\simple_mob\subtypes\mechanical\mecha\gygax.dm" #include "code\modules\mob\living\simple_mob\subtypes\mechanical\mecha\hoverpod.dm" +#include "code\modules\mob\living\simple_mob\subtypes\mechanical\mecha\marauder.dm" #include "code\modules\mob\living\simple_mob\subtypes\mechanical\mecha\mecha.dm" #include "code\modules\mob\living\simple_mob\subtypes\mechanical\mecha\odysseus.dm" #include "code\modules\mob\living\simple_mob\subtypes\mechanical\mecha\ripley.dm"