diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 39074c65664..0bd2b82b42a 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -24,6 +24,7 @@ #define FIRELOSS 2 #define TOXLOSS 4 #define OXYLOSS 8 +#define SHAME 16 //Bitflags defining which status effects could be or are inflicted on a mob #define CANSTUN 1 diff --git a/code/__DEFINES/genetics.dm b/code/__DEFINES/genetics.dm index 11393957fc1..8e7be007d12 100644 --- a/code/__DEFINES/genetics.dm +++ b/code/__DEFINES/genetics.dm @@ -12,6 +12,7 @@ #define DISABILITY_FLAG_DEAF 8 #define DISABILITY_FLAG_BLIND 16 #define DISABILITY_FLAG_MUTE 32 +#define DISABILITY_FLAG_COLOURBLIND 64 /////////////////////////////////////// // MUTATIONS @@ -84,8 +85,9 @@ #define TOURETTES 8 #define NERVOUS 16 #define BLIND 32 -#define MUTE 64 -#define DEAF 128 +#define COLOURBLIND 64 +#define MUTE 128 +#define DEAF 256 //Nutrition levels for humans. No idea where else to put it #define NUTRITION_LEVEL_FAT 600 @@ -113,4 +115,4 @@ #define GENETIC_DAMAGE_STAGE_3 35 #define CLONER_FRESH_CLONE "fresh" -#define CLONER_MATURE_CLONE "mature" \ No newline at end of file +#define CLONER_MATURE_CLONE "mature" diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm new file mode 100644 index 00000000000..83db83c329c --- /dev/null +++ b/code/__DEFINES/inventory.dm @@ -0,0 +1,7 @@ +//ITEM INVENTORY WEIGHT, FOR w_class +#define WEIGHT_CLASS_TINY 1 //Usually items smaller then a human hand, ex: Playing Cards, Lighter, Scalpel, Coins/Money +#define WEIGHT_CLASS_SMALL 2 //Pockets can hold small and tiny items, ex: Flashlight, Multitool, Grenades, GPS Device +#define WEIGHT_CLASS_NORMAL 3 //Standard backpacks can carry tiny, small & normal items, ex: Fire extinguisher, Stunbaton, Gas Mask, Metal Sheets +#define WEIGHT_CLASS_BULKY 4 //Items that can be weilded or equipped but not stored in an inventory, ex: Defibrillator, Backpack, Space Suits +#define WEIGHT_CLASS_HUGE 5 //Usually represents objects that require two hands to operate, ex: Shotgun, Two Handed Melee Weapons +#define WEIGHT_CLASS_GIGANTIC 6 //Essentially means it cannot be picked up or placed in an inventory, ex: Mech Parts, Safe \ No newline at end of file diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm new file mode 100644 index 00000000000..08a267322db --- /dev/null +++ b/code/__DEFINES/layers.dm @@ -0,0 +1,63 @@ +//Defines for atom layers and planes +//KEEP THESE IN A NICE ACSCENDING ORDER, PLEASE + +#define CLICKCATCHER_PLANE -99 + +#define PLANE_SPACE -95 +#define PLANE_SPACE_PARALLAX -90 + +#define GAME_PLANE 0 +//#define TURF_LAYER 2 //For easy recordkeeping; this is a byond define +#define MID_TURF_LAYER 2.02 +#define HIGH_TURF_LAYER 2.03 +#define ABOVE_OPEN_TURF_LAYER 2.04 +#define CLOSED_TURF_LAYER 2.05 +#define ABOVE_NORMAL_TURF_LAYER 2.08 +#define LATTICE_LAYER 2.2 +#define DISPOSAL_PIPE_LAYER 2.3 +#define GAS_PIPE_LAYER 2.35 +#define WIRE_LAYER 2.4 +#define WIRE_TERMINAL_LAYER 2.45 +#define LOW_OBJ_LAYER 2.5 + +#define BELOW_OPEN_DOOR_LAYER 2.6 +#define OPEN_DOOR_LAYER 2.7 +#define PROJECTILE_HIT_THRESHHOLD_LAYER 2.75 //projectiles won't hit objects at or below this layer if possible +#define TABLE_LAYER 2.8 +#define BELOW_OBJ_LAYER 2.9 +#define LOW_ITEM_LAYER 2.95 +//#define OBJ_LAYER 3 //For easy recordkeeping; this is a byond define +#define CLOSED_DOOR_LAYER 3.1 +#define CLOSED_FIREDOOR_LAYER 3.11 +#define ABOVE_OBJ_LAYER 3.2 +#define ABOVE_WINDOW_LAYER 3.3 +#define SIGN_LAYER 3.4 +#define NOT_HIGH_OBJ_LAYER 3.5 +#define HIGH_OBJ_LAYER 3.6 + +#define BELOW_MOB_LAYER 3.7 +#define LYING_MOB_LAYER 3.8 +//#define MOB_LAYER 4 //For easy recordkeeping; this is a byond define +#define ABOVE_MOB_LAYER 4.1 +#define WALL_OBJ_LAYER 4.25 +#define EDGED_TURF_LAYER 4.3 +#define ON_EDGED_TURF_LAYER 4.35 +#define LARGE_MOB_LAYER 4.4 +#define ABOVE_ALL_MOB_LAYER 4.5 + +#define SPACEVINE_LAYER 4.8 +#define SPACEVINE_MOB_LAYER 4.9 +//#define FLY_LAYER 5 //For easy recordkeeping; this is a byond define +#define RIPPLE_LAYER 5.1 + +#define GHOST_LAYER 6 +#define AREA_LAYER 10 +#define MASSIVE_OBJ_LAYER 11 +#define POINT_LAYER 12 + +#define LIGHTING_PLANE 15 +#define LIGHTING_LAYER 15 + +//HUD layer defines +#define HUD_LAYER 19 +#define HUD_PLANE 90 \ No newline at end of file diff --git a/code/__DEFINES/lighting.dm b/code/__DEFINES/lighting.dm index 7fbec83455a..c18fb516f4b 100644 --- a/code/__DEFINES/lighting.dm +++ b/code/__DEFINES/lighting.dm @@ -1,10 +1,43 @@ -#define LIGHTING_INTERVAL 5 // frequency, in 1/10ths of a second, of the lighting process - #define LIGHTING_FALLOFF 1 // type of falloff to use for lighting; 1 for circular, 2 for square #define LIGHTING_LAMBERTIAN 0 // use lambertian shading for light sources #define LIGHTING_HEIGHT 1 // height off the ground of light sources on the pseudo-z-axis, you should probably leave this alone #define LIGHTING_LAYER 10 // drawing layer for lighting overlays -#define LIGHTING_ICON 'icons/effects/lighting_overlay.dmi' // icon used for lighting shading effects +#define LIGHTING_ICON 'icons/effects/lighting_overlay.png' // icon used for lighting shading effects #define LIGHTING_ROUND_VALUE (1 / 128) //Value used to round lumcounts, values smaller than 1/255 don't matter (if they do, thanks sinking points), greater values will make lighting less precise, but in turn increase performance, VERY SLIGHTLY. + +#define LIGHTING_SOFT_THRESHOLD 0.05 // If the max of the lighting lumcounts of each spectrum drops below this, disable luminosity on the lighting overlays. + +// If I were you I'd leave this alone. +#define LIGHTING_BASE_MATRIX \ + list \ + ( \ + LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \ + LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \ + LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \ + LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \ + 0, 0, 0, 1 \ + ) \ + +// Helpers so we can (more easily) control the colour matrices. +#define CL_MATRIX_RR 1 +#define CL_MATRIX_RG 2 +#define CL_MATRIX_RB 3 +#define CL_MATRIX_RA 4 +#define CL_MATRIX_GR 5 +#define CL_MATRIX_GG 6 +#define CL_MATRIX_GB 7 +#define CL_MATRIX_GA 8 +#define CL_MATRIX_BR 9 +#define CL_MATRIX_BG 10 +#define CL_MATRIX_BB 11 +#define CL_MATRIX_BA 12 +#define CL_MATRIX_AR 13 +#define CL_MATRIX_AG 14 +#define CL_MATRIX_AB 15 +#define CL_MATRIX_AA 16 +#define CL_MATRIX_CR 17 +#define CL_MATRIX_CG 18 +#define CL_MATRIX_CB 19 +#define CL_MATRIX_CA 20 \ No newline at end of file diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 64e38bba06d..b9f32e9b49a 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -253,16 +253,19 @@ #define MAP_MAXZ 6 //Matricies -#define MATRIX_DEFAULT list(1, 0, 0, 0,\ - 0, 1, 0, 0,\ - 0, 0, 1, 0,\ - 0, 0, 0, 1) +#define MATRIX_GREYSCALE list(0.33, 0.33, 0.33,\ + 0.33, 0.33, 0.33,\ + 0.33, 0.33, 0.33) + +#define MATRIX_VULP_CBLIND list(0.5,0.4,0.1,\ + 0.5,0.4,0.1,\ + 0.0,0.2,0.8) + +#define MATRIX_TAJ_CBLIND list(0.4,0.2,0.4,\ + 0.4,0.6,0.0,\ + 0.2,0.2,0.6) + -#define MATRIX_GREYSCALE list(0.33, 0.33, 0.33, 0,\ - 0.33, 0.33, 0.33, 0,\ - 0.33, 0.33, 0.33, 0,\ - 0.00, 0.00, 0.00, 1,\ - 0.00, 0.00, 0.00, 0) //Gun trigger guards #define TRIGGER_GUARD_ALLOW_ALL -1 #define TRIGGER_GUARD_NONE 0 diff --git a/code/__DEFINES/reagents.dm b/code/__DEFINES/reagents.dm new file mode 100644 index 00000000000..3e81a67b1b2 --- /dev/null +++ b/code/__DEFINES/reagents.dm @@ -0,0 +1,3 @@ +#define SOLID 1 +#define LIQUID 2 +#define GAS 3 \ No newline at end of file diff --git a/code/__HELPERS/AnimationLibrary.dm b/code/__HELPERS/AnimationLibrary.dm index fcabe2e0a78..fd79fe197f2 100644 --- a/code/__HELPERS/AnimationLibrary.dm +++ b/code/__HELPERS/AnimationLibrary.dm @@ -7,7 +7,7 @@ /proc/animate_fade_grayscale(var/atom/A, var/time = 5) if(!istype(A) && !istype(A, /client)) return - A.color = MATRIX_DEFAULT + A.color = null animate(A, color = MATRIX_GREYSCALE, time = time, easing = SINE_EASING) /proc/animate_melt_pixel(var/atom/A) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 1ada9f5100d..c6f0e9bf1c9 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -412,6 +412,23 @@ return 0 return 1 + +/proc/GetRedPart(const/hexa) + return hex2num(copytext(hexa, 2, 4)) + +/proc/GetGreenPart(const/hexa) + return hex2num(copytext(hexa, 4, 6)) + +/proc/GetBluePart(const/hexa) + return hex2num(copytext(hexa, 6, 8)) + +/proc/GetHexColors(const/hexa) + return list( + GetRedPart(hexa), + GetGreenPart(hexa), + GetBluePart(hexa), + ) + /proc/MinutesToTicks(var/minutes as num) return minutes * 60 * 10 diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 5d5307cd50d..cfe37505e1c 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -884,3 +884,9 @@ proc/sort_atoms_by_layer(var/list/atoms) icon = J return J return 0 + +//Hook, override to run code on- wait this is images +//Images have dir without being an atom, so they get their own definition. +//Lame. +/image/proc/setDir(newdir) + dir = newdir diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 9644b4348b3..930e8244eb6 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1563,7 +1563,7 @@ var/mob/dview/dview_mob = new //pre_rotation: Chooses to rotate src 90 degress towards the orbit dir (clockwise/anticlockwise), useful for things to go "head first" like ghosts //lockinorbit: Forces src to always be on A's turf, otherwise the orbit cancels when src gets too far away (eg: ghosts) -/atom/movable/proc/orbit(atom/A, radius = 10, clockwise = FALSE, rotation_speed = 20, rotation_segments = 36, pre_rotation = TRUE, lockinorbit = FALSE) +/atom/movable/proc/orbit(atom/A, radius = 10, clockwise = FALSE, rotation_speed = 20, rotation_segments = 36, pre_rotation = TRUE, lockinorbit = FALSE, forceMove = FALSE) if(!istype(A)) return @@ -1595,7 +1595,10 @@ var/mob/dview/dview_mob = new var/targetloc = get_turf(A) if(!lockinorbit && loc != lastloc && loc != targetloc) break - loc = targetloc + if(forceMove) + forceMove(targetloc) + else + loc = targetloc lastloc = loc sleep(0.6) diff --git a/code/_globalvars/genetics.dm b/code/_globalvars/genetics.dm index 73b2b7304f6..116aa0797cb 100644 --- a/code/_globalvars/genetics.dm +++ b/code/_globalvars/genetics.dm @@ -1,5 +1,6 @@ /////////// var/BLINDBLOCK = 0 +var/COLOURBLINDBLOCK = 0 var/DEAFBLOCK = 0 var/HULKBLOCK = 0 var/TELEBLOCK = 0 diff --git a/code/_onclick/_defines.dm b/code/_onclick/_defines.dm deleted file mode 100644 index a02a1f43590..00000000000 --- a/code/_onclick/_defines.dm +++ /dev/null @@ -1,3 +0,0 @@ -#define CLICKCATCHER_PLANE -99 - -#define HUD_PLANE 90 \ No newline at end of file diff --git a/code/controllers/Processes/lighting.dm b/code/controllers/Processes/lighting.dm index 7d463abbd7f..15b134ecf44 100644 --- a/code/controllers/Processes/lighting.dm +++ b/code/controllers/Processes/lighting.dm @@ -1,18 +1,91 @@ -var/global/datum/controller/process/lighting/lighting_controller +// Solves problems with lighting updates lagging shit +// Max constraints on number of updates per doWork(): +#define MAX_LIGHT_UPDATES_PER_WORK 100 +#define MAX_CORNER_UPDATES_PER_WORK 1000 +#define MAX_OVERLAY_UPDATES_PER_WORK 2000 +/var/lighting_overlays_initialised = FALSE + +/var/list/lighting_update_lights = list() // List of lighting sources queued for update. +/var/list/lighting_update_corners = list() // List of lighting corners queued for update. +/var/list/lighting_update_overlays = list() // List of lighting overlays queued for update. + +/var/list/lighting_update_lights_old = list() // List of lighting sources currently being updated. +/var/list/lighting_update_corners_old = list() // List of lighting corners currently being updated. +/var/list/lighting_update_overlays_old = list() // List of lighting overlays currently being updated. + + +/datum/controller/process/lighting /datum/controller/process/lighting/setup() name = "lighting" - schedule_interval = LIGHTING_INTERVAL - start_delay = 1 - lighting_controller = src - create_lighting_overlays() + schedule_interval = world.tick_lag // run as fast as you possibly can + create_all_lighting_overlays() + lighting_overlays_initialised = TRUE + // Pre-process lighting once before the round starts. Wait 30 seconds so the away mission has time to load. spawn(300) - doWork() + doWork(1) -/datum/controller/process/lighting/statProcess() - ..() - stat(null, "[last_light_count] lights, [last_overlay_count] overlays") +/datum/controller/process/lighting/doWork(roundstart) + // Counters + var/light_updates = 0 + var/corner_updates = 0 + var/overlay_updates = 0 -// Lighting process code located in modules\lighting\lighting_process.dm \ No newline at end of file + lighting_update_lights_old = lighting_update_lights //We use a different list so any additions to the update lists during a delay from scheck() don't cause things to be cut from the list without being updated. + lighting_update_lights = list() + for(var/datum/light_source/L in lighting_update_lights_old) + if(light_updates >= MAX_LIGHT_UPDATES_PER_WORK && !roundstart) + lighting_update_lights += L + continue // DON'T break, we're adding stuff back into the update queue. + + if(L.check() || L.destroyed || L.force_update) + L.remove_lum() + if(!L.destroyed) + L.apply_lum() + + else if(L.vis_update) //We smartly update only tiles that became (in) visible to use. + L.smart_vis_update() + + L.vis_update = FALSE + L.force_update = FALSE + L.needs_update = FALSE + + light_updates++ + + SCHECK + + lighting_update_corners_old = lighting_update_corners //Same as above. + lighting_update_corners = list() + for(var/A in lighting_update_corners_old) + if(corner_updates >= MAX_CORNER_UPDATES_PER_WORK && !roundstart) + lighting_update_corners += A + continue // DON'T break, we're adding stuff back into the update queue. + + var/datum/lighting_corner/C = A + + C.update_overlays() + + C.needs_update = FALSE + + corner_updates++ + + SCHECK + + lighting_update_overlays_old = lighting_update_overlays //Same as above. + lighting_update_overlays = list() + + for(var/atom/movable/lighting_overlay/O in lighting_update_overlays_old) + if(overlay_updates >= MAX_OVERLAY_UPDATES_PER_WORK && !roundstart) + lighting_update_overlays += O + continue // DON'T break, we're adding stuff back into the update queue. + + O.update_overlay() + O.needs_update = 0 + overlay_updates++ + SCHECK + +#undef MAX_LIGHT_UPDATES_PER_WORK +#undef MAX_CORNER_UPDATES_PER_WORK +#undef MAX_OVERLAY_UPDATES_PER_WORK diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm index 027101df146..fe8d1cbb133 100644 --- a/code/controllers/verbs.dm +++ b/code/controllers/verbs.dm @@ -17,7 +17,7 @@ message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.") return -/client/proc/debug_controller(controller in list("Master","failsafe","Ticker","Air","Lighting","Jobs","Sun","Radio","Configuration","pAI", "Cameras","Garbage", "Transfer Controller","Event","Alarm","Scheduler","Nano","Vote","Diseases","Fires","Mob","NPC AI","Shuttle","Timer","Weather","Space","Mob Hunt Server")) +/client/proc/debug_controller(controller in list("Master","failsafe","Ticker","Air","Jobs","Sun","Radio","Configuration","pAI", "Cameras","Garbage", "Transfer Controller","Event","Alarm","Scheduler","Nano","Vote","Diseases","Fires","Mob","NPC AI","Shuttle","Timer","Weather","Space","Mob Hunt Server")) set category = "Debug" set name = "Debug Controller" set desc = "Debug the various periodic loop controllers for the game (be careful!)" @@ -36,9 +36,6 @@ if("Air") debug_variables(air_master) feedback_add_details("admin_verb","DAir") - if("Lighting") - debug_variables(lighting_controller) - feedback_add_details("admin_verb","DLighting") if("Jobs") debug_variables(job_master) feedback_add_details("admin_verb","DJobs") diff --git a/code/datums/spells/summonitem.dm b/code/datums/spells/summonitem.dm index 8ad20486041..7872c3978cb 100644 --- a/code/datums/spells/summonitem.dm +++ b/code/datums/spells/summonitem.dm @@ -26,6 +26,10 @@ for(var/obj/item in hand_items) if(istype(item, /obj/item/organ/internal/brain)) //Yeah, sadly this doesn't work due to the organ system. break + if(ABSTRACT in item.flags) + continue + if(NODROP in item.flags) + message += "This feels very redundant, but you go through with it anyway.
" marked_item = item message += "You mark [item] for recall." name = "Recall [item]" @@ -36,6 +40,7 @@ message = "You aren't holding anything that can be marked for recall." else message = "You must hold the desired item in your hands to mark it for recall." + else if(marked_item && marked_item in hand_items) //unlinking item to the spell message = "You remove the mark on [marked_item] to use elsewhere." name = "Instant Summons" diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 5585ec23a4f..8ec413450b0 100644 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -106,14 +106,14 @@ var/list/ghostteleportlocs = list() name = "\improper Admin Room" icon_state = "start" requires_power = 0 - lighting_use_dynamic = 0 + dynamic_lighting = 0 /area/adminconstruction name = "\improper Admin Testing Area" icon_state = "start" requires_power = 0 - lighting_use_dynamic = 0 + dynamic_lighting = 0 /area/space icon_state = "space" @@ -466,7 +466,7 @@ var/list/ghostteleportlocs = list() icon_state = "start" requires_power = 0 luminosity = 1 - lighting_use_dynamic = 0 + dynamic_lighting = 0 has_gravity = 1 // === end remove @@ -482,7 +482,7 @@ var/list/ghostteleportlocs = list() name = "\improper Centcom" icon_state = "centcom" requires_power = 0 - lighting_use_dynamic = 0 + dynamic_lighting = 0 /area/centcom/control name = "\improper Centcom Control" @@ -563,7 +563,7 @@ var/list/ghostteleportlocs = list() name = "\improper Thunderdome" icon_state = "thunder" requires_power = 0 - lighting_use_dynamic = 0 + dynamic_lighting = 0 /area/tdome/arena_source @@ -648,7 +648,7 @@ var/list/ghostteleportlocs = list() icon_state = "yellow" requires_power = 0 has_gravity = 1 - lighting_use_dynamic = 0 + dynamic_lighting = 0 /area/wizard_station name = "\improper Wizard's Den" @@ -671,7 +671,7 @@ var/list/ghostteleportlocs = list() name = "\improper Vox Base" icon_state = "yellow" requires_power = 0 - lighting_use_dynamic = 0 + dynamic_lighting = 0 no_teleportlocs = 1 /area/vox_station/transit @@ -1228,7 +1228,7 @@ var/list/ghostteleportlocs = list() /area/holodeck name = "\improper Holodeck" icon_state = "Holodeck" - lighting_use_dynamic = 0 + dynamic_lighting = 0 /area/holodeck/alphadeck name = "\improper Holodeck Alpha" @@ -1365,7 +1365,7 @@ var/list/ghostteleportlocs = list() /area/solar requires_power = 0 - lighting_use_dynamic = 0 + dynamic_lighting = 0 auxport name = "\improper Fore Port Solar Array" @@ -2280,25 +2280,25 @@ area/security/podbay name = "\improper AI Sat Ext" icon_state = "storage" luminosity = 1 - lighting_use_dynamic = 0 + dynamic_lighting = 0 /area/turret_protected/AIsatextFS name = "\improper AI Sat Ext" icon_state = "storage" luminosity = 1 - lighting_use_dynamic = 0 + dynamic_lighting = 0 /area/turret_protected/AIsatextAS name = "\improper AI Sat Ext" icon_state = "storage" luminosity = 1 - lighting_use_dynamic = 0 + dynamic_lighting = 0 /area/turret_protected/AIsatextAP name = "\improper AI Sat Ext" icon_state = "storage" luminosity = 1 - lighting_use_dynamic = 0 + dynamic_lighting = 0 /area/turret_protected/NewAIMain name = "\improper AI Main New" @@ -2475,7 +2475,7 @@ area/security/podbay name = "Beach" icon_state = "beach" luminosity = 1 - lighting_use_dynamic = 0 + dynamic_lighting = 0 requires_power = 0 ambientsounds = list('sound/ambience/shore.ogg', 'sound/ambience/seag1.ogg','sound/ambience/seag2.ogg','sound/ambience/seag2.ogg') diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 34c6d785fb5..ec70d50c504 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -29,7 +29,7 @@ if(type == /area) // override defaults for space. TODO: make space areas of type /area/space rather than /area requires_power = 1 always_unpowered = 1 - lighting_use_dynamic = 1 + dynamic_lighting = 1 power_light = 0 power_equip = 0 power_environ = 0 diff --git a/code/game/asteroid.dm b/code/game/asteroid.dm index c78037a73b4..77c3179adf5 100644 --- a/code/game/asteroid.dm +++ b/code/game/asteroid.dm @@ -88,7 +88,7 @@ var/global/max_secret_rooms = 6 theme = "cavein" walltypes = list(/turf/simulated/mineral/random/high_chance=1) floortypes = list(/turf/simulated/floor/plating/airless/asteroid, /turf/simulated/floor/beach/sand) - treasureitems = list(/obj/mecha/working/ripley/mining=1, /obj/item/weapon/pickaxe/drill/diamonddrill=2,/obj/item/weapon/gun/energy/kinetic_accelerator/hyper=1, + treasureitems = list(/obj/mecha/working/ripley/mining=1, /obj/item/weapon/pickaxe/drill/diamonddrill=2, /obj/item/weapon/resonator/upgraded=1, /obj/item/weapon/pickaxe/drill/jackhammer=5) fluffitems = list(/obj/effect/decal/cleanable/blood=3,/obj/effect/decal/remains/human=1,/obj/item/clothing/under/overalls=1, /obj/item/weapon/reagent_containers/food/snacks/grown/chili=1,/obj/item/weapon/tank/oxygen/red=2) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index eef930f78a7..a7d464fb9db 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -81,6 +81,10 @@ reagents = null invisibility = 101 return ..() + +//Hook for running code when a dir change occurs +/atom/proc/setDir(newdir) + dir = newdir /atom/proc/CheckParts(list/parts_list) for(var/A in parts_list) @@ -222,11 +226,6 @@ /atom/proc/relaymove() return -//called to set the atom's dir and used to add behaviour to dir-changes - Not fully used (yet) -/atom/proc/set_dir(new_dir) - . = new_dir != dir - dir = new_dir - /atom/proc/ex_act() return diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index f64b914f3eb..b8673b497d5 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -32,7 +32,13 @@ /atom/movable/Destroy() for(var/atom/movable/AM in contents) qdel(AM) + var/turf/un_opaque + if(opacity && isturf(loc)) + un_opaque = loc + loc = null + if(un_opaque) + un_opaque.recalc_atom_opacity() if(pulledby) if(pulledby.pulling == src) pulledby.pulling = null diff --git a/code/game/dna/genes/disabilities.dm b/code/game/dna/genes/disabilities.dm index 4cfa6f45750..aaea991d5cf 100644 --- a/code/game/dna/genes/disabilities.dm +++ b/code/game/dna/genes/disabilities.dm @@ -115,6 +115,24 @@ /datum/dna/gene/disability/blindness/New() block=BLINDBLOCK +/datum/dna/gene/disability/colourblindness + name = "Colourblindness" + activation_message = "You feel a peculiar prickling in your eyes while your perception of colour changes." + deactivation_message ="Your eyes tingle unsettlingly, though everything seems to become alot more colourful." + instability = -GENE_INSTABILITY_MODERATE + disability = COLOURBLIND + +/datum/dna/gene/disability/colourblindness/New() + block=COLOURBLINDBLOCK + +/datum/dna/gene/disability/colourblindness/activate(var/mob/M, var/connected, var/flags) + ..() + M.update_client_colour() //Handle the activation of the colourblindness on the mob. + +/datum/dna/gene/disability/colourblindness/deactivate(var/mob/M, var/connected, var/flags) + ..() + M.update_client_colour() //Handle the deactivation of the colourblindness on the mob. + /datum/dna/gene/disability/deaf name="Deafness" activation_message="It's kinda quiet." @@ -126,7 +144,7 @@ block=DEAFBLOCK /datum/dna/gene/disability/deaf/activate(var/mob/M, var/connected, var/flags) - ..(M,connected,flags) + ..() M.EarDeaf(1) /datum/dna/gene/disability/nearsighted @@ -139,7 +157,6 @@ /datum/dna/gene/disability/nearsighted/New() block=GLASSESBLOCK - /datum/dna/gene/disability/lisp name = "Lisp" desc = "I wonder wath thith doeth." diff --git a/code/game/dna/genes/goon_powers.dm b/code/game/dna/genes/goon_powers.dm index 60b002b4bf8..e4c09aeac17 100644 --- a/code/game/dna/genes/goon_powers.dm +++ b/code/game/dna/genes/goon_powers.dm @@ -57,12 +57,7 @@ var/turf/simulated/T = get_turf(M) if(!istype(T)) return - var/atom/movable/lighting_overlay/L = locate(/atom/movable/lighting_overlay) in T - var/light_available - if(L) - light_available = L.get_clamped_lum()*10 - else - light_available = 5 + var/light_available = T.get_lumcount() * 10 if(light_available <= 2) M.alpha = round(M.alpha * 0.8) else diff --git a/code/game/gamemodes/changeling/powers/humanform.dm b/code/game/gamemodes/changeling/powers/humanform.dm index e587a7db0ab..fb3012cd274 100644 --- a/code/game/gamemodes/changeling/powers/humanform.dm +++ b/code/game/gamemodes/changeling/powers/humanform.dm @@ -24,15 +24,18 @@ if(!user) return 0 to_chat(user, "We transform our appearance.") - user.dna.SetSEState(MONKEYBLOCK,0) - domutcheck(user, null) // Do a pre-mutcheck to cleanly switch from monkey form. - user.dna = chosen_dna + user.dna.SetSEState(MONKEYBLOCK,0,1) + genemutcheck(user,MONKEYBLOCK,null,MUTCHK_FORCED) + user.dna = chosen_dna.Clone() user.real_name = chosen_dna.real_name + if(istype(user)) + user.set_species(chosen_dna.species) + domutcheck(user,null,MUTCHK_FORCED) user.flavor_text = "" - if(ishuman(user)) - user.set_species() + user.dna.UpdateSE() + user.dna.UpdateUI() + user.sync_organ_dna(1) user.UpdateAppearance() - domutcheck(user, null) changeling.purchasedpowers -= src //O.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/lesserform(null) diff --git a/code/game/gamemodes/changeling/powers/lesserform.dm b/code/game/gamemodes/changeling/powers/lesserform.dm index e5040af282f..8ba1e53cb10 100644 --- a/code/game/gamemodes/changeling/powers/lesserform.dm +++ b/code/game/gamemodes/changeling/powers/lesserform.dm @@ -21,6 +21,7 @@ to_chat(H, "We cannot perform this ability in this form!") return + user.dna = user.dna.Clone() H.visible_message("[H] transforms!") changeling.geneticdamage = 30 to_chat(H, "Our genes cry out!") diff --git a/code/game/gamemodes/changeling/powers/transform.dm b/code/game/gamemodes/changeling/powers/transform.dm index f1ff51a42a2..b7c8abefd1d 100644 --- a/code/game/gamemodes/changeling/powers/transform.dm +++ b/code/game/gamemodes/changeling/powers/transform.dm @@ -16,12 +16,15 @@ return user.dna = chosen_dna.Clone() user.real_name = chosen_dna.real_name - user.flavor_text = "" if(ishuman(user)) - user.set_species() + user.set_species(chosen_dna.species) + domutcheck(user, null, MUTCHK_FORCED) //Ensures species that get powers by the species proc handle_dna keep them + user.flavor_text = "" + user.dna.UpdateSE() + user.dna.UpdateUI() + user.sync_organ_dna(1) user.UpdateAppearance() - domutcheck(user, null) - + user.changeling_update_languages(changeling.absorbed_languages) feedback_add_details("changeling_powers","TR") diff --git a/code/game/gamemodes/miniantags/slaughter/slaughter.dm b/code/game/gamemodes/miniantags/slaughter/slaughter.dm index 2750341e982..6988d2b16dd 100644 --- a/code/game/gamemodes/miniantags/slaughter/slaughter.dm +++ b/code/game/gamemodes/miniantags/slaughter/slaughter.dm @@ -193,10 +193,9 @@ return ..() /datum/action/innate/demon/whisper/proc/choose_targets(mob/user = usr)//yes i am copying from telepathy..hush... - var/list/targets = new /list() - var/list/validtargets = new /list() - for(var/mob/M in view(user.client.view, user)) - if(M && M.mind) + var/list/validtargets = list() + for(var/mob/living/M in view(user.client.view, get_turf(user))) + if(M && M.mind && M.stat != DEAD) if(M == user) continue @@ -206,15 +205,12 @@ to_chat(usr, "There are no valid targets!") return - targets += input("Choose the target to talk to.", "Targeting") as null|mob in validtargets - - if(!targets.len || !targets[1]) - return + var/mob/living/target = input("Choose the target to talk to.", "Targeting") as null|mob in validtargets + return target /datum/action/innate/demon/whisper/Activate() - var/list/choice = choose_targets() - - if(!choice.len) + var/mob/living/choice = choose_targets() + if(!choice) return var/msg = stripped_input(usr, "What do you wish to tell [choice]?", null, "") diff --git a/code/game/gamemodes/setupgame.dm b/code/game/gamemodes/setupgame.dm index c177e85f870..c785c511304 100644 --- a/code/game/gamemodes/setupgame.dm +++ b/code/game/gamemodes/setupgame.dm @@ -35,6 +35,7 @@ // Standard muts BLINDBLOCK = getAssignedBlock("BLIND", numsToAssign) + COLOURBLINDBLOCK = getAssignedBlock("COLOURBLIND", numsToAssign) DEAFBLOCK = getAssignedBlock("DEAF", numsToAssign) HULKBLOCK = getAssignedBlock("HULK", numsToAssign, DNA_HARD_BOUNDS, good=1) TELEBLOCK = getAssignedBlock("TELE", numsToAssign, DNA_HARD_BOUNDS, good=1) diff --git a/code/game/gamemodes/shadowling/shadowling_abilities.dm b/code/game/gamemodes/shadowling/shadowling_abilities.dm index fbfbbb12527..b04a3012fc3 100644 --- a/code/game/gamemodes/shadowling/shadowling_abilities.dm +++ b/code/game/gamemodes/shadowling/shadowling_abilities.dm @@ -84,8 +84,8 @@ P.visible_message("[P]'s light fades and turns off.") else if(istype(I, /obj/item/weapon/gun)) var/obj/item/weapon/gun/G = I - if(G.F) - var/obj/item/device/flashlight/F = G.F + if(G.gun_light) + var/obj/item/device/flashlight/F = G.gun_light if(F.on) G.toggle_gunlight() G.visible_message("[G]'s light fades and turns off.") diff --git a/code/game/gamemodes/vampire/vampire.dm b/code/game/gamemodes/vampire/vampire.dm index f37f846104a..f3dc8e4e41a 100644 --- a/code/game/gamemodes/vampire/vampire.dm +++ b/code/game/gamemodes/vampire/vampire.dm @@ -416,12 +416,7 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha owner.alpha = 255 return var/turf/simulated/T = get_turf(owner) - var/atom/movable/lighting_overlay/L = locate(/atom/movable/lighting_overlay) in T - var/light_available - if(L) - light_available = L.get_clamped_lum(0.5) * 10 - else - light_available = 10 + var/light_available = T.get_lumcount(0.5) * 10 if(!istype(T)) return 0 @@ -429,6 +424,7 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha if(!iscloaking) owner.alpha = 255 return 0 + if(light_available <= 2) owner.alpha = round((255 * 0.15)) return 1 diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm index 023fef59a7b..c38c50ad40a 100644 --- a/code/game/gamemodes/vampire/vampire_powers.dm +++ b/code/game/gamemodes/vampire/vampire_powers.dm @@ -479,8 +479,7 @@ if(T.y > world.maxy-outer_tele_radius || T.y < outer_tele_radius) continue - var/atom/movable/lighting_overlay/L = locate(/atom/movable/lighting_overlay) in T - var/lightingcount = L.get_clamped_lum(0.5) * 10 + var/lightingcount = T.get_lumcount(0.5) * 10 // LIGHTING CHECK if(lightingcount > max_lum) diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm index 18cc1d64b7d..7e9f98a64f2 100644 --- a/code/game/gamemodes/wizard/artefact.dm +++ b/code/game/gamemodes/wizard/artefact.dm @@ -786,6 +786,7 @@ var/global/list/multiverse = list() GiveHint(target) cooldown = world.time +cooldown_time return + if(!link) if(I.loc == user && istype(I) && I.w_class <= 2) user.drop_item() @@ -794,13 +795,17 @@ var/global/list/multiverse = list() to_chat(user, "You attach [I] to the doll.") update_targets() ..() + /obj/item/voodoo/check_eye(mob/user as mob) - return src.loc == user + if(loc != user) + user.reset_perspective(null) + user.unset_machine() /obj/item/voodoo/attack_self(mob/user as mob) if(!target && possible.len) target = input(user, "Select your victim!", "Voodoo") as null|anything in possible return + if(user.zone_sel.selecting == "chest") if(link) target = null @@ -809,6 +814,7 @@ var/global/list/multiverse = list() link = null update_targets() return + if(target && cooldown < world.time) switch(user.zone_sel.selecting) if("mouth") diff --git a/code/game/gamemodes/wizard/godhand.dm b/code/game/gamemodes/wizard/godhand.dm index 97770b47944..3340b044958 100644 --- a/code/game/gamemodes/wizard/godhand.dm +++ b/code/game/gamemodes/wizard/godhand.dm @@ -32,6 +32,11 @@ attached_spell.attached_hand = null qdel(src) +/obj/item/weapon/melee/touch_attack/dropped() + if(attached_spell) + attached_spell.attached_hand = null + qdel(src) + /obj/item/weapon/melee/touch_attack/disintegrate name = "disintegrating touch" desc = "This hand of mine glows with an awesome power!" diff --git a/code/game/gamemodes/wizard/rightandwrong.dm b/code/game/gamemodes/wizard/rightandwrong.dm index a8e449e1175..7145a414d7e 100644 --- a/code/game/gamemodes/wizard/rightandwrong.dm +++ b/code/game/gamemodes/wizard/rightandwrong.dm @@ -1,7 +1,7 @@ /mob/proc/rightandwrong(var/summon_type) //0 = Summon Guns, 1 = Summon Magic - var/list/gunslist = list("taser","egun","laser","revolver","detective","c20r","nuclear","deagle","gyrojet","pulse","suppressed","cannon","doublebarrel","shotgun","combatshotgun","bulldog","mateba","sabr","crossbow","saw","car","boltaction","arg","uzi","turret","pulsecarbine","decloner","mindflayer","hyperkinetic","advplasmacutter","wormhole","wt550","grenadelauncher","medibeam") + var/list/gunslist = list("taser","egun","laser","revolver","detective","c20r","nuclear","deagle","gyrojet","pulse","suppressed","cannon","doublebarrel","shotgun","combatshotgun","bulldog","mateba","sabr","crossbow","saw","car","boltaction","arg","uzi","turret","pulsecarbine","decloner","mindflayer","kinetic","advplasmacutter","wormhole","wt550","grenadelauncher","medibeam") var/list/magiclist = list("fireball","smoke","blind","mindswap","forcewall","knock","horsemask","charge", "summonitem", "wandnothing", "wanddeath", "wandresurrection", "wandpolymorph", "wandteleport", "wanddoor", "wandfireball", "staffhealing", "armor", "scrying", "staffdoor", "special","voodoo","special") var/list/magicspeciallist = list("staffchange","staffanimation", "wandbelt", "contract", "staffchaos","necromantic") @@ -76,8 +76,8 @@ new /obj/item/weapon/gun/energy/decloner(get_turf(H)) if("mindflayer") new /obj/item/weapon/gun/energy/mindflayer(get_turf(H)) - if("hyperkinetic") - new /obj/item/weapon/gun/energy/kinetic_accelerator/hyper(get_turf(H)) + if("kinetic") + new /obj/item/weapon/gun/energy/kinetic_accelerator(get_turf(H)) if("advplasmacutter") new /obj/item/weapon/gun/energy/plasmacutter/adv(get_turf(H)) if("wormhole") diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm index cddea783625..5a2d4ebb411 100644 --- a/code/game/gamemodes/wizard/soulstone.dm +++ b/code/game/gamemodes/wizard/soulstone.dm @@ -8,84 +8,118 @@ slot_flags = SLOT_BELT origin_tech = "bluespace=4;materials=4" var/imprinted = "empty" + + var/usability = TRUE // Can this soul stone be used by anyone, or only cultists/wizards? + var/reusable = TRUE // Can this soul stone be used more than once? + var/spent = FALSE // If the soul stone can only be used once, has it been used? +/obj/item/device/soulstone/proc/can_use(mob/living/user) + if(iscultist(user) || iswizard(user) || usability) + return TRUE -//////////////////////////////Capturing//////////////////////////////////////////////////////// + return FALSE + +/obj/item/device/soulstone/proc/was_used() + if(!reusable) + spent = TRUE + name = "dull [name]" + desc = "A fragment of the legendary treasure known simply as \ + the 'Soul Stone'. The shard lies still, dull and lifeless; \ + whatever spark it once held long extinguished." + +/obj/item/device/soulstone/anybody + usability = TRUE - attack(mob/living/carbon/human/M as mob, mob/user as mob) - if(!istype(M, /mob/living/carbon/human))//If target is not a human. - return ..() - if(istype(M, /mob/living/carbon/human/dummy)) - return ..() - - if(M.has_brain_worms()) //Borer stuff - RR - to_chat(user, "This being is corrupted by an alien intelligence and cannot be soul trapped.") - return ..() - - if(jobban_isbanned(M, "cultist") || jobban_isbanned(M, "Syndicate")) - to_chat(user, "A mysterious force prevents you from trapping this being's soul.") - return ..() - - M.create_attack_log("Has had their soul captured with [src.name] by [key_name(user)]") - user.create_attack_log("Used the [src.name] to capture the soul of [key_name(M)]") - - log_attack("[key_name(user)] used the [src.name] to capture the soul of [key_name(M)]") - - - transfer_soul("VICTIM", M, user) +/obj/item/device/soulstone/anybody/chaplain + name = "mysterious old shard" + reusable = FALSE + +/obj/item/device/soulstone/pickup(mob/living/user) + ..() + if(!can_use(user)) + to_chat(user, "An overwhelming feeling of dread comes over you as you pick up the soulstone. It would be wise to be rid of this quickly.") + user.Dizzy(120) + +//////////////////////////////Capturing//////////////////////////////////////////////////////// +/obj/item/device/soulstone/attack(mob/living/carbon/human/M as mob, mob/user as mob) + if(!can_use(user)) + user.Paralyse(5) + to_chat(user, "Your body is wracked with debilitating pain!") return - /*attack(mob/living/simple_animal/shade/M as mob, mob/user as mob)//APPARENTLY THEY NEED THEIR OWN SPECIAL SNOWFLAKE CODE IN THE LIVING ANIMAL DEFINES - if(!istype(M, /mob/living/simple_animal/shade))//If target is not a shade - return ..() - user.create_attack_log("Used the [src.name] to capture the soul of [M.name] ([M.ckey])") - - transfer_soul("SHADE", M, user) - return*/ -///////////////////Options for using captured souls/////////////////////////////////////// - - attack_self(mob/user) - if(!in_range(src, user)) - return - user.set_machine(src) - var/dat = "Soul Stone
" - for(var/mob/living/simple_animal/shade/A in src) - dat += "Captured Soul: [A.name]
" - dat += {"Summon Shade"} - dat += "
" - dat += {" Close"} - user << browse(dat, "window=aicard") - onclose(user, "aicard") + if(spent) + to_chat(user, "There is no power left in the shard.") return + if(!ishuman(M) || istype(M, /mob/living/carbon/human/dummy)) //If target is not a human or a dummy + return ..() + + if(M.has_brain_worms()) //Borer stuff - RR + to_chat(user, "This being is corrupted by an alien intelligence and cannot be soul trapped.") + return ..() + if(jobban_isbanned(M, "cultist") || jobban_isbanned(M, "Syndicate")) + to_chat(user, "A mysterious force prevents you from trapping this being's soul.") + return ..() + M.create_attack_log("Has had their soul captured with [src.name] by [key_name(user)]") + user.create_attack_log("Used the [src.name] to capture the soul of [key_name(M)]") + log_attack("[key_name(user)] used the [src.name] to capture the soul of [key_name(M)]") - Topic(href, href_list) - var/mob/U = usr - if(!in_range(src, U)||U.machine!=src) + transfer_soul("VICTIM", M, user) + return + +///////////////////Options for using captured souls/////////////////////////////////////// +/obj/item/device/soulstone/attack_self(mob/user) + if(!in_range(src, user)) + return + + if(!can_use(user)) + user.Paralyse(5) + to_chat(user, "Your body is wracked with debilitating pain!") + return + + user.set_machine(src) + var/dat = "Soul Stone
" + for(var/mob/living/simple_animal/shade/A in src) + dat += "Captured Soul: [A.name]
" + dat += {"Summon Shade"} + dat += "
" + dat += {" Close"} + user << browse(dat, "window=aicard") + onclose(user, "aicard") + return + +/obj/item/device/soulstone/Topic(href, href_list) + var/mob/U = usr + if(!in_range(src, U) || U.machine != src || !can_use(usr)) + U << browse(null, "window=aicard") + U.unset_machine() + return + + add_fingerprint(U) + U.set_machine(src) + + switch(href_list["choice"])//Now we switch based on choice. + if("Close") U << browse(null, "window=aicard") U.unset_machine() return - add_fingerprint(U) - U.set_machine(src) - - switch(href_list["choice"])//Now we switch based on choice. - if("Close") - U << browse(null, "window=aicard") - U.unset_machine() - return - - if("Summon") - for(var/mob/living/simple_animal/shade/A in src) - A.status_flags &= ~GODMODE - A.canmove = 1 - to_chat(A, "You have been released from your prison, but you are still bound to [U.name]'s will. Help them suceed in their goals at all costs.") - A.loc = U.loc - A.cancel_camera() - src.icon_state = "soulstone" - attack_self(U) + if("Summon") + for(var/mob/living/simple_animal/shade/A in src) + A.status_flags &= ~GODMODE + A.canmove = 1 + A.forceMove(get_turf(usr)) + A.cancel_camera() + icon_state = "soulstone" + name = initial(name) + if(iswizard(usr) || usability) + to_chat(A, "You have been released from your prison, but you are still bound to [usr.real_name]'s will. Help them succeed in their goals at all costs.") + else if(iscultist(usr)) + to_chat(A, "You have been released from your prison, but you are still bound to the cult's will. Help them succeed in their goals at all costs.") + was_used() + attack_self(U) ///////////////////////////Transferring to constructs///////////////////////////////////////////////////// /obj/structure/constructshell @@ -93,15 +127,30 @@ icon = 'icons/obj/wizard.dmi' icon_state = "construct" desc = "A wicked machine used by those skilled in magical arts. It is inactive" + +/obj/structure/constructshell/examine(mob/user) + if(..(user, 0)) + if(iscultist(user) || iswizard(user) || user.stat == DEAD) + to_chat(user, "A construct shell, used to house bound souls from a soulstone.") + to_chat(user, "Placing a soulstone with a soul into this shell allows you to produce your choice of the following:") + to_chat(user, "An Artificer, which can produce more shells and soulstones, as well as fortifications.") + to_chat(user, "A Wraith, which does high damage and can jaunt through walls, though it is quite fragile.") + to_chat(user, "A Juggernaut, which is very hard to kill and can produce temporary walls, but is slow.") /obj/structure/constructshell/attackby(obj/item/O as obj, mob/user as mob, params) if(istype(O, /obj/item/device/soulstone)) - O.transfer_soul("CONSTRUCT",src,user) - + var/obj/item/device/soulstone/SS = O + if(!SS.can_use(user)) + to_chat(user, "An overwhelming feeling of dread comes over you as you attempt to place the soulstone into the shell. It would be wise to be rid of this quickly.") + user.Dizzy(120) + return + SS.transfer_soul("CONSTRUCT",src,user) + SS.was_used() + else + return ..() ////////////////////////////Proc for moving soul in and out off stone////////////////////////////////////// - /obj/item/proc/transfer_soul(var/choice as text, var/target, var/mob/U as mob). switch(choice) if("FORCE") @@ -238,7 +287,6 @@ to_chat(newstruct, "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs.") newstruct.cancel_camera() - /obj/item/device/soulstone/proc/init_shade(mob/living/carbon/human/T, mob/U, vic = 0) new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton T.invisibility = 101 @@ -268,7 +316,6 @@ if(vic && U) to_chat(U, "Capture successful!: [T.real_name]'s soul has been ripped from their body and stored within the soul stone.") - /obj/item/device/soulstone/proc/getCultGhost(mob/living/carbon/human/T, mob/U) var/mob/dead/observer/chosen_ghost diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm index 5cc190f267b..3c59d47f020 100644 --- a/code/game/gamemodes/wizard/spellbook.dm +++ b/code/game/gamemodes/wizard/spellbook.dm @@ -848,7 +848,6 @@ to_chat(user, "[src] suddenly vanishes!") qdel(src) - /obj/item/weapon/spellbook/oneuse/fake_gib spell = /obj/effect/proc_holder/spell/targeted/touch/fake_disintegrate spellname = "disintegrate" diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm index f7b793b6033..4f9e357cd61 100644 --- a/code/game/machinery/adv_med.dm +++ b/code/game/machinery/adv_med.dm @@ -453,6 +453,7 @@ occupantData["intOrgan"] = intOrganData occupantData["blind"] = (H.disabilities & BLIND) + occupantData["colourblind"] = (H.disabilities & COLOURBLIND) occupantData["nearsighted"] = (H.disabilities & NEARSIGHTED) data["occupant"] = occupantData @@ -639,6 +640,8 @@ dat += "" if(occupant.disabilities & BLIND) dat += "Cataracts detected.
" + if(occupant.disabilities & COLOURBLIND) + dat += "Photoreceptor abnormalities detected.
" if(occupant.disabilities & NEARSIGHTED) dat += "Retinal misalignment detected.
" else diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index 26344ec96f1..ed322d99564 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -117,9 +117,9 @@ var/global/list/image/splatter_cache=list() user.hand_blood_color = basecolor user.update_inv_gloves(1) user.verbs += /mob/living/carbon/human/proc/bloody_doodle - + /obj/effect/decal/cleanable/blood/can_bloodcrawl_in() - return amount + return TRUE /obj/effect/decal/cleanable/blood/splatter random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5") diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm index 140c013b270..0bb6278c0bc 100644 --- a/code/game/objects/effects/overlays.dm +++ b/code/game/objects/effects/overlays.dm @@ -113,6 +113,18 @@ layer = 4.1 duration = 4 +/obj/effect/overlay/temp/explosion + name = "explosion" + icon = 'icons/effects/96x96.dmi' + icon_state = "explosion" + pixel_x = -32 + pixel_y = -32 + duration = 8 + +/obj/effect/overlay/temp/explosion/fast + icon_state = "explosionfast" + duration = 4 + /obj/effect/overlay/temp/decoy desc = "It's a decoy!" duration = 15 diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm index 546db62032c..b9804e7d9a5 100644 --- a/code/game/objects/effects/spawners/lootdrop.dm +++ b/code/game/objects/effects/spawners/lootdrop.dm @@ -194,6 +194,6 @@ /obj/item/weapon/stock_parts/scanning_module = 1, /obj/item/weapon/spacecash/c200 = 1, /obj/item/weapon/airlock_electronics = 1, - /obj/item/weapon/gun/energy/kinetic_accelerator/super = 1, + /obj/item/weapon/gun/energy/kinetic_accelerator = 1, /obj/item/pizzabox = 3, ) diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 7806982a627..216c37e7a51 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -54,8 +54,8 @@ return var/mob/living/carbon/human/H = M //mob has protective eyewear - if(istype(M, /mob/living/carbon/human) && ((H.head && H.head.flags & HEADCOVERSEYES) || (H.wear_mask && H.wear_mask.flags & MASKCOVERSEYES) || (H.glasses && H.glasses.flags & GLASSESCOVERSEYES))) - to_chat(user, "You're going to need to remove that [(H.head && H.head.flags & HEADCOVERSEYES) ? "helmet" : (H.wear_mask && H.wear_mask.flags & MASKCOVERSEYES) ? "mask": "glasses"] first.") + if(istype(H) && ((H.head && H.head.flags & HEADCOVERSEYES) || (H.wear_mask && H.wear_mask.flags & MASKCOVERSEYES) || (H.glasses && H.glasses.flags & GLASSESCOVERSEYES))) + to_chat(user, "You're going to need to remove that [(H.head && H.head.flags & HEADCOVERSEYES) ? "helmet" : (H.wear_mask && H.wear_mask.flags & MASKCOVERSEYES) ? "mask" : "glasses"] first.") return if(M == user) //they're using it on themselves @@ -70,12 +70,13 @@ user.visible_message("[user] directs [src] to [M]'s eyes.", \ "You direct [src] to [M]'s eyes.") - if(istype(M, /mob/living/carbon/human)) //robots and aliens are unaffected - if(M.stat == DEAD || M.disabilities & BLIND) //mob is dead or fully blind - to_chat(user, "[M] pupils does not react to the light!") - else if(XRAY in M.mutations) //mob has X-RAY vision - to_chat(user, "[M] pupils give an eerie glow!") - else //they're okay! + if(istype(H)) //robots and aliens are unaffected + var/obj/item/organ/internal/eyes/eyes = H.get_int_organ(/obj/item/organ/internal/eyes) + if(M.stat == DEAD || !eyes || M.disabilities & BLIND) //mob is dead or fully blind + to_chat(user, "[M]'s pupils are unresponsive to the light!") + else if((XRAY in M.mutations) || (eyes.colourblind_darkview && eyes.colourblind_darkview == eyes.get_dark_view())) //The mob's either got the X-RAY vision or has a tapetum lucidum (extreme nightvision, i.e. Vulp/Tajara with COLOURBLIND & their monkey forms). + to_chat(user, "[M]'s pupils glow eerily!") + else //they're okay! if(M.flash_eyes(visual = 1)) to_chat(user, "[M]'s pupils narrow.") else diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index bd6f3acfdee..40cc65da34a 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -196,25 +196,6 @@ return 1 -/obj/item/borg/upgrade/hyperka - name = "mining cyborg hyper-kinetic accelerator" - desc = "A satchel of holding replacement for mining cyborg's ore satchel module." - icon_state = "cyborg_upgrade3" - require_module = 1 - module_type = /obj/item/weapon/robot_module/miner - -/obj/item/borg/upgrade/hyperka/action(mob/living/silicon/robot/R) - if(..()) - return - - for(var/obj/item/weapon/gun/energy/kinetic_accelerator/cyborg/H in R.module.modules) - qdel(H) - - R.module.modules += new /obj/item/weapon/gun/energy/kinetic_accelerator/hyper/cyborg(R.module) - R.module.rebuild() - - return 1 - /obj/item/borg/upgrade/syndicate name = "illegal equipment module" desc = "Unlocks the hidden, deadlier functions of a cyborg" diff --git a/code/game/objects/items/weapons/powerfist.dm b/code/game/objects/items/weapons/powerfist.dm index eefd3b7d0f6..0167ab589be 100644 --- a/code/game/objects/items/weapons/powerfist.dm +++ b/code/game/objects/items/weapons/powerfist.dm @@ -87,7 +87,7 @@ target.apply_damage(force * fisto_setting, BRUTE) target.visible_message("[user]'s powerfist lets out a loud hiss as they punch [target.name]!", \ "You cry out in pain as [user]'s punch flings you backwards!") - new/obj/effect/kinetic_blast(target.loc) + new /obj/effect/overlay/temp/kinetic_blast(target.loc) playsound(loc, 'sound/weapons/resonator_blast.ogg', 50, 1) playsound(loc, 'sound/weapons/genhit2.ogg', 50, 1) diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index 0e6be05df88..3c8a25ca739 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -23,18 +23,14 @@ slot_flags = SLOT_BELT force = 2 throwforce = 1 - sharp = 1 - edge = 1 w_class = 3 + hitsound = 'sound/weapons/bladeslice.ogg' attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - suicide_act(mob/user) - to_chat(viewers(user), "[user] is impaling \himself with the [src.name]! It looks like \he's trying to commit suicide.") - return(BRUTELOSS) - -/obj/item/weapon/sord/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) - playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1, -1) - return ..() +/obj/item/weapon/sord/suicide_act(mob/user) + user.visible_message("[user] is trying to impale themself with [src]! It might be a suicide attempt if it weren't so shitty.", \ + "You try to impale yourself with [src], but it's USELESS...") + return SHAME /obj/item/weapon/claymore name = "claymore" diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 9bc6d5fec8f..23f5330e48a 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -3,7 +3,7 @@ /obj/structure/closet/crate name = "crate" desc = "A rectangular steel crate." - icon = 'icons/obj/storage.dmi' + icon = 'icons/obj/crates.dmi' icon_state = "crate" icon_opened = "crateopen" icon_closed = "crate" @@ -490,7 +490,6 @@ /obj/structure/closet/crate/large name = "large crate" desc = "A hefty metal crate." - icon = 'icons/obj/storage.dmi' icon_state = "largemetal" icon_opened = "largemetalopen" icon_closed = "largemetal" @@ -515,7 +514,6 @@ /obj/structure/closet/crate/secure/large name = "large crate" desc = "A hefty metal crate with an electronic locking system." - icon = 'icons/obj/storage.dmi' icon_state = "largemetal" icon_opened = "largemetalopen" icon_closed = "largemetal" diff --git a/code/game/objects/structures/crates_lockers/largecrate.dm b/code/game/objects/structures/crates_lockers/largecrate.dm index d19600989be..4fe6715a05a 100644 --- a/code/game/objects/structures/crates_lockers/largecrate.dm +++ b/code/game/objects/structures/crates_lockers/largecrate.dm @@ -1,8 +1,8 @@ /obj/structure/largecrate name = "large crate" desc = "A hefty wooden crate." - icon = 'icons/obj/storage.dmi' - icon_state = "densecrate" + icon = 'icons/obj/crates.dmi' + icon_state = "largecrate" density = 1 var/obj/item/weapon/paper/manifest/manifest @@ -49,7 +49,6 @@ return attack_hand(user) /obj/structure/largecrate/mule - icon_state = "mulecrate" /obj/structure/largecrate/lisa icon_state = "lisacrate" diff --git a/code/game/objects/structures/curtains.dm b/code/game/objects/structures/curtains.dm index 9d7bbc96e1b..104fac7fd69 100644 --- a/code/game/objects/structures/curtains.dm +++ b/code/game/objects/structures/curtains.dm @@ -27,7 +27,7 @@ ..() /obj/structure/curtain/proc/toggle() - opacity = !opacity + set_opacity(!opacity) if(opacity) icon_state = "closed" layer = SHOWER_CLOSED_LAYER diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index b9af7b2d032..824759b35cb 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -191,7 +191,7 @@ Close() ..() - opacity = 0 + set_opacity(0) /obj/structure/mineral_door/transparent/plasma mineralType = "plasma" @@ -228,7 +228,7 @@ flick("[mineralType]opening",src) sleep(10) density = 0 - opacity = 0 + set_opacity(0) state = 1 update_icon() isSwitchingStates = 0 @@ -239,7 +239,7 @@ flick("[mineralType]closing",src) sleep(10) density = 1 - opacity = 1 + set_opacity(1) state = 0 update_icon() isSwitchingStates = 0 @@ -265,7 +265,7 @@ flick("[mineralType]opening",src) sleep(10) density = 0 - opacity = 0 + set_opacity(0) state = 1 update_icon() isSwitchingStates = 0 @@ -280,7 +280,7 @@ flick("[mineralType]closing",src) sleep(10) density = 1 - opacity = 1 + set_opacity(1) state = 0 update_icon() isSwitchingStates = 0 diff --git a/code/game/objects/structures/spirit_board.dm b/code/game/objects/structures/spirit_board.dm index 25fe7f4a134..253f93dc7ae 100644 --- a/code/game/objects/structures/spirit_board.dm +++ b/code/game/objects/structures/spirit_board.dm @@ -55,11 +55,10 @@ //lighting check var/light_amount = 0 var/turf/T = get_turf(src) - var/atom/movable/lighting_overlay/LO = locate(/atom/movable/lighting_overlay) in T - if(LO) - light_amount = LO.get_clamped_lum(0.5)*10 + if(T) + light_amount = T.get_lumcount(0.5) * 10 else - light_amount = 10 + light_amount = 10 if(light_amount > 2) to_chat(M, "It's too bright here to use [src.name]!") diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index ba5ced7723c..69b0df22ae3 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -24,8 +24,6 @@ var/PathNode/PNode = null //associated PathNode in the A* algorithm - var/dynamic_lighting = 1 - flags = 0 var/image/obscured //camerachunks @@ -161,10 +159,11 @@ return src var/old_opacity = opacity var/old_dynamic_lighting = dynamic_lighting - var/list/old_affecting_lights = affecting_lights + var/old_affecting_lights = affecting_lights var/old_lighting_overlay = lighting_overlay var/old_blueprint_data = blueprint_data var/old_obscured = obscured + var/old_corners = corners BeforeChange() if(air_master) @@ -178,16 +177,19 @@ for(var/turf/space/S in range(W,1)) S.update_starlight() - lighting_overlay = old_lighting_overlay + recalc_atom_opacity() - affecting_lights = old_affecting_lights - if((old_opacity != opacity) || (dynamic_lighting != old_dynamic_lighting)) - reconsider_lights() - if(dynamic_lighting != old_dynamic_lighting) - if(dynamic_lighting) - lighting_build_overlays() - else - lighting_clear_overlays() + if(lighting_overlays_initialised) + lighting_overlay = old_lighting_overlay + affecting_lights = old_affecting_lights + corners = old_corners + if((old_opacity != opacity) || (dynamic_lighting != old_dynamic_lighting)) + reconsider_lights() + if(dynamic_lighting != old_dynamic_lighting) + if(dynamic_lighting) + lighting_build_overlay() + else + lighting_clear_overlay() obscured = old_obscured @@ -384,11 +386,6 @@ if(ticker) cameranet.updateVisibility(src) -/turf/proc/get_lumcount() //Gets the lighting level of a given turf. - if(lighting_overlay) - return lighting_overlay.get_clamped_lum() - return 1 - /turf/attackby(obj/item/C, mob/user, params) if(can_lay_cable() && istype(C, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/coil = C diff --git a/code/game/verbs/suicide.dm b/code/game/verbs/suicide.dm index 31c8c322596..896bd2b850d 100644 --- a/code/game/verbs/suicide.dm +++ b/code/game/verbs/suicide.dm @@ -77,6 +77,10 @@ if(held_item) var/damagetype = held_item.suicide_act(src) if(damagetype) + if(damagetype & SHAME) + adjustStaminaLoss(200) + suiciding = 0 + return do_suicide(damagetype, held_item) return diff --git a/code/modules/admin/buildmode.dm b/code/modules/admin/buildmode.dm index 3acc106b907..32bdfa135b5 100644 --- a/code/modules/admin/buildmode.dm +++ b/code/modules/admin/buildmode.dm @@ -447,7 +447,7 @@ new/obj/machinery/door/airlock(get_turf(object)) else if(istype(object,/turf) && ctrl_click && left_click) var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object)) - WIN.set_dir(build_dir) + WIN.setDir(build_dir) log_admin("Build Mode: [key_name(user)] built a window at ([object.x],[object.y],[object.z])") if(ADV_BUILDMODE) @@ -458,7 +458,7 @@ T.ChangeTurf(objholder) else var/obj/A = new objholder (get_turf(object)) - A.set_dir(build_dir) + A.setDir(build_dir) log_admin("Build Mode: [key_name(user)] modified [A]'s ([A.x],[A.y],[A.z]) dir to [build_dir]") else if(right_click) if(isobj(object)) @@ -547,7 +547,7 @@ T.ChangeTurf(objholder) else var/obj/A = new objholder(T) - A.set_dir(build_dir) + A.setDir(build_dir) deselect_region() return diff --git a/code/modules/awaymissions/mission_code/clownplanet.dm b/code/modules/awaymissions/mission_code/clownplanet.dm index 359037ada0a..8d64d3074d2 100644 --- a/code/modules/awaymissions/mission_code/clownplanet.dm +++ b/code/modules/awaymissions/mission_code/clownplanet.dm @@ -4,10 +4,10 @@ name = "\improper Clown Planet" icon_state = "honk" luminosity = 1 - lighting_use_dynamic = 0 + dynamic_lighting = 0 requires_power = 0 report_alerts = 0 - + /area/awaymission/clownplanet/miningtown name = "\improper Clown Planet - Bananium-o-Rama" icon_state = "away1" diff --git a/code/modules/awaymissions/zlevel.dm b/code/modules/awaymissions/zlevel.dm index f5b951eb627..d340fc6a651 100644 --- a/code/modules/awaymissions/zlevel.dm +++ b/code/modules/awaymissions/zlevel.dm @@ -13,13 +13,6 @@ var/global/list/potentialRandomZlevels = generateMapList(filename = "config/away air_master.setup_allturfs(turfs) log_debug("\tTook [stop_watch(subtimer)]s") - subtimer = start_watch() - log_debug("Initializing lighting") - for(var/turf/T in turfs) - if(T.dynamic_lighting) - T.lighting_build_overlays() - log_debug("\tTook [stop_watch(subtimer)]s") - subtimer = start_watch() log_debug("Smoothing tiles") for(var/turf/T in smoothTurfs) diff --git a/code/modules/awaymissions/zvis.dm b/code/modules/awaymissions/zvis.dm index 06d60f3389f..735dd307ddb 100644 --- a/code/modules/awaymissions/zvis.dm +++ b/code/modules/awaymissions/zvis.dm @@ -1,7 +1,7 @@ /area/awaymission/upperlevel name = "Open Space" color = "#888" - lighting_use_dynamic = 0 + dynamic_lighting = 0 requires_power = 0 // Used by /turf/unsimulated/floor/upperlevel as a reference for where the other floor is diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 6e1fe9126fd..8f8d26efebe 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -232,6 +232,10 @@ to_chat(src, "Become a BYOND member to access member-perks and features, as well as support the engine that makes this game possible. Click here to find out more.") return 0 return 1 + +//Like for /atoms, but clients are their own snowflake FUCK +/client/proc/setDir(newdir) + dir = newdir /client/proc/handle_spam_prevention(var/message, var/mute_type, var/throttle = 0) if(throttle) @@ -621,3 +625,6 @@ if(lang.flags & RESTRICTED) message += " (RESTRICTED)" to_chat(world, "[message]") + +/client/proc/colour_transition(var/list/colour_to = null, var/time = 10) //Call this with no parameters to reset to default. + animate(src, color=colour_to, time=time, easing=SINE_EASING) diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index c9b3127094b..764e88f02fa 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -817,6 +817,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts HTML += ShowDisabilityState(user,DISABILITY_FLAG_EPILEPTIC,"Seizures") HTML += ShowDisabilityState(user,DISABILITY_FLAG_DEAF,"Deaf") HTML += ShowDisabilityState(user,DISABILITY_FLAG_BLIND,"Blind") + HTML += ShowDisabilityState(user,DISABILITY_FLAG_COLOURBLIND,"Colourblind") HTML += ShowDisabilityState(user,DISABILITY_FLAG_MUTE,"Mute") @@ -1339,9 +1340,8 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts //Reset prosthetics. organ_data = list() rlimb_data = list() - if("speciesprefs")//oldvox code - speciesprefs = !speciesprefs - + if("speciesprefs") + speciesprefs = !speciesprefs //Starts 0, so if someone clicks the button up top there, this won't be 0 anymore. If they click it again, it'll go back to 0. if("language") // var/languages_available var/list/new_languages = list("None") @@ -2168,6 +2168,9 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts if(disabilities & DISABILITY_FLAG_BLIND) character.dna.SetSEState(BLINDBLOCK,1,1) + if(disabilities & DISABILITY_FLAG_COLOURBLIND) + character.dna.SetSEState(COLOURBLINDBLOCK,1,1) + if(disabilities & DISABILITY_FLAG_MUTE) character.dna.SetSEState(MUTEBLOCK,1,1) diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm index 4fde338ba54..00bd068e067 100644 --- a/code/modules/clothing/glasses/glasses.dm +++ b/code/modules/clothing/glasses/glasses.dm @@ -232,8 +232,6 @@ name = "noir sunglasses" desc = "Somehow these seem even more out-of-date than normal sunglasses." actions_types = list(/datum/action/item_action/noir) - var/noir_mode = 0 - color_view = MATRIX_GREYSCALE /obj/item/clothing/glasses/sunglasses/noir/attack_self() toggle_noir() @@ -243,36 +241,8 @@ return 1 /obj/item/clothing/glasses/sunglasses/noir/proc/toggle_noir() - var/list/difference = difflist(usr.client.color, color_view) - - if(!noir_mode) - if(color_view && usr.client && (!usr.client.color || difference)) - animate(usr.client, color = color_view, time = 10) - noir_mode = 1 - else - if(usr.client && usr.client.color && !difference) - animate(usr.client, color = initial(usr.client.color), time = 10) - noir_mode = 0 - -/obj/item/clothing/glasses/sunglasses/noir/equipped(mob/user, slot) - var/list/difference = difflist(user.client.color, color_view) - - if(slot == slot_glasses) - if(noir_mode) - if(color_view && user.client && (!user.client.color || difference.len)) - animate(user.client, color = color_view, time = 10) - else - if(user.client && user.client.color && !difference.len) - animate(user.client, color = initial(user.client.color), time = 10) - ..(user, slot) - -/obj/item/clothing/glasses/sunglasses/noir/dropped(mob/living/carbon/human/user) - var/list/difference = difflist(user.client.color, color_view) - - if(istype(user) && user.glasses == src) - if(user.client && user.client.color && !difference.len) - animate(user.client, color = initial(user.client.color), time = 10) - ..(user) + color_view = color_view ? null : MATRIX_GREYSCALE //Toggles between null and grayscale, with null being the default option. + usr.update_client_colour() /obj/item/clothing/glasses/sunglasses/yeah name = "agreeable glasses" @@ -498,3 +468,28 @@ name = "gar glasses" icon_state = "gar" item_state = "gar" + +/obj/item/clothing/glasses/godeye + name = "eye of god" + desc = "A strange eye, said to have been torn from an omniscient creature that used to roam the wastes." + icon_state = "godeye" + item_state = "godeye" + vision_flags = SEE_TURFS|SEE_MOBS|SEE_OBJS + darkness_view = 8 + scan_reagents = 1 + flags = NODROP + invis_view = SEE_INVISIBLE_MINIMUM + +/obj/item/clothing/glasses/godeye/attackby(obj/item/weapon/W as obj, mob/user as mob, params) + if(istype(W, src) && W != src && W.loc == user) + if(W.icon_state == "godeye") + W.icon_state = "doublegodeye" + W.item_state = "doublegodeye" + W.desc = "A pair of strange eyes, said to have been torn from an omniscient creature that used to roam the wastes. There's no real reason to have two, but that isn't stopping you." + if(iscarbon(user)) + var/mob/living/carbon/C = user + C.update_inv_wear_mask() + else + to_chat(user, "The eye winks at you and vanishes into the abyss, you feel really unlucky.") + qdel(src) + ..() \ No newline at end of file diff --git a/code/modules/clothing/spacesuits/ert.dm b/code/modules/clothing/spacesuits/ert.dm index d5c4d5626bb..6e484d27ff7 100644 --- a/code/modules/clothing/spacesuits/ert.dm +++ b/code/modules/clothing/spacesuits/ert.dm @@ -7,20 +7,21 @@ armor = list(melee = 45, bullet = 25, laser = 30, energy = 10, bomb = 25, bio = 100, rad = 50) rig_restrict_helmet = 0 // ERT helmets can be taken on and off at will. var/obj/machinery/camera/camera + var/has_camera = TRUE strip_delay = 130 /obj/item/clothing/head/helmet/space/rig/ert/attack_self(mob/user) - if(camera) + if(camera || !has_camera) ..(user) else camera = new /obj/machinery/camera(src) camera.network = list("ERT") cameranet.removeCamera(camera) camera.c_tag = user.name - to_chat(user, "\blue User scanned as [camera.c_tag]. Camera activated.") + to_chat(user, "User scanned as [camera.c_tag]. Camera activated.") /obj/item/clothing/head/helmet/space/rig/ert/examine(mob/user) - if(..(user, 1)) + if(..(user, 1) && has_camera) to_chat(user, "This helmet has a built-in camera. It's [camera ? "" : "in"]active.") /obj/item/clothing/suit/space/rig/ert @@ -101,6 +102,7 @@ desc = "A suit worn by the janitorial of a Nanotrasen Emergency Response Team. Has purple highlights. Armoured, space ready, and fire resistant." icon_state = "ert_janitor" +//Paranormal /obj/item/clothing/head/helmet/space/rig/ert/paranormal name = "paranormal response unit helmet" desc = "A helmet worn by those who deal with paranormal threats for a living." @@ -108,16 +110,39 @@ item_color = "ert_paranormal" max_heat_protection_temperature = FIRE_IMMUNITY_HELM_MAX_TEMP_PROTECT sprite_sheets = null + icon_override = 'icons/mob/clothing/paranormal_hardsuit.dmi' + actions_types = list() + has_camera = 0 /obj/item/clothing/suit/space/rig/ert/paranormal name = "paranormal response team suit" desc = "Powerful wards are built into this hardsuit, protecting the user from all manner of paranormal threats." - icon_state = "knight_grey" - item_state = "knight_grey" + icon_state = "rig-paranormal" max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT sprite_sheets = null - + icon_override = 'icons/mob/clothing/paranormal_hardsuit.dmi' + actions_types = list() /obj/item/clothing/suit/space/rig/ert/paranormal/New() ..() new /obj/item/weapon/nullrod(src) + +/obj/item/clothing/head/helmet/space/rig/ert/paranormal/inquisitor + name = "inquisitor's helmet" + icon_state = "rig0-inquisitor" + item_color = "inquisitor" + +/obj/item/clothing/suit/space/rig/ert/paranormal/inquisitor + name = "inquisitor's hardsuit" + icon_state = "rig-inquisitor" + +/obj/item/clothing/head/helmet/space/rig/ert/paranormal/berserker + name = "champion's helmet" + desc = "Peering into the eyes of the helmet is enough to seal damnation." + icon_state = "rig0-berserker" + item_color = "berserker" + +/obj/item/clothing/suit/space/rig/ert/paranormal/berserker + name = "champion's hardsuit" + desc = "Voices echo from the hardsuit, driving the user insane." + icon_state = "rig-berserker" \ No newline at end of file diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm index deaa1b85aa8..90889ef7eba 100644 --- a/code/modules/events/event_container.dm +++ b/code/modules/events/event_container.dm @@ -101,8 +101,13 @@ var/list/event_last_fired = list() playercount_modifier = 1 if(26 to 35) playercount_modifier = 0.9 - if(36 to 100000) + if(36 to 50) playercount_modifier = 0.8 + if(50 to 80) + playercount_modifier = 0.7 + if(80 to 10000) + playercount_modifier = 0.6 + playercount_modifier = playercount_modifier * delay_modifier var/event_delay = rand(config.event_delay_lower[severity], config.event_delay_upper[severity]) * playercount_modifier @@ -155,6 +160,7 @@ var/list/event_last_fired = list() new /datum/event_meta(EVENT_LEVEL_MODERATE, "Spider Infestation", /datum/event/spider_infestation, 100, list(ASSIGNMENT_SECURITY = 30), 1), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Ion Storm", /datum/event/ion_storm, 0, list(ASSIGNMENT_AI = 50, ASSIGNMENT_CYBORG = 50, ASSIGNMENT_ENGINEER = 15, ASSIGNMENT_SCIENTIST = 5)), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Borer Infestation", /datum/event/borer_infestation, 40, list(ASSIGNMENT_SECURITY = 30), 1), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Immovable Rod", /datum/event/immovable_rod, 0, list(ASSIGNMENT_ENGINEER = 30), 1), //new /datum/event_meta/ninja(EVENT_LEVEL_MODERATE, "Space Ninja", /datum/event/space_ninja, 0, list(ASSIGNMENT_SECURITY = 15), 1), // NON-BAY EVENTS new /datum/event_meta(EVENT_LEVEL_MODERATE, "Mass Hallucination", /datum/event/mass_hallucination, 300), @@ -170,7 +176,7 @@ var/list/event_last_fired = list() new /datum/event_meta(EVENT_LEVEL_MODERATE, "Gravitational Anomaly", /datum/event/anomaly/anomaly_grav, 200), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Revenant", /datum/event/revenant, 150), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Swarmer Spawn", /datum/event/spawn_swarmer, 150, is_one_shot = 1), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Morph Spawn", /datum/event/spawn_morph, 0, is_one_shot = 1), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Morph Spawn", /datum/event/spawn_morph, 40, is_one_shot = 1), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Disease Outbreak", /datum/event/disease_outbreak, 0, list(ASSIGNMENT_MEDICAL = 150), 1) ) @@ -185,6 +191,7 @@ var/list/event_last_fired = list() new /datum/event_meta(EVENT_LEVEL_MAJOR, "Abductor Visit", /datum/event/abductor, 80, is_one_shot = 1), new /datum/event_meta/alien(EVENT_LEVEL_MAJOR, "Alien Infestation", /datum/event/alien_infestation, 0, list(ASSIGNMENT_SECURITY = 30), 1), new /datum/event_meta(EVENT_LEVEL_MAJOR, "Traders", /datum/event/traders, 0, is_one_shot = 1), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Slaughter Demon", /datum/event/spawn_slaughter, 15, is_one_shot = 1), ) diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index f7c48c88e23..2dc2c8a17dd 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -34,10 +34,19 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 loc = start z_original = z destination = end + notify_ghosts("\A [src] is inbound!", + enter_link="(Click to follow)", + source=src, action=NOTIFY_FOLLOW) poi_list |= src if(end && end.z==z_original) walk_towards(src, destination, 1) - + +/obj/effect/immovablerod/Topic(href, href_list) + if(href_list["follow"]) + var/mob/dead/observer/ghost = usr + if(istype(ghost)) + ghost.ManualFollow(src) + /obj/effect/immovablerod/Destroy() poi_list.Remove(src) return ..() @@ -70,4 +79,4 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 H.adjustBruteLoss(160) if(clong.density || prob(10)) clong.ex_act(2) - return + return \ No newline at end of file diff --git a/code/modules/events/slaughterevent.dm b/code/modules/events/slaughterevent.dm index 3a7464baa8c..f46ebcfd605 100644 --- a/code/modules/events/slaughterevent.dm +++ b/code/modules/events/slaughterevent.dm @@ -37,8 +37,8 @@ player_mind.transfer_to(S) player_mind.assigned_role = "Slaughter Demon" player_mind.special_role = SPECIAL_ROLE_SLAUGHTER_DEMON - message_admins("[key_of_slaughter] has been made into a Slaughter Demon by an event.") - log_game("[key_of_slaughter] was spawned as a Slaughter Demon by an event.") + message_admins("[key_name_admin(S)] has been made into a Slaughter Demon by an event.") + log_game("[key_name_admin(S)] was spawned as a Slaughter Demon by an event.") return 1 /datum/event/spawn_slaughter/start() diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm index 3c694f993cf..936b9e30827 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm @@ -20,6 +20,8 @@ var/locked = 0 var/scan_id = 1 var/is_secure = 0 + var/can_dry = FALSE + var/drying = FALSE var/datum/wires/smartfridge/wires = null /obj/machinery/smartfridge/New() @@ -195,7 +197,7 @@ /obj/machinery/smartfridge/default_deconstruction_screwdriver(mob/user, obj/item/weapon/screwdriver/S) . = ..(user, icon_state, icon_state, S) - + overlays.Cut() if(panel_open) overlays += image(icon, "[initial(icon_state)]-panel") @@ -332,6 +334,8 @@ data["shoot_inventory"] = shoot_inventory data["locked"] = locked data["secure"] = is_secure + data["can_dry"] = can_dry + data["drying"] = drying var/list/items[0] for(var/i=1 to length(item_quants)) @@ -372,6 +376,7 @@ for(var/obj/O in contents) if(O.name == K) O.forceMove(loc) + update_icon() i-- if(i <= 0) return 1 @@ -394,6 +399,7 @@ if(T.name == O) T.forceMove(loc) throw_item = T + update_icon() break break if(!throw_item) @@ -416,7 +422,7 @@ active_power_usage = 200 icon_on = "drying_rack_on" icon_off = "drying_rack" - var/drying = FALSE + can_dry = TRUE /obj/machinery/smartfridge/drying_rack/New() ..() @@ -443,6 +449,22 @@ /obj/machinery/smartfridge/drying_rack/default_deconstruction_crowbar(obj/item/weapon/crowbar/C, ignore_panel = 1) ..() +/obj/machinery/smartfridge/drying_rack/Topic(href, href_list) + if(..()) + return 1 + if(href_list["dryingOn"]) + drying = TRUE + use_power = 2 + update_icon() + return 1 + + if(href_list["dryingOff"]) + drying = FALSE + use_power = 1 + update_icon() + return 1 + return 0 + /obj/machinery/smartfridge/drying_rack/power_change() if(powered() && anchored) stat &= ~NOPOWER @@ -451,9 +473,10 @@ toggle_drying(TRUE) update_icon() -/obj/machinery/smartfridge/drying_rack/load() //For updating the filled overlay - ..() - update_icon() +/obj/machinery/smartfridge/drying_rack/load(obj/I, mob/user) //For updating the filled overlay + if(..()) + update_icon() + return 1 /obj/machinery/smartfridge/drying_rack/update_icon() ..() @@ -470,11 +493,11 @@ update_icon() /obj/machinery/smartfridge/drying_rack/accept_check(obj/item/O) - if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/)) + if(istype(O, /obj/item/weapon/reagent_containers/food/snacks)) var/obj/item/weapon/reagent_containers/food/snacks/S = O if(S.dried_type) return TRUE - if(istype(O,/obj/item/stack/sheet/wetleather/)) + if(istype(O, /obj/item/stack/sheet/wetleather)) return TRUE return FALSE @@ -492,16 +515,21 @@ if(S.dried_type == S.type)//if the dried type is the same as the object's type, don't bother creating a whole new item... S.color = "#ad7257" S.dry = TRUE + item_quants[S.name]-- S.forceMove(get_turf(src)) else var/dried = S.dried_type new dried(loc) + item_quants[S.name]-- qdel(S) + nanomanager.update_uis(src) return TRUE for(var/obj/item/stack/sheet/wetleather/WL in contents) var/obj/item/stack/sheet/leather/L = new(loc) L.amount = WL.amount + item_quants[WL.name]-- qdel(WL) + nanomanager.update_uis(src) return TRUE return FALSE @@ -509,21 +537,6 @@ ..() atmos_spawn_air(SPAWN_HEAT) -/obj/machinery/smartfridge/drying_rack/verb/adjust_drying() - set category = "Object" - set name = "Toggle Drying" - set src in view(1) - - if(!iscarbon(usr)) - to_chat(usr, "You can't do that!") - return - - if(usr.incapacitated()) - return - - toggle_drying(FALSE) - update_icon() - /************************ * Secure SmartFridges *************************/ diff --git a/code/modules/hydroponics/grown/mushrooms.dm b/code/modules/hydroponics/grown/mushrooms.dm index 0588bdef455..346e8344ca9 100644 --- a/code/modules/hydroponics/grown/mushrooms.dm +++ b/code/modules/hydroponics/grown/mushrooms.dm @@ -74,7 +74,7 @@ growthstages = 3 genes = list(/datum/plant_gene/trait/plant_type/fungal_metabolism) growing_icon = 'icons/obj/hydroponics/growing_mushrooms.dmi' - reagents_add = list("psilocybin" = 0.04, "amanitin" = 0.1, "nutriment" = 0, "amanitin" = 0.2) + reagents_add = list("psilocybin" = 0.04, "nutriment" = 0, "amanitin" = 0.3) rarity = 30 origin_tech = "biotech=5" @@ -291,4 +291,4 @@ name = "fungus" desc = "A fungus ideal for making antibacterials." icon_state = "angel" - color = "#4f4331" \ No newline at end of file + color = "#4f4331" diff --git a/code/modules/lighting/light_source.dm b/code/modules/lighting/light_source.dm deleted file mode 100644 index fd92e6675f1..00000000000 --- a/code/modules/lighting/light_source.dm +++ /dev/null @@ -1,257 +0,0 @@ -/datum/light_source - var/atom/top_atom - var/atom/source_atom - - var/turf/source_turf - var/light_power - var/light_range - var/light_color // string, decomposed by parse_light_color() - - var/lum_r - var/lum_g - var/lum_b - - var/tmp/applied_lum_r - var/tmp/applied_lum_g - var/tmp/applied_lum_b - - var/list/effect_str - var/list/effect_turf - - var/applied - - var/vis_update //Whetever we should smartly recalculate visibility. and then only update tiles that became (in) visible to us - var/needs_update - var/destroyed - var/force_update - -/datum/light_source/New(atom/owner, atom/top) - source_atom = owner - if(!source_atom.light_sources) source_atom.light_sources = list() - source_atom.light_sources += src - top_atom = top - if(top_atom != source_atom) - if(!top.light_sources) top.light_sources = list() - top_atom.light_sources += src - - source_turf = top_atom - light_power = source_atom.light_power - light_range = source_atom.light_range - light_color = source_atom.light_color - - parse_light_color() - - effect_str = list() - effect_turf = list() - - update() - - return ..() - -/datum/light_source/proc/destroy() - destroyed = 1 - force_update() - if(source_atom && source_atom.light_sources) source_atom.light_sources -= src - if(top_atom && top_atom.light_sources) top_atom.light_sources -= src - -/datum/light_source/proc/update(atom/new_top_atom) - if(new_top_atom && new_top_atom != top_atom) - if(top_atom != source_atom) top_atom.light_sources -= src - top_atom = new_top_atom - if(top_atom != source_atom) - if(!top_atom.light_sources) top_atom.light_sources = list() - top_atom.light_sources += src - - if(!needs_update) //Incase we're already updating either way. - lighting_update_lights += src - needs_update = 1 - -/datum/light_source/proc/force_update() - force_update = 1 - if(!needs_update) //Incase we're already updating either way. - needs_update = 1 - lighting_update_lights += src - -/datum/light_source/proc/vis_update() - if(!needs_update) - needs_update = 1 - lighting_update_lights += src - - vis_update = 1 - -/datum/light_source/proc/check() - if(!source_atom || !light_range || !light_power) - destroy() - return 1 - - if(!top_atom) - top_atom = source_atom - . = 1 - - if(istype(top_atom, /turf)) - if(source_turf != top_atom) - source_turf = top_atom - . = 1 - else if(top_atom.loc != source_turf) - source_turf = top_atom.loc - . = 1 - - if(source_atom.light_power != light_power) - light_power = source_atom.light_power - . = 1 - - if(source_atom.light_range != light_range) - light_range = source_atom.light_range - . = 1 - - if(light_range && light_power && !applied) - . = 1 - - if(source_atom.light_color != light_color) - light_color = source_atom.light_color - parse_light_color() - . = 1 - -/datum/light_source/proc/parse_light_color() - if(light_color) - lum_r = color2R(light_color) / 255 - lum_g = color2G(light_color) / 255 - lum_b = color2B(light_color) / 255 - else - lum_r = 1 - lum_g = 1 - lum_b = 1 - -#if LIGHTING_FALLOFF == 1 //circular - #define LUM_DISTANCE(swapvar, O, T) swapvar = (O.x - T.x)**2 + (O.y - T.y)**2 + LIGHTING_HEIGHT - #if LIGHTING_LAMBERTIAN == 1 - #define LUM_ATTENUATION(swapvar) swapvar = CLAMP01((1 - CLAMP01(sqrt(swapvar) / max(1,light_range))) * (1 / sqrt(swapvar + 1))) - #else - #define LUM_ATTENUATION(swapvar) swapvar = 1 - CLAMP01(sqrt(swapvar) / max(1,light_range)) - #endif -#elif LIGHTING_FALLOFF == 2 //square - #define LUM_DISTANCE(swapvar, O, T) swapvar = abs(O.x - T.x) + abs(O.y - T.y) + LIGHTING_HEIGHT - #if LIGHTING_LAMBERTIAN == 1 - #define LUM_ATTENUATION(swapvar) swapvar = CLAMP01((1 - CLAMP01(swapvar / max(1,light_range))) * (1 / sqrt(swapvar**2 + 1))) - #else - #define LUM_ATTENUATION(swapvar) swapvar = CLAMP01(swapvar / max(1,light_range)) - #endif -#endif - -#define LUM_FALLOFF(swapvar, O, T) \ - LUM_DISTANCE(swapvar, O, T); \ - LUM_ATTENUATION(swapvar); - -/datum/light_source/proc/apply_lum() - applied = 1 - - // Cache the applied lum counts. - applied_lum_r = lum_r - applied_lum_g = lum_g - applied_lum_b = lum_b - - if(istype(source_turf)) - FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING) - if(T.lighting_overlay) - var/strength - LUM_FALLOFF(strength, T, source_turf) - strength *= light_power - - if(!strength) //Don't add turfs that aren't affected to the affected turfs. - continue - - strength = round(strength, LIGHTING_ROUND_VALUE) //Screw sinking points. - - effect_str += strength - - T.lighting_overlay.update_lumcount( - lum_r * strength, - lum_g * strength, - lum_b * strength - ) - - else - effect_str += 0 - - if(!T.affecting_lights) - T.affecting_lights = list() - - T.affecting_lights += src - effect_turf += T - END_FOR_DVIEW - -/datum/light_source/proc/remove_lum() - applied = 0 - var/i = 1 - for(var/turf/T in effect_turf) - if(T.affecting_lights) - T.affecting_lights -= src - - if(T.lighting_overlay) - var/str = effect_str[i] - T.lighting_overlay.update_lumcount(-str * applied_lum_r, -str * applied_lum_g, -str * applied_lum_b) - - i++ - - effect_str.Cut() - effect_turf.Cut() - -/datum/light_source/proc/forget_turf(turf/T) - var/idx = effect_turf.Find(T) - effect_turf.Cut(idx, idx + 1) - effect_str.Cut(idx, idx + 1) - -//Smartly updates the lighting, only removes lum from and adds lum to turfs that actually got changed. -//This is for lights that need to reconsider due to nearby opacity changes. -//Stupid dumb copy pasta because BYOND and speed. -/datum/light_source/proc/smart_vis_update() - var/list/view[0] - FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING) - view += T //Filter out turfs. - END_FOR_DVIEW - //This is the part where we calculate new turfs (if any) - var/list/new_turfs = view - effect_turf //This will result with all the tiles that are added. - for(var/turf/T in new_turfs) - if(T.lighting_overlay) - LUM_FALLOFF(., T, source_turf) - . *= light_power - - if(!.) //Don't add turfs that aren't affected to the affected turfs. - continue - - . = round(., LIGHTING_ROUND_VALUE) - - effect_str += . - - T.lighting_overlay.update_lumcount( - lum_r * ., - lum_g * ., - lum_b * . - ) - - else - effect_str += 0 - - if(!T.affecting_lights) - T.affecting_lights = list() - - T.affecting_lights += src - effect_turf += T - - var/list/old_turfs = effect_turf - view - for(var/turf/T in old_turfs) - //Insert not-so-huge copy paste from remove_lum(). - var/idx = effect_turf.Find(T) //Get the index, luckily Find() is cheap in small lists like this. (with small I mean under a couple thousand len) - if(T.affecting_lights) - T.affecting_lights -= src - - if(T.lighting_overlay) - var/str = effect_str[idx] - T.lighting_overlay.update_lumcount(-str * lum_r, -str * lum_g, -str * lum_b) - - effect_turf.Cut(idx, idx + 1) - effect_str.Cut(idx, idx + 1) - -#undef LUM_FALLOFF -#undef LUM_DISTANCE -#undef LUM_ATTENUATION \ No newline at end of file diff --git a/code/modules/lighting/lighting_area.dm b/code/modules/lighting/lighting_area.dm new file mode 100644 index 00000000000..92923e6b0d5 --- /dev/null +++ b/code/modules/lighting/lighting_area.dm @@ -0,0 +1,9 @@ +/area + luminosity = TRUE + var/dynamic_lighting = TRUE + +/area/New() + . = ..() + + if(dynamic_lighting) + luminosity = FALSE \ No newline at end of file diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm index 92500ecc1d9..679f6fb86ef 100644 --- a/code/modules/lighting/lighting_atom.dm +++ b/code/modules/lighting/lighting_atom.dm @@ -1,19 +1,30 @@ /atom var/light_power = 1 // intensity of the light var/light_range = 0 // range in tiles of the light - var/light_color // RGB string representing the colour of the light + var/light_color // Hexadecimal RGB string representing the colour of the light var/datum/light_source/light var/list/light_sources -/atom/proc/set_light(l_range, l_power, l_color) - if(l_power != null) light_power = l_power - if(l_range != null) light_range = l_range - if(l_color != null) light_color = l_color +// Nonsensical value for l_color default, so we can detect if it gets set to null. +#define NONSENSICAL_VALUE -99999 +/atom/proc/set_light(l_range, l_power, l_color = NONSENSICAL_VALUE) + if(l_power != null) + light_power = l_power + + if(l_range != null) + light_range = l_range + + if(l_color != NONSENSICAL_VALUE) + light_color = l_color update_light() +#undef NONSENSICAL_VALUE + /atom/proc/update_light() + set waitfor = FALSE + if(!light_power || !light_range) if(light) light.destroy() @@ -31,9 +42,14 @@ /atom/New() . = ..() + if(light_power && light_range) update_light() + if(opacity && isturf(loc)) + var/turf/T = loc + T.has_opaque_atom = TRUE // No need to recalculate it in this case, it's guranteed to be on afterwards anyways. + /atom/Destroy() if(light) light.destroy() @@ -62,11 +78,22 @@ new_loc.reconsider_lights() /atom/proc/set_opacity(new_opacity) - var/old_opacity = opacity + if(new_opacity == opacity) + return + opacity = new_opacity var/turf/T = loc - if(old_opacity != new_opacity && istype(T)) + if(!isturf(T)) + return + + if(new_opacity == TRUE) + T.has_opaque_atom = TRUE T.reconsider_lights() + else + var/old_has_opaque_atom = T.has_opaque_atom + T.recalc_atom_opacity() + if(old_has_opaque_atom != T.has_opaque_atom) + T.reconsider_lights() /obj/item/equipped() . = ..() diff --git a/code/modules/lighting/lighting_corner.dm b/code/modules/lighting/lighting_corner.dm new file mode 100644 index 00000000000..a464f5af2d0 --- /dev/null +++ b/code/modules/lighting/lighting_corner.dm @@ -0,0 +1,125 @@ +/var/list/datum/lighting_corner/all_lighting_corners = list() +/var/datum/lighting_corner/dummy/dummy_lighting_corner = new +// Because we can control each corner of every lighting overlay. +// And corners get shared between multiple turfs (unless you're on the corners of the map, then 1 corner doesn't). +// For the record: these should never ever ever be deleted, even if the turf doesn't have dynamic lighting. + +// This list is what the code that assigns corners listens to, the order in this list is the order in which corners are added to the /turf/corners list. +/var/list/LIGHTING_CORNER_DIAGONAL = list(NORTHEAST, SOUTHEAST, SOUTHWEST, NORTHWEST) + +/datum/lighting_corner + var/list/turf/masters = list() + var/list/datum/light_source/affecting = list() // Light sources affecting us. + var/active = FALSE // TRUE if one of our masters has dynamic lighting. + + var/x = 0 + var/y = 0 + var/z = 0 + + var/lum_r = 0 + var/lum_g = 0 + var/lum_b = 0 + + var/needs_update = FALSE + + var/cache_r = LIGHTING_SOFT_THRESHOLD + var/cache_g = LIGHTING_SOFT_THRESHOLD + var/cache_b = LIGHTING_SOFT_THRESHOLD + var/cache_mx = 0 + + var/update_gen = 0 + +/datum/lighting_corner/New(var/turf/new_turf, var/diagonal) + . = ..() + + all_lighting_corners += src + + masters[new_turf] = turn(diagonal, 180) + z = new_turf.z + + var/vertical = diagonal & ~(diagonal - 1) // The horizontal directions (4 and 8) are bigger than the vertical ones (1 and 2), so we can reliably say the lsb is the horizontal direction. + var/horizontal = diagonal & ~vertical // Now that we know the horizontal one we can get the vertical one. + + x = new_turf.x + (horizontal == EAST ? 0.5 : -0.5) + y = new_turf.y + (vertical == NORTH ? 0.5 : -0.5) + + // My initial plan was to make this loop through a list of all the dirs (horizontal, vertical, diagonal). + // Issue being that the only way I could think of doing it was very messy, slow and honestly overengineered. + // So we'll have this hardcode instead. + var/turf/T + var/i + + // Diagonal one is easy. + T = get_step(new_turf, diagonal) + if (T) // In case we're on the map's border. + if (!T.corners) + T.corners = list(null, null, null, null) + + masters[T] = diagonal + i = LIGHTING_CORNER_DIAGONAL.Find(turn(diagonal, 180)) + T.corners[i] = src + + // Now the horizontal one. + T = get_step(new_turf, horizontal) + if (T) // Ditto. + if (!T.corners) + T.corners = list(null, null, null, null) + + masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates. + i = LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180)) + T.corners[i] = src + + // And finally the vertical one. + T = get_step(new_turf, vertical) + if (T) + if (!T.corners) + T.corners = list(null, null, null, null) + + masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates. + i = LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180)) + T.corners[i] = src + + update_active() + +/datum/lighting_corner/proc/update_active() + active = FALSE + for (var/turf/T in masters) + if (T.lighting_overlay) + active = TRUE + +// God that was a mess, now to do the rest of the corner code! Hooray! +/datum/lighting_corner/proc/update_lumcount(var/delta_r, var/delta_g, var/delta_b) + lum_r += delta_r + lum_g += delta_g + lum_b += delta_b + + if (!needs_update) + needs_update = TRUE + lighting_update_corners += src + +/datum/lighting_corner/proc/update_overlays() + + // Cache these values a head of time so 4 individual lighting overlays don't all calculate them individually. + var/mx = max(lum_r, lum_g, lum_b) // Scale it so 1 is the strongest lum, if it is above 1. + . = 1 // factor + if (mx > 1) + . = 1 / mx + + else if (mx < LIGHTING_SOFT_THRESHOLD) + . = 0 // 0 means soft lighting. + + cache_r = lum_r * . || LIGHTING_SOFT_THRESHOLD + cache_g = lum_g * . || LIGHTING_SOFT_THRESHOLD + cache_b = lum_b * . || LIGHTING_SOFT_THRESHOLD + cache_mx = mx + + for (var/TT in masters) + var/turf/T = TT + if (T.lighting_overlay) + if (!T.lighting_overlay.needs_update) + T.lighting_overlay.needs_update = TRUE + lighting_update_overlays += T.lighting_overlay + + +/datum/lighting_corner/dummy/New() + return diff --git a/code/modules/lighting/lighting_overlay.dm b/code/modules/lighting/lighting_overlay.dm index 24854085c1a..7c2e1a55842 100644 --- a/code/modules/lighting/lighting_overlay.dm +++ b/code/modules/lighting/lighting_overlay.dm @@ -1,3 +1,4 @@ +var/list/all_lighting_overlays = list() // Global list of lighting overlays. /atom/movable/lighting_overlay name = "" mouse_opacity = 0 @@ -6,90 +7,75 @@ icon = LIGHTING_ICON layer = LIGHTING_LAYER invisibility = INVISIBILITY_LIGHTING - color = "#000000" + color = LIGHTING_BASE_MATRIX icon_state = "light1" auto_init = 0 // doesn't need special init + blend_mode = BLEND_MULTIPLY - var/lum_r - var/lum_g - var/lum_b + var/lum_r = 0 + var/lum_g = 0 + var/lum_b = 0 - var/needs_update + var/needs_update = FALSE -/atom/movable/lighting_overlay/New() +/atom/movable/lighting_overlay/New(var/atom/loc, var/no_update = FALSE) . = ..() verbs.Cut() + global.all_lighting_overlays += src var/turf/T = loc //If this runtimes atleast we'll know what's creating overlays outside of turfs. + T.lighting_overlay = src T.luminosity = 0 - -/atom/movable/lighting_overlay/proc/get_clamped_lum(var/minlum = 0, var/maxlum = 1) - var/lum = max(lum_r, lum_g, lum_b) - if(lum <= minlum) - return 0 - else if(lum >= maxlum) - return 1 - else - return (lum - minlum) / (maxlum - minlum) - -/atom/movable/lighting_overlay/proc/update_lumcount(delta_r, delta_g, delta_b) - if(!delta_r && !delta_g && !delta_b) //Nothing is being changed all together. + if(no_update) return - - var/should_update = 0 - - if(!needs_update) //If this isn't true, we're already updating anyways. - if(max(lum_r, lum_g, lum_b) < 1) //Any change that could happen WILL change appearance. - should_update = 1 - - else if(max(lum_r + delta_r, lum_g + delta_g, lum_b + delta_b) < 1) //The change would bring us under 1 max lum, again, guaranteed to change appearance. - should_update = 1 - - else //We need to make sure that the colour ratios won't change in this code block. - var/mx1 = max(lum_r, lum_g, lum_b) - var/mx2 = max(lum_r + delta_r, lum_g + delta_g, lum_b + delta_b) - - if(lum_r / mx1 != (lum_r + delta_r) / mx2 || lum_g / mx1 != (lum_g + delta_g) / mx2 || lum_b / mx1 != (lum_b + delta_b) / mx2) //Stuff would change. - should_update = 1 - - lum_r = max(lum_r + delta_r, 0) //Lum shouldn't drop below 1 - lum_g = max(lum_g + delta_g, 0) - lum_b = max(lum_b + delta_b, 0) - - if(!needs_update && should_update) - needs_update = 1 - lighting_update_overlays += src + update_overlay() /atom/movable/lighting_overlay/proc/update_overlay() + set waitfor = FALSE var/turf/T = loc - if(istype(T)) //Incase we're not on a turf, pool ourselves, something happened. - if(lum_r == lum_g && lum_r == lum_b) //greyscale - blend_mode = BLEND_OVERLAY - if(lum_r <= 0) - T.luminosity = 0 - color = "#000000" - alpha = 255 - else - T.luminosity = 1 - color = "#000000" - alpha = (1 - min(lum_r, 1)) * 255 + if(!istype(T)) + if(loc) + log_debug("A lighting overlay realised its loc was NOT a turf (actual loc: [loc][loc ? ", " + loc.type : "null"]) in update_overlay() and got qdel'ed!") else - alpha = 255 - var/mx = max(lum_r, lum_g, lum_b) - . = 1 // factor - if(mx > 1) - . = 1/mx - blend_mode = BLEND_MULTIPLY - color = rgb(lum_r * 255 * ., lum_g * 255 * ., lum_b * 255 * .) - if(color != "#000000") - T.luminosity = 1 - else //No light, set the turf's luminosity to 0 to remove it from view() - T.luminosity = 0 - else - //warning("A lighting overlay realised its loc was NOT a turf (actual loc: [loc][loc ? ", " + loc.type : "null"]) in update_overlay() and got qdel'ed!") //fucking bullshit bugs means this spams when shuttles move, feel free to fix - log_debug("A lighting overlay realised its loc was NOT a turf (actual loc: [loc][loc ? ", " + loc.type : "null"]) in update_overlay() and got qdel'ed!") + log_debug("A lighting overlay realised it was in nullspace in update_overlay() and got pooled!") qdel(src) + return + + // To the future coder who sees this and thinks + // "Why didn't he just use a loop?" + // Well my man, it's because the loop performed like shit. + // And there's no way to improve it because + // without a loop you can make the list all at once which is the fastest you're gonna get. + // Oh it's also shorter line wise. + // Including with these comments. + + // See LIGHTING_CORNER_DIAGONAL in lighting_corner.dm for why these values are what they are. + // No I seriously cannot think of a more efficient method, fuck off Comic. + var/datum/lighting_corner/cr = T.corners[3] || dummy_lighting_corner + var/datum/lighting_corner/cg = T.corners[2] || dummy_lighting_corner + var/datum/lighting_corner/cb = T.corners[4] || dummy_lighting_corner + var/datum/lighting_corner/ca = T.corners[1] || dummy_lighting_corner + + var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx) + + var/list/new_matrix = list( + cr.cache_r, cr.cache_g, cr.cache_b, 0, + cg.cache_r, cg.cache_g, cg.cache_b, 0, + cb.cache_r, cb.cache_g, cb.cache_b, 0, + ca.cache_r, ca.cache_g, ca.cache_b, 0, + 0, 0, 0, 1 + ) + var/lum = max > LIGHTING_SOFT_THRESHOLD + + if(lum) + luminosity = 1 + animate(src, color = new_matrix, time = 5) + else + animate(src, color = new_matrix, time = 5) + animate(luminosity = 0, time = 0) + + /atom/movable/lighting_overlay/singularity_act() return @@ -98,10 +84,13 @@ return /atom/movable/lighting_overlay/Destroy() - lighting_update_overlays -= src + global.all_lighting_overlays -= src + global.lighting_update_overlays -= src + global.lighting_update_overlays_old -= src var/turf/T = loc if(istype(T)) T.lighting_overlay = null + T.luminosity = 1 return ..() diff --git a/code/modules/lighting/lighting_process.dm b/code/modules/lighting/lighting_process.dm deleted file mode 100644 index 916920393ba..00000000000 --- a/code/modules/lighting/lighting_process.dm +++ /dev/null @@ -1,35 +0,0 @@ -/datum/controller/process/lighting - var/last_light_count = 0 - var/last_overlay_count = 0 - -/datum/controller/process/lighting/doWork() - var/list/lighting_update_lights_old = lighting_update_lights //We use a different list so any additions to the update lists during a delay from SCHECK don't cause things to be cut from the list without being updated. - last_light_count = lighting_update_lights.len - lighting_update_lights = null //Nulling it first because of http://www.byond.com/forum/?post=1854520 - lighting_update_lights = list() - - for(var/datum/light_source/L in lighting_update_lights_old) - if(L.destroyed || L.check() || L.force_update) - L.remove_lum() - if(!L.destroyed) - L.apply_lum() - - else if(L.vis_update) //We smartly update only tiles that became (in) visible to use. - L.smart_vis_update() - - L.vis_update = 0 - L.force_update = 0 - L.needs_update = 0 - - SCHECK - - var/list/lighting_update_overlays_old = lighting_update_overlays //Same as above. - last_overlay_count = lighting_update_overlays.len - lighting_update_overlays = null //Same as above - lighting_update_overlays = list() - - for(var/atom/movable/lighting_overlay/O in lighting_update_overlays_old) - O.update_overlay() - O.needs_update = 0 - - SCHECK diff --git a/code/modules/lighting/lighting_setup.dm b/code/modules/lighting/lighting_setup.dm new file mode 100644 index 00000000000..981de658649 --- /dev/null +++ b/code/modules/lighting/lighting_setup.dm @@ -0,0 +1,16 @@ +/proc/create_all_lighting_overlays() + for(var/zlevel = 1 to world.maxz) + create_lighting_overlays_zlevel(zlevel) + +/proc/create_lighting_overlays_zlevel(var/zlevel) + ASSERT(zlevel) + + for(var/turf/T in block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel))) + if(!T.dynamic_lighting) + continue + + var/area/A = T.loc + if(!A.dynamic_lighting) + continue + + new /atom/movable/lighting_overlay(T, TRUE) diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm new file mode 100644 index 00000000000..c26522dc5a7 --- /dev/null +++ b/code/modules/lighting/lighting_source.dm @@ -0,0 +1,283 @@ +// This is where the fun begins. +// These are the main datums that emit light. + +/datum/light_source + var/atom/top_atom // The atom we're emitting light from(for example a mob if we're from a flashlight that's being held). + var/atom/source_atom // The atom that we belong to. + + var/turf/source_turf // The turf under the above. + var/light_power // Intensity of the emitter light. + var/light_range // The range of the emitted light. + var/light_color // The colour of the light, string, decomposed by parse_light_color() + + // Variables for keeping track of the colour. + var/lum_r + var/lum_g + var/lum_b + + // The lumcount values used to apply the light. + var/tmp/applied_lum_r + var/tmp/applied_lum_g + var/tmp/applied_lum_b + + var/list/datum/lighting_corner/effect_str // List used to store how much we're affecting corners. + var/list/turf/affecting_turfs + + var/applied = FALSE // Whether we have applied our light yet or not. + + var/vis_update // Whether we should smartly recalculate visibility. and then only update tiles that became(in)visible to us. + var/needs_update // Whether we are queued for an update. + var/destroyed // Whether we are destroyed and need to stop emitting light. + var/force_update + +/datum/light_source/New(var/atom/owner, var/atom/top) + source_atom = owner // Set our new owner. + if(!source_atom.light_sources) + source_atom.light_sources = list() + + source_atom.light_sources += src // Add us to the lights of our owner. + top_atom = top + if(top_atom != source_atom) + if(!top.light_sources) + top.light_sources = list() + + top_atom.light_sources += src + + source_turf = top_atom + light_power = source_atom.light_power + light_range = source_atom.light_range + light_color = source_atom.light_color + + parse_light_color() + + effect_str = list() + affecting_turfs = list() + + update() + + return ..() + +// Kill ourselves. +/datum/light_source/proc/destroy() + destroyed = TRUE + force_update() + if(source_atom) + source_atom.light_sources -= src + + if(top_atom) + top_atom.light_sources -= src + +// Call it dirty, I don't care. +// This is here so there's no performance loss on non-instant updates from the fact that the engine can also do instant updates. +// If you're wondering what's with the "BYOND" argument: BYOND won't let me have a() macro that has no arguments :|. +#define effect_update(BYOND) \ + if(!needs_update) \ + { \ + lighting_update_lights += src; \ + needs_update = TRUE; \ + } + +// This proc will cause the light source to update the top atom, and add itself to the update queue. +/datum/light_source/proc/update(var/atom/new_top_atom) + // This top atom is different. + if(new_top_atom && new_top_atom != top_atom) + if(top_atom != source_atom) // Remove ourselves from the light sources of that top atom. + top_atom.light_sources -= src + + top_atom = new_top_atom + + if(top_atom != source_atom) + if(!top_atom.light_sources) + top_atom.light_sources = list() + + top_atom.light_sources += src // Add ourselves to the light sources of our new top atom. + + effect_update(null) + +// Will force an update without checking if it's actually needed. +/datum/light_source/proc/force_update() + force_update = 1 + + effect_update(null) + +// Will cause the light source to recalculate turfs that were removed or added to visibility only. +/datum/light_source/proc/vis_update() + vis_update = 1 + + effect_update(null) + +// Will check if we actually need to update, and update any variables that may need to be updated. +/datum/light_source/proc/check() + if(!source_atom || !light_range || !light_power) + destroy() + return 1 + + if(!top_atom) + top_atom = source_atom + . = 1 + + if(isturf(top_atom)) + if(source_turf != top_atom) + source_turf = top_atom + . = 1 + else if(top_atom.loc != source_turf) + source_turf = top_atom.loc + . = 1 + + if(source_atom.light_power != light_power) + light_power = source_atom.light_power + . = 1 + + if(source_atom.light_range != light_range) + light_range = source_atom.light_range + . = 1 + + if(light_range && light_power && !applied) + . = 1 + + if(source_atom.light_color != light_color) + light_color = source_atom.light_color + parse_light_color() + . = 1 + +// Decompile the hexadecimal colour into lumcounts of each perspective. +/datum/light_source/proc/parse_light_color() + if(light_color) + lum_r = GetRedPart (light_color) / 255 + lum_g = GetGreenPart(light_color) / 255 + lum_b = GetBluePart (light_color) / 255 + else + lum_r = 1 + lum_g = 1 + lum_b = 1 + +// Macro that applies light to a new corner. +// It is a macro in the interest of speed, yet not having to copy paste it. +// If you're wondering what's with the backslashes, the backslashes cause BYOND to not automatically end the line. +// As such this all gets counted as a single line. +// The braces and semicolons are there to be able to do this on a single line. + +#define APPLY_CORNER(C) \ + . = LUM_FALLOFF(C, source_turf); \ + \ + . *= light_power; \ + \ + effect_str[C] = .; \ + \ + C.update_lumcount \ + ( \ + . * applied_lum_r, \ + . * applied_lum_g, \ + . * applied_lum_b \ + ); + +// I don't need to explain what this does, do I? +#define REMOVE_CORNER(C) \ + . = -effect_str[C]; \ + C.update_lumcount \ + ( \ + . * applied_lum_r, \ + . * applied_lum_g, \ + . * applied_lum_b \ + ); + +// This is the define used to calculate falloff. +#define LUM_FALLOFF(C, T)(1 - CLAMP01(sqrt((C.x - T.x) ** 2 +(C.y - T.y) ** 2 + LIGHTING_HEIGHT) / max(1, light_range))) + +/datum/light_source/proc/apply_lum() + var/static/update_gen = 1 + applied = 1 + + // Keep track of the last applied lum values so that the lighting can be reversed + applied_lum_r = lum_r + applied_lum_g = lum_g + applied_lum_b = lum_b + + FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING) + if(!T.lighting_corners_initialised) + T.generate_missing_corners() + + for(var/datum/lighting_corner/C in T.get_corners()) + if(C.update_gen == update_gen) + continue + + C.update_gen = update_gen + C.affecting += src + + if(!C.active) + effect_str[C] = 0 + continue + + APPLY_CORNER(C) + + if(!T.affecting_lights) + T.affecting_lights = list() + + T.affecting_lights += src + affecting_turfs += T + + update_gen++ + +/datum/light_source/proc/remove_lum() + applied = FALSE + + for(var/turf/T in affecting_turfs) + if(!T.affecting_lights) + T.affecting_lights = list() + else + T.affecting_lights -= src + + affecting_turfs.Cut() + + for(var/datum/lighting_corner/C in effect_str) + REMOVE_CORNER(C) + + C.affecting -= src + + effect_str.Cut() + +/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/C) + if(effect_str.Find(C)) // Already have one. + REMOVE_CORNER(C) + + APPLY_CORNER(C) + +/datum/light_source/proc/smart_vis_update() + var/list/datum/lighting_corner/corners = list() + var/list/turf/turfs = list() + FOR_DVIEW(var/turf/T, light_range, source_turf, 0) + if(!T.lighting_corners_initialised) + T.generate_missing_corners() + corners |= T.get_corners() + turfs += T + + var/list/L = turfs - affecting_turfs // New turfs, add us to the affecting lights of them. + affecting_turfs += L + for(var/turf/T in L) + if(!T.affecting_lights) + T.affecting_lights = list(src) + else + T.affecting_lights += src + + L = affecting_turfs - turfs // Now-gone turfs, remove us from the affecting lights. + affecting_turfs -= L + for(var/turf/T in L) + T.affecting_lights -= src + + for(var/datum/lighting_corner/C in corners - effect_str) // New corners + C.affecting += src + if(!C.active) + effect_str[C] = 0 + continue + + APPLY_CORNER(C) + + for(var/datum/lighting_corner/C in effect_str - corners) // Old, now gone, corners. + REMOVE_CORNER(C) + C.affecting -= src + effect_str -= C + +#undef effect_update +#undef LUM_FALLOFF +#undef REMOVE_CORNER +#undef APPLY_CORNER diff --git a/code/modules/lighting/lighting_system.dm b/code/modules/lighting/lighting_system.dm deleted file mode 100644 index bdad6316395..00000000000 --- a/code/modules/lighting/lighting_system.dm +++ /dev/null @@ -1,25 +0,0 @@ -/var/list/lighting_update_lights = list() -/var/list/lighting_update_overlays = list() - -/area/var/lighting_use_dynamic = 1 - -// duplicates lots of code, but this proc needs to be as fast as possible. -/proc/create_lighting_overlays(zlevel = 0) - var/area/A - if(zlevel == 0) // populate all zlevels - for(var/turf/T in world) - if(T.dynamic_lighting) - A = T.loc - if(A.lighting_use_dynamic) - var/atom/movable/lighting_overlay/O = new(T) - T.lighting_overlay = O - - else - for(var/x = 1; x <= world.maxx; x++) - for(var/y = 1; y <= world.maxy; y++) - var/turf/T = locate(x, y, zlevel) - if(T.dynamic_lighting) - A = T.loc - if(A.lighting_use_dynamic) - var/atom/movable/lighting_overlay/O = new(T) - T.lighting_overlay = O \ No newline at end of file diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index 53d9ab0455c..ddb934aed61 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -1,26 +1,102 @@ /turf - var/list/affecting_lights - var/atom/movable/lighting_overlay/lighting_overlay + var/dynamic_lighting = TRUE + luminosity = 1 + var/tmp/lighting_corners_initialised = FALSE + + var/tmp/list/datum/light_source/affecting_lights // List of light sources affecting this turf. + var/tmp/atom/movable/lighting_overlay/lighting_overlay // Our lighting overlay. + var/tmp/list/datum/lighting_corner/corners + var/tmp/has_opaque_atom = FALSE // Not to be confused with opacity, this will be TRUE if there's any opaque atom on the tile. + +/turf/New() + . = ..() + + if(opacity) + has_opaque_atom = TRUE + +// Causes any affecting light sources to be queued for a visibility update, for example a door got opened. /turf/proc/reconsider_lights() for(var/datum/light_source/L in affecting_lights) L.vis_update() -/turf/proc/lighting_clear_overlays() +/turf/proc/lighting_clear_overlay() if(lighting_overlay) qdel(lighting_overlay) -/turf/proc/lighting_build_overlays() + for(var/datum/lighting_corner/C in corners) + C.update_active() + +// Builds a lighting overlay for us, but only if our area is dynamic. +/turf/proc/lighting_build_overlay() if(lighting_overlay) return var/area/A = loc - if(A.lighting_use_dynamic) - var/atom/movable/lighting_overlay/O = new(src) - lighting_overlay = O - // forcibly refresh lighting on this tile - // must make light forget tile or it wil remain - // convinced that it is already lighting it - for(var/datum/light_source/L in affecting_lights) - L.forget_turf(src) - L.vis_update() \ No newline at end of file + if(A.dynamic_lighting) + if(!lighting_corners_initialised) + generate_missing_corners() + + new /atom/movable/lighting_overlay(src) + + for(var/datum/lighting_corner/C in corners) + if(!C.active) // We would activate the corner, calculate the lighting for it. + for(var/L in C.affecting) + var/datum/light_source/S = L + S.recalc_corner(C) + + C.active = TRUE + +// Used to get a scaled lumcount. +/turf/proc/get_lumcount(var/minlum = 0, var/maxlum = 1) + if(!lighting_overlay) + return 1 + + var/totallums = 0 + for(var/datum/lighting_corner/L in corners) + totallums += max(L.lum_r, L.lum_g, L.lum_b) + + totallums /= 4 // 4 corners, max channel selected, return the average + + totallums =(totallums - minlum) /(maxlum - minlum) + + return CLAMP01(totallums) + +// Can't think of a good name, this proc will recalculate the has_opaque_atom variable. +/turf/proc/recalc_atom_opacity() + has_opaque_atom = FALSE + for(var/atom/A in src.contents + src) // Loop through every movable atom on our tile PLUS ourselves (we matter too...) + if(A.opacity) + has_opaque_atom = TRUE + +// If an opaque movable atom moves around we need to potentially update visibility. +/turf/Entered(var/atom/movable/Obj, var/atom/OldLoc) + . = ..() + + if(Obj && Obj.opacity) + has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case. + reconsider_lights() + +/turf/Exited(var/atom/movable/Obj, var/atom/newloc) + . = ..() + + if(Obj && Obj.opacity) + recalc_atom_opacity() // Make sure to do this before reconsider_lights(), incase we're on instant updates. + reconsider_lights() + +/turf/proc/get_corners() + if(has_opaque_atom) + return null // Since this proc gets used in a for loop, null won't be looped though. + + return corners + +/turf/proc/generate_missing_corners() + lighting_corners_initialised = TRUE + if(!corners) + corners = list(null, null, null, null) + + for(var/i = 1 to 4) + if(corners[i]) // Already have a corner on this direction. + continue + + corners[i] = new /datum/lighting_corner(src, LIGHTING_CORNER_DIAGONAL[i]) diff --git a/code/modules/lighting/~lighting_undefs.dm b/code/modules/lighting/~lighting_undefs.dm index 09100322b8a..2de3f9dbe26 100644 --- a/code/modules/lighting/~lighting_undefs.dm +++ b/code/modules/lighting/~lighting_undefs.dm @@ -1,9 +1,7 @@ -#undef LIGHTING_INTERVAL - #undef LIGHTING_FALLOFF #undef LIGHTING_LAMBERTIAN #undef LIGHTING_HEIGHT -#undef LIGHTING_RESOLUTION -#undef LIGHTING_LAYER -#undef LIGHTING_ICON \ No newline at end of file +#undef LIGHTING_ICON + +#undef LIGHTING_BASE_MATRIX diff --git a/code/modules/mining/abandonedcrates.dm b/code/modules/mining/abandonedcrates.dm index db641754240..c7212fe5a15 100644 --- a/code/modules/mining/abandonedcrates.dm +++ b/code/modules/mining/abandonedcrates.dm @@ -63,7 +63,7 @@ if(57 to 58) new /obj/item/toy/syndicateballoon(src) if(59 to 60) - new /obj/item/weapon/gun/energy/kinetic_accelerator/hyper(src) + new /obj/item/borg/upgrade/modkit/aoe/mobs(src) new /obj/item/clothing/suit/space(src) new /obj/item/clothing/head/helmet/space(src) if(61 to 62) diff --git a/code/modules/mining/equipment_locker.dm b/code/modules/mining/equipment_locker.dm index 712fca9592a..cc6529f665d 100644 --- a/code/modules/mining/equipment_locker.dm +++ b/code/modules/mining/equipment_locker.dm @@ -313,7 +313,7 @@ anchored = 1.0 var/obj/item/weapon/card/id/inserted_id var/list/prize_list = list( - new /datum/data/mining_equipment("Stimpack", /obj/item/weapon/reagent_containers/hypospray/autoinjector/stimpack, 50), + new /datum/data/mining_equipment("Stimpack", /obj/item/weapon/reagent_containers/hypospray/autoinjector/stimpack, 50), new /datum/data/mining_equipment("Teporone MediPen", /obj/item/weapon/reagent_containers/hypospray/autoinjector/teporone, 50), new /datum/data/mining_equipment("MediPen Bundle", /obj/item/weapon/storage/box/autoinjector/utility, 200), new /datum/data/mining_equipment("Whiskey", /obj/item/weapon/reagent_containers/food/drinks/bottle/whiskey, 100), @@ -324,10 +324,10 @@ new /datum/data/mining_equipment("Advanced Scanner", /obj/item/device/t_scanner/adv_mining_scanner, 400), new /datum/data/mining_equipment("Hivelord Stabilizer", /obj/item/weapon/hivelordstabilizer, 400), new /datum/data/mining_equipment("Mining Drone", /obj/item/weapon/mining_drone_cube, 500), - new /datum/data/mining_equipment("Drone Melee Upgrade", /obj/item/device/mine_bot_ugprade, 400), - new /datum/data/mining_equipment("Drone Health Upgrade",/obj/item/device/mine_bot_ugprade/health, 400), - new /datum/data/mining_equipment("Drone Ranged Upgrade",/obj/item/device/mine_bot_ugprade/cooldown, 600), - new /datum/data/mining_equipment("Kinetic Crusher", /obj/item/weapon/twohanded/required/mining_hammer, 750), + new /datum/data/mining_equipment("Drone Melee Upgrade", /obj/item/device/mine_bot_upgrade, 400), + new /datum/data/mining_equipment("Drone Health Upgrade",/obj/item/device/mine_bot_upgrade/health, 400), + new /datum/data/mining_equipment("Drone Ranged Upgrade",/obj/item/device/mine_bot_upgrade/cooldown, 600), + new /datum/data/mining_equipment("Kinetic Crusher", /obj/item/weapon/twohanded/required/mining_hammer, 750), new /datum/data/mining_equipment("Drone AI Upgrade", /obj/item/slimepotion/sentience/mining, 1000), new /datum/data/mining_equipment("GAR mesons", /obj/item/clothing/glasses/meson/gar, 500), new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/weapon/storage/firstaid/brute, 600), @@ -342,7 +342,14 @@ new /datum/data/mining_equipment("Space Cash", /obj/item/weapon/spacecash/c1000, 2000), new /datum/data/mining_equipment("Diamond Pickaxe", /obj/item/weapon/pickaxe/diamond, 2000), new /datum/data/mining_equipment("Super Resonator", /obj/item/weapon/resonator/upgraded, 2500), - new /datum/data/mining_equipment("Super Accelerator", /obj/item/weapon/gun/energy/kinetic_accelerator/super, 3000), + new /datum/data/mining_equipment("KA White Tracer Rounds", /obj/item/borg/upgrade/modkit/tracer, 100), + new /datum/data/mining_equipment("KA Adjustable Tracer Rounds", /obj/item/borg/upgrade/modkit/tracer/adjustable, 150), + new /datum/data/mining_equipment("KA Super Chassis", /obj/item/borg/upgrade/modkit/chassis_mod, 250), + new /datum/data/mining_equipment("KA Hyper Chassis", /obj/item/borg/upgrade/modkit/chassis_mod/orange, 300), + new /datum/data/mining_equipment("KA Range Increase", /obj/item/borg/upgrade/modkit/range, 1000), + new /datum/data/mining_equipment("KA Damage Increase", /obj/item/borg/upgrade/modkit/damage, 1000), + new /datum/data/mining_equipment("KA Cooldown Decrease",/obj/item/borg/upgrade/modkit/cooldown, 1000), + new /datum/data/mining_equipment("KA AoE Damage", /obj/item/borg/upgrade/modkit/aoe/mobs, 2000), new /datum/data/mining_equipment("Point Transfer Card", /obj/item/weapon/card/mining_point_card, 500), ) @@ -938,18 +945,18 @@ //Melee -/obj/item/device/mine_bot_ugprade +/obj/item/device/mine_bot_upgrade name = "minebot melee upgrade" desc = "A minebot upgrade." icon_state = "door_electronics" icon = 'icons/obj/doors/door_assembly.dmi' -/obj/item/device/mine_bot_ugprade/afterattack(mob/living/simple_animal/hostile/mining_drone/M, mob/user, proximity) +/obj/item/device/mine_bot_upgrade/afterattack(mob/living/simple_animal/hostile/mining_drone/M, mob/user, proximity) if(!istype(M) || !proximity) return upgrade_bot(M, user) -/obj/item/device/mine_bot_ugprade/proc/upgrade_bot(mob/living/simple_animal/hostile/mining_drone/M, mob/user) +/obj/item/device/mine_bot_upgrade/proc/upgrade_bot(mob/living/simple_animal/hostile/mining_drone/M, mob/user) if(M.melee_damage_upper != initial(M.melee_damage_upper)) to_chat(user, "[M] already has a combat upgrade installed!") return @@ -960,10 +967,10 @@ //Health -/obj/item/device/mine_bot_ugprade/health +/obj/item/device/mine_bot_upgrade/health name = "minebot chassis upgrade" -/obj/item/device/mine_bot_ugprade/health/upgrade_bot(mob/living/simple_animal/hostile/mining_drone/M, mob/user) +/obj/item/device/mine_bot_upgrade/health/upgrade_bot(mob/living/simple_animal/hostile/mining_drone/M, mob/user) if(M.maxHealth != initial(M.maxHealth)) to_chat(user, "[M] already has a reinforced chassis!") return @@ -974,10 +981,10 @@ //Cooldown -/obj/item/device/mine_bot_ugprade/cooldown +/obj/item/device/mine_bot_upgrade/cooldown name = "minebot cooldown upgrade" -/obj/item/device/mine_bot_ugprade/cooldown/upgrade_bot(mob/living/simple_animal/hostile/mining_drone/M, mob/user) +/obj/item/device/mine_bot_upgrade/cooldown/upgrade_bot(mob/living/simple_animal/hostile/mining_drone/M, mob/user) if(M.ranged_cooldown_time != initial(M.ranged_cooldown_time)) to_chat(user, "[M] already has a decreased weapon cooldown!") return diff --git a/code/modules/mining/lavaland/loot/ashdragon_loot.dm b/code/modules/mining/lavaland/loot/ashdragon_loot.dm new file mode 100644 index 00000000000..4565039d52e --- /dev/null +++ b/code/modules/mining/lavaland/loot/ashdragon_loot.dm @@ -0,0 +1,217 @@ +/obj/structure/closet/crate/necropolis/dragon + name = "dragon chest" + +/obj/structure/closet/crate/necropolis/dragon/New() + ..() + var/loot = rand(1,4) + switch(loot) + if(1) + new /obj/item/weapon/melee/ghost_sword(src) + if(2) + new /obj/item/weapon/lava_staff(src) + if(3) + new /obj/item/weapon/spellbook/oneuse/sacredflame(src) + new /obj/item/weapon/gun/magic/wand/fireball(src) + if(4) + new /obj/item/weapon/dragons_blood(src) + +// Spectral Blade + +/obj/item/weapon/melee/ghost_sword + name = "spectral blade" + desc = "A rusted and dulled blade. It doesn't look like it'd do much damage. It glows weakly." + icon_state = "spectral" + item_state = "spectral" + flags = CONDUCT + sharp = 1 + edge = 1 + w_class = 4 + force = 1 + throwforce = 1 + hitsound = 'sound/effects/ghost2.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "rended") + var/summon_cooldown = 0 + var/list/mob/dead/observer/spirits + +/obj/item/weapon/melee/ghost_sword/New() + ..() + spirits = list() + processing_objects.Add(src) + poi_list |= src + +/obj/item/weapon/melee/ghost_sword/Destroy() + for(var/mob/dead/observer/G in spirits) + G.invisibility = initial(G.invisibility) + spirits.Cut() + processing_objects.Remove(src) + poi_list -= src + . = ..() + +/obj/item/weapon/melee/ghost_sword/attack_self(mob/user) + if(summon_cooldown > world.time) + to_chat(user, "You just recently called out for aid. You don't want to annoy the spirits.") + return + to_chat(user, "You call out for aid, attempting to summon spirits to your side.") + + notify_ghosts("[user] is raising their [src], calling for your help!", enter_link="(Click to help)", source = user, action = NOTIFY_FOLLOW) + + summon_cooldown = world.time + 600 + +/obj/item/weapon/melee/ghost_sword/Topic(href, href_list) + if(href_list["follow"]) + var/mob/dead/observer/ghost = usr + if(istype(ghost)) + ghost.ManualFollow(src) + +/obj/item/weapon/melee/ghost_sword/process() + ghost_check() + +/obj/item/weapon/melee/ghost_sword/proc/ghost_check() + var/ghost_counter = 0 + var/turf/T = get_turf(src) + var/list/contents = T.GetAllContents() + var/mob/dead/observer/current_spirits = list() + + for(var/mob/dead/observer/O in player_list) + if(is_type_in_list(O.following, contents)) + ghost_counter++ + O.invisibility = 0 + current_spirits |= O + + for(var/mob/dead/observer/G in spirits - current_spirits) + G.invisibility = initial(G.invisibility) + + spirits = current_spirits + + return ghost_counter + +/obj/item/weapon/melee/ghost_sword/attack(mob/living/target, mob/living/carbon/human/user) + force = 0 + var/ghost_counter = ghost_check() + + force = Clamp((ghost_counter * 4), 0, 75) + user.visible_message("[user] strikes with the force of [ghost_counter] vengeful spirits!") + ..() + +/obj/item/weapon/melee/ghost_sword/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type) + var/ghost_counter = ghost_check() + final_block_chance += Clamp((ghost_counter * 5), 0, 75) + owner.visible_message("[owner] is protected by a ring of [ghost_counter] ghosts!") + return ..() + +// Blood + +/obj/item/weapon/dragons_blood + name = "bottle of dragons blood" + desc = "You're not actually going to drink this, are you?" + icon = 'icons/obj/wizard.dmi' + icon_state = "vial" + +/obj/item/weapon/dragons_blood/attack_self(mob/living/carbon/human/user) + if(!istype(user)) + return + + var/mob/living/carbon/human/H = user + var/random = rand(1,3) + + switch(random) + if(1) + to_chat(user, "Your flesh begins to melt! Miraculously, you seem fine otherwise.") + H.set_species("Skeleton") + if(2) + to_chat(user, "Power courses through you! You can now shift your form at will.") + if(user.mind) + var/obj/effect/proc_holder/spell/targeted/shapeshift/dragon/D = new + user.mind.AddSpell(D) + if(3) + to_chat(user, "You feel like you could walk straight through lava now.") + H.weather_immunities |= "lava" + + playsound(user.loc,'sound/items/drink.ogg', rand(10,50), 1) + qdel(src) + +/datum/disease/transformation/dragon + name = "dragon transformation" + cure_text = "nothing" + cures = list("adminordrazine") + agent = "dragon's blood" + desc = "What do dragons have to do with Space Station 13?" + stage_prob = 20 + severity = BIOHAZARD + visibility_flags = 0 + stage1 = list("Your bones ache.") + stage2 = list("Your skin feels scaley.") + stage3 = list("You have an overwhelming urge to terrorize some peasants.", "Your teeth feel sharper.") + stage4 = list("Your blood burns.") + stage5 = list("You're a fucking dragon. However, any previous allegiances you held still apply. It'd be incredibly rude to eat your still human friends for no reason.") + new_form = /mob/living/simple_animal/hostile/megafauna/dragon/lesser + +//Lava Staff + +/obj/item/weapon/lava_staff + name = "staff of lava" + desc = "The ability to fill the emergency shuttle with lava. What more could you want out of life?" + icon_state = "staffofstorms" + item_state = "staffofstorms" + icon = 'icons/obj/guns/magic.dmi' + slot_flags = SLOT_BACK + item_state = "staffofstorms" + w_class = 4 + force = 25 + damtype = BURN + hitsound = 'sound/weapons/sear.ogg' + burn_state = LAVA_PROOF | FIRE_PROOF + unacidable = 1 + var/turf_type = /turf/unsimulated/floor/lava // /turf/simulated/floor/plating/lava/smooth once Lavaland turfs are added + var/transform_string = "lava" + var/reset_turf_type = /turf/simulated/floor/plating/airless/asteroid // /turf/simulated/floor/plating/asteroid/basalt once Lavaland turfs are added + var/reset_string = "basalt" + var/create_cooldown = 100 + var/create_delay = 30 + var/reset_cooldown = 50 + var/timer = 0 + var/banned_turfs + +/obj/item/weapon/lava_staff/New() + . = ..() + banned_turfs = typecacheof(list(/turf/space/transit, /turf/unsimulated)) + +/obj/item/weapon/lava_staff/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + ..() + if(timer > world.time) + return + + if(is_type_in_typecache(target, banned_turfs)) + return + + if(target in view(user.client.view, get_turf(user))) + + var/turf/simulated/T = get_turf(target) + if(!istype(T)) + return + if(!istype(T, turf_type)) + var/obj/effect/overlay/temp/lavastaff/L = new /obj/effect/overlay/temp/lavastaff(T) + L.alpha = 0 + animate(L, alpha = 255, time = create_delay) + user.visible_message("[user] points [src] at [T]!") + timer = world.time + create_delay + 1 + if(do_after(user, create_delay, target = T)) + user.visible_message("[user] turns \the [T] into [transform_string]!") + message_admins("[key_name_admin(user)] fired the lava staff at [get_area(target)] (JMP).") + log_game("[key_name(user)] fired the lava staff at [get_area(target)] ([T.x], [T.y], [T.z]).") + T.ChangeTurf(turf_type) + timer = world.time + create_cooldown + qdel(L) + else + timer = world.time + qdel(L) + return + else + user.visible_message("[user] turns \the [T] into [reset_string]!") + T.ChangeTurf(reset_turf_type) + timer = world.time + reset_cooldown + playsound(T,'sound/magic/Fireball.ogg', 200, 1) + +/obj/effect/overlay/temp/lavastaff + icon_state = "lavastaff_warn" + duration = 50 \ No newline at end of file diff --git a/code/modules/mining/lavaland/loot/bubblegum_loot.dm b/code/modules/mining/lavaland/loot/bubblegum_loot.dm new file mode 100644 index 00000000000..8ee0ecacd8d --- /dev/null +++ b/code/modules/mining/lavaland/loot/bubblegum_loot.dm @@ -0,0 +1,81 @@ +/obj/structure/closet/crate/necropolis/bubblegum + name = "bubblegum chest" + +/obj/structure/closet/crate/necropolis/bubblegum/New() + ..() + var/loot = rand(1,3) + switch(loot) + if(1) + new /obj/item/mayhem(src) + if(2) + new /obj/item/blood_contract(src) + if(3) + new /obj/item/weapon/gun/magic/staff/spellblade(src) + +// Mayhem + +/obj/item/mayhem + name = "mayhem in a bottle" + desc = "A magically infused bottle of blood, the scent of which will drive anyone nearby into a murderous frenzy." + icon = 'icons/obj/wizard.dmi' + icon_state = "vial" + +/obj/item/mayhem/attack_self(mob/user) + for(var/mob/living/carbon/human/H in range(7,user)) + spawn() + var/obj/effect/mine/pickup/bloodbath/B = new(H) + B.mineEffect(H) + to_chat(user, "You shatter the bottle!") + playsound(user.loc, 'sound/effects/Glassbr1.ogg', 100, 1) + qdel(src) + +// Blood Contract + +/obj/item/blood_contract + name = "blood contract" + icon = 'icons/obj/wizard.dmi' + icon_state = "scroll2" + color = "#FF0000" + desc = "Mark your target for death." + var/used = FALSE + +/obj/item/blood_contract/attack_self(mob/user) + if(used) + return + + used = TRUE + var/choice = input(user,"Who do you want dead?","Choose Your Victim") as null|anything in player_list + + if(!choice) + used = FALSE + return + else if(!isliving(choice)) + to_chat(user, "[choice] is already dead!") + used = FALSE + return + else if(choice == user) + to_chat(user, "You feel like writing your own name into a cursed death warrant would be unwise.") + used = FALSE + return + else + var/mob/living/L = choice + + message_admins("[key_name_admin(L)] has been marked for death by [key_name_admin(user)].") + log_admin("[key_name(L)] has been marked for death by [key_name(user)].") + + var/datum/objective/survive/survive = new + survive.owner = L.mind + L.mind.objectives += survive + to_chat(L, "You've been marked for death! Don't let the demons get you!") + L.color = "#FF0000" + spawn() + var/obj/effect/mine/pickup/bloodbath/B = new(L) + B.mineEffect(L) + + for(var/mob/living/carbon/human/H in player_list) + if(H == L) + continue + to_chat(H, "You have an overwhelming desire to kill [L]. They have been marked red! Go kill them!") + H.put_in_hands(new /obj/item/weapon/kitchen/knife/butcher(H)) + + qdel(src) \ No newline at end of file diff --git a/code/modules/mining/lavaland/colossus_loot.dm b/code/modules/mining/lavaland/loot/colossus_loot.dm similarity index 99% rename from code/modules/mining/lavaland/colossus_loot.dm rename to code/modules/mining/lavaland/loot/colossus_loot.dm index 1928ff0f342..fc950b429d2 100644 --- a/code/modules/mining/lavaland/colossus_loot.dm +++ b/code/modules/mining/lavaland/loot/colossus_loot.dm @@ -10,6 +10,7 @@ luminosity = 8 max_n_of_items = INFINITY unacidable = 1 + burn_state = LAVA_PROOF | FIRE_PROOF pixel_y = -4 use_power = 0 var/memory_saved = FALSE @@ -98,6 +99,7 @@ luminosity = 8 use_power = 0 density = 1 + burn_state = LAVA_PROOF | FIRE_PROOF unacidable = 1 var/activation_method = "touch" var/activation_damage_type = null diff --git a/code/modules/mining/lavaland/loot/hierophant_loot.dm b/code/modules/mining/lavaland/loot/hierophant_loot.dm new file mode 100644 index 00000000000..f06fd25d428 --- /dev/null +++ b/code/modules/mining/lavaland/loot/hierophant_loot.dm @@ -0,0 +1,188 @@ +/obj/item/weapon/hierophant_staff + name = "Hierophant's staff" + desc = "A large club with intense magic power infused into it." + icon_state = "hierophant_staff" + item_state = "hierophant_staff" + icon = 'icons/obj/guns/magic.dmi' + slot_flags = SLOT_BACK + w_class = 4 + force = 20 + hitsound = "swing_hit" + //hitsound = 'sound/weapons/sonic_jackhammer.ogg' + actions_types = list(/datum/action/item_action/vortex_recall, /datum/action/item_action/toggle_unfriendly_fire) + var/cooldown_time = 20 //how long the cooldown between non-melee ranged attacks is + var/chaser_cooldown = 101 //how long the cooldown between firing chasers at mobs is + var/chaser_timer = 0 //what our current chaser cooldown is + var/timer = 0 //what our current cooldown is + var/blast_range = 3 //how long the cardinal blast's walls are + var/obj/effect/hierophant/rune //the associated rune we teleport to + var/teleporting = FALSE //if we ARE teleporting + var/friendly_fire_check = FALSE //if the blasts we make will consider our faction against the faction of hit targets + +/obj/item/weapon/hierophant_staff/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + ..() + var/turf/T = get_turf(target) + if(!T || timer > world.time) + return + timer = world.time + CLICK_CD_MELEE //by default, melee attacks only cause melee blasts, and have an accordingly short cooldown + if(proximity_flag) + spawn(0) + aoe_burst(T, user) + add_logs(user, target, "fired 3x3 blast at", src) + else + if(ismineralturf(target) && get_dist(user, target) < 6) //target is minerals, we can hit it(even if we can't see it) + spawn(0) + cardinal_blasts(T, user) + timer = world.time + cooldown_time + else if(target in view(5, get_turf(user))) //if the target is in view, hit it + timer = world.time + cooldown_time + if(isliving(target) && chaser_timer <= world.time) //living and chasers off cooldown? fire one! + chaser_timer = world.time + chaser_cooldown + new /obj/effect/overlay/temp/hierophant/chaser(get_turf(user), user, target, 1.5, friendly_fire_check) + add_logs(user, target, "fired a chaser at", src) + else + spawn(0) + cardinal_blasts(T, user) //otherwise, just do cardinal blast + add_logs(user, target, "fired cardinal blast at", src) + else + to_chat(user, "That target is out of range!") //too far away + +/obj/item/weapon/hierophant_staff/ui_action_click(mob/user, actiontype) + if(actiontype == /datum/action/item_action/toggle_unfriendly_fire) //toggle friendly fire... + friendly_fire_check = !friendly_fire_check + to_chat(user, "You toggle friendly fire [friendly_fire_check ? "off":"on"]!") + return + if(user.get_active_hand() != src && user.get_inactive_hand() != src) //you need to hold the staff to teleport + to_chat(user, "You need to hold the staff in your hands to [rune ? "teleport with it" : "create a rune"]!") + return + if(!rune) + if(isturf(user.loc)) + user.visible_message("[user] holds [src] carefully in front of them, moving it in a strange pattern...", \ + "You start creating a hierophant rune to teleport to...") + timer = world.time + 51 + if(do_after(user, 50, target = user)) + var/turf/T = get_turf(user) + playsound(T,'sound/magic/Blind.ogg', 200, 1, -4) + new /obj/effect/overlay/temp/hierophant/telegraph/teleport(T, user) + var/obj/effect/hierophant/H = new/obj/effect/hierophant(T) + rune = H + user.update_action_buttons_icon() + user.visible_message("[user] creates a strange rune beneath them!", \ + "You create a hierophant rune, which you can teleport yourself and any allies to at any time!\n\ + You can remove the rune to place a new one by striking it with the staff.") + else + timer = world.time + else + to_chat(user, "You need to be on solid ground to produce a rune!") + return + if(get_dist(user, rune) <= 2) //rune too close abort + to_chat(user, "You are too close to the rune to teleport to it!") + return + if(is_blocked_turf(get_turf(rune))) + to_chat(user, "The rune is blocked by something, preventing teleportation!") + return + teleporting = TRUE //start channel + user.update_action_buttons_icon() + user.visible_message("[user] starts to glow faintly...") + timer = world.time + 50 + if(do_after(user, 40, target = user) && rune) + var/turf/T = get_turf(rune) + var/turf/source = get_turf(user) + if(is_blocked_turf(T)) + teleporting = FALSE + to_chat(user, "The rune is blocked by something, preventing teleportation!") + user.update_action_buttons_icon() + return + new /obj/effect/overlay/temp/hierophant/telegraph(T, user) + new /obj/effect/overlay/temp/hierophant/telegraph(source, user) + playsound(T,'sound/magic/blink.ogg', 200, 1) + //playsound(T,'sound/magic/Wand_Teleport.ogg', 200, 1) + playsound(source,'sound/magic/blink.ogg', 200, 1) + //playsound(source,'sound/machines/AirlockOpen.ogg', 200, 1) + if(!do_after(user, 3, target = user) || !rune) //no walking away shitlord + teleporting = FALSE + if(user) + user.update_action_buttons_icon() + return + if(is_blocked_turf(T)) + teleporting = FALSE + to_chat(user, "The rune is blocked by something, preventing teleportation!") + user.update_action_buttons_icon() + return + add_logs(user, rune, "teleported self from ([source.x],[source.y],[source.z]) to") + new /obj/effect/overlay/temp/hierophant/telegraph/teleport(T, user) + new /obj/effect/overlay/temp/hierophant/telegraph/teleport(source, user) + for(var/t in RANGE_TURFS(1, T)) + var/obj/effect/overlay/temp/hierophant/blast/B = new /obj/effect/overlay/temp/hierophant/blast(t, user, TRUE) //blasts produced will not hurt allies + B.damage = 30 + for(var/t in RANGE_TURFS(1, source)) + var/obj/effect/overlay/temp/hierophant/blast/B = new /obj/effect/overlay/temp/hierophant/blast(t, user, TRUE) //but absolutely will hurt enemies + B.damage = 30 + for(var/mob/living/L in range(1, source)) + spawn(0) + teleport_mob(source, L, T, user) //regardless, take all mobs near us along + sleep(6) //at this point the blasts detonate + else + timer = world.time + teleporting = FALSE + if(user) + user.update_action_buttons_icon() + +/obj/item/weapon/hierophant_staff/proc/teleport_mob(turf/source, mob/M, turf/target, mob/user) + var/turf/turf_to_teleport_to = get_step(target, get_dir(source, M)) //get position relative to caster + if(!turf_to_teleport_to || is_blocked_turf(turf_to_teleport_to)) + return + animate(M, alpha = 0, time = 2, easing = EASE_OUT) //fade out + sleep(1) + if(!M) + return + M.visible_message("[M] fades out!") + sleep(2) + if(!M) + return + M.forceMove(turf_to_teleport_to) + sleep(1) + if(!M) + return + animate(M, alpha = 255, time = 2, easing = EASE_IN) //fade IN + sleep(1) + if(!M) + return + M.visible_message("[M] fades in!") + if(user != M) + add_logs(user, M, "teleported", null, "from ([source.x],[source.y],[source.z])") + +/obj/item/weapon/hierophant_staff/proc/cardinal_blasts(turf/T, mob/living/user) //fire cardinal cross blasts with a delay + if(!T) + return + new /obj/effect/overlay/temp/hierophant/telegraph/cardinal(T, user) + playsound(T,'sound/magic/blink.ogg', 200, 1) + //playsound(T,'sound/effects/bin_close.ogg', 200, 1) + sleep(2) + new /obj/effect/overlay/temp/hierophant/blast(T, user, friendly_fire_check) + for(var/d in cardinal) + spawn(0) + blast_wall(T, d, user) + +/obj/item/weapon/hierophant_staff/proc/blast_wall(turf/T, dir, mob/living/user) //make a wall of blasts blast_range tiles long + if(!T) + return + var/range = blast_range + var/turf/previousturf = T + var/turf/J = get_step(previousturf, dir) + for(var/i in 1 to range) + if(!J) + return + new /obj/effect/overlay/temp/hierophant/blast(J, user, friendly_fire_check) + previousturf = J + J = get_step(previousturf, dir) + +/obj/item/weapon/hierophant_staff/proc/aoe_burst(turf/T, mob/living/user) //make a 3x3 blast around a target + if(!T) + return + new /obj/effect/overlay/temp/hierophant/telegraph(T, user) + playsound(T,'sound/magic/blink.ogg', 200, 1) + //playsound(T,'sound/effects/bin_close.ogg', 200, 1) + sleep(2) + for(var/t in RANGE_TURFS(1, T)) + new /obj/effect/overlay/temp/hierophant/blast(t, user, friendly_fire_check) \ No newline at end of file diff --git a/code/modules/mining/lavaland/loot/legion_loot.dm b/code/modules/mining/lavaland/loot/legion_loot.dm new file mode 100644 index 00000000000..49e64f3349e --- /dev/null +++ b/code/modules/mining/lavaland/loot/legion_loot.dm @@ -0,0 +1,52 @@ +/obj/item/weapon/staff/storm + name = "staff of storms" + desc = "An ancient staff retrieved from the remains of Legion. The wind stirs as you move it." + icon_state = "staffofstorms" + item_state = "staffofstorms" + icon = 'icons/obj/guns/magic.dmi' + slot_flags = SLOT_BACK + item_state = "staffofstorms" + w_class = 4 + force = 25 + damtype = BURN + hitsound = 'sound/weapons/sear.ogg' + var/storm_type = /datum/weather/ash_storm + var/storm_cooldown = 0 + +/obj/item/weapon/staff/storm/attack_self(mob/user) + if(storm_cooldown > world.time) + to_chat(user, "The staff is still recharging!") + return + + var/area/user_area = get_area(user) + var/datum/weather/A + var/z_level_name = space_manager.levels_by_name[user.z] + for(var/V in weather_master.existing_weather) + var/datum/weather/W = V + if(W.target_z == z_level_name && W.area_type == user_area.type) + A = W + break + if(A) + + if(A.stage != END_STAGE) + if(A.stage == WIND_DOWN_STAGE) + to_chat(user, "The storm is already ending! It would be a waste to use the staff now.") + return + user.visible_message("[user] holds [src] skywards as an orange beam travels into the sky!", \ + "You hold [src] skyward, dispelling the storm!") + playsound(user, 'sound/magic/Staff_Change.ogg', 200, 0) + A.wind_down() + return + else + A = new storm_type + A.name = "staff storm" + A.area_type = user_area.type + A.target_z = z_level_name + A.telegraph_duration = 100 + A.end_duration = 100 + + user.visible_message("[user] holds [src] skywards as red lightning crackles into the sky!", \ + "You hold [src] skyward, calling down a terrible storm!") + playsound(user, 'sound/magic/Staff_Change.ogg', 200, 0) + A.telegraph() + storm_cooldown = world.time + 200 \ No newline at end of file diff --git a/code/modules/mining/lavaland/loot/tendril_loot.dm b/code/modules/mining/lavaland/loot/tendril_loot.dm new file mode 100644 index 00000000000..ed8b400337a --- /dev/null +++ b/code/modules/mining/lavaland/loot/tendril_loot.dm @@ -0,0 +1,394 @@ +//Shared Bag + +//Internal +/obj/item/weapon/storage/backpack/shared + name = "paradox bag" + desc = "Somehow, it's in two places at once." + max_combined_w_class = 60 + max_w_class = 3 + +//External +/obj/item/device/shared_storage + name = "paradox bag" + desc = "Somehow, it's in two places at once." + icon = 'icons/obj/storage.dmi' + icon_state = "cultpack" + slot_flags = SLOT_BACK + var/obj/item/weapon/storage/backpack/shared/bag + +/obj/item/device/shared_storage/red + name = "paradox bag" + desc = "Somehow, it's in two places at once." + +/obj/item/device/shared_storage/red/New() + ..() + if(!bag) + var/obj/item/weapon/storage/backpack/shared/S = new(src) + var/obj/item/device/shared_storage/blue = new(loc) + + bag = S + blue.bag = S + +/obj/item/device/shared_storage/attackby(obj/item/W, mob/user, params) + if(bag) + bag.loc = user + bag.attackby(W, user, params) + +/obj/item/device/shared_storage/attack_self(mob/living/carbon/user) + if(!iscarbon(user)) + return + if(src == user.l_hand || src == user.r_hand) + if(bag) + bag.loc = user + bag.attack_hand(user) + else + ..() + +/obj/item/device/shared_storage/attack_hand(mob/living/carbon/user) + if(!iscarbon(user)) + return + if(loc == user && user.back && user.back == src) + if(bag) + bag.loc = user + bag.attack_hand(user) + else + ..() + +/obj/item/device/shared_storage/MouseDrop(atom/over_object) + if(iscarbon(usr)) + var/mob/M = usr + + if(!over_object) + return + + if(istype(M.loc, /obj/mecha)) + return + + if(!M.restrained() && !M.stat) + playsound(loc, "rustle", 50, 1, -5) + + if(istype(over_object, /obj/screen/inventory/hand)) + if(!M.unEquip(src)) + return + M.put_in_active_hand(src) + else if(bag) + bag.loc = usr + bag.attack_hand(usr) + + add_fingerprint(M) + +//Potion of Flight: as we do not have the "Angel" species this currently does not work. + +/obj/item/weapon/reagent_containers/glass/bottle/potion + icon = 'icons/obj/lavaland/artefacts.dmi' + icon_state = "potionflask" + +/obj/item/weapon/reagent_containers/glass/bottle/potion/flight + name = "strange elixir" + desc = "A flask with an almost-holy aura emitting from it. The label on the bottle says: 'erqo'hyy tvi'rf lbh jv'atf'." + list_reagents = list("flightpotion" = 5) + +/obj/item/weapon/reagent_containers/glass/bottle/potion/update_icon() + if(reagents.total_volume) + icon_state = "potionflask" + else + icon_state = "potionflask_empty" + +/datum/reagent/flightpotion + name = "Flight Potion" + id = "flightpotion" + description = "Strange mutagenic compound of unknown origins." + reagent_state = LIQUID + color = "#FFEBEB" + +/datum/reagent/flightpotion/reaction_mob(mob/living/M, method = TOUCH, reac_volume, show_message = 1) + to_chat(M, "This item is currently non-functional.") + /*if(ishuman(M) && M.stat != DEAD) + var/mob/living/carbon/human/H = M + if(H.species.name != "Human" || reac_volume < 5) // implying xenohumans are holy + if(method == INGEST && show_message) + to_chat(H, "You feel nothing but a terrible aftertaste.") + return ..() + + to_chat(H, "A terrible pain travels down your back as wings burst out!") + H.set_species("Angel") + playsound(H.loc, 'sound/items/poster_ripped.ogg', 50, 1, -1) + H.adjustBruteLoss(20) + H.emote("scream") + ..()*/ + +//Boat + +/obj/vehicle/lavaboat + name = "lava boat" + desc = "A boat used for traversing lava." + icon_state = "goliath_boat" + icon = 'icons/obj/lavaland/dragonboat.dmi' + keytype = /obj/item/weapon/oar + burn_state = LAVA_PROOF | FIRE_PROOF + +/obj/vehicle/lavaboat/relaymove(mob/user, direction) + var/turf/next = get_step(src, direction) + var/turf/current = get_turf(src) + + if(istype(next, /turf/unsimulated/floor/lava) || istype(current, /turf/unsimulated/floor/lava)) //We can move from land to lava, or lava to land, but not from land to land + ..() + else + to_chat(user, "Boats don't go on land!") + return 0 + +/obj/item/weapon/oar + name = "oar" + icon = 'icons/obj/vehicles.dmi' + icon_state = "oar" + item_state = "rods" + desc = "Not to be confused with the kind Research hassles you for." + force = 12 + w_class = 3 + burn_state = LAVA_PROOF | FIRE_PROOF + +/datum/crafting_recipe/oar + name = "goliath bone oar" + result = /obj/item/weapon/oar + reqs = list(/obj/item/stack/sheet/bone = 2) + time = 15 + category = CAT_PRIMAL + +/datum/crafting_recipe/boat + name = "goliath hide boat" + result = /obj/vehicle/lavaboat + reqs = list(/obj/item/stack/sheet/animalhide/goliath_hide = 3) + time = 50 + category = CAT_PRIMAL + +//Dragon Boat + +/obj/item/ship_in_a_bottle + name = "ship in a bottle" + desc = "A tiny ship inside a bottle." + icon = 'icons/obj/lavaland/artefacts.dmi' + icon_state = "ship_bottle" + +/obj/item/ship_in_a_bottle/attack_self(mob/user) + to_chat(user, "You're not sure how they get the ships in these things, but you're pretty sure you know how to get it out.") + playsound(user.loc, 'sound/effects/Glassbr1.ogg', 100, 1) + new /obj/vehicle/lavaboat/dragon(get_turf(src)) + qdel(src) + +/obj/vehicle/lavaboat/dragon + name = "mysterious boat" + desc = "This boat moves where you will it, without the need for an oar." + keytype = null + icon_state = "dragon_boat" + generic_pixel_y = 2 + generic_pixel_x = 1 + vehicle_move_delay = 1 + +// Wisp Lantern +/obj/item/device/wisp_lantern + name = "spooky lantern" + desc = "This lantern gives off no light, but is home to a friendly wisp." + icon = 'icons/obj/lighting.dmi' + icon_state = "lantern-blue" + var/obj/effect/wisp/wisp + +/obj/item/device/wisp_lantern/attack_self(mob/user) + if(!wisp) + to_chat(user, "The wisp has gone missing!") + return + if(wisp.loc == src) + to_chat(user, "You release the wisp. It begins to bob around your head.") + user.sight |= SEE_MOBS + icon_state = "lantern" + wisp.orbit(user, 20, forceMove = TRUE) + feedback_add_details("wisp_lantern","F") // freed + + else + to_chat(user, "You return the wisp to the lantern.") + + if(wisp.orbiting) + var/atom/A = wisp.orbiting + if(isliving(A)) + var/mob/living/M = A + M.sight &= ~SEE_MOBS + to_chat(M, "Your vision returns to normal.") + + wisp.stop_orbit() + wisp.loc = src + icon_state = "lantern-blue" + feedback_add_details("wisp_lantern","R") // returned + +/obj/item/device/wisp_lantern/New() + ..() + wisp = new(src) + +/obj/item/device/wisp_lantern/Destroy() + if(wisp) + if(wisp.loc == src) + qdel(wisp) + else + wisp.visible_message("[wisp] has a sad feeling for a moment, then it passes.") + return ..() + +/obj/effect/wisp + name = "friendly wisp" + desc = "Happy to light your way." + icon = 'icons/obj/lighting.dmi' + icon_state = "orb" + layer = ABOVE_ALL_MOB_LAYER + light_power = 1 + light_range = 7 + +//Red/Blue Cubes + +/obj/item/device/warp_cube + name = "blue cube" + desc = "A mysterious blue cube." + icon = 'icons/obj/lavaland/artefacts.dmi' + icon_state = "blue_cube" + var/obj/item/device/warp_cube/linked + +/obj/item/device/warp_cube/Destroy() + if(linked) + linked.linked = null + linked = null + return ..() + +/obj/item/device/warp_cube/attack_self(mob/user) + if(!linked) + to_chat(user, "[src] fizzles uselessly.") + return + + var/datum/effect/system/harmless_smoke_spread/smoke = new /datum/effect/system/harmless_smoke_spread() + smoke.set_up(1, 0, user.loc) + smoke.start() + + user.forceMove(get_turf(linked)) + feedback_add_details("warp_cube","[src.type]") + + var/datum/effect/system/harmless_smoke_spread/smoke2 = new /datum/effect/system/harmless_smoke_spread() + smoke2.set_up(1, 0, user.loc) + smoke2.start() + +/obj/item/device/warp_cube/red + name = "red cube" + desc = "A mysterious red cube." + icon_state = "red_cube" + +/obj/item/device/warp_cube/red/New() + ..() + if(!linked) + var/obj/item/device/warp_cube/blue = new(src.loc) + linked = blue + blue.linked = src + +//Meat Hook + +/obj/item/weapon/gun/magic/hook + name = "meat hook" + desc = "Mid or feed." + ammo_type = /obj/item/ammo_casing/magic/hook + icon_state = "hook" + item_state = "chain" + fire_sound = 'sound/weapons/batonextend.ogg' + max_charges = 1 + flags = NOBLUDGEON + force = 18 + +/obj/item/ammo_casing/magic/hook + name = "hook" + desc = "a hook." + projectile_type = /obj/item/projectile/hook + caliber = "hook" + icon_state = "hook" + +/obj/item/projectile/hook + name = "hook" + icon_state = "hook" + icon = 'icons/obj/lavaland/artefacts.dmi' + pass_flags = PASSTABLE + damage = 25 + armour_penetration = 100 + damage_type = BRUTE + hitsound = 'sound/effects/splat.ogg' + weaken = 3 + var/chain + +/obj/item/projectile/hook/fire(setAngle) + if(firer) + chain = firer.Beam(src, icon_state = "chain", time = INFINITY, maxdistance = INFINITY) + ..() + //TODO: root the firer until the chain returns + +/obj/item/projectile/hook/on_hit(atom/target) + . = ..() + if(isliving(target)) + var/mob/living/L = target + if(!L.anchored) + L.visible_message("[L] is snagged by [firer]'s hook!") + L.forceMove(get_turf(firer)) + +/obj/item/projectile/hook/Destroy() + qdel(chain) + return ..() + +//Immortality Talisman + +/obj/item/device/immortality_talisman + name = "Immortality Talisman" + desc = "A dread talisman that can render you completely invulnerable." + icon = 'icons/obj/lavaland/artefacts.dmi' + icon_state = "talisman" + actions_types = list(/datum/action/item_action/immortality) + var/cooldown = 0 + +/datum/action/item_action/immortality + name = "Immortality" + +/obj/item/device/immortality_talisman/Destroy(force) + if(force) + . = ..() + else + return QDEL_HINT_LETMELIVE + +/obj/item/device/immortality_talisman/attack_self(mob/user) + if(cooldown < world.time) + feedback_add_details("immortality_talisman","U") // usage + cooldown = world.time + 600 + user.visible_message("[user] vanishes from reality, leaving a a hole in their place!") + var/obj/effect/immortality_talisman/Z = new(get_turf(src.loc)) + Z.name = "hole in reality" + Z.desc = "It's shaped an awful lot like [user.name]." + Z.setDir(user.dir) + user.forceMove(Z) + user.notransform = 1 + user.status_flags |= GODMODE + spawn(100) + user.status_flags &= ~GODMODE + user.notransform = 0 + user.forceMove(get_turf(Z)) + user.visible_message("[user] pops back into reality!") + Z.can_destroy = TRUE + qdel(Z) + else + to_chat(user, "[src] is still recharging.") + +/obj/effect/immortality_talisman + icon_state = "blank" + icon = 'icons/effects/effects.dmi' + var/can_destroy = FALSE + +/obj/effect/immortality_talisman/attackby() + return + +/obj/effect/immortality_talisman/ex_act() + return + +/obj/effect/immortality_talisman/singularity_pull() + return 0 + +/obj/effect/immortality_talisman/Destroy(force) + if(!can_destroy && !force) + return QDEL_HINT_LETMELIVE + else + . = ..() \ No newline at end of file diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 649a868077d..3910baf10de 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -6,19 +6,21 @@ icon_state = "necrocrate" icon_opened = "necrocrateopen" icon_closed = "necrocrate" + burn_state = LAVA_PROOF | FIRE_PROOF + unacidable = 1 /obj/structure/closet/crate/necropolis/tendril desc = "It's watching you suspiciously." /obj/structure/closet/crate/necropolis/tendril/New() ..() - // uncomment me once these items are being implemented - /*var/loot = rand(1,25) + var/loot = rand(1,24) switch(loot) if(1) new /obj/item/device/shared_storage/red(src) if(2) - new /obj/item/clothing/suit/space/hardsuit/cult(src) + new /obj/item/clothing/head/helmet/space/cult(src) + new /obj/item/clothing/suit/space/cult(src) if(3) new /obj/item/device/soulstone/anybody(src) if(4) @@ -26,593 +28,45 @@ if(5) new /obj/item/clothing/glasses/godeye(src) if(6) - new /obj/item/weapon/reagent_containers/glass/bottle/potion/flight(src) - if(7) new /obj/item/weapon/pickaxe/diamond(src) - if(8) + if(7) new /obj/item/clothing/head/culthood(src) - new /obj/item/clothing/suit/cultrobes(src) + new /obj/item/clothing/suit/hooded/cultrobes(src) new /obj/item/weapon/bedsheet/cult(src) + if(8) + new /obj/item/organ/internal/brain/xeno(src) if(9) - new /obj/item/organ/brain/alien(src) + new /obj/item/organ/internal/heart/cursed(src) if(10) - new /obj/item/organ/heart/cursed(src) - if(11) new /obj/item/ship_in_a_bottle(src) + if(11) + new /obj/item/clothing/head/helmet/space/rig/ert/paranormal/berserker(src) + new /obj/item/clothing/suit/space/rig/ert/paranormal/berserker(src) if(12) - new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker(src) - if(13) new /obj/item/weapon/sord(src) - if(14) + if(13) new /obj/item/weapon/nullrod/scythe/talking(src) - if(15) + if(14) new /obj/item/weapon/nullrod/armblade(src) - if(16) + if(15) new /obj/item/weapon/guardiancreator(src) - if(17) + if(16) new /obj/item/borg/upgrade/modkit/aoe/turfs/andmobs(src) - if(18) + if(17) new /obj/item/device/warp_cube/red(src) - if(19) + if(18) new /obj/item/device/wisp_lantern(src) - if(20) + if(19) new /obj/item/device/immortality_talisman(src) - if(21) + if(20) new /obj/item/weapon/gun/magic/hook(src) - if(22) + if(21) new /obj/item/voodoo(src) - if(23) + if(22) new /obj/item/weapon/grenade/clusterbuster/inferno(src) - if(24) + if(23) new /obj/item/weapon/reagent_containers/food/drinks/bottle/holywater/hell(src) - new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor(src) - if(25) - new /obj/item/weapon/spellbook/oneuse/summonitem(src)*/ - -///Bosses - -//Dragon - -/obj/structure/closet/crate/necropolis/dragon - name = "dragon chest" - -/obj/structure/closet/crate/necropolis/dragon/New() - ..() - var/loot = rand(1,4) - switch(loot) - if(1) - new /obj/item/weapon/melee/ghost_sword(src) - if(2) - new /obj/item/weapon/lava_staff(src) - if(3) - new /obj/item/weapon/spellbook/oneuse/sacredflame(src) - new /obj/item/weapon/gun/magic/wand/fireball(src) - if(4) - new /obj/item/weapon/dragons_blood(src) - -/obj/item/weapon/melee/ghost_sword - name = "spectral blade" - desc = "A rusted and dulled blade. It doesn't look like it'd do much damage. It glows weakly." - icon_state = "spectral" - item_state = "spectral" - flags = CONDUCT - sharp = 1 - edge = 1 - w_class = 4 - force = 1 - throwforce = 1 - hitsound = 'sound/effects/ghost2.ogg' - attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "rended") - var/summon_cooldown = 0 - var/list/mob/dead/observer/spirits - -/obj/item/weapon/melee/ghost_sword/New() - ..() - spirits = list() - processing_objects.Add(src) - poi_list |= src - -/obj/item/weapon/melee/ghost_sword/Destroy() - for(var/mob/dead/observer/G in spirits) - G.invisibility = initial(G.invisibility) - spirits.Cut() - processing_objects.Remove(src) - poi_list -= src - . = ..() - -/obj/item/weapon/melee/ghost_sword/attack_self(mob/user) - if(summon_cooldown > world.time) - to_chat(user, "You just recently called out for aid. You don't want to annoy the spirits.") - return - to_chat(user, "You call out for aid, attempting to summon spirits to your side.") - - notify_ghosts("[user] is raising their [src], calling for your help!", enter_link="(Click to help)", source = user, action = NOTIFY_FOLLOW) - - summon_cooldown = world.time + 600 - -/obj/item/weapon/melee/ghost_sword/Topic(href, href_list) - if(href_list["follow"]) - var/mob/dead/observer/ghost = usr - if(istype(ghost)) - ghost.ManualFollow(src) - -/obj/item/weapon/melee/ghost_sword/process() - ghost_check() - -/obj/item/weapon/melee/ghost_sword/proc/ghost_check() - var/ghost_counter = 0 - var/turf/T = get_turf(src) - var/list/contents = T.GetAllContents() - var/mob/dead/observer/current_spirits = list() - - for(var/mob/dead/observer/O in player_list) - if(is_type_in_list(O.following, contents)) - ghost_counter++ - O.invisibility = 0 - current_spirits |= O - - for(var/mob/dead/observer/G in spirits - current_spirits) - G.invisibility = initial(G.invisibility) - - spirits = current_spirits - - return ghost_counter - -/obj/item/weapon/melee/ghost_sword/attack(mob/living/target, mob/living/carbon/human/user) - force = 0 - var/ghost_counter = ghost_check() - - force = Clamp((ghost_counter * 4), 0, 75) - user.visible_message("[user] strikes with the force of [ghost_counter] vengeful spirits!") - ..() - -/obj/item/weapon/melee/ghost_sword/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type) - var/ghost_counter = ghost_check() - final_block_chance += Clamp((ghost_counter * 5), 0, 75) - owner.visible_message("[owner] is protected by a ring of [ghost_counter] ghosts!") - return ..() - -// Blood - -/obj/item/weapon/dragons_blood - name = "bottle of dragons blood" - desc = "You're not actually going to drink this, are you?" - icon = 'icons/obj/wizard.dmi' - icon_state = "vial" - -/obj/item/weapon/dragons_blood/attack_self(mob/living/carbon/human/user) - if(!istype(user)) - return - - var/mob/living/carbon/human/H = user - var/random = rand(1,3) - - switch(random) - if(1) - to_chat(user, "Your flesh begins to melt! Miraculously, you seem fine otherwise.") - H.set_species("Skeleton") - if(2) - to_chat(user, "Power courses through you! You can now shift your form at will.") - if(user.mind) - var/obj/effect/proc_holder/spell/targeted/shapeshift/dragon/D = new - user.mind.AddSpell(D) - if(3) - to_chat(user, "You feel like you could walk straight through lava now.") - H.weather_immunities |= "lava" - - playsound(user.loc,'sound/items/drink.ogg', rand(10,50), 1) - qdel(src) - -/datum/disease/transformation/dragon - name = "dragon transformation" - cure_text = "nothing" - cures = list("adminordrazine") - agent = "dragon's blood" - desc = "What do dragons have to do with Space Station 13?" - stage_prob = 20 - severity = BIOHAZARD - visibility_flags = 0 - stage1 = list("Your bones ache.") - stage2 = list("Your skin feels scaley.") - stage3 = list("You have an overwhelming urge to terrorize some peasants.", "Your teeth feel sharper.") - stage4 = list("Your blood burns.") - stage5 = list("You're a fucking dragon. However, any previous allegiances you held still apply. It'd be incredibly rude to eat your still human friends for no reason.") - new_form = /mob/living/simple_animal/hostile/megafauna/dragon/lesser - -//Lava Staff - -/obj/item/weapon/lava_staff - name = "staff of lava" - desc = "The ability to fill the emergency shuttle with lava. What more could you want out of life?" - icon_state = "staffofstorms" - item_state = "staffofstorms" - icon = 'icons/obj/guns/magic.dmi' - slot_flags = SLOT_BACK - item_state = "staffofstorms" - w_class = 4 - force = 25 - damtype = BURN - hitsound = 'sound/weapons/sear.ogg' - var/turf_type = /turf/unsimulated/floor/lava // /turf/simulated/floor/plating/lava/smooth once Lavaland turfs are added - var/transform_string = "lava" - var/reset_turf_type = /turf/simulated/floor/plating/airless/asteroid // /turf/simulated/floor/plating/asteroid/basalt once Lavaland turfs are added - var/reset_string = "basalt" - var/create_cooldown = 100 - var/create_delay = 30 - var/reset_cooldown = 50 - var/timer = 0 - var/banned_turfs - -/obj/item/weapon/lava_staff/New() - . = ..() - banned_turfs = typecacheof(list(/turf/space/transit, /turf/unsimulated)) - -/obj/item/weapon/lava_staff/afterattack(atom/target, mob/user, proximity_flag, click_parameters) - ..() - if(timer > world.time) - return - - if(is_type_in_typecache(target, banned_turfs)) - return - - if(target in view(user.client.view, get_turf(user))) - - var/turf/simulated/T = get_turf(target) - if(!istype(T)) - return - if(!istype(T, turf_type)) - var/obj/effect/overlay/temp/lavastaff/L = new /obj/effect/overlay/temp/lavastaff(T) - L.alpha = 0 - animate(L, alpha = 255, time = create_delay) - user.visible_message("[user] points [src] at [T]!") - timer = world.time + create_delay + 1 - if(do_after(user, create_delay, target = T)) - user.visible_message("[user] turns \the [T] into [transform_string]!") - message_admins("[key_name_admin(user)] fired the lava staff at [get_area(target)] (JMP).") - log_game("[key_name(user)] fired the lava staff at [get_area(target)] ([T.x], [T.y], [T.z]).") - T.ChangeTurf(turf_type) - timer = world.time + create_cooldown - qdel(L) - else - timer = world.time - qdel(L) - return - else - user.visible_message("[user] turns \the [T] into [reset_string]!") - T.ChangeTurf(reset_turf_type) - timer = world.time + reset_cooldown - playsound(T,'sound/magic/Fireball.ogg', 200, 1) - -/obj/effect/overlay/temp/lavastaff - icon_state = "lavastaff_warn" - duration = 50 - -// Bubblegum - -/obj/structure/closet/crate/necropolis/bubblegum - name = "bubblegum chest" - -/obj/structure/closet/crate/necropolis/bubblegum/New() - ..() - var/loot = rand(1,3) - switch(loot) - if(1) - new /obj/item/mayhem(src) - if(2) - new /obj/item/blood_contract(src) - if(3) - new /obj/item/weapon/gun/magic/staff/spellblade(src) - -// Mayhem - -/obj/item/mayhem - name = "mayhem in a bottle" - desc = "A magically infused bottle of blood, the scent of which will drive anyone nearby into a murderous frenzy." - icon = 'icons/obj/wizard.dmi' - icon_state = "vial" - -/obj/item/mayhem/attack_self(mob/user) - for(var/mob/living/carbon/human/H in range(7,user)) - spawn() - var/obj/effect/mine/pickup/bloodbath/B = new(H) - B.mineEffect(H) - to_chat(user, "You shatter the bottle!") - playsound(user.loc, 'sound/effects/Glassbr1.ogg', 100, 1) - qdel(src) - -// Blood Contract - -/obj/item/blood_contract - name = "blood contract" - icon = 'icons/obj/wizard.dmi' - icon_state = "scroll2" - color = "#FF0000" - desc = "Mark your target for death." - var/used = FALSE - -/obj/item/blood_contract/attack_self(mob/user) - if(used) - return - - used = TRUE - var/choice = input(user,"Who do you want dead?","Choose Your Victim") as null|anything in player_list - - if(!choice) - used = FALSE - return - else if(!isliving(choice)) - to_chat(user, "[choice] is already dead!") - used = FALSE - return - else - var/mob/living/L = choice - - message_admins("[key_name_admin(L)] has been marked for death by [key_name_admin(user)].") - log_admin("[key_name(L)] has been marked for death by [key_name(user)].") - - var/datum/objective/survive/survive = new - survive.owner = L.mind - L.mind.objectives += survive - to_chat(L, "You've been marked for death! Don't let the demons get you!") - L.color = "#FF0000" - spawn() - var/obj/effect/mine/pickup/bloodbath/B = new(L) - B.mineEffect(L) - - for(var/mob/living/carbon/human/H in player_list) - if(H == L) - continue - to_chat(H, "You have an overwhelming desire to kill [L]. They have been marked red! Go kill them!") - H.put_in_hands(new /obj/item/weapon/kitchen/knife/butcher(H)) - - qdel(src) - -// Legion - -// Staff of Storms - -/obj/item/weapon/staff/storm - name = "staff of storms" - desc = "An ancient staff retrieved from the remains of Legion. The wind stirs as you move it." - icon_state = "staffofstorms" - item_state = "staffofstorms" - icon = 'icons/obj/guns/magic.dmi' - slot_flags = SLOT_BACK - item_state = "staffofstorms" - w_class = 4 - force = 25 - damtype = BURN - hitsound = 'sound/weapons/sear.ogg' - var/storm_type = /datum/weather/ash_storm - var/storm_cooldown = 0 - -/obj/item/weapon/staff/storm/attack_self(mob/user) - if(storm_cooldown > world.time) - to_chat(user, "The staff is still recharging!") - return - - var/area/user_area = get_area(user) - var/datum/weather/A - var/z_level_name = space_manager.levels_by_name[user.z] - for(var/V in weather_master.existing_weather) - var/datum/weather/W = V - if(W.target_z == z_level_name && W.area_type == user_area.type) - A = W - break - if(A) - - if(A.stage != END_STAGE) - if(A.stage == WIND_DOWN_STAGE) - to_chat(user, "The storm is already ending! It would be a waste to use the staff now.") - return - user.visible_message("[user] holds [src] skywards as an orange beam travels into the sky!", \ - "You hold [src] skyward, dispelling the storm!") - playsound(user, 'sound/magic/Staff_Change.ogg', 200, 0) - A.wind_down() - return - else - A = new storm_type - A.name = "staff storm" - A.area_type = user_area.type - A.target_z = z_level_name - A.telegraph_duration = 100 - A.end_duration = 100 - - user.visible_message("[user] holds [src] skywards as red lightning crackles into the sky!", \ - "You hold [src] skyward, calling down a terrible storm!") - playsound(user, 'sound/magic/Staff_Change.ogg', 200, 0) - A.telegraph() - storm_cooldown = world.time + 200 - -// Hierophant - -//Hierophant - -/obj/item/weapon/hierophant_staff - name = "Hierophant's staff" - desc = "A large club with intense magic power infused into it." - icon_state = "hierophant_staff" - item_state = "hierophant_staff" - icon = 'icons/obj/guns/magic.dmi' - slot_flags = SLOT_BACK - w_class = 4 - force = 20 - hitsound = "swing_hit" - //hitsound = 'sound/weapons/sonic_jackhammer.ogg' - actions_types = list(/datum/action/item_action/vortex_recall, /datum/action/item_action/toggle_unfriendly_fire) - var/cooldown_time = 20 //how long the cooldown between non-melee ranged attacks is - var/chaser_cooldown = 101 //how long the cooldown between firing chasers at mobs is - var/chaser_timer = 0 //what our current chaser cooldown is - var/timer = 0 //what our current cooldown is - var/blast_range = 3 //how long the cardinal blast's walls are - var/obj/effect/hierophant/rune //the associated rune we teleport to - var/teleporting = FALSE //if we ARE teleporting - var/friendly_fire_check = FALSE //if the blasts we make will consider our faction against the faction of hit targets - -/obj/item/weapon/hierophant_staff/afterattack(atom/target, mob/user, proximity_flag, click_parameters) - ..() - var/turf/T = get_turf(target) - if(!T || timer > world.time) - return - timer = world.time + CLICK_CD_MELEE //by default, melee attacks only cause melee blasts, and have an accordingly short cooldown - if(proximity_flag) - spawn(0) - aoe_burst(T, user) - add_logs(user, target, "fired 3x3 blast at", src) - else - if(ismineralturf(target) && get_dist(user, target) < 6) //target is minerals, we can hit it(even if we can't see it) - spawn(0) - cardinal_blasts(T, user) - timer = world.time + cooldown_time - else if(target in view(5, get_turf(user))) //if the target is in view, hit it - timer = world.time + cooldown_time - if(isliving(target) && chaser_timer <= world.time) //living and chasers off cooldown? fire one! - chaser_timer = world.time + chaser_cooldown - new /obj/effect/overlay/temp/hierophant/chaser(get_turf(user), user, target, 1.5, friendly_fire_check) - add_logs(user, target, "fired a chaser at", src) - else - spawn(0) - cardinal_blasts(T, user) //otherwise, just do cardinal blast - add_logs(user, target, "fired cardinal blast at", src) - else - to_chat(user, "That target is out of range!") //too far away - -/obj/item/weapon/hierophant_staff/ui_action_click(mob/user, actiontype) - if(actiontype == /datum/action/item_action/toggle_unfriendly_fire) //toggle friendly fire... - friendly_fire_check = !friendly_fire_check - to_chat(user, "You toggle friendly fire [friendly_fire_check ? "off":"on"]!") - return - if(user.get_active_hand() != src && user.get_inactive_hand() != src) //you need to hold the staff to teleport - to_chat(user, "You need to hold the staff in your hands to [rune ? "teleport with it" : "create a rune"]!") - return - if(!rune) - if(isturf(user.loc)) - user.visible_message("[user] holds [src] carefully in front of them, moving it in a strange pattern...", \ - "You start creating a hierophant rune to teleport to...") - timer = world.time + 51 - if(do_after(user, 50, target = user)) - var/turf/T = get_turf(user) - playsound(T,'sound/magic/Blind.ogg', 200, 1, -4) - new /obj/effect/overlay/temp/hierophant/telegraph/teleport(T, user) - var/obj/effect/hierophant/H = new/obj/effect/hierophant(T) - rune = H - user.update_action_buttons_icon() - user.visible_message("[user] creates a strange rune beneath them!", \ - "You create a hierophant rune, which you can teleport yourself and any allies to at any time!\n\ - You can remove the rune to place a new one by striking it with the staff.") - else - timer = world.time - else - to_chat(user, "You need to be on solid ground to produce a rune!") - return - if(get_dist(user, rune) <= 2) //rune too close abort - to_chat(user, "You are too close to the rune to teleport to it!") - return - if(is_blocked_turf(get_turf(rune))) - to_chat(user, "The rune is blocked by something, preventing teleportation!") - return - teleporting = TRUE //start channel - user.update_action_buttons_icon() - user.visible_message("[user] starts to glow faintly...") - timer = world.time + 50 - if(do_after(user, 40, target = user) && rune) - var/turf/T = get_turf(rune) - var/turf/source = get_turf(user) - if(is_blocked_turf(T)) - teleporting = FALSE - to_chat(user, "The rune is blocked by something, preventing teleportation!") - user.update_action_buttons_icon() - return - new /obj/effect/overlay/temp/hierophant/telegraph(T, user) - new /obj/effect/overlay/temp/hierophant/telegraph(source, user) - playsound(T,'sound/magic/blink.ogg', 200, 1) - //playsound(T,'sound/magic/Wand_Teleport.ogg', 200, 1) - playsound(source,'sound/magic/blink.ogg', 200, 1) - //playsound(source,'sound/machines/AirlockOpen.ogg', 200, 1) - if(!do_after(user, 3, target = user) || !rune) //no walking away shitlord - teleporting = FALSE - if(user) - user.update_action_buttons_icon() - return - if(is_blocked_turf(T)) - teleporting = FALSE - to_chat(user, "The rune is blocked by something, preventing teleportation!") - user.update_action_buttons_icon() - return - add_logs(user, rune, "teleported self from ([source.x],[source.y],[source.z]) to") - new /obj/effect/overlay/temp/hierophant/telegraph/teleport(T, user) - new /obj/effect/overlay/temp/hierophant/telegraph/teleport(source, user) - for(var/t in RANGE_TURFS(1, T)) - var/obj/effect/overlay/temp/hierophant/blast/B = new /obj/effect/overlay/temp/hierophant/blast(t, user, TRUE) //blasts produced will not hurt allies - B.damage = 30 - for(var/t in RANGE_TURFS(1, source)) - var/obj/effect/overlay/temp/hierophant/blast/B = new /obj/effect/overlay/temp/hierophant/blast(t, user, TRUE) //but absolutely will hurt enemies - B.damage = 30 - for(var/mob/living/L in range(1, source)) - spawn(0) - teleport_mob(source, L, T, user) //regardless, take all mobs near us along - sleep(6) //at this point the blasts detonate - else - timer = world.time - teleporting = FALSE - if(user) - user.update_action_buttons_icon() - -/obj/item/weapon/hierophant_staff/proc/teleport_mob(turf/source, mob/M, turf/target, mob/user) - var/turf/turf_to_teleport_to = get_step(target, get_dir(source, M)) //get position relative to caster - if(!turf_to_teleport_to || is_blocked_turf(turf_to_teleport_to)) - return - animate(M, alpha = 0, time = 2, easing = EASE_OUT) //fade out - sleep(1) - if(!M) - return - M.visible_message("[M] fades out!") - sleep(2) - if(!M) - return - M.forceMove(turf_to_teleport_to) - sleep(1) - if(!M) - return - animate(M, alpha = 255, time = 2, easing = EASE_IN) //fade IN - sleep(1) - if(!M) - return - M.visible_message("[M] fades in!") - if(user != M) - add_logs(user, M, "teleported", null, "from ([source.x],[source.y],[source.z])") - -/obj/item/weapon/hierophant_staff/proc/cardinal_blasts(turf/T, mob/living/user) //fire cardinal cross blasts with a delay - if(!T) - return - new /obj/effect/overlay/temp/hierophant/telegraph/cardinal(T, user) - playsound(T,'sound/magic/blink.ogg', 200, 1) - //playsound(T,'sound/effects/bin_close.ogg', 200, 1) - sleep(2) - new /obj/effect/overlay/temp/hierophant/blast(T, user, friendly_fire_check) - for(var/d in cardinal) - spawn(0) - blast_wall(T, d, user) - -/obj/item/weapon/hierophant_staff/proc/blast_wall(turf/T, dir, mob/living/user) //make a wall of blasts blast_range tiles long - if(!T) - return - var/range = blast_range - var/turf/previousturf = T - var/turf/J = get_step(previousturf, dir) - for(var/i in 1 to range) - if(!J) - return - new /obj/effect/overlay/temp/hierophant/blast(J, user, friendly_fire_check) - previousturf = J - J = get_step(previousturf, dir) - -/obj/item/weapon/hierophant_staff/proc/aoe_burst(turf/T, mob/living/user) //make a 3x3 blast around a target - if(!T) - return - new /obj/effect/overlay/temp/hierophant/telegraph(T, user) - playsound(T,'sound/magic/blink.ogg', 200, 1) - //playsound(T,'sound/effects/bin_close.ogg', 200, 1) - sleep(2) - for(var/t in RANGE_TURFS(1, T)) - new /obj/effect/overlay/temp/hierophant/blast(t, user, friendly_fire_check) \ No newline at end of file + new /obj/item/clothing/head/helmet/space/rig/ert/paranormal/inquisitor(src) + new /obj/item/clothing/suit/space/rig/ert/paranormal/inquisitor(src) + if(24) + new /obj/item/weapon/spellbook/oneuse/summonitem(src) \ No newline at end of file diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm index 6027a0272d8..defa8a930ff 100644 --- a/code/modules/mining/mine_items.dm +++ b/code/modules/mining/mine_items.dm @@ -200,7 +200,6 @@ /obj/structure/closet/crate/miningcar desc = "A mining car. This one doesn't work on rails, but has to be dragged." name = "mining car (not for rails)" - icon = 'icons/obj/storage.dmi' icon_state = "miningcar" density = 1 icon_opened = "miningcaropen" diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 07ba42b69d7..d0289e1f32e 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -309,7 +309,7 @@ Stun(2) var/obj/item/organ/internal/eyes/E = get_int_organ(/obj/item/organ/internal/eyes) - if(!E) + if(!E || (E && E.weld_proof)) return switch(damage) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index abc2c0186d3..f9e2b42d68b 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -721,8 +721,6 @@ if(istype(id)) return id - - /mob/living/carbon/human/update_sight() if(!client) return @@ -1532,12 +1530,6 @@ if(species.default_language) add_language(species.default_language) - see_in_dark = species.darksight - if(see_in_dark > 2) - see_invisible = SEE_INVISIBLE_LEVEL_ONE - else - see_invisible = SEE_INVISIBLE_LIVING - hunger_drain = species.hunger_drain digestion_ratio = species.digestion_ratio @@ -1607,8 +1599,17 @@ dna.real_name = real_name species.handle_post_spawn(src) + + see_in_dark = species.get_resultant_darksight(src) + if(see_in_dark > 2) + see_invisible = SEE_INVISIBLE_LEVEL_ONE + else + see_invisible = SEE_INVISIBLE_LIVING + species.handle_dna(src) //Give them whatever special dna business they got. + update_client_colour(0) + spawn(0) overlays.Cut() update_mutantrace(1) @@ -1631,7 +1632,6 @@ return null return species.default_language ? all_languages[species.default_language] : null - /mob/living/carbon/human/proc/bloody_doodle() set category = "IC" set name = "Write in blood" diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index 4e90d763e9e..c375d718e3d 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -119,6 +119,7 @@ if(G.vision_flags || G.darkness_view || G.invis_override || G.invis_view) update_sight() update_inv_glasses() + update_client_colour() else if(I == head) head = null if(I.flags & BLOCKHAIR || I.flags & BLOCKHEADHAIR) @@ -271,6 +272,7 @@ if(G.vision_flags || G.darkness_view || G.invis_override || G.invis_view) update_sight() update_inv_glasses(redraw_mob) + update_client_colour() if(slot_gloves) gloves = W update_inv_gloves(redraw_mob) diff --git a/code/modules/mob/living/carbon/human/species/abductor.dm b/code/modules/mob/living/carbon/human/species/abductor.dm index 3bcade9f00d..4690529524f 100644 --- a/code/modules/mob/living/carbon/human/species/abductor.dm +++ b/code/modules/mob/living/carbon/human/species/abductor.dm @@ -7,8 +7,16 @@ language = "Abductor Mindlink" default_language = "Abductor Mindlink" unarmed_type = /datum/unarmed_attack/punch - darksight = 3 eyes = "blank_eyes" + has_organ = list( + "heart" = /obj/item/organ/internal/heart, + "lungs" = /obj/item/organ/internal/lungs, + "liver" = /obj/item/organ/internal/liver, + "kidneys" = /obj/item/organ/internal/kidneys, + "brain" = /obj/item/organ/internal/brain, + "appendix" = /obj/item/organ/internal/appendix, + "eyes" = /obj/item/organ/internal/eyes/abductor //3 darksight. + ) flags = HAS_LIPS | NO_BLOOD | NO_BREATHE diff --git a/code/modules/mob/living/carbon/human/species/apollo.dm b/code/modules/mob/living/carbon/human/species/apollo.dm index 416a1e8e88e..4c871405c8d 100644 --- a/code/modules/mob/living/carbon/human/species/apollo.dm +++ b/code/modules/mob/living/carbon/human/species/apollo.dm @@ -9,7 +9,6 @@ punchdamagelow = 0 punchdamagehigh = 1 //primitive = /mob/living/carbon/monkey/wryn - darksight = 3 slowdown = 1 warning_low_pressure = -300 hazard_low_pressure = 1 @@ -32,7 +31,7 @@ has_organ = list( "heart" = /obj/item/organ/internal/heart, "brain" = /obj/item/organ/internal/brain, - "eyes" = /obj/item/organ/internal/eyes, + "eyes" = /obj/item/organ/internal/eyes/wryn, //3 darksight. "appendix" = /obj/item/organ/internal/appendix, "antennae" = /obj/item/organ/internal/wryn/hivenode ) @@ -89,7 +88,7 @@ name_plural = "Nucleations" icobase = 'icons/mob/human_races/r_nucleation.dmi' unarmed_type = /datum/unarmed_attack/punch - blurb = "A sub-race of unforunates who have been exposed to too much supermatter radiation. As a result, \ + blurb = "A sub-race of unfortunates who have been exposed to too much supermatter radiation. As a result, \ supermatter crystal clusters have begun to grow across their bodies. Research to find a cure for this ailment \ has been slow, and so this is a common fate for veteran engineers. The supermatter crystals produce oxygen, \ negating the need for the individual to breathe. Their massive change in biology, however, renders most medicines \ @@ -109,8 +108,8 @@ reagent_tag = PROCESS_ORG has_organ = list( "heart" = /obj/item/organ/internal/heart, - "crystalized brain" = /obj/item/organ/internal/brain/crystal, - "eyes" = /obj/item/organ/internal/eyes/luminescent_crystal, + "crystallized brain" = /obj/item/organ/internal/brain/crystal, + "eyes" = /obj/item/organ/internal/eyes/luminescent_crystal, //Standard darksight of 2. "strange crystal" = /obj/item/organ/internal/nucleation/strange_crystal, "resonant crystal" = /obj/item/organ/internal/nucleation/resonant_crystal ) diff --git a/code/modules/mob/living/carbon/human/species/golem.dm b/code/modules/mob/living/carbon/human/species/golem.dm index 1bb4ba8e214..a2f2eb30467 100644 --- a/code/modules/mob/living/carbon/human/species/golem.dm +++ b/code/modules/mob/living/carbon/human/species/golem.dm @@ -40,7 +40,8 @@ has_organ = list( "brain" = /obj/item/organ/internal/brain/golem - ) + ) //Has standard darksight of 2. + suicide_messages = list( "is crumbling into dust!", "is smashing their body apart!") diff --git a/code/modules/mob/living/carbon/human/species/monkey.dm b/code/modules/mob/living/carbon/human/species/monkey.dm index dffc73d4e1d..6e29d658cfe 100644 --- a/code/modules/mob/living/carbon/human/species/monkey.dm +++ b/code/modules/mob/living/carbon/human/species/monkey.dm @@ -26,6 +26,7 @@ tail = "chimptail" bodyflags = FEET_PADDED | HAS_TAIL reagent_tag = PROCESS_ORG + //Has standard darksight of 2. //unarmed_types = list(/datum/unarmed_attack/bite, /datum/unarmed_attack/claws) //inherent_verbs = list(/mob/living/proc/ventcrawl) @@ -54,7 +55,7 @@ /datum/species/monkey/handle_dna(var/mob/living/carbon/human/H) H.dna.SetSEState(MONKEYBLOCK,1) - genemutcheck(H, MONKEYBLOCK) + genemutcheck(H,MONKEYBLOCK,null,MUTCHK_FORCED) /datum/species/monkey/handle_can_equip(obj/item/I, slot, disable_warning = 0, mob/living/carbon/human/user) switch(slot) @@ -105,6 +106,15 @@ base_color = "#000000" tail = "farwatail" reagent_tag = PROCESS_ORG + has_organ = list( + "heart" = /obj/item/organ/internal/heart, + "lungs" = /obj/item/organ/internal/lungs, + "liver" = /obj/item/organ/internal/liver/tajaran, + "kidneys" = /obj/item/organ/internal/kidneys, + "brain" = /obj/item/organ/internal/brain, + "appendix" = /obj/item/organ/internal/appendix, + "eyes" = /obj/item/organ/internal/eyes/tajaran/farwa //Tajara monkey-forms are uniquely colourblind and have excellent darksight, which is why they need a subtype of their greater-form's organ.. + ) /datum/species/monkey/vulpkanin @@ -120,6 +130,15 @@ base_color = "#000000" tail = "wolpintail" reagent_tag = PROCESS_ORG + has_organ = list( + "heart" = /obj/item/organ/internal/heart, + "lungs" = /obj/item/organ/internal/lungs, + "liver" = /obj/item/organ/internal/liver/vulpkanin, + "kidneys" = /obj/item/organ/internal/kidneys, + "brain" = /obj/item/organ/internal/brain, + "appendix" = /obj/item/organ/internal/appendix, + "eyes" = /obj/item/organ/internal/eyes/vulpkanin/wolpin //Vulpkanin monkey-forms are uniquely colourblind and have excellent darksight, which is why they need a subtype of their greater-form's organ.. + ) /datum/species/monkey/skrell diff --git a/code/modules/mob/living/carbon/human/species/plasmaman.dm b/code/modules/mob/living/carbon/human/species/plasmaman.dm index e76aaa91b02..05f24facc65 100644 --- a/code/modules/mob/living/carbon/human/species/plasmaman.dm +++ b/code/modules/mob/living/carbon/human/species/plasmaman.dm @@ -20,6 +20,8 @@ heat_level_2 = 400 // Heat damage level 2 above this point. heat_level_3 = 500 // Heat damage level 3 above this point. + //Has default darksight of 2. + suicide_messages = list( "is twisting their own neck!", "is letting some O2 in!", diff --git a/code/modules/mob/living/carbon/human/species/shadow.dm b/code/modules/mob/living/carbon/human/species/shadow.dm index 66a62f1b10c..6f594768d4e 100644 --- a/code/modules/mob/living/carbon/human/species/shadow.dm +++ b/code/modules/mob/living/carbon/human/species/shadow.dm @@ -7,15 +7,14 @@ default_language = "Galactic Common" unarmed_type = /datum/unarmed_attack/claws - - darksight = 8 - + ignored_by = list(/mob/living/simple_animal/hostile/faithless) blood_color = "#CCCCCC" flesh_color = "#AAAAAA" has_organ = list( - "brain" = /obj/item/organ/internal/brain + "brain" = /obj/item/organ/internal/brain, + "eyes" = /obj/item/organ/internal/eyes/shadow //8 darksight. ) flags = NO_BLOOD | NO_BREATHE | RADIMMUNE @@ -23,7 +22,7 @@ oxy_mod = 0 virus_immune = 1 - + dietflags = DIET_OMNI //the mutation process allowed you to now digest all foods regardless of initial race reagent_tag = PROCESS_ORG suicide_messages = list( @@ -31,10 +30,10 @@ "is jamming their claws into their eye sockets!", "is twisting their own neck!", "is staring into the closest light source!") - + var/grant_vision_toggle = 1 var/datum/action/innate/shadow/darkvision/vision_toggle - + /datum/action/innate/shadow/darkvision //Darkvision toggle so shadowpeople can actually see where darkness is name = "Toggle Darkvision" check_flags = AB_CHECK_CONSCIOUS @@ -49,13 +48,13 @@ else H.vision_type = null to_chat(H, "You adjust your vision to recognize the shadows.") - + /datum/species/shadow/grant_abilities(var/mob/living/carbon/human/H) . = ..() if(grant_vision_toggle) vision_toggle = new vision_toggle.Grant(H) - + /datum/species/shadow/remove_abilities(var/mob/living/carbon/human/H) . = ..() if(grant_vision_toggle && vision_toggle) diff --git a/code/modules/mob/living/carbon/human/species/skeleton.dm b/code/modules/mob/living/carbon/human/species/skeleton.dm index 4a3b087e93d..d09c8dd1699 100644 --- a/code/modules/mob/living/carbon/human/species/skeleton.dm +++ b/code/modules/mob/living/carbon/human/species/skeleton.dm @@ -41,7 +41,7 @@ "is twisting their skull off!") has_organ = list( "brain" = /obj/item/organ/internal/brain/golem, - ) + ) //Has default darksight of 2. /datum/species/skeleton/handle_reagents(var/mob/living/carbon/human/H, var/datum/reagent/R) // Crazylemon is still silly diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index 7745f950aec..d8769a3acea 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -49,8 +49,7 @@ var/siemens_coeff = 1 //base electrocution coefficient var/invis_sight = SEE_INVISIBLE_LIVING - var/darksight = 2 - + var/hazard_high_pressure = HAZARD_HIGH_PRESSURE // Dangerously high pressure. var/warning_high_pressure = WARNING_HIGH_PRESSURE // High pressure warning. var/warning_low_pressure = WARNING_LOW_PRESSURE // Low pressure warning. @@ -85,7 +84,7 @@ var/ventcrawler = 0 //Determines if the mob can go through the vents. var/has_fine_manipulation = 1 // Can use small items. - + var/mob/living/list/ignored_by = list() // list of mobs that will ignore this species var/list/allowed_consumed_mobs = list() //If a species can consume mobs, put the type of mobs it can consume here. @@ -588,12 +587,23 @@ It'll return null if the organ doesn't correspond, so include null checks when u return null return has_organ[organ_slot] +/datum/species/proc/get_resultant_darksight(mob/living/carbon/human/H) //Returns default value of 2 if the mob doesn't have eyes, otherwise it grabs the eyes darksight. + var/resultant_darksight = 2 + var/obj/item/organ/internal/eyes/eyes = H.get_int_organ(/obj/item/organ/internal/eyes) + if(eyes) + resultant_darksight = eyes.get_dark_view() + return resultant_darksight /datum/species/proc/update_sight(mob/living/carbon/human/H) H.sight = initial(H.sight) - H.see_in_dark = darksight + H.see_in_dark = get_resultant_darksight(H) H.see_invisible = invis_sight + if(H.see_in_dark > 2) //Preliminary see_invisible handling as per set_species() in code\modules\mob\living\carbon\human\human.dm. + H.see_invisible = SEE_INVISIBLE_LEVEL_ONE + else + H.see_invisible = SEE_INVISIBLE_LIVING + if(H.client.eye != H) var/atom/A = H.client.eye if(A.update_remote_sight(H)) //returns 1 if we override all other sight updates. @@ -644,7 +654,7 @@ It'll return null if the organ doesn't correspond, so include null checks when u if(rig.visor && rig.visor.vision && rig.visor.active && rig.visor.vision.glasses) var/obj/item/clothing/glasses/G = rig.visor.vision.glasses if(istype(G)) - H.see_in_dark = (G.darkness_view ? G.darkness_view : darksight) // Otherwise we keep our darkness view with togglable nightvision. + H.see_in_dark = (G.darkness_view ? G.darkness_view : get_resultant_darksight(H)) // Otherwise we keep our darkness view with togglable nightvision. if(G.vision_flags) // MESONS H.sight |= G.vision_flags @@ -654,7 +664,7 @@ It'll return null if the organ doesn't correspond, so include null checks when u H.see_in_dark = max(lesser_darkview_bonus, H.see_in_dark) if(H.vision_type) - H.see_in_dark = max(H.see_in_dark, H.vision_type.see_in_dark, darksight) + H.see_in_dark = max(H.see_in_dark, H.vision_type.see_in_dark, get_resultant_darksight(H)) H.see_invisible = H.vision_type.see_invisible if(H.vision_type.light_sensitive) H.weakeyes = 1 diff --git a/code/modules/mob/living/carbon/human/species/station.dm b/code/modules/mob/living/carbon/human/species/station.dm index ec4fe892af9..1ea4387e477 100644 --- a/code/modules/mob/living/carbon/human/species/station.dm +++ b/code/modules/mob/living/carbon/human/species/station.dm @@ -18,6 +18,7 @@ worlds tumultous at best." reagent_tag = PROCESS_ORG + //Has standard darksight of 2. /datum/species/unathi name = "Unathi" @@ -30,7 +31,6 @@ tail = "sogtail" unarmed_type = /datum/unarmed_attack/claws primitive_form = "Stok" - darksight = 3 blurb = "A heavily reptillian species, Unathi (or 'Sinta as they call themselves) hail from the \ Uuosa-Eso system, which roughly translates to 'burning mother'.

