From 593f7699db71ff23ff1b41560563cc73339c375c Mon Sep 17 00:00:00 2001 From: mwerezak Date: Sat, 25 Jul 2015 03:09:36 -0400 Subject: [PATCH 01/60] Refactors item_attack.dm Refactors and cleans up item_attack.dm and related mob attack code Conflicts: code/_onclick/item_attack.dm code/game/objects/items.dm code/modules/mob/living/bot/bot.dm code/modules/mob/living/carbon/human/human_defense.dm code/modules/mob/living/living_defense.dm code/modules/mob/living/simple_animal/simple_animal.dm --- code/_onclick/item_attack.dm | 85 +++----- code/game/objects/items.dm | 3 - code/modules/hydroponics/grown.dm | 41 ++-- code/modules/mob/living/bot/bot.dm | 1 + .../mob/living/carbon/carbon_defense.dm | 98 +++++++++ .../living/carbon/human/human_attackhand.dm | 17 -- .../mob/living/carbon/human/human_defense.dm | 187 ++++++++++-------- code/modules/mob/living/living_defense.dm | 86 ++++---- code/modules/mob/living/silicon/silicon.dm | 3 - .../mob/living/simple_animal/simple_animal.dm | 6 +- polaris.dme | 1 + 11 files changed, 275 insertions(+), 253 deletions(-) create mode 100644 code/modules/mob/living/carbon/carbon_defense.dm diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 093975051b5..94f9b7774d4 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -3,6 +3,10 @@ /obj/item/proc/attack_self(mob/user) return +/obj/item/proc/resolve_attackby(atom/A, mob/source) + add_fingerprint(source) + return A.attackby(src,source) + // No comment /atom/proc/attackby(obj/item/W, mob/user) return @@ -12,29 +16,23 @@ visible_message("[src] has been hit by [user] with [W].") /mob/living/attackby(obj/item/I, mob/user) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if(istype(I) && ismob(user)) - I.attack(src, user) - + if(!ismob(user)) + return 0 + if(can_operate(src) && do_surgery(src,user,I)) //Surgery + return 1 + if(istype(I)) + return I.attack(src, user, user.zone_sel.selecting) // Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person. // Click parameters is the params string from byond Click() code, see that documentation. /obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters) return -//TODO: refactor mob attack code. -/* -Busy writing something else that I don't want to get mixed up in a general attack code, and I don't want to forget this so leaving a note here. -leave attackby() as handling the general case of "using an item on a mob" -attackby() will decide to call attacked_by() or not. -attacked_by() will be made a living level proc and handle the specific case of "attacking with an item to cause harm" -attacked_by() will then call attack() so that stunbatons and other weapons that have special attack effects can do their thing. -attacked_by() will handle hitting/missing/logging as it does now, and will call attack() to apply the attack effects (damage) instead of the other way around (as it is now). -*/ - -/obj/item/proc/attack(mob/living/M as mob, mob/living/user as mob, def_zone) - - if(!istype(M) || (can_operate(M) && do_surgery(M,user,src))) return 0 +/obj/item/proc/attack(mob/living/M, mob/living/user, def_zone) + if(!istype(M)) + return 0 + if(!force || (flags & NOBLUDGEON)) + return 0 ///////////////////////// user.lastattacked = M @@ -46,50 +44,19 @@ attacked_by() will handle hitting/missing/logging as it does now, and will call msg_admin_attack("[key_name(user)] attacked [key_name(M)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" ) ///////////////////////// - // Attacking someone with a weapon while they are neck-grabbed - if(user.a_intent == I_HURT) - for(var/obj/item/weapon/grab/G in M.grabbed_by) - if(G.assailant == user && G.state >= GRAB_NECK) - M.attack_throat(src, G, user) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(M) + M.attacked_with_item(src, user, def_zone) + return 1 + +//Called when a weapon is used to make a successful melee attack on a mob. +/obj/item/proc/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) + if(hitsound) + playsound(loc, hitsound, 50, 1, -1) + var/power = force if(HULK in user.mutations) power *= 2 + return target.hit_with_weapon(src, user, power, hit_zone) - // TODO: needs to be refactored into a mob/living level attacked_by() proc. ~Z - user.do_attack_animation(M) - user.break_cloak() - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - - // Handle striking to cripple. - var/dislocation_str - if(user.a_intent == I_DISARM) - dislocation_str = H.attack_joint(src, user, def_zone) - if(H.attacked_by(src, user, def_zone) && hitsound) - playsound(loc, hitsound, 50, 1, -1) - spawn(1) //ugh I hate this but I don't want to root through human attack procs to print it after this call resolves. - if(dislocation_str) user.visible_message("[dislocation_str]") - return 1 - return 0 - else - if(attack_verb.len) - user.visible_message("[M] has been [pick(attack_verb)] with [src] by [user]!") - else - user.visible_message("[M] has been attacked with [src] by [user]!") - - if (hitsound) - playsound(loc, hitsound, 50, 1, -1) - switch(damtype) - if("brute") - M.take_organ_damage(power) - if(prob(33)) // Added blood for whacking non-humans too - var/turf/simulated/location = get_turf(M) - if(istype(location)) location.add_blood_floor(M) - if("fire") - if (!(COLD_RESISTANCE in M.mutations)) - M.take_organ_damage(0, power) - M << "Aargh it burns!" - M.updatehealth() - add_fingerprint(user) - return 1 diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 2493e296099..9b40cf4e8c9 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -633,6 +633,3 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out. /obj/item/proc/pwr_drain() return 0 // Process Kill -/obj/item/proc/resolve_attackby(atom/A, mob/source) - return A.attackby(src,source) - diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 7c17c584670..8528033f528 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -242,40 +242,23 @@ if(user.a_intent == I_HURT) - // This is being copypasted here because reagent_containers (WHY DOES FOOD DESCEND FROM THAT) overrides it completely. - // TODO: refactor all food paths to be less horrible and difficult to work with in this respect. ~Z - if(!istype(M) || (can_operate(M) && do_surgery(M,user,src))) return 0 + if(!istype(M)) + return 0 + if(!force || (flags & NOBLUDGEON)) + return 0 + ///////////////////////// user.lastattacked = M M.lastattacker = user - 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)])" ) - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - var/hit = H.attacked_by(src, user, def_zone) - if(hit && hitsound) - playsound(loc, hitsound, 50, 1, -1) - return hit - else - if(attack_verb.len) - user.visible_message("[M] has been [pick(attack_verb)] with [src] by [user]!") - else - user.visible_message("[M] has been attacked with [src] by [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)])" ) + ///////////////////////// - if (hitsound) - playsound(loc, hitsound, 50, 1, -1) - switch(damtype) - if("brute") - M.take_organ_damage(force) - if(prob(33)) - var/turf/simulated/location = get_turf(M) - if(istype(location)) location.add_blood_floor(M) - if("fire") - if (!(COLD_RESISTANCE in M.mutations)) - M.take_organ_damage(0, force) - M.updatehealth() + user.do_attack_animation(M) + M.attacked_with_item(src, user, def_zone) if(seed && seed.get_trait(TRAIT_STINGS)) if(!reagents || reagents.total_volume <= 0) diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm index 5679cc1a461..5eceb7c7bab 100644 --- a/code/modules/mob/living/bot/bot.dm +++ b/code/modules/mob/living/bot/bot.dm @@ -337,3 +337,4 @@ //if((dir & EAST ) && (D.dir & (NORTH|SOUTH))) return !D.check_access(ID) else return !D.check_access(ID) // it's a real, air blocking door return 0 + diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm new file mode 100644 index 00000000000..933ec801caa --- /dev/null +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -0,0 +1,98 @@ + +//Called when the mob is hit with an item in combat. +/mob/living/carbon/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) + if(check_attack_throat(I, user)) + return + ..() + +/mob/living/carbon/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone) + if(!effective_force || blocked >= 2) + return 0 + + //Hulk modifier + if(HULK in user.mutations) + effective_force *= 2 + + //Apply weapon damage + var/weapon_sharp = is_sharp(I) + var/weapon_edge = has_edge(I) + if(prob(getarmor(hit_zone, "melee"))) //melee armour provides a chance to turn sharp/edge weapon attacks into blunt ones + weapon_sharp = 0 + weapon_edge = 0 + + apply_damage(effective_force, I.damtype, hit_zone, blocked, sharp=weapon_sharp, edge=weapon_edge, used_weapon=I) + + //Melee weapon embedded object code. + if (I && I.damtype == BRUTE && !I.anchored && !is_robot_module(I)) + var/damage = effective_force + if (blocked) + damage /= blocked+1 + + //blunt objects should really not be embedding in things unless a huge amount of force is involved + var/embed_chance = weapon_sharp? damage/I.w_class : damage/(I.w_class*3) + var/embed_threshold = weapon_sharp? 5*I.w_class : 15*I.w_class + + //Sharp objects will always embed if they do enough damage. + if((weapon_sharp && damage > (10*I.w_class)) || (damage > embed_threshold && prob(embed_chance))) + src.embed(I, hit_zone) + + return 1 + +// Attacking someone with a weapon while they are neck-grabbed +/mob/living/carbon/proc/check_attack_throat(obj/item/W, mob/user) + if(user.a_intent == I_HURT) + for(var/obj/item/weapon/grab/G in src.grabbed_by) + if(G.assailant == user && G.state >= GRAB_NECK) + if(attack_throat(W, G, user)) + return 1 + return 0 + +// Knifing +/mob/living/carbon/proc/attack_throat(obj/item/W, obj/item/weapon/grab/G, mob/user) + + if(!W.edge || !W.force || W.damtype != BRUTE) + return 0 //unsuitable weapon + + user.visible_message("\The [user] begins to slit [src]'s throat with \the [W]!") + + user.next_move = world.time + 20 //also should prevent user from triggering this repeatedly + if(!do_after(user, 20)) + return 0 + if(!(G && G.assailant == user && G.affecting == src)) //check that we still have a grab + return 0 + + var/damage_mod = 1 + //presumably, if they are wearing a helmet that stops pressure effects, then it probably covers the throat as well + var/obj/item/clothing/head/helmet = get_equipped_item(slot_head) + if(istype(helmet) && (helmet.body_parts_covered & HEAD) && (helmet.flags & STOPPRESSUREDAMAGE)) + //we don't do an armor_check here because this is not an impact effect like a weapon swung with momentum, that either penetrates or glances off. + damage_mod = 1.0 - (helmet.armor["melee"]/100) + + var/total_damage = 0 + for(var/i in 1 to 3) + var/damage = min(W.force*1.5, 20)*damage_mod + apply_damage(damage, W.damtype, "head", 0, sharp=W.sharp, edge=W.edge) + total_damage += damage + + var/oxyloss = total_damage + if(total_damage >= 40) //threshold to make someone pass out + oxyloss = 60 // Brain lacks oxygen immediately, pass out + + adjustOxyLoss(min(oxyloss, 100 - getOxyLoss())) //don't put them over 100 oxyloss + + if(total_damage) + if(oxyloss >= 40) + user.visible_message("\The [user] slit [src]'s throat open with \the [W]!") + else + user.visible_message("\The [user] cut [src]'s neck with \the [W]!") + + if(W.hitsound) + playsound(loc, W.hitsound, 50, 1, -1) + + G.last_action = world.time + flick(G.hud.icon_state, G.hud) + + user.attack_log += "\[[time_stamp()]\] Knifed [name] ([ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])" + src.attack_log += "\[[time_stamp()]\] Got knifed by [user.name] ([user.ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])" + msg_admin_attack("[key_name(user)] knifed [key_name(src)] with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])" ) + return 1 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm index a38e516acf8..1d61cd6d0e6 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -310,23 +310,6 @@ updatehealth() return 1 -/mob/living/carbon/human/proc/attack_joint(var/obj/item/W, var/mob/living/user, var/def_zone) - if(!def_zone) def_zone = user.zone_sel.selecting - var/target_zone = get_zone_with_miss_chance(check_zone(def_zone), src) - - if(user == src) // Attacking yourself can't miss - target_zone = user.zone_sel.selecting - if(!target_zone) - return null - var/obj/item/organ/external/organ = get_organ(check_zone(target_zone)) - if(!organ || (organ.dislocated == 2) || (organ.dislocated == -1)) - return null - var/dislocation_str - if(prob(W.force)) - dislocation_str = "[src]'s [organ.joint] [pick("gives way","caves in","crumbles","collapses")]!" - organ.dislocate(1) - return dislocation_str - //Used to attack a joint through grabbing /mob/living/carbon/human/proc/grab_joint(var/mob/living/user, var/def_zone) var/has_grab = 0 diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 105d7be9bd2..accfed5513f 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -139,67 +139,75 @@ emp_act if(.) return return 0 -//Returns 1 if the attack hit, 0 if it missed. -/mob/living/carbon/human/proc/attacked_by(var/obj/item/I, var/mob/living/user, var/def_zone) - if(!I || !user) return 0 +/mob/living/carbon/human/emp_act(severity) + for(var/obj/O in src) + if(!O) continue + O.emp_act(severity) + ..() - var/target_zone = def_zone? check_zone(def_zone) : get_zone_with_miss_chance(user.zone_sel.selecting, src) +/mob/living/carbon/human/attacked_with_item(obj/item/I, mob/living/user, var/target_zone) + if(!I || !user) + return - if(user == src) // Attacking yourself can't miss - target_zone = user.zone_sel.selecting - if(!target_zone) - visible_message("[user] misses [src] with \the [I]!") - return 0 + if(check_attack_throat(I, user)) + return - var/obj/item/organ/external/affecting = get_organ(target_zone) + var/hit_zone = target_zone + if(user != src) // Attacking yourself can't miss + hit_zone = get_zone_with_miss_chance(target_zone, src) + if(!hit_zone) + visible_message("\The [user] misses [src] with \the [I]!") + return + + if(check_shields(I.force, I, user, target_zone, "the [I.name]")) + return + + var/obj/item/organ/external/affecting = get_organ(hit_zone) if (!affecting || affecting.is_stump()) user << "They are missing that limb!" return 0 - var/effective_force = I.force - if(user.a_intent == "disarm") effective_force = round(I.force/2) - var/hit_area = affecting.name + I.apply_hit_effect(src, user, target_zone) - if((user != src) && check_shields(effective_force, I, user, target_zone, "the [I.name]")) +/mob/living/carbon/human/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) + var/obj/item/organ/external/affecting = get_organ(hit_zone) + if(!affecting) + return //should be prevented by attacked_with_item() but for sanity. + + visible_message("[src] has been [I.attack_verb.len? pick(I.attack_verb) : "attacked"] in the [affecting.name] with [I.name] by [user]!") + + 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 + +/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) + if(!affecting) return 0 - if(istype(I,/obj/item/weapon/card/emag)) - if(!(affecting.status & ORGAN_ROBOT)) - user << "\red That limb isn't robotic." - return - if(affecting.sabotaged) - user << "\red [src]'s [affecting.name] is already sabotaged!" + // Handle striking to cripple. + if(user.a_intent == I_DISARM) + effective_force /= 2 + if(..(I, user effective_force, blocked, hit_zone)) + attack_joint(affecting, I, blocked) else - user << "\red You sneakily slide [I] into the dataport on [src]'s [affecting.name] and short out the safeties." - var/obj/item/weapon/card/emag/emag = I - emag.uses-- - affecting.sabotaged = 1 - return 1 + return 0 + else if(!..()) + return 0 - if(I.attack_verb.len) - visible_message("\red [src] has been [pick(I.attack_verb)] in the [hit_area] with [I.name] by [user]!") - else - visible_message("\red [src] has been attacked in the [hit_area] with [I.name] by [user]!") + if(effective_force > 10 || effective_force >= 5 && prob(33)) + forcesay(hit_appends) //forcesay checks stat already - var/armor = run_armor_check(affecting, "melee", I.armor_penetration, "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].") - var/weapon_sharp = is_sharp(I) - var/weapon_edge = has_edge(I) - if ((weapon_sharp || weapon_edge) && prob(getarmor(target_zone, "melee"))) - weapon_sharp = 0 - weapon_edge = 0 + if(prob(25 + (effective_force * 2))) + if(!((I.damtype == BRUTE) || (I.damtype == HALLOSS))) + return - if(armor >= 100) return 0 - if(!effective_force) return 0 - var/Iforce = effective_force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords) + if(!(I.flags & NOBLOODY)) + I.add_blood(src) - apply_damage(effective_force, I.damtype, affecting, armor, sharp=weapon_sharp, edge=weapon_edge, used_weapon=I) - - var/bloody = 0 - if(((I.damtype == BRUTE) || (I.damtype == HALLOSS)) && prob(25 + (effective_force * 2))) - I.add_blood(src) //Make the weapon bloody, not the person. -// if(user.hand) user.update_inv_l_hand() //updates the attacker's overlay for the (now bloodied) weapon -// else user.update_inv_r_hand() //removed because weapons don't have on-mob blood overlays + var/bloody = 0 if(prob(33)) bloody = 1 var/turf/location = loc @@ -212,51 +220,56 @@ emp_act H.bloody_hands(src) if(!stat) - if(headcheck(hit_area)) - //Harder to score a stun but if you do it lasts a bit longer - if(prob(effective_force)) - apply_effect(20, PARALYZE, armor) - visible_message("[src] [species.get_knockout_message(src)]") - else - //Easier to score a stun but lasts less time - if(prob(effective_force + 10)) - apply_effect(6, WEAKEN, armor) - visible_message("[src] has been knocked down!") + switch(hit_zone) + if("head")//Harder to score a stun but if you do it lasts a bit longer + if(prob(effective_force)) + apply_effect(20, PARALYZE, blocked) + visible_message("\The [src] has been knocked unconscious!") + if(bloody)//Apply blood + if(wear_mask) + wear_mask.add_blood(src) + update_inv_wear_mask(0) + if(head) + head.add_blood(src) + update_inv_head(0) + if(glasses && prob(33)) + glasses.add_blood(src) + update_inv_glasses(0) + if("chest")//Easier to score a stun but lasts less time + if(prob(effective_force + 10)) + apply_effect(6, WEAKEN, blocked) + visible_message("\The [src] has been knocked down!") + if(bloody) + bloody_body(src) - //Apply blood - if(bloody) - switch(hit_area) - if(BP_HEAD) - if(wear_mask) - wear_mask.add_blood(src) - update_inv_wear_mask(0) - if(head) - head.add_blood(src) - update_inv_head(0) - if(glasses && prob(33)) - glasses.add_blood(src) - update_inv_glasses(0) - if(BP_TORSO) - bloody_body(src) - - if(Iforce > 10 || Iforce >= 5 && prob(33)) - forcesay(hit_appends) //forcesay checks stat already - - //Melee weapon embedded object code. - if (I && I.damtype == BRUTE && !I.anchored && !is_robot_module(I)) - var/damage = effective_force - if (armor) - damage /= armor+1 - - //blunt objects should really not be embedding in things unless a huge amount of force is involved - var/embed_chance = weapon_sharp? damage/I.w_class : damage/(I.w_class*3) - var/embed_threshold = weapon_sharp? 5*I.w_class : 15*I.w_class - - //Sharp objects will always embed if they do enough damage. - if((weapon_sharp && damage > (10*I.w_class)) || (damage > embed_threshold && prob(embed_chance))) - affecting.embed(I) return 1 +/mob/living/carbon/human/proc/attack_joint(var/obj/item/organ/external/organ, var/obj/item/W, var/blocked) + if(!organ || (organ.dislocated == 2) || (organ.dislocated == -1) || blocked >= 2) + return 0 + if(prob(W.force / (blocked+1))) + visible_message("[src]'s [organ.joint] [pick("gives way","caves in","crumbles","collapses")]!") + organ.dislocate(1) + return 1 + return 0 + +//*** TODO + +/* TODO Reimplement pending cleanup +if(istype(I,/obj/item/weapon/card/emag)) + if(!(affecting.status & ORGAN_ROBOT)) + user << "\red That limb isn't robotic." + return + if(affecting.sabotaged) + user << "\red [src]'s [affecting.name] is already sabotaged!" + else + user << "\red You sneakily slide [I] into the dataport on [src]'s [affecting.name] and short out the safeties." + var/obj/item/weapon/card/emag/emag = I + emag.uses-- + affecting.sabotaged = 1 + return 1 +*/ + //this proc handles being hit by a thrown atom /mob/living/carbon/human/hitby(atom/movable/AM as mob|obj,var/speed = THROWFORCE_SPEED_DIVISOR) if(istype(AM,/obj/)) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 3966f60a209..5f96e48b8de 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -144,6 +144,41 @@ 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) + I.apply_hit_effect(src, user, target_zone) + +//Called when the mob is hit with an item in combat. +/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]!") + + var/blocked = run_armor_check(hit_zone, "melee") + standard_weapon_hit_effects(I, user, effective_force, blocked, hit_zone) + + if(I.damtype == BRUTE && prob(33)) // Added blood for whacking non-humans too + var/turf/simulated/location = get_turf(src) + if(istype(location)) location.add_blood_floor(src) + +//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) + return 0 + + //Hulk modifier + if(HULK in user.mutations) + effective_force *= 2 + + //Apply weapon damage + var/weapon_sharp = is_sharp(I) + var/weapon_edge = has_edge(I) + if(prob(max(getarmor(hit_zone, "melee") - I.armor_penetration, 0))) //melee armour provides a chance to turn sharp/edge weapon attacks into blunt ones + weapon_sharp = 0 + weapon_edge = 0 + + apply_damage(effective_force, I.damtype, hit_zone, blocked, sharp=weapon_sharp, edge=weapon_edge, used_weapon=I) + + return 1 + //this proc handles being hit by a thrown atom /mob/living/hitby(atom/movable/AM as mob|obj,var/speed = THROWFORCE_SPEED_DIVISOR)//Standardization and logging -Sieve if(istype(AM,/obj/)) @@ -370,54 +405,3 @@ hud_used.hide_actions_toggle.screen_loc = hud_used.ButtonNumberToScreenCoords(button_number+1) //hud_used.SetButtonCoords(hud_used.hide_actions_toggle,button_number+1) client.screen += hud_used.hide_actions_toggle - - -//If simple_animals are ever moved under carbon, then this can probably be moved to carbon as well -/mob/living/proc/attack_throat(obj/item/W, obj/item/weapon/grab/G, mob/user) - - // Knifing - if(!W.edge || !W.force || W.damtype != BRUTE) return //unsuitable weapon - - user.visible_message("\The [user] begins to slit [src]'s throat with \the [W]!") - - user.next_move = world.time + 20 //also should prevent user from triggering this repeatedly - if(!do_after(user, 20)) - return - if(!(G && G.assailant == user && G.affecting == src)) //check that we still have a grab - return - - var/damage_mod = 1 - //presumably, if they are wearing a helmet that stops pressure effects, then it probably covers the throat as well - var/obj/item/clothing/head/helmet = get_equipped_item(slot_head) - if(istype(helmet) && (helmet.body_parts_covered & HEAD) && (helmet.item_flags & STOPPRESSUREDAMAGE)) - //we don't do an armor_check here because this is not an impact effect like a weapon swung with momentum, that either penetrates or glances off. - damage_mod = 1.0 - (helmet.armor["melee"]/100) - - var/total_damage = 0 - for(var/i in 1 to 3) - var/damage = min(W.force*1.5, 20)*damage_mod - apply_damage(damage, W.damtype, BP_HEAD, 0, sharp=W.sharp, edge=W.edge) - total_damage += damage - - var/oxyloss = total_damage - if(total_damage >= 40) //threshold to make someone pass out - oxyloss = 60 // Brain lacks oxygen immediately, pass out - - adjustOxyLoss(min(oxyloss, 100 - getOxyLoss())) //don't put them over 100 oxyloss - - if(total_damage) - if(oxyloss >= 40) - user.visible_message("\The [user] slit [src]'s throat open with \the [W]!") - else - user.visible_message("\The [user] cut [src]'s neck with \the [W]!") - - if(W.hitsound) - playsound(loc, W.hitsound, 50, 1, -1) - - G.last_action = world.time - flick(G.hud.icon_state, G.hud) - - user.attack_log += "\[[time_stamp()]\] Knifed [name] ([ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])" - src.attack_log += "\[[time_stamp()]\] Got knifed by [user.name] ([user.ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])" - msg_admin_attack("[key_name(user)] knifed [key_name(src)] with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])" ) - return diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 0d0a83b7d1a..d670e17ee3c 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -132,9 +132,6 @@ updatehealth() return 1*/ -/mob/living/silicon/attack_throat() - return - /proc/islinked(var/mob/living/silicon/robot/bot, var/mob/living/silicon/ai/ai) if(!istype(bot) || !istype(ai)) return 0 diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 2fbad9deee4..d0a7ba2ba38 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -287,11 +287,9 @@ if(istype(O, /obj/item/weapon/material/knife) || istype(O, /obj/item/weapon/material/knife/butch)) harvest(user) else - attacked_with_item(O, user) + attacked_with_item(O, user, user.zone_sel.selecting) -//TODO: refactor mob attackby(), attacked_by(), and friends. -/mob/living/simple_animal/proc/attacked_with_item(var/obj/item/O, var/mob/user) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) +/mob/living/simple_animal/attacked_with_item(obj/item/O, mob/living/user, var/target_zone) if(!O.force) visible_message("[user] gently taps [src] with \the [O].") return diff --git a/polaris.dme b/polaris.dme index 82459576ff9..ab2cacb4f07 100644 --- a/polaris.dme +++ b/polaris.dme @@ -1305,6 +1305,7 @@ #include "code\modules\mob\living\bot\secbot.dm" #include "code\modules\mob\living\carbon\breathe.dm" #include "code\modules\mob\living\carbon\carbon.dm" +#include "code\modules\mob\living\carbon\carbon_defense.dm" #include "code\modules\mob\living\carbon\carbon_defines.dm" #include "code\modules\mob\living\carbon\carbon_powers.dm" #include "code\modules\mob\living\carbon\give.dm" From 11c5b10bb9ad1fd2c2cf61543aa49528a52d4ae3 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Sat, 25 Jul 2015 21:43:49 -0400 Subject: [PATCH 02/60] Refactors various item attack() implementations Replaced some attack() overrides with apply_hit_effect() or other attack procs where appropriate. Removed the attack() override from reagent_containers. Conflicts: code/game/objects/items/weapons/clown_items.dm code/game/objects/items/weapons/material/kitchen.dm code/game/objects/items/weapons/stunbaton.dm code/modules/mob/living/carbon/human/human_defense.dm code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm code/modules/mob/living/simple_animal/friendly/spiderbot.dm code/modules/mob/living/simple_animal/simple_animal.dm --- code/_onclick/item_attack.dm | 22 +++--- code/game/gamemodes/cult/cult_items.dm | 26 ++++--- code/game/objects/items/devices/flash.dm | 7 +- code/game/objects/items/robot/robot_items.dm | 18 ++--- .../game/objects/items/weapons/clown_items.dm | 5 +- .../objects/items/weapons/gift_wrappaper.dm | 3 +- .../weapons/material/material_weapons.dm | 4 +- .../objects/items/weapons/material/misc.dm | 1 - code/game/objects/items/weapons/stunbaton.dm | 70 +++++++------------ .../objects/items/weapons/swords_axes_etc.dm | 10 +-- code/game/objects/items/weapons/weaponry.dm | 36 ---------- code/modules/holodeck/HolodeckObjects.dm | 3 - code/modules/hydroponics/grown.dm | 59 +++++----------- .../hydroponics/trays/tray_reagents.dm | 16 +---- .../mob/living/carbon/carbon_defense.dm | 4 +- .../mob/living/carbon/human/human_defense.dm | 20 +++--- code/modules/mob/living/living_defense.dm | 28 +++++++- .../simple_animal/friendly/spiderbot.dm | 2 +- .../mob/living/simple_animal/simple_animal.dm | 13 ++-- code/modules/reagents/reagent_containers.dm | 5 -- 20 files changed, 131 insertions(+), 221 deletions(-) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 94f9b7774d4..67e9fbc0ccf 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -3,16 +3,17 @@ /obj/item/proc/attack_self(mob/user) return -/obj/item/proc/resolve_attackby(atom/A, mob/source) - add_fingerprint(source) - return A.attackby(src,source) +//I would prefer to rename this to attack(), but that would involve touching hundreds of files. +/obj/item/proc/resolve_attackby(atom/A, mob/user) + add_fingerprint(user) + return A.attackby(src, user) // No comment /atom/proc/attackby(obj/item/W, mob/user) return /atom/movable/attackby(obj/item/W, mob/user) - if(!(W.flags&NOBLUDGEON)) + if(!(W.flags & NOBLUDGEON)) visible_message("[src] has been hit by [user] with [W].") /mob/living/attackby(obj/item/I, mob/user) @@ -20,17 +21,15 @@ return 0 if(can_operate(src) && do_surgery(src,user,I)) //Surgery return 1 - if(istype(I)) - return I.attack(src, user, user.zone_sel.selecting) + return I.attack(src, user, user.zone_sel.selecting) // Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person. // Click parameters is the params string from byond Click() code, see that documentation. /obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters) return -/obj/item/proc/attack(mob/living/M, mob/living/user, def_zone) - if(!istype(M)) - return 0 +//I would prefer to rename this attack_as_weapon(), but that would involve touching hundreds of files. +/obj/item/proc/attack(mob/living/M, mob/living/user, var/target_zone) if(!force || (flags & NOBLUDGEON)) return 0 @@ -46,7 +45,10 @@ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) user.do_attack_animation(M) - M.attacked_with_item(src, user, def_zone) + + var/hit_zone = M.resolve_item_attack(src, user, target_zone) + if(hit_zone) + apply_hit_effect(M, user, hit_zone) return 1 diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm index 83b124efc90..4bef5534f36 100644 --- a/code/game/gamemodes/cult/cult_items.dm +++ b/code/game/gamemodes/cult/cult_items.dm @@ -6,23 +6,31 @@ w_class = 4 force = 30 throwforce = 10 + hitsound = 'sound/weapons/bladeslice.ogg' attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") /obj/item/weapon/melee/cultblade/cultify() return -/obj/item/weapon/melee/cultblade/attack(mob/living/target as mob, mob/living/carbon/human/user as mob) +/obj/item/weapon/melee/cultblade/attack(mob/living/M, mob/living/user, var/target_zone) if(iscultist(user)) - playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1, -1) return ..() + + var/zone = (user.hand ? "l_arm":"r_arm") + if(ishuman(user)) + var/mob/living/carbon/human/H = user + var/obj/item/organ/external/affecting = H.get_organ(zone) + user << "An unexplicable force rips through your [affecting.name], tearing the sword from your grasp!" else - user.Paralyse(5) - user << "An unexplicable force powerfully repels the sword from [target]!" - var/organ = ((user.hand ? "l_":"r_") + "arm") - var/obj/item/organ/external/affecting = user.get_organ(organ) - if(affecting.take_damage(rand(force/2, force))) //random amount of damage between half of the blade's force and the full force of the blade. - user.UpdateDamageIcon() - return + user << "An unexplicable force rips through you, tearing the sword from your grasp!" + + //random amount of damage between half of the blade's force and the full force of the blade. + user.apply_damage(rand(force/2, force), BRUTE, zone, 0) + user.Weaken(5) + + user.drop_from_inventory(src) + throw_at(get_edge_target_turf(src, pick(alldirs)), rand(1,3), throw_speed) + return 1 /obj/item/weapon/melee/cultblade/pickup(mob/living/user as mob) if(!iscultist(user)) diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm index da512f94492..58590965460 100644 --- a/code/game/objects/items/devices/flash.dm +++ b/code/game/objects/items/devices/flash.dm @@ -31,8 +31,8 @@ last_used = world.time times_used = max(0,round(times_used)) //sanity - -/obj/item/device/flash/attack(mob/living/M as mob, mob/user as mob) +//attack_as_weapon +/obj/item/device/flash/attack(mob/living/M, mob/living/user, var/target_zone) if(!user || !M) return //sanity M.attack_log += text("\[[time_stamp()]\] Has been flashed (attempt) with [src.name] by [user.name] ([user.ckey])") @@ -178,7 +178,8 @@ icon_state = "sflash" origin_tech = list(TECH_MAGNET = 2, TECH_COMBAT = 1) -/obj/item/device/flash/synthetic/attack(mob/living/M as mob, mob/user as mob) +//attack_as_weapon +/obj/item/device/flash/synthetic/attack(mob/living/M, mob/living/user, var/target_zone) ..() if(!broken) broken = 1 diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm index bf7c6eeccfb..dca91ac26b1 100644 --- a/code/game/objects/items/robot/robot_items.dm +++ b/code/game/objects/items/robot/robot_items.dm @@ -10,11 +10,7 @@ icon = 'icons/obj/decals.dmi' icon_state = "shock" -/obj/item/borg/stun/attack(var/mob/living/M, var/mob/living/silicon/robot/user) - - if(!istype(M)) - return - +/obj/item/borg/stun/apply_hit_effect(mob/living/M, mob/living/silicon/robot/user, var/hit_zone) // How the Hell. if(!istype(user)) var/mob/living/temp = user @@ -23,18 +19,16 @@ qdel(src) return - M.attack_log += text("\[[time_stamp()]\] Has been attacked with [src.name] by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to attack [M.name] ([M.ckey])") - msg_admin_attack("[user.name] ([user.ckey]) used the [src.name] to attack [M.name] ([M.ckey]) (JMP)") - 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 - if (M.stuttering < 5) - M.stuttering = 5 - M.stun_effect_act(0, 70, check_zone(user.zone_sel.selecting), src) 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) + M.stun_effect_act(0, 70, check_zone(hit_zone), src) + if(ishuman(M)) var/mob/living/carbon/human/H = M H.forcesay(hit_appends) diff --git a/code/game/objects/items/weapons/clown_items.dm b/code/game/objects/items/weapons/clown_items.dm index 0ccb1f1a242..b78c305f9a5 100644 --- a/code/game/objects/items/weapons/clown_items.dm +++ b/code/game/objects/items/weapons/clown_items.dm @@ -49,8 +49,9 @@ target.clean_blood() return -/obj/item/weapon/soap/attack(mob/target as mob, mob/user as mob) - if(target && user && ishuman(target) && ishuman(user) && !target.stat && !user.stat && user.zone_sel &&user.zone_sel.selecting == O_MOUTH) +//attack_as_weapon +/obj/item/weapon/soap/attack(mob/living/target, mob/living/user, var/target_zone) + if(target && user && ishuman(target) && ishuman(user) && !user.incapacitated() && user.zone_sel &&user.zone_sel.selecting == "mouth" ) user.visible_message("\The [user] washes \the [target]'s mouth out with soap!") return ..() diff --git a/code/game/objects/items/weapons/gift_wrappaper.dm b/code/game/objects/items/weapons/gift_wrappaper.dm index c1292ba9d15..7b896bdd546 100644 --- a/code/game/objects/items/weapons/gift_wrappaper.dm +++ b/code/game/objects/items/weapons/gift_wrappaper.dm @@ -61,7 +61,7 @@ qdel(src) /obj/item/weapon/a_gift/attack_self(mob/M as mob) - var/gift_type = pick(/obj/item/weapon/sord, + var/gift_type = pick( /obj/item/weapon/storage/wallet, /obj/item/weapon/storage/photo_album, /obj/item/weapon/storage/box/snappops, @@ -80,7 +80,6 @@ /obj/item/weapon/bikehorn, /obj/item/weapon/beach_ball, /obj/item/weapon/beach_ball/holoball, - /obj/item/weapon/banhammer, /obj/item/toy/balloon, /obj/item/toy/blink, /obj/item/toy/crossbow, diff --git a/code/game/objects/items/weapons/material/material_weapons.dm b/code/game/objects/items/weapons/material/material_weapons.dm index b7d4907f619..dc270eb62fa 100644 --- a/code/game/objects/items/weapons/material/material_weapons.dm +++ b/code/game/objects/items/weapons/material/material_weapons.dm @@ -64,9 +64,7 @@ processing_objects -= src ..() -/obj/item/weapon/material/attack() - if(!..()) - return +/obj/item/weapon/material/apply_hit_effect() if(!unbreakable) if(material.is_brittle()) health = 0 diff --git a/code/game/objects/items/weapons/material/misc.dm b/code/game/objects/items/weapons/material/misc.dm index 80d3771f0e8..1dd142f9fe8 100644 --- a/code/game/objects/items/weapons/material/misc.dm +++ b/code/game/objects/items/weapons/material/misc.dm @@ -65,7 +65,6 @@ icon = 'icons/obj/weapons.dmi' icon_state = "hoe" item_state = "hoe" - flags = CONDUCT | NOBLUDGEON force_divisor = 0.25 // 5 with weight 20 (steel) thrown_force_divisor = 0.25 // as above w_class = 2 diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index a4d771aa81e..e0cb519003b 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -102,73 +102,53 @@ user << "[src] is out of charge." add_fingerprint(user) - /obj/item/weapon/melee/baton/attack(mob/M, mob/user) if(status && (CLUMSY in user.mutations) && prob(50)) user << "You accidentally hit yourself with the [src]!" user.Weaken(30) deductcharge(hitcost) return + return ..() - if(isrobot(M)) +/obj/item/weapon/melee/baton/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) + if(isrobot(target)) ..() return var/agony = agonyforce var/stun = stunforce - var/mob/living/L = M + var/obj/item/organ/external/affecting = null + if(ishuman(target)) + var/mob/living/carbon/human/H = target + affecting = H.get_organ(hit_zone) - var/target_zone = check_zone(user.zone_sel.selecting) if(user.a_intent == I_HURT) - if (!..()) //item/attack() does it's own messaging and logs - return 0 // item/attack() will return 1 if they hit, 0 if they missed. + ..() + //whacking someone causes a much poorer electrical contact than deliberately prodding them. + agony *= 0.5 stun *= 0.5 - if(status) //Checks to see if the stunbaton is on. - agony *= 0.5 //whacking someone causes a much poorer contact than prodding them. + else if(!status) + if(affecting) + target.visible_message("[target] has been prodded in the [affecting.name] with [src] by [user]. Luckily it was off.") else - agony = 0 //Shouldn't really stun if it's off, should it? - //we can't really extract the actual hit zone from ..(), unfortunately. Just act like they attacked the area they intended to. + target.visible_message("[target] has been prodded with [src] by [user]. Luckily it was off.") else - //copied from human_defense.dm - human defence code should really be refactored some time. - if (ishuman(L)) - user.lastattacked = L //are these used at all, if we have logs? - L.lastattacker = user - - if (user != L) // Attacking yourself can't miss - target_zone = get_zone_with_miss_chance(user.zone_sel.selecting, L) - - if(!target_zone) - L.visible_message("\The [user] misses [L] with \the [src]!") - return 0 - - var/mob/living/carbon/human/H = L - var/obj/item/organ/external/affecting = H.get_organ(target_zone) - if (affecting) - if(!status) - L.visible_message("[L] has been prodded in the [affecting.name] with [src] by [user]. Luckily it was off.") - return 1 - else - H.visible_message("[L] has been prodded in the [affecting.name] with [src] by [user]!") + if(affecting) + target.visible_message("[target] has been prodded in the [affecting.name] with [src] by [user]!") else - if(!status) - L.visible_message("[L] has been prodded with [src] by [user]. Luckily it was off.") - return 1 - else - L.visible_message("[L] has been prodded with [src] by [user]!") + target.visible_message("[target] has been prodded with [src] by [user]!") + playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) //stun effects - L.stun_effect_act(stun, agony, target_zone, src) + if(status) + target.stun_effect_act(stun, agony, hit_zone, src) + msg_admin_attack("[key_name(user)] stunned [key_name(target)] with the [src].") - playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) - msg_admin_attack("[key_name(user)] stunned [key_name(L)] with the [src].") + deductcharge(hitcost) - deductcharge(hitcost) - - if(ishuman(L)) - var/mob/living/carbon/human/H = L - H.forcesay(hit_appends) - - return 1 + if(ishuman(target)) + var/mob/living/carbon/human/H = target + H.forcesay(hit_appends) /obj/item/weapon/melee/baton/emp_act(severity) if(bcell) diff --git a/code/game/objects/items/weapons/swords_axes_etc.dm b/code/game/objects/items/weapons/swords_axes_etc.dm index c773f3da383..94c55de5b01 100644 --- a/code/game/objects/items/weapons/swords_axes_etc.dm +++ b/code/game/objects/items/weapons/swords_axes_etc.dm @@ -1,18 +1,10 @@ /* Weapons * Contains: - * Banhammer * Sword * Classic Baton */ -/* - * Banhammer - */ -/obj/item/weapon/banhammer/attack(mob/M as mob, mob/user as mob) - M << " You have been banned FOR NO REISIN by [user]" - user << " You have BANNED [M]" - -/* +/* * Classic Baton */ /obj/item/weapon/melee/classic_baton diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index 35302dc5dcd..fa698f97edb 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -1,18 +1,3 @@ -/obj/item/weapon/banhammer - desc = "banhammer" - name = "banhammer" - icon = 'icons/obj/items.dmi' - icon_state = "toyhammer" - slot_flags = SLOT_BELT - throwforce = 0 - w_class = 2.0 - throw_speed = 7 - throw_range = 15 - attack_verb = list("banned") - - suicide_act(mob/user) - viewers(user) << "[user] is hitting \himself with the [src.name]! It looks like \he's trying to ban \himself from life." - return (BRUTELOSS|FIRELOSS|TOXLOSS|OXYLOSS) /obj/item/weapon/nullrod name = "null rod" @@ -68,27 +53,6 @@ user << "You hit the floor with the [src]." call(/obj/effect/rune/proc/revealrunes)(src) -/obj/item/weapon/sord - name = "\improper SORD" - desc = "This thing is so unspeakably shitty you are having a hard time even holding it." - icon_state = "sord" - item_state = "sord" - slot_flags = SLOT_BELT - force = 2 - throwforce = 1 - sharp = 1 - edge = 1 - w_class = 3 - attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - - suicide_act(mob/user) - viewers(user) << "[user] is impaling \himself with the [src.name]! It looks like \he's trying to commit suicide." - return(BRUTELOSS) - -/obj/item/weapon/sord/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) - playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1, -1) - return ..() - /obj/item/weapon/energy_net name = "energy net" desc = "It's a net made of green energy." diff --git a/code/modules/holodeck/HolodeckObjects.dm b/code/modules/holodeck/HolodeckObjects.dm index bc0f1a376c9..f9536420e26 100644 --- a/code/modules/holodeck/HolodeckObjects.dm +++ b/code/modules/holodeck/HolodeckObjects.dm @@ -263,9 +263,6 @@ return 1 return 0 -/obj/item/weapon/holo/esword/attack(target as mob, mob/user as mob) - ..() - /obj/item/weapon/holo/esword/New() item_color = pick("red","blue","green","purple") diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 8528033f528..3bfd33b4f56 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -236,49 +236,22 @@ return ..() -/obj/item/weapon/reagent_containers/food/snacks/grown/attack(var/mob/living/carbon/M, var/mob/user, var/def_zone) - if(user == M) - return ..() - - if(user.a_intent == I_HURT) - - if(!istype(M)) - return 0 - if(!force || (flags & NOBLUDGEON)) - 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) - M.attacked_with_item(src, user, def_zone) - - if(seed && seed.get_trait(TRAIT_STINGS)) - if(!reagents || reagents.total_volume <= 0) - return - reagents.remove_any(rand(1,3)) - seed.thrown_at(src,M) - sleep(-1) - if(!src) - return - if(prob(35)) - if(user) - user << "\The [src] has fallen to bits." - user.removeItem(src) - qdel(src) - - add_fingerprint(user) - return 1 - - else - ..() +/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) + return + reagents.remove_any(rand(1,3)) + seed.thrown_at(src, target) + sleep(-1) + if(!src) + return + if(prob(35)) + if(user) + user << "\The [src] has fallen to bits." + user.drop_from_inventory(src) + qdel(src) /obj/item/weapon/reagent_containers/food/snacks/grown/attack_self(mob/user as mob) diff --git a/code/modules/hydroponics/trays/tray_reagents.dm b/code/modules/hydroponics/trays/tray_reagents.dm index 818bbd3b15f..ba2013812ab 100644 --- a/code/modules/hydroponics/trays/tray_reagents.dm +++ b/code/modules/hydroponics/trays/tray_reagents.dm @@ -48,20 +48,6 @@ toxicity = 8 pest_kill_str = 7 -/obj/item/weapon/material/minihoe // -- Numbers - name = "mini hoe" - desc = "It's used for removing weeds or scratching your back." - icon = 'icons/obj/weapons.dmi' - icon_state = "hoe" - item_state = "hoe" - flags = CONDUCT | NOBLUDGEON - force = 5.0 - throwforce = 7.0 - w_class = 2.0 - matter = list(DEFAULT_WALL_MATERIAL = 50) - attack_verb = list("slashed", "sliced", "cut", "clawed") - - // ************************************* // Weedkiller defines for hydroponics // ************************************* @@ -92,4 +78,4 @@ icon = 'icons/obj/chemical.dmi' icon_state = "bottle15" toxicity = 8 - weed_kill_str = 7 \ No newline at end of file + weed_kill_str = 7 diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 933ec801caa..b4d9d1614d8 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -1,8 +1,8 @@ //Called when the mob is hit with an item in combat. -/mob/living/carbon/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) +/mob/living/carbon/resolve_item_attack(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) if(check_attack_throat(I, user)) - return + return null ..() /mob/living/carbon/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index accfed5513f..fc9e40e550c 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -145,20 +145,18 @@ emp_act O.emp_act(severity) ..() -/mob/living/carbon/human/attacked_with_item(obj/item/I, mob/living/user, var/target_zone) - if(!I || !user) - return - +/mob/living/carbon/human/resolve_item_attack(obj/item/I, mob/living/user, var/target_zone) if(check_attack_throat(I, user)) - return + return null - var/hit_zone = target_zone - if(user != src) // Attacking yourself can't miss - hit_zone = get_zone_with_miss_chance(target_zone, src) + if(user == src) // Attacking yourself can't miss + return target_zone + + var/hit_zone = get_zone_with_miss_chance(target_zone, src) if(!hit_zone) visible_message("\The [user] misses [src] with \the [I]!") - return + return null if(check_shields(I.force, I, user, target_zone, "the [I.name]")) return @@ -166,9 +164,9 @@ emp_act var/obj/item/organ/external/affecting = get_organ(hit_zone) if (!affecting || affecting.is_stump()) user << "They are missing that limb!" - return 0 + return null - I.apply_hit_effect(src, user, target_zone) + return hit_zone /mob/living/carbon/human/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) var/obj/item/organ/external/affecting = get_organ(hit_zone) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 5f96e48b8de..09852f33e0c 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -144,9 +144,33 @@ 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) - I.apply_hit_effect(src, user, 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. /mob/living/proc/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) @@ -154,7 +178,7 @@ var/blocked = run_armor_check(hit_zone, "melee") standard_weapon_hit_effects(I, user, effective_force, blocked, hit_zone) - + if(I.damtype == BRUTE && prob(33)) // Added blood for whacking non-humans too var/turf/simulated/location = get_turf(src) if(istype(location)) location.add_blood_floor(src) diff --git a/code/modules/mob/living/simple_animal/friendly/spiderbot.dm b/code/modules/mob/living/simple_animal/friendly/spiderbot.dm index db6eb8f4b7f..394dd742acf 100644 --- a/code/modules/mob/living/simple_animal/friendly/spiderbot.dm +++ b/code/modules/mob/living/simple_animal/friendly/spiderbot.dm @@ -130,7 +130,7 @@ return 0 else - attacked_with_item(O, user) + O.attack(src, user, user.zone_sel.selecting) /mob/living/simple_animal/spiderbot/emag_act(var/remaining_charges, var/mob/user) if (emagged) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index d0a7ba2ba38..aaa71b3cb13 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -287,12 +287,12 @@ if(istype(O, /obj/item/weapon/material/knife) || istype(O, /obj/item/weapon/material/knife/butch)) harvest(user) else - attacked_with_item(O, user, user.zone_sel.selecting) + if(!O.force) + visible_message("[user] gently taps [src] with \the [O].") + else + O.attack(src, user, user.zone_sel.selecting) -/mob/living/simple_animal/attacked_with_item(obj/item/O, mob/living/user, var/target_zone) - if(!O.force) - visible_message("[user] gently taps [src] with \the [O].") - return +/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 @@ -303,10 +303,9 @@ purge = 3 adjustBruteLoss(damage) else - usr << "This weapon is ineffective, it does no damage." + user << "This weapon is ineffective, it does no damage." visible_message("\The [src] has been attacked with \the [O] by [user].") - user.do_attack_animation(src) /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.dm b/code/modules/reagents/reagent_containers.dm index f98d90b248e..04b31d43c45 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -25,11 +25,6 @@ /obj/item/weapon/reagent_containers/attack_self(mob/user as mob) return -/obj/item/weapon/reagent_containers/attack(mob/M as mob, mob/user as mob, def_zone) - if(can_operate(M))//Checks if mob is lying down on table for surgery - if(do_surgery(M, user, src)) - return - /obj/item/weapon/reagent_containers/afterattack(obj/target, mob/user, flag) return From 3c22e65399305a966a535c3fcc17b1d3f46b6589 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Tue, 8 Sep 2015 23:41:50 -0400 Subject: [PATCH 03/60] Adds some documentation to item_attack.dm --- code/_onclick/item_attack.dm | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 67e9fbc0ccf..95421ced48d 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -1,3 +1,23 @@ +/* +=== Item Click Call Sequences === +These are the default click code call sequences used when clicking on stuff with an item. + +Atoms: + +mob/ClickOn() calls the item's resolve_attackby() proc. +item/resolve_attackby() calls the target atom's attackby() proc. + +Mobs: + +mob/living/attackby() after checking for surgery, calls the item's attack() proc. +item/attack() generates attack logs and calls the mob's attacked_with_item() proc. +mob/attacked_with_item() should then do mob-type specific stuff (like determining hit/miss, handling shields, etc) and then possibly call the item's apply_hit_effect() proc to actually apply the effects of being hit. + +Item Hit Effects: + +item/apply_hit_effect() can be overriden to do whatever you want. However "standard" physical damage based weapons should make use of the target mob's hit_with_weapon() proc to +avoid code duplication. This includes items that may sometimes act as a standard weapon in addition to having other effects (e.g. stunbatons on harm intent). +*/ // Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown. /obj/item/proc/attack_self(mob/user) From d4cbc491324fdf5d39a600d13476f03d8433fce2 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Tue, 8 Sep 2015 23:51:40 -0400 Subject: [PATCH 04/60] Prevents attacking yourself with items unless on harm intent --- code/_onclick/item_attack.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 95421ced48d..8c0b5d84382 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -52,6 +52,8 @@ avoid code duplication. This includes items that may sometimes act as a standard /obj/item/proc/attack(mob/living/M, mob/living/user, var/target_zone) if(!force || (flags & NOBLUDGEON)) return 0 + if(M == user && user.a_intent != I_HURT) + return 0 ///////////////////////// user.lastattacked = M From c0ac25ec4b9b8c9c57ad072f5fba05988d628352 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Wed, 9 Sep 2015 02:30:15 -0400 Subject: [PATCH 05/60] Refactors robolimb emagging, fixes emag resolve_attackby not passing emag_source --- .../mob/living/carbon/human/human_defense.dm | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index fc9e40e550c..997ad98b4d9 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -251,22 +251,17 @@ emp_act return 1 return 0 -//*** TODO - -/* TODO Reimplement pending cleanup -if(istype(I,/obj/item/weapon/card/emag)) - if(!(affecting.status & ORGAN_ROBOT)) - user << "\red That limb isn't robotic." - return +/mob/living/carbon/human/emag_act(var/remaining_charges, mob/user, var/emag_source) + var/obj/item/organ/external/affecting = get_organ(user.zone_sel.selecting) + if(!affecting || !(affecting.status & ORGAN_ROBOT)) + user << "That limb isn't robotic." + return -1 if(affecting.sabotaged) - user << "\red [src]'s [affecting.name] is already sabotaged!" - else - user << "\red You sneakily slide [I] into the dataport on [src]'s [affecting.name] and short out the safeties." - var/obj/item/weapon/card/emag/emag = I - emag.uses-- - affecting.sabotaged = 1 + user << "[src]'s [affecting.name] is already sabotaged!" + return -1 + user << "You sneakily slide [emag_source] into the dataport on [src]'s [affecting.name] and short out the safeties." + affecting.sabotaged = 1 return 1 -*/ //this proc handles being hit by a thrown atom /mob/living/carbon/human/hitby(atom/movable/AM as mob|obj,var/speed = THROWFORCE_SPEED_DIVISOR) From 9ef3df66e372c8273aff3620ce087a8776ba7a42 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Wed, 9 Sep 2015 13:22:17 -0400 Subject: [PATCH 06/60] Fixes missing ..() --- code/game/objects/items/weapons/material/material_weapons.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/game/objects/items/weapons/material/material_weapons.dm b/code/game/objects/items/weapons/material/material_weapons.dm index dc270eb62fa..2c634589e29 100644 --- a/code/game/objects/items/weapons/material/material_weapons.dm +++ b/code/game/objects/items/weapons/material/material_weapons.dm @@ -65,6 +65,7 @@ ..() /obj/item/weapon/material/apply_hit_effect() + ..() if(!unbreakable) if(material.is_brittle()) health = 0 From deb215d262caedfa368619bb3364a2bfc0f10e15 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Wed, 9 Sep 2015 13:39:18 -0400 Subject: [PATCH 07/60] 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 8c0b5d84382..1c74362c2ea 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 dca91ac26b1..eaa34333432 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 e0cb519003b..16803eac9bd 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 3bfd33b4f56..521c4499995 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 997ad98b4d9..83089d53dab 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 00000000000..691ac149bdf --- /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 09852f33e0c..68c506be12d 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 aaa71b3cb13..563ebb06f13 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 396a35e1ec5..a0731a8ce4b 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) From 4951790b5080ac8317e9e3d40c8d95ac83c68010 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Wed, 9 Sep 2015 15:13:30 -0400 Subject: [PATCH 08/60] Fixes missing cooldowns, missing cult blade sound. Conflicts: code/game/objects/items/weapons/material/kitchen.dm --- code/__defines/mobs.dm | 2 +- code/_onclick/item_attack.dm | 2 +- code/game/gamemodes/cult/cult_items.dm | 10 +++++-- code/game/objects/items.dm | 3 ++ code/game/objects/items/devices/flash.dm | 6 ++++ code/game/objects/items/devices/flashlight.dm | 2 ++ .../game/objects/items/weapons/clown_items.dm | 1 + .../objects/items/weapons/dna_injector.dm | 3 ++ code/game/objects/items/weapons/explosives.dm | 1 + code/game/objects/items/weapons/handcuffs.dm | 5 +++- .../items/weapons/implants/implanter.dm | 10 +++---- .../objects/items/weapons/material/kitchen.dm | 7 ----- .../objects/items/weapons/swords_axes_etc.dm | 28 +------------------ code/game/objects/items/weapons/tools.dm | 2 +- code/game/objects/items/weapons/weaponry.dm | 3 ++ .../structures/stool_bed_chair_nest/stools.dm | 3 ++ .../clothing/under/accessories/badges.dm | 4 ++- code/modules/library/lib_items.dm | 1 + code/modules/projectiles/gun.dm | 4 +-- .../reagents/reagent_containers/hypospray.dm | 2 ++ .../reagents/reagent_containers/syringes.dm | 3 ++ 21 files changed, 53 insertions(+), 49 deletions(-) diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index 98ad3b28ca9..0d1a04d4e22 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -180,4 +180,4 @@ #define MOB_PULL_NONE 0 #define MOB_PULL_SMALLER 1 #define MOB_PULL_SAME 2 -#define MOB_PULL_LARGER 3 \ No newline at end of file +#define MOB_PULL_LARGER 3 diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 1c74362c2ea..3c65b03f736 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -10,7 +10,7 @@ item/resolve_attackby() calls the target atom's attackby() proc. Mobs: mob/living/attackby() after checking for surgery, calls the item's attack() proc. -item/attack() generates attack logs and calls the mob's attacked_with_item() proc. +item/attack() generates attack logs, sets click cooldown and calls the mob's attacked_with_item() proc. If you override this, consider whether you need to set a click cooldown, play attack animations, and generate logs yourself. mob/attacked_with_item() should then do mob-type specific stuff (like determining hit/miss, handling shields, etc) and then possibly call the item's apply_hit_effect() proc to actually apply the effects of being hit. Item Hit Effects: diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm index 4bef5534f36..7a7ecbcf4ef 100644 --- a/code/game/gamemodes/cult/cult_items.dm +++ b/code/game/gamemodes/cult/cult_items.dm @@ -20,16 +20,20 @@ if(ishuman(user)) var/mob/living/carbon/human/H = user var/obj/item/organ/external/affecting = H.get_organ(zone) - user << "An unexplicable force rips through your [affecting.name], tearing the sword from your grasp!" + user << "An unexplicable force rips through your [affecting.name], tearing the sword from your grasp!" else - user << "An unexplicable force rips through you, tearing the sword from your grasp!" + user << "An unexplicable force rips through you, tearing the sword from your grasp!" //random amount of damage between half of the blade's force and the full force of the blade. - user.apply_damage(rand(force/2, force), BRUTE, zone, 0) + user.apply_damage(rand(force/2, force), BRUTE, zone, 0, sharp=1, edge=1) user.Weaken(5) user.drop_from_inventory(src) throw_at(get_edge_target_turf(src, pick(alldirs)), rand(1,3), throw_speed) + + var/spooky = pick('sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg', 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/wail.ogg') + playsound(loc, spooky, 50, 1) + return 1 /obj/item/weapon/melee/cultblade/pickup(mob/living/user as mob) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 9b40cf4e8c9..4d04c7b3aa4 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -453,6 +453,9 @@ var/list/global/slot_flags_enumeration = list( M.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])" msg_admin_attack("[user.name] ([user.ckey]) attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)]) (JMP)") //BS12 EDIT ALG + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(M) + src.add_fingerprint(user) //if((CLUMSY in user.mutations) && prob(50)) // M = user diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm index 58590965460..7a8740c2871 100644 --- a/code/game/objects/items/devices/flash.dm +++ b/code/game/objects/items/devices/flash.dm @@ -39,6 +39,9 @@ user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to flash [M.name] ([M.ckey])") msg_admin_attack("[user.name] ([user.ckey]) Used the [src.name] to flash [M.name] ([M.ckey]) (JMP)") + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(M) + if(!clown_check(user)) return if(broken) user << "\The [src] is broken." @@ -112,6 +115,9 @@ /obj/item/device/flash/attack_self(mob/living/carbon/user as mob, flag = 0, emp = 0) if(!user || !clown_check(user)) return + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(broken) user.show_message("The [src.name] is broken", 2) return diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index c7f90e97468..f0c70dde9ad 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -79,6 +79,8 @@ user << "\The [M]'s pupils narrow slightly, but are still very dilated." else user << "\The [M]'s pupils narrow." + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //can be used offensively flick("flash", M.flash) else return ..() diff --git a/code/game/objects/items/weapons/clown_items.dm b/code/game/objects/items/weapons/clown_items.dm index b78c305f9a5..2b7307f6ff1 100644 --- a/code/game/objects/items/weapons/clown_items.dm +++ b/code/game/objects/items/weapons/clown_items.dm @@ -53,6 +53,7 @@ /obj/item/weapon/soap/attack(mob/living/target, mob/living/user, var/target_zone) if(target && user && ishuman(target) && ishuman(user) && !user.incapacitated() && user.zone_sel &&user.zone_sel.selecting == "mouth" ) user.visible_message("\The [user] washes \the [target]'s mouth out with soap!") + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) //prevent spam return ..() diff --git a/code/game/objects/items/weapons/dna_injector.dm b/code/game/objects/items/weapons/dna_injector.dm index 5e2cb1946d4..2c1292fad89 100644 --- a/code/game/objects/items/weapons/dna_injector.dm +++ b/code/game/objects/items/weapons/dna_injector.dm @@ -114,6 +114,9 @@ if(!do_after(user,50)) return + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + user.do_attack_animation(M) + M.visible_message("\The [M] has been injected with \the [src] by \the [user].") var/mob/living/carbon/human/H = M diff --git a/code/game/objects/items/weapons/explosives.dm b/code/game/objects/items/weapons/explosives.dm index 8e3fed202d8..6f5e2d3d53c 100644 --- a/code/game/objects/items/weapons/explosives.dm +++ b/code/game/objects/items/weapons/explosives.dm @@ -46,6 +46,7 @@ if (ismob(target) || istype(target, /turf/unsimulated) || istype(target, /turf/simulated/shuttle) || istype(target, /obj/item/weapon/storage/) || istype(target, /obj/item/clothing/accessory/storage/) || istype(target, /obj/item/clothing/under)) return user << "Planting explosives..." + user.do_attack_animation(target) if(do_after(user, 50) && in_range(user, target)) user.drop_item() diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm index 4b43cc26018..ce2384ccb38 100644 --- a/code/game/objects/items/weapons/handcuffs.dm +++ b/code/game/objects/items/weapons/handcuffs.dm @@ -74,6 +74,9 @@ msg_admin_attack("[key_name(user)] attempted to handcuff [key_name(H)]") feedback_add_details("handcuffs","H") + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(H) + user.visible_message("\The [user] has put [cuff_type] on \the [H]!") // Apply cuffs. @@ -166,4 +169,4 @@ var/last_chew = 0 item_state = null icon = 'icons/obj/bureaucracy.dmi' breakouttime = 200 - cuff_type = "duct tape" \ No newline at end of file + cuff_type = "duct tape" diff --git a/code/game/objects/items/weapons/implants/implanter.dm b/code/game/objects/items/weapons/implants/implanter.dm index 8011d258591..da7f1b1401e 100644 --- a/code/game/objects/items/weapons/implants/implanter.dm +++ b/code/game/objects/items/weapons/implants/implanter.dm @@ -30,18 +30,18 @@ if (!istype(M, /mob/living/carbon)) return if (user && src.imp) - for (var/mob/O in viewers(M, null)) - O.show_message("[user] is attemping to implant [M].", 1) + M.visible_message("[user] is attemping to implant [M].") + + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + user.do_attack_animation(M) var/turf/T1 = get_turf(M) if (T1 && ((M == user) || do_after(user, 50))) if(user && M && (get_turf(M) == T1) && src && src.imp) - for (var/mob/O in viewers(M, null)) - O.show_message("[M] has been implanted by [user].", 1) + M.visible_message("[M] has been implanted by [user].") admin_attack_log(user, M, "Implanted using \the [src.name] ([src.imp.name])", "Implanted with \the [src.name] ([src.imp.name])", "used an implanter, [src.name] ([src.imp.name]), on") - user.show_message("You implanted the implant into [M].") if(src.imp.implanted(M)) src.imp.loc = M src.imp.imp_in = M diff --git a/code/game/objects/items/weapons/material/kitchen.dm b/code/game/objects/items/weapons/material/kitchen.dm index b5c966ebd5d..d4f45187802 100644 --- a/code/game/objects/items/weapons/material/kitchen.dm +++ b/code/game/objects/items/weapons/material/kitchen.dm @@ -101,13 +101,6 @@ return return ..() -/obj/item/weapon/material/kitchen/utensil/knife/attack(target as mob, mob/living/user as mob) - if ((CLUMSY in user.mutations) && prob(50)) - user << "You somehow managed to cut yourself with \the [src]." - user.take_organ_damage(20) - return - return ..() - /obj/item/weapon/material/kitchen/utensil/knife/plastic default_material = "plastic" diff --git a/code/game/objects/items/weapons/swords_axes_etc.dm b/code/game/objects/items/weapons/swords_axes_etc.dm index 94c55de5b01..b289e792572 100644 --- a/code/game/objects/items/weapons/swords_axes_etc.dm +++ b/code/game/objects/items/weapons/swords_axes_etc.dm @@ -26,33 +26,7 @@ else user.take_organ_damage(2*force) return -/*this is already called in ..() - src.add_fingerprint(user) - M.attack_log += text("\[[time_stamp()]\] Has been attacked with [src.name] by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to attack [M.name] ([M.ckey])") - - log_attack("[user.name] ([user.ckey]) attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])") -*/ - if (user.a_intent == I_HURT) - if(!..()) return - //playsound(src.loc, "swing_hit", 50, 1, -1) - if (M.stuttering < 8 && (!(HULK in M.mutations)) /*&& (!istype(H:wear_suit, /obj/item/clothing/suit/judgerobe))*/) - M.stuttering = 8 - M.Stun(8) - M.Weaken(8) - for(var/mob/O in viewers(M)) - if (O.client) O.show_message("\The [M] has been beaten with \the [src] by [user]!", 1, "You hear someone fall", 2) - else - playsound(src.loc, 'sound/weapons/Genhit.ogg', 50, 1, -1) - M.Stun(5) - M.Weaken(5) - M.attack_log += text("\[[time_stamp()]\] Has been attacked with [src.name] by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to attack [M.name] ([M.ckey])") - msg_admin_attack("[key_name(user)] attacked [key_name(user)] with [src.name] (INTENT: [uppertext(user.a_intent)])") - src.add_fingerprint(user) - - for(var/mob/O in viewers(M)) - if (O.client) O.show_message("\The [M] has been stunned with \the [src] by [user]!", 1, "You hear someone fall", 2) + return ..() //Telescopic baton /obj/item/weapon/melee/telebaton diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index fe1e62caa02..83d3296981c 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -115,7 +115,7 @@ item_state = "cutters_yellow" /obj/item/weapon/wirecutters/attack(mob/living/carbon/C as mob, mob/user as mob) - if((C.handcuffed) && (istype(C.handcuffed, /obj/item/weapon/handcuffs/cable))) + if(user.a_intent == I_HELP && (C.handcuffed) && (istype(C.handcuffed, /obj/item/weapon/handcuffs/cable))) usr.visible_message("\The [usr] cuts \the [C]'s restraints with \the [src]!",\ "You cut \the [C]'s restraints with \the [src]!",\ "You hear cable being cut.") diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index fa698f97edb..0f5cebc44da 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -22,6 +22,9 @@ msg_admin_attack("[user.name] ([user.ckey]) attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)]) (JMP)") + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(M) + if (!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") user << "You don't have the dexterity to do this!" return diff --git a/code/game/objects/structures/stool_bed_chair_nest/stools.dm b/code/game/objects/structures/stool_bed_chair_nest/stools.dm index a579ceab8e8..8fed533bb6b 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/stools.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/stools.dm @@ -72,6 +72,9 @@ var/global/list/stool_cache = list() //haha stool /obj/item/weapon/stool/attack(mob/M as mob, mob/user as mob) if (prob(5) && istype(M,/mob/living)) user.visible_message("[user] breaks [src] over [M]'s back!") + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(M) + user.removeItem(src) dismantle() qdel(src) diff --git a/code/modules/clothing/under/accessories/badges.dm b/code/modules/clothing/under/accessories/badges.dm index b78b0ffac3c..2908a7b639d 100644 --- a/code/modules/clothing/under/accessories/badges.dm +++ b/code/modules/clothing/under/accessories/badges.dm @@ -38,6 +38,8 @@ /obj/item/clothing/accessory/badge/attack(mob/living/carbon/human/M, mob/living/user) if(isliving(user)) user.visible_message("[user] invades [M]'s personal space, thrusting [src] into their face insistently.","You invade [M]'s personal space, thrusting [src] into their face insistently.") + user.do_attack_animation(M) + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) //to prevent spam //.Holobadges. /obj/item/clothing/accessory/badge/holo @@ -127,4 +129,4 @@ new /obj/item/clothing/accessory/badge/holo/hos(src) new /obj/item/clothing/accessory/badge/holo/cord(src) ..() - return \ No newline at end of file + return diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm index 3dbb74d9335..ba96ada8b7f 100644 --- a/code/modules/library/lib_items.dm +++ b/code/modules/library/lib_items.dm @@ -256,6 +256,7 @@ user.visible_message("You open up the book and show it to [M]. ", \ " [user] opens up a book and shows it to [M]. ") M << browse("Penned by [author].
" + "[dat]", "window=book") + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) //to prevent spam /* diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index de6c67446ef..bc28b4577bd 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -214,7 +214,7 @@ admin_attack_log(usr, attacker_message="Fired [src]", admin_message="fired a gun ([src]) (MODE: [src.mode_name]) [reflex ? "by reflex" : "manually"].") //update timing - user.setClickCooldown(4) + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) user.setMoveCooldown(move_delay) next_fire_time = world.time + fire_delay @@ -419,4 +419,4 @@ return new_mode /obj/item/weapon/gun/attack_self(mob/user) - switch_firemodes(user) \ No newline at end of file + switch_firemodes(user) diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 7632f8456fc..28b4704fdd7 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -37,6 +37,8 @@ user << "You cannot inject a robotic limb." return + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + user.do_attack_animation(M) user << "You inject [M] with [src]." M << "You feel a tiny prick!" diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index 9b4b697f9c0..c35928d22d1 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -176,6 +176,9 @@ else user.visible_message("[user] begins hunting for an injection port on [target]'s suit!") + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + user.do_attack_animation(target) + if(!do_mob(user, target, injtime)) return From 28192c667537cb76d1b85a02c8068d696d965e61 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Wed, 9 Sep 2015 15:44:46 -0400 Subject: [PATCH 09/60] Adds cooldowns to eating/feeding, allows attacking with reagent containers while on harm intent. --- code/modules/reagents/reagent_containers.dm | 2 ++ code/modules/reagents/reagent_containers/food/drinks.dm | 7 +++---- code/modules/reagents/reagent_containers/food/snacks.dm | 4 ++++ code/modules/reagents/reagent_containers/pill.dm | 3 +++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index 04b31d43c45..2c8c853ebcb 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -101,6 +101,7 @@ user << "\The [blocked] is in the way!" return + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //puts a limit on how fast people can eat/drink things self_feed_message(user) reagents.trans_to_mob(user, issmall(user) ? ceil(amount_per_transfer_from_this/2) : amount_per_transfer_from_this, CHEM_INGEST) feed_sound(user) @@ -118,6 +119,7 @@ other_feed_message_start(user, target) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(!do_mob(user, target)) return diff --git a/code/modules/reagents/reagent_containers/food/drinks.dm b/code/modules/reagents/reagent_containers/food/drinks.dm index 7fd9bec3a20..d5526c9b1d8 100644 --- a/code/modules/reagents/reagent_containers/food/drinks.dm +++ b/code/modules/reagents/reagent_containers/food/drinks.dm @@ -23,6 +23,9 @@ flags |= OPENCONTAINER attack(mob/M as mob, mob/user as mob, def_zone) + if(force && !(flags & NOBLUDGEON) && user.a_intent == I_HURT) + return ..() + if(standard_feed_mob(user, M)) return @@ -93,10 +96,6 @@ volume = 150 flags = CONDUCT | OPENCONTAINER -/obj/item/weapon/reagent_containers/food/drinks/golden_cup/tournament_26_06_2011 - desc = "A golden cup. It will be presented to a winner of tournament 26 june and name of the winner will be graved on it." - - ///////////////////////////////////////////////Drinks //Notes by Darem: Drinks are simply containers that start preloaded. Unlike condiments, the contents can be ingested directly // rather then having to add it to something else first. They should only contain liquids. They have a default container size of 50. diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm index cfe34198de0..aecfdbacc9b 100644 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -40,6 +40,8 @@ return 0 if(istype(M, /mob/living/carbon)) + //TODO: replace with standard_feed_mob() call. + var/fullness = M.nutrition + (M.reagents.get_reagent_amount("nutriment") * 25) if(M == user) //If you're eating it yourself if(istype(M,/mob/living/carbon/human)) @@ -52,6 +54,7 @@ user << "\The [blocked] is in the way!" return + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //puts a limit on how fast people can eat/drink things if (fullness <= 50) M << "You hungrily chew out a piece of [src] and gobble it!" if (fullness > 50 && fullness <= 150) @@ -82,6 +85,7 @@ user.visible_message("[user] cannot force anymore of [src] down [M]'s throat.") return 0 + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(!do_mob(user, M)) return M.attack_log += text("\[[time_stamp()]\] Has been fed [src.name] by [user.name] ([user.ckey]) Reagents: [reagentlist(src)]") diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index e0dc0fc9f6b..b231c8cd35c 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -18,6 +18,8 @@ icon_state = "pill[rand(1, 20)]" attack(mob/M as mob, mob/user as mob, def_zone) + //TODO: replace with standard_feed_mob() call. + if(M == user) if(istype(M, /mob/living/carbon/human)) @@ -50,6 +52,7 @@ user.visible_message("[user] attempts to force [M] to swallow \the [src].") + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(!do_mob(user, M)) return From 5543209bbdc9c3d057ade83b393ed549ff4d7e77 Mon Sep 17 00:00:00 2001 From: HarpyEagle Date: Thu, 8 Oct 2015 23:00:23 -0400 Subject: [PATCH 10/60] Fix macro --- .../modules/reagents/reagent_containers/food/drinks/bottle.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm index a0731a8ce4b..a9fc3d288ba 100644 --- a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm +++ b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm @@ -32,7 +32,7 @@ var/throw_dist = get_dist(throw_source, loc) if(speed >= throw_speed && smash_check(throw_dist)) //not as reliable as smashing directly if(reagents) - hit_atom.visible_message("The contents of the [src] splash all over [hit_atom]!") + hit_atom.visible_message("The contents of \the [src] splash all over [hit_atom]!") reagents.splash(hit_atom, reagents.total_volume) src.smash(loc, hit_atom) @@ -158,7 +158,7 @@ //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]!") + 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. From 03761c5eed7032c1646e4c9652d263a28455a0b4 Mon Sep 17 00:00:00 2001 From: HarpyEagle Date: Tue, 19 Apr 2016 19:26:12 -0400 Subject: [PATCH 11/60] Compile fixes --- code/modules/mob/living/bot/bot.dm | 3 --- code/modules/mob/living/carbon/human/human_defense.dm | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm index 5eceb7c7bab..0ad82ae384e 100644 --- a/code/modules/mob/living/bot/bot.dm +++ b/code/modules/mob/living/bot/bot.dm @@ -268,9 +268,6 @@ /mob/living/bot/proc/explode() qdel(src) -/mob/living/bot/attack_throat() - return - /******************************************************************/ // Navigation procs // Used for A-star pathfinding diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 83089d53dab..fc7b73c10b9 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -188,7 +188,7 @@ emp_act // Handle striking to cripple. if(user.a_intent == I_DISARM) effective_force /= 2 - if(..(I, user effective_force, blocked, hit_zone)) + if(..(I, user, effective_force, blocked, hit_zone)) attack_joint(affecting, I, blocked) else return 0 From 3ae1f9ed785fa6adf89f8d68a73663f15bc56d39 Mon Sep 17 00:00:00 2001 From: HarpyEagle Date: Fri, 22 Apr 2016 04:49:53 -0400 Subject: [PATCH 12/60] Updates more instances of blocked<2 or /=(blocked+1) Removes facehugger source code file --- code/game/gamemodes/cult/cult_items.dm | 2 +- code/modules/hydroponics/grown.dm | 2 +- .../mob/living/carbon/carbon_defense.dm | 4 +- .../mob/living/carbon/human/human_defense.dm | 4 +- .../species/xenomorphs/alien_facehugger.dm | 232 ------------------ code/modules/mob/living/living_defense.dm | 2 +- .../reagent_containers/food/drinks/bottle.dm | 2 +- 7 files changed, 8 insertions(+), 240 deletions(-) delete mode 100644 code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm index 7a7ecbcf4ef..35f067323a4 100644 --- a/code/game/gamemodes/cult/cult_items.dm +++ b/code/game/gamemodes/cult/cult_items.dm @@ -28,7 +28,7 @@ user.apply_damage(rand(force/2, force), BRUTE, zone, 0, sharp=1, edge=1) user.Weaken(5) - user.drop_from_inventory(src) + user.removeItem(src, src.loc) throw_at(get_edge_target_turf(src, pick(alldirs)), rand(1,3), throw_speed) var/spooky = pick('sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg', 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/wail.ogg') diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 521c4499995..e10d024591b 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -250,7 +250,7 @@ if(prob(35)) if(user) user << "\The [src] has fallen to bits." - user.drop_from_inventory(src) + user.removeItem(src) qdel(src) /obj/item/weapon/reagent_containers/food/snacks/grown/attack_self(mob/user as mob) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index b4d9d1614d8..dd9e4f28b9b 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -6,7 +6,7 @@ ..() /mob/living/carbon/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone) - if(!effective_force || blocked >= 2) + if(!effective_force || blocked >= 100) return 0 //Hulk modifier @@ -26,7 +26,7 @@ if (I && I.damtype == BRUTE && !I.anchored && !is_robot_module(I)) var/damage = effective_force if (blocked) - damage /= blocked+1 + damage *= (100 - blocked)/100 //blunt objects should really not be embedding in things unless a huge amount of force is involved var/embed_chance = weapon_sharp? damage/I.w_class : damage/(I.w_class*3) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index fc7b73c10b9..ad34de145b4 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -243,9 +243,9 @@ emp_act return 1 /mob/living/carbon/human/proc/attack_joint(var/obj/item/organ/external/organ, var/obj/item/W, var/blocked) - if(!organ || (organ.dislocated == 2) || (organ.dislocated == -1) || blocked >= 2) + if(!organ || (organ.dislocated == 2) || (organ.dislocated == -1) || blocked >= 100) return 0 - if(prob(W.force / (blocked+1))) + if(prob(W.force * (100 - blocked)/100)) visible_message("[src]'s [organ.joint] [pick("gives way","caves in","crumbles","collapses")]!") organ.dislocate(1) return 1 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 deleted file mode 100644 index 691ac149bdf..00000000000 --- a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm +++ /dev/null @@ -1,232 +0,0 @@ -//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 68c506be12d..9c374685546 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -162,7 +162,7 @@ //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) + if(!effective_force || blocked >= 100) return 0 //Hulk modifier diff --git a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm index a9fc3d288ba..390f09ed783 100644 --- a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm +++ b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm @@ -146,7 +146,7 @@ // You are going to knock someone out for longer if they are not wearing a helmet. var/weaken_duration = 0 - if(blocked < 2) + if(blocked < 100) weaken_duration = smash_duration + min(0, force - target.getarmor(hit_zone, "melee") + 10) if(hit_zone == "head" && istype(target, /mob/living/carbon/)) From 7277885c73ada8dc9b133e9b5d05301c14d7debf Mon Sep 17 00:00:00 2001 From: Ccomp5950 Date: Thu, 26 May 2016 18:41:26 -0400 Subject: [PATCH 13/60] Couple of optimizations to get_mobs_and_objs_in_view_fast() --- code/_helpers/game.dm | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/code/_helpers/game.dm b/code/_helpers/game.dm index d5a7b1ed46e..57ff4b70138 100644 --- a/code/_helpers/game.dm +++ b/code/_helpers/game.dm @@ -248,31 +248,31 @@ . |= M // Since we're already looping through mobs, why bother using |= ? This only slows things down. return . -/proc/get_mobs_and_objs_in_view_fast(var/turf/T, var/range) - var/list/results = list("objs" = list(), "mobs" = list()) +/proc/get_mobs_and_objs_in_view_fast(var/turf/T, var/range, var/checkghosts = 1) - var/list/hear = dview(range,T,INVISIBILITY_MAXIMUM) - var/list/hearturfs = list() + var/list/mobs = list() + var/list/objs = list() - for(var/I in hear) - if(ismob(I)) - var/mob/M = I - results["mobs"] += M - hearturfs += M.locs[1] - else if(isobj(I)) - var/obj/O = I - results["objs"] += I - hearturfs += O.locs[1] + var/list/hear = dview(range,T,INVISIBILITY_MAXIMUM) + var/list/hearturfs = list() + + for(var/atom/movable/AM in hear) + if(ismob(AM)) + mobs += AM + hearturfs += AM.locs[1] + else if(isobj(AM)) + objs += AM + hearturfs += AM.locs[1] - for(var/mob/M in player_list) - if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears)) - results["mobs"] |= M - continue - if(M.loc && M.locs[1] in hearturfs) - results["mobs"] |= M + for(var/mob/M in player_list) + if(checkghosts && M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears)) + mobs |= M + continue + if(M.loc && M.locs[1] in hearturfs) + mobs |= M - return results + return list("mobs" = mobs, "objs" = objs) From 21f898e0470b87f54affc197da914b0ba964cbc9 Mon Sep 17 00:00:00 2001 From: Jon Date: Sun, 29 May 2016 00:56:11 +0100 Subject: [PATCH 14/60] First commit of manual port of BS12 #13042 and #13086 --- code/_helpers/global_lists.dm | 10 + code/_macros.dm | 2 + code/game/antagonist/outsider/deathsquad.dm | 2 +- code/game/jobs/job/civilian_chaplain.dm | 9 +- code/game/jobs/job/job.dm | 7 +- code/game/jobs/job/medical.dm | 88 ++- code/game/jobs/job/security.dm | 4 +- code/game/jobs/job/silicon.dm | 2 + code/modules/admin/verbs/randomverbs.dm | 6 +- .../preference_setup/general/01_basic.dm | 2 +- .../preference_setup/general/03_body.dm | 46 +- .../preference_setup/general/04_equipment.dm | 10 +- .../preference_setup/occupation/occupation.dm | 4 +- .../preference_setup/preference_setup.dm | 7 +- code/modules/client/preferences.dm | 18 +- code/modules/mob/inventory.dm | 5 + .../mob/living/carbon/human/human_species.dm | 7 + code/modules/mob/new_player/new_player.dm | 10 +- .../mob/new_player/preferences_setup.dm | 613 ++---------------- code/modules/projectiles/projectile/change.dm | 2 +- 20 files changed, 215 insertions(+), 639 deletions(-) diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm index 7ce97d62e68..f455f505b47 100644 --- a/code/_helpers/global_lists.dm +++ b/code/_helpers/global_lists.dm @@ -33,6 +33,8 @@ var/global/list/language_keys[0] // Table of say codes for all languages var/global/list/whitelisted_species = list("Human") // Species that require a whitelist check. var/global/list/playable_species = list("Human") // A list of ALL playable species, whitelisted, latejoin or otherwise. +var/list/mannequins_ + // Posters var/global/list/poster_designs = list() @@ -137,6 +139,14 @@ var/global/list/string_slot_flags = list( "holster" = SLOT_HOLSTER ) +/proc/get_mannequin(var/ckey) + if(!mannequins_) + mannequins_ = new() + . = mannequins_[ckey] + if(!.) + . = new/mob/living/carbon/human/dummy/mannequin() + mannequins_[ckey] = . + ////////////////////////// /////Initial Building///// ////////////////////////// diff --git a/code/_macros.dm b/code/_macros.dm index 45e67c75303..801498d915d 100644 --- a/code/_macros.dm +++ b/code/_macros.dm @@ -38,3 +38,5 @@ #define isslime(A) istype(A, /mob/living/carbon/slime) #define isxeno(A) istype(A, /mob/living/simple_animal/xeno) + +#define RANDOM_BLOOD_TYPE pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+") diff --git a/code/game/antagonist/outsider/deathsquad.dm b/code/game/antagonist/outsider/deathsquad.dm index 3a61152ab2b..1234bdb1f60 100644 --- a/code/game/antagonist/outsider/deathsquad.dm +++ b/code/game/antagonist/outsider/deathsquad.dm @@ -70,7 +70,7 @@ var/datum/antagonist/deathsquad/deathsquad var/syndicate_commando_name = pick(last_names) var/datum/preferences/A = new() //Randomize appearance for the commando. - A.randomize_appearance_for(player.current) + A.randomize_appearance_and_body_for(player.current) player.name = "[syndicate_commando_rank] [syndicate_commando_name]" player.current.name = player.name diff --git a/code/game/jobs/job/civilian_chaplain.dm b/code/game/jobs/job/civilian_chaplain.dm index cf162c14949..61cba700238 100644 --- a/code/game/jobs/job/civilian_chaplain.dm +++ b/code/game/jobs/job/civilian_chaplain.dm @@ -14,7 +14,7 @@ alt_titles = list("Counselor") - equip(var/mob/living/carbon/human/H) + equip(var/mob/living/carbon/human/H, var/alt_title, var/ask_questions = TRUE) if(!H) return 0 var/obj/item/weapon/storage/bible/B = new /obj/item/weapon/storage/bible(H) //BS12 EDIT @@ -22,6 +22,10 @@ H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/chaplain(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/device/pda/chaplain(H), slot_belt) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/black(H), slot_shoes) + if(!ask_questions) + return 1 + + spawn(0) var/religion_name = "Christianity" var/new_religion = sanitize(input(H, "You are the crew services officer. Would you like to change your religion? Default is Christianity, in SPACE.", "Name change", religion_name), MAX_NAME_LEN) @@ -150,3 +154,6 @@ feedback_set_details("religion_deity","[new_deity]") feedback_set_details("religion_book","[new_book_style]") return 1 + +/datum/job/chaplain/equip_preview(var/mob/living/carbon/human/H, var/alt_title) + return equip(H, alt_title, FALSE) diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index 2ae944adfda..6bdf3c1c4a1 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -71,8 +71,8 @@ H << "Your account number is: [M.account_number], your account pin is: [M.remote_access_pin]" // overrideable separately so AIs/borgs can have cardborg hats without unneccessary new()/del() -/datum/job/proc/equip_preview(mob/living/carbon/human/H) - return equip(H) +/datum/job/proc/equip_preview(mob/living/carbon/human/H, var/alt_title) + . = equip(H, alt_title) /datum/job/proc/get_access() if(!config || config.jobs_have_minimal_access) @@ -104,3 +104,6 @@ /datum/job/proc/is_position_available() return (current_positions < total_positions) || (total_positions == -1) + +/datum/job/proc/has_alt_title(var/mob/H, var/supplied_title, var/desired_title) + return (supplied_title == desired_title) || (H.mind && H.mind.role_alt_title == desired_title) \ No newline at end of file diff --git a/code/game/jobs/job/medical.dm b/code/game/jobs/job/medical.dm index 8a769df0b57..eeb0c8072a5 100644 --- a/code/game/jobs/job/medical.dm +++ b/code/game/jobs/job/medical.dm @@ -23,7 +23,7 @@ minimal_player_age = 10 ideal_character_age = 50 - equip(var/mob/living/carbon/human/H) + equip(var/mob/living/carbon/human/H, var/alt_title) if(!H) return 0 H.equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/cmo(H), slot_l_ear) switch(H.backbag) @@ -53,7 +53,7 @@ minimal_access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_virology, access_eva) alt_titles = list("Surgeon","Emergency Physician","Nurse","Virologist") - equip(var/mob/living/carbon/human/H) + equip(var/mob/living/carbon/human/H, var/alt_title) if(!H) return 0 H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_med(H), slot_l_ear) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/white(H), slot_shoes) @@ -62,35 +62,33 @@ if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/medic(H), slot_back) if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/med(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) - if (H.mind.role_alt_title) - switch(H.mind.role_alt_title) - if("Emergency Physician") - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/fr_jacket(H), slot_wear_suit) - if("Surgeon") - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/blue(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat(H), slot_wear_suit) - H.equip_to_slot_or_del(new /obj/item/clothing/head/surgery/blue(H), slot_head) - if("Virologist") - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/virologist(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat/virologist(H), slot_wear_suit) - H.equip_to_slot_or_del(new /obj/item/clothing/mask/surgical(H), slot_wear_mask) - switch(H.backbag) - if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/virology(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/vir(H), slot_back) - if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) - if("Medical Doctor") - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat(H), slot_wear_suit) - if("Nurse") - if(H.gender == FEMALE) - if(prob(50)) - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/nursesuit(H), slot_w_uniform) - else - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/nurse(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/head/nursehat(H), slot_head) - else - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/purple(H), slot_w_uniform) + if(has_alt_title(H, alt_title,"Emergency Physician")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/fr_jacket(H), slot_wear_suit) + else if(has_alt_title(H, alt_title,"Surgeon")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/blue(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat(H), slot_wear_suit) + H.equip_to_slot_or_del(new /obj/item/clothing/head/surgery/blue(H), slot_head) + else if(has_alt_title(H, alt_title,"Virologist")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/virologist(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat/virologist(H), slot_wear_suit) + H.equip_to_slot_or_del(new /obj/item/clothing/mask/surgical(H), slot_wear_mask) + switch(H.backbag) + if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/virology(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/vir(H), slot_back) + if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) + else if(has_alt_title(H, alt_title,"Medical Doctor")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat(H), slot_wear_suit) + else if(has_alt_title(H, alt_title,"Nurse")) + if(H.gender == FEMALE) + if(prob(50)) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/nursesuit(H), slot_w_uniform) + else + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/nurse(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/head/nursehat(H), slot_head) + else + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/purple(H), slot_w_uniform) else H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat(H), slot_wear_suit) @@ -176,19 +174,17 @@ minimal_access = list(access_medical, access_medical_equip, access_psychiatrist) alt_titles = list("Psychologist") - equip(var/mob/living/carbon/human/H) + equip(var/mob/living/carbon/human/H, var/alt_title) if(!H) return 0 H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_med(H), slot_l_ear) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(H), slot_back) if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/norm(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) - if (H.mind.role_alt_title) - switch(H.mind.role_alt_title) - if("Psychiatrist") - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/psych(H), slot_w_uniform) - if("Psychologist") - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/psych/turtleneck(H), slot_w_uniform) + if(has_alt_title(H, alt_title,"Psychiatrist")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/psych(H), slot_w_uniform) + else if(has_alt_title(H, alt_title,"Psychologist")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/psych/turtleneck(H), slot_w_uniform) else H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(H), slot_shoes) @@ -211,7 +207,7 @@ minimal_access = list(access_medical, access_medical_equip, access_morgue, access_eva, access_maint_tunnels, access_external_airlocks) alt_titles = list("Emergency Medical Technician") - equip(var/mob/living/carbon/human/H) + equip(var/mob/living/carbon/human/H, var/alt_title) if(!H) return 0 H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_med(H), slot_l_ear) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/jackboots(H), slot_shoes) @@ -220,14 +216,12 @@ if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/medic(H), slot_back) if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/med(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) - if (H.mind.role_alt_title) - switch(H.mind.role_alt_title) - if("Emergency Medical Technician") - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/paramedic(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/fr_jacket(H), slot_wear_suit) - if("Paramedic") - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/black(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/fr_jacket(H), slot_wear_suit) + if(has_alt_title(H, alt_title,"Emergency Medical Technician")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/paramedic(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/fr_jacket(H), slot_wear_suit) + else if(has_alt_title(H, alt_title,"Paramedic")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/black(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/fr_jacket(H), slot_wear_suit) else H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/weapon/storage/belt/medical/emt(H), slot_belt) diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm index dfb3659e0d6..6320a475ce3 100644 --- a/code/game/jobs/job/security.dm +++ b/code/game/jobs/job/security.dm @@ -98,7 +98,7 @@ minimal_access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_eva, access_external_airlocks) economic_modifier = 5 minimal_player_age = 3 - equip(var/mob/living/carbon/human/H) + equip(var/mob/living/carbon/human/H, var/alt_title) if(!H) return 0 H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_sec(H), slot_l_ear) switch(H.backbag) @@ -114,7 +114,7 @@ H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/evidence(H), slot_l_hand) else H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/evidence(H), slot_in_backpack) - if(H.mind.role_alt_title && H.mind.role_alt_title == "Forensic Technician") + if(has_alt_title(H, alt_title,"Forensic Technician")) H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/forensics/blue(H), slot_wear_suit) H.equip_to_slot_or_del(new /obj/item/weapon/storage/briefcase/crimekit, slot_r_hand) else diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm index fb9aeb793fd..d9aa96f7101 100644 --- a/code/game/jobs/job/silicon.dm +++ b/code/game/jobs/job/silicon.dm @@ -29,6 +29,7 @@ /datum/job/ai/equip_preview(mob/living/carbon/human/H) H.equip_to_slot_or_del(new /obj/item/clothing/suit/straight_jacket(H), slot_wear_suit) H.equip_to_slot_or_del(new /obj/item/clothing/head/cardborg(H), slot_head) + return 1 /datum/job/cyborg title = "Cyborg" @@ -60,3 +61,4 @@ /datum/job/cyborg/equip_preview(mob/living/carbon/human/H) H.equip_to_slot_or_del(new /obj/item/clothing/suit/cardborg(H), slot_wear_suit) H.equip_to_slot_or_del(new /obj/item/clothing/head/cardborg(H), slot_head) + return 1 diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 5d8db9c0729..170f9302f9a 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -234,9 +234,9 @@ Ccomp's first proc. var/list/mobs = list() var/list/ghosts = list() - var/list/sortmob = sortAtom(mob_list) // get the mob list. + var/list/sortmob = sortAtom(mob_list) // get the mob list. var/any=0 - for(var/mob/observer/dead/M in sortmob) + for(var/mob/observer/dead/M in sortmob) mobs.Add(M) //filter it where it's only ghosts any = 1 //if no ghosts show up, any will just be 0 if(!any) @@ -388,7 +388,7 @@ Traitors and the like can also be revived with the previous role mostly intact. else new_character.gender = pick(MALE,FEMALE) var/datum/preferences/A = new() - A.randomize_appearance_for(new_character) + A.randomize_appearance_and_body_for(new_character) new_character.real_name = G_found.real_name if(!new_character.real_name) diff --git a/code/modules/client/preference_setup/general/01_basic.dm b/code/modules/client/preference_setup/general/01_basic.dm index 2588836df56..656f54d4778 100644 --- a/code/modules/client/preference_setup/general/01_basic.dm +++ b/code/modules/client/preference_setup/general/01_basic.dm @@ -80,7 +80,7 @@ datum/preferences/proc/set_biological_gender(var/gender) var/new_gender = input(user, "Choose your character's biological gender:", "Character Preference", pref.biological_gender) as null|anything in get_genders() if(new_gender && CanUseTopic(user)) pref.set_biological_gender(new_gender) - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["id_gender"]) var/new_gender = input(user, "Choose your character's identifying gender:", "Character Preference", pref.identifying_gender) as null|anything in all_genders_define_list diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index ee93b2acf47..27e5d22e830 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -1,5 +1,8 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-") +/datum/preferences + var/dress_mob = TRUE + /datum/category_item/player_setup_item/general/body name = "Body" sort_order = 3 @@ -25,6 +28,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O S["disabilities"] >> pref.disabilities S["organ_data"] >> pref.organ_data S["rlimb_data"] >> pref.rlimb_data + pref.preview_icon = null /datum/category_item/player_setup_item/general/body/save_character(var/savefile/S) S["species"] << pref.species @@ -74,10 +78,9 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O /datum/category_item/player_setup_item/general/body/content(var/mob/user) . = list() - pref.update_preview_icon() - if(pref.preview_icon_front && pref.preview_icon_side) - user << browse_rsc(pref.preview_icon_front, "preview_icon.png") - user << browse_rsc(pref.preview_icon_side, "preview_icon2.png") + if(!pref.preview_icon) + pref.update_preview_icon() + user << browse_rsc(pref.preview_icon, "previewicon.png") var/mob_species = all_species[pref.species] . += "
Body " @@ -167,7 +170,10 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O else . += "

