Merge branch 'master' into upstream-merge-10961

This commit is contained in:
Nadyr
2021-07-08 00:09:21 -04:00
committed by GitHub
49 changed files with 1604 additions and 1237 deletions

View File

@@ -11,6 +11,9 @@
//#define ZASDBG // Uncomment to turn on super detailed ZAS debugging that probably won't even compile.
#define MULTIZAS // Uncomment to turn on Multi-Z ZAS Support!
// Movement Compile Options
//#define CARDINAL_INPUT_ONLY // Uncomment to disable diagonal player movement (restore previous cardinal-moves-only behavior)
// Comment/Uncomment this to turn off/on shuttle code debugging logs
#define DEBUG_SHUTTLES

View File

@@ -54,6 +54,9 @@ What is the naming convention for planes or layers?
#define OPENSPACE_LAYER 600 // Above every other layer
#define OPENSPACE_BACKDROP_PLANE -50 // Black square has to be above openspace turfs
#define MAP_VIEW_PLANE -48 // Plane for 'embedded' maps in consoles and such
#define MAP_VIEW_LAYER 0
// Turf Planes
#define PLATING_PLANE -44 // Plating
#define DISPOSAL_LAYER 2.1 // Under objects, even when planeswapped

21
code/__defines/input.dm Normal file
View File

@@ -0,0 +1,21 @@
// Bitflags for the move_keys_held bitfield.
#define NORTH_KEY (1<<0)
#define SOUTH_KEY (1<<1)
#define EAST_KEY (1<<2)
#define WEST_KEY (1<<3)
#define W_KEY (1<<4)
#define S_KEY (1<<5)
#define D_KEY (1<<6)
#define A_KEY (1<<7)
// Combine the held WASD and arrow keys together (OR) into byond N/S/E/W dir
#define MOVEMENT_KEYS_TO_DIR(MK) ((((MK)>>4)|(MK))&(ALL_CARDINALS))
// Bitflags for pressed modifier keys.
// Values chosen specifically to not conflict with dir bitfield, in case we want to smoosh them together.
#define CTRL_KEY (1<<8)
#define SHIFT_KEY (1<<9)
#define ALT_KEY (1<<10)
// Uncomment to get a lot of debug logging for movement keys.
// #define DEBUG_INPUT(A) to_world_log(A)
#define DEBUG_INPUT(A)

View File

@@ -56,6 +56,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define INIT_ORDER_DBCORE 41 //CHOMPEdit
#define INIT_ORDER_SQLITE 40
#define INIT_ORDER_MEDIA_TRACKS 38 // Gotta get that lobby music up, yo
#define INIT_ORDER_INPUT 37
#define INIT_ORDER_CHEMISTRY 35
#define INIT_ORDER_VIS 32
#define INIT_ORDER_SKYBOX 30
@@ -115,6 +116,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define FIRE_PRIORITY_PROJECTILES 150
#define FIRE_PRIORITY_CHAT 400
#define FIRE_PRIORITY_OVERLAYS 500
#define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost.
// Macro defining the actual code applying our overlays lists to the BYOND overlays list. (I guess a macro for speed)
// TODO - I don't really like the location of this macro define. Consider it. ~Leshana

View File

@@ -244,7 +244,7 @@ GLOBAL_LIST_EMPTY(mannequins)
wing_styles_list[path] = instance
// VOREStation Add - Vore Modes!
paths = subtypesof(/datum/digest_mode)
paths = typesof(/datum/digest_mode)
for(var/T in paths)
var/datum/digest_mode/DM = new T
GLOB.digest_modes[DM.id] = DM

View File

@@ -96,6 +96,19 @@
if ("SOUTHEAST") return 6
if ("SOUTHWEST") return 10
// Turns a direction into text showing all bits set
/proc/dirs2text(direction)
if(!direction)
return ""
var/list/dirs = list()
if(direction & NORTH) dirs += "NORTH"
if(direction & SOUTH) dirs += "SOUTH"
if(direction & EAST) dirs += "EAST"
if(direction & WEST) dirs += "WEST"
if(direction & UP) dirs += "UP"
if(direction & DOWN) dirs += "DOWN"
return dirs.Join(" ")
// Converts an angle (degrees) into an ss13 direction
/proc/angle2dir(var/degree)
degree = (degree + 22.5) % 365 // 22.5 = 45 / 2

View File

