Merge pull request #1 from Citadel-Station-13/master

aeughupdoot
This commit is contained in:
bunny232
2022-03-19 19:01:42 -04:00
committed by GitHub
349 changed files with 7099 additions and 10888 deletions
+10 -1
View File
@@ -11,7 +11,8 @@
6. [Pull Request Process](#pull-request-process)
7. [Porting features/sprites/sounds/tools from other codebases](#porting-featuresspritessoundstools-from-other-codebases)
8. [Banned content](#banned-content)
9. [A word on Git](#a-word-on-git)
9. [Content requiring prior approval](#content-requiring-prior-approval)
10. [A word on Git](#a-word-on-git)
## Reporting Issues
If you ever encounter a bug in-game, the best way to let a coder know about it is with our GitHub Issue Tracker. Please make sure you use the supplied issue template, and include the round ID for the server.
@@ -678,6 +679,14 @@ Do not add any of the following in a Pull Request or risk getting the PR closed:
Just because something isn't on this list doesn't mean that it's acceptable. Use common sense above all else.
## Content requiring prior approval
Certain types of changes may require prior approval from maintainers. This currently includes:
* Code adding, removing, or updating the availability of alien races/species/human mutants. This includes pull requests attempting to add or remove features from said races/species/mutants. (Requires approval from at least one maintainer)
* Code adding, removing, or modifying the functionality of adult-oriented features (such as, but not limited to: vore, genitals, MKUltra, and more). This also includes pull requests attempting to add or remove these features outright. (Requires approval from at least half of the formal maintainer team)
If a PR contains any of the above content, and it lacks prior approval, then it may closed at maintainer discretion. Prior approval requires an @Maintainer ping in a relevant development/code or staff channel on the Discord. This is primarily to limit the impact of PRs that're created in bad faith, or are otherwise counterproductive to the server's health.
## A word on Git
This repository uses `LF` line endings for all code as specified in the **.gitattributes** and **.editorconfig** files.
+4 -4
View File
@@ -19118,6 +19118,10 @@
/obj/effect/turf_decal/tile/yellow{
dir = 4
},
/obj/machinery/navbeacon{
codes_txt = "patrol;next_patrol=14-Starboard-Central";
location = "13.2-Tcommstore"
},
/turf/open/floor/plasteel/dark/corner,
/area/hallway/primary/starboard)
"bxn" = (
@@ -21190,10 +21194,6 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
/obj/machinery/navbeacon{
codes_txt = "patrol;next_patrol=14-Starboard-Central";
location = "13.2-Tcommstore"
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel,
/area/hallway/primary/starboard)
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -182,7 +182,7 @@
////organ defines
#define STANDARD_ORGAN_THRESHOLD 100
#define STANDARD_ORGAN_HEALING (1/(15 MINUTES / (2 SECONDS)))
#define STANDARD_ORGAN_HEALING (1/(15 MINUTES / (2 SECONDS))) / 3 //Base organ healing can be amped by a factor of up to x5 via satiety. This assumes it to be somewhat in the upper center of positive satiety as base.
#define STANDARD_ORGAN_DECAY (1/(15 MINUTES / (2 SECONDS))) //designed to fail organs when left to decay for ~15 minutes. 2 SECOND is SSmobs tickrate.
+2
View File
@@ -37,6 +37,8 @@ GLOBAL_LIST_INIT(bitflags, list(
#define OVERLAY_QUEUED_1 (1<<8)
///Item has priority to check when entering or leaving.
#define ON_BORDER_1 (1<<9)
///Whether or not this atom shows screentips when hovered over
#define NO_SCREENTIPS_1 (1<<10)
///Prevent clicking things below it on the same turf eg. doors/ fulltile windows.
#define PREVENT_CLICK_UNDER_1 (1<<11)
#define HOLOGRAM_1 (1<<12)
+4
View File
@@ -57,6 +57,10 @@
#define ADMIN_SET_SD_CODE "(<a href='?_src_=holder;[HrefToken(TRUE)];set_selfdestruct_code=1'>SETCODE</a>)"
#define ADMIN_FULLMONTY_NONAME(user) "[ADMIN_QUE(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_FLW(user)] [ADMIN_TP(user)] [ADMIN_INDIVIDUALLOG(user)] [ADMIN_SMITE(user)]"
#define ADMIN_FULLMONTY(user) "[key_name_admin(user)] [ADMIN_FULLMONTY_NONAME(user)]"
//ambition start
#define ADMIN_TPMONTY_NONAME(user) "[ADMIN_QUE(user)] [ADMIN_JMP(user)] [ADMIN_FLW(user)]"
#define ADMIN_TPMONTY(user) "[key_name_admin(user)] [ADMIN_TPMONTY_NONAME(user)]"
//ambition end
#define ADMIN_JMP(src) "(<a href='?_src_=holder;[HrefToken(TRUE)];adminplayerobservecoodjump=1;X=[src.x];Y=[src.y];Z=[src.z]'>JMP</a>)"
#define COORD(src) "[src ? "([src.x],[src.y],[src.z])" : "nonexistent location"]"
#define AREACOORD(src) "[src ? "[get_area_name(src, TRUE)] ([src.x], [src.y], [src.z])" : "nonexistent location"]"
+6
View File
@@ -123,3 +123,9 @@ GLOBAL_LIST_EMPTY(living_heart_cache) //A list of all living hearts in existance
/// The dimensions of the antagonist preview icon. Will be scaled to this size.
#define ANTAGONIST_PREVIEW_ICON_SIZE 96
//Objectives-Ambitions Panel
#define REQUEST_NEW_OBJECTIVE "new_objective"
#define REQUEST_DEL_OBJECTIVE "del_objective"
#define REQUEST_WIN_OBJECTIVE "win_objective"
#define REQUEST_LOSE_OBJECTIVE "lose_objective"
+1
View File
@@ -116,6 +116,7 @@
#define GLOVES_MAX_TEMP_PROTECT 1500 //For some gloves
#define SHOES_MIN_TEMP_PROTECT 2.0 //For gloves
#define SHOES_MAX_TEMP_PROTECT 1500 //For gloves
#define COAT_MAX_TEMP_PROTECT 330 //For winter coats (if they can stop you from getting cold why can't they do it the other way to a lesser extent)
#define PRESSURE_DAMAGE_COEFFICIENT 4 //The amount of pressure damage someone takes is equal to (pressure / HAZARD_HIGH_PRESSURE)*PRESSURE_DAMAGE_COEFFICIENT, with the maximum of MAX_PRESSURE_DAMAGE
#define MAX_HIGH_PRESSURE_DAMAGE 16 // CITADEL CHANGES Max to 16, low to 8.
+3
View File
@@ -27,6 +27,9 @@
//INDEXES
#define COOLDOWN_EMPLOYMENT_CABINET "employment cabinet"
#define COOLDOWN_AMBITION "ambition"
#define COOLDOWN_OBJECTIVES "objectives"
#define COOLDOWN_OBJ_ADMIN_PING "obj_admin_ping"
//car cooldowns
#define COOLDOWN_CAR_HONK "car_honk"
+3
View File
@@ -359,6 +359,9 @@
#define COMSIG_LIVING_RUN_BLOCK "living_do_run_block" //from base of mob/living/do_run_block(): (real_attack, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone)
#define COMSIG_LIVING_GET_BLOCKING_ITEMS "get_blocking_items" //from base of mob/living/get_blocking_items(): (list/items)
#define COMSIG_LIVING_RESTING "living_on_resting" //from mob/living/set_resting
#define COMSIG_LIVING_STOPPED_PULLING "living_on_stop_pulling" //from mob/living/stop_pulling
#define COMSIG_LIVING_ACTIVE_BLOCK_START "active_block_start" //from base of mob/living/keybind_start_active_blocking(): (obj/item/blocking_item, list/backup_items)
#define COMPONENT_PREVENT_BLOCK_START 1
#define COMSIG_LIVING_ACTIVE_PARRY_START "active_parry_start" //from base of mob/living/initiate_parry_sequence(): (parrying_method, datum/parrying_item_mob_or_art, list/backup_items, list/override)
+45 -80
View File
@@ -6,87 +6,52 @@
#define STORAGE_VIEW_DEPTH 2
//ITEM INVENTORY SLOT BITMASKS
#define ITEM_SLOT_OCLOTHING (1<<0)
#define ITEM_SLOT_ICLOTHING (1<<1)
#define ITEM_SLOT_GLOVES (1<<2)
#define ITEM_SLOT_EYES (1<<3)
#define ITEM_SLOT_EARS (1<<4)
#define ITEM_SLOT_MASK (1<<5)
#define ITEM_SLOT_HEAD (1<<6)
#define ITEM_SLOT_FEET (1<<7)
#define ITEM_SLOT_ID (1<<8)
#define ITEM_SLOT_BELT (1<<9)
#define ITEM_SLOT_BACK (1<<10)
#define ITEM_SLOT_POCKET (1<<11) // this is to allow items with a w_class of WEIGHT_CLASS_NORMAL or WEIGHT_CLASS_BULKY to fit in pockets.
#define ITEM_SLOT_DENYPOCKET (1<<12) // this is to deny items with a w_class of WEIGHT_CLASS_SMALL or WEIGHT_CLASS_TINY to fit in pockets.
#define ITEM_SLOT_NECK (1<<13)
#define ITEM_SLOT_HANDS (1<<14)
#define ITEM_SLOT_BACKPACK (1<<15)
#define ITEM_SLOT_SUITSTORE (1<<16)
/// Suit slot (armors, costumes, space suits, etc.)
#define ITEM_SLOT_OCLOTHING (1<<0)
/// Jumpsuit slot
#define ITEM_SLOT_ICLOTHING (1<<1)
/// Glove slot
#define ITEM_SLOT_GLOVES (1<<2)
/// Glasses slot
#define ITEM_SLOT_EYES (1<<3)
/// Ear slot (radios, earmuffs)
#define ITEM_SLOT_EARS (1<<4)
/// Mask slot
#define ITEM_SLOT_MASK (1<<5)
/// Head slot (helmets, hats, etc.)
#define ITEM_SLOT_HEAD (1<<6)
/// Shoe slot
#define ITEM_SLOT_FEET (1<<7)
/// ID slot
#define ITEM_SLOT_ID (1<<8)
/// Belt slot
#define ITEM_SLOT_BELT (1<<9)
/// Back slot
#define ITEM_SLOT_BACK (1<<10)
/// Dextrous simplemob "hands" (used for Drones and Dextrous Guardians)
#define ITEM_SLOT_DEX_STORAGE (1<<11)
/// Neck slot (ties, bedsheets, scarves)
#define ITEM_SLOT_NECK (1<<12)
/// A character's hand slots
#define ITEM_SLOT_HANDS (1<<13)
/// Inside of a character's backpack
#define ITEM_SLOT_BACKPACK (1<<14)
/// Suit Storage slot
#define ITEM_SLOT_SUITSTORE (1<<15)
/// Left Pocket slot
#define ITEM_SLOT_LPOCKET (1<<16)
/// Right Pocket slot
#define ITEM_SLOT_RPOCKET (1<<17)
/// Handcuff slot
#define ITEM_SLOT_HANDCUFFED (1<<18)
/// Legcuff slot (bolas, beartraps)
#define ITEM_SLOT_LEGCUFFED (1<<19)
//SLOTS
#define SLOT_BACK 1
#define SLOT_WEAR_MASK 2
#define SLOT_HANDCUFFED 3
#define SLOT_HANDS 4 //wherever you provide a slot for hands you provide SLOT_HANDS
//SLOT_HANDS as a slot will pick ANY available hand
#define SLOT_BELT 5
#define SLOT_WEAR_ID 6
#define SLOT_EARS 7
#define SLOT_GLASSES 8
#define SLOT_GLOVES 9
#define SLOT_NECK 10
#define SLOT_HEAD 11
#define SLOT_SHOES 12
#define SLOT_WEAR_SUIT 13
#define SLOT_W_UNIFORM 14
#define SLOT_L_STORE 15
#define SLOT_R_STORE 16
#define SLOT_S_STORE 17
#define SLOT_IN_BACKPACK 18
#define SLOT_LEGCUFFED 19
#define SLOT_GENERC_DEXTROUS_STORAGE 20
#define SLOTS_AMT 20 // Keep this up to date!
//I hate that this has to exist
/proc/slotdefine2slotbit(slotdefine) //Keep this up to date with the value of SLOT BITMASKS and SLOTS (the two define sections above)
. = 0
switch(slotdefine)
if(SLOT_BACK)
. = ITEM_SLOT_BACK
if(SLOT_WEAR_MASK)
. = ITEM_SLOT_MASK
if(SLOT_NECK)
. = ITEM_SLOT_NECK
if(SLOT_BELT)
. = ITEM_SLOT_BELT
if(SLOT_WEAR_ID)
. = ITEM_SLOT_ID
if(SLOT_EARS)
. = ITEM_SLOT_EARS
if(SLOT_GLASSES)
. = ITEM_SLOT_EYES
if(SLOT_GLOVES)
. = ITEM_SLOT_GLOVES
if(SLOT_HEAD)
. = ITEM_SLOT_HEAD
if(SLOT_SHOES)
. = ITEM_SLOT_FEET
if(SLOT_WEAR_SUIT)
. = ITEM_SLOT_OCLOTHING
if(SLOT_W_UNIFORM)
. = ITEM_SLOT_ICLOTHING
if(SLOT_L_STORE, SLOT_R_STORE)
. = ITEM_SLOT_POCKET
if(SLOT_HANDS)
. = ITEM_SLOT_HANDS
if(SLOT_IN_BACKPACK)
. = ITEM_SLOT_BACKPACK
if(SLOT_S_STORE)
. = ITEM_SLOT_SUITSTORE
/// Total amount of slots
#define SLOTS_AMT 20 // Keep this up to date!
//SLOT GROUP HELPERS
#define ITEM_SLOT_POCKETS (ITEM_SLOT_LPOCKET|ITEM_SLOT_RPOCKET)
//Bit flags for the flags_inv variable, which determine when a piece of clothing hides another. IE a helmet hiding glasses.
#define HIDEGLOVES (1<<0)
@@ -245,4 +210,4 @@ GLOBAL_LIST_INIT(security_wintercoat_allowed, typecacheof(list(
#define GET_INTERNAL_SLOTS(C) list(C.head, C.wear_mask)
//Slots that won't trigger humans' update_genitals() on equip().
GLOBAL_LIST_INIT(no_genitals_update_slots, list(SLOT_L_STORE, SLOT_R_STORE, SLOT_S_STORE, SLOT_IN_BACKPACK, SLOT_LEGCUFFED, SLOT_HANDCUFFED, SLOT_HANDS, SLOT_GENERC_DEXTROUS_STORAGE))
GLOBAL_LIST_INIT(no_genitals_update_slots, list(ITEM_SLOT_LPOCKET, ITEM_SLOT_RPOCKET, ITEM_SLOT_SUITSTORE, ITEM_SLOT_BACKPACK, ITEM_SLOT_LEGCUFFED, ITEM_SLOT_HANDCUFFED, ITEM_SLOT_HANDS, ITEM_SLOT_DEX_STORAGE))
-1
View File
@@ -76,7 +76,6 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define isvampire(A) (is_species(A,/datum/species/vampire))
#define isdullahan(A) (is_species(A, /datum/species/dullahan))
#define isangel(A) (is_species(A, /datum/species/angel))
#define ismush(A) (is_species(A, /datum/species/mush))
#define isshadow(A) (is_species(A, /datum/species/shadow))
#define isrobotic(A) (is_species(A, /datum/species/ipc) || is_species(A, /datum/species/synthliz) || is_species(A, /datum/species/mammal/synthetic))
+3
View File
@@ -105,6 +105,9 @@
#define TORADIANS(degrees) ((degrees) * 0.0174532925)
/// Gets shift x that would be required the bitflag (1<<x)
#define TOBITSHIFT(bit) ( log(2, bit) )
// Will filter out extra rotations and negative rotations
// E.g: 540 becomes 180. -180 becomes 180.
#define SIMPLIFY_DEGREES(degrees) (MODULUS((degrees), 360))
+3
View File
@@ -63,6 +63,9 @@
#define THRESHOLD_UNHUSK 50 // health threshold for synthflesh/rezadone to unhusk someone
#define SYNTHTISSUE_BORROW_CAP 250 //The cap for synthtissue's borrowed health value when used on someone dead or already having borrowed health.
#define SYNTHTISSUE_DAMAGE_FLIP_CYCLES 45 //After how many cycles the damage will be pure toxdamage as opposed to clonedamage like initially. Gradually changes during its cycles.
//reagent bitflags, used for altering how they works
#define REAGENT_DEAD_PROCESS (1<<0) //calls on_mob_dead() if present in a dead body
#define REAGENT_DONOTSPLIT (1<<1) //Do not split the chem at all during processing
+2 -2
View File
@@ -74,5 +74,5 @@
)
#define BOMB_TARGET_POINTS 50000 //Adjust as needed. Actual hard cap is double this, but will never be reached due to hyperbolic curve.
#define BOMB_TARGET_SIZE 200 // The shockwave radius required for a bomb to get TECHWEB_BOMB_MIDPOINT points.
#define BOMB_SUB_TARGET_EXPONENT 2 // The power of the points curve below the target size. Higher = less points for worse bombs, below target.
#define BOMB_TARGET_SIZE 175 // The shockwave radius required for a bomb to get TECHWEB_BOMB_MIDPOINT points.
#define BOMB_SUB_TARGET_EXPONENT 3 // The power of the points curve below the target size. Higher = less points for worse bombs, below target.
+3
View File
@@ -86,6 +86,9 @@
#define EMOTE_OMNI 4
//Don't set this very much higher then 1024 unless you like inviting people in to dos your server with message spam
//ambition start
#define MAX_AMBITION_LEN 1024
//ambition end
#define MAX_MESSAGE_LEN 4096 //Citadel edit: What's the WORST that could happen?
#define MAX_FLAVOR_LEN 4096
#define MAX_TASTE_LEN 40 //lick... vore... ew...
+11 -1
View File
@@ -3,7 +3,6 @@
#define SPECIES_ABDUCTOR "abductor"
#define SPECIES_ANDROID "android"
#define SPECIES_ANGEL "angel"
#define SPECIES_MAMMAL "mammal"
#define SPECIES_MAMMAL_SYNTHETIC "mammal_synthetic"
#define SPECIES_ARACHNID "arachnid"
@@ -53,3 +52,14 @@
#define SPECIES_CATEGORY_SHADOW "shadow"
#define SPECIES_CATEGORY_SKELETON "skeleton"
#define SPECIES_CATEGORY_UNDEAD "undead"
//Species Wing Type Defines ----------------------
#define SPECIES_WINGS_ANGEL list("Angel")
#define SPECIES_WINGS_DRAGON list("Dragon") //could also be considered demon wings or bat wings?
#define SPECIES_WINGS_ROBOT list("Robotic")
#define SPECIES_WINGS_INSECT list("Fly") //"hey when can we have something besides giant fly wings?" "when you sprite it!"
#define SPECIES_WINGS_SKELETAL list("Skeleton")
#define SPECIES_WINGS_MOTH list("Megamoth","Mothra")
#define SPECIES_WINGS_JELLY list("Angel") //no actual slime wings present right now, but I'm making this in the event someone wants to sprite slime wings.
#define SPECIES_WINGS_ALL list("Angel","Dragon","Robotic","Fly","Skeleton","Megamoth","Mothra") //keep this updated
+3
View File
@@ -5,6 +5,9 @@
#define HIGHEST_MEDIAN_VOTING "HIGHEST_MEDIAN"
#define INSTANT_RUNOFF_VOTING "IRV"
#define VOTE_TRANSFER "Initiate Crew Transfer"
#define VOTE_CONTINUE "Continue Playing"
#define SHOW_RESULTS (1<<0)
#define SHOW_VOTES (1<<1)
#define SHOW_WINNER (1<<2)
-209
View File
@@ -1,209 +0,0 @@
/*
A Star pathfinding algorithm
Returns a list of tiles forming a path from A to B, taking dense objects as well as walls, and the orientation of
windows along the route into account.
Use:
your_list = AStar(start location, end location, moving atom, distance proc, max nodes, maximum node depth, minimum distance to target, adjacent proc, atom id, turfs to exclude, check only simulated)
Optional extras to add on (in order):
Distance proc : the distance used in every A* calculation (length of path and heuristic)
MaxNodes: The maximum number of nodes the returned path can be (0 = infinite)
Maxnodedepth: The maximum number of nodes to search (default: 30, 0 = infinite)
Mintargetdist: Minimum distance to the target before path returns, could be used to get
near a target, but not right to it - for an AI mob with a gun, for example.
Adjacent proc : returns the turfs to consider around the actually processed node
Simulated only : whether to consider unsimulated turfs or not (used by some Adjacent proc)
Also added 'exclude' turf to avoid travelling over; defaults to null
Actual Adjacent procs :
/turf/proc/reachableAdjacentTurfs : returns reachable turfs in cardinal directions (uses simulated_only)
/turf/proc/reachableAdjacentAtmosTurfs : returns turfs in cardinal directions reachable via atmos
*/
#define PF_TIEBREAKER 0.005
//tiebreker weight.To help to choose between equal paths
//////////////////////
//datum/PathNode object
//////////////////////
#define MASK_ODD 85
#define MASK_EVEN 170
//A* nodes variables
/datum/PathNode
var/turf/source //turf associated with the PathNode
var/datum/PathNode/prevNode //link to the parent PathNode
var/f //A* Node weight (f = g + h)
var/g //A* movement cost variable
var/h //A* heuristic variable
var/nt //count the number of Nodes traversed
var/bf //bitflag for dir to expand.Some sufficiently advanced motherfuckery
/datum/PathNode/New(s,p,pg,ph,pnt,_bf)
source = s
prevNode = p
g = pg
h = ph
f = g + h*(1+ PF_TIEBREAKER)
nt = pnt
bf = _bf
/datum/PathNode/proc/setp(p,pg,ph,pnt)
prevNode = p
g = pg
h = ph
f = g + h*(1+ PF_TIEBREAKER)
nt = pnt
/datum/PathNode/proc/calc_f()
f = g + h
//////////////////////
//A* procs
//////////////////////
//the weighting function, used in the A* algorithm
/proc/PathWeightCompare(datum/PathNode/a, datum/PathNode/b)
return a.f - b.f
//reversed so that the Heap is a MinHeap rather than a MaxHeap
/proc/HeapPathWeightCompare(datum/PathNode/a, datum/PathNode/b)
return b.f - a.f
//wrapper that returns an empty list if A* failed to find a path
/proc/get_path_to(caller, end, dist, maxnodes, maxnodedepth = 30, mintargetdist, adjacent = /turf/proc/reachableTurftest, id=null, turf/exclude=null, simulated_only = 1)
var/l = SSpathfinder.mobs.getfree(caller)
while(!l)
stoplag(3)
l = SSpathfinder.mobs.getfree(caller)
var/list/path = AStar(caller, end, dist, maxnodes, maxnodedepth, mintargetdist, adjacent,id, exclude, simulated_only)
SSpathfinder.mobs.found(l)
if(!path)
path = list()
return path
/proc/cir_get_path_to(caller, end, dist, maxnodes, maxnodedepth = 30, mintargetdist, adjacent = /turf/proc/reachableTurftest, id=null, turf/exclude=null, simulated_only = 1)
var/l = SSpathfinder.circuits.getfree(caller)
while(!l)
stoplag(3)
l = SSpathfinder.circuits.getfree(caller)
var/list/path = AStar(caller, end, dist, maxnodes, maxnodedepth, mintargetdist, adjacent,id, exclude, simulated_only)
SSpathfinder.circuits.found(l)
if(!path)
path = list()
return path
/proc/AStar(caller, _end, dist, maxnodes, maxnodedepth = 30, mintargetdist, adjacent = /turf/proc/reachableTurftest, id=null, turf/exclude=null, simulated_only = 1)
//sanitation
var/turf/end = get_turf(_end)
var/turf/start = get_turf(caller)
if(!start || !end)
stack_trace("Invalid A* start or destination")
return 0
if( start.z != end.z || start == end ) //no pathfinding between z levels
return 0
if(maxnodes)
//if start turf is farther than maxnodes from end turf, no need to do anything
if(call(start, dist)(end) > maxnodes)
return 0
maxnodedepth = maxnodes //no need to consider path longer than maxnodes
var/datum/Heap/open = new /datum/Heap(/proc/HeapPathWeightCompare) //the open list
var/list/openc = new() //open list for node check
var/list/path = null //the returned path, if any
//initialization
var/datum/PathNode/cur = new /datum/PathNode(start,null,0,call(start,dist)(end),0,15,1)//current processed turf
open.Insert(cur)
openc[start] = cur
//then run the main loop
while(!open.IsEmpty() && !path)
cur = open.Pop() //get the lower f turf in the open list
//get the lower f node on the open list
//if we only want to get near the target, check if we're close enough
var/closeenough
if(mintargetdist)
closeenough = call(cur.source,dist)(end) <= mintargetdist
//found the target turf (or close enough), let's create the path to it
if(cur.source == end || closeenough)
path = new()
path.Add(cur.source)
while(cur.prevNode)
cur = cur.prevNode
path.Add(cur.source)
break
//get adjacents turfs using the adjacent proc, checking for access with id
if((!maxnodedepth)||(cur.nt <= maxnodedepth))//if too many steps, don't process that path
for(var/i = 0 to 3)
var/f= 1<<i //get cardinal directions.1,2,4,8
if(cur.bf & f)
var/T = get_step(cur.source,f)
if(T != exclude)
var/datum/PathNode/CN = openc[T] //current checking turf
var/r=((f & MASK_ODD)<<1)|((f & MASK_EVEN)>>1) //getting reverse direction throught swapping even and odd bits.((f & 01010101)<<1)|((f & 10101010)>>1)
var/newg = cur.g + call(cur.source,dist)(T)
if(CN)
//is already in open list, check if it's a better way from the current turf
CN.bf &= 15^r //we have no closed, so just cut off exceed dir.00001111 ^ reverse_dir.We don't need to expand to checked turf.
if((newg < CN.g) )
if(call(cur.source,adjacent)(caller, T, id, simulated_only))
CN.setp(cur,newg,CN.h,cur.nt+1)
open.ReSort(CN)//reorder the changed element in the list
else
//is not already in open list, so add it
if(call(cur.source,adjacent)(caller, T, id, simulated_only))
CN = new(T,cur,newg,call(T,dist)(end),cur.nt+1,15^r)
open.Insert(CN)
openc[T] = CN
cur.bf = 0
CHECK_TICK
//reverse the path to get it from start to finish
if(path)
for(var/i = 1 to round(0.5*path.len))
path.Swap(i,path.len-i+1)
openc = null
//cleaning after us
return path
//Returns adjacent turfs in cardinal directions that are reachable
//simulated_only controls whether only simulated turfs are considered or not
/turf/proc/reachableAdjacentTurfs(caller, ID, simulated_only)
var/list/L = new()
var/turf/T
var/static/space_type_cache = typecacheof(/turf/open/space)
for(var/k in 1 to GLOB.cardinals.len)
T = get_step(src,GLOB.cardinals[k])
if(!T || (simulated_only && space_type_cache[T.type]))
continue
if(!T.density && !LinkBlockedWithAccess(T,caller, ID))
L.Add(T)
return L
/turf/proc/reachableTurftest(caller, var/turf/T, ID, simulated_only)
if(T && !T.density && !(simulated_only && SSpathfinder.space_type_cache[T.type]) && !LinkBlockedWithAccess(T,caller, ID))
return TRUE
//Returns adjacent turfs in cardinal directions that are reachable via atmos
/turf/proc/reachableAdjacentAtmosTurfs()
return atmos_adjacent_turfs
/turf/proc/LinkBlockedWithAccess(turf/T, caller, ID)
var/adir = get_dir(src, T)
var/rdir = ((adir & MASK_ODD)<<1)|((adir & MASK_EVEN)>>1)
for(var/obj/structure/window/W in src)
if(!W.CanAStarPass(ID, adir))
return 1
for(var/obj/machinery/door/window/W in src)
if(!W.CanAStarPass(ID, adir))
return 1
for(var/obj/O in T)
if(!O.CanAStarPass(ID, rdir, caller))
return 1
return 0
+3
View File
@@ -14,6 +14,9 @@
///Like LAZYCOPY - copies an input list if the list has entries, If it doesn't the assigned list is nulled
#define LAZYLISTDUPLICATE(L) (L ? L.Copy() : null )
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!length(L)) { L = null; } }
//ambition start
#define LAZYCUT(L, S, E) if((length(L) >= S) && (E == 0 || length(L) >= (E - 1))) { L.Cut(S, E); if(!length(L)) { L = null; } }
//ambition end
#define LAZYADD(L, I) if(!L) { L = list(); } L += I;
#define LAZYOR(L, I) if(!L) { L = list(); } L |= I;
#define LAZYFIND(L, V) (L ? L.Find(V) : 0)
+4
View File
@@ -109,6 +109,10 @@
if (CONFIG_GET(flag/log_attack))
WRITE_LOG(GLOB.world_attack_log, "ATTACK: [text]")
/proc/log_victim(text)
if (CONFIG_GET(flag/log_victim))
WRITE_LOG(GLOB.world_victim_log, "VICTIM: [text]")
/proc/log_manifest(ckey, datum/mind/mind,mob/body, latejoin = FALSE)
if (CONFIG_GET(flag/log_manifest))
WRITE_LOG(GLOB.world_manifest_log, "[ckey] \\ [body.real_name] \\ [mind.assigned_role] \\ [mind.special_role ? mind.special_role : "NONE"] \\ [latejoin ? "LATEJOIN":"ROUNDSTART"]")
+3
View File
@@ -140,3 +140,6 @@ GLOBAL_VAR_INIT(cmp_field, "name")
/proc/cmp_typepaths_asc(A, B)
return sorttext("[B]","[A]")
/proc/cmp_playtime(list/A, list/B)
return A["playtime"] - B["playtime"]
+1 -1
View File
@@ -18,7 +18,7 @@
if(length(inhand_equipment))
for(var/path in inhand_equipment)
var/obj/item/I = new path
mannequin.equip_to_slot_if_possible(I, SLOT_HANDS, TRUE, TRUE, TRUE, TRUE)
mannequin.equip_to_slot_if_possible(I, ITEM_SLOT_HANDS, TRUE, TRUE, TRUE, TRUE)
var/icon/combined = new
+32 -27
View File
@@ -1,39 +1,45 @@
//////////////////////
//datum/Heap object
//datum/heap object
//////////////////////
/datum/Heap
/datum/heap
var/list/L
var/cmp
/datum/Heap/New(compare)
/datum/heap/New(compare)
L = new()
cmp = compare
/datum/Heap/proc/IsEmpty()
return !L.len
/datum/heap/Destroy(force, ...)
for(var/i in L) // because this is before the list helpers are loaded
qdel(i)
L = null
return ..()
//Insert and place at its position a new node in the heap
/datum/Heap/proc/Insert(atom/A)
/datum/heap/proc/is_empty()
return !length(L)
//insert and place at its position a new node in the heap
/datum/heap/proc/insert(atom/A)
L.Add(A)
Swim(L.len)
swim(length(L))
//removes and returns the first element of the heap
//(i.e the max or the min dependant on the comparison function)
/datum/Heap/proc/Pop()
if(!L.len)
/datum/heap/proc/pop()
if(!length(L))
return 0
. = L[1]
L[1] = L[L.len]
L.Cut(L.len)
if(L.len)
Sink(1)
L[1] = L[length(L)]
L.Cut(length(L))
if(length(L))
sink(1)
//Get a node up to its right position in the heap
/datum/Heap/proc/Swim(var/index)
/datum/heap/proc/swim(index)
var/parent = round(index * 0.5)
while(parent > 0 && (call(cmp)(L[index],L[parent]) > 0))
@@ -42,21 +48,21 @@
parent = round(index * 0.5)
//Get a node down to its right position in the heap
/datum/Heap/proc/Sink(var/index)
var/g_child = GetGreaterChild(index)
/datum/heap/proc/sink(index)
var/g_child = get_greater_child(index)
while(g_child > 0 && (call(cmp)(L[index],L[g_child]) < 0))
L.Swap(index,g_child)
index = g_child
g_child = GetGreaterChild(index)
g_child = get_greater_child(index)
//Returns the greater (relative to the comparison proc) of a node children
//or 0 if there's no child
/datum/Heap/proc/GetGreaterChild(var/index)
if(index * 2 > L.len)
/datum/heap/proc/get_greater_child(index)
if(index * 2 > length(L))
return 0
if(index * 2 + 1 > L.len)
if(index * 2 + 1 > length(L))
return index * 2
if(call(cmp)(L[index * 2],L[index * 2 + 1]) < 0)
@@ -65,12 +71,11 @@
return index * 2
//Replaces a given node so it verify the heap condition
/datum/Heap/proc/ReSort(atom/A)
/datum/heap/proc/resort(atom/A)
var/index = L.Find(A)
Swim(index)
Sink(index)
swim(index)
sink(index)
/datum/Heap/proc/List()
/datum/heap/proc/List()
. = L.Copy()
+359
View File
@@ -0,0 +1,359 @@
/**
* This file contains the stuff you need for using JPS (Jump Point Search) pathing, an alternative to A* that skips
* over large numbers of uninteresting tiles resulting in much quicker pathfinding solutions. Mind that diagonals
* cost the same as cardinal moves currently, so paths may look a bit strange, but should still be optimal.
*/
/**
* This is the proc you use whenever you want to have pathfinding more complex than "try stepping towards the thing".
* If no path was found, returns an empty list, which is important for bots like medibots who expect an empty list rather than nothing.
*
* Arguments:
* * caller: The movable atom that's trying to find the path
* * end: What we're trying to path to. It doesn't matter if this is a turf or some other atom, we're gonna just path to the turf it's on anyway
* * max_distance: The maximum number of steps we can take in a given path to search (default: 30, 0 = infinite)
* * mintargetdistance: Minimum distance to the target before path returns, could be used to get near a target, but not right to it - for an AI mob with a gun, for example.
* * id: An ID card representing what access we have and what doors we can open. Its location relative to the pathing atom is irrelevant
* * simulated_only: Whether we consider turfs without atmos simulation (AKA do we want to ignore space)
* * exclude: If we want to avoid a specific turf, like if we're a mulebot who already got blocked by some turf
* * skip_first: Whether or not to delete the first item in the path. This would be done because the first item is the starting tile, which can break movement for some creatures.
*/
/proc/get_path_to(caller, end, max_distance = 30, mintargetdist, id=null, simulated_only = TRUE, turf/exclude, skip_first=TRUE)
if(!caller || !get_turf(end))
return
var/l = SSpathfinder.mobs.getfree(caller)
while(!l)
stoplag(3)
l = SSpathfinder.mobs.getfree(caller)
var/list/path
var/datum/pathfind/pathfind_datum = new(caller, end, id, max_distance, mintargetdist, simulated_only, exclude)
path = pathfind_datum.search()
qdel(pathfind_datum)
SSpathfinder.mobs.found(l)
if(!path)
path = list()
if(length(path) > 0 && skip_first)
path.Cut(1,2)
return path
/**
* A helper macro to see if it's possible to step from the first turf into the second one, minding things like door access and directional windows.
* Note that this can only be used inside the [datum/pathfind][pathfind datum] since it uses variables from said datum.
* If you really want to optimize things, optimize this, cuz this gets called a lot.
*/
#define CAN_STEP(cur_turf, next) (next && !next.density && cur_turf.Adjacent(next) && !(simulated_only && SSpathfinder.space_type_cache[next.type]) && !cur_turf.LinkBlockedWithAccess(next,caller, id) && (next != avoid))
/// Another helper macro for JPS, for telling when a node has forced neighbors that need expanding
#define STEP_NOT_HERE_BUT_THERE(cur_turf, dirA, dirB) ((!CAN_STEP(cur_turf, get_step(cur_turf, dirA)) && CAN_STEP(cur_turf, get_step(cur_turf, dirB))))
/// The JPS Node datum represents a turf that we find interesting enough to add to the open list and possibly search for new tiles from
/datum/jps_node
/// The turf associated with this node
var/turf/tile
/// The node we just came from
var/datum/jps_node/previous_node
/// The A* node weight (f_value = number_of_tiles + heuristic)
var/f_value
/// The A* node heuristic (a rough estimate of how far we are from the goal)
var/heuristic
/// How many steps it's taken to get here from the start (currently pulling double duty as steps taken & cost to get here, since all moves incl diagonals cost 1 rn)
var/number_tiles
/// How many steps it took to get here from the last node
var/jumps
/// Nodes store the endgoal so they can process their heuristic without a reference to the pathfind datum
var/turf/node_goal
/datum/jps_node/New(turf/our_tile, datum/jps_node/incoming_previous_node, jumps_taken, turf/incoming_goal)
tile = our_tile
jumps = jumps_taken
if(incoming_goal) // if we have the goal argument, this must be the first/starting node
node_goal = incoming_goal
else if(incoming_previous_node) // if we have the parent, this is from a direct lateral/diagonal scan, we can fill it all out now
previous_node = incoming_previous_node
number_tiles = previous_node.number_tiles + jumps
node_goal = previous_node.node_goal
heuristic = get_dist(tile, node_goal)
f_value = number_tiles + heuristic
// otherwise, no parent node means this is from a subscan lateral scan, so we just need the tile for now until we call [datum/jps/proc/update_parent] on it
/datum/jps_node/Destroy(force, ...)
previous_node = null
return ..()
/datum/jps_node/proc/update_parent(datum/jps_node/new_parent)
previous_node = new_parent
node_goal = previous_node.node_goal
jumps = get_dist(tile, previous_node.tile)
number_tiles = previous_node.number_tiles + jumps
heuristic = get_dist(tile, node_goal)
f_value = number_tiles + heuristic
/// TODO: Macro this to reduce proc overhead
/proc/HeapPathWeightCompare(datum/jps_node/a, datum/jps_node/b)
return b.f_value - a.f_value
/// The datum used to handle the JPS pathfinding, completely self-contained
/datum/pathfind
/// The thing that we're actually trying to path for
var/atom/movable/caller
/// The turf where we started at
var/turf/start
/// The turf we're trying to path to (note that this won't track a moving target)
var/turf/end
/// The open list/stack we pop nodes out from (TODO: make this a normal list and macro-ize the heap operations to reduce proc overhead)
var/datum/heap/open
///An assoc list that serves as the closed list & tracks what turfs came from where. Key is the turf, and the value is what turf it came from
var/list/sources
/// The list we compile at the end if successful to pass back
var/list/path
// general pathfinding vars/args
/// An ID card representing what access we have and what doors we can open. Its location relative to the pathing atom is irrelevant
var/obj/item/card/id/id
/// How far away we have to get to the end target before we can call it quits
var/mintargetdist = 0
/// I don't know what this does vs , but they limit how far we can search before giving up on a path
var/max_distance = 30
/// Space is big and empty, if this is TRUE then we ignore pathing through unsimulated tiles
var/simulated_only
/// A specific turf we're avoiding, like if a mulebot is being blocked by someone t-posing in a doorway we're trying to get through
var/turf/avoid
/datum/pathfind/New(atom/movable/caller, atom/goal, id, max_distance, mintargetdist, simulated_only, avoid)
src.caller = caller
end = get_turf(goal)
open = new /datum/heap(/proc/HeapPathWeightCompare)
sources = new()
src.id = id
src.max_distance = max_distance
src.mintargetdist = mintargetdist
src.simulated_only = simulated_only
src.avoid = avoid
/**
* search() is the proc you call to kick off and handle the actual pathfinding, and kills the pathfind datum instance when it's done.
*
* If a valid path was found, it's returned as a list. If invalid or cross-z-level params are entered, or if there's no valid path found, we
* return null, which [/proc/get_path_to] translates to an empty list (notable for simple bots, who need empty lists)
*/
/datum/pathfind/proc/search()
start = get_turf(caller)
if(!start || !end)
stack_trace("Invalid A* start or destination")
return
if(start.z != end.z || start == end ) //no pathfinding between z levels
return
if(max_distance && (max_distance < get_dist(start, end))) //if start turf is farther than max_distance from end turf, no need to do anything
return
//initialization
var/datum/jps_node/current_processed_node = new (start, -1, 0, end)
open.insert(current_processed_node)
sources[start] = start // i'm sure this is fine
//then run the main loop
while(!open.is_empty() && !path)
if(!caller)
return
current_processed_node = open.pop() //get the lower f_value turf in the open list
if(max_distance && (current_processed_node.number_tiles > max_distance))//if too many steps, don't process that path
continue
var/turf/current_turf = current_processed_node.tile
for(var/scan_direction in list(EAST, WEST, NORTH, SOUTH))
lateral_scan_spec(current_turf, scan_direction, current_processed_node)
for(var/scan_direction in list(NORTHEAST, SOUTHEAST, NORTHWEST, SOUTHWEST))
diag_scan_spec(current_turf, scan_direction, current_processed_node)
CHECK_TICK
//we're done! reverse the path to get it from start to finish
if(path)
for(var/i = 1 to round(0.5 * length(path)))
path.Swap(i, length(path) - i + 1)
sources = null
qdel(open)
return path
/// Called when we've hit the goal with the node that represents the last tile, then sets the path var to that path so it can be returned by [datum/pathfind/proc/search]
/datum/pathfind/proc/unwind_path(datum/jps_node/unwind_node)
path = new()
var/turf/iter_turf = unwind_node.tile
path.Add(iter_turf)
while(unwind_node.previous_node)
var/dir_goal = get_dir(iter_turf, unwind_node.previous_node.tile)
for(var/i = 1 to unwind_node.jumps)
iter_turf = get_step(iter_turf,dir_goal)
path.Add(iter_turf)
unwind_node = unwind_node.previous_node
/**
* For performing lateral scans from a given starting turf.
*
* These scans are called from both the main search loop, as well as subscans for diagonal scans, and they treat finding interesting turfs slightly differently.
* If we're doing a normal lateral scan, we already have a parent node supplied, so we just create the new node and immediately insert it into the heap, ezpz.
* If we're part of a subscan, we still need for the diagonal scan to generate a parent node, so we return a node datum with just the turf and let the diag scan
* proc handle transferring the values and inserting them into the heap.
*
* Arguments:
* * original_turf: What turf did we start this scan at?
* * heading: What direction are we going in? Obviously, should be cardinal
* * parent_node: Only given for normal lateral scans, if we don't have one, we're a diagonal subscan.
*/
/datum/pathfind/proc/lateral_scan_spec(turf/original_turf, heading, datum/jps_node/parent_node)
var/steps_taken = 0
var/turf/current_turf = original_turf
var/turf/lag_turf = original_turf
while(TRUE)
if(path)
return
lag_turf = current_turf
current_turf = get_step(current_turf, heading)
steps_taken++
if(!CAN_STEP(lag_turf, current_turf))
return
if(current_turf == end || (mintargetdist && (get_dist(current_turf, end) <= mintargetdist)))
var/datum/jps_node/final_node = new(current_turf, parent_node, steps_taken)
sources[current_turf] = original_turf
if(parent_node) // if this is a direct lateral scan we can wrap up, if it's a subscan from a diag, we need to let the diag make their node first, then finish
unwind_path(final_node)
return final_node
else if(sources[current_turf]) // already visited, essentially in the closed list
return
else
sources[current_turf] = original_turf
if(parent_node && parent_node.number_tiles + steps_taken > max_distance)
return
var/interesting = FALSE // have we found a forced neighbor that would make us add this turf to the open list?
switch(heading)
if(NORTH)
if(STEP_NOT_HERE_BUT_THERE(current_turf, WEST, NORTHWEST) || STEP_NOT_HERE_BUT_THERE(current_turf, EAST, NORTHEAST))
interesting = TRUE
if(SOUTH)
if(STEP_NOT_HERE_BUT_THERE(current_turf, WEST, SOUTHWEST) || STEP_NOT_HERE_BUT_THERE(current_turf, EAST, SOUTHEAST))
interesting = TRUE
if(EAST)
if(STEP_NOT_HERE_BUT_THERE(current_turf, NORTH, NORTHEAST) || STEP_NOT_HERE_BUT_THERE(current_turf, SOUTH, SOUTHEAST))
interesting = TRUE
if(WEST)
if(STEP_NOT_HERE_BUT_THERE(current_turf, NORTH, NORTHWEST) || STEP_NOT_HERE_BUT_THERE(current_turf, SOUTH, SOUTHWEST))
interesting = TRUE
if(interesting)
var/datum/jps_node/newnode = new(current_turf, parent_node, steps_taken)
if(parent_node) // if we're a diagonal subscan, we'll handle adding ourselves to the heap in the diag
open.insert(newnode)
return newnode
/**
* For performing diagonal scans from a given starting turf.
*
* Unlike lateral scans, these only are called from the main search loop, so we don't need to worry about returning anything,
* though we do need to handle the return values of our lateral subscans of course.
*
* Arguments:
* * original_turf: What turf did we start this scan at?
* * heading: What direction are we going in? Obviously, should be diagonal
* * parent_node: We should always have a parent node for diagonals
*/
/datum/pathfind/proc/diag_scan_spec(turf/original_turf, heading, datum/jps_node/parent_node)
var/steps_taken = 0
var/turf/current_turf = original_turf
var/turf/lag_turf = original_turf
while(TRUE)
if(path)
return
lag_turf = current_turf
current_turf = get_step(current_turf, heading)
steps_taken++
if(!CAN_STEP(lag_turf, current_turf))
return
if(current_turf == end || (mintargetdist && (get_dist(current_turf, end) <= mintargetdist)))
var/datum/jps_node/final_node = new(current_turf, parent_node, steps_taken)
sources[current_turf] = original_turf
unwind_path(final_node)
return
else if(sources[current_turf]) // already visited, essentially in the closed list
return
else
sources[current_turf] = original_turf
if(parent_node.number_tiles + steps_taken > max_distance)
return
var/interesting = FALSE // have we found a forced neighbor that would make us add this turf to the open list?
var/datum/jps_node/possible_child_node // otherwise, did one of our lateral subscans turn up something?
switch(heading)
if(NORTHWEST)
if(STEP_NOT_HERE_BUT_THERE(current_turf, EAST, NORTHEAST) || STEP_NOT_HERE_BUT_THERE(current_turf, SOUTH, SOUTHWEST))
interesting = TRUE
else
possible_child_node = (lateral_scan_spec(current_turf, WEST) || lateral_scan_spec(current_turf, NORTH))
if(NORTHEAST)
if(STEP_NOT_HERE_BUT_THERE(current_turf, WEST, NORTHWEST) || STEP_NOT_HERE_BUT_THERE(current_turf, SOUTH, SOUTHEAST))
interesting = TRUE
else
possible_child_node = (lateral_scan_spec(current_turf, EAST) || lateral_scan_spec(current_turf, NORTH))
if(SOUTHWEST)
if(STEP_NOT_HERE_BUT_THERE(current_turf, EAST, SOUTHEAST) || STEP_NOT_HERE_BUT_THERE(current_turf, NORTH, NORTHWEST))
interesting = TRUE
else
possible_child_node = (lateral_scan_spec(current_turf, SOUTH) || lateral_scan_spec(current_turf, WEST))
if(SOUTHEAST)
if(STEP_NOT_HERE_BUT_THERE(current_turf, WEST, SOUTHWEST) || STEP_NOT_HERE_BUT_THERE(current_turf, NORTH, NORTHEAST))
interesting = TRUE
else
possible_child_node = (lateral_scan_spec(current_turf, SOUTH) || lateral_scan_spec(current_turf, EAST))
if(interesting || possible_child_node)
var/datum/jps_node/newnode = new(current_turf, parent_node, steps_taken)
open.insert(newnode)
if(possible_child_node)
possible_child_node.update_parent(newnode)
open.insert(possible_child_node)
if(possible_child_node.tile == end || (mintargetdist && (get_dist(possible_child_node.tile, end) <= mintargetdist)))
unwind_path(possible_child_node)
return
/**
* For seeing if we can actually move between 2 given turfs while accounting for our access and the caller's pass_flags
*
* Arguments:
* * caller: The movable, if one exists, being used for mobility checks to see what tiles it can reach
* * ID: An ID card that decides if we can gain access to doors that would otherwise block a turf
* * simulated_only: Do we only worry about turfs with simulated atmos, most notably things that aren't space?
*/
/turf/proc/LinkBlockedWithAccess(turf/destination_turf, caller, ID)
var/actual_dir = get_dir(src, destination_turf)
for(var/obj/structure/window/iter_window in src)
if(!iter_window.CanAStarPass(ID, actual_dir))
return TRUE
for(var/obj/machinery/door/window/iter_windoor in src)
if(!iter_windoor.CanAStarPass(ID, actual_dir))
return TRUE
var/reverse_dir = get_dir(destination_turf, src)
for(var/obj/iter_object in destination_turf)
if(!iter_object.CanAStarPass(ID, reverse_dir, caller))
return TRUE
return FALSE
#undef CAN_STEP
#undef STEP_NOT_HERE_BUT_THERE
+9 -9
View File
@@ -203,62 +203,62 @@
/mob/living/carbon/human/p_they(capitalized, temp_gender)
var/list/obscured = check_obscured_slots()
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
if((SLOT_W_UNIFORM in obscured) && skipface)
if((ITEM_SLOT_ICLOTHING in obscured) && skipface)
temp_gender = PLURAL
return ..()
/mob/living/carbon/human/p_their(capitalized, temp_gender)
var/list/obscured = check_obscured_slots()
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
if((SLOT_W_UNIFORM in obscured) && skipface)
if((ITEM_SLOT_ICLOTHING in obscured) && skipface)
temp_gender = PLURAL
return ..()
/mob/living/carbon/human/p_them(capitalized, temp_gender)
var/list/obscured = check_obscured_slots()
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
if((SLOT_W_UNIFORM in obscured) && skipface)
if((ITEM_SLOT_ICLOTHING in obscured) && skipface)
temp_gender = PLURAL
return ..()
/mob/living/carbon/human/p_have(temp_gender)
var/list/obscured = check_obscured_slots()
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
if((SLOT_W_UNIFORM in obscured) && skipface)
if((ITEM_SLOT_ICLOTHING in obscured) && skipface)
temp_gender = PLURAL
return ..()
/mob/living/carbon/human/p_are(temp_gender)
var/list/obscured = check_obscured_slots()
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
if((SLOT_W_UNIFORM in obscured) && skipface)
if((ITEM_SLOT_ICLOTHING in obscured) && skipface)
temp_gender = PLURAL
return ..()
/mob/living/carbon/human/p_were(temp_gender)
var/list/obscured = check_obscured_slots()
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
if((SLOT_W_UNIFORM in obscured) && skipface)
if((ITEM_SLOT_ICLOTHING in obscured) && skipface)
temp_gender = PLURAL
return ..()
/mob/living/carbon/human/p_do(temp_gender)
var/list/obscured = check_obscured_slots()
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
if((SLOT_W_UNIFORM in obscured) && skipface)
if((ITEM_SLOT_ICLOTHING in obscured) && skipface)
temp_gender = PLURAL
return ..()
/mob/living/carbon/human/p_s(temp_gender)
var/list/obscured = check_obscured_slots()
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
if((SLOT_W_UNIFORM in obscured) && skipface)
if((ITEM_SLOT_ICLOTHING in obscured) && skipface)
temp_gender = PLURAL
return ..()
/mob/living/carbon/human/p_es(temp_gender)
var/list/obscured = check_obscured_slots()
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
if((SLOT_W_UNIFORM in obscured) && skipface)
if((ITEM_SLOT_ICLOTHING in obscured) && skipface)
temp_gender = PLURAL
return ..()
+4
View File
@@ -624,6 +624,10 @@
currrent_category = A.roundend_category
previous_category = A
result += A.roundend_report()
//ambition start
for(var/count in 1 to LAZYLEN(A.owner.ambitions))
result += "<br><B>Ambition #[count]</B>: [A.owner.ambitions[count]]"
//ambition end
result += "<br><br>"
CHECK_TICK
+20 -20
View File
@@ -412,25 +412,25 @@
/proc/slot2body_zone(slot)
switch(slot)
if(SLOT_BACK, SLOT_WEAR_SUIT, SLOT_W_UNIFORM, SLOT_BELT, SLOT_WEAR_ID)
if(ITEM_SLOT_BACK, ITEM_SLOT_OCLOTHING, ITEM_SLOT_ICLOTHING, ITEM_SLOT_BELT, ITEM_SLOT_ID)
return BODY_ZONE_CHEST
if(SLOT_GLOVES, SLOT_HANDS, SLOT_HANDCUFFED)
if(ITEM_SLOT_GLOVES, ITEM_SLOT_HANDS, ITEM_SLOT_HANDCUFFED)
return pick(BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND)
if(SLOT_HEAD, SLOT_NECK, SLOT_NECK, SLOT_EARS)
if(ITEM_SLOT_HEAD, ITEM_SLOT_NECK, ITEM_SLOT_NECK, ITEM_SLOT_EARS)
return BODY_ZONE_HEAD
if(SLOT_WEAR_MASK)
if(ITEM_SLOT_MASK)
return BODY_ZONE_PRECISE_MOUTH
if(SLOT_GLASSES)
if(ITEM_SLOT_EYES)
return BODY_ZONE_PRECISE_EYES
if(SLOT_SHOES)
if(ITEM_SLOT_FEET)
return pick(BODY_ZONE_PRECISE_R_FOOT, BODY_ZONE_PRECISE_L_FOOT)
if(SLOT_LEGCUFFED)
if(ITEM_SLOT_LEGCUFFED)
return pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
//adapted from http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
@@ -652,31 +652,31 @@
/proc/slot_to_string(slot)
switch(slot)
if(SLOT_BACK)
if(ITEM_SLOT_BACK)
return "Backpack"
if(SLOT_WEAR_MASK)
if(ITEM_SLOT_MASK)
return "Mask"
if(SLOT_HANDS)
if(ITEM_SLOT_HANDS)
return "Hands"
if(SLOT_BELT)
if(ITEM_SLOT_BELT)
return "Belt"
if(SLOT_EARS)
if(ITEM_SLOT_EARS)
return "Ears"
if(SLOT_GLASSES)
if(ITEM_SLOT_EYES)
return "Glasses"
if(SLOT_GLOVES)
if(ITEM_SLOT_GLOVES)
return "Gloves"
if(SLOT_NECK)
if(ITEM_SLOT_NECK)
return "Neck"
if(SLOT_HEAD)
if(ITEM_SLOT_HEAD)
return "Head"
if(SLOT_SHOES)
if(ITEM_SLOT_FEET)
return "Shoes"
if(SLOT_WEAR_SUIT)
if(ITEM_SLOT_OCLOTHING)
return "Suit"
if(SLOT_W_UNIFORM)
if(ITEM_SLOT_ICLOTHING)
return "Uniform"
if(SLOT_IN_BACKPACK)
if(ITEM_SLOT_BACKPACK)
return "In backpack"
/proc/tg_ui_icon_to_cit_ui(ui_style)
+1 -1
View File
@@ -1600,7 +1600,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
if(!iscarbon(target))
return TRUE
if(check_neck)
if(istype(target.get_item_by_slot(SLOT_NECK), /obj/item/clothing/neck/garlic_necklace))
if(istype(target.get_item_by_slot(ITEM_SLOT_NECK), /obj/item/clothing/neck/garlic_necklace))
return FALSE
if(check_blood)
if(target.reagents.has_reagent(/datum/reagent/consumable/garlic))
+1
View File
@@ -160,6 +160,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"HOLOGRAM_1" = HOLOGRAM_1,
"SHOCKED_1" = SHOCKED_1,
"INITIALIZED_1" = INITIALIZED_1,
"NO_SCREENTIPS_1" = NO_SCREENTIPS_1,
"ADMIN_SPAWNED_1" = ADMIN_SPAWNED_1,
"BLOCK_FACE_ATOM_1" = BLOCK_FACE_ATOM_1,
"PREVENT_CONTENTS_EXPLOSION_1" = PREVENT_CONTENTS_EXPLOSION_1
+2
View File
@@ -16,6 +16,8 @@ GLOBAL_LIST_EMPTY(singularities) //list of all singularities on the stati
GLOBAL_LIST_EMPTY(grounding_rods) //list of all grounding rods on the station
GLOBAL_LIST(chemical_reactions_list) //list of all /datum/chemical_reaction datums. Used during chemical reactions
GLOBAL_LIST(drink_reactions_list) //list of all /datum/chemical_reaction datums where the output is of type /datum/reagent/consumable for bartender PDA
GLOBAL_LIST(normalized_chemical_reactions_list) //list of all /datum/chemical_reaction datums with actual sane indexing for chemistry PDA
GLOBAL_LIST(chemical_reagents_list) //list of all /datum/reagent datums indexed by reagent id. Used by chemistry stuff
GLOBAL_LIST_EMPTY(tech_list) //list of all /datum/tech datums indexed by id.
GLOBAL_LIST_EMPTY(surgeries_list) //list of all surgeries by name, associated with their path.
+2
View File
@@ -11,6 +11,8 @@ GLOBAL_VAR(world_qdel_log)
GLOBAL_PROTECT(world_qdel_log)
GLOBAL_VAR(world_attack_log)
GLOBAL_PROTECT(world_attack_log)
GLOBAL_VAR(world_victim_log)
GLOBAL_PROTECT(world_victim_log)
// GLOBAL_VAR(world_econ_log)
// GLOBAL_PROTECT(world_econ_log)
GLOBAL_VAR(world_href_log)
+1 -1
View File
@@ -117,7 +117,7 @@
for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory))
if(inv.slot_id)
inv.hud = src
inv_slots[inv.slot_id] = inv
inv_slots[TOBITSHIFT(inv.slot_id) + 1] = inv
inv.update_icon()
/datum/hud/alien/persistent_inventory_update()
+3 -3
View File
@@ -8,7 +8,7 @@
inv_box.icon_state = "suit_storage"
// inv_box.icon_full = "template"
inv_box.screen_loc = ui_drone_storage
inv_box.slot_id = SLOT_GENERC_DEXTROUS_STORAGE
inv_box.slot_id = ITEM_SLOT_DEX_STORAGE
static_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
@@ -17,13 +17,13 @@
inv_box.icon_state = "mask"
// inv_box.icon_full = "template"
inv_box.screen_loc = ui_drone_head
inv_box.slot_id = SLOT_HEAD
inv_box.slot_id = ITEM_SLOT_HEAD
static_inventory += inv_box
for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory))
if(inv.slot_id)
inv.hud = src
inv_slots[inv.slot_id] = inv
inv_slots[TOBITSHIFT(inv.slot_id) + 1] = inv
inv.update_icon()
+1 -1
View File
@@ -60,7 +60,7 @@
for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory))
if(inv.slot_id)
inv.hud = src
inv_slots[inv.slot_id] = inv
inv_slots[TOBITSHIFT(inv.slot_id) + 1] = inv
inv.update_icon()
/datum/hud/dextrous/persistent_inventory_update()
+1 -1
View File
@@ -43,7 +43,7 @@
inv_box.icon = ui_style
inv_box.icon_state = "suit_storage"
inv_box.screen_loc = ui_id
inv_box.slot_id = SLOT_GENERC_DEXTROUS_STORAGE
inv_box.slot_id = ITEM_SLOT_DEX_STORAGE
static_inventory += inv_box
using = new /atom/movable/screen/guardian/Communicate()
+20
View File
@@ -53,6 +53,22 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
var/list/hand_slots // /atom/movable/screen/inventory/hand objects, assoc list of "[held_index]" = object
var/list/atom/movable/screen/plane_master/plane_masters = list() // see "appearance_flags" in the ref, assoc list of "[plane]" = object
///UI for screentips that appear when you mouse over things
var/atom/movable/screen/screentip/screentip_text
/// Whether or not screentips are enabled.
/// This is updated by the preference for cheaper reads than would be
/// had with a proc call, especially on one of the hottest procs in the
/// game (MouseEntered).
var/screentips_enabled = TRUE
/// The color to use for the screentips.
/// This is updated by the preference for cheaper reads than would be
/// had with a proc call, especially on one of the hottest procs in the
/// game (MouseEntered).
var/screentip_color
var/atom/movable/screen/movable/action_button/hide_toggle/hide_actions_toggle
var/action_buttons_hidden = FALSE
@@ -83,6 +99,8 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
plane_masters["[instance.plane]"] = instance
instance.backdrop(mymob)
screentip_text = new(null, src)
static_inventory += screentip_text
/datum/hud/Destroy()
if(mymob.hud_used == src)
@@ -117,6 +135,8 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
QDEL_LIST(screenoverlays)
mymob = null
QDEL_NULL(screentip_text)
return ..()
+16 -16
View File
@@ -233,7 +233,7 @@
inv_box = new /atom/movable/screen/inventory()
inv_box.name = "i_clothing"
inv_box.icon = ui_style
inv_box.slot_id = SLOT_W_UNIFORM
inv_box.slot_id = ITEM_SLOT_ICLOTHING
inv_box.icon_state = "uniform"
inv_box.screen_loc = ui_iclothing
toggleable_inventory += inv_box
@@ -241,7 +241,7 @@
inv_box = new /atom/movable/screen/inventory()
inv_box.name = "o_clothing"
inv_box.icon = ui_style
inv_box.slot_id = SLOT_WEAR_SUIT
inv_box.slot_id = ITEM_SLOT_OCLOTHING
inv_box.icon_state = "suit"
inv_box.screen_loc = ui_oclothing
toggleable_inventory += inv_box
@@ -267,7 +267,7 @@
inv_box.icon = ui_style
inv_box.icon_state = "id"
inv_box.screen_loc = ui_id
inv_box.slot_id = SLOT_WEAR_ID
inv_box.slot_id = ITEM_SLOT_ID
static_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
@@ -275,7 +275,7 @@
inv_box.icon = ui_style
inv_box.icon_state = "mask"
inv_box.screen_loc = ui_mask
inv_box.slot_id = SLOT_WEAR_MASK
inv_box.slot_id = ITEM_SLOT_MASK
toggleable_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
@@ -283,7 +283,7 @@
inv_box.icon = ui_style
inv_box.icon_state = "neck"
inv_box.screen_loc = ui_neck
inv_box.slot_id = SLOT_NECK
inv_box.slot_id = ITEM_SLOT_NECK
toggleable_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
@@ -291,7 +291,7 @@
inv_box.icon = ui_style
inv_box.icon_state = "back"
inv_box.screen_loc = ui_back
inv_box.slot_id = SLOT_BACK
inv_box.slot_id = ITEM_SLOT_BACK
static_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
@@ -299,7 +299,7 @@
inv_box.icon = ui_style
inv_box.icon_state = "pocket"
inv_box.screen_loc = ui_storage1
inv_box.slot_id = SLOT_L_STORE
inv_box.slot_id = ITEM_SLOT_LPOCKET
static_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
@@ -307,7 +307,7 @@
inv_box.icon = ui_style
inv_box.icon_state = "pocket"
inv_box.screen_loc = ui_storage2
inv_box.slot_id = SLOT_R_STORE
inv_box.slot_id = ITEM_SLOT_RPOCKET
static_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
@@ -315,7 +315,7 @@
inv_box.icon = ui_style
inv_box.icon_state = "suit_storage"
inv_box.screen_loc = ui_sstore1
inv_box.slot_id = SLOT_S_STORE
inv_box.slot_id = ITEM_SLOT_SUITSTORE
static_inventory += inv_box
using = new /atom/movable/screen/resist()
@@ -348,7 +348,7 @@
inv_box.icon = ui_style
inv_box.icon_state = "gloves"
inv_box.screen_loc = ui_gloves
inv_box.slot_id = SLOT_GLOVES
inv_box.slot_id = ITEM_SLOT_GLOVES
toggleable_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
@@ -356,7 +356,7 @@
inv_box.icon = ui_style
inv_box.icon_state = "glasses"
inv_box.screen_loc = ui_glasses
inv_box.slot_id = SLOT_GLASSES
inv_box.slot_id = ITEM_SLOT_EYES
toggleable_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
@@ -364,7 +364,7 @@
inv_box.icon = ui_style
inv_box.icon_state = "ears"
inv_box.screen_loc = ui_ears
inv_box.slot_id = SLOT_EARS
inv_box.slot_id = ITEM_SLOT_EARS
toggleable_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
@@ -372,7 +372,7 @@
inv_box.icon = ui_style
inv_box.icon_state = "head"
inv_box.screen_loc = ui_head
inv_box.slot_id = SLOT_HEAD
inv_box.slot_id = ITEM_SLOT_HEAD
toggleable_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
@@ -380,7 +380,7 @@
inv_box.icon = ui_style
inv_box.icon_state = "shoes"
inv_box.screen_loc = ui_shoes
inv_box.slot_id = SLOT_SHOES
inv_box.slot_id = ITEM_SLOT_FEET
toggleable_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
@@ -389,7 +389,7 @@
inv_box.icon_state = "belt"
// inv_box.icon_full = "template_small"
inv_box.screen_loc = ui_belt
inv_box.slot_id = SLOT_BELT
inv_box.slot_id = ITEM_SLOT_BELT
static_inventory += inv_box
throw_icon = new /atom/movable/screen/throw_catch()
@@ -464,7 +464,7 @@
for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory))
if(inv.slot_id)
inv.hud = src
inv_slots[inv.slot_id] = inv
inv_slots[TOBITSHIFT(inv.slot_id) + 1] = inv
inv.update_icon()
update_locked_slots()
+5 -5
View File
@@ -50,7 +50,7 @@
inv_box.icon_state = "mask"
// inv_box.icon_full = "template"
inv_box.screen_loc = ui_monkey_mask
inv_box.slot_id = SLOT_WEAR_MASK
inv_box.slot_id = ITEM_SLOT_MASK
static_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
@@ -59,7 +59,7 @@
inv_box.icon_state = "neck"
// inv_box.icon_full = "template"
inv_box.screen_loc = ui_monkey_neck
inv_box.slot_id = SLOT_NECK
inv_box.slot_id = ITEM_SLOT_NECK
static_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
@@ -68,7 +68,7 @@
inv_box.icon_state = "head"
// inv_box.icon_full = "template"
inv_box.screen_loc = ui_monkey_head
inv_box.slot_id = SLOT_HEAD
inv_box.slot_id = ITEM_SLOT_HEAD
static_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
@@ -76,7 +76,7 @@
inv_box.icon = ui_style
inv_box.icon_state = "back"
inv_box.screen_loc = ui_monkey_back
inv_box.slot_id = SLOT_BACK
inv_box.slot_id = ITEM_SLOT_BACK
static_inventory += inv_box
throw_icon = new /atom/movable/screen/throw_catch()
@@ -126,7 +126,7 @@
for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory))
if(inv.slot_id)
inv.hud = src
inv_slots[inv.slot_id] = inv
inv_slots[TOBITSHIFT(inv.slot_id) + 1] = inv
inv.update_icon()
/datum/hud/monkey/persistent_inventory_update()
+19
View File
@@ -0,0 +1,19 @@
/atom/movable/screen/screentip
icon = null
icon_state = null
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
screen_loc = "TOP,LEFT"
maptext_height = 480
maptext_width = 480
maptext = ""
/atom/movable/screen/screentip/Initialize(mapload, _hud)
. = ..()
hud = _hud
update_view()
/atom/movable/screen/screentip/proc/update_view(datum/source)
SIGNAL_HANDLER
if(!hud || !hud.mymob.client.view_size) //Might not have been initialized by now
return
maptext_width = getviewsize(hud.mymob.client.view_size.getView())[1] * world.icon_size
+1 -1
View File
@@ -101,7 +101,7 @@
//stops TK grabs being equipped anywhere but into hands
/obj/item/tk_grab/equipped(mob/user, slot)
if(slot == SLOT_HANDS)
if(slot == ITEM_SLOT_HANDS)
return ..()
qdel(src)
+1 -1
View File
@@ -174,7 +174,7 @@
L.SetView(C.view, TRUE)
. |= L
C.screen |= .
if(!secondary_map)
if(!secondary_map && (owner.prefs.parallax != PARALLAX_DISABLE))
var/atom/movable/screen/plane_master/parallax_white/PM = locate() in C.screen
if(PM)
PM.color = list(
+1 -1
View File
@@ -17,7 +17,7 @@
P.pixel_x = planet_offset_x
P.pixel_y = planet_offset_y
. += P
if(random_layer)
if(ispath(random_layer, /atom/movable/screen/parallax_layer))
. += new random_layer
if(ispath(random_layer, /atom/movable/screen/parallax_layer/space/random/space_gas))
var/atom/movable/screen/parallax_layer/space/random/space_gas/SG = locate(random_layer) in objects
@@ -94,6 +94,10 @@
config_entry_value = 10
min_val = 0
/datum/config_entry/keyed_list/dynamic_mode_days
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_FLAG
/datum/config_entry/keyed_list/storyteller_weight
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_NUM
@@ -349,3 +349,9 @@
/datum/config_entry/flag/dynamic_config_enabled
/datum/config_entry/flag/station_name_needs_approval
//ambition start
/datum/config_entry/number/max_ambitions // Maximum number of ambitions a mind can store.
config_entry_value = 5
//ambition end
@@ -1,88 +1,119 @@
/datum/config_entry/flag/log_ooc // log OOC channel
/// log OOC channel
/datum/config_entry/flag/log_ooc
config_entry_value = TRUE
/datum/config_entry/flag/log_access // log login/logout
/// log login/logout
/datum/config_entry/flag/log_access
config_entry_value = TRUE
/// Config entry which special logging of failed logins under suspicious circumstances.
/datum/config_entry/flag/log_suspicious_login
config_entry_value = TRUE
/datum/config_entry/flag/log_say // log client say
/// log client say
/datum/config_entry/flag/log_say
config_entry_value = TRUE
/datum/config_entry/flag/log_admin // log admin actions
/// log admin actions
/datum/config_entry/flag/log_admin
protection = CONFIG_ENTRY_LOCKED
config_entry_value = TRUE
/datum/config_entry/flag/log_prayer // log prayers
/// log prayers
/datum/config_entry/flag/log_prayer
config_entry_value = TRUE
/datum/config_entry/flag/log_law // log lawchanges
/// log lawchanges
/datum/config_entry/flag/log_law
config_entry_value = TRUE
/datum/config_entry/flag/log_game // log game events
/// log game events
/datum/config_entry/flag/log_game
config_entry_value = TRUE
/datum/config_entry/flag/log_virus // log virology data
/// log virology data
/datum/config_entry/flag/log_virus
config_entry_value = TRUE
/datum/config_entry/flag/log_vote // log voting
/// log voting
/datum/config_entry/flag/log_vote
config_entry_value = TRUE
/datum/config_entry/flag/log_craft // log crafting
/// log crafting
/datum/config_entry/flag/log_craft
config_entry_value = TRUE
/datum/config_entry/flag/log_whisper // log client whisper
/// log client whisper
/datum/config_entry/flag/log_whisper
config_entry_value = TRUE
/datum/config_entry/flag/log_attack // log attack messages
/// log attack messages
/datum/config_entry/flag/log_attack
config_entry_value = TRUE
/datum/config_entry/flag/log_emote // log emotes
/// log attack messages
/datum/config_entry/flag/log_victim
config_entry_value = TRUE
/datum/config_entry/flag/log_adminchat // log admin chat messages
/// log emotes
/datum/config_entry/flag/log_emote
config_entry_value = TRUE
/// log admin chat messages
/datum/config_entry/flag/log_adminchat
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/flag/log_shuttle // log shuttle related actions, ie shuttle computers, shuttle manipulator, emergency console
/// log shuttle related actions, ie shuttle computers, shuttle manipulator, emergency console
/datum/config_entry/flag/log_shuttle
config_entry_value = TRUE
/datum/config_entry/flag/log_pda // log pda messages
/// log pda messages
/datum/config_entry/flag/log_pda
config_entry_value = TRUE
/datum/config_entry/flag/log_telecomms // log telecomms messages
/// log telecomms messages
/datum/config_entry/flag/log_telecomms
config_entry_value = TRUE
/datum/config_entry/flag/log_twitter // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases.
/// log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases.
/datum/config_entry/flag/log_twitter
config_entry_value = TRUE
/datum/config_entry/flag/log_world_topic // log all world.Topic() calls
/// log all world.Topic() calls
/datum/config_entry/flag/log_world_topic
config_entry_value = TRUE
/datum/config_entry/flag/log_manifest // log crew manifest to seperate file
/// log crew manifest to seperate file
/datum/config_entry/flag/log_manifest
config_entry_value = TRUE
/datum/config_entry/flag/log_job_debug // log roundstart divide occupations debug information to a file
/// log roundstart divide occupations debug information to a file
/datum/config_entry/flag/log_job_debug
config_entry_value = TRUE
/// log photos taken by players with a camera
/datum/config_entry/flag/log_pictures
/// This is... shitcode, literally same as above, if one of them is inactive, won't log at all, PLEASE FUCKING REMOVE THIS.
/datum/config_entry/flag/picture_logging_camera
/// forces log_href for tgui
/datum/config_entry/flag/emergency_tgui_logging
config_entry_value = FALSE
/datum/config_entry/number/error_cooldown // The "cooldown" time for each occurrence of a unique error
/// The "cooldown" time for each occurrence of a unique error
/datum/config_entry/number/error_cooldown
config_entry_value = 600
min_val = 0
/datum/config_entry/number/error_limit // How many occurrences before the next will silence them
/// How many occurrences before the next will silence them
/datum/config_entry/number/error_limit
config_entry_value = 50
/datum/config_entry/number/error_silence_time // How long a unique error will be silenced for
/// How long a unique error will be silenced for
/datum/config_entry/number/error_silence_time
config_entry_value = 6000
/datum/config_entry/number/error_msg_delay // How long to wait between messaging admins about occurrences of a unique error
/// How long to wait between messaging admins about occurrences of a unique error
/datum/config_entry/number/error_msg_delay
config_entry_value = 50
+9 -6
View File
@@ -396,12 +396,15 @@ SUBSYSTEM_DEF(air)
*/
/datum/controller/subsystem/air/proc/run_delay_heuristics()
if(!equalize_enabled)
cost_equalize = 0
if(should_do_equalization)
eq_cooldown--
if(eq_cooldown <= 0)
equalize_enabled = TRUE
if(should_do_equalization)
if(!equalize_enabled)
cost_equalize = 0
if(should_do_equalization)
eq_cooldown--
if(eq_cooldown <= 0)
equalize_enabled = TRUE
else
equalize_enabled = FALSE
var/total_thread_time = cost_turfs + cost_equalize + cost_groups + cost_post_process
if(total_thread_time)
var/wait_ms = wait * 100
+4 -4
View File
@@ -500,7 +500,7 @@ SUBSYSTEM_DEF(job)
tcg_cards = N.client.prefs.tcg_cards
if(tcg_cards)
var/obj/item/tcgcard_binder/binder = new(get_turf(H))
H.equip_to_slot_if_possible(binder, SLOT_IN_BACKPACK, disable_warning = TRUE, bypass_equip_delay_self = TRUE)
H.equip_to_slot_if_possible(binder, ITEM_SLOT_BACKPACK, disable_warning = TRUE, bypass_equip_delay_self = TRUE)
for(var/card_type in N.client.prefs.tcg_cards)
if(card_type)
if(islist(H.client.prefs.tcg_cards[card_type]))
@@ -710,9 +710,9 @@ SUBSYSTEM_DEF(job)
permitted = FALSE
if(G.donoritem && !G.donator_ckey_check(the_mob.client.ckey))
permitted = FALSE
if(!equipbackpackstuff && G.slot == SLOT_IN_BACKPACK)//snowflake check since plopping stuff in the backpack doesnt work for pre-job equip loadout stuffs
if(!equipbackpackstuff && G.slot == ITEM_SLOT_BACKPACK)//snowflake check since plopping stuff in the backpack doesnt work for pre-job equip loadout stuffs
permitted = FALSE
if(equipbackpackstuff && G.slot != SLOT_IN_BACKPACK)//ditto
if(equipbackpackstuff && G.slot != ITEM_SLOT_BACKPACK)//ditto
permitted = FALSE
if(!permitted)
continue
@@ -749,7 +749,7 @@ SUBSYSTEM_DEF(job)
I.forceMove(get_turf(C))
else
qdel(I)
else if(!M.equip_to_slot_if_possible(I, SLOT_IN_BACKPACK, disable_warning = TRUE, bypass_equip_delay_self = TRUE)) // Otherwise, try to put it in the backpack
else if(!M.equip_to_slot_if_possible(I, ITEM_SLOT_BACKPACK, disable_warning = TRUE, bypass_equip_delay_self = TRUE)) // Otherwise, try to put it in the backpack
if(can_drop)
I.forceMove(get_turf(M)) // If everything fails, just put it on the floor under the mob.
else
+17 -5
View File
@@ -32,6 +32,8 @@ SUBSYSTEM_DEF(vote)
var/list/stored_modetier_results = list() // The aggregated tier list of the modes available in secret.
var/transfer_votes_done = 0
/datum/controller/subsystem/vote/fire() //called by master_controller
if(mode)
if(end_time < world.time)
@@ -248,8 +250,18 @@ SUBSYSTEM_DEF(vote)
if(vote_system == SCORE_VOTING)
calculate_scores(vote_title_text)
if(vote_system == HIGHEST_MEDIAN_VOTING)
calculate_highest_median(vote_title_text) // nothing uses this at the moment
var/list/winners = vote_system == INSTANT_RUNOFF_VOTING ? get_runoff_results() : get_result()
calculate_highest_median(vote_title_text)
var/list/winners = list()
if(mode == "transfer")
var/amount_required = 3 + transfer_votes_done
transfer_votes_done += 1
text += "\nExtending requires at least [amount_required] votes to win."
if(choices[VOTE_CONTINUE] < amount_required || choices[VOTE_TRANSFER] >= choices[VOTE_CONTINUE])
winners = list(VOTE_TRANSFER)
else
winners = list(VOTE_CONTINUE)
else
winners = vote_system == INSTANT_RUNOFF_VOTING ? get_runoff_results() : get_result()
var/was_roundtype_vote = mode == "roundtype" || mode == "dynamic"
if(winners.len > 0)
if(was_roundtype_vote)
@@ -305,7 +317,7 @@ SUBSYSTEM_DEF(vote)
if(vote_system == SCHULZE_VOTING)
admintext += "\nIt should be noted that this is not a raw tally of votes (impossible in ranked choice) but the score determined by the schulze method of voting, so the numbers will look weird!"
else if(vote_system == HIGHEST_MEDIAN_VOTING)
admintext += "\nIt should be noted that this is not a raw tally of votes but the number of runoffs done by majority judgement!"
admintext += "\nIt should be noted that this is not a raw tally of votes but rather the median score plus a tiebreaker!"
for(var/i=1,i<=choices.len,i++)
var/votes = choices[choices[i]]
admintext += "\n<b>[choices[i]]:</b> [votes]"
@@ -339,7 +351,7 @@ SUBSYSTEM_DEF(vote)
if(SSmapping.changemap(config.maplist[.]))
to_chat(world, "<span class='boldannounce'>The map vote has chosen [VM.map_name] for next round!</span>")
if("transfer") // austation begin -- Crew autotransfer vote
if(. == "Initiate Crew Transfer")
if(. == VOTE_TRANSFER)
SSshuttle.autoEnd()
var/obj/machinery/computer/communications/C = locate() in GLOB.machines
if(C)
@@ -446,7 +458,7 @@ SUBSYSTEM_DEF(vote)
continue
choices |= M
if("transfer") // austation begin -- Crew autotranfer vote
choices.Add("Initiate Crew Transfer","Continue Playing") // austation end
choices.Add(VOTE_TRANSFER,VOTE_CONTINUE) // austation end
if("roundtype") //CIT CHANGE - adds the roundstart secret/extended vote
choices.Add("dynamic", "extended")
if("custom")
+1 -1
View File
@@ -516,7 +516,7 @@
H.attack_self(owner)
return
var/obj/item/I = target
if(owner.can_equip(I, SLOT_HANDS))
if(owner.can_equip(I, ITEM_SLOT_HANDS))
owner.temporarilyRemoveItemFromInventory(I)
owner.put_in_hands(I)
I.attack_self(owner)
+1 -1
View File
@@ -29,7 +29,7 @@
expire = _expire
/datum/component/anti_magic/proc/on_equip(datum/source, mob/equipper, slot)
if(!(allowed_slots & slotdefine2slotbit(slot))) //Check that the slot is valid for antimagic
if(!(allowed_slots & slot)) //Check that the slot is valid for antimagic
UnregisterSignal(equipper, COMSIG_MOB_RECEIVE_MAGIC)
return
RegisterSignal(equipper, COMSIG_MOB_RECEIVE_MAGIC, .proc/protect, TRUE)
+1 -1
View File
@@ -9,7 +9,7 @@
var/filter_size
var/filter_color
/datum/component/wearertargeting/phantomthief/Initialize(_x = -2, _y = 0, _size = 0, _color = "#E62111", list/_valid_slots = list(SLOT_GLASSES))
/datum/component/wearertargeting/phantomthief/Initialize(_x = -2, _y = 0, _size = 0, _color = "#E62111", list/_valid_slots = list(ITEM_SLOT_EYES))
. = ..()
if(. == COMPONENT_INCOMPATIBLE)
return
+1 -1
View File
@@ -108,7 +108,7 @@
SSvis_overlays.add_vis_overlay(holder, 'icons/effects/effects.dmi', to_add, layer, GAME_PLANE, holder.dir)
/datum/component/shielded/proc/on_equip(obj/item/source, mob/living/equipper, slot)
if(!(accepted_slots & slotdefine2slotbit(slot)))
if(!(accepted_slots & slot))
return
holder = equipper
RegisterSignal(parent, COMSIG_ITEM_RUN_BLOCK, .proc/on_run_block)
+1 -1
View File
@@ -89,7 +89,7 @@
/// Triggered on equip of the item containing the component
/datum/component/two_handed/proc/on_equip(datum/source, mob/user, slot)
if(require_twohands && slot == SLOT_HANDS) // force equip the item
if(require_twohands && slot == ITEM_SLOT_HANDS) // force equip the item
wield(user)
if(!user.is_holding(parent) && wielded && !require_twohands)
unwield(user)
+1
View File
@@ -235,6 +235,7 @@
else
return returned
/**
* Callback called by a timer to end an associative-list-indexed cooldown.
*
+2 -2
View File
@@ -75,8 +75,8 @@
if(isobj(H.wear_suit))
Cl = H.wear_suit
passed = prob((Cl.permeability_coefficient*100) - 1)
if(passed && isobj(SLOT_W_UNIFORM))
Cl = SLOT_W_UNIFORM
if(passed && isobj(ITEM_SLOT_ICLOTHING))
Cl = ITEM_SLOT_ICLOTHING
passed = prob((Cl.permeability_coefficient*100) - 1)
if(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)
if(isobj(H.wear_suit) && H.wear_suit.body_parts_covered&HANDS)
+3 -3
View File
@@ -61,19 +61,19 @@ STI KALY - blind
if(!istype(H.head, /obj/item/clothing/head/wizard))
if(!H.dropItemToGround(H.head))
qdel(H.head)
H.equip_to_slot_or_del(new /obj/item/clothing/head/wizard(H), SLOT_HEAD)
H.equip_to_slot_or_del(new /obj/item/clothing/head/wizard(H), ITEM_SLOT_HEAD)
return
if(prob(chance))
if(!istype(H.wear_suit, /obj/item/clothing/suit/wizrobe))
if(!H.dropItemToGround(H.wear_suit))
qdel(H.wear_suit)
H.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe(H), SLOT_WEAR_SUIT)
H.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe(H), ITEM_SLOT_OCLOTHING)
return
if(prob(chance))
if(!istype(H.shoes, /obj/item/clothing/shoes/sandal/magic))
if(!H.dropItemToGround(H.shoes))
qdel(H.shoes)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal/magic(H), SLOT_SHOES)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal/magic(H), ITEM_SLOT_FEET)
return
else
var/mob/living/carbon/H = affected_mob
+1 -1
View File
@@ -19,7 +19,7 @@
user_by_item -= target
/datum/element/earhealing/proc/equippedChanged(datum/source, mob/living/carbon/user, slot)
if(slot == SLOT_EARS && istype(user))
if(slot == ITEM_SLOT_EARS && istype(user))
user_by_item[source] = user
else
user_by_item -= source
+1 -1
View File
@@ -144,7 +144,7 @@
return TRUE
/datum/element/polychromic/proc/grant_user_action(atom/source, mob/user, slot)
if(slot == SLOT_IN_BACKPACK || slot == SLOT_LEGCUFFED || slot == SLOT_HANDCUFFED || slot == SLOT_GENERC_DEXTROUS_STORAGE)
if(slot == ITEM_SLOT_BACKPACK || slot == ITEM_SLOT_LEGCUFFED || slot == ITEM_SLOT_HANDCUFFED || slot == ITEM_SLOT_DEX_STORAGE)
return
var/datum/action/polychromic/P = actions_by_atom[source]
if(!P)
+1 -1
View File
@@ -34,7 +34,7 @@
stacked_spellcasting_by_user -= target
/datum/element/spellcasting/proc/on_equip(datum/source, mob/equipper, slot)
if(!(cast_slots & slotdefine2slotbit(slot)))
if(!(cast_slots & slot))
return
users_by_item[source] = equipper
if(!stacked_spellcasting_by_user[equipper])
+2 -2
View File
@@ -59,7 +59,7 @@
/obj/item/clothing/gloves/boxing/equipped(mob/user, slot)
. = ..()
if(ishuman(user) && slot == SLOT_GLOVES)
if(ishuman(user) && slot == ITEM_SLOT_GLOVES)
var/mob/living/carbon/human/H = user
style.teach(H,TRUE)
@@ -68,5 +68,5 @@
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
if(H.get_item_by_slot(SLOT_GLOVES) == src)
if(H.get_item_by_slot(ITEM_SLOT_GLOVES) == src)
style.remove(H)
+2 -2
View File
@@ -197,7 +197,7 @@
/obj/item/clothing/gloves/krav_maga/equipped(mob/user, slot)
. = ..()
if(ishuman(user) && slot == SLOT_GLOVES)
if(ishuman(user) && slot == ITEM_SLOT_GLOVES)
var/mob/living/carbon/human/H = user
style.teach(H,1)
@@ -206,7 +206,7 @@
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
if(H.get_item_by_slot(SLOT_GLOVES) == src)
if(H.get_item_by_slot(ITEM_SLOT_GLOVES) == src)
style.remove(H)
/obj/item/clothing/gloves/krav_maga/sec//more obviously named, given to sec
+2 -2
View File
@@ -485,7 +485,7 @@
/obj/item/storage/belt/champion/wrestling/equipped(mob/user, slot)
. = ..()
if(ishuman(user) && slot == SLOT_BELT)
if(ishuman(user) && slot == ITEM_SLOT_BELT)
var/mob/living/carbon/human/H = user
style.teach(H,1)
@@ -494,7 +494,7 @@
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
if(H.get_item_by_slot(SLOT_BELT) == src)
if(H.get_item_by_slot(ITEM_SLOT_BELT) == src)
style.remove(H)
//Subtype of wrestling, reserved for the wrestling belts found in the holodeck
+955 -39
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -17,18 +17,18 @@
if(!istype(H.wear_mask, /obj/item/clothing/mask/gas/cluwne))
if(!H.dropItemToGround(H.wear_mask))
qdel(H.wear_mask)
H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/cluwne(H), SLOT_WEAR_MASK)
H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/cluwne(H), ITEM_SLOT_MASK)
if(!istype(H.w_uniform, /obj/item/clothing/under/cluwne))
if(!H.dropItemToGround(H.w_uniform))
qdel(H.w_uniform)
H.equip_to_slot_or_del(new /obj/item/clothing/under/cluwne(H), SLOT_W_UNIFORM)
H.equip_to_slot_or_del(new /obj/item/clothing/under/cluwne(H), ITEM_SLOT_ICLOTHING)
if(!istype(H.shoes, /obj/item/clothing/shoes/clown_shoes/cluwne))
if(!H.dropItemToGround(H.shoes))
qdel(H.shoes)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/clown_shoes/cluwne(H), SLOT_SHOES)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/clown_shoes/cluwne(H), ITEM_SLOT_FEET)
owner.equip_to_slot_or_del(new /obj/item/clothing/gloves/color/white(owner), SLOT_GLOVES) // this is purely for cosmetic purposes incase they aren't wearing anything in that slot
owner.equip_to_slot_or_del(new /obj/item/storage/backpack/clown(owner), SLOT_BACK) // ditto
owner.equip_to_slot_or_del(new /obj/item/clothing/gloves/color/white(owner), ITEM_SLOT_GLOVES) // this is purely for cosmetic purposes incase they aren't wearing anything in that slot
owner.equip_to_slot_or_del(new /obj/item/storage/backpack/clown(owner), ITEM_SLOT_BACK) // ditto
/datum/mutation/human/cluwne/on_life(mob/living/carbon/human/owner)
if((prob(15) && owner.IsUnconscious()))
+16 -16
View File
@@ -153,31 +153,31 @@
//Start with uniform,suit,backpack for additional slots
if(uniform)
H.equip_to_slot_or_del(new uniform(H), SLOT_W_UNIFORM, TRUE)
H.equip_to_slot_or_del(new uniform(H), ITEM_SLOT_ICLOTHING, TRUE)
if(suit)
H.equip_to_slot_or_del(new suit(H), SLOT_WEAR_SUIT, TRUE)
H.equip_to_slot_or_del(new suit(H), ITEM_SLOT_OCLOTHING, TRUE)
if(back)
H.equip_to_slot_or_del(new back(H), SLOT_BACK, TRUE)
H.equip_to_slot_or_del(new back(H), ITEM_SLOT_BACK, TRUE)
if(belt)
H.equip_to_slot_or_del(new belt(H), SLOT_BELT, TRUE)
H.equip_to_slot_or_del(new belt(H), ITEM_SLOT_BELT, TRUE)
if(gloves)
H.equip_to_slot_or_del(new gloves(H), SLOT_GLOVES, TRUE)
H.equip_to_slot_or_del(new gloves(H), ITEM_SLOT_GLOVES, TRUE)
if(shoes)
H.equip_to_slot_or_del(new shoes(H), SLOT_SHOES, TRUE)
H.equip_to_slot_or_del(new shoes(H), ITEM_SLOT_FEET, TRUE)
if(head)
H.equip_to_slot_or_del(new head(H), SLOT_HEAD, TRUE)
H.equip_to_slot_or_del(new head(H), ITEM_SLOT_HEAD, TRUE)
if(mask)
H.equip_to_slot_or_del(new mask(H), SLOT_WEAR_MASK, TRUE)
H.equip_to_slot_or_del(new mask(H), ITEM_SLOT_MASK, TRUE)
if(neck)
H.equip_to_slot_or_del(new neck(H), SLOT_NECK, TRUE)
H.equip_to_slot_or_del(new neck(H), ITEM_SLOT_NECK, TRUE)
if(ears)
H.equip_to_slot_or_del(new ears(H), SLOT_EARS, TRUE)
H.equip_to_slot_or_del(new ears(H), ITEM_SLOT_EARS, TRUE)
if(glasses)
H.equip_to_slot_or_del(new glasses(H), SLOT_GLASSES, TRUE)
H.equip_to_slot_or_del(new glasses(H), ITEM_SLOT_EYES, TRUE)
if(id)
H.equip_to_slot_or_del(new id(H), SLOT_WEAR_ID, TRUE)
H.equip_to_slot_or_del(new id(H), ITEM_SLOT_ID, TRUE)
if(suit_store)
H.equip_to_slot_or_del(new suit_store(H), SLOT_S_STORE, TRUE)
H.equip_to_slot_or_del(new suit_store(H), ITEM_SLOT_SUITSTORE, TRUE)
if(undershirt)
H.undershirt = initial(undershirt.name)
@@ -195,9 +195,9 @@
if(!visualsOnly) // Items in pockets or backpack don't show up on mob's icon.
if(l_pocket)
H.equip_to_slot_or_del(new l_pocket(H), SLOT_L_STORE, TRUE)
H.equip_to_slot_or_del(new l_pocket(H), ITEM_SLOT_LPOCKET, TRUE)
if(r_pocket)
H.equip_to_slot_or_del(new r_pocket(H), SLOT_R_STORE, TRUE)
H.equip_to_slot_or_del(new r_pocket(H), ITEM_SLOT_RPOCKET, TRUE)
if(box)
if(!backpack_contents)
@@ -211,7 +211,7 @@
if(!isnum(number))//Default to 1
number = 1
for(var/i in 1 to number)
H.equip_to_slot_or_del(new path(H), SLOT_IN_BACKPACK, TRUE)
H.equip_to_slot_or_del(new path(H), ITEM_SLOT_BACKPACK, TRUE)
if(!H.head && toggle_helmet && istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit))
var/obj/item/clothing/suit/space/hardsuit/HS = H.wear_suit
+6 -2
View File
@@ -578,8 +578,12 @@
/datum/status_effect/regenerative_core/on_apply()
. = ..()
ADD_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, "regenerative_core")
if(HAS_TRAIT(owner, TRAIT_ROBOTIC_ORGANISM)) //Robots can heal from cores, but only get 1/5th of the healing. They can use this to get past the damage threshhold however, and then regularely heal from there.
var/turf/T = get_turf(owner)
if(T && is_mining_level(T.z))
if(HAS_TRAIT(owner, TRAIT_ROBOTIC_ORGANISM)) //Robots can heal from cores, though they ""only"" heal 20 brute + burn damage each instead of 25
heal_amount *= 0.8
else
duration = 10 SECONDS
heal_amount *= 0.2
owner.adjustBruteLoss(-heal_amount, only_organic = FALSE)
if(!AmBloodsucker(owner)) //use your coffin you lazy bastard
+5 -1
View File
@@ -1005,11 +1005,15 @@
/datum/status_effect/trance/proc/hypnotize(datum/source, list/hearing_args)
if(!owner.can_hear())
return
if(hearing_args[HEARING_SPEAKER] == owner)
var/mob/hearing_speaker = hearing_args[HEARING_SPEAKER]
if(hearing_speaker == owner)
return
var/mob/living/carbon/C = owner
var/hypnomsg = uncostumize_say(hearing_args[HEARING_RAW_MESSAGE], hearing_args[HEARING_MESSAGE_MODE])
C.cure_trauma_type(/datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY) //clear previous hypnosis
// The brain trauma itself does its own set of logging, but this is the only place the source of the hypnosis phrase can be found.
hearing_speaker.log_message("has hypnotised [key_name(C)] with the phrase '[hypnomsg]'", LOG_ATTACK)
C.log_message("has been hypnotised by the phrase '[hypnomsg]' spoken by [key_name(hearing_speaker)]", LOG_VICTIM, log_globally = FALSE)
addtimer(CALLBACK(C, /mob/living/carbon.proc/gain_trauma, /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, hypnomsg), 10)
addtimer(CALLBACK(C, /mob/living.proc/Stun, 60, TRUE, TRUE), 15) //Take some time to think about it
qdel(src)
+1 -1
View File
@@ -129,7 +129,7 @@ Use this as a guideline
var/mob/living/carbon/human/H = quirk_holder
var/obj/item/clothing/glasses/regular/glasses = new(get_turf(H))
H.put_in_hands(glasses)
H.equip_to_slot(glasses, SLOT_GLASSES)
H.equip_to_slot(glasses, ITEM_SLOT_EYES)
H.regenerate_icons()
//This whole proc is called automatically
+5 -5
View File
@@ -108,10 +108,10 @@
var/mob/living/carbon/human/H = quirk_holder
var/obj/item/choice_beacon/music/B = new(get_turf(H))
H.put_in_hands(B)
H.equip_to_slot_if_possible(B, SLOT_IN_BACKPACK)
H.equip_to_slot_if_possible(B, ITEM_SLOT_BACKPACK)
var/obj/item/musicaltuner/musicaltuner = new(get_turf(H))
H.put_in_hands(musicaltuner)
H.equip_to_slot_if_possible(musicaltuner, SLOT_IN_BACKPACK)
H.equip_to_slot_if_possible(musicaltuner, ITEM_SLOT_BACKPACK)
H.regenerate_icons()
/datum/quirk/photographer
@@ -127,7 +127,7 @@
var/mob/living/carbon/human/H = quirk_holder
var/obj/item/camera/camera = new(get_turf(H))
H.put_in_hands(camera)
H.equip_to_slot(camera, SLOT_NECK)
H.equip_to_slot(camera, ITEM_SLOT_NECK)
H.regenerate_icons()
/datum/quirk/selfaware
@@ -166,7 +166,7 @@
var/mob/living/carbon/human/H = quirk_holder
var/obj/item/toy/crayon/spraycan/spraycan = new(get_turf(H))
H.put_in_hands(spraycan)
H.equip_to_slot(spraycan, SLOT_IN_BACKPACK)
H.equip_to_slot(spraycan, ITEM_SLOT_BACKPACK)
H.regenerate_icons()
/datum/quirk/voracious
@@ -188,7 +188,7 @@
/datum/quirk/trandening/on_spawn()
var/mob/living/carbon/human/H = quirk_holder
var/obj/item/autosurgeon/gloweyes/gloweyes = new(get_turf(H))
H.equip_to_slot(gloweyes, SLOT_IN_BACKPACK)
H.equip_to_slot(gloweyes, ITEM_SLOT_BACKPACK)
H.regenerate_icons()
/datum/quirk/bloodpressure
+5 -5
View File
@@ -57,9 +57,9 @@ GLOBAL_LIST_EMPTY(family_heirlooms)
heirloom = new heirloom_type(get_turf(quirk_holder))
GLOB.family_heirlooms += heirloom
var/list/slots = list(
"in your left pocket" = SLOT_L_STORE,
"in your right pocket" = SLOT_R_STORE,
"in your backpack" = SLOT_IN_BACKPACK
"in your left pocket" = ITEM_SLOT_LPOCKET,
"in your right pocket" = ITEM_SLOT_RPOCKET,
"in your backpack" = ITEM_SLOT_BACKPACK
)
where = H.equip_in_one_of_slots(heirloom, slots, FALSE) || "at your feet"
@@ -120,7 +120,7 @@ GLOBAL_LIST_EMPTY(family_heirlooms)
/datum/quirk/nearsighted/on_spawn()
var/mob/living/carbon/human/H = quirk_holder
var/obj/item/clothing/glasses/regular/glasses = new(get_turf(H))
if(!H.equip_to_slot_if_possible(glasses, SLOT_GLASSES))
if(!H.equip_to_slot_if_possible(glasses, ITEM_SLOT_EYES))
H.put_in_hands(glasses)
/datum/quirk/nyctophobia
@@ -383,7 +383,7 @@ GLOBAL_LIST_EMPTY(family_heirlooms)
/datum/quirk/blindness/on_spawn()
var/mob/living/carbon/human/H = quirk_holder
var/obj/item/clothing/glasses/sunglasses/blindfold/white/glasses = new(get_turf(H))
if(!H.equip_to_slot_if_possible(glasses, SLOT_GLASSES, bypass_equip_delay_self = TRUE)) //if you can't put it on the user's eyes, put it in their hands, otherwise put it on their eyes eyes
if(!H.equip_to_slot_if_possible(glasses, ITEM_SLOT_EYES, bypass_equip_delay_self = TRUE)) //if you can't put it on the user's eyes, put it in their hands, otherwise put it on their eyes eyes
H.put_in_hands(glasses)
H.regenerate_icons()
+1 -1
View File
@@ -172,7 +172,7 @@
/datum/quirk/colorist/on_spawn()
var/mob/living/carbon/human/H = quirk_holder
var/obj/item/dyespray/spraycan = new(get_turf(quirk_holder))
H.equip_to_slot(spraycan, SLOT_IN_BACKPACK)
H.equip_to_slot(spraycan, ITEM_SLOT_BACKPACK)
H.regenerate_icons()
/datum/quirk/colorist/post_add()
+9 -8
View File
@@ -1215,7 +1215,7 @@
if(user != target)
var/reverse_message = "has been [what_done] by [ssource][postfix]"
target.log_message(reverse_message, LOG_ATTACK, color="orange", log_globally=FALSE)
target.log_message(reverse_message, LOG_VICTIM, color="orange", log_globally=FALSE)
/**
* log_wound() is for when someone is *attacked* and suffers a wound. Note that this only captures wounds from damage, so smites/forced wounds aren't logged, as well as demotions like cuts scabbing over
@@ -1406,11 +1406,12 @@
//Update the screentip to reflect what we're hoverin over
/atom/MouseEntered(location, control, params)
. = ..()
// Statusbar
// status_bar_set_text(usr, name)
// Screentips
// if(usr?.hud_used)
// if(!usr.client?.prefs.screentip_pref || (flags_1 & NO_SCREENTIPS_1))
// usr.hud_used.screentip_text.maptext = ""
// else
// usr.hud_used.screentip_text.maptext = MAPTEXT("<span style='text-align: center'><span style='font-size: 32px'><span style='color:[usr.client.prefs.screentip_color]: 32px'>[name]</span>")
var/client/client = usr?.client
var/datum/hud/active_hud = client?.mob?.hud_used
if(active_hud)
if(!client.prefs.screentip_pref || (flags_1 & NO_SCREENTIPS_1))
active_hud.screentip_text.maptext = ""
else
//We inline a MAPTEXT() here, because there's no good way to statically add to a string like this
active_hud.screentip_text.maptext = MAPTEXT("<span style='text-align: center; font-size: 32px; color: [client?.prefs?.screentip_color]'>[name]</span>")
+1 -1
View File
@@ -1,6 +1,6 @@
GLOBAL_LIST_INIT(possible_changeling_IDs, list("Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta","Theta","Iota","Kappa","Lambda","Mu","Nu","Xi","Omicron","Pi","Rho","Sigma","Tau","Upsilon","Phi","Chi","Psi","Omega"))
GLOBAL_LIST_INIT(slots, list("head", "wear_mask", "back", "wear_suit", "w_uniform", "shoes", "belt", "gloves", "glasses", "ears", "wear_id", "s_store"))
GLOBAL_LIST_INIT(slot2slot, list("head" = SLOT_HEAD, "wear_mask" = SLOT_WEAR_MASK, "neck" = SLOT_NECK, "back" = SLOT_BACK, "wear_suit" = SLOT_WEAR_SUIT, "w_uniform" = SLOT_W_UNIFORM, "shoes" = SLOT_SHOES, "belt" = SLOT_BELT, "gloves" = SLOT_GLOVES, "glasses" = SLOT_GLASSES, "ears" = SLOT_EARS, "wear_id" = SLOT_WEAR_ID, "s_store" = SLOT_S_STORE))
GLOBAL_LIST_INIT(slot2slot, list("head" = ITEM_SLOT_HEAD, "wear_mask" = ITEM_SLOT_MASK, "neck" = ITEM_SLOT_NECK, "back" = ITEM_SLOT_BACK, "wear_suit" = ITEM_SLOT_OCLOTHING, "w_uniform" = ITEM_SLOT_ICLOTHING, "shoes" = ITEM_SLOT_FEET, "belt" = ITEM_SLOT_BELT, "gloves" = ITEM_SLOT_GLOVES, "glasses" = ITEM_SLOT_EYES, "ears" = ITEM_SLOT_EARS, "wear_id" = ITEM_SLOT_ID, "s_store" = ITEM_SLOT_SUITSTORE))
GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "wear_mask" = /obj/item/clothing/mask/changeling, "back" = /obj/item/changeling, "wear_suit" = /obj/item/clothing/suit/changeling, "w_uniform" = /obj/item/clothing/under/changeling, "shoes" = /obj/item/clothing/shoes/changeling, "belt" = /obj/item/changeling, "gloves" = /obj/item/clothing/gloves/changeling, "glasses" = /obj/item/clothing/glasses/changeling, "ears" = /obj/item/changeling, "wear_id" = /obj/item/changeling, "s_store" = /obj/item/changeling))
GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our this objective to all lings
+2 -2
View File
@@ -205,11 +205,11 @@ Credit where due:
var/mob/living/carbon/human/L = M
var/obj/item/clockwork/slab/S = new
var/slot = "At your feet"
var/list/slots = list("In your left pocket" = SLOT_L_STORE, "In your right pocket" = SLOT_R_STORE, "In your backpack" = SLOT_IN_BACKPACK)
var/list/slots = list("In your left pocket" = ITEM_SLOT_LPOCKET, "In your right pocket" = ITEM_SLOT_RPOCKET, "In your backpack" = ITEM_SLOT_BACKPACK)
if(ishuman(L))
var/mob/living/carbon/human/H = L
var/obj/item/clockwork/replica_fabricator/F = new
if(H.equip_to_slot_or_del(F, SLOT_IN_BACKPACK))
if(H.equip_to_slot_or_del(F, ITEM_SLOT_BACKPACK))
to_chat(H, "<span class='brass'>You have been equipped with a replica fabricator, an advanced tool that can convert objects like doors, tables or even coats into clockwork equivalents.</span>")
slot = H.equip_in_one_of_slots(S, slots)
if(slot == "In your backpack")
@@ -37,17 +37,17 @@
if(!H.w_uniform || H.dropItemToGround(H.w_uniform))
C = new /obj/item/clothing/under/rank/civilian/clown(H)
ADD_TRAIT(C, TRAIT_NODROP, CLOWN_NUKE_TRAIT)
H.equip_to_slot_or_del(C, SLOT_W_UNIFORM)
H.equip_to_slot_or_del(C, ITEM_SLOT_ICLOTHING)
if(!H.shoes || H.dropItemToGround(H.shoes))
C = new /obj/item/clothing/shoes/clown_shoes(H)
ADD_TRAIT(C, TRAIT_NODROP, CLOWN_NUKE_TRAIT)
H.equip_to_slot_or_del(C, SLOT_SHOES)
H.equip_to_slot_or_del(C, ITEM_SLOT_FEET)
if(!H.wear_mask || H.dropItemToGround(H.wear_mask))
C = new /obj/item/clothing/mask/gas/clown_hat(H)
ADD_TRAIT(C, TRAIT_NODROP, CLOWN_NUKE_TRAIT)
H.equip_to_slot_or_del(C, SLOT_WEAR_MASK)
H.equip_to_slot_or_del(C, ITEM_SLOT_MASK)
H.dna.add_mutation(CLOWNMUT)
H.dna.add_mutation(SMILE)
@@ -214,7 +214,7 @@
if(!istype(C.wear_mask, /obj/item/clothing/mask/gas/clown_hat) && !istype(C.wear_mask, /obj/item/clothing/mask/gas/mime))
if(!C.wear_mask || C.dropItemToGround(C.wear_mask))
var/obj/item/clothing/mask/fakemoustache/sticky/the_stash = new /obj/item/clothing/mask/fakemoustache/sticky()
C.equip_to_slot_or_del(the_stash, SLOT_WEAR_MASK, TRUE, TRUE, TRUE, TRUE)
C.equip_to_slot_or_del(the_stash, ITEM_SLOT_MASK, TRUE, TRUE, TRUE, TRUE)
/obj/item/clothing/mask/fakemoustache/sticky
var/unstick_time = 2 MINUTES
@@ -226,7 +226,7 @@
/obj/item/clothing/mask/fakemoustache/sticky/equipped(mob/user, slot)
. = ..()
if(slot == SLOT_WEAR_MASK)
if(slot == ITEM_SLOT_MASK)
ADD_TRAIT(user, TRAIT_NO_INTERNALS, STICKY_MOUSTACHE_TRAIT)
/obj/item/clothing/mask/fakemoustache/sticky/dropped(mob/user)
+3 -3
View File
@@ -154,7 +154,7 @@
if(tc)
var/obj/item/U = new uplink_type(H, H.key, tc)
H.equip_to_slot_or_del(U, SLOT_IN_BACKPACK)
H.equip_to_slot_or_del(U, ITEM_SLOT_BACKPACK)
var/obj/item/implant/weapons_auth/W = new
W.implant(H)
@@ -170,7 +170,7 @@
mask = /obj/item/clothing/mask/gas/syndicate
suit = /obj/item/clothing/suit/space/hardsuit/syndi
r_pocket = /obj/item/tank/internals/emergency_oxygen/engi
internals_slot = SLOT_R_STORE
internals_slot = ITEM_SLOT_RPOCKET
belt = /obj/item/storage/belt/military
r_hand = /obj/item/gun/ballistic/automatic/shotgun/bulldog
backpack_contents = list(/obj/item/storage/box/survival/syndie=1,\
@@ -186,7 +186,7 @@
suit = /obj/item/clothing/suit/space/syndicate/black/red
head = /obj/item/clothing/head/helmet/space/syndicate/black/red
r_pocket = /obj/item/tank/internals/emergency_oxygen/engi
internals_slot = SLOT_R_STORE
internals_slot = ITEM_SLOT_RPOCKET
belt = /obj/item/storage/belt/military
backpack_contents = list(/obj/item/storage/box/survival/syndie=1,\
/obj/item/tank/jetpack/oxygen/harness=1,\
+2 -2
View File
@@ -165,7 +165,7 @@ If not set, defaults to check_completion instead. Set it. It's used by cryo.
if(receiver && receiver.current)
if(ishuman(receiver.current))
var/mob/living/carbon/human/H = receiver.current
var/list/slots = list("backpack" = SLOT_IN_BACKPACK)
var/list/slots = list("backpack" = ITEM_SLOT_BACKPACK)
for(var/eq_path in special_equipment)
var/obj/O = new eq_path
. += O
@@ -1197,7 +1197,7 @@ GLOBAL_LIST_EMPTY(cult_contraband)
I.forceMove(get_turf(owner))
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
H.equip_in_one_of_slots(I, list("backpack" = SLOT_IN_BACKPACK), critical = TRUE)
H.equip_in_one_of_slots(I, list("backpack" = ITEM_SLOT_BACKPACK), critical = TRUE)
hoarded_item = I
+3 -3
View File
@@ -102,7 +102,7 @@
rad_insulation = RAD_MEDIUM_INSULATION
var/static/list/airlock_overlays = list()
/// sigh
var/unelectrify_timerid
@@ -1278,8 +1278,8 @@
assemblytype = /obj/structure/door_assembly/door_assembly_extmai
update_icon()
/obj/machinery/door/airlock/CanAStarPass(obj/item/card/id/ID)
//Airlock is passable if it is open (!density), bot has access, and is not bolted shut or powered off)
/obj/machinery/door/airlock/CanAStarPass(obj/item/card/id/ID, to_dir, atom/movable/caller)
//Airlock is passable if it is open (!density), bot has access, and is not bolted shut or powered off)
return !density || (check_access(ID) && !locked && hasPower())
/obj/machinery/door/airlock/emag_act(mob/user)
+102 -21
View File
@@ -52,23 +52,30 @@
/obj/machinery/limbgrower/ui_data(mob/user)
var/list/data = list()
for(var/datum/reagent/reagent_id in reagents.reagent_list)
var/list/reagent_data = list(
reagent_name = reagent_id.name,
reagent_amount = reagent_id.volume,
reagent_type = reagent_id.type
)
data["reagents"] += list(reagent_data)
if(reagents.reagent_list.len)
for(var/datum/reagent/reagent_id in reagents.reagent_list)
var/list/reagent_data = list(
reagent_name = reagent_id.name,
reagent_amount = reagent_id.volume,
reagent_type = reagent_id.type
)
data["reagents"] += list(reagent_data)
else
data["reagents"] = list()
data["total_reagents"] = reagents.total_volume
data["max_reagents"] = reagents.maximum_volume
data["busy"] = busy
var/list/disk_data = list()
disk_data["disk"] = dna_disk //Do i, the machine, have a disk?
disk_data["name"] = dna_disk?.fields["name"] //Name for the human saved if there is one
if(dna_disk)
if(dna_disk.fields["name"])
disk_data["name"] = dna_disk.fields["name"]
else if(dna_disk.genetic_makeup_buffer["name"])
disk_data["name"] = dna_disk.genetic_makeup_buffer["name"]
else
disk_data["name"] = "No name"
//Name for the human saved if there is one
data["disk"] = disk_data
return data
/obj/machinery/limbgrower/ui_static_data(mob/user)
@@ -119,6 +126,18 @@
if (busy)
to_chat(user, "<span class=\"alert\">\The [src] is busy. Please wait for completion of previous operation.</span>")
return
if(ispath(user_item.type, /obj/item/reagent_containers/blood) && user.a_intent != INTENT_HARM)
var/obj/item/reagent_containers/blood/B = user_item
if(!B.reagents.get_reagents())
to_chat(user, "<span class=\"alert\">You can't fill [src] with an empty [B.name]!</span>")
return
if(reagents.total_volume == reagents.maximum_volume)
to_chat(user, "<span class=\"alert\">\The [src] can't hold more blood!</span>")
return
user.visible_message("<span class='notice'>[user] drains the [user_item] into [src] using the blood bag port on [src].</span>",
"You drain the [user_item] into [src] using the blood bag port.")
B.reagents.trans_to(src, B.amount_per_transfer_from_this)
return
if(default_deconstruction_screwdriver(user, "limbgrower_panelopen", "limbgrower_idleoff", user_item))
ui_close(user)
@@ -180,7 +199,7 @@
for(var/reagent_id in consumed_reagents_list)
consumed_reagents_list[reagent_id] *= production_coefficient
if(!reagents.has_reagent(reagent_id, consumed_reagents_list[reagent_id]))
audible_message("<span class='notice'>\The [src] buzzes.</span>")
audible_message("<span class='warning'>\The [src] buzzes and states \"INSUFFICENT REAGENTS\"</span>")
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
return
@@ -206,17 +225,13 @@
* modified_consumed_reagents_list - the list of reagents we will consume on build, modified by the production coefficient.
*/
/obj/machinery/limbgrower/proc/build_item(list/modified_consumed_reagents_list)
for(var/reagent_id in modified_consumed_reagents_list)
if(!reagents.has_reagent(reagent_id, modified_consumed_reagents_list[reagent_id]))
audible_message("<span class='notice'>\The [src] buzzes.</span>")
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
break
reagents.remove_reagent(reagent_id, modified_consumed_reagents_list[reagent_id])
reagent_usage(modified_consumed_reagents_list)
var/built_typepath = being_built.build_path
// If we have a bodypart, we need to initialize the limb on its own. Otherwise we can build it here.
if(ispath(built_typepath, /obj/item/bodypart))
if(ispath(built_typepath, /mob/living/carbon/human/chestonly))
if(!build_mob_chest(built_typepath, FALSE))
reagent_usage(modified_consumed_reagents_list, FALSE)
else if(ispath(built_typepath, /obj/item/bodypart))
build_limb(built_typepath)
else if(ispath(built_typepath, /obj/item/organ/genital)) //genitals are uhh... customizable
build_genital(built_typepath)
@@ -227,6 +242,25 @@
flick("limbgrower_unfill", src)
icon_state = "limbgrower_idleoff"
/obj/machinery/limbgrower/proc/reagent_usage(modified_consumed_reagents_list, remove = TRUE)
// Apparently, having a boolean in a loop is worse than doing it twice
if(remove)
for(var/reagent_id in modified_consumed_reagents_list)
if(reagent_sanity_check(reagent_id, modified_consumed_reagents_list[reagent_id]))
reagents.remove_reagent(reagent_id, modified_consumed_reagents_list[reagent_id])
else
for(var/reagent_id in modified_consumed_reagents_list)
if(reagent_sanity_check(reagent_id, modified_consumed_reagents_list[reagent_id]))
reagents.add_reagent(reagent_id, modified_consumed_reagents_list[reagent_id])
/obj/machinery/limbgrower/proc/reagent_sanity_check(reagent_id, amount)
if(reagents.has_reagent(reagent_id, amount))
return TRUE
audible_message("<span class='warning'>\The [src] buzzes, with a screen showing: INSUFFICENT REAGENTS</span>")
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
return FALSE
/*
* The process of putting together a limb.
* This is called from after we remove the reagents, so this proc is just initializing the limb type.
@@ -306,6 +340,53 @@
else
new built_typepath(loc)
/obj/machinery/limbgrower/proc/build_mob_chest(built_typepath)
// Create a mob with a chest, but nothing else
if(!ispath(built_typepath, /mob/living/carbon/human/chestonly))
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
visible_message(src, "Buzzes, an error screen appearing on its display.")
return FALSE
// Fields is from cloning, a much fuller scan, genetic_makeup_buffer is less so
var/dna_genetics = dna_disk?.genetic_makeup_buffer
var/dna_cloning = dna_disk?.fields
var/datum/species/selected = GLOB.species_datums[selected_category]
var/mob/living/carbon/human/chestonly/C = new(loc)
C.real_name = length(dna_genetics) ? dna_genetics["name"] : "Synthetic Humanoid #[rand(10000, 99999)]"
if(length(dna_cloning))
C.hardset_dna(dna_cloning["UI"], dna_cloning["SE"], dna_cloning["name"], dna_cloning["blood_type"], dna_cloning["mrace"], dna_cloning["features"])
else if(length(dna_genetics))
C.hardset_dna(dna_genetics["UI"], null, dna_genetics["name"], dna_genetics["blood_type"])
else
C.real_name = "Synthetic Humanoid #[rand(10000, 99999)]"
C.hair_style = "bald"
C.skin_tone = "albino"
C.set_species(selected)
C.set_resting(TRUE, TRUE)
// Don't want to cause it to deathgasp..
C.stat = DEAD
C.adjustOxyLoss(200)
// Limb replacement causes toxloss, which can cause too much suffering for the doctor that I don't want
C.adjustCloneLoss(45)
C.med_hud_set_status()
C.med_hud_set_health()
C.underwear = "Nude"
C.undershirt = "Nude"
C.saved_underwear = ""
C.saved_undershirt = ""
// Just enough to start reviving them, I hope
C.blood_volume = BLOOD_VOLUME_SURVIVE
// At some point, make a way to deal with species regenerate_organs
// Remove all the organs
for(var/organ in C.internal_organs)
var/obj/item/organ/O = organ
O.Remove(organ)
C.update_body(TRUE)
C.update_hair()
C.update_body_parts()
C.update_appearance()
return TRUE
/obj/machinery/limbgrower/RefreshParts()
reagents.maximum_volume = 0
for(var/obj/item/reagent_containers/glass/our_beaker in component_parts)
+4 -4
View File
@@ -351,7 +351,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
return
if(anchored)
return
if(loc == user && current_equipped_slot && current_equipped_slot != SLOT_HANDS)
if(loc == user && current_equipped_slot && current_equipped_slot != ITEM_SLOT_HANDS)
if(current_equipped_slot in user.check_obscured_slots())
to_chat(user, "<span class='warning'>You are unable to unequip that while wearing other garments over it!</span>")
return FALSE
@@ -416,7 +416,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
return
if(anchored)
return
if(loc == user && current_equipped_slot && current_equipped_slot != SLOT_HANDS)
if(loc == user && current_equipped_slot && current_equipped_slot != ITEM_SLOT_HANDS)
if(current_equipped_slot in user.check_obscured_slots())
to_chat(user, "<span class='warning'>You are unable to unequip that while wearing other garments over it!</span>")
return FALSE
@@ -568,7 +568,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
//sometimes we only want to grant the item's action if it's equipped in a specific slot.
/obj/item/proc/item_action_slot_check(slot, mob/user, datum/action/A)
if(slot == SLOT_IN_BACKPACK || slot == SLOT_LEGCUFFED) //these aren't true slots, so avoid granting actions there
if(slot == ITEM_SLOT_BACKPACK || slot == ITEM_SLOT_LEGCUFFED) //these aren't true slots, so avoid granting actions there
return FALSE
return TRUE
@@ -817,7 +817,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
if(ismob(location))
var/mob/M = location
var/success = FALSE
if(src == M.get_item_by_slot(SLOT_WEAR_MASK))
if(src == M.get_item_by_slot(ITEM_SLOT_MASK))
success = TRUE
if(success)
location = get_turf(M)
+1 -1
View File
@@ -34,7 +34,7 @@
user.put_in_hands(PA)
/obj/item/chrono_eraser/item_action_slot_check(slot, mob/user, datum/action/A)
if(slot == SLOT_BACK)
if(slot == ITEM_SLOT_BACK)
return 1
/obj/item/gun/energy/chrono_gun
+4 -4
View File
@@ -89,7 +89,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
..()
/obj/item/proc/help_light_cig(mob/living/M)
var/mask_item = M.get_item_by_slot(SLOT_WEAR_MASK)
var/mask_item = M.get_item_by_slot(ITEM_SLOT_MASK)
if(istype(mask_item, /obj/item/clothing/mask/cigarette))
return mask_item
@@ -130,7 +130,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
reagents.add_reagent_list(list_reagents)
if(starts_lit)
light()
AddComponent(/datum/component/knockoff,90,list(BODY_ZONE_PRECISE_MOUTH),list(SLOT_WEAR_MASK))//90% to knock off when wearing a mask
AddComponent(/datum/component/knockoff,90,list(BODY_ZONE_PRECISE_MOUTH),list(ITEM_SLOT_MASK))//90% to knock off when wearing a mask
/obj/item/clothing/mask/cigarette/Destroy()
STOP_PROCESSING(SSobj, src)
@@ -819,7 +819,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/clothing/mask/vape/equipped(mob/user, slot)
. = ..()
if(slot == SLOT_WEAR_MASK)
if(slot == ITEM_SLOT_MASK)
if(!screw)
to_chat(user, "<span class='notice'>You start puffing on the vape.</span>")
reagents.reagents_holder_flags &= ~(NO_REACT)
@@ -830,7 +830,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/clothing/mask/vape/dropped(mob/user)
. = ..()
var/mob/living/carbon/C = user
if(C.get_item_by_slot(SLOT_WEAR_MASK) == src)
if(C.get_item_by_slot(ITEM_SLOT_MASK) == src)
reagents.reagents_holder_flags |= NO_REACT
STOP_PROCESSING(SSobj, src)
+4 -4
View File
@@ -80,13 +80,13 @@
/obj/item/defibrillator/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(loc == user)
if(slot_flags == ITEM_SLOT_BACK)
if(user.get_item_by_slot(SLOT_BACK) == src)
if(user.get_item_by_slot(ITEM_SLOT_BACK) == src)
ui_action_click()
else
to_chat(user, "<span class='warning'>Put the defibrillator on your back first!</span>")
else if(slot_flags == ITEM_SLOT_BELT)
if(user.get_item_by_slot(SLOT_BELT) == src)
if(user.get_item_by_slot(ITEM_SLOT_BELT) == src)
ui_action_click()
else
to_chat(user, "<span class='warning'>Strap the defibrillator's belt on first!</span>")
@@ -182,7 +182,7 @@
/obj/item/defibrillator/equipped(mob/user, slot)
..()
if((slot_flags == ITEM_SLOT_BACK && slot != SLOT_BACK) || (slot_flags == ITEM_SLOT_BELT && slot != SLOT_BELT))
if((slot_flags == ITEM_SLOT_BACK && slot != ITEM_SLOT_BACK) || (slot_flags == ITEM_SLOT_BELT && slot != ITEM_SLOT_BELT))
remove_paddles(user)
update_power()
@@ -423,7 +423,7 @@
if((!req_defib && grab_ghost) || (req_defib && defib.grab_ghost))
H.notify_ghost_cloning("Your heart is being defibrillated!")
H.grab_ghost() // Shove them back in their body.
else if(H.can_defib())
else if(H.can_revive())
H.notify_ghost_cloning("Your heart is being defibrillated. Re-enter your corpse if you want to be revived!", source = src)
do_help(H, user)
@@ -369,6 +369,10 @@ GLOBAL_LIST_EMPTY(PDAs)
dat += "<li><a href='byond://?src=[REF(src)];choice=Toggle Door'>[PDAIMG(rdoor)]Toggle Remote Door</a></li>"
if (cartridge.access & CART_DRONEPHONE)
dat += "<li><a href='byond://?src=[REF(src)];choice=Drone Phone'>[PDAIMG(dronephone)]Drone Phone</a></li>"
if (cartridge.access & CART_BARTENDER)
dat += "<li><a href='byond://?src=[REF(src)];choice=Drink Recipe Browser'>[PDAIMG(bucket)]Drink Recipe Browser</a></li>"
if (cartridge.access & CART_CHEMISTRY)
dat += "<li><a href='byond://?src=[REF(src)];choice=Chemistry Recipe Browser'>[PDAIMG(bucket)]Chemistry Recipe Browser</a></li>"
dat += "<li><a href='byond://?src=[REF(src)];choice=3'>[PDAIMG(atmos)]Atmospheric Scan</a></li>"
dat += "<li><a href='byond://?src=[REF(src)];choice=Light'>[PDAIMG(flashlight)][fon ? "Disable" : "Enable"] Flashlight</a></li>"
if (pai)
@@ -705,6 +709,16 @@ GLOBAL_LIST_EMPTY(PDAs)
if(T)
pai.forceMove(T)
//DRINK RECIPE BROWSER=============================
if("Drink Recipe Browser")
if(cartridge && cartridge.access & CART_BARTENDER)
recipe_search(U, GLOB.drink_reactions_list)
//CHEMISTRY RECIPE BROWSER
if("Chemistry Recipe Browser")
if(cartridge && cartridge.access & CART_CHEMISTRY)
recipe_search(U, GLOB.normalized_chemical_reactions_list)
//LINK FUNCTIONS===================================
else//Cartridge menu linking
@@ -222,6 +222,7 @@
/obj/item/pda/bar
name = "bartender PDA"
icon_state = "pda-bartender"
default_cartridge = /obj/item/cartridge/bartender
inserted_item = /obj/item/pen/fountain
/obj/item/pda/atmos
+9 -1
View File
@@ -13,6 +13,8 @@
#define CART_QUARTERMASTER (1<<12)
#define CART_HYDROPONICS (1<<13)
#define CART_DRONEPHONE (1<<14)
#define CART_BARTENDER (1<<15)
#define CART_CHEMISTRY (1<<16)
/obj/item/cartridge
@@ -77,7 +79,7 @@
/obj/item/cartridge/chemistry
name = "\improper ChemWhiz cartridge"
icon_state = "cart-chem"
access = CART_REAGENT_SCANNER
access = CART_REAGENT_SCANNER | CART_CHEMISTRY
bot_access_flags = MED_BOT
/obj/item/cartridge/security
@@ -190,6 +192,12 @@
bot_access_flags = SEC_BOT | MULE_BOT | FLOOR_BOT | CLEAN_BOT | MED_BOT | FIRE_BOT
spam_enabled = 1
/obj/item/cartridge/bartender
name = "\improper B.O.O.Z.E cartridge"
desc = "Now with 12% alcohol!"
icon_state = "cart-bar"
access = CART_BARTENDER
/obj/item/cartridge/captain/New()
..()
radio = new(src)
+1 -1
View File
@@ -19,7 +19,7 @@
/obj/item/megaphone/equipped(mob/M, slot)
. = ..()
if (slot == SLOT_HANDS)
if (slot == ITEM_SLOT_HANDS)
RegisterSignal(M, COMSIG_MOB_SAY, .proc/handle_speech)
else
UnregisterSignal(M, COMSIG_MOB_SAY)
@@ -156,7 +156,7 @@
category = list("hacked", "Misc")
/obj/item/electropack/shockcollar/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(loc == user && user.get_item_by_slot(SLOT_NECK))
if(loc == user && user.get_item_by_slot(ITEM_SLOT_NECK))
to_chat(user, "<span class='warning'>The collar is fastened tight! You'll need help taking this off!</span>")
return
return ..()
@@ -167,7 +167,7 @@
if(isliving(loc) && on) //the "on" arg is currently useless
var/mob/living/L = loc
if(!L.get_item_by_slot(SLOT_NECK)) //**properly** stops pocket shockers
if(!L.get_item_by_slot(ITEM_SLOT_NECK)) //**properly** stops pocket shockers
return
if(shock_cooldown == TRUE)
return
@@ -56,7 +56,7 @@ GLOBAL_LIST_INIT(channel_tokens, list(
/obj/item/radio/headset/ComponentInitialize()
. = ..()
if (bowman)
AddComponent(/datum/component/wearertargeting/earprotection, list(SLOT_EARS))
AddComponent(/datum/component/wearertargeting/earprotection, list(ITEM_SLOT_EARS))
/obj/item/radio/headset/Initialize()
. = ..()
@@ -373,4 +373,4 @@ GLOBAL_LIST_INIT(channel_tokens, list(
name = replacetext(name,"headset", "bowman headset")
desc = "[desc] Protects ears from flashbangs."
bowman = TRUE
AddComponent(/datum/component/wearertargeting/earprotection, list(SLOT_EARS))
AddComponent(/datum/component/wearertargeting/earprotection, list(ITEM_SLOT_EARS))
@@ -48,7 +48,7 @@
/obj/item/reverse_bear_trap/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(iscarbon(user))
var/mob/living/carbon/C = user
if(C.get_item_by_slot(SLOT_HEAD) == src)
if(C.get_item_by_slot(ITEM_SLOT_HEAD) == src)
if(HAS_TRAIT_FROM(src, TRAIT_NODROP, REVERSE_BEAR_TRAP_TRAIT) && !struggling)
struggling = TRUE
var/fear_string
@@ -82,26 +82,26 @@
..()
/obj/item/reverse_bear_trap/attack(mob/living/target, mob/living/user)
if(target.get_item_by_slot(SLOT_HEAD))
if(target.get_item_by_slot(ITEM_SLOT_HEAD))
to_chat(user, "<span class='warning'>Remove [target.p_their()] headgear first!</span>")
return
target.visible_message("<span class='warning'>[user] starts forcing [src] onto [target]'s head!</span>", \
"<span class='userdanger'>[target] starts forcing [src] onto your head!</span>", "<i>You hear clanking.</i>")
to_chat(user, "<span class='danger'>You start forcing [src] onto [target]'s head...</span>")
if(!do_after(user, 30, target = target) || target.get_item_by_slot(SLOT_HEAD))
if(!do_after(user, 30, target = target) || target.get_item_by_slot(ITEM_SLOT_HEAD))
return
target.visible_message("<span class='warning'>[user] forces and locks [src] onto [target]'s head!</span>", \
"<span class='userdanger'>[target] locks [src] onto your head!</span>", "<i>You hear a click, and then a timer ticking down.</i>")
to_chat(user, "<span class='danger'>You force [src] onto [target]'s head and click the padlock shut.</span>")
user.dropItemToGround(src)
target.equip_to_slot_if_possible(src, SLOT_HEAD)
target.equip_to_slot_if_possible(src, ITEM_SLOT_HEAD)
arm()
notify_ghosts("[user] put a reverse bear trap on [target]!", source = src, action = NOTIFY_ORBIT, ghost_sound = 'sound/machines/beep.ogg')
/obj/item/reverse_bear_trap/proc/snap()
reset()
var/mob/living/carbon/human/H = loc
if(!istype(H) || H.get_item_by_slot(SLOT_HEAD) != src)
if(!istype(H) || H.get_item_by_slot(ITEM_SLOT_HEAD) != src)
visible_message("<span class='warning'>[src]'s jaws snap open with an ear-piercing crack!</span>")
playsound(src, 'sound/effects/snap.ogg', 75, TRUE)
else
+3 -1
View File
@@ -380,6 +380,8 @@ GENETICS SCANNER
mutant = TRUE
else if (S.mutantstomach != initial(S.mutantstomach))
mutant = TRUE
else if (S.flying_species != initial(S.flying_species))
mutant = TRUE
msg += "\t<span class='info'>Reported Species: [H.spec_trait_examine_font()][H.dna.custom_species ? H.dna.custom_species : S.name]</font></span>\n"
msg += "\t<span class='info'>Base Species: [H.spec_trait_examine_font()][S.name]</font></span>\n"
@@ -434,7 +436,7 @@ GENETICS SCANNER
if(R)
blood_type = R.name
if((C.scan_blood_volume() + C.integrating_blood) <= (BLOOD_VOLUME_SAFE * C.blood_ratio) && (C.scan_blood_volume() + C.integrating_blood) > (BLOOD_VOLUME_OKAY*C.blood_ratio))
msg += "<span class='danger'>LOW [HAS_TRAIT(C, TRAIT_ROBOTIC_ORGANISM) ? "coolant" : "blood"] level [blood_percent] %, [C.scan_blood_volume()] cl[C.integrating_blood? ", with [integrated_blood_percent] % of it integrating, [C.integrating_blood] cl " : ""].</span> <span class='info'>type: [blood_type]</span>\n"
else if((C.scan_blood_volume() + C.integrating_blood) <= (BLOOD_VOLUME_OKAY * C.blood_ratio))
@@ -208,7 +208,7 @@ effective or pretty fucking useless.
actions_types = list(/datum/action/item_action/toggle)
/obj/item/shadowcloak/ui_action_click(mob/user)
if(user.get_item_by_slot(SLOT_BELT) == src)
if(user.get_item_by_slot(ITEM_SLOT_BELT) == src)
if(!on)
Activate(usr)
else
@@ -216,7 +216,7 @@ effective or pretty fucking useless.
return
/obj/item/shadowcloak/item_action_slot_check(slot, mob/user, datum/action/A)
if(slot == SLOT_BELT)
if(slot == ITEM_SLOT_BELT)
return 1
/obj/item/shadowcloak/proc/Activate(mob/living/carbon/human/user)
@@ -238,11 +238,11 @@ effective or pretty fucking useless.
/obj/item/shadowcloak/dropped(mob/user)
..()
if(user && user.get_item_by_slot(SLOT_BELT) != src)
if(user && user.get_item_by_slot(ITEM_SLOT_BELT) != src)
Deactivate()
/obj/item/shadowcloak/process()
if(user.get_item_by_slot(SLOT_BELT) != src)
if(user.get_item_by_slot(ITEM_SLOT_BELT) != src)
Deactivate()
return
var/turf/T = get_turf(src)
+1 -1
View File
@@ -6,7 +6,7 @@
// 1) Tennis balls, lines 39 - 99
// 2) Chew bones, lines 101 - 138
// 3) Frisbee, lines 140 - 166
*/
*/
/obj/item/toy/fluff
name = "Fluff Item"
+1 -1
View File
@@ -336,7 +336,7 @@
var/obj/item/clothing/magichead = new /obj/item/clothing/mask/horsehead/cursed(user.drop_location())
if(!user.dropItemToGround(user.wear_mask))
qdel(user.wear_mask)
user.equip_to_slot_if_possible(magichead, SLOT_WEAR_MASK, TRUE, TRUE)
user.equip_to_slot_if_possible(magichead, ITEM_SLOT_MASK, TRUE, TRUE)
qdel(src)
else
to_chat(user,"<span class='notice'>I say thee neigh</span>") //It still lives here
@@ -189,5 +189,7 @@
return FALSE
brainwash(C, objective)
message_admins("[ADMIN_LOOKUPFLW(user)] brainwashed [key_name_admin(C)] with objective '[objective]'.")
user.log_message("has brainwashed [key_name(C)] with the objective '[objective]' using \the [src]", LOG_ATTACK)
C.log_message("has been brainwashed with the objective '[objective]' by [key_name(user)] using \the [src]", LOG_VICTIM, log_globally = FALSE)
log_game("[key_name(user)] brainwashed [key_name(C)] with objective '[objective]'.")
return TRUE
+1 -1
View File
@@ -188,7 +188,7 @@
icon_state = "inducer-combat"
item_state = "inducer-combat"
w_class = WEIGHT_CLASS_BULKY
slot_flags = SLOT_BELT
slot_flags = ITEM_SLOT_BELT
desc = "A tool for inductively charging internal power cells. This one has been modified and upgraded to be able to charge into guns as well as normal electronics."
cell_type = /obj/item/stock_parts/cell/hyper
powertransfer = 1300

Some files were not shown because too many files have changed in this diff Show More