From 9e080d555f1710773b2d4cb4bb9c60831534659e Mon Sep 17 00:00:00 2001 From: Miauw Date: Sat, 24 May 2014 17:45:36 +0200 Subject: [PATCH 01/55] Fixed #3077. Singularity now sucks small items instead of large ones. --- code/modules/power/singularity/singularity.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index a0725f79ee5..ba71e63268b 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -231,9 +231,9 @@ var/global/list/uneatable = list( step_towards(H,src) if(current_size >= 5) - var/list/handlist = list(H.l_hand, H.r_hand) + var/list/handlist = get_both_hands() for(var/obj/item/hand in handlist) - if(prob(current_size * 5) && hand.w_class <= 2 && H.unEquip(hand)) + if(prob(current_size * 5) && hand.w_class >= 5 - round((current_size / 3)) && H.unEquip(hand)) step_towards(hand, src) H << "\The [src] pulls \the [hand] from your grip!" From 9ed94fcb78e582cd708ce5b5c4e471b90470194c Mon Sep 17 00:00:00 2001 From: Miauw Date: Sat, 24 May 2014 19:18:17 +0200 Subject: [PATCH 02/55] Makes this actually work properly. It's always harder than it looks. --- code/modules/power/singularity/singularity.dm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index ba71e63268b..8ceae066f17 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -31,6 +31,7 @@ var/global/list/uneatable = list( var/target = null //its target. moves towards the target if it has one var/last_failed_movement = 0//Will not move in the same dir if it couldnt before, will help with the getting stuck on fields thing var/teleport_del = 0 + var/sizes_to_number = list("1" = 0, "3" = 1, "5" = 2, "7" = 3, "9" = 4) //so i dont have to mess around with weirdass formulas to get this done. var/last_warning /obj/machinery/singularity/New(loc, var/starting_energy = 50, var/temp = 0) @@ -231,9 +232,10 @@ var/global/list/uneatable = list( step_towards(H,src) if(current_size >= 5) - var/list/handlist = get_both_hands() + var/list/handlist = list(H.l_hand, H.r_hand) for(var/obj/item/hand in handlist) - if(prob(current_size * 5) && hand.w_class >= 5 - round((current_size / 3)) && H.unEquip(hand)) + if(prob(current_size * 5) && hand.w_class >= 5 - sizes_to_number["[current_size]"] && H.unEquip(hand)) + H.unEquip(hand) step_towards(hand, src) H << "\The [src] pulls \the [hand] from your grip!" From dca72dc916d3dddb0f6d7e47c2e40bc8bba8b684 Mon Sep 17 00:00:00 2001 From: phil235 Date: Mon, 2 Jun 2014 20:25:06 +0200 Subject: [PATCH 03/55] Fix Tachyon detector and TTV not being deleted if inside something --- code/game/objects/items/weapons/tanks/tanks.dm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 74393eafbe3..1cd70a97fe7 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -205,13 +205,16 @@ air_contents.react() pressure = air_contents.return_pressure() var/range = (pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE - range = min(range, MAX_EX_LIGHT_RANGE) + //range = min(range, MAX_EX_LIGHT_RANGE) --- handled in explosion.dm and prevented tachyon detectors fromstating true blast var/turf/epicenter = get_turf(loc) //world << "\blue Exploding Pressure: [pressure] kPa, intensity: [range]" explosion(epicenter, round(range*0.25), round(range*0.5), round(range), round(range*1.5)) - qdel(src) + if(istype(src.loc,/obj/item/device/transfer_valve)) + qdel(src.loc) + else + qdel(src) else if(pressure > TANK_RUPTURE_PRESSURE) //world << "\blue[x],[y] tank is rupturing: [pressure] kPa, integrity [integrity]" @@ -237,4 +240,4 @@ integrity-- else if(integrity < 3) - integrity++ \ No newline at end of file + integrity++ From b5b5735631e4cfe9362f2b827f933d27192e32d8 Mon Sep 17 00:00:00 2001 From: Cheridan Date: Mon, 9 Jun 2014 19:56:25 -0500 Subject: [PATCH 04/55] Refactoring of match code, makes it a little neater Refactoring of rolling paper packs to a storage item. Improves Rolling Paper and Packs sprites. Cigarettes/Matches can be lit by fires now. --- code/game/machinery/vending.dm | 2 +- .../objects/items/weapons/cigs_lighters.dm | 90 ++++++++---------- .../objects/items/weapons/storage/boxes.dm | 26 ++--- .../objects/items/weapons/storage/fancy.dm | 25 +++++ icons/obj/cigarettes.dmi | Bin 2454 -> 4673 bytes 5 files changed, 75 insertions(+), 68 deletions(-) diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index e02188a5fb3..50da8e4965b 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -646,7 +646,7 @@ product_ads = "Probably not bad for you!;Don't believe the scientists!;It's good for you!;Don't quit, buy more!;Smoke!;Nicotine heaven.;Best cigarettes since 2150.;Award-winning cigs." vend_delay = 34 icon_state = "cigs" - products = list(/obj/item/weapon/storage/fancy/cigarettes = 10,/obj/item/weapon/storage/box/matches = 10,/obj/item/weapon/lighter/random = 4,/obj/item/weapon/rollingpaperpack = 5) + products = list(/obj/item/weapon/storage/fancy/cigarettes = 10,/obj/item/weapon/storage/box/matches = 10,/obj/item/weapon/lighter/random = 4,/obj/item/weapon/storage/fancy/rollingpapers = 5) contraband = list(/obj/item/weapon/lighter/zippo = 4) premium = list(/obj/item/clothing/mask/cigarette/cigar/havana = 2) refill_canister = /obj/item/weapon/vending_refill/cigarette diff --git a/code/game/objects/items/weapons/cigs_lighters.dm b/code/game/objects/items/weapons/cigs_lighters.dm index 35f0eadaa47..8fb56e71196 100644 --- a/code/game/objects/items/weapons/cigs_lighters.dm +++ b/code/game/objects/items/weapons/cigs_lighters.dm @@ -30,21 +30,31 @@ CIGARETTE PACKETS ARE IN FANCY.DM var/turf/location = get_turf(src) smoketime-- if(smoketime < 1) - lit = -1 - damtype = "brute" - force = 0 - icon_state = "match_burnt" - item_state = "cigoff" - name = "burnt match" - desc = "A match. This one has seen better days." - attack_verb = null - processing_objects.Remove(src) + matchburnout() return if(location) location.hotspot_expose(700, 5) return -/obj/item/weapon/match/dropped(mob/user as mob) +/obj/item/weapon/match/fire_act() + matchignite() + +/obj/item/weapon/match/proc/matchignite() + if(lit == 0) + lit = 1 + icon_state = "match_lit" + damtype = "fire" + force = 3 + hitsound = 'sound/items/welder.ogg' + item_state = "cigon" + name = "lit match" + desc = "A match. This one is lit." + attack_verb = list("burnt","singed") + processing_objects.Add(src) + update_icon() + return + +/obj/item/weapon/match/proc/matchburnout() if(lit == 1) lit = -1 damtype = "brute" @@ -53,6 +63,10 @@ CIGARETTE PACKETS ARE IN FANCY.DM name = "burnt match" desc = "A match. This one has seen better days." attack_verb = null + processing_objects.Remove(src) + +/obj/item/weapon/match/dropped(mob/user as mob) + matchburnout() return ..() ////////////////// @@ -78,7 +92,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/cigarette/New() ..() flags |= NOREACT // so it doesn't react until you light it - create_reagents(chem_volume) // making the cigarrete a chemical holder with a maximum volume of 15 + create_reagents(chem_volume) // making the cigarette a chemical holder with a maximum volume of 15 /obj/item/clothing/mask/cigarette/attackby(obj/item/weapon/W as obj, mob/user as mob) ..() @@ -120,7 +134,6 @@ CIGARETTE PACKETS ARE IN FANCY.DM light("[user] lights their [name] with [W].") return - /obj/item/clothing/mask/cigarette/afterattack(obj/item/weapon/reagent_containers/glass/glass, mob/user as mob, proximity) if(!proximity) return if(istype(glass)) //you can dip cigarettes into beakers @@ -134,15 +147,14 @@ CIGARETTE PACKETS ARE IN FANCY.DM user << "[src] is full." -/obj/item/clothing/mask/cigarette/proc/light(var/flavor_text = "[usr] lights the [name].") +/obj/item/clothing/mask/cigarette/proc/light(var/flavor_text = null) if(!src.lit) src.lit = 1 name = "lit [name]" - if(!istype(src, /obj/item/clothing/mask/cigarette/pipe)) //can't burn people with pipes - attack_verb = list("burnt", "singed") - hitsound = 'sound/items/welder.ogg' - damtype = "fire" - force = 4 + attack_verb = list("burnt", "singed") + hitsound = 'sound/items/welder.ogg' + damtype = "fire" + force = 4 if(reagents.get_reagent_amount("plasma")) // the plasma explodes when exposed to fire var/datum/effect/effect/system/reagents_explosion/e = new() e.set_up(round(reagents.get_reagent_amount("plasma") / 2.5, 1), get_turf(src), 0, 0) @@ -165,8 +177,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM reagents.handle_reactions() icon_state = icon_on item_state = icon_on - var/turf/T = get_turf(src) - T.visible_message(flavor_text) + if(flavor_text) + var/turf/T = get_turf(src) + T.visible_message(flavor_text) processing_objects.Add(src) //can't think of any other way to update the overlays :< @@ -176,6 +189,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM M.update_inv_l_hand(0) M.update_inv_r_hand(0) + /obj/item/clothing/mask/cigarette/proc/handle_reagents() if(iscarbon(loc)) var/mob/living/carbon/C = loc @@ -183,10 +197,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM if(prob(15)) // so it's not an instarape in case of acid reagents.reaction(C, INGEST) reagents.trans_to(C, REAGENTS_METABOLISM) - else - reagents.remove_any(REAGENTS_METABOLISM) - else - reagents.remove_any(REAGENTS_METABOLISM) + return + reagents.remove_any(REAGENTS_METABOLISM) + /obj/item/clothing/mask/cigarette/process() var/turf/location = get_turf(src) @@ -231,6 +244,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM else return ..() +/obj/item/clothing/mask/cigarette/fire_act() + light() + /obj/item/clothing/mask/cigarette/rollie name = "rollie" desc = "A roll of dried plant matter wrapped in thin paper." @@ -535,28 +551,4 @@ CIGARETTE PACKETS ARE IN FANCY.DM else user << "You need to dry this first." else - ..() - -/obj/item/weapon/rollingpaperpack - name = "rolling paper pack" - desc = "A pack of NanoTrasen brand rolling papers." - icon = 'icons/obj/cigarettes.dmi' - icon_state = "cig_paper_pack" - w_class = 1 - var/papers = 25 - -/obj/item/weapon/rollingpaperpack/attack_self(mob/user) - if(papers > 1) - var/obj/item/weapon/rollingpaper/P = new /obj/item/weapon/rollingpaper(user.loc) - user.put_in_inactive_hand(P) - user << "You take a paper out of the pack." - papers -- - else - var/obj/item/weapon/rollingpaper/P = new /obj/item/weapon/rollingpaper(user.loc) - user.put_in_inactive_hand(P) - user << "You take the last paper out of the pack, and throw the pack away." - qdel(src) - -/obj/item/weapon/rollingpaperpack/examine() - ..() - usr << "There are [src.papers] left" \ No newline at end of file + ..() \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index b51af2ded03..6aeff9dee4a 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -455,25 +455,15 @@ w_class = 1 slot_flags = SLOT_BELT - New() - ..() - for(var/i=1; i <= storage_slots; i++) - new /obj/item/weapon/match(src) +/obj/item/weapon/storage/box/matches/New() + ..() + for(var/i=1; i <= storage_slots; i++) + new /obj/item/weapon/match(src) - attackby(obj/item/weapon/match/W as obj, mob/user as mob) - if(istype(W, /obj/item/weapon/match) && W.lit == 0) - W.lit = 1 - W.icon_state = "match_lit" - W.damtype = "fire" - W.force = 3 - W.hitsound = 'sound/items/welder.ogg' - W.item_state = "cigon" - W.name = "lit match" - W.desc = "A match. This one is lit." - W.attack_verb = list("burnt","singed") - processing_objects.Add(W) - W.update_icon() - return +/obj/item/weapon/storage/box/matches/attackby(obj/item/weapon/match/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/match) && W.lit == 0) + W.matchignite() + return /obj/item/weapon/storage/box/lights name = "box of replacement bulbs" diff --git a/code/game/objects/items/weapons/storage/fancy.dm b/code/game/objects/items/weapons/storage/fancy.dm index b959c652871..303850c14dd 100644 --- a/code/game/objects/items/weapons/storage/fancy.dm +++ b/code/game/objects/items/weapons/storage/fancy.dm @@ -192,3 +192,28 @@ desc = "A packet of six imported DromedaryCo cancer sticks. A label on the packaging reads, \"Wouldn't a slow death make a change?\"" icon_state = "Dpacket" item_state = "Dpacket" + + +/obj/item/weapon/storage/fancy/rollingpapers + name = "rolling paper pack" + desc = "A pack of NanoTrasen brand rolling papers." + w_class = 1 + icon = 'icons/obj/cigarettes.dmi' + icon_state = "cig_paper_pack" + storage_slots = 10 + icon_type = "rolling papers" + can_hold = list(/obj/item/weapon/rollingpaper) + +/obj/item/weapon/storage/fancy/rollingpapers/update_icon() + if(!contents.len) + icon_state = "[initial(icon_state)]0" + else + icon_state = initial(icon_state) + + desc = "There are [contents.len] papers\s left!" + return + +/obj/item/weapon/storage/fancy/rollingpapers/New() + ..() + for(var/i = 1 to storage_slots) + new /obj/item/weapon/rollingpaper(src) diff --git a/icons/obj/cigarettes.dmi b/icons/obj/cigarettes.dmi index d254c6c843d70d4f402eb298c4a5c901a6187925..2ce3ce877fa0e56aba0a8193db9e4e5c27f99c3c 100644 GIT binary patch literal 4673 zcmaJ_XH-+$y4@ipK@y4t#Lz($P*e!Lha!Sf1XPMN0g)!eBcYejks``DN)w}?B5(ku zNUsqoQbPxUAOfL-^bo>}Z;boiyYJome(d$_HOF4xH@>~+nq%(u_=d?yqed?-nhDcl=9S^ak?39gyW(~hJn!ijo9JX-x;r2}G)=OC5t2Uq0w=eC^imwWs z(VQh{OzjzZw-YTp&Jsk&VkLolAA|J^@0SPaC*Cjj*Y~_%j?=$>e3W&*no1RSP!BVX zLn4K*AAx!6-K%9fpn(8z5^AWYeKX+YYId+MawNO0QLfa5*7O3Z6K(D+QP=X#+j=S1j-}@nXB|HY$>qn- zG@+R8l5Ol||7jD9`1(n^^x4JbyWNvoE-H%c+9esw{WQ%5ib3YH?fM3K=z`{ak5BZO zt55JE+X?Np0CO`E4ZQJe2cnBb!JIX*2n>bqAAsSE9o{Wqz^u3BLHNz{Tn2<~XKgv? zZ$L9}=f-HL;Dw&Di!o;t=tu)Cm7QF4Q%~Z098LuAs=N0thi9XsFmA*DThlN^;Eq99e_2Ufn=#qqg=$K4{Pyi*R2zGH<;w`*fw4R0C!9gs{L+33ITqb->t9ggI z$1_y@EX>l9*A{l6YH7ktacFtQCbVK%^kqZ0D=`r^TL=>+wPIspVpfDRJxV6%WoMWB zr^Z>YIuLT~UhnSu?XC-6EuNrT*~@y}zFs zT@@dU%h!$WpL?l$$%^#e=@C5_z~4_<*BRSBH2l5D2`oP)n!=8sFj1KO9J8gr$K!91 zPzk{DvhTf5k^=A%0~+nNGS0r!zk2he!kER5eh#MW>se*ol`@}pYpx3trvLB|V%%yk z@n4jblTN;( zz<~F|n>X5<6(SiZRF@ZfxY$ZdYvNl|s_e;6AQmyyo4LM!!IS?(oc{;FL#0$LRcBfa zJuC(_0z0|jE&!W3q4o~>LF5hc$Q}Q}RFsWWJD_(nnrZrIW=F-m!r*3_-me}Gtqe(3 z%g&`o2LeYr?8h(uoISZVK+p#kfau;++$aXyYf0wn zdsB_f)ACN+2cPPkylnQd0$2J(>cD+9cO=hC-}7d^??g(ozDamubh#X#rwNoxSHq9T zrlZ&%()7PXIZhqSNbp}-(6<3?!0~by^G*ZbHT^{iV;|PccYTVlc~dWHn9T20eZ&q+ z&#iME)Xaq6{bhP${+LY3xApf3s{Wcd93oXUj)Von<~-I1DX@sM_pYtgTvv{RG6N zLOQV;l*Cw*t_->LufjCeoKAMT+qX~o9WF-+zmYZ$*Cz`Cnk6sUmU*FPa$`$ye&3{?P>M=bR4eiD#3MQIi)fo|06vN9y_ zQRUc-HajwF4bkD`LpQ}F^2Xp$d$0fg8}Utx5X(@OmVBfHSxBHok9UdlOLE_LJF$9Q zU8BV;G?J<rp7R%0ALjk+`_6Nh+04R%xVu&a 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 literal 2454 zcmV;H32F9;P)xwWmqy|l%_xHAAVbx$g?va*F#b(NKslarH!Q**Vo zwR=-6l$3s*orG#bAF-~dy}7W}(a7D|&`L^5d{Zi#nwpoFmxxq(l9G~!RCk9|cZyVb zuCA_mQ!JR6fpt(VhR4)yjnUa~7kFKkvc~B{rBqW?BCY~lHpC%@tB_*FF zC7mTDoFyf7P%w2+FLqEca7`|EQ80>!fRm7kpPZFhSy^;VD48WCkRv0KBO{k1BbFp2 zm?R{bBqVQ3E^tjPb51U8OD%_leRFejY(^n+MI3WR8+AwsadAsHIHp-yIV&swzyK&79`(2Y>#+dhssPoX z0N$qn&6)tklmNiMzyJVdGc(L90IJNWc-;U100DGTPE!Ct=GbNc008oOR9JLGWpiV4 zX>fFDZ*Bkpc$}4#O^d=X5QfjquL$)jQd`}dmt|z}pnsvHb!vm@2kF#Z|NUkaJSfF? z$z?J;ZvvBt%=G8>Yj@DJ->D1x!FH|Q=+z=o(YHNH9X462qMGfgmiuN9BOJ=Ow5Q&b zXO>t+N9%{sTdJt?rr~@2N-l9U#nB8$S2()H(GMI=-lC0>vd*2I7;6@~?94Tk={&6G z;Mh(^UoI&|--2w>{lH*uT+(>nL^aUH8U1(29Gn*1h)%h}D!n(f`78 zP7?8{oc9g)=H}k$`*|MvLqF-s_nUK)+`K$b${0Zq1VI!=g~YucqoPt$m@%WFL4Abk8iT>cMqRmp)1Dt832=lYz!p2}(O030kVN?iIPK8_O<{?00jGWb z2r2zW%@Wsof*=TjAP9mW2!b$;)%m;A;PZEvBj@kc9`*d)?a2AN*JtMrMDd%%%&(rE zzXxnRLQ%w9h+n|`y$D1>8)Ge27Dwmr1rWtFa)Uw+nG$sVUIK0{XiE$DN{M+kYqr{< z^Z6#$R99C4zEh(CT3bQQVu;^lQ`kc^hnpgLXfya~uXS^HkuA2g=I3k$dx++6V3zsFjfEyu>B6!{Ej=p9)cIZcK{2p^DfqW+pe&O5JyPYkpftN z-7Nau_kcY}tzH|ht%5%9m=!-zY3byHNR7k zu<`^r@SuYaIrOl@k2vzEqmMbZyL&+?y>Z;}U0tFwysr}8j+zNV;Z;JokxNX_M z?TeQ7qxrKx|K^T6@4EY*d+)pdfd?OYcyMs=k?!v0CH2gB^s!}+4`2sq((IBahMs(C z#nZ#X!_Pds;<@Kvc=4s>rS-hQ%dfnOJ^@}+n%CcW^R2hv85&x-YUQeT-+TXqb=SAs z^8z0ha1r{E(tP~Mr=NZP#g|`w{mr-EegDIcKb6{x255Z7elFlPuEy?PAP@vW5ClQ| zM@dPX^HxcXNJgFVIHOrqdZhXn!HC*>Fkg*%58zR Date: Mon, 9 Jun 2014 20:00:38 -0500 Subject: [PATCH 05/55] Update boxes.dm Removes necessary check from matchbox attackby. --- code/game/objects/items/weapons/storage/boxes.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index 6aeff9dee4a..fe97efbfbad 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -461,7 +461,7 @@ new /obj/item/weapon/match(src) /obj/item/weapon/storage/box/matches/attackby(obj/item/weapon/match/W as obj, mob/user as mob) - if(istype(W, /obj/item/weapon/match) && W.lit == 0) + if(istype(W, /obj/item/weapon/match)) W.matchignite() return @@ -500,4 +500,4 @@ for(var/i = 0; i < 14; i++) new /obj/item/weapon/light/tube(src) for(var/i = 0; i < 7; i++) - new /obj/item/weapon/light/bulb(src) \ No newline at end of file + new /obj/item/weapon/light/bulb(src) From 4facf4aa4759ba468141d5e201c18ef3474f2207 Mon Sep 17 00:00:00 2001 From: Cheridan Date: Mon, 9 Jun 2014 21:30:57 -0500 Subject: [PATCH 06/55] Update cigs_lighters.dm burnt matches get weak again --- code/game/objects/items/weapons/cigs_lighters.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/game/objects/items/weapons/cigs_lighters.dm b/code/game/objects/items/weapons/cigs_lighters.dm index 8fb56e71196..3b2c2381328 100644 --- a/code/game/objects/items/weapons/cigs_lighters.dm +++ b/code/game/objects/items/weapons/cigs_lighters.dm @@ -58,6 +58,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM if(lit == 1) lit = -1 damtype = "brute" + force = initial(force) icon_state = "match_burnt" item_state = "cigoff" name = "burnt match" @@ -551,4 +552,4 @@ CIGARETTE PACKETS ARE IN FANCY.DM else user << "You need to dry this first." else - ..() \ No newline at end of file + ..() From 7181120cfaab63245b19cdec63ef9ba426268cce Mon Sep 17 00:00:00 2001 From: ikarrus Date: Mon, 9 Jun 2014 20:59:27 -0600 Subject: [PATCH 07/55] Removes "Enter Exosuit" verb Mechs can be entered with click-drags now. --- code/game/mecha/mecha.dm | 44 ++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index df02cb26e81..2ba407e28a2 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -933,50 +933,40 @@ return -/obj/mecha/verb/move_inside() - set category = "Object" - set name = "Enter Exosuit" - set src in oview(1) - - if (usr.stat || !ishuman(usr) || usr.restrained() || !usr.Adjacent(src)) +/obj/mecha/MouseDrop_T(mob/M as mob, mob/user as mob) + if (!usr.canUseTopic(src) || (user != M)) return - src.log_message("[usr] tries to move in.") + src.log_message("[user] tries to move in.") if (src.occupant) - usr << "\blue The [src.name] is already occupied!" + usr << "The [src.name] is already occupied!" src.log_append_to_last("Permission denied.") return -/* - if (usr.abiotic()) - usr << "\blue Subject cannot have abiotic items on." - return -*/ var/passed if(src.dna) - if(check_dna_integrity(usr)) - var/mob/living/carbon/C = usr + if(check_dna_integrity(user)) + var/mob/living/carbon/C = user if(C.dna.unique_enzymes==src.dna) passed = 1 - else if(src.operation_allowed(usr)) + else if(src.operation_allowed(user)) passed = 1 if(!passed) - usr << "\red Access denied" + user << "Access denied." src.log_append_to_last("Permission denied.") return - for(var/mob/living/carbon/slime/M in range(1,usr)) - if(M.Victim == usr) - usr << "You're too busy getting your life sucked out of you." + for(var/mob/living/carbon/slime/S in range(1,user)) + if(S.Victim == user) + user << "You're too busy getting your life sucked out of you." return -// usr << "You start climbing into [src.name]" - visible_message("\blue [usr] starts to climb into [src.name]") + visible_message("[user] starts to climb into [src.name]") - if(enter_after(40,usr)) + if(enter_after(40,user)) if(!src.occupant) - moved_inside(usr) - else if(src.occupant!=usr) - usr << "[src.occupant] was faster. Try better next time, loser." + moved_inside(user) + else if(src.occupant!=user) + user << "[src.occupant] was faster. Try better next time, loser." else - usr << "You stop entering the exosuit." + user << "You stop entering the exosuit." return /obj/mecha/proc/moved_inside(var/mob/living/carbon/human/H as mob) From fff8858e0479a56373910375f09a671efa34c603 Mon Sep 17 00:00:00 2001 From: ikarrus Date: Mon, 9 Jun 2014 22:02:56 -0600 Subject: [PATCH 08/55] Mechas deal brute organ damage to mobs Instead of calling ex_act(2) on everything, it checks for mobs before dealing brute damage to the chest. This means people will actually look like they've been drilled through now! --- code/game/mecha/equipment/tools/tools.dm | 30 +++++++++++++++++------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm index 5e4fc703326..4a9261d2d8e 100644 --- a/code/game/mecha/equipment/tools/tools.dm +++ b/code/game/mecha/equipment/tools/tools.dm @@ -112,10 +112,10 @@ ore.Move(ore_box) else if(target.loc == C) log_message("Drilled through [target]") - if(ismob(target)) - var/mob/M = target - add_logs(chassis.occupant, M, "attacked", object="[name]", addition="(INTENT: [uppertext(chassis.occupant.a_intent)]) (DAMTYE: [uppertext(damtype)])") - target.ex_act(2) + if(isliving(target)) + drill_mob(target, chassis.occupant) + else + target.ex_act(2) return 1 can_attach(obj/mecha/M as obj) @@ -124,6 +124,20 @@ return 1 return 0 +/obj/item/mecha_parts/mecha_equipment/tool/drill/proc/drill_mob(mob/living/target, mob/user, var/drill_damage=80) + target.visible_message("[chassis] drills [target] with the [src].\ + [chassis] drills [target] with the [src].") + add_logs(user, target, "attacked", object="[name]", addition="(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])") + if(ishuman(target)) + var/mob/living/carbon/human/H = target + var/obj/item/organ/limb/affecting = H.get_organ("chest") + affecting.take_damage(drill_damage) + H.update_damage_overlays(0) + else + target.take_organ_damage(drill_damage) + target.Paralyse(10) + target.updatehealth() + /obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill name = "diamond-tipped exosuit drill" desc = "Equipment for engineering and combat exosuits. This is an upgraded version of the drill that'll pierce the heavens!" @@ -172,10 +186,10 @@ ore.Move(ore_box) else if(target.loc == C) log_message("Drilled through [target]") - if(ismob(target)) - var/mob/M = target - add_logs(chassis.occupant, M, "attacked", object="[name]", addition="(INTENT: [uppertext(chassis.occupant.a_intent)]) (DAMTYE: [uppertext(damtype)])") - target.ex_act(2) + if(isliving(target)) + drill_mob(target, chassis.occupant, 120) + else + target.ex_act(2) return 1 can_attach(obj/mecha/M as obj) From 3908160998e27decf43de275040ca9e2655a4bd5 Mon Sep 17 00:00:00 2001 From: Kelenius Date: Tue, 10 Jun 2014 20:36:08 +0400 Subject: [PATCH 09/55] One big update for stacks. --- code/game/machinery/alarm.dm | 29 ++--- code/game/machinery/bots/ed209bot.dm | 16 +-- code/game/machinery/bots/floorbot.dm | 30 +++-- code/game/machinery/camera/camera_assembly.dm | 5 +- code/game/machinery/computer/ai_core.dm | 27 ++-- .../game/machinery/computer/buildandrepair.dm | 39 +++--- code/game/machinery/constructable_frame.dm | 13 +- code/game/machinery/portable_turret.dm | 16 +-- code/game/machinery/rechargestation.dm | 13 +- code/game/machinery/shieldgen.dm | 11 +- .../telecomms/machine_interactions.dm | 2 +- code/game/mecha/mecha.dm | 7 +- code/game/mecha/mecha_construction_paths.dm | 14 +-- .../objects/items/devices/lightreplacer.dm | 19 ++- code/game/objects/items/robot/robot_parts.dm | 31 +++-- code/game/objects/items/stacks/rods.dm | 6 +- .../game/objects/items/stacks/sheets/glass.dm | 75 +++++++---- .../game/objects/items/stacks/sheets/light.dm | 20 ++- .../items/stacks/sheets/sheet_types.dm | 2 + code/game/objects/items/stacks/stack.dm | 119 +++++++++++------- .../objects/items/stacks/tiles/plasteel.dm | 5 +- .../items/weapons/grenades/chem_grenade.dm | 11 +- .../items/weapons/grenades/ghettobomb.dm | 19 +-- code/game/objects/items/weapons/handcuffs.dm | 18 +-- .../objects/items/weapons/table_rack_parts.dm | 14 +-- code/game/objects/items/weapons/tools.dm | 18 +-- .../structures/crates_lockers/crates.dm | 10 +- code/game/objects/structures/door_assembly.dm | 11 +- code/game/objects/structures/girders.dm | 26 ++-- code/game/objects/structures/grille.dm | 9 +- code/game/turfs/simulated/floor.dm | 34 ++--- code/game/turfs/simulated/walls_reinforced.dm | 30 +++-- code/game/turfs/space/space.dm | 28 +++-- code/modules/hydroponics/grown.dm | 8 +- code/modules/mining/mint.dm | 16 +-- code/modules/mining/ores_coins.dm | 17 ++- .../modules/mob/living/silicon/robot/robot.dm | 14 ++- .../mob/living/silicon/robot/robot_modules.dm | 79 ++++++++---- code/modules/power/apc.dm | 35 +++--- code/modules/power/cable.dm | 43 +++++-- code/modules/power/lighting.dm | 20 +-- .../particle_accelerator.dm | 6 +- code/modules/power/solar.dm | 6 +- code/modules/research/circuitprinter.dm | 20 +-- 44 files changed, 584 insertions(+), 407 deletions(-) diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index 4f0df133f3b..4bc346319f4 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -807,20 +807,17 @@ table tr:first-child th:first-child { border: none;} if(istype(W, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/cable = W - if(cable.amount < 5) - user << "You need more cable!" + if(cable.get_amount() < 5) + user << "You need five lengths of cable to wire fire alarm." return - - user << "You start wiring the air alarm!" - spawn(20) - cable.amount -= 5 - if(!cable.amount) - qdel(cable) - - user << "You wire the air alarm!" - wires.wires_status = 0 - buildstage = 2 - update_icon() + user << "You start wiring the air alarm." + if (do_after(user, 20)) + if (cable.get_amount() >= 5 && buildstage == 1) + cable.use(5) + user << "You wire the air alarm." + wires.wires_status = 0 + buildstage = 2 + update_icon() return if(0) if(istype(W, /obj/item/weapon/airalarm_electronics)) @@ -999,13 +996,11 @@ FIRE ALARM if(1) if(istype(W, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/coil = W - if(coil.amount < 5) + if(coil.get_amount() < 5) user << "You need more cable for this!" return - coil.amount -= 5 - if(!coil.amount) - qdel(coil) + coil.use(5) buildstage = 2 user << "You wire \the [src]!" diff --git a/code/game/machinery/bots/ed209bot.dm b/code/game/machinery/bots/ed209bot.dm index 5cb9d67a849..09106fcee3b 100644 --- a/code/game/machinery/bots/ed209bot.dm +++ b/code/game/machinery/bots/ed209bot.dm @@ -967,14 +967,16 @@ Auto Patrol: []"}, if(6) if(istype(W, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/coil = W - var/turf/T = get_turf(user) + if (coil.get_amount() < 1) + user << "You need one length of cable to wire ED-209." + return user << "You start to wire [src]..." - sleep(40) - if(get_turf(user) == T) - coil.use(1) - build_step++ - user << "You wire the ED-209 assembly." - name = "wired ED-209 assembly" + if (do_after(user, 40)) + if (coil.get_amount() >= 1 && build_step == 6) + coil.use(1) + build_step = 7 + user << "You wire the ED-209 assembly." + name = "wired ED-209 assembly" if(7) switch(lasercolor) diff --git a/code/game/machinery/bots/floorbot.dm b/code/game/machinery/bots/floorbot.dm index 642dcfe2ff9..c5d6d7de5a5 100644 --- a/code/game/machinery/bots/floorbot.dm +++ b/code/game/machinery/bots/floorbot.dm @@ -102,11 +102,14 @@ var/obj/item/stack/tile/plasteel/T = W if(src.amount >= 50) return - var/loaded = min(50-src.amount, T.amount) + var/loaded = min(50 - src.amount, T.get_amount()) T.use(loaded) src.amount += loaded - user << "You load [loaded] tiles into the floorbot. He now contains [src.amount] tiles." - src.updateicon() + if (loaded > 0) + user << "You load [loaded] tiles into the floorbot. He now contains [src.amount] tiles." + src.updateicon() + else + user << "You need at least one floor tile to put it into floorbot." else if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) if(src.allowed(usr) && !open && !emagged) src.locked = !src.locked @@ -409,16 +412,19 @@ ..() return if(src.contents.len >= 1) - user << "They wont fit in as there is already stuff inside." + user << "They won't fit in, as there is already stuff inside." + return + if(T.use(10)) + if(user.s_active) + user.s_active.close(user) + var/obj/item/weapon/toolbox_tiles/B = new /obj/item/weapon/toolbox_tiles + user.put_in_hands(B) + user << "You add the tiles into the empty toolbox. They protrude from the top." + user.unEquip(src, 1) + qdel(src) + else + user << "You need 10 floor tiles to start building a floorbot." return - if(user.s_active) - user.s_active.close(user) - qdel(T) - var/obj/item/weapon/toolbox_tiles/B = new /obj/item/weapon/toolbox_tiles - user.put_in_hands(B) - user << "You add the tiles into the empty toolbox. They protrude from the top." - user.unEquip(src, 1) - qdel(src) /obj/item/weapon/toolbox_tiles/attackby(var/obj/item/W, mob/user as mob) ..() diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm index 32efc75734d..cc44b26c0c3 100644 --- a/code/game/machinery/camera/camera_assembly.dm +++ b/code/game/machinery/camera/camera_assembly.dm @@ -59,8 +59,11 @@ if(istype(W, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/C = W if(C.use(2)) - user << "You add wires to the assembly." + user << "You add wires to the assembly." state = 3 + else + user << "You need two lengths of cable to wire a camera." + return return else if(istype(W, /obj/item/weapon/weldingtool)) diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm index 5f0e35b08ec..5665d6997b8 100644 --- a/code/game/machinery/computer/ai_core.dm +++ b/code/game/machinery/computer/ai_core.dm @@ -63,14 +63,18 @@ state = 1 icon_state = "1" if(istype(P, /obj/item/stack/cable_coil)) - if(P:amount >= 5) + var/obj/item/stack/cable_coil/C = P + if(C.get_amount() >= 5) playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1) if(do_after(user, 20)) - P:amount -= 5 - if(!P:amount) qdel(P) - user << "You add cables to the frame." - state = 3 - icon_state = "3" + if (C.get_amount() >= 5 && state == 3) + C.use(5) + user << "You add cables to the frame." + state = 3 + icon_state = "3" + else + user << "You need five lengths of cable to wire the AI core." + return if(3) if(istype(P, /obj/item/weapon/wirecutters)) if (brain) @@ -84,15 +88,18 @@ A.amount = 5 if(istype(P, /obj/item/stack/sheet/rglass)) - if(P:amount >= 2) + var/obj/item/stack/sheet/rglass/G = P + if(G.get_amount() >= 2) playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1) if(do_after(user, 20)) - if (P) - P:amount -= 2 - if(!P:amount) qdel(P) + if (G.get_amount() >= 2 && state == 3) + G.use(2) user << "You put in the glass panel." state = 4 icon_state = "4" + else + user << "You need two sheets of reinforced glass to insert them into AI core." + return if(istype(P, /obj/item/weapon/aiModule/core/full)) //Allows any full core boards to be applied to AI cores. var/obj/item/weapon/aiModule/core/M = P diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index 012ed538d50..0b6c713d2fd 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -326,50 +326,51 @@ if(istype(P, /obj/item/weapon/screwdriver) && circuit) playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) user << "You unfasten the circuit board." - src.state = 1 - src.icon_state = "1" + state = 1 + icon_state = "1" if(istype(P, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/C = P - if(C.amount >= 5) + if(C.get_amount() >= 5) playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) user << "You start adding cables to the frame." if(do_after(user, 20)) - if(C && C.amount >= 5) - C.amount -= 5 - if(C.amount <= 0) qdel(C) + if(C.get_amount() >= 5 && state == 2) + C.use(5) user << "You've added cables to the frame." - src.state = 3 - src.icon_state = "3" + state = 3 + icon_state = "3" else - user << "You need more cable to do that." + user << "You need five lengths of cable to wire the frame." if(3) if(istype(P, /obj/item/weapon/wirecutters)) playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1) user << "You remove the cables." - src.state = 2 - src.icon_state = "2" + state = 2 + icon_state = "2" var/obj/item/stack/cable_coil/A = new (loc) A.amount = 5 A.add_fingerprint(user) if(istype(P, /obj/item/stack/sheet/glass)) - if(P:amount >= 2) + var/obj/item/stack/sheet/glass/G = P + if(G.get_amount() < 2) + user << "You need two glass sheets to continue construction." + return + else playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) user << "You start to put in the glass panel." if(do_after(user, 20)) - if(P) - P:use(2) + if(G.get_amount() >= 2 && state == 3) + G.use(2) user << "You've put in the glass panel." - src.state = 4 + state = 4 src.icon_state = "4" - else - user << "You need more glass to do that." if(4) if(istype(P, /obj/item/weapon/crowbar)) playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) user << "You remove the glass panel." - src.state = 3 - src.icon_state = "3" + state = 3 + icon_state = "3" var/obj/item/stack/sheet/glass/G = new (loc, 2) G.add_fingerprint(user) if(istype(P, /obj/item/weapon/screwdriver)) diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index f33beedab30..f5a285e8290 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -55,16 +55,18 @@ if(1) if(istype(P, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/C = P - if(C.amount >= 5) + if(C.get_amount() >= 5) playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) user << "You start to add cables to the frame." if(do_after(user, 20)) - if(C) - C.amount -= 5 - if(!C.amount) qdel(C) + if(C.get_amount() >= 5 && state == 1) + C.use(5) user << "You add cables to the frame." state = 2 icon_state = "box_1" + else + user << "You need five length of cable to wire the frame." + return if(istype(P, /obj/item/weapon/wrench)) playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) user << "You dismantle the frame." @@ -138,6 +140,9 @@ success=1 if(istype(P, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/CP = P + if (CP.get_amount() < 1) + user << "You need more cable!" + return var/obj/item/stack/cable_coil/CC = new /obj/item/stack/cable_coil(src, 1, CP.item_color) if(CP.use(1)) components += CC diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 7747da62bc7..e52421b06be 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -653,16 +653,12 @@ if(1) if(istype(I, /obj/item/stack/sheet/metal)) var/obj/item/stack/sheet/metal/M = I - if(M.amount>=2) //requires 2 metal sheets + if(M.use(2)) user << "You add some metal armor to the interior frame." build_step = 2 - M.amount -= 2 icon_state = "turret_frame2" - if(M.amount <= 0) - user.unEquip(M, 1) //We're deleting it anyway, so no point in having NODROP fuck shit up. - qdel(M) else - user << "You need two sheets of metal for that." + user << "You need two sheets of metal to continue construction." return else if(istype(I, /obj/item/weapon/wrench)) @@ -743,15 +739,11 @@ if(6) if(istype(I, /obj/item/stack/sheet/metal)) var/obj/item/stack/sheet/metal/M = I - if(M.amount>=2) + if(M.use(2)) user << "You add some metal armor to the exterior frame." build_step = 7 - M.amount -= 2 - if(M.amount <= 0) - user.unEquip(M, 1) //If we don't force-unequip, bugs happen because the item was deleted without updating the neccesary stuffs. - qdel(M) else - user << "You need two sheets of metal for that." + user << "You need two sheets of metal to continue construction." return else if(istype(I, /obj/item/weapon/screwdriver)) diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index f3c06c9424d..522483a63be 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -155,20 +155,19 @@ /obj/machinery/recharge_station/proc/restock_modules() if(occupier) if(occupier.module && occupier.module.modules) - var/list/um = occupier.contents|occupier.module.modules - // ^ makes sinle list of active (occupier.contents) and inactive modules (occupier.module.modules) + var/list/um = occupier.contents|occupier.module.modules // Makes single list of active (occupier.contents) and inactive (occupier.module.modules) modules var/coeff = recharge_speed / 200 + for (var/datum/robot_energy_storage/st in occupier.module.storages) + st.energy = min(st.max_energy, st.energy + coeff * st.recharge_rate) for(var/obj/O in um) - // Engineering - if(istype(O,/obj/item/stack/sheet/metal) || istype(O,/obj/item/stack/sheet/rglass) || istype(O,/obj/item/stack/rods) || istype(O,/obj/item/stack/cable_coil)|| istype(O,/obj/item/stack/tile/plasteel)) - if(O:amount < 50) - O:amount += coeff - // Security + //General if(istype(O,/obj/item/device/flash)) if(O:broken) O:broken = 0 O:times_used = 0 O:icon_state = "flash" + // Engineering + // Security if(istype(O,/obj/item/weapon/gun/energy/taser/cyborg)) if(O:power_supply.charge < O:power_supply.maxcharge) var/obj/item/weapon/gun/energy/G = O diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index d3e32c02081..796f8dcc729 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -247,14 +247,17 @@ else if(istype(W, /obj/item/stack/cable_coil) && malfunction && is_open) var/obj/item/stack/cable_coil/coil = W - user << "\blue You begin to replace the wires." - //if(do_after(user, min(60, round( ((maxhealth/health)*10)+(malfunction*10) ))) //Take longer to repair heavier damage + if (coil.get_amount() < 1) + user << "You need one length of cable to repair [src]." + return + user << "You begin to replace the wires." if(do_after(user, 30)) - if(!src || !coil) return + if(coil.get_amount() < 1) + return coil.use(1) health = max_health malfunction = 0 - user << "\blue You repair the [src]!" + user << "You repair the [src]!" update_icon() else if(istype(W, /obj/item/weapon/wrench)) diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm index 4098ed938c8..f3d1796d3a2 100644 --- a/code/game/machinery/telecomms/machine_interactions.dm +++ b/code/game/machinery/telecomms/machine_interactions.dm @@ -56,7 +56,7 @@ construct_op -- stat &= ~BROKEN // the machine's not borked anymore! else - user << "You need more cable to do that." + user << "You need five lengths of cable for this machine." if(istype(P, /obj/item/weapon/crowbar)) user << "You begin prying out the circuit board and components..." playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index df02cb26e81..b6524eee6bc 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -703,12 +703,11 @@ else if(istype(W, /obj/item/stack/cable_coil)) if(state == 3 && hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) var/obj/item/stack/cable_coil/CC = W - if(CC.amount > 1) - CC.use(2) + if(CC.use(2)) clearInternalDamage(MECHA_INT_SHORT_CIRCUIT) - user << "You replace the fused wires." + user << "You replace the fused wires." else - user << "There's not enough wire to finish the task." + user << "You need two lengths of cable to fix this mecha." return else if(istype(W, /obj/item/weapon/screwdriver)) if(hasInternalDamage(MECHA_INT_TEMP_CONTROL)) diff --git a/code/game/mecha/mecha_construction_paths.dm b/code/game/mecha/mecha_construction_paths.dm index 24a42e5f774..96f233152ef 100644 --- a/code/game/mecha/mecha_construction_paths.dm +++ b/code/game/mecha/mecha_construction_paths.dm @@ -20,12 +20,11 @@ else if(istype(used_atom, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/C = used_atom - if(C.amount<4) + if(C.use(4)) + playsound(holder, 'sound/items/Deconstruct.ogg', 50, 1) + else user << ("There's not enough cable to finish the task.") return 0 - else - C.use(4) - playsound(holder, 'sound/items/Deconstruct.ogg', 50, 1) else if(istype(used_atom, /obj/item/stack)) var/obj/item/stack/S = used_atom if(S.amount < 5) @@ -53,12 +52,11 @@ else if(istype(used_atom, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/C = used_atom - if(C.amount<4) + if (C.use(4)) + playsound(holder, 'sound/items/Deconstruct.ogg', 50, 1) + else user << ("There's not enough cable to finish the task.") return 0 - else - C.use(4) - playsound(holder, 'sound/items/Deconstruct.ogg', 50, 1) else if(istype(used_atom, /obj/item/stack)) var/obj/item/stack/S = used_atom if(S.amount < 5) diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm index 9c6dbbdb37c..2b844aaa029 100644 --- a/code/game/objects/items/devices/lightreplacer.dm +++ b/code/game/objects/items/devices/lightreplacer.dm @@ -78,18 +78,15 @@ if(istype(W, /obj/item/stack/sheet/glass)) var/obj/item/stack/sheet/glass/G = W - if(G.amount - decrement >= 0 && uses < max_uses) - var/remaining = max(G.amount - decrement, 0) - if(!remaining && !(G.amount - decrement) == 0) - user << "There isn't enough glass." - return - G.amount = remaining - if(!G.amount) - user.drop_item() - qdel(G) - AddUses(increment) - user << "You insert a piece of glass into the [src.name]. You have [uses] lights remaining." + if(uses >= max_uses) + user << "span class='warning'>[src.name] is full." return + else if(G.use(decrement)) + AddUses(increment) + user << "You insert a piece of glass into the [src.name]. You have [uses] lights remaining." + return + else + user << "You need one sheet of glass to replace lights." if(istype(W, /obj/item/weapon/light)) var/obj/item/weapon/light/L = W diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index 5173e9842e3..f88936e66d9 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -104,14 +104,18 @@ /obj/item/robot_parts/robot_suit/attackby(obj/item/W as obj, mob/user as mob) ..() if(istype(W, /obj/item/stack/sheet/metal) && !l_arm && !r_arm && !l_leg && !r_leg && !chest && !head) - var/obj/item/weapon/ed209_assembly/B = new /obj/item/weapon/ed209_assembly - B.loc = get_turf(src) - user << "You armed the robot frame" - W:use(1) - if (user.get_inactive_hand()==src) - user.unEquip(src) - user.put_in_inactive_hand(B) - qdel(src) + var/obj/item/stack/sheet/metal/M = W + if (M.use(1)) + var/obj/item/weapon/ed209_assembly/B = new /obj/item/weapon/ed209_assembly + B.loc = get_turf(src) + user << "You armed the robot frame." + if (user.get_inactive_hand()==src) + user.unEquip(src) + user.put_in_inactive_hand(B) + qdel(src) + else + user << "You need one sheet of metal to start building ED-209." + return if(istype(W, /obj/item/robot_parts/l_leg)) if(src.l_leg) return user.drop_item() @@ -313,13 +317,14 @@ user << "\blue You insert the cell!" if(istype(W, /obj/item/stack/cable_coil)) if(src.wires) - user << "\blue You have already inserted wire!" + user << "You have already inserted wire." return - else - var/obj/item/stack/cable_coil/coil = W - coil.use(1) + var/obj/item/stack/cable_coil/coil = W + if (coil.use(1)) src.wires = 1.0 - user << "\blue You insert the wire!" + user << "You insert the wire." + else + user << "You need one length of coil to wire it." return /obj/item/robot_parts/head/attackby(obj/item/W as obj, mob/user as mob) diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm index 47d017a5c22..ac5c1cbca99 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/rods.dm @@ -19,7 +19,7 @@ if (istype(W, /obj/item/weapon/weldingtool)) var/obj/item/weapon/weldingtool/WT = W - if(amount < 2) + if(get_amount() < 2) user << "\red You need at least two rods to do this." return @@ -54,7 +54,7 @@ else return 1 else - if(amount < 2) + if(get_amount() < 2) user << "\blue You need at least two rods to do this." return usr << "\blue Assembling grille..." @@ -68,3 +68,5 @@ /obj/item/stack/rods/cyborg/ m_amt = 0 + is_cyborg = 1 + cost = 250 \ No newline at end of file diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index 299677c2a17..c19167e2fee 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -16,6 +16,10 @@ g_amt = MINERAL_MATERIAL_AMOUNT origin_tech = "materials=1" +/obj/item/stack/sheet/glass/cyborg + g_amt = 0 + is_cyborg = 1 + cost = 500 /obj/item/stack/sheet/glass/attack_self(mob/user as mob) construct_window(user) @@ -23,28 +27,32 @@ /obj/item/stack/sheet/glass/attackby(obj/item/W, mob/user) ..() add_fingerprint(user) - if(istype(W,/obj/item/stack/cable_coil)) + if(istype(W, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/CC = W - if(CC.amount < 5) - user << "\b There is not enough wire in this coil. You need 5 lengths." + if (get_amount() < 1 || CC.get_amount() < 5) + user << "You attach wire to the [name]." var/obj/item/stack/light_w/new_tile = new(user.loc) new_tile.add_fingerprint(user) - src.use(1) - else if( istype(W, /obj/item/stack/rods) ) - var/obj/item/stack/rods/V = W - var/obj/item/stack/sheet/rglass/RG = new (user.loc) - RG.add_fingerprint(user) - RG.add_to_stacks(user) - V.use(1) - var/obj/item/stack/sheet/glass/G = src - src = null - var/replace = (user.get_inactive_hand()==G) - G.use(1) - if (!G && !RG && replace) - user.put_in_hands(RG) + else if(istype(W, /obj/item/stack/rods)) + var/obj/item/stack/rods/V = W + if (V.get_amount() > 1 && src.get_amount() > 1) + var/obj/item/stack/sheet/rglass/RG = new (user.loc) + RG.add_fingerprint(user) + RG.add_to_stacks(user) + var/obj/item/stack/sheet/glass/G = src + src = null + var/replace = (user.get_inactive_hand()==G) + V.use(1) + G.use(1) + if (!G && replace) + user.put_in_hands(RG) + else + user << "You need one rod and one sheet of glass to make reinforced glass." + return else return ..() @@ -55,7 +63,7 @@ user << "\red You don't have the dexterity to do this!" return 0 var/title = "Sheet-Glass" - title += " ([src.amount] sheet\s left)" + title += " ([src.get_amount()] sheet\s left)" switch(alert(title, "Would you like full tile glass or one direction?", "One Direction", "Full Window", "Cancel", null)) if("One Direction") if(!src) return 1 @@ -95,7 +103,7 @@ if("Full Window") if(!src) return 1 if(src.loc != user) return 1 - if(src.amount < 2) + if(src.get_amount() < 2) user << "\red You need more glass to do that." return 1 if(locate(/obj/structure/window) in user.loc) @@ -121,16 +129,29 @@ singular_name = "reinforced glass sheet" icon_state = "sheet-rglass" g_amt = MINERAL_MATERIAL_AMOUNT - m_amt = 1000 + m_amt = MINERAL_MATERIAL_AMOUNT / 2 origin_tech = "materials=2" /obj/item/stack/sheet/rglass/cyborg - name = "reinforced glass" - desc = "Glass which seems to have rods or something stuck in them." - singular_name = "reinforced glass sheet" - icon_state = "sheet-rglass" g_amt = 0 m_amt = 0 + var/datum/robot_energy_storage/metsource + var/datum/robot_energy_storage/glasource + var/metcost = 250 + var/glacost = 500 + +/obj/item/stack/sheet/rglass/cyborg/get_amount() + return min(round(metsource.energy / metcost), round(glasource.energy / glacost)) + +/obj/item/stack/sheet/rglass/cyborg/use(var/amount) // Requires special checks, because it uses two storages + metsource.use_charge(amount * metcost) + glasource.use_charge(amount * glacost) + return + +/obj/item/stack/sheet/rglass/cyborg/add(var/amount) + metsource.add_charge(amount * metcost) + glasource.add_charge(amount * glacost) + return /obj/item/stack/sheet/rglass/attack_self(mob/user as mob) construct_window(user) @@ -142,7 +163,7 @@ user << "\red You don't have the dexterity to do this!" return 0 var/title = "Sheet Reinf. Glass" - title += " ([src.amount] sheet\s left)" + title += " ([src.get_amount()] sheet\s left)" switch(input(title, "Would you like full tile glass a one direction glass pane or a windoor?") in list("One Direction", "Full Window", "Windoor", "Cancel")) if("One Direction") if(!src) return 1 @@ -182,7 +203,7 @@ if("Full Window") if(!src) return 1 if(src.loc != user) return 1 - if(src.amount < 2) + if(src.get_amount() < 2) user << "You need more glass to do that." return 1 if(locate(/obj/structure/window) in user.loc) @@ -208,7 +229,7 @@ user << "There is already a windoor in that location." return 1 - if(src.amount < 5) + if(src.get_amount() < 5) user << "You need more glass to do that." return 1 diff --git a/code/game/objects/items/stacks/sheets/light.dm b/code/game/objects/items/stacks/sheets/light.dm index e00fe5da5e5..00bc8110c1c 100644 --- a/code/game/objects/items/stacks/sheets/light.dm +++ b/code/game/objects/items/stacks/sheets/light.dm @@ -24,15 +24,13 @@ user.unEquip(src, 1) qdel(src) - if(istype(O,/obj/item/stack/sheet/metal)) + if(istype(O, /obj/item/stack/sheet/metal)) var/obj/item/stack/sheet/metal/M = O - M.amount-- - if(M.amount <= 0) - user.unEquip(M, 1) - qdel(M) - amount-- - var/obj/item/stack/tile/light/L = new (user.loc) - L.add_fingerprint(user) - if(amount <= 0) - user.unEquip(src, 1) - qdel(src) + if (M.use(1)) + use(1) + var/obj/item/stack/tile/light/L = new (user.loc) + user << "You make a light tile." + L.add_fingerprint(user) + else + user << "You need one metal sheet to finish the light tile." + return diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 774f723db8f..8951c278576 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -55,6 +55,8 @@ var/global/list/datum/stack_recipe/metal_recipes = list ( \ /obj/item/stack/sheet/metal/cyborg m_amt = 0 + is_cyborg = 1 + cost = 500 /obj/item/stack/sheet/metal/New(var/loc, var/amount=null) recipes = metal_recipes diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index f622413ce9c..568898f5802 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -14,14 +14,19 @@ var/singular_name var/amount = 1 var/max_amount //also see stack recipes initialisation, param "max_res_amount" must be equal to this max_amount + var/is_cyborg = 0 // It's 1 if module is used by a cyborg, and uses its storage + var/datum/robot_energy_storage/source + var/cost = 1 // How much energy from storage it costs /obj/item/stack/New(var/loc, var/amount=null) ..() if (amount) - src.amount=amount + src.amount = amount return /obj/item/stack/Destroy() + if (is_cyborg) + return // Not supposed to be destroyed if (usr && usr.machine==src) usr << browse(null, "window=stack") ..() @@ -29,27 +34,39 @@ /obj/item/stack/examine() set src in view(1) ..() - if(src.singular_name) - if(src.amount>1) - usr << "There are [src.amount] [src.singular_name]\s in the stack." + if (is_cyborg) + if(src.singular_name) + usr << "There is enough energy for [src.get_amount()] [src.singular_name]\s." else - usr << "There is [src.amount] [src.singular_name] in the stack." - else if(src.amount>1) - usr << "There are [src.amount] in the stack." + usr << "There is enough energy for [src.get_amount()]." + return + if(src.singular_name) + if(src.get_amount()>1) + usr << "There are [src.get_amount()] [src.singular_name]\s in the stack." + else + usr << "There is [src.get_amount()] [src.singular_name] in the stack." + else if(src.get_amount()>1) + usr << "There are [src.get_amount()] in the stack." else - usr << "There is [src.amount] in the stack." + usr << "There is [src.get_amount()] in the stack." return +/obj/item/stack/proc/get_amount() + if (is_cyborg) + return round(source.energy / cost) + else + return (amount) + /obj/item/stack/attack_self(mob/user as mob) interact(user) /obj/item/stack/interact(mob/user as mob) if (!recipes) return - if (!src || amount<=0) + if (!src || get_amount() <= 0) user << browse(null, "window=stack") user.set_machine(src) //for correct work of onclose - var/t1 = text("Constructions from []Amount Left: []
", src, src.amount) + var/t1 = text("Constructions from []Amount Left: []
", src, src.get_amount()) for(var/i=1;i<=recipes.len,i++) var/datum/stack_recipe/R = recipes[i] if (isnull(R)) @@ -57,7 +74,7 @@ continue if (i>1 && !isnull(recipes[i-1])) t1+="
" - var/max_multiplier = round(src.amount / R.req_amount) + var/max_multiplier = round(src.get_amount() / R.req_amount) var/title as text var/can_build = 1 can_build = can_build && (max_multiplier>0) @@ -97,12 +114,12 @@ if ((usr.restrained() || usr.stat || usr.get_active_hand() != src)) return if (href_list["make"]) - if (src.amount < 1) qdel(src) //Never should happen + if (src.get_amount() < 1) qdel(src) //Never should happen var/datum/stack_recipe/R = recipes[text2num(href_list["make"])] var/multiplier = text2num(href_list["multiplier"]) if (!multiplier) multiplier = 1 - if (src.amount < R.req_amount*multiplier) + if (src.get_amount() < R.req_amount*multiplier) if (R.req_amount*multiplier>1) usr << "\red You haven't got enough [src] to build \the [R.req_amount*multiplier] [R.title]\s!" else @@ -118,24 +135,19 @@ usr << "\blue Building [R.title] ..." if (!do_after(usr, R.time)) return - if (src.amount < R.req_amount*multiplier) + if (src.get_amount() < R.req_amount*multiplier) return var/atom/O = new R.result_type( usr.loc ) O.dir = usr.dir - if (R.max_res_amount>1) + if (R.max_res_amount > 1) var/obj/item/stack/new_item = O new_item.amount = R.res_amount*multiplier - //new_item.add_to_stacks(usr) - src.amount-=R.req_amount*multiplier - if (src.amount<=0) - var/oldsrc = src - src = null //dont kill proc after del() - usr.unEquip(oldsrc, 1) - qdel(oldsrc) - if (istype(O,/obj/item)) - usr.put_in_hands(O) + new_item.add_to_stacks(usr) + use(R.req_amount * multiplier) + if (istype(O,/obj/item)) + usr.put_in_hands(O) O.add_fingerprint(usr) - //BubbleWrap - so newly formed boxes are empty + //BubbleWrap - so newly formed boxes are empty // This is so insanely bad I don't even if ( istype(O, /obj/item/weapon/storage) ) for (var/obj/item/I in O) qdel(I) @@ -146,15 +158,23 @@ return return -/obj/item/stack/proc/use(var/amount) - src.amount-=amount - if (src.amount<=0) - var/oldsrc = src - src = null //dont kill proc after del() +/obj/item/stack/proc/use(var/used) // return 0 = borked; return 1 = had enough + if (is_cyborg) + return source.use_charge(used * cost) + if (amount < used) + return 0 + amount -= used + if (amount <= 0) if(usr) - usr.unEquip(oldsrc, 1) - qdel(oldsrc) - return + usr.unEquip(src, 1) + qdel(src) + return 1 + +/obj/item/stack/proc/add(var/amount) + if (is_cyborg) + source.add_charge(amount * cost) + else + src.amount += amount /obj/item/stack/proc/add_to_stacks(mob/usr as mob) var/obj/item/stack/oldsrc = src @@ -189,19 +209,28 @@ ..() if (istype(W, src.type)) var/obj/item/stack/S = W - if (S.amount >= max_amount) - return 1 - var/to_transfer as num - if (user.get_inactive_hand()==src) - to_transfer = 1 + if (S.is_cyborg) + var/to_transfer = min(src.amount, round((S.source.max_energy - S.source.energy) / S.cost)) + S.add(to_transfer) + if (S && usr.machine==S) + spawn(0) S.interact(usr) + src.use(to_transfer) + if (src && usr.machine==src) + spawn(0) src.interact(usr) else - to_transfer = min(src.amount, S.max_amount-S.amount) - S.amount+=to_transfer - if (S && usr.machine==S) - spawn(0) S.interact(usr) - src.use(to_transfer) - if (src && usr.machine==src) - spawn(0) src.interact(usr) + if (S.amount >= max_amount) + return 1 + var/to_transfer as num + if (user.get_inactive_hand()==src) + to_transfer = 1 + else + to_transfer = min(src.amount, S.max_amount-S.amount) + S.amount+=to_transfer + if (S && usr.machine==S) + spawn(0) S.interact(usr) + src.use(to_transfer) + if (src && usr.machine==src) + spawn(0) src.interact(usr) else return ..() /obj/item/stack/proc/copy_evidences(obj/item/stack/from as obj) diff --git a/code/game/objects/items/stacks/tiles/plasteel.dm b/code/game/objects/items/stacks/tiles/plasteel.dm index fce3db65f83..adf2e4f7257 100644 --- a/code/game/objects/items/stacks/tiles/plasteel.dm +++ b/code/game/objects/items/stacks/tiles/plasteel.dm @@ -15,7 +15,8 @@ /obj/item/stack/tile/plasteel/cyborg desc = "The ground you walk on" //Not the usual floor tile desc as that refers to throwing, Cyborgs can't do that - RR m_amt = 0 // All other Borg versions of items have no Metal or Glass - RR - max_amount = 50 + is_cyborg = 1 + cost = 125 /obj/item/stack/tile/plasteel/New(var/loc, var/amount=null) ..() @@ -28,7 +29,7 @@ if (istype(W, /obj/item/weapon/weldingtool)) var/obj/item/weapon/weldingtool/WT = W - if(amount < 4) + if(get_amount() < 4) user << "\red You need at least four tiles to do this." return diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm index 8f6eab792de..99173ffb58b 100644 --- a/code/game/objects/items/weapons/grenades/chem_grenade.dm +++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm @@ -93,10 +93,13 @@ else if(stage == EMPTY && istype(I, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/C = I - C.use(1) - det_time = 50 // In case the cable_coil was removed and readded. - stage_change(WIRED) - user << "You rig the [initial(name)] assembly." + if (C.use(1)) + det_time = 50 // In case the cable_coil was removed and readded. + stage_change(WIRED) + user << "You rig the [initial(name)] assembly." + else + user << "You need one length of coil to wire the assembly." + return else if(stage == READY && istype(I, /obj/item/weapon/wirecutters)) stage_change(WIRED) diff --git a/code/game/objects/items/weapons/grenades/ghettobomb.dm b/code/game/objects/items/weapons/grenades/ghettobomb.dm index df3e801863f..3bdb2c6cc6e 100644 --- a/code/game/objects/items/weapons/grenades/ghettobomb.dm +++ b/code/game/objects/items/weapons/grenades/ghettobomb.dm @@ -52,14 +52,17 @@ if(istype(I, /obj/item/stack/cable_coil)) if(assembled == 1) var/obj/item/stack/cable_coil/C = I - C.use(1) - assembled = 2 - user << "You wire the igniter to detonate the fuel." - desc = "A weak, improvised explosive." - overlays += image('icons/obj/grenade.dmi', icon_state = "improvised_grenade_wired") - name = "improvised explosive" - active = 0 - det_time = rand(30,80) + if (C.use(1)) + assembled = 2 + user << "You wire the igniter to detonate the fuel." + desc = "A weak, improvised explosive." + overlays += image('icons/obj/grenade.dmi', icon_state = "improvised_grenade_wired") + name = "improvised explosive" + active = 0 + det_time = rand(30,80) + else + user <<"span class='warning'>You need one length of cable to add an igniter.
" + return /obj/item/weapon/grenade/iedcasing/attack_self(mob/user as mob) // if(!active) diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm index 799b5e57d52..4506afb18a6 100644 --- a/code/game/objects/items/weapons/handcuffs.dm +++ b/code/game/objects/items/weapons/handcuffs.dm @@ -91,15 +91,15 @@ ..() if(istype(I, /obj/item/stack/rods)) var/obj/item/stack/rods/R = I - var/obj/item/weapon/wirerod/W = new /obj/item/weapon/wirerod - R.use(1) - - user.unEquip(src) - - user.put_in_hands(W) - user << "You wrap the cable restraint around the top of the rod." - - qdel(src) + if (R.use(1)) + var/obj/item/weapon/wirerod/W = new /obj/item/weapon/wirerod + user.unEquip(src) + user.put_in_hands(W) + user << "You wrap the cable restraint around the top of the rod." + qdel(src) + else + user << "You need one rod to make a wired rod." + return /obj/item/weapon/handcuffs/cyborg/attack(mob/living/carbon/C, mob/user) if(isrobot(user)) diff --git a/code/game/objects/items/weapons/table_rack_parts.dm b/code/game/objects/items/weapons/table_rack_parts.dm index 8adcedd4ff9..d8cbe11c631 100644 --- a/code/game/objects/items/weapons/table_rack_parts.dm +++ b/code/game/objects/items/weapons/table_rack_parts.dm @@ -17,15 +17,15 @@ new /obj/item/stack/sheet/metal( user.loc ) //SN src = null qdel(src) - if (istype(W, /obj/item/stack/rods)) - var/obj/item/stack/rods/R = W - if (R.amount >= 4) + if (istype(W, /obj/item/stack/rods)) + var/obj/item/stack/rods/V = W + if (V.use(4)) new /obj/item/weapon/table_parts/reinforced( user.loc ) user << "You reinforce the [name]." - R.use(4) qdel(src) - else if (R.amount < 4) - user << "You need at least 4 rods to do that." + else + user << "You need four rods to reinforce table parts." + return /obj/item/weapon/table_parts/attack_self(mob/user as mob) user << "Constructing table.." @@ -93,4 +93,4 @@ R.add_fingerprint(user) user.drop_item() qdel(src) - return \ No newline at end of file + return diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 385115c97a8..617fe7a030a 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -361,13 +361,17 @@ /obj/item/weapon/weldingtool/proc/flamethrower_rods(obj/item/I, mob/user) if(!status) var/obj/item/stack/rods/R = I - R.use(1) - var/obj/item/weapon/flamethrower/F = new /obj/item/weapon/flamethrower(user.loc) - user.unEquip(src) - loc = F - F.weldtool = src - add_fingerprint(user) - user.put_in_hands(F) + if (R.use(1)) + var/obj/item/weapon/flamethrower/F = new /obj/item/weapon/flamethrower(user.loc) + user.unEquip(src) + loc = F + F.weldtool = src + add_fingerprint(user) + user << "You add a rod to a welder, starting to build a flamethrower." + user.put_in_hands(F) + else + user << "You need one rod to start building a flamethrower." + return /obj/item/weapon/weldingtool/largetank name = "industrial welding tool" diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 358c961abc2..790f7f188e1 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -335,10 +335,12 @@ if(rigged) user << "[src] is already rigged!" return - user << "You rig [src]." - user.drop_item() - qdel(W) - rigged = 1 + var/obj/item/stack/cable_coil/C = W + if (C.use(5)) + user << "You rig [src]." + rigged = 1 + else + user << "You need 5 lengths of cable to rig [src]." return else if(istype(W, /obj/item/device/radio/electropack)) if(rigged) diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index 553122c43fb..09193785f88 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -458,13 +458,16 @@ obj/structure/door_assembly src.anchored = 0 else if(istype(W, /obj/item/stack/cable_coil) && state == 0 && anchored ) - var/obj/item/stack/cable_coil/coil = W + var/obj/item/stack/cable_coil/C = W + if (C.get_amount() < 1) + user << "You need one length of cable to wire the airlock assembly." + return user.visible_message("[user] wires the airlock assembly.", "You start to wire the airlock assembly.") if(do_after(user, 40)) - if(!src) return - coil.use(1) + if(C.get_amount() < 1 || state != 0) return + C.use(1) src.state = 1 - user << "\blue You've wired the airlock assembly." + user << "You've wired the airlock assembly." src.name = "wired airlock assembly" else if(istype(W, /obj/item/weapon/wirecutters) && state == 1 ) diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 1311dbea0b8..d0875271714 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -73,25 +73,29 @@ if(/obj/item/stack/sheet/metal, /obj/item/stack/sheet/metal/cyborg) if(!anchored) - if(S.amount < 2) - user << "You need at least two sheets to create a false wall." + if (S.use(2)) + user << "You create a false wall! Push on it to open or close the passage." + var/obj/structure/falsewall/F = new (loc) + transfer_fingerprints_to(F) + qdel(src) + else + user << "You need two sheets of metal to create a false wall." return - S.use(2) - user << "You create a false wall! Push on it to open or close the passage." - var/obj/structure/falsewall/F = new (loc) - transfer_fingerprints_to(F) - qdel(src) else - if(S.amount < 2) return ..() + if(S.get_amount() < 2) + user << "You need two sheets of metal to finish a wall." + return user << "Now adding plating..." - if (do_after(user,40)) - if(!src || !S || S.amount < 2) return + if (do_after(user, 40)) + if(loc == null || S.get_amount() < 2) + return S.use(2) user << "You added the plating!" var/turf/Tsrc = get_turf(src) Tsrc.ChangeTurf(/turf/simulated/wall) for(var/turf/simulated/wall/X in Tsrc.loc) - if(X) transfer_fingerprints_to(X) + if(X) + transfer_fingerprints_to(X) qdel(src) return diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index ff59707bbed..fbdc264dcf3 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -119,7 +119,11 @@ return //window placing begin - else if( istype(W,/obj/item/stack/sheet/rglass) || istype(W,/obj/item/stack/sheet/glass) ) + else if(istype(W, /obj/item/stack/sheet/rglass) || istype(W, /obj/item/stack/sheet/glass)) + var/obj/item/stack/ST = W + if (ST.get_amount() < 1) + user << "You need at least one sheet of glass for that." + return var/dir_to_set = 1 if(loc == user.loc) dir_to_set = user.dir @@ -150,7 +154,7 @@ user << "There is already a window facing this way there." return var/obj/structure/window/WD - if(istype(W,/obj/item/stack/sheet/rglass)) + if(istype(W, /obj/item/stack/sheet/rglass)) WD = new/obj/structure/window(loc,1) //reinforced window else WD = new/obj/structure/window(loc,0) //normal window @@ -158,7 +162,6 @@ WD.ini_dir = dir_to_set WD.anchored = 0 WD.state = 0 - var/obj/item/stack/ST = W ST.use(1) user << "You place the [WD] on [src]." return diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index 7c02b232b65..be5e7807136 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -199,13 +199,13 @@ turf/simulated/floor/proc/update_icon() break_tile() /turf/simulated/floor/is_plasteel_floor() - if(istype(floor_tile,/obj/item/stack/tile/plasteel)) + if(istype(floor_tile, /obj/item/stack/tile/plasteel)) return 1 else return 0 /turf/simulated/floor/is_light_floor() - if(istype(floor_tile,/obj/item/stack/tile/light)) + if(istype(floor_tile, /obj/item/stack/tile/light)) return 1 else return 0 @@ -324,7 +324,7 @@ turf/simulated/floor/proc/update_icon() intact = 1 SetLuminosity(0) if(T) - if(istype(T,/obj/item/stack/tile/plasteel)) + if(istype(T, /obj/item/stack/tile/plasteel)) floor_tile = T if (icon_regular_floor) icon_state = icon_regular_floor @@ -463,24 +463,30 @@ turf/simulated/floor/proc/update_icon() if(istype(C, /obj/item/stack/rods)) var/obj/item/stack/rods/R = C if (is_plating()) - if (R.amount >= 2) - user << "\blue Reinforcing the floor..." - if(do_after(user, 30) && R && R.amount >= 2 && is_plating()) - ChangeTurf(/turf/simulated/floor/engine) - playsound(src, 'sound/items/Deconstruct.ogg', 80, 1) - R.use(2) - return + if (R.get_amount() < 2) + user << "You need two rods to make a reinforced floor." + return else - user << "\red You need more rods." + user << "Reinforcing the floor..." + if(do_after(user, 30)) + if (R.get_amount() >= 2 && is_plating()) + ChangeTurf(/turf/simulated/floor/engine) + playsound(src, 'sound/items/Deconstruct.ogg', 80, 1) + R.use(2) + user << "You have reinforced the floor." + return else - user << "\red You must remove the plating first." + user << "You must remove the plating first." return if(istype(C, /obj/item/stack/tile)) if(is_plating()) if(!broken && !burnt) var/obj/item/stack/tile/T = C - floor_tile = new T.type + if(istype(T, /obj/item/stack/tile/plasteel/cyborg)) + floor_tile = new /obj/item/stack/tile/plasteel + else + floor_tile = new T.type intact = 1 if(istype(T,/obj/item/stack/tile/light)) var/obj/item/stack/tile/light/L = T @@ -514,7 +520,7 @@ turf/simulated/floor/proc/update_icon() return coil.turf_place(src, user) else - user << "\red You must remove the plating first." + user << "You must remove the plating first." if(istype(C, /obj/item/weapon/shovel)) if(is_grass_floor()) diff --git a/code/game/turfs/simulated/walls_reinforced.dm b/code/game/turfs/simulated/walls_reinforced.dm index 1dfbc9d1bb3..8126029fc18 100644 --- a/code/game/turfs/simulated/walls_reinforced.dm +++ b/code/game/turfs/simulated/walls_reinforced.dm @@ -75,13 +75,16 @@ return //REPAIRING (replacing the outer grille for cosmetic damage) - else if( istype(W, /obj/item/stack/rods) ) + else if(istype(W, /obj/item/stack/rods)) var/obj/item/stack/rods/O = W - src.d_state = 0 - src.icon_state = "r_wall" - relativewall_neighbours() //call smoothwall stuff - user << "You replace the outer grille." - O.use(1) + if (O.use(1)) + src.d_state = 0 + src.icon_state = "r_wall" + relativewall_neighbours() //call smoothwall stuff + user << "You replace the outer grille." + else + user << "You need one rod to repair the wall." + return return if(2) @@ -211,20 +214,23 @@ dismantle_wall() //REPAIRING - else if( istype(W, /obj/item/stack/sheet/metal) && d_state ) + else if(istype(W, /obj/item/stack/sheet/metal) && d_state) var/obj/item/stack/sheet/metal/MS = W + if (MS.get_amount() < 1) + user << "You need one sheet of metal to repair the wall." + return + user << "You begin patching-up the wall with \a [MS]." - sleep( max(20*d_state,100) ) //time taken to repair is proportional to the damage! (max 10 seconds) - if( !istype(src, /turf/simulated/wall/r_wall) || !user || !MS || !T ) return - - if( user.loc == T && user.get_active_hand() == MS && d_state ) + if (do_after(user, max(20*d_state,100)))//time taken to repair is proportional to the damage! (max 10 seconds) + if(loc == null || MS.get_amount() < 1) + return + MS.use(1) src.d_state = 0 src.icon_state = "r_wall" relativewall_neighbours() //call smoothwall stuff user << "You repair the last of the damage." - MS.use(1) //APC diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index d5f53c2942a..b4bf950331f 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -18,27 +18,35 @@ /turf/space/attackby(obj/item/C as obj, mob/user as mob) if (istype(C, /obj/item/stack/rods)) + var/obj/item/stack/rods/R = C var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) if(L) + user << "There is already a lattice." + return + if (R.use(1)) + user << "Constructing support lattice..." + playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) + ReplaceWithLattice() + else + user << "You need one rod to build lattice." return - var/obj/item/stack/rods/R = C - user << "\blue Constructing support lattice ..." - playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) - ReplaceWithLattice() - R.use(1) return if (istype(C, /obj/item/stack/tile/plasteel)) var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) if(L) var/obj/item/stack/tile/plasteel/S = C - qdel(L) - playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) - S.build(src) - S.use(1) + if (S.use(1)) + qdel(L) + playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) + user << "You build a floor." + S.build(src) + else + user << "You need one floor tile to build a floor." + return return else - user << "\red The plating is going to need some support." + user << "The plating is going to need some support. Place metal rods first." return diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 53b7210d99f..1832f971b2d 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -144,15 +144,17 @@ /obj/item/weapon/reagent_containers/food/snacks/grown/potato/attackby(obj/item/weapon/W as obj, mob/user as mob) ..() if(istype(W, /obj/item/stack/cable_coil)) - if(W:amount >= 5) - W:amount -= 5 - if(!W:amount) qdel(W) + var/obj/item/stack/cable_coil/C + if (C.use(5)) user << "You add some cable to the potato and slide it inside the battery encasing." var/obj/item/weapon/stock_parts/cell/potato/pocell = new /obj/item/weapon/stock_parts/cell/potato(user.loc) pocell.maxcharge = src.potency * 10 pocell.charge = pocell.maxcharge qdel(src) return + else + user << "You need five lengths of cable to make a potato battery." + return /obj/item/weapon/reagent_containers/food/snacks/grown/grapes seed = "/obj/item/seeds/grapeseed" diff --git a/code/modules/mining/mint.dm b/code/modules/mining/mint.dm index 44cbb1da3cf..2f130f34d6e 100644 --- a/code/modules/mining/mint.dm +++ b/code/modules/mining/mint.dm @@ -25,28 +25,28 @@ var/turf/T = get_step(src,input_dir) if(T) for(var/obj/item/stack/sheet/O in T) - if (istype(O,/obj/item/stack/sheet/mineral/gold)) + if (istype(O, /obj/item/stack/sheet/mineral/gold)) amt_gold += 100 * O.amount O.loc = null - if (istype(O,/obj/item/stack/sheet/mineral/silver)) + if (istype(O, /obj/item/stack/sheet/mineral/silver)) amt_silver += 100 * O.amount O.loc = null - if (istype(O,/obj/item/stack/sheet/mineral/diamond)) + if (istype(O, /obj/item/stack/sheet/mineral/diamond)) amt_diamond += 100 * O.amount O.loc = null - if (istype(O,/obj/item/stack/sheet/mineral/plasma)) + if (istype(O, /obj/item/stack/sheet/mineral/plasma)) amt_plasma += 100 * O.amount O.loc = null - if (istype(O,/obj/item/stack/sheet/mineral/uranium)) + if (istype(O, /obj/item/stack/sheet/mineral/uranium)) amt_uranium += 100 * O.amount O.loc = null - if (istype(O,/obj/item/stack/sheet/metal)) + if (istype(O, /obj/item/stack/sheet/metal)) amt_iron += 100 * O.amount O.loc = null - if (istype(O,/obj/item/stack/sheet/mineral/clown)) + if (istype(O, /obj/item/stack/sheet/mineral/clown)) amt_clown += 100 * O.amount O.loc = null - if (istype(O,/obj/item/stack/sheet/mineral/adamantine)) + if (istype(O, /obj/item/stack/sheet/mineral/adamantine)) amt_adamantine += 100 * O.amount O.loc = null //Commented out for now. -Durandan return diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index 48c101d41be..88a115e20fb 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -224,21 +224,20 @@ /obj/item/weapon/coin/attackby(obj/item/weapon/W as obj, mob/user as mob) - if(istype(W,/obj/item/stack/cable_coil) ) + if(istype(W, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/CC = W if(string_attached) - user << "\blue There already is a string attached to this coin." + user << "There already is a string attached to this coin." return - if(CC.amount <= 0) - user << "\blue This cable coil appears to be empty." - qdel(CC) + if (CC.use(1)) + overlays += image('icons/obj/economy.dmi',"coin_string_overlay") + string_attached = 1 + user << "You attach a string to the coin." + else + user << "You need one length of cable to attach a string to the coin." return - overlays += image('icons/obj/economy.dmi',"coin_string_overlay") - string_attached = 1 - user << "\blue You attach a string to the coin." - CC.use(1) else if(istype(W,/obj/item/weapon/wirecutters)) if(!string_attached) ..() diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 9354918ac99..23019c83f9e 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -317,6 +317,8 @@ if(internal) stat("Internal Atmosphere Info", internal.name) stat("Tank Pressure", internal.air_contents.return_pressure()) + for (var/datum/robot_energy_storage/st in module.storages) + stat("[st.name]: [st.energy]/[st.max_energy]") /mob/living/silicon/robot/restrained() return 0 @@ -413,11 +415,13 @@ else if(istype(W, /obj/item/stack/cable_coil) && wiresexposed) var/obj/item/stack/cable_coil/coil = W - adjustFireLoss(-30) - updatehealth() - for(var/mob/O in viewers(user, null)) - O.show_message(text("\red [user] has fixed some of the burnt wires on [src]!"), 1) - coil.use(1) + if (coil.use(1)) + adjustFireLoss(-30) + updatehealth() + for(var/mob/O in viewers(user, null)) + O.show_message(text("\red [user] has fixed some of the burnt wires on [src]!"), 1) + else + user << "You need one length of cable to repair [src]." else if (istype(W, /obj/item/weapon/crowbar)) // crowbar means open or close the cover if(opened) diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 277bacfe30b..3fedce48ffb 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -9,7 +9,7 @@ var/list/modules = list() var/obj/item/emag = null var/obj/item/borg/upgrade/jetpack = null - + var/list/storages = list() /obj/item/weapon/robot_module/emp_act(severity) if(modules) @@ -108,42 +108,38 @@ modules += new /obj/item/device/t_scanner(src) modules += new /obj/item/device/analyzer(src) + var/datum/robot_energy_storage/metal/metstore = new /datum/robot_energy_storage/metal(src) + var/datum/robot_energy_storage/glass/glastore = new /datum/robot_energy_storage/glass(src) + var/datum/robot_energy_storage/wire/wirestore = new /datum/robot_energy_storage/wire(src) + var/obj/item/stack/sheet/metal/cyborg/M = new /obj/item/stack/sheet/metal/cyborg(src) - M.amount = 50 + M.source = metstore modules += M + var/obj/item/stack/sheet/glass/cyborg/Q = new /obj/item/stack/sheet/glass/cyborg(src) + Q.source = glastore + modules += Q + var/obj/item/stack/sheet/rglass/cyborg/G = new /obj/item/stack/sheet/rglass/cyborg(src) - G.amount = 50 + G.metsource = metstore + G.glasource = glastore modules += G var/obj/item/stack/rods/cyborg/R = new /obj/item/stack/rods/cyborg(src) - R.amount = 50 + R.source = metstore modules += R - var/obj/item/stack/cable_coil/W = new /obj/item/stack/cable_coil(src) - W.amount = 50 + var/obj/item/stack/cable_coil/cyborg/W = new /obj/item/stack/cable_coil/cyborg(src) + W.source = wirestore modules += W var/obj/item/stack/tile/plasteel/cyborg/F = new /obj/item/stack/tile/plasteel/cyborg(src) //"Plasteel" is the normal metal floor tile, Don't be confused - RR - F.amount = 50 - modules += F //'F' for floor tile - RR - - - respawn_consumable(var/mob/living/silicon/robot/R) - var/list/what = list ( - /obj/item/stack/sheet/metal, - /obj/item/stack/sheet/rglass, - /obj/item/stack/rods, - /obj/item/stack/cable_coil, - /obj/item/stack/tile/plasteel/cyborg, - ) - for(var/T in what) - if(!(locate(T) in modules)) - modules -= null - var/O = new T(src) - modules += O - O:amount = 1 + F.source = metstore + modules += F //'F' for floor tile - RR(src) + storages += metstore + storages += glastore + storages += wirestore /obj/item/weapon/robot_module/security name = "security robot module" @@ -239,4 +235,37 @@ modules += new /obj/item/weapon/gun/energy/laser/cyborg(src) modules += new /obj/item/weapon/tank/jetpack/carbondioxide(src) modules += new /obj/item/weapon/crowbar(src) - emag = null \ No newline at end of file + emag = null + +/datum/robot_energy_storage + var/name = "Generic energy storage" + var/max_energy = 30000 + var/recharge_rate = 1000 + var/energy + +/datum/robot_energy_storage/New() + energy = max_energy + return + +/datum/robot_energy_storage/proc/use_charge(var/amount) + if (energy >= amount) + energy -= amount + if (energy == 0) + return 1 + return 2 + else + return 0 + +/datum/robot_energy_storage/proc/add_charge(var/amount) + energy = min(energy + amount, max_energy) + +/datum/robot_energy_storage/metal + name = "Metal Synthesizer" + +/datum/robot_energy_storage/glass + name = "Glass Synthesizer" + +/datum/robot_energy_storage/wire + max_energy = 50 + recharge_rate = 2 + name = "Wire Synthesizer" diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index e296c3123fd..dd23b2ed520 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -488,28 +488,29 @@ user << "You fail to [ locked ? "unlock" : "lock"] the APC interface." else if (istype(W, /obj/item/stack/cable_coil) && !terminal && opened && has_electronics!=2) if (src.loc:intact) - user << "\red You must remove the floor plating in front of the APC first." + user << "You must remove the floor plating in front of the APC first." return var/obj/item/stack/cable_coil/C = W - if(C.amount < 10) - user << "\red You need more wires." + if(C.get_amount() < 10) + user << "You need ten lengths of cable for APC." return user << "You start adding cables to the APC frame..." playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) - if(do_after(user, 20) && C.amount >= 10) - var/turf/T = get_turf(src) - var/obj/structure/cable/N = T.get_cable_node() - if (prob(50) && electrocute_mob(usr, N, N)) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(5, 1, src) - s.start() - return - C.use(10) - user.visible_message(\ - "\red [user.name] has added cables to the APC frame!",\ - "You add cables to the APC frame.") - make_terminal() - terminal.connect_to_network() + if(do_after(user, 20)) + if (C.amount >= 10 && !terminal && opened && has_electronics != 2) + var/turf/T = get_turf(src) + var/obj/structure/cable/N = T.get_cable_node() + if (prob(50) && electrocute_mob(usr, N, N)) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, src) + s.start() + return + C.use(10) + user.visible_message(\ + "\red [user.name] has added cables to the APC frame!",\ + "You add cables to the APC frame.") + make_terminal() + terminal.connect_to_network() else if (istype(W, /obj/item/weapon/wirecutters) && terminal && opened && has_electronics!=2) if (src.loc:intact) user << "\red You must remove the floor plating in front of the APC first." diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 5dc3e03aef9..94acb6797ee 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -146,6 +146,9 @@ By design, d1 is the smallest direction and d2 is the highest else if(istype(W, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/coil = W + if (coil.get_amount() < 1) + user << "Not enough cable" + return coil.cable_join(src, user) else if(istype(W, /obj/item/device/multitool)) @@ -464,6 +467,12 @@ obj/structure/cable/proc/avail() slot_flags = SLOT_BELT attack_verb = list("whipped", "lashed", "disciplined", "flogged") +/obj/item/stack/cable_coil/cyborg + is_cyborg = 1 + m_amt = 0 + g_amt = 0 + cost = 1 + /obj/item/stack/cable_coil/suicide_act(mob/user) if(locate(/obj/structure/stool) in user.loc) user.visible_message("[user] is making a noose with the [src.name]! It looks like \he's trying to commit suicide.") @@ -515,12 +524,15 @@ obj/structure/cable/proc/avail() /obj/item/stack/cable_coil/examine() set src in view(1) - if(amount == 1) - usr << "A short piece of power cable." - else if(amount == 2) - usr << "A piece of power cable." + if (is_cyborg) + usr << "A cable synthesizer. Currently has energy for [get_amount()] lengths of cable." else - usr << "A coil of power cable. There are [amount] lengths of cable in the coil." + if(get_amount() == 1) + usr << "A short piece of power cable." + else if(get_amount() == 2) + usr << "A piece of power cable." + else + usr << "A coil of power cable. There are [get_amount()] lengths of cable in the coil." /obj/item/stack/cable_coil/verb/make_restraint() @@ -553,7 +565,12 @@ obj/structure/cable/proc/avail() src.update_icon() return - else if( istype(W, /obj/item/stack/cable_coil) ) + else if(istype(W, /obj/item/stack/cable_coil/cyborg)) + var/obj/item/stack/cable_coil/cyborg/C = W + var/to_transfer = min(src.amount, round((C.source.max_energy - C.source.energy) / C.cost)) + C.add(to_transfer) + src.use(to_transfer) + else if(istype(W, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/C = W if(C.amount >= MAXCOIL) user << "The coil is too long, you cannot add any more cable to it." @@ -573,6 +590,7 @@ obj/structure/cable/proc/avail() return //remove cables from the stack +/* This is probably reduntant /obj/item/stack/cable_coil/use(var/used) if(src.amount < used) return 0 @@ -586,6 +604,11 @@ obj/structure/cable/proc/avail() amount -= used update_icon() return 1 +*/ +/obj/item/stack/cable_coil/use(var/used) + . = ..() + update_icon() + return //add cables to the stack /obj/item/stack/cable_coil/proc/give(var/extra) @@ -604,11 +627,15 @@ obj/structure/cable/proc/avail() if(!isturf(user.loc)) return - if(get_dist(F,user) > 1) //too far + if(get_amount() < 1) // Out of cable + user << "There is no cable left." + return + + if(get_dist(F,user) > 1) // Too far user << "You can't lay cable at a place that far away." return - if(F.intact) // if floor is intact, complain + if(F.intact) // Ff floor is intact, complain user << "You can't lay cable there unless the floor tiles are removed." return diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 7158a28f907..8261e9fc7dc 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -137,15 +137,17 @@ if(istype(W, /obj/item/stack/cable_coil)) if (src.stage != 1) return var/obj/item/stack/cable_coil/coil = W - coil.use(1) - switch(fixture_type) - if ("tube") - src.icon_state = "tube-construct-stage2" - if("bulb") - src.icon_state = "bulb-construct-stage2" - src.stage = 2 - user.visible_message("[user.name] adds wires to [src].", \ - "You add wires to [src].") + if (coil.use(1)) + switch(fixture_type) + if ("tube") + src.icon_state = "tube-construct-stage2" + if("bulb") + src.icon_state = "bulb-construct-stage2" + src.stage = 2 + user.visible_message("[user.name] adds wires to [src].", \ + "You add wires to [src].") + else + user << "You need one length of cable to wire [src]." return if(istype(W, /obj/item/weapon/screwdriver)) diff --git a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm index f4751450a1d..85684c8e756 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm @@ -226,10 +226,14 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin "You remove the external bolts.") temp_state-- else if(istype(O, /obj/item/stack/cable_coil)) - if(O:use(1,user)) + var/obj/item/stack/cable_coil/C = O + if(C.use(1)) user.visible_message("[user.name] adds wires to the [src.name].", \ "You add some wires.") temp_state++ + else + user << "You need one length of cable to wire the [src.name]." + return if(2) if(istype(O, /obj/item/weapon/wirecutters))//TODO:Shock user if its on? user.visible_message("[user.name] removes some wires from the [src.name].", \ diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm index 7c3e16ed5a4..8b394c28d73 100644 --- a/code/modules/power/solar.dm +++ b/code/modules/power/solar.dm @@ -219,15 +219,17 @@ var/list/solars_list = list() if(istype(W, /obj/item/stack/sheet/glass) || istype(W, /obj/item/stack/sheet/rglass)) var/obj/item/stack/sheet/S = W - if(S.amount >= 2) + if(S.use(2)) glass_type = W.type - S.use(2) playsound(src.loc, 'sound/machines/click.ogg', 50, 1) user.visible_message("[user] places the glass on the solar assembly.") if(tracker) new /obj/machinery/power/tracker(get_turf(src), src) else new /obj/machinery/power/solar(get_turf(src), src) + else + user << "You need two sheets of glass to put them into a solar panel." + return return 1 if(!tracker) diff --git a/code/modules/research/circuitprinter.dm b/code/modules/research/circuitprinter.dm index e5588ca946f..6c960e0d5c8 100644 --- a/code/modules/research/circuitprinter.dm +++ b/code/modules/research/circuitprinter.dm @@ -75,15 +75,15 @@ using metal and glass, it uses glass and reagents (usually sulfuric acis). if(istype(O, /obj/item/weapon/crowbar)) for(var/obj/item/weapon/reagent_containers/glass/G in component_parts) reagents.trans_to(G, G.reagents.maximum_volume) - if(g_amount >= 3750) + if(g_amount >= MINERAL_MATERIAL_AMOUNT) var/obj/item/stack/sheet/glass/G = new /obj/item/stack/sheet/glass(src.loc) - G.amount = round(g_amount / 3750) - if(gold_amount >= 2000) + G.amount = round(g_amount / MINERAL_MATERIAL_AMOUNT) + if(gold_amount >= MINERAL_MATERIAL_AMOUNT) var/obj/item/stack/sheet/mineral/gold/G = new /obj/item/stack/sheet/mineral/gold(src.loc) - G.amount = round(gold_amount / 2000) - if(diamond_amount >= 2000) + G.amount = round(gold_amount / MINERAL_MATERIAL_AMOUNT) + if(diamond_amount >= MINERAL_MATERIAL_AMOUNT) var/obj/item/stack/sheet/mineral/diamond/G = new /obj/item/stack/sheet/mineral/diamond(src.loc) - G.amount = round(diamond_amount / 2000) + G.amount = round(diamond_amount / MINERAL_MATERIAL_AMOUNT) default_deconstruction_crowbar(O) return else @@ -116,14 +116,14 @@ using metal and glass, it uses glass and reagents (usually sulfuric acis). amount = min(stack.amount, round((max_material_amount-TotalMaterials())/stack.perunit)) busy = 1 - use_power(max(1000, (3750*amount/10))) + use_power(max(1000, (MINERAL_MATERIAL_AMOUNT*amount/10))) user << "You add [amount] sheets to the [src.name]." if(istype(stack, /obj/item/stack/sheet/glass)) - g_amount += amount * 3750 + g_amount += amount * MINERAL_MATERIAL_AMOUNT else if(istype(stack, /obj/item/stack/sheet/mineral/gold)) - gold_amount += amount * 2000 + gold_amount += amount * MINERAL_MATERIAL_AMOUNT else if(istype(stack, /obj/item/stack/sheet/mineral/diamond)) - diamond_amount += amount * 2000 + diamond_amount += amount * MINERAL_MATERIAL_AMOUNT stack.use(amount) busy = 0 src.updateUsrDialog() From ce98f5a82b483012b09a8fdaa9701f70d05ebeae Mon Sep 17 00:00:00 2001 From: Kelenius Date: Wed, 11 Jun 2014 11:04:00 +0400 Subject: [PATCH 10/55] Some grammar --- code/game/machinery/alarm.dm | 2 +- code/game/machinery/bots/ed209bot.dm | 2 +- code/game/machinery/bots/floorbot.dm | 2 +- code/game/objects/items/stacks/stack.dm | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index 4bc346319f4..9b404e0531b 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -808,7 +808,7 @@ table tr:first-child th:first-child { border: none;} if(istype(W, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/cable = W if(cable.get_amount() < 5) - user << "You need five lengths of cable to wire fire alarm." + user << "You need five lengths of cable to wire the fire alarm." return user << "You start wiring the air alarm." if (do_after(user, 20)) diff --git a/code/game/machinery/bots/ed209bot.dm b/code/game/machinery/bots/ed209bot.dm index 09106fcee3b..85ace07a430 100644 --- a/code/game/machinery/bots/ed209bot.dm +++ b/code/game/machinery/bots/ed209bot.dm @@ -968,7 +968,7 @@ Auto Patrol: []"}, if(istype(W, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/coil = W if (coil.get_amount() < 1) - user << "You need one length of cable to wire ED-209." + user << "You need one length of cable to wire the ED-209." return user << "You start to wire [src]..." if (do_after(user, 40)) diff --git a/code/game/machinery/bots/floorbot.dm b/code/game/machinery/bots/floorbot.dm index c5d6d7de5a5..bdcaea0f7e8 100644 --- a/code/game/machinery/bots/floorbot.dm +++ b/code/game/machinery/bots/floorbot.dm @@ -109,7 +109,7 @@ user << "You load [loaded] tiles into the floorbot. He now contains [src.amount] tiles." src.updateicon() else - user << "You need at least one floor tile to put it into floorbot." + user << "You need at least one floor tile to put into the floorbot." else if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) if(src.allowed(usr) && !open && !emagged) src.locked = !src.locked diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 568898f5802..2630ca27570 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -147,7 +147,7 @@ if (istype(O,/obj/item)) usr.put_in_hands(O) O.add_fingerprint(usr) - //BubbleWrap - so newly formed boxes are empty // This is so insanely bad I don't even + //BubbleWrap - so newly formed boxes are empty if ( istype(O, /obj/item/weapon/storage) ) for (var/obj/item/I in O) qdel(I) From b80e9eda57636396a168210d1658b2469c11de61 Mon Sep 17 00:00:00 2001 From: Cheridan Date: Wed, 11 Jun 2014 14:19:58 -0500 Subject: [PATCH 11/55] Nar-Sie update --- code/datums/mind.dm | 15 +-- code/datums/spell.dm | 5 + code/datums/spells/construct_spells.dm | 17 ++++ code/game/gamemodes/wizard/soulstone.dm | 69 +++++--------- code/game/objects/effects/effect_system.dm | 5 +- .../mob/living/simple_animal/constructs.dm | 92 +++++++------------ code/modules/mob/transform_procs.dm | 16 +--- code/modules/power/singularity/singularity.dm | 57 ++++++------ 8 files changed, 111 insertions(+), 165 deletions(-) diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 9b004722c96..1e2f7d20e0e 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -1172,19 +1172,8 @@ datum/mind ..() mind.assigned_role = "Shade" -/mob/living/simple_animal/construct/builder/mind_initialize() +/mob/living/simple_animal/construct/mind_initialize() ..() - mind.assigned_role = "Artificer" + mind.assigned_role = "[initial(name)]" mind.special_role = "Cultist" -/mob/living/simple_animal/construct/wraith/mind_initialize() - ..() - mind.assigned_role = "Wraith" - mind.special_role = "Cultist" - -/mob/living/simple_animal/construct/armoured/mind_initialize() - ..() - mind.assigned_role = "Juggernaut" - mind.special_role = "Cultist" - - diff --git a/code/datums/spell.dm b/code/datums/spell.dm index 06bedadbd4d..1b3228133b0 100644 --- a/code/datums/spell.dm +++ b/code/datums/spell.dm @@ -191,6 +191,11 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin var/datum/effect/effect/system/bad_smoke_spread/smoke = new /datum/effect/effect/system/bad_smoke_spread() smoke.set_up(smoke_amt, 0, location, smoke_amt == 1 ? 15 : 0) // same here smoke.start() + else if(smoke_spread == 3) + var/datum/effect/effect/system/sleep_smoke_spread/smoke = new /datum/effect/effect/system/sleep_smoke_spread() + smoke.set_up(smoke_amt, 0, location, smoke_amt == 1 ? 15 : 0) // same here + smoke.start() + /obj/effect/proc_holder/spell/proc/cast(list/targets) return diff --git a/code/datums/spells/construct_spells.dm b/code/datums/spells/construct_spells.dm index ed3248d776a..3f1512bb4f5 100644 --- a/code/datums/spells/construct_spells.dm +++ b/code/datums/spells/construct_spells.dm @@ -110,3 +110,20 @@ invocation_type = "none" proj_lifespan = 10 max_targets = 6 + + +/obj/effect/proc_holder/spell/targeted/smoke/disable + name = "Disabling Smoke" + desc = "This spell spawns a cloud of disabling smoke." + + school = "conjuration" + charge_max = 200 + clothes_req = 0 + invocation = "none" + invocation_type = "none" + range = -1 + include_user = 1 + cooldown_min = 20 //25 deciseconds reduction per rank + + smoke_spread = 3 + smoke_amt = 10 \ No newline at end of file diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm index 2e7d0f8d0f2..3f40d34b6de 100644 --- a/code/game/gamemodes/wizard/soulstone.dm +++ b/code/game/gamemodes/wizard/soulstone.dm @@ -22,13 +22,6 @@ transfer_soul("VICTIM", M, user) return -/*/obj/item/device/soulstone/attack(mob/living/simple_animal/shade/M as mob, mob/user as mob)//APPARENTLY THEY NEED THEIR OWN SPECIAL SNOWFLAKE CODE IN THE LIVING ANIMAL DEFINES - if(!istype(M, /mob/living/simple_animal/shade))//If target is not a shade - return ..() - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to capture the soul of [M.name] ([M.ckey])") - - transfer_soul("SHADE", M, user) - return*/ ///////////////////Options for using captured souls/////////////////////////////////////// /obj/item/device/soulstone/attack_self(mob/user) @@ -46,8 +39,6 @@ return - - /obj/item/device/soulstone/Topic(href, href_list) var/mob/U = usr if (!in_range(src, U)||U.machine!=src) @@ -160,53 +151,35 @@ var/construct_class = alert(U, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer") switch(construct_class) if("Juggernaut") - var/mob/living/simple_animal/construct/armoured/Z = new /mob/living/simple_animal/construct/armoured (get_turf(T.loc)) - Z.key = A.key - if(iscultist(U)) - if(ticker.mode.name == "cult") - ticker.mode:add_cultist(Z.mind) - else - ticker.mode.cult+=Z.mind - ticker.mode.update_cult_icons_added(Z.mind) - qdel(T) - Z << "You are a Juggernaut. Though slow, your shell can withstand extreme punishment, create shield walls and even deflect energy weapons, and rip apart enemies and walls alike." - Z << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." - Z.cancel_camera() - qdel(C) + makeNewConstruct(/mob/living/simple_animal/construct/armoured, T, U) if("Wraith") - var/mob/living/simple_animal/construct/wraith/Z = new /mob/living/simple_animal/construct/wraith (get_turf(T.loc)) - Z.key = A.key - if(iscultist(U)) - if(ticker.mode.name == "cult") - ticker.mode:add_cultist(Z.mind) - else - ticker.mode.cult+=Z.mind - ticker.mode.update_cult_icons_added(Z.mind) - qdel(T) - Z << "You are a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls." - Z << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." - Z.cancel_camera() - qdel(C) + makeNewConstruct(/mob/living/simple_animal/construct/wraith, T, U) if("Artificer") - var/mob/living/simple_animal/construct/builder/Z = new /mob/living/simple_animal/construct/builder (get_turf(T.loc)) - Z.key = A.key - if(iscultist(U)) - if(ticker.mode.name == "cult") - ticker.mode:add_cultist(Z.mind) - else - ticker.mode.cult+=Z.mind - ticker.mode.update_cult_icons_added(Z.mind) - qdel(T) - Z << "You are an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, use magic missile, repair allied constructs (by clicking on them), and most important of all create new constructs (Use your Artificer spell to summon a new construct shell and Summon Soulstone to create a new soulstone)." - Z << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." - Z.cancel_camera() - qdel(C) + makeNewConstruct(/mob/living/simple_animal/construct/builder, T, U) + + qdel(T) + qdel(C) else U << "Creation failed!: The soul stone is empty! Go kill someone!" return + +proc/makeNewConstruct(var/mob/living/simple_animal/construct/ctype, var/mob/target, var/mob/stoner = null, cultoverride = 0) + var/mob/living/simple_animal/construct/newstruct = new ctype(get_turf(target)) + newstruct.key = target.key + if(stoner && iscultist(stoner) || cultoverride) + if(ticker.mode.name == "cult") + ticker.mode:add_cultist(newstruct.mind) + else + ticker.mode.cult+=newstruct.mind + ticker.mode.update_cult_icons_added(newstruct.mind) + newstruct << newstruct.playstyle_string + newstruct << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." + newstruct.cancel_camera() + + /obj/item/device/soulstone/proc/init_shade(var/obj/item/device/soulstone/C, var/mob/living/carbon/human/T, var/mob/U as mob, var/vic = 0) new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton T.invisibility = 101 diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index b5b4b4f7f5a..8dd8ad4263b 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -582,6 +582,7 @@ steam.start() -- spawns the effect icon = 'icons/effects/96x96.dmi' pixel_x = -32 pixel_y = -32 + color = "#9C3636" /obj/effect/effect/sleep_smoke/New() ..() @@ -596,7 +597,7 @@ steam.start() -- spawns the effect // if (M.wear_suit, /obj/item/clothing/suit/wizrobe && (M.hat, /obj/item/clothing/head/wizard) && (M.shoes, /obj/item/clothing/shoes/sandal)) // I'll work on it later else M.drop_item() - M:sleeping += 1 + M:sleeping += 5 if (M.coughedtime != 1) M.coughedtime = 1 M.emote("cough") @@ -612,7 +613,7 @@ steam.start() -- spawns the effect return else M.drop_item() - M:sleeping += 1 + M:sleeping += 5 if (M.coughedtime != 1) M.coughedtime = 1 M.emote("cough") diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 2ab4636438a..9506df68555 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -9,6 +9,7 @@ response_disarm = "flails at" response_harm = "punches" icon_dead = "shade_dead" + icon = 'icons/mob/mob.dmi' speed = 0 a_intent = "harm" stop_automated_movement = 1 @@ -25,6 +26,7 @@ minbodytemp = 0 faction = "cult" var/list/construct_spells = list() + var/playstyle_string = "You are a generic construct! Your job is to not exist." /mob/living/simple_animal/construct/New() ..() @@ -118,8 +120,7 @@ /mob/living/simple_animal/construct/armoured name = "Juggernaut" real_name = "Juggernaut" - desc = "A possessed suit of armour driven by the will of the restless dead" - icon = 'icons/mob/mob.dmi' + desc = "A possessed suit of armour driven by the will of the restless dead." icon_state = "behemoth" icon_living = "behemoth" maxHealth = 250 @@ -135,7 +136,8 @@ status_flags = 0 force_threshold = 11 construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall) - + playstyle_string = "You are a Juggernaut. Though slow, your shell can withstand extreme punishment, \ + create shield walls and even deflect energy weapons, and rip apart enemies and walls alike." /mob/living/simple_animal/construct/armoured/bullet_act(var/obj/item/projectile/P) if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)) @@ -174,7 +176,6 @@ name = "Wraith" real_name = "Wraith" desc = "A wicked bladed shell contraption piloted by a bound spirit" - icon = 'icons/mob/mob.dmi' icon_state = "floating" icon_living = "floating" maxHealth = 75 @@ -186,18 +187,16 @@ see_in_dark = 7 attack_sound = 'sound/weapons/bladeslice.ogg' construct_spells = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift) + playstyle_string = "You are a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls." /////////////////////////////Artificer///////////////////////// - - /mob/living/simple_animal/construct/builder name = "Artificer" real_name = "Artificer" desc = "A bulbous construct dedicated to building and maintaining The Cult of Nar-Sie's armies" - icon = 'icons/mob/mob.dmi' icon_state = "artificer" icon_living = "artificer" maxHealth = 50 @@ -215,60 +214,31 @@ /obj/effect/proc_holder/spell/aoe_turf/conjure/floor, /obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone, /obj/effect/proc_holder/spell/targeted/projectile/magic_missile/lesser) + playstyle_string = "You are an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, \ + use magic missile, repair allied constructs (by clicking on them), \ + and most important of all create new constructs \ + (Use your Artificer spell to summon a new construct shell and Summon Soulstone to create a new soulstone)." +/////////////////////////////Harvester///////////////////////// -/////////////////////////////Behemoth///////////////////////// +/mob/living/simple_animal/construct/harvester + name = "Harvester" + real_name = "Harvester" + desc = "A harbinger of Nar-Sie's enlightenment. It'll be all over soon." + icon_state = "harvester" + icon_living = "harvester" + maxHealth = 60 + health = 60 + melee_damage_lower = 1 + melee_damage_upper = 5 + attacktext = "prods" + speed = 0 + environment_smash = 1 + see_in_dark = 7 + attack_sound = 'sound/weapons/tap.ogg' + construct_spells = list(/obj/effect/proc_holder/spell/targeted/smoke/disable) + playstyle_string = "You are a Harvester. You are not strong, but your powers of domination will assist you in your role: \ + Bring those who still cling to this world of illusion back to the Geometer so they may know Truth." - -/mob/living/simple_animal/construct/behemoth - name = "Behemoth" - real_name = "Behemoth" - desc = "The pinnacle of occult technology, Behemoths are the ultimate weapon in the Cult of Nar-Sie's arsenal." - icon = 'icons/mob/mob.dmi' - icon_state = "behemoth" - icon_living = "behemoth" - maxHealth = 750 - health = 750 - speak_emote = list("rumbles") - response_harm = "harmlessly punches" - harm_intent_damage = 0 - melee_damage_lower = 50 - melee_damage_upper = 50 - attacktext = "brutally crushes" - speed = 5 - environment_smash = 2 - attack_sound = 'sound/weapons/punch4.ogg' - force_threshold = 11 - var/energy = 0 - var/max_energy = 1000 - - -////////////////Powers////////////////// - - -/* -/client/proc/summon_cultist() - set category = "Behemoth" - set name = "Summon Cultist (300)" - set desc = "Teleport a cultist to your location" - if (istype(usr,/mob/living/simple_animal/constructbehemoth)) - - if(usr.energy<300) - usr << "\red You do not have enough power stored!" - return - - if(usr.stat) - return - - usr.energy -= 300 - var/list/mob/living/cultists = new - for(var/datum/mind/H in ticker.mode.cult) - if (istype(H.current,/mob/living)) - cultists+=H.current - var/mob/cultist = input("Choose the one who you want to summon", "Followers of Geometer") as null|anything in (cultists - usr) - if(!cultist) - return - if (cultist == usr) //just to be sure. - return - cultist.loc = usr.loc - usr.visible_message("/red [cultist] appears in a flash of red light as [usr] glows with power")*/ +/mob/living/simple_animal/construct/harvester/Process_Spacemove(var/check_drift = 0) + return 1 \ No newline at end of file diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 03fb40fb3a9..087480c786c 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -473,20 +473,8 @@ if(!MP) return 0 //Sanity, this should never happen. -// if(ispath(MP, /mob/living/simple_animal/space_worm)) //Goodbye Space Worms 2014 -// return 0 //Unfinished. Very buggy, they seem to just spawn additional space worms everywhere and eating your own tail results in new worms spawning. - - if(ispath(MP, /mob/living/simple_animal/construct/behemoth)) - return 0 //I think this may have been an unfinished WiP or something. These constructs should really have their own class simple_animal/construct/subtype - - if(ispath(MP, /mob/living/simple_animal/construct/armoured)) - return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype - - if(ispath(MP, /mob/living/simple_animal/construct/wraith)) - return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype - - if(ispath(MP, /mob/living/simple_animal/construct/builder)) - return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype + if(ispath(MP, /mob/living/simple_animal/construct)) + return 0 //Verbs do not appear for players. //Good mobs! if(ispath(MP, /mob/living/simple_animal/cat)) diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index a0725f79ee5..ef84ff36073 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -1,10 +1,5 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 -var/global/list/uneatable = list( - /turf/space, - /obj/effect/overlay - ) - /obj/machinery/singularity name = "gravitational singularity" desc = "A gravitational singularity." @@ -32,6 +27,7 @@ var/global/list/uneatable = list( var/last_failed_movement = 0//Will not move in the same dir if it couldnt before, will help with the getting stuck on fields thing var/teleport_del = 0 var/last_warning + var/list/uneatable = list(/turf/space, /obj/effect/overlay) /obj/machinery/singularity/New(loc, var/starting_energy = 50, var/temp = 0) //CARN: admin-alert for chuckle-fuckery. @@ -477,6 +473,7 @@ var/global/list/uneatable = list( move_self = 1 //Do we move on our own? grav_pull = 5 //How many tiles out do we pull? consume_range = 6 //How many tiles out do we eat + uneatable = list(/turf/space, /obj/effect/overlay, /mob/living/simple_animal/construct) /obj/machinery/singularity/narsie/large name = "Nar-Sie" @@ -496,6 +493,11 @@ var/global/list/uneatable = list( if(emergency_shuttle) emergency_shuttle.incall(0.3) // Cannot recall + +/obj/machinery/singularity/narsie/large/attack_ghost(mob/dead/observer/user as mob) + makeNewConstruct(/mob/living/simple_animal/construct/harvester, user, null, 1) + + /obj/machinery/singularity/narsie/process() eat() if(!target || prob(5)) @@ -538,8 +540,11 @@ var/global/list/uneatable = list( if(istype(A,/mob/living/)) var/mob/living/C = A + if(C.client) + makeNewConstruct(/mob/living/simple_animal/construct/harvester, C, null, 1) C.spawn_dust() C.gib() + return if(isturf(A)) var/turf/T = A @@ -550,35 +555,33 @@ var/global/list/uneatable = list( if(prob(20)) T.ChangeTurf(/turf/simulated/wall/cult) return + /obj/machinery/singularity/narsie/ex_act() //No throwing bombs at it either. --NEO return + /obj/machinery/singularity/narsie/proc/pickcultist() //Narsie rewards his cultists with being devoured first, then picks a ghost to follow. --NEO var/list/cultists = list() - for(var/datum/mind/cult_nh_mind in ticker.mode.cult) - if(!cult_nh_mind.current) - continue - if(cult_nh_mind.current.stat) - continue - var/turf/pos = get_turf(cult_nh_mind.current) - if(pos.z != src.z) - continue - cultists += cult_nh_mind.current - if(cultists.len) - acquire(pick(cultists)) - return - //If there was living cultists, it picks one to follow. - for(var/mob/living/carbon/human/food in living_mob_list) - if(food.stat) - continue + var/list/noncultists = list() + for(var/mob/living/carbon/food in living_mob_list) //we don't care about constructs or cult-Ians or whatever. cult-monkeys are fair game i guess var/turf/pos = get_turf(food) if(pos.z != src.z) continue - cultists += food - if(cultists.len) - acquire(pick(cultists)) - return - //no living cultists, pick a living human instead. + + if(iscultist(food)) + cultists += food + else + noncultists += food + + if(cultists.len) //cultists get higher priority + acquire(pick(cultists)) + return + + if(noncultists.len) + acquire(pick(noncultists)) + return + + //no living humans, follow a ghost instead. for(var/mob/dead/observer/ghost in player_list) if(!ghost.client) continue @@ -589,7 +592,7 @@ var/global/list/uneatable = list( if(cultists.len) acquire(pick(cultists)) return - //no living humans, follow a ghost instead. + /obj/machinery/singularity/narsie/proc/acquire(var/mob/food) target << "\blue NAR-SIE HAS LOST INTEREST IN YOU" From d46a7831ce6e28760b7bbfa99ef0edd2257691a6 Mon Sep 17 00:00:00 2001 From: Cheridan Date: Wed, 11 Jun 2014 15:04:21 -0500 Subject: [PATCH 12/55] Update construct_spells.dm updated spell name/description --- code/datums/spells/construct_spells.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/datums/spells/construct_spells.dm b/code/datums/spells/construct_spells.dm index 3f1512bb4f5..7e4221f9a03 100644 --- a/code/datums/spells/construct_spells.dm +++ b/code/datums/spells/construct_spells.dm @@ -113,8 +113,8 @@ /obj/effect/proc_holder/spell/targeted/smoke/disable - name = "Disabling Smoke" - desc = "This spell spawns a cloud of disabling smoke." + name = "Paralysing Smoke" + desc = "This spell spawns a cloud of paralysing smoke." school = "conjuration" charge_max = 200 @@ -126,4 +126,4 @@ cooldown_min = 20 //25 deciseconds reduction per rank smoke_spread = 3 - smoke_amt = 10 \ No newline at end of file + smoke_amt = 10 From 9107668cec503ccb40bce192f5a59fe3281c4ace Mon Sep 17 00:00:00 2001 From: Giacomand Date: Wed, 11 Jun 2014 21:18:08 +0100 Subject: [PATCH 13/55] New configuration option for how many objectives traitors get, on top of their escape/hijack objective. Defaults to 2. --- code/controllers/configuration.dm | 3 +++ code/game/gamemodes/traitor/traitor.dm | 21 +++++++++++---------- config/game_options.txt | 4 ++++ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index a4c1fac1f53..b029d0b7390 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -77,6 +77,7 @@ var/traitor_scaling_coeff = 6 //how much does the amount of players get divided by to determine traitors var/changeling_scaling_coeff = 7 //how much does the amount of players get divided by to determine changelings + var/traitor_objectives_amount = 2 var/protect_roles_from_antagonist = 0// If security and such can be traitor/cult/other var/allow_latejoin_antagonists = 0 // If late-joining players can be traitor/changeling var/continuous_round_rev = 0 // Gamemodes which end instantly will instead keep on going until the round ends by escape shuttle or nuke. @@ -344,6 +345,8 @@ config.traitor_scaling_coeff = text2num(value) if("changeling_scaling_coeff") config.changeling_scaling_coeff = text2num(value) + if("traitor_objectives_amount") + config.traitor_objectives_amount = text2num(value) if("probability") var/prob_pos = findtext(value, " ") var/prob_name = null diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index 42d1fa7d398..2849e97d70b 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -116,16 +116,17 @@ assign_exchange_role(exchange_red,"red") assign_exchange_role(exchange_blue,"blue") else - if(prob(50)) - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = traitor - kill_objective.find_target() - traitor.objectives += kill_objective - else - var/datum/objective/steal/steal_objective = new - steal_objective.owner = traitor - steal_objective.find_target() - traitor.objectives += steal_objective + for(var/i = 0, i < config.traitor_objectives_amount, i++) + if(prob(50)) + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = traitor + kill_objective.find_target() + traitor.objectives += kill_objective + else + var/datum/objective/steal/steal_objective = new + steal_objective.owner = traitor + steal_objective.find_target() + traitor.objectives += steal_objective if(prob(90)) if (!(locate(/datum/objective/escape) in traitor.objectives)) diff --git a/config/game_options.txt b/config/game_options.txt index b9ca7e763ca..d01a6f3a8a9 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -114,6 +114,10 @@ SHUTTLE_REFUEL_DELAY 12000 TRAITOR_SCALING_COEFF 6 CHANGELING_SCALING_COEFF 7 +# The number of objectives traitors get. +# Not including escaping/hijacking. +TRAITOR_OBJECTIVES_AMOUNT 2 + ## Uncomment to prohibit jobs that start with loyalty ## implants from being most antagonists. #PROTECT_ROLES_FROM_ANTAGONIST From 698fde12f45466da5a89f005f0e89808bae4b956 Mon Sep 17 00:00:00 2001 From: Kelenius Date: Fri, 13 Jun 2014 01:01:10 +0400 Subject: [PATCH 14/55] Two small bugs... --- code/game/objects/items/stacks/sheets/glass.dm | 2 +- code/game/objects/structures/door_assembly.dm | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index c19167e2fee..1e3e9157602 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -39,7 +39,7 @@ new_tile.add_fingerprint(user) else if(istype(W, /obj/item/stack/rods)) var/obj/item/stack/rods/V = W - if (V.get_amount() > 1 && src.get_amount() > 1) + if (V.get_amount() >= 1 && src.get_amount() >= 1) var/obj/item/stack/sheet/rglass/RG = new (user.loc) RG.add_fingerprint(user) RG.add_to_stacks(user) diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index 09193785f88..e9cb8803220 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -517,11 +517,12 @@ obj/structure/door_assembly else if(istype(W, /obj/item/stack/sheet) && !mineral) var/obj/item/stack/sheet/G = W if(G) - if(G.amount>=1) + if(G.get_amount() >= 1) if(G.type == /obj/item/stack/sheet/rglass) playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) user.visible_message("[user] adds [G.name] to the airlock assembly.", "You start to install [G.name] into the airlock assembly.") if(do_after(user, 40)) + if(C.get_amount() < 1 || mineral) return user << "\blue You've installed reinforced glass windows into the airlock assembly." G.use(1) mineral = "glass" @@ -540,10 +541,11 @@ obj/structure/door_assembly glass_base_icon_state = "door_as_g[icontext]" else if(istype(G, /obj/item/stack/sheet/mineral)) var/M = G.sheettype - if(G.amount>=2) + if(G.get_amount() >= 2) playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) user.visible_message("[user] adds [G.name] to the airlock assembly.", "You start to install [G.name] into the airlock assembly.") if(do_after(user, 40)) + if(C.get_amount() < 2 || mineral) return user << "\blue You've installed [M] plating into the airlock assembly." G.use(2) mineral = "[M]" From 2f03f0fabd602cf19121de0e2748b3229b1ecf0d Mon Sep 17 00:00:00 2001 From: phil235 Date: Thu, 12 Jun 2014 23:06:42 +0200 Subject: [PATCH 15/55] Door Assembly exploit fix --- code/game/objects/structures/door_assembly.dm | 61 +++++++++++-------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index 553122c43fb..f447bc1f405 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -318,8 +318,10 @@ obj/structure/door_assembly /obj/structure/door_assembly/attackby(obj/item/W as obj, mob/user as mob) if(istype(W, /obj/item/weapon/pen)) var/t = copytext(stripped_input(user, "Enter the name for the door.", src.name, src.created_name),1,MAX_NAME_LEN) - if(!t) return - if(!in_range(src, usr) && src.loc != usr) return + if(!t) + return + if(!in_range(src, usr) && src.loc != usr) + return created_name = t return @@ -343,7 +345,8 @@ obj/structure/door_assembly icontype = input(user, "Please select a paintjob for this airlock.") in optionlist - if((!in_range(src, usr) && src.loc != usr) || !WT.use(user)) return + if((!in_range(src, usr) && src.loc != usr) || !WT.use(user)) + return var/has_solid = 0 var/has_glass = 0 switch(icontype) @@ -414,7 +417,7 @@ obj/structure/door_assembly if(mineral && mineral != "glass") mineral = null //I know this is stupid, but until we change glass to a boolean it's how this code works. - user << "\blue You change the paintjob on the airlock assembly." + user << " You change the paintjob on the airlock assembly." else if(istype(W, /obj/item/weapon/weldingtool) && !anchored ) var/obj/item/weapon/weldingtool/WT = W @@ -423,8 +426,9 @@ obj/structure/door_assembly playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) if(do_after(user, 40)) - if(!src || !WT.isOn()) return - user << "\blue You've dissasembled the airlock assembly." + if(!src || !WT.isOn()) + return + user << " You've disassembled the airlock assembly." new /obj/item/stack/sheet/metal(get_turf(src), 4) if (mineral) if (mineral == "glass") @@ -435,7 +439,7 @@ obj/structure/door_assembly new M(get_turf(src)) qdel(src) else - user << "\blue You need more welding fuel to dissassemble the airlock assembly." + user << " You need more welding fuel to dissassemble the airlock assembly." return else if(istype(W, /obj/item/weapon/wrench) && !anchored ) @@ -443,8 +447,9 @@ obj/structure/door_assembly user.visible_message("[user] secures the airlock assembly to the floor.", "You start to secure the airlock assembly to the floor.") if(do_after(user, 40)) - if(!src) return - user << "\blue You've secured the airlock assembly." + if(!src || src.anchored ) + return + user << " You've secured the airlock assembly." src.name = "secured airlock assembly" src.anchored = 1 @@ -452,8 +457,9 @@ obj/structure/door_assembly playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) user.visible_message("[user] unsecures the airlock assembly from the floor.", "You start to unsecure the airlock assembly from the floor.") if(do_after(user, 40)) - if(!src) return - user << "\blue You've unsecured the airlock assembly." + if(!src || !src.anchored ) + return + user << " You've unsecured the airlock assembly." src.name = "airlock assembly" src.anchored = 0 @@ -461,10 +467,11 @@ obj/structure/door_assembly var/obj/item/stack/cable_coil/coil = W user.visible_message("[user] wires the airlock assembly.", "You start to wire the airlock assembly.") if(do_after(user, 40)) - if(!src) return + if(!src) + return coil.use(1) src.state = 1 - user << "\blue You've wired the airlock assembly." + user << " You've wired the airlock assembly." src.name = "wired airlock assembly" else if(istype(W, /obj/item/weapon/wirecutters) && state == 1 ) @@ -472,8 +479,9 @@ obj/structure/door_assembly user.visible_message("[user] cuts the wires from the airlock assembly.", "You start to cut the wires from airlock assembly.") if(do_after(user, 40)) - if(!src) return - user << "\blue You've cut the wires from the airlock assembly." + if(!src || src.state != 1 ) + return + user << " You've cut the wires from the airlock assembly." new/obj/item/stack/cable_coil(get_turf(user), 1) src.state = 0 src.name = "secured airlock assembly" @@ -485,8 +493,9 @@ obj/structure/door_assembly W.loc = src if(do_after(user, 40)) - if(!src) return - user << "\blue You've installed the airlock electronics." + if(!src || src.state != 1 ) + return + user << " You've installed the airlock electronics." src.state = 2 src.name = "near finished airlock assembly" src.electronics = W @@ -500,8 +509,9 @@ obj/structure/door_assembly user.visible_message("[user] removes the electronics from the airlock assembly.", "You start to remove the electronics from the airlock assembly.") if(do_after(user, 40)) - if(!src) return - user << "\blue You've removed the airlock electronics." + if( !src || src.state != 2 ) + return + user << " You've removed the airlock electronics." src.state = 1 src.name = "wired airlock assembly" var/obj/item/weapon/airlock_electronics/ae @@ -519,7 +529,7 @@ obj/structure/door_assembly playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) user.visible_message("[user] adds [G.name] to the airlock assembly.", "You start to install [G.name] into the airlock assembly.") if(do_after(user, 40)) - user << "\blue You've installed reinforced glass windows into the airlock assembly." + user << " You've installed reinforced glass windows into the airlock assembly." G.use(1) mineral = "glass" name = "near finished window airlock assembly" @@ -541,7 +551,7 @@ obj/structure/door_assembly playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) user.visible_message("[user] adds [G.name] to the airlock assembly.", "You start to install [G.name] into the airlock assembly.") if(do_after(user, 40)) - user << "\blue You've installed [M] plating into the airlock assembly." + user << " You've installed [M] plating into the airlock assembly." G.use(2) mineral = "[M]" name = "near finished [M] airlock assembly" @@ -552,11 +562,12 @@ obj/structure/door_assembly else if(istype(W, /obj/item/weapon/screwdriver) && state == 2 ) playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) - user << "\blue You start finishing the airlock." + user.visible_message("[user] finishes the airlock.", "You start finishing the airlock.") if(do_after(user, 40)) - if(!src) return - user << "\blue You've finished the airlock." + if(!src) + return + user << " You've finished the airlock." var/obj/machinery/door/airlock/door if(mineral == "glass") door = new src.glass_type( src.loc ) @@ -580,4 +591,4 @@ obj/structure/door_assembly icon_state = "[base_icon_state][state]" //This updates the icon_state. They are named as "door_as1_eng" where the 1 in that example //represents what state it's in. So the most generic algorithm for the correct updating of - //this is simply to change the number. \ No newline at end of file + //this is simply to change the number. From 0b4387f031e647c2ce599a6f21c236f63928df7d Mon Sep 17 00:00:00 2001 From: Hornygranny Date: Thu, 12 Jun 2014 14:52:53 -0700 Subject: [PATCH 16/55] removes gravity failure event placeholder --- code/modules/admin/admin.dm | 1 - code/modules/admin/topic.dm | 7 ------- 2 files changed, 8 deletions(-) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index f08e6bffef1..7a7d7c45166 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -434,7 +434,6 @@ var/global/floorIsLava = 0 dat += {" 'Random' Events

- Trigger a gravity-failure event
Spawn a wave of meteors (aka lagocolyptic shower)
Spawn a vortex anomaly
Spawn a gravitational anomaly
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index f9fcfb99bf8..25510344edc 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1584,13 +1584,6 @@ usr.client.triple_ai() feedback_inc("admin_secrets_fun_used",1) feedback_add_details("admin_secrets_fun_used","TriAI") - if("gravity") - alert("WIP - event unavailable") -/* E = new /datum/round_event/weightless() - log_admin("[key_name(usr)] triggered a gravity-failure event.", 1) - message_admins("\blue [key_name_admin(usr)] triggered a gravity-failure event.", 1) - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","Grav") */ if("power") feedback_inc("admin_secrets_fun_used",1) feedback_add_details("admin_secrets_fun_used","P") From 8796e6e914ef6d7317d14f36a26dc14adc69aa25 Mon Sep 17 00:00:00 2001 From: Cheridan Date: Fri, 13 Jun 2014 08:48:14 -0500 Subject: [PATCH 17/55] Update singularity.dm smoke effect when ghosts arise as harvesters --- code/modules/power/singularity/singularity.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index ef84ff36073..3d2c161a28f 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -496,6 +496,7 @@ /obj/machinery/singularity/narsie/large/attack_ghost(mob/dead/observer/user as mob) makeNewConstruct(/mob/living/simple_animal/construct/harvester, user, null, 1) + new /obj/effect/effect/sleep_smoke(user.loc) /obj/machinery/singularity/narsie/process() From 5e082609aaf4f7b76a05b04840970653bcd911d3 Mon Sep 17 00:00:00 2001 From: Ikarrus Date: Fri, 13 Jun 2014 08:52:15 -0600 Subject: [PATCH 18/55] Update mecha.dm --- code/game/mecha/mecha.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 2ba407e28a2..d2342fa9188 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -934,7 +934,7 @@ /obj/mecha/MouseDrop_T(mob/M as mob, mob/user as mob) - if (!usr.canUseTopic(src) || (user != M)) + if (!user.canUseTopic(src) || (user != M)) return src.log_message("[user] tries to move in.") if (src.occupant) From 6d1bfb9244fbf43aa6ff018040d5484bc2f43b76 Mon Sep 17 00:00:00 2001 From: phil235 Date: Fri, 13 Jun 2014 19:38:15 +0200 Subject: [PATCH 19/55] removing !src checks --- code/game/objects/structures/door_assembly.dm | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index f447bc1f405..e6518e44186 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -426,7 +426,7 @@ obj/structure/door_assembly playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) if(do_after(user, 40)) - if(!src || !WT.isOn()) + if( !WT.isOn() ) return user << " You've disassembled the airlock assembly." new /obj/item/stack/sheet/metal(get_turf(src), 4) @@ -447,7 +447,7 @@ obj/structure/door_assembly user.visible_message("[user] secures the airlock assembly to the floor.", "You start to secure the airlock assembly to the floor.") if(do_after(user, 40)) - if(!src || src.anchored ) + if( src.anchored ) return user << " You've secured the airlock assembly." src.name = "secured airlock assembly" @@ -457,7 +457,7 @@ obj/structure/door_assembly playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) user.visible_message("[user] unsecures the airlock assembly from the floor.", "You start to unsecure the airlock assembly from the floor.") if(do_after(user, 40)) - if(!src || !src.anchored ) + if( !src.anchored ) return user << " You've unsecured the airlock assembly." src.name = "airlock assembly" @@ -467,8 +467,6 @@ obj/structure/door_assembly var/obj/item/stack/cable_coil/coil = W user.visible_message("[user] wires the airlock assembly.", "You start to wire the airlock assembly.") if(do_after(user, 40)) - if(!src) - return coil.use(1) src.state = 1 user << " You've wired the airlock assembly." @@ -479,7 +477,7 @@ obj/structure/door_assembly user.visible_message("[user] cuts the wires from the airlock assembly.", "You start to cut the wires from airlock assembly.") if(do_after(user, 40)) - if(!src || src.state != 1 ) + if( src.state != 1 ) return user << " You've cut the wires from the airlock assembly." new/obj/item/stack/cable_coil(get_turf(user), 1) @@ -493,7 +491,7 @@ obj/structure/door_assembly W.loc = src if(do_after(user, 40)) - if(!src || src.state != 1 ) + if( src.state != 1 ) return user << " You've installed the airlock electronics." src.state = 2 @@ -509,7 +507,7 @@ obj/structure/door_assembly user.visible_message("[user] removes the electronics from the airlock assembly.", "You start to remove the electronics from the airlock assembly.") if(do_after(user, 40)) - if( !src || src.state != 2 ) + if( src.state != 2 ) return user << " You've removed the airlock electronics." src.state = 1 @@ -565,8 +563,6 @@ obj/structure/door_assembly user.visible_message("[user] finishes the airlock.", "You start finishing the airlock.") if(do_after(user, 40)) - if(!src) - return user << " You've finished the airlock." var/obj/machinery/door/airlock/door if(mineral == "glass") From 1152a5b0993ffb22a7c356e5cd97c97a1d27c7de Mon Sep 17 00:00:00 2001 From: phil235 Date: Fri, 13 Jun 2014 20:03:59 +0200 Subject: [PATCH 20/55] attack message simple animals --- .../mob/living/simple_animal/simple_animal.dm | 48 ++++++++----------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index bf2a8a17afd..38916358259 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -245,8 +245,7 @@ return if(act) if(act == "scream") act = "makes a loud and pained whimper" //ugly hack to stop animals screaming when crushed :P - for (var/mob/O in viewers(src, null)) - O.show_message("[src] [act].") + visible_message("[src] [act].") /mob/living/simple_animal/attack_animal(mob/living/simple_animal/M as mob) @@ -255,8 +254,8 @@ else if(M.attack_sound) playsound(loc, M.attack_sound, 50, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message("\red \The [M] [M.attacktext] [src]!", 1) + visible_message("\The [M] [M.attacktext] [src]!", \ + "\The [M] [M.attacktext] [src]!") add_logs(M, src, "attacked", admin=0) var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) adjustBruteLoss(damage) @@ -276,9 +275,7 @@ if("help") if (health > 0) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message("\blue [M] [response_help] [src].") + visible_message(" [M] [response_help] [src].") if("grab") if (M == src || anchored) @@ -294,15 +291,11 @@ LAssailant = M - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has grabbed [] passively!", M, src), 1) + visible_message("[M] has grabbed [src] passively!") if("harm", "disarm") adjustBruteLoss(harm_intent_damage) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message("\red [M] [response_harm] [src]!") + visible_message("[M] [response_harm] [src]!") return @@ -312,9 +305,7 @@ if ("help") - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\blue [M] caresses [src] with its scythe like arm."), 1) + visible_message("[M] caresses [src] with its scythe like arm.") if ("grab") if(M == src || anchored) return @@ -329,13 +320,12 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has grabbed [] passively!", M, src), 1) + visible_message("[M] has grabbed [src] passively!") if("harm", "disarm") var/damage = rand(15, 30) - visible_message("\red [M] has slashed at [src]!") + visible_message("[M] has slashed at [src]!", \ + "[M] has slashed at [src]!") adjustBruteLoss(damage) return @@ -344,13 +334,14 @@ switch(L.a_intent) if("help") - visible_message("\blue [L] rubs it's head against [src]") + visible_message("[L] rubs its head against [src].") else var/damage = rand(5, 10) - visible_message("\red [L] bites [src]!") + visible_message("[L] bites [src]!", \ + "[L] bites [src]!") if(stat != DEAD) L.amount_grown = min(L.amount_grown + damage, L.max_grown) @@ -364,7 +355,8 @@ if(M.Victim) return // can't attack while eating! - visible_message("\red [M.name] glomps [src]!") + visible_message("[M.name] glomps [src]!", \ + "[M.name] glomps [src]!") var/damage = rand(1, 3) @@ -391,18 +383,16 @@ MED.amount -= 1 if(MED.amount <= 0) qdel(MED) - for(var/mob/M in viewers(src, null)) - if ((M.client && !( M.blinded ))) - M.show_message("\blue [user] applies [MED] on [src]") + visible_message(" [user] applies [MED] on [src].") return else - user << "\blue [MED] won't help at all." + user << " [MED] won't help at all." return else - user << "\blue [src] is at full health." + user << " [src] is at full health." return else - user << "\blue [src] is dead, medical items won't bring it back to life." + user << " [src] is dead, medical items won't bring it back to life." return else if(meat_type && (stat == DEAD)) //if the animal has a meat, and if it is dead. if(istype(O, /obj/item/weapon/kitchenknife) || istype(O, /obj/item/weapon/butch)) From 6817e93aebc44bb515783385eeaef3881e193981 Mon Sep 17 00:00:00 2001 From: phil235 Date: Fri, 13 Jun 2014 20:05:05 +0200 Subject: [PATCH 21/55] attack message monkey --- .../mob/living/carbon/monkey/monkey.dm | 83 ++++++++----------- 1 file changed, 35 insertions(+), 48 deletions(-) diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index d1f94f76d29..e7492ba5f1c 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -77,8 +77,8 @@ if ((M.a_intent == "harm" && !( istype(wear_mask, /obj/item/clothing/mask/muzzle) ))) if ((prob(75) && health > 0)) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - O.show_message("[M.name] bites [name]!", 1) + visible_message("[M.name] bites [name]!", \ + "[M.name] bites [name]!") var/damage = rand(1, 5) adjustBruteLoss(damage) health = 100 - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() @@ -86,8 +86,8 @@ if(istype(D, /datum/disease/jungle_fever)) contract_disease(D,1,0) else - for(var/mob/O in viewers(src, null)) - O.show_message("[M.name] has attempted to bite [name]!", 1) + visible_message("[M.name] has attempted to bite [name]!", \ + "[M.name] has attempted to bite [name]!") return /mob/living/carbon/monkey/attack_hand(mob/living/carbon/human/M as mob) @@ -108,9 +108,8 @@ else if (M.a_intent == "harm") if (prob(75)) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has punched [name]!", M), 1) + visible_message("[M] has punched [name]!", \ + "[M] has punched [name]!") playsound(loc, "punch", 25, 1, -1) var/damage = rand(5, 10) @@ -119,17 +118,15 @@ if ( (paralysis < 5) && (health > 0) ) Paralyse(rand(10, 15)) spawn( 0 ) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has knocked out [name]!", M), 1) + visible_message("[M] has knocked out [name]!", \ + "[M] has knocked out [name]!") return adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has attempted to punch [name]!", M), 1) + visible_message("[M] has attempted to punch [name]!", \ + "[M] has attempted to punch [name]!") else if (M.a_intent == "grab") if (M == src || anchored) @@ -144,22 +141,19 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - O.show_message(text("\red [] has grabbed [name] passively!", M), 1) + visible_message("[M] has grabbed [name] passively!") else if (!( paralysis )) if (prob(25)) Paralyse(2) playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has pushed down [name]!", M), 1) + visible_message("[M] has pushed down [src]!", \ + "[M] has pushed down [src]!") else if(drop_item()) playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has disarmed [name]!", M), 1) + visible_message("[M] has disarmed [src]!", \ + "[M] has disarmed [src]!") return /mob/living/carbon/monkey/attack_alien(mob/living/carbon/alien/humanoid/M as mob) @@ -173,9 +167,7 @@ switch(M.a_intent) if ("help") - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\blue [M] caresses [src] with its scythe like arm."), 1) + visible_message(" [M] caresses [src] with its scythe like arm.") if ("harm") if ((prob(95) && health > 0)) @@ -185,20 +177,17 @@ damage = rand(20, 40) if (paralysis < 15) Paralyse(rand(10, 15)) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has wounded [name]!", M), 1) + visible_message("[M] has wounded [name]!", \ + "[M] has wounded [name]!") else - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has slashed [name]!", M), 1) + visible_message("[M] has slashed [name]!", \ + "[M] has slashed [name]!") adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has attempted to lunge at [name]!", M), 1) + visible_message("[M] has attempted to lunge at [name]!", \ + "[M] has attempted to lunge at [name]!") if ("grab") if (M == src || anchored) @@ -212,22 +201,19 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - O.show_message(text("\red [] has grabbed [name] passively!", M), 1) + visible_message("[M] has grabbed [name] passively!") if ("disarm") playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) var/damage = 5 if(prob(95)) Weaken(10) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has tackled down [name]!", M), 1) + visible_message("[M] has tackled down [name]!", \ + "[M] has tackled down [name]!") else if(drop_item()) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has disarmed [name]!", M), 1) + visible_message("[M] has disarmed [name]!", \ + "[M] has disarmed [name]!") adjustBruteLoss(damage) updatehealth() return @@ -238,8 +224,8 @@ else if(M.attack_sound) playsound(loc, M.attack_sound, 50, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message("[M] [M.attacktext] [src]!", 1) + visible_message("[M] [M.attacktext] [src]!", \ + "[M] [M.attacktext] [src]!") add_logs(M, src, "attacked", admin=0) var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) adjustBruteLoss(damage) @@ -255,9 +241,8 @@ if (health > -100) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("The [M.name] glomps []!", src), 1) + visible_message("The [M.name] glomps [src]!", \ + "The [M.name] glomps [src]!") var/damage = rand(1, 3) @@ -285,7 +270,8 @@ if(M.powerlevel < 0) M.powerlevel = 0 - visible_message("[M] shocked [src]!", "[M] shocked [src]!") + visible_message("[M] shocked [src]!", \ + "[M] shocked [src]!") Weaken(power) if (stuttering < power) @@ -343,6 +329,7 @@ /mob/living/carbon/monkey/blob_act() if (stat != 2) + show_message("The blob attacks you!") adjustFireLoss(60) health = 100 - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() if (prob(50)) @@ -360,4 +347,4 @@ return 0 /mob/living/carbon/monkey/canBeHandcuffed() - return 1 + return 1 From 19a9bab445d16deede19ebd0f148fa9b3767af8e Mon Sep 17 00:00:00 2001 From: phil235 Date: Fri, 13 Jun 2014 20:06:03 +0200 Subject: [PATCH 22/55] attack message slime --- .../mob/living/carbon/metroid/metroid.dm | 88 +++++++------------ 1 file changed, 32 insertions(+), 56 deletions(-) diff --git a/code/modules/mob/living/carbon/metroid/metroid.dm b/code/modules/mob/living/carbon/metroid/metroid.dm index 3d1c6f8c70c..599f790d6b8 100644 --- a/code/modules/mob/living/carbon/metroid/metroid.dm +++ b/code/modules/mob/living/carbon/metroid/metroid.dm @@ -225,7 +225,7 @@ //paralysis += 1 - show_message(" The blob attacks you!") + show_message(" The blob attacks you!") adjustFireLoss(damage) @@ -237,7 +237,7 @@ return /mob/living/carbon/slime/attack_ui(slot) - return + return /mob/living/carbon/slime/attack_slime(mob/living/carbon/slime/M as mob) if (!ticker) @@ -248,10 +248,8 @@ if (health > -100) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" The [M.name] has glomped []!", src), 1) - + visible_message(" The [M.name] has glomped [src]!", \ + " The [M.name] has glomped [src]!") var/damage = rand(1, 3) attacked += 5 @@ -271,8 +269,8 @@ else if(M.attack_sound) playsound(loc, M.attack_sound, 50, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message(" [M] [M.attacktext] [src]!", 1) + visible_message("[M] [M.attacktext] [src]!", \ + "[M] [M.attacktext] [src]!") add_logs(M, src, "attacked", admin=0) var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) attacked += 10 @@ -303,9 +301,8 @@ if (health > 0) attacked += 10 //playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [M.name] has attacked [src]!"), 1) + visible_message("[M.name] has attacked [src]!", \ + "[M.name] has attacked [src]!") adjustBruteLoss(rand(1, 3)) updatehealth() return @@ -325,15 +322,11 @@ if(Victim) if(Victim == M) if(prob(60)) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(" [M] attempts to wrestle \the [name] off!", 1) + visible_message("[M] attempts to wrestle \the [name] off!") playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) else - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(" [M] manages to wrestle \the [name] off!", 1) + visible_message(" [M] manages to wrestle \the [name] off!") playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) if(prob(90) && !client) @@ -353,15 +346,11 @@ else if(prob(30)) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(" [M] attempts to wrestle \the [name] off of [Victim]!", 1) + visible_message("[M] attempts to wrestle \the [name] off of [Victim]!") playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) else - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(" [M] manages to wrestle \the [name] off of [Victim]!", 1) + visible_message(" [M] manages to wrestle \the [name] off of [Victim]!") playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) if(prob(80) && !client) @@ -400,9 +389,7 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has grabbed [] passively!", M, src), 1) + visible_message("[M] has grabbed [src] passively!") else @@ -426,17 +413,14 @@ playsound(loc, "punch", 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has punched []!", M, src), 1) + visible_message("[M] has punched [src]!", \ + "[M] has punched [src]!") adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has attempted to punch []!", M, src), 1) + visible_message("[M] has attempted to punch [src]!") return @@ -452,9 +436,7 @@ switch(M.a_intent) if ("help") - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\blue [M] caresses [src] with its scythe like arm."), 1) + visible_message("[M] caresses [src] with its scythe like arm.") if ("harm") @@ -464,20 +446,17 @@ var/damage = rand(15, 30) if (damage >= 25) damage = rand(20, 40) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has attacked [name]!", M), 1) + visible_message("[M] has attacked [name]!", \ + "[M] has attacked [name]!") else - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has wounded [name]!", M), 1) + visible_message("[M] has wounded [name]!", \ + ")[M] has wounded [name]!") adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has attempted to lunge at [name]!", M), 1) + visible_message("[M] has attempted to lunge at [name]!", \ + "[M] has attempted to lunge at [name]!") if ("grab") if (M == src || anchored) @@ -491,8 +470,7 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - O.show_message(text(" [] has grabbed [name] passively!", M), 1) + visible_message(" [M] has grabbed [name] passively!") if ("disarm") playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) @@ -500,9 +478,8 @@ attacked += 10 if(prob(95)) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has tackled [name]!", M), 1) + visible_message("[M] has tackled [name]!", \ + "[M] has tackled [name]!") if(Victim || Target) Victim = null @@ -527,9 +504,8 @@ else drop_item() - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has disarmed [name]!", M), 1) + visible_message("[M] has disarmed [name]!", + "[M] has disarmed [name]!") adjustBruteLoss(damage) updatehealth() return @@ -538,7 +514,7 @@ if(W.force > 0) attacked += 10 if(prob(25)) - user << "\red [W] passes right through [src]!" + user << "[W] passes right through [src]!" return if(Discipline && prob(50)) // wow, buddy, why am I getting attacked?? Discipline = 0 @@ -1047,9 +1023,9 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 /obj/item/weapon/reagent_containers/food/snacks/egg/slime/proc/Hatch() processing_objects.Remove(src) var/turf/T = get_turf(src) - src.visible_message("\blue The [name] pulsates and quivers!") + src.visible_message(" The [name] pulsates and quivers!") spawn(rand(50,100)) - src.visible_message("\blue The [name] bursts open!") + src.visible_message(" The [name] bursts open!") new/mob/living/carbon/slime(T) qdel(src) @@ -1065,4 +1041,4 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 return else ..() -*/ \ No newline at end of file +*/ From d825ae0f92e08c5343bf8cabdd68ea7279122e9b Mon Sep 17 00:00:00 2001 From: phil235 Date: Fri, 13 Jun 2014 20:07:28 +0200 Subject: [PATCH 23/55] attack message alien larva --- .../mob/living/carbon/alien/larva/larva.dm | 47 ++++++++----------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm index 12b3713d6df..303f19e9b45 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -101,7 +101,7 @@ //paralysis += 1 - show_message("\red The blob attacks you!") + show_message("The blob attacks you!") adjustFireLoss(damage) @@ -117,8 +117,8 @@ if(M.melee_damage_upper == 0) M.emote("[M.friendly] [src]") else - for(var/mob/O in viewers(src, null)) - O.show_message("\red [M] [M.attacktext] [src]!", 1) + visible_message("[M] [M.attacktext] [src]!", \ + "[M] [M.attacktext] [src]!") var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) adjustBruteLoss(damage) add_logs(M, src, "attacked", admin=0) @@ -146,9 +146,8 @@ return if (health > 0) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[M.name] bites [src]!"), 1) + visible_message("[M.name] bites [src]!", \ + "[M.name] bites [src]!") adjustBruteLoss(rand(1, 3)) updatehealth() return @@ -163,9 +162,8 @@ if (health > -100) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red The [M.name] glomps []!", src), 1) + visible_message("The [M.name] glomps [src]!", \ + "The [M.name] glomps [src]!") var/damage = rand(1, 3) @@ -209,9 +207,7 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has grabbed [] passively!", M, src), 1) + visible_message("[M] has grabbed [src] passively!") else var/damage = rand(1, 9) @@ -224,21 +220,19 @@ sleep(3) step_away(src,M,15) playsound(loc, "punch", 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has kicked []!", M, src), 1) + visible_message("[M] has kicked [src]!", \ + "[M] has kicked [src]!") if ((stat != DEAD) && (damage > 4.9)) Weaken(rand(5,10)) - for(var/mob/O in viewers(M, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has weakened []!", M, src), 1, "\red You hear someone fall.", 2) + visible_message("[M] has weakened [src]!", \ + "[M] has weakened [src]!", \ + "You hear someone fall.") adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has attempted to kick []!", M, src), 1) + visible_message("[M] has attempted to kick [src]!", \ + "[M] has attempted to kick [src]!") return /mob/living/carbon/alien/larva/attack_alien(mob/living/carbon/alien/humanoid/M as mob) @@ -260,21 +254,18 @@ AdjustParalysis(-3) AdjustStunned(-3) AdjustWeakened(-3) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\blue [M.name] nuzzles [] trying to wake it up!", src), 1) + visible_message("[M.name] nuzzles [src] trying to wake it up!") else if (health > 0) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) var/damage = rand(1, 3) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[M.name] bites []!", src), 1) + visible_message("[M.name] bites [src]!", \ + "[M.name] bites [src]!") adjustBruteLoss(damage) updatehealth() else - M << "\green [name] is too injured for that." + M << "[name] is too injured for that." return /mob/living/carbon/alien/larva/restrained() From 10ef6bf1b171f21863b470003e3210ed9e1f765e Mon Sep 17 00:00:00 2001 From: phil235 Date: Fri, 13 Jun 2014 20:08:27 +0200 Subject: [PATCH 24/55] attack message alien humanoid --- .../living/carbon/alien/humanoid/humanoid.dm | 67 +++++++------------ 1 file changed, 26 insertions(+), 41 deletions(-) diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm index ebe2a488d4f..b92d4c01cfd 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm @@ -94,7 +94,7 @@ if(shielded) damage /= 4 - show_message("\red The blob attacks!") + show_message("The blob attacks!") adjustFireLoss(damage) return @@ -120,9 +120,8 @@ return if (health > 0) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[M.name] bites [src]!"), 1) + visible_message("[M.name] bites [src]!", \ + "[M.name] bites [src]!") adjustBruteLoss(rand(1, 3)) updatehealth() return @@ -137,10 +136,8 @@ if (health > -100) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red The [M.name] glomps []!", src), 1) - + visible_message("The [M.name] glomps [src]!", \ + "The [M.name] glomps [src]!") var/damage = rand(1, 3) if(M.is_adult) @@ -167,9 +164,8 @@ if(M.powerlevel < 0) M.powerlevel = 0 - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red The [M.name] has shocked []!", src), 1) + visible_message("The [M.name] has shocked [src]!", \ + "The [M.name] has shocked [src]!") Weaken(power) if (stuttering < power) @@ -194,8 +190,8 @@ else if(M.attack_sound) playsound(loc, M.attack_sound, 50, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message("\red [M] [M.attacktext] [src]!", 1) + visible_message("[M] [M.attacktext] [src]!", \ + "[M] [M.attacktext] [src]!") var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) adjustBruteLoss(damage) updatehealth() @@ -229,9 +225,7 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has grabbed [] passively!", M, src), 1) + visible_message("[M] has grabbed [src] passively!") if ("harm") var/damage = rand(1, 9) @@ -244,42 +238,35 @@ sleep(3) step_away(src,M,15) playsound(loc, "punch", 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has punched []!", M, src), 1) + visible_message("[M] has punched [src]!", \ + "[M] has punched [src]!") if ((stat != DEAD) && (damage > 9||prob(5)))//Regular humans have a very small chance of weakening an alien. Weaken(1,5) - for(var/mob/O in viewers(M, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has weakened []!", M, src), 1, "\red You hear someone fall.", 2) + visible_message("[M] has weakened [src]!", \ + "[M] has weakened [src]!", \ + "You hear someone fall.") adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has attempted to punch []!", M, src), 1) + visible_message("[M] has attempted to punch [src]!") if ("disarm") if (!lying) if (prob(5))//Very small chance to push an alien down. Weaken(2) playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has pushed down []!", M, src), 1) + visible_message("[M] has pushed down [src]!", \ + "[M] has pushed down [src]!") else if (prob(50)) drop_item() playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has disarmed []!", M, src), 1) + visible_message("[M] has disarmed [src]!", \ + "[M] has disarmed [src]!") else playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has attempted to disarm []!", M, src), 1) + visible_message("[M] has attempted to disarm [src]!") return /*Code for aliens attacking aliens. Because aliens act on a hivemind, I don't see them as very aggressive with each other. @@ -306,21 +293,19 @@ In all, this is a lot like the monkey code. /N AdjustParalysis(-3) AdjustStunned(-3) AdjustWeakened(-3) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\blue [M.name] nuzzles [] trying to wake it up!", src), 1) + visible_message("[M.name] nuzzles [src] trying to wake it up!") else if (health > 0) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) var/damage = rand(1, 3) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[M.name] bites []!", src), 1) + visible_message("[M.name] bites [src]!!", \ + "[M.name] bites [src]!!") + adjustBruteLoss(damage) updatehealth() else - M << "\green [name] is too injured for that." + M << "[name] is too injured for that." return From 04d37171934712de9a3838f06d8e7f4924409d3c Mon Sep 17 00:00:00 2001 From: phil235 Date: Fri, 13 Jun 2014 20:12:16 +0200 Subject: [PATCH 25/55] attack message Human --- code/modules/mob/living/carbon/human/human.dm | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 7030742e370..765d8689bfd 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -51,12 +51,12 @@ for(var/mob/M in range(tmob, 1)) if( ((M.pulling == tmob && ( tmob.restrained() && !( M.restrained() ) && M.stat == 0)) || locate(/obj/item/weapon/grab, tmob.grabbed_by.len)) ) if ( !(world.time % 5) ) - src << "\red [tmob] is restrained, you cannot push past" + src << "[tmob] is restrained, you cannot push past." now_pushing = 0 return if( tmob.pulling == M && ( M.restrained() && !( tmob.restrained() ) && tmob.stat == 0) ) if ( !(world.time % 5) ) - src << "\red [tmob] is restraining [M], you cannot push past" + src << "[tmob] is restraining [M], you cannot push past." now_pushing = 0 return @@ -198,7 +198,7 @@ /mob/living/carbon/human/blob_act() if(stat == 2) return - show_message("\red The blob attacks you!") + show_message(" The blob attacks you!") var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg") var/obj/item/organ/limb/affecting = get_organ(ran_zone(dam_zone)) apply_damage(rand(20,30), BRUTE, affecting, run_armor_check(affecting, "melee")) @@ -211,8 +211,8 @@ else if(M.attack_sound) playsound(loc, M.attack_sound, 50, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message("\red [M] [M.attacktext] [src]!", 1) + visible_message("[M] [M.attacktext] [src]!", \ + "[M] [M.attacktext]!") add_logs(M, src, "attacked", admin=0) var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg") @@ -227,9 +227,8 @@ if (health > -100) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red The [M.name] glomps []!", src), 1) + visible_message("The [M.name] glomps [src]!", \ + "The [M.name] glomps [src]!") var/damage = rand(1, 3) @@ -262,10 +261,8 @@ M.powerlevel -= 3 if(M.powerlevel < 0) M.powerlevel = 0 - - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red The [M.name] has shocked []!", src), 1) + visible_message("The [M.name] has shocked [src]!", \ + "The [M.name] has shocked [src]!") Weaken(power) if (stuttering < power) @@ -467,7 +464,7 @@ H.handle_regular_hud_updates() if(!modified) - usr << "\red Unable to locate a data core entry for this person." + usr << "Unable to locate a data core entry for this person." /mob/living/carbon/human/proc/play_xylophone() if(!src.xylophone) @@ -516,4 +513,4 @@ if(obscured.len > 0) return obscured else - return null + return null From 44638fd05c35ae64946ebb7435c45d455ad7cd6d Mon Sep 17 00:00:00 2001 From: MrPerson Date: Fri, 13 Jun 2014 11:46:17 -0700 Subject: [PATCH 26/55] Add logging to failed GC's that result in a del() call You can view these logs in-game using a debug verb. You have to use the debug-verbs command to see it. Removed the dellogging compile option. If this is a problem, speak up, but for most users, this new functionality is more useful. --- code/_compile_options.dm | 12 ------------ code/controllers/garbage.dm | 4 ++++ code/modules/admin/verbs/debug.dm | 12 ++++++++++++ code/modules/admin/verbs/mapping.dm | 1 + code/world.dm | 9 --------- 5 files changed, 17 insertions(+), 21 deletions(-) diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 2949a7e70d7..22ca425a9e0 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -1,5 +1,4 @@ #define DEBUG //Enables byond profiling and full runtime logs - note, this may also be defined in your .dme file -//#define dellogging //Enables logging of forced del() calls (used for debugging) //#define TESTING //Enables in-depth debug messages to runtime log (used for debugging) //By using the testing("message") proc you can create debug-feedback for people with this //uncommented, but not visible in the release version) @@ -43,17 +42,6 @@ #define AI_CAMERA_LUMINOSITY 5 #define AI_VOX 1 // Comment out if you don't want VOX to be enabled and have players download the voice sounds. - -//Additional code for the above flags. -#ifdef dellogging -#warn compiling del logging. This will have additional overheads. //will warn you if compiling with dellogging -var/list/del_counter = list() -/proc/log_del(datum/X) - if(istype(X)){del_counter[X.type]++;} - del(X) -#define del(X) log_del(X) //overrides all del() calls with log_del() -#endif - #ifdef TESTING #warn compiling in TESTING mode. testing() debug messages will be visible. #endif diff --git a/code/controllers/garbage.dm b/code/controllers/garbage.dm index 53b1d8019a1..322bc086d89 100644 --- a/code/controllers/garbage.dm +++ b/code/controllers/garbage.dm @@ -11,6 +11,9 @@ var/datum/controller/garbage_collector/garbage = new() // refID's are associated with the time at which they time out and need to be manually del() // we do this so we aren't constantly locating them and preventing them from being gc'd + var/list/logging = list() // list of all types that have failed to GC associated with the number of times that's happened. + // the types are stored as strings + /datum/controller/garbage_collector/proc/AddTrash(var/datum/A) if(!istype(A) || !isnull(A.gc_destroyed)) return @@ -37,6 +40,7 @@ var/datum/controller/garbage_collector/garbage = new() if(A && A.gc_destroyed == GCd_at_time) // So if something else coincidently gets the same ref, it's not deleted by mistake // Something's still referring to the qdel'd object. Kill it. testing("GC: -- \ref[A] | [A.type] was unable to be GC'd and was deleted --") + logging["[A.type]"]++ del(A) dels++ // else diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 0be71e2376b..b206dfa347b 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -1137,3 +1137,15 @@ var/global/list/g_fancy_list_of_safe_types = null usr << list2text(clients,",") if("Joined Clients") usr << list2text(joined_player_list,",") + +/client/proc/cmd_display_del_log() + set category = "Debug" + set name = "Display del() Log" + set desc = "Displays a list of things that have failed to GC this round" + + var/dat = "List of things that failed to GC this round

" + + for(var/path in garbage.logging) + dat += "[path] - [garbage.logging[path]] times
" + + usr << browse(dat, "window=dellog") diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 8745247f96e..a567d4eaec6 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -148,6 +148,7 @@ var/intercom_range_display_status = 0 src.verbs += /client/proc/print_pointers src.verbs += /client/proc/count_movable_instances src.verbs += /client/proc/SDQL2_query + src.verbs += /client/proc/cmd_display_del_log //src.verbs += /client/proc/cmd_admin_rejuvenate feedback_add_details("admin_verb","mDV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/world.dm b/code/world.dm index 4d5f62ea91a..67e392d7c75 100644 --- a/code/world.dm +++ b/code/world.dm @@ -173,15 +173,6 @@ #undef CHAT_PULLR /world/Reboot(var/reason) -#ifdef dellogging - var/log = file("data/logs/del.log") - log << time2text(world.realtime) - //mergeSort(del_counter, /proc/cmp_descending_associative) //still testing the sorting procs. Use notepad++ to sort the resultant logfile for now. - for(var/index in del_counter) - var/count = del_counter[index] - if(count > 10) - log << "#[count]\t[index]" -#endif spawn(0) world << sound(pick('sound/AI/newroundsexy.ogg','sound/misc/apcdestroyed.ogg','sound/misc/bangindonk.ogg')) // random end sounds!! - LastyBatsy From 67ee39541b24575b0405e000c679146436c0dd46 Mon Sep 17 00:00:00 2001 From: Giacomand Date: Fri, 13 Jun 2014 21:04:54 +0100 Subject: [PATCH 27/55] Stops the objectives automatically giving you two of the same target. --- code/game/gamemodes/objective.dm | 36 +++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index f29f7b9d1d2..5007a845681 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -13,10 +13,19 @@ datum/objective/New(var/text) datum/objective/proc/check_completion() return completed +datum/objective/proc/is_unique_objective(possible_target) + for(var/datum/objective/assassinate/O in owner.objectives) + if(O.get_target() == possible_target) + return 0 + return 1 + +datum/objective/proc/get_target() + return target + datum/objective/proc/find_target() var/list/possible_targets = list() for(var/datum/mind/possible_target in ticker.minds) - if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != 2)) + if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != 2) && is_unique_objective(possible_target)) possible_targets += possible_target if(possible_targets.len > 0) target = pick(possible_targets) @@ -255,21 +264,32 @@ datum/objective/steal var/obj/item/steal_target = null //Needed for custom objectives (they're just items, not datums). dangerrating = 5 //Overridden by the individual item's difficulty, but defaults to 5 for custom objectives. +datum/objective/steal/get_target() + return steal_target + datum/objective/steal/New() ..() if(!possible_items.len)//Only need to fill the list when it's needed. init_subtypes(/datum/objective_item/steal,possible_items) datum/objective/steal/find_target() - return set_target(pick(possible_items)) + var/approved_targets = list() + for(var/datum/objective_item/possible_item in possible_items) + if(is_unique_objective(possible_item.targetitem)) + approved_targets += possible_item + return set_target(safepick(possible_items)) datum/objective/steal/proc/set_target(var/datum/objective_item/item) - targetinfo = item + if(item) + targetinfo = item - steal_target = targetinfo.targetitem - explanation_text = "Steal [targetinfo.name]." - dangerrating = targetinfo.difficulty - return steal_target + steal_target = targetinfo.targetitem + explanation_text = "Steal [targetinfo.name]." + dangerrating = targetinfo.difficulty + return steal_target + else + explanation_text = "Free objective" + return datum/objective/steal/proc/select_target() //For admins setting objectives manually. var/list/possible_items_all = possible_items+"custom" @@ -292,7 +312,7 @@ datum/objective/steal/proc/select_target() //For admins setting objectives manua return steal_target datum/objective/steal/check_completion() - if(!steal_target || !owner.current) return 0 + if(!steal_target) return 1 if(!isliving(owner.current)) return 0 var/list/all_items = owner.current.GetAllContents() //this should get things in cheesewheels, books, etc. From 71c71367fe53c033bca3a57bb4485c70a86d44e5 Mon Sep 17 00:00:00 2001 From: Menshin Date: Fri, 13 Jun 2014 22:17:30 +0200 Subject: [PATCH 28/55] Fixes energy weapons drawing charges on click even when no shot was fired (fixes #3910). --- code/modules/projectiles/guns/energy.dm | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 988d947a13e..fd063141789 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -33,20 +33,24 @@ /obj/item/weapon/gun/energy/afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, params) - newshot() + newshot() //prepare a new shot ..() /obj/item/weapon/gun/energy/proc/newshot() - if (!ammo_type || !power_supply) return + if (!ammo_type || !power_supply) + return var/obj/item/ammo_casing/energy/shot = ammo_type[select] - if (!power_supply.use(shot.e_cost)) return - chambered = shot - chambered.newshot() + if(power_supply.charge >= shot.e_cost) //if there's enough power in the power_supply cell... + chambered = shot //...prepare a new shot based on the current ammo type selected + chambered.newshot() return /obj/item/weapon/gun/energy/process_chamber() - chambered = null + if(chambered && !chambered.BB) //if BB is null, i.e the shot has been fired... + var/obj/item/ammo_casing/energy/shot = chambered + power_supply.use(shot.e_cost)//... drain the power_supply cell + chambered = null //either way, released the prepared shot return /obj/item/weapon/gun/energy/proc/select_fire(mob/living/user as mob) From c84f26a96d6d3f3e9a0ee3c5608c4606293ccd6b Mon Sep 17 00:00:00 2001 From: phil235 Date: Fri, 13 Jun 2014 22:36:36 +0200 Subject: [PATCH 29/55] Scanners messages fix --- code/game/objects/items/devices/scanners.dm | 98 ++++++++++----------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 996ce6ff0b1..d96eee665fe 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -78,16 +78,16 @@ MASS SPECTROMETER // Clumsiness/brain damage check if ((CLUMSY in user.mutations || user.getBrainLoss() >= 60) && prob(50)) - user << text("You stupidly try to analyze the floor's vitals!") - user.visible_message(text("[user] has analyzed the floor's vitals!")) - user.show_message(text("Analyzing Results for The floor:\n\t Overall Status: Healthy"), 1) - user.show_message(text("\t Damage Specifics: 0-0-0-0"), 1) + user << "You stupidly try to analyze the floor's vitals!" + user.visible_message("[user] has analyzed the floor's vitals!") + user.show_message("Analyzing Results for The floor:\n\t Overall Status: Healthy", 1) + user.show_message("\t Damage Specifics: 0-0-0-0", 1) user.show_message("Key: Suffocation/Toxin/Burn/Brute", 1) user.show_message("Body Temperature: ???", 1) return - user.visible_message(text("[] has analyzed []'s vitals!", user, M)) + user.visible_message("[user] has analyzed [M]'s vitals.") healthscan(user, M, mode) @@ -102,21 +102,21 @@ MASS SPECTROMETER var/tox_loss = M.getToxLoss() var/fire_loss = M.getFireLoss() var/brute_loss = M.getBruteLoss() - var/mob_status = (M.stat > 1 ? "Deceased" : text("[]% healthy", M.health)) + var/mob_status = (M.stat > 1 ? "Deceased" : "[M.health]% healthy") if(M.status_flags & FAKEDEATH) mob_status = "Deceased" oxy_loss = max(rand(1, 40), oxy_loss, (300 - (tox_loss + fire_loss + brute_loss))) // Random oxygen loss - user.show_message(text("Analyzing Results for []:\n\t Overall Status: []", M, mob_status), 1) - user.show_message(text("\t Damage Specifics: []-[]-[]-[]", oxy_loss, tox_loss, fire_loss, brute_loss), 1) + user.show_message("Analyzing Results for [M]:\n\t Overall Status: [mob_status]", 1) + user.show_message("\t Damage Specifics: [oxy_loss]-[tox_loss]-[fire_loss]-[brute_loss]", 1) user.show_message("Key: Suffocation/Toxin/Burn/Brute", 1) user.show_message("Body Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1) // Time of death if(M.tod && (M.stat == DEAD || (M.status_flags & FAKEDEATH))) - user.show_message("Time of Death: [M.tod]") + user.show_message("Time of Death: [M.tod]", 1) // Organ damage report if(istype(M, /mob/living/carbon/human) && mode == 1) @@ -131,26 +131,26 @@ MASS SPECTROMETER // Damage descriptions - user.show_message(text("[] | [] | [] | []", oxy_loss > 50 ? "\red Severe oxygen deprivation detected\blue" : "Subject bloodstream oxygen level normal", tox_loss > 50 ? "\red Dangerous amount of toxins detected\blue" : "Subject bloodstream toxin level minimal", fire_loss > 50 ? "\red Severe burn damage detected\blue" : "Subject burn injury status O.K", brute_loss > 50 ? "\red Severe anatomical damage detected\blue" : "Subject brute-force injury status O.K"), 1) + user.show_message(text("[] | [] | [] | []", oxy_loss > 50 ? " Severe oxygen deprivation detected" : "Subject bloodstream oxygen level normal", tox_loss > 50 ? " Dangerous amount of toxins detected" : "Subject bloodstream toxin level minimal", fire_loss > 50 ? " Severe burn damage detected" : "Subject burn injury status O.K", brute_loss > 50 ? " Severe anatomical damage detected" : "Subject brute-force injury status O.K"), 1) if(M.getStaminaLoss()) - user.show_message(text("Subject appears to be suffering from fatigue."), 1) + user.show_message("Subject appears to be suffering from fatigue.", 1) if (M.getCloneLoss()) - user.show_message(text("Subject appears to have been imperfectly cloned."), 1) + user.show_message("Subject appears to have been imperfectly cloned.", 1) for(var/datum/disease/D in M.viruses) if(!D.hidden[SCANNER]) - user.show_message(text("Warning: [D.form] Detected\nName: [D.name].\nType: [D.spread].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure]")) + user.show_message("Warning: [D.form] Detected\nName: [D.name].\nType: [D.spread].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure]", 1) if (M.reagents && M.reagents.get_reagent_amount("inaprovaline")) - user.show_message(text("Bloodstream Analysis located [M.reagents:get_reagent_amount("inaprovaline")] units of rejuvenation chemicals."), 1) + user.show_message("Bloodstream Analysis located [M.reagents:get_reagent_amount("inaprovaline")] units of rejuvenation chemicals.", 1) if (M.getBrainLoss() >= 100 || !M.getorgan(/obj/item/organ/brain)) - user.show_message(text("Subject brain function is non-existant."), 1) + user.show_message("Subject brain function is non-existant.", 1) else if (M.getBrainLoss() >= 60) - user.show_message(text("Severe brain damage detected. Subject likely to have mental retardation."), 1) + user.show_message("Severe brain damage detected. Subject likely to have mental retardation.", 1) else if (M.getBrainLoss() >= 10) - user.show_message(text("Significant brain damage detected. Subject may have had a concussion."), 1) + user.show_message("Significant brain damage detected. Subject may have had a concussion.", 1) /obj/item/device/healthanalyzer/verb/toggle_mode() set name = "Switch Verbosity" @@ -193,11 +193,11 @@ MASS SPECTROMETER var/pressure = environment.return_pressure() var/total_moles = environment.total_moles() - user.show_message("\blue Results:", 1) + user.show_message(" Results:", 1) if(abs(pressure - ONE_ATMOSPHERE) < 10) - user.show_message("\blue Pressure: [round(pressure,0.1)] kPa", 1) + user.show_message(" Pressure: [round(pressure,0.1)] kPa", 1) else - user.show_message("\red Pressure: [round(pressure,0.1)] kPa", 1) + user.show_message(" Pressure: [round(pressure,0.1)] kPa", 1) if(total_moles) var/o2_concentration = environment.oxygen/total_moles var/n2_concentration = environment.nitrogen/total_moles @@ -206,27 +206,27 @@ MASS SPECTROMETER var/unknown_concentration = 1-(o2_concentration+n2_concentration+co2_concentration+plasma_concentration) if(abs(n2_concentration - N2STANDARD) < 20) - user.show_message("\blue Nitrogen: [round(n2_concentration*100)]%", 1) + user.show_message(" Nitrogen: [round(n2_concentration*100)]%", 1) else - user.show_message("\red Nitrogen: [round(n2_concentration*100)]%", 1) + user.show_message(" Nitrogen: [round(n2_concentration*100)]%", 1) if(abs(o2_concentration - O2STANDARD) < 2) - user.show_message("\blue Oxygen: [round(o2_concentration*100)]%", 1) + user.show_message(" Oxygen: [round(o2_concentration*100)]%", 1) else - user.show_message("\red Oxygen: [round(o2_concentration*100)]%", 1) + user.show_message(" Oxygen: [round(o2_concentration*100)]%", 1) if(co2_concentration > 0.01) - user.show_message("\red CO2: [round(co2_concentration*100)]%", 1) + user.show_message(" CO2: [round(co2_concentration*100)]%", 1) else - user.show_message("\blue CO2: [round(co2_concentration*100)]%", 1) + user.show_message(" CO2: [round(co2_concentration*100)]%", 1) if(plasma_concentration > 0.01) - user.show_message("\red Plasma: [round(plasma_concentration*100)]%", 1) + user.show_message(" Plasma: [round(plasma_concentration*100)]%", 1) if(unknown_concentration > 0.01) - user.show_message("\red Unknown: [round(unknown_concentration*100)]%", 1) + user.show_message(" Unknown: [round(unknown_concentration*100)]%", 1) - user.show_message("\blue Temperature: [round(environment.temperature-T0C)]°C", 1) + user.show_message(" Temperature: [round(environment.temperature-T0C)]°C", 1) src.add_fingerprint(user) return @@ -262,17 +262,17 @@ MASS SPECTROMETER if (user.stat) return if (crit_fail) - user << "\red This device has critically failed and is no longer functional!" + user << " This device has critically failed and is no longer functional!" return if (!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") - user << "\red You don't have the dexterity to do this!" + user << " You don't have the dexterity to do this!" return if(reagents.total_volume) var/list/blood_traces = list() for(var/datum/reagent/R in reagents.reagent_list) if(R.id != "blood") reagents.clear_reagents() - user << "\red The sample was contaminated! Please insert another sample" + user.show_message(" The sample was contaminated! Please insert another sample.", 1) return else blood_traces = params2list(R.data["trace_chem"]) @@ -317,31 +317,31 @@ MASS SPECTROMETER /obj/item/device/slime_scanner/attack(mob/living/M as mob, mob/living/user as mob) if (!isslime(M)) - user << "This device can only scan slimes!" + user.show_message("This device can only scan slimes!", 1) return var/mob/living/carbon/slime/T = M - user.show_message("Slime scan results:") - user.show_message(text("[T.colour] [] slime", T.is_adult ? "adult" : "baby")) - user.show_message(text("Nutrition: [T.nutrition]/[]", T.get_max_nutrition())) + user.show_message("Slime scan results:", 1) + user.show_message(text("[T.colour] [] slime", T.is_adult ? "adult" : "baby"), 1) + user.show_message(text("Nutrition: [T.nutrition]/[]", T.get_max_nutrition()), 1) if (T.nutrition < T.get_starve_nutrition()) - user.show_message("Warning: slime is starving!") + user.show_message("Warning: slime is starving!", 1) else if (T.nutrition < T.get_hunger_nutrition()) - user.show_message("Warning: slime is hungry") - user.show_message("Electric change strength: [T.powerlevel]") - user.show_message("Health: [T.health]") + user.show_message("Warning: slime is hungry", 1) + user.show_message("Electric change strength: [T.powerlevel]", 1) + user.show_message("Health: [T.health]", 1) if (T.slime_mutation[4] == T.colour) - user.show_message("This slime does not evolve any further") + user.show_message("This slime does not evolve any further.", 1) else if (T.slime_mutation[3] == T.slime_mutation[4]) if (T.slime_mutation[2] == T.slime_mutation[1]) - user.show_message(text("Possible mutation: []", T.slime_mutation[3])) - user.show_message("Genetic destability: [T.mutation_chance/2]% chance of mutation on splitting") + user.show_message("Possible mutation: [T.slime_mutation[3]]", 1) + user.show_message("Genetic destability: [T.mutation_chance/2]% chance of mutation on splitting", 1) else - user.show_message(text("Possible mutations: [], [], [] (x2)", T.slime_mutation[1], T.slime_mutation[2], T.slime_mutation[3])) - user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting") + user.show_message("Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]] (x2)", 1) + user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting", 1) else - user.show_message(text("Possible mutations: [], [], [], []", T.slime_mutation[1], T.slime_mutation[2], T.slime_mutation[3], T.slime_mutation[4])) - user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting") + user.show_message("Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]], [T.slime_mutation[4]]", 1) + user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting", 1) if (T.cores > 1) - user.show_message("Anomalious slime core amount detected") - user.show_message("Growth progress: [T.amount_grown]/10") \ No newline at end of file + user.show_message("Anomalious slime core amount detected", 1) + user.show_message("Growth progress: [T.amount_grown]/10", 1) From 920975dd68fe64a08bce2804572277e1819afca9 Mon Sep 17 00:00:00 2001 From: phil235 Date: Fri, 13 Jun 2014 22:55:51 +0200 Subject: [PATCH 30/55] notice -> warning --- code/modules/reagents/reagent_containers.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index e23270bafc3..0f630190c1a 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -62,9 +62,9 @@ var/who = (isnull(user) || eater == user) ? "your" : "their" if(istype(cover, /obj/item/clothing/mask/)) - user << "You have to remove [who] mask first!" + user << "You have to remove [who] mask first!" else - user << "You have to remove [who] helmet first!" + user << "You have to remove [who] helmet first!" return 0 - return 1 \ No newline at end of file + return 1 From 3f1837d21df183212dce63b91dae5ac560075e00 Mon Sep 17 00:00:00 2001 From: Cheridan Date: Fri, 13 Jun 2014 23:01:28 -0500 Subject: [PATCH 31/55] Gives spells tablepass hurhurrrrhrurhurh lets make these things that act like projectiles but aren't at all hgluhbglbuhglbuhgbluhguhlgubhgblhhblgbh --- code/datums/spell.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/datums/spell.dm b/code/datums/spell.dm index 06bedadbd4d..f68552d77f6 100644 --- a/code/datums/spell.dm +++ b/code/datums/spell.dm @@ -8,6 +8,7 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin desc = "A wizard spell" panel = "Spells" anchored = 1 // Crap like fireball projectiles are proc_holders, this is needed so fireballs don't get blown back into your face via atmos etc. + pass_flags = PASSTABLE density = 0 opacity = 0 From f691c84983545e2abd837011df13d70ffa90bce7 Mon Sep 17 00:00:00 2001 From: Menshin Date: Sat, 14 Jun 2014 22:29:37 +0200 Subject: [PATCH 32/55] Span class. --- code/modules/projectiles/guns/energy.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index fd063141789..f1ee2f12a74 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -60,7 +60,7 @@ var/obj/item/ammo_casing/energy/shot = ammo_type[select] fire_sound = shot.fire_sound if (shot.select_name) - user << "\red [src] is now set to [shot.select_name]." + user << "[src] is now set to [shot.select_name]." update_icon() return From fa98cdcad487e21647ff58ddd594f1c516f78dd2 Mon Sep 17 00:00:00 2001 From: ikarrus Date: Sat, 14 Jun 2014 16:32:26 -0600 Subject: [PATCH 33/55] Improved wording on the shuttle tracing announcement To help remove some ambiguity of what it means. --- code/controllers/shuttle_controller.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/controllers/shuttle_controller.dm b/code/controllers/shuttle_controller.dm index 0858a70f7f1..6e1c9a0a078 100644 --- a/code/controllers/shuttle_controller.dm +++ b/code/controllers/shuttle_controller.dm @@ -73,7 +73,7 @@ datum/shuttle_controller last_call_loc = null if(recall_count == 2) - priority_announce("The emergency shuttle has been recalled.\n\nExcessive number of emergency shuttle calls detected. We will attempt to trace any further signals to their source. Results may be viewed on any communications console.", null, 'sound/AI/shuttlerecalled.ogg') + priority_announce("The emergency shuttle has been recalled.\n\nExcessive number of emergency shuttle calls detected. We will attempt to trace all future calls and recalls to their source. Tracing results can be viewed on any communications console.", null, 'sound/AI/shuttlerecalled.ogg') else priority_announce("The emergency shuttle has been recalled.", null, 'sound/AI/shuttlerecalled.ogg', "Priority") setdirection(-1) From 49b7ca26050444eb2a403c4ec1c73146c20a1b32 Mon Sep 17 00:00:00 2001 From: ikarrus Date: Sat, 14 Jun 2014 16:51:45 -0600 Subject: [PATCH 34/55] Updated the message on comms consoles --- code/game/machinery/computer/communications.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 4c5148c3dc8..7ab878e4c54 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -355,9 +355,9 @@ var/const/CALL_SHUTTLE_REASON_LENGTH = 12 if (src.authenticated) if(emergency_shuttle.recall_count > 1) if(emergency_shuttle.last_call_loc) - dat += "
Latest emergency signal trace attempt successful.
Last signal origin: [format_text(emergency_shuttle.last_call_loc.name)].
" + dat += "
Last emergency shuttle call/recall traced to: [format_text(emergency_shuttle.last_call_loc.name)].
" else - dat += "
Latest emergency signal trace attempt failed.
" + dat += "
Last emergency shuttle call/recall trace failed.
" dat += "Logged in as: [auth_id]" dat += "
\[ Log Out \]
" dat += "
General Functions" From 9da454ed5766915fd51764cfaf9417b92bdc2dad Mon Sep 17 00:00:00 2001 From: ikarrus Date: Sat, 14 Jun 2014 20:35:44 -0600 Subject: [PATCH 35/55] Changed Supply Status Display text from SUPPLY to CARGO So it fits inside the icon instead of clipping out of it --- code/game/machinery/status_display.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index 9f85aa337b6..ed0b5bf6e4a 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -109,7 +109,7 @@ index2 -= message2_len update_display(line1, line2) if(4) // supply shuttle timer - var/line1 = "SUPPLY" + var/line1 = "CARGO" var/line2 if(supply_shuttle.moving) line2 = get_supply_shuttle_timer() From 726b1dc28f215be3ee4abd604ac65593eece4187 Mon Sep 17 00:00:00 2001 From: ikarrus Date: Sat, 14 Jun 2014 22:05:15 -0600 Subject: [PATCH 36/55] The Select-Equipment admin verb now includes all jobs Useful for admins and coders alike. --- code/modules/admin/verbs/debug.dm | 32 ++++++++++++------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 0be71e2376b..ed21a87442c 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -619,7 +619,7 @@ var/global/list/g_fancy_list_of_safe_types = null //log_admin("[key_name(src)] has alienized [M.key].") var/list/dresspacks = list( "naked", - "assistant grey", + "as job...", "standard space gear", "tournament standard red", "tournament standard green", @@ -647,6 +647,12 @@ var/global/list/g_fancy_list_of_safe_types = null var/dresscode = input("Select dress for [M]", "Robust quick dress shop") as null|anything in dresspacks if (isnull(dresscode)) return + + var/datum/job/jobdatum + if (dresscode == "as job...") + var/jobname = input("Select job", "Robust quick dress shop") as null|anything in get_all_jobs() + jobdatum = job_master.GetJob(jobname) + feedback_add_details("admin_verb","SEQ") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! for (var/obj/item/I in M) if (istype(I, /obj/item/weapon/implant)) @@ -656,25 +662,10 @@ var/global/list/g_fancy_list_of_safe_types = null if ("naked") //do nothing - if ("assistant grey") - var/obj/item/weapon/storage/backpack/BPK = new/obj/item/weapon/storage/backpack(M) - new /obj/item/weapon/storage/box/survival(BPK) - M.equip_to_slot_or_del(BPK, slot_back,1) - M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) - M.equip_to_slot_or_del(new /obj/item/clothing/under/color/grey(M), slot_w_uniform) - M.equip_to_slot_or_del(new /obj/item/clothing/shoes/sneakers/black(M), slot_shoes) - - var/obj/item/weapon/card/id/W = new(M) - W.assignment = "Assistant" - W.registered_name = M.real_name - W.update_label() - M.equip_to_slot_or_del(W, slot_wear_id) - var/obj/item/device/pda/P = new(M) - P.owner = M.real_name - P.ownjob = "Assistant" - P.update_label() - M.equip_to_slot_or_del(P, slot_belt) - + if ("as job...") + if(jobdatum) + dresscode = "[jobdatum.title]" + jobdatum.equip(M) if ("standard space gear") M.equip_to_slot_or_del(new /obj/item/clothing/shoes/sneakers/black(M), slot_shoes) @@ -687,6 +678,7 @@ var/global/list/g_fancy_list_of_safe_types = null J.toggle() M.equip_to_slot_or_del(new /obj/item/clothing/mask/breath(M), slot_wear_mask) J.Topic(null, list("stat" = 1)) + if ("tournament standard red","tournament standard green") //we think stunning weapon is too overpowered to use it on tournaments. --rastaf0 if (dresscode=="tournament standard red") M.equip_to_slot_or_del(new /obj/item/clothing/under/color/red(M), slot_w_uniform) From 49390f9e4d26eef81cdc6fefb8ee95faaef0bb5f Mon Sep 17 00:00:00 2001 From: ikarrus Date: Sat, 14 Jun 2014 22:30:26 -0600 Subject: [PATCH 37/55] AIs are declared to world at round start -Roundstart and admin-transformed AIs are declared in the same way that Captains are when they sign up, after they rename themselves -IC built and admin-renamed AIs do not declare -Admin-renamed AIs will update their Eye name and PDAs properly -Flavoured up Captain declaration text --- code/__HELPERS/unsorted.dm | 14 +++++++++++++- code/game/jobs/job/captain.dm | 2 +- code/modules/mob/transform_procs.dm | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 5e8ceba95ba..82171d503bf 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -252,6 +252,15 @@ Turf and target are seperate in case you want to teleport some distance from a t if(isAI(src)) var/mob/living/silicon/ai/AI = src if(oldname != real_name) + if(AI.eyeobj) + AI.eyeobj.name = "[newname] (AI Eye)" + + // Set ai pda name + if(AI.aiPDA) + AI.aiPDA.owner = newname + AI.aiPDA.name = newname + " (" + AI.aiPDA.ownjob + ")" + + // Notify Cyborgs for(var/mob/living/silicon/robot/Slave in AI.connected_robots) Slave.show_laws() @@ -302,7 +311,7 @@ Turf and target are seperate in case you want to teleport some distance from a t //Generalised helper proc for letting mobs rename themselves. Used to be clname() and ainame() //Last modified by Carn -/mob/proc/rename_self(var/role, var/allow_numbers=0) +/mob/proc/rename_self(var/role, var/allow_numbers=0, var/announce_ai=0) spawn(0) var/oldname = real_name @@ -347,6 +356,9 @@ Turf and target are seperate in case you want to teleport some distance from a t for(var/mob/living/silicon/robot/Slave in A.connected_robots) Slave.show_laws() + if(announce_ai) + world << "AI unit [newname] online." + if(cmptext("cyborg",role)) if(isrobot(src)) var/mob/living/silicon/robot/A = src diff --git a/code/game/jobs/job/captain.dm b/code/game/jobs/job/captain.dm index 62b93744f17..bfa0a915c94 100644 --- a/code/game/jobs/job/captain.dm +++ b/code/game/jobs/job/captain.dm @@ -43,7 +43,7 @@ Captain L.imp_in = H L.implanted = 1 - world << "[H.real_name] is the captain!" + world << "Captain [H.real_name] on deck!" /datum/job/captain/get_access() return get_all_accesses() diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 03fb40fb3a9..d35b29060dc 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -257,7 +257,7 @@ O.job = "AI" - O.rename_self("ai",1) + O.rename_self("ai",1, 1) . = O qdel(src) return From 01407620db06871af94dbadb92ce114e3694a8ab Mon Sep 17 00:00:00 2001 From: ikarrus Date: Sat, 14 Jun 2014 22:35:15 -0600 Subject: [PATCH 38/55] Forgot a hunk --- code/__HELPERS/unsorted.dm | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 82171d503bf..eaa4359ef74 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -339,23 +339,7 @@ Turf and target are seperate in case you want to teleport some distance from a t if(cmptext("ai",role)) if(isAI(src)) - var/mob/living/silicon/ai/A = src oldname = null//don't bother with the records update crap - //world << "[newname] is the AI!" - //world << sound('sound/AI/newAI.ogg') - // Set eyeobj name - if(A.eyeobj) - A.eyeobj.name = "[newname] (AI Eye)" - - // Set ai pda name - if(A.aiPDA) - A.aiPDA.owner = newname - A.aiPDA.name = newname + " (" + A.aiPDA.ownjob + ")" - - // Notify Cyborgs - for(var/mob/living/silicon/robot/Slave in A.connected_robots) - Slave.show_laws() - if(announce_ai) world << "AI unit [newname] online." From f491080ae2e6ab8c7be4bb30b9657060170d33b3 Mon Sep 17 00:00:00 2001 From: phil235 Date: Sun, 15 Jun 2014 21:46:38 +0200 Subject: [PATCH 39/55] Adding return 1 to atoms_movable.dm --- code/game/atoms_movable.dm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 6d60e1c7835..22a06b41da6 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -127,7 +127,10 @@ //done throwing, either because it hit something or it finished moving src.throwing = 0 - if(isobj(src)) src.throw_impact(get_turf(src)) + if(isobj(src)) + src.throw_impact(get_turf(src)) + + return 1 //Overlays @@ -152,4 +155,4 @@ /atom/movable/overlay/attack_hand(a, b, c) if (src.master) return src.master.attack_hand(a, b, c) - return \ No newline at end of file + return From c7c16f9ac77623231e8d27a2608e66ebd39df534 Mon Sep 17 00:00:00 2001 From: ikarrus Date: Sun, 15 Jun 2014 18:24:47 -0600 Subject: [PATCH 40/55] New sound for forcing airlocks to open/close sound/machines/airlockforced.ogg --- code/game/machinery/doors/airlock.dm | 5 +++++ sound/machines/airlockforced.ogg | Bin 0 -> 22214 bytes 2 files changed, 5 insertions(+) create mode 100644 sound/machines/airlockforced.ogg diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index fe8e972b78a..e8d184b4b88 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1024,6 +1024,8 @@ About the new airlock wires panel: playsound(src.loc, 'sound/machines/airlock.ogg', 30, 1) if(src.closeOther != null && istype(src.closeOther, /obj/machinery/door/airlock/) && !src.closeOther.density) src.closeOther.close() + else + playsound(src.loc, 'sound/machines/airlockforced.ogg', 30, 1) if(autoclose && normalspeed) spawn(150) @@ -1060,6 +1062,9 @@ About the new airlock wires panel: playsound(src.loc, 'sound/items/bikehorn.ogg', 30, 1) else playsound(src.loc, 'sound/machines/airlock.ogg', 30, 1) + else + playsound(src.loc, 'sound/machines/airlockforced.ogg', 30, 1) + var/obj/structure/window/killthis = (locate(/obj/structure/window) in get_turf(src)) if(killthis) killthis.ex_act(2)//Smashin windows diff --git a/sound/machines/airlockforced.ogg b/sound/machines/airlockforced.ogg new file mode 100644 index 0000000000000000000000000000000000000000..c249fb21e70faee2cc121701c3ac3f104df5359b GIT binary patch literal 22214 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±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
q1{#pJdg&=d-;0pQdkI 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 Date: Sun, 15 Jun 2014 18:38:14 -0600 Subject: [PATCH 41/55] Removed AI declarations --- code/__HELPERS/unsorted.dm | 4 +--- code/modules/mob/transform_procs.dm | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index eaa4359ef74..979f8042173 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -311,7 +311,7 @@ Turf and target are seperate in case you want to teleport some distance from a t //Generalised helper proc for letting mobs rename themselves. Used to be clname() and ainame() //Last modified by Carn -/mob/proc/rename_self(var/role, var/allow_numbers=0, var/announce_ai=0) +/mob/proc/rename_self(var/role, var/allow_numbers=0) spawn(0) var/oldname = real_name @@ -340,8 +340,6 @@ Turf and target are seperate in case you want to teleport some distance from a t if(cmptext("ai",role)) if(isAI(src)) oldname = null//don't bother with the records update crap - if(announce_ai) - world << "AI unit [newname] online." if(cmptext("cyborg",role)) if(isrobot(src)) diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index d35b29060dc..03fb40fb3a9 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -257,7 +257,7 @@ O.job = "AI" - O.rename_self("ai",1, 1) + O.rename_self("ai",1) . = O qdel(src) return From 041ae1a015e9312188505248d3edf0e5536369d3 Mon Sep 17 00:00:00 2001 From: ikarrus Date: Sun, 15 Jun 2014 18:48:50 -0600 Subject: [PATCH 42/55] Trimmed the end a little bit --- sound/machines/airlockforced.ogg | Bin 22214 -> 16204 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/sound/machines/airlockforced.ogg b/sound/machines/airlockforced.ogg index c249fb21e70faee2cc121701c3ac3f104df5359b..8f46a89fe3202b2c04ce11d30a6829876838c021 100644 GIT binary patch delta 12180 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 Date: Mon, 16 Jun 2014 11:21:42 -0700 Subject: [PATCH 43/55] Per Aran's request, re-add dellogging --- code/_compile_options.dm | 11 +++++++++++ code/world.dm | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 22ca425a9e0..c6c1d29785f 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -1,4 +1,5 @@ #define DEBUG //Enables byond profiling and full runtime logs - note, this may also be defined in your .dme file +//#define dellogging //Enables logging of forced del() calls (used for debugging) //#define TESTING //Enables in-depth debug messages to runtime log (used for debugging) //By using the testing("message") proc you can create debug-feedback for people with this //uncommented, but not visible in the release version) @@ -42,6 +43,16 @@ #define AI_CAMERA_LUMINOSITY 5 #define AI_VOX 1 // Comment out if you don't want VOX to be enabled and have players download the voice sounds. +//Additional code for the above flags. +#ifdef dellogging +#warn compiling del logging. This will have additional overheads. //will warn you if compiling with dellogging +var/list/del_counter = list() +/proc/log_del(datum/X) + if(istype(X)){del_counter[X.type]++;} + del(X) +#define del(X) log_del(X) //overrides all del() calls with log_del() +#endif + #ifdef TESTING #warn compiling in TESTING mode. testing() debug messages will be visible. #endif diff --git a/code/world.dm b/code/world.dm index 67e392d7c75..4d5f62ea91a 100644 --- a/code/world.dm +++ b/code/world.dm @@ -173,6 +173,15 @@ #undef CHAT_PULLR /world/Reboot(var/reason) +#ifdef dellogging + var/log = file("data/logs/del.log") + log << time2text(world.realtime) + //mergeSort(del_counter, /proc/cmp_descending_associative) //still testing the sorting procs. Use notepad++ to sort the resultant logfile for now. + for(var/index in del_counter) + var/count = del_counter[index] + if(count > 10) + log << "#[count]\t[index]" +#endif spawn(0) world << sound(pick('sound/AI/newroundsexy.ogg','sound/misc/apcdestroyed.ogg','sound/misc/bangindonk.ogg')) // random end sounds!! - LastyBatsy From caef47f07527c67a427eac48396f222f5481eaae Mon Sep 17 00:00:00 2001 From: phil235 Date: Wed, 18 Jun 2014 20:59:03 +0200 Subject: [PATCH 44/55] removing the commented part --- code/game/objects/items/weapons/tanks/tanks.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 1cd70a97fe7..9c1e150c3e2 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -205,7 +205,6 @@ air_contents.react() pressure = air_contents.return_pressure() var/range = (pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE - //range = min(range, MAX_EX_LIGHT_RANGE) --- handled in explosion.dm and prevented tachyon detectors fromstating true blast var/turf/epicenter = get_turf(loc) //world << "\blue Exploding Pressure: [pressure] kPa, intensity: [range]" From cd4be00d3b2cfa76ec137970f3cf483b8ee84fe2 Mon Sep 17 00:00:00 2001 From: Kelenius Date: Thu, 19 Jun 2014 02:48:37 +0400 Subject: [PATCH 45/55] Fix --- code/game/objects/structures/door_assembly.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index 2a7ca416341..db202e16461 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -531,7 +531,7 @@ obj/structure/door_assembly playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) user.visible_message("[user] adds [G.name] to the airlock assembly.", "You start to install [G.name] into the airlock assembly.") if(do_after(user, 40)) - if(C.get_amount() < 1 || mineral) return + if(G.get_amount() < 1 || mineral) return user << "You've installed reinforced glass windows into the airlock assembly." G.use(1) mineral = "glass" @@ -554,7 +554,7 @@ obj/structure/door_assembly playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) user.visible_message("[user] adds [G.name] to the airlock assembly.", "You start to install [G.name] into the airlock assembly.") if(do_after(user, 40)) - if(C.get_amount() < 2 || mineral) return + if(G.get_amount() < 2 || mineral) return user << "You've installed [M] plating into the airlock assembly." G.use(2) mineral = "[M]" From 75a0eadb375332d1aec268e25382984f4f93b3c6 Mon Sep 17 00:00:00 2001 From: Miauw Date: Thu, 19 Jun 2014 19:00:10 +0200 Subject: [PATCH 46/55] Removes an unneeded unEquip(). --- code/modules/power/singularity/singularity.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 8ceae066f17..180053b72f2 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -235,7 +235,6 @@ var/global/list/uneatable = list( var/list/handlist = list(H.l_hand, H.r_hand) for(var/obj/item/hand in handlist) if(prob(current_size * 5) && hand.w_class >= 5 - sizes_to_number["[current_size]"] && H.unEquip(hand)) - H.unEquip(hand) step_towards(hand, src) H << "\The [src] pulls \the [hand] from your grip!" From 913b3061a0ce0fb44b472f47f94792c5b8c21687 Mon Sep 17 00:00:00 2001 From: Hornygranny Date: Thu, 19 Jun 2014 13:44:24 -0700 Subject: [PATCH 47/55] more obvious metaconfirmation from digital camo --- code/modules/mob/living/carbon/human/examine.dm | 2 +- code/modules/mob/living/carbon/monkey/examine.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index ea0cc16a2d5..f5cab1c04fb 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -253,7 +253,7 @@ msg += "[t_He] [t_has] a vacant, braindead stare...\n" if(digitalcamo) - msg += "[t_He] [t_is] repulsively uncanny!\n" + msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatanly inhuman manner.\n" if(istype(usr, /mob/living/carbon/human)) diff --git a/code/modules/mob/living/carbon/monkey/examine.dm b/code/modules/mob/living/carbon/monkey/examine.dm index fa16619e4d2..6fc0a1d4772 100644 --- a/code/modules/mob/living/carbon/monkey/examine.dm +++ b/code/modules/mob/living/carbon/monkey/examine.dm @@ -43,7 +43,7 @@ msg += "" if (src.digitalcamo) - msg += "It is repulsively uncanny!\n" + msg += "It is moving its body in an unnatural and blatantly unsimian manner.\n" msg += "*---------*" From 2aab5fa71c7826c430ef7061c4f35c14a2964944 Mon Sep 17 00:00:00 2001 From: CollenN Date: Thu, 19 Jun 2014 17:42:14 -0400 Subject: [PATCH 48/55] Finalizes Mutantrace Datum Update https://github.com/tgstation/-tg-station/pull/3609 Squashes the commits from the above pull request. Should hopefully be a lot less cluttered. --- code/__DEFINES/flags.dm | 17 +- code/__HELPERS/global_lists.dm | 9 + code/__HELPERS/mobs.dm | 6 +- code/__HELPERS/unsorted.dm | 24 +- code/controllers/configuration.dm | 3 + code/controllers/shuttle_controller.dm | 2 +- code/datums/datumvars.dm | 21 +- code/datums/diseases/transformation.dm | 9 +- code/datums/mind.dm | 15 +- code/datums/spell.dm | 6 + code/datums/spells/construct_spells.dm | 17 + code/game/atoms.dm | 6 +- code/game/atoms_movable.dm | 7 +- code/game/dna.dm | 29 +- .../gamemodes/changeling/powers/absorb.dm | 3 +- .../gamemodes/changeling/powers/tiny_prick.dm | 2 +- .../gamemodes/changeling/powers/transform.dm | 5 +- code/game/gamemodes/wizard/soulstone.dm | 69 +- code/game/jobs/job/captain.dm | 2 +- code/game/jobs/job/job.dm | 6 + code/game/machinery/bots/ed209bot.dm | 3 - code/game/machinery/bots/secbot.dm | 5 +- code/game/machinery/cloning.dm | 7 +- code/game/machinery/computer/cloning.dm | 11 +- .../game/machinery/computer/communications.dm | 4 +- code/game/machinery/doors/airlock.dm | 5 + code/game/machinery/status_display.dm | 2 +- code/game/machinery/teleporter.dm | 7 +- code/game/machinery/vending.dm | 2 +- code/game/objects/effects/effect_system.dm | 5 +- code/game/objects/items.dm | 2 + .../objects/items/devices/laserpointer.dm | 8 +- code/game/objects/items/devices/scanners.dm | 103 +- .../objects/items/weapons/cigs_lighters.dm | 95 +- .../objects/items/weapons/storage/boxes.dm | 28 +- .../objects/items/weapons/storage/fancy.dm | 25 + .../game/objects/items/weapons/tanks/tanks.dm | 8 +- code/game/objects/structures/door_assembly.dm | 57 +- code/modules/admin/admin.dm | 1 - code/modules/admin/topic.dm | 7 - .../awaymissions/mission_code/wildwest.dm | 16 +- code/modules/client/preferences.dm | 55 +- code/modules/client/preferences_savefile.dm | 16 +- code/modules/clothing/gloves/boxing.dm | 1 + code/modules/events/holiday/halloween.dm | 4 +- code/modules/hydroponics/hydroponics.dm | 2 +- .../living/carbon/alien/humanoid/humanoid.dm | 67 +- .../mob/living/carbon/alien/larva/larva.dm | 47 +- code/modules/mob/living/carbon/carbon.dm | 9 +- code/modules/mob/living/carbon/human/death.dm | 12 +- code/modules/mob/living/carbon/human/human.dm | 48 +- .../living/carbon/human/human_attackhand.dm | 158 +- .../mob/living/carbon/human/human_damage.dm | 58 +- .../mob/living/carbon/human/human_defense.dm | 138 +- .../mob/living/carbon/human/human_defines.dm | 2 +- .../mob/living/carbon/human/human_helpers.dm | 9 +- .../mob/living/carbon/human/human_movement.dm | 27 +- .../mob/living/carbon/human/inventory.dm | 296 ++-- code/modules/mob/living/carbon/human/life.dm | 599 +------- .../mob/living/carbon/human/mutantrace.dm | 22 + code/modules/mob/living/carbon/human/say.dm | 37 +- .../mob/living/carbon/human/species.dm | 1330 +++++++++++++++++ .../mob/living/carbon/human/species_types.dm | 177 +++ .../mob/living/carbon/human/update_icons.dm | 126 +- .../modules/mob/living/carbon/metroid/life.dm | 9 +- .../mob/living/carbon/metroid/metroid.dm | 116 +- .../mob/living/carbon/monkey/monkey.dm | 83 +- code/modules/mob/living/living.dm | 4 +- code/modules/mob/living/living_defense.dm | 2 + .../mob/living/simple_animal/constructs.dm | 92 +- .../living/simple_animal/hostile/hostile.dm | 5 + .../mob/living/simple_animal/simple_animal.dm | 48 +- code/modules/mob/mob_helpers.dm | 5 +- .../mob/new_player/preferences_setup.dm | 17 +- code/modules/mob/transform_procs.dm | 22 +- code/modules/power/gravitygenerator.dm | 10 +- code/modules/power/singularity/singularity.dm | 58 +- code/modules/projectiles/gun.dm | 4 +- code/modules/projectiles/guns/energy.dm | 18 +- code/modules/projectiles/projectile.dm | 1 + code/modules/projectiles/projectile/magic.dm | 8 +- .../modules/projectiles/projectile/special.dm | 39 +- code/modules/reagents/Chemistry-Holder.dm | 4 +- code/modules/reagents/Chemistry-Reagents.dm | 22 - code/modules/reagents/reagent_containers.dm | 6 +- .../reagents/reagent_containers/syringes.dm | 6 + config/game_options.txt | 8 +- icons/mob/human.dmi | Bin 66301 -> 65202 bytes icons/mob/human_face.dmi | Bin 30991 -> 31661 bytes icons/obj/cigarettes.dmi | Bin 2454 -> 4673 bytes sound/machines/airlockforced.ogg | Bin 0 -> 16204 bytes tgstation.dme | 2 + 92 files changed, 2638 insertions(+), 1850 deletions(-) create mode 100644 code/modules/mob/living/carbon/human/mutantrace.dm create mode 100644 code/modules/mob/living/carbon/human/species.dm create mode 100644 code/modules/mob/living/carbon/human/species_types.dm create mode 100644 sound/machines/airlockforced.ogg diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 3db6e30fa52..b86d5e613b5 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -46,4 +46,19 @@ #define PASSTABLE 1 #define PASSGLASS 2 #define PASSGRILLE 4 -#define PASSBLOB 8 \ No newline at end of file +#define PASSBLOB 8 + +//flags for species + +#define MUTCOLORS 1 +#define HAIR 2 +#define FACEHAIR 4 +#define EYECOLOR 8 +#define LIPS 16 +#define COLDRES 32 +#define HEATRES 64 +#define RADIMMUNE 128 +#define NOBREATH 256 +#define NOGUNS 512 +#define NOBLOOD 1024 +#define NOFIRE 2048 \ No newline at end of file diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 9ab0003633a..d7ecd960955 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -10,6 +10,15 @@ //underwear init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear, underwear_all, underwear_m, underwear_f) + //Species + for(var/spath in typesof(/datum/species)) + if(spath == /datum/species) + continue + var/datum/species/S = new spath() + if(S.roundstart) + roundstart_species[S.name] = S.type + species_list[S.id] = S.type + //Surgeries for(var/path in typesof(/datum/surgery)) if(path == /datum/surgery) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index b382bb1e678..6b53dcaa221 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -56,10 +56,8 @@ var/list/skin_tones = list( "african2" ) -var/list/mutant_races = list( - "human", - "lizard", - ) +var/global/list/species_list[0] +var/global/list/roundstart_species[0] proc/age2agedescription(age) switch(age) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 5e8ceba95ba..979f8042173 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -252,6 +252,15 @@ Turf and target are seperate in case you want to teleport some distance from a t if(isAI(src)) var/mob/living/silicon/ai/AI = src if(oldname != real_name) + if(AI.eyeobj) + AI.eyeobj.name = "[newname] (AI Eye)" + + // Set ai pda name + if(AI.aiPDA) + AI.aiPDA.owner = newname + AI.aiPDA.name = newname + " (" + AI.aiPDA.ownjob + ")" + + // Notify Cyborgs for(var/mob/living/silicon/robot/Slave in AI.connected_robots) Slave.show_laws() @@ -330,22 +339,7 @@ Turf and target are seperate in case you want to teleport some distance from a t if(cmptext("ai",role)) if(isAI(src)) - var/mob/living/silicon/ai/A = src oldname = null//don't bother with the records update crap - //world << "[newname] is the AI!" - //world << sound('sound/AI/newAI.ogg') - // Set eyeobj name - if(A.eyeobj) - A.eyeobj.name = "[newname] (AI Eye)" - - // Set ai pda name - if(A.aiPDA) - A.aiPDA.owner = newname - A.aiPDA.name = newname + " (" + A.aiPDA.ownjob + ")" - - // Notify Cyborgs - for(var/mob/living/silicon/robot/Slave in A.connected_robots) - Slave.show_laws() if(cmptext("cyborg",role)) if(isrobot(src)) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index a4c1fac1f53..892e781fb5e 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -85,6 +85,7 @@ var/shuttle_refuel_delay = 12000 var/show_game_type_odds = 0 //if set this allows players to see the odds of each roundtype on the get revision screen var/mutant_races = 0 //players can choose their mutant race before joining the game + var/mutant_colors = 0 var/alert_desc_green = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced." var/alert_desc_blue_upto = "The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible, random searches are permitted." @@ -385,6 +386,8 @@ config.default_laws = text2num(value) if("join_with_mutant_race") config.mutant_races = 1 + if("mutant_colors") + config.mutant_colors = 1 else diary << "Unknown setting in configuration: '[name]'" diff --git a/code/controllers/shuttle_controller.dm b/code/controllers/shuttle_controller.dm index 0858a70f7f1..6e1c9a0a078 100644 --- a/code/controllers/shuttle_controller.dm +++ b/code/controllers/shuttle_controller.dm @@ -73,7 +73,7 @@ datum/shuttle_controller last_call_loc = null if(recall_count == 2) - priority_announce("The emergency shuttle has been recalled.\n\nExcessive number of emergency shuttle calls detected. We will attempt to trace any further signals to their source. Results may be viewed on any communications console.", null, 'sound/AI/shuttlerecalled.ogg') + priority_announce("The emergency shuttle has been recalled.\n\nExcessive number of emergency shuttle calls detected. We will attempt to trace all future calls and recalls to their source. Tracing results can be viewed on any communications console.", null, 'sound/AI/shuttlerecalled.ogg') else priority_announce("The emergency shuttle has been recalled.", null, 'sound/AI/shuttlerecalled.ogg', "Priority") setdirection(-1) diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 4dba24ce357..831de1e8858 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -254,7 +254,7 @@ client body += "" if(ishuman(D)) body += "" - body += "" + body += "" body += "" body += "" body += "" @@ -786,25 +786,24 @@ client return holder.Topic(href, list("makeai"=href_list["makeai"])) - else if(href_list["setmutantrace"]) + else if(href_list["setspecies"]) if(!check_rights(R_SPAWN)) return - var/mob/living/carbon/human/H = locate(href_list["setmutantrace"]) + var/mob/living/carbon/human/H = locate(href_list["setspecies"]) if(!istype(H)) usr << "This can only be done to instances of type /mob/living/carbon/human" return - var/new_mutantrace = input("Please choose a new mutantrace","Mutantrace",null) as null|anything in list("NONE","golem","lizard","slime","plant","shadow", "fly", "skeleton") - switch(new_mutantrace) - if(null) return - if("NONE") new_mutantrace = "" + var/result = input(usr, "Please choose a new species","Species") as null|anything in species_list + if(!H) usr << "Mob doesn't exist anymore" return - if(H.dna) - H.dna.mutantrace = new_mutantrace - H.update_body() - H.update_hair() + + if(result) + var/newtype = species_list[result] + H.dna.species = new newtype() + H.regenerate_icons() else if(href_list["adjustDamage"] && href_list["mobToDamage"]) if(!check_rights(0)) return diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm index f1ee58534ec..8749abed60d 100644 --- a/code/datums/diseases/transformation.dm +++ b/code/datums/diseases/transformation.dm @@ -139,15 +139,14 @@ ..() switch(stage) if(1) - if(ishuman(affected_mob) && affected_mob.dna && affected_mob.dna.mutantrace == "slime") + if(ishuman(affected_mob) && affected_mob.dna && affected_mob.dna.species.id == "slime") stage = 5 if(3) if(ishuman(affected_mob)) var/mob/living/carbon/human/human = affected_mob - if(human.dna && !human.dna.mutantrace) - human.dna.mutantrace = "slime" - human.update_body() - + if(human.dna && human.dna.species.id != "slime") + human.dna.species = new /datum/species/slime() + human.update_icons() /datum/disease/transformation/corgi name = "The Barkening" diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 9b004722c96..1e2f7d20e0e 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -1172,19 +1172,8 @@ datum/mind ..() mind.assigned_role = "Shade" -/mob/living/simple_animal/construct/builder/mind_initialize() +/mob/living/simple_animal/construct/mind_initialize() ..() - mind.assigned_role = "Artificer" + mind.assigned_role = "[initial(name)]" mind.special_role = "Cultist" -/mob/living/simple_animal/construct/wraith/mind_initialize() - ..() - mind.assigned_role = "Wraith" - mind.special_role = "Cultist" - -/mob/living/simple_animal/construct/armoured/mind_initialize() - ..() - mind.assigned_role = "Juggernaut" - mind.special_role = "Cultist" - - diff --git a/code/datums/spell.dm b/code/datums/spell.dm index 06bedadbd4d..c792d2845cc 100644 --- a/code/datums/spell.dm +++ b/code/datums/spell.dm @@ -8,6 +8,7 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin desc = "A wizard spell" panel = "Spells" anchored = 1 // Crap like fireball projectiles are proc_holders, this is needed so fireballs don't get blown back into your face via atmos etc. + pass_flags = PASSTABLE density = 0 opacity = 0 @@ -191,6 +192,11 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin var/datum/effect/effect/system/bad_smoke_spread/smoke = new /datum/effect/effect/system/bad_smoke_spread() smoke.set_up(smoke_amt, 0, location, smoke_amt == 1 ? 15 : 0) // same here smoke.start() + else if(smoke_spread == 3) + var/datum/effect/effect/system/sleep_smoke_spread/smoke = new /datum/effect/effect/system/sleep_smoke_spread() + smoke.set_up(smoke_amt, 0, location, smoke_amt == 1 ? 15 : 0) // same here + smoke.start() + /obj/effect/proc_holder/spell/proc/cast(list/targets) return diff --git a/code/datums/spells/construct_spells.dm b/code/datums/spells/construct_spells.dm index ed3248d776a..7e4221f9a03 100644 --- a/code/datums/spells/construct_spells.dm +++ b/code/datums/spells/construct_spells.dm @@ -110,3 +110,20 @@ invocation_type = "none" proj_lifespan = 10 max_targets = 6 + + +/obj/effect/proc_holder/spell/targeted/smoke/disable + name = "Paralysing Smoke" + desc = "This spell spawns a cloud of paralysing smoke." + + school = "conjuration" + charge_max = 200 + clothes_req = 0 + invocation = "none" + invocation_type = "none" + range = -1 + include_user = 1 + cooldown_min = 20 //25 deciseconds reduction per rank + + smoke_spread = 3 + smoke_amt = 10 diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 718fe4db854..d8b0638b193 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -250,6 +250,10 @@ var/list/blood_splatter_icons = list() //returns 1 if made bloody, returns 0 otherwise /atom/proc/add_blood(mob/living/carbon/M) + if(ishuman(M) && M.dna) + var/mob/living/carbon/human/H = M + if(NOBLOOD in H.dna.species.specflags) + return 0 if(rejects_blood()) return 0 if(!istype(M)) @@ -270,7 +274,7 @@ var/list/blood_splatter_icons = list() //try to find a pre-processed blood-splatter. otherwise, make a new one var/index = blood_splatter_index() var/icon/blood_splatter_icon = blood_splatter_icons[index] - if(!blood_splatter_icon ) + if(!blood_splatter_icon) blood_splatter_icon = icon(initial(icon), initial(icon_state), , 1) //we only want to apply blood-splatters to the initial icon_state for each object blood_splatter_icon.Blend("#fff", ICON_ADD) //fills the icon_state with white (except where it's transparent) blood_splatter_icon.Blend(icon('icons/effects/blood.dmi', "itemblood"), ICON_MULTIPLY) //adds blood and the remaining white areas become transparant diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 6d60e1c7835..22a06b41da6 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -127,7 +127,10 @@ //done throwing, either because it hit something or it finished moving src.throwing = 0 - if(isobj(src)) src.throw_impact(get_turf(src)) + if(isobj(src)) + src.throw_impact(get_turf(src)) + + return 1 //Overlays @@ -152,4 +155,4 @@ /atom/movable/overlay/attack_hand(a, b, c) if (src.master) return src.master.attack_hand(a, b, c) - return \ No newline at end of file + return diff --git a/code/game/dna.dm b/code/game/dna.dm index d969e6bc1a1..35314862a41 100644 --- a/code/game/dna.dm +++ b/code/game/dna.dm @@ -20,7 +20,8 @@ var/struc_enzymes var/uni_identity var/blood_type - var/mutantrace = null //The type of mutant race the player is if applicable (i.e. potato-man) + var/datum/species/species = new /datum/species/human() //The type of mutant race the player is if applicable (i.e. potato-man) + var/mutant_color = "FFF" // What color you are if you have certain speciess var/real_name //Stores the real name of the person who originally got this dna datum. Used primarely for changelings, /datum/dna/proc/generate_uni_identity(mob/living/carbon/character) @@ -30,6 +31,8 @@ L[DNA_GENDER_BLOCK] = construct_block((character.gender!=MALE)+1, 2) if(istype(character, /mob/living/carbon/human)) var/mob/living/carbon/human/H = character + if(!H.dna.species) + H.dna.species = new /datum/species/human() L[DNA_HAIR_STYLE_BLOCK] = construct_block(hair_styles_list.Find(H.hair_style), hair_styles_list.len) L[DNA_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.hair_color) L[DNA_FACIAL_HAIR_STYLE_BLOCK] = construct_block(facial_hair_styles_list.Find(H.facial_hair_style), facial_hair_styles_list.len) @@ -62,11 +65,17 @@ . += repeat_string(DNA_UNIQUE_ENZYMES_LEN, "0") return . -/proc/hardset_dna(mob/living/carbon/owner, ui, se, real_name, mutantrace, blood_type) +/proc/hardset_dna(mob/living/carbon/owner, ui, se, real_name, blood_type, datum/species/mrace, mcolor) if(!istype(owner, /mob/living/carbon/monkey) && !istype(owner, /mob/living/carbon/human)) return if(!owner.dna) - create_dna(owner) + create_dna(owner, mrace) + + if(mrace) + owner.dna.species = new mrace() + + if(mcolor) + owner.dna.mutant_color = mcolor if(real_name) owner.real_name = real_name @@ -79,18 +88,13 @@ owner.dna.uni_identity = ui updateappearance(owner) - var/update_mutantrace = (mutantrace != owner.dna.mutantrace) - owner.dna.mutantrace = mutantrace - if(update_mutantrace && istype(owner, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = owner - H.update_body() - H.update_hair() - if(se) owner.dna.struc_enzymes = se domutcheck(owner) check_dna_integrity(owner) + + owner.regenerate_icons() return /proc/check_dna_integrity(mob/living/carbon/character) @@ -122,8 +126,9 @@ character.dna.unique_enzymes = character.dna.generate_unique_enzymes(character) return character.dna -/proc/create_dna(mob/living/carbon/C) //don't use this unless you're about to use hardset_dna or ready_dna +/proc/create_dna(mob/living/carbon/C, datum/species/S) //don't use this unless you're about to use hardset_dna or ready_dna C.dna = new /datum/dna() + if(S) C.dna.species = new S() // do not remove; this is here to prevent runtimes /////////////////////////// DNA DATUM @@ -981,7 +986,7 @@ proc/deconstruct_block(value, values, blocksize=DNA_BLOCK_SIZE) /datum/dna/proc/is_same_as(var/datum/dna/D) if(uni_identity == D.uni_identity && struc_enzymes == D.struc_enzymes && real_name == D.real_name) - if(mutantrace == D.mutantrace && blood_type == D.blood_type) + if(species == D.species && mutant_color == D.mutant_color && blood_type == D.blood_type) return 1 return 0 diff --git a/code/game/gamemodes/changeling/powers/absorb.dm b/code/game/gamemodes/changeling/powers/absorb.dm index 946ca14f8c4..bd1b910f90e 100644 --- a/code/game/gamemodes/changeling/powers/absorb.dm +++ b/code/game/gamemodes/changeling/powers/absorb.dm @@ -90,7 +90,8 @@ new_dna.uni_identity = T.dna.uni_identity new_dna.struc_enzymes = T.dna.struc_enzymes new_dna.real_name = T.dna.real_name - new_dna.mutantrace = T.dna.mutantrace + new_dna.species = T.dna.species + new_dna.mutant_color = T.dna.mutant_color new_dna.blood_type = T.dna.blood_type absorbed_dna |= new_dna //And add the target DNA to our absorbed list. absorbedcount++ //all that done, let's increment the objective counter. \ No newline at end of file diff --git a/code/game/gamemodes/changeling/powers/tiny_prick.dm b/code/game/gamemodes/changeling/powers/tiny_prick.dm index 17aae0b9b84..da147e0d128 100644 --- a/code/game/gamemodes/changeling/powers/tiny_prick.dm +++ b/code/game/gamemodes/changeling/powers/tiny_prick.dm @@ -88,7 +88,7 @@ var/datum/dna/NewDNA = selected_dna if(ismonkey(target)) user << "We stealthily sting [target.name]." - hardset_dna(target, NewDNA.uni_identity, NewDNA.struc_enzymes, NewDNA.real_name, NewDNA.mutantrace, NewDNA.blood_type) + hardset_dna(target, NewDNA.uni_identity, NewDNA.struc_enzymes, NewDNA.real_name, NewDNA.blood_type, NewDNA.species, NewDNA.mutant_color) updateappearance(target) feedback_add_details("changeling_powers","TS") return 1 diff --git a/code/game/gamemodes/changeling/powers/transform.dm b/code/game/gamemodes/changeling/powers/transform.dm index 612d7871abc..b6954ccf79c 100644 --- a/code/game/gamemodes/changeling/powers/transform.dm +++ b/code/game/gamemodes/changeling/powers/transform.dm @@ -8,16 +8,17 @@ max_genetic_damage = 3 //Change our DNA to that of somebody we've absorbed. -/obj/effect/proc_holder/changeling/transform/sting_action(var/mob/living/carbon/user) +/obj/effect/proc_holder/changeling/transform/sting_action(var/mob/living/carbon/human/user) var/datum/changeling/changeling = user.mind.changeling var/datum/dna/chosen_dna = changeling.select_dna("Select the target DNA: ", "Target DNA") if(!chosen_dna) return - user.dna = chosen_dna user.real_name = chosen_dna.real_name + user.dna.species = new chosen_dna.species.type(user) + user.dna.mutant_color = chosen_dna.mutant_color updateappearance(user) domutcheck(user, null) diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm index 2e7d0f8d0f2..3f40d34b6de 100644 --- a/code/game/gamemodes/wizard/soulstone.dm +++ b/code/game/gamemodes/wizard/soulstone.dm @@ -22,13 +22,6 @@ transfer_soul("VICTIM", M, user) return -/*/obj/item/device/soulstone/attack(mob/living/simple_animal/shade/M as mob, mob/user as mob)//APPARENTLY THEY NEED THEIR OWN SPECIAL SNOWFLAKE CODE IN THE LIVING ANIMAL DEFINES - if(!istype(M, /mob/living/simple_animal/shade))//If target is not a shade - return ..() - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to capture the soul of [M.name] ([M.ckey])") - - transfer_soul("SHADE", M, user) - return*/ ///////////////////Options for using captured souls/////////////////////////////////////// /obj/item/device/soulstone/attack_self(mob/user) @@ -46,8 +39,6 @@ return - - /obj/item/device/soulstone/Topic(href, href_list) var/mob/U = usr if (!in_range(src, U)||U.machine!=src) @@ -160,53 +151,35 @@ var/construct_class = alert(U, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer") switch(construct_class) if("Juggernaut") - var/mob/living/simple_animal/construct/armoured/Z = new /mob/living/simple_animal/construct/armoured (get_turf(T.loc)) - Z.key = A.key - if(iscultist(U)) - if(ticker.mode.name == "cult") - ticker.mode:add_cultist(Z.mind) - else - ticker.mode.cult+=Z.mind - ticker.mode.update_cult_icons_added(Z.mind) - qdel(T) - Z << "You are a Juggernaut. Though slow, your shell can withstand extreme punishment, create shield walls and even deflect energy weapons, and rip apart enemies and walls alike." - Z << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." - Z.cancel_camera() - qdel(C) + makeNewConstruct(/mob/living/simple_animal/construct/armoured, T, U) if("Wraith") - var/mob/living/simple_animal/construct/wraith/Z = new /mob/living/simple_animal/construct/wraith (get_turf(T.loc)) - Z.key = A.key - if(iscultist(U)) - if(ticker.mode.name == "cult") - ticker.mode:add_cultist(Z.mind) - else - ticker.mode.cult+=Z.mind - ticker.mode.update_cult_icons_added(Z.mind) - qdel(T) - Z << "You are a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls." - Z << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." - Z.cancel_camera() - qdel(C) + makeNewConstruct(/mob/living/simple_animal/construct/wraith, T, U) if("Artificer") - var/mob/living/simple_animal/construct/builder/Z = new /mob/living/simple_animal/construct/builder (get_turf(T.loc)) - Z.key = A.key - if(iscultist(U)) - if(ticker.mode.name == "cult") - ticker.mode:add_cultist(Z.mind) - else - ticker.mode.cult+=Z.mind - ticker.mode.update_cult_icons_added(Z.mind) - qdel(T) - Z << "You are an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, use magic missile, repair allied constructs (by clicking on them), and most important of all create new constructs (Use your Artificer spell to summon a new construct shell and Summon Soulstone to create a new soulstone)." - Z << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." - Z.cancel_camera() - qdel(C) + makeNewConstruct(/mob/living/simple_animal/construct/builder, T, U) + + qdel(T) + qdel(C) else U << "Creation failed!: The soul stone is empty! Go kill someone!" return + +proc/makeNewConstruct(var/mob/living/simple_animal/construct/ctype, var/mob/target, var/mob/stoner = null, cultoverride = 0) + var/mob/living/simple_animal/construct/newstruct = new ctype(get_turf(target)) + newstruct.key = target.key + if(stoner && iscultist(stoner) || cultoverride) + if(ticker.mode.name == "cult") + ticker.mode:add_cultist(newstruct.mind) + else + ticker.mode.cult+=newstruct.mind + ticker.mode.update_cult_icons_added(newstruct.mind) + newstruct << newstruct.playstyle_string + newstruct << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." + newstruct.cancel_camera() + + /obj/item/device/soulstone/proc/init_shade(var/obj/item/device/soulstone/C, var/mob/living/carbon/human/T, var/mob/U as mob, var/vic = 0) new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton T.invisibility = 101 diff --git a/code/game/jobs/job/captain.dm b/code/game/jobs/job/captain.dm index 62b93744f17..bfa0a915c94 100644 --- a/code/game/jobs/job/captain.dm +++ b/code/game/jobs/job/captain.dm @@ -43,7 +43,7 @@ Captain L.imp_in = H L.implanted = 1 - world << "[H.real_name] is the captain!" + world << "Captain [H.real_name] on deck!" /datum/job/captain/get_access() return get_all_accesses() diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index 460b9fbeaa5..93c43bd653d 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -74,8 +74,14 @@ equip_backpack(H) //Equip the rest of the gear + if(H.dna) + H.dna.species.before_equip_job(src, H) + equip_items(H) + if(H.dna) + H.dna.species.after_equip_job(src, H) + //Equip ID var/obj/item/weapon/card/id/C = new default_id(H) C.access = get_access() diff --git a/code/game/machinery/bots/ed209bot.dm b/code/game/machinery/bots/ed209bot.dm index 5cb9d67a849..9c18fef3d9a 100644 --- a/code/game/machinery/bots/ed209bot.dm +++ b/code/game/machinery/bots/ed209bot.dm @@ -698,9 +698,6 @@ Auto Patrol: []"}, if(istype(perp:wear_suit, /obj/item/clothing/suit/wizrobe)) threatcount += 2 - if(perp.dna && perp.dna.mutantrace && perp.dna.mutantrace != "none") - threatcount += 2 - //Agent cards lower threatlevel when normal idchecking is off. if((perp.wear_id && istype(perp:wear_id.GetID(), /obj/item/weapon/card/id/syndicate)) && src.idcheck) threatcount -= 2 diff --git a/code/game/machinery/bots/secbot.dm b/code/game/machinery/bots/secbot.dm index e14f870ce67..7d1b29986d9 100644 --- a/code/game/machinery/bots/secbot.dm +++ b/code/game/machinery/bots/secbot.dm @@ -630,9 +630,6 @@ Auto Patrol: []"}, if(istype(humanperp.head, /obj/item/clothing/head/wizard) || istype(humanperp.head, /obj/item/clothing/head/helmet/space/rig/wizard)) threatcount += 2 - if(humanperp.dna && humanperp.dna.mutantrace && humanperp.dna.mutantrace != "none") - threatcount += 2 - //Agent cards lower threatlevel. if(humanperp.wear_id && istype(humanperp.wear_id.GetID(), /obj/item/weapon/card/id/syndicate)) threatcount -= 2 @@ -789,4 +786,4 @@ Auto Patrol: []"}, overlays -= "hs_arm" new /obj/item/robot_parts/l_arm(get_turf(src)) user << "You remove the robot arm from [src]." - build_step-- \ No newline at end of file + build_step-- diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 16437db55e0..ec9da16ba30 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -123,7 +123,7 @@ //Clonepod //Start growing a human clone in the pod! -/obj/machinery/clonepod/proc/growclone(var/ckey, var/clonename, var/ui, var/se, var/mindref, var/mrace) +/obj/machinery/clonepod/proc/growclone(var/ckey, var/clonename, var/ui, var/se, var/mindref, var/datum/species/mrace, var/mcolor) if(panel_open) return 0 if(mess || attempting) @@ -188,7 +188,8 @@ // -- End mode specific stuff - hardset_dna(H, ui, se, null, mrace) + hardset_dna(H, ui, se, null, null, mrace, mcolor) + if(efficiency > 2) for(var/A in bad_se_blocks) setblock(H.dna.struc_enzymes, A, construct_block(0,2)) @@ -203,6 +204,8 @@ H.facial_hair_style = "Shaved" H.hair_style = pick("Bedhead", "Bedhead 2", "Bedhead 3") + H.regenerate_icons() + H.suiciding = 0 src.attempting = 0 return 1 diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index 47f4870e719..f4e41af1fd2 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -34,7 +34,7 @@ if(!(pod1.occupant || pod1.mess) && (pod1.efficiency > 5)) for(var/datum/data/record/R in records) if(!(pod1.occupant || pod1.mess)) - if(pod1.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"])) + if(pod1.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"], R.fields["mcolor"])) records -= R /obj/machinery/computer/cloning/proc/updatemodules() @@ -328,7 +328,7 @@ temp = "Clonepod malfunction." else if(!config.revival_cloning) temp = "Unable to initiate cloning cycle." - else if(pod1.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"])) + else if(pod1.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["mcolor"])) temp = "[C.fields["name"]] => Cloning cycle in progress..." records.Remove(C) if(active_record == C) @@ -368,10 +368,10 @@ return var/datum/data/record/R = new() - if(subject.dna) - R.fields["mrace"] = subject.dna.mutantrace + if(subject.dna.species) + R.fields["mrace"] = subject.dna.species.type else - R.fields["mrace"] = null + R.fields["mrace"] = /datum/species/human R.fields["ckey"] = subject.ckey R.fields["name"] = subject.real_name R.fields["id"] = copytext(md5(subject.real_name), 2, 6) @@ -379,6 +379,7 @@ R.fields["UI"] = subject.dna.uni_identity R.fields["SE"] = subject.dna.struc_enzymes R.fields["blood_type"] = subject.dna.blood_type + R.fields["mcolor"] = subject.dna.mutant_color //Add an implant if needed var/obj/item/weapon/implant/health/imp = locate(/obj/item/weapon/implant/health, subject) diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 4c5148c3dc8..7ab878e4c54 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -355,9 +355,9 @@ var/const/CALL_SHUTTLE_REASON_LENGTH = 12 if (src.authenticated) if(emergency_shuttle.recall_count > 1) if(emergency_shuttle.last_call_loc) - dat += "
Latest emergency signal trace attempt successful.
Last signal origin: [format_text(emergency_shuttle.last_call_loc.name)].
" + dat += "
Last emergency shuttle call/recall traced to: [format_text(emergency_shuttle.last_call_loc.name)].
" else - dat += "
Latest emergency signal trace attempt failed.
" + dat += "
Last emergency shuttle call/recall trace failed.
" dat += "Logged in as: [auth_id]" dat += "
\[
Log Out \]
" dat += "
General Functions" diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index fe8e972b78a..e8d184b4b88 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1024,6 +1024,8 @@ About the new airlock wires panel: playsound(src.loc, 'sound/machines/airlock.ogg', 30, 1) if(src.closeOther != null && istype(src.closeOther, /obj/machinery/door/airlock/) && !src.closeOther.density) src.closeOther.close() + else + playsound(src.loc, 'sound/machines/airlockforced.ogg', 30, 1) if(autoclose && normalspeed) spawn(150) @@ -1060,6 +1062,9 @@ About the new airlock wires panel: playsound(src.loc, 'sound/items/bikehorn.ogg', 30, 1) else playsound(src.loc, 'sound/machines/airlock.ogg', 30, 1) + else + playsound(src.loc, 'sound/machines/airlockforced.ogg', 30, 1) + var/obj/structure/window/killthis = (locate(/obj/structure/window) in get_turf(src)) if(killthis) killthis.ex_act(2)//Smashin windows diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index 9f85aa337b6..ed0b5bf6e4a 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -109,7 +109,7 @@ index2 -= message2_len update_display(line1, line2) if(4) // supply shuttle timer - var/line1 = "SUPPLY" + var/line1 = "CARGO" var/line2 if(supply_shuttle.moving) line2 = get_supply_shuttle_timer() diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index b2386d2b4f4..df07d30f159 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -247,11 +247,10 @@ if(prob(30 - (accurate * 10))) //oh dear a problem if(ishuman(M))//don't remove people from the round randomly you jerks var/mob/living/carbon/human/human = M - if(human.dna && !human.dna.mutantrace) + if(human.dna && human.dna.species.id == "human") M << "You hear a buzzing in your ears." - human.dna.mutantrace = "fly" - human.update_body() - human.update_hair() + human.dna.species = new /datum/species/fly() + human.regenerate_icons() human.apply_effect((rand(120 - accurate * 40, 180 - accurate * 60)), IRRADIATE, 0) return diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index e02188a5fb3..50da8e4965b 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -646,7 +646,7 @@ product_ads = "Probably not bad for you!;Don't believe the scientists!;It's good for you!;Don't quit, buy more!;Smoke!;Nicotine heaven.;Best cigarettes since 2150.;Award-winning cigs." vend_delay = 34 icon_state = "cigs" - products = list(/obj/item/weapon/storage/fancy/cigarettes = 10,/obj/item/weapon/storage/box/matches = 10,/obj/item/weapon/lighter/random = 4,/obj/item/weapon/rollingpaperpack = 5) + products = list(/obj/item/weapon/storage/fancy/cigarettes = 10,/obj/item/weapon/storage/box/matches = 10,/obj/item/weapon/lighter/random = 4,/obj/item/weapon/storage/fancy/rollingpapers = 5) contraband = list(/obj/item/weapon/lighter/zippo = 4) premium = list(/obj/item/clothing/mask/cigarette/cigar/havana = 2) refill_canister = /obj/item/weapon/vending_refill/cigarette diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index b5b4b4f7f5a..8dd8ad4263b 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -582,6 +582,7 @@ steam.start() -- spawns the effect icon = 'icons/effects/96x96.dmi' pixel_x = -32 pixel_y = -32 + color = "#9C3636" /obj/effect/effect/sleep_smoke/New() ..() @@ -596,7 +597,7 @@ steam.start() -- spawns the effect // if (M.wear_suit, /obj/item/clothing/suit/wizrobe && (M.hat, /obj/item/clothing/head/wizard) && (M.shoes, /obj/item/clothing/shoes/sandal)) // I'll work on it later else M.drop_item() - M:sleeping += 1 + M:sleeping += 5 if (M.coughedtime != 1) M.coughedtime = 1 M.emote("cough") @@ -612,7 +613,7 @@ steam.start() -- spawns the effect return else M.drop_item() - M:sleeping += 1 + M:sleeping += 5 if (M.coughedtime != 1) M.coughedtime = 1 M.emote("cough") diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index ff296e1dfec..cbf87e7b1c2 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -32,6 +32,8 @@ var/obj/item/device/uplink/hidden/hidden_uplink = null // All items can have an uplink hidden inside, just remember to add the triggers. var/reflect_chance = 0 //This var dictates what % of a time an object will reflect an energy based weapon's shot + var/list/species_exception = list() // even if a species cannot put items in a certain slot, if the species id is in the item's exception list, it will be able to wear that item + /obj/item/device icon = 'icons/obj/device.dmi' diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm index 3910f798064..4e0804e76cf 100644 --- a/code/game/objects/items/devices/laserpointer.dm +++ b/code/game/objects/items/devices/laserpointer.dm @@ -81,10 +81,10 @@ if(user.has_mutation(HULK)) user << "Your meaty finger is too large for the button!" return - if(iscarbon(user)) - var/mob/living/carbon/C = user - if(C.is_mutantrace("adamantine")) - user << "Your metal fingers can't press the button!" + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.dna && NOGUNS in H.dna.species.specflags) + user << "Your fingers can't press the button!" return add_fingerprint(user) diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 996ce6ff0b1..8d25a62be7e 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -78,16 +78,16 @@ MASS SPECTROMETER // Clumsiness/brain damage check if ((CLUMSY in user.mutations || user.getBrainLoss() >= 60) && prob(50)) - user << text("You stupidly try to analyze the floor's vitals!") - user.visible_message(text("[user] has analyzed the floor's vitals!")) - user.show_message(text("Analyzing Results for The floor:\n\t Overall Status: Healthy"), 1) - user.show_message(text("\t Damage Specifics: 0-0-0-0"), 1) + user << "You stupidly try to analyze the floor's vitals!" + user.visible_message("[user] has analyzed the floor's vitals!") + user.show_message("Analyzing Results for The floor:\n\t Overall Status: Healthy", 1) + user.show_message("\t Damage Specifics: 0-0-0-0", 1) user.show_message("Key: Suffocation/Toxin/Burn/Brute", 1) user.show_message("Body Temperature: ???", 1) return - user.visible_message(text("[] has analyzed []'s vitals!", user, M)) + user.visible_message("[user] has analyzed [M]'s vitals.") healthscan(user, M, mode) @@ -102,21 +102,26 @@ MASS SPECTROMETER var/tox_loss = M.getToxLoss() var/fire_loss = M.getFireLoss() var/brute_loss = M.getBruteLoss() - var/mob_status = (M.stat > 1 ? "Deceased" : text("[]% healthy", M.health)) + var/mob_status = (M.stat > 1 ? "Deceased" : "[M.health]% healthy") if(M.status_flags & FAKEDEATH) mob_status = "Deceased" oxy_loss = max(rand(1, 40), oxy_loss, (300 - (tox_loss + fire_loss + brute_loss))) // Random oxygen loss user.show_message(text("Analyzing Results for []:\n\t Overall Status: []", M, mob_status), 1) - user.show_message(text("\t Damage Specifics: []-[]-[]-[]", oxy_loss, tox_loss, fire_loss, brute_loss), 1) - + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.dna)// Show target's species, if they have one + user.show_message("Species: [H.dna.species.name]", 1) + else // Otherwise we can assume that they are a regular human + user.show_message("Species: Human", 1) + user.show_message("\t Damage Specifics: [oxy_loss]-[tox_loss]-[fire_loss]-[brute_loss]", 1) user.show_message("Key: Suffocation/Toxin/Burn/Brute", 1) user.show_message("Body Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1) // Time of death if(M.tod && (M.stat == DEAD || (M.status_flags & FAKEDEATH))) - user.show_message("Time of Death: [M.tod]") + user.show_message("Time of Death: [M.tod]", 1) // Organ damage report if(istype(M, /mob/living/carbon/human) && mode == 1) @@ -131,26 +136,26 @@ MASS SPECTROMETER // Damage descriptions - user.show_message(text("[] | [] | [] | []", oxy_loss > 50 ? "\red Severe oxygen deprivation detected\blue" : "Subject bloodstream oxygen level normal", tox_loss > 50 ? "\red Dangerous amount of toxins detected\blue" : "Subject bloodstream toxin level minimal", fire_loss > 50 ? "\red Severe burn damage detected\blue" : "Subject burn injury status O.K", brute_loss > 50 ? "\red Severe anatomical damage detected\blue" : "Subject brute-force injury status O.K"), 1) + user.show_message(text("[] | [] | [] | []", oxy_loss > 50 ? " Severe oxygen deprivation detected" : "Subject bloodstream oxygen level normal", tox_loss > 50 ? " Dangerous amount of toxins detected" : "Subject bloodstream toxin level minimal", fire_loss > 50 ? " Severe burn damage detected" : "Subject burn injury status O.K", brute_loss > 50 ? " Severe anatomical damage detected" : "Subject brute-force injury status O.K"), 1) if(M.getStaminaLoss()) - user.show_message(text("Subject appears to be suffering from fatigue."), 1) + user.show_message("Subject appears to be suffering from fatigue.", 1) if (M.getCloneLoss()) - user.show_message(text("Subject appears to have been imperfectly cloned."), 1) + user.show_message("Subject appears to have been imperfectly cloned.", 1) for(var/datum/disease/D in M.viruses) if(!D.hidden[SCANNER]) - user.show_message(text("Warning: [D.form] Detected\nName: [D.name].\nType: [D.spread].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure]")) + user.show_message("Warning: [D.form] Detected\nName: [D.name].\nType: [D.spread].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure]", 1) if (M.reagents && M.reagents.get_reagent_amount("inaprovaline")) - user.show_message(text("Bloodstream Analysis located [M.reagents:get_reagent_amount("inaprovaline")] units of rejuvenation chemicals."), 1) + user.show_message("Bloodstream Analysis located [M.reagents:get_reagent_amount("inaprovaline")] units of rejuvenation chemicals.", 1) if (M.getBrainLoss() >= 100 || !M.getorgan(/obj/item/organ/brain)) - user.show_message(text("Subject brain function is non-existant."), 1) + user.show_message("Subject brain function is non-existant.", 1) else if (M.getBrainLoss() >= 60) - user.show_message(text("Severe brain damage detected. Subject likely to have mental retardation."), 1) + user.show_message("Severe brain damage detected. Subject likely to have mental retardation.", 1) else if (M.getBrainLoss() >= 10) - user.show_message(text("Significant brain damage detected. Subject may have had a concussion."), 1) + user.show_message("Significant brain damage detected. Subject may have had a concussion.", 1) /obj/item/device/healthanalyzer/verb/toggle_mode() set name = "Switch Verbosity" @@ -193,11 +198,11 @@ MASS SPECTROMETER var/pressure = environment.return_pressure() var/total_moles = environment.total_moles() - user.show_message("\blue Results:", 1) + user.show_message(" Results:", 1) if(abs(pressure - ONE_ATMOSPHERE) < 10) - user.show_message("\blue Pressure: [round(pressure,0.1)] kPa", 1) + user.show_message(" Pressure: [round(pressure,0.1)] kPa", 1) else - user.show_message("\red Pressure: [round(pressure,0.1)] kPa", 1) + user.show_message(" Pressure: [round(pressure,0.1)] kPa", 1) if(total_moles) var/o2_concentration = environment.oxygen/total_moles var/n2_concentration = environment.nitrogen/total_moles @@ -206,27 +211,27 @@ MASS SPECTROMETER var/unknown_concentration = 1-(o2_concentration+n2_concentration+co2_concentration+plasma_concentration) if(abs(n2_concentration - N2STANDARD) < 20) - user.show_message("\blue Nitrogen: [round(n2_concentration*100)]%", 1) + user.show_message(" Nitrogen: [round(n2_concentration*100)]%", 1) else - user.show_message("\red Nitrogen: [round(n2_concentration*100)]%", 1) + user.show_message(" Nitrogen: [round(n2_concentration*100)]%", 1) if(abs(o2_concentration - O2STANDARD) < 2) - user.show_message("\blue Oxygen: [round(o2_concentration*100)]%", 1) + user.show_message(" Oxygen: [round(o2_concentration*100)]%", 1) else - user.show_message("\red Oxygen: [round(o2_concentration*100)]%", 1) + user.show_message(" Oxygen: [round(o2_concentration*100)]%", 1) if(co2_concentration > 0.01) - user.show_message("\red CO2: [round(co2_concentration*100)]%", 1) + user.show_message(" CO2: [round(co2_concentration*100)]%", 1) else - user.show_message("\blue CO2: [round(co2_concentration*100)]%", 1) + user.show_message(" CO2: [round(co2_concentration*100)]%", 1) if(plasma_concentration > 0.01) - user.show_message("\red Plasma: [round(plasma_concentration*100)]%", 1) + user.show_message(" Plasma: [round(plasma_concentration*100)]%", 1) if(unknown_concentration > 0.01) - user.show_message("\red Unknown: [round(unknown_concentration*100)]%", 1) + user.show_message(" Unknown: [round(unknown_concentration*100)]%", 1) - user.show_message("\blue Temperature: [round(environment.temperature-T0C)]°C", 1) + user.show_message(" Temperature: [round(environment.temperature-T0C)]°C", 1) src.add_fingerprint(user) return @@ -262,17 +267,17 @@ MASS SPECTROMETER if (user.stat) return if (crit_fail) - user << "\red This device has critically failed and is no longer functional!" + user << " This device has critically failed and is no longer functional!" return if (!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") - user << "\red You don't have the dexterity to do this!" + user << " You don't have the dexterity to do this!" return if(reagents.total_volume) var/list/blood_traces = list() for(var/datum/reagent/R in reagents.reagent_list) if(R.id != "blood") reagents.clear_reagents() - user << "\red The sample was contaminated! Please insert another sample" + user.show_message(" The sample was contaminated! Please insert another sample.", 1) return else blood_traces = params2list(R.data["trace_chem"]) @@ -317,31 +322,31 @@ MASS SPECTROMETER /obj/item/device/slime_scanner/attack(mob/living/M as mob, mob/living/user as mob) if (!isslime(M)) - user << "This device can only scan slimes!" + user.show_message("This device can only scan slimes!", 1) return var/mob/living/carbon/slime/T = M - user.show_message("Slime scan results:") - user.show_message(text("[T.colour] [] slime", T.is_adult ? "adult" : "baby")) - user.show_message(text("Nutrition: [T.nutrition]/[]", T.get_max_nutrition())) + user.show_message("Slime scan results:", 1) + user.show_message(text("[T.colour] [] slime", T.is_adult ? "adult" : "baby"), 1) + user.show_message(text("Nutrition: [T.nutrition]/[]", T.get_max_nutrition()), 1) if (T.nutrition < T.get_starve_nutrition()) - user.show_message("Warning: slime is starving!") + user.show_message("Warning: slime is starving!", 1) else if (T.nutrition < T.get_hunger_nutrition()) - user.show_message("Warning: slime is hungry") - user.show_message("Electric change strength: [T.powerlevel]") - user.show_message("Health: [T.health]") + user.show_message("Warning: slime is hungry", 1) + user.show_message("Electric change strength: [T.powerlevel]", 1) + user.show_message("Health: [T.health]", 1) if (T.slime_mutation[4] == T.colour) - user.show_message("This slime does not evolve any further") + user.show_message("This slime does not evolve any further.", 1) else if (T.slime_mutation[3] == T.slime_mutation[4]) if (T.slime_mutation[2] == T.slime_mutation[1]) - user.show_message(text("Possible mutation: []", T.slime_mutation[3])) - user.show_message("Genetic destability: [T.mutation_chance/2]% chance of mutation on splitting") + user.show_message("Possible mutation: [T.slime_mutation[3]]", 1) + user.show_message("Genetic destability: [T.mutation_chance/2]% chance of mutation on splitting", 1) else - user.show_message(text("Possible mutations: [], [], [] (x2)", T.slime_mutation[1], T.slime_mutation[2], T.slime_mutation[3])) - user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting") + user.show_message("Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]] (x2)", 1) + user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting", 1) else - user.show_message(text("Possible mutations: [], [], [], []", T.slime_mutation[1], T.slime_mutation[2], T.slime_mutation[3], T.slime_mutation[4])) - user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting") + user.show_message("Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]], [T.slime_mutation[4]]", 1) + user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting", 1) if (T.cores > 1) - user.show_message("Anomalious slime core amount detected") - user.show_message("Growth progress: [T.amount_grown]/10") \ No newline at end of file + user.show_message("Anomalious slime core amount detected", 1) + user.show_message("Growth progress: [T.amount_grown]/10", 1) diff --git a/code/game/objects/items/weapons/cigs_lighters.dm b/code/game/objects/items/weapons/cigs_lighters.dm index 35f0eadaa47..3b2c2381328 100644 --- a/code/game/objects/items/weapons/cigs_lighters.dm +++ b/code/game/objects/items/weapons/cigs_lighters.dm @@ -30,29 +30,44 @@ CIGARETTE PACKETS ARE IN FANCY.DM var/turf/location = get_turf(src) smoketime-- if(smoketime < 1) + matchburnout() + return + if(location) + location.hotspot_expose(700, 5) + return + +/obj/item/weapon/match/fire_act() + matchignite() + +/obj/item/weapon/match/proc/matchignite() + if(lit == 0) + lit = 1 + icon_state = "match_lit" + damtype = "fire" + force = 3 + hitsound = 'sound/items/welder.ogg' + item_state = "cigon" + name = "lit match" + desc = "A match. This one is lit." + attack_verb = list("burnt","singed") + processing_objects.Add(src) + update_icon() + return + +/obj/item/weapon/match/proc/matchburnout() + if(lit == 1) lit = -1 damtype = "brute" - force = 0 + force = initial(force) icon_state = "match_burnt" item_state = "cigoff" name = "burnt match" desc = "A match. This one has seen better days." attack_verb = null processing_objects.Remove(src) - return - if(location) - location.hotspot_expose(700, 5) - return /obj/item/weapon/match/dropped(mob/user as mob) - if(lit == 1) - lit = -1 - damtype = "brute" - icon_state = "match_burnt" - item_state = "cigoff" - name = "burnt match" - desc = "A match. This one has seen better days." - attack_verb = null + matchburnout() return ..() ////////////////// @@ -78,7 +93,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/cigarette/New() ..() flags |= NOREACT // so it doesn't react until you light it - create_reagents(chem_volume) // making the cigarrete a chemical holder with a maximum volume of 15 + create_reagents(chem_volume) // making the cigarette a chemical holder with a maximum volume of 15 /obj/item/clothing/mask/cigarette/attackby(obj/item/weapon/W as obj, mob/user as mob) ..() @@ -120,7 +135,6 @@ CIGARETTE PACKETS ARE IN FANCY.DM light("[user] lights their [name] with [W].") return - /obj/item/clothing/mask/cigarette/afterattack(obj/item/weapon/reagent_containers/glass/glass, mob/user as mob, proximity) if(!proximity) return if(istype(glass)) //you can dip cigarettes into beakers @@ -134,15 +148,14 @@ CIGARETTE PACKETS ARE IN FANCY.DM user << "[src] is full." -/obj/item/clothing/mask/cigarette/proc/light(var/flavor_text = "[usr] lights the [name].") +/obj/item/clothing/mask/cigarette/proc/light(var/flavor_text = null) if(!src.lit) src.lit = 1 name = "lit [name]" - if(!istype(src, /obj/item/clothing/mask/cigarette/pipe)) //can't burn people with pipes - attack_verb = list("burnt", "singed") - hitsound = 'sound/items/welder.ogg' - damtype = "fire" - force = 4 + attack_verb = list("burnt", "singed") + hitsound = 'sound/items/welder.ogg' + damtype = "fire" + force = 4 if(reagents.get_reagent_amount("plasma")) // the plasma explodes when exposed to fire var/datum/effect/effect/system/reagents_explosion/e = new() e.set_up(round(reagents.get_reagent_amount("plasma") / 2.5, 1), get_turf(src), 0, 0) @@ -165,8 +178,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM reagents.handle_reactions() icon_state = icon_on item_state = icon_on - var/turf/T = get_turf(src) - T.visible_message(flavor_text) + if(flavor_text) + var/turf/T = get_turf(src) + T.visible_message(flavor_text) processing_objects.Add(src) //can't think of any other way to update the overlays :< @@ -176,6 +190,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM M.update_inv_l_hand(0) M.update_inv_r_hand(0) + /obj/item/clothing/mask/cigarette/proc/handle_reagents() if(iscarbon(loc)) var/mob/living/carbon/C = loc @@ -183,10 +198,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM if(prob(15)) // so it's not an instarape in case of acid reagents.reaction(C, INGEST) reagents.trans_to(C, REAGENTS_METABOLISM) - else - reagents.remove_any(REAGENTS_METABOLISM) - else - reagents.remove_any(REAGENTS_METABOLISM) + return + reagents.remove_any(REAGENTS_METABOLISM) + /obj/item/clothing/mask/cigarette/process() var/turf/location = get_turf(src) @@ -231,6 +245,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM else return ..() +/obj/item/clothing/mask/cigarette/fire_act() + light() + /obj/item/clothing/mask/cigarette/rollie name = "rollie" desc = "A roll of dried plant matter wrapped in thin paper." @@ -536,27 +553,3 @@ CIGARETTE PACKETS ARE IN FANCY.DM user << "You need to dry this first." else ..() - -/obj/item/weapon/rollingpaperpack - name = "rolling paper pack" - desc = "A pack of NanoTrasen brand rolling papers." - icon = 'icons/obj/cigarettes.dmi' - icon_state = "cig_paper_pack" - w_class = 1 - var/papers = 25 - -/obj/item/weapon/rollingpaperpack/attack_self(mob/user) - if(papers > 1) - var/obj/item/weapon/rollingpaper/P = new /obj/item/weapon/rollingpaper(user.loc) - user.put_in_inactive_hand(P) - user << "You take a paper out of the pack." - papers -- - else - var/obj/item/weapon/rollingpaper/P = new /obj/item/weapon/rollingpaper(user.loc) - user.put_in_inactive_hand(P) - user << "You take the last paper out of the pack, and throw the pack away." - qdel(src) - -/obj/item/weapon/rollingpaperpack/examine() - ..() - usr << "There are [src.papers] left" \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index 521945ee7fd..010cb0420e5 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -470,25 +470,15 @@ w_class = 1 slot_flags = SLOT_BELT - New() - ..() - for(var/i=1; i <= storage_slots; i++) - new /obj/item/weapon/match(src) +/obj/item/weapon/storage/box/matches/New() + ..() + for(var/i=1; i <= storage_slots; i++) + new /obj/item/weapon/match(src) - attackby(obj/item/weapon/match/W as obj, mob/user as mob) - if(istype(W, /obj/item/weapon/match) && W.lit == 0) - W.lit = 1 - W.icon_state = "match_lit" - W.damtype = "fire" - W.force = 3 - W.hitsound = 'sound/items/welder.ogg' - W.item_state = "cigon" - W.name = "lit match" - W.desc = "A match. This one is lit." - W.attack_verb = list("burnt","singed") - processing_objects.Add(W) - W.update_icon() - return +/obj/item/weapon/storage/box/matches/attackby(obj/item/weapon/match/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/match)) + W.matchignite() + return /obj/item/weapon/storage/box/lights name = "box of replacement bulbs" @@ -525,4 +515,4 @@ for(var/i = 0; i < 14; i++) new /obj/item/weapon/light/tube(src) for(var/i = 0; i < 7; i++) - new /obj/item/weapon/light/bulb(src) \ No newline at end of file + new /obj/item/weapon/light/bulb(src) diff --git a/code/game/objects/items/weapons/storage/fancy.dm b/code/game/objects/items/weapons/storage/fancy.dm index b959c652871..303850c14dd 100644 --- a/code/game/objects/items/weapons/storage/fancy.dm +++ b/code/game/objects/items/weapons/storage/fancy.dm @@ -192,3 +192,28 @@ desc = "A packet of six imported DromedaryCo cancer sticks. A label on the packaging reads, \"Wouldn't a slow death make a change?\"" icon_state = "Dpacket" item_state = "Dpacket" + + +/obj/item/weapon/storage/fancy/rollingpapers + name = "rolling paper pack" + desc = "A pack of NanoTrasen brand rolling papers." + w_class = 1 + icon = 'icons/obj/cigarettes.dmi' + icon_state = "cig_paper_pack" + storage_slots = 10 + icon_type = "rolling papers" + can_hold = list(/obj/item/weapon/rollingpaper) + +/obj/item/weapon/storage/fancy/rollingpapers/update_icon() + if(!contents.len) + icon_state = "[initial(icon_state)]0" + else + icon_state = initial(icon_state) + + desc = "There are [contents.len] papers\s left!" + return + +/obj/item/weapon/storage/fancy/rollingpapers/New() + ..() + for(var/i = 1 to storage_slots) + new /obj/item/weapon/rollingpaper(src) diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 74393eafbe3..9c1e150c3e2 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -205,13 +205,15 @@ air_contents.react() pressure = air_contents.return_pressure() var/range = (pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE - range = min(range, MAX_EX_LIGHT_RANGE) var/turf/epicenter = get_turf(loc) //world << "\blue Exploding Pressure: [pressure] kPa, intensity: [range]" explosion(epicenter, round(range*0.25), round(range*0.5), round(range), round(range*1.5)) - qdel(src) + if(istype(src.loc,/obj/item/device/transfer_valve)) + qdel(src.loc) + else + qdel(src) else if(pressure > TANK_RUPTURE_PRESSURE) //world << "\blue[x],[y] tank is rupturing: [pressure] kPa, integrity [integrity]" @@ -237,4 +239,4 @@ integrity-- else if(integrity < 3) - integrity++ \ No newline at end of file + integrity++ diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index 553122c43fb..e6518e44186 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -318,8 +318,10 @@ obj/structure/door_assembly /obj/structure/door_assembly/attackby(obj/item/W as obj, mob/user as mob) if(istype(W, /obj/item/weapon/pen)) var/t = copytext(stripped_input(user, "Enter the name for the door.", src.name, src.created_name),1,MAX_NAME_LEN) - if(!t) return - if(!in_range(src, usr) && src.loc != usr) return + if(!t) + return + if(!in_range(src, usr) && src.loc != usr) + return created_name = t return @@ -343,7 +345,8 @@ obj/structure/door_assembly icontype = input(user, "Please select a paintjob for this airlock.") in optionlist - if((!in_range(src, usr) && src.loc != usr) || !WT.use(user)) return + if((!in_range(src, usr) && src.loc != usr) || !WT.use(user)) + return var/has_solid = 0 var/has_glass = 0 switch(icontype) @@ -414,7 +417,7 @@ obj/structure/door_assembly if(mineral && mineral != "glass") mineral = null //I know this is stupid, but until we change glass to a boolean it's how this code works. - user << "\blue You change the paintjob on the airlock assembly." + user << " You change the paintjob on the airlock assembly." else if(istype(W, /obj/item/weapon/weldingtool) && !anchored ) var/obj/item/weapon/weldingtool/WT = W @@ -423,8 +426,9 @@ obj/structure/door_assembly playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) if(do_after(user, 40)) - if(!src || !WT.isOn()) return - user << "\blue You've dissasembled the airlock assembly." + if( !WT.isOn() ) + return + user << " You've disassembled the airlock assembly." new /obj/item/stack/sheet/metal(get_turf(src), 4) if (mineral) if (mineral == "glass") @@ -435,7 +439,7 @@ obj/structure/door_assembly new M(get_turf(src)) qdel(src) else - user << "\blue You need more welding fuel to dissassemble the airlock assembly." + user << " You need more welding fuel to dissassemble the airlock assembly." return else if(istype(W, /obj/item/weapon/wrench) && !anchored ) @@ -443,8 +447,9 @@ obj/structure/door_assembly user.visible_message("[user] secures the airlock assembly to the floor.", "You start to secure the airlock assembly to the floor.") if(do_after(user, 40)) - if(!src) return - user << "\blue You've secured the airlock assembly." + if( src.anchored ) + return + user << " You've secured the airlock assembly." src.name = "secured airlock assembly" src.anchored = 1 @@ -452,8 +457,9 @@ obj/structure/door_assembly playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) user.visible_message("[user] unsecures the airlock assembly from the floor.", "You start to unsecure the airlock assembly from the floor.") if(do_after(user, 40)) - if(!src) return - user << "\blue You've unsecured the airlock assembly." + if( !src.anchored ) + return + user << " You've unsecured the airlock assembly." src.name = "airlock assembly" src.anchored = 0 @@ -461,10 +467,9 @@ obj/structure/door_assembly var/obj/item/stack/cable_coil/coil = W user.visible_message("[user] wires the airlock assembly.", "You start to wire the airlock assembly.") if(do_after(user, 40)) - if(!src) return coil.use(1) src.state = 1 - user << "\blue You've wired the airlock assembly." + user << " You've wired the airlock assembly." src.name = "wired airlock assembly" else if(istype(W, /obj/item/weapon/wirecutters) && state == 1 ) @@ -472,8 +477,9 @@ obj/structure/door_assembly user.visible_message("[user] cuts the wires from the airlock assembly.", "You start to cut the wires from airlock assembly.") if(do_after(user, 40)) - if(!src) return - user << "\blue You've cut the wires from the airlock assembly." + if( src.state != 1 ) + return + user << " You've cut the wires from the airlock assembly." new/obj/item/stack/cable_coil(get_turf(user), 1) src.state = 0 src.name = "secured airlock assembly" @@ -485,8 +491,9 @@ obj/structure/door_assembly W.loc = src if(do_after(user, 40)) - if(!src) return - user << "\blue You've installed the airlock electronics." + if( src.state != 1 ) + return + user << " You've installed the airlock electronics." src.state = 2 src.name = "near finished airlock assembly" src.electronics = W @@ -500,8 +507,9 @@ obj/structure/door_assembly user.visible_message("[user] removes the electronics from the airlock assembly.", "You start to remove the electronics from the airlock assembly.") if(do_after(user, 40)) - if(!src) return - user << "\blue You've removed the airlock electronics." + if( src.state != 2 ) + return + user << " You've removed the airlock electronics." src.state = 1 src.name = "wired airlock assembly" var/obj/item/weapon/airlock_electronics/ae @@ -519,7 +527,7 @@ obj/structure/door_assembly playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) user.visible_message("[user] adds [G.name] to the airlock assembly.", "You start to install [G.name] into the airlock assembly.") if(do_after(user, 40)) - user << "\blue You've installed reinforced glass windows into the airlock assembly." + user << " You've installed reinforced glass windows into the airlock assembly." G.use(1) mineral = "glass" name = "near finished window airlock assembly" @@ -541,7 +549,7 @@ obj/structure/door_assembly playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) user.visible_message("[user] adds [G.name] to the airlock assembly.", "You start to install [G.name] into the airlock assembly.") if(do_after(user, 40)) - user << "\blue You've installed [M] plating into the airlock assembly." + user << " You've installed [M] plating into the airlock assembly." G.use(2) mineral = "[M]" name = "near finished [M] airlock assembly" @@ -552,11 +560,10 @@ obj/structure/door_assembly else if(istype(W, /obj/item/weapon/screwdriver) && state == 2 ) playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) - user << "\blue You start finishing the airlock." + user.visible_message("[user] finishes the airlock.", "You start finishing the airlock.") if(do_after(user, 40)) - if(!src) return - user << "\blue You've finished the airlock." + user << " You've finished the airlock." var/obj/machinery/door/airlock/door if(mineral == "glass") door = new src.glass_type( src.loc ) @@ -580,4 +587,4 @@ obj/structure/door_assembly icon_state = "[base_icon_state][state]" //This updates the icon_state. They are named as "door_as1_eng" where the 1 in that example //represents what state it's in. So the most generic algorithm for the correct updating of - //this is simply to change the number. \ No newline at end of file + //this is simply to change the number. diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index f08e6bffef1..7a7d7c45166 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -434,7 +434,6 @@ var/global/floorIsLava = 0 dat += {" 'Random' Events

- Trigger a gravity-failure event
Spawn a wave of meteors (aka lagocolyptic shower)
Spawn a vortex anomaly
Spawn a gravitational anomaly
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index f9fcfb99bf8..25510344edc 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1584,13 +1584,6 @@ usr.client.triple_ai() feedback_inc("admin_secrets_fun_used",1) feedback_add_details("admin_secrets_fun_used","TriAI") - if("gravity") - alert("WIP - event unavailable") -/* E = new /datum/round_event/weightless() - log_admin("[key_name(usr)] triggered a gravity-failure event.", 1) - message_admins("\blue [key_name_admin(usr)] triggered a gravity-failure event.", 1) - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","Grav") */ if("power") feedback_inc("admin_secrets_fun_used",1) feedback_add_details("admin_secrets_fun_used","P") diff --git a/code/modules/awaymissions/mission_code/wildwest.dm b/code/modules/awaymissions/mission_code/wildwest.dm index 9a2d6c758b4..1f0a894cd5a 100644 --- a/code/modules/awaymissions/mission_code/wildwest.dm +++ b/code/modules/awaymissions/mission_code/wildwest.dm @@ -89,20 +89,20 @@ user.see_in_dark = 8 user.see_invisible = SEE_INVISIBLE_LEVEL_TWO user << "\blue The walls suddenly disappear." - user.dna.mutantrace = "shadow" - user.update_body() + user.dna.species = new /datum/species/shadow() + user.regenerate_icons() if("Wealth") user << "Your wish is granted, but at a terrible cost..." user << "The Wish Granter punishes you for your selfishness, claiming your soul and warping your body to match the darkness in your heart." new /obj/structure/closet/syndicate/resources/everything(loc) - user.dna.mutantrace = "shadow" - user.update_body() + user.dna.species = new /datum/species/shadow() + user.regenerate_icons() if("Immortality") user << "Your wish is granted, but at a terrible cost..." user << "The Wish Granter punishes you for your selfishness, claiming your soul and warping your body to match the darkness in your heart." user.verbs += /mob/living/carbon/proc/immortality - user.dna.mutantrace = "shadow" - user.update_body() + user.dna.species = new /datum/species/shadow() + user.regenerate_icons() if("To Kill") user << "Your wish is granted, but at a terrible cost..." user << "The Wish Granter punishes you for your wickedness, claiming your soul and warping your body to match the darkness in your heart." @@ -116,8 +116,8 @@ for(var/datum/objective/OBJ in user.mind.objectives) user << "Objective #[obj_count]: [OBJ.explanation_text]" obj_count++ - user.dna.mutantrace = "shadow" - user.update_body() + user.dna.species = new /datum/species/shadow() + user.regenerate_icons() if("Peace") user << "Whatever alien sentience that the Wish Granter possesses is satisfied with your wish. There is a distant wailing as the last of the Faithless begin to die, then silence." user << "You feel as if you just narrowly avoided a terrible fate..." diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 7eaacc46d10..f3085e14e0f 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -53,7 +53,8 @@ datum/preferences var/facial_hair_color = "000" //Facial hair color var/skin_tone = "caucasian1" //Skin color var/eye_color = "000" //Eye color - var/mutant_race = "human" //Mutant race + var/datum/species/pref_species = new /datum/species/human() //Mutant race + var/mutant_color = "FFF" //Mutant race skin color //Mob preview var/icon/preview_icon_front = null @@ -165,16 +166,17 @@ datum/preferences dat += "
" if(config.mutant_races) - dat += "Mutant Race:
[mutant_race]
" + dat += "Species:
[pref_species.name]
" else - dat += "Mutant Race: Human
" + dat += "Species: Human
" + dat += "Blood Type: [blood_type]
" dat += "Skin Tone:
[skin_tone]
" dat += "Underwear:
[underwear]
" dat += "Backpack:
[backbaglist[backbag]]
" - dat += "
" + dat += "" dat += "

Hair Style

" @@ -182,7 +184,7 @@ datum/preferences dat += "    Change
" - dat += "
" + dat += "" dat += "

Facial Hair Style

" @@ -190,12 +192,17 @@ datum/preferences dat += "    Change
" - dat += "
" + dat += "" dat += "

Eye Color

" dat += "    Change
" + dat += "
" + + dat += "

Alien Color

" // even if choosing your mutantrace is off, this is here in case you gain one during a round + + dat += "    Change
" dat += "
" @@ -618,10 +625,27 @@ datum/preferences if(new_eyes) eye_color = sanitize_hexcolor(new_eyes) - if("mutant_race") - var/new_mutant_race = input(user, "Choose your character's mutant race:", "Character Preference") as null|anything in mutant_races - if(new_mutant_race) - mutant_race = new_mutant_race + if("species") + + var/result = input(user, "Select a species", "Species Selection") as null|anything in roundstart_species + + if(result) + var/newtype = roundstart_species[result] + pref_species = new newtype() + if(!config.mutant_colors) + mutant_color = pref_species.default_color + + if("mutant_color") + if(!config.mutant_colors) + user << "Alien colors are disabled." + return + var/new_mutantcolor = input(user, "Choose your character's alien skin color:", "Character Preference") as color|null + if(new_mutantcolor) + var/temp_hsv = RGBtoHSV(new_mutantcolor) + if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright + mutant_color = sanitize_hexcolor(new_mutantcolor) + else + user << "Invalid color. Your color is not bright enough." if("s_tone") var/new_s_tone = input(user, "Choose your character's skin-tone:", "Character Preference") as null|anything in skin_tones @@ -685,8 +709,10 @@ datum/preferences if("ghost_sight") toggles ^= CHAT_GHOSTSIGHT + if("pull_requests") toggles ^= CHAT_PULLR + if("save") save_preferences() save_character() @@ -722,10 +748,15 @@ datum/preferences character.real_name = real_name character.name = character.real_name + if(character.dna) character.dna.real_name = character.real_name - if(mutant_race != "human" && config.mutant_races) - character.dna.mutantrace = mutant_race + if(pref_species != /datum/species/human && config.mutant_races) + character.dna.species = new pref_species.type() + else + character.dna.species = new /datum/species/human() + character.dna.mutant_color = mutant_color + character.update_mutcolor() character.gender = gender character.age = age diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 1204bf5edee..93c33b755be 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -73,6 +73,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(11) underwear = "Ladies Kinky" if(12) underwear = "Tankini" if(13) underwear = "Nude" + if(!pref_species in species_list) + pref_species = new /datum/species/human() return /datum/preferences/proc/load_path(ckey,filename="preferences.sav") @@ -151,6 +153,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(needs_update == -2) //fatal, can't load any data return 0 + if(!S["species"] || !config.mutant_races) + S["species"] << new /datum/species/human() + //Character S["OOC_Notes"] >> metadata S["real_name"] >> real_name @@ -165,7 +170,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["facial_style_name"] >> facial_hair_style S["underwear"] >> underwear S["backbag"] >> backbag - S["mutant_race"] >> mutant_race + S["species"] >> pref_species + S["mutant_color"] >> mutant_color //Jobs S["userandomjob"] >> userandomjob @@ -186,6 +192,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car //Sanitize metadata = sanitize_text(metadata, initial(metadata)) real_name = reject_bad_name(real_name) + if(!pref_species in species_list) + pref_species = new /datum/species/human() + world << "[pref_species] is the species" if(!real_name) real_name = random_name(gender) be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name)) gender = sanitize_gender(gender) @@ -203,7 +212,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car eye_color = sanitize_hexcolor(eye_color, 3, 0) skin_tone = sanitize_inlist(skin_tone, skin_tones) backbag = sanitize_integer(backbag, 1, backbaglist.len, initial(backbag)) - mutant_race = sanitize_text(mutant_race, initial(mutant_race)) + mutant_color = sanitize_hexcolor(mutant_color, 3, 0) userandomjob = sanitize_integer(userandomjob, 0, 1, initial(userandomjob)) job_civilian_high = sanitize_integer(job_civilian_high, 0, 65535, initial(job_civilian_high)) @@ -240,7 +249,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["facial_style_name"] << facial_hair_style S["underwear"] << underwear S["backbag"] << backbag - S["mutant_race"] << mutant_race + S["species"] << pref_species + S["mutant_color"] << mutant_color //Jobs S["userandomjob"] << userandomjob diff --git a/code/modules/clothing/gloves/boxing.dm b/code/modules/clothing/gloves/boxing.dm index 0865c31e942..9467c63e34e 100644 --- a/code/modules/clothing/gloves/boxing.dm +++ b/code/modules/clothing/gloves/boxing.dm @@ -3,6 +3,7 @@ desc = "Because you really needed another excuse to punch your crewmates." icon_state = "boxing" item_state = "boxing" + species_exception = list(/datum/species/golem, /datum/species/golem/adamantine) // now you too can be a golem boxing champion /obj/item/clothing/gloves/boxing/green icon_state = "boxinggreen" diff --git a/code/modules/events/holiday/halloween.dm b/code/modules/events/holiday/halloween.dm index 67536e1dec7..9a7945d7719 100644 --- a/code/modules/events/holiday/halloween.dm +++ b/code/modules/events/holiday/halloween.dm @@ -9,9 +9,9 @@ /datum/round_event/spooky/start() for(var/mob/living/carbon/human/H in mob_list) if(H.dna) - hardset_dna(H, null, null, null, "skeleton") + hardset_dna(H, null, null, null, null, /datum/species/skeleton) for(var/mob/living/simple_animal/corgi/Ian/Ian in mob_list) Ian.place_on_head(new /obj/item/weapon/bedsheet(Ian)) /datum/round_event/spooky/announce() - priority_announce(pick("RATTLE ME BONES!","THE RIDE NEVER ENDS!", "A SKELETON POPS OUT!", "SPOOKY SCARY SKELETONS!", "CREWMEMBERS BEWARE, YOU'RE IN FOR A SCARE!") , "THE CALL IS COMING FROM INSIDE THE HOUSE") \ No newline at end of file + priority_announce(pick("RATTLE ME BONES!","THE RIDE NEVER ENDS!", "A SKELETON POPS OUT!", "SPOOKY SCARY SKELETONS!", "CREWMEMBERS BEWARE, YOU'RE IN FOR A SCARE!") , "THE CALL IS COMING FROM INSIDE THE HOUSE") diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 80642e3957b..10f10353b41 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -909,7 +909,7 @@ obj/machinery/hydroponics/attackby(var/obj/item/O as obj, var/mob/user as mob) podman.gender = ghost.gender //dna stuff - hardset_dna(podman, ui, se, null, !prob(potency) ? "plant" : null) //makes sure podman has dna and sets the dna's ui/se/mutantrace/real_name etc variables + hardset_dna(podman, ui, se, null, null, null, !prob(potency) ? /datum/species/plant/pod : null, "#59CE00") //makes sure podman has dna and sets the dna's ui/se/mutantrace/real_name etc variables else //else, one packet of seeds. maybe two var/seed_count = 1 diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm index ebe2a488d4f..b92d4c01cfd 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm @@ -94,7 +94,7 @@ if(shielded) damage /= 4 - show_message("\red The blob attacks!") + show_message("The blob attacks!") adjustFireLoss(damage) return @@ -120,9 +120,8 @@ return if (health > 0) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[M.name] bites [src]!"), 1) + visible_message("[M.name] bites [src]!", \ + "[M.name] bites [src]!") adjustBruteLoss(rand(1, 3)) updatehealth() return @@ -137,10 +136,8 @@ if (health > -100) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red The [M.name] glomps []!", src), 1) - + visible_message("The [M.name] glomps [src]!", \ + "The [M.name] glomps [src]!") var/damage = rand(1, 3) if(M.is_adult) @@ -167,9 +164,8 @@ if(M.powerlevel < 0) M.powerlevel = 0 - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red The [M.name] has shocked []!", src), 1) + visible_message("The [M.name] has shocked [src]!", \ + "The [M.name] has shocked [src]!") Weaken(power) if (stuttering < power) @@ -194,8 +190,8 @@ else if(M.attack_sound) playsound(loc, M.attack_sound, 50, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message("\red [M] [M.attacktext] [src]!", 1) + visible_message("[M] [M.attacktext] [src]!", \ + "[M] [M.attacktext] [src]!") var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) adjustBruteLoss(damage) updatehealth() @@ -229,9 +225,7 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has grabbed [] passively!", M, src), 1) + visible_message("[M] has grabbed [src] passively!") if ("harm") var/damage = rand(1, 9) @@ -244,42 +238,35 @@ sleep(3) step_away(src,M,15) playsound(loc, "punch", 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has punched []!", M, src), 1) + visible_message("[M] has punched [src]!", \ + "[M] has punched [src]!") if ((stat != DEAD) && (damage > 9||prob(5)))//Regular humans have a very small chance of weakening an alien. Weaken(1,5) - for(var/mob/O in viewers(M, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has weakened []!", M, src), 1, "\red You hear someone fall.", 2) + visible_message("[M] has weakened [src]!", \ + "[M] has weakened [src]!", \ + "You hear someone fall.") adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has attempted to punch []!", M, src), 1) + visible_message("[M] has attempted to punch [src]!") if ("disarm") if (!lying) if (prob(5))//Very small chance to push an alien down. Weaken(2) playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has pushed down []!", M, src), 1) + visible_message("[M] has pushed down [src]!", \ + "[M] has pushed down [src]!") else if (prob(50)) drop_item() playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has disarmed []!", M, src), 1) + visible_message("[M] has disarmed [src]!", \ + "[M] has disarmed [src]!") else playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has attempted to disarm []!", M, src), 1) + visible_message("[M] has attempted to disarm [src]!") return /*Code for aliens attacking aliens. Because aliens act on a hivemind, I don't see them as very aggressive with each other. @@ -306,21 +293,19 @@ In all, this is a lot like the monkey code. /N AdjustParalysis(-3) AdjustStunned(-3) AdjustWeakened(-3) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\blue [M.name] nuzzles [] trying to wake it up!", src), 1) + visible_message("[M.name] nuzzles [src] trying to wake it up!") else if (health > 0) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) var/damage = rand(1, 3) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[M.name] bites []!", src), 1) + visible_message("[M.name] bites [src]!!", \ + "[M.name] bites [src]!!") + adjustBruteLoss(damage) updatehealth() else - M << "\green [name] is too injured for that." + M << "[name] is too injured for that." return diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm index 12b3713d6df..303f19e9b45 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -101,7 +101,7 @@ //paralysis += 1 - show_message("\red The blob attacks you!") + show_message("The blob attacks you!") adjustFireLoss(damage) @@ -117,8 +117,8 @@ if(M.melee_damage_upper == 0) M.emote("[M.friendly] [src]") else - for(var/mob/O in viewers(src, null)) - O.show_message("\red [M] [M.attacktext] [src]!", 1) + visible_message("[M] [M.attacktext] [src]!", \ + "[M] [M.attacktext] [src]!") var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) adjustBruteLoss(damage) add_logs(M, src, "attacked", admin=0) @@ -146,9 +146,8 @@ return if (health > 0) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[M.name] bites [src]!"), 1) + visible_message("[M.name] bites [src]!", \ + "[M.name] bites [src]!") adjustBruteLoss(rand(1, 3)) updatehealth() return @@ -163,9 +162,8 @@ if (health > -100) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red The [M.name] glomps []!", src), 1) + visible_message("The [M.name] glomps [src]!", \ + "The [M.name] glomps [src]!") var/damage = rand(1, 3) @@ -209,9 +207,7 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has grabbed [] passively!", M, src), 1) + visible_message("[M] has grabbed [src] passively!") else var/damage = rand(1, 9) @@ -224,21 +220,19 @@ sleep(3) step_away(src,M,15) playsound(loc, "punch", 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has kicked []!", M, src), 1) + visible_message("[M] has kicked [src]!", \ + "[M] has kicked [src]!") if ((stat != DEAD) && (damage > 4.9)) Weaken(rand(5,10)) - for(var/mob/O in viewers(M, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has weakened []!", M, src), 1, "\red You hear someone fall.", 2) + visible_message("[M] has weakened [src]!", \ + "[M] has weakened [src]!", \ + "You hear someone fall.") adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has attempted to kick []!", M, src), 1) + visible_message("[M] has attempted to kick [src]!", \ + "[M] has attempted to kick [src]!") return /mob/living/carbon/alien/larva/attack_alien(mob/living/carbon/alien/humanoid/M as mob) @@ -260,21 +254,18 @@ AdjustParalysis(-3) AdjustStunned(-3) AdjustWeakened(-3) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\blue [M.name] nuzzles [] trying to wake it up!", src), 1) + visible_message("[M.name] nuzzles [src] trying to wake it up!") else if (health > 0) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) var/damage = rand(1, 3) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[M.name] bites []!", src), 1) + visible_message("[M.name] bites [src]!", \ + "[M.name] bites [src]!") adjustBruteLoss(damage) updatehealth() else - M << "\green [name] is too injured for that." + M << "[name] is too injured for that." return /mob/living/carbon/alien/larva/restrained() diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 5745bcea0e5..498fd4a2c5c 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -205,7 +205,7 @@ src << "You're completely exhausted." else src << "You feel fatigued." - if(dna && (dna.mutantrace == "skeleton") && !H.w_uniform && !H.wear_suit) + if(dna && (dna.species == /datum/species/skeleton) && !H.w_uniform && !H.wear_suit) H.play_xylophone() else if(ishuman(src)) @@ -458,13 +458,6 @@ ..(message, bubble_type) -/mob/living/carbon/proc/is_mutantrace(var/mrace) - if(mrace) - if(src.dna && src.dna.mutantrace == mrace) - return 1 - else - return src.dna && src.dna.mutantrace ? 1 : 0 - /mob/living/carbon/getTrail() if(getBruteLoss() < 300) if(prob(50)) diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 473707ff132..380d0de4cc3 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -8,7 +8,8 @@ ..() /mob/living/carbon/human/spawn_gibs() - hgibs(loc, viruses, dna) + if(dna) + hgibs(loc, viruses, dna) /mob/living/carbon/human/spawn_dust() new /obj/effect/decal/remains/human(loc) @@ -31,6 +32,9 @@ update_canmove() if(client) blind.layer = 0 + if(dna) + dna.species.spec_death(gibbed,src) + tod = worldtime2text() //weasellos time of death patch if(mind) mind.store_memory("Time of death: [tod]", 0) if(ticker && ticker.mode) @@ -40,11 +44,9 @@ return ..(gibbed) /mob/living/carbon/human/proc/makeSkeleton() - if(!check_dna_integrity(src) || (dna.mutantrace == "skeleton")) return - dna.mutantrace = "skeleton" + if(!check_dna_integrity(src)) return status_flags |= DISFIGURED - update_hair() - update_body() + dna.species = new /datum/species/skeleton(src) return 1 /mob/living/carbon/proc/ChangeToHusk() diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 7030742e370..773c4bf2b23 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -51,12 +51,12 @@ for(var/mob/M in range(tmob, 1)) if( ((M.pulling == tmob && ( tmob.restrained() && !( M.restrained() ) && M.stat == 0)) || locate(/obj/item/weapon/grab, tmob.grabbed_by.len)) ) if ( !(world.time % 5) ) - src << "\red [tmob] is restrained, you cannot push past" + src << "[tmob] is restrained, you cannot push past." now_pushing = 0 return if( tmob.pulling == M && ( M.restrained() && !( tmob.restrained() ) && tmob.stat == 0) ) if ( !(world.time % 5) ) - src << "\red [tmob] is restraining [M], you cannot push past" + src << "[tmob] is restraining [M], you cannot push past." now_pushing = 0 return @@ -198,7 +198,7 @@ /mob/living/carbon/human/blob_act() if(stat == 2) return - show_message("\red The blob attacks you!") + show_message(" The blob attacks you!") var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg") var/obj/item/organ/limb/affecting = get_organ(ran_zone(dam_zone)) apply_damage(rand(20,30), BRUTE, affecting, run_armor_check(affecting, "melee")) @@ -211,8 +211,8 @@ else if(M.attack_sound) playsound(loc, M.attack_sound, 50, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message("\red [M] [M.attacktext] [src]!", 1) + visible_message("[M] [M.attacktext] [src]!", \ + "[M] [M.attacktext]!") add_logs(M, src, "attacked", admin=0) var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg") @@ -227,9 +227,8 @@ if (health > -100) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red The [M.name] glomps []!", src), 1) + visible_message("The [M.name] glomps [src]!", \ + "The [M.name] glomps [src]!") var/damage = rand(1, 3) @@ -262,10 +261,8 @@ M.powerlevel -= 3 if(M.powerlevel < 0) M.powerlevel = 0 - - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red The [M.name] has shocked []!", src), 1) + visible_message("The [M.name] has shocked [src]!", \ + "The [M.name] has shocked [src]!") Weaken(power) if (stuttering < power) @@ -344,7 +341,7 @@ dat += "
Uniform: Obscured by [wear_suit]" else dat += "
Uniform: [(w_uniform && !(w_uniform.flags&ABSTRACT)) ? w_uniform : "Empty"]" - if(w_uniform) + if(w_uniform || dna.species.nojumpsuit) dat += "
[TAB]↳Belt: [(belt && !(belt.flags&ABSTRACT)) ? belt : "Empty"]" if(has_breathable_mask && istype(belt, /obj/item/weapon/tank)) dat += "
[TAB][TAB]↳[internal ? "Disable Internals" : "Set Internals"]" @@ -352,12 +349,31 @@ dat += " [(r_store && !(r_store.flags&ABSTRACT)) ? "Right (Full)" : "Right (Empty)"]" dat += "
[TAB]↳ID: [(wear_id && !(wear_id.flags&ABSTRACT)) ? wear_id : "Empty"]" + if(dna) + if(dna.species.nojumpsuit) + dat += "
ID: [(wear_id && !(wear_id.flags&ABSTRACT)) ? wear_id : "Nothing"]" + else if(w_uniform) + dat += "
ID: [(wear_id && !(wear_id.flags&ABSTRACT)) ? wear_id : "Nothing"]" + else if(w_uniform) + dat += "
ID: [(wear_id && !(wear_id.flags&ABSTRACT)) ? wear_id : "Nothing"]" + dat += "
" if(handcuffed) dat += "
Handcuffed: Remove" if(legcuffed) - dat += "
Legcuffed: Remove" + dat += "
Legcuffed" + + if(dna) + if(dna.species.nojumpsuit) + dat += "

Left Pocket ([(l_store && !(l_store.flags&ABSTRACT)) ? "Full" : "Empty"])" + dat += " - Right Pocket ([(r_store && !(r_store.flags&ABSTRACT)) ? "Full" : "Empty"])" + else if(w_uniform) + dat += "

Left Pocket ([(l_store && !(l_store.flags&ABSTRACT)) ? "Full" : "Empty"])" + dat += " - Right Pocket ([(r_store && !(r_store.flags&ABSTRACT)) ? "Full" : "Empty"])" + else if(w_uniform) + dat += "

Left Pocket ([(l_store && !(l_store.flags&ABSTRACT)) ? "Full" : "Empty"])" + dat += " - Right Pocket ([(r_store && !(r_store.flags&ABSTRACT)) ? "Full" : "Empty"])" dat += {"
@@ -467,7 +483,7 @@ H.handle_regular_hud_updates() if(!modified) - usr << "\red Unable to locate a data core entry for this person." + usr << "Unable to locate a data core entry for this person." /mob/living/carbon/human/proc/play_xylophone() if(!src.xylophone) @@ -516,4 +532,4 @@ if(obscured.len > 0) return obscured else - return null + return null diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm index 0d1ef146670..d703a7ab610 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -2,163 +2,9 @@ if(..()) //to allow surgery to return properly. return - if((M != src) && check_shields(0, M.name)) - add_logs(M, src, "attempted to touch") - visible_message("[M] attempted to touch [src]!") - return 0 + if(dna) + dna.species.spec_attack_hand(M, src) - switch(M.a_intent) - if("help") - if(health >= 0) - help_shake_act(M) - if(src != M) - add_logs(M, src, "shaked") - return 1 - - //CPR - if((M.head && (M.head.flags & HEADCOVERSMOUTH)) || (M.wear_mask && (M.wear_mask.flags & MASKCOVERSMOUTH))) - M << "Remove your mask!" - return 0 - if((head && (head.flags & HEADCOVERSMOUTH)) || (wear_mask && (wear_mask.flags & MASKCOVERSMOUTH))) - M << "Remove their mask!" - return 0 - - if(cpr_time < world.time + 30) - add_logs(src, M, "CPRed") - visible_message("[M] is trying to perform CPR on [src]!") - if(!do_mob(M, src)) - return 0 - if((health >= -99 && health <= 0)) - cpr_time = world.time - var/suff = min(getOxyLoss(), 7) - adjustOxyLoss(-suff) - updatehealth() - M.visible_message("[M] performs CPR on [src]!") - src << "You feel a breath of fresh air enter your lungs. It feels good." - - if("grab") - if(M == src || anchored) - return 0 - - add_logs(M, src, "grabbed", addition="passively") - - if(w_uniform) - w_uniform.add_fingerprint(M) - - var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src) - if(buckled) - M << "You cannot grab [src], \he is buckled in!" - if(!G) //the grab will delete itself in New if affecting is anchored - return - M.put_in_active_hand(G) - G.synch() - LAssailant = M - - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - visible_message("[M] has grabbed [src] passively!") - return 1 - - if("harm") - add_logs(M, src, "punched") - - var/attack_verb = "punch" - if(lying) - attack_verb = "kick" - else if(M.dna) - switch(M.dna.mutantrace) - if("lizard") - attack_verb = "scratch" - if("plant") - attack_verb = "slash" - - var/damage = rand(0, 9) - if(!damage) - switch(attack_verb) - if("slash") - playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1) - else - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - - visible_message("[M] has attempted to [attack_verb] [src]!") - return 0 - - - var/obj/item/organ/limb/affecting = get_organ(ran_zone(M.zone_sel.selecting)) - var/armor_block = run_armor_check(affecting, "melee") - - if(HULK in M.mutations) - damage += 5 - - switch(attack_verb) - if("slash") - playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) - else - playsound(loc, "punch", 25, 1, -1) - - visible_message("[M] has [attack_verb]ed [src]!", \ - "[M] has [attack_verb]ed [src]!") - - apply_damage(damage, BRUTE, affecting, armor_block) - if((stat != DEAD) && damage >= 9) - visible_message("[M] has weakened [src]!", \ - "[M] has weakened [src]!") - apply_effect(4, WEAKEN, armor_block) - forcesay(hit_appends) - else if(lying) - forcesay(hit_appends) - - if("disarm") - add_logs(M, src, "disarmed") - - if(w_uniform) - w_uniform.add_fingerprint(M) - var/obj/item/organ/limb/affecting = get_organ(ran_zone(M.zone_sel.selecting)) - var/randn = rand(1, 100) - if(randn <= 25) - apply_effect(2, WEAKEN, run_armor_check(affecting, "melee")) - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - visible_message("[M] has pushed [src]!", - "[M] has pushed [src]!") - forcesay(hit_appends) - return - - var/talked = 0 // BubbleWrap - - if(randn <= 60) - //BubbleWrap: Disarming breaks a pull - if(pulling) - visible_message("[M] has broken [src]'s grip on [pulling]!") - talked = 1 - stop_pulling() - - //BubbleWrap: Disarming also breaks a grab - this will also stop someone being choked, won't it? - if(istype(l_hand, /obj/item/weapon/grab)) - var/obj/item/weapon/grab/lgrab = l_hand - if(lgrab.affecting) - visible_message("[M] has broken [src]'s grip on [lgrab.affecting]!") - talked = 1 - spawn(1) - qdel(lgrab) - if(istype(r_hand, /obj/item/weapon/grab)) - var/obj/item/weapon/grab/rgrab = r_hand - if(rgrab.affecting) - visible_message("[M] has broken [src]'s grip on [rgrab.affecting]!") - talked = 1 - spawn(1) - qdel(rgrab) - //End BubbleWrap - - if(!talked) //BubbleWrap - if(drop_item()) - visible_message("[M] has disarmed [src]!", \ - "[M] has disarmed [src]!") - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - return - - - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - visible_message("[M] attempted to disarm [src]!", \ - "[M] attemped to disarm [src]!") return /mob/living/carbon/human/proc/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, inrange, params) diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index c1c1e7240f1..633e72059db 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -102,6 +102,7 @@ mob/living/carbon/human/proc/hat_fall_prob() var/obj/item/organ/limb/picked = pick(parts) if(picked.take_damage(brute,burn)) update_damage_overlays(0) + updatehealth() @@ -128,6 +129,7 @@ mob/living/carbon/human/proc/hat_fall_prob() // damage MANY external organs, in random order /mob/living/carbon/human/take_overall_damage(var/brute, var/burn) if(status_flags & GODMODE) return //godmode + var/list/obj/item/organ/limb/parts = get_damageable_organs() var/update = 0 while(parts.len && (brute>0 || burn>0) ) @@ -143,7 +145,9 @@ mob/living/carbon/human/proc/hat_fall_prob() burn -= (picked.burn_dam - burn_was) parts -= picked + updatehealth() + if(update) update_damage_overlays(0) @@ -159,34 +163,38 @@ mob/living/carbon/human/proc/hat_fall_prob() /mob/living/carbon/human/apply_damage(var/damage = 0,var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0) - if((damagetype != BRUTE) && (damagetype != BURN)) - ..(damage, damagetype, def_zone, blocked) - return 1 - - blocked = (100-blocked)/100 - if(blocked <= 0) return 0 - - var/obj/item/organ/limb/organ = null - if(isorgan(def_zone)) - organ = def_zone + if(dna) // if you have a species, it will run the apply_damage code there instead + dna.species.apply_damage(damage, damagetype, def_zone, blocked, src) else - if(!def_zone) def_zone = ran_zone(def_zone) - organ = get_organ(check_zone(def_zone)) - if(!organ) return 0 + if((damagetype != BRUTE) && (damagetype != BURN)) + ..(damage, damagetype, def_zone, blocked) + return 1 - damage = (damage * blocked) + else + blocked = (100-blocked)/100 + if(blocked <= 0) return 0 - switch(damagetype) - if(BRUTE) - damageoverlaytemp = 20 - if(organ.take_damage(damage, 0)) - update_damage_overlays(0) - if(BURN) - damageoverlaytemp = 20 - if(organ.take_damage(0, damage)) - update_damage_overlays(0) + var/obj/item/organ/limb/organ = null + if(isorgan(def_zone)) + organ = def_zone + else + if(!def_zone) def_zone = ran_zone(def_zone) + organ = get_organ(check_zone(def_zone)) + if(!organ) return 0 - // Will set our damageoverlay icon to the next level, which will then be set back to the normal level the next mob.Life(). + damage = (damage * blocked) - updatehealth() + switch(damagetype) + if(BRUTE) + damageoverlaytemp = 20 + if(organ.take_damage(damage, 0)) + update_damage_overlays(0) + if(BURN) + damageoverlaytemp = 20 + if(organ.take_damage(0, damage)) + update_damage_overlays(0) + + // Will set our damageoverlay icon to the next level, which will then be set back to the normal level the next mob.Life(). + + updatehealth() return 1 diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 76ef3e5583d..4048c7e762c 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -36,6 +36,11 @@ emp_act protection += C.armor[type] return protection +/mob/living/carbon/human/on_hit(proj_type) + if(dna) + dna.species.on_hit(proj_type, src) + return + /mob/living/carbon/human/bullet_act(var/obj/item/projectile/P, var/def_zone) if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)) if(check_reflect(def_zone)) // Checks if you've passed a reflection% check @@ -118,94 +123,93 @@ emp_act /mob/living/carbon/human/attacked_by(var/obj/item/I, var/mob/living/user, var/def_zone) if(!I || !user) return 0 + var/obj/item/organ/limb/target_limb = get_organ(user.zone_sel.selecting) var/obj/item/organ/limb/affecting = get_organ(ran_zone(user.zone_sel.selecting)) - var/hit_area = parse_zone(affecting.name) + var/target_area = parse_zone(target_limb.name) - if((user != src) && check_shields(I.force, "the [I.name]")) - return 0 + if(dna) // allows your species to affect the attacked_by code + return dna.species.spec_attacked_by(I,user,def_zone,affecting,hit_area,src.a_intent,target_limb,target_area,src) - if(I.attack_verb && I.attack_verb.len) - visible_message("[src] has been [pick(I.attack_verb)] in the [hit_area] with [I] by [user]!", \ - "[src] has been [pick(I.attack_verb)] in the [hit_area] with [I] by [user]!") - else if(I.force) - visible_message("[src] has been attacked in the [hit_area] with [I] by [user]!", \ - "[src] has been attacked in the [hit_area] with [I] by [user]!") else - return 0 + if((user != src) && check_shields(I.force, "the [I.name]")) + return 0 - var/armor = run_armor_check(affecting, "melee", "Your armour has protected your [hit_area].", "Your armour has softened a hit to your [hit_area].") - if(armor >= 100) return 0 - var/Iforce = I.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.attack_verb && I.attack_verb.len) + visible_message("[src] has been [pick(I.attack_verb)] in the [hit_area] with [I] by [user]!", \ + "[src] has been [pick(I.attack_verb)] in the [hit_area] with [I] by [user]!") + else if(I.force) + visible_message("[src] has been attacked in the [hit_area] with [I] by [user]!", \ + "[src] has been attacked in the [hit_area] with [I] by [user]!") + else + return 0 - apply_damage(I.force, I.damtype, affecting, armor , I) + var/armor = run_armor_check(affecting, "melee", "Your armour has protected your [hit_area].", "Your armour has softened a hit to your [hit_area].") + if(armor >= 100) return 0 + var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords) - var/bloody = 0 - if(((I.damtype == BRUTE) && prob(25 + (I.force * 2)))) - if(affecting.status == ORGAN_ORGANIC) - I.add_blood(src) //Make the weapon bloody, not the person. - if(prob(I.force * 2)) //blood spatter! - bloody = 1 - var/turf/location = loc - if(istype(location, /turf/simulated)) - location.add_blood(src) - if(ishuman(user)) - var/mob/living/carbon/human/H = user - if(get_dist(H, src) <= 1) //people with TK won't get smeared with blood - if(H.wear_suit) - H.wear_suit.add_blood(src) - H.update_inv_wear_suit(0) //updates mob overlays to show the new blood (no refresh) - else if(H.w_uniform) - H.w_uniform.add_blood(src) - H.update_inv_w_uniform(0) //updates mob overlays to show the new blood (no refresh) - if (H.gloves) - var/obj/item/clothing/gloves/G = H.gloves - G.add_blood(H) - else - H.add_blood(H) - H.update_inv_gloves() //updates on-mob overlays for bloody hands and/or bloody gloves + apply_damage(I.force, I.damtype, affecting, armor , I) + var/bloody = 0 + if(((I.damtype == BRUTE) && prob(25 + (I.force * 2)))) + if(affecting.status == ORGAN_ORGANIC) + I.add_blood(src) //Make the weapon bloody, not the person. + if(prob(I.force * 2)) //blood spatter! + bloody = 1 + var/turf/location = loc + if(istype(location, /turf/simulated)) + location.add_blood(src) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(get_dist(H, src) <= 1) //people with TK won't get smeared with blood + if(H.wear_suit) + H.wear_suit.add_blood(src) + H.update_inv_wear_suit(0) //updates mob overlays to show the new blood (no refresh) + else if(H.w_uniform) + H.w_uniform.add_blood(src) + H.update_inv_w_uniform(0) //updates mob overlays to show the new blood (no refresh) + if (H.gloves) + var/obj/item/clothing/gloves/G = H.gloves + G.add_blood(H) + else + H.add_blood(H) + H.update_inv_gloves() //updates on-mob overlays for bloody hands and/or bloody gloves - switch(hit_area) - if("head") //Harder to score a stun but if you do it lasts a bit longer - if(stat == CONSCIOUS && prob(I.force)) - if(Iforce >= 5) + switch(hit_area) + if("head") //Harder to score a stun but if you do it lasts a bit longer + if(stat == CONSCIOUS && prob(I.force)) visible_message("[src] has been knocked unconscious!", \ "[src] has been knocked unconscious!") apply_effect(20, PARALYZE, armor) if(src != user && I.damtype == BRUTE) ticker.mode.remove_revolutionary(mind) + 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(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(stat == CONSCIOUS && prob(I.force + 10)) - if(Iforce >= 5) + if("chest") //Easier to score a stun but lasts less time + if(stat == CONSCIOUS && prob(I.force + 10)) visible_message("[src] has been knocked down!", \ "[src] has been knocked down!") apply_effect(5, WEAKEN, armor) - if(bloody) - if(wear_suit) - wear_suit.add_blood(src) - update_inv_wear_suit(0) - if(w_uniform) - w_uniform.add_blood(src) - update_inv_w_uniform(0) - - if(Iforce > 10 || Iforce >= 5 && prob(33)) - forcesay(hit_appends) //forcesay checks stat already. - + if(bloody) + if(wear_suit) + wear_suit.add_blood(src) + update_inv_wear_suit(0) + if(w_uniform) + w_uniform.add_blood(src) + update_inv_w_uniform(0) + if(Iforce > 10 || Iforce >= 5 && prob(33)) + forcesay(hit_appends) //forcesay checks stat already /mob/living/carbon/human/emp_act(severity) var/informed = 0 diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index ba27693b4c6..3fffa8a5958 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -34,7 +34,7 @@ var/obj/item/l_store = null var/obj/item/s_store = null - var/base_icon_state = "caucasian1_m" + var/icon/base_icon_state = "caucasian1_m" var/list/organs = list() //Gets filled up in the constructor (human.dm, New() proc, line 24. I'm sick and tired of missing comments. -Agouri diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 6b59a125648..3af3219a129 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -119,4 +119,11 @@ return 1//Humans can use guns and such /mob/living/carbon/human/InCritical() - return (health <= config.health_threshold_crit && stat == UNCONSCIOUS) \ No newline at end of file + return (health <= config.health_threshold_crit && stat == UNCONSCIOUS) + +/mob/living/carbon/human/reagent_check(datum/reagent/R) + if(dna) + var/bypass = dna.species.handle_chemicals(R,src) + return bypass // if it returns 0, it will run the usual on_mob_life for that reagent. otherwise, it will stop after running handle_chemicals for the species. + else + return 0 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 905c9adaf4d..438fb8c650b 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -1,29 +1,6 @@ /mob/living/carbon/human/movement_delay() - if(!has_gravity(src)) - return -1 //It's hard to be slowed down in space by... anything - else if(status_flags & GOTTAGOFAST) - return -1 - - . = 0 - var/health_deficiency = (100 - health + staminaloss) - if(health_deficiency >= 40) - . += (health_deficiency / 25) - - var/hungry = (500 - nutrition) / 5 //So overeat would be 100 and default level would be 80 - if(hungry >= 70) - . += hungry / 50 - - if(wear_suit) - . += wear_suit.slowdown - if(shoes) - . += shoes.slowdown - if(back) - . += back.slowdown - - if(FAT in mutations) - . += 1.5 - if(bodytemperature < 283.222) - . += (283.222 - bodytemperature) / 10 * 1.75 + if(dna) + . += dna.species.movement_delay(src) . += ..() . += config.human_delay diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index ac1cddac276..9e99030ba8d 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -1,153 +1,156 @@ /mob/living/carbon/human/can_equip(obj/item/I, slot, disable_warning = 0) - switch(slot) - if(slot_l_hand) - if(l_hand) - return 0 - return 1 - if(slot_r_hand) - if(r_hand) - return 0 - return 1 - if(slot_wear_mask) - if(wear_mask) - return 0 - if( !(I.slot_flags & SLOT_MASK) ) - return 0 - return 1 - if(slot_back) - if(back) - return 0 - if( !(I.slot_flags & SLOT_BACK) ) - return 0 - return 1 - if(slot_wear_suit) - if(wear_suit) - return 0 - if( !(I.slot_flags & SLOT_OCLOTHING) ) - return 0 - return 1 - if(slot_gloves) - if(gloves) - return 0 - if( !(I.slot_flags & SLOT_GLOVES) ) - return 0 - return 1 - if(slot_shoes) - if(shoes) - return 0 - if( !(I.slot_flags & SLOT_FEET) ) - return 0 - return 1 - if(slot_belt) - if(belt) - return 0 - if(!w_uniform) - if(!disable_warning) - src << "\red You need a jumpsuit before you can attach this [I.name]." - return 0 - if( !(I.slot_flags & SLOT_BELT) ) - return - return 1 - if(slot_glasses) - if(glasses) - return 0 - if( !(I.slot_flags & SLOT_EYES) ) - return 0 - return 1 - if(slot_head) - if(head) - return 0 - if( !(I.slot_flags & SLOT_HEAD) ) - return 0 - return 1 - if(slot_ears) - if(ears) - return 0 - if( !(I.slot_flags & SLOT_EARS) ) - return 0 - return 1 - if(slot_w_uniform) - if(w_uniform) - return 0 - if( !(I.slot_flags & SLOT_ICLOTHING) ) - return 0 - return 1 - if(slot_wear_id) - if(wear_id) - return 0 - if(!w_uniform) - if(!disable_warning) - src << "\red You need a jumpsuit before you can attach this [I.name]." - return 0 - if( !(I.slot_flags & SLOT_ID) ) - return 0 - return 1 - if(slot_l_store) - if(I.flags & NODROP) //Pockets aren't visible, so you can't move NODROP items into them. - return 0 - if(l_store) - return 0 - if(!w_uniform) - if(!disable_warning) - src << "\red You need a jumpsuit before you can attach this [I.name]." - return 0 - if(I.slot_flags & SLOT_DENYPOCKET) - return - if( I.w_class <= 2 || (I.slot_flags & SLOT_POCKET) ) + if(dna) + return dna.species.can_equip(I, slot, disable_warning, src) + else + switch(slot) + if(slot_l_hand) + if(l_hand) + return 0 return 1 - if(slot_r_store) - if(I.flags & NODROP) - return 0 - if(r_store) - return 0 - if(!w_uniform) - if(!disable_warning) - src << "\red You need a jumpsuit before you can attach this [I.name]." - return 0 - if(I.slot_flags & SLOT_DENYPOCKET) - return 0 - if( I.w_class <= 2 || (I.slot_flags & SLOT_POCKET) ) + if(slot_r_hand) + if(r_hand) + return 0 return 1 - return 0 - if(slot_s_store) - if(I.flags & NODROP) //Suit storage NODROP items drop if you take a suit off, this is to prevent people exploiting this. - return 0 - if(s_store) - return 0 - if(!wear_suit) - if(!disable_warning) - src << "\red You need a suit before you can attach this [I.name]." - return 0 - if(!wear_suit.allowed) - if(!disable_warning) - usr << "You somehow have a suit with no defined allowed items for suit storage, stop that." //should be src? - return 0 - if(I.w_class > 4) - if(!disable_warning) - usr << "The [I.name] is too big to attach." //should be src? - return 0 - if( istype(I, /obj/item/device/pda) || istype(I, /obj/item/weapon/pen) || is_type_in_list(I, wear_suit.allowed) ) //ugly and un-polymorphic. + if(slot_wear_mask) + if(wear_mask) + return 0 + if( !(I.slot_flags & SLOT_MASK) ) + return 0 return 1 - return 0 - if(slot_handcuffed) - if(handcuffed) - return 0 - if(!istype(I, /obj/item/weapon/handcuffs)) - return 0 - return 1 - if(slot_legcuffed) - if(legcuffed) - return 0 - if(!istype(I, /obj/item/weapon/legcuffs)) - return 0 - return 1 - if(slot_in_backpack) - if (back && istype(back, /obj/item/weapon/storage/backpack)) - var/obj/item/weapon/storage/backpack/B = back - if(B.contents.len < B.storage_slots && I.w_class <= B.max_w_class) + if(slot_back) + if(back) + return 0 + if( !(I.slot_flags & SLOT_BACK) ) + return 0 + return 1 + if(slot_wear_suit) + if(wear_suit) + return 0 + if( !(I.slot_flags & SLOT_OCLOTHING) ) + return 0 + return 1 + if(slot_gloves) + if(gloves) + return 0 + if( !(I.slot_flags & SLOT_GLOVES) ) + return 0 + return 1 + if(slot_shoes) + if(shoes) + return 0 + if( !(I.slot_flags & SLOT_FEET) ) + return 0 + return 1 + if(slot_belt) + if(belt) + return 0 + if(!w_uniform) + if(!disable_warning) + src << "\red You need a jumpsuit before you can attach this [I.name]." + return 0 + if( !(I.slot_flags & SLOT_BELT) ) + return + return 1 + if(slot_glasses) + if(glasses) + return 0 + if( !(I.slot_flags & SLOT_EYES) ) + return 0 + return 1 + if(slot_head) + if(head) + return 0 + if( !(I.slot_flags & SLOT_HEAD) ) + return 0 + return 1 + if(slot_ears) + if(ears) + return 0 + if( !(I.slot_flags & SLOT_EARS) ) + return 0 + return 1 + if(slot_w_uniform) + if(w_uniform) + return 0 + if( !(I.slot_flags & SLOT_ICLOTHING) ) + return 0 + return 1 + if(slot_wear_id) + if(wear_id) + return 0 + if(!w_uniform) + if(!disable_warning) + src << "\red You need a jumpsuit before you can attach this [I.name]." + return 0 + if( !(I.slot_flags & SLOT_ID) ) + return 0 + return 1 + if(slot_l_store) + if(I.flags & NODROP) //Pockets aren't visible, so you can't move NODROP items into them. + return 0 + if(l_store) + return 0 + if(!w_uniform) + if(!disable_warning) + src << "\red You need a jumpsuit before you can attach this [I.name]." + return 0 + if(I.slot_flags & SLOT_DENYPOCKET) + return + if( I.w_class <= 2 || (I.slot_flags & SLOT_POCKET) ) return 1 - return 0 - return 0 //Unsupported slot + if(slot_r_store) + if(I.flags & NODROP) + return 0 + if(r_store) + return 0 + if(!w_uniform) + if(!disable_warning) + src << "\red You need a jumpsuit before you can attach this [I.name]." + return 0 + if(I.slot_flags & SLOT_DENYPOCKET) + return 0 + if( I.w_class <= 2 || (I.slot_flags & SLOT_POCKET) ) + return 1 + return 0 + if(slot_s_store) + if(I.flags & NODROP) //Suit storage NODROP items drop if you take a suit off, this is to prevent people exploiting this. + return 0 + if(s_store) + return 0 + if(!wear_suit) + if(!disable_warning) + src << "\red You need a suit before you can attach this [I.name]." + return 0 + if(!wear_suit.allowed) + if(!disable_warning) + usr << "You somehow have a suit with no defined allowed items for suit storage, stop that." //should be src? + return 0 + if(I.w_class > 4) + if(!disable_warning) + usr << "The [I.name] is too big to attach." //should be src? + return 0 + if( istype(I, /obj/item/device/pda) || istype(I, /obj/item/weapon/pen) || is_type_in_list(I, wear_suit.allowed) ) //ugly and un-polymorphic. + return 1 + return 0 + if(slot_handcuffed) + if(handcuffed) + return 0 + if(!istype(I, /obj/item/weapon/handcuffs)) + return 0 + return 1 + if(slot_legcuffed) + if(legcuffed) + return 0 + if(!istype(I, /obj/item/weapon/legcuffs)) + return 0 + return 1 + if(slot_in_backpack) + if (back && istype(back, /obj/item/weapon/storage/backpack)) + var/obj/item/weapon/storage/backpack/B = back + if(B.contents.len < B.storage_slots && I.w_class <= B.max_w_class) + return 1 + return 0 + return 0 //Unsupported slot @@ -383,5 +386,4 @@ return else src << "\red You are trying to equip this item to an unsupported inventory slot. Report this to a coder!" - return - + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 341bc28445e..65d0d00b9b0 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -1,6 +1,11 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 //NOTE: Breathing happens once per FOUR TICKS, unless the last breath fails. In which case it happens once per ONE TICK! So oxyloss healing is done once per 4 ticks while oxyloss damage is applied once per tick! + + +#define TINT_IMPAIR 2 //Threshold of tint level to apply weld mask overlay +#define TINT_BLIND 3 //Threshold of tint level to obscure vision fully + #define HUMAN_MAX_OXYLOSS 3 //Defines how much oxyloss humans can get per tick. A tile with no air at all (such as space) applies this value, otherwise it's a percentage of it. #define HUMAN_CRIT_MAX_OXYLOSS ( (last_tick_duration) /3) //The amount of damage you'll get when in critical condition. We want this to be a 5 minute deal = 300s. There are 100HP to get through, so (1/3)*last_tick_duration per second. Breaths however only happen every 4 ticks. @@ -21,9 +26,6 @@ #define COLD_GAS_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when the current breath's temperature passes the 200K point #define COLD_GAS_DAMAGE_LEVEL_3 3 //Amount of damage applied when the current breath's temperature passes the 120K point -#define TINT_IMPAIR 2 //Threshold of tint level to apply weld mask overlay -#define TINT_BLIND 3 //Threshold of tint level to obscure vision fully - /mob/living/carbon/human var/oxygen_alert = 0 var/toxins_alert = 0 @@ -51,7 +53,6 @@ fire_alert = 0 //Reset this here, because both breathe() and handle_environment() have a chance to set it. tinttotal = tintcheck() //here as both hud updates and status updates call it - //TODO: seperate this out var/datum/gas_mixture/environment = loc.return_air() @@ -98,6 +99,9 @@ handle_regular_hud_updates() + if(dna) + dna.species.spec_life(src) // for mutantraces + // Grabbing for(var/obj/item/weapon/grab/G in src) G.process() @@ -163,132 +167,14 @@ proc/handle_mutations_and_radiation() - if(getFireLoss()) - if((COLD_RESISTANCE in mutations) || (prob(1))) - heal_organ_damage(0,1) - - if ((HULK in mutations) && health <= 25) - mutations.Remove(HULK) - update_mutations() //update our mutation overlays - src << "\red You suddenly feel very weak." - Weaken(3) - emote("collapse") - - if (radiation) - if (radiation > 100) - radiation = 100 - Weaken(10) - src << "\red You feel weak." - emote("collapse") - - if (radiation < 0) - radiation = 0 - - else - switch(radiation) - if(1 to 49) - radiation-- - if(prob(25)) - adjustToxLoss(1) - updatehealth() - - if(50 to 74) - radiation -= 2 - adjustToxLoss(1) - if(prob(5)) - radiation -= 5 - Weaken(3) - src << "\red You feel weak." - emote("collapse") - if(prob(15)) - if(!( hair_style == "Shaved") || !(hair_style == "Bald")) - src << "Your hair starts to fall out in clumps..." - spawn(50) - facial_hair_style = "Shaved" - hair_style = "Bald" - update_hair() - updatehealth() - - if(75 to 100) - radiation -= 3 - adjustToxLoss(3) - if(prob(1)) - src << "\red You mutate!" - randmutb(src) - domutcheck(src,null) - emote("gasp") - updatehealth() - + if(dna) + dna.species.handle_mutations_and_radiation(src) proc/breathe() + if(dna) + dna.species.breathe(src) - if(reagents.has_reagent("lexorin")) return - if(istype(loc, /obj/machinery/atmospherics/unary/cryo_cell)) return - - var/datum/gas_mixture/environment = loc.return_air() - var/datum/gas_mixture/breath - // HACK NEED CHANGING LATER - if(health <= config.health_threshold_crit) - losebreath++ - - if(losebreath>0) //Suffocating so do not take a breath - losebreath-- - if (prob(10)) //Gasp per 10 ticks? Sounds about right. - spawn emote("gasp") - if(istype(loc, /obj/)) - var/obj/location_as_object = loc - location_as_object.handle_internal_lifeform(src, 0) - else - //First, check for air from internal atmosphere (using an air tank and mask generally) - breath = get_breath_from_internal(BREATH_VOLUME) // Super hacky -- TLE - //breath = get_breath_from_internal(0.5) // Manually setting to old BREATH_VOLUME amount -- TLE - - //No breath from internal atmosphere so get breath from location - if(!breath) - if(isobj(loc)) - var/obj/location_as_object = loc - breath = location_as_object.handle_internal_lifeform(src, BREATH_VOLUME) - else if(isturf(loc)) - var/breath_moles = 0 - /*if(environment.return_pressure() > ONE_ATMOSPHERE) - // Loads of air around (pressure effect will be handled elsewhere), so lets just take a enough to fill our lungs at normal atmos pressure (using n = Pv/RT) - breath_moles = (ONE_ATMOSPHERE*BREATH_VOLUME/R_IDEAL_GAS_EQUATION*environment.temperature) - else*/ - // Not enough air around, take a percentage of what's there to model this properly - breath_moles = environment.total_moles()*BREATH_PERCENTAGE - - breath = loc.remove_air(breath_moles) - // Handle chem smoke effect -- Doohl - var/block = 0 - if(wear_mask) - if(wear_mask.flags & BLOCK_GAS_SMOKE_EFFECT) - block = 1 - if(glasses) - if(glasses.flags & BLOCK_GAS_SMOKE_EFFECT) - block = 1 - if(head) - if(head.flags & BLOCK_GAS_SMOKE_EFFECT) - block = 1 - - if(!block) - - for(var/obj/effect/effect/chem_smoke/smoke in view(1, src)) - if(smoke.reagents.total_volume) - smoke.reagents.reaction(src, INGEST) - spawn(5) - if(smoke) - smoke.reagents.copy_to(src, 10) // I dunno, maybe the reagents enter the blood stream through the lungs? - break // If they breathe in the nasty stuff once, no need to continue checking - - else //Still give containing object the chance to interact - if(istype(loc, /obj/)) - var/obj/location_as_object = loc - location_as_object.handle_internal_lifeform(src, 0) - - handle_breath(breath) - - if(breath) - loc.assume_air(breath) + return proc/get_breath_from_internal(volume_needed) @@ -304,229 +190,45 @@ return null - proc/handle_breath(datum/gas_mixture/breath) + /*proc/handle_breath(datum/gas_mixture/breath) if((status_flags & GODMODE)) return - if(!breath || (breath.total_moles() == 0) || suiciding) - if(reagents.has_reagent("inaprovaline")) - return - if(suiciding) - adjustOxyLoss(2)//If you are suiciding, you should die a little bit faster - failed_last_breath = 1 - oxygen_alert = max(oxygen_alert, 1) - return 0 - if(health >= config.health_threshold_crit) - adjustOxyLoss(HUMAN_MAX_OXYLOSS) - failed_last_breath = 1 - else - adjustOxyLoss(HUMAN_CRIT_MAX_OXYLOSS) - failed_last_breath = 1 + if(dna) + dna.species.handle_breath(breath) - oxygen_alert = max(oxygen_alert, 1) - - return 0 - - var/safe_oxygen_min = 16 // Minimum safe partial pressure of O2, in kPa - //var/safe_oxygen_max = 140 // Maximum safe partial pressure of O2, in kPa (Not used for now) - var/safe_co2_max = 10 // Yes it's an arbitrary value who cares? - var/safe_toxins_max = 0.005 - var/SA_para_min = 1 - var/SA_sleep_min = 5 - var/oxygen_used = 0 - var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME - - //Partial pressure of the O2 in our breath - var/O2_pp = (breath.oxygen/breath.total_moles())*breath_pressure - // Same, but for the toxins - var/Toxins_pp = (breath.toxins/breath.total_moles())*breath_pressure - // And CO2, lets say a PP of more than 10 will be bad (It's a little less really, but eh, being passed out all round aint no fun) - var/CO2_pp = (breath.carbon_dioxide/breath.total_moles())*breath_pressure // Tweaking to fit the hacky bullshit I've done with atmo -- TLE - //var/CO2_pp = (breath.carbon_dioxide/breath.total_moles())*0.5 // The default pressure value - - if(O2_pp < safe_oxygen_min) // Too little oxygen - if(prob(20)) - spawn(0) emote("gasp") - if(O2_pp > 0) - var/ratio = safe_oxygen_min/O2_pp - adjustOxyLoss(min(5*ratio, HUMAN_MAX_OXYLOSS)) // Don't fuck them up too fast (space only does HUMAN_MAX_OXYLOSS after all!) - failed_last_breath = 1 - oxygen_used = breath.oxygen*ratio/6 - else - adjustOxyLoss(HUMAN_MAX_OXYLOSS) - failed_last_breath = 1 - oxygen_alert = max(oxygen_alert, 1) - /*else if (O2_pp > safe_oxygen_max) // Too much oxygen (commented this out for now, I'll deal with pressure damage elsewhere I suppose) - spawn(0) emote("cough") - var/ratio = O2_pp/safe_oxygen_max - oxyloss += 5*ratio - oxygen_used = breath.oxygen*ratio/6 - oxygen_alert = max(oxygen_alert, 1)*/ - else // We're in safe limits - failed_last_breath = 0 - adjustOxyLoss(-5) - oxygen_used = breath.oxygen/6 - oxygen_alert = 0 - - breath.oxygen -= oxygen_used - breath.carbon_dioxide += oxygen_used - - //CO2 does not affect failed_last_breath. So if there was enough oxygen in the air but too much co2, this will hurt you, but only once per 4 ticks, instead of once per tick. - if(CO2_pp > safe_co2_max) - if(!co2overloadtime) // If it's the first breath with too much CO2 in it, lets start a counter, then have them pass out after 12s or so. - co2overloadtime = world.time - else if(world.time - co2overloadtime > 120) - Paralyse(3) - adjustOxyLoss(3) // Lets hurt em a little, let them know we mean business - if(world.time - co2overloadtime > 300) // They've been in here 30s now, lets start to kill them for their own good! - adjustOxyLoss(8) - if(prob(20)) // Lets give them some chance to know somethings not right though I guess. - spawn(0) emote("cough") - - else - co2overloadtime = 0 - - if(Toxins_pp > safe_toxins_max) // Too much toxins - var/ratio = (breath.toxins/safe_toxins_max) * 10 - //adjustToxLoss(Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE)) //Limit amount of damage toxin exposure can do per second - if(reagents) - reagents.add_reagent("plasma", Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE)) - toxins_alert = max(toxins_alert, 1) - else - toxins_alert = 0 - - if(breath.trace_gases.len) // If there's some other shit in the air lets deal with it here. - for(var/datum/gas/sleeping_agent/SA in breath.trace_gases) - var/SA_pp = (SA.moles/breath.total_moles())*breath_pressure - if(SA_pp > SA_para_min) // Enough to make us paralysed for a bit - Paralyse(3) // 3 gives them one second to wake up and run away a bit! - if(SA_pp > SA_sleep_min) // Enough to make us sleep as well - sleeping = max(sleeping+2, 10) - else if(SA_pp > 0.01) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning - if(prob(20)) - spawn(0) emote(pick("giggle", "laugh")) - - if( (abs(310.15 - breath.temperature) > 50) && !(COLD_RESISTANCE in mutations)) // Hot air hurts :( - if(breath.temperature < 260.15) - if(prob(20)) - src << "\red You feel your face freezing and an icicle forming in your lungs!" - else if(breath.temperature > 360.15) - if(prob(20)) - src << "\red You feel your face burning and a searing heat in your lungs!" - - switch(breath.temperature) - if(-INFINITY to 120) - apply_damage(COLD_GAS_DAMAGE_LEVEL_3, BURN, "head") - fire_alert = max(fire_alert, 1) - if(120 to 200) - apply_damage(COLD_GAS_DAMAGE_LEVEL_2, BURN, "head") - fire_alert = max(fire_alert, 1) - if(200 to 260) - apply_damage(COLD_GAS_DAMAGE_LEVEL_1, BURN, "head") - fire_alert = max(fire_alert, 1) - if(360 to 400) - apply_damage(HEAT_GAS_DAMAGE_LEVEL_1, BURN, "head") - fire_alert = max(fire_alert, 2) - if(400 to 1000) - apply_damage(HEAT_GAS_DAMAGE_LEVEL_2, BURN, "head") - fire_alert = max(fire_alert, 2) - if(1000 to INFINITY) - apply_damage(HEAT_GAS_DAMAGE_LEVEL_3, BURN, "head") - fire_alert = max(fire_alert, 2) - - //Temporary fixes to the alerts. - - return 1 + return 1*/ proc/handle_environment(datum/gas_mixture/environment) - if(!environment) - return - - var/loc_temp = get_temperature(environment) - //world << "Loc temp: [loc_temp] - Body temp: [bodytemperature] - Fireloss: [getFireLoss()] - Thermal protection: [get_thermal_protection()] - Fire protection: [thermal_protection + add_fire_protection(loc_temp)] - Heat capacity: [environment_heat_capacity] - Location: [loc] - src: [src]" - - //Body temperature is adjusted in two steps. Firstly your body tries to stabilize itself a bit. - if(stat != 2) - stabilize_temperature_from_calories() - - //After then, it reacts to the surrounding atmosphere based on your thermal protection - if(!on_fire) //If you're on fire, you do not heat up or cool down based on surrounding gases - if(loc_temp < bodytemperature) - //Place is colder than we are - var/thermal_protection = get_cold_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. - if(thermal_protection < 1) - bodytemperature += min((1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_COLD_DIVISOR), BODYTEMP_COOLING_MAX) - else - //Place is hotter than we are - var/thermal_protection = get_heat_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. - if(thermal_protection < 1) - bodytemperature += min((1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_HEAT_DIVISOR), BODYTEMP_HEATING_MAX) - - // +/- 50 degrees from 310.15K is the 'safe' zone, where no damage is dealt. - if(bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT) - //Body temperature is too hot. - fire_alert = max(fire_alert, 1) - switch(bodytemperature) - if(360 to 400) - apply_damage(HEAT_DAMAGE_LEVEL_1, BURN) - fire_alert = max(fire_alert, 2) - if(400 to 460) - apply_damage(HEAT_DAMAGE_LEVEL_2, BURN) - fire_alert = max(fire_alert, 2) - if(460 to INFINITY) - if(on_fire) - apply_damage(HEAT_DAMAGE_LEVEL_3, BURN) - fire_alert = max(fire_alert, 2) - else - apply_damage(HEAT_DAMAGE_LEVEL_2, BURN) - fire_alert = max(fire_alert, 2) - - else if(bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT) - fire_alert = max(fire_alert, 1) - if(!istype(loc, /obj/machinery/atmospherics/unary/cryo_cell)) - switch(bodytemperature) - if(200 to 260) - apply_damage(COLD_DAMAGE_LEVEL_1, BURN) - fire_alert = max(fire_alert, 1) - if(120 to 200) - apply_damage(COLD_DAMAGE_LEVEL_2, BURN) - fire_alert = max(fire_alert, 1) - if(-INFINITY to 120) - apply_damage(COLD_DAMAGE_LEVEL_3, BURN) - fire_alert = max(fire_alert, 1) - - // Account for massive pressure differences. Done by Polymorph - // Made it possible to actually have something that can protect against high pressure... Done by Errorage. Polymorph now has an axe sticking from his head for his previous hardcoded nonsense! - - var/pressure = environment.return_pressure() - var/adjusted_pressure = calculate_affecting_pressure(pressure) //Returns how much pressure actually affects the mob. - switch(adjusted_pressure) - if(HAZARD_HIGH_PRESSURE to INFINITY) - adjustBruteLoss( min( ( (adjusted_pressure / HAZARD_HIGH_PRESSURE) -1 )*PRESSURE_DAMAGE_COEFFICIENT , MAX_HIGH_PRESSURE_DAMAGE) ) - pressure_alert = 2 - if(WARNING_HIGH_PRESSURE to HAZARD_HIGH_PRESSURE) - pressure_alert = 1 - if(WARNING_LOW_PRESSURE to WARNING_HIGH_PRESSURE) - pressure_alert = 0 - if(HAZARD_LOW_PRESSURE to WARNING_LOW_PRESSURE) - pressure_alert = -1 - else - if( !(COLD_RESISTANCE in mutations) ) - adjustBruteLoss( LOW_PRESSURE_DAMAGE ) - pressure_alert = -2 - else - pressure_alert = -1 + if(dna) + dna.species.handle_environment(environment, src) return ///FIRE CODE handle_fire() + if(dna) + dna.species.handle_fire(src) + if(..()) return var/thermal_protection = get_heat_protection(30000) //If you don't have fire suit level protection, you get a temperature increase if((1 - thermal_protection) > 0.0001) bodytemperature += BODYTEMP_HEATING_MAX return + + IgniteMob() + if(dna) + dna.species.IgniteMob(src) + else + ..() + + ExtinguishMob() + if(dna) + dna.species.ExtinguishMob(src) + else + ..() + //END FIRE CODE /* @@ -650,6 +352,9 @@ if(COLD_RESISTANCE in mutations) return 1 //Fully protected from the cold. + if(dna && COLDRES in dna.species.specflags) + return 1 + temperature = max(temperature, 2.7) //There is an occasional bug where the temperature is miscalculated in ares with a small amount of gas on them, so this is necessary to ensure that that bug does not affect this calculation. Space's temperature is 2.7K and most suits that are intended to protect against any cold, protect down to 2.0K. var/thermal_protection_flags = get_cold_protection_flags(temperature) @@ -739,82 +444,8 @@ */ proc/handle_chemicals_in_body() - if(reagents) reagents.metabolize(src) - - if(dna && dna.mutantrace == "plant") //couldn't think of a better place to place it, since it handles nutrition -- Urist - var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing - if(isturf(loc)) //else, there's considered to be no light - var/turf/T = loc - var/area/A = T.loc - if(A) - if(A.lighting_use_dynamic) light_amount = min(10,T.lighting_lumcount) - 5 //hardcapped so it's not abused by having a ton of flashlights - else light_amount = 5 - nutrition += light_amount - if(nutrition > 500) - nutrition = 500 - if(light_amount > 2) //if there's enough light, heal - heal_overall_damage(1,1) - adjustToxLoss(-1) - adjustOxyLoss(-1) - if(dna && dna.mutantrace == "shadow") - var/light_amount = 0 - if(isturf(loc)) - var/turf/T = loc - var/area/A = T.loc - if(A) - if(A.lighting_use_dynamic) light_amount = T.lighting_lumcount - else light_amount = 10 - if(light_amount > 2) //if there's enough light, start dying - take_overall_damage(1,1) - else if (light_amount < 2) //heal in the dark - heal_overall_damage(1,1) - - //The fucking FAT mutation is the dumbest shit ever. It makes the code so difficult to work with - if(FAT in mutations) - if(overeatduration < 100) - src << "\blue You feel fit again!" - mutations -= FAT - update_inv_w_uniform(0) - update_inv_wear_suit() - else - if(overeatduration > 500) - src << "\red You suddenly feel blubbery!" - mutations |= FAT - update_inv_w_uniform(0) - update_inv_wear_suit() - - // nutrition decrease - if (nutrition > 0 && stat != 2) - nutrition = max (0, nutrition - HUNGER_FACTOR) - - if (nutrition > 450) - if(overeatduration < 600) //capped so people don't take forever to unfat - overeatduration++ - else - if(overeatduration > 1) - overeatduration -= 2 //doubled the unfat rate - - if(dna && dna.mutantrace == "plant") - if(nutrition < 200) - take_overall_damage(2,0) - - if (drowsyness) - drowsyness-- - eye_blurry = max(2, eye_blurry) - if (prob(5)) - sleeping += 1 - Paralyse(5) - - confused = max(0, confused - 1) - // decrement dizziness counter, clamped to 0 - if(resting) - dizziness = max(0, dizziness - 15) - jitteriness = max(0, jitteriness - 15) - else - dizziness = max(0, dizziness - 3) - jitteriness = max(0, jitteriness - 3) - - updatehealth() + if(dna) + dna.species.handle_chemicals_in_body(src) return //TODO: DEFERRED @@ -1048,155 +679,15 @@ damageoverlay.overlays += I damageoverlay.overlays += black - if( stat == DEAD ) - sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS) - see_in_dark = 8 - if(!druggy) see_invisible = SEE_INVISIBLE_LEVEL_TWO - if(healths) healths.icon_state = "health7" //DEAD healthmeter - else - sight &= ~(SEE_TURFS|SEE_MOBS|SEE_OBJS) - var/see_temp = see_invisible - see_invisible = SEE_INVISIBLE_LIVING - if(dna) - switch(dna.mutantrace) - if("slime") - see_in_dark = 3 - see_invisible = SEE_INVISIBLE_LEVEL_ONE - if("shadow") - see_in_dark = 8 - else - see_in_dark = 2 - - if(XRAY in mutations) - sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS - see_in_dark = 8 - see_invisible = SEE_INVISIBLE_LEVEL_TWO - - if(seer) - see_invisible = SEE_INVISIBLE_OBSERVER - - if(mind && mind.changeling) - hud_used.lingchemdisplay.invisibility = 0 - hud_used.lingchemdisplay.maptext = "
[src.mind.changeling.chem_charges]
" - else - hud_used.lingchemdisplay.invisibility = 101 - - if(istype(wear_mask, /obj/item/clothing/mask/gas/voice/space_ninja)) - var/obj/item/clothing/mask/gas/voice/space_ninja/O = wear_mask - switch(O.mode) - if(0) - var/target_list[] = list() - for(var/mob/living/target in oview(src)) - if( target.mind&&(target.mind.special_role||issilicon(target)) )//They need to have a mind. - target_list += target - if(target_list.len)//Everything else is handled by the ninja mask proc. - O.assess_targets(target_list, src) - see_invisible = SEE_INVISIBLE_LIVING - if(1) - see_in_dark = 5 - see_invisible = SEE_INVISIBLE_LIVING - if(2) - sight |= SEE_MOBS - see_invisible = SEE_INVISIBLE_LEVEL_TWO - if(3) - sight |= SEE_TURFS - see_invisible = SEE_INVISIBLE_LIVING - - if(glasses) - if(istype(glasses, /obj/item/clothing/glasses)) - var/obj/item/clothing/glasses/G = glasses - sight |= G.vision_flags - see_in_dark = G.darkness_view - see_invisible = G.invis_view - if(G.hud) - G.process_hud(src) - - if(druggy) //Override for druggy - see_invisible = see_temp - - if(see_override) //Override all - see_invisible = see_override - - if(healths) - switch(hal_screwyhud) - if(1) healths.icon_state = "health6" - if(2) healths.icon_state = "health7" - else - switch(health - staminaloss) - if(100 to INFINITY) healths.icon_state = "health0" - if(80 to 100) healths.icon_state = "health1" - if(60 to 80) healths.icon_state = "health2" - if(40 to 60) healths.icon_state = "health3" - if(20 to 40) healths.icon_state = "health4" - if(0 to 20) healths.icon_state = "health5" - else healths.icon_state = "health6" - - if(nutrition_icon) - switch(nutrition) - if(450 to INFINITY) nutrition_icon.icon_state = "nutrition0" - if(350 to 450) nutrition_icon.icon_state = "nutrition1" - if(250 to 350) nutrition_icon.icon_state = "nutrition2" - if(150 to 250) nutrition_icon.icon_state = "nutrition3" - else nutrition_icon.icon_state = "nutrition4" - - if(pressure) - pressure.icon_state = "pressure[pressure_alert]" - - if(pullin) - if(pulling) pullin.icon_state = "pull" - else pullin.icon_state = "pull0" -// if(rest) //Not used with new UI -// if(resting || lying || sleeping) rest.icon_state = "rest1" -// else rest.icon_state = "rest0" - if(toxin) - if(hal_screwyhud == 4 || toxins_alert) toxin.icon_state = "tox1" - else toxin.icon_state = "tox0" - if(oxygen) - if(hal_screwyhud == 3 || oxygen_alert) oxygen.icon_state = "oxy1" - else oxygen.icon_state = "oxy0" - if(fire) - if(fire_alert) fire.icon_state = "fire[fire_alert]" //fire_alert is either 0 if no alert, 1 for cold and 2 for heat. - else fire.icon_state = "fire0" - - if(bodytemp) - switch(bodytemperature) //310.055 optimal body temp - if(370 to INFINITY) bodytemp.icon_state = "temp4" - if(350 to 370) bodytemp.icon_state = "temp3" - if(335 to 350) bodytemp.icon_state = "temp2" - if(320 to 335) bodytemp.icon_state = "temp1" - if(300 to 320) bodytemp.icon_state = "temp0" - if(295 to 300) bodytemp.icon_state = "temp-1" - if(280 to 295) bodytemp.icon_state = "temp-2" - if(260 to 280) bodytemp.icon_state = "temp-3" - else bodytemp.icon_state = "temp-4" - -// This checks how much the mob's eyewear impairs their vision - if(tinttotal >= TINT_IMPAIR) - if(tinted_weldhelh) - if(tinttotal >= TINT_BLIND) - blinded = 1 // You get the sudden urge to learn to play keyboard - client.screen += global_hud.darkMask - else - client.screen += global_hud.darkMask - - if(blind) - if(blinded) blind.layer = 18 - else blind.layer = 0 - - if( disabilities & NEARSIGHTED && !istype(glasses, /obj/item/clothing/glasses/regular) ) - client.screen += global_hud.vimpaired - if(eye_blurry) client.screen += global_hud.blurry - if(druggy) client.screen += global_hud.druggy - - - if(eye_stat > 20) - if(eye_stat > 30) client.screen += global_hud.darkMask - else client.screen += global_hud.vimpaired - if(machine) if(!machine.check_eye(src)) reset_view(null) else if(!client.adminobs) reset_view(null) + + if(dna) + dna.species.handle_vision(src) + dna.species.handle_hud_icons(src) + return 1 proc/handle_random_events() diff --git a/code/modules/mob/living/carbon/human/mutantrace.dm b/code/modules/mob/living/carbon/human/mutantrace.dm new file mode 100644 index 00000000000..30615bb624c --- /dev/null +++ b/code/modules/mob/living/carbon/human/mutantrace.dm @@ -0,0 +1,22 @@ +var/global/list/colored_mutraces = list( // these mutantraces are affected by mutant color + "lizard", + "plant", + "pod", + "slime", + "jelly", + "golem" +) + +var/global/list/mutants_with_eyes = list( // these mutantraces have eyes + "lizard", + "plant", + "pod", + "jelly", +) + +/mob/living/carbon/human/proc/check_mutrace(var/mutneeded = "mut1", var/mutneededalt = "mut2") + if(dna) + if(dna.mutantrace == mutneeded || dna.mutantrace == mutneededalt) + return 1 + + return 0 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm index cdd8b0cc80a..be98cf67ed9 100644 --- a/code/modules/mob/living/carbon/human/say.dm +++ b/code/modules/mob/living/carbon/human/say.dm @@ -22,24 +22,8 @@ return if(dna) - if(dna.mutantrace == "lizard") - if(copytext(message, 1, 2) != "*") - message = replacetext(message, "s", stutter("ss")) + message = dna.species.handle_speech(message,src) - if(dna.mutantrace == "fly") - if(copytext(message, 1, 2) != "*") - message = replacetext(message, "z", stutter("zz")) - - /*if(dna.mutantrace == "slime" && prob(5)) - if(copytext(message, 1, 2) != "*") - if(copytext(message, 1, 2) == ";") - message = ";" - else - message = "" - message += "SKR" - var/imax = rand(5,20) - for(var/i = 0,i= 60) + return "gibbers, \"[text]\""; + if (ending == "?") + return "asks, \"[text]\""; + if (ending == "!") + return "exclaims, \"[text]\""; + + if(dna) + return "[dna.species.say_mod], \"[text]\""; + + return "says, \"[text]\""; /mob/living/carbon/human/proc/forcesay(list/append) if(stat == CONSCIOUS) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm new file mode 100644 index 00000000000..64fad2b5de4 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species.dm @@ -0,0 +1,1330 @@ +// This code handles different species in the game. + +#define SPECIES_LAYER 23 +#define BODY_LAYER 22 +#define HAIR_LAYER 8 + +#define TINT_IMPAIR 2 +#define TINT_BLIND 3 + +#define HUMAN_MAX_OXYLOSS 3 +#define HUMAN_CRIT_MAX_OXYLOSS ( (last_tick_duration) /3) + +#define HEAT_DAMAGE_LEVEL_1 2 +#define HEAT_DAMAGE_LEVEL_2 3 +#define HEAT_DAMAGE_LEVEL_3 8 + +#define COLD_DAMAGE_LEVEL_1 0.5 +#define COLD_DAMAGE_LEVEL_2 1.5 +#define COLD_DAMAGE_LEVEL_3 3 + +#define HEAT_GAS_DAMAGE_LEVEL_1 2 +#define HEAT_GAS_DAMAGE_LEVEL_2 4 +#define HEAT_GAS_DAMAGE_LEVEL_3 8 + +#define COLD_GAS_DAMAGE_LEVEL_1 0.5 +#define COLD_GAS_DAMAGE_LEVEL_2 1.5 +#define COLD_GAS_DAMAGE_LEVEL_3 3 + +/datum/species + var/id = null // if the game needs to manually check your race to do something not included in a proc here, it will use this + var/name = null // this is the fluff name. these will be left generic (such as 'Lizardperson' for the lizard race) so servers can change them to whatever + var/roundstart = 0 // can this mob be chosen at roundstart? (assuming the config option is checked?) + var/default_color = "#FFF" // if alien colors are disabled, this is the color that will be used by that race + + var/eyes = "eyes" // which eyes the race uses. at the moment, the only types of eyes are "eyes" (regular eyes) and "jelleyes" (three eyes) + var/sexes = 1 // whether or not the race has sexual characteristics. at the moment this is only 0 for skeletons and shadows + var/hair_color = null // this allows races to have specific hair colors... if null, it uses the H's hair/facial hair colors. if "mutcolor", it uses the H's mutant_color + var/hair_alpha = 255 // the alpha used by the hair. 255 is completely solid, 0 is transparent. + var/use_skintones = 0 // does it use skintones or not? (spoiler alert this is only used by humans) + + var/list/no_equip = list() // slots the race can't equip stuff to + var/nojumpsuit = 0 // this is sorta... weird. it basically lets you equip stuff that usually needs jumpsuits without one, like belts and pockets and ids + + var/say_mod = "says" // affects the speech message + + var/speedmod = 0 // this affects the race's speed. positive numbers make it move slower, negative numbers make it move faster + var/armor = 0 // overall defense for the race... or less defense, if it's negative. + var/brutemod = 1 // multiplier for brute damage + var/burnmod = 1 // multiplier for burn damage + var/coldmod = 1 // multiplier for cold damage + var/heatmod = 1 // multiplier for heat damage + var/punchmod = 0 // adds to the punch damage + + var/invis_sight = SEE_INVISIBLE_LIVING + var/darksight = 2 + + // species flags. these can be found in flags.dm + var/list/specflags = list() + + var/attack_verb = "punch" // punch-specific attack verb + var/sound/attack_sound = 'sound/weapons/punch1.ogg' + var/sound/miss_sound = 'sound/weapons/punchmiss.ogg' + + var/mob/living/list/ignored_by = list() // list of mobs that will ignore this species + + /////////// + // PROCS // + /////////// + + proc/update_base_icon_state(var/mob/living/carbon/human/H) + if(HUSK in H.mutations) + H.remove_overlay(SPECIES_LAYER) // races lose their color + return "husk" + else if(sexes) + if(use_skintones) + return "[H.skin_tone]_[(H.gender == FEMALE) ? "f" : "m"]" + else + return "[id]_[(H.gender == FEMALE) ? "f" : "m"]" + else + return "[id]" + + proc/update_color(var/mob/living/carbon/human/H) + H.remove_overlay(SPECIES_LAYER) + + var/image/standing + + var/g = (H.gender == FEMALE) ? "f" : "m" + + if(MUTCOLORS in specflags) + var/image/spec_base + if(sexes) + spec_base = image("icon" = 'icons/mob/human.dmi', "icon_state" = "[id]_[g]_s", "layer" = -SPECIES_LAYER) + else + spec_base = image("icon" = 'icons/mob/human.dmi', "icon_state" = "[id]_s", "layer" = -SPECIES_LAYER) + if(!config.mutant_colors) + H.dna.mutant_color = default_color + spec_base.color = "#[H.dna.mutant_color]" + standing = spec_base + + if(standing) + H.overlays_standing[SPECIES_LAYER] = standing + + H.apply_overlay(SPECIES_LAYER) + + proc/handle_hair(var/mob/living/carbon/human/H) + H.remove_overlay(HAIR_LAYER) + + var/datum/sprite_accessory/S + var/list/standing = list() + + if(H.facial_hair_style && FACEHAIR in specflags) + S = facial_hair_styles_list[H.facial_hair_style] + if(S) + var/image/img_facial_s + + img_facial_s = image("icon" = S.icon, "icon_state" = "[S.icon_state]_s", "layer" = -HAIR_LAYER) + + if(hair_color) + if(hair_color == "mutcolor") + if(!config.mutant_colors) + img_facial_s.color = "#" + default_color + else + img_facial_s.color = "#" + H.dna.mutant_color + else + img_facial_s.color = "#" + hair_color + else + img_facial_s.color = "#" + H.facial_hair_color + img_facial_s.alpha = hair_alpha + + standing += img_facial_s + + //Applies the debrained overlay if there is no brain + if(!H.getorgan(/obj/item/organ/brain)) + standing += image("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s", "layer" = -HAIR_LAYER) + + else if(H.hair_style && HAIR in specflags) + S = hair_styles_list[H.hair_style] + if(S) + var/image/img_hair_s = image("icon" = S.icon, "icon_state" = "[S.icon_state]_s", "layer" = -HAIR_LAYER) + + img_hair_s = image("icon" = S.icon, "icon_state" = "[S.icon_state]_s", "layer" = -HAIR_LAYER) + + if(hair_color) + if(hair_color == "mutcolor") + if(!config.mutant_colors) + img_hair_s.color = "#" + default_color + else + img_hair_s.color = "#" + H.dna.mutant_color + else + img_hair_s.color = "#" + hair_color + else + img_hair_s.color = "#" + H.hair_color + img_hair_s.alpha = hair_alpha + + standing += img_hair_s + + if(standing.len) + H.overlays_standing[HAIR_LAYER] = standing + + H.apply_overlay(HAIR_LAYER) + + return + + proc/handle_body(var/mob/living/carbon/human/H) + H.remove_overlay(BODY_LAYER) + + var/list/standing = list() + + // lipstick + if(H.lip_style && LIPS in specflags) + standing += image("icon"='icons/mob/human_face.dmi', "icon_state"="lips_[H.lip_style]_s", "layer" = -BODY_LAYER) + + // eyes + if(EYECOLOR in specflags) + var/image/img_eyes_s = image("icon" = 'icons/mob/human_face.dmi', "icon_state" = "[eyes]_s", "layer" = -BODY_LAYER) + img_eyes_s.color = "#" + H.eye_color + standing += img_eyes_s + + //Underwear + if(H.underwear) + var/datum/sprite_accessory/underwear/U = underwear_all[H.underwear] + if(U) + standing += image("icon"=U.icon, "icon_state"="[U.icon_state]_s", "layer"=-BODY_LAYER) + + if(standing.len) + H.overlays_standing[BODY_LAYER] = standing + + H.apply_overlay(BODY_LAYER) + + return + + proc/spec_life(var/mob/living/carbon/human/H) + return + + proc/spec_death(var/gibbed, var/mob/living/carbon/human/H) + return + + proc/auto_equip(var/mob/living/carbon/human/H) + // handles the equipping of species-specific gear + return + + proc/can_equip(var/obj/item/I, var/slot, var/disable_warning, var/mob/living/carbon/human/H) + if(slot in no_equip) + if(!(type in I.species_exception)) + return 0 + + switch(slot) + if(slot_l_hand) + if(H.l_hand) + return 0 + return 1 + if(slot_r_hand) + if(H.r_hand) + return 0 + return 1 + if(slot_wear_mask) + if(H.wear_mask) + return 0 + if( !(I.slot_flags & SLOT_MASK) ) + return 0 + return 1 + if(slot_back) + if(H.back) + return 0 + if( !(I.slot_flags & SLOT_BACK) ) + return 0 + return 1 + if(slot_wear_suit) + if(H.wear_suit) + return 0 + if( !(I.slot_flags & SLOT_OCLOTHING) ) + return 0 + return 1 + if(slot_gloves) + if(H.gloves) + return 0 + if( !(I.slot_flags & SLOT_GLOVES) ) + return 0 + return 1 + if(slot_shoes) + if(H.shoes) + return 0 + if( !(I.slot_flags & SLOT_FEET) ) + return 0 + return 1 + if(slot_belt) + if(H.belt) + return 0 + if(!H.w_uniform && !nojumpsuit) + if(!disable_warning) + H << "You need a jumpsuit before you can attach this [I.name]." + return 0 + if( !(I.slot_flags & SLOT_BELT) ) + return + return 1 + if(slot_glasses) + if(H.glasses) + return 0 + if( !(I.slot_flags & SLOT_EYES) ) + return 0 + return 1 + if(slot_head) + if(H.head) + return 0 + if( !(I.slot_flags & SLOT_HEAD) ) + return 0 + return 1 + if(slot_ears) + if(H.ears) + return 0 + if( !(I.slot_flags & SLOT_EARS) ) + return 0 + return 1 + if(slot_w_uniform) + if(H.w_uniform) + return 0 + if( !(I.slot_flags & SLOT_ICLOTHING) ) + return 0 + return 1 + if(slot_wear_id) + if(H.wear_id) + return 0 + if(!H.w_uniform && !nojumpsuit) + if(!disable_warning) + H << "You need a jumpsuit before you can attach this [I.name]." + return 0 + if( !(I.slot_flags & SLOT_ID) ) + return 0 + return 1 + if(slot_l_store) + if(I.flags & NODROP) //Pockets aren't visible, so you can't move NODROP items into them. + return 0 + if(H.l_store) + return 0 + if(!H.w_uniform && !nojumpsuit) + if(!disable_warning) + H << "You need a jumpsuit before you can attach this [I.name]." + return 0 + if(I.slot_flags & SLOT_DENYPOCKET) + return + if( I.w_class <= 2 || (I.slot_flags & SLOT_POCKET) ) + return 1 + if(slot_r_store) + if(I.flags & NODROP) + return 0 + if(H.r_store) + return 0 + if(!H.w_uniform && !nojumpsuit) + if(!disable_warning) + H << "You need a jumpsuit before you can attach this [I.name]." + return 0 + if(I.slot_flags & SLOT_DENYPOCKET) + return 0 + if( I.w_class <= 2 || (I.slot_flags & SLOT_POCKET) ) + return 1 + return 0 + if(slot_s_store) + if(I.flags & NODROP) + return 0 + if(H.s_store) + return 0 + if(!H.wear_suit) + if(!disable_warning) + H << "You need a suit before you can attach this [I.name]." + return 0 + if(!H.wear_suit.allowed) + if(!disable_warning) + H << "You somehow have a suit with no defined allowed items for suit storage, stop that." + return 0 + if(I.w_class > 4) + if(!disable_warning) + H << "The [I.name] is too big to attach." //should be src? + return 0 + if( istype(I, /obj/item/device/pda) || istype(I, /obj/item/weapon/pen) || is_type_in_list(I, H.wear_suit.allowed) ) + return 1 + return 0 + if(slot_handcuffed) + if(H.handcuffed) + return 0 + if(!istype(I, /obj/item/weapon/handcuffs)) + return 0 + return 1 + if(slot_legcuffed) + if(H.legcuffed) + return 0 + if(!istype(I, /obj/item/weapon/legcuffs)) + return 0 + return 1 + if(slot_in_backpack) + if (H.back && istype(H.back, /obj/item/weapon/storage/backpack)) + var/obj/item/weapon/storage/backpack/B = H.back + if(B.contents.len < B.storage_slots && I.w_class <= B.max_w_class) + return 1 + return 0 + return 0 //Unsupported slot + + proc/before_equip_job(var/datum/job/J, var/mob/living/carbon/human/H) + return + + proc/after_equip_job(var/datum/job/J, var/mob/living/carbon/human/H) + return + + proc/handle_chemicals(var/datum/reagent/chem, var/mob/living/carbon/human/H) + return 0 + + proc/handle_speech(var/message, var/mob/living/carbon/human/H) + return message + + //////// + //LIFE// + //////// + + proc/handle_chemicals_in_body(var/mob/living/carbon/human/H) + if(H.reagents) H.reagents.metabolize(H) + + //The fucking FAT mutation is the dumbest shit ever. It makes the code so difficult to work with + if(FAT in H.mutations) + if(H.overeatduration < 100) + H << "You feel fit again!" + H.mutations -= FAT + H.update_inv_w_uniform(0) + H.update_inv_wear_suit() + else + if(H.overeatduration > 500) + H << "You suddenly feel blubbery!" + H.mutations |= FAT + H.update_inv_w_uniform(0) + H.update_inv_wear_suit() + + // nutrition decrease + if (H.nutrition > 0 && H.stat != 2) + H.nutrition = max (0, H.nutrition - HUNGER_FACTOR) + + if (H.nutrition > 450) + if(H.overeatduration < 600) //capped so people don't take forever to unfat + H.overeatduration++ + else + if(H.overeatduration > 1) + H.overeatduration -= 2 //doubled the unfat rate + + if (H.drowsyness) + H.drowsyness-- + H.eye_blurry = max(2, H.eye_blurry) + if (prob(5)) + H.sleeping += 1 + H.Paralyse(5) + + H.confused = max(0, H.confused - 1) + // decrement dizziness counter, clamped to 0 + if(H.resting) + H.dizziness = max(0, H.dizziness - 15) + H.jitteriness = max(0, H.jitteriness - 15) + else + H.dizziness = max(0, H.dizziness - 3) + H.jitteriness = max(0, H.jitteriness - 3) + + H.updatehealth() + + return + + proc/handle_vision(var/mob/living/carbon/human/H) + if( H.stat == DEAD ) + H.sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS) + H.see_in_dark = 8 + if(!H.druggy) H.see_invisible = SEE_INVISIBLE_LEVEL_TWO + else + H.sight &= ~(SEE_TURFS|SEE_MOBS|SEE_OBJS) + var/see_temp = H.see_invisible + H.see_invisible = invis_sight + H.see_in_dark = darksight + + if(XRAY in H.mutations) + H.sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS + H.see_in_dark = 8 + H.see_invisible = SEE_INVISIBLE_LEVEL_TWO + + if(H.seer) + H.see_invisible = SEE_INVISIBLE_OBSERVER + + if(H.mind && H.mind.changeling) + H.hud_used.lingchemdisplay.invisibility = 0 + H.hud_used.lingchemdisplay.maptext = "
[H.mind.changeling.chem_charges]
" + else + H.hud_used.lingchemdisplay.invisibility = 101 + + if(istype(H.wear_mask, /obj/item/clothing/mask/gas/voice/space_ninja)) + var/obj/item/clothing/mask/gas/voice/space_ninja/O = H.wear_mask + switch(O.mode) + if(0) + var/target_list[] = list() + for(var/mob/living/target in oview(H)) + if( target.mind&&(target.mind.special_role||issilicon(target)) )//They need to have a mind. + target_list += target + if(target_list.len)//Everything else is handled by the ninja mask proc. + O.assess_targets(target_list, H) + H.see_invisible = SEE_INVISIBLE_LIVING + if(1) + H.see_in_dark = 5 + H.see_invisible = SEE_INVISIBLE_LIVING + if(2) + H.sight |= SEE_MOBS + H.see_invisible = SEE_INVISIBLE_LEVEL_TWO + if(3) + H.sight |= SEE_TURFS + H.see_invisible = SEE_INVISIBLE_LIVING + + if(H.glasses) + if(istype(H.glasses, /obj/item/clothing/glasses)) + var/obj/item/clothing/glasses/G = H.glasses + H.sight |= G.vision_flags + H.see_in_dark = G.darkness_view + H.see_invisible = G.invis_view + if(G.hud) + G.process_hud(H) + + if(H.druggy) //Override for druggy + H.see_invisible = see_temp + + if(H.see_override) //Override all + H.see_invisible = H.see_override + + // This checks how much the mob's eyewear impairs their vision + if(H.tinttotal >= TINT_IMPAIR) + if(tinted_weldhelh) + if(H.tinttotal >= TINT_BLIND) + H.blinded = 1 // You get the sudden urge to learn to play keyboard + H.client.screen += global_hud.darkMask + else + H.client.screen += global_hud.darkMask + + if(H.blind) + if(H.blinded) H.blind.layer = 18 + else H.blind.layer = 0 + + if( H.disabilities & NEARSIGHTED && !istype(H.glasses, /obj/item/clothing/glasses/regular) ) + H.client.screen += global_hud.vimpaired + if(H.eye_blurry) H.client.screen += global_hud.blurry + if(H.druggy) H.client.screen += global_hud.druggy + + + if(H.eye_stat > 20) + if(H.eye_stat > 30) H.client.screen += global_hud.darkMask + else H.client.screen += global_hud.vimpaired + + return 1 + + proc/handle_hud_icons(var/mob/living/carbon/human/H) + if(H.healths) + if(H.stat == DEAD) + H.healths.icon_state = "health7" + else + switch(H.hal_screwyhud) + if(1) H.healths.icon_state = "health6" + if(2) H.healths.icon_state = "health7" + else + switch(H.health - H.staminaloss) + if(100 to INFINITY) H.healths.icon_state = "health0" + if(80 to 100) H.healths.icon_state = "health1" + if(60 to 80) H.healths.icon_state = "health2" + if(40 to 60) H.healths.icon_state = "health3" + if(20 to 40) H.healths.icon_state = "health4" + if(0 to 20) H.healths.icon_state = "health5" + else H.healths.icon_state = "health6" + + if(H.nutrition_icon) + switch(H.nutrition) + if(450 to INFINITY) H.nutrition_icon.icon_state = "nutrition0" + if(350 to 450) H.nutrition_icon.icon_state = "nutrition1" + if(250 to 350) H.nutrition_icon.icon_state = "nutrition2" + if(150 to 250) H.nutrition_icon.icon_state = "nutrition3" + else H.nutrition_icon.icon_state = "nutrition4" + + if(H.pressure) + H.pressure.icon_state = "pressure[H.pressure_alert]" + + if(H.pullin) + if(H.pulling) H.pullin.icon_state = "pull" + else H.pullin.icon_state = "pull0" +// if(rest) //Not used with new UI +// if(resting || lying || sleeping) rest.icon_state = "rest1" +// else rest.icon_state = "rest0" + if(H.toxin) + if(H.hal_screwyhud == 4 || H.toxins_alert) H.toxin.icon_state = "tox1" + else H.toxin.icon_state = "tox0" + if(H.oxygen) + if(H.hal_screwyhud == 3 || H.oxygen_alert) H.oxygen.icon_state = "oxy1" + else H.oxygen.icon_state = "oxy0" + if(H.fire) + if(H.fire_alert) H.fire.icon_state = "fire[H.fire_alert]" //fire_alert is either 0 if no alert, 1 for cold and 2 for heat. + else H.fire.icon_state = "fire0" + + if(H.bodytemp) + if(!(HEATRES in specflags)) + switch(H.bodytemperature) //310.055 optimal body temp + if(370 to INFINITY) H.bodytemp.icon_state = "temp4" + if(350 to 370) H.bodytemp.icon_state = "temp3" + if(335 to 350) H.bodytemp.icon_state = "temp2" + switch(H.bodytemperature) + if(320 to 335) H.bodytemp.icon_state = "temp1" + if(300 to 320) H.bodytemp.icon_state = "temp0" + if(295 to 300) H.bodytemp.icon_state = "temp-1" + if(!(COLDRES in specflags)) + switch(H.bodytemperature) + if(280 to 295) H.bodytemp.icon_state = "temp-2" + if(260 to 280) H.bodytemp.icon_state = "temp-3" + if(-INFINITY to 260) H.bodytemp.icon_state = "temp-4" + + return 1 + + proc/handle_mutations_and_radiation(var/mob/living/carbon/human/H) + if(H.getFireLoss()) + if((COLD_RESISTANCE in H.mutations) || (prob(1))) + H.heal_organ_damage(0,1) + + if ((HULK in H.mutations) && H.health <= 25) + H.mutations.Remove(HULK) + H.update_mutations() //update our mutation overlays + H << "You suddenly feel very weak." + H.Weaken(3) + H.emote("collapse") + + if (H.radiation && !(RADIMMUNE in specflags)) + if (H.radiation > 100) + H.radiation = 100 + H.Weaken(10) + H << "You feel weak." + H.emote("collapse") + + if (H.radiation < 0) + H.radiation = 0 + + else + switch(H.radiation) + if(1 to 49) + H.radiation-- + if(prob(25)) + H.adjustToxLoss(1) + H.updatehealth() + + if(50 to 74) + H.radiation -= 2 + H.adjustToxLoss(1) + if(prob(5)) + H.radiation -= 5 + H.Weaken(3) + H << "You feel weak." + H.emote("collapse") + if(prob(15)) + if(!( H.hair_style == "Shaved") || !(H.hair_style == "Bald") || HAIR in specflags) + H << "Your hair starts to fall out in clumps..." + spawn(50) + H.facial_hair_style = "Shaved" + H.hair_style = "Bald" + H.update_hair() + H.updatehealth() + + if(75 to 100) + H.radiation -= 3 + H.adjustToxLoss(3) + if(prob(1)) + H << "You mutate!" + randmutb(H) + domutcheck(H,null) + H.emote("gasp") + H.updatehealth() + + //////////////// + // MOVE SPEED // + //////////////// + + proc/movement_delay(var/mob/living/carbon/human/H) + var/mspeed = 0 + + if(!has_gravity(H)) + return -1 //It's hard to be slowed down in space by... anything + else if(H.status_flags & GOTTAGOFAST) + return -1 + + mspeed = 0 + var/health_deficiency = (100 - H.health + H.staminaloss) + if(health_deficiency >= 40) + mspeed += (health_deficiency / 25) + + var/hungry = (500 - H.nutrition) / 5 //So overeat would be 100 and default level would be 80 + if(hungry >= 70) + mspeed += hungry / 50 + + if(H.wear_suit) + mspeed += H.wear_suit.slowdown + if(H.shoes) + mspeed += H.shoes.slowdown + if(H.back) + mspeed += H.back.slowdown + + if(FAT in H.mutations) + mspeed += 1.5 + if(H.bodytemperature < 283.222) + mspeed += (283.222 - H.bodytemperature) / 10 * 1.75 + + mspeed += speedmod + + return mspeed + + ////////////////// + // ATTACK PROCS // + ////////////////// + + proc/spec_attack_hand(var/mob/living/carbon/human/M, var/mob/living/carbon/human/H) + if((M != H) && H.check_shields(0, M.name)) + add_logs(M, H, "attempted to touch") + H.visible_message("[M] attempted to touch [H]!") + return 0 + + switch(M.a_intent) + if("help") + if(H.health >= 0) + H.help_shake_act(M) + if(H != M) + add_logs(M, H, "shaked") + return 1 + + //CPR + if((M.head && (M.head.flags & HEADCOVERSMOUTH)) || (M.wear_mask && (M.wear_mask.flags & MASKCOVERSMOUTH))) + M << "Remove your mask!" + return 0 + if((H.head && (H.head.flags & HEADCOVERSMOUTH)) || (H.wear_mask && (H.wear_mask.flags & MASKCOVERSMOUTH))) + M << "Remove their mask!" + return 0 + + if(H.cpr_time < world.time + 30) + add_logs(H, M, "CPRed") + H.visible_message("[M] is trying to perform CPR on [H]!") + if(!do_mob(M, H)) + return 0 + if((H.health >= -99 && H.health <= 0)) + H.cpr_time = world.time + var/suff = min(H.getOxyLoss(), 7) + H.adjustOxyLoss(-suff) + H.updatehealth() + M.visible_message("[M] performs CPR on [H]!") + H << "You feel a breath of fresh air enter your lungs. It feels good." + + if("grab") + if(M == H || H.anchored) + return 0 + + add_logs(M, H, "grabbed", addition="passively") + + if(H.w_uniform) + H.w_uniform.add_fingerprint(M) + + var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, H) + if(H.buckled) + M << "You cannot grab [H], \he is buckled in!" + if(!G) //the grab will delete itself in New if affecting is anchored + return + M.put_in_active_hand(G) + G.synch() + H.LAssailant = M + + playsound(H.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + H.visible_message("[M] has grabbed [H] passively!") + return 1 + + if("harm") + add_logs(M, H, "punched") + + var/atk_verb = "punch" + if(H.lying) + atk_verb = "kick" + else if(M.dna) + atk_verb = M.dna.species.attack_verb + + var/damage = rand(0, 9) + damage += punchmod + + if(!damage) + if(M.dna) + playsound(H.loc, M.dna.species.miss_sound, 25, 1, -1) + else + playsound(H.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + + H.visible_message("[M] has attempted to [atk_verb] [H]!") + return 0 + + + var/obj/item/organ/limb/affecting = H.get_organ(ran_zone(M.zone_sel.selecting)) + var/armor_block = H.run_armor_check(affecting, "melee") + + if(HULK in M.mutations) + damage += 5 + + if(M.dna) + playsound(H.loc, M.dna.species.attack_sound, 25, 1, -1) + else + playsound(H.loc, 'sound/weapons/punch1.ogg', 25, 1, -1) + + + H.visible_message("[M] has [atk_verb]ed [H]!", \ + "[M] has [atk_verb]ed [H]!") + + H.apply_damage(damage, BRUTE, affecting, armor_block) + if((H.stat != DEAD) && damage >= 9) + H.visible_message("[M] has weakened [H]!", \ + "[M] has weakened [H]!") + H.apply_effect(4, WEAKEN, armor_block) + H.forcesay(hit_appends) + else if(H.lying) + H.forcesay(hit_appends) + + if("disarm") + add_logs(M, H, "disarmed") + + if(H.w_uniform) + H.w_uniform.add_fingerprint(M) + var/obj/item/organ/limb/affecting = H.get_organ(ran_zone(M.zone_sel.selecting)) + var/randn = rand(1, 100) + if(randn <= 25) + H.apply_effect(2, WEAKEN, H.run_armor_check(affecting, "melee")) + playsound(H, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + H.visible_message("[M] has pushed [H]!", + "[M] has pushed [H]!") + H.forcesay(hit_appends) + return + + var/talked = 0 // BubbleWrap + + if(randn <= 60) + //BubbleWrap: Disarming breaks a pull + if(H.pulling) + H.visible_message("[M] has broken [H]'s grip on [H.pulling]!") + talked = 1 + H.stop_pulling() + + //BubbleWrap: Disarming also breaks a grab - this will also stop someone being choked, won't it? + if(istype(H.l_hand, /obj/item/weapon/grab)) + var/obj/item/weapon/grab/lgrab = H.l_hand + if(lgrab.affecting) + H.visible_message("[M] has broken [H]'s grip on [lgrab.affecting]!") + talked = 1 + spawn(1) + qdel(lgrab) + if(istype(H.r_hand, /obj/item/weapon/grab)) + var/obj/item/weapon/grab/rgrab = H.r_hand + if(rgrab.affecting) + H.visible_message("[M] has broken [H]'s grip on [rgrab.affecting]!") + talked = 1 + spawn(1) + qdel(rgrab) + //End BubbleWrap + + if(!talked) //BubbleWrap + if(H.drop_item()) + H.visible_message("[M] has disarmed [H]!", \ + "[M] has disarmed [H]!") + playsound(H, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + return + + + playsound(H, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + H.visible_message("[M] attempted to disarm [H]!", \ + "[M] attemped to disarm [H]!") + return + + proc/spec_attacked_by(var/obj/item/I, var/mob/living/user, var/def_zone, var/obj/item/organ/limb/affecting, var/hit_area, var/intent, var/obj/item/organ/limb/target_limb, target_area, var/mob/living/carbon/human/H) + // Allows you to put in item-specific reactions based on species + if((user != H) && H.check_shields(I.force, "the [I.name]")) + return 0 + + if(I.attack_verb && I.attack_verb.len) + H.visible_message("[H] has been [pick(I.attack_verb)] in the [hit_area] with [I] by [user]!", \ + "[H] has been [pick(I.attack_verb)] in the [hit_area] with [I] by [user]!") + else if(I.force) + H.visible_message("[H] has been attacked in the [hit_area] with [I] by [user]!", \ + "[H] has been attacked in the [hit_area] with [I] by [user]!") + else + return 0 + + var/armor = H.run_armor_check(affecting, "melee", "Your armour has protected your [hit_area].", "Your armour has softened a hit to your [hit_area].") + if(armor >= 100) return 0 + var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords) + + apply_damage(I.force, I.damtype, affecting, armor, H) + + var/bloody = 0 + if(((I.damtype == BRUTE) && prob(25 + (I.force * 2)))) + if(affecting.status == ORGAN_ORGANIC) + I.add_blood(H) //Make the weapon bloody, not the person. + if(prob(I.force * 2)) //blood spatter! + bloody = 1 + var/turf/location = H.loc + if(istype(location, /turf/simulated)) + location.add_blood(H) + if(get_dist(H, H) <= 1) //people with TK won't get smeared with blood + if(H.wear_suit) + H.wear_suit.add_blood(H) + H.update_inv_wear_suit(0) //updates mob overlays to show the new blood (no refresh) + else if(H.w_uniform) + H.w_uniform.add_blood(H) + H.update_inv_w_uniform(0) //updates mob overlays to show the new blood (no refresh) + if (H.gloves) + var/obj/item/clothing/gloves/G = H.gloves + G.add_blood(H) + else + H.add_blood(H) + H.update_inv_gloves() //updates on-mob overlays for bloody hands and/or bloody gloves + + + switch(hit_area) + if("head") //Harder to score a stun but if you do it lasts a bit longer + if(H.stat == CONSCIOUS && prob(I.force) && armor < 50) + H.visible_message("[H] has been knocked unconscious!", \ + "[H] has been knocked unconscious!") + H.apply_effect(20, PARALYZE, armor) + if(H != user && I.damtype == BRUTE) + ticker.mode.remove_revolutionary(H.mind) + + if(bloody) //Apply blood + if(H.wear_mask) + H.wear_mask.add_blood(H) + H.update_inv_wear_mask(0) + if(H.head) + H.head.add_blood(H) + H.update_inv_head(0) + if(H.glasses && prob(33)) + H.glasses.add_blood(H) + H.update_inv_glasses(0) + + if("chest") //Easier to score a stun but lasts less time + if(H.stat == CONSCIOUS && prob(I.force + 10)) + H.visible_message("[H] has been knocked down!", \ + "[H] has been knocked down!") + H.apply_effect(5, WEAKEN, armor) + + if(bloody) + if(H.wear_suit) + H.wear_suit.add_blood(H) + H.update_inv_wear_suit(0) + if(H.w_uniform) + H.w_uniform.add_blood(H) + H.update_inv_w_uniform(0) + + if(Iforce > 10 || Iforce >= 5 && prob(33)) + H.forcesay(hit_appends) //forcesay checks stat already. + return + + proc/attacked_by(var/obj/item/I, var/mob/living/user, var/def_zone, var/mob/living/carbon/human/H) + H.apply_damage(I.force, I.damtype) + if(I.damtype == "brute") + if(prob(33) && I.force && !(NOBLOOD in specflags)) + var/turf/location = H.loc + if(istype(location, /turf/simulated)) + location.add_blood_floor(H) + + var/showname = "." + if(user) + showname = " by [user]!" + if(!(user in viewers(I, null))) + showname = "." + + if(I.attack_verb && I.attack_verb.len) + H.visible_message("[H] has been [pick(I.attack_verb)] with [I][showname]", + "[H] has been [pick(I.attack_verb)] with [I][showname]") + else if(I.force) + H.visible_message("[H] has been attacked with [I][showname]", + "[H] has been attacked with [I][showname]") + if(!showname && user) + if(user.client) + user << "You attack [H] with [I]. " + + return + + proc/apply_damage(var/damage, var/damagetype = BRUTE, var/def_zone = null, var/blocked, var/mob/living/carbon/human/H) + blocked = (100-(blocked+armor))/100 + if(blocked <= 0) return 0 + + var/obj/item/organ/limb/organ = null + if(isorgan(def_zone)) + organ = def_zone + else + if(!def_zone) def_zone = ran_zone(def_zone) + organ = H.get_organ(check_zone(def_zone)) + if(!organ) return 0 + + damage = (damage * blocked) + + switch(damagetype) + if(BRUTE) + H.damageoverlaytemp = 20 + if(organ.take_damage(damage*brutemod, 0)) + H.update_damage_overlays(0) + if(BURN) + H.damageoverlaytemp = 20 + if(organ.take_damage(0, damage*burnmod)) + H.update_damage_overlays(0) + if(TOX) + H.adjustToxLoss(damage * blocked) + if(OXY) + H.adjustOxyLoss(damage * blocked) + if(CLONE) + H.adjustCloneLoss(damage * blocked) + if(STAMINA) + H.adjustStaminaLoss(damage * blocked) + + proc/on_hit(var/obj/item/projectile/proj_type, var/mob/living/carbon/human/H) + // called when hit by a projectile + switch(proj_type) + if(/obj/item/projectile/energy/floramut) // overwritten by plants/pods + H.show_message("The radiation beam dissipates harmlessly through your body.") + if(/obj/item/projectile/energy/florayield) + H.show_message("The radiation beam dissipates harmlessly through your body.") + return + + ///////////// + //BREATHING// + ///////////// + + proc/breathe(var/mob/living/carbon/human/H) + if(H.reagents.has_reagent("lexorin")) return + if(istype(H.loc, /obj/machinery/atmospherics/unary/cryo_cell)) return + + var/datum/gas_mixture/environment = H.loc.return_air() + var/datum/gas_mixture/breath + // HACK NEED CHANGING LATER + if(H.health <= config.health_threshold_crit) + H.losebreath++ + + if(H.losebreath>0) //Suffocating so do not take a breath + H.losebreath-- + if (prob(10)) //Gasp per 10 ticks? Sounds about right. + spawn H.emote("gasp") + if(istype(H.loc, /obj/)) + var/obj/location_as_object = H.loc + location_as_object.handle_internal_lifeform(H, 0) + else + //First, check for air from internal atmosphere (using an air tank and mask generally) + breath = H.get_breath_from_internal(BREATH_VOLUME) // Super hacky -- TLE + //breath = get_breath_from_internal(0.5) // Manually setting to old BREATH_VOLUME amount -- TLE + + //No breath from internal atmosphere so get breath from location + if(!breath) + if(isobj(H.loc)) + var/obj/location_as_object = H.loc + breath = location_as_object.handle_internal_lifeform(H, BREATH_VOLUME) + else if(isturf(H.loc)) + var/breath_moles = 0 + /*if(environment.return_pressure() > ONE_ATMOSPHERE) + // Loads of air around (pressure effect will be handled elsewhere), so lets just take a enough to fill our lungs at normal atmos pressure (using n = Pv/RT) + breath_moles = (ONE_ATMOSPHERE*BREATH_VOLUME/R_IDEAL_GAS_EQUATION*environment.temperature) + else*/ + // Not enough air around, take a percentage of what's there to model this properly + breath_moles = environment.total_moles()*BREATH_PERCENTAGE + + breath = H.loc.remove_air(breath_moles) + // Handle chem smoke effect -- Doohl + var/block = 0 + if(H.wear_mask) + if(H.wear_mask.flags & BLOCK_GAS_SMOKE_EFFECT) + block = 1 + if(H.glasses) + if(H.glasses.flags & BLOCK_GAS_SMOKE_EFFECT) + block = 1 + if(H.head) + if(H.head.flags & BLOCK_GAS_SMOKE_EFFECT) + block = 1 + + if(!block) + + for(var/obj/effect/effect/chem_smoke/smoke in view(1, H)) + if(smoke.reagents.total_volume) + smoke.reagents.reaction(H, INGEST) + spawn(5) + if(smoke) + smoke.reagents.copy_to(H, 10) // I dunno, maybe the reagents enter the blood stream through the lungs? + break // If they breathe in the nasty stuff once, no need to continue checking + + else //Still give containing object the chance to interact + if(istype(H.loc, /obj/)) + var/obj/location_as_object = H.loc + location_as_object.handle_internal_lifeform(H, 0) + + handle_breath(breath, H) + + if(breath) + H.loc.assume_air(breath) + + proc/handle_breath(datum/gas_mixture/breath, var/mob/living/carbon/human/H) + if((H.status_flags & GODMODE)) + return + + if(!breath || (breath.total_moles() == 0) || H.suiciding) + if(H.reagents.has_reagent("inaprovaline")) + return + if(H.suiciding) + H.adjustOxyLoss(2)//If you are suiciding, you should die a little bit faster + H.failed_last_breath = 1 + H.oxygen_alert = max(H.oxygen_alert, 1) + return 0 + if(H.health >= config.health_threshold_crit) + if(NOBREATH in specflags) return 1 + H.adjustOxyLoss(HUMAN_MAX_OXYLOSS) + H.failed_last_breath = 1 + else + H.adjustOxyLoss(HUMAN_CRIT_MAX_OXYLOSS) + H.failed_last_breath = 1 + + H.oxygen_alert = max(H.oxygen_alert, 1) + + return 0 + + var/safe_oxygen_min = 16 // Minimum safe partial pressure of O2, in kPa + //var/safe_oxygen_max = 140 // Maximum safe partial pressure of O2, in kPa (Not used for now) + var/safe_co2_max = 10 // Yes it's an arbitrary value who cares? + var/safe_toxins_max = 0.005 + var/SA_para_min = 1 + var/SA_sleep_min = 5 + var/oxygen_used = 0 + var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME + + //Partial pressure of the O2 in our breath + var/O2_pp = (breath.oxygen/breath.total_moles())*breath_pressure + // Same, but for the toxins + var/Toxins_pp = (breath.toxins/breath.total_moles())*breath_pressure + // And CO2, lets say a PP of more than 10 will be bad (It's a little less really, but eh, being passed out all round aint no fun) + var/CO2_pp = (breath.carbon_dioxide/breath.total_moles())*breath_pressure // Tweaking to fit the hacky bullshit I've done with atmo -- TLE + //var/CO2_pp = (breath.carbon_dioxide/breath.total_moles())*0.5 // The default pressure value + + if(O2_pp < safe_oxygen_min) // Too little oxygen + if(!(NOBREATH in specflags) || (H.health <= config.health_threshold_crit)) + if(prob(20)) + spawn(0) H.emote("gasp") + if(O2_pp > 0) + var/ratio = safe_oxygen_min/O2_pp + H.adjustOxyLoss(min(5*ratio, HUMAN_MAX_OXYLOSS)) // Don't fuck them up too fast (space only does HUMAN_MAX_OXYLOSS after all!) + H.failed_last_breath = 1 + oxygen_used = breath.oxygen*ratio/6 + else + H.adjustOxyLoss(HUMAN_MAX_OXYLOSS) + H.failed_last_breath = 1 + H.oxygen_alert = max(H.oxygen_alert, 1) + /*else if (O2_pp > safe_oxygen_max) // Too much oxygen (commented this out for now, I'll deal with pressure damage elsewhere I suppose) + spawn(0) emote("cough") + var/ratio = O2_pp/safe_oxygen_max + oxyloss += 5*ratio + oxygen_used = breath.oxygen*ratio/6 + oxygen_alert = max(oxygen_alert, 1)*/ + else // We're in safe limits + H.failed_last_breath = 0 + H.adjustOxyLoss(-5) + oxygen_used = breath.oxygen/6 + H.oxygen_alert = 0 + + breath.oxygen -= oxygen_used + breath.carbon_dioxide += oxygen_used + + //CO2 does not affect failed_last_breath. So if there was enough oxygen in the air but too much co2, this will hurt you, but only once per 4 ticks, instead of once per tick. + if(CO2_pp > safe_co2_max && !(NOBREATH in specflags)) + if(!H.co2overloadtime) // If it's the first breath with too much CO2 in it, lets start a counter, then have them pass out after 12s or so. + H.co2overloadtime = world.time + else if(world.time - H.co2overloadtime > 120) + H.Paralyse(3) + H.adjustOxyLoss(3) // Lets hurt em a little, let them know we mean business + if(world.time - H.co2overloadtime > 300) // They've been in here 30s now, lets start to kill them for their own good! + H.adjustOxyLoss(8) + if(prob(20)) // Lets give them some chance to know somethings not right though I guess. + spawn(0) H.emote("cough") + + else + H.co2overloadtime = 0 + + if(Toxins_pp > safe_toxins_max && !(NOBREATH in specflags)) // Too much toxins + var/ratio = (breath.toxins/safe_toxins_max) * 10 + //adjustToxLoss(Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE)) //Limit amount of damage toxin exposure can do per second + if(H.reagents) + H.reagents.add_reagent("plasma", Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE)) + H.toxins_alert = max(H.toxins_alert, 1) + else + H.toxins_alert = 0 + + if(breath.trace_gases.len && !(NOBREATH in specflags)) // If there's some other shit in the air lets deal with it here. + for(var/datum/gas/sleeping_agent/SA in breath.trace_gases) + var/SA_pp = (SA.moles/breath.total_moles())*breath_pressure + if(SA_pp > SA_para_min) // Enough to make us paralysed for a bit + H.Paralyse(3) // 3 gives them one second to wake up and run away a bit! + if(SA_pp > SA_sleep_min) // Enough to make us sleep as well + H.sleeping = max(H.sleeping+2, 10) + else if(SA_pp > 0.01) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning + if(prob(20)) + spawn(0) H.emote(pick("giggle", "laugh")) + + handle_temperature(breath) + + return 1 + + proc/handle_temperature(datum/gas_mixture/breath, var/mob/living/carbon/human/H) // called by human/life, handles temperatures + if( (abs(310.15 - breath.temperature) > 50) && !(COLD_RESISTANCE in H.mutations) && !(COLDRES in specflags)) // Hot air hurts :( + if(breath.temperature < 260.15) + if(prob(20)) + H << "You feel your face freezing and an icicle forming in your lungs!" + else if(breath.temperature > 360.15 && !(HEATRES in specflags)) + if(prob(20)) + H << "You feel your face burning and a searing heat in your lungs!" + + if(!(COLDRES in specflags)) // COLD DAMAGE + switch(breath.temperature) + if(-INFINITY to 120) + H.apply_damage(COLD_GAS_DAMAGE_LEVEL_3, BURN, "head") + H.fire_alert = max(H.fire_alert, 1) + if(120 to 200) + H.apply_damage(COLD_GAS_DAMAGE_LEVEL_2, BURN, "head") + H.fire_alert = max(H.fire_alert, 1) + if(200 to 260) + H.apply_damage(COLD_GAS_DAMAGE_LEVEL_1, BURN, "head") + H.fire_alert = max(H.fire_alert, 1) + + if(!(HEATRES in specflags)) // HEAT DAMAGE + switch(breath.temperature) + if(360 to 400) + H.apply_damage(HEAT_GAS_DAMAGE_LEVEL_1, BURN, "head") + H.fire_alert = max(H.fire_alert, 2) + if(400 to 1000) + H.apply_damage(HEAT_GAS_DAMAGE_LEVEL_2, BURN, "head") + H.fire_alert = max(H.fire_alert, 2) + if(1000 to INFINITY) + H.apply_damage(HEAT_GAS_DAMAGE_LEVEL_3, BURN, "head") + H.fire_alert = max(H.fire_alert, 2) + + return + + proc/handle_environment(datum/gas_mixture/environment, var/mob/living/carbon/human/H) + if(!environment) + return + + var/loc_temp = H.get_temperature(environment) + //world << "Loc temp: [loc_temp] - Body temp: [bodytemperature] - Fireloss: [getFireLoss()] - Thermal protection: [get_thermal_protection()] - Fire protection: [thermal_protection + add_fire_protection(loc_temp)] - Heat capacity: [environment_heat_capacity] - Location: [loc] - src: [src]" + + //Body temperature is adjusted in two steps. Firstly your body tries to stabilize itself a bit. + if(H.stat != 2) + H.stabilize_temperature_from_calories() + + //After then, it reacts to the surrounding atmosphere based on your thermal protection + if(!H.on_fire) //If you're on fire, you do not heat up or cool down based on surrounding gases + if(loc_temp < H.bodytemperature) + //Place is colder than we are + var/thermal_protection = H.get_cold_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. + if(thermal_protection < 1) + H.bodytemperature += min((1-thermal_protection) * ((loc_temp - H.bodytemperature) / BODYTEMP_COLD_DIVISOR), BODYTEMP_COOLING_MAX) + else + //Place is hotter than we are + var/thermal_protection = H.get_heat_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. + if(thermal_protection < 1) + H.bodytemperature += min((1-thermal_protection) * ((loc_temp - H.bodytemperature) / BODYTEMP_HEAT_DIVISOR), BODYTEMP_HEATING_MAX) + + // +/- 50 degrees from 310.15K is the 'safe' zone, where no damage is dealt. + if(H.bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT && !(HEATRES in specflags)) + //Body temperature is too hot. + H.fire_alert = max(H.fire_alert, 1) + switch(H.bodytemperature) + if(360 to 400) + H.apply_damage(HEAT_DAMAGE_LEVEL_1*heatmod, BURN) + H.fire_alert = max(H.fire_alert, 2) + if(400 to 460) + H.apply_damage(HEAT_DAMAGE_LEVEL_2*heatmod, BURN) + H.fire_alert = max(H.fire_alert, 2) + if(460 to INFINITY) + if(H.on_fire) + H.apply_damage(HEAT_DAMAGE_LEVEL_3*heatmod, BURN) + H.fire_alert = max(H.fire_alert, 2) + else + H.apply_damage(HEAT_DAMAGE_LEVEL_2*heatmod, BURN) + H.fire_alert = max(H.fire_alert, 2) + + else if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT && !(COLDRES in specflags)) + H.fire_alert = max(H.fire_alert, 1) + if(!istype(H.loc, /obj/machinery/atmospherics/unary/cryo_cell)) + switch(H.bodytemperature) + if(200 to 260) + H.apply_damage(COLD_DAMAGE_LEVEL_1*coldmod, BURN) + H.fire_alert = max(H.fire_alert, 1) + if(120 to 200) + H.apply_damage(COLD_DAMAGE_LEVEL_2*coldmod, BURN) + H.fire_alert = max(H.fire_alert, 1) + if(-INFINITY to 120) + H.apply_damage(COLD_DAMAGE_LEVEL_3*coldmod, BURN) + H.fire_alert = max(H.fire_alert, 1) + + // Account for massive pressure differences. Done by Polymorph + // Made it possible to actually have something that can protect against high pressure... Done by Errorage. Polymorph now has an axe sticking from his head for his previous hardcoded nonsense! + + var/pressure = environment.return_pressure() + var/adjusted_pressure = H.calculate_affecting_pressure(pressure) //Returns how much pressure actually affects the mob. + switch(adjusted_pressure) + if(HAZARD_HIGH_PRESSURE to INFINITY) + if(!(HEATRES in specflags)) + H.adjustBruteLoss( min( ( (adjusted_pressure / HAZARD_HIGH_PRESSURE) -1 )*PRESSURE_DAMAGE_COEFFICIENT , MAX_HIGH_PRESSURE_DAMAGE) ) + H.pressure_alert = 2 + else + H.pressure_alert = 1 + if(WARNING_HIGH_PRESSURE to HAZARD_HIGH_PRESSURE) + H.pressure_alert = 1 + if(WARNING_LOW_PRESSURE to WARNING_HIGH_PRESSURE) + H.pressure_alert = 0 + if(HAZARD_LOW_PRESSURE to WARNING_LOW_PRESSURE) + H.pressure_alert = -1 + else + if((COLD_RESISTANCE in H.mutations) || (COLDRES in specflags)) + H.pressure_alert = -1 + else + H.adjustBruteLoss( LOW_PRESSURE_DAMAGE ) + H.pressure_alert = -2 + + return + + ////////// + // FIRE // + ////////// + + proc/handle_fire(var/mob/living/carbon/human/H) + if(HEATRES in specflags || NOFIRE in specflags) + return + if(H.fire_stacks < 0) + H.fire_stacks++ //If we've doused ourselves in water to avoid fire, dry off slowly + H.fire_stacks = min(0, H.fire_stacks)//So we dry ourselves back to default, nonflammable. + if(!H.on_fire) + return + var/datum/gas_mixture/G = H.loc.return_air() // Check if we're standing in an oxygenless environment + if(G.oxygen < 1) + ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire + return + var/turf/location = get_turf(H) + location.hotspot_expose(700, 50, 1) + + proc/IgniteMob(var/mob/living/carbon/human/H) + if(H.fire_stacks > 0 && !H.on_fire && !(HEATRES in specflags) && !(NOFIRE in specflags)) + H.on_fire = 1 + H.AddLuminosity(3) + H.update_fire() + + proc/ExtinguishMob(var/mob/living/carbon/human/H) + if(H.on_fire) + H.on_fire = 0 + H.fire_stacks = 0 + H.AddLuminosity(-3) + H.update_fire() + +#undef SPECIES_LAYER +#undef BODY_LAYER +#undef HAIR_LAYER + +#undef HUMAN_MAX_OXYLOSS +#undef HUMAN_CRIT_MAX_OXYLOSS + +#undef HEAT_DAMAGE_LEVEL_1 +#undef HEAT_DAMAGE_LEVEL_2 +#undef HEAT_DAMAGE_LEVEL_3 + +#undef COLD_DAMAGE_LEVEL_1 +#undef COLD_DAMAGE_LEVEL_2 +#undef COLD_DAMAGE_LEVEL_3 + +#undef HEAT_GAS_DAMAGE_LEVEL_1 +#undef HEAT_GAS_DAMAGE_LEVEL_2 +#undef HEAT_GAS_DAMAGE_LEVEL_3 + +#undef COLD_GAS_DAMAGE_LEVEL_1 +#undef COLD_GAS_DAMAGE_LEVEL_2 +#undef COLD_GAS_DAMAGE_LEVEL_3 + +#undef TINT_IMPAIR +#undef TINT_BLIND \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/species_types.dm b/code/modules/mob/living/carbon/human/species_types.dm new file mode 100644 index 00000000000..1e2d538fad3 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species_types.dm @@ -0,0 +1,177 @@ +/datum/species/human + name = "Human" + id = "human" + roundstart = 1 + specflags = list(EYECOLOR,HAIR,FACEHAIR,LIPS) + use_skintones = 1 + + handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + if(chem.id == "mutationtoxin") + H << "Your flesh rapidly mutates!" + H.dna.species = new /datum/species/slime() + H.regenerate_icons() + H.reagents.del_reagent(chem.type) + return 1 + +/datum/species/lizard + // Reptilian humanoids with scaled skin and tails. + name = "Lizardperson" + id = "lizard" + say_mod = "hisses" + default_color = "00FF00" + roundstart = 1 + specflags = list(MUTCOLORS,EYECOLOR,LIPS) + attack_verb = "slash" + attack_sound = 'sound/weapons/slash.ogg' + miss_sound = 'sound/weapons/slashmiss.ogg' + + handle_speech(message) + // jesus christ why + if(copytext(message, 1, 2) != "*") + message = replacetext(message, "s", stutter("ss")) + + return message + +/datum/species/plant + // Creatures made of leaves and plant matter. + name = "Plant" + id = "plant" + default_color = "59CE00" + specflags = list(MUTCOLORS,EYECOLOR) + attack_verb = "slice" + attack_sound = 'sound/weapons/slice.ogg' + miss_sound = 'sound/weapons/slashmiss.ogg' + burnmod = 1.25 + heatmod = 1.5 + + handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + if(chem.id == "plantbgone") + H.adjustToxLoss(3) + H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM) + return 1 + + on_hit(proj_type, mob/living/carbon/human/H) + switch(proj_type) + if(/obj/item/projectile/energy/floramut) + if(prob(15)) + H.apply_effect((rand(30,80)),IRRADIATE) + H.Weaken(5) + for (var/mob/V in viewers(H)) + V.show_message("[H] writhes in pain as \his vacuoles boil.", 3, "You hear the crunching of leaves.", 2) + if(prob(80)) + randmutb(H) + domutcheck(H,null) + else + randmutg(H) + domutcheck(H,null) + else + H.adjustFireLoss(rand(5,15)) + H.show_message("The radiation beam singes you!") + if(/obj/item/projectile/energy/florayield) + H.nutrition = min(H.nutrition+30, 500) + return + +/datum/species/plant/pod + // A mutation caused by a human being ressurected in a revival pod. These regain health in light, and begin to wither in darkness. + name = "Podperson" + id = "pod" + + spec_life(mob/living/carbon/human/H) + var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing + if(isturf(H.loc)) //else, there's considered to be no light + var/turf/T = H.loc + var/area/A = T.loc + if(A) + if(A.lighting_use_dynamic) light_amount = min(10,T.lighting_lumcount) - 5 + else light_amount = 5 + H.nutrition += light_amount + if(H.nutrition > 500) + H.nutrition = 500 + if(light_amount > 2) //if there's enough light, heal + H.heal_overall_damage(1,1) + H.adjustToxLoss(-1) + H.adjustOxyLoss(-1) + + if(H.nutrition < 200) + H.take_overall_damage(2,0) + +/datum/species/shadow + // Humans cursed to stay in the darkness, lest their life forces drain. They regain health in shadow and die in light. + name = "???" + id = "shadow" + darksight = 8 + sexes = 0 + ignored_by = list(/mob/living/simple_animal/hostile/faithless) + + spec_life(mob/living/carbon/human/H) + var/light_amount = 0 + if(isturf(H.loc)) + var/turf/T = H.loc + var/area/A = T.loc + if(A) + if(A.lighting_use_dynamic) light_amount = T.lighting_lumcount + else light_amount = 10 + if(light_amount > 2) //if there's enough light, start dying + H.take_overall_damage(1,1) + else if (light_amount < 2) //heal in the dark + H.heal_overall_damage(1,1) + +/datum/species/slime + // Humans mutated by slime mutagen, produced from green slimes. They are not targetted by slimes. + name = "Slimeperson" + id = "slime" + default_color = "00FFFF" + darksight = 3 + invis_sight = SEE_INVISIBLE_LEVEL_ONE + specflags = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR) + hair_color = "mutcolor" + hair_alpha = 150 + ignored_by = list(/mob/living/carbon/slime) + +/datum/species/jelly + // Entirely alien beings that seem to be made entirely out of gel. They have three eyes and a skeleton visible within them. + name = "Xenobiological Jelly Entity" + id = "jelly" + default_color = "00FF90" + say_mod = "chirps" + eyes = "jelleyes" + specflags = list(MUTCOLORS,EYECOLOR) + +/datum/species/golem + // Animated beings of stone. They have increased defenses, and do not need to breathe. They're also slow as fuuuck. + name = "Golem" + id = "golem" + specflags = list(NOBREATH,HEATRES,COLDRES,NOGUNS,NOBLOOD,RADIMMUNE) + speedmod = 3 + armor = 55 + punchmod = 5 + no_equip = list(slot_wear_mask, slot_wear_suit, slot_gloves, slot_shoes, slot_head, slot_w_uniform) + nojumpsuit = 1 + +/datum/species/golem/adamantine + name = "Adamantine Golem" + id = "adamantine" + +/datum/species/fly + // Humans turned into fly-like abominations in teleporter accidents. + name = "Human?" + id = "fly" + say_mod = "buzzes" + + handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + if(chem.id == "pestkiller") + H.adjustToxLoss(3) + H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM) + return 1 + + handle_speech(message) + if(copytext(message, 1, 2) != "*") + message = replacetext(message, "z", stutter("zz")) + + return message + +/datum/species/skeleton + // 2spooky + name = "Spooky Scary Skeleton" + id = "skeleton" + sexes = 0 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index e09d39d53dd..c9edac17e1c 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -56,6 +56,7 @@ Please contact me on #coderbus IRC. ~Carnie x */ //Human Overlays Indexes///////// +#define SPECIES_LAYER 23 // mutantrace colors... these are on a seperate layer in order to prvent #define BODY_LAYER 22 //underwear, eyes, lips(makeup) #define MUTATIONS_LAYER 21 //Tk headglows etc. #define AUGMENTS_LAYER 20 @@ -78,28 +79,28 @@ Please contact me on #coderbus IRC. ~Carnie x #define L_HAND_LAYER 3 #define R_HAND_LAYER 2 //Having the two hands seperate seems rather silly, merge them together? It'll allow for code to be reused on mobs with arbitarily many hands #define FIRE_LAYER 1 //If you're on fire -#define TOTAL_LAYERS 22 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_; +#define TOTAL_LAYERS 23 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_; ////////////////////////////////// + /mob/living/carbon/human var/list/overlays_standing[TOTAL_LAYERS] /mob/living/carbon/human/proc/update_base_icon_state() - var/race = dna ? dna.mutantrace : null - switch(race) - if("lizard","golem","slime","shadow","adamantine","fly","plant") - base_icon_state = "[dna.mutantrace]_[(gender == FEMALE) ? "f" : "m"]" - if("skeleton") - base_icon_state = "skeleton" + //var/race = dna ? dna.mutantrace : null + if(dna) + base_icon_state = dna.species.update_base_icon_state(src) + else + if(HUSK in mutations) + base_icon_state = "husk" else - if(HUSK in mutations) - base_icon_state = "husk" - else - base_icon_state = "[skin_tone]_[(gender == FEMALE) ? "f" : "m"]" + base_icon_state = "[skin_tone]_[(gender == FEMALE) ? "f" : "m"]" + icon_state = "[base_icon_state]_s" /mob/living/carbon/human/proc/apply_overlay(cache_index) var/image/I = overlays_standing[cache_index] + if(I) overlays += I @@ -145,42 +146,11 @@ Please contact me on #coderbus IRC. ~Carnie x //Reset our hair remove_overlay(HAIR_LAYER) - //mutants don't have hair. masks and helmets can obscure our hair too. - if( (HUSK in mutations) || (dna && dna.mutantrace) || (head && (head.flags & BLOCKHAIR)) || (wear_mask && (wear_mask.flags & BLOCKHAIR)) ) + if( (HUSK in mutations) || (head && (head.flags & BLOCKHAIR)) || (wear_mask && (wear_mask.flags & BLOCKHAIR)) ) return - //base icons - var/datum/sprite_accessory/S - var/list/standing = list() - - if(facial_hair_style) - S = facial_hair_styles_list[facial_hair_style] - if(S) - var/image/img_facial_s = image("icon" = S.icon, "icon_state" = "[S.icon_state]_s", "layer" = -HAIR_LAYER) - - var/new_color = "#" + facial_hair_color - img_facial_s.color = new_color - - standing += img_facial_s - - //Applies the debrained overlay if there is no brain - if(!getorgan(/obj/item/organ/brain)) - standing += image("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s", "layer" = -HAIR_LAYER) - else if(hair_style) - S = hair_styles_list[hair_style] - if(S) - var/image/img_hair_s = image("icon" = S.icon, "icon_state" = "[S.icon_state]_s", "layer" = -HAIR_LAYER) - - var/new_color = "#" + hair_color - img_hair_s.color = new_color - - standing += img_hair_s - - if(standing.len) - overlays_standing[HAIR_LAYER] = standing - - apply_overlay(HAIR_LAYER) - + if(dna) + dna.species.handle_hair(src) /mob/living/carbon/human/update_mutations() remove_overlay(MUTATIONS_LAYER) @@ -188,6 +158,7 @@ Please contact me on #coderbus IRC. ~Carnie x var/list/standing = list() var/g = (gender == FEMALE) ? "f" : "m" + for(var/mut in mutations) switch(mut) if(HULK) @@ -203,41 +174,22 @@ Please contact me on #coderbus IRC. ~Carnie x apply_overlay(MUTATIONS_LAYER) +/mob/living/carbon/human/proc/update_mutcolor() + if(dna && !(HUSK in mutations)) + dna.species.update_color(src) /mob/living/carbon/human/proc/update_body() remove_overlay(BODY_LAYER) - update_base_icon_state() + if(dna) + base_icon_state = dna.species.update_base_icon_state(src) + else + update_base_icon_state() + icon_state = "[base_icon_state]_s" - var/list/standing = list() - - //Mouth (lipstick!) - if(lip_style) - standing += image("icon"='icons/mob/human_face.dmi', "icon_state"="lips_[lip_style]_s", "layer" = -BODY_LAYER) - - //Eyes - if(!dna || dna.mutantrace != "skeleton") - var/image/img_eyes_s = image("icon" = 'icons/mob/human_face.dmi', "icon_state" = "eyes_s", "layer" = -BODY_LAYER) - - var/new_color = "#" + eye_color - - img_eyes_s.color = new_color - - standing += img_eyes_s - - //Underwear - if(underwear) - var/datum/sprite_accessory/underwear/U = underwear_all[underwear] - if(U) - standing += image("icon"=U.icon, "icon_state"="[U.icon_state]_s", "layer"=-BODY_LAYER) - - - if(standing.len) - overlays_standing[BODY_LAYER] = standing - - apply_overlay(BODY_LAYER) - + if(dna) // didn't want to have a duplicate if(dna) here, but due to the ordering of the code this was the only way + dna.species.handle_body(src) /mob/living/carbon/human/update_fire() @@ -274,8 +226,6 @@ Please contact me on #coderbus IRC. ~Carnie x apply_overlay(AUGMENTS_LAYER) - - /* --------------------------------------- */ //For legacy support. /mob/living/carbon/human/regenerate_icons() @@ -305,6 +255,8 @@ Please contact me on #coderbus IRC. ~Carnie x update_transform() //Hud Stuff update_hud() + // Mutantrace colors + update_mutcolor() /* --------------------------------------- */ //vvvvvv UPDATE_INV PROCS vvvvvv @@ -322,16 +274,18 @@ Please contact me on #coderbus IRC. ~Carnie x var/t_color = w_uniform.item_color if(!t_color) t_color = icon_state var/image/standing = image("icon"='icons/mob/uniform.dmi', "icon_state"="[t_color]_s", "layer"=-UNIFORM_LAYER) + overlays_standing[UNIFORM_LAYER] = standing - var/G = (gender == FEMALE) ? "f" : "m" - if(G == "f" && U.fitted == 1) - var/index = "[t_color]_s" - var/icon/female_uniform_icon = female_uniform_icons[index] - if(!female_uniform_icon ) //Create standing/laying icons if they don't exist - generate_uniform(index,t_color) - standing = image("icon"=female_uniform_icons["[t_color]_s"], "layer"=-UNIFORM_LAYER) - overlays_standing[UNIFORM_LAYER] = standing + if(dna && dna.species.sexes) + var/G = (gender == FEMALE) ? "f" : "m" + if(G == "f" && U.fitted == 1) + var/index = "[t_color]_s" + var/icon/female_uniform_icon = female_uniform_icons[index] + if(!female_uniform_icon ) //Create standing/laying icons if they don't exist + generate_uniform(index,t_color) + standing = image("icon"=female_uniform_icons["[t_color]_s"], "layer"=-UNIFORM_LAYER) + overlays_standing[UNIFORM_LAYER] = standing if(w_uniform.blood_DNA) standing.overlays += image("icon"='icons/effects/blood.dmi', "icon_state"="uniformblood") @@ -375,6 +329,7 @@ Please contact me on #coderbus IRC. ~Carnie x if(gloves.blood_DNA) standing.overlays += image("icon"='icons/effects/blood.dmi', "icon_state"="bloodyhands") + else if(blood_DNA) overlays_standing[GLOVES_LAYER] = image("icon"='icons/effects/blood.dmi', "icon_state"="bloodyhands") @@ -532,7 +487,6 @@ Please contact me on #coderbus IRC. ~Carnie x if(wear_mask.blood_DNA && !istype(wear_mask, /obj/item/clothing/mask/cigarette)) standing.overlays += image("icon"='icons/effects/blood.dmi', "icon_state"="maskblood") - apply_overlay(FACEMASK_LAYER) @@ -628,7 +582,9 @@ Please contact me on #coderbus IRC. ~Carnie x apply_overlay(L_HAND_LAYER) + //Human Overlays Indexes///////// +#undef SPECIES_LAYER #undef BODY_LAYER #undef MUTATIONS_LAYER #undef DAMAGE_LAYER diff --git a/code/modules/mob/living/carbon/metroid/life.dm b/code/modules/mob/living/carbon/metroid/life.dm index 3cfb35adffc..c045f843831 100644 --- a/code/modules/mob/living/carbon/metroid/life.dm +++ b/code/modules/mob/living/carbon/metroid/life.dm @@ -331,13 +331,10 @@ if(issilicon(L) && (rabid || attacked)) // They can't eat silicons, but they can glomp them in defence targets += L // Possible target found! - if(isanimal(L) && (rabid || attacked || hungry >= 2)) //Simple_Animals only get retaliated against. - targets += L - - if(istype(L, /mob/living/carbon/human)) // Ignore slime(wo)men + if(istype(L, /mob/living/carbon/human) && dna) //Ignore slime(wo)men var/mob/living/carbon/human/H = L if(H.dna) - if(H.dna.mutantrace == "slime") + if(/mob/living/carbon/slime in H.dna.species.ignored_by) continue if(!L.canmove) // Only one slime can latch on at a time. @@ -568,4 +565,4 @@ if (hunger == 2 || rabid || attacked) return 1 if (Leader) return 0 if (holding_still) return 0 - return 1 \ No newline at end of file + return 1 diff --git a/code/modules/mob/living/carbon/metroid/metroid.dm b/code/modules/mob/living/carbon/metroid/metroid.dm index 3d1c6f8c70c..6f53f94d6de 100644 --- a/code/modules/mob/living/carbon/metroid/metroid.dm +++ b/code/modules/mob/living/carbon/metroid/metroid.dm @@ -225,7 +225,7 @@ //paralysis += 1 - show_message(" The blob attacks you!") + show_message(" The blob attacks you!") adjustFireLoss(damage) @@ -237,7 +237,7 @@ return /mob/living/carbon/slime/attack_ui(slot) - return + return /mob/living/carbon/slime/attack_slime(mob/living/carbon/slime/M as mob) if (!ticker) @@ -248,10 +248,8 @@ if (health > -100) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" The [M.name] has glomped []!", src), 1) - + visible_message(" The [M.name] has glomped [src]!", \ + " The [M.name] has glomped [src]!") var/damage = rand(1, 3) attacked += 5 @@ -271,8 +269,8 @@ else if(M.attack_sound) playsound(loc, M.attack_sound, 50, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message(" [M] [M.attacktext] [src]!", 1) + visible_message("[M] [M.attacktext] [src]!", \ + "[M] [M.attacktext] [src]!") add_logs(M, src, "attacked", admin=0) var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) attacked += 10 @@ -303,9 +301,8 @@ if (health > 0) attacked += 10 //playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [M.name] has attacked [src]!"), 1) + visible_message("[M.name] has attacked [src]!", \ + "[M.name] has attacked [src]!") adjustBruteLoss(rand(1, 3)) updatehealth() return @@ -325,15 +322,11 @@ if(Victim) if(Victim == M) if(prob(60)) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(" [M] attempts to wrestle \the [name] off!", 1) + visible_message("[M] attempts to wrestle \the [name] off!") playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) else - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(" [M] manages to wrestle \the [name] off!", 1) + visible_message(" [M] manages to wrestle \the [name] off!") playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) if(prob(90) && !client) @@ -353,15 +346,11 @@ else if(prob(30)) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(" [M] attempts to wrestle \the [name] off of [Victim]!", 1) + visible_message("[M] attempts to wrestle \the [name] off of [Victim]!") playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) else - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(" [M] manages to wrestle \the [name] off of [Victim]!", 1) + visible_message(" [M] manages to wrestle \the [name] off of [Victim]!") playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) if(prob(80) && !client) @@ -400,9 +389,7 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has grabbed [] passively!", M, src), 1) + visible_message("[M] has grabbed [src] passively!") else @@ -426,17 +413,14 @@ playsound(loc, "punch", 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has punched []!", M, src), 1) + visible_message("[M] has punched [src]!", \ + "[M] has punched [src]!") adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has attempted to punch []!", M, src), 1) + visible_message("[M] has attempted to punch [src]!") return @@ -452,9 +436,7 @@ switch(M.a_intent) if ("help") - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\blue [M] caresses [src] with its scythe like arm."), 1) + visible_message("[M] caresses [src] with its scythe like arm.") if ("harm") @@ -464,20 +446,17 @@ var/damage = rand(15, 30) if (damage >= 25) damage = rand(20, 40) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has attacked [name]!", M), 1) + visible_message("[M] has attacked [name]!", \ + "[M] has attacked [name]!") else - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has wounded [name]!", M), 1) + visible_message("[M] has wounded [name]!", \ + ")[M] has wounded [name]!") adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has attempted to lunge at [name]!", M), 1) + visible_message("[M] has attempted to lunge at [name]!", \ + "[M] has attempted to lunge at [name]!") if ("grab") if (M == src || anchored) @@ -491,8 +470,7 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - O.show_message(text(" [] has grabbed [name] passively!", M), 1) + visible_message(" [M] has grabbed [name] passively!") if ("disarm") playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) @@ -500,9 +478,8 @@ attacked += 10 if(prob(95)) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has tackled [name]!", M), 1) + visible_message("[M] has tackled [name]!", \ + "[M] has tackled [name]!") if(Victim || Target) Victim = null @@ -527,9 +504,8 @@ else drop_item() - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has disarmed [name]!", M), 1) + visible_message("[M] has disarmed [name]!", + "[M] has disarmed [name]!") adjustBruteLoss(damage) updatehealth() return @@ -538,7 +514,7 @@ if(W.force > 0) attacked += 10 if(prob(25)) - user << "\red [W] passes right through [src]!" + user << "[W] passes right through [src]!" return if(Discipline && prob(50)) // wow, buddy, why am I getting attacked?? Discipline = 0 @@ -847,6 +823,8 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 ////////Adamantine Golem stuff I dunno where else to put it +// This will eventually be removed. + /obj/item/clothing/under/golem name = "adamantine skin" desc = "a golem's skin" @@ -855,7 +833,6 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 item_color = "golem" flags = ABSTRACT | NODROP has_sensor = 0 - armor = list(melee = 10, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) /obj/item/clothing/suit/golem name = "adamantine shell" @@ -866,14 +843,8 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 gas_transfer_coefficient = 0.90 permeability_coefficient = 0.50 body_parts_covered = FULL_BODY - slowdown = 1.0 flags_inv = HIDEGLOVES | HIDESHOES | HIDEJUMPSUIT - flags = STOPSPRESSUREDMAGE | ABSTRACT | NODROP - heat_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS | HEAD - max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT - cold_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS | HEAD - min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT - armor = list(melee = 80, bullet = 20, laser = 20, energy = 10, bomb = 0, bio = 0, rad = 0) + flags = ABSTRACT | NODROP /obj/item/clothing/shoes/golem name = "golem's feet" @@ -881,7 +852,6 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 icon_state = "golem" item_state = null flags = NOSLIP | ABSTRACT | NODROP - slowdown = SHOES_SLOWDOWN+1 /obj/item/clothing/mask/breath/golem @@ -891,7 +861,7 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 item_state = "golem" siemens_coefficient = 0 unacidable = 1 - flags = ABSTRACT | NODROP | MASKINTERNALS | MASKCOVERSMOUTH + flags = ABSTRACT | NODROP /obj/item/clothing/gloves/golem @@ -910,10 +880,7 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 name = "golem's head" desc = "a golem's head" unacidable = 1 - flags = STOPSPRESSUREDMAGE | ABSTRACT | NODROP - heat_protection = HEAD - max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT - armor = list(melee = 80, bullet = 20, laser = 20, energy = 10, bomb = 0, bio = 0, rad = 0) + flags = ABSTRACT | NODROP /obj/effect/golemrune anchored = 1 @@ -952,14 +919,9 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 return var/mob/living/carbon/human/G = new /mob/living/carbon/human if(prob(50)) G.gender = "female" - hardset_dna(G, null, null, null, "adamantine") + hardset_dna(G, null, null, null, null, /datum/species/golem/adamantine) G.real_name = text("Adamantine Golem ([rand(1, 1000)])") - G.equip_to_slot_or_del(new /obj/item/clothing/under/golem(G), slot_w_uniform) - G.equip_to_slot_or_del(new /obj/item/clothing/suit/golem(G), slot_wear_suit) - G.equip_to_slot_or_del(new /obj/item/clothing/shoes/golem(G), slot_shoes) - G.equip_to_slot_or_del(new /obj/item/clothing/mask/breath/golem(G), slot_wear_mask) - G.equip_to_slot_or_del(new /obj/item/clothing/gloves/golem(G), slot_gloves) - //G.equip_to_slot_or_del(new /obj/item/clothing/head/space/golem(G), slot_head) + G.dna.species.auto_equip(G) G.loc = src.loc G.key = ghost.key G << "You are an adamantine golem. You move slowly, but are highly resistant to heat and cold as well as blunt trauma. You are unable to wear clothes, but can still use most tools. Serve [user], and assist them in completing their goals at any cost." @@ -1047,9 +1009,9 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 /obj/item/weapon/reagent_containers/food/snacks/egg/slime/proc/Hatch() processing_objects.Remove(src) var/turf/T = get_turf(src) - src.visible_message("\blue The [name] pulsates and quivers!") + src.visible_message(" The [name] pulsates and quivers!") spawn(rand(50,100)) - src.visible_message("\blue The [name] bursts open!") + src.visible_message(" The [name] bursts open!") new/mob/living/carbon/slime(T) qdel(src) @@ -1065,4 +1027,4 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 return else ..() -*/ \ No newline at end of file +*/ diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index d1f94f76d29..e7492ba5f1c 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -77,8 +77,8 @@ if ((M.a_intent == "harm" && !( istype(wear_mask, /obj/item/clothing/mask/muzzle) ))) if ((prob(75) && health > 0)) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - O.show_message("[M.name] bites [name]!", 1) + visible_message("[M.name] bites [name]!", \ + "[M.name] bites [name]!") var/damage = rand(1, 5) adjustBruteLoss(damage) health = 100 - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() @@ -86,8 +86,8 @@ if(istype(D, /datum/disease/jungle_fever)) contract_disease(D,1,0) else - for(var/mob/O in viewers(src, null)) - O.show_message("[M.name] has attempted to bite [name]!", 1) + visible_message("[M.name] has attempted to bite [name]!", \ + "[M.name] has attempted to bite [name]!") return /mob/living/carbon/monkey/attack_hand(mob/living/carbon/human/M as mob) @@ -108,9 +108,8 @@ else if (M.a_intent == "harm") if (prob(75)) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has punched [name]!", M), 1) + visible_message("[M] has punched [name]!", \ + "[M] has punched [name]!") playsound(loc, "punch", 25, 1, -1) var/damage = rand(5, 10) @@ -119,17 +118,15 @@ if ( (paralysis < 5) && (health > 0) ) Paralyse(rand(10, 15)) spawn( 0 ) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has knocked out [name]!", M), 1) + visible_message("[M] has knocked out [name]!", \ + "[M] has knocked out [name]!") return adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has attempted to punch [name]!", M), 1) + visible_message("[M] has attempted to punch [name]!", \ + "[M] has attempted to punch [name]!") else if (M.a_intent == "grab") if (M == src || anchored) @@ -144,22 +141,19 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - O.show_message(text("\red [] has grabbed [name] passively!", M), 1) + visible_message("[M] has grabbed [name] passively!") else if (!( paralysis )) if (prob(25)) Paralyse(2) playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has pushed down [name]!", M), 1) + visible_message("[M] has pushed down [src]!", \ + "[M] has pushed down [src]!") else if(drop_item()) playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has disarmed [name]!", M), 1) + visible_message("[M] has disarmed [src]!", \ + "[M] has disarmed [src]!") return /mob/living/carbon/monkey/attack_alien(mob/living/carbon/alien/humanoid/M as mob) @@ -173,9 +167,7 @@ switch(M.a_intent) if ("help") - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\blue [M] caresses [src] with its scythe like arm."), 1) + visible_message(" [M] caresses [src] with its scythe like arm.") if ("harm") if ((prob(95) && health > 0)) @@ -185,20 +177,17 @@ damage = rand(20, 40) if (paralysis < 15) Paralyse(rand(10, 15)) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has wounded [name]!", M), 1) + visible_message("[M] has wounded [name]!", \ + "[M] has wounded [name]!") else - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has slashed [name]!", M), 1) + visible_message("[M] has slashed [name]!", \ + "[M] has slashed [name]!") adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has attempted to lunge at [name]!", M), 1) + visible_message("[M] has attempted to lunge at [name]!", \ + "[M] has attempted to lunge at [name]!") if ("grab") if (M == src || anchored) @@ -212,22 +201,19 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - O.show_message(text("\red [] has grabbed [name] passively!", M), 1) + visible_message("[M] has grabbed [name] passively!") if ("disarm") playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) var/damage = 5 if(prob(95)) Weaken(10) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has tackled down [name]!", M), 1) + visible_message("[M] has tackled down [name]!", \ + "[M] has tackled down [name]!") else if(drop_item()) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has disarmed [name]!", M), 1) + visible_message("[M] has disarmed [name]!", \ + "[M] has disarmed [name]!") adjustBruteLoss(damage) updatehealth() return @@ -238,8 +224,8 @@ else if(M.attack_sound) playsound(loc, M.attack_sound, 50, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message("[M] [M.attacktext] [src]!", 1) + visible_message("[M] [M.attacktext] [src]!", \ + "[M] [M.attacktext] [src]!") add_logs(M, src, "attacked", admin=0) var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) adjustBruteLoss(damage) @@ -255,9 +241,8 @@ if (health > -100) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("The [M.name] glomps []!", src), 1) + visible_message("The [M.name] glomps [src]!", \ + "The [M.name] glomps [src]!") var/damage = rand(1, 3) @@ -285,7 +270,8 @@ if(M.powerlevel < 0) M.powerlevel = 0 - visible_message("[M] shocked [src]!", "[M] shocked [src]!") + visible_message("[M] shocked [src]!", \ + "[M] shocked [src]!") Weaken(power) if (stuttering < power) @@ -343,6 +329,7 @@ /mob/living/carbon/monkey/blob_act() if (stat != 2) + show_message("The blob attacks you!") adjustFireLoss(60) health = 100 - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() if (prob(50)) @@ -360,4 +347,4 @@ return 0 /mob/living/carbon/monkey/canBeHandcuffed() - return 1 + return 1 diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 707e55f0602..d952a5be3f9 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -431,11 +431,11 @@ qdel(I) if(C.handcuffed) - C.update_inv_handcuffed(0) C.handcuffed = null + C.update_inv_handcuffed(0) else - C.update_inv_legcuffed(0) C.legcuffed = null + C.update_inv_legcuffed(0) /mob/living/proc/cuff_resist(obj/item/I, mob/living/carbon/C) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index e492bb5d2fb..e903b7cef30 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -16,6 +16,8 @@ /mob/living/proc/getarmor(var/def_zone, var/type) return 0 +/mob/living/proc/on_hit(var/obj/item/projectile/proj_type) + return /mob/living/bullet_act(obj/item/projectile/P, def_zone) var/armor = run_armor_check(def_zone, P.flag) diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 2ab4636438a..9506df68555 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -9,6 +9,7 @@ response_disarm = "flails at" response_harm = "punches" icon_dead = "shade_dead" + icon = 'icons/mob/mob.dmi' speed = 0 a_intent = "harm" stop_automated_movement = 1 @@ -25,6 +26,7 @@ minbodytemp = 0 faction = "cult" var/list/construct_spells = list() + var/playstyle_string = "You are a generic construct! Your job is to not exist." /mob/living/simple_animal/construct/New() ..() @@ -118,8 +120,7 @@ /mob/living/simple_animal/construct/armoured name = "Juggernaut" real_name = "Juggernaut" - desc = "A possessed suit of armour driven by the will of the restless dead" - icon = 'icons/mob/mob.dmi' + desc = "A possessed suit of armour driven by the will of the restless dead." icon_state = "behemoth" icon_living = "behemoth" maxHealth = 250 @@ -135,7 +136,8 @@ status_flags = 0 force_threshold = 11 construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall) - + playstyle_string = "You are a Juggernaut. Though slow, your shell can withstand extreme punishment, \ + create shield walls and even deflect energy weapons, and rip apart enemies and walls alike." /mob/living/simple_animal/construct/armoured/bullet_act(var/obj/item/projectile/P) if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)) @@ -174,7 +176,6 @@ name = "Wraith" real_name = "Wraith" desc = "A wicked bladed shell contraption piloted by a bound spirit" - icon = 'icons/mob/mob.dmi' icon_state = "floating" icon_living = "floating" maxHealth = 75 @@ -186,18 +187,16 @@ see_in_dark = 7 attack_sound = 'sound/weapons/bladeslice.ogg' construct_spells = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift) + playstyle_string = "You are a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls." /////////////////////////////Artificer///////////////////////// - - /mob/living/simple_animal/construct/builder name = "Artificer" real_name = "Artificer" desc = "A bulbous construct dedicated to building and maintaining The Cult of Nar-Sie's armies" - icon = 'icons/mob/mob.dmi' icon_state = "artificer" icon_living = "artificer" maxHealth = 50 @@ -215,60 +214,31 @@ /obj/effect/proc_holder/spell/aoe_turf/conjure/floor, /obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone, /obj/effect/proc_holder/spell/targeted/projectile/magic_missile/lesser) + playstyle_string = "You are an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, \ + use magic missile, repair allied constructs (by clicking on them), \ + and most important of all create new constructs \ + (Use your Artificer spell to summon a new construct shell and Summon Soulstone to create a new soulstone)." +/////////////////////////////Harvester///////////////////////// -/////////////////////////////Behemoth///////////////////////// +/mob/living/simple_animal/construct/harvester + name = "Harvester" + real_name = "Harvester" + desc = "A harbinger of Nar-Sie's enlightenment. It'll be all over soon." + icon_state = "harvester" + icon_living = "harvester" + maxHealth = 60 + health = 60 + melee_damage_lower = 1 + melee_damage_upper = 5 + attacktext = "prods" + speed = 0 + environment_smash = 1 + see_in_dark = 7 + attack_sound = 'sound/weapons/tap.ogg' + construct_spells = list(/obj/effect/proc_holder/spell/targeted/smoke/disable) + playstyle_string = "You are a Harvester. You are not strong, but your powers of domination will assist you in your role: \ + Bring those who still cling to this world of illusion back to the Geometer so they may know Truth." - -/mob/living/simple_animal/construct/behemoth - name = "Behemoth" - real_name = "Behemoth" - desc = "The pinnacle of occult technology, Behemoths are the ultimate weapon in the Cult of Nar-Sie's arsenal." - icon = 'icons/mob/mob.dmi' - icon_state = "behemoth" - icon_living = "behemoth" - maxHealth = 750 - health = 750 - speak_emote = list("rumbles") - response_harm = "harmlessly punches" - harm_intent_damage = 0 - melee_damage_lower = 50 - melee_damage_upper = 50 - attacktext = "brutally crushes" - speed = 5 - environment_smash = 2 - attack_sound = 'sound/weapons/punch4.ogg' - force_threshold = 11 - var/energy = 0 - var/max_energy = 1000 - - -////////////////Powers////////////////// - - -/* -/client/proc/summon_cultist() - set category = "Behemoth" - set name = "Summon Cultist (300)" - set desc = "Teleport a cultist to your location" - if (istype(usr,/mob/living/simple_animal/constructbehemoth)) - - if(usr.energy<300) - usr << "\red You do not have enough power stored!" - return - - if(usr.stat) - return - - usr.energy -= 300 - var/list/mob/living/cultists = new - for(var/datum/mind/H in ticker.mode.cult) - if (istype(H.current,/mob/living)) - cultists+=H.current - var/mob/cultist = input("Choose the one who you want to summon", "Followers of Geometer") as null|anything in (cultists - usr) - if(!cultist) - return - if (cultist == usr) //just to be sure. - return - cultist.loc = usr.loc - usr.visible_message("/red [cultist] appears in a flash of red light as [usr] glows with power")*/ +/mob/living/simple_animal/construct/harvester/Process_Spacemove(var/check_drift = 0) + return 1 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 522122633b8..c65884dfc63 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -111,6 +111,11 @@ return 0 if(L in friends) return 0 + if(ishuman(L)) + var/mob/living/carbon/human/H = L + if(H.dna) + if(src.type in H.dna.species.ignored_by) + return 0 return 1 if(isobj(the_target)) if(the_target.type in wanted_objects) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index bf2a8a17afd..38916358259 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -245,8 +245,7 @@ return if(act) if(act == "scream") act = "makes a loud and pained whimper" //ugly hack to stop animals screaming when crushed :P - for (var/mob/O in viewers(src, null)) - O.show_message("[src] [act].") + visible_message("[src] [act].") /mob/living/simple_animal/attack_animal(mob/living/simple_animal/M as mob) @@ -255,8 +254,8 @@ else if(M.attack_sound) playsound(loc, M.attack_sound, 50, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message("\red \The [M] [M.attacktext] [src]!", 1) + visible_message("\The [M] [M.attacktext] [src]!", \ + "\The [M] [M.attacktext] [src]!") add_logs(M, src, "attacked", admin=0) var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) adjustBruteLoss(damage) @@ -276,9 +275,7 @@ if("help") if (health > 0) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message("\blue [M] [response_help] [src].") + visible_message(" [M] [response_help] [src].") if("grab") if (M == src || anchored) @@ -294,15 +291,11 @@ LAssailant = M - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has grabbed [] passively!", M, src), 1) + visible_message("[M] has grabbed [src] passively!") if("harm", "disarm") adjustBruteLoss(harm_intent_damage) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message("\red [M] [response_harm] [src]!") + visible_message("[M] [response_harm] [src]!") return @@ -312,9 +305,7 @@ if ("help") - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\blue [M] caresses [src] with its scythe like arm."), 1) + visible_message("[M] caresses [src] with its scythe like arm.") if ("grab") if(M == src || anchored) return @@ -329,13 +320,12 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has grabbed [] passively!", M, src), 1) + visible_message("[M] has grabbed [src] passively!") if("harm", "disarm") var/damage = rand(15, 30) - visible_message("\red [M] has slashed at [src]!") + visible_message("[M] has slashed at [src]!", \ + "[M] has slashed at [src]!") adjustBruteLoss(damage) return @@ -344,13 +334,14 @@ switch(L.a_intent) if("help") - visible_message("\blue [L] rubs it's head against [src]") + visible_message("[L] rubs its head against [src].") else var/damage = rand(5, 10) - visible_message("\red [L] bites [src]!") + visible_message("[L] bites [src]!", \ + "[L] bites [src]!") if(stat != DEAD) L.amount_grown = min(L.amount_grown + damage, L.max_grown) @@ -364,7 +355,8 @@ if(M.Victim) return // can't attack while eating! - visible_message("\red [M.name] glomps [src]!") + visible_message("[M.name] glomps [src]!", \ + "[M.name] glomps [src]!") var/damage = rand(1, 3) @@ -391,18 +383,16 @@ MED.amount -= 1 if(MED.amount <= 0) qdel(MED) - for(var/mob/M in viewers(src, null)) - if ((M.client && !( M.blinded ))) - M.show_message("\blue [user] applies [MED] on [src]") + visible_message(" [user] applies [MED] on [src].") return else - user << "\blue [MED] won't help at all." + user << " [MED] won't help at all." return else - user << "\blue [src] is at full health." + user << " [src] is at full health." return else - user << "\blue [src] is dead, medical items won't bring it back to life." + user << " [src] is dead, medical items won't bring it back to life." return else if(meat_type && (stat == DEAD)) //if the animal has a meat, and if it is dead. if(istype(O, /obj/item/weapon/kitchenknife) || istype(O, /obj/item/weapon/butch)) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index e295e0b6553..25d81d559cb 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -420,6 +420,9 @@ proc/is_special_character(mob/M) // returns 1 for special characters and 2 for h var/list/hands = list(M.l_hand, M.r_hand) return hands +/mob/proc/reagent_check(var/datum/reagent/R) // utilized in the species code + return 1 + /proc/item_heal_robotic(var/mob/living/carbon/human/H, var/mob/user, var/brute, var/burn) var/obj/item/organ/limb/affecting = H.get_organ(check_zone(user.zone_sel.selecting)) @@ -442,4 +445,4 @@ proc/is_special_character(mob/M) // returns 1 for special characters and 2 for h user << "[H]'s [affecting.getDisplayName()] is already in good condition" return else - return \ No newline at end of file + return diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index 6badea404f5..17df645d3aa 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -12,6 +12,7 @@ datum/preferences hair_color = random_short_color() facial_hair_color = hair_color eye_color = random_eye_color() + pref_species = new /datum/species/human() backbag = 2 age = rand(AGE_MIN,AGE_MAX) @@ -23,7 +24,11 @@ datum/preferences var/g = "m" if(gender == FEMALE) g = "f" - preview_icon = new /icon('icons/mob/human.dmi', "[skin_tone]_[g]_s") + if(pref_species.id == "human" || !config.mutant_races) + preview_icon = new /icon('icons/mob/human.dmi', "[skin_tone]_[g]_s") + else + preview_icon = new /icon('icons/mob/human.dmi', "[pref_species.id]_[g]_s") + preview_icon.Blend("#[mutant_color]", ICON_MULTIPLY) var/datum/sprite_accessory/S if(underwear) @@ -31,17 +36,19 @@ datum/preferences if(S) preview_icon.Blend(new /icon(S.icon, "[S.icon_state]_s"), ICON_OVERLAY) - var/icon/eyes_s = new/icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = "eyes_s") - eyes_s.Blend("#[eye_color]", ICON_MULTIPLY) + var/icon/eyes_s = new/icon() + if(EYECOLOR in pref_species.specflags) + eyes_s = new/icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = "[pref_species.eyes]_s") + eyes_s.Blend("#[eye_color]", ICON_MULTIPLY) S = hair_styles_list[hair_style] - if(S) + if(S && (HAIR in pref_species.specflags)) var/icon/hair_s = new/icon("icon" = S.icon, "icon_state" = "[S.icon_state]_s") hair_s.Blend("#[hair_color]", ICON_MULTIPLY) eyes_s.Blend(hair_s, ICON_OVERLAY) S = facial_hair_styles_list[facial_hair_style] - if(S) + if(S && (FACEHAIR in pref_species.specflags)) var/icon/facial_s = new/icon("icon" = S.icon, "icon_state" = "[S.icon_state]_s") facial_s.Blend("#[facial_hair_color]", ICON_MULTIPLY) eyes_s.Blend(facial_s, ICON_OVERLAY) diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 03fb40fb3a9..dae51d0cc97 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -131,6 +131,12 @@ O.gender = (deconstruct_block(getblock(dna.uni_identity, DNA_GENDER_BLOCK), 2)-1) ? FEMALE : MALE O.dna = dna + + if(!dna.species) + O.dna.species = new /datum/species/human() + else + O.dna.species = new dna.species.type() + dna = null if (newname) //if there's a name as an argument, always take that one over the current name O.real_name = newname @@ -473,20 +479,8 @@ if(!MP) return 0 //Sanity, this should never happen. -// if(ispath(MP, /mob/living/simple_animal/space_worm)) //Goodbye Space Worms 2014 -// return 0 //Unfinished. Very buggy, they seem to just spawn additional space worms everywhere and eating your own tail results in new worms spawning. - - if(ispath(MP, /mob/living/simple_animal/construct/behemoth)) - return 0 //I think this may have been an unfinished WiP or something. These constructs should really have their own class simple_animal/construct/subtype - - if(ispath(MP, /mob/living/simple_animal/construct/armoured)) - return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype - - if(ispath(MP, /mob/living/simple_animal/construct/wraith)) - return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype - - if(ispath(MP, /mob/living/simple_animal/construct/builder)) - return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype + if(ispath(MP, /mob/living/simple_animal/construct)) + return 0 //Verbs do not appear for players. //Good mobs! if(ispath(MP, /mob/living/simple_animal/cat)) diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index 95bb4dec398..e49459293f1 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -350,11 +350,13 @@ var/const/GRAV_NEEDS_WRENCH = 3 // Shake everyone on the z level to let them know that gravity was enagaged/disenagaged. /obj/machinery/gravity_generator/main/proc/shake_everyone() var/turf/our_turf = get_turf(src) - for(var/mob/M in player_list) + for(var/mob/M in mob_list) var/turf/their_turf = get_turf(M) - if(M.client && their_turf.z == our_turf.z) - shake_camera(M, 15, 1) - M.playsound_local(our_turf, 'sound/effects/alert.ogg', 100, 1, 0.5) + if(their_turf.z == our_turf.z) + M.update_gravity(M.mob_has_gravity()) + if(M.client) + shake_camera(M, 15, 1) + M.playsound_local(our_turf, 'sound/effects/alert.ogg', 100, 1, 0.5) /obj/machinery/gravity_generator/main/proc/gravity_in_level() var/turf/T = get_turf(src) diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index a0725f79ee5..3d2c161a28f 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -1,10 +1,5 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 -var/global/list/uneatable = list( - /turf/space, - /obj/effect/overlay - ) - /obj/machinery/singularity name = "gravitational singularity" desc = "A gravitational singularity." @@ -32,6 +27,7 @@ var/global/list/uneatable = list( var/last_failed_movement = 0//Will not move in the same dir if it couldnt before, will help with the getting stuck on fields thing var/teleport_del = 0 var/last_warning + var/list/uneatable = list(/turf/space, /obj/effect/overlay) /obj/machinery/singularity/New(loc, var/starting_energy = 50, var/temp = 0) //CARN: admin-alert for chuckle-fuckery. @@ -477,6 +473,7 @@ var/global/list/uneatable = list( move_self = 1 //Do we move on our own? grav_pull = 5 //How many tiles out do we pull? consume_range = 6 //How many tiles out do we eat + uneatable = list(/turf/space, /obj/effect/overlay, /mob/living/simple_animal/construct) /obj/machinery/singularity/narsie/large name = "Nar-Sie" @@ -496,6 +493,12 @@ var/global/list/uneatable = list( if(emergency_shuttle) emergency_shuttle.incall(0.3) // Cannot recall + +/obj/machinery/singularity/narsie/large/attack_ghost(mob/dead/observer/user as mob) + makeNewConstruct(/mob/living/simple_animal/construct/harvester, user, null, 1) + new /obj/effect/effect/sleep_smoke(user.loc) + + /obj/machinery/singularity/narsie/process() eat() if(!target || prob(5)) @@ -538,8 +541,11 @@ var/global/list/uneatable = list( if(istype(A,/mob/living/)) var/mob/living/C = A + if(C.client) + makeNewConstruct(/mob/living/simple_animal/construct/harvester, C, null, 1) C.spawn_dust() C.gib() + return if(isturf(A)) var/turf/T = A @@ -550,35 +556,33 @@ var/global/list/uneatable = list( if(prob(20)) T.ChangeTurf(/turf/simulated/wall/cult) return + /obj/machinery/singularity/narsie/ex_act() //No throwing bombs at it either. --NEO return + /obj/machinery/singularity/narsie/proc/pickcultist() //Narsie rewards his cultists with being devoured first, then picks a ghost to follow. --NEO var/list/cultists = list() - for(var/datum/mind/cult_nh_mind in ticker.mode.cult) - if(!cult_nh_mind.current) - continue - if(cult_nh_mind.current.stat) - continue - var/turf/pos = get_turf(cult_nh_mind.current) - if(pos.z != src.z) - continue - cultists += cult_nh_mind.current - if(cultists.len) - acquire(pick(cultists)) - return - //If there was living cultists, it picks one to follow. - for(var/mob/living/carbon/human/food in living_mob_list) - if(food.stat) - continue + var/list/noncultists = list() + for(var/mob/living/carbon/food in living_mob_list) //we don't care about constructs or cult-Ians or whatever. cult-monkeys are fair game i guess var/turf/pos = get_turf(food) if(pos.z != src.z) continue - cultists += food - if(cultists.len) - acquire(pick(cultists)) - return - //no living cultists, pick a living human instead. + + if(iscultist(food)) + cultists += food + else + noncultists += food + + if(cultists.len) //cultists get higher priority + acquire(pick(cultists)) + return + + if(noncultists.len) + acquire(pick(noncultists)) + return + + //no living humans, follow a ghost instead. for(var/mob/dead/observer/ghost in player_list) if(!ghost.client) continue @@ -589,7 +593,7 @@ var/global/list/uneatable = list( if(cultists.len) acquire(pick(cultists)) return - //no living humans, follow a ghost instead. + /obj/machinery/singularity/narsie/proc/acquire(var/mob/food) target << "\blue NAR-SIE HAS LOST INTEREST IN YOU" diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 7d79eaeb7de..ea2a9a8c73e 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -80,8 +80,8 @@ return if(ishuman(user)) var/mob/living/carbon/human/H = user - if(H.dna && H.dna.mutantrace == "adamantine") - user << "Your metal fingers don't fit in the trigger guard!" + if(H.dna && NOGUNS in H.dna.species.specflags) + user << "Your fingers don't fit in the trigger guard!" return add_fingerprint(user) diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 988d947a13e..f1ee2f12a74 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -33,20 +33,24 @@ /obj/item/weapon/gun/energy/afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, params) - newshot() + newshot() //prepare a new shot ..() /obj/item/weapon/gun/energy/proc/newshot() - if (!ammo_type || !power_supply) return + if (!ammo_type || !power_supply) + return var/obj/item/ammo_casing/energy/shot = ammo_type[select] - if (!power_supply.use(shot.e_cost)) return - chambered = shot - chambered.newshot() + if(power_supply.charge >= shot.e_cost) //if there's enough power in the power_supply cell... + chambered = shot //...prepare a new shot based on the current ammo type selected + chambered.newshot() return /obj/item/weapon/gun/energy/process_chamber() - chambered = null + if(chambered && !chambered.BB) //if BB is null, i.e the shot has been fired... + var/obj/item/ammo_casing/energy/shot = chambered + power_supply.use(shot.e_cost)//... drain the power_supply cell + chambered = null //either way, released the prepared shot return /obj/item/weapon/gun/energy/proc/select_fire(mob/living/user as mob) @@ -56,7 +60,7 @@ var/obj/item/ammo_casing/energy/shot = ammo_type[select] fire_sound = shot.fire_sound if (shot.select_name) - user << "\red [src] is now set to [shot.select_name]." + user << "[src] is now set to [shot.select_name]." update_icon() return diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 6fc8094d59f..afd7bf263ab 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -58,6 +58,7 @@ if(!isliving(target)) return 0 if(isanimal(target)) return 0 var/mob/living/L = target + L.on_hit(type) return L.apply_effects(stun, weaken, paralyze, irradiate, stutter, eyeblur, drowsy, blocked) proc/vol_by_damage() diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index e65431d7ad7..2efdbab093b 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -199,8 +199,12 @@ proc/wabbajack(mob/living/M) var/mob/living/carbon/human/H = new_mob ready_dna(H) if(H.dna) - H.dna.mutantrace = pick("lizard","golem","slime","plant","fly","shadow","adamantine","skeleton",8;"") - H.update_body() + var/list/randspecies = list() + for(var/t in typesof(/datum/species)) // returns a bunch of types + var/datum/species/temp = new t() + randspecies += "[temp.type]" + var/datum/species/new_species = pick(randspecies) + H.dna.species = new new_species() else return diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm index afe46c110e3..e067b00b949 100644 --- a/code/modules/projectiles/projectile/special.dm +++ b/code/modules/projectiles/projectile/special.dm @@ -82,32 +82,8 @@ flag = "energy" on_hit(var/atom/target, var/blocked = 0) - if(iscarbon(target)) - var/mob/living/carbon/M = target - if(check_dna_integrity(M) && M.dna.mutantrace == "plant") //Plantmen possibly get mutated and damaged by the rays. - if(prob(15)) - M.apply_effect((rand(30,80)),IRRADIATE) - M.Weaken(5) - for (var/mob/V in viewers(src)) - V.show_message("\red [M] writhes in pain as \his vacuoles boil.", 3, "\red You hear the crunching of leaves.", 2) - if(prob(35)) - // for (var/mob/V in viewers(src)) //Public messages commented out to prevent possible metaish genetics experimentation and stuff. - Cheridan - // V.show_message("\red [M] is mutated by the radiation beam.", 3, "\red You hear the snapping of twigs.", 2) - if(prob(80)) - randmutb(M) - domutcheck(M,null) - else - randmutg(M) - domutcheck(M,null) - else - M.adjustFireLoss(rand(5,15)) - M.show_message("\red The radiation beam singes you!") - // for (var/mob/V in viewers(src)) - // V.show_message("\red [M] is singed by the radiation beam.", 3, "\red You hear the crackle of burning leaves.", 2) - else - // for (var/mob/V in viewers(src)) - // V.show_message("The radiation beam dissipates harmlessly through [M]", 3) - M.show_message("\blue The radiation beam dissipates harmlessly through your body.") + ..() + return /obj/item/projectile/energy/florayield name = "beta somatoray" @@ -117,14 +93,9 @@ nodamage = 1 flag = "energy" - on_hit(mob/living/carbon/target, var/blocked = 0) - if(iscarbon(target)) - if(ishuman(target) && target.dna && target.dna.mutantrace == "plant") //These rays make plantmen fat. - target.nutrition = min(target.nutrition+30, 500) - else - target.show_message("\blue The radiation beam dissipates harmlessly through your body.") - else - return 1 + on_hit(mob/living/carbon/human/target, var/blocked = 0) + ..() + return /obj/item/projectile/beam/mindflayer diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm index a675580369a..4eec5cad53a 100644 --- a/code/modules/reagents/Chemistry-Holder.dm +++ b/code/modules/reagents/Chemistry-Holder.dm @@ -200,7 +200,9 @@ datum for(var/A in reagent_list) var/datum/reagent/R = A if(M && R) - R.on_mob_life(M) + if(M.reagent_check(R) != 1) + R.on_mob_life(M) + update_total() conditional_update_move(var/atom/A, var/Running = 0) diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm index e7a8c57b042..ef9f736fa34 100644 --- a/code/modules/reagents/Chemistry-Reagents.dm +++ b/code/modules/reagents/Chemistry-Reagents.dm @@ -342,18 +342,6 @@ datum reagent_state = LIQUID color = "#13BC5E" // rgb: 19, 188, 94 - on_mob_life(var/mob/living/M as mob) - if(!M) M = holder.my_atom - if(ishuman(M)) - var/mob/living/carbon/human/human = M - if(human.dna && !human.dna.mutantrace) - M << "Your flesh rapidly mutates!" - human.dna.mutantrace = "slime" - human.update_body() - human.update_hair() - ..() - return - aslimetoxin name = "Advanced Mutation Toxin" id = "amutationtoxin" @@ -1507,11 +1495,6 @@ datum var/mob/living/carbon/C = M if(!C.wear_mask) // If not wearing a mask C.adjustToxLoss(2) // 4 toxic damage per application, doubled for some reason - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.dna) - if(H.dna.mutantrace == "plant") //plantmen take a LOT of damage - H.adjustToxLoss(10) toxin/plantbgone/weedkiller name = "Weed Killer" @@ -1534,11 +1517,6 @@ datum var/mob/living/carbon/C = M if(!C.wear_mask) // If not wearing a mask C.adjustToxLoss(2) // 4 toxic damage per application, doubled for some reason - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.dna) - if(H.dna.mutantrace == "fly") //Botanists can now genocide plant and fly people alike. - H.adjustToxLoss(10) toxin/stoxin name = "Sleep Toxin" diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index e23270bafc3..0f630190c1a 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -62,9 +62,9 @@ var/who = (isnull(user) || eater == user) ? "your" : "their" if(istype(cover, /obj/item/clothing/mask/)) - user << "You have to remove [who] mask first!" + user << "You have to remove [who] mask first!" else - user << "You have to remove [who] helmet first!" + user << "You have to remove [who] helmet first!" return 0 - return 1 \ No newline at end of file + return 1 diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index 7d8ae71c443..697a96fc5bd 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -59,6 +59,12 @@ return if(ismob(target)) //Blood! + if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(H.dna) + if(NOBLOOD in H.dna.species.specflags) + user << "You are unable to locate any blood." + return if(reagents.has_reagent("blood")) user << "There is already a blood sample in this syringe." return diff --git a/config/game_options.txt b/config/game_options.txt index b9ca7e763ca..9ba5daa2914 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -187,5 +187,9 @@ SEC_START_BRIG ## Set to 2 for "random", silicons will start with a random lawset picked from (at the time of writing): P.A.L.A.D.I.N., Corporate, Asimov. More can be added by changing the law datum paths in ai_laws.dm. DEFAULT_LAWS 1 -## Uncoment to give players the choice of their mutantrace before they join the game -#JOIN_WITH_MUTANT_RACE \ No newline at end of file +## Uncoment to give players the choice of their species before they join the game +#JOIN_WITH_MUTANT_RACE + +## Uncomment to allow certain species to have custom colors + +#MUTANT_COLORS \ No newline at end of file diff --git a/icons/mob/human.dmi b/icons/mob/human.dmi index efbb59c0fd7c78ed5e5b5e9a7cb1a2c69d4d7fe5..8b586b4fab90982346399e6671a1c806d2086a5d 100644 GIT binary patch delta 43932 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 Rq=15dMyJg5%5?0){~y=o4`=`Y delta 45042 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 diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi index 9e2059cafbe1e3326a8b203ad8548c3843d775fd..7b9629e0de8b0ac4c926a794315b4e6e108127a5 100644 GIT binary patch literal 31661 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 L^LBxf$*cbb`l+}) literal 30991 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 z zG6@hJUEMQw-lX1pPOeEw;$f(g?lF(kG`8#4RSOLE=uh+tmiy!Fi3aHvqwQ_xca^Yf z0-<1_-?5)%edq>tyj#t+I%!wI*{y0$R6C4AHcQVegS!@q>zQjBo0EI8L|#b#wbPFn zv6ba0k4rXK)uQ^)F;)*h?E8*Jc8LTBFst5dt2T~wNqjo3Cfo1dpTohRmt;8Tot=?V z?u`gc}uRqI%DD#*o=?ox->PW@&SzXYacRHD*^^+l~PNt(@zQ2F)Si^^@AvCPgND168=K zuPPP6CkqtK8TU7PMI``p!xap1Ezj`@BguJenie_B7kcXOMPl-)Cw62E7VR6U`t`}H zXD$|D+Mh2SBah8QKmi284R2WS`w$L^btYH^&bK={UJ|GO-R)(e+ZFld^FaENN_;4G zx0|aG#B(6&wYj+oZiJ=zAvgCXX6C2I8U}M*AJ*POaw4YG-lp1eX=W=5@uy-qBDj2I z-%mGUa%H(diWRZpla_r+OpB|NwkQgeZepMv@tP@cU-7E@; zx&u#q*s)AMSSViJ@W-F|-X;(C-kgz-XOX%B4+jY~S1HNq%dy3bv`tTHC-;EnL#-^VGS^wT+N}lWUBg~2wnrY!*>nY8ccp#g7CTfPp7{J{ml%5bT7(o0! zGble$9T5%zRMvZ?w?mVL4Zxn?#SXqyrWB_o`|zLN|L~T}Z;boiyYJome(d$_HOF4xH@>~+nq%(u_=d?yqed?-nhDcl=9S^ak?39gyW(~hJn!ijo9JX-x;r2}G)=OC5t2Uq0w=eC^imwWs z(VQh{OzjzZw-YTp&Jsk&VkLolAA|J^@0SPaC*Cjj*Y~_%j?=$>e3W&*no1RSP!BVX zLn4K*AAx!6-K%9fpn(8z5^AWYeKX+YYId+MawNO0QLfa5*7O3Z6K(D+QP=X#+j=S1j-}@nXB|HY$>qn- zG@+R8l5Ol||7jD9`1(n^^x4JbyWNvoE-H%c+9esw{WQ%5ib3YH?fM3K=z`{ak5BZO zt55JE+X?Np0CO`E4ZQJe2cnBb!JIX*2n>bqAAsSE9o{Wqz^u3BLHNz{Tn2<~XKgv? zZ$L9}=f-HL;Dw&Di!o;t=tu)Cm7QF4Q%~Z098LuAs=N0thi9XsFmA*DThlN^;Eq99e_2Ufn=#qqg=$K4{Pyi*R2zGH<;w`*fw4R0C!9gs{L+33ITqb->t9ggI z$1_y@EX>l9*A{l6YH7ktacFtQCbVK%^kqZ0D=`r^TL=>+wPIspVpfDRJxV6%WoMWB zr^Z>YIuLT~UhnSu?XC-6EuNrT*~@y}zFs zT@@dU%h!$WpL?l$$%^#e=@C5_z~4_<*BRSBH2l5D2`oP)n!=8sFj1KO9J8gr$K!91 zPzk{DvhTf5k^=A%0~+nNGS0r!zk2he!kER5eh#MW>se*ol`@}pYpx3trvLB|V%%yk z@n4jblTN;( zz<~F|n>X5<6(SiZRF@ZfxY$ZdYvNl|s_e;6AQmyyo4LM!!IS?(oc{;FL#0$LRcBfa zJuC(_0z0|jE&!W3q4o~>LF5hc$Q}Q}RFsWWJD_(nnrZrIW=F-m!r*3_-me}Gtqe(3 z%g&`o2LeYr?8h(uoISZVK+p#kfau;++$aXyYf0wn zdsB_f)ACN+2cPPkylnQd0$2J(>cD+9cO=hC-}7d^??g(ozDamubh#X#rwNoxSHq9T zrlZ&%()7PXIZhqSNbp}-(6<3?!0~by^G*ZbHT^{iV;|PccYTVlc~dWHn9T20eZ&q+ z&#iME)Xaq6{bhP${+LY3xApf3s{Wcd93oXUj)Von<~-I1DX@sM_pYtgTvv{RG6N zLOQV;l*Cw*t_->LufjCeoKAMT+qX~o9WF-+zmYZ$*Cz`Cnk6sUmU*FPa$`$ye&3{?P>M=bR4eiD#3MQIi)fo|06vN9y_ zQRUc-HajwF4bkD`LpQ}F^2Xp$d$0fg8}Utx5X(@OmVBfHSxBHok9UdlOLE_LJF$9Q zU8BV;G?J<rp7R%0ALjk+`_6Nh+04R%xVu&a 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 literal 2454 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 XVF?PtovKnk{IriDQ$d6LN$r0D?V@a) literal 0 HcmV?d00001 diff --git a/tgstation.dme b/tgstation.dme index 86fb4497c89..c01bdc15e3a 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -963,6 +963,8 @@ #include "code\modules\mob\living\carbon\human\life.dm" #include "code\modules\mob\living\carbon\human\login.dm" #include "code\modules\mob\living\carbon\human\say.dm" +#include "code\modules\mob\living\carbon\human\species.dm" +#include "code\modules\mob\living\carbon\human\species_types.dm" #include "code\modules\mob\living\carbon\human\update_icons.dm" #include "code\modules\mob\living\carbon\human\whisper.dm" #include "code\modules\mob\living\carbon\metroid\death.dm" From cdaf1662176290897f6c2b95aba1104ab3050496 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 20 Jun 2014 07:44:48 +0100 Subject: [PATCH 49/55] Changelog for mech change. --- html/changelog.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/html/changelog.html b/html/changelog.html index 245a2c28a3c..7fb97f47b88 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -53,6 +53,14 @@ should be listed in the changelog upon commit tho. Thanks. --> +
+

20 June 2014

+

Ikarrus updated:

+
    +
  • The 'Enter Exosuit' button was removed, and you have to click + drag yourself to enter a mech now; like you would to enter a disposal unit.
  • +
+
+

12 June 2014

From 9d1659219efcee44b64b8d16a862c8ec89b13b7f Mon Sep 17 00:00:00 2001 From: CollenN Date: Fri, 20 Jun 2014 06:52:58 -0400 Subject: [PATCH 50/55] Encapsulates if() statement Profakos pointed this out --- code/modules/client/preferences_savefile.dm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 93c33b755be..33768cb04c7 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -73,7 +73,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(11) underwear = "Ladies Kinky" if(12) underwear = "Tankini" if(13) underwear = "Nude" - if(!pref_species in species_list) + if(!(pref_species in species_list)) pref_species = new /datum/species/human() return @@ -192,9 +192,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car //Sanitize metadata = sanitize_text(metadata, initial(metadata)) real_name = reject_bad_name(real_name) - if(!pref_species in species_list) + if(!(pref_species in species_list)) pref_species = new /datum/species/human() - world << "[pref_species] is the species" if(!real_name) real_name = random_name(gender) be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name)) gender = sanitize_gender(gender) From 80a093643c950fd6a76d601e5ee81c8f93267e69 Mon Sep 17 00:00:00 2001 From: Miauw Date: Fri, 20 Jun 2014 14:55:04 +0200 Subject: [PATCH 51/55] Removes confusion because players cannot understand my genius. --- code/game/objects/items/weapons/AI_modules.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm index 6d13cdee986..446395634f4 100644 --- a/code/game/objects/items/weapons/AI_modules.dm +++ b/code/game/objects/items/weapons/AI_modules.dm @@ -279,8 +279,8 @@ AI MODULES /********************* Custom *********************/ /obj/item/weapon/aiModule/core/full/custom - name = "Custom Core AI Module" - desc = "A core AI module that is adjusted to fit each station's needs." + name = "Default Core AI Module" + desc = "A core AI module custom-made for each station by Nanotrasen." origin_tech = "programming=3;materials=4" //Should be the same as asimov, considering that this is the "default" lawset. /obj/item/weapon/aiModule/core/full/custom/New() From 713ce934b467b314b34bd4c315bd6d7029b23e5d Mon Sep 17 00:00:00 2001 From: Hornygranny Date: Fri, 20 Jun 2014 09:22:27 -0700 Subject: [PATCH 52/55] t --- code/modules/mob/living/carbon/human/examine.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index f5cab1c04fb..f7db2f18267 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -253,7 +253,7 @@ msg += "[t_He] [t_has] a vacant, braindead stare...\n" if(digitalcamo) - msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatanly inhuman manner.\n" + msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly inhuman manner.\n" if(istype(usr, /mob/living/carbon/human)) From 0a173f10ddc73a55d30c605dc2537bdfa3d174be Mon Sep 17 00:00:00 2001 From: CollenN Date: Fri, 20 Jun 2014 17:19:00 -0400 Subject: [PATCH 53/55] Aaaaaaaaaaaaaaarghhhhh IN MY DEFENSE, you can't actually be set on fire in the first place if you have HEATRES or NOFIRE in your specflags, so it was easy for me to overlook this one. This is really more of an issue with BYOND than anything else. --- code/modules/mob/living/carbon/human/species.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 64fad2b5de4..97143b147b1 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1276,7 +1276,7 @@ ////////// proc/handle_fire(var/mob/living/carbon/human/H) - if(HEATRES in specflags || NOFIRE in specflags) + if((HEATRES in specflags) || (NOFIRE in specflags)) return if(H.fire_stacks < 0) H.fire_stacks++ //If we've doused ourselves in water to avoid fire, dry off slowly From 56eb50938b9615c192f9e08671f190b47c1aaf1b Mon Sep 17 00:00:00 2001 From: CollenN Date: Fri, 20 Jun 2014 21:35:48 -0400 Subject: [PATCH 54/55] Added some of Cheridan's suggestions *Removed 'Make 2spooky' admin command *You can still gib even if you don't have DNA *species_types now uses absolute pathing (probably not gonna do the same for species.dm, mainly because with such a large file it strikes me as practical to keep the paths relative) --- code/datums/datumvars.dm | 12 -- code/modules/mob/living/carbon/human/death.dm | 2 + .../mob/living/carbon/human/species_types.dm | 192 +++++++++++------- 3 files changed, 120 insertions(+), 86 deletions(-) diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 831de1e8858..7477a1bea43 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -249,7 +249,6 @@ client body += "" body += "" body += "" - body += "" body += "" body += "" if(ishuman(D)) @@ -581,17 +580,6 @@ client if(usr.client) usr.client.cmd_assume_direct_control(M) - else if(href_list["make_skeleton"]) - if(!check_rights(R_FUN)) return - - var/mob/living/carbon/human/H = locate(href_list["make_skeleton"]) - if(!istype(H)) - usr << "This can only be used on instances of type /mob/living/carbon/human" - return - - H.makeSkeleton() - href_list["datumrefresh"] = href_list["make_skeleton"] - else if(href_list["delall"]) if(!check_rights(R_DEBUG|R_SERVER)) return diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 380d0de4cc3..045ca305efa 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -10,6 +10,8 @@ /mob/living/carbon/human/spawn_gibs() if(dna) hgibs(loc, viruses, dna) + else + hgibs(loc, viruses, null) /mob/living/carbon/human/spawn_dust() new /obj/effect/decal/remains/human(loc) diff --git a/code/modules/mob/living/carbon/human/species_types.dm b/code/modules/mob/living/carbon/human/species_types.dm index 1e2d538fad3..7d159238fc5 100644 --- a/code/modules/mob/living/carbon/human/species_types.dm +++ b/code/modules/mob/living/carbon/human/species_types.dm @@ -1,3 +1,7 @@ +/* + HUMANS +*/ + /datum/species/human name = "Human" id = "human" @@ -5,13 +9,17 @@ specflags = list(EYECOLOR,HAIR,FACEHAIR,LIPS) use_skintones = 1 - handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) - if(chem.id == "mutationtoxin") - H << "Your flesh rapidly mutates!" - H.dna.species = new /datum/species/slime() - H.regenerate_icons() - H.reagents.del_reagent(chem.type) - return 1 +/datum/species/human/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + if(chem.id == "mutationtoxin") + H << "Your flesh rapidly mutates!" + H.dna.species = new /datum/species/slime() + H.regenerate_icons() + H.reagents.del_reagent(chem.type) + return 1 + +/* + LIZARDPEOPLE +*/ /datum/species/lizard // Reptilian humanoids with scaled skin and tails. @@ -25,12 +33,16 @@ attack_sound = 'sound/weapons/slash.ogg' miss_sound = 'sound/weapons/slashmiss.ogg' - handle_speech(message) - // jesus christ why - if(copytext(message, 1, 2) != "*") - message = replacetext(message, "s", stutter("ss")) +/datum/species/lizard/handle_speech(message) + // jesus christ why + if(copytext(message, 1, 2) != "*") + message = replacetext(message, "s", stutter("ss")) - return message + return message + +/* + PLANTPEOPLE +*/ /datum/species/plant // Creatures made of leaves and plant matter. @@ -44,56 +56,64 @@ burnmod = 1.25 heatmod = 1.5 - handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) - if(chem.id == "plantbgone") - H.adjustToxLoss(3) - H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM) - return 1 +/datum/species/plant/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + if(chem.id == "plantbgone") + H.adjustToxLoss(3) + H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM) + return 1 - on_hit(proj_type, mob/living/carbon/human/H) - switch(proj_type) - if(/obj/item/projectile/energy/floramut) - if(prob(15)) - H.apply_effect((rand(30,80)),IRRADIATE) - H.Weaken(5) - for (var/mob/V in viewers(H)) - V.show_message("[H] writhes in pain as \his vacuoles boil.", 3, "You hear the crunching of leaves.", 2) - if(prob(80)) - randmutb(H) - domutcheck(H,null) - else - randmutg(H) - domutcheck(H,null) +/datum/species/plant/on_hit(proj_type, mob/living/carbon/human/H) + switch(proj_type) + if(/obj/item/projectile/energy/floramut) + if(prob(15)) + H.apply_effect((rand(30,80)),IRRADIATE) + H.Weaken(5) + for (var/mob/V in viewers(H)) + V.show_message("[H] writhes in pain as \his vacuoles boil.", 3, "You hear the crunching of leaves.", 2) + if(prob(80)) + randmutb(H) + domutcheck(H,null) else - H.adjustFireLoss(rand(5,15)) - H.show_message("The radiation beam singes you!") - if(/obj/item/projectile/energy/florayield) - H.nutrition = min(H.nutrition+30, 500) - return + randmutg(H) + domutcheck(H,null) + else + H.adjustFireLoss(rand(5,15)) + H.show_message("The radiation beam singes you!") + if(/obj/item/projectile/energy/florayield) + H.nutrition = min(H.nutrition+30, 500) + return + +/* + PODPEOPLE +*/ /datum/species/plant/pod // A mutation caused by a human being ressurected in a revival pod. These regain health in light, and begin to wither in darkness. name = "Podperson" id = "pod" - spec_life(mob/living/carbon/human/H) - var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing - if(isturf(H.loc)) //else, there's considered to be no light - var/turf/T = H.loc - var/area/A = T.loc - if(A) - if(A.lighting_use_dynamic) light_amount = min(10,T.lighting_lumcount) - 5 - else light_amount = 5 - H.nutrition += light_amount - if(H.nutrition > 500) - H.nutrition = 500 - if(light_amount > 2) //if there's enough light, heal - H.heal_overall_damage(1,1) - H.adjustToxLoss(-1) - H.adjustOxyLoss(-1) +/datum/species/plant/pod/spec_life(mob/living/carbon/human/H) + var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing + if(isturf(H.loc)) //else, there's considered to be no light + var/turf/T = H.loc + var/area/A = T.loc + if(A) + if(A.lighting_use_dynamic) light_amount = min(10,T.lighting_lumcount) - 5 + else light_amount = 5 + H.nutrition += light_amount + if(H.nutrition > 500) + H.nutrition = 500 + if(light_amount > 2) //if there's enough light, heal + H.heal_overall_damage(1,1) + H.adjustToxLoss(-1) + H.adjustOxyLoss(-1) - if(H.nutrition < 200) - H.take_overall_damage(2,0) + if(H.nutrition < 200) + H.take_overall_damage(2,0) + +/* + SHADOWPEOPLE +*/ /datum/species/shadow // Humans cursed to stay in the darkness, lest their life forces drain. They regain health in shadow and die in light. @@ -103,18 +123,22 @@ sexes = 0 ignored_by = list(/mob/living/simple_animal/hostile/faithless) - spec_life(mob/living/carbon/human/H) - var/light_amount = 0 - if(isturf(H.loc)) - var/turf/T = H.loc - var/area/A = T.loc - if(A) - if(A.lighting_use_dynamic) light_amount = T.lighting_lumcount - else light_amount = 10 - if(light_amount > 2) //if there's enough light, start dying - H.take_overall_damage(1,1) - else if (light_amount < 2) //heal in the dark - H.heal_overall_damage(1,1) +/datum/species/shadow/spec_life(mob/living/carbon/human/H) + var/light_amount = 0 + if(isturf(H.loc)) + var/turf/T = H.loc + var/area/A = T.loc + if(A) + if(A.lighting_use_dynamic) light_amount = T.lighting_lumcount + else light_amount = 10 + if(light_amount > 2) //if there's enough light, start dying + H.take_overall_damage(1,1) + else if (light_amount < 2) //heal in the dark + H.heal_overall_damage(1,1) + +/* + SLIMEPEOPLE +*/ /datum/species/slime // Humans mutated by slime mutagen, produced from green slimes. They are not targetted by slimes. @@ -128,6 +152,10 @@ hair_alpha = 150 ignored_by = list(/mob/living/carbon/slime) +/* + JELLYPEOPLE +*/ + /datum/species/jelly // Entirely alien beings that seem to be made entirely out of gel. They have three eyes and a skeleton visible within them. name = "Xenobiological Jelly Entity" @@ -137,6 +165,10 @@ eyes = "jelleyes" specflags = list(MUTCOLORS,EYECOLOR) +/* + GOLEMS +*/ + /datum/species/golem // Animated beings of stone. They have increased defenses, and do not need to breathe. They're also slow as fuuuck. name = "Golem" @@ -148,27 +180,39 @@ no_equip = list(slot_wear_mask, slot_wear_suit, slot_gloves, slot_shoes, slot_head, slot_w_uniform) nojumpsuit = 1 +/* + ADAMANTINE GOLEMS +*/ + /datum/species/golem/adamantine name = "Adamantine Golem" id = "adamantine" +/* + FLIES +*/ + /datum/species/fly // Humans turned into fly-like abominations in teleporter accidents. name = "Human?" id = "fly" say_mod = "buzzes" - handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) - if(chem.id == "pestkiller") - H.adjustToxLoss(3) - H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM) - return 1 +/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + if(chem.id == "pestkiller") + H.adjustToxLoss(3) + H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM) + return 1 - handle_speech(message) - if(copytext(message, 1, 2) != "*") - message = replacetext(message, "z", stutter("zz")) +/datum/species/fly/handle_speech(message) + if(copytext(message, 1, 2) != "*") + message = replacetext(message, "z", stutter("zz")) - return message + return message + +/* + SKELETONS +*/ /datum/species/skeleton // 2spooky From e0dac711c5cd49b66d0b276ac9f9c89c1931729f Mon Sep 17 00:00:00 2001 From: Cheridan Date: Sat, 21 Jun 2014 00:35:52 -0500 Subject: [PATCH 55/55] Fixes constructs not passing their shades properly --- code/game/gamemodes/wizard/soulstone.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm index 3f40d34b6de..fb7dd81ace1 100644 --- a/code/game/gamemodes/wizard/soulstone.dm +++ b/code/game/gamemodes/wizard/soulstone.dm @@ -151,13 +151,13 @@ var/construct_class = alert(U, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer") switch(construct_class) if("Juggernaut") - makeNewConstruct(/mob/living/simple_animal/construct/armoured, T, U) + makeNewConstruct(/mob/living/simple_animal/construct/armoured, A, U) if("Wraith") - makeNewConstruct(/mob/living/simple_animal/construct/wraith, T, U) + makeNewConstruct(/mob/living/simple_animal/construct/wraith, A, U) if("Artificer") - makeNewConstruct(/mob/living/simple_animal/construct/builder, T, U) + makeNewConstruct(/mob/living/simple_animal/construct/builder, A, U) qdel(T) qdel(C)