From fd59386d788e6fd573269bed78310198da9aeec0 Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Fri, 2 Feb 2024 20:35:59 +0800 Subject: [PATCH 01/28] Spacepods? --- code/__DEFINES/is_helpers.dm | 2 + code/__DEFINES/layers.dm | 1 + code/__DEFINES/spacepods.dm | 18 + code/__HELPERS/lists.dm | 2 + code/_onclick/drag_drop.dm | 13 + code/_onclick/hud/map_popups.dm | 7 + .../subsystem/processing/spacepods.dm | 12 + code/datums/components/rotation.dm | 166 +++++ code/game/objects/items/stacks/rods.dm | 7 + .../mob/living/carbon/human/human_mob.dm | 9 + code/modules/mob/living/living.dm | 4 + code/modules/mob/mob_vars.dm | 6 + .../modules/research/designs/mecha_designs.dm | 11 + .../research/designs/spacepod_designs.dm | 241 ++++++ code/modules/research/protolathe.dm | 3 +- code/modules/spacepods/icons/2x2.dmi | Bin 0 -> 1085 bytes .../spacepods/icons/actions_spacepod.dmi | Bin 0 -> 1828 bytes code/modules/spacepods/icons/parts.dmi | Bin 0 -> 4712 bytes code/modules/spacepods/spacepod.dm | 691 ++++++++++++++++++ code/modules/spacepods/spacepod_actions.dm | 122 ++++ .../spacepods/spacepod_construction.dm | 206 ++++++ code/modules/spacepods/spacepod_equipment.dm | 379 ++++++++++ code/modules/spacepods/spacepod_parts.dm | 181 +++++ code/modules/spacepods/spacepod_physics.dm | 297 ++++++++ code/modules/spacepods/spacepod_prebuilt.dm | 64 ++ goon/icons/obj/spacepods/2x2.dmi | Bin 0 -> 7679 bytes goon/icons/obj/spacepods/construction_2x2.dmi | Bin 0 -> 5631 bytes goon/icons/obj/spacepods/parts.dmi | Bin 0 -> 5007 bytes paradise.dme | 11 + 29 files changed, 2452 insertions(+), 1 deletion(-) create mode 100644 code/__DEFINES/spacepods.dm create mode 100644 code/controllers/subsystem/processing/spacepods.dm create mode 100644 code/datums/components/rotation.dm create mode 100644 code/modules/research/designs/spacepod_designs.dm create mode 100644 code/modules/spacepods/icons/2x2.dmi create mode 100644 code/modules/spacepods/icons/actions_spacepod.dmi create mode 100644 code/modules/spacepods/icons/parts.dmi create mode 100644 code/modules/spacepods/spacepod.dm create mode 100644 code/modules/spacepods/spacepod_actions.dm create mode 100644 code/modules/spacepods/spacepod_construction.dm create mode 100644 code/modules/spacepods/spacepod_equipment.dm create mode 100644 code/modules/spacepods/spacepod_parts.dm create mode 100644 code/modules/spacepods/spacepod_physics.dm create mode 100644 code/modules/spacepods/spacepod_prebuilt.dm create mode 100644 goon/icons/obj/spacepods/2x2.dmi create mode 100644 goon/icons/obj/spacepods/construction_2x2.dmi create mode 100644 goon/icons/obj/spacepods/parts.dmi diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index e73af05c7d61..fa918c4d41f9 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -52,6 +52,8 @@ #define ismecha(A) (istype(A, /obj/mecha)) +#define isspacepod(A) (istype(A, /obj/spacepod)) + #define iseffect(A) (istype(A, /obj/effect)) #define isclothing(A) (istype(A, /obj/item/clothing)) diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index 9e475ab6e9e0..55754bbba5f9 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -73,6 +73,7 @@ #define BELOW_MOB_LAYER 3.7 #define LYING_MOB_LAYER 3.8 +#define SPACEPOD_LAYER 3.9 // yogs //#define MOB_LAYER 4 //For easy recordkeeping; this is a byond define #define ABOVE_MOB_LAYER 4.1 #define HITSCAN_LAYER 4.2 diff --git a/code/__DEFINES/spacepods.dm b/code/__DEFINES/spacepods.dm new file mode 100644 index 000000000000..a4bfbd5abf88 --- /dev/null +++ b/code/__DEFINES/spacepods.dm @@ -0,0 +1,18 @@ +#define SPACEPOD_EMPTY 1 +#define SPACEPOD_WIRES_LOOSE 2 +#define SPACEPOD_WIRES_SECURED 3 +#define SPACEPOD_CIRCUIT_LOOSE 4 +#define SPACEPOD_CIRCUIT_SECURED 5 +#define SPACEPOD_CORE_LOOSE 6 +#define SPACEPOD_CORE_SECURED 7 +#define SPACEPOD_BULKHEAD_LOOSE 8 +#define SPACEPOD_BULKHEAD_SECURED 9 +#define SPACEPOD_BULKHEAD_WELDED 10 +#define SPACEPOD_ARMOR_LOOSE 11 +#define SPACEPOD_ARMOR_SECURED 12 +#define SPACEPOD_ARMOR_WELDED 13 + +#define SPACEPOD_SLOT_CARGO "cargo" +#define SPACEPOD_SLOT_MISC "misc" +#define SPACEPOD_SLOT_WEAPON "weapon" +#define SPACEPOD_SLOT_LOCK "lock" diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index cf6642875ffa..d04d7ebc28e3 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -696,6 +696,8 @@ ///If the lazy list is currently initialized find item I in list L #define LAZYIN(L, I) (L && (I in L)) +#define LAZYOR(L, I) if(!L) { L = list(); } L |= I; + //same, but returns nothing and acts on list in place /proc/shuffle_inplace(list/L) if(!L) diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm index 5d7d41143320..90af86729836 100644 --- a/code/_onclick/drag_drop.dm +++ b/code/_onclick/drag_drop.dm @@ -48,3 +48,16 @@ to inform the game this action was expected and its fine */ /atom/proc/MouseDrop_T(atom/dropping, mob/user, params) // return TRUE if you want to prevent us click the object after it return + +/client/MouseMove(object,location,control,params) + mouseParams = params + mouse_location_ref = location + mouse_object_ref = object + mouseControlObject = control + if(mob && LAZYLEN(mob.mousemove_intercept_objects)) + for(var/datum/D in mob.mousemove_intercept_objects) + D.onMouseMove(object, location, control, params) + ..() + +/datum/proc/onMouseMove(object, location, control, params) + return diff --git a/code/_onclick/hud/map_popups.dm b/code/_onclick/hud/map_popups.dm index dc9e255cba93..9c2bc9b148ce 100644 --- a/code/_onclick/hud/map_popups.dm +++ b/code/_onclick/hud/map_popups.dm @@ -7,6 +7,13 @@ */ var/list/screen_maps = list() + var/mouseParams = "" + ///Used in MouseDrag to preserve the last mouse-entered location + var/datum/mouse_location_ref = null + ///Used in MouseDrag to preserve the last mouse-entered object + var/datum/mouse_object_ref + var/mouseControlObject = null + /obj/screen /** * Map name assigned to this object. diff --git a/code/controllers/subsystem/processing/spacepods.dm b/code/controllers/subsystem/processing/spacepods.dm new file mode 100644 index 000000000000..036beea2fa4d --- /dev/null +++ b/code/controllers/subsystem/processing/spacepods.dm @@ -0,0 +1,12 @@ +// Yogstation use fastprocess subsystem but for Paradise it causes +// movement lag (updates, like it should, 5 times / second). +// This wait time (0.075) is the closest (and laziest) I could get to +// Yogstation's movement speed + +// RMNZ: Maybe performance issues? + +PROCESSING_SUBSYSTEM_DEF(spacepods) + name = "Spacepods" + wait = 0.075 + stat_tag = "SP" + offline_implications = "Spacepods will no longer process. Shuttle call recommended." diff --git a/code/datums/components/rotation.dm b/code/datums/components/rotation.dm new file mode 100644 index 000000000000..fc023da258cb --- /dev/null +++ b/code/datums/components/rotation.dm @@ -0,0 +1,166 @@ +//RMNZ: Please, check if this component is really needed or not +#define ROTATION_ALTCLICK (1<<0) +#define ROTATION_WRENCH (1<<1) +#define ROTATION_VERBS (1<<2) +#define ROTATION_COUNTERCLOCKWISE (1<<3) +#define ROTATION_CLOCKWISE (1<<4) +#define ROTATION_FLIP (1<<5) + +/datum/component/simple_rotation + var/datum/callback/can_user_rotate //Checks if user can rotate + var/datum/callback/can_be_rotated //Check if object can be rotated at all + var/datum/callback/after_rotation //Additional stuff to do after rotation + + var/rotation_flags = NONE + var/default_rotation_direction = ROTATION_CLOCKWISE + +/datum/component/simple_rotation/Initialize(rotation_flags = NONE, can_user_rotate, can_be_rotated, after_rotation) + if(!ismovable(parent)) + return COMPONENT_INCOMPATIBLE + + //throw if no rotation direction is specificed ? + + src.rotation_flags = rotation_flags + + if(can_user_rotate) + src.can_user_rotate = can_user_rotate + else + src.can_user_rotate = CALLBACK(src, PROC_REF(default_can_user_rotate)) + + if(can_be_rotated) + src.can_be_rotated = can_be_rotated + else + src.can_be_rotated = CALLBACK(src, PROC_REF(default_can_be_rotated)) + + if(after_rotation) + src.after_rotation = after_rotation + else + src.after_rotation = CALLBACK(src, PROC_REF(default_after_rotation)) + + //Try Clockwise,counter,flip in order + if(src.rotation_flags & ROTATION_FLIP) + default_rotation_direction = ROTATION_FLIP + if(src.rotation_flags & ROTATION_COUNTERCLOCKWISE) + default_rotation_direction = ROTATION_COUNTERCLOCKWISE + if(src.rotation_flags & ROTATION_CLOCKWISE) + default_rotation_direction = ROTATION_CLOCKWISE + +/datum/component/simple_rotation/proc/add_signals() + if(rotation_flags & ROTATION_ALTCLICK) + RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(HandRot)) + RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(ExamineMessage)) + if(rotation_flags & ROTATION_WRENCH) + RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, PROC_REF(WrenchRot)) + +/datum/component/simple_rotation/proc/add_verbs() + if(rotation_flags & ROTATION_VERBS) + var/atom/movable/AM = parent + if(rotation_flags & ROTATION_FLIP) + AM.verbs += /atom/movable/proc/simple_rotate_flip + if(src.rotation_flags & ROTATION_CLOCKWISE) + AM.verbs += /atom/movable/proc/simple_rotate_clockwise + if(src.rotation_flags & ROTATION_COUNTERCLOCKWISE) + AM.verbs += /atom/movable/proc/simple_rotate_counterclockwise + +/datum/component/simple_rotation/proc/remove_verbs() + if(parent) + var/atom/movable/AM = parent + AM.verbs -= /atom/movable/proc/simple_rotate_flip + AM.verbs -= /atom/movable/proc/simple_rotate_clockwise + AM.verbs -= /atom/movable/proc/simple_rotate_counterclockwise + +/datum/component/simple_rotation/proc/remove_signals() + UnregisterSignal(parent, list(COMSIG_CLICK_ALT, COMSIG_PARENT_EXAMINE, COMSIG_PARENT_ATTACKBY)) + +/datum/component/simple_rotation/RegisterWithParent() + add_verbs() + add_signals() + . = ..() + +/datum/component/simple_rotation/PostTransfer() + //Because of the callbacks which we don't track cleanly we can't transfer this + //item cleanly, better to let the new of the new item create a new rotation datum + //instead (there's no real state worth transferring) + return COMPONENT_NOTRANSFER + +/datum/component/simple_rotation/UnregisterFromParent() + remove_verbs() + remove_signals() + . = ..() + +/datum/component/simple_rotation/Destroy() + QDEL_NULL(can_user_rotate) + QDEL_NULL(can_be_rotated) + QDEL_NULL(after_rotation) + //Signals + verbs removed via UnRegister + . = ..() + +/datum/component/simple_rotation/RemoveComponent() + remove_verbs() + . = ..() + +/datum/component/simple_rotation/proc/ExamineMessage(datum/source, mob/user, list/examine_list) + if(rotation_flags & ROTATION_ALTCLICK) + examine_list += "Alt-click to rotate it clockwise." + +/datum/component/simple_rotation/proc/HandRot(datum/source, mob/user, rotation = default_rotation_direction) + if(!can_be_rotated.Invoke(user, rotation) || !can_user_rotate.Invoke(user, rotation)) + return + BaseRot(user, rotation) + +/datum/component/simple_rotation/proc/WrenchRot(datum/source, obj/item/I, mob/living/user) + if(!can_be_rotated.Invoke(user,default_rotation_direction) || !can_user_rotate.Invoke(user,default_rotation_direction)) + return + if(I.tool_behaviour == TOOL_WRENCH) + BaseRot(user,default_rotation_direction) + return COMPONENT_NO_AFTERATTACK + +/datum/component/simple_rotation/proc/BaseRot(mob/user,rotation_type) + var/atom/movable/AM = parent + var/rot_degree + switch(rotation_type) + if(ROTATION_CLOCKWISE) + rot_degree = -90 + if(ROTATION_COUNTERCLOCKWISE) + rot_degree = 90 + if(ROTATION_FLIP) + rot_degree = 180 + AM.setDir(turn(AM.dir,rot_degree)) + after_rotation.Invoke(user,rotation_type) + +/datum/component/simple_rotation/proc/default_can_user_rotate(mob/living/user, rotation_type) + //RMNZ: Check if be_close needed or not + if(!istype(user) || !user.can_use(parent)) + return FALSE + return TRUE + +/datum/component/simple_rotation/proc/default_can_be_rotated(mob/user, rotation_type) + var/atom/movable/AM = parent + return !AM.anchored + +/datum/component/simple_rotation/proc/default_after_rotation(mob/user, rotation_type) + to_chat(user, "You [rotation_type == ROTATION_FLIP ? "flip" : "rotate"] [parent].") + +/atom/movable/proc/simple_rotate_clockwise() + set name = "Rotate Clockwise" + set category = "Object" + set src in oview(1) + var/datum/component/simple_rotation/rotcomp = GetComponent(/datum/component/simple_rotation) + if(rotcomp) + rotcomp.HandRot(null,usr,ROTATION_CLOCKWISE) + +/atom/movable/proc/simple_rotate_counterclockwise() + set name = "Rotate Counter-Clockwise" + set category = "Object" + set src in oview(1) + var/datum/component/simple_rotation/rotcomp = GetComponent(/datum/component/simple_rotation) + if(rotcomp) + rotcomp.HandRot(null,usr,ROTATION_COUNTERCLOCKWISE) + +/atom/movable/proc/simple_rotate_flip() + set name = "Flip" + set category = "Object" + set src in oview(1) + var/datum/component/simple_rotation/rotcomp = GetComponent(/datum/component/simple_rotation) + if(rotcomp) + rotcomp.HandRot(null,usr,ROTATION_FLIP) diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm index db2d1a8a6442..a9e9b4d6bf58 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/rods.dm @@ -16,6 +16,13 @@ GLOBAL_LIST_INIT(rod_recipes, list ( new /datum/stack_recipe("chainlink fence door", /obj/structure/fence/door, 10, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), new /datum/stack_recipe("chainlink fence end", /obj/structure/fence/end, 3, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), )), + null, + new /datum/stack_recipe_list("octagon spacepod...", list( + new /datum/stack_recipe("aft starboard pod frame", /obj/item/pod_parts/pod_frame/aft_starboard, 15, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), + new /datum/stack_recipe("aft port pod frame", /obj/item/pod_parts/pod_frame/aft_port, 15, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), + new /datum/stack_recipe("fore port pod frame", /obj/item/pod_parts/pod_frame/fore_port, 15, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), + new /datum/stack_recipe("fore starboard pod frame", /obj/item/pod_parts/pod_frame/fore_starboard, 15, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), + )), )) /obj/item/stack/rods diff --git a/code/modules/mob/living/carbon/human/human_mob.dm b/code/modules/mob/living/carbon/human/human_mob.dm index b4d8babeb117..cb68f52419a1 100644 --- a/code/modules/mob/living/carbon/human/human_mob.dm +++ b/code/modules/mob/living/carbon/human/human_mob.dm @@ -216,6 +216,15 @@ if(V) stat("Total Blood", "[V.bloodtotal]") stat("Usable Blood", "[V.bloodusable]") + if(istype(loc, /obj/spacepod)) // Spacepods! + var/obj/spacepod/S = loc + // If we want numbers instead of percents + // [S.cell ? "[round(S.cell.charge,0.1)]/[S.cell.maxcharge] KJ" : "NONE"] + stat(null, "Spacepod Charge: [S.cell ? "[round((S.cell.charge / S.cell.maxcharge) * 100, 0.1)]%" : "No cell detected"]") + // Same here + // [round((S.obj_integrity / S.max_integrity) * 100, 0.1)] + stat(null, "Spacepod Integrity: [!S.obj_integrity ? "0" : "[round(S.obj_integrity,0.1)]/[S.max_integrity]"]") + stat(null, "Spacepod Velocity: [round(sqrt(S.velocity_x*S.velocity_x+S.velocity_y*S.velocity_y), 0.1)] m/s") /mob/living/carbon/human/ex_act(severity) if(status_flags & GODMODE) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 61d972c71eab..681ff41bdbe2 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -926,6 +926,10 @@ var/obj/mecha/M = loc loc_temp = M.return_temperature() + else if(isspacepod(loc)) + var/obj/spacepod/S = loc + loc_temp = S.return_temperature() + else if(istype(loc, /obj/structure/transit_tube_pod)) loc_temp = environment.temperature diff --git a/code/modules/mob/mob_vars.dm b/code/modules/mob/mob_vars.dm index f20d80240b2f..9907034453ba 100644 --- a/code/modules/mob/mob_vars.dm +++ b/code/modules/mob/mob_vars.dm @@ -252,3 +252,9 @@ var/next_click_modifier = 1 /// Tracks the open UIs that a mob has, used in TGUI for various things, such as updating UIs var/list/open_uis = list() + + ///Allows a datum to intercept all click calls this mob is the so + var/datum/click_intercept + + ///List of datums that this has which make use of MouseMove() + var/list/mousemove_intercept_objects diff --git a/code/modules/research/designs/mecha_designs.dm b/code/modules/research/designs/mecha_designs.dm index 837f80365c04..0ced7b73ffec 100644 --- a/code/modules/research/designs/mecha_designs.dm +++ b/code/modules/research/designs/mecha_designs.dm @@ -196,3 +196,14 @@ materials = list(MAT_GLASS = 1000) build_path = /obj/item/circuitboard/mecha/reticence/targeting category = list("Exosuit Modules") + +// Pod +/datum/design/spacepod_main + name = "Circuit Design (Space Pod Mainboard)" + desc = "Allows for the construction of a spacepod mainboard." + id = "spacepod_main" + req_tech = list("programming" = 1) //RMNZ: Change req_tech + build_type = IMPRINTER + materials = list(MAT_GLASS = 1000) + build_path = /obj/item/circuitboard/mecha/pod + category = list("Exosuit Modules") diff --git a/code/modules/research/designs/spacepod_designs.dm b/code/modules/research/designs/spacepod_designs.dm new file mode 100644 index 000000000000..1e473fe777ff --- /dev/null +++ b/code/modules/research/designs/spacepod_designs.dm @@ -0,0 +1,241 @@ +//////////////////// +////// Core ////// +//////////////////// + +/datum/design/pod_core + name = "Spacepod Core" + desc = "Allows for the construction of a spacepod core system, made up of the engine and life support systems." + id = "podcore" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=5000, MAT_URANIUM=1000, MAT_PLASMA=5000) + build_path = /obj/item/pod_parts/core + category = list("Spacepod Designs") + +///////////////////// +////// Armor ////// +///////////////////// + +/datum/design/pod_armor_civ + name = "Spacepod Armor (civilian)" + desc = "Allows for the construction of spacepod armor. This is the civilian version." + id = "podarmor_civ" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=15000,MAT_GLASS=5000,MAT_PLASMA=10000) + build_path = /obj/item/pod_parts/armor + category = list("Spacepod Designs") + +/datum/design/pod_armor_black + name = "Spacepod Armor (dark)" + desc = "Allows for the construction of spacepod armor. This is the dark civillian version." + id = "podarmor_dark" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=15000,MAT_GLASS=5000,MAT_PLASMA=10000) + build_path = /obj/item/pod_parts/armor/black + category = list("Spacepod Designs") + +/datum/design/pod_armor_industrial + name = "Spacepod Armor (industrial)" + desc = "Allows for the construction of spacepod armor. This is the industrial grade version." + id = "podarmor_industiral" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=15000,MAT_GLASS=5000,MAT_PLASMA=10000,MAT_DIAMOND=5000,MAT_SILVER=7500) + build_path = /obj/item/pod_parts/armor/industrial + category = list("Spacepod Designs") + +/datum/design/pod_armor_sec + name = "Spacepod Armor (security)" + desc = "Allows for the construction of spacepod armor. This is the security version." + id = "podarmor_sec" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=15000,MAT_GLASS=5000,MAT_PLASMA=10000,MAT_DIAMOND=5000,MAT_SILVER=7500) + build_path = /obj/item/pod_parts/armor/security + category = list("Spacepod Designs") + +/datum/design/pod_armor_gold + name = "Spacepod Armor (golden)" + desc = "Allows for the construction of spacepod armor. This is the golden version." + id = "podarmor_gold" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=5000,MAT_GLASS=2500,MAT_PLASMA=7500,MAT_GOLD=10000) + build_path = /obj/item/pod_parts/armor/gold + category = list("Spacepod Designs") + +///////////////////////////// +////// Spacepod Guns ////// +///////////////////////////// + +/* +/datum/design/pod_gun_disabler + name = "Spacepod Equipment (Disabler)" + desc = "Allows for the construction of a spacepod mounted disabler." + id = "podgun_disabler" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 15000) + build_path = /obj/item/spacepod_equipment/weaponry/disabler + category = list("Spacepod Designs") + +/datum/design/pod_gun_bdisabler + name = "Spacepod Equipment (Burst Disabler)" + desc = "Allows for the construction of a spacepod mounted disabler. This is the burst-fire model." + id = "podgun_bdisabler" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 15000, MAT_PLASMA=2000) + build_path = /obj/item/spacepod_equipment/weaponry/burst_disabler + category = list("Spacepod Designs") + +/datum/design/pod_gun_laser + name = "Spacepod Equipment (Laser)" + desc = "Allows for the construction of a spacepod mounted laser." + id = "podgun_laser" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=10000,MAT_GLASS=5000,MAT_GOLD=1000,MAT_SILVER=2000) + build_path = /obj/item/spacepod_equipment/weaponry/laser + category = list("Spacepod Designs") + +/datum/design/pod_ka_basic + name = "Spacepod Equipment (Basic Kinetic Accelerator)" + desc = "Allows for the construction of a weak spacepod Kinetic Accelerator" + id = "pod_ka_basic" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 10000, MAT_GLASS = 5000, MAT_SILVER = 2000, MAT_URANIUM = 2000) + build_path = /obj/item/spacepod_equipment/weaponry/basic_pod_ka + category = list("Spacepod Designs") + +/datum/design/pod_ka + name = "Spacepod Equipment (Kinetic Accelerator)" + desc = "Allows for the construction of a spacepod Kinetic Accelerator." + id = "pod_ka" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 10000, MAT_GLASS = 5000, MAT_SILVER = 2000, MAT_GOLD = 2000, MAT_DIAMOND = 2000) + build_path = /obj/item/spacepod_equipment/weaponry/pod_ka + category = list("Spacepod Designs") + +/datum/design/pod_plasma_cutter + name = "Spacepod Equipment (Plasma Cutter)" + desc = "Allows for the construction of a plasma cutter." + id = "pod_plasma_cutter" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 10000, MAT_GLASS = 5000, MAT_SILVER = 2000, MAT_GOLD = 2000, MAT_DIAMOND = 2000) + build_path = /obj/item/spacepod_equipment/weaponry/plasma_cutter + category = list("Spacepod Designs") + +/datum/design/pod_adv_plasma_cutter + name = "Spacepod Equipment (Advanced Plasma cutter)" + desc = "Allows for the construction of an advanced plasma cutter." + id = "pod_adv_plasma_cutter" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 10000, MAT_GLASS = 5000, MAT_SILVER = 4000, MAT_GOLD = 4000, MAT_DIAMOND = 4000) + build_path = /obj/item/spacepod_equipment/weaponry/plasma_cutter/adv + category = list("Spacepod Designs") +*/ + +//////////////////////////////////// +////// Spacepod Misc. Items ////// +//////////////////////////////////// + +/* +/datum/design/pod_misc_tracker + name = "Spacepod Tracking Module" + desc = "Allows for the construction of a spacepod tracking module." + id = "podmisc_tracker" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=5000) + build_path = /obj/item/spacepod_equipment/tracker + category = list("Spacepod Designs") +*/ + +//////////////////////////////////// +////// Spacepod Cargo Items ////// +//////////////////////////////////// + +/* +/datum/design/pod_cargo_ore + name = "Spacepod Ore Storage Module" + desc = "Allows for the construction of a spacepod ore storage module." + id = "podcargo_ore" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=20000, MAT_GLASS=2000) + build_path = /obj/item/spacepod_equipment/cargo/large/ore + category = list("Spacepod Designs") + +/datum/design/pod_cargo_crate + name = "Spacepod Crate Storage Module" + desc = "Allows the construction of a spacepod crate storage module." + id = "podcargo_crate" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=25000) + build_path = /obj/item/spacepod_equipment/cargo/large + category = list("Spacepod Designs") +*/ + +/datum/design/passenger_seat + name = "Spacepod Passenger Seat" + desc = "Allows the construction of a spacepod passenger seat module." + id = "podcargo_seat" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=7500, MAT_GLASS=2500) + build_path = /obj/item/spacepod_equipment/cargo/chair + category = list("Spacepod Designs") + +/* +/datum/design/loot_box + name = "Spacepod Loot Storage Module" + desc = "Allows the construction of a spacepod auxillary cargo module." + id = "podcargo_lootbox" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=7500, MAT_GLASS=2500) + build_path = /obj/item/spacepod_equipment/cargo/loot_box + category = list("Spacepod Designs") +*/ + +/////////////////////////////////// +////// Spacepod Lock Items ////// +/////////////////////////////////// + +/datum/design/pod_lock_keyed + name = "Spacepod Tumbler Lock" + desc = "Allows for the construction of a tumbler style podlock." + id = "podlock_keyed" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=4500) + build_path = /obj/item/spacepod_equipment/lock/keyed + category = list("Spacepod Designs") + +/datum/design/pod_key + name = "Spacepod Tumbler Lock Key" + desc = "Allows for the construction of a blank key for a podlock." + id = "podkey" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=500) + build_path = /obj/item/spacepod_key + category = list("Spacepod Designs") + +/datum/design/lockbuster + name = "Spacepod Lock Buster" + desc = "Allows for the construction of a spacepod lockbuster." + id = "pod_lockbuster" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 15000, MAT_DIAMOND=2500) //it IS a drill! + build_path = /obj/item/device/lock_buster + category = list("Spacepod Designs") diff --git a/code/modules/research/protolathe.dm b/code/modules/research/protolathe.dm index 2b78ebd2f94b..26cedb8720ed 100644 --- a/code/modules/research/protolathe.dm +++ b/code/modules/research/protolathe.dm @@ -22,7 +22,8 @@ Note: Must be placed west/left of and R&D console to function. "Miscellaneous", "Power", "Stock Parts", - "Weapons" + "Weapons", + "Spacepod Designs" ) /obj/machinery/r_n_d/protolathe/Initialize(mapload) diff --git a/code/modules/spacepods/icons/2x2.dmi b/code/modules/spacepods/icons/2x2.dmi new file mode 100644 index 0000000000000000000000000000000000000000..ecdb69d66c379973535ccd296a41f797ae6039d4 GIT binary patch literal 1085 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 G5&s9g{0XA~ literal 0 HcmV?d00001 diff --git a/code/modules/spacepods/spacepod.dm b/code/modules/spacepods/spacepod.dm new file mode 100644 index 000000000000..8e6fbd8e2d92 --- /dev/null +++ b/code/modules/spacepods/spacepod.dm @@ -0,0 +1,691 @@ +//YOGSTATION SPECEPODS + ITS ORIGINAL COMMENT +/* ------------------------------------------------------------ +This is like paradise spacepods but with a few differences: +- no spacepod fabricator, parts are made in techfabs and frames are made using metal rods. +- not tile based, instead has velocity and acceleration. why? so I can put all this math to use. +- damages shit if you run into it too fast instead of just stopping. You have to have a huge running start to do that though and damages the spacepod as well. +- doesn't explode +------------------------------------------------------------ */ + +// MrRomainzZ Comment: +// I decided to split the code like mechs do because I find it very similar in some ways +// Mostly untouched, but adapted for paradise and addition of new pods + +GLOBAL_LIST_INIT(spacepods_list, list()) + +/obj/spacepod + name = "space pod" + desc = "A frame for a spacepod." + icon = 'goon/icons/obj/spacepods/construction_2x2.dmi' + icon_state = "pod_1" + density = TRUE + opacity = FALSE + anchored = TRUE + dir = NORTH // always points north because why not + layer = SPACEPOD_LAYER + bound_width = 64 + bound_height = 64 + animate_movement = NO_STEPS // we do our own gliding here + + resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF // it floats above lava or something, I dunno + + max_integrity = 50 + integrity_failure = 50 + + var/list/equipment = list() + var/list/equipment_slot_limits = list( + SPACEPOD_SLOT_MISC = 1, + SPACEPOD_SLOT_CARGO = 2, + SPACEPOD_SLOT_WEAPON = 1, + SPACEPOD_SLOT_LOCK = 1) + var/obj/item/spacepod_equipment/lock/lock + var/obj/item/spacepod_equipment/weaponry/weapon + var/next_firetime = 0 + var/locked = FALSE + var/hatch_open = FALSE + var/construction_state = SPACEPOD_EMPTY + var/obj/item/pod_parts/armor/pod_armor = null + var/obj/item/stock_parts/cell/cell = null + + //inner atmos + var/datum/gas_mixture/cabin_air + var/obj/machinery/atmospherics/portable/canister/internal_tank + var/last_slowprocess = 0 + + var/mob/living/pilot = null + var/list/passengers = list() + var/max_passengers = 0 + + var/velocity_x = 0 // tiles per second. + var/velocity_y = 0 + var/offset_x = 0 // like pixel_x/y but in tiles + var/offset_y = 0 + var/angle = 0 // degrees, clockwise + var/desired_angle = null // set by pilot moving his mouse + var/angular_velocity = 0 // degrees per second + var/max_angular_acceleration = 360 // in degrees per second per second + var/last_thrust_forward = 0 + var/last_thrust_right = 0 + var/last_rotate = 0 + + var/brakes = TRUE + var/user_thrust_dir = 0 + var/forward_maxthrust = 6 + var/backward_maxthrust = 3 + var/side_maxthrust = 1 + + var/lights = 0 + var/lights_power = 6 + var/static/list/icon_light_color = list("pod_civ" = LIGHT_COLOR_WHITE, \ + "pod_mil" = "#BBF093", \ + "pod_synd" = LIGHT_COLOR_RED, \ + "pod_gold" = LIGHT_COLOR_WHITE, \ + "pod_black" = "#3B8FE5", \ + "pod_industrial" = "#CCCC00") + + var/bump_impulse = 0.6 + var/bounce_factor = 0.2 // how much of our velocity to keep on collision + var/lateral_bounce_factor = 0.95 // mostly there to slow you down when you drive (pilot?) down a 2x2 corridor + +/obj/spacepod/Initialize(mapload) + . = ..() + GLOB.spacepods_list += src + START_PROCESSING(SSspacepods, src) + cabin_air = new + cabin_air.temperature = T20C + cabin_air.volume = 200 + + /* Paradise variant + cabin_air.oxygen = O2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) + cabin_air.nitrogen = N2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) + */ + + /* Yogstation variant + cabin_air.assert_gas(GAS_O2) + cabin_air.assert_gas(GAS_N2) + cabin_air.gases[GAS_O2][MOLES] = ONE_ATMOSPHERE*O2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) + cabin_air.gases[GAS_N2][MOLES] = ONE_ATMOSPHERE*N2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) + */ + +/////////////////////// +////// Helpers ////// +/////////////////////// + +/obj/spacepod/Entered() + . = ..() + +/obj/spacepod/Exited() + . = ..() + +/obj/spacepod/proc/InterceptClickOn(mob/user, params, atom/target) + var/list/params_list = params2list(params) + if(target == src || istype(target, /atom/movable/screen) || (target && (target in user.get_contents())) || user != pilot || params_list["shift"] || params_list["alt"] || params_list["ctrl"]) + return FALSE + if(weapon) + weapon.fire_weapons(target) + return TRUE + +/obj/spacepod/proc/enter_pod(mob/living/user) + if(user.stat != CONSCIOUS) + return FALSE + + if(locked) // RMNZ: You also check your health on this + to_chat(user, "[src]'s doors are locked!") + return FALSE + + if(!istype(user)) + return FALSE + + if(user.incapacitated()) + return FALSE + if(!ishuman(user)) + return FALSE + + if(passengers.len <= max_passengers || !pilot) + visible_message("[user] starts to climb into [src].") + if(do_after(user, 4 SECONDS, target = src) && construction_state == SPACEPOD_ARMOR_WELDED) // RMNZ: No check for free passenger seats + var/success = add_rider(user) + if(!success) + to_chat(user, "You were too slow. Try better next time, loser.") + return success + else + to_chat(user, "You stop entering [src].") + else + to_chat(user, "You can't fit in [src], it's full!") + return FALSE + +/obj/spacepod/proc/go_out(forced, atom/newloc = loc) + if(!pilot) + return + if(!isliving(usr) || usr.stat > CONSCIOUS) + return + + if(usr.restrained()) + to_chat(usr, "You attempt to stumble out of [src]. This will take two minutes.") + if(pilot) + to_chat(pilot, "[usr] is trying to escape [src].") + if(!do_after(usr, 2 MINUTES, target = src)) + return + + if(remove_rider(usr)) + to_chat(usr, "You climb out of [src].") + +/obj/spacepod/proc/add_rider(mob/living/M, allow_pilot = TRUE) + if(M == pilot || (M in passengers)) + return FALSE + if(!pilot && allow_pilot) + pilot = M + LAZYOR(M.mousemove_intercept_objects, src) + M.click_intercept = src + // GrantActions(M) + // addverbs(M) + else if(passengers.len < max_passengers) + passengers += M + else + return FALSE + GrantActions(M) // Passengers have buttons now + M.stop_pulling() + M.forceMove(src) + playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) + return TRUE + +/obj/spacepod/proc/remove_rider(mob/living/M) + if(!M) + return + + RemoveActions(M) + + if(M == pilot) + pilot = null + // removeverbs(M) + LAZYREMOVE(M.mousemove_intercept_objects, src) + if(M.click_intercept == src) + M.click_intercept = null + desired_angle = null // since there's no pilot there's no one aiming it. + else if(M in passengers) + passengers -= M + else + return FALSE + if(M.loc == src) + M.forceMove(loc) + if(M.client) + M.client.pixel_x = 0 + M.client.pixel_y = 0 + return TRUE + +/obj/spacepod/proc/lock_pod() + if(!lock) // RMNZ: Passengers see this instead of "You can't reach controls" + to_chat(usr, "[src] has no locking mechanism.") + locked = FALSE //Should never be false without a lock, but if it somehow happens, that will force an unlock. + else + locked = !locked + to_chat(usr, "You [locked ? "lock" : "unlock"] the doors.") // RMNZ: You "tap" on the pod with your key. Also action button doesn't update + +/obj/spacepod/proc/verb_check(require_pilot = TRUE, mob/user = null) + if(!user) + user = usr + if(require_pilot && user != pilot) + to_chat(user, "You can't reach the controls from your chair") + return FALSE + return !user.incapacitated() && isliving(user) + +/obj/spacepod/AltClick(user) + if(!verb_check(user = user)) + return + brakes = !brakes + to_chat(usr, "You toggle the brakes [brakes ? "on" : "off"].") + +//////////////////////// +////// AttackBy ////// +//////////////////////// + +/obj/spacepod/attackby(obj/item/W, mob/living/user) + if(user.a_intent == INTENT_HARM) + return ..() + else if(construction_state != SPACEPOD_ARMOR_WELDED) + . = handle_spacepod_construction(W, user) + if(.) + return + else + return ..() + // and now for the real stuff + else + if(W.tool_behaviour == TOOL_CROWBAR) + if(hatch_open || !locked) + hatch_open = !hatch_open + W.play_tool_sound(src) + to_chat(user, "You [hatch_open ? "open" : "close"] the maintenance hatch.") + else + to_chat(user, "The hatch is locked shut!") + return TRUE + if(istype(W, /obj/item/stock_parts/cell)) + if(!hatch_open) + to_chat(user, "The maintenance hatch is closed!") + return TRUE + if(cell) + to_chat(user, "The pod already has a battery.") + return TRUE + if(user.drop_item()) + to_chat(user, "You insert [W] into the pod.") + W.forceMove(src) + cell = W + return TRUE + if(istype(W, /obj/item/spacepod_equipment)) + if(!hatch_open) + to_chat(user, "The maintenance hatch is closed!") + return TRUE + var/obj/item/spacepod_equipment/SE = W + if(SE.can_install(src, user)) + if(user.drop_item()) + SE.forceMove(src) + SE.on_install(src) + return TRUE + if(lock && istype(W, /obj/item/device/lock_buster)) + var/obj/item/device/lock_buster/L = W + if(L.on) + user.visible_message("[user] is drilling through [src]'s lock!", + "You start drilling through [src]'s lock!") + if(do_after(user, 10 SECONDS * W.toolspeed, target = src)) + if(lock) + var/obj/O = lock + lock.on_uninstall() + qdel(O) + user.visible_message("[user] has destroyed [src]'s lock!", + "You destroy [src]'s lock!") + else + user.visible_message("[user] fails to break through [src]'s lock!", + "You were unable to break through [src]'s lock!") + return TRUE + to_chat(user, "Turn the [L] on first.") + return TRUE + if(W.tool_behaviour == TOOL_WELDER) + var/repairing = cell || internal_tank || equipment.len || (obj_integrity < max_integrity) || pilot || passengers.len + if(!hatch_open) + to_chat(user, "You must open the maintenance hatch before [repairing ? "attempting repairs" : "unwelding the armor"].") + return TRUE + if(repairing && obj_integrity >= max_integrity) + to_chat(user, "[src] is fully repaired!") + return TRUE + to_chat(user, "You start [repairing ? "repairing [src]" : "slicing off [src]'s armor'"]") + if(W.use_tool(src, user, 50, amount=3, volume = 50)) + if(repairing) + obj_integrity = min(max_integrity, obj_integrity + 10) + update_appearance(UPDATE_ICON) + to_chat(user, "You mend some [pick("dents","bumps","damage")] with [W]") + else if(!cell && !internal_tank && !equipment.len && !pilot && !passengers.len && construction_state == SPACEPOD_ARMOR_WELDED) + user.visible_message("[user] slices off [src]'s armor.", "You slice off [src]'s armor.") + construction_state = SPACEPOD_ARMOR_SECURED + update_appearance(UPDATE_ICON) + return TRUE + return ..() + +//////////////////////////////////// +////// Health related procs ////// +//////////////////////////////////// + +/obj/spacepod/Destroy() + GLOB.spacepods_list -= src + QDEL_NULL(pilot) + QDEL_LIST_CONTENTS(passengers) + QDEL_LIST_CONTENTS(equipment) + QDEL_NULL(cabin_air) + QDEL_NULL(cell) + return ..() + +/obj/spacepod/attack_hand(mob/user as mob) + if(user.a_intent == INTENT_GRAB && !locked) + var/mob/living/target + if(pilot) + target = pilot + else if(passengers.len > 0) + target = passengers[1] + + if(target && istype(target)) // RMNZ: You can rip yourself out the pod + src.visible_message("[user] is trying to rip the door open and pull [target] out of [src]!", + "You see [user] outside the door trying to rip it open!") + if(do_after(user, 5 SECONDS, target = src) && construction_state == SPACEPOD_ARMOR_WELDED) + if(remove_rider(target)) + target.Stun(20) + target.visible_message("[user] flings the door open and tears [target] out of [src]", + "The door flies open and you are thrown out of [src] and to the ground!") + return + target.visible_message("[user] was unable to get the door open!", + "You manage to keep [user] out of [src]!") + + if(!hatch_open) + //if(cargo_hold.storage_slots > 0) + // if(!locked) + // cargo_hold.open(user) + // else + // to_chat(user, "The storage compartment is locked") + return ..() + + if(user == pilot) + return ..() + + var/list/items = list(cell, internal_tank) + items += equipment + var/list/item_map = list() + //var/list/used_key_list = list() + for(var/obj/I in items) + item_map[I.name] = I + var/selection = input(user, "Remove which equipment?", null, null) as null|anything in item_map + var/obj/O = item_map[selection] + if(O && istype(O) && (O in contents) && user != pilot) + // alrightey now to figure out what it is + if(O == cell) + cell = null + else if(O == internal_tank) + internal_tank = null + else if(O in equipment) + var/obj/item/spacepod_equipment/SE = O + if(!SE.can_uninstall(user)) + return + SE.on_uninstall() + else + return + O.forceMove(loc) + if(isitem(O)) + user.put_in_hands(O) + +/obj/spacepod/ex_act(severity) + switch(severity) + if(1) + for(var/mob/living/M in contents) + M.ex_act(severity+1) + deconstruct() + if(2) + take_damage(100, BRUTE, BOMB, 0) + if(3) + if(prob(40)) + take_damage(40, BRUTE, BOMB, 0) + +/obj/spacepod/obj_break() + if(obj_integrity <= 0) + return // nah we'll let the other boy handle it + if(construction_state < SPACEPOD_ARMOR_LOOSE) + return + if(pod_armor) + var/obj/A = pod_armor + remove_armor() + qdel(A) + if(prob(40)) + new /obj/item/stack/sheet/metal(loc, 5) + if(prob(40)) + new /obj/item/stack/sheet/metal(loc, 5) + construction_state = SPACEPOD_CORE_SECURED + if(cabin_air) + var/datum/gas_mixture/GM = cabin_air.remove_ratio(1) + var/turf/T = get_turf(src) + if(GM && T) + T.assume_air(GM) + cell = null + internal_tank = null + for(var/atom/movable/AM in contents) + if(AM in equipment) + var/obj/item/spacepod_equipment/SE = AM + if(istype(SE)) + SE.on_uninstall(src) + if(ismob(AM)) + forceMove(AM, loc) + remove_rider(AM) + else if(prob(60)) + AM.forceMove(loc) + else if(isitem(AM) || !isobj(AM)) + qdel(AM) + else + var/obj/O = AM + O.forceMove(loc) + O.deconstruct() + +/obj/spacepod/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = TRUE, attack_dir, armour_penetration = 0) + ..() + update_appearance(UPDATE_ICON) + +/obj/spacepod/deconstruct(disassembled = FALSE) + if(!get_turf(src)) + qdel(src) + return + remove_rider(pilot) + while(passengers.len) + remove_rider(passengers[1]) + passengers.Cut() + if(disassembled) + // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + // alright fine fine you can have the frame pieces back + var/clamped_angle = (round(angle, 90) % 360 + 360) % 360 + var/target_dir = NORTH + switch(clamped_angle) + if(0) + target_dir = NORTH + if(90) + target_dir = EAST + if(180) + target_dir = SOUTH + if(270) + target_dir = WEST + //RMNZ: Addition of new pods 2 + var/list/frame_piece_types = list(/obj/item/pod_parts/pod_frame/aft_port, /obj/item/pod_parts/pod_frame/aft_starboard, /obj/item/pod_parts/pod_frame/fore_port, /obj/item/pod_parts/pod_frame/fore_starboard) + var/obj/item/pod_parts/pod_frame/current_piece = null + var/turf/CT = get_turf(src) + var/list/frame_pieces = list() + for(var/frame_type in frame_piece_types) + var/obj/item/pod_parts/pod_frame/F = new frame_type + F.dir = target_dir + F.anchored = TRUE + if(1 == turn(F.dir, -F.link_angle)) + current_piece = F + frame_pieces += F + while(current_piece && !current_piece.loc) + if(!CT) + break + current_piece.forceMove(CT) + CT = get_step(CT, turn(current_piece.dir, -current_piece.link_angle)) + current_piece = locate(current_piece.link_to) in frame_pieces + // there here's your frame pieces back, happy? + qdel(src) + +///////////////////////////////// +////// Atmospheric stuff ////// +///////////////////////////////// + +/obj/spacepod/return_air() + return cabin_air + +/obj/spacepod/remove_air(amount) + return cabin_air.remove(amount) + +/obj/spacepod/proc/return_temperature() + var/datum/gas_mixture/t_air = return_air() + if(t_air) + . = t_air.return_temperature() + +/obj/spacepod/proc/slowprocess() + // Temp Regulation + if(cabin_air && cabin_air.return_volume() > 0) + var/delta = cabin_air.temperature - T20C + cabin_air.temperature -= max(-10, min(10, round(delta / 4, 0.1))) + + // Air Regulation + if(internal_tank && cabin_air) + var/datum/gas_mixture/tank_air = internal_tank.return_air() + + var/release_pressure = ONE_ATMOSPHERE + var/cabin_pressure = cabin_air.return_pressure() + var/pressure_delta = min(release_pressure - cabin_pressure, (tank_air.return_pressure() - cabin_pressure)/2) + var/transfer_moles = 0 + if(pressure_delta > 0) //cabin pressure lower than release pressure + if(tank_air.return_temperature() > 0) + transfer_moles = pressure_delta*cabin_air.return_volume()/(cabin_air.return_temperature() * R_IDEAL_GAS_EQUATION) + var/datum/gas_mixture/removed = tank_air.remove(transfer_moles) + cabin_air.merge(removed) + else if(pressure_delta < 0) //cabin pressure higher than release pressure + var/datum/gas_mixture/t_air = return_air() + pressure_delta = cabin_pressure - release_pressure + if(t_air) + pressure_delta = min(cabin_pressure - t_air.return_pressure(), pressure_delta) + if(pressure_delta > 0) //if location pressure is lower than cabin pressure + transfer_moles = pressure_delta*cabin_air.return_volume()/(cabin_air.return_temperature() * R_IDEAL_GAS_EQUATION) + var/datum/gas_mixture/removed = cabin_air.remove(transfer_moles) + if(t_air) + t_air.merge(removed) + else //just delete the cabin gas, we're in space or some shit + qdel(removed) + + //Power Related + if(!cell || cell.charge < 1) // RMNZ: How to update action button from here? + lights = 0 + set_light(0) + +////////////////////////////// +////// Movement procs ////// +////////////////////////////// + +/obj/spacepod/onMouseMove(object,location,control,params) + if(!pilot || !pilot.client || pilot.incapacitated()) + return // I don't know what's going on. + var/list/params_list = params2list(params) + var/sl_list = splittext(params_list["screen-loc"],",") + var/sl_x_list = splittext(sl_list[1], ":") + var/sl_y_list = splittext(sl_list[2], ":") + var/view_list = isnum(pilot.client.view) ? list("[pilot.client.view*2+1]","[pilot.client.view*2+1]") : splittext(pilot.client.view, "x") + var/dx = text2num(sl_x_list[1]) + (text2num(sl_x_list[2]) / world.icon_size) - 1 - text2num(view_list[1]) / 2 + var/dy = text2num(sl_y_list[1]) + (text2num(sl_y_list[2]) / world.icon_size) - 1 - text2num(view_list[2]) / 2 + if(sqrt(dx*dx+dy*dy) > 1) + desired_angle = 90 - ATAN2(dx, dy) + else + desired_angle = null + +/obj/spacepod/relaymove(mob/user, direction) + if(user != pilot || pilot.incapacitated()) + return + user_thrust_dir = direction + +////////////////////////////////// +////// Construction procs ////// +////////////////////////////////// + +/obj/spacepod/proc/add_armor(obj/item/pod_parts/armor/armor) + desc = armor.pod_desc + max_integrity = armor.pod_integrity + obj_integrity = max_integrity - integrity_failure + obj_integrity + pod_armor = armor + update_appearance(UPDATE_ICON) + +/obj/spacepod/proc/remove_armor() + if(!pod_armor) + obj_integrity = min(integrity_failure, obj_integrity) + max_integrity = integrity_failure + desc = initial(desc) + pod_armor = null + update_appearance(UPDATE_ICON) + +/obj/spacepod/update_icon_state() + . = ..() + if(construction_state != SPACEPOD_ARMOR_WELDED) + icon = 'goon/icons/obj/spacepods/construction_2x2.dmi' + icon_state = "pod_[construction_state]" + return + + if(pod_armor) + icon = pod_armor.pod_icon + icon_state = pod_armor.pod_icon_state + else + icon = 'goon/icons/obj/spacepods/2x2.dmi' + icon_state = initial(icon_state) + +/obj/spacepod/update_overlays() + . = ..() + if(construction_state != SPACEPOD_ARMOR_WELDED) + if(pod_armor && construction_state >= SPACEPOD_ARMOR_LOOSE) + var/mutable_appearance/masked_armor = mutable_appearance(icon = 'goon/icons/obj/spacepods/construction_2x2.dmi', icon_state = "armor_mask") + var/mutable_appearance/armor = mutable_appearance(pod_armor.pod_icon, pod_armor.pod_icon_state) + armor.blend_mode = BLEND_MULTIPLY + masked_armor.overlays = list(armor) + masked_armor.appearance_flags = KEEP_TOGETHER + . += masked_armor + return + + if(obj_integrity <= max_integrity / 2) + . += image(icon='goon/icons/obj/spacepods/2x2.dmi', icon_state="pod_damage") + if(obj_integrity <= max_integrity / 4) + . += image(icon='goon/icons/obj/spacepods/2x2.dmi', icon_state="pod_fire") + + if(weapon && weapon.overlay_icon_state) + . += image(icon=weapon.overlay_icon,icon_state=weapon.overlay_icon_state) + + light_color = icon_light_color[icon_state] || LIGHT_COLOR_WHITE + + // Thrust! + var/list/left_thrusts = list() + left_thrusts.len = 8 + var/list/right_thrusts = list() + right_thrusts.len = 8 + for(var/cdir in GLOB.cardinal) + left_thrusts[cdir] = 0 + right_thrusts[cdir] = 0 + var/back_thrust = 0 + if(last_thrust_right != 0) + var/tdir = last_thrust_right > 0 ? WEST : EAST + left_thrusts[tdir] = abs(last_thrust_right) / side_maxthrust + right_thrusts[tdir] = abs(last_thrust_right) / side_maxthrust + if(last_thrust_forward > 0) + back_thrust = last_thrust_forward / forward_maxthrust + if(last_thrust_forward < 0) + left_thrusts[NORTH] = -last_thrust_forward / backward_maxthrust + right_thrusts[NORTH] = -last_thrust_forward / backward_maxthrust + if(last_rotate != 0) + var/frac = abs(last_rotate) / max_angular_acceleration + for(var/cdir in GLOB.cardinal) + if(last_rotate > 0) + right_thrusts[cdir] += frac + else + left_thrusts[cdir] += frac + for(var/cdir in GLOB.cardinal) + var/left_thrust = left_thrusts[cdir] + var/right_thrust = right_thrusts[cdir] + if(left_thrust) + . += image(icon = 'code/modules/spacepods/icons/2x2.dmi', icon_state = "rcs_left", dir = cdir) + if(right_thrust) + . += image(icon = 'code/modules/spacepods/icons/2x2.dmi', icon_state = "rcs_right", dir = cdir) + if(back_thrust) + var/image/I = image(icon = 'code/modules/spacepods/icons/2x2.dmi', icon_state = "thrust") + I.transform = matrix(1, 0, 0, 0, 1, -32) + . += I + +/obj/spacepod/MouseDrop_T(atom/movable/A, mob/living/user) + if(user == pilot || (user in passengers) || construction_state != SPACEPOD_ARMOR_WELDED) + return + + if(istype(A, /obj/machinery/atmospherics/portable/canister)) + if(internal_tank) + to_chat(user, "[src] already has an internaltank!") + return + if(!A.Adjacent(src)) + to_chat(user, "The canister is not close enough!") + return + if(hatch_open) + to_chat(user, "The hatch is shut!") + to_chat(user, "You begin inserting the canister into [src]") + if(do_after(user, 5 SECONDS, target = A) && construction_state == SPACEPOD_ARMOR_WELDED) + to_chat(user, "You insert the canister into [src]") + A.forceMove(src) + internal_tank = A + return + + if(isliving(A)) + var/mob/living/M = A + if(M != user && !locked) + if(passengers.len >= max_passengers && !pilot) + to_chat(user, "[A.p_they()] can't fly the pod!") + return + if(passengers.len < max_passengers) + visible_message("[user] starts loading [M] into [src]!") + if(do_after(user, 5 SECONDS, target = M) && construction_state == SPACEPOD_ARMOR_WELDED) + add_rider(M, FALSE) + return + if(M == user) + enter_pod(user) + return + + return ..() diff --git a/code/modules/spacepods/spacepod_actions.dm b/code/modules/spacepods/spacepod_actions.dm new file mode 100644 index 000000000000..dc12481b1d37 --- /dev/null +++ b/code/modules/spacepods/spacepod_actions.dm @@ -0,0 +1,122 @@ +/obj/spacepod + //Action datums + var/datum/action/innate/spacepod/spacepod_exit/exit_action = new + var/datum/action/innate/spacepod/spacepod_toggle_brakes/brakes_action = new + var/datum/action/innate/spacepod/spacepod_toggle_lights/lights_action = new + var/datum/action/innate/spacepod/spacepod_toggle_poddoors/podddoors_action = new + var/datum/action/innate/spacepod/spacepod_lock_doors/lock_action = new + +/obj/spacepod/proc/GrantActions(mob/living/user) + exit_action.Grant(user, src) + brakes_action.Grant(user, src) + lights_action.Grant(user, src) + podddoors_action.Grant(user, src) + lock_action.Grant(user, src) + +/obj/spacepod/proc/RemoveActions(mob/living/user) + exit_action.Remove(user) + brakes_action.Remove(user) + lights_action.Remove(user) + podddoors_action.Remove(user) + lock_action.Remove(user) + +/datum/action/innate/spacepod + check_flags = AB_CHECK_RESTRAINED | AB_CHECK_STUNNED | AB_CHECK_CONSCIOUS + icon_icon = 'code/modules/spacepods/icons/actions_spacepod.dmi' + var/obj/spacepod/frame + +/datum/action/innate/spacepod/Grant(mob/living/L, obj/spacepod/S) + if(S) + frame = S + . = ..() + +/datum/action/innate/spacepod/Destroy() + frame = null + return ..() + +// Actions! + +/datum/action/innate/spacepod/spacepod_exit + name = "Eject From Spacepod" + button_icon_state = "pods_exit" + +/datum/action/innate/spacepod/spacepod_exit/Activate() + frame.go_out() + +/datum/action/innate/spacepod/spacepod_toggle_brakes + name = "Toggle Spacepod Brakes" + button_icon_state = "handbrake_on" + +/datum/action/innate/spacepod/spacepod_toggle_brakes/Activate() + if(!frame.verb_check()) + return + frame.brakes = !frame.brakes + to_chat(usr, "You toggle the brakes [frame.brakes ? "on" : "off"].") + button_icon_state = "handbrake_[frame.brakes ? "on" : "off"]" + UpdateButtonIcon() + +/datum/action/innate/spacepod/spacepod_toggle_lights + name = "Toggle Spacepod Lights" + button_icon_state = "pods_lights_off" + +/datum/action/innate/spacepod/spacepod_toggle_lights/Activate() + if(!frame.verb_check()) + return + + /* + if(!frame.cell || frame.cell.charge < 1) // RMNZ: To turn off button when cell has no power + button_icon_state = "pods_lights_off" + UpdateButtonIcon() + return + */ + + frame.lights = !frame.lights + if(frame.lights) + frame.set_light(frame.lights_power) + else + frame.set_light(0) + to_chat(usr, "Lights toggled [frame.lights ? "on" : "off"].") + button_icon_state = "pods_lights_[frame.lights ? "on" : "off"]" + for(var/mob/M in frame.passengers) + to_chat(M, "Lights toggled [frame.lights ? "on" : "off"].") + button_icon_state = "pods_lights_[frame.lights ? "on" : "off"]" + UpdateButtonIcon() + +/datum/action/innate/spacepod/spacepod_toggle_poddoors + name = "Toggle Nearest Pod Doors" + button_icon_state = "blast_door_use" + +/datum/action/innate/spacepod/spacepod_toggle_poddoors/Activate() + if(!frame.verb_check()) + return + + for(var/obj/machinery/door/poddoor/multi_tile/P in orange(3, frame)) + for(var/mob/living/carbon/human/O in frame.contents) + if(P.check_access(O.get_active_hand()) || P.check_access(O.wear_id)) + if(P.density) + P.open() + return TRUE + else + P.close() + return TRUE + to_chat(usr, "Access denied.") + return + + to_chat(usr, "You are not close to any pod doors.") + +/datum/action/innate/spacepod/spacepod_lock_doors + name = "Lock Spacepod Doors" + button_icon_state = "pods_door_on" + +/datum/action/innate/spacepod/spacepod_lock_doors/Activate() + if(!frame.verb_check(FALSE)) + return + + if(!frame.lock) + to_chat(usr, "[src] has no locking mechanism.") + frame.locked = FALSE //Should never be false without a lock, but if it somehow happens, that will force an unlock. + else + frame.locked = !frame.locked + to_chat(usr, "You [frame.locked ? "lock" : "unlock"] the doors.") + button_icon_state = "pods_door_[!frame.locked ? "on" : "off"]" + UpdateButtonIcon() diff --git a/code/modules/spacepods/spacepod_construction.dm b/code/modules/spacepods/spacepod_construction.dm new file mode 100644 index 000000000000..b8db43e49bd5 --- /dev/null +++ b/code/modules/spacepods/spacepod_construction.dm @@ -0,0 +1,206 @@ +/obj/spacepod/examine(mob/user) + . = ..() + switch(construction_state) // more construction states than r-walls! + if(SPACEPOD_EMPTY) + . += "The struts holding it together can be cut and it is missing wires." + if(SPACEPOD_WIRES_LOOSE) + . += "The wires need to be screwed on." + if(SPACEPOD_WIRES_SECURED) + . += "The wires are screwed on and need a circuit board." + if(SPACEPOD_CIRCUIT_LOOSE) + . += "The circuit board is loosely attached and needs to be screwed on." + if(SPACEPOD_CIRCUIT_SECURED) + . += "The circuit board is screwed on, and there is space for a core." + if(SPACEPOD_CORE_LOOSE) + . += "The core is loosely attached and needs to be bolted on." + if(SPACEPOD_CORE_SECURED) + . += "The core is bolted on and the metal bulkhead can be attached." + if(SPACEPOD_BULKHEAD_LOOSE) + . += "The bulkhead is loosely attached and can be bolted down." + if(SPACEPOD_BULKHEAD_SECURED) + . += "The bulkhead is bolted on but not welded on." + if(SPACEPOD_BULKHEAD_WELDED) + . += "The bulkhead is welded on and armor can be attached." + if(SPACEPOD_ARMOR_LOOSE) + . += "The armor is loosely attached and can be bolted down." + if(SPACEPOD_ARMOR_SECURED) + . += "The armor is bolted on but not welded on." + if(SPACEPOD_ARMOR_WELDED) + if(hatch_open) + if(cell || internal_tank || equipment.len) + . += "The maintenance hatch is pried open and there are parts inside that can be removed." + else + . += "The maintenance hatch is pried open and the armor is welded on." + else + if(locked) + . += "[src] is locked." + else + . += "The maintenance hatch is closed." + +/obj/spacepod/proc/handle_spacepod_construction(obj/item/W, mob/living/user) + // time for a construction/deconstruction process to rival r-walls + var/obj/item/stack/ST = W + switch(construction_state) + if(SPACEPOD_EMPTY) + if(W.tool_behaviour == TOOL_WIRECUTTER) + . = TRUE + user.visible_message("[user] deconstructs [src].", "You deconstruct [src].") + W.play_tool_sound(src) + deconstruct(TRUE) + else if(istype(W, /obj/item/stack/cable_coil)) + . = TRUE + if(ST.use(10)) + user.visible_message("[user] wires [src].", "You wire [src].") + construction_state++ + else + to_chat(user, "You need 10 wires for this!") + if(SPACEPOD_WIRES_LOOSE) + if(W.tool_behaviour == TOOL_WIRECUTTER) + . = TRUE + var/obj/item/stack/cable_coil/CC = new + CC.amount = 10 + CC.forceMove(loc) + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] cuts [src]'s wiring.", "You remove [src]'s wiring.") + else if(W.tool_behaviour == TOOL_SCREWDRIVER) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] screws on [src]'s wiring harnesses.", "You screw on [src]'s wiring harnesses.") + if(SPACEPOD_WIRES_SECURED) + if(W.tool_behaviour == TOOL_SCREWDRIVER) + . = TRUE + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] unclips [src]'s wiring harnesses.", "You unclip [src]'s wiring harnesses.") + else if(istype(W, /obj/item/circuitboard/mecha/pod)) + . = TRUE + if(user.canUnEquip(W)) + qdel(W) + construction_state++ + user.visible_message("[user] inserts the mainboard into [src].", "You insert the mainboard into [src].") + else + to_chat(user, "[W] is stuck to your hand!") + if(SPACEPOD_CIRCUIT_LOOSE) + if(W.tool_behaviour == TOOL_CROWBAR) + . = TRUE + W.play_tool_sound(src) + construction_state-- + var/obj/item/circuitboard/mecha/pod/B = new + B.forceMove(loc) + user.visible_message("[user] pries out the mainboard from [src].", "You pry out the mainboard from [src].") + else if(W.tool_behaviour == TOOL_SCREWDRIVER) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] secures the mainboard to [src].", "You secure the mainboard to [src].") + if(SPACEPOD_CIRCUIT_SECURED) + if(W.tool_behaviour == TOOL_SCREWDRIVER) + . = TRUE + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] unsecures the mainboard.", "You unscrew the mainboard from [src].") + else if(istype(W, /obj/item/pod_parts/core)) + . = TRUE + if(user.canUnEquip(W)) + qdel(W) + construction_state++ + user.visible_message("[user] inserts the core into [src].", "You carefully insert the core into [src].") + else + to_chat(user, "[W] is stuck to your hand!") + if(SPACEPOD_CORE_LOOSE) + if(W.tool_behaviour == TOOL_CROWBAR) + . = TRUE + W.play_tool_sound(src) + var/obj/item/pod_parts/core/C = new + C.forceMove(loc) + construction_state-- + user.visible_message("[user] delicately removes the core from [src].", "You delicately remove the core from [src].") + else if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] secures [src]'s core bolts.", "You secure [src]'s core bolts.") + if(SPACEPOD_CORE_SECURED) + if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] unsecures [src]'s core.", "You unsecure [src]'s core.") + else if(istype(W, /obj/item/stack/sheet/metal)) + . = TRUE + if(ST.use(5)) + user.visible_message("[user] fabricates a pressure bulkhead for [src].", "You frabricate a pressure bulkhead for [src].") + construction_state++ + else + to_chat(user, "You need 5 metal for this!") + if(SPACEPOD_BULKHEAD_LOOSE) + if(W.tool_behaviour == TOOL_CROWBAR) + . = TRUE + W.play_tool_sound(src) + construction_state-- + // RMNZ: Test this thing out + var/obj/item/stack/sheet/metal/M = new + M.amount = 5 + M.forceMove(loc) + user.visible_message("[user] pops [src]'s bulkhead panelling loose.", "You pop [src]'s bulkhead panelling loose.") + else if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] secures [src]'s bulkhead panelling.", "You secure [src]'s bulkhead panelling.") + if(SPACEPOD_BULKHEAD_SECURED) + if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] unbolts [src]'s bulkhead panelling.", "You unbolt [src]'s bulkhead panelling.") + else if(W.tool_behaviour == TOOL_WELDER) + . = TRUE + if(W.use_tool(src, user, 20, amount=3, volume = 50)) + construction_state = SPACEPOD_BULKHEAD_WELDED + user.visible_message("[user] seals [src]'s bulkhead panelling.", "You seal [src]'s bulkhead panelling.") + if(SPACEPOD_BULKHEAD_WELDED) + if(W.tool_behaviour == TOOL_WELDER) + . = TRUE + if(W.use_tool(src, user, 20, amount=3, volume = 50)) + construction_state = SPACEPOD_BULKHEAD_SECURED + user.visible_message("[user] cuts [src]'s bulkhead panelling loose.", "You cut [src]'s bulkhead panelling loose.") + if(istype(W, /obj/item/pod_parts/armor)) + . = TRUE + if(user.drop_item()) + W.forceMove() + add_armor(W) + construction_state++ + user.visible_message("[user] installs [src]'s armor plating.", "You install [src]'s armor plating.") + else + to_chat(user, "[W] is stuck to your hand!") + if(SPACEPOD_ARMOR_LOOSE) + if(W.tool_behaviour == TOOL_CROWBAR) + . = TRUE + if(pod_armor) + pod_armor.forceMove(loc) + remove_armor() + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] pries off [src]'s armor.", "You pry off [src]'s armor.") + if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] bolts down [src]'s armor.", "You bolt down [src]'s armor.") + if(SPACEPOD_ARMOR_SECURED) + if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] unsecures [src]'s armor.", "You unsecure [src]'s armor.") + else if(W.tool_behaviour == TOOL_WELDER) + . = TRUE + if(W.use_tool(src, user, 50, amount=3, volume = 50)) + construction_state = SPACEPOD_ARMOR_WELDED + user.visible_message("[user] welds [src]'s armor.", "You weld [src]'s armor.") + // finally this took too fucking long + // somehow this takes up 40 lines less code than the original, code-less version. And it actually works + update_appearance(UPDATE_ICON) diff --git a/code/modules/spacepods/spacepod_equipment.dm b/code/modules/spacepods/spacepod_equipment.dm new file mode 100644 index 000000000000..d1f35476329b --- /dev/null +++ b/code/modules/spacepods/spacepod_equipment.dm @@ -0,0 +1,379 @@ +/obj/item/spacepod_equipment + var/obj/spacepod/spacepod + icon = 'code/modules/spacepods/icons/parts.dmi' + var/slot = SPACEPOD_SLOT_MISC + var/slot_space = 1 + +/obj/item/spacepod_equipment/proc/on_install(obj/spacepod/SP) + spacepod = SP + SP.equipment |= src + forceMove(SP) + +/obj/item/spacepod_equipment/proc/on_uninstall() + spacepod.equipment -= src + +/obj/item/spacepod_equipment/proc/can_install(obj/spacepod/SP, mob/user) + var/room = SP.equipment_slot_limits[slot] || 0 + for(var/obj/item/spacepod_equipment/EQ in SP.equipment) + if(EQ.slot == slot) + room -= EQ.slot_space + if(room < slot_space) + to_chat(user, "There's no room for another [slot] system!") + return FALSE + return TRUE + +/obj/item/spacepod_equipment/proc/can_uninstall(mob/user) + return TRUE + +// RMNZ: Weapons doesn't work + +/* +/obj/item/spacepod_equipment/weaponry + slot = SPACEPOD_SLOT_WEAPON + var/projectile_type + var/shot_cost = 0 + var/shots_per = 1 + var/fire_sound + var/fire_delay = 15 + var/overlay_icon + var/overlay_icon_state + +/obj/item/spacepod_equipment/weaponry/on_install(obj/spacepod/SP) + . = ..() + SP.weapon = src + SP.update_appearance(UPDATE_ICON) + +/obj/item/spacepod_equipment/weaponry/on_uninstall() + . = ..() + if(spacepod.weapon == src) + spacepod.weapon = null + +/obj/item/spacepod_equipment/weaponry/proc/fire_weapons(target) + if(spacepod.next_firetime > world.time) + to_chat(usr, "Your weapons are recharging.") + playsound(src, 'sound/weapons/empty.ogg', 30, TRUE) + return + if(!spacepod.cell || !spacepod.cell.use(shot_cost)) + to_chat(usr, "Insufficient charge to fire the weapons") + playsound(src, 'sound/weapons/empty.ogg', 30, TRUE) + return + spacepod.next_firetime = world.time + fire_delay + for(var/I in 1 to shots_per) + spacepod.fire_projectiles(projectile_type, target) + playsound(src, fire_sound, 50, TRUE) + sleep(0.2 SECONDS) +*/ + +//////////////////////////// +////// Cargo System ////// +//////////////////////////// + +/obj/item/spacepod_equipment/cargo // this one holds large crates and shit + name = "pod cargo" + desc = "You shouldn't be seeing this" + icon_state = "cargo_blank" + slot = SPACEPOD_SLOT_CARGO + +// RMNZ: Doesn't work properly + +/* +/obj/item/spacepod_equipment/cargo/large + name = "spacepod crate storage system" + desc = "A heavy duty storage system for spacepods. Holds one crate." + icon_state = "cargo_crate" + var/obj/storage = null + var/storage_type = /obj/structure/closet/crate + +/obj/item/spacepod_equipment/cargo/large/on_install(obj/spacepod/SP) + ..() + // COMSIG - a way to make component signals sound more important than they actually are. + // it's not even limited to components. Does this look like a component to you? + // Okay here's a better name: It's a fucking *event handler*. Like the ones in javascript. + // a much more descriptive and less scary name than fucking "COMSIG". But noooooooooo + // the TG coders were too self important to pick a descriptive name and wanted to sound all scientific + RegisterSignal(SP, COMSIG_MOUSEDROPPED_ONTO, PROC_REF(spacepod_mousedrop)) + SP.verbs |= /obj/spacepod/proc/unload_cargo + +/obj/item/spacepod_equipment/cargo/large/on_uninstall() + UnregisterSignal(spacepod, COMSIG_MOUSEDROPPED_ONTO) + ..() + if(!(locate(/obj/item/spacepod_equipment/cargo/large) in spacepod.equipment)) + spacepod.verbs -= /obj/spacepod/proc/unload_cargo + +/obj/item/spacepod_equipment/cargo/large/can_uninstall(mob/user) + if(storage) + to_chat(user, "Unload the cargo first!") + return FALSE + return ..() + +/obj/spacepod/proc/unload_cargo() // if I could i'd put this on spacepod_equipment but unfortunately BYOND is stupid | RMNZ: What is this comment? Make this as action + set name = "Unload Cargo" + set category = "Spacepod" + set src = usr.loc + + if(!verb_check()) + return + + //var/used_key_list = list() + var/cargo_map = list() + for(var/obj/item/spacepod_equipment/cargo/large/E in equipment) + if(!E.storage) + continue + cargo_map[E.name] = E + var/selection = input(usr, "Unload which cargo?", null, null) as null|anything in cargo_map + var/obj/item/spacepod_equipment/cargo/large/E = cargo_map[selection] + if(!selection || !verb_check() || !E || !(E in equipment) || !E.storage) + return + E.storage.forceMove(loc) + E.storage = null + +/obj/item/spacepod_equipment/cargo/large/proc/spacepod_mousedrop(obj/spacepod/SP, obj/A, mob/user) + if(user == SP.pilot || (user in SP.passengers)) + return FALSE + if(istype(A, storage_type) && SP.Adjacent(A)) // For loading ore boxes + if(!storage) + to_chat(user, "You begin loading [A] into [SP]'s [src]") + if(do_after(user, 4 SECONDS, target = A)) + storage = A + A.forceMove(src) + to_chat(user, "You load [A] into [SP]'s [src]!") + else + to_chat(user, "You fail to load [A] into [SP]'s [src]") + else + to_chat(user, "[SP] already has \an [storage]") + return TRUE + return FALSE + +/obj/item/spacepod_equipment/cargo/large/ore //RMNZ: Can't load ore_box + name = "spacepod ore storage system" + desc = "An ore storage system for spacepods. Scoops up any ore you drive over. Needs to be loaded with an ore box to work" + icon_state = "cargo_ore" + storage_type = /obj/structure/ore_box + +/obj/item/spacepod_equipment/cargo/large/ore/on_install(obj/spacepod/SP) + ..() + RegisterSignal(SP, COMSIG_MOVABLE_MOVED, PROC_REF(spacepod_moved)) + +/obj/item/spacepod_equipment/cargo/large/ore/on_uninstall() + UnregisterSignal(spacepod, COMSIG_MOVABLE_MOVED) + ..() + +/obj/item/spacepod_equipment/cargo/large/ore/proc/spacepod_moved(obj/spacepod/SP) + if(storage) + for(var/turf/T in SP.locs) + for(var/obj/item/stack/ore in T) + ore.forceMove(storage) +*/ + +/obj/item/spacepod_equipment/cargo/chair + name = "passenger seat" + desc = "A passenger seat for a spacepod." + icon_state = "sec_cargo_chair" + var/occupant_mod = 1 + +/obj/item/spacepod_equipment/cargo/chair/on_install(obj/spacepod/SP) + ..() + SP.max_passengers += occupant_mod + +/obj/item/spacepod_equipment/cargo/chair/on_uninstall() + spacepod.max_passengers -= occupant_mod + ..() + +/obj/item/spacepod_equipment/cargo/chair/can_uninstall(mob/user) + if(spacepod.passengers.len > (spacepod.max_passengers - occupant_mod)) + to_chat(user, "You can't remove an occupied seat! Remove the occupant first.") + return FALSE + return ..() + +///////////////////////////// +////// Weapon System ////// +///////////////////////////// + +// RMNZ: Doesn't shoot (?) + +/* +/obj/item/spacepod_equipment/weaponry/disabler + name = "disabler system" + desc = "A weak disabler system for space pods, fires disabler beams." + icon_state = "weapon_taser" + projectile_type = /obj/item/projectile/beam/disabler + shot_cost = 400 + fire_sound = 'sound/weapons/taser2.ogg' + overlay_icon = 'code/modules/spacepods/icons/2x2.dmi' + overlay_icon_state = "pod_weapon_disabler" + +/obj/item/spacepod_equipment/weaponry/burst_disabler + name = "burst disabler system" + desc = "A weak disabler system for space pods, this one fires 3 at a time." + icon_state = "weapon_burst_taser" + projectile_type = /obj/item/projectile/beam/disabler + shot_cost = 1200 + shots_per = 3 + fire_sound = 'sound/weapons/taser2.ogg' + fire_delay = 30 + overlay_icon = 'code/modules/spacepods/icons/2x2.dmi' + overlay_icon_state = "pod_weapon_disabler" + +/obj/item/spacepod_equipment/weaponry/laser + name = "laser system" + desc = "A weak laser system for space pods, fires concentrated bursts of energy." + icon_state = "weapon_laser" + projectile_type = /obj/item/projectile/beam/laser + shot_cost = 600 + fire_sound = 'sound/weapons/Laser.ogg' + overlay_icon = 'code/modules/spacepods/icons/2x2.dmi' + overlay_icon_state = "pod_weapon_laser" + +// MINING LASERS +/obj/item/spacepod_equipment/weaponry/basic_pod_ka + name = "weak kinetic accelerator" + desc = "A weak kinetic accelerator for space pods, fires bursts of energy that cut through rock." + icon = 'goon/icons/obj/spacepods/parts.dmi' + icon_state = "pod_taser" + projectile_type = /obj/item/projectile/kinetic/pod + shot_cost = 300 + fire_delay = 14 + fire_sound = 'sound/weapons/Kenetic_accel.ogg' + +/obj/item/spacepod_equipment/weaponry/pod_ka + name = "kinetic accelerator system" + desc = "A kinetic accelerator system for space pods, fires bursts of energy that cut through rock." + icon = 'goon/icons/obj/spacepods/parts.dmi' + icon_state = "pod_m_laser" + projectile_type = /obj/item/projectile/kinetic/pod/regular + shot_cost = 250 + fire_delay = 10 + fire_sound = 'sound/weapons/Kenetic_accel.ogg' + +/obj/item/projectile/kinetic/pod + range = 4 + +/obj/item/projectile/kinetic/pod/regular + damage = 50 + pressure_decrease = 0.5 + +/obj/item/spacepod_equipment/weaponry/plasma_cutter + name = "plasma cutter system" + desc = "A plasma cutter system for space pods. It is capable of expelling concentrated plasma bursts to mine or cut off xeno limbs!" + icon = 'goon/icons/obj/spacepods/parts.dmi' + icon_state = "pod_p_cutter" + projectile_type = /obj/item/projectile/plasma + shot_cost = 250 + fire_delay = 10 + fire_sound = 'sound/weapons/plasma_cutter.ogg' + overlay_icon = 'code/modules/spacepods/icons/2x2.dmi' + overlay_icon_state = "pod_weapon_plasma" + +/obj/item/spacepod_equipment/weaponry/plasma_cutter/adv + name = "enhanced plasma cutter system" + desc = "An enhanced plasma cutter system for space pods. It is capable of expelling concentrated plasma bursts to mine or cut off xeno faces!" + icon_state = "pod_ap_cutter" + projectile_type = /obj/item/projectile/plasma/adv + shot_cost = 200 + fire_delay = 8 + +*/ +//////////////////////////// +////// Misc. System ////// +//////////////////////////// + +// RMNZ: No purpose (?) + +/* +/obj/item/spacepod_equipment/tracker + name = "spacepod tracking system" + desc = "A tracking device for spacepods." + icon = 'goon/icons/obj/spacepods/parts.dmi' + icon_state = "pod_locator" +*/ +/////////////////////////// +////// Lock System ////// +/////////////////////////// + +/obj/item/spacepod_equipment/lock + name = "pod lock" + desc = "You shouldn't be seeing this" + icon_state = "blank" + slot = SPACEPOD_SLOT_LOCK + +/obj/item/spacepod_equipment/lock/on_install(obj/spacepod/SP) + ..() + RegisterSignal(SP, COMSIG_PARENT_ATTACKBY, PROC_REF(spacepod_attackby)) + SP.lock = src + +/obj/item/spacepod_equipment/lock/on_uninstall() + UnregisterSignal(spacepod, COMSIG_PARENT_ATTACKBY) + if(spacepod.lock == src) + spacepod.lock = null + spacepod.locked = FALSE + ..() + +/obj/item/spacepod_equipment/lock/proc/spacepod_attackby(obj/spacepod/SP, I, mob/user) + return FALSE + +// Key and Tumbler System +/obj/item/spacepod_equipment/lock/keyed + name = "spacepod tumbler lock" + desc = "A locking system to stop podjacking. This version uses a standalone key." + icon_state = "lock_tumbler" + var/static/id_source = 0 + var/id = null + +/obj/item/spacepod_equipment/lock/keyed/Initialize(mapload) + . = ..() + if(id == null) + id = ++id_source + +/obj/item/spacepod_equipment/lock/keyed/spacepod_attackby(obj/spacepod/SP, obj/item/I, mob/user) + if(istype(I, /obj/item/spacepod_key)) + var/obj/item/spacepod_key/key = I + if(key.id == id) + SP.lock_pod() + return + else + to_chat(user, "This is the wrong key!") + return TRUE + return FALSE + +/obj/item/spacepod_equipment/lock/keyed/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/spacepod_key)) + var/obj/item/spacepod_key/key = I + if(key.id == null) + key.id = id + to_chat(user, "You grind the blank key to fit the lock.") + else + to_chat(user, "This key is already ground!") + else + ..() + +/obj/item/spacepod_equipment/lock/keyed/sec + id = "security spacepod" + +// The key +/obj/item/spacepod_key + name = "spacepod key" + desc = "A key for a spacepod lock." + icon = 'code/modules/spacepods/icons/parts.dmi' + icon_state = "podkey" + w_class = WEIGHT_CLASS_TINY + var/id = null + +/obj/item/spacepod_key/sec + name = "security spacepod key" + desc = "Unlocks the security spacepod. Probably best kept out of assistant hands." + id = "security spacepod" + +/obj/item/device/lock_buster + name = "pod lock buster" + desc = "Destroys a podlock in mere seconds once applied. Waranty void if used." + icon = 'code/modules/spacepods/icons/parts.dmi' + icon_state = "lock_buster_off" + var/on = FALSE + +/obj/item/device/lock_buster/attack_self(mob/user) + on = !on + if(on) + icon_state = "lock_buster_on" + else + icon_state = "lock_buster_off" + to_chat(user, "You turn the [src] [on ? "on" : "off"].") diff --git a/code/modules/spacepods/spacepod_parts.dm b/code/modules/spacepods/spacepod_parts.dm new file mode 100644 index 000000000000..32e098aa1aef --- /dev/null +++ b/code/modules/spacepods/spacepod_parts.dm @@ -0,0 +1,181 @@ +/obj/item/pod_parts + icon = 'goon/icons/obj/spacepods/parts.dmi' + w_class = WEIGHT_CLASS_GIGANTIC + flags = CONDUCT + +/obj/item/pod_parts/core + name = "space pod core" + icon_state = "core" + +/obj/item/pod_parts/pod_frame + name = "space pod frame" + density = FALSE + anchored = FALSE + var/link_to = null + var/link_angle = 0 + +/obj/item/pod_parts/pod_frame/attack_hand() + return + +/obj/item/pod_parts/pod_frame/Initialize(mapload) + . = ..() + AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE) + +/obj/item/pod_parts/pod_frame/proc/find_square() + /* + each part, in essence, stores the relative position of another part + you can find where this part should be by looking at the current direction of the current part and applying the link_angle + the link_angle is the angle between the part's direction and its following part, which is the current part's link_to + the code works by going in a loop - each part is capable of starting a loop by checking for the part after it, and that part checking, and so on + this 4-part loop, starting from any part of the frame, can determine if all the parts are properly in place and aligned + it also checks that each part is unique, and that all the parts are there for the spacepod itself + */ + //RMNZ: Addition of new pods + var/neededparts = list(/obj/item/pod_parts/pod_frame/aft_port, /obj/item/pod_parts/pod_frame/aft_starboard, /obj/item/pod_parts/pod_frame/fore_port, /obj/item/pod_parts/pod_frame/fore_starboard) + var/turf/T + var/obj/item/pod_parts/pod_frame/linked + var/obj/item/pod_parts/pod_frame/pointer + var/list/connectedparts = list() + neededparts -= src + linked = src + for(var/i = 1; i <= 4; i++) + T = get_turf(get_step(linked, turn(linked.dir, -linked.link_angle))) //get the next place that we want to look at + if(locate(linked.link_to) in T) + pointer = locate(linked.link_to) in T + if(istype(pointer, linked.link_to) && pointer.dir == linked.dir && pointer.anchored) + if(!(pointer in connectedparts)) + connectedparts += pointer + linked = pointer + pointer = null + if(connectedparts.len < 4) + return FALSE + for(var/i = 1; i <=4; i++) + var/obj/item/pod_parts/pod_frame/F = connectedparts[i] + if(F.type in neededparts) //if one of the items can be founded in neededparts + neededparts -= F.type + else //because neededparts has 4 distinct items, this must be called if theyre not all in place and wrenched + return FALSE + return connectedparts + +/obj/item/pod_parts/pod_frame/attackby(obj/item/O, mob/user) + if(istype(O, /obj/item/stack/rods)) + var/obj/item/stack/rods/R = O + var/list/linkedparts = find_square() + if(!linkedparts) + to_chat(user, "You cannot assemble a pod frame because you do not have the necessary assembly.") + return TRUE + if(!R.use(10)) + to_chat(user, "You need 10 rods for this.") + return TRUE + var/obj/spacepod/pod = new + pod.forceMove(loc) + switch(dir) + if(NORTH) + pod.angle = 0 + if(SOUTH) + pod.angle = 180 + if(WEST) + pod.angle = 270 + if(EAST) + pod.angle = 90 + pod.process(2) + to_chat(user, "You strut the pod frame together.") + for(var/obj/item/pod_parts/pod_frame/F in linkedparts) + if(1 == turn(F.dir, -F.link_angle)) //if the part links north during construction, as the bottom left part always does + pod.forceMove(F.loc) + qdel(F) + return TRUE + if(O.tool_behaviour == TOOL_WRENCH) + to_chat(user, "You [!anchored ? "secure \the [src] in place." : "remove the securing bolts."]") + anchored = !anchored + density = anchored + O.play_tool_sound(src) + return TRUE + +/obj/item/pod_parts/pod_frame/fore_port + name = "fore port pod frame" + icon_state = "pod_fp" + desc = "A space pod frame component. This is the fore port component." + link_to = /obj/item/pod_parts/pod_frame/fore_starboard + link_angle = 90 + +/obj/item/pod_parts/pod_frame/fore_starboard + name = "fore starboard pod frame" + icon_state = "pod_fs" + desc = "A space pod frame component. This is the fore starboard component." + link_to = /obj/item/pod_parts/pod_frame/aft_starboard + link_angle = 180 + +/obj/item/pod_parts/pod_frame/aft_port + name = "aft port pod frame" + icon_state = "pod_ap" + desc = "A space pod frame component. This is the aft port component." + link_to = /obj/item/pod_parts/pod_frame/fore_port + link_angle = 0 + +/obj/item/pod_parts/pod_frame/aft_starboard + name = "aft starboard pod frame" + icon_state = "pod_as" + desc = "A space pod frame component. This is the aft starboard component." + link_to = /obj/item/pod_parts/pod_frame/aft_port + link_angle = 270 + +/obj/item/pod_parts/armor + name = "civilian pod armor" + icon_state = "pod_armor_civ" + desc = "Spacepod armor. This is the civilian version. It looks rather flimsy." + var/pod_icon = 'goon/icons/obj/spacepods/2x2.dmi' + var/pod_icon_state = "pod_civ" + var/pod_desc = "A sleek civilian space pod." + var/pod_integrity = 250 + +/obj/item/pod_parts/armor/syndicate + name = "syndicate pod armor" + icon_state = "pod_armor_synd" + desc = "Tough-looking spacepod armor, with a bold \"FUCK NT\" stenciled directly into it." + pod_icon_state = "pod_synd" + pod_desc = "A menacing military space pod with \"FUCK NT\" stenciled onto the side" + pod_integrity = 400 + +/obj/item/pod_parts/armor/black + name = "black pod armor" + icon_state = "pod_armor_black" + desc = "Plain black spacepod armor, with no logos or insignias anywhere on it." + pod_icon_state = "pod_black" + pod_desc = "An all black space pod with no insignias." + +/obj/item/pod_parts/armor/gold + name = "golden pod armor" + icon_state = "pod_armor_gold" + desc = "Golden spacepod armor. Looks like what a rich spessmen put on their spacepod." + pod_icon_state = "pod_gold" + pod_desc = "A civilian space pod with a gold body, must have cost somebody a pretty penny" + pod_integrity = 220 + +/obj/item/pod_parts/armor/industrial + name = "industrial pod armor" + icon_state = "pod_armor_industrial" + desc = "Tough industrial-grade spacepod armor. While meant for construction work, it is commonly used in spacepod battles, too." + pod_icon_state = "pod_industrial" + pod_desc = "A rough looking space pod meant for industrial work" + pod_integrity = 330 + +/obj/item/pod_parts/armor/security + name = "security pod armor" + icon_state = "pod_armor_mil" + desc = "Tough military-grade pod armor, meant for use by the Nanotrasen military and it's sub-divisons for space combat." + pod_icon_state = "pod_mil" + pod_desc = "An armed security spacepod with reinforced armor plating brandishing the Nanotrasen Military insignia" + pod_integrity = 350 + +/obj/item/pod_parts/armor/security/red + name = "security pod armor" + icon_state = "pod_armor_synd" + desc = "Tough military-grade pod armor, meant for use by the Nanotrasen military and it's sub-divisons for space combat." + pod_icon_state = "pod_synd" + pod_desc = "An armed security spacepod with reinforced armor plating brandishing the Nanotrasen Military insignia" + pod_integrity = 350 + +/obj/item/circuitboard/mecha/pod + name = "Circuit board (Space Pod Mainboard)" + icon_state = "mainboard" diff --git a/code/modules/spacepods/spacepod_physics.dm b/code/modules/spacepods/spacepod_physics.dm new file mode 100644 index 000000000000..0330050dd381 --- /dev/null +++ b/code/modules/spacepods/spacepod_physics.dm @@ -0,0 +1,297 @@ +/obj/spacepod/process(time) + + if(world.time > last_slowprocess + 15) + last_slowprocess = world.time + slowprocess() + + var/last_offset_x = offset_x + var/last_offset_y = offset_y + var/last_angle = angle + var/desired_angular_velocity = 0 + if(isnum(desired_angle)) + // do some finagling to make sure that our angles end up rotating the short way + while(angle > desired_angle + 180) + angle -= 360 + last_angle -= 360 + while(angle < desired_angle - 180) + angle += 360 + last_angle += 360 + if(abs(desired_angle - angle) < (max_angular_acceleration * time)) + desired_angular_velocity = (desired_angle - angle) / time + else if(desired_angle > angle) + desired_angular_velocity = 2 * sqrt((desired_angle - angle) * max_angular_acceleration * 0.25) + else + desired_angular_velocity = -2 * sqrt((angle - desired_angle) * max_angular_acceleration * 0.25) + var/angular_velocity_adjustment = clamp(desired_angular_velocity - angular_velocity, -max_angular_acceleration*time, max_angular_acceleration*time) + if(angular_velocity_adjustment && cell && cell.use(abs(angular_velocity_adjustment) * 0.05)) + last_rotate = angular_velocity_adjustment / time + angular_velocity += angular_velocity_adjustment + else + last_rotate = 0 + angle += angular_velocity * time + + // calculate drag and shit + + var/velocity_mag = sqrt(velocity_x*velocity_x+velocity_y*velocity_y) // magnitude + if(velocity_mag || angular_velocity) + var/drag = 0 + for(var/turf/T in locs) + if(isspaceturf(T)) + continue + drag += 0.001 + var/floating = FALSE + if(has_gravity() && !brakes && velocity_mag > 0.1 && cell && cell.use((is_mining_level(z) ? 3 : 15) * time)) + floating = TRUE // want to fly this shit on the station? Have fun draining your battery. + if((!floating && has_gravity()) || brakes) // brakes are a kind of magboots okay? + drag += is_mining_level(z) ? 0.1 : 0.5 // some serious drag. Damn. Except lavaland, it has less gravity or something + if(velocity_mag > 5 && prob(velocity_mag * 4) && istype(T, /turf/simulated/floor)) + var/turf/simulated/floor/TF = T + TF.make_plating() // pull up some floor tiles. Stop going so fast, ree. + take_damage(3, BRUTE, MELEE, FALSE) + var/datum/gas_mixture/env = T.return_air() + if(env) + var/pressure = env.return_pressure() + drag += velocity_mag * pressure * 0.0001 // 1 atmosphere should shave off 1% of velocity per tile + if(velocity_mag > 20) + drag = max(drag, (velocity_mag - 20) / time) + if(drag) + if(velocity_mag) + var/drag_factor = 1 - clamp(drag * time / velocity_mag, 0, 1) + velocity_x *= drag_factor + velocity_y *= drag_factor + if(angular_velocity != 0) + var/drag_factor_spin = 1 - clamp(drag * 30 * time / abs(angular_velocity), 0, 1) + angular_velocity *= drag_factor_spin + + // Alright now calculate the THRUST + var/thrust_x + var/thrust_y + var/fx = cos(90 - angle) + var/fy = sin(90 - angle) + var/sx = fy + var/sy = -fx + last_thrust_forward = 0 + last_thrust_right = 0 + if(brakes) + if(user_thrust_dir) + to_chat(pilot, "Your brakes are on!") + // basically calculates how much we can brake using the thrust + var/forward_thrust = -((fx * velocity_x) + (fy * velocity_y)) / time + var/right_thrust = -((sx * velocity_x) + (sy * velocity_y)) / time + forward_thrust = clamp(forward_thrust, -backward_maxthrust, forward_maxthrust) + right_thrust = clamp(right_thrust, -side_maxthrust, side_maxthrust) + thrust_x += forward_thrust * fx + right_thrust * sx; + thrust_y += forward_thrust * fy + right_thrust * sy; + last_thrust_forward = forward_thrust + last_thrust_right = right_thrust + else // want some sort of help piloting the ship? Haha no fuck you do it yourself + if(user_thrust_dir & NORTH) + thrust_x += fx * forward_maxthrust + thrust_y += fy * forward_maxthrust + last_thrust_forward = forward_maxthrust + if(user_thrust_dir & SOUTH) + thrust_x -= fx * backward_maxthrust + thrust_y -= fy * backward_maxthrust + last_thrust_forward = -backward_maxthrust + if(user_thrust_dir & EAST) + thrust_x += sx * side_maxthrust + thrust_y += sy * side_maxthrust + last_thrust_right = side_maxthrust + if(user_thrust_dir & WEST) + thrust_x -= sx * side_maxthrust + thrust_y -= sy * side_maxthrust + last_thrust_right = -side_maxthrust + + if(cell && cell.use(10 * sqrt((thrust_x*thrust_x)+(thrust_y*thrust_y)) * time)) + velocity_x += thrust_x * time + velocity_y += thrust_y * time + else + last_thrust_forward = 0 + last_thrust_right = 0 + if(!brakes && user_thrust_dir) + to_chat(pilot, "You are out of power!") + + offset_x += velocity_x * time + offset_y += velocity_y * time + // alright so now we reconcile the offsets with the in-world position. + while((offset_x > 0 && velocity_x > 0) || (offset_y > 0 && velocity_y > 0) || (offset_x < 0 && velocity_x < 0) || (offset_y < 0 && velocity_y < 0)) + var/failed_x = FALSE + var/failed_y = FALSE + if(offset_x > 0 && velocity_x > 0) + dir = EAST + if(!Move(get_step(src, EAST))) + offset_x = 0 + failed_x = TRUE + velocity_x *= -bounce_factor + velocity_y *= lateral_bounce_factor + else + offset_x-- + last_offset_x-- + else if(offset_x < 0 && velocity_x < 0) + dir = WEST + if(!Move(get_step(src, WEST))) + offset_x = 0 + failed_x = TRUE + velocity_x *= -bounce_factor + velocity_y *= lateral_bounce_factor + else + offset_x++ + last_offset_x++ + else + failed_x = TRUE + if(offset_y > 0 && velocity_y > 0) + dir = NORTH + if(!Move(get_step(src, NORTH))) + offset_y = 0 + failed_y = TRUE + velocity_y *= -bounce_factor + velocity_x *= lateral_bounce_factor + else + offset_y-- + last_offset_y-- + else if(offset_y < 0 && velocity_y < 0) + dir = SOUTH + if(!Move(get_step(src, SOUTH))) + offset_y = 0 + failed_y = TRUE + velocity_y *= -bounce_factor + velocity_x *= lateral_bounce_factor + else + offset_y++ + last_offset_y++ + else + failed_y = TRUE + if(failed_x && failed_y) + break + // prevents situations where you go "wtf I'm clearly right next to it" as you enter a stationary spacepod + if(velocity_x == 0) + if(offset_x > 0.5) + if(Move(get_step(src, EAST))) + offset_x-- + last_offset_x-- + else + offset_x = 0 + if(offset_x < -0.5) + if(Move(get_step(src, WEST))) + offset_x++ + last_offset_x++ + else + offset_x = 0 + if(velocity_y == 0) + if(offset_y > 0.5) + if(Move(get_step(src, NORTH))) + offset_y-- + last_offset_y-- + else + offset_y = 0 + if(offset_y < -0.5) + if(Move(get_step(src, SOUTH))) + offset_y++ + last_offset_y++ + else + offset_y = 0 + dir = NORTH + var/matrix/mat_from = new() + mat_from.Turn(last_angle) + var/matrix/mat_to = new() + mat_to.Turn(angle) + transform = mat_from + pixel_x = last_offset_x*32 + pixel_y = last_offset_y*32 + animate(src, transform=mat_to, pixel_x = offset_x*32, pixel_y = offset_y*32, time = time SECONDS, flags=ANIMATION_END_NOW) + for(var/mob/living/M in contents) + var/client/C = M.client + if(!C) + continue + C.pixel_x = last_offset_x*32 + C.pixel_y = last_offset_y*32 + animate(C, pixel_x = offset_x*32, pixel_y = offset_y*32, time = time SECONDS, flags=ANIMATION_END_NOW) + user_thrust_dir = 0 + update_appearance(UPDATE_ICON) + +/obj/spacepod/Bumped(atom/movable/A) // RMNZ: Thrown items or pushable objects slightly move pods though + if(ismob(A)) // I don't like it when little silly humans can move these pods + return + if(A.dir & NORTH) + velocity_y += bump_impulse + if(A.dir & SOUTH) + velocity_y -= bump_impulse + if(A.dir & EAST) + velocity_x += bump_impulse + if(A.dir & WEST) + velocity_x -= bump_impulse + return ..() + +/obj/spacepod/Bump(atom/A) + var/bump_velocity = 0 + if(dir & (NORTH|SOUTH)) + bump_velocity = abs(velocity_y) + (abs(velocity_x) / 15) + else + bump_velocity = abs(velocity_x) + (abs(velocity_y) / 15) + if(istype(A, /obj/machinery/door/airlock)) // try to open doors + var/obj/machinery/door/D = A + if(!D.operating) + if(D.allowed(D.requiresID() ? pilot : null)) + spawn(0) + D.open() + else + D.do_animate("deny") + var/atom/movable/AM = A + if(istype(AM) && !AM.anchored && bump_velocity > 1) + step(AM, dir) + // if a bump is that fast then it's not a bump. It's a collision. + if(bump_velocity > 10 && !ismob(A)) + var/strength = bump_velocity / 10 + strength = strength * strength + strength = min(strength, 5) // don't want the explosions *too* big + // wew lad, might wanna slow down there + explosion(A, -1, round((strength - 1) / 2), round(strength)) + message_admins("[key_name_admin(pilot)] has impacted a spacepod into [A] with velocity [bump_velocity]") + take_damage(strength*10, BRUTE, MELEE, TRUE) + log_game("[key_name(pilot)] has impacted a spacepod into [A] with velocity [bump_velocity]") + visible_message("The force of the impact causes a shockwave") + else if(isliving(A) && bump_velocity > 5) + var/mob/living/M = A + M.apply_damage(bump_velocity * 2) + take_damage(bump_velocity, BRUTE, MELEE, FALSE) + playsound(M.loc, "swing_hit", 1000, 1, -1) + M.KnockOut() + M.visible_message("The force of the impact knocks [M] down!", "The force of the impact knocks you down!") + add_attack_logs(pilot, M, "impacted", src, "with velocity of [bump_velocity]") + return ..() + +/obj/spacepod/proc/fire_projectiles(proj_type, target) // if spacepods of other sizes are added override this or something + var/fx = cos(90 - angle) + var/fy = sin(90 - angle) + var/sx = fy + var/sy = -fx + var/ox = (offset_x * 32) + 16 + var/oy = (offset_y * 32) + 16 + var/list/origins = list(list(ox + fx*16 - sx*16, oy + fy*16 - sy*16), list(ox + fx*16 + sx*16, oy + fy*16 + sy*16)) + for(var/list/origin in origins) + var/this_x = origin[1] + var/this_y = origin[2] + var/turf/T = get_turf(src) + while(this_x > 16) + T = get_step(T, EAST) + this_x -= 32 + while(this_x < -16) + T = get_step(T, WEST) + this_x += 32 + while(this_y > 16) + T = get_step(T, NORTH) + this_y -= 32 + while(this_y < -16) + T = get_step(T, SOUTH) + this_y += 32 + if(!T) + continue + var/obj/item/projectile/proj = new proj_type(T) + proj.starting = T + proj.firer = usr + proj.def_zone = "chest" + proj.original = target + proj.pixel_x = round(this_x) + proj.pixel_y = round(this_y) + spawn() + proj.fire(angle) diff --git a/code/modules/spacepods/spacepod_prebuilt.dm b/code/modules/spacepods/spacepod_prebuilt.dm new file mode 100644 index 000000000000..c1b42bb1a5ab --- /dev/null +++ b/code/modules/spacepods/spacepod_prebuilt.dm @@ -0,0 +1,64 @@ +/obj/spacepod/prebuilt + icon = 'goon/icons/obj/spacepods/2x2.dmi' + icon_state = "pod_civ" + var/cell_type = /obj/item/stock_parts/cell/high/plus + var/armor_type = /obj/item/pod_parts/armor + var/internal_tank_type = /obj/machinery/atmospherics/portable/canister/air + var/equipment_types = list() + construction_state = SPACEPOD_ARMOR_WELDED + +/obj/spacepod/prebuilt/Initialize(mapload) + . =..() + add_armor(new armor_type(src)) + if(cell_type) + cell = new cell_type(src) + if(internal_tank_type) + internal_tank = new internal_tank_type(src) + for(var/equip in equipment_types) + var/obj/item/spacepod_equipment/SE = new equip(src) + SE.on_install(src) + +/obj/spacepod/prebuilt/sec + name = "security space pod" + icon_state = "pod_mil" + locked = TRUE + armor_type = /obj/item/pod_parts/armor/security + equipment_types = list(/obj/item/spacepod_equipment/weaponry/disabler, + /obj/item/spacepod_equipment/lock/keyed/sec, + /obj/item/spacepod_equipment/tracker, + /obj/item/spacepod_equipment/cargo/chair) + +// adminbus spacepod for jousting events +/obj/spacepod/prebuilt/jousting + name = "jousting space pod" + icon_state = "pod_mil" + armor_type = /obj/item/pod_parts/armor/security + cell_type = /obj/item/stock_parts/cell/infinite + equipment_types = list(/obj/item/spacepod_equipment/weaponry/laser, + /obj/item/spacepod_equipment/cargo/chair, + /obj/item/spacepod_equipment/cargo/chair) + +/obj/spacepod/prebuilt/jousting/red + icon_state = "pod_synd" + armor_type = /obj/item/pod_parts/armor/security/red + +/obj/spacepod/random + icon = 'goon/icons/obj/spacepods/2x2.dmi' + icon_state = "pod_civ" + construction_state = SPACEPOD_ARMOR_WELDED + +/obj/spacepod/random/Initialize(mapload) + . = ..() + var/armor_type = pick(/obj/item/pod_parts/armor, + /obj/item/pod_parts/armor/syndicate, + /obj/item/pod_parts/armor/black, + /obj/item/pod_parts/armor/gold, + /obj/item/pod_parts/armor/industrial, + /obj/item/pod_parts/armor/security) + add_armor(new armor_type(src)) + cell = new /obj/item/stock_parts/cell/high/empty(src) + internal_tank = new /obj/machinery/atmospherics/portable/canister/air(src) + velocity_x = rand(-3, 3) + velocity_y = rand(-3, 3) + obj_integrity = rand(100, max_integrity) + brakes = FALSE diff --git a/goon/icons/obj/spacepods/2x2.dmi b/goon/icons/obj/spacepods/2x2.dmi new file mode 100644 index 0000000000000000000000000000000000000000..02def41cf1bc43bf9a86c41adc898a1f16504cde GIT binary patch literal 7679 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 XjZR|H`S literal 0 HcmV?d00001 diff --git a/paradise.dme b/paradise.dme index bb26fe9f3eaf..daa8787dd3ff 100644 --- a/paradise.dme +++ b/paradise.dme @@ -98,6 +98,7 @@ #include "code\__DEFINES\rolebans.dm" #include "code\__DEFINES\rust_g.dm" #include "code\__DEFINES\shuttle_defines.dm" +#include "code\__DEFINES\spacepods.dm" #include "code\__DEFINES\sight.dm" #include "code\__DEFINES\sound_defines.dm" #include "code\__DEFINES\spell_defines.dm" @@ -316,6 +317,7 @@ #include "code\controllers\subsystem\processing\fields.dm" #include "code\controllers\subsystem\processing\instruments.dm" #include "code\controllers\subsystem\processing\obj.dm" +#include "code\controllers\subsystem\processing\spacepods.dm" #include "code\controllers\subsystem\processing\processing.dm" #include "code\controllers\subsystem\processing\projectiles.dm" #include "code\controllers\subsystem\processing\SSstation.dm" @@ -394,6 +396,7 @@ #include "code\datums\components\paintable.dm" #include "code\datums\components\parry.dm" #include "code\datums\components\persistent_overlay.dm" +#include "code\datums\components\rotation.dm" #include "code\datums\components\proximity_monitor.dm" #include "code\datums\components\radioactive.dm" #include "code\datums\components\shielded.dm" @@ -2636,6 +2639,7 @@ #include "code\modules\research\designs\mining_designs.dm" #include "code\modules\research\designs\misc_designs.dm" #include "code\modules\research\designs\modsuit_designs.dm" +#include "code\modules\research\designs\spacepod_designs.dm" #include "code\modules\research\designs\power_designs.dm" #include "code\modules\research\designs\smelting_designs.dm" #include "code\modules\research\designs\stock_parts_designs.dm" @@ -2678,9 +2682,16 @@ #include "code\modules\shuttle\syndicate_shuttles.dm" #include "code\modules\space_management\heap_space_level.dm" #include "code\modules\space_management\level_check.dm" +#include "code\modules\spacepods\spacepod_actions.dm" #include "code\modules\space_management\level_traits.dm" #include "code\modules\space_management\space_chunk.dm" #include "code\modules\space_management\space_level.dm" +#include "code\modules\spacepods\spacepod_equipment.dm" +#include "code\modules\spacepods\spacepod_parts.dm" +#include "code\modules\spacepods\spacepod.dm" +#include "code\modules\spacepods\spacepod_construction.dm" +#include "code\modules\spacepods\spacepod_physics.dm" +#include "code\modules\spacepods\spacepod_prebuilt.dm" #include "code\modules\space_management\space_transition.dm" #include "code\modules\space_management\zlevel_manager.dm" #include "code\modules\station_goals\bluespace_tap.dm" From 19c1aa47e22dfff735067f2bab17ccf86fe78477 Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Fri, 2 Feb 2024 20:35:59 +0800 Subject: [PATCH 02/28] Spacepods? --- code/__DEFINES/is_helpers.dm | 2 + code/__DEFINES/layers.dm | 1 + code/__DEFINES/spacepods.dm | 18 + code/__HELPERS/lists.dm | 2 + code/_onclick/drag_drop.dm | 13 + code/_onclick/hud/map_popups.dm | 7 + .../subsystem/processing/spacepods.dm | 12 + code/datums/components/rotation.dm | 166 +++++ code/game/objects/items/stacks/rods.dm | 7 + .../mob/living/carbon/human/human_mob.dm | 9 + code/modules/mob/living/living.dm | 4 + code/modules/mob/mob_vars.dm | 6 + .../modules/research/designs/mecha_designs.dm | 11 + .../research/designs/spacepod_designs.dm | 241 ++++++ code/modules/research/protolathe.dm | 3 +- code/modules/spacepods/icons/2x2.dmi | Bin 0 -> 1085 bytes .../spacepods/icons/actions_spacepod.dmi | Bin 0 -> 1828 bytes code/modules/spacepods/icons/parts.dmi | Bin 0 -> 4712 bytes code/modules/spacepods/spacepod.dm | 691 ++++++++++++++++++ code/modules/spacepods/spacepod_actions.dm | 122 ++++ .../spacepods/spacepod_construction.dm | 206 ++++++ code/modules/spacepods/spacepod_equipment.dm | 379 ++++++++++ code/modules/spacepods/spacepod_parts.dm | 181 +++++ code/modules/spacepods/spacepod_physics.dm | 297 ++++++++ code/modules/spacepods/spacepod_prebuilt.dm | 64 ++ goon/icons/obj/spacepods/2x2.dmi | Bin 0 -> 7679 bytes goon/icons/obj/spacepods/construction_2x2.dmi | Bin 0 -> 5631 bytes goon/icons/obj/spacepods/parts.dmi | Bin 0 -> 5007 bytes paradise.dme | 11 + 29 files changed, 2452 insertions(+), 1 deletion(-) create mode 100644 code/__DEFINES/spacepods.dm create mode 100644 code/controllers/subsystem/processing/spacepods.dm create mode 100644 code/datums/components/rotation.dm create mode 100644 code/modules/research/designs/spacepod_designs.dm create mode 100644 code/modules/spacepods/icons/2x2.dmi create mode 100644 code/modules/spacepods/icons/actions_spacepod.dmi create mode 100644 code/modules/spacepods/icons/parts.dmi create mode 100644 code/modules/spacepods/spacepod.dm create mode 100644 code/modules/spacepods/spacepod_actions.dm create mode 100644 code/modules/spacepods/spacepod_construction.dm create mode 100644 code/modules/spacepods/spacepod_equipment.dm create mode 100644 code/modules/spacepods/spacepod_parts.dm create mode 100644 code/modules/spacepods/spacepod_physics.dm create mode 100644 code/modules/spacepods/spacepod_prebuilt.dm create mode 100644 goon/icons/obj/spacepods/2x2.dmi create mode 100644 goon/icons/obj/spacepods/construction_2x2.dmi create mode 100644 goon/icons/obj/spacepods/parts.dmi diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index e73af05c7d61..fa918c4d41f9 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -52,6 +52,8 @@ #define ismecha(A) (istype(A, /obj/mecha)) +#define isspacepod(A) (istype(A, /obj/spacepod)) + #define iseffect(A) (istype(A, /obj/effect)) #define isclothing(A) (istype(A, /obj/item/clothing)) diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index 9e475ab6e9e0..55754bbba5f9 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -73,6 +73,7 @@ #define BELOW_MOB_LAYER 3.7 #define LYING_MOB_LAYER 3.8 +#define SPACEPOD_LAYER 3.9 // yogs //#define MOB_LAYER 4 //For easy recordkeeping; this is a byond define #define ABOVE_MOB_LAYER 4.1 #define HITSCAN_LAYER 4.2 diff --git a/code/__DEFINES/spacepods.dm b/code/__DEFINES/spacepods.dm new file mode 100644 index 000000000000..a4bfbd5abf88 --- /dev/null +++ b/code/__DEFINES/spacepods.dm @@ -0,0 +1,18 @@ +#define SPACEPOD_EMPTY 1 +#define SPACEPOD_WIRES_LOOSE 2 +#define SPACEPOD_WIRES_SECURED 3 +#define SPACEPOD_CIRCUIT_LOOSE 4 +#define SPACEPOD_CIRCUIT_SECURED 5 +#define SPACEPOD_CORE_LOOSE 6 +#define SPACEPOD_CORE_SECURED 7 +#define SPACEPOD_BULKHEAD_LOOSE 8 +#define SPACEPOD_BULKHEAD_SECURED 9 +#define SPACEPOD_BULKHEAD_WELDED 10 +#define SPACEPOD_ARMOR_LOOSE 11 +#define SPACEPOD_ARMOR_SECURED 12 +#define SPACEPOD_ARMOR_WELDED 13 + +#define SPACEPOD_SLOT_CARGO "cargo" +#define SPACEPOD_SLOT_MISC "misc" +#define SPACEPOD_SLOT_WEAPON "weapon" +#define SPACEPOD_SLOT_LOCK "lock" diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index cf6642875ffa..d04d7ebc28e3 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -696,6 +696,8 @@ ///If the lazy list is currently initialized find item I in list L #define LAZYIN(L, I) (L && (I in L)) +#define LAZYOR(L, I) if(!L) { L = list(); } L |= I; + //same, but returns nothing and acts on list in place /proc/shuffle_inplace(list/L) if(!L) diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm index 5d7d41143320..90af86729836 100644 --- a/code/_onclick/drag_drop.dm +++ b/code/_onclick/drag_drop.dm @@ -48,3 +48,16 @@ to inform the game this action was expected and its fine */ /atom/proc/MouseDrop_T(atom/dropping, mob/user, params) // return TRUE if you want to prevent us click the object after it return + +/client/MouseMove(object,location,control,params) + mouseParams = params + mouse_location_ref = location + mouse_object_ref = object + mouseControlObject = control + if(mob && LAZYLEN(mob.mousemove_intercept_objects)) + for(var/datum/D in mob.mousemove_intercept_objects) + D.onMouseMove(object, location, control, params) + ..() + +/datum/proc/onMouseMove(object, location, control, params) + return diff --git a/code/_onclick/hud/map_popups.dm b/code/_onclick/hud/map_popups.dm index dc9e255cba93..9c2bc9b148ce 100644 --- a/code/_onclick/hud/map_popups.dm +++ b/code/_onclick/hud/map_popups.dm @@ -7,6 +7,13 @@ */ var/list/screen_maps = list() + var/mouseParams = "" + ///Used in MouseDrag to preserve the last mouse-entered location + var/datum/mouse_location_ref = null + ///Used in MouseDrag to preserve the last mouse-entered object + var/datum/mouse_object_ref + var/mouseControlObject = null + /obj/screen /** * Map name assigned to this object. diff --git a/code/controllers/subsystem/processing/spacepods.dm b/code/controllers/subsystem/processing/spacepods.dm new file mode 100644 index 000000000000..036beea2fa4d --- /dev/null +++ b/code/controllers/subsystem/processing/spacepods.dm @@ -0,0 +1,12 @@ +// Yogstation use fastprocess subsystem but for Paradise it causes +// movement lag (updates, like it should, 5 times / second). +// This wait time (0.075) is the closest (and laziest) I could get to +// Yogstation's movement speed + +// RMNZ: Maybe performance issues? + +PROCESSING_SUBSYSTEM_DEF(spacepods) + name = "Spacepods" + wait = 0.075 + stat_tag = "SP" + offline_implications = "Spacepods will no longer process. Shuttle call recommended." diff --git a/code/datums/components/rotation.dm b/code/datums/components/rotation.dm new file mode 100644 index 000000000000..fc023da258cb --- /dev/null +++ b/code/datums/components/rotation.dm @@ -0,0 +1,166 @@ +//RMNZ: Please, check if this component is really needed or not +#define ROTATION_ALTCLICK (1<<0) +#define ROTATION_WRENCH (1<<1) +#define ROTATION_VERBS (1<<2) +#define ROTATION_COUNTERCLOCKWISE (1<<3) +#define ROTATION_CLOCKWISE (1<<4) +#define ROTATION_FLIP (1<<5) + +/datum/component/simple_rotation + var/datum/callback/can_user_rotate //Checks if user can rotate + var/datum/callback/can_be_rotated //Check if object can be rotated at all + var/datum/callback/after_rotation //Additional stuff to do after rotation + + var/rotation_flags = NONE + var/default_rotation_direction = ROTATION_CLOCKWISE + +/datum/component/simple_rotation/Initialize(rotation_flags = NONE, can_user_rotate, can_be_rotated, after_rotation) + if(!ismovable(parent)) + return COMPONENT_INCOMPATIBLE + + //throw if no rotation direction is specificed ? + + src.rotation_flags = rotation_flags + + if(can_user_rotate) + src.can_user_rotate = can_user_rotate + else + src.can_user_rotate = CALLBACK(src, PROC_REF(default_can_user_rotate)) + + if(can_be_rotated) + src.can_be_rotated = can_be_rotated + else + src.can_be_rotated = CALLBACK(src, PROC_REF(default_can_be_rotated)) + + if(after_rotation) + src.after_rotation = after_rotation + else + src.after_rotation = CALLBACK(src, PROC_REF(default_after_rotation)) + + //Try Clockwise,counter,flip in order + if(src.rotation_flags & ROTATION_FLIP) + default_rotation_direction = ROTATION_FLIP + if(src.rotation_flags & ROTATION_COUNTERCLOCKWISE) + default_rotation_direction = ROTATION_COUNTERCLOCKWISE + if(src.rotation_flags & ROTATION_CLOCKWISE) + default_rotation_direction = ROTATION_CLOCKWISE + +/datum/component/simple_rotation/proc/add_signals() + if(rotation_flags & ROTATION_ALTCLICK) + RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(HandRot)) + RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(ExamineMessage)) + if(rotation_flags & ROTATION_WRENCH) + RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, PROC_REF(WrenchRot)) + +/datum/component/simple_rotation/proc/add_verbs() + if(rotation_flags & ROTATION_VERBS) + var/atom/movable/AM = parent + if(rotation_flags & ROTATION_FLIP) + AM.verbs += /atom/movable/proc/simple_rotate_flip + if(src.rotation_flags & ROTATION_CLOCKWISE) + AM.verbs += /atom/movable/proc/simple_rotate_clockwise + if(src.rotation_flags & ROTATION_COUNTERCLOCKWISE) + AM.verbs += /atom/movable/proc/simple_rotate_counterclockwise + +/datum/component/simple_rotation/proc/remove_verbs() + if(parent) + var/atom/movable/AM = parent + AM.verbs -= /atom/movable/proc/simple_rotate_flip + AM.verbs -= /atom/movable/proc/simple_rotate_clockwise + AM.verbs -= /atom/movable/proc/simple_rotate_counterclockwise + +/datum/component/simple_rotation/proc/remove_signals() + UnregisterSignal(parent, list(COMSIG_CLICK_ALT, COMSIG_PARENT_EXAMINE, COMSIG_PARENT_ATTACKBY)) + +/datum/component/simple_rotation/RegisterWithParent() + add_verbs() + add_signals() + . = ..() + +/datum/component/simple_rotation/PostTransfer() + //Because of the callbacks which we don't track cleanly we can't transfer this + //item cleanly, better to let the new of the new item create a new rotation datum + //instead (there's no real state worth transferring) + return COMPONENT_NOTRANSFER + +/datum/component/simple_rotation/UnregisterFromParent() + remove_verbs() + remove_signals() + . = ..() + +/datum/component/simple_rotation/Destroy() + QDEL_NULL(can_user_rotate) + QDEL_NULL(can_be_rotated) + QDEL_NULL(after_rotation) + //Signals + verbs removed via UnRegister + . = ..() + +/datum/component/simple_rotation/RemoveComponent() + remove_verbs() + . = ..() + +/datum/component/simple_rotation/proc/ExamineMessage(datum/source, mob/user, list/examine_list) + if(rotation_flags & ROTATION_ALTCLICK) + examine_list += "Alt-click to rotate it clockwise." + +/datum/component/simple_rotation/proc/HandRot(datum/source, mob/user, rotation = default_rotation_direction) + if(!can_be_rotated.Invoke(user, rotation) || !can_user_rotate.Invoke(user, rotation)) + return + BaseRot(user, rotation) + +/datum/component/simple_rotation/proc/WrenchRot(datum/source, obj/item/I, mob/living/user) + if(!can_be_rotated.Invoke(user,default_rotation_direction) || !can_user_rotate.Invoke(user,default_rotation_direction)) + return + if(I.tool_behaviour == TOOL_WRENCH) + BaseRot(user,default_rotation_direction) + return COMPONENT_NO_AFTERATTACK + +/datum/component/simple_rotation/proc/BaseRot(mob/user,rotation_type) + var/atom/movable/AM = parent + var/rot_degree + switch(rotation_type) + if(ROTATION_CLOCKWISE) + rot_degree = -90 + if(ROTATION_COUNTERCLOCKWISE) + rot_degree = 90 + if(ROTATION_FLIP) + rot_degree = 180 + AM.setDir(turn(AM.dir,rot_degree)) + after_rotation.Invoke(user,rotation_type) + +/datum/component/simple_rotation/proc/default_can_user_rotate(mob/living/user, rotation_type) + //RMNZ: Check if be_close needed or not + if(!istype(user) || !user.can_use(parent)) + return FALSE + return TRUE + +/datum/component/simple_rotation/proc/default_can_be_rotated(mob/user, rotation_type) + var/atom/movable/AM = parent + return !AM.anchored + +/datum/component/simple_rotation/proc/default_after_rotation(mob/user, rotation_type) + to_chat(user, "You [rotation_type == ROTATION_FLIP ? "flip" : "rotate"] [parent].") + +/atom/movable/proc/simple_rotate_clockwise() + set name = "Rotate Clockwise" + set category = "Object" + set src in oview(1) + var/datum/component/simple_rotation/rotcomp = GetComponent(/datum/component/simple_rotation) + if(rotcomp) + rotcomp.HandRot(null,usr,ROTATION_CLOCKWISE) + +/atom/movable/proc/simple_rotate_counterclockwise() + set name = "Rotate Counter-Clockwise" + set category = "Object" + set src in oview(1) + var/datum/component/simple_rotation/rotcomp = GetComponent(/datum/component/simple_rotation) + if(rotcomp) + rotcomp.HandRot(null,usr,ROTATION_COUNTERCLOCKWISE) + +/atom/movable/proc/simple_rotate_flip() + set name = "Flip" + set category = "Object" + set src in oview(1) + var/datum/component/simple_rotation/rotcomp = GetComponent(/datum/component/simple_rotation) + if(rotcomp) + rotcomp.HandRot(null,usr,ROTATION_FLIP) diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm index db2d1a8a6442..a9e9b4d6bf58 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/rods.dm @@ -16,6 +16,13 @@ GLOBAL_LIST_INIT(rod_recipes, list ( new /datum/stack_recipe("chainlink fence door", /obj/structure/fence/door, 10, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), new /datum/stack_recipe("chainlink fence end", /obj/structure/fence/end, 3, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), )), + null, + new /datum/stack_recipe_list("octagon spacepod...", list( + new /datum/stack_recipe("aft starboard pod frame", /obj/item/pod_parts/pod_frame/aft_starboard, 15, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), + new /datum/stack_recipe("aft port pod frame", /obj/item/pod_parts/pod_frame/aft_port, 15, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), + new /datum/stack_recipe("fore port pod frame", /obj/item/pod_parts/pod_frame/fore_port, 15, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), + new /datum/stack_recipe("fore starboard pod frame", /obj/item/pod_parts/pod_frame/fore_starboard, 15, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), + )), )) /obj/item/stack/rods diff --git a/code/modules/mob/living/carbon/human/human_mob.dm b/code/modules/mob/living/carbon/human/human_mob.dm index b4d8babeb117..cb68f52419a1 100644 --- a/code/modules/mob/living/carbon/human/human_mob.dm +++ b/code/modules/mob/living/carbon/human/human_mob.dm @@ -216,6 +216,15 @@ if(V) stat("Total Blood", "[V.bloodtotal]") stat("Usable Blood", "[V.bloodusable]") + if(istype(loc, /obj/spacepod)) // Spacepods! + var/obj/spacepod/S = loc + // If we want numbers instead of percents + // [S.cell ? "[round(S.cell.charge,0.1)]/[S.cell.maxcharge] KJ" : "NONE"] + stat(null, "Spacepod Charge: [S.cell ? "[round((S.cell.charge / S.cell.maxcharge) * 100, 0.1)]%" : "No cell detected"]") + // Same here + // [round((S.obj_integrity / S.max_integrity) * 100, 0.1)] + stat(null, "Spacepod Integrity: [!S.obj_integrity ? "0" : "[round(S.obj_integrity,0.1)]/[S.max_integrity]"]") + stat(null, "Spacepod Velocity: [round(sqrt(S.velocity_x*S.velocity_x+S.velocity_y*S.velocity_y), 0.1)] m/s") /mob/living/carbon/human/ex_act(severity) if(status_flags & GODMODE) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 61d972c71eab..681ff41bdbe2 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -926,6 +926,10 @@ var/obj/mecha/M = loc loc_temp = M.return_temperature() + else if(isspacepod(loc)) + var/obj/spacepod/S = loc + loc_temp = S.return_temperature() + else if(istype(loc, /obj/structure/transit_tube_pod)) loc_temp = environment.temperature diff --git a/code/modules/mob/mob_vars.dm b/code/modules/mob/mob_vars.dm index f20d80240b2f..9907034453ba 100644 --- a/code/modules/mob/mob_vars.dm +++ b/code/modules/mob/mob_vars.dm @@ -252,3 +252,9 @@ var/next_click_modifier = 1 /// Tracks the open UIs that a mob has, used in TGUI for various things, such as updating UIs var/list/open_uis = list() + + ///Allows a datum to intercept all click calls this mob is the so + var/datum/click_intercept + + ///List of datums that this has which make use of MouseMove() + var/list/mousemove_intercept_objects diff --git a/code/modules/research/designs/mecha_designs.dm b/code/modules/research/designs/mecha_designs.dm index 837f80365c04..0ced7b73ffec 100644 --- a/code/modules/research/designs/mecha_designs.dm +++ b/code/modules/research/designs/mecha_designs.dm @@ -196,3 +196,14 @@ materials = list(MAT_GLASS = 1000) build_path = /obj/item/circuitboard/mecha/reticence/targeting category = list("Exosuit Modules") + +// Pod +/datum/design/spacepod_main + name = "Circuit Design (Space Pod Mainboard)" + desc = "Allows for the construction of a spacepod mainboard." + id = "spacepod_main" + req_tech = list("programming" = 1) //RMNZ: Change req_tech + build_type = IMPRINTER + materials = list(MAT_GLASS = 1000) + build_path = /obj/item/circuitboard/mecha/pod + category = list("Exosuit Modules") diff --git a/code/modules/research/designs/spacepod_designs.dm b/code/modules/research/designs/spacepod_designs.dm new file mode 100644 index 000000000000..1e473fe777ff --- /dev/null +++ b/code/modules/research/designs/spacepod_designs.dm @@ -0,0 +1,241 @@ +//////////////////// +////// Core ////// +//////////////////// + +/datum/design/pod_core + name = "Spacepod Core" + desc = "Allows for the construction of a spacepod core system, made up of the engine and life support systems." + id = "podcore" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=5000, MAT_URANIUM=1000, MAT_PLASMA=5000) + build_path = /obj/item/pod_parts/core + category = list("Spacepod Designs") + +///////////////////// +////// Armor ////// +///////////////////// + +/datum/design/pod_armor_civ + name = "Spacepod Armor (civilian)" + desc = "Allows for the construction of spacepod armor. This is the civilian version." + id = "podarmor_civ" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=15000,MAT_GLASS=5000,MAT_PLASMA=10000) + build_path = /obj/item/pod_parts/armor + category = list("Spacepod Designs") + +/datum/design/pod_armor_black + name = "Spacepod Armor (dark)" + desc = "Allows for the construction of spacepod armor. This is the dark civillian version." + id = "podarmor_dark" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=15000,MAT_GLASS=5000,MAT_PLASMA=10000) + build_path = /obj/item/pod_parts/armor/black + category = list("Spacepod Designs") + +/datum/design/pod_armor_industrial + name = "Spacepod Armor (industrial)" + desc = "Allows for the construction of spacepod armor. This is the industrial grade version." + id = "podarmor_industiral" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=15000,MAT_GLASS=5000,MAT_PLASMA=10000,MAT_DIAMOND=5000,MAT_SILVER=7500) + build_path = /obj/item/pod_parts/armor/industrial + category = list("Spacepod Designs") + +/datum/design/pod_armor_sec + name = "Spacepod Armor (security)" + desc = "Allows for the construction of spacepod armor. This is the security version." + id = "podarmor_sec" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=15000,MAT_GLASS=5000,MAT_PLASMA=10000,MAT_DIAMOND=5000,MAT_SILVER=7500) + build_path = /obj/item/pod_parts/armor/security + category = list("Spacepod Designs") + +/datum/design/pod_armor_gold + name = "Spacepod Armor (golden)" + desc = "Allows for the construction of spacepod armor. This is the golden version." + id = "podarmor_gold" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=5000,MAT_GLASS=2500,MAT_PLASMA=7500,MAT_GOLD=10000) + build_path = /obj/item/pod_parts/armor/gold + category = list("Spacepod Designs") + +///////////////////////////// +////// Spacepod Guns ////// +///////////////////////////// + +/* +/datum/design/pod_gun_disabler + name = "Spacepod Equipment (Disabler)" + desc = "Allows for the construction of a spacepod mounted disabler." + id = "podgun_disabler" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 15000) + build_path = /obj/item/spacepod_equipment/weaponry/disabler + category = list("Spacepod Designs") + +/datum/design/pod_gun_bdisabler + name = "Spacepod Equipment (Burst Disabler)" + desc = "Allows for the construction of a spacepod mounted disabler. This is the burst-fire model." + id = "podgun_bdisabler" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 15000, MAT_PLASMA=2000) + build_path = /obj/item/spacepod_equipment/weaponry/burst_disabler + category = list("Spacepod Designs") + +/datum/design/pod_gun_laser + name = "Spacepod Equipment (Laser)" + desc = "Allows for the construction of a spacepod mounted laser." + id = "podgun_laser" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=10000,MAT_GLASS=5000,MAT_GOLD=1000,MAT_SILVER=2000) + build_path = /obj/item/spacepod_equipment/weaponry/laser + category = list("Spacepod Designs") + +/datum/design/pod_ka_basic + name = "Spacepod Equipment (Basic Kinetic Accelerator)" + desc = "Allows for the construction of a weak spacepod Kinetic Accelerator" + id = "pod_ka_basic" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 10000, MAT_GLASS = 5000, MAT_SILVER = 2000, MAT_URANIUM = 2000) + build_path = /obj/item/spacepod_equipment/weaponry/basic_pod_ka + category = list("Spacepod Designs") + +/datum/design/pod_ka + name = "Spacepod Equipment (Kinetic Accelerator)" + desc = "Allows for the construction of a spacepod Kinetic Accelerator." + id = "pod_ka" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 10000, MAT_GLASS = 5000, MAT_SILVER = 2000, MAT_GOLD = 2000, MAT_DIAMOND = 2000) + build_path = /obj/item/spacepod_equipment/weaponry/pod_ka + category = list("Spacepod Designs") + +/datum/design/pod_plasma_cutter + name = "Spacepod Equipment (Plasma Cutter)" + desc = "Allows for the construction of a plasma cutter." + id = "pod_plasma_cutter" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 10000, MAT_GLASS = 5000, MAT_SILVER = 2000, MAT_GOLD = 2000, MAT_DIAMOND = 2000) + build_path = /obj/item/spacepod_equipment/weaponry/plasma_cutter + category = list("Spacepod Designs") + +/datum/design/pod_adv_plasma_cutter + name = "Spacepod Equipment (Advanced Plasma cutter)" + desc = "Allows for the construction of an advanced plasma cutter." + id = "pod_adv_plasma_cutter" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 10000, MAT_GLASS = 5000, MAT_SILVER = 4000, MAT_GOLD = 4000, MAT_DIAMOND = 4000) + build_path = /obj/item/spacepod_equipment/weaponry/plasma_cutter/adv + category = list("Spacepod Designs") +*/ + +//////////////////////////////////// +////// Spacepod Misc. Items ////// +//////////////////////////////////// + +/* +/datum/design/pod_misc_tracker + name = "Spacepod Tracking Module" + desc = "Allows for the construction of a spacepod tracking module." + id = "podmisc_tracker" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=5000) + build_path = /obj/item/spacepod_equipment/tracker + category = list("Spacepod Designs") +*/ + +//////////////////////////////////// +////// Spacepod Cargo Items ////// +//////////////////////////////////// + +/* +/datum/design/pod_cargo_ore + name = "Spacepod Ore Storage Module" + desc = "Allows for the construction of a spacepod ore storage module." + id = "podcargo_ore" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=20000, MAT_GLASS=2000) + build_path = /obj/item/spacepod_equipment/cargo/large/ore + category = list("Spacepod Designs") + +/datum/design/pod_cargo_crate + name = "Spacepod Crate Storage Module" + desc = "Allows the construction of a spacepod crate storage module." + id = "podcargo_crate" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=25000) + build_path = /obj/item/spacepod_equipment/cargo/large + category = list("Spacepod Designs") +*/ + +/datum/design/passenger_seat + name = "Spacepod Passenger Seat" + desc = "Allows the construction of a spacepod passenger seat module." + id = "podcargo_seat" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=7500, MAT_GLASS=2500) + build_path = /obj/item/spacepod_equipment/cargo/chair + category = list("Spacepod Designs") + +/* +/datum/design/loot_box + name = "Spacepod Loot Storage Module" + desc = "Allows the construction of a spacepod auxillary cargo module." + id = "podcargo_lootbox" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=7500, MAT_GLASS=2500) + build_path = /obj/item/spacepod_equipment/cargo/loot_box + category = list("Spacepod Designs") +*/ + +/////////////////////////////////// +////// Spacepod Lock Items ////// +/////////////////////////////////// + +/datum/design/pod_lock_keyed + name = "Spacepod Tumbler Lock" + desc = "Allows for the construction of a tumbler style podlock." + id = "podlock_keyed" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=4500) + build_path = /obj/item/spacepod_equipment/lock/keyed + category = list("Spacepod Designs") + +/datum/design/pod_key + name = "Spacepod Tumbler Lock Key" + desc = "Allows for the construction of a blank key for a podlock." + id = "podkey" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=500) + build_path = /obj/item/spacepod_key + category = list("Spacepod Designs") + +/datum/design/lockbuster + name = "Spacepod Lock Buster" + desc = "Allows for the construction of a spacepod lockbuster." + id = "pod_lockbuster" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 15000, MAT_DIAMOND=2500) //it IS a drill! + build_path = /obj/item/device/lock_buster + category = list("Spacepod Designs") diff --git a/code/modules/research/protolathe.dm b/code/modules/research/protolathe.dm index 2b78ebd2f94b..26cedb8720ed 100644 --- a/code/modules/research/protolathe.dm +++ b/code/modules/research/protolathe.dm @@ -22,7 +22,8 @@ Note: Must be placed west/left of and R&D console to function. "Miscellaneous", "Power", "Stock Parts", - "Weapons" + "Weapons", + "Spacepod Designs" ) /obj/machinery/r_n_d/protolathe/Initialize(mapload) diff --git a/code/modules/spacepods/icons/2x2.dmi b/code/modules/spacepods/icons/2x2.dmi new file mode 100644 index 0000000000000000000000000000000000000000..ecdb69d66c379973535ccd296a41f797ae6039d4 GIT binary patch literal 1085 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 G5&s9g{0XA~ literal 0 HcmV?d00001 diff --git a/code/modules/spacepods/spacepod.dm b/code/modules/spacepods/spacepod.dm new file mode 100644 index 000000000000..8e6fbd8e2d92 --- /dev/null +++ b/code/modules/spacepods/spacepod.dm @@ -0,0 +1,691 @@ +//YOGSTATION SPECEPODS + ITS ORIGINAL COMMENT +/* ------------------------------------------------------------ +This is like paradise spacepods but with a few differences: +- no spacepod fabricator, parts are made in techfabs and frames are made using metal rods. +- not tile based, instead has velocity and acceleration. why? so I can put all this math to use. +- damages shit if you run into it too fast instead of just stopping. You have to have a huge running start to do that though and damages the spacepod as well. +- doesn't explode +------------------------------------------------------------ */ + +// MrRomainzZ Comment: +// I decided to split the code like mechs do because I find it very similar in some ways +// Mostly untouched, but adapted for paradise and addition of new pods + +GLOBAL_LIST_INIT(spacepods_list, list()) + +/obj/spacepod + name = "space pod" + desc = "A frame for a spacepod." + icon = 'goon/icons/obj/spacepods/construction_2x2.dmi' + icon_state = "pod_1" + density = TRUE + opacity = FALSE + anchored = TRUE + dir = NORTH // always points north because why not + layer = SPACEPOD_LAYER + bound_width = 64 + bound_height = 64 + animate_movement = NO_STEPS // we do our own gliding here + + resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF // it floats above lava or something, I dunno + + max_integrity = 50 + integrity_failure = 50 + + var/list/equipment = list() + var/list/equipment_slot_limits = list( + SPACEPOD_SLOT_MISC = 1, + SPACEPOD_SLOT_CARGO = 2, + SPACEPOD_SLOT_WEAPON = 1, + SPACEPOD_SLOT_LOCK = 1) + var/obj/item/spacepod_equipment/lock/lock + var/obj/item/spacepod_equipment/weaponry/weapon + var/next_firetime = 0 + var/locked = FALSE + var/hatch_open = FALSE + var/construction_state = SPACEPOD_EMPTY + var/obj/item/pod_parts/armor/pod_armor = null + var/obj/item/stock_parts/cell/cell = null + + //inner atmos + var/datum/gas_mixture/cabin_air + var/obj/machinery/atmospherics/portable/canister/internal_tank + var/last_slowprocess = 0 + + var/mob/living/pilot = null + var/list/passengers = list() + var/max_passengers = 0 + + var/velocity_x = 0 // tiles per second. + var/velocity_y = 0 + var/offset_x = 0 // like pixel_x/y but in tiles + var/offset_y = 0 + var/angle = 0 // degrees, clockwise + var/desired_angle = null // set by pilot moving his mouse + var/angular_velocity = 0 // degrees per second + var/max_angular_acceleration = 360 // in degrees per second per second + var/last_thrust_forward = 0 + var/last_thrust_right = 0 + var/last_rotate = 0 + + var/brakes = TRUE + var/user_thrust_dir = 0 + var/forward_maxthrust = 6 + var/backward_maxthrust = 3 + var/side_maxthrust = 1 + + var/lights = 0 + var/lights_power = 6 + var/static/list/icon_light_color = list("pod_civ" = LIGHT_COLOR_WHITE, \ + "pod_mil" = "#BBF093", \ + "pod_synd" = LIGHT_COLOR_RED, \ + "pod_gold" = LIGHT_COLOR_WHITE, \ + "pod_black" = "#3B8FE5", \ + "pod_industrial" = "#CCCC00") + + var/bump_impulse = 0.6 + var/bounce_factor = 0.2 // how much of our velocity to keep on collision + var/lateral_bounce_factor = 0.95 // mostly there to slow you down when you drive (pilot?) down a 2x2 corridor + +/obj/spacepod/Initialize(mapload) + . = ..() + GLOB.spacepods_list += src + START_PROCESSING(SSspacepods, src) + cabin_air = new + cabin_air.temperature = T20C + cabin_air.volume = 200 + + /* Paradise variant + cabin_air.oxygen = O2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) + cabin_air.nitrogen = N2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) + */ + + /* Yogstation variant + cabin_air.assert_gas(GAS_O2) + cabin_air.assert_gas(GAS_N2) + cabin_air.gases[GAS_O2][MOLES] = ONE_ATMOSPHERE*O2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) + cabin_air.gases[GAS_N2][MOLES] = ONE_ATMOSPHERE*N2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) + */ + +/////////////////////// +////// Helpers ////// +/////////////////////// + +/obj/spacepod/Entered() + . = ..() + +/obj/spacepod/Exited() + . = ..() + +/obj/spacepod/proc/InterceptClickOn(mob/user, params, atom/target) + var/list/params_list = params2list(params) + if(target == src || istype(target, /atom/movable/screen) || (target && (target in user.get_contents())) || user != pilot || params_list["shift"] || params_list["alt"] || params_list["ctrl"]) + return FALSE + if(weapon) + weapon.fire_weapons(target) + return TRUE + +/obj/spacepod/proc/enter_pod(mob/living/user) + if(user.stat != CONSCIOUS) + return FALSE + + if(locked) // RMNZ: You also check your health on this + to_chat(user, "[src]'s doors are locked!") + return FALSE + + if(!istype(user)) + return FALSE + + if(user.incapacitated()) + return FALSE + if(!ishuman(user)) + return FALSE + + if(passengers.len <= max_passengers || !pilot) + visible_message("[user] starts to climb into [src].") + if(do_after(user, 4 SECONDS, target = src) && construction_state == SPACEPOD_ARMOR_WELDED) // RMNZ: No check for free passenger seats + var/success = add_rider(user) + if(!success) + to_chat(user, "You were too slow. Try better next time, loser.") + return success + else + to_chat(user, "You stop entering [src].") + else + to_chat(user, "You can't fit in [src], it's full!") + return FALSE + +/obj/spacepod/proc/go_out(forced, atom/newloc = loc) + if(!pilot) + return + if(!isliving(usr) || usr.stat > CONSCIOUS) + return + + if(usr.restrained()) + to_chat(usr, "You attempt to stumble out of [src]. This will take two minutes.") + if(pilot) + to_chat(pilot, "[usr] is trying to escape [src].") + if(!do_after(usr, 2 MINUTES, target = src)) + return + + if(remove_rider(usr)) + to_chat(usr, "You climb out of [src].") + +/obj/spacepod/proc/add_rider(mob/living/M, allow_pilot = TRUE) + if(M == pilot || (M in passengers)) + return FALSE + if(!pilot && allow_pilot) + pilot = M + LAZYOR(M.mousemove_intercept_objects, src) + M.click_intercept = src + // GrantActions(M) + // addverbs(M) + else if(passengers.len < max_passengers) + passengers += M + else + return FALSE + GrantActions(M) // Passengers have buttons now + M.stop_pulling() + M.forceMove(src) + playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) + return TRUE + +/obj/spacepod/proc/remove_rider(mob/living/M) + if(!M) + return + + RemoveActions(M) + + if(M == pilot) + pilot = null + // removeverbs(M) + LAZYREMOVE(M.mousemove_intercept_objects, src) + if(M.click_intercept == src) + M.click_intercept = null + desired_angle = null // since there's no pilot there's no one aiming it. + else if(M in passengers) + passengers -= M + else + return FALSE + if(M.loc == src) + M.forceMove(loc) + if(M.client) + M.client.pixel_x = 0 + M.client.pixel_y = 0 + return TRUE + +/obj/spacepod/proc/lock_pod() + if(!lock) // RMNZ: Passengers see this instead of "You can't reach controls" + to_chat(usr, "[src] has no locking mechanism.") + locked = FALSE //Should never be false without a lock, but if it somehow happens, that will force an unlock. + else + locked = !locked + to_chat(usr, "You [locked ? "lock" : "unlock"] the doors.") // RMNZ: You "tap" on the pod with your key. Also action button doesn't update + +/obj/spacepod/proc/verb_check(require_pilot = TRUE, mob/user = null) + if(!user) + user = usr + if(require_pilot && user != pilot) + to_chat(user, "You can't reach the controls from your chair") + return FALSE + return !user.incapacitated() && isliving(user) + +/obj/spacepod/AltClick(user) + if(!verb_check(user = user)) + return + brakes = !brakes + to_chat(usr, "You toggle the brakes [brakes ? "on" : "off"].") + +//////////////////////// +////// AttackBy ////// +//////////////////////// + +/obj/spacepod/attackby(obj/item/W, mob/living/user) + if(user.a_intent == INTENT_HARM) + return ..() + else if(construction_state != SPACEPOD_ARMOR_WELDED) + . = handle_spacepod_construction(W, user) + if(.) + return + else + return ..() + // and now for the real stuff + else + if(W.tool_behaviour == TOOL_CROWBAR) + if(hatch_open || !locked) + hatch_open = !hatch_open + W.play_tool_sound(src) + to_chat(user, "You [hatch_open ? "open" : "close"] the maintenance hatch.") + else + to_chat(user, "The hatch is locked shut!") + return TRUE + if(istype(W, /obj/item/stock_parts/cell)) + if(!hatch_open) + to_chat(user, "The maintenance hatch is closed!") + return TRUE + if(cell) + to_chat(user, "The pod already has a battery.") + return TRUE + if(user.drop_item()) + to_chat(user, "You insert [W] into the pod.") + W.forceMove(src) + cell = W + return TRUE + if(istype(W, /obj/item/spacepod_equipment)) + if(!hatch_open) + to_chat(user, "The maintenance hatch is closed!") + return TRUE + var/obj/item/spacepod_equipment/SE = W + if(SE.can_install(src, user)) + if(user.drop_item()) + SE.forceMove(src) + SE.on_install(src) + return TRUE + if(lock && istype(W, /obj/item/device/lock_buster)) + var/obj/item/device/lock_buster/L = W + if(L.on) + user.visible_message("[user] is drilling through [src]'s lock!", + "You start drilling through [src]'s lock!") + if(do_after(user, 10 SECONDS * W.toolspeed, target = src)) + if(lock) + var/obj/O = lock + lock.on_uninstall() + qdel(O) + user.visible_message("[user] has destroyed [src]'s lock!", + "You destroy [src]'s lock!") + else + user.visible_message("[user] fails to break through [src]'s lock!", + "You were unable to break through [src]'s lock!") + return TRUE + to_chat(user, "Turn the [L] on first.") + return TRUE + if(W.tool_behaviour == TOOL_WELDER) + var/repairing = cell || internal_tank || equipment.len || (obj_integrity < max_integrity) || pilot || passengers.len + if(!hatch_open) + to_chat(user, "You must open the maintenance hatch before [repairing ? "attempting repairs" : "unwelding the armor"].") + return TRUE + if(repairing && obj_integrity >= max_integrity) + to_chat(user, "[src] is fully repaired!") + return TRUE + to_chat(user, "You start [repairing ? "repairing [src]" : "slicing off [src]'s armor'"]") + if(W.use_tool(src, user, 50, amount=3, volume = 50)) + if(repairing) + obj_integrity = min(max_integrity, obj_integrity + 10) + update_appearance(UPDATE_ICON) + to_chat(user, "You mend some [pick("dents","bumps","damage")] with [W]") + else if(!cell && !internal_tank && !equipment.len && !pilot && !passengers.len && construction_state == SPACEPOD_ARMOR_WELDED) + user.visible_message("[user] slices off [src]'s armor.", "You slice off [src]'s armor.") + construction_state = SPACEPOD_ARMOR_SECURED + update_appearance(UPDATE_ICON) + return TRUE + return ..() + +//////////////////////////////////// +////// Health related procs ////// +//////////////////////////////////// + +/obj/spacepod/Destroy() + GLOB.spacepods_list -= src + QDEL_NULL(pilot) + QDEL_LIST_CONTENTS(passengers) + QDEL_LIST_CONTENTS(equipment) + QDEL_NULL(cabin_air) + QDEL_NULL(cell) + return ..() + +/obj/spacepod/attack_hand(mob/user as mob) + if(user.a_intent == INTENT_GRAB && !locked) + var/mob/living/target + if(pilot) + target = pilot + else if(passengers.len > 0) + target = passengers[1] + + if(target && istype(target)) // RMNZ: You can rip yourself out the pod + src.visible_message("[user] is trying to rip the door open and pull [target] out of [src]!", + "You see [user] outside the door trying to rip it open!") + if(do_after(user, 5 SECONDS, target = src) && construction_state == SPACEPOD_ARMOR_WELDED) + if(remove_rider(target)) + target.Stun(20) + target.visible_message("[user] flings the door open and tears [target] out of [src]", + "The door flies open and you are thrown out of [src] and to the ground!") + return + target.visible_message("[user] was unable to get the door open!", + "You manage to keep [user] out of [src]!") + + if(!hatch_open) + //if(cargo_hold.storage_slots > 0) + // if(!locked) + // cargo_hold.open(user) + // else + // to_chat(user, "The storage compartment is locked") + return ..() + + if(user == pilot) + return ..() + + var/list/items = list(cell, internal_tank) + items += equipment + var/list/item_map = list() + //var/list/used_key_list = list() + for(var/obj/I in items) + item_map[I.name] = I + var/selection = input(user, "Remove which equipment?", null, null) as null|anything in item_map + var/obj/O = item_map[selection] + if(O && istype(O) && (O in contents) && user != pilot) + // alrightey now to figure out what it is + if(O == cell) + cell = null + else if(O == internal_tank) + internal_tank = null + else if(O in equipment) + var/obj/item/spacepod_equipment/SE = O + if(!SE.can_uninstall(user)) + return + SE.on_uninstall() + else + return + O.forceMove(loc) + if(isitem(O)) + user.put_in_hands(O) + +/obj/spacepod/ex_act(severity) + switch(severity) + if(1) + for(var/mob/living/M in contents) + M.ex_act(severity+1) + deconstruct() + if(2) + take_damage(100, BRUTE, BOMB, 0) + if(3) + if(prob(40)) + take_damage(40, BRUTE, BOMB, 0) + +/obj/spacepod/obj_break() + if(obj_integrity <= 0) + return // nah we'll let the other boy handle it + if(construction_state < SPACEPOD_ARMOR_LOOSE) + return + if(pod_armor) + var/obj/A = pod_armor + remove_armor() + qdel(A) + if(prob(40)) + new /obj/item/stack/sheet/metal(loc, 5) + if(prob(40)) + new /obj/item/stack/sheet/metal(loc, 5) + construction_state = SPACEPOD_CORE_SECURED + if(cabin_air) + var/datum/gas_mixture/GM = cabin_air.remove_ratio(1) + var/turf/T = get_turf(src) + if(GM && T) + T.assume_air(GM) + cell = null + internal_tank = null + for(var/atom/movable/AM in contents) + if(AM in equipment) + var/obj/item/spacepod_equipment/SE = AM + if(istype(SE)) + SE.on_uninstall(src) + if(ismob(AM)) + forceMove(AM, loc) + remove_rider(AM) + else if(prob(60)) + AM.forceMove(loc) + else if(isitem(AM) || !isobj(AM)) + qdel(AM) + else + var/obj/O = AM + O.forceMove(loc) + O.deconstruct() + +/obj/spacepod/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = TRUE, attack_dir, armour_penetration = 0) + ..() + update_appearance(UPDATE_ICON) + +/obj/spacepod/deconstruct(disassembled = FALSE) + if(!get_turf(src)) + qdel(src) + return + remove_rider(pilot) + while(passengers.len) + remove_rider(passengers[1]) + passengers.Cut() + if(disassembled) + // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + // alright fine fine you can have the frame pieces back + var/clamped_angle = (round(angle, 90) % 360 + 360) % 360 + var/target_dir = NORTH + switch(clamped_angle) + if(0) + target_dir = NORTH + if(90) + target_dir = EAST + if(180) + target_dir = SOUTH + if(270) + target_dir = WEST + //RMNZ: Addition of new pods 2 + var/list/frame_piece_types = list(/obj/item/pod_parts/pod_frame/aft_port, /obj/item/pod_parts/pod_frame/aft_starboard, /obj/item/pod_parts/pod_frame/fore_port, /obj/item/pod_parts/pod_frame/fore_starboard) + var/obj/item/pod_parts/pod_frame/current_piece = null + var/turf/CT = get_turf(src) + var/list/frame_pieces = list() + for(var/frame_type in frame_piece_types) + var/obj/item/pod_parts/pod_frame/F = new frame_type + F.dir = target_dir + F.anchored = TRUE + if(1 == turn(F.dir, -F.link_angle)) + current_piece = F + frame_pieces += F + while(current_piece && !current_piece.loc) + if(!CT) + break + current_piece.forceMove(CT) + CT = get_step(CT, turn(current_piece.dir, -current_piece.link_angle)) + current_piece = locate(current_piece.link_to) in frame_pieces + // there here's your frame pieces back, happy? + qdel(src) + +///////////////////////////////// +////// Atmospheric stuff ////// +///////////////////////////////// + +/obj/spacepod/return_air() + return cabin_air + +/obj/spacepod/remove_air(amount) + return cabin_air.remove(amount) + +/obj/spacepod/proc/return_temperature() + var/datum/gas_mixture/t_air = return_air() + if(t_air) + . = t_air.return_temperature() + +/obj/spacepod/proc/slowprocess() + // Temp Regulation + if(cabin_air && cabin_air.return_volume() > 0) + var/delta = cabin_air.temperature - T20C + cabin_air.temperature -= max(-10, min(10, round(delta / 4, 0.1))) + + // Air Regulation + if(internal_tank && cabin_air) + var/datum/gas_mixture/tank_air = internal_tank.return_air() + + var/release_pressure = ONE_ATMOSPHERE + var/cabin_pressure = cabin_air.return_pressure() + var/pressure_delta = min(release_pressure - cabin_pressure, (tank_air.return_pressure() - cabin_pressure)/2) + var/transfer_moles = 0 + if(pressure_delta > 0) //cabin pressure lower than release pressure + if(tank_air.return_temperature() > 0) + transfer_moles = pressure_delta*cabin_air.return_volume()/(cabin_air.return_temperature() * R_IDEAL_GAS_EQUATION) + var/datum/gas_mixture/removed = tank_air.remove(transfer_moles) + cabin_air.merge(removed) + else if(pressure_delta < 0) //cabin pressure higher than release pressure + var/datum/gas_mixture/t_air = return_air() + pressure_delta = cabin_pressure - release_pressure + if(t_air) + pressure_delta = min(cabin_pressure - t_air.return_pressure(), pressure_delta) + if(pressure_delta > 0) //if location pressure is lower than cabin pressure + transfer_moles = pressure_delta*cabin_air.return_volume()/(cabin_air.return_temperature() * R_IDEAL_GAS_EQUATION) + var/datum/gas_mixture/removed = cabin_air.remove(transfer_moles) + if(t_air) + t_air.merge(removed) + else //just delete the cabin gas, we're in space or some shit + qdel(removed) + + //Power Related + if(!cell || cell.charge < 1) // RMNZ: How to update action button from here? + lights = 0 + set_light(0) + +////////////////////////////// +////// Movement procs ////// +////////////////////////////// + +/obj/spacepod/onMouseMove(object,location,control,params) + if(!pilot || !pilot.client || pilot.incapacitated()) + return // I don't know what's going on. + var/list/params_list = params2list(params) + var/sl_list = splittext(params_list["screen-loc"],",") + var/sl_x_list = splittext(sl_list[1], ":") + var/sl_y_list = splittext(sl_list[2], ":") + var/view_list = isnum(pilot.client.view) ? list("[pilot.client.view*2+1]","[pilot.client.view*2+1]") : splittext(pilot.client.view, "x") + var/dx = text2num(sl_x_list[1]) + (text2num(sl_x_list[2]) / world.icon_size) - 1 - text2num(view_list[1]) / 2 + var/dy = text2num(sl_y_list[1]) + (text2num(sl_y_list[2]) / world.icon_size) - 1 - text2num(view_list[2]) / 2 + if(sqrt(dx*dx+dy*dy) > 1) + desired_angle = 90 - ATAN2(dx, dy) + else + desired_angle = null + +/obj/spacepod/relaymove(mob/user, direction) + if(user != pilot || pilot.incapacitated()) + return + user_thrust_dir = direction + +////////////////////////////////// +////// Construction procs ////// +////////////////////////////////// + +/obj/spacepod/proc/add_armor(obj/item/pod_parts/armor/armor) + desc = armor.pod_desc + max_integrity = armor.pod_integrity + obj_integrity = max_integrity - integrity_failure + obj_integrity + pod_armor = armor + update_appearance(UPDATE_ICON) + +/obj/spacepod/proc/remove_armor() + if(!pod_armor) + obj_integrity = min(integrity_failure, obj_integrity) + max_integrity = integrity_failure + desc = initial(desc) + pod_armor = null + update_appearance(UPDATE_ICON) + +/obj/spacepod/update_icon_state() + . = ..() + if(construction_state != SPACEPOD_ARMOR_WELDED) + icon = 'goon/icons/obj/spacepods/construction_2x2.dmi' + icon_state = "pod_[construction_state]" + return + + if(pod_armor) + icon = pod_armor.pod_icon + icon_state = pod_armor.pod_icon_state + else + icon = 'goon/icons/obj/spacepods/2x2.dmi' + icon_state = initial(icon_state) + +/obj/spacepod/update_overlays() + . = ..() + if(construction_state != SPACEPOD_ARMOR_WELDED) + if(pod_armor && construction_state >= SPACEPOD_ARMOR_LOOSE) + var/mutable_appearance/masked_armor = mutable_appearance(icon = 'goon/icons/obj/spacepods/construction_2x2.dmi', icon_state = "armor_mask") + var/mutable_appearance/armor = mutable_appearance(pod_armor.pod_icon, pod_armor.pod_icon_state) + armor.blend_mode = BLEND_MULTIPLY + masked_armor.overlays = list(armor) + masked_armor.appearance_flags = KEEP_TOGETHER + . += masked_armor + return + + if(obj_integrity <= max_integrity / 2) + . += image(icon='goon/icons/obj/spacepods/2x2.dmi', icon_state="pod_damage") + if(obj_integrity <= max_integrity / 4) + . += image(icon='goon/icons/obj/spacepods/2x2.dmi', icon_state="pod_fire") + + if(weapon && weapon.overlay_icon_state) + . += image(icon=weapon.overlay_icon,icon_state=weapon.overlay_icon_state) + + light_color = icon_light_color[icon_state] || LIGHT_COLOR_WHITE + + // Thrust! + var/list/left_thrusts = list() + left_thrusts.len = 8 + var/list/right_thrusts = list() + right_thrusts.len = 8 + for(var/cdir in GLOB.cardinal) + left_thrusts[cdir] = 0 + right_thrusts[cdir] = 0 + var/back_thrust = 0 + if(last_thrust_right != 0) + var/tdir = last_thrust_right > 0 ? WEST : EAST + left_thrusts[tdir] = abs(last_thrust_right) / side_maxthrust + right_thrusts[tdir] = abs(last_thrust_right) / side_maxthrust + if(last_thrust_forward > 0) + back_thrust = last_thrust_forward / forward_maxthrust + if(last_thrust_forward < 0) + left_thrusts[NORTH] = -last_thrust_forward / backward_maxthrust + right_thrusts[NORTH] = -last_thrust_forward / backward_maxthrust + if(last_rotate != 0) + var/frac = abs(last_rotate) / max_angular_acceleration + for(var/cdir in GLOB.cardinal) + if(last_rotate > 0) + right_thrusts[cdir] += frac + else + left_thrusts[cdir] += frac + for(var/cdir in GLOB.cardinal) + var/left_thrust = left_thrusts[cdir] + var/right_thrust = right_thrusts[cdir] + if(left_thrust) + . += image(icon = 'code/modules/spacepods/icons/2x2.dmi', icon_state = "rcs_left", dir = cdir) + if(right_thrust) + . += image(icon = 'code/modules/spacepods/icons/2x2.dmi', icon_state = "rcs_right", dir = cdir) + if(back_thrust) + var/image/I = image(icon = 'code/modules/spacepods/icons/2x2.dmi', icon_state = "thrust") + I.transform = matrix(1, 0, 0, 0, 1, -32) + . += I + +/obj/spacepod/MouseDrop_T(atom/movable/A, mob/living/user) + if(user == pilot || (user in passengers) || construction_state != SPACEPOD_ARMOR_WELDED) + return + + if(istype(A, /obj/machinery/atmospherics/portable/canister)) + if(internal_tank) + to_chat(user, "[src] already has an internaltank!") + return + if(!A.Adjacent(src)) + to_chat(user, "The canister is not close enough!") + return + if(hatch_open) + to_chat(user, "The hatch is shut!") + to_chat(user, "You begin inserting the canister into [src]") + if(do_after(user, 5 SECONDS, target = A) && construction_state == SPACEPOD_ARMOR_WELDED) + to_chat(user, "You insert the canister into [src]") + A.forceMove(src) + internal_tank = A + return + + if(isliving(A)) + var/mob/living/M = A + if(M != user && !locked) + if(passengers.len >= max_passengers && !pilot) + to_chat(user, "[A.p_they()] can't fly the pod!") + return + if(passengers.len < max_passengers) + visible_message("[user] starts loading [M] into [src]!") + if(do_after(user, 5 SECONDS, target = M) && construction_state == SPACEPOD_ARMOR_WELDED) + add_rider(M, FALSE) + return + if(M == user) + enter_pod(user) + return + + return ..() diff --git a/code/modules/spacepods/spacepod_actions.dm b/code/modules/spacepods/spacepod_actions.dm new file mode 100644 index 000000000000..dc12481b1d37 --- /dev/null +++ b/code/modules/spacepods/spacepod_actions.dm @@ -0,0 +1,122 @@ +/obj/spacepod + //Action datums + var/datum/action/innate/spacepod/spacepod_exit/exit_action = new + var/datum/action/innate/spacepod/spacepod_toggle_brakes/brakes_action = new + var/datum/action/innate/spacepod/spacepod_toggle_lights/lights_action = new + var/datum/action/innate/spacepod/spacepod_toggle_poddoors/podddoors_action = new + var/datum/action/innate/spacepod/spacepod_lock_doors/lock_action = new + +/obj/spacepod/proc/GrantActions(mob/living/user) + exit_action.Grant(user, src) + brakes_action.Grant(user, src) + lights_action.Grant(user, src) + podddoors_action.Grant(user, src) + lock_action.Grant(user, src) + +/obj/spacepod/proc/RemoveActions(mob/living/user) + exit_action.Remove(user) + brakes_action.Remove(user) + lights_action.Remove(user) + podddoors_action.Remove(user) + lock_action.Remove(user) + +/datum/action/innate/spacepod + check_flags = AB_CHECK_RESTRAINED | AB_CHECK_STUNNED | AB_CHECK_CONSCIOUS + icon_icon = 'code/modules/spacepods/icons/actions_spacepod.dmi' + var/obj/spacepod/frame + +/datum/action/innate/spacepod/Grant(mob/living/L, obj/spacepod/S) + if(S) + frame = S + . = ..() + +/datum/action/innate/spacepod/Destroy() + frame = null + return ..() + +// Actions! + +/datum/action/innate/spacepod/spacepod_exit + name = "Eject From Spacepod" + button_icon_state = "pods_exit" + +/datum/action/innate/spacepod/spacepod_exit/Activate() + frame.go_out() + +/datum/action/innate/spacepod/spacepod_toggle_brakes + name = "Toggle Spacepod Brakes" + button_icon_state = "handbrake_on" + +/datum/action/innate/spacepod/spacepod_toggle_brakes/Activate() + if(!frame.verb_check()) + return + frame.brakes = !frame.brakes + to_chat(usr, "You toggle the brakes [frame.brakes ? "on" : "off"].") + button_icon_state = "handbrake_[frame.brakes ? "on" : "off"]" + UpdateButtonIcon() + +/datum/action/innate/spacepod/spacepod_toggle_lights + name = "Toggle Spacepod Lights" + button_icon_state = "pods_lights_off" + +/datum/action/innate/spacepod/spacepod_toggle_lights/Activate() + if(!frame.verb_check()) + return + + /* + if(!frame.cell || frame.cell.charge < 1) // RMNZ: To turn off button when cell has no power + button_icon_state = "pods_lights_off" + UpdateButtonIcon() + return + */ + + frame.lights = !frame.lights + if(frame.lights) + frame.set_light(frame.lights_power) + else + frame.set_light(0) + to_chat(usr, "Lights toggled [frame.lights ? "on" : "off"].") + button_icon_state = "pods_lights_[frame.lights ? "on" : "off"]" + for(var/mob/M in frame.passengers) + to_chat(M, "Lights toggled [frame.lights ? "on" : "off"].") + button_icon_state = "pods_lights_[frame.lights ? "on" : "off"]" + UpdateButtonIcon() + +/datum/action/innate/spacepod/spacepod_toggle_poddoors + name = "Toggle Nearest Pod Doors" + button_icon_state = "blast_door_use" + +/datum/action/innate/spacepod/spacepod_toggle_poddoors/Activate() + if(!frame.verb_check()) + return + + for(var/obj/machinery/door/poddoor/multi_tile/P in orange(3, frame)) + for(var/mob/living/carbon/human/O in frame.contents) + if(P.check_access(O.get_active_hand()) || P.check_access(O.wear_id)) + if(P.density) + P.open() + return TRUE + else + P.close() + return TRUE + to_chat(usr, "Access denied.") + return + + to_chat(usr, "You are not close to any pod doors.") + +/datum/action/innate/spacepod/spacepod_lock_doors + name = "Lock Spacepod Doors" + button_icon_state = "pods_door_on" + +/datum/action/innate/spacepod/spacepod_lock_doors/Activate() + if(!frame.verb_check(FALSE)) + return + + if(!frame.lock) + to_chat(usr, "[src] has no locking mechanism.") + frame.locked = FALSE //Should never be false without a lock, but if it somehow happens, that will force an unlock. + else + frame.locked = !frame.locked + to_chat(usr, "You [frame.locked ? "lock" : "unlock"] the doors.") + button_icon_state = "pods_door_[!frame.locked ? "on" : "off"]" + UpdateButtonIcon() diff --git a/code/modules/spacepods/spacepod_construction.dm b/code/modules/spacepods/spacepod_construction.dm new file mode 100644 index 000000000000..b8db43e49bd5 --- /dev/null +++ b/code/modules/spacepods/spacepod_construction.dm @@ -0,0 +1,206 @@ +/obj/spacepod/examine(mob/user) + . = ..() + switch(construction_state) // more construction states than r-walls! + if(SPACEPOD_EMPTY) + . += "The struts holding it together can be cut and it is missing wires." + if(SPACEPOD_WIRES_LOOSE) + . += "The wires need to be screwed on." + if(SPACEPOD_WIRES_SECURED) + . += "The wires are screwed on and need a circuit board." + if(SPACEPOD_CIRCUIT_LOOSE) + . += "The circuit board is loosely attached and needs to be screwed on." + if(SPACEPOD_CIRCUIT_SECURED) + . += "The circuit board is screwed on, and there is space for a core." + if(SPACEPOD_CORE_LOOSE) + . += "The core is loosely attached and needs to be bolted on." + if(SPACEPOD_CORE_SECURED) + . += "The core is bolted on and the metal bulkhead can be attached." + if(SPACEPOD_BULKHEAD_LOOSE) + . += "The bulkhead is loosely attached and can be bolted down." + if(SPACEPOD_BULKHEAD_SECURED) + . += "The bulkhead is bolted on but not welded on." + if(SPACEPOD_BULKHEAD_WELDED) + . += "The bulkhead is welded on and armor can be attached." + if(SPACEPOD_ARMOR_LOOSE) + . += "The armor is loosely attached and can be bolted down." + if(SPACEPOD_ARMOR_SECURED) + . += "The armor is bolted on but not welded on." + if(SPACEPOD_ARMOR_WELDED) + if(hatch_open) + if(cell || internal_tank || equipment.len) + . += "The maintenance hatch is pried open and there are parts inside that can be removed." + else + . += "The maintenance hatch is pried open and the armor is welded on." + else + if(locked) + . += "[src] is locked." + else + . += "The maintenance hatch is closed." + +/obj/spacepod/proc/handle_spacepod_construction(obj/item/W, mob/living/user) + // time for a construction/deconstruction process to rival r-walls + var/obj/item/stack/ST = W + switch(construction_state) + if(SPACEPOD_EMPTY) + if(W.tool_behaviour == TOOL_WIRECUTTER) + . = TRUE + user.visible_message("[user] deconstructs [src].", "You deconstruct [src].") + W.play_tool_sound(src) + deconstruct(TRUE) + else if(istype(W, /obj/item/stack/cable_coil)) + . = TRUE + if(ST.use(10)) + user.visible_message("[user] wires [src].", "You wire [src].") + construction_state++ + else + to_chat(user, "You need 10 wires for this!") + if(SPACEPOD_WIRES_LOOSE) + if(W.tool_behaviour == TOOL_WIRECUTTER) + . = TRUE + var/obj/item/stack/cable_coil/CC = new + CC.amount = 10 + CC.forceMove(loc) + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] cuts [src]'s wiring.", "You remove [src]'s wiring.") + else if(W.tool_behaviour == TOOL_SCREWDRIVER) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] screws on [src]'s wiring harnesses.", "You screw on [src]'s wiring harnesses.") + if(SPACEPOD_WIRES_SECURED) + if(W.tool_behaviour == TOOL_SCREWDRIVER) + . = TRUE + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] unclips [src]'s wiring harnesses.", "You unclip [src]'s wiring harnesses.") + else if(istype(W, /obj/item/circuitboard/mecha/pod)) + . = TRUE + if(user.canUnEquip(W)) + qdel(W) + construction_state++ + user.visible_message("[user] inserts the mainboard into [src].", "You insert the mainboard into [src].") + else + to_chat(user, "[W] is stuck to your hand!") + if(SPACEPOD_CIRCUIT_LOOSE) + if(W.tool_behaviour == TOOL_CROWBAR) + . = TRUE + W.play_tool_sound(src) + construction_state-- + var/obj/item/circuitboard/mecha/pod/B = new + B.forceMove(loc) + user.visible_message("[user] pries out the mainboard from [src].", "You pry out the mainboard from [src].") + else if(W.tool_behaviour == TOOL_SCREWDRIVER) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] secures the mainboard to [src].", "You secure the mainboard to [src].") + if(SPACEPOD_CIRCUIT_SECURED) + if(W.tool_behaviour == TOOL_SCREWDRIVER) + . = TRUE + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] unsecures the mainboard.", "You unscrew the mainboard from [src].") + else if(istype(W, /obj/item/pod_parts/core)) + . = TRUE + if(user.canUnEquip(W)) + qdel(W) + construction_state++ + user.visible_message("[user] inserts the core into [src].", "You carefully insert the core into [src].") + else + to_chat(user, "[W] is stuck to your hand!") + if(SPACEPOD_CORE_LOOSE) + if(W.tool_behaviour == TOOL_CROWBAR) + . = TRUE + W.play_tool_sound(src) + var/obj/item/pod_parts/core/C = new + C.forceMove(loc) + construction_state-- + user.visible_message("[user] delicately removes the core from [src].", "You delicately remove the core from [src].") + else if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] secures [src]'s core bolts.", "You secure [src]'s core bolts.") + if(SPACEPOD_CORE_SECURED) + if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] unsecures [src]'s core.", "You unsecure [src]'s core.") + else if(istype(W, /obj/item/stack/sheet/metal)) + . = TRUE + if(ST.use(5)) + user.visible_message("[user] fabricates a pressure bulkhead for [src].", "You frabricate a pressure bulkhead for [src].") + construction_state++ + else + to_chat(user, "You need 5 metal for this!") + if(SPACEPOD_BULKHEAD_LOOSE) + if(W.tool_behaviour == TOOL_CROWBAR) + . = TRUE + W.play_tool_sound(src) + construction_state-- + // RMNZ: Test this thing out + var/obj/item/stack/sheet/metal/M = new + M.amount = 5 + M.forceMove(loc) + user.visible_message("[user] pops [src]'s bulkhead panelling loose.", "You pop [src]'s bulkhead panelling loose.") + else if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] secures [src]'s bulkhead panelling.", "You secure [src]'s bulkhead panelling.") + if(SPACEPOD_BULKHEAD_SECURED) + if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] unbolts [src]'s bulkhead panelling.", "You unbolt [src]'s bulkhead panelling.") + else if(W.tool_behaviour == TOOL_WELDER) + . = TRUE + if(W.use_tool(src, user, 20, amount=3, volume = 50)) + construction_state = SPACEPOD_BULKHEAD_WELDED + user.visible_message("[user] seals [src]'s bulkhead panelling.", "You seal [src]'s bulkhead panelling.") + if(SPACEPOD_BULKHEAD_WELDED) + if(W.tool_behaviour == TOOL_WELDER) + . = TRUE + if(W.use_tool(src, user, 20, amount=3, volume = 50)) + construction_state = SPACEPOD_BULKHEAD_SECURED + user.visible_message("[user] cuts [src]'s bulkhead panelling loose.", "You cut [src]'s bulkhead panelling loose.") + if(istype(W, /obj/item/pod_parts/armor)) + . = TRUE + if(user.drop_item()) + W.forceMove() + add_armor(W) + construction_state++ + user.visible_message("[user] installs [src]'s armor plating.", "You install [src]'s armor plating.") + else + to_chat(user, "[W] is stuck to your hand!") + if(SPACEPOD_ARMOR_LOOSE) + if(W.tool_behaviour == TOOL_CROWBAR) + . = TRUE + if(pod_armor) + pod_armor.forceMove(loc) + remove_armor() + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] pries off [src]'s armor.", "You pry off [src]'s armor.") + if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] bolts down [src]'s armor.", "You bolt down [src]'s armor.") + if(SPACEPOD_ARMOR_SECURED) + if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] unsecures [src]'s armor.", "You unsecure [src]'s armor.") + else if(W.tool_behaviour == TOOL_WELDER) + . = TRUE + if(W.use_tool(src, user, 50, amount=3, volume = 50)) + construction_state = SPACEPOD_ARMOR_WELDED + user.visible_message("[user] welds [src]'s armor.", "You weld [src]'s armor.") + // finally this took too fucking long + // somehow this takes up 40 lines less code than the original, code-less version. And it actually works + update_appearance(UPDATE_ICON) diff --git a/code/modules/spacepods/spacepod_equipment.dm b/code/modules/spacepods/spacepod_equipment.dm new file mode 100644 index 000000000000..d1f35476329b --- /dev/null +++ b/code/modules/spacepods/spacepod_equipment.dm @@ -0,0 +1,379 @@ +/obj/item/spacepod_equipment + var/obj/spacepod/spacepod + icon = 'code/modules/spacepods/icons/parts.dmi' + var/slot = SPACEPOD_SLOT_MISC + var/slot_space = 1 + +/obj/item/spacepod_equipment/proc/on_install(obj/spacepod/SP) + spacepod = SP + SP.equipment |= src + forceMove(SP) + +/obj/item/spacepod_equipment/proc/on_uninstall() + spacepod.equipment -= src + +/obj/item/spacepod_equipment/proc/can_install(obj/spacepod/SP, mob/user) + var/room = SP.equipment_slot_limits[slot] || 0 + for(var/obj/item/spacepod_equipment/EQ in SP.equipment) + if(EQ.slot == slot) + room -= EQ.slot_space + if(room < slot_space) + to_chat(user, "There's no room for another [slot] system!") + return FALSE + return TRUE + +/obj/item/spacepod_equipment/proc/can_uninstall(mob/user) + return TRUE + +// RMNZ: Weapons doesn't work + +/* +/obj/item/spacepod_equipment/weaponry + slot = SPACEPOD_SLOT_WEAPON + var/projectile_type + var/shot_cost = 0 + var/shots_per = 1 + var/fire_sound + var/fire_delay = 15 + var/overlay_icon + var/overlay_icon_state + +/obj/item/spacepod_equipment/weaponry/on_install(obj/spacepod/SP) + . = ..() + SP.weapon = src + SP.update_appearance(UPDATE_ICON) + +/obj/item/spacepod_equipment/weaponry/on_uninstall() + . = ..() + if(spacepod.weapon == src) + spacepod.weapon = null + +/obj/item/spacepod_equipment/weaponry/proc/fire_weapons(target) + if(spacepod.next_firetime > world.time) + to_chat(usr, "Your weapons are recharging.") + playsound(src, 'sound/weapons/empty.ogg', 30, TRUE) + return + if(!spacepod.cell || !spacepod.cell.use(shot_cost)) + to_chat(usr, "Insufficient charge to fire the weapons") + playsound(src, 'sound/weapons/empty.ogg', 30, TRUE) + return + spacepod.next_firetime = world.time + fire_delay + for(var/I in 1 to shots_per) + spacepod.fire_projectiles(projectile_type, target) + playsound(src, fire_sound, 50, TRUE) + sleep(0.2 SECONDS) +*/ + +//////////////////////////// +////// Cargo System ////// +//////////////////////////// + +/obj/item/spacepod_equipment/cargo // this one holds large crates and shit + name = "pod cargo" + desc = "You shouldn't be seeing this" + icon_state = "cargo_blank" + slot = SPACEPOD_SLOT_CARGO + +// RMNZ: Doesn't work properly + +/* +/obj/item/spacepod_equipment/cargo/large + name = "spacepod crate storage system" + desc = "A heavy duty storage system for spacepods. Holds one crate." + icon_state = "cargo_crate" + var/obj/storage = null + var/storage_type = /obj/structure/closet/crate + +/obj/item/spacepod_equipment/cargo/large/on_install(obj/spacepod/SP) + ..() + // COMSIG - a way to make component signals sound more important than they actually are. + // it's not even limited to components. Does this look like a component to you? + // Okay here's a better name: It's a fucking *event handler*. Like the ones in javascript. + // a much more descriptive and less scary name than fucking "COMSIG". But noooooooooo + // the TG coders were too self important to pick a descriptive name and wanted to sound all scientific + RegisterSignal(SP, COMSIG_MOUSEDROPPED_ONTO, PROC_REF(spacepod_mousedrop)) + SP.verbs |= /obj/spacepod/proc/unload_cargo + +/obj/item/spacepod_equipment/cargo/large/on_uninstall() + UnregisterSignal(spacepod, COMSIG_MOUSEDROPPED_ONTO) + ..() + if(!(locate(/obj/item/spacepod_equipment/cargo/large) in spacepod.equipment)) + spacepod.verbs -= /obj/spacepod/proc/unload_cargo + +/obj/item/spacepod_equipment/cargo/large/can_uninstall(mob/user) + if(storage) + to_chat(user, "Unload the cargo first!") + return FALSE + return ..() + +/obj/spacepod/proc/unload_cargo() // if I could i'd put this on spacepod_equipment but unfortunately BYOND is stupid | RMNZ: What is this comment? Make this as action + set name = "Unload Cargo" + set category = "Spacepod" + set src = usr.loc + + if(!verb_check()) + return + + //var/used_key_list = list() + var/cargo_map = list() + for(var/obj/item/spacepod_equipment/cargo/large/E in equipment) + if(!E.storage) + continue + cargo_map[E.name] = E + var/selection = input(usr, "Unload which cargo?", null, null) as null|anything in cargo_map + var/obj/item/spacepod_equipment/cargo/large/E = cargo_map[selection] + if(!selection || !verb_check() || !E || !(E in equipment) || !E.storage) + return + E.storage.forceMove(loc) + E.storage = null + +/obj/item/spacepod_equipment/cargo/large/proc/spacepod_mousedrop(obj/spacepod/SP, obj/A, mob/user) + if(user == SP.pilot || (user in SP.passengers)) + return FALSE + if(istype(A, storage_type) && SP.Adjacent(A)) // For loading ore boxes + if(!storage) + to_chat(user, "You begin loading [A] into [SP]'s [src]") + if(do_after(user, 4 SECONDS, target = A)) + storage = A + A.forceMove(src) + to_chat(user, "You load [A] into [SP]'s [src]!") + else + to_chat(user, "You fail to load [A] into [SP]'s [src]") + else + to_chat(user, "[SP] already has \an [storage]") + return TRUE + return FALSE + +/obj/item/spacepod_equipment/cargo/large/ore //RMNZ: Can't load ore_box + name = "spacepod ore storage system" + desc = "An ore storage system for spacepods. Scoops up any ore you drive over. Needs to be loaded with an ore box to work" + icon_state = "cargo_ore" + storage_type = /obj/structure/ore_box + +/obj/item/spacepod_equipment/cargo/large/ore/on_install(obj/spacepod/SP) + ..() + RegisterSignal(SP, COMSIG_MOVABLE_MOVED, PROC_REF(spacepod_moved)) + +/obj/item/spacepod_equipment/cargo/large/ore/on_uninstall() + UnregisterSignal(spacepod, COMSIG_MOVABLE_MOVED) + ..() + +/obj/item/spacepod_equipment/cargo/large/ore/proc/spacepod_moved(obj/spacepod/SP) + if(storage) + for(var/turf/T in SP.locs) + for(var/obj/item/stack/ore in T) + ore.forceMove(storage) +*/ + +/obj/item/spacepod_equipment/cargo/chair + name = "passenger seat" + desc = "A passenger seat for a spacepod." + icon_state = "sec_cargo_chair" + var/occupant_mod = 1 + +/obj/item/spacepod_equipment/cargo/chair/on_install(obj/spacepod/SP) + ..() + SP.max_passengers += occupant_mod + +/obj/item/spacepod_equipment/cargo/chair/on_uninstall() + spacepod.max_passengers -= occupant_mod + ..() + +/obj/item/spacepod_equipment/cargo/chair/can_uninstall(mob/user) + if(spacepod.passengers.len > (spacepod.max_passengers - occupant_mod)) + to_chat(user, "You can't remove an occupied seat! Remove the occupant first.") + return FALSE + return ..() + +///////////////////////////// +////// Weapon System ////// +///////////////////////////// + +// RMNZ: Doesn't shoot (?) + +/* +/obj/item/spacepod_equipment/weaponry/disabler + name = "disabler system" + desc = "A weak disabler system for space pods, fires disabler beams." + icon_state = "weapon_taser" + projectile_type = /obj/item/projectile/beam/disabler + shot_cost = 400 + fire_sound = 'sound/weapons/taser2.ogg' + overlay_icon = 'code/modules/spacepods/icons/2x2.dmi' + overlay_icon_state = "pod_weapon_disabler" + +/obj/item/spacepod_equipment/weaponry/burst_disabler + name = "burst disabler system" + desc = "A weak disabler system for space pods, this one fires 3 at a time." + icon_state = "weapon_burst_taser" + projectile_type = /obj/item/projectile/beam/disabler + shot_cost = 1200 + shots_per = 3 + fire_sound = 'sound/weapons/taser2.ogg' + fire_delay = 30 + overlay_icon = 'code/modules/spacepods/icons/2x2.dmi' + overlay_icon_state = "pod_weapon_disabler" + +/obj/item/spacepod_equipment/weaponry/laser + name = "laser system" + desc = "A weak laser system for space pods, fires concentrated bursts of energy." + icon_state = "weapon_laser" + projectile_type = /obj/item/projectile/beam/laser + shot_cost = 600 + fire_sound = 'sound/weapons/Laser.ogg' + overlay_icon = 'code/modules/spacepods/icons/2x2.dmi' + overlay_icon_state = "pod_weapon_laser" + +// MINING LASERS +/obj/item/spacepod_equipment/weaponry/basic_pod_ka + name = "weak kinetic accelerator" + desc = "A weak kinetic accelerator for space pods, fires bursts of energy that cut through rock." + icon = 'goon/icons/obj/spacepods/parts.dmi' + icon_state = "pod_taser" + projectile_type = /obj/item/projectile/kinetic/pod + shot_cost = 300 + fire_delay = 14 + fire_sound = 'sound/weapons/Kenetic_accel.ogg' + +/obj/item/spacepod_equipment/weaponry/pod_ka + name = "kinetic accelerator system" + desc = "A kinetic accelerator system for space pods, fires bursts of energy that cut through rock." + icon = 'goon/icons/obj/spacepods/parts.dmi' + icon_state = "pod_m_laser" + projectile_type = /obj/item/projectile/kinetic/pod/regular + shot_cost = 250 + fire_delay = 10 + fire_sound = 'sound/weapons/Kenetic_accel.ogg' + +/obj/item/projectile/kinetic/pod + range = 4 + +/obj/item/projectile/kinetic/pod/regular + damage = 50 + pressure_decrease = 0.5 + +/obj/item/spacepod_equipment/weaponry/plasma_cutter + name = "plasma cutter system" + desc = "A plasma cutter system for space pods. It is capable of expelling concentrated plasma bursts to mine or cut off xeno limbs!" + icon = 'goon/icons/obj/spacepods/parts.dmi' + icon_state = "pod_p_cutter" + projectile_type = /obj/item/projectile/plasma + shot_cost = 250 + fire_delay = 10 + fire_sound = 'sound/weapons/plasma_cutter.ogg' + overlay_icon = 'code/modules/spacepods/icons/2x2.dmi' + overlay_icon_state = "pod_weapon_plasma" + +/obj/item/spacepod_equipment/weaponry/plasma_cutter/adv + name = "enhanced plasma cutter system" + desc = "An enhanced plasma cutter system for space pods. It is capable of expelling concentrated plasma bursts to mine or cut off xeno faces!" + icon_state = "pod_ap_cutter" + projectile_type = /obj/item/projectile/plasma/adv + shot_cost = 200 + fire_delay = 8 + +*/ +//////////////////////////// +////// Misc. System ////// +//////////////////////////// + +// RMNZ: No purpose (?) + +/* +/obj/item/spacepod_equipment/tracker + name = "spacepod tracking system" + desc = "A tracking device for spacepods." + icon = 'goon/icons/obj/spacepods/parts.dmi' + icon_state = "pod_locator" +*/ +/////////////////////////// +////// Lock System ////// +/////////////////////////// + +/obj/item/spacepod_equipment/lock + name = "pod lock" + desc = "You shouldn't be seeing this" + icon_state = "blank" + slot = SPACEPOD_SLOT_LOCK + +/obj/item/spacepod_equipment/lock/on_install(obj/spacepod/SP) + ..() + RegisterSignal(SP, COMSIG_PARENT_ATTACKBY, PROC_REF(spacepod_attackby)) + SP.lock = src + +/obj/item/spacepod_equipment/lock/on_uninstall() + UnregisterSignal(spacepod, COMSIG_PARENT_ATTACKBY) + if(spacepod.lock == src) + spacepod.lock = null + spacepod.locked = FALSE + ..() + +/obj/item/spacepod_equipment/lock/proc/spacepod_attackby(obj/spacepod/SP, I, mob/user) + return FALSE + +// Key and Tumbler System +/obj/item/spacepod_equipment/lock/keyed + name = "spacepod tumbler lock" + desc = "A locking system to stop podjacking. This version uses a standalone key." + icon_state = "lock_tumbler" + var/static/id_source = 0 + var/id = null + +/obj/item/spacepod_equipment/lock/keyed/Initialize(mapload) + . = ..() + if(id == null) + id = ++id_source + +/obj/item/spacepod_equipment/lock/keyed/spacepod_attackby(obj/spacepod/SP, obj/item/I, mob/user) + if(istype(I, /obj/item/spacepod_key)) + var/obj/item/spacepod_key/key = I + if(key.id == id) + SP.lock_pod() + return + else + to_chat(user, "This is the wrong key!") + return TRUE + return FALSE + +/obj/item/spacepod_equipment/lock/keyed/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/spacepod_key)) + var/obj/item/spacepod_key/key = I + if(key.id == null) + key.id = id + to_chat(user, "You grind the blank key to fit the lock.") + else + to_chat(user, "This key is already ground!") + else + ..() + +/obj/item/spacepod_equipment/lock/keyed/sec + id = "security spacepod" + +// The key +/obj/item/spacepod_key + name = "spacepod key" + desc = "A key for a spacepod lock." + icon = 'code/modules/spacepods/icons/parts.dmi' + icon_state = "podkey" + w_class = WEIGHT_CLASS_TINY + var/id = null + +/obj/item/spacepod_key/sec + name = "security spacepod key" + desc = "Unlocks the security spacepod. Probably best kept out of assistant hands." + id = "security spacepod" + +/obj/item/device/lock_buster + name = "pod lock buster" + desc = "Destroys a podlock in mere seconds once applied. Waranty void if used." + icon = 'code/modules/spacepods/icons/parts.dmi' + icon_state = "lock_buster_off" + var/on = FALSE + +/obj/item/device/lock_buster/attack_self(mob/user) + on = !on + if(on) + icon_state = "lock_buster_on" + else + icon_state = "lock_buster_off" + to_chat(user, "You turn the [src] [on ? "on" : "off"].") diff --git a/code/modules/spacepods/spacepod_parts.dm b/code/modules/spacepods/spacepod_parts.dm new file mode 100644 index 000000000000..32e098aa1aef --- /dev/null +++ b/code/modules/spacepods/spacepod_parts.dm @@ -0,0 +1,181 @@ +/obj/item/pod_parts + icon = 'goon/icons/obj/spacepods/parts.dmi' + w_class = WEIGHT_CLASS_GIGANTIC + flags = CONDUCT + +/obj/item/pod_parts/core + name = "space pod core" + icon_state = "core" + +/obj/item/pod_parts/pod_frame + name = "space pod frame" + density = FALSE + anchored = FALSE + var/link_to = null + var/link_angle = 0 + +/obj/item/pod_parts/pod_frame/attack_hand() + return + +/obj/item/pod_parts/pod_frame/Initialize(mapload) + . = ..() + AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE) + +/obj/item/pod_parts/pod_frame/proc/find_square() + /* + each part, in essence, stores the relative position of another part + you can find where this part should be by looking at the current direction of the current part and applying the link_angle + the link_angle is the angle between the part's direction and its following part, which is the current part's link_to + the code works by going in a loop - each part is capable of starting a loop by checking for the part after it, and that part checking, and so on + this 4-part loop, starting from any part of the frame, can determine if all the parts are properly in place and aligned + it also checks that each part is unique, and that all the parts are there for the spacepod itself + */ + //RMNZ: Addition of new pods + var/neededparts = list(/obj/item/pod_parts/pod_frame/aft_port, /obj/item/pod_parts/pod_frame/aft_starboard, /obj/item/pod_parts/pod_frame/fore_port, /obj/item/pod_parts/pod_frame/fore_starboard) + var/turf/T + var/obj/item/pod_parts/pod_frame/linked + var/obj/item/pod_parts/pod_frame/pointer + var/list/connectedparts = list() + neededparts -= src + linked = src + for(var/i = 1; i <= 4; i++) + T = get_turf(get_step(linked, turn(linked.dir, -linked.link_angle))) //get the next place that we want to look at + if(locate(linked.link_to) in T) + pointer = locate(linked.link_to) in T + if(istype(pointer, linked.link_to) && pointer.dir == linked.dir && pointer.anchored) + if(!(pointer in connectedparts)) + connectedparts += pointer + linked = pointer + pointer = null + if(connectedparts.len < 4) + return FALSE + for(var/i = 1; i <=4; i++) + var/obj/item/pod_parts/pod_frame/F = connectedparts[i] + if(F.type in neededparts) //if one of the items can be founded in neededparts + neededparts -= F.type + else //because neededparts has 4 distinct items, this must be called if theyre not all in place and wrenched + return FALSE + return connectedparts + +/obj/item/pod_parts/pod_frame/attackby(obj/item/O, mob/user) + if(istype(O, /obj/item/stack/rods)) + var/obj/item/stack/rods/R = O + var/list/linkedparts = find_square() + if(!linkedparts) + to_chat(user, "You cannot assemble a pod frame because you do not have the necessary assembly.") + return TRUE + if(!R.use(10)) + to_chat(user, "You need 10 rods for this.") + return TRUE + var/obj/spacepod/pod = new + pod.forceMove(loc) + switch(dir) + if(NORTH) + pod.angle = 0 + if(SOUTH) + pod.angle = 180 + if(WEST) + pod.angle = 270 + if(EAST) + pod.angle = 90 + pod.process(2) + to_chat(user, "You strut the pod frame together.") + for(var/obj/item/pod_parts/pod_frame/F in linkedparts) + if(1 == turn(F.dir, -F.link_angle)) //if the part links north during construction, as the bottom left part always does + pod.forceMove(F.loc) + qdel(F) + return TRUE + if(O.tool_behaviour == TOOL_WRENCH) + to_chat(user, "You [!anchored ? "secure \the [src] in place." : "remove the securing bolts."]") + anchored = !anchored + density = anchored + O.play_tool_sound(src) + return TRUE + +/obj/item/pod_parts/pod_frame/fore_port + name = "fore port pod frame" + icon_state = "pod_fp" + desc = "A space pod frame component. This is the fore port component." + link_to = /obj/item/pod_parts/pod_frame/fore_starboard + link_angle = 90 + +/obj/item/pod_parts/pod_frame/fore_starboard + name = "fore starboard pod frame" + icon_state = "pod_fs" + desc = "A space pod frame component. This is the fore starboard component." + link_to = /obj/item/pod_parts/pod_frame/aft_starboard + link_angle = 180 + +/obj/item/pod_parts/pod_frame/aft_port + name = "aft port pod frame" + icon_state = "pod_ap" + desc = "A space pod frame component. This is the aft port component." + link_to = /obj/item/pod_parts/pod_frame/fore_port + link_angle = 0 + +/obj/item/pod_parts/pod_frame/aft_starboard + name = "aft starboard pod frame" + icon_state = "pod_as" + desc = "A space pod frame component. This is the aft starboard component." + link_to = /obj/item/pod_parts/pod_frame/aft_port + link_angle = 270 + +/obj/item/pod_parts/armor + name = "civilian pod armor" + icon_state = "pod_armor_civ" + desc = "Spacepod armor. This is the civilian version. It looks rather flimsy." + var/pod_icon = 'goon/icons/obj/spacepods/2x2.dmi' + var/pod_icon_state = "pod_civ" + var/pod_desc = "A sleek civilian space pod." + var/pod_integrity = 250 + +/obj/item/pod_parts/armor/syndicate + name = "syndicate pod armor" + icon_state = "pod_armor_synd" + desc = "Tough-looking spacepod armor, with a bold \"FUCK NT\" stenciled directly into it." + pod_icon_state = "pod_synd" + pod_desc = "A menacing military space pod with \"FUCK NT\" stenciled onto the side" + pod_integrity = 400 + +/obj/item/pod_parts/armor/black + name = "black pod armor" + icon_state = "pod_armor_black" + desc = "Plain black spacepod armor, with no logos or insignias anywhere on it." + pod_icon_state = "pod_black" + pod_desc = "An all black space pod with no insignias." + +/obj/item/pod_parts/armor/gold + name = "golden pod armor" + icon_state = "pod_armor_gold" + desc = "Golden spacepod armor. Looks like what a rich spessmen put on their spacepod." + pod_icon_state = "pod_gold" + pod_desc = "A civilian space pod with a gold body, must have cost somebody a pretty penny" + pod_integrity = 220 + +/obj/item/pod_parts/armor/industrial + name = "industrial pod armor" + icon_state = "pod_armor_industrial" + desc = "Tough industrial-grade spacepod armor. While meant for construction work, it is commonly used in spacepod battles, too." + pod_icon_state = "pod_industrial" + pod_desc = "A rough looking space pod meant for industrial work" + pod_integrity = 330 + +/obj/item/pod_parts/armor/security + name = "security pod armor" + icon_state = "pod_armor_mil" + desc = "Tough military-grade pod armor, meant for use by the Nanotrasen military and it's sub-divisons for space combat." + pod_icon_state = "pod_mil" + pod_desc = "An armed security spacepod with reinforced armor plating brandishing the Nanotrasen Military insignia" + pod_integrity = 350 + +/obj/item/pod_parts/armor/security/red + name = "security pod armor" + icon_state = "pod_armor_synd" + desc = "Tough military-grade pod armor, meant for use by the Nanotrasen military and it's sub-divisons for space combat." + pod_icon_state = "pod_synd" + pod_desc = "An armed security spacepod with reinforced armor plating brandishing the Nanotrasen Military insignia" + pod_integrity = 350 + +/obj/item/circuitboard/mecha/pod + name = "Circuit board (Space Pod Mainboard)" + icon_state = "mainboard" diff --git a/code/modules/spacepods/spacepod_physics.dm b/code/modules/spacepods/spacepod_physics.dm new file mode 100644 index 000000000000..0330050dd381 --- /dev/null +++ b/code/modules/spacepods/spacepod_physics.dm @@ -0,0 +1,297 @@ +/obj/spacepod/process(time) + + if(world.time > last_slowprocess + 15) + last_slowprocess = world.time + slowprocess() + + var/last_offset_x = offset_x + var/last_offset_y = offset_y + var/last_angle = angle + var/desired_angular_velocity = 0 + if(isnum(desired_angle)) + // do some finagling to make sure that our angles end up rotating the short way + while(angle > desired_angle + 180) + angle -= 360 + last_angle -= 360 + while(angle < desired_angle - 180) + angle += 360 + last_angle += 360 + if(abs(desired_angle - angle) < (max_angular_acceleration * time)) + desired_angular_velocity = (desired_angle - angle) / time + else if(desired_angle > angle) + desired_angular_velocity = 2 * sqrt((desired_angle - angle) * max_angular_acceleration * 0.25) + else + desired_angular_velocity = -2 * sqrt((angle - desired_angle) * max_angular_acceleration * 0.25) + var/angular_velocity_adjustment = clamp(desired_angular_velocity - angular_velocity, -max_angular_acceleration*time, max_angular_acceleration*time) + if(angular_velocity_adjustment && cell && cell.use(abs(angular_velocity_adjustment) * 0.05)) + last_rotate = angular_velocity_adjustment / time + angular_velocity += angular_velocity_adjustment + else + last_rotate = 0 + angle += angular_velocity * time + + // calculate drag and shit + + var/velocity_mag = sqrt(velocity_x*velocity_x+velocity_y*velocity_y) // magnitude + if(velocity_mag || angular_velocity) + var/drag = 0 + for(var/turf/T in locs) + if(isspaceturf(T)) + continue + drag += 0.001 + var/floating = FALSE + if(has_gravity() && !brakes && velocity_mag > 0.1 && cell && cell.use((is_mining_level(z) ? 3 : 15) * time)) + floating = TRUE // want to fly this shit on the station? Have fun draining your battery. + if((!floating && has_gravity()) || brakes) // brakes are a kind of magboots okay? + drag += is_mining_level(z) ? 0.1 : 0.5 // some serious drag. Damn. Except lavaland, it has less gravity or something + if(velocity_mag > 5 && prob(velocity_mag * 4) && istype(T, /turf/simulated/floor)) + var/turf/simulated/floor/TF = T + TF.make_plating() // pull up some floor tiles. Stop going so fast, ree. + take_damage(3, BRUTE, MELEE, FALSE) + var/datum/gas_mixture/env = T.return_air() + if(env) + var/pressure = env.return_pressure() + drag += velocity_mag * pressure * 0.0001 // 1 atmosphere should shave off 1% of velocity per tile + if(velocity_mag > 20) + drag = max(drag, (velocity_mag - 20) / time) + if(drag) + if(velocity_mag) + var/drag_factor = 1 - clamp(drag * time / velocity_mag, 0, 1) + velocity_x *= drag_factor + velocity_y *= drag_factor + if(angular_velocity != 0) + var/drag_factor_spin = 1 - clamp(drag * 30 * time / abs(angular_velocity), 0, 1) + angular_velocity *= drag_factor_spin + + // Alright now calculate the THRUST + var/thrust_x + var/thrust_y + var/fx = cos(90 - angle) + var/fy = sin(90 - angle) + var/sx = fy + var/sy = -fx + last_thrust_forward = 0 + last_thrust_right = 0 + if(brakes) + if(user_thrust_dir) + to_chat(pilot, "Your brakes are on!") + // basically calculates how much we can brake using the thrust + var/forward_thrust = -((fx * velocity_x) + (fy * velocity_y)) / time + var/right_thrust = -((sx * velocity_x) + (sy * velocity_y)) / time + forward_thrust = clamp(forward_thrust, -backward_maxthrust, forward_maxthrust) + right_thrust = clamp(right_thrust, -side_maxthrust, side_maxthrust) + thrust_x += forward_thrust * fx + right_thrust * sx; + thrust_y += forward_thrust * fy + right_thrust * sy; + last_thrust_forward = forward_thrust + last_thrust_right = right_thrust + else // want some sort of help piloting the ship? Haha no fuck you do it yourself + if(user_thrust_dir & NORTH) + thrust_x += fx * forward_maxthrust + thrust_y += fy * forward_maxthrust + last_thrust_forward = forward_maxthrust + if(user_thrust_dir & SOUTH) + thrust_x -= fx * backward_maxthrust + thrust_y -= fy * backward_maxthrust + last_thrust_forward = -backward_maxthrust + if(user_thrust_dir & EAST) + thrust_x += sx * side_maxthrust + thrust_y += sy * side_maxthrust + last_thrust_right = side_maxthrust + if(user_thrust_dir & WEST) + thrust_x -= sx * side_maxthrust + thrust_y -= sy * side_maxthrust + last_thrust_right = -side_maxthrust + + if(cell && cell.use(10 * sqrt((thrust_x*thrust_x)+(thrust_y*thrust_y)) * time)) + velocity_x += thrust_x * time + velocity_y += thrust_y * time + else + last_thrust_forward = 0 + last_thrust_right = 0 + if(!brakes && user_thrust_dir) + to_chat(pilot, "You are out of power!") + + offset_x += velocity_x * time + offset_y += velocity_y * time + // alright so now we reconcile the offsets with the in-world position. + while((offset_x > 0 && velocity_x > 0) || (offset_y > 0 && velocity_y > 0) || (offset_x < 0 && velocity_x < 0) || (offset_y < 0 && velocity_y < 0)) + var/failed_x = FALSE + var/failed_y = FALSE + if(offset_x > 0 && velocity_x > 0) + dir = EAST + if(!Move(get_step(src, EAST))) + offset_x = 0 + failed_x = TRUE + velocity_x *= -bounce_factor + velocity_y *= lateral_bounce_factor + else + offset_x-- + last_offset_x-- + else if(offset_x < 0 && velocity_x < 0) + dir = WEST + if(!Move(get_step(src, WEST))) + offset_x = 0 + failed_x = TRUE + velocity_x *= -bounce_factor + velocity_y *= lateral_bounce_factor + else + offset_x++ + last_offset_x++ + else + failed_x = TRUE + if(offset_y > 0 && velocity_y > 0) + dir = NORTH + if(!Move(get_step(src, NORTH))) + offset_y = 0 + failed_y = TRUE + velocity_y *= -bounce_factor + velocity_x *= lateral_bounce_factor + else + offset_y-- + last_offset_y-- + else if(offset_y < 0 && velocity_y < 0) + dir = SOUTH + if(!Move(get_step(src, SOUTH))) + offset_y = 0 + failed_y = TRUE + velocity_y *= -bounce_factor + velocity_x *= lateral_bounce_factor + else + offset_y++ + last_offset_y++ + else + failed_y = TRUE + if(failed_x && failed_y) + break + // prevents situations where you go "wtf I'm clearly right next to it" as you enter a stationary spacepod + if(velocity_x == 0) + if(offset_x > 0.5) + if(Move(get_step(src, EAST))) + offset_x-- + last_offset_x-- + else + offset_x = 0 + if(offset_x < -0.5) + if(Move(get_step(src, WEST))) + offset_x++ + last_offset_x++ + else + offset_x = 0 + if(velocity_y == 0) + if(offset_y > 0.5) + if(Move(get_step(src, NORTH))) + offset_y-- + last_offset_y-- + else + offset_y = 0 + if(offset_y < -0.5) + if(Move(get_step(src, SOUTH))) + offset_y++ + last_offset_y++ + else + offset_y = 0 + dir = NORTH + var/matrix/mat_from = new() + mat_from.Turn(last_angle) + var/matrix/mat_to = new() + mat_to.Turn(angle) + transform = mat_from + pixel_x = last_offset_x*32 + pixel_y = last_offset_y*32 + animate(src, transform=mat_to, pixel_x = offset_x*32, pixel_y = offset_y*32, time = time SECONDS, flags=ANIMATION_END_NOW) + for(var/mob/living/M in contents) + var/client/C = M.client + if(!C) + continue + C.pixel_x = last_offset_x*32 + C.pixel_y = last_offset_y*32 + animate(C, pixel_x = offset_x*32, pixel_y = offset_y*32, time = time SECONDS, flags=ANIMATION_END_NOW) + user_thrust_dir = 0 + update_appearance(UPDATE_ICON) + +/obj/spacepod/Bumped(atom/movable/A) // RMNZ: Thrown items or pushable objects slightly move pods though + if(ismob(A)) // I don't like it when little silly humans can move these pods + return + if(A.dir & NORTH) + velocity_y += bump_impulse + if(A.dir & SOUTH) + velocity_y -= bump_impulse + if(A.dir & EAST) + velocity_x += bump_impulse + if(A.dir & WEST) + velocity_x -= bump_impulse + return ..() + +/obj/spacepod/Bump(atom/A) + var/bump_velocity = 0 + if(dir & (NORTH|SOUTH)) + bump_velocity = abs(velocity_y) + (abs(velocity_x) / 15) + else + bump_velocity = abs(velocity_x) + (abs(velocity_y) / 15) + if(istype(A, /obj/machinery/door/airlock)) // try to open doors + var/obj/machinery/door/D = A + if(!D.operating) + if(D.allowed(D.requiresID() ? pilot : null)) + spawn(0) + D.open() + else + D.do_animate("deny") + var/atom/movable/AM = A + if(istype(AM) && !AM.anchored && bump_velocity > 1) + step(AM, dir) + // if a bump is that fast then it's not a bump. It's a collision. + if(bump_velocity > 10 && !ismob(A)) + var/strength = bump_velocity / 10 + strength = strength * strength + strength = min(strength, 5) // don't want the explosions *too* big + // wew lad, might wanna slow down there + explosion(A, -1, round((strength - 1) / 2), round(strength)) + message_admins("[key_name_admin(pilot)] has impacted a spacepod into [A] with velocity [bump_velocity]") + take_damage(strength*10, BRUTE, MELEE, TRUE) + log_game("[key_name(pilot)] has impacted a spacepod into [A] with velocity [bump_velocity]") + visible_message("The force of the impact causes a shockwave") + else if(isliving(A) && bump_velocity > 5) + var/mob/living/M = A + M.apply_damage(bump_velocity * 2) + take_damage(bump_velocity, BRUTE, MELEE, FALSE) + playsound(M.loc, "swing_hit", 1000, 1, -1) + M.KnockOut() + M.visible_message("The force of the impact knocks [M] down!", "The force of the impact knocks you down!") + add_attack_logs(pilot, M, "impacted", src, "with velocity of [bump_velocity]") + return ..() + +/obj/spacepod/proc/fire_projectiles(proj_type, target) // if spacepods of other sizes are added override this or something + var/fx = cos(90 - angle) + var/fy = sin(90 - angle) + var/sx = fy + var/sy = -fx + var/ox = (offset_x * 32) + 16 + var/oy = (offset_y * 32) + 16 + var/list/origins = list(list(ox + fx*16 - sx*16, oy + fy*16 - sy*16), list(ox + fx*16 + sx*16, oy + fy*16 + sy*16)) + for(var/list/origin in origins) + var/this_x = origin[1] + var/this_y = origin[2] + var/turf/T = get_turf(src) + while(this_x > 16) + T = get_step(T, EAST) + this_x -= 32 + while(this_x < -16) + T = get_step(T, WEST) + this_x += 32 + while(this_y > 16) + T = get_step(T, NORTH) + this_y -= 32 + while(this_y < -16) + T = get_step(T, SOUTH) + this_y += 32 + if(!T) + continue + var/obj/item/projectile/proj = new proj_type(T) + proj.starting = T + proj.firer = usr + proj.def_zone = "chest" + proj.original = target + proj.pixel_x = round(this_x) + proj.pixel_y = round(this_y) + spawn() + proj.fire(angle) diff --git a/code/modules/spacepods/spacepod_prebuilt.dm b/code/modules/spacepods/spacepod_prebuilt.dm new file mode 100644 index 000000000000..c1b42bb1a5ab --- /dev/null +++ b/code/modules/spacepods/spacepod_prebuilt.dm @@ -0,0 +1,64 @@ +/obj/spacepod/prebuilt + icon = 'goon/icons/obj/spacepods/2x2.dmi' + icon_state = "pod_civ" + var/cell_type = /obj/item/stock_parts/cell/high/plus + var/armor_type = /obj/item/pod_parts/armor + var/internal_tank_type = /obj/machinery/atmospherics/portable/canister/air + var/equipment_types = list() + construction_state = SPACEPOD_ARMOR_WELDED + +/obj/spacepod/prebuilt/Initialize(mapload) + . =..() + add_armor(new armor_type(src)) + if(cell_type) + cell = new cell_type(src) + if(internal_tank_type) + internal_tank = new internal_tank_type(src) + for(var/equip in equipment_types) + var/obj/item/spacepod_equipment/SE = new equip(src) + SE.on_install(src) + +/obj/spacepod/prebuilt/sec + name = "security space pod" + icon_state = "pod_mil" + locked = TRUE + armor_type = /obj/item/pod_parts/armor/security + equipment_types = list(/obj/item/spacepod_equipment/weaponry/disabler, + /obj/item/spacepod_equipment/lock/keyed/sec, + /obj/item/spacepod_equipment/tracker, + /obj/item/spacepod_equipment/cargo/chair) + +// adminbus spacepod for jousting events +/obj/spacepod/prebuilt/jousting + name = "jousting space pod" + icon_state = "pod_mil" + armor_type = /obj/item/pod_parts/armor/security + cell_type = /obj/item/stock_parts/cell/infinite + equipment_types = list(/obj/item/spacepod_equipment/weaponry/laser, + /obj/item/spacepod_equipment/cargo/chair, + /obj/item/spacepod_equipment/cargo/chair) + +/obj/spacepod/prebuilt/jousting/red + icon_state = "pod_synd" + armor_type = /obj/item/pod_parts/armor/security/red + +/obj/spacepod/random + icon = 'goon/icons/obj/spacepods/2x2.dmi' + icon_state = "pod_civ" + construction_state = SPACEPOD_ARMOR_WELDED + +/obj/spacepod/random/Initialize(mapload) + . = ..() + var/armor_type = pick(/obj/item/pod_parts/armor, + /obj/item/pod_parts/armor/syndicate, + /obj/item/pod_parts/armor/black, + /obj/item/pod_parts/armor/gold, + /obj/item/pod_parts/armor/industrial, + /obj/item/pod_parts/armor/security) + add_armor(new armor_type(src)) + cell = new /obj/item/stock_parts/cell/high/empty(src) + internal_tank = new /obj/machinery/atmospherics/portable/canister/air(src) + velocity_x = rand(-3, 3) + velocity_y = rand(-3, 3) + obj_integrity = rand(100, max_integrity) + brakes = FALSE diff --git a/goon/icons/obj/spacepods/2x2.dmi b/goon/icons/obj/spacepods/2x2.dmi new file mode 100644 index 0000000000000000000000000000000000000000..02def41cf1bc43bf9a86c41adc898a1f16504cde GIT binary patch literal 7679 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 XjZR|H`S literal 0 HcmV?d00001 diff --git a/paradise.dme b/paradise.dme index bb26fe9f3eaf..daa8787dd3ff 100644 --- a/paradise.dme +++ b/paradise.dme @@ -98,6 +98,7 @@ #include "code\__DEFINES\rolebans.dm" #include "code\__DEFINES\rust_g.dm" #include "code\__DEFINES\shuttle_defines.dm" +#include "code\__DEFINES\spacepods.dm" #include "code\__DEFINES\sight.dm" #include "code\__DEFINES\sound_defines.dm" #include "code\__DEFINES\spell_defines.dm" @@ -316,6 +317,7 @@ #include "code\controllers\subsystem\processing\fields.dm" #include "code\controllers\subsystem\processing\instruments.dm" #include "code\controllers\subsystem\processing\obj.dm" +#include "code\controllers\subsystem\processing\spacepods.dm" #include "code\controllers\subsystem\processing\processing.dm" #include "code\controllers\subsystem\processing\projectiles.dm" #include "code\controllers\subsystem\processing\SSstation.dm" @@ -394,6 +396,7 @@ #include "code\datums\components\paintable.dm" #include "code\datums\components\parry.dm" #include "code\datums\components\persistent_overlay.dm" +#include "code\datums\components\rotation.dm" #include "code\datums\components\proximity_monitor.dm" #include "code\datums\components\radioactive.dm" #include "code\datums\components\shielded.dm" @@ -2636,6 +2639,7 @@ #include "code\modules\research\designs\mining_designs.dm" #include "code\modules\research\designs\misc_designs.dm" #include "code\modules\research\designs\modsuit_designs.dm" +#include "code\modules\research\designs\spacepod_designs.dm" #include "code\modules\research\designs\power_designs.dm" #include "code\modules\research\designs\smelting_designs.dm" #include "code\modules\research\designs\stock_parts_designs.dm" @@ -2678,9 +2682,16 @@ #include "code\modules\shuttle\syndicate_shuttles.dm" #include "code\modules\space_management\heap_space_level.dm" #include "code\modules\space_management\level_check.dm" +#include "code\modules\spacepods\spacepod_actions.dm" #include "code\modules\space_management\level_traits.dm" #include "code\modules\space_management\space_chunk.dm" #include "code\modules\space_management\space_level.dm" +#include "code\modules\spacepods\spacepod_equipment.dm" +#include "code\modules\spacepods\spacepod_parts.dm" +#include "code\modules\spacepods\spacepod.dm" +#include "code\modules\spacepods\spacepod_construction.dm" +#include "code\modules\spacepods\spacepod_physics.dm" +#include "code\modules\spacepods\spacepod_prebuilt.dm" #include "code\modules\space_management\space_transition.dm" #include "code\modules\space_management\zlevel_manager.dm" #include "code\modules\station_goals\bluespace_tap.dm" From fd70b1cf67b844e5a8550d03128ca02935b7fe0f Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Fri, 2 Feb 2024 21:30:19 +0800 Subject: [PATCH 03/28] Small oversight from me --- code/modules/spacepods/spacepod.dm | 8 ++++---- code/modules/spacepods/spacepod_prebuilt.dm | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/code/modules/spacepods/spacepod.dm b/code/modules/spacepods/spacepod.dm index 8e6fbd8e2d92..f641a02b0985 100644 --- a/code/modules/spacepods/spacepod.dm +++ b/code/modules/spacepods/spacepod.dm @@ -121,8 +121,8 @@ GLOBAL_LIST_INIT(spacepods_list, list()) var/list/params_list = params2list(params) if(target == src || istype(target, /atom/movable/screen) || (target && (target in user.get_contents())) || user != pilot || params_list["shift"] || params_list["alt"] || params_list["ctrl"]) return FALSE - if(weapon) - weapon.fire_weapons(target) + // if(weapon) // RMNZ: As i said, weapons don't work for now + // weapon.fire_weapons(target) return TRUE /obj/spacepod/proc/enter_pod(mob/living/user) @@ -611,8 +611,8 @@ GLOBAL_LIST_INIT(spacepods_list, list()) if(obj_integrity <= max_integrity / 4) . += image(icon='goon/icons/obj/spacepods/2x2.dmi', icon_state="pod_fire") - if(weapon && weapon.overlay_icon_state) - . += image(icon=weapon.overlay_icon,icon_state=weapon.overlay_icon_state) + // if(weapon && weapon.overlay_icon_state) // RMNZ: Weapons don't work for now! + // . += image(icon=weapon.overlay_icon,icon_state=weapon.overlay_icon_state) light_color = icon_light_color[icon_state] || LIGHT_COLOR_WHITE diff --git a/code/modules/spacepods/spacepod_prebuilt.dm b/code/modules/spacepods/spacepod_prebuilt.dm index c1b42bb1a5ab..8e592c1a3311 100644 --- a/code/modules/spacepods/spacepod_prebuilt.dm +++ b/code/modules/spacepods/spacepod_prebuilt.dm @@ -23,9 +23,10 @@ icon_state = "pod_mil" locked = TRUE armor_type = /obj/item/pod_parts/armor/security - equipment_types = list(/obj/item/spacepod_equipment/weaponry/disabler, + equipment_types = list( + // /obj/item/spacepod_equipment/weaponry/disabler, //RMNZ: Weapons don't work for now! /obj/item/spacepod_equipment/lock/keyed/sec, - /obj/item/spacepod_equipment/tracker, + // /obj/item/spacepod_equipment/tracker, //RMNZ: And this too! /obj/item/spacepod_equipment/cargo/chair) // adminbus spacepod for jousting events @@ -34,7 +35,8 @@ icon_state = "pod_mil" armor_type = /obj/item/pod_parts/armor/security cell_type = /obj/item/stock_parts/cell/infinite - equipment_types = list(/obj/item/spacepod_equipment/weaponry/laser, + equipment_types = list( + // /obj/item/spacepod_equipment/weaponry/laser, //RMNZ: Weapons don't work for now! /obj/item/spacepod_equipment/cargo/chair, /obj/item/spacepod_equipment/cargo/chair) From c1aa0da752bc1e9dc1344f32d8c32cd257f90fd4 Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Fri, 2 Feb 2024 21:55:05 +0800 Subject: [PATCH 04/28] Testmerge "is_helpers" fix + Indentation fix --- code/__DEFINES/is_helpers.dm | 2 -- code/modules/mob/living/living.dm | 1 + code/modules/spacepods/spacepod.dm | 10 +++++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index fa918c4d41f9..e73af05c7d61 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -52,8 +52,6 @@ #define ismecha(A) (istype(A, /obj/mecha)) -#define isspacepod(A) (istype(A, /obj/spacepod)) - #define iseffect(A) (istype(A, /obj/effect)) #define isclothing(A) (istype(A, /obj/item/clothing)) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 681ff41bdbe2..0e8c5c72d7fc 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -926,6 +926,7 @@ var/obj/mecha/M = loc loc_temp = M.return_temperature() + #define isspacepod(A) (istype(A, /obj/spacepod)) // RMNZ: Temporary solution for testmerge. Should be in is_helpers else if(isspacepod(loc)) var/obj/spacepod/S = loc loc_temp = S.return_temperature() diff --git a/code/modules/spacepods/spacepod.dm b/code/modules/spacepods/spacepod.dm index f641a02b0985..c37d6b3e6bd9 100644 --- a/code/modules/spacepods/spacepod.dm +++ b/code/modules/spacepods/spacepod.dm @@ -77,11 +77,11 @@ GLOBAL_LIST_INIT(spacepods_list, list()) var/lights = 0 var/lights_power = 6 var/static/list/icon_light_color = list("pod_civ" = LIGHT_COLOR_WHITE, \ - "pod_mil" = "#BBF093", \ - "pod_synd" = LIGHT_COLOR_RED, \ - "pod_gold" = LIGHT_COLOR_WHITE, \ - "pod_black" = "#3B8FE5", \ - "pod_industrial" = "#CCCC00") + "pod_mil" = "#BBF093", \ + "pod_synd" = LIGHT_COLOR_RED, \ + "pod_gold" = LIGHT_COLOR_WHITE, \ + "pod_black" = "#3B8FE5", \ + "pod_industrial" = "#CCCC00") var/bump_impulse = 0.6 var/bounce_factor = 0.2 // how much of our velocity to keep on collision From b53b4f88d0829df5251a5c7ce76cde6b0e752e9a Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Fri, 2 Feb 2024 22:08:36 +0800 Subject: [PATCH 05/28] Small linter fix --- .../subsystem/processing/{spacepods.dm => spacepod.dm} | 4 ++-- code/modules/spacepods/spacepod.dm | 2 +- paradise.dme | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename code/controllers/subsystem/processing/{spacepods.dm => spacepod.dm} (87%) diff --git a/code/controllers/subsystem/processing/spacepods.dm b/code/controllers/subsystem/processing/spacepod.dm similarity index 87% rename from code/controllers/subsystem/processing/spacepods.dm rename to code/controllers/subsystem/processing/spacepod.dm index 036beea2fa4d..7c8846a79806 100644 --- a/code/controllers/subsystem/processing/spacepods.dm +++ b/code/controllers/subsystem/processing/spacepod.dm @@ -5,8 +5,8 @@ // RMNZ: Maybe performance issues? -PROCESSING_SUBSYSTEM_DEF(spacepods) - name = "Spacepods" +PROCESSING_SUBSYSTEM_DEF(spacepod) + name = "Spacepod" wait = 0.075 stat_tag = "SP" offline_implications = "Spacepods will no longer process. Shuttle call recommended." diff --git a/code/modules/spacepods/spacepod.dm b/code/modules/spacepods/spacepod.dm index c37d6b3e6bd9..e0db75c01d8c 100644 --- a/code/modules/spacepods/spacepod.dm +++ b/code/modules/spacepods/spacepod.dm @@ -90,7 +90,7 @@ GLOBAL_LIST_INIT(spacepods_list, list()) /obj/spacepod/Initialize(mapload) . = ..() GLOB.spacepods_list += src - START_PROCESSING(SSspacepods, src) + START_PROCESSING(SSspacepod, src) cabin_air = new cabin_air.temperature = T20C cabin_air.volume = 200 diff --git a/paradise.dme b/paradise.dme index daa8787dd3ff..ae619715ae80 100644 --- a/paradise.dme +++ b/paradise.dme @@ -317,7 +317,7 @@ #include "code\controllers\subsystem\processing\fields.dm" #include "code\controllers\subsystem\processing\instruments.dm" #include "code\controllers\subsystem\processing\obj.dm" -#include "code\controllers\subsystem\processing\spacepods.dm" +#include "code\controllers\subsystem\processing\spacepod.dm" #include "code\controllers\subsystem\processing\processing.dm" #include "code\controllers\subsystem\processing\projectiles.dm" #include "code\controllers\subsystem\processing\SSstation.dm" From ce4ddd8c0b86ffa82c0b71be65ca8ad46c7dfdd7 Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Fri, 2 Feb 2024 22:14:25 +0800 Subject: [PATCH 06/28] Small linter fix x2 --- code/modules/spacepods/{spacepod.dm => spacepods.dm} | 0 paradise.dme | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename code/modules/spacepods/{spacepod.dm => spacepods.dm} (100%) diff --git a/code/modules/spacepods/spacepod.dm b/code/modules/spacepods/spacepods.dm similarity index 100% rename from code/modules/spacepods/spacepod.dm rename to code/modules/spacepods/spacepods.dm diff --git a/paradise.dme b/paradise.dme index ae619715ae80..412a9629d90c 100644 --- a/paradise.dme +++ b/paradise.dme @@ -2688,7 +2688,7 @@ #include "code\modules\space_management\space_level.dm" #include "code\modules\spacepods\spacepod_equipment.dm" #include "code\modules\spacepods\spacepod_parts.dm" -#include "code\modules\spacepods\spacepod.dm" +#include "code\modules\spacepods\spacepods.dm" #include "code\modules\spacepods\spacepod_construction.dm" #include "code\modules\spacepods\spacepod_physics.dm" #include "code\modules\spacepods\spacepod_prebuilt.dm" From 357bec6ec96ea571cec57b9a59de84864eb496fc Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Fri, 2 Feb 2024 22:20:33 +0800 Subject: [PATCH 07/28] Small linter fix x3 --- code/__DEFINES/{spacepods.dm => spacepods_defines.dm} | 0 paradise.dme | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename code/__DEFINES/{spacepods.dm => spacepods_defines.dm} (100%) diff --git a/code/__DEFINES/spacepods.dm b/code/__DEFINES/spacepods_defines.dm similarity index 100% rename from code/__DEFINES/spacepods.dm rename to code/__DEFINES/spacepods_defines.dm diff --git a/paradise.dme b/paradise.dme index 412a9629d90c..ad7df06945f5 100644 --- a/paradise.dme +++ b/paradise.dme @@ -98,7 +98,7 @@ #include "code\__DEFINES\rolebans.dm" #include "code\__DEFINES\rust_g.dm" #include "code\__DEFINES\shuttle_defines.dm" -#include "code\__DEFINES\spacepods.dm" +#include "code\__DEFINES\spacepods_defines.dm" #include "code\__DEFINES\sight.dm" #include "code\__DEFINES\sound_defines.dm" #include "code\__DEFINES\spell_defines.dm" From 3334f27b0e28b6eed8611edb551c6d88a8d4e178 Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Sat, 3 Feb 2024 03:44:34 +0800 Subject: [PATCH 08/28] Spacepods Test Map --- code/modules/spacepods/spacepods.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/spacepods/spacepods.dm b/code/modules/spacepods/spacepods.dm index e0db75c01d8c..12cad63315bc 100644 --- a/code/modules/spacepods/spacepods.dm +++ b/code/modules/spacepods/spacepods.dm @@ -177,7 +177,7 @@ GLOBAL_LIST_INIT(spacepods_list, list()) pilot = M LAZYOR(M.mousemove_intercept_objects, src) M.click_intercept = src - // GrantActions(M) + GrantActions(M) // addverbs(M) else if(passengers.len < max_passengers) passengers += M From 866ba4c5f090dbc5d305deae311b0d5a506b54e2 Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Fri, 2 Feb 2024 22:20:33 +0800 Subject: [PATCH 09/28] Action buttons possible fix --- code/__DEFINES/{spacepods.dm => spacepods_defines.dm} | 0 code/modules/spacepods/spacepods.dm | 2 +- paradise.dme | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename code/__DEFINES/{spacepods.dm => spacepods_defines.dm} (100%) diff --git a/code/__DEFINES/spacepods.dm b/code/__DEFINES/spacepods_defines.dm similarity index 100% rename from code/__DEFINES/spacepods.dm rename to code/__DEFINES/spacepods_defines.dm diff --git a/code/modules/spacepods/spacepods.dm b/code/modules/spacepods/spacepods.dm index e0db75c01d8c..12cad63315bc 100644 --- a/code/modules/spacepods/spacepods.dm +++ b/code/modules/spacepods/spacepods.dm @@ -177,7 +177,7 @@ GLOBAL_LIST_INIT(spacepods_list, list()) pilot = M LAZYOR(M.mousemove_intercept_objects, src) M.click_intercept = src - // GrantActions(M) + GrantActions(M) // addverbs(M) else if(passengers.len < max_passengers) passengers += M diff --git a/paradise.dme b/paradise.dme index 412a9629d90c..ad7df06945f5 100644 --- a/paradise.dme +++ b/paradise.dme @@ -98,7 +98,7 @@ #include "code\__DEFINES\rolebans.dm" #include "code\__DEFINES\rust_g.dm" #include "code\__DEFINES\shuttle_defines.dm" -#include "code\__DEFINES\spacepods.dm" +#include "code\__DEFINES\spacepods_defines.dm" #include "code\__DEFINES\sight.dm" #include "code\__DEFINES\sound_defines.dm" #include "code\__DEFINES\spell_defines.dm" From 8bc5ad9a54a42bb79d7a49372688e6a951b86428 Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Sat, 3 Feb 2024 05:41:26 +0800 Subject: [PATCH 10/28] Action-buttons possible fix x2 --- code/modules/spacepods/spacepods.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/spacepods/spacepods.dm b/code/modules/spacepods/spacepods.dm index 12cad63315bc..aa80881f8e51 100644 --- a/code/modules/spacepods/spacepods.dm +++ b/code/modules/spacepods/spacepods.dm @@ -181,6 +181,7 @@ GLOBAL_LIST_INIT(spacepods_list, list()) // addverbs(M) else if(passengers.len < max_passengers) passengers += M + GrantActions(M) else return FALSE GrantActions(M) // Passengers have buttons now From 928848580f46a4a8be15f382bb92753c7521a5a2 Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Tue, 6 Feb 2024 19:00:05 +0800 Subject: [PATCH 11/28] Runtime error possible fix 1 / 2 --- code/_onclick/drag_drop.dm | 2 +- code/_onclick/hud/map_popups.dm | 2 +- code/modules/spacepods/spacepods.dm | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm index 90af86729836..b0b032fc6b35 100644 --- a/code/_onclick/drag_drop.dm +++ b/code/_onclick/drag_drop.dm @@ -49,7 +49,7 @@ to inform the game this action was expected and its fine /atom/proc/MouseDrop_T(atom/dropping, mob/user, params) // return TRUE if you want to prevent us click the object after it return -/client/MouseMove(object,location,control,params) +/client/MouseMove(object, location, control, params) mouseParams = params mouse_location_ref = location mouse_object_ref = object diff --git a/code/_onclick/hud/map_popups.dm b/code/_onclick/hud/map_popups.dm index 9c2bc9b148ce..1d56e2dd1b88 100644 --- a/code/_onclick/hud/map_popups.dm +++ b/code/_onclick/hud/map_popups.dm @@ -7,7 +7,7 @@ */ var/list/screen_maps = list() - var/mouseParams = "" + var/mouseParams = null ///Used in MouseDrag to preserve the last mouse-entered location var/datum/mouse_location_ref = null ///Used in MouseDrag to preserve the last mouse-entered object diff --git a/code/modules/spacepods/spacepods.dm b/code/modules/spacepods/spacepods.dm index aa80881f8e51..59bbc9bd195b 100644 --- a/code/modules/spacepods/spacepods.dm +++ b/code/modules/spacepods/spacepods.dm @@ -542,13 +542,13 @@ GLOBAL_LIST_INIT(spacepods_list, list()) ////// Movement procs ////// ////////////////////////////// -/obj/spacepod/onMouseMove(object,location,control,params) - if(!pilot || !pilot.client || pilot.incapacitated()) +/obj/spacepod/onMouseMove(object, location, control, params) + if(!pilot || !pilot.client || pilot.incapacitated() || params == null) return // I don't know what's going on. - var/list/params_list = params2list(params) - var/sl_list = splittext(params_list["screen-loc"],",") - var/sl_x_list = splittext(sl_list[1], ":") - var/sl_y_list = splittext(sl_list[2], ":") + var/list/params_list = params2list(params) // icon-x, icon-y, screen-loc + var/sl_list = splittext(params_list["screen-loc"],",") // get only screen-loc + var/sl_x_list = splittext(sl_list[1], ":") // sl-x[1] = tile, sl-x[2] = pixel on tile + var/sl_y_list = splittext(sl_list[2], ":") // sl-y[1] = tile, sl-y[2] = pixel on tile var/view_list = isnum(pilot.client.view) ? list("[pilot.client.view*2+1]","[pilot.client.view*2+1]") : splittext(pilot.client.view, "x") var/dx = text2num(sl_x_list[1]) + (text2num(sl_x_list[2]) / world.icon_size) - 1 - text2num(view_list[1]) / 2 var/dy = text2num(sl_y_list[1]) + (text2num(sl_y_list[2]) / world.icon_size) - 1 - text2num(view_list[2]) / 2 From f023f7c4f5dd6c25461f76782983e276c41f0e9f Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Tue, 6 Feb 2024 19:13:16 +0800 Subject: [PATCH 12/28] Make em slower --- code/modules/spacepods/spacepods.dm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/modules/spacepods/spacepods.dm b/code/modules/spacepods/spacepods.dm index 59bbc9bd195b..fbc368784492 100644 --- a/code/modules/spacepods/spacepods.dm +++ b/code/modules/spacepods/spacepods.dm @@ -70,8 +70,9 @@ GLOBAL_LIST_INIT(spacepods_list, list()) var/brakes = TRUE var/user_thrust_dir = 0 - var/forward_maxthrust = 6 - var/backward_maxthrust = 3 + // Spacepod speed + var/forward_maxthrust = 2 + var/backward_maxthrust = 1 var/side_maxthrust = 1 var/lights = 0 From 8858d7a25a4ee724d8bea712623e1ad5c48ceb7f Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Tue, 6 Feb 2024 20:01:12 +0800 Subject: [PATCH 13/28] Mass comment update --- code/datums/components/rotation.dm | 3 ++- code/modules/spacepods/spacepod_construction.dm | 2 +- code/modules/spacepods/spacepod_parts.dm | 1 - code/modules/spacepods/spacepod_physics.dm | 2 +- code/modules/spacepods/spacepod_prebuilt.dm | 2 +- code/modules/spacepods/spacepods.dm | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/code/datums/components/rotation.dm b/code/datums/components/rotation.dm index fc023da258cb..162791eda3a5 100644 --- a/code/datums/components/rotation.dm +++ b/code/datums/components/rotation.dm @@ -129,7 +129,8 @@ after_rotation.Invoke(user,rotation_type) /datum/component/simple_rotation/proc/default_can_user_rotate(mob/living/user, rotation_type) - //RMNZ: Check if be_close needed or not + //RMNZ: Check if be_close needed or not (NO_DEXTERY isn't used in this build it seems) + // if(!istype(user) || !user.canUseTopic(parent, BE_CLOSE, NO_DEXTERY)) if(!istype(user) || !user.can_use(parent)) return FALSE return TRUE diff --git a/code/modules/spacepods/spacepod_construction.dm b/code/modules/spacepods/spacepod_construction.dm index b8db43e49bd5..349cf37d43f0 100644 --- a/code/modules/spacepods/spacepod_construction.dm +++ b/code/modules/spacepods/spacepod_construction.dm @@ -140,7 +140,7 @@ . = TRUE W.play_tool_sound(src) construction_state-- - // RMNZ: Test this thing out + // RMNZ: Test this. Should be five metal sheets to construct var/obj/item/stack/sheet/metal/M = new M.amount = 5 M.forceMove(loc) diff --git a/code/modules/spacepods/spacepod_parts.dm b/code/modules/spacepods/spacepod_parts.dm index 32e098aa1aef..2e98272c29de 100644 --- a/code/modules/spacepods/spacepod_parts.dm +++ b/code/modules/spacepods/spacepod_parts.dm @@ -30,7 +30,6 @@ this 4-part loop, starting from any part of the frame, can determine if all the parts are properly in place and aligned it also checks that each part is unique, and that all the parts are there for the spacepod itself */ - //RMNZ: Addition of new pods var/neededparts = list(/obj/item/pod_parts/pod_frame/aft_port, /obj/item/pod_parts/pod_frame/aft_starboard, /obj/item/pod_parts/pod_frame/fore_port, /obj/item/pod_parts/pod_frame/fore_starboard) var/turf/T var/obj/item/pod_parts/pod_frame/linked diff --git a/code/modules/spacepods/spacepod_physics.dm b/code/modules/spacepods/spacepod_physics.dm index 0330050dd381..46b4368ed831 100644 --- a/code/modules/spacepods/spacepod_physics.dm +++ b/code/modules/spacepods/spacepod_physics.dm @@ -255,7 +255,7 @@ M.apply_damage(bump_velocity * 2) take_damage(bump_velocity, BRUTE, MELEE, FALSE) playsound(M.loc, "swing_hit", 1000, 1, -1) - M.KnockOut() + M.KnockOut() // RMNZ: Knockout WAY too long M.visible_message("The force of the impact knocks [M] down!", "The force of the impact knocks you down!") add_attack_logs(pilot, M, "impacted", src, "with velocity of [bump_velocity]") return ..() diff --git a/code/modules/spacepods/spacepod_prebuilt.dm b/code/modules/spacepods/spacepod_prebuilt.dm index 8e592c1a3311..74aa3fab6644 100644 --- a/code/modules/spacepods/spacepod_prebuilt.dm +++ b/code/modules/spacepods/spacepod_prebuilt.dm @@ -26,7 +26,7 @@ equipment_types = list( // /obj/item/spacepod_equipment/weaponry/disabler, //RMNZ: Weapons don't work for now! /obj/item/spacepod_equipment/lock/keyed/sec, - // /obj/item/spacepod_equipment/tracker, //RMNZ: And this too! + // /obj/item/spacepod_equipment/tracker, //RMNZ: Tracker doesn't have purpose! /obj/item/spacepod_equipment/cargo/chair) // adminbus spacepod for jousting events diff --git a/code/modules/spacepods/spacepods.dm b/code/modules/spacepods/spacepods.dm index fbc368784492..816ea22557b3 100644 --- a/code/modules/spacepods/spacepods.dm +++ b/code/modules/spacepods/spacepods.dm @@ -130,7 +130,7 @@ GLOBAL_LIST_INIT(spacepods_list, list()) if(user.stat != CONSCIOUS) return FALSE - if(locked) // RMNZ: You also check your health on this + if(locked) // RMNZ: You also show health of your mob in chat to_chat(user, "[src]'s doors are locked!") return FALSE @@ -466,7 +466,7 @@ GLOBAL_LIST_INIT(spacepods_list, list()) target_dir = SOUTH if(270) target_dir = WEST - //RMNZ: Addition of new pods 2 + //RMNZ: Count this for addition of new pods (?) var/list/frame_piece_types = list(/obj/item/pod_parts/pod_frame/aft_port, /obj/item/pod_parts/pod_frame/aft_starboard, /obj/item/pod_parts/pod_frame/fore_port, /obj/item/pod_parts/pod_frame/fore_starboard) var/obj/item/pod_parts/pod_frame/current_piece = null var/turf/CT = get_turf(src) From 990698aad4b2191625cc92137ba6c9a121bc9b94 Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Fri, 2 Feb 2024 20:35:59 +0800 Subject: [PATCH 14/28] Spacepods? --- code/__DEFINES/is_helpers.dm | 2 + code/__DEFINES/layers.dm | 1 + code/__DEFINES/spacepods.dm | 18 + code/__HELPERS/lists.dm | 2 + code/_onclick/drag_drop.dm | 13 + code/_onclick/hud/map_popups.dm | 7 + .../subsystem/processing/spacepods.dm | 12 + code/datums/components/rotation.dm | 166 +++++ code/game/objects/items/stacks/rods.dm | 7 + .../mob/living/carbon/human/human_mob.dm | 9 + code/modules/mob/living/living.dm | 4 + code/modules/mob/mob_vars.dm | 6 + .../modules/research/designs/mecha_designs.dm | 11 + .../research/designs/spacepod_designs.dm | 241 ++++++ code/modules/research/protolathe.dm | 3 +- code/modules/spacepods/icons/2x2.dmi | Bin 0 -> 1085 bytes .../spacepods/icons/actions_spacepod.dmi | Bin 0 -> 1828 bytes code/modules/spacepods/icons/parts.dmi | Bin 0 -> 4712 bytes code/modules/spacepods/spacepod.dm | 691 ++++++++++++++++++ code/modules/spacepods/spacepod_actions.dm | 122 ++++ .../spacepods/spacepod_construction.dm | 206 ++++++ code/modules/spacepods/spacepod_equipment.dm | 379 ++++++++++ code/modules/spacepods/spacepod_parts.dm | 181 +++++ code/modules/spacepods/spacepod_physics.dm | 297 ++++++++ code/modules/spacepods/spacepod_prebuilt.dm | 64 ++ goon/icons/obj/spacepods/2x2.dmi | Bin 0 -> 7679 bytes goon/icons/obj/spacepods/construction_2x2.dmi | Bin 0 -> 5631 bytes goon/icons/obj/spacepods/parts.dmi | Bin 0 -> 5007 bytes paradise.dme | 11 + 29 files changed, 2452 insertions(+), 1 deletion(-) create mode 100644 code/__DEFINES/spacepods.dm create mode 100644 code/controllers/subsystem/processing/spacepods.dm create mode 100644 code/datums/components/rotation.dm create mode 100644 code/modules/research/designs/spacepod_designs.dm create mode 100644 code/modules/spacepods/icons/2x2.dmi create mode 100644 code/modules/spacepods/icons/actions_spacepod.dmi create mode 100644 code/modules/spacepods/icons/parts.dmi create mode 100644 code/modules/spacepods/spacepod.dm create mode 100644 code/modules/spacepods/spacepod_actions.dm create mode 100644 code/modules/spacepods/spacepod_construction.dm create mode 100644 code/modules/spacepods/spacepod_equipment.dm create mode 100644 code/modules/spacepods/spacepod_parts.dm create mode 100644 code/modules/spacepods/spacepod_physics.dm create mode 100644 code/modules/spacepods/spacepod_prebuilt.dm create mode 100644 goon/icons/obj/spacepods/2x2.dmi create mode 100644 goon/icons/obj/spacepods/construction_2x2.dmi create mode 100644 goon/icons/obj/spacepods/parts.dmi diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index e73af05c7d61..fa918c4d41f9 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -52,6 +52,8 @@ #define ismecha(A) (istype(A, /obj/mecha)) +#define isspacepod(A) (istype(A, /obj/spacepod)) + #define iseffect(A) (istype(A, /obj/effect)) #define isclothing(A) (istype(A, /obj/item/clothing)) diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index 9e475ab6e9e0..55754bbba5f9 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -73,6 +73,7 @@ #define BELOW_MOB_LAYER 3.7 #define LYING_MOB_LAYER 3.8 +#define SPACEPOD_LAYER 3.9 // yogs //#define MOB_LAYER 4 //For easy recordkeeping; this is a byond define #define ABOVE_MOB_LAYER 4.1 #define HITSCAN_LAYER 4.2 diff --git a/code/__DEFINES/spacepods.dm b/code/__DEFINES/spacepods.dm new file mode 100644 index 000000000000..a4bfbd5abf88 --- /dev/null +++ b/code/__DEFINES/spacepods.dm @@ -0,0 +1,18 @@ +#define SPACEPOD_EMPTY 1 +#define SPACEPOD_WIRES_LOOSE 2 +#define SPACEPOD_WIRES_SECURED 3 +#define SPACEPOD_CIRCUIT_LOOSE 4 +#define SPACEPOD_CIRCUIT_SECURED 5 +#define SPACEPOD_CORE_LOOSE 6 +#define SPACEPOD_CORE_SECURED 7 +#define SPACEPOD_BULKHEAD_LOOSE 8 +#define SPACEPOD_BULKHEAD_SECURED 9 +#define SPACEPOD_BULKHEAD_WELDED 10 +#define SPACEPOD_ARMOR_LOOSE 11 +#define SPACEPOD_ARMOR_SECURED 12 +#define SPACEPOD_ARMOR_WELDED 13 + +#define SPACEPOD_SLOT_CARGO "cargo" +#define SPACEPOD_SLOT_MISC "misc" +#define SPACEPOD_SLOT_WEAPON "weapon" +#define SPACEPOD_SLOT_LOCK "lock" diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index cf6642875ffa..d04d7ebc28e3 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -696,6 +696,8 @@ ///If the lazy list is currently initialized find item I in list L #define LAZYIN(L, I) (L && (I in L)) +#define LAZYOR(L, I) if(!L) { L = list(); } L |= I; + //same, but returns nothing and acts on list in place /proc/shuffle_inplace(list/L) if(!L) diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm index 5d7d41143320..90af86729836 100644 --- a/code/_onclick/drag_drop.dm +++ b/code/_onclick/drag_drop.dm @@ -48,3 +48,16 @@ to inform the game this action was expected and its fine */ /atom/proc/MouseDrop_T(atom/dropping, mob/user, params) // return TRUE if you want to prevent us click the object after it return + +/client/MouseMove(object,location,control,params) + mouseParams = params + mouse_location_ref = location + mouse_object_ref = object + mouseControlObject = control + if(mob && LAZYLEN(mob.mousemove_intercept_objects)) + for(var/datum/D in mob.mousemove_intercept_objects) + D.onMouseMove(object, location, control, params) + ..() + +/datum/proc/onMouseMove(object, location, control, params) + return diff --git a/code/_onclick/hud/map_popups.dm b/code/_onclick/hud/map_popups.dm index dc9e255cba93..9c2bc9b148ce 100644 --- a/code/_onclick/hud/map_popups.dm +++ b/code/_onclick/hud/map_popups.dm @@ -7,6 +7,13 @@ */ var/list/screen_maps = list() + var/mouseParams = "" + ///Used in MouseDrag to preserve the last mouse-entered location + var/datum/mouse_location_ref = null + ///Used in MouseDrag to preserve the last mouse-entered object + var/datum/mouse_object_ref + var/mouseControlObject = null + /obj/screen /** * Map name assigned to this object. diff --git a/code/controllers/subsystem/processing/spacepods.dm b/code/controllers/subsystem/processing/spacepods.dm new file mode 100644 index 000000000000..036beea2fa4d --- /dev/null +++ b/code/controllers/subsystem/processing/spacepods.dm @@ -0,0 +1,12 @@ +// Yogstation use fastprocess subsystem but for Paradise it causes +// movement lag (updates, like it should, 5 times / second). +// This wait time (0.075) is the closest (and laziest) I could get to +// Yogstation's movement speed + +// RMNZ: Maybe performance issues? + +PROCESSING_SUBSYSTEM_DEF(spacepods) + name = "Spacepods" + wait = 0.075 + stat_tag = "SP" + offline_implications = "Spacepods will no longer process. Shuttle call recommended." diff --git a/code/datums/components/rotation.dm b/code/datums/components/rotation.dm new file mode 100644 index 000000000000..fc023da258cb --- /dev/null +++ b/code/datums/components/rotation.dm @@ -0,0 +1,166 @@ +//RMNZ: Please, check if this component is really needed or not +#define ROTATION_ALTCLICK (1<<0) +#define ROTATION_WRENCH (1<<1) +#define ROTATION_VERBS (1<<2) +#define ROTATION_COUNTERCLOCKWISE (1<<3) +#define ROTATION_CLOCKWISE (1<<4) +#define ROTATION_FLIP (1<<5) + +/datum/component/simple_rotation + var/datum/callback/can_user_rotate //Checks if user can rotate + var/datum/callback/can_be_rotated //Check if object can be rotated at all + var/datum/callback/after_rotation //Additional stuff to do after rotation + + var/rotation_flags = NONE + var/default_rotation_direction = ROTATION_CLOCKWISE + +/datum/component/simple_rotation/Initialize(rotation_flags = NONE, can_user_rotate, can_be_rotated, after_rotation) + if(!ismovable(parent)) + return COMPONENT_INCOMPATIBLE + + //throw if no rotation direction is specificed ? + + src.rotation_flags = rotation_flags + + if(can_user_rotate) + src.can_user_rotate = can_user_rotate + else + src.can_user_rotate = CALLBACK(src, PROC_REF(default_can_user_rotate)) + + if(can_be_rotated) + src.can_be_rotated = can_be_rotated + else + src.can_be_rotated = CALLBACK(src, PROC_REF(default_can_be_rotated)) + + if(after_rotation) + src.after_rotation = after_rotation + else + src.after_rotation = CALLBACK(src, PROC_REF(default_after_rotation)) + + //Try Clockwise,counter,flip in order + if(src.rotation_flags & ROTATION_FLIP) + default_rotation_direction = ROTATION_FLIP + if(src.rotation_flags & ROTATION_COUNTERCLOCKWISE) + default_rotation_direction = ROTATION_COUNTERCLOCKWISE + if(src.rotation_flags & ROTATION_CLOCKWISE) + default_rotation_direction = ROTATION_CLOCKWISE + +/datum/component/simple_rotation/proc/add_signals() + if(rotation_flags & ROTATION_ALTCLICK) + RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(HandRot)) + RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(ExamineMessage)) + if(rotation_flags & ROTATION_WRENCH) + RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, PROC_REF(WrenchRot)) + +/datum/component/simple_rotation/proc/add_verbs() + if(rotation_flags & ROTATION_VERBS) + var/atom/movable/AM = parent + if(rotation_flags & ROTATION_FLIP) + AM.verbs += /atom/movable/proc/simple_rotate_flip + if(src.rotation_flags & ROTATION_CLOCKWISE) + AM.verbs += /atom/movable/proc/simple_rotate_clockwise + if(src.rotation_flags & ROTATION_COUNTERCLOCKWISE) + AM.verbs += /atom/movable/proc/simple_rotate_counterclockwise + +/datum/component/simple_rotation/proc/remove_verbs() + if(parent) + var/atom/movable/AM = parent + AM.verbs -= /atom/movable/proc/simple_rotate_flip + AM.verbs -= /atom/movable/proc/simple_rotate_clockwise + AM.verbs -= /atom/movable/proc/simple_rotate_counterclockwise + +/datum/component/simple_rotation/proc/remove_signals() + UnregisterSignal(parent, list(COMSIG_CLICK_ALT, COMSIG_PARENT_EXAMINE, COMSIG_PARENT_ATTACKBY)) + +/datum/component/simple_rotation/RegisterWithParent() + add_verbs() + add_signals() + . = ..() + +/datum/component/simple_rotation/PostTransfer() + //Because of the callbacks which we don't track cleanly we can't transfer this + //item cleanly, better to let the new of the new item create a new rotation datum + //instead (there's no real state worth transferring) + return COMPONENT_NOTRANSFER + +/datum/component/simple_rotation/UnregisterFromParent() + remove_verbs() + remove_signals() + . = ..() + +/datum/component/simple_rotation/Destroy() + QDEL_NULL(can_user_rotate) + QDEL_NULL(can_be_rotated) + QDEL_NULL(after_rotation) + //Signals + verbs removed via UnRegister + . = ..() + +/datum/component/simple_rotation/RemoveComponent() + remove_verbs() + . = ..() + +/datum/component/simple_rotation/proc/ExamineMessage(datum/source, mob/user, list/examine_list) + if(rotation_flags & ROTATION_ALTCLICK) + examine_list += "Alt-click to rotate it clockwise." + +/datum/component/simple_rotation/proc/HandRot(datum/source, mob/user, rotation = default_rotation_direction) + if(!can_be_rotated.Invoke(user, rotation) || !can_user_rotate.Invoke(user, rotation)) + return + BaseRot(user, rotation) + +/datum/component/simple_rotation/proc/WrenchRot(datum/source, obj/item/I, mob/living/user) + if(!can_be_rotated.Invoke(user,default_rotation_direction) || !can_user_rotate.Invoke(user,default_rotation_direction)) + return + if(I.tool_behaviour == TOOL_WRENCH) + BaseRot(user,default_rotation_direction) + return COMPONENT_NO_AFTERATTACK + +/datum/component/simple_rotation/proc/BaseRot(mob/user,rotation_type) + var/atom/movable/AM = parent + var/rot_degree + switch(rotation_type) + if(ROTATION_CLOCKWISE) + rot_degree = -90 + if(ROTATION_COUNTERCLOCKWISE) + rot_degree = 90 + if(ROTATION_FLIP) + rot_degree = 180 + AM.setDir(turn(AM.dir,rot_degree)) + after_rotation.Invoke(user,rotation_type) + +/datum/component/simple_rotation/proc/default_can_user_rotate(mob/living/user, rotation_type) + //RMNZ: Check if be_close needed or not + if(!istype(user) || !user.can_use(parent)) + return FALSE + return TRUE + +/datum/component/simple_rotation/proc/default_can_be_rotated(mob/user, rotation_type) + var/atom/movable/AM = parent + return !AM.anchored + +/datum/component/simple_rotation/proc/default_after_rotation(mob/user, rotation_type) + to_chat(user, "You [rotation_type == ROTATION_FLIP ? "flip" : "rotate"] [parent].") + +/atom/movable/proc/simple_rotate_clockwise() + set name = "Rotate Clockwise" + set category = "Object" + set src in oview(1) + var/datum/component/simple_rotation/rotcomp = GetComponent(/datum/component/simple_rotation) + if(rotcomp) + rotcomp.HandRot(null,usr,ROTATION_CLOCKWISE) + +/atom/movable/proc/simple_rotate_counterclockwise() + set name = "Rotate Counter-Clockwise" + set category = "Object" + set src in oview(1) + var/datum/component/simple_rotation/rotcomp = GetComponent(/datum/component/simple_rotation) + if(rotcomp) + rotcomp.HandRot(null,usr,ROTATION_COUNTERCLOCKWISE) + +/atom/movable/proc/simple_rotate_flip() + set name = "Flip" + set category = "Object" + set src in oview(1) + var/datum/component/simple_rotation/rotcomp = GetComponent(/datum/component/simple_rotation) + if(rotcomp) + rotcomp.HandRot(null,usr,ROTATION_FLIP) diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm index db2d1a8a6442..a9e9b4d6bf58 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/rods.dm @@ -16,6 +16,13 @@ GLOBAL_LIST_INIT(rod_recipes, list ( new /datum/stack_recipe("chainlink fence door", /obj/structure/fence/door, 10, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), new /datum/stack_recipe("chainlink fence end", /obj/structure/fence/end, 3, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), )), + null, + new /datum/stack_recipe_list("octagon spacepod...", list( + new /datum/stack_recipe("aft starboard pod frame", /obj/item/pod_parts/pod_frame/aft_starboard, 15, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), + new /datum/stack_recipe("aft port pod frame", /obj/item/pod_parts/pod_frame/aft_port, 15, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), + new /datum/stack_recipe("fore port pod frame", /obj/item/pod_parts/pod_frame/fore_port, 15, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), + new /datum/stack_recipe("fore starboard pod frame", /obj/item/pod_parts/pod_frame/fore_starboard, 15, time = 1 SECONDS, one_per_turf = TRUE, on_floor = TRUE), + )), )) /obj/item/stack/rods diff --git a/code/modules/mob/living/carbon/human/human_mob.dm b/code/modules/mob/living/carbon/human/human_mob.dm index b4d8babeb117..cb68f52419a1 100644 --- a/code/modules/mob/living/carbon/human/human_mob.dm +++ b/code/modules/mob/living/carbon/human/human_mob.dm @@ -216,6 +216,15 @@ if(V) stat("Total Blood", "[V.bloodtotal]") stat("Usable Blood", "[V.bloodusable]") + if(istype(loc, /obj/spacepod)) // Spacepods! + var/obj/spacepod/S = loc + // If we want numbers instead of percents + // [S.cell ? "[round(S.cell.charge,0.1)]/[S.cell.maxcharge] KJ" : "NONE"] + stat(null, "Spacepod Charge: [S.cell ? "[round((S.cell.charge / S.cell.maxcharge) * 100, 0.1)]%" : "No cell detected"]") + // Same here + // [round((S.obj_integrity / S.max_integrity) * 100, 0.1)] + stat(null, "Spacepod Integrity: [!S.obj_integrity ? "0" : "[round(S.obj_integrity,0.1)]/[S.max_integrity]"]") + stat(null, "Spacepod Velocity: [round(sqrt(S.velocity_x*S.velocity_x+S.velocity_y*S.velocity_y), 0.1)] m/s") /mob/living/carbon/human/ex_act(severity) if(status_flags & GODMODE) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 61d972c71eab..681ff41bdbe2 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -926,6 +926,10 @@ var/obj/mecha/M = loc loc_temp = M.return_temperature() + else if(isspacepod(loc)) + var/obj/spacepod/S = loc + loc_temp = S.return_temperature() + else if(istype(loc, /obj/structure/transit_tube_pod)) loc_temp = environment.temperature diff --git a/code/modules/mob/mob_vars.dm b/code/modules/mob/mob_vars.dm index f20d80240b2f..9907034453ba 100644 --- a/code/modules/mob/mob_vars.dm +++ b/code/modules/mob/mob_vars.dm @@ -252,3 +252,9 @@ var/next_click_modifier = 1 /// Tracks the open UIs that a mob has, used in TGUI for various things, such as updating UIs var/list/open_uis = list() + + ///Allows a datum to intercept all click calls this mob is the so + var/datum/click_intercept + + ///List of datums that this has which make use of MouseMove() + var/list/mousemove_intercept_objects diff --git a/code/modules/research/designs/mecha_designs.dm b/code/modules/research/designs/mecha_designs.dm index 837f80365c04..0ced7b73ffec 100644 --- a/code/modules/research/designs/mecha_designs.dm +++ b/code/modules/research/designs/mecha_designs.dm @@ -196,3 +196,14 @@ materials = list(MAT_GLASS = 1000) build_path = /obj/item/circuitboard/mecha/reticence/targeting category = list("Exosuit Modules") + +// Pod +/datum/design/spacepod_main + name = "Circuit Design (Space Pod Mainboard)" + desc = "Allows for the construction of a spacepod mainboard." + id = "spacepod_main" + req_tech = list("programming" = 1) //RMNZ: Change req_tech + build_type = IMPRINTER + materials = list(MAT_GLASS = 1000) + build_path = /obj/item/circuitboard/mecha/pod + category = list("Exosuit Modules") diff --git a/code/modules/research/designs/spacepod_designs.dm b/code/modules/research/designs/spacepod_designs.dm new file mode 100644 index 000000000000..1e473fe777ff --- /dev/null +++ b/code/modules/research/designs/spacepod_designs.dm @@ -0,0 +1,241 @@ +//////////////////// +////// Core ////// +//////////////////// + +/datum/design/pod_core + name = "Spacepod Core" + desc = "Allows for the construction of a spacepod core system, made up of the engine and life support systems." + id = "podcore" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=5000, MAT_URANIUM=1000, MAT_PLASMA=5000) + build_path = /obj/item/pod_parts/core + category = list("Spacepod Designs") + +///////////////////// +////// Armor ////// +///////////////////// + +/datum/design/pod_armor_civ + name = "Spacepod Armor (civilian)" + desc = "Allows for the construction of spacepod armor. This is the civilian version." + id = "podarmor_civ" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=15000,MAT_GLASS=5000,MAT_PLASMA=10000) + build_path = /obj/item/pod_parts/armor + category = list("Spacepod Designs") + +/datum/design/pod_armor_black + name = "Spacepod Armor (dark)" + desc = "Allows for the construction of spacepod armor. This is the dark civillian version." + id = "podarmor_dark" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=15000,MAT_GLASS=5000,MAT_PLASMA=10000) + build_path = /obj/item/pod_parts/armor/black + category = list("Spacepod Designs") + +/datum/design/pod_armor_industrial + name = "Spacepod Armor (industrial)" + desc = "Allows for the construction of spacepod armor. This is the industrial grade version." + id = "podarmor_industiral" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=15000,MAT_GLASS=5000,MAT_PLASMA=10000,MAT_DIAMOND=5000,MAT_SILVER=7500) + build_path = /obj/item/pod_parts/armor/industrial + category = list("Spacepod Designs") + +/datum/design/pod_armor_sec + name = "Spacepod Armor (security)" + desc = "Allows for the construction of spacepod armor. This is the security version." + id = "podarmor_sec" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=15000,MAT_GLASS=5000,MAT_PLASMA=10000,MAT_DIAMOND=5000,MAT_SILVER=7500) + build_path = /obj/item/pod_parts/armor/security + category = list("Spacepod Designs") + +/datum/design/pod_armor_gold + name = "Spacepod Armor (golden)" + desc = "Allows for the construction of spacepod armor. This is the golden version." + id = "podarmor_gold" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=5000,MAT_GLASS=2500,MAT_PLASMA=7500,MAT_GOLD=10000) + build_path = /obj/item/pod_parts/armor/gold + category = list("Spacepod Designs") + +///////////////////////////// +////// Spacepod Guns ////// +///////////////////////////// + +/* +/datum/design/pod_gun_disabler + name = "Spacepod Equipment (Disabler)" + desc = "Allows for the construction of a spacepod mounted disabler." + id = "podgun_disabler" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 15000) + build_path = /obj/item/spacepod_equipment/weaponry/disabler + category = list("Spacepod Designs") + +/datum/design/pod_gun_bdisabler + name = "Spacepod Equipment (Burst Disabler)" + desc = "Allows for the construction of a spacepod mounted disabler. This is the burst-fire model." + id = "podgun_bdisabler" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 15000, MAT_PLASMA=2000) + build_path = /obj/item/spacepod_equipment/weaponry/burst_disabler + category = list("Spacepod Designs") + +/datum/design/pod_gun_laser + name = "Spacepod Equipment (Laser)" + desc = "Allows for the construction of a spacepod mounted laser." + id = "podgun_laser" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=10000,MAT_GLASS=5000,MAT_GOLD=1000,MAT_SILVER=2000) + build_path = /obj/item/spacepod_equipment/weaponry/laser + category = list("Spacepod Designs") + +/datum/design/pod_ka_basic + name = "Spacepod Equipment (Basic Kinetic Accelerator)" + desc = "Allows for the construction of a weak spacepod Kinetic Accelerator" + id = "pod_ka_basic" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 10000, MAT_GLASS = 5000, MAT_SILVER = 2000, MAT_URANIUM = 2000) + build_path = /obj/item/spacepod_equipment/weaponry/basic_pod_ka + category = list("Spacepod Designs") + +/datum/design/pod_ka + name = "Spacepod Equipment (Kinetic Accelerator)" + desc = "Allows for the construction of a spacepod Kinetic Accelerator." + id = "pod_ka" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 10000, MAT_GLASS = 5000, MAT_SILVER = 2000, MAT_GOLD = 2000, MAT_DIAMOND = 2000) + build_path = /obj/item/spacepod_equipment/weaponry/pod_ka + category = list("Spacepod Designs") + +/datum/design/pod_plasma_cutter + name = "Spacepod Equipment (Plasma Cutter)" + desc = "Allows for the construction of a plasma cutter." + id = "pod_plasma_cutter" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 10000, MAT_GLASS = 5000, MAT_SILVER = 2000, MAT_GOLD = 2000, MAT_DIAMOND = 2000) + build_path = /obj/item/spacepod_equipment/weaponry/plasma_cutter + category = list("Spacepod Designs") + +/datum/design/pod_adv_plasma_cutter + name = "Spacepod Equipment (Advanced Plasma cutter)" + desc = "Allows for the construction of an advanced plasma cutter." + id = "pod_adv_plasma_cutter" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 10000, MAT_GLASS = 5000, MAT_SILVER = 4000, MAT_GOLD = 4000, MAT_DIAMOND = 4000) + build_path = /obj/item/spacepod_equipment/weaponry/plasma_cutter/adv + category = list("Spacepod Designs") +*/ + +//////////////////////////////////// +////// Spacepod Misc. Items ////// +//////////////////////////////////// + +/* +/datum/design/pod_misc_tracker + name = "Spacepod Tracking Module" + desc = "Allows for the construction of a spacepod tracking module." + id = "podmisc_tracker" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=5000) + build_path = /obj/item/spacepod_equipment/tracker + category = list("Spacepod Designs") +*/ + +//////////////////////////////////// +////// Spacepod Cargo Items ////// +//////////////////////////////////// + +/* +/datum/design/pod_cargo_ore + name = "Spacepod Ore Storage Module" + desc = "Allows for the construction of a spacepod ore storage module." + id = "podcargo_ore" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=20000, MAT_GLASS=2000) + build_path = /obj/item/spacepod_equipment/cargo/large/ore + category = list("Spacepod Designs") + +/datum/design/pod_cargo_crate + name = "Spacepod Crate Storage Module" + desc = "Allows the construction of a spacepod crate storage module." + id = "podcargo_crate" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=25000) + build_path = /obj/item/spacepod_equipment/cargo/large + category = list("Spacepod Designs") +*/ + +/datum/design/passenger_seat + name = "Spacepod Passenger Seat" + desc = "Allows the construction of a spacepod passenger seat module." + id = "podcargo_seat" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=7500, MAT_GLASS=2500) + build_path = /obj/item/spacepod_equipment/cargo/chair + category = list("Spacepod Designs") + +/* +/datum/design/loot_box + name = "Spacepod Loot Storage Module" + desc = "Allows the construction of a spacepod auxillary cargo module." + id = "podcargo_lootbox" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=7500, MAT_GLASS=2500) + build_path = /obj/item/spacepod_equipment/cargo/loot_box + category = list("Spacepod Designs") +*/ + +/////////////////////////////////// +////// Spacepod Lock Items ////// +/////////////////////////////////// + +/datum/design/pod_lock_keyed + name = "Spacepod Tumbler Lock" + desc = "Allows for the construction of a tumbler style podlock." + id = "podlock_keyed" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=4500) + build_path = /obj/item/spacepod_equipment/lock/keyed + category = list("Spacepod Designs") + +/datum/design/pod_key + name = "Spacepod Tumbler Lock Key" + desc = "Allows for the construction of a blank key for a podlock." + id = "podkey" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL=500) + build_path = /obj/item/spacepod_key + category = list("Spacepod Designs") + +/datum/design/lockbuster + name = "Spacepod Lock Buster" + desc = "Allows for the construction of a spacepod lockbuster." + id = "pod_lockbuster" + req_tech = list("programming" = 1, "engineering" = 1) //RMNZ: Change req_tech + build_type = PROTOLATHE + materials = list(MAT_METAL = 15000, MAT_DIAMOND=2500) //it IS a drill! + build_path = /obj/item/device/lock_buster + category = list("Spacepod Designs") diff --git a/code/modules/research/protolathe.dm b/code/modules/research/protolathe.dm index 2b78ebd2f94b..26cedb8720ed 100644 --- a/code/modules/research/protolathe.dm +++ b/code/modules/research/protolathe.dm @@ -22,7 +22,8 @@ Note: Must be placed west/left of and R&D console to function. "Miscellaneous", "Power", "Stock Parts", - "Weapons" + "Weapons", + "Spacepod Designs" ) /obj/machinery/r_n_d/protolathe/Initialize(mapload) diff --git a/code/modules/spacepods/icons/2x2.dmi b/code/modules/spacepods/icons/2x2.dmi new file mode 100644 index 0000000000000000000000000000000000000000..ecdb69d66c379973535ccd296a41f797ae6039d4 GIT binary patch literal 1085 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 G5&s9g{0XA~ literal 0 HcmV?d00001 diff --git a/code/modules/spacepods/spacepod.dm b/code/modules/spacepods/spacepod.dm new file mode 100644 index 000000000000..8e6fbd8e2d92 --- /dev/null +++ b/code/modules/spacepods/spacepod.dm @@ -0,0 +1,691 @@ +//YOGSTATION SPECEPODS + ITS ORIGINAL COMMENT +/* ------------------------------------------------------------ +This is like paradise spacepods but with a few differences: +- no spacepod fabricator, parts are made in techfabs and frames are made using metal rods. +- not tile based, instead has velocity and acceleration. why? so I can put all this math to use. +- damages shit if you run into it too fast instead of just stopping. You have to have a huge running start to do that though and damages the spacepod as well. +- doesn't explode +------------------------------------------------------------ */ + +// MrRomainzZ Comment: +// I decided to split the code like mechs do because I find it very similar in some ways +// Mostly untouched, but adapted for paradise and addition of new pods + +GLOBAL_LIST_INIT(spacepods_list, list()) + +/obj/spacepod + name = "space pod" + desc = "A frame for a spacepod." + icon = 'goon/icons/obj/spacepods/construction_2x2.dmi' + icon_state = "pod_1" + density = TRUE + opacity = FALSE + anchored = TRUE + dir = NORTH // always points north because why not + layer = SPACEPOD_LAYER + bound_width = 64 + bound_height = 64 + animate_movement = NO_STEPS // we do our own gliding here + + resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF // it floats above lava or something, I dunno + + max_integrity = 50 + integrity_failure = 50 + + var/list/equipment = list() + var/list/equipment_slot_limits = list( + SPACEPOD_SLOT_MISC = 1, + SPACEPOD_SLOT_CARGO = 2, + SPACEPOD_SLOT_WEAPON = 1, + SPACEPOD_SLOT_LOCK = 1) + var/obj/item/spacepod_equipment/lock/lock + var/obj/item/spacepod_equipment/weaponry/weapon + var/next_firetime = 0 + var/locked = FALSE + var/hatch_open = FALSE + var/construction_state = SPACEPOD_EMPTY + var/obj/item/pod_parts/armor/pod_armor = null + var/obj/item/stock_parts/cell/cell = null + + //inner atmos + var/datum/gas_mixture/cabin_air + var/obj/machinery/atmospherics/portable/canister/internal_tank + var/last_slowprocess = 0 + + var/mob/living/pilot = null + var/list/passengers = list() + var/max_passengers = 0 + + var/velocity_x = 0 // tiles per second. + var/velocity_y = 0 + var/offset_x = 0 // like pixel_x/y but in tiles + var/offset_y = 0 + var/angle = 0 // degrees, clockwise + var/desired_angle = null // set by pilot moving his mouse + var/angular_velocity = 0 // degrees per second + var/max_angular_acceleration = 360 // in degrees per second per second + var/last_thrust_forward = 0 + var/last_thrust_right = 0 + var/last_rotate = 0 + + var/brakes = TRUE + var/user_thrust_dir = 0 + var/forward_maxthrust = 6 + var/backward_maxthrust = 3 + var/side_maxthrust = 1 + + var/lights = 0 + var/lights_power = 6 + var/static/list/icon_light_color = list("pod_civ" = LIGHT_COLOR_WHITE, \ + "pod_mil" = "#BBF093", \ + "pod_synd" = LIGHT_COLOR_RED, \ + "pod_gold" = LIGHT_COLOR_WHITE, \ + "pod_black" = "#3B8FE5", \ + "pod_industrial" = "#CCCC00") + + var/bump_impulse = 0.6 + var/bounce_factor = 0.2 // how much of our velocity to keep on collision + var/lateral_bounce_factor = 0.95 // mostly there to slow you down when you drive (pilot?) down a 2x2 corridor + +/obj/spacepod/Initialize(mapload) + . = ..() + GLOB.spacepods_list += src + START_PROCESSING(SSspacepods, src) + cabin_air = new + cabin_air.temperature = T20C + cabin_air.volume = 200 + + /* Paradise variant + cabin_air.oxygen = O2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) + cabin_air.nitrogen = N2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) + */ + + /* Yogstation variant + cabin_air.assert_gas(GAS_O2) + cabin_air.assert_gas(GAS_N2) + cabin_air.gases[GAS_O2][MOLES] = ONE_ATMOSPHERE*O2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) + cabin_air.gases[GAS_N2][MOLES] = ONE_ATMOSPHERE*N2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) + */ + +/////////////////////// +////// Helpers ////// +/////////////////////// + +/obj/spacepod/Entered() + . = ..() + +/obj/spacepod/Exited() + . = ..() + +/obj/spacepod/proc/InterceptClickOn(mob/user, params, atom/target) + var/list/params_list = params2list(params) + if(target == src || istype(target, /atom/movable/screen) || (target && (target in user.get_contents())) || user != pilot || params_list["shift"] || params_list["alt"] || params_list["ctrl"]) + return FALSE + if(weapon) + weapon.fire_weapons(target) + return TRUE + +/obj/spacepod/proc/enter_pod(mob/living/user) + if(user.stat != CONSCIOUS) + return FALSE + + if(locked) // RMNZ: You also check your health on this + to_chat(user, "[src]'s doors are locked!") + return FALSE + + if(!istype(user)) + return FALSE + + if(user.incapacitated()) + return FALSE + if(!ishuman(user)) + return FALSE + + if(passengers.len <= max_passengers || !pilot) + visible_message("[user] starts to climb into [src].") + if(do_after(user, 4 SECONDS, target = src) && construction_state == SPACEPOD_ARMOR_WELDED) // RMNZ: No check for free passenger seats + var/success = add_rider(user) + if(!success) + to_chat(user, "You were too slow. Try better next time, loser.") + return success + else + to_chat(user, "You stop entering [src].") + else + to_chat(user, "You can't fit in [src], it's full!") + return FALSE + +/obj/spacepod/proc/go_out(forced, atom/newloc = loc) + if(!pilot) + return + if(!isliving(usr) || usr.stat > CONSCIOUS) + return + + if(usr.restrained()) + to_chat(usr, "You attempt to stumble out of [src]. This will take two minutes.") + if(pilot) + to_chat(pilot, "[usr] is trying to escape [src].") + if(!do_after(usr, 2 MINUTES, target = src)) + return + + if(remove_rider(usr)) + to_chat(usr, "You climb out of [src].") + +/obj/spacepod/proc/add_rider(mob/living/M, allow_pilot = TRUE) + if(M == pilot || (M in passengers)) + return FALSE + if(!pilot && allow_pilot) + pilot = M + LAZYOR(M.mousemove_intercept_objects, src) + M.click_intercept = src + // GrantActions(M) + // addverbs(M) + else if(passengers.len < max_passengers) + passengers += M + else + return FALSE + GrantActions(M) // Passengers have buttons now + M.stop_pulling() + M.forceMove(src) + playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) + return TRUE + +/obj/spacepod/proc/remove_rider(mob/living/M) + if(!M) + return + + RemoveActions(M) + + if(M == pilot) + pilot = null + // removeverbs(M) + LAZYREMOVE(M.mousemove_intercept_objects, src) + if(M.click_intercept == src) + M.click_intercept = null + desired_angle = null // since there's no pilot there's no one aiming it. + else if(M in passengers) + passengers -= M + else + return FALSE + if(M.loc == src) + M.forceMove(loc) + if(M.client) + M.client.pixel_x = 0 + M.client.pixel_y = 0 + return TRUE + +/obj/spacepod/proc/lock_pod() + if(!lock) // RMNZ: Passengers see this instead of "You can't reach controls" + to_chat(usr, "[src] has no locking mechanism.") + locked = FALSE //Should never be false without a lock, but if it somehow happens, that will force an unlock. + else + locked = !locked + to_chat(usr, "You [locked ? "lock" : "unlock"] the doors.") // RMNZ: You "tap" on the pod with your key. Also action button doesn't update + +/obj/spacepod/proc/verb_check(require_pilot = TRUE, mob/user = null) + if(!user) + user = usr + if(require_pilot && user != pilot) + to_chat(user, "You can't reach the controls from your chair") + return FALSE + return !user.incapacitated() && isliving(user) + +/obj/spacepod/AltClick(user) + if(!verb_check(user = user)) + return + brakes = !brakes + to_chat(usr, "You toggle the brakes [brakes ? "on" : "off"].") + +//////////////////////// +////// AttackBy ////// +//////////////////////// + +/obj/spacepod/attackby(obj/item/W, mob/living/user) + if(user.a_intent == INTENT_HARM) + return ..() + else if(construction_state != SPACEPOD_ARMOR_WELDED) + . = handle_spacepod_construction(W, user) + if(.) + return + else + return ..() + // and now for the real stuff + else + if(W.tool_behaviour == TOOL_CROWBAR) + if(hatch_open || !locked) + hatch_open = !hatch_open + W.play_tool_sound(src) + to_chat(user, "You [hatch_open ? "open" : "close"] the maintenance hatch.") + else + to_chat(user, "The hatch is locked shut!") + return TRUE + if(istype(W, /obj/item/stock_parts/cell)) + if(!hatch_open) + to_chat(user, "The maintenance hatch is closed!") + return TRUE + if(cell) + to_chat(user, "The pod already has a battery.") + return TRUE + if(user.drop_item()) + to_chat(user, "You insert [W] into the pod.") + W.forceMove(src) + cell = W + return TRUE + if(istype(W, /obj/item/spacepod_equipment)) + if(!hatch_open) + to_chat(user, "The maintenance hatch is closed!") + return TRUE + var/obj/item/spacepod_equipment/SE = W + if(SE.can_install(src, user)) + if(user.drop_item()) + SE.forceMove(src) + SE.on_install(src) + return TRUE + if(lock && istype(W, /obj/item/device/lock_buster)) + var/obj/item/device/lock_buster/L = W + if(L.on) + user.visible_message("[user] is drilling through [src]'s lock!", + "You start drilling through [src]'s lock!") + if(do_after(user, 10 SECONDS * W.toolspeed, target = src)) + if(lock) + var/obj/O = lock + lock.on_uninstall() + qdel(O) + user.visible_message("[user] has destroyed [src]'s lock!", + "You destroy [src]'s lock!") + else + user.visible_message("[user] fails to break through [src]'s lock!", + "You were unable to break through [src]'s lock!") + return TRUE + to_chat(user, "Turn the [L] on first.") + return TRUE + if(W.tool_behaviour == TOOL_WELDER) + var/repairing = cell || internal_tank || equipment.len || (obj_integrity < max_integrity) || pilot || passengers.len + if(!hatch_open) + to_chat(user, "You must open the maintenance hatch before [repairing ? "attempting repairs" : "unwelding the armor"].") + return TRUE + if(repairing && obj_integrity >= max_integrity) + to_chat(user, "[src] is fully repaired!") + return TRUE + to_chat(user, "You start [repairing ? "repairing [src]" : "slicing off [src]'s armor'"]") + if(W.use_tool(src, user, 50, amount=3, volume = 50)) + if(repairing) + obj_integrity = min(max_integrity, obj_integrity + 10) + update_appearance(UPDATE_ICON) + to_chat(user, "You mend some [pick("dents","bumps","damage")] with [W]") + else if(!cell && !internal_tank && !equipment.len && !pilot && !passengers.len && construction_state == SPACEPOD_ARMOR_WELDED) + user.visible_message("[user] slices off [src]'s armor.", "You slice off [src]'s armor.") + construction_state = SPACEPOD_ARMOR_SECURED + update_appearance(UPDATE_ICON) + return TRUE + return ..() + +//////////////////////////////////// +////// Health related procs ////// +//////////////////////////////////// + +/obj/spacepod/Destroy() + GLOB.spacepods_list -= src + QDEL_NULL(pilot) + QDEL_LIST_CONTENTS(passengers) + QDEL_LIST_CONTENTS(equipment) + QDEL_NULL(cabin_air) + QDEL_NULL(cell) + return ..() + +/obj/spacepod/attack_hand(mob/user as mob) + if(user.a_intent == INTENT_GRAB && !locked) + var/mob/living/target + if(pilot) + target = pilot + else if(passengers.len > 0) + target = passengers[1] + + if(target && istype(target)) // RMNZ: You can rip yourself out the pod + src.visible_message("[user] is trying to rip the door open and pull [target] out of [src]!", + "You see [user] outside the door trying to rip it open!") + if(do_after(user, 5 SECONDS, target = src) && construction_state == SPACEPOD_ARMOR_WELDED) + if(remove_rider(target)) + target.Stun(20) + target.visible_message("[user] flings the door open and tears [target] out of [src]", + "The door flies open and you are thrown out of [src] and to the ground!") + return + target.visible_message("[user] was unable to get the door open!", + "You manage to keep [user] out of [src]!") + + if(!hatch_open) + //if(cargo_hold.storage_slots > 0) + // if(!locked) + // cargo_hold.open(user) + // else + // to_chat(user, "The storage compartment is locked") + return ..() + + if(user == pilot) + return ..() + + var/list/items = list(cell, internal_tank) + items += equipment + var/list/item_map = list() + //var/list/used_key_list = list() + for(var/obj/I in items) + item_map[I.name] = I + var/selection = input(user, "Remove which equipment?", null, null) as null|anything in item_map + var/obj/O = item_map[selection] + if(O && istype(O) && (O in contents) && user != pilot) + // alrightey now to figure out what it is + if(O == cell) + cell = null + else if(O == internal_tank) + internal_tank = null + else if(O in equipment) + var/obj/item/spacepod_equipment/SE = O + if(!SE.can_uninstall(user)) + return + SE.on_uninstall() + else + return + O.forceMove(loc) + if(isitem(O)) + user.put_in_hands(O) + +/obj/spacepod/ex_act(severity) + switch(severity) + if(1) + for(var/mob/living/M in contents) + M.ex_act(severity+1) + deconstruct() + if(2) + take_damage(100, BRUTE, BOMB, 0) + if(3) + if(prob(40)) + take_damage(40, BRUTE, BOMB, 0) + +/obj/spacepod/obj_break() + if(obj_integrity <= 0) + return // nah we'll let the other boy handle it + if(construction_state < SPACEPOD_ARMOR_LOOSE) + return + if(pod_armor) + var/obj/A = pod_armor + remove_armor() + qdel(A) + if(prob(40)) + new /obj/item/stack/sheet/metal(loc, 5) + if(prob(40)) + new /obj/item/stack/sheet/metal(loc, 5) + construction_state = SPACEPOD_CORE_SECURED + if(cabin_air) + var/datum/gas_mixture/GM = cabin_air.remove_ratio(1) + var/turf/T = get_turf(src) + if(GM && T) + T.assume_air(GM) + cell = null + internal_tank = null + for(var/atom/movable/AM in contents) + if(AM in equipment) + var/obj/item/spacepod_equipment/SE = AM + if(istype(SE)) + SE.on_uninstall(src) + if(ismob(AM)) + forceMove(AM, loc) + remove_rider(AM) + else if(prob(60)) + AM.forceMove(loc) + else if(isitem(AM) || !isobj(AM)) + qdel(AM) + else + var/obj/O = AM + O.forceMove(loc) + O.deconstruct() + +/obj/spacepod/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = TRUE, attack_dir, armour_penetration = 0) + ..() + update_appearance(UPDATE_ICON) + +/obj/spacepod/deconstruct(disassembled = FALSE) + if(!get_turf(src)) + qdel(src) + return + remove_rider(pilot) + while(passengers.len) + remove_rider(passengers[1]) + passengers.Cut() + if(disassembled) + // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + // alright fine fine you can have the frame pieces back + var/clamped_angle = (round(angle, 90) % 360 + 360) % 360 + var/target_dir = NORTH + switch(clamped_angle) + if(0) + target_dir = NORTH + if(90) + target_dir = EAST + if(180) + target_dir = SOUTH + if(270) + target_dir = WEST + //RMNZ: Addition of new pods 2 + var/list/frame_piece_types = list(/obj/item/pod_parts/pod_frame/aft_port, /obj/item/pod_parts/pod_frame/aft_starboard, /obj/item/pod_parts/pod_frame/fore_port, /obj/item/pod_parts/pod_frame/fore_starboard) + var/obj/item/pod_parts/pod_frame/current_piece = null + var/turf/CT = get_turf(src) + var/list/frame_pieces = list() + for(var/frame_type in frame_piece_types) + var/obj/item/pod_parts/pod_frame/F = new frame_type + F.dir = target_dir + F.anchored = TRUE + if(1 == turn(F.dir, -F.link_angle)) + current_piece = F + frame_pieces += F + while(current_piece && !current_piece.loc) + if(!CT) + break + current_piece.forceMove(CT) + CT = get_step(CT, turn(current_piece.dir, -current_piece.link_angle)) + current_piece = locate(current_piece.link_to) in frame_pieces + // there here's your frame pieces back, happy? + qdel(src) + +///////////////////////////////// +////// Atmospheric stuff ////// +///////////////////////////////// + +/obj/spacepod/return_air() + return cabin_air + +/obj/spacepod/remove_air(amount) + return cabin_air.remove(amount) + +/obj/spacepod/proc/return_temperature() + var/datum/gas_mixture/t_air = return_air() + if(t_air) + . = t_air.return_temperature() + +/obj/spacepod/proc/slowprocess() + // Temp Regulation + if(cabin_air && cabin_air.return_volume() > 0) + var/delta = cabin_air.temperature - T20C + cabin_air.temperature -= max(-10, min(10, round(delta / 4, 0.1))) + + // Air Regulation + if(internal_tank && cabin_air) + var/datum/gas_mixture/tank_air = internal_tank.return_air() + + var/release_pressure = ONE_ATMOSPHERE + var/cabin_pressure = cabin_air.return_pressure() + var/pressure_delta = min(release_pressure - cabin_pressure, (tank_air.return_pressure() - cabin_pressure)/2) + var/transfer_moles = 0 + if(pressure_delta > 0) //cabin pressure lower than release pressure + if(tank_air.return_temperature() > 0) + transfer_moles = pressure_delta*cabin_air.return_volume()/(cabin_air.return_temperature() * R_IDEAL_GAS_EQUATION) + var/datum/gas_mixture/removed = tank_air.remove(transfer_moles) + cabin_air.merge(removed) + else if(pressure_delta < 0) //cabin pressure higher than release pressure + var/datum/gas_mixture/t_air = return_air() + pressure_delta = cabin_pressure - release_pressure + if(t_air) + pressure_delta = min(cabin_pressure - t_air.return_pressure(), pressure_delta) + if(pressure_delta > 0) //if location pressure is lower than cabin pressure + transfer_moles = pressure_delta*cabin_air.return_volume()/(cabin_air.return_temperature() * R_IDEAL_GAS_EQUATION) + var/datum/gas_mixture/removed = cabin_air.remove(transfer_moles) + if(t_air) + t_air.merge(removed) + else //just delete the cabin gas, we're in space or some shit + qdel(removed) + + //Power Related + if(!cell || cell.charge < 1) // RMNZ: How to update action button from here? + lights = 0 + set_light(0) + +////////////////////////////// +////// Movement procs ////// +////////////////////////////// + +/obj/spacepod/onMouseMove(object,location,control,params) + if(!pilot || !pilot.client || pilot.incapacitated()) + return // I don't know what's going on. + var/list/params_list = params2list(params) + var/sl_list = splittext(params_list["screen-loc"],",") + var/sl_x_list = splittext(sl_list[1], ":") + var/sl_y_list = splittext(sl_list[2], ":") + var/view_list = isnum(pilot.client.view) ? list("[pilot.client.view*2+1]","[pilot.client.view*2+1]") : splittext(pilot.client.view, "x") + var/dx = text2num(sl_x_list[1]) + (text2num(sl_x_list[2]) / world.icon_size) - 1 - text2num(view_list[1]) / 2 + var/dy = text2num(sl_y_list[1]) + (text2num(sl_y_list[2]) / world.icon_size) - 1 - text2num(view_list[2]) / 2 + if(sqrt(dx*dx+dy*dy) > 1) + desired_angle = 90 - ATAN2(dx, dy) + else + desired_angle = null + +/obj/spacepod/relaymove(mob/user, direction) + if(user != pilot || pilot.incapacitated()) + return + user_thrust_dir = direction + +////////////////////////////////// +////// Construction procs ////// +////////////////////////////////// + +/obj/spacepod/proc/add_armor(obj/item/pod_parts/armor/armor) + desc = armor.pod_desc + max_integrity = armor.pod_integrity + obj_integrity = max_integrity - integrity_failure + obj_integrity + pod_armor = armor + update_appearance(UPDATE_ICON) + +/obj/spacepod/proc/remove_armor() + if(!pod_armor) + obj_integrity = min(integrity_failure, obj_integrity) + max_integrity = integrity_failure + desc = initial(desc) + pod_armor = null + update_appearance(UPDATE_ICON) + +/obj/spacepod/update_icon_state() + . = ..() + if(construction_state != SPACEPOD_ARMOR_WELDED) + icon = 'goon/icons/obj/spacepods/construction_2x2.dmi' + icon_state = "pod_[construction_state]" + return + + if(pod_armor) + icon = pod_armor.pod_icon + icon_state = pod_armor.pod_icon_state + else + icon = 'goon/icons/obj/spacepods/2x2.dmi' + icon_state = initial(icon_state) + +/obj/spacepod/update_overlays() + . = ..() + if(construction_state != SPACEPOD_ARMOR_WELDED) + if(pod_armor && construction_state >= SPACEPOD_ARMOR_LOOSE) + var/mutable_appearance/masked_armor = mutable_appearance(icon = 'goon/icons/obj/spacepods/construction_2x2.dmi', icon_state = "armor_mask") + var/mutable_appearance/armor = mutable_appearance(pod_armor.pod_icon, pod_armor.pod_icon_state) + armor.blend_mode = BLEND_MULTIPLY + masked_armor.overlays = list(armor) + masked_armor.appearance_flags = KEEP_TOGETHER + . += masked_armor + return + + if(obj_integrity <= max_integrity / 2) + . += image(icon='goon/icons/obj/spacepods/2x2.dmi', icon_state="pod_damage") + if(obj_integrity <= max_integrity / 4) + . += image(icon='goon/icons/obj/spacepods/2x2.dmi', icon_state="pod_fire") + + if(weapon && weapon.overlay_icon_state) + . += image(icon=weapon.overlay_icon,icon_state=weapon.overlay_icon_state) + + light_color = icon_light_color[icon_state] || LIGHT_COLOR_WHITE + + // Thrust! + var/list/left_thrusts = list() + left_thrusts.len = 8 + var/list/right_thrusts = list() + right_thrusts.len = 8 + for(var/cdir in GLOB.cardinal) + left_thrusts[cdir] = 0 + right_thrusts[cdir] = 0 + var/back_thrust = 0 + if(last_thrust_right != 0) + var/tdir = last_thrust_right > 0 ? WEST : EAST + left_thrusts[tdir] = abs(last_thrust_right) / side_maxthrust + right_thrusts[tdir] = abs(last_thrust_right) / side_maxthrust + if(last_thrust_forward > 0) + back_thrust = last_thrust_forward / forward_maxthrust + if(last_thrust_forward < 0) + left_thrusts[NORTH] = -last_thrust_forward / backward_maxthrust + right_thrusts[NORTH] = -last_thrust_forward / backward_maxthrust + if(last_rotate != 0) + var/frac = abs(last_rotate) / max_angular_acceleration + for(var/cdir in GLOB.cardinal) + if(last_rotate > 0) + right_thrusts[cdir] += frac + else + left_thrusts[cdir] += frac + for(var/cdir in GLOB.cardinal) + var/left_thrust = left_thrusts[cdir] + var/right_thrust = right_thrusts[cdir] + if(left_thrust) + . += image(icon = 'code/modules/spacepods/icons/2x2.dmi', icon_state = "rcs_left", dir = cdir) + if(right_thrust) + . += image(icon = 'code/modules/spacepods/icons/2x2.dmi', icon_state = "rcs_right", dir = cdir) + if(back_thrust) + var/image/I = image(icon = 'code/modules/spacepods/icons/2x2.dmi', icon_state = "thrust") + I.transform = matrix(1, 0, 0, 0, 1, -32) + . += I + +/obj/spacepod/MouseDrop_T(atom/movable/A, mob/living/user) + if(user == pilot || (user in passengers) || construction_state != SPACEPOD_ARMOR_WELDED) + return + + if(istype(A, /obj/machinery/atmospherics/portable/canister)) + if(internal_tank) + to_chat(user, "[src] already has an internaltank!") + return + if(!A.Adjacent(src)) + to_chat(user, "The canister is not close enough!") + return + if(hatch_open) + to_chat(user, "The hatch is shut!") + to_chat(user, "You begin inserting the canister into [src]") + if(do_after(user, 5 SECONDS, target = A) && construction_state == SPACEPOD_ARMOR_WELDED) + to_chat(user, "You insert the canister into [src]") + A.forceMove(src) + internal_tank = A + return + + if(isliving(A)) + var/mob/living/M = A + if(M != user && !locked) + if(passengers.len >= max_passengers && !pilot) + to_chat(user, "[A.p_they()] can't fly the pod!") + return + if(passengers.len < max_passengers) + visible_message("[user] starts loading [M] into [src]!") + if(do_after(user, 5 SECONDS, target = M) && construction_state == SPACEPOD_ARMOR_WELDED) + add_rider(M, FALSE) + return + if(M == user) + enter_pod(user) + return + + return ..() diff --git a/code/modules/spacepods/spacepod_actions.dm b/code/modules/spacepods/spacepod_actions.dm new file mode 100644 index 000000000000..dc12481b1d37 --- /dev/null +++ b/code/modules/spacepods/spacepod_actions.dm @@ -0,0 +1,122 @@ +/obj/spacepod + //Action datums + var/datum/action/innate/spacepod/spacepod_exit/exit_action = new + var/datum/action/innate/spacepod/spacepod_toggle_brakes/brakes_action = new + var/datum/action/innate/spacepod/spacepod_toggle_lights/lights_action = new + var/datum/action/innate/spacepod/spacepod_toggle_poddoors/podddoors_action = new + var/datum/action/innate/spacepod/spacepod_lock_doors/lock_action = new + +/obj/spacepod/proc/GrantActions(mob/living/user) + exit_action.Grant(user, src) + brakes_action.Grant(user, src) + lights_action.Grant(user, src) + podddoors_action.Grant(user, src) + lock_action.Grant(user, src) + +/obj/spacepod/proc/RemoveActions(mob/living/user) + exit_action.Remove(user) + brakes_action.Remove(user) + lights_action.Remove(user) + podddoors_action.Remove(user) + lock_action.Remove(user) + +/datum/action/innate/spacepod + check_flags = AB_CHECK_RESTRAINED | AB_CHECK_STUNNED | AB_CHECK_CONSCIOUS + icon_icon = 'code/modules/spacepods/icons/actions_spacepod.dmi' + var/obj/spacepod/frame + +/datum/action/innate/spacepod/Grant(mob/living/L, obj/spacepod/S) + if(S) + frame = S + . = ..() + +/datum/action/innate/spacepod/Destroy() + frame = null + return ..() + +// Actions! + +/datum/action/innate/spacepod/spacepod_exit + name = "Eject From Spacepod" + button_icon_state = "pods_exit" + +/datum/action/innate/spacepod/spacepod_exit/Activate() + frame.go_out() + +/datum/action/innate/spacepod/spacepod_toggle_brakes + name = "Toggle Spacepod Brakes" + button_icon_state = "handbrake_on" + +/datum/action/innate/spacepod/spacepod_toggle_brakes/Activate() + if(!frame.verb_check()) + return + frame.brakes = !frame.brakes + to_chat(usr, "You toggle the brakes [frame.brakes ? "on" : "off"].") + button_icon_state = "handbrake_[frame.brakes ? "on" : "off"]" + UpdateButtonIcon() + +/datum/action/innate/spacepod/spacepod_toggle_lights + name = "Toggle Spacepod Lights" + button_icon_state = "pods_lights_off" + +/datum/action/innate/spacepod/spacepod_toggle_lights/Activate() + if(!frame.verb_check()) + return + + /* + if(!frame.cell || frame.cell.charge < 1) // RMNZ: To turn off button when cell has no power + button_icon_state = "pods_lights_off" + UpdateButtonIcon() + return + */ + + frame.lights = !frame.lights + if(frame.lights) + frame.set_light(frame.lights_power) + else + frame.set_light(0) + to_chat(usr, "Lights toggled [frame.lights ? "on" : "off"].") + button_icon_state = "pods_lights_[frame.lights ? "on" : "off"]" + for(var/mob/M in frame.passengers) + to_chat(M, "Lights toggled [frame.lights ? "on" : "off"].") + button_icon_state = "pods_lights_[frame.lights ? "on" : "off"]" + UpdateButtonIcon() + +/datum/action/innate/spacepod/spacepod_toggle_poddoors + name = "Toggle Nearest Pod Doors" + button_icon_state = "blast_door_use" + +/datum/action/innate/spacepod/spacepod_toggle_poddoors/Activate() + if(!frame.verb_check()) + return + + for(var/obj/machinery/door/poddoor/multi_tile/P in orange(3, frame)) + for(var/mob/living/carbon/human/O in frame.contents) + if(P.check_access(O.get_active_hand()) || P.check_access(O.wear_id)) + if(P.density) + P.open() + return TRUE + else + P.close() + return TRUE + to_chat(usr, "Access denied.") + return + + to_chat(usr, "You are not close to any pod doors.") + +/datum/action/innate/spacepod/spacepod_lock_doors + name = "Lock Spacepod Doors" + button_icon_state = "pods_door_on" + +/datum/action/innate/spacepod/spacepod_lock_doors/Activate() + if(!frame.verb_check(FALSE)) + return + + if(!frame.lock) + to_chat(usr, "[src] has no locking mechanism.") + frame.locked = FALSE //Should never be false without a lock, but if it somehow happens, that will force an unlock. + else + frame.locked = !frame.locked + to_chat(usr, "You [frame.locked ? "lock" : "unlock"] the doors.") + button_icon_state = "pods_door_[!frame.locked ? "on" : "off"]" + UpdateButtonIcon() diff --git a/code/modules/spacepods/spacepod_construction.dm b/code/modules/spacepods/spacepod_construction.dm new file mode 100644 index 000000000000..b8db43e49bd5 --- /dev/null +++ b/code/modules/spacepods/spacepod_construction.dm @@ -0,0 +1,206 @@ +/obj/spacepod/examine(mob/user) + . = ..() + switch(construction_state) // more construction states than r-walls! + if(SPACEPOD_EMPTY) + . += "The struts holding it together can be cut and it is missing wires." + if(SPACEPOD_WIRES_LOOSE) + . += "The wires need to be screwed on." + if(SPACEPOD_WIRES_SECURED) + . += "The wires are screwed on and need a circuit board." + if(SPACEPOD_CIRCUIT_LOOSE) + . += "The circuit board is loosely attached and needs to be screwed on." + if(SPACEPOD_CIRCUIT_SECURED) + . += "The circuit board is screwed on, and there is space for a core." + if(SPACEPOD_CORE_LOOSE) + . += "The core is loosely attached and needs to be bolted on." + if(SPACEPOD_CORE_SECURED) + . += "The core is bolted on and the metal bulkhead can be attached." + if(SPACEPOD_BULKHEAD_LOOSE) + . += "The bulkhead is loosely attached and can be bolted down." + if(SPACEPOD_BULKHEAD_SECURED) + . += "The bulkhead is bolted on but not welded on." + if(SPACEPOD_BULKHEAD_WELDED) + . += "The bulkhead is welded on and armor can be attached." + if(SPACEPOD_ARMOR_LOOSE) + . += "The armor is loosely attached and can be bolted down." + if(SPACEPOD_ARMOR_SECURED) + . += "The armor is bolted on but not welded on." + if(SPACEPOD_ARMOR_WELDED) + if(hatch_open) + if(cell || internal_tank || equipment.len) + . += "The maintenance hatch is pried open and there are parts inside that can be removed." + else + . += "The maintenance hatch is pried open and the armor is welded on." + else + if(locked) + . += "[src] is locked." + else + . += "The maintenance hatch is closed." + +/obj/spacepod/proc/handle_spacepod_construction(obj/item/W, mob/living/user) + // time for a construction/deconstruction process to rival r-walls + var/obj/item/stack/ST = W + switch(construction_state) + if(SPACEPOD_EMPTY) + if(W.tool_behaviour == TOOL_WIRECUTTER) + . = TRUE + user.visible_message("[user] deconstructs [src].", "You deconstruct [src].") + W.play_tool_sound(src) + deconstruct(TRUE) + else if(istype(W, /obj/item/stack/cable_coil)) + . = TRUE + if(ST.use(10)) + user.visible_message("[user] wires [src].", "You wire [src].") + construction_state++ + else + to_chat(user, "You need 10 wires for this!") + if(SPACEPOD_WIRES_LOOSE) + if(W.tool_behaviour == TOOL_WIRECUTTER) + . = TRUE + var/obj/item/stack/cable_coil/CC = new + CC.amount = 10 + CC.forceMove(loc) + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] cuts [src]'s wiring.", "You remove [src]'s wiring.") + else if(W.tool_behaviour == TOOL_SCREWDRIVER) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] screws on [src]'s wiring harnesses.", "You screw on [src]'s wiring harnesses.") + if(SPACEPOD_WIRES_SECURED) + if(W.tool_behaviour == TOOL_SCREWDRIVER) + . = TRUE + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] unclips [src]'s wiring harnesses.", "You unclip [src]'s wiring harnesses.") + else if(istype(W, /obj/item/circuitboard/mecha/pod)) + . = TRUE + if(user.canUnEquip(W)) + qdel(W) + construction_state++ + user.visible_message("[user] inserts the mainboard into [src].", "You insert the mainboard into [src].") + else + to_chat(user, "[W] is stuck to your hand!") + if(SPACEPOD_CIRCUIT_LOOSE) + if(W.tool_behaviour == TOOL_CROWBAR) + . = TRUE + W.play_tool_sound(src) + construction_state-- + var/obj/item/circuitboard/mecha/pod/B = new + B.forceMove(loc) + user.visible_message("[user] pries out the mainboard from [src].", "You pry out the mainboard from [src].") + else if(W.tool_behaviour == TOOL_SCREWDRIVER) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] secures the mainboard to [src].", "You secure the mainboard to [src].") + if(SPACEPOD_CIRCUIT_SECURED) + if(W.tool_behaviour == TOOL_SCREWDRIVER) + . = TRUE + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] unsecures the mainboard.", "You unscrew the mainboard from [src].") + else if(istype(W, /obj/item/pod_parts/core)) + . = TRUE + if(user.canUnEquip(W)) + qdel(W) + construction_state++ + user.visible_message("[user] inserts the core into [src].", "You carefully insert the core into [src].") + else + to_chat(user, "[W] is stuck to your hand!") + if(SPACEPOD_CORE_LOOSE) + if(W.tool_behaviour == TOOL_CROWBAR) + . = TRUE + W.play_tool_sound(src) + var/obj/item/pod_parts/core/C = new + C.forceMove(loc) + construction_state-- + user.visible_message("[user] delicately removes the core from [src].", "You delicately remove the core from [src].") + else if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] secures [src]'s core bolts.", "You secure [src]'s core bolts.") + if(SPACEPOD_CORE_SECURED) + if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] unsecures [src]'s core.", "You unsecure [src]'s core.") + else if(istype(W, /obj/item/stack/sheet/metal)) + . = TRUE + if(ST.use(5)) + user.visible_message("[user] fabricates a pressure bulkhead for [src].", "You frabricate a pressure bulkhead for [src].") + construction_state++ + else + to_chat(user, "You need 5 metal for this!") + if(SPACEPOD_BULKHEAD_LOOSE) + if(W.tool_behaviour == TOOL_CROWBAR) + . = TRUE + W.play_tool_sound(src) + construction_state-- + // RMNZ: Test this thing out + var/obj/item/stack/sheet/metal/M = new + M.amount = 5 + M.forceMove(loc) + user.visible_message("[user] pops [src]'s bulkhead panelling loose.", "You pop [src]'s bulkhead panelling loose.") + else if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] secures [src]'s bulkhead panelling.", "You secure [src]'s bulkhead panelling.") + if(SPACEPOD_BULKHEAD_SECURED) + if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] unbolts [src]'s bulkhead panelling.", "You unbolt [src]'s bulkhead panelling.") + else if(W.tool_behaviour == TOOL_WELDER) + . = TRUE + if(W.use_tool(src, user, 20, amount=3, volume = 50)) + construction_state = SPACEPOD_BULKHEAD_WELDED + user.visible_message("[user] seals [src]'s bulkhead panelling.", "You seal [src]'s bulkhead panelling.") + if(SPACEPOD_BULKHEAD_WELDED) + if(W.tool_behaviour == TOOL_WELDER) + . = TRUE + if(W.use_tool(src, user, 20, amount=3, volume = 50)) + construction_state = SPACEPOD_BULKHEAD_SECURED + user.visible_message("[user] cuts [src]'s bulkhead panelling loose.", "You cut [src]'s bulkhead panelling loose.") + if(istype(W, /obj/item/pod_parts/armor)) + . = TRUE + if(user.drop_item()) + W.forceMove() + add_armor(W) + construction_state++ + user.visible_message("[user] installs [src]'s armor plating.", "You install [src]'s armor plating.") + else + to_chat(user, "[W] is stuck to your hand!") + if(SPACEPOD_ARMOR_LOOSE) + if(W.tool_behaviour == TOOL_CROWBAR) + . = TRUE + if(pod_armor) + pod_armor.forceMove(loc) + remove_armor() + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] pries off [src]'s armor.", "You pry off [src]'s armor.") + if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] bolts down [src]'s armor.", "You bolt down [src]'s armor.") + if(SPACEPOD_ARMOR_SECURED) + if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state-- + user.visible_message("[user] unsecures [src]'s armor.", "You unsecure [src]'s armor.") + else if(W.tool_behaviour == TOOL_WELDER) + . = TRUE + if(W.use_tool(src, user, 50, amount=3, volume = 50)) + construction_state = SPACEPOD_ARMOR_WELDED + user.visible_message("[user] welds [src]'s armor.", "You weld [src]'s armor.") + // finally this took too fucking long + // somehow this takes up 40 lines less code than the original, code-less version. And it actually works + update_appearance(UPDATE_ICON) diff --git a/code/modules/spacepods/spacepod_equipment.dm b/code/modules/spacepods/spacepod_equipment.dm new file mode 100644 index 000000000000..d1f35476329b --- /dev/null +++ b/code/modules/spacepods/spacepod_equipment.dm @@ -0,0 +1,379 @@ +/obj/item/spacepod_equipment + var/obj/spacepod/spacepod + icon = 'code/modules/spacepods/icons/parts.dmi' + var/slot = SPACEPOD_SLOT_MISC + var/slot_space = 1 + +/obj/item/spacepod_equipment/proc/on_install(obj/spacepod/SP) + spacepod = SP + SP.equipment |= src + forceMove(SP) + +/obj/item/spacepod_equipment/proc/on_uninstall() + spacepod.equipment -= src + +/obj/item/spacepod_equipment/proc/can_install(obj/spacepod/SP, mob/user) + var/room = SP.equipment_slot_limits[slot] || 0 + for(var/obj/item/spacepod_equipment/EQ in SP.equipment) + if(EQ.slot == slot) + room -= EQ.slot_space + if(room < slot_space) + to_chat(user, "There's no room for another [slot] system!") + return FALSE + return TRUE + +/obj/item/spacepod_equipment/proc/can_uninstall(mob/user) + return TRUE + +// RMNZ: Weapons doesn't work + +/* +/obj/item/spacepod_equipment/weaponry + slot = SPACEPOD_SLOT_WEAPON + var/projectile_type + var/shot_cost = 0 + var/shots_per = 1 + var/fire_sound + var/fire_delay = 15 + var/overlay_icon + var/overlay_icon_state + +/obj/item/spacepod_equipment/weaponry/on_install(obj/spacepod/SP) + . = ..() + SP.weapon = src + SP.update_appearance(UPDATE_ICON) + +/obj/item/spacepod_equipment/weaponry/on_uninstall() + . = ..() + if(spacepod.weapon == src) + spacepod.weapon = null + +/obj/item/spacepod_equipment/weaponry/proc/fire_weapons(target) + if(spacepod.next_firetime > world.time) + to_chat(usr, "Your weapons are recharging.") + playsound(src, 'sound/weapons/empty.ogg', 30, TRUE) + return + if(!spacepod.cell || !spacepod.cell.use(shot_cost)) + to_chat(usr, "Insufficient charge to fire the weapons") + playsound(src, 'sound/weapons/empty.ogg', 30, TRUE) + return + spacepod.next_firetime = world.time + fire_delay + for(var/I in 1 to shots_per) + spacepod.fire_projectiles(projectile_type, target) + playsound(src, fire_sound, 50, TRUE) + sleep(0.2 SECONDS) +*/ + +//////////////////////////// +////// Cargo System ////// +//////////////////////////// + +/obj/item/spacepod_equipment/cargo // this one holds large crates and shit + name = "pod cargo" + desc = "You shouldn't be seeing this" + icon_state = "cargo_blank" + slot = SPACEPOD_SLOT_CARGO + +// RMNZ: Doesn't work properly + +/* +/obj/item/spacepod_equipment/cargo/large + name = "spacepod crate storage system" + desc = "A heavy duty storage system for spacepods. Holds one crate." + icon_state = "cargo_crate" + var/obj/storage = null + var/storage_type = /obj/structure/closet/crate + +/obj/item/spacepod_equipment/cargo/large/on_install(obj/spacepod/SP) + ..() + // COMSIG - a way to make component signals sound more important than they actually are. + // it's not even limited to components. Does this look like a component to you? + // Okay here's a better name: It's a fucking *event handler*. Like the ones in javascript. + // a much more descriptive and less scary name than fucking "COMSIG". But noooooooooo + // the TG coders were too self important to pick a descriptive name and wanted to sound all scientific + RegisterSignal(SP, COMSIG_MOUSEDROPPED_ONTO, PROC_REF(spacepod_mousedrop)) + SP.verbs |= /obj/spacepod/proc/unload_cargo + +/obj/item/spacepod_equipment/cargo/large/on_uninstall() + UnregisterSignal(spacepod, COMSIG_MOUSEDROPPED_ONTO) + ..() + if(!(locate(/obj/item/spacepod_equipment/cargo/large) in spacepod.equipment)) + spacepod.verbs -= /obj/spacepod/proc/unload_cargo + +/obj/item/spacepod_equipment/cargo/large/can_uninstall(mob/user) + if(storage) + to_chat(user, "Unload the cargo first!") + return FALSE + return ..() + +/obj/spacepod/proc/unload_cargo() // if I could i'd put this on spacepod_equipment but unfortunately BYOND is stupid | RMNZ: What is this comment? Make this as action + set name = "Unload Cargo" + set category = "Spacepod" + set src = usr.loc + + if(!verb_check()) + return + + //var/used_key_list = list() + var/cargo_map = list() + for(var/obj/item/spacepod_equipment/cargo/large/E in equipment) + if(!E.storage) + continue + cargo_map[E.name] = E + var/selection = input(usr, "Unload which cargo?", null, null) as null|anything in cargo_map + var/obj/item/spacepod_equipment/cargo/large/E = cargo_map[selection] + if(!selection || !verb_check() || !E || !(E in equipment) || !E.storage) + return + E.storage.forceMove(loc) + E.storage = null + +/obj/item/spacepod_equipment/cargo/large/proc/spacepod_mousedrop(obj/spacepod/SP, obj/A, mob/user) + if(user == SP.pilot || (user in SP.passengers)) + return FALSE + if(istype(A, storage_type) && SP.Adjacent(A)) // For loading ore boxes + if(!storage) + to_chat(user, "You begin loading [A] into [SP]'s [src]") + if(do_after(user, 4 SECONDS, target = A)) + storage = A + A.forceMove(src) + to_chat(user, "You load [A] into [SP]'s [src]!") + else + to_chat(user, "You fail to load [A] into [SP]'s [src]") + else + to_chat(user, "[SP] already has \an [storage]") + return TRUE + return FALSE + +/obj/item/spacepod_equipment/cargo/large/ore //RMNZ: Can't load ore_box + name = "spacepod ore storage system" + desc = "An ore storage system for spacepods. Scoops up any ore you drive over. Needs to be loaded with an ore box to work" + icon_state = "cargo_ore" + storage_type = /obj/structure/ore_box + +/obj/item/spacepod_equipment/cargo/large/ore/on_install(obj/spacepod/SP) + ..() + RegisterSignal(SP, COMSIG_MOVABLE_MOVED, PROC_REF(spacepod_moved)) + +/obj/item/spacepod_equipment/cargo/large/ore/on_uninstall() + UnregisterSignal(spacepod, COMSIG_MOVABLE_MOVED) + ..() + +/obj/item/spacepod_equipment/cargo/large/ore/proc/spacepod_moved(obj/spacepod/SP) + if(storage) + for(var/turf/T in SP.locs) + for(var/obj/item/stack/ore in T) + ore.forceMove(storage) +*/ + +/obj/item/spacepod_equipment/cargo/chair + name = "passenger seat" + desc = "A passenger seat for a spacepod." + icon_state = "sec_cargo_chair" + var/occupant_mod = 1 + +/obj/item/spacepod_equipment/cargo/chair/on_install(obj/spacepod/SP) + ..() + SP.max_passengers += occupant_mod + +/obj/item/spacepod_equipment/cargo/chair/on_uninstall() + spacepod.max_passengers -= occupant_mod + ..() + +/obj/item/spacepod_equipment/cargo/chair/can_uninstall(mob/user) + if(spacepod.passengers.len > (spacepod.max_passengers - occupant_mod)) + to_chat(user, "You can't remove an occupied seat! Remove the occupant first.") + return FALSE + return ..() + +///////////////////////////// +////// Weapon System ////// +///////////////////////////// + +// RMNZ: Doesn't shoot (?) + +/* +/obj/item/spacepod_equipment/weaponry/disabler + name = "disabler system" + desc = "A weak disabler system for space pods, fires disabler beams." + icon_state = "weapon_taser" + projectile_type = /obj/item/projectile/beam/disabler + shot_cost = 400 + fire_sound = 'sound/weapons/taser2.ogg' + overlay_icon = 'code/modules/spacepods/icons/2x2.dmi' + overlay_icon_state = "pod_weapon_disabler" + +/obj/item/spacepod_equipment/weaponry/burst_disabler + name = "burst disabler system" + desc = "A weak disabler system for space pods, this one fires 3 at a time." + icon_state = "weapon_burst_taser" + projectile_type = /obj/item/projectile/beam/disabler + shot_cost = 1200 + shots_per = 3 + fire_sound = 'sound/weapons/taser2.ogg' + fire_delay = 30 + overlay_icon = 'code/modules/spacepods/icons/2x2.dmi' + overlay_icon_state = "pod_weapon_disabler" + +/obj/item/spacepod_equipment/weaponry/laser + name = "laser system" + desc = "A weak laser system for space pods, fires concentrated bursts of energy." + icon_state = "weapon_laser" + projectile_type = /obj/item/projectile/beam/laser + shot_cost = 600 + fire_sound = 'sound/weapons/Laser.ogg' + overlay_icon = 'code/modules/spacepods/icons/2x2.dmi' + overlay_icon_state = "pod_weapon_laser" + +// MINING LASERS +/obj/item/spacepod_equipment/weaponry/basic_pod_ka + name = "weak kinetic accelerator" + desc = "A weak kinetic accelerator for space pods, fires bursts of energy that cut through rock." + icon = 'goon/icons/obj/spacepods/parts.dmi' + icon_state = "pod_taser" + projectile_type = /obj/item/projectile/kinetic/pod + shot_cost = 300 + fire_delay = 14 + fire_sound = 'sound/weapons/Kenetic_accel.ogg' + +/obj/item/spacepod_equipment/weaponry/pod_ka + name = "kinetic accelerator system" + desc = "A kinetic accelerator system for space pods, fires bursts of energy that cut through rock." + icon = 'goon/icons/obj/spacepods/parts.dmi' + icon_state = "pod_m_laser" + projectile_type = /obj/item/projectile/kinetic/pod/regular + shot_cost = 250 + fire_delay = 10 + fire_sound = 'sound/weapons/Kenetic_accel.ogg' + +/obj/item/projectile/kinetic/pod + range = 4 + +/obj/item/projectile/kinetic/pod/regular + damage = 50 + pressure_decrease = 0.5 + +/obj/item/spacepod_equipment/weaponry/plasma_cutter + name = "plasma cutter system" + desc = "A plasma cutter system for space pods. It is capable of expelling concentrated plasma bursts to mine or cut off xeno limbs!" + icon = 'goon/icons/obj/spacepods/parts.dmi' + icon_state = "pod_p_cutter" + projectile_type = /obj/item/projectile/plasma + shot_cost = 250 + fire_delay = 10 + fire_sound = 'sound/weapons/plasma_cutter.ogg' + overlay_icon = 'code/modules/spacepods/icons/2x2.dmi' + overlay_icon_state = "pod_weapon_plasma" + +/obj/item/spacepod_equipment/weaponry/plasma_cutter/adv + name = "enhanced plasma cutter system" + desc = "An enhanced plasma cutter system for space pods. It is capable of expelling concentrated plasma bursts to mine or cut off xeno faces!" + icon_state = "pod_ap_cutter" + projectile_type = /obj/item/projectile/plasma/adv + shot_cost = 200 + fire_delay = 8 + +*/ +//////////////////////////// +////// Misc. System ////// +//////////////////////////// + +// RMNZ: No purpose (?) + +/* +/obj/item/spacepod_equipment/tracker + name = "spacepod tracking system" + desc = "A tracking device for spacepods." + icon = 'goon/icons/obj/spacepods/parts.dmi' + icon_state = "pod_locator" +*/ +/////////////////////////// +////// Lock System ////// +/////////////////////////// + +/obj/item/spacepod_equipment/lock + name = "pod lock" + desc = "You shouldn't be seeing this" + icon_state = "blank" + slot = SPACEPOD_SLOT_LOCK + +/obj/item/spacepod_equipment/lock/on_install(obj/spacepod/SP) + ..() + RegisterSignal(SP, COMSIG_PARENT_ATTACKBY, PROC_REF(spacepod_attackby)) + SP.lock = src + +/obj/item/spacepod_equipment/lock/on_uninstall() + UnregisterSignal(spacepod, COMSIG_PARENT_ATTACKBY) + if(spacepod.lock == src) + spacepod.lock = null + spacepod.locked = FALSE + ..() + +/obj/item/spacepod_equipment/lock/proc/spacepod_attackby(obj/spacepod/SP, I, mob/user) + return FALSE + +// Key and Tumbler System +/obj/item/spacepod_equipment/lock/keyed + name = "spacepod tumbler lock" + desc = "A locking system to stop podjacking. This version uses a standalone key." + icon_state = "lock_tumbler" + var/static/id_source = 0 + var/id = null + +/obj/item/spacepod_equipment/lock/keyed/Initialize(mapload) + . = ..() + if(id == null) + id = ++id_source + +/obj/item/spacepod_equipment/lock/keyed/spacepod_attackby(obj/spacepod/SP, obj/item/I, mob/user) + if(istype(I, /obj/item/spacepod_key)) + var/obj/item/spacepod_key/key = I + if(key.id == id) + SP.lock_pod() + return + else + to_chat(user, "This is the wrong key!") + return TRUE + return FALSE + +/obj/item/spacepod_equipment/lock/keyed/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/spacepod_key)) + var/obj/item/spacepod_key/key = I + if(key.id == null) + key.id = id + to_chat(user, "You grind the blank key to fit the lock.") + else + to_chat(user, "This key is already ground!") + else + ..() + +/obj/item/spacepod_equipment/lock/keyed/sec + id = "security spacepod" + +// The key +/obj/item/spacepod_key + name = "spacepod key" + desc = "A key for a spacepod lock." + icon = 'code/modules/spacepods/icons/parts.dmi' + icon_state = "podkey" + w_class = WEIGHT_CLASS_TINY + var/id = null + +/obj/item/spacepod_key/sec + name = "security spacepod key" + desc = "Unlocks the security spacepod. Probably best kept out of assistant hands." + id = "security spacepod" + +/obj/item/device/lock_buster + name = "pod lock buster" + desc = "Destroys a podlock in mere seconds once applied. Waranty void if used." + icon = 'code/modules/spacepods/icons/parts.dmi' + icon_state = "lock_buster_off" + var/on = FALSE + +/obj/item/device/lock_buster/attack_self(mob/user) + on = !on + if(on) + icon_state = "lock_buster_on" + else + icon_state = "lock_buster_off" + to_chat(user, "You turn the [src] [on ? "on" : "off"].") diff --git a/code/modules/spacepods/spacepod_parts.dm b/code/modules/spacepods/spacepod_parts.dm new file mode 100644 index 000000000000..32e098aa1aef --- /dev/null +++ b/code/modules/spacepods/spacepod_parts.dm @@ -0,0 +1,181 @@ +/obj/item/pod_parts + icon = 'goon/icons/obj/spacepods/parts.dmi' + w_class = WEIGHT_CLASS_GIGANTIC + flags = CONDUCT + +/obj/item/pod_parts/core + name = "space pod core" + icon_state = "core" + +/obj/item/pod_parts/pod_frame + name = "space pod frame" + density = FALSE + anchored = FALSE + var/link_to = null + var/link_angle = 0 + +/obj/item/pod_parts/pod_frame/attack_hand() + return + +/obj/item/pod_parts/pod_frame/Initialize(mapload) + . = ..() + AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE) + +/obj/item/pod_parts/pod_frame/proc/find_square() + /* + each part, in essence, stores the relative position of another part + you can find where this part should be by looking at the current direction of the current part and applying the link_angle + the link_angle is the angle between the part's direction and its following part, which is the current part's link_to + the code works by going in a loop - each part is capable of starting a loop by checking for the part after it, and that part checking, and so on + this 4-part loop, starting from any part of the frame, can determine if all the parts are properly in place and aligned + it also checks that each part is unique, and that all the parts are there for the spacepod itself + */ + //RMNZ: Addition of new pods + var/neededparts = list(/obj/item/pod_parts/pod_frame/aft_port, /obj/item/pod_parts/pod_frame/aft_starboard, /obj/item/pod_parts/pod_frame/fore_port, /obj/item/pod_parts/pod_frame/fore_starboard) + var/turf/T + var/obj/item/pod_parts/pod_frame/linked + var/obj/item/pod_parts/pod_frame/pointer + var/list/connectedparts = list() + neededparts -= src + linked = src + for(var/i = 1; i <= 4; i++) + T = get_turf(get_step(linked, turn(linked.dir, -linked.link_angle))) //get the next place that we want to look at + if(locate(linked.link_to) in T) + pointer = locate(linked.link_to) in T + if(istype(pointer, linked.link_to) && pointer.dir == linked.dir && pointer.anchored) + if(!(pointer in connectedparts)) + connectedparts += pointer + linked = pointer + pointer = null + if(connectedparts.len < 4) + return FALSE + for(var/i = 1; i <=4; i++) + var/obj/item/pod_parts/pod_frame/F = connectedparts[i] + if(F.type in neededparts) //if one of the items can be founded in neededparts + neededparts -= F.type + else //because neededparts has 4 distinct items, this must be called if theyre not all in place and wrenched + return FALSE + return connectedparts + +/obj/item/pod_parts/pod_frame/attackby(obj/item/O, mob/user) + if(istype(O, /obj/item/stack/rods)) + var/obj/item/stack/rods/R = O + var/list/linkedparts = find_square() + if(!linkedparts) + to_chat(user, "You cannot assemble a pod frame because you do not have the necessary assembly.") + return TRUE + if(!R.use(10)) + to_chat(user, "You need 10 rods for this.") + return TRUE + var/obj/spacepod/pod = new + pod.forceMove(loc) + switch(dir) + if(NORTH) + pod.angle = 0 + if(SOUTH) + pod.angle = 180 + if(WEST) + pod.angle = 270 + if(EAST) + pod.angle = 90 + pod.process(2) + to_chat(user, "You strut the pod frame together.") + for(var/obj/item/pod_parts/pod_frame/F in linkedparts) + if(1 == turn(F.dir, -F.link_angle)) //if the part links north during construction, as the bottom left part always does + pod.forceMove(F.loc) + qdel(F) + return TRUE + if(O.tool_behaviour == TOOL_WRENCH) + to_chat(user, "You [!anchored ? "secure \the [src] in place." : "remove the securing bolts."]") + anchored = !anchored + density = anchored + O.play_tool_sound(src) + return TRUE + +/obj/item/pod_parts/pod_frame/fore_port + name = "fore port pod frame" + icon_state = "pod_fp" + desc = "A space pod frame component. This is the fore port component." + link_to = /obj/item/pod_parts/pod_frame/fore_starboard + link_angle = 90 + +/obj/item/pod_parts/pod_frame/fore_starboard + name = "fore starboard pod frame" + icon_state = "pod_fs" + desc = "A space pod frame component. This is the fore starboard component." + link_to = /obj/item/pod_parts/pod_frame/aft_starboard + link_angle = 180 + +/obj/item/pod_parts/pod_frame/aft_port + name = "aft port pod frame" + icon_state = "pod_ap" + desc = "A space pod frame component. This is the aft port component." + link_to = /obj/item/pod_parts/pod_frame/fore_port + link_angle = 0 + +/obj/item/pod_parts/pod_frame/aft_starboard + name = "aft starboard pod frame" + icon_state = "pod_as" + desc = "A space pod frame component. This is the aft starboard component." + link_to = /obj/item/pod_parts/pod_frame/aft_port + link_angle = 270 + +/obj/item/pod_parts/armor + name = "civilian pod armor" + icon_state = "pod_armor_civ" + desc = "Spacepod armor. This is the civilian version. It looks rather flimsy." + var/pod_icon = 'goon/icons/obj/spacepods/2x2.dmi' + var/pod_icon_state = "pod_civ" + var/pod_desc = "A sleek civilian space pod." + var/pod_integrity = 250 + +/obj/item/pod_parts/armor/syndicate + name = "syndicate pod armor" + icon_state = "pod_armor_synd" + desc = "Tough-looking spacepod armor, with a bold \"FUCK NT\" stenciled directly into it." + pod_icon_state = "pod_synd" + pod_desc = "A menacing military space pod with \"FUCK NT\" stenciled onto the side" + pod_integrity = 400 + +/obj/item/pod_parts/armor/black + name = "black pod armor" + icon_state = "pod_armor_black" + desc = "Plain black spacepod armor, with no logos or insignias anywhere on it." + pod_icon_state = "pod_black" + pod_desc = "An all black space pod with no insignias." + +/obj/item/pod_parts/armor/gold + name = "golden pod armor" + icon_state = "pod_armor_gold" + desc = "Golden spacepod armor. Looks like what a rich spessmen put on their spacepod." + pod_icon_state = "pod_gold" + pod_desc = "A civilian space pod with a gold body, must have cost somebody a pretty penny" + pod_integrity = 220 + +/obj/item/pod_parts/armor/industrial + name = "industrial pod armor" + icon_state = "pod_armor_industrial" + desc = "Tough industrial-grade spacepod armor. While meant for construction work, it is commonly used in spacepod battles, too." + pod_icon_state = "pod_industrial" + pod_desc = "A rough looking space pod meant for industrial work" + pod_integrity = 330 + +/obj/item/pod_parts/armor/security + name = "security pod armor" + icon_state = "pod_armor_mil" + desc = "Tough military-grade pod armor, meant for use by the Nanotrasen military and it's sub-divisons for space combat." + pod_icon_state = "pod_mil" + pod_desc = "An armed security spacepod with reinforced armor plating brandishing the Nanotrasen Military insignia" + pod_integrity = 350 + +/obj/item/pod_parts/armor/security/red + name = "security pod armor" + icon_state = "pod_armor_synd" + desc = "Tough military-grade pod armor, meant for use by the Nanotrasen military and it's sub-divisons for space combat." + pod_icon_state = "pod_synd" + pod_desc = "An armed security spacepod with reinforced armor plating brandishing the Nanotrasen Military insignia" + pod_integrity = 350 + +/obj/item/circuitboard/mecha/pod + name = "Circuit board (Space Pod Mainboard)" + icon_state = "mainboard" diff --git a/code/modules/spacepods/spacepod_physics.dm b/code/modules/spacepods/spacepod_physics.dm new file mode 100644 index 000000000000..0330050dd381 --- /dev/null +++ b/code/modules/spacepods/spacepod_physics.dm @@ -0,0 +1,297 @@ +/obj/spacepod/process(time) + + if(world.time > last_slowprocess + 15) + last_slowprocess = world.time + slowprocess() + + var/last_offset_x = offset_x + var/last_offset_y = offset_y + var/last_angle = angle + var/desired_angular_velocity = 0 + if(isnum(desired_angle)) + // do some finagling to make sure that our angles end up rotating the short way + while(angle > desired_angle + 180) + angle -= 360 + last_angle -= 360 + while(angle < desired_angle - 180) + angle += 360 + last_angle += 360 + if(abs(desired_angle - angle) < (max_angular_acceleration * time)) + desired_angular_velocity = (desired_angle - angle) / time + else if(desired_angle > angle) + desired_angular_velocity = 2 * sqrt((desired_angle - angle) * max_angular_acceleration * 0.25) + else + desired_angular_velocity = -2 * sqrt((angle - desired_angle) * max_angular_acceleration * 0.25) + var/angular_velocity_adjustment = clamp(desired_angular_velocity - angular_velocity, -max_angular_acceleration*time, max_angular_acceleration*time) + if(angular_velocity_adjustment && cell && cell.use(abs(angular_velocity_adjustment) * 0.05)) + last_rotate = angular_velocity_adjustment / time + angular_velocity += angular_velocity_adjustment + else + last_rotate = 0 + angle += angular_velocity * time + + // calculate drag and shit + + var/velocity_mag = sqrt(velocity_x*velocity_x+velocity_y*velocity_y) // magnitude + if(velocity_mag || angular_velocity) + var/drag = 0 + for(var/turf/T in locs) + if(isspaceturf(T)) + continue + drag += 0.001 + var/floating = FALSE + if(has_gravity() && !brakes && velocity_mag > 0.1 && cell && cell.use((is_mining_level(z) ? 3 : 15) * time)) + floating = TRUE // want to fly this shit on the station? Have fun draining your battery. + if((!floating && has_gravity()) || brakes) // brakes are a kind of magboots okay? + drag += is_mining_level(z) ? 0.1 : 0.5 // some serious drag. Damn. Except lavaland, it has less gravity or something + if(velocity_mag > 5 && prob(velocity_mag * 4) && istype(T, /turf/simulated/floor)) + var/turf/simulated/floor/TF = T + TF.make_plating() // pull up some floor tiles. Stop going so fast, ree. + take_damage(3, BRUTE, MELEE, FALSE) + var/datum/gas_mixture/env = T.return_air() + if(env) + var/pressure = env.return_pressure() + drag += velocity_mag * pressure * 0.0001 // 1 atmosphere should shave off 1% of velocity per tile + if(velocity_mag > 20) + drag = max(drag, (velocity_mag - 20) / time) + if(drag) + if(velocity_mag) + var/drag_factor = 1 - clamp(drag * time / velocity_mag, 0, 1) + velocity_x *= drag_factor + velocity_y *= drag_factor + if(angular_velocity != 0) + var/drag_factor_spin = 1 - clamp(drag * 30 * time / abs(angular_velocity), 0, 1) + angular_velocity *= drag_factor_spin + + // Alright now calculate the THRUST + var/thrust_x + var/thrust_y + var/fx = cos(90 - angle) + var/fy = sin(90 - angle) + var/sx = fy + var/sy = -fx + last_thrust_forward = 0 + last_thrust_right = 0 + if(brakes) + if(user_thrust_dir) + to_chat(pilot, "Your brakes are on!") + // basically calculates how much we can brake using the thrust + var/forward_thrust = -((fx * velocity_x) + (fy * velocity_y)) / time + var/right_thrust = -((sx * velocity_x) + (sy * velocity_y)) / time + forward_thrust = clamp(forward_thrust, -backward_maxthrust, forward_maxthrust) + right_thrust = clamp(right_thrust, -side_maxthrust, side_maxthrust) + thrust_x += forward_thrust * fx + right_thrust * sx; + thrust_y += forward_thrust * fy + right_thrust * sy; + last_thrust_forward = forward_thrust + last_thrust_right = right_thrust + else // want some sort of help piloting the ship? Haha no fuck you do it yourself + if(user_thrust_dir & NORTH) + thrust_x += fx * forward_maxthrust + thrust_y += fy * forward_maxthrust + last_thrust_forward = forward_maxthrust + if(user_thrust_dir & SOUTH) + thrust_x -= fx * backward_maxthrust + thrust_y -= fy * backward_maxthrust + last_thrust_forward = -backward_maxthrust + if(user_thrust_dir & EAST) + thrust_x += sx * side_maxthrust + thrust_y += sy * side_maxthrust + last_thrust_right = side_maxthrust + if(user_thrust_dir & WEST) + thrust_x -= sx * side_maxthrust + thrust_y -= sy * side_maxthrust + last_thrust_right = -side_maxthrust + + if(cell && cell.use(10 * sqrt((thrust_x*thrust_x)+(thrust_y*thrust_y)) * time)) + velocity_x += thrust_x * time + velocity_y += thrust_y * time + else + last_thrust_forward = 0 + last_thrust_right = 0 + if(!brakes && user_thrust_dir) + to_chat(pilot, "You are out of power!") + + offset_x += velocity_x * time + offset_y += velocity_y * time + // alright so now we reconcile the offsets with the in-world position. + while((offset_x > 0 && velocity_x > 0) || (offset_y > 0 && velocity_y > 0) || (offset_x < 0 && velocity_x < 0) || (offset_y < 0 && velocity_y < 0)) + var/failed_x = FALSE + var/failed_y = FALSE + if(offset_x > 0 && velocity_x > 0) + dir = EAST + if(!Move(get_step(src, EAST))) + offset_x = 0 + failed_x = TRUE + velocity_x *= -bounce_factor + velocity_y *= lateral_bounce_factor + else + offset_x-- + last_offset_x-- + else if(offset_x < 0 && velocity_x < 0) + dir = WEST + if(!Move(get_step(src, WEST))) + offset_x = 0 + failed_x = TRUE + velocity_x *= -bounce_factor + velocity_y *= lateral_bounce_factor + else + offset_x++ + last_offset_x++ + else + failed_x = TRUE + if(offset_y > 0 && velocity_y > 0) + dir = NORTH + if(!Move(get_step(src, NORTH))) + offset_y = 0 + failed_y = TRUE + velocity_y *= -bounce_factor + velocity_x *= lateral_bounce_factor + else + offset_y-- + last_offset_y-- + else if(offset_y < 0 && velocity_y < 0) + dir = SOUTH + if(!Move(get_step(src, SOUTH))) + offset_y = 0 + failed_y = TRUE + velocity_y *= -bounce_factor + velocity_x *= lateral_bounce_factor + else + offset_y++ + last_offset_y++ + else + failed_y = TRUE + if(failed_x && failed_y) + break + // prevents situations where you go "wtf I'm clearly right next to it" as you enter a stationary spacepod + if(velocity_x == 0) + if(offset_x > 0.5) + if(Move(get_step(src, EAST))) + offset_x-- + last_offset_x-- + else + offset_x = 0 + if(offset_x < -0.5) + if(Move(get_step(src, WEST))) + offset_x++ + last_offset_x++ + else + offset_x = 0 + if(velocity_y == 0) + if(offset_y > 0.5) + if(Move(get_step(src, NORTH))) + offset_y-- + last_offset_y-- + else + offset_y = 0 + if(offset_y < -0.5) + if(Move(get_step(src, SOUTH))) + offset_y++ + last_offset_y++ + else + offset_y = 0 + dir = NORTH + var/matrix/mat_from = new() + mat_from.Turn(last_angle) + var/matrix/mat_to = new() + mat_to.Turn(angle) + transform = mat_from + pixel_x = last_offset_x*32 + pixel_y = last_offset_y*32 + animate(src, transform=mat_to, pixel_x = offset_x*32, pixel_y = offset_y*32, time = time SECONDS, flags=ANIMATION_END_NOW) + for(var/mob/living/M in contents) + var/client/C = M.client + if(!C) + continue + C.pixel_x = last_offset_x*32 + C.pixel_y = last_offset_y*32 + animate(C, pixel_x = offset_x*32, pixel_y = offset_y*32, time = time SECONDS, flags=ANIMATION_END_NOW) + user_thrust_dir = 0 + update_appearance(UPDATE_ICON) + +/obj/spacepod/Bumped(atom/movable/A) // RMNZ: Thrown items or pushable objects slightly move pods though + if(ismob(A)) // I don't like it when little silly humans can move these pods + return + if(A.dir & NORTH) + velocity_y += bump_impulse + if(A.dir & SOUTH) + velocity_y -= bump_impulse + if(A.dir & EAST) + velocity_x += bump_impulse + if(A.dir & WEST) + velocity_x -= bump_impulse + return ..() + +/obj/spacepod/Bump(atom/A) + var/bump_velocity = 0 + if(dir & (NORTH|SOUTH)) + bump_velocity = abs(velocity_y) + (abs(velocity_x) / 15) + else + bump_velocity = abs(velocity_x) + (abs(velocity_y) / 15) + if(istype(A, /obj/machinery/door/airlock)) // try to open doors + var/obj/machinery/door/D = A + if(!D.operating) + if(D.allowed(D.requiresID() ? pilot : null)) + spawn(0) + D.open() + else + D.do_animate("deny") + var/atom/movable/AM = A + if(istype(AM) && !AM.anchored && bump_velocity > 1) + step(AM, dir) + // if a bump is that fast then it's not a bump. It's a collision. + if(bump_velocity > 10 && !ismob(A)) + var/strength = bump_velocity / 10 + strength = strength * strength + strength = min(strength, 5) // don't want the explosions *too* big + // wew lad, might wanna slow down there + explosion(A, -1, round((strength - 1) / 2), round(strength)) + message_admins("[key_name_admin(pilot)] has impacted a spacepod into [A] with velocity [bump_velocity]") + take_damage(strength*10, BRUTE, MELEE, TRUE) + log_game("[key_name(pilot)] has impacted a spacepod into [A] with velocity [bump_velocity]") + visible_message("The force of the impact causes a shockwave") + else if(isliving(A) && bump_velocity > 5) + var/mob/living/M = A + M.apply_damage(bump_velocity * 2) + take_damage(bump_velocity, BRUTE, MELEE, FALSE) + playsound(M.loc, "swing_hit", 1000, 1, -1) + M.KnockOut() + M.visible_message("The force of the impact knocks [M] down!", "The force of the impact knocks you down!") + add_attack_logs(pilot, M, "impacted", src, "with velocity of [bump_velocity]") + return ..() + +/obj/spacepod/proc/fire_projectiles(proj_type, target) // if spacepods of other sizes are added override this or something + var/fx = cos(90 - angle) + var/fy = sin(90 - angle) + var/sx = fy + var/sy = -fx + var/ox = (offset_x * 32) + 16 + var/oy = (offset_y * 32) + 16 + var/list/origins = list(list(ox + fx*16 - sx*16, oy + fy*16 - sy*16), list(ox + fx*16 + sx*16, oy + fy*16 + sy*16)) + for(var/list/origin in origins) + var/this_x = origin[1] + var/this_y = origin[2] + var/turf/T = get_turf(src) + while(this_x > 16) + T = get_step(T, EAST) + this_x -= 32 + while(this_x < -16) + T = get_step(T, WEST) + this_x += 32 + while(this_y > 16) + T = get_step(T, NORTH) + this_y -= 32 + while(this_y < -16) + T = get_step(T, SOUTH) + this_y += 32 + if(!T) + continue + var/obj/item/projectile/proj = new proj_type(T) + proj.starting = T + proj.firer = usr + proj.def_zone = "chest" + proj.original = target + proj.pixel_x = round(this_x) + proj.pixel_y = round(this_y) + spawn() + proj.fire(angle) diff --git a/code/modules/spacepods/spacepod_prebuilt.dm b/code/modules/spacepods/spacepod_prebuilt.dm new file mode 100644 index 000000000000..c1b42bb1a5ab --- /dev/null +++ b/code/modules/spacepods/spacepod_prebuilt.dm @@ -0,0 +1,64 @@ +/obj/spacepod/prebuilt + icon = 'goon/icons/obj/spacepods/2x2.dmi' + icon_state = "pod_civ" + var/cell_type = /obj/item/stock_parts/cell/high/plus + var/armor_type = /obj/item/pod_parts/armor + var/internal_tank_type = /obj/machinery/atmospherics/portable/canister/air + var/equipment_types = list() + construction_state = SPACEPOD_ARMOR_WELDED + +/obj/spacepod/prebuilt/Initialize(mapload) + . =..() + add_armor(new armor_type(src)) + if(cell_type) + cell = new cell_type(src) + if(internal_tank_type) + internal_tank = new internal_tank_type(src) + for(var/equip in equipment_types) + var/obj/item/spacepod_equipment/SE = new equip(src) + SE.on_install(src) + +/obj/spacepod/prebuilt/sec + name = "security space pod" + icon_state = "pod_mil" + locked = TRUE + armor_type = /obj/item/pod_parts/armor/security + equipment_types = list(/obj/item/spacepod_equipment/weaponry/disabler, + /obj/item/spacepod_equipment/lock/keyed/sec, + /obj/item/spacepod_equipment/tracker, + /obj/item/spacepod_equipment/cargo/chair) + +// adminbus spacepod for jousting events +/obj/spacepod/prebuilt/jousting + name = "jousting space pod" + icon_state = "pod_mil" + armor_type = /obj/item/pod_parts/armor/security + cell_type = /obj/item/stock_parts/cell/infinite + equipment_types = list(/obj/item/spacepod_equipment/weaponry/laser, + /obj/item/spacepod_equipment/cargo/chair, + /obj/item/spacepod_equipment/cargo/chair) + +/obj/spacepod/prebuilt/jousting/red + icon_state = "pod_synd" + armor_type = /obj/item/pod_parts/armor/security/red + +/obj/spacepod/random + icon = 'goon/icons/obj/spacepods/2x2.dmi' + icon_state = "pod_civ" + construction_state = SPACEPOD_ARMOR_WELDED + +/obj/spacepod/random/Initialize(mapload) + . = ..() + var/armor_type = pick(/obj/item/pod_parts/armor, + /obj/item/pod_parts/armor/syndicate, + /obj/item/pod_parts/armor/black, + /obj/item/pod_parts/armor/gold, + /obj/item/pod_parts/armor/industrial, + /obj/item/pod_parts/armor/security) + add_armor(new armor_type(src)) + cell = new /obj/item/stock_parts/cell/high/empty(src) + internal_tank = new /obj/machinery/atmospherics/portable/canister/air(src) + velocity_x = rand(-3, 3) + velocity_y = rand(-3, 3) + obj_integrity = rand(100, max_integrity) + brakes = FALSE diff --git a/goon/icons/obj/spacepods/2x2.dmi b/goon/icons/obj/spacepods/2x2.dmi new file mode 100644 index 0000000000000000000000000000000000000000..02def41cf1bc43bf9a86c41adc898a1f16504cde GIT binary patch literal 7679 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 XjZR|H`S literal 0 HcmV?d00001 diff --git a/paradise.dme b/paradise.dme index 0b9703489d7d..18f8192b2d75 100644 --- a/paradise.dme +++ b/paradise.dme @@ -98,6 +98,7 @@ #include "code\__DEFINES\rolebans.dm" #include "code\__DEFINES\rust_g.dm" #include "code\__DEFINES\shuttle_defines.dm" +#include "code\__DEFINES\spacepods.dm" #include "code\__DEFINES\sight.dm" #include "code\__DEFINES\sound_defines.dm" #include "code\__DEFINES\spell_defines.dm" @@ -316,6 +317,7 @@ #include "code\controllers\subsystem\processing\fields.dm" #include "code\controllers\subsystem\processing\instruments.dm" #include "code\controllers\subsystem\processing\obj.dm" +#include "code\controllers\subsystem\processing\spacepods.dm" #include "code\controllers\subsystem\processing\processing.dm" #include "code\controllers\subsystem\processing\projectiles.dm" #include "code\controllers\subsystem\processing\SSstation.dm" @@ -395,6 +397,7 @@ #include "code\datums\components\paintable.dm" #include "code\datums\components\parry.dm" #include "code\datums\components\persistent_overlay.dm" +#include "code\datums\components\rotation.dm" #include "code\datums\components\proximity_monitor.dm" #include "code\datums\components\radioactive.dm" #include "code\datums\components\shielded.dm" @@ -2637,6 +2640,7 @@ #include "code\modules\research\designs\mining_designs.dm" #include "code\modules\research\designs\misc_designs.dm" #include "code\modules\research\designs\modsuit_designs.dm" +#include "code\modules\research\designs\spacepod_designs.dm" #include "code\modules\research\designs\power_designs.dm" #include "code\modules\research\designs\smelting_designs.dm" #include "code\modules\research\designs\stock_parts_designs.dm" @@ -2679,9 +2683,16 @@ #include "code\modules\shuttle\syndicate_shuttles.dm" #include "code\modules\space_management\heap_space_level.dm" #include "code\modules\space_management\level_check.dm" +#include "code\modules\spacepods\spacepod_actions.dm" #include "code\modules\space_management\level_traits.dm" #include "code\modules\space_management\space_chunk.dm" #include "code\modules\space_management\space_level.dm" +#include "code\modules\spacepods\spacepod_equipment.dm" +#include "code\modules\spacepods\spacepod_parts.dm" +#include "code\modules\spacepods\spacepod.dm" +#include "code\modules\spacepods\spacepod_construction.dm" +#include "code\modules\spacepods\spacepod_physics.dm" +#include "code\modules\spacepods\spacepod_prebuilt.dm" #include "code\modules\space_management\space_transition.dm" #include "code\modules\space_management\zlevel_manager.dm" #include "code\modules\station_goals\bluespace_tap.dm" From e8016d68ee2640bd66e8a346a0195d9af626cbad Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Fri, 2 Feb 2024 21:30:19 +0800 Subject: [PATCH 15/28] Small oversight from me --- code/modules/spacepods/spacepod.dm | 8 ++++---- code/modules/spacepods/spacepod_prebuilt.dm | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/code/modules/spacepods/spacepod.dm b/code/modules/spacepods/spacepod.dm index 8e6fbd8e2d92..f641a02b0985 100644 --- a/code/modules/spacepods/spacepod.dm +++ b/code/modules/spacepods/spacepod.dm @@ -121,8 +121,8 @@ GLOBAL_LIST_INIT(spacepods_list, list()) var/list/params_list = params2list(params) if(target == src || istype(target, /atom/movable/screen) || (target && (target in user.get_contents())) || user != pilot || params_list["shift"] || params_list["alt"] || params_list["ctrl"]) return FALSE - if(weapon) - weapon.fire_weapons(target) + // if(weapon) // RMNZ: As i said, weapons don't work for now + // weapon.fire_weapons(target) return TRUE /obj/spacepod/proc/enter_pod(mob/living/user) @@ -611,8 +611,8 @@ GLOBAL_LIST_INIT(spacepods_list, list()) if(obj_integrity <= max_integrity / 4) . += image(icon='goon/icons/obj/spacepods/2x2.dmi', icon_state="pod_fire") - if(weapon && weapon.overlay_icon_state) - . += image(icon=weapon.overlay_icon,icon_state=weapon.overlay_icon_state) + // if(weapon && weapon.overlay_icon_state) // RMNZ: Weapons don't work for now! + // . += image(icon=weapon.overlay_icon,icon_state=weapon.overlay_icon_state) light_color = icon_light_color[icon_state] || LIGHT_COLOR_WHITE diff --git a/code/modules/spacepods/spacepod_prebuilt.dm b/code/modules/spacepods/spacepod_prebuilt.dm index c1b42bb1a5ab..8e592c1a3311 100644 --- a/code/modules/spacepods/spacepod_prebuilt.dm +++ b/code/modules/spacepods/spacepod_prebuilt.dm @@ -23,9 +23,10 @@ icon_state = "pod_mil" locked = TRUE armor_type = /obj/item/pod_parts/armor/security - equipment_types = list(/obj/item/spacepod_equipment/weaponry/disabler, + equipment_types = list( + // /obj/item/spacepod_equipment/weaponry/disabler, //RMNZ: Weapons don't work for now! /obj/item/spacepod_equipment/lock/keyed/sec, - /obj/item/spacepod_equipment/tracker, + // /obj/item/spacepod_equipment/tracker, //RMNZ: And this too! /obj/item/spacepod_equipment/cargo/chair) // adminbus spacepod for jousting events @@ -34,7 +35,8 @@ icon_state = "pod_mil" armor_type = /obj/item/pod_parts/armor/security cell_type = /obj/item/stock_parts/cell/infinite - equipment_types = list(/obj/item/spacepod_equipment/weaponry/laser, + equipment_types = list( + // /obj/item/spacepod_equipment/weaponry/laser, //RMNZ: Weapons don't work for now! /obj/item/spacepod_equipment/cargo/chair, /obj/item/spacepod_equipment/cargo/chair) From ee22e14880cb943a410426e8cfd69de27a01b81d Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Fri, 2 Feb 2024 21:55:05 +0800 Subject: [PATCH 16/28] Testmerge "is_helpers" fix + Indentation fix --- code/__DEFINES/is_helpers.dm | 2 -- code/modules/mob/living/living.dm | 1 + code/modules/spacepods/spacepod.dm | 10 +++++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index fa918c4d41f9..e73af05c7d61 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -52,8 +52,6 @@ #define ismecha(A) (istype(A, /obj/mecha)) -#define isspacepod(A) (istype(A, /obj/spacepod)) - #define iseffect(A) (istype(A, /obj/effect)) #define isclothing(A) (istype(A, /obj/item/clothing)) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 681ff41bdbe2..0e8c5c72d7fc 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -926,6 +926,7 @@ var/obj/mecha/M = loc loc_temp = M.return_temperature() + #define isspacepod(A) (istype(A, /obj/spacepod)) // RMNZ: Temporary solution for testmerge. Should be in is_helpers else if(isspacepod(loc)) var/obj/spacepod/S = loc loc_temp = S.return_temperature() diff --git a/code/modules/spacepods/spacepod.dm b/code/modules/spacepods/spacepod.dm index f641a02b0985..c37d6b3e6bd9 100644 --- a/code/modules/spacepods/spacepod.dm +++ b/code/modules/spacepods/spacepod.dm @@ -77,11 +77,11 @@ GLOBAL_LIST_INIT(spacepods_list, list()) var/lights = 0 var/lights_power = 6 var/static/list/icon_light_color = list("pod_civ" = LIGHT_COLOR_WHITE, \ - "pod_mil" = "#BBF093", \ - "pod_synd" = LIGHT_COLOR_RED, \ - "pod_gold" = LIGHT_COLOR_WHITE, \ - "pod_black" = "#3B8FE5", \ - "pod_industrial" = "#CCCC00") + "pod_mil" = "#BBF093", \ + "pod_synd" = LIGHT_COLOR_RED, \ + "pod_gold" = LIGHT_COLOR_WHITE, \ + "pod_black" = "#3B8FE5", \ + "pod_industrial" = "#CCCC00") var/bump_impulse = 0.6 var/bounce_factor = 0.2 // how much of our velocity to keep on collision From 85ae2b5daa85768e76b72428da0683d290b0a80c Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Fri, 2 Feb 2024 22:08:36 +0800 Subject: [PATCH 17/28] Small linter fix --- .../subsystem/processing/{spacepods.dm => spacepod.dm} | 4 ++-- code/modules/spacepods/spacepod.dm | 2 +- paradise.dme | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename code/controllers/subsystem/processing/{spacepods.dm => spacepod.dm} (87%) diff --git a/code/controllers/subsystem/processing/spacepods.dm b/code/controllers/subsystem/processing/spacepod.dm similarity index 87% rename from code/controllers/subsystem/processing/spacepods.dm rename to code/controllers/subsystem/processing/spacepod.dm index 036beea2fa4d..7c8846a79806 100644 --- a/code/controllers/subsystem/processing/spacepods.dm +++ b/code/controllers/subsystem/processing/spacepod.dm @@ -5,8 +5,8 @@ // RMNZ: Maybe performance issues? -PROCESSING_SUBSYSTEM_DEF(spacepods) - name = "Spacepods" +PROCESSING_SUBSYSTEM_DEF(spacepod) + name = "Spacepod" wait = 0.075 stat_tag = "SP" offline_implications = "Spacepods will no longer process. Shuttle call recommended." diff --git a/code/modules/spacepods/spacepod.dm b/code/modules/spacepods/spacepod.dm index c37d6b3e6bd9..e0db75c01d8c 100644 --- a/code/modules/spacepods/spacepod.dm +++ b/code/modules/spacepods/spacepod.dm @@ -90,7 +90,7 @@ GLOBAL_LIST_INIT(spacepods_list, list()) /obj/spacepod/Initialize(mapload) . = ..() GLOB.spacepods_list += src - START_PROCESSING(SSspacepods, src) + START_PROCESSING(SSspacepod, src) cabin_air = new cabin_air.temperature = T20C cabin_air.volume = 200 diff --git a/paradise.dme b/paradise.dme index 18f8192b2d75..a2e16421d417 100644 --- a/paradise.dme +++ b/paradise.dme @@ -317,7 +317,7 @@ #include "code\controllers\subsystem\processing\fields.dm" #include "code\controllers\subsystem\processing\instruments.dm" #include "code\controllers\subsystem\processing\obj.dm" -#include "code\controllers\subsystem\processing\spacepods.dm" +#include "code\controllers\subsystem\processing\spacepod.dm" #include "code\controllers\subsystem\processing\processing.dm" #include "code\controllers\subsystem\processing\projectiles.dm" #include "code\controllers\subsystem\processing\SSstation.dm" From 64856041318c06a13e045cda0bc15849c883eb13 Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Fri, 2 Feb 2024 22:14:25 +0800 Subject: [PATCH 18/28] Small linter fix x2 --- code/modules/spacepods/{spacepod.dm => spacepods.dm} | 0 paradise.dme | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename code/modules/spacepods/{spacepod.dm => spacepods.dm} (100%) diff --git a/code/modules/spacepods/spacepod.dm b/code/modules/spacepods/spacepods.dm similarity index 100% rename from code/modules/spacepods/spacepod.dm rename to code/modules/spacepods/spacepods.dm diff --git a/paradise.dme b/paradise.dme index a2e16421d417..7a6a1c454641 100644 --- a/paradise.dme +++ b/paradise.dme @@ -2689,7 +2689,7 @@ #include "code\modules\space_management\space_level.dm" #include "code\modules\spacepods\spacepod_equipment.dm" #include "code\modules\spacepods\spacepod_parts.dm" -#include "code\modules\spacepods\spacepod.dm" +#include "code\modules\spacepods\spacepods.dm" #include "code\modules\spacepods\spacepod_construction.dm" #include "code\modules\spacepods\spacepod_physics.dm" #include "code\modules\spacepods\spacepod_prebuilt.dm" From 75d786714f3876441913c0f428b0f6e8af9a9281 Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Fri, 2 Feb 2024 22:20:33 +0800 Subject: [PATCH 19/28] Action buttons possible fix --- code/__DEFINES/{spacepods.dm => spacepods_defines.dm} | 0 code/modules/spacepods/spacepods.dm | 2 +- paradise.dme | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename code/__DEFINES/{spacepods.dm => spacepods_defines.dm} (100%) diff --git a/code/__DEFINES/spacepods.dm b/code/__DEFINES/spacepods_defines.dm similarity index 100% rename from code/__DEFINES/spacepods.dm rename to code/__DEFINES/spacepods_defines.dm diff --git a/code/modules/spacepods/spacepods.dm b/code/modules/spacepods/spacepods.dm index e0db75c01d8c..12cad63315bc 100644 --- a/code/modules/spacepods/spacepods.dm +++ b/code/modules/spacepods/spacepods.dm @@ -177,7 +177,7 @@ GLOBAL_LIST_INIT(spacepods_list, list()) pilot = M LAZYOR(M.mousemove_intercept_objects, src) M.click_intercept = src - // GrantActions(M) + GrantActions(M) // addverbs(M) else if(passengers.len < max_passengers) passengers += M diff --git a/paradise.dme b/paradise.dme index 7a6a1c454641..39e2d543716e 100644 --- a/paradise.dme +++ b/paradise.dme @@ -98,7 +98,7 @@ #include "code\__DEFINES\rolebans.dm" #include "code\__DEFINES\rust_g.dm" #include "code\__DEFINES\shuttle_defines.dm" -#include "code\__DEFINES\spacepods.dm" +#include "code\__DEFINES\spacepods_defines.dm" #include "code\__DEFINES\sight.dm" #include "code\__DEFINES\sound_defines.dm" #include "code\__DEFINES\spell_defines.dm" From c2d7f858aa28a8751c0a828a0309ebc1bf0494bd Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Sat, 3 Feb 2024 05:41:26 +0800 Subject: [PATCH 20/28] Action-buttons possible fix x2 --- code/modules/spacepods/spacepods.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/spacepods/spacepods.dm b/code/modules/spacepods/spacepods.dm index 12cad63315bc..aa80881f8e51 100644 --- a/code/modules/spacepods/spacepods.dm +++ b/code/modules/spacepods/spacepods.dm @@ -181,6 +181,7 @@ GLOBAL_LIST_INIT(spacepods_list, list()) // addverbs(M) else if(passengers.len < max_passengers) passengers += M + GrantActions(M) else return FALSE GrantActions(M) // Passengers have buttons now From 0a1e28c22de8a9ef083acf4ed8dfc4737c006bfd Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Tue, 6 Feb 2024 19:00:05 +0800 Subject: [PATCH 21/28] Runtime error possible fix 1 / 2 --- code/_onclick/drag_drop.dm | 2 +- code/_onclick/hud/map_popups.dm | 2 +- code/modules/spacepods/spacepods.dm | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm index 90af86729836..b0b032fc6b35 100644 --- a/code/_onclick/drag_drop.dm +++ b/code/_onclick/drag_drop.dm @@ -49,7 +49,7 @@ to inform the game this action was expected and its fine /atom/proc/MouseDrop_T(atom/dropping, mob/user, params) // return TRUE if you want to prevent us click the object after it return -/client/MouseMove(object,location,control,params) +/client/MouseMove(object, location, control, params) mouseParams = params mouse_location_ref = location mouse_object_ref = object diff --git a/code/_onclick/hud/map_popups.dm b/code/_onclick/hud/map_popups.dm index 9c2bc9b148ce..1d56e2dd1b88 100644 --- a/code/_onclick/hud/map_popups.dm +++ b/code/_onclick/hud/map_popups.dm @@ -7,7 +7,7 @@ */ var/list/screen_maps = list() - var/mouseParams = "" + var/mouseParams = null ///Used in MouseDrag to preserve the last mouse-entered location var/datum/mouse_location_ref = null ///Used in MouseDrag to preserve the last mouse-entered object diff --git a/code/modules/spacepods/spacepods.dm b/code/modules/spacepods/spacepods.dm index aa80881f8e51..59bbc9bd195b 100644 --- a/code/modules/spacepods/spacepods.dm +++ b/code/modules/spacepods/spacepods.dm @@ -542,13 +542,13 @@ GLOBAL_LIST_INIT(spacepods_list, list()) ////// Movement procs ////// ////////////////////////////// -/obj/spacepod/onMouseMove(object,location,control,params) - if(!pilot || !pilot.client || pilot.incapacitated()) +/obj/spacepod/onMouseMove(object, location, control, params) + if(!pilot || !pilot.client || pilot.incapacitated() || params == null) return // I don't know what's going on. - var/list/params_list = params2list(params) - var/sl_list = splittext(params_list["screen-loc"],",") - var/sl_x_list = splittext(sl_list[1], ":") - var/sl_y_list = splittext(sl_list[2], ":") + var/list/params_list = params2list(params) // icon-x, icon-y, screen-loc + var/sl_list = splittext(params_list["screen-loc"],",") // get only screen-loc + var/sl_x_list = splittext(sl_list[1], ":") // sl-x[1] = tile, sl-x[2] = pixel on tile + var/sl_y_list = splittext(sl_list[2], ":") // sl-y[1] = tile, sl-y[2] = pixel on tile var/view_list = isnum(pilot.client.view) ? list("[pilot.client.view*2+1]","[pilot.client.view*2+1]") : splittext(pilot.client.view, "x") var/dx = text2num(sl_x_list[1]) + (text2num(sl_x_list[2]) / world.icon_size) - 1 - text2num(view_list[1]) / 2 var/dy = text2num(sl_y_list[1]) + (text2num(sl_y_list[2]) / world.icon_size) - 1 - text2num(view_list[2]) / 2 From e95a4c3354a14a5e7bc0cd7b14f62d60a650ce4d Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Tue, 6 Feb 2024 19:13:16 +0800 Subject: [PATCH 22/28] Make em slower --- code/modules/spacepods/spacepods.dm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/modules/spacepods/spacepods.dm b/code/modules/spacepods/spacepods.dm index 59bbc9bd195b..fbc368784492 100644 --- a/code/modules/spacepods/spacepods.dm +++ b/code/modules/spacepods/spacepods.dm @@ -70,8 +70,9 @@ GLOBAL_LIST_INIT(spacepods_list, list()) var/brakes = TRUE var/user_thrust_dir = 0 - var/forward_maxthrust = 6 - var/backward_maxthrust = 3 + // Spacepod speed + var/forward_maxthrust = 2 + var/backward_maxthrust = 1 var/side_maxthrust = 1 var/lights = 0 From 9be891afb7ab821cb1812750db1a4159efeb8962 Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Tue, 6 Feb 2024 20:01:12 +0800 Subject: [PATCH 23/28] Mass comment update --- code/datums/components/rotation.dm | 3 ++- code/modules/spacepods/spacepod_construction.dm | 2 +- code/modules/spacepods/spacepod_parts.dm | 1 - code/modules/spacepods/spacepod_physics.dm | 2 +- code/modules/spacepods/spacepod_prebuilt.dm | 2 +- code/modules/spacepods/spacepods.dm | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/code/datums/components/rotation.dm b/code/datums/components/rotation.dm index fc023da258cb..162791eda3a5 100644 --- a/code/datums/components/rotation.dm +++ b/code/datums/components/rotation.dm @@ -129,7 +129,8 @@ after_rotation.Invoke(user,rotation_type) /datum/component/simple_rotation/proc/default_can_user_rotate(mob/living/user, rotation_type) - //RMNZ: Check if be_close needed or not + //RMNZ: Check if be_close needed or not (NO_DEXTERY isn't used in this build it seems) + // if(!istype(user) || !user.canUseTopic(parent, BE_CLOSE, NO_DEXTERY)) if(!istype(user) || !user.can_use(parent)) return FALSE return TRUE diff --git a/code/modules/spacepods/spacepod_construction.dm b/code/modules/spacepods/spacepod_construction.dm index b8db43e49bd5..349cf37d43f0 100644 --- a/code/modules/spacepods/spacepod_construction.dm +++ b/code/modules/spacepods/spacepod_construction.dm @@ -140,7 +140,7 @@ . = TRUE W.play_tool_sound(src) construction_state-- - // RMNZ: Test this thing out + // RMNZ: Test this. Should be five metal sheets to construct var/obj/item/stack/sheet/metal/M = new M.amount = 5 M.forceMove(loc) diff --git a/code/modules/spacepods/spacepod_parts.dm b/code/modules/spacepods/spacepod_parts.dm index 32e098aa1aef..2e98272c29de 100644 --- a/code/modules/spacepods/spacepod_parts.dm +++ b/code/modules/spacepods/spacepod_parts.dm @@ -30,7 +30,6 @@ this 4-part loop, starting from any part of the frame, can determine if all the parts are properly in place and aligned it also checks that each part is unique, and that all the parts are there for the spacepod itself */ - //RMNZ: Addition of new pods var/neededparts = list(/obj/item/pod_parts/pod_frame/aft_port, /obj/item/pod_parts/pod_frame/aft_starboard, /obj/item/pod_parts/pod_frame/fore_port, /obj/item/pod_parts/pod_frame/fore_starboard) var/turf/T var/obj/item/pod_parts/pod_frame/linked diff --git a/code/modules/spacepods/spacepod_physics.dm b/code/modules/spacepods/spacepod_physics.dm index 0330050dd381..46b4368ed831 100644 --- a/code/modules/spacepods/spacepod_physics.dm +++ b/code/modules/spacepods/spacepod_physics.dm @@ -255,7 +255,7 @@ M.apply_damage(bump_velocity * 2) take_damage(bump_velocity, BRUTE, MELEE, FALSE) playsound(M.loc, "swing_hit", 1000, 1, -1) - M.KnockOut() + M.KnockOut() // RMNZ: Knockout WAY too long M.visible_message("The force of the impact knocks [M] down!", "The force of the impact knocks you down!") add_attack_logs(pilot, M, "impacted", src, "with velocity of [bump_velocity]") return ..() diff --git a/code/modules/spacepods/spacepod_prebuilt.dm b/code/modules/spacepods/spacepod_prebuilt.dm index 8e592c1a3311..74aa3fab6644 100644 --- a/code/modules/spacepods/spacepod_prebuilt.dm +++ b/code/modules/spacepods/spacepod_prebuilt.dm @@ -26,7 +26,7 @@ equipment_types = list( // /obj/item/spacepod_equipment/weaponry/disabler, //RMNZ: Weapons don't work for now! /obj/item/spacepod_equipment/lock/keyed/sec, - // /obj/item/spacepod_equipment/tracker, //RMNZ: And this too! + // /obj/item/spacepod_equipment/tracker, //RMNZ: Tracker doesn't have purpose! /obj/item/spacepod_equipment/cargo/chair) // adminbus spacepod for jousting events diff --git a/code/modules/spacepods/spacepods.dm b/code/modules/spacepods/spacepods.dm index fbc368784492..816ea22557b3 100644 --- a/code/modules/spacepods/spacepods.dm +++ b/code/modules/spacepods/spacepods.dm @@ -130,7 +130,7 @@ GLOBAL_LIST_INIT(spacepods_list, list()) if(user.stat != CONSCIOUS) return FALSE - if(locked) // RMNZ: You also check your health on this + if(locked) // RMNZ: You also show health of your mob in chat to_chat(user, "[src]'s doors are locked!") return FALSE @@ -466,7 +466,7 @@ GLOBAL_LIST_INIT(spacepods_list, list()) target_dir = SOUTH if(270) target_dir = WEST - //RMNZ: Addition of new pods 2 + //RMNZ: Count this for addition of new pods (?) var/list/frame_piece_types = list(/obj/item/pod_parts/pod_frame/aft_port, /obj/item/pod_parts/pod_frame/aft_starboard, /obj/item/pod_parts/pod_frame/fore_port, /obj/item/pod_parts/pod_frame/fore_starboard) var/obj/item/pod_parts/pod_frame/current_piece = null var/turf/CT = get_turf(src) From 2c4e8ff87f16df4624ed54be0a687508e65190cf Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Wed, 7 Feb 2024 09:05:00 +0800 Subject: [PATCH 24/28] More drag in atmos + better bump variables + comment fix --- code/modules/spacepods/spacepod_physics.dm | 44 +++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/code/modules/spacepods/spacepod_physics.dm b/code/modules/spacepods/spacepod_physics.dm index 46b4368ed831..e0b4e44fbfb7 100644 --- a/code/modules/spacepods/spacepod_physics.dm +++ b/code/modules/spacepods/spacepod_physics.dm @@ -51,7 +51,7 @@ var/datum/gas_mixture/env = T.return_air() if(env) var/pressure = env.return_pressure() - drag += velocity_mag * pressure * 0.0001 // 1 atmosphere should shave off 1% of velocity per tile + drag += velocity_mag * pressure * 0.002 // 1 atmosphere should shave off 20% of velocity per tile if(velocity_mag > 20) drag = max(drag, (velocity_mag - 20) / time) if(drag) @@ -222,42 +222,42 @@ velocity_x -= bump_impulse return ..() -/obj/spacepod/Bump(atom/A) +/obj/spacepod/Bump(atom/Atom) var/bump_velocity = 0 if(dir & (NORTH|SOUTH)) bump_velocity = abs(velocity_y) + (abs(velocity_x) / 15) else bump_velocity = abs(velocity_x) + (abs(velocity_y) / 15) - if(istype(A, /obj/machinery/door/airlock)) // try to open doors - var/obj/machinery/door/D = A - if(!D.operating) - if(D.allowed(D.requiresID() ? pilot : null)) + if(istype(Atom, /obj/machinery/door/airlock)) // try to open doors + var/obj/machinery/door/Door = Atom + if(!Door.operating) + if(Door.allowed(Door.requiresID() ? pilot : null)) spawn(0) - D.open() + Door.open() else - D.do_animate("deny") - var/atom/movable/AM = A - if(istype(AM) && !AM.anchored && bump_velocity > 1) - step(AM, dir) + Door.do_animate("deny") + var/atom/movable/MovableAtom = Atom + if(istype(MovableAtom) && !MovableAtom.anchored && bump_velocity > 1) + step(MovableAtom, dir) // if a bump is that fast then it's not a bump. It's a collision. - if(bump_velocity > 10 && !ismob(A)) + if(bump_velocity > 10 && !ismob(Atom)) var/strength = bump_velocity / 10 strength = strength * strength strength = min(strength, 5) // don't want the explosions *too* big // wew lad, might wanna slow down there - explosion(A, -1, round((strength - 1) / 2), round(strength)) - message_admins("[key_name_admin(pilot)] has impacted a spacepod into [A] with velocity [bump_velocity]") + explosion(Atom, -1, round((strength - 1) / 2), round(strength)) + message_admins("[key_name_admin(pilot)] has impacted a spacepod into [Atom] with velocity [bump_velocity]") take_damage(strength*10, BRUTE, MELEE, TRUE) - log_game("[key_name(pilot)] has impacted a spacepod into [A] with velocity [bump_velocity]") + log_game("[key_name(pilot)] has impacted a spacepod into [Atom] with velocity [bump_velocity]") visible_message("The force of the impact causes a shockwave") - else if(isliving(A) && bump_velocity > 5) - var/mob/living/M = A - M.apply_damage(bump_velocity * 2) + else if(isliving(Atom) && bump_velocity > 5) + var/mob/living/Mob = Atom + Mob.apply_damage(bump_velocity * 2) take_damage(bump_velocity, BRUTE, MELEE, FALSE) - playsound(M.loc, "swing_hit", 1000, 1, -1) - M.KnockOut() // RMNZ: Knockout WAY too long - M.visible_message("The force of the impact knocks [M] down!", "The force of the impact knocks you down!") - add_attack_logs(pilot, M, "impacted", src, "with velocity of [bump_velocity]") + playsound(Mob.loc, "swing_hit", 1000, 1, -1) + Mob.KnockOut() // RMNZ: Knockout WAY too long / Sometimes (?) + Mob.visible_message("The force of the impact knocks [Mob] down!", "The force of the impact knocks you down!") + add_attack_logs(pilot, Mob, "impacted", src, "with velocity of [bump_velocity]") return ..() /obj/spacepod/proc/fire_projectiles(proj_type, target) // if spacepods of other sizes are added override this or something From 0dae7677ee4295915cde2519a6cf97c827cdc23c Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Thu, 8 Feb 2024 02:28:13 +0800 Subject: [PATCH 25/28] You should be able to insert objects in pod at any adjacent turf --- code/_onclick/adjacent.dm | 11 +++++++++++ code/modules/spacepods/spacepod_construction.dm | 1 - code/modules/spacepods/spacepod_equipment.dm | 2 +- code/modules/spacepods/spacepods.dm | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm index b7bab7b28bf1..e3ca49d2fbc8 100644 --- a/code/_onclick/adjacent.dm +++ b/code/_onclick/adjacent.dm @@ -13,6 +13,9 @@ /atom/proc/Adjacent(atom/neighbor) // basic inheritance, unused return 0 +/atom/proc/AdjacentByNeighbor(atom/movable/neighbor) + return 0 + // Not a sane use of the function and (for now) indicative of an error elsewhere /area/Adjacent(atom/neighbor) CRASH("Call to /area/Adjacent(), unimplemented proc") @@ -71,6 +74,14 @@ if(T.Adjacent(neighbor,src)) return 1 return 0 +// RMNZ: Added different adjacent check for spacepods? +/atom/movable/AdjacentByNeighbor(atom/movable/neighbor) + if(neighbor == loc) return 1 + if(!isturf(loc)) return 0 + for(var/turf/T in neighbor.locs) + if(T.Adjacent(neighbor,src)) return 1 + return 0 + // This is necessary for storage items not on your person. /obj/item/Adjacent(atom/neighbor, recurse = 1) if(neighbor == loc) return 1 diff --git a/code/modules/spacepods/spacepod_construction.dm b/code/modules/spacepods/spacepod_construction.dm index 349cf37d43f0..b54d30e1e85c 100644 --- a/code/modules/spacepods/spacepod_construction.dm +++ b/code/modules/spacepods/spacepod_construction.dm @@ -140,7 +140,6 @@ . = TRUE W.play_tool_sound(src) construction_state-- - // RMNZ: Test this. Should be five metal sheets to construct var/obj/item/stack/sheet/metal/M = new M.amount = 5 M.forceMove(loc) diff --git a/code/modules/spacepods/spacepod_equipment.dm b/code/modules/spacepods/spacepod_equipment.dm index d1f35476329b..93047efb2c2e 100644 --- a/code/modules/spacepods/spacepod_equipment.dm +++ b/code/modules/spacepods/spacepod_equipment.dm @@ -130,7 +130,7 @@ /obj/item/spacepod_equipment/cargo/large/proc/spacepod_mousedrop(obj/spacepod/SP, obj/A, mob/user) if(user == SP.pilot || (user in SP.passengers)) return FALSE - if(istype(A, storage_type) && SP.Adjacent(A)) // For loading ore boxes + if(istype(A, storage_type) && SP.AdjacentByNeighbor(A)) // For loading ore boxes if(!storage) to_chat(user, "You begin loading [A] into [SP]'s [src]") if(do_after(user, 4 SECONDS, target = A)) diff --git a/code/modules/spacepods/spacepods.dm b/code/modules/spacepods/spacepods.dm index 816ea22557b3..77be68da97f2 100644 --- a/code/modules/spacepods/spacepods.dm +++ b/code/modules/spacepods/spacepods.dm @@ -663,7 +663,7 @@ GLOBAL_LIST_INIT(spacepods_list, list()) if(internal_tank) to_chat(user, "[src] already has an internaltank!") return - if(!A.Adjacent(src)) + if(!A.AdjacentByNeighbor(src)) to_chat(user, "The canister is not close enough!") return if(hatch_open) From 0e28b2475f65b9402c23993ea60cc50fcacb999e Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Tue, 5 Mar 2024 13:45:51 +0800 Subject: [PATCH 26/28] Adapting to avoid merge conflicts --- code/_onclick/hud/map_popups.dm | 7 ------- code/modules/spacepods/spacepod_temp_client.dm | 7 +++++++ paradise.dme | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) create mode 100644 code/modules/spacepods/spacepod_temp_client.dm diff --git a/code/_onclick/hud/map_popups.dm b/code/_onclick/hud/map_popups.dm index 1d56e2dd1b88..dc9e255cba93 100644 --- a/code/_onclick/hud/map_popups.dm +++ b/code/_onclick/hud/map_popups.dm @@ -7,13 +7,6 @@ */ var/list/screen_maps = list() - var/mouseParams = null - ///Used in MouseDrag to preserve the last mouse-entered location - var/datum/mouse_location_ref = null - ///Used in MouseDrag to preserve the last mouse-entered object - var/datum/mouse_object_ref - var/mouseControlObject = null - /obj/screen /** * Map name assigned to this object. diff --git a/code/modules/spacepods/spacepod_temp_client.dm b/code/modules/spacepods/spacepod_temp_client.dm new file mode 100644 index 000000000000..cec7f251d562 --- /dev/null +++ b/code/modules/spacepods/spacepod_temp_client.dm @@ -0,0 +1,7 @@ +/client + var/mouseParams = null + ///Used in MouseDrag to preserve the last mouse-entered location + var/datum/mouse_location_ref = null + ///Used in MouseDrag to preserve the last mouse-entered object + var/datum/mouse_object_ref + var/mouseControlObject = null diff --git a/paradise.dme b/paradise.dme index 39e2d543716e..6ab63a34cfa4 100644 --- a/paradise.dme +++ b/paradise.dme @@ -2687,6 +2687,7 @@ #include "code\modules\space_management\level_traits.dm" #include "code\modules\space_management\space_chunk.dm" #include "code\modules\space_management\space_level.dm" +#include "code\modules\spacepods\spacepod_temp_client.dm" #include "code\modules\spacepods\spacepod_equipment.dm" #include "code\modules\spacepods\spacepod_parts.dm" #include "code\modules\spacepods\spacepods.dm" From aecb79981ca89aa547fa2f544ea5575b1910f32a Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Tue, 5 Mar 2024 13:51:07 +0800 Subject: [PATCH 27/28] Removes duplicate sprite of burst taser (?) --- goon/icons/obj/spacepods/parts.dmi | Bin 5007 -> 9288 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/goon/icons/obj/spacepods/parts.dmi b/goon/icons/obj/spacepods/parts.dmi index 6375a6ebba77d0bee443ca9d276802cb2f4d63c7..d2c94f65004cbf99d39cfeb30d8337734b722336 100644 GIT binary patch literal 9288 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 H6!U)o|IY;! literal 5007 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 XjZR|H`S From 39794e3167627969f0c1074118e53de3a406ed1a Mon Sep 17 00:00:00 2001 From: MrRomainzZ Date: Fri, 8 Mar 2024 20:17:44 +0800 Subject: [PATCH 28/28] Fix status --- .../mob/living/carbon/human/human_mob.dm | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/code/modules/mob/living/carbon/human/human_mob.dm b/code/modules/mob/living/carbon/human/human_mob.dm index 72810068432d..f96f5dabc790 100644 --- a/code/modules/mob/living/carbon/human/human_mob.dm +++ b/code/modules/mob/living/carbon/human/human_mob.dm @@ -211,16 +211,16 @@ if(V) status_tab_data[++status_tab_data.len] = list("Total Blood:", "[V.bloodtotal]") status_tab_data[++status_tab_data.len] = list("Usable Blood:", "[V.bloodusable]") - if(istype(loc, /obj/spacepod)) // Spacepods! - var/obj/spacepod/S = loc - // If we want numbers instead of percents - // [S.cell ? "[round(S.cell.charge,0.1)]/[S.cell.maxcharge] KJ" : "NONE"] - status_tab_data[++status_tab_data.len] = list("Spacepod Charge:", "[S.cell ? "[round((S.cell.charge / S.cell.maxcharge) * 100, 0.1)]%" : "No cell detected"]") - // Same here - // [round((S.obj_integrity / S.max_integrity) * 100, 0.1)] - status_tab_data[++status_tab_data.len] = list("Spacepod Integrity:", "[!S.obj_integrity ? "0" : "[round(S.obj_integrity,0.1)]/[S.max_integrity]"]") - status_tab_data[++status_tab_data.len] = list("Spacepod Velocity:", "[round(sqrt(S.velocity_x*S.velocity_x+S.velocity_y*S.velocity_y), 0.1)] m/s") - + if(istype(loc, /obj/spacepod)) // Spacepods! + var/obj/spacepod/S = loc + // If we want numbers instead of percents + // [S.cell ? "[round(S.cell.charge,0.1)]/[S.cell.maxcharge] KJ" : "NONE"] + status_tab_data[++status_tab_data.len] = list("Spacepod Charge:", "[S.cell ? "[round((S.cell.charge / S.cell.maxcharge) * 100, 0.1)]" : "No cell detected"]") + // Same here + // [round((S.obj_integrity / S.max_integrity) * 100, 0.1)] + status_tab_data[++status_tab_data.len] = list("Spacepod Integrity:", "[!S.obj_integrity ? "0" : "[round(S.obj_integrity, 0.1)]/[S.max_integrity]"]") + status_tab_data[++status_tab_data.len] = list("Spacepod Velocity:", "[round(sqrt(S.velocity_x*S.velocity_x+S.velocity_y*S.velocity_y), 0.1)] m/s") + /mob/living/carbon/human/ex_act(severity) if(status_flags & GODMODE) return FALSE