diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 600fc8eb2669..1fcc2a4744e5 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -210,6 +210,8 @@ GLOBAL_LIST_INIT(heavyfootmob, typecacheof(list( #define ismecha(A) (istype(A, /obj/mecha)) +#define isspacepod(A) (istype(A, /obj/spacepod)) // yogs + #define is_cleanable(A) (istype(A, /obj/effect/decal/cleanable) || istype(A, /obj/effect/rune)) //if something is cleanable #define isorgan(A) (istype(A, /obj/item/organ)) @@ -247,4 +249,4 @@ GLOBAL_LIST_INIT(glass_sheet_types, typecacheof(list( #define isblobmonster(O) (istype(O, /mob/living/simple_animal/hostile/blob)) -#define isshuttleturf(T) (length(T.baseturfs) && (/turf/baseturf_skipover/shuttle in T.baseturfs)) \ No newline at end of file +#define isshuttleturf(T) (length(T.baseturfs) && (/turf/baseturf_skipover/shuttle in T.baseturfs)) diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index 08ffee272c0f..510eccca1cf6 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -55,6 +55,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 WALL_OBJ_LAYER 4.25 diff --git a/code/__DEFINES/~yogs_defines/spacepods.dm b/code/__DEFINES/~yogs_defines/spacepods.dm new file mode 100644 index 000000000000..a4bfbd5abf88 --- /dev/null +++ b/code/__DEFINES/~yogs_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/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm index a06e03324685..bd746261c182 100644 --- a/code/_globalvars/lists/maintenance_loot.dm +++ b/code/_globalvars/lists/maintenance_loot.dm @@ -106,5 +106,10 @@ GLOBAL_LIST_INIT(maintenance_loot, list( /obj/item/storage/toolbox/artistic = 2, /obj/item/toy/eightball = 1, /obj/item/reagent_containers/pill/floorpill = 1, + // yogs start + /obj/item/pod_parts/core = 1, + /obj/item/pod_parts/armor = 1, + /obj/item/circuitboard/mecha/pod = 1, + // yogs end "" = 3 )) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 8fae785ca3ed..cfb674550fc2 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -209,11 +209,28 @@ direct = get_dir(src, newloc) setDir(direct) - if(!loc.Exit(src, newloc)) - return + // yogs start - multi tile object handling + if(bound_width != world.icon_size || bound_height != world.icon_size) + var/list/newlocs = isturf(newloc) ? block(locate(newloc.x+(-bound_x)/world.icon_size,newloc.y+(-bound_y)/world.icon_size,newloc.z),locate(newloc.x+(-bound_x+bound_width)/world.icon_size-1,newloc.y+(-bound_y+bound_height)/world.icon_size-1,newloc.z)) : list(newloc) + if(!newlocs) + return // we're trying to cross into the edge of space + var/bothturfs = isturf(newloc) && isturf(loc) + var/dx = bothturfs ? newloc.x - loc.x : 0 + var/dy = bothturfs ? newloc.y - loc.y : 0 + var/dz = bothturfs ? newloc.z - loc.z : 0 + for(var/atom/A in (locs - newlocs)) + if(!A.Exit(src, bothturfs ? locate(A.x+dx,A.y+dy,A.z+dz) : newloc)) + return + for(var/atom/A in (newlocs - locs)) + if(!A.Enter(src, bothturfs ? locate(A.x-dx,A.y-dy,A.z+dz) : loc)) + return + else + if(!loc.Exit(src, newloc)) + return - if(!newloc.Enter(src, src.loc)) - return + if(!newloc.Enter(src, src.loc)) + return + // yogs end // Past this is the point of no return var/atom/oldloc = loc diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm index 2a54764024d6..4f3121801709 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/rods.dm @@ -2,6 +2,13 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \ new/datum/stack_recipe("grille", /obj/structure/grille, 2, time = 10, one_per_turf = TRUE, on_floor = FALSE), \ new/datum/stack_recipe("table frame", /obj/structure/table_frame, 2, time = 10, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("scooter frame", /obj/item/scooter_frame, 10, time = 25, one_per_turf = 0), \ + // yogs start + null, \ + new/datum/stack_recipe("fore port spacepod frame", /obj/item/pod_parts/pod_frame/fore_port, 15, time = 30, one_per_turf = 0), \ + new/datum/stack_recipe("fore starboard spacepod frame", /obj/item/pod_parts/pod_frame/fore_starboard, 15, time = 30, one_per_turf = 0), \ + new/datum/stack_recipe("aft port spacepod frame", /obj/item/pod_parts/pod_frame/aft_port, 15, time = 30, one_per_turf = 0), \ + new/datum/stack_recipe("aft starboard spacepod frame", /obj/item/pod_parts/pod_frame/aft_starboard, 15, time = 30, one_per_turf = 0), \ + // yogs end )) /obj/item/stack/rods diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index f2c9a6ef96ea..4925aa660d7e 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -100,7 +100,7 @@ if(!target || !isturf(target.loc) || !isturf(loc) || stat == DEAD) return var/target_dir = get_dir(src,target) - + var/static/list/cardinal_sidestep_directions = list(-90,-45,0,45,90) var/static/list/diagonal_sidestep_directions = list(-45,0,45) var/chosen_dir = 0 @@ -131,7 +131,7 @@ if(!search_objects) . = hearers(vision_range, targets_from) - src //Remove self, so we don't suicide - var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha, /obj/structure/destructible/clockwork/ocular_warden)) + var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha, /obj/structure/destructible/clockwork/ocular_warden, /obj/spacepod)) // yogs - add spacepod for(var/HM in typecache_filter_list(range(vision_range, targets_from), hostile_machines)) if(can_see(targets_from, HM, vision_range)) @@ -296,7 +296,7 @@ if(target) if(targets_from && isturf(targets_from.loc) && target.Adjacent(targets_from)) //If they're next to us, attack MeleeAction() - else + else if(rapid_melee > 1 && target_distance <= melee_queue_distance) MeleeAction(FALSE) in_melee = FALSE //If we're just preparing to strike do not enter sidestep mode @@ -563,7 +563,7 @@ mob/living/simple_animal/hostile/proc/DestroySurroundings() // for use with mega toggle_ai(AI_ON) /mob/living/simple_animal/hostile/proc/ListTargetsLazy(var/_Z)//Step 1, find out what we can see - var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha, /obj/structure/destructible/clockwork/ocular_warden)) + var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha, /obj/structure/destructible/clockwork/ocular_warden, /obj/spacepod)) // yogs - add spacepod . = list() for (var/I in SSmobs.clients_by_zlevel[_Z]) var/mob/M = I diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm index 57df489d4ef3..2e8b1fa4179b 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm @@ -12,6 +12,12 @@ var/obj/mecha/M = A if(M.occupant) return A + // yogs start + else if(istype(A, /obj/spacepod)) + var/obj/spacepod/M = A + if(M.pilot || M.passengers.len) + return A + // yogs end /mob/living/simple_animal/hostile/retaliate/ListTargets() if(!enemies.len) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 151aad5cb5ee..84ec44985f79 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -342,6 +342,12 @@ var/obj/mecha/M = the_target if (M.occupant) return FALSE + // yogs start + if(isspacepod(the_target)) + var/obj/spacepod/SP = the_target + if(SP.pilot || SP.passengers.len) + return FALSE + // yogs end return TRUE /mob/living/simple_animal/handle_fire() diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 9e14864c21a5..ec100babd082 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -247,9 +247,16 @@ return TRUE if(firer && !ignore_source_check) var/mob/checking = firer - if((A == firer) || (((A in firer.buckled_mobs) || (istype(checking) && (A == checking.buckled))) && (A != original)) || (A == firer.loc && ismecha(A))) //cannot shoot yourself or your mech + if((A == firer) || (((A in firer.buckled_mobs) || (istype(checking) && (A == checking.buckled))) && (A != original)) || (A == firer.loc && (ismecha(A) || isspacepod(A)))) //cannot shoot yourself or your mech // yogs - or your spacepod trajectory_ignore_forcemove = TRUE - forceMove(get_turf(A)) + // yogs start - multitile objects + var/turf/T = trajectory.return_turf() + if(!istype(T)) + qdel(src) + return + if(T != loc) + forceMove(get_step_towards(src, T)) + // yogs end trajectory_ignore_forcemove = FALSE return FALSE diff --git a/code/modules/research/machinery/protolathe.dm b/code/modules/research/machinery/protolathe.dm index e04261c961dd..ee9a1960fa5d 100644 --- a/code/modules/research/machinery/protolathe.dm +++ b/code/modules/research/machinery/protolathe.dm @@ -15,7 +15,8 @@ "Weapons", "Ammo", "Firing Pins", - "Computer Parts" + "Computer Parts", + "Spacepod Designs" // yogs ) production_animation = "protolathe_n" allowed_buildtypes = PROTOLATHE diff --git a/code/modules/research/machinery/techfab.dm b/code/modules/research/machinery/techfab.dm index 5525066f2ab6..447ab66fed65 100644 --- a/code/modules/research/machinery/techfab.dm +++ b/code/modules/research/machinery/techfab.dm @@ -26,7 +26,8 @@ "Subspace Telecomms", "Research Machinery", "Misc. Machinery", - "Computer Parts" + "Computer Parts", + "Spacepod Designs" // yogs ) console_link = FALSE production_animation = "protolathe_n" diff --git a/yogstation.dme b/yogstation.dme index 3398fed23c79..a2a5d6407485 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -118,6 +118,7 @@ #include "code\__DEFINES\~yogs_defines\mentor.dm" #include "code\__DEFINES\~yogs_defines\preferences.dm" #include "code\__DEFINES\~yogs_defines\shuttles.dm" +#include "code\__DEFINES\~yogs_defines\spacepods.dm" #include "code\__DEFINES\~yogs_defines\wires.dm" #include "code\__HELPERS\_lists.dm" #include "code\__HELPERS\_logging.dm" @@ -2750,6 +2751,7 @@ #include "yogstation\code\_globalvars\configuration.dm" #include "yogstation\code\_globalvars\logging.dm" #include "yogstation\code\_globalvars\lists\mobs.dm" +#include "yogstation\code\_onclick\adjacent.dm" #include "yogstation\code\_onclick\click.dm" #include "yogstation\code\_onclick\hud\vampire.dm" #include "yogstation\code\controllers\configuration\entries\general.dm" @@ -2803,6 +2805,8 @@ #include "yogstation\code\game\machinery\computer\medical.dm" #include "yogstation\code\game\machinery\computer\Operating.dm" #include "yogstation\code\game\machinery\doors\airlock.dm" +#include "yogstation\code\game\machinery\doors\poddoor.dm" +#include "yogstation\code\game\machinery\doors\spacepod.dm" #include "yogstation\code\game\machinery\pipe\construction.dm" #include "yogstation\code\game\machinery\telecomms\computers\logbrowser.dm" #include "yogstation\code\game\machinery\telecomms\computers\telemonitor.dm" @@ -2985,9 +2989,17 @@ #include "yogstation\code\modules\research\rdconsole.dm" #include "yogstation\code\modules\research\designs\bluespace_designs.dm" #include "yogstation\code\modules\research\designs\comp_board_designs.dm" +#include "yogstation\code\modules\research\designs\spacepod_designs.dm" #include "yogstation\code\modules\research\designs\stock_parts_designs.dm" #include "yogstation\code\modules\research\designs\tool_designs.dm" +#include "yogstation\code\modules\research\techweb\all_nodes.dm" #include "yogstation\code\modules\shuttle\emergency.dm" +#include "yogstation\code\modules\spacepods\construction.dm" +#include "yogstation\code\modules\spacepods\equipment.dm" +#include "yogstation\code\modules\spacepods\parts.dm" +#include "yogstation\code\modules\spacepods\physics.dm" +#include "yogstation\code\modules\spacepods\prebuilt.dm" +#include "yogstation\code\modules\spacepods\spacepod.dm" #include "yogstation\code\modules\spells\cluwnecurse.dm" #include "yogstation\code\modules\spells\spells.dm" #include "yogstation\code\modules\spells\spell_types\mime.dm" diff --git a/yogstation/code/_onclick/adjacent.dm b/yogstation/code/_onclick/adjacent.dm new file mode 100644 index 000000000000..3664701f94f1 --- /dev/null +++ b/yogstation/code/_onclick/adjacent.dm @@ -0,0 +1,70 @@ +/* + Adjacency (to turf): + * If you are in the same turf, always true + * If you are vertically/horizontally adjacent, ensure there are no border objects + * If you are diagonally adjacent, ensure you can pass through at least one of the mutually adjacent square. + * Passing through in this case ignores anything with the LETPASSTHROW pass flag, such as tables, racks, and morgue trays. +*/ +/turf/Adjacent(atom/neighbor, atom/target = null, atom/movable/mover = null) + if(neighbor == src) + return TRUE //don't be retarded!! + + if(istype(neighbor, /atom/movable)) //fml + var/atom/movable/AM = neighbor + if((AM.bound_width != world.icon_size || AM.bound_height != world.icon_size) && (islist(AM.locs) && AM.locs.len > 1)) + for(var/turf/T in AM.locs) + if(Adjacent(T, target, mover)) + return TRUE + return FALSE + + var/turf/T0 = get_turf(neighbor) + + if(T0 == src) //same turf + return TRUE + + if(get_dist(src, T0) > 1 || z != T0.z) //too far + return FALSE + + // Non diagonal case + if(T0.x == x || T0.y == y) + // Check for border blockages + return T0.ClickCross(get_dir(T0,src), border_only = 1, target_atom = target, mover = mover) && src.ClickCross(get_dir(src,T0), border_only = 1, target_atom = target, mover = mover) + + // Diagonal case + var/in_dir = get_dir(T0,src) // eg. northwest (1+8) = 9 (00001001) + var/d1 = in_dir&3 // eg. north (1+8)&3 (0000 0011) = 1 (0000 0001) + var/d2 = in_dir&12 // eg. west (1+8)&12 (0000 1100) = 8 (0000 1000) + + for(var/d in list(d1,d2)) + if(!T0.ClickCross(d, border_only = 1, target_atom = target, mover = mover)) + continue // could not leave T0 in that direction + + var/turf/T1 = get_step(T0,d) + if(!T1 || T1.density) + continue + if(!T1.ClickCross(get_dir(T1,src), border_only = 0, target_atom = target, mover = mover) || !T1.ClickCross(get_dir(T1,T0), border_only = 0, target_atom = target, mover = mover)) + continue // couldn't enter or couldn't leave T1 + + if(!src.ClickCross(get_dir(src,T1), border_only = 1, target_atom = target, mover = mover)) + continue // could not enter src + + return TRUE // we don't care about our own density + + return FALSE + +/* + Adjacency (to anything else): + * Must be on a turf +*/ +/atom/movable/Adjacent(var/atom/neighbor) + if(neighbor == loc) + return TRUE + if(!isturf(loc)) + return FALSE + if((islist(locs) && locs.len > 1) && (bound_width != world.icon_size || bound_height != world.icon_size)) + for(var/turf/T in locs) //this is to handle multi tile objects + if(T.Adjacent(neighbor, src, src)) + return TRUE + else if(loc.Adjacent(neighbor,target = neighbor, mover = src)) + return TRUE + return FALSE diff --git a/yogstation/code/game/machinery/doors/poddoor.dm b/yogstation/code/game/machinery/doors/poddoor.dm new file mode 100644 index 000000000000..323356b1f7ad --- /dev/null +++ b/yogstation/code/game/machinery/doors/poddoor.dm @@ -0,0 +1,60 @@ +/obj/machinery/door/poddoor/multi_tile + name = "large pod door" + layer = CLOSED_DOOR_LAYER + closingLayer = CLOSED_DOOR_LAYER + +/obj/machinery/door/poddoor/multi_tile/New() + . = ..() + apply_opacity_to_my_turfs(opacity) + +/obj/machinery/door/poddoor/multi_tile/open() + if(..()) + apply_opacity_to_my_turfs(opacity) + + +/obj/machinery/door/poddoor/multi_tile/close() + if(..()) + apply_opacity_to_my_turfs(opacity) + +/obj/machinery/door/poddoor/multi_tile/Destroy() + apply_opacity_to_my_turfs(0) + return ..() + +//Multi-tile poddoors don't turn invisible automatically, so we change the opacity of the turfs below instead one by one. +/obj/machinery/door/poddoor/multi_tile/proc/apply_opacity_to_my_turfs(var/new_opacity) + for(var/turf/T in locs) + T.opacity = new_opacity + T.has_opaque_atom = new_opacity + T.reconsider_lights() + T.air_update_turf(1) + update_freelook_sight() + +/obj/machinery/door/poddoor/multi_tile/four_tile_ver/ + icon = 'yogstation/icons/obj/doors/1x4blast_vert.dmi' + bound_height = 128 + dir = NORTH + +/obj/machinery/door/poddoor/multi_tile/three_tile_ver/ + icon = 'yogstation/icons/obj/doors/1x3blast_vert.dmi' + bound_height = 96 + dir = NORTH + +/obj/machinery/door/poddoor/multi_tile/two_tile_ver/ + icon = 'yogstation/icons/obj/doors/1x2blast_vert.dmi' + bound_height = 64 + dir = NORTH + +/obj/machinery/door/poddoor/multi_tile/four_tile_hor/ + icon = 'yogstation/icons/obj/doors/1x4blast_hor.dmi' + bound_width = 128 + dir = EAST + +/obj/machinery/door/poddoor/multi_tile/three_tile_hor/ + icon = 'yogstation/icons/obj/doors/1x3blast_hor.dmi' + bound_width = 96 + dir = EAST + +/obj/machinery/door/poddoor/multi_tile/two_tile_hor/ + icon = 'yogstation/icons/obj/doors/1x2blast_hor.dmi' + bound_width = 64 + dir = EAST diff --git a/yogstation/code/game/machinery/doors/spacepod.dm b/yogstation/code/game/machinery/doors/spacepod.dm new file mode 100644 index 000000000000..7b9c689ae38c --- /dev/null +++ b/yogstation/code/game/machinery/doors/spacepod.dm @@ -0,0 +1,22 @@ +/obj/structure/spacepoddoor + name = "podlock" + desc = "Why it no open!!!" + icon = 'yogstation/icons/effects/beam.dmi' + icon_state = "n_beam" + density = 1 + anchored = 1 + var/id = 1.0 + CanAtmosPass = ATMOS_PASS_NO + +/obj/structure/spacepoddoor/Initialize() + ..() + air_update_turf(1) + +/obj/structure/spacepoddoor/Destroy() + air_update_turf(1) + return ..() + +/obj/structure/spacepoddoor/CanPass(atom/movable/A, turf/T) + if(istype(A, /obj/spacepod)) + return TRUE + return ..() diff --git a/yogstation/code/modules/research/designs/spacepod_designs.dm b/yogstation/code/modules/research/designs/spacepod_designs.dm new file mode 100644 index 000000000000..c831f143912a --- /dev/null +++ b/yogstation/code/modules/research/designs/spacepod_designs.dm @@ -0,0 +1,237 @@ +/datum/design/board/spacepod_main + name = "Circuit Design (Space Pod Mainboard)" + desc = "Allows for the construction of a Space Pod mainboard." + id = "spacepod_main" + build_path = /obj/item/circuitboard/mecha/pod + category = list("Exosuit Modules") + departmental_flags = DEPARTMENTAL_FLAG_ALL + +/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" + 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") + departmental_flags = DEPARTMENTAL_FLAG_ALL + +/datum/design/pod_armor_civ + name = "Spacepod Armor (civilian)" + desc = "Allows for the construction of spcaepod armor. This is the civilian version." + id = "podarmor_civ" + 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") + departmental_flags = DEPARTMENTAL_FLAG_ALL + +/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" + build_type = PROTOLATHE + build_path = /obj/item/pod_parts/armor/black + category = list("Spacepod Designs") + materials = list(MAT_METAL=15000,MAT_GLASS=5000,MAT_PLASMA=10000) + departmental_flags = DEPARTMENTAL_FLAG_ALL + +/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" + build_type = PROTOLATHE + build_path = /obj/item/pod_parts/armor/industrial + category = list("Spacepod Designs") + materials = list(MAT_METAL=15000,MAT_GLASS=5000,MAT_PLASMA=10000,MAT_DIAMOND=5000,MAT_SILVER=7500) + departmental_flags = DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_ENGINEERING + +/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" + build_type = PROTOLATHE + build_path = /obj/item/pod_parts/armor/security + category = list("Spacepod Designs") + materials = list(MAT_METAL=15000,MAT_GLASS=5000,MAT_PLASMA=10000,MAT_DIAMOND=5000,MAT_SILVER=7500) + departmental_flags = DEPARTMENTAL_FLAG_SECURITY + +/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" + build_type = PROTOLATHE + build_path = /obj/item/pod_parts/armor/gold + category = list("Spacepod Designs") + materials = list(MAT_METAL=5000,MAT_GLASS=2500,MAT_PLASMA=7500,MAT_GOLD=10000) + departmental_flags = DEPARTMENTAL_FLAG_ALL + +////////////////////////////////////////// +//////SPACEPOD GUNS/////////////////////// +////////////////////////////////////////// + +/datum/design/pod_gun_disabler + name = "Spacepod Equipment (Disabler)" + desc = "Allows for the construction of a spacepod mounted disabler." + id = "podgun_disabler" + build_type = PROTOLATHE + build_path = /obj/item/spacepod_equipment/weaponry/disabler + category = list("Spacepod Designs") + materials = list(MAT_METAL = 15000) + departmental_flags = DEPARTMENTAL_FLAG_SECURITY + +/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" + build_type = PROTOLATHE + build_path = /obj/item/spacepod_equipment/weaponry/burst_disabler + category = list("Spacepod Designs") + materials = list(MAT_METAL = 15000,MAT_PLASMA=2000) + departmental_flags = DEPARTMENTAL_FLAG_SECURITY + +/datum/design/pod_gun_laser + name = "Spacepod Equipment (Laser)" + desc = "Allows for the construction of a spacepod mounted laser." + id = "podgun_laser" + build_type = PROTOLATHE + build_path = /obj/item/spacepod_equipment/weaponry/laser + category = list("Spacepod Designs") + materials = list(MAT_METAL=10000,MAT_GLASS=5000,MAT_GOLD=1000,MAT_SILVER=2000) + departmental_flags = DEPARTMENTAL_FLAG_SECURITY + +/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" + 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") + departmental_flags = DEPARTMENTAL_FLAG_CARGO + +/datum/design/pod_ka + name = "Spacepod Equipment (Kinetic Accelerator)" + desc = "Allows for the construction of a spacepod Kinetic Accelerator." + id = "pod_ka" + 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") + departmental_flags = DEPARTMENTAL_FLAG_CARGO + + +/datum/design/pod_plasma_cutter + name = "Spacepod Equipment (Plasma Cutter)" + desc = "Allows for the construction of a plasma cutter." + id = "pod_plasma_cutter" + 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") + departmental_flags = DEPARTMENTAL_FLAG_CARGO + +/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" + 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") + departmental_flags = DEPARTMENTAL_FLAG_CARGO + +////////////////////////////////////////// +//////SPACEPOD MISC. ITEMS//////////////// +////////////////////////////////////////// + +/datum/design/pod_misc_tracker + name = "Spacepod Tracking Module" + desc = "Allows for the construction of a Space Pod Tracking Module." + id = "podmisc_tracker" + build_type = PROTOLATHE + materials = list(MAT_METAL=5000) + build_path = /obj/item/spacepod_equipment/tracker + category = list("Spacepod Designs") + departmental_flags = DEPARTMENTAL_FLAG_ALL + +////////////////////////////////////////// +//////SPACEPOD CARGO ITEMS//////////////// +////////////////////////////////////////// + +/datum/design/pod_cargo_ore + name = "Spacepod Ore Storage Module" + desc = "Allows for the construction of a Space Pod Ore Storage Module." + id = "podcargo_ore" + build_type = PROTOLATHE + materials = list(MAT_METAL=20000, MAT_GLASS=2000) + build_path = /obj/item/spacepod_equipment/cargo/large/ore + category = list("Spacepod Designs") + departmental_flags = DEPARTMENTAL_FLAG_CARGO + +/datum/design/pod_cargo_crate + name = "Spacepod Crate Storage Module" + desc = "Allows the construction of a Space Pod Crate Storage Module." + id = "podcargo_crate" + build_type = PROTOLATHE + materials = list(MAT_METAL=25000) + build_path = /obj/item/spacepod_equipment/cargo/large + category = list("Spacepod Designs") + departmental_flags = DEPARTMENTAL_FLAG_ALL + +////////////////////////////////////////// +//////SPACEPOD SEC CARGO ITEMS//////////// +////////////////////////////////////////// + +/datum/design/passenger_seat + name = "Spacepod Passenger Seat" + desc = "Allows the construction of a Space Pod Passenger Seat Module." + id = "podcargo_seat" + build_type = PROTOLATHE + materials = list(MAT_METAL=7500, MAT_GLASS=2500) + build_path = /obj/item/spacepod_equipment/cargo/chair + category = list("Spacepod Designs") + departmental_flags = DEPARTMENTAL_FLAG_ALL + +/*/datum/design/loot_box + name = "Spacepod Loot Storage Module" + desc = "Allows the construction of a Space Pod Auxillary Cargo Module." + id = "podcargo_lootbox" + build_type = PROTOLATHE + materials = list(MAT_METAL=7500, MAT_GLASS=2500) + build_path = /obj/item/spacepod_equipment/cargo/loot_box + category = list("Spacepod Designs") + departmental_flags = DEPARTMENTAL_FLAG_ALL*/ + +////////////////////////////////////////// +//////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" + build_type = PROTOLATHE + materials = list(MAT_METAL=4500) + build_path = /obj/item/spacepod_equipment/lock/keyed + category = list("Spacepod Designs") + departmental_flags = DEPARTMENTAL_FLAG_ALL + +/datum/design/pod_key + name = "Spacepod Tumbler Lock Key" + desc = "Allows for the construction of a blank key for a podlock." + id = "podkey" + build_type = PROTOLATHE + materials = list(MAT_METAL=500) + build_path = /obj/item/spacepod_key + category = list("Spacepod Designs") + departmental_flags = DEPARTMENTAL_FLAG_ALL + +/datum/design/lockbuster + name = "Spacepod Lock Buster" + desc = "Allows for the construction of a spacepod lockbuster." + id = "pod_lockbuster" + build_type = PROTOLATHE + build_path = /obj/item/device/lock_buster + category = list("Spacepod Designs") + materials = list(MAT_METAL = 15000, MAT_DIAMOND=2500) //it IS a drill! + departmental_flags = DEPARTMENTAL_FLAG_SECURITY diff --git a/yogstation/code/modules/research/techweb/all_nodes.dm b/yogstation/code/modules/research/techweb/all_nodes.dm new file mode 100644 index 000000000000..92ce59bb8052 --- /dev/null +++ b/yogstation/code/modules/research/techweb/all_nodes.dm @@ -0,0 +1,89 @@ +/datum/techweb_node/spacepod_basic + id = "spacepod_basic" + display_name = "Spacepod Construction" + description = "Basic stuff to construct Spacepods. Don't crash your first spacepod into the station, especially while going more than 10 m/s." + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) + export_price = 2500 + prereq_ids = list("base") + design_ids = list("podcore", "podarmor_civ", "podarmor_dark", "spacepod_main") + +/datum/techweb_node/spacepod_disabler + id = "spacepod_disabler" + display_name = "Spacepod Weaponry" + description = "For a bit of pew pew space battles" + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500) + export_price = 3500 + prereq_ids = list("spacepod_basic", "weaponry") + design_ids = list("podgun_disabler") + +/datum/techweb_node/spacepod_lasers + id = "spacepod_lasers" + display_name = "Advanced Spacepod Weaponry" + description = "For a lot of pew pew space battles. PEW PEW PEW!! Shit, I missed. I need better aim. Whatever." + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5250) + export_price = 5250 + prereq_ids = list("spacepod_disabler", "electronic_weapons") + design_ids = list("podgun_laser", "podgun_bdisabler") + +/datum/techweb_node/spacepod_ka + id = "spacepod_ka" + display_name = "Spacepod Mining Tech" + description = "Cutting up asteroids using your spacepods" + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500) + export_price = 500 + prereq_ids = list("basic_mining", "spacepod_disabler") + design_ids = list("pod_ka_basic") + +/datum/techweb_node/spacepod_advmining + id = "spacepod_aka" + display_name = "Advanced Spacepod Mining Tech" + description = "Cutting up asteroids using your spacepods.... faster!" + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500) + export_price = 3500 + prereq_ids = list("spacepod_ka", "adv_mining") + design_ids = list("pod_ka", "pod_plasma_cutter") + +/datum/techweb_node/spacepod_advplasmacutter + id = "spacepod_apc" + display_name = "Advanced Spacepod Plasma Cutter" + description = "Cutting up asteroids using your spacepods........... FASTERRRRRR!!!!!! Oh shit, that was gibtonite." + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 4500) + export_price = 4500 + prereq_ids = list("spacepod_aka", "adv_plasma") + design_ids = list("pod_adv_plasma_cutter") + +/datum/techweb_node/spacepod_pseat + id = "spacepod_pseat" + display_name = "Spacepod Passenger Seat" + description = "For bringing along victims as you fly off into the far reaches of space" + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3750) + export_price = 3750 + prereq_ids = list("spacepod_basic", "adv_engi") + design_ids = list("podcargo_seat") + +/datum/techweb_node/spacepod_storage + id = "spacepod_storage" + display_name = "Spacepod Storage" + description = "For storing the stuff you find in the far reaches of space" + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 4500) + export_price = 4500 + prereq_ids = list("spacepod_pseat", "high_efficiency") + design_ids = list("podcargo_lootbox", "podcargo_crate", "podcargo_ore") + +/datum/techweb_node/spacepod_lockbuster + id = "spacepod_lockbuster" + display_name = "Spacepod Lock Buster" + description = "For when someone's being really naughty with a spacepod" + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 8500) + export_price = 8500 + prereq_ids = list("spacepod_lasers", "high_efficiency", "adv_mining") + design_ids = list("pod_lockbuster") + +/datum/techweb_node/spacepod_iarmor + id = "spacepod_iarmor" + display_name = "Advanced Spacepod Armor" + description = "Better protection for your precious ride. You'll need it if you plan on engaging in spacepod battles." + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2750) + export_price = 2750 + prereq_ids = list("spacepod_storage", "high_efficiency") + design_ids = list("podarmor_industiral", "podarmor_sec", "podarmor_gold") diff --git a/yogstation/code/modules/spacepods/construction.dm b/yogstation/code/modules/spacepods/construction.dm new file mode 100644 index 000000000000..3467f54db279 --- /dev/null +++ b/yogstation/code/modules/spacepods/construction.dm @@ -0,0 +1,202 @@ +/obj/spacepod/examine(mob/user) + ..() + switch(construction_state) // more construction states than r-walls! + if(SPACEPOD_EMPTY) + to_chat(user, "The strits holding it together can be cut and i't is missing wires.") + if(SPACEPOD_WIRES_LOOSE) + to_chat(user, "The wires need to be screwed on.") + if(SPACEPOD_WIRES_SECURED) + to_chat(user, "The wires are screwed on and needs a circuit board.") + if(SPACEPOD_CIRCUIT_LOOSE) + to_chat(user, "The circuit board is loosely attached and needs to be screwed on.") + if(SPACEPOD_CIRCUIT_SECURED) + to_chat(user, "The circuit board is screwed on, and there is space for a core.") + if(SPACEPOD_CORE_LOOSE) + to_chat(user, "The core is loosely attached and needs to be bolted on.") + if(SPACEPOD_CORE_SECURED) + to_chat(user, "The core is bolted on and the metal bulkhead can be attached.") + if(SPACEPOD_BULKHEAD_LOOSE) + to_chat(user, "The bulkhead is loosely attached and can be bolted down.") + if(SPACEPOD_BULKHEAD_SECURED) + to_chat(user, "The bulkhead is bolted on but not welded on.") + if(SPACEPOD_BULKHEAD_WELDED) + to_chat(user, "The bulkhead is welded on and armor can be attached.") + if(SPACEPOD_ARMOR_LOOSE) + to_chat(user, "The armor is loosely attached and can be bolted down.") + if(SPACEPOD_ARMOR_SECURED) + to_chat(user, "The armor is bolted on but not welded on.") + if(SPACEPOD_ARMOR_WELDED) + if(hatch_open) + if(cell || internal_tank || equipment.len) + to_chat(user, "The maintenance hatch is pried and there are parts inside that can be removed.") + else + to_chat(user, "The maintenance hatch is pried open and the armor is welded on.") + else + if(locked) + to_chat(user, "[src] is locked.") + else + to_chat(user, "The maintenance hatch is pried 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].") + 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] adjusts the wiring.", "You adjust [src]'s wiring.") + 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.temporarilyRemoveItemFromInventory(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.", "You pry out the mainboard.") + else if(W.tool_behaviour == TOOL_SCREWDRIVER) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") + 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.temporarilyRemoveItemFromInventory(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] with a crowbar.", "You delicately remove the core from [src] with a crowbar.") + else if(W.tool_behaviour == TOOL_WRENCH) + . = TRUE + W.play_tool_sound(src) + construction_state++ + user.visible_message("[user] secures the core's bolts.", "You secure the core's 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-- + var/obj/item/stack/sheet/metal/five/M = new + 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_ARMOR_WELDED + user.visible_message("[user] seals [src]'s bulkhead panelling with a weld.", "You seal [src]'s bulkhead panelling with a weld.") + 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.transferItemToLoc(W, src)) + 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_icon() diff --git a/yogstation/code/modules/spacepods/equipment.dm b/yogstation/code/modules/spacepods/equipment.dm new file mode 100644 index 000000000000..6f84897079e7 --- /dev/null +++ b/yogstation/code/modules/spacepods/equipment.dm @@ -0,0 +1,349 @@ +/obj/item/spacepod_equipment + var/obj/spacepod/spacepod + icon = 'yogstation/icons/obj/spacepods/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 + +/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_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/gun_dry_fire.ogg', 30, TRUE) + return + spacepod.next_firetime = world.time + fire_delay + if(!spacepod.cell || !spacepod.cell.use(shot_cost)) + to_chat(usr, "Insufficient charge to fire the weapons") + playsound(src, 'sound/weapons/gun_dry_fire.ogg', 30, TRUE) + return + for(var/I in 1 to shots_per) + spacepod.fire_projectiles(projectile_type, target) + playsound(src, fire_sound, 50, TRUE) + sleep(2) + +/* +/////////////////////////////////////// +/////////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 + +/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/spacepod_mousedrop) + +/obj/item/spacepod_equipment/cargo/large/on_uninstall() + UnregisterSignal(spacepod, COMSIG_MOUSEDROPPED_ONTO) + ..() + +/obj/item/spacepod_equipment/cargo/large/can_uninstall(mob/user) + if(storage) + to_chat(user, "Unload the cargo first!") + return FALSE + return ..() + +/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_mob(user, list(A, SP), 40)) + 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 + 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/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/////////////////// +/////////////////////////////////////// +*/ + +/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 = 'yogstation/icons/obj/spacepods/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 = 'yogstation/icons/obj/spacepods/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 + shot_cost = 600 + fire_sound = 'sound/weapons/Laser.ogg' + overlay_icon = 'yogstation/icons/obj/spacepods/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 = 'yogstation/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 = 'yogstation/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 = 'yogstation/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 = 'yogstation/icons/obj/spacepods/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/////////////////// +/////////////////////////////////////// +*/ + +/obj/item/spacepod_equipment/tracker + name = "spacepod tracking system" + desc = "A tracking device for spacepods." + icon = 'yogstation/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/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() + . = ..() + 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 = 'yogstation/icons/obj/spacepods/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 = 'yogstation/icons/obj/spacepods/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/yogstation/code/modules/spacepods/parts.dm b/yogstation/code/modules/spacepods/parts.dm new file mode 100644 index 000000000000..00836229b329 --- /dev/null +++ b/yogstation/code/modules/spacepods/parts.dm @@ -0,0 +1,168 @@ +/obj/item/pod_parts + icon = 'yogstation/goon/icons/obj/spacepods/parts.dmi' + w_class = WEIGHT_CLASS_GIGANTIC + flags_1 = CONDUCT_1 + +/obj/item/pod_parts/core + name = "space pod core" + icon_state = "core" + +/obj/item/pod_parts/pod_frame + name = "space pod frame" + density = 0 + anchored = 0 + var/link_to = null + var/link_angle = 0 + +/obj/item/pod_parts/pod_frame/ComponentInitialize() + 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 + */ + 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 0 + 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 0 + return connectedparts + +/obj/item/pod_parts/pod_frame/attackby(var/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 = 'yogstation/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/circuitboard/mecha/pod + name = "Circuit board (Space Pod Mainboard)" + icon_state = "mainboard" diff --git a/yogstation/code/modules/spacepods/physics.dm b/yogstation/code/modules/spacepods/physics.dm new file mode 100644 index 000000000000..3bf8824b27c9 --- /dev/null +++ b/yogstation/code/modules/spacepods/physics.dm @@ -0,0 +1,295 @@ +/obj/spacepod/process(time) + time /= 10 // fuck off with your deciseconds + + 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 != 0) + var/drag = 0 + for(var/turf/T in locs) + if(isspaceturf(T)) + continue + drag += 0.001 + var/floating = FALSE + if(T.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 && T.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/open/floor)) + var/turf/open/floor/TF = T + TF.make_plating() // pull up some floor tiles. Stop going so fast, ree. + 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*10, 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*10, flags=ANIMATION_END_NOW) + user_thrust_dir = 0 + update_icon() + +/obj/spacepod/Bumped(atom/movable/A) + 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 wall with velocity [bump_velocity]") + take_damage(strength*10, BRUTE, "melee", TRUE) + log_game("[key_name(pilot)] has impacted a spacepod into a wall 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.Knockdown(bump_velocity * 2) + M.visible_message("The force of the impact knocks [M] down!","The force of the impact knocks you down!") + log_combat(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/yogstation/code/modules/spacepods/prebuilt.dm b/yogstation/code/modules/spacepods/prebuilt.dm new file mode 100644 index 000000000000..5414cded2865 --- /dev/null +++ b/yogstation/code/modules/spacepods/prebuilt.dm @@ -0,0 +1,29 @@ +/obj/spacepod/prebuilt + icon = 'yogstation/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/portable_atmospherics/canister/air + var/equipment_types = list() + construction_state = SPACEPOD_ARMOR_WELDED + +/obj/spacepod/prebuilt/Initialize() + ..() + 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) diff --git a/yogstation/code/modules/spacepods/spacepod.dm b/yogstation/code/modules/spacepods/spacepod.dm new file mode 100644 index 000000000000..91fcc51a2358 --- /dev/null +++ b/yogstation/code/modules/spacepods/spacepod.dm @@ -0,0 +1,683 @@ +// 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 + +GLOBAL_LIST_INIT(spacepods_list, list()) + +/obj/spacepod + name = "space pod" + desc = "A frame for a spacepod." + icon = 'yogstation/goon/icons/obj/spacepods/construction_2x2.dmi' + icon_state = "pod_1" + density = 1 + opacity = 0 + 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 + + anchored = 1 + 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 + var/datum/gas_mixture/cabin_air + var/obj/machinery/portable_atmospherics/canister/internal_tank + var/last_slowprocess = 0 + + var/mob/living/pilot + 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() + . = ..() + GLOB.spacepods_list += src + START_PROCESSING(SSfastprocess, src) + cabin_air = new + cabin_air.temperature = T20C + cabin_air.volume = 200 + /*cabin_air.assert_gas(/datum/gas/oxygen) + cabin_air.assert_gas(/datum/gas/nitrogen) + cabin_air.gases[/datum/gas/oxygen][MOLES] = ONE_ATMOSPHERE*O2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) + cabin_air.gases[/datum/gas/nitrogen][MOLES] = ONE_ATMOSPHERE*N2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature)*/ + +/obj/spacepod/Destroy() + GLOB.spacepods_list -= src + QDEL_NULL(pilot) + QDEL_LIST(passengers) + QDEL_LIST(equipment) + QDEL_NULL(cabin_air) + QDEL_NULL(cell) + return ..() + +/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.transferItemToLoc(W, src)) + to_chat(user, "You insert [W] into the pod.") + 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) && user.temporarilyRemoveItemFromInventory(SE)) + 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, "[user] is drilling through the [src]'s lock!", + "You start drilling through the [src]'s lock!") + if(do_after(user, 100 * W.toolspeed, target = src)) + if(lock) + var/obj/O = lock + lock.on_uninstall() + qdel(O) + user.visible_message(user, "[user] has destroyed the [src]'s lock!", + "You destroy the [src]'s lock!") + else + user.visible_message(user, "[user] fails to break through the [src]'s lock!", + "You were unable to break through the [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_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_icon() + 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)) + src.visible_message("[user] is trying to rip the door open and pull [target] out of the [src]!", + "You see [user] outside the door trying to rip it open!") + if(do_after(user, 50, 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 the [src]", + "The door flies open and you are thrown out of the [src] and to the ground!") + return + target.visible_message("[user] was unable to get the door open!", + "You manage to keep [user] out of the [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 ..() + var/list/items = list(cell, internal_tank) + items += equipment + var/list/item_map = 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) + // 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/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_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_icon() + + +/obj/spacepod/proc/InterceptClickOn(mob/user, params, atom/target) + var/list/params_list = params2list(params) + if(target == src || istype(target, /obj/screen) || (target && (target in user.GetAllContents())) || user != pilot || params_list["shift"] || params_list["alt"] || params_list["ctrl"]) + return FALSE + if(weapon) + weapon.fire_weapons(target) + return TRUE + +/obj/spacepod/take_damage() + ..() + update_icon() + +/obj/spacepod/return_air() + return cabin_air +/obj/spacepod/remove_air(amount) + return cabin_air.remove(amount) + +/obj/spacepod/proc/slowprocess() + if(cabin_air && cabin_air.volume > 0) + var/delta = cabin_air.temperature - T20C + cabin_air.temperature -= max(-10, min(10, round(delta/4,0.1))) + 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/turf/T = get_turf(src) + var/datum/gas_mixture/t_air = T.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) + T.assume_air(removed) + else //just delete the cabin gas, we're in space or some shit + qdel(removed) + +/mob/Stat() + . = ..() + if(isspacepod(loc) && statpanel("Status")) + var/obj/spacepod/S = loc + stat(null) + stat(null, "Spacepod Charge: [S.cell ? "[round(S.cell.charge,0.1)]/[S.cell.maxcharge] KJ" : "NONE"]") + stat(null, "Spacepod Integrity: [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") + stat(null) + +/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/five(loc) + if(prob(40)) + new /obj/item/stack/sheet/metal/five(loc) + 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(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/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 + + 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) + +/obj/spacepod/update_icon() + cut_overlays() + if(construction_state != SPACEPOD_ARMOR_WELDED) + icon = 'yogstation/goon/icons/obj/spacepods/construction_2x2.dmi' + icon_state = "pod_[construction_state]" + if(pod_armor && construction_state >= SPACEPOD_ARMOR_LOOSE) + var/mutable_appearance/masked_armor = mutable_appearance(icon = 'yogstation/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 + add_overlay(masked_armor) + return + + if(pod_armor) + icon = pod_armor.pod_icon + icon_state = pod_armor.pod_icon_state + else + icon = 'yogstation/goon/icons/obj/spacepods/2x2.dmi' + icon_state = initial(icon_state) + + if(obj_integrity <= max_integrity / 2) + add_overlay(image(icon='yogstation/goon/icons/obj/spacepods/2x2.dmi', icon_state="pod_damage")) + if(obj_integrity <= max_integrity / 4) + add_overlay(image(icon='yogstation/goon/icons/obj/spacepods/2x2.dmi', icon_state="pod_fire")) + + if(weapon && weapon.overlay_icon_state) + add_overlay(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.cardinals) + 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.cardinals) + if(last_rotate > 0) + right_thrusts[cdir] += frac + else + left_thrusts[cdir] += frac + for(var/cdir in GLOB.cardinals) + var/left_thrust = left_thrusts[cdir] + var/right_thrust = right_thrusts[cdir] + if(left_thrust) + add_overlay(image(icon = 'yogstation/icons/obj/spacepods/2x2.dmi', icon_state = "rcs_left", dir = cdir)) + if(right_thrust) + add_overlay(image(icon = 'yogstation/icons/obj/spacepods/2x2.dmi', icon_state = "rcs_right", dir = cdir)) + if(back_thrust) + var/image/I = image(icon = 'yogstation/icons/obj/spacepods/2x2.dmi', icon_state = "thrust") + I.transform = matrix(1, 0, 0, 0, 1, -32) + add_overlay(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/portable_atmospherics/canister)) + if(internal_tank) + to_chat(user, "[src] already has an internal_tank!") + 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_mob(user, list(A, src), 50) && 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, "That person can't fly the pod!") + return + if(passengers.len < max_passengers) + visible_message("[user] starts loading [M] into [src]!") + if(do_after_mob(user, list(M, src), 50) && construction_state == SPACEPOD_ARMOR_WELDED) + add_rider(M, FALSE) + return + if(M == user) + enter_pod(user) + return + + return ..() + +/obj/spacepod/proc/enter_pod(mob/living/user) + if(user.stat != CONSCIOUS) + return FALSE + + if(locked) + 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, 40, target = src) && construction_state == SPACEPOD_ARMOR_WELDED) + 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/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/verb/exit_pod() + set name = "Exit pod" + set category = "Spacepod" + set src = usr.loc + + if(!isliving(usr) || usr.stat > CONSCIOUS) + return + + if(usr.restrained()) + to_chat(usr, "You attempt to stumble out of the [src]. This will take two minutes.") + if(pilot) + to_chat(pilot, "[usr] is trying to escape the [src].") + if(!do_after(usr, 1200, target = src)) + return + + if(remove_rider(usr)) + to_chat(usr, "You climb out of [src].") + +/obj/spacepod/verb/lock_pod() + set name = "Lock Doors" + set category = "Spacepod" + set src = usr.loc + + if(!verb_check(FALSE)) + return + + if(!lock) + 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.") + +/obj/spacepod/verb/toggle_brakes() + set name = "Toggle Brakes" + set category = "Spacepod" + set src = usr.loc + + if(!verb_check()) + return + brakes = !brakes + to_chat(usr, "You toggle the brakes [brakes ? "on" : "off"].") + +/obj/spacepod/AltClick(user) + if(!verb_check(user = user)) + return + brakes = !brakes + to_chat(usr, "You toggle the brakes [brakes ? "on" : "off"].") + +/obj/spacepod/verb/toggleLights() + set name = "Toggle Lights" + set category = "Spacepod" + set src = usr.loc + + if(!verb_check()) + return + + lights = !lights + if(lights) + set_light(lights_power) + else + set_light(0) + to_chat(usr, "Lights toggled [lights ? "on" : "off"].") + for(var/mob/M in passengers) + to_chat(M, "Lights toggled [lights ? "on" : "off"].") + +/obj/spacepod/verb/toggleDoors() + set name = "Toggle Nearby Pod Doors" + set category = "Spacepod" + set src = usr.loc + + if(!verb_check()) + return + + for(var/obj/machinery/door/poddoor/multi_tile/P in orange(3,src)) + for(var/mob/living/carbon/human/O in contents) + if(P.check_access(O.get_active_held_item()) || 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.") + +/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 + else if(passengers.len < max_passengers) + passengers += M + else + return FALSE + 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 + if(M == pilot) + pilot = null + 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/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 + +/obj/spacepod/Entered() + . = ..() +/obj/spacepod/Exited() + . = ..() diff --git a/yogstation/goon/LICENSE.md b/yogstation/goon/LICENSE.md new file mode 100644 index 000000000000..d227d11c6cdf --- /dev/null +++ b/yogstation/goon/LICENSE.md @@ -0,0 +1,4 @@ +This work is licensed under the Creative Commons +Attribution-NonCommercial-ShareAlike 3.0 United States License. To view a copy +of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/us/ or +send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. \ No newline at end of file diff --git a/yogstation/goon/README.md b/yogstation/goon/README.md new file mode 100644 index 000000000000..cae34de90841 --- /dev/null +++ b/yogstation/goon/README.md @@ -0,0 +1,8 @@ +# Goon-ported-assets + +All files excluding this one you're reading right now have been most likely, taken from [goonstation's 2016 release](https://github.com/goonstation/goonstation-2016), unless stated otherwise. +It is very likely that there are modifications to be compatible or on par with our code, however. These changes are licensed under the same license as the other goon files. + +## License + +See LICENSE.md diff --git a/yogstation/goon/icons/obj/spacepods/2x2.dmi b/yogstation/goon/icons/obj/spacepods/2x2.dmi new file mode 100644 index 000000000000..02def41cf1bc Binary files /dev/null and b/yogstation/goon/icons/obj/spacepods/2x2.dmi differ diff --git a/yogstation/goon/icons/obj/spacepods/construction_2x2.dmi b/yogstation/goon/icons/obj/spacepods/construction_2x2.dmi new file mode 100644 index 000000000000..7766fa79788e Binary files /dev/null and b/yogstation/goon/icons/obj/spacepods/construction_2x2.dmi differ diff --git a/yogstation/goon/icons/obj/spacepods/parts.dmi b/yogstation/goon/icons/obj/spacepods/parts.dmi new file mode 100644 index 000000000000..6375a6ebba77 Binary files /dev/null and b/yogstation/goon/icons/obj/spacepods/parts.dmi differ diff --git a/yogstation/icons/effects/beam.dmi b/yogstation/icons/effects/beam.dmi new file mode 100644 index 000000000000..792622d8fd2c Binary files /dev/null and b/yogstation/icons/effects/beam.dmi differ diff --git a/yogstation/icons/obj/doors/1x2blast_hor.dmi b/yogstation/icons/obj/doors/1x2blast_hor.dmi new file mode 100644 index 000000000000..59827a280793 Binary files /dev/null and b/yogstation/icons/obj/doors/1x2blast_hor.dmi differ diff --git a/yogstation/icons/obj/doors/1x2blast_vert.dmi b/yogstation/icons/obj/doors/1x2blast_vert.dmi new file mode 100644 index 000000000000..f3fe9da8bbfe Binary files /dev/null and b/yogstation/icons/obj/doors/1x2blast_vert.dmi differ diff --git a/yogstation/icons/obj/doors/1x3blast_hor.dmi b/yogstation/icons/obj/doors/1x3blast_hor.dmi new file mode 100644 index 000000000000..72d8898ae6c9 Binary files /dev/null and b/yogstation/icons/obj/doors/1x3blast_hor.dmi differ diff --git a/yogstation/icons/obj/doors/1x3blast_vert.dmi b/yogstation/icons/obj/doors/1x3blast_vert.dmi new file mode 100644 index 000000000000..6fe220f28ccd Binary files /dev/null and b/yogstation/icons/obj/doors/1x3blast_vert.dmi differ diff --git a/yogstation/icons/obj/doors/1x4blast_hor.dmi b/yogstation/icons/obj/doors/1x4blast_hor.dmi new file mode 100644 index 000000000000..41165639a905 Binary files /dev/null and b/yogstation/icons/obj/doors/1x4blast_hor.dmi differ diff --git a/yogstation/icons/obj/doors/1x4blast_vert.dmi b/yogstation/icons/obj/doors/1x4blast_vert.dmi new file mode 100644 index 000000000000..2835732ad540 Binary files /dev/null and b/yogstation/icons/obj/doors/1x4blast_vert.dmi differ diff --git a/yogstation/icons/obj/spacepods/2x2.dmi b/yogstation/icons/obj/spacepods/2x2.dmi new file mode 100644 index 000000000000..ecdb69d66c37 Binary files /dev/null and b/yogstation/icons/obj/spacepods/2x2.dmi differ diff --git a/yogstation/icons/obj/spacepods/parts.dmi b/yogstation/icons/obj/spacepods/parts.dmi new file mode 100644 index 000000000000..4b51a7ca68b4 Binary files /dev/null and b/yogstation/icons/obj/spacepods/parts.dmi differ