Coming from a harsh, radioactive \ @@ -66,7 +66,7 @@ "kidneys" = /obj/item/organ/internal/kidneys, "brain" = /obj/item/organ/internal/brain, "appendix" = /obj/item/organ/internal/appendix, - "eyes" = /obj/item/organ/internal/eyes, + "eyes" = /obj/item/organ/internal/eyes/unathi //3 darksight. ) allowed_consumed_mobs = list(/mob/living/simple_animal/mouse, /mob/living/simple_animal/lizard, /mob/living/simple_animal/chick, /mob/living/simple_animal/chicken, @@ -91,7 +91,6 @@ language = "Siik'tajr" tail = "tajtail" unarmed_type = /datum/unarmed_attack/claws - darksight = 8 blurb = "The Tajaran race is a species of feline-like bipeds hailing from the planet of Ahdomai in the \ S'randarr system. They have been brought up into the space age by the Humans and Skrell, and have been \ @@ -126,7 +125,8 @@ "kidneys" = /obj/item/organ/internal/kidneys, "brain" = /obj/item/organ/internal/brain, "appendix" = /obj/item/organ/internal/appendix, - "eyes" = /obj/item/organ/internal/eyes, + "eyes" = /obj/item/organ/internal/eyes/tajaran /*Most Tajara see in full colour as a result of genetic augmentation, although it cost them their darksight (darksight = 2) + unless they choose otherwise by selecting the colourblind disability in character creation (darksight = 8 but colourblind).*/ ) allowed_consumed_mobs = list(/mob/living/simple_animal/mouse, /mob/living/simple_animal/chick, /mob/living/simple_animal/butterfly, /mob/living/simple_animal/parrot, @@ -152,7 +152,6 @@ primitive_form = "Wolpin" tail = "vulptail" unarmed_type = /datum/unarmed_attack/claws - darksight = 8 blurb = "Vulpkanin are a species of sharp-witted canine-pideds residing on the planet Altam just barely within the \ dual-star Vazzend system. Their politically de-centralized society and independent natures have led them to become a species and \ @@ -176,7 +175,8 @@ "kidneys" = /obj/item/organ/internal/kidneys, "brain" = /obj/item/organ/internal/brain, "appendix" = /obj/item/organ/internal/appendix, - "eyes" = /obj/item/organ/internal/eyes, + "eyes" = /obj/item/organ/internal/eyes/vulpkanin /*Most Vulpkanin see in full colour as a result of genetic augmentation, although it cost them their darksight (darksight = 2) + unless they choose otherwise by selecting the colourblind disability in character creation (darksight = 8 but colourblind).*/ ) allowed_consumed_mobs = list(/mob/living/simple_animal/mouse, /mob/living/simple_animal/lizard, /mob/living/simple_animal/chick, /mob/living/simple_animal/chicken, @@ -226,7 +226,7 @@ "kidneys" = /obj/item/organ/internal/kidneys, "brain" = /obj/item/organ/internal/brain, "appendix" = /obj/item/organ/internal/appendix, - "eyes" = /obj/item/organ/internal/eyes, + "eyes" = /obj/item/organ/internal/eyes //Default darksight of 2. ) suicide_messages = list( @@ -315,7 +315,7 @@ "kidneys" = /obj/item/organ/internal/kidneys, "brain" = /obj/item/organ/internal/brain, "appendix" = /obj/item/organ/internal/appendix, - "eyes" = /obj/item/organ/internal/eyes, + "eyes" = /obj/item/organ/internal/eyes, //Default darksight of 2. "stack" = /obj/item/organ/internal/stack/vox //Not the same as the cortical stack implant Vox Raiders spawn with. The cortical stack implant is used ) //for determining the success of the heist game-mode's 'leave nobody behind' objective, while this is just an organ. @@ -439,7 +439,7 @@ "liver" = /obj/item/organ/internal/liver, "kidneys" = /obj/item/organ/internal/kidneys, "brain" = /obj/item/organ/internal/brain, - "eyes" = /obj/item/organ/internal/eyes, + "eyes" = /obj/item/organ/internal/eyes, //Default darksight of 2. "stack" = /obj/item/organ/internal/stack/vox //Not the same as the cortical stack implant Vox Raiders spawn with. The cortical stack implant is used ) //for determining the success of the heist game-mode's 'leave nobody behind' objective, while this is just an organ. @@ -478,7 +478,7 @@ "kidneys" = /obj/item/organ/internal/kidneys, "brain" = /obj/item/organ/internal/brain, "appendix" = /obj/item/organ/internal/appendix, - "eyes" = /obj/item/organ/internal/eyes, + "eyes" = /obj/item/organ/internal/eyes //Default darksight of 2. ) allowed_consumed_mobs = list(/mob/living/simple_animal/diona) @@ -517,6 +517,7 @@ exotic_blood = "water" //ventcrawler = 1 //ventcrawling commented out butt_sprite = "slime" + //Has default darksight of 2. has_organ = list( "brain" = /obj/item/organ/internal/brain/slime @@ -685,7 +686,6 @@ default_language = "Galactic Common" language = "Psionic Communication" unarmed_type = /datum/unarmed_attack/punch - darksight = 5 // BOOSTED from 2 eyes = "grey_eyes_s" butt_sprite = "grey" @@ -696,7 +696,7 @@ "kidneys" = /obj/item/organ/internal/kidneys, "brain" = /obj/item/organ/internal/brain/grey, "appendix" = /obj/item/organ/internal/appendix, - "eyes" = /obj/item/organ/internal/eyes, + "eyes" = /obj/item/organ/internal/eyes/grey //5 darksight. ) brute_mod = 1.25 //greys are fragile @@ -714,11 +714,9 @@ /datum/species/grey/handle_dna(var/mob/living/carbon/C, var/remove) if(!remove) C.dna.SetSEState(REMOTETALKBLOCK,1,1) - C.mutations |= REMOTE_TALK genemutcheck(C,REMOTETALKBLOCK,null,MUTCHK_FORCED) else C.dna.SetSEState(REMOTETALKBLOCK,0,1) - C.mutations -= REMOTE_TALK genemutcheck(C,REMOTETALKBLOCK,null,MUTCHK_FORCED) ..() @@ -771,13 +769,13 @@ has_organ = list( "nutrient channel" = /obj/item/organ/internal/liver/diona, "neural strata" = /obj/item/organ/internal/heart/diona, - "receptor node" = /obj/item/organ/internal/diona_receptor, + "receptor node" = /obj/item/organ/internal/eyes/diona, //Default darksight of 2. "gas bladder" = /obj/item/organ/internal/brain/diona, "polyp segment" = /obj/item/organ/internal/kidneys/diona, "anchoring ligament" = /obj/item/organ/internal/appendix/diona ) - vision_organ = /obj/item/organ/internal/diona_receptor + vision_organ = /obj/item/organ/internal/eyes/diona has_limbs = list( "chest" = list("path" = /obj/item/organ/external/chest/diona), "groin" = list("path" = /obj/item/organ/external/groin/diona), @@ -883,10 +881,10 @@ has_organ = list( "brain" = /obj/item/organ/internal/brain/mmi_holder/posibrain, "cell" = /obj/item/organ/internal/cell, - "optics" = /obj/item/organ/internal/optical_sensor + "optics" = /obj/item/organ/internal/eyes/optical_sensor //Default darksight of 2. ) - vision_organ = /obj/item/organ/internal/optical_sensor + vision_organ = /obj/item/organ/internal/eyes/optical_sensor has_limbs = list( "chest" = list("path" = /obj/item/organ/external/chest/ipc), "groin" = list("path" = /obj/item/organ/external/groin/ipc), @@ -932,7 +930,6 @@ language = "Orluum" unarmed_type = /datum/unarmed_attack/punch eyes = "drask_eyes_s" - darksight = 5 speech_sounds = list('sound/voice/DraskTalk.ogg') speech_chance = 20 @@ -982,7 +979,7 @@ "heart" = /obj/item/organ/internal/heart/drask, "lungs" = /obj/item/organ/internal/lungs/drask, "metabolic strainer" = /obj/item/organ/internal/liver/drask, - "eyes" = /obj/item/organ/internal/eyes/drask, + "eyes" = /obj/item/organ/internal/eyes/drask, //5 darksight. "brain" = /obj/item/organ/internal/brain/drask ) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm index 11d6b68aeec..bd916532519 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm @@ -95,7 +95,8 @@ visible_message( "[src] devours [L]!", "You feast on [L], restoring your health!") - adjustBruteLoss(-L.maxHealth/2) + if(!is_station_level(z) && !client) //NPC monsters won't heal while on station + adjustBruteLoss(-L.maxHealth/2) L.gib() /mob/living/simple_animal/hostile/megafauna/ex_act(severity, target) diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm index 87754e1428a..0b28722e497 100644 --- a/code/modules/mob/living/simple_animal/hostile/mimic.dm +++ b/code/modules/mob/living/simple_animal/hostile/mimic.dm @@ -1,7 +1,7 @@ /mob/living/simple_animal/hostile/mimic name = "crate" desc = "A rectangular steel crate." - icon = 'icons/obj/storage.dmi' + icon = 'icons/obj/crates.dmi' icon_state = "crate" icon_living = "crate" diff --git a/code/modules/mob/living/simple_animal/posessed_object.dm b/code/modules/mob/living/simple_animal/posessed_object.dm index 70ea452381d..1473bd5990a 100644 --- a/code/modules/mob/living/simple_animal/posessed_object.dm +++ b/code/modules/mob/living/simple_animal/posessed_object.dm @@ -103,7 +103,7 @@ dir = possessed_item.dir color = possessed_item.color overlays = possessed_item.overlays - opacity = possessed_item.opacity + set_opacity(possessed_item.opacity) visible_message("[src] rises into the air and begins to float!") // Inform those around us that shit's gettin' spooky. animate_ghostly_presence(src, -1, 20, 1) diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index 8cc51882ebf..27197474c00 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -72,6 +72,8 @@ for(var/datum/alternate_appearance/AA in viewing_alternate_appearances) AA.display_to(list(src)) + update_client_colour(0) + callHook("mob_login", list("client" = client, "mob" = src)) // Calling update_interface() in /mob/Login() causes the Cyborg to immediately be ghosted; because of winget(). diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index b03062f6e4a..446ec797a76 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -194,7 +194,7 @@ animate(affecting, pixel_x = 0, pixel_y = 0, 5, 1, LINEAR_EASING) return //KJK /* if(force_down) //THIS GOES ABOVE THE RETURN LABELED KJK - affecting.set_dir(SOUTH)*///This shows how you can apply special directions based on a variable. //face up + affecting.setDir(SOUTH)*///This shows how you can apply special directions based on a variable. //face up var/shift = 0 var/adir = get_dir(assailant, affecting) @@ -204,18 +204,18 @@ shift = 8 if(dancing) //look at partner shift = 10 - assailant.set_dir(get_dir(assailant, affecting)) + assailant.setDir(get_dir(assailant, affecting)) if(GRAB_AGGRESSIVE) shift = 12 if(GRAB_NECK, GRAB_UPGRADING) shift = -10 adir = assailant.dir - affecting.set_dir(assailant.dir) + affecting.setDir(assailant.dir) affecting.loc = assailant.loc if(GRAB_KILL) shift = 0 adir = 1 - affecting.set_dir(SOUTH)//face up + affecting.setDir(SOUTH)//face up affecting.loc = assailant.loc switch(adir) @@ -254,8 +254,8 @@ force_down = 1 affecting.Weaken(3) step_to(assailant, affecting) - assailant.set_dir(EAST) //face the victim - affecting.set_dir(SOUTH) //face up //This is an example of a new feature based on the context of the location of the victim. + assailant.setDir(EAST) //face the victim + affecting.setDir(SOUTH) //face up //This is an example of a new feature based on the context of the location of the victim. */ //It means that upgrading while someone is lying on the ground would cause you to go into pin mode. state = GRAB_AGGRESSIVE icon_state = "grabbed1" @@ -268,7 +268,7 @@ assailant.visible_message("[assailant] has reinforced \his grip on [affecting] (now neck)!") state = GRAB_NECK icon_state = "grabbed+1" - assailant.set_dir(get_dir(assailant, affecting)) + assailant.setDir(get_dir(assailant, affecting)) affecting.create_attack_log("Has had their neck grabbed by [assailant.name] ([assailant.ckey])") assailant.create_attack_log("Grabbed the neck of [affecting.name] ([affecting.ckey])") log_attack("[assailant.name] ([assailant.ckey]) grabbed the neck of [affecting.name] ([affecting.ckey])") @@ -291,7 +291,7 @@ assailant.next_move = world.time + 10 affecting.AdjustLoseBreath(1) - affecting.set_dir(WEST) + affecting.setDir(WEST) adjust_position() //This is used to make sure the victim hasn't managed to yackety sax away before using the grab. @@ -378,8 +378,8 @@ affecting.Weaken(3) affecting.lying = 1 step_to(assailant, affecting) - assailant.set_dir(EAST) //face the victim - affecting.set_dir(SOUTH) //face up + assailant.setDir(EAST) //face the victim + affecting.setDir(SOUTH) //face up return else to_chat(assailant, "You are already pinning [affecting] to the ground.") diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 95fce0b9399..0a9e0e77912 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -22,6 +22,25 @@ return 0 return 1 +/mob/proc/get_screen_colour() + +/mob/proc/update_client_colour(var/time = 10) //Update the mob's client.color with an animation the specified time in length. + if(!client) //No client_colour without client. If the player logs back in they'll be back through here anyway. + return + client.colour_transition(get_screen_colour(), time = time) //Get the colour matrix we're going to transition to depending on relevance (magic glasses first, eyes second). + +/mob/living/carbon/human/get_screen_colour() //Fetch the colour matrix from wherever (e.g. eyes) so it can be compared to client.color. + . = ..() + if(.) + return . + + var/obj/item/clothing/glasses/worn_glasses = glasses + var/obj/item/organ/internal/eyes/eyes = get_int_organ(/obj/item/organ/internal/eyes) + if(istype(worn_glasses) && worn_glasses.color_view) //Check to see if they got those magic glasses and they're augmenting the colour of what the wearer sees. If they're not, color_view should be null. + return worn_glasses.color_view + else if(eyes) //If they're not, check to see if their eyes got one of them there colour matrices. Will be null if eyes are robotic/the mob isn't colourblind and they have no default colour matrix. + return eyes.get_colourmatrix() + /proc/isloyal(A) //Checks to see if the person contains a mindshield implant, then checks that the implant is actually inside of them for(var/obj/item/weapon/implant/loyalty/L in A) if(L && L.implanted) @@ -291,10 +310,10 @@ proc/muffledspeech(phrase) /mob/proc/abiotic(var/full_body = 0) - if(full_body && ((src.l_hand && !(src.l_hand.flags & ABSTRACT)) || (src.r_hand && !(src.r_hand.flags & ABSTRACT)) || (src.back || src.wear_mask))) + if(full_body && ((l_hand && !(l_hand.flags & ABSTRACT)) || (r_hand && !(r_hand.flags & ABSTRACT)) || (back || wear_mask))) return 1 - if((src.l_hand && !(src.l_hand.flags & ABSTRACT)) || (src.r_hand && !(src.r_hand.flags & ABSTRACT))) + if((l_hand && !(l_hand.flags & ABSTRACT)) || (r_hand && !(r_hand.flags & ABSTRACT))) return 1 return 0 diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 74c9528071c..8b8fafd32b7 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -276,7 +276,7 @@ for(var/obj/item/weapon/grab/G in mob) if(G.state == GRAB_NECK) - mob.set_dir(reverse_dir[direct]) + mob.setDir(reverse_dir[direct]) G.adjust_position() for(var/obj/item/weapon/grab/G in mob.grabbed_by) G.adjust_position() diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 8adc505102b..f7fb545d495 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -1,7 +1,7 @@ /mob/living/carbon/human/proc/monkeyize() var/mob/H = src H.dna.SetSEState(MONKEYBLOCK,1) - domutcheck(H, null) + genemutcheck(H,MONKEYBLOCK,null,MUTCHK_FORCED) /mob/new_player/AIize() spawning = 1 diff --git a/code/modules/power/supermatter/wall.dm b/code/modules/power/supermatter/wall.dm index e8997dee07c..afadcb23a46 100644 --- a/code/modules/power/supermatter/wall.dm +++ b/code/modules/power/supermatter/wall.dm @@ -49,7 +49,7 @@ icon_state = "smatter" temperature = T20C+80 density = 1 - opacity = 1 + set_opacity(1) blocks_air = 1 spawn(2) diff --git a/code/modules/projectiles/ammunition/energy.dm b/code/modules/projectiles/ammunition/energy.dm index 93e5d5f2bb4..d98f53ef74c 100644 --- a/code/modules/projectiles/ammunition/energy.dm +++ b/code/modules/projectiles/ammunition/energy.dm @@ -118,18 +118,6 @@ projectile_type = /obj/item/projectile/meteor select_name = "goddamn meteor" -/obj/item/ammo_casing/energy/kinetic - projectile_type = /obj/item/projectile/kinetic - select_name = "kinetic" - e_cost = 5000 - fire_sound = 'sound/weapons/Kenetic_accel.ogg' // fine spelling there chap - -/obj/item/ammo_casing/energy/kinetic/super - projectile_type = /obj/item/projectile/kinetic/super - -/obj/item/ammo_casing/energy/kinetic/hyper - projectile_type = /obj/item/projectile/kinetic/hyper - /obj/item/ammo_casing/energy/disabler projectile_type = /obj/item/projectile/beam/disabler select_name = "disable" diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 6cafcce56c3..bba922624f1 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -45,7 +45,7 @@ lefthand_file = 'icons/mob/inhands/guns_lefthand.dmi' righthand_file = 'icons/mob/inhands/guns_righthand.dmi' - var/obj/item/device/flashlight/F = null + var/obj/item/device/flashlight/gun_light = null var/can_flashlight = 0 var/list/upgrades = list() @@ -63,7 +63,7 @@ /obj/item/weapon/gun/New() ..() - if(F) + if(gun_light) verbs += /obj/item/weapon/gun/proc/toggle_gunlight build_zooming() @@ -241,27 +241,27 @@ obj/item/weapon/gun/proc/newshot() if(istype(I, /obj/item/device/flashlight/seclite)) var/obj/item/device/flashlight/seclite/S = I if(can_flashlight) - if(!F) + if(!gun_light) if(!user.unEquip(I)) return to_chat(user, "You click [S] into place on [src].") if(S.on) set_light(0) - F = S + gun_light = S I.loc = src update_icon() - update_gunlight(user) + update_gun_light(user) var/datum/action/A = new /datum/action/item_action/toggle_gunlight(src) if(loc == user) A.Grant(user) if(istype(I, /obj/item/weapon/screwdriver)) - if(F && can_flashlight) + if(gun_light && can_flashlight) for(var/obj/item/device/flashlight/seclite/S in src) to_chat(user, "You unscrew the seclite from [src].") - F = null + gun_light = null S.loc = get_turf(user) - update_gunlight(user) + update_gun_light(user) S.update_brightness(user) update_icon() for(var/datum/action/item_action/toggle_gunlight/TGL in actions) @@ -273,26 +273,26 @@ obj/item/weapon/gun/proc/newshot() ..() /obj/item/weapon/gun/proc/toggle_gunlight() - set name = "Toggle Gunlight" + set name = "Toggle Gun Light" set category = "Object" set desc = "Click to toggle your weapon's attached flashlight." - if(!F) + if(!gun_light) return var/mob/living/carbon/human/user = usr if(!isturf(user.loc)) to_chat(user, "You cannot turn the light on while in this [user.loc]!") - F.on = !F.on - to_chat(user, "You toggle the gunlight [F.on ? "on":"off"].") + gun_light.on = !gun_light.on + to_chat(user, "You toggle the gun light [gun_light.on ? "on":"off"].") playsound(user, 'sound/weapons/empty.ogg', 100, 1) - update_gunlight(user) + update_gun_light(user) -/obj/item/weapon/gun/proc/update_gunlight(mob/user = null) - if(F) - if(F.on) - set_light(F.brightness_on) +/obj/item/weapon/gun/proc/update_gun_light(mob/user = null) + if(gun_light) + if(gun_light.on) + set_light(gun_light.brightness_on) else set_light(0) update_icon() diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 7c6391a7af8..4e5bbce386c 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -30,6 +30,12 @@ else power_supply = new(src) power_supply.give(power_supply.maxcharge) + update_ammo_types() + if(selfcharge) + processing_objects.Add(src) + update_icon() + +/obj/item/weapon/gun/energy/proc/update_ammo_types() var/obj/item/ammo_casing/energy/shot for(var/i = 1, i <= ammo_type.len, i++) var/shottype = ammo_type[i] @@ -38,9 +44,6 @@ shot = ammo_type[select] fire_sound = shot.fire_sound fire_delay = shot.delay - if(selfcharge) - processing_objects.Add(src) - update_icon() /obj/item/weapon/gun/energy/Destroy() if(selfcharge) @@ -129,9 +132,9 @@ overlays += image(icon = icon, icon_state = iconState, pixel_x = ammo_x_offset * (i -1)) else overlays += image(icon = icon, icon_state = "[icon_state]_[modifystate ? "[shot.select_name]_" : ""]charge[ratio]") - if(F && can_flashlight) + if(gun_light && can_flashlight) var/iconF = "flight" - if(F.on) + if(gun_light.on) iconF = "flight_on" overlays += image(icon = icon, icon_state = iconF, pixel_x = flight_x_offset, pixel_y = flight_y_offset) if(itemState) diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm new file mode 100644 index 00000000000..7b8872f7819 --- /dev/null +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -0,0 +1,416 @@ +/obj/item/weapon/gun/energy/kinetic_accelerator + name = "proto-kinetic accelerator" + desc = "A self recharging, ranged mining tool that does increased damage in low pressure. Capable of holding up to six slots worth of mod kits." + icon_state = "kineticgun" + item_state = "kineticgun" + ammo_type = list(/obj/item/ammo_casing/energy/kinetic) + cell_type = /obj/item/weapon/stock_parts/cell/emproof + needs_permit = 0 + unique_rename = 1 + origin_tech = "combat=3;powerstorage=3;engineering=3" + weapon_weight = WEAPON_LIGHT + can_flashlight = 1 + flight_x_offset = 15 + flight_y_offset = 9 + var/overheat_time = 16 + var/holds_charge = FALSE + var/unique_frequency = FALSE // modified by KA modkits + var/overheat = FALSE + + var/max_mod_capacity = 100 + var/list/modkits = list() + + var/empty_state = "kineticgun_empty" + +/obj/item/weapon/gun/energy/kinetic_accelerator/examine(mob/user) + if(..(user, 1)) + if(max_mod_capacity) + to_chat(user, "[get_remaining_mod_capacity()]% mod capacity remaining.") + for(var/A in get_modkits()) + var/obj/item/borg/upgrade/modkit/M = A + to_chat(user, "There is a [M.name] mod installed, using [M.cost]% capacity.") + +/obj/item/weapon/gun/energy/kinetic_accelerator/attackby(obj/item/A, mob/user) + if(istype(A, /obj/item/weapon/crowbar)) + if(modkits.len) + to_chat(user, "You pry the modifications out.") + playsound(loc, 'sound/items/Crowbar.ogg', 100, 1) + for(var/obj/item/borg/upgrade/modkit/M in modkits) + M.uninstall(src) + else + to_chat(user, "There are no modifications currently installed.") + else if(istype(A, /obj/item/borg/upgrade/modkit)) + var/obj/item/borg/upgrade/modkit/MK = A + MK.install(src, user) + else + ..() + +/obj/item/weapon/gun/energy/kinetic_accelerator/proc/get_remaining_mod_capacity() + var/current_capacity_used = 0 + for(var/A in get_modkits()) + var/obj/item/borg/upgrade/modkit/M = A + current_capacity_used += M.cost + return max_mod_capacity - current_capacity_used + +/obj/item/weapon/gun/energy/kinetic_accelerator/proc/get_modkits() + . = list() + for(var/A in modkits) + . += A + +/obj/item/weapon/gun/energy/kinetic_accelerator/proc/modify_projectile(obj/item/projectile/kinetic/K) + for(var/A in get_modkits()) + var/obj/item/borg/upgrade/modkit/M = A + M.modify_projectile(K) + +/obj/item/weapon/gun/energy/kinetic_accelerator/cyborg + holds_charge = TRUE + unique_frequency = TRUE + max_mod_capacity = 80 + +/obj/item/weapon/gun/energy/kinetic_accelerator/New() + . = ..() + if(!holds_charge) + empty() + +/obj/item/weapon/gun/energy/kinetic_accelerator/shoot_live_shot() + . = ..() + attempt_reload() + +/obj/item/weapon/gun/energy/kinetic_accelerator/equipped(mob/user) + . = ..() + if(!can_shoot()) + attempt_reload() + +/obj/item/weapon/gun/energy/kinetic_accelerator/dropped() + . = ..() + if(!holds_charge) + // Put it on a delay because moving item from slot to hand + // calls dropped(). + spawn(2) + empty_if_not_held() + +/obj/item/weapon/gun/energy/kinetic_accelerator/proc/empty_if_not_held() + if(!ismob(loc)) + empty() + +/obj/item/weapon/gun/energy/kinetic_accelerator/proc/empty() + power_supply.use(5000) + update_icon() + +/obj/item/weapon/gun/energy/kinetic_accelerator/proc/attempt_reload() + if(overheat) + return + overheat = TRUE + + var/carried = 0 + if(!unique_frequency) + for(var/obj/item/weapon/gun/energy/kinetic_accelerator/K in \ + loc.GetAllContents()) + + carried++ + + carried = max(carried, 1) + else + carried = 1 + + spawn(overheat_time * carried) + reload() + +/obj/item/weapon/gun/energy/kinetic_accelerator/emp_act(severity) + return + +/obj/item/weapon/gun/energy/kinetic_accelerator/proc/reload() + power_supply.give(5000) + if(!suppressed) + playsound(loc, 'sound/weapons/kenetic_reload.ogg', 60, 1) + else if(isliving(loc)) + to_chat(loc, "[src] silently charges up.") + update_icon() + overheat = FALSE + +/obj/item/weapon/gun/energy/kinetic_accelerator/update_icon() + overlays.Cut() + if(empty_state && !can_shoot()) + overlays += empty_state + + if(gun_light && can_flashlight) + var/iconF = "flight" + if(gun_light.on) + iconF = "flight_on" + overlays += image(icon = icon, icon_state = iconF, pixel_x = flight_x_offset, pixel_y = flight_y_offset) + + +//Casing +/obj/item/ammo_casing/energy/kinetic + projectile_type = /obj/item/projectile/kinetic + select_name = "kinetic" + e_cost = 5000 + fire_sound = 'sound/weapons/Kenetic_accel.ogg' // fine spelling there chap + +/obj/item/ammo_casing/energy/kinetic/ready_proj(atom/target, mob/living/user, quiet, zone_override = "") + ..() + if(loc && istype(loc, /obj/item/weapon/gun/energy/kinetic_accelerator)) + var/obj/item/weapon/gun/energy/kinetic_accelerator/KA = loc + KA.modify_projectile(BB) + + var/turf/proj_turf = get_turf(BB) + if(!isturf(proj_turf)) + return + var/datum/gas_mixture/environment = proj_turf.return_air() + var/pressure = environment.return_pressure() + if(pressure > 50) + BB.name = "weakened [BB.name]" + var/obj/item/projectile/kinetic/K = BB + K.damage *= K.pressure_decrease + + +//Projectiles +/obj/item/projectile/kinetic + name = "kinetic force" + icon_state = null + damage = 40 + damage_type = BRUTE + flag = "bomb" + range = 3 + log_override = TRUE + + var/pressure_decrease = 0.25 + var/turf_aoe = FALSE + var/mob_aoe = 0 + var/list/hit_overlays = list() + +/obj/item/projectile/kinetic/on_range() + strike_thing() + ..() + +/obj/item/projectile/kinetic/on_hit(atom/target) + strike_thing(target) + . = ..() + +/obj/item/projectile/kinetic/proc/strike_thing(atom/target) + var/turf/target_turf = get_turf(target) + if(!target_turf) + target_turf = get_turf(src) + if(ismineralturf(target_turf)) + var/turf/simulated/mineral/M = target_turf + M.gets_drilled(firer) + var/obj/effect/overlay/temp/kinetic_blast/K = new /obj/effect/overlay/temp/kinetic_blast(target_turf) + K.color = color + for(var/type in hit_overlays) + new type(target_turf) + if(turf_aoe) + for(var/T in RANGE_TURFS(1, target_turf) - target_turf) + if(ismineralturf(T)) + var/turf/simulated/mineral/M = T + M.gets_drilled(firer) + if(mob_aoe) + for(var/mob/living/L in range(1, target_turf) - firer - target) + var/armor = L.run_armor_check(def_zone, flag, "", "", armour_penetration) + L.apply_damage(damage*mob_aoe, damage_type, def_zone, armor) + to_chat(L, "You're struck by a [name]!") + + +//Modkits +/obj/item/borg/upgrade/modkit + name = "modification kit" + desc = "An upgrade for kinetic accelerators." + icon = 'icons/obj/objects.dmi' + icon_state = "modkit" + origin_tech = "programming=2;materials=2;magnets=4" + require_module = 1 + module_type = /obj/item/weapon/robot_module/miner + var/denied_type = null + var/maximum_of_type = 1 + var/cost = 30 + var/modifier = 1 //For use in any mod kit that has numerical modifiers + +/obj/item/borg/upgrade/modkit/examine(mob/user) + if(..(user, 1)) + to_chat(user, "Occupies [cost]% of mod capacity.") + +/obj/item/borg/upgrade/modkit/attackby(obj/item/A, mob/user) + if(istype(A, /obj/item/weapon/gun/energy/kinetic_accelerator) && !issilicon(user)) + install(A, user) + else + ..() + +/obj/item/borg/upgrade/modkit/action(mob/living/silicon/robot/R) + if(..()) + return + + for(var/obj/item/weapon/gun/energy/kinetic_accelerator/cyborg/H in R.module.modules) + return install(H, usr) + +/obj/item/borg/upgrade/modkit/proc/install(obj/item/weapon/gun/energy/kinetic_accelerator/KA, mob/user) + . = TRUE + if(denied_type) + var/number_of_denied = 0 + for(var/A in KA.get_modkits()) + var/obj/item/borg/upgrade/modkit/M = A + if(istype(M, denied_type)) + number_of_denied++ + if(number_of_denied >= maximum_of_type) + . = FALSE + break + if(KA.get_remaining_mod_capacity() >= cost) + if(.) + to_chat(user, "You install the modkit.") + playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1) + user.unEquip(src) + forceMove(KA) + KA.modkits += src + else + to_chat(user, "The modkit you're trying to install would conflict with an already installed modkit. Use a crowbar to remove existing modkits.") + else + to_chat(user, "You don't have room([KA.get_remaining_mod_capacity()]% remaining, [cost]% needed) to install this modkit. Use a crowbar to remove existing modkits.") + . = FALSE + +/obj/item/borg/upgrade/modkit/proc/uninstall(obj/item/weapon/gun/energy/kinetic_accelerator/KA) + forceMove(get_turf(KA)) + KA.modkits -= src + +/obj/item/borg/upgrade/modkit/proc/modify_projectile(obj/item/projectile/kinetic/K) + + +//Range +/obj/item/borg/upgrade/modkit/range + name = "range increase" + desc = "Increases the range of a kinetic accelerator when installed." + modifier = 1 + cost = 24 //so you can fit four plus a tracer cosmetic + +/obj/item/borg/upgrade/modkit/range/modify_projectile(obj/item/projectile/kinetic/K) + K.range += modifier + + +//Damage +/obj/item/borg/upgrade/modkit/damage + name = "damage increase" + desc = "Increases the damage of kinetic accelerator when installed." + modifier = 10 + +/obj/item/borg/upgrade/modkit/damage/modify_projectile(obj/item/projectile/kinetic/K) + K.damage += modifier + + +//Cooldown +/obj/item/borg/upgrade/modkit/cooldown + name = "cooldown decrease" + desc = "Decreases the cooldown of a kinetic accelerator." + modifier = 2.5 + +/obj/item/borg/upgrade/modkit/cooldown/install(obj/item/weapon/gun/energy/kinetic_accelerator/KA, mob/user) + . = ..() + if(.) + KA.overheat_time -= modifier + +/obj/item/borg/upgrade/modkit/cooldown/uninstall(obj/item/weapon/gun/energy/kinetic_accelerator/KA) + KA.overheat_time += modifier + ..() + + +//AoE blasts +/obj/item/borg/upgrade/modkit/aoe + modifier = 0 + +/obj/item/borg/upgrade/modkit/aoe/modify_projectile(obj/item/projectile/kinetic/K) + K.name = "kinetic explosion" + if(!K.turf_aoe && !K.mob_aoe) + K.hit_overlays += /obj/effect/overlay/temp/explosion/fast + K.mob_aoe += modifier + +/obj/item/borg/upgrade/modkit/aoe/turfs + name = "mining explosion" + desc = "Causes the kinetic accelerator to destroy rock in an AoE." + denied_type = /obj/item/borg/upgrade/modkit/aoe/turfs + +/obj/item/borg/upgrade/modkit/aoe/turfs/modify_projectile(obj/item/projectile/kinetic/K) + ..() + K.turf_aoe = TRUE + +/obj/item/borg/upgrade/modkit/aoe/turfs/andmobs + name = "offensive mining explosion" + desc = "Causes the kinetic accelerator to destroy rock and damage mobs in an AoE." + maximum_of_type = 3 + modifier = 0.25 + +/obj/item/borg/upgrade/modkit/aoe/mobs + name = "offensive explosion" + desc = "Causes the kinetic accelerator to damage mobs in an AoE." + modifier = 0.2 + + +//Indoors +/obj/item/borg/upgrade/modkit/indoors + name = "decrease pressure penalty" + desc = "Increases the damage a kinetic accelerator does in a high pressure environment." + modifier = 2 + denied_type = /obj/item/borg/upgrade/modkit/indoors + maximum_of_type = 2 + cost = 40 + +/obj/item/borg/upgrade/modkit/indoors/modify_projectile(obj/item/projectile/kinetic/K) + K.pressure_decrease *= modifier + + +//Trigger Guard +/obj/item/borg/upgrade/modkit/trigger_guard + name = "modified trigger guard" + desc = "Allows creatures normally incapable of firing guns to operate the weapon when installed." + cost = 20 + denied_type = /obj/item/borg/upgrade/modkit/trigger_guard + +/obj/item/borg/upgrade/modkit/trigger_guard/install(obj/item/weapon/gun/energy/kinetic_accelerator/KA, mob/user) + . = ..() + if(.) + KA.trigger_guard = TRIGGER_GUARD_ALLOW_ALL + +/obj/item/borg/upgrade/modkit/trigger_guard/uninstall(obj/item/weapon/gun/energy/kinetic_accelerator/KA) + KA.trigger_guard = TRIGGER_GUARD_NORMAL + ..() + + +//Cosmetic + +/obj/item/borg/upgrade/modkit/chassis_mod + name = "super chassis" + desc = "Makes your KA yellow. All the fun of having a more powerful KA without actually having a more powerful KA." + cost = 0 + denied_type = /obj/item/borg/upgrade/modkit/chassis_mod + var/chassis_icon = "kineticgun_u" + var/chassis_name = "super-kinetic accelerator" + +/obj/item/borg/upgrade/modkit/chassis_mod/install(obj/item/weapon/gun/energy/kinetic_accelerator/KA, mob/user) + . = ..() + if(.) + KA.icon_state = chassis_icon + KA.name = chassis_name + +/obj/item/borg/upgrade/modkit/chassis_mod/uninstall(obj/item/weapon/gun/energy/kinetic_accelerator/KA) + KA.icon_state = initial(KA.icon_state) + KA.name = initial(KA.name) + ..() + +/obj/item/borg/upgrade/modkit/chassis_mod/orange + name = "hyper chassis" + desc = "Makes your KA orange. All the fun of having explosive blasts without actually having explosive blasts." + chassis_icon = "kineticgun_h" + chassis_name = "hyper-kinetic accelerator" + +/obj/item/borg/upgrade/modkit/tracer + name = "white tracer bolts" + desc = "Causes kinetic accelerator bolts to have a white tracer trail and explosion." + cost = 0 + denied_type = /obj/item/borg/upgrade/modkit/tracer + var/bolt_color = "#FFFFFF" + +/obj/item/borg/upgrade/modkit/tracer/modify_projectile(obj/item/projectile/kinetic/K) + K.icon_state = "ka_tracer" + K.color = bolt_color + +/obj/item/borg/upgrade/modkit/tracer/adjustable + name = "adjustable tracer bolts" + desc = "Causes kinetic accelerator bolts to have a adjustably-colored tracer trail and explosion. Use in-hand to change color." + +/obj/item/borg/upgrade/modkit/tracer/adjustable/attack_self(mob/user) + bolt_color = input(user,"Choose Color") as color diff --git a/code/modules/projectiles/guns/energy/nuclear.dm b/code/modules/projectiles/guns/energy/nuclear.dm index 8d920a7e736..ef184bd8d5b 100644 --- a/code/modules/projectiles/guns/energy/nuclear.dm +++ b/code/modules/projectiles/guns/energy/nuclear.dm @@ -37,14 +37,14 @@ can_flashlight = 0 // Can't attach or detach the flashlight, and override it's icon update /obj/item/weapon/gun/energy/gun/mini/New() - F = new /obj/item/device/flashlight/seclite(src) + gun_light = new /obj/item/device/flashlight/seclite(src) ..() power_supply.maxcharge = 6000 power_supply.charge = 6000 /obj/item/weapon/gun/energy/gun/mini/update_icon() ..() - if(F && F.on) + if(gun_light && gun_light.on) overlays += "mini-light" /obj/item/weapon/gun/energy/gun/hos diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index a648831cd8b..12eb34e8c54 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -84,141 +84,6 @@ ammo_type = list(/obj/item/ammo_casing/energy/mindflayer) ammo_x_offset = 2 -/obj/item/weapon/gun/energy/kinetic_accelerator - name = "proto-kinetic accelerator" - desc = "In the year 2544, only a year after the discovery of a potentially \ - world-changing substance, now colloquially referred to as plasma, the \ - Nanotrasen-UEG mining conglomerate introduced a prototype of a gun-like \ - device intended for quick, effective mining of plasma in the low \ - pressures of the solar system. Included in this presentation were \ - demonstrations of the gun being fired at collections of rocks contained \ - in vacuumed environments, obliterating them instantly while maintaining \ - the structure of the ores buried within them. Additionally, volunteers \ - were called from the crowd to have the gun used on them, only proving that \ - the gun caused little harm to objects in standard pressure. \n\ - An official from an unnamed, now long dissipated company observed this \ - presentation and offered to share their self-recharger cells, powered \ - by the user's bioelectrical field, another new and unknown technology. \ - They warned that the cells were incredibly experimental and several times \ - had injured workers, but the scientists as Nanotrasen were unable to resist \ - the money-saving potential of self recharging cells. Upon accepting this \ - offer, it took only a matter of days to prove the volatility of these cells, \ - as they exploded left and right whenever inserted into the prototype devices, \ - only throwing more money in the bin. \n\ - Whenever the Nanotrasen scientists were on the edge of giving up, a \ - breakthrough was made by head researcher Miles Parks McCollum, who \ - demonstrated that the cells could be stabilized when exposed to radium \ - then cooled with cryostylane. After this discovery, the low pressure gun, \ - now named the Kinetic Accelerator, was hastily completed and made compatible \ - with the self-recharging cells. As a result of poor testing, the currently \ - used guns lose their charge when not in use, and when two Kinetic Accelerators \ - come in proximity of one another, they will interfere with each other. Despite \ - this, the shoddy guns still see use in the mining of plasma to this day." - icon_state = "kineticgun" - item_state = "kineticgun" - ammo_type = list(/obj/item/ammo_casing/energy/kinetic) - cell_type = /obj/item/weapon/stock_parts/cell/emproof - // Apparently these are safe to carry? I'm sure goliaths would disagree. - needs_permit = 0 - unique_rename = 1 - origin_tech = "combat=3;powerstorage=3;engineering=3" - weapon_weight = WEAPON_LIGHT - can_flashlight = 1 - flight_x_offset = 15 - flight_y_offset = 9 - var/overheat_time = 16 - var/holds_charge = FALSE - var/unique_frequency = FALSE // modified by KA modkits - var/overheat = FALSE - -/obj/item/weapon/gun/energy/kinetic_accelerator/super - name = "super-kinetic accelerator" - desc = "An upgraded, superior version of the proto-kinetic accelerator." - icon_state = "kineticgun_u" - ammo_type = list(/obj/item/ammo_casing/energy/kinetic/super) - overheat_time = 15 - origin_tech = "combat=3;powerstorage=2" - -/obj/item/weapon/gun/energy/kinetic_accelerator/hyper - name = "hyper-kinetic accelerator" - desc = "An upgraded, even more superior version of the proto-kinetic accelerator." - icon_state = "kineticgun_h" - ammo_type = list(/obj/item/ammo_casing/energy/kinetic/hyper) - overheat_time = 14 - origin_tech = "combat=4;powerstorage=3" - -/obj/item/weapon/gun/energy/kinetic_accelerator/cyborg - holds_charge = TRUE - unique_frequency = TRUE - -/obj/item/weapon/gun/energy/kinetic_accelerator/hyper/cyborg - holds_charge = TRUE - unique_frequency = TRUE - -/obj/item/weapon/gun/energy/kinetic_accelerator/New() - . = ..() - if(!holds_charge) - empty() - -/obj/item/weapon/gun/energy/kinetic_accelerator/shoot_live_shot() - . = ..() - attempt_reload() - -/obj/item/weapon/gun/energy/kinetic_accelerator/equipped(mob/user) - . = ..() - if(!can_shoot()) - attempt_reload() - -/obj/item/weapon/gun/energy/kinetic_accelerator/dropped() - . = ..() - if(!holds_charge) - // Put it on a delay because moving item from slot to hand - // calls dropped(). - spawn(1) - if(!ismob(loc)) - empty() - -/obj/item/weapon/gun/energy/kinetic_accelerator/proc/empty() - power_supply.use(5000) - update_icon() - -/obj/item/weapon/gun/energy/kinetic_accelerator/proc/attempt_reload() - if(overheat) - return - overheat = TRUE - - var/carried = 0 - if(!unique_frequency) - for(var/obj/item/weapon/gun/energy/kinetic_accelerator/K in \ - loc.GetAllContents()) - - carried++ - - carried = max(carried, 1) - else - carried = 1 - - spawn(overheat_time * carried) - reload() - overheat = FALSE - -/obj/item/weapon/gun/energy/kinetic_accelerator/emp_act(severity) - return - -/obj/item/weapon/gun/energy/kinetic_accelerator/proc/reload() - power_supply.give(5000) - if(!suppressed) - playsound(loc, 'sound/weapons/kenetic_reload.ogg', 60, 1) - else if(ismob(loc)) - to_chat(loc, "[src] silently charges up.") - update_icon() - -/obj/item/weapon/gun/energy/kinetic_accelerator/update_icon() - if(!can_shoot()) - icon_state = "[initial(icon_state)]_empty" - else - icon_state = initial(icon_state) - /obj/item/weapon/gun/energy/kinetic_accelerator/crossbow name = "mini energy crossbow" desc = "A weapon favored by syndicate stealth specialists." @@ -234,6 +99,9 @@ overheat_time = 20 holds_charge = TRUE unique_frequency = TRUE + can_flashlight = 0 + max_mod_capacity = 0 + empty_state = null /obj/item/weapon/gun/energy/kinetic_accelerator/crossbow/ninja name = "energy dart thrower" diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 7b0bcda17d0..4a3afd18684 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -52,7 +52,7 @@ var/forcedodge = 0 //to pass through everything var/dismemberment = 0 //The higher the number, the greater the bonus to dismembering. 0 will not dismember at all. - var/log = 1 //whether print to admin attack logs or just keep it in the diary + var/log_override = FALSE //whether print to admin attack logs or just keep it in the diary /obj/item/projectile/New() permutated = list() @@ -90,7 +90,8 @@ for(var/datum/reagent/R in reagents.reagent_list) reagent_note += R.id + " (" reagent_note += num2text(R.volume) + ") " - add_logs(firer, L, "shot", src, reagent_note, print_attack_log = log) + if(!log_override && firer && original) + add_logs(firer, L, "shot", src, reagent_note) return L.apply_effects(stun, weaken, paralyze, irradiate, slur, stutter, eyeblur, drowsy, blocked, stamina, jitter) /obj/item/projectile/proc/vol_by_damage() diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index 872ee7c3f26..6cddc1c1b91 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -20,7 +20,7 @@ name = "practice laser" damage = 0 nodamage = 1 - log = 0 + log_override = TRUE /obj/item/projectile/beam/scatter name = "laser pellet" @@ -75,7 +75,7 @@ damage_type = STAMINA flag = "laser" var/suit_types = list(/obj/item/clothing/suit/redtag, /obj/item/clothing/suit/bluetag) - log = 0 + log_override = TRUE /obj/item/projectile/beam/lasertag/on_hit(atom/target, blocked = 0) . = ..() diff --git a/code/modules/projectiles/projectile/reusable.dm b/code/modules/projectiles/projectile/reusable.dm index 17aaad71a2a..cb0ee34ad75 100644 --- a/code/modules/projectiles/projectile/reusable.dm +++ b/code/modules/projectiles/projectile/reusable.dm @@ -37,7 +37,7 @@ var/obj/item/weapon/pen/pen = null edge = 0 embed = 0 - log = 0//it won't log even when there's a pen inside, but since the damage will be so low, I don't think there's any point in making it any more complex + log_override = TRUE//it won't log even when there's a pen inside, but since the damage will be so low, I don't think there's any point in making it any more complex /obj/item/projectile/bullet/reusable/foam_dart/handle_drop() if(dropped) @@ -65,4 +65,4 @@ icon_state = "foamdart_riot" ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot stamina = 25 - log = 1 + log_override = FALSE diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm index b1cdef1f73c..83a4ec0650c 100644 --- a/code/modules/projectiles/projectile/special.dm +++ b/code/modules/projectiles/projectile/special.dm @@ -201,62 +201,6 @@ playsound(src, 'sound/effects/snap.ogg', 50, 1) qdel(src) -/obj/item/projectile/kinetic - name = "kinetic force" - icon_state = null - damage = 10 - damage_type = BRUTE - flag = "bomb" - range = 3 - var/splash = 0 - -/obj/item/projectile/kinetic/super - damage = 11 - range = 4 - -/obj/item/projectile/kinetic/hyper - damage = 12 - range = 5 - splash = 1 - -obj/item/projectile/kinetic/New() - var/turf/proj_turf = get_turf(src) - if(!istype(proj_turf, /turf)) - return - var/datum/gas_mixture/environment = proj_turf.return_air() - var/pressure = environment.return_pressure() - if(pressure < 50) - name = "full strength kinetic force" - damage *= 4 - ..() - -/obj/item/projectile/kinetic/on_range() - new /obj/effect/kinetic_blast(loc) - ..() - -/obj/item/projectile/kinetic/on_hit(atom/target) - . = ..() - var/turf/target_turf= get_turf(target) - if(istype(target_turf, /turf/simulated/mineral)) - var/turf/simulated/mineral/M = target_turf - M.gets_drilled(firer) - new /obj/effect/kinetic_blast(target_turf) - if(splash) - for(var/turf/T in range(splash, target_turf)) - if(istype(T, /turf/simulated/mineral)) - var/turf/simulated/mineral/M = T - M.gets_drilled(firer) - -/obj/effect/kinetic_blast - name = "kinetic explosion" - icon = 'icons/obj/projectiles.dmi' - icon_state = "kinetic_blast" - layer = 4.1 - -/obj/effect/kinetic_blast/New() - spawn(4) - qdel(src) - /obj/item/projectile/beam/wormhole name = "bluespace beam" icon_state = "spark" diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index 0f6e202ba07..db77f30e76b 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -1,7 +1,3 @@ -#define SOLID 1 -#define LIQUID 2 -#define GAS 3 - /datum/reagent var/name = "Reagent" var/id = "reagent" diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm index 2785683e378..3d57f950995 100644 --- a/code/modules/recycling/conveyor2.dm +++ b/code/modules/recycling/conveyor2.dm @@ -50,7 +50,7 @@ dir = newdir update_move_direction() -/obj/machinery/conveyor/set_dir(newdir) +/obj/machinery/conveyor/setDir(newdir) . = ..() update_move_direction() diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 5ea86d2c7a3..779a0809577 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -1038,16 +1038,6 @@ construction_time = 120 category = list("Cyborg Upgrade Modules") -/datum/design/borg_upgrade_hyperka - name = "Cyborg Upgrade (Hyper-Kinetic Accelerator)" - id = "borg_upgrade_hyperka" - req_tech = list("materials" = 7, "powerstorage" = 5, "engineering" = 5, "magnets" = 5, "combat" = 4) - build_type = MECHFAB //Reqs same as human Hyper KA - materials = list(MAT_METAL = 8000, MAT_GLASS = 1500, MAT_SILVER = 2000, MAT_GOLD = 2000, MAT_DIAMOND = 2000) - build_path = /obj/item/borg/upgrade/hyperka - construction_time = 120 - category = list("Cyborg Upgrade Modules") - /datum/design/borg_syndicate_module name = "Cyborg Upgrade (Illegal Modules)" id = "borg_syndicate_module" @@ -1110,7 +1100,7 @@ name = "IPC Optical Sensor" id = "ipc_optics" build_type = MECHFAB - build_path = /obj/item/organ/internal/optical_sensor + build_path = /obj/item/organ/internal/eyes/optical_sensor materials = list(MAT_METAL=1000, MAT_GLASS=2500) construction_time = 200 category = list("Misc") diff --git a/code/modules/research/designs/mining_designs.dm b/code/modules/research/designs/mining_designs.dm index 2b7d911f2b1..aa3014e2825 100644 --- a/code/modules/research/designs/mining_designs.dm +++ b/code/modules/research/designs/mining_designs.dm @@ -64,26 +64,6 @@ build_path = /obj/item/weapon/pickaxe/drill/jackhammer category = list("Mining") -/datum/design/superaccelerator - name = "Super-Kinetic Accelerator" - desc = "An upgraded version of the proto-kinetic accelerator, with superior damage, speed and range." - id = "superaccelerator" - req_tech = list("materials" = 5, "powerstorage" = 4, "engineering" = 4, "magnets" = 4, "combat" = 3) - build_type = PROTOLATHE - materials = list(MAT_METAL = 8000, MAT_GLASS = 1500, MAT_SILVER = 2000, MAT_URANIUM = 2000) - build_path = /obj/item/weapon/gun/energy/kinetic_accelerator/super - category = list("Mining") - -/datum/design/hyperaccelerator - name = "Hyper-Kinetic Accelerator" - desc = "An upgraded version of the proto-kinetic accelerator, with even more superior damage, speed and range." - id = "hyperaccelerator" - req_tech = list("materials" = 6, "powerstorage" = 6, "engineering" = 5, "magnets" = 6, "combat" = 4) - build_type = PROTOLATHE - materials = list(MAT_METAL = 8000, MAT_GLASS = 1500, MAT_SILVER = 2000, MAT_GOLD = 2000, MAT_DIAMOND = 2000) - build_path = /obj/item/weapon/gun/energy/kinetic_accelerator/hyper - category = list("Mining") - /datum/design/superresonator name = "Upgraded Resonator" desc = "An upgraded version of the resonator that allows more fields to be active at once." @@ -92,4 +72,64 @@ build_type = PROTOLATHE materials = list(MAT_METAL = 4000, MAT_GLASS = 1500, MAT_SILVER = 2000, MAT_URANIUM = 2000) build_path = /obj/item/weapon/resonator/upgraded - category = list("Mining") \ No newline at end of file + category = list("Mining") + +/datum/design/trigger_guard_mod + name = "Kinetic Accelerator Trigger Guard Mod" + desc = "A device which allows kinetic accelerators to be wielded by any organism." + id = "triggermod" + req_tech = list("materials" = 5, "powerstorage" = 4, "engineering" = 4, "magnets" = 4, "combat" = 3) + build_type = PROTOLATHE + materials = list(MAT_METAL = 2000, MAT_GLASS = 1500, MAT_GOLD = 1500, MAT_URANIUM = 1000) + build_path = /obj/item/borg/upgrade/modkit/trigger_guard + category = list("Mining") + +/datum/design/damage_mod + name = "Kinetic Accelerator Damage Mod" + desc = "A device which allows kinetic accelerators to deal more damage." + id = "damagemod" + req_tech = list("materials" = 5, "powerstorage" = 4, "engineering" = 4, "magnets" = 4, "combat" = 3) + build_type = PROTOLATHE | MECHFAB + materials = list(MAT_METAL = 2000, MAT_GLASS = 1500, MAT_GOLD = 1500, MAT_URANIUM = 1000) + build_path = /obj/item/borg/upgrade/modkit/damage + category = list("Mining", "Cyborg Upgrade Modules") + +/datum/design/cooldown_mod + name = "Kinetic Accelerator Cooldown Mod" + desc = "A device which decreases the cooldown of a Kinetic Accelerator." + id = "cooldownmod" + req_tech = list("materials" = 5, "powerstorage" = 4, "engineering" = 4, "magnets" = 4, "combat" = 3) + build_type = PROTOLATHE | MECHFAB + materials = list(MAT_METAL = 2000, MAT_GLASS = 1500, MAT_GOLD = 1500, MAT_URANIUM = 1000) + build_path = /obj/item/borg/upgrade/modkit/cooldown + category = list("Mining", "Cyborg Upgrade Modules") + +/datum/design/range_mod + name = "Kinetic Accelerator Range Mod" + desc = "A device which allows kinetic accelerators to fire at a further range." + id = "rangemod" + req_tech = list("materials" = 5, "powerstorage" = 4, "engineering" = 4, "magnets" = 4, "combat" = 3) + build_type = PROTOLATHE | MECHFAB + materials = list(MAT_METAL = 2000, MAT_GLASS = 1500, MAT_GOLD = 1500, MAT_URANIUM = 1000) + build_path = /obj/item/borg/upgrade/modkit/range + category = list("Mining", "Cyborg Upgrade Modules") + +/datum/design/superaccelerator + name = "Kinetic Accelerator Pressure Mod" + desc = "A modification kit which allows Kinetic Accelerators to do more damage while indoors." + id = "indoormod" + req_tech = list("materials" = 5, "powerstorage" = 4, "engineering" = 4, "magnets" = 4, "combat" = 3) + build_type = PROTOLATHE | MECHFAB + materials = list(MAT_METAL = 2000, MAT_GLASS = 1500, MAT_SILVER = 2000, MAT_URANIUM = 2000) + build_path = /obj/item/borg/upgrade/modkit/indoors + category = list("Mining", "Cyborg Upgrade Modules") + +/datum/design/hyperaccelerator + name = "Kinetic Accelerator Mining AoE Mod" + desc = "A modification kit for Kinetic Accelerators which causes it to fire AoE blasts that destroy rock." + id = "hypermod" + req_tech = list("materials" = 7, "powerstorage" = 5, "engineering" = 5, "magnets" = 5, "combat" = 4) + build_type = PROTOLATHE | MECHFAB + materials = list(MAT_METAL = 8000, MAT_GLASS = 1500, MAT_SILVER = 2000, MAT_GOLD = 2000, MAT_DIAMOND = 2000) + build_path = /obj/item/borg/upgrade/modkit/aoe/turfs + category = list("Mining", "Cyborg Upgrade Modules") \ No newline at end of file diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm index e2ba439a0dd..8944cf84131 100644 --- a/code/modules/shuttle/supply.dm +++ b/code/modules/shuttle/supply.dm @@ -247,6 +247,8 @@ /obj/machinery/teleport/hub, /obj/machinery/telepad, /obj/machinery/clonepod, + /obj/effect/hierophant, + /obj/item/device/warp_cube, /obj/machinery/quantumpad ) if(A) diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm index 0d029c8e1ce..16a22ea81f6 100644 --- a/code/modules/surgery/organs/organ.dm +++ b/code/modules/surgery/organs/organ.dm @@ -228,10 +228,10 @@ var/list/organ_cache = list() /obj/item/organ/proc/take_damage(amount, var/silent=0) if(tough) return - if(src.status & ORGAN_ROBOT) - src.damage = between(0, src.damage + (amount * 0.8), max_damage) + if(status & ORGAN_ROBOT) + damage = between(0, damage + (amount * 0.8), max_damage) else - src.damage = between(0, src.damage + amount, max_damage) + damage = between(0, damage + amount, max_damage) //only show this if the organ is not robotic if(owner && parent_organ && amount > 0) @@ -241,18 +241,18 @@ var/list/organ_cache = list() /obj/item/organ/proc/robotize() //Being used to make robutt hearts, etc robotic = 2 - src.status &= ~ORGAN_BROKEN - src.status &= ~ORGAN_BLEEDING - src.status &= ~ORGAN_SPLINTED - src.status &= ~ORGAN_CUT_AWAY - src.status &= ~ORGAN_ATTACHABLE - src.status &= ~ORGAN_DESTROYED - src.status |= ORGAN_ROBOT - src.status |= ORGAN_ASSISTED + status &= ~ORGAN_BROKEN + status &= ~ORGAN_BLEEDING + status &= ~ORGAN_SPLINTED + status &= ~ORGAN_CUT_AWAY + status &= ~ORGAN_ATTACHABLE + status &= ~ORGAN_DESTROYED + status |= ORGAN_ROBOT + status |= ORGAN_ASSISTED /obj/item/organ/proc/mechassist() //Used to add things like pacemakers, etc - robotize() - src.status &= ~ORGAN_ROBOT + robotize(1) //Skip the icon/name setting that occurs in robotize to avoid having to reset the icon file. + status &= ~ORGAN_ROBOT robotic = 1 min_bruised_damage = 15 min_broken_damage = 35 @@ -325,7 +325,7 @@ var/list/organ_cache = list() affected.internal_organs |= src if(!target.get_int_organ(src)) target.internal_organs += src - src.loc = target + loc = target if(robotic) status |= ORGAN_ROBOT diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 8a5a6a6b158..8de7cccd2d6 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -201,7 +201,7 @@ /obj/item/organ/internal/heart/prepare_eat() var/obj/S = ..() - S.icon_state = "heart-off" + S.icon_state = dead_icon return S /obj/item/organ/internal/heart/cursed @@ -343,16 +343,47 @@ parent_organ = "head" slot = "eyes" var/list/eye_colour = list(0,0,0) + var/list/colourmatrix = null + var/list/colourblind_matrix = MATRIX_GREYSCALE //Special colourblindness parameters. By default, it's black-and-white. + var/colourblind_darkview = null + var/dependent_disabilities = null //Gets set by eye-dependent disabilities such as colourblindness so the eyes can transfer the disability during transplantation. + var/dark_view = 2 //Default dark_view for Humans. + var/weld_proof = null //If set, the eyes will not take damage during welding. eg. IPC optical sensors do not take damage when they weld things while all other eyes will. /obj/item/organ/internal/eyes/proc/update_colour() dna.write_eyes_attributes(src) -/obj/item/organ/internal/eyes/insert(mob/living/carbon/M, special = 0) +/obj/item/organ/internal/eyes/proc/get_colourmatrix() //Returns a special colour matrix if the eyes are organic and the mob is colourblind, otherwise it uses the current one. + if(!robotic && owner.disabilities & COLOURBLIND) + return colourblind_matrix + else + return colourmatrix + +/obj/item/organ/internal/eyes/proc/get_dark_view() //Returns dark_view (if the eyes are organic) for see_invisible handling in species.dm to be autoprocessed by life(). + if(!robotic && colourblind_darkview && owner.disabilities & COLOURBLIND) //Returns special darkview value if colourblind and it exists, otherwise reuse current. + return colourblind_darkview + else + return dark_view + +/obj/item/organ/internal/eyes/insert(mob/living/carbon/human/M, special = 0) ..() if(istype(M) && eye_colour) - var/mob/living/carbon/human/H = M - // Apply our eye colour to the target. - H.update_body() + M.update_body() //Apply our eye colour to the target. + + if(!(M.disabilities & COLOURBLIND) && (dependent_disabilities & COLOURBLIND)) //If the eyes are colourblind and we're not, carry over the gene. + dependent_disabilities &= ~COLOURBLIND + M.dna.SetSEState(COLOURBLINDBLOCK,1) + genemutcheck(M,COLOURBLINDBLOCK,null,MUTCHK_FORCED) + else + M.update_client_colour() //If we're here, that means the mob acquired the colourblindness gene while they didn't have eyes. Better handle it. + +/obj/item/organ/internal/eyes/remove(mob/living/carbon/human/M, special = 0) + if(!special && (M.disabilities & COLOURBLIND)) //If special is set, that means these eyes are getting deleted (i.e. during set_species()) + if(!(dependent_disabilities & COLOURBLIND)) //We only want to change COLOURBLINDBLOCK and such it the eyes are being surgically removed. + dependent_disabilities |= COLOURBLIND + M.dna.SetSEState(COLOURBLINDBLOCK,0) + genemutcheck(M,COLOURBLINDBLOCK,null,MUTCHK_FORCED) + . = ..() /obj/item/organ/internal/eyes/surgeryize() if(!owner) @@ -362,6 +393,38 @@ owner.SetEyeBlurry(0) owner.SetEyeBlind(0) +/obj/item/organ/internal/robotize(var/icon_bypass) //If icon bypass isn't null, skip the processing here and go straight to the parent call. + if(!icon_bypass && !(status & ORGAN_ROBOT)) //Don't override the icons for the already-mechanical IPC organs. + var/list/states = icon_states('icons/obj/surgery.dmi') //Insensitive to specially-defined icon files for species like the Drask or whomever else. Everyone gets the same robotic heart. + if(slot == "heart" && ("[slot]-prosthetic-on" in states) && ("[slot]-prosthetic-off" in states)) //Give the robotic heart its robotic heart icons if they exist. + var/obj/item/organ/internal/heart/H = src + H.icon = icon('icons/obj/surgery.dmi') + H.icon_base = "[slot]-prosthetic" + H.dead_icon = "[slot]-prosthetic-off" + H.update_icon() + else if("[slot]-prosthetic" in states) //Give the robotic organ its robotic organ icons if they exist. + icon = icon('icons/obj/surgery.dmi') + icon_state = "[slot]-prosthetic" + name = "mechanical [slot]" + ..() //Go apply all the organ flags/robotic statuses. + +/obj/item/organ/internal/eyes/robotize() + colourmatrix = null + dark_view = 2 + ..() //Make sure the organ's got the robotic status indicators before updating the client colour. + owner.update_client_colour(0) //Since both mechassisted and mechanical eyes give dark_view of 2 and full colour vision atm, just having this here is fine as mechassist() will call it anyway. + +/obj/item/organ/internal/mechassist() + ..() //Go back, call robotize(), adjust the robotic status indicators and the organ damage parameters. + var/list/states = icon_states(icon) //Sensitive to specially-defined icon files since the organs are not fully synthetic. + if(slot == "heart" && ("[organ_tag]-assisted-on" in states) && ("[organ_tag]-assisted-off" in states)) //Give the mechassisted heart its mechassisted heart icons if they exist. + var/obj/item/organ/internal/heart/H = src + H.icon_base = "[organ_tag]-assisted" + H.dead_icon = "[organ_tag]-assisted-off" + H.update_icon() + else if("[organ_tag]-assisted" in states) //Give the mechassisted organ its mechassisted organ icons if they exist. + icon_state = "[organ_tag]-assisted" + name = "mechanically assisted [initial(name)]" //Avoid setting the organ's name to something like "mechanically assisted mechanical eyes". /obj/item/organ/internal/liver name = "liver" @@ -372,7 +435,6 @@ var/alcohol_intensity = 1 /obj/item/organ/internal/liver/process() - ..() if(!owner) diff --git a/code/modules/surgery/organs/subtypes/abductor.dm b/code/modules/surgery/organs/subtypes/abductor.dm new file mode 100644 index 00000000000..6fd234bc501 --- /dev/null +++ b/code/modules/surgery/organs/subtypes/abductor.dm @@ -0,0 +1,4 @@ +/obj/item/organ/internal/eyes/abductor + name = "abductor eyeballs" + dark_view = 3 + species = "Abductor" diff --git a/code/modules/surgery/organs/subtypes/diona.dm b/code/modules/surgery/organs/subtypes/diona.dm index 48ad2fb3cea..c7044f92fb9 100644 --- a/code/modules/surgery/organs/subtypes/diona.dm +++ b/code/modules/surgery/organs/subtypes/diona.dm @@ -97,74 +97,42 @@ /obj/item/organ/diona/process() return -/obj/item/organ/internal/heart/diona +/obj/item/organ/internal/heart/diona // Turns into a nymph instantly, no transplanting possible. name = "neural strata" icon = 'icons/obj/objects.dmi' icon_state = "nymph" - organ_tag = "heart" // Turns into a nymph instantly, no transplanting possible. - origin_tech = "biotech=3" - parent_organ = "chest" - slot = "heart" species = "Diona" -/obj/item/organ/internal/brain/diona +/obj/item/organ/internal/brain/diona // Turns into a nymph instantly, no transplanting possible. name = "gas bladder" - parent_organ = "head" icon = 'icons/obj/objects.dmi' icon_state = "nymph" - organ_tag = "brain" // Turns into a nymph instantly, no transplanting possible. - origin_tech = "biotech=3" - slot = "brain" species = "Diona" -/obj/item/organ/internal/kidneys/diona +/obj/item/organ/internal/kidneys/diona // Turns into a nymph instantly, no transplanting possible. name = "polyp segment" icon = 'icons/obj/objects.dmi' icon_state = "nymph" - organ_tag = "kidneys" // Turns into a nymph instantly, no transplanting possible. - origin_tech = "biotech=3" - parent_organ = "groin" - slot = "kidneys" species = "Diona" -/obj/item/organ/internal/appendix/diona +/obj/item/organ/internal/appendix/diona // Turns into a nymph instantly, no transplanting possible. name = "anchoring ligament" icon = 'icons/obj/objects.dmi' icon_state = "nymph" - organ_tag = "appendix" // Turns into a nymph instantly, no transplanting possible. - origin_tech = "biotech=3" - parent_organ = "groin" - slot = "appendix" species = "Diona" -/obj/item/organ/internal/diona_receptor +/obj/item/organ/internal/eyes/diona // Turns into a nymph instantly, no transplanting possible. name = "receptor node" - organ_tag = "eyes" icon = 'icons/mob/alien.dmi' icon_state = "claw" - origin_tech = "biotech=3" - parent_organ = "head" - slot = "eyes" species = "Diona" -/obj/item/organ/internal/diona_receptor/surgeryize() - if(!owner) - return - owner.CureNearsighted() - owner.CureBlind() - owner.SetEyeBlurry(0) - owner.SetEyeBlind(0) - - //TODO:Make absorb rads on insert -/obj/item/organ/internal/liver/diona +/obj/item/organ/internal/liver/diona // Turns into a nymph instantly, no transplanting possible. name = "nutrient vessel" - parent_organ = "chest" - organ_tag = "liver" icon = 'icons/mob/alien.dmi' icon_state = "claw" - slot = "liver" alcohol_intensity = 0.5 species = "Diona" diff --git a/code/modules/surgery/organs/subtypes/drask.dm b/code/modules/surgery/organs/subtypes/drask.dm index b3b260a28a0..6e1e6662d0a 100644 --- a/code/modules/surgery/organs/subtypes/drask.dm +++ b/code/modules/surgery/organs/subtypes/drask.dm @@ -9,51 +9,29 @@ /obj/item/organ/internal/heart/drask name = "drask heart" icon = 'icons/obj/surgery_drask.dmi' - icon_state = "heart-on" - dead_icon = "heart-off" - organ_tag = "heart" parent_organ = "head" - slot = "heart" species = "Drask" /obj/item/organ/internal/lungs/drask - name = "lungs" icon = 'icons/obj/surgery_drask.dmi' - icon_state = "lungs" - gender = PLURAL - organ_tag = "lungs" - parent_organ = "chest" - slot = "lungs" species = "Drask" /obj/item/organ/internal/liver/drask name = "metabolic strainer" icon = 'icons/obj/surgery_drask.dmi' - icon_state = "kidneys" - gender = PLURAL - organ_tag = "kidneys" - parent_organ = "groin" - slot = "kidneys" alcohol_intensity = 0.8 species = "Drask" /obj/item/organ/internal/brain/drask - name = "brain" icon = 'icons/obj/surgery_drask.dmi' icon_state = "brain2" - organ_tag = "brain" - slot = "brain" mmi_icon = 'icons/obj/surgery_drask.dmi' mmi_icon_state = "mmi_full" species = "Drask" /obj/item/organ/internal/eyes/drask - name = "eyes" + name = "drask eyeballs" icon = 'icons/obj/surgery_drask.dmi' - icon_state = "eyes" - gender = PLURAL - organ_tag = "eyes" - parent_organ = "head" - slot = "eyes" desc = "Drask eyes. They look even stranger disembodied" + dark_view = 5 species = "Drask" diff --git a/code/modules/surgery/organs/subtypes/grey.dm b/code/modules/surgery/organs/subtypes/grey.dm index a47ab801d6f..6c06da373b7 100644 --- a/code/modules/surgery/organs/subtypes/grey.dm +++ b/code/modules/surgery/organs/subtypes/grey.dm @@ -14,3 +14,8 @@ /obj/item/organ/internal/brain/grey/remove(var/mob/living/carbon/M, var/special = 0) . = ..() M.remove_language("Psionic Communication") + +/obj/item/organ/internal/eyes/grey + name = "grey eyeballs" + dark_view = 5 + species = "Grey" diff --git a/code/modules/surgery/organs/subtypes/machine.dm b/code/modules/surgery/organs/subtypes/machine.dm index 0f402a42e5d..b3bb3f61e07 100644 --- a/code/modules/surgery/organs/subtypes/machine.dm +++ b/code/modules/surgery/organs/subtypes/machine.dm @@ -117,37 +117,26 @@ robotize() ..() -/obj/item/organ/internal/optical_sensor +/obj/item/organ/internal/eyes/optical_sensor name = "optical sensor" - organ_tag = "eyes" - parent_organ = "head" icon = 'icons/obj/robot_component.dmi' icon_state = "camera" - slot = "eyes" status = ORGAN_ROBOT species = "Machine" // dead_icon = "camera_broken" + weld_proof = 1 -/obj/item/organ/internal/optical_sensor/New() +/obj/item/organ/internal/eyes/optical_sensor/New() robotize() ..() -/obj/item/organ/internal/optical_sensor/remove(var/mob/living/user,special = 0) +/obj/item/organ/internal/eyes/optical_sensor/remove(var/mob/living/user,special = 0) if(!special) to_chat(owner, "Error 404:Optical Sensors not found.") . = ..() -/obj/item/organ/internal/optical_sensor/surgeryize() - if(!owner) - return - owner.CureNearsighted() - owner.CureBlind() - owner.SetEyeBlurry(0) - owner.SetEyeBlind(0) - - // Used for an MMI or posibrain being installed into a human. /obj/item/organ/internal/brain/mmi_holder name = "brain" @@ -160,7 +149,6 @@ species = "Machine" var/obj/item/device/mmi/stored_mmi - /obj/item/organ/internal/brain/mmi_holder/Destroy() if(stored_mmi) qdel(stored_mmi) diff --git a/code/modules/surgery/organs/subtypes/nucleation.dm b/code/modules/surgery/organs/subtypes/nucleation.dm index d234b666ae3..4223834501d 100644 --- a/code/modules/surgery/organs/subtypes/nucleation.dm +++ b/code/modules/surgery/organs/subtypes/nucleation.dm @@ -26,8 +26,6 @@ icon_state = "crystal-eyes" organ_tag = "luminescent eyes" light_color = "#1C1C00" - parent_organ = "head" - slot = "eyes" species = "Nucleation" /obj/item/organ/internal/eyes/luminescent_crystal/New() @@ -35,8 +33,7 @@ ..() /obj/item/organ/internal/brain/crystal - name = "crystalized brain" + name = "crystallized brain" icon_state = "crystal-brain" - organ_tag = "crystalized brain" - slot = "brain" + organ_tag = "crystallized brain" species = "Nucleation" diff --git a/code/modules/surgery/organs/subtypes/shadow.dm b/code/modules/surgery/organs/subtypes/shadow.dm new file mode 100644 index 00000000000..f81fc54bfb1 --- /dev/null +++ b/code/modules/surgery/organs/subtypes/shadow.dm @@ -0,0 +1,4 @@ +/obj/item/organ/internal/eyes/shadow + name = "dark orbs" + dark_view = 8 + species = "Shadow" diff --git a/code/modules/surgery/organs/subtypes/tajaran.dm b/code/modules/surgery/organs/subtypes/tajaran.dm index e37686a05ca..746abd6e601 100644 --- a/code/modules/surgery/organs/subtypes/tajaran.dm +++ b/code/modules/surgery/organs/subtypes/tajaran.dm @@ -1,3 +1,16 @@ /obj/item/organ/internal/liver/tajaran alcohol_intensity = 1.4 species = "Tajaran" + +/obj/item/organ/internal/eyes/tajaran /*Most Tajara see in full colour as a result of genetic augmentation, although it cost them their darksight (darksight = 2) + unless they choose otherwise by selecting the colourblind disability in character creation (darksight = 8 but colourblind).*/ + name = "tajaran eyeballs" + species = "Tajaran" + colourblind_matrix = MATRIX_TAJ_CBLIND //The colour matrix and darksight parameters that the mob will recieve when they get the disability. + colourblind_darkview = 8 + +/obj/item/organ/internal/eyes/tajaran/farwa //Being the lesser form of Tajara, Farwas have an utterly incurable version of their colourblindness. + name = "farwa eyeballs" + species = "Farwa" + colourmatrix = MATRIX_TAJ_CBLIND + dark_view = 8 diff --git a/code/modules/surgery/organs/subtypes/unathi.dm b/code/modules/surgery/organs/subtypes/unathi.dm index a769bce7a02..0fb45319ce5 100644 --- a/code/modules/surgery/organs/subtypes/unathi.dm +++ b/code/modules/surgery/organs/subtypes/unathi.dm @@ -1,3 +1,8 @@ /obj/item/organ/internal/liver/unathi alcohol_intensity = 0.8 species = "Unathi" + +/obj/item/organ/internal/eyes/unathi + name = "unathi eyeballs" + dark_view = 3 + species = "Unathi" diff --git a/code/modules/surgery/organs/subtypes/vulpkanin.dm b/code/modules/surgery/organs/subtypes/vulpkanin.dm index ca47ac83ddd..af3d9deab09 100644 --- a/code/modules/surgery/organs/subtypes/vulpkanin.dm +++ b/code/modules/surgery/organs/subtypes/vulpkanin.dm @@ -1,3 +1,16 @@ /obj/item/organ/internal/liver/vulpkanin alcohol_intensity = 1.4 species = "Vulpkanin" + +/obj/item/organ/internal/eyes/vulpkanin /*Most Vulpkanin see in full colour as a result of genetic augmentation, although it cost them their darksight (darksight = 2) + unless they choose otherwise by selecting the colourblind disability in character creation (darksight = 8 but colourblind).*/ + name = "vulpkanin eyeballs" + species = "Vulpkanin" + colourblind_matrix = MATRIX_VULP_CBLIND //The colour matrix and darksight parameters that the mob will recieve when they get the disability. + colourblind_darkview = 8 + +/obj/item/organ/internal/eyes/vulpkanin/wolpin //Being the lesser form of Vulpkanin, Wolpins have an utterly incurable version of their colourblindness. + name = "wolpin eyeballs" + species = "Wolpin" + colourmatrix = MATRIX_VULP_CBLIND + dark_view = 8 diff --git a/code/modules/surgery/organs/subtypes/wryn.dm b/code/modules/surgery/organs/subtypes/wryn.dm index f51adb6054e..ee1a12fd1ab 100644 --- a/code/modules/surgery/organs/subtypes/wryn.dm +++ b/code/modules/surgery/organs/subtypes/wryn.dm @@ -7,3 +7,7 @@ parent_organ = "head" slot = "hivenode" species = "Wryn" + +/obj/item/organ/internal/eyes/wryn + dark_view = 3 + species = "Wryn" diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index f86cf41bcd0..73416045624 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -182,7 +182,7 @@ H.custom_pain("The pain in your [affected.name] is living hell!", 1) else if(istype(tool, /obj/item/weapon/reagent_containers/food/snacks/organ)) - to_chat(user, "[tool] was biten by someone! It's too damaged to use!") + to_chat(user, "[tool] was bitten by someone! It's too damaged to use!") return -1 ..() @@ -244,6 +244,8 @@ thing.forceMove(get_turf(target)) else user.put_in_hands(thing) + + target.update_icons() else user.visible_message("[user] can't seem to extract anything from [target]'s [parse_zone(target_zone)]!", "You can't extract anything from [target]'s [parse_zone(target_zone)]!") diff --git a/html/changelog.html b/html/changelog.html index 551751dc447..93108539e6c 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -55,13 +55,43 @@ -->
+

