Merge remote-tracking branch 'ParadiseSS13/master' into multi-instance-support

This commit is contained in:
AffectedArc07
2021-10-17 20:49:07 +01:00
55 changed files with 699 additions and 214 deletions
+2 -1
View File
@@ -706,8 +706,9 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
if(istext(flags))
flags = text2num(flags)
var/client/check_client = GLOB.directory[ckey]
// Do a little check here
if(GLOB.configuration.system.is_production && (flags & R_ADMIN) && prefs._2fa_status == _2FA_DISABLED) // If they are an admin and their 2FA is disabled
if(GLOB.configuration.system.is_production && (flags & R_ADMIN) && check_client.prefs._2fa_status == _2FA_DISABLED) // If they are an admin and their 2FA is disabled
to_chat(src,"<span class='boldannounce'><big>You do not have 2FA enabled. Admin verbs will be unavailable until you have enabled 2FA.</big></span>") // Very fucking obvious
qdel(admin_read)
return
+6
View File
@@ -117,10 +117,16 @@
/// Client's pAI save
var/datum/pai_save/pai_save
/// List of the clients CUIs
var/list/datum/custom_user_item/cui_entries = list()
/client/vv_edit_var(var_name, var_value)
switch(var_name)
// I know we will never be in a world where admins are editing client vars to let people bypass TOS
// But guess what, if I have the ability to overengineer something, I am going to do it
if("tos_consent")
return FALSE
// Dont fuck with this
if("cui_entries")
return FALSE
return ..()
-2
View File
@@ -149,8 +149,6 @@
karma_purchase(karma,30,"job","Nanotrasen Representative")
if("4")
karma_purchase(karma,30,"job","Blueshield")
if("5")
karma_purchase(karma,45,"job","Magistrate")
return
if(href_list["KarmaBuy2"])
var/karma=verify_karma()
@@ -0,0 +1,20 @@
/datum/client_login_processor/cuis
priority = 45
/datum/client_login_processor/cuis/get_query(client/C)
var/datum/db_query/query = SSdbcore.NewQuery("SELECT cuiRealName, cuiPath, cuiItemName, cuiDescription, cuiJobMask FROM customuseritems WHERE cuiCKey=:ckey", list(
"ckey" = C.ckey
))
return query
/datum/client_login_processor/cuis/process_result(datum/db_query/Q, client/C)
while(Q.NextRow())
var/datum/custom_user_item/cui = new()
cui.characer_name = Q.item[1]
cui.object_typepath = text2path(Q.item[2])
cui.item_name_override = Q.item[3]
cui.item_desc_override = Q.item[4]
cui.raw_job_mask = Q.item[5]
if(cui.parse_info(C.ckey))
C.cui_entries += cui
@@ -96,6 +96,9 @@
if(user.get_active_hand() != src)
to_chat(user, "You must hold [src] in your hand to do this.")
return
toggle_waddle(user)
/obj/item/clothing/shoes/clown_shoes/proc/toggle_waddle(mob/living/user)
if(!enabled_waddle)
to_chat(user, "<span class='notice'>You switch off the waddle dampeners!</span>")
enabled_waddle = TRUE
@@ -111,6 +114,45 @@
desc = "Standard-issue shoes of the wizarding class clown. Damn they're huge! And powerful! Somehow."
magical = TRUE
/obj/item/clothing/shoes/clown_shoes/slippers
actions_types = list(/datum/action/item_action/slipping)
var/slide_distance = 6
var/recharging_rate = 8 SECONDS
var/recharging_time = 0
/obj/item/clothing/shoes/clown_shoes/slippers/item_action_slot_check(slot, mob/user)
if(slot == slot_shoes)
return TRUE
/obj/item/clothing/shoes/clown_shoes/slippers/ui_action_click(mob/user, action)
if(recharging_time > world.time)
to_chat(user, "<span class='warning'>The boot's internal propulsion needs to recharge still!</span>")
return
var/prev_dir = user.dir
var/prev_pass_flags = user.pass_flags
user.pass_flags |= PASSMOB
user.Weaken(2)
user.dir = prev_dir
playsound(src, 'sound/effects/stealthoff.ogg', 50, TRUE, 1)
recharging_time = world.time + recharging_rate
user.visible_message("<span class='warning'>[user] slips forward!</span>")
for(var/i in 1 to slide_distance)
step(user, user.dir)
sleep(1)
user.SetWeakened(0)
user.pass_flags = prev_pass_flags
/obj/item/clothing/shoes/clown_shoes/slippers/toggle_waddle(mob/living/user)
if(!enabled_waddle)
to_chat(user, "<span class='notice'>You switch off the waddle dampeners!</span>")
enabled_waddle = TRUE
slowdown = initial(slowdown)
else
to_chat(user, "<span class='notice'>You switch on the waddle dampeners, [src] no longer slow you down!</span>")
enabled_waddle = FALSE
slowdown = SHOES_SLOWDOWN
/obj/item/clothing/shoes/jackboots
name = "jackboots"
desc = "Nanotrasen-issue Security combat boots for combat scenarios or combat situations. All combat, all the time."
+65 -1
View File
@@ -373,7 +373,71 @@
result = list(/obj/item/stack/tile/carpet/black)
time = 20
reqs = list(/obj/item/stack/tile/carpet = 1)
pathtools = list(/obj/item/toy/crayon)
pathtools = list(/obj/item/toy/crayon/black)
category = CAT_MISC
/datum/crafting_recipe/bluecarpet
name = "Black Carpet"
result = list(/obj/item/stack/tile/carpet/blue)
time = 20
reqs = list(/obj/item/stack/tile/carpet = 1)
pathtools = list(/obj/item/toy/crayon/blue)
category = CAT_MISC
/datum/crafting_recipe/cyancarpet
name = "Cyan Carpet"
result = list(/obj/item/stack/tile/carpet/blue)
time = 20
reqs = list(/obj/item/stack/tile/carpet = 1)
pathtools = list(/obj/item/toy/crayon/blue, /obj/item/toy/crayon/green)
category = CAT_MISC
/datum/crafting_recipe/greencarpet
name = "Green Carpet"
result = list(/obj/item/stack/tile/carpet/green)
time = 20
reqs = list(/obj/item/stack/tile/carpet = 1)
pathtools = list(/obj/item/toy/crayon/green)
category = CAT_MISC
/datum/crafting_recipe/orangecarpet
name = "Orange Carpet"
result = list(/obj/item/stack/tile/carpet/orange)
time = 20
reqs = list(/obj/item/stack/tile/carpet = 1)
pathtools = list(/obj/item/toy/crayon/yellow, /obj/item/toy/crayon/red)
category = CAT_MISC
/datum/crafting_recipe/purplecarpet
name = "Purple Carpet"
result = list(/obj/item/stack/tile/carpet/purple)
time = 20
reqs = list(/obj/item/stack/tile/carpet = 1)
pathtools = list(/obj/item/toy/crayon/red, /obj/item/toy/crayon/blue)
category = CAT_MISC
/datum/crafting_recipe/redcarpet
name = "Red Carpet"
result = list(/obj/item/stack/tile/carpet/purple)
time = 20
reqs = list(/obj/item/stack/tile/carpet = 1)
pathtools = list(/obj/item/toy/crayon/red)
category = CAT_MISC
/datum/crafting_recipe/royalblackcarpet
name = "Royal Black Carpet"
result = list(/obj/item/stack/tile/carpet/royalblack = 10)
time = 20
reqs = list(/obj/item/stack/tile/carpet/black = 10,
/obj/item/stack/sheet/mineral/gold = 2)
category = CAT_MISC
/datum/crafting_recipe/royalbluecarpet
name = "Royal Blue Carpet"
result = list(/obj/item/stack/tile/carpet/royalblue = 10)
time = 20
reqs = list(/obj/item/stack/tile/carpet/blue = 10,
/obj/item/stack/sheet/mineral/gold = 2)
category = CAT_MISC
/datum/crafting_recipe/showercurtain
-101
View File
@@ -1,101 +0,0 @@
/proc/EquipCustomItems(mob/living/carbon/human/M)
if(!SSdbcore.IsConnected())
return
// Grab the info we want.
var/datum/db_query/query = SSdbcore.NewQuery({"
SELECT cuiPath, cuiPropAdjust, cuiJobMask, cuiDescription, cuiItemName FROM customuseritems
WHERE cuiCKey=:ckey AND (cuiRealName=:realname OR cuiRealName='*')"}, list(
"ckey" = M.ckey,
"realname" = M.real_name
))
if(!query.warn_execute(async = FALSE)) // Dont make this async. Youll make roundstart slow. Trust me.
qdel(query)
return
while(query.NextRow())
var/path = text2path(query.item[1])
var/propadjust = query.item[2]
var/jobmask = query.item[3]
var/ok = 0
if(!path || !ispath(path))
log_debug("Incorrect database entry found in table 'customuseritems' path value = [path], cuiPath is null. cuiCKey='[M.ckey]' AND (cuiRealName='[M.real_name]' OR cuiRealName='*'")
continue
if(jobmask != "*")
var/list/allowed_jobs = splittext(jobmask,",")
for(var/i = 1, i <= allowed_jobs.len, i++)
if(istext(allowed_jobs[i]))
allowed_jobs[i] = trim(allowed_jobs[i])
var/alt_blocked = 0
if(M.mind.role_alt_title)
if(!(M.mind.role_alt_title in allowed_jobs))
alt_blocked = 1
if(!(M.mind.assigned_role in allowed_jobs) || alt_blocked)
continue
var/obj/item/Item = new path()
var/description = query.item[4]
var/newname = query.item[5]
if(istype(Item,/obj/item/card/id))
var/obj/item/card/id/I = Item
for(var/obj/item/card/id/C in M)
//default settings
I.name = "[M.real_name]'s ID Card ([M.mind.role_alt_title ? M.mind.role_alt_title : M.mind.assigned_role])"
I.registered_name = M.real_name
I.access = C.access
I.assignment = C.assignment
I.blood_type = C.blood_type
I.dna_hash = C.dna_hash
I.fingerprint_hash = C.fingerprint_hash
qdel(C)
ok = M.equip_or_collect(I, slot_wear_id, 0) //if 1, last argument deletes on fail
break
else if(istype(M.back, /obj/item/storage)) // Try to place it in something on the mob's back
var/obj/item/storage/S = M.back
if(S.contents.len < S.storage_slots)
Item.loc = M.back
ok = 1
to_chat(M, "<span class='notice'>Your [Item.name] has been added to your [M.back.name].</span>")
if(ok == 0)
for(var/obj/item/storage/S in M.contents) // Try to place it in any item that can store stuff, on the mob.
if(S.contents.len < S.storage_slots)
Item.loc = S
ok = 1
to_chat(M, "<span class='notice'>Your [Item.name] has been added to your [S.name].</span>")
break
if(description)
Item.desc = description
if(newname)
Item.name = newname
if(ok == 0) // Finally, since everything else failed, place it on the ground
Item.loc = get_turf(M.loc)
HackProperties(Item,propadjust)
M.regenerate_icons()
qdel(query)
// This is hacky, but since it's difficult as fuck to make a proper parser in BYOND without killing the server, here it is. - N3X
/proc/HackProperties(mob/living/carbon/human/M, obj/item/I, script)
var/list/statements = splittext(script,";")
if(statements.len == 0)
return
for(var/statement in statements)
var/list/assignmentChunks = splittext(statement,"=")
var/varname = assignmentChunks[1]
var/list/typeChunks=splittext(script,":")
var/desiredType=typeChunks[1]
switch(desiredType)
if("string")
var/output = typeChunks[2]
output = replacetext(output,"{REALNAME}", M.real_name)
output = replacetext(output,"{ROLE}", M.mind.assigned_role)
output = replacetext(output,"{ROLE_ALT}", "[M.mind.role_alt_title ? M.mind.role_alt_title : M.mind.assigned_role]")
I.vars[varname]=output
if("number")
I.vars[varname]=text2num(typeChunks[2])
if("icon")
if(typeChunks.len==2)
I.vars[varname]=new /icon(typeChunks[2])
if(typeChunks.len==3)
I.vars[varname]=new /icon(typeChunks[2],typeChunks[3])
+9
View File
@@ -3,3 +3,12 @@
/datum/event/wizard/ghost/start()
var/msg = "<span class='warning'>You suddenly feel extremely obvious...</span>"
set_observer_default_invisibility(0, msg)
/datum/event/wizard/ghost_mute //The spook is silent
/datum/event/wizard/ghost_mute/start()
GLOB.dsay_enabled = FALSE
var/sound/S = sound('sound/hallucinations/wail.ogg')
for(var/mob/dead/observer/silenced in GLOB.player_list)
to_chat(silenced, "<span class='warning'>Magical forces wrap around your spectral form. You can no longer speak to other ghosts!</span>")
SEND_SOUND(silenced, S)
+6 -5
View File
@@ -200,11 +200,12 @@
deckshuffle()
/obj/item/deck/verb/verb_shuffle()
set category = "Object"
set name = "Shuffle"
set desc = "Shuffle the cards in the deck."
set src in view(1)
deckshuffle()
if(!isobserver(usr))
set category = "Object"
set name = "Shuffle"
set desc = "Shuffle the cards in the deck."
set src in view(1)
deckshuffle()
/obj/item/deck/proc/deckshuffle()
var/mob/living/user = usr
+5 -4
View File
@@ -275,10 +275,6 @@ GLOBAL_LIST_EMPTY(karma_spenders)
dat += "<a href='?src=[UID()];karmashop=shop;KarmaBuy=4'>Unlock Blueshield -- 30KP</a><br>"
else
dat += "Blueshield - <font color='green'>Unlocked</font><br>"
if(!("Magistrate" in joblist))
dat += "<a href='?src=[UID()];karmashop=shop;KarmaBuy=5'>Unlock Magistrate -- 45KP</a><br>"
else
dat+= "Magistrate - <font color='green'>Unlocked</font><br>"
if(1) // Species Unlocks
if(!("Machine" in specieslist))
@@ -349,6 +345,9 @@ GLOBAL_LIST_EMPTY(karma_spenders)
if("Security Pod Pilot" in purchased)
refundable += "Security Pod Pilot"
dat += "<a href='?src=[UID()];karmashop=shop;KarmaRefund=Security Pod Pilot;KarmaRefundType=job;KarmaRefundCost=30'>Refund Security Pod Pilot -- 30KP</a><br>"
if("Magistrate" in purchased)
refundable += "Magistrate"
dat += "<a href='?src=[UID()];karmashop=shop;KarmaRefund=Magistrate;KarmaRefundType=job;KarmaRefundCost=45'>Refund Magistrate -- 45KP</a><br>"
if(!refundable.len)
dat += "You do not have any refundable karma purchases.<br>"
@@ -515,6 +514,8 @@ GLOBAL_LIST_EMPTY(karma_spenders)
cost = 30
if("Nanotrasen Recruiter")
cost = 10
if("Magistrate")
cost = 45
else
to_chat(usr, "<span class='warning'>That job is not refundable.</span>")
return
+3
View File
@@ -79,6 +79,9 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
var/obj/machinery/power/apc/malfhack = null
var/explosive = 0 //does the AI explode when it dies?
/// List of modules the AI has purchased malf upgrades for.
var/list/purchased_modules = list()
var/mob/living/silicon/ai/parent = null
var/camera_light_on = 0
var/list/obj/machinery/camera/lit_cameras = list()
+4 -2
View File
@@ -26,7 +26,8 @@
"Parrot" = "parrot",
"Box Bot" = "boxbot",
"Spider Bot" = "spiderbot",
"Fairy" = "fairy"
"Fairy" = "fairy",
"Snake" = "snake"
)
var/global/list/possible_say_verbs = list(
@@ -35,7 +36,8 @@
"Beep" = list("beeps","beeps loudly","boops"),
"Chirp" = list("chirps","chirrups","cheeps"),
"Feline" = list("purrs","yowls","meows"),
"Canine" = list("yaps","barks","growls")
"Canine" = list("yaps","barks","growls"),
"Hiss" = list("hisses","hisses","hisses")
)
@@ -1264,6 +1264,8 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
connected_ai = AI
connected_ai.connected_robots |= src
notify_ai(1)
if(module)
module.rebuild_modules() //This way, if a borg gets linked to a malf AI that has upgrades, they get their upgrades.
sync()
/mob/living/silicon/robot/adjustOxyLoss(amount)
@@ -6,12 +6,17 @@
item_state = "electronic"
flags = CONDUCT
/// Has the AI hacked the borg module, allowing access to the malf AI exclusive item.
var/malfhacked = FALSE
/// A list of all currently usable and created modules the robot currently has access too.
var/list/modules = list()
/// A list of module-specific, non-emag modules the borg will gain when this module is chosen.
var/list/basic_modules = list()
/// A list of modules the robot gets when emagged.
var/list/emag_modules = list()
/// A list of modules that the robot gets when malf AI buys it.
var/list/malf_modules = list()
/// A list of modules that require special recharge handling. Examples include things like flashes, sprays and welding tools.
var/list/special_rechargables = list()
/// A list of all "energy stacks", i.e metal, glass, brute kits, splints, etc.
@@ -43,12 +48,17 @@
emag_modules += I
emag_modules -= i
for(var/i in malf_modules)
var/obj/item/I = new i(src)
malf_modules += I
malf_modules -= i
// Flashes need a special recharge, and since basically every module uses it, add it here.
// Even if the module doesn't use a flash, it wont cause any issues to have it in this list.
special_rechargables += /obj/item/flash/cyborg
// This is done so we can loop through this list later and call cyborg_recharge() on the items while the borg is recharging.
var/all_modules = basic_modules | emag_modules
var/all_modules = basic_modules | emag_modules | malf_modules
for(var/path in special_rechargables)
var/obj/item/I = locate(path) in all_modules
if(I) // If it exists, add the object reference.
@@ -70,6 +80,7 @@
QDEL_LIST(modules)
QDEL_LIST(basic_modules)
QDEL_LIST(emag_modules)
QDEL_LIST(malf_modules)
QDEL_LIST(storages)
QDEL_LIST(special_rechargables)
return ..()
@@ -88,6 +99,7 @@
var/list/lists = list(
basic_modules,
emag_modules,
malf_modules,
storages,
special_rechargables
)
@@ -155,13 +167,17 @@
return I
/**
* Builds the usable module list from the modules we have in `basic_modules` and `emag_modules`
* Builds the usable module list from the modules we have in `basic_modules`, `emag_modules` and `malf_modules`
*/
/obj/item/robot_module/proc/rebuild_modules()
var/mob/living/silicon/robot/R = loc
R.uneq_all()
modules = list()
if(!malfhacked && R.connected_ai)
if(type in R.connected_ai.purchased_modules)
malfhacked = TRUE
// By this point these lists should only contain items. It's safe to use typeless loops here.
for(var/item in basic_modules)
add_module(item, FALSE)
@@ -170,6 +186,10 @@
for(var/item in emag_modules)
add_module(item, FALSE)
if(malfhacked)
for(var/item in malf_modules)
add_module(item, FALSE)
if(R.hud_used)
R.hud_used.update_robot_modules_display()
@@ -354,8 +374,9 @@
/obj/item/stack/sheet/glass/cyborg,
/obj/item/stack/sheet/rglass/cyborg
)
emag_modules = list(/obj/item/borg/stun)
special_rechargables = list(/obj/item/extinguisher, /obj/item/weldingtool/largetank/cyborg)
emag_modules = list(/obj/item/borg/stun, /obj/item/restraints/handcuffs/cable/zipties/cyborg)
malf_modules = list(/obj/item/gun/energy/emitter/cyborg)
special_rechargables = list(/obj/item/extinguisher, /obj/item/weldingtool/largetank/cyborg, /obj/item/gun/energy/emitter/cyborg)
/obj/item/robot_module/engineering/handle_death(mob/living/silicon/robot/R, gibbed)
var/obj/item/gripper/G = locate(/obj/item/gripper) in modules
@@ -400,7 +421,7 @@
/obj/item/holosign_creator,
/obj/item/extinguisher/mini
)
emag_modules = list(/obj/item/reagent_containers/spray/cyborg_lube)
emag_modules = list(/obj/item/reagent_containers/spray/cyborg_lube, /obj/item/restraints/handcuffs/cable/zipties/cyborg)
special_rechargables = list(
/obj/item/lightreplacer,
/obj/item/reagent_containers/spray/cyborg_lube,
@@ -471,7 +492,7 @@
/obj/item/storage/bag/tray/cyborg,
/obj/item/reagent_containers/food/drinks/shaker
)
emag_modules = list(/obj/item/reagent_containers/food/drinks/cans/beer/sleepy_beer)
emag_modules = list(/obj/item/reagent_containers/food/drinks/cans/beer/sleepy_beer, /obj/item/restraints/handcuffs/cable/zipties/cyborg)
special_rechargables = list(
/obj/item/reagent_containers/food/condiment/enzyme,
/obj/item/reagent_containers/food/drinks/cans/beer/sleepy_beer
@@ -530,7 +551,7 @@
/obj/item/gun/energy/kinetic_accelerator/cyborg,
/obj/item/gps/cyborg
)
emag_modules = list(/obj/item/borg/stun, /obj/item/pickaxe/drill/cyborg/diamond)
emag_modules = list(/obj/item/borg/stun, /obj/item/pickaxe/drill/cyborg/diamond, /obj/item/restraints/handcuffs/cable/zipties/cyborg)
special_rechargables = list(/obj/item/extinguisher/mini, /obj/item/weldingtool/mini)
// Replace their normal drill with a diamond drill.
+1 -1
View File
@@ -359,7 +359,7 @@
character.buckled.dir = character.dir
character = SSjobs.EquipRank(character, rank, 1) //equips the human
EquipCustomItems(character)
SSticker.equip_cuis(character) // Gives them their CUIs
SSticker.mode.latespawn(character)
+1
View File
@@ -140,6 +140,7 @@
var/on = 0
var/brightness_on = 2
light_color = LIGHT_COLOR_RED
armour_penetration = 20
/obj/item/pen/edagger/attack_self(mob/living/user)
if(on)
@@ -271,6 +271,17 @@
delay = 50
select_name = "snipe"
/obj/item/ammo_casing/energy/emitter
projectile_type = /obj/item/projectile/beam/emitter
muzzle_flash_color = LIGHT_COLOR_GREEN
fire_sound = 'sound/weapons/emitter.ogg'
e_cost = 100
delay = 2 SECONDS // Lasers fire twice every second for 40 dps, this fires every 2 seconds for 15 dps. Seems fair, since every cyborg will have this with more shots?
select_name = "emitter"
/obj/item/ammo_casing/energy/emitter/cyborg
e_cost = 500 // about 28 shots on an engineering borg from a borging machine, assuming some power is used for lights / movement. May need to change.
/obj/item/ammo_casing/energy/bsg
projectile_type = /obj/item/projectile/energy/bsg
muzzle_flash_color = LIGHT_COLOR_DARKBLUE
@@ -141,6 +141,29 @@
name = "cyborg immolator cannon"
ammo_type = list(/obj/item/ammo_casing/energy/immolator/scatter/cyborg, /obj/item/ammo_casing/energy/immolator/strong/cyborg) // scatter is default, because it is more useful
/obj/item/gun/energy/emitter
name = "mobile emitter"
desc = "An emitter removed from its base, and attached to a laser cannon frame."
icon_state = "emittercannon"
item_state = "laser"
w_class = WEIGHT_CLASS_BULKY
shaded_charge = TRUE
can_holster = FALSE
origin_tech = "combat=4;magnets=4;powerstorage=3"
ammo_type = list(/obj/item/ammo_casing/energy/emitter)
ammo_x_offset = 3
/obj/item/gun/energy/emitter/cyborg
name = "mounted emitter"
desc = "An emitter built into to your cyborg frame, draining charge from your cell."
ammo_type = list(/obj/item/ammo_casing/energy/emitter/cyborg)
/obj/item/gun/energy/emitter/cyborg/newshot()
..()
robocharge()
/obj/item/gun/energy/emitter/cyborg/emp_act()
return
////////Laser Tag////////////////////