-
-
Notifications
You must be signed in to change notification settings - Fork 444
/
Copy pathbrother.dm
279 lines (231 loc) · 10.1 KB
/
brother.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
/datum/antagonist/brother
name = "Brother"
antagpanel_category = "Brother"
job_rank = ROLE_BROTHER
var/special_role = ROLE_BROTHER
antag_hud_name = "brother"
var/datum/team/brother_team/team
antag_moodlet = /datum/mood_event/focused
can_hijack = HIJACK_HIJACKER
count_towards_antag_cap = TRUE
/datum/antagonist/brother/create_team(datum/team/brother_team/new_team)
if(!new_team)
return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
team = new_team
/datum/antagonist/brother/get_team()
return team
/datum/antagonist/brother/on_gain()
SSgamemode.brothers += owner
owner.special_role = special_role
if(owner.current)
give_pinpointer()
equip_brother()
finalize_brother()
return ..()
/datum/antagonist/brother/proc/equip_brother()
var/mob/living/carbon/brother = owner.current
var/obj/item/book/granter/crafting_recipe/weapons/W = new
W.on_reading_finished(brother)
qdel(W)
brother.add_skill_points(EXP_HIGH) // extra skills
ADD_TRAIT(owner, TRAIT_EXCEPTIONAL_SKILL, type)
if(istype(brother))
var/obj/item/storage/box/bloodbrother/T = new()
if(brother.equip_to_slot_or_del(T, ITEM_SLOT_BACKPACK))
SEND_SIGNAL(brother.back, COMSIG_TRY_STORAGE_SHOW, brother)
return
//this only prints if it fails to give the box
to_chat(brother, span_userdanger("Unfortunately, you weren't able to get a keepsake box. This is bad and you should adminhelp (press F1)."))
/datum/antagonist/brother/on_removal()
SSgamemode.brothers -= owner
if(owner.current)
to_chat(owner.current,span_userdanger("You are no longer the [special_role]!"))
owner.current.remove_status_effect(/datum/status_effect/agent_pinpointer/brother)
owner.special_role = null
return ..()
/datum/antagonist/brother/antag_panel_data()
return "Conspirators : [get_brother_names()]"
/datum/antagonist/brother/get_preview_icon()
var/mob/living/carbon/human/dummy/consistent/brother1 = new
var/mob/living/carbon/human/dummy/consistent/brother2 = new
brother1.dna.features["mcolor"] = "#ff4d4d"
brother1.set_species(/datum/species/ethereal)
brother2.dna.features["moth_antennae"] = "Plain"
brother2.dna.features["moth_markings"] = "None"
brother2.dna.features["moth_wings"] = "Plain"
brother2.set_species(/datum/species/moth)
var/icon/brother1_icon = render_preview_outfit(/datum/outfit/job/quartermaster, brother1)
brother1_icon.Blend(icon('icons/effects/blood.dmi', "maskblood"), ICON_OVERLAY)
brother1_icon.Shift(WEST, 8)
var/icon/brother2_icon = render_preview_outfit(/datum/outfit/job/scientist, brother2)
brother2_icon.Blend(icon('icons/effects/blood.dmi', "uniformblood"), ICON_OVERLAY)
brother2_icon.Shift(EAST, 8)
var/icon/final_icon = brother1_icon
final_icon.Blend(brother2_icon, ICON_OVERLAY)
qdel(brother1)
qdel(brother2)
return finish_preview_icon(final_icon)
/datum/antagonist/brother/proc/get_brother_names()
var/list/brothers = team.members - owner
var/brother_text = ""
for(var/i = 1 to brothers.len)
var/datum/mind/M = brothers[i]
brother_text += M.name
if(i == brothers.len - 1)
brother_text += " and "
else if(i != brothers.len)
brother_text += ", "
return brother_text
/datum/antagonist/brother/proc/give_meeting_area()
if(!owner.current || !team || !team.meeting_area)
return
to_chat(owner.current, "<B>Your designated meeting area:</B> [team.meeting_area]")
antag_memory += "<b>Meeting Area</b>: [team.meeting_area]<br>"
/datum/antagonist/brother/greet()
var/brother_text = get_brother_names()
to_chat(owner.current, span_alertsyndie("You are the [owner.special_role] of [brother_text]."))
to_chat(owner.current, "The Syndicate only accepts those that have proven themselves. Prove yourself and prove your [team.member_name]s by completing your objectives together! You and your team are outfitted with communication implants allowing for direct, encrypted communication.")
owner.announce_objectives()
give_meeting_area()
/datum/antagonist/brother/proc/finalize_brother()
var/obj/item/implant/bloodbrother/I = new /obj/item/implant/bloodbrother()
I.implant(owner.current, null, TRUE, TRUE)
for(var/datum/mind/M in team.members) // Link the implants of all team members
var/obj/item/implant/bloodbrother/T = locate() in M.current.implants
I.link_implant(T)
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE)
/datum/antagonist/brother/admin_add(datum/mind/new_owner,mob/admin)
//show list of possible brothers
var/list/candidates = list()
for(var/mob/living/L in GLOB.alive_mob_list)
if(!L.mind || L.mind == new_owner || !can_be_owned(L.mind))
continue
candidates[L.mind.name] = L.mind
var/choice = input(admin,"Choose the blood brother.", "Brother") as null|anything in candidates
if(!choice)
return
var/datum/mind/bro = candidates[choice]
var/datum/team/brother_team/T = new
T.add_member(new_owner)
T.add_member(bro)
T.pick_meeting_area()
T.forge_brother_objectives()
new_owner.add_antag_datum(/datum/antagonist/brother,T)
bro.add_antag_datum(/datum/antagonist/brother, T)
T.update_name()
message_admins("[key_name_admin(admin)] made [key_name_admin(new_owner)] and [key_name_admin(bro)] into blood brothers.")
log_admin("[key_name(admin)] made [key_name(new_owner)] and [key_name(bro)] into blood brothers.")
/datum/antagonist/brother/get_admin_commands()
. = ..()
.["Convert To Traitor"] = CALLBACK(src, PROC_REF(make_traitor))
/datum/antagonist/brother/proc/make_traitor()
if(tgui_alert(usr, "Are you sure? This will turn the blood brother into a traitor with the same objectives!",,list("Yes","No")) != "Yes")
return
var/datum/antagonist/traitor/tot = new()
tot.give_objectives = FALSE
for(var/datum/objective/obj in team.objectives)
var/obj_type = obj.type
var/datum/objective/new_obj = new obj_type()
new_obj.owner = owner
new_obj.copy_target(obj)
tot.add_objective(new_obj)
owner.remove_antag_datum(/datum/antagonist/brother)
owner.add_antag_datum(tot)
/datum/antagonist/brother/proc/give_pinpointer()
if(owner && owner.current)
var/datum/status_effect/agent_pinpointer/brother/P = owner.current.apply_status_effect(/datum/status_effect/agent_pinpointer/brother)
P.allowed_targets = team.members - owner
/datum/team/brother_team
name = "brotherhood"
member_name = "blood brother"
var/meeting_area
var/static/meeting_areas = list("The Bar", "Dorms", "Escape Dock", "Arrivals", "Holodeck", "Primary Tool Storage", "Recreation Area", "Chapel", "Library")
/datum/team/brother_team/is_solo()
return FALSE
/datum/team/brother_team/proc/pick_meeting_area()
meeting_area = pick(meeting_areas)
meeting_areas -= meeting_area
/datum/team/brother_team/proc/update_name()
var/list/last_names = list()
for(var/datum/mind/M in members)
var/list/split_name = splittext(M.name," ")
last_names += split_name[split_name.len]
name = last_names.Join(" & ")
/datum/team/brother_team/roundend_report()
var/list/parts = list()
parts += span_header("The blood brothers of [name] were:")
for(var/datum/mind/M in members)
parts += printplayer(M)
var/win = TRUE
var/objective_count = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
parts += "<B>Objective #[objective_count]</B>: [objective.explanation_text] [span_greentext("Success!")]"
else
parts += "<B>Objective #[objective_count]</B>: [objective.explanation_text] [span_redtext("Fail.")]"
win = FALSE
objective_count++
if(win)
parts += span_greentext("The blood brothers were successful!")
else
parts += span_redtext("The blood brothers have failed!")
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
/datum/team/brother_team/proc/add_objective(datum/objective/O, needs_target = FALSE)
O.team = src
if(needs_target)
O.find_target(dupe_search_range = list(src))
O.update_explanation_text()
objectives += O
/datum/team/brother_team/proc/forge_brother_objectives()
objectives = list()
var/is_hijacker = FALSE
if (GLOB.joined_player_list.len >= 30) // Less murderboning on lowpop thanks
is_hijacker = prob(10)
for(var/i = 1 to max(1, CONFIG_GET(number/brother_objectives_amount) + (members.len > 2) - is_hijacker))
forge_single_objective()
if(is_hijacker)
if(!locate(/datum/objective/hijack) in objectives)
add_objective(new/datum/objective/hijack)
else if(!locate(/datum/objective/escape/onesurvivor) in objectives)
add_objective(new/datum/objective/escape/onesurvivor)
/datum/team/brother_team/proc/forge_single_objective()
if(prob(50))
if(LAZYLEN(active_ais()) && prob(100/GLOB.joined_player_list.len))
add_objective(new/datum/objective/destroy, TRUE)
else if(prob(30))
add_objective(new/datum/objective/maroon, TRUE)
else
var/A = pick(/datum/objective/assassinate, /datum/objective/assassinate/cloned, /datum/objective/assassinate/once)
add_objective(new A, TRUE)
else
add_objective(new/datum/objective/steal, TRUE)
/datum/team/brother_team/antag_listing_name()
return "[name] blood brothers"
//box given to every bloodbrother
/obj/item/storage/box/bloodbrother
name = "keepsake box"
desc = "A box full of unusual items found in the maintenance hallways."
///total tc cost that can be inside the box
var/total_box_value = 5
///maximum amount of tc any individual item can be
var/item_value_cap = 2
///list of categories that items are allowed to come from
var/list/allowed_categories = list(UPLINK_CATEGORY_STEALTH_GADGETS, UPLINK_CATEGORY_MISC, UPLINK_CATEGORY_BADASS)
/obj/item/storage/box/bloodbrother/PopulateContents()
var/list/uplink_items = get_uplink_items(null, FALSE)
var/remaining_value = total_box_value
for(var/i = 50; i > 0; i--) //only iterate 50 times, so it doesn't get stuck in an infinite loop
if(remaining_value <= 0)
break
var/category = pick(allowed_categories)
var/item = pick(uplink_items[category])
var/datum/uplink_item/I = uplink_items[category][item]
if(I.cost > item_value_cap || I.cost > remaining_value)
uplink_items[category] -= uplink_items[category][item] //remove it so it can't keep getting picked despite being invalid
continue
remaining_value -= I.cost
new I.item(src)
if(remaining_value > 0)
message_admins("a blood brother has spawned with a keepsake box that has less than the usual value of items, please alert a coder")