11 February 2017

+

Markolie updated:

+
    +
  • Ports over the remaining Lavaland loot items from /tg/ (most developed by KorPhaeron).
  • +
  • Refactors the kinetic accelerator to use modkits instead of subtypes: these unique mods (such as more range or shorter cooldown) can be purchased from the mining vendor or built by R&D or robotics (developed by KorPhaeron).
  • +
+

10 February 2017

+

Fox McCloud updated:

+
    +
  • Fixes not being able to bloodcrawl in most sources of blood
  • +
  • Fixes slaughter demon whisper not working at all
  • +
  • Drying rack drying now properly uses NanoUI instead of a right-click verb
  • +
  • Fixes produce appearing stuck in a drying rack when it was empty
  • +
  • Fixes a few failed icon updates with the drying rack
  • +
+

KasparoVy, Krausus updated:

+
    +
  • Adds the colourblindness gene. It is eye-dependent, and can be transferred from person-to-person with the eye organ.
  • +
  • Colourblindness can be detected by the advanced medical scanner just like blindness and short-sightedness.
  • +
  • Vulpkanin and Tajara can now choose to be uniquely colourblind in exchange for fantastic darksight. The default option is colour vision but low darksight.
  • +
  • Selecting mechanical or mechanically assisted eyes at character creation grants full colour vision, but standard Human darksight. This overrides the colour vision preference.
  • +
  • Mechanical(ly assisted) internal organs such as hearts and eyes are now appropriately named, and have appropriate sprites.
  • +
  • Vulpkanin and Tajara monkey-forms (Wolpins and Farwas) are incurably colourblind but have excellent darksight as they get nearly the same organs as their greater forms.
  • +
  • Increases reliability of turning into a monkey.
  • +
  • Fixes a bug with changelings lesser-forming, transforming and humanforming into a different identity.
  • +

