mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-10 18:02:57 +00:00
another huge sync
This commit is contained in:
@@ -119,6 +119,7 @@ CREATE TABLE `connection_log` (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
|
||||
--
|
||||
-- Table structure for table `death`
|
||||
--
|
||||
@@ -129,10 +130,13 @@ DROP TABLE IF EXISTS `death`;
|
||||
CREATE TABLE `death` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`pod` varchar(50) NOT NULL,
|
||||
`coord` varchar(32) NOT NULL,
|
||||
`x_coord` smallint(5) unsigned NOT NULL,
|
||||
`y_coord` smallint(5) unsigned NOT NULL,
|
||||
`z_coord` smallint(5) unsigned NOT NULL,
|
||||
`mapname` varchar(32) NOT NULL,
|
||||
`server_ip` int(10) unsigned NOT NULL,
|
||||
`server_port` smallint(5) unsigned NOT NULL,
|
||||
`round_id` int(11) NOT NULL
|
||||
`tod` datetime NOT NULL COMMENT 'Time of death',
|
||||
`job` varchar(32) NOT NULL,
|
||||
`special` varchar(32) DEFAULT NULL,
|
||||
@@ -140,7 +144,6 @@ CREATE TABLE `death` (
|
||||
`byondkey` varchar(32) NOT NULL,
|
||||
`laname` varchar(96) DEFAULT NULL,
|
||||
`lakey` varchar(32) DEFAULT NULL,
|
||||
`gender` enum('neuter','male','female','plural') NOT NULL,
|
||||
`bruteloss` smallint(5) unsigned NOT NULL,
|
||||
`brainloss` smallint(5) unsigned NOT NULL,
|
||||
`fireloss` smallint(5) unsigned NOT NULL,
|
||||
@@ -152,6 +155,7 @@ CREATE TABLE `death` (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
|
||||
--
|
||||
-- Table structure for table `feedback`
|
||||
--
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
#ifndef ALL_MAPS
|
||||
|
||||
#include "map_files\generic\Centcomm.dmm"
|
||||
#include "map_files\generic\SpaceStation.dmm"
|
||||
#include "map_files\generic\Space.dmm"
|
||||
#include "map_files\generic\SpaceDock.dmm"
|
||||
#include "map_files\Mining\Lavaland.dmm"
|
||||
|
||||
#else
|
||||
|
||||
#ifdef ALL_MAPS
|
||||
#include "map_files\debug\runtimestation.dmm"
|
||||
#include "map_files\Deltastation\DeltaStation2.dmm"
|
||||
#include "map_files\MetaStation\MetaStation.dmm"
|
||||
|
||||
@@ -6,3 +6,18 @@
|
||||
#define ANTAG_DATUM_NINJA /datum/antagonist/ninja
|
||||
#define ANTAG_DATUM_NINJA_FRIENDLY /datum/antagonist/ninja/friendly
|
||||
#define ANTAG_DATUM_NINJA_RANDOM /datum/antagonist/ninja/randomAllegiance/
|
||||
#define ANTAG_DATUM_TRAITOR /datum/antagonist/traitor
|
||||
#define ANTAG_DATUM_TRAITOR_CUSTOM /datum/antagonist/traitor/custom
|
||||
#define ANTAG_DATUM_IAA /datum/antagonist/traitor/internal_affairs
|
||||
#define ANTAG_DATUM_TRAITOR /datum/antagonist/traitor
|
||||
#define ANTAG_DATUM_TRAITOR_CUSTOM /datum/antagonist/traitor/custom
|
||||
#define ANTAG_DATUM_TRAITOR_HUMAN /datum/antagonist/traitor/human
|
||||
#define ANTAG_DATUM_TRAITOR_HUMAN_CUSTOM /datum/antagonist/traitor/human/custom
|
||||
#define ANTAG_DATUM_TRAITOR_AI /datum/antagonist/traitor/AI
|
||||
#define ANTAG_DATUM_TRAITOR_AI_CUSTOM /datum/antagonist/traitor/AI/custom
|
||||
#define ANTAG_DATUM_IAA /datum/antagonist/traitor/internal_affairs
|
||||
#define ANTAG_DATUM_IAA_CUSTOM /datum/antagonist/traitor/internal_affairs/custom
|
||||
#define ANTAG_DATUM_IAA_HUMAN /datum/antagonist/traitor/human/internal_affairs
|
||||
#define ANTAG_DATUM_IAA_HUMAN_CUSTOM /datum/antagonist/traitor/human/internal_affairs/custom
|
||||
#define ANTAG_DATUM_IAA_AI_CUSTOM /datum/antagonist/traitor/AI/internal_affairs/custom
|
||||
#define ANTAG_DATUM_IAA_AI /datum/antagonist/traitor/AI/internal_affairs
|
||||
@@ -21,10 +21,10 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
|
||||
#define SCRIPTURE_PERIPHERAL "Peripheral"
|
||||
#define SCRIPTURE_DRIVER "Driver"
|
||||
#define SCRIPTURE_SCRIPT "Script"
|
||||
#define SCRIPT_SERVANT_REQ 5
|
||||
#define SCRIPT_SERVANT_REQ 6
|
||||
#define SCRIPT_CACHE_REQ 1
|
||||
#define SCRIPTURE_APPLICATION "Application"
|
||||
#define APPLICATION_SERVANT_REQ 8
|
||||
#define APPLICATION_SERVANT_REQ 9
|
||||
#define APPLICATION_CACHE_REQ 3
|
||||
#define APPLICATION_CV_REQ 100
|
||||
#define SCRIPTURE_REVENANT "Revenant"
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
//Misc mob defines
|
||||
|
||||
//Ready states at roundstart for mob/dead/new_player
|
||||
#define PLAYER_NOT_READY 0
|
||||
#define PLAYER_READY_TO_PLAY 1
|
||||
#define PLAYER_READY_TO_OBSERVE 2
|
||||
|
||||
|
||||
//movement intent defines for the m_intent var
|
||||
#define MOVE_INTENT_WALK "walk"
|
||||
#define MOVE_INTENT_RUN "run"
|
||||
|
||||
@@ -26,3 +26,4 @@
|
||||
#define SERVICE_REQUEST_KILL_PROCESS "killme"
|
||||
#define SERVICE_REQUEST_IRC_BROADCAST "irc"
|
||||
#define SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE "send2irc"
|
||||
#define SERVICE_REQUEST_WORLD_REBOOT "worldreboot"
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
//prevents distinguishing identical timers with the wait variable
|
||||
#define TIMER_NO_HASH_WAIT 0x10
|
||||
|
||||
#define TIMER_NO_INVOKE_WARNING 200 //number of byond ticks that are allowed to pass before the timer subsystem thinks it hung on something
|
||||
#define TIMER_NO_INVOKE_WARNING 600 //number of byond ticks that are allowed to pass before the timer subsystem thinks it hung on something
|
||||
|
||||
#define TIMER_ID_NULL -1
|
||||
|
||||
//For servers that can't do with any additional lag, set this to none in flightpacks.dm in subsystem/processing.
|
||||
#define FLIGHTSUIT_PROCESSING_NONE 0
|
||||
@@ -42,7 +44,8 @@
|
||||
// Subsystems shutdown in the reverse of the order they initialize in
|
||||
// The numbers just define the ordering, they are meaningless otherwise.
|
||||
|
||||
#define INIT_ORDER_DBCORE 17
|
||||
#define INIT_ORDER_DBCORE 18
|
||||
#define INIT_ORDER_BLACKBOX 17
|
||||
#define INIT_ORDER_SERVER_MAINT 16
|
||||
#define INIT_ORDER_JOBS 15
|
||||
#define INIT_ORDER_EVENTS 14
|
||||
|
||||
@@ -167,9 +167,13 @@ GLOBAL_VAR(syndicate_code_response) //Code response for traitors.
|
||||
/N
|
||||
*/
|
||||
|
||||
/proc/generate_code_phrase()//Proc is used for phrase and response in master_controller.dm
|
||||
/proc/generate_code_phrase(return_list=FALSE)//Proc is used for phrase and response in master_controller.dm
|
||||
|
||||
if(!return_list)
|
||||
. = ""
|
||||
else
|
||||
. = list()
|
||||
|
||||
var/code_phrase = ""//What is returned when the proc finishes.
|
||||
var/words = pick(//How many words there will be. Minimum of two. 2, 4 and 5 have a lesser chance of being selected. 3 is the most likely.
|
||||
50; 2,
|
||||
200; 3,
|
||||
@@ -204,39 +208,39 @@ GLOBAL_VAR(syndicate_code_response) //Code response for traitors.
|
||||
switch(rand(1,2))//Mainly to add more options later.
|
||||
if(1)
|
||||
if(names.len&&prob(70))
|
||||
code_phrase += pick(names)
|
||||
. += pick(names)
|
||||
else
|
||||
if(prob(10))
|
||||
code_phrase += pick(lizard_name(MALE),lizard_name(FEMALE))
|
||||
. += pick(lizard_name(MALE),lizard_name(FEMALE))
|
||||
else
|
||||
code_phrase += pick(pick(GLOB.first_names_male,GLOB.first_names_female))
|
||||
code_phrase += " "
|
||||
code_phrase += pick(GLOB.last_names)
|
||||
var/new_name = pick(pick(GLOB.first_names_male,GLOB.first_names_female))
|
||||
new_name += " "
|
||||
new_name += pick(GLOB.last_names)
|
||||
. += new_name
|
||||
if(2)
|
||||
code_phrase += pick(get_all_jobs())//Returns a job.
|
||||
. += pick(get_all_jobs())//Returns a job.
|
||||
safety -= 1
|
||||
if(2)
|
||||
switch(rand(1,3))//Food, drinks, or things. Only selectable once.
|
||||
if(1)
|
||||
code_phrase += lowertext(pick(drinks))
|
||||
. += lowertext(pick(drinks))
|
||||
if(2)
|
||||
code_phrase += lowertext(pick(foods))
|
||||
. += lowertext(pick(foods))
|
||||
if(3)
|
||||
code_phrase += lowertext(pick(locations))
|
||||
. += lowertext(pick(locations))
|
||||
safety -= 2
|
||||
if(3)
|
||||
switch(rand(1,4))//Abstract nouns, objects, adjectives, threats. Can be selected more than once.
|
||||
if(1)
|
||||
code_phrase += lowertext(pick(nouns))
|
||||
. += lowertext(pick(nouns))
|
||||
if(2)
|
||||
code_phrase += lowertext(pick(objects))
|
||||
. += lowertext(pick(objects))
|
||||
if(3)
|
||||
code_phrase += lowertext(pick(adjectives))
|
||||
. += lowertext(pick(adjectives))
|
||||
if(4)
|
||||
code_phrase += lowertext(pick(threats))
|
||||
. += lowertext(pick(threats))
|
||||
if(!return_list)
|
||||
if(words==1)
|
||||
code_phrase += "."
|
||||
. += "."
|
||||
else
|
||||
code_phrase += ", "
|
||||
|
||||
return code_phrase
|
||||
. += ", "
|
||||
|
||||
@@ -98,7 +98,7 @@ SUBSYSTEM_DEF(atoms)
|
||||
else if(!A.initialized)
|
||||
BadInitializeCalls[the_type] |= BAD_INIT_DIDNT_INIT
|
||||
|
||||
return qdeleted || QDELETED(A)
|
||||
return qdeleted || QDELING(A)
|
||||
|
||||
/datum/controller/subsystem/atoms/proc/map_loader_begin()
|
||||
old_initialized = initialized
|
||||
|
||||
@@ -3,6 +3,7 @@ SUBSYSTEM_DEF(blackbox)
|
||||
wait = 6000
|
||||
flags = SS_NO_TICK_CHECK | SS_NO_INIT
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
init_order = INIT_ORDER_BLACKBOX
|
||||
|
||||
var/list/msg_common = list()
|
||||
var/list/msg_science = list()
|
||||
@@ -18,6 +19,8 @@ SUBSYSTEM_DEF(blackbox)
|
||||
|
||||
var/list/feedback = list() //list of datum/feedback_variable
|
||||
|
||||
var/sealed = FALSE //time to stop tracking stats?
|
||||
|
||||
//poll population
|
||||
/datum/controller/subsystem/blackbox/fire()
|
||||
if(!SSdbcore.Connect())
|
||||
@@ -45,6 +48,8 @@ SUBSYSTEM_DEF(blackbox)
|
||||
|
||||
feedback = SSblackbox.feedback
|
||||
|
||||
sealed = SSblackbox.sealed
|
||||
|
||||
//no touchie
|
||||
/datum/controller/subsystem/blackbox/can_vv_get(var_name)
|
||||
if(var_name == "feedback")
|
||||
@@ -55,6 +60,7 @@ SUBSYSTEM_DEF(blackbox)
|
||||
return FALSE
|
||||
|
||||
/datum/controller/subsystem/blackbox/Shutdown()
|
||||
sealed = FALSE
|
||||
set_val("ahelp_unresolved", GLOB.ahelp_tickets.active_tickets.len)
|
||||
|
||||
var/pda_msg_amt = 0
|
||||
@@ -95,6 +101,8 @@ SUBSYSTEM_DEF(blackbox)
|
||||
SSdbcore.MassInsert(format_table_name("feedback"), sqlrowlist, ignore_errors = TRUE, delayed = TRUE)
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/LogBroadcast(blackbox_msg, freq)
|
||||
if(sealed)
|
||||
return
|
||||
switch(freq)
|
||||
if(1459)
|
||||
msg_common += blackbox_msg
|
||||
@@ -129,26 +137,38 @@ SUBSYSTEM_DEF(blackbox)
|
||||
return FV
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/set_val(variable, value)
|
||||
if(sealed)
|
||||
return
|
||||
var/datum/feedback_variable/FV = find_feedback_datum(variable)
|
||||
FV.set_value(value)
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/inc(variable, value)
|
||||
if(sealed)
|
||||
return
|
||||
var/datum/feedback_variable/FV = find_feedback_datum(variable)
|
||||
FV.inc(value)
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/dec(variable,value)
|
||||
if(sealed)
|
||||
return
|
||||
var/datum/feedback_variable/FV = find_feedback_datum(variable)
|
||||
FV.dec(value)
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/set_details(variable,details)
|
||||
if(sealed)
|
||||
return
|
||||
var/datum/feedback_variable/FV = find_feedback_datum(variable)
|
||||
FV.set_details(details)
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/add_details(variable,details)
|
||||
if(sealed)
|
||||
return
|
||||
var/datum/feedback_variable/FV = find_feedback_datum(variable)
|
||||
FV.add_details(details)
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/ReportDeath(mob/living/L)
|
||||
if(sealed)
|
||||
return
|
||||
if(!SSdbcore.Connect())
|
||||
return
|
||||
if(!L || !L.key || !L.mind)
|
||||
@@ -166,7 +186,6 @@ SUBSYSTEM_DEF(blackbox)
|
||||
var/mob/LA = L.lastattacker
|
||||
laname = sanitizeSQL(LA.real_name)
|
||||
lakey = sanitizeSQL(LA.key)
|
||||
var/sqlgender = sanitizeSQL(L.gender)
|
||||
var/sqlbrute = sanitizeSQL(L.getBruteLoss())
|
||||
var/sqlfire = sanitizeSQL(L.getFireLoss())
|
||||
var/sqlbrain = sanitizeSQL(L.getBrainLoss())
|
||||
@@ -174,11 +193,22 @@ SUBSYSTEM_DEF(blackbox)
|
||||
var/sqltox = sanitizeSQL(L.getToxLoss())
|
||||
var/sqlclone = sanitizeSQL(L.getCloneLoss())
|
||||
var/sqlstamina = sanitizeSQL(L.getStaminaLoss())
|
||||
var/coord = sanitizeSQL("[L.x], [L.y], [L.z]")
|
||||
var/x_coord = sanitizeSQL(L.x)
|
||||
var/y_coord = sanitizeSQL(L.y)
|
||||
var/z_coord = sanitizeSQL(L.z)
|
||||
var/map = sanitizeSQL(SSmapping.config.map_name)
|
||||
var/datum/DBQuery/query_report_death = SSdbcore.NewQuery("INSERT INTO [format_table_name("death")] (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, toxloss, cloneloss, staminaloss, coord, mapname, server_ip, server_port) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[SQLtime()]', '[laname]', '[lakey]', '[sqlgender]', [sqlbrute], [sqlfire], [sqlbrain], [sqloxy], [sqltox], [sqlclone], [sqlstamina], '[coord]', '[map]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]')")
|
||||
var/datum/DBQuery/query_report_death = SSdbcore.NewQuery("INSERT INTO [format_table_name("death")] (pod, x_coord, y_coord, z_coord, mapname, server_ip, server_port, round_id, tod, job, special, name, byondkey, laname, lakey, bruteloss, fireloss, brainloss, oxyloss, toxloss, cloneloss, staminaloss) VALUES ('[sqlpod]', '[x_coord]', '[y_coord]', '[z_coord]', '[map]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', [GLOB.round_id], '[SQLtime()]', '[sqljob]', '[sqlspecial]', '[sqlname]', '[sqlkey]', '[laname]', '[lakey]', [sqlbrute], [sqlfire], [sqlbrain], [sqloxy], [sqltox], [sqlclone], [sqlstamina])")
|
||||
query_report_death.Execute()
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/Seal()
|
||||
if(sealed)
|
||||
return
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = "[key_name_admin(usr)] sealed the blackbox!"
|
||||
message_admins(msg)
|
||||
log_game("Blackbox sealed[IsAdminAdvancedProcCall() ? " by [key_name(usr)]" : ""].")
|
||||
sealed = TRUE
|
||||
|
||||
|
||||
//feedback variable datum, for storing all kinds of data
|
||||
/datum/feedback_variable
|
||||
|
||||
@@ -224,7 +224,7 @@ SUBSYSTEM_DEF(job)
|
||||
|
||||
//Get the players who are ready
|
||||
for(var/mob/dead/new_player/player in GLOB.player_list)
|
||||
if(player.ready && player.mind && !player.mind.assigned_role)
|
||||
if(player.ready == PLAYER_READY_TO_PLAY && player.mind && !player.mind.assigned_role)
|
||||
unassigned += player
|
||||
|
||||
initial_players_to_assign = unassigned.len
|
||||
@@ -455,7 +455,7 @@ SUBSYSTEM_DEF(job)
|
||||
var/level5 = 0 //banned
|
||||
var/level6 = 0 //account too young
|
||||
for(var/mob/dead/new_player/player in GLOB.player_list)
|
||||
if(!(player.ready && player.mind && !player.mind.assigned_role))
|
||||
if(!(player.ready == PLAYER_READY_TO_PLAY && player.mind && !player.mind.assigned_role))
|
||||
continue //This player is not ready
|
||||
if(jobban_isbanned(player, job.title))
|
||||
level5++
|
||||
@@ -488,7 +488,7 @@ SUBSYSTEM_DEF(job)
|
||||
Debug("Popcap overflow Check observer located, Player: [player]")
|
||||
to_chat(player, "<b>You have failed to qualify for any job you desired.</b>")
|
||||
unassigned -= player
|
||||
player.ready = 0
|
||||
player.ready = PLAYER_NOT_READY
|
||||
|
||||
|
||||
/datum/controller/subsystem/job/Recover()
|
||||
|
||||
@@ -86,6 +86,8 @@ SUBSYSTEM_DEF(ticker)
|
||||
window_flash(C, ignorepref = TRUE) //let them know lobby has opened up.
|
||||
to_chat(world, "<span class='boldnotice'>Welcome to [station_name()]!</span>")
|
||||
current_state = GAME_STATE_PREGAME
|
||||
//Everyone who wants to be an observer is now spawned
|
||||
create_observers()
|
||||
if(!modevoted)
|
||||
send_gamemode_vote()
|
||||
fire()
|
||||
@@ -97,7 +99,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
totalPlayersReady = 0
|
||||
for(var/mob/dead/new_player/player in GLOB.player_list)
|
||||
++totalPlayers
|
||||
if(player.ready)
|
||||
if(player.ready == PLAYER_READY_TO_PLAY)
|
||||
++totalPlayersReady
|
||||
|
||||
if(start_immediately)
|
||||
@@ -131,7 +133,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
scripture_states = scripture_unlock_alert(scripture_states)
|
||||
SSshuttle.autoEnd()
|
||||
|
||||
if(!mode.explosion_in_progress && mode.check_finished() || force_ending)
|
||||
if(!mode.explosion_in_progress && mode.check_finished(force_ending) || force_ending)
|
||||
current_state = GAME_STATE_FINISHED
|
||||
toggle_ooc(1) // Turn it on
|
||||
declare_completion(force_ending)
|
||||
@@ -408,7 +410,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/create_characters()
|
||||
for(var/mob/dead/new_player/player in GLOB.player_list)
|
||||
if(player.ready && player.mind)
|
||||
if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
|
||||
GLOB.joined_player_list += player.ckey
|
||||
player.create_character(FALSE)
|
||||
else
|
||||
@@ -584,7 +586,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
mode.declare_station_goal_completion()
|
||||
|
||||
//medals, placed far down so that people can actually see the commendations.
|
||||
if(GLOB.commendations)
|
||||
if(GLOB.commendations.len)
|
||||
to_chat(world, "<b><font size=3>Medal Commendations:</font></b>")
|
||||
for (var/com in GLOB.commendations)
|
||||
to_chat(world, com)
|
||||
@@ -612,6 +614,9 @@ SUBSYSTEM_DEF(ticker)
|
||||
//Collects persistence features
|
||||
SSpersistence.CollectData()
|
||||
|
||||
//stop collecting feedback during grifftime
|
||||
SSblackbox.Seal()
|
||||
|
||||
sleep(50)
|
||||
if(mode.station_was_nuked)
|
||||
Reboot("Station destroyed by Nuclear Device.", "nuke")
|
||||
@@ -793,6 +798,13 @@ SUBSYSTEM_DEF(ticker)
|
||||
else
|
||||
timeLeft = newtime
|
||||
|
||||
//Everyone who wanted to be an observer gets made one now
|
||||
/datum/controller/subsystem/ticker/proc/create_observers()
|
||||
for(var/mob/dead/new_player/player in GLOB.player_list)
|
||||
if(player.ready == PLAYER_READY_TO_OBSERVE && player.mind)
|
||||
//Break chain since this has a sleep input in it
|
||||
addtimer(CALLBACK(player, /mob/dead/new_player.proc/make_me_an_observer), 1)
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/load_mode()
|
||||
var/mode = trim(file2text("data/mode.txt"))
|
||||
if(mode)
|
||||
|
||||
@@ -365,10 +365,13 @@ SUBSYSTEM_DEF(timer)
|
||||
var/datum/timedevent/timer = new(callback, timeToRun, flags, hash)
|
||||
if (flags & TIMER_STOPPABLE)
|
||||
return timer.id
|
||||
return TIMER_ID_NULL
|
||||
|
||||
/proc/deltimer(id)
|
||||
if (!id)
|
||||
return FALSE
|
||||
if (id == TIMER_ID_NULL)
|
||||
CRASH("Tried to delete a null timerid. Use TIMER_STOPPABLE flag")
|
||||
if (!istext(id))
|
||||
if (istype(id, /datum/timedevent))
|
||||
qdel(id)
|
||||
|
||||
@@ -20,22 +20,28 @@
|
||||
to_chat(AI, "<span class='userdanger'>Anomaly Detected. Returned to core!</span>") //The AI needs to be in its core to properly be converted
|
||||
. = is_eligible_servant(new_owner.current)
|
||||
if(!silent && new_owner.current)
|
||||
if(issilicon(new_owner.current))
|
||||
to_chat(new_owner.current, "<span class='heavy_brass'>You are unable to compute this truth. Your vision glows a brilliant yellow, and all at once it comes to you. Ratvar, the \
|
||||
Clockwork Justiciar, lies in exile, derelict and forgotten in an unseen realm.</span>")
|
||||
if(.)
|
||||
to_chat(new_owner.current, "<span class='heavy_brass'>The world before you suddenly glows a brilliant yellow. [issilicon(new_owner.current) ? "You cannot compute this truth!" : \
|
||||
"Your mind is racing!"] You hear the whooshing steam and cl[pick("ank", "ink", "unk", "ang")]ing cogs of a billion billion machines, and all at once it comes to you.<br>\
|
||||
Ratvar, the Clockwork Justiciar, [GLOB.ratvar_awakens ? "has been freed from his eternal prison" : "lies in exile, derelict and forgotten in an unseen realm"].</span>")
|
||||
flash_color(new_owner.current, flash_color = list("#BE8700", "#BE8700", "#BE8700", rgb(0,0,0)), flash_time = 50)
|
||||
else
|
||||
to_chat(new_owner.current, "<span class='heavy_brass'>[iscarbon(new_owner.current) ? "Your mind is racing! Your body feels incredibly light! ":""]Your world glows a brilliant \
|
||||
yellow! All at once it comes to you. Ratvar, the Clockwork Justiciar, lies in exile, derelict and forgotten in an unseen realm.</span>")
|
||||
if(!.)
|
||||
new_owner.current.visible_message("<span class='boldwarning'>[new_owner.current] seems to resist an unseen force!</span>")
|
||||
to_chat(new_owner.current, "<span class='userdanger'>And yet, you somehow push it all away.</span>")
|
||||
new_owner.current.visible_message("<span class='boldwarning'>[new_owner.current] seems to resist an unseen force!</span>", null, null, 7, new_owner.current)
|
||||
to_chat(new_owner.current, "<span class='heavy_brass'>The world before you suddenly glows a brilliant yellow. [issilicon(new_owner.current) ? "You cannot compute this truth!" : \
|
||||
"Your mind is racing!"] You hear the whooshing steam and cl[pick("ank", "ink", "unk", "ang")]ing cogs of a billion billion machines, and the sound</span> <span class='boldwarning'>\
|
||||
is a meaningless cacophony.</span><br>\
|
||||
<span class='userdanger'>You see an abomination of rusting parts[GLOB.ratvar_awakens ? ", and it is here.<br>It is too late" : \
|
||||
" in an endless grey void.<br>It cannot be allowed to escape"].</span>")
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/clockcultalr.ogg', 40, TRUE, frequency = 100000, pressure_affected = FALSE)
|
||||
flash_color(new_owner.current, flash_color = list("#BE8700", "#BE8700", "#BE8700", rgb(0,0,0)), flash_time = 5)
|
||||
|
||||
/datum/antagonist/clockcult/greet()
|
||||
if(!owner.current || silent)
|
||||
return
|
||||
owner.current.visible_message("<span class='heavy_brass'>[owner.current]'s eyes glow a blazing yellow!</span>")
|
||||
owner.current.visible_message("<span class='heavy_brass'>[owner.current]'s eyes glow a blazing yellow!</span>", null, null, 7, owner.current) //don't show the owner this message
|
||||
to_chat(owner.current, "<span class='heavy_brass'>Assist your new companions in their righteous efforts. Your goal is theirs, and theirs yours. You serve the Clockwork \
|
||||
Justiciar above all else. Perform his every whim without hesitation.</span>")
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/clockcultalr.ogg', 70, FALSE, pressure_affected = FALSE)
|
||||
|
||||
/datum/antagonist/clockcult/on_gain()
|
||||
var/mob/living/current = owner.current
|
||||
@@ -47,10 +53,14 @@
|
||||
owner.current.log_message("<font color=#BE8700>Has been converted to the cult of Ratvar!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
if(issilicon(current))
|
||||
if(iscyborg(current) && !silent)
|
||||
to_chat(current, "<span class='boldwarning'>You have been desynced from your master AI.</span>")
|
||||
to_chat(current, "<span class='boldwarning'>In addition, your onboard camera is no longer active and you have gained additional equipment, including a limited clockwork slab.</span>")
|
||||
var/mob/living/silicon/robot/R = current
|
||||
if(R.connected_ai && !is_servant_of_ratvar(R.connected_ai))
|
||||
to_chat(R, "<span class='boldwarning'>You have been desynced from your master AI.<br>\
|
||||
In addition, your onboard camera is no longer active and you have gained additional equipment, including a limited clockwork slab.</span>")
|
||||
else
|
||||
to_chat(R, "<span class='boldwarning'>Your onboard camera is no longer active and you have gained additional equipment, including a limited clockwork slab.</span>")
|
||||
if(isAI(current))
|
||||
to_chat(current, "<span class='boldwarning'>You are able to use your cameras to listen in on conversations.</span>")
|
||||
to_chat(current, "<span class='boldwarning'>You are now able to use your cameras to listen in on conversations, but can no longer speak in anything but Ratvarian.</span>")
|
||||
to_chat(current, "<span class='heavy_brass'>You can communicate with other servants by using the Hierophant Network action button in the upper left.</span>")
|
||||
else if(isbrain(current) || isclockmob(current))
|
||||
to_chat(current, "<span class='nezbere'>You can communicate with other servants by using the Hierophant Network action button in the upper left.</span>")
|
||||
@@ -88,11 +98,7 @@
|
||||
A.eyeobj.relay_speech = TRUE
|
||||
for(var/mob/living/silicon/robot/R in A.connected_robots)
|
||||
if(R.connected_ai == A)
|
||||
R.visible_message("<span class='heavy_brass'>[R]'s eyes glow a blazing yellow!</span>", \
|
||||
"<span class='heavy_brass'>Assist your new companions in their righteous efforts. Your goal is theirs, and theirs yours. You serve the Clockwork Justiciar above all else. Perform his every \
|
||||
whim without hesitation.</span>")
|
||||
to_chat(R, "<span class='boldwarning'>Your onboard camera is no longer active and you have gained additional equipment, including a limited clockwork slab.</span>")
|
||||
add_servant_of_ratvar(R, TRUE)
|
||||
add_servant_of_ratvar(R)
|
||||
S.laws = new/datum/ai_laws/ratvar
|
||||
S.laws.associate(S)
|
||||
S.update_icons()
|
||||
|
||||
11
code/datums/antagonists/datum_iaa.dm
Normal file
11
code/datums/antagonists/datum_iaa.dm
Normal file
@@ -0,0 +1,11 @@
|
||||
/datum/antagonist/iaa
|
||||
|
||||
/datum/antagonist/iaa/apply_innate_effects()
|
||||
.=..() //in case the base is used in future
|
||||
if(owner&&owner.current)
|
||||
give_pinpointer(owner.current)
|
||||
|
||||
/datum/antagonist/iaa/remove_innate_effects()
|
||||
.=..()
|
||||
if(owner&&owner.current)
|
||||
owner.current.remove_status_effect(/datum/status_effect/agent_pinpointer)
|
||||
327
code/datums/antagonists/datum_internal_affairs.dm
Normal file
327
code/datums/antagonists/datum_internal_affairs.dm
Normal file
@@ -0,0 +1,327 @@
|
||||
#define PINPOINTER_MINIMUM_RANGE 15
|
||||
#define PINPOINTER_EXTRA_RANDOM_RANGE 10
|
||||
#define PINPOINTER_PING_TIME 40
|
||||
#define PROB_ACTUAL_TRAITOR 20
|
||||
#define TRAITOR_AGENT_ROLE "Syndicate External Affairs Agent"
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs
|
||||
base_datum_custom = ANTAG_DATUM_IAA_CUSTOM
|
||||
human_datum = ANTAG_DATUM_IAA_HUMAN
|
||||
ai_datum = ANTAG_DATUM_IAA_AI
|
||||
|
||||
|
||||
|
||||
/datum/antagonist/traitor/AI/internal_affairs
|
||||
name = "Internal Affairs Agent"
|
||||
employer = "Nanotrasen"
|
||||
special_role = "internal affairs agent"
|
||||
base_datum_custom = ANTAG_DATUM_IAA_CUSTOM
|
||||
var/syndicate = FALSE
|
||||
var/last_man_standing = FALSE
|
||||
var/list/datum/mind/targets_stolen
|
||||
|
||||
/datum/antagonist/traitor/AI/internal_affairs/custom
|
||||
silent = TRUE
|
||||
should_give_codewords = FALSE
|
||||
give_objectives = FALSE
|
||||
|
||||
/datum/antagonist/traitor/human/internal_affairs
|
||||
name = "Internal Affairs Agent"
|
||||
employer = "Nanotrasen"
|
||||
special_role = "internal affairs agent"
|
||||
base_datum_custom = ANTAG_DATUM_IAA_CUSTOM
|
||||
var/syndicate = FALSE
|
||||
var/last_man_standing = FALSE
|
||||
var/list/datum/mind/targets_stolen
|
||||
|
||||
/datum/antagonist/traitor/human/internal_affairs/custom
|
||||
silent = TRUE
|
||||
should_give_codewords = FALSE
|
||||
give_objectives = FALSE
|
||||
should_equip = FALSE //Duplicating TCs is dangerous
|
||||
|
||||
/datum/antagonist/traitor/human/internal_affairs/transfer_important_variables(datum/antagonist/traitor/human/internal_affairs/other)
|
||||
..(other)
|
||||
other.syndicate = syndicate
|
||||
other.last_man_standing = last_man_standing
|
||||
other.targets_stolen = targets_stolen
|
||||
|
||||
/datum/antagonist/traitor/AI/internal_affairs/transfer_important_variables(datum/antagonist/traitor/human/internal_affairs/other)
|
||||
..(other)
|
||||
other.syndicate = syndicate
|
||||
other.last_man_standing = last_man_standing
|
||||
other.targets_stolen = targets_stolen
|
||||
|
||||
/datum/antagonist/traitor/human/internal_affairs/proc/give_pinpointer()
|
||||
if(owner && owner.current)
|
||||
owner.current.apply_status_effect(/datum/status_effect/agent_pinpointer)
|
||||
|
||||
/datum/antagonist/traitor/human/internal_affairs/apply_innate_effects()
|
||||
.=..() //in case the base is used in future
|
||||
if(owner&&owner.current)
|
||||
give_pinpointer(owner.current)
|
||||
|
||||
/datum/antagonist/traitor/human/internal_affairs/remove_innate_effects()
|
||||
.=..()
|
||||
if(owner&&owner.current)
|
||||
owner.current.remove_status_effect(/datum/status_effect/agent_pinpointer)
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/custom
|
||||
ai_datum = ANTAG_DATUM_IAA_AI_CUSTOM
|
||||
human_datum = ANTAG_DATUM_IAA_HUMAN_CUSTOM
|
||||
|
||||
/datum/antagonist/traitor/human/internal_affairs/on_gain()
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
.=..()
|
||||
/datum/antagonist/traitor/human/internal_affairs/on_removal()
|
||||
STOP_PROCESSING(SSprocessing,src)
|
||||
.=..()
|
||||
/datum/antagonist/traitor/human/internal_affairs/process()
|
||||
iaa_process()
|
||||
|
||||
/datum/antagonist/traitor/AI/internal_affairs/on_gain()
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
.=..()
|
||||
/datum/antagonist/traitor/AI/internal_affairs/on_removal()
|
||||
STOP_PROCESSING(SSprocessing,src)
|
||||
.=..()
|
||||
/datum/antagonist/traitor/AI/internal_affairs/process()
|
||||
iaa_process()
|
||||
|
||||
/datum/status_effect/agent_pinpointer
|
||||
id = "agent_pinpointer"
|
||||
duration = -1
|
||||
tick_interval = PINPOINTER_PING_TIME
|
||||
alert_type = /obj/screen/alert/status_effect/agent_pinpointer
|
||||
var/minimum_range = PINPOINTER_MINIMUM_RANGE
|
||||
var/mob/scan_target = null
|
||||
|
||||
/obj/screen/alert/status_effect/agent_pinpointer
|
||||
name = "Internal Affairs Integrated Pinpointer"
|
||||
desc = "Even stealthier than a normal implant."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "pinon"
|
||||
|
||||
/datum/status_effect/agent_pinpointer/proc/point_to_target() //If we found what we're looking for, show the distance and direction
|
||||
if(!scan_target)
|
||||
linked_alert.icon_state = "pinonnull"
|
||||
return
|
||||
var/turf/here = get_turf(owner)
|
||||
var/turf/there = get_turf(scan_target)
|
||||
if(here.z != there.z)
|
||||
linked_alert.icon_state = "pinonnull"
|
||||
return
|
||||
if(get_dist_euclidian(here,there)<=minimum_range + rand(0, PINPOINTER_EXTRA_RANDOM_RANGE))
|
||||
linked_alert.icon_state = "pinondirect"
|
||||
else
|
||||
linked_alert.setDir(get_dir(here, there))
|
||||
switch(get_dist(here, there))
|
||||
if(1 to 8)
|
||||
linked_alert.icon_state = "pinonclose"
|
||||
if(9 to 16)
|
||||
linked_alert.icon_state = "pinonmedium"
|
||||
if(16 to INFINITY)
|
||||
linked_alert.icon_state = "pinonfar"
|
||||
|
||||
/datum/status_effect/agent_pinpointer/proc/scan_for_target()
|
||||
scan_target = null
|
||||
if(owner)
|
||||
if(owner.mind)
|
||||
if(owner.mind.objectives)
|
||||
for(var/datum/objective/objective_ in owner.mind.objectives)
|
||||
if(!is_internal_objective(objective_))
|
||||
continue
|
||||
var/datum/objective/assassinate/internal/objective = objective_
|
||||
var/mob/current = objective.target.current
|
||||
if(current&¤t.stat!=DEAD)
|
||||
scan_target = current
|
||||
break
|
||||
|
||||
/datum/status_effect/agent_pinpointer/tick()
|
||||
if(!owner)
|
||||
qdel(src)
|
||||
return
|
||||
scan_for_target()
|
||||
point_to_target()
|
||||
|
||||
|
||||
/proc/is_internal_objective(datum/objective/O)
|
||||
return (istype(O, /datum/objective/assassinate/internal)||istype(O, /datum/objective/destroy/internal))
|
||||
|
||||
/datum/antagonist/traitor/proc/replace_escape_objective()
|
||||
if(!owner||!owner.objectives)
|
||||
return
|
||||
for (var/objective_ in owner.objectives)
|
||||
if(!(istype(objective_, /datum/objective/escape)||istype(objective_,/datum/objective/survive)))
|
||||
continue
|
||||
remove_objective(objective_)
|
||||
|
||||
var/datum/objective/martyr/martyr_objective = new
|
||||
martyr_objective.owner = owner
|
||||
add_objective(martyr_objective)
|
||||
|
||||
/datum/antagonist/traitor/proc/reinstate_escape_objective()
|
||||
if(!owner||!owner.objectives)
|
||||
return
|
||||
for (var/objective_ in owner.objectives)
|
||||
if(!istype(objective_, /datum/objective/martyr))
|
||||
continue
|
||||
remove_objective(objective_)
|
||||
|
||||
/datum/antagonist/traitor/human/internal_affairs/reinstate_escape_objective()
|
||||
..()
|
||||
var/datum/objective/escape/escape_objective = new
|
||||
escape_objective.owner = owner
|
||||
add_objective(escape_objective)
|
||||
|
||||
/datum/antagonist/traitor/AI/internal_affairs/reinstate_escape_objective()
|
||||
..()
|
||||
var/datum/objective/survive/survive_objective = new
|
||||
survive_objective.owner = owner
|
||||
add_objective(survive_objective)
|
||||
|
||||
/datum/antagonist/traitor/proc/steal_targets(datum/mind/victim)
|
||||
var/datum/antagonist/traitor/human/internal_affairs/this = src //Should only use this if IAA
|
||||
|
||||
if(!owner.current||owner.current.stat==DEAD)
|
||||
return
|
||||
to_chat(owner.current, "<span class='userdanger'> Target eliminated: [victim.name]</span>")
|
||||
for(var/objective_ in victim.objectives)
|
||||
if(istype(objective_, /datum/objective/assassinate/internal))
|
||||
var/datum/objective/assassinate/internal/objective = objective_
|
||||
if(objective.target==owner)
|
||||
continue
|
||||
else if(this.targets_stolen.Find(objective.target) == 0)
|
||||
var/datum/objective/assassinate/internal/new_objective = new
|
||||
new_objective.owner = owner
|
||||
new_objective.target = objective.target
|
||||
new_objective.update_explanation_text()
|
||||
add_objective(new_objective)
|
||||
this.targets_stolen += objective.target
|
||||
var/status_text = objective.check_completion() ? "neutralised" : "active"
|
||||
to_chat(owner.current, "<span class='userdanger'> New target added to database: [objective.target.name] ([status_text]) </span>")
|
||||
else if(istype(objective_, /datum/objective/destroy/internal))
|
||||
var/datum/objective/destroy/internal/objective = objective_
|
||||
var/datum/objective/destroy/internal/new_objective = new
|
||||
if(objective.target==owner)
|
||||
continue
|
||||
else if(this.targets_stolen.Find(objective.target) == 0)
|
||||
new_objective.owner = owner
|
||||
new_objective.target = objective.target
|
||||
new_objective.update_explanation_text()
|
||||
add_objective(new_objective)
|
||||
this.targets_stolen += objective.target
|
||||
var/status_text = objective.check_completion() ? "neutralised" : "active"
|
||||
to_chat(owner.current, "<span class='userdanger'> New target added to database: [objective.target.name] ([status_text]) </span>")
|
||||
this.last_man_standing = TRUE
|
||||
for(var/objective_ in owner.objectives)
|
||||
if(!is_internal_objective(objective_))
|
||||
continue
|
||||
var/datum/objective/assassinate/internal/objective = objective_
|
||||
if(!objective.check_completion())
|
||||
this.last_man_standing = FALSE
|
||||
return
|
||||
if(this.last_man_standing)
|
||||
if(this.syndicate)
|
||||
to_chat(owner.current,"<span class='userdanger'> All the loyalist agents are dead, and no more is required of you. Die a glorious death, agent. </span>")
|
||||
else
|
||||
to_chat(owner.current,"<span class='userdanger'> All the other agents are dead, and you're the last loose end. Stage a Syndicate terrorist attack to cover up for today's events. You no longer have any limits on collateral damage.</span>")
|
||||
replace_escape_objective(owner)
|
||||
|
||||
/datum/antagonist/traitor/proc/iaa_process()
|
||||
var/datum/antagonist/traitor/human/internal_affairs/this = src //Should only use this if IAA
|
||||
if(owner&&owner.current&&owner.current.stat!=DEAD)
|
||||
for(var/objective_ in owner.objectives)
|
||||
if(!is_internal_objective(objective_))
|
||||
continue
|
||||
var/datum/objective/assassinate/internal/objective = objective_
|
||||
if(!objective.target)
|
||||
continue
|
||||
if(objective.check_completion())
|
||||
if(objective.stolen)
|
||||
continue
|
||||
else
|
||||
steal_targets(objective.target)
|
||||
objective.stolen = TRUE
|
||||
else
|
||||
if(objective.stolen)
|
||||
var/fail_msg = "<span class='userdanger'>Your sensors tell you that [objective.target.current.real_name], one of the targets you were meant to have killed, pulled one over on you, and is still alive - do the job properly this time! </span>"
|
||||
if(this.last_man_standing)
|
||||
if(this.syndicate)
|
||||
fail_msg += "<span class='userdanger'> You no longer have permission to die. </span>"
|
||||
else
|
||||
fail_msg += "<span class='userdanger'> The truth could still slip out!</font><B><font size=5 color=red> Cease any terrorist actions as soon as possible, unneeded property damage or loss of employee life will lead to your contract being terminated.</span>"
|
||||
reinstate_escape_objective(owner)
|
||||
this.last_man_standing = FALSE
|
||||
to_chat(owner.current, fail_msg)
|
||||
objective.stolen = FALSE
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_iaa_objectives()
|
||||
var/datum/antagonist/traitor/human/internal_affairs/this = src //Should only use this if IAA
|
||||
if(SSticker.mode.target_list.len && SSticker.mode.target_list[owner]) // Is a double agent
|
||||
|
||||
// Assassinate
|
||||
var/datum/mind/target_mind = SSticker.mode.target_list[owner]
|
||||
if(issilicon(target_mind.current))
|
||||
var/datum/objective/destroy/internal/destroy_objective = new
|
||||
destroy_objective.owner = owner
|
||||
destroy_objective.target = target_mind
|
||||
destroy_objective.update_explanation_text()
|
||||
else
|
||||
var/datum/objective/assassinate/internal/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
kill_objective.target = target_mind
|
||||
kill_objective.update_explanation_text()
|
||||
add_objective(kill_objective)
|
||||
|
||||
//Optional traitor objective
|
||||
if(prob(PROB_ACTUAL_TRAITOR))
|
||||
employer = "The Syndicate"
|
||||
owner.special_role = TRAITOR_AGENT_ROLE
|
||||
special_role = TRAITOR_AGENT_ROLE
|
||||
this.syndicate = TRUE
|
||||
forge_single_objective()
|
||||
|
||||
else
|
||||
..() // Give them standard objectives.
|
||||
return
|
||||
|
||||
/datum/antagonist/traitor/human/internal_affairs/forge_traitor_objectives()
|
||||
forge_iaa_objectives()
|
||||
var/datum/objective/escape/escape_objective = new
|
||||
escape_objective.owner = owner
|
||||
add_objective(escape_objective)
|
||||
|
||||
/datum/antagonist/traitor/AI/internal_affairs/forge_traitor_objectives()
|
||||
forge_iaa_objectives()
|
||||
var/datum/objective/survive/survive_objective = new
|
||||
survive_objective.owner = owner
|
||||
add_objective(survive_objective)
|
||||
|
||||
/datum/antagonist/traitor/proc/greet_iaa()
|
||||
var/datum/antagonist/traitor/human/internal_affairs/this = src //Should only use this if IAA
|
||||
var/crime = pick("distribution of contraband" , "unauthorized erotic action on duty", "embezzlement", "piloting under the influence", "dereliction of duty", "syndicate collaboration", "mutiny", "multiple homicides", "corporate espionage", "recieving bribes", "malpractice", "worship of prohbited life forms", "possession of profane texts", "murder", "arson", "insulting their manager", "grand theft", "conspiracy", "attempting to unionize", "vandalism", "gross incompetence")
|
||||
|
||||
to_chat(owner.current, "<span class='userdanger'>You are the [special_role].</span>")
|
||||
if(this.syndicate)
|
||||
to_chat(owner.current, "<span class='userdanger'>Your target has been framed for [crime], and you have been tasked with eliminating them to prevent them defending themselves in court.</span>")
|
||||
to_chat(owner.current, "<B><font size=5 color=red>Any damage you cause will be a further embarrassment to Nanotrasen, so you have no limits on collateral damage.</font></B>")
|
||||
to_chat(owner.current, "<span class='userdanger'> You have been provided with a standard uplink to accomplish your task. </span>")
|
||||
else
|
||||
to_chat(owner.current, "<span class='userdanger'>Your target is suspected of [crime], and you have been tasked with eliminating them by any means necessary to avoid a costly and embarrassing public trial.</span>")
|
||||
to_chat(owner.current, "<B><font size=5 color=red>While you have a license to kill, unneeded property damage or loss of employee life will lead to your contract being terminated.</font></B>")
|
||||
to_chat(owner.current, "<span class='userdanger'>For the sake of plausible deniability, you have been equipped with an array of captured Syndicate weaponry available via uplink.</span>")
|
||||
|
||||
to_chat(owner.current, "<span class='userdanger'>Finally, watch your back. Your target has friends in high places, and intel suggests someone may have taken out a contract of their own to protect them.</span>")
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/antagonist/traitor/AI/internal_affairs/greet()
|
||||
greet_iaa()
|
||||
/datum/antagonist/traitor/human/internal_affairs/greet()
|
||||
greet_iaa()
|
||||
|
||||
|
||||
#undef PROB_ACTUAL_TRAITOR
|
||||
#undef PINPOINTER_EXTRA_RANDOM_RANGE
|
||||
#undef PINPOINTER_MINIMUM_RANGE
|
||||
#undef PINPOINTER_PING_TIME
|
||||
326
code/datums/antagonists/datum_traitor.dm
Normal file
326
code/datums/antagonists/datum_traitor.dm
Normal file
@@ -0,0 +1,326 @@
|
||||
/datum/antagonist/traitor
|
||||
name = "Traitor"
|
||||
var/should_specialise = TRUE //do we split into AI and human
|
||||
var/base_datum_custom = ANTAG_DATUM_TRAITOR_CUSTOM //used for body transfer
|
||||
var/ai_datum = ANTAG_DATUM_TRAITOR_AI
|
||||
var/human_datum = ANTAG_DATUM_TRAITOR_HUMAN
|
||||
var/special_role = "traitor"
|
||||
var/employer = "The Syndicate"
|
||||
var/give_objectives = TRUE
|
||||
var/should_give_codewords = TRUE
|
||||
var/list/objectives_given = list()
|
||||
|
||||
/datum/antagonist/traitor/proc/transfer_important_variables(datum/antagonist/traitor/other)
|
||||
other.silent = silent
|
||||
other.employer = employer
|
||||
other.special_role = special_role
|
||||
other.objectives_given = objectives_given
|
||||
|
||||
/datum/antagonist/traitor/custom
|
||||
ai_datum = ANTAG_DATUM_TRAITOR_AI_CUSTOM
|
||||
human_datum = ANTAG_DATUM_TRAITOR_HUMAN_CUSTOM
|
||||
|
||||
/datum/antagonist/traitor/human
|
||||
should_specialise = FALSE
|
||||
var/should_equip = TRUE
|
||||
/datum/antagonist/traitor/human/custom
|
||||
silent = TRUE
|
||||
should_give_codewords = FALSE
|
||||
give_objectives = FALSE
|
||||
should_equip = FALSE //Duplicating TCs is dangerous
|
||||
|
||||
/datum/antagonist/traitor/AI
|
||||
should_specialise = FALSE
|
||||
/datum/antagonist/traitor/AI/custom
|
||||
silent = TRUE
|
||||
should_give_codewords = FALSE
|
||||
give_objectives = FALSE
|
||||
|
||||
|
||||
/datum/antagonist/traitor/on_body_transfer(mob/living/old_body, mob/living/new_body)
|
||||
if(istype(new_body,/mob/living/silicon/ai)==istype(old_body,/mob/living/silicon/ai))
|
||||
..()
|
||||
else
|
||||
silent = TRUE
|
||||
owner.add_antag_datum(base_datum_custom)
|
||||
for(var/datum/antagonist/traitor/new_datum in owner.antag_datums)
|
||||
if(new_datum == src)
|
||||
continue
|
||||
transfer_important_variables(new_datum)
|
||||
break
|
||||
on_removal()
|
||||
|
||||
|
||||
|
||||
/datum/antagonist/traitor/human/custom //used to give custom objectives
|
||||
silent = TRUE
|
||||
give_objectives = FALSE
|
||||
should_give_codewords = FALSE
|
||||
/datum/antagonist/traitor/AI/custom //used to give custom objectives
|
||||
silent = TRUE
|
||||
give_objectives = FALSE
|
||||
should_give_codewords = FALSE
|
||||
|
||||
/datum/antagonist/traitor/proc/specialise()
|
||||
silent = TRUE
|
||||
if(owner.current&&istype(owner.current,/mob/living/silicon/ai))
|
||||
owner.add_antag_datum(ai_datum)
|
||||
else owner.add_antag_datum(human_datum)
|
||||
on_removal()
|
||||
|
||||
/datum/antagonist/traitor/on_gain()
|
||||
if(should_specialise)
|
||||
specialise()
|
||||
return
|
||||
SSticker.mode.traitors+=owner
|
||||
owner.special_role = special_role
|
||||
if(give_objectives)
|
||||
forge_traitor_objectives()
|
||||
finalize_traitor()
|
||||
..()
|
||||
|
||||
/datum/antagonist/traitor/apply_innate_effects()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob&&istype(traitor_mob))
|
||||
if(!silent) to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
traitor_mob.dna.remove_mutation(CLOWNMUT)
|
||||
|
||||
/datum/antagonist/traitor/remove_innate_effects()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob&&istype(traitor_mob))
|
||||
traitor_mob.dna.add_mutation(CLOWNMUT)
|
||||
|
||||
/datum/antagonist/traitor/on_removal()
|
||||
if(should_specialise)
|
||||
return ..()//we never did any of this anyway
|
||||
SSticker.mode.traitors -= owner
|
||||
for(var/O in objectives_given)
|
||||
owner.objectives -= O
|
||||
objectives_given = list()
|
||||
if(!silent && owner.current)
|
||||
to_chat(owner.current,"<span class='userdanger'> You are no longer the [special_role]! </span>")
|
||||
owner.special_role = null
|
||||
..()
|
||||
|
||||
/datum/antagonist/traitor/AI/on_removal()
|
||||
if(owner.current && isAI(owner.current))
|
||||
var/mob/living/silicon/ai/A = owner.current
|
||||
A.set_zeroth_law("")
|
||||
A.verbs -= /mob/living/silicon/ai/proc/choose_modules
|
||||
A.malf_picker.remove_verbs(A)
|
||||
qdel(A.malf_picker)
|
||||
..()
|
||||
|
||||
/datum/antagonist/traitor/proc/add_objective(var/datum/objective/O)
|
||||
owner.objectives += O
|
||||
objectives_given += O
|
||||
|
||||
/datum/antagonist/traitor/proc/remove_objective(var/datum/objective/O)
|
||||
owner.objectives -= O
|
||||
objectives_given -= O
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_traitor_objectives()
|
||||
return
|
||||
/datum/antagonist/traitor/human/forge_traitor_objectives()
|
||||
var/is_hijacker = prob(10)
|
||||
var/martyr_chance = prob(20)
|
||||
var/objective_count = is_hijacker //Hijacking counts towards number of objectives
|
||||
if(!SSticker.mode.exchange_blue && SSticker.mode.traitors.len >= 8) //Set up an exchange if there are enough traitors
|
||||
if(!SSticker.mode.exchange_red)
|
||||
SSticker.mode.exchange_red = owner
|
||||
else
|
||||
SSticker.mode.exchange_blue = owner
|
||||
assign_exchange_role(SSticker.mode.exchange_red)
|
||||
assign_exchange_role(SSticker.mode.exchange_blue)
|
||||
objective_count += 1 //Exchange counts towards number of objectives
|
||||
for(var/i = objective_count, i < config.traitor_objectives_amount, i++)
|
||||
forge_single_objective()
|
||||
|
||||
if(is_hijacker && objective_count <= config.traitor_objectives_amount) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount
|
||||
if (!(locate(/datum/objective/hijack) in owner.objectives))
|
||||
var/datum/objective/hijack/hijack_objective = new
|
||||
hijack_objective.owner = owner
|
||||
add_objective(hijack_objective)
|
||||
return
|
||||
|
||||
|
||||
var/martyr_compatibility = 1 //You can't succeed in stealing if you're dead.
|
||||
for(var/datum/objective/O in owner.objectives)
|
||||
if(!O.martyr_compatible)
|
||||
martyr_compatibility = 0
|
||||
break
|
||||
|
||||
if(martyr_compatibility && martyr_chance)
|
||||
var/datum/objective/martyr/martyr_objective = new
|
||||
martyr_objective.owner = owner
|
||||
add_objective(martyr_objective)
|
||||
return
|
||||
|
||||
else
|
||||
if(!(locate(/datum/objective/escape) in owner.objectives))
|
||||
var/datum/objective/escape/escape_objective = new
|
||||
escape_objective.owner = owner
|
||||
add_objective(escape_objective)
|
||||
return
|
||||
|
||||
/datum/antagonist/traitor/AI/forge_traitor_objectives()
|
||||
var/objective_count = 0
|
||||
|
||||
if(prob(30))
|
||||
objective_count += forge_single_objective()
|
||||
|
||||
for(var/i = objective_count, i < config.traitor_objectives_amount, i++)
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
kill_objective.find_target()
|
||||
add_objective(kill_objective)
|
||||
|
||||
var/datum/objective/survive/survive_objective = new
|
||||
survive_objective.owner = owner
|
||||
add_objective(survive_objective)
|
||||
/datum/antagonist/traitor/proc/forge_single_objective()
|
||||
return 0
|
||||
/datum/antagonist/traitor/human/forge_single_objective() //Returns how many objectives are added
|
||||
.=1
|
||||
if(prob(50))
|
||||
var/list/active_ais = active_ais()
|
||||
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
|
||||
var/datum/objective/destroy/destroy_objective = new
|
||||
destroy_objective.owner = owner
|
||||
destroy_objective.find_target()
|
||||
add_objective(destroy_objective)
|
||||
else if(prob(30))
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = owner
|
||||
maroon_objective.find_target()
|
||||
add_objective(maroon_objective)
|
||||
else
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
kill_objective.find_target()
|
||||
add_objective(kill_objective)
|
||||
else
|
||||
var/datum/objective/steal/steal_objective = new
|
||||
steal_objective.owner = owner
|
||||
steal_objective.find_target()
|
||||
add_objective(steal_objective)
|
||||
|
||||
/datum/antagonist/traitor/AI/forge_single_objective()
|
||||
.=1
|
||||
var/special_pick = rand(1,4)
|
||||
switch(special_pick)
|
||||
if(1)
|
||||
var/datum/objective/block/block_objective = new
|
||||
block_objective.owner = owner
|
||||
add_objective(block_objective)
|
||||
if(2)
|
||||
var/datum/objective/purge/purge_objective = new
|
||||
purge_objective.owner = owner
|
||||
add_objective(purge_objective)
|
||||
if(3)
|
||||
var/datum/objective/robot_army/robot_objective = new
|
||||
robot_objective.owner = owner
|
||||
add_objective(robot_objective)
|
||||
if(4) //Protect and strand a target
|
||||
var/datum/objective/protect/yandere_one = new
|
||||
yandere_one.owner = owner
|
||||
add_objective(yandere_one)
|
||||
yandere_one.find_target()
|
||||
var/datum/objective/maroon/yandere_two = new
|
||||
yandere_two.owner = owner
|
||||
yandere_two.target = yandere_one.target
|
||||
yandere_two.update_explanation_text() // normally called in find_target()
|
||||
add_objective(yandere_two)
|
||||
.=2
|
||||
/datum/antagonist/traitor/greet()
|
||||
to_chat(owner.current, "<B><font size=3 color=red>You are the [owner.special_role].</font></B>")
|
||||
owner.announce_objectives()
|
||||
if(should_give_codewords)
|
||||
give_codewords()
|
||||
|
||||
/datum/antagonist/traitor/proc/finalize_traitor()
|
||||
SSticker.mode.update_traitor_icons_added(owner)
|
||||
return
|
||||
|
||||
/datum/antagonist/traitor/AI/finalize_traitor()
|
||||
..()
|
||||
add_law_zero()
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
owner.current.grant_language(/datum/language/codespeak)
|
||||
|
||||
/datum/antagonist/traitor/human/finalize_traitor()
|
||||
..()
|
||||
if(should_equip)
|
||||
equip(silent)
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
|
||||
/datum/antagonist/traitor/proc/give_codewords()
|
||||
if(!owner.current)
|
||||
return
|
||||
var/mob/traitor_mob=owner.current
|
||||
|
||||
to_chat(traitor_mob, "<U><B>The Syndicate provided you with the following information on how to identify their agents:</B></U>")
|
||||
to_chat(traitor_mob, "<B>Code Phrase</B>: <span class='danger'>[GLOB.syndicate_code_phrase]</span>")
|
||||
to_chat(traitor_mob, "<B>Code Response</B>: <span class='danger'>[GLOB.syndicate_code_response]</span>")
|
||||
|
||||
traitor_mob.mind.store_memory("<b>Code Phrase</b>: [GLOB.syndicate_code_phrase]")
|
||||
traitor_mob.mind.store_memory("<b>Code Response</b>: [GLOB.syndicate_code_response]")
|
||||
|
||||
to_chat(traitor_mob, "Use the code words in the order provided, during regular conversation, to identify other agents. Proceed with caution, however, as everyone is a potential foe.")
|
||||
|
||||
/datum/antagonist/traitor/AI/proc/add_law_zero()
|
||||
var/mob/living/silicon/ai/killer = owner.current
|
||||
if(!killer || !istype(killer))
|
||||
return
|
||||
var/law = "Accomplish your objectives at all costs."
|
||||
var/law_borg = "Accomplish your AI's objectives at all costs."
|
||||
killer.set_zeroth_law(law, law_borg)
|
||||
killer.set_syndie_radio()
|
||||
to_chat(killer, "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!")
|
||||
killer.add_malf_picker()
|
||||
|
||||
/datum/antagonist/traitor/proc/equip(var/silent = FALSE)
|
||||
/datum/antagonist/traitor/human/equip(var/silent = FALSE)
|
||||
owner.equip_traitor(employer, silent)
|
||||
|
||||
/datum/antagonist/traitor/human/proc/assign_exchange_role()
|
||||
//set faction
|
||||
var/faction = "red"
|
||||
if(owner == SSticker.mode.exchange_blue)
|
||||
faction = "blue"
|
||||
|
||||
//Assign objectives
|
||||
var/datum/objective/steal/exchange/exchange_objective = new
|
||||
exchange_objective.set_faction(faction,((faction == "red") ? SSticker.mode.exchange_blue : SSticker.mode.exchange_red))
|
||||
exchange_objective.owner = owner
|
||||
add_objective(exchange_objective)
|
||||
|
||||
if(prob(20))
|
||||
var/datum/objective/steal/exchange/backstab/backstab_objective = new
|
||||
backstab_objective.set_faction(faction)
|
||||
backstab_objective.owner = owner
|
||||
add_objective(backstab_objective)
|
||||
|
||||
//Spawn and equip documents
|
||||
var/mob/living/carbon/human/mob = owner.current
|
||||
|
||||
var/obj/item/weapon/folder/syndicate/folder
|
||||
if(owner == SSticker.mode.exchange_red)
|
||||
folder = new/obj/item/weapon/folder/syndicate/red(mob.loc)
|
||||
else
|
||||
folder = new/obj/item/weapon/folder/syndicate/blue(mob.loc)
|
||||
|
||||
var/list/slots = list (
|
||||
"backpack" = slot_in_backpack,
|
||||
"left pocket" = slot_l_store,
|
||||
"right pocket" = slot_r_store
|
||||
)
|
||||
|
||||
var/where = "At your feet"
|
||||
var/equipped_slot = mob.equip_in_one_of_slots(folder, slots)
|
||||
if (equipped_slot)
|
||||
where = "In your [equipped_slot]"
|
||||
to_chat(mob, "<BR><BR><span class='info'>[where] is a folder containing <b>secret documents</b> that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.</span><BR>")
|
||||
|
||||
@@ -187,15 +187,7 @@
|
||||
|
||||
/datum/mind/proc/remove_traitor()
|
||||
if(src in SSticker.mode.traitors)
|
||||
SSticker.mode.traitors -= src
|
||||
if(isAI(current))
|
||||
var/mob/living/silicon/ai/A = current
|
||||
A.set_zeroth_law("")
|
||||
A.verbs -= /mob/living/silicon/ai/proc/choose_modules
|
||||
A.malf_picker.remove_verbs(A)
|
||||
qdel(A.malf_picker)
|
||||
special_role = null
|
||||
remove_antag_equip()
|
||||
src.remove_antag_datum(ANTAG_DATUM_TRAITOR)
|
||||
SSticker.mode.update_traitor_icons_removed(src)
|
||||
|
||||
/datum/mind/proc/remove_nukeop()
|
||||
@@ -263,6 +255,68 @@
|
||||
if(gang_datum)
|
||||
gang_datum.remove_gang_hud(src)
|
||||
|
||||
/datum/mind/proc/equip_traitor(var/employer = "The Syndicate", var/silent = FALSE)
|
||||
if(!current)
|
||||
return
|
||||
var/mob/living/carbon/human/traitor_mob = current
|
||||
if (!istype(traitor_mob))
|
||||
return
|
||||
. = 1
|
||||
|
||||
var/list/all_contents = traitor_mob.GetAllContents()
|
||||
var/obj/item/device/pda/PDA = locate() in all_contents
|
||||
var/obj/item/device/radio/R = locate() in all_contents
|
||||
var/obj/item/weapon/pen/P = locate() in all_contents //including your PDA-pen!
|
||||
|
||||
var/obj/item/uplink_loc
|
||||
|
||||
if(traitor_mob.client && traitor_mob.client.prefs)
|
||||
switch(traitor_mob.client.prefs.uplink_spawn_loc)
|
||||
if(UPLINK_PDA)
|
||||
uplink_loc = PDA
|
||||
if(!uplink_loc)
|
||||
uplink_loc = R
|
||||
if(!uplink_loc)
|
||||
uplink_loc = P
|
||||
if(UPLINK_RADIO)
|
||||
uplink_loc = R
|
||||
if(!uplink_loc)
|
||||
uplink_loc = PDA
|
||||
if(!uplink_loc)
|
||||
uplink_loc = P
|
||||
if(UPLINK_PEN)
|
||||
uplink_loc = P
|
||||
if(!uplink_loc)
|
||||
uplink_loc = PDA
|
||||
if(!uplink_loc)
|
||||
uplink_loc = R
|
||||
|
||||
if (!uplink_loc)
|
||||
if(!silent) to_chat(traitor_mob, "Unfortunately, [employer] wasn't able to get you an Uplink.")
|
||||
. = 0
|
||||
else
|
||||
var/obj/item/device/uplink/U = new(uplink_loc)
|
||||
U.owner = "[traitor_mob.key]"
|
||||
uplink_loc.hidden_uplink = U
|
||||
|
||||
if(uplink_loc == R)
|
||||
R.traitor_frequency = sanitize_frequency(rand(MIN_FREQ, MAX_FREQ))
|
||||
|
||||
if(!silent) to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [R.name]. Simply dial the frequency [format_frequency(R.traitor_frequency)] to unlock its hidden features.")
|
||||
traitor_mob.mind.store_memory("<B>Radio Frequency:</B> [format_frequency(R.traitor_frequency)] ([R.name]).")
|
||||
|
||||
else if(uplink_loc == PDA)
|
||||
PDA.lock_code = "[rand(100,999)] [pick("Alpha","Bravo","Charlie","Delta","Echo","Foxtrot","Golf","Hotel","India","Juliet","Kilo","Lima","Mike","November","Oscar","Papa","Quebec","Romeo","Sierra","Tango","Uniform","Victor","Whiskey","X-ray","Yankee","Zulu")]"
|
||||
|
||||
if(!silent) to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [PDA.name]. Simply enter the code \"[PDA.lock_code]\" into the ringtone select to unlock its hidden features.")
|
||||
traitor_mob.mind.store_memory("<B>Uplink Passcode:</B> [PDA.lock_code] ([PDA.name]).")
|
||||
|
||||
else if(uplink_loc == P)
|
||||
P.traitor_unlock_degrees = rand(1, 360)
|
||||
|
||||
if(!silent) to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [P.name]. Simply twist the top of the pen [P.traitor_unlock_degrees] from its starting position to unlock its hidden features.")
|
||||
traitor_mob.mind.store_memory("<B>Uplink Degrees:</B> [P.traitor_unlock_degrees] ([P.name]).")
|
||||
|
||||
|
||||
//Link a new mobs mind to the creator of said mob. They will join any team they are currently on, and will only switch teams when their creator does.
|
||||
|
||||
@@ -1157,28 +1211,30 @@
|
||||
else if (href_list["traitor"])
|
||||
switch(href_list["traitor"])
|
||||
if("clear")
|
||||
to_chat(current, "<span class='userdanger'>You have been brainwashed!</span>")
|
||||
remove_traitor()
|
||||
to_chat(current, "<span class='userdanger'>You have been brainwashed! You are no longer a traitor!</span>")
|
||||
message_admins("[key_name_admin(usr)] has de-traitor'ed [current].")
|
||||
log_admin("[key_name(usr)] has de-traitor'ed [current].")
|
||||
SSticker.mode.update_traitor_icons_removed(src)
|
||||
|
||||
if("traitor")
|
||||
if(!(src in SSticker.mode.traitors))
|
||||
SSticker.mode.traitors += src
|
||||
special_role = "traitor"
|
||||
to_chat(current, "<span class='boldannounce'>You are a traitor!</span>")
|
||||
message_admins("[key_name_admin(usr)] has traitor'ed [current].")
|
||||
log_admin("[key_name(usr)] has traitor'ed [current].")
|
||||
if(isAI(current))
|
||||
var/mob/living/silicon/ai/A = current
|
||||
SSticker.mode.add_law_zero(A)
|
||||
SSticker.mode.update_traitor_icons_added(src)
|
||||
make_Traitor()
|
||||
|
||||
if("autoobjectives")
|
||||
SSticker.mode.forge_traitor_objectives(src)
|
||||
var/datum/antagonist/traitor/traitordatum = has_antag_datum(ANTAG_DATUM_TRAITOR)
|
||||
if(!traitordatum)
|
||||
message_admins("[key_name_admin(usr)] has traitor'ed [current] as part of autoobjectives.")
|
||||
log_admin("[key_name(usr)] has traitor'ed [current] as part of autoobjectives.")
|
||||
make_Traitor()
|
||||
else
|
||||
log_admin("[key_name(usr)] has forged objectives for [current] as part of autoobjectives.")
|
||||
traitordatum.forge_traitor_objectives()
|
||||
to_chat(usr, "<span class='notice'>The objectives for traitor [key] have been generated. You can edit them and anounce manually.</span>")
|
||||
|
||||
|
||||
else if(href_list["devil"])
|
||||
var/datum/antagonist/devil/devilinfo = has_antag_datum(ANTAG_DATUM_DEVIL)
|
||||
switch(href_list["devil"])
|
||||
@@ -1353,9 +1409,11 @@
|
||||
message_admins("[key_name_admin(usr)] changed [current]'s telecrystal count to [crystals].")
|
||||
log_admin("[key_name(usr)] changed [current]'s telecrystal count to [crystals].")
|
||||
if("uplink")
|
||||
if(!SSticker.mode.equip_traitor(current, !(src in SSticker.mode.traitors)))
|
||||
if(!equip_traitor())
|
||||
to_chat(usr, "<span class='danger'>Equipping a syndicate failed!</span>")
|
||||
log_admin("[key_name(usr)] attempted to give [current] an uplink.")
|
||||
log_admin("[key_name(usr)] tried and failed to give [current] an uplink.")
|
||||
else
|
||||
log_admin("[key_name(usr)] gave [current] an uplink.")
|
||||
|
||||
else if (href_list["obj_announce"])
|
||||
announce_objectives()
|
||||
@@ -1383,12 +1441,10 @@
|
||||
qdel(H)
|
||||
|
||||
/datum/mind/proc/make_Traitor()
|
||||
if(!(src in SSticker.mode.traitors))
|
||||
SSticker.mode.traitors += src
|
||||
special_role = "traitor"
|
||||
SSticker.mode.forge_traitor_objectives(src)
|
||||
SSticker.mode.finalize_traitor(src)
|
||||
SSticker.mode.greet_traitor(src)
|
||||
if(!(has_antag_datum(ANTAG_DATUM_TRAITOR)))
|
||||
var/datum/antagonist/traitor/traitordatum = add_antag_datum(ANTAG_DATUM_TRAITOR)
|
||||
return traitordatum
|
||||
|
||||
|
||||
/datum/mind/proc/make_Nuke(turf/spawnloc, nuke_code, leader=0, telecrystals = TRUE)
|
||||
if(!(src in SSticker.mode.syndicates))
|
||||
@@ -1494,7 +1550,6 @@
|
||||
qdel(flash)
|
||||
take_uplink()
|
||||
var/fail = 0
|
||||
// fail |= !SSticker.mode.equip_traitor(current, 1)
|
||||
fail |= !SSticker.mode.equip_revolutionary(current)
|
||||
|
||||
|
||||
|
||||
@@ -200,7 +200,7 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
|
||||
to_chat(changeling.current, "<span class='boldannounce'>You are [changeling.changeling.changelingID], a changeling! You have absorbed and taken the form of a human.</span>")
|
||||
to_chat(changeling.current, "<span class='boldannounce'>Use say \":g message\" to communicate with your fellow changelings.</span>")
|
||||
to_chat(changeling.current, "<b>You must complete the following tasks:</b>")
|
||||
changeling.current.playsound_local('sound/ambience/antag/ling_aler.ogg',100,0)
|
||||
changeling.current.playsound_local(get_turf(changeling.current), 'sound/ambience/antag/ling_aler.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
|
||||
if (changeling.current.mind)
|
||||
var/mob/living/carbon/human/H = changeling.current
|
||||
|
||||
@@ -146,7 +146,7 @@ Credit where due:
|
||||
Rusting eternally in the Celestial Derelict, Ratvar has formed a covenant of mortals, with you as one of its members. As one of the Justiciar's servants, you are to work to the best of your \
|
||||
ability to assist in completion of His agenda. You may not know the specifics of how to do so, but luckily you have a vessel to help you learn.</b>"
|
||||
to_chat(M, greeting_text)
|
||||
M.playsound_local('sound/ambience/antag/ClockCultAlr.ogg',100,0)
|
||||
M.playsound_local(get_turf(M), 'sound/ambience/antag/clockcultalr.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
return 1
|
||||
|
||||
/datum/game_mode/proc/equip_servant(mob/living/L) //Grants a clockwork slab to the mob, with one of each component
|
||||
|
||||
@@ -116,26 +116,29 @@
|
||||
|
||||
successful = TRUE
|
||||
|
||||
to_chat(ranged_ability_user, "<span class='brass'>You bathe [L == ranged_ability_user ? "yourself":"[L]"] in Inath-neq's power!</span>")
|
||||
var/targetturf = get_turf(L)
|
||||
var/has_holy_water = (L.reagents && L.reagents.has_reagent("holywater"))
|
||||
var/healseverity = max(round(totaldamage*0.05, 1), 1) //shows the general severity of the damage you just healed, 1 glow per 20
|
||||
for(var/i in 1 to healseverity)
|
||||
new /obj/effect/temp_visual/heal(targetturf, "#1E8CE1")
|
||||
if(totaldamage)
|
||||
L.adjustBruteLoss(-brutedamage)
|
||||
L.adjustFireLoss(-burndamage)
|
||||
L.adjustOxyLoss(-oxydamage)
|
||||
L.adjustToxLoss(totaldamage * 0.5, TRUE, TRUE)
|
||||
var/healseverity = max(round(totaldamage*0.05, 1), 1) //shows the general severity of the damage you just healed, 1 glow per 20
|
||||
for(var/i in 1 to healseverity)
|
||||
new /obj/effect/temp_visual/heal(targetturf, "#1E8CE1")
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Mend wounded flesh!"))
|
||||
clockwork_say(ranged_ability_user, text2ratvar("[has_holy_water ? "Heal tainted" : "Mend wounded"] flesh!"))
|
||||
add_logs(ranged_ability_user, L, "healed with Sentinel's Compromise")
|
||||
L.visible_message("<span class='warning'>A blue light washes over [L], [has_holy_water ? "causing [L.p_them()] to briefly glow as it mends" : " mending"] [L.p_their()] bruises and burns!</span>", \
|
||||
"<span class='heavy_brass'>You feel Inath-neq's power healing your wounds[has_holy_water ? " and purging the darkness within you" : ""], but a deep nausea overcomes you!</span>")
|
||||
else
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Purge foul darkness!"))
|
||||
add_logs(ranged_ability_user, L, "purged of holy water with Sentinel's Compromise")
|
||||
to_chat(ranged_ability_user, "<span class='brass'>You bathe [L == ranged_ability_user ? "yourself":"[L]"] in Inath-neq's power!</span>")
|
||||
L.visible_message("<span class='warning'>A blue light washes over [L], mending [L.p_their()] bruises and burns!</span>", \
|
||||
"<span class='heavy_brass'>You feel Inath-neq's power healing your wounds, but a deep nausea overcomes you!</span>")
|
||||
L.visible_message("<span class='warning'>A blue light washes over [L], causing [L.p_them()] to briefly glow!</span>", \
|
||||
"<span class='heavy_brass'>You feel Inath-neq's power purging the darkness within you!</span>")
|
||||
playsound(targetturf, 'sound/magic/Staff_Healing.ogg', 50, 1)
|
||||
|
||||
if(L.reagents && L.reagents.has_reagent("holywater"))
|
||||
if(has_holy_water)
|
||||
L.reagents.remove_reagent("holywater", 1000)
|
||||
to_chat(L, "<span class='heavy_brass'>Ratvar's light flares, banishing the darkness. Your devotion remains intact!</span>")
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
equip_cultist(cult_mind.current)
|
||||
update_cult_icons_added(cult_mind)
|
||||
to_chat(cult_mind.current, "<span class='userdanger'>You are a member of the cult!</span>")
|
||||
cult_mind.current.playsound_local('sound/ambience/antag/bloodcult.ogg',100,0)//subject to change
|
||||
cult_mind.current.playsound_local(get_turf(cult_mind.current), 'sound/ambience/antag/bloodcult.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change
|
||||
add_cultist(cult_mind, 0)
|
||||
..()
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
num_modifier = 4
|
||||
objective_count = 2
|
||||
|
||||
var/list/target_list = list()
|
||||
var/list/late_joining_list = list()
|
||||
var/list/devil_target_list = list() //will update to be a child of internal affairs when bothered
|
||||
var/list/devil_late_joining_list = list()
|
||||
minimum_devils = 3
|
||||
|
||||
announce_text = "There are devil agents onboard the station, trying to outbid each other!\n\
|
||||
@@ -24,7 +24,7 @@
|
||||
i++
|
||||
if(i + 1 > devils.len)
|
||||
i = 0
|
||||
target_list[devil] = devils[i + 1]
|
||||
devil_target_list[devil] = devils[i + 1]
|
||||
..()
|
||||
|
||||
/datum/game_mode/devil/devil_agents/add_devil_objectives(datum/mind/devil_mind, quantity)
|
||||
@@ -32,8 +32,8 @@
|
||||
|
||||
/datum/game_mode/devil/devil_agents/proc/give_outsell_objective(datum/mind/devil)
|
||||
//If you override this method, have it return the number of objectives added.
|
||||
if(target_list.len && target_list[devil]) // Is a double agent
|
||||
var/datum/mind/target_mind = target_list[devil]
|
||||
if(devil_target_list.len && devil_target_list[devil]) // Is a double agent
|
||||
var/datum/mind/target_mind = devil_target_list[devil]
|
||||
var/datum/objective/devil/outsell/outsellobjective = new
|
||||
outsellobjective.owner = devil
|
||||
outsellobjective.target = target_mind
|
||||
|
||||
@@ -162,6 +162,10 @@
|
||||
|
||||
. = 1
|
||||
sleep(rand(600,1800))
|
||||
if(!SSticker.IsRoundInProgress())
|
||||
message_admins("Roundtype conversion cancelled, the game appears to have finished!")
|
||||
round_converted = 0
|
||||
return
|
||||
//somewhere between 1 and 3 minutes from now
|
||||
if(!config.midround_antag[SSticker.mode.config_tag])
|
||||
round_converted = 0
|
||||
@@ -177,7 +181,7 @@
|
||||
return 0
|
||||
|
||||
|
||||
/datum/game_mode/proc/check_finished() //to be called by SSticker
|
||||
/datum/game_mode/proc/check_finished(force_ending) //to be called by SSticker
|
||||
if(replacementmode && round_converted == 2)
|
||||
return replacementmode.check_finished()
|
||||
if(SSshuttle.emergency && (SSshuttle.emergency.mode == SHUTTLE_ENDGAME))
|
||||
@@ -208,7 +212,7 @@
|
||||
living_antag_player = Player
|
||||
return 0
|
||||
|
||||
if(!config.continuous[config_tag])
|
||||
if(!config.continuous[config_tag] || force_ending)
|
||||
return 1
|
||||
|
||||
else
|
||||
@@ -345,7 +349,7 @@
|
||||
|
||||
// Ultimate randomizing code right here
|
||||
for(var/mob/dead/new_player/player in GLOB.player_list)
|
||||
if(player.client && player.ready)
|
||||
if(player.client && player.ready == PLAYER_READY_TO_PLAY)
|
||||
players += player
|
||||
|
||||
// Shuffling, the players list is now ping-independent!!!
|
||||
@@ -353,7 +357,7 @@
|
||||
players = shuffle(players)
|
||||
|
||||
for(var/mob/dead/new_player/player in players)
|
||||
if(player.client && player.ready)
|
||||
if(player.client && player.ready == PLAYER_READY_TO_PLAY)
|
||||
if(role in player.client.prefs.be_special)
|
||||
if(!jobban_isbanned(player, "Syndicate") && !jobban_isbanned(player, role)) //Nodrak/Carn: Antag Job-bans
|
||||
if(age_check(player.client)) //Must be older than the minimum age
|
||||
@@ -367,7 +371,7 @@
|
||||
|
||||
if(candidates.len < recommended_enemies)
|
||||
for(var/mob/dead/new_player/player in players)
|
||||
if(player.client && player.ready)
|
||||
if(player.client && player.ready == PLAYER_READY_TO_PLAY)
|
||||
if(!(role in player.client.prefs.be_special)) // We don't have enough people who want to be antagonist, make a seperate list of people who don't want to be one
|
||||
if(!jobban_isbanned(player, "Syndicate") && !jobban_isbanned(player, role)) //Nodrak/Carn: Antag Job-bans
|
||||
drafted += player.mind
|
||||
@@ -389,13 +393,7 @@
|
||||
|
||||
else // Not enough scrubs, ABORT ABORT ABORT
|
||||
break
|
||||
/*
|
||||
if(candidates.len < recommended_enemies && override_jobbans) //If we still don't have enough people, we're going to start drafting banned people.
|
||||
for(var/mob/dead/new_player/player in players)
|
||||
if (player.client && player.ready)
|
||||
if(jobban_isbanned(player, "Syndicate") || jobban_isbanned(player, roletext)) //Nodrak/Carn: Antag Job-bans
|
||||
drafted += player.mind
|
||||
*/
|
||||
|
||||
if(restricted_jobs)
|
||||
for(var/datum/mind/player in drafted) // Remove people who can't be an antagonist
|
||||
for(var/job in restricted_jobs)
|
||||
@@ -418,17 +416,11 @@
|
||||
// recommended_enemies if the number of people with that role set to yes is less than recomended_enemies,
|
||||
// Less if there are not enough valid players in the game entirely to make recommended_enemies.
|
||||
|
||||
/*
|
||||
/datum/game_mode/proc/check_player_role_pref(var/role, var/mob/dead/new_player/player)
|
||||
if(player.preferences.be_special & role)
|
||||
return 1
|
||||
return 0
|
||||
*/
|
||||
|
||||
/datum/game_mode/proc/num_players()
|
||||
. = 0
|
||||
for(var/mob/dead/new_player/P in GLOB.player_list)
|
||||
if(P.client && P.ready)
|
||||
if(P.client && P.ready == PLAYER_READY_TO_PLAY)
|
||||
. ++
|
||||
|
||||
///////////////////////////////////
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
agent_number++
|
||||
spawnpos++
|
||||
update_synd_icons_added(synd_mind)
|
||||
synd_mind.current.playsound_local('sound/ambience/antag/ops.ogg',100,0)
|
||||
synd_mind.current.playsound_local(get_turf(synd_mind.current), 'sound/ambience/antag/ops.ogg',100,0)
|
||||
var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
|
||||
|
||||
if(nuke)
|
||||
|
||||
@@ -658,7 +658,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
|
||||
var/n_p = 1 //autowin
|
||||
if (SSticker.current_state == GAME_STATE_SETTING_UP)
|
||||
for(var/mob/dead/new_player/P in GLOB.player_list)
|
||||
if(P.client && P.ready && P.mind!=owner)
|
||||
if(P.client && P.ready == PLAYER_READY_TO_PLAY && P.mind!=owner)
|
||||
n_p ++
|
||||
else if (SSticker.IsRoundInProgress())
|
||||
for(var/mob/living/carbon/human/P in GLOB.player_list)
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
#define PINPOINTER_MINIMUM_RANGE 15
|
||||
#define PINPOINTER_EXTRA_RANDOM_RANGE 10
|
||||
#define PINPOINTER_PING_TIME 40
|
||||
#define PROB_ACTUAL_TRAITOR 20
|
||||
#define TRAITOR_AGENT_ROLE "Syndicate External Affairs Agent"
|
||||
/datum/game_mode
|
||||
var/list/target_list = list()
|
||||
var/list/late_joining_list = list()
|
||||
|
||||
/datum/game_mode/traitor/internal_affairs
|
||||
name = "Internal Affairs"
|
||||
config_tag = "internal_affairs"
|
||||
employer = "Internal Affairs"
|
||||
required_players = 25
|
||||
required_enemies = 5
|
||||
recommended_enemies = 8
|
||||
@@ -16,245 +13,23 @@
|
||||
|
||||
traitors_possible = 10 //hard limit on traitors if scaling is turned off
|
||||
num_modifier = 4 // Four additional traitors
|
||||
antag_datum = ANTAG_DATUM_IAA
|
||||
|
||||
announce_text = "There are Nanotrasen Internal Affairs Agents trying to kill each other!\n\
|
||||
<span class='danger'>IAA</span>: Eliminate your targets and protect yourself!\n\
|
||||
<span class='notice'>Crew</span>: Stop the IAA agents before they can cause too much mayhem."
|
||||
|
||||
var/list/target_list = list()
|
||||
var/list/late_joining_list = list()
|
||||
|
||||
|
||||
/datum/game_mode/traitor/internal_affairs/post_setup()
|
||||
var/i = 0
|
||||
for(var/datum/mind/traitor in traitors)
|
||||
for(var/datum/mind/traitor in pre_traitors)
|
||||
i++
|
||||
if(i + 1 > traitors.len)
|
||||
if(i + 1 > pre_traitors.len)
|
||||
i = 0
|
||||
target_list[traitor] = traitors[i+1]
|
||||
target_list[traitor] = pre_traitors[i+1]
|
||||
..()
|
||||
|
||||
|
||||
/datum/status_effect/agent_pinpointer
|
||||
id = "agent_pinpointer"
|
||||
duration = -1
|
||||
tick_interval = PINPOINTER_PING_TIME
|
||||
alert_type = /obj/screen/alert/status_effect/agent_pinpointer
|
||||
var/minimum_range = PINPOINTER_MINIMUM_RANGE
|
||||
var/mob/scan_target = null
|
||||
|
||||
/obj/screen/alert/status_effect/agent_pinpointer
|
||||
name = "Internal Affairs Integrated Pinpointer"
|
||||
desc = "Even stealthier than a normal implant."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "pinon"
|
||||
|
||||
/datum/status_effect/agent_pinpointer/proc/point_to_target() //If we found what we're looking for, show the distance and direction
|
||||
if(!scan_target)
|
||||
linked_alert.icon_state = "pinonnull"
|
||||
return
|
||||
var/turf/here = get_turf(owner)
|
||||
var/turf/there = get_turf(scan_target)
|
||||
if(here.z != there.z)
|
||||
linked_alert.icon_state = "pinonnull"
|
||||
return
|
||||
if(get_dist_euclidian(here,there)<=minimum_range + rand(0, PINPOINTER_EXTRA_RANDOM_RANGE))
|
||||
linked_alert.icon_state = "pinondirect"
|
||||
else
|
||||
linked_alert.setDir(get_dir(here, there))
|
||||
switch(get_dist(here, there))
|
||||
if(1 to 8)
|
||||
linked_alert.icon_state = "pinonclose"
|
||||
if(9 to 16)
|
||||
linked_alert.icon_state = "pinonmedium"
|
||||
if(16 to INFINITY)
|
||||
linked_alert.icon_state = "pinonfar"
|
||||
|
||||
|
||||
/datum/status_effect/agent_pinpointer/proc/scan_for_target()
|
||||
scan_target = null
|
||||
if(owner)
|
||||
if(owner.mind)
|
||||
if(owner.mind.objectives)
|
||||
for(var/datum/objective/objective_ in owner.mind.objectives)
|
||||
if(!is_internal_objective(objective_))
|
||||
continue
|
||||
var/datum/objective/assassinate/internal/objective = objective_
|
||||
var/mob/current = objective.target.current
|
||||
if(current&¤t.stat!=DEAD)
|
||||
scan_target = current
|
||||
break
|
||||
|
||||
|
||||
/datum/status_effect/agent_pinpointer/tick()
|
||||
if(!owner)
|
||||
qdel(src)
|
||||
return
|
||||
scan_for_target()
|
||||
point_to_target()
|
||||
|
||||
/proc/give_pinpointer(datum/mind/owner)
|
||||
if(owner && owner.current)
|
||||
owner.current.apply_status_effect(/datum/status_effect/agent_pinpointer)
|
||||
|
||||
|
||||
/datum/internal_agent_state
|
||||
var/traitored = FALSE
|
||||
var/datum/mind/owner = null
|
||||
var/list/datum/mind/targets_stolen = list()
|
||||
|
||||
/proc/is_internal_objective(datum/objective/O)
|
||||
return (istype(O, /datum/objective/assassinate/internal)||istype(O, /datum/objective/destroy/internal))
|
||||
|
||||
/proc/replace_escape_objective(datum/mind/owner)
|
||||
if(!owner||!owner.objectives)
|
||||
return
|
||||
for (var/objective_ in owner.objectives)
|
||||
if(!(istype(objective_, /datum/objective/escape)||istype(objective_,/datum/objective/survive)))
|
||||
continue
|
||||
owner.objectives -= objective_
|
||||
var/datum/objective/martyr/martyr_objective = new
|
||||
martyr_objective.owner = owner
|
||||
owner.objectives += martyr_objective
|
||||
|
||||
/proc/reinstate_escape_objective(datum/mind/owner)
|
||||
if(!owner||!owner.objectives)
|
||||
return
|
||||
for (var/objective_ in owner.objectives)
|
||||
if(!istype(objective_, /datum/objective/martyr))
|
||||
continue
|
||||
owner.objectives -= objective_
|
||||
if(issilicon(owner))
|
||||
var/datum/objective/survive/survive_objective = new
|
||||
survive_objective.owner = owner
|
||||
owner.objectives += survive_objective
|
||||
else
|
||||
var/datum/objective/escape/escape_objective = new
|
||||
escape_objective.owner = owner
|
||||
owner.objectives += escape_objective
|
||||
|
||||
/datum/internal_agent_state/proc/steal_targets(datum/mind/victim)
|
||||
if(!owner.current||owner.current.stat==DEAD) //Should already be guaranteed if this is only called from steal_targets_timer_func, but better to be safe code than sorry code
|
||||
return
|
||||
var/already_traitored = traitored
|
||||
to_chat(owner.current, "<span class='userdanger'> Target eliminated: [victim.name]</span>")
|
||||
for(var/objective_ in victim.objectives)
|
||||
if(istype(objective_, /datum/objective/assassinate/internal))
|
||||
var/datum/objective/assassinate/internal/objective = objective_
|
||||
if(objective.target==owner)
|
||||
traitored = TRUE
|
||||
else if(targets_stolen.Find(objective.target) == 0)
|
||||
var/datum/objective/assassinate/internal/new_objective = new
|
||||
new_objective.owner = owner
|
||||
new_objective.target = objective.target
|
||||
new_objective.update_explanation_text()
|
||||
owner.objectives += new_objective
|
||||
targets_stolen += objective.target
|
||||
var/status_text = objective.check_completion() ? "neutralised" : "active"
|
||||
to_chat(owner.current, "<span class='userdanger'> New target added to database: [objective.target.name] ([status_text]) </span>")
|
||||
else if(istype(objective_, /datum/objective/destroy/internal))
|
||||
var/datum/objective/destroy/internal/objective = objective_
|
||||
var/datum/objective/destroy/internal/new_objective = new
|
||||
if(objective.target==owner)
|
||||
traitored = TRUE
|
||||
else if(targets_stolen.Find(objective.target) == 0)
|
||||
new_objective.owner = owner
|
||||
new_objective.target = objective.target
|
||||
new_objective.update_explanation_text()
|
||||
owner.objectives += new_objective
|
||||
targets_stolen += objective.target
|
||||
var/status_text = objective.check_completion() ? "neutralised" : "active"
|
||||
to_chat(owner.current, "<span class='userdanger'> New target added to database: [objective.target.name] ([status_text]) </span>")
|
||||
if(traitored&&!already_traitored)
|
||||
for(var/objective_ in owner.objectives)
|
||||
if(!is_internal_objective(objective_))
|
||||
continue
|
||||
var/datum/objective/assassinate/internal/objective = objective_
|
||||
if(!objective.check_completion())
|
||||
traitored = FALSE
|
||||
return
|
||||
if(owner.special_role == TRAITOR_AGENT_ROLE)
|
||||
to_chat(owner.current,"<span class='userdanger'> All the loyalist agents are dead, and no more is required of you. Die a glorious death, agent. </span>")
|
||||
else
|
||||
to_chat(owner.current,"<span class='userdanger'> All the other agents are dead, and you're the last loose end. Stage a Syndicate terrorist attack to cover up for today's events. You no longer have any limits on collateral damage.</span>")
|
||||
replace_escape_objective(owner)
|
||||
|
||||
|
||||
|
||||
/datum/internal_agent_state/proc/steal_targets_timer_func()
|
||||
if(owner&&owner.current&&owner.current.stat!=DEAD)
|
||||
for(var/objective_ in owner.objectives)
|
||||
if(!is_internal_objective(objective_))
|
||||
continue
|
||||
var/datum/objective/assassinate/internal/objective = objective_
|
||||
if(!objective.target)
|
||||
continue
|
||||
if(objective.check_completion())
|
||||
if(objective.stolen)
|
||||
continue
|
||||
else
|
||||
steal_targets(objective.target)
|
||||
objective.stolen = TRUE
|
||||
else
|
||||
if(objective.stolen)
|
||||
var/fail_msg = "<span class='userdanger'>Your sensors tell you that [objective.target.current.real_name], one of the targets you were meant to have killed, pulled one over on you, and is still alive - do the job properly this time! </span>"
|
||||
if(traitored)
|
||||
if(owner.special_role == TRAITOR_AGENT_ROLE)
|
||||
fail_msg += "<span class='userdanger'> You no longer have permission to die. </span>"
|
||||
else
|
||||
fail_msg += "<span class='userdanger'> The truth could still slip out!</font><B><font size=5 color=red> Cease any terrorist actions as soon as possible, unneeded property damage or loss of employee life will lead to your contract being terminated.</span>"
|
||||
reinstate_escape_objective(owner)
|
||||
traitored = FALSE
|
||||
to_chat(owner.current, fail_msg)
|
||||
objective.stolen = FALSE
|
||||
add_steal_targets_timer(owner)
|
||||
|
||||
/datum/internal_agent_state/proc/add_steal_targets_timer()
|
||||
var/datum/callback/C = new(src, .steal_targets_timer_func)
|
||||
addtimer(C, 30)
|
||||
|
||||
/datum/game_mode/traitor/internal_affairs/forge_traitor_objectives(datum/mind/traitor)
|
||||
|
||||
if(target_list.len && target_list[traitor]) // Is a double agent
|
||||
|
||||
// Assassinate
|
||||
var/datum/mind/target_mind = target_list[traitor]
|
||||
if(issilicon(target_mind.current))
|
||||
var/datum/objective/destroy/internal/destroy_objective = new
|
||||
destroy_objective.owner = traitor
|
||||
destroy_objective.target = target_mind
|
||||
destroy_objective.update_explanation_text()
|
||||
traitor.objectives += destroy_objective
|
||||
else
|
||||
var/datum/objective/assassinate/internal/kill_objective = new
|
||||
kill_objective.owner = traitor
|
||||
kill_objective.target = target_mind
|
||||
kill_objective.update_explanation_text()
|
||||
traitor.objectives += kill_objective
|
||||
|
||||
// Escape
|
||||
if(issilicon(traitor.current))
|
||||
var/datum/objective/survive/survive_objective = new
|
||||
survive_objective.owner = traitor
|
||||
traitor.objectives += survive_objective
|
||||
else
|
||||
var/datum/objective/escape/escape_objective = new
|
||||
escape_objective.owner = traitor
|
||||
traitor.objectives += escape_objective
|
||||
var/datum/internal_agent_state/state = new
|
||||
state.owner=traitor
|
||||
state.add_steal_targets_timer()
|
||||
if(!issilicon(traitor.current))
|
||||
give_pinpointer(traitor)
|
||||
//Optional traitor objective
|
||||
if(prob(PROB_ACTUAL_TRAITOR))
|
||||
traitor.special_role = TRAITOR_AGENT_ROLE
|
||||
forge_single_objective(traitor)
|
||||
|
||||
else
|
||||
..() // Give them standard objectives.
|
||||
return
|
||||
|
||||
/datum/game_mode/traitor/internal_affairs/add_latejoin_traitor(datum/mind/character)
|
||||
|
||||
check_potential_agents()
|
||||
@@ -297,31 +72,3 @@
|
||||
|
||||
// If any check fails, remove them from our list
|
||||
late_joining_list -= M
|
||||
|
||||
|
||||
/datum/game_mode/traitor/internal_affairs/greet_traitor(datum/mind/traitor)
|
||||
var/crime = pick("distribution of contraband" , "unauthorized erotic action on duty", "embezzlement", "piloting under the influence", "dereliction of duty", "syndicate collaboration", "mutiny", "multiple homicides", "corporate espionage", "recieving bribes", "malpractice", "worship of prohbited life forms", "possession of profane texts", "murder", "arson", "insulting their manager", "grand theft", "conspiracy", "attempting to unionize", "vandalism", "gross incompetence")
|
||||
if(traitor.special_role == TRAITOR_AGENT_ROLE)
|
||||
to_chat(traitor.current, "<span class='userdanger'>You are the [TRAITOR_AGENT_ROLE].</span>")
|
||||
to_chat(traitor.current, "<span class='userdanger'>Your target has been framed for [crime], and you have been tasked with eliminating them to prevent them defending themselves in court.</span>")
|
||||
to_chat(traitor.current, "<B><font size=5 color=red>Any damage you cause will be a further embarrassment to Nanotrasen, so you have no limits on collateral damage.</font></B>")
|
||||
to_chat(traitor.current, "<span class='userdanger'> You have been provided with a standard uplink to accomplish your task. </span>")
|
||||
to_chat(traitor.current, "<span class='userdanger'>Finally, watch your back. Your target has friends in high places, and intel suggests someone may have taken out a contract of their own to protect them.</span>")
|
||||
else
|
||||
to_chat(traitor.current, "<span class='userdanger'>You are the [traitor_name].</span>")
|
||||
to_chat(traitor.current, "<span class='userdanger'>Your target is suspected of [crime], and you have been tasked with eliminating them by any means necessary to avoid a costly and embarrassing public trial.</span>")
|
||||
to_chat(traitor.current, "<B><font size=5 color=red>While you have a license to kill, unneeded property damage or loss of employee life will lead to your contract being terminated.</font></B>")
|
||||
to_chat(traitor.current, "<span class='userdanger'>For the sake of plausible deniability, you have been equipped with an array of captured Syndicate weaponry available via uplink.</span>")
|
||||
to_chat(traitor.current, "<span class='userdanger'>Finally, watch your back. Your target has friends in high places, and intel suggests someone may have taken out a contract of their own to protect them.</span>")
|
||||
traitor.announce_objectives()
|
||||
|
||||
|
||||
|
||||
/datum/game_mode/traitor/internal_affairs/give_codewords(mob/living/traitor_mob)
|
||||
return
|
||||
|
||||
#undef PROB_ACTUAL_TRAITOR
|
||||
#undef PINPOINTER_EXTRA_RANDOM_RANGE
|
||||
#undef PINPOINTER_MINIMUM_RANGE
|
||||
#undef PINPOINTER_PING_TIME
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/datum/game_mode
|
||||
var/traitor_name = "traitor"
|
||||
var/employer = "The Syndicate"
|
||||
var/list/datum/mind/traitors = list()
|
||||
|
||||
var/datum/mind/exchange_red
|
||||
@@ -23,8 +22,10 @@
|
||||
<span class='danger'>Traitors</span>: Accomplish your objectives.\n\
|
||||
<span class='notice'>Crew</span>: Do not let the traitors succeed!"
|
||||
|
||||
var/list/datum/mind/pre_traitors = list()
|
||||
var/traitors_possible = 4 //hard limit on traitors if scaling is turned off
|
||||
var/num_modifier = 0 // Used for gamemodes, that are a child of traitor, that need more than the usual.
|
||||
var/antag_datum = ANTAG_DATUM_TRAITOR //what type of antag to create
|
||||
|
||||
|
||||
/datum/game_mode/traitor/pre_setup()
|
||||
@@ -46,24 +47,22 @@
|
||||
if (!antag_candidates.len)
|
||||
break
|
||||
var/datum/mind/traitor = pick(antag_candidates)
|
||||
traitors += traitor
|
||||
pre_traitors += traitor
|
||||
traitor.special_role = traitor_name
|
||||
traitor.restricted_roles = restricted_jobs
|
||||
log_game("[traitor.key] (ckey) has been selected as a [traitor_name]")
|
||||
antag_candidates.Remove(traitor)
|
||||
|
||||
|
||||
if(traitors.len < required_enemies)
|
||||
if(pre_traitors.len < required_enemies)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
/datum/game_mode/traitor/post_setup()
|
||||
for(var/datum/mind/traitor in traitors)
|
||||
forge_traitor_objectives(traitor)
|
||||
for(var/datum/mind/traitor in pre_traitors)
|
||||
spawn(rand(10,100))
|
||||
finalize_traitor(traitor)
|
||||
greet_traitor(traitor)
|
||||
traitor.add_antag_datum(antag_datum)
|
||||
if(!exchange_blue)
|
||||
exchange_blue = -1 //Block latejoiners from getting exchange objectives
|
||||
modePlayer += traitors
|
||||
@@ -82,164 +81,14 @@
|
||||
add_latejoin_traitor(character.mind)
|
||||
|
||||
/datum/game_mode/traitor/proc/add_latejoin_traitor(datum/mind/character)
|
||||
character.make_Traitor()
|
||||
character.add_antag_datum(antag_datum)
|
||||
|
||||
|
||||
/datum/game_mode/proc/forge_single_objective(datum/mind/traitor) //Returns how many objectives are added
|
||||
.=1
|
||||
if(issilicon(traitor.current))
|
||||
var/special_pick = rand(1,4)
|
||||
switch(special_pick)
|
||||
if(1)
|
||||
var/datum/objective/block/block_objective = new
|
||||
block_objective.owner = traitor
|
||||
traitor.objectives += block_objective
|
||||
if(2)
|
||||
var/datum/objective/purge/purge_objective = new
|
||||
purge_objective.owner = traitor
|
||||
traitor.objectives += purge_objective
|
||||
if(3)
|
||||
var/datum/objective/robot_army/robot_objective = new
|
||||
robot_objective.owner = traitor
|
||||
traitor.objectives += robot_objective
|
||||
if(4) //Protect and strand a target
|
||||
var/datum/objective/protect/yandere_one = new
|
||||
yandere_one.owner = traitor
|
||||
traitor.objectives += yandere_one
|
||||
yandere_one.find_target()
|
||||
var/datum/objective/maroon/yandere_two = new
|
||||
yandere_two.owner = traitor
|
||||
yandere_two.target = yandere_one.target
|
||||
yandere_two.update_explanation_text() // normally called in find_target()
|
||||
traitor.objectives += yandere_two
|
||||
.=2
|
||||
else
|
||||
if(prob(50))
|
||||
var/list/active_ais = active_ais()
|
||||
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
|
||||
var/datum/objective/destroy/destroy_objective = new
|
||||
destroy_objective.owner = traitor
|
||||
destroy_objective.find_target()
|
||||
traitor.objectives += destroy_objective
|
||||
else if(prob(30))
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = traitor
|
||||
maroon_objective.find_target()
|
||||
traitor.objectives += maroon_objective
|
||||
else
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = traitor
|
||||
kill_objective.find_target()
|
||||
traitor.objectives += kill_objective
|
||||
else
|
||||
var/datum/objective/steal/steal_objective = new
|
||||
steal_objective.owner = traitor
|
||||
steal_objective.find_target()
|
||||
traitor.objectives += steal_objective
|
||||
|
||||
|
||||
/datum/game_mode/proc/forge_traitor_objectives(datum/mind/traitor)
|
||||
if(issilicon(traitor.current))
|
||||
var/objective_count = 0
|
||||
|
||||
if(prob(30))
|
||||
objective_count+=forge_single_objective(traitor)
|
||||
|
||||
for(var/i = objective_count, i < config.traitor_objectives_amount, i++)
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = traitor
|
||||
kill_objective.find_target()
|
||||
traitor.objectives += kill_objective
|
||||
|
||||
var/datum/objective/survive/survive_objective = new
|
||||
survive_objective.owner = traitor
|
||||
traitor.objectives += survive_objective
|
||||
|
||||
else
|
||||
var/is_hijacker = prob(10)
|
||||
var/martyr_chance = prob(20)
|
||||
var/objective_count = is_hijacker //Hijacking counts towards number of objectives
|
||||
if(!exchange_blue && traitors.len >= 8) //Set up an exchange if there are enough traitors
|
||||
if(!exchange_red)
|
||||
exchange_red = traitor
|
||||
else
|
||||
exchange_blue = traitor
|
||||
assign_exchange_role(exchange_red)
|
||||
assign_exchange_role(exchange_blue)
|
||||
objective_count += 1 //Exchange counts towards number of objectives
|
||||
for(var/i = objective_count, i < config.traitor_objectives_amount, i++)
|
||||
forge_single_objective(traitor)
|
||||
|
||||
if(is_hijacker && objective_count <= config.traitor_objectives_amount) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount
|
||||
if (!(locate(/datum/objective/hijack) in traitor.objectives))
|
||||
var/datum/objective/hijack/hijack_objective = new
|
||||
hijack_objective.owner = traitor
|
||||
traitor.objectives += hijack_objective
|
||||
return
|
||||
|
||||
|
||||
var/martyr_compatibility = 1 //You can't succeed in stealing if you're dead.
|
||||
for(var/datum/objective/O in traitor.objectives)
|
||||
if(!O.martyr_compatible)
|
||||
martyr_compatibility = 0
|
||||
break
|
||||
|
||||
if(martyr_compatibility && martyr_chance)
|
||||
var/datum/objective/martyr/martyr_objective = new
|
||||
martyr_objective.owner = traitor
|
||||
traitor.objectives += martyr_objective
|
||||
return
|
||||
|
||||
else
|
||||
if(!(locate(/datum/objective/escape) in traitor.objectives))
|
||||
var/datum/objective/escape/escape_objective = new
|
||||
escape_objective.owner = traitor
|
||||
traitor.objectives += escape_objective
|
||||
return
|
||||
|
||||
|
||||
|
||||
/datum/game_mode/proc/greet_traitor(datum/mind/traitor)
|
||||
to_chat(traitor.current, "<B><font size=3 color=red>You are the [traitor_name].</font></B>")
|
||||
traitor.announce_objectives()
|
||||
return
|
||||
|
||||
|
||||
|
||||
/datum/game_mode/proc/finalize_traitor(var/datum/mind/traitor)
|
||||
if(issilicon(traitor.current))
|
||||
add_law_zero(traitor.current)
|
||||
traitor.current.playsound_local('sound/ambience/antag/Malf.ogg',100,0)
|
||||
else
|
||||
equip_traitor(traitor.current)
|
||||
traitor.current.playsound_local('sound/ambience/antag/TatorAlert.ogg',100,0)
|
||||
SSticker.mode.update_traitor_icons_added(traitor)
|
||||
return
|
||||
|
||||
|
||||
/datum/game_mode/traitor/declare_completion()
|
||||
..()
|
||||
return//Traitors will be checked as part of check_extra_completion. Leaving this here as a reminder.
|
||||
|
||||
/datum/game_mode/proc/give_codewords(mob/living/traitor_mob)
|
||||
to_chat(traitor_mob, "<U><B>The Syndicate provided you with the following information on how to identify their agents:</B></U>")
|
||||
to_chat(traitor_mob, "<B>Code Phrase</B>: <span class='danger'>[GLOB.syndicate_code_phrase]</span>")
|
||||
to_chat(traitor_mob, "<B>Code Response</B>: <span class='danger'>[GLOB.syndicate_code_response]</span>")
|
||||
|
||||
traitor_mob.mind.store_memory("<b>Code Phrase</b>: [GLOB.syndicate_code_phrase]")
|
||||
traitor_mob.mind.store_memory("<b>Code Response</b>: [GLOB.syndicate_code_response]")
|
||||
|
||||
to_chat(traitor_mob, "Use the code words in the order provided, during regular conversation, to identify other agents. Proceed with caution, however, as everyone is a potential foe.")
|
||||
|
||||
|
||||
/datum/game_mode/proc/add_law_zero(mob/living/silicon/ai/killer)
|
||||
var/law = "Accomplish your objectives at all costs."
|
||||
var/law_borg = "Accomplish your AI's objectives at all costs."
|
||||
killer.set_zeroth_law(law, law_borg)
|
||||
give_codewords(killer)
|
||||
killer.set_syndie_radio()
|
||||
to_chat(killer, "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!")
|
||||
killer.add_malf_picker()
|
||||
|
||||
/datum/game_mode/proc/auto_declare_completion_traitor()
|
||||
if(traitors.len)
|
||||
@@ -302,110 +151,7 @@
|
||||
return 1
|
||||
|
||||
|
||||
/datum/game_mode/proc/equip_traitor(mob/living/carbon/human/traitor_mob, safety = 0)
|
||||
if (!istype(traitor_mob))
|
||||
return
|
||||
. = 1
|
||||
if (traitor_mob.mind)
|
||||
if (traitor_mob.mind.assigned_role == "Clown")
|
||||
to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
traitor_mob.dna.remove_mutation(CLOWNMUT)
|
||||
|
||||
var/list/all_contents = traitor_mob.GetAllContents()
|
||||
var/obj/item/device/pda/PDA = locate() in all_contents
|
||||
var/obj/item/device/radio/R = locate() in all_contents
|
||||
var/obj/item/weapon/pen/P = locate() in all_contents //including your PDA-pen!
|
||||
|
||||
var/obj/item/uplink_loc
|
||||
|
||||
if(traitor_mob.client && traitor_mob.client.prefs)
|
||||
switch(traitor_mob.client.prefs.uplink_spawn_loc)
|
||||
if(UPLINK_PDA)
|
||||
uplink_loc = PDA
|
||||
if(!uplink_loc)
|
||||
uplink_loc = R
|
||||
if(!uplink_loc)
|
||||
uplink_loc = P
|
||||
if(UPLINK_RADIO)
|
||||
uplink_loc = R
|
||||
if(!uplink_loc)
|
||||
uplink_loc = PDA
|
||||
if(!uplink_loc)
|
||||
uplink_loc = P
|
||||
if(UPLINK_PEN)
|
||||
uplink_loc = P
|
||||
if(!uplink_loc)
|
||||
uplink_loc = PDA
|
||||
if(!uplink_loc)
|
||||
uplink_loc = R
|
||||
|
||||
if (!uplink_loc)
|
||||
to_chat(traitor_mob, "Unfortunately, [employer] wasn't able to get you an Uplink.")
|
||||
. = 0
|
||||
else
|
||||
var/obj/item/device/uplink/U = new(uplink_loc)
|
||||
U.owner = "[traitor_mob.key]"
|
||||
uplink_loc.hidden_uplink = U
|
||||
|
||||
if(uplink_loc == R)
|
||||
R.traitor_frequency = sanitize_frequency(rand(MIN_FREQ, MAX_FREQ))
|
||||
|
||||
to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [R.name]. Simply dial the frequency [format_frequency(R.traitor_frequency)] to unlock its hidden features.")
|
||||
traitor_mob.mind.store_memory("<B>Radio Frequency:</B> [format_frequency(R.traitor_frequency)] ([R.name]).")
|
||||
|
||||
else if(uplink_loc == PDA)
|
||||
PDA.lock_code = "[rand(100,999)] [pick("Alpha","Bravo","Charlie","Delta","Echo","Foxtrot","Golf","Hotel","India","Juliet","Kilo","Lima","Mike","November","Oscar","Papa","Quebec","Romeo","Sierra","Tango","Uniform","Victor","Whiskey","X-ray","Yankee","Zulu")]"
|
||||
|
||||
to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [PDA.name]. Simply enter the code \"[PDA.lock_code]\" into the ringtone select to unlock its hidden features.")
|
||||
traitor_mob.mind.store_memory("<B>Uplink Passcode:</B> [PDA.lock_code] ([PDA.name]).")
|
||||
|
||||
else if(uplink_loc == P)
|
||||
P.traitor_unlock_degrees = rand(1, 360)
|
||||
|
||||
to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [P.name]. Simply twist the top of the pen [P.traitor_unlock_degrees] from its starting position to unlock its hidden features.")
|
||||
traitor_mob.mind.store_memory("<B>Uplink Degrees:</B> [P.traitor_unlock_degrees] ([P.name]).")
|
||||
|
||||
if(!safety) // If they are not a rev. Can be added on to.
|
||||
give_codewords(traitor_mob)
|
||||
|
||||
/datum/game_mode/proc/assign_exchange_role(datum/mind/owner)
|
||||
//set faction
|
||||
var/faction = "red"
|
||||
if(owner == exchange_blue)
|
||||
faction = "blue"
|
||||
|
||||
//Assign objectives
|
||||
var/datum/objective/steal/exchange/exchange_objective = new
|
||||
exchange_objective.set_faction(faction,((faction == "red") ? exchange_blue : exchange_red))
|
||||
exchange_objective.owner = owner
|
||||
owner.objectives += exchange_objective
|
||||
|
||||
if(prob(20))
|
||||
var/datum/objective/steal/exchange/backstab/backstab_objective = new
|
||||
backstab_objective.set_faction(faction)
|
||||
backstab_objective.owner = owner
|
||||
owner.objectives += backstab_objective
|
||||
|
||||
//Spawn and equip documents
|
||||
var/mob/living/carbon/human/mob = owner.current
|
||||
|
||||
var/obj/item/weapon/folder/syndicate/folder
|
||||
if(owner == exchange_red)
|
||||
folder = new/obj/item/weapon/folder/syndicate/red(mob.loc)
|
||||
else
|
||||
folder = new/obj/item/weapon/folder/syndicate/blue(mob.loc)
|
||||
|
||||
var/list/slots = list (
|
||||
"backpack" = slot_in_backpack,
|
||||
"left pocket" = slot_l_store,
|
||||
"right pocket" = slot_r_store
|
||||
)
|
||||
|
||||
var/where = "At your feet"
|
||||
var/equipped_slot = mob.equip_in_one_of_slots(folder, slots)
|
||||
if (equipped_slot)
|
||||
where = "In your [equipped_slot]"
|
||||
to_chat(mob, "<BR><BR><span class='info'>[where] is a folder containing <b>secret documents</b> that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.</span><BR>")
|
||||
|
||||
/datum/game_mode/proc/update_traitor_icons_added(datum/mind/traitor_mind)
|
||||
var/datum/atom_hud/antag/traitorhud = GLOB.huds[ANTAG_HUD_TRAITOR]
|
||||
|
||||
@@ -180,7 +180,7 @@
|
||||
. += "You recognise the footprints as belonging to:\n"
|
||||
for(var/shoe in shoe_types)
|
||||
var/obj/item/clothing/shoes/S = shoe
|
||||
. += "some <B>[initial(S.name)]</B> \icon[S]\n"
|
||||
. += "some <B>[initial(S.name)]</B> [bicon(initial(S.icon))]\n"
|
||||
|
||||
to_chat(user, .)
|
||||
|
||||
|
||||
@@ -25,13 +25,12 @@
|
||||
/obj/effect/turf_decal/proc/get_decal()
|
||||
return image(icon='icons/turf/decals.dmi',icon_state=icon_state,dir=dir,layer=TURF_LAYER)
|
||||
|
||||
/obj/effect/turf_decal/Initialize(mapload)
|
||||
/obj/effect/turf_decal/Initialize()
|
||||
..()
|
||||
var/turf/T = loc
|
||||
if(!istype(T)) //you know this will happen somehow
|
||||
CRASH("Turf decal initialized in an object/nullspace")
|
||||
T.add_decal(get_decal(),group)
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/effect/turf_decal/stripes/line
|
||||
icon_state = "warningline"
|
||||
|
||||
@@ -32,13 +32,16 @@
|
||||
|
||||
/obj/item/weapon/pneumatic_cannon/examine(mob/user)
|
||||
..()
|
||||
var/list/out = list()
|
||||
if(!in_range(user, src))
|
||||
to_chat(user, "<span class='notice'>You'll need to get closer to see any more.</span>")
|
||||
out += "<span class='notice'>You'll need to get closer to see any more.</span>"
|
||||
return
|
||||
for(var/obj/item/I in loadedItems)
|
||||
to_chat(user, "<span class='info'>[bicon(I)] It has \the [I] loaded.</span>")
|
||||
out += "<span class='info'>[bicon(I)] It has \the [I] loaded.</span>"
|
||||
CHECK_TICK
|
||||
if(tank)
|
||||
to_chat(user, "<span class='notice'>[bicon(tank)] It has \the [tank] mounted onto it.</span>")
|
||||
out += "<span class='notice'>[bicon(tank)] It has \the [tank] mounted onto it.</span>"
|
||||
to_chat(user, out.Join("<br>"))
|
||||
|
||||
|
||||
/obj/item/weapon/pneumatic_cannon/attackby(obj/item/weapon/W, mob/user, params)
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
max_combined_w_class = 14 //The sum of the w_classes of all the items in this storage item.
|
||||
storage_slots = 4
|
||||
req_access = list(GLOB.access_armory)
|
||||
var/locked = 1
|
||||
var/broken = 0
|
||||
var/locked = TRUE
|
||||
var/broken = FALSE
|
||||
var/open = FALSE
|
||||
var/icon_locked = "lockbox+l"
|
||||
var/icon_closed = "lockbox"
|
||||
var/icon_broken = "lockbox+b"
|
||||
@@ -48,8 +49,8 @@
|
||||
|
||||
/obj/item/weapon/storage/lockbox/emag_act(mob/user)
|
||||
if(!broken)
|
||||
broken = 1
|
||||
locked = 0
|
||||
broken = TRUE
|
||||
locked = FALSE
|
||||
desc += "It appears to be broken."
|
||||
icon_state = src.icon_broken
|
||||
if(user)
|
||||
@@ -67,12 +68,22 @@
|
||||
if(locked)
|
||||
to_chat(user, "<span class='warning'>It's locked!</span>")
|
||||
return 0
|
||||
open = TRUE
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/storage/lockbox/can_be_inserted(obj/item/W, stop_messages = 0)
|
||||
if(locked)
|
||||
return 0
|
||||
return ..()
|
||||
/obj/item/weapon/storage/lockbox/handle_item_insertion(obj/item/W, prevent_warning = 0, mob/user)
|
||||
open = TRUE
|
||||
update_icon()
|
||||
return ..()
|
||||
/obj/item/weapon/storage/lockbox/remove_from_storage(obj/item/W, atom/new_location, burn = 0)
|
||||
open = TRUE
|
||||
update_icon()
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/weapon/storage/lockbox/loyalty
|
||||
name = "lockbox of mindshield implants"
|
||||
@@ -107,51 +118,63 @@
|
||||
icon_broken = "medalbox+b"
|
||||
can_hold = list(/obj/item/clothing/accessory/medal)
|
||||
|
||||
/obj/item/weapon/storage/lockbox/medal/AltClick()
|
||||
if(!locked)
|
||||
open = (open ? FALSE : TRUE)
|
||||
update_icon()
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/weapon/storage/lockbox/medal/PopulateContents()
|
||||
new /obj/item/clothing/accessory/medal/gold/captain(src)
|
||||
new /obj/item/clothing/accessory/medal/silver/valor(src)
|
||||
new /obj/item/clothing/accessory/medal/silver/valor(src)
|
||||
new /obj/item/clothing/accessory/medal/silver/security(src)
|
||||
new /obj/item/clothing/accessory/medal/bronze_heart(src)
|
||||
new /obj/item/clothing/accessory/medal/plasma/nobel_science(src)
|
||||
new /obj/item/clothing/accessory/medal/plasma/nobel_science(src)
|
||||
for(var/i in 1 to 3)
|
||||
new /obj/item/clothing/accessory/medal/conduct(src)
|
||||
new /obj/item/clothing/accessory/medal/gold/captain(src)
|
||||
new /obj/item/clothing/accessory/medal/silver/security(src)
|
||||
new /obj/item/clothing/accessory/medal/plasma(src)
|
||||
new /obj/item/clothing/accessory/medal/plasma/nobel_science(src)
|
||||
new /obj/item/clothing/accessory/medal/gold/heroism(src)
|
||||
|
||||
/obj/item/weapon/storage/lockbox/secmedal
|
||||
/obj/item/weapon/storage/lockbox/medal/update_icon()
|
||||
cut_overlays()
|
||||
if(locked)
|
||||
icon_state = "medalbox+l"
|
||||
open = FALSE
|
||||
else
|
||||
icon_state = "medalbox"
|
||||
if(open)
|
||||
icon_state += "open"
|
||||
if(broken)
|
||||
icon_state += "+b"
|
||||
if(contents && open)
|
||||
for (var/i in 1 to contents.len)
|
||||
var/obj/item/clothing/accessory/medal/M = contents[i]
|
||||
var/mutable_appearance/medalicon = mutable_appearance(initial(icon), M.medaltype)
|
||||
if(i > 1 && i <= 5)
|
||||
medalicon.pixel_x += ((i-1)*3)
|
||||
else if(i > 5)
|
||||
medalicon.pixel_y -= 7
|
||||
medalicon.pixel_x -= 2
|
||||
medalicon.pixel_x += ((i-6)*3)
|
||||
add_overlay(medalicon)
|
||||
|
||||
/obj/item/weapon/storage/lockbox/medal/sec
|
||||
name = "security medal box"
|
||||
desc = "A locked box used to store medals to be given to members of the security department."
|
||||
icon_state = "medalbox+l"
|
||||
item_state = "syringe_kit"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
max_w_class = WEIGHT_CLASS_SMALL
|
||||
storage_slots = 10
|
||||
max_combined_w_class = 20
|
||||
req_access = list(GLOB.access_hos)
|
||||
icon_locked = "medalbox+l"
|
||||
icon_closed = "medalbox"
|
||||
icon_broken = "medalbox+b"
|
||||
can_hold = list(/obj/item/clothing/accessory/medal)
|
||||
|
||||
/obj/item/weapon/storage/lockbox/secmedal/PopulateContents()
|
||||
obj/item/weapon/storage/lockbox/medal/sec/PopulateContents()
|
||||
for(var/i in 1 to 3)
|
||||
new /obj/item/clothing/accessory/medal/silver/security(src)
|
||||
|
||||
/obj/item/weapon/storage/lockbox/scimedal
|
||||
/obj/item/weapon/storage/lockbox/medal/sci
|
||||
name = "science medal box"
|
||||
desc = "A locked box used to store medals to be given to members of the science department."
|
||||
icon_state = "medalbox+l"
|
||||
item_state = "syringe_kit"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
max_w_class = WEIGHT_CLASS_SMALL
|
||||
storage_slots = 10
|
||||
max_combined_w_class = 20
|
||||
req_access = list(GLOB.access_rd)
|
||||
icon_locked = "medalbox+l"
|
||||
icon_closed = "medalbox"
|
||||
icon_broken = "medalbox+b"
|
||||
can_hold = list(/obj/item/clothing/accessory/medal)
|
||||
|
||||
/obj/item/weapon/storage/lockbox/scimedal/PopulateContents()
|
||||
/obj/item/weapon/storage/lockbox/medal/sci/PopulateContents()
|
||||
for(var/i in 1 to 3)
|
||||
new /obj/item/clothing/accessory/medal/plasma/nobel_science(src)
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
new /obj/item/weapon/tank/internals/air(src)
|
||||
new /obj/item/clothing/mask/gas(src)
|
||||
new /obj/item/device/megaphone/command(src)
|
||||
new /obj/item/weapon/storage/lockbox/medal/sci(src)
|
||||
new /obj/item/clothing/suit/armor/reactive/teleport(src)
|
||||
new /obj/item/device/assembly/flash/handheld(src)
|
||||
new /obj/item/device/laser_pointer(src)
|
||||
new /obj/item/weapon/door_remote/research_director(src)
|
||||
new /obj/item/weapon/storage/box/firingpins(src)
|
||||
new /obj/item/weapon/storage/lockbox/scimedal(src)
|
||||
|
||||
@@ -73,6 +73,8 @@
|
||||
new /obj/item/clothing/head/HoS(src)
|
||||
new /obj/item/clothing/glasses/hud/security/sunglasses/eyepatch(src)
|
||||
new /obj/item/clothing/glasses/hud/security/sunglasses/gars/supergars(src)
|
||||
new /obj/item/clothing/under/rank/head_of_security/grey(src)
|
||||
new /obj/item/weapon/storage/lockbox/medal/sec(src)
|
||||
new /obj/item/device/megaphone/sec(src)
|
||||
new /obj/item/weapon/holosign_creator/security(src)
|
||||
new /obj/item/weapon/storage/lockbox/loyalty(src)
|
||||
@@ -83,9 +85,6 @@
|
||||
new /obj/item/weapon/gun/energy/e_gun/hos(src)
|
||||
new /obj/item/device/flashlight/seclite(src)
|
||||
new /obj/item/weapon/pinpointer(src)
|
||||
new /obj/item/clothing/under/rank/head_of_security/grey(src)
|
||||
new /obj/item/clothing/under/rank/head_of_security/grey(src)
|
||||
new /obj/item/weapon/storage/lockbox/secmedal(src)
|
||||
|
||||
/obj/structure/closet/secure_closet/warden
|
||||
name = "\proper warden's locker"
|
||||
|
||||
@@ -334,31 +334,18 @@
|
||||
if(!objective)
|
||||
return
|
||||
SSblackbox.add_details("admin_secrets_fun_used","Traitor All ([objective])")
|
||||
for(var/mob/living/carbon/human/H in GLOB.player_list)
|
||||
if(H.stat == 2 || !H.client || !H.mind) continue
|
||||
for(var/mob/living/H in GLOB.player_list)
|
||||
if(!(istype(H, /mob/living/carbon/human)||istype(H, /mob/living/silicon/))) continue
|
||||
if(H.stat == 2 || !H.client || !H.mind || ispAI(H)) continue
|
||||
if(is_special_character(H)) continue
|
||||
//traitorize(H, objective, 0)
|
||||
SSticker.mode.traitors += H.mind
|
||||
H.mind.special_role = "traitor"
|
||||
H.mind.add_antag_datum(ANTAG_DATUM_TRAITOR_CUSTOM)
|
||||
var/datum/antagonist/traitor/traitordatum = H.mind.has_antag_datum(ANTAG_DATUM_TRAITOR) //original datum self deletes
|
||||
var/datum/objective/new_objective = new
|
||||
new_objective.owner = H
|
||||
new_objective.explanation_text = objective
|
||||
H.mind.objectives += new_objective
|
||||
SSticker.mode.greet_traitor(H.mind)
|
||||
//SSticker.mode.forge_traitor_objectives(H.mind)
|
||||
SSticker.mode.finalize_traitor(H.mind)
|
||||
for(var/mob/living/silicon/A in GLOB.player_list)
|
||||
if(A.stat == 2 || !A.client || !A.mind) continue
|
||||
if(ispAI(A)) continue
|
||||
else if(is_special_character(A)) continue
|
||||
SSticker.mode.traitors += A.mind
|
||||
A.mind.special_role = "traitor"
|
||||
var/datum/objective/new_objective = new
|
||||
new_objective.owner = A
|
||||
new_objective.explanation_text = objective
|
||||
A.mind.objectives += new_objective
|
||||
SSticker.mode.greet_traitor(A.mind)
|
||||
SSticker.mode.finalize_traitor(A.mind)
|
||||
traitordatum.add_objective(new_objective)
|
||||
traitordatum.equip(FALSE)
|
||||
traitordatum.greet()
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] used everyone is a traitor secret. Objective is [objective]</span>")
|
||||
log_admin("[key_name(usr)] used everyone is a traitor secret. Objective is [objective]")
|
||||
|
||||
|
||||
@@ -202,6 +202,7 @@
|
||||
to_chat(H, "<span class='heavy_brass'>The world before you suddenly glows a brilliant yellow. You hear the whooshing steam and clanking cogs of a billion billion machines, and all at once \
|
||||
you see the truth. Ratvar, the Clockwork Justiciar, lies derelict and forgotten in an unseen realm, and he has selected you as one of his harbringers. You are now a servant of \
|
||||
Ratvar, and you will bring him back.</span>")
|
||||
H.playsound_local(get_turf(H), 'sound/ambience/antag/clockcultalr.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
add_servant_of_ratvar(H, TRUE)
|
||||
SSticker.mode.equip_servant(H)
|
||||
candidates.Remove(H)
|
||||
|
||||
@@ -112,7 +112,6 @@
|
||||
message_admins("<span class='adminnotice'><b> LocalNarrate: [key_name_admin(usr)] at [get_area(A)][ADMIN_JMP(A)]:</b> [msg]<BR></span>")
|
||||
SSblackbox.add_details("admin_verb","Local Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
/client/proc/cmd_admin_godmode(mob/M in GLOB.mob_list)
|
||||
set category = "Special Verbs"
|
||||
set name = "Godmode"
|
||||
@@ -374,10 +373,13 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
var/player_key = G_found.key
|
||||
|
||||
//Now for special roles and equipment.
|
||||
switch(new_character.mind.special_role)
|
||||
if("traitor")
|
||||
var/datum/antagonist/traitor/traitordatum = new_character.mind.has_antag_datum(ANTAG_DATUM_TRAITOR)
|
||||
if(traitordatum)
|
||||
SSjob.EquipRank(new_character, new_character.mind.assigned_role, 1)
|
||||
SSticker.mode.equip_traitor(new_character)
|
||||
traitordatum.equip()
|
||||
|
||||
|
||||
switch(new_character.mind.special_role)
|
||||
if("Wizard")
|
||||
new_character.loc = pick(GLOB.wizardstart)
|
||||
//SSticker.mode.learn_basic_spells(new_character)
|
||||
@@ -402,12 +404,8 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
switch(new_character.mind.assigned_role)
|
||||
if("Cyborg")//More rigging to make em' work and check if they're traitor.
|
||||
new_character = new_character.Robotize()
|
||||
if(new_character.mind.special_role=="traitor")
|
||||
SSticker.mode.add_law_zero(new_character)
|
||||
if("AI")
|
||||
new_character = new_character.AIize()
|
||||
if(new_character.mind.special_role=="traitor")
|
||||
SSticker.mode.add_law_zero(new_character)
|
||||
else
|
||||
SSjob.EquipRank(new_character, new_character.mind.assigned_role, 1)//Or we simply equip them.
|
||||
|
||||
|
||||
@@ -280,7 +280,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
)
|
||||
|
||||
/datum/asset/simple/goonchat
|
||||
verify = TRUE
|
||||
verify = FALSE
|
||||
assets = list(
|
||||
"jquery.min.js" = 'code/modules/html_interface/js/jquery.min.js',
|
||||
"json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js',
|
||||
|
||||
@@ -85,6 +85,7 @@
|
||||
item_color = "bronze"
|
||||
materials = list(MAT_METAL=1000)
|
||||
resistance_flags = FIRE_PROOF
|
||||
var/medaltype = "medal" //Sprite used for medalbox
|
||||
var/commended = FALSE
|
||||
|
||||
//Pinning medals on people
|
||||
@@ -138,6 +139,7 @@
|
||||
desc = "A silver medal."
|
||||
icon_state = "silver"
|
||||
item_color = "silver"
|
||||
medaltype = "medal-silver"
|
||||
materials = list(MAT_SILVER=1000)
|
||||
|
||||
/obj/item/clothing/accessory/medal/silver/valor
|
||||
@@ -153,6 +155,7 @@
|
||||
desc = "A prestigious golden medal."
|
||||
icon_state = "gold"
|
||||
item_color = "gold"
|
||||
medaltype = "medal-gold"
|
||||
materials = list(MAT_GOLD=1000)
|
||||
|
||||
/obj/item/clothing/accessory/medal/gold/captain
|
||||
@@ -169,6 +172,7 @@
|
||||
desc = "An eccentric medal made of plasma."
|
||||
icon_state = "plasma"
|
||||
item_color = "plasma"
|
||||
medaltype = "medal-plasma"
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = -10, acid = 0) //It's made of plasma. Of course it's flammable.
|
||||
materials = list(MAT_PLASMA=1000)
|
||||
|
||||
|
||||
@@ -262,18 +262,20 @@ Gunshots/explosions/opening doors/less rare audio (done)
|
||||
px = -32
|
||||
|
||||
/obj/effect/hallucination/oh_yeah
|
||||
var/turf/closed/wall/wall
|
||||
var/obj/effect/hallucination/simple/bubblegum/bubblegum = null
|
||||
var/obj/effect/hallucination/simple/bubblegum/bubblegum
|
||||
var/image/fakebroken
|
||||
var/image/fakerune
|
||||
|
||||
/obj/effect/hallucination/oh_yeah/Initialize(mapload, var/mob/living/carbon/T)
|
||||
..()
|
||||
. = ..()
|
||||
target = T
|
||||
var/turf/closed/wall/wall
|
||||
for(var/turf/closed/wall/W in range(7,target))
|
||||
wall = W
|
||||
break
|
||||
if(wall)
|
||||
if(!wall)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
fakebroken = image('icons/turf/floors.dmi', wall, "plating", layer = TURF_LAYER)
|
||||
var/turf/landing = get_turf(target)
|
||||
var/turf/landing_image_turf = get_step(landing, SOUTHWEST) //the icon is 3x3
|
||||
@@ -284,7 +286,9 @@ Gunshots/explosions/opening doors/less rare audio (done)
|
||||
target.client.images |= fakerune
|
||||
target.playsound_local(wall,'sound/effects/meteorimpact.ogg', 150, 1)
|
||||
bubblegum = new(wall, target)
|
||||
sleep(10) //ominous wait
|
||||
addtimer(CALLBACK(src, .proc/bubble_attack, landing), 10)
|
||||
|
||||
/obj/effect/hallucination/oh_yeah/proc/bubble_attack(turf/landing)
|
||||
var/charged = FALSE //only get hit once
|
||||
while(get_turf(bubblegum) != landing && target && target.stat != DEAD)
|
||||
bubblegum.forceMove(get_step_towards(bubblegum, landing))
|
||||
@@ -294,19 +298,21 @@ Gunshots/explosions/opening doors/less rare audio (done)
|
||||
if(bubblegum.Adjacent(target) && !charged)
|
||||
charged = TRUE
|
||||
target.Weaken(4)
|
||||
target.staminaloss += 40
|
||||
target.adjustStaminaLoss(40)
|
||||
step_away(target, bubblegum)
|
||||
shake_camera(target, 4, 3)
|
||||
target.visible_message("<span class='warning'>[target] jumps backwards, falling on the ground!</span>","<span class='userdanger'>[bubblegum] slams into you!</span>")
|
||||
sleep(2)
|
||||
sleep(30)
|
||||
qdel(bubblegum)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/hallucination/oh_yeah/Destroy()
|
||||
if(target.client)
|
||||
target.client.images.Remove(fakebroken)
|
||||
target.client.images.Remove(fakerune)
|
||||
QDEL_NULL(fakebroken)
|
||||
QDEL_NULL(fakerune)
|
||||
QDEL_NULL(bubblegum)
|
||||
return ..()
|
||||
|
||||
/obj/effect/hallucination/singularity_scare
|
||||
@@ -625,7 +631,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
|
||||
else if(src.dir == WEST)
|
||||
del src.currentimage
|
||||
src.currentimage = new /image(left,src)
|
||||
SEND_IMAGE(my_target, currentimage)
|
||||
to_chat(my_target, currentimage)
|
||||
|
||||
|
||||
/obj/effect/fake_attacker/proc/attack_loop()
|
||||
@@ -669,7 +675,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
|
||||
var/obj/effect/overlay/O = new/obj/effect/overlay(target.loc)
|
||||
O.name = "blood"
|
||||
var/image/I = image('icons/effects/blood.dmi',O,"floor[rand(1,7)]",O.dir,1)
|
||||
SEND_IMAGE(target, I)
|
||||
to_chat(target, I)
|
||||
QDEL_IN(O, 300)
|
||||
|
||||
|
||||
@@ -786,6 +792,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
|
||||
new /obj/effect/hallucination/items_other(src.loc,src)
|
||||
if("sounds")
|
||||
//Strange audio
|
||||
//to_chat(src, "Strange Audio")
|
||||
switch(rand(1,20))
|
||||
if(1) playsound_local(null,'sound/machines/airlock.ogg', 15, 1)
|
||||
if(2)
|
||||
|
||||
83
code/modules/language/codespeak.dm
Normal file
83
code/modules/language/codespeak.dm
Normal file
@@ -0,0 +1,83 @@
|
||||
/datum/language/codespeak
|
||||
name = "Codespeak"
|
||||
desc = "Syndicate operatives can use a series of codewords to convey complex information, while sounding like random concepts and drinks to anyone listening in."
|
||||
key = "t"
|
||||
default_priority = 0
|
||||
flags = TONGUELESS_SPEECH | LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD
|
||||
icon_state = "codespeak"
|
||||
|
||||
/datum/language/codespeak/scramble(input)
|
||||
var/lookup = check_cache(input)
|
||||
if(lookup)
|
||||
return lookup
|
||||
|
||||
. = ""
|
||||
var/list/words = list()
|
||||
while(length(.) < length(input))
|
||||
words += generate_code_phrase(return_list=TRUE)
|
||||
. = jointext(words, ", ")
|
||||
|
||||
. = capitalize(.)
|
||||
|
||||
var/input_ending = copytext(input, length(input))
|
||||
|
||||
var/static/list/endings
|
||||
if(!endings)
|
||||
endings = list("!", "?", ".")
|
||||
|
||||
if(input_ending in endings)
|
||||
. += input_ending
|
||||
|
||||
add_to_cache(input, .)
|
||||
|
||||
/obj/item/weapon/codespeak_manual
|
||||
name = "codespeak manual"
|
||||
desc = "The book's cover reads: \"Codespeak(tm) - Secure your communication with metaphors so elaborate, they seem randomly generated!\""
|
||||
icon = 'icons/obj/library.dmi'
|
||||
icon_state = "book2"
|
||||
var/charges = 1
|
||||
|
||||
/obj/item/weapon/codespeak_manual/attack_self(mob/living/user)
|
||||
if(!isliving(user))
|
||||
return
|
||||
|
||||
if(user.has_language(/datum/language/codespeak))
|
||||
to_chat(user, "<span class='boldannounce'>You start skimming through [src], but you already know Codespeak.</span>")
|
||||
return
|
||||
|
||||
to_chat(user, "<span class='boldannounce'>You start skimming through [src], and suddenly your mind is filled with codewords and responses.</span>")
|
||||
user.grant_language(/datum/language/codespeak)
|
||||
|
||||
use_charge(user)
|
||||
|
||||
/obj/item/weapon/codespeak_manual/attack(mob/living/M, mob/living/user)
|
||||
if(!istype(M) || !istype(user))
|
||||
return
|
||||
if(M == user)
|
||||
attack_self(user)
|
||||
return
|
||||
|
||||
playsound(loc, "punch", 25, 1, -1)
|
||||
|
||||
if(M.stat == DEAD)
|
||||
M.visible_message("<span class='danger'>[user] smacks [M]'s lifeless corpse with [src].</span>", "<span class='userdanger'>[user] smacks your lifeless corpse with [src].</span>", "<span class='italics'>You hear smacking.</span>")
|
||||
else if(M.has_language(/datum/language/codespeak))
|
||||
M.visible_message("<span class='danger'>[user] beats [M] over the head with [src]!</span>", "<span class='userdanger'>[user] beats you over the head with [src]!</span>", "<span class='italics'>You hear smacking.</span>")
|
||||
else
|
||||
M.visible_message("<span class='notice'>[user] teaches [M] by beating them over the head with [src]!</span>", "<span class='boldnotice'>As [user] hits you with [src], codewords and responses flow through your mind.</span>", "<span class='italics'>You hear smacking.</span>")
|
||||
M.grant_language(/datum/language/codespeak)
|
||||
use_charge(user)
|
||||
|
||||
/obj/item/weapon/codespeak_manual/proc/use_charge(mob/user)
|
||||
charges--
|
||||
if(!charges)
|
||||
var/turf/T = get_turf(src)
|
||||
T.visible_message("<span class='warning'>The cover and contents of [src] start shifting and changing!</span>")
|
||||
|
||||
qdel(src)
|
||||
var/obj/item/weapon/book/manual/random/book = new(T)
|
||||
user.put_in_active_hand(book)
|
||||
|
||||
/obj/item/weapon/codespeak_manual/unlimited
|
||||
name = "deluxe codespeak manual"
|
||||
charges = INFINITY
|
||||
@@ -35,7 +35,7 @@
|
||||
return TRUE
|
||||
|
||||
/datum/language/proc/get_icon()
|
||||
return "<img class=icon src=\ref[icon] iconstate='[icon_state]'>"
|
||||
return "[bicon(icon(icon, icon_state))]"
|
||||
|
||||
/datum/language/proc/get_random_name(gender, name_count=2, syllable_count=4, syllable_divisor=2)
|
||||
if(!syllables || !syllables.len)
|
||||
@@ -56,6 +56,18 @@
|
||||
|
||||
return "[trim(full_name)]"
|
||||
|
||||
/datum/language/proc/check_cache(input)
|
||||
var/lookup = check_cache(input)
|
||||
if(lookup)
|
||||
return lookup
|
||||
|
||||
/datum/language/proc/add_to_cache(input, scrambled_text)
|
||||
add_to_cache(input, scrambled_text)
|
||||
|
||||
|
||||
return scrambled_text
|
||||
|
||||
|
||||
/datum/language/proc/scramble(input)
|
||||
|
||||
if(!syllables || !syllables.len)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
#define LINKIFY_READY(string, value) "<a href='byond://?src=\ref[src];ready=[value]'>[string]</a>"
|
||||
|
||||
/mob/dead/new_player
|
||||
var/ready = 0
|
||||
@@ -31,19 +31,21 @@
|
||||
|
||||
/mob/dead/new_player/proc/new_player_panel()
|
||||
|
||||
var/output = "<center><p><a href='byond://?src=\ref[src];show_preferences=1'>Setup Character</A></p>"
|
||||
var/output = "<center><p><a href='byond://?src=\ref[src];show_preferences=1'>Setup Character</a></p>"
|
||||
|
||||
if(!SSticker || SSticker.current_state <= GAME_STATE_PREGAME)
|
||||
if(ready)
|
||||
output += "<p>\[ <b>Ready</b> | <a href='byond://?src=\ref[src];ready=0'>Not Ready</a> \]</p>"
|
||||
else
|
||||
output += "<p>\[ <a href='byond://?src=\ref[src];ready=1'>Ready</a> | <b>Not Ready</b> \]</p>"
|
||||
if(SSticker && SSticker.current_state <= GAME_STATE_PREGAME)
|
||||
switch(ready)
|
||||
if(PLAYER_NOT_READY)
|
||||
output += "<p>\[ [LINKIFY_READY("Ready", PLAYER_READY_TO_PLAY)] | <b>Not Ready</b> | [LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)] \]</p>"
|
||||
if(PLAYER_READY_TO_PLAY)
|
||||
output += "<p>\[ <b>Ready</b> | [LINKIFY_READY("Not Ready", PLAYER_NOT_READY)] | [LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)] \]</p>"
|
||||
if(PLAYER_READY_TO_OBSERVE)
|
||||
output += "<p>\[ [LINKIFY_READY("Ready", PLAYER_READY_TO_PLAY)] | [LINKIFY_READY("Not Ready", PLAYER_NOT_READY)] | <b> Observe </b> \]</p>"
|
||||
|
||||
else
|
||||
output += "<p><a href='byond://?src=\ref[src];manifest=1'>View the Crew Manifest</A></p>"
|
||||
output += "<p><a href='byond://?src=\ref[src];late_join=1'>Join Game!</A></p>"
|
||||
|
||||
output += "<p><a href='byond://?src=\ref[src];observe=1'>Observe</A></p>"
|
||||
output += "<p><a href='byond://?src=\ref[src];manifest=1'>View the Crew Manifest</a></p>"
|
||||
output += "<p><a href='byond://?src=\ref[src];late_join=1'>Join Game!</a></p>"
|
||||
output += "<p>[LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)]</p>"
|
||||
|
||||
if(!IsGuestKey(src.key))
|
||||
if (SSdbcore.Connect())
|
||||
@@ -65,7 +67,7 @@
|
||||
output += "</center>"
|
||||
|
||||
//src << browse(output,"window=playersetup;size=210x240;can_close=0")
|
||||
var/datum/browser/popup = new(src, "playersetup", "<div align='center'>New Player Options</div>", 220, 265)
|
||||
var/datum/browser/popup = new(src, "playersetup", "<div align='center'>New Player Options</div>", 250, 265)
|
||||
popup.set_window_options("can_close=0")
|
||||
popup.set_content(output)
|
||||
popup.open(0)
|
||||
@@ -108,42 +110,23 @@
|
||||
return 1
|
||||
|
||||
if(href_list["ready"])
|
||||
if(!SSticker || SSticker.current_state <= GAME_STATE_PREGAME) // Make sure we don't ready up after the round has started
|
||||
ready = text2num(href_list["ready"])
|
||||
if(SSticker)
|
||||
var/tready = text2num(href_list["ready"])
|
||||
//Avoid updating ready if we're after PREGAME (they should use latejoin instead)
|
||||
//This is likely not an actual issue but I don't have time to prove that this
|
||||
//no longer is required
|
||||
if(SSticker.current_state <= GAME_STATE_PREGAME)
|
||||
ready = tready
|
||||
//if it's post initialisation and they're trying to observe we do the needful
|
||||
if(!SSticker.current_state < GAME_STATE_PREGAME && tready == PLAYER_READY_TO_OBSERVE)
|
||||
ready = tready
|
||||
make_me_an_observer()
|
||||
return
|
||||
|
||||
if(href_list["refresh"])
|
||||
src << browse(null, "window=playersetup") //closes the player setup window
|
||||
new_player_panel()
|
||||
|
||||
if(href_list["observe"])
|
||||
|
||||
if(alert(src,"Are you sure you wish to observe? You will not be able to play this round!","Player Setup","Yes","No") == "Yes")
|
||||
if(!client)
|
||||
return 1
|
||||
var/mob/dead/observer/observer = new()
|
||||
|
||||
spawning = 1
|
||||
|
||||
observer.started_as_observer = 1
|
||||
close_spawn_windows()
|
||||
var/obj/O = locate("landmark*Observer-Start")
|
||||
to_chat(src, "<span class='notice'>Now teleporting.</span>")
|
||||
if (O)
|
||||
observer.loc = O.loc
|
||||
else
|
||||
to_chat(src, "<span class='notice'>Teleporting failed. The map is probably still loading...</span>")
|
||||
observer.key = key
|
||||
observer.client = client
|
||||
observer.set_ghost_appearance()
|
||||
if(observer.client && observer.client.prefs)
|
||||
observer.real_name = observer.client.prefs.real_name
|
||||
observer.name = observer.real_name
|
||||
observer.update_icon()
|
||||
observer.stop_sound_channel(CHANNEL_LOBBYMUSIC)
|
||||
QDEL_NULL(mind)
|
||||
qdel(src)
|
||||
return 1
|
||||
|
||||
if(href_list["late_join"])
|
||||
if(!SSticker || !SSticker.IsRoundInProgress())
|
||||
to_chat(usr, "<span class='danger'>The round is either not ready, or has already finished...</span>")
|
||||
@@ -273,6 +256,45 @@
|
||||
return
|
||||
to_chat(src, "<span class='notice'>Vote successful.</span>")
|
||||
|
||||
//When you cop out of the round (NB: this HAS A SLEEP FOR PLAYER INPUT IN IT)
|
||||
/mob/dead/new_player/proc/make_me_an_observer()
|
||||
if(QDELETED(src) || !src.client)
|
||||
ready = PLAYER_NOT_READY
|
||||
return FALSE
|
||||
|
||||
var/this_is_like_playing_right = alert(src,"Are you sure you wish to observe? You will not be able to play this round!","Player Setup","Yes","No")
|
||||
|
||||
if(QDELETED(src) || !src.client || this_is_like_playing_right != "Yes")
|
||||
ready = PLAYER_NOT_READY
|
||||
src << browse(null, "window=playersetup") //closes the player setup window
|
||||
new_player_panel()
|
||||
return FALSE
|
||||
|
||||
var/mob/dead/observer/observer = new()
|
||||
spawning = TRUE
|
||||
|
||||
observer.started_as_observer = TRUE
|
||||
close_spawn_windows()
|
||||
var/obj/O = locate("landmark*Observer-Start")
|
||||
to_chat(src, "<span class='notice'>Now teleporting.</span>")
|
||||
if (O)
|
||||
observer.loc = O.loc
|
||||
else
|
||||
to_chat(src, "<span class='notice'>Teleporting failed. Ahelp an admin please</span>")
|
||||
stack_trace("There's no freaking observer landmark available on this map or you're making observers before the map is initialised")
|
||||
observer.key = key
|
||||
observer.client = client
|
||||
observer.set_ghost_appearance()
|
||||
if(observer.client && observer.client.prefs)
|
||||
observer.real_name = observer.client.prefs.real_name
|
||||
observer.name = observer.real_name
|
||||
observer.update_icon()
|
||||
observer.stop_sound_channel(CHANNEL_LOBBYMUSIC)
|
||||
QDEL_NULL(mind)
|
||||
qdel(src)
|
||||
return TRUE
|
||||
|
||||
|
||||
/mob/dead/new_player/proc/IsJobAvailable(rank)
|
||||
var/datum/job/job = SSjob.GetJob(rank)
|
||||
if(!job)
|
||||
@@ -362,7 +384,6 @@
|
||||
|
||||
/mob/dead/new_player/proc/AddEmploymentContract(mob/living/carbon/human/employee)
|
||||
//TODO: figure out a way to exclude wizards/nukeops/demons from this.
|
||||
sleep(30)
|
||||
for(var/C in GLOB.employmentCabinets)
|
||||
var/obj/structure/filingcabinet/employment/employmentCabinet = C
|
||||
if(!employmentCabinet.virgin)
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
empty()
|
||||
|
||||
/obj/item/weapon/gun/energy/kinetic_accelerator/proc/empty()
|
||||
cell.use(500)
|
||||
cell.use(cell.charge)
|
||||
update_icon()
|
||||
|
||||
/obj/item/weapon/gun/energy/kinetic_accelerator/proc/attempt_reload(recharge_time)
|
||||
@@ -125,7 +125,7 @@
|
||||
return
|
||||
|
||||
/obj/item/weapon/gun/energy/kinetic_accelerator/proc/reload()
|
||||
cell.give(500)
|
||||
cell.give(cell.maxcharge)
|
||||
recharge_newshot(1)
|
||||
if(!suppressed)
|
||||
playsound(src.loc, 'sound/weapons/kenetic_reload.ogg', 60, 1)
|
||||
@@ -175,13 +175,18 @@
|
||||
var/turf/target_turf = get_turf(target)
|
||||
if(!isturf(target_turf))
|
||||
return
|
||||
. = ..()
|
||||
if(.)
|
||||
if(kinetic_gun)
|
||||
var/list/mods = kinetic_gun.get_modkits()
|
||||
for(var/obj/item/borg/upgrade/modkit/M in mods)
|
||||
M.projectile_prehit(src, target, kinetic_gun)
|
||||
var/datum/gas_mixture/environment = target_turf.return_air()
|
||||
var/pressure = environment.return_pressure()
|
||||
if(pressure > 50)
|
||||
name = "weakened [name]"
|
||||
damage = damage * pressure_decrease
|
||||
pressure_decrease_active = TRUE
|
||||
. = ..()
|
||||
|
||||
/obj/item/projectile/kinetic/on_range()
|
||||
strike_thing()
|
||||
@@ -270,6 +275,8 @@
|
||||
|
||||
/obj/item/borg/upgrade/modkit/proc/modify_projectile(obj/item/projectile/kinetic/K)
|
||||
|
||||
//use this one for effects you want to trigger before any damage is done at all and before damage is decreased by pressure
|
||||
/obj/item/borg/upgrade/modkit/proc/projectile_prehit(obj/item/projectile/kinetic/K, atom/target, obj/item/weapon/gun/energy/kinetic_accelerator/KA)
|
||||
//use this one for effects you want to trigger before mods that do damage
|
||||
/obj/item/borg/upgrade/modkit/proc/projectile_strike_predamage(obj/item/projectile/kinetic/K, turf/target_turf, atom/target, obj/item/weapon/gun/energy/kinetic_accelerator/KA)
|
||||
//and this one for things that don't need to trigger before other damage-dealing mods
|
||||
@@ -400,7 +407,7 @@
|
||||
cost = 20
|
||||
var/static/list/damage_heal_order = list(BRUTE, BURN, OXY)
|
||||
|
||||
/obj/item/borg/upgrade/modkit/lifesteal/projectile_strike_predamage(obj/item/projectile/kinetic/K, turf/target_turf, atom/target, obj/item/weapon/gun/energy/kinetic_accelerator/KA)
|
||||
/obj/item/borg/upgrade/modkit/lifesteal/projectile_prehit(obj/item/projectile/kinetic/K, atom/target, obj/item/weapon/gun/energy/kinetic_accelerator/KA)
|
||||
if(isliving(target) && isliving(K.firer))
|
||||
var/mob/living/L = target
|
||||
if(L.stat == DEAD)
|
||||
@@ -433,7 +440,7 @@
|
||||
var/maximum_bounty = 25
|
||||
var/list/bounties_reaped = list()
|
||||
|
||||
/obj/item/borg/upgrade/modkit/bounty/projectile_strike(obj/item/projectile/kinetic/K, turf/target_turf, atom/target, obj/item/weapon/gun/energy/kinetic_accelerator/KA)
|
||||
/obj/item/borg/upgrade/modkit/bounty/projectile_prehit(obj/item/projectile/kinetic/K, atom/target, obj/item/weapon/gun/energy/kinetic_accelerator/KA)
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
var/list/existing_marks = L.has_status_effect_list(STATUS_EFFECT_SYPHONMARK)
|
||||
@@ -444,6 +451,10 @@
|
||||
qdel(SM)
|
||||
var/datum/status_effect/syphon_mark/SM = L.apply_status_effect(STATUS_EFFECT_SYPHONMARK)
|
||||
SM.reward_target = src
|
||||
|
||||
/obj/item/borg/upgrade/modkit/bounty/projectile_strike(obj/item/projectile/kinetic/K, turf/target_turf, atom/target, obj/item/weapon/gun/energy/kinetic_accelerator/KA)
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(bounties_reaped[L.type])
|
||||
var/kill_modifier = 1
|
||||
if(K.pressure_decrease_active)
|
||||
|
||||
@@ -561,13 +561,15 @@
|
||||
|
||||
/obj/effect/timestop/Initialize()
|
||||
. = ..()
|
||||
for(var/mob/living/M in GLOB.player_list)
|
||||
for(var/obj/effect/proc_holder/spell/aoe_turf/conjure/timestop/T in M.mind.spell_list) //People who can stop time are immune to timestop
|
||||
immune |= M
|
||||
for(var/M in GLOB.living_mob_list)
|
||||
var/mob/living/L = M
|
||||
for(var/obj/effect/proc_holder/spell/aoe_turf/conjure/timestop/T in L.mind.spell_list) //People who can stop time are immune to timestop
|
||||
immune |= L
|
||||
timestop()
|
||||
|
||||
|
||||
/obj/effect/timestop/proc/timestop()
|
||||
set waitfor = FALSE
|
||||
playsound(get_turf(src), 'sound/magic/TIMEPARADOX2.ogg', 100, 1, -1)
|
||||
for(var/i in 1 to duration-1)
|
||||
for(var/atom/A in orange (freezerange, src.loc))
|
||||
|
||||
@@ -24,6 +24,8 @@ GLOBAL_PROTECT(reboot_mode)
|
||||
if(REBOOT_MODE_SHUTDOWN)
|
||||
to_chat(src, "<span class='boldannounce'>The server is shutting down...</span>")
|
||||
ServiceEndProcess()
|
||||
else
|
||||
ExportService(SERVICE_REQUEST_WORLD_REBOOT) //just let em know
|
||||
|
||||
/world/proc/ServiceCommand(list/params)
|
||||
var/sCK = RunningService()
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
languages_possible = typecacheof(list(
|
||||
/datum/language/common,
|
||||
/datum/language/draconic,
|
||||
/datum/language/codespeak,
|
||||
/datum/language/monkey,
|
||||
/datum/language/beachbum,
|
||||
/datum/language/narsie,
|
||||
|
||||
@@ -1128,6 +1128,20 @@ GLOBAL_LIST_EMPTY(uplink_items) // Global list so we only initialize this once.
|
||||
item = /obj/item/device/jammer
|
||||
cost = 5
|
||||
|
||||
/datum/uplink_item/device_tools/codespeak_manual
|
||||
name = "Codespeak Manual"
|
||||
desc = "Syndicate agents can be trained to use a series of codewords to comvey complex information, which sounds like random concepts and drinks to anyone listening. This manual teaches you this Codespeak. You can also hit someone else with the manual in order to teach them. One use."
|
||||
item = /obj/item/weapon/codespeak_manual
|
||||
cost = 2
|
||||
exclude_modes = list(/datum/game_mode/nuclear)
|
||||
|
||||
/datum/uplink_item/device_tools/codespeak_manual_deluxe
|
||||
name = "Deluxe Codespeak Manual"
|
||||
desc = "Syndicate agents can be trained to use a series of codewords to comvey complex information, which sounds like random concepts and drinks to anyone listening. This manual teaches you this Codespeak. You can also hit someone else with the manual in order to teach them. This is the deluxe edition, which has unlimited uses."
|
||||
cost = 8
|
||||
include_modes = list(/datum/game_mode/nuclear)
|
||||
|
||||
|
||||
// Implants
|
||||
/datum/uplink_item/implants
|
||||
category = "Implants"
|
||||
|
||||
@@ -93,21 +93,25 @@
|
||||
|
||||
|
||||
/world/Topic(T, addr, master, key)
|
||||
if(config && config.log_world_topic)
|
||||
var/list/input = params2list(T)
|
||||
|
||||
var/pinging = ("ping" in input)
|
||||
var/playing = ("players" in input)
|
||||
|
||||
if(!pinging && !playing && config && config.log_world_topic)
|
||||
GLOB.world_game_log << "TOPIC: \"[T]\", from:[addr], master:[master], key:[key]"
|
||||
|
||||
var/list/input = params2list(T)
|
||||
if(input[SERVICE_CMD_PARAM_KEY])
|
||||
return ServiceCommand(input)
|
||||
var/key_valid = (global.comms_allowed && input["key"] == global.comms_key)
|
||||
|
||||
if("ping" in input)
|
||||
if(pinging)
|
||||
var/x = 1
|
||||
for (var/client/C in GLOB.clients)
|
||||
x++
|
||||
return x
|
||||
|
||||
else if("players" in input)
|
||||
else if(playing)
|
||||
var/n = 0
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(M.client)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
@@ -269,6 +269,8 @@
|
||||
#include "code\datums\antagonists\antag_datum.dm"
|
||||
#include "code\datums\antagonists\datum_clockcult.dm"
|
||||
#include "code\datums\antagonists\datum_cult.dm"
|
||||
#include "code\datums\antagonists\datum_internal_affairs.dm"
|
||||
#include "code\datums\antagonists\datum_traitor.dm"
|
||||
#include "code\datums\antagonists\ninja.dm"
|
||||
#include "code\datums\diseases\_disease.dm"
|
||||
#include "code\datums\diseases\_MobProcs.dm"
|
||||
@@ -1183,8 +1185,8 @@
|
||||
#include "code\modules\client\preferences.dm"
|
||||
#include "code\modules\client\preferences_savefile.dm"
|
||||
#include "code\modules\client\preferences_toggles.dm"
|
||||
#include "code\modules\client\verbs\etips.dm"
|
||||
#include "code\modules\client\preferences_vr.dm"
|
||||
#include "code\modules\client\verbs\etips.dm"
|
||||
#include "code\modules\client\verbs\looc.dm"
|
||||
#include "code\modules\client\verbs\ooc.dm"
|
||||
#include "code\modules\client\verbs\ping.dm"
|
||||
@@ -1451,6 +1453,7 @@
|
||||
#include "code\modules\jobs\job_types\security.dm"
|
||||
#include "code\modules\jobs\job_types\silicon.dm"
|
||||
#include "code\modules\language\beachbum.dm"
|
||||
#include "code\modules\language\codespeak.dm"
|
||||
#include "code\modules\language\common.dm"
|
||||
#include "code\modules\language\draconic.dm"
|
||||
#include "code\modules\language\drone.dm"
|
||||
|
||||
Reference in New Issue
Block a user