mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-19 02:54:41 +01:00
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:
@@ -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"
|
||||
|
||||
@@ -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.")
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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,\
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 ..()
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,4 +1,5 @@
|
||||
/mob/living/Logout()
|
||||
update_z(null)
|
||||
if(ranged_ability && client)
|
||||
ranged_ability.remove_mousepointer(client)
|
||||
..()
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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 ..()
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user