From deb215d262caedfa368619bb3364a2bfc0f10e15 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Wed, 9 Sep 2015 13:39:18 -0400 Subject: [PATCH] Refactors bottle smashing, apply_hit_effect() now returns the blocked status. Conflicts: code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm code/modules/mob/living/simple_animal/simple_animal.dm code/modules/reagents/reagent_containers/food/drinks/bottle.dm --- code/_onclick/item_attack.dm | 2 +- code/game/objects/items/robot/robot_items.dm | 4 +- code/game/objects/items/weapons/stunbaton.dm | 5 +- code/modules/hydroponics/grown.dm | 2 +- .../mob/living/carbon/human/human_defense.dm | 2 +- .../species/xenomorphs/alien_facehugger.dm | 232 ++++++++++++++++++ code/modules/mob/living/living_defense.dm | 29 +-- .../mob/living/simple_animal/simple_animal.dm | 25 +- .../reagent_containers/food/drinks/bottle.dm | 73 ++---- 9 files changed, 280 insertions(+), 94 deletions(-) create mode 100644 code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 8c0b5d8438..1c74362c2e 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -74,7 +74,7 @@ avoid code duplication. This includes items that may sometimes act as a standard return 1 -//Called when a weapon is used to make a successful melee attack on a mob. +//Called when a weapon is used to make a successful melee attack on a mob. Returns the blocked result /obj/item/proc/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) if(hitsound) playsound(loc, hitsound, 50, 1, -1) diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm index dca91ac26b..eaa3433343 100644 --- a/code/game/objects/items/robot/robot_items.dm +++ b/code/game/objects/items/robot/robot_items.dm @@ -19,11 +19,11 @@ qdel(src) return + user.visible_message("\The [user] has prodded \the [M] with \a [src]!") + if(!user.cell || !user.cell.checked_use(1250)) //Slightly more than a baton. - user.visible_message("\The [user] has prodded \the [M] with its arm!") return - user.visible_message("\The [user] has prodded \the [M] with \a [src]!") playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) M.apply_effect(5, STUTTER) diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index e0cb519003..16803eac9b 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -112,8 +112,7 @@ /obj/item/weapon/melee/baton/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) if(isrobot(target)) - ..() - return + return ..() var/agony = agonyforce var/stun = stunforce @@ -123,7 +122,7 @@ affecting = H.get_organ(hit_zone) if(user.a_intent == I_HURT) - ..() + . = ..() //whacking someone causes a much poorer electrical contact than deliberately prodding them. agony *= 0.5 stun *= 0.5 diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 3bfd33b4f5..521c449999 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -237,7 +237,7 @@ ..() /obj/item/weapon/reagent_containers/food/snacks/grown/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) - ..() + . = ..() if(seed && seed.get_trait(TRAIT_STINGS)) if(!reagents || reagents.total_volume <= 0) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 997ad98b4d..83089d53da 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -178,7 +178,7 @@ emp_act var/blocked = run_armor_check(hit_zone, "melee", I.armor_penetration, "Your armor has protected your [affecting.name].", "Your armor has softened the blow to your [affecting.name].") standard_weapon_hit_effects(I, user, effective_force, blocked, hit_zone) - return 1 + return blocked /mob/living/carbon/human/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone) var/obj/item/organ/external/affecting = get_organ(hit_zone) diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm new file mode 100644 index 0000000000..691ac149bd --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm @@ -0,0 +1,232 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +//TODO: Make these simple_animals + +var/const/MIN_IMPREGNATION_TIME = 100 //time it takes to impregnate someone +var/const/MAX_IMPREGNATION_TIME = 150 + +var/const/MIN_ACTIVE_TIME = 200 //time between being dropped and going idle +var/const/MAX_ACTIVE_TIME = 400 + +/obj/item/clothing/mask/facehugger + name = "alien" + desc = "It has some sort of a tube at the end of its tail." + icon = 'icons/mob/alien.dmi' + icon_state = "facehugger" + item_state = "facehugger" + w_class = 3 //note: can be picked up by aliens unlike most other items of w_class below 4 + flags = PROXMOVE + body_parts_covered = FACE|EYES + throw_range = 5 + + var/stat = CONSCIOUS //UNCONSCIOUS is the idle state in this case + var/sterile = 0 + var/strength = 5 + var/attached = 0 + +/obj/item/clothing/mask/facehugger/attack_hand(user as mob) + + if((stat == CONSCIOUS && !sterile)) + if(Attach(user)) + return + + ..() + +/obj/item/clothing/mask/facehugger/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) + . = ..() + user.drop_from_inventory(src) + if(hit_zone == "head") + Attach(target) + +/obj/item/clothing/mask/facehugger/New() + if(config.aliens_allowed) + ..() + else + qdel(src) + +/obj/item/clothing/mask/facehugger/examine(mob/user) + ..(user) + switch(stat) + if(DEAD,UNCONSCIOUS) + user << "\red \b [src] is not moving." + if(CONSCIOUS) + user << "\red \b [src] seems to be active." + if (sterile) + user << "\red \b It looks like the proboscis has been removed." + return + +/obj/item/clothing/mask/facehugger/attackby(obj/item/I, mob/user) + if(I.force) + user.do_attack_animation(src) + Die() + return + +/obj/item/clothing/mask/facehugger/bullet_act() + Die() + return + +/obj/item/clothing/mask/facehugger/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > T0C+80) + Die() + return + +/obj/item/clothing/mask/facehugger/equipped(mob/M) + Attach(M) + +/obj/item/clothing/mask/facehugger/Crossed(atom/target) + HasProximity(target) + return + +/obj/item/clothing/mask/facehugger/on_found(mob/finder as mob) + if(stat == CONSCIOUS) + HasProximity(finder) + return 1 + return + +/obj/item/clothing/mask/facehugger/HasProximity(atom/movable/AM as mob|obj) + if(CanHug(AM)) + Attach(AM) + +/obj/item/clothing/mask/facehugger/throw_at(atom/target, range, speed) + ..() + if(stat == CONSCIOUS) + icon_state = "[initial(icon_state)]_thrown" + spawn(15) + if(icon_state == "[initial(icon_state)]_thrown") + icon_state = "[initial(icon_state)]" + +/obj/item/clothing/mask/facehugger/throw_impact(atom/hit_atom) + ..() + if(stat == CONSCIOUS) + icon_state = "[initial(icon_state)]" + throwing = 0 + GoIdle(30,100) //stunned for a few seconds - allows throwing them to be useful for positioning but not as an offensive action (unless you're setting up a trap) + +/obj/item/clothing/mask/facehugger/proc/Attach(M as mob) + + if((!iscorgi(M) && !iscarbon(M))) + return + + if(attached) + return + + var/mob/living/carbon/C = M + if(istype(C) && locate(/obj/item/organ/xenos/hivenode) in C.internal_organs) + return + + + attached++ + spawn(MAX_IMPREGNATION_TIME) + attached = 0 + + var/mob/living/L = M //just so I don't need to use : + + if(loc == L) return + if(stat != CONSCIOUS) return + if(!sterile) L.take_organ_damage(strength,0) //done here so that even borgs and humans in helmets take damage + + L.visible_message("\red \b [src] leaps at [L]'s face!") + + if(iscarbon(M)) + var/mob/living/carbon/target = L + + if(target.wear_mask) + if(prob(20)) return + var/obj/item/clothing/W = target.wear_mask + if(!W.canremove) return + target.drop_from_inventory(W) + + target.visible_message("\red \b [src] tears [W] off of [target]'s face!") + + target.equip_to_slot(src, slot_wear_mask) + target.contents += src // Monkey sanity check - Snapshot + + if(!sterile) L.Paralyse(MAX_IMPREGNATION_TIME/6) //something like 25 ticks = 20 seconds with the default settings + else if (iscorgi(M)) + var/mob/living/simple_animal/corgi/corgi = M + src.loc = corgi + corgi.facehugger = src + corgi.wear_mask = src + //C.regenerate_icons() + + GoIdle() //so it doesn't jump the people that tear it off + + spawn(rand(MIN_IMPREGNATION_TIME,MAX_IMPREGNATION_TIME)) + Impregnate(L) + + return + +/obj/item/clothing/mask/facehugger/proc/Impregnate(mob/living/target as mob) + if(!target || target.wear_mask != src || target.stat == DEAD) //was taken off or something + return + + if(!sterile) + //target.contract_disease(new /datum/disease/alien_embryo(0)) //so infection chance is same as virus infection chance + new /obj/item/alien_embryo(target) + target.status_flags |= XENO_HOST + + target.visible_message("\red \b [src] falls limp after violating [target]'s face!") + + Die() + icon_state = "[initial(icon_state)]_impregnated" + + if(iscorgi(target)) + var/mob/living/simple_animal/corgi/C = target + src.loc = get_turf(C) + C.facehugger = null + else + target.visible_message("\red \b [src] violates [target]'s face!") + return + +/obj/item/clothing/mask/facehugger/proc/GoActive() + if(stat == DEAD || stat == CONSCIOUS) + return + + stat = CONSCIOUS + icon_state = "[initial(icon_state)]" + + return + +/obj/item/clothing/mask/facehugger/proc/GoIdle(var/min_time=MIN_ACTIVE_TIME, var/max_time=MAX_ACTIVE_TIME) + if(stat == DEAD || stat == UNCONSCIOUS) + return + +/* RemoveActiveIndicators() */ + + stat = UNCONSCIOUS + icon_state = "[initial(icon_state)]_inactive" + + spawn(rand(min_time,max_time)) + GoActive() + return + +/obj/item/clothing/mask/facehugger/proc/Die() + if(stat == DEAD) + return + +/* RemoveActiveIndicators() */ + + icon_state = "[initial(icon_state)]_dead" + stat = DEAD + + src.visible_message("\red \b[src] curls up into a ball!") + + return + +/proc/CanHug(var/mob/M) + + if(iscorgi(M)) + return 1 + + if(!iscarbon(M)) + return 0 + + var/mob/living/carbon/C = M + if(istype(C) && locate(/obj/item/organ/xenos/hivenode) in C.internal_organs) + return 0 + + if(ishuman(C)) + var/mob/living/carbon/human/H = C + if(H.head && (H.head.body_parts_covered & FACE) && !(H.head.item_flags & FLEXIBLEMATERIAL)) + return 0 + return 1 diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 09852f33e0..68c506be12 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -144,35 +144,10 @@ O.emp_act(severity) ..() -/* -//Whereas attackby() handles the general case of using items on mobs, this handles the specific case of attacking a mob with an item as a weapon. -/mob/living/proc/attacked_with_item(obj/item/I, mob/living/user, var/target_zone) - if(!istype(user)) - return 0 - - ///////////////////////// - user.lastattacked = M - M.lastattacker = user - - if(!no_attack_log) - user.attack_log += "\[[time_stamp()]\] Attacked [M.name] ([M.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" - M.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" - msg_admin_attack("[key_name(user)] attacked [key_name(M)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" ) - ///////////////////////// - - user.do_attack_animation(M) - - var/hit_zone = resolve_hit_zone(I, user, target_zone) - if(hit_zone) - I.apply_hit_effect(src, user, hit_zone) - - return 1 -*/ - /mob/living/proc/resolve_item_attack(obj/item/I, mob/living/user, var/target_zone) return target_zone -//Called when the mob is hit with an item in combat. +//Called when the mob is hit with an item in combat. Returns the blocked result /mob/living/proc/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) visible_message("[src] has been [I.attack_verb.len? pick(I.attack_verb) : "attacked"] with [I.name] by [user]!") @@ -183,6 +158,8 @@ var/turf/simulated/location = get_turf(src) if(istype(location)) location.add_blood_floor(src) + return blocked + //returns 0 if the effects failed to apply for some reason, 1 otherwise. /mob/living/proc/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone) if(!effective_force || blocked >= 2) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index aaa71b3cb1..563ebb06f1 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -294,19 +294,22 @@ /mob/living/simple_animal/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone) - if(O.force > resistance) - var/damage = O.force - if (O.damtype == HALLOSS) - damage = 0 - if(supernatural && istype(O,/obj/item/weapon/nullrod)) - damage *= 2 - purge = 3 - adjustBruteLoss(damage) - else - user << "This weapon is ineffective, it does no damage." - visible_message("\The [src] has been attacked with \the [O] by [user].") + if(O.force <= resistance) + user << "This weapon is ineffective, it does no damage." + return 2 + + var/damage = O.force + if (O.damtype == HALLOSS) + damage = 0 + if(supernatural && istype(O,/obj/item/weapon/nullrod)) + damage *= 2 + purge = 3 + adjustBruteLoss(damage) + + return 0 + /mob/living/simple_animal/movement_delay() var/tally = 0 //Incase I need to add stuff other than "speed" later diff --git a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm index 396a35e1ec..a0731a8ce4 100644 --- a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm +++ b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm @@ -136,59 +136,34 @@ else set_light(0) -/obj/item/weapon/reagent_containers/food/drinks/bottle/attack(mob/living/target as mob, mob/living/user as mob) - if(!target) +/obj/item/weapon/reagent_containers/food/drinks/bottle/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) + var/blocked = ..() + + if(user.a_intent != I_HURT) return - - if(user.a_intent != I_HURT || !isGlass) - return ..() - - var/affecting = user.zone_sel.selecting //Find what the player is aiming at - - var/armor_block = 0 //Get the target's armour values for normal attack damage. - var/armor_duration = 0 //The more force the bottle has, the longer the duration. - - //Calculating duration and calculating damage. - armor_block = target.run_armor_check(affecting, "melee") - - //force will counteract armour, but will never increase duration - armor_duration = smash_duration + min(0, force - target.getarmor(affecting, "melee") + 10) - - //Apply the damage! - target.apply_damage(force, BRUTE, affecting, armor_block, sharp=0) - + if(!smash_check(1)) + return //won't always break on the first hit + // You are going to knock someone out for longer if they are not wearing a helmet. - var/do_smash = smash_check(1) //won't always break on the first hit - var/mob/living/carbon/human/H = target - if(do_smash && istype(H) && H.headcheck(affecting)) - //Display an attack message. - var/obj/item/organ/O = H.get_organ(affecting) - user.visible_message("[user] smashes [src] into [H]'s [O.name]!") - //Weaken the target for the duration that we calculated and divide it by 5. - if(armor_duration) - target.apply_effect(min(armor_duration, 5) , WEAKEN, armor_block) // Never weaken more than a flash! + var/weaken_duration = 0 + if(blocked < 2) + weaken_duration = smash_duration + min(0, force - target.getarmor(hit_zone, "melee") + 10) + + if(hit_zone == "head" && istype(target, /mob/living/carbon/)) + user.visible_message("\The [user] smashes [src] over [target]'s head!") + if(weaken_duration) + target.apply_effect(min(weaken_duration, 5), WEAKEN, blocked) // Never weaken more than a flash! else - //Default attack message and don't weaken the target. - for(var/mob/O in viewers(user, null)) - if(target != user) O.show_message(text("\red [target] has been attacked with a bottle of [src.name], by [user]!"), 1) - else O.show_message(text("\red [target] has attacked \himself with a bottle of [src.name]!"), 1) + user.visible_message("\The [user] smashes [src] into [target]!") - //Attack logs - user.attack_log += text("\[[time_stamp()]\] Has attacked [target.name] ([target.ckey]) with a bottle!") - target.attack_log += text("\[[time_stamp()]\] Has been smashed with a bottle by [user.name] ([user.ckey])") - msg_admin_attack("[user.name] ([user.ckey]) attacked [target.name] ([target.ckey]) with a bottle. (INTENT: [uppertext(user.a_intent)]) (JMP)") + //The reagents in the bottle splash all over the target, thanks for the idea Nodrak + if(reagents) + user.visible_message("The contents of the [src] splash all over [target]!") + reagents.splash(target, reagents.total_volume) - if(do_smash) - //The reagents in the bottle splash all over the target, thanks for the idea Nodrak - if(reagents) - user.visible_message("The contents of the [src] splash all over [target]!") - reagents.splash(target, reagents.total_volume) - - //Finally, smash the bottle. This kills (qdel) the bottle. - var/obj/item/weapon/broken_bottle/B = src.smash(target.loc, target) - user.put_in_active_hand(B) - - return + //Finally, smash the bottle. This kills (qdel) the bottle. + var/obj/item/weapon/broken_bottle/B = smash(target.loc, target) + user.put_in_active_hand(B) //Keeping this here for now, I'll ask if I should keep it here. /obj/item/weapon/broken_bottle @@ -480,4 +455,4 @@ center_of_mass = list("x"=16, "y"=10) New() ..() - reagents.add_reagent("ale", 30) \ No newline at end of file + reagents.add_reagent("ale", 30)