Merge branch 'master' of https://github.com/ParadiseSS13/Paradise into turfs

# Conflicts:
#	code/__DEFINES/misc.dm
#	code/modules/mob/living/simple_animal/hostile/hostile.dm
#	code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
#	code/modules/shuttle/shuttle.dm
#	icons/mob/actions/actions.dmi
#	paradise.dme
This commit is contained in:
Mark van Alphen
2019-05-04 03:16:38 +02:00
83 changed files with 1247 additions and 2868 deletions
-30
View File
@@ -72,7 +72,6 @@ var/list/admin_verbs_admin = list(
/client/proc/change_human_appearance_admin, /* Allows an admin to change the basic appearance of human-based mobs */
/client/proc/change_human_appearance_self, /* Allows the human-based mob itself change its basic appearance */
/client/proc/debug_variables,
/client/proc/show_snpc_verbs,
/client/proc/reset_all_tcs, /*resets all telecomms scripts*/
/client/proc/toggle_mentor_chat,
/client/proc/toggle_advanced_interaction, /*toggle admin ability to interact with not only machines, but also atoms such as buttons and doors*/
@@ -216,11 +215,6 @@ var/list/admin_verbs_proccall = list(
/client/proc/callproc_datum,
/client/proc/SDQL2_query
)
var/list/admin_verbs_snpc = list(
/client/proc/resetSNPC,
/client/proc/customiseSNPC,
/client/proc/hide_snpc_verbs
)
var/list/admin_verbs_ticket = list(
/client/proc/openAdminTicketUI,
/client/proc/toggleticketlogs,
@@ -291,8 +285,6 @@ var/list/admin_verbs_ticket = list(
admin_verbs_proccall,
admin_verbs_show_debug_verbs,
/client/proc/readmin,
admin_verbs_snpc,
/client/proc/hide_snpc_verbs,
admin_verbs_ticket
)
@@ -1013,28 +1005,6 @@ var/list/admin_verbs_ticket = list(
log_admin("[key_name(usr)] told everyone to man up and deal with it.")
message_admins("[key_name_admin(usr)] told everyone to man up and deal with it.")
/client/proc/show_snpc_verbs()
set name = "Show SNPC Verbs"
set category = "Admin"
if(!check_rights(R_ADMIN))
return
verbs += admin_verbs_snpc
verbs -= /client/proc/show_snpc_verbs
to_chat(src, "<span class='interface'>SNPC verbs have been toggled on.</span>")
/client/proc/hide_snpc_verbs()
set name = "Hide SNPC Verbs"
set category = "Admin"
if(!check_rights(R_ADMIN))
return
verbs -= admin_verbs_snpc
verbs += /client/proc/show_snpc_verbs
to_chat(src, "<span class='interface'>SNPC verbs have been toggled off.</span>")
/client/proc/toggle_advanced_interaction()
set name = "Toggle Advanced Admin Interaction"
set category = "Admin"
+1 -4
View File
@@ -390,10 +390,7 @@
/datum/admins/proc/check_antagonists_line(mob/M, caption = "", close = 1)
var/logout_status
if(istype(M, /mob/living/carbon/human/interactive))
logout_status = " <i>(snpc)</i>"
else
logout_status = M.client ? "" : " <i>(logged out)</i>"
logout_status = M.client ? "" : " <i>(logged out)</i>"
var/dname = M.real_name
if(!dname)
dname = M
@@ -170,7 +170,7 @@ var/global/sent_syndicate_infiltration_team = 0
equip_or_collect(new /obj/item/pda(src), slot_in_backpack)
// Other gear
equip_to_slot_or_del(new /obj/item/clothing/shoes/syndigaloshes(src), slot_shoes)
equip_to_slot_or_del(new /obj/item/clothing/shoes/chameleon/noslip(src), slot_shoes)
var/obj/item/card/id/syndicate/W = new(src)
if (flag_mgmt)
@@ -152,14 +152,6 @@
/obj/machinery/door/unpowered/hotel_door/autoclose()
if(!density && !operating && autoclose)
close()
/obj/machinery/door/unpowered/hotel_door/emag_act(mob/user)
if(isliving(user) && density)
var/obj/effect/hotel_controller/H
if(H.controller)
H.controller.deploy_sec(user)
..()
/obj/item/card/hotel_card
name = "Key Card"
icon_state = "guest"
@@ -283,20 +275,4 @@
spawn(300)
if(D.occupant == deadbeat)
// they still haven't checked out...
deploy_sec(deadbeat)
checkout(roomid)
/obj/effect/hotel_controller/proc/deploy_sec(mob/living/target)
if(!istype(target) || !istype(get_area(target), /area/awaymission/spacehotel))
return
var/list/secs[0]
for(var/mob/living/carbon/human/interactive/away/hotel/guard/M in get_area(src))
if(!M.retal)
secs += M
var/mob/living/carbon/human/interactive/away/hotel/guard/S = safepick(secs)
if(!S)
return
S.retal_target = target
S.retal = 1
checkout(roomid)
@@ -1,132 +0,0 @@
/mob/living/carbon/human/interactive/away/hotel
away_area = /area/awaymission/spacehotel
override_under = /obj/item/clothing/under/mafia
chattyness = SNPC_CHANCE_TALK / 4
/mob/living/carbon/human/interactive/away/hotel/Initialize(mapload)
. = ..(mapload, /datum/species/skrell)
/mob/living/carbon/human/interactive/away/hotel/doSetup()
..()
MYID.access = list(access_syndicate)
RPID.access = list(access_syndicate)
/mob/living/carbon/human/interactive/away/hotel/guard
default_job = /datum/job/officer
/mob/living/carbon/human/interactive/away/hotel/guard/doSetup()
..("Guard")
// anti-pinata cheese
var/obj/item/implant/dust/D = new /obj/item/implant/dust(src)
D.implant(src)
for(var/obj/item/I in get_all_slots())
I.flags |= NODROP
/mob/living/carbon/human/interactive/away/hotel/guard/KnockOut()
// you'll never take me alive (this triggers the implant)
emote("deathgasp")
if(stat != DEAD)
// mission failed. we'll get em next time
..()
/mob/living/carbon/human/interactive/away/hotel/chef
default_job = /datum/job/chef
away_area = /area/awaymission/spacehotel/kitchen
override_under = /obj/item/clothing/under/mafia/vest
/mob/living/carbon/human/interactive/away/hotel/bartender
default_job = /datum/job/bartender
override_under = /obj/item/clothing/under/mafia/vest
/mob/living/carbon/human/interactive/away/hotel/concierge
override_under = /obj/item/clothing/under/mafia/white
away_area = /area/awaymission/spacehotel/reception
var/list/known_guests[0]
var/obj/effect/hotel_controller/hotel
var/obj/item/card/id/last_seen_id = null
/mob/living/carbon/human/interactive/away/hotel/concierge/random()
..()
equip_or_collect(new /obj/item/clipboard(src), slot_l_hand)
/mob/living/carbon/human/interactive/away/hotel/concierge/doSetup()
..("Concierge")
/mob/living/carbon/human/interactive/away/hotel/concierge/setup_job()
favoured_types = list(/obj/item/paper, /obj/item/clipboard)
functions += list("stamping", "concierge")
restrictedJob = 1
/mob/living/carbon/human/interactive/away/hotel/concierge/proc/concierge()
if(!hotel)
hotel = hotel.controller
if(!hotel)
return
var/verbs_use = pick_list(speak_file, "verbs_use")
var/verbs_touch = pick_list(speak_file, "verbs_touch")
var/verbs_move = pick_list(speak_file, "verbs_move")
var/nouns_generic = pick_list(speak_file, "nouns_generic")
var/adjective_insult = pick_list(speak_file, "adjective_insult")
var/adjective_objects = pick_list(speak_file, "adjective_objects")
var/adjective_generic = pick_list(speak_file, "adjective_generic")
var/curse_words = pick_list(speak_file, "curse_words")
var/found = 0
for(var/mob/living/carbon/human/H in nearby - known_guests)
pointed(H)
known_guests += H
found = 1
if(found)
say("Welcome to [hotel], [nouns_generic]! Please check in by [ing_verb(verbs_move)] and [ing_verb(verbs_use)] your [adjective_objects] ID onto the table.")
return
var/obj/item/card/id
var/id_seen = 0
for(var/obj/item/card/id/I in get_area(src))
id_seen = 1
if(I != last_seen_id)
id = I
if(!id_seen)
last_seen_id = null
return
if(!id)
return
var/turf/idloc = get_turf(id)
if(!Adjacent(idloc))
tryWalk(idloc)
else
// is the last jerk that touched it over here?
var/mob/id_owner
for(var/mob/living/carbon/human/H in nearby)
if(H.ckey == id.fingerprintslast)
id_owner = H
break
if(!id_owner)
say("Whose card is this?")
pointed(id)
return
last_seen_id = id
// Checking in or out?
if(id_owner in hotel.guests)
// Check out
say ("Hope you enjoyed your [adjective_objects] stay at our [adjective_generic] hotel!")
hotel.checkout(hotel.guests[id_owner])
else
// pick a room
var/obj/machinery/door/unpowered/hotel_door/D = safepick(hotel.vacant_rooms)
if(!D)
say("Sorry, all the [adjective_objects] are occupied currently.")
else
// Check in
say("$100 per 10 minutes. The cost will be automatically [past_verb(verbs_touch)] while you're checked in.")
var/obj/item/card/hotel_card/K = hotel.checkin(D.id, id_owner, id)
if(K)
K.forceMove(idloc)
else
say("Your [adjective_insult] [curse_words] card was rejected.")
-85
View File
@@ -1,85 +0,0 @@
/mob/living/carbon/human/interactive/away
var/away_area = /area/awaymission // their overriden job area
var/override_under = null // optional type for uniform, else default for job
var/squad_member = 0 // was spawned by squad
var/home_z
/mob/living/carbon/human/interactive/away/Initialize(mapload)
. = ..()
TRAITS |= TRAIT_ROBUST
faction += "away"
/mob/living/carbon/human/interactive/away/random()
..()
// a little hacky but it should prevent doubled uniforms
if(ispath(override_under, /obj/item/clothing/under))
var/old_under = w_uniform
w_uniform = null
equip_to_slot(new override_under(src), slot_w_uniform)
qdel(old_under)
/mob/living/carbon/human/interactive/away/doSetup()
..()
var/datum/data/pda/app/messenger/M = MYPDA.find_program(/datum/data/pda/app/messenger)
M.toff = 1
/mob/living/carbon/human/interactive/away/job2area()
return away_area
/mob/living/carbon/human/interactive/away/doProcess()
if(!home_z)
home_z = get_turf(z)
if(home_z != get_turf(z))
gib()
..()
/obj/effect/spawner/snpc_squad
name = "squad spawner"
icon = 'icons/mob/screen_gen.dmi'
icon_state = "x"
density = 0
opacity = 0
invisibility = 101
var/squad_type = /mob/living/carbon/human/interactive/away
var/squad_size = 3
var/global/list/squads[0]
var/list/squad
/obj/effect/spawner/snpc_squad/New()
START_PROCESSING(SSobj, src)
squad = squads[squad_type]
if(!squad)
squad = list()
squads[squad_type] = squad
squad += src
/obj/effect/spawner/snpc_squad/Destroy()
squad = null
STOP_PROCESSING(SSobj, src)
return ..()
/obj/effect/spawner/snpc_squad/process()
// check squad memebers
var/living = 0
for(var/mob/living/carbon/human/interactive/away/A in squad)
if(!A.stat)
living++
else
// see if anyone's looking, if not, despawn
var/can_despawn = 1
for(var/mob/living/M in viewers(A, world.view + 1))
if(M.client)
living++ // dead guy that can be seen still takes up a slot
can_despawn = 0
break
if(can_despawn)
squad -= A
qdel(A)
// spawn new ones
if(living < squad_size && !length(viewers(src, world.view)))
var/mob/living/carbon/human/interactive/away/A = new squad_type(loc)
squad += A
A.squad_member = 1
+5 -3
View File
@@ -597,8 +597,9 @@ BLIND // can't see anything
"Drask" = 'icons/mob/species/drask/uniform.dmi',
"Grey" = 'icons/mob/species/grey/uniform.dmi'
)
var/has_sensor = 1//For the crew computer 2 = unable to change mode
var/sensor_mode = 0
var/has_sensor = TRUE//For the crew computer 2 = unable to change mode
var/sensor_mode = SENSOR_OFF
var/random_sensor = TRUE
/*
1 = Report living/dead
2 = Report detailed damages
@@ -610,7 +611,8 @@ BLIND // can't see anything
var/basecolor
/obj/item/clothing/under/rank/New()
sensor_mode = pick(0,1,2,3)
if(random_sensor)
sensor_mode = pick(SENSOR_OFF, SENSOR_LIVING, SENSOR_VITALS, SENSOR_COORDS)
..()
/obj/item/clothing/under/Destroy()
-5
View File
@@ -181,11 +181,6 @@
item_state = "sexymime"
burn_state = FLAMMABLE
/obj/item/clothing/mask/gas/death_commando
name = "Death Commando Mask"
icon_state = "death_commando_mask"
item_state = "death_commando_mask"
/obj/item/clothing/mask/gas/cyborg
name = "cyborg visor"
desc = "Beep boop"
-38
View File
@@ -1,38 +0,0 @@
/obj/item/voice_changer
name = "voice changer"
desc = "A voice scrambling module. If you can see this, report it as a bug on the tracker."
var/voice //If set and item is present in mask/suit, this name will be used for the wearer's speech.
var/active
/obj/item/clothing/mask/gas/voice
name = "gas mask"
// desc = "A face-covering mask that can be connected to an air supply. It seems to house some odd electronics."
var/obj/item/voice_changer/changer
burn_state = FIRE_PROOF
/obj/item/clothing/mask/gas/voice/verb/Toggle_Voice_Changer()
set category = "Object"
set src in usr
changer.active = !changer.active
to_chat(usr, "<span class='notice'>You [changer.active ? "enable" : "disable"] the voice-changing module in \the [src].</span>")
/obj/item/clothing/mask/gas/voice/verb/Set_Voice(name as text)
set category = "Object"
set src in usr
var/voice = sanitize(copytext(name,1,MAX_MESSAGE_LEN))
if(!voice || !length(voice)) return
changer.voice = voice
to_chat(usr, "<span class='notice'>You are now mimicking <B>[changer.voice]</B>.</span>")
/obj/item/clothing/mask/gas/voice/New()
..()
changer = new(src)
/obj/item/clothing/mask/gas/voice/clown
name = "clown wig and mask"
desc = "A true prankster's facial attire. A clown is incomplete without his wig and mask."
icon_state = "clown"
item_state = "clown_hat"
flags = BLOCK_GAS_SMOKE_EFFECT | AIRTIGHT | BLOCKHAIR
@@ -1,21 +1,3 @@
/obj/item/clothing/shoes/syndigaloshes
desc = "A pair of brown shoes. They seem to have extra grip."
name = "brown shoes"
icon_state = "brown"
item_state = "brown"
permeability_coefficient = 0.05
flags = NOSLIP
origin_tech = "syndicate=2"
burn_state = FIRE_PROOF
var/list/clothing_choices = list()
silence_steps = 1
/obj/item/clothing/shoes/syndigaloshes/black
name = "black shoes"
icon_state = "black"
item_color = "black"
desc = "A pair of black shoes. They seem to have extra grip."
/obj/item/clothing/shoes/mime
name = "mime shoes"
icon_state = "mime"
@@ -269,14 +269,13 @@
/obj/item/rig_module/voice/New()
..()
voice_holder = new(src)
voice_holder.active = 0
voice_holder.active = FALSE
/obj/item/rig_module/voice/installed()
..()
holder.speech = src
/obj/item/rig_module/voice/engage()
if(!..())
return 0
@@ -287,17 +286,17 @@
switch(choice)
if("Enable")
active = 1
voice_holder.active = 1
active = TRUE
voice_holder.active = TRUE
to_chat(usr, "<font color='blue'>You enable the speech synthesiser.</font>")
if("Disable")
active = 0
voice_holder.active = 0
active = FALSE
voice_holder.active = FALSE
to_chat(usr, "<font color='blue'>You disable the speech synthesiser.</font>")
if("Set Name")
var/raw_choice = sanitize(input(usr, "Please enter a new name.") as text|null, MAX_NAME_LEN)
if(!raw_choice)
return 0
return FALSE
voice_holder.voice = raw_choice
to_chat(usr, "<font color='blue'>You are now mimicking <B>[voice_holder.voice]</B>.</font>")
return 1
+457 -65
View File
@@ -1,86 +1,478 @@
#define EMP_RANDOMISE_TIME 300
/datum/action/chameleon_outfit
name = "Select Chameleon Outfit"
button_icon_state = "chameleon_outfit"
var/list/outfit_options //By default, this list is shared between all instances. It is not static because if it were, subtypes would not be able to have their own. If you ever want to edit it, copy it first.
/datum/action/chameleon_outfit/New()
..()
initialize_outfits()
/datum/action/chameleon_outfit/proc/initialize_outfits()
var/static/list/standard_outfit_options
if(!standard_outfit_options)
standard_outfit_options = list()
for(var/path in subtypesof(/datum/outfit/job))
var/datum/outfit/O = path
standard_outfit_options[initial(O.name)] = path
sortTim(standard_outfit_options, /proc/cmp_text_asc)
outfit_options = standard_outfit_options
/datum/action/chameleon_outfit/Trigger()
return select_outfit(owner)
/datum/action/chameleon_outfit/proc/select_outfit(mob/user)
if(!user || !IsAvailable())
return FALSE
var/selected = input("Select outfit to change into", "Chameleon Outfit") as null|anything in outfit_options
if(!IsAvailable() || QDELETED(src) || QDELETED(user))
return FALSE
var/outfit_type = outfit_options[selected]
if(!outfit_type)
return FALSE
var/datum/outfit/O = new outfit_type()
var/list/outfit_types = O.get_chameleon_disguise_info()
for(var/V in user.chameleon_item_actions)
var/datum/action/item_action/chameleon/change/A = V
var/done = FALSE
for(var/T in outfit_types)
for(var/name in A.chameleon_list)
if(A.chameleon_list[name] == T)
A.update_look(user, T)
outfit_types -= T
done = TRUE
break
if(done)
break
//hardsuit helmets/suit hoods
if(ispath(O.suit, /obj/item/clothing/suit/hooded) && ishuman(user))
var/mob/living/carbon/human/H = user
//make sure they are actually wearing the suit, not just holding it, and that they have a chameleon hat
if(istype(H.wear_suit, /obj/item/clothing/suit/chameleon) && istype(H.head, /obj/item/clothing/head/chameleon))
var/helmet_type
var/obj/item/clothing/suit/hooded/hooded = O.suit
helmet_type = initial(hooded.hoodtype)
if(helmet_type)
var/obj/item/clothing/head/chameleon/hat = H.head
hat.chameleon_action.update_look(user, helmet_type)
qdel(O)
return TRUE
/datum/action/item_action/chameleon/change
name = "Chameleon Change"
var/list/chameleon_blacklist = list() //This is a typecache
var/list/chameleon_list = list()
var/chameleon_type = null
var/chameleon_name = "Item"
var/emp_timer
/datum/action/item_action/chameleon/change/Grant(mob/M)
if(M && (owner != M))
if(!M.chameleon_item_actions)
M.chameleon_item_actions = list(src)
var/datum/action/chameleon_outfit/O = new /datum/action/chameleon_outfit()
O.Grant(M)
else
M.chameleon_item_actions |= src
..()
/datum/action/item_action/chameleon/change/Remove(mob/M)
if(M && (M == owner))
LAZYREMOVE(M.chameleon_item_actions, src)
if(!LAZYLEN(M.chameleon_item_actions))
var/datum/action/chameleon_outfit/O = locate(/datum/action/chameleon_outfit) in M.actions
qdel(O)
..()
/datum/action/item_action/chameleon/change/proc/initialize_disguises()
if(button)
button.name = "Change [chameleon_name] Appearance"
chameleon_blacklist |= typecacheof(target.type)
for(var/V in typesof(chameleon_type))
if(ispath(V) && ispath(V, /obj/item))
var/obj/item/I = V
if(chameleon_blacklist[V] || (initial(I.flags) & ABSTRACT) || !initial(I.icon_state))
continue
var/chameleon_item_name = "[initial(I.name)] ([initial(I.icon_state)])"
chameleon_list[chameleon_item_name] = I
/datum/action/item_action/chameleon/change/proc/select_look(mob/user)
var/obj/item/picked_item
var/picked_name
picked_name = input("Select [chameleon_name] to change into", "Chameleon [chameleon_name]", picked_name) as null|anything in chameleon_list
if(!picked_name)
return
picked_item = chameleon_list[picked_name]
if(!picked_item)
return
update_look(user, picked_item)
/datum/action/item_action/chameleon/change/proc/random_look(mob/user)
var/picked_name = pick(chameleon_list)
// If a user is provided, then this item is in use, and we
// need to update our icons and stuff
if(user)
update_look(user, chameleon_list[picked_name])
// Otherwise, it's likely a random initialisation, so we
// don't have to worry
else
update_item(chameleon_list[picked_name])
/datum/action/item_action/chameleon/change/proc/update_look(mob/user, obj/item/picked_item)
if(isliving(user))
var/mob/living/C = user
if(C.stat != CONSCIOUS)
return
update_item(picked_item)
var/obj/item/thing = target
thing.update_slot_icon()
UpdateButtonIcon()
/datum/action/item_action/chameleon/change/proc/update_item(obj/item/picked_item)
target.name = initial(picked_item.name)
target.desc = initial(picked_item.desc)
target.icon_state = initial(picked_item.icon_state)
if(isitem(target))
var/obj/item/I = target
I.item_state = initial(picked_item.item_state)
I.item_color = initial(picked_item.item_color)
if(istype(I, /obj/item/clothing) && istype(initial(picked_item), /obj/item/clothing))
var/obj/item/clothing/CL = I
var/obj/item/clothing/PCL = picked_item
CL.flags_cover = initial(PCL.flags_cover)
target.icon = initial(picked_item.icon)
/datum/action/item_action/chameleon/change/Trigger()
if(!IsAvailable())
return
select_look(owner)
return 1
/datum/action/item_action/chameleon/change/proc/emp_randomise(var/amount = EMP_RANDOMISE_TIME)
START_PROCESSING(SSprocessing, src)
random_look(owner)
var/new_value = world.time + amount
if(new_value > emp_timer)
emp_timer = new_value
/datum/action/item_action/chameleon/change/process()
if(world.time > emp_timer)
STOP_PROCESSING(SSprocessing, src)
return
random_look(owner)
/obj/item/clothing/under/chameleon
//starts off as black
name = "black jumpsuit"
icon_state = "black"
item_state = "bl_suit"
item_color = "black"
desc = "It's a plain jumpsuit. It seems to have a small dial on the wrist."
origin_tech = "syndicate=2"
var/list/clothing_choices = list()
burn_state = FIRE_PROOF
armor = list(melee = 10, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 0, rad = 0)
desc = "It's a plain jumpsuit. It has a small dial on the wrist."
sensor_mode = SENSOR_OFF //Hey who's this guy on the Syndicate Shuttle??
random_sensor = FALSE
resistance_flags = NONE
armor = list("melee" = 10, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
New()
..()
var/blocked = list(/obj/item/clothing/under/color/random, /obj/item/clothing/under/rank/centcom) // Stops random coloured jumpsuit and undefined centcomm suit appearing in the list.
for(var/U in subtypesof(/obj/item/clothing/under/color) - blocked)
var/obj/item/clothing/under/V = new U
src.clothing_choices += V
var/datum/action/item_action/chameleon/change/chameleon_action
for(var/U in subtypesof(/obj/item/clothing/under/rank) - blocked)
var/obj/item/clothing/under/V = new U
src.clothing_choices += V
return
/obj/item/clothing/under/chameleon/Initialize()
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/under
chameleon_action.chameleon_name = "Jumpsuit"
chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/clothing/under, /obj/item/clothing/under/color, /obj/item/clothing/under/rank), only_root_path = TRUE)
chameleon_action.initialize_disguises()
/obj/item/clothing/under/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
attackby(obj/item/clothing/under/U as obj, mob/user as mob, params)
..()
if(istype(U, /obj/item/clothing/under/chameleon))
to_chat(user, "<span class='warning'>Nothing happens.</span>")
return
if(istype(U, /obj/item/clothing/under))
if(src.clothing_choices.Find(U))
to_chat(user, "<span class='warning'>Pattern is already recognised by the suit.</span>")
return
src.clothing_choices += U
to_chat(user, "<span class='warning'>Pattern absorbed by the suit.</span>")
/obj/item/clothing/under/chameleon/broken/Initialize()
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/clothing/suit/chameleon
name = "armor"
desc = "A slim armored vest that protects against most types of damage."
icon_state = "armor"
item_state = "armor"
blood_overlay_type = "armor"
resistance_flags = NONE
armor = list("melee" = 10, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
emp_act(severity)
name = "psychedelic"
desc = "Groovy!"
icon_state = "psyche"
item_color = "psyche"
usr.update_inv_w_uniform()
spawn(200)
name = initial(name)
icon_state = initial(icon_state)
item_color = initial(item_color)
desc = initial(desc)
usr.update_inv_w_uniform()
..()
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/clothing/suit/chameleon/Initialize()
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/suit
chameleon_action.chameleon_name = "Suit"
chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/clothing/suit/armor/abductor), only_root_path = TRUE)
chameleon_action.initialize_disguises()
verb/change()
set name = "Change Color"
set category = "Object"
set src in usr
/obj/item/clothing/suit/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
if(icon_state == "psyche")
to_chat(usr, "<span class='warning'>Your suit is malfunctioning</span>")
return
/obj/item/clothing/suit/chameleon/broken/Initialize()
. = ..()
chameleon_action.emp_randomise(INFINITY)
var/obj/item/clothing/under/A
A = input("Select Colour to change it to", "BOOYEA", A) in clothing_choices
if(!A)
return
/obj/item/clothing/glasses/chameleon
name = "Optical Meson Scanner"
desc = "Used by engineering and mining staff to see basic structural and terrain layouts through walls, regardless of lighting condition."
icon_state = "meson"
item_state = "meson"
resistance_flags = NONE
armor = list("melee" = 10, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
desc = null
permeability_coefficient = 0.90
var/datum/action/item_action/chameleon/change/chameleon_action
desc = A.desc
name = A.name
icon_state = A.icon_state
item_state = A.item_state
item_color = A.item_color
usr.update_inv_w_uniform() //so our overlays update.
/obj/item/clothing/glasses/chameleon/Initialize()
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/glasses
chameleon_action.chameleon_name = "Glasses"
chameleon_action.chameleon_blacklist = list()
chameleon_action.initialize_disguises()
/obj/item/clothing/glasses/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/clothing/glasses/chameleon/broken/Initialize()
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/clothing/under/chameleon/all/New()
..()
var/blocked = list(/obj/item/clothing/under/chameleon, /obj/item/clothing/under/chameleon/all)
//to prevent an infinite loop
for(var/U in typesof(/obj/item/clothing/under)-blocked)
var/obj/item/clothing/under/V = new U
src.clothing_choices += V
/obj/item/clothing/gloves/chameleon
desc = "These gloves will protect the wearer from electric shock."
name = "insulated gloves"
icon_state = "yellow"
item_state = "ygloves"
resistance_flags = NONE
armor = list("melee" = 10, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/clothing/gloves/chameleon/Initialize()
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/gloves
chameleon_action.chameleon_name = "Gloves"
chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/clothing/gloves, /obj/item/clothing/gloves/color), only_root_path = TRUE)
chameleon_action.initialize_disguises()
/obj/item/clothing/gloves/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/clothing/gloves/chameleon/broken/Initialize()
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/clothing/head/chameleon
name = "grey cap"
desc = "It's a baseball hat in a tasteful grey colour."
icon_state = "greysoft"
item_color = "grey"
resistance_flags = NONE
armor = list("melee" = 5, "bullet" = 5, "laser" = 5, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/clothing/head/chameleon/Initialize()
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/head
chameleon_action.chameleon_name = "Hat"
chameleon_action.chameleon_blacklist = list()
chameleon_action.initialize_disguises()
/obj/item/clothing/head/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/clothing/head/chameleon/broken/Initialize()
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/clothing/mask/chameleon
name = "gas mask"
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"
item_state = "gas_alt"
resistance_flags = NONE
armor = list("melee" = 5, "bullet" = 5, "laser" = 5, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
flags = AIRTIGHT | BLOCK_GAS_SMOKE_EFFECT
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.01
flags_cover = MASKCOVERSEYES | MASKCOVERSMOUTH
var/obj/item/voice_changer/voice_changer
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/clothing/mask/chameleon/Initialize()
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/mask
chameleon_action.chameleon_name = "Mask"
chameleon_action.chameleon_blacklist = list()
chameleon_action.initialize_disguises()
voice_changer = new(src)
/obj/item/clothing/mask/chameleon/Destroy()
QDEL_NULL(voice_changer)
return ..()
/obj/item/clothing/mask/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/clothing/mask/chameleon/broken/Initialize()
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/clothing/shoes/chameleon
name = "black shoes"
icon_state = "black"
item_color = "black"
desc = "A pair of black shoes."
permeability_coefficient = 0.05
resistance_flags = NONE
armor = list("melee" = 10, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/clothing/shoes/chameleon/Initialize()
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/shoes
chameleon_action.chameleon_name = "Shoes"
chameleon_action.chameleon_blacklist = list()
chameleon_action.initialize_disguises()
/obj/item/clothing/shoes/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/clothing/shoes/chameleon/noslip
name = "black shoes"
icon_state = "black"
item_color = "black"
desc = "A pair of black shoes."
flags = NOSLIP
/obj/item/clothing/shoes/chameleon/noslip/broken/Initialize()
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/storage/backpack/chameleon
name = "backpack"
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/storage/backpack/chameleon/Initialize()
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/storage/backpack
chameleon_action.chameleon_name = "Backpack"
chameleon_action.initialize_disguises()
/obj/item/storage/backpack/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/storage/backpack/chameleon/broken/Initialize()
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/storage/belt/chameleon
name = "toolbelt"
desc = "Holds tools."
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/storage/belt/chameleon/Initialize()
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/storage/belt
chameleon_action.chameleon_name = "Belt"
chameleon_action.initialize_disguises()
/obj/item/storage/belt/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/storage/belt/chameleon/broken/Initialize()
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/radio/headset/chameleon
name = "radio headset"
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/radio/headset/chameleon/Initialize()
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/radio/headset
chameleon_action.chameleon_name = "Headset"
chameleon_action.initialize_disguises()
/obj/item/radio/headset/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/radio/headset/chameleon/broken/Initialize()
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/pda/chameleon
name = "PDA"
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/pda/chameleon/Initialize()
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/pda
chameleon_action.chameleon_name = "PDA"
chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/pda/heads), only_root_path = TRUE)
chameleon_action.initialize_disguises()
/obj/item/pda/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/pda/chameleon/broken/Initialize()
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/stamp/chameleon
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/stamp/chameleon/Initialize()
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/stamp
chameleon_action.chameleon_name = "Stamp"
chameleon_action.initialize_disguises()
/obj/item/stamp/chameleon/broken/Initialize()
. = ..()
chameleon_action.emp_randomise(INFINITY)
+2 -2
View File
@@ -671,8 +671,8 @@ var/list/non_fakeattack_weapons = list(/obj/item/gun/projectile, /obj/item/ammo_
/obj/item/gun/energy/kinetic_accelerator/crossbow,\
/obj/item/storage/box/syndicate, /obj/item/storage/box/emps,\
/obj/item/cartridge/syndicate, /obj/item/clothing/under/chameleon,\
/obj/item/clothing/shoes/syndigaloshes, /obj/item/card/id/syndicate,\
/obj/item/clothing/mask/gas/voice, /obj/item/clothing/glasses/thermal,\
/obj/item/clothing/shoes/chameleon/noslip, /obj/item/card/id/syndicate,\
/obj/item/clothing/mask/chameleon, /obj/item/clothing/glasses/thermal,\
/obj/item/chameleon, /obj/item/card/emag,\
/obj/item/storage/toolbox/syndicate, /obj/item/aiModule,\
/obj/item/radio/headset/syndicate, /obj/item/grenade/plastic/c4,\
+1 -1
View File
@@ -69,7 +69,7 @@
visible_message("<span class='warning'>[src] crackles and buzzes violently!</span>")
/mob/living/simple_animal/hostile/mining_drone/sentience_act()
AIStatus = AI_OFF
..()
check_friendly_fire = 0
/mob/living/simple_animal/hostile/mining_drone/attackby(obj/item/I, mob/user, params)
+3
View File
@@ -83,6 +83,9 @@ obj/structure/ore_box/ex_act(severity, target)
O.forceMove(loc)
CHECK_TICK
/obj/structure/ore_box/onTransitZ()
return
/obj/structure/ore_box/verb/empty_box()
set name = "Empty Ore Box"
set category = "Object"
+1 -1
View File
@@ -20,4 +20,4 @@
for(var/datum/light_source/L in light_sources)
L.source_atom.update_light()
return 1
return 1
@@ -315,15 +315,7 @@
msg += "[p_they(TRUE)] [p_have()] a stupid expression on [p_their()] face.\n"
if(get_int_organ(/obj/item/organ/internal/brain))
if(istype(src, /mob/living/carbon/human/interactive))
var/mob/living/carbon/human/interactive/auto = src
if(auto.showexaminetext)
msg += "<span class='deadsay'>[p_they(TRUE)] [p_are()] appears to be some sort of sick automaton, [p_their()] eyes are glazed over and [p_their()] mouth is slightly agape.</span>\n"
if(auto.debugexamine)
var/dodebug = auto.doing2string(auto.doing)
var/interestdebug = auto.interest2string(auto.interest)
msg += "<span class='deadsay'>[p_they(TRUE)] [p_are()] appears to be [interestdebug] and [dodebug].</span>\n"
else if(dna.species.show_ssd)
if(dna.species.show_ssd)
if(!key)
msg += "<span class='deadsay'>[p_they(TRUE)] [p_are()] totally catatonic. The stresses of life in deep-space must have been too much for [p_them()]. Any recovery is unlikely.</span>\n"
else if(!client)
@@ -1,874 +0,0 @@
/mob/living/carbon/human/interactive/proc/chatter(obj)
var/verbs_use = pick_list(speak_file, "verbs_use")
var/verbs_touch = pick_list(speak_file, "verbs_touch")
var/verbs_move = pick_list(speak_file, "verbs_move")
var/nouns_insult = pick_list(speak_file, "nouns_insult")
var/nouns_generic = pick_list(speak_file, "nouns_generic")
var/nouns_objects = pick_list(speak_file, "nouns_objects")
var/nouns_body = pick_list(speak_file, "nouns_body")
var/adjective_insult = pick_list(speak_file, "adjective_insult")
var/adjective_objects = pick_list(speak_file, "adjective_objects")
var/adjective_generic = pick_list(speak_file, "adjective_generic")
var/curse_words = pick_list(speak_file, "curse_words")
var/chatmsg = ""
if(prob(10)) // 10% chance to broadcast it over the radio
chatmsg = ";"
if(prob(chattyness) || knownStrings.len < 10) // say a generic phrase, otherwise draw from our strings.
if(doing & SNPC_INTERACTING)
if(prob(chattyness))
chatmsg += pick("This [nouns_objects] is a little [adjective_objects].",
"Well [verbs_use] my [nouns_body], this [nouns_insult] is pretty [adjective_insult].",
"[capitalize(curse_words)], what am I meant to do with this [adjective_insult] [nouns_objects].")
else if(doing & SNPC_TRAVEL)
if(prob(chattyness))
chatmsg += pick("Oh [curse_words], [verbs_move]!",
"Time to get my [adjective_generic] [adjective_insult] [nouns_body] elsewhere.",
"I wonder if there is anything to [verbs_use] and [verbs_touch] somewhere else..")
else if(doing & SNPC_FIGHTING)
if(prob(chattyness))
chatmsg += pick("I'm going to [verbs_use] you, you [adjective_insult] [nouns_insult]!",
"Rend and [verbs_touch], Rend and [verbs_use]!",
"You [nouns_insult], I'm going to [verbs_use] you right in the [nouns_body]. JUST YOU WAIT!")
if(prob(chattyness/2))
chatmsg = ";"
var/what = pick(1,2,3,4,5)
switch(what)
if(1)
chatmsg += "Well [curse_words], this is a [adjective_generic] situation."
if(2)
chatmsg += "Oh [curse_words], that [nouns_insult] was one hell of an [adjective_insult] [nouns_body]."
if(3)
chatmsg += "I want to [verbs_use] that [nouns_insult] when I find them."
if(4)
chatmsg += "[pick("Innocent","Guilty","Traitorous","Honk")] until proven [adjective_generic]!"
if(5)
var/toSay = ""
for(var/i = 0; i < 5; i++)
curse_words = pick_list(speak_file, "curse_words")
toSay += "[curse_words] "
chatmsg += "Hey [nouns_generic], why don't you go [copytext(toSay, 1, length(toSay))], you [nouns_insult]!"
else if(prob(chattyness))
chatmsg += pick(knownStrings)
if(prob(25)) // cut out some phrases now and then to make sure we're fresh and new
knownStrings -= pick(chatmsg)
if(chatmsg != ";" && chatmsg != "")
say(chatmsg)
/mob/living/carbon/human/interactive/proc/traitor(obj)
if(traitorType == SNPC_PSYCHO && nearby.len)
traitorTarget = pick(nearby)
if(prob(traitorScale))
if(!Adjacent(traitorTarget) && !(traitorType == SNPC_PSYCHO))
tryWalk(get_turf(traitorTarget))
else
switch(traitorType)
if(SNPC_BRUTE)
retal = 1
retal_target = traitorTarget
if(SNPC_STEALTH)
if(istype(traitorTarget,/mob)) // it's inside something, lets kick their shit in
var/mob/M = traitorTarget
if(!M.stat)
retal = 1
retal_target = traitorTarget
else
var/obj/item/I = traitorTarget
I.loc = get_turf(traitorTarget) // pull it outta them
else
take_to_slot(traitorTarget)
if(SNPC_MARTYR)
custom_emote(1, "[src]'s chest opens up, revealing a large mass of explosives and tangled wires!")
if(inactivity_period <= 0)
inactivity_period = 9999 // technically infinite
if(do_after(src, 60, target = traitorTarget))
custom_emote(1, "A fire bursts from [src]'s eyes, igniting white hot and consuming [p_their()] body in a flaming explosion!")
explosion(src, 6, 6, 6)
else
inactivity_period = 0
custom_emote(1, "[src]'s chest closes, hiding [p_their()] insides.")
if(SNPC_PSYCHO)
var/choice = pick(typesof(/obj/item/grenade/chem_grenade) - /obj/item/grenade/chem_grenade)
new choice(src)
retal = 1
retal_target = traitorTarget
/mob/living/carbon/human/interactive/proc/botany(obj)
if(shouldModulePass())
return
if(enforceHome())
return
var/list/allContents = getAllContents()
var/obj/item/reagent_containers/glass/beaker/bluespace/internalBeaker = locate(/obj/item/reagent_containers/glass/beaker/bluespace) in allContents
var/obj/item/storage/bag/plants/internalBag = locate(/obj/item/storage/bag/plants) in allContents
if(!internalBag)
internalBag = new/obj/item/storage/bag/plants(src)
if(!internalBeaker)
internalBeaker = new/obj/item/reagent_containers/glass/beaker/bluespace(src)
internalBeaker.name = "Grow-U-All Super Spray"
if(internalBeaker && internalBag)
var/obj/machinery/hydroponics/HP
//consider the appropriate target
var/list/considered = list()
for(var/obj/machinery/hydroponics/tester in view(12,src))
considered[tester] = 1
if(!tester.myseed)
considered[tester] += 50
if(tester.weedlevel > 0)
considered[tester] += 5
if(tester.pestlevel > 0)
considered[tester] += 5
if(tester.nutrilevel < tester.maxnutri)
considered[tester] += 15
if(tester.waterlevel < tester.maxwater)
considered[tester] += 15
if(tester.harvest || tester.dead)
considered[tester] += 100
considered[tester] = max(1, considered[tester] - get_dist(src,tester))
var/index = 0
for(var/A in considered)
++index
if(considered[A] > considered[HP] || !HP)
HP = considered[index]
if(HP)
TARGET = HP
if(!Adjacent(HP))
tryWalk(get_turf(HP))
else
if(HP.harvest || HP.dead)
HP.attack_hand(src)
else if(!HP.myseed)
var/obj/item/seeds/SEED = new /obj/item/seeds/random(src)
custom_emote(1, "[pick("gibbers","drools","slobbers","claps wildly","spits")] towards [TARGET], producing a [SEED]!")
HP.attackby(SEED, src)
else
var/change = 0
if(HP.weedlevel > 0)
change = 1
if(!internalBeaker.reagents.has_reagent("atrazine", 10))
internalBeaker.reagents.add_reagent("atrazine", 10)
if(HP.pestlevel > 0)
change = 1
if(!internalBeaker.reagents.has_reagent("diethylamine", 10))
internalBeaker.reagents.add_reagent("diethylamine", 10)
if(HP.nutrilevel < HP.maxnutri)
change = 1
if(!internalBeaker.reagents.has_reagent("eznutriment", 15))
internalBeaker.reagents.add_reagent("eznutriment", 15)
if(!internalBeaker.reagents.has_reagent("diethylamine", 15))
internalBeaker.reagents.add_reagent("diethylamine", 15)
if(HP.waterlevel < HP.maxwater)
change = 1
if(!internalBeaker.reagents.has_reagent("holywater", 50))
internalBeaker.reagents.add_reagent("holywater", 50)
if(change)
HP.attackby(internalBeaker,src)
var/obj/item/reagent_containers/food/snacks/grown/GF = locate(/obj/item/reagent_containers/food/snacks/grown) in view(12,src)
if(GF)
if(!Adjacent(GF))
tryWalk(get_turf(GF))
else
GF.attackby(internalBag,src)
if(internalBag.contents.len)
var/obj/machinery/smartfridge/SF = locate(/obj/machinery/smartfridge) in range(12, src)
if(!Adjacent(SF))
tryWalk(get_turf(SF))
else
custom_emote(1, "[pick("gibbers","drools","slobbers","claps wildly","spits")], upending the [internalBag]'s contents all over the [SF]!")
//smartfridges call updateUsrDialog when you call attackby, so we're going to have to cheese-magic-space this
for(var/obj/toLoad in internalBag.contents)
if(contents.len >= SF.max_n_of_items)
break
if(SF.accept_check(toLoad))
SF.load(toLoad, src)
else
qdel(toLoad) // destroy everything we dont need
/mob/living/carbon/human/interactive/proc/bartend(obj)
if(shouldModulePass())
return
if(enforceHome())
return
var/list/rangeCheck = oview(6,src)
var/obj/structure/table/RT
var/mob/living/carbon/human/serveTarget
for(var/mob/living/carbon/human/H in rangeCheck)
if(!locate(/obj/item/reagent_containers/food/drinks) in orange(1, H))
serveTarget = H
if(serveTarget)
RT = locate(/obj/structure/table) in orange(1, serveTarget)
if(RT && serveTarget)
if(!Adjacent(RT))
tryWalk(get_turf(RT))
else
var/drinkChoice = pick(typesof(/obj/item/reagent_containers/food/drinks) - /obj/item/reagent_containers/food/drinks)
if(drinkChoice)
var/obj/item/reagent_containers/food/drinks/D = new drinkChoice(get_turf(src))
RT.attackby(D,src)
say("[pick("Something to wet your whistle!","Down the hatch, a tasty beverage!","One drink, coming right up!","Tasty liquid for your oral intake!","Enjoy!")]")
custom_emote(2, "[pick("gibbers","drools","slobbers","claps wildly","spits")], serving up a [D]!")
/mob/living/carbon/human/interactive/proc/shitcurity(obj)
var/list/allContents = getAllContents()
if(retal && TARGET)
if(Adjacent(TARGET))
var/obj/item/restraints/R = locate() in allContents
if(R)
R.attack(TARGET, src) // go go bluespace restraint launcher!
else if(TARGET in oview(7, src))
var/obj/item/gun/G = locate() in allContents
if(G)
G.afterattack(TARGET, src)
/mob/living/carbon/human/interactive/proc/clowning(obj)
if(shouldModulePass())
return
var/list/allContents = getAllContents()
var/list/rangeCheck = oview(12, src)
var/mob/living/carbon/human/clownTarget
var/list/clownPriority = list()
var/obj/item/reagent_containers/spray/S
if(!locate(/obj/item/reagent_containers/spray) in allContents)
new/obj/item/reagent_containers/spray(src)
else
S = locate(/obj/item/reagent_containers/spray) in allContents
for(var/mob/living/carbon/human/C in rangeCheck)
var/pranksNearby = 100
for(var/turf/simulated/T in orange(1, C))
for(var/obj/item/A in T)
if(istype(A,/obj/item/soap) || istype(A,/obj/item/reagent_containers/food/snacks/grown/banana) || istype(A,/obj/item/grown/bananapeel))
pranksNearby--
if(T.wet)
pranksNearby -= 10
clownPriority[C] = pranksNearby
for(var/A in clownPriority)
if(!clownTarget)
clownTarget = A
else
if(clownPriority[A] > clownPriority[clownTarget])
clownTarget = clownPriority[A]
if(clownTarget)
if(!Adjacent(clownTarget))
tryWalk(clownTarget)
else
var/hasPranked = 0
for(var/A in allContents)
if(prob(smartness/2) && !hasPranked)
if(istype(A,/obj/item/soap))
npcDrop(A)
hasPranked = 1
if(istype(A,/obj/item/reagent_containers/food/snacks/grown/banana))
var/obj/item/reagent_containers/food/snacks/B = A
B.attack(src, src)
if(istype(A,/obj/item/grown/bananapeel))
npcDrop(A)
hasPranked = 1
if(!hasPranked)
if(S.reagents.total_volume <= 5)
S.reagents.add_reagent("water", 25)
S.afterattack(get_turf(pick(orange(1, clownTarget))),src)
/mob/living/carbon/human/interactive/proc/healpeople(obj)
var/shouldTryHeal = 0
var/obj/item/stack/medical/M
var/list/allContents = getAllContents()
for(var/A in allContents)
if(istype(A,/obj/item/stack/medical))
shouldTryHeal = 1
M = A
var/obj/item/reagent_containers/hypospray/HPS
if(!locate(/obj/item/reagent_containers/hypospray) in allContents)
new/obj/item/reagent_containers/hypospray(src)
else
HPS = locate(/obj/item/reagent_containers/hypospray) in allContents
if(!shouldTryHeal)
shouldTryHeal = 2 // we have no stackables to use, lets use our internal hypospray instead
if(shouldTryHeal == 1)
for(var/mob/living/carbon/human/C in nearby)
if(istype(C,/mob/living/carbon/human)) //I haven't the foggiest clue why this is turning up non-carbons but sure here whatever
if(C.health <= 75)
if(get_dist(src,C) <= 2)
src.say("Wait, [C], let me heal you!")
M.attack(C,src)
sleep(25)
else
tryWalk(get_turf(C))
else if(shouldTryHeal == 2)
if(HPS)
if(HPS.reagents.total_volume <= 0)
HPS.reagents.add_reagent("omnizine",30)
for(var/mob/living/carbon/human/C in nearby)
if(istype(C,/mob/living/carbon/human))
if(C.health <= 75 && C.reagents.get_reagent_amount("omnizine") <= 0) // make sure they wont be overdosing
if(get_dist(src,C) <= 2)
src.say("Wait, [C], let me heal you!")
HPS.attack(C,src)
sleep(25)
else
tryWalk(get_turf(C))
/mob/living/carbon/human/interactive/proc/dojanitor(obj)
if(shouldModulePass())
return
var/list/allContents = getAllContents()
//now with bluespace magic!
var/obj/item/reagent_containers/spray/SP = locate() in allContents
if(!SP)
SP = new /obj/item/reagent_containers/spray(src)
var/obj/item/soap/SO = locate() in allContents
if(!SO)
SO = new /obj/item/soap(src)
if(SP.reagents.total_volume <= 5)
SP.reagents.add_reagent("cleaner", 25) // bluespess water delivery for AI
var/obj/effect/decal/cleanable/TC
TC = locate(/obj/effect/decal/cleanable) in view(6, src)
if(TC)
if(!Adjacent(TC))
tryWalk(TC)
else
var/turf/T = get_turf(TC)
if(T && !T.density)
SP.afterattack(TC, src, 1)
else
SO.afterattack(TC, src, 1)
qdel(TC)
// START COOKING MODULE
/mob/living/carbon/human/interactive/proc/refundrecipe(list/ingredients)
for(var/obj/I in ingredients)
I.loc = contents
// Ingredients may be in the rangeCheck or inside the chef's inventory.
// As they are checked off, they are moved to a seperate list as to not be counted twice
// If the recipe fails (eg somebody else took an ingredient before it was picked up) the ingredients are dumped back to inventory
// That way, the chef has a better chance of making a recipe next ptick, if he has more stuff on him
/mob/living/carbon/human/interactive/proc/makerecipe(datum/recipe/R, allContents, rangeCheck)
set background = 1
var/list/ingredients[0]
for(var/P in R.items)
var/obj/item/I = locate(P) in allContents
if(I)
ingredients += I
I.forceMove(null)
continue
I = locate(P) in rangeCheck
TARGET = I
if(I && !Adjacent(I))
tryWalk(get_turf(I))
sleep(get_dist(src, I))
if(!I || !(I in rangeCheck))
refundrecipe(ingredients)
return 0
custom_emote(1, "[pick("gibbers","drools","slobbers","claps wildly","spits")], picking up [I].")
ingredients += I
I.forceMove(null)
// cheaply cook the ingredients into result
sleep(R.time)
for(var/obj/I in ingredients)
qdel(I)
ingredients.Cut()
var/result = new R.result(get_turf(src))
custom_emote(1, "[pick("gibbers","drools","slobbers","claps wildly","spits")] and, with a bang, \a [result] is cooked!")
return 1
/mob/living/carbon/human/interactive/proc/souschef(obj)
if(shouldModulePass() || enforceHome() || prob(SNPC_FUZZY_CHANCE_HIGH) || prob(SNPC_FUZZY_CHANCE_HIGH))
return
if(doing & SNPC_SPECIAL)
return
doing |= SNPC_SPECIAL
var/static/list/customableTypes = list(/obj/item/reagent_containers/food/snacks/customizable,/obj/item/reagent_containers/food/snacks/breadslice,/obj/item/reagent_containers/food/snacks/bun,/obj/item/reagent_containers/food/snacks/sliceable/flatdough,/obj/item/reagent_containers/food/snacks/boiledspaghetti,/obj/item/trash/plate,/obj/item/trash/bowl)
var/static/list/rawtypes = list(/obj/item/reagent_containers/food/snacks/grown, /obj/item/reagent_containers/food/snacks/rawcutlet, /obj/item/reagent_containers/food/snacks/rawsticks, /obj/item/reagent_containers/food/snacks/salmonmeat, /obj/item/reagent_containers/food/snacks/carpmeat, /obj/item/reagent_containers/food/snacks/catfishmeat, /obj/item/reagent_containers/food/snacks/spaghetti, /obj/item/reagent_containers/food/snacks/dough, /obj/item/reagent_containers/food/snacks/sliceable/flatdough, /obj/item/reagent_containers/food/snacks/doughslice, /obj/item/reagent_containers/food/snacks/meat, /obj/item/reagent_containers/food/snacks/boiledrice, /obj/item/reagent_containers/food/snacks/cheesewedge, /obj/item/reagent_containers/food/snacks/raw_bacon)
try
var/list/allContents = getAllContents()
var/list/rangeCheck = view(6, src)
//Bluespace in some inbuilt tools
var/obj/item/kitchen/rollingpin/RP = locate() in allContents
if(!RP)
RP = new /obj/item/kitchen/rollingpin(src)
var/obj/item/kitchen/knife/KK = locate() in allContents
if(!KK)
KK = new /obj/item/kitchen/knife(src)
var/global/list/available_recipes
if(!available_recipes)
available_recipes = list()
for(var/type in subtypesof(/datum/recipe))
var/datum/recipe/recipe = new type
if(recipe.result) // Ignore recipe subtypes that lack a result
available_recipes += recipe
else
qdel(recipe)
var/foundCookable = 0
//Make some basic custom food
var/foundCustom
for(var/customType in customableTypes)
var/A = locate(customType) in rangeCheck
var/obj/item/reagent_containers/food/snacks/customizable/I = A
if(A && (!istype(I) || I.ingredients.len <= 3))
foundCustom = A // this will eventually wittle down to 0
break
var/obj/machinery/smartfridge/SF = locate(/obj/machinery/smartfridge) in rangeCheck
if(SF)
if(SF.contents.len > 0)
if(!Adjacent(SF))
tryWalk(get_turf(SF))
else
custom_emote(2, "[pick("gibbers","drools","slobbers","claps wildly","spits")], grabbing various foodstuffs from [SF] and sticking them in its mouth!")
for(var/obj/item/A in SF.contents)
if(prob(smartness/2))
var/count = SF.item_quants[A.name]
if(count)
SF.item_quants[A.name] = count - 1
A.forceMove(src)
if(foundCustom)
var/obj/item/reagent_containers/food/snacks/FC = foundCustom
for(var/obj/item/reagent_containers/food/snacks/toMake in allContents)
if(prob(smartness))
if(FC.reagents)
if(toMake.reagents)
var/raw = 0
for(var/type in rawtypes)
if(istype(toMake, type))
raw = 1
break
if(!raw)
npcDrop(toMake)
FC.attackby(toMake, src)
allContents -= toMake
break
else
qdel(FC) // this food is usless, toss it
// Process tool-based ingredients
var/obj/item/reagent_containers/food/snacks/dough/D = locate() in rangeCheck
var/obj/item/reagent_containers/food/snacks/sliceable/flatdough/FD = locate() in rangeCheck
var/obj/item/reagent_containers/food/snacks/rawcutlet/RC = locate() in rangeCheck
var/obj/item/reagent_containers/food/snacks/sliceable/cheesewheel/CW = locate() in rangeCheck
var/obj/item/reagent_containers/food/snacks/grown/potato/PO = locate() in rangeCheck
var/obj/item/reagent_containers/food/snacks/meat/ME = locate() in rangeCheck
var/obj/item/reagent_containers/food/snacks/raw_bacon/RB = locate() in rangeCheck
if(D)
TARGET = D
if(prob(50))
tryWalk(get_turf(D))
sleep(get_dist(src, D))
D.attackby(RP, src)
foundCookable = 1
else if(FD)
TARGET = FD
if(prob(50))
tryWalk(get_turf(FD))
sleep(get_dist(src, FD))
FD.attackby(KK, src)
foundCookable = 1
else if(RC)
TARGET = RC
if(prob(50))
tryWalk(get_turf(RC))
sleep(get_dist(src, RC))
RC.attackby(KK, src)
foundCookable = 1
else if(CW)
TARGET = CW
if(prob(50))
tryWalk(get_turf(CW))
sleep(get_dist(src, CW))
CW.attackby(KK, src)
foundCookable = 1
else if(PO)
TARGET = PO
if(prob(50))
tryWalk(get_turf(PO))
sleep(get_dist(src, PO))
PO.attackby(KK, src)
foundCookable = 1
else if(ME)
TARGET = ME
if(prob(50))
tryWalk(get_turf(ME))
sleep(get_dist(src, ME))
ME.attackby(KK, src)
foundCookable = 1
else if(RB)
TARGET = RB
if(prob(50))
tryWalk(get_turf(RB))
sleep(get_dist(src, RB))
RB.attackby(KK, src)
foundCookable = 1
// refresh
allContents = getAllContents()
rangeCheck = view(6, src)
// Find most complex recipe we can cook
var/ingredientZone = rangeCheck + allContents
var/highest_count = 0
var/datum/recipe/winner = null
for(var/datum/recipe/R in available_recipes)
if(R.check_items(ingredientZone) >= 0)
var/count = (R.items ? R.items.len : 0)
if(count > highest_count)
highest_count = count
winner = R
// make winner
if(winner)
if(makerecipe(winner, allContents, rangeCheck))
foundCookable = 1
// refresh
allContents = getAllContents()
rangeCheck = view(6, src)
// dont display our ingredients
var/list/finishedList = list()
for(var/obj/item/reagent_containers/food/snacks/toDisplay in allContents)
var/raw = 0
for(var/type in rawtypes)
if(istype(toDisplay, type))
raw = 1
break
if(!raw)
finishedList += toDisplay
for(var/obj/item/reagent_containers/food/snacks/toGrab in rangeCheck)
if(!(locate(/obj/structure/table/reinforced) in get_turf(toGrab))) //it's not being displayed
var/raw = 0
for(var/type in rawtypes)
if(istype(toGrab, type))
raw = 1
break
if(!raw)
foundCookable = 1
if(!Adjacent(toGrab))
tryWalk(toGrab)
else
finishedList += toGrab
toGrab.forceMove(src)
if(finishedList.len)
var/obj/structure/table/reinforced/RT
for(var/obj/structure/table/reinforced/toCheck in rangeCheck)
var/counted = 0
for(var/obj/item/reagent_containers/food/snacks/S in get_turf(toCheck))
++counted
if(counted < 12) // make sure theres not too much food here
RT = toCheck
break
if(RT)
foundCookable = 1
if(!Adjacent(RT))
tryWalk(get_turf(RT))
else
for(var/obj/item/reagent_containers/food/snacks/toPlop in finishedList)
RT.attackby(toPlop,src)
if(!foundCookable)
var/chosenType = pick(rawtypes)
var/obj/item/reagent_containers/food/snacks/newSnack = new chosenType(get_turf(src))
TARGET = newSnack
newSnack.reagents.remove_any((newSnack.reagents.total_volume/2)-1)
newSnack.name = "synthetic [newSnack.name]"
custom_emote(2, "[pick("gibbers","drools","slobbers","claps wildly","spits")] as [p_they()] vomit[p_s()] [newSnack] from [p_their()] mouth!")
catch(var/exception/e)
log_runtime(e, src, "Caught in SNPC cooking module")
doing &= ~SNPC_SPECIAL
// END COOKING MODULE
/mob/living/carbon/human/interactive/proc/combat(obj)
set background = 1
enforce_hands()
if(canmove)
if((graytide || (TRAITS & TRAIT_MEAN)) || retal)
interest += targetInterestShift
a_intent = INTENT_HARM
zone_sel.selecting = pick("chest","r_leg","l_leg","r_arm","l_arm","head")
doing |= SNPC_FIGHTING
if(retal)
TARGET = retal_target
else
var/mob/living/M = locate(/mob/living) in oview(7, src)
if(!M)
doing = doing & ~SNPC_FIGHTING
else if(M != src && !compareFaction(M.faction))
TARGET = M
//no infighting
if(retal)
if(retal_target)
if(compareFaction(retal_target.faction))
retal = 0
retal_target = null
TARGET = null
doing = 0
//ensure we're using the best object possible
var/obj/item/best
var/foundFav = 0
var/list/allContents = getAllContents()
for(var/test in allContents)
for(var/a in favoured_types)
if(ispath(test,a) && !(doing & SNPC_FIGHTING)) // if we're not in combat and we find our favourite things, use them (for people like janitor and doctors)
best = test
foundFav = 1
return
if(!foundFav)
if(istype(test,/obj/item))
var/obj/item/R = test
if(R.force > 2) // make sure we don't equip any non-weaponlike items, ie bags and stuff
if(!best)
best = R
else
if(best.force < R.force)
best = R
if(istype(R, /obj/item/gun))
var/obj/item/gun/G = R
if(G.can_shoot())
best = R
break // gun with ammo? screw the rest
if(best && best != main_hand)
take_to_slot(best,1)
if(TARGET && (doing & SNPC_FIGHTING)) // this is a redundancy check
var/mob/living/M = TARGET
if(istype(M,/mob/living))
if(M.health > 1 && (M in oview(src, 6)))
//THROWING OBJECTS
for(var/A in allContents)
if(istype(A,/obj/item/gun)) // guns are for shooting, not throwing.
continue
if(prob(robustness))
if(istype(A,/obj/item))
var/obj/item/W = A
if(W.throwforce > 19) // Only throw worthwile stuff, no more lobbing wrenches at wenches
npcDrop(W, 1)
throw_item(TARGET)
if(istype(A,/obj/item/grenade)) // Allahu ackbar! ALLAHU ACKBARR!!
var/obj/item/grenade/G = A
G.attack_self(src)
if(prob(smartness))
npcDrop(G, 1)
sleep(15)
throw_item(TARGET)
if(!main_hand && other_hand)
swap_hands()
if(main_hand)
if(main_hand.force != 0)
if(istype(main_hand,/obj/item/gun))
var/obj/item/gun/G = main_hand
if(G.can_trigger_gun(src))
var/shouldFire = 1
if(istype(main_hand, /obj/item/gun/energy))
var/obj/item/gun/energy/P = main_hand
var/stunning = 0
for(var/A in P.ammo_type)
if(ispath(A,/obj/item/ammo_casing/energy/electrode))
stunning = 1
var/mob/stunCheck = TARGET
if(stunning && stunCheck.stunned)
shouldFire = 0
if(shouldFire)
if(!G.can_shoot())
G.shoot_with_empty_chamber(src)
npcDrop(G, 1)
else
G.process_fire(TARGET, src)
else
if(get_dist(src,TARGET) > 6)
if(!walk2derpless(TARGET))
timeout++
else
var/obj/item/W = main_hand
W.attack(TARGET, src)
else
npcDrop(G, 1)
else
if(targetRange(TARGET) > 2)
tryWalk(TARGET)
else
if(Adjacent(TARGET))
a_intent = pick(INTENT_DISARM, INTENT_HARM)
M.attack_hand(src)
timeout++
else if(timeout >= 10 || !(targetRange(M) > 14))
doing = doing & ~SNPC_FIGHTING
timeout = 0
TARGET = null
retal = 0
retal_target = null
else
timeout++
/mob/living/carbon/human/interactive/proc/past_verb(word)
if(copytext(word, length(word)) == "e")
return "[word]d"
else
return "[word]ed"
/mob/living/carbon/human/interactive/proc/ing_verb(word)
if(copytext(word, length(word)) == "e")
return "[copytext(word, 1, length(word))]ing"
else
return "[word]ing"
/mob/living/carbon/human/interactive/proc/paperwork_sentence()
var/verbs_use = pick_list(speak_file, "verbs_use")
var/verbs_touch = pick_list(speak_file, "verbs_touch")
var/verbs_move = pick_list(speak_file, "verbs_move")
var/nouns_insult = pick_list(speak_file, "nouns_insult")
var/nouns_generic = pick_list(speak_file, "nouns_generic")
var/nouns_objects = pick_list(speak_file, "nouns_objects")
var/nouns_body = pick_list(speak_file, "nouns_body")
var/adjective_insult = pick_list(speak_file, "adjective_insult")
var/adjective_objects = pick_list(speak_file, "adjective_objects")
var/adjective_generic = pick_list(speak_file, "adjective_generic")
var/curse_words = pick_list(speak_file, "curse_words")
var/result = pick("fired", "promoted", "demoted", "terminated", "incinerated", "sent to CentCom", "borged")
return pick(
"The [adjective_insult] [pick(command_positions)] [past_verb(verbs_touch)] the [adjective_objects] [nouns_objects] and was [result].",
"The [adjective_generic] [pick(engineering_positions)] [past_verb(verbs_touch)] the [adjective_insult] [nouns_objects]. [capitalize(curse_words)], the [nouns_insult] was [result].",
"The [adjective_insult] [pick(security_positions)] [past_verb(verbs_touch)] the [adjective_generic] [nouns_insult] [pick(support_positions)]'s [nouns_body] and had to be [result].",
"Medical had to [verbs_use] the [adjective_generic] [pick(command_positions)]'s [adjective_objects] [nouns_body] after the incident.",
"I demand that [nouns_generic] respond with a [adjective_generic] update ASAP.",
"Would like an update from [nouns_generic] regarding the [adjective_insult] [pick(command_positions)] being [result].",
"The [pick(medical_positions)] needs to [verbs_move] faster when the crew's [adjective_objects] [nouns_body]s are injured, or they will be [result].",
"[capitalize(curse_words)] [adjective_insult] [curse_words].",
"<br><br>")
/mob/living/carbon/human/interactive/proc/pickStamp(allContents)
var/list/stamps[0]
for(var/obj/item/stamp/S in allContents)
stamps += S
if(stamps.len)
return pick(stamps)
// just make one, maybe
if(prob(SNPC_FUZZY_CHANCE_LOW / 2))
for(var/p in favoured_types)
if(ispath(p, /obj/item/stamp))
return new p(src)
return null
/mob/living/carbon/human/interactive/proc/paperwork(obj)
set background = 1
if(shouldModulePass() || !prob(SNPC_FUZZY_CHANCE_LOW / 4))
return
var/list/allContents = getAllContents()
var/obj/item/paper/P = locate() in allContents
var/obj/item/stamp/S = pickStamp(allContents)
var/mob/living/carbon/human/H = locate() in nearby
if(!P)
P = new /obj/item/paper(src)
if(P && S && H)
if(!P.stamped || !P.stamped.len)
// generate form
P.name = pick("Inspection Report", "Re: Crew", "Complaint", "To: CentCom")
P.info = {"<center><img src=ntlogo.png><br><b><font size="1">[paperwork_sentence()]</font></b></center>"}
for(var/I in 1 to rand(10, 20))
P.info += "[paperwork_sentence()] "
P.info += {"<br><br>[pick("Signed", "Sincerely", "Regards")], <font face="Times New Roman"><i>[real_name]</i></font>"}
P.update_icon()
P.stamp(S)
custom_emote(2, "[pick("gibbers","drools","slobbers","claps wildly","spits")] and throws [P] on the ground!")
npcDrop(P)
P.throw_at(H, P.throw_range, P.throw_speed, src)
/mob/living/carbon/human/interactive/proc/stamping(obj)
if(shouldModulePass())
return
var/list/allContents = getAllContents()
var/list/rangeCheck = view(7, src)
var/obj/item/stamp/S = pickStamp(allContents)
if(!S)
return
// stamp a paper we're holding, and drop it
var/obj/item/paper/P = locate() in allContents
if(P)
if(!P.stamped || !P.stamped.len)
P.stamp(S)
custom_emote(2, "[pick("gibbers","drools","slobbers","claps wildly","spits")] as they stamp \the [P] with \a [S]!")
npcDrop(P, 1)
return
// stamp a paper in the world
for(var/obj/item/paper/A in rangeCheck)
if(!A.stamped || !A.stamped.len)
if(!Adjacent(A))
tryWalk(A)
else
A.stamp(S)
custom_emote(2, "[pick("gibbers","drools","slobbers","claps wildly","spits")] as they stamp \the [A] with \a [S]!")
return
@@ -1,960 +0,0 @@
/*
NPC VAR EXPLANATIONS (for modules and other things)
doing = their current action, SNPC_INTERACTING, SNPC_TRAVEL or SNPC_FIGHTING
interest = how interested the NPC is in the situation, if they are idle, this drops
timeout = this is internal
TARGET = their current target
LAST_TARGET = their last target
nearby = a list of nearby mobs
best_force = the highest force object, used for checking when to swap items
retal = this is internal
retal_target = this is internal
update_hands = this is a bool (1/0) to determine if the NPC should update what is in his hands
MYID = their ID card
MYPDA = their PDA
main_hand = what is in their "main" hand (chosen from left > right)
TRAITS = the traits assigned to this npc
mymjob = the job assigned to the npc
robustness = the chance for the npc to hit something
smartness = the inverse chance for an npc to do stupid things
attitude = the chance for an npc to do rude or mean things
slyness = the chance for an npc to do naughty things ie thieving
functions = the list of procs that the npc will use for modules
graytide = shitmin var to make them go psycho
*/
/mob/living/carbon/human/interactive
name = "interactive station member"
var/doing = 0
var/interest = 10
var/maxInterest = 10
var/timeout = 0
var/inactivity_period = 0
var/atom/TARGET = null
var/atom/LAST_TARGET = null
var/list/nearby = list()
var/best_force = 0
var/retal = 0
var/mob/retal_target = null
var/update_hands = 0
var/list/blacklistItems = list() // items we should be ignoring
var/maxStepsTick = 6 // step as many times as we can per frame
//Job and mind data
var/obj/item/card/id/MYID
var/obj/item/card/id/RPID // the "real" idea they use
var/obj/item/pda/MYPDA
var/obj/item/main_hand
var/obj/item/other_hand
var/TRAITS = 0
var/obj/item/card/id/Path_ID
var/default_job = /datum/job/civilian // the type for the default job
var/datum/job/myjob
var/list/myPath = list()
faction = list("synth")
//trait vars
var/robustness = 50
var/smartness = 50
var/attitude = 50
var/slyness = 50
var/graytide = 0
var/list/favoured_types = list() // allow a mob to favour a type, and hold onto them
var/chattyness = SNPC_CHANCE_TALK
var/targetInterestShift = 5 // how much a good action should "reward" the npc
//modules
var/list/functions = list("nearbyscan","combat","shitcurity","chatter")
var/restrictedJob = 0
var/forceProcess = 0
var/speak_file = "npc_chatter.json"
var/debugexamine = FALSE //If we show debug info in our examine
var/showexaminetext = TRUE //If we show our telltale examine text
var/voice_saved = FALSE
var/list/knownStrings = list()
//snpc traitor variables
var/isTraitor = 0
var/traitorTarget
var/traitorScale = 0 // our ability as a traitor
var/traitorType = 0
/// SNPC voice handling
/mob/living/carbon/human/interactive/proc/loadVoice()
var/savefile/S = new /savefile("data/npc_saves/snpc.sav")
S["knownStrings"] >> knownStrings
if(isnull(knownStrings))
knownStrings = list()
/mob/living/carbon/human/interactive/proc/saveVoice()
if(voice_saved)
return
var/savefile/S = new /savefile("data/npc_saves/snpc.sav")
S["knownStrings"] << knownStrings
//botPool funcs
/mob/living/carbon/human/interactive/proc/takeDelegate(mob/living/carbon/human/interactive/from,doReset=TRUE)
change_eye_color(255, 0, 0)
if(from == src)
return FALSE
TARGET = from.TARGET
LAST_TARGET = from.LAST_TARGET
retal = from.retal
retal_target = from.retal_target
doing = from.doing
//
timeout = 0
inactivity_period = 0
interest = maxInterest
//
update_icons()
if(doReset)
from.TARGET = null
from.LAST_TARGET = null
from.retal = 0
from.retal_target = null
from.doing = 0
return TRUE
//end pool funcs
/mob/living/carbon/human/interactive/proc/random()
//this is here because this has no client/prefs/brain whatever.
age = rand(AGE_MIN, AGE_MAX)
change_gender(pick("male", "female"))
rename_character(real_name, dna.species.get_random_name(gender))
//job handling
myjob = new default_job()
job = myjob.title
mind.assigned_role = job
myjob.equip(src)
/mob/living/carbon/human/interactive/proc/reset()
walk(src, 0)
timeout = 100
retal = 0
doing = 0
inactivity_period = 0
/client/proc/resetSNPC(mob/living/carbon/human/interactive/T in SSnpcpool.processing)
set name = "Reset SNPC"
set desc = "Reset the SNPC"
set category = "Debug"
if(!holder)
return
if(istype(T))
T.reset()
/client/proc/customiseSNPC(mob/living/carbon/human/interactive/T in SSnpcpool.processing)
set name = "Customize SNPC"
set desc = "Customize the SNPC"
set category = "Debug"
if(!holder)
return
if(!istype(T))
return
var/list/jobs[0]
for(var/datum/job/j in SSjobs.occupations)
if(j.title != "AI" && j.title != "Cyborg")
jobs[j.title] = j
jobs = sortAssoc(jobs)
var/job_name = input("Choose Job") as null|anything in jobs
if(job_name)
var/datum/job/cjob = jobs[job_name]
var/alt_title = input("Choose Alt Title") in (list(job_name) + cjob.alt_titles)
T.myjob = cjob
T.job = cjob.title
T.mind.assigned_role = cjob.title
for(var/obj/item/I in T)
if(istype(I, /obj/item/implant))
continue
if(istype(I, /obj/item/organ))
continue
qdel(I)
T.myjob.equip(T)
T.doSetup(alt_title)
var/shouldDoppel = input("Do you want the SNPC to disguise themself as a crewmember?") as anything in list("Yes", "No")
if(shouldDoppel == "Yes")
var/list/validchoices = list()
for(var/mob/living/carbon/human/M in GLOB.mob_list)
validchoices += M
var/mob/living/carbon/human/chosen = input("Which crewmember?") as null|anything in validchoices
if(chosen)
var/datum/dna/toDoppel = chosen.dna
T.real_name = toDoppel.real_name
T.set_species(chosen.dna.species.type)
T.dna = toDoppel.Clone()
T.body_accessory = chosen.body_accessory
T.UpdateAppearance()
domutcheck(T)
var/doTrait = input("Do you want the SNPC to be a traitor?") as anything in list("Yes", "No")
if(doTrait == "Yes")
var/list/tType = list("Brute" = SNPC_BRUTE, "Stealth" = SNPC_STEALTH, "Martyr" = SNPC_MARTYR, "Psycho" = SNPC_PSYCHO)
var/cType = input("Choose the traitor personality.") as null|anything in tType
if(cType)
var/value = tType[cType]
T.makeTraitor(value)
var/doTele = input("Place the SNPC in their department?") as anything in list("Yes", "No")
if(doTele == "Yes")
T.loc = pick(get_area_turfs(T.job2area(T.myjob)))
T.revive()
/mob/living/carbon/human/interactive/proc/doSetup(alt_title = null)
Path_ID = new /obj/item/card/id(src)
var/datum/job/captain/C = new/datum/job/captain
Path_ID.access = C.get_access()
if(!alt_title)
alt_title = job
MYID = new(src)
MYID.name = "[real_name]'s ID Card ([alt_title])"
MYID.assignment = "[alt_title]"
MYID.rank = job
MYID.sex = capitalize(gender)
MYID.age = age
MYID.registered_name = real_name
MYID.photo = get_id_photo(src)
MYID.access = Path_ID.access.Copy() // Automatons have strange powers... strange indeed
RPID = new(src)
RPID.name = "[real_name]'s ID Card ([alt_title])"
RPID.assignment = "[alt_title]"
RPID.rank = job
RPID.sex = capitalize(gender)
RPID.age = age
RPID.registered_name = real_name
RPID.photo = get_id_photo(src)
RPID.access = myjob.get_access()
if(wear_id)
qdel(wear_id)
if(!equip_to_slot_or_del(MYID, slot_wear_id))
create_attack_log("<font color='blue'>Deleted ID due to slot contention</font>")
if(wear_pda)
MYPDA = wear_pda
else
MYPDA = new(src)
equip_to_slot_or_del(MYPDA, slot_wear_pda)
MYPDA.owner = real_name
MYPDA.ownjob = alt_title
MYPDA.ownrank = job
MYPDA.name = "PDA-[real_name] ([alt_title])"
zone_sel.selecting = "chest"
//arms
if(prob((SNPC_FUZZY_CHANCE_LOW+SNPC_FUZZY_CHANCE_HIGH)/4))
var/obj/item/organ/external/R = bodyparts_by_name["r_arm"]
if(R)
R.robotize(make_tough = 1)
else
var/obj/item/organ/external/L = bodyparts_by_name["l_arm"]
if(L)
L.robotize(make_tough = 1)
//legs
if(prob((SNPC_FUZZY_CHANCE_LOW+SNPC_FUZZY_CHANCE_HIGH)/4))
var/obj/item/organ/external/R = bodyparts_by_name["r_leg"]
if(R)
R.robotize(make_tough = 1)
else
var/obj/item/organ/external/L = bodyparts_by_name["l_leg"]
if(L)
L.robotize(make_tough = 1)
UpdateDamageIcon()
regenerate_icons()
hand = 0
functions = list("nearbyscan", "combat", "shitcurity", "chatter") // stop customize adding multiple copies of a function
setup_job(job)
if(TRAITS & TRAIT_ROBUST)
robustness = 75
else if(TRAITS & TRAIT_UNROBUST)
robustness = 25
//modifiers are prob chances, lower = smarter
if(TRAITS & TRAIT_SMART)
smartness = 75
else if(TRAITS & TRAIT_DUMB)
disabilities |= CLUMSY
smartness = 25
if(TRAITS & TRAIT_MEAN)
attitude = 75
else if(TRAITS & TRAIT_FRIENDLY)
attitude = 1
if(TRAITS & TRAIT_THIEVING)
slyness = 75
/mob/living/carbon/human/interactive/proc/InteractiveProcess()
if(ticker.current_state == GAME_STATE_FINISHED)
saveVoice()
voice_saved = TRUE
doProcess()
/mob/living/carbon/human/interactive/proc/setup_job(thejob)
switch(thejob)
if("Civilian")
favoured_types = list(/obj/item/clothing, /obj/item)
if("Captain", "Head of Personnel")
favoured_types = list(/obj/item/clothing, /obj/item/stamp/captain,/obj/item/disk/nuclear)
if("Nanotrasen Representative")
favoured_types = list(/obj/item/clothing, /obj/item/stamp/centcom, /obj/item/paper, /obj/item/melee/classic_baton/ntcane)
functions += "paperwork"
if("Magistrate", "Internal Affairs Agent")
favoured_types = list(/obj/item/clothing, /obj/item/stamp/law, /obj/item/paper)
functions += "paperwork"
if("Quartermaster", "Cargo Technician")
favoured_types = list(/obj/item/clothing, /obj/item/stamp/granted, /obj/item/stamp/denied, /obj/item/paper, /obj/item/clipboard)
functions += "stamping"
if("Chef")
favoured_types = list(/obj/item/reagent_containers/food, /obj/item/kitchen)
functions += "souschef"
restrictedJob = 1
if("Bartender")
favoured_types = list(/obj/item/reagent_containers/food, /obj/item/kitchen)
functions += "bartend"
restrictedJob = 1
if("Station Engineer", "Chief Engineer", "Life Support Specialist", "Mechanic")
favoured_types = list(/obj/item/stack, /obj/item, /obj/item/clothing)
if("Chief Medical Officer", "Medical Doctor", "Chemist", "Virologist", "Geneticist", "Psychiatrist", "Paramedic", "Brig Physician")
favoured_types = list(/obj/item/reagent_containers/glass/beaker, /obj/item/storage/firstaid, /obj/item/stack/medical, /obj/item/reagent_containers/syringe)
functions += "healpeople"
if("Research Director", "Scientist", "Roboticist")
favoured_types = list(/obj/item/reagent_containers/glass/beaker, /obj/item/stack, /obj/item/reagent_containers)
if("Head of Security", "Warden", "Security Officer", "Detective", "Security Pod Pilot", "Blueshield")
favoured_types = list(/obj/item/clothing, /obj/item, /obj/item/restraints)
if("Janitor")
favoured_types = list(/obj/item/mop, /obj/item/reagent_containers/glass/bucket, /obj/item/reagent_containers/spray/cleaner, /obj/effect/decal/cleanable)
functions += "dojanitor"
if("Clown")
favoured_types = list(/obj/item/soap, /obj/item/reagent_containers/food/snacks/grown/banana, /obj/item/grown/bananapeel)
functions += "clowning"
if("Botanist")
favoured_types = list(/obj/machinery/hydroponics, /obj/item/reagent_containers, /obj/item)
functions += "botany"
restrictedJob = 1
else
favoured_types = list(/obj/item/clothing)
/mob/living/carbon/human/interactive/proc/makeTraitor(var/inPers)
isTraitor = 1
traitorScale = (slyness + smartness) + rand(-10,10)
traitorType = inPers
ticker.mode.traitors += mind
mind.special_role = SPECIAL_ROLE_TRAITOR
var/datum/mindslaves/slaved = new()
slaved.masters += mind
mind.som = slaved
ticker.mode.update_traitor_icons_added(mind)
switch(traitorType)
if(SNPC_BRUTE) // SMASH KILL RAAARGH
var/datum/objective/assassinate/A = new
A.owner = mind
A.find_target()
mind.objectives += A
traitorTarget = A.target.current
if(SNPC_STEALTH) // Shhh we is sneekies
var/datum/objective/steal/S = new
S.owner = mind
S.find_target()
mind.objectives += S
traitorTarget = locate(S.steal_target.typepath) in world
if(SNPC_MARTYR) // MY LIFE FOR SPESZUL
var/targetType = pick(/obj/structure/particle_accelerator, /obj/machinery/gravity_generator/main, /obj/machinery/power/smes)
traitorTarget = locate(targetType) in world
var/datum/objective/O = new("Destroy \the [traitorTarget].")
O.owner = mind
mind.objectives += O
if(SNPC_PSYCHO) // YOU'RE LIKE A FLESH BICYLE AND I WANT TO DISMANTLE YOU
var/datum/objective/hijack/H = new
H.owner = mind
mind.objectives += H
traitorTarget = null
functions += "traitor"
faction -= "neutral"
faction += "hostile"
/mob/living/carbon/human/interactive/create_mob_hud()
if(!hud_used)
hud_used = new /datum/hud/human(src)
/mob/living/carbon/human/interactive/Initialize()
..()
return INITIALIZE_HINT_LATELOAD
/mob/living/carbon/human/interactive/LateInitialize()
. = ..()
GLOB.snpc_list += src
create_mob_hud()
sync_mind()
random()
doSetup()
START_PROCESSING(SSnpcpool, src)
loadVoice()
GLOB.hear_radio_list += src
// a little bit of variation to make individuals more unique
robustness += rand(-10, 10)
smartness += rand(-10, 10)
attitude += rand(-10, 10)
slyness += rand(-10, 10)
doProcess()
/mob/living/carbon/human/interactive/Destroy()
SSnpcpool.stop_processing(src)
return ..()
/mob/living/carbon/human/interactive/proc/retalTarget(mob/living/target)
var/mob/living/M = target
if(istype(M))
if(health > 0)
if(M.a_intent == INTENT_HELP && !incapacitated())
chatter()
if(istype(target, /mob/living/carbon) && !retal && prob(SNPC_FUZZY_CHANCE_LOW))
var/mob/living/carbon/C = target
if(!Adjacent(target))
tryWalk(target)
else
C.help_shake_act(src)
if(M.a_intent == INTENT_HARM)
retal = 1
retal_target = target
//Retaliation clauses
/mob/living/carbon/human/interactive/attacked_by(obj/item/I, mob/living/user, def_zone)
..()
retalTarget(user)
/mob/living/carbon/human/interactive/hitby(atom/movable/AM, skipcatch, hitpush, blocked)
..()
var/mob/living/carbon/C = locate(/mob/living/carbon) in view(SNPC_MIN_RANGE_FIND, src)
if(C)
retalTarget(C)
/mob/living/carbon/human/interactive/bullet_act(obj/item/projectile/P)
..()
retalTarget(P.firer)
/mob/living/carbon/human/interactive/attack_hand(mob/living/carbon/human/M)
..()
retalTarget(M)
/mob/living/carbon/human/interactive/show_inv(mob/user)
..()
retalTarget(user)
/mob/living/carbon/human/interactive/can_inject(mob/user, error_msg, target_zone, var/penetrate_thick = 0)
..()
retalTarget(user)
//THESE EXIST FOR DEBUGGING OF THE DOING/INTEREST SYSTEM EASILY
/mob/living/carbon/human/interactive/proc/doing2string(doin)
var/toReturn = ""
if(!doin)
toReturn = "not doing anything"
if(doin & SNPC_INTERACTING)
toReturn += "interacting with something, "
if(doin & SNPC_FIGHTING)
toReturn += "engaging in combat, "
if(doin & SNPC_TRAVEL)
toReturn += "and going somewhere"
return toReturn
/mob/living/carbon/human/interactive/proc/interest2string(inter)
var/toReturn = "Flatlined"
if(inter >= 0 && inter <= 25)
toReturn = "Very Bored"
if(inter >= 26 && inter <= 50)
toReturn = "Bored"
if(inter >= 51 && inter <= 75)
toReturn = "Content"
if(inter >= 76)
toReturn = "Excited"
return toReturn
//END DEBUG
/mob/living/carbon/human/interactive/proc/IsDeadOrIncap(checkDead = TRUE)
if(!canmove)
return 1
if(health <= 0 && checkDead)
return 1
if(restrained())
return 1
if(paralysis)
return 1
if(stunned)
return 1
if(stat)
return 1
if(inactivity_period > 0)
return 1
return 0
/mob/living/carbon/human/interactive/proc/enforce_hands()
if(main_hand)
if(main_hand.loc != src)
main_hand = null
if(other_hand)
if(other_hand.loc != src)
other_hand = null
if(hand)
if(!l_hand)
main_hand = null
if(r_hand)
swap_hands()
else
if(!r_hand)
main_hand = null
if(l_hand)
swap_hands()
/mob/living/carbon/human/interactive/proc/swap_hands()
hand = !hand
var/obj/item/T = other_hand
main_hand = other_hand
other_hand = T
update_hands = 1
/mob/living/carbon/human/interactive/proc/take_to_slot(obj/item/G, var/hands=0)
var/list/slots = list("left pocket" = slot_l_store, "right pocket" = slot_r_store, "left hand" = slot_l_hand, "right hand" = slot_r_hand)
if(hands)
slots = list("left hand" = slot_l_hand, "right hand" = slot_r_hand)
G.loc = src
if(G.force && G.force > best_force)
best_force = G.force
equip_in_one_of_slots(G, slots)
update_hands = 1
/mob/living/carbon/human/interactive/proc/insert_into_backpack()
var/list/slots = list(slot_l_store, slot_r_store, slot_l_hand, slot_r_hand)
var/obj/item/I = get_item_by_slot(pick(slots))
var/obj/item/storage/BP = get_item_by_slot(slot_back)
if(back && BP && I)
// hack to allow SNPCs to "sticky grab" items without losing their inventorying
var/oldnodrop = I.flags | NODROP
I.flags &= ~NODROP
if(BP.can_be_inserted(I))
BP.handle_item_insertion(I)
I.flags |= oldnodrop
else
unEquip(I,TRUE)
update_hands = 1
/mob/living/carbon/human/interactive/proc/targetRange(towhere)
return get_dist(get_turf(towhere), get_turf(src))
/mob/living/carbon/human/interactive/death()
// Only execute the below if we successfully died
. = ..()
if(!.)
return FALSE
saveVoice()
/mob/living/carbon/human/interactive/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol)
if(!istype(speaker, /mob/living/carbon/human/interactive))
knownStrings |= html_decode(multilingual_to_message(message_pieces))
..()
/mob/living/carbon/human/interactive/hear_radio(list/message_pieces, verb = "says", part_a, part_b, mob/speaker = null, hard_to_hear = 0, vname = "", atom/follow_target)
if(!istype(speaker, /mob/living/carbon/human/interactive))
knownStrings |= html_decode(multilingual_to_message(message_pieces))
..()
/mob/living/carbon/human/interactive/proc/doProcess()
set waitfor = FALSE
if(IsDeadOrIncap())
reset()
return
//---------------------------
//---- interest flow control
if(interest < 0 || inactivity_period < 0)
if(interest < 0)
interest = 0
if(inactivity_period < 0)
inactivity_period = 0
if(interest > maxInterest)
interest = maxInterest
//---------------------------
//VIEW FUNCTIONS
//doorscan is now integrated into life and runs before all other procs
var/mistake_chance = (100 - smartness) / 2
spawn(0)
for(var/dir in alldirs)
var/turf/T = get_step(src, dir)
if(T)
for(var/obj/machinery/door/D in T.contents)
if(!istype(D,/obj/machinery/door/poddoor) && D.density)
spawn(0)
if(istype(D,/obj/machinery/door/airlock))
var/obj/machinery/door/airlock/AL = D
if(!AL.CanAStarPass(RPID)) // only crack open doors we can't get through
inactivity_period = 20
AL.panel_open = 1
AL.update_icon()
AL.shock(src, mistake_chance)
sleep(5)
if(QDELETED(AL))
return
AL.unlock()
if(prob(mistake_chance))
if(!AL.wires.IsIndexCut(AIRLOCK_WIRE_DOOR_BOLTS))
AL.wires.CutWireIndex(AIRLOCK_WIRE_DOOR_BOLTS)
else
if(AL.wires.IsIndexCut(AIRLOCK_WIRE_DOOR_BOLTS))
AL.wires.CutWireIndex(AIRLOCK_WIRE_DOOR_BOLTS, 1)
if(AL.locked)
AL.wires.UpdatePulsed(AIRLOCK_WIRE_DOOR_BOLTS)
if(!AL.wires.IsIndexCut(AIRLOCK_WIRE_MAIN_POWER1))
AL.wires.CutWireIndex(AIRLOCK_WIRE_MAIN_POWER1)
if(prob(mistake_chance) && !AL.wires.IsIndexCut(AIRLOCK_WIRE_SAFETY))
AL.wires.CutWireIndex(AIRLOCK_WIRE_SAFETY)
if(prob(mistake_chance) && !AL.wires.IsIndexCut(AIRLOCK_WIRE_ELECTRIFY))
AL.wires.CutWireIndex(AIRLOCK_WIRE_ELECTRIFY)
sleep(5)
if(QDELETED(AL))
return
AL.panel_open = 0
AL.update_icon()
D.open()
if(update_hands)
if(l_hand || r_hand)
if(l_hand)
hand = 1
main_hand = l_hand
if(r_hand)
other_hand = r_hand
else if(r_hand)
hand = 0
main_hand = r_hand
if(l_hand) //this technically shouldnt occur, but its a redundancy
other_hand = l_hand
update_icons()
update_hands = 0
if(grabbed_by.len > 0)
for(var/obj/item/grab/G in grabbed_by)
if(Adjacent(G))
a_intent = INTENT_DISARM
G.assailant.attack_hand(src)
inactivity_period = 10
if(buckled)
resist()
inactivity_period = 10
//proc functions
for(var/Proc in functions)
if(!IsDeadOrIncap())
INVOKE_ASYNC(src, Proc)
//target interaction stays hardcoded
if(TARGET && (TARGET in blacklistItems)) // don't use blacklisted items
TARGET = null
if(TARGET && Adjacent(TARGET))
doing |= SNPC_INTERACTING
//--------DOORS
if(istype(TARGET, /obj/machinery/door))
var/obj/machinery/door/D = TARGET
if(D.check_access(MYID) && !istype(D,/obj/machinery/door/poddoor))
inactivity_period = 10
D.open()
var/turf/T = get_step(get_step(D.loc, dir), dir) //recursion yo
tryWalk(T)
//THIEVING SKILLS
insert_into_backpack() // dump random item into backpack to make space
//---------ITEMS
if(istype(TARGET, /obj/item))
var/obj/item/I = TARGET
if(I.anchored)
TARGET = null
else if(istype(TARGET, /obj/item))
var/obj/item/W = TARGET
if(W.force >= best_force || prob((SNPC_FUZZY_CHANCE_LOW + SNPC_FUZZY_CHANCE_HIGH) / 2) || favouredObjIn(list(W)))
if(!l_hand || !r_hand)
put_in_hands(W)
else
insert_into_backpack()
else
if(!l_hand || !r_hand)
put_in_hands(TARGET)
else
insert_into_backpack()
//---------FASHION
if(istype(TARGET, /obj/item/clothing))
drop_item()
dressup(TARGET)
update_hands = 1
if(MYPDA in loc)
equip_to_appropriate_slot(MYPDA)
if(MYID in loc)
equip_to_appropriate_slot(MYID)
//THIEVING SKILLS END
//-------------TOUCH ME
if(istype(TARGET, /obj/structure))
var/obj/structure/STR = TARGET
if(main_hand)
var/obj/item/W = main_hand
STR.attackby(W, src)
else
STR.attack_hand(src)
interest += targetInterestShift
doing = doing & ~SNPC_INTERACTING
timeout = 0
TARGET = null
else
if(TARGET)
tryWalk(TARGET)
timeout++
if(doing == 0)
interest--
else
interest++
if(inactivity_period > 0)
inactivity_period--
if(interest <= 0 || timeout >= 10) // facilitate boredom functions
TARGET = null
doing = 0
timeout = 0
myPath = list()
//this is boring, lets move
if(!doing && !IsDeadOrIncap() && !TARGET)
doing |= SNPC_TRAVEL
if(!isTraitor || !traitorTarget || get_dist(src, traitorTarget) >= SNPC_MAX_RANGE_FIND || get_dist(src, traitorTarget) <= 1)
var/choice = rand(1,50)
switch(choice)
if(1 to 30)
//chance to chase an item
TARGET = locate(/obj/item) in favouredObjIn(oview(SNPC_MIN_RANGE_FIND, src))
if(31 to 40)
TARGET = safepick(get_area_turfs(job2area(myjob)))
if(41 to 45)
TARGET = pick(target_filter(favouredObjIn(urange(SNPC_MAX_RANGE_FIND, src, 1))))
if(46 to 50)
TARGET = pick(target_filter(oview(SNPC_MIN_RANGE_FIND, src)))
else
TARGET = traitorTarget
tryWalk(TARGET)
LAST_TARGET = TARGET
/mob/living/carbon/human/interactive/proc/dressup(obj/item/clothing/C)
set waitfor = FALSE
inactivity_period = 12
sleep(5)
if(!QDELETED(C) && !QDELETED(src))
take_to_slot(C,1)
if(!equip_to_appropriate_slot(C))
var/obj/item/I = get_item_by_slot(C)
unEquip(I)
sleep(5)
if(!QDELETED(src) && !QDELETED(C))
equip_to_appropriate_slot(C)
/mob/living/carbon/human/interactive/proc/favouredObjIn(list/inList)
var/list/outList = list()
for(var/i in inList)
for(var/path in favoured_types)
if(istype(i, path))
outList += i
if(!outList.len)
outList = inList
return outList
/mob/living/carbon/human/interactive/proc/tryWalk(turf/inTarget)
if(restrictedJob) // we're a job that has to stay in our home
if(!(get_turf(inTarget) in get_area_turfs(job2area(myjob))))
TARGET = null
return
if(!IsDeadOrIncap())
if(!walk2derpless(inTarget))
timeout++
else
timeout++
/mob/living/carbon/human/interactive/proc/getGoodPath(target, maxtries=512)
set background = 1
var/turf/end = get_turf(target)
var/turf/current = get_turf(src)
var/list/path = list()
var/tries = 0
while(current != end && tries < maxtries)
var/turf/shortest = current
for(var/turf/T in view(current,1))
var/foundDense = 0
for(var/atom/A in T)
if(A.density)
foundDense = 1
if(T.density == 0 && !foundDense)
if(get_dist(T, target) < get_dist(shortest,target))
shortest = T
else
tries++
else
tries++
current = shortest
path += shortest
return path
/mob/living/carbon/human/interactive/proc/walk2derpless(target)
set background = 1
if(!target)
return 0
if(myPath.len <= 0)
myPath = get_path_to(src, get_turf(target), /turf/proc/Distance, SNPC_MAX_RANGE_FIND + 1, 250,1, id=Path_ID, simulated_only = 0)
if(myPath)
if(myPath.len > 0)
doing = doing & ~SNPC_TRAVEL
for(var/i = 0; i < maxStepsTick; ++i)
if(!IsDeadOrIncap())
if(myPath.len >= 1)
walk_to(src,myPath[1],0,5)
myPath -= myPath[1]
return 1
return 0
/mob/living/carbon/human/interactive/proc/job2area(target)
var/datum/job/T = target
switch(T.title)
if("Civilian", "Paramedic")
return /area/hallway/primary
if("Captain", "Head of Personnel", "Blueshield")
return /area/bridge
if("Bartender")
return /area/crew_quarters/bar
if("Chef")
return /area/crew_quarters/kitchen
if("Station Engineer", "Chief Engineer", "Mechanic")
return /area/engine
if("Life Support Specialist")
return /area/atmos
if("Chief Medical Officer", "Medical Doctor", "Chemist", "Virologist", "Psychiatrist")
return /area/medical
if("Geneticist")
return /area/medical/genetics
if("Research Director", "Scientist")
return /area/toxins
if("Roboticist")
return /area/assembly/robotics
if("Head of Security", "Warden", "Security Officer", "Detective", "Security Pod Pilot", "Brig Physician", "Magistrate", "Internal Affairs Agent")
return /area/security
if("Botanist")
return /area/hydroponics
else
return pick(/area/hallway, /area/crew_quarters)
/mob/living/carbon/human/interactive/proc/target_filter(target)
var/list/filtered_targets = list(/area, /turf, /obj/machinery/door, /atom/movable/lighting_overlay, /obj/structure/cable, /obj/machinery/atmospherics, /obj/item/radio/intercom)
var/list/L = target
for(var/atom/A in target) // added a bunch of "junk" that clogs up the general find procs
if(is_type_in_list(A,filtered_targets))
L -= A
return L
/mob/living/carbon/human/interactive/proc/shouldModulePass() // returns 1 if the npc is in anything "primary"
if(doing & (SNPC_FIGHTING | SNPC_SPECIAL))
return 1
if(retal)
return 1
return 0
/mob/living/carbon/human/interactive/proc/getAllContents()
var/list/allContents = list()
for(var/atom/A in contents)
allContents += A
if(A.contents.len)
for(var/atom/B in A)
allContents += B
return allContents
/mob/living/carbon/human/interactive/proc/enforceHome()
var/list/validHome = get_area_turfs(job2area(myjob))
if(TARGET)
var/atom/tcheck = TARGET
if(tcheck)
if(!(get_turf(tcheck) in validHome))
TARGET = null
return 1
if(!(get_turf(src) in validHome) && validHome.len)
tryWalk(pick(get_area_turfs(job2area(myjob))))
return 1
return 0
/mob/living/carbon/human/interactive/proc/npcDrop(obj/item/A, blacklist = 0)
if(blacklist)
blacklistItems += A
unEquip(A)
enforce_hands()
update_icons()
/mob/living/carbon/human/interactive/proc/compareFaction(list/targetFactions)
var/hasSame = 0
for(var/A in targetFactions)
if(A in faction)
hasSame = 1
return hasSame
/mob/living/carbon/human/interactive/proc/nearbyscan(obj)
nearby = list()
for(var/mob/living/M in view(4,src))
if(M != src)
nearby += M
/mob/living/carbon/human/interactive/rename_character(oldname, newname)
if(!..())
return 0
if(oldname)
if(MYID)
MYID.registered_name = newname
MYID.name = "[newname]'s ID Card ([MYID.assignment])"
if(RPID)
RPID.registered_name = MYID.registered_name
RPID.name = MYID.name
return 1
@@ -1,24 +0,0 @@
/mob/living/carbon/human/interactive/angry/Initialize(mapload)
TRAITS |= TRAIT_ROBUST
TRAITS |= TRAIT_MEAN
faction += "bot_angry"
return ..()
/mob/living/carbon/human/interactive/friendly/Initialize(mapload)
TRAITS |= TRAIT_FRIENDLY
TRAITS |= TRAIT_UNROBUST
faction += "bot_friendly"
faction += "neutral"
functions -= "combat"
return ..()
/mob/living/carbon/human/interactive/greytide/Initialize(mapload)
TRAITS |= TRAIT_ROBUST
TRAITS |= TRAIT_MEAN
TRAITS |= TRAIT_THIEVING
TRAITS |= TRAIT_DUMB
maxInterest = 5 // really short attention span
targetInterestShift = 2 // likewise
faction += "bot_grey"
graytide = 1
return ..()
+16 -6
View File
@@ -62,27 +62,38 @@
return ..()
/mob/living/carbon/human/proc/HasVoiceChanger()
if(istype(back,/obj/item/rig))
if(istype(back, /obj/item/rig))
var/obj/item/rig/rig = back
if(rig.speech && rig.speech.voice_holder && rig.speech.voice_holder.active && rig.speech.voice_holder.voice)
return rig.speech.voice_holder.voice
for(var/obj/item/gear in list(wear_mask,wear_suit,head))
for(var/obj/item/gear in list(wear_mask, wear_suit, head))
if(!gear)
continue
var/obj/item/voice_changer/changer = locate() in gear
if(changer && changer.active && changer.voice)
return changer.voice
return 0
if(changer && changer.active)
if(changer.voice)
return changer.voice
else if(wear_id)
var/obj/item/card/id/idcard = wear_id.GetID()
if(istype(idcard))
return idcard.registered_name
return FALSE
/mob/living/carbon/human/GetVoice()
var/has_changer = HasVoiceChanger()
if(has_changer)
return has_changer
if(mind && mind.changeling && mind.changeling.mimicing)
return mind.changeling.mimicing
if(GetSpecialVoice())
return GetSpecialVoice()
return real_name
/mob/living/carbon/human/IsVocal()
@@ -124,7 +135,6 @@
span = mind.speech_span
if((COMIC in mutations) \
|| (locate(/obj/item/organ/internal/cyberimp/brain/clown_voice) in internal_organs) \
|| istype(get_item_by_slot(slot_wear_mask), /obj/item/clothing/mask/gas/voice/clown) \
|| GetComponent(/datum/component/jestosterone))
span = "sans"
+9
View File
@@ -8,6 +8,15 @@
return 0
var/datum/gas_mixture/environment = loc.return_air()
if(client || registered_z) // This is a temporary error tracker to make sure we've caught everything
var/turf/T = get_turf(src)
if(client && registered_z != T.z)
message_admins("[src] [ADMIN_FLW(src, "FLW")] has somehow ended up in Z-level [T.z] despite being registered in Z-level [registered_z]. If you could ask them how that happened and notify the coders, it would be appreciated.")
log_game("Z-TRACKING: [src] has somehow ended up in Z-level [T.z] despite being registered in Z-level [registered_z].")
update_z(T.z)
else if (!client && registered_z)
log_game("Z-TRACKING: [src] of type [src.type] has a Z-registration despite not having a client.")
update_z(null)
if(stat != DEAD)
//Chemicals in the body
handle_chemicals_in_body()
+21
View File
@@ -953,6 +953,27 @@
to_chat(src, "<span class='notice'>You can taste [english_list(final_taste_list)].</span>")
/mob/living/proc/update_z(new_z) // 1+ to register, null to unregister
if(registered_z != new_z)
if(registered_z)
SSmobs.clients_by_zlevel[registered_z] -= src
if(client)
if(new_z)
SSmobs.clients_by_zlevel[new_z] += src
for (var/I in length(SSidlenpcpool.idle_mobs_by_zlevel[new_z]) to 1 step -1) //Backwards loop because we're removing (guarantees optimal rather than worst-case performance), it's fine to use .len here but doesn't compile on 511
var/mob/living/simple_animal/SA = SSidlenpcpool.idle_mobs_by_zlevel[new_z][I]
if (SA)
SA.toggle_ai(AI_ON) // Guarantees responsiveness for when appearing right next to mobs
else
SSidlenpcpool.idle_mobs_by_zlevel[new_z] -= SA
registered_z = new_z
else
registered_z = null
/mob/living/onTransitZ(old_z,new_z)
..()
update_z(new_z)
/mob/living/proc/owns_soul()
if(mind)
return mind.soulOwner == mind
+4
View File
@@ -5,6 +5,10 @@
update_stat("mob login")
update_sight()
var/turf/T = get_turf(src)
if(isturf(T))
update_z(T.z)
//If they're SSD, remove it so they can wake back up.
player_logged = 0
//Vents
+1
View File
@@ -1,4 +1,5 @@
/mob/living/Logout()
update_z(null)
if(ranged_ability && client)
ranged_ability.remove_mousepointer(client)
..()
+4 -4
View File
@@ -634,7 +634,7 @@ var/list/ai_verbs_default = list(
return
if(href_list["trackbot"])
var/mob/living/simple_animal/bot/target = locate(href_list["trackbot"]) in GLOB.simple_animal_list
var/mob/living/simple_animal/bot/target = locate(href_list["trackbot"]) in GLOB.simple_animals
if(target)
ai_actual_track(target)
else
@@ -642,7 +642,7 @@ var/list/ai_verbs_default = list(
return
if(href_list["callbot"]) //Command a bot to move to a selected location.
Bot = locate(href_list["callbot"]) in GLOB.simple_animal_list
Bot = locate(href_list["callbot"]) in GLOB.simple_animals
if(!Bot || Bot.remote_disabled || control_disabled)
return //True if there is no bot found, the bot is manually emagged, or the AI is carded with wireless off.
waypoint_mode = 1
@@ -650,7 +650,7 @@ var/list/ai_verbs_default = list(
return
if(href_list["interface"]) //Remotely connect to a bot!
Bot = locate(href_list["interface"]) in GLOB.simple_animal_list
Bot = locate(href_list["interface"]) in GLOB.simple_animals
if(!Bot || Bot.remote_disabled || control_disabled)
return
Bot.attack_ai(src)
@@ -746,7 +746,7 @@ var/list/ai_verbs_default = list(
d += "<A HREF=?src=[UID()];botrefresh=\ref[Bot]>Query network status</A><br>"
d += "<table width='100%'><tr><td width='40%'><h3>Name</h3></td><td width='20%'><h3>Status</h3></td><td width='30%'><h3>Location</h3></td><td width='10%'><h3>Control</h3></td></tr>"
for(var/mob/living/simple_animal/bot/Bot in GLOB.simple_animal_list)
for(var/mob/living/simple_animal/bot/Bot in GLOB.simple_animals)
if(is_ai_allowed(Bot.z) && !Bot.remote_disabled) //Only non-emagged bots on the allowed Z-level are detected!
bot_area = get_area(Bot)
d += "<tr><td width='30%'>[Bot.hacked ? "<span class='bad'>(!) </span>[Bot.name]" : Bot.name] ([Bot.model])</td>"
@@ -451,7 +451,7 @@
response_harm = "kicks"
gold_core_spawnable = CHEM_MOB_SPAWN_INVALID
/mob/living/simple_animal/pet/corgi/Ian/process_ai()
/mob/living/simple_animal/pet/corgi/Ian/Life()
..()
//Feeding, chasing food, FOOOOODDDD
@@ -578,7 +578,7 @@
return
..()
/mob/living/simple_animal/pet/corgi/Lisa/process_ai()
/mob/living/simple_animal/pet/corgi/Lisa/Life()
..()
make_babies()
@@ -54,9 +54,8 @@
else if(prob(5))
emote("snuffles")
/mob/living/simple_animal/mouse/process_ai()
/mob/living/simple_animal/mouse/Life()
..()
if(prob(0.5))
stat = UNCONSCIOUS
icon_state = "mouse_[mouse_color]_sleep"
@@ -19,7 +19,7 @@
see_in_dark = 5
gold_core_spawnable = CHEM_MOB_SPAWN_FRIENDLY
/mob/living/simple_animal/pet/pug/process_ai()
/mob/living/simple_animal/pet/pug/Life()
..()
if(!resting && !buckled)
@@ -30,8 +30,6 @@
var/stat_exclusive = 0 //Mobs with this set to 1 will exclusively attack things defined by stat_attack, stat_attack 2 means they will only attack corpses
var/attack_same = 0 //Set us to 1 to allow us to attack our own faction, or 2, to only ever attack our own faction
var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever)
//typecache of things this mob will attack in DestroySurroundings() if it has environment_smash
var/list/environment_target_typecache = list(
/obj/machinery/door/window,
@@ -71,12 +69,6 @@
walk(src, 0)
return 0
/mob/living/simple_animal/hostile/process_ai()
..()
if(!AICanContinue())
return 0
return 1
/mob/living/simple_animal/hostile/handle_automated_action()
if(AIStatus == AI_OFF)
return 0
@@ -88,7 +80,7 @@
DestroySurroundings()
if(!MoveToTarget(possible_targets)) //if we lose our target
if(AIShouldSleep(possible_targets)) // we try to acquire a new one
AIStatus = AI_IDLE // otherwise we go idle
toggle_ai(AI_IDLE) // otherwise we go idle
return 1
/mob/living/simple_animal/hostile/attacked_by(obj/item/I, mob/living/user)
@@ -272,8 +264,8 @@
if(search_objects)//Turn off item searching and ignore whatever item we were looking at, we're more concerned with fight or flight
search_objects = 0
target = null
if(AIStatus == AI_IDLE)
AIStatus = AI_ON
if(AIStatus != AI_ON && AIStatus != AI_OFF)
toggle_ai(AI_ON)
FindTarget()
else if(target != null && prob(40))//No more pulling a mob forever and having a second player attack it, it can switch targets now if it finds a more suitable one
FindTarget()
@@ -409,7 +401,7 @@
if(AI_IDLE)
if(FindTarget(possible_targets, 1))
. = 1
AIStatus = AI_ON //Wake up for more than one Life() cycle.
toggle_ai(AI_ON) //Wake up for more than one Life() cycle.
else
. = 0
@@ -426,3 +418,37 @@
/mob/living/simple_animal/hostile/proc/LosePatience()
deltimer(lose_patience_timer_id)
/mob/living/simple_animal/hostile/consider_wakeup()
..()
var/list/tlist
var/turf/T = get_turf(src)
if(!T)
return
if(!length(SSmobs.clients_by_zlevel[T.z])) // It's fine to use .len here but doesn't compile on 511
toggle_ai(AI_Z_OFF)
return
var/cheap_search = isturf(T) && !(T.z == 1) // The original check for SSmapping's station z level trait, unfortunately it isn't here.
if(cheap_search)
tlist = ListTargetsLazy(T.z)
else
tlist = ListTargets()
if(AIStatus == AI_IDLE && FindTarget(tlist, 1))
if(cheap_search) //Try again with full effort
FindTarget()
toggle_ai(AI_ON)
/mob/living/simple_animal/hostile/proc/ListTargetsLazy(var/_Z)//Step 1, find out what we can see
var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha, /obj/spacepod))
. = list()
for(var/I in SSmobs.clients_by_zlevel[_Z])
var/mob/M = I
if(get_dist(M, src) < vision_range)
if(isturf(M.loc))
. += M
else if(M.loc.type in hostile_machines)
. += M.loc
@@ -35,7 +35,7 @@
var/pre_attack_icon = "Goliath_preattack"
loot = list(/obj/item/stack/sheet/animalhide/goliath_hide{layer = 4.1})
/mob/living/simple_animal/hostile/asteroid/goliath/process_ai()
/mob/living/simple_animal/hostile/asteroid/goliath/Life()
..()
handle_preattack()
@@ -0,0 +1,268 @@
/mob/living/simple_animal/hostile/asteroid/
vision_range = 2
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
unsuitable_atmos_damage = 15
faction = list("mining")
weather_immunities = list("lava","ash")
obj_damage = 30
environment_smash = 2
minbodytemp = 0
heat_damage_per_tick = 20
response_help = "pokes"
response_disarm = "shoves"
response_harm = "strikes"
status_flags = 0
a_intent = INTENT_HARM
var/throw_message = "bounces off of"
var/icon_aggro = null // for swapping to when we get aggressive
see_in_dark = 8
see_invisible = SEE_INVISIBLE_MINIMUM
mob_size = MOB_SIZE_LARGE
/mob/living/simple_animal/hostile/asteroid/Aggro()
..()
icon_state = icon_aggro
/mob/living/simple_animal/hostile/asteroid/LoseAggro()
..()
if(stat == CONSCIOUS)
icon_state = icon_living
/mob/living/simple_animal/hostile/asteroid/bullet_act(var/obj/item/projectile/P)//Reduces damage from most projectiles to curb off-screen kills
if(!stat)
Aggro()
if(P.damage < 30 && P.damage_type != BRUTE)
P.damage = (P.damage / 3)
visible_message("<span class='danger'>The [P] has a reduced effect on [src]!</span>")
..()
/mob/living/simple_animal/hostile/asteroid/hitby(atom/movable/AM)//No floor tiling them to death, wiseguy
if(istype(AM, /obj/item))
var/obj/item/T = AM
if(!stat)
Aggro()
if(T.throwforce <= 20)
visible_message("<span class='notice'>The [T.name] [src.throw_message] [src.name]!</span>")
return
..()
/mob/living/simple_animal/hostile/asteroid/basilisk
name = "basilisk"
desc = "A territorial beast, covered in a thick shell that absorbs energy. Its stare causes victims to freeze from the inside."
icon = 'icons/mob/animal.dmi'
icon_state = "Basilisk"
icon_living = "Basilisk"
icon_aggro = "Basilisk_alert"
icon_dead = "Basilisk_dead"
icon_gib = "syndicate_gib"
move_to_delay = 20
projectiletype = /obj/item/projectile/temp/basilisk
projectilesound = 'sound/weapons/pierce.ogg'
ranged = 1
ranged_message = "stares"
ranged_cooldown_time = 30
throw_message = "does nothing against the hard shell of"
vision_range = 2
speed = 3
maxHealth = 200
health = 200
harm_intent_damage = 5
obj_damage = 60
melee_damage_lower = 12
melee_damage_upper = 12
attacktext = "bites into"
a_intent = INTENT_HARM
speak_emote = list("chitters")
attack_sound = 'sound/weapons/bladeslice.ogg'
aggro_vision_range = 9
idle_vision_range = 2
turns_per_move = 5
loot = list(/obj/item/stack/ore/diamond{layer = 4.1},
/obj/item/stack/ore/diamond{layer = 4.1})
/obj/item/projectile/temp/basilisk
name = "freezing blast"
icon_state = "ice_2"
damage = 0
damage_type = BURN
nodamage = 1
flag = "energy"
temperature = 50
/mob/living/simple_animal/hostile/asteroid/basilisk/GiveTarget(var/new_target)
if(..()) //we have a target
if(isliving(target))
var/mob/living/L = target
if(L.bodytemperature > 261)
L.bodytemperature = 261
visible_message("<span class='danger'>The [src.name]'s stare chills [L.name] to the bone!</span>")
/mob/living/simple_animal/hostile/asteroid/basilisk/ex_act(severity)
switch(severity)
if(1.0)
gib()
if(2.0)
adjustBruteLoss(140)
if(3.0)
adjustBruteLoss(110)
/mob/living/simple_animal/hostile/asteroid/goliath
name = "goliath"
desc = "A massive beast that uses long tentacles to ensare its prey, threatening them is not advised under any conditions."
icon = 'icons/mob/animal.dmi'
icon_state = "Goliath"
icon_living = "Goliath"
icon_aggro = "Goliath_alert"
icon_dead = "Goliath_dead"
icon_gib = "syndicate_gib"
attack_sound = 'sound/weapons/punch4.ogg'
mouse_opacity = MOUSE_OPACITY_OPAQUE
move_to_delay = 40
ranged = 1
ranged_cooldown = 2 //By default, start the Goliath with his cooldown off so that people can run away quickly on first sight
ranged_cooldown_time = 120
friendly = "wails at"
speak_emote = list("bellows")
vision_range = 4
speed = 3
maxHealth = 300
health = 300
harm_intent_damage = 1 //Only the manliest of men can kill a Goliath with only their fists.
obj_damage = 100
melee_damage_lower = 25
melee_damage_upper = 25
attacktext = "pulverizes"
attack_sound = 'sound/weapons/punch1.ogg'
throw_message = "does nothing to the rocky hide of the"
aggro_vision_range = 9
idle_vision_range = 5
move_force = MOVE_FORCE_VERY_STRONG
move_resist = MOVE_FORCE_VERY_STRONG
pull_force = MOVE_FORCE_VERY_STRONG
var/pre_attack = 0
loot = list(/obj/item/asteroid/goliath_hide{layer = 4.1})
/mob/living/simple_animal/hostile/asteroid/goliath/Life()
..()
handle_preattack()
/mob/living/simple_animal/hostile/asteroid/goliath/proc/handle_preattack()
if(ranged_cooldown <= world.time + ranged_cooldown_time * 0.25 && !pre_attack)
pre_attack++
if(!pre_attack || stat || AIStatus == AI_IDLE)
return
icon_state = "Goliath_preattack"
/mob/living/simple_animal/hostile/asteroid/goliath/revive()
move_force = MOVE_FORCE_VERY_STRONG
move_resist = MOVE_FORCE_VERY_STRONG
pull_force = MOVE_FORCE_VERY_STRONG
..()
/mob/living/simple_animal/hostile/asteroid/goliath/OpenFire()
var/tturf = get_turf(target)
if(get_dist(src, target) <= 7)//Screen range check, so you can't get tentacle'd offscreen
visible_message("<span class='warning'>The [src.name] digs its tentacles under [target.name]!</span>")
new /obj/effect/goliath_tentacle/original(tturf)
ranged_cooldown = world.time + ranged_cooldown_time
icon_state = icon_aggro
pre_attack = 0
return
/mob/living/simple_animal/hostile/asteroid/goliath/adjustHealth(damage)
ranged_cooldown--
handle_preattack()
..()
/mob/living/simple_animal/hostile/asteroid/goliath/Aggro()
vision_range = aggro_vision_range
handle_preattack()
if(icon_state != icon_aggro)
icon_state = icon_aggro
return
/obj/effect/goliath_tentacle/
name = "Goliath tentacle"
icon = 'icons/mob/animal.dmi'
icon_state = "Goliath_tentacle"
var/latched = 0
/obj/effect/goliath_tentacle/New()
var/turftype = get_turf(src)
if(istype(turftype, /turf/simulated/mineral))
var/turf/simulated/mineral/M = turftype
M.gets_drilled()
spawn(20)
Trip()
/obj/effect/goliath_tentacle/original
/obj/effect/goliath_tentacle/original/New()
for(var/obj/effect/goliath_tentacle/original/O in loc)//No more GG NO RE from 2+ goliaths simultaneously tentacling you
if(O != src)
qdel(src)
var/list/directions = cardinal.Copy()
var/counter
for(counter = 1, counter <= 3, counter++)
var/spawndir = pick(directions)
directions -= spawndir
var/turf/T = get_step(src,spawndir)
new /obj/effect/goliath_tentacle(T)
..()
/obj/effect/goliath_tentacle/proc/Trip()
for(var/mob/living/M in src.loc)
M.Stun(5)
M.adjustBruteLoss(rand(10,15))
latched = 1
if(src && M)
visible_message("<span class='danger'>The [src.name] grabs hold of [M.name]!</span>")
if(!latched)
qdel(src)
else
spawn(50)
qdel(src)
/obj/item/asteroid/goliath_hide
name = "goliath hide plates"
desc = "Pieces of a goliath's rocky hide, these might be able to make your suit a bit more durable to attack from the local fauna."
icon = 'icons/obj/items.dmi'
icon_state = "goliath_hide"
flags = NOBLUDGEON
w_class = WEIGHT_CLASS_NORMAL
layer = 4
/obj/item/asteroid/goliath_hide/afterattack(atom/target, mob/user, proximity_flag)
if(proximity_flag)
if(istype(target, /obj/item/clothing/suit/space/hardsuit/mining) || istype(target, /obj/item/clothing/head/helmet/space/hardsuit/mining) || istype(target, /obj/item/clothing/suit/space/eva/plasmaman/miner) || istype(target, /obj/item/clothing/head/helmet/space/eva/plasmaman/miner))
var/obj/item/clothing/C = target
var/current_armor = C.armor
if(current_armor["melee"] < 60)
current_armor["melee"] = min(current_armor["melee"] + 10, 60)
to_chat(user, "<span class='info'>You strengthen [target], improving its resistance against melee attacks.</span>")
qdel(src)
else
to_chat(user, "<span class='info'>You can't improve [C] any further.</span>")
return
if(istype(target, /obj/mecha/working/ripley))
var/obj/mecha/D = target
if(D.icon_state != "ripley-open")
to_chat(user, "<span class='info'>You can't add armour onto the mech while someone is inside!</span>")
return
var/list/damage_absorption = D.damage_absorption
if(damage_absorption["brute"] > 0.3)
damage_absorption["brute"] = max(damage_absorption["brute"] - 0.1, 0.3)
damage_absorption["bullet"] = damage_absorption["bullet"] - 0.05
damage_absorption["fire"] = damage_absorption["fire"] - 0.05
damage_absorption["laser"] = damage_absorption["laser"] - 0.025
to_chat(user, "<span class='info'>You strengthen [target], improving its resistance against melee attacks.</span>")
qdel(src)
D.overlays += image("icon"="mecha.dmi", "icon_state"="ripley-g-open")
D.desc = "Autonomous Power Loader Unit. Its armour is enhanced with some goliath hide plates."
if(damage_absorption["brute"] == 0.3)
D.overlays += image("icon"="mecha.dmi", "icon_state"="ripley-g-full-open")
D.desc = "Autonomous Power Loader Unit. It's wearing a fearsome carapace entirely composed of goliath hide plates - the pilot must be an experienced monster hunter."
else
to_chat(user, "<span class='warning'>You can't improve [D] any further!</span>")
return
@@ -80,10 +80,14 @@
var/deathmessage = ""
var/death_sound = null //The sound played on death
var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever)
var/can_have_ai = TRUE //once we have become sentient, we can never go back
var/shouldwakeup = FALSE //convenience var for forcibly waking up an idling AI on next check.
/mob/living/simple_animal/Initialize()
..()
GLOB.simple_animal_list += src
GLOB.simple_animals[AIStatus] += src
verbs -= /mob/verb/observe
if(!can_hide)
verbs -= /mob/living/simple_animal/verb/hide
@@ -97,7 +101,18 @@
collar.forceMove(loc)
collar = null
master_commander = null
GLOB.simple_animal_list -= src
GLOB.simple_animals[AIStatus] -= src
if(SSnpcpool.state == SS_PAUSED && LAZYLEN(SSnpcpool.currentrun))
SSnpcpool.currentrun -= src
if(nest)
nest.spawned_mobs -= src
nest = null
var/turf/T = get_turf(src)
if (T && AIStatus == AI_Z_OFF)
SSidlenpcpool.idle_mobs_by_zlevel[T.z] -= src
return ..()
/mob/living/simple_animal/Login()
@@ -111,12 +126,6 @@
health = Clamp(health, 0, maxHealth)
med_hud_set_status()
/mob/living/simple_animal/proc/process_ai()
handle_automated_movement()
handle_automated_action()
handle_automated_speech()
/mob/living/simple_animal/lay_down()
..()
handle_resting_state_icons()
@@ -562,6 +571,8 @@
/* End Inventory */
/mob/living/simple_animal/proc/sentience_act() //Called when a simple animal gains sentience via gold slime potion
toggle_ai(AI_OFF)
can_have_ai = FALSE
return
/mob/living/simple_animal/update_sight()
@@ -581,4 +592,37 @@
return
/mob/living/simple_animal/can_hear()
. = TRUE
. = TRUE
/mob/living/simple_animal/proc/consider_wakeup()
if(pulledby || shouldwakeup)
toggle_ai(AI_ON)
/mob/living/simple_animal/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
. = ..()
if(!ckey && !stat)//Not unconscious
if(AIStatus == AI_IDLE)
toggle_ai(AI_ON)
/mob/living/simple_animal/proc/toggle_ai(togglestatus)
if(!can_have_ai && (togglestatus != AI_OFF))
return
if(AIStatus != togglestatus)
if(togglestatus > 0 && togglestatus < 5)
if(togglestatus == AI_Z_OFF || AIStatus == AI_Z_OFF)
var/turf/T = get_turf(src)
if(AIStatus == AI_Z_OFF)
SSidlenpcpool.idle_mobs_by_zlevel[T.z] -= src
else
SSidlenpcpool.idle_mobs_by_zlevel[T.z] += src
GLOB.simple_animals[AIStatus] -= src
GLOB.simple_animals[togglestatus] += src
AIStatus = togglestatus
else
stack_trace("Something attempted to set simple animals AI to an invalid state: [togglestatus]")
/mob/living/simple_animal/onTransitZ(old_z, new_z)
..()
if(AIStatus == AI_Z_OFF)
SSidlenpcpool.idle_mobs_by_zlevel[old_z] -= src
toggle_ai(initial(AIStatus))
@@ -29,7 +29,7 @@
spawned_mobs = null
return ..()
/mob/living/simple_animal/hostile/spawner/process_ai()
/mob/living/simple_animal/hostile/spawner/Life()
..()
spawn_mob()
+2
View File
@@ -196,9 +196,11 @@
var/list/permanent_huds = list()
var/list/actions = list()
var/list/datum/action/chameleon_item_actions
var/list/progressbars = null //for stacking do_after bars
var/list/tkgrabbed_objects = list() // Assoc list of items to TK grabs
var/forced_look = null // This can either be a numerical direction or a soft object reference (UID). It makes the mob always face towards the selected thing.
var/registered_z
+28 -24
View File
@@ -193,7 +193,7 @@
close_spawn_windows()
var/obj/O = locate("landmark*Observer-Start")
to_chat(src, "<span class='notice'>Now teleporting.</span>")
observer.loc = O.loc
observer.forceMove(O.loc)
observer.timeofdeath = world.time // Set the time of death so that the respawn timer works correctly.
client.prefs.update_preview_icon(1)
observer.icon = client.prefs.preview_icon
@@ -344,27 +344,27 @@
else if(IsSyndicateCommand(rank))
character.loc = pick(syndicateofficer)
else
character.loc = pick(aroomwarp)
character.forceMove(pick(aroomwarp))
join_message = "has arrived"
else
if(spawning_at)
S = spawntypes[spawning_at]
if(S && istype(S))
if(S.check_job_spawning(rank))
character.loc = pick(S.turfs)
character.forceMove(pick(S.turfs))
join_message = S.msg
else
to_chat(character, "Your chosen spawnpoint ([S.display_name]) is unavailable for your chosen job. Spawning you at the Arrivals shuttle instead.")
character.loc = pick(latejoin)
character.forceMove(pick(latejoin))
join_message = "has arrived on the station"
else
character.loc = pick(latejoin)
character.forceMove(pick(latejoin))
join_message = "has arrived on the station"
character.lastarea = get_area(loc)
// Moving wheelchair if they have one
if(character.buckled && istype(character.buckled, /obj/structure/chair/wheelchair))
character.buckled.loc = character.loc
character.buckled.forceMove(character.loc)
character.buckled.dir = character.dir
character = SSjobs.EquipRank(character, rank, 1) //equips the human
@@ -464,8 +464,7 @@
dat += " [a.title]. </font><br>"
dat += "Choose from the following open positions:<br><br>"
var/num_jobs_available = 0
var/list/activePlayers = list()
var/list/categorizedJobs = list(
"Command" = list(jobs = list(), titles = command_positions, color = "#aac1ee"),
@@ -480,6 +479,7 @@
)
for(var/datum/job/job in SSjobs.occupations)
if(job && IsJobAvailable(job.title) && !job.barred_by_disability(client))
num_jobs_available++
activePlayers[job] = 0
var/categorized = 0
// Only players with the job assigned and AFK for less than 10 minutes count as active
@@ -502,23 +502,27 @@
if(!categorized)
categorizedJobs["Miscellaneous"]["jobs"] += job
dat += "<table><tr><td valign='top'>"
for(var/jobcat in categorizedJobs)
if(categorizedJobs[jobcat]["colBreak"])
dat += "</td><td valign='top'>"
if(length(categorizedJobs[jobcat]["jobs"]) < 1)
continue
var/color = categorizedJobs[jobcat]["color"]
dat += "<fieldset style='border: 2px solid [color]; display: inline'>"
dat += "<legend align='center' style='color: [color]'>[jobcat]</legend>"
for(var/datum/job/job in categorizedJobs[jobcat]["jobs"])
if(job in SSjobs.prioritized_jobs)
dat += "<a href='byond://?src=[UID()];SelectedJob=[job.title]'><font color='lime'><B>[job.title] ([job.current_positions]) (Active: [activePlayers[job]])</B></font></a><br>"
else
dat += "<a href='byond://?src=[UID()];SelectedJob=[job.title]'>[job.title] ([job.current_positions]) (Active: [activePlayers[job]])</a><br>"
dat += "</fieldset><br>"
if(num_jobs_available)
dat += "Choose from the following open positions:<br><br>"
dat += "<table><tr><td valign='top'>"
for(var/jobcat in categorizedJobs)
if(categorizedJobs[jobcat]["colBreak"])
dat += "</td><td valign='top'>"
if(length(categorizedJobs[jobcat]["jobs"]) < 1)
continue
var/color = categorizedJobs[jobcat]["color"]
dat += "<fieldset style='border: 2px solid [color]; display: inline'>"
dat += "<legend align='center' style='color: [color]'>[jobcat]</legend>"
for(var/datum/job/job in categorizedJobs[jobcat]["jobs"])
if(job in SSjobs.prioritized_jobs)
dat += "<a href='byond://?src=[UID()];SelectedJob=[job.title]'><font color='lime'><B>[job.title] ([job.current_positions]) (Active: [activePlayers[job]])</B></font></a><br>"
else
dat += "<a href='byond://?src=[UID()];SelectedJob=[job.title]'>[job.title] ([job.current_positions]) (Active: [activePlayers[job]])</a><br>"
dat += "</fieldset><br>"
dat += "</td></tr></table></center>"
dat += "</td></tr></table></center>"
else
dat += "<br><br><center>Unfortunately, there are no job slots free currently.<BR>Wait a few minutes, then try again.<BR>Or, try observing the round.</center>"
// Removing the old window method but leaving it here for reference
// src << browse(dat, "window=latechoices;size=300x640;can_close=1")
// Added the new browser window method
+11 -1
View File
@@ -6,7 +6,7 @@ Contents:
*/
/obj/item/clothing/mask/gas/voice/space_ninja
/obj/item/clothing/mask/gas/space_ninja
name = "ninja mask"
desc = "A close-fitting mask that acts both as an air filter and a post-modern fashion statement."
icon_state = "s-ninja(norm)"
@@ -19,3 +19,13 @@ Contents:
"Tajaran" = 'icons/mob/species/tajaran/mask.dmi',
"Vulpkanin" = 'icons/mob/species/vulpkanin/mask.dmi'
)
var/obj/item/voice_changer/voice_changer
/obj/item/clothing/mask/gas/space_ninja/Initialize(mapload)
. = ..()
voice_changer = new(src)
/obj/item/clothing/mask/gas/space_ninja/Destroy()
QDEL_NULL(voice_changer)
return ..()
+2 -2
View File
@@ -24,7 +24,7 @@ Contents:
var/obj/item/clothing/head/helmet/space/space_ninja/suitHood
var/obj/item/clothing/gloves/space_ninja/suitGloves
var/obj/item/clothing/shoes/space_ninja/suitShoes
var/obj/item/clothing/mask/gas/voice/space_ninja/suitMask
var/obj/item/clothing/mask/gas/space_ninja/suitMask
var/mob/living/carbon/human/suitOccupant
/obj/item/clothing/suit/space/space_ninja/proc/toggle_suit_lock(mob/living/carbon/human/user)
@@ -41,7 +41,7 @@ Contents:
if(!istype(user.shoes, /obj/item/clothing/shoes/space_ninja))
to_chat(user, "<span style='color: #ff0000;'><b>ERROR:</b> Unable to locate foot gear.\nABORTING...</span>")
return 0
if(!istype(user.wear_mask, /obj/item/clothing/mask/gas/voice/space_ninja))
if(!istype(user.wear_mask, /obj/item/clothing/mask/gas/space_ninja))
to_chat(user, "<span style='color: #ff0000;'><b>ERROR:</b> Unable to locate mask.\nABORTING...</span>")
return 0
-24
View File
@@ -92,27 +92,3 @@
icon_state = "stamp-syndicate"
item_color = "syndicate"
// Syndicate stamp to forge documents.
/obj/item/stamp/chameleon/attack_self(mob/user as mob)
var/list/stamp_types = typesof(/obj/item/stamp) - src.type // Get all stamp types except our own
var/list/stamps = list()
// Generate them into a list
for(var/stamp_type in stamp_types)
var/obj/item/stamp/S = new stamp_type
stamps[capitalize(S.name)] = S
var/list/show_stamps = list("EXIT" = null) + sortList(stamps) // the list that will be shown to the user to pick from
var/input_stamp = input(user, "Choose a stamp to disguise as.", "Choose a stamp.") in show_stamps
if(user && src in user.contents)
var/obj/item/stamp/chosen_stamp = stamps[capitalize(input_stamp)]
if(chosen_stamp)
name = chosen_stamp.name
icon_state = chosen_stamp.icon_state
item_color = chosen_stamp.item_color
+1 -1
View File
@@ -392,7 +392,7 @@
BucketData[++BucketData.len] = list("x" = 0, "y" = 0, dir=null, status = null)
var/CbotData[0]
for(var/mob/living/simple_animal/bot/cleanbot/B in GLOB.simple_animal_list)
for(var/mob/living/simple_animal/bot/cleanbot/B in GLOB.simple_animals)
var/turf/bl = get_turf(B)
if(bl)
if(bl.z != cl.z)
+8 -5
View File
@@ -1,9 +1,12 @@
// Shuttle on-movement //
/atom/movable/proc/onShuttleMove(turf/T1, rotation)
if(rotation)
shuttleRotate(rotation)
forceMove(T1)
return 1
/atom/movable/proc/onShuttleMove(turf/oldT, turf/T1, rotation)
var/turf/newT = get_turf(src)
if(newT.z != oldT.z)
onTransitZ(oldT.z, newT.z)
if(rotation)
shuttleRotate(rotation)
forceMove(T1)
return 1
/atom/movable/lighting_overlay/onShuttleMove()
return 0
+3
View File
@@ -490,6 +490,7 @@
var/turf/T1 = L1[i]
if(!T1)
continue
if(T0.type != T0.baseturf) //So if there is a hole in the shuttle we don't drag along the space/asteroid/etc to wherever we are going next
T0.copyTurf(T1)
areaInstance.contents += T1
@@ -714,6 +715,8 @@
possible_destinations = C.possible_destinations
shuttleId = C.shuttleId
/obj/machinery/computer/shuttle/Initialize(mapload)
. = ..()
connect()
/obj/machinery/computer/shuttle/proc/connect()