" - . += "
Preview
" + . += "
Preview
" + . += "
" + . += "
[pref.dress_mob ? "Hide equipment" : "Show equipment"]" + . += "
" . += "Hair
" @@ -196,8 +202,8 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/datum/species/mob_species = all_species[pref.species] if(href_list["random"]) - pref.randomize_appearance_for() - return TOPIC_REFRESH + pref.randomize_appearance_and_body_for() + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["blood_type"]) var/new_b_type = input(user, "Choose your character's blood-type:", "Character Preference") as null|anything in valid_bloodtypes @@ -274,7 +280,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/datum/species/S = all_species[pref.species] pref.age = max(min(pref.age, S.max_age), S.min_age) - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["hair_color"]) if(!has_flag(mob_species, HAS_HAIR_COLOR)) @@ -284,7 +290,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.r_hair = hex2num(copytext(new_hair, 2, 4)) pref.g_hair = hex2num(copytext(new_hair, 4, 6)) pref.b_hair = hex2num(copytext(new_hair, 6, 8)) - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["hair_style"]) var/list/valid_hairstyles = list() @@ -298,7 +304,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/new_h_style = input(user, "Choose your character's hair style:", "Character Preference", pref.h_style) as null|anything in valid_hairstyles if(new_h_style && CanUseTopic(user)) pref.h_style = new_h_style - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["facial_color"]) if(!has_flag(mob_species, HAS_HAIR_COLOR)) @@ -308,7 +314,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.r_facial = hex2num(copytext(new_facial, 2, 4)) pref.g_facial = hex2num(copytext(new_facial, 4, 6)) pref.b_facial = hex2num(copytext(new_facial, 6, 8)) - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["eye_color"]) if(!has_flag(mob_species, HAS_EYE_COLOR)) @@ -318,7 +324,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.r_eyes = hex2num(copytext(new_eyes, 2, 4)) pref.g_eyes = hex2num(copytext(new_eyes, 4, 6)) pref.b_eyes = hex2num(copytext(new_eyes, 6, 8)) - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["skin_tone"]) if(!has_flag(mob_species, HAS_SKIN_TONE)) @@ -326,7 +332,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/new_s_tone = input(user, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Character Preference", (-pref.s_tone) + 35) as num|null if(new_s_tone && has_flag(mob_species, HAS_SKIN_TONE) && CanUseTopic(user)) pref.s_tone = 35 - max(min( round(new_s_tone), 220),1) - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["skin_color"]) if(!has_flag(mob_species, HAS_SKIN_COLOR)) @@ -336,7 +342,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.r_skin = hex2num(copytext(new_skin, 2, 4)) pref.g_skin = hex2num(copytext(new_skin, 4, 6)) pref.b_skin = hex2num(copytext(new_skin, 6, 8)) - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["facial_style"]) var/list/valid_facialhairstyles = list() @@ -354,11 +360,11 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/new_f_style = input(user, "Choose your character's facial-hair style:", "Character Preference", pref.f_style) as null|anything in valid_facialhairstyles if(new_f_style && has_flag(mob_species, HAS_HAIR_COLOR) && CanUseTopic(user)) pref.f_style = new_f_style - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["reset_limbs"]) reset_limbs() - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["limbs"]) @@ -473,7 +479,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O for(var/internal_organ in list(O_HEART,O_EYES)) pref.organ_data[internal_organ] = "mechanical" - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["organs"]) @@ -511,7 +517,11 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O else if(href_list["disabilities"]) var/disability_flag = text2num(href_list["disabilities"]) pref.disabilities ^= disability_flag - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW + + else if(href_list["toggle_clothing"]) + pref.dress_mob = !pref.dress_mob + return TOPIC_REFRESH_UPDATE_PREVIEW return ..() diff --git a/code/modules/client/preference_setup/general/04_equipment.dm b/code/modules/client/preference_setup/general/04_equipment.dm index e3565515070..68e5eb9d318 100644 --- a/code/modules/client/preference_setup/general/04_equipment.dm +++ b/code/modules/client/preference_setup/general/04_equipment.dm @@ -55,32 +55,32 @@ var/new_underwear_top = input(user, "Choose your character's top underwear:", "Character Preference", get_key_by_value(get_undies_top(),pref.underwear_top)) as null|anything in underwear_top_options if(!isnull(new_underwear_top) && CanUseTopic(user)) pref.underwear_top = underwear_top_options[new_underwear_top] - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["change_underwear_bottom"]) var/underwear_bottom_options = get_undies_bottom() var/new_underwear_bottom = input(user, "Choose your character's bottom underwear:", "Character Preference", get_key_by_value(get_undies_bottom(),pref.underwear_bottom)) as null|anything in underwear_bottom_options if(!isnull(new_underwear_bottom) && CanUseTopic(user)) pref.underwear_bottom = underwear_bottom_options[new_underwear_bottom] - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["change_undershirt"]) var/new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference", get_key_by_value(undershirt_t,pref.undershirt)) as null|anything in undershirt_t if(!isnull(new_undershirt) && CanUseTopic(user)) pref.undershirt = undershirt_t[new_undershirt] - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["change_socks"]) var/new_socks = input(user, "Choose your character's socks:", "Character Preference", get_key_by_value(socks_t,pref.socks)) as null|anything in socks_t if(!isnull(new_socks) && CanUseTopic(user)) pref.socks = socks_t[new_socks] - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["change_backpack"]) var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference", backbaglist[pref.backbag]) as null|anything in backbaglist if(!isnull(new_backbag) && CanUseTopic(user)) pref.backbag = backbaglist.Find(new_backbag) - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["change_pda"]) var/new_pdachoice = input(user, "Choose your character's style of PDA:", "Character Preference", pdachoicelist[pref.pdachoice]) as null|anything in pdachoicelist diff --git a/code/modules/client/preference_setup/occupation/occupation.dm b/code/modules/client/preference_setup/occupation/occupation.dm index 09dd7f573e4..b3704bfb0c5 100644 --- a/code/modules/client/preference_setup/occupation/occupation.dm +++ b/code/modules/client/preference_setup/occupation/occupation.dm @@ -160,10 +160,10 @@ var/choice = input("Choose an title for [job.title].", "Choose Title", pref.GetPlayerAltTitle(job)) as anything in choices|null if(choice && CanUseTopic(user)) SetPlayerAltTitle(job, choice) - return TOPIC_REFRESH + return (pref.dress_mob ? TOPIC_REFRESH_UPDATE_PREVIEW : TOPIC_REFRESH) else if(href_list["set_job"]) - if(SetJob(user, href_list["set_job"])) return TOPIC_REFRESH + if(SetJob(user, href_list["set_job"])) return (pref.dress_mob ? TOPIC_REFRESH_UPDATE_PREVIEW : TOPIC_REFRESH) return ..() diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/client/preference_setup/preference_setup.dm index a890db16f51..7028894fda4 100644 --- a/code/modules/client/preference_setup/preference_setup.dm +++ b/code/modules/client/preference_setup/preference_setup.dm @@ -1,7 +1,8 @@ -// These are not flags, binary operations not intended #define TOPIC_NOACTION 0 #define TOPIC_HANDLED 1 #define TOPIC_REFRESH 2 +#define TOPIC_UPDATE_PREVIEW 4 +#define TOPIC_REFRESH_UPDATE_PREVIEW (TOPIC_REFRESH|TOPIC_UPDATE_PREVIEW) /datum/category_group/player_setup_category/general_preferences name = "General" @@ -217,7 +218,9 @@ return 1 . = OnTopic(href, href_list, usr) - if(. == TOPIC_REFRESH) + if(. & TOPIC_UPDATE_PREVIEW) + pref_mob.client.prefs.preview_icon = null + if(. & TOPIC_REFRESH) pref_mob.client.prefs.ShowChoices(usr) /datum/category_item/player_setup_item/CanUseTopic(var/mob/user) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 0e9bf5323bd..f133466a197 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -63,8 +63,6 @@ datum/preferences //Mob preview var/icon/preview_icon = null - var/icon/preview_icon_front = null - var/icon/preview_icon_side = null //Jobs, uses bitflags var/job_civilian_high = 0 @@ -122,7 +120,7 @@ datum/preferences player_setup = new(src) set_biological_gender(pick(MALE, FEMALE)) real_name = random_name(identifying_gender,species) - b_type = pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+") + b_type = RANDOM_BLOOD_TYPE gear = list() @@ -213,7 +211,7 @@ datum/preferences dat += "" //user << browse(dat, "window=preferences;size=635x736") - var/datum/browser/popup = new(user, "Character Setup","Character Setup", 635, 736, src) + var/datum/browser/popup = new(user, "Character Setup","Character Setup", 800, 800, src) popup.set_content(dat) popup.open() @@ -254,9 +252,10 @@ datum/preferences ShowChoices(usr) return 1 -/datum/preferences/proc/copy_to(mob/living/carbon/human/character, safety = 0) +/datum/preferences/proc/copy_to(mob/living/carbon/human/character, icon_updates = 1) // Sanitizing rather than saving as someone might still be editing when copy_to occurs. player_setup.sanitize_setup() + character.set_species(species) if(be_random_name) real_name = random_name(identifying_gender,species) @@ -297,10 +296,12 @@ datum/preferences character.g_eyes = g_eyes character.b_eyes = b_eyes + character.h_style = h_style character.r_hair = r_hair character.g_hair = g_hair character.b_hair = b_hair + character.f_style = f_style character.r_facial = r_facial character.g_facial = g_facial character.b_facial = b_facial @@ -359,7 +360,12 @@ datum/preferences pdachoice = 1 character.pdachoice = pdachoice - character.update_body() + if(icon_updates) + character.force_update_limbs() + character.update_mutations(0) + character.update_body(0) + character.update_hair(0) + character.update_icons() /datum/preferences/proc/open_load_dialog(mob/user) var/dat = "" diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 9d979787c5b..ad71cebe1f6 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -233,3 +233,8 @@ var/list/slot_equipment_priority = list( \ //if(hasvar(src,"r_hand")) if(src:r_hand) items += src:r_hand return items + +/mob/proc/delete_inventory() + for(var/entry in get_equipped_items()) + drop_from_inventory(entry) + qdel(entry) diff --git a/code/modules/mob/living/carbon/human/human_species.dm b/code/modules/mob/living/carbon/human/human_species.dm index 4aad06fd7ae..ea1afb157fb 100644 --- a/code/modules/mob/living/carbon/human/human_species.dm +++ b/code/modules/mob/living/carbon/human/human_species.dm @@ -2,6 +2,13 @@ real_name = "Test Dummy" status_flags = GODMODE|CANPUSH +/mob/living/carbon/human/dummy/mannequin/New() + ..() + mob_list -= src + living_mob_list -= src + dead_mob_list -= src + delete_inventory() + /mob/living/carbon/human/skrell/New(var/new_loc) h_style = "Skrell Male Tentacles" ..(new_loc, "Skrell") diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 55530ddcd85..a1b8437b0b7 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -127,9 +127,13 @@ observer.timeofdeath = world.time // Set the time of death so that the respawn timer works correctly. announce_ghost_joinleave(src) - client.prefs.update_preview_icon() - observer.icon = client.prefs.preview_icon + var/mob/living/carbon/human/dummy/mannequin = new() + client.prefs.dress_preview_mob(mannequin) + observer.appearance = mannequin observer.alpha = 127 + observer.layer = initial(observer.layer) + observer.invisibility = initial(observer.invisibility) + qdel(mannequin) if(client.prefs.be_random_name) client.prefs.real_name = random_name(client.prefs.identifying_gender) @@ -427,7 +431,7 @@ if(ticker.random_players) new_character.gender = pick(MALE, FEMALE) client.prefs.real_name = random_name(new_character.gender) - client.prefs.randomize_appearance_for(new_character) + client.prefs.randomize_appearance_and_body_for(new_character) else client.prefs.copy_to(new_character) diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index e93f2af24c5..9167c284a39 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -1,6 +1,6 @@ /datum/preferences //The mob should have a gender you want before running this proc. Will run fine without H -/datum/preferences/proc/randomize_appearance_for(var/mob/living/carbon/human/H) +/datum/preferences/proc/randomize_appearance_and_body_for(var/mob/living/carbon/human/H) var/datum/species/current_species = all_species[species ? species : "Human"] set_biological_gender(pick(current_species.genders)) @@ -9,6 +9,10 @@ if(current_species) if(current_species.appearance_flags & HAS_SKIN_TONE) s_tone = random_skin_tone() + if(current_species.appearance_flags & HAS_SKIN_COLOR) + r_skin = rand (0,255) + g_skin = rand (0,255) + b_skin = rand (0,255) if(current_species.appearance_flags & HAS_EYE_COLOR) randomize_eyes_color() if(current_species.appearance_flags & HAS_UNDERWEAR) @@ -25,11 +29,10 @@ b_skin = rand (0,255) - //backbag = 2 backbag = rand(1,4) pdachoice = rand(1,3) age = rand(current_species.min_age, current_species.max_age) - b_type = pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+") + b_type = RANDOM_BLOOD_TYPE if(H) copy_to(H,1) @@ -190,554 +193,74 @@ g_skin = green b_skin = blue +/datum/preferences/proc/dress_preview_mob(var/mob/living/carbon/human/mannequin) + copy_to(mannequin) + if(!dress_mob) + return -/datum/preferences/proc/update_preview_icon() //seriously. This is horrendous. - qdel(preview_icon_front) - qdel(preview_icon_side) - qdel(preview_icon) - - var/g = "m" - if(biological_gender == FEMALE) g = "f" - - var/icon/icobase - var/datum/species/current_species = all_species[species] - - if(current_species) - icobase = current_species.icobase + // Determine what job is marked as 'High' priority, and dress them up as such. + var/datum/job/previewJob + if(job_civilian_low & ASSISTANT) + previewJob = job_master.GetJob("Assistant") else - icobase = 'icons/mob/human_races/r_human.dmi' + for(var/datum/job/job in job_master.occupations) + var/job_flag + switch(job.department_flag) + if(CIVILIAN) + job_flag = job_civilian_high + if(MEDSCI) + job_flag = job_medsci_high + if(ENGSEC) + job_flag = job_engsec_high + if(job.flag == job_flag) + previewJob = job + break - preview_icon = new /icon(icobase, "") - for(var/name in BP_ALL) - if(organ_data[name] == "amputated") - continue - if(organ_data[name] == "cyborg") - var/datum/robolimb/R - if(rlimb_data[name]) R = all_robolimbs[rlimb_data[name]] - if(!R) R = basic_robolimb - if(name in list(BP_TORSO, BP_GROIN, BP_HEAD)) - preview_icon.Blend(icon(R.icon, "[name]_[g]"), ICON_OVERLAY) - else - preview_icon.Blend(icon(R.icon, "[name]"), ICON_OVERLAY) - continue - var/icon/limb_icon - if(name in list(BP_TORSO, BP_GROIN, BP_HEAD)) - limb_icon = new /icon(icobase, "[name]_[g]") - else - limb_icon = new /icon(icobase, "[name]") - // Skin color - if(current_species && (current_species.appearance_flags & HAS_SKIN_COLOR)) - limb_icon.Blend(rgb(r_skin, g_skin, b_skin), ICON_ADD) - // Skin tone - if(current_species && (current_species.appearance_flags & HAS_SKIN_TONE)) - if (s_tone >= 0) - limb_icon.Blend(rgb(s_tone, s_tone, s_tone), ICON_ADD) - else - limb_icon.Blend(rgb(-s_tone, -s_tone, -s_tone), ICON_SUBTRACT) - preview_icon.Blend(limb_icon, ICON_OVERLAY) - - //Tail - if(current_species && (current_species.tail)) - var/icon/temp = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[current_species.tail]_s") - if(current_species && (current_species.appearance_flags & HAS_SKIN_COLOR)) - temp.Blend(rgb(r_skin, g_skin, b_skin), ICON_ADD) - if(current_species && (current_species.appearance_flags & HAS_SKIN_TONE)) - if (s_tone >= 0) - temp.Blend(rgb(s_tone, s_tone, s_tone), ICON_ADD) - else - temp.Blend(rgb(-s_tone, -s_tone, -s_tone), ICON_SUBTRACT) - preview_icon.Blend(temp, ICON_OVERLAY) - - // This is absolute garbage but whatever. It will do until this entire file can be rewritten without crashes. - var/use_eye_icon = "eyes_s" - var/list/use_eye_data = current_species.has_limbs[BP_HEAD] - if(islist(use_eye_data)) - var/use_eye_path = use_eye_data["path"] - var/obj/item/organ/external/head/temp_head = new use_eye_path () - if(istype(temp_head)) - use_eye_icon = temp_head.eye_icon - qdel(temp_head) - - var/icon/eyes_s = new/icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = use_eye_icon) - if ((current_species && (current_species.appearance_flags & HAS_EYE_COLOR))) - eyes_s.Blend(rgb(r_eyes, g_eyes, b_eyes), ICON_ADD) - - var/datum/sprite_accessory/hair_style = hair_styles_list[h_style] - if(hair_style) - var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s") - hair_s.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD) - eyes_s.Blend(hair_s, ICON_OVERLAY) - - var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[f_style] - if(facial_hair_style) - var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s") - facial_s.Blend(rgb(r_facial, g_facial, b_facial), ICON_ADD) - eyes_s.Blend(facial_s, ICON_OVERLAY) - - var/icon/underwear_top_s = null - if(underwear_top && current_species.appearance_flags & HAS_UNDERWEAR) - underwear_top_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = underwear_top) - var/icon/underwear_bottom_s = null - if(underwear_bottom && current_species.appearance_flags & HAS_UNDERWEAR) - underwear_bottom_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = underwear_bottom) - - var/icon/undershirt_s = null - if(undershirt && current_species.appearance_flags & HAS_UNDERWEAR) - undershirt_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = undershirt) - - var/icon/socks_s = null - if(socks && current_species.appearance_flags & HAS_UNDERWEAR) - socks_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = socks) - - var/icon/clothes_s = null - if(job_civilian_low & ASSISTANT)//This gives the preview icon clothes depending on which job(if any) is set to 'high' - clothes_s = new /icon('icons/mob/uniform.dmi', "grey_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) - if(backbag == 2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - else if(backbag == 3 || backbag == 4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - - else if(job_civilian_high)//I hate how this looks, but there's no reason to go through this switch if it's empty - switch(job_civilian_high) - if(HOP) - clothes_s = new /icon('icons/mob/uniform.dmi', "hop_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "ianshirt"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(BARTENDER) - clothes_s = new /icon('icons/mob/uniform.dmi', "ba_suit_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "tophat"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(BOTANIST) - clothes_s = new /icon('icons/mob/uniform.dmi', "hydroponics_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/hands.dmi', "ggloves"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "apron"), ICON_OVERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "nymph"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-hyd"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(CHEF) - clothes_s = new /icon('icons/mob/uniform.dmi', "chef_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "chefhat"), ICON_OVERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "apronchef"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(JANITOR) - clothes_s = new /icon('icons/mob/uniform.dmi', "janitor_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "bio_janitor"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(LIBRARIAN) - clothes_s = new /icon('icons/mob/uniform.dmi', "red_suit_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "hairflower"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(QUARTERMASTER) - clothes_s = new /icon('icons/mob/uniform.dmi', "qm_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "poncho"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(CARGOTECH) - clothes_s = new /icon('icons/mob/uniform.dmi', "cargotech_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "flat_cap"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(MINER) - clothes_s = new /icon('icons/mob/uniform.dmi', "miner_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "bearpelt"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-eng"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(LAWYER) - clothes_s = new /icon('icons/mob/uniform.dmi', "internalaffairs_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) - clothes_s.Blend(new /icon(INV_R_HAND_DEF_ICON, "briefcase"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "suitjacket_blue"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(CHAPLAIN) - clothes_s = new /icon('icons/mob/uniform.dmi', "chapblack_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "imperium_monk"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(CLOWN) - clothes_s = new /icon('icons/mob/uniform.dmi', "clown_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "clown"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/mask.dmi', "clown"), ICON_OVERLAY) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "clownpack"), ICON_OVERLAY) - if(MIME) - clothes_s = new /icon('icons/mob/uniform.dmi', "mime_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/hands.dmi', "lgloves"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/mask.dmi', "mime"), ICON_OVERLAY) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "beret"), ICON_OVERLAY) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "suspenders"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - - else if(job_medsci_high) - switch(job_medsci_high) - if(RD) - clothes_s = new /icon('icons/mob/uniform.dmi', "director_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "petehat"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-tox"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(SCIENTIST) - clothes_s = new /icon('icons/mob/uniform.dmi', "sciencewhite_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_tox_open"), ICON_OVERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "metroid"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-tox"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(XENOBIOLOGIST) - clothes_s = new /icon('icons/mob/uniform.dmi', "sciencewhite_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_tox_open"), ICON_OVERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "metroid"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-tox"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(CHEMIST) - clothes_s = new /icon('icons/mob/uniform.dmi', "chemistrywhite_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labgreen"), ICON_OVERLAY) + if(previewJob) + mannequin.job = previewJob.title + previewJob.equip_preview(mannequin, player_alt_titles[previewJob.title]) + var/list/equipped_slots = list() //If more than one item takes the same slot only spawn the first + for(var/thing in gear) + var/datum/gear/G = gear_datums[thing] + if(G) + var/permitted = 0 + if(G.allowed_roles) + for(var/job_name in G.allowed_roles) + if(previewJob.title == job_name) + permitted = 1 else - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_chem_open"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-chem"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(CMO) - clothes_s = new /icon('icons/mob/uniform.dmi', "cmo_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "bio_cmo"), ICON_OVERLAY) - else - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_cmo_open"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "medicalpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-med"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(DOCTOR) - clothes_s = new /icon('icons/mob/uniform.dmi', "medical_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "surgeon"), ICON_OVERLAY) - else - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "medicalpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-med"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(GENETICIST) - clothes_s = new /icon('icons/mob/uniform.dmi', "geneticswhite_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "monkeysuit"), ICON_OVERLAY) - else - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_gen_open"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-gen"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(VIROLOGIST) - clothes_s = new /icon('icons/mob/uniform.dmi', "virologywhite_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/mask.dmi', "sterile"), ICON_OVERLAY) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_vir_open"), ICON_OVERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "plaguedoctor"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "medicalpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-vir"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(ROBOTICIST) - clothes_s = new /icon('icons/mob/uniform.dmi', "robotics_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY) - if(prob(1)) - clothes_s.Blend(new /icon(INV_R_HAND_DEF_ICON, "toolbox_blue"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + permitted = 1 - else if(job_engsec_high) - switch(job_engsec_high) - if(CAPTAIN) - clothes_s = new /icon('icons/mob/uniform.dmi', "captain_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "centcomcaptain"), ICON_OVERLAY) - else - clothes_s.Blend(new /icon('icons/mob/head.dmi', "captain"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-cap"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(HOS) - clothes_s = new /icon('icons/mob/uniform.dmi', "hosred_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "hosberet"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "securitypack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-sec"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(WARDEN) - clothes_s = new /icon('icons/mob/uniform.dmi', "warden_s") - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "slippers_worn"), ICON_OVERLAY) - else - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "securitypack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-sec"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(DETECTIVE) - clothes_s = new /icon('icons/mob/uniform.dmi', "detective_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/mask.dmi', "cigaron"), ICON_OVERLAY) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "detective"), ICON_OVERLAY) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "detective"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(OFFICER) - clothes_s = new /icon('icons/mob/uniform.dmi', "secred_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "officerberet"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "securitypack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-sec"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(CHIEF) - clothes_s = new /icon('icons/mob/uniform.dmi', "chief_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "hardhat0_white"), ICON_OVERLAY) - if(prob(1)) - clothes_s.Blend(new /icon(INV_R_HAND_DEF_ICON, "blueprints"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "engiepack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-eng"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(ENGINEER) - clothes_s = new /icon('icons/mob/uniform.dmi', "engine_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "orange"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "hardhat0_yellow"), ICON_OVERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "hazard"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "engiepack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-eng"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(ATMOSTECH) - clothes_s = new /icon('icons/mob/uniform.dmi', "atmos_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY) - if(prob(1)) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "firesuit"), ICON_OVERLAY) - switch(backbag) - if(2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - if(3) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) - if(4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(G.whitelisted && (G.whitelisted != mannequin.species.name)) + permitted = 0 - if(AI)//Gives AI and borgs assistant-wear, so they can still customize their character - clothes_s = new /icon('icons/mob/uniform.dmi', "grey_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "straight_jacket"), ICON_OVERLAY) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "cardborg_h"), ICON_OVERLAY) - if(backbag == 2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - else if(backbag == 3 || backbag == 4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) - if(CYBORG) - clothes_s = new /icon('icons/mob/uniform.dmi', "grey_s") - clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) - clothes_s.Blend(new /icon('icons/mob/suit.dmi', "cardborg"), ICON_OVERLAY) - clothes_s.Blend(new /icon('icons/mob/head.dmi', "cardborg_h"), ICON_OVERLAY) - if(backbag == 2) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) - else if(backbag == 3 || backbag == 4) - clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(!permitted) + continue - if(disabilities & NEARSIGHTED) - preview_icon.Blend(new /icon('icons/mob/eyes.dmi', "glasses"), ICON_OVERLAY) + if(G.slot && !(G.slot in equipped_slots)) + equipped_slots += G.slot + var/metadata = gear[G.display_name] + mannequin.equip_to_slot_or_del(G.spawn_item(mannequin, metadata), G.slot) + mannequin.update_icons() - preview_icon.Blend(eyes_s, ICON_OVERLAY) - if(underwear_top_s) - preview_icon.Blend(underwear_top_s, ICON_OVERLAY) - if(underwear_bottom_s) - preview_icon.Blend(underwear_bottom_s, ICON_OVERLAY) - if(undershirt_s) - preview_icon.Blend(undershirt_s, ICON_OVERLAY) - if(socks_s) - preview_icon.Blend(socks_s, ICON_OVERLAY) - if(clothes_s) - preview_icon.Blend(clothes_s, ICON_OVERLAY) - preview_icon_front = new(preview_icon, dir = SOUTH) - preview_icon_side = new(preview_icon, dir = WEST) +/datum/preferences/proc/update_preview_icon() + var/mob/living/carbon/human/dummy/mannequin/mannequin = get_mannequin(client_ckey) + mannequin.delete_inventory(TRUE) + dress_preview_mob(mannequin) - qdel(eyes_s) - qdel(underwear_top_s) - qdel(underwear_bottom_s) - qdel(undershirt_s) - qdel(socks_s) - qdel(clothes_s) + preview_icon = icon('icons/effects/effects.dmi', "nothing") + preview_icon.Scale(48+32, 16+32) + + mannequin.dir = NORTH + var/icon/stamp = getFlatIcon(mannequin) + preview_icon.Blend(stamp, ICON_OVERLAY, 25, 17) + + mannequin.dir = WEST + stamp = getFlatIcon(mannequin) + preview_icon.Blend(stamp, ICON_OVERLAY, 1, 9) + + mannequin.dir = SOUTH + stamp = getFlatIcon(mannequin) + preview_icon.Blend(stamp, ICON_OVERLAY, 49, 1) + + preview_icon.Scale(preview_icon.Width() * 2, preview_icon.Height() * 2) // Scaling here to prevent blurring in the browser. \ No newline at end of file diff --git a/code/modules/projectiles/projectile/change.dm b/code/modules/projectiles/projectile/change.dm index 9fcc709ba05..b389d39153f 100644 --- a/code/modules/projectiles/projectile/change.dm +++ b/code/modules/projectiles/projectile/change.dm @@ -78,7 +78,7 @@ H.set_species(randomize) H.universal_speak = 1 var/datum/preferences/A = new() //Randomize appearance for the human - A.randomize_appearance_for(H) + A.randomize_appearance_and_body_for(H) if(new_mob) for (var/spell/S in M.spell_list) From 1e6ecb0c88ece95ba2efac83dd0d50aa9df6c8b7 Mon Sep 17 00:00:00 2001 From: Datraen Date: Sat, 28 May 2016 20:06:51 -0400 Subject: [PATCH 15/60] Xenobio2 Tweaks Adds nameVar to products, sets it to products/xenos when they are created from the proper machinery. Adds the manual injector to the machinery that can take beakers, preventing them from spilling onto the machine when inserted. Tweaks the NanoUI to properly display percent mutated, adds a proper check to see if it is not a xeno occupant. --- code/game/machinery/kitchen/smartfridge.dm | 1 + code/modules/reagents/reagent_containers/glass.dm | 3 ++- code/modules/xenobio2/machinery/core_extractor.dm | 2 ++ code/modules/xenobio2/machinery/injector_computer.dm | 5 +++-- code/modules/xenobio2/machinery/slime_replicator.dm | 2 ++ code/modules/xenobio2/mob/xeno procs.dm | 2 -- code/modules/xenobio2/mob/xeno_product.dm | 1 + nano/templates/xenobio_computer.tmpl | 4 ++-- 8 files changed, 13 insertions(+), 7 deletions(-) diff --git a/code/game/machinery/kitchen/smartfridge.dm b/code/game/machinery/kitchen/smartfridge.dm index 8790bb337f6..a844d248e00 100644 --- a/code/game/machinery/kitchen/smartfridge.dm +++ b/code/game/machinery/kitchen/smartfridge.dm @@ -67,6 +67,7 @@ return 0 /obj/machinery/smartfridge/secure/extract/New() + ..() for(var/i=1 to 5) var/obj/item/xenoproduct/slime/core/C = new(src) C.traits = new() diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm index 44ea628eca3..4eb927444e7 100644 --- a/code/modules/reagents/reagent_containers/glass.dm +++ b/code/modules/reagents/reagent_containers/glass.dm @@ -41,7 +41,8 @@ /obj/machinery/smartfridge/, /obj/machinery/biogenerator, /obj/structure/frame, - /obj/machinery/radiocarbon_spectrometer + /obj/machinery/radiocarbon_spectrometer, + /obj/machinery/xenobio2/manualinjector ) /obj/item/weapon/reagent_containers/glass/New() diff --git a/code/modules/xenobio2/machinery/core_extractor.dm b/code/modules/xenobio2/machinery/core_extractor.dm index 818e3e65107..421c8ed22f5 100644 --- a/code/modules/xenobio2/machinery/core_extractor.dm +++ b/code/modules/xenobio2/machinery/core_extractor.dm @@ -112,6 +112,8 @@ var/obj/item/xenoproduct/slime/core/C = new(src) C.traits = occupant.traitdat + C.nameVar = occupant.nameVar + C.create_reagents(C.traits.traits[TRAIT_XENO_CHEMVOL]) for(var/reagent in occupant.traitdat.chems) C.reagents.add_reagent(reagent, occupant.traitdat.chems[reagent]) diff --git a/code/modules/xenobio2/machinery/injector_computer.dm b/code/modules/xenobio2/machinery/injector_computer.dm index d39f791cb7c..f65599e4850 100644 --- a/code/modules/xenobio2/machinery/injector_computer.dm +++ b/code/modules/xenobio2/machinery/injector_computer.dm @@ -60,9 +60,10 @@ data["occupied"] = 1 if(isxeno(injector.occupant)) var/mob/living/simple_animal/xeno/X = injector.occupant - data["instability"] = (X.mut_level / X.mut_max) * 100 + data["compatible"] = 1 + data["instability"] = 100 * (X.mut_level / X.mut_max) else - data["instability"] = null + data["compatible"] = null if(injector.beaker) data["reagentAmount"] = injector.beaker.reagents.total_volume diff --git a/code/modules/xenobio2/machinery/slime_replicator.dm b/code/modules/xenobio2/machinery/slime_replicator.dm index 77b70bc3b86..3626304bfef 100644 --- a/code/modules/xenobio2/machinery/slime_replicator.dm +++ b/code/modules/xenobio2/machinery/slime_replicator.dm @@ -74,6 +74,8 @@ spawn(30) var/mob/living/simple_animal/xeno/slime/S = new(src) S.traitdat = core.traits + S.nameVar = core.nameVar + S.name = "[S.nameVar] baby slime" S.ProcessTraits() qdel(core) spawn(30) diff --git a/code/modules/xenobio2/mob/xeno procs.dm b/code/modules/xenobio2/mob/xeno procs.dm index e0a64ebdd34..14317f7c261 100644 --- a/code/modules/xenobio2/mob/xeno procs.dm +++ b/code/modules/xenobio2/mob/xeno procs.dm @@ -51,8 +51,6 @@ Procs for targeting if(!stasis) if(!reagents) return - if(reagents.total_volume <= 0) - return //Let's handle some chemical smoke, for scientific smoke bomb purposes. for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) diff --git a/code/modules/xenobio2/mob/xeno_product.dm b/code/modules/xenobio2/mob/xeno_product.dm index 2ea970c89fb..b084b8eea64 100644 --- a/code/modules/xenobio2/mob/xeno_product.dm +++ b/code/modules/xenobio2/mob/xeno_product.dm @@ -9,4 +9,5 @@ Xenobiological product lives here as a basic type. var/datum/xeno/traits/traits var/source = "Unknown" var/product = "mess" + var/nameVar = "blah" \ No newline at end of file diff --git a/nano/templates/xenobio_computer.tmpl b/nano/templates/xenobio_computer.tmpl index 9cf053cddd4..96e74b23b34 100644 --- a/nano/templates/xenobio_computer.tmpl +++ b/nano/templates/xenobio_computer.tmpl @@ -11,7 +11,7 @@ Used In File(s): \code\modules\xenobio2\machines\injector_computer.dm {{:data.reagentAmount}}u / {{:data.reagentMax}}u {{:helper.displayBar(data.reagentAmount, data.reagentMax, data.reagentMin, 'good', null, 'displayBarBeaker')}} {{else}} - ERRR% + ERR {{:helper.displayBar(data.reagentAmount, data.reagentMax, data.reagentMin, 'good', null, 'displayBarBeaker')}} {{/if}} @@ -23,7 +23,7 @@ Used In File(s): \code\modules\xenobio2\machines\injector_computer.dm Instability:
- {{if data.instability}} + {{if data.compatible}} {{:data.instability}}% {{else}} ERRR% Please contact your local technician for assistance. From 5decb131d26ce95308ad9a059a523d27556f95be Mon Sep 17 00:00:00 2001 From: Datraen Date: Sat, 28 May 2016 20:08:31 -0400 Subject: [PATCH 16/60] Updates Map Chemical Dispenser added to the lab for easy access to chemicals without having to run to the anomaly chem lab. Moves biological genetic bombarders to the center of cells, to prevent any overlapping from occuring with the map and the bombarders. --- maps/polaris-5.dmm | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/maps/polaris-5.dmm b/maps/polaris-5.dmm index 58ce998b1c1..aa97ea0411f 100644 --- a/maps/polaris-5.dmm +++ b/maps/polaris-5.dmm @@ -299,7 +299,7 @@ "fM" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio2"; name = "Containment Blast Doors"; opacity = 0},/obj/machinery/door/window/southright{dir = 1; name = "Containment Pen"; req_access = list(47)},/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) "fN" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio2"; name = "Containment Blast Doors"; opacity = 0},/obj/structure/disposalpipe/segment,/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/plating,/area/outpost/research/xenobiology) "fO" = (/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) -"fP" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) +"fP" = (/obj/machinery/xenobio/editor,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) "fQ" = (/obj/structure/sign/securearea,/turf/simulated/wall/r_wall,/area/outpost/research/hallway/toxins_hallway) "fR" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock/research{autoclose = 0; frequency = 1379; icon_state = "door_locked"; id_tag = "toxins_airlock_exterior"; locked = 1; name = "Toxins External Airlock"; req_access = list(7)},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1379; master_tag = "toxins_airlock_control"; name = "Toxins Access Button"; pixel_x = 26; pixel_y = 0; req_access = list(7)},/turf/simulated/floor/tiled/white,/area/outpost/research/hallway/toxins_hallway) "fS" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging,/turf/space,/area/space) @@ -432,7 +432,7 @@ "ip" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/outpost/research/hallway/catwalk) "iq" = (/obj/structure/window/reinforced{dir = 8},/obj/structure/lattice,/turf/simulated/mineral/floor/ignore_mapgen,/area/mine/explored) "ir" = (/obj/structure/table/standard,/obj/item/weapon/paper_bin{pixel_x = -2; pixel_y = 5},/obj/item/weapon/pen/blue{pixel_x = -5; pixel_y = -1},/obj/item/weapon/pen/red{pixel_x = -1; pixel_y = 3},/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology) -"is" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/machinery/xenobio/editor,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) +"is" = (/obj/machinery/chemical_dispenser/full{density = 1},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "it" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "iu" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "iv" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) @@ -1588,7 +1588,7 @@ "EB" = (/obj/effect/floor_decal/industrial/warning/dust/corner,/obj/machinery/light/small,/turf/simulated/floor/tiled/asteroid_steel/airless,/area/outpost/mining_main/refinery) "EC" = (/obj/item/weapon/stool/padded,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "ED" = (/obj/machinery/xenobio/extractor,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology) -"EE" = (/obj/structure/disposalpipe/segment,/obj/machinery/xenobio/editor,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) +"EE" = (/obj/structure/bed/chair/office/light{dir = 1},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "EF" = (/obj/machinery/recharger/wallcharger/map{pixel_x = 32},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) (1,1,1) = {" @@ -1679,21 +1679,21 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaeeWaqeXaiaqeYeZfafbfcfdeCeUfeEcfgdRacacacacacacacacaceVfhfhfieVfhfhfieVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaefsfkaqaqaeaeflaeaeeTeBfmfyfofoacacacacacacacaceVeVeVfhfhfqeVfhfhfqeVeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaeaefrfraegYftfuaefvfwfofofofxdldlacacdlacaceVeVjeeVfpfhfzeVfpfhfzeVfAeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadlaeaeaeaefBfCfDaedRdRfofEfxfFdldldldldlaceVeVfGhWeVfIfJfKeVfLfMfNeVfOfPeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadlaeaeaeaefBfCfDaedRdRfofEfxfFdldldldldlaceVeVfGhWeVfIfJfKeVfLfMfNeVfOgdeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadldldlaeaefQfRaeaedRaafEfSfFfFdldldldldleVeVfTfOfUfVfWfXfYfZgafXgbgcgdfOfAeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadldlgegfggghgiaaaafSfSfSfSaadldldldlgjgkfOglfOfHgngogpgqgrgogsfOgmeVeVeVeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadlgtgugvgwgxaaaagygzgygzaaaaaaaadlgAfAgCgDgdgEgFgGgGgHgGgGgGgIgJgKfpgLfheVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadlgNgMgOgwgxgPaaaaaaaaaaaaaagPgQgReVeVeVeVeVgSgTgUgogVfOfOgdgWgXiofhfhfheVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgZgvgwhagQgQgQgQgQgQgQgQhbgZhceVhdhehfeVgBgTgWhghhhifOgdhjhkhlhmhmhneVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahohphqhrhshshthuhshshshvhshshwhxhyhzhAhBhChDhEhFhGhHhIhJhKhLkkeVhNhNhNeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOguorhPhQhQhQhRhQhQhQhShQhQhQhTeVhUhVkreVgWgTgWhXhYhZgWgdiaibicisidideVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagPieifigiiihijijijijijijijijijikeVeVeVeVeVilgTimgoingogVgdgWgXmrfhfhfheVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOipiUiqdldlaaaaaaaaaaaaaaaaaagjiriEitgdiuiviwiwixiwiwiwiyhkiziAiBiCeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOiDiUiqdldldlaaaaaaaaaaaaaaaagAiFfOfOfOfOiGgoiHiIingoiJfOEFeVeVeVeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOguorhPhQhQhQhRhQhQhQhShQhQhQhTeVhUhVkreVgWgTgWhXhYhZgWgdiaibicididideVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagPieifigiiihijijijijijijijijijikeVeVeVeVeVilgTimgoingogVgdgWgXmrfhfPfheVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOipiUiqdldlaaaaaaaaaaaaaaaaaagjiriEitisiuiviwiwixiwiwiwiyhkiziAiBiCeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOiDiUiqdldldlaaaaaaaaaaaaaaaagAiFfOfOEEfOiGgoiHiIingoiJfOEFeVeVeVeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOiDiUiqdldldlaaaaaaaaaaaaaaaaeVeViRiKgdiLiMiNiOhMiPiNiQiSgdfOiVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOiTjgiqdldldlaaaaaaaaaaaaaaaaaaeVeVjdECeViWiXiYeViZjajbeVfOjceVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtiDiUiqdldldlaaaaaaaaaaaaaaaaaaaaeVeVEDeVEEfhfhjefzfhfpeVjfeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadlgtiDjpiqdldldldldlaaaaaaaaaaaaaaaaaaeVeVeVjhfhfhjejhfhfheVeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtiDiUiqdldldlaaaaaaaaaaaaaaaaaaaaeVeVEDeVfzfhfhjefzfhfpeVjfeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadlgtiDjpiqdldldldldlaaaaaaaaaaaaaaaaaaeVeVeVjhfPfhjejhfhfheVeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadlgtiDiUiqdldldldldlaaaaaaaaaaaaaaaaaaaaaaeVjifhfhjejifhfheVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadlgtiDiUiqdldldldldlaaaaaaaaaaaaaaaaaaaaaaeVjjjjjjeVeVeVeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtifigiqdldldldldlaaaaaaaaaaaaaaaaaaaaaajkjkjkjkjkacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa From 5d3dbb8b6faad2203597665e71df28bf8e875e20 Mon Sep 17 00:00:00 2001 From: Yoshax Date: Sun, 29 May 2016 01:33:48 +0100 Subject: [PATCH 17/60] Fixes chromatic slime laser reflection and adjusts a span class --- code/modules/xenobio2/mob/xeno procs.dm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/code/modules/xenobio2/mob/xeno procs.dm b/code/modules/xenobio2/mob/xeno procs.dm index 4684d9d9d15..eb237e7a295 100644 --- a/code/modules/xenobio2/mob/xeno procs.dm +++ b/code/modules/xenobio2/mob/xeno procs.dm @@ -137,10 +137,10 @@ Procs for targeting /mob/living/simple_animal/xeno/proc/BuildReagentLists() return -/mob/living/simple_animal/xeno/proc/bulet_act(var/obj/item/projectile/P) +/mob/living/simple_animal/xeno/bullet_act(var/obj/item/projectile/P) //Shamelessly stolen from ablative armor. if((traitdat.traits[TRAIT_XENO_CHROMATIC]) && istype(P, /obj/item/projectile/beam)) - visible_message("") + visible_message(")\The beam reflects off of the [src]!") // Find a turf near or on the original location to bounce to var/new_x = P.starting.x + pick(0, -1, 1, -2, 2) var/new_y = P.starting.y + pick(0, -1, 1, -2, 2) @@ -149,7 +149,8 @@ Procs for targeting // redirect the projectile P.redirect(new_x, new_y, curloc, src) - return + return -1 + else ..() From ba529fabedcf90b8afd33aecb321d4466c454411 Mon Sep 17 00:00:00 2001 From: Jon Date: Sun, 29 May 2016 04:15:22 +0100 Subject: [PATCH 18/60] Fixes #1790 --- code/modules/client/preference_setup/loadout/loadout.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/client/preference_setup/loadout/loadout.dm index e2d73ff8b3f..cb0b31ba289 100644 --- a/code/modules/client/preference_setup/loadout/loadout.dm +++ b/code/modules/client/preference_setup/loadout/loadout.dm @@ -169,7 +169,7 @@ var/list/gear_datums = list() if(istype(G)) total_cost += G.cost if((total_cost+TG.cost) <= MAX_GEAR_COST) pref.gear += TG.display_name - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW if(href_list["gear"] && href_list["tweak"]) var/datum/gear/gear = gear_datums[href_list["gear"]] var/datum/gear_tweak/tweak = locate(href_list["tweak"]) @@ -179,13 +179,13 @@ var/list/gear_datums = list() if(!metadata || !CanUseTopic(user)) return TOPIC_NOACTION set_tweak_metadata(gear, tweak, metadata) - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["select_category"]) current_tab = href_list["select_category"] return TOPIC_REFRESH else if(href_list["clear_loadout"]) pref.gear.Cut() - return TOPIC_REFRESH + return TOPIC_REFRESH_UPDATE_PREVIEW return ..() /datum/gear From 34d323e57fc27f5da1cfd7d63603384943e9bcf3 Mon Sep 17 00:00:00 2001 From: Arokha Sieyes Date: Sun, 29 May 2016 02:37:13 -0400 Subject: [PATCH 19/60] The Terminator Update This updates synthetic limbs to make more sense. It tweaks what you can 'see' when examining people. If someone has a robotic leg but is wearing pants, how would you know that? If someone has a burn on their arm, but their jumpsuit sleeves down, how would you know that? If someone has a replacement Vey-Med arm, how would you know it's robotic? It also treats examining FBPs more 'realistically'. If they are covered except for their head, it doesn't matter if their whole body is Bishop robotic. If their head is Vey-Med and that's all you can see, they just look human to you. So FBP manufacturers can have a 'lifelike' var set. Vey-Med has this. This makes the limbs not show obviously non-organic damage (dents) until they are more damaged and start showing wires/metal. Attempts to treat these limbs with medical stuff results in a different message. Manufacturers can also set individual blood colors. Vey-Med blood is now white, ala Bishop from Aliens. isSynthetic proc = Is the mob actually synthetic, as in, mechanically for breathing/tox purposes? looksSynthetic proc = Does the mob display outward signs of being synthetic? Based on head and torso and what's revealed. Other fixes: You can no longer attach limbs to non-existent parents. You can't give somone a foot on a leg that doesn't exist. You can't attach fleshy limbs to robotic ones. BODIES DO NOT WORK THAT WAY. 'Synthetic' var on humans points to manufacturer if you need to grab it quickly. isSynthetic returns this as well. Robolimb count (and thus overheating speed) updates whenever your limbs change. Lifelike FBPs do not show a 'system offline glyph'. isSynthetic and looksSynthetic moved to human_helpers becasue they were defined on human in mob_helpers Nanopaste correctly repairs limbs using the new procs (both burn and brute, making it an expensive welder+wire) --- code/__defines/damage_organs.dm | 7 +- code/game/machinery/computer/cloning.dm | 2 +- .../effects/decals/Cleanable/humans.dm | 7 +- code/game/objects/items/stacks/medical.dm | 9 ++- code/game/objects/items/stacks/nanopaste.dm | 17 ++--- .../mob/living/carbon/human/examine.dm | 70 +++++++++++++++---- code/modules/mob/living/carbon/human/human.dm | 2 - .../mob/living/carbon/human/human_defines.dm | 2 +- .../mob/living/carbon/human/human_helpers.dm | 31 ++++++++ .../carbon/human/species/species_getters.dm | 13 +++- .../mob/living/carbon/human/update_icons.dm | 7 +- code/modules/mob/mob_helpers.dm | 12 ---- code/modules/organs/blood.dm | 3 + code/modules/organs/organ_external.dm | 45 ++++++++---- code/modules/organs/robolimbs.dm | 5 ++ code/modules/surgery/limb_reattach.dm | 12 ++++ 16 files changed, 175 insertions(+), 69 deletions(-) diff --git a/code/__defines/damage_organs.dm b/code/__defines/damage_organs.dm index 89b01a699b6..124be534525 100644 --- a/code/__defines/damage_organs.dm +++ b/code/__defines/damage_organs.dm @@ -44,10 +44,11 @@ #define DROPLIMB_BURN 2 // Damage above this value must be repaired with surgery. -#define ROBOLIMB_SELF_REPAIR_CAP 30 +#define ROBOLIMB_REPAIR_CAP 30 -#define ORGAN_ASSISTED 1 -#define ORGAN_ROBOT 2 +#define ORGAN_ASSISTED 1 // Like pacemakers, not robotic +#define ORGAN_ROBOT 2 // Fully robotic, no organic parts +#define ORGAN_LIFELIKE 3 // Robotic, made to appear organic //Germs and infections. #define GERM_LEVEL_AMBIENT 110 // Maximum germ level you can reach by standing still. diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index 83b6f2ce861..bdab3bbbb14 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -360,7 +360,7 @@ return if(subject.isSynthetic()) - scantemp = "Error: Subject is not organic." + scantemp = "Error: Majority of subject is non-organic." return if (subject.suiciding == 1) scantemp = "Error: Subject's brain is not responding to scanning stimuli." diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index 036e4270780..fc764efd02d 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -17,6 +17,7 @@ var/global/list/image/splatter_cache=list() var/base_icon = 'icons/effects/blood.dmi' blood_DNA = list() var/basecolor="#A10808" // Color when wet. + var/synthblood = 0 var/list/datum/disease2/disease/virus2 = list() var/amount = 5 var/drytime @@ -61,9 +62,9 @@ var/global/list/image/splatter_cache=list() /obj/effect/decal/cleanable/blood/update_icon() if(basecolor == "rainbow") basecolor = "#[get_random_colour(1)]" color = basecolor - if(basecolor == SYNTH_BLOOD_COLOUR) - name = "oil" - desc = "It's black and greasy." + if(synthblood) + name = "synthetic blood" + desc = "It's quite greasy." else name = initial(name) desc = initial(desc) diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index d47df19f196..2ddbd4e330e 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -37,8 +37,13 @@ user << "You can't apply [src] through [H.wear_suit]!" return 1 - if(affecting.robotic >= ORGAN_ROBOT) - user << "This isn't useful at all on a robotic limb.." + if(affecting.robotic == ORGAN_ROBOT) + user << "This isn't useful at all on a robotic limb." + return 1 + + if(affecting.robotic >= ORGAN_LIFELIKE) + user << "You apply the [src], but it seems to have no effect..." + use(1) return 1 H.UpdateDamageIcon() diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/nanopaste.dm index 5b85763b324..1ff55adf852 100644 --- a/code/game/objects/items/stacks/nanopaste.dm +++ b/code/game/objects/items/stacks/nanopaste.dm @@ -27,19 +27,12 @@ var/mob/living/carbon/human/H = M var/obj/item/organ/external/S = H.get_organ(user.zone_sel.selecting) - if(S.open == 1) - if (S && (S.robotic >= ORGAN_ROBOT)) - if(S.get_damage()) - S.heal_damage(15, 15, robo_repair = 1) - H.updatehealth() - use(1) - user.visible_message("\The [user] applies some nanite paste at[user != M ? " \the [M]'s" : " \the"][S.name] with \the [src].",\ - "You apply some nanite paste at [user == M ? "your" : "[M]'s"] [S.name].") - else - user << "Nothing to fix here." + if (S && (S.robotic >= ORGAN_ROBOT)) + if(S.robo_repair(15, "omni", 0, src, user)) + use(1) + user.visible_message("\The [user] applies some nanite paste on [user != M ? "\the [M]'s" : "their"] [S.name].",\ + "You apply some nanite paste on [user == M ? "your" : "[M]'s"] [S.name].") else if (can_operate(H)) if (do_surgery(H,user,src)) return - else - user << "Nothing to fix in here." diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index de3764e5af3..53d12e8b7de 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -4,26 +4,69 @@ var/skipjumpsuit = 0 var/skipshoes = 0 var/skipmask = 0 + var/skipears = 0 var/skipeyes = 0 var/skipface = 0 + var/skipchest = 0 + var/skipgroin = 0 + var/skiphands = 0 + var/skiplegs = 0 + var/skiparms = 0 + var/skipfeet = 0 + + var/looks_synth = looksSynthetic() //exosuits and helmets obscure our view and stuff. if(wear_suit) - skipgloves = wear_suit.flags_inv & HIDEGLOVES - skipsuitstorage = wear_suit.flags_inv & HIDESUITSTORAGE - skipjumpsuit = wear_suit.flags_inv & HIDEJUMPSUIT - skipshoes = wear_suit.flags_inv & HIDESHOES + skipsuitstorage |= wear_suit.flags_inv & HIDESUITSTORAGE + if(wear_suit.flags_inv & HIDEJUMPSUIT) + skiparms |= 1 + skiplegs |= 1 + skipchest |= 1 + skipgroin |= 1 + if(wear_suit.flags_inv & HIDESHOES) + skipshoes |= 1 + skipfeet |= 1 + if(wear_suit.flags_inv & HIDEGLOVES) + skipgloves |= 1 + skiphands |= 1 + + if(w_uniform) + skiplegs |= w_uniform.body_parts_covered & LEGS + skiparms |= w_uniform.body_parts_covered & ARMS + skipchest |= w_uniform.body_parts_covered & UPPER_TORSO + skipgroin |= w_uniform.body_parts_covered & LOWER_TORSO + + if(gloves) + skiphands |= gloves.body_parts_covered & HANDS + + if(shoes) + skipfeet |= shoes.body_parts_covered & FEET if(head) - skipmask = head.flags_inv & HIDEMASK - skipeyes = head.flags_inv & HIDEEYES - skipears = head.flags_inv & HIDEEARS - skipface = head.flags_inv & HIDEFACE + skipmask |= head.flags_inv & HIDEMASK + skipeyes |= head.flags_inv & HIDEEYES + skipears |= head.flags_inv & HIDEEARS + skipface |= head.flags_inv & HIDEFACE if(wear_mask) skipface |= wear_mask.flags_inv & HIDEFACE + //This is what hides what + var/list/hidden = list( + BP_GROIN = skipgroin, + BP_TORSO = skipchest, + BP_HEAD = skipface, + BP_L_ARM = skiparms, + BP_R_ARM = skiparms, + BP_L_HAND= skiphands, + BP_R_HAND= skiphands, + BP_L_FOOT= skipfeet, + BP_R_FOOT= skipfeet, + BP_L_LEG = skiplegs, + BP_R_LEG = skiplegs) + var/msg = "*---------*\nThis is " var/datum/gender/T = gender_datums[get_gender()] @@ -39,9 +82,8 @@ msg += "[src.name]" - var/is_synth = isSynthetic() if(!(skipjumpsuit && skipface)) - if(is_synth) + if(looks_synth) var/use_gender = "a synthetic" if(gender == MALE) use_gender = "an android" @@ -124,8 +166,6 @@ else if(blood_DNA) msg += "[T.He] [T.has] [(hand_blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained hands!\n" - //handcuffed? - //handcuffed? if(handcuffed) if(istype(handcuffed, /obj/item/weapon/handcuffs/cable)) @@ -273,14 +313,16 @@ for(var/obj/item/organ/external/temp in organs) if(temp) + if((temp.organ_tag in hidden) && hidden[temp.organ_tag]) + continue //Organ is hidden, don't talk about it if(temp.status & ORGAN_DESTROYED) wound_flavor_text["[temp.name]"] = "[T.He] [T.is] missing [T.his] [temp.name].\n" continue - if(!is_synth && temp.robotic >= ORGAN_ROBOT) + if(!looks_synth && temp.robotic == ORGAN_ROBOT) if(!(temp.brute_dam + temp.burn_dam)) wound_flavor_text["[temp.name]"] = "[T.He] [T.has] a [temp.name].\n" else - wound_flavor_text["[temp.name]"] = "[T.He] [T.has] a [temp.name]. It has [temp.get_wounds_desc()]!\n" + wound_flavor_text["[temp.name]"] = "[T.He] [T.has] a [temp.name] with [temp.get_wounds_desc()]!\n" continue else if(temp.wounds.len > 0 || temp.open) if(temp.is_stump() && temp.parent_organ && organs_by_name[temp.parent_organ]) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index b5ea7931c10..7736a66657d 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1140,8 +1140,6 @@ qdel(hud_used) hud_used = new /datum/hud(src) - full_prosthetic = null - if(species) return 1 else diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 390e7ee6c5f..5a9d3846024 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -31,6 +31,7 @@ var/age = 30 //Player's age (pure fluff) var/b_type = "A+" //Player's bloodtype + var/synthetic //If they are a synthetic (aka synthetic torso) var/underwear_top = 1 //Which underwear the player wants var/underwear_bottom = 1 @@ -83,7 +84,6 @@ var/list/flavor_texts = list() var/gunshot_residue var/pulling_punches // Are you trying not to hurt your opponent? - var/full_prosthetic // We are a robutt. var/robolimb_count = 0 // Number of robot limbs. mob_bump_flag = HUMAN diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index df8eead14ec..db0f44ce31c 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -58,6 +58,37 @@ /mob/living/carbon/human/get_gender() return identifying_gender ? identifying_gender : gender +// This is the 'mechanical' check for synthetic-ness, not appearance +// Returns the company that made the synthetic +/mob/living/carbon/human/isSynthetic() + if(synthetic) return synthetic //Your synthetic-ness is not going away + var/obj/item/organ/external/T = organs_by_name[BP_TORSO] + if(T && T.robotic >= ORGAN_ROBOT) + var/datum/robolimb/R = all_robolimbs[T.model] + synthetic = R + return synthetic + + return 0 + +// Would an onlooker know this person is synthetic? +// Based on sort of logical reasoning, 'Look at head, look at torso' +/mob/living/carbon/human/proc/looksSynthetic() + var/obj/item/organ/external/T = organs_by_name[BP_TORSO] + var/obj/item/organ/external/H = organs_by_name[BP_HEAD] + + //Look at their head + if(!head || !(head && (head.flags_inv & HIDEFACE))) + if(H && H.robotic == ORGAN_ROBOT) //Exactly robotic, not higher as lifelike is higher + return 1 + + //Look at their torso + if(!wear_suit || (wear_suit && !(wear_suit.flags_inv & HIDEJUMPSUIT))) + if(!w_uniform || (w_uniform && !(w_uniform.body_parts_covered & UPPER_TORSO))) + if(T && T.robotic == ORGAN_ROBOT) + return 1 + + return 0 + #undef HUMAN_EATING_NO_ISSUE #undef HUMAN_EATING_NO_MOUTH #undef HUMAN_EATING_BLOCKED_MOUTH diff --git a/code/modules/mob/living/carbon/human/species/species_getters.dm b/code/modules/mob/living/carbon/human/species/species_getters.dm index 625d5559433..efb053eddfe 100644 --- a/code/modules/mob/living/carbon/human/species/species_getters.dm +++ b/code/modules/mob/living/carbon/human/species/species_getters.dm @@ -47,10 +47,19 @@ return "no message" /datum/species/proc/get_ssd(var/mob/living/carbon/human/H) - return ((H && H.isSynthetic()) ? "flashing a 'system offline' glyph on their monitor" : show_ssd) + if(H) + if(H.looksSynthetic()) + return "flashing a 'system offline' light" + else + return show_ssd /datum/species/proc/get_blood_colour(var/mob/living/carbon/human/H) - return ((H && H.isSynthetic()) ? SYNTH_BLOOD_COLOUR : blood_color) + if(H) + var/datum/robolimb/company = H.isSynthetic() + if(company) + return company.blood_color + else + return blood_color /datum/species/proc/get_virus_immune(var/mob/living/carbon/human/H) return ((H && H.isSynthetic()) ? 1 : virus_immune) diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 088c796f289..64a50e26965 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -220,6 +220,8 @@ var/global/list/damage_icon_parts = list() var/hulk = (HULK in src.mutations) var/skeleton = (SKELETON in src.mutations) + robolimb_count = 0 + //CACHING: Generate an index key from visible bodyparts. //0 = destroyed, 1 = normal, 2 = robotic, 3 = necrotic. @@ -249,6 +251,7 @@ var/global/list/damage_icon_parts = list() icon_key += "0" else if(part.robotic >= ORGAN_ROBOT) icon_key += "2[part.model ? "-[part.model]": ""]" + robolimb_count++ else if(part.status & ORGAN_DEAD) icon_key += "3" else @@ -596,7 +599,7 @@ var/global/list/damage_icon_parts = list() standing = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[t_type]") standing.color = l_ear.color both.overlays += standing - + if(r_ear) var/image/standing var/t_type = r_ear.icon_state @@ -610,7 +613,7 @@ var/global/list/damage_icon_parts = list() standing = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[t_type]") standing.color = r_ear.color both.overlays += standing - + overlays_standing[EARS_LAYER] = both else diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 612861ed8c5..5271034d2ba 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -19,18 +19,6 @@ return L.mob_size <= MOB_MINISCULE return 0 - -// If they are 100% robotic, they count as synthetic. -/mob/living/carbon/human/isSynthetic() - if(isnull(full_prosthetic)) - robolimb_count = 0 - for(var/obj/item/organ/external/E in organs) - if(E.robotic >= ORGAN_ROBOT) - robolimb_count++ - if(robolimb_count == organs.len) - full_prosthetic = 1 - return full_prosthetic - /mob/living/silicon/isSynthetic() return 1 diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm index 17219a48d43..2c5f24984a5 100644 --- a/code/modules/organs/blood.dm +++ b/code/modules/organs/blood.dm @@ -266,9 +266,11 @@ proc/blood_splatter(var/target,var/datum/reagent/blood/source,var/large) var/obj/effect/decal/cleanable/blood/B var/decal_type = /obj/effect/decal/cleanable/blood/splatter var/turf/T = get_turf(target) + var/synth = 0 if(istype(source,/mob/living/carbon/human)) var/mob/living/carbon/human/M = source + if(M.isSynthetic()) synth = 1 source = M.get_blood(M.vessel) // Are we dripping or splattering? @@ -297,6 +299,7 @@ proc/blood_splatter(var/target,var/datum/reagent/blood/source,var/large) // Update appearance. if(source.data["blood_colour"]) B.basecolor = source.data["blood_colour"] + B.synthblood = synth B.update_icon() // Update blood information. diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index cc105e1bbf7..419d82ea649 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -363,15 +363,16 @@ var/damage_amount switch(damage_type) - if(BRUTE) damage_amount = brute_dam - if(BURN) damage_amount = burn_dam + if(BRUTE) damage_amount = brute_dam + if(BURN) damage_amount = burn_dam + if("omni") damage_amount = max(brute_dam,burn_dam) else return 0 if(!damage_amount) user << "Nothing to fix!" return 0 - if(damage_amount >= ROBOLIMB_SELF_REPAIR_CAP) + if(damage_amount >= ROBOLIMB_REPAIR_CAP) user << "The damage is far too severe to patch over externally." return 0 @@ -394,10 +395,13 @@ switch(damage_type) if(BRUTE) src.heal_damage(repair_amount, 0, 0, 1) if(BURN) src.heal_damage(0, repair_amount, 0, 1) - if(user == src.owner) - user.visible_message("\The [user] patches [damage_desc] on \his [src.name] with [tool].") - else - user.visible_message("\The [user] patches [damage_desc] on [owner]'s [src.name] with [tool].") + if("omni")src.heal_damage(repair_amount, repair_amount, 0, 1) + + if(damage_desc) + if(user == src.owner) + user.visible_message("\The [user] patches [damage_desc] on \his [src.name] with [tool].") + else + user.visible_message("\The [user] patches [damage_desc] on [owner]'s [src.name] with [tool].") return 1 @@ -1028,7 +1032,11 @@ Note that amputating the affected organ does in fact remove the infection from t R = basic_robolimb if(R) force_icon = R.icon - name = "robotic [initial(name)]" + if(R.lifelike) + robotic = ORGAN_LIFELIKE + name = "[initial(name)]" + else + name = "robotic [initial(name)]" desc = "[R.desc] It looks like it was produced by [R.company]." dislocated = -1 @@ -1041,9 +1049,6 @@ Note that amputating the affected organ does in fact remove the infection from t if(owner) - if(!skip_prosthetics) - owner.full_prosthetic = null // Will be rechecked next isSynthetic() call. - if(!keep_organs) for(var/obj/item/organ/thing in internal_organs) if(istype(thing)) @@ -1175,29 +1180,39 @@ Note that amputating the affected organ does in fact remove the infection from t if(status & ORGAN_DESTROYED && !is_stump()) . += "tear at [amputation_point] so severe that it hangs by a scrap of flesh" + //Handle robotic and synthetic organ damage if(robotic >= ORGAN_ROBOT) + var/LL //Life-Like, aka only show that it's robotic in heavy damage + if(robotic >= ORGAN_LIFELIKE) + LL = 1 if(brute_dam) switch(brute_dam) if(0 to 20) - . += "some dents" + . += "some [LL ? "cuts" : "dents"]" if(21 to INFINITY) - . += pick("a lot of dents","severe denting") + . += "[LL ? pick("exposed wiring","torn-back synthflesh") : pick("a lot of dents","severe denting")]" + if(brute_dam && burn_dam) . += " and " + if(burn_dam) switch(burn_dam) if(0 to 20) . += "some burns" if(21 to INFINITY) - . += pick("a lot of burns","severe melting") + . += "[LL ? pick("roasted synth-flesh","melted internal wiring") : pick("many burns","scorched metal")]" + if(open) if(brute_dam || burn_dam) - . += " and an open panel" + . += " and " + if(open == 1) + . += "some exposed screws" else . += "an open panel" return + //Normal organic organ damage var/list/wound_descriptors = list() if(open > 1) wound_descriptors["an open incision"] = 1 diff --git a/code/modules/organs/robolimbs.dm b/code/modules/organs/robolimbs.dm index e54598d23e4..a20777928d1 100644 --- a/code/modules/organs/robolimbs.dm +++ b/code/modules/organs/robolimbs.dm @@ -15,6 +15,9 @@ var/datum/robolimb/basic_robolimb var/desc = "A generic unbranded robotic prosthesis." // Seen when examining a limb. var/icon = 'icons/mob/human_races/robotic.dmi' // Icon base to draw from. var/unavailable_at_chargen // If set, not available at chargen. + var/unavailable_to_build // If set, can't be constructed. + var/lifelike // If set, appears organic. + var/blood_color = "#030303" var/list/species_cannot_use = list("Teshari") /datum/robolimb/bishop @@ -48,6 +51,8 @@ var/datum/robolimb/basic_robolimb icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi.dmi' /datum/robolimb/veymed + lifelike = 1 + blood_color = "#CCCCCC" company = "Vey-Med" desc = "This high quality limb is nearly indistinguishable from an organic one." icon = 'icons/mob/human_races/cyberlimbs/veymed.dmi' \ No newline at end of file diff --git a/code/modules/surgery/limb_reattach.dm b/code/modules/surgery/limb_reattach.dm index eadd4db655a..ee0dfecb4fd 100644 --- a/code/modules/surgery/limb_reattach.dm +++ b/code/modules/surgery/limb_reattach.dm @@ -21,6 +21,18 @@ min_duration = 50 max_duration = 70 + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = tool + var/obj/item/organ/external/P = target.organs_by_name[E.parent_organ] + if(!P) + user << "There's nothing to attach [E] to!" + return 0 + else if((P.robotic >= ORGAN_ROBOT) && (E.robotic < ORGAN_ROBOT)) + user << "Attaching [E] to [P] wouldn't work well." + return 0 + else + return 1 + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/E = tool user.visible_message("[user] starts attaching [E.name] to [target]'s [E.amputation_point].", \ From d5aabda108c5e9bbea9341e34766b5a422295ca2 Mon Sep 17 00:00:00 2001 From: KasparoVy Date: Sun, 29 May 2016 10:09:56 -0400 Subject: [PATCH 20/60] Ports Models for Cybernetic Limb Manufacturers + More Monitor-head Wallpapers (#1775) * Ports Models for Cybernetic Limb Manufacturers + More Monitor-head Wallpapers As requested! * Modified as requested. * Different Names --- .../preference_setup/general/03_body.dm | 3 +- code/modules/clothing/masks/monitor.dm | 34 ++--- code/modules/organs/robolimbs.dm | 128 +++++++++++++++--- .../cyberlimbs/bishop/bishop_alt1.dmi | Bin 0 -> 784 bytes .../{bishop.dmi => bishop/bishop_main.dmi} | Bin .../cyberlimbs/bishop/bishop_monitor.dmi | Bin 0 -> 627 bytes .../hesphiastos/hesphiastos_alt1.dmi | Bin 0 -> 599 bytes .../hesphiastos_main.dmi} | Bin .../hesphiastos/hesphiastos_monitor.dmi | Bin 0 -> 577 bytes .../cyberlimbs/morpheus/morpheus_alt1.dmi | Bin 0 -> 657 bytes .../{ipc.dmi => morpheus/morpheus_main.dmi} | Bin .../{veymed.dmi => veymed/veymed_main.dmi} | Bin .../wardtakahashi/wardtakahashi_alt1.dmi | Bin 0 -> 621 bytes .../wardtakahashi_main.dmi} | Bin .../wardtakahashi/wardtakahashi_monitor.dmi | Bin 0 -> 633 bytes .../human_races/cyberlimbs/xion/xion_alt1.dmi | Bin 0 -> 593 bytes .../{xion.dmi => xion/xion_main.dmi} | Bin .../cyberlimbs/xion/xion_monitor.dmi | Bin 0 -> 598 bytes .../{zenghu.dmi => zenghu/zenghu_main.dmi} | Bin icons/mob/monitor_icons.dmi | Bin 4656 -> 4806 bytes 20 files changed, 122 insertions(+), 43 deletions(-) create mode 100644 icons/mob/human_races/cyberlimbs/bishop/bishop_alt1.dmi rename icons/mob/human_races/cyberlimbs/{bishop.dmi => bishop/bishop_main.dmi} (100%) create mode 100644 icons/mob/human_races/cyberlimbs/bishop/bishop_monitor.dmi create mode 100644 icons/mob/human_races/cyberlimbs/hesphiastos/hesphiastos_alt1.dmi rename icons/mob/human_races/cyberlimbs/{hesphaistos.dmi => hesphiastos/hesphiastos_main.dmi} (100%) create mode 100644 icons/mob/human_races/cyberlimbs/hesphiastos/hesphiastos_monitor.dmi create mode 100644 icons/mob/human_races/cyberlimbs/morpheus/morpheus_alt1.dmi rename icons/mob/human_races/cyberlimbs/{ipc.dmi => morpheus/morpheus_main.dmi} (100%) rename icons/mob/human_races/cyberlimbs/{veymed.dmi => veymed/veymed_main.dmi} (100%) create mode 100644 icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_alt1.dmi rename icons/mob/human_races/cyberlimbs/{wardtakahashi.dmi => wardtakahashi/wardtakahashi_main.dmi} (100%) create mode 100644 icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_monitor.dmi create mode 100644 icons/mob/human_races/cyberlimbs/xion/xion_alt1.dmi rename icons/mob/human_races/cyberlimbs/{xion.dmi => xion/xion_main.dmi} (100%) create mode 100644 icons/mob/human_races/cyberlimbs/xion/xion_monitor.dmi rename icons/mob/human_races/cyberlimbs/{zenghu.dmi => zenghu/zenghu_main.dmi} (100%) diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index 27e5d22e830..a092b859b31 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -425,7 +425,6 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O switch(new_state) if("Normal") - if(limb == BP_TORSO) for(var/other_limb in BP_ALL - BP_TORSO) pref.organ_data[other_limb] = null @@ -450,6 +449,8 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/list/usable_manufacturers = list() for(var/company in chargen_robolimbs) var/datum/robolimb/M = chargen_robolimbs[company] + if(!(limb in M.parts)) + continue if(tmp_species in M.species_cannot_use) continue usable_manufacturers[company] = M diff --git a/code/modules/clothing/masks/monitor.dm b/code/modules/clothing/masks/monitor.dm index e8f63401722..9d0651d5ba8 100644 --- a/code/modules/clothing/masks/monitor.dm +++ b/code/modules/clothing/masks/monitor.dm @@ -9,28 +9,10 @@ icon = 'icons/mob/monitor_icons.dmi' icon_override = 'icons/mob/monitor_icons.dmi' - icon_state = "ipc_blank" - item_state = null + icon_state = "monitor" var/monitor_state_index = "blank" - var/global/list/monitor_states = list( - "blank" = "ipc_blank", - "pink" = "ipc_pink", - "red" = "ipc_red", - "green" = "ipc_green", - "blue" = "ipc_blue", - "breakout" = "ipc_breakout", - "eight" = "ipc_eight", - "goggles" = "ipc_goggles", - "heart" = "ipc_heart", - "monoeye" = "ipc_monoeye", - "nature" = "ipc_nature", - "orange" = "ipc_orange", - "purple" = "ipc_purple", - "shower" = "ipc_shower", - "static" = "ipc_static", - "yellow" = "ipc_yellow" - ) + var/global/list/monitor_states = list() /obj/item/clothing/mask/monitor/set_dir() dir = SOUTH @@ -40,8 +22,13 @@ ..() var/mob/living/carbon/human/H = loc if(istype(H) && H.wear_mask == src) + var/obj/item/organ/external/E = H.organs_by_name[BP_HEAD] + var/datum/robolimb/robohead = all_robolimbs[E.model] canremove = 0 - H << "\The [src] connects to your display output." + if(robohead.monitor_styles) + monitor_states = params2list(robohead.monitor_styles) + icon_state = monitor_states[monitor_state_index] + H << "\The [src] connects to your display output." /obj/item/clothing/mask/monitor/dropped() canremove = 1 @@ -52,9 +39,10 @@ return 0 if(istype(user)) var/obj/item/organ/external/E = user.organs_by_name[BP_HEAD] - if(istype(E) && (E.robotic >= ORGAN_ROBOT)) + var/datum/robolimb/robohead = all_robolimbs[E.model] + if(istype(E) && (E.robotic >= ORGAN_ROBOT) && robohead.monitor_styles) return 1 - user << "You must have a robotic head to install this upgrade." + user << "You must have a compatible robotic head to install this upgrade." return 0 /obj/item/clothing/mask/monitor/verb/set_monitor_state() diff --git a/code/modules/organs/robolimbs.dm b/code/modules/organs/robolimbs.dm index e54598d23e4..77c023c0db0 100644 --- a/code/modules/organs/robolimbs.dm +++ b/code/modules/organs/robolimbs.dm @@ -1,6 +1,27 @@ var/list/all_robolimbs = list() +var/list/robolimb_data = list() var/list/chargen_robolimbs = list() var/datum/robolimb/basic_robolimb +var/const/standard_monitor_styles = "blank=ipc_blank;\ + pink=ipc_pink;\ + green=ipc_green,\ + red=ipc_red;\ + blue=ipc_blue;\ + shower=ipc_shower;\ + orange=ipc_orange;\ + nature=ipc_nature;\ + eight=ipc_eight;\ + goggles=ipc_goggles;\ + heart=ipc_heart;\ + monoeye=ipc_monoeye;\ + breakout=ipc_breakout;\ + yellow=ipc_yellow;\ + static=ipc_static;\ + purple=ipc_purple;\ + scroll=ipc_scroll;\ + console=ipc_console;\ + glider=ipc_gol_glider;\ + rainbow=ipc_rainbow" /proc/populate_robolimb_list() basic_robolimb = new() @@ -8,7 +29,7 @@ var/datum/robolimb/basic_robolimb var/datum/robolimb/R = new limb_type() all_robolimbs[R.company] = R if(!R.unavailable_at_chargen) - chargen_robolimbs[R.company] = R + chargen_robolimbs[R.company] = R //List only main brands and solo parts. /datum/robolimb var/company = "Unbranded" // Shown when selecting the limb. @@ -16,38 +37,107 @@ var/datum/robolimb/basic_robolimb var/icon = 'icons/mob/human_races/robotic.dmi' // Icon base to draw from. var/unavailable_at_chargen // If set, not available at chargen. var/list/species_cannot_use = list("Teshari") + var/list/monitor_styles //If empty, the model of limbs offers a head compatible with monitors. + var/parts = BP_ALL //Defines what parts said brand can replace on a body. /datum/robolimb/bishop company = "Bishop" desc = "This limb has a white polymer casing with blue holo-displays." - icon = 'icons/mob/human_races/cyberlimbs/bishop.dmi' + icon = 'icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi' -/datum/robolimb/hesphaistos +/datum/robolimb/bishop_alt1 + company = "Bishop - Glyph" + desc = "This limb has a white polymer casing with blue holo-displays." + icon = 'icons/mob/human_races/cyberlimbs/bishop/bishop_alt1.dmi' + parts = list(BP_HEAD) + +/datum/robolimb/bishop_monitor + company = "Bishop Monitor" + desc = "Bishop Cybernetics' unique spin on a popular prosthetic head model. The themes conflict in an intriguing way." + icon = 'icons/mob/human_races/cyberlimbs/bishop/bishop_monitor.dmi' + parts = list(BP_HEAD) + monitor_styles = standard_monitor_styles + +/datum/robolimb/hesphiastos company = "Hesphiastos" desc = "This limb has a militaristic black and green casing with gold stripes." - icon = 'icons/mob/human_races/cyberlimbs/hesphaistos.dmi' + icon = 'icons/mob/human_races/cyberlimbs/hesphiastos/hesphiastos_main.dmi' -/datum/robolimb/zenghu - company = "Zeng-Hu" - desc = "This limb has a rubbery fleshtone covering with visible seams." - icon = 'icons/mob/human_races/cyberlimbs/zenghu.dmi' +/datum/robolimb/hesphiastos_alt1 + company = "Hesphiastos - Frontier" + desc = "A rugged prosthetic head featuring the standard Hesphiastos theme, a visor and an external display." + icon = 'icons/mob/human_races/cyberlimbs/hesphiastos/hesphiastos_alt1.dmi' + parts = list(BP_HEAD) + monitor_styles = "blank=hesphiastos_alt_off;\ + pink=hesphiastos_alt_pink;\ + orange=hesphiastos_alt_orange;\ + goggles=hesphiastos_alt_goggles;\ + scroll=hesphiastos_alt_scroll;\ + rgb=hesphiastos_alt_rgb;\ + rainbow=hesphiastos_alt_rainbow" -/datum/robolimb/xion - company = "Xion" - desc = "This limb has a minimalist black and red casing." - icon = 'icons/mob/human_races/cyberlimbs/xion.dmi' +/datum/robolimb/hesphiastos_monitor + company = "Hesphiastos Monitor" + desc = "Hesphiastos' unique spin on a popular prosthetic head model. It looks rugged and sturdy." + icon = 'icons/mob/human_races/cyberlimbs/hesphiastos/hesphiastos_monitor.dmi' + parts = list(BP_HEAD) + monitor_styles = standard_monitor_styles -/datum/robolimb/ipc +/datum/robolimb/morpheus company = "Morpheus" desc = "This limb is simple and functional; no effort has been made to make it look human." - icon = 'icons/mob/human_races/cyberlimbs/ipc.dmi' + icon = 'icons/mob/human_races/cyberlimbs/morpheus/morpheus_main.dmi' + monitor_styles = standard_monitor_styles -/datum/robolimb/wardtakahashi - company = "Ward-Takahashi" - desc = "This limb features sleek black and white polymers." - icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi.dmi' +/datum/robolimb/morpheus_alt1 + company = "Morpheus - Zenith" + desc = "This limb is simple and functional; no effort has been made to make it look human." + icon = 'icons/mob/human_races/cyberlimbs/morpheus/morpheus_alt1.dmi' + parts = list(BP_HEAD) + unavailable_at_chargen = null /datum/robolimb/veymed company = "Vey-Med" desc = "This high quality limb is nearly indistinguishable from an organic one." - icon = 'icons/mob/human_races/cyberlimbs/veymed.dmi' \ No newline at end of file + icon = 'icons/mob/human_races/cyberlimbs/veymed/veymed_main.dmi' + +/datum/robolimb/wardtakahashi + company = "Ward-Takahashi" + desc = "This limb features sleek black and white polymers." + icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_main.dmi' + +/datum/robolimb/wardtakahashi_alt1 + company = "Ward-Takahashi - Shroud" + desc = "This limb features sleek black and white polymers. This one looks more like a helmet of some sort." + icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_alt1.dmi' + parts = list(BP_HEAD) + +/datum/robolimb/wardtakahashi_monitor + company = "Ward-Takahashi Monitor" + desc = "Ward-Takahashi's unique spin on a popular prosthetic head model. It looks sleek and modern." + icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_monitor.dmi' + parts = list(BP_HEAD) + monitor_styles = standard_monitor_styles + +/datum/robolimb/xion + company = "Xion" + desc = "This limb has a minimalist black and red casing." + icon = 'icons/mob/human_races/cyberlimbs/xion/xion_main.dmi' + +/datum/robolimb/xion_alt1 + company = "Xion Mfg. - Breach" + desc = "This limb has a minimalist black and red casing. Looks a bit menacing." + icon = 'icons/mob/human_races/cyberlimbs/xion/xion_alt1.dmi' + parts = list(BP_HEAD) + +/datum/robolimb/xion_monitor + company = "Xion Mfg. Monitor" + desc = "Xion Mfg.'s unique spin on a popular prosthetic head model. It looks and minimalist and utilitarian." + icon = 'icons/mob/human_races/cyberlimbs/xion/xion_monitor.dmi' + parts = list(BP_HEAD) + monitor_styles = standard_monitor_styles + +/datum/robolimb/zenghu + company = "Zeng-Hu" + desc = "This limb has a rubbery fleshtone covering with visible seams." + icon = 'icons/mob/human_races/cyberlimbs/zenghu/zenghu_main.dmi' diff --git a/icons/mob/human_races/cyberlimbs/bishop/bishop_alt1.dmi b/icons/mob/human_races/cyberlimbs/bishop/bishop_alt1.dmi new file mode 100644 index 0000000000000000000000000000000000000000..e403436daf428d61b816e942d7ab0fad0c99c927 GIT binary patch literal 784 zcmV+r1MmEaP)Iv9Zt3&$zg_wY9aw!^5GWp{uK_udlD5prEX* zte2OUn3$Nv#Ke)2k;ur%ySuyC*w|E5RGyxmz`(#tN=m}Q!lTq3y3Nha z_xJaclarmDoxi`o)z#I#y}iZ7#sB~Rwzjt6;o-r-!OqUkmX?-#dwagVzN4d~)YR0n zva;6J)}NoBjEsz_sj0xgzGC)ttc@!6~s0~Q=Gk>_)w%Ec+%^z2-WyGe-ZXk(@ef<=PGs2-cY9&aOF%vGjNXkw|NdYw z7^Wj|gP)0foQuo{^p8}ku`1F}K%YdaRMSe#=FkZiB3HRsKquf|a;cVb1?dyLD#KdK zT0xJ%7e!ux{zhLH<6;f!JkDgGOQAQQgI}o%dO;5hqg%cq=Sj2;cKZW7aa2d!Z^n;H ztIqf-ljqA79`Kdz0gS=7)!z(^Zg*saAP9mW2;vpMF8Gf5f$^x*ZiVm$$NXTfW$Dmd z@%zvQ$Na$NGf_>=6+fE%uDj+3rfR9{uv}?ifopzX8!bv5$SejO-0}lE?03O7N;o{> zm>;f}v&>HReBhQJ`27Y)#0Sp#fglKiAPC|$K>L4m0P)BAe=I*>{#gHy^`tvBK8>Pfw$h0KmY&1M%4>00001bW%=J06^y0W&i*HZ+cW%bVOxyV{&P5bZKvH z004NLQ&w|kt-;I z37^Q{H}c;JZD7~ZLn0y~DJdzyz`*79 zb>{#800DGTPE!Ct=GbNc003`#R9JLGWpiV4X>fFDZ*Bkpc$`yKaB_9`^iy#0_2eo` zEh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LYR3K9+BQ-H4K39p0GbOXA z7^I7fGp#5wHxaf02unywnTTR|Q#3OmRUrdox?<>Kw2j zm#U%_9wFCiX0<|H)$BMF7L@irX$9%UCI#x<$M@3O4Gwq!8{Fp?(EDP5U(x$FP#~kV zkJg4j{Q=aa=YE|M6!cScsGJ??e!1Zdke*KY0u^)_It0F-`WSf(tV{N1RCvWXK^FZv zc}|du2mB1b-9HF|AP9nh`}^Jea7=TH1Hg8EsCpdcAp(@_=7)51bKAY91Ao4oACepU z<|kMT*vk*;df6>LvfsP;A$`016X@Id;j;GAfTM!#{7_}~U;N0s`5}yb5ClOG1b+pd z4@dxD{n`GXexR`ZKg$msvj1oKfkXEHG(T|G`+uGv lo&;yC?bbmM1VIqIicc0k4SStbl_3BC002ovPDHLkV1nnF2@U`N literal 0 HcmV?d00001 diff --git a/icons/mob/human_races/cyberlimbs/hesphaistos.dmi b/icons/mob/human_races/cyberlimbs/hesphiastos/hesphiastos_main.dmi similarity index 100% rename from icons/mob/human_races/cyberlimbs/hesphaistos.dmi rename to icons/mob/human_races/cyberlimbs/hesphiastos/hesphiastos_main.dmi diff --git a/icons/mob/human_races/cyberlimbs/hesphiastos/hesphiastos_monitor.dmi b/icons/mob/human_races/cyberlimbs/hesphiastos/hesphiastos_monitor.dmi new file mode 100644 index 0000000000000000000000000000000000000000..5f3d72f3fc4dff00edbf675aaf10609a9e935d54 GIT binary patch literal 577 zcmV-H0>1r;P)V=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRL zOex6#a*U0*I5Sc+(=$pSoZ^zil2jm5DI+y8B|cY)i!&v&s2HS+i!-e#F*g;&HbhgF zhD({Uf~%hk*m?kBXeDGp!K2Xt00B)&L_t(oh3%KUN&`_4g~y+T-OfoOn52kVfR&(ZI-^<1Ed^gdu=C~A%DHD?FN=i<%-5a0b1qxmk0DxCYFyhY z%WKT3%p1M&#i=~M?hmeHp5DFEO-FNlX{+&q^bj$Cmp3vF)K<$3e9 zv+ot|U6ISe!RNd8&(q#s*DFlMm$HzgT<^+40tL$RJd@cu_ee0{WtwDue(~oizVS2N zK_P*2f^$7kmEEd^^*UbN=nMh%R4(etE#FxIXOv5Nii`oX=`hno0}UN8VU#q7#SJq>+5@XcjJaWn(XeIgchC znG~WBtf_2jsA?D9*=?-4d4%^q>hqJ4Ke}ders9VSK4Z0-X ztz6Pxbb|ld`%{X-w$XV-jOPNT{E4`)KWo~5|2h-9q|*Kj+Y1-hzp?0hY;kUOLljeT zw6ozdN8SxT+eJP<^;sSmo&Smd&JBHUsZ|%GXa8k3ul*V7$Yt=W{Zw!5y}au>Vg|q1 zrGD~m3sd=>@QpvFVfOFkMHkonOI*KTcgW&;1);aM%RA26Ke%`AoxIHPLYd>0!Vb;( z@1(B$wEw~{Q2USnFEh)T{}bz9Xe>DQe<3>MF!z7*{|li`Gr^SOy#M7t+ShTda^3j6 f9AwyY^?eLqyhYv~@OIk?jCKZ3S3j3^P6o$;P3D6i;IhdgoJ5nX|}euaBy&}tgOJm zz=@3iAOHXW0d!JMQvg8b*k%9#0B?F!Sad{Xb7OL8aCB*JZU6vyoKseCa&`CgQ*iP1 zGC)ttc@!6~s0~Q~Ptc_1E64*pTT#a#Q+ShzJu*HIOAQBZ11Y3_Eyz)IhQi z$XH-Yb{544$UY$BddXRGF0kBjL0#bqw60YRm&FGN6l^XKA0ZV8wD<(Ig09e??_W5e z*4oVc8bDB6DPC^q0Ok|?V`zZ&E7bOb8|Yod@5pbcenV7F`r41PwRR$b-BsAXPq0D% zly>JlPy916uMYZij_Z2sHfUk+1qVS81VIq|3g++WHP^UjQg(^FzAL`?0_931{VU zp@Kg|yew*RO3fes-1 zf0iF8Z2!;l1BdMYS$=rHc>hoH!vluP)t-sz`(#% zR8&`2SD66+LPA2UtgO@1(;OTe@9*#b0RPm~)Fvh->+9>xX8+6p|2sQ70002Cwzid( zm5Ymuz`($1X=!k9aHEp|z`(#_XQsaZ0004WQchCV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+(=$pS zoZ^zil2jm5DI+y8B|cY)i!&v&s2HS+i!-e#F*g;&HbhgFhD({Uf~%hk*m?kBXeDGp z!K2Xt00Ci1L_t(&f$f;Vj>8}fL|Gsq*pMcn&Hn$NE=sjWGgP#P)%r<2jq6F2%Z!at zUg7JBs9R@k{mBdLg%|fva|mIcBnP`hS|~1(gY}$JUK2|Lw>fOv7G@T7PwP(mO41X0 z;NhwV24^Yd zlno3gawUoehM&m)2m0?sYhY@rRWEJ5z9m=ybOU5O02h3i@4xTRHu(GtDvF{g%D=!r z^S!8#_6J+jcTS1DFf!U7OyC;sYk!amz-WJ{1~uI0#COSHus>9Tk{v~s28R1X;8+|b zQGY{!0O@|bKj3&j+8PEJEZ zLnk0d!JMQvg8b*k%9#0B?F!Sad{Xb7OL8aCB*JZU6vy zoKseCa&`CgQ*iP1GC)ttc@!6~s0~Q?C*i5es!zLsra9?i#!H)CBGs(2;+vi|=2j^F-fh^yHMXb2C zHn*l$oX+##pB3jS{gTCei6ytfrR8E4D5<~2RLomoE>hUOq#mBdK7J%fFDZ*Bkpc$`yKaB_9`^iy#0_2eo` zEh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LYR3K9+BQ-H4K39p0GbOXA z7^I7fGp#5wHxwQ21KUJrPf;5>agwy?|kg0 zPQpqPtAI*9&$AZm4T!J8*bkjh_=)I3&=~~f>XRyeF{XEe13^z`Jtls0VL;CtcUtar(20&H^ zpr5G0hxz{d4!*(X511rLk|h5EB9IS)`C*mzn(u{-l4yQdsvJ6=v+Txn7R?W8pu@cy zSQXLypayz_mtK*fhx5a2P?|a4#`6Q3?&J9ZkN461fX4fHen4b?2){)pgd|ClB>4@% z{vYKB*dFZvQGS4+{XfbN*Z}PRQGS?k@b~{HKTP27|51LJ!A}VA@4$?M9}rM}m~jZn kNtmhWJ|jSqBuVl$}D)vPT5+x!_0JWj01QkRD35o_;B$PE_NyLa^U4WN@ zB0{L3wjy8!Lf#zl) zHx+=lZ|5VT3>*c9&)KW(01XXC;b?n%I1?`V3AhTtID43~3|NB$C=_J1!}NQ2w;|vN zSHN%`q7dQ0hmpetI9U4N{{8!~&`H?>czJmh0)?gz5O@?vN5>~mp6uVh-`(AvPNxGI za2k*n0Ym`jI&5rga5$W)si~QnS&O+jABQtl*xD1e&BHVX?r!UhK$85ub{J7X{y4-bzmTeetQS`vvwV`JlVu?MV3U(_y}${vqN1)L;Oh-Oh5~pLE`QxovgP z`sfV?_TlAYr*pe$M_|n#UHAHqCqH>OC8VCl|FvhS^Tk~zBbiBfYJ|^+&RAlTVG!j;{ICu0M-N5nibq@F-aZ32^b?xG_4V6BL?3Emk1BO(4q4m=6mt|o= z!k|A!?_4LJxL7!UGa=)ek*2TRlHLmj1{*^@L>HbfrL8J0&;9SV5`y)`hXdymSj(-! zWdC~(^{7{HS{~8p>zexT6v}RGK}tZvB5JxG@xUr!)6CeptSywQ-+z7Lh>K>b`L&=^ z*HUh#NOjgoJ6h?{TK8IAZzMb){;I&3I$dtDlw{W}W!`x91ydQY>FD8jip^ZPoGo;1nae1~e|oO$#)>#w+@}IXdGT zaYEp!$wjukah*pjx9>R^&;RC-)taPK(rL^f!;dzw) z$Jnj4J6~C@I2qKEk!w`EQOR*#e35@Lu(Hu7swWaruc4E&+idzFsFDWjP1zyBx2d*^++nOyDtm0?N9^ zQaM;*93Q5P-G+~`F1{Kby>6;~vz!qXDeP+}6`_y>&B;FDn#1>MJj5w0DVeE)pu6Si z_if~mOhCB7h9P7@wW&^!^qZ3hV<6$Kp7*dBAx=rwnU)Q12*A&^g*A~Fj67m{fkJuX z78`U*(bKU43F z)ai1#cplBjt3{C{*jN^KhBahDfVINRNMI_)k^q8)+ky0kr1KC&$U=S^vDhjolnRdM z@l6p!@hgzn{&HM$kG7Cq!K$9tKtmWosg1a!GyMj+NkGm<6#TWG0M8-B(#bIeH7X)v z=f@Iw0&Fbeq^Gd6N9i-eBC+2TVcNqTjY(7CLo(=ux&>$VN!L5))D zOP&C*zF-y_ZY~~8Pd}WVJ}ooe(3U2~T!kjuNsar+*q9$v3OB<(@1ihR zFG?jV763SJC@<-ukjr!zi8Cx3L8mo+T-tcoGmMUXsaOzV}BzJQe21oE(LilSQ1prX zgbYPcya5!M_Y7jls(6P2grWoED1(k*=>Zp&icMB}eDZwg+^_qXDfb%3s-Q4XuyH}} zRPQ7lQyJD19?EjXnEyhbr-CJ`I{HO_gsKdMOtC^3%%F{fP1E8|{{MG(@-#xUBr9sE zPVH4B_3h*n6_eSGA9<-p*CRyk*o#e&s|_cE2Dz%EKhh5(&{c&y*|gPmuRF z3b^K-p;}tel_5<~>&urvb>QbfnIw?I!+KYSOr2Ce6Y&kCaO$H2VpRScQNKuQ5bYhq zki|D)s$iAET`0oDN*$W;bC*7PAim)X@2jV7Y$0?-jR|qCUSJdH1;kzQDG~InnXb%v z3FXs$R<3;a5n9o*OVu3^G~m_P4u1A47i5L7ux?d6{n-57ENW9}C3{*CEUi|dghBHa z6b_yy_y{ZVv!<%5!`or%=iqqJypR)-v>XZ-mm%4#j>WiSg3UXHpuWgfi8~GkeNq!U zJN77)F|NdWUQgkksKK!A?oVRK<~#O^8cj_Vd=52ZnFEfGLLNJ z%4WI;?hf4DTP414N)DLT=IbVXb=Q9~x=~_s<^|LygEI{==r@<=t@|P(g@hl{iy} zv#B9YZvn?1zcAILL=zv{ax3;T`oIoMS_Y<{&Y&k2(UpoUj9r)RU_`!PvM`GrQ5iZ8 z_9ou&&?HdE@P)gsu$C@so_mcWXSG zbSHmdMCF6s5t2((cQ)Ib&Y-auDgpM#kYZP4rGY1cXZ8^-_&7)N2U3wuS%p+Kp6?mdo@qdG-r z^=%N-Al}V+JMD)}wyUFe*u>3;f9h~Nhog{I1u>6+$EcfzS0X>8+i82U5QVzPphEGF zou3lnG#DWx!dBo(GXk?j9*Vqpw{IeSNNHg83cVc`LY(bv@ny{6ChlP?=8-&}wFGk> zRn+HG-Gh$&L(ZK;+dX{aQ_6LCK=6r>GhGo6ETZz`6DKAWcgz2uz)rc8>%#ii=|PcfvAG>|WRi_|Tz;c)TKJK`azF2Th^Wpmq} zp^~&3>wB>RrQ6UP6Lj_+UT>=?rcH#1u#pQ{N_O@6&zdoEJqn|WGUs1i{gZZ0(pXO= zx2h_RiNnD>rB>KF+I!V(Gl`;7HaR5>#}nRBFEKMf-M8RnrQS1DmdwLsuw&{}X;|np zUR1;~+QE0ud5&Q|k>mFkS*9LOeoTiQ#xw~|Zz?y&hT-I>TGI>D^-1?sBsM6o_6sY5 zl}Ewiz@*yLA-^|PJC&vlA#;RsrEMa?XylS#SeUh3Wx4(2hPOnOl<-)QAI+%T)7})r zEmxJ3*H2kqFH;>F9UUP1F|-zV$N`_$f|nc3iMlqWcG(YIUalS_L|rvW(I{_SL@KZ} zG54OdBSd%3|L~YK96vc-J32Z#_y+3eT6RaP>qGA)vNtC*Zo?G!<>1t*N#oRCPFjYg zpaP?RNatqX%(4!4@rf%{K*N1Tt;b&`*=+US8C$7urSMCJ2VPuZUC|@(8)0*|?n8&7 zBgeIgNz1OUt4hAXH2f@yM04y$(dp3%1s9q0!ydi}zw7}0^}cq|4ArR>Dsjd>HDyF( z-pcZyTJih*n7|T!bC_2`yX+b_>ldYOgIl130DzTUO+}0{dAu+#B5c;ggW-7+l2m7s z$Kyo#nYw<=>G_Ezr-sPPRoz2Pmo66^@3xKSL&Q$w-dLKlb&TZQubz|E?Ri31wwe?Z zK(Tn#W9^?HGOGeCpXu9W(hVdOX#1W{7wrlC&O6c$K*BjlZ;V{-~^)x*^8gOqH02$?mORx9^HN zOeHRlwc6h%In57%mi<`;FAN@zOj7-rk^YpZC*KB~N?(ZNIhLRC*7V{!TCYRwoZrc3 z6Fz7EdkN<*~wa(%r)g-LP-hApT}KU2^*CBB@w zZC7aJ*%Z_j;hl|)*|l5Re5O2K)d)D%d-OLmuH2gIj(Y0EdO>`HpDLa_8_XI{B(0~u z^%M5K(NNZ-41S}>hX+4$$k20=pbWly%C$mUZjx!O+KKPV;bVLfmCIUcOm5}ZV3#ih z|IzceGV4Rtq!V!CYO1!vJGLgSU07aSt^s6MTX zEW-$^JQTZgbmfH;+veQS&5rv0z5dde>K+r#xK;hV;94(Man8k$r%%sudomYWLI+vJ hbu;*X5Ijm$={i&i|N5ow;bXPz=RGdF3mtvV{|_ayOi=&; literal 4656 zcmbtY3se)=x}LyQ+EN;OsiM_7w#SM`6!4&+f(cqGK3bwyMFkBO1s_OgK|x3|QQJeU zkK8V+=tT_5sj+$>7L2Rj=9y!>kPdVL1SSigRKPft&S_bmhbXb=z(1=jHB=G^|Z=IkZcYYZ+~pZp(}_-pPIe|2D2bXtYyjDq=RKDsHSx)-zv zeoXn3F#XRN*QVEf@aCSW?z{PqoU02rA518yxH2_pjsG0O@#C?F7QX(f_QN~N#p-=u z&Iv2rP_yWK=$Rdp>su|xtIHn=KH`13g46GI@14RGKb*>(>fLX-Q_M{FP;Q%>miEOy zErPIR>q1s-Nx3rI9+A9d>;3Ak^;@0ZnaYkT(OfwudXkeJNx>HujQMcUOPd6 z=%IUGi3HuedT>1ZZZPf! zVjW|tyX+TxwD1u4vB}a@XQ|sp3l|f!YtG$pru>N zWwv8rWYpSS%edz-jC+sKb6$sR(b2jZtZIt5N0IIc{yW8hBUwoSG=!%D{0GDO)7tv<(4cahDtikycZ248YgWwDyr) z%`4@OQ|usE91_)x?Cp}$kfx+vu5s}CCJ9Q#+Z?642b1@Oq{sz&HWZB zn4~;sPNPKEDe0VS1<{3@&7W|Oi*@2|R+uSemtqw+8HL&N;+p>ok=~%z@XC2|@W8di zr*ul8dU`oqj%u)xDvbw!NFVMKm5BP1oGixXWFc>R+$m;XN|S|ws!hLeqI9DBV~jDU zg4y6RTyENo;fts2q?=V_mno5q9ib9z#Z;H0op@gK_|Y2JHNwl5m7s7ISqb~aLg4+a zFZ8N@tXEItH&7rpL96Ctu5^yj)!xI2EnlN?pbENYS%&;KTg-Mt8~mZ&!)&w^97a+ zh|qjt`BP|;=Mx1uk!GhtOMjEc9h_e#$z?{*ZV-4=RK`PXhAD!QKwRPMaQK7hejj6- znT_-5$@PLE=klckM0(n7p>12DOqZ+d=m-JBqy25QOpjN%H{L+tn>l6I1?WcX0lj0K za|K3k%+XFfZ!qP51G~oE`?R`=ZL;gfi)+%vhPMGfILGbylXors`6RhJ?XWu~Z2Tp?CX8*h z1Bwo3I4>3q?;EE$z<`$Xl-EQYI(=AQX4@GFqZt2#@gJFj_)leu73XrmS_=!!hq&>; z)fr_tgM49z0O&oPoVPGTZz69K6*lQ!)bOqya>lBjO&D%-`#UBCSzZ}F&0IvT`Gcz~ zWd|H*Vl38MZS!r?7}OxR&kHaSMW)`#wnnx@9F6)OMZL@MYohW2mtgRC$eH<=?C(8o zcA1laF1BORyBsLsszzA#3WoZb>^BWN56FKF;s0Zs@UoH;yrd0hDVO>LitWG^G zFq|Ywg$06kk&OSMGa@{crV<)m_76Ag(zLC`^UobQAvO(4_4=&cn4*lm%wm6IE5?EV zHP4*#jDR*a)}`@5_Ar}m&_O8ZG^70`wW9mUgvM3pf-_}jOg4cEdQiz}@8};^4Sy`O_YF}n(n_6urGn>FiiMT)hgijvkhis#`w!^( zUNU~B5R`4gK-s7@&BBVH$xxamA8GYUs#(F84)M|5jG1A~qgFFs$>}VTPHREMv>qp* zMo40S&EVd`=T|UdnEE8^yuLdZcc@1Fkd%-dr_Gb>oY}d~!ipxXC&&@bbTi4FFBAJ( znRG}V={*f>7rk{3a%q+CwWkRFTVaId6buTd%80Z~!^QyF*C`}Si_ zRMKOb2jzR-+zf5z`!-I3748Oo*a&2mmX+tNSIN=OCB5fOA$9HI1VJtXlH92 zCXh6_iT`BUzrmG&fBSDq`W^oSubSZ3QPBz!C9$3QRkRvfWeTXAB|e`i+RZ=t5$}ZN$EpvXf5Lb(c#f!^qEJ1&tWw4h0MM*)X?;K zacLvYPQEP^--d5ceSLjLF>us6ezX8IhVwD=RtyY|TAR=7F~0#l_6Y~vC}S6u9vN)P zw-dQrORGHazKF6o*sx`QC^nk20%E`ek}DNg5{2k}gH-6HI= zWe$L-fTIj3@Z+$e5oCW)HcyCMt*D|$Nr)rRn?WN`24~*62mR3`6YrQI6GJH^p*v(x zgWi(>d!Relgtn8SV0s-HJF_J{B6693{jw%r2T{R^{1YrwJeKW)arr-$2LkMv@AwzP zs>6rDvH?BV&H|el@?aBhi`&R z*D73!Hxc{`>hK0VtP<^2S~FLtawC1>(fIQ1m@}+$2uUq-6G}Q_J1eR{#mio4PtWub zzilS51v2Ju+c;pLr^G9F z;UCZ~FUeqB6b+Z2oFf$H6!W0O1X%~!Ly*xSU5JWQqt-pJNH8SKZkLK_m7w#fZCLbU zOEWhj?yMf{u~#6homA2wUn1U%&2EPEYPzv&vYpk@?0dX`-hg_=IBOV^K6e&6=Poy> z;(K!hbw=eZTmj1i>aNgsAQ5I%;{TSfbvJ%X90?55OA=?CqX{x{I+`qM7X)E~#ZS*YM+_2PHkmCQjE9OaEq4e-6gUH6i&qZK9G!6hJ2& zn{4OL-~uiucstDWFpvS6I%Blo$6f!s+Aokg?OI)4dA8f&D2)X8$Yhy~BAS0A(kE(2 zFiudT40fdw{ch3Oa~$O%Mm28&oOVTzk)KH=;d%Z~_$%YE8b#Q!SrPVxpVcwQ-NZG} z@FcR0Qt_ar*eb+}c}ngpI)&vVABzJ^2(UE`O`u)-U}YqBilCBIgG2~!o4ka|JVvt# zqGnJr&d3>Ctg&j0)uM-1oZv&Uc-rl)7L))DgK!?e7Sp-#lz^YLkzHah8Pn7*kC;TJ z+ZGgowt=U%+efjf&+J~oy&MfU{K5wibdXx@TLW9iGyZ<+v$gOG^C~QWCu(BWZ~jV7 zICg*@{_LuEDw^O-3Eed=LF>34u7AEd zycqFp^$e;KRk#lut90&p?~yYm%JhHjRFH1TS=r)proH-fhvzsAkBnnwI0&_lOOIlZ zTgrq?+98?G&T&rXf)rG*P9t^nGXfL{nb-nM@RWc>J>J}^J?*b^zS?W|$u|`h6p68p zLHp^ZgxhDoMaz6zi`YsVyQ4Z{DK+R?Z&&*Rq^i~fcN_5NG?63zchzJ)B_Z|jPY^K% z6r=ro&pv_(0b;93oCxPP!6JQ(!@t`H5!Wdy-~SjMeI8T7$Jc@D2~IWSgePimTR^rf i(ry^{+cB&YSoyyYsfS|+1itpTt@|)6ByV-piT?s4{8Q8b From 384292b53d16ad302f8a0adc9185601340088692 Mon Sep 17 00:00:00 2001 From: Yoshax Date: Sun, 29 May 2016 16:25:10 +0100 Subject: [PATCH 21/60] Updates changelog --- html/changelog.html | 14 +++++++++ html/changelogs/.all_changelog.yml | 12 +++++++ html/changelogs/Datraen-Xenobio2Init.yml | 40 ------------------------ html/changelogs/Zuhayr-accessorizing.yml | 5 --- 4 files changed, 26 insertions(+), 45 deletions(-) delete mode 100644 html/changelogs/Datraen-Xenobio2Init.yml delete mode 100644 html/changelogs/Zuhayr-accessorizing.yml diff --git a/html/changelog.html b/html/changelog.html index 5f348af1424..7199a0ef38b 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -53,6 +53,20 @@ -->
+

29 May 2016

+

Datraen updated:

+
    +
  • Injecting people with mutationtoxin no longer mutates them into slime people.
  • +
  • Removes amutationtoxin.
  • +
  • Removes slime core recipies.
  • +
  • Adds slime monkey cubes, which are created by injecting monkey cubes with mutationtoxin and activating like a posibrain.
  • +
  • Maps for Xenobio2 research labs/stations.
  • +
+

Zuhayr updated:

+
    +
  • Backend change: allowed accessories to be placed on any clothing item with the appropriate variables set.
  • +
+

27 May 2016

Yoshax updated: