diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index 8aab6175..8acc1d8f 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -185,6 +185,12 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
//We will round to this value in damage calculations.
#define DAMAGE_PRECISION 0.1
+//bullet_act() return values
+#define BULLET_ACT_HIT "HIT" //It's a successful hit, whatever that means in the context of the thing it's hitting.
+#define BULLET_ACT_BLOCK "BLOCK" //It's a blocked hit, whatever that means in the context of the thing it's hitting.
+#define BULLET_ACT_FORCE_PIERCE "PIERCE" //It pierces through the object regardless of the bullet being piercing by default.
+#define BULLET_ACT_TURF "TURF" //It hit us but it should hit something on the same turf too. Usually used for turfs.
+
//items total mass, used to calculate their attacks' stamina costs. If not defined, the cost will be (w_class * 1.25)
#define TOTAL_MASS_TINY_ITEM 1.25
#define TOTAL_MASS_SMALL_ITEM 2.5
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 83d603df..5bcee19f 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -1,10 +1,16 @@
// simple is_type and similar inline helpers
+#if DM_VERSION < 513
#define islist(L) (istype(L, /list))
+#endif
#define in_range(source, user) (get_dist(source, user) <= 1 && (get_step(source, 0)?:z) == (get_step(user, 0)?:z))
+#if DM_VERSION < 513
#define ismovableatom(A) (istype(A, /atom/movable))
+#else
+#define ismovableatom(A) ismovable(A)
+#endif
#define isatom(A) (isloc(A))
diff --git a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm
index 8548b2be..cabc67f6 100644
--- a/code/__DEFINES/logging.dm
+++ b/code/__DEFINES/logging.dm
@@ -35,6 +35,7 @@
#define LOG_GAME (1 << 12)
#define LOG_ADMIN_PRIVATE (1 << 13)
#define LOG_ASAY (1 << 14)
+#define LOG_CLONING (1 << 15)
//Individual logging panel pages
#define INDIVIDUAL_ATTACK_LOG (LOG_ATTACK)
diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm
index ec719794..0edb4239 100644
--- a/code/__DEFINES/machines.dm
+++ b/code/__DEFINES/machines.dm
@@ -100,6 +100,10 @@
#define NUKE_ON_TIMING 2
#define NUKE_ON_EXPLODING 3
+//cloning defines. These are flags.
+#define CLONING_SUCCESS (1<<0)
+#define CLONING_DELETE_RECORD (1<<1)
+
//these flags are used to tell the DNA modifier if a plant gene cannot be extracted or modified.
#define PLANT_GENE_REMOVABLE (1<<0)
#define PLANT_GENE_EXTRACTABLE (1<<1)
diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm
index d344f7f0..402c3dc1 100644
--- a/code/__DEFINES/maths.dm
+++ b/code/__DEFINES/maths.dm
@@ -30,7 +30,11 @@
// round() acts like floor(x, 1) by default but can't handle other values
#define FLOOR(x, y) ( round((x) / (y)) * (y) )
+#if DM_VERSION < 513
#define CLAMP(CLVALUE,CLMIN,CLMAX) ( max( (CLMIN), min((CLVALUE), (CLMAX)) ) )
+#else
+#define CLAMP(CLVALUE,CLMIN,CLMAX) clamp(CLVALUE,CLMIN,CLMAX)
+#endif
// Similar to clamp but the bottom rolls around to the top and vice versa. min is inclusive, max is exclusive
#define WRAP(val, min, max) ( min == max ? min : (val) - (round(((val) - (min))/((max) - (min))) * ((max) - (min))) )
@@ -39,7 +43,11 @@
#define MODULUS(x, y) ( (x) - (y) * round((x) / (y)) )
// Tangent
+#if DM_VERSION < 513
#define TAN(x) (sin(x) / cos(x))
+#else
+#define TAN(x) tan(x)
+#endif
// Cotangent
#define COT(x) (1 / TAN(x))
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 98d630b7..bb6fab9f 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -476,7 +476,7 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define PDAIMG(what) {""}
//Filters
-#define AMBIENT_OCCLUSION list("type"="drop_shadow","x"=0,"y"=-2,"size"=4,"border"=4,"color"="#04080FAA")
+#define AMBIENT_OCCLUSION list("type"="drop_shadow","x"=0,"y"=-2,"size"=4,"color"="#04080FAA")
#define EYE_BLUR(size) list("type"="blur", "size"=size)
#define GRAVITY_MOTION_BLUR list("type"="motion_blur","x"=0,"y"=0)
diff --git a/code/__DEFINES/typeids.dm b/code/__DEFINES/typeids.dm
index ae5df258..8bfe6216 100644
--- a/code/__DEFINES/typeids.dm
+++ b/code/__DEFINES/typeids.dm
@@ -2,7 +2,7 @@
#define TYPEID_NULL "0"
#define TYPEID_NORMAL_LIST "f"
//helper macros
-#define GET_TYPEID(ref) ( ( (lentext(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, lentext(ref)-6) ) )
+#define GET_TYPEID(ref) ( ( (length(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, length(ref)-6) ) )
#define IS_NORMAL_LIST(L) (GET_TYPEID("\ref[L]") == TYPEID_NORMAL_LIST)
diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm
index 99cb6c54..812ced8d 100644
--- a/code/__HELPERS/_lists.dm
+++ b/code/__HELPERS/_lists.dm
@@ -514,7 +514,7 @@
used_key_list[input_key] = 1
return input_key
-#if DM_VERSION > 512
+#if DM_VERSION > 513
#error Remie said that lummox was adding a way to get a lists
#error contents via list.values, if that is true remove this
#error otherwise, update the version and bug lummox
diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm
index 30740956..b6b4efa0 100644
--- a/code/__HELPERS/_logging.dm
+++ b/code/__HELPERS/_logging.dm
@@ -58,6 +58,10 @@
if (CONFIG_GET(flag/log_game))
WRITE_LOG(GLOB.world_game_log, "GAME: [text]")
+/proc/log_cloning(text, mob/initiator)
+ if(CONFIG_GET(flag/log_cloning))
+ WRITE_LOG(GLOB.world_cloning_log, "CLONING: [text]")
+
/proc/log_access(text)
if (CONFIG_GET(flag/log_access))
WRITE_LOG(GLOB.world_game_log, "ACCESS: [text]")
diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm
index 351411ce..402f0c76 100644
--- a/code/__HELPERS/text.dm
+++ b/code/__HELPERS/text.dm
@@ -305,9 +305,9 @@
//is in the other string at the same spot (assuming it is not a replace char).
//This is used for fingerprints
var/newtext = text
- if(lentext(text) != lentext(compare))
+ if(length(text) != length(compare))
return 0
- for(var/i = 1, i < lentext(text), i++)
+ for(var/i = 1, i < length(text), i++)
var/a = copytext(text,i,i+1)
var/b = copytext(compare,i,i+1)
//if it isn't both the same letter, or if they are both the replacement character
@@ -327,7 +327,7 @@
if(!text || !character)
return 0
var/count = 0
- for(var/i = 1, i <= lentext(text), i++)
+ for(var/i = 1, i <= length(text), i++)
var/a = copytext(text,i,i+1)
if(a == character)
count++
@@ -608,8 +608,8 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
continue
var/buffer = ""
var/early_culling = TRUE
- for(var/pos = 1, pos <= lentext(string), pos++)
- var/let = copytext(string, pos, (pos + 1) % lentext(string))
+ for(var/pos = 1, pos <= length(string), pos++)
+ var/let = copytext(string, pos, (pos + 1) % length(string))
if(early_culling && !findtext(let,GLOB.is_alphanumeric))
continue
early_culling = FALSE
@@ -617,9 +617,9 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
if(!findtext(buffer,GLOB.is_alphanumeric))
continue
var/punctbuffer = ""
- var/cutoff = lentext(buffer)
- for(var/pos = lentext(buffer), pos >= 0, pos--)
- var/let = copytext(buffer, pos, (pos + 1) % lentext(buffer))
+ var/cutoff = length(buffer)
+ for(var/pos = length(buffer), pos >= 0, pos--)
+ var/let = copytext(buffer, pos, (pos + 1) % length(buffer))
if(findtext(let,GLOB.is_alphanumeric))
break
if(findtext(let,GLOB.is_punctuation))
@@ -629,8 +629,8 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
var/exclaim = FALSE
var/question = FALSE
var/periods = 0
- for(var/pos = lentext(punctbuffer), pos >= 0, pos--)
- var/punct = copytext(punctbuffer, pos, (pos + 1) % lentext(punctbuffer))
+ for(var/pos = length(punctbuffer), pos >= 0, pos--)
+ var/punct = copytext(punctbuffer, pos, (pos + 1) % length(punctbuffer))
if(!exclaim && findtext(punct,"!"))
exclaim = TRUE
if(!question && findtext(punct,"?"))
@@ -652,7 +652,7 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
buffer = copytext(buffer, 1, cutoff) + punctbuffer
if(!findtext(buffer,GLOB.is_alphanumeric))
continue
- if(!buffer || lentext(buffer) > 280 || lentext(buffer) <= cullshort || buffer in accepted)
+ if(!buffer || length(buffer) > 280 || length(buffer) <= cullshort || buffer in accepted)
continue
accepted += buffer
diff --git a/code/__HELPERS/text_vr.dm b/code/__HELPERS/text_vr.dm
index 64e13ef6..9be806fc 100644
--- a/code/__HELPERS/text_vr.dm
+++ b/code/__HELPERS/text_vr.dm
@@ -9,8 +9,8 @@
return t
proc/TextPreview(var/string,var/len=40)
- if(lentext(string) <= len)
- if(!lentext(string))
+ if(length(string) <= len)
+ if(!length(string))
return "\[...\]"
else
return string
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 7e078184..1f8db38f 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -451,10 +451,15 @@ Turf and target are separate in case you want to teleport some distance from a t
var/y = min(world.maxy, max(1, A.y + dy))
return locate(x,y,A.z)
+#if DM_VERSION > 513
+#warn if you're getting this warning it means 513 is stable
+#warn and you should remove this tidbit
+#endif
+#if DM_VERSION < 513
/proc/arctan(x)
var/y=arcsin(x/sqrt(1+x*x))
return y
-
+#endif
/*
Gets all contents of contents and returns them all in a list.
*/
diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm
index deffd25b..bf4ff55f 100644
--- a/code/_globalvars/logging.dm
+++ b/code/_globalvars/logging.dm
@@ -26,6 +26,8 @@ GLOBAL_VAR(query_debug_log)
GLOBAL_PROTECT(query_debug_log)
GLOBAL_VAR(world_job_debug_log)
GLOBAL_PROTECT(world_job_debug_log)
+GLOBAL_VAR(world_cloning_log)
+GLOBAL_PROTECT(world_cloning_log)
GLOBAL_LIST_EMPTY(bombers)
GLOBAL_PROTECT(bombers)
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
index 9a1a083b..ccfa668b 100644
--- a/code/controllers/configuration/entries/general.dm
+++ b/code/controllers/configuration/entries/general.dm
@@ -39,6 +39,8 @@
/datum/config_entry/flag/log_game // log game events
+/datum/config_entry/flag/log_cloning // log cloning actions.
+
/datum/config_entry/flag/log_vote // log voting
/datum/config_entry/flag/log_whisper // log client whisper
diff --git a/code/datums/dna.dm b/code/datums/dna.dm
index 43ec9e54..466a5406 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -371,7 +371,7 @@
updateappearance(icon_update=0)
if(LAZYLEN(mutation_index))
- dna.mutation_index = mutation_index
+ dna.mutation_index = mutation_index.Copy()
domutcheck()
if(mrace || newfeatures || ui)
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index 855ede0e..e4f9d292 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -74,6 +74,23 @@
if(heal_level > 100)
heal_level = 100
+/obj/machinery/clonepod/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
+ user.examinate(src)
+
+/obj/machinery/clonepod/attack_ai(mob/user)
+ return attack_hand(user)
+
+/obj/machinery/clonepod/examine(mob/user)
+ . = ..()
+ . += "The linking device can be scanned with a multitool."
+ if(in_range(user, src) || isobserver(user))
+ . += "The status display reads: Cloning speed at [speed_coeff*50]%.
Predicted amount of cellular damage: [100-heal_level]%."
+ if(efficiency > 5)
+ . += "Pod has been upgraded to support autoprocessing and apply beneficial mutations."
+
//The return of data disks?? Just for transferring between genetics machine/cloning machine.
//TO-DO: Make the genetics machine accept them.
/obj/item/disk/data
@@ -129,41 +146,42 @@
return examine(user)
//Start growing a human clone in the pod!
-/obj/machinery/clonepod/proc/growclone(ckey, clonename, ui, mutation_index, mindref, datum/species/mrace, list/features, factions, list/quirks)
+/obj/machinery/clonepod/proc/growclone(clonename, ui, mutation_index, mindref, last_death, blood_type, datum/species/mrace, list/features, factions, list/quirks, datum/bank_account/insurance, list/traumas, empty)
if(panel_open)
return FALSE
if(mess || attempting)
return FALSE
- clonemind = locate(mindref) in SSticker.minds
- if(!istype(clonemind)) //not a mind
- return FALSE
- if(!QDELETED(clonemind.current))
- if(clonemind.current.stat != DEAD) //mind is associated with a non-dead body
+ if(!empty) //Doesn't matter if we're just making a copy
+ clonemind = locate(mindref) in SSticker.minds
+ if(!istype(clonemind)) //not a mind
return FALSE
- if(clonemind.current.suiciding) // Mind is associated with a body that is suiciding.
+// if(clonemind.last_death != last_death) //The soul has advanced, the record has not.
+// return FALSE
+ if(!QDELETED(clonemind.current))
+ if(clonemind.current.stat != DEAD) //mind is associated with a non-dead body
+ return NONE
+ if(clonemind.current.suiciding) // Mind is associated with a body that is suiciding.
+ return NONE
+ if(!clonemind.active)
+ // get_ghost() will fail if they're unable to reenter their body
+ var/mob/dead/observer/G = clonemind.get_ghost()
+ if(!G)
+ return NONE
+ if(G.suiciding) // The ghost came from a body that is suiciding.
+ return NONE
+ if(clonemind.damnation_type) //Can't clone the damned.
+ INVOKE_ASYNC(src, .proc/horrifyingsound)
+ mess = TRUE
+ icon_state = "pod_g"
+ update_icon()
return FALSE
- if(clonemind.active) //somebody is using that mind
- if( ckey(clonemind.key)!=ckey )
- return FALSE
- else
- // get_ghost() will fail if they're unable to reenter their body
- var/mob/dead/observer/G = clonemind.get_ghost()
- if(!G)
- return FALSE
- if(G.suiciding) // The ghost came from a body that is suiciding.
- return FALSE
- if(clonemind.damnation_type) //Can't clone the damned.
- INVOKE_ASYNC(src, .proc/horrifyingsound)
- mess = TRUE
- update_icon()
- return FALSE
attempting = TRUE //One at a time!!
countdown.start()
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src)
- H.hardset_dna(ui, mutation_index, H.real_name, null, mrace, features)
+ H.hardset_dna(ui, mutation_index, H.real_name, blood_type, mrace, features)
if(prob(50 - efficiency*10)) //Chance to give a bad mutation.
H.easy_randmut(NEGATIVE+MINOR_NEGATIVE) //100% bad mutation. Can be cured with mutadone.
@@ -184,15 +202,16 @@
ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, "cloning")
H.Unconscious(80)
- clonemind.transfer_to(H)
+ if(!empty)
+ clonemind.transfer_to(H)
- if(grab_ghost_when == CLONER_FRESH_CLONE)
- H.grab_ghost()
- to_chat(H, "Consciousness slowly creeps over you as your body regenerates.
So this is what cloning feels like?")
+ if(grab_ghost_when == CLONER_FRESH_CLONE)
+ H.grab_ghost()
+ to_chat(H, "Consciousness slowly creeps over you as your body regenerates.
So this is what cloning feels like?")
- if(grab_ghost_when == CLONER_MATURE_CLONE)
- H.ghostize(TRUE) //Only does anything if they were still in their old body and not already a ghost
- to_chat(H.get_ghost(TRUE), "Your body is beginning to regenerate in a cloning pod. You will become conscious when it is complete.")
+ if(grab_ghost_when == CLONER_MATURE_CLONE)
+ H.ghostize(TRUE) //Only does anything if they were still in their old body and not already a ghost
+ to_chat(H.get_ghost(TRUE), "Your body is beginning to regenerate in a cloning pod. You will become conscious when it is complete.")
if(H)
H.faction |= factions
@@ -381,6 +400,7 @@
unattached_flesh.Cut()
occupant = null
+ clonemind = null
/obj/machinery/clonepod/proc/malfunction()
var/mob/living/mob_occupant = occupant
@@ -391,7 +411,7 @@
mess = TRUE
maim_clone(mob_occupant) //Remove every bit that's grown back so far to drop later, also destroys bits that haven't grown yet
update_icon()
- if(mob_occupant.mind != clonemind)
+ if(clonemind && mob_occupant.mind != clonemind)
clonemind.transfer_to(mob_occupant)
mob_occupant.grab_ghost() // We really just want to make you suffer.
flash_color(mob_occupant, flash_color="#960000", flash_time=100)
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index 039152f5..ca5e15d1 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -39,7 +39,7 @@
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
- if(pod.occupant && pod.clonemind == mind)
+ if(pod.occupant && mind && pod.clonemind == mind)
return null
if(pod.is_operational() && !(pod.occupant || pod.mess))
return pod
@@ -60,6 +60,9 @@
else if(!. && pod.is_operational() && !(pod.occupant || pod.mess) && pod.efficiency > 5)
. = pod
+/proc/grow_clone_from_record(obj/machinery/clonepod/pod, datum/data/record/R, empty)
+ return pod.growclone(R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mindref"], R.fields["last_death"], R.fields["blood_type"], R.fields["mrace"], R.fields["features"], R.fields["factions"], R.fields["quirks"], R.fields["bank_account"], R.fields["traumas"], empty)
+
/obj/machinery/computer/cloning/process()
if(!(scanner && LAZYLEN(pods) && autoprocess))
return
@@ -76,8 +79,11 @@
if(pod.occupant)
continue //how though?
- if(pod.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"], R.fields["features"], R.fields["factions"], R.fields["quirks"]))
+ var/result = grow_clone_from_record(pod, R)
+ if(result & CLONING_SUCCESS)
temp = "[R.fields["name"]] => Cloning cycle in progress..."
+ log_cloning("Cloning of [key_name(R.fields["mindref"])] automatically started via autoprocess - [src] at [AREACOORD(src)]. Pod: [pod] at [AREACOORD(pod)].")
+ if(result & CLONING_DELETE_RECORD)
records -= R
/obj/machinery/computer/cloning/proc/updatemodules(findfirstcloner)
@@ -201,6 +207,7 @@
if(scanner_occupant)
dat += "Start Scan"
+ dat += "Body-Only Scan"
dat += "
[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]"
else
dat += "Start Scan"
@@ -228,8 +235,11 @@
if (!src.active_record)
dat += "Record not found."
else
- dat += "
"
dat += "Flavor Text" dat += "Set Examine Text" - if(lentext(features["flavor_text"]) <= 40) - if(!lentext(features["flavor_text"])) + if(length(features["flavor_text"]) <= 40) + if(!length(features["flavor_text"])) dat += "\[...\]" else dat += "[features["flavor_text"]]" diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm index 2811168f..1b923389 100644 --- a/code/modules/crafting/recipes.dm +++ b/code/modules/crafting/recipes.dm @@ -636,11 +636,24 @@ /datum/crafting_recipe/wheelchair name = "Wheelchair" result = /obj/vehicle/ridden/wheelchair - reqs = list(/obj/item/stack/sheet/plasteel = 2, + reqs = list(/obj/item/stack/sheet/metal = 10, /obj/item/stack/rods = 8) time = 100 category = CAT_MISC +/datum/crafting_recipe/motorized_wheelchair + name = "Motorized Wheelchair" + result = /obj/vehicle/ridden/wheelchair/motorized + reqs = list(/obj/item/stack/sheet/metal = 10, + /obj/item/stack/rods = 8, + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/capacitor = 1) + parts = list(/obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/capacitor = 1) + tools = list(TOOL_WELDER, TOOL_SCREWDRIVER, TOOL_WRENCH) + time = 200 + category = CAT_MISC + /datum/crafting_recipe/rcl name = "Makeshift Rapid Cable Layer" result = /obj/item/twohanded/rcl/ghetto diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index fefa032e..0e2e50c2 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -231,7 +231,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) var/r_val var/b_val var/g_val - var/color_format = lentext(input_color) + var/color_format = length(input_color) if(color_format == 3) r_val = hex2num(copytext(input_color, 1, 2))*16 g_val = hex2num(copytext(input_color, 2, 3))*16 diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 7232944b..f6793aa2 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -781,7 +781,7 @@ broken_plural = TRUE else var/holder = broken[1] //our one and only element - if(holder[lentext(holder)] == "s") + if(holder[length(holder)] == "s") broken_plural = TRUE //Put the items in that list into a string of text for(var/B in broken) @@ -793,7 +793,7 @@ damaged_plural = TRUE else var/holder = damaged[1] - if(holder[lentext(holder)] == "s") + if(holder[length(holder)] == "s") damaged_plural = TRUE for(var/D in damaged) damaged_message += D diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 83eca8b8..3a3dacee 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -67,8 +67,8 @@ /proc/slur(n,var/strength=50) strength = min(strength,50) var/phrase = html_decode(n) - var/leng = lentext(phrase) - var/counter=lentext(phrase) + var/leng = length(phrase) + var/counter=length(phrase) var/newphrase="" var/newletter="" while(counter>=1) @@ -102,8 +102,8 @@ /proc/cultslur(n) // Inflicted on victims of a stun talisman var/phrase = html_decode(n) - var/leng = lentext(phrase) - var/counter=lentext(phrase) + var/leng = length(phrase) + var/counter=length(phrase) var/newphrase="" var/newletter="" while(counter>=1) diff --git a/code/modules/mob/say_vr.dm b/code/modules/mob/say_vr.dm index 1fc97c31..4bbeef70 100644 --- a/code/modules/mob/say_vr.dm +++ b/code/modules/mob/say_vr.dm @@ -25,7 +25,7 @@ if(flavor_text && flavor_text != "") // We are decoding and then encoding to not only get correct amount of characters, but also to prevent partial escaping characters being shown. var/msg = html_decode(replacetext(flavor_text, "\n", " ")) - if(lentext(msg) <= 40) + if(length(msg) <= 40) return "[html_encode(msg)]" else return "[html_encode(copytext(msg, 1, 37))]... More..." diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 841a8897..4659d322 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -476,6 +476,15 @@ category = list("Phazon") //Exosuit Equipment +/datum/design/ripleyupgrade + name = "Ripley MK-1 to MK-II conversion kit" + id = "ripleyupgrade" + build_type = MECHFAB + build_path = /obj/item/mecha_parts/mecha_equipment/ripleyupgrade + materials = list(MAT_METAL=10000,MAT_PLASMA=10000) + construction_time = 100 + category = list("Exosuit Equipment") + /datum/design/mech_hydraulic_clamp name = "Exosuit Engineering Equipment (Hydraulic Clamp)" id = "mech_hydraulic_clamp" diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 2f51b33e..cd4ca3e3 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -34,7 +34,7 @@ display_name = "Mechanical Exosuits" description = "Mechanized exosuits that are several magnitudes stronger and more powerful than the average human." design_ids = list("mecha_tracking", "mechacontrol", "mechapower", "mech_recharger", "ripley_chassis", "firefighter_chassis", "ripley_torso", "ripley_left_arm", "ripley_right_arm", "ripley_left_leg", "ripley_right_leg", - "ripley_main", "ripley_peri", "mech_hydraulic_clamp") + "ripley_main", "ripley_peri", "ripleyupgrade", "mech_hydraulic_clamp") /datum/techweb_node/mech_tools id = "mech_tools" diff --git a/code/modules/vehicles/motorized_wheelchair.dm b/code/modules/vehicles/motorized_wheelchair.dm new file mode 100644 index 00000000..873ae7ac --- /dev/null +++ b/code/modules/vehicles/motorized_wheelchair.dm @@ -0,0 +1,168 @@ +/obj/vehicle/ridden/wheelchair/motorized + name = "motorized wheelchair" + desc = "A chair with big wheels. It seems to have a motor in it." + max_integrity = 150 + var/speed = 2 + var/power_efficiency = 1 + var/power_usage = 100 + var/panel_open = FALSE + var/list/required_parts = list(/obj/item/stock_parts/manipulator, + /obj/item/stock_parts/manipulator, + /obj/item/stock_parts/capacitor) + var/obj/item/stock_parts/cell/power_cell + +/obj/vehicle/ridden/wheelchair/motorized/CheckParts(list/parts_list) + ..() + refresh_parts() + +/obj/vehicle/ridden/wheelchair/motorized/proc/refresh_parts() + speed = 1 // Should never be under 1 + for(var/obj/item/stock_parts/manipulator/M in contents) + speed += M.rating + for(var/obj/item/stock_parts/capacitor/C in contents) + power_efficiency = C.rating + var/datum/component/riding/D = GetComponent(/datum/component/riding) + D.vehicle_move_delay = round(CONFIG_GET(number/movedelay/run_delay) * delay_multiplier) / speed + +/obj/vehicle/ridden/wheelchair/motorized/obj_destruction(damage_flag) + var/turf/T = get_turf(src) + for(var/atom/movable/A in contents) + A.forceMove(T) + //if(isliving(A)) + // var/mob/living/L = A + // L.update_mobility() + ..() + +/obj/vehicle/ridden/wheelchair/motorized/driver_move(mob/living/user, direction) + if(istype(user)) + if(!canmove) + return FALSE + if(!power_cell) + to_chat(user, "There seems to be no cell installed in [src].") + canmove = FALSE + addtimer(VARSET_CALLBACK(src, canmove, TRUE), 20) + return FALSE + if(power_cell.charge < power_usage / max(power_efficiency, 1)) + to_chat(user, "The display on [src] blinks 'Out of Power'.") + canmove = FALSE + addtimer(VARSET_CALLBACK(src, canmove, TRUE), 20) + return FALSE + if(user.get_num_arms() < arms_required) + to_chat(user, "You don't have enough arms to operate the motor controller!") + canmove = FALSE + addtimer(VARSET_CALLBACK(src, canmove, TRUE), 20) + return FALSE + power_cell.use(power_usage / max(power_efficiency, 1)) + return ..() + +/obj/vehicle/ridden/wheelchair/motorized/set_move_delay(mob/living/user) + return + +/obj/vehicle/ridden/wheelchair/motorized/post_buckle_mob(mob/living/user) + . = ..() + density = TRUE + +/obj/vehicle/ridden/wheelchair/motorized/post_unbuckle_mob() + . = ..() + density = FALSE + +/obj/vehicle/ridden/wheelchair/motorized/attack_hand(mob/living/user) + if(power_cell && panel_open) + power_cell.update_icon() + user.put_in_hands(power_cell) + power_cell = null + to_chat(user, "You remove the power cell from [src].") + return + return ..() + +/obj/vehicle/ridden/wheelchair/motorized/attackby(obj/item/I, mob/user, params) + if(I.tool_behaviour == TOOL_SCREWDRIVER) + I.play_tool_sound(src) + panel_open = !panel_open + user.visible_message("[user] [panel_open ? "opens" : "closes"] the maintenance panel on [src].", "You [panel_open ? "open" : "close"] the maintenance panel.") + return + if(panel_open) + if(istype(I, /obj/item/stock_parts/cell)) + if(power_cell) + to_chat(user, "There is a power cell already installed.") + else + I.forceMove(src) + power_cell = I + to_chat(user, "You install the [I].") + refresh_parts() + return + if(istype(I, /obj/item/stock_parts)) + var/obj/item/stock_parts/B = I + var/P + for(var/obj/item/stock_parts/A in contents) + for(var/D in required_parts) + if(ispath(A.type, D)) + P = D + break + if(istype(B, P) && istype(A, P)) + if(B.get_part_rating() > A.get_part_rating()) + B.forceMove(src) + user.put_in_hands(A) + user.visible_message("[user] replaces [A] with [B] in [src].", "You replace [A] with [B].") + break + refresh_parts() + return + return ..() + +/obj/vehicle/ridden/wheelchair/motorized/wrench_act(mob/living/user, obj/item/I) + to_chat(user, "You begin to detach the wheels...") + if(I.use_tool(src, user, 40, volume=50)) + to_chat(user, "You detach the wheels and deconstruct the chair.") + new /obj/item/stack/rods(drop_location(), 8) + new /obj/item/stack/sheet/metal(drop_location(), 10) + var/turf/T = get_turf(src) + for(var/atom/movable/A in contents) + A.forceMove(T) + //if(isliving(A)) + // var/mob/living/L = A + // L.update_mobility() + qdel(src) + return TRUE + +/obj/vehicle/ridden/wheelchair/motorized/examine(mob/user) + . = ..() + if((obj_flags & EMAGGED) && panel_open) + . += "There is a bomb under the maintenance panel." + . += "There is a small screen on it, [(in_range(user, src) || isobserver(user)) ? "[power_cell ? "it reads:" : "but it is dark."]" : "but you can't see it from here."]" + if(!power_cell || (!in_range(user, src) && !isobserver(user))) + return + . += "Speed: [speed]" + . += "Energy efficiency: [power_efficiency]" + . += "Power: [power_cell.charge] out of [power_cell.maxcharge]" + +/obj/vehicle/ridden/wheelchair/motorized/Bump(atom/movable/M) + . = ..() + // Here is the shitty emag functionality. + if(obj_flags & EMAGGED && (istype(M, /turf/closed) || isliving(M))) + explosion(src, -1, 1, 3, 2, 0) + visible_message("[src] explodes!!") + return + // If the speed is higher than delay_multiplier throw the person on the wheelchair away + if(M.density && speed > delay_multiplier && has_buckled_mobs()) + var/mob/living/H = buckled_mobs[1] + var/atom/throw_target = get_edge_target_turf(H, pick(GLOB.cardinals)) + unbuckle_mob(H) + H.throw_at(throw_target, 2, 3) + H.Knockdown(100) + H.adjustStaminaLoss(40) + if(isliving(M)) + var/mob/living/D = M + throw_target = get_edge_target_turf(D, pick(GLOB.cardinals)) + D.throw_at(throw_target, 2, 3) + D.Knockdown(80) + D.adjustStaminaLoss(35) + visible_message("[src] crashes into [M], sending [H] and [D] flying!") + else + visible_message("[src] crashes into [M], sending [H] flying!") + playsound(src, 'sound/effects/bang.ogg', 50, 1) + +/obj/vehicle/ridden/wheelchair/motorized/emag_act(mob/user) + if((obj_flags & EMAGGED) || !panel_open) + return + to_chat(user, "A bomb appears in [src], what the fuck?") + obj_flags |= EMAGGED diff --git a/code/modules/vehicles/wheelchair.dm b/code/modules/vehicles/wheelchair.dm index 137242c5..2eb1a2ad 100644 --- a/code/modules/vehicles/wheelchair.dm +++ b/code/modules/vehicles/wheelchair.dm @@ -1,4 +1,4 @@ -/obj/vehicle/ridden/wheelchair //ported from Hippiestation (by Jujumatic) Then ported by Fermis from tg! +/obj/vehicle/ridden/wheelchair //ported from Hippiestation (by Jujumatic) name = "wheelchair" desc = "A chair with big wheels. It looks like you can move in this on your own." icon = 'icons/obj/vehicles.dmi' @@ -9,7 +9,8 @@ legs_required = 0 //You'll probably be using this if you don't have legs canmove = TRUE density = FALSE //Thought I couldn't fix this one easily, phew - arms_required = 1 + // Run speed delay is multiplied with this for vehicle move delay. + var/delay_multiplier = 6.7 /obj/vehicle/ridden/wheelchair/Initialize() . = ..() @@ -42,16 +43,19 @@ canmove = FALSE addtimer(VARSET_CALLBACK(src, canmove, TRUE), 20) return FALSE - var/datum/component/riding/D = GetComponent(/datum/component/riding) - //1.5 (movespeed as of this change) multiplied by 6.7 gets ABOUT 10 (rounded), the old constant for the wheelchair that gets divided by how many arms they have - //if that made no sense this simply makes the wheelchair speed change along with movement speed delay - D.vehicle_move_delay = round((CONFIG_GET(number/movedelay/run_delay) * 4) / min(user.get_num_arms(), 2), world.tick_lag) + set_move_delay(user) return ..() +/obj/vehicle/ridden/wheelchair/proc/set_move_delay(mob/living/user) + var/datum/component/riding/D = GetComponent(/datum/component/riding) + //1.5 (movespeed as of this change) multiplied by 6.7 gets ABOUT 10 (rounded), the old constant for the wheelchair that gets divided by how many arms they have + //if that made no sense this simply makes the wheelchair speed change along with movement speed delay + D.vehicle_move_delay = round(CONFIG_GET(number/movedelay/run_delay) * delay_multiplier) / min(user.get_num_arms(), 2) + /obj/vehicle/ridden/wheelchair/Moved() . = ..() cut_overlays() - playsound(src, 'sound/effects/roll.ogg', 75, 1) + playsound(src, 'sound/effects/roll.ogg', 75, TRUE) if(has_buckled_mobs()) handle_rotation_overlayed() @@ -69,6 +73,7 @@ handle_rotation(newdir) /obj/vehicle/ridden/wheelchair/wrench_act(mob/living/user, obj/item/I) //Attackby should stop it attacking the wheelchair after moving away during decon + ..() to_chat(user, "You begin to detach the wheels...") if(I.use_tool(src, user, 40, volume=50)) to_chat(user, "You detach the wheels and deconstruct the chair.") diff --git a/config/config.txt b/config/config.txt index 5dda144c..819bc01a 100644 --- a/config/config.txt +++ b/config/config.txt @@ -146,6 +146,9 @@ LOG_MANIFEST ## Enable logging pictures # LOG_PICTURES +## log cloning actions +LOG_CLONING + ##Log camera pictures - Must have picture logging enabled PICTURE_LOGGING_CAMERA diff --git a/icons/mecha/mech_construction.dmi b/icons/mecha/mech_construction.dmi index cdb07215..d7f0f3e0 100644 Binary files a/icons/mecha/mech_construction.dmi and b/icons/mecha/mech_construction.dmi differ diff --git a/icons/mecha/mecha.dmi b/icons/mecha/mecha.dmi index 4b09f791..291abf96 100644 Binary files a/icons/mecha/mecha.dmi and b/icons/mecha/mecha.dmi differ diff --git a/icons/mecha/mecha_equipment.dmi b/icons/mecha/mecha_equipment.dmi index 02c79848..af1324c0 100644 Binary files a/icons/mecha/mecha_equipment.dmi and b/icons/mecha/mecha_equipment.dmi differ diff --git a/icons/mob/human_parts_greyscale.dmi b/icons/mob/human_parts_greyscale.dmi index fb800d7d..3df9fe5f 100644 Binary files a/icons/mob/human_parts_greyscale.dmi and b/icons/mob/human_parts_greyscale.dmi differ diff --git a/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm b/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm index f4af8a40..58bf4fb2 100644 --- a/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm +++ b/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm @@ -43,6 +43,9 @@ icon_state = "hemiknot" name = "Knotted Hemi" +/datum/sprite_accessory/penis/thick + icon_state = "thick" + name = "thick" //////////////////////// // Taur cocks go here // diff --git a/modular_citadel/icons/obj/genitals/penis.dmi b/modular_citadel/icons/obj/genitals/penis.dmi index 517758b2..5118b094 100644 Binary files a/modular_citadel/icons/obj/genitals/penis.dmi and b/modular_citadel/icons/obj/genitals/penis.dmi differ diff --git a/modular_citadel/icons/obj/genitals/penis_onmob.dmi b/modular_citadel/icons/obj/genitals/penis_onmob.dmi index 361001a4..6ad0628d 100644 Binary files a/modular_citadel/icons/obj/genitals/penis_onmob.dmi and b/modular_citadel/icons/obj/genitals/penis_onmob.dmi differ diff --git a/tgstation.dme b/tgstation.dme index bb323e64..e196b844 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2812,6 +2812,7 @@ #include "code\modules\vehicles\atv.dm" #include "code\modules\vehicles\bicycle.dm" #include "code\modules\vehicles\lavaboat.dm" +#include "code\modules\vehicles\motorized_wheelchair.dm" #include "code\modules\vehicles\pimpin_ride.dm" #include "code\modules\vehicles\ridden.dm" #include "code\modules\vehicles\scooter.dm" |