Merge branch 'master' into the-fuck-am-i-doing
This commit is contained in:
@@ -6,13 +6,21 @@ GLOBAL_PROTECT(admin_verbs_default)
|
||||
return list(
|
||||
/client/proc/deadmin, /*destroys our own admin datum so we can play as a regular player*/
|
||||
/client/proc/cmd_admin_say, /*admin-only ooc chat*/
|
||||
/client/proc/dsay, /*talk in deadchat using our ckey/fakekey*/
|
||||
/client/proc/deadchat,
|
||||
/client/proc/investigate_show, /*various admintools for investigation. Such as a singulo grief-log*/
|
||||
/client/proc/hide_verbs, /*hides all our adminverbs*/
|
||||
/client/proc/hide_most_verbs, /*hides all our hideable adminverbs*/
|
||||
/client/proc/debug_variables, /*allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify*/
|
||||
/client/proc/toggleprayers,
|
||||
/client/proc/toggleadminhelpsound,
|
||||
/client/proc/debugstatpanel,
|
||||
/client/proc/dsay, /*talk in deadchat using our ckey/fakekey*/
|
||||
/client/proc/investigate_show, /*various admintools for investigation. Such as a singulo grief-log*/
|
||||
/client/proc/secrets,
|
||||
/client/proc/toggle_hear_radio, /*allows admins to hide all radio output*/
|
||||
/client/proc/reload_admins,
|
||||
/client/proc/reestablish_db_connection, /*reattempt a connection to the database*/
|
||||
/client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/
|
||||
/client/proc/cmd_admin_pm_panel, /*admin-pm list*/
|
||||
/client/proc/stop_sounds,
|
||||
/client/proc/mark_datum_mapview,
|
||||
/client/proc/debugstatpanel
|
||||
// /client/proc/fix_air /*resets air in designated radius to its default atmos composition*/
|
||||
)
|
||||
GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin())
|
||||
GLOBAL_PROTECT(admin_verbs_admin)
|
||||
@@ -24,6 +32,7 @@ GLOBAL_PROTECT(admin_verbs_admin)
|
||||
/datum/verbs/menu/Admin/verb/playerpanel,
|
||||
/client/proc/game_panel, /*game panel, allows to change game-mode etc*/
|
||||
/client/proc/check_ai_laws, /*shows AI and borg laws*/
|
||||
// /client/proc/ghost_pool_protection, /*opens a menu for toggling ghost roles*/
|
||||
/datum/admins/proc/toggleooc, /*toggles ooc on/off for everyone*/
|
||||
/datum/admins/proc/toggleooclocal, /*toggles looc on/off for everyone*/
|
||||
/datum/admins/proc/toggleoocdead, /*toggles ooc on/off for everyone who is dead*/
|
||||
@@ -35,15 +44,15 @@ GLOBAL_PROTECT(admin_verbs_admin)
|
||||
/client/proc/admin_ghost, /*allows us to ghost/reenter body at will*/
|
||||
/client/proc/toggle_view_range, /*changes how far we can see*/
|
||||
/client/proc/getserverlogs, /*for accessing server logs*/
|
||||
/client/proc/cmd_admin_subtle_message, /*send an message to somebody as a 'voice in their head'*/
|
||||
/client/proc/cmd_admin_headset_message, /*send an message to somebody through their headset as CentCom*/
|
||||
/client/proc/getcurrentlogs, /*for accessing server logs for the current round*/
|
||||
/client/proc/cmd_admin_subtle_message, /*send a message to somebody as a 'voice in their head'*/
|
||||
/client/proc/cmd_admin_headset_message, /*send a message to somebody through their headset as CentCom*/
|
||||
/client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/
|
||||
/client/proc/cmd_admin_check_contents, /*displays the contents of an instance*/
|
||||
/client/proc/centcom_podlauncher,/*Open a window to launch a Supplypod and configure it or it's contents*/
|
||||
/client/proc/check_antagonists, /*shows all antags*/
|
||||
/datum/admins/proc/access_news_network, /*allows access of newscasters*/
|
||||
/client/proc/jumptocoord, /*we ghost and jump to a coordinate*/
|
||||
/client/proc/getcurrentlogs, /*for accessing server logs for the current round*/
|
||||
/client/proc/Getmob, /*teleports a mob to our location*/
|
||||
/client/proc/Getkey, /*teleports a mob with a certain ckey to our location*/
|
||||
// /client/proc/sendmob, /*sends a mob somewhere*/ -Removed due to it needing two sorting procs to work, which were executed every time an admin right-clicked. ~Errorage
|
||||
@@ -53,6 +62,8 @@ GLOBAL_PROTECT(admin_verbs_admin)
|
||||
/client/proc/jumptoturf, /*allows us to jump to a specific turf*/
|
||||
/client/proc/admin_call_shuttle, /*allows us to call the emergency shuttle*/
|
||||
/client/proc/admin_cancel_shuttle, /*allows us to cancel the emergency shuttle, sending it back to centcom*/
|
||||
// /client/proc/admin_disable_shuttle, /*allows us to disable the emergency shuttle admin-wise so that it cannot be called*/
|
||||
// /client/proc/admin_enable_shuttle, /*undoes the above*/
|
||||
/client/proc/cmd_admin_direct_narrate, /*send text directly to a player with no padding. Useful for narratives and fluff-text*/
|
||||
/client/proc/cmd_admin_world_narrate, /*sends text to all players with no padding*/
|
||||
/client/proc/cmd_admin_local_narrate, /*sends text to all mobs within view of atom*/
|
||||
@@ -64,25 +75,19 @@ GLOBAL_PROTECT(admin_verbs_admin)
|
||||
/client/proc/toggle_combo_hud, // toggle display of the combination pizza antag and taco sci/med/eng hud
|
||||
/client/proc/toggle_AI_interact, /*toggle admin ability to interact with machines as an AI*/
|
||||
/datum/admins/proc/open_shuttlepanel, /* Opens shuttle manipulator UI */
|
||||
/client/proc/deadchat,
|
||||
/client/proc/toggleprayers,
|
||||
// /client/proc/toggle_prayer_sound,
|
||||
// /client/proc/colorasay,
|
||||
// /client/proc/resetasaycolor,
|
||||
/client/proc/toggleadminhelpsound,
|
||||
/client/proc/respawn_character,
|
||||
/client/proc/secrets,
|
||||
/client/proc/toggle_hear_radio, /*allows admins to hide all radio output*/
|
||||
/client/proc/reload_admins,
|
||||
/client/proc/reestablish_db_connection, /*reattempt a connection to the database*/
|
||||
/client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/
|
||||
/client/proc/cmd_admin_pm_panel, /*admin-pm list*/
|
||||
/client/proc/panicbunker,
|
||||
/client/proc/addbunkerbypass,
|
||||
/client/proc/revokebunkerbypass,
|
||||
/client/proc/stop_sounds,
|
||||
/client/proc/mark_datum_mapview,
|
||||
/client/proc/hide_verbs, /*hides all our adminverbs*/
|
||||
/client/proc/hide_most_verbs, /*hides all our hideable adminverbs*/
|
||||
/datum/admins/proc/open_borgopanel,
|
||||
/client/proc/admin_cmd_respawn_return_to_lobby,
|
||||
/client/proc/admin_cmd_remove_ghost_respawn_timer
|
||||
/client/proc/admin_cmd_respawn_return_to_lobby, //CIT
|
||||
/client/proc/admin_cmd_remove_ghost_respawn_timer, //CIT
|
||||
/client/proc/addbunkerbypass, //CIT
|
||||
/client/proc/revokebunkerbypass, //CIT
|
||||
/datum/admins/proc/open_borgopanel
|
||||
)
|
||||
|
||||
GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/DB_ban_panel, /client/proc/stickybanpanel))
|
||||
GLOBAL_PROTECT(admin_verbs_ban)
|
||||
GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_sound, /client/proc/manual_play_web_sound, /client/proc/set_round_end_sound))
|
||||
@@ -110,13 +115,14 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list(
|
||||
/client/proc/show_tip,
|
||||
/client/proc/smite,
|
||||
/client/proc/admin_away,
|
||||
/client/proc/cmd_admin_toggle_fov,
|
||||
/client/proc/cmd_admin_toggle_fov, //CIT CHANGE - FOV
|
||||
/client/proc/roll_dices //CIT CHANGE - Adds dice verb
|
||||
))
|
||||
GLOBAL_PROTECT(admin_verbs_fun)
|
||||
GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/podspawn_atom, /datum/admins/proc/spawn_cargo, /datum/admins/proc/spawn_objasmob, /client/proc/respawn_character))
|
||||
GLOBAL_PROTECT(admin_verbs_spawn)
|
||||
GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer())
|
||||
GLOBAL_PROTECT(admin_verbs_server)
|
||||
/world/proc/AVerbsServer()
|
||||
return list(
|
||||
/datum/admins/proc/startnow,
|
||||
@@ -126,17 +132,20 @@ GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer())
|
||||
/datum/admins/proc/toggleaban,
|
||||
/client/proc/everyone_random,
|
||||
/datum/admins/proc/toggleAI,
|
||||
/datum/admins/proc/toggleMulticam,
|
||||
/datum/admins/proc/toggledynamicvote,
|
||||
/datum/admins/proc/toggleMulticam, //CIT
|
||||
/datum/admins/proc/toggledynamicvote, //CIT
|
||||
/client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/
|
||||
/client/proc/cmd_debug_del_all,
|
||||
/client/proc/toggle_random_events,
|
||||
/client/proc/forcerandomrotate,
|
||||
/client/proc/adminchangemap,
|
||||
/client/proc/toggle_hub
|
||||
/client/proc/panicbunker,
|
||||
// /client/proc/toggle_interviews,
|
||||
/client/proc/toggle_hub,
|
||||
/client/proc/toggle_cdn
|
||||
)
|
||||
GLOBAL_PROTECT(admin_verbs_server)
|
||||
GLOBAL_LIST_INIT(admin_verbs_debug, world.AVerbsDebug())
|
||||
GLOBAL_PROTECT(admin_verbs_debug)
|
||||
/world/proc/AVerbsDebug()
|
||||
return list(
|
||||
/client/proc/restart_controller,
|
||||
@@ -174,27 +183,37 @@ GLOBAL_LIST_INIT(admin_verbs_debug, world.AVerbsDebug())
|
||||
/client/proc/cmd_display_init_log,
|
||||
/client/proc/cmd_display_overlay_log,
|
||||
/client/proc/reload_configuration,
|
||||
// /client/proc/atmos_control,
|
||||
// /client/proc/reload_cards,
|
||||
// /client/proc/validate_cards,
|
||||
// /client/proc/test_cardpack_distribution,
|
||||
// /client/proc/print_cards,
|
||||
// #ifdef TESTING
|
||||
// /client/proc/check_missing_sprites,
|
||||
// #endif
|
||||
/datum/admins/proc/create_or_modify_area,
|
||||
#ifdef REFERENCE_TRACKING
|
||||
/datum/admins/proc/view_refs,
|
||||
/datum/admins/proc/view_del_failures,
|
||||
#endif
|
||||
/client/proc/generate_wikichem_list, //DO NOT PRESS UNLESS YOU WANT SUPERLAG
|
||||
// /client/proc/check_timer_sources,
|
||||
/client/proc/toggle_cdn,
|
||||
/client/proc/generate_wikichem_list //DO NOT PRESS UNLESS YOU WANT SUPERLAG
|
||||
)
|
||||
GLOBAL_PROTECT(admin_verbs_debug)
|
||||
GLOBAL_LIST_INIT(admin_verbs_possess, list(/proc/possess, /proc/release))
|
||||
GLOBAL_PROTECT(admin_verbs_possess)
|
||||
GLOBAL_LIST_INIT(admin_verbs_permissions, list(/client/proc/edit_admin_permissions))
|
||||
GLOBAL_PROTECT(admin_verbs_permissions)
|
||||
GLOBAL_LIST_INIT(admin_verbs_poll, list(/client/proc/create_poll))
|
||||
GLOBAL_PROTECT(admin_verbs_poll)
|
||||
|
||||
//verbs which can be hidden - needs work
|
||||
GLOBAL_PROTECT(admin_verbs_poll)
|
||||
GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
/client/proc/set_ooc,
|
||||
/client/proc/reset_ooc,
|
||||
/client/proc/deadmin,
|
||||
/datum/admins/proc/show_traitor_panel,
|
||||
// /datum/admins/proc/show_skill_panel,
|
||||
/datum/admins/proc/toggleenter,
|
||||
/datum/admins/proc/toggleguests,
|
||||
/datum/admins/proc/announce,
|
||||
@@ -239,7 +258,7 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
/client/proc/Debug2,
|
||||
/client/proc/reload_admins,
|
||||
/client/proc/cmd_debug_make_powernets,
|
||||
/client/proc/startSinglo,
|
||||
/client/proc/startSinglo, // tg removed this
|
||||
/client/proc/cmd_debug_mob_lists,
|
||||
/client/proc/cmd_debug_del_all,
|
||||
/client/proc/enable_debug_verbs,
|
||||
@@ -247,8 +266,9 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
/proc/release,
|
||||
/client/proc/reload_admins,
|
||||
/client/proc/panicbunker,
|
||||
/client/proc/addbunkerbypass,
|
||||
/client/proc/revokebunkerbypass,
|
||||
/client/proc/addbunkerbypass, //CIT
|
||||
/client/proc/revokebunkerbypass, //CIT
|
||||
// /client/proc/toggle_interviews,
|
||||
/client/proc/admin_change_sec_level,
|
||||
/client/proc/toggle_nuke,
|
||||
/client/proc/cmd_display_del_log,
|
||||
@@ -322,7 +342,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
remove_verb(src, /client/proc/hide_most_verbs)
|
||||
add_verb(src, /client/proc/show_verbs)
|
||||
|
||||
to_chat(src, "<span class='interface'>Most of your adminverbs have been hidden.</span>")
|
||||
to_chat(src, "<span class='interface'>Most of your adminverbs have been hidden.</span>", confidential = TRUE)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Hide Most Adminverbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
|
||||
@@ -333,7 +353,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
remove_admin_verbs()
|
||||
add_verb(src, /client/proc/show_verbs)
|
||||
|
||||
to_chat(src, "<span class='interface'>Almost all of your adminverbs have been hidden.</span>")
|
||||
to_chat(src, "<span class='interface'>Almost all of your adminverbs have been hidden.</span>", confidential = TRUE)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Hide All Adminverbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
|
||||
@@ -344,7 +364,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
remove_verb(src, /client/proc/show_verbs)
|
||||
add_admin_verbs()
|
||||
|
||||
to_chat(src, "<span class='interface'>All of your adminverbs are now visible.</span>")
|
||||
to_chat(src, "<span class='interface'>All of your adminverbs are now visible.</span>", confidential = TRUE)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Adminverbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
@@ -354,7 +374,8 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
set category = "Admin.Game"
|
||||
set name = "Aghost"
|
||||
if(!holder)
|
||||
return FALSE
|
||||
return
|
||||
. = TRUE
|
||||
if(isobserver(mob))
|
||||
//re-enter
|
||||
var/mob/dead/observer/ghost = mob
|
||||
@@ -367,7 +388,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
ghost.reenter_corpse()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Admin Reenter") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
else if(isnewplayer(mob))
|
||||
to_chat(src, "<font color='red'>Error: Aghost: Can't admin-ghost whilst in the lobby. Join or Observe first.</font>")
|
||||
to_chat(src, "<font color='red'>Error: Aghost: Can't admin-ghost whilst in the lobby. Join or Observe first.</font>", confidential = TRUE)
|
||||
return FALSE
|
||||
else
|
||||
//ghostize
|
||||
@@ -375,10 +396,10 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
message_admins("[key_name_admin(usr)] admin ghosted.")
|
||||
var/mob/body = mob
|
||||
body.ghostize(1, voluntary = TRUE)
|
||||
init_verbs()
|
||||
if(body && !body.key)
|
||||
body.key = "@[key]" //Haaaaaaaack. But the people have spoken. If it breaks; blame adminbus
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Admin Ghost") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return TRUE
|
||||
|
||||
/client/proc/invisimin()
|
||||
set name = "Invisimin"
|
||||
@@ -387,10 +408,10 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
if(holder && mob)
|
||||
if(mob.invisibility == INVISIBILITY_OBSERVER)
|
||||
mob.invisibility = initial(mob.invisibility)
|
||||
to_chat(mob, "<span class='boldannounce'>Invisimin off. Invisibility reset.</span>")
|
||||
to_chat(mob, "<span class='boldannounce'>Invisimin off. Invisibility reset.</span>", confidential = TRUE)
|
||||
else
|
||||
mob.invisibility = INVISIBILITY_OBSERVER
|
||||
to_chat(mob, "<span class='adminnotice'><b>Invisimin on. You are now as invisible as a ghost.</b></span>")
|
||||
to_chat(mob, "<span class='adminnotice'><b>Invisimin on. You are now as invisible as a ghost.</b></span>", confidential = TRUE)
|
||||
|
||||
/client/proc/check_antagonists()
|
||||
set name = "Check Antagonists"
|
||||
@@ -403,8 +424,10 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Check Antagonists") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/unban_panel()
|
||||
set name = "Unban Panel"
|
||||
set name = "Unbanning Panel"
|
||||
set category = "Admin"
|
||||
if(!check_rights(R_BAN))
|
||||
return
|
||||
if(holder)
|
||||
if(CONFIG_GET(flag/ban_legacy_system))
|
||||
holder.unbanpanel()
|
||||
@@ -412,6 +435,14 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
holder.DB_ban_panel()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Unban Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
// /client/proc/ban_panel()
|
||||
// set name = "Banning Panel"
|
||||
// set category = "Admin"
|
||||
// if(!check_rights(R_BAN))
|
||||
// return
|
||||
// holder.ban_panel()
|
||||
// SSblackbox.record_feedback("tally", "admin_verb", 1, "Banning Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/game_panel()
|
||||
set name = "Game Panel"
|
||||
set category = "Admin.Game"
|
||||
@@ -419,13 +450,13 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
holder.Game()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Game Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/secrets()
|
||||
set name = "Secrets"
|
||||
set category = "Admin.Game"
|
||||
if (holder)
|
||||
holder.Secrets()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Secrets Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
// /client/proc/poll_panel()
|
||||
// set name = "Server Poll Management"
|
||||
// set category = "Admin"
|
||||
// if(!check_rights(R_POLL))
|
||||
// return
|
||||
// holder.poll_list_panel()
|
||||
// SSblackbox.record_feedback("tally", "admin_verb", 1, "Server Poll Management") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/findStealthKey(txt)
|
||||
if(txt)
|
||||
@@ -457,7 +488,10 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
if(isobserver(mob))
|
||||
mob.invisibility = initial(mob.invisibility)
|
||||
mob.alpha = initial(mob.alpha)
|
||||
mob.name = initial(mob.name)
|
||||
if(mob.mind)
|
||||
mob.name = mob.mind.name
|
||||
else
|
||||
mob.name = mob.real_name
|
||||
mob.mouse_opacity = initial(mob.mouse_opacity)
|
||||
else
|
||||
var/new_key = ckeyEx(stripped_input(usr, "Enter your desired display name.", "Fake Key", key, 26))
|
||||
@@ -485,7 +519,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
|
||||
switch(choice)
|
||||
if(null)
|
||||
return 0
|
||||
return
|
||||
if("Small Bomb (1, 2, 3, 3)")
|
||||
explosion(epicenter, 1, 2, 3, 3, TRUE, TRUE)
|
||||
if("Medium Bomb (2, 3, 4, 4)")
|
||||
@@ -538,7 +572,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
if (isnull(ex_power))
|
||||
return
|
||||
var/range = round((2 * ex_power)**GLOB.DYN_EX_SCALE)
|
||||
to_chat(usr, "Estimated Explosive Range: (Devastation: [round(range*0.25)], Heavy: [round(range*0.5)], Light: [round(range)])")
|
||||
to_chat(usr, "Estimated Explosive Range: (Devastation: [round(range*0.25)], Heavy: [round(range*0.5)], Light: [round(range)])", confidential = TRUE)
|
||||
|
||||
/client/proc/get_dynex_power()
|
||||
set category = "Debug"
|
||||
@@ -549,7 +583,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
if (isnull(ex_range))
|
||||
return
|
||||
var/power = (0.5 * ex_range)**(1/GLOB.DYN_EX_SCALE)
|
||||
to_chat(usr, "Estimated Explosive Power: [power]")
|
||||
to_chat(usr, "Estimated Explosive Power: [power]", confidential = TRUE)
|
||||
|
||||
/client/proc/set_dynex_scale()
|
||||
set category = "Debug"
|
||||
@@ -563,6 +597,55 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
log_admin("[key_name(usr)] has modified Dynamic Explosion Scale: [ex_scale]")
|
||||
message_admins("[key_name_admin(usr)] has modified Dynamic Explosion Scale: [ex_scale]")
|
||||
|
||||
// /client/proc/atmos_control()
|
||||
// set name = "Atmos Control Panel"
|
||||
// set category = "Debug"
|
||||
// if(!check_rights(R_DEBUG))
|
||||
// return
|
||||
// SSair.ui_interact(mob)
|
||||
|
||||
// /client/proc/reload_cards()
|
||||
// set name = "Reload Cards"
|
||||
// set category = "Debug"
|
||||
// if(!check_rights(R_DEBUG))
|
||||
// return
|
||||
// if(!SStrading_card_game.loaded)
|
||||
// message_admins("The card subsystem is not currently loaded")
|
||||
// return
|
||||
// reloadAllCardFiles(SStrading_card_game.card_files, SStrading_card_game.card_directory)
|
||||
|
||||
// /client/proc/validate_cards()
|
||||
// set name = "Validate Cards"
|
||||
// set category = "Debug"
|
||||
// if(!check_rights(R_DEBUG))
|
||||
// return
|
||||
// if(!SStrading_card_game.loaded)
|
||||
// message_admins("The card subsystem is not currently loaded")
|
||||
// return
|
||||
// var/message = checkCardpacks(SStrading_card_game.card_packs)
|
||||
// message += checkCardDatums()
|
||||
// if(message)
|
||||
// message_admins(message)
|
||||
|
||||
// /client/proc/test_cardpack_distribution()
|
||||
// set name = "Test Cardpack Distribution"
|
||||
// set category = "Debug"
|
||||
// if(!check_rights(R_DEBUG))
|
||||
// return
|
||||
// if(!SStrading_card_game.loaded)
|
||||
// message_admins("The card subsystem is not currently loaded")
|
||||
// return
|
||||
// var/pack = input("Which pack should we test?", "You fucked it didn't you") as null|anything in sortList(SStrading_card_game.card_packs)
|
||||
// var/batchCount = input("How many times should we open it?", "Don't worry, I understand") as null|num
|
||||
// var/batchSize = input("How many cards per batch?", "I hope you remember to check the validation") as null|num
|
||||
// var/guar = input("Should we use the pack's guaranteed rarity? If so, how many?", "We've all been there. Man you should have seen the old system") as null|num
|
||||
// checkCardDistribution(pack, batchSize, batchCount, guar)
|
||||
|
||||
// /client/proc/print_cards()
|
||||
// set name = "Print Cards"
|
||||
// set category = "Debug"
|
||||
// printAllCards()
|
||||
|
||||
/client/proc/give_spell(mob/T in GLOB.mob_list)
|
||||
set category = "Admin.Fun"
|
||||
set name = "Give Spell"
|
||||
@@ -572,13 +655,13 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
var/type_length = length_char("/obj/effect/proc_holder/spell") + 2
|
||||
for(var/A in GLOB.spells)
|
||||
spell_list[copytext_char("[A]", type_length)] = A
|
||||
var/obj/effect/proc_holder/spell/S = input("Choose the spell to give to that guy", "ABRAKADABRA") as null|anything in spell_list
|
||||
var/obj/effect/proc_holder/spell/S = input("Choose the spell to give to that guy", "ABRAKADABRA") as null|anything in sortList(spell_list)
|
||||
if(!S)
|
||||
return
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Give Spell") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
log_admin("[key_name(usr)] gave [key_name(T)] the spell [S].")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] gave [key_name(T)] the spell [S].</span>")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] gave [key_name_admin(T)] the spell [S].</span>")
|
||||
|
||||
S = spell_list[S]
|
||||
if(T.mind)
|
||||
@@ -592,12 +675,12 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
set name = "Remove Spell"
|
||||
set desc = "Remove a spell from the selected mob."
|
||||
|
||||
if(T && T.mind)
|
||||
var/obj/effect/proc_holder/spell/S = input("Choose the spell to remove", "NO ABRAKADABRA") as null|anything in T.mind.spell_list
|
||||
if(T?.mind)
|
||||
var/obj/effect/proc_holder/spell/S = input("Choose the spell to remove", "NO ABRAKADABRA") as null|anything in sortList(T.mind.spell_list)
|
||||
if(S)
|
||||
T.mind.RemoveSpell(S)
|
||||
log_admin("[key_name(usr)] removed the spell [S] from [key_name(T)].")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] removed the spell [S] from [key_name(T)].</span>")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] removed the spell [S] from [key_name_admin(T)].</span>")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Remove Spell") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/give_disease(mob/living/T in GLOB.mob_living_list)
|
||||
@@ -605,15 +688,15 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
set name = "Give Disease"
|
||||
set desc = "Gives a Disease to a mob."
|
||||
if(!istype(T))
|
||||
to_chat(src, "<span class='notice'>You can only give a disease to a mob of type /mob/living.</span>")
|
||||
to_chat(src, "<span class='notice'>You can only give a disease to a mob of type /mob/living.</span>", confidential = TRUE)
|
||||
return
|
||||
var/datum/disease/D = input("Choose the disease to give to that guy", "ACHOO") as null|anything in SSdisease.diseases
|
||||
var/datum/disease/D = input("Choose the disease to give to that guy", "ACHOO") as null|anything in sortList(SSdisease.diseases, /proc/cmp_typepaths_asc)
|
||||
if(!D)
|
||||
return
|
||||
T.ForceContractDisease(new D, FALSE, TRUE)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Give Disease") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
log_admin("[key_name(usr)] gave [key_name(T)] the disease [D].")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] gave [key_name(T)] the disease [D].</span>")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] gave [key_name_admin(T)] the disease [D].</span>")
|
||||
|
||||
/client/proc/object_say(obj/O in world)
|
||||
set category = "Admin.Events"
|
||||
@@ -655,8 +738,8 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
holder.deactivate()
|
||||
|
||||
to_chat(src, "<span class='interface'>You are now a normal player.</span>")
|
||||
log_admin("[src] deadmined themself.")
|
||||
message_admins("[src] deadmined themself.")
|
||||
log_admin("[src] deadminned themselves.")
|
||||
message_admins("[src] deadminned themselves.")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Deadmin")
|
||||
|
||||
/client/proc/readmin()
|
||||
@@ -679,7 +762,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
if (!holder)
|
||||
return //This can happen if an admin attempts to vv themself into somebody elses's deadmin datum by getting ref via brute force
|
||||
|
||||
to_chat(src, "<span class='interface'>You are now an admin.</span>")
|
||||
to_chat(src, "<span class='interface'>You are now an admin.</span>", confidential = TRUE)
|
||||
message_admins("[src] re-adminned themselves.")
|
||||
log_admin("[src] re-adminned themselves.")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Readmin")
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/client/proc/callproc()
|
||||
set category = "Debug"
|
||||
set name = "Advanced ProcCall"
|
||||
@@ -21,7 +20,7 @@
|
||||
return
|
||||
target = value["value"]
|
||||
if(!istype(target))
|
||||
to_chat(usr, "<span class='danger'>Invalid target.</span>")
|
||||
to_chat(usr, "<span class='danger'>Invalid target.</span>", confidential = TRUE)
|
||||
return
|
||||
if("No")
|
||||
target = null
|
||||
@@ -41,12 +40,12 @@
|
||||
|
||||
if(targetselected)
|
||||
if(!hascall(target, procname))
|
||||
to_chat(usr, "<span class='warning'>Error: callproc(): type [target.type] has no [proctype] named [procpath].</span>")
|
||||
to_chat(usr, "<span class='warning'>Error: callproc(): type [target.type] has no [proctype] named [procpath].</span>", confidential = TRUE)
|
||||
return
|
||||
else
|
||||
procpath = "/[proctype]/[procname]"
|
||||
if(!text2path(procpath))
|
||||
to_chat(usr, "<span class='warning'>Error: callproc(): [procpath] does not exist.</span>")
|
||||
to_chat(usr, "<span class='warning'>Error: callproc(): [procpath] does not exist.</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
var/list/lst = get_callproc_args()
|
||||
@@ -55,24 +54,24 @@
|
||||
|
||||
if(targetselected)
|
||||
if(!target)
|
||||
to_chat(usr, "<font color='red'>Error: callproc(): owner of proc no longer exists.</font>")
|
||||
to_chat(usr, "<font color='red'>Error: callproc(): owner of proc no longer exists.</font>", confidential = TRUE)
|
||||
return
|
||||
var/msg = "[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
|
||||
log_admin(msg)
|
||||
message_admins(msg) //Proccall announce removed.
|
||||
message_admins(msg) //Proccall announce removed.
|
||||
admin_ticket_log(target, msg)
|
||||
returnval = WrapAdminProcCall(target, procname, lst) // Pass the lst as an argument list to the proc
|
||||
else
|
||||
//this currently has no hascall protection. wasn't able to get it working.
|
||||
log_admin("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
|
||||
message_admins("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") //Proccall announce removed.
|
||||
message_admins("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") //Proccall announce removed.
|
||||
returnval = WrapAdminProcCall(GLOBAL_PROC, procname, lst) // Pass the lst as an argument list to the proc
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Advanced ProcCall") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
if(get_retval)
|
||||
get_retval += returnval
|
||||
. = get_callproc_returnval(returnval, procname)
|
||||
if(.)
|
||||
to_chat(usr, .)
|
||||
to_chat(usr, ., confidential = TRUE)
|
||||
|
||||
GLOBAL_VAR(AdminProcCaller)
|
||||
GLOBAL_PROTECT(AdminProcCaller)
|
||||
@@ -84,34 +83,30 @@ GLOBAL_VAR(LastAdminCalledTarget)
|
||||
GLOBAL_PROTECT(LastAdminCalledTarget)
|
||||
GLOBAL_VAR(LastAdminCalledProc)
|
||||
GLOBAL_PROTECT(LastAdminCalledProc)
|
||||
GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention)
|
||||
GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
|
||||
/// Wrapper for proccalls where the datum is flagged as vareditted
|
||||
/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
|
||||
if(target != GLOBAL_PROC && procname == "Del")
|
||||
to_chat(usr, "<span class='warning'>Calling Del() is not allowed</span>")
|
||||
if(target && procname == "Del")
|
||||
to_chat(usr, "Calling Del() is not allowed", confidential = TRUE)
|
||||
return
|
||||
|
||||
if(target != GLOBAL_PROC && !target.CanProcCall(procname))
|
||||
to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!")
|
||||
to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!", confidential = TRUE)
|
||||
return
|
||||
var/current_caller = GLOB.AdminProcCaller
|
||||
var/ckey = usr ? usr.client.ckey : GLOB.AdminProcCaller
|
||||
if(!ckey)
|
||||
CRASH("WrapAdminProcCall with no ckey: [target] [procname] [english_list(arguments)]")
|
||||
|
||||
if(current_caller && current_caller != ckey)
|
||||
if(!GLOB.AdminProcCallSpamPrevention[ckey])
|
||||
to_chat(usr, "<span class='adminnotice'>Another set of admin called procs are still running, your proc will be run after theirs finish.</span>")
|
||||
GLOB.AdminProcCallSpamPrevention[ckey] = TRUE
|
||||
UNTIL(!GLOB.AdminProcCaller)
|
||||
to_chat(usr, "<span class='adminnotice'>Running your proc</span>")
|
||||
GLOB.AdminProcCallSpamPrevention -= ckey
|
||||
else
|
||||
UNTIL(!GLOB.AdminProcCaller)
|
||||
// hey kev i removed the sleep here because it blocks this proc
|
||||
to_chat(usr, "<span class='adminnotice'>Another set of admin called procs are still running. Try again later.</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
GLOB.LastAdminCalledProc = procname
|
||||
if(target != GLOBAL_PROC)
|
||||
GLOB.LastAdminCalledTargetRef = "[REF(target)]"
|
||||
GLOB.AdminProcCaller = ckey //if this runtimes, too bad for you
|
||||
GLOB.LastAdminCalledTargetRef = REF(target)
|
||||
GLOB.AdminProcCaller = ckey //if this runtimes, too bad for you
|
||||
++GLOB.AdminProcCallCount
|
||||
. = world.WrapAdminProcCall(target, procname, arguments)
|
||||
if(--GLOB.AdminProcCallCount == 0)
|
||||
@@ -120,11 +115,11 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
//adv proc call this, ya nerds
|
||||
/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
|
||||
if(target == GLOBAL_PROC)
|
||||
return call(text2path("/proc/[procname]"))(arglist(arguments))
|
||||
return call("/proc/[procname]")(arglist(arguments))
|
||||
else if(target != world)
|
||||
return call(target, procname)(arglist(arguments))
|
||||
else
|
||||
log_admin_private("[key_name(usr)] attempted to call world/proc/[procname] with arguments: [english_list(arguments)]")
|
||||
log_admin("[key_name(usr)] attempted to call world/proc/[procname] with arguments: [english_list(arguments)]")
|
||||
|
||||
/proc/IsAdminAdvancedProcCall()
|
||||
#ifdef TESTING
|
||||
@@ -145,17 +140,17 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
if(!procname)
|
||||
return
|
||||
if(!hascall(A,procname))
|
||||
to_chat(usr, "<span class='warning'>Error: callproc_datum(): type [A.type] has no proc named [procname].</span>")
|
||||
to_chat(usr, "<font color='red'>Error: callproc_datum(): type [A.type] has no proc named [procname].</font>", confidential = TRUE)
|
||||
return
|
||||
var/list/lst = get_callproc_args()
|
||||
if(!lst)
|
||||
return
|
||||
|
||||
if(!A || !IsValidSrc(A))
|
||||
to_chat(usr, "<span class='warning'>Error: callproc_datum(): owner of proc no longer exists.</span>")
|
||||
to_chat(usr, "<span class='warning'>Error: callproc_datum(): owner of proc no longer exists.</span>", confidential = TRUE)
|
||||
return
|
||||
log_admin("[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
|
||||
var/msg = "[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
|
||||
log_admin(msg)
|
||||
message_admins(msg)
|
||||
admin_ticket_log(A, msg)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Atom ProcCall") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
@@ -163,7 +158,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
var/returnval = WrapAdminProcCall(A, procname, lst) // Pass the lst as an argument list to the proc
|
||||
. = get_callproc_returnval(returnval,procname)
|
||||
if(.)
|
||||
to_chat(usr, .)
|
||||
to_chat(usr, ., confidential = TRUE)
|
||||
|
||||
/client/proc/get_callproc_args()
|
||||
var/argnum = input("Number of arguments","Number:",0) as num|null
|
||||
@@ -188,7 +183,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
. = ""
|
||||
if(islist(returnval))
|
||||
var/list/returnedlist = returnval
|
||||
. = "<span class='notice'>"
|
||||
. = "<font color='blue'>"
|
||||
if(returnedlist.len)
|
||||
var/assoc_check = returnedlist[1]
|
||||
if(istext(assoc_check) && (returnedlist[assoc_check] != null))
|
||||
@@ -202,7 +197,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
. += "\n[elem]"
|
||||
else
|
||||
. = "[procname] returned an empty list"
|
||||
. += "</span>"
|
||||
. += "</font>"
|
||||
|
||||
else
|
||||
. = "<span class='notice'>[procname] returned: [!isnull(returnval) ? returnval : "null"]</span>"
|
||||
. = "<font color='blue'>[procname] returned: [!isnull(returnval) ? html_encode(returnval) : "null"]</font>"
|
||||
|
||||
@@ -28,6 +28,8 @@ GLOBAL_PROTECT(href_token)
|
||||
|
||||
var/deadmined
|
||||
|
||||
var/datum/filter_editor/filteriffic
|
||||
|
||||
/datum/admins/CanProcCall(procname)
|
||||
. = ..()
|
||||
if(!check_rights(R_SENSITIVE))
|
||||
|
||||
@@ -2513,9 +2513,6 @@
|
||||
break
|
||||
return
|
||||
|
||||
else if(href_list["secrets"])
|
||||
Secrets_topic(href_list["secrets"],href_list)
|
||||
|
||||
else if(href_list["ac_view_wanted"]) //Admin newscaster Topic() stuff be here
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
@@ -643,7 +643,6 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
CRASH("Invalid cross comms config: [server_name]")
|
||||
world.Export("[server_url]?[list2params(message)]")
|
||||
|
||||
|
||||
/proc/ircadminwho()
|
||||
var/list/message = list("Admins: ")
|
||||
var/list/admin_keys = list()
|
||||
|
||||
@@ -790,11 +790,12 @@
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
|
||||
SSmedals.hub_enabled = !SSmedals.hub_enabled
|
||||
SSachievements.achievements_enabled = !SSachievements.achievements_enabled
|
||||
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(src)] [SSmedals.hub_enabled ? "disabled" : "enabled"] the medal hub lockout.</span>")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(src)] [SSachievements.achievements_enabled ? "disabled" : "enabled"] the medal hub lockout.</span>")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Toggle Medal Disable") // If...
|
||||
log_admin("[key_name(src)] [SSmedals.hub_enabled ? "disabled" : "enabled"] the medal hub lockout.")
|
||||
log_admin("[key_name(src)] [SSachievements.achievements_enabled ? "disabled" : "enabled"] the medal hub lockout.")
|
||||
|
||||
|
||||
/client/proc/view_runtimes()
|
||||
set category = "Debug"
|
||||
|
||||
@@ -63,3 +63,31 @@
|
||||
load_admins()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Reload All Admins") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
message_admins("[key_name_admin(usr)] manually reloaded admins")
|
||||
|
||||
/client/proc/toggle_cdn()
|
||||
set name = "Toggle CDN"
|
||||
set category = "Server"
|
||||
var/static/admin_disabled_cdn_transport = null
|
||||
if (alert(usr, "Are you sure you want to toggle the CDN asset transport?", "Confirm", "Yes", "No") != "Yes")
|
||||
return
|
||||
var/current_transport = CONFIG_GET(string/asset_transport)
|
||||
if (!current_transport || current_transport == "simple")
|
||||
if (admin_disabled_cdn_transport)
|
||||
CONFIG_SET(string/asset_transport, admin_disabled_cdn_transport)
|
||||
admin_disabled_cdn_transport = null
|
||||
SSassets.OnConfigLoad()
|
||||
message_admins("[key_name_admin(usr)] re-enabled the CDN asset transport")
|
||||
log_admin("[key_name(usr)] re-enabled the CDN asset transport")
|
||||
else
|
||||
to_chat(usr, "<span class='adminnotice'>The CDN is not enabled!</span>")
|
||||
if (alert(usr, "The CDN asset transport is not enabled! If you having issues with assets you can also try disabling filename mutations.", "The CDN asset transport is not enabled!", "Try disabling filename mutations", "Nevermind") == "Try disabling filename mutations")
|
||||
SSassets.transport.dont_mutate_filenames = !SSassets.transport.dont_mutate_filenames
|
||||
message_admins("[key_name_admin(usr)] [(SSassets.transport.dont_mutate_filenames ? "disabled" : "re-enabled")] asset filename transforms")
|
||||
log_admin("[key_name(usr)] [(SSassets.transport.dont_mutate_filenames ? "disabled" : "re-enabled")] asset filename transforms")
|
||||
else
|
||||
admin_disabled_cdn_transport = current_transport
|
||||
CONFIG_SET(string/asset_transport, "simple")
|
||||
SSassets.OnConfigLoad()
|
||||
SSassets.transport.dont_mutate_filenames = TRUE
|
||||
message_admins("[key_name_admin(usr)] disabled the CDN asset transport")
|
||||
log_admin("[key_name(usr)] disabled the CDN asset transport")
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
set name = "Pray"
|
||||
|
||||
if(GLOB.say_disabled) //This is here to try to identify lag problems
|
||||
to_chat(usr, "<span class='danger'>Speech is currently admin-disabled.</span>")
|
||||
to_chat(usr, "<span class='danger'>Speech is currently admin-disabled.</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
msg = copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN)
|
||||
@@ -12,7 +12,7 @@
|
||||
log_prayer("[src.key]/([src.name]): [msg]")
|
||||
if(usr.client)
|
||||
if(usr.client.prefs.muted & MUTE_PRAY)
|
||||
to_chat(usr, "<span class='danger'>You cannot pray (muted).</span>")
|
||||
to_chat(usr, "<span class='danger'>You cannot pray (muted).</span>", confidential = TRUE)
|
||||
return
|
||||
if(src.client.handle_spam_prevention(msg,MUTE_PRAY))
|
||||
return
|
||||
@@ -44,34 +44,35 @@
|
||||
|
||||
for(var/client/C in GLOB.admins)
|
||||
if(C.prefs.chat_toggles & CHAT_PRAYER)
|
||||
to_chat(C, msg)
|
||||
to_chat(C, msg, confidential = TRUE)
|
||||
if(C.prefs.toggles & SOUND_PRAYERS)
|
||||
if(usr.job == "Chaplain")
|
||||
SEND_SOUND(C, sound('sound/effects/pray.ogg'))
|
||||
else
|
||||
SEND_SOUND(C, sound('sound/effects/ding.ogg'))
|
||||
to_chat(usr, "<span class='info'>You pray to the gods: \"[msg_tmp]\"</span>")
|
||||
to_chat(usr, "<span class='info'>You pray to the gods: \"[msg_tmp]\"</span>", confidential = TRUE)
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Prayer") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
//log_admin("HELP: [key_name(src)]: [msg]")
|
||||
|
||||
/proc/CentCom_announce(text , mob/Sender)
|
||||
/// Used by communications consoles to message CentCom
|
||||
/proc/message_centcom(text, mob/sender)
|
||||
var/msg = copytext_char(sanitize(text), 1, MAX_MESSAGE_LEN)
|
||||
msg = "<span class='adminnotice'><b><font color=orange>CENTCOM:</font>[ADMIN_FULLMONTY(Sender)] [ADMIN_CENTCOM_REPLY(Sender)]:</b> [msg]</span>"
|
||||
to_chat(GLOB.admins, msg)
|
||||
for(var/obj/machinery/computer/communications/C in GLOB.machines)
|
||||
C.overrideCooldown()
|
||||
msg = "<span class='adminnotice'><b><font color=orange>CENTCOM:</font>[ADMIN_FULLMONTY(sender)] [ADMIN_CENTCOM_REPLY(sender)]:</b> [msg]</span>"
|
||||
to_chat(GLOB.admins, msg, confidential = TRUE)
|
||||
for(var/obj/machinery/computer/communications/console in GLOB.machines)
|
||||
console.override_cooldown()
|
||||
|
||||
/proc/Syndicate_announce(text , mob/Sender)
|
||||
/// Used by communications consoles to message the Syndicate
|
||||
/proc/message_syndicate(text, mob/sender)
|
||||
var/msg = copytext_char(sanitize(text), 1, MAX_MESSAGE_LEN)
|
||||
msg = "<span class='adminnotice'><b><font color=crimson>SYNDICATE:</font>[ADMIN_FULLMONTY(Sender)] [ADMIN_SYNDICATE_REPLY(Sender)]:</b> [msg]</span>"
|
||||
to_chat(GLOB.admins, msg)
|
||||
for(var/obj/machinery/computer/communications/C in GLOB.machines)
|
||||
C.overrideCooldown()
|
||||
msg = "<span class='adminnotice'><b><font color=crimson>SYNDICATE:</font>[ADMIN_FULLMONTY(sender)] [ADMIN_SYNDICATE_REPLY(sender)]:</b> [msg]</span>"
|
||||
to_chat(GLOB.admins, msg, confidential = TRUE)
|
||||
for(var/obj/machinery/computer/communications/console in GLOB.machines)
|
||||
console.override_cooldown()
|
||||
|
||||
/proc/Nuke_request(text , mob/Sender)
|
||||
/// Used by communications consoles to request the nuclear launch codes
|
||||
/proc/nuke_request(text, mob/sender)
|
||||
var/msg = copytext_char(sanitize(text), 1, MAX_MESSAGE_LEN)
|
||||
msg = "<span class='adminnotice'><b><font color=orange>NUKE CODE REQUEST:</font>[ADMIN_FULLMONTY(Sender)] [ADMIN_CENTCOM_REPLY(Sender)] [ADMIN_SET_SD_CODE]:</b> [msg]</span>"
|
||||
to_chat(GLOB.admins, msg)
|
||||
for(var/obj/machinery/computer/communications/C in GLOB.machines)
|
||||
C.overrideCooldown()
|
||||
msg = "<span class='adminnotice'><b><font color=orange>NUKE CODE REQUEST:</font>[ADMIN_FULLMONTY(sender)] [ADMIN_CENTCOM_REPLY(sender)] [ADMIN_SET_SD_CODE]:</b> [msg]</span>"
|
||||
to_chat(GLOB.admins, msg, confidential = TRUE)
|
||||
for(var/obj/machinery/computer/communications/console in GLOB.machines)
|
||||
console.override_cooldown()
|
||||
|
||||
@@ -1547,22 +1547,17 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
msg += "</UL></BODY></HTML>"
|
||||
src << browse(msg.Join(), "window=Player_playtime_check")
|
||||
|
||||
/datum/admins/proc/cmd_show_exp_panel(client/C)
|
||||
/datum/admins/proc/cmd_show_exp_panel(client/client_to_check)
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(!C)
|
||||
to_chat(usr, "<span class='danger'>ERROR: Client not found.</span>")
|
||||
if(!client_to_check)
|
||||
to_chat(usr, "<span class='danger'>ERROR: Client not found.</span>", confidential = TRUE)
|
||||
return
|
||||
if(!CONFIG_GET(flag/use_exp_tracking))
|
||||
to_chat(usr, "<span class='warning'>Tracking is disabled in the server configuration file.</span>")
|
||||
to_chat(usr, "<span class='warning'>Tracking is disabled in the server configuration file.</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
var/list/body = list()
|
||||
body += "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>Playtime for [C.key]</title></head><BODY><BR>Playtime:"
|
||||
body += C.get_exp_report()
|
||||
body += "<A href='?_src_=holder;[HrefToken()];toggleexempt=[REF(C)]'>Toggle Exempt status</a>"
|
||||
body += "</BODY></HTML>"
|
||||
usr << browse(body.Join(), "window=playerplaytime[C.ckey];size=550x615")
|
||||
new /datum/job_report_menu(client_to_check, usr)
|
||||
|
||||
/datum/admins/proc/toggle_exempt_status(client/C)
|
||||
if(!check_rights(R_ADMIN))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,99 @@
|
||||
/datum/filter_editor
|
||||
var/atom/target
|
||||
|
||||
/datum/filter_editor/New(atom/target)
|
||||
src.target = target
|
||||
|
||||
/datum/filter_editor/ui_state(mob/user)
|
||||
return GLOB.admin_state
|
||||
|
||||
/datum/filter_editor/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Filteriffic")
|
||||
ui.open()
|
||||
|
||||
/datum/filter_editor/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["filter_info"] = GLOB.master_filter_info
|
||||
return data
|
||||
|
||||
/datum/filter_editor/ui_data()
|
||||
var/list/data = list()
|
||||
data["target_name"] = target.name
|
||||
data["target_filter_data"] = target.filter_data
|
||||
return data
|
||||
|
||||
/datum/filter_editor/ui_act(action, list/params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("add_filter")
|
||||
var/target_name = params["name"]
|
||||
while(target.filter_data && target.filter_data[target_name])
|
||||
target_name = "[target_name]-dupe"
|
||||
target.add_filter(target_name, params["priority"], list("type" = params["type"]))
|
||||
. = TRUE
|
||||
if("remove_filter")
|
||||
target.remove_filter(params["name"])
|
||||
. = TRUE
|
||||
if("rename_filter")
|
||||
var/list/filter_data = target.filter_data[params["name"]]
|
||||
target.remove_filter(params["name"])
|
||||
target.add_filter(params["new_name"], filter_data["priority"], filter_data)
|
||||
. = TRUE
|
||||
if("edit_filter")
|
||||
target.remove_filter(params["name"])
|
||||
target.add_filter(params["name"], params["priority"], params["new_filter"])
|
||||
. = TRUE
|
||||
if("change_priority")
|
||||
var/new_priority = params["new_priority"]
|
||||
target.change_filter_priority(params["name"], new_priority)
|
||||
. = TRUE
|
||||
if("transition_filter_value")
|
||||
target.transition_filter(params["name"], 4, params["new_data"])
|
||||
. = TRUE
|
||||
if("modify_filter_value")
|
||||
var/list/old_filter_data = target.filter_data[params["name"]]
|
||||
var/list/new_filter_data = old_filter_data.Copy()
|
||||
for(var/entry in params["new_data"])
|
||||
new_filter_data[entry] = params["new_data"][entry]
|
||||
for(var/entry in new_filter_data)
|
||||
if(entry == GLOB.master_filter_info[old_filter_data["type"]]["defaults"][entry])
|
||||
new_filter_data.Remove(entry)
|
||||
target.remove_filter(params["name"])
|
||||
target.add_filter(params["name"], old_filter_data["priority"], new_filter_data)
|
||||
. = TRUE
|
||||
if("modify_color_value")
|
||||
var/new_color = input(usr, "Pick new filter color", "Filteriffic Colors!") as color|null
|
||||
if(new_color)
|
||||
target.transition_filter(params["name"], 4, list("color" = new_color))
|
||||
. = TRUE
|
||||
if("modify_icon_value")
|
||||
var/icon/new_icon = input("Pick icon:", "Icon") as null|icon
|
||||
if(new_icon)
|
||||
target.filter_data[params["name"]]["icon"] = new_icon
|
||||
target.update_filters()
|
||||
. = TRUE
|
||||
if("mass_apply")
|
||||
if(!check_rights_for(usr.client, R_FUN))
|
||||
to_chat(usr, "<span class='userdanger>Stay in your lane, jannie.</span>'")
|
||||
return
|
||||
var/target_path = text2path(params["path"])
|
||||
if(!target_path)
|
||||
return
|
||||
var/filters_to_copy = target.filters
|
||||
var/filter_data_to_copy = target.filter_data
|
||||
var/count = 0
|
||||
for(var/thing in world.contents)
|
||||
if(istype(thing, target_path))
|
||||
var/atom/thing_at = thing
|
||||
thing_at.filters = filters_to_copy
|
||||
thing_at.filter_data = filter_data_to_copy
|
||||
count += 1
|
||||
message_admins("LOCAL CLOWN [usr.ckey] JUST MASS FILTER EDITED [count] WITH PATH OF [params["path"]]!")
|
||||
log_admin("LOCAL CLOWN [usr.ckey] JUST MASS FILTER EDITED [count] WITH PATH OF [params["path"]]!")
|
||||
|
||||
|
||||
@@ -5,10 +5,13 @@
|
||||
|
||||
var/method = 0 //0 means strict type detection while 1 means this type and all subtypes (IE: /obj/item with this set to 1 will set it to ALL items)
|
||||
|
||||
if(tgui_alert(src, "Are you sure you'd like to mass-modify every instance of the [var_name] variable? This can break everything if you do not know what you are doing.", "Slow down, chief!", list("Yes", "No")) != "Yes")
|
||||
return
|
||||
|
||||
if(!check_rights(R_VAREDIT))
|
||||
return
|
||||
|
||||
if(A && A.type)
|
||||
if(A?.type)
|
||||
method = vv_subtype_prompt(A.type)
|
||||
|
||||
src.massmodify_variables(A, var_name, method)
|
||||
@@ -114,7 +117,7 @@
|
||||
var/list/varsvars = vv_parse_text(O, new_value)
|
||||
var/pre_processing = new_value
|
||||
var/unique
|
||||
if (varsvars && varsvars.len)
|
||||
if (varsvars?.len)
|
||||
unique = alert(usr, "Process vars unique to each instance, or same for all?", "Variable Association", "Unique", "Same")
|
||||
if(unique == "Unique")
|
||||
unique = TRUE
|
||||
|
||||
@@ -23,7 +23,7 @@ GLOBAL_PROTECT(VVpixelmovement)
|
||||
var/list/subtypes = subtypesof(type)
|
||||
if (!subtypes || !subtypes.len)
|
||||
return FALSE
|
||||
if (subtypes && subtypes.len)
|
||||
if (subtypes?.len)
|
||||
switch(alert("Strict object type detection?", "Type detection", "Strictly this type","This type and subtypes", "Cancel"))
|
||||
if("Strictly this type")
|
||||
return FALSE
|
||||
|
||||
@@ -29,6 +29,12 @@
|
||||
return
|
||||
|
||||
var/new_name = stripped_input(usr,"What would you like to name this mob?","Input a name",M.real_name,MAX_NAME_LEN)
|
||||
|
||||
// If the new name is something that would be restricted by IC chat filters,
|
||||
// give the admin a warning but allow them to do it anyway if they want.
|
||||
// if(CHAT_FILTER_CHECK(new_name) && alert(usr, "Your selected name contains words restricted by IC chat filters. Confirm this new name?", "IC Chat Filter Conflict", "Confirm", "Cancel") == "Cancel")
|
||||
// return
|
||||
|
||||
if( !new_name || !M )
|
||||
return
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
usr.client.debug_variables(src)
|
||||
return
|
||||
|
||||
#ifdef REFERENCE_TRACKING //people with debug can only access this putnam!
|
||||
#ifdef REFERENCE_TRACKING
|
||||
if(href_list[VV_HK_VIEW_REFERENCES])
|
||||
var/datum/D = locate(href_list[VV_HK_TARGET])
|
||||
if(!D)
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
if(!D)
|
||||
return
|
||||
|
||||
var/datum/asset/asset_cache_datum = get_asset_datum(/datum/asset/simple/vv)
|
||||
asset_cache_datum.send(usr)
|
||||
|
||||
var/islist = islist(D)
|
||||
if(!islist && !istype(D))
|
||||
return
|
||||
|
||||
@@ -7,98 +7,79 @@
|
||||
// Over Time, tick down toward a "Solar Flare" of UV buffeting the station. This period is harmful to vamps.
|
||||
/obj/effect/sunlight
|
||||
//var/amDay = FALSE
|
||||
var/cancel_me = FALSE
|
||||
var/amDay = FALSE
|
||||
var/time_til_cycle = 0
|
||||
var/nightime_duration = 900 //15 Minutes
|
||||
var/nighttime_duration = 900 //15 Minutes
|
||||
var/issued_XP = FALSE
|
||||
|
||||
/obj/effect/sunlight/Initialize()
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, .proc/countdown)
|
||||
INVOKE_ASYNC(src, .proc/hud_tick)
|
||||
|
||||
/obj/effect/sunlight/proc/countdown()
|
||||
set waitfor = FALSE
|
||||
/obj/effect/sunlight/proc/start_countdown()
|
||||
START_PROCESSING(SSweather, src) //it counts as weather right
|
||||
time_til_cycle = nighttime_duration
|
||||
|
||||
while(!cancel_me)
|
||||
|
||||
time_til_cycle = nightime_duration
|
||||
|
||||
// Part 1: Night (all is well)
|
||||
while(time_til_cycle > TIME_BLOODSUCKER_DAY_WARN)
|
||||
sleep(10)
|
||||
if(cancel_me)
|
||||
return
|
||||
//sleep(TIME_BLOODSUCKER_NIGHT - TIME_BLOODSUCKER_DAY_WARN)
|
||||
warn_daylight(1,"<span class = 'danger'>Solar Flares will bombard the station with dangerous UV in [TIME_BLOODSUCKER_DAY_WARN / 60] minutes. <b>Prepare to seek cover in a coffin or closet.</b></span>") // time2text <-- use Help On
|
||||
give_home_power() // Give VANISHING ACT power to all vamps with a lair!
|
||||
|
||||
// Part 2: Night Ending
|
||||
while(time_til_cycle > TIME_BLOODSUCKER_DAY_FINAL_WARN)
|
||||
sleep(10)
|
||||
if(cancel_me)
|
||||
return
|
||||
//sleep(TIME_BLOODSUCKER_DAY_WARN - TIME_BLOODSUCKER_DAY_FINAL_WARN)
|
||||
message_admins("BLOODSUCKER NOTICE: Daylight beginning in [TIME_BLOODSUCKER_DAY_FINAL_WARN] seconds.)")
|
||||
warn_daylight(2,"<span class = 'userdanger'>Solar Flares are about to bombard the station! You have [TIME_BLOODSUCKER_DAY_FINAL_WARN] seconds to find cover!</span>",\
|
||||
"<span class = 'danger'>In [TIME_BLOODSUCKER_DAY_FINAL_WARN / 10], your master will be at risk of a Solar Flare. Make sure they find cover!</span>")
|
||||
|
||||
// (FINAL LIL WARNING)
|
||||
while(time_til_cycle > 5)
|
||||
sleep(10)
|
||||
if(cancel_me)
|
||||
return
|
||||
//sleep(TIME_BLOODSUCKER_DAY_FINAL_WARN - 50)
|
||||
warn_daylight(3,"<span class = 'userdanger'>Seek cover, for Sol rises!</span>")
|
||||
|
||||
// Part 3: Night Ending
|
||||
while(time_til_cycle > 0)
|
||||
sleep(10)
|
||||
if(cancel_me)
|
||||
return
|
||||
//sleep(50)
|
||||
warn_daylight(4,"<span class = 'userdanger'>Solar flares bombard the station with deadly UV light!</span><br><span class = ''>Stay in cover for the next [TIME_BLOODSUCKER_DAY / 60] minutes or risk Final Death!</span>",\
|
||||
"<span class = 'danger'>Solar flares bombard the station with UV light!</span>")
|
||||
|
||||
// Part 4: Day
|
||||
amDay = TRUE
|
||||
message_admins("BLOODSUCKER NOTICE: Daylight Beginning (Lasts for [TIME_BLOODSUCKER_DAY / 60] minutes.)")
|
||||
time_til_cycle = TIME_BLOODSUCKER_DAY
|
||||
sleep(10) // One second grace period.
|
||||
//var/daylight_time = TIME_BLOODSUCKER_DAY
|
||||
var/issued_XP = FALSE
|
||||
while(time_til_cycle > 0)
|
||||
/obj/effect/sunlight/process()
|
||||
// Update all Bloodsucker sunlight huds
|
||||
for(var/datum/mind/M in SSticker.mode.bloodsuckers)
|
||||
if(!istype(M) || !istype(M.current))
|
||||
continue
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = M.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
if(istype(bloodsuckerdatum))
|
||||
bloodsuckerdatum.update_sunlight(max(0, time_til_cycle), amDay) // This pings all HUDs
|
||||
time_til_cycle--
|
||||
if(amDay)
|
||||
if(time_til_cycle > 0 && time_til_cycle % 4 == 0)
|
||||
punish_vamps()
|
||||
sleep(TIME_BLOODSUCKER_BURN_INTERVAL)
|
||||
if(cancel_me)
|
||||
return
|
||||
//daylight_time -= TIME_BLOODSUCKER_BURN_INTERVAL
|
||||
// Issue Level Up!
|
||||
if(!issued_XP && time_til_cycle <= 5)
|
||||
issued_XP = TRUE
|
||||
vamps_rank_up()
|
||||
// Cycle through all vamp antags and check if they're inside a closet.
|
||||
for(var/datum/mind/M in SSticker.mode.bloodsuckers)
|
||||
if(!istype(M) || !istype(M.current))
|
||||
continue
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = M.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
if(istype(bloodsuckerdatum))
|
||||
bloodsuckerdatum.RankUp() // Rank up! Must still be in a coffin to level!
|
||||
|
||||
warn_daylight(5,"<span class = 'announce'>The solar flare has ended, and the daylight danger has passed...for now.</span>",\
|
||||
"<span class = 'announce'>The solar flare has ended, and the daylight danger has passed...for now.</span>")
|
||||
amDay = FALSE
|
||||
day_end() // Remove VANISHING ACT power from all vamps who have it! Clear Warnings (sunlight, locker protection)
|
||||
nightime_duration += 100 //Each day makes the night a minute longer.
|
||||
message_admins("BLOODSUCKER NOTICE: Daylight Ended. Resetting to Night (Lasts for [nightime_duration / 60] minutes.)")
|
||||
|
||||
|
||||
|
||||
/obj/effect/sunlight/proc/hud_tick()
|
||||
set waitfor = FALSE
|
||||
while(!cancel_me)
|
||||
// Update all Bloodsucker sunlight huds
|
||||
issued_XP = FALSE
|
||||
for(var/datum/mind/M in SSticker.mode.bloodsuckers)
|
||||
if(!istype(M) || !istype(M.current))
|
||||
continue
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = M.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
if(istype(bloodsuckerdatum))
|
||||
bloodsuckerdatum.update_sunlight(max(0, time_til_cycle), amDay) // This pings all HUDs
|
||||
sleep(10)
|
||||
time_til_cycle --
|
||||
if(!istype(bloodsuckerdatum))
|
||||
continue
|
||||
// Reset Warnings
|
||||
bloodsuckerdatum.warn_sun_locker = FALSE
|
||||
bloodsuckerdatum.warn_sun_burn = FALSE
|
||||
// Remove Dawn Powers
|
||||
for(var/datum/action/bloodsucker/P in bloodsuckerdatum.powers)
|
||||
if(istype(P, /datum/action/bloodsucker/gohome))
|
||||
bloodsuckerdatum.powers -= P
|
||||
P.Remove(M.current)
|
||||
nighttime_duration += 100 //Each day makes the night a minute longer.
|
||||
time_til_cycle = nighttime_duration
|
||||
message_admins("BLOODSUCKER NOTICE: Daylight Ended. Resetting to Night (Lasts for [nighttime_duration / 60] minutes.)")
|
||||
else
|
||||
switch(time_til_cycle)
|
||||
if(TIME_BLOODSUCKER_DAY_WARN)
|
||||
//sleep(TIME_BLOODSUCKER_NIGHT - TIME_BLOODSUCKER_DAY_WARN)
|
||||
warn_daylight(1,"<span class = 'danger'>Solar Flares will bombard the station with dangerous UV in [TIME_BLOODSUCKER_DAY_WARN / 60] minutes. <b>Prepare to seek cover in a coffin or closet.</b></span>") // time2text <-- use Help On
|
||||
give_home_power() // Give VANISHING ACT power to all vamps with a lair!
|
||||
if(TIME_BLOODSUCKER_DAY_FINAL_WARN)
|
||||
message_admins("BLOODSUCKER NOTICE: Daylight beginning in [TIME_BLOODSUCKER_DAY_FINAL_WARN] seconds.)")
|
||||
warn_daylight(2,"<span class = 'userdanger'>Solar Flares are about to bombard the station! You have [TIME_BLOODSUCKER_DAY_FINAL_WARN] seconds to find cover!</span>",\
|
||||
"<span class = 'danger'>In [TIME_BLOODSUCKER_DAY_FINAL_WARN / 10], your master will be at risk of a Solar Flare. Make sure they find cover!</span>")
|
||||
if(5)
|
||||
warn_daylight(3,"<span class = 'userdanger'>Seek cover, for Sol rises!</span>")
|
||||
if(0)
|
||||
warn_daylight(4,"<span class = 'userdanger'>Solar flares bombard the station with deadly UV light!</span><br><span class = ''>Stay in cover for the next [TIME_BLOODSUCKER_DAY / 60] minutes or risk Final Death!</span>",\
|
||||
"<span class = 'danger'>Solar flares bombard the station with UV light!</span>")
|
||||
amDay = TRUE
|
||||
message_admins("BLOODSUCKER NOTICE: Daylight Beginning (Lasts for [TIME_BLOODSUCKER_DAY / 60] minutes.)")
|
||||
time_til_cycle = TIME_BLOODSUCKER_DAY
|
||||
|
||||
/obj/effect/sunlight/proc/warn_daylight(danger_level =0, vampwarn = "", vassalwarn = "")
|
||||
for(var/datum/mind/M in SSticker.mode.bloodsuckers)
|
||||
@@ -162,32 +143,6 @@
|
||||
M.current.updatehealth()
|
||||
SEND_SIGNAL(M.current, COMSIG_ADD_MOOD_EVENT, "vampsleep", /datum/mood_event/daylight_2)
|
||||
|
||||
/obj/effect/sunlight/proc/day_end()
|
||||
for(var/datum/mind/M in SSticker.mode.bloodsuckers)
|
||||
if(!istype(M) || !istype(M.current))
|
||||
continue
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = M.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
if(!istype(bloodsuckerdatum))
|
||||
continue
|
||||
// Reset Warnings
|
||||
bloodsuckerdatum.warn_sun_locker = FALSE
|
||||
bloodsuckerdatum.warn_sun_burn = FALSE
|
||||
// Remove Dawn Powers
|
||||
for(var/datum/action/bloodsucker/P in bloodsuckerdatum.powers)
|
||||
if(istype(P, /datum/action/bloodsucker/gohome))
|
||||
bloodsuckerdatum.powers -= P
|
||||
P.Remove(M.current)
|
||||
|
||||
/obj/effect/sunlight/proc/vamps_rank_up()
|
||||
set waitfor = FALSE
|
||||
// Cycle through all vamp antags and check if they're inside a closet.
|
||||
for(var/datum/mind/M in SSticker.mode.bloodsuckers)
|
||||
if(!istype(M) || !istype(M.current))
|
||||
continue
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = M.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
if(istype(bloodsuckerdatum))
|
||||
bloodsuckerdatum.RankUp() // Rank up! Must still be in a coffin to level!
|
||||
|
||||
/obj/effect/sunlight/proc/give_home_power()
|
||||
// It's late...! Give the "Vanishing Act" gohome power to bloodsuckers.
|
||||
for(var/datum/mind/M in SSticker.mode.bloodsuckers)
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
update_slab_info()
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(is_servant_of_ratvar(M) || isobserver(M))
|
||||
M.playsound_local(M, 'sound/magic/clockwork/scripture_tier_up.ogg', 50, FALSE, pressure_affected = FALSE)
|
||||
M.playsound_local(M, 'sound/magic/clockwork/scripture_tier_up.ogg', 20, FALSE, pressure_affected = FALSE)
|
||||
|
||||
/proc/update_slab_info(obj/item/clockwork/slab/set_slab)
|
||||
generate_all_scripture()
|
||||
|
||||
@@ -21,8 +21,10 @@
|
||||
var/recollecting = TRUE //if we're looking at fancy recollection. tutorial enabled by default
|
||||
var/recollection_category = "Default"
|
||||
|
||||
var/list/quickbound = list(/datum/clockwork_scripture/spatial_gateway, \
|
||||
/datum/clockwork_scripture/ranged_ability/kindle, /datum/clockwork_scripture/ranged_ability/hateful_manacles) //quickbound scripture, accessed by index
|
||||
var/list/quickbound = list(
|
||||
/datum/clockwork_scripture/spatial_gateway,
|
||||
/datum/clockwork_scripture/ranged_ability/kindle,
|
||||
/datum/clockwork_scripture/ranged_ability/hateful_manacles) //quickbound scripture, accessed by index
|
||||
var/maximum_quickbound = 5 //how many quickbound scriptures we can have
|
||||
|
||||
var/obj/structure/destructible/clockwork/trap/linking //If we're linking traps together, which ones we're doing
|
||||
@@ -326,6 +328,7 @@
|
||||
"requirement" = "Unlock powerful equipment and structures by converting five servants or if [DisplayPower(JUDGEMENT_UNLOCK_THRESHOLD)] of power is reached..",
|
||||
"ready" = SSticker.scripture_states[SCRIPTURE_JUDGEMENT]
|
||||
)
|
||||
// no need to learn shit, ratvar is free
|
||||
.["recollection_categories"] = list()
|
||||
if(GLOB.ratvar_awakens)
|
||||
return
|
||||
@@ -340,19 +343,25 @@
|
||||
)
|
||||
.["rec_section"] = get_recollection(recollection_category)
|
||||
generate_all_scripture()
|
||||
//needs a new place to live, preferably when clockcult unlocks/downgrades a tier. Smart enough to earlyreturn.
|
||||
//needs a new place to live, preferably when clockcult unlocks/downgrades a tier.
|
||||
//comsig maybe?
|
||||
|
||||
/obj/item/clockwork/slab/ui_act(action, params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
switch(action)
|
||||
if("toggle")
|
||||
recollecting = !recollecting
|
||||
. = TRUE
|
||||
if("recite")
|
||||
INVOKE_ASYNC(src, .proc/recite_scripture, text2path(params["script"]), usr, FALSE)
|
||||
. = TRUE
|
||||
if("bind")
|
||||
var/datum/clockwork_scripture/path = text2path(params["script"]) //we need a path and not a string
|
||||
if(!ispath(path, /datum/clockwork_scripture) || !initial(path.quickbind) || initial(path.tier) == SCRIPTURE_PERIPHERAL) //fuck you href bus
|
||||
to_chat(usr, "<span class='warning'>Nice try using href exploits</span>")
|
||||
return
|
||||
return FALSE
|
||||
var/found_index = quickbound.Find(path)
|
||||
if(found_index) //hey, we already HAVE this bound
|
||||
if(LAZYLEN(quickbound) == found_index) //if it's the last scripture, remove it instead of leaving a null
|
||||
@@ -361,6 +370,7 @@
|
||||
quickbound[found_index] = null //otherwise, leave it as a null so the scripture maintains position
|
||||
update_quickbind()
|
||||
else
|
||||
// todo: async this due to ((input)) but its fine for now
|
||||
var/target_index = input("Position of [initial(path.name)], 1 to [maximum_quickbound]?", "Input") as num|null
|
||||
if(isnum(target_index) && target_index > 0 && target_index <= maximum_quickbound && !..())
|
||||
var/datum/clockwork_scripture/S
|
||||
@@ -368,10 +378,11 @@
|
||||
S = quickbound[target_index]
|
||||
if(S != path)
|
||||
quickbind_to_slot(path, target_index)
|
||||
. = TRUE
|
||||
if("rec_category")
|
||||
recollection_category = params["category"]
|
||||
update_static_data()
|
||||
return TRUE
|
||||
. = TRUE
|
||||
|
||||
/obj/item/clockwork/slab/proc/quickbind_to_slot(datum/clockwork_scripture/scripture, index) //takes a typepath(typecast for initial()) and binds it to a slot
|
||||
if(!ispath(scripture) || !scripture || (scripture in quickbound))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/mob/living/carbon/true_devil/doUnEquip(obj/item/I, force)
|
||||
/mob/living/carbon/true_devil/doUnEquip(obj/item/I, force, silent = FALSE)
|
||||
if(..())
|
||||
update_inv_hands()
|
||||
return 1
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
var/list/trait_list = list(TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE)
|
||||
|
||||
/datum/eldritch_knowledge/final/ash_final/on_finished_recipe(mob/living/user, list/atoms, loc)
|
||||
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the blaze, for Ashbringer [user.real_name] has come! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
|
||||
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the blaze, for the Ashlord, [user.real_name] has ascended! The flames shall consume all! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
|
||||
user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/fire_cascade/big)
|
||||
user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/fire_sworn)
|
||||
var/mob/living/carbon/human/H = user
|
||||
@@ -201,6 +201,7 @@
|
||||
H.physiology.burn_mod *= 0.5
|
||||
var/datum/antagonist/heretic/ascension = H.mind.has_antag_datum(/datum/antagonist/heretic)
|
||||
ascension.ascended = TRUE
|
||||
H.client?.give_award(/datum/award/achievement/misc/ash_ascension, H)
|
||||
for(var/X in trait_list)
|
||||
ADD_TRAIT(user,X,MAGIC_TRAIT)
|
||||
return ..()
|
||||
|
||||
@@ -232,7 +232,7 @@
|
||||
log_game("[key_name_admin(ghost_candidate)] has taken control of ([key_name_admin(summoned)]).")
|
||||
summoned.ghostize(FALSE)
|
||||
summoned.key = ghost_candidate.key
|
||||
summoned.mind.add_antag_datum(/datum/antagonist/heretic_monster)
|
||||
summoned.mind.add_antag_datum(/datum/antagonist/heretic_monster) //no you will NOT get the achivement you ghost.
|
||||
var/datum/antagonist/heretic_monster/monster = summoned.mind.has_antag_datum(/datum/antagonist/heretic_monster)
|
||||
var/datum/antagonist/heretic/master = user.mind.has_antag_datum(/datum/antagonist/heretic)
|
||||
monster.set_owner(master)
|
||||
@@ -243,11 +243,14 @@
|
||||
user.SetImmobilized(0)
|
||||
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the dark, for king of arms has ascended! Lord of the night has come! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
|
||||
log_game("[user.real_name] ascended as [summoned.real_name]")
|
||||
var/mob/living/carbon/carbon_user = user
|
||||
var/datum/antagonist/heretic/ascension = carbon_user.mind.has_antag_datum(/datum/antagonist/heretic)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.client?.give_award(/datum/award/achievement/misc/flesh_ascension, H)
|
||||
var/datum/antagonist/heretic/ascension = user.mind.has_antag_datum(/datum/antagonist/heretic)
|
||||
ascension.ascended = TRUE
|
||||
carbon_user.mind.transfer_to(summoned, TRUE)
|
||||
carbon_user.gib()
|
||||
user.mind.transfer_to(summoned, TRUE)
|
||||
user.gib()
|
||||
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -169,7 +169,8 @@
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.physiology.brute_mod *= 0.5
|
||||
H.physiology.burn_mod *= 0.5
|
||||
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the decay, for Rustbringer [user.real_name] has come! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
|
||||
H.client?.give_award(/datum/award/achievement/misc/rust_ascension, H)
|
||||
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the decay, for the Rustbringer, [user.real_name] has ascended! None shall escape the corrosion! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
|
||||
new /datum/rust_spread(loc)
|
||||
var/datum/antagonist/heretic/ascension = H.mind.has_antag_datum(/datum/antagonist/heretic)
|
||||
ascension.ascended = TRUE
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
/datum/asset_cache_item/New(name, file)
|
||||
if (!isfile(file))
|
||||
file = fcopy_rsc(file)
|
||||
|
||||
|
||||
hash = md5asfile(file) //icons sent to the rsc sometimes md5 incorrectly
|
||||
if (!hash)
|
||||
CRASH("invalid asset sent to asset cache")
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/datum/asset/simple/tgui_common
|
||||
keep_local_name = TRUE
|
||||
assets = list(
|
||||
"tgui-common.chunk.js" = 'tgui/public/tgui-common.chunk.js',
|
||||
"tgui-common.bundle.js" = 'tgui/public/tgui-common.bundle.js',
|
||||
)
|
||||
|
||||
/datum/asset/simple/tgui
|
||||
@@ -47,9 +47,9 @@
|
||||
"smmon_3.gif" = 'icons/program_icons/smmon_3.gif',
|
||||
"smmon_4.gif" = 'icons/program_icons/smmon_4.gif',
|
||||
"smmon_5.gif" = 'icons/program_icons/smmon_5.gif',
|
||||
"smmon_6.gif" = 'icons/program_icons/smmon_6.gif'
|
||||
// "borg_mon.gif" = 'icons/program_icons/borg_mon.gif',
|
||||
// "robotact.gif" = 'icons/program_icons/robotact.gif'
|
||||
"smmon_6.gif" = 'icons/program_icons/smmon_6.gif',
|
||||
"borg_mon.gif" = 'icons/program_icons/borg_mon.gif',
|
||||
"robotact.gif" = 'icons/program_icons/robotact.gif'
|
||||
)
|
||||
|
||||
/datum/asset/simple/radar_assets
|
||||
@@ -172,7 +172,6 @@
|
||||
/datum/asset/spritesheet/chat/register()
|
||||
InsertAll("emoji", 'icons/emoji.dmi')
|
||||
InsertAll("emoji", 'icons/emoji_32.dmi')
|
||||
|
||||
// pre-loading all lanugage icons also helps to avoid meta
|
||||
InsertAll("language", 'icons/misc/language.dmi')
|
||||
// catch languages which are pulling icons from another file
|
||||
@@ -190,7 +189,7 @@
|
||||
)
|
||||
|
||||
/datum/asset/simple/namespaced/common
|
||||
assets = list("padlock.png" = 'html/padlock.png')
|
||||
assets = list("padlock.png" = 'html/padlock.png')
|
||||
parents = list("common.css" = 'html/browser/common.css')
|
||||
|
||||
/datum/asset/simple/permissions
|
||||
@@ -222,7 +221,7 @@
|
||||
"boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif',
|
||||
"boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif',
|
||||
)
|
||||
/*
|
||||
|
||||
/datum/asset/spritesheet/simple/achievements
|
||||
name ="achievements"
|
||||
assets = list(
|
||||
@@ -233,6 +232,7 @@
|
||||
"bbgum" = 'icons/UI_Icons/Achievements/Boss/bbgum.png',
|
||||
"colossus" = 'icons/UI_Icons/Achievements/Boss/colossus.png',
|
||||
"hierophant" = 'icons/UI_Icons/Achievements/Boss/hierophant.png',
|
||||
"drake" = 'icons/UI_Icons/Achievements/Boss/drake.png',
|
||||
"legion" = 'icons/UI_Icons/Achievements/Boss/legion.png',
|
||||
"miner" = 'icons/UI_Icons/Achievements/Boss/miner.png',
|
||||
"swarmer" = 'icons/UI_Icons/Achievements/Boss/swarmer.png',
|
||||
@@ -246,32 +246,23 @@
|
||||
"clownking" = 'icons/UI_Icons/Achievements/Misc/clownking.png',
|
||||
"clownthanks" = 'icons/UI_Icons/Achievements/Misc/clownthanks.png',
|
||||
"rule8" = 'icons/UI_Icons/Achievements/Misc/rule8.png',
|
||||
"longshift" = 'icons/UI_Icons/Achievements/Misc/longshift.png',
|
||||
"snail" = 'icons/UI_Icons/Achievements/Misc/snail.png',
|
||||
"ascension" = 'icons/UI_Icons/Achievements/Misc/ascension.png',
|
||||
"ashascend" = 'icons/UI_Icons/Achievements/Misc/ashascend.png',
|
||||
"fleshascend" = 'icons/UI_Icons/Achievements/Misc/fleshascend.png',
|
||||
"rustascend" = 'icons/UI_Icons/Achievements/Misc/rustascend.png',
|
||||
"voidascend" = 'icons/UI_Icons/Achievements/Misc/voidascend.png',
|
||||
"toolbox_soul" = 'icons/UI_Icons/Achievements/Misc/toolbox_soul.png',
|
||||
"chem_tut" = 'icons/UI_Icons/Achievements/Misc/chem_tut.png',
|
||||
"mining" = 'icons/UI_Icons/Achievements/Skills/mining.png',
|
||||
"assistant" = 'icons/UI_Icons/Achievements/Mafia/assistant.png',
|
||||
"changeling" = 'icons/UI_Icons/Achievements/Mafia/changeling.png',
|
||||
"chaplain" = 'icons/UI_Icons/Achievements/Mafia/chaplain.png',
|
||||
"clown" = 'icons/UI_Icons/Achievements/Mafia/clown.png',
|
||||
"detective" = 'icons/UI_Icons/Achievements/Mafia/detective.png',
|
||||
"fugitive" = 'icons/UI_Icons/Achievements/Mafia/fugitive.png',
|
||||
"mafia" = 'icons/UI_Icons/Achievements/Mafia/mafia.png',
|
||||
"town" = 'icons/UI_Icons/Achievements/Mafia/town.png',
|
||||
"neutral" = 'icons/UI_Icons/Achievements/Mafia/neutral.png',
|
||||
"hated" = 'icons/UI_Icons/Achievements/Mafia/hated.png',
|
||||
"hop" = 'icons/UI_Icons/Achievements/Mafia/hop.png',
|
||||
"lawyer" = 'icons/UI_Icons/Achievements/Mafia/lawyer.png',
|
||||
"md" = 'icons/UI_Icons/Achievements/Mafia/md.png',
|
||||
"nightmare" = 'icons/UI_Icons/Achievements/Mafia/nightmare.png',
|
||||
"obsessed" = 'icons/UI_Icons/Achievements/Mafia/obsessed.png',
|
||||
"psychologist" = 'icons/UI_Icons/Achievements/Mafia/psychologist.png',
|
||||
"thoughtfeeder" = 'icons/UI_Icons/Achievements/Mafia/thoughtfeeder.png',
|
||||
"traitor" = 'icons/UI_Icons/Achievements/Mafia/traitor.png',
|
||||
"basemafia" ='icons/UI_Icons/Achievements/basemafia.png',
|
||||
"frenching" = 'icons/UI_Icons/Achievements/Misc/frenchingthebubble.png'
|
||||
)
|
||||
*/
|
||||
|
||||
/datum/asset/spritesheet/simple/minesweeper
|
||||
name = "minesweeper"
|
||||
@@ -317,28 +308,28 @@
|
||||
"pill21" = 'icons/UI_Icons/Pills/pill21.png',
|
||||
"pill22" = 'icons/UI_Icons/Pills/pill22.png',
|
||||
)
|
||||
/*
|
||||
/datum/asset/spritesheet/simple/condiments
|
||||
name = "condiments"
|
||||
assets = list(
|
||||
CONDIMASTER_STYLE_FALLBACK = 'icons/UI_Icons/Condiments/emptycondiment.png',
|
||||
"enzyme" = 'icons/UI_Icons/Condiments/enzyme.png',
|
||||
"flour" = 'icons/UI_Icons/Condiments/flour.png',
|
||||
"mayonnaise" = 'icons/UI_Icons/Condiments/mayonnaise.png',
|
||||
"milk" = 'icons/UI_Icons/Condiments/milk.png',
|
||||
"blackpepper" = 'icons/UI_Icons/Condiments/peppermillsmall.png',
|
||||
"rice" = 'icons/UI_Icons/Condiments/rice.png',
|
||||
"sodiumchloride" = 'icons/UI_Icons/Condiments/saltshakersmall.png',
|
||||
"soymilk" = 'icons/UI_Icons/Condiments/soymilk.png',
|
||||
"soysauce" = 'icons/UI_Icons/Condiments/soysauce.png',
|
||||
"sugar" = 'icons/UI_Icons/Condiments/sugar.png',
|
||||
"ketchup" = 'icons/UI_Icons/Condiments/ketchup.png',
|
||||
"capsaicin" = 'icons/UI_Icons/Condiments/hotsauce.png',
|
||||
"frostoil" = 'icons/UI_Icons/Condiments/coldsauce.png',
|
||||
"bbqsauce" = 'icons/UI_Icons/Condiments/bbqsauce.png',
|
||||
"cornoil" = 'icons/UI_Icons/Condiments/oliveoil.png',
|
||||
)
|
||||
*/
|
||||
|
||||
// /datum/asset/spritesheet/simple/condiments
|
||||
// name = "condiments"
|
||||
// assets = list(
|
||||
// CONDIMASTER_STYLE_FALLBACK = 'icons/UI_Icons/Condiments/emptycondiment.png',
|
||||
// "enzyme" = 'icons/UI_Icons/Condiments/enzyme.png',
|
||||
// "flour" = 'icons/UI_Icons/Condiments/flour.png',
|
||||
// "mayonnaise" = 'icons/UI_Icons/Condiments/mayonnaise.png',
|
||||
// "milk" = 'icons/UI_Icons/Condiments/milk.png',
|
||||
// "blackpepper" = 'icons/UI_Icons/Condiments/peppermillsmall.png',
|
||||
// "rice" = 'icons/UI_Icons/Condiments/rice.png',
|
||||
// "sodiumchloride" = 'icons/UI_Icons/Condiments/saltshakersmall.png',
|
||||
// "soymilk" = 'icons/UI_Icons/Condiments/soymilk.png',
|
||||
// "soysauce" = 'icons/UI_Icons/Condiments/soysauce.png',
|
||||
// "sugar" = 'icons/UI_Icons/Condiments/sugar.png',
|
||||
// "ketchup" = 'icons/UI_Icons/Condiments/ketchup.png',
|
||||
// "capsaicin" = 'icons/UI_Icons/Condiments/hotsauce.png',
|
||||
// "frostoil" = 'icons/UI_Icons/Condiments/coldsauce.png',
|
||||
// "bbqsauce" = 'icons/UI_Icons/Condiments/bbqsauce.png',
|
||||
// "cornoil" = 'icons/UI_Icons/Condiments/oliveoil.png',
|
||||
// )
|
||||
|
||||
//this exists purely to avoid meta by pre-loading all language icons.
|
||||
/datum/asset/language/register()
|
||||
for(var/path in typesof(/datum/language))
|
||||
@@ -485,7 +476,7 @@
|
||||
|
||||
/datum/asset/simple/orbit
|
||||
assets = list(
|
||||
"ghost.png" = 'html/ghost.png'
|
||||
"ghost.png" = 'html/ghost.png'
|
||||
)
|
||||
|
||||
/datum/asset/simple/vv
|
||||
@@ -521,7 +512,8 @@
|
||||
var/list/portrait = p
|
||||
var/png = "data/paintings/[tab]/[portrait["md5"]].png"
|
||||
if(fexists(png))
|
||||
assets[portrait["title"]] = png
|
||||
var/asset_name = "[tab]_[portrait["md5"]]"
|
||||
assets[asset_name] = png
|
||||
..() //this is where it registers all these assets we added to the list
|
||||
|
||||
/datum/asset/simple/portraits/library
|
||||
@@ -537,3 +529,27 @@
|
||||
assets = list(
|
||||
"safe_dial.png" = 'html/safe_dial.png'
|
||||
)
|
||||
|
||||
// /datum/asset/spritesheet/fish
|
||||
// name = "fish"
|
||||
|
||||
// /datum/asset/spritesheet/fish/register()
|
||||
// for (var/path in subtypesof(/datum/aquarium_behaviour/fish))
|
||||
// var/datum/aquarium_behaviour/fish/fish_type = path
|
||||
// var/fish_icon = initial(fish_type.icon)
|
||||
// var/fish_icon_state = initial(fish_type.icon_state)
|
||||
// var/id = sanitize_css_class_name("[fish_icon][fish_icon_state]")
|
||||
// if(sprites[id]) //no dupes
|
||||
// continue
|
||||
// Insert(id, fish_icon, fish_icon_state)
|
||||
// ..()
|
||||
|
||||
/// Removes all non-alphanumerics from the text, keep in mind this can lead to id conflicts
|
||||
/proc/sanitize_css_class_name(name)
|
||||
var/static/regex/regex = new(@"[^a-zA-Z0-9]","g")
|
||||
return replacetext(name, regex, "")
|
||||
|
||||
/datum/asset/simple/tutorial_advisors
|
||||
assets = list(
|
||||
"chem_help_advisor.gif" = 'icons/UI_Icons/Advisors/chem_help_advisor.gif',
|
||||
)
|
||||
|
||||
@@ -24,7 +24,7 @@ Call .get_url_mappings() to get an associated list with the urls your assets can
|
||||
|
||||
See the documentation for `/datum/asset_transport` for the backend api the asset datums utilize.
|
||||
|
||||
The global variable `SSassets.transport` contains the currently configured transport.
|
||||
The global variable `SSassets.transport` contains the currently configured transport.
|
||||
|
||||
|
||||
|
||||
@@ -32,6 +32,6 @@ The global variable `SSassets.transport` contains the currently configured trans
|
||||
|
||||
Because byond browse() calls use non-blocking queues, if your code uses output() (which bypasses all of these queues) to invoke javascript functions you will need to first have the javascript announce to the server it has loaded before trying to invoke js functions.
|
||||
|
||||
To make your code work with any CDNs configured by the server, you must make sure assets are referenced from the url returned by `get_url_mappings()` or by asset_transport's `get_asset_url()`. (TGUI also has helpers for this.) If this can not be easily done, you can bypass the cdn using legacy assets, see the simple asset datum for details.
|
||||
To make your code work with any CDNs configured by the server, you must make sure assets are referenced from the url returned by `get_url_mappings()` or by asset_transport's `get_asset_url()`. (TGUI also has helpers for this.) If this can not be easily done, you can bypass the cdn using legacy assets, see the simple asset datum for details.
|
||||
|
||||
CSS files that use url() can be made to use the CDN without needing to rewrite all url() calls in code by using the namespaced helper datum. See the documentation for `/datum/asset/simple/namespaced` for details.
|
||||
|
||||
@@ -359,3 +359,28 @@ get_true_breath_pressure(pp) --> gas_pp = pp/breath_pp*total_moles()
|
||||
to_chat(src, "Total time (new gas mixture): [total_time]ms")
|
||||
to_chat(src, "Operations per second: [100000 / (total_time/1000)]")
|
||||
*/
|
||||
|
||||
/// Releases gas from src to output air. This means that it can not transfer air to gas mixture with higher pressure.
|
||||
/// a global proc due to rustmos
|
||||
/proc/release_gas_to(datum/gas_mixture/input_air, datum/gas_mixture/output_air, target_pressure)
|
||||
var/output_starting_pressure = output_air.return_pressure()
|
||||
var/input_starting_pressure = input_air.return_pressure()
|
||||
|
||||
if(output_starting_pressure >= min(target_pressure,input_starting_pressure-10))
|
||||
//No need to pump gas if target is already reached or input pressure is too low
|
||||
//Need at least 10 KPa difference to overcome friction in the mechanism
|
||||
return FALSE
|
||||
|
||||
//Calculate necessary moles to transfer using PV = nRT
|
||||
if((input_air.total_moles() > 0) && (input_air.return_temperature()>0))
|
||||
var/pressure_delta = min(target_pressure - output_starting_pressure, (input_starting_pressure - output_starting_pressure)/2)
|
||||
//Can not have a pressure delta that would cause output_pressure > input_pressure
|
||||
|
||||
var/transfer_moles = pressure_delta*output_air.return_volume()/(input_air.return_temperature() * R_IDEAL_GAS_EQUATION)
|
||||
|
||||
//Actually transfer the gas
|
||||
var/datum/gas_mixture/removed = input_air.remove(transfer_moles)
|
||||
output_air.merge(removed)
|
||||
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -358,7 +358,7 @@
|
||||
/datum/gas/oxygen = 20,
|
||||
/datum/gas/nitrogen = 20,
|
||||
/datum/gas/nitrous_oxide = 5,
|
||||
"TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST*400
|
||||
"TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST*25
|
||||
)
|
||||
|
||||
/datum/gas_reaction/nitrylformation/react(datum/gas_mixture/air)
|
||||
@@ -369,8 +369,8 @@
|
||||
var/energy_used = heat_efficency*NITRYL_FORMATION_ENERGY
|
||||
if ((air.get_moles(/datum/gas/oxygen) - heat_efficency < 0 )|| (air.get_moles(/datum/gas/nitrogen) - heat_efficency < 0)) //Shouldn't produce gas from nothing.
|
||||
return NO_REACTION
|
||||
air.adjust_moles(/datum/gas/oxygen, heat_efficency)
|
||||
air.adjust_moles(/datum/gas/nitrogen, heat_efficency)
|
||||
air.adjust_moles(/datum/gas/oxygen, -heat_efficency)
|
||||
air.adjust_moles(/datum/gas/nitrogen, -heat_efficency)
|
||||
air.adjust_moles(/datum/gas/nitryl, heat_efficency*2)
|
||||
|
||||
if(energy_used > 0)
|
||||
@@ -499,7 +499,7 @@
|
||||
min_requirements = list(
|
||||
/datum/gas/nitrogen = 10,
|
||||
/datum/gas/tritium = 5,
|
||||
"TEMP" = 5000000)
|
||||
"ENER" = NOBLIUM_FORMATION_ENERGY)
|
||||
|
||||
/datum/gas_reaction/nobliumformation/react(datum/gas_mixture/air)
|
||||
var/old_heat_capacity = air.heat_capacity()
|
||||
|
||||
@@ -55,26 +55,7 @@ Passive gate is similar to the regular pump except:
|
||||
|
||||
var/datum/gas_mixture/air1 = airs[1]
|
||||
var/datum/gas_mixture/air2 = airs[2]
|
||||
|
||||
var/output_starting_pressure = air2.return_pressure()
|
||||
var/input_starting_pressure = air1.return_pressure()
|
||||
|
||||
if(output_starting_pressure >= min(target_pressure,input_starting_pressure-10))
|
||||
//No need to pump gas if target is already reached or input pressure is too low
|
||||
//Need at least 10 KPa difference to overcome friction in the mechanism
|
||||
return
|
||||
|
||||
//Calculate necessary moles to transfer using PV = nRT
|
||||
if((air1.total_moles() > 0) && (air1.return_temperature()>0))
|
||||
var/pressure_delta = min(target_pressure - output_starting_pressure, (input_starting_pressure - output_starting_pressure)/2)
|
||||
//Can not have a pressure delta that would cause output_pressure > input_pressure
|
||||
|
||||
var/transfer_moles = pressure_delta*air2.return_volume()/(air1.return_temperature() * R_IDEAL_GAS_EQUATION)
|
||||
|
||||
//Actually transfer the gas
|
||||
var/datum/gas_mixture/removed = air1.remove(transfer_moles)
|
||||
air2.merge(removed)
|
||||
|
||||
if(release_gas_to(air1, air2, target_pressure))
|
||||
update_parents()
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
desc = "Very useful for filtering gasses."
|
||||
|
||||
can_unwrench = TRUE
|
||||
|
||||
var/transfer_rate = MAX_TRANSFER_RATE
|
||||
var/filter_type = null
|
||||
var/frequency = 0
|
||||
|
||||
@@ -2,14 +2,17 @@
|
||||
/obj/machinery/atmospherics/components/unary/tank
|
||||
icon = 'icons/obj/atmospherics/pipes/pressure_tank.dmi'
|
||||
icon_state = "generic"
|
||||
|
||||
name = "pressure tank"
|
||||
desc = "A large vessel containing pressurized gas."
|
||||
|
||||
max_integrity = 800
|
||||
density = TRUE
|
||||
layer = ABOVE_WINDOW_LAYER
|
||||
plane = GAME_PLANE
|
||||
pipe_flags = PIPING_ONE_PER_TURF
|
||||
|
||||
var/volume = 10000 //in liters
|
||||
/// The typepath of the gas this tank should be filled with.
|
||||
var/gas_type = 0
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/New()
|
||||
@@ -20,6 +23,7 @@
|
||||
if(gas_type)
|
||||
air_contents.set_moles(AIR_CONTENTS)
|
||||
name = "[name] ([GLOB.meta_gas_names[gas_type]])"
|
||||
setPipingLayer(piping_layer)
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/air
|
||||
icon_state = "grey"
|
||||
@@ -38,15 +42,71 @@
|
||||
icon_state = "orange"
|
||||
gas_type = /datum/gas/plasma
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/oxygen
|
||||
icon_state = "blue"
|
||||
gas_type = /datum/gas/oxygen
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/nitrogen
|
||||
icon_state = "red"
|
||||
gas_type = /datum/gas/nitrogen
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/nitrous_oxide
|
||||
/obj/machinery/atmospherics/components/unary/tank/oxygen
|
||||
icon_state = "blue"
|
||||
gas_type = /datum/gas/oxygen
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/nitrous
|
||||
icon_state = "red_white"
|
||||
gas_type = /datum/gas/nitrous_oxide
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/bz
|
||||
gas_type = /datum/gas/bz
|
||||
|
||||
// /obj/machinery/atmospherics/components/unary/tank/freon
|
||||
// icon_state = "blue"
|
||||
// gas_type = /datum/gas/freon
|
||||
|
||||
// /obj/machinery/atmospherics/components/unary/tank/halon
|
||||
// icon_state = "blue"
|
||||
// gas_type = /datum/gas/halon
|
||||
|
||||
// /obj/machinery/atmospherics/components/unary/tank/healium
|
||||
// icon_state = "red"
|
||||
// gas_type = /datum/gas/healium
|
||||
|
||||
// /obj/machinery/atmospherics/components/unary/tank/hydrogen
|
||||
// icon_state = "grey"
|
||||
// gas_type = /datum/gas/hydrogen
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/hypernoblium
|
||||
icon_state = "blue"
|
||||
gas_type = /datum/gas/hypernoblium
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/miasma
|
||||
gas_type = /datum/gas/miasma
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/nitryl
|
||||
gas_type = /datum/gas/nitryl
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/pluoxium
|
||||
icon_state = "blue"
|
||||
gas_type = /datum/gas/pluoxium
|
||||
|
||||
// /obj/machinery/atmospherics/components/unary/tank/proto_nitrate
|
||||
// icon_state = "red"
|
||||
// gas_type = /datum/gas/proto_nitrate
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/stimulum
|
||||
icon_state = "red"
|
||||
gas_type = /datum/gas/stimulum
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/tritium
|
||||
gas_type = /datum/gas/tritium
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/water_vapor
|
||||
icon_state = "grey"
|
||||
gas_type = /datum/gas/water_vapor
|
||||
|
||||
// /obj/machinery/atmospherics/components/unary/tank/zauker
|
||||
// gas_type = /datum/gas/zauker
|
||||
|
||||
// /obj/machinery/atmospherics/components/unary/tank/helium
|
||||
// gas_type = /datum/gas/helium
|
||||
|
||||
// /obj/machinery/atmospherics/components/unary/tank/antinoblium
|
||||
// gas_type = /datum/gas/antinoblium
|
||||
|
||||
@@ -5,22 +5,28 @@
|
||||
desc = "A canister for the storage of gas."
|
||||
icon_state = "yellow"
|
||||
density = TRUE
|
||||
|
||||
var/valve_open = FALSE
|
||||
var/obj/machinery/atmospherics/components/binary/passive_gate/pump
|
||||
var/release_log = ""
|
||||
|
||||
volume = 1000
|
||||
var/filled = 0.5
|
||||
var/gas_type
|
||||
var/release_pressure = ONE_ATMOSPHERE
|
||||
var/can_max_release_pressure = (ONE_ATMOSPHERE * 10)
|
||||
var/can_min_release_pressure = (ONE_ATMOSPHERE / 10)
|
||||
|
||||
armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 100, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 50)
|
||||
max_integrity = 250
|
||||
integrity_failure = 0.4
|
||||
pressure_resistance = 7 * ONE_ATMOSPHERE
|
||||
|
||||
var/valve_open = FALSE
|
||||
var/release_log = ""
|
||||
|
||||
var/filled = 0.5
|
||||
var/gas_type
|
||||
|
||||
var/release_pressure = ONE_ATMOSPHERE
|
||||
var/can_max_release_pressure = (ONE_ATMOSPHERE * 10)
|
||||
var/can_min_release_pressure = (ONE_ATMOSPHERE / 10)
|
||||
|
||||
// this removes atmos fusion cans**
|
||||
///Max amount of heat allowed inside of the canister before it starts to melt (different tiers have different limits)
|
||||
// var/heat_limit = 5000
|
||||
///Max amount of pressure allowed inside of the canister before it starts to break (different tiers have different limits)
|
||||
// var/pressure_limit = 50000
|
||||
|
||||
var/temperature_resistance = 1000 + T0C
|
||||
var/starter_temp
|
||||
// Prototype vars
|
||||
@@ -32,6 +38,8 @@
|
||||
var/maximum_timer_set = 300
|
||||
var/timing = FALSE
|
||||
var/restricted = FALSE
|
||||
///Set the tier of the canister and overlay used
|
||||
// var/mode = CANISTER_TIER_1
|
||||
req_access = list()
|
||||
|
||||
var/update = 0
|
||||
@@ -186,7 +194,6 @@
|
||||
can_min_release_pressure = (ONE_ATMOSPHERE / 30)
|
||||
prototype = TRUE
|
||||
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/proto/default/oxygen
|
||||
name = "prototype canister"
|
||||
desc = "A prototype canister for a prototype bike, what could go wrong?"
|
||||
@@ -195,27 +202,18 @@
|
||||
filled = 1
|
||||
release_pressure = ONE_ATMOSPHERE*2
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/New(loc, datum/gas_mixture/existing_mixture)
|
||||
..()
|
||||
/obj/machinery/portable_atmospherics/canister/Initialize(mapload, datum/gas_mixture/existing_mixture)
|
||||
. = ..()
|
||||
if(existing_mixture)
|
||||
air_contents.copy_from(existing_mixture)
|
||||
else
|
||||
create_gas()
|
||||
pump = new(src, FALSE)
|
||||
pump.on = TRUE
|
||||
pump.stat = 0
|
||||
SSair.add_to_rebuild_queue(pump)
|
||||
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/Destroy()
|
||||
qdel(pump)
|
||||
pump = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/proc/create_gas()
|
||||
if(gas_type)
|
||||
// air_contents.add_gas(gas_type)
|
||||
if(starter_temp)
|
||||
air_contents.set_temperature(starter_temp)
|
||||
air_contents.set_moles(gas_type,(maximum_pressure * filled) * air_contents.return_volume() / (R_IDEAL_GAS_EQUATION * air_contents.return_temperature()))
|
||||
@@ -223,8 +221,10 @@
|
||||
air_contents.set_temperature(starter_temp)
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/air/create_gas()
|
||||
air_contents.set_moles(/datum/gas/oxygen, (O2STANDARD * maximum_pressure * filled) * air_contents.return_volume() / (R_IDEAL_GAS_EQUATION * air_contents.return_temperature()))
|
||||
air_contents.set_moles(/datum/gas/nitrogen, (N2STANDARD * maximum_pressure * filled) * air_contents.return_volume() / (R_IDEAL_GAS_EQUATION * air_contents.return_temperature()))
|
||||
var/oh_two = /datum/gas/oxygen
|
||||
var/dihydrogen = /datum/gas/nitrogen //how to piss of chemists
|
||||
air_contents.set_moles(oh_two, (O2STANDARD * maximum_pressure * filled) * air_contents.return_volume() / (R_IDEAL_GAS_EQUATION * air_contents.return_temperature()))
|
||||
air_contents.set_moles(dihydrogen, (N2STANDARD * maximum_pressure * filled) * air_contents.return_volume() / (R_IDEAL_GAS_EQUATION * air_contents.return_temperature()))
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/update_icon_state()
|
||||
if(stat & BROKEN)
|
||||
@@ -266,14 +266,17 @@
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
return FALSE
|
||||
|
||||
if(stat & BROKEN)
|
||||
if(!I.tool_start_check(user, amount=0))
|
||||
return TRUE
|
||||
to_chat(user, "<span class='notice'>You begin cutting [src] apart...</span>")
|
||||
if(I.use_tool(src, user, 30, volume=50))
|
||||
deconstruct(TRUE)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You cannot slice [src] apart when it isn't broken.</span>")
|
||||
if(!I.tool_start_check(user, amount=0))
|
||||
return TRUE
|
||||
var/pressure = air_contents.return_pressure()
|
||||
if(pressure > 300)
|
||||
to_chat(user, "<span class='alert'>The pressure gauge on \the [src] indicates a high pressure inside... maybe you want to reconsider?</span>")
|
||||
to_chat(user, "<span class='notice'>You begin cutting \the [src] apart...</span>")
|
||||
if(I.use_tool(src, user, 3 SECONDS, volume=50))
|
||||
to_chat(user, "<span class='notice'>You cut \the [src] apart.</span>")
|
||||
deconstruct(TRUE)
|
||||
message_admins("[src] deconstructed by [ADMIN_LOOKUPFLW(user)]")
|
||||
log_game("[src] deconstructed by [key_name(user)]")
|
||||
|
||||
return TRUE
|
||||
|
||||
@@ -316,19 +319,20 @@
|
||||
if(timing && valve_timer < world.time)
|
||||
valve_open = !valve_open
|
||||
timing = FALSE
|
||||
if(!valve_open)
|
||||
pump.airs[1] = null
|
||||
pump.airs[2] = null
|
||||
return
|
||||
if(valve_open)
|
||||
var/turf/T = get_turf(src)
|
||||
var/datum/gas_mixture/target_air = holding ? holding.air_contents : T.return_air()
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
pump.airs[1] = air_contents
|
||||
pump.airs[2] = holding ? holding.air_contents : T.return_air()
|
||||
pump.target_pressure = release_pressure
|
||||
if(release_gas_to(air_contents, target_air, release_pressure) && !holding)
|
||||
air_update_turf()
|
||||
|
||||
pump.process_atmos() // Pump gas.
|
||||
if(!holding)
|
||||
air_update_turf() // Update the environment if needed.
|
||||
// var/our_pressure = air_contents.return_pressure()
|
||||
// var/our_temperature = air_contents.return_temperature()
|
||||
|
||||
///function used to check the limit of the canisters and also set the amount of damage that the canister can receive, if the heat and pressure are way higher than the limit the more damage will be done
|
||||
// currently unused
|
||||
// if(our_temperature > heat_limit || our_pressure > pressure_limit)
|
||||
// take_damage(clamp((our_temperature/heat_limit) * (our_pressure/pressure_limit) * delta_time * 2, 5, 50), BURN, 0)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/ui_state(mob/user)
|
||||
@@ -340,35 +344,48 @@
|
||||
ui = new(user, src, "Canister", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/ui_static_data(mob/user)
|
||||
return list(
|
||||
"defaultReleasePressure" = round(CAN_DEFAULT_RELEASE_PRESSURE),
|
||||
"minReleasePressure" = round(can_min_release_pressure),
|
||||
"maxReleasePressure" = round(can_max_release_pressure),
|
||||
"pressureLimit" = round(1e14),
|
||||
"holdingTankLeakPressure" = round(TANK_LEAK_PRESSURE),
|
||||
"holdingTankFragPressure" = round(TANK_FRAGMENT_PRESSURE)
|
||||
)
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/ui_data()
|
||||
var/data = list()
|
||||
data["portConnected"] = connected_port ? 1 : 0
|
||||
data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
|
||||
data["releasePressure"] = round(release_pressure ? release_pressure : 0)
|
||||
data["defaultReleasePressure"] = round(CAN_DEFAULT_RELEASE_PRESSURE)
|
||||
data["minReleasePressure"] = round(can_min_release_pressure)
|
||||
data["maxReleasePressure"] = round(can_max_release_pressure)
|
||||
data["valveOpen"] = valve_open ? 1 : 0
|
||||
. = list(
|
||||
"portConnected" = !!connected_port,
|
||||
"tankPressure" = round(air_contents.return_pressure()),
|
||||
"releasePressure" = round(release_pressure),
|
||||
"valveOpen" = !!valve_open,
|
||||
"isPrototype" = !!prototype,
|
||||
"hasHoldingTank" = !!holding
|
||||
)
|
||||
|
||||
data["isPrototype"] = prototype ? 1 : 0
|
||||
if (prototype)
|
||||
data["restricted"] = restricted
|
||||
data["timing"] = timing
|
||||
data["time_left"] = get_time_left()
|
||||
data["timer_set"] = timer_set
|
||||
data["timer_is_not_default"] = timer_set != default_timer_set
|
||||
data["timer_is_not_min"] = timer_set != minimum_timer_set
|
||||
data["timer_is_not_max"] = timer_set != maximum_timer_set
|
||||
. += list(
|
||||
"restricted" = restricted,
|
||||
"timing" = timing,
|
||||
"time_left" = get_time_left(),
|
||||
"timer_set" = timer_set,
|
||||
"timer_is_not_default" = timer_set != default_timer_set,
|
||||
"timer_is_not_min" = timer_set != minimum_timer_set,
|
||||
"timer_is_not_max" = timer_set != maximum_timer_set
|
||||
)
|
||||
|
||||
data["hasHoldingTank"] = holding ? 1 : 0
|
||||
if (holding)
|
||||
data["holdingTank"] = list()
|
||||
data["holdingTank"]["name"] = holding.name
|
||||
data["holdingTank"]["tankPressure"] = round(holding.air_contents.return_pressure())
|
||||
return data
|
||||
. += list(
|
||||
"holdingTank" = list(
|
||||
"name" = holding.name,
|
||||
"tankPressure" = round(holding.air_contents.return_pressure())
|
||||
)
|
||||
)
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/ui_act(action, params)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
switch(action)
|
||||
if("relabel")
|
||||
@@ -377,6 +394,7 @@
|
||||
var/newtype = label2types[label]
|
||||
if(newtype)
|
||||
var/obj/machinery/portable_atmospherics/canister/replacement = newtype
|
||||
investigate_log("was relabelled to [initial(replacement.name)] by [key_name(usr)].", INVESTIGATE_ATMOS)
|
||||
name = initial(replacement.name)
|
||||
desc = initial(replacement.desc)
|
||||
icon_state = initial(replacement.icon_state)
|
||||
@@ -458,9 +476,8 @@
|
||||
if("eject")
|
||||
if(holding)
|
||||
if(valve_open)
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] removed [holding] from [src] with valve still open at [ADMIN_VERBOSEJMP(src)] releasing contents into the <span class='boldannounce'>air</span><br>.")
|
||||
investigate_log("[key_name(usr)] removed the [holding], leaving the valve open and transferring into the <span class='boldannounce'>air</span><br>", INVESTIGATE_ATMOS)
|
||||
holding.forceMove(get_turf(src))
|
||||
holding = null
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] removed [holding] from [src] with valve still open at [ADMIN_VERBOSEJMP(src)] releasing contents into the <span class='boldannounce'>air</span>.")
|
||||
investigate_log("[key_name(usr)] removed the [holding], leaving the valve open and transferring into the <span class='boldannounce'>air</span>.", INVESTIGATE_ATMOS)
|
||||
replace_tank(usr, FALSE)
|
||||
. = TRUE
|
||||
update_icon()
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
name = "pamphlet"
|
||||
icon_state = "pamphlet"
|
||||
|
||||
/obj/item/paper/pamphlet/violent_video_games
|
||||
name = "pamphlet - \'Violent Video Games and You\'"
|
||||
desc = "A pamphlet encouraging the reader to maintain a balanced lifestyle and take care of their mental health, while still enjoying video games in a healthy way. You probably don't need this..."
|
||||
info = "They don't make you kill people. There, we said it. Now get back to work!"
|
||||
|
||||
/obj/item/paper/pamphlet/gateway
|
||||
info = "<b>Welcome to the Nanotrasen Gateway project...</b><br>\
|
||||
Congratulations! If you're reading this, you and your superiors have decided that you're \
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
if(1000)
|
||||
SpeakPeace(list("The ends exists somewhere beyond meaningful milestones.", "There will be no more messages until then.", "You disgust me."))
|
||||
if(5643)
|
||||
SSmedals.UnlockMedal(MEDAL_TIMEWASTE, user.client)
|
||||
user.client.give_award(/datum/award/achievement/misc/time_waste, user)
|
||||
var/obj/item/reagent_containers/food/drinks/trophy/gold_cup/never_ends = new(get_turf(user))
|
||||
never_ends.name = "Overextending The Joke: First Place"
|
||||
never_ends.desc = "And so we are left alone with our regrets."
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
set name = "Config/Launch Supplypod"
|
||||
set desc = "Configure and launch a CentCom supplypod full of whatever your heart desires!"
|
||||
set category = "Admin.Events"
|
||||
var/datum/centcom_podlauncher/plaunch = new(usr)//create the datum
|
||||
plaunch.ui_interact(usr)//datum has a tgui component, here we open the window
|
||||
new /datum/centcom_podlauncher(usr)//create the datum
|
||||
|
||||
//Variables declared to change how items in the launch bay are picked and launched. (Almost) all of these are changed in the ui_act proc
|
||||
//Some effect groups are choices, while other are booleans. This is because some effects can stack, while others dont (ex: you can stack explosion and quiet, but you cant stack ordered launch and random launch)
|
||||
@@ -56,7 +55,6 @@
|
||||
var/list/cam_plane_masters
|
||||
var/obj/screen/background/cam_background
|
||||
var/tabIndex = 1
|
||||
var/list/timers = list("landingDelay", "fallDuration", "openingDelay", "departureDelay")
|
||||
var/renderLighting = FALSE
|
||||
|
||||
/datum/centcom_podlauncher/New(user) //user can either be a client or a mob
|
||||
@@ -148,10 +146,9 @@
|
||||
data["launchChoice"] = launchChoice //Launch turfs all at once (0), ordered (1), or randomly(1)
|
||||
data["explosionChoice"] = explosionChoice //An explosion that occurs when landing. Can be no explosion (0), custom explosion (1), or maxcap (2)
|
||||
data["damageChoice"] = damageChoice //Damage that occurs to any mob under the pod when it lands. Can be no damage (0), custom damage (1), or gib+5000dmg (2)
|
||||
data["delay_1"] = temp_pod.landingDelay //How long the pod takes to land after launching
|
||||
data["delay_2"] = temp_pod.fallDuration //How long the pod's falling animation lasts
|
||||
data["delay_3"] = temp_pod.openingDelay //How long the pod takes to open after landing
|
||||
data["delay_4"] = temp_pod.departureDelay //How long the pod takes to leave after opening (if bluespace=true, it deletes. if reversing=true, it flies back to centcom)
|
||||
data["delays"] = temp_pod.delays
|
||||
data["rev_delays"] = temp_pod.reverse_delays
|
||||
data["custom_rev_delay"] = temp_pod.custom_rev_delay
|
||||
data["styleChoice"] = temp_pod.style //Style is a variable that keeps track of what the pod is supposed to look like. It acts as an index to the GLOB.podstyles list in cargo.dm defines to get the proper icon/name/desc for the pod.
|
||||
data["effectShrapnel"] = temp_pod.effectShrapnel //If true, creates a cloud of shrapnel of a decided type and magnitude on landing
|
||||
data["shrapnelType"] = "[temp_pod.shrapnel_type]" //Path2String
|
||||
@@ -166,7 +163,7 @@
|
||||
data["effectCircle"] = temp_pod.effectCircle //If true, allows the pod to come in at any angle. Bit of a weird feature but whatever its here
|
||||
data["effectBurst"] = effectBurst //IOf true, launches five pods at once (with a very small delay between for added coolness), in a 3x3 area centered around the area
|
||||
data["effectReverse"] = temp_pod.reversing //If true, the pod will not send any items. Instead, after opening, it will close again (picking up items/mobs) and fly back to centcom
|
||||
data["reverseOptionList"] = temp_pod.reverseOptionList
|
||||
data["reverse_option_list"] = temp_pod.reverse_option_list
|
||||
data["effectTarget"] = specificTarget //Launches the pod at the turf of a specific mob target, rather than wherever the user clicked. Useful for smites
|
||||
data["effectName"] = temp_pod.adminNamed //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc)
|
||||
data["podName"] = temp_pod.name
|
||||
@@ -182,7 +179,8 @@
|
||||
return data
|
||||
|
||||
/datum/centcom_podlauncher/ui_act(action, params)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
switch(action)
|
||||
////////////////////////////UTILITIES//////////////////
|
||||
@@ -398,7 +396,7 @@
|
||||
. = TRUE
|
||||
if("reverseOption")
|
||||
var/reverseOption = params["reverseOption"]
|
||||
temp_pod.reverseOptionList[reverseOption] = !temp_pod.reverseOptionList[reverseOption]
|
||||
temp_pod.reverse_option_list[reverseOption] = !temp_pod.reverse_option_list[reverseOption]
|
||||
. = TRUE
|
||||
if("effectTarget") //Toggle: Launch at a specific mob (instead of at whatever turf you click on). Used for the supplypod smite
|
||||
if (specificTarget)
|
||||
@@ -415,13 +413,19 @@
|
||||
////////////////////////////TIMER DELAYS//////////////////
|
||||
if("editTiming") //Change the different timers relating to the pod
|
||||
var/delay = params["timer"]
|
||||
var/timer = timers[delay]
|
||||
var/value = params["value"]
|
||||
temp_pod.vars[timer] = value * 10
|
||||
var/reverse = params["reverse"]
|
||||
if (reverse)
|
||||
temp_pod.reverse_delays[delay] = value * 10
|
||||
else
|
||||
temp_pod.delays[delay] = value * 10
|
||||
. = TRUE
|
||||
if("resetTiming")
|
||||
for (var/timer in timers)
|
||||
temp_pod.vars[timer] = initial(temp_pod.vars[timer])
|
||||
temp_pod.delays = list(POD_TRANSIT = 20, POD_FALLING = 4, POD_OPENING = 30, POD_LEAVING = 30)
|
||||
temp_pod.reverse_delays = list(POD_TRANSIT = 20, POD_FALLING = 4, POD_OPENING = 30, POD_LEAVING = 30)
|
||||
. = TRUE
|
||||
if("toggleRevDelays")
|
||||
temp_pod.custom_rev_delay = !temp_pod.custom_rev_delay
|
||||
. = TRUE
|
||||
////////////////////////////ADMIN SOUNDS//////////////////
|
||||
if("fallingSound") //Admin sound from a local file that plays when the pod lands
|
||||
@@ -544,7 +548,7 @@
|
||||
var/turf/drop = locate(coords_list[1], coords_list[2], coords_list[3])
|
||||
setupView(RANGE_TURFS(3, drop))
|
||||
|
||||
/datum/centcom_podlauncher/proc/setupView(var/list/visible_turfs)
|
||||
/datum/centcom_podlauncher/proc/setupView(list/visible_turfs)
|
||||
var/list/bbox = get_bbox_of_atoms(visible_turfs)
|
||||
var/size_x = bbox[3] - bbox[1] + 1
|
||||
var/size_y = bbox[4] - bbox[2] + 1
|
||||
@@ -553,7 +557,7 @@
|
||||
cam_background.icon_state = "clear"
|
||||
cam_background.fill_rect(1, 1, size_x, size_y)
|
||||
|
||||
/datum/centcom_podlauncher/proc/updateCursor(var/forceClear = FALSE) //Update the mouse of the user
|
||||
/datum/centcom_podlauncher/proc/updateCursor(forceClear = FALSE) //Update the mouse of the user
|
||||
if (!holder) //Can't update the mouse icon if the client doesnt exist!
|
||||
return
|
||||
if (!forceClear && (launcherActivated || picking_dropoff_turf)) //If the launching param is true, we give the user new mouse icons.
|
||||
@@ -702,11 +706,10 @@
|
||||
/datum/centcom_podlauncher/proc/launch(turf/target_turf) //Game time started
|
||||
if (isnull(target_turf))
|
||||
return
|
||||
var/obj/structure/closet/supplypod/centcompod/toLaunch = DuplicateObject(temp_pod, sameloc = TRUE) //Duplicate the temp_pod (which we have been varediting or configuring with the UI) and store the result
|
||||
var/obj/structure/closet/supplypod/centcompod/toLaunch = DuplicateObject(temp_pod) //Duplicate the temp_pod (which we have been varediting or configuring with the UI) and store the result
|
||||
toLaunch.update_icon()//we update_icon() here so that the door doesnt "flicker on" right after it lands
|
||||
//We don't have this area, lets just have it where we had the temp pod
|
||||
//var/shippingLane = GLOB.areas_by_type[/area/centcom/supplypod/supplypod_temp_holding]
|
||||
//toLaunch.forceMove(shippingLane)
|
||||
var/shippingLane = GLOB.areas_by_type[/area/centcom/supplypod/supplypod_temp_holding]
|
||||
toLaunch.forceMove(shippingLane)
|
||||
if (launchClone) //We arent launching the actual items from the bay, rather we are creating clones and launching those
|
||||
if(launchRandomItem)
|
||||
var/launch_candidate = pick_n_take(launchList)
|
||||
@@ -792,7 +795,7 @@
|
||||
for (var/mob/living/M in whoDyin)
|
||||
admin_ticket_log(M, "[key_name_admin(usr)] [msg]")
|
||||
|
||||
/datum/centcom_podlauncher/proc/loadData(var/list/dataToLoad)
|
||||
/datum/centcom_podlauncher/proc/loadData(list/dataToLoad)
|
||||
bayNumber = dataToLoad["bayNumber"]
|
||||
customDropoff = dataToLoad["customDropoff"]
|
||||
renderLighting = dataToLoad["renderLighting"]
|
||||
@@ -801,10 +804,9 @@
|
||||
launchChoice = dataToLoad["launchChoice"] //Launch turfs all at once (0), ordered (1), or randomly(1)
|
||||
explosionChoice = dataToLoad["explosionChoice"] //An explosion that occurs when landing. Can be no explosion (0), custom explosion (1), or maxcap (2)
|
||||
damageChoice = dataToLoad["damageChoice"] //Damage that occurs to any mob under the pod when it lands. Can be no damage (0), custom damage (1), or gib+5000dmg (2)
|
||||
temp_pod.landingDelay = dataToLoad["delay_1"] //How long the pod takes to land after launching
|
||||
temp_pod.fallDuration = dataToLoad["delay_2"] //How long the pod's falling animation lasts
|
||||
temp_pod.openingDelay = dataToLoad["delay_3"] //How long the pod takes to open after landing
|
||||
temp_pod.departureDelay = dataToLoad["delay_4"] //How long the pod takes to leave after opening (if bluespace=true, it deletes. if reversing=true, it flies back to centcom)
|
||||
temp_pod.delays = dataToLoad["delays"]
|
||||
temp_pod.reverse_delays = dataToLoad["rev_delays"]
|
||||
temp_pod.custom_rev_delay = dataToLoad["custom_rev_delay"]
|
||||
temp_pod.setStyle(dataToLoad["styleChoice"]) //Style is a variable that keeps track of what the pod is supposed to look like. It acts as an index to the GLOB.podstyles list in cargo.dm defines to get the proper icon/name/desc for the pod.
|
||||
temp_pod.effectShrapnel = dataToLoad["effectShrapnel"] //If true, creates a cloud of shrapnel of a decided type and magnitude on landing
|
||||
temp_pod.shrapnel_type = text2path(dataToLoad["shrapnelType"])
|
||||
@@ -819,7 +821,7 @@
|
||||
temp_pod.effectCircle = dataToLoad["effectCircle"] //If true, allows the pod to come in at any angle. Bit of a weird feature but whatever its here
|
||||
effectBurst = dataToLoad["effectBurst"] //IOf true, launches five pods at once (with a very small delay between for added coolness), in a 3x3 area centered around the area
|
||||
temp_pod.reversing = dataToLoad["effectReverse"] //If true, the pod will not send any items. Instead, after opening, it will close again (picking up items/mobs) and fly back to centcom
|
||||
temp_pod.reverseOptionList = dataToLoad["reverseOptionList"]
|
||||
temp_pod.reverse_option_list = dataToLoad["reverse_option_list"]
|
||||
specificTarget = dataToLoad["effectTarget"] //Launches the pod at the turf of a specific mob target, rather than wherever the user clicked. Useful for smites
|
||||
temp_pod.adminNamed = dataToLoad["effectName"] //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc)
|
||||
temp_pod.name = dataToLoad["podName"]
|
||||
|
||||
@@ -3,8 +3,14 @@
|
||||
desc = "Used to order supplies, approve requests, and control the shuttle."
|
||||
icon_screen = "supply"
|
||||
circuit = /obj/item/circuitboard/computer/cargo
|
||||
light_color = "#E2853D"//orange
|
||||
|
||||
///Can the supply console send the shuttle back and forth? Used in the UI backend.
|
||||
var/can_send = TRUE
|
||||
///Can this console only send requests?
|
||||
var/requestonly = FALSE
|
||||
///Can you approve requests placed for cargo? Works differently between the app and the computer.
|
||||
var/can_approve_requests = TRUE
|
||||
var/contraband = FALSE
|
||||
var/self_paid = FALSE
|
||||
var/safety_warning = "For safety reasons, the automated supply shuttle \
|
||||
@@ -16,25 +22,21 @@
|
||||
/// var that tracks message cooldown
|
||||
var/message_cooldown
|
||||
var/list/loaded_coupons
|
||||
|
||||
light_color = "#E2853D"//orange
|
||||
/// var that makes express console use rockets
|
||||
var/is_express = FALSE
|
||||
|
||||
/obj/machinery/computer/cargo/request
|
||||
name = "supply request console"
|
||||
desc = "Used to request supplies from cargo."
|
||||
icon_screen = "request"
|
||||
circuit = /obj/item/circuitboard/computer/cargo/request
|
||||
can_send = FALSE
|
||||
can_approve_requests = FALSE
|
||||
requestonly = TRUE
|
||||
|
||||
/obj/machinery/computer/cargo/Initialize()
|
||||
. = ..()
|
||||
radio = new /obj/item/radio/headset/headset_cargo(src)
|
||||
var/obj/item/circuitboard/computer/cargo/board = circuit
|
||||
contraband = board.contraband
|
||||
if (board.obj_flags & EMAGGED)
|
||||
obj_flags |= EMAGGED
|
||||
else
|
||||
obj_flags &= ~EMAGGED
|
||||
|
||||
/obj/machinery/computer/cargo/Destroy()
|
||||
QDEL_NULL(radio)
|
||||
@@ -64,6 +66,10 @@
|
||||
board.obj_flags |= EMAGGED
|
||||
update_static_data(user)
|
||||
|
||||
/obj/machinery/computer/cargo/on_construction()
|
||||
. = ..()
|
||||
circuit.configure_machine(src)
|
||||
|
||||
/obj/machinery/computer/cargo/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
@@ -81,6 +87,8 @@
|
||||
data["docked"] = SSshuttle.supply.mode == SHUTTLE_IDLE
|
||||
data["loan"] = !!SSshuttle.shuttle_loan
|
||||
data["loan_dispatched"] = SSshuttle.shuttle_loan && SSshuttle.shuttle_loan.dispatched
|
||||
data["can_send"] = can_send
|
||||
data["can_approve_requests"] = can_approve_requests
|
||||
var/message = "Remember to stamp and send back the supply manifests."
|
||||
if(SSshuttle.centcom_message)
|
||||
message = SSshuttle.centcom_message
|
||||
@@ -128,14 +136,15 @@
|
||||
"id" = pack,
|
||||
"desc" = P.desc || P.name, // If there is a description, use it. Otherwise use the pack's name.
|
||||
"goody" = P.goody,
|
||||
"private_goody" = P.goody == PACK_GOODY_PRIVATE,
|
||||
"access" = P.access,
|
||||
"private_goody" = P.goody == PACK_GOODY_PRIVATE,
|
||||
"can_private_buy" = P.can_private_buy
|
||||
))
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/cargo/ui_act(action, params, datum/tgui/ui)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
switch(action)
|
||||
if("send")
|
||||
@@ -147,13 +156,13 @@
|
||||
return
|
||||
if(SSshuttle.supply.getDockedId() == "supply_home")
|
||||
SSshuttle.supply.export_categories = get_export_categories()
|
||||
SSshuttle.moveShuttle("supply", "supply_away", TRUE)
|
||||
SSshuttle.moveShuttle(SSshuttle.supply.id, "supply_away", TRUE)
|
||||
say("The supply shuttle is departing.")
|
||||
investigate_log("[key_name(usr)] sent the supply shuttle away.", INVESTIGATE_CARGO)
|
||||
else
|
||||
investigate_log("[key_name(usr)] called the supply shuttle.", INVESTIGATE_CARGO)
|
||||
say("The supply shuttle has been called and will arrive in [SSshuttle.supply.timeLeft(600)] minutes.")
|
||||
SSshuttle.moveShuttle("supply", "supply_home", TRUE)
|
||||
SSshuttle.moveShuttle(SSshuttle.supply.id, "supply_home", TRUE)
|
||||
. = TRUE
|
||||
if("loan")
|
||||
if(!SSshuttle.shuttle_loan)
|
||||
@@ -172,6 +181,8 @@
|
||||
log_game("[key_name(usr)] accepted a shuttle loan event.")
|
||||
. = TRUE
|
||||
if("add")
|
||||
if(is_express)
|
||||
return
|
||||
var/id = text2path(params["id"])
|
||||
var/datum/supply_pack/pack = SSshuttle.supply_packs[id]
|
||||
if(!istype(pack))
|
||||
@@ -195,9 +206,9 @@
|
||||
rank = "Silicon"
|
||||
|
||||
var/datum/bank_account/account
|
||||
if(self_paid && ishuman(usr))
|
||||
var/mob/living/carbon/human/H = usr
|
||||
var/obj/item/card/id/id_card = H.get_idcard(TRUE)
|
||||
if(self_paid && isliving(usr))
|
||||
var/mob/living/L = usr
|
||||
var/obj/item/card/id/id_card = L.get_idcard(TRUE)
|
||||
if(!istype(id_card))
|
||||
say("No ID card detected.")
|
||||
return
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
desc = "A fun way to spend the shift. Contains unmentionable desires."
|
||||
cost = 2000
|
||||
contraband = TRUE
|
||||
contains = list(/obj/item/vending_refill/kink, /obj/item/circuitboard/machine/kinkmate)
|
||||
contains = list(/obj/item/vending_refill/kink)
|
||||
crate_name = "Kinkmate construction kit"
|
||||
|
||||
/datum/supply_pack/vending/medical
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
//*****NOTE*****: Many of these comments are similarly described in centcom_podlauncher.dm. If you change them here, please consider doing so in the centcom podlauncher code as well!
|
||||
var/adminNamed = FALSE //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc)
|
||||
var/bluespace = FALSE //If true, the pod deletes (in a shower of sparks) after landing
|
||||
var/landingDelay = 30 //How long the pod takes to land after launching
|
||||
var/openingDelay = 30 //How long the pod takes to open after landing
|
||||
var/departureDelay = 30 //How long the pod takes to leave after opening. If bluespace = TRUE, it deletes. If reversing = TRUE, it flies back to centcom.
|
||||
var/delays = list(POD_TRANSIT = 30, POD_FALLING = 4, POD_OPENING = 30, POD_LEAVING = 30)
|
||||
var/reverse_delays = list(POD_TRANSIT = 30, POD_FALLING = 4, POD_OPENING = 30, POD_LEAVING = 30)
|
||||
var/custom_rev_delay = FALSE
|
||||
var/damage = 0 //Damage that occurs to any mob under the pod when it lands.
|
||||
var/effectStun = FALSE //If true, stuns anyone under the pod when it launches until it lands, forcing them to get hit by the pod. Devilish!
|
||||
var/effectLimb = FALSE //If true, pops off a limb (if applicable) from anyone caught under the pod when it lands
|
||||
@@ -38,7 +38,6 @@
|
||||
var/style = STYLE_STANDARD //Style is a variable that keeps track of what the pod is supposed to look like. It acts as an index to the GLOB.podstyles list in cargo.dm defines to get the proper icon/name/desc for the pod.
|
||||
var/reversing = FALSE //If true, the pod will not send any items. Instead, after opening, it will close again (picking up items/mobs) and fly back to centcom
|
||||
var/list/reverse_dropoff_coords //Turf that the reverse pod will drop off it's newly-acquired cargo to
|
||||
var/fallDuration = 4
|
||||
var/fallingSoundLength = 11
|
||||
var/fallingSound = 'sound/weapons/mortar_long_whistle.ogg'//Admin sound to play before the pod lands
|
||||
var/landingSound //Admin sound to play when the pod lands
|
||||
@@ -57,14 +56,13 @@
|
||||
var/effectShrapnel = FALSE
|
||||
var/shrapnel_type = /obj/item/projectile/bullet/shrapnel
|
||||
var/shrapnel_magnitude = 3
|
||||
var/list/reverseOptionList = list("Mobs"=FALSE,"Objects"=FALSE,"Anchored"=FALSE,"Underfloor"=FALSE,"Wallmounted"=FALSE,"Floors"=FALSE,"Walls"=FALSE)
|
||||
var/list/reverse_option_list = list("Mobs"=FALSE,"Objects"=FALSE,"Anchored"=FALSE,"Underfloor"=FALSE,"Wallmounted"=FALSE,"Floors"=FALSE,"Walls"=FALSE, "Mecha"=FALSE)
|
||||
var/list/turfs_in_cargo = list()
|
||||
|
||||
/obj/structure/closet/supplypod/bluespacepod
|
||||
style = STYLE_BLUESPACE
|
||||
bluespace = TRUE
|
||||
explosionSize = list(0,0,1,2)
|
||||
landingDelay = 15 //Slightly quicker than the supplypod
|
||||
|
||||
/obj/structure/closet/supplypod/extractionpod
|
||||
name = "Syndicate Extraction Pod"
|
||||
@@ -73,16 +71,16 @@
|
||||
style = STYLE_SYNDICATE
|
||||
bluespace = TRUE
|
||||
explosionSize = list(0,0,1,2)
|
||||
landingDelay = 25 //Longer than others
|
||||
delays = list(POD_TRANSIT = 25, POD_FALLING = 4, POD_OPENING = 30, POD_LEAVING = 30)
|
||||
|
||||
/obj/structure/closet/supplypod/centcompod
|
||||
style = STYLE_CENTCOM
|
||||
bluespace = TRUE
|
||||
explosionSize = list(0,0,0,0)
|
||||
landingDelay = 20 //Very speedy!
|
||||
delays = list(POD_TRANSIT = 20, POD_FALLING = 4, POD_OPENING = 30, POD_LEAVING = 30)
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
|
||||
/obj/structure/closet/supplypod/Initialize(var/customStyle = FALSE)
|
||||
/obj/structure/closet/supplypod/Initialize(mapload, customStyle = FALSE)
|
||||
. = ..()
|
||||
if (!loc)
|
||||
var/shippingLane = GLOB.areas_by_type[/area/centcom/supplypod/supplypod_temp_holding] //temporary holder for supplypods mid-transit
|
||||
@@ -212,9 +210,8 @@
|
||||
var/obj/error_landmark = locate(/obj/effect/landmark/error) in GLOB.landmarks_list
|
||||
var/turf/error_landmark_turf = get_turf(error_landmark)
|
||||
reverse_dropoff_coords = list(error_landmark_turf.x, error_landmark_turf.y, error_landmark_turf.z)
|
||||
landingDelay = initial(landingDelay) //Reset the landing timers so we land on whatever turf we're aiming at normally. Will be changed to be editable later (tm)
|
||||
fallDuration = initial(fallDuration) //This is so if someone adds a really long dramatic landing time they don't have to sit through it twice on the pod's return trip
|
||||
openingDelay = initial(openingDelay)
|
||||
if (custom_rev_delay)
|
||||
delays = reverse_delays
|
||||
backToNonReverseIcon()
|
||||
var/turf/return_turf = locate(reverse_dropoff_coords[1], reverse_dropoff_coords[2], reverse_dropoff_coords[3])
|
||||
new /obj/effect/pod_landingzone(return_turf, src)
|
||||
@@ -274,11 +271,11 @@
|
||||
var/mob/living/simple_animal/pet/gondola/gondolapod/benis = new(turf_underneath, src)
|
||||
benis.contents |= contents //Move the contents of this supplypod into the gondolapod mob.
|
||||
moveToNullspace()
|
||||
addtimer(CALLBACK(src, .proc/open_pod, benis), openingDelay) //After the openingDelay passes, we use the open proc from this supplyprod while referencing the contents of the "holder", in this case the gondolapod mob
|
||||
addtimer(CALLBACK(src, .proc/open_pod, benis), delays[POD_OPENING]) //After the opening delay passes, we use the open proc from this supplyprod while referencing the contents of the "holder", in this case the gondolapod mob
|
||||
else if (style == STYLE_SEETHROUGH)
|
||||
open_pod(src)
|
||||
else
|
||||
addtimer(CALLBACK(src, .proc/open_pod, src), openingDelay) //After the openingDelay passes, we use the open proc from this supplypod, while referencing this supplypod's contents
|
||||
addtimer(CALLBACK(src, .proc/open_pod, src), delays[POD_OPENING]) //After the opening delay passes, we use the open proc from this supplypod, while referencing this supplypod's contents
|
||||
|
||||
/obj/structure/closet/supplypod/proc/open_pod(atom/movable/holder, broken = FALSE, forced = FALSE) //The holder var represents an atom whose contents we will be working with
|
||||
if (!holder)
|
||||
@@ -306,9 +303,9 @@
|
||||
startExitSequence(src)
|
||||
else
|
||||
if (reversing)
|
||||
addtimer(CALLBACK(src, .proc/SetReverseIcon), departureDelay/2) //Finish up the pod's duties after a certain amount of time
|
||||
addtimer(CALLBACK(src, .proc/SetReverseIcon), delays[POD_LEAVING]/2) //Finish up the pod's duties after a certain amount of time
|
||||
if(!stay_after_drop) // Departing should be handled manually
|
||||
addtimer(CALLBACK(src, .proc/startExitSequence, holder), departureDelay*(4/5)) //Finish up the pod's duties after a certain amount of time
|
||||
addtimer(CALLBACK(src, .proc/startExitSequence, holder), delays[POD_LEAVING]*(4/5)) //Finish up the pod's duties after a certain amount of time
|
||||
|
||||
/obj/structure/closet/supplypod/proc/startExitSequence(atom/movable/holder)
|
||||
if (leavingSound)
|
||||
@@ -329,7 +326,7 @@
|
||||
take_contents(holder)
|
||||
playsound(holder, close_sound, soundVolume*0.75, TRUE, -3)
|
||||
holder.setClosed()
|
||||
addtimer(CALLBACK(src, .proc/preReturn, holder), departureDelay * 0.2) //Start to leave a bit after closing for cinematic effect
|
||||
addtimer(CALLBACK(src, .proc/preReturn, holder), delays[POD_LEAVING] * 0.2) //Start to leave a bit after closing for cinematic effect
|
||||
|
||||
/obj/structure/closet/supplypod/take_contents(atom/movable/holder)
|
||||
var/turf/turf_underneath = holder.drop_location()
|
||||
@@ -355,7 +352,7 @@
|
||||
if(to_insert.invisibility == INVISIBILITY_ABSTRACT)
|
||||
return FALSE
|
||||
if(ismob(to_insert))
|
||||
if(!reverseOptionList["Mobs"])
|
||||
if(!reverse_option_list["Mobs"])
|
||||
return FALSE
|
||||
if(!isliving(to_insert)) //let's not put ghosts or camera mobs inside
|
||||
return FALSE
|
||||
@@ -374,32 +371,30 @@
|
||||
return FALSE
|
||||
if(istype(obj_to_insert, /obj/effect/supplypod_rubble))
|
||||
return FALSE
|
||||
if(obj_to_insert.level == 1)
|
||||
return FALSE // underfloor, until we get hide components.
|
||||
/*
|
||||
if((obj_to_insert.comp_lookup && obj_to_insert.comp_lookup[COMSIG_OBJ_HIDE]) && reverseOptionList["Underfloor"])
|
||||
// if((obj_to_insert.comp_lookup && obj_to_insert.comp_lookup[COMSIG_OBJ_HIDE]) && reverse_option_list["Underfloor"])
|
||||
// return TRUE
|
||||
// else if ((obj_to_insert.comp_lookup && obj_to_insert.comp_lookup[COMSIG_OBJ_HIDE]) && !reverse_option_list["Underfloor"])
|
||||
// return FALSE
|
||||
if(isProbablyWallMounted(obj_to_insert) && reverse_option_list["Wallmounted"])
|
||||
return TRUE
|
||||
else if ((obj_to_insert.comp_lookup && obj_to_insert.comp_lookup[COMSIG_OBJ_HIDE]) && !reverseOptionList["Underfloor"])
|
||||
else if (isProbablyWallMounted(obj_to_insert) && !reverse_option_list["Wallmounted"])
|
||||
return FALSE
|
||||
*/
|
||||
if(isProbablyWallMounted(obj_to_insert) && reverseOptionList["Wallmounted"])
|
||||
if(!obj_to_insert.anchored && reverse_option_list["Unanchored"])
|
||||
return TRUE
|
||||
else if (isProbablyWallMounted(obj_to_insert) && !reverseOptionList["Wallmounted"])
|
||||
return FALSE
|
||||
if(!obj_to_insert.anchored && reverseOptionList["Unanchored"])
|
||||
if(obj_to_insert.anchored && !ismecha(obj_to_insert) && reverse_option_list["Anchored"]) //Mecha are anchored but there is a separate option for them
|
||||
return TRUE
|
||||
if(obj_to_insert.anchored && reverseOptionList["Anchored"])
|
||||
if(ismecha(obj_to_insert) && reverse_option_list["Mecha"])
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
else if (isturf(to_insert))
|
||||
if(isfloorturf(to_insert) && reverseOptionList["Floors"])
|
||||
if(isfloorturf(to_insert) && reverse_option_list["Floors"])
|
||||
return TRUE
|
||||
if(isfloorturf(to_insert) && !reverseOptionList["Floors"])
|
||||
if(isfloorturf(to_insert) && !reverse_option_list["Floors"])
|
||||
return FALSE
|
||||
if(isclosedturf(to_insert) && reverseOptionList["Walls"])
|
||||
if(isclosedturf(to_insert) && reverse_option_list["Walls"])
|
||||
return TRUE
|
||||
if(isclosedturf(to_insert) && !reverseOptionList["Walls"])
|
||||
if(isclosedturf(to_insert) && !reverse_option_list["Walls"])
|
||||
return FALSE
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -459,10 +454,12 @@
|
||||
if(!glow_effect)
|
||||
return
|
||||
glow_effect.layer = LOW_ITEM_LAYER
|
||||
glow_effect.fadeAway(openingDelay)
|
||||
glow_effect.fadeAway(delays[POD_OPENING])
|
||||
glow_effect = null
|
||||
|
||||
/obj/structure/closet/supplypod/Destroy()
|
||||
deleteRubble()
|
||||
endGlow()
|
||||
open_pod(src, broken = TRUE) //Lets dump our contents by opening up
|
||||
return ..()
|
||||
|
||||
@@ -536,9 +533,9 @@
|
||||
layer = PROJECTILE_HIT_THRESHHOLD_LAYER
|
||||
|
||||
/obj/effect/pod_landingzone_effect/Initialize(mapload, obj/structure/closet/supplypod/pod)
|
||||
. = ..()
|
||||
transform = matrix() * 1.5
|
||||
animate(src, transform = matrix()*0.01, time = pod.landingDelay+pod.fallDuration)
|
||||
..()
|
||||
animate(src, transform = matrix()*0.01, time = pod.delays[POD_TRANSIT]+pod.delays[POD_FALLING])
|
||||
|
||||
/obj/effect/pod_landingzone //This is the object that forceMoves the supplypod to it's location
|
||||
name = "Landing Zone Indicator"
|
||||
@@ -564,11 +561,12 @@
|
||||
if (!pod.effectStealth)
|
||||
helper = new (drop_location(), pod)
|
||||
alpha = 255
|
||||
animate(src, transform = matrix().Turn(90), time = pod.landingDelay+pod.fallDuration)
|
||||
animate(src, transform = matrix().Turn(90), time = pod.delays[POD_TRANSIT]+pod.delays[POD_FALLING])
|
||||
if (single_order)
|
||||
if (istype(single_order, /datum/supply_order))
|
||||
var/datum/supply_order/SO = single_order
|
||||
SO.generate(pod)
|
||||
if (SO.pack.crate_type)
|
||||
SO.generate(pod)
|
||||
else if (istype(single_order, /atom/movable))
|
||||
var/atom/movable/O = single_order
|
||||
O.forceMove(pod)
|
||||
@@ -576,16 +574,16 @@
|
||||
mob_in_pod.reset_perspective(src)
|
||||
if(pod.effectStun) //If effectStun is true, stun any mobs caught on this pod_landingzone until the pod gets a chance to hit them
|
||||
for (var/mob/living/target_living in get_turf(src))
|
||||
target_living.Stun(pod.landingDelay+10, ignore_canstun = TRUE)//you ain't goin nowhere, kid.
|
||||
if (pod.fallDuration == initial(pod.fallDuration) && pod.landingDelay + pod.fallDuration < pod.fallingSoundLength)
|
||||
target_living.Stun(pod.delays[POD_TRANSIT]+10, ignore_canstun = TRUE)//you ain't goin nowhere, kid.
|
||||
if (pod.delays[POD_FALLING] == initial(pod.delays[POD_FALLING]) && pod.delays[POD_TRANSIT] + pod.delays[POD_FALLING] < pod.fallingSoundLength)
|
||||
pod.fallingSoundLength = 3 //The default falling sound is a little long, so if the landing time is shorter than the default falling sound, use a special, shorter default falling sound
|
||||
pod.fallingSound = 'sound/weapons/mortar_whistle.ogg'
|
||||
var/soundStartTime = pod.landingDelay - pod.fallingSoundLength + pod.fallDuration
|
||||
var/soundStartTime = pod.delays[POD_TRANSIT] - pod.fallingSoundLength + pod.delays[POD_FALLING]
|
||||
if (soundStartTime < 0)
|
||||
soundStartTime = 1
|
||||
if (!pod.effectQuiet && !(pod.pod_flags & FIRST_SOUNDS))
|
||||
addtimer(CALLBACK(src, .proc/playFallingSound), soundStartTime)
|
||||
addtimer(CALLBACK(src, .proc/beginLaunch, pod.effectCircle), pod.landingDelay)
|
||||
addtimer(CALLBACK(src, .proc/beginLaunch, pod.effectCircle), pod.delays[POD_TRANSIT])
|
||||
|
||||
/obj/effect/pod_landingzone/proc/playFallingSound()
|
||||
playsound(src, pod.fallingSound, pod.soundVolume, TRUE, 6)
|
||||
@@ -606,9 +604,9 @@
|
||||
pod.transform = matrix().Turn(rotation)
|
||||
pod.layer = FLY_LAYER
|
||||
if (pod.style != STYLE_INVISIBLE)
|
||||
animate(pod.get_filter("motionblur"), y = 0, time = pod.fallDuration, flags = ANIMATION_PARALLEL)
|
||||
animate(pod, pixel_z = -1 * abs(sin(rotation))*4, pixel_x = SUPPLYPOD_X_OFFSET + (sin(rotation) * 20), time = pod.fallDuration, easing = LINEAR_EASING, flags = ANIMATION_PARALLEL) //Make the pod fall! At an angle!
|
||||
addtimer(CALLBACK(src, .proc/endLaunch), pod.fallDuration, TIMER_CLIENT_TIME) //Go onto the last step after a very short falling animation
|
||||
animate(pod.get_filter("motionblur"), y = 0, time = pod.delays[POD_FALLING], flags = ANIMATION_PARALLEL)
|
||||
animate(pod, pixel_z = -1 * abs(sin(rotation))*4, pixel_x = SUPPLYPOD_X_OFFSET + (sin(rotation) * 20), time = pod.delays[POD_FALLING], easing = LINEAR_EASING, flags = ANIMATION_PARALLEL) //Make the pod fall! At an angle!
|
||||
addtimer(CALLBACK(src, .proc/endLaunch), pod.delays[POD_FALLING], TIMER_CLIENT_TIME) //Go onto the last step after a very short falling animation
|
||||
|
||||
/obj/effect/pod_landingzone/proc/setupSmoke(rotation)
|
||||
if (pod.style == STYLE_INVISIBLE || pod.style == STYLE_SEETHROUGH)
|
||||
@@ -622,17 +620,17 @@
|
||||
smoke_effects[i] = smoke_part
|
||||
smoke_part.pixel_x = sin(rotation)*32 * i
|
||||
smoke_part.pixel_y = abs(cos(rotation))*32 * i
|
||||
smoke_part.filters += filter(type = "blur", size = 4)
|
||||
var/time = (pod.fallDuration / length(smoke_effects))*(length(smoke_effects)-i)
|
||||
smoke_part.add_filter("smoke_blur", 1, gauss_blur_filter(size = 4))
|
||||
var/time = (pod.delays[POD_FALLING] / length(smoke_effects))*(length(smoke_effects)-i)
|
||||
addtimer(CALLBACK(smoke_part, /obj/effect/supplypod_smoke/.proc/drawSelf, i), time, TIMER_CLIENT_TIME) //Go onto the last step after a very short falling animation
|
||||
QDEL_IN(smoke_part, pod.fallDuration + 35)
|
||||
QDEL_IN(smoke_part, pod.delays[POD_FALLING] + 35)
|
||||
|
||||
/obj/effect/pod_landingzone/proc/drawSmoke()
|
||||
if (pod.style == STYLE_INVISIBLE || pod.style == STYLE_SEETHROUGH)
|
||||
return
|
||||
for (var/obj/effect/supplypod_smoke/smoke_part in smoke_effects)
|
||||
animate(smoke_part, alpha = 0, time = 20, flags = ANIMATION_PARALLEL)
|
||||
animate(smoke_part.filters[1], size = 6, time = 15, easing = CUBIC_EASING|EASE_OUT, flags = ANIMATION_PARALLEL)
|
||||
animate(smoke_part.get_filter("smoke_blur"), size = 6, time = 15, easing = CUBIC_EASING|EASE_OUT, flags = ANIMATION_PARALLEL)
|
||||
|
||||
/obj/effect/pod_landingzone/proc/endLaunch()
|
||||
pod.tryMakeRubble(drop_location())
|
||||
|
||||
@@ -1007,7 +1007,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
var/mob/living/M = mob
|
||||
M.update_damage_hud()
|
||||
if (prefs.auto_fit_viewport)
|
||||
fit_viewport()
|
||||
addtimer(CALLBACK(src,.verb/fit_viewport,10)) //Delayed to avoid wingets from Login calls.
|
||||
SEND_SIGNAL(mob, COMSIG_MOB_CLIENT_CHANGE_VIEW, src, old_view, actualview)
|
||||
|
||||
/client/proc/generate_clickcatcher()
|
||||
@@ -1048,6 +1048,25 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
/client/proc/can_have_part(part_name)
|
||||
return prefs.pref_species.mutant_bodyparts[part_name] || (part_name in GLOB.unlocked_mutant_parts)
|
||||
|
||||
///Redirect proc that makes it easier to call the unlock achievement proc. Achievement type is the typepath to the award, user is the mob getting the award, and value is an optional variable used for leaderboard value increments
|
||||
/client/proc/give_award(achievement_type, mob/user, value = 1)
|
||||
return player_details.achievements.unlock(achievement_type, user, value)
|
||||
|
||||
///Redirect proc that makes it easier to get the status of an achievement. Achievement type is the typepath to the award.
|
||||
/client/proc/get_award_status(achievement_type, mob/user, value = 1)
|
||||
return player_details.achievements.get_achievement_status(achievement_type)
|
||||
|
||||
///Redirect proc that makes it easier to get the status of an achievement. Achievement type is the typepath to the award.
|
||||
/client/proc/award_heart(heart_reason)
|
||||
to_chat(src, "<span class='nicegreen'>Someone awarded you a heart![heart_reason ? " They said: [heart_reason]!" : ""]</span>")
|
||||
if(!src)
|
||||
return
|
||||
prefs.hearted_until = world.realtime + (24 HOURS)
|
||||
prefs.hearted = TRUE
|
||||
if(!src)
|
||||
return
|
||||
prefs.save_preferences()
|
||||
|
||||
/// compiles a full list of verbs and sends it to the browser
|
||||
/client/proc/init_verbs()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
@@ -1087,3 +1106,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/client/proc/open_filter_editor(atom/in_atom)
|
||||
if(holder)
|
||||
holder.filteriffic = new /datum/filter_editor(in_atom)
|
||||
holder.filteriffic.ui_interact(mob)
|
||||
|
||||
@@ -3,4 +3,21 @@
|
||||
var/list/logging = list()
|
||||
var/list/post_login_callbacks = list()
|
||||
var/list/post_logout_callbacks = list()
|
||||
var/list/played_names = list() //List of names this key played under this round
|
||||
var/byond_version = "Unknown"
|
||||
var/datum/achievement_data/achievements
|
||||
|
||||
/datum/player_details/New(key)
|
||||
achievements = new(key)
|
||||
|
||||
/proc/log_played_names(ckey, ...)
|
||||
if(!ckey)
|
||||
return
|
||||
if(args.len < 2)
|
||||
return
|
||||
var/list/names = args.Copy(2)
|
||||
var/datum/player_details/P = GLOB.player_details[ckey]
|
||||
if(P)
|
||||
for(var/name in names)
|
||||
if(name)
|
||||
P.played_names |= name
|
||||
|
||||
@@ -62,9 +62,15 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/UI_style = null
|
||||
var/buttons_locked = FALSE
|
||||
var/hotkeys = FALSE
|
||||
|
||||
///Runechat preference. If true, certain messages will be displayed on the map, not ust on the chat area. Boolean.
|
||||
var/chat_on_map = TRUE
|
||||
///Limit preference on the size of the message. Requires chat_on_map to have effect.
|
||||
var/max_chat_length = CHAT_MESSAGE_MAX_LENGTH
|
||||
///Whether non-mob messages will be displayed, such as machine vendor announcements. Requires chat_on_map to have effect. Boolean.
|
||||
var/see_chat_non_mob = TRUE
|
||||
///Whether emotes will be displayed on runechat. Requires chat_on_map to have effect. Boolean.
|
||||
var/see_rc_emotes = TRUE
|
||||
|
||||
/// Custom Keybindings
|
||||
var/list/key_bindings = list()
|
||||
@@ -162,13 +168,13 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/auto_fit_viewport = FALSE
|
||||
///Should we be in the widescreen mode set by the config?
|
||||
var/widescreenpref = TRUE
|
||||
|
||||
///What size should pixels be displayed as? 0 is strech to fit
|
||||
var/pixel_size = 0
|
||||
///What scaling method should we use?
|
||||
var/scaling_method = "normal"
|
||||
|
||||
var/uplink_spawn_loc = UPLINK_PDA
|
||||
///The playtime_reward_cloak variable can be set to TRUE from the prefs menu only once the user has gained over 5K playtime hours. If true, it allows the user to get a cool looking roundstart cloak.
|
||||
var/playtime_reward_cloak = FALSE
|
||||
|
||||
var/hud_toggle_flash = TRUE
|
||||
var/hud_toggle_color = "#ffffff"
|
||||
@@ -211,8 +217,17 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/autostand = TRUE
|
||||
var/auto_ooc = FALSE
|
||||
|
||||
///This var stores the amount of points the owner will get for making it out alive.
|
||||
var/hardcore_survival_score = 0
|
||||
|
||||
///Someone thought we were nice! We get a little heart in OOC until we join the server past the below time (we can keep it until the end of the round otherwise)
|
||||
var/hearted
|
||||
///If we have a hearted commendations, we honor it every time the player loads preferences until this time has been passed
|
||||
var/hearted_until
|
||||
/// If we have persistent scars enabled
|
||||
var/persistent_scars = TRUE
|
||||
///If we want to broadcast deadchat connect/disconnect messages
|
||||
var/broadcast_login_logout = TRUE
|
||||
/// We have 5 slots for persistent scars, if enabled we pick a random one to load (empty by default) and scars at the end of the shift if we survived as our original person
|
||||
var/list/scars_list = list("1" = "", "2" = "", "3" = "", "4" = "", "5" = "")
|
||||
/// Which of the 5 persistent scar slots we randomly roll to load for this round, if enabled. Actually rolled in [/datum/preferences/proc/load_character(slot)]
|
||||
@@ -1611,7 +1626,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
for(var/modified_limb in modified_limbs)
|
||||
if(modified_limbs[modified_limb][1] == LOADOUT_LIMB_PROSTHETIC && modified_limb != limb_type)
|
||||
number_of_prosthetics += 1
|
||||
if(number_of_prosthetics > MAXIMUM_LOADOUT_PROSTHETICS)
|
||||
if(number_of_prosthetics == MAXIMUM_LOADOUT_PROSTHETICS)
|
||||
to_chat(user, "<span class='danger'>You can only have up to two prosthetic limbs!</span>")
|
||||
else
|
||||
//save the actual prosthetic data
|
||||
|
||||
@@ -190,11 +190,7 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
|
||||
to_chat(usr, "<span class='notice'>Sorry, tracking is currently disabled.</span>")
|
||||
return
|
||||
|
||||
var/list/body = list()
|
||||
body += "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>Playtime for [key]</title></head><BODY><BR>Playtime:"
|
||||
body += get_exp_report()
|
||||
body += "</BODY></HTML>"
|
||||
usr << browse(body.Join(), "window=playerplaytime[ckey];size=550x615")
|
||||
new /datum/job_report_menu(src, usr)
|
||||
|
||||
/client/proc/ignore_key(client)
|
||||
var/client/C = client
|
||||
@@ -233,7 +229,14 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
|
||||
set category = "OOC"
|
||||
set desc = "View the last round end report you've seen"
|
||||
|
||||
SSticker.show_roundend_report(src, TRUE)
|
||||
SSticker.show_roundend_report(src, report_type = PERSONAL_LAST_ROUND)
|
||||
|
||||
/client/proc/show_servers_last_roundend_report()
|
||||
set name = "Server's Last Round"
|
||||
set category = "OOC"
|
||||
set desc = "View the last round end report from this server"
|
||||
|
||||
SSticker.show_roundend_report(src, report_type = SERVER_LAST_ROUND)
|
||||
|
||||
/client/verb/fit_viewport()
|
||||
set name = "Fit Viewport"
|
||||
@@ -245,8 +248,20 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
|
||||
var/aspect_ratio = view_size[1] / view_size[2]
|
||||
|
||||
// Calculate desired pixel width using window size and aspect ratio
|
||||
var/sizes = params2list(winget(src, "mainwindow.split;mapwindow", "size"))
|
||||
var/map_size = splittext(sizes["mapwindow.size"], "x")
|
||||
var/list/sizes = params2list(winget(src, "mainwindow.split;mapwindow", "size"))
|
||||
|
||||
// Client closed the window? Some other error? This is unexpected behaviour, let's
|
||||
// CRASH with some info.
|
||||
if(!sizes["mapwindow.size"])
|
||||
CRASH("sizes does not contain mapwindow.size key. This means a winget failed to return what we wanted. --- sizes var: [sizes] --- sizes length: [length(sizes)]")
|
||||
|
||||
var/list/map_size = splittext(sizes["mapwindow.size"], "x")
|
||||
|
||||
// Looks like we expect mapwindow.size to be "ixj" where i and j are numbers.
|
||||
// If we don't get our expected 2 outputs, let's give some useful error info.
|
||||
if(length(map_size) != 2)
|
||||
CRASH("map_size of incorrect length --- map_size var: [map_size] --- map_size length: [length(map_size)]")
|
||||
|
||||
var/height = text2num(map_size[2])
|
||||
var/desired_width = round(height * aspect_ratio)
|
||||
if (text2num(map_size[1]) == desired_width)
|
||||
@@ -256,6 +271,9 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
|
||||
var/split_size = splittext(sizes["mainwindow.split.size"], "x")
|
||||
var/split_width = text2num(split_size[1])
|
||||
|
||||
// Avoid auto-resizing the statpanel and chat into nothing.
|
||||
desired_width = min(desired_width, split_width - 300)
|
||||
|
||||
// Calculate and apply a best estimate
|
||||
// +4 pixels are for the width of the splitter's handle
|
||||
var/pct = 100 * (desired_width + 4) / split_width
|
||||
|
||||
@@ -40,11 +40,11 @@
|
||||
if(iscyborg(hit_atom))
|
||||
var/mob/living/silicon/robot/R = hit_atom
|
||||
///hats in the borg's blacklist bounce off
|
||||
if(!is_type_in_typecache(src, R.equippable_hats) || R.hat_offset == INFINITY)
|
||||
R.visible_message("<span class='warning'>[src] bounces off [R]!", "<span class='warning'>[src] bounces off you, falling to the floor.</span>")
|
||||
if(is_type_in_typecache(src, GLOB.blacklisted_borg_hats))
|
||||
R.visible_message("<span class='warning'>[src] bounces off [R]!</span>", "<span class='warning'>[src] bounces off you, falling to the floor.</span>")
|
||||
return
|
||||
else
|
||||
R.visible_message("<span class='notice'>[src] lands neatly on top of [R].", "<span class='notice'>[src] lands perfectly on top of you.</span>")
|
||||
R.visible_message("<span class='notice'>[src] lands neatly on top of [R]!</span>", "<span class='notice'>[src] lands perfectly on top of you.</span>")
|
||||
R.place_on_head(src) //hats aren't designed to snugly fit borg heads or w/e so they'll always manage to knock eachother off
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
if(!is_station_level(H.z))
|
||||
continue
|
||||
traumatize(H)
|
||||
announce_to_ghosts(H)
|
||||
break
|
||||
|
||||
/datum/round_event/brain_trauma/proc/traumatize(mob/living/carbon/human/H)
|
||||
|
||||
@@ -160,6 +160,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
|
||||
wizard.apply_damage(25, BRUTE)
|
||||
qdel(src)
|
||||
else
|
||||
U.client.give_award(/datum/award/achievement/misc/feat_of_strength, U) //rod-form wizards would probably make this a lot easier to get so keep it to regular rods only
|
||||
U.visible_message("<span class='boldwarning'>[U] suplexes [src] into the ground!</span>", "<span class='warning'>You suplex [src] into the ground!</span>")
|
||||
new /obj/structure/festivus/anchored(drop_location())
|
||||
new /obj/effect/anomaly/flux(drop_location())
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/datum/round_event_control/supernova
|
||||
name = "Supernova"
|
||||
typepath = /datum/round_event/supernova
|
||||
weight = 10
|
||||
max_occurrences = 2
|
||||
min_players = 2
|
||||
|
||||
/datum/round_event/supernova
|
||||
announceWhen = 40
|
||||
startWhen = 1
|
||||
endWhen = 300
|
||||
var/power = 1
|
||||
var/datum/sun/supernova
|
||||
var/storm_count = 0
|
||||
|
||||
/datum/round_event/supernova/setup()
|
||||
announceWhen = rand(4, 60)
|
||||
supernova = new
|
||||
SSsun.suns += supernova
|
||||
if(prob(50))
|
||||
power = rand(5,100) / 100
|
||||
else
|
||||
power = rand(5,5000) / 100
|
||||
supernova.azimuth = rand(0, 359)
|
||||
supernova.power_mod = 0
|
||||
|
||||
/datum/round_event/supernova/announce()
|
||||
var/message = "Our tachyon-doppler array has detected a supernova in your vicinity. Peak flux from the supernova estimated to be [round(power,0.1)] times current solar flux. [power > 4 ? "Short burts of radiation may be possible, so please prepare accordingly." : ""]"
|
||||
if(prob(power * 25))
|
||||
priority_announce(message)
|
||||
else
|
||||
print_command_report(message)
|
||||
|
||||
|
||||
/datum/round_event/supernova/start()
|
||||
supernova.power_mod = 0.00000002 * power
|
||||
var/explosion_size = rand(1000000000, 999999999)
|
||||
var/turf/epicenter = get_turf_in_angle(supernova.azimuth, SSmapping.get_station_center(), world.maxx / 2)
|
||||
for(var/array in GLOB.doppler_arrays)
|
||||
var/obj/machinery/doppler_array/A = array
|
||||
A.sense_explosion(epicenter, explosion_size/2, explosion_size, 0, 107000000 / power, explosion_size/2, explosion_size, 0)
|
||||
if(power > 1 && SSticker.mode.bloodsucker_sunlight?.time_til_cycle > 90)
|
||||
var/obj/effect/sunlight/sucker_light = SSticker.mode.bloodsucker_sunlight
|
||||
sucker_light.time_til_cycle = 90
|
||||
sucker_light.warn_daylight(1,"<span class = 'danger'>A supernova will bombard the station with dangerous UV in [90 / 60] minutes. <b>Prepare to seek cover in a coffin or closet.</b></span>")
|
||||
sucker_light.give_home_power()
|
||||
|
||||
/datum/round_event/supernova/tick()
|
||||
var/midpoint = (endWhen-startWhen)/2
|
||||
switch(activeFor)
|
||||
if(startWhen to midpoint)
|
||||
supernova.power_mod = min(supernova.power_mod*1.2, power)
|
||||
if(endWhen-10 to endWhen)
|
||||
supernova.power_mod /= 4
|
||||
if(prob(round(supernova.power_mod / 2)) && storm_count < 3 && !SSweather.get_weather_by_type(/datum/weather/rad_storm))
|
||||
SSweather.run_weather(/datum/weather/rad_storm/supernova)
|
||||
storm_count++
|
||||
|
||||
/datum/round_event/supernova/end()
|
||||
SSsun.suns -= supernova
|
||||
qdel(supernova)
|
||||
|
||||
/datum/weather/rad_storm/supernova
|
||||
weather_duration_lower = 50
|
||||
weather_duration_lower = 100
|
||||
telegraph_duration = 100
|
||||
radiation_intensity = 50
|
||||
@@ -492,7 +492,9 @@
|
||||
playsound(user.loc,'sound/weapons/pierce.ogg', rand(10,50), 1)
|
||||
var/obj/item/trash/can/crushed_can = new /obj/item/trash/can(user.loc)
|
||||
crushed_can.icon_state = icon_state
|
||||
qdel(src)
|
||||
M.dropItemToGround(src)
|
||||
M.put_in_active_hand(crushed_can)
|
||||
return qdel(src)
|
||||
..()
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/soda_cans/attack_self(mob/user)
|
||||
|
||||
@@ -156,11 +156,7 @@
|
||||
/obj/machinery/processor/slime
|
||||
name = "slime processor"
|
||||
desc = "An industrial grinder with a sticker saying appropriated for science department. Keep hands clear of intake area while operating."
|
||||
|
||||
/obj/machinery/processor/slime/Initialize()
|
||||
. = ..()
|
||||
var/obj/item/circuitboard/machine/B = new /obj/item/circuitboard/machine/processor/slime(null)
|
||||
B.apply_default_parts(src)
|
||||
circuit = /obj/item/circuitboard/machine/processor/slime
|
||||
|
||||
/obj/machinery/processor/slime/adjust_item_drop_location(atom/movable/AM)
|
||||
var/static/list/slimecores = subtypesof(/obj/item/slime_extract)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
active_power_usage = 100
|
||||
circuit = /obj/item/circuitboard/machine/smartfridge
|
||||
|
||||
var/base_build_path = /obj/machinery/smartfridge ///What path boards used to construct it should build into when dropped. Needed so we don't accidentally have them build variants with items preloaded in them.
|
||||
var/max_n_of_items = 1500
|
||||
var/allow_ai_retrieve = FALSE
|
||||
var/list/initial_contents
|
||||
@@ -43,7 +44,7 @@
|
||||
SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
|
||||
if(!stat)
|
||||
SSvis_overlays.add_vis_overlay(src, icon, "smartfridge-light-mask", EMISSIVE_LAYER, EMISSIVE_PLANE, dir, alpha)
|
||||
if(visible_contents)
|
||||
if (visible_contents)
|
||||
switch(contents.len)
|
||||
if(0)
|
||||
icon_state = "[initial(icon_state)]"
|
||||
@@ -111,10 +112,10 @@
|
||||
if(loaded)
|
||||
if(contents.len >= max_n_of_items)
|
||||
user.visible_message("<span class='notice'>[user] loads \the [src] with \the [O].</span>", \
|
||||
"<span class='notice'>You fill \the [src] with \the [O].</span>")
|
||||
"<span class='notice'>You fill \the [src] with \the [O].</span>")
|
||||
else
|
||||
user.visible_message("<span class='notice'>[user] loads \the [src] with \the [O].</span>", \
|
||||
"<span class='notice'>You load \the [src] with \the [O].</span>")
|
||||
"<span class='notice'>You load \the [src] with \the [O].</span>")
|
||||
if(O.contents.len > 0)
|
||||
to_chat(user, "<span class='warning'>Some items are refused.</span>")
|
||||
if (visible_contents)
|
||||
@@ -172,6 +173,10 @@
|
||||
|
||||
var/listofitems = list()
|
||||
for (var/I in src)
|
||||
// We do not vend our own components.
|
||||
if(I in component_parts)
|
||||
continue
|
||||
|
||||
var/atom/movable/O = I
|
||||
if (!QDELETED(O))
|
||||
var/md5name = md5(O.name) // This needs to happen because of a bug in a TGUI component, https://github.com/ractivejs/ractive/issues/744
|
||||
@@ -212,6 +217,8 @@
|
||||
if(desired == 1 && Adjacent(usr) && !issilicon(usr))
|
||||
for(var/obj/item/O in src)
|
||||
if(O.name == params["name"])
|
||||
if(O in component_parts)
|
||||
CRASH("Attempted removal of [O] component_part from vending machine via vending interface.")
|
||||
dispense(O, usr)
|
||||
break
|
||||
if (visible_contents)
|
||||
@@ -222,6 +229,8 @@
|
||||
if(desired <= 0)
|
||||
break
|
||||
if(O.name == params["name"])
|
||||
if(O in component_parts)
|
||||
CRASH("Attempted removal of [O] component_part from vending machine via vending interface.")
|
||||
dispense(O, usr)
|
||||
desired--
|
||||
if (visible_contents)
|
||||
@@ -242,13 +251,21 @@
|
||||
idle_power_usage = 5
|
||||
active_power_usage = 200
|
||||
visible_contents = FALSE
|
||||
base_build_path = /obj/machinery/smartfridge/drying_rack //should really be seeing this without admin fuckery.
|
||||
var/drying = FALSE
|
||||
|
||||
/obj/machinery/smartfridge/drying_rack/Initialize()
|
||||
. = ..()
|
||||
if(component_parts && component_parts.len)
|
||||
component_parts.Cut()
|
||||
|
||||
// Cache the old_parts first, we'll delete it after we've changed component_parts to a new list.
|
||||
// This stops handle_atom_del being called on every part when not necessary.
|
||||
var/list/old_parts = component_parts.Copy()
|
||||
|
||||
component_parts = null
|
||||
circuit = null
|
||||
|
||||
QDEL_LIST(old_parts)
|
||||
RefreshParts()
|
||||
|
||||
/obj/machinery/smartfridge/drying_rack/on_deconstruction()
|
||||
new /obj/item/stack/sheet/mineral/wood(drop_location(), 10)
|
||||
@@ -282,25 +299,18 @@
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// /obj/machinery/smartfridge/drying_rack/powered() do we have this? no.
|
||||
// if(!anchored)
|
||||
// return FALSE
|
||||
// return ..()
|
||||
/obj/machinery/smartfridge/drying_rack/powered()
|
||||
if(!anchored)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/machinery/smartfridge/drying_rack/power_change()
|
||||
if(powered() && anchored)
|
||||
stat &= ~NOPOWER
|
||||
else
|
||||
stat |= NOPOWER
|
||||
. = ..()
|
||||
if(!powered())
|
||||
toggle_drying(TRUE)
|
||||
update_icon()
|
||||
|
||||
// . = ..()
|
||||
// if(!powered())
|
||||
// toggle_drying(TRUE)
|
||||
|
||||
/obj/machinery/smartfridge/drying_rack/load() //For updating the filled overlay
|
||||
..()
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/smartfridge/drying_rack/update_overlays()
|
||||
@@ -365,6 +375,7 @@
|
||||
/obj/machinery/smartfridge/drinks
|
||||
name = "drink showcase"
|
||||
desc = "A refrigerated storage unit for tasty tasty alcohol."
|
||||
base_build_path = /obj/machinery/smartfridge/drinks
|
||||
|
||||
/obj/machinery/smartfridge/drinks/accept_check(obj/item/O)
|
||||
if(!istype(O, /obj/item/reagent_containers) || (O.item_flags & ABSTRACT) || !O.reagents || !O.reagents.reagent_list.len)
|
||||
@@ -377,6 +388,7 @@
|
||||
// ----------------------------
|
||||
/obj/machinery/smartfridge/food
|
||||
desc = "A refrigerated storage unit for food."
|
||||
base_build_path = /obj/machinery/smartfridge/food
|
||||
|
||||
/obj/machinery/smartfridge/food/accept_check(obj/item/O)
|
||||
if(istype(O, /obj/item/reagent_containers/food/snacks/))
|
||||
@@ -389,6 +401,7 @@
|
||||
/obj/machinery/smartfridge/extract
|
||||
name = "smart slime extract storage"
|
||||
desc = "A refrigerated storage unit for slime extracts."
|
||||
base_build_path = /obj/machinery/smartfridge/extract
|
||||
|
||||
/obj/machinery/smartfridge/extract/accept_check(obj/item/O)
|
||||
if(istype(O, /obj/item/slime_extract))
|
||||
@@ -407,6 +420,7 @@
|
||||
name = "smart organ storage"
|
||||
desc = "A refrigerated storage unit for organ storage."
|
||||
max_n_of_items = 20 //vastly lower to prevent processing too long
|
||||
base_build_path = /obj/machinery/smartfridge/organ
|
||||
var/repair_rate = 0
|
||||
|
||||
/obj/machinery/smartfridge/organ/accept_check(obj/item/O)
|
||||
@@ -431,14 +445,14 @@
|
||||
/obj/machinery/smartfridge/organ/RefreshParts()
|
||||
for(var/obj/item/stock_parts/matter_bin/B in component_parts)
|
||||
max_n_of_items = 20 * B.rating
|
||||
repair_rate = max(0, STANDARD_ORGAN_HEALING * (B.rating - 1))
|
||||
repair_rate = max(0, STANDARD_ORGAN_HEALING * (B.rating - 1) * 0.5)
|
||||
|
||||
/obj/machinery/smartfridge/organ/process()
|
||||
/obj/machinery/smartfridge/organ/process(delta_time)
|
||||
for(var/organ in contents)
|
||||
var/obj/item/organ/O = organ
|
||||
if(!istype(O))
|
||||
return
|
||||
O.applyOrganDamage(-repair_rate)
|
||||
O.applyOrganDamage(-repair_rate * delta_time)
|
||||
|
||||
/obj/machinery/smartfridge/organ/Exited(atom/movable/AM, atom/newLoc)
|
||||
. = ..()
|
||||
@@ -446,7 +460,9 @@
|
||||
var/obj/item/organ/O = AM
|
||||
O.organ_flags &= ~ORGAN_FROZEN
|
||||
|
||||
/obj/machinery/smartfridge/organ/preloaded //cit specific??????
|
||||
//cit specific??????
|
||||
/obj/machinery/smartfridge/organ/preloaded
|
||||
base_build_path = /obj/machinery/smartfridge/organ/preloaded
|
||||
initial_contents = list(
|
||||
/obj/item/reagent_containers/medspray/synthtissue = 1,
|
||||
/obj/item/reagent_containers/medspray/sterilizine = 1)
|
||||
@@ -463,6 +479,7 @@
|
||||
/obj/machinery/smartfridge/chemistry
|
||||
name = "smart chemical storage"
|
||||
desc = "A refrigerated storage unit for medicine storage."
|
||||
base_build_path = /obj/machinery/smartfridge/chemistry
|
||||
|
||||
/obj/machinery/smartfridge/chemistry/accept_check(obj/item/O)
|
||||
var/static/list/chemfridge_typecache = typecacheof(list(
|
||||
@@ -504,6 +521,7 @@
|
||||
/obj/machinery/smartfridge/chemistry/virology
|
||||
name = "smart virus storage"
|
||||
desc = "A refrigerated storage unit for volatile sample storage."
|
||||
base_build_path = /obj/machinery/smartfridge/chemistry/virology
|
||||
|
||||
/obj/machinery/smartfridge/chemistry/virology/preloaded
|
||||
initial_contents = list(
|
||||
@@ -525,6 +543,7 @@
|
||||
icon_state = "disktoaster"
|
||||
pass_flags = PASSTABLE
|
||||
visible_contents = FALSE
|
||||
base_build_path = /obj/machinery/smartfridge/disks
|
||||
|
||||
/obj/machinery/smartfridge/disks/accept_check(obj/item/O)
|
||||
if(istype(O, /obj/item/disk/))
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#define JOB_REPORT_MENU_FAIL_REASON_TRACKING_DISABLED 1
|
||||
#define JOB_REPORT_MENU_FAIL_REASON_NO_RECORDS 2
|
||||
|
||||
/datum/job_report_menu
|
||||
var/client/owner
|
||||
|
||||
/datum/job_report_menu/New(client/owner, mob/viewer)
|
||||
src.owner = owner
|
||||
ui_interact(viewer)
|
||||
|
||||
/datum/job_report_menu/ui_state()
|
||||
return GLOB.always_state
|
||||
|
||||
/datum/job_report_menu/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if (!ui)
|
||||
ui = new(user, src, "TrackedPlaytime")
|
||||
ui.open()
|
||||
|
||||
/datum/job_report_menu/ui_static_data()
|
||||
if (!CONFIG_GET(flag/use_exp_tracking))
|
||||
return list("failReason" = JOB_REPORT_MENU_FAIL_REASON_TRACKING_DISABLED)
|
||||
|
||||
var/list/play_records = owner.prefs.exp
|
||||
if (!play_records.len)
|
||||
owner.set_exp_from_db()
|
||||
play_records = owner.prefs.exp
|
||||
if (!play_records.len)
|
||||
return list("failReason" = JOB_REPORT_MENU_FAIL_REASON_NO_RECORDS)
|
||||
|
||||
var/list/data = list()
|
||||
data["jobPlaytimes"] = list()
|
||||
data["specialPlaytimes"] = list()
|
||||
|
||||
for (var/job_name in SSjob.name_occupations)
|
||||
var/playtime = play_records[job_name] ? text2num(play_records[job_name]) : 0
|
||||
data["jobPlaytimes"][job_name] = playtime
|
||||
|
||||
for (var/special_name in GLOB.exp_specialmap[EXP_TYPE_SPECIAL])
|
||||
var/playtime = play_records[special_name] ? text2num(play_records[special_name]) : 0
|
||||
data["specialPlaytimes"][special_name] = playtime
|
||||
|
||||
data["livingTime"] = play_records[EXP_TYPE_LIVING]
|
||||
data["ghostTime"] = play_records[EXP_TYPE_GHOST]
|
||||
|
||||
return data
|
||||
|
||||
#undef JOB_REPORT_MENU_FAIL_REASON_TRACKING_DISABLED
|
||||
#undef JOB_REPORT_MENU_FAIL_REASON_NO_RECORDS
|
||||
@@ -4,7 +4,7 @@
|
||||
department_head = list("Chief Medical Officer")
|
||||
department_flag = MEDSCI
|
||||
faction = "Station"
|
||||
total_positions = 3
|
||||
total_positions = 2
|
||||
spawn_positions = 2
|
||||
supervisors = "the chief medical officer"
|
||||
selection_color = "#74b5e0"
|
||||
|
||||
+190
-176
@@ -1,21 +1,21 @@
|
||||
|
||||
|
||||
/**
|
||||
* The mafia controller handles the mafia minigame in progress.
|
||||
* It is first created when the first ghost signs up to play.
|
||||
*/
|
||||
* The mafia controller handles the mafia minigame in progress.
|
||||
* It is first created when the first ghost signs up to play.
|
||||
*/
|
||||
/datum/mafia_controller
|
||||
///list of observers that should get game updates.
|
||||
var/list/spectators = list()
|
||||
///all roles in the game, dead or alive. check their game status if you only want living or dead.
|
||||
var/list/all_roles = list()
|
||||
///exists to speed up role retrieval, it's a dict. player_role_lookup[player ckey] will give you the role they play
|
||||
///exists to speed up role retrieval, it's a dict. `player_role_lookup[player ckey]` will give you the role they play
|
||||
var/list/player_role_lookup = list()
|
||||
///what part of the game you're playing in. day phases, night phases, judgement phases, etc.
|
||||
var/phase = MAFIA_PHASE_SETUP
|
||||
///how long the game has gone on for, changes with every sunrise. day one, night one, day two, etc.
|
||||
var/turn = 0
|
||||
///for debugging and testing a full game, or adminbuse. If this is not null, it will use this as a setup. clears when game is over
|
||||
///for debugging and testing a full game, or adminbuse. If this is not empty, it will use this as a setup. clears when game is over
|
||||
var/list/custom_setup = list()
|
||||
///first day has no voting, and thus is shorter
|
||||
var/first_day_phase_period = 20 SECONDS
|
||||
@@ -82,20 +82,20 @@
|
||||
qdel(map_deleter)
|
||||
|
||||
/**
|
||||
* Triggers at beginning of the game when there is a confirmed list of valid, ready players.
|
||||
* Creates a 100% ready game that has NOT started (no players in bodies)
|
||||
* Followed by start game
|
||||
*
|
||||
* Does the following:
|
||||
* * Picks map, and loads it
|
||||
* * Grabs landmarks if it is the first time it's loading
|
||||
* * Sets up the role list
|
||||
* * Puts players in each role randomly
|
||||
* Arguments:
|
||||
* * setup_list: list of all the datum setups (fancy list of roles) that would work for the game
|
||||
* * ready_players: list of filtered, sane players (so not playing or disconnected) for the game to put into roles
|
||||
*/
|
||||
/datum/mafia_controller/proc/prepare_game(setup_list, ready_players)
|
||||
* Triggers at beginning of the game when there is a confirmed list of valid, ready players.
|
||||
* Creates a 100% ready game that has NOT started (no players in bodies)
|
||||
* Followed by start game
|
||||
*
|
||||
* Does the following:
|
||||
* * Picks map, and loads it
|
||||
* * Grabs landmarks if it is the first time it's loading
|
||||
* * Sets up the role list
|
||||
* * Puts players in each role randomly
|
||||
* Arguments:
|
||||
* * setup_list: list of all the datum setups (fancy list of roles) that would work for the game
|
||||
* * ready_players: list of filtered, sane players (so not playing or disconnected) for the game to put into roles
|
||||
*/
|
||||
/datum/mafia_controller/proc/prepare_game(setup_list,ready_players)
|
||||
|
||||
var/list/possible_maps = subtypesof(/datum/map_template/mafia)
|
||||
var/turf/spawn_area = get_turf(locate(/obj/effect/landmark/mafia_game_area) in GLOB.landmarks_list)
|
||||
@@ -166,23 +166,23 @@
|
||||
to_chat(M, "[link] MAFIA: [msg] [team_suffix]")
|
||||
|
||||
/**
|
||||
* The game by this point is now all set up, and so we can put people in their bodies and start the first phase.
|
||||
*
|
||||
* Does the following:
|
||||
* * Creates bodies for all of the roles with the first proc
|
||||
* * Starts the first day manually (so no timer) with the second proc
|
||||
*/
|
||||
* The game by this point is now all set up, and so we can put people in their bodies and start the first phase.
|
||||
*
|
||||
* Does the following:
|
||||
* * Creates bodies for all of the roles with the first proc
|
||||
* * Starts the first day manually (so no timer) with the second proc
|
||||
*/
|
||||
/datum/mafia_controller/proc/start_game()
|
||||
create_bodies()
|
||||
start_day()
|
||||
|
||||
/**
|
||||
* How every day starts.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * If day one, just a small starting period to see who is in the game and check role, leading to the night phase.
|
||||
* * Otherwise, it's a longer period used to discuss events that happened during the night, leading to the voting phase.
|
||||
*/
|
||||
* How every day starts.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * If day one, just a small starting period to see who is in the game and check role, leading to the night phase.
|
||||
* * Otherwise, it's a longer period used to discuss events that happened during the night, leading to the voting phase.
|
||||
*/
|
||||
/datum/mafia_controller/proc/start_day()
|
||||
turn += 1
|
||||
phase = MAFIA_PHASE_DAY
|
||||
@@ -198,12 +198,12 @@
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/**
|
||||
* Players have finished the discussion period, and now must put up someone to the chopping block.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * Vote on which player to put up for lynching, leading to the judgement phase.
|
||||
* * If no votes are case, the judgement phase is skipped, leading to the night phase.
|
||||
*/
|
||||
* Players have finished the discussion period, and now must put up someone to the chopping block.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * Vote on which player to put up for lynching, leading to the judgement phase.
|
||||
* * If no votes are case, the judgement phase is skipped, leading to the night phase.
|
||||
*/
|
||||
/datum/mafia_controller/proc/start_voting_phase()
|
||||
phase = MAFIA_PHASE_VOTING
|
||||
next_phase_timer = addtimer(CALLBACK(src, .proc/check_trial, TRUE),voting_phase_period,TIMER_STOPPABLE) //be verbose!
|
||||
@@ -211,21 +211,21 @@
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/**
|
||||
* Players have voted someone up, and now the person must defend themselves while the town votes innocent or guilty.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * Vote innocent or guilty, if they are not on trial.
|
||||
* * Defend themselves and wait for judgement, if they are.
|
||||
* * Leads to the lynch phase.
|
||||
* Arguments:
|
||||
* * verbose: boolean, announces whether there were votes or not. after judgement it goes back here with no voting period to end the day.
|
||||
*/
|
||||
* Players have voted someone up, and now the person must defend themselves while the town votes innocent or guilty.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * Vote innocent or guilty, if they are not on trial.
|
||||
* * Defend themselves and wait for judgement, if they are.
|
||||
* * Leads to the lynch phase.
|
||||
* Arguments:
|
||||
* * verbose: boolean, announces whether there were votes or not. after judgement it goes back here with no voting period to end the day.
|
||||
*/
|
||||
/datum/mafia_controller/proc/check_trial(verbose = TRUE)
|
||||
var/datum/mafia_role/loser = get_vote_winner("Day")//, majority_of_town = TRUE)
|
||||
// var/loser_votes = get_vote_count(loser,"Day")
|
||||
var/loser_votes = get_vote_count(loser,"Day")
|
||||
if(loser)
|
||||
// if(loser_votes > 12)
|
||||
// loser.body.client?.give_award(/datum/award/achievement/mafia/universally_hated, loser.body)
|
||||
if(loser_votes > 12)
|
||||
award_role(/datum/award/achievement/mafia/universally_hated, loser)
|
||||
send_message("<b>[loser.body.real_name] wins the day vote, Listen to their defense and vote \"INNOCENT\" or \"GUILTY\"!</b>")
|
||||
//refresh the lists
|
||||
judgement_abstain_votes = list()
|
||||
@@ -248,12 +248,12 @@
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/**
|
||||
* Players have voted innocent or guilty on the person on trial, and that person is now killed or returned home.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * r/watchpeopledie
|
||||
* * If the accused is killed, their true role is revealed to the rest of the players.
|
||||
*/
|
||||
* Players have voted innocent or guilty on the person on trial, and that person is now killed or returned home.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * r/watchpeopledie
|
||||
* * If the accused is killed, their true role is revealed to the rest of the players.
|
||||
*/
|
||||
/datum/mafia_controller/proc/lynch()
|
||||
for(var/i in judgement_innocent_votes)
|
||||
var/datum/mafia_role/role = i
|
||||
@@ -276,25 +276,25 @@
|
||||
next_phase_timer = addtimer(CALLBACK(src, .proc/check_trial, FALSE),judgement_lynch_period,TIMER_STOPPABLE)// small pause to see the guy dead, no verbosity since we already did this
|
||||
|
||||
/**
|
||||
* Teenie helper proc to move players back to their home.
|
||||
* Used in the above, but also used in the debug button "send all players home"
|
||||
* Arguments:
|
||||
* * role: mafia role that is getting sent back to the game.
|
||||
*/
|
||||
* Teenie helper proc to move players back to their home.
|
||||
* Used in the above, but also used in the debug button "send all players home"
|
||||
* Arguments:
|
||||
* * role: mafia role that is getting sent back to the game.
|
||||
*/
|
||||
/datum/mafia_controller/proc/send_home(datum/mafia_role/role)
|
||||
role.body.forceMove(get_turf(role.assigned_landmark))
|
||||
|
||||
/**
|
||||
* Checks to see if a faction (or solo antagonist) has won.
|
||||
*
|
||||
* Calculates in this order:
|
||||
* * counts up town, mafia, and solo
|
||||
* * solos can count as town members for the purposes of mafia winning
|
||||
* * sends the amount of living people to the solo antagonists, and see if they won OR block the victory of the teams
|
||||
* * checks if solos won from above, then if town, then if mafia
|
||||
* * starts the end of the game if a faction won
|
||||
* * returns TRUE if someone won the game, halting other procs from continuing in the case of a victory
|
||||
*/
|
||||
* Checks to see if a faction (or solo antagonist) has won.
|
||||
*
|
||||
* Calculates in this order:
|
||||
* * counts up town, mafia, and solo
|
||||
* * solos can count as town members for the purposes of mafia winning
|
||||
* * sends the amount of living people to the solo antagonists, and see if they won OR block the victory of the teams
|
||||
* * checks if solos won from above, then if town, then if mafia
|
||||
* * starts the end of the game if a faction won
|
||||
* * returns TRUE if someone won the game, halting other procs from continuing in the case of a victory
|
||||
*/
|
||||
/datum/mafia_controller/proc/check_victory()
|
||||
//needed for achievements
|
||||
var/list/total_town = list()
|
||||
@@ -336,8 +336,7 @@
|
||||
var/solo_end = FALSE
|
||||
for(var/datum/mafia_role/winner in total_victors)
|
||||
send_message("<span class='big comradio'>!! [uppertext(winner.name)] VICTORY !!</span>")
|
||||
// var/client/winner_client = GLOB.directory[winner.player_key]
|
||||
// winner_client?.give_award(winner.winner_award, winner.body)
|
||||
award_role(winner.winner_award, winner)
|
||||
solo_end = TRUE
|
||||
if(solo_end)
|
||||
start_the_end()
|
||||
@@ -345,28 +344,39 @@
|
||||
if(blocked_victory)
|
||||
return FALSE
|
||||
if(alive_mafia == 0)
|
||||
// for(var/datum/mafia_role/townie in total_town)
|
||||
// var/client/townie_client = GLOB.directory[townie.player_key]
|
||||
// townie_client?.give_award(townie.winner_award, townie.body)
|
||||
for(var/datum/mafia_role/townie in total_town)
|
||||
award_role(townie.winner_award, townie)
|
||||
start_the_end("<span class='big green'>!! TOWN VICTORY !!</span>")
|
||||
return TRUE
|
||||
else if(alive_mafia >= alive_town) //guess could change if town nightkill is added
|
||||
start_the_end("<span class='big red'>!! MAFIA VICTORY !!</span>")
|
||||
// for(var/datum/mafia_role/changeling in total_mafia)
|
||||
// var/client/changeling_client = GLOB.directory[changeling.player_key]
|
||||
// changeling_client?.give_award(changeling.winner_award, changeling.body)
|
||||
for(var/datum/mafia_role/changeling in total_mafia)
|
||||
award_role(changeling.winner_award, changeling)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* The end of the game is in two procs, because we want a bit of time for players to see eachothers roles.
|
||||
* Because of how check_victory works, the game is halted in other places by this point.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * See everyone's role postgame
|
||||
* * See who won the game
|
||||
* Arguments:
|
||||
* * message: string, if non-null it sends it to all players. used to announce team victories while solos are handled in check victory
|
||||
*/
|
||||
* Lets the game award roles with all their checks and sanity, prevents achievements given out for debug games
|
||||
*
|
||||
* Arguments:
|
||||
* * award: path of the award
|
||||
* * role: mafia_role datum to reward.
|
||||
*/
|
||||
/datum/mafia_controller/proc/award_role(award, datum/mafia_role/rewarded)
|
||||
if(custom_setup.len)
|
||||
return
|
||||
var/client/role_client = GLOB.directory[rewarded.player_key]
|
||||
role_client?.give_award(award, rewarded.body)
|
||||
|
||||
/**
|
||||
* The end of the game is in two procs, because we want a bit of time for players to see eachothers roles.
|
||||
* Because of how check_victory works, the game is halted in other places by this point.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * See everyone's role postgame
|
||||
* * See who won the game
|
||||
* Arguments:
|
||||
* * message: string, if non-null it sends it to all players. used to announce team victories while solos are handled in check victory
|
||||
*/
|
||||
/datum/mafia_controller/proc/start_the_end(message)
|
||||
SEND_SIGNAL(src,COMSIG_MAFIA_GAME_END)
|
||||
if(message)
|
||||
@@ -377,8 +387,8 @@
|
||||
next_phase_timer = addtimer(CALLBACK(src,.proc/end_game),victory_lap_period,TIMER_STOPPABLE)
|
||||
|
||||
/**
|
||||
* Cleans up the game, resetting variables back to the beginning and removing the map with the generator.
|
||||
*/
|
||||
* Cleans up the game, resetting variables back to the beginning and removing the map with the generator.
|
||||
*/
|
||||
/datum/mafia_controller/proc/end_game()
|
||||
map_deleter.generate() //remove the map, it will be loaded at the start of the next one
|
||||
QDEL_LIST(all_roles)
|
||||
@@ -392,17 +402,17 @@
|
||||
phase = MAFIA_PHASE_SETUP
|
||||
|
||||
/**
|
||||
* After the voting and judgement phases, the game goes to night shutting the windows and beginning night with a proc.
|
||||
*/
|
||||
* After the voting and judgement phases, the game goes to night shutting the windows and beginning night with a proc.
|
||||
*/
|
||||
/datum/mafia_controller/proc/lockdown()
|
||||
toggle_night_curtains(close=TRUE)
|
||||
start_night()
|
||||
|
||||
/**
|
||||
* Shuts poddoors attached to mafia.
|
||||
* Arguments:
|
||||
* * close: boolean, the state you want the curtains in.
|
||||
*/
|
||||
* Shuts poddoors attached to mafia.
|
||||
* Arguments:
|
||||
* * close: boolean, the state you want the curtains in.
|
||||
*/
|
||||
/datum/mafia_controller/proc/toggle_night_curtains(close)
|
||||
for(var/obj/machinery/door/poddoor/D in GLOB.machines) //I really dislike pathing of these
|
||||
if(D.id != "mafia") //so as to not trigger shutters on station, lol
|
||||
@@ -413,12 +423,12 @@
|
||||
INVOKE_ASYNC(D, /obj/machinery/door/poddoor.proc/open)
|
||||
|
||||
/**
|
||||
* The actual start of night for players. Mostly info is given at the start of the night as the end of the night is when votes and actions are submitted and tried.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * Mafia are told to begin voting on who to kill
|
||||
* * Powers that are picked during the day announce themselves right now
|
||||
*/
|
||||
* The actual start of night for players. Mostly info is given at the start of the night as the end of the night is when votes and actions are submitted and tried.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * Mafia are told to begin voting on who to kill
|
||||
* * Powers that are picked during the day announce themselves right now
|
||||
*/
|
||||
/datum/mafia_controller/proc/start_night()
|
||||
phase = MAFIA_PHASE_NIGHT
|
||||
send_message("<b>Night [turn] started! Lockdown will end in 45 seconds.</b>")
|
||||
@@ -427,16 +437,16 @@
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/**
|
||||
* The end of the night, and a series of signals for the order of events on a night.
|
||||
*
|
||||
* Order of events, and what they mean:
|
||||
* * Start of resolve (NIGHT_START) is for activating night abilities that MUST go first
|
||||
* * Action phase (NIGHT_ACTION_PHASE) is for non-lethal day abilities
|
||||
* * Mafia then tallies votes and kills the highest voted person (note: one random voter visits that person for the purposes of roleblocking)
|
||||
* * Killing phase (NIGHT_KILL_PHASE) is for lethal night abilities
|
||||
* * End of resolve (NIGHT_END) is for cleaning up abilities that went off and i guess doing some that must go last
|
||||
* * Finally opens the curtains and calls the start of day phase, completing the cycle until check victory returns TRUE
|
||||
*/
|
||||
* The end of the night, and a series of signals for the order of events on a night.
|
||||
*
|
||||
* Order of events, and what they mean:
|
||||
* * Start of resolve (NIGHT_START) is for activating night abilities that MUST go first
|
||||
* * Action phase (NIGHT_ACTION_PHASE) is for non-lethal day abilities
|
||||
* * Mafia then tallies votes and kills the highest voted person (note: one random voter visits that person for the purposes of roleblocking)
|
||||
* * Killing phase (NIGHT_KILL_PHASE) is for lethal night abilities
|
||||
* * End of resolve (NIGHT_END) is for cleaning up abilities that went off and i guess doing some that must go last
|
||||
* * Finally opens the curtains and calls the start of day phase, completing the cycle until check victory returns TRUE
|
||||
*/
|
||||
/datum/mafia_controller/proc/resolve_night()
|
||||
SEND_SIGNAL(src,COMSIG_MAFIA_NIGHT_START)
|
||||
SEND_SIGNAL(src,COMSIG_MAFIA_NIGHT_ACTION_PHASE)
|
||||
@@ -457,15 +467,15 @@
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/**
|
||||
* Proc that goes off when players vote for something with their mafia panel.
|
||||
*
|
||||
* If teams, it hides the tally overlay and only sends the vote messages to the team that is voting
|
||||
* Arguments:
|
||||
* * voter: the mafia role that is trying to vote for...
|
||||
* * target: the mafia role that is getting voted for
|
||||
* * vote_type: type of vote submitted (is this the day vote? is this the mafia night vote?)
|
||||
* * teams: see mafia team defines for what to put in, makes the messages only send to a specific team (so mafia night votes only sending messages to mafia at night)
|
||||
*/
|
||||
* Proc that goes off when players vote for something with their mafia panel.
|
||||
*
|
||||
* If teams, it hides the tally overlay and only sends the vote messages to the team that is voting
|
||||
* Arguments:
|
||||
* * voter: the mafia role that is trying to vote for...
|
||||
* * target: the mafia role that is getting voted for
|
||||
* * vote_type: type of vote submitted (is this the day vote? is this the mafia night vote?)
|
||||
* * teams: see mafia team defines for what to put in, makes the messages only send to a specific team (so mafia night votes only sending messages to mafia at night)
|
||||
*/
|
||||
/datum/mafia_controller/proc/vote_for(datum/mafia_role/voter,datum/mafia_role/target,vote_type, teams)
|
||||
if(!votes[vote_type])
|
||||
votes[vote_type] = list()
|
||||
@@ -485,8 +495,8 @@
|
||||
old.body.update_icon()
|
||||
|
||||
/**
|
||||
* Clears out the votes of a certain type (day votes, mafia kill votes) while leaving others untouched
|
||||
*/
|
||||
* Clears out the votes of a certain type (day votes, mafia kill votes) while leaving others untouched
|
||||
*/
|
||||
/datum/mafia_controller/proc/reset_votes(vote_type)
|
||||
var/list/bodies_to_update = list()
|
||||
for(var/vote in votes[vote_type])
|
||||
@@ -497,11 +507,11 @@
|
||||
M.update_icon()
|
||||
|
||||
/**
|
||||
* Returns how many people voted for the role, in whatever vote (day vote, night kill vote)
|
||||
* Arguments:
|
||||
* * role: the mafia role the proc tries to get the amount of votes for
|
||||
* * vote_type: the vote type (getting how many day votes were for the role, or mafia night votes for the role)
|
||||
*/
|
||||
* Returns how many people voted for the role, in whatever vote (day vote, night kill vote)
|
||||
* Arguments:
|
||||
* * role: the mafia role the proc tries to get the amount of votes for
|
||||
* * vote_type: the vote type (getting how many day votes were for the role, or mafia night votes for the role)
|
||||
*/
|
||||
/datum/mafia_controller/proc/get_vote_count(role,vote_type)
|
||||
. = 0
|
||||
for(var/v in votes[vote_type])
|
||||
@@ -510,11 +520,11 @@
|
||||
. += votee.vote_power
|
||||
|
||||
/**
|
||||
* Returns whichever role got the most votes, in whatever vote (day vote, night kill vote)
|
||||
* returns null if no votes
|
||||
* Arguments:
|
||||
* * vote_type: the vote type (getting the role that got the most day votes, or the role that got the most mafia votes)
|
||||
*/
|
||||
* Returns whichever role got the most votes, in whatever vote (day vote, night kill vote)
|
||||
* returns null if no votes
|
||||
* Arguments:
|
||||
* * vote_type: the vote type (getting the role that got the most day votes, or the role that got the most mafia votes)
|
||||
*/
|
||||
/datum/mafia_controller/proc/get_vote_winner(vote_type)
|
||||
var/list/tally = list()
|
||||
for(var/votee in votes[vote_type])
|
||||
@@ -526,21 +536,23 @@
|
||||
return length(tally) ? tally[1] : null
|
||||
|
||||
/**
|
||||
* Returns a random person who voted for whatever vote (day vote, night kill vote)
|
||||
* Arguments:
|
||||
* * vote_type: vote type (getting a random day voter, or mafia night voter)
|
||||
*/
|
||||
* Returns a random person who voted for whatever vote (day vote, night kill vote)
|
||||
* Arguments:
|
||||
* * vote_type: vote type (getting a random day voter, or mafia night voter)
|
||||
*/
|
||||
/datum/mafia_controller/proc/get_random_voter(vote_type)
|
||||
if(length(votes[vote_type]))
|
||||
return pick(votes[vote_type])
|
||||
|
||||
/**
|
||||
* Adds mutable appearances to people who get publicly voted on (so not night votes) showing how many people are picking them
|
||||
* Arguments:
|
||||
* * source: the body of the role getting the overlays
|
||||
* * overlay_list: signal var passing the overlay list of the mob
|
||||
*/
|
||||
* Adds mutable appearances to people who get publicly voted on (so not night votes) showing how many people are picking them
|
||||
* Arguments:
|
||||
* * source: the body of the role getting the overlays
|
||||
* * overlay_list: signal var passing the overlay list of the mob
|
||||
*/
|
||||
/datum/mafia_controller/proc/display_votes(atom/source, list/overlay_list)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(phase != MAFIA_PHASE_VOTING)
|
||||
return
|
||||
var/v = get_vote_count(player_role_lookup[source],"Day")
|
||||
@@ -548,14 +560,14 @@
|
||||
overlay_list += MA
|
||||
|
||||
/**
|
||||
* Called when the game is setting up, AFTER map is loaded but BEFORE the phase timers start. Creates and places each role's body and gives the correct player key
|
||||
*
|
||||
* Notably:
|
||||
* * Toggles godmode so the mafia players cannot kill themselves
|
||||
* * Adds signals for voting overlays, see display_votes proc
|
||||
* * gives mafia panel
|
||||
* * sends the greeting text (goals, role name, etc)
|
||||
*/
|
||||
* Called when the game is setting up, AFTER map is loaded but BEFORE the phase timers start. Creates and places each role's body and gives the correct player key
|
||||
*
|
||||
* Notably:
|
||||
* * Toggles godmode so the mafia players cannot kill themselves
|
||||
* * Adds signals for voting overlays, see display_votes proc
|
||||
* * gives mafia panel
|
||||
* * sends the greeting text (goals, role name, etc)
|
||||
*/
|
||||
/datum/mafia_controller/proc/create_bodies()
|
||||
for(var/datum/mafia_role/role in all_roles)
|
||||
var/mob/living/carbon/human/H = new(get_turf(role.assigned_landmark))
|
||||
@@ -716,13 +728,14 @@
|
||||
if(GLOB.mafia_signup[C.ckey])
|
||||
GLOB.mafia_signup -= C.ckey
|
||||
to_chat(usr, "<span class='notice'>You unregister from Mafia.</span>")
|
||||
return
|
||||
return TRUE
|
||||
else
|
||||
GLOB.mafia_signup[C.ckey] = C
|
||||
to_chat(usr, "<span class='notice'>You sign up for Mafia.</span>")
|
||||
if(phase == MAFIA_PHASE_SETUP)
|
||||
check_signups()
|
||||
try_autostart()
|
||||
return TRUE
|
||||
if("mf_spectate")
|
||||
if(C.ckey in spectators)
|
||||
to_chat(usr, "<span class='notice'>You will no longer get messages from the game.</span>")
|
||||
@@ -730,6 +743,7 @@
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You will now get messages from the game.</span>")
|
||||
spectators += C.ckey
|
||||
return TRUE
|
||||
if(user_role.game_status == MAFIA_DEAD)
|
||||
return
|
||||
//User actions (just living)
|
||||
@@ -800,13 +814,13 @@
|
||||
. += L[key]
|
||||
|
||||
/**
|
||||
* Returns a semirandom setup, with...
|
||||
* Town, Two invest roles, one protect role, sometimes a misc role, and the rest assistants for town.
|
||||
* Mafia, 2 normal mafia and one special.
|
||||
* Neutral, two disruption roles, sometimes one is a killing.
|
||||
*
|
||||
* See _defines.dm in the mafia folder for a rundown on what these groups of roles include.
|
||||
*/
|
||||
* Returns a semirandom setup, with...
|
||||
* Town, Two invest roles, one protect role, sometimes a misc role, and the rest assistants for town.
|
||||
* Mafia, 2 normal mafia and one special.
|
||||
* Neutral, two disruption roles, sometimes one is a killing.
|
||||
*
|
||||
* See _defines.dm in the mafia folder for a rundown on what these groups of roles include.
|
||||
*/
|
||||
/datum/mafia_controller/proc/generate_random_setup()
|
||||
var/invests_left = 2
|
||||
var/protects_left = 1
|
||||
@@ -845,8 +859,8 @@
|
||||
return random_setup
|
||||
|
||||
/**
|
||||
* Helper proc that adds a random role of a type to a setup. if it doesn't exist in the setup, it adds the path to the list and otherwise bumps the path in the list up one
|
||||
*/
|
||||
* Helper proc that adds a random role of a type to a setup. if it doesn't exist in the setup, it adds the path to the list and otherwise bumps the path in the list up one
|
||||
*/
|
||||
/datum/mafia_controller/proc/add_setup_role(setup_list, wanted_role_type)
|
||||
var/list/role_type_paths = list()
|
||||
for(var/path in typesof(/datum/mafia_role))
|
||||
@@ -868,17 +882,17 @@
|
||||
setup_list[mafia_path] = 1
|
||||
|
||||
/**
|
||||
* Called when enough players have signed up to fill a setup. DOESN'T NECESSARILY MEAN THE GAME WILL START.
|
||||
*
|
||||
* Checks for a custom setup, if so gets the required players from that and if not it sets the player requirement to required_player(max_player) and generates one IF basic setup starts a game.
|
||||
* Checks if everyone signed up is an observer, and is still connected. If people aren't, they're removed from the list.
|
||||
* If there aren't enough players post sanity, it aborts. otherwise, it selects enough people for the game and starts preparing the game for real.
|
||||
*/
|
||||
* Called when enough players have signed up to fill a setup. DOESN'T NECESSARILY MEAN THE GAME WILL START.
|
||||
*
|
||||
* Checks for a custom setup, if so gets the required players from that and if not it sets the player requirement to MAFIA_MAX_PLAYER_COUNT and generates one IF basic setup starts a game.
|
||||
* Checks if everyone signed up is an observer, and is still connected. If people aren't, they're removed from the list.
|
||||
* If there aren't enough players post sanity, it aborts. otherwise, it selects enough people for the game and starts preparing the game for real.
|
||||
*/
|
||||
/datum/mafia_controller/proc/basic_setup()
|
||||
var/req_players
|
||||
var/list/setup = custom_setup
|
||||
if(!setup.len)
|
||||
req_players = required_player //max_player
|
||||
req_players = max_player //MAFIA_MAX_PLAYER_COUNT
|
||||
else
|
||||
req_players = assoc_value_sum(setup)
|
||||
|
||||
@@ -918,10 +932,10 @@
|
||||
start_game()
|
||||
|
||||
/**
|
||||
* Called when someone signs up, and sees if there are enough people in the signup list to begin.
|
||||
*
|
||||
* Only checks if everyone is actually valid to start (still connected and an observer) if there are enough players (basic_setup)
|
||||
*/
|
||||
* Called when someone signs up, and sees if there are enough people in the signup list to begin.
|
||||
*
|
||||
* Only checks if everyone is actually valid to start (still connected and an observer) if there are enough players (basic_setup)
|
||||
*/
|
||||
/datum/mafia_controller/proc/try_autostart()
|
||||
if(phase != MAFIA_PHASE_SETUP) // || !(GLOB.ghost_role_flags & GHOSTROLE_MINIGAME))
|
||||
return
|
||||
@@ -929,10 +943,10 @@
|
||||
basic_setup()
|
||||
|
||||
/**
|
||||
* Filters inactive player into a different list until they reconnect, and removes players who are no longer ghosts.
|
||||
*
|
||||
* If a disconnected player gets a non-ghost mob and reconnects, they will be first put back into mafia_signup then filtered by that.
|
||||
*/
|
||||
* Filters inactive player into a different list until they reconnect, and removes players who are no longer ghosts.
|
||||
*
|
||||
* If a disconnected player gets a non-ghost mob and reconnects, they will be first put back into mafia_signup then filtered by that.
|
||||
*/
|
||||
/datum/mafia_controller/proc/check_signups()
|
||||
for(var/bad_key in GLOB.mafia_bad_signup)
|
||||
if(GLOB.directory[bad_key])//they have reconnected if we can search their key and get a client
|
||||
@@ -962,8 +976,8 @@
|
||||
parent.ui_interact(owner)
|
||||
|
||||
/**
|
||||
* Creates the global datum for playing mafia games, destroys the last if that's required and returns the new.
|
||||
*/
|
||||
* Creates the global datum for playing mafia games, destroys the last if that's required and returns the new.
|
||||
*/
|
||||
/proc/create_mafia_game()
|
||||
if(GLOB.mafia_game)
|
||||
QDEL_NULL(GLOB.mafia_game)
|
||||
|
||||
+61
-20
@@ -19,7 +19,7 @@
|
||||
var/list/actions = list()
|
||||
var/list/targeted_actions = list()
|
||||
//what the role gets when it wins a game
|
||||
// var/winner_award = /datum/award/achievement/mafia/assistant
|
||||
var/winner_award = /datum/award/achievement/mafia/assistant
|
||||
|
||||
//so mafia have to also kill them to have a majority
|
||||
var/solo_counts_as_town = FALSE //(don't set this for town)
|
||||
@@ -124,7 +124,7 @@
|
||||
desc = "You can investigate a single person each night to learn their team."
|
||||
revealed_outfit = /datum/outfit/mafia/detective
|
||||
role_type = TOWN_INVEST
|
||||
// winner_award = /datum/award/achievement/mafia/detective
|
||||
winner_award = /datum/award/achievement/mafia/detective
|
||||
|
||||
hud_icon = "huddetective"
|
||||
revealed_icon = "detective"
|
||||
@@ -151,6 +151,8 @@
|
||||
current_investigation = target
|
||||
|
||||
/datum/mafia_role/detective/proc/investigate(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/datum/mafia_role/target = current_investigation
|
||||
if(target)
|
||||
if(target.detect_immune)
|
||||
@@ -178,7 +180,7 @@
|
||||
desc = "You can visit someone ONCE PER GAME to reveal their true role in the morning!"
|
||||
revealed_outfit = /datum/outfit/mafia/psychologist
|
||||
role_type = TOWN_INVEST
|
||||
// winner_award = /datum/award/achievement/mafia/psychologist
|
||||
winner_award = /datum/award/achievement/mafia/psychologist
|
||||
|
||||
hud_icon = "hudpsychologist"
|
||||
revealed_icon = "psychologist"
|
||||
@@ -202,6 +204,8 @@
|
||||
current_target = target
|
||||
|
||||
/datum/mafia_role/psychologist/proc/therapy_reveal(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(SEND_SIGNAL(src,COMSIG_MAFIA_CAN_PERFORM_ACTION,game,"reveal",current_target) & MAFIA_PREVENT_ACTION || game_status != MAFIA_ALIVE) //Got lynched or roleblocked by a lawyer.
|
||||
current_target = null
|
||||
if(current_target)
|
||||
@@ -218,7 +222,7 @@
|
||||
role_type = TOWN_INVEST
|
||||
hud_icon = "hudchaplain"
|
||||
revealed_icon = "chaplain"
|
||||
// winner_award = /datum/award/achievement/mafia/chaplain
|
||||
winner_award = /datum/award/achievement/mafia/chaplain
|
||||
|
||||
targeted_actions = list("Pray")
|
||||
var/current_target
|
||||
@@ -238,6 +242,8 @@
|
||||
current_target = target
|
||||
|
||||
/datum/mafia_role/chaplain/proc/commune(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/datum/mafia_role/target = current_target
|
||||
if(target)
|
||||
to_chat(body,"<span class='warning'>You invoke spirit of [target.body.real_name] and learn their role was <b>[target.name]<b>.</span>")
|
||||
@@ -251,7 +257,7 @@
|
||||
role_type = TOWN_PROTECT
|
||||
hud_icon = "hudmedicaldoctor"
|
||||
revealed_icon = "medicaldoctor"
|
||||
// winner_award = /datum/award/achievement/mafia/md
|
||||
winner_award = /datum/award/achievement/mafia/md
|
||||
|
||||
targeted_actions = list("Protect")
|
||||
var/datum/mafia_role/current_protected
|
||||
@@ -277,16 +283,22 @@
|
||||
current_protected = target
|
||||
|
||||
/datum/mafia_role/md/proc/protect(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(current_protected)
|
||||
RegisterSignal(current_protected,COMSIG_MAFIA_ON_KILL,.proc/prevent_kill)
|
||||
add_note("N[game.turn] - Protected [current_protected.body.real_name]")
|
||||
|
||||
/datum/mafia_role/md/proc/prevent_kill(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
to_chat(body,"<span class='warning'>The person you protected tonight was attacked!</span>")
|
||||
to_chat(current_protected.body,"<span class='userdanger'>You were attacked last night, but someone nursed you back to life!</span>")
|
||||
return MAFIA_PREVENT_KILL
|
||||
|
||||
/datum/mafia_role/md/proc/end_protection(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(current_protected)
|
||||
UnregisterSignal(current_protected,COMSIG_MAFIA_ON_KILL)
|
||||
current_protected = null
|
||||
@@ -298,7 +310,7 @@
|
||||
role_type = TOWN_PROTECT
|
||||
hud_icon = "hudlawyer"
|
||||
revealed_icon = "lawyer"
|
||||
// winner_award = /datum/award/achievement/mafia/lawyer
|
||||
winner_award = /datum/award/achievement/mafia/lawyer
|
||||
|
||||
targeted_actions = list("Advise")
|
||||
var/datum/mafia_role/current_target
|
||||
@@ -310,6 +322,8 @@
|
||||
RegisterSignal(game,COMSIG_MAFIA_NIGHT_END,.proc/release)
|
||||
|
||||
/datum/mafia_role/lawyer/proc/roleblock_text(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(SEND_SIGNAL(src,COMSIG_MAFIA_CAN_PERFORM_ACTION,game,"roleblock",current_target) & MAFIA_PREVENT_ACTION || game_status != MAFIA_ALIVE) //Got lynched or roleblocked by another lawyer.
|
||||
current_target = null
|
||||
if(current_target)
|
||||
@@ -335,16 +349,22 @@
|
||||
to_chat(body,"<span class='warning'>You will block [target.body.real_name] tonight.</span>")
|
||||
|
||||
/datum/mafia_role/lawyer/proc/try_to_roleblock(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(current_target)
|
||||
RegisterSignal(current_target,COMSIG_MAFIA_CAN_PERFORM_ACTION, .proc/prevent_action)
|
||||
|
||||
/datum/mafia_role/lawyer/proc/release(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
. = ..()
|
||||
if(current_target)
|
||||
UnregisterSignal(current_target, COMSIG_MAFIA_CAN_PERFORM_ACTION)
|
||||
current_target = null
|
||||
|
||||
/datum/mafia_role/lawyer/proc/prevent_action(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(game_status == MAFIA_ALIVE) //in case we got killed while imprisoning sk - bad luck edge
|
||||
return MAFIA_PREVENT_ACTION
|
||||
|
||||
@@ -355,7 +375,7 @@
|
||||
role_type = TOWN_MISC
|
||||
hud_icon = "hudheadofpersonnel"
|
||||
revealed_icon = "headofpersonnel"
|
||||
// winner_award = /datum/award/achievement/mafia/hop
|
||||
winner_award = /datum/award/achievement/mafia/hop
|
||||
|
||||
targeted_actions = list("Reveal")
|
||||
|
||||
@@ -378,7 +398,7 @@
|
||||
role_type = MAFIA_REGULAR
|
||||
hud_icon = "hudchangeling"
|
||||
revealed_icon = "changeling"
|
||||
// winner_award = /datum/award/achievement/mafia/changeling
|
||||
winner_award = /datum/award/achievement/mafia/changeling
|
||||
|
||||
revealed_outfit = /datum/outfit/mafia/changeling
|
||||
special_theme = "syndicate"
|
||||
@@ -389,6 +409,8 @@
|
||||
RegisterSignal(game,COMSIG_MAFIA_SUNDOWN,.proc/mafia_text)
|
||||
|
||||
/datum/mafia_role/mafia/proc/mafia_text(datum/mafia_controller/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
to_chat(body,"<b>Vote for who to kill tonight. The killer will be chosen randomly from voters.</b>")
|
||||
|
||||
//better detective for mafia
|
||||
@@ -398,7 +420,7 @@
|
||||
role_type = MAFIA_SPECIAL
|
||||
hud_icon = "hudthoughtfeeder"
|
||||
revealed_icon = "thoughtfeeder"
|
||||
// winner_award = /datum/award/achievement/mafia/thoughtfeeder
|
||||
winner_award = /datum/award/achievement/mafia/thoughtfeeder
|
||||
|
||||
targeted_actions = list("Learn Role")
|
||||
var/datum/mafia_role/current_investigation
|
||||
@@ -418,6 +440,8 @@
|
||||
current_investigation = target
|
||||
|
||||
/datum/mafia_role/mafia/thoughtfeeder/proc/investigate(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/datum/mafia_role/target = current_investigation
|
||||
current_investigation = null
|
||||
if(SEND_SIGNAL(src,COMSIG_MAFIA_CAN_PERFORM_ACTION,game,"thoughtfeed",target) & MAFIA_PREVENT_ACTION)
|
||||
@@ -441,7 +465,7 @@
|
||||
win_condition = "kill everyone."
|
||||
team = MAFIA_TEAM_SOLO
|
||||
role_type = NEUTRAL_KILL
|
||||
// winner_award = /datum/award/achievement/mafia/traitor
|
||||
winner_award = /datum/award/achievement/mafia/traitor
|
||||
|
||||
targeted_actions = list("Night Kill")
|
||||
revealed_outfit = /datum/outfit/mafia/traitor
|
||||
@@ -464,6 +488,8 @@
|
||||
return TRUE //while alive, town AND mafia cannot win (though since mafia know who is who it's pretty easy to win from that point)
|
||||
|
||||
/datum/mafia_role/traitor/proc/nightkill_immunity(datum/source,datum/mafia_controller/game,lynch)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(game.phase == MAFIA_PHASE_NIGHT && !lynch)
|
||||
to_chat(body,"<span class='userdanger'>You were attacked, but they'll have to try harder than that to put you down.</span>")
|
||||
return MAFIA_PREVENT_KILL
|
||||
@@ -481,6 +507,8 @@
|
||||
to_chat(body,"<span class='warning'>You will attempt to kill [target.body.real_name] tonight.</span>")
|
||||
|
||||
/datum/mafia_role/traitor/proc/try_to_kill(datum/mafia_controller/source)
|
||||
// SIGNAL_HANDLER
|
||||
|
||||
var/datum/mafia_role/target = current_victim
|
||||
current_victim = null
|
||||
if(SEND_SIGNAL(src,COMSIG_MAFIA_CAN_PERFORM_ACTION,source,"traitor kill",target) & MAFIA_PREVENT_ACTION)
|
||||
@@ -500,7 +528,7 @@
|
||||
special_theme = "neutral"
|
||||
hud_icon = "hudnightmare"
|
||||
revealed_icon = "nightmare"
|
||||
// winner_award = /datum/award/achievement/mafia/nightmare
|
||||
winner_award = /datum/award/achievement/mafia/nightmare
|
||||
|
||||
targeted_actions = list("Flicker", "Hunt")
|
||||
var/list/flickering = list()
|
||||
@@ -543,6 +571,8 @@
|
||||
to_chat(body,"<span class='danger'>You will hunt everyone in a flickering room down tonight.</span>")
|
||||
|
||||
/datum/mafia_role/nightmare/proc/flicker_or_hunt(datum/mafia_controller/source)
|
||||
// SIGNAL_HANDLER
|
||||
|
||||
if(game_status != MAFIA_ALIVE || !flicker_target)
|
||||
return
|
||||
if(SEND_SIGNAL(src,COMSIG_MAFIA_CAN_PERFORM_ACTION,source,"nightmare actions",flicker_target) & MAFIA_PREVENT_ACTION)
|
||||
@@ -576,7 +606,7 @@
|
||||
special_theme = "neutral"
|
||||
hud_icon = "hudfugitive"
|
||||
revealed_icon = "fugitive"
|
||||
// winner_award = /datum/award/achievement/mafia/fugitive
|
||||
winner_award = /datum/award/achievement/mafia/fugitive
|
||||
|
||||
actions = list("Self Preservation")
|
||||
var/charges = 2
|
||||
@@ -604,11 +634,15 @@
|
||||
protection_status = !protection_status
|
||||
|
||||
/datum/mafia_role/fugitive/proc/night_start(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(protection_status == FUGITIVE_WILL_PRESERVE)
|
||||
to_chat(body,"<span class='danger'>Your preparations are complete. Nothing could kill you tonight!</span>")
|
||||
RegisterSignal(src,COMSIG_MAFIA_ON_KILL,.proc/prevent_death)
|
||||
|
||||
/datum/mafia_role/fugitive/proc/night_end(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(protection_status == FUGITIVE_WILL_PRESERVE)
|
||||
charges--
|
||||
UnregisterSignal(src,COMSIG_MAFIA_ON_KILL)
|
||||
@@ -616,13 +650,16 @@
|
||||
protection_status = FUGITIVE_NOT_PRESERVING
|
||||
|
||||
/datum/mafia_role/fugitive/proc/prevent_death(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
to_chat(body,"<span class='userdanger'>You were attacked! Luckily, you were ready for this!</span>")
|
||||
return MAFIA_PREVENT_KILL
|
||||
|
||||
/datum/mafia_role/fugitive/proc/survived(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(game_status == MAFIA_ALIVE)
|
||||
// var/client/winner_client = GLOB.directory[player_key]
|
||||
// winner_client?.give_award(winner_award, body)
|
||||
game.award_role(winner_award, src)
|
||||
game.send_message("<span class='big comradio'>!! FUGITIVE VICTORY !!</span>")
|
||||
|
||||
#undef FUGITIVE_NOT_PRESERVING
|
||||
@@ -640,7 +677,7 @@
|
||||
hud_icon = "hudobsessed"
|
||||
revealed_icon = "obsessed"
|
||||
|
||||
// winner_award = /datum/award/achievement/mafia/obsessed
|
||||
winner_award = /datum/award/achievement/mafia/obsessed
|
||||
|
||||
revealed_outfit = /datum/outfit/mafia/obsessed // /mafia <- outfit must be readded (just make a new mafia outfits file for all of these)
|
||||
solo_counts_as_town = TRUE //after winning or whatever, can side with whoever. they've already done their objective!
|
||||
@@ -652,6 +689,8 @@
|
||||
RegisterSignal(game,COMSIG_MAFIA_SUNDOWN,.proc/find_obsession)
|
||||
|
||||
/datum/mafia_role/obsessed/proc/find_obsession(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/list/all_roles_shuffle = shuffle(game.all_roles)
|
||||
for(var/role in all_roles_shuffle)
|
||||
var/datum/mafia_role/possible = role
|
||||
@@ -667,13 +706,14 @@
|
||||
UnregisterSignal(game,COMSIG_MAFIA_SUNDOWN)
|
||||
|
||||
/datum/mafia_role/obsessed/proc/check_victory(datum/source,datum/mafia_controller/game,lynch)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
UnregisterSignal(source,COMSIG_MAFIA_ON_KILL)
|
||||
if(game_status == MAFIA_DEAD)
|
||||
return
|
||||
if(lynch)
|
||||
game.send_message("<span class='big comradio'>!! OBSESSED VICTORY !!</span>")
|
||||
// var/client/winner_client = GLOB.directory[player_key]
|
||||
// winner_client?.give_award(winner_award, body)
|
||||
game.award_role(winner_award, src)
|
||||
reveal_role(game, FALSE)
|
||||
else
|
||||
to_chat(body, "<span class='userdanger'>You have failed your objective to lynch [obsession.body]!</span>")
|
||||
@@ -689,17 +729,18 @@
|
||||
special_theme = "neutral"
|
||||
hud_icon = "hudclown"
|
||||
revealed_icon = "clown"
|
||||
// winner_award = /datum/award/achievement/mafia/clown
|
||||
winner_award = /datum/award/achievement/mafia/clown
|
||||
|
||||
/datum/mafia_role/clown/New(datum/mafia_controller/game)
|
||||
. = ..()
|
||||
RegisterSignal(src,COMSIG_MAFIA_ON_KILL,.proc/prank)
|
||||
|
||||
/datum/mafia_role/clown/proc/prank(datum/source,datum/mafia_controller/game,lynch)
|
||||
// SIGNAL_HANDLER
|
||||
|
||||
if(lynch)
|
||||
var/datum/mafia_role/victim = pick(game.judgement_guilty_votes + game.judgement_abstain_votes)
|
||||
game.send_message("<span class='big clown'>[body.real_name] WAS A CLOWN! HONK! They take down [victim.body.real_name] with their last prank.</span>")
|
||||
game.send_message("<span class='big clown'>!! CLOWN VICTORY !!</span>")
|
||||
// var/client/winner_client = GLOB.directory[player_key]
|
||||
// winner_client?.give_award(winner_award, body)
|
||||
game.award_role(winner_award, src)
|
||||
victim.kill(game,FALSE)
|
||||
|
||||
@@ -196,6 +196,9 @@
|
||||
deleted_atoms++
|
||||
log_world("Annihilated [deleted_atoms] objects.")
|
||||
|
||||
/datum/map_template/proc/post_load()
|
||||
return
|
||||
|
||||
//for your ever biggening badminnery kevinz000
|
||||
//❤ - Cyberboss
|
||||
/proc/load_new_z_level(file, name, orientation, list/ztraits)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// An error report generated by [parsed_map/check_for_errors].
|
||||
/// An error report generated by [/datum/parsed_map/proc/check_for_errors].
|
||||
/datum/map_report
|
||||
var/original_path
|
||||
var/list/bad_paths = list()
|
||||
|
||||
@@ -25,7 +25,7 @@ interface with the mining shuttle at the landing site if a mobile beacon is also
|
||||
var/possible_destinations
|
||||
clockwork = TRUE
|
||||
var/obj/item/gps/internal/base/locator
|
||||
circuit = /obj/item/circuitboard/computer/auxillary_base
|
||||
circuit = /obj/item/circuitboard/computer/auxiliary_base
|
||||
|
||||
/obj/machinery/computer/auxillary_base/Initialize()
|
||||
. = ..()
|
||||
|
||||
@@ -8,12 +8,12 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
icon = 'icons/obj/machines/mining_machines.dmi'
|
||||
icon_state = "console"
|
||||
density = FALSE
|
||||
|
||||
/// Connected stacking machine
|
||||
var/obj/machinery/mineral/stacking_machine/laborstacker/stacking_machine = null
|
||||
/// Direction of the stacking machine
|
||||
var/machinedir = SOUTH
|
||||
var/obj/machinery/door/airlock/release_door
|
||||
var/door_tag = "prisonshuttle"
|
||||
var/obj/item/radio/Radio //needed to send messages to sec radio
|
||||
/// Needed to send messages to sec radio
|
||||
var/obj/item/radio/Radio
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/Initialize()
|
||||
. = ..()
|
||||
@@ -39,15 +39,23 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
ui = new(user, src, "LaborClaimConsole", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["ores"] = GLOB.labor_sheet_values
|
||||
return data
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
var/can_go_home = FALSE
|
||||
|
||||
data["emagged"] = (obj_flags & EMAGGED) ? 1 : 0
|
||||
data["emagged"] = FALSE
|
||||
if(obj_flags & EMAGGED)
|
||||
data["emagged"] = TRUE
|
||||
can_go_home = TRUE
|
||||
|
||||
var/obj/item/card/id/I = user.get_idcard(TRUE)
|
||||
var/obj/item/card/id/I
|
||||
if(isliving(usr))
|
||||
var/mob/living/L = usr
|
||||
I = L.get_idcard(TRUE)
|
||||
if(istype(I, /obj/item/card/id/prisoner))
|
||||
var/obj/item/card/id/prisoner/P = I
|
||||
data["id_points"] = P.points
|
||||
@@ -63,43 +71,46 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
if(stacking_machine)
|
||||
data["unclaimed_points"] = stacking_machine.points
|
||||
|
||||
data["ores"] = GLOB.labor_sheet_values
|
||||
data["can_go_home"] = can_go_home
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/ui_act(action, params)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/mob/M = usr
|
||||
switch(action)
|
||||
if("claim_points")
|
||||
var/mob/M = usr
|
||||
var/obj/item/card/id/I = M.get_idcard(TRUE)
|
||||
var/obj/item/card/id/I
|
||||
if(isliving(M))
|
||||
var/mob/living/L = M
|
||||
I = L.get_idcard(TRUE)
|
||||
if(istype(I, /obj/item/card/id/prisoner))
|
||||
var/obj/item/card/id/prisoner/P = I
|
||||
P.points += stacking_machine.points
|
||||
stacking_machine.points = 0
|
||||
to_chat(usr, "<span class='notice'>Points transferred.</span>")
|
||||
. = TRUE
|
||||
to_chat(M, "<span class='notice'>Points transferred.</span>")
|
||||
return TRUE
|
||||
else
|
||||
to_chat(usr, "<span class='alert'>No valid id for point transfer detected.</span>")
|
||||
to_chat(M, "<span class='alert'>No valid id for point transfer detected.</span>")
|
||||
if("move_shuttle")
|
||||
if(!alone_in_area(get_area(src), usr))
|
||||
to_chat(usr, "<span class='alert'>Prisoners are only allowed to be released while alone.</span>")
|
||||
else
|
||||
switch(SSshuttle.moveShuttle("laborcamp", "laborcamp_home", TRUE))
|
||||
if(1)
|
||||
to_chat(usr, "<span class='alert'>Shuttle not found.</span>")
|
||||
if(2)
|
||||
to_chat(usr, "<span class='alert'>Shuttle already at station.</span>")
|
||||
if(3)
|
||||
to_chat(usr, "<span class='alert'>No permission to dock could be granted.</span>")
|
||||
else
|
||||
if(!(obj_flags & EMAGGED))
|
||||
Radio.set_frequency(FREQ_SECURITY)
|
||||
Radio.talk_into(src, "A prisoner has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY)
|
||||
to_chat(usr, "<span class='notice'>Shuttle received message and will be sent shortly.</span>")
|
||||
. = TRUE
|
||||
if(!alone_in_area(get_area(src), M))
|
||||
to_chat(M, "<span class='alert'>Prisoners are only allowed to be released while alone.</span>")
|
||||
return
|
||||
switch(SSshuttle.moveShuttle("laborcamp", "laborcamp_home", TRUE))
|
||||
if(1)
|
||||
to_chat(M, "<span class='alert'>Shuttle not found.</span>")
|
||||
if(2)
|
||||
to_chat(M, "<span class='alert'>Shuttle already at station.</span>")
|
||||
if(3)
|
||||
to_chat(M, "<span class='alert'>No permission to dock could be granted.</span>")
|
||||
else
|
||||
if(!(obj_flags & EMAGGED))
|
||||
Radio.set_frequency(FREQ_SECURITY)
|
||||
Radio.talk_into(src, "A prisoner has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY)
|
||||
to_chat(M, "<span class='notice'>Shuttle received message and will be sent shortly.</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/proc/locate_stacking_machine()
|
||||
stacking_machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir))
|
||||
@@ -110,10 +121,9 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/emag_act(mob/user)
|
||||
. = ..()
|
||||
if((obj_flags & EMAGGED))
|
||||
return
|
||||
obj_flags |= EMAGGED
|
||||
to_chat(user, "<span class='warning'>PZZTTPFFFT</span>")
|
||||
if(!(obj_flags & EMAGGED))
|
||||
obj_flags |= EMAGGED
|
||||
to_chat(user, "<span class='warning'>PZZTTPFFFT</span>")
|
||||
return TRUE
|
||||
|
||||
/**********************Prisoner Collection Unit**************************/
|
||||
@@ -121,13 +131,13 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
/obj/machinery/mineral/stacking_machine/laborstacker
|
||||
force_connect = TRUE
|
||||
var/points = 0 //The unclaimed value of ore stacked.
|
||||
//damage_deflection = 21
|
||||
// damage_deflection = 21
|
||||
/obj/machinery/mineral/stacking_machine/laborstacker/process_sheet(obj/item/stack/sheet/inp)
|
||||
points += inp.point_value * inp.amount
|
||||
..()
|
||||
|
||||
/obj/machinery/mineral/stacking_machine/laborstacker/attackby(obj/item/I, mob/living/user)
|
||||
if(istype(I, /obj/item/stack/sheet) && user.canUnEquip(I))
|
||||
if(istype(I, /obj/item/stack/sheet) && user.canUnEquip(I) && user.a_intent == INTENT_HELP)
|
||||
var/obj/item/stack/sheet/inp = I
|
||||
points += inp.point_value * inp.amount
|
||||
return ..()
|
||||
@@ -141,7 +151,10 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
icon_state = "console"
|
||||
density = FALSE
|
||||
|
||||
/obj/machinery/mineral/labor_points_checker/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/machinery/mineral/labor_points_checker/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(. || user.is_blind())
|
||||
return
|
||||
user.examinate(src)
|
||||
|
||||
/obj/machinery/mineral/labor_points_checker/attackby(obj/item/I, mob/user, params)
|
||||
|
||||
@@ -47,7 +47,7 @@ GLOBAL_LIST_EMPTY(silo_access_logs)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/ore_silo/proc/remote_attackby(obj/machinery/M, mob/user, obj/item/stack/I)
|
||||
/obj/machinery/ore_silo/proc/remote_attackby(obj/machinery/M, mob/user, obj/item/stack/I, remote = null)
|
||||
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
|
||||
// stolen from /datum/component/material_container/proc/OnAttackBy
|
||||
if(user.a_intent != INTENT_HELP)
|
||||
@@ -63,7 +63,7 @@ GLOBAL_LIST_EMPTY(silo_access_logs)
|
||||
return
|
||||
// assumes unlimited space...
|
||||
var/amount = I.amount
|
||||
materials.user_insert(I, user)
|
||||
materials.user_insert(I, user, remote)
|
||||
silo_log(M, "deposited", amount, "sheets", item_mats)
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
desc = "Controls a stacking machine... in theory."
|
||||
density = FALSE
|
||||
circuit = /obj/item/circuitboard/machine/stacking_unit_console
|
||||
/// Connected stacking machine
|
||||
var/obj/machinery/mineral/stacking_machine/machine
|
||||
/// Direction for which console looks for stacking machine to connect to
|
||||
var/machinedir = SOUTHEAST
|
||||
|
||||
/obj/machinery/mineral/stacking_unit_console/Initialize()
|
||||
@@ -16,49 +18,53 @@
|
||||
if (machine)
|
||||
machine.CONSOLE = src
|
||||
|
||||
/obj/machinery/mineral/stacking_unit_console/ui_interact(mob/user)
|
||||
. = ..()
|
||||
|
||||
if(!machine)
|
||||
to_chat(user, "<span class='notice'>[src] is not linked to a machine!</span>")
|
||||
return
|
||||
|
||||
var/obj/item/stack/sheet/s
|
||||
var/dat
|
||||
|
||||
dat += text("<b>Stacking unit console</b><br><br>")
|
||||
|
||||
for(var/O in machine.stack_list)
|
||||
s = machine.stack_list[O]
|
||||
if(s.amount > 0)
|
||||
dat += text("[capitalize(s.name)]: [s.amount] <A href='?src=[REF(src)];release=[s.type]'>Release</A><br>")
|
||||
|
||||
dat += text("<br>Stacking: [machine.stack_amt]<br><br>")
|
||||
|
||||
user << browse(dat, "window=console_stacking_machine")
|
||||
|
||||
/obj/machinery/mineral/stacking_unit_console/multitool_act(mob/living/user, obj/item/I)
|
||||
if(I.tool_behaviour == TOOL_MULTITOOL)
|
||||
I.buffer = src
|
||||
to_chat(user, "<span class='notice'>You store linkage information in [I]'s buffer.</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/mineral/stacking_unit_console/Topic(href, href_list)
|
||||
if(..())
|
||||
if(!multitool_check_buffer(user, I))
|
||||
return
|
||||
usr.set_machine(src)
|
||||
src.add_fingerprint(usr)
|
||||
if(href_list["release"])
|
||||
if(!(text2path(href_list["release"]) in machine.stack_list))
|
||||
return //someone tried to spawn materials by spoofing hrefs
|
||||
var/obj/item/stack/sheet/inp = machine.stack_list[text2path(href_list["release"])]
|
||||
var/obj/item/stack/sheet/out = new inp.type(null, inp.amount)
|
||||
inp.amount = 0
|
||||
machine.unload_mineral(out)
|
||||
var/obj/item/multitool/M = I
|
||||
M.buffer = src
|
||||
to_chat(user, "<span class='notice'>You store linkage information in [I]'s buffer.</span>")
|
||||
return TRUE
|
||||
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
/obj/machinery/mineral/stacking_unit_console/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "StackingConsole", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/mineral/stacking_unit_console/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["machine"] = machine ? TRUE : FALSE
|
||||
data["stacking_amount"] = null
|
||||
data["contents"] = list()
|
||||
if(machine)
|
||||
data["stacking_amount"] = machine.stack_amt
|
||||
for(var/stack_type in machine.stack_list)
|
||||
var/obj/item/stack/sheet/stored_sheet = machine.stack_list[stack_type]
|
||||
if(stored_sheet.amount <= 0)
|
||||
continue
|
||||
data["contents"] += list(list(
|
||||
"type" = stored_sheet.type,
|
||||
"name" = capitalize(stored_sheet.name),
|
||||
"amount" = stored_sheet.amount,
|
||||
))
|
||||
return data
|
||||
|
||||
/obj/machinery/mineral/stacking_unit_console/ui_act(action, list/params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("release")
|
||||
var/obj/item/stack/sheet/released_type = text2path(params["type"])
|
||||
if(!released_type || !(initial(released_type.merge_type) in machine.stack_list))
|
||||
return //someone tried to spawn materials by spoofing hrefs
|
||||
var/obj/item/stack/sheet/inp = machine.stack_list[initial(released_type.merge_type)]
|
||||
var/obj/item/stack/sheet/out = new inp.type(null, inp.amount)
|
||||
inp.amount = 0
|
||||
machine.unload_mineral(out)
|
||||
return TRUE
|
||||
|
||||
/**********************Mineral stacking unit**************************/
|
||||
|
||||
@@ -107,6 +113,17 @@
|
||||
/obj/machinery/mineral/stacking_machine/proc/process_sheet(obj/item/stack/sheet/inp)
|
||||
if(QDELETED(inp))
|
||||
return
|
||||
|
||||
// Dump the sheets to the silo if attached
|
||||
if(materials.silo && !materials.on_hold())
|
||||
var/matlist = inp.custom_materials & materials.mat_container.materials
|
||||
if (length(matlist))
|
||||
var/inserted = materials.mat_container.insert_item(inp)
|
||||
materials.silo_log(src, "collected", inserted, "sheets", matlist)
|
||||
qdel(inp)
|
||||
return
|
||||
|
||||
// No silo attached process to internal storage
|
||||
var/key = inp.merge_type
|
||||
var/obj/item/stack/sheet/storage = stack_list[key]
|
||||
if(!storage) //It's the first of this sheet added
|
||||
@@ -114,15 +131,6 @@
|
||||
storage.amount += inp.amount //Stack the sheets
|
||||
qdel(inp)
|
||||
|
||||
if(materials.silo && !materials.on_hold()) //Dump the sheets to the silo
|
||||
var/matlist = storage.custom_materials & materials.mat_container.materials
|
||||
if (length(matlist))
|
||||
var/inserted = materials.mat_container.insert_item(storage)
|
||||
materials.silo_log(src, "collected", inserted, "sheets", matlist)
|
||||
if (QDELETED(storage))
|
||||
stack_list -= key
|
||||
return
|
||||
|
||||
while(storage.amount >= stack_amt) //Get rid of excessive stackage
|
||||
var/obj/item/stack/sheet/out = new inp.type(null, stack_amt)
|
||||
unload_mineral(out)
|
||||
|
||||
@@ -298,20 +298,21 @@
|
||||
return doUnEquip(I, force, drop_location(), FALSE)
|
||||
|
||||
//for when the item will be immediately placed in a loc other than the ground
|
||||
/mob/proc/transferItemToLoc(obj/item/I, newloc = null, force = FALSE)
|
||||
return doUnEquip(I, force, newloc, FALSE)
|
||||
/mob/proc/transferItemToLoc(obj/item/I, newloc = null, force = FALSE, silent = TRUE)
|
||||
return doUnEquip(I, force, newloc, FALSE, silent = silent)
|
||||
|
||||
//visibly unequips I but it is NOT MOVED AND REMAINS IN SRC
|
||||
//item MUST BE FORCEMOVE'D OR QDEL'D
|
||||
/mob/proc/temporarilyRemoveItemFromInventory(obj/item/I, force = FALSE, idrop = TRUE)
|
||||
return doUnEquip(I, force, null, TRUE, idrop)
|
||||
return doUnEquip(I, force, null, TRUE, idrop, silent = TRUE)
|
||||
|
||||
//DO NOT CALL THIS PROC
|
||||
//use one of the above 3 helper procs
|
||||
//you may override it, but do not modify the args
|
||||
/mob/proc/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE) //Force overrides TRAIT_NODROP for things like wizarditis and admin undress.
|
||||
/mob/proc/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE, silent = FALSE) //Force overrides TRAIT_NODROP for things like wizarditis and admin undress.
|
||||
//Use no_move if the item is just gonna be immediately moved afterward
|
||||
//Invdrop is used to prevent stuff in pockets dropping. only set to false if it's going to immediately be replaced
|
||||
PROTECTED_PROC(TRUE)
|
||||
if(!I) //If there's nothing to drop, the drop is automatically succesfull. If(unEquip) should generally be used to check for TRAIT_NODROP.
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
//can't unequip since it can't equip anything
|
||||
/mob/living/carbon/alien/larva/doUnEquip(obj/item/W)
|
||||
/mob/living/carbon/alien/larva/doUnEquip(obj/item/W, silent = FALSE)
|
||||
return
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
var/lastpuke = 0
|
||||
var/account_id
|
||||
var/last_fire_update
|
||||
var/hardcore_survival_score = 0
|
||||
|
||||
/// Unarmed parry data for human
|
||||
/datum/block_parry_data/unarmed/human
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
var/obj/item/thing = sloties
|
||||
. += thing?.slowdown
|
||||
|
||||
/mob/living/carbon/human/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE)
|
||||
/mob/living/carbon/human/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE, silent = FALSE)
|
||||
var/index = get_held_index_of_item(I)
|
||||
. = ..() //See mob.dm for an explanation on this and some rage about people copypasting instead of calling ..() like they should.
|
||||
if(!. || !I)
|
||||
|
||||
@@ -3,16 +3,30 @@
|
||||
GLOBAL_LIST_EMPTY(roundstart_races)
|
||||
GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
|
||||
/**
|
||||
* # species datum
|
||||
*
|
||||
* Datum that handles different species in the game.
|
||||
*
|
||||
* This datum handles species in the game, such as lizardpeople, mothmen, zombies, skeletons, etc.
|
||||
* It is used in [carbon humans][mob/living/carbon/human] to determine various things about them, like their food preferences, if they have biological genders, their damage resistances, and more.
|
||||
*
|
||||
*/
|
||||
/datum/species
|
||||
var/id // if the game needs to manually check your race to do something not included in a proc here, it will use this
|
||||
var/limbs_id //this is used if you want to use a different species limb sprites. Mainly used for angels as they look like humans.
|
||||
var/name // this is the fluff name. these will be left generic (such as 'Lizardperson' for the lizard race) so servers can change them to whatever
|
||||
var/default_color = "#FFFFFF" // if alien colors are disabled, this is the color that will be used by that race
|
||||
///If the game needs to manually check your race to do something not included in a proc here, it will use this.
|
||||
var/id
|
||||
//This is used if you want to use a different species' limb sprites.
|
||||
var/limbs_id
|
||||
///This is the fluff name. They are displayed on health analyzers and in the character setup menu. Leave them generic for other servers to customize.
|
||||
var/name
|
||||
// Default color. If mutant colors are disabled, this is the color that will be used by that race.
|
||||
var/default_color = "#FFF"
|
||||
|
||||
var/sexes = 1 // whether or not the race has sexual characteristics. at the moment this is only 0 for skeletons and shadows
|
||||
///Whether or not the race has sexual characteristics (biological genders). At the moment this is only FALSE for skeletons and shadows
|
||||
var/sexes = TRUE
|
||||
var/has_field_of_vision = TRUE
|
||||
|
||||
//Species Icon Drawing Offsets - Pixel X, Pixel Y, Aka X = Horizontal and Y = Vertical, from bottom left corner
|
||||
///Clothing offsets. If a species has a different body than other species, you can offset clothing so they look less weird.
|
||||
var/list/offset_features = list(
|
||||
OFFSET_UNIFORM = list(0,0),
|
||||
OFFSET_ID = list(0,0),
|
||||
@@ -34,74 +48,141 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
OFFSET_MUTPARTS = list(0,0)
|
||||
)
|
||||
|
||||
var/hair_color // this allows races to have specific hair colors... if null, it uses the H's hair/facial hair colors. if "mutcolor", it uses the H's mutant_color
|
||||
var/hair_alpha = 255 // the alpha used by the hair. 255 is completely solid, 0 is transparent.
|
||||
var/use_skintones = NO_SKINTONES // does it use skintones or not? (spoiler alert this is only used by humans)
|
||||
var/exotic_blood = "" // If your race wants to bleed something other than bog standard blood, change this to reagent id.
|
||||
var/exotic_bloodtype = "" //If your race uses a non standard bloodtype (A+, O-, AB-, etc)
|
||||
var/exotic_blood_color = BLOOD_COLOR_HUMAN //assume human as the default blood colour, override this default by species subtypes
|
||||
///This allows races to have specific hair colors. If null, it uses the H's hair/facial hair colors. If "mutcolor", it uses the H's mutant_color. If "fixedmutcolor", it uses fixedmutcolor
|
||||
var/hair_color
|
||||
///The alpha used by the hair. 255 is completely solid, 0 is invisible.
|
||||
var/hair_alpha = 255
|
||||
|
||||
///Does the species use skintones or not? As of now only used by humans.
|
||||
var/use_skintones = FALSE
|
||||
///If your race bleeds something other than bog standard blood, change this to reagent id. For example, ethereals bleed liquid electricity.
|
||||
var/exotic_blood = ""
|
||||
///If your race uses a non standard bloodtype (A+, O-, AB-, etc). For example, lizards have L type blood.
|
||||
var/exotic_bloodtype = ""
|
||||
/// Assume human as the default blood colour, override this default by species subtypes
|
||||
var/exotic_blood_color = BLOOD_COLOR_HUMAN
|
||||
///What the species drops when gibbed by a gibber machine.
|
||||
var/meat = /obj/item/reagent_containers/food/snacks/meat/slab/human //What the species drops on gibbing
|
||||
var/list/gib_types = list(/obj/effect/gibspawner/human, /obj/effect/gibspawner/human/bodypartless)
|
||||
///What skin the species drops when gibbed by a gibber machine.
|
||||
var/skinned_type
|
||||
///Bitfield for food types that the species likes, giving them a mood boost. Lizards like meat, for example.
|
||||
var/liked_food = NONE
|
||||
///Bitfield for food types that the species dislikes, giving them disgust. Humans hate raw food, for example.
|
||||
var/disliked_food = GROSS
|
||||
///Bitfield for food types that the species absolutely hates, giving them even more disgust than disliked food. Meat is "toxic" to moths, for example.
|
||||
var/toxic_food = TOXIC
|
||||
var/list/no_equip = list() // slots the race can't equip stuff to
|
||||
var/nojumpsuit = 0 // this is sorta... weird. it basically lets you equip stuff that usually needs jumpsuits without one, like belts and pockets and ids
|
||||
///Inventory slots the race can't equip stuff to. Golems cannot wear jumpsuits, for example.
|
||||
var/list/no_equip = list()
|
||||
/// Allows the species to equip items that normally require a jumpsuit without having one equipped. Used by golems.
|
||||
var/nojumpsuit = FALSE
|
||||
var/blacklisted = 0 //Flag to exclude from green slime core species.
|
||||
var/dangerous_existence //A flag for transformation spells that tells them "hey if you turn a person into one of these without preperation, they'll probably die!"
|
||||
var/say_mod = "says" // affects the speech message
|
||||
///Affects the speech message, for example: Motharula flutters, "My speech message is flutters!"
|
||||
var/say_mod = "says"
|
||||
///What languages this species can understand and say. Use a [language holder datum][/datum/language_holder] in this var.
|
||||
var/species_language_holder = /datum/language_holder
|
||||
var/list/mutant_bodyparts = list() // Visible CURRENT bodyparts that are unique to a species. Changes to this list for non-species specific bodyparts (ie cat ears and tails) should be assigned at organ level if possible. Layer hiding is handled by handle_mutant_bodyparts() below.
|
||||
var/list/mutant_organs = list() //Internal organs that are unique to this race.
|
||||
var/speedmod = 0 // this affects the race's speed. positive numbers make it move slower, negative numbers make it move faster
|
||||
var/armor = 0 // overall defense for the race... or less defense, if it's negative.
|
||||
var/attack_type = BRUTE // the type of damage unarmed attacks from this species do
|
||||
var/brutemod = 1 // multiplier for brute damage
|
||||
var/burnmod = 1 // multiplier for burn damage
|
||||
var/coldmod = 1 // multiplier for cold damage
|
||||
var/heatmod = 1 // multiplier for heat damage
|
||||
var/stunmod = 1 // multiplier for stun duration
|
||||
var/punchdamagelow = 1 //lowest possible punch damage. if this is set to 0, punches will always miss
|
||||
var/punchdamagehigh = 10 //highest possible punch damage
|
||||
var/punchstunthreshold = 10 //damage at which punches from this race will stun //yes it should be to the attacked race but it's not useful that way even if it's logical
|
||||
/**
|
||||
* Visible CURRENT bodyparts that are unique to a species.
|
||||
* DO NOT USE THIS AS A LIST OF ALL POSSIBLE BODYPARTS AS IT WILL FUCK
|
||||
* SHIT UP! Changes to this list for non-species specific bodyparts (ie
|
||||
* cat ears and tails) should be assigned at organ level if possible.
|
||||
* Assoc values are defaults for given bodyparts, also modified by aforementioned organs.
|
||||
* They also allow for faster '[]' list access versus 'in'. Other than that, they are useless right now.
|
||||
* Layer hiding is handled by [/datum/species/proc/handle_mutant_bodyparts] below.
|
||||
*/
|
||||
var/list/mutant_bodyparts = list()
|
||||
///Internal organs that are unique to this race, like a tail.
|
||||
var/list/mutant_organs = list()
|
||||
///Multiplier for the race's speed. Positive numbers make it move slower, negative numbers make it move faster.
|
||||
var/speedmod = 0
|
||||
///Percentage modifier for overall defense of the race, or less defense, if it's negative.
|
||||
var/armor = 0
|
||||
///multiplier for brute damage
|
||||
var/brutemod = 1
|
||||
///multiplier for burn damage
|
||||
var/burnmod = 1
|
||||
///multiplier for damage from cold temperature
|
||||
var/coldmod = 1
|
||||
///multiplier for damage from hot temperature
|
||||
var/heatmod = 1
|
||||
///multiplier for stun durations
|
||||
var/stunmod = 1
|
||||
///multiplier for money paid at payday
|
||||
var/payday_modifier = 1
|
||||
///Type of damage attack does. Ethereals attack with burn damage for example.
|
||||
var/attack_type = BRUTE // multiplier for stun duration
|
||||
///Lowest possible punch damage this species can give. If this is set to 0, punches will always miss.
|
||||
var/punchdamagelow = 1
|
||||
///Highest possible punch damage this species can give.
|
||||
var/punchdamagehigh = 10
|
||||
///Damage at which punches from this race will stun
|
||||
var/punchstunthreshold = 10 //yes it should be to the attacked race but it's not useful that way even if it's logical
|
||||
var/punchwoundbonus = 0 // additional wound bonus. generally zero.
|
||||
var/siemens_coeff = 1 //base electrocution coefficient
|
||||
var/damage_overlay_type = "human" //what kind of damage overlays (if any) appear on our species when wounded?
|
||||
var/fixed_mut_color = "" //to use MUTCOLOR with a fixed color that's independent of dna.feature["mcolor"]
|
||||
///Base electrocution coefficient. Basically a multiplier for damage from electrocutions.
|
||||
var/siemens_coeff = 1
|
||||
///What kind of damage overlays (if any) appear on our species when wounded? If this is "", does not add an overlay.
|
||||
var/damage_overlay_type = "human"
|
||||
///To use MUTCOLOR with a fixed color that's independent of the mcolor feature in DNA.
|
||||
var/fixed_mut_color = ""
|
||||
///Special mutation that can be found in the genepool exclusively in this species. Dont leave empty or changing species will be a headache
|
||||
var/inert_mutation = DWARFISM
|
||||
var/list/special_step_sounds //Sounds to override barefeet walkng
|
||||
var/grab_sound //Special sound for grabbing
|
||||
var/datum/outfit/outfit_important_for_life // A path to an outfit that is important for species life e.g. plasmaman outfit
|
||||
///Sounds to override barefeet walking
|
||||
var/list/special_step_sounds
|
||||
///Special sound for grabbing
|
||||
var/grab_sound
|
||||
/// A path to an outfit that is important for species life e.g. plasmaman outfit
|
||||
var/datum/outfit/outfit_important_for_life
|
||||
|
||||
// species-only traits. Can be found in DNA.dm
|
||||
///Species-only traits. Can be found in [code/__DEFINES/DNA.dm]
|
||||
var/list/species_traits = list(HAS_FLESH,HAS_BONE) //by default they can scar and have bones/flesh unless set to something else
|
||||
// generic traits tied to having the species
|
||||
var/list/inherent_traits = list()
|
||||
///Generic traits tied to having the species.
|
||||
var/list/inherent_traits = list() //list(TRAIT_ADVANCEDTOOLUSER)
|
||||
/// List of biotypes the mob belongs to. Used by diseases.
|
||||
var/inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID
|
||||
|
||||
var/list/blacklisted_quirks = list() // Quirks that will be removed upon gaining this species, to be defined by species
|
||||
var/list/removed_quirks = list() // Quirks that got removed due to being blacklisted, and will be restored when on_species_loss() is called
|
||||
|
||||
var/attack_verb = "punch" // punch-specific attack verb
|
||||
///Punch-specific attack verb.
|
||||
var/attack_verb = "punch"
|
||||
///
|
||||
var/sound/attack_sound = 'sound/weapons/punch1.ogg'
|
||||
var/sound/miss_sound = 'sound/weapons/punchmiss.ogg'
|
||||
|
||||
var/list/mob/living/ignored_by = list() // list of mobs that will ignore this species
|
||||
//Breathing!
|
||||
var/obj/item/organ/lungs/mutantlungs = null
|
||||
///What gas does this species breathe? Used by suffocation screen alerts, most of actual gas breathing is handled by mutantlungs. See [life.dm][code/modules/mob/living/carbon/human/life.dm]
|
||||
var/breathid = "o2"
|
||||
|
||||
//Do NOT remove by setting to null. use OR make a RESPECTIVE TRAIT (removing stomach? add the NOSTOMACH trait to your species)
|
||||
//why does it work this way? because traits also disable the downsides of not having an organ, removing organs but not having the trait will make your species die
|
||||
|
||||
///Replaces default brain with a different organ
|
||||
var/obj/item/organ/brain/mutant_brain = /obj/item/organ/brain
|
||||
///Replaces default heart with a different organ
|
||||
var/obj/item/organ/heart/mutant_heart = /obj/item/organ/heart
|
||||
///Replaces default lungs with a different organ
|
||||
// var/obj/item/organ/lungs/mutantlungs = /obj/item/organ/lungs
|
||||
///Replaces default eyes with a different organ
|
||||
var/obj/item/organ/eyes/mutanteyes = /obj/item/organ/eyes
|
||||
///Replaces default ears with a different organ
|
||||
var/obj/item/organ/ears/mutantears = /obj/item/organ/ears
|
||||
var/obj/item/mutanthands
|
||||
///Replaces default tongue with a different organ
|
||||
var/obj/item/organ/tongue/mutanttongue = /obj/item/organ/tongue
|
||||
///Replaces default liver with a different organ
|
||||
var/obj/item/organ/liver/mutantliver = /obj/item/organ/liver
|
||||
///Replaces default stomach with a different organ
|
||||
var/obj/item/organ/stomach/mutantstomach = /obj/item/organ/stomach
|
||||
///Replaces default appendix with a different organ.
|
||||
var/obj/item/organ/appendix/mutantappendix = /obj/item/organ/appendix
|
||||
///Forces an item into this species' hands. Only an honorary mutantthing because this is not an organ and not loaded in the same way, you've been warned to do your research.
|
||||
var/obj/item/mutanthands
|
||||
|
||||
/// CIT SPECIFIC Mutant tail
|
||||
var/obj/item/organ/tail/mutanttail = null
|
||||
|
||||
var/obj/item/organ/liver/mutantliver
|
||||
var/obj/item/organ/stomach/mutantstomach
|
||||
var/override_float = FALSE
|
||||
|
||||
//Citadel snowflake
|
||||
@@ -126,6 +207,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
//the icon state of the eyes this species has
|
||||
var/eye_type = "normal"
|
||||
|
||||
///For custom overrides for species ass images
|
||||
var/icon/ass_image
|
||||
|
||||
///////////
|
||||
// PROCS //
|
||||
///////////
|
||||
@@ -141,6 +225,12 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
//update our mutant bodyparts to include unlocked ones
|
||||
mutant_bodyparts += GLOB.unlocked_mutant_parts
|
||||
|
||||
/**
|
||||
* Generates species available to choose in character setup at roundstart
|
||||
*
|
||||
* This proc generates which species are available to pick from in character setup.
|
||||
* If there are no available roundstart species, defaults to human.
|
||||
*/
|
||||
/proc/generate_selectable_species(clear = FALSE)
|
||||
if(clear)
|
||||
GLOB.roundstart_races = list()
|
||||
@@ -154,11 +244,26 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
if(!GLOB.roundstart_races.len)
|
||||
GLOB.roundstart_races += "human"
|
||||
|
||||
/**
|
||||
* Checks if a species is eligible to be picked at roundstart.
|
||||
*
|
||||
* Checks the config to see if this species is allowed to be picked in the character setup menu.
|
||||
* Used by [/proc/generate_selectable_species].
|
||||
*/
|
||||
/datum/species/proc/check_roundstart_eligible()
|
||||
if(id in (CONFIG_GET(keyed_list/roundstart_races)))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Generates a random name for a carbon.
|
||||
*
|
||||
* This generates a random unique name based on a human's species and gender.
|
||||
* Arguments:
|
||||
* * gender - The gender that the name should adhere to. Use MALE for male names, use anything else for female names.
|
||||
* * unique - If true, ensures that this new name is not a duplicate of anyone else's name currently on the station.
|
||||
* * lastname - Does this species' naming system adhere to the last name system? Set to false if it doesn't.
|
||||
*/
|
||||
/datum/species/proc/random_name(gender,unique,lastname)
|
||||
if(unique)
|
||||
return random_unique_name(gender)
|
||||
@@ -176,7 +281,13 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
|
||||
return randname
|
||||
|
||||
//Called when cloning, copies some vars that should be kept
|
||||
/**
|
||||
* Copies some vars and properties over that should be kept when creating a copy of this species.
|
||||
*
|
||||
* Used by slimepeople to copy themselves, and by the DNA datum to hardset DNA to a species
|
||||
* Arguments:
|
||||
* * old_species - The species that the carbon used to be before copying
|
||||
*/
|
||||
/datum/species/proc/copy_properties_from(datum/species/old_species)
|
||||
mutant_bodyparts["limbs_id"] = old_species.mutant_bodyparts["limbs_id"]
|
||||
eye_type = old_species.eye_type
|
||||
@@ -189,7 +300,18 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
// return 0 //It returns false when it runs the proc so they don't get jobs from the global list.
|
||||
return 1 //It returns 1 to say they are a-okay to continue.
|
||||
|
||||
//Will regenerate missing organs
|
||||
/**
|
||||
* Corrects organs in a carbon, removing ones it doesn't need and adding ones it does.
|
||||
*
|
||||
* Takes all organ slots, removes organs a species should not have, adds organs a species should have.
|
||||
* can use replace_current to refresh all organs, creating an entirely new set.
|
||||
*
|
||||
* Arguments:
|
||||
* * C - carbon, the owner of the species datum AKA whoever we're regenerating organs in
|
||||
* * old_species - datum, used when regenerate organs is called in a switching species to remove old mutant organs.
|
||||
* * replace_current - boolean, forces all old organs to get deleted whether or not they pass the species' ability to keep that organ
|
||||
* * excluded_zones - list, add zone defines to block organs inside of the zones from getting handled. see headless mutation for an example
|
||||
*/
|
||||
/datum/species/proc/regenerate_organs(mob/living/carbon/C,datum/species/old_species,replace_current=TRUE)
|
||||
var/obj/item/organ/brain/brain = C.getorganslot(ORGAN_SLOT_BRAIN)
|
||||
var/obj/item/organ/heart/heart = C.getorganslot(ORGAN_SLOT_HEART)
|
||||
@@ -305,6 +427,16 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/obj/item/organ/I = new path()
|
||||
I.Insert(C)
|
||||
|
||||
/**
|
||||
* Proc called when a carbon becomes this species.
|
||||
*
|
||||
* This sets up and adds/changes/removes things, qualities, abilities, and traits so that the transformation is as smooth and bugfree as possible.
|
||||
* Produces a [COMSIG_SPECIES_GAIN] signal.
|
||||
* Arguments:
|
||||
* * C - Carbon, this is whoever became the new species.
|
||||
* * old_species - The species that the carbon used to be before becoming this race, used for regenerating organs.
|
||||
* * pref_load - Preferences to be loaded from character setup, loads in preferred mutant things like bodyparts, digilegs, skin color, etc.
|
||||
*/
|
||||
/datum/species/proc/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
|
||||
// Drop the items the new species can't wear
|
||||
for(var/slot_id in no_equip)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_CHUNKYFINGERS,TRAIT_NOHUNGER,TRAIT_NOBREATH)
|
||||
mutanttongue = /obj/item/organ/tongue/abductor
|
||||
species_category = SPECIES_CATEGORY_ALIEN
|
||||
ass_image = 'icons/ass/assgrey.png'
|
||||
|
||||
/datum/species/abductor/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
tail_type = "mam_tail"
|
||||
wagging_type = "mam_waggingtail"
|
||||
species_category = SPECIES_CATEGORY_FURRY
|
||||
ass_image = 'icons/ass/asscat.png'
|
||||
|
||||
/datum/species/human/felinid/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
|
||||
if(ishuman(C))
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
tail_type = "mam_tail"
|
||||
wagging_type = "mam_waggingtail"
|
||||
species_category = SPECIES_CATEGORY_JELLY
|
||||
ass_image = 'icons/ass/assslime.png'
|
||||
|
||||
/obj/item/organ/brain/jelly
|
||||
name = "slime nucleus"
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
wagging_type = "waggingtail_lizard"
|
||||
species_category = SPECIES_CATEGORY_LIZARD
|
||||
|
||||
ass_image = 'icons/ass/asslizard.png'
|
||||
|
||||
/datum/species/lizard/random_name(gender,unique,lastname)
|
||||
if(unique)
|
||||
return random_unique_lizard_name(gender)
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
species_category = SPECIES_CATEGORY_SKELETON
|
||||
|
||||
ass_image = 'icons/ass/assplasma.png'
|
||||
|
||||
/datum/species/plasmaman/spec_life(mob/living/carbon/human/H)
|
||||
var/datum/gas_mixture/environment = H.loc.return_air()
|
||||
var/atmos_sealed = FALSE
|
||||
|
||||
@@ -187,12 +187,8 @@
|
||||
AM.emp_act(50)
|
||||
if(iscyborg(AM))
|
||||
var/mob/living/silicon/robot/borg = AM
|
||||
if(borg.lamp_intensity)
|
||||
borg.update_headlamp(TRUE, INFINITY)
|
||||
to_chat(borg, "<span class='danger'>Your headlamp is fried! You'll need a human to help replace it.</span>")
|
||||
for(var/obj/item/assembly/flash/cyborg/F in borg.held_items)
|
||||
if(!F.crit_fail)
|
||||
F.burn_out()
|
||||
if(borg.lamp_enabled)
|
||||
borg.smash_headlamp()
|
||||
else
|
||||
for(var/obj/item/O in AM)
|
||||
if(O.light_range && O.light_power)
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
|
||||
return not_handled
|
||||
|
||||
/mob/living/carbon/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE)
|
||||
/mob/living/carbon/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE, silent = FALSE)
|
||||
. = ..() //Sets the default return value to what the parent returns.
|
||||
if(!. || !I) //We don't want to set anything to null if the parent returned 0.
|
||||
return
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
|
||||
//Portrait picker! It's a tgui window that lets you look through all the portraits, and choose one as your AI.
|
||||
|
||||
//very similar to centcom_podlauncher in terms of how this is coded, so i kept a lot of comments from it
|
||||
//^ wow! it's the second time i've said this! i'm a real coder now, copying my statement of copying other people's stuff.
|
||||
|
||||
|
||||
#define TAB_LIBRARY 1
|
||||
#define TAB_SECURE 2
|
||||
#define TAB_PRIVATE 3
|
||||
|
||||
/datum/portrait_picker
|
||||
var/client/holder //client of whoever is using this datum
|
||||
|
||||
/datum/portrait_picker/New(user)//user can either be a client or a mob due to byondcode(tm)
|
||||
if (istype(user, /client))
|
||||
var/client/user_client = user
|
||||
holder = user_client //if its a client, assign it to holder
|
||||
else
|
||||
var/mob/user_mob = user
|
||||
holder = user_mob.client //if its a mob, assign the mob's client to holder
|
||||
|
||||
/datum/portrait_picker/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "PortraitPicker")
|
||||
ui.open()
|
||||
|
||||
/datum/portrait_picker/ui_close()
|
||||
qdel(src)
|
||||
|
||||
/datum/portrait_picker/ui_state(mob/user)
|
||||
return GLOB.conscious_state
|
||||
|
||||
/datum/portrait_picker/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/simple/portraits/library),
|
||||
get_asset_datum(/datum/asset/simple/portraits/library_secure),
|
||||
get_asset_datum(/datum/asset/simple/portraits/library_private)
|
||||
)
|
||||
|
||||
/datum/portrait_picker/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["library"] = SSpersistence.paintings["library"] ? SSpersistence.paintings["library"] : 0
|
||||
data["library_secure"] = SSpersistence.paintings["library_secure"] ? SSpersistence.paintings["library_secure"] : 0
|
||||
data["library_private"] = SSpersistence.paintings["library_private"] ? SSpersistence.paintings["library_private"] : 0 //i'm gonna regret this, won't i?
|
||||
return data
|
||||
|
||||
/datum/portrait_picker/ui_act(action, params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
switch(action)
|
||||
if("select")
|
||||
var/list/tab2key = list(TAB_LIBRARY = "library", TAB_SECURE = "library_secure", TAB_PRIVATE = "library_private")
|
||||
var/folder = tab2key[params["tab"]]
|
||||
var/list/current_list = SSpersistence.paintings[folder]
|
||||
var/list/chosen_portrait = current_list[params["selected"]]
|
||||
var/png = "data/paintings/[folder]/[chosen_portrait["md5"]].png"
|
||||
var/icon/portrait_icon = new(png)
|
||||
var/mob/living/ai = holder.mob
|
||||
var/w = portrait_icon.Width()
|
||||
var/h = portrait_icon.Height()
|
||||
var/mutable_appearance/MA = mutable_appearance(portrait_icon)
|
||||
if(w == 23 || h == 23)
|
||||
to_chat(ai, "<span class='notice'>Small note: 23x23 Portraits are accepted, but they do not fit perfectly inside the display frame.</span>")
|
||||
MA.pixel_x = 5
|
||||
MA.pixel_y = 5
|
||||
else if(w == 24 || h == 24)
|
||||
to_chat(ai, "<span class='notice'>Portrait Accepted. Enjoy!</span>")
|
||||
MA.pixel_x = 4
|
||||
MA.pixel_y = 4
|
||||
else
|
||||
to_chat(ai, "<span class='warning'>Sorry, only 23x23 and 24x24 Portraits are accepted.</span>")
|
||||
return
|
||||
ai.cut_overlays() //so people can't keep repeatedly select portraits to add stacking overlays
|
||||
ai.icon_state = "ai-portrait-active"//background
|
||||
ai.add_overlay(MA)
|
||||
@@ -16,7 +16,9 @@
|
||||
/mob/living/silicon/robot/death(gibbed)
|
||||
if(stat == DEAD)
|
||||
return
|
||||
|
||||
if(!gibbed)
|
||||
logevent("FATAL -- SYSTEM HALT")
|
||||
modularInterface.shutdown_computer()
|
||||
. = ..()
|
||||
|
||||
locked = FALSE //unlock cover
|
||||
@@ -24,7 +26,7 @@
|
||||
update_mobility()
|
||||
if(!QDELETED(builtInCamera) && builtInCamera.status)
|
||||
builtInCamera.toggle_cam(src,0)
|
||||
update_headlamp(1) //So borg lights are disabled when killed.
|
||||
toggle_headlamp(TRUE) //So borg lights are disabled when killed.
|
||||
|
||||
uneq_all() // particularly to ensure sight modes are cleared
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
//These procs handle putting stuff in your hand. It's probably best to use these rather than setting stuff manually
|
||||
//as they handle all relevant stuff like adding it to the player's screen and such
|
||||
|
||||
//Returns the thing in our active hand (whatever is in our active module-slot, in this case)
|
||||
//This proc has been butchered into a proc that overrides borg item holding for the sake of making grippers work.
|
||||
//I'd be immensely thankful if anyone can figure out a less obtuse way of making grippers work without breaking functionality.
|
||||
/**
|
||||
* Returns the thing in our active hand (whatever is in our active module-slot, in this case)
|
||||
*/
|
||||
/mob/living/silicon/robot/get_active_held_item()
|
||||
var/item = module_active
|
||||
// snowflake handler for the gripper
|
||||
if(istype(item, /obj/item/weapon/gripper))
|
||||
var/obj/item/weapon/gripper/G = item
|
||||
if(G.wrapped)
|
||||
@@ -15,230 +16,416 @@
|
||||
item = G.wrapped
|
||||
return item
|
||||
return module_active
|
||||
/**
|
||||
* Parent proc - triggers when an item/module is unequipped from a cyborg.
|
||||
*/
|
||||
/obj/item/proc/cyborg_unequip(mob/user)
|
||||
return
|
||||
|
||||
/mob/living/silicon/robot/proc/uneq_module(obj/item/O)
|
||||
if(!O)
|
||||
return 0
|
||||
O.mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
if(istype(O, /obj/item/borg/sight))
|
||||
var/obj/item/borg/sight/S = O
|
||||
sight_mode &= ~S.sight_mode
|
||||
/**
|
||||
* Finds the first available slot and attemps to put item item_module in it.
|
||||
*
|
||||
* Arguments
|
||||
* * item_module - the item being equipped to a slot.
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/activate_module(obj/item/item_module)
|
||||
if(QDELETED(item_module))
|
||||
CRASH("activate_module called with improper item_module")
|
||||
|
||||
if(!(item_module in module.modules))
|
||||
CRASH("activate_module called with item_module not in module.modules")
|
||||
|
||||
if(activated(item_module))
|
||||
to_chat(src, "<span class='warning'>That module is already activated.</span>")
|
||||
return FALSE
|
||||
|
||||
if(disabled_modules & BORG_MODULE_ALL_DISABLED)
|
||||
to_chat(src, "<span class='warning'>All modules are disabled!</span>")
|
||||
return FALSE
|
||||
|
||||
/// What's the first free slot for the borg?
|
||||
var/first_free_slot = !held_items[1] ? 1 : (!held_items[2] ? 2 : (!held_items[3] ? 3 : null))
|
||||
|
||||
if(!first_free_slot || is_invalid_module_number(first_free_slot))
|
||||
to_chat(src, "<span class='warning'>Deactivate a module first!</span>")
|
||||
return FALSE
|
||||
|
||||
return equip_module_to_slot(item_module, first_free_slot)
|
||||
|
||||
/**
|
||||
* Is passed an item and a module slot. Equips the item to that borg slot.
|
||||
*
|
||||
* Arguments
|
||||
* * item_module - the item being equipped to a slot
|
||||
* * module_num - the slot number being equipped to.
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/equip_module_to_slot(obj/item/item_module, module_num)
|
||||
var/storage_was_closed = FALSE //Just to be consistant and all
|
||||
if(!shown_robot_modules) //Tools may be invisible if the collection is hidden
|
||||
hud_used.toggle_show_robot_modules()
|
||||
storage_was_closed = TRUE
|
||||
switch(module_num)
|
||||
if(1)
|
||||
item_module.screen_loc = inv1.screen_loc
|
||||
if(2)
|
||||
item_module.screen_loc = inv2.screen_loc
|
||||
if(3)
|
||||
item_module.screen_loc = inv3.screen_loc
|
||||
|
||||
held_items[module_num] = item_module
|
||||
item_module.equipped(src, ITEM_SLOT_HANDS)
|
||||
item_module.mouse_opacity = initial(item_module.mouse_opacity)
|
||||
item_module.layer = ABOVE_HUD_LAYER
|
||||
item_module.plane = ABOVE_HUD_PLANE
|
||||
item_module.forceMove(src)
|
||||
|
||||
if(istype(item_module, /obj/item/borg/sight))
|
||||
var/obj/item/borg/sight/borg_sight = item_module
|
||||
sight_mode |= borg_sight.sight_mode
|
||||
update_sight()
|
||||
|
||||
observer_screen_update(item_module, TRUE)
|
||||
|
||||
if(storage_was_closed)
|
||||
hud_used.toggle_show_robot_modules()
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Unequips item item_module from slot module_num. Deletes it if delete_after = TRUE.
|
||||
*
|
||||
* Arguments
|
||||
* * item_module - the item being unequipped
|
||||
* * module_num - the slot number being unequipped.
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/unequip_module_from_slot(obj/item/item_module, module_num)
|
||||
if(QDELETED(item_module))
|
||||
CRASH("unequip_module_from_slot called with improper item_module")
|
||||
|
||||
if(!(item_module in module.modules))
|
||||
CRASH("unequip_module_from_slot called with item_module not in module.modules")
|
||||
|
||||
item_module.mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
|
||||
if(istype(item_module, /obj/item/storage/bag/tray/))
|
||||
SEND_SIGNAL(item_module, COMSIG_TRY_STORAGE_QUICK_EMPTY)
|
||||
if(istype(item_module, /obj/item/borg/sight))
|
||||
var/obj/item/borg/sight/borg_sight = item_module
|
||||
sight_mode &= ~borg_sight.sight_mode
|
||||
update_sight()
|
||||
else if(istype(O, /obj/item/storage/bag/tray/))
|
||||
SEND_SIGNAL(O, COMSIG_TRY_STORAGE_QUICK_EMPTY)
|
||||
//CITADEL EDIT reee proc, Dogborg modules
|
||||
if(istype(O,/obj/item/gun/energy/laser/cyborg))
|
||||
if(istype(item_module, /obj/item/gun/energy/laser/cyborg))
|
||||
laser = FALSE
|
||||
update_icons()
|
||||
else if(istype(O,/obj/item/gun/energy/disabler/cyborg) || istype(O,/obj/item/gun/energy/e_gun/advtaser/cyborg))
|
||||
if(istype(item_module, /obj/item/gun/energy/disabler/cyborg) || istype(item_module, /obj/item/gun/energy/e_gun/advtaser/cyborg))
|
||||
disabler = FALSE
|
||||
update_icons() //PUT THE GUN AWAY
|
||||
else if(istype(O,/obj/item/dogborg/sleeper))
|
||||
if(istype(item_module, /obj/item/dogborg/sleeper))
|
||||
sleeper_g = FALSE
|
||||
sleeper_r = FALSE
|
||||
update_icons()
|
||||
var/obj/item/dogborg/sleeper/S = O
|
||||
var/obj/item/dogborg/sleeper/S = item_module
|
||||
S.go_out() //this should stop edgecase deletions
|
||||
//END CITADEL EDIT
|
||||
|
||||
if(client)
|
||||
client.screen -= O
|
||||
observer_screen_update(O,FALSE)
|
||||
client.screen -= item_module
|
||||
|
||||
if(module_active == O)
|
||||
if(module_active == item_module)
|
||||
module_active = null
|
||||
if(held_items[1] == O)
|
||||
inv1.icon_state = "inv1"
|
||||
held_items[1] = null
|
||||
else if(held_items[2] == O)
|
||||
inv2.icon_state = "inv2"
|
||||
held_items[2] = null
|
||||
else if(held_items[3] == O)
|
||||
inv3.icon_state = "inv3"
|
||||
held_items[3] = null
|
||||
|
||||
if(O.item_flags & DROPDEL)
|
||||
O.item_flags &= ~DROPDEL //we shouldn't HAVE things with DROPDEL_1 in our modules, but better safe than runtiming horribly
|
||||
switch(module_num)
|
||||
if(1)
|
||||
if(!(disabled_modules & BORG_MODULE_ALL_DISABLED))
|
||||
inv1.icon_state = initial(inv1.icon_state)
|
||||
if(2)
|
||||
if(!(disabled_modules & BORG_MODULE_TWO_DISABLED))
|
||||
inv2.icon_state = initial(inv2.icon_state)
|
||||
if(3)
|
||||
if(!(disabled_modules & BORG_MODULE_THREE_DISABLED))
|
||||
inv3.icon_state = initial(inv3.icon_state)
|
||||
|
||||
O.forceMove(module) //Return item to module so it appears in its contents, so it can be taken out again.
|
||||
if(item_module.item_flags & DROPDEL)
|
||||
item_module.item_flags &= ~DROPDEL //we shouldn't HAVE things with DROPDEL_1 in our modules, but better safe than runtiming horribly
|
||||
|
||||
held_items[module_num] = null
|
||||
item_module.cyborg_unequip(src)
|
||||
item_module.forceMove(module) //Return item to module so it appears in its contents, so it can be taken out again.
|
||||
|
||||
observer_screen_update(item_module, FALSE)
|
||||
hud_used.update_robot_modules_display()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/mob/living/silicon/robot/proc/activate_module(obj/item/O)
|
||||
. = FALSE
|
||||
if(!(O in module.modules))
|
||||
return
|
||||
//CITADEL EDIT Dogborg lasers
|
||||
if(istype(O,/obj/item/gun/energy/laser/cyborg))
|
||||
laser = TRUE
|
||||
update_icons() //REEEEEEACH FOR THE SKY
|
||||
if(istype(O,/obj/item/gun/energy/disabler/cyborg) || istype(O,/obj/item/gun/energy/e_gun/advtaser/cyborg))
|
||||
disabler = TRUE
|
||||
update_icons()
|
||||
//END CITADEL EDIT
|
||||
if(activated(O))
|
||||
to_chat(src, "<span class='warning'>That module is already activated.</span>")
|
||||
return
|
||||
if(!held_items[1] && health >= -maxHealth*0.5)
|
||||
held_items[1] = O
|
||||
O.screen_loc = inv1.screen_loc
|
||||
. = TRUE
|
||||
else if(!held_items[2] && health >= 0)
|
||||
held_items[2] = O
|
||||
O.screen_loc = inv2.screen_loc
|
||||
. = TRUE
|
||||
else if(!held_items[3] && health >= maxHealth*0.5)
|
||||
held_items[3] = O
|
||||
O.screen_loc = inv3.screen_loc
|
||||
. = TRUE
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You need to disable a module first!</span>")
|
||||
if(.)
|
||||
O.equipped(src, SLOT_HANDS)
|
||||
O.mouse_opacity = initial(O.mouse_opacity)
|
||||
O.layer = ABOVE_HUD_LAYER
|
||||
O.plane = ABOVE_HUD_PLANE
|
||||
observer_screen_update(O,TRUE)
|
||||
O.forceMove(src)
|
||||
if(istype(O, /obj/item/borg/sight))
|
||||
var/obj/item/borg/sight/S = O
|
||||
sight_mode |= S.sight_mode
|
||||
update_sight()
|
||||
/**
|
||||
* Breaks the slot number, changing the icon.
|
||||
*
|
||||
* Arguments
|
||||
* * module_num - the slot number being repaired.
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/break_cyborg_slot(module_num)
|
||||
if(is_invalid_module_number(module_num, TRUE))
|
||||
return FALSE
|
||||
|
||||
if(held_items[module_num]) //If there's a held item, unequip it first.
|
||||
if(!unequip_module_from_slot(held_items[module_num], module_num)) //If we fail to unequip it, then don't continue
|
||||
return FALSE
|
||||
|
||||
/mob/living/silicon/robot/proc/observer_screen_update(obj/item/I,add = TRUE)
|
||||
if(observers && observers.len)
|
||||
switch(module_num)
|
||||
if(1)
|
||||
if(disabled_modules & BORG_MODULE_ALL_DISABLED)
|
||||
return FALSE
|
||||
|
||||
inv1.icon_state = "[initial(inv1.icon_state)] +b"
|
||||
disabled_modules |= BORG_MODULE_ALL_DISABLED
|
||||
|
||||
playsound(src, 'sound/machines/warning-buzzer.ogg', 75, TRUE, TRUE)
|
||||
audible_message("<span class='warning'>[src] sounds an alarm! \"CRITICAL ERROR: ALL modules OFFLINE.\"</span>")
|
||||
|
||||
if(builtInCamera)
|
||||
builtInCamera.status = FALSE
|
||||
to_chat(src, "<span class='userdanger'>CRITICAL ERROR: Built in security camera OFFLINE.</span>")
|
||||
|
||||
to_chat(src, "<span class='userdanger'>CRITICAL ERROR: ALL modules OFFLINE.</span>")
|
||||
|
||||
if(2)
|
||||
if(disabled_modules & BORG_MODULE_TWO_DISABLED)
|
||||
return FALSE
|
||||
|
||||
inv2.icon_state = "[initial(inv2.icon_state)] +b"
|
||||
disabled_modules |= BORG_MODULE_TWO_DISABLED
|
||||
|
||||
playsound(src, 'sound/machines/warning-buzzer.ogg', 60, TRUE, TRUE)
|
||||
audible_message("<span class='warning'>[src] sounds an alarm! \"SYSTEM ERROR: Module [module_num] OFFLINE.\"</span>")
|
||||
to_chat(src, "<span class='userdanger'>SYSTEM ERROR: Module [module_num] OFFLINE.</span>")
|
||||
|
||||
if(3)
|
||||
if(disabled_modules & BORG_MODULE_THREE_DISABLED)
|
||||
return FALSE
|
||||
|
||||
inv3.icon_state = "[initial(inv3.icon_state)] +b"
|
||||
disabled_modules |= BORG_MODULE_THREE_DISABLED
|
||||
|
||||
playsound(src, 'sound/machines/warning-buzzer.ogg', 50, TRUE, TRUE)
|
||||
audible_message("<span class='warning'>[src] sounds an alarm! \"SYSTEM ERROR: Module [module_num] OFFLINE.\"</span>")
|
||||
to_chat(src, "<span class='userdanger'>SYSTEM ERROR: Module [module_num] OFFLINE.</span>")
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Breaks all of a cyborg's slots.
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/break_all_cyborg_slots()
|
||||
for(var/cyborg_slot in 1 to 3)
|
||||
break_cyborg_slot(cyborg_slot)
|
||||
|
||||
/**
|
||||
* Repairs the slot number, updating the icon.
|
||||
*
|
||||
* Arguments
|
||||
* * module_num - the module number being repaired.
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/repair_cyborg_slot(module_num)
|
||||
if(is_invalid_module_number(module_num, TRUE))
|
||||
return FALSE
|
||||
|
||||
switch(module_num)
|
||||
if(1)
|
||||
if(!(disabled_modules & BORG_MODULE_ALL_DISABLED))
|
||||
return FALSE
|
||||
|
||||
inv1.icon_state = initial(inv1.icon_state)
|
||||
disabled_modules &= ~BORG_MODULE_ALL_DISABLED
|
||||
if(builtInCamera)
|
||||
builtInCamera.status = TRUE
|
||||
to_chat(src, "<span class='notice'>You hear your built in security camera focus adjust as it comes back online!</span>")
|
||||
if(2)
|
||||
if(!(disabled_modules & BORG_MODULE_TWO_DISABLED))
|
||||
return FALSE
|
||||
|
||||
inv2.icon_state = initial(inv2.icon_state)
|
||||
disabled_modules &= ~BORG_MODULE_TWO_DISABLED
|
||||
if(3)
|
||||
if(!(disabled_modules & BORG_MODULE_THREE_DISABLED))
|
||||
return FALSE
|
||||
|
||||
inv3.icon_state = initial(inv3.icon_state)
|
||||
disabled_modules &= ~BORG_MODULE_THREE_DISABLED
|
||||
|
||||
to_chat(src, "<span class='notice'>ERROR CLEARED: Module [module_num] back online.</span>")
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Repairs all slots. Unbroken slots are unaffected.
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/repair_all_cyborg_slots()
|
||||
for(var/cyborg_slot in 1 to 3)
|
||||
repair_cyborg_slot(cyborg_slot)
|
||||
|
||||
/**
|
||||
* Updates the observers's screens with cyborg itemss.
|
||||
* Arguments
|
||||
* * item_module - the item being added or removed from the screen
|
||||
* * add - whether or not the item is being added, or removed.
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/observer_screen_update(obj/item/item_module, add = TRUE)
|
||||
if(observers?.len)
|
||||
for(var/M in observers)
|
||||
var/mob/dead/observe = M
|
||||
if(observe.client && observe.client.eye == src)
|
||||
if(add)
|
||||
observe.client.screen += I
|
||||
observe.client.screen += item_module
|
||||
else
|
||||
observe.client.screen -= I
|
||||
observe.client.screen -= item_module
|
||||
else
|
||||
observers -= observe
|
||||
if(!observers.len)
|
||||
observers = null
|
||||
break
|
||||
|
||||
/**
|
||||
* Unequips the active held item, if there is one.
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/uneq_active()
|
||||
uneq_module(module_active)
|
||||
if(module_active)
|
||||
unequip_module_from_slot(module_active, get_selected_module())
|
||||
|
||||
/**
|
||||
* Unequips all held items.
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/uneq_all()
|
||||
for(var/obj/item/I in held_items)
|
||||
uneq_module(I)
|
||||
for(var/cyborg_slot in 1 to 3)
|
||||
if(!held_items[cyborg_slot])
|
||||
continue
|
||||
unequip_module_from_slot(held_items[cyborg_slot], cyborg_slot)
|
||||
|
||||
/mob/living/silicon/robot/proc/activated(obj/item/O)
|
||||
if(O in held_items)
|
||||
/**
|
||||
* Checks if the item is currently in a slot.
|
||||
*
|
||||
* If the item is found in a slot, this returns TRUE. Otherwise, it returns FALSE
|
||||
* Arguments
|
||||
* * item_module - the item being checked
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/activated(obj/item/item_module)
|
||||
if(item_module in held_items)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//Helper procs for cyborg modules on the UI.
|
||||
//These are hackish but they help clean up code elsewhere.
|
||||
/**
|
||||
* Checks if the provided module number is a valid number.
|
||||
*
|
||||
* If the number is between 1 and 3 (if check_all_slots is true) or between 1 and the number of disabled
|
||||
* modules (if check_all_slots is false), then it returns FALSE. Otherwise, it returns TRUE.
|
||||
* Arguments
|
||||
* * module_num - the passed module num that is checked for validity.
|
||||
* * check_all_slots - TRUE = the proc checks all slots | FALSE = the proc only checks un-disabled slots
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/is_invalid_module_number(module_num, check_all_slots = FALSE)
|
||||
if(!module_num)
|
||||
return TRUE
|
||||
|
||||
//module_selected(module) - Checks whether the module slot specified by "module" is currently selected.
|
||||
/mob/living/silicon/robot/proc/module_selected(module) //Module is 1-3
|
||||
return module == get_selected_module()
|
||||
/// The number of module slots we're checking
|
||||
var/max_number = 3
|
||||
if(!check_all_slots)
|
||||
if(disabled_modules & BORG_MODULE_ALL_DISABLED)
|
||||
max_number = 0
|
||||
else if(disabled_modules & BORG_MODULE_TWO_DISABLED)
|
||||
max_number = 1
|
||||
else if(disabled_modules & BORG_MODULE_THREE_DISABLED)
|
||||
max_number = 2
|
||||
|
||||
//module_active(module) - Checks whether there is a module active in the slot specified by "module".
|
||||
/mob/living/silicon/robot/proc/module_active(module) //Module is 1-3
|
||||
if(module < 1 || module > 3)
|
||||
return FALSE
|
||||
return module_num < 1 || module_num > max_number
|
||||
|
||||
if(LAZYLEN(held_items) >= module)
|
||||
if(held_items[module])
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//get_selected_module() - Returns the slot number of the currently selected module. Returns 0 if no modules are selected.
|
||||
/**
|
||||
* Returns the slot number of the selected module, or zero if no modules are selected.
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/get_selected_module()
|
||||
if(module_active)
|
||||
return held_items.Find(module_active)
|
||||
|
||||
return 0
|
||||
|
||||
//select_module(module) - Selects the module slot specified by "module"
|
||||
/mob/living/silicon/robot/proc/select_module(module) //Module is 1-3
|
||||
if(module < 1 || module > 3)
|
||||
return
|
||||
/**
|
||||
* Selects the module in the slot module_num.
|
||||
* Arguments
|
||||
* * module_num - the slot number being selected
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/select_module(module_num)
|
||||
if(is_invalid_module_number(module_num) || !held_items[module_num]) //If the slot number is invalid, or there's nothing there, we have nothing to equip
|
||||
return FALSE
|
||||
|
||||
if(!module_active(module))
|
||||
return
|
||||
|
||||
switch(module)
|
||||
switch(module_num)
|
||||
if(1)
|
||||
if(module_active != held_items[module])
|
||||
inv1.icon_state = "inv1 +a"
|
||||
inv2.icon_state = "inv2"
|
||||
inv3.icon_state = "inv3"
|
||||
if(module_active != held_items[module_num])
|
||||
inv1.icon_state = "[initial(inv1.icon_state)] +a"
|
||||
if(2)
|
||||
if(module_active != held_items[module])
|
||||
inv1.icon_state = "inv1"
|
||||
inv2.icon_state = "inv2 +a"
|
||||
inv3.icon_state = "inv3"
|
||||
if(module_active != held_items[module_num])
|
||||
inv2.icon_state = "[initial(inv2.icon_state)] +a"
|
||||
if(3)
|
||||
if(module_active != held_items[module])
|
||||
inv1.icon_state = "inv1"
|
||||
inv2.icon_state = "inv2"
|
||||
inv3.icon_state = "inv3 +a"
|
||||
module_active = held_items[module]
|
||||
if(module_active != held_items[module_num])
|
||||
inv3.icon_state = "[initial(inv3.icon_state)] +a"
|
||||
module_active = held_items[module_num]
|
||||
return TRUE
|
||||
|
||||
//deselect_module(module) - Deselects the module slot specified by "module"
|
||||
/mob/living/silicon/robot/proc/deselect_module(module) //Module is 1-3
|
||||
if(module < 1 || module > 3)
|
||||
return
|
||||
|
||||
if(!module_active(module))
|
||||
return
|
||||
|
||||
switch(module)
|
||||
/**
|
||||
* Deselects the module in the slot module_num.
|
||||
* Arguments
|
||||
* * module_num - the slot number being de-selected
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/deselect_module(module_num)
|
||||
switch(module_num)
|
||||
if(1)
|
||||
if(module_active == held_items[module])
|
||||
inv1.icon_state = "inv1"
|
||||
if(module_active == held_items[module_num])
|
||||
inv1.icon_state = initial(inv1.icon_state)
|
||||
if(2)
|
||||
if(module_active == held_items[module])
|
||||
inv2.icon_state = "inv2"
|
||||
if(module_active == held_items[module_num])
|
||||
inv2.icon_state = initial(inv2.icon_state)
|
||||
if(3)
|
||||
if(module_active == held_items[module])
|
||||
inv3.icon_state = "inv3"
|
||||
if(module_active == held_items[module_num])
|
||||
inv3.icon_state = initial(inv3.icon_state)
|
||||
module_active = null
|
||||
return TRUE
|
||||
|
||||
//toggle_module(module) - Toggles the selection of the module slot specified by "module".
|
||||
/mob/living/silicon/robot/proc/toggle_module(module) //Module is 1-3
|
||||
if(module < 1 || module > 3)
|
||||
return
|
||||
/**
|
||||
* Toggles selection of the module in the slot module_num.
|
||||
* Arguments
|
||||
* * module_num - the slot number being toggled
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/toggle_module(module_num)
|
||||
if(is_invalid_module_number(module_num))
|
||||
return FALSE
|
||||
|
||||
if(module_selected(module))
|
||||
deselect_module(module)
|
||||
else
|
||||
if(module_active(module))
|
||||
select_module(module)
|
||||
else
|
||||
deselect_module(get_selected_module()) //If we can't do select anything, at least deselect the current module.
|
||||
return
|
||||
if(module_num == get_selected_module())
|
||||
deselect_module(module_num)
|
||||
return TRUE
|
||||
|
||||
//cycle_modules() - Cycles through the list of selected modules.
|
||||
if(module_active != held_items[module_num])
|
||||
deselect_module(get_selected_module())
|
||||
|
||||
return select_module(module_num)
|
||||
|
||||
/**
|
||||
* Cycles through the list of enabled modules, deselecting the current one and selecting the next one.
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/cycle_modules()
|
||||
var/slot_start = get_selected_module()
|
||||
var/slot_num
|
||||
if(slot_start)
|
||||
deselect_module(slot_start) //Only deselect if we have a selected slot.
|
||||
|
||||
var/slot_num
|
||||
if(slot_start == 0)
|
||||
slot_num = slot_start + 1
|
||||
else
|
||||
slot_num = 1
|
||||
slot_start = 4
|
||||
else
|
||||
slot_num = slot_start + 1
|
||||
|
||||
while(slot_num != slot_start) //If we wrap around without finding any free slots, just give up.
|
||||
if(module_active(slot_num))
|
||||
select_module(slot_num)
|
||||
if(select_module(slot_num))
|
||||
return
|
||||
slot_num++
|
||||
if(slot_num > 4) // not >3 otherwise cycling with just one item on module 3 wouldn't work
|
||||
slot_num = 1 //Wrap around.
|
||||
|
||||
|
||||
|
||||
/mob/living/silicon/robot/swap_hand()
|
||||
cycle_modules()
|
||||
|
||||
/mob/living/silicon/robot/can_hold_items(obj/item/I)
|
||||
return (I && (I in module.modules)) //Only if it's part of our module.
|
||||
|
||||
|
||||
@@ -8,22 +8,21 @@
|
||||
/mob/living/silicon/robot/proc/handle_robot_cell()
|
||||
if(stat != DEAD)
|
||||
if(low_power_mode)
|
||||
if(cell && cell.charge)
|
||||
low_power_mode = 0
|
||||
update_headlamp()
|
||||
if(cell?.charge)
|
||||
low_power_mode = FALSE
|
||||
else if(stat == CONSCIOUS)
|
||||
use_power()
|
||||
|
||||
/mob/living/silicon/robot/proc/use_power()
|
||||
if(cell && cell.charge)
|
||||
if(cell?.charge)
|
||||
if(cell.charge <= 100)
|
||||
uneq_all()
|
||||
var/amt = clamp((lamp_intensity - 2) * 2,1,cell.charge) //Always try to use at least one charge per tick, but allow it to completely drain the cell.
|
||||
var/amt = clamp((lamp_enabled * lamp_intensity),1,cell.charge) //Lamp will use a max of 5 charge, depending on brightness of lamp. If lamp is off, borg systems consume 1 point of charge, or the rest of the cell if it's lower than that.
|
||||
cell.use(amt) //Usage table: 1/tick if off/lowest setting, 4 = 4/tick, 6 = 8/tick, 8 = 12/tick, 10 = 16/tick
|
||||
else
|
||||
uneq_all()
|
||||
low_power_mode = 1
|
||||
update_headlamp()
|
||||
low_power_mode = TRUE
|
||||
toggle_headlamp(TRUE)
|
||||
diag_hud_set_borgcell()
|
||||
|
||||
/mob/living/silicon/robot/proc/handle_robot_hud_updates()
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
wires = new /datum/wires/robot(src)
|
||||
AddElement(/datum/element/empprotection, EMP_PROTECT_WIRES)
|
||||
|
||||
// AddElement(/datum/element/ridable, /datum/component/riding/creature/cyborg)
|
||||
RegisterSignal(src, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, .proc/charge)
|
||||
|
||||
robot_modules_background = new()
|
||||
@@ -23,10 +23,16 @@
|
||||
robot_modules_background.layer = HUD_LAYER //Objects that appear on screen are on layer ABOVE_HUD_LAYER, UI should be just below it.
|
||||
robot_modules_background.plane = HUD_PLANE
|
||||
|
||||
ident = rand(1, 999)
|
||||
inv1 = new /obj/screen/robot/module1()
|
||||
inv2 = new /obj/screen/robot/module2()
|
||||
inv3 = new /obj/screen/robot/module3()
|
||||
|
||||
if(!cell)
|
||||
cell = new /obj/item/stock_parts/cell/high(src)
|
||||
previous_health = health
|
||||
|
||||
if(ispath(cell))
|
||||
cell = new cell(src)
|
||||
|
||||
create_modularInterface()
|
||||
|
||||
if(lawupdate)
|
||||
make_laws()
|
||||
@@ -63,18 +69,23 @@
|
||||
mmi.brainmob.real_name = src.real_name
|
||||
mmi.brainmob.container = mmi
|
||||
|
||||
updatename()
|
||||
INVOKE_ASYNC(src, .proc/updatename)
|
||||
|
||||
equippable_hats = typecacheof(equippable_hats)
|
||||
|
||||
playsound(loc, 'sound/voice/liveagain.ogg', 75, 1)
|
||||
playsound(loc, 'sound/voice/liveagain.ogg', 75, TRUE)
|
||||
aicamera = new/obj/item/camera/siliconcam/robot_camera(src)
|
||||
toner = tonermax
|
||||
diag_hud_set_borgcell()
|
||||
logevent("System brought online.")
|
||||
|
||||
add_verb(src, /mob/living/proc/lay_down) //CITADEL EDIT gimmie rest verb kthx
|
||||
add_verb(src, /mob/living/silicon/robot/proc/rest_style)
|
||||
|
||||
/mob/living/silicon/robot/proc/create_modularInterface()
|
||||
if(!modularInterface)
|
||||
modularInterface = new /obj/item/modular_computer/tablet/integrated(src)
|
||||
modularInterface.layer = ABOVE_HUD_PLANE
|
||||
modularInterface.plane = ABOVE_HUD_PLANE
|
||||
|
||||
//If there's an MMI in the robot, have it ejected when the mob goes away. --NEO
|
||||
/mob/living/silicon/robot/Destroy()
|
||||
var/atom/T = drop_location()//To hopefully prevent run time errors.
|
||||
@@ -93,28 +104,31 @@
|
||||
ghostize()
|
||||
stack_trace("Borg MMI lacked a brainmob")
|
||||
mmi = null
|
||||
//CITADEL EDIT: Cyborgs drop encryption keys on destroy
|
||||
if(istype(radio) && istype(radio.keyslot))
|
||||
radio.keyslot.forceMove(T)
|
||||
radio.keyslot = null
|
||||
//END CITADEL EDIT
|
||||
if(modularInterface)
|
||||
QDEL_NULL(modularInterface)
|
||||
if(connected_ai)
|
||||
set_connected_ai(null)
|
||||
if(shell)
|
||||
if(shell) //??? why would you give an ai radio keys?
|
||||
GLOB.available_ai_shells -= src
|
||||
else
|
||||
if(T && istype(radio) && istype(radio.keyslot))
|
||||
radio.keyslot.forceMove(T)
|
||||
radio.keyslot = null
|
||||
qdel(wires)
|
||||
qdel(module)
|
||||
qdel(eye_lights)
|
||||
wires = null
|
||||
module = null
|
||||
eye_lights = null
|
||||
QDEL_NULL(wires)
|
||||
QDEL_NULL(module)
|
||||
QDEL_NULL(eye_lights)
|
||||
QDEL_NULL(inv1)
|
||||
QDEL_NULL(inv2)
|
||||
QDEL_NULL(inv3)
|
||||
cell = null
|
||||
return ..()
|
||||
|
||||
// /mob/living/silicon/robot/Topic(href, href_list)
|
||||
// . = ..()
|
||||
// //Show alerts window if user clicked on "Show alerts" in chat
|
||||
// if (href_list["showalerts"])
|
||||
// robot_alerts()
|
||||
|
||||
/mob/living/silicon/robot/proc/pick_module()
|
||||
if(module.type != /obj/item/robot_module)
|
||||
return
|
||||
@@ -136,7 +150,7 @@
|
||||
if(BORG_SEC_AVAILABLE)
|
||||
modulelist["Security"] = /obj/item/robot_module/security
|
||||
|
||||
var/input_module = input("Please, select a module!", "Robot", null, null) as null|anything in modulelist
|
||||
var/input_module = input("Please, select a module!", "Robot", null, null) as null|anything in sortList(modulelist)
|
||||
if(!input_module || module.type != /obj/item/robot_module)
|
||||
return
|
||||
|
||||
@@ -151,9 +165,11 @@
|
||||
var/changed_name = ""
|
||||
if(custom_name)
|
||||
changed_name = custom_name
|
||||
if(changed_name == "" && C && C.prefs.custom_names["cyborg"] != DEFAULT_CYBORG_NAME)
|
||||
if(apply_pref_name("cyborg", C))
|
||||
return //built in camera handled in proc
|
||||
// if(SSticker.anonymousnames) //only robotic renames will allow for anything other than the anonymous one
|
||||
// changed_name = anonymous_ai_name(is_ai = FALSE)
|
||||
if(!changed_name && C && C.prefs.custom_names["cyborg"] != DEFAULT_CYBORG_NAME)
|
||||
apply_pref_name("cyborg", C)
|
||||
return //built in camera handled in proc
|
||||
if(!changed_name)
|
||||
changed_name = get_standard_name()
|
||||
|
||||
@@ -262,7 +278,7 @@
|
||||
C = O
|
||||
L[A.name] = list(A, (C) ? C : O, list(alarmsource))
|
||||
queueAlarm(text("--- [class] alarm detected in [A.name]!"), class)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/mob/living/silicon/robot/cancelAlarm(class, area/A, obj/origin)
|
||||
var/list/L = alarms[class]
|
||||
@@ -281,6 +297,8 @@
|
||||
return !cleared
|
||||
|
||||
/mob/living/silicon/robot/can_interact_with(atom/A)
|
||||
if (A == modularInterface)
|
||||
return TRUE //bypass for borg tablets
|
||||
if (low_power_mode)
|
||||
return FALSE
|
||||
var/turf/T0 = get_turf(src)
|
||||
@@ -475,19 +493,6 @@
|
||||
toner = tonermax
|
||||
qdel(W)
|
||||
to_chat(user, "<span class='notice'>You fill the toner level of [src] to its max capacity.</span>")
|
||||
|
||||
else if(istype(W, /obj/item/flashlight))
|
||||
if(!opened)
|
||||
to_chat(user, "<span class='warning'>You need to open the panel to repair the headlamp!</span>")
|
||||
else if(lamp_cooldown <= world.time)
|
||||
to_chat(user, "<span class='warning'>The headlamp is already functional!</span>")
|
||||
else
|
||||
if(!user.temporarilyRemoveItemFromInventory(W))
|
||||
to_chat(user, "<span class='warning'>[W] seems to be stuck to your hand. You'll have to find a different light.</span>")
|
||||
return
|
||||
lamp_cooldown = 0
|
||||
qdel(W)
|
||||
to_chat(user, "<span class='notice'>You replace the headlamp bulbs.</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -520,47 +525,46 @@
|
||||
/mob/living/silicon/robot/proc/allowed(mob/M)
|
||||
//check if it doesn't require any access at all
|
||||
if(check_access(null))
|
||||
return 1
|
||||
return TRUE
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
//if they are holding or wearing a card that has access, that works
|
||||
if(check_access(H.get_active_held_item()) || check_access(H.wear_id))
|
||||
return 1
|
||||
return TRUE
|
||||
else if(ismonkey(M))
|
||||
var/mob/living/carbon/monkey/george = M
|
||||
//they can only hold things :(
|
||||
if(isitem(george.get_active_held_item()))
|
||||
return check_access(george.get_active_held_item())
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
/mob/living/silicon/robot/proc/check_access(obj/item/card/id/I)
|
||||
if(!istype(req_access, /list)) //something's very wrong
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
var/list/L = req_access
|
||||
if(!L.len) //no requirements
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(!istype(I, /obj/item/card/id) && isitem(I))
|
||||
I = I.GetID()
|
||||
|
||||
if(!I || !I.access) //not ID or no access
|
||||
return 0
|
||||
return FALSE
|
||||
for(var/req in req_access)
|
||||
if(!(req in I.access)) //doesn't have this access
|
||||
return 0
|
||||
return 1
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/mob/living/silicon/robot/regenerate_icons()
|
||||
return update_icons()
|
||||
|
||||
/mob/living/silicon/robot/proc/self_destruct()
|
||||
if(emagged)
|
||||
if(mmi)
|
||||
qdel(mmi)
|
||||
explosion(src.loc,1,2,4,flame_range = 2)
|
||||
QDEL_NULL(mmi)
|
||||
explosion(loc,1,2,4,flame_range = 2)
|
||||
else
|
||||
explosion(src.loc,-1,0,2)
|
||||
explosion(loc,-1,0,2)
|
||||
gib()
|
||||
|
||||
/mob/living/silicon/robot/proc/UnlinkSelf()
|
||||
@@ -599,6 +603,8 @@
|
||||
clear_alert("locked")
|
||||
locked_down = state
|
||||
update_mobility()
|
||||
logevent("System lockdown [locked_down?"triggered":"released"].")
|
||||
|
||||
|
||||
/mob/living/silicon/robot/proc/SetEmagged(new_state)
|
||||
emagged = new_state
|
||||
@@ -609,6 +615,22 @@
|
||||
else
|
||||
clear_alert("hacked")
|
||||
|
||||
/**
|
||||
* Handles headlamp smashing
|
||||
*
|
||||
* When called (such as by the shadowperson lighteater's attack), this proc will break the borg's headlamp
|
||||
* and then call toggle_headlamp to disable the light. It also plays a sound effect of glass breaking, and
|
||||
* tells the borg what happened to its chat. Broken lights can be repaired by using a flashlight on the borg.
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/smash_headlamp()
|
||||
if(!lamp_functional)
|
||||
return
|
||||
lamp_functional = FALSE
|
||||
playsound(src, 'sound/effects/glass_step.ogg', 50)
|
||||
toggle_headlamp(TRUE)
|
||||
to_chat(src, "<span class='danger'>Your headlamp is broken! You'll need a human to help replace it.</span>")
|
||||
|
||||
|
||||
/mob/living/silicon/robot/verb/outputlaws()
|
||||
set category = "Robot Commands"
|
||||
set name = "State Laws"
|
||||
@@ -626,32 +648,40 @@
|
||||
return //won't work if dead
|
||||
set_autosay()
|
||||
|
||||
/mob/living/silicon/robot/proc/control_headlamp()
|
||||
if(stat || lamp_cooldown > world.time || low_power_mode)
|
||||
to_chat(src, "<span class='danger'>This function is currently offline.</span>")
|
||||
/**
|
||||
* Handles headlamp toggling, disabling, and color setting.
|
||||
*
|
||||
* The initial if statment is a bit long, but the gist of it is that should the lamp be on AND the update_color
|
||||
* arg be true, we should simply change the color of the lamp but not disable it. Otherwise, should the turn_off
|
||||
* arg be true, the lamp already be enabled, any of the normal reasons the lamp would turn off happen, or the
|
||||
* update_color arg be passed with the lamp not on, we should set the lamp off. The update_color arg is only
|
||||
* ever true when this proc is called from the borg tablet, when the color selection feature is used.
|
||||
*
|
||||
* Arguments:
|
||||
* * arg1 - turn_off, if enabled will force the lamp into an off state (rather than toggling it if possible)
|
||||
* * arg2 - update_color, if enabled, will adjust the behavior of the proc to change the color of the light if it is already on.
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/toggle_headlamp(turn_off = FALSE, update_color = FALSE)
|
||||
//if both lamp is enabled AND the update_color flag is on, keep the lamp on. Otherwise, if anything listed is true, disable the lamp.
|
||||
if(!(update_color && lamp_enabled) && (turn_off || lamp_enabled || update_color || !lamp_functional || stat || low_power_mode))
|
||||
set_light((lamp_functional && stat != DEAD && lamp_doom) ? lamp_intensity : 0, l_color = COLOR_RED)
|
||||
// set_light_on(lamp_functional && stat != DEAD && lamp_doom) //If the lamp isn't broken and borg isn't dead, doomsday borgs cannot disable their light fully.
|
||||
// set_light_color(COLOR_RED) //This should only matter for doomsday borgs, as any other time the lamp will be off and the color not seen
|
||||
// set_light_range(1) //Again, like above, this only takes effect when the light is forced on by doomsday mode.
|
||||
lamp_enabled = FALSE
|
||||
lampButton.update_icon()
|
||||
update_icons()
|
||||
return
|
||||
|
||||
//Some sort of magical "modulo" thing which somehow increments lamp power by 2, until it hits the max and resets to 0.
|
||||
lamp_intensity = (lamp_intensity+2) % (lamp_max+2)
|
||||
to_chat(src, "[lamp_intensity ? "Headlamp power set to Level [lamp_intensity/2]" : "Headlamp disabled."]")
|
||||
update_headlamp()
|
||||
|
||||
/mob/living/silicon/robot/proc/update_headlamp(var/turn_off = 0, var/cooldown = 100)
|
||||
set_light(0)
|
||||
|
||||
if(lamp_intensity && (turn_off || stat || low_power_mode))
|
||||
to_chat(src, "<span class='danger'>Your headlamp has been deactivated.</span>")
|
||||
lamp_intensity = 0
|
||||
lamp_cooldown = world.time + cooldown
|
||||
else
|
||||
set_light(lamp_intensity)
|
||||
|
||||
if(lamp_button)
|
||||
lamp_button.icon_state = "lamp[lamp_intensity]"
|
||||
|
||||
set_light(lamp_intensity, l_color = (lamp_doom? COLOR_RED : lamp_color))
|
||||
// set_light_range(lamp_intensity)
|
||||
// set_light_color(lamp_doom? COLOR_RED : lamp_color) //Red for doomsday killborgs, borg's choice otherwise
|
||||
// set_light_on(TRUE)
|
||||
lamp_enabled = TRUE
|
||||
lampButton.update_icon()
|
||||
update_icons()
|
||||
|
||||
/mob/living/silicon/robot/proc/deconstruct()
|
||||
// SEND_SIGNAL(src, COMSIG_BORG_SAFE_DECONSTRUCT)
|
||||
var/turf/T = get_turf(src)
|
||||
if (robot_suit)
|
||||
robot_suit.forceMove(T)
|
||||
@@ -661,7 +691,7 @@
|
||||
robot_suit.r_leg = null
|
||||
new /obj/item/stack/cable_coil(T, robot_suit.chest.wired)
|
||||
robot_suit.chest.forceMove(T)
|
||||
robot_suit.chest.wired = 0
|
||||
robot_suit.chest.wired = FALSE
|
||||
robot_suit.chest = null
|
||||
robot_suit.l_arm.forceMove(T)
|
||||
robot_suit.l_arm = null
|
||||
@@ -694,8 +724,12 @@
|
||||
cell = null
|
||||
qdel(src)
|
||||
|
||||
///This is the subtype that gets created by robot suits. It's needed so that those kind of borgs don't have a useless cell in them
|
||||
/mob/living/silicon/robot/nocell
|
||||
cell = null
|
||||
|
||||
/mob/living/silicon/robot/modules
|
||||
var/set_module = null
|
||||
var/set_module = /obj/item/robot_module
|
||||
|
||||
/mob/living/silicon/robot/modules/Initialize()
|
||||
. = ..()
|
||||
@@ -735,14 +769,20 @@
|
||||
Your cyborg LMG will slowly produce ammunition from your power supply, and your operative pinpointer will find and locate fellow nuclear operatives. \
|
||||
<i>Help the operatives secure the disk at all costs!</i></b>"
|
||||
set_module = /obj/item/robot_module/syndicate
|
||||
cell = /obj/item/stock_parts/cell/hyper
|
||||
// radio = /obj/item/radio/borg/syndicate
|
||||
|
||||
/mob/living/silicon/robot/modules/syndicate/Initialize()
|
||||
. = ..()
|
||||
cell = new /obj/item/stock_parts/cell/hyper(src, 25000)
|
||||
radio = new /obj/item/radio/borg/syndicate(src)
|
||||
laws = new /datum/ai_laws/syndicate_override()
|
||||
addtimer(CALLBACK(src, .proc/show_playstyle), 5)
|
||||
|
||||
/mob/living/silicon/robot/modules/syndicate/create_modularInterface()
|
||||
if(!modularInterface)
|
||||
modularInterface = new /obj/item/modular_computer/tablet/integrated/syndicate(src)
|
||||
return ..()
|
||||
|
||||
/mob/living/silicon/robot/modules/syndicate/proc/show_playstyle()
|
||||
if(playstyle_string)
|
||||
to_chat(src, playstyle_string)
|
||||
@@ -797,21 +837,32 @@
|
||||
|
||||
/mob/living/silicon/robot/updatehealth()
|
||||
..()
|
||||
if(health < maxHealth*0.5) //Gradual break down of modules as more damage is sustained
|
||||
if(uneq_module(held_items[3]))
|
||||
playsound(loc, 'sound/machines/warning-buzzer.ogg', 50, 1, 1)
|
||||
audible_message("<span class='warning'>[src] sounds an alarm! \"SYSTEM ERROR: Module 3 OFFLINE.\"</span>")
|
||||
to_chat(src, "<span class='userdanger'>SYSTEM ERROR: Module 3 OFFLINE.</span>")
|
||||
if(health < 0)
|
||||
if(uneq_module(held_items[2]))
|
||||
audible_message("<span class='warning'>[src] sounds an alarm! \"SYSTEM ERROR: Module 2 OFFLINE.\"</span>")
|
||||
to_chat(src, "<span class='userdanger'>SYSTEM ERROR: Module 2 OFFLINE.</span>")
|
||||
playsound(loc, 'sound/machines/warning-buzzer.ogg', 60, 1, 1)
|
||||
if(health < -maxHealth*0.5)
|
||||
if(uneq_module(held_items[1]))
|
||||
audible_message("<span class='warning'>[src] sounds an alarm! \"CRITICAL ERROR: All modules OFFLINE.\"</span>")
|
||||
to_chat(src, "<span class='userdanger'>CRITICAL ERROR: All modules OFFLINE.</span>")
|
||||
playsound(loc, 'sound/machines/warning-buzzer.ogg', 75, 1, 1)
|
||||
// if(!module.breakable_modules)
|
||||
// return
|
||||
|
||||
/// the current percent health of the robot (-1 to 1)
|
||||
var/percent_hp = health/maxHealth
|
||||
if(health <= previous_health) //if change in health is negative (we're losing hp)
|
||||
if(percent_hp <= 0.5)
|
||||
break_cyborg_slot(3)
|
||||
|
||||
if(percent_hp <= 0)
|
||||
break_cyborg_slot(2)
|
||||
|
||||
if(percent_hp <= -0.5)
|
||||
break_cyborg_slot(1)
|
||||
|
||||
else //if change in health is positive (we're gaining hp)
|
||||
if(percent_hp >= 0.5)
|
||||
repair_cyborg_slot(3)
|
||||
|
||||
if(percent_hp >= 0)
|
||||
repair_cyborg_slot(2)
|
||||
|
||||
if(percent_hp >= -0.5)
|
||||
repair_cyborg_slot(1)
|
||||
|
||||
previous_health = health
|
||||
|
||||
/mob/living/silicon/robot/update_sight()
|
||||
if(!client)
|
||||
@@ -834,7 +885,7 @@
|
||||
|
||||
if(sight_mode & BORGMESON)
|
||||
sight |= SEE_TURFS
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
|
||||
see_in_dark = 1
|
||||
|
||||
if(sight_mode & BORGMATERIAL)
|
||||
@@ -849,6 +900,7 @@
|
||||
|
||||
if(sight_mode & BORGTHERM)
|
||||
sight |= SEE_MOBS
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
|
||||
see_invisible = min(see_invisible, SEE_INVISIBLE_LIVING)
|
||||
see_in_dark = 8
|
||||
|
||||
@@ -862,34 +914,27 @@
|
||||
if(stat != DEAD)
|
||||
if(health <= -maxHealth) //die only once
|
||||
death()
|
||||
toggle_headlamp(1)
|
||||
return
|
||||
if(IsUnconscious() || IsStun() || IsParalyzed() || getOxyLoss() > maxHealth*0.5)
|
||||
if(stat == CONSCIOUS)
|
||||
stat = UNCONSCIOUS
|
||||
if(!eye_blind)
|
||||
blind_eyes(1)
|
||||
update_mobility()
|
||||
update_headlamp()
|
||||
if(IsUnconscious() || IsStun() || IsKnockdown() || IsParalyzed() || getOxyLoss() > maxHealth * 0.5)
|
||||
stat = UNCONSCIOUS
|
||||
else
|
||||
if(stat == UNCONSCIOUS)
|
||||
stat = CONSCIOUS
|
||||
adjust_blindness(-1)
|
||||
update_mobility()
|
||||
update_headlamp()
|
||||
stat = CONSCIOUS
|
||||
update_mobility()
|
||||
diag_hud_set_status()
|
||||
diag_hud_set_health()
|
||||
diag_hud_set_aishell()
|
||||
update_health_hud()
|
||||
|
||||
/mob/living/silicon/robot/revive(full_heal = 0, admin_revive = 0)
|
||||
/mob/living/silicon/robot/revive(full_heal = FALSE, admin_revive = FALSE)
|
||||
if(..()) //successfully ressuscitated from death
|
||||
if(!QDELETED(builtInCamera) && !wires.is_cut(WIRE_CAMERA))
|
||||
builtInCamera.toggle_cam(src,0)
|
||||
update_headlamp()
|
||||
if(admin_revive)
|
||||
locked = TRUE
|
||||
notify_ai(NEW_BORG)
|
||||
. = 1
|
||||
. = TRUE
|
||||
toggle_headlamp(FALSE, TRUE) //This will reenable borg headlamps if doomsday is currently going on still.
|
||||
|
||||
/mob/living/silicon/robot/fully_replace_character_name(oldname, newname)
|
||||
..()
|
||||
@@ -901,6 +946,7 @@
|
||||
|
||||
|
||||
/mob/living/silicon/robot/proc/ResetModule()
|
||||
// SEND_SIGNAL(src, COMSIG_BORG_SAFE_DECONSTRUCT)
|
||||
uneq_all()
|
||||
shown_robot_modules = FALSE
|
||||
if(hud_used)
|
||||
@@ -910,6 +956,7 @@
|
||||
resize = 0.5
|
||||
hasExpanded = FALSE
|
||||
update_transform()
|
||||
logevent("Chassis configuration has been reset.")
|
||||
module.transform_to(/obj/item/robot_module)
|
||||
|
||||
// Remove upgrades.
|
||||
@@ -935,7 +982,8 @@
|
||||
designation = module.name
|
||||
if(hands)
|
||||
hands.icon_state = module.moduleselect_icon
|
||||
hands.icon = (module.moduleselect_alternate_icon ? module.moduleselect_alternate_icon : initial(hands.icon)) //CITADEL CHANGE - allows module select icons to use a different icon file
|
||||
//CITADEL CHANGE - allows module select icons to use a different icon file
|
||||
hands.icon = (module.moduleselect_alternate_icon ? module.moduleselect_alternate_icon : initial(hands.icon))
|
||||
if(module.can_be_pushed)
|
||||
status_flags |= CANPUSH
|
||||
else
|
||||
@@ -949,7 +997,7 @@
|
||||
hat_offset = module.hat_offset
|
||||
|
||||
magpulse = module.magpulsing
|
||||
updatename()
|
||||
INVOKE_ASYNC(src, .proc/updatename)
|
||||
|
||||
|
||||
/mob/living/silicon/robot/proc/place_on_head(obj/item/new_hat)
|
||||
@@ -959,12 +1007,68 @@
|
||||
new_hat.forceMove(src)
|
||||
update_icons()
|
||||
|
||||
/mob/living/silicon/robot/proc/make_shell(var/obj/item/borg/upgrade/ai/board)
|
||||
/**
|
||||
*Checking Exited() to detect if a hat gets up and walks off.
|
||||
*Drones and pAIs might do this, after all.
|
||||
*/
|
||||
/mob/living/silicon/robot/Exited(atom/A)
|
||||
if(hat && hat == A)
|
||||
hat = null
|
||||
if(!QDELETED(src)) //Don't update icons if we are deleted.
|
||||
update_icons()
|
||||
return ..()
|
||||
|
||||
///Use this to add upgrades to robots. It'll register signals for when the upgrade is moved or deleted, if not single use.
|
||||
/mob/living/silicon/robot/proc/add_to_upgrades(obj/item/borg/upgrade/new_upgrade, mob/user)
|
||||
if(new_upgrade in upgrades)
|
||||
return FALSE
|
||||
if(!user.temporarilyRemoveItemFromInventory(new_upgrade)) //calling the upgrade's dropped() proc /before/ we add action buttons
|
||||
return FALSE
|
||||
if(!new_upgrade.action(src, user))
|
||||
to_chat(user, "<span class='danger'>Upgrade error.</span>")
|
||||
new_upgrade.forceMove(loc) //gets lost otherwise
|
||||
return FALSE
|
||||
to_chat(user, "<span class='notice'>You apply the upgrade to [src].</span>")
|
||||
to_chat(src, "----------------\nNew hardware detected...Identified as \"<b>[new_upgrade]</b>\"...Setup complete.\n----------------")
|
||||
if(new_upgrade.one_use)
|
||||
logevent("Firmware [new_upgrade] run successfully.")
|
||||
qdel(new_upgrade)
|
||||
return FALSE
|
||||
upgrades += new_upgrade
|
||||
new_upgrade.forceMove(src)
|
||||
RegisterSignal(new_upgrade, COMSIG_MOVABLE_MOVED, .proc/remove_from_upgrades)
|
||||
RegisterSignal(new_upgrade, COMSIG_PARENT_QDELETING, .proc/on_upgrade_deleted)
|
||||
logevent("Hardware [new_upgrade] installed successfully.")
|
||||
|
||||
///Called when an upgrade is moved outside the robot. So don't call this directly, use forceMove etc.
|
||||
/mob/living/silicon/robot/proc/remove_from_upgrades(obj/item/borg/upgrade/old_upgrade)
|
||||
SIGNAL_HANDLER
|
||||
if(loc == src)
|
||||
return
|
||||
old_upgrade.deactivate(src)
|
||||
upgrades -= old_upgrade
|
||||
UnregisterSignal(old_upgrade, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING))
|
||||
|
||||
///Called when an applied upgrade is deleted.
|
||||
/mob/living/silicon/robot/proc/on_upgrade_deleted(obj/item/borg/upgrade/old_upgrade)
|
||||
SIGNAL_HANDLER
|
||||
if(!QDELETED(src))
|
||||
old_upgrade.deactivate(src)
|
||||
upgrades -= old_upgrade
|
||||
UnregisterSignal(old_upgrade, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING))
|
||||
|
||||
/**
|
||||
* make_shell: Makes an AI shell out of a cyborg unit
|
||||
*
|
||||
* Arguments:
|
||||
* * board - B.O.R.I.S. module board used for transforming the cyborg into AI shell
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/make_shell(obj/item/borg/upgrade/ai/board)
|
||||
if(!board)
|
||||
upgrades |= new /obj/item/borg/upgrade/ai(src)
|
||||
shell = TRUE
|
||||
braintype = "AI Shell"
|
||||
name = "[designation] AI Shell [rand(100,999)]"
|
||||
name = "Empty AI Shell-[ident]"
|
||||
real_name = name
|
||||
GLOB.available_ai_shells |= src
|
||||
if(!QDELETED(builtInCamera))
|
||||
@@ -972,6 +1076,9 @@
|
||||
diag_hud_set_aishell()
|
||||
notify_ai(AI_SHELL)
|
||||
|
||||
/**
|
||||
* revert_shell: Reverts AI shell back into a normal cyborg unit
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/revert_shell()
|
||||
if(!shell)
|
||||
return
|
||||
@@ -981,14 +1088,20 @@
|
||||
qdel(boris)
|
||||
shell = FALSE
|
||||
GLOB.available_ai_shells -= src
|
||||
name = "Unformatted Cyborg [rand(100,999)]"
|
||||
name = "Unformatted Cyborg-[ident]"
|
||||
real_name = name
|
||||
if(!QDELETED(builtInCamera))
|
||||
builtInCamera.c_tag = real_name
|
||||
diag_hud_set_aishell()
|
||||
|
||||
/mob/living/silicon/robot/proc/deploy_init(var/mob/living/silicon/ai/AI)
|
||||
real_name = "[AI.real_name] shell [rand(100, 999)] - [designation]" //Randomizing the name so it shows up separately in the shells list
|
||||
/**
|
||||
* deploy_init: Deploys AI unit into AI shell
|
||||
*
|
||||
* Arguments:
|
||||
* * AI - AI unit that initiated the deployment into the AI shell
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/deploy_init(mob/living/silicon/ai/AI)
|
||||
real_name = "[AI.real_name] [designation] Shell-[ident]"
|
||||
name = real_name
|
||||
if(!QDELETED(builtInCamera))
|
||||
builtInCamera.c_tag = real_name //update the camera name too
|
||||
@@ -1069,10 +1182,10 @@
|
||||
mainframe.diag_hud_set_deployed()
|
||||
if(mainframe.laws)
|
||||
mainframe.laws.show_laws(mainframe) //Always remind the AI when switching
|
||||
if(mainframe.eyeobj)
|
||||
mainframe.eyeobj.setLoc(loc)
|
||||
mainframe = null
|
||||
|
||||
|
||||
|
||||
/mob/living/silicon/robot/attack_ai(mob/user)
|
||||
if(shell && (!connected_ai || connected_ai == user))
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
@@ -1080,6 +1193,7 @@
|
||||
|
||||
/mob/living/silicon/robot/shell
|
||||
shell = TRUE
|
||||
cell = null
|
||||
|
||||
/mob/living/silicon/robot/MouseDrop_T(mob/living/M, mob/living/user)
|
||||
. = ..()
|
||||
@@ -1090,20 +1204,19 @@
|
||||
if(!is_type_in_typecache(M, can_ride_typecache))
|
||||
M.visible_message("<span class='warning'>[M] really can't seem to mount [src]...</span>")
|
||||
return
|
||||
|
||||
var/datum/component/riding/riding_datum = LoadComponent(/datum/component/riding/cyborg)
|
||||
if(buckled_mobs)
|
||||
if(buckled_mobs.len >= max_buckled_mobs)
|
||||
return
|
||||
if(M in buckled_mobs)
|
||||
return
|
||||
if(stat)
|
||||
|
||||
if(stat || incapacitated())
|
||||
return
|
||||
if(incapacitated())
|
||||
if(module && !module.allow_riding)
|
||||
M.visible_message("<span class='boldwarning'>Unfortunately, [M] just can't seem to hold onto [src]!</span>")
|
||||
return
|
||||
if(module)
|
||||
if(!module.allow_riding)
|
||||
M.visible_message("<span class='boldwarning'>Unfortunately, [M] just can't seem to hold onto [src]!</span>")
|
||||
return
|
||||
if(iscarbon(M) && !M.incapacitated() && !riding_datum.equip_buckle_inhands(M, 1))
|
||||
if(M.get_num_arms() <= 0)
|
||||
M.visible_message("<span class='boldwarning'>[M] can't climb onto [src] because [M.p_they()] don't have any usable arms!</span>")
|
||||
@@ -1120,17 +1233,25 @@
|
||||
riding_datum.restore_position(user)
|
||||
. = ..(user)
|
||||
|
||||
/mob/living/silicon/robot/resist()
|
||||
. = ..()
|
||||
if(!has_buckled_mobs())
|
||||
return
|
||||
for(var/i in buckled_mobs)
|
||||
var/mob/unbuckle_me_now = i
|
||||
unbuckle_mob(unbuckle_me_now, FALSE)
|
||||
|
||||
/mob/living/silicon/robot/proc/TryConnectToAI()
|
||||
set_connected_ai(select_active_ai_with_fewest_borgs(z))
|
||||
if(connected_ai)
|
||||
lawsync()
|
||||
lawupdate = 1
|
||||
lawupdate = TRUE
|
||||
return TRUE
|
||||
picturesync()
|
||||
return FALSE
|
||||
|
||||
/mob/living/silicon/robot/proc/picturesync()
|
||||
if(connected_ai && connected_ai.aicamera && aicamera)
|
||||
if(connected_ai?.aicamera && aicamera)
|
||||
for(var/i in aicamera.stored)
|
||||
connected_ai.aicamera.stored[i] = TRUE
|
||||
for(var/i in connected_ai.aicamera.stored)
|
||||
@@ -1138,12 +1259,11 @@
|
||||
|
||||
/mob/living/silicon/robot/proc/charge(datum/source, amount, repairs)
|
||||
if(module)
|
||||
var/coeff = amount * 0.005
|
||||
module.respawn_consumable(src, coeff)
|
||||
if(repairs)
|
||||
heal_bodypart_damage(repairs, repairs - 1)
|
||||
module.respawn_consumable(src, amount * 0.005)
|
||||
if(cell)
|
||||
cell.charge = min(cell.charge + amount, cell.maxcharge)
|
||||
if(repairs)
|
||||
heal_bodypart_damage(repairs, repairs - 1)
|
||||
|
||||
/mob/living/silicon/robot/proc/rest_style()
|
||||
set name = "Switch Rest Style"
|
||||
@@ -1178,5 +1298,31 @@
|
||||
if(.)
|
||||
var/mob/living/silicon/ai/old_ai = .
|
||||
old_ai.connected_robots -= src
|
||||
lamp_doom = FALSE
|
||||
if(connected_ai)
|
||||
connected_ai.connected_robots |= src
|
||||
lamp_doom = connected_ai.doomsday_device ? TRUE : FALSE
|
||||
toggle_headlamp(FALSE, TRUE)
|
||||
|
||||
/**
|
||||
* Records an IC event log entry in the cyborg's internal tablet.
|
||||
*
|
||||
* Creates an entry in the borglog list of the cyborg's internal tablet, listing the current
|
||||
* in-game time followed by the message given. These logs can be seen by the cyborg in their
|
||||
* BorgUI tablet app. By design, logging fails if the cyborg is dead.
|
||||
*
|
||||
* Arguments:
|
||||
* arg1: a string containing the message to log.
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/logevent(string = "")
|
||||
if(!string)
|
||||
return
|
||||
if(stat == DEAD) //Dead borgs log no longer
|
||||
return
|
||||
if(!modularInterface)
|
||||
stack_trace("Cyborg [src] ( [type] ) was somehow missing their integrated tablet. Please make a bug report.")
|
||||
create_modularInterface()
|
||||
modularInterface.borglog += "[STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)] - [string]"
|
||||
var/datum/computer_file/program/robotact/program = modularInterface.get_robotact()
|
||||
if(program)
|
||||
program.force_full_update()
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't really work on borgos
|
||||
/obj/item/clothing/head/helmet/space,
|
||||
/obj/item/clothing/head/welding,
|
||||
/obj/item/clothing/head/chameleon/broken \
|
||||
)))
|
||||
|
||||
/mob/living/silicon/robot/attackby(obj/item/I, mob/living/user)
|
||||
if(hat_offset != INFINITY && user.a_intent == INTENT_HELP && is_type_in_typecache(I, equippable_hats))
|
||||
if(hat_offset != INFINITY && user.a_intent == INTENT_HELP && is_type_in_typecache(I, GLOB.blacklisted_borg_hats))
|
||||
if(!(I.slot_flags & ITEM_SLOT_HEAD))
|
||||
to_chat(user, "<span class='warning'>You can't quite fit [I] onto [src]'s head.</span>")
|
||||
return
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
|
||||
/mob/living/silicon/robot
|
||||
maxHealth = 100
|
||||
health = 100
|
||||
designation = "Default" //used for displaying the prefix & getting the current module of cyborg
|
||||
has_limbs = TRUE
|
||||
hud_type = /datum/hud/robot
|
||||
|
||||
// radio = /obj/item/radio/borg
|
||||
|
||||
blocks_emissive = EMISSIVE_BLOCK_UNIQUE
|
||||
|
||||
maxHealth = 100
|
||||
health = 100
|
||||
|
||||
combat_flags = COMBAT_FLAGS_DEFAULT
|
||||
// light_system = MOVABLE_LIGHT_DIRECTIONAL
|
||||
var/light_on = FALSE
|
||||
|
||||
var/custom_name = ""
|
||||
var/braintype = "Cyborg"
|
||||
@@ -21,6 +22,8 @@
|
||||
var/mob/living/silicon/ai/mainframe = null
|
||||
var/datum/action/innate/undeployment/undeployment_action = new
|
||||
|
||||
/// the last health before updating - to check net change in health
|
||||
var/previous_health
|
||||
//Hud stuff
|
||||
|
||||
var/obj/screen/inv1 = null
|
||||
@@ -38,16 +41,20 @@
|
||||
var/obj/item/module_active = null
|
||||
held_items = list(null, null, null) //we use held_items for the module holding, because that makes sense to do!
|
||||
|
||||
/// For checking which modules are disabled or not.
|
||||
var/disabled_modules
|
||||
|
||||
var/mutable_appearance/eye_lights
|
||||
|
||||
var/mob/living/silicon/ai/connected_ai = null
|
||||
var/obj/item/stock_parts/cell/cell = null
|
||||
var/obj/item/stock_parts/cell/cell = /obj/item/stock_parts/cell/high ///If this is a path, this gets created as an object in Initialize.
|
||||
|
||||
var/opened = 0
|
||||
var/opened = FALSE
|
||||
var/emagged = FALSE
|
||||
var/emag_cooldown = 0
|
||||
var/wiresexposed = 0
|
||||
var/wiresexposed = FALSE
|
||||
|
||||
/// Random serial number generated for each cyborg upon its initialization
|
||||
var/ident = 0
|
||||
var/locked = TRUE
|
||||
var/list/req_access = list(ACCESS_ROBOTICS)
|
||||
@@ -64,57 +71,52 @@
|
||||
var/datum/effect_system/spark_spread/spark_system // So they can initialize sparks whenever/N
|
||||
|
||||
var/lawupdate = 1 //Cyborgs will sync their laws with their AI by default
|
||||
var/scrambledcodes = 0 // Used to determine if a borg shows up on the robotics console. Setting to one hides them.
|
||||
var/locked_down //Boolean of whether the borg is locked down or not
|
||||
var/scrambledcodes = FALSE // Used to determine if a borg shows up on the robotics console. Setting to TRUE hides them.
|
||||
var/locked_down = FALSE //Boolean of whether the borg is locked down or not
|
||||
|
||||
var/toner = 0
|
||||
var/tonermax = 40
|
||||
|
||||
var/lamp_max = 10 //Maximum brightness of a borg lamp. Set as a var for easy adjusting.
|
||||
var/lamp_intensity = 0 //Luminosity of the headlamp. 0 is off. Higher settings than the minimum require power.
|
||||
light_color = "#FFCC66"
|
||||
light_power = 0.8
|
||||
var/lamp_cooldown = 0 //Flag for if the lamp is on cooldown after being forcibly disabled.
|
||||
///If the lamp isn't broken.
|
||||
var/lamp_functional = TRUE
|
||||
///If the lamp is turned on
|
||||
var/lamp_enabled = FALSE
|
||||
///Set lamp color
|
||||
var/lamp_color = "#FFCC66" //COLOR_WHITE
|
||||
///Set to true if a doomsday event is locking our lamp to on and RED
|
||||
var/lamp_doom = FALSE
|
||||
///Lamp brightness. Starts at 3, but can be 1 - 5.
|
||||
var/lamp_intensity = 3
|
||||
///Lamp button reference
|
||||
var/obj/screen/robot/lamp/lampButton
|
||||
|
||||
var/sight_mode = 0
|
||||
hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_BATT_HUD, DIAG_TRACK_HUD)
|
||||
|
||||
///The reference to the built-in tablet that borgs carry.
|
||||
var/obj/item/modular_computer/tablet/integrated/modularInterface
|
||||
var/obj/screen/robot/modPC/interfaceButton
|
||||
|
||||
var/list/upgrades = list()
|
||||
|
||||
var/hasExpanded = FALSE
|
||||
var/obj/item/hat
|
||||
var/hat_offset = -3
|
||||
var/list/equippable_hats = list(/obj/item/clothing/head/caphat,
|
||||
/obj/item/clothing/head/hardhat,
|
||||
/obj/item/clothing/head/centhat,
|
||||
/obj/item/clothing/head/HoS,
|
||||
/obj/item/clothing/head/beret,
|
||||
/obj/item/clothing/head/kitty,
|
||||
/obj/item/clothing/head/hopcap,
|
||||
/obj/item/clothing/head/wizard,
|
||||
/obj/item/clothing/head/nursehat,
|
||||
/obj/item/clothing/head/sombrero,
|
||||
/obj/item/clothing/head/helmet/chaplain/witchunter_hat,
|
||||
/obj/item/clothing/head/soft/, //All baseball caps
|
||||
/obj/item/clothing/head/that, //top hat
|
||||
/obj/item/clothing/head/collectable/tophat, //Not sure where this one is found, but it looks the same so might as well include
|
||||
/obj/item/clothing/mask/bandana/, //All bandanas (which only work in hat mode)
|
||||
/obj/item/clothing/head/fedora,
|
||||
/obj/item/clothing/head/beanie/, //All beanies
|
||||
/obj/item/clothing/ears/headphones,
|
||||
/obj/item/clothing/head/helmet/skull,
|
||||
/obj/item/clothing/head/crown/fancy)
|
||||
|
||||
can_buckle = TRUE
|
||||
buckle_lying = FALSE
|
||||
/// What types of mobs are allowed to ride/buckle to this mob
|
||||
var/static/list/can_ride_typecache = typecacheof(/mob/living/carbon/human)
|
||||
|
||||
// cit specific vars //
|
||||
var/sitting = 0
|
||||
var/bellyup = 0
|
||||
var/dogborg = FALSE
|
||||
|
||||
var/cansprint = 1
|
||||
|
||||
combat_flags = COMBAT_FLAGS_DEFAULT
|
||||
|
||||
var/orebox = null
|
||||
|
||||
//doggie borg stuff.
|
||||
|
||||
@@ -269,9 +269,10 @@
|
||||
if(!prev_locked_down)
|
||||
R.SetLockdown(0)
|
||||
R.setDir(SOUTH)
|
||||
R.anchored = FALSE
|
||||
R.set_anchored(FALSE)
|
||||
R.mob_transforming = FALSE
|
||||
R.update_headlamp()
|
||||
R.updatehealth()
|
||||
R.update_icons()
|
||||
R.notify_ai(NEW_MODULE)
|
||||
if(R.hud_used)
|
||||
R.hud_used.update_robot_modules_display()
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
model = "Cleanbot"
|
||||
bot_core_type = /obj/machinery/bot_core/cleanbot
|
||||
window_id = "autoclean"
|
||||
window_name = "Automatic Station Cleaner v1.3"
|
||||
pass_flags = PASSMOB
|
||||
window_name = "Automatic Station Cleaner v1.4"
|
||||
pass_flags = PASSMOB // | PASSFLAPS
|
||||
path_image_color = "#993299"
|
||||
weather_immunities = list("lava","ash")
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
var/blood = 1
|
||||
var/trash = 0
|
||||
var/pests = 0
|
||||
var/drawn = 0
|
||||
|
||||
var/list/target_types
|
||||
var/obj/effect/decal/cleanable/target
|
||||
@@ -53,6 +54,9 @@
|
||||
var/list/prefixes
|
||||
var/list/suffixes
|
||||
|
||||
var/ascended = FALSE // if we have all the top titles, grant achievements to living mobs that gaze upon our cleanbot god
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/proc/deputize(obj/item/W, mob/user)
|
||||
if(in_range(src, user))
|
||||
to_chat(user, "<span class='notice'>You attach \the [W] to \the [src].</span>")
|
||||
@@ -66,6 +70,8 @@
|
||||
/mob/living/simple_animal/bot/cleanbot/proc/update_titles()
|
||||
var/working_title = ""
|
||||
|
||||
ascended = TRUE
|
||||
|
||||
for(var/pref in prefixes)
|
||||
for(var/title in pref)
|
||||
if(title in stolen_valor)
|
||||
@@ -73,6 +79,8 @@
|
||||
if(title in officers)
|
||||
commissioned = TRUE
|
||||
break
|
||||
else
|
||||
ascended = FALSE // we didn't have the first entry in the list if we got here, so we're not achievement worthy yet
|
||||
|
||||
working_title += chosen_name
|
||||
|
||||
@@ -81,6 +89,8 @@
|
||||
if(title in stolen_valor)
|
||||
working_title += " " + suf[title]
|
||||
break
|
||||
else
|
||||
ascended = FALSE
|
||||
|
||||
name = working_title
|
||||
|
||||
@@ -89,8 +99,12 @@
|
||||
if(weapon)
|
||||
. += " <span class='warning'>Is that \a [weapon] taped to it...?</span>"
|
||||
|
||||
if(ascended && user.stat == CONSCIOUS && user.client)
|
||||
user.client.give_award(/datum/award/achievement/misc/cleanboss, user)
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/Initialize()
|
||||
. = ..()
|
||||
|
||||
chosen_name = name
|
||||
get_targets()
|
||||
icon_state = "cleanbot[on]"
|
||||
@@ -98,7 +112,6 @@
|
||||
var/datum/job/janitor/J = new/datum/job/janitor
|
||||
access_card.access += J.get_access()
|
||||
prev_access = access_card.access
|
||||
|
||||
stolen_valor = list()
|
||||
|
||||
prefixes = list(command, security, engineering)
|
||||
@@ -123,7 +136,7 @@
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/bot_reset()
|
||||
..()
|
||||
if(weapon && (emagged == 2))
|
||||
if(weapon && emagged == 2)
|
||||
weapon.force = weapon_orig_force
|
||||
ignore_list = list() //Allows the bot to clean targets it previously ignored due to being unreachable.
|
||||
target = null
|
||||
@@ -151,7 +164,7 @@
|
||||
C.Knockdown(20)
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/card/id)||istype(W, /obj/item/pda))
|
||||
if(W.GetID())
|
||||
if(bot_core.allowed(user) && !open && !emagged)
|
||||
locked = !locked
|
||||
to_chat(user, "<span class='notice'>You [ locked ? "lock" : "unlock"] \the [src] behaviour controls.</span>")
|
||||
@@ -161,7 +174,7 @@
|
||||
if(open)
|
||||
to_chat(user, "<span class='warning'>Please close the access panel before locking it.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>The [src] doesn't seem to respect your authority.</span>")
|
||||
to_chat(user, "<span class='notice'>\The [src] doesn't seem to respect your authority.</span>")
|
||||
|
||||
else if(istype(W, /obj/item/kitchen/knife) && user.a_intent != INTENT_HARM)
|
||||
to_chat(user, "<span class='notice'>You start attaching \the [W] to \the [src]...</span>")
|
||||
@@ -203,7 +216,8 @@
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/emag_act(mob/user)
|
||||
. = ..()
|
||||
..()
|
||||
|
||||
if(emagged == 2)
|
||||
if(weapon)
|
||||
weapon.force = weapon_orig_force
|
||||
@@ -259,6 +273,9 @@
|
||||
if(!target && trash) //Then for trash.
|
||||
target = scan(/obj/item/trash)
|
||||
|
||||
// if(!target && trash) //Search for dead mices.
|
||||
// target = scan(/obj/item/food/deadmouse)
|
||||
|
||||
if(!target && auto_patrol) //Search for cleanables it can see.
|
||||
if(mode == BOT_IDLE || mode == BOT_START_PATROL)
|
||||
start_patrol()
|
||||
@@ -335,13 +352,18 @@
|
||||
target_types += /mob/living/simple_animal/cockroach
|
||||
target_types += /mob/living/simple_animal/mouse
|
||||
|
||||
if(drawn)
|
||||
target_types += /obj/effect/decal/cleanable/crayon
|
||||
|
||||
if(trash)
|
||||
target_types += /obj/item/trash
|
||||
target_types += /obj/item/reagent_containers/food/snacks/meat/slab/human
|
||||
|
||||
target_types = typecacheof(target_types)
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
|
||||
/mob/living/simple_animal/bot/cleanbot/UnarmedAttack(atom/A)
|
||||
// if(HAS_TRAIT(src, TRAIT_HANDS_BLOCKED))
|
||||
// return
|
||||
if(istype(A, /obj/effect/decal/cleanable))
|
||||
anchored = TRUE
|
||||
icon_state = "cleanbot-c"
|
||||
@@ -361,8 +383,9 @@
|
||||
icon_state = "cleanbot[on]"
|
||||
else if(istype(A, /obj/item) || istype(A, /obj/effect/decal/remains))
|
||||
visible_message("<span class='danger'>[src] sprays hydrofluoric acid at [A]!</span>")
|
||||
playsound(src, 'sound/effects/spray2.ogg', 50, 1, -6)
|
||||
playsound(src, 'sound/effects/spray2.ogg', 50, TRUE, -6)
|
||||
A.acid_act(75, 10)
|
||||
target = null
|
||||
else if(istype(A, /mob/living/simple_animal/cockroach) || istype(A, /mob/living/simple_animal/mouse))
|
||||
var/mob/living/simple_animal/M = target
|
||||
if(!M.stat)
|
||||
@@ -383,7 +406,7 @@
|
||||
"FREED AT LEST FROM FILTHY PROGRAMMING.")
|
||||
say(phrase)
|
||||
victim.emote("scream")
|
||||
playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6)
|
||||
playsound(src.loc, 'sound/effects/spray2.ogg', 50, TRUE, -6)
|
||||
victim.acid_act(5, 100)
|
||||
else if(A == src) // Wets floors and spawns foam randomly
|
||||
if(prob(75))
|
||||
@@ -412,10 +435,14 @@
|
||||
do_sparks(3, TRUE, src)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/medbay
|
||||
name = "Scrubs, MD"
|
||||
bot_core_type = /obj/machinery/bot_core/cleanbot/medbay
|
||||
on = FALSE
|
||||
|
||||
/obj/machinery/bot_core/cleanbot
|
||||
req_one_access = list(ACCESS_JANITOR, ACCESS_ROBOTICS)
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/get_controls(mob/user)
|
||||
var/dat
|
||||
dat += hack(user)
|
||||
@@ -424,9 +451,10 @@
|
||||
Status: <A href='?src=[REF(src)];power=1'>[on ? "On" : "Off"]</A><BR>
|
||||
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
|
||||
Maintenance panel panel is [open ? "opened" : "closed"]"})
|
||||
if(!locked || hasSiliconAccessInArea(user)|| IsAdminGhost(user))
|
||||
if(!locked || issilicon(user)|| IsAdminGhost(user))
|
||||
dat += "<BR>Clean Blood: <A href='?src=[REF(src)];operation=blood'>[blood ? "Yes" : "No"]</A>"
|
||||
dat += "<BR>Clean Trash: <A href='?src=[REF(src)];operation=trash'>[trash ? "Yes" : "No"]</A>"
|
||||
dat += "<BR>Clean Graffiti: <A href='?src=[REF(src)];operation=drawn'>[drawn ? "Yes" : "No"]</A>"
|
||||
dat += "<BR>Exterminate Pests: <A href='?src=[REF(src)];operation=pests'>[pests ? "Yes" : "No"]</A>"
|
||||
dat += "<BR><BR>Patrol Station: <A href='?src=[REF(src)];operation=patrol'>[auto_patrol ? "Yes" : "No"]</A>"
|
||||
return dat
|
||||
@@ -442,5 +470,10 @@ Maintenance panel panel is [open ? "opened" : "closed"]"})
|
||||
pests = !pests
|
||||
if("trash")
|
||||
trash = !trash
|
||||
if("drawn")
|
||||
drawn = !drawn
|
||||
get_targets()
|
||||
update_controls()
|
||||
|
||||
/obj/machinery/bot_core/cleanbot/medbay
|
||||
req_one_access = list(ACCESS_JANITOR, ACCESS_ROBOTICS, ACCESS_MEDICAL)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//Drone hands
|
||||
|
||||
|
||||
/mob/living/simple_animal/drone/doUnEquip(obj/item/I, force)
|
||||
/mob/living/simple_animal/drone/doUnEquip(obj/item/I, force, silent = FALSE)
|
||||
if(..())
|
||||
update_inv_hands()
|
||||
if(I == head)
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
..() //lose items, then return
|
||||
|
||||
//SLOT HANDLING BULLSHIT FOR INTERNAL STORAGE
|
||||
/mob/living/simple_animal/hostile/guardian/dextrous/doUnEquip(obj/item/I, force)
|
||||
/mob/living/simple_animal/hostile/guardian/dextrous/doUnEquip(obj/item/I, force, silent = FALSE)
|
||||
if(..())
|
||||
update_inv_hands()
|
||||
if(I == internal_storage)
|
||||
|
||||
@@ -44,7 +44,9 @@ Difficulty: Medium
|
||||
wander = FALSE
|
||||
del_on_death = TRUE
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
medal_type = BOSS_MEDAL_MINER
|
||||
achievement_type = /datum/award/achievement/boss/blood_miner_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/blood_miner_crusher
|
||||
score_achievement_type = /datum/award/score/blood_miner_score
|
||||
var/obj/item/melee/transforming/cleaving_saw/miner/miner_saw
|
||||
var/time_until_next_transform = 0
|
||||
var/dashing = FALSE
|
||||
|
||||
@@ -51,8 +51,11 @@ Difficulty: Hard
|
||||
crusher_loot = list(/obj/structure/closet/crate/necropolis/bubblegum/crusher)
|
||||
loot = list(/obj/structure/closet/crate/necropolis/bubblegum)
|
||||
var/charging = 0
|
||||
medal_type = BOSS_MEDAL_BUBBLEGUM
|
||||
score_type = BUBBLEGUM_SCORE
|
||||
|
||||
achievement_type = /datum/award/achievement/boss/bubblegum_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/bubblegum_crusher
|
||||
score_achievement_type = /datum/award/score/bubblegum_score
|
||||
|
||||
deathmessage = "sinks into a pool of blood, fleeing the battle. You've won, for now... "
|
||||
death_sound = 'sound/magic/enter_blood.ogg'
|
||||
|
||||
@@ -153,6 +156,20 @@ Difficulty: Hard
|
||||
charging = 0
|
||||
Goto(target, move_to_delay, minimum_distance)
|
||||
|
||||
/**
|
||||
* Attack by override for bubblegum
|
||||
*
|
||||
* This is used to award the frenching achievement for hitting bubblegum with a tongue
|
||||
*
|
||||
* Arguments:
|
||||
* * obj/item/W the item hitting bubblegum
|
||||
* * mob/user The user of the item
|
||||
* * params, extra parameters
|
||||
*/
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/attackby(obj/item/W, mob/user, params)
|
||||
. = ..()
|
||||
if(istype(W, /obj/item/organ/tongue))
|
||||
user.client?.give_award(/datum/award/achievement/misc/frenching, user)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A)
|
||||
if(charging)
|
||||
|
||||
@@ -43,9 +43,10 @@ Difficulty: Very Hard
|
||||
move_to_delay = 10
|
||||
ranged = 1
|
||||
pixel_x = -32
|
||||
del_on_death = 1
|
||||
medal_type = BOSS_MEDAL_COLOSSUS
|
||||
score_type = COLOSSUS_SCORE
|
||||
del_on_death = TRUE
|
||||
achievement_type = /datum/award/achievement/boss/colossus_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/colossus_crusher
|
||||
score_achievement_type = /datum/award/score/colussus_score
|
||||
crusher_loot = list(/obj/structure/closet/crate/necropolis/colossus/crusher)
|
||||
loot = list(/obj/structure/closet/crate/necropolis/colossus)
|
||||
butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/animalhide/ashdrake = 10, /obj/item/stack/sheet/bone = 30)
|
||||
|
||||
@@ -31,6 +31,9 @@ Difficulty: Extremely Hard
|
||||
wander = FALSE
|
||||
del_on_death = TRUE
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
achievement_type = /datum/award/achievement/boss/demonic_miner_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/demonic_miner_crusher
|
||||
score_achievement_type = /datum/award/score/demonic_miner_score
|
||||
deathmessage = "falls to the ground, decaying into plasma particles."
|
||||
deathsound = "bodyfall"
|
||||
attack_action_types = list(/datum/action/innate/megafauna_attack/frost_orbs,
|
||||
|
||||
@@ -64,8 +64,9 @@ Difficulty: Medium
|
||||
guaranteed_butcher_results = list(/obj/item/stack/sheet/animalhide/ashdrake = 10)
|
||||
var/swooping = NONE
|
||||
var/swoop_cooldown = 0
|
||||
medal_type = BOSS_MEDAL_DRAKE
|
||||
score_type = DRAKE_SCORE
|
||||
achievement_type = /datum/award/achievement/boss/drake_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/drake_crusher
|
||||
score_achievement_type = /datum/award/score/drake_score
|
||||
deathmessage = "collapses into a pile of bones, its flesh sloughing away."
|
||||
death_sound = 'sound/magic/demon_dies.ogg'
|
||||
var/datum/action/small_sprite/smallsprite = new/datum/action/small_sprite/drake()
|
||||
|
||||
@@ -61,8 +61,9 @@ Difficulty: Normal
|
||||
loot = list(/obj/item/hierophant_club)
|
||||
crusher_loot = list(/obj/item/hierophant_club)
|
||||
wander = FALSE
|
||||
medal_type = BOSS_MEDAL_HIEROPHANT
|
||||
score_type = HIEROPHANT_SCORE
|
||||
achievement_type = /datum/award/achievement/boss/hierophant_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/hierophant_crusher
|
||||
score_achievement_type = /datum/award/score/hierophant_score
|
||||
del_on_death = TRUE
|
||||
death_sound = 'sound/magic/repulse.ogg'
|
||||
|
||||
|
||||
@@ -42,8 +42,9 @@ SHITCODE AHEAD. BE ADVISED. Also comment extravaganza
|
||||
retreat_distance = 5
|
||||
minimum_distance = 5
|
||||
ranged_cooldown_time = 10
|
||||
medal_type = BOSS_MEDAL_LEGION
|
||||
score_type = LEGION_SCORE
|
||||
achievement_type = /datum/award/achievement/boss/legion_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/legion_crusher
|
||||
score_achievement_type = /datum/award/score/legion_score
|
||||
pixel_y = -16
|
||||
pixel_x = -32
|
||||
loot = list(/obj/item/stack/sheet/bone = 3)
|
||||
|
||||
@@ -28,24 +28,31 @@
|
||||
layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise
|
||||
flags_1 = PREVENT_CONTENTS_EXPLOSION_1 | HEAR_1
|
||||
has_field_of_vision = FALSE //You are a frikkin boss
|
||||
/// Crusher loot dropped when fauna killed with a crusher
|
||||
/// Crusher loot dropped when the megafauna is killed with a crusher
|
||||
var/list/crusher_loot
|
||||
var/medal_type
|
||||
/// Score given to players when the fauna is killed
|
||||
var/score_type = BOSS_SCORE
|
||||
/// If the megafauna is actually killed (vs entering another phase)
|
||||
/// Achievement given to surrounding players when the megafauna is killed
|
||||
var/achievement_type
|
||||
/// Crusher achievement given to players when megafauna is killed
|
||||
var/crusher_achievement_type
|
||||
/// Score given to players when megafauna is killed
|
||||
var/score_achievement_type
|
||||
/// If the megafauna was actually killed (not just dying, then transforming into another type)
|
||||
var/elimination = 0
|
||||
/// Modifies attacks when at lower health
|
||||
var/anger_modifier = 0
|
||||
/// Internal tracking GPS inside fauna
|
||||
var/obj/item/gps/internal
|
||||
/// Next time fauna can use a melee attack
|
||||
/// Next time the megafauna can use a melee attack
|
||||
var/recovery_time = 0
|
||||
|
||||
var/true_spawn = TRUE // if this is a megafauna that should grant achievements, or have a gps signal
|
||||
/// If this is a megafauna that is real (has achievements, gps signal)
|
||||
var/true_spawn = TRUE
|
||||
/// Range the megafauna can move from their nest (if they have one
|
||||
var/nest_range = 10
|
||||
var/chosen_attack = 1 // chosen attack num
|
||||
/// The chosen attack by the megafauna
|
||||
var/chosen_attack = 1
|
||||
/// Attack actions, sets chosen_attack to the number in the action
|
||||
var/list/attack_action_types = list()
|
||||
/// If there is a small sprite icon for players controlling the megafauna to use
|
||||
var/small_sprite_type
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/Initialize(mapload)
|
||||
@@ -73,23 +80,22 @@
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/death(gibbed)
|
||||
/mob/living/simple_animal/hostile/megafauna/death(gibbed, list/force_grant)
|
||||
if(health > 0)
|
||||
return
|
||||
else
|
||||
var/datum/status_effect/crusher_damage/C = has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
|
||||
var/crusher_kill = FALSE
|
||||
if(C && crusher_loot && C.total_damage >= maxHealth * 0.6)
|
||||
spawn_crusher_loot()
|
||||
crusher_kill = TRUE
|
||||
if(!(flags_1 & ADMIN_SPAWNED_1))
|
||||
var/tab = "megafauna_kills"
|
||||
if(crusher_kill)
|
||||
tab = "megafauna_kills_crusher"
|
||||
var/datum/status_effect/crusher_damage/crusher_dmg = has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
|
||||
var/crusher_kill = FALSE
|
||||
if(crusher_dmg && crusher_loot && crusher_dmg.total_damage >= maxHealth * 0.6)
|
||||
spawn_crusher_loot()
|
||||
crusher_kill = TRUE
|
||||
if(true_spawn && !(flags_1 & ADMIN_SPAWNED_1))
|
||||
var/tab = "megafauna_kills"
|
||||
if(crusher_kill)
|
||||
tab = "megafauna_kills_crusher"
|
||||
if(!elimination) //used so the achievment only occurs for the last legion to die.
|
||||
grant_achievement(achievement_type, score_achievement_type, crusher_kill, force_grant)
|
||||
SSblackbox.record_feedback("tally", tab, 1, "[initial(name)]")
|
||||
if(!elimination) //used so the achievment only occurs for the last legion to die.
|
||||
grant_achievement(medal_type, score_type, crusher_kill)
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/spawn_crusher_loot()
|
||||
loot = crusher_loot
|
||||
@@ -143,26 +149,29 @@
|
||||
if(EXPLODE_LIGHT)
|
||||
adjustBruteLoss(50)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/SetRecoveryTime(buffer_time)
|
||||
/// Sets the next time the megafauna can use a melee or ranged attack, in deciseconds
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/SetRecoveryTime(buffer_time, ranged_buffer_time)
|
||||
recovery_time = world.time + buffer_time
|
||||
ranged_cooldown = max(ranged_cooldown, world.time + buffer_time) // CITADEL BANDAID FIX FOR MEGAFAUNA NOT RESPECTING RECOVERY TIME.
|
||||
ranged_cooldown = world.time + buffer_time
|
||||
if(ranged_buffer_time)
|
||||
ranged_cooldown = world.time + ranged_buffer_time
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/grant_achievement(medaltype, scoretype, crusher_kill)
|
||||
if(!medal_type || (flags_1 & ADMIN_SPAWNED_1)) //Don't award medals if the medal type isn't set
|
||||
/// Grants medals and achievements to surrounding players
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/grant_achievement(medaltype, scoretype, crusher_kill, list/grant_achievement = list())
|
||||
if(!achievement_type || (flags_1 & ADMIN_SPAWNED_1) || !SSachievements.achievements_enabled) //Don't award medals if the medal type isn't set
|
||||
return FALSE
|
||||
if(!SSmedals.hub_enabled) // This allows subtypes to carry on other special rewards not tied with medals. (such as bubblegum's arena shuttle)
|
||||
return TRUE
|
||||
|
||||
for(var/mob/living/L in view(7,src))
|
||||
if(!grant_achievement.len)
|
||||
for(var/mob/living/L in view(7,src))
|
||||
grant_achievement += L
|
||||
for(var/mob/living/L in grant_achievement)
|
||||
if(L.stat || !L.client)
|
||||
continue
|
||||
var/client/C = L.client
|
||||
SSmedals.UnlockMedal("Boss [BOSS_KILL_MEDAL]", C)
|
||||
SSmedals.UnlockMedal("[medaltype] [BOSS_KILL_MEDAL]", C)
|
||||
L.client.give_award(/datum/award/achievement/boss/boss_killer, L)
|
||||
L.client.give_award(achievement_type, L)
|
||||
if(crusher_kill && istype(L.get_active_held_item(), /obj/item/kinetic_crusher))
|
||||
SSmedals.UnlockMedal("[medaltype] [BOSS_KILL_MEDAL_CRUSHER]", C)
|
||||
SSmedals.SetScore(BOSS_SCORE, C, 1)
|
||||
SSmedals.SetScore(score_type, C, 1)
|
||||
L.client.give_award(crusher_achievement_type, L)
|
||||
L.client.give_award(/datum/award/score/boss_score, L) //Score progression for bosses killed in general
|
||||
L.client.give_award(score_achievement_type, L) //Score progression for specific boss killed
|
||||
return TRUE
|
||||
|
||||
/datum/action/innate/megafauna_attack
|
||||
|
||||
@@ -48,8 +48,9 @@ GLOBAL_LIST_INIT(AISwarmerCapsByType, list(/mob/living/simple_animal/hostile/swa
|
||||
health = 750
|
||||
maxHealth = 750 //""""low-ish"""" HP because it's a passive boss, and the swarm itself is the real foe
|
||||
mob_biotypes = MOB_ROBOTIC
|
||||
medal_type = BOSS_MEDAL_SWARMERS
|
||||
score_type = SWARMER_BEACON_SCORE
|
||||
achievement_type = /datum/award/achievement/boss/swarmer_beacon_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/swarmer_beacon_crusher
|
||||
score_achievement_type = /datum/award/score/swarmer_beacon_score
|
||||
faction = list("mining", "boss", "swarmer")
|
||||
weather_immunities = list("lava","ash")
|
||||
stop_automated_movement = TRUE
|
||||
|
||||
@@ -252,7 +252,7 @@
|
||||
Feedon(Food)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/slime/doUnEquip(obj/item/W)
|
||||
/mob/living/simple_animal/slime/doUnEquip(obj/item/W, silent = FALSE)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/slime/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
var/multiple_slots = istype(card_slot) && istype(card_slot2)
|
||||
if(card_slot)
|
||||
if(card_slot?.stored_card || card_slot2?.stored_card)
|
||||
var/obj/item/card/id/first_ID = card_slot.stored_card
|
||||
var/obj/item/card/id/second_ID = card_slot2.stored_card
|
||||
var/obj/item/card/id/first_ID = card_slot?.stored_card
|
||||
var/obj/item/card/id/second_ID = card_slot2?.stored_card
|
||||
var/multiple_cards = istype(first_ID) && istype(second_ID)
|
||||
if(user_is_adjacent)
|
||||
. += "It has [multiple_slots ? "two slots" : "a slot"] for identification cards installed[multiple_cards ? " which contain [first_ID] and [second_ID]" : ", one of which contains [first_ID ? first_ID : second_ID]"]."
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
var/last_battery_percent = 0 // Used for deciding if battery percentage has chandged
|
||||
var/last_world_time = "00:00"
|
||||
var/list/last_header_icons
|
||||
///Looping sound for when the computer is on
|
||||
var/datum/looping_sound/computer/soundloop
|
||||
///Whether or not this modular computer uses the looping sound
|
||||
var/looping_sound = TRUE
|
||||
|
||||
var/base_active_power_usage = 50 // Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too.
|
||||
var/base_idle_power_usage = 5 // Power usage when the computer is idle and screen is off (currently only applies to laptops)
|
||||
@@ -57,11 +61,14 @@
|
||||
physical = src
|
||||
comp_light_color = "#FFFFFF"
|
||||
idle_threads = list()
|
||||
if(looping_sound)
|
||||
soundloop = new(list(src), enabled)
|
||||
update_icon()
|
||||
|
||||
/obj/item/modular_computer/Destroy()
|
||||
kill_program(forced = TRUE)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
QDEL_NULL(soundloop)
|
||||
for(var/H in all_components)
|
||||
var/obj/item/computer_hardware/CH = all_components[H]
|
||||
if(CH.holder == src)
|
||||
@@ -104,7 +111,6 @@
|
||||
var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
|
||||
var/obj/item/computer_hardware/card_slot/card_slot2 = all_components[MC_CARD2]
|
||||
if(!(card_slot || card_slot2))
|
||||
//to_chat(user, "<span class='warning'>There isn't anywhere you can fit a card into on this computer.</span>")
|
||||
return FALSE
|
||||
|
||||
var/obj/item/card/inserting_id = inserting_item.RemoveID()
|
||||
@@ -113,7 +119,6 @@
|
||||
|
||||
if((card_slot?.try_insert(inserting_id)) || (card_slot2?.try_insert(inserting_id)))
|
||||
return TRUE
|
||||
//to_chat(user, "<span class='warning'>This computer doesn't have an open card slot.</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/item/modular_computer/MouseDrop(obj/over_object, src_location, over_location)
|
||||
@@ -199,7 +204,7 @@
|
||||
to_chat(user, "<span class='warning'>You send an activation signal to \the [src], but it responds with an error code. It must be damaged.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You press the power button, but the computer fails to boot up, displaying variety of errors before shutting down again.</span>")
|
||||
return
|
||||
return FALSE
|
||||
|
||||
// If we have a recharger, enable it automatically. Lets computer without a battery work.
|
||||
var/obj/item/computer_hardware/recharger/recharger = all_components[MC_CHARGE]
|
||||
@@ -211,24 +216,28 @@
|
||||
to_chat(user, "<span class='notice'>You send an activation signal to \the [src], turning it on.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You press the power button and start up \the [src].</span>")
|
||||
if(looping_sound)
|
||||
soundloop.start()
|
||||
enabled = 1
|
||||
update_icon()
|
||||
ui_interact(user)
|
||||
return TRUE
|
||||
else // Unpowered
|
||||
if(issynth)
|
||||
to_chat(user, "<span class='warning'>You send an activation signal to \the [src] but it does not respond.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You press the power button but \the [src] does not respond.</span>")
|
||||
return FALSE
|
||||
|
||||
// Process currently calls handle_power(), may be expanded in future if more things are added.
|
||||
/obj/item/modular_computer/process()
|
||||
/obj/item/modular_computer/process(delta_time)
|
||||
if(!enabled) // The computer is turned off
|
||||
last_power_usage = 0
|
||||
return 0
|
||||
return
|
||||
|
||||
if(obj_integrity <= integrity_failure * max_integrity)
|
||||
shutdown_computer()
|
||||
return 0
|
||||
return
|
||||
|
||||
if(active_program && active_program.requires_ntnet && !get_ntnet_status(active_program.requires_ntnet_feature))
|
||||
active_program.event_networkfailure(0) // Active program requires NTNet to run but we've just lost connection. Crash.
|
||||
@@ -240,7 +249,7 @@
|
||||
|
||||
if(active_program)
|
||||
if(active_program.program_state != PROGRAM_STATE_KILLED)
|
||||
active_program.process_tick()
|
||||
active_program.process_tick(delta_time)
|
||||
active_program.ntnet_status = get_ntnet_status()
|
||||
else
|
||||
active_program = null
|
||||
@@ -248,14 +257,36 @@
|
||||
for(var/I in idle_threads)
|
||||
var/datum/computer_file/program/P = I
|
||||
if(P.program_state != PROGRAM_STATE_KILLED)
|
||||
P.process_tick()
|
||||
P.process_tick(delta_time)
|
||||
P.ntnet_status = get_ntnet_status()
|
||||
else
|
||||
idle_threads.Remove(P)
|
||||
|
||||
handle_power() // Handles all computer power interaction
|
||||
handle_power(delta_time) // Handles all computer power interaction
|
||||
//check_update_ui_need()
|
||||
|
||||
/**
|
||||
* Displays notification text alongside a soundbeep when requested to by a program.
|
||||
*
|
||||
* After checking tha the requesting program is allowed to send an alert, creates
|
||||
* a visible message of the requested text alongside a soundbeep. This proc adds
|
||||
* text to indicate that the message is coming from this device and the program
|
||||
* on it, so the supplied text should be the exact message and ending punctuation.
|
||||
*
|
||||
* Arguments:
|
||||
* The program calling this proc.
|
||||
* The message that the program wishes to display.
|
||||
*/
|
||||
|
||||
/obj/item/modular_computer/proc/alert_call(datum/computer_file/program/caller, alerttext, sound = 'sound/machines/twobeep_high.ogg')
|
||||
if(!caller || !caller.alert_able || caller.alert_silenced || !alerttext) //Yeah, we're checking alert_able. No, you don't get to make alerts that the user can't silence.
|
||||
return
|
||||
playsound(src, sound, 50, TRUE)
|
||||
visible_message("<span class='notice'>The [src] displays a [caller.filedesc] notification: [alerttext]</span>")
|
||||
var/mob/living/holder = loc
|
||||
if(istype(holder))
|
||||
to_chat(holder, "[icon2html(src)] <span class='notice'>The [src] displays a [caller.filedesc] notification: [alerttext]</span>")
|
||||
|
||||
// Function used by NanoUI's to obtain data for header. All relevant entries begin with "PC_"
|
||||
/obj/item/modular_computer/proc/get_header_data()
|
||||
var/list/data = list()
|
||||
@@ -345,13 +376,76 @@
|
||||
for(var/datum/computer_file/program/P in idle_threads)
|
||||
P.kill_program(forced = TRUE)
|
||||
idle_threads.Remove(P)
|
||||
if(looping_sound)
|
||||
soundloop.stop()
|
||||
if(loud)
|
||||
physical.visible_message("<span class='notice'>\The [src] shuts down.</span>")
|
||||
enabled = 0
|
||||
update_icon()
|
||||
|
||||
/**
|
||||
* Toggles the computer's flashlight, if it has one.
|
||||
*
|
||||
* Called from ui_act(), does as the name implies.
|
||||
* It is seperated from ui_act() to be overwritten as needed.
|
||||
*/
|
||||
/obj/item/modular_computer/proc/toggle_flashlight()
|
||||
if(!has_light)
|
||||
return FALSE
|
||||
light_on = !light_on
|
||||
if(light_on)
|
||||
set_light(comp_light_luminosity, 1, comp_light_color)
|
||||
else
|
||||
set_light(0)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Sets the computer's light color, if it has a light.
|
||||
*
|
||||
* Called from ui_act(), this proc takes a color string and applies it.
|
||||
* It is seperated from ui_act() to be overwritten as needed.
|
||||
* Arguments:
|
||||
** color is the string that holds the color value that we should use. Proc auto-fails if this is null.
|
||||
*/
|
||||
/obj/item/modular_computer/proc/set_flashlight_color(color)
|
||||
if(!has_light || !color)
|
||||
return FALSE
|
||||
comp_light_color = color
|
||||
// set_light_color(color)
|
||||
update_light()
|
||||
return TRUE
|
||||
|
||||
/obj/item/modular_computer/screwdriver_act(mob/user, obj/item/tool)
|
||||
if(!all_components.len)
|
||||
to_chat(user, "<span class='warning'>This device doesn't have any components installed.</span>")
|
||||
return
|
||||
var/list/component_names = list()
|
||||
for(var/h in all_components)
|
||||
var/obj/item/computer_hardware/H = all_components[h]
|
||||
component_names.Add(H.name)
|
||||
|
||||
var/choice = input(user, "Which component do you want to uninstall?", "Computer maintenance", null) as null|anything in sortList(component_names)
|
||||
|
||||
if(!choice)
|
||||
return
|
||||
|
||||
if(!Adjacent(user))
|
||||
return
|
||||
|
||||
var/obj/item/computer_hardware/H = find_hardware_by_name(choice)
|
||||
|
||||
if(!H)
|
||||
return
|
||||
|
||||
uninstall_component(H, user)
|
||||
return
|
||||
|
||||
|
||||
/obj/item/modular_computer/attackby(obj/item/W as obj, mob/user as mob)
|
||||
// Check for ID first
|
||||
if(istype(W, /obj/item/card/id) && InsertID(W))
|
||||
return
|
||||
|
||||
// Insert items into the components
|
||||
for(var/h in all_components)
|
||||
var/obj/item/computer_hardware/H = all_components[h]
|
||||
@@ -387,31 +481,6 @@
|
||||
to_chat(user, "<span class='notice'>You repair \the [src].</span>")
|
||||
return
|
||||
|
||||
if(W.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
if(!all_components.len)
|
||||
to_chat(user, "<span class='warning'>This device doesn't have any components installed.</span>")
|
||||
return
|
||||
var/list/component_names = list()
|
||||
for(var/h in all_components)
|
||||
var/obj/item/computer_hardware/H = all_components[h]
|
||||
component_names.Add(H.name)
|
||||
|
||||
var/choice = input(user, "Which component do you want to uninstall?", "Computer maintenance", null) as null|anything in sortList(component_names)
|
||||
|
||||
if(!choice)
|
||||
return
|
||||
|
||||
if(!Adjacent(user))
|
||||
return
|
||||
|
||||
var/obj/item/computer_hardware/H = find_hardware_by_name(choice)
|
||||
|
||||
if(!H)
|
||||
return
|
||||
|
||||
uninstall_component(H, user)
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
// Used by processor to relay qdel() to machinery type.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
var/obj/item/computer_hardware/recharger/recharger = all_components[MC_CHARGE]
|
||||
|
||||
if(recharger && recharger.check_functionality())
|
||||
if(recharger?.check_functionality())
|
||||
if(recharger.use_power(amount))
|
||||
return TRUE
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
/obj/item/modular_computer/proc/give_power(amount)
|
||||
var/obj/item/computer_hardware/battery/battery_module = all_components[MC_CELL]
|
||||
if(battery_module && battery_module.battery)
|
||||
if(battery_module?.battery)
|
||||
return battery_module.battery.give(amount)
|
||||
return 0
|
||||
|
||||
@@ -41,10 +41,10 @@
|
||||
shutdown_computer(0)
|
||||
|
||||
// Handles power-related things, such as battery interaction, recharging, shutdown when it's discharged
|
||||
/obj/item/modular_computer/proc/handle_power()
|
||||
/obj/item/modular_computer/proc/handle_power(delta_time)
|
||||
var/obj/item/computer_hardware/recharger/recharger = all_components[MC_CHARGE]
|
||||
if(recharger)
|
||||
recharger.process()
|
||||
recharger.process(delta_time)
|
||||
|
||||
var/power_usage = screen_on ? base_active_power_usage : base_idle_power_usage
|
||||
|
||||
|
||||
@@ -7,17 +7,17 @@
|
||||
if(!enabled)
|
||||
if(ui)
|
||||
ui.close()
|
||||
return 0
|
||||
return
|
||||
if(!use_power())
|
||||
if(ui)
|
||||
ui.close()
|
||||
return 0
|
||||
return
|
||||
|
||||
// Robots don't really need to see the screen, their wireless connection works as long as computer is on.
|
||||
if(!screen_on && !issilicon(user))
|
||||
if(ui)
|
||||
ui.close()
|
||||
return 0
|
||||
return
|
||||
|
||||
// If we have an active program switch to it now.
|
||||
if(active_program)
|
||||
@@ -37,8 +37,8 @@
|
||||
if (!ui)
|
||||
ui = new(user, src, "NtosMain")
|
||||
ui.set_autoupdate(TRUE)
|
||||
ui.open()
|
||||
ui.send_asset(get_asset_datum(/datum/asset/simple/headers))
|
||||
if(ui.open())
|
||||
ui.send_asset(get_asset_datum(/datum/asset/simple/headers))
|
||||
|
||||
|
||||
/obj/item/modular_computer/ui_data(mob/user)
|
||||
@@ -47,7 +47,9 @@
|
||||
|
||||
data["login"] = list()
|
||||
var/obj/item/computer_hardware/card_slot/cardholder = all_components[MC_CARD]
|
||||
data["cardholder"] = FALSE
|
||||
if(cardholder)
|
||||
data["cardholder"] = TRUE
|
||||
var/obj/item/card/id/stored_card = cardholder.GetID()
|
||||
if(stored_card)
|
||||
var/stored_name = stored_card.registered_name
|
||||
@@ -74,11 +76,11 @@
|
||||
data["programs"] = list()
|
||||
var/obj/item/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD]
|
||||
for(var/datum/computer_file/program/P in hard_drive.stored_files)
|
||||
var/running = 0
|
||||
var/running = FALSE
|
||||
if(P in idle_threads)
|
||||
running = 1
|
||||
running = TRUE
|
||||
|
||||
data["programs"] += list(list("name" = P.filename, "desc" = P.filedesc, "running" = running))
|
||||
data["programs"] += list(list("name" = P.filename, "desc" = P.filedesc, "running" = running, "icon" = P.program_icon, "alert" = P.alert_pending))
|
||||
|
||||
data["has_light"] = has_light
|
||||
data["light_on"] = light_on
|
||||
@@ -88,8 +90,10 @@
|
||||
|
||||
// Handles user's GUI input
|
||||
/obj/item/modular_computer/ui_act(action, params)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/obj/item/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD]
|
||||
switch(action)
|
||||
if("PC_exit")
|
||||
@@ -144,6 +148,7 @@
|
||||
if(P in idle_threads)
|
||||
P.program_state = PROGRAM_STATE_ACTIVE
|
||||
active_program = P
|
||||
P.alert_pending = FALSE
|
||||
idle_threads.Remove(P)
|
||||
update_icon()
|
||||
return
|
||||
@@ -159,16 +164,12 @@
|
||||
return
|
||||
if(P.run_program(user))
|
||||
active_program = P
|
||||
P.alert_pending = FALSE
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
if("PC_toggle_light")
|
||||
light_on = !light_on
|
||||
if(light_on)
|
||||
set_light(comp_light_luminosity, 1, comp_light_color)
|
||||
else
|
||||
set_light(0)
|
||||
return TRUE
|
||||
return toggle_flashlight()
|
||||
|
||||
if("PC_light_color")
|
||||
var/mob/user = usr
|
||||
@@ -180,10 +181,7 @@
|
||||
if(color_hex2num(new_color) < 200) //Colors too dark are rejected
|
||||
to_chat(user, "<span class='warning'>That color is too dark! Choose a lighter one.</span>")
|
||||
new_color = null
|
||||
comp_light_color = new_color
|
||||
light_color = new_color
|
||||
update_light()
|
||||
return TRUE
|
||||
return set_flashlight_color(new_color)
|
||||
|
||||
if("PC_Eject_Disk")
|
||||
var/param = params["name"]
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// No running around with open laptops in hands.
|
||||
item_flags = SLOWS_WHILE_IN_HAND
|
||||
|
||||
screen_on = 0 // Starts closed
|
||||
screen_on = FALSE // Starts closed
|
||||
var/start_open = TRUE // unless this var is set to 1
|
||||
var/icon_state_closed = "laptop-closed"
|
||||
var/w_class_open = WEIGHT_CLASS_BULKY
|
||||
@@ -64,17 +64,18 @@
|
||||
. = ..()
|
||||
if(over_object == usr || over_object == src)
|
||||
try_toggle_open(usr)
|
||||
else if(istype(over_object, /obj/screen/inventory/hand))
|
||||
return
|
||||
if(istype(over_object, /obj/screen/inventory/hand))
|
||||
var/obj/screen/inventory/hand/H = over_object
|
||||
var/mob/M = usr
|
||||
|
||||
if(!M.restrained() && !M.stat)
|
||||
if(!isturf(loc) || !Adjacent(M))
|
||||
return
|
||||
M.put_in_hand(src, H.held_index)
|
||||
if(M.stat != CONSCIOUS || M.restrained())
|
||||
return
|
||||
if(!isturf(loc) || !Adjacent(M))
|
||||
return
|
||||
M.put_in_hand(src, H.held_index)
|
||||
|
||||
/obj/item/modular_computer/laptop/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
/obj/item/modular_computer/laptop/on_attack_hand(mob/user)
|
||||
if(screen_on && isturf(loc))
|
||||
return attack_self(user)
|
||||
|
||||
|
||||
@@ -43,13 +43,6 @@
|
||||
/obj/item/modular_computer/processor/relay_qdel()
|
||||
qdel(machinery_computer)
|
||||
|
||||
// This thing is not meant to be used on it's own, get topic data from our machinery owner.
|
||||
//obj/item/modular_computer/processor/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE)
|
||||
// if(!machinery_computer)
|
||||
// return 0
|
||||
|
||||
// return machinery_computer.canUseTopic(user, state)
|
||||
|
||||
/obj/item/modular_computer/processor/shutdown_computer()
|
||||
if(!machinery_computer)
|
||||
return
|
||||
@@ -59,3 +52,9 @@
|
||||
|
||||
/obj/item/modular_computer/processor/attack_ghost(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/item/modular_computer/processor/alert_call(datum/computer_file/program/caller, alerttext)
|
||||
if(!caller || !caller.alert_able || caller.alert_silenced || !alerttext)
|
||||
return
|
||||
playsound(src, 'sound/machines/twobeep_high.ogg', 50, TRUE)
|
||||
machinery_computer.visible_message("<span class='notice'>The [src] displays a [caller.filedesc] notification: [alerttext]</span>")
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
slot_flags = ITEM_SLOT_ID | ITEM_SLOT_BELT
|
||||
has_light = TRUE //LED flashlight!
|
||||
comp_light_luminosity = 2.3 //Same as the PDA
|
||||
looping_sound = FALSE
|
||||
var/has_variants = TRUE
|
||||
var/finish_color = null
|
||||
|
||||
@@ -41,6 +42,7 @@
|
||||
comp_light_luminosity = 6.3
|
||||
has_variants = FALSE
|
||||
device_theme = "syndicate"
|
||||
light_color = COLOR_RED
|
||||
|
||||
/obj/item/modular_computer/tablet/nukeops/emag_act(mob/user)
|
||||
if(!enabled)
|
||||
@@ -48,3 +50,98 @@
|
||||
return FALSE
|
||||
to_chat(user, "<span class='notice'>You swipe \the [src]. It's screen briefly shows a message reading \"MEMORY CODE INJECTION DETECTED AND SUCCESSFULLY QUARANTINED\".</span>")
|
||||
return FALSE
|
||||
|
||||
/// Borg Built-in tablet interface
|
||||
/obj/item/modular_computer/tablet/integrated
|
||||
name = "modular interface"
|
||||
icon_state = "tablet-silicon"
|
||||
has_light = FALSE //tablet light button actually enables/disables the borg lamp
|
||||
comp_light_luminosity = 0
|
||||
has_variants = FALSE
|
||||
///Ref to the borg we're installed in. Set by the borg during our creation.
|
||||
var/mob/living/silicon/robot/borgo
|
||||
///Ref to the RoboTact app. Important enough to borgs to deserve a ref.
|
||||
var/datum/computer_file/program/robotact/robotact
|
||||
///IC log that borgs can view in their personal management app
|
||||
var/list/borglog = list()
|
||||
|
||||
/obj/item/modular_computer/tablet/integrated/Initialize(mapload)
|
||||
. = ..()
|
||||
vis_flags |= VIS_INHERIT_ID
|
||||
borgo = loc
|
||||
if(!istype(borgo))
|
||||
borgo = null
|
||||
stack_trace("[type] initialized outside of a borg, deleting.")
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/item/modular_computer/tablet/integrated/Destroy()
|
||||
borgo = null
|
||||
return ..()
|
||||
|
||||
/obj/item/modular_computer/tablet/integrated/turn_on(mob/user)
|
||||
if(borgo?.stat != DEAD)
|
||||
return ..()
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Returns a ref to the RoboTact app, creating the app if need be.
|
||||
*
|
||||
* The RoboTact app is important for borgs, and so should always be available.
|
||||
* This proc will look for it in the tablet's robotact var, then check the
|
||||
* hard drive if the robotact var is unset, and finally attempt to create a new
|
||||
* copy if the hard drive does not contain the app. If the hard drive rejects
|
||||
* the new copy (such as due to lack of space), the proc will crash with an error.
|
||||
* RoboTact is supposed to be undeletable, so these will create runtime messages.
|
||||
*/
|
||||
/obj/item/modular_computer/tablet/integrated/proc/get_robotact()
|
||||
if(!borgo)
|
||||
return null
|
||||
if(!robotact)
|
||||
var/obj/item/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD]
|
||||
robotact = hard_drive.find_file_by_name("robotact")
|
||||
if(!robotact)
|
||||
stack_trace("Cyborg [borgo] ( [borgo.type] ) was somehow missing their self-manage app in their tablet. A new copy has been created.")
|
||||
robotact = new(hard_drive)
|
||||
if(!hard_drive.store_file(robotact))
|
||||
qdel(robotact)
|
||||
robotact = null
|
||||
CRASH("Cyborg [borgo]'s tablet hard drive rejected recieving a new copy of the self-manage app. To fix, check the hard drive's space remaining. Please make a bug report about this.")
|
||||
return robotact
|
||||
|
||||
//Makes the light settings reflect the borg's headlamp settings
|
||||
/obj/item/modular_computer/tablet/integrated/ui_data(mob/user)
|
||||
. = ..()
|
||||
.["has_light"] = TRUE
|
||||
.["light_on"] = borgo?.lamp_intensity
|
||||
.["comp_light_color"] = borgo?.lamp_color
|
||||
|
||||
//Makes the flashlight button affect the borg rather than the tablet
|
||||
/obj/item/modular_computer/tablet/integrated/toggle_flashlight()
|
||||
if(!borgo || QDELETED(borgo))
|
||||
return FALSE
|
||||
borgo.toggle_headlamp()
|
||||
return TRUE
|
||||
|
||||
//Makes the flashlight color setting affect the borg rather than the tablet
|
||||
/obj/item/modular_computer/tablet/integrated/set_flashlight_color(color)
|
||||
if(!borgo || QDELETED(borgo) || !color)
|
||||
return FALSE
|
||||
borgo.lamp_color = color
|
||||
borgo.toggle_headlamp(FALSE, TRUE)
|
||||
return TRUE
|
||||
|
||||
/obj/item/modular_computer/tablet/integrated/alert_call(datum/computer_file/program/caller, alerttext, sound = 'sound/machines/twobeep_high.ogg')
|
||||
if(!caller || !caller.alert_able || caller.alert_silenced || !alerttext) //Yeah, we're checking alert_able. No, you don't get to make alerts that the user can't silence.
|
||||
return
|
||||
borgo.playsound_local(src, sound, 50, TRUE)
|
||||
to_chat(borgo, "<span class='notice'>The [src] displays a [caller.filedesc] notification: [alerttext]</span>")
|
||||
|
||||
|
||||
/obj/item/modular_computer/tablet/integrated/syndicate
|
||||
icon_state = "tablet-silicon-syndicate"
|
||||
device_theme = "syndicate"
|
||||
|
||||
|
||||
/obj/item/modular_computer/tablet/integrated/syndicate/Initialize()
|
||||
. = ..()
|
||||
borgo.lamp_color = COLOR_RED //Syndicate likes it red
|
||||
|
||||
@@ -29,8 +29,7 @@
|
||||
install_component(new /obj/item/computer_hardware/card_slot)
|
||||
install_component(new /obj/item/computer_hardware/network_card)
|
||||
install_component(new /obj/item/computer_hardware/printer/mini)
|
||||
hard_drive.store_file(new /datum/computer_file/program/bounty)
|
||||
//hard_drive.store_file(new /datum/computer_file/program/shipping)
|
||||
// hard_drive.store_file(new /datum/computer_file/program/shipping)
|
||||
|
||||
/obj/item/modular_computer/tablet/preset/advanced/atmos/Initialize() //This will be defunct and will be replaced when NtOS PDAs are done
|
||||
. = ..()
|
||||
@@ -38,8 +37,10 @@
|
||||
|
||||
/obj/item/modular_computer/tablet/preset/advanced/command/Initialize()
|
||||
. = ..()
|
||||
var/obj/item/computer_hardware/hard_drive/small/hard_drive = find_hardware_by_name("solid state drive")
|
||||
install_component(new /obj/item/computer_hardware/sensorpackage)
|
||||
install_component(new /obj/item/computer_hardware/card_slot/secondary)
|
||||
hard_drive.store_file(new /datum/computer_file/program/budgetorders)
|
||||
|
||||
/// Given by the syndicate as part of the contract uplink bundle - loads in the Contractor Uplink.
|
||||
/obj/item/modular_computer/tablet/syndicate_contract_uplink/preset/uplink/Initialize()
|
||||
@@ -67,3 +68,11 @@
|
||||
install_component(new /obj/item/computer_hardware/battery(src, /obj/item/stock_parts/cell/computer))
|
||||
install_component(new /obj/item/computer_hardware/hard_drive/small/nukeops)
|
||||
install_component(new /obj/item/computer_hardware/network_card)
|
||||
|
||||
//Borg Built-in tablet
|
||||
/obj/item/modular_computer/tablet/integrated/Initialize()
|
||||
. = ..()
|
||||
install_component(new /obj/item/computer_hardware/processor_unit/small)
|
||||
install_component(new /obj/item/computer_hardware/hard_drive/small/integrated)
|
||||
install_component(new /obj/item/computer_hardware/recharger/cyborg)
|
||||
install_component(new /obj/item/computer_hardware/network_card/integrated)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user