diff --git a/code/game/gamemodes/technomancer/assistance/golem.dm b/code/game/gamemodes/technomancer/assistance/golem.dm index 3bd54ed1f5..33fc246911 100644 --- a/code/game/gamemodes/technomancer/assistance/golem.dm +++ b/code/game/gamemodes/technomancer/assistance/golem.dm @@ -29,47 +29,133 @@ melee_damage_lower = 30 // It has a built in esword. melee_damage_upper = 30 + attack_sound = 'sound/weapons/blade1.ogg' attacktext = "slashed" - attack_sound = null friendly = "hugs" resistance = 0 + melee_miss_chance = 0 var/obj/item/weapon/technomancer_core/golem/core = null var/obj/item/weapon/spell/active_spell = null // Shield and ranged spells var/mob/living/master = null var/list/known_spells = list( - "reflect" = /obj/item/weapon/spell/reflect, - "shield" = /obj/item/weapon/spell/shield, - "dispel" = /obj/item/weapon/spell/dispel, - "mend life" = /obj/item/weapon/spell/modifier/mend_life, - "mend synthetic" = /obj/item/weapon/spell/modifier/mend_synthetic, - "repel missiles" = /obj/item/weapon/spell/modifier/repel_missiles, - "corona" = /obj/item/weapon/spell/modifier/corona, "beam" = /obj/item/weapon/spell/projectile/beam, "chain lightning" = /obj/item/weapon/spell/projectile/chain_lightning, "force missile" = /obj/item/weapon/spell/projectile/force_missile, "ionic bolt" = /obj/item/weapon/spell/projectile/ionic_bolt, - "lightning" = /obj/item/weapon/spell/projectile/lightning + "lightning" = /obj/item/weapon/spell/projectile/lightning, + "blink" = /obj/item/weapon/spell/blink, + "dispel" = /obj/item/weapon/spell/dispel, + "oxygenate" = /obj/item/weapon/spell/oxygenate, + "mend life" = /obj/item/weapon/spell/modifier/mend_life, + "mend synthetic" = /obj/item/weapon/spell/modifier/mend_synthetic, + "mend organs" = /obj/item/weapon/spell/mend_organs, + "purify" = /obj/item/weapon/spell/modifier/purify, + "resurrect" = /obj/item/weapon/spell/resurrect, + "passwall" = /obj/item/weapon/spell/passwall, + "repel missiles" = /obj/item/weapon/spell/modifier/repel_missiles, + "corona" = /obj/item/weapon/spell/modifier/corona, + "haste" = /obj/item/weapon/spell/modifier/haste ) + // Holds the overlays, when idle or attacking. + var/image/sword_image = null + var/image/spell_image = null + // These contain icon_states for each frame of an attack animation, which is swapped in and out manually, because BYOND. + // They are assoc lists, to hold the frame duration and the frame icon_state in one list. + var/list/spell_pre_attack_states = list( + "golem_spell_attack_1" = 1, + "golem_spell_attack_2" = 2, + "golem_spell_attack_3" = 2 + ) + var/list/spell_post_attack_states = list( + "golem_spell_attack_4" = 2, + "golem_spell_attack_5" = 3, + "golem_spell_attack_6" = 3 + ) + var/list/sword_pre_attack_states = list( + "golem_sword_attack_1" = 1, + "golem_sword_attack_2" = 5 + ) + var/list/sword_post_attack_states = list( + "golem_sword_attack_3" = 1, + "golem_sword_attack_4" = 3 + ) + /mob/living/simple_animal/technomancer_golem/New() ..() core = new(src) + sword_image = image(icon, src, "golem_sword") + spell_image = image(icon, src, "golem_spell") update_icon() /mob/living/simple_animal/technomancer_golem/Destroy() qdel(core) + qdel(sword_image) + qdel(spell_image) return ..() +/mob/living/simple_animal/technomancer_golem/unref_spell() + active_spell = null + return ..() + +/mob/living/simple_animal/hostile/hivebot/death() + ..() + visible_message("\The [src] disintegrates!") + new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + qdel(src) + /mob/living/simple_animal/technomancer_golem/update_icon() overlays.Cut() - overlays.Add(image(icon, src, "golem_sword")) - overlays.Add(image(icon, src, "golem_spell")) + overlays += sword_image + overlays += spell_image + update_modifier_visuals() + +// Unfortunately, BYOND does not let you flick() images or other overlays, so we need to do this in a terrible way. +/atom/proc/manual_flick(var/list/frames, var/image/I, var/reset_to = null) + // Swap in and out each frame manually. + for(var/frame in frames) + overlays -= I + I.icon_state = frame + overlays += I + sleep(frames[frame]) + if(reset_to) + // One more time to reset it to what it was before. + overlays -= I + I.icon_state = reset_to + overlays += I + +/mob/living/simple_animal/technomancer_golem/proc/spellcast_pre_animation() + setClickCooldown(5) + manual_flick(spell_pre_attack_states, spell_image, reset_to = "golem_spell_attack_3") + +/mob/living/simple_animal/technomancer_golem/proc/spellcast_post_animation() + setClickCooldown(8) + manual_flick(spell_post_attack_states, spell_image, reset_to = "golem_spell") + +/mob/living/simple_animal/technomancer_golem/proc/sword_pre_animation() + setClickCooldown(6) + manual_flick(sword_pre_attack_states, sword_image) + +/mob/living/simple_animal/technomancer_golem/proc/sword_post_animation() + setClickCooldown(3) + manual_flick(sword_post_attack_states, sword_image, reset_to = "golem_sword") + +/mob/living/simple_animal/technomancer_golem/DoPunch(var/atom/A) + sword_pre_animation() + . = ..() // This does the actual attack and will check adjacency again. + sword_post_animation() /mob/living/simple_animal/technomancer_golem/isSynthetic() return TRUE // So Mend Synthetic will work on them. +/mob/living/simple_animal/technomancer_golem/speech_bubble_appearance() + return "synthetic_evil" + /mob/living/simple_animal/technomancer_golem/place_spell_in_hand(var/path) if(!path || !ispath(path)) return 0 @@ -84,21 +170,30 @@ var/choice = input(usr, "What spell?", "Give spell") as null|anything in known_spells if(choice) place_spell_in_hand(known_spells[choice]) + else + qdel(active_spell) // Used to cast spells. /mob/living/simple_animal/technomancer_golem/RangedAttack(var/atom/A, var/params) if(active_spell) + spellcast_pre_animation() if(active_spell.cast_methods & CAST_RANGED) active_spell.on_ranged_cast(A, src) + spellcast_post_animation() /mob/living/simple_animal/technomancer_golem/UnarmedAttack(var/atom/A, var/proximity) if(proximity) if(active_spell) + spellcast_pre_animation() + if(!Adjacent(A)) // Need to check again since they might've moved while 'warming up'. + spellcast_post_animation() + return + var/effective_cooldown = round(active_spell.cooldown * core.cooldown_modifier, 5) if(active_spell.cast_methods & CAST_MELEE) active_spell.on_melee_cast(A, src) else if(active_spell.cast_methods & CAST_RANGED) active_spell.on_ranged_cast(A, src) - var/effective_cooldown = round(active_spell.cooldown * core.cooldown_modifier, 5) + spellcast_post_animation() src.setClickCooldown(effective_cooldown) else ..() diff --git a/code/game/gamemodes/technomancer/spell_objs.dm b/code/game/gamemodes/technomancer/spell_objs.dm index 5ba100a4b4..fb28813102 100644 --- a/code/game/gamemodes/technomancer/spell_objs.dm +++ b/code/game/gamemodes/technomancer/spell_objs.dm @@ -149,10 +149,17 @@ // Parameters: 0 // Description: Nulls object references so it can qdel() cleanly. /obj/item/weapon/spell/Destroy() + owner.unref_spell(src) owner = null core = null return ..() +// Proc: unref_spells() +// Parameters: 0 +// Description: Nulls object references on specific mobs so it can qdel() cleanly. +/mob/proc/unref_spell(var/obj/item/weapon/spell/the_spell) + return + // Proc: update_icon() // Parameters: 0 // Description: Applys an overlay if it is a passive spell. diff --git a/code/game/gamemodes/technomancer/spells/aura/aura.dm b/code/game/gamemodes/technomancer/spells/aura/aura.dm index 23e45a2669..f3c7c93876 100644 --- a/code/game/gamemodes/technomancer/spells/aura/aura.dm +++ b/code/game/gamemodes/technomancer/spells/aura/aura.dm @@ -15,7 +15,7 @@ /obj/item/weapon/spell/aura/Destroy() processing_objects -= src log_and_message_admins("has stopped maintaining [src].") - ..() + return ..() /obj/item/weapon/spell/aura/process() return diff --git a/code/game/gamemodes/technomancer/spells/control.dm b/code/game/gamemodes/technomancer/spells/control.dm index c4591345e5..ebcf373baf 100644 --- a/code/game/gamemodes/technomancer/spells/control.dm +++ b/code/game/gamemodes/technomancer/spells/control.dm @@ -109,7 +109,7 @@ for(var/mob/living/simple_animal/hostile/SM in controlled_mobs) deselect(SM) controlled_mobs = list() - ..() + return ..() /obj/item/weapon/spell/control/on_use_cast(mob/living/user) if(controlled_mobs.len != 0) diff --git a/code/game/gamemodes/technomancer/spells/energy_siphon.dm b/code/game/gamemodes/technomancer/spells/energy_siphon.dm index 630bd5408f..345b632282 100644 --- a/code/game/gamemodes/technomancer/spells/energy_siphon.dm +++ b/code/game/gamemodes/technomancer/spells/energy_siphon.dm @@ -27,7 +27,7 @@ /obj/item/weapon/spell/energy_siphon/Destroy() stop_siphoning() processing_objects -= src - ..() + return ..() /obj/item/weapon/spell/energy_siphon/process() if(!siphoning) diff --git a/code/game/gamemodes/technomancer/spells/flame_tongue.dm b/code/game/gamemodes/technomancer/spells/flame_tongue.dm index 33b4b6204d..271240ad05 100644 --- a/code/game/gamemodes/technomancer/spells/flame_tongue.dm +++ b/code/game/gamemodes/technomancer/spells/flame_tongue.dm @@ -24,7 +24,7 @@ /obj/item/weapon/spell/flame_tongue/Destroy() qdel(welder) welder = null - ..() + return ..() /obj/item/weapon/weldingtool/spell name = "flame" diff --git a/code/game/gamemodes/technomancer/spells/illusion.dm b/code/game/gamemodes/technomancer/spells/illusion.dm index 48efd67783..e2afb8d120 100644 --- a/code/game/gamemodes/technomancer/spells/illusion.dm +++ b/code/game/gamemodes/technomancer/spells/illusion.dm @@ -64,7 +64,7 @@ /obj/item/weapon/spell/illusion/Destroy() if(illusion) qdel(illusion) - ..() + return ..() // Makes a tiny overlay of the thing the player has copied, so they can easily tell what they currently have. /obj/item/weapon/spell/illusion/update_icon() diff --git a/code/game/gamemodes/technomancer/spells/modifier/mend_synthetic.dm b/code/game/gamemodes/technomancer/spells/modifier/mend_synthetic.dm index cca20eb3b0..5b05ce56b8 100644 --- a/code/game/gamemodes/technomancer/spells/modifier/mend_synthetic.dm +++ b/code/game/gamemodes/technomancer/spells/modifier/mend_synthetic.dm @@ -29,9 +29,6 @@ stacks = MODIFIER_STACK_EXTEND /datum/modifier/technomancer/mend_synthetic/tick() -// if(!holder.isSynthetic()) // Don't heal biologicals! -// expire() -// return if(!holder.getActualBruteLoss() && !holder.getActualFireLoss()) // No point existing if the spell can't heal. expire() return @@ -42,8 +39,9 @@ if(O.robotic >= ORGAN_ROBOT) O.heal_damage(4 * spell_power, 4 * spell_power, 0, 1) else - holder.adjustBruteLoss(-4 * spell_power) // Should heal roughly 20 burn/brute over 10 seconds, as tick() is run every 2 seconds. - holder.adjustFireLoss(-4 * spell_power) // Ditto. + if(holder.isSynthetic()) + holder.adjustBruteLoss(-4 * spell_power) // Should heal roughly 20 burn/brute over 10 seconds, as tick() is run every 2 seconds. + holder.adjustFireLoss(-4 * spell_power) // Ditto. holder.adjust_instability(1) if(origin) diff --git a/code/game/gamemodes/technomancer/spells/reflect.dm b/code/game/gamemodes/technomancer/spells/reflect.dm index 60abcee63f..22b32bb660 100644 --- a/code/game/gamemodes/technomancer/spells/reflect.dm +++ b/code/game/gamemodes/technomancer/spells/reflect.dm @@ -29,7 +29,7 @@ /obj/item/weapon/spell/reflect/Destroy() spark_system = null - ..() + return ..() /obj/item/weapon/spell/reflect/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") if(user.incapacitated()) diff --git a/code/game/gamemodes/technomancer/spells/shield.dm b/code/game/gamemodes/technomancer/spells/shield.dm index 4ea507e959..772fd7a8f8 100644 --- a/code/game/gamemodes/technomancer/spells/shield.dm +++ b/code/game/gamemodes/technomancer/spells/shield.dm @@ -26,7 +26,7 @@ /obj/item/weapon/spell/shield/Destroy() spark_system = null - ..() + return ..() /obj/item/weapon/spell/shield/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") if(user.incapacitated()) diff --git a/code/game/gamemodes/technomancer/spells/track.dm b/code/game/gamemodes/technomancer/spells/track.dm index b02c88fc4d..230e282ee1 100644 --- a/code/game/gamemodes/technomancer/spells/track.dm +++ b/code/game/gamemodes/technomancer/spells/track.dm @@ -24,7 +24,7 @@ var/list/technomancer_belongings = list() /obj/item/weapon/spell/track/Destroy() tracked = null tracking = 0 - ..() + return ..() /obj/item/weapon/spell/track/on_use_cast(mob/user) if(tracking) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 3f4e37f1a0..ac33f7c09c 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -293,7 +293,7 @@ default behaviour is: return fireloss /mob/living/proc/getActualFireLoss() // Mostly for humans with robolimbs. - return getBruteLoss() + return getFireLoss() /mob/living/proc/adjustFireLoss(var/amount) if(status_flags & GODMODE) return 0 //godmode diff --git a/code/modules/mob/living/silicon/robot/subtypes/lost_drone.dm b/code/modules/mob/living/silicon/robot/subtypes/lost_drone.dm index 476059a274..ba6890e835 100644 --- a/code/modules/mob/living/silicon/robot/subtypes/lost_drone.dm +++ b/code/modules/mob/living/silicon/robot/subtypes/lost_drone.dm @@ -22,6 +22,9 @@ playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0) +/mob/living/silicon/robot/lost/speech_bubble_appearance() + return "synthetic_evil" + /mob/living/silicon/robot/lost/randomlaws /mob/living/silicon/robot/lost/randomlaws/init() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 0697f81714..32a5a9cb35 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -227,19 +227,14 @@ //Should we be dead? /mob/living/simple_animal/updatehealth() + health = getMaxHealth() - getToxLoss() - getFireLoss() - getBruteLoss() + //Alive, becoming dead if((stat < DEAD) && (health <= 0)) death() - //Dead, becoming alive - else if((stat >= DEAD) && (health > 0)) - dead_mob_list -= src - living_mob_list += src - stat = CONSCIOUS - density = 1 - //Overhealth - else if(health > getMaxHealth()) + if(health > getMaxHealth()) health = getMaxHealth() /mob/living/simple_animal/update_icon() @@ -621,6 +616,16 @@ var/tally = 0 //Incase I need to add stuff other than "speed" later tally = speed + + if(force_max_speed) + return -3 + + for(var/datum/modifier/M in modifiers) + if(!isnull(M.haste) && M.haste == TRUE) + return -3 + if(!isnull(M.slowdown)) + tally += M.slowdown + if(purge)//Purged creatures will move more slowly. The more time before their purge stops, the slower they'll move. if(tally <= 0) tally = 1 @@ -674,52 +679,6 @@ if(3.0) adjustBruteLoss(30) -// Don't understand why simple animals don't use the regular /mob/living health system. -/mob/living/simple_animal/adjustBruteLoss(damage) - if(damage > 0) - for(var/datum/modifier/M in modifiers) - if(!isnull(M.incoming_damage_percent)) - damage *= M.incoming_damage_percent - if(!isnull(M.incoming_brute_damage_percent)) - damage *= M.incoming_brute_damage_percent - else if(damage < 0) - for(var/datum/modifier/M in modifiers) - if(!isnull(M.incoming_healing_percent)) - damage *= M.incoming_healing_percent - - health = Clamp(health - damage, 0, getMaxHealth()) - updatehealth() - -/mob/living/simple_animal/adjustFireLoss(damage) - if(damage > 0) - for(var/datum/modifier/M in modifiers) - if(!isnull(M.incoming_damage_percent)) - damage *= M.incoming_damage_percent - if(!isnull(M.incoming_fire_damage_percent)) - damage *= M.incoming_brute_damage_percent - else if(damage < 0) - for(var/datum/modifier/M in modifiers) - if(!isnull(M.incoming_healing_percent)) - damage *= M.incoming_healing_percent - - health = Clamp(health - damage, 0, getMaxHealth()) - updatehealth() - -/mob/living/simple_animal/adjustToxLoss(damage) - if(damage > 0) - for(var/datum/modifier/M in modifiers) - if(!isnull(M.incoming_damage_percent)) - damage *= M.incoming_damage_percent - if(!isnull(M.incoming_tox_damage_percent)) - damage *= M.incoming_brute_damage_percent - else if(damage < 0) - for(var/datum/modifier/M in modifiers) - if(!isnull(M.incoming_healing_percent)) - damage *= M.incoming_healing_percent - - health = Clamp(health - damage, 0, getMaxHealth()) - updatehealth() - // Check target_mob if worthy of attack (i.e. check if they are dead or empty mecha) /mob/living/simple_animal/proc/SA_attackable(target_mob) ai_log("SA_attackable([target_mob])",3) @@ -1238,6 +1197,9 @@ if(!isnull(M.outgoing_melee_damage_percent)) damage_to_do *= M.outgoing_melee_damage_percent + if(attack_sound) + playsound(src, attack_sound, 75, 1) + // SA attacks can be blocked with shields. if(ishuman(A)) var/mob/living/carbon/human/H = A diff --git a/code/modules/mob/modifiers.dm b/code/modules/mob/modifiers.dm index 95d3db1e93..b581a97894 100644 --- a/code/modules/mob/modifiers.dm +++ b/code/modules/mob/modifiers.dm @@ -123,7 +123,7 @@ // Removes all modifiers of a type /mob/living/proc/remove_modifiers_of_type(var/modifier_type, var/silent = FALSE) for(var/datum/modifier/M in modifiers) - if(istype(M, modifier_type)) + if(ispath(M.type, modifier_type)) M.expire(silent) // Removes all modifiers, useful if the mob's being deleted diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi index ec0e70ccdc..33133bda47 100644 Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