@@ -29,8 +29,8 @@
/obj/screen/map_view
icon_state = "blank"
// Map view has to be on the lowest plane to enable proper lighting
layer = SPACE_PLANE
plane = SPACE_PLANE
layer = MAP_VIEW_LAYER
plane = MAP_VIEW_PLANE
/**
* A generic background object.
@@ -41,8 +41,8 @@
name = "background"
icon = 'icons/mob/map_backgrounds.dmi'
icon_state = "clear"
layer = SPACE_PLANE
plane = SPACE_PLANE
layer = MAP_VIEW_LAYER
plane = MAP_VIEW_PLANE
/**
* Sets screen_loc of this screen object, in form of point coordinates,

View File

@@ -6,12 +6,13 @@
/obj/screen/skybox
name = "skybox"
icon = null
vis_flags = NONE
appearance_flags = TILE_BOUND|PIXEL_SCALE
mouse_opacity = 0
anchored = TRUE
simulated = FALSE
screen_loc = "CENTER,CENTER"
layer = OBJ_LAYER
layer = BACKGROUND_LAYER
plane = SKYBOX_PLANE
blend_mode = BLEND_MULTIPLY // You actually need to do it this way or you see it in occlusion.

View File

@@ -0,0 +1,13 @@
SUBSYSTEM_DEF(input)
name = "Input"
wait = 1 // SS_TICKER means this runs every tick
init_order = INIT_ORDER_INPUT
flags = SS_TICKER
priority = FIRE_PRIORITY_INPUT
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
/datum/controller/subsystem/input/fire()
var/list/clients = GLOB.clients // Let's sing the list cache song
for(var/i in 1 to clients.len)
var/client/C = clients[i]
C?.keyLoop()

View File

@@ -7,7 +7,8 @@ SUBSYSTEM_DEF(persistence)
/// Places our subsystem can spawn paintings (helps with art spawning differently across maps)
var/list/obj/structure/sign/painting/painting_frames = list()
var/list/paintings = list()
var/list/all_paintings = list()
var/list/unpicked_paintings = list()
/datum/controller/subsystem/persistence/Initialize()
. = ..()

View File

@@ -1,6 +1,6 @@
/atom/movable
layer = OBJ_LAYER
appearance_flags = TILE_BOUND|PIXEL_SCALE|KEEP_TOGETHER
appearance_flags = TILE_BOUND|PIXEL_SCALE|KEEP_TOGETHER|LONG_GLIDE
glide_size = 8
var/last_move = null //The direction the atom last moved
var/anchored = 0
@@ -119,7 +119,8 @@
var/dest_z = get_z(newloc)
// Do The Move
glide_for(movetime)
if(movetime)
glide_for(movetime) // First attempt, lets let the diag do it.
loc = newloc
. = TRUE
@@ -161,7 +162,7 @@
// place due to a Crossed, Bumped, etc. call will interrupt
// the second half of the diagonal movement, or the second attempt
// at a first half if step() fails because we hit something.
glide_for(movetime)
glide_for(movetime * 2)
if (direct & NORTH)
if (direct & EAST)
if (step(src, NORTH) && moving_diagonally)
@@ -214,7 +215,7 @@
// If we moved, call Moved() on ourselves
if(.)
Moved(oldloc, direct, FALSE, movetime)
Moved(oldloc, direct, FALSE, movetime ? movetime : ( (TICKS2DS(WORLD_ICON_SIZE/glide_size)) * (moving_diagonally ? (0.5) : 1) ) )
// Update timers/cooldown stuff
move_speed = world.time - l_move_time

View File

@@ -123,7 +123,7 @@
spawn_positions = 2
alt_titles = list("Journalist" = /datum/alt_title/journalist, "Reporter" = /datum/alt_title/reporter, "Writer" = /datum/alt_title/writer,
"Historian" = /datum/alt_title/historian, "Archivist" = /datum/alt_title/archivist, "Professor" = /datum/alt_title/professor,
"Academic" = /datum/alt_title/academic, "Philosopher" = /datum/alt_title/philosopher)
"Academic" = /datum/alt_title/academic, "Philosopher" = /datum/alt_title/philosopher, "Curator" = /datum/alt_title/curator)
pto_type = PTO_CIVILIAN
/datum/alt_title/reporter
@@ -150,6 +150,9 @@
title = "Philosopher"
title_blurb = "The Philosopher uses the Library as a base of operation to ruminate on nature of life and other great questions, and share their opinions with the crew."
/datum/alt_title/curator
title = "Curator"
title_blurb = "The Curator uses the Library as a base of operation to gather the finest of art for display and preservation."
/datum/job/lawyer
disallow_jobhop = TRUE

View File

@@ -345,6 +345,7 @@
///Description set when canvas is added.
var/desc_with_canvas
var/persistence_id
var/loaded = FALSE
//Presets for art gallery mapping, for paintings to be shared across stations
/obj/structure/sign/painting/public
@@ -402,10 +403,18 @@
. = ..()
if(persistence_id)
. += "<span class='notice'>Any painting placed here will be archived at the end of the shift.</span>"
if(current_canvas)
current_canvas.tgui_interact(user)
. += "<span class='notice'>Use wirecutters to remove the painting.</span>"
// Painting loaded and persistent frame, give a hint about removal safety
if(persistence_id)
if(loaded)
. += "<span class='notice'>Don't worry, the currently framed painting has already been entered into the archives and can be safely removed. It will still be used on future shifts.</span>"
else
. += "<span class='warning'>This painting has not been entered into the archives yet. Removing it will prevent that from happening.</span>"
/obj/structure/sign/painting/proc/frame_canvas(mob/user,obj/item/canvas/new_canvas)
if(!allowed(user))
to_chat(user, "<span class='warning'>You're not comfortable framing this canvas in such a prestigious spot!</span>")
@@ -418,9 +427,13 @@
update_appearance()
/obj/structure/sign/painting/proc/unframe_canvas(mob/living/user)
if(!allowed(user))
to_chat(user, "<span class='warning'>You're not comfortable removing this prestigious canvas!</span>")
return
if(current_canvas)
current_canvas.forceMove(drop_location())
current_canvas = null
loaded = FALSE
to_chat(user, "<span class='notice'>You remove the painting from the frame.</span>")
update_appearance()
@@ -462,12 +475,14 @@
* Deleting paintings leaves their json, so this proc will remove the json and try again if it finds one of those.
*/
/obj/structure/sign/painting/proc/load_persistent()
if(!persistence_id || !SSpersistence.paintings)
if(!persistence_id || !LAZYLEN(SSpersistence.unpicked_paintings))
return
var/list/painting_category = list()
for (var/list/P in SSpersistence.paintings)
for (var/list/P in SSpersistence.unpicked_paintings)
if(P["persistence_id"] == persistence_id)
painting_category[++painting_category.len] = P
var/list/painting
while(!painting)
if(!length(painting_category))
@@ -475,24 +490,30 @@
var/list/chosen = pick(painting_category)
if(!fexists("data/persistent/paintings/[persistence_id]/[chosen["md5"]].png")) //shitmin deleted this art, lets remove json entry to avoid errors
painting_category -= list(chosen)
SSpersistence.unpicked_paintings -= chosen
continue //and try again
painting = chosen
SSpersistence.unpicked_paintings -= chosen
var/title = painting["title"]
var/author_name = painting["author"]
var/author_ckey = painting["ckey"]
var/png = "data/persistent/paintings/[persistence_id]/[painting["md5"]].png"
if(!title)
title = "Untitled Artwork" //legacy artwork allowed null names which was bad for the json, lets fix that
painting["title"] = title
var/icon/I = new(png)
var/obj/item/canvas/new_canvas
var/w = I.Width()
var/h = I.Height()
for(var/T in typesof(/obj/item/canvas))
new_canvas = T
if(initial(new_canvas.width) == w && initial(new_canvas.height) == h)
new_canvas = new T(src)
break
if(!new_canvas)
warning("Couldn't find a canvas to match [w]x[h] of painting")
return
new_canvas.fill_grid_from_icon(I)
new_canvas.generated_icon = I
new_canvas.icon_generated = TRUE
@@ -502,6 +523,7 @@
new_canvas.author_ckey = author_ckey
new_canvas.name = "painting - [title]"
current_canvas = new_canvas
loaded = TRUE
update_appearance()
/obj/structure/sign/painting/proc/save_persistent()
@@ -512,18 +534,20 @@
return
if(!current_canvas.painting_name)
current_canvas.painting_name = "Untitled Artwork"
var/data = current_canvas.get_data_string()
var/md5 = md5(lowertext(data))
LAZYINITLIST(SSpersistence.paintings)
for(var/list/entry in SSpersistence.paintings)
if(entry["md5"] == md5)
for(var/list/entry in SSpersistence.all_paintings)
if(entry["md5"] == md5 && entry["persistence_id"] == persistence_id)
return
var/png_directory = "data/persistent/paintings/[persistence_id]/"
var/png_path = png_directory + "[md5].png"
var/result = rustg_dmi_create_png(png_path,"[current_canvas.width]","[current_canvas.height]",data)
if(result)
CRASH("Error saving persistent painting: [result]")
SSpersistence.paintings += list(list(
SSpersistence.all_paintings += list(list(
"persistence_id" = persistence_id,
"title" = current_canvas.painting_name,
"md5" = md5,
@@ -547,10 +571,10 @@
var/md5 = md5(lowertext(current_canvas.get_data_string()))
var/author = current_canvas.author_ckey
var/list/filenames_found = list()
for(var/list/entry in SSpersistence.paintings)
for(var/list/entry in SSpersistence.all_paintings)
if(entry["md5"] == md5)
filenames_found += "data/persistent/paintings/[entry["persistence_id"]]/[entry["md5"]].png"
SSpersistence.paintings -= entry
SSpersistence.all_paintings -= entry
for(var/png in filenames_found)
if(fexists(png))
fdel(png)
@@ -558,4 +582,5 @@
if(P.current_canvas && md5(P.current_canvas.get_data_string()) == md5)
QDEL_NULL(P.current_canvas)
P.update_appearance()
loaded = FALSE
log_and_message_admins("<span class='notice'>[key_name_admin(user)] has deleted persistent painting made by [author].</span>")

View File

@@ -31,7 +31,14 @@
for(var/atom/movable/AM in contents)
if(AM.simulated)
AM.forceMove(T)
//VOREStation Add Start
if(isanimal(AM))
var/mob/living/simple_mob/AMBLINAL = AM
if(!AMBLINAL.mind)
AMBLINAL.ghostjoin = 1
AMBLINAL.ghostjoin_icon()
active_ghost_pods |= AMBLINAL
//VOREStation Add End
user.visible_message("<span class='notice'>[user] pries \the [src] open.</span>", \
"<span class='notice'>You pry open \the [src].</span>", \
"<span class='notice'>You hear splitting wood.</span>")

View File

@@ -1570,9 +1570,16 @@
var/mob/M = locate(href_list["sendmob"])
if(!M)
return
var/area/A = tgui_input_list(usr, "Pick an area:", "Send Mob", return_sorted_areas())
var/list/areachoices = return_sorted_areas()
var/choice = tgui_input_list(usr, "Pick an area:", "Send Mob", areachoices)
if(!choice)
return
var/area/A = areachoices[choice]
if(!A)
return
M.on_mob_jump()
M.forceMove(pick(get_area_turfs(A)))
var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)]"

View File

@@ -4,25 +4,32 @@
/mob/observer/dead/on_mob_jump()
following = null
/client/proc/Jump()
/client/proc/Jump(areaname as null|anything in return_sorted_areas())
set name = "Jump to Area"
set desc = "Area to jump to"
set category = "Admin"
if(!check_rights(R_ADMIN|R_MOD|R_DEBUG|R_EVENT))
return
if(config.allow_admin_jump)
var/area/A = tgui_input_list(usr, "Pick an area:", "Jump to Area", return_sorted_areas())
if(!config.allow_admin_jump)
tgui_alert_async(usr, "Admin jumping disabled")
return
var/area/A
if(areaname)
A = return_sorted_areas()[areaname]
else
A = tgui_input_list(usr, "Pick an area:", "Jump to Area", return_sorted_areas())
if(!A)
return
usr.on_mob_jump()
usr.forceMove(pick(get_area_turfs(A)))
log_admin("[key_name(usr)] jumped to [A]")
message_admins("[key_name_admin(usr)] jumped to [A]", 1)
feedback_add_details("admin_verb","JA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
else
tgui_alert_async(usr, "Admin jumping disabled")
/client/proc/jumptoturf(var/turf/T in world)
set name = "Jump to Turf"
@@ -40,7 +47,7 @@
return
/// Verb wrapper around do_jumptomob()
/client/proc/jumptomob()
/client/proc/jumptomob(mob as null|anything in mob_list)
set category = "Admin"
set name = "Jump to Mob"
set popup_menu = FALSE //VOREStation Edit - Declutter.
@@ -48,16 +55,16 @@
if(!check_rights(R_ADMIN|R_MOD|R_DEBUG|R_EVENT))
return
var/mob/M = tgui_input_list(usr, "Pick a mob:", "Jump to Mob", mob_list)
if(!M) // Cancelled
return
do_jumptomob(M)
do_jumptomob(mob)
/// Performs the jumps
/// Performs the jumps, also called from admin Topic() for JMP links
/client/proc/do_jumptomob(var/mob/M)
if(!config.allow_admin_jump)
tgui_alert_async(usr, "Admin jumping disabled")
return
if(!M)
M = tgui_input_list(usr, "Pick a mob:", "Jump to Mob", mob_list)
if(!M)
return

View File

@@ -80,3 +80,32 @@
// Runechat messages
var/list/seen_messages
///////////
// INPUT //
///////////
/// Bitfield of modifier keys (Shift, Ctrl, Alt) held currently.
var/mod_keys_held = 0
/// Bitfield of movement keys (WASD/Cursor Keys) held currently.
var/move_keys_held = 0
/// These next two vars are to apply movement for keypresses and releases made while move delayed.
/// Because discarding that input makes the game less responsive.
/// Bitfield of movement dirs that were pressed down *this* cycle (even if not currently held).
/// Note that only dirs that actually are first pressed down during this cycle are included, if it was still held from last cycle it won't be in here.
/// On next move, add this dir to the move that would otherwise be done
var/next_move_dir_add
/// Bitfield of movement dirs that were released *this* cycle (even if currently held).
/// Note that only dirs that were already held at the start of this cycle are included, if it pressed then released it won't be in here.
/// On next move, subtract this dir from the move that would otherwise be done
var/next_move_dir_sub
#ifdef CARDINAL_INPUT_ONLY
/// Movement dir of the most recently pressed movement key. Used in cardinal-only movement mode.
var/last_move_dir_pressed = NONE
#endif

View File

@@ -40,21 +40,24 @@
reagents.add_reagent("nutriment",(nutriment_amt*2),nutriment_desc) //VOREStation Edit: Undoes global nutrition nerf
//Placeholder for effect that trigger on eating that aren't tied to reagents.
/obj/item/weapon/reagent_containers/food/snacks/proc/On_Consume(var/mob/M)
if(!usr)
/obj/item/weapon/reagent_containers/food/snacks/proc/On_Consume(var/mob/living/M)
if(!usr) // what
usr = M
if(!reagents.total_volume)
M.visible_message("<span class='notice'>[M] finishes eating \the [src].</span>","<span class='notice'>You finish eating \the [src].</span>")
usr.drop_from_inventory(src) //so icons update :[
// Embedded-in-food smol vore
for(var/obj/item/weapon/holder/holder in src)
if(holder.held_mob?.devourable)
holder.held_mob.forceMove(M.vore_selected)
holder.held_mob = null
qdel(holder)
usr.drop_from_inventory(src) // Drop food from inventory so it doesn't end up staying on the hud after qdel, and so inhands go away
if(trash)
if(ispath(trash,/obj/item))
var/obj/item/TrashItem = new trash(usr)
usr.put_in_hands(TrashItem)
else if(istype(trash,/obj/item))
usr.put_in_hands(trash)
qdel(src)
return
/obj/item/weapon/reagent_containers/food/snacks/attack_self(mob/user as mob)
if(package && !user.incapacitated())
@@ -4264,7 +4267,7 @@
if (!feeder)
feeder = eater
feeder.drop_from_inventory(src) //so icons update :[ //what the fuck is this????
feeder.drop_from_inventory(src) // Drop food from inventory so it doesn't end up staying on the hud after qdel, and so inhands go away
if(trash)
if(ispath(trash,/obj/item))
@@ -7114,7 +7117,7 @@
desc = "A burger stored in a plastic wrapping for vending machine distribution. Surely it tastes fine!"
package = TRUE
package_trash = /obj/item/trash/vendor_burger
package_open_state = "smolburger"
package_open_state = "smolcheeseburger"
nutriment_amt = 3
nutriment_desc = list("stale burger" = 3)
starts_with = list("sodiumchloride" = 1)

View File

@@ -0,0 +1,45 @@
// You might be wondering why this isn't client level. If focus is null, we don't want you to move.
// Only way to do that is to tie the behavior into the focus's keyLoop().
// THE TRADITIONAL STYLE FROM /TG (modified)
/atom/movable/keyLoop(client/user)
// Bail out if the user is holding the "face direction" key (Maybe?)
// TODO - I think this breaks non-hotkeys WASD movement, so maybe adopt the /tg solution)
if(user.mod_keys_held & CTRL_KEY)
return
var/must_call_move = FALSE
var/movement_dir = MOVEMENT_KEYS_TO_DIR(user.move_keys_held)
if(user.next_move_dir_add)
must_call_move = TRUE // So that next_move_dir_add gets cleared if its time.
movement_dir |= user.next_move_dir_add
if(user.next_move_dir_sub)
DEBUG_INPUT("[(user.next_move_dir_sub & movement_dir) ? "Actually" : "Want to"] subtract [dirs2text(user.next_move_dir_sub)] from [dirs2text(movement_dir)]")
must_call_move = TRUE // So that next_move_dir_sub gets cleared if its time.
movement_dir &= ~user.next_move_dir_sub
// Sanity checks in case you hold left and right and up to make sure you only go up
if((movement_dir & (NORTH|SOUTH)) == (NORTH|SOUTH))
movement_dir &= ~(NORTH|SOUTH)
if((movement_dir & (EAST|WEST)) == (EAST|WEST))
movement_dir &= ~(EAST|WEST)
#ifdef CARDINAL_INPUT_ONLY
if(movement_dir & user.last_move_dir_pressed)
movement_dir = user.last_move_dir_pressed
else if (movement_dir == NORTHEAST || movement_dir == NORTHWEST)
DEBUG_INPUT("overriding to NORTH: movement_dir=[dirs2text(movement_dir)] last=[dirs2text(user.last_move_dir_pressed)]")
movement_dir = NORTH
else if (movement_dir == SOUTHEAST || movement_dir == SOUTHWEST)
DEBUG_INPUT("overriding to SOUTH: movement_dir=[dirs2text(movement_dir)] last=[dirs2text(user.last_move_dir_pressed)]")
movement_dir = SOUTH
#endif
// Compensate for client camera spinning (client.dir) so our movement still makes sense I guess.
if(movement_dir) // Only compensate if non-zero, as byond will auto-fill dir otherwise
movement_dir = turn(movement_dir, -dir2angle(user.dir))
// Move, but only if we actually are planing to move, or we need to clear the next move vars
if(movement_dir || must_call_move)
user.Move(get_step(src, movement_dir), movement_dir)

View File

@@ -0,0 +1,77 @@
// TODO - Optimize this into numerics if this ends up working out
var/global/list/MOVE_KEY_MAPPINGS = list(
"North" = NORTH_KEY,
"South" = SOUTH_KEY,
"East" = EAST_KEY,
"West" = WEST_KEY,
"W" = W_KEY,
"A" = A_KEY,
"S" = S_KEY,
"D" = D_KEY,
"Shift" = SHIFT_KEY,
"Ctrl" = CTRL_KEY,
"Alt" = ALT_KEY,
)
// These verbs are called for all movemen key press and release events
/client/verb/moveKeyDown(movekeyName as text)
set instant = TRUE
set hidden = TRUE
// set name = ".movekeydown"
set name = "KeyDown"
// Map text sent by skin.dmf to our numeric codes. (This can be optimized away once we update skin.dmf)
var/movekey = MOVE_KEY_MAPPINGS[movekeyName]
// Validate input. Must be one (and only one) of the key codes)
if(isnull(movekey) || (movekey & ~0xFFF) || (movekey & (movekey - 1)))
log_debug("Client [ckey] sent an illegal movement key down: [movekeyName] ([movekey])")
return
// Record that we are now holding the key!
move_keys_held |= (movekey & 0x0FF)
mod_keys_held |= (movekey & 0xF00)
// If we were NOT holding at the start of this move cycle and pressed it, remember that.
var/movement = MOVEMENT_KEYS_TO_DIR(movekey)
if(movement && !(next_move_dir_sub & movement) && !(mod_keys_held & CTRL_KEY)) // TODO-LESHANA - Possibly not holding Alt either
DEBUG_INPUT("Saving [dirs2text(movement)] into next_move_dir_ADD")
next_move_dir_add |= movement
#ifdef CARDINAL_INPUT_ONLY
if(movement)
DEBUG_INPUT("set last=[dirs2text(movement)]")
last_move_dir_pressed = movement
#endif
mob.focus?.key_down(movekey, src)
/client/verb/moveKeyUp(movekeyName as text)
set instant = TRUE
set hidden = TRUE
// set name = ".movekeyup"
set name = "KeyUp"
// Map text sent by skin.dmf to our numeric codes. (This can be optimized away once we update skin.dmf)
var/movekey = MOVE_KEY_MAPPINGS[movekeyName]
// Validate input. Must be one (and only one) of the key codes)
if(isnull(movekey) || (movekey & ~0xFFF) || (movekey & (movekey - 1)))
log_debug("Client [ckey] sent an illegal movement key up: [movekeyName] ([movekey])")
return
// Clear bit indicating we were holding the key
move_keys_held &= ~movekey
mod_keys_held &= ~movekey
// If we were holding at the start of this move cycle and now relased it, remember that.
var/movement = MOVEMENT_KEYS_TO_DIR(movekey)
if(movement && !(next_move_dir_add & movement))
DEBUG_INPUT("Saving [dirs2text(movement)] into next_move_dir_SUB")
next_move_dir_sub |= movement
mob.focus?.key_up(movekey, src)
// Called every game tick
/client/keyLoop()
mob.focus?.keyLoop(src)

View File

@@ -0,0 +1,42 @@
# In-code keypress handling system
This whole system is heavily based off of forum_account's keyboard library.
Thanks to forum_account for saving the day, the library can be found
[here](https://secure.byond.com/developer/Forum_account/Keyboard)!
.dmf macros have some very serious shortcomings. For example, they do not allow reusing parts
of one macro in another, so giving cyborgs their own shortcuts to swap active module couldn't
inherit the movement that all mobs should have anyways. The webclient only supports one macro,
so having more than one was problematic. Additionally each keybind has to call an actual
verb, which meant a lot of hidden verbs that just call one other proc. Also our existing
macro was really bad and tied unrelated behavior into `Northeast()`, `Southeast()`, `Northwest()`,
and `Southwest()`.
The basic premise of this system is to not screw with .dmf macro setup at all and handle
pressing those keys in the code instead. We have every key call `client.keyDown()`
or `client.keyUp()` with the pressed key as an argument. Certain keys get processed
directly by the client because they should be doable at any time, then we call
`keyDown()` or `keyUp()` on the client's holder and the client's mob's focus.
By default `mob.focus` is the mob itself, but you can set it to any datum to give control of a
client's keypresses to another object. This would be a good way to handle a menu or driving
a mech. You can also set it to null to disregard input from a certain user.
Movement is handled by having each client call `client.keyLoop()` every game tick.
As above, this calls holder and `focus.keyLoop()`. `atom/movable/keyLoop()` handles movement
Try to keep the calculations in this proc light. It runs every tick for every client after all!
You can also tell which keys are being held down now. Each client a list of keys pressed called
`keys_held`. Each entry is a key as a text string associated with the world.time when it was
pressed.
No client-set keybindings at this time, but it shouldn't be too hard if someone wants.
Notes about certain keys:
* `Tab` has client-sided behavior but acts normally
* `T`, `O`, and `M` move focus to the input when pressed. This fires the keyUp macro right away.
* `\` needs to be escaped in the dmf so any usage is `\\`
You cannot `TICK_CHECK` or check `world.tick_usage` inside of procs called by key down and up
events. They happen outside of a byond tick and have no meaning there. Key looping
works correctly since it's part of a subsystem, not direct input.

View File

@@ -0,0 +1,34 @@
// Set a client's focus to an object and override these procs on that object to let it handle keypresses
/datum/proc/key_down(key, client/user) // Called when a key is pressed down initially
return
/datum/proc/key_up(key, client/user) // Called when a key is released
return
/datum/proc/keyLoop(client/user) // Called once every server tick
set waitfor = FALSE
return
/// Set mob's focus
/// TODO - Do we even need this concept?
/mob/proc/set_focus(datum/new_focus)
if(focus == new_focus)
return
focus = new_focus
/// Turns a keys bitfield into text showing all bits set
/proc/keys2text(keys)
if(!keys)
return ""
var/list/out = list()
if(keys & NORTH_KEY) out += "NORTH"
if(keys & SOUTH_KEY) out += "SOUTH"
if(keys & EAST_KEY) out += "EAST"
if(keys & WEST_KEY) out += "WEST"
if(keys & W_KEY) out += "W"
if(keys & A_KEY) out += "A"
if(keys & S_KEY) out += "S"
if(keys & D_KEY) out += "D"
if(keys & CTRL_KEY) out += "CTRL"
if(keys & SHIFT_KEY) out += "SHIFT"
if(keys & ALT_KEY) out += "ALT"
return out.Join(" ")

View File

@@ -139,18 +139,6 @@
. * applied_lum_b \
);
#define APPLY_CORNER_SIMPLE(C) \
. = light_power; \
var/OLD = effect_str[C]; \
\
C.update_lumcount \
( \
(. * lum_r) - (OLD * applied_lum_r), \
(. * lum_g) - (OLD * applied_lum_g), \
(. * lum_b) - (OLD * applied_lum_b) \
); \
/datum/light_source/proc/remove_lum()
applied = FALSE
for (var/datum/lighting_corner/corner as anything in effect_str)
@@ -284,91 +272,7 @@
UNSETEMPTY(effect_str)
// For planets and fake suns
/datum/light_source/sun
light_range = 1
light_color = "#FFFFFF"
light_power = 2
var/applied_power = 2
/datum/light_source/sun/New()
return
/datum/light_source/sun/force_update()
return
/datum/light_source/sun/vis_update()
return
/datum/light_source/sun/update_corners(var/list/turfs_to_update)
if(!LAZYLEN(turfs_to_update))
stack_trace("Planet sun tried to update with no turfs given")
return
// Update lum_r/g/b from our light_color
PARSE_LIGHT_COLOR(src)
// Noop update
if(lum_r == applied_lum_r && lum_g == applied_lum_g && lum_b == applied_lum_b && light_power == applied_power)
return
// No reason to unapply on the first run or if previous run was 0 power
if(applied)
remove_lum()
// Entirely dark, just stop now that we've remove_lum()'d
if(!light_power)
applied = FALSE
return
LAZYINITLIST(effect_str)
var/list/datum/lighting_corner/corners = list()
for(var/turf/T as anything in turfs_to_update)
if(!IS_OPAQUE_TURF(T))
if(!T.lighting_corners_initialised)
T.generate_missing_corners()
var/datum/lighting_corner/LC = T.lighting_corner_NE
if(!corners[LC])
corners[LC] = 1
APPLY_CORNER_SIMPLE(LC)
LAZYADD(LC.affecting, src)
effect_str[LC] = .
LC = T.lighting_corner_SE
if(!corners[LC])
corners[LC] = 1
APPLY_CORNER_SIMPLE(LC)
LAZYADD(LC.affecting, src)
effect_str[LC] = .
LC = T.lighting_corner_NW
if(!corners[LC])
corners[LC] = 1
APPLY_CORNER_SIMPLE(LC)
LAZYADD(LC.affecting, src)
effect_str[LC] = .
LC = T.lighting_corner_SW
if(!corners[LC])
corners[LC] = 1
APPLY_CORNER_SIMPLE(LC)
LAZYADD(LC.affecting, src)
effect_str[LC] = .
CHECK_TICK
applied_lum_r = lum_r
applied_lum_g = lum_g
applied_lum_b = lum_b
applied_power = light_power
applied = TRUE // remove_lum() now necessary in the future
UNSETEMPTY(effect_str)
#undef EFFECT_UPDATE
#undef LUM_FALLOFF
#undef REMOVE_CORNER
#undef APPLY_CORNER
#undef APPLY_CORNER_SIMPLE

View File

@@ -98,7 +98,6 @@
sight |= SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF
see_invisible = SEE_INVISIBLE_OBSERVER
see_in_dark = world.view //I mean. I don't even know if byond has occlusion culling... but...
verbs += /mob/observer/dead/proc/dead_tele
var/turf/T
if(ismob(body))
@@ -342,6 +341,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/area/A = areas[key]
if(A.z in using_map?.secret_levels)
areas -= key
return areas
/mob/observer/dead/proc/jumpable_mobs()
@@ -353,40 +353,61 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/mobz = get_z(mobs[key])
if(mobz in using_map?.secret_levels)
mobs -= key
return mobs
/mob/observer/dead/proc/dead_tele()
set category = "Ghost"
/mob/observer/dead/verb/dead_tele(areaname as null|anything in jumpable_areas())
set name = "Teleport"
set desc = "Teleport to a location"
set category = "Ghost"
set desc = "Teleport to a location."
if(!istype(usr, /mob/observer/dead))
to_chat(usr, "Not when you're not dead!")
return
var/area/A
if(!areaname)
var/list/areas = jumpable_areas()
var/input = tgui_input_list(usr, "Select an area:", "Ghost Teleport", areas)
if(!input)
return
A = areas[input]
if(!A)
return
var/area/A = areas[input]
if(!A) return
usr.forceMove(pick(get_area_turfs(A)))
if(!istype(usr, /mob/observer/dead))
to_chat(usr, "Not when you're not dead!")
return
usr.forceMove(pick(get_area_turfs(A || jumpable_areas()[areaname])))
usr.on_mob_jump()
/mob/observer/dead/verb/follow()
/mob/observer/dead/verb/follow(mobname as null|anything in jumpable_mobs())
set name = "Follow"
set category = "Ghost"
set name = "Follow" // "Haunt"
set desc = "Follow and haunt a mob."
if(!istype(usr, /mob/observer/dead))
to_chat(usr, "Not when you're not dead!")
return
var/mob/M
if(!mobname)
var/list/possible_mobs = jumpable_mobs()
var/input = tgui_input_list(usr, "Select a mob:", "Ghost Follow", possible_mobs)
if(!input)
return
M = possible_mobs[input]
if(!M)
return
var/target = possible_mobs[input]
if(!target) return
ManualFollow(target)
if(!istype(usr, /mob/observer/dead))
to_chat(usr, "Not when you're not dead!")
return
ManualFollow(M || jumpable_mobs()[mobname])
/mob/observer/dead/forceMove(atom/destination)
if(client?.holder)

View File

@@ -45,6 +45,12 @@
/mob/living/carbon/brain/isSynthetic()
return istype(loc, /obj/item/device/mmi)
/mob/living/carbon/brain/runechat_holder(datum/chatmessage/CM)
if(isturf(loc))
return ..()
return loc
/mob/living/carbon/brain/set_typing_indicator(var/state)
if(isturf(loc))
return ..()

View File

@@ -135,11 +135,139 @@ var/list/_human_default_emotes = list(
//VOREStation Add End
)
//VOREStation Add Start
var/list/_simple_mob_default_emotes = list(
/decl/emote/visible/blink,
/decl/emote/visible/nod,
/decl/emote/visible/shake,
/decl/emote/visible/shiver,
/decl/emote/visible/collapse,
/decl/emote/audible/gasp,
/decl/emote/audible/choke,
/decl/emote/audible/sneeze,
/decl/emote/audible/sniff,
/decl/emote/audible/snore,
/decl/emote/audible/whimper,
/decl/emote/audible/whistle,
/decl/emote/audible/whistle/quiet,
/decl/emote/audible/whistle/wolf,
/decl/emote/audible/whistle/summon,
/decl/emote/audible/yawn,
/decl/emote/audible/clap,
/decl/emote/audible/chuckle,
/decl/emote/audible/cough,
/decl/emote/audible/cry,
/decl/emote/audible/sigh,
/decl/emote/audible/laugh,
/decl/emote/audible/mumble,
/decl/emote/audible/grumble,
/decl/emote/audible/groan,
/decl/emote/audible/moan,
/decl/emote/audible/grunt,
/decl/emote/audible/slap,
/decl/emote/audible/crack,
/decl/emote/human/deathgasp,
/decl/emote/audible/giggle,
/decl/emote/audible/scream,
/decl/emote/visible/airguitar,
/decl/emote/visible/blink_r,
/decl/emote/visible/bow,
/decl/emote/visible/salute,
/decl/emote/visible/flap,
/decl/emote/visible/aflap,
/decl/emote/visible/drool,
/decl/emote/visible/eyebrow,
/decl/emote/visible/twitch,
/decl/emote/visible/dance,
/decl/emote/visible/twitch_v,
/decl/emote/visible/faint,
/decl/emote/visible/frown,
/decl/emote/visible/blush,
/decl/emote/visible/wave,
/decl/emote/visible/glare,
/decl/emote/visible/stare,
/decl/emote/visible/look,
/decl/emote/visible/point,
/decl/emote/visible/raise,
/decl/emote/visible/grin,
/decl/emote/visible/shrug,
/decl/emote/visible/smile,
/decl/emote/visible/pale,
/decl/emote/visible/tremble,
/decl/emote/visible/wink,
/decl/emote/visible/hug,
/decl/emote/visible/signal,
/decl/emote/visible/afold,
/decl/emote/visible/alook,
/decl/emote/visible/eroll,
/decl/emote/visible/hbow,
/decl/emote/visible/hip,
/decl/emote/visible/holdup,
/decl/emote/visible/hshrug,
/decl/emote/visible/crub,
/decl/emote/visible/erub,
/decl/emote/visible/fslap,
/decl/emote/visible/ftap,
/decl/emote/visible/hrub,
/decl/emote/visible/hspread,
/decl/emote/visible/rsalute,
/decl/emote/visible/rshoulder,
/decl/emote/visible/squint,
/decl/emote/visible/tfist,
/decl/emote/visible/tilt,
/decl/emote/visible/spin,
/decl/emote/visible/sidestep,
/decl/emote/visible/vomit,
/decl/emote/visible/floorspin,
/decl/emote/visible/flip,
/decl/emote/audible/awoo,
/decl/emote/audible/awoo2,
/decl/emote/audible/growl,
/decl/emote/audible/woof,
/decl/emote/audible/woof2,
/decl/emote/audible/nya,
/decl/emote/audible/mrowl,
/decl/emote/audible/peep,
/decl/emote/audible/chirp,
/decl/emote/audible/hoot,
/decl/emote/audible/weh,
/decl/emote/audible/merp,
/decl/emote/audible/myarp,
/decl/emote/audible/bark,
/decl/emote/audible/bork,
/decl/emote/audible/mrow,
/decl/emote/audible/hypno,
/decl/emote/audible/hiss,
/decl/emote/audible/rattle,
/decl/emote/audible/squeak,
/decl/emote/audible/geck,
/decl/emote/audible/baa,
/decl/emote/audible/baa2,
/decl/emote/audible/mar,
/decl/emote/audible/wurble,
/decl/emote/audible/snort,
/decl/emote/audible/meow,
/decl/emote/audible/moo,
/decl/emote/audible/croak,
/decl/emote/audible/gao,
/decl/emote/audible/cackle,
/decl/emote/audible/squish,
/decl/emote/audible/spiderchitter,
/decl/emote/audible/spiderpurr,
/decl/emote/visible/mlem,
/decl/emote/visible/blep
)
//VOREStation Add End
/mob/living/carbon/human/get_available_emotes()
. = global._human_default_emotes
if(length(species?.default_emotes))
. |= species.default_emotes
/mob/living/simple_mob/get_available_emotes()
. = global._simple_mob_default_emotes
/mob/living/carbon/human/verb/pose()
set name = "Set Pose"
set desc = "Sets a description which will be shown when someone examines you."

View File

@@ -3,7 +3,7 @@
/mob/living
var/ooc_notes = null
appearance_flags = TILE_BOUND|PIXEL_SCALE|KEEP_TOGETHER
appearance_flags = TILE_BOUND|PIXEL_SCALE|KEEP_TOGETHER|LONG_GLIDE
var/hunger_rate = DEFAULT_HUNGER_FACTOR
//custom say verbs
var/custom_say = null

View File

@@ -197,7 +197,15 @@ default behaviour is:
now_pushing = 0
return
step(AM, t)
var/turf/T = AM.loc
var/turf/T2 = get_step(AM,t)
if(!T2) // Map edge
now_pushing = 0
return
var/move_time = movement_delay(loc, t)
move_time = DS2NEARESTTICK(move_time)
if(AM.Move(T2, t, move_time))
Move(T, t, move_time)
if(ishuman(AM) && AM:grabbed_by)
for(var/obj/item/weapon/grab/G in AM:grabbed_by)

View File

@@ -141,7 +141,12 @@ GLOBAL_VAR_INIT(chicken_count, 0) // How mant chickens DO we have?
if(!stat)
amount_grown += rand(1,2)
if(amount_grown >= 100)
new /mob/living/simple_mob/animal/passive/chicken(src.loc)
//VOREStation Edit Begin
var/mob/living/simple_mob/animal/passive/chicken/C = new (src.loc)
C.ghostjoin = 1
C.ghostjoin_icon()
active_ghost_pods |= C
//VOREStation Edit End
qdel(src)
// Say Lists

View File

@@ -40,6 +40,7 @@
else
living_mob_list += src
lastarea = get_area(src)
set_focus(src) // VOREStation Add - Key Handling
hook_vr("mob_new",list(src)) //VOREStation Code
update_transform() // Some mobs may start bigger or smaller than normal.
return ..()
@@ -616,6 +617,9 @@
stat("CPU:","[world.cpu]")
stat("Instances:","[world.contents.len]")
stat(null, "Time Dilation: [round(SStime_track.time_dilation_current,1)]% AVG:([round(SStime_track.time_dilation_avg_fast,1)]%, [round(SStime_track.time_dilation_avg,1)]%, [round(SStime_track.time_dilation_avg_slow,1)]%)")
stat("Keys Held", keys2text(client.move_keys_held | client.mod_keys_held))
stat("Next Move ADD", dirs2text(client.next_move_dir_add))
stat("Next Move SUB", dirs2text(client.next_move_dir_sub))
if(statpanel("MC"))
stat("Location:", "([x], [y], [z]) [loc]")
@@ -689,6 +693,7 @@
/mob/proc/facedir(var/ndir)
if(!canface() || (client && (client.moving || !checkMoveCooldown())))
DEBUG_INPUT("Denying Facedir for [src] (moving=[client?.moving])")
return 0
set_dir(ndir)
if(buckled && buckled.buckle_movable)

View File

@@ -231,3 +231,5 @@
var/in_enclosed_vehicle = 0 //For mechs and fighters ambiance. Can be used in other cases.
var/list/progressbars = null //VOREStation Edit
var/datum/focus //What receives our keyboard inputs. src by default // VOREStation Add - Key Handling

View File

@@ -140,22 +140,32 @@
// Used many times below, faster reference.
var/atom/loc = my_mob.loc
// We're controlling an object which is SOMEHOW DIFFERENT FROM AN EYE??
// We're controlling an object which is when admins possess an object.
if(my_mob.control_object)
Move_object(direct)
// Ghosty mob movement
if(my_mob.incorporeal_move && isobserver(my_mob))
Process_Incorpmove(direct)
DEBUG_INPUT("--------")
next_move_dir_add = 0 // This one I *think* exists so you can tap move and it will move even if delay isn't quite up.
next_move_dir_sub = 0 // I'm not really sure why next_move_dir_sub even exists.
return
// We're in the middle of another move we've already decided to do
if(moving)
log_debug("Client [src] attempted to move while moving=[moving]")
return 0
// We're still cooling down from the last move
if(!my_mob.checkMoveCooldown())
return
DEBUG_INPUT("--------")
next_move_dir_add = 0 // This one I *think* exists so you can tap move and it will move even if delay isn't quite up.
next_move_dir_sub = 0 // I'm not really sure why next_move_dir_sub even exists.
if(!n || !direct)
return
// If dead and we try to move in our mob, it leaves our body
if(my_mob.stat == DEAD && isliving(my_mob) && !my_mob.forbid_seeing_deadchat)
@@ -287,6 +297,10 @@
else
. = my_mob.SelfMove(n, direct, total_delay)
// If we ended up moving diagonally, increase delay.
if((direct & (direct - 1)) && mob.loc == n)
my_mob.setMoveCooldown(total_delay * 2)
// If we have a grab
var/list/grablist = my_mob.ret_grab()
if(LAZYLEN(grablist))

View File

@@ -122,6 +122,7 @@
screen_loc = "CENTER"
plane = -100 //Dodge just in case someone instantiates one of these accidentally, don't end up on 0 with plane_master
appearance_flags = PLANE_MASTER
vis_flags = NONE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT //Normally unclickable
alpha = 0 //Hidden from view
var/desired_alpha = 255 //What we go to when we're enabled

View File

@@ -95,7 +95,7 @@
if(stored_mmi)
. = stored_mmi //VOREStation Code
stored_mmi.loc = get_turf(src)
stored_mmi.forceMove(drop_location())
if(owner.mind)
owner.mind.transfer_to(stored_mmi.brainmob)
..()

View File

@@ -32,7 +32,7 @@
/obj/effect/overmap/bluespace_rift/attack_ghost(var/mob/observer/dead/user)
if(!partner && user?.client?.holder)
var/response = tgui_alert(user, "You appear to be staff. This rift has no exit point. If you want to make one, move to where you want it to go, and click 'Make Here', otherwise click 'Cancel'",list("Rift Exit","Cancel","Make Here"))
var/response = tgui_alert(user, "You appear to be staff. This rift has no exit point. If you want to make one, move to where you want it to go, and click 'Make Here', otherwise click 'Cancel'", "Bluespace Rift", list("Cancel","Make Here"))
if(response == "Make Here")
new type(get_turf(user), src)
else if(partner)

View File

@@ -8,16 +8,17 @@
/datum/persistent/paintings/Initialize()
. = ..()
if(fexists(filename))
SSpersistence.paintings = json_decode(file2text(filename))
var/list/tokens = SSpersistence.paintings
SSpersistence.all_paintings = json_decode(file2text(filename))
var/list/tokens = SSpersistence.all_paintings
for(var/list/token in tokens)
token["age"]++ // Increment age!
if(!CheckTokenSanity(token))
tokens -= token
SSpersistence.unpicked_paintings = SSpersistence.all_paintings.Copy()
for(var/obj/structure/sign/painting/P in SSpersistence.painting_frames)
P.load_persistent()
return
/datum/persistent/paintings/CheckTokenSanity(var/list/token)
var/png_filename = "data/paintings/[token["persistence_id"]]/[token["md5"]].png"
@@ -33,4 +34,4 @@
if(fexists(filename))
fdel(filename)
to_file(file(filename), json_encode(SSpersistence.paintings))
to_file(file(filename), json_encode(SSpersistence.all_paintings))

View File

@@ -67,8 +67,8 @@
/obj/machinery/conveyor/proc/update_dir()
if(!(dir in cardinal)) // Diagonal. Forwards is *away* from dir, curving to the right.
forwards = turn(dir, 135)
backwards = turn(dir, 45)
forwards = turn(dir, 45)
backwards = turn(dir, 135)
else
forwards = dir
backwards = turn(dir, 180)

View File

@@ -580,11 +580,9 @@
for(var/obj/item/W in M)
if(istype(W, /obj/item/organ/internal/mmi_holder/posibrain))
var/obj/item/organ/internal/mmi_holder/MMI = W
var/atom/movable/brain = MMI.removed()
if(brain)
M.remove_from_mob(brain,owner)
brain.forceMove(src)
items_preserved += brain
var/obj/item/device/mmi/brainbox = MMI.removed()
if(brainbox)
items_preserved += brainbox
for(var/slot in slots)
var/obj/item/I = M.get_equipped_item(slot = slot)
if(I)

View File

@@ -10,6 +10,10 @@
return
HandleBellyReagents() //CHOMP reagent belly stuff, here to jam it into subsystems and avoid too much cpu usage
// VERY early exit
if(!contents.len)
return
var/play_sound //Potential sound to play at the end to avoid code duplication.
var/to_update = FALSE //Did anything update worthy happen?
@@ -51,19 +55,20 @@
if(hta_returns["to_update"])
to_update = hta_returns["to_update"]
if(!islist(touchable_mobs))
if(!LAZYLEN(touchable_mobs))
return
///////////////////// Early Non-Mode Handling /////////////////////
if(emote_active)
var/list/EL = emote_lists[digest_mode]
if(LAZYLEN(EL) && touchable_mobs && next_emote <= world.time && emote_active)
if(LAZYLEN(EL) && next_emote <= world.time)
var/living_count = 0
for(var/mob/living/L in contents)
living_count++
next_emote = world.time + (emote_time SECONDS)
for(var/mob/living/M in contents)
if(digest_mode == DM_DIGEST && !M.digestable)
continue // don't give digesty messages to indigestible people
var/living_count = 0
for(var/mob/living/L in contents)
living_count++
var/raw_message = pick(EL)
var/formatted_message

View File

@@ -542,8 +542,11 @@
else
swallow_time = istype(prey, /mob/living/carbon/human) ? belly.human_prey_swallow_time : belly.nonhuman_prey_swallow_time
// Their AI should get notified so they can stab us
prey.ai_holder?.react_to_attack(user)
//Timer and progress bar
if(!do_after(user, swallow_time, prey))
if(!do_after(user, swallow_time, prey, exclusive = TRUE))
return FALSE // Prey escpaed (or user disabled) before timer expired.
// If we got this far, nom successful! Announce it!

View File

@@ -61,7 +61,7 @@
if(!ui)
update_preview_icon() //CHOMPEdit
give_client_previews(user.client) //CHOMPEdit
ui = new(user, src, "VorePanel", "Inside!")
ui = new(user, src, "VorePanel", "Vore Panel")
ui.open()
// This looks weird, but all tgui_host is used for is state checking

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View File

@@ -3,8 +3,23 @@ macro "borghotkeymode"
name = "TAB"
command = ".winset \"mainwindow.macro=borgmacro hotkey_toggle.is-checked=false input.focus=true input.background-color=#D3B5B5\""
elem
name = "CENTER+REP"
command = ".center"
name = "Shift"
command = "KeyDown Shift"
elem
name = "Shift+UP"
command = "KeyUp Shift"
elem
name = "Ctrl"
command = "KeyDown Ctrl"
elem
name = "Ctrl+UP"
command = "KeyUp Ctrl"
elem
name = "Alt"
command = "KeyDown Alt"
elem
name = "Alt+UP"
command = "KeyUp Alt"
elem
name = "NORTHEAST"
command = ".northeast"
@@ -24,8 +39,11 @@ macro "borghotkeymode"
name = "CTRL+WEST"
command = "westface"
elem
name = "WEST+REP"
command = ".west"
name = "West"
command = "KeyDown West"
elem
name = "West+UP"
command = "KeyUp West"
elem
name = "ALT+NORTH"
command = "northfaceperm"
@@ -33,8 +51,11 @@ macro "borghotkeymode"
name = "CTRL+NORTH"
command = "northface"
elem
name = "NORTH+REP"
command = ".moveup"
name = "North"
command = "KeyDown North"
elem
name = "North+UP"
command = "KeyUp North"
elem
name = "ALT+EAST"
command = "eastfaceperm"
@@ -42,17 +63,17 @@ macro "borghotkeymode"
name = "CTRL+EAST"
command = "eastface"
elem
name = "EAST+REP"
command = ".moveright"
name = "East"
command = "KeyDown East"
elem
name = "East+UP"
command = "KeyUp East"
elem
name = "ALT+SOUTH"
command = "southfaceperm"
elem
name = "CTRL+SOUTH"
command = "southface"
elem
name = "SOUTH+REP"
command = ".movedown"
elem
name = "CTRL+SHIFT+NORTH"
command = "shiftnorth"
@@ -65,6 +86,11 @@ macro "borghotkeymode"
elem
name = "CTRL+SHIFT+EAST"
command = "shifteast"
name = "South"
command = "KeyDown South"
elem
name = "South+UP"
command = "KeyUp South"
elem
name = "INSERT"
command = "a-intent right"
@@ -99,17 +125,17 @@ macro "borghotkeymode"
name = "5"
command = ".me"
elem
name = "A+REP"
command = ".moveleft"
name = "A"
command = "KeyDown A"
elem
name = "CTRL+A+REP"
command = ".moveleft"
name = "A+UP"
command = "KeyUp A"
elem
name = "D+REP"
command = ".moveright"
name = "D"
command = "KeyDown D"
elem
name = "CTRL+D+REP"
command = ".moveright"
name = "D+UP"
command = "KeyUp D"
elem
name = "F"
command = "a-intent left"
@@ -141,20 +167,20 @@ macro "borghotkeymode"
name = "CTRL+R"
command = ".southwest"
elem "s_key"
name = "S+REP"
command = ".movedown"
name = "S"
command = "KeyDown S"
elem
name = "CTRL+S+REP"
command = ".movedown"
name = "S+UP"
command = "KeyUp S"
elem
name = "T"
command = ".say"
elem "w_key"
name = "W+REP"
command = ".moveup"
name = "W"
command = "KeyDown W"
elem
name = "CTRL+W+REP"
command = ".moveup"
name = "W+UP"
command = "KeyUp W"
elem
name = "X"
command = ".northeast"
@@ -236,8 +262,23 @@ macro "macro"
name = "TAB"
command = ".winset \"mainwindow.macro=hotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true\""
elem
name = "CENTER+REP"
command = ".center"
name = "Shift"
command = "KeyDown Shift"
elem
name = "Shift+UP"
command = "KeyUp Shift"
elem
name = "Ctrl"
command = "KeyDown Ctrl"
elem
name = "Ctrl+UP"
command = "KeyUp Ctrl"
elem
name = "Alt"
command = "KeyDown Alt"
elem
name = "Alt+UP"
command = "KeyUp Alt"
elem
name = "NORTHEAST"
command = ".northeast"
@@ -257,8 +298,11 @@ macro "macro"
name = "CTRL+WEST"
command = "westface"
elem
name = "WEST+REP"
command = ".moveleft"
name = "West"
command = "KeyDown West"
elem
name = "West+UP"
command = "KeyUp West"
elem
name = "ALT+NORTH"
command = "northfaceperm"
@@ -266,8 +310,11 @@ macro "macro"
name = "CTRL+NORTH"
command = "northface"
elem
name = "NORTH+REP"
command = ".moveup"
name = "North"
command = "KeyDown North"
elem
name = "North+UP"
command = "KeyUp North"
elem
name = "ALT+EAST"
command = "eastfaceperm"
@@ -275,17 +322,17 @@ macro "macro"
name = "CTRL+EAST"
command = "eastface"
elem
name = "EAST+REP"
command = ".moveright"
name = "East"
command = "KeyDown East"
elem
name = "East+UP"
command = "KeyUp East"
elem
name = "ALT+SOUTH"
command = "southfaceperm"
elem
name = "CTRL+SOUTH"
command = "southface"
elem
name = "SOUTH+REP"
command = ".movedown"
elem
name = "CTRL+SHIFT+NORTH"
command = "shiftnorth"
@@ -298,6 +345,11 @@ macro "macro"
elem
name = "CTRL+SHIFT+EAST"
command = "shifteast"
name = "South"
command = "KeyDown South"
elem
name = "South+UP"
command = "KeyUp South"
elem
name = "INSERT"
command = "a-intent right"
@@ -317,11 +369,17 @@ macro "macro"
name = "CTRL+4"
command = "a-intent harm"
elem
name = "CTRL+A+REP"
command = ".moveleft"
name = "CTRL+A"
command = "KeyDown A"
elem
name = "CTRL+D+REP"
command = ".moveright"
name = "CTRL+A+UP"
command = "KeyUp A"
elem
name = "CTRL+D"
command = "KeyDown D"
elem
name = "CTRL+D+UP"
command = "KeyUp D"
elem
name = "CTRL+E"
command = "quick-equip"
@@ -338,11 +396,17 @@ macro "macro"
name = "CTRL+R"
command = ".southwest"
elem
name = "CTRL+S+REP"
command = ".movedown"
name = "CTRL+S"
command = "KeyDown S"
elem
name = "CTRL+W+REP"
command = ".moveup"
name = "CTRL+S+UP"
command = "KeyUp S"
elem
name = "CTRL+W"
command = "KeyDown W"
elem
name = "CTRL+W+UP"
command = "KeyUp W"
elem
name = "CTRL+X"
command = ".northeast"
@@ -421,8 +485,23 @@ macro "hotkeymode"
name = "TAB"
command = ".winset \"mainwindow.macro=macro hotkey_toggle.is-checked=false input.focus=true\""
elem
name = "CENTER+REP"
command = ".center"
name = "Shift"
command = "KeyDown Shift"
elem
name = "Shift+UP"
command = "KeyUp Shift"
elem
name = "Ctrl"
command = "KeyDown Ctrl"
elem
name = "Ctrl+UP"
command = "KeyUp Ctrl"
elem
name = "Alt"
command = "KeyDown Alt"
elem
name = "Alt+UP"
command = "KeyUp Alt"
elem
name = "NORTHEAST"
command = ".northeast"
@@ -442,8 +521,11 @@ macro "hotkeymode"
name = "CTRL+WEST"
command = "westface"
elem
name = "WEST+REP"
command = ".moveleft"
name = "West"
command = "KeyDown West"
elem
name = "West+UP"
command = "KeyUp West"
elem
name = "ALT+NORTH"
command = "northfaceperm"
@@ -451,8 +533,11 @@ macro "hotkeymode"
name = "CTRL+NORTH"
command = "northface"
elem
name = "NORTH+REP"
command = ".moveup"
name = "North"
command = "KeyDown North"
elem
name = "North+UP"
command = "KeyUp North"
elem
name = "ALT+EAST"
command = "eastfaceperm"
@@ -460,17 +545,17 @@ macro "hotkeymode"
name = "CTRL+EAST"
command = "eastface"
elem
name = "EAST+REP"
command = ".moveright"
name = "East"
command = "KeyDown East"
elem
name = "East+UP"
command = "KeyUp East"
elem
name = "ALT+SOUTH"
command = "southfaceperm"
elem
name = "CTRL+SOUTH"
command = "southface"
elem
name = "SOUTH+REP"
command = ".movedown"
elem
name = "CTRL+SHIFT+NORTH"
command = "shiftnorth"
@@ -483,6 +568,11 @@ macro "hotkeymode"
elem
name = "CTRL+SHIFT+EAST"
command = "shifteast"
name = "South"
command = "KeyDown South"
elem
name = "South+UP"
command = "KeyUp South"
elem
name = "INSERT"
command = "a-intent right"
@@ -520,17 +610,17 @@ macro "hotkeymode"
name = "6"
command = ".Subtle"
elem
name = "A+REP"
command = ".moveleft"
name = "A"
command = "KeyDown A"
elem
name = "CTRL+A+REP"
command = ".moveleft"
name = "A+UP"
command = "KeyUp A"
elem
name = "D+REP"
command = ".moveright"
name = "D"
command = "KeyDown D"
elem
name = "CTRL+D+REP"
command = ".moveright"
name = "D+UP"
command = "KeyUp D"
elem
name = "E"
command = "quick-equip"
@@ -574,20 +664,20 @@ macro "hotkeymode"
name = "CTRL+R"
command = ".southwest"
elem "s_key"
name = "S+REP"
command = ".movedown"
name = "S"
command = "KeyDown S"
elem
name = "CTRL+S+REP"
command = ".movedown"
name = "S+UP"
command = "KeyUp S"
elem
name = "T"
command = ".say"
elem "w_key"
name = "W+REP"
command = ".moveup"
name = "W"
command = "KeyDown W"
elem
name = "CTRL+W+REP"
command = ".moveup"
name = "W+UP"
command = "KeyUp W"
elem
name = "X"
command = ".northeast"
@@ -675,8 +765,23 @@ macro "borgmacro"
name = "TAB"
command = ".winset \"mainwindow.macro=borghotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true input.background-color=#F0F0F0\""
elem
name = "CENTER+REP"
command = ".center"
name = "Shift"
command = "KeyDown Shift"
elem
name = "Shift+UP"
command = "KeyUp Shift"
elem
name = "Ctrl"
command = "KeyDown Ctrl"
elem
name = "Ctrl+UP"
command = "KeyUp Ctrl"
elem
name = "Alt"
command = "KeyDown Alt"
elem
name = "Alt+UP"
command = "KeyUp Alt"
elem
name = "NORTHEAST"
command = ".northeast"
@@ -696,8 +801,11 @@ macro "borgmacro"
name = "CTRL+WEST"
command = "westface"
elem
name = "WEST+REP"
command = ".moveleft"
name = "West"
command = "KeyDown West"
elem
name = "West+UP"
command = "KeyUp West"
elem
name = "ALT+NORTH"
command = "northfaceperm"
@@ -705,8 +813,11 @@ macro "borgmacro"
name = "CTRL+NORTH"
command = "northface"
elem
name = "NORTH+REP"
command = ".moveup"
name = "North"
command = "KeyDown North"
elem
name = "North+UP"
command = "KeyUp North"
elem
name = "ALT+EAST"
command = "eastfaceperm"
@@ -714,17 +825,17 @@ macro "borgmacro"
name = "CTRL+EAST"
command = "eastface"
elem
name = "EAST+REP"
command = ".moveright"
name = "East"
command = "KeyDown East"
elem
name = "East+UP"
command = "KeyUp East"
elem
name = "ALT+SOUTH"
command = "southfaceperm"
elem
name = "CTRL+SOUTH"
command = "southface"
elem
name = "SOUTH+REP"
command = ".movedown"
elem
name = "CTRL+SHIFT+NORTH"
command = "shiftnorth"
@@ -737,6 +848,11 @@ macro "borgmacro"
elem
name = "CTRL+SHIFT+EAST"
command = "shifteast"
name = "South"
command = "KeyDown South"
elem
name = "South+UP"
command = "KeyUp South"
elem
name = "INSERT"
command = "a-intent right"
@@ -756,11 +872,17 @@ macro "borgmacro"
name = "CTRL+4"
command = "a-intent left"
elem
name = "CTRL+A+REP"
command = ".moveleft"
name = "CTRL+A"
command = "KeyDown A"
elem
name = "CTRL+D+REP"
command = ".moveright"
name = "CTRL+A+UP"
command = "KeyUp A"
elem
name = "CTRL+D"
command = "KeyDown D"
elem
name = "CTRL+D+UP"
command = "KeyUp D"
elem
name = "CTRL+F"
command = "a-intent left"
@@ -774,11 +896,17 @@ macro "borgmacro"
name = "CTRL+R"
command = ".southwest"
elem
name = "CTRL+S+REP"
command = ".movedown"
name = "CTRL+S"
command = "KeyDown S"
elem
name = "CTRL+W+REP"
command = ".moveup"
name = "CTRL+S+UP"
command = "KeyUp S"
elem
name = "CTRL+W"
command = "KeyDown W"
elem
name = "CTRL+W+UP"
command = "KeyUp W"
elem
name = "CTRL+X"
command = ".northeast"
@@ -980,210 +1108,6 @@ menu "menu"
category = "&Help"
saved-params = "is-checked"
window "Telecomms IDE"
elem "Telecomms IDE"
type = MAIN
pos = 281,0
size = 569x582
anchor1 = -1,-1
anchor2 = -1,-1
background-color = #ffffff
is-visible = false
saved-params = "pos;size;is-minimized;is-maximized"
title = "TCS IDE"
statusbar = false
on-close = "exittcs"
elem "button5"
type = BUTTON
pos = 209,464
size = 70x20
anchor1 = 37,80
anchor2 = 49,83
saved-params = "is-checked"
text = "Clear Memory"
command = "tcsclearmem"
elem "button4"
type = BUTTON
pos = 157,464
size = 52x20
anchor1 = 28,80
anchor2 = 37,83
saved-params = "is-checked"
text = "Revert"
command = "tcsrevert"
elem "button3"
type = BUTTON
pos = 105,464
size = 52x20
anchor1 = 18,80
anchor2 = 28,83
saved-params = "is-checked"
text = "Execute"
command = "tcsrun"
elem "tcserror"
type = OUTPUT
pos = 0,488
size = 566x94
anchor1 = 0,84
anchor2 = 99,100
font-family = "sans-serif"
font-size = 9
saved-params = "max-lines"
elem "button2"
type = BUTTON
pos = 53,464
size = 52x20
anchor1 = 9,80
anchor2 = 18,83
saved-params = "is-checked"
text = "Compile"
command = "tcscompile"
elem "button1"
type = BUTTON
pos = 0,464
size = 53x20
anchor1 = 0,80
anchor2 = 9,83
saved-params = "is-checked"
text = "Apply"
command = "tcssave"
elem "tcscode"
type = INPUT
pos = 0,0
size = 569x464
anchor1 = 0,0
anchor2 = 100,80
font-family = "Courier"
font-size = 10
saved-params = ""
command = "cancel"
multi-line = true
no-command = true
window "chemdispenser"
elem "chemdispenser"
type = MAIN
pos = 281,0
size = 340x480
anchor1 = -1,-1
anchor2 = -1,-1
is-visible = false
saved-params = "pos;size;is-minimized;is-maximized"
title = "Chem Dispenser"
statusbar = false
elem "energy"
type = LABEL
pos = 8,24
size = 56x16
anchor1 = -1,-1
anchor2 = -1,-1
saved-params = ""
text = "Energy: 25"
elem "eject"
type = BUTTON
pos = 264,4
size = 72x20
anchor1 = -1,-1
anchor2 = -1,-1
saved-params = "is-checked"
text = "[Insert beaker]"
command = "skincmd \"chemdispenser;eject\""
elem "amountc"
type = BUTTON
pos = 208,4
size = 48x20
anchor1 = -1,-1
anchor2 = -1,-1
saved-params = "is-checked"
text = "[Other]"
command = "skincmd \"chemdispenser;amountc\""
elem "amount3"
type = BUTTON
pos = 176,4
size = 24x20
anchor1 = -1,-1
anchor2 = -1,-1
saved-params = "is-checked"
text = "[30]"
command = "skincmd \"chemdispenser;amount30\""
elem "amount2"
type = BUTTON
pos = 144,4
size = 24x20
anchor1 = -1,-1
anchor2 = -1,-1
saved-params = "is-checked"
text = "[20]"
command = "skincmd \"chemdispenser;amount20\""
elem "amount1"
type = BUTTON
pos = 112,4
size = 24x20
anchor1 = -1,-1
anchor2 = -1,-1
saved-params = "is-checked"
text = "[10]"
command = "skincmd \"chemdispenser;amount10\""
elem "amount"
type = LABEL
pos = 4,4
size = 100x20
anchor1 = -1,-1
anchor2 = -1,-1
font-size = 12
saved-params = ""
text = "Amount: 30"
elem "child1"
type = CHILD
pos = 0,40
size = 340x440
anchor1 = -1,-1
anchor2 = -1,-1
saved-params = "splitter"
left = "chemdispenser_reagents"
is-vert = false
window "chemdispenser_reagents"
elem "chemdispenser_reagents"
type = MAIN
pos = 281,0
size = 340x448
anchor1 = -1,-1
anchor2 = -1,-1
saved-params = "pos;size;is-minimized;is-maximized"
titlebar = false
statusbar = false
can-close = false
can-minimize = false
can-resize = false
is-pane = true
can-scroll = vertical
elem "template_dispense"
type = BUTTON
pos = 256,8
size = 64x32
anchor1 = -1,-1
anchor2 = -1,-1
is-visible = false
saved-params = "is-checked"
text = "Dispense"
image = 'icons\\dispensebutton_bg.png'
command = ""
is-flat = true
elem "template_name"
type = LABEL
pos = 18,8
size = 230x32
anchor1 = -1,-1
anchor2 = -1,-1
font-size = 15
is-visible = false
saved-params = ""
text = "Chloral Hydrate"
image = 'icons\\reagentname_bg.png'
image-mode = stretch
window "mainwindow"
elem "mainwindow"
type = MAIN

View File

@@ -249,7 +249,7 @@
var/mob/living/carbon/human/user = AM
var/choice = tgui_alert(usr, "Do you want to depart via the tram? Your character will leave the round.","Departure",list("Yes","No"))
var/choice = tgui_alert(user, "Do you want to depart via the tram? Your character will leave the round.","Departure",list("Yes","No"))
if(user && Adjacent(user) && choice == "Yes")
var/mob/observer/dead/newghost = user.ghostize()
newghost.timeofdeath = world.time

View File

@@ -132,7 +132,7 @@ export const releaseHeldKeys = () => {
if (keyState[byondKeyCode]) {
keyState[byondKeyCode] = false;
logger.log(`releasing key "${byondKeyCode}"`);
Byond.command(`KeyUp "${byondKeyCode}"`);
Byond.command(`TguiKeyUp "${byondKeyCode}"`);
}
}
};

View File

@@ -172,7 +172,7 @@ const digestModeToPreyMode = {
export const VorePanel = (props, context) => {
const { act, data } = useBackend(context);
return (
<Window width={700} height={800} resizable>
<Window width={700} height={660} theme="abstract" resizable>
<Window.Content scrollable>
{data.unsaved_changes && (
<NoticeBox danger>

File diff suppressed because one or more lines are too long

View File

@@ -51,6 +51,7 @@
#include "code\__defines\gamemode.dm"
#include "code\__defines\holomap.dm"
#include "code\__defines\hoses.dm"
#include "code\__defines\input.dm"
#include "code\__defines\instruments.dm"
#include "code\__defines\integrated_circuits.dm"
#include "code\__defines\inventory_sizes.dm"
@@ -281,6 +282,7 @@
#include "code\controllers\subsystems\garbage.dm"
#include "code\controllers\subsystems\holomaps.dm"
#include "code\controllers\subsystems\inactivity.dm"
#include "code\controllers\subsystems\input.dm"
#include "code\controllers\subsystems\job.dm"
#include "code\controllers\subsystems\lighting.dm"
#include "code\controllers\subsystems\machines.dm"
@@ -2602,6 +2604,9 @@
#include "code\modules\integrated_electronics\subtypes\trig.dm"
#include "code\modules\integrated_electronics\subtypes\z_mixed_ch.dm"
#include "code\modules\integrated_electronics\~defines\~defines.dm"
#include "code\modules\keybindings\bindings_atom.dm"
#include "code\modules\keybindings\bindings_movekeys.dm"
#include "code\modules\keybindings\setup.dm"
#include "code\modules\library\lib_items.dm"
#include "code\modules\library\lib_machines.dm"
#include "code\modules\library\lib_readme.dm"