mirror of
https://github.com/quotefox/Hyper-Station-13.git
synced 2026-08-30 16:16:15 +01:00
Merge branch 'master' into fairylights
This commit is contained in:
@@ -736,6 +736,9 @@
|
||||
///from datum/action/cyborg_small_sprite and sends when a cyborg changes modules
|
||||
#define COMSIG_CYBORG_MODULE_CHANGE "cyborg_module_change"
|
||||
|
||||
// /datum/element/ventcrawling signals
|
||||
#define COMSIG_HANDLE_VENTCRAWL "handle_ventcrawl" //when atom with ventcrawling element attempts to ventcrawl
|
||||
#define COMSIG_CHECK_VENTCRAWL "check_ventcrawl" //to check an atom's ventcrawling element tier (if applicable)
|
||||
|
||||
/* Attack signals. They should share the returned flags, to standardize the attack chain. */
|
||||
/// tool_act -> pre_attack -> target.attackby (item.attack) -> afterattack
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#define BELLY_MIN_SIZE 0
|
||||
#define BELLY_MAX_SIZE 8
|
||||
|
||||
#define BELLY_STRAIN_SIZE 3 // for flavor text
|
||||
#define BELLY_STRETCH_SIZE 6 // for flavor text
|
||||
|
||||
#define BUTT_MIN_SIZE 0
|
||||
#define BUTT_MAX_SIZE 5
|
||||
@@ -285,3 +285,7 @@
|
||||
#define HUMAN_CARRY_SLOWDOWN 0
|
||||
|
||||
#define TYPING_INDICATOR_TIMEOUT 10 MINUTES
|
||||
|
||||
//Gremlins
|
||||
#define NPC_TAMPER_ACT_FORGET 1 //Don't try to tamper with this again
|
||||
#define NPC_TAMPER_ACT_NOMSG 2 //Don't produce a visible message
|
||||
|
||||
@@ -36,6 +36,7 @@ Ask ninjanomnom if they're around
|
||||
#define RAD_MEDIUM_INSULATION 0.7 // What common walls have
|
||||
#define RAD_HEAVY_INSULATION 0.6 // What reinforced walls have
|
||||
#define RAD_EXTREME_INSULATION 0.5 // What rad collectors have
|
||||
#define RAD_NEAR_FULL_INSULATION 0.2 // What radiation shutters and specialised walls for the RBMK use.
|
||||
#define RAD_FULL_INSULATION 0 // Unused
|
||||
|
||||
// WARNING: The deines below could have disastrous consequences if tweaked incorrectly. See: The great SM purge of Oct.6.2017
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
#define SPAN_COMMAND "command_headset"
|
||||
#define SPAN_CLOWN "clown"
|
||||
#define SPAN_SINGING "singing"
|
||||
#define SPAN_SMALL "small"
|
||||
|
||||
//bitflag #defines for return value of the radio() proc.
|
||||
#define ITALICS 1
|
||||
|
||||
@@ -206,6 +206,8 @@
|
||||
|
||||
#define TRAIT_ZAOCORP_NOGUNS "zao_no_guns"
|
||||
|
||||
#define INNATE_TRAIT "innate"
|
||||
|
||||
// common trait sources
|
||||
#define TRAIT_GENERIC "generic"
|
||||
#define EYE_DAMAGE "eye_damage"
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#define MAXIMUM_MARKOV_LENGTH 25000
|
||||
|
||||
/proc/markov_chain(var/text, var/order = 4, var/length = 250)
|
||||
if(!text || order < 0 || order > 20 || length < 1 || length > MAXIMUM_MARKOV_LENGTH)
|
||||
return
|
||||
|
||||
var/table = markov_table(text, order)
|
||||
var/markov = markov_text(length, table, order)
|
||||
return markov
|
||||
|
||||
/proc/markov_table(var/text, var/look_forward = 4)
|
||||
if(!text)
|
||||
return
|
||||
var/list/table = list()
|
||||
|
||||
for(var/i = 1, i <= length(text), i++)
|
||||
var/char = copytext(text, i, look_forward+i)
|
||||
if(!table[char])
|
||||
table[char] = list()
|
||||
|
||||
for(var/i = 1, i <= (length(text) - look_forward), i++)
|
||||
var/char_index = copytext(text, i, look_forward+i)
|
||||
var/char_count = copytext(text, i+look_forward, (look_forward*2)+i)
|
||||
|
||||
if(table[char_index][char_count])
|
||||
table[char_index][char_count]++
|
||||
else
|
||||
table[char_index][char_count] = 1
|
||||
|
||||
return table
|
||||
|
||||
/proc/markov_text(var/length = 250, var/table, var/look_forward = 4)
|
||||
if(!table)
|
||||
return
|
||||
var/char = pick(table)
|
||||
var/o = char
|
||||
|
||||
for(var/i = 0, i <= (length / look_forward), i++)
|
||||
var/newchar = markov_weighted_char(table[char])
|
||||
|
||||
if(newchar)
|
||||
char = newchar
|
||||
o += "[newchar]"
|
||||
else
|
||||
char = pick(table)
|
||||
|
||||
return o
|
||||
|
||||
/proc/markov_weighted_char(var/list/array)
|
||||
if(!array || !array.len)
|
||||
return
|
||||
|
||||
var/total = 0
|
||||
for(var/i in array)
|
||||
total += array[i]
|
||||
var/r = rand(1, total)
|
||||
for(var/i in array)
|
||||
var/weight = array[i]
|
||||
if(r <= weight)
|
||||
return i
|
||||
r -= weight
|
||||
@@ -1109,7 +1109,7 @@ B --><-- A
|
||||
|
||||
/proc/get_random_station_turf()
|
||||
return safepick(get_area_turfs(pick(GLOB.the_station_areas)))
|
||||
|
||||
|
||||
/proc/get_safe_random_station_turf()
|
||||
for (var/i in 1 to 5)
|
||||
var/list/L = get_area_turfs(pick(GLOB.the_station_areas))
|
||||
@@ -1273,6 +1273,14 @@ GLOBAL_REAL_VAR(list/stack_trace_storage)
|
||||
animate(src, transform = M, time = halftime, easing = ELASTIC_EASING)
|
||||
animate(src, transform = OM, time = halftime, easing = ELASTIC_EASING)
|
||||
|
||||
/atom/proc/do_twist(targetangle = 45, timer = 20)
|
||||
var/matrix/OM = matrix(transform)
|
||||
var/matrix/M = matrix(transform)
|
||||
var/halftime = timer * 0.5
|
||||
M.Turn(pick(-targetangle, targetangle))
|
||||
animate(src, transform = M, time = halftime, easing = ELASTIC_EASING)
|
||||
animate(src, transform = OM, time = halftime, easing = QUAD_EASING)
|
||||
|
||||
/atom/proc/do_squish(squishx = 1.2, squishy = 0.6, timer = 20)
|
||||
var/matrix/OM = matrix(transform)
|
||||
var/matrix/M = matrix(transform)
|
||||
@@ -1526,7 +1534,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
|
||||
blocked |= typesof(/obj/item/reagent_containers/food/drinks/prospacillin,
|
||||
/obj/item/reagent_containers/food/drinks/diminicillin
|
||||
)
|
||||
|
||||
|
||||
return pick(subtypesof(/obj/item/reagent_containers/food/drinks) - blocked)
|
||||
|
||||
//For these two procs refs MUST be ref = TRUE format like typecaches!
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/datum/element/ventcrawling
|
||||
element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH
|
||||
id_arg_index = 2
|
||||
var/tier
|
||||
|
||||
/datum/element/ventcrawling/Attach(datum/target, duration = 0, given_tier = VENTCRAWLER_NUDE)
|
||||
. = ..()
|
||||
|
||||
var/mob/living/person = target
|
||||
if(!istype(person))
|
||||
return FALSE
|
||||
|
||||
src.tier = given_tier
|
||||
|
||||
RegisterSignal(target, COMSIG_HANDLE_VENTCRAWL, .proc/handle_ventcrawl)
|
||||
RegisterSignal(target, COMSIG_CHECK_VENTCRAWL, .proc/check_ventcrawl)
|
||||
to_chat(target, "<span class='notice'>You can ventcrawl! Use alt+click on vents to quickly travel about the station.</span>")
|
||||
|
||||
if(duration!=0)
|
||||
addtimer(CALLBACK(src, .proc/Detach, target), duration)
|
||||
|
||||
/datum/element/ventcrawling/Detach(datum/target)
|
||||
UnregisterSignal(target, list(COMSIG_HANDLE_VENTCRAWL, COMSIG_CHECK_VENTCRAWL))
|
||||
to_chat(target, "<span class='notice'>You can no longer ventcrawl.</span>")
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/element/ventcrawling/proc/handle_ventcrawl(datum/target,atom/A)
|
||||
var/mob/living/person = target
|
||||
if(!istype(person))
|
||||
return FALSE
|
||||
|
||||
person.handle_ventcrawl(A,tier)
|
||||
|
||||
/datum/element/ventcrawling/proc/check_ventcrawl()
|
||||
return tier
|
||||
@@ -255,3 +255,11 @@
|
||||
suffix = "lavaland_surface_cozy_cabin.dmm"
|
||||
allow_duplicates = FALSE
|
||||
cost = 0
|
||||
|
||||
/datum/map_template/ruin/lavaland/jettisoned_reactor
|
||||
name = "Jettisoned Reactor"
|
||||
id = "jettreactor"
|
||||
description = "An incredibly dangerous ruin, filled with radiation and unknown lifeforms."
|
||||
suffix = "lavaland_surface_jettisoned_reactor.dmm"
|
||||
allow_duplicates = FALSE
|
||||
cost = 15//Not too important, if you disregard the rads and facehugger.
|
||||
|
||||
@@ -295,3 +295,15 @@
|
||||
to_chat(L, "<span class='warning'>You need an attachable assembly!</span>")
|
||||
|
||||
#undef MAXIMUM_EMP_WIRES
|
||||
|
||||
//gremlins
|
||||
/datum/wires/proc/npc_tamper(mob/living/L)
|
||||
if(!wires.len)
|
||||
return
|
||||
|
||||
var/wire_to_screw = pick(wires)
|
||||
|
||||
if(is_color_cut(wire_to_screw) || prob(50)) //CutWireColour() proc handles both cutting and mending wires. If the wire is already cut, always mend it back. Otherwise, 50% to cut it and 50% to pulse it
|
||||
cut(wire_to_screw)
|
||||
else
|
||||
pulse(wire_to_screw, L)
|
||||
|
||||
@@ -81,7 +81,6 @@
|
||||
icon_state = "red"
|
||||
|
||||
//Xeno Nest
|
||||
|
||||
/area/ruin/unpowered/xenonest
|
||||
name = "The Hive"
|
||||
always_unpowered = TRUE
|
||||
@@ -90,6 +89,10 @@
|
||||
power_light = FALSE
|
||||
poweralm = FALSE
|
||||
|
||||
//ash walker nest
|
||||
//Ash Walker Nest
|
||||
/area/ruin/unpowered/ash_walkers
|
||||
icon_state = "red"
|
||||
|
||||
//Jettisoned Reactor
|
||||
/area/ruin/unpowered/reactor
|
||||
icon_state = "red"
|
||||
|
||||
@@ -844,7 +844,7 @@
|
||||
typepath = /datum/round_event/spontaneous_appendicitis
|
||||
enemy_roles = list("Medical Doctor","Chief Medical Officer")
|
||||
required_enemies = list(2,2,2,2,2,2,2,1,1,1)
|
||||
requirements = list(5,5,5,5,5,5,5,5,0,0)
|
||||
requirements = list(101,101,20,18,16,14,12,10,8,6)
|
||||
high_population_requirement = 10
|
||||
weight = 5
|
||||
cost = 6
|
||||
|
||||
@@ -91,3 +91,55 @@
|
||||
/obj/machinery/door/poddoor/try_to_crowbar(obj/item/I, mob/user)
|
||||
if(stat & NOPOWER)
|
||||
open(1)
|
||||
|
||||
//Multi-tile poddoors don't turn invisible automatically, so we change the opacity of the turfs below instead one by one.
|
||||
/obj/machinery/door/poddoor/multi_tile/proc/apply_opacity_to_my_turfs(var/new_opacity)
|
||||
for(var/turf/T in locs)
|
||||
T.opacity = new_opacity
|
||||
T.has_opaque_atom = new_opacity
|
||||
T.reconsider_lights()
|
||||
T.air_update_turf(1)
|
||||
update_freelook_sight()
|
||||
|
||||
/obj/machinery/door/poddoor/multi_tile
|
||||
rad_insulation = RAD_NEAR_FULL_INSULATION
|
||||
|
||||
/obj/machinery/door/poddoor/multi_tile/open()
|
||||
. = ..()
|
||||
rad_insulation = RAD_NO_INSULATION
|
||||
apply_opacity_to_my_turfs(0)
|
||||
|
||||
/obj/machinery/door/poddoor/multi_tile/close()
|
||||
. = ..()
|
||||
rad_insulation = RAD_NEAR_FULL_INSULATION
|
||||
apply_opacity_to_my_turfs(1)
|
||||
|
||||
/obj/machinery/door/poddoor/multi_tile/four_tile_ver/
|
||||
icon = 'icons/obj/doors/1x4blast_vert.dmi'
|
||||
bound_height = 128
|
||||
dir = NORTH
|
||||
|
||||
/obj/machinery/door/poddoor/multi_tile/three_tile_ver/
|
||||
icon = 'icons/obj/doors/1x3blast_vert.dmi'
|
||||
bound_height = 96
|
||||
dir = NORTH
|
||||
|
||||
/obj/machinery/door/poddoor/multi_tile/two_tile_ver/
|
||||
icon = 'icons/obj/doors/1x2blast_vert.dmi'
|
||||
bound_height = 64
|
||||
dir = NORTH
|
||||
|
||||
/obj/machinery/door/poddoor/multi_tile/four_tile_hor/
|
||||
icon = 'icons/obj/doors/1x4blast_hor.dmi'
|
||||
bound_width = 128
|
||||
dir = EAST
|
||||
|
||||
/obj/machinery/door/poddoor/multi_tile/three_tile_hor/
|
||||
icon = 'icons/obj/doors/1x3blast_hor.dmi'
|
||||
bound_width = 96
|
||||
dir = EAST
|
||||
|
||||
/obj/machinery/door/poddoor/multi_tile/two_tile_hor/
|
||||
icon = 'icons/obj/doors/1x2blast_hor.dmi'
|
||||
bound_width = 64
|
||||
dir = EAST
|
||||
@@ -42,23 +42,21 @@
|
||||
desc = "Lead-lined shutters painted yellow with a radioactive hazard symbol on it. Blocks out most radiation"
|
||||
icon = 'icons/obj/doors/shutters_radiation.dmi'
|
||||
icon_state = "closed"
|
||||
rad_insulation = 0.2
|
||||
rad_insulation = RAD_NEAR_FULL_INSULATION
|
||||
|
||||
/obj/machinery/door/poddoor/shutters/radiation/preopen
|
||||
icon_state = "open"
|
||||
density = FALSE
|
||||
opacity = 0
|
||||
rad_insulation = 1
|
||||
opacity = FALSE
|
||||
rad_insulation = RAD_NO_INSULATION
|
||||
|
||||
/obj/machinery/door/poddoor/shutters/radiation/do_animate(animation)
|
||||
..()
|
||||
switch(animation)
|
||||
if("opening")
|
||||
rad_insulation = 1
|
||||
if("closing")
|
||||
rad_insulation = -0.5
|
||||
/obj/machinery/door/poddoor/shutters/radiation/open()
|
||||
. = ..()
|
||||
rad_insulation = RAD_NO_INSULATION
|
||||
|
||||
// A 3x3 N2 SM setup won't irradiate you if you're behind the shutter at -0.9 insulation. If it starts to delam, it'll start irradiating you slowly. Keep the value between -0.1 to -0.9
|
||||
/obj/machinery/door/poddoor/shutters/radiation/close()
|
||||
. = ..()
|
||||
rad_insulation = RAD_NEAR_FULL_INSULATION
|
||||
|
||||
/obj/machinery/door/poddoor/shutters/window
|
||||
name = "windowed shutters"
|
||||
|
||||
@@ -249,6 +249,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
|
||||
new/datum/stack_recipe("display case chassis", /obj/structure/displaycase_chassis, 5, one_per_turf = TRUE, on_floor = TRUE), \
|
||||
new/datum/stack_recipe("loom", /obj/structure/loom, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
|
||||
new/datum/stack_recipe("apiary", /obj/structure/beebox, 40, time = 50),\
|
||||
new/datum/stack_recipe("nestbox", /obj/structure/nestbox, 4, time = 30, one_per_turf = TRUE, on_floor = TRUE),\
|
||||
null, \
|
||||
new/datum/stack_recipe("picture frame", /obj/item/wallframe/picture, 1, time = 10),\
|
||||
new/datum/stack_recipe("mortar", /obj/item/reagent_containers/glass/mortar, 3), \
|
||||
@@ -485,8 +486,8 @@ GLOBAL_LIST_INIT(cardboard_recipes, list ( \
|
||||
null, \
|
||||
new/datum/stack_recipe("colored brown", /obj/item/storage/box/brown), \
|
||||
new/datum/stack_recipe("colored green", /obj/item/storage/box/green), \
|
||||
new/datum/stack_recipe("colored red", /obj/item/storage/box/blue), \
|
||||
new/datum/stack_recipe("colored blue", /obj/item/storage/box/red), \
|
||||
new/datum/stack_recipe("colored red", /obj/item/storage/box/red), \
|
||||
new/datum/stack_recipe("colored blue", /obj/item/storage/box/blue), \
|
||||
new/datum/stack_recipe("colored yellow", /obj/item/storage/box/yellow), \
|
||||
new/datum/stack_recipe("colored pink", /obj/item/storage/box/pink), \
|
||||
new/datum/stack_recipe("colored purple", /obj/item/storage/box/purple), \
|
||||
|
||||
+40
-214
@@ -613,12 +613,11 @@
|
||||
if(prob(5))
|
||||
name = "drone (760) action figure"
|
||||
desc = "An action figure modeled after 'drone (760)', it seems to be a bit dusty."
|
||||
|
||||
|
||||
/*
|
||||
|| A Deck of Cards for playing various games of chance ||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/obj/item/toy/cards
|
||||
resistance_flags = FLAMMABLE
|
||||
max_integrity = 50
|
||||
@@ -636,7 +635,8 @@
|
||||
playsound(src, 'sound/items/cardshuffle.ogg', 50, 1)
|
||||
return BRUTELOSS
|
||||
|
||||
/obj/item/toy/cards/proc/apply_card_vars(obj/item/toy/cards/newobj, obj/item/toy/cards/sourceobj) // Applies variables for supporting multiple types of card deck
|
||||
/obj/item/toy/cards/proc/apply_card_vars(obj/item/toy/cards/newobj, obj/item/toy/cards/sourceobj)
|
||||
// Applies variables for supporting multiple types of card deck
|
||||
if(!istype(sourceobj))
|
||||
return
|
||||
|
||||
@@ -658,53 +658,24 @@
|
||||
|
||||
/obj/item/toy/cards/deck/proc/populate_deck()
|
||||
icon_state = "deck_[deckstyle]_full"
|
||||
for(var/i in 2 to 10)
|
||||
cards += "[i] of Hearts"
|
||||
cards += "[i] of Spades"
|
||||
cards += "[i] of Clubs"
|
||||
cards += "[i] of Diamonds"
|
||||
cards += "King of Hearts"
|
||||
cards += "King of Spades"
|
||||
cards += "King of Clubs"
|
||||
cards += "King of Diamonds"
|
||||
cards += "Queen of Hearts"
|
||||
cards += "Queen of Spades"
|
||||
cards += "Queen of Clubs"
|
||||
cards += "Queen of Diamonds"
|
||||
cards += "Jack of Hearts"
|
||||
cards += "Jack of Spades"
|
||||
cards += "Jack of Clubs"
|
||||
cards += "Jack of Diamonds"
|
||||
cards += "Ace of Hearts"
|
||||
cards += "Ace of Spades"
|
||||
cards += "Ace of Clubs"
|
||||
cards += "Ace of Diamonds"
|
||||
var/_suits = list("Hearts", "Spades", "Clubs", "Diamonds")
|
||||
var/_faces = list("Ace", "King", "Queen", "Jack")
|
||||
for(var/suit in _suits)
|
||||
for(var/i in 2 to 10)
|
||||
cards += list(list(
|
||||
"name" = "[i] of [suit]",
|
||||
"icon_state" = "[i]of[lowertext(suit)]",
|
||||
"rotation" = null,
|
||||
"face_up" = null
|
||||
))
|
||||
for(var/i in _faces)
|
||||
cards += list(list(
|
||||
"name" = "[i] of [suit]",
|
||||
"icon_state" = "[lowertext(i)]of[lowertext(suit)]",
|
||||
"rotation" = null,
|
||||
"face_up" = null
|
||||
))
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
//ATTACK HAND NOT CALLING PARENT
|
||||
/obj/item/toy/cards/deck/attack_hand(mob/user)
|
||||
draw_card(user)
|
||||
|
||||
/obj/item/toy/cards/deck/proc/draw_card(mob/user)
|
||||
if(user.lying)
|
||||
return
|
||||
var/choice = null
|
||||
if(cards.len == 0)
|
||||
to_chat(user, "<span class='warning'>There are no more cards to draw!</span>")
|
||||
return
|
||||
var/obj/item/toy/cards/singlecard/H = new/obj/item/toy/cards/singlecard(user.loc)
|
||||
if(holo)
|
||||
holo.spawned += H // track them leaving the holodeck
|
||||
choice = cards[1]
|
||||
H.cardname = choice
|
||||
H.parentdeck = src
|
||||
var/O = src
|
||||
H.apply_card_vars(H,O)
|
||||
src.cards.Cut(1,2) //Removes the top card from the list
|
||||
H.pickup(user)
|
||||
user.put_in_hands(H)
|
||||
user.visible_message("[user] draws a card from the deck.", "<span class='notice'>You draw a card from the deck.</span>")
|
||||
update_icon()
|
||||
|
||||
/obj/item/toy/cards/deck/update_icon()
|
||||
if(cards.len > original_size/2)
|
||||
@@ -716,60 +687,6 @@
|
||||
else if(cards.len == 0)
|
||||
icon_state = "deck_[deckstyle]_empty"
|
||||
|
||||
/obj/item/toy/cards/deck/attack_self(mob/user)
|
||||
if(cooldown < world.time - 50)
|
||||
cards = shuffle(cards)
|
||||
playsound(src, 'sound/items/cardshuffle.ogg', 50, 1)
|
||||
user.visible_message("[user] shuffles the deck.", "<span class='notice'>You shuffle the deck.</span>")
|
||||
cooldown = world.time
|
||||
|
||||
/obj/item/toy/cards/deck/attackby(obj/item/I, mob/living/user, params)
|
||||
if(istype(I, /obj/item/toy/cards/singlecard))
|
||||
var/obj/item/toy/cards/singlecard/SC = I
|
||||
if(SC.parentdeck == src)
|
||||
if(!user.temporarilyRemoveItemFromInventory(SC))
|
||||
to_chat(user, "<span class='warning'>The card is stuck to your hand, you can't add it to the deck!</span>")
|
||||
return
|
||||
cards += SC.cardname
|
||||
user.visible_message("[user] adds a card to the bottom of the deck.","<span class='notice'>You add the card to the bottom of the deck.</span>")
|
||||
qdel(SC)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't mix cards from other decks!</span>")
|
||||
update_icon()
|
||||
else if(istype(I, /obj/item/toy/cards/cardhand))
|
||||
var/obj/item/toy/cards/cardhand/CH = I
|
||||
if(CH.parentdeck == src)
|
||||
if(!user.temporarilyRemoveItemFromInventory(CH))
|
||||
to_chat(user, "<span class='warning'>The hand of cards is stuck to your hand, you can't add it to the deck!</span>")
|
||||
return
|
||||
cards += CH.currenthand
|
||||
user.visible_message("[user] puts [user.p_their()] hand of cards in the deck.", "<span class='notice'>You put the hand of cards in the deck.</span>")
|
||||
qdel(CH)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't mix cards from other decks!</span>")
|
||||
update_icon()
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/toy/cards/deck/MouseDrop(atom/over_object)
|
||||
. = ..()
|
||||
var/mob/living/M = usr
|
||||
if(!istype(M) || usr.incapacitated() || usr.lying)
|
||||
return
|
||||
if(Adjacent(usr))
|
||||
if(over_object == M && loc != M)
|
||||
M.put_in_hands(src)
|
||||
to_chat(usr, "<span class='notice'>You pick up the deck.</span>")
|
||||
|
||||
else if(istype(over_object, /obj/screen/inventory/hand))
|
||||
var/obj/screen/inventory/hand/H = over_object
|
||||
if(M.putItemFromInventoryInHandIfPossible(src, H.held_index))
|
||||
to_chat(usr, "<span class='notice'>You pick up the deck.</span>")
|
||||
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>You can't reach it from here!</span>")
|
||||
|
||||
|
||||
|
||||
/obj/item/toy/cards/cardhand
|
||||
name = "hand of cards"
|
||||
@@ -780,59 +697,9 @@
|
||||
var/list/currenthand = list()
|
||||
var/choice = null
|
||||
|
||||
/obj/item/toy/cards/cardhand/attack_self(mob/user)
|
||||
var/list/handradial = list()
|
||||
interact(user)
|
||||
|
||||
for(var/t in currenthand)
|
||||
handradial[t] = image(icon = src.icon, icon_state = "sc_[t]_[deckstyle]")
|
||||
|
||||
if(usr.stat || !ishuman(usr))
|
||||
return
|
||||
var/mob/living/carbon/human/cardUser = usr
|
||||
var/O = src
|
||||
var/choice = show_radial_menu(usr,src, handradial, custom_check = CALLBACK(src, .proc/check_menu, user), radius = 36, require_near = TRUE)
|
||||
if(!choice)
|
||||
return FALSE
|
||||
var/obj/item/toy/cards/singlecard/C = new/obj/item/toy/cards/singlecard(cardUser.loc)
|
||||
currenthand -= choice
|
||||
handradial -= choice
|
||||
C.parentdeck = parentdeck
|
||||
C.cardname = choice
|
||||
C.apply_card_vars(C,O)
|
||||
C.pickup(cardUser)
|
||||
cardUser.put_in_hands(C)
|
||||
cardUser.visible_message("<span class='notice'>[cardUser] draws a card from [cardUser.p_their()] hand.</span>", "<span class='notice'>You take the [C.cardname] from your hand.</span>")
|
||||
|
||||
interact(cardUser)
|
||||
update_sprite()
|
||||
if(length(currenthand) == 1)
|
||||
var/obj/item/toy/cards/singlecard/N = new/obj/item/toy/cards/singlecard(loc)
|
||||
N.parentdeck = parentdeck
|
||||
N.cardname = currenthand[1]
|
||||
N.apply_card_vars(N,O)
|
||||
qdel(src)
|
||||
N.pickup(cardUser)
|
||||
cardUser.put_in_hands(N)
|
||||
to_chat(cardUser, "<span class='notice'>You also take [currenthand[1]] and hold it.</span>")
|
||||
|
||||
/obj/item/toy/cards/cardhand/attackby(obj/item/toy/cards/singlecard/C, mob/living/user, params)
|
||||
if(istype(C))
|
||||
if(C.parentdeck == src.parentdeck)
|
||||
src.currenthand += C.cardname
|
||||
user.visible_message("<span class='notice'>[user] adds a card to [user.p_their()] hand.</span>", "<span class='notice'>You add the [C.cardname] to your hand.</span>")
|
||||
qdel(C)
|
||||
interact(user)
|
||||
update_sprite(src)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't mix cards from other decks!</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/toy/cards/cardhand/apply_card_vars(obj/item/toy/cards/newobj,obj/item/toy/cards/sourceobj)
|
||||
..()
|
||||
newobj.deckstyle = sourceobj.deckstyle
|
||||
update_sprite()
|
||||
newobj.card_hitsound = sourceobj.card_hitsound
|
||||
newobj.card_force = sourceobj.card_force
|
||||
newobj.card_throwforce = sourceobj.card_throwforce
|
||||
@@ -840,6 +707,7 @@
|
||||
newobj.card_throw_range = sourceobj.card_throw_range
|
||||
newobj.card_attack_verb = sourceobj.card_attack_verb
|
||||
newobj.resistance_flags = sourceobj.resistance_flags
|
||||
update_icon()
|
||||
|
||||
/**
|
||||
* check_menu: Checks if we are allowed to interact with a radial menu
|
||||
@@ -857,13 +725,23 @@
|
||||
/**
|
||||
* This proc updates the sprite for when you create a hand of cards
|
||||
*/
|
||||
/obj/item/toy/cards/cardhand/proc/update_sprite()
|
||||
/obj/item/toy/cards/cardhand/update_icon()
|
||||
cut_overlays()
|
||||
var/overlay_cards = currenthand.len
|
||||
if(overlay_cards)
|
||||
var/k = overlay_cards == 2 ? 1 : overlay_cards - 2
|
||||
for(var/i = k; i <= overlay_cards; i++)
|
||||
var/card_overlay = image(icon=src.icon,icon_state="sc_[currenthand[i]]_[deckstyle]",pixel_x=(1-i+k)*3,pixel_y=(1-i+k)*3)
|
||||
var/_card = currenthand[i]
|
||||
var/_angle = _card["rotation"] || rotation
|
||||
var/matrix/rot_matrix = matrix()
|
||||
rot_matrix.Turn(GetAngle(_angle))
|
||||
var/image/card_overlay = image(
|
||||
icon = src.icon,
|
||||
icon_state = "sc_[_card["icon_state"] || _card["name"]]_[deckstyle]",
|
||||
pixel_x = (1 - i + k)*3,
|
||||
pixel_y = (1 - i + k)*3,
|
||||
)
|
||||
card_overlay.transform = rot_matrix
|
||||
add_overlay(card_overlay)
|
||||
|
||||
/obj/item/toy/cards/singlecard
|
||||
@@ -872,8 +750,7 @@
|
||||
icon = 'icons/obj/toy.dmi'
|
||||
icon_state = "singlecard_down_nanotrasen"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/cardname = null
|
||||
var/flipped = 0
|
||||
var/card = null
|
||||
pixel_x = -5
|
||||
|
||||
|
||||
@@ -882,7 +759,9 @@
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/cardUser = user
|
||||
if(cardUser.is_holding(src))
|
||||
cardUser.visible_message("[cardUser] checks [cardUser.p_their()] card.", "<span class='notice'>The card reads: [cardname].</span>")
|
||||
cardUser.visible_message(
|
||||
"[cardUser] checks [cardUser.p_their()] card.",
|
||||
"<span class='notice'>The card reads: [card["name"]]. [card["desc"] || ""]</span>")
|
||||
else
|
||||
. += "<span class='warning'>You need to have the card in your hand to check it!</span>"
|
||||
|
||||
@@ -892,65 +771,11 @@
|
||||
set src in range(1)
|
||||
if(!ishuman(usr) || !usr.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
if(!flipped)
|
||||
src.flipped = 1
|
||||
if (cardname)
|
||||
src.icon_state = "sc_[cardname]_[deckstyle]"
|
||||
src.name = src.cardname
|
||||
else
|
||||
src.icon_state = "sc_Ace of Spades_[deckstyle]"
|
||||
src.name = "What Card"
|
||||
src.pixel_x = 5
|
||||
else if(flipped)
|
||||
src.flipped = 0
|
||||
src.icon_state = "singlecard_down_[deckstyle]"
|
||||
src.name = "card"
|
||||
src.pixel_x = -5
|
||||
|
||||
/obj/item/toy/cards/singlecard/attackby(obj/item/I, mob/living/user, params)
|
||||
if(istype(I, /obj/item/toy/cards/singlecard/))
|
||||
var/obj/item/toy/cards/singlecard/C = I
|
||||
if(C.parentdeck == src.parentdeck)
|
||||
var/obj/item/toy/cards/cardhand/H = new/obj/item/toy/cards/cardhand(user.loc)
|
||||
H.currenthand += C.cardname
|
||||
H.currenthand += src.cardname
|
||||
H.parentdeck = C.parentdeck
|
||||
H.apply_card_vars(H,C)
|
||||
to_chat(user, "<span class='notice'>You combine the [C.cardname] and the [src.cardname] into a hand.</span>")
|
||||
qdel(C)
|
||||
qdel(src)
|
||||
H.pickup(user)
|
||||
user.put_in_active_hand(H)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't mix cards from other decks!</span>")
|
||||
|
||||
if(istype(I, /obj/item/toy/cards/cardhand/))
|
||||
var/obj/item/toy/cards/cardhand/H = I
|
||||
if(H.parentdeck == parentdeck)
|
||||
H.currenthand += cardname
|
||||
user.visible_message("[user] adds a card to [user.p_their()] hand.", "<span class='notice'>You add the [cardname] to your hand.</span>")
|
||||
qdel(src)
|
||||
H.interact(user)
|
||||
if(H.currenthand.len > 4)
|
||||
H.icon_state = "[deckstyle]_hand5"
|
||||
else if(H.currenthand.len > 3)
|
||||
H.icon_state = "[deckstyle]_hand4"
|
||||
else if(H.currenthand.len > 2)
|
||||
H.icon_state = "[deckstyle]_hand3"
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't mix cards from other decks!</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/toy/cards/singlecard/attack_self(mob/user)
|
||||
if(usr.stat || !ishuman(usr) || !usr.canmove || usr.restrained())
|
||||
return
|
||||
Flip()
|
||||
FlipCard()
|
||||
|
||||
/obj/item/toy/cards/singlecard/apply_card_vars(obj/item/toy/cards/singlecard/newobj,obj/item/toy/cards/sourceobj)
|
||||
..()
|
||||
newobj.deckstyle = sourceobj.deckstyle
|
||||
newobj.icon_state = "singlecard_down_[deckstyle]" // Without this the card is invisible until flipped. It's an ugly hack, but it works.
|
||||
newobj.card_hitsound = sourceobj.card_hitsound
|
||||
newobj.hitsound = newobj.card_hitsound
|
||||
newobj.card_force = sourceobj.card_force
|
||||
@@ -963,6 +788,7 @@
|
||||
newobj.throw_range = newobj.card_throw_range
|
||||
newobj.card_attack_verb = sourceobj.card_attack_verb
|
||||
newobj.attack_verb = newobj.card_attack_verb
|
||||
newobj.update_icon()
|
||||
|
||||
/*
|
||||
|| Syndicate playing cards, for pretending you're Gambit and playing poker for the nuke disk. ||
|
||||
|
||||
@@ -209,3 +209,15 @@
|
||||
sheet_type = /obj/item/stack/tile/bronze
|
||||
sheet_amount = 2
|
||||
girder_type = /obj/structure/girder/bronze
|
||||
|
||||
/turf/closed/wall/mineral/lead
|
||||
name = "lead lined metal wall"
|
||||
desc = "A hefty wall with lead inserts."
|
||||
icon = 'icons/turf/walls/riveted.dmi'
|
||||
icon_state = "riveted"
|
||||
sheet_type = /obj/item/stack/rods
|
||||
hardness = 10
|
||||
girder_type = /obj/structure/girder/reinforced
|
||||
explosion_block = 2
|
||||
rad_insulation = RAD_NEAR_FULL_INSULATION
|
||||
canSmoothWith = list(/turf/closed/wall/mineral/lead)
|
||||
|
||||
@@ -2435,14 +2435,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
to_chat(user,"<span class='danger'>Invalid color. Your color is not bright enough.</span>")
|
||||
|
||||
if("belly_size")
|
||||
var/new_bellysize = input(user, "Belly size :\n(1-3)", "Character Preference") as num|null
|
||||
if(new_bellysize)
|
||||
features["belly_size"] = clamp(new_bellysize, 1, 3)
|
||||
var/new_bellysize = input(user, "Belly size :\n([BELLY_MIN_SIZE]-[BELLY_MAX_SIZE])", "Character Preference") as num|null
|
||||
if(new_bellysize != null)
|
||||
features["belly_size"] = clamp(new_bellysize, BELLY_MIN_SIZE, BELLY_MAX_SIZE)
|
||||
|
||||
if("butt_size")
|
||||
var/new_buttsize = input(user, "Butt size :\n(0-5)", "Character Preference") as num|null
|
||||
if(new_buttsize)
|
||||
features["butt_size"] = clamp(new_buttsize, 0, 5)
|
||||
var/new_buttsize = input(user, "Butt size :\n([BUTT_MIN_SIZE]-[BUTT_MAX_SIZE])", "Character Preference") as num|null
|
||||
if(new_buttsize != null)
|
||||
features["butt_size"] = clamp(new_buttsize, BUTT_MIN_SIZE, BUTT_MAX_SIZE)
|
||||
|
||||
if("vag_shape")
|
||||
var/new_shape
|
||||
@@ -2577,7 +2577,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
if(features["has_belly"] == FALSE)
|
||||
features["hide_belly"] = FALSE
|
||||
features["inflatable_belly"] = FALSE
|
||||
features["belly_size"] = 1
|
||||
features["belly_size"] = 0
|
||||
|
||||
if("inflatable_belly")
|
||||
features["inflatable_belly"] = !features["inflatable_belly"]
|
||||
|
||||
@@ -438,7 +438,7 @@
|
||||
resistance_flags = NONE
|
||||
armor = list("melee" = 5, "bullet" = 5, "laser" = 5, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
|
||||
clothing_flags = BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS
|
||||
flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEFACIALHAIR
|
||||
flags_inv = HIDEEYES|HIDEFACE|HIDEFACIALHAIR
|
||||
gas_transfer_coefficient = 0.01
|
||||
permeability_coefficient = 0.01
|
||||
flags_cover = MASKCOVERSEYES | MASKCOVERSMOUTH
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
desc = "A face-covering mask that can be connected to an air supply. While good for concealing your identity, it isn't good for blocking gas flow." //More accurate
|
||||
icon_state = "gas_alt"
|
||||
clothing_flags = BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS
|
||||
flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEFACIALHAIR|HIDESNOUT
|
||||
flags_inv = HIDEEYES|HIDEFACE|HIDEFACIALHAIR|HIDESNOUT
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
item_state = "gas_alt"
|
||||
gas_transfer_coefficient = 0.01
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
icon_state = "swat"
|
||||
item_state = "swat"
|
||||
aggressiveness = 3
|
||||
flags_inv = HIDEFACIALHAIR|HIDEFACE|HIDEEYES|HIDEEARS|HIDEHAIR
|
||||
flags_inv = HIDEFACIALHAIR|HIDEFACE|HIDEEYES|HIDEHAIR
|
||||
visor_flags_inv = 0
|
||||
|
||||
/obj/item/clothing/mask/gas/sechailer/cyborg
|
||||
|
||||
+54
-88
@@ -2,39 +2,36 @@
|
||||
// This is a parody of Cards Against Humanity (https://en.wikipedia.org/wiki/Cards_Against_Humanity)
|
||||
// which is licensed under CC BY-NC-SA 2.0, the full text of which can be found at the following URL:
|
||||
// https://creativecommons.org/licenses/by-nc-sa/2.0/legalcode
|
||||
// Original code by Zuhayr, Polaris Station, ported with modifications
|
||||
/datum/playingcard
|
||||
var/name = "playing card"
|
||||
var/card_icon = "card_back"
|
||||
var/suit
|
||||
var/number
|
||||
// Original code by Zuhayr, Polaris Station, ported with modifications
|
||||
// April 2022: modified by sarcoph for hyperstation
|
||||
|
||||
/obj/item/toy/cards/deck/cas
|
||||
name = "\improper CAS deck (white)"
|
||||
desc = "A deck for the game Cards Against Spess, still popular after all these centuries. Warning: may include traces of broken fourth wall. This is the white deck."
|
||||
icon = 'icons/obj/toy.dmi'
|
||||
icon_state = "deck_caswhite_full"
|
||||
deckstyle = "caswhite"
|
||||
var/card_face = "cas_white"
|
||||
deckstyle = "cas"
|
||||
var/card_face = "white"
|
||||
var/blanks = 25
|
||||
var/decksize = 150
|
||||
var/card_text_file = "strings/cas_white.txt"
|
||||
var/list/allcards = list()
|
||||
|
||||
/obj/item/toy/cards/deck/cas/black
|
||||
name = "\improper CAS deck (black)"
|
||||
desc = "A deck for the game Cards Against Spess, still popular after all these centuries. Warning: may include traces of broken fourth wall. This is the black deck."
|
||||
icon_state = "deck_casblack_full"
|
||||
deckstyle = "casblack"
|
||||
card_face = "cas_black"
|
||||
card_face = "black"
|
||||
blanks = 0
|
||||
decksize = 50
|
||||
card_text_file = "strings/cas_black.txt"
|
||||
|
||||
/obj/item/toy/cards/deck/cas/populate_deck()
|
||||
var/static/list/cards_against_space = list("cas_white" = world.file2list("strings/cas_white.txt"),"cas_black" = world.file2list("strings/cas_black.txt"))
|
||||
allcards = cards_against_space[card_face]
|
||||
var/list/possiblecards = allcards.Copy()
|
||||
var/static/list/cards_against_space = list(
|
||||
"white" = world.file2list("strings/cas_white.txt"),
|
||||
"black" = world.file2list("strings/cas_black.txt")
|
||||
)
|
||||
var/list/_cards = cards_against_space[card_face]
|
||||
var/list/possiblecards = _cards.Copy()
|
||||
if(possiblecards.len < decksize) // sanity check
|
||||
decksize = (possiblecards.len - 1)
|
||||
var/list/randomcards = list()
|
||||
@@ -42,105 +39,74 @@
|
||||
randomcards += pick_n_take(possiblecards)
|
||||
for(var/x in 1 to randomcards.len)
|
||||
var/cardtext = randomcards[x]
|
||||
var/datum/playingcard/P
|
||||
P = new()
|
||||
P.name = "[cardtext]"
|
||||
P.card_icon = "[src.card_face]"
|
||||
cards += P
|
||||
cards += list(list(
|
||||
"name" = cardtext,
|
||||
"icon_state" = src.card_face,
|
||||
"rotation" = null,
|
||||
"face_up" = null
|
||||
))
|
||||
if(!blanks)
|
||||
return
|
||||
for(var/x in 1 to blanks)
|
||||
var/datum/playingcard/P
|
||||
P = new()
|
||||
P.name = "Blank Card"
|
||||
P.card_icon = "cas_white"
|
||||
cards += P
|
||||
shuffle_inplace(cards) // distribute blank cards throughout deck
|
||||
cards += list(list(
|
||||
"name" = "Blank Card",
|
||||
"icon_state" = "white",
|
||||
"rotation" = null,
|
||||
"face_up" = null
|
||||
))
|
||||
|
||||
/obj/item/toy/cards/deck/cas/draw_card(mob/user)
|
||||
if(user.lying)
|
||||
return
|
||||
if(cards.len == 0)
|
||||
to_chat(user, "<span class='warning'>There are no more cards to draw!</span>")
|
||||
return
|
||||
var/obj/item/toy/cards/singlecard/cas/H = new/obj/item/toy/cards/singlecard/cas(user.loc)
|
||||
var/datum/playingcard/choice = cards[1]
|
||||
if (choice.name == "Blank Card")
|
||||
H.blank = 1
|
||||
H.name = choice.name
|
||||
H.buffertext = choice.name
|
||||
H.icon_state = choice.card_icon
|
||||
H.card_face = choice.card_icon
|
||||
H.parentdeck = src
|
||||
src.cards -= choice
|
||||
H.pickup(user)
|
||||
user.put_in_hands(H)
|
||||
user.visible_message("[user] draws a card from the deck.", "<span class='notice'>You draw a card from the deck.</span>")
|
||||
update_icon()
|
||||
|
||||
/obj/item/toy/cards/deck/cas/attackby(obj/item/I, mob/living/user, params)
|
||||
if(istype(I, /obj/item/toy/cards/singlecard/cas))
|
||||
var/obj/item/toy/cards/singlecard/cas/SC = I
|
||||
if(!user.temporarilyRemoveItemFromInventory(SC))
|
||||
to_chat(user, "<span class='warning'>The card is stuck to your hand, you can't add it to the deck!</span>")
|
||||
return
|
||||
var/datum/playingcard/RC // replace null datum for the re-added card
|
||||
RC = new()
|
||||
RC.name = "[SC.name]"
|
||||
RC.card_icon = SC.card_face
|
||||
cards += RC
|
||||
user.visible_message("[user] adds a card to the bottom of the deck.","<span class='notice'>You add the card to the bottom of the deck.</span>")
|
||||
qdel(SC)
|
||||
/obj/item/toy/cards/deck/cas/DrawOneCard(list/card_indices)
|
||||
var/obj/item/toy/cards/singlecard/cas/S = new/obj/item/toy/cards/singlecard/cas(usr.loc)
|
||||
var/_card = cards[card_indices[1]]
|
||||
_card["rotation"] = rotation
|
||||
_card["face_up"] = face_up
|
||||
if(_card["name"] == "Blank Card")
|
||||
S.blank = TRUE
|
||||
S.card = _card
|
||||
S.card_face = card_face
|
||||
S.rotation = _card["rotation"]
|
||||
S.face_up = _card["face_up"]
|
||||
S.parentdeck = src
|
||||
S.apply_card_vars(S,src)
|
||||
cards -= list(_card)
|
||||
update_icon()
|
||||
return S
|
||||
|
||||
/obj/item/toy/cards/deck/cas/update_icon()
|
||||
if(cards.len < 26)
|
||||
icon_state = "deck_[deckstyle]_low"
|
||||
icon_state = "deck_[deckstyle][card_face]_low"
|
||||
|
||||
|
||||
|
||||
// ----------- SINGLE CARD -----------
|
||||
|
||||
/obj/item/toy/cards/singlecard/cas
|
||||
name = "CAS card"
|
||||
desc = "A CAS card."
|
||||
icon_state = "cas_white"
|
||||
flipped = 0
|
||||
var/card_face = "cas_white"
|
||||
icon_state = "sc_cas_white"
|
||||
var/card_face = "white"
|
||||
var/blank = 0
|
||||
var/buffertext = "A funny bit of text."
|
||||
|
||||
/obj/item/toy/cards/singlecard/cas/examine(mob/user)
|
||||
. = ..()
|
||||
if (flipped)
|
||||
if (!face_up)
|
||||
. += "<span class='notice'>The card is face down.</span>"
|
||||
else if (blank)
|
||||
. += "<span class='notice'>The card is blank. Write on it with a pen.</span>"
|
||||
else
|
||||
. += "<span class='notice'>The card reads: [name]</span>"
|
||||
. += "<span class='notice'>Alt-click to flip it.</span>"
|
||||
|
||||
/obj/item/toy/cards/singlecard/cas/Flip()
|
||||
set name = "Flip Card"
|
||||
set category = "Object"
|
||||
set src in range(1)
|
||||
if(!ishuman(usr) || !usr.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
if(!flipped)
|
||||
name = "CAS card"
|
||||
else if(flipped)
|
||||
name = buffertext
|
||||
flipped = !flipped
|
||||
update_icon()
|
||||
|
||||
/obj/item/toy/cards/singlecard/cas/AltClick(mob/living/user)
|
||||
. = ..()
|
||||
if(!ishuman(user) || !user.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
Flip()
|
||||
return TRUE
|
||||
|
||||
/obj/item/toy/cards/singlecard/cas/update_icon()
|
||||
if(flipped)
|
||||
icon_state = "[card_face]_flipped"
|
||||
var/matrix/rot_matrix = matrix()
|
||||
rot_matrix.Turn(GetAngle(rotation))
|
||||
transform = rot_matrix
|
||||
if(face_up)
|
||||
icon_state = "sc_[deckstyle]_[card_face]"
|
||||
name = card["name"]
|
||||
else
|
||||
icon_state = "[card_face]"
|
||||
icon_state = "sc_[deckstyle]_[card_face]_flipped"
|
||||
name = "CAS card"
|
||||
|
||||
/obj/item/toy/cards/singlecard/cas/attackby(obj/item/I, mob/living/user, params)
|
||||
if(istype(I, /obj/item/pen))
|
||||
|
||||
@@ -181,147 +181,6 @@
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/chick
|
||||
name = "\improper chick"
|
||||
desc = "Adorable! They make such a racket though."
|
||||
icon_state = "chick"
|
||||
icon_living = "chick"
|
||||
icon_dead = "chick_dead"
|
||||
icon_gib = "chick_gib"
|
||||
gender = FEMALE
|
||||
mob_biotypes = MOB_ORGANIC|MOB_BEAST
|
||||
speak = list("Cherp.","Cherp?","Chirrup.","Cheep!")
|
||||
speak_emote = list("cheeps")
|
||||
emote_hear = list("cheeps.")
|
||||
emote_see = list("pecks at the ground.","flaps its tiny wings.")
|
||||
density = FALSE
|
||||
speak_chance = 2
|
||||
turns_per_move = 2
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/chicken = 1)
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "kicks"
|
||||
attacktext = "kicks"
|
||||
health = 3
|
||||
maxHealth = 3
|
||||
ventcrawler = VENTCRAWLER_ALWAYS
|
||||
var/amount_grown = 0
|
||||
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
|
||||
mob_size = MOB_SIZE_TINY
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
|
||||
do_footstep = TRUE
|
||||
|
||||
/mob/living/simple_animal/chick/Initialize()
|
||||
. = ..()
|
||||
pixel_x = rand(-6, 6)
|
||||
pixel_y = rand(0, 10)
|
||||
|
||||
/mob/living/simple_animal/chick/Life()
|
||||
. =..()
|
||||
if(!.)
|
||||
return
|
||||
if(!stat && !ckey)
|
||||
amount_grown += rand(1,2)
|
||||
if(amount_grown >= 100)
|
||||
new /mob/living/simple_animal/chicken(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/chick/holo/Life()
|
||||
..()
|
||||
amount_grown = 0
|
||||
|
||||
/mob/living/simple_animal/chicken
|
||||
name = "\improper chicken"
|
||||
desc = "Hopefully the eggs are good this season."
|
||||
gender = FEMALE
|
||||
mob_biotypes = MOB_ORGANIC|MOB_BEAST
|
||||
icon_state = "chicken_brown"
|
||||
icon_living = "chicken_brown"
|
||||
icon_dead = "chicken_brown_dead"
|
||||
speak = list("Cluck!","BWAAAAARK BWAK BWAK BWAK!","Bwaak bwak.")
|
||||
speak_emote = list("clucks","croons")
|
||||
emote_hear = list("clucks.")
|
||||
emote_see = list("pecks at the ground.","flaps its wings viciously.")
|
||||
density = FALSE
|
||||
speak_chance = 2
|
||||
turns_per_move = 3
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/chicken = 2)
|
||||
var/egg_type = /obj/item/reagent_containers/food/snacks/egg
|
||||
var/food_type = /obj/item/reagent_containers/food/snacks/grown/wheat
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "kicks"
|
||||
attacktext = "kicks"
|
||||
health = 15
|
||||
maxHealth = 15
|
||||
ventcrawler = VENTCRAWLER_ALWAYS
|
||||
var/eggsleft = 0
|
||||
var/eggsFertile = TRUE
|
||||
var/body_color
|
||||
var/icon_prefix = "chicken"
|
||||
pass_flags = PASSTABLE | PASSMOB
|
||||
mob_size = MOB_SIZE_SMALL
|
||||
var/list/feedMessages = list("It clucks happily.","It clucks happily.")
|
||||
var/list/layMessage = EGG_LAYING_MESSAGES
|
||||
var/list/validColors = list("brown","black","white")
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
var/static/chicken_count = 0
|
||||
|
||||
do_footstep = TRUE
|
||||
|
||||
/mob/living/simple_animal/chicken/Initialize()
|
||||
. = ..()
|
||||
if(!body_color)
|
||||
body_color = pick(validColors)
|
||||
icon_state = "[icon_prefix]_[body_color]"
|
||||
icon_living = "[icon_prefix]_[body_color]"
|
||||
icon_dead = "[icon_prefix]_[body_color]_dead"
|
||||
pixel_x = rand(-6, 6)
|
||||
pixel_y = rand(0, 10)
|
||||
++chicken_count
|
||||
|
||||
/mob/living/simple_animal/chicken/Destroy()
|
||||
--chicken_count
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/chicken/attackby(obj/item/O, mob/user, params)
|
||||
if(istype(O, food_type)) //feedin' dem chickens
|
||||
if(!stat && eggsleft < 8)
|
||||
var/feedmsg = "[user] feeds [O] to [name]! [pick(feedMessages)]"
|
||||
user.visible_message(feedmsg)
|
||||
qdel(O)
|
||||
eggsleft += rand(1, 4)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[name] doesn't seem hungry!</span>")
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/chicken/Life()
|
||||
. =..()
|
||||
if(!.)
|
||||
return
|
||||
if((!stat && prob(3) && eggsleft > 0) && egg_type)
|
||||
visible_message("<span class='alertalien'>[src] [pick(layMessage)]</span>")
|
||||
eggsleft--
|
||||
var/obj/item/E = new egg_type(get_turf(src))
|
||||
E.pixel_x = rand(-6,6)
|
||||
E.pixel_y = rand(-6,6)
|
||||
if(eggsFertile)
|
||||
if(chicken_count < MAX_CHICKENS && prob(25))
|
||||
START_PROCESSING(SSobj, E)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/egg/var/amount_grown = 0
|
||||
/obj/item/reagent_containers/food/snacks/egg/process()
|
||||
if(isturf(loc))
|
||||
amount_grown += rand(1,2)
|
||||
if(amount_grown >= 100)
|
||||
visible_message("[src] hatches with a quiet cracking sound.")
|
||||
new /mob/living/simple_animal/chick(get_turf(src))
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
qdel(src)
|
||||
else
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
// Space kiwis, ergo quite a copypasta of chickens.
|
||||
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
#define GREMLIN_VENT_CHANCE 1.75
|
||||
|
||||
//Gremlins
|
||||
//Small monsters that don't attack humans or other animals. Instead they mess with electronics, computers and machinery
|
||||
|
||||
//List of objects that gremlins can't tamper with (because nobody coded an interaction for it)
|
||||
//List starts out empty. Whenever a gremlin finds a machine that it couldn't tamper with, the machine's type is added here, and all machines of such type are ignored from then on (NOT SUBTYPES)
|
||||
GLOBAL_LIST(bad_gremlin_items)
|
||||
|
||||
/mob/living/simple_animal/hostile/gremlin
|
||||
name = "gremlin"
|
||||
desc = "This tiny creature finds great joy in discovering and using technology. Nothing excites it more than pushing random buttons on a computer to see what it might do."
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "gremlin"
|
||||
icon_living = "gremlin"
|
||||
icon_dead = "gremlin_dead"
|
||||
|
||||
var/body_color
|
||||
|
||||
var/in_vent = FALSE
|
||||
|
||||
health = 20
|
||||
maxHealth = 20
|
||||
search_objects = 3 //Completely ignore mobs
|
||||
|
||||
//Tampering is handled by the 'npc_tamper()' obj proc
|
||||
wanted_objects = list(
|
||||
/obj/machinery,
|
||||
/obj/item/reagent_containers/food,
|
||||
/obj/structure/sink
|
||||
)
|
||||
|
||||
var/obj/machinery/atmospherics/components/unary/vent_pump/entry_vent
|
||||
var/obj/machinery/atmospherics/components/unary/vent_pump/exit_vent
|
||||
|
||||
dextrous = TRUE
|
||||
possible_a_intents = list(INTENT_HELP, INTENT_GRAB, INTENT_DISARM, INTENT_HARM)
|
||||
faction = list("meme", "gremlin")
|
||||
speed = 0.5
|
||||
gold_core_spawnable = 2
|
||||
unique_name = TRUE
|
||||
|
||||
//Ensure gremlins don't attack other mobs
|
||||
melee_damage_upper = 0
|
||||
melee_damage_lower = 0
|
||||
attack_sound = null
|
||||
obj_damage = 0
|
||||
environment_smash = ENVIRONMENT_SMASH_NONE
|
||||
|
||||
//List of objects that we don't even want to try to tamper with
|
||||
//Subtypes of these are calculated too
|
||||
var/list/unwanted_objects = list(/obj/machinery/atmospherics/pipe, /turf, /obj/structure) //ensure gremlins dont try to fuck with walls / normal pipes / glass / etc
|
||||
|
||||
var/min_next_vent = 0
|
||||
|
||||
//Amount of ticks spent pathing to the target. If it gets above a certain amount, assume that the target is unreachable and stop
|
||||
var/time_chasing_target = 0
|
||||
|
||||
//If you're going to make gremlins slower, increase this value - otherwise gremlins will abandon their targets too early
|
||||
var/max_time_chasing_target = 2
|
||||
|
||||
var/next_eat = 0
|
||||
|
||||
//Last 20 heard messages are remembered by gremlins, and will be used to generate messages for comms console tampering, etc...
|
||||
var/list/hear_memory = list()
|
||||
var/const/max_hear_memory = 20
|
||||
|
||||
/mob/living/simple_animal/hostile/gremlin/Initialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
|
||||
ADD_TRAIT(src, TRAIT_SHOCKIMMUNE, INNATE_TRAIT)
|
||||
access_card = new /obj/item/card/id(src)
|
||||
var/datum/job/captain/C = new /datum/job/captain
|
||||
access_card.access = C.get_access()
|
||||
if(!body_color)
|
||||
body_color = pick(list("orange","blue","purple", "green", "crystal"))
|
||||
AddElement(/datum/element/mob_holder, "gremlin_[body_color]")
|
||||
icon_state = "gremlin_[body_color]"
|
||||
icon_living = "gremlin_[body_color]"
|
||||
icon_dead = "gremlin_[body_color]_dead"
|
||||
|
||||
/mob/living/simple_animal/hostile/gremlin/AttackingTarget()
|
||||
var/is_hungry = world.time >= next_eat || prob(25)
|
||||
if(istype(target, /obj/item/reagent_containers/food) && is_hungry) //eat food if we're hungry or bored
|
||||
visible_message("<span class='danger'>[src] hungrily devours [target]!</span>")
|
||||
playsound(src, 'sound/items/eatfood.ogg', 50, 1)
|
||||
qdel(target)
|
||||
LoseTarget()
|
||||
next_eat = world.time + rand(700, 3000) //anywhere from 70 seconds to 5 minutes until the gremlin is hungry again
|
||||
return
|
||||
if(istype(target, /obj))
|
||||
var/obj/M = target
|
||||
tamper(M)
|
||||
if(prob(50)) //50% chance to move to the next machine
|
||||
LoseTarget()
|
||||
|
||||
/mob/living/simple_animal/hostile/gremlin/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if(message)
|
||||
hear_memory.Insert(1, raw_message)
|
||||
if(hear_memory.len > max_hear_memory)
|
||||
hear_memory.Cut(hear_memory.len)
|
||||
|
||||
/mob/living/simple_animal/hostile/gremlin/proc/generate_markov_input()
|
||||
var/result = ""
|
||||
|
||||
for(var/memory in hear_memory)
|
||||
result += memory + " "
|
||||
|
||||
return result
|
||||
|
||||
/mob/living/simple_animal/hostile/gremlin/proc/generate_markov_chain()
|
||||
return markov_chain(generate_markov_input(), rand(2,5), rand(100,700)) //The numbers are chosen arbitarily
|
||||
|
||||
/mob/living/simple_animal/hostile/gremlin/proc/tamper(obj/M)
|
||||
switch(M.npc_tamper_act(src))
|
||||
if(NPC_TAMPER_ACT_FORGET)
|
||||
visible_message(pick(
|
||||
"<span class='notice'>\The [src] plays around with \the [M], but finds it rather boring.</span>",
|
||||
"<span class='notice'>\The [src] tries to think of some more ways to screw \the [M] up, but fails miserably.</span>",
|
||||
"<span class='notice'>\The [src] decides to ignore \the [M], and starts looking for something more fun.</span>"))
|
||||
|
||||
LAZYADD(GLOB.bad_gremlin_items,M.type)
|
||||
return FALSE
|
||||
if(NPC_TAMPER_ACT_NOMSG)
|
||||
//Don't create a visible message
|
||||
return TRUE
|
||||
|
||||
else
|
||||
visible_message(pick(
|
||||
"<span class='danger'>\The [src]'s eyes light up as \he tampers with \the [M].</span>",
|
||||
"<span class='danger'>\The [src] twists some knobs around on \the [M] and bursts into laughter!</span>",
|
||||
"<span class='danger'>\The [src] presses a few buttons on \the [M] and giggles mischievously.</span>",
|
||||
"<span class='danger'>\The [src] rubs its hands devilishly and starts messing with \the [M].</span>",
|
||||
"<span class='danger'>\The [src] turns a small valve on \the [M].</span>"))
|
||||
|
||||
//Add a clue for detectives to find. The clue is only added if no such clue already existed on that machine
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/gremlin/CanAttack(atom/new_target)
|
||||
if(LAZYFIND(GLOB.bad_gremlin_items,new_target.type))
|
||||
return FALSE
|
||||
if(is_type_in_list(new_target, unwanted_objects))
|
||||
return FALSE
|
||||
if(istype(new_target, /obj/machinery))
|
||||
var/obj/machinery/M = new_target
|
||||
if(M.stat) //Unpowered or broken
|
||||
return FALSE
|
||||
else if(istype(new_target, /obj/machinery/door/firedoor))
|
||||
var/obj/machinery/door/firedoor/F = new_target
|
||||
//Only tamper with firelocks that are closed, opening them!
|
||||
if(!F.density)
|
||||
return FALSE
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/gremlin/death(gibbed)
|
||||
walk(src,0)
|
||||
QDEL_NULL(access_card)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/gremlin/Life()
|
||||
. = ..()
|
||||
if(!health || stat == DEAD)
|
||||
return
|
||||
//Don't try to path to one target for too long. If it takes longer than a certain amount of time, assume it can't be reached and find a new one
|
||||
if(!client) //don't do this shit if there's a client, they're capable of ventcrawling manually
|
||||
if(in_vent)
|
||||
target = null
|
||||
if(entry_vent && get_dist(src, entry_vent) <= 1)
|
||||
var/list/vents = list()
|
||||
var/datum/pipeline/entry_vent_parent = entry_vent.parents[1]
|
||||
for(var/obj/machinery/atmospherics/components/unary/vent_pump/temp_vent in entry_vent_parent.other_atmosmch)
|
||||
vents += temp_vent
|
||||
if(!vents.len)
|
||||
entry_vent = null
|
||||
in_vent = FALSE
|
||||
return
|
||||
exit_vent = pick(vents)
|
||||
visible_message("<span class='notice'>[src] crawls into the ventilation ducts!</span>")
|
||||
|
||||
loc = exit_vent
|
||||
var/travel_time = round(get_dist(loc, exit_vent.loc) / 2)
|
||||
addtimer(CALLBACK(src, .proc/exit_vents), travel_time) //come out at exit vent in 2 to 20 seconds
|
||||
|
||||
|
||||
if(world.time > min_next_vent && !entry_vent && !in_vent && prob(GREMLIN_VENT_CHANCE)) //small chance to go into a vent
|
||||
for(var/obj/machinery/atmospherics/components/unary/vent_pump/v in view(7,src))
|
||||
if(!v.welded)
|
||||
entry_vent = v
|
||||
in_vent = TRUE
|
||||
walk_to(src, entry_vent)
|
||||
break
|
||||
if(!target)
|
||||
time_chasing_target = 0
|
||||
else
|
||||
if(++time_chasing_target > max_time_chasing_target)
|
||||
LoseTarget()
|
||||
time_chasing_target = 0
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/gremlin/EscapeConfinement()
|
||||
if(istype(loc, /obj) && CanAttack(loc)) //If we're inside a machine, screw with it
|
||||
var/obj/M = loc
|
||||
tamper(M)
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/gremlin/proc/exit_vents()
|
||||
if(!exit_vent || exit_vent.welded)
|
||||
loc = entry_vent
|
||||
entry_vent = null
|
||||
return
|
||||
loc = exit_vent.loc
|
||||
entry_vent = null
|
||||
exit_vent = null
|
||||
in_vent = FALSE
|
||||
var/area/new_area = get_area(loc)
|
||||
message_admins("[src] came out at [new_area][ADMIN_JMP(loc)]!")
|
||||
if(new_area)
|
||||
new_area.Entered(src)
|
||||
visible_message("<span class='notice'>[src] climbs out of the ventilation ducts!</span>")
|
||||
min_next_vent = world.time + 900 //90 seconds between ventcrawls
|
||||
|
||||
//This allows player-controlled gremlins to tamper with machinery
|
||||
/mob/living/simple_animal/hostile/gremlin/UnarmedAttack(var/atom/A)
|
||||
if(istype(A, /obj/machinery) || istype(A, /obj/structure))
|
||||
tamper(A)
|
||||
if(istype(target, /obj/item/reagent_containers/food)) //eat food
|
||||
visible_message("<span class='danger'>[src] hungrily devours [target]!</span>", "<span class='danger'>You hungrily devour [target]!</span>")
|
||||
playsound(src, 'sound/items/eatfood.ogg', 50, 1)
|
||||
qdel(target)
|
||||
LoseTarget()
|
||||
next_eat = world.time + rand(700, 3000) //anywhere from 70 seconds to 5 minutes until the gremlin is hungry again
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/gremlin/IsAdvancedToolUser()
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/gremlin/proc/divide()
|
||||
//Health is halved and then reduced by 2. A new gremlin is spawned with the same health as the parent
|
||||
//Need to have at least 6 health for this, otherwise resulting health would be less than 1
|
||||
if(health < 7.5)
|
||||
return
|
||||
|
||||
visible_message("<span class='notice'>\The [src] splits into two!</span>")
|
||||
var/mob/living/simple_animal/hostile/gremlin/G = new /mob/living/simple_animal/hostile/gremlin(get_turf(src))
|
||||
|
||||
if(mind)
|
||||
mind.transfer_to(G)
|
||||
|
||||
health = round(health * 0.5) - 2
|
||||
maxHealth = health
|
||||
resize *= 0.9
|
||||
|
||||
G.health = health
|
||||
G.maxHealth = maxHealth
|
||||
|
||||
/mob/living/simple_animal/hostile/gremlin/traitor
|
||||
health = 85
|
||||
maxHealth = 85
|
||||
gold_core_spawnable = 0
|
||||
@@ -0,0 +1,214 @@
|
||||
/obj/proc/npc_tamper_act(mob/living/L)
|
||||
return NPC_TAMPER_ACT_FORGET
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/passive_gate/npc_tamper_act(mob/living/L)
|
||||
if(prob(50)) //Turn on/off
|
||||
on = !on
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(L)]", INVESTIGATE_ATMOS)
|
||||
else //Change pressure
|
||||
target_pressure = rand(0, MAX_OUTPUT_PRESSURE)
|
||||
investigate_log("was set to [target_pressure] kPa by [key_name(L)]", INVESTIGATE_ATMOS)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/pump/npc_tamper_act(mob/living/L)
|
||||
if(prob(50)) //Turn on/off
|
||||
on = !on
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(L)]", INVESTIGATE_ATMOS)
|
||||
else //Change pressure
|
||||
target_pressure = rand(0, MAX_OUTPUT_PRESSURE)
|
||||
investigate_log("was set to [target_pressure] kPa by [key_name(L)]", INVESTIGATE_ATMOS)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/volume_pump/npc_tamper_act(mob/living/L)
|
||||
if(prob(50)) //Turn on/off
|
||||
on = !on
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(L)]", INVESTIGATE_ATMOS)
|
||||
else //Change pressure
|
||||
transfer_rate = rand(0, MAX_TRANSFER_RATE)
|
||||
investigate_log("was set to [transfer_rate] L/s by [key_name(L)]", INVESTIGATE_ATMOS)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/valve/npc_tamper_act(mob/living/L)
|
||||
attack_hand(L)
|
||||
|
||||
/obj/machinery/space_heater/npc_tamper_act(mob/living/L)
|
||||
var/list/choose_modes = list("standby", "heat", "cool")
|
||||
if(prob(50))
|
||||
choose_modes -= mode
|
||||
mode = pick(choose_modes)
|
||||
else
|
||||
on = !on
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/shield_gen/npc_tamper_act(mob/living/L)
|
||||
attack_hand(L)
|
||||
|
||||
/obj/machinery/firealarm/npc_tamper_act(mob/living/L)
|
||||
alarm()
|
||||
|
||||
/obj/machinery/airalarm/npc_tamper_act(mob/living/L)
|
||||
if(panel_open)
|
||||
wires.npc_tamper(L)
|
||||
else
|
||||
panel_open = !panel_open
|
||||
|
||||
/obj/machinery/ignition_switch/npc_tamper_act(mob/living/L)
|
||||
attack_hand(L)
|
||||
|
||||
/obj/machinery/flasher_button/npc_tamper_act(mob/living/L)
|
||||
attack_hand(L)
|
||||
|
||||
/obj/machinery/crema_switch/npc_tamper_act(mob/living/L)
|
||||
attack_hand(L)
|
||||
|
||||
/obj/machinery/camera/npc_tamper_act(mob/living/L)
|
||||
if(!panel_open)
|
||||
panel_open = !panel_open
|
||||
if(wires)
|
||||
wires.npc_tamper(L)
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/cryo_cell/npc_tamper_act(mob/living/L)
|
||||
if(prob(50))
|
||||
if(beaker)
|
||||
beaker.forceMove(loc)
|
||||
beaker = null
|
||||
else
|
||||
if(occupant)
|
||||
if(state_open)
|
||||
if (close_machine() == usr)
|
||||
on = TRUE
|
||||
else
|
||||
open_machine()
|
||||
|
||||
/obj/machinery/door_control/npc_tamper_act(mob/living/L)
|
||||
attack_hand(L)
|
||||
|
||||
/obj/machinery/door/airlock/npc_tamper_act(mob/living/L)
|
||||
//Open the firelocks as well, otherwise they block the way for our gremlin which isn't fun
|
||||
for(var/obj/machinery/door/firedoor/F in get_turf(src))
|
||||
if(F.density)
|
||||
F.npc_tamper_act(L)
|
||||
|
||||
if(prob(40)) //40% - mess with wires
|
||||
if(!panel_open)
|
||||
panel_open = !panel_open
|
||||
if(wires)
|
||||
wires.npc_tamper(L)
|
||||
else //60% - just open it
|
||||
open()
|
||||
|
||||
/obj/machinery/gibber/npc_tamper_act(mob/living/L)
|
||||
attack_hand(L)
|
||||
|
||||
/obj/machinery/light_switch/npc_tamper_act(mob/living/L)
|
||||
attack_hand(L)
|
||||
|
||||
/obj/machinery/turretid/npc_tamper_act(mob/living/L)
|
||||
enabled = rand(0, 1)
|
||||
lethal = rand(0, 1)
|
||||
updateTurrets()
|
||||
|
||||
/obj/machinery/vending/npc_tamper_act(mob/living/L)
|
||||
if(!panel_open)
|
||||
panel_open = !panel_open
|
||||
if(wires)
|
||||
wires.npc_tamper(L)
|
||||
|
||||
/obj/machinery/shower/npc_tamper_act(mob/living/L)
|
||||
attack_hand(L)
|
||||
|
||||
|
||||
/obj/machinery/deepfryer/npc_tamper_act(mob/living/L)
|
||||
//Deepfry a random nearby item
|
||||
var/list/pickable_items = list()
|
||||
|
||||
for(var/obj/item/I in range(1, L))
|
||||
pickable_items.Add(I)
|
||||
|
||||
if(!pickable_items.len)
|
||||
return
|
||||
|
||||
var/obj/item/I = pick(pickable_items)
|
||||
|
||||
attackby(I, L) //shove the item in, even if it can't be deepfried normally
|
||||
|
||||
/obj/machinery/power/apc/npc_tamper_act(mob/living/L)
|
||||
if(!panel_open)
|
||||
panel_open = !panel_open
|
||||
if(wires)
|
||||
wires.npc_tamper(L)
|
||||
|
||||
/obj/machinery/power/rad_collector/npc_tamper_act(mob/living/L)
|
||||
attack_hand(L)
|
||||
|
||||
/obj/machinery/power/emitter/npc_tamper_act(mob/living/L)
|
||||
attack_hand(L)
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/npc_tamper_act(mob/living/L)
|
||||
if(!panel_open)
|
||||
panel_open = !panel_open
|
||||
if(wires)
|
||||
wires.npc_tamper(L)
|
||||
|
||||
/obj/machinery/computer/communications/npc_tamper_act(mob/living/user)
|
||||
if(!authenticated)
|
||||
if(prob(20)) //20% chance to log in
|
||||
authenticated = TRUE
|
||||
|
||||
else //Already logged in
|
||||
if(prob(50)) //50% chance to log off
|
||||
authenticated = FALSE
|
||||
else if(istype(user, /mob/living/simple_animal/hostile/gremlin)) //make a hilarious public message
|
||||
var/mob/living/simple_animal/hostile/gremlin/G = user
|
||||
var/result = G.generate_markov_chain()
|
||||
|
||||
if(result)
|
||||
if(prob(85))
|
||||
SScommunications.make_announcement(G, FALSE, result)
|
||||
var/turf/T = get_turf(G)
|
||||
log_say("[key_name(usr)] ([ADMIN_JMP(T)]) has made a captain announcement: [result]")
|
||||
message_admins("[key_name_admin(G)] has made a captain announcement.", 1)
|
||||
else
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_IDLE)
|
||||
SSshuttle.requestEvac(G, result)
|
||||
else if(SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
|
||||
SSshuttle.cancelEvac(G)
|
||||
|
||||
/obj/machinery/button/door/npc_tamper_act(mob/living/L)
|
||||
attack_hand(L)
|
||||
|
||||
/obj/machinery/sleeper/npc_tamper_act(mob/living/L)
|
||||
if(prob(75))
|
||||
inject_chem(pick(available_chems))
|
||||
else
|
||||
if(state_open)
|
||||
close_machine()
|
||||
else
|
||||
open_machine()
|
||||
|
||||
/obj/machinery/power/smes/npc_tamper_act(mob/living/L)
|
||||
if(prob(50)) //mess with input
|
||||
input_level = rand(0, input_level_max)
|
||||
else //mess with output
|
||||
output_level = rand(0, output_level_max)
|
||||
|
||||
/obj/machinery/syndicatebomb/npc_tamper_act(mob/living/L) //suicide bomber gremlins
|
||||
if(!open_panel)
|
||||
open_panel = !open_panel
|
||||
if(wires)
|
||||
wires.npc_tamper(L)
|
||||
|
||||
/obj/machinery/computer/bank_machine/npc_tamper_act(mob/living/L)
|
||||
siphoning = !siphoning
|
||||
|
||||
/obj/machinery/computer/slot_machine/npc_tamper_act(mob/living/L)
|
||||
spin(L)
|
||||
|
||||
/obj/structure/sink/npc_tamper_act(mob/living/L)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/gremlin))
|
||||
visible_message("<span class='danger'>\The [L] climbs into \the [src] and turns the faucet on!</span>")
|
||||
|
||||
var/mob/living/simple_animal/hostile/gremlin/G = L
|
||||
G.divide()
|
||||
|
||||
return NPC_TAMPER_ACT_NOMSG
|
||||
@@ -0,0 +1,44 @@
|
||||
/datum/round_event_control/gremlin
|
||||
name = "Spawn Gremlins"
|
||||
typepath = /datum/round_event/gremlin
|
||||
weight = 15
|
||||
max_occurrences = 2
|
||||
earliest_start = 20 MINUTES
|
||||
min_players = 5
|
||||
|
||||
|
||||
|
||||
/datum/round_event/gremlin
|
||||
var/static/list/acceptable_spawns = list("xeno_spawn", "generic event spawn", "blobstart", "Assistant")
|
||||
|
||||
/datum/round_event/gremlin/announce()
|
||||
priority_announce("Bioscans indicate that some gremlins entered through the vents. Deal with them!", "Gremlin Alert", 'sound/ai/beep.ogg')
|
||||
|
||||
/datum/round_event/gremlin/start()
|
||||
|
||||
var/list/spawn_locs = list()
|
||||
|
||||
for(var/obj/effect/landmark/L in GLOB.landmarks_list)
|
||||
if(isturf(L.loc) && !isspaceturf(L.loc))
|
||||
if(L.name in acceptable_spawns)
|
||||
spawn_locs += L.loc
|
||||
if(!spawn_locs.len) //If we can't find any gremlin spawns, try the xeno spawns
|
||||
for(var/obj/effect/landmark/L in GLOB.landmarks_list)
|
||||
if(isturf(L.loc))
|
||||
switch(L.name)
|
||||
if("Assistant")
|
||||
spawn_locs += L.loc
|
||||
if(!spawn_locs.len) //If we can't find THAT, then just give up and cry
|
||||
return MAP_ERROR
|
||||
|
||||
var/gremlins_to_spawn = rand(2,5)
|
||||
var/list/gremlin_areas = list()
|
||||
for(var/i = 0, i <= gremlins_to_spawn, i++)
|
||||
var/spawnat = pick(spawn_locs)
|
||||
spawn_locs -= spawnat
|
||||
gremlin_areas += get_area(spawnat)
|
||||
new /mob/living/simple_animal/hostile/gremlin(spawnat)
|
||||
var/grems = gremlin_areas.Join(", ")
|
||||
message_admins("Gremlins have been spawned at the areas: [grems]")
|
||||
log_game("Gremlins have been spawned at the areas: [grems]")
|
||||
return SUCCESSFUL_SPAWN
|
||||
@@ -1001,3 +1001,5 @@
|
||||
glass_desc = "A Summer time drink that can be frozen and eaten or Drinked from a glass!"
|
||||
glass_name = "Orange Creamsicle"
|
||||
hydration = 4
|
||||
|
||||
|
||||
|
||||
@@ -158,10 +158,10 @@
|
||||
var/altered_height
|
||||
altered_height = input(user, "Choose your desired sprite size:\n([MIN_BODYSIZE]-400%)", "Height Alteration") as num|null
|
||||
if(altered_height)
|
||||
H.size_multiplier = (max(min( round(text2num(altered_height)),400),MIN_BODYSIZE))/100
|
||||
H.size_multiplier = (max(min( round(text2num(altered_height)),1000),MIN_BODYSIZE))/100
|
||||
playsound(user.loc, pshoom_or_beepboopblorpzingshadashwoosh, 40, 1)
|
||||
do_sparks(5, FALSE, user.loc)
|
||||
H.visible_message("<span class='danger'>[pick("[H] shifts in size!", "[H] alters in height!", "[H] reshapes into a new stature!")]</span>")
|
||||
|
||||
else
|
||||
return
|
||||
return
|
||||
|
||||
@@ -195,7 +195,7 @@
|
||||
burn_dam += burn
|
||||
|
||||
if(status == BODYPART_ORGANIC) //pain is only applied to organic organs, because nerves.
|
||||
pain_dam += (brute+burn)*1.2 //add the total damage applied to the limb as pain damage, build pain quicker, because sudden pain is more.. painful.
|
||||
pain_dam += (brute+burn)*1.05 //add the total damage applied to the limb as pain damage, build pain quicker, because sudden pain is more.. painful.
|
||||
|
||||
//We've dealt the physical damages, if there's room lets apply the stamina damage.
|
||||
var/current_damage = get_damage(TRUE) //This time around, count stamina loss too.
|
||||
|
||||
@@ -111,7 +111,8 @@
|
||||
/obj/item/clothing/ears/headphones = 2,
|
||||
/obj/item/clothing/head/wig/random = 3,
|
||||
/obj/item/clothing/suit/ran = 2,
|
||||
/obj/item/clothing/head/ran = 2)
|
||||
/obj/item/clothing/head/ran = 2,
|
||||
/obj/item/clothing/under/vaultsuit = 3)
|
||||
contraband = list(/obj/item/clothing/suit/judgerobe = 1,
|
||||
/obj/item/clothing/head/powdered_wig = 1,
|
||||
/obj/item/gun/magic/wand = 2,
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
/obj/item/clothing/suit/toggle/jacket_white = 3,
|
||||
/obj/item/clothing/suit/jacket/letterman_red = 3,
|
||||
/obj/item/clothing/suit/fluffyhalfcrop = 3,
|
||||
/obj/item/clothing/under/officesexy = 3,
|
||||
/obj/item/clothing/ears/headphones = 10,
|
||||
/obj/item/clothing/suit/apron/purple_bartender = 4,
|
||||
/obj/item/clothing/under/rank/bartender/purple = 4,
|
||||
@@ -133,6 +134,7 @@
|
||||
/obj/item/clothing/head/cowboyhat/pink = 3,
|
||||
/obj/item/clothing/shoes/cowboyboots = 3,
|
||||
/obj/item/clothing/shoes/cowboyboots/black = 3,
|
||||
/obj/item/clothing/under/raccveralls = 3,
|
||||
/obj/item/clothing/under/polychromic/vsweater = 3)
|
||||
contraband = list(/obj/item/clothing/under/syndicate/tacticool = 3,
|
||||
/obj/item/clothing/under/syndicate/tacticool/skirt = 3,
|
||||
|
||||
@@ -46,7 +46,8 @@
|
||||
/obj/item/seeds/tower = 3,
|
||||
/obj/item/seeds/watermelon = 3,
|
||||
/obj/item/seeds/wheat = 3,
|
||||
/obj/item/seeds/whitebeet = 3)
|
||||
/obj/item/seeds/whitebeet = 3,
|
||||
/obj/item/seeds/kalyna = 3) //Hyperstation addition
|
||||
|
||||
contraband=list(/obj/item/seeds/amanita = 2,
|
||||
/obj/item/seeds/glowshroom = 2,
|
||||
|
||||
Reference in New Issue
Block a user