diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index ed4fb787b8d..1e4692b7e3b 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -269,6 +269,7 @@ CREATE TABLE `player` ( `fuid` bigint(20) NULL DEFAULT NULL, `fupdate` smallint(4) NULL DEFAULT '0', `afk_watch` tinyint(1) NOT NULL DEFAULT '0', + `parallax` tinyint(1) DEFAULT '8', PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) ) ENGINE=InnoDB AUTO_INCREMENT=32446 DEFAULT CHARSET=latin1; diff --git a/SQL/paradise_schema_prefixed.sql b/SQL/paradise_schema_prefixed.sql index b0f7bbc5c82..aa5d5895e56 100644 --- a/SQL/paradise_schema_prefixed.sql +++ b/SQL/paradise_schema_prefixed.sql @@ -268,6 +268,7 @@ CREATE TABLE `SS13_player` ( `fuid` bigint(20) NULL DEFAULT NULL, `fupdate` smallint(4) NULL DEFAULT '0', `afk_watch` tinyint(1) NOT NULL DEFAULT '0', + `parallax` tinyint(1) DEFAULT '8', PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) ) ENGINE=InnoDB AUTO_INCREMENT=32446 DEFAULT CHARSET=latin1; diff --git a/SQL/updates/8-9.sql b/SQL/updates/8-9.sql new file mode 100644 index 00000000000..d7f0fd19ab3 --- /dev/null +++ b/SQL/updates/8-9.sql @@ -0,0 +1,4 @@ +#Updating the SQL from version 8 to version 9. -affectedarc07 +#Adding new column to contain the parallax value. +ALTER TABLE `player` + ADD `parallax` tinyint(1) DEFAULT '8' AFTER `fupdate`; diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 049f2541bc1..45d1d07c940 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -403,7 +403,7 @@ #define INVESTIGATE_BOMB "bombs" // The SQL version required by this version of the code -#define SQL_VERSION 8 +#define SQL_VERSION 9 // Vending machine stuff #define CAT_NORMAL 1 @@ -485,4 +485,10 @@ #define DICE_NOT_RIGGED 1 #define DICE_BASICALLY_RIGGED 2 -#define DICE_TOTALLY_RIGGED 3 \ No newline at end of file +#define DICE_TOTALLY_RIGGED 3 + +// Parallax +#define PARALLAX_DELAY_DEFAULT world.tick_lag +#define PARALLAX_DELAY_MED 1 +#define PARALLAX_DELAY_LOW 2 +#define PARALLAX_LOOP_TIME 25 diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index 9582fddccfe..a28d68a392b 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -63,3 +63,12 @@ #define EXP_TYPE_WHITELIST "Whitelist" #define EXP_DEPT_TYPE_LIST list(EXP_TYPE_SERVICE, EXP_TYPE_MEDICAL, EXP_TYPE_ENGINEERING, EXP_TYPE_SCIENCE, EXP_TYPE_SECURITY, EXP_TYPE_COMMAND, EXP_TYPE_SILICON, EXP_TYPE_SPECIAL) + +// Defines just for parallax because its levels make storing it in the regular prefs a pain in the ass +// These dont need to be bitflags because there isnt going to be more than one at a time of these active +// But its gonna piss off my OCD if it isnt bitflags, so deal with it, -affected +#define PARALLAX_DISABLE 1 +#define PARALLAX_LOW 2 +#define PARALLAX_MED 4 +#define PARALLAX_HIGH 8 +#define PARALLAX_INSANE 16 diff --git a/code/__HELPERS/icon_smoothing.dm b/code/__HELPERS/icon_smoothing.dm index 11c86940b75..acf202f0eee 100644 --- a/code/__HELPERS/icon_smoothing.dm +++ b/code/__HELPERS/icon_smoothing.dm @@ -153,29 +153,33 @@ /turf/simulated/wall/diagonal_smooth(adjacencies) adjacencies = reverse_ndir(..()) if(adjacencies) - var/list/U = list() + var/mutable_appearance/underlay_appearance = mutable_appearance(layer = TURF_LAYER, plane = FLOOR_PLANE) + var/list/U = list(underlay_appearance) if(fixed_underlay) if(fixed_underlay["space"]) - U += image('icons/turf/space.dmi', SPACE_ICON_STATE, layer=TURF_LAYER) + underlay_appearance.icon = 'icons/turf/space.dmi' + underlay_appearance.icon_state = SPACE_ICON_STATE + underlay_appearance.plane = PLANE_SPACE else - U += image(fixed_underlay["icon"], fixed_underlay["icon_state"], layer=TURF_LAYER) + underlay_appearance.icon = fixed_underlay["icon"] + underlay_appearance.icon_state = fixed_underlay["icon_state"] else - var/turf/T = get_step(src, turn(adjacencies, 180)) - if(T && (T.density || T.smooth)) + var/turned_adjacency = turn(adjacencies, 180) + var/turf/T = get_step(src, turned_adjacency) + if(!T.get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency)) T = get_step(src, turn(adjacencies, 135)) - if(T && (T.density || T.smooth)) + if(!T.get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency)) T = get_step(src, turn(adjacencies, 225)) - - if(istype(T, /turf/space) && !istype(T, /turf/space/transit)) - U += image('icons/turf/space.dmi', SPACE_ICON_STATE, layer=TURF_LAYER) - else if(T && !T.density && !T.smooth) - U += T - else if(baseturf && !initial(baseturf.density) && !initial(baseturf.smooth)) - U += image(initial(baseturf.icon), initial(baseturf.icon_state), layer=TURF_LAYER) - else - U += DEFAULT_UNDERLAY_IMAGE + //if all else fails, ask our own turf + if(!T.get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency) && !get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency)) + underlay_appearance.icon = DEFAULT_UNDERLAY_ICON + underlay_appearance.icon_state = DEFAULT_UNDERLAY_ICON_STATE underlays = U + // Drop posters which were previously placed on this wall. + for(var/obj/structure/sign/poster/P in src) + P.roll_and_drop(src) + /proc/cardinal_smooth(atom/A, adjacencies) //NW CORNER var/nw = "1-i" diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm index 4e92395f4cc..600c1105e8e 100644 --- a/code/_onclick/hud/ghost.dm +++ b/code/_onclick/hud/ghost.dm @@ -59,3 +59,8 @@ using = new /obj/screen/ghost/teleport() using.screen_loc = ui_ghost_teleport static_inventory += using + +/datum/hud/ghost/show_hud() + mymob.client.screen = list() + mymob.client.screen += static_inventory + ..() diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 0063feae9cf..e93b3b121e6 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -99,6 +99,7 @@ /datum/hud/proc/show_hud(version = 0) if(!ismob(mymob)) return FALSE + if(!mymob.client) return FALSE @@ -172,6 +173,7 @@ mymob.update_action_buttons(1) reorganize_alerts() reload_fullscreen() + update_parallax_pref(mymob) plane_masters_update() /datum/hud/proc/plane_masters_update() diff --git a/code/_onclick/hud/parallax.dm b/code/_onclick/hud/parallax.dm new file mode 100644 index 00000000000..0d981962cc0 --- /dev/null +++ b/code/_onclick/hud/parallax.dm @@ -0,0 +1,308 @@ +/client + var/list/parallax_layers + var/list/parallax_layers_cached + var/static/list/parallax_static_layers_tail = newlist(/obj/screen/parallax_pmaster, /obj/screen/parallax_space_whitifier) + var/atom/movable/movingmob + var/turf/previous_turf + var/dont_animate_parallax //world.time of when we can state animate()ing parallax again + var/last_parallax_shift //world.time of last update + var/parallax_throttle = 0 //ds between updates + var/parallax_movedir = 0 + var/new_parallax_movedir = 0 + var/parallax_layers_max = 3 + var/parallax_animate_timer + +/datum/hud/proc/create_parallax() + var/client/C = mymob.client + if(!apply_parallax_pref()) + return + + if(!length(C.parallax_layers_cached)) + C.parallax_layers_cached = list() + C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_1(null, C.view) + C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_2(null, C.view) + C.parallax_layers_cached += new /obj/screen/parallax_layer/planet(null, C.view) + + C.parallax_layers = C.parallax_layers_cached.Copy() + + if(length(C.parallax_layers) > C.parallax_layers_max) + C.parallax_layers.len = C.parallax_layers_max + + C.screen |= (C.parallax_layers + C.parallax_static_layers_tail) + +/datum/hud/proc/remove_parallax() + var/client/C = mymob.client + C.screen -= (C.parallax_layers_cached + C.parallax_static_layers_tail) + C.parallax_layers = null + +/datum/hud/proc/apply_parallax_pref() + var/client/C = mymob.client + if(C.prefs) + var/pref = C.prefs.parallax + if (isnull(pref)) + pref = PARALLAX_HIGH + switch(C.prefs.parallax) + if (PARALLAX_INSANE) + C.parallax_throttle = FALSE + C.parallax_layers_max = 4 + return TRUE + + if (PARALLAX_MED) + C.parallax_throttle = PARALLAX_DELAY_MED + C.parallax_layers_max = 2 + return TRUE + + if (PARALLAX_LOW) + C.parallax_throttle = PARALLAX_DELAY_LOW + C.parallax_layers_max = 1 + return TRUE + + if (PARALLAX_DISABLE) + return FALSE + + C.parallax_throttle = PARALLAX_DELAY_DEFAULT + C.parallax_layers_max = 3 + return TRUE + +/datum/hud/proc/update_parallax_pref() + remove_parallax() + create_parallax() + update_parallax() + +// This sets which way the current shuttle is moving (returns true if the shuttle has stopped moving so the caller can append their animation) +// Well, it would if our shuttle code had dynamic areas +/datum/hud/proc/set_parallax_movedir(new_parallax_movedir, skip_windups) + . = FALSE + var/client/C = mymob.client + if(new_parallax_movedir == C.parallax_movedir) + return + var/animatedir = new_parallax_movedir + if(new_parallax_movedir == FALSE) + var/animate_time = 0 + for(var/thing in C.parallax_layers) + var/obj/screen/parallax_layer/L = thing + L.icon_state = initial(L.icon_state) + L.update_o(C.view) + var/T = PARALLAX_LOOP_TIME / L.speed + if(T > animate_time) + animate_time = T + C.dont_animate_parallax = world.time + min(animate_time, PARALLAX_LOOP_TIME) + animatedir = C.parallax_movedir + + var/matrix/newtransform + switch(animatedir) + if(NORTH) + newtransform = matrix(1, 0, 0, 0, 1, 480) + if(SOUTH) + newtransform = matrix(1, 0, 0, 0, 1,-480) + if(EAST) + newtransform = matrix(1, 0, 480, 0, 1, 0) + if(WEST) + newtransform = matrix(1, 0,-480, 0, 1, 0) + + var/shortesttimer + for(var/thing in C.parallax_layers) + var/obj/screen/parallax_layer/L = thing + + var/T = PARALLAX_LOOP_TIME / L.speed + if(isnull(shortesttimer)) + shortesttimer = T + if(T < shortesttimer) + shortesttimer = T + L.transform = newtransform + animate(L, transform = matrix(), time = T, easing = QUAD_EASING | (new_parallax_movedir ? EASE_IN : EASE_OUT), flags = ANIMATION_END_NOW) + if(new_parallax_movedir) + L.transform = newtransform + animate(transform = matrix(), time = T) //queue up another animate so lag doesn't create a shutter + + C.parallax_movedir = new_parallax_movedir + if(C.parallax_animate_timer) + deltimer(C.parallax_animate_timer) + var/datum/callback/CB = CALLBACK(src, .proc/update_parallax_motionblur, C, animatedir, new_parallax_movedir, newtransform) + if(skip_windups) + CB.Invoke() + else + C.parallax_animate_timer = addtimer(CB, min(shortesttimer, PARALLAX_LOOP_TIME), TIMER_CLIENT_TIME|TIMER_STOPPABLE) + +/datum/hud/proc/update_parallax_motionblur(client/C, animatedir, new_parallax_movedir, matrix/newtransform) + C.parallax_animate_timer = FALSE + for(var/thing in C.parallax_layers) + var/obj/screen/parallax_layer/L = thing + if(!new_parallax_movedir) + animate(L) + continue + + var/newstate = initial(L.icon_state) + if(animatedir) + if(animatedir == NORTH || animatedir == SOUTH) + newstate += "_vertical" + else + newstate += "_horizontal" + + var/T = PARALLAX_LOOP_TIME / L.speed + + if(newstate in icon_states(L.icon)) + L.icon_state = newstate + L.update_o(C.view) + + L.transform = newtransform + + animate(L, transform = matrix(), time = T, loop = -1, flags = ANIMATION_END_NOW) + +/datum/hud/proc/update_parallax() + var/client/C = mymob.client + var/turf/posobj = get_turf(C.eye) + var/area/areaobj = posobj.loc + + // Update the movement direction of the parallax if necessary (for shuttles) + set_parallax_movedir(C.new_parallax_movedir) + + var/force + if(!C.previous_turf || (C.previous_turf.z != posobj.z)) + C.previous_turf = posobj + force = TRUE + + if(!force && world.time < C.last_parallax_shift+C.parallax_throttle) + return + + //Doing it this way prevents parallax layers from "jumping" when you change Z-Levels. + var/offset_x = posobj.x - C.previous_turf.x + var/offset_y = posobj.y - C.previous_turf.y + + if(!offset_x && !offset_y && !force) + return + + var/last_delay = world.time - C.last_parallax_shift + last_delay = min(last_delay, C.parallax_throttle) + C.previous_turf = posobj + C.last_parallax_shift = world.time + + for(var/thing in C.parallax_layers) + var/obj/screen/parallax_layer/L = thing + L.update_status(mymob) + if(L.view_sized != C.view) + L.update_o(C.view) + + var/change_x + var/change_y + + if(L.absolute) + L.offset_x = -(posobj.x - SSparallax.planet_x_offset) * L.speed + L.offset_y = -(posobj.y - SSparallax.planet_y_offset) * L.speed + else + change_x = offset_x * L.speed + L.offset_x -= change_x + change_y = offset_y * L.speed + L.offset_y -= change_y + + if(L.offset_x > 240) + L.offset_x -= 480 + if(L.offset_x < -240) + L.offset_x += 480 + if(L.offset_y > 240) + L.offset_y -= 480 + if(L.offset_y < -240) + L.offset_y += 480 + + if(!areaobj.parallax_movedir && C.dont_animate_parallax <= world.time && (offset_x || offset_y) && abs(offset_x) <= max(C.parallax_throttle/world.tick_lag+1,1) && abs(offset_y) <= max(C.parallax_throttle/world.tick_lag+1,1) && (round(abs(change_x)) > 1 || round(abs(change_y)) > 1)) + L.transform = matrix(1, 0, offset_x*L.speed, 0, 1, offset_y*L.speed) + animate(L, transform=matrix(), time = last_delay) + + L.screen_loc = "CENTER-7:[round(L.offset_x,1)],CENTER-7:[round(L.offset_y,1)]" + +/atom/movable/proc/update_parallax_contents() + if(length(client_mobs_in_contents)) + for(var/thing in client_mobs_in_contents) + var/mob/M = thing + if(M && M.client && M.hud_used && length(M.client.parallax_layers)) + M.hud_used.update_parallax() + +/obj/screen/parallax_layer + icon = 'icons/effects/parallax.dmi' + var/speed = 1 + var/offset_x = 0 + var/offset_y = 0 + var/view_sized + var/absolute = FALSE + blend_mode = BLEND_ADD + plane = PLANE_SPACE_PARALLAX + screen_loc = "CENTER-7,CENTER-7" + mouse_opacity = 0 + + +/obj/screen/parallax_layer/New(view) + ..() + if(!view) + view = world.view + update_o(view) + +/obj/screen/parallax_layer/proc/update_o(view) + if(!view) + view = world.view + var/list/new_overlays = list() + var/count = Ceiling(view/(480/world.icon_size))+1 + for(var/x in -count to count) + for(var/y in -count to count) + if(x == 0 && y == 0) + continue + var/mutable_appearance/texture_overlay = mutable_appearance(icon, icon_state) + texture_overlay.transform = matrix(1, 0, x*480, 0, 1, y*480) + new_overlays += texture_overlay + + overlays = new_overlays + view_sized = view + +/obj/screen/parallax_layer/proc/update_status(mob/M) + return + +/obj/screen/parallax_layer/layer_1 + icon_state = "layer1" + speed = 0.6 + layer = 1 + +/obj/screen/parallax_layer/layer_2 + icon_state = "layer2" + speed = 1 + layer = 2 + +/obj/screen/parallax_layer/planet + icon_state = "planet" + blend_mode = BLEND_OVERLAY + absolute = TRUE //Status of seperation + speed = 3 + layer = 30 + +/obj/screen/parallax_layer/planet/update_status(mob/M) + var/turf/T = get_turf(M) + if(is_station_level(T.z)) + invisibility = 0 + else + invisibility = INVISIBILITY_ABSTRACT + +/obj/screen/parallax_layer/planet/update_o() + return //Shit wont move + +/obj/screen/parallax_pmaster + appearance_flags = PLANE_MASTER + plane = PLANE_SPACE_PARALLAX + blend_mode = BLEND_MULTIPLY + mouse_opacity = FALSE + screen_loc = "CENTER-7,CENTER-7" + +/obj/screen/parallax_space_whitifier + appearance_flags = PLANE_MASTER + plane = PLANE_SPACE + color = list( + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 1, 1, 1, 1, + 0, 0, 0, 0 + ) + screen_loc = "CENTER-7,CENTER-7" + + +#undef LOOP_NONE +#undef LOOP_NORMAL +#undef LOOP_REVERSE +#undef LOOP_TIME \ No newline at end of file diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index 797384b8336..a988277012b 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -17,6 +17,7 @@ else following = null forceMove(get_turf(A)) + update_parallax_contents() /mob/dead/observer/ClickOn(var/atom/A, var/params) if(client.click_intercept) diff --git a/code/controllers/subsystem/parallax.dm b/code/controllers/subsystem/parallax.dm new file mode 100644 index 00000000000..039b6d2b008 --- /dev/null +++ b/code/controllers/subsystem/parallax.dm @@ -0,0 +1,44 @@ +SUBSYSTEM_DEF(parallax) + name = "Parallax" + wait = 2 + flags = SS_POST_FIRE_TIMING | SS_BACKGROUND + priority = FIRE_PRIORITY_PARALLAX + runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT + var/list/currentrun + var/planet_x_offset = 128 + var/planet_y_offset = 128 + +/datum/controller/subsystem/parallax/Initialize(timeofday) + . = ..() + planet_y_offset = rand(100, 160) + planet_x_offset = rand(100, 160) + +/datum/controller/subsystem/parallax/fire(resumed = 0) + if(!resumed) + src.currentrun = GLOB.clients.Copy() + + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + + while(length(currentrun)) + var/client/C = currentrun[currentrun.len] + currentrun.len-- + if(!C || !C.eye) + if(MC_TICK_CHECK) + return + continue + var/atom/movable/A = C.eye + if(!istype(A)) + continue + for (A; isloc(A.loc) && !isturf(A.loc); A = A.loc); + + if(A != C.movingmob) + if(C.movingmob != null) + C.movingmob.client_mobs_in_contents -= C.mob + UNSETEMPTY(C.movingmob.client_mobs_in_contents) + LAZYINITLIST(A.client_mobs_in_contents) + A.client_mobs_in_contents += C.mob + C.movingmob = A + if(MC_TICK_CHECK) + return + currentrun = null diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 2e7448ec5c8..442bde3aa68 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -67,6 +67,8 @@ var/can_get_auto_cryod = TRUE var/hide_attacklogs = FALSE // For areas such as thunderdome, lavaland syndiebase, etc which generate a lot of spammy attacklogs. Reduces log priority. + var/parallax_movedir = 0 + /area/Initialize(mapload) GLOB.all_areas += src icon_state = "" diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 1a23dc71070..0a22c19770b 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -26,7 +26,7 @@ var/inertia_move_delay = 5 var/moving_diagonally = 0 //0: not doing a diagonal move. 1 and 2: doing the first/second step of the diagonal move - + var/list/client_mobs_in_contents var/area/areaMaster /atom/movable/New() @@ -215,6 +215,8 @@ if(!inertia_moving) inertia_next_move = world.time + inertia_move_delay newtonian_move(Dir) + if(length(client_mobs_in_contents)) + update_parallax_contents() return TRUE // Previously known as HasEntered() diff --git a/code/game/turfs/simulated/floor/chasm.dm b/code/game/turfs/simulated/floor/chasm.dm index 6a213400d04..17807bd255b 100644 --- a/code/game/turfs/simulated/floor/chasm.dm +++ b/code/game/turfs/simulated/floor/chasm.dm @@ -22,6 +22,11 @@ if(!drop_stuff()) STOP_PROCESSING(SSprocessing, src) +/turf/open/chasm/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) + underlay_appearance.icon = 'icons/turf/floors.dmi' + underlay_appearance.icon_state = "basalt" + return TRUE + /turf/simulated/floor/chasm/attackby(obj/item/C, mob/user, params, area/area_restriction) ..() if(istype(C, /obj/item/stack/rods)) diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm index 97065cd9711..12b1654994c 100644 --- a/code/game/turfs/simulated/floor/fancy_floor.dm +++ b/code/game/turfs/simulated/floor/fancy_floor.dm @@ -117,6 +117,9 @@ burnt = 1 update_icon() +/turf/open/floor/carpet/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) + return FALSE + /turf/simulated/floor/carpet/black icon = 'icons/turf/floors/carpet_black.dmi' floor_tile = /obj/item/stack/tile/carpet/black @@ -127,6 +130,7 @@ icon_state = "0" floor_tile = /obj/item/stack/tile/fakespace broken_states = list("damaged") + plane = PLANE_SPACE /turf/simulated/floor/fakespace/New() ..() @@ -137,3 +141,9 @@ icon_state = "arcade" floor_tile = /obj/item/stack/tile/arcade_carpet smooth = SMOOTH_FALSE + +/turf/open/floor/fakespace/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) + underlay_appearance.icon = 'icons/turf/space.dmi' + underlay_appearance.icon_state = SPACE_ICON_STATE + underlay_appearance.plane = PLANE_SPACE + return TRUE diff --git a/code/game/turfs/simulated/floor/indestructible.dm b/code/game/turfs/simulated/floor/indestructible.dm index 6c1679776e6..3705e24eea0 100644 --- a/code/game/turfs/simulated/floor/indestructible.dm +++ b/code/game/turfs/simulated/floor/indestructible.dm @@ -81,5 +81,8 @@ planetary_atmos = TRUE desc = "A floor with a square pattern. It's faintly cool to the touch." +/turf/open/indestructible/hierophant/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) + return FALSE + /turf/simulated/floor/indestructible/hierophant/two icon_state = "hierophant2" diff --git a/code/game/turfs/simulated/floor/lava.dm b/code/game/turfs/simulated/floor/lava.dm index 0882bb18766..66d7eaca83d 100644 --- a/code/game/turfs/simulated/floor/lava.dm +++ b/code/game/turfs/simulated/floor/lava.dm @@ -41,6 +41,11 @@ /turf/simulated/floor/plating/lava/remove_plating() return +/turf/open/lava/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) + underlay_appearance.icon = 'icons/turf/floors.dmi' + underlay_appearance.icon_state = "basalt" + return TRUE + /turf/simulated/floor/plating/lava/proc/is_safe() var/static/list/lava_safeties_typecache = typecacheof(list(/obj/structure/lattice/catwalk, /obj/structure/stone_tile)) var/list/found_safeties = typecache_filter_list(contents, lava_safeties_typecache) diff --git a/code/game/turfs/simulated/minerals.dm b/code/game/turfs/simulated/minerals.dm index 119f0b000d9..aee23831050 100644 --- a/code/game/turfs/simulated/minerals.dm +++ b/code/game/turfs/simulated/minerals.dm @@ -48,6 +48,13 @@ setDir(angle2dir(rotation + dir2angle(dir))) queue_smooth(src) +/turf/simulated/mineral/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) + if(turf_type) + underlay_appearance.icon = initial(turf_type.icon) + underlay_appearance.icon_state = initial(turf_type.icon_state) + return TRUE + return ..() + /turf/simulated/mineral/attackby(var/obj/item/pickaxe/P as obj, mob/user as mob, params) if(!user.IsAdvancedToolUser()) to_chat(usr, "You don't have the dexterity to do this!") diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index 0d6428b10a2..daecd225355 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -16,6 +16,7 @@ var/destination_z var/destination_x var/destination_y + plane = PLANE_SPACE /turf/space/Initialize(mapload) if(!istype(src, /turf/space/transit)) @@ -105,6 +106,12 @@ ..() if((!(A) || !(src in A.locs))) return + + if(ismob(A)) + var/mob/M = A + if(M && M.client && M.client.new_parallax_movedir) + M.client.new_parallax_movedir = 0 + M.update_parallax_contents() if(destination_z && destination_x && destination_y) A.forceMove(locate(destination_x, destination_y, destination_z)) @@ -262,4 +269,10 @@ /turf/space/attack_ghost(mob/dead/observer/user) if(destination_z) var/turf/T = locate(destination_x, destination_y, destination_z) - user.forceMove(T) \ No newline at end of file + user.forceMove(T) + +/turf/space/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) + underlay_appearance.icon = 'icons/turf/space.dmi' + underlay_appearance.icon_state = SPACE_ICON_STATE + underlay_appearance.plane = PLANE_SPACE + return TRUE diff --git a/code/game/turfs/space/transit.dm b/code/game/turfs/space/transit.dm index 79bf171ce1f..15c553b3f95 100644 --- a/code/game/turfs/space/transit.dm +++ b/code/game/turfs/space/transit.dm @@ -1,5 +1,6 @@ /turf/space/transit var/pushdirection // push things that get caught in the transit tile this direction + plane = PLANE_SPACE //Overwrite because we dont want people building rods in space. /turf/space/transit/attackby(obj/O as obj, mob/user as mob, params) @@ -151,3 +152,9 @@ icon_state = "speedspace_ns_[state]" transform = turn(matrix(), angle) + +/turf/space/transit/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) + underlay_appearance.icon = 'icons/turf/space.dmi' + underlay_appearance.icon_state = SPACE_ICON_STATE + underlay_appearance.plane = PLANE_SPACE + return TRUE diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index e315ad26ad0..51285932f00 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -470,6 +470,12 @@ if(ismob(A) || .) A.ratvar_act() +/turf/proc/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) + underlay_appearance.icon = icon + underlay_appearance.icon_state = icon_state + underlay_appearance.dir = adjacency_dir + return TRUE + /turf/proc/add_blueprints(atom/movable/AM) var/image/I = new I.appearance = AM.appearance diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 95f6c16ba97..2d4092ff159 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -433,6 +433,9 @@ GLOB.admins -= src GLOB.directory -= ckey GLOB.clients -= src + if(movingmob) + movingmob.client_mobs_in_contents -= mob + UNSETEMPTY(movingmob.client_mobs_in_contents) Master.UpdateTickRate() return ..() diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index 97f9ddc6169..7fce23b9e4c 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -201,6 +201,8 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts //Gear stuff var/list/gear = list() var/gear_tab = "General" + // Parallax + var/parallax = PARALLAX_HIGH /datum/preferences/New(client/C) parent = C @@ -462,6 +464,19 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts dat += "OOC Color:     Change
" if(config.allow_Metadata) dat += "OOC Notes: Edit
" + dat += "Parallax (Fancy Space): " + switch (parallax) + if(PARALLAX_LOW) + dat += "Low" + if(PARALLAX_MED) + dat += "Medium" + if(PARALLAX_INSANE) + dat += "Insane" + if(PARALLAX_DISABLE) + dat += "Disabled" + else + dat += "High" + dat += "
" dat += "Play Admin MIDIs: [(sound & SOUND_MIDI) ? "Yes" : "No"]
" dat += "Play Lobby Music: [(sound & SOUND_LOBBY) ? "Yes" : "No"]
" dat += "Randomized Character Slot: [randomslot ? "Yes" : "No"]
" @@ -2072,6 +2087,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts if(href_list["tab"]) current_tab = text2num(href_list["tab"]) + if("ambientocclusion") toggles ^= AMBIENT_OCCLUSION if(parent && parent.screen && parent.screen.len) @@ -2080,6 +2096,19 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts if(toggles & AMBIENT_OCCLUSION) PM.filters += FILTER_AMBIENT_OCCLUSION + if("parallax") + var/parallax_styles = list( + "Off" = PARALLAX_DISABLE, + "Low" = PARALLAX_LOW, + "Medium" = PARALLAX_MED, + "High" = PARALLAX_HIGH, + "Insane" = PARALLAX_INSANE + ) + parallax = parallax_styles[input(user, "Pick a parallax style", "Parallax Style") as null|anything in parallax_styles] + if(parent && parent.mob && parent.mob.hud_used) + parent.mob.hud_used.update_parallax_pref() + + ShowChoices(user) return 1 diff --git a/code/modules/client/preference/preferences_mysql.dm b/code/modules/client/preference/preferences_mysql.dm index cdbfe2afb2f..6090538f2b3 100644 --- a/code/modules/client/preference/preferences_mysql.dm +++ b/code/modules/client/preference/preferences_mysql.dm @@ -20,7 +20,8 @@ clientfps, atklog, fuid, - afk_watch + afk_watch, + parallax FROM [format_table_name("player")] WHERE ckey='[C.ckey]'"} ) @@ -54,6 +55,7 @@ atklog = text2num(query.item[18]) fuid = text2num(query.item[19]) afk_watch = text2num(query.item[20]) + parallax = text2num(query.item[21]) //Sanitize ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor)) @@ -75,6 +77,7 @@ atklog = sanitize_integer(atklog, 0, 100, initial(atklog)) fuid = sanitize_integer(fuid, 0, 10000000, initial(fuid)) afk_watch = sanitize_integer(afk_watch, 0, 1, initial(afk_watch)) + parallax = sanitize_integer(parallax, 0, 16, initial(parallax)) return 1 /datum/preferences/proc/save_preferences(client/C) @@ -105,7 +108,8 @@ ghost_anonsay='[ghost_anonsay]', clientfps='[clientfps]', atklog='[atklog]', - afk_watch='[afk_watch]' + afk_watch='[afk_watch]', + parallax='[parallax]' WHERE ckey='[C.ckey]'"} ) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 731f53c7838..ab855b5dc80 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -236,6 +236,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp return 1 /mob/dead/observer/Move(NewLoc, direct) + update_parallax_contents() following = null setDir(direct) ghostimage.setDir(dir) @@ -417,6 +418,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp return forceMove(pick(L)) + update_parallax_contents() following = null /mob/dead/observer/verb/follow() @@ -511,6 +513,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(T && isturf(T)) //Make sure the turf exists, then move the source to that destination. A.forceMove(T) + M.update_parallax_contents() + following = null return to_chat(A, "This mob is not located in the game world.") diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm index 7344c6469c4..c3c47235b91 100644 --- a/code/modules/mob/living/silicon/ai/freelook/eye.dm +++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm @@ -31,6 +31,7 @@ ai.camera_visibility(src) if(ai.client && !ai.multicam_on) ai.client.eye = src + update_parallax_contents() //Holopad if(ai.master_multicam) ai.master_multicam.refresh_view() diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index 67765ef8ac5..77c6a21dd0d 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -30,17 +30,22 @@ if(id_tag == "s_docking_airlock") INVOKE_ASYNC(src, .proc/lock) -/mob/onShuttleMove() +/mob/onShuttleMove(turf/oldT, turf/T1, rotation, travelDir) if(!move_on_shuttle) return 0 . = ..() if(!.) return - if(client) - if(buckled) - shake_camera(src, 2, 1) // turn it down a bit come on - else - shake_camera(src, 7, 1) + if(!client) + return + + if(buckled) + shake_camera(src, 2, 1) // turn it down a bit come on + else + shake_camera(src, 7, 1) + + client.new_parallax_movedir = travelDir ? WEST : NORTH + update_parallax_contents() /mob/living/carbon/onShuttleMove() . = ..() @@ -54,8 +59,16 @@ if(smooth) queue_smooth(src) +/mob/postDock(obj/docking_port/S1, transit, list/parallax_mobs) + if(!client) + return + if(transit) + parallax_mobs.Add(src) + return + client.new_parallax_movedir = 0 + update_parallax_contents() + /obj/machinery/door/airlock/postDock(obj/docking_port/stationary/S1) . = ..() if(!S1.lock_shuttle_doors && id_tag == "s_docking_airlock") INVOKE_ASYNC(src, .proc/unlock) - diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 51ba6c6bad1..b2d710ba215 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -189,7 +189,7 @@ /obj/docking_port/stationary/transit name = "In transit" turf_type = /turf/space/transit - + var/area/shuttle/transit/assigned_area lock_shuttle_doors = 1 /obj/docking_port/stationary/transit/register() @@ -215,6 +215,7 @@ var/roundstart_move //id of port to send shuttle to at roundstart var/travelDir = 0 //direction the shuttle would travel in var/rebuildable = 0 //can build new shuttle consoles for this one + var/list/parallax_mobs = list() //mobs to unparallax var/obj/docking_port/stationary/destination var/obj/docking_port/stationary/previous @@ -358,7 +359,7 @@ var/obj/docking_port/stationary/S0 = get_docked() var/obj/docking_port/stationary/S1 = findTransitDock() if(S1) - if(dock(S1)) + if(dock(S1, , TRUE)) WARNING("shuttle \"[id]\" could not enter transit space. Docked at [S0 ? S0.id : "null"]. Transit dock [S1 ? S1.id : "null"].") else previous = S0 @@ -429,7 +430,7 @@ //this is the main proc. It instantly moves our mobile port to stationary port S1 //it handles all the generic behaviour, such as sanity checks, closing doors on the shuttle, stunning mobs, etc -/obj/docking_port/mobile/proc/dock(obj/docking_port/stationary/S1, force=FALSE) +/obj/docking_port/mobile/proc/dock(obj/docking_port/stationary/S1, force=FALSE, transit=FALSE) // Crashing this ship with NO SURVIVORS if(S1.get_docked() == src) remove_ripples() @@ -494,7 +495,7 @@ //move mobile to new location for(var/atom/movable/AM in T0) - AM.onShuttleMove(T0, T1, rotation) + AM.onShuttleMove(T0, T1, rotation, travelDir) if(rotation) T1.shuttleRotate(rotation) @@ -516,7 +517,15 @@ var/turf/T1 = A1 T1.postDock(S1) for(var/atom/movable/M in T1) - M.postDock(S1) + M.postDock(S1, transit, parallax_mobs) + + // For mobs who move away from a transiting shuttle for whatever reason (teleportation, jumping, etc) so that they don't get stuck parallaxing + if(!transit) + for(var/mob/M in parallax_mobs) + if(M.client && M.client.new_parallax_movedir) + M.client.new_parallax_movedir = 0 + M.update_parallax_contents() + parallax_mobs = list() loc = S1.loc dir = S1.dir diff --git a/config/example/dbconfig.txt b/config/example/dbconfig.txt index 2404119d52f..ad859d92543 100644 --- a/config/example/dbconfig.txt +++ b/config/example/dbconfig.txt @@ -9,7 +9,7 @@ ## This value must be set to the version of the paradise schema in use. ## If this value does not match, the SQL database will not be loaded and an error will be generated. ## Roundstart will be delayed. -DB_VERSION 8 +DB_VERSION 9 ## Server the MySQL database can be found at. # Examples: localhost, 200.135.5.43, www.mysqldb.com, etc. diff --git a/icons/effects/parallax.dmi b/icons/effects/parallax.dmi new file mode 100644 index 00000000000..22f091ff11a Binary files /dev/null and b/icons/effects/parallax.dmi differ diff --git a/paradise.dme b/paradise.dme index 86eb2825b04..bd4af9dc9fe 100644 --- a/paradise.dme +++ b/paradise.dme @@ -143,6 +143,7 @@ #include "code\_onclick\hud\monkey.dm" #include "code\_onclick\hud\movable_screen_objects.dm" #include "code\_onclick\hud\other_mobs.dm" +#include "code\_onclick\hud\parallax.dm" #include "code\_onclick\hud\picture_in_picture.dm" #include "code\_onclick\hud\plane_master.dm" #include "code\_onclick\hud\radial.dm" @@ -224,6 +225,7 @@ #include "code\controllers\subsystem\npcpool.dm" #include "code\controllers\subsystem\overlays.dm" #include "code\controllers\subsystem\radio.dm" +#include "code\controllers\subsystem\parallax.dm" #include "code\controllers\subsystem\shuttles.dm" #include "code\controllers\subsystem\spacedrift.dm" #include "code\controllers\subsystem\sun.dm"