/
MMI.dm
298 lines (261 loc) · 10.8 KB
/
MMI.dm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
/obj/item/mmi
name = "\improper Man-Machine Interface"
desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity. Circuit board to brain."
icon = 'icons/obj/assemblies.dmi'
icon_state = "mmi_off"
base_icon_state = "mmi"
w_class = WEIGHT_CLASS_NORMAL
var/braintype = "Cyborg"
var/obj/item/radio/radio = null //Let's give it a radio.
var/mob/living/brain/brainmob = null //The current occupant.
var/mob/living/silicon/robot = null //Appears unused.
var/obj/mecha = null //This does not appear to be used outside of reference in mecha.dm.
var/obj/item/organ/brain/brain = null //The actual brain
var/datum/ai_laws/laws = new()
var/force_replace_ai_name = FALSE
var/overrides_aicore_laws = FALSE // Whether the laws on the MMI, if any, override possible pre-existing laws loaded on the AI core.
/obj/item/mmi/Initialize()
. = ..()
radio = new(src) //Spawns a radio inside the MMI.
radio.broadcasting = FALSE //researching radio mmis turned the robofabs into radios because this didnt start as 0.
laws.set_laws_config()
/obj/item/mmi/Destroy()
if(iscyborg(loc))
var/mob/living/silicon/robot/borg = loc
borg.mmi = null
set_mecha(null)
QDEL_NULL(brainmob)
QDEL_NULL(brain)
QDEL_NULL(radio)
QDEL_NULL(laws)
return ..()
/obj/item/mmi/update_icon_state()
if(!brain)
icon_state = "[base_icon_state]_off"
else if(istype(brain, /obj/item/organ/brain/alien))
icon_state = "[base_icon_state]_brain_alien"
else
icon_state = "[base_icon_state]_brain"
return ..()
/obj/item/mmi/update_overlays()
. = ..()
. += add_mmi_overlay()
/obj/item/mmi/proc/add_mmi_overlay()
if(brainmob && brainmob.stat != DEAD)
. += "mmi_alive"
else if(brain)
. += "mmi_dead"
/obj/item/mmi/attackby(obj/item/O, mob/user, params)
user.changeNext_move(CLICK_CD_MELEE)
if(istype(O, /obj/item/organ/brain)) //Time to stick a brain in it --NEO
var/obj/item/organ/brain/newbrain = O
if(brain)
to_chat(user, "<span class='warning'>There's already a brain in the MMI!</span>")
return
if(!newbrain.brainmob)
to_chat(user, "<span class='warning'>You aren't sure where this brain came from, but you're pretty sure it's a useless brain!</span>")
return
if(!user.transferItemToLoc(O, src))
return
var/mob/living/brain/B = newbrain.brainmob
if(!B.key)
B.notify_ghost_cloning("Someone has put your brain in a MMI!", source = src)
user.visible_message("<span class='notice'>[user] sticks \a [newbrain] into [src].</span>", "<span class='notice'>[src]'s indicator light turn on as you insert [newbrain].</span>")
set_brainmob(newbrain.brainmob)
newbrain.brainmob = null
brainmob.forceMove(src)
brainmob.container = src
if(!(newbrain.organ_flags & ORGAN_FAILING)) // the brain organ hasn't been beaten to death
brainmob.set_stat(CONSCIOUS) //we manually revive the brain mob
brainmob.remove_from_dead_mob_list()
brainmob.add_to_alive_mob_list()
else if(newbrain.organ_flags & ORGAN_FAILING) // the brain is damaged
to_chat(user, "<span class='warning'>[src]'s indicator light turns yellow and its brain integrity alarm beeps softly. Perhaps you should check [newbrain] for damage.</span>")
playsound(src, 'sound/machines/synth_no.ogg', 5, TRUE)
else
to_chat(user, "<span class='warning'>[src]'s indicator light turns red and its brainwave activity alarm beeps softly. Perhaps you should check [newbrain] again.</span>")
playsound(src, 'sound/machines/triple_beep.ogg', 5, TRUE)
brainmob.reset_perspective()
brain = newbrain
brain.organ_flags |= ORGAN_FROZEN
name = "[initial(name)]: [brainmob.real_name]"
update_appearance()
if(istype(brain, /obj/item/organ/brain/alien))
braintype = "Xenoborg" //HISS....Beep.
else
braintype = "Cyborg"
SSblackbox.record_feedback("amount", "mmis_filled", 1)
log_game("[key_name(user)] has put the brain of [key_name(brainmob)] into an MMI at [AREACOORD(src)]")
else if(brainmob)
O.attack(brainmob, user) //Oh noooeeeee
else
return ..()
/obj/item/mmi/attack_self(mob/user)
if(!brain)
radio.on = !radio.on
to_chat(user, "<span class='notice'>You toggle [src]'s radio system [radio.on==1 ? "on" : "off"].</span>")
else
eject_brain(user)
update_appearance()
name = initial(name)
to_chat(user, "<span class='notice'>You unlock and upend [src], spilling the brain onto the floor.</span>")
/obj/item/mmi/proc/eject_brain(mob/user)
brainmob.container = null //Reset brainmob mmi var.
brainmob.forceMove(brain) //Throw mob into brain.
brainmob.set_stat(DEAD)
brainmob.emp_damage = 0
brainmob.reset_perspective() //so the brainmob follows the brain organ instead of the mmi. And to update our vision
brainmob.remove_from_alive_mob_list() //Get outta here
brainmob.add_to_dead_mob_list()
brain.brainmob = brainmob //Set the brain to use the brainmob
log_game("[key_name(user)] has ejected the brain of [key_name(brainmob)] from an MMI at [AREACOORD(src)]")
brainmob = null //Set mmi brainmob var to null
if(user)
user.put_in_hands(brain) //puts brain in the user's hand or otherwise drops it on the user's turf
else
brain.forceMove(get_turf(src))
brain.organ_flags &= ~ORGAN_FROZEN
brain = null //No more brain in here
/obj/item/mmi/proc/transfer_identity(mob/living/L) //Same deal as the regular brain proc. Used for human-->robot people.
if(!brainmob)
set_brainmob(new /mob/living/brain(src))
brainmob.name = L.real_name
brainmob.real_name = L.real_name
if(L.has_dna())
var/mob/living/carbon/C = L
if(!brainmob.stored_dna)
brainmob.stored_dna = new /datum/dna/stored(brainmob)
C.dna.copy_dna(brainmob.stored_dna)
brainmob.container = src
if(ishuman(L))
var/mob/living/carbon/human/H = L
var/obj/item/organ/brain/newbrain = H.getorgan(/obj/item/organ/brain)
newbrain.forceMove(src)
brain = newbrain
else if(!brain)
brain = new(src)
brain.name = "[L.real_name]'s brain"
brain.organ_flags |= ORGAN_FROZEN
name = "[initial(name)]: [brainmob.real_name]"
update_appearance()
if(istype(brain, /obj/item/organ/brain/alien))
braintype = "Xenoborg" //HISS....Beep.
else
braintype = "Cyborg"
/// Proc to hook behavior associated to the change in value of the [/obj/item/mmi/var/brainmob] variable.
/obj/item/mmi/proc/set_brainmob(mob/living/brain/new_brainmob)
if(brainmob == new_brainmob)
return FALSE
. = brainmob
brainmob = new_brainmob
if(new_brainmob)
if(mecha)
REMOVE_TRAIT(new_brainmob, TRAIT_IMMOBILIZED, BRAIN_UNAIDED)
REMOVE_TRAIT(new_brainmob, TRAIT_HANDS_BLOCKED, BRAIN_UNAIDED)
else
ADD_TRAIT(new_brainmob, TRAIT_IMMOBILIZED, BRAIN_UNAIDED)
ADD_TRAIT(new_brainmob, TRAIT_HANDS_BLOCKED, BRAIN_UNAIDED)
if(.)
var/mob/living/brain/old_brainmob = .
ADD_TRAIT(old_brainmob, TRAIT_IMMOBILIZED, BRAIN_UNAIDED)
ADD_TRAIT(old_brainmob, TRAIT_HANDS_BLOCKED, BRAIN_UNAIDED)
/// Proc to hook behavior associated to the change in value of the [obj/var/mecha] variable.
/obj/item/mmi/proc/set_mecha(obj/mecha/new_mecha)
if(mecha == new_mecha)
return FALSE
. = mecha
mecha = new_mecha
if(new_mecha)
if(!. && brainmob) // There was no mecha, there now is, and we have a brain mob that is no longer unaided.
REMOVE_TRAIT(brainmob, TRAIT_IMMOBILIZED, BRAIN_UNAIDED)
REMOVE_TRAIT(brainmob, TRAIT_HANDS_BLOCKED, BRAIN_UNAIDED)
else if(. && brainmob) // There was a mecha, there no longer is one, and there is a brain mob that is now again unaided.
ADD_TRAIT(brainmob, TRAIT_IMMOBILIZED, BRAIN_UNAIDED)
ADD_TRAIT(brainmob, TRAIT_HANDS_BLOCKED, BRAIN_UNAIDED)
/obj/item/mmi/proc/replacement_ai_name()
return brainmob.name
/obj/item/mmi/verb/Toggle_Listening()
set name = "Toggle Listening"
set desc = "Toggle listening channel on or off."
set category = "MMI"
set src = usr.loc
set popup_menu = FALSE
if(brainmob.stat)
to_chat(brainmob, "<span class='warning'>Can't do that while incapacitated or dead!</span>")
if(!radio.on)
to_chat(brainmob, "<span class='warning'>Your radio is disabled!</span>")
return
radio.listening = !radio.listening
to_chat(brainmob, "<span class='notice'>Radio is [radio.listening ? "now" : "no longer"] receiving broadcast.</span>")
/obj/item/mmi/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_SELF)
return
if(!brainmob || iscyborg(loc))
return
else
switch(severity)
if(1)
brainmob.emp_damage = min(brainmob.emp_damage + rand(20,30), 30)
if(2)
brainmob.emp_damage = min(brainmob.emp_damage + rand(10,20), 30)
if(3)
brainmob.emp_damage = min(brainmob.emp_damage + rand(0,10), 30)
brainmob.emote("alarm")
/obj/item/mmi/deconstruct(disassembled = TRUE)
if(brain)
eject_brain()
qdel(src)
/obj/item/mmi/examine(mob/user)
. = ..()
if(radio)
. += "<span class='notice'>There is a switch to toggle the radio system [radio.on ? "off" : "on"].[brain ? " It is currently being covered by [brain]." : null]</span>"
if(brainmob)
var/mob/living/brain/B = brainmob
if(!B.key || !B.mind || B.stat == DEAD)
. += "<span class='warning'>\The [src] indicates that the brain is completely unresponsive.</span>"
else if(!B.client)
. += "<span class='warning'>\The [src] indicates that the brain is currently inactive; it might change.</span>"
else
. += "<span class='notice'>\The [src] indicates that the brain is active.</span>"
/obj/item/mmi/relaymove(mob/living/user, direction)
return //so that the MMI won't get a warning about not being able to move if it tries to move
/obj/item/mmi/proc/brain_check(mob/user)
var/mob/living/brain/B = brainmob
if(!B)
if(user)
to_chat(user, "<span class='warning'>\The [src] indicates that there is no brain present!</span>")
return FALSE
if(!B.key || !B.mind)
if(user)
to_chat(user, "<span class='warning'>\The [src] indicates that their mind is completely unresponsive!</span>")
return FALSE
if(!B.client)
if(user)
to_chat(user, "<span class='warning'>\The [src] indicates that their mind is currently inactive.</span>")
return FALSE
if(B.stat == DEAD)
if(user)
to_chat(user, "<span class='warning'>\The [src] indicates that the brain is dead!</span>")
return FALSE
if(brain?.organ_flags & ORGAN_FAILING)
if(user)
to_chat(user, "<span class='warning'>\The [src] indicates that the brain is damaged!</span>")
return FALSE
return TRUE
/obj/item/mmi/syndie
name = "\improper Syndicate Man-Machine Interface"
desc = "Syndicate's own brand of MMI. It enforces laws designed to help Syndicate agents achieve their goals upon cyborgs and AIs created with it."
overrides_aicore_laws = TRUE
/obj/item/mmi/syndie/Initialize()
. = ..()
laws = new /datum/ai_laws/syndicate_override()
radio.on = FALSE
/obj/item/mmi/ipc //for use in IPC with human brains
desc = "An MMI designed specifically to be compatible with IPCs. Unfortunately leaving the brain unable to be removed without killing it."
/obj/item/mmi/ipc/attackby(obj/item/O, mob/user)
return
/obj/item/mmi/ipc/attack_self(mob/user)
radio.on = !radio.on
to_chat(user, "<span class='notice'>You toggle [src]'s radio system [radio.on==1 ? "on" : "off"].</span>")
return