Markolie updated:

  • Firelocks can now be constructed and deconstructed.
  • Firelocks no longer show a confirmation message when being opened.
  • Various map fixes (vents, scrubbers, firelocks and intercoms). Also removes the firelocks covering the windows in escape/cargo.
+

tigercat2000 updated:

+
    +
  • Ported Goonstation slash /vg/ lighting. Pretty.
  • +

uraniummeltdown updated:

  • Quantum Pads are now buildable in R&D!
  • @@ -69,6 +99,8 @@
  • Pads do not need to be linked in pairs: Pad A can lead to Pad B which can lead to pad C.
  • Upgrading a Quantum Pad will reduce the cooldown, charge-up time, and power consumption.
  • Quantum Pads require a bluespace crystal, a micro manipulator, a capacitor and a cable piece.
  • +
  • Events now scale better with population.
  • +
  • Enabled immovable rod, slaughter demon and morph events.

08 February 2017

diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 6c2ea070652..b27e7bece5a 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -3582,11 +3582,37 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. Fox McCloud: - bugfix: Grinding wheat and other products produces the proper reagents again 2017-02-10: + Fox McCloud: + - bugfix: Fixes not being able to bloodcrawl in most sources of blood + - bugfix: Fixes slaughter demon whisper not working at all + - tweak: Drying rack drying now properly uses NanoUI instead of a right-click verb + - bugfix: Fixes produce appearing stuck in a drying rack when it was empty + - bugfix: Fixes a few failed icon updates with the drying rack + KasparoVy, Krausus: + - rscadd: Adds the colourblindness gene. It is eye-dependent, and can be transferred + from person-to-person with the eye organ. + - rscadd: Colourblindness can be detected by the advanced medical scanner just like + blindness and short-sightedness. + - rscadd: Vulpkanin and Tajara can now choose to be uniquely colourblind in exchange + for fantastic darksight. The default option is colour vision but low darksight. + - rscadd: Selecting mechanical or mechanically assisted eyes at character creation + grants full colour vision, but standard Human darksight. This overrides the + colour vision preference. + - rscadd: Mechanical(ly assisted) internal organs such as hearts and eyes are now + appropriately named, and have appropriate sprites. + - tweak: Vulpkanin and Tajara monkey-forms (Wolpins and Farwas) are incurably colourblind + but have excellent darksight as they get nearly the same organs as their greater + forms. + - bugfix: Increases reliability of turning into a monkey. + - bugfix: Fixes a bug with changelings lesser-forming, transforming and humanforming + into a different identity. Markolie: - rscadd: Firelocks can now be constructed and deconstructed. - tweak: Firelocks no longer show a confirmation message when being opened. - tweak: Various map fixes (vents, scrubbers, firelocks and intercoms). Also removes the firelocks covering the windows in escape/cargo. + tigercat2000: + - rscadd: Ported Goonstation slash /vg/ lighting. Pretty. uraniummeltdown: - rscadd: Quantum Pads are now buildable in R&D! - rscadd: Quantum Pads, once built, can be linked to other Quantum Pads using a @@ -3598,3 +3624,12 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. power consumption. - rscadd: Quantum Pads require a bluespace crystal, a micro manipulator, a capacitor and a cable piece. + - tweak: Events now scale better with population. + - tweak: Enabled immovable rod, slaughter demon and morph events. +2017-02-11: + Markolie: + - rscadd: Ports over the remaining Lavaland loot items from /tg/ (most developed + by KorPhaeron). + - rscadd: 'Refactors the kinetic accelerator to use modkits instead of subtypes: + these unique mods (such as more range or shorter cooldown) can be purchased + from the mining vendor or built by R&D or robotics (developed by KorPhaeron).' diff --git a/icons/effects/96x96.dmi b/icons/effects/96x96.dmi index 01729aa70af..9111297a266 100644 Binary files a/icons/effects/96x96.dmi and b/icons/effects/96x96.dmi differ diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi index b20f8abf0b8..67da41362f8 100644 Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 93a175f3efc..a7962c37ec1 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/effects/lighting_overlay.dmi b/icons/effects/lighting_overlay.dmi deleted file mode 100644 index a5bee534b3d..00000000000 Binary files a/icons/effects/lighting_overlay.dmi and /dev/null differ diff --git a/icons/effects/lighting_overlay.png b/icons/effects/lighting_overlay.png new file mode 100644 index 00000000000..b317268b702 Binary files /dev/null and b/icons/effects/lighting_overlay.png differ diff --git a/icons/mob/clothing/paranormal_hardsuit.dmi b/icons/mob/clothing/paranormal_hardsuit.dmi new file mode 100644 index 00000000000..f06e81ab1e7 Binary files /dev/null and b/icons/mob/clothing/paranormal_hardsuit.dmi differ diff --git a/icons/mob/eyes.dmi b/icons/mob/eyes.dmi index f74ebda9d34..97966c61dac 100644 Binary files a/icons/mob/eyes.dmi and b/icons/mob/eyes.dmi differ diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi index e6b8d4ca621..d56a42ca099 100644 Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ diff --git a/icons/obj/clothing/glasses.dmi b/icons/obj/clothing/glasses.dmi index 938d810a612..fd2947d7d69 100644 Binary files a/icons/obj/clothing/glasses.dmi and b/icons/obj/clothing/glasses.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index 24585cbdccc..f12fcf3d86c 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index a72971f450d..b98c786872a 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/crates.dmi b/icons/obj/crates.dmi new file mode 100644 index 00000000000..9ec95b4f300 Binary files /dev/null and b/icons/obj/crates.dmi differ diff --git a/icons/obj/guns/magic.dmi b/icons/obj/guns/magic.dmi index 05c8aa7794f..b057d644918 100644 Binary files a/icons/obj/guns/magic.dmi and b/icons/obj/guns/magic.dmi differ diff --git a/icons/obj/lighting.dmi b/icons/obj/lighting.dmi index b0a35a3f35b..06afc67979c 100644 Binary files a/icons/obj/lighting.dmi and b/icons/obj/lighting.dmi differ diff --git a/icons/obj/objects.dmi b/icons/obj/objects.dmi index 53d3954ec06..c02603ecd25 100644 Binary files a/icons/obj/objects.dmi and b/icons/obj/objects.dmi differ diff --git a/icons/obj/storage.dmi b/icons/obj/storage.dmi index bd45f38cd00..6c3fdcf2bee 100644 Binary files a/icons/obj/storage.dmi and b/icons/obj/storage.dmi differ diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi index a5638d1db1b..2f055a0c491 100644 Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ diff --git a/icons/obj/vehicles.dmi b/icons/obj/vehicles.dmi index 63515f5b2e5..2f528c44c77 100644 Binary files a/icons/obj/vehicles.dmi and b/icons/obj/vehicles.dmi differ diff --git a/nano/templates/adv_med.tmpl b/nano/templates/adv_med.tmpl index 51b74a12fda..e88db47456a 100644 --- a/nano/templates/adv_med.tmpl +++ b/nano/templates/adv_med.tmpl @@ -52,10 +52,13 @@ Used In File(s): \code\game\machinery\adv_med.dm Large growth detected in frontal lobe, possibly cancerous. Surgical removal is recommended.
{{/if}} {{if data.occupant.blind}} - Pupils unresponsive.
+ Cataracts detected.
+ {{/if}} + {{if data.occupant.colourblind}} + Photoreceptor abnormalities detected.
{{/if}} {{if data.occupant.nearsighted}} - Retinal misalignment detected
+ Retinal misalignment detected.
{{/if}}
diff --git a/nano/templates/smartfridge.tmpl b/nano/templates/smartfridge.tmpl index 873487454dc..3c59892486d 100644 --- a/nano/templates/smartfridge.tmpl +++ b/nano/templates/smartfridge.tmpl @@ -10,6 +10,16 @@ {{/if}}
+
+ {{if data.can_dry}} +
+ Drying: +
+
+ {{:helper.link('On', 'power-off', {'dryingOn' : 1}, data.drying ? 'selected' : null)}}{{:helper.link('Off', 'close', {'dryingOff' : 1}, data.drying ? null : 'selected')}} +
+ {{/if}} +
{{if data.contents}} {{for data.contents}} diff --git a/paradise.dme b/paradise.dme index 15d3c08f39d..4f8a12f79f9 100644 --- a/paradise.dme +++ b/paradise.dme @@ -29,8 +29,10 @@ #include "code\__DEFINES\genetics.dm" #include "code\__DEFINES\hud.dm" #include "code\__DEFINES\hydroponics.dm" +#include "code\__DEFINES\inventory.dm" #include "code\__DEFINES\is_helpers.dm" #include "code\__DEFINES\language.dm" +#include "code\__DEFINES\layers.dm" #include "code\__DEFINES\lighting.dm" #include "code\__DEFINES\machines.dm" #include "code\__DEFINES\math.dm" @@ -40,6 +42,7 @@ #include "code\__DEFINES\preferences.dm" #include "code\__DEFINES\process_scheduler.dm" #include "code\__DEFINES\qdel.dm" +#include "code\__DEFINES\reagents.dm" #include "code\__DEFINES\role_preferences.dm" #include "code\__DEFINES\rolebans.dm" #include "code\__DEFINES\sight.dm" @@ -87,7 +90,6 @@ #include "code\_globalvars\lists\names.dm" #include "code\_globalvars\lists\objects.dm" #include "code\_globalvars\lists\reagents.dm" -#include "code\_onclick\_defines.dm" #include "code\_onclick\adjacent.dm" #include "code\_onclick\ai.dm" #include "code\_onclick\click.dm" @@ -398,7 +400,6 @@ #include "code\game\gamemodes\changeling\powers\hivemind.dm" #include "code\game\gamemodes\changeling\powers\humanform.dm" #include "code\game\gamemodes\changeling\powers\lesserform.dm" -#include "code\game\gamemodes\changeling\powers\linglink.dm" #include "code\game\gamemodes\changeling\powers\mimic_voice.dm" #include "code\game\gamemodes\changeling\powers\mutations.dm" #include "code\game\gamemodes\changeling\powers\panacea.dm" @@ -1416,12 +1417,14 @@ #include "code\modules\library\computers\checkout.dm" #include "code\modules\library\computers\public.dm" #include "code\modules\lighting\__lighting_docs.dm" -#include "code\modules\lighting\light_source.dm" +#include "code\modules\lighting\lighting_area.dm" #include "code\modules\lighting\lighting_atom.dm" +#include "code\modules\lighting\lighting_corner.dm" #include "code\modules\lighting\lighting_overlay.dm" -#include "code\modules\lighting\lighting_process.dm" -#include "code\modules\lighting\lighting_system.dm" +#include "code\modules\lighting\lighting_setup.dm" +#include "code\modules\lighting\lighting_source.dm" #include "code\modules\lighting\lighting_turf.dm" +#include "code\modules\lighting\~lighting_undefs.dm" #include "code\modules\logic\converter.dm" #include "code\modules\logic\dual_input.dm" #include "code\modules\logic\logic_base.dm" @@ -1453,8 +1456,13 @@ #include "code\modules\mining\laborcamp\laborshuttle.dm" #include "code\modules\mining\laborcamp\laborstacker.dm" #include "code\modules\mining\lavaland\ash_flora.dm" -#include "code\modules\mining\lavaland\colossus_loot.dm" #include "code\modules\mining\lavaland\necropolis_chests.dm" +#include "code\modules\mining\lavaland\loot\ashdragon_loot.dm" +#include "code\modules\mining\lavaland\loot\bubblegum_loot.dm" +#include "code\modules\mining\lavaland\loot\colossus_loot.dm" +#include "code\modules\mining\lavaland\loot\hierophant_loot.dm" +#include "code\modules\mining\lavaland\loot\legion_loot.dm" +#include "code\modules\mining\lavaland\loot\tendril_loot.dm" #include "code\modules\mob\abilities.dm" #include "code\modules\mob\death.dm" #include "code\modules\mob\emote.dm" @@ -1858,6 +1866,7 @@ #include "code\modules\projectiles\guns\rocket.dm" #include "code\modules\projectiles\guns\syringe_gun.dm" #include "code\modules\projectiles\guns\throw.dm" +#include "code\modules\projectiles\guns\energy\kinetic_accelerator.dm" #include "code\modules\projectiles\guns\energy\laser.dm" #include "code\modules\projectiles\guns\energy\nuclear.dm" #include "code\modules\projectiles\guns\energy\pulse.dm" @@ -2094,6 +2103,7 @@ #include "code\modules\surgery\organs\skeleton.dm" #include "code\modules\surgery\organs\vocal_cords.dm" #include "code\modules\surgery\organs\wound.dm" +#include "code\modules\surgery\organs\subtypes\abductor.dm" #include "code\modules\surgery\organs\subtypes\diona.dm" #include "code\modules\surgery\organs\subtypes\drask.dm" #include "code\modules\surgery\organs\subtypes\grey.dm" @@ -2101,6 +2111,7 @@ #include "code\modules\surgery\organs\subtypes\machine.dm" #include "code\modules\surgery\organs\subtypes\misc.dm" #include "code\modules\surgery\organs\subtypes\nucleation.dm" +#include "code\modules\surgery\organs\subtypes\shadow.dm" #include "code\modules\surgery\organs\subtypes\skrell.dm" #include "code\modules\surgery\organs\subtypes\standard.dm" #include "code\modules\surgery\organs\subtypes\tajaran.dm"