Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into revert-8235-defib-notouch
This commit is contained in:
@@ -200,13 +200,15 @@
|
||||
/datum/dynamic_ruleset/latejoin/heretic_smuggler
|
||||
name = "Heretic Smuggler"
|
||||
antag_datum = /datum/antagonist/heretic
|
||||
antag_flag = ROLE_HERETIC
|
||||
antag_flag = "latejoin_heretic"
|
||||
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
restricted_roles = list("AI","Cyborg")
|
||||
required_candidates = 1
|
||||
weight = 4
|
||||
cost = 10
|
||||
requirements = list(40,30,20,10,10,10,10,10,10,10)
|
||||
cost = 25
|
||||
requirements = list(60,60,60,55,50,50,50,50,50,50)
|
||||
high_population_requirement = 50
|
||||
property_weights = list("story_potential" = 1, "trust" = -1, "chaos" = 2, "extended" = -1, "valid" = 2)
|
||||
repeatable = TRUE
|
||||
|
||||
//////////////////////////////////////////////
|
||||
|
||||
@@ -538,7 +538,7 @@
|
||||
name = "Slaughter Demon"
|
||||
config_tag = "slaughter_demon"
|
||||
antag_flag = ROLE_ALIEN
|
||||
enemy_roles = list("Security Officer","Shaft Miner","Head of Security","Captain","Janitor","AI","Cyborg")
|
||||
enemy_roles = list("Security Officer","Shaft Miner","Head of Security","Captain","Janitor","AI","Cyborg","Bartender")
|
||||
required_enemies = list(3,2,2,2,2,1,1,1,1,0)
|
||||
required_candidates = 1
|
||||
weight = 4
|
||||
|
||||
@@ -151,16 +151,18 @@
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/heretics
|
||||
name = "Heretics"
|
||||
antag_flag = ROLE_HERETIC
|
||||
antag_flag = "heretic"
|
||||
antag_datum = /datum/antagonist/heretic
|
||||
protected_roles = list("Prisoner","Security Officer", "Warden", "Detective", "Head of Security", "Captain")
|
||||
restricted_roles = list("AI", "Cyborg")
|
||||
required_candidates = 1
|
||||
weight = 3
|
||||
cost = 20
|
||||
cost = 25
|
||||
scaling_cost = 15
|
||||
requirements = list(50,45,45,40,35,20,20,15,10,10)
|
||||
requirements = list(60,60,60,55,50,50,50,50,50,50)
|
||||
property_weights = list("story_potential" = 1, "trust" = -1, "chaos" = 2, "extended" = -1, "valid" = 2)
|
||||
antag_cap = list(1,1,1,1,2,2,2,2,3,3)
|
||||
high_population_requirement = 50
|
||||
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/heretics/pre_execute()
|
||||
|
||||
@@ -22,14 +22,14 @@
|
||||
var/datum/game_mode/dynamic/mode = null // Cached as soon as it's made, by dynamic.
|
||||
|
||||
/**
|
||||
Property weights are:
|
||||
Property weights are added to the config weight of the ruleset. They are:
|
||||
"story_potential" -- essentially how many different ways the antag can be played.
|
||||
"trust" -- How much it makes the crew trust each other. Negative values means they're suspicious. Team antags are like this.
|
||||
"chaos" -- How chaotic it makes the round. Has some overlap with "valid" and somewhat contradicts "extended".
|
||||
"valid" -- How likely the non-antag-enemy crew are to get involved, e.g. nukies encouraging the warden to
|
||||
let everyone into the armory, wizard moving around and being a nuisance, nightmare busting lights.
|
||||
"extended" -- How much the antag is conducive to a long round. Nukies and cults are bad for this; Wizard is less bad; and so on.
|
||||
"conversion" -- Basically a bool. Conversion antags, well, convert. It's its own class for a good reason.
|
||||
"conversion" -- Basically a bool. Conversion antags, well, convert. It's in its own class 'cause people kinda hate conversion.
|
||||
*/
|
||||
|
||||
/datum/dynamic_storyteller/proc/start_injection_cooldowns()
|
||||
@@ -126,8 +126,9 @@ Property weights are:
|
||||
for(var/property in property_weights)
|
||||
if(property in rule.property_weights) // just treat it as 0 if it's not in there
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
if(property_weight > 0)
|
||||
drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult
|
||||
var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult
|
||||
if(calced_weight > 0) // negatives in the list might cause problems
|
||||
drafted_rules[rule] = calced_weight
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/proc/midround_draft()
|
||||
@@ -144,21 +145,24 @@ Property weights are:
|
||||
for(var/property in property_weights)
|
||||
if(property in rule.property_weights) // just treat it as 0 if it's not in there
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
if(property_weight > 0)
|
||||
var/threat_weight = 1
|
||||
if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway
|
||||
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
|
||||
/* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to
|
||||
pick this particular ruleset.
|
||||
Let's use a toy example: there's 60 threat level and 10 threat spent.
|
||||
We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets.
|
||||
Ruleset 1 has 30 cost, ruleset 2 has 5 cost.
|
||||
When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1
|
||||
is 2.26 times as likely to be picked, all other things considered.
|
||||
Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight.
|
||||
*/
|
||||
threat_weight = abs(1-abs(1-LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
|
||||
drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult * threat_weight
|
||||
var/threat_weight = 1
|
||||
if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway
|
||||
var/cost_difference = rule.cost-(mode.threat_level-mode.threat)
|
||||
/* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to
|
||||
pick this particular ruleset.
|
||||
Let's use a toy example: there's 60 threat level and 10 threat spent.
|
||||
We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets.
|
||||
Ruleset 1 has 30 cost, ruleset 2 has 5 cost.
|
||||
When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1
|
||||
is 2.26 times as likely to be picked, all other things considered.
|
||||
Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight.
|
||||
*/
|
||||
threat_weight = abs(1-abs(1-LOGISTIC_FUNCTION(2,0.05,abs(cost_difference),0)))
|
||||
if(cost_difference > 0)
|
||||
threat_weight /= (1+(cost_difference*0.1))
|
||||
var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult * threat_weight
|
||||
if(calced_weight > 0)
|
||||
drafted_rules[rule] = calced_weight
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/proc/latejoin_draft(mob/living/carbon/human/newPlayer)
|
||||
@@ -180,12 +184,15 @@ Property weights are:
|
||||
for(var/property in property_weights)
|
||||
if(property in rule.property_weights)
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
if(property_weight > 0)
|
||||
var/threat_weight = 1
|
||||
if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))
|
||||
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
|
||||
threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
|
||||
drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult * threat_weight
|
||||
var/threat_weight = 1
|
||||
if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))
|
||||
var/cost_difference = rule.cost-(mode.threat_level-mode.threat)
|
||||
threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,abs(cost_difference),0)))
|
||||
if(cost_difference > 0)
|
||||
threat_weight /= (1+(cost_difference*0.1))
|
||||
var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult * threat_weight
|
||||
if(calced_weight > 0)
|
||||
drafted_rules[rule] = calced_weight
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/proc/event_draft()
|
||||
@@ -196,8 +203,9 @@ Property weights are:
|
||||
for(var/property in property_weights)
|
||||
if(property in rule.property_weights)
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
if(property_weight > 0)
|
||||
drafted_rules[rule] = rule.get_weight() + property_weight * rule.weight_mult
|
||||
var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult
|
||||
if(calced_weight > 0)
|
||||
drafted_rules[rule] = calced_weight
|
||||
return drafted_rules
|
||||
|
||||
|
||||
@@ -327,12 +335,6 @@ Property weights are:
|
||||
flags = USE_PREV_ROUND_WEIGHTS
|
||||
property_weights = list("story_potential" = 2)
|
||||
|
||||
|
||||
/datum/dynamic_storyteller/story/calculate_threat()
|
||||
var/current_time = (world.time / SSautotransfer.targettime)*180
|
||||
mode.threat_level = round((mode.initial_threat_level*(sin(current_time)/2)+0.75),0.1)
|
||||
return ..()
|
||||
|
||||
/datum/dynamic_storyteller/classic
|
||||
name = "Classic"
|
||||
config_tag = "classic"
|
||||
|
||||
@@ -74,12 +74,6 @@
|
||||
/obj/machinery/door/firedoor/Bumped(atom/movable/AM)
|
||||
if(panel_open || operating || welded)
|
||||
return
|
||||
if(ismob(AM))
|
||||
var/mob/user = AM
|
||||
if(density && !welded && !operating && !(stat & NOPOWER) && (!density || allow_hand_open(user)))
|
||||
add_fingerprint(user)
|
||||
open()
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/door/firedoor/power_change()
|
||||
@@ -90,14 +84,6 @@
|
||||
stat |= NOPOWER
|
||||
|
||||
/obj/machinery/door/firedoor/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
if(!welded && !operating && !(stat & NOPOWER) && (!density || allow_hand_open(user)))
|
||||
add_fingerprint(user)
|
||||
if(density)
|
||||
emergency_close_timer = world.time + 30 // prevent it from instaclosing again if in space
|
||||
open()
|
||||
else
|
||||
close()
|
||||
return TRUE
|
||||
if(operating || !density)
|
||||
return
|
||||
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
/obj/mecha/proc/get_armour_facing(relative_dir)
|
||||
switch(relative_dir)
|
||||
if(0) // BACKSTAB!
|
||||
if(180) // BACKSTAB!
|
||||
return facing_modifiers[BACK_ARMOUR]
|
||||
if(45, 90, 270, 315)
|
||||
return facing_modifiers[SIDE_ARMOUR]
|
||||
if(225, 180, 135)
|
||||
if(0, 45) // direct or 45 degrees off
|
||||
return facing_modifiers[FRONT_ARMOUR]
|
||||
return 1 //always return non-0
|
||||
return facing_modifiers[SIDE_ARMOUR] //if its not a front hit or back hit then assume its from the side
|
||||
|
||||
/obj/mecha/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
|
||||
. = ..()
|
||||
@@ -43,7 +41,7 @@
|
||||
break
|
||||
|
||||
if(attack_dir)
|
||||
var/facing_modifier = get_armour_facing(dir2angle(attack_dir) - dir2angle(src))
|
||||
var/facing_modifier = get_armour_facing(abs(dir2angle(dir) - dir2angle(attack_dir)))
|
||||
booster_damage_modifier /= facing_modifier
|
||||
booster_deflection_modifier *= facing_modifier
|
||||
if(prob(deflect_chance * booster_deflection_modifier))
|
||||
|
||||
@@ -285,7 +285,7 @@
|
||||
S.rabid = TRUE
|
||||
S.amount_grown = SLIME_EVOLUTION_THRESHOLD
|
||||
S.Evolve()
|
||||
offer_control(S)
|
||||
offer_control(S,POLL_IGNORE_SENTIENCE_POTION)
|
||||
|
||||
/////////////////////
|
||||
|
||||
|
||||
@@ -28,39 +28,37 @@
|
||||
/// triggered on wield of two handed item
|
||||
/obj/item/broom/proc/on_wield(obj/item/source, mob/user)
|
||||
to_chat(user, "<span class='notice'>You brace the [src] against the ground in a firm sweeping stance.</span>")
|
||||
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/sweep)
|
||||
RegisterSignal(user, COMSIG_MOVABLE_PRE_MOVE, .proc/sweep)
|
||||
|
||||
/// triggered on unwield of two handed item
|
||||
/obj/item/broom/proc/on_unwield(obj/item/source, mob/user)
|
||||
UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
|
||||
UnregisterSignal(user, COMSIG_MOVABLE_PRE_MOVE)
|
||||
|
||||
/obj/item/broom/afterattack(atom/A, mob/user, proximity)
|
||||
. = ..()
|
||||
if(!proximity)
|
||||
return
|
||||
sweep(user, A, FALSE)
|
||||
sweep(user, A)
|
||||
|
||||
/obj/item/broom/proc/sweep(mob/user, atom/A, moving = TRUE)
|
||||
var/turf/target
|
||||
if (!moving)
|
||||
if (isturf(A))
|
||||
target = A
|
||||
else
|
||||
target = A.loc
|
||||
else
|
||||
target = user.loc
|
||||
if (!isturf(target))
|
||||
/obj/item/broom/proc/sweep(datum/source, atom/newLoc)
|
||||
if(!ismob(source) || !isturf(newLoc) || (get_dist(source, newLoc) > 1))
|
||||
return
|
||||
if (locate(/obj/structure/table) in target.contents)
|
||||
var/turf/target = newLoc
|
||||
var/atom/movable/AM
|
||||
var/sweep_dir = get_dir(source, target)
|
||||
if(!sweep_dir)
|
||||
return
|
||||
for(var/i in target.contents)
|
||||
AM = i
|
||||
if(AM.density) // eh good enough heuristic check
|
||||
return
|
||||
var/i = 0
|
||||
for(var/obj/item/garbage in target.contents)
|
||||
if(!garbage.anchored)
|
||||
garbage.Move(get_step(target, user.dir), user.dir)
|
||||
i++
|
||||
if(i >= 20)
|
||||
step(garbage, sweep_dir)
|
||||
if(++i > 20)
|
||||
break
|
||||
if(i >= 1)
|
||||
if(i)
|
||||
playsound(loc, 'sound/weapons/thudswoosh.ogg', 30, TRUE, -1)
|
||||
|
||||
/obj/item/broom/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J) //bless you whoever fixes this copypasta
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/obj/item/storage/portable_chem_mixer
|
||||
name = "Portable Chemical Mixer"
|
||||
desc = "A portable device that dispenses and mixes chemicals. All necessary reagents need to be supplied with beakers. A label indicates that a screwdriver is required to open it for refills. This device can be worn on a belt. The letters 'S&T' are imprinted on the side."
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "portablechemicalmixer_open"
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
custom_price = 2000
|
||||
custom_premium_price = 2000
|
||||
|
||||
var/obj/item/reagent_containers/beaker = null ///Creating an empty slot for a beaker that can be added to dispense into
|
||||
var/amount = 30 ///The amount of reagent that is to be dispensed currently
|
||||
|
||||
var/list/dispensable_reagents = list() ///List in which all currently dispensable reagents go
|
||||
|
||||
/obj/item/storage/portable_chem_mixer/ComponentInitialize()
|
||||
. = ..()
|
||||
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
|
||||
STR.max_combined_w_class = 200
|
||||
STR.max_items = 50
|
||||
STR.insert_preposition = "in"
|
||||
STR.can_hold = typecacheof(list(
|
||||
/obj/item/reagent_containers/glass/beaker,
|
||||
))
|
||||
|
||||
/obj/item/storage/portable_chem_mixer/Destroy()
|
||||
QDEL_NULL(beaker)
|
||||
return ..()
|
||||
|
||||
/obj/item/storage/portable_chem_mixer/ex_act(severity, target)
|
||||
if(severity < 3)
|
||||
..()
|
||||
|
||||
/obj/item/storage/portable_chem_mixer/attackby(obj/item/I, mob/user, params)
|
||||
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
|
||||
if (I.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, !locked)
|
||||
if (!locked)
|
||||
update_contents()
|
||||
if (locked)
|
||||
replace_beaker(user)
|
||||
update_icon()
|
||||
I.play_tool_sound(src, 50)
|
||||
return
|
||||
|
||||
else if (istype(I, /obj/item/reagent_containers) && !(I.item_flags & ABSTRACT) && I.is_open_container() && locked)
|
||||
var/obj/item/reagent_containers/B = I
|
||||
. = TRUE //no afterattack
|
||||
if(!user.transferItemToLoc(B, src))
|
||||
return
|
||||
replace_beaker(user, B)
|
||||
update_icon()
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Updates the contents of the portable chemical mixer
|
||||
*
|
||||
* A list of dispensable reagents is created by iterating through each source beaker in the portable chemical beaker and reading its contents
|
||||
*/
|
||||
/obj/item/storage/portable_chem_mixer/proc/update_contents()
|
||||
dispensable_reagents.Cut()
|
||||
|
||||
for (var/obj/item/reagent_containers/glass/beaker/B in contents)
|
||||
var/key = B.reagents.get_master_reagent_id()
|
||||
if (!(key in dispensable_reagents))
|
||||
dispensable_reagents[key] = list()
|
||||
dispensable_reagents[key]["reagents"] = list()
|
||||
dispensable_reagents[key]["reagents"] += B.reagents
|
||||
|
||||
return
|
||||
|
||||
/obj/item/storage/portable_chem_mixer/update_icon_state()
|
||||
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
|
||||
if (!locked)
|
||||
icon_state = "portablechemicalmixer_open"
|
||||
else if (beaker)
|
||||
icon_state = "portablechemicalmixer_full"
|
||||
else
|
||||
icon_state = "portablechemicalmixer_empty"
|
||||
|
||||
|
||||
/obj/item/storage/portable_chem_mixer/AltClick(mob/living/user)
|
||||
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
|
||||
if (!locked)
|
||||
return ..()
|
||||
if(!can_interact(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
|
||||
return
|
||||
replace_beaker(user)
|
||||
update_icon()
|
||||
|
||||
/**
|
||||
* Replaces the beaker of the portable chemical mixer with another beaker, or simply adds the new beaker if none is in currently
|
||||
*
|
||||
* Checks if a valid user and a valid new beaker exist and attempts to replace the current beaker in the portable chemical mixer with the one in hand. Simply places the new beaker in if no beaker is currently loaded
|
||||
* Arguments:
|
||||
* * mob/living/user - The user who is trying to exchange beakers
|
||||
* * obj/item/reagent_containers/new_beaker - The new beaker that the user wants to put into the device
|
||||
*/
|
||||
/obj/item/storage/portable_chem_mixer/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker)
|
||||
if(!user)
|
||||
return FALSE
|
||||
if(beaker)
|
||||
user.put_in_hands(beaker)
|
||||
beaker = null
|
||||
if(new_beaker)
|
||||
beaker = new_beaker
|
||||
return TRUE
|
||||
|
||||
/obj/item/storage/portable_chem_mixer/attack_hand(mob/user)
|
||||
if (loc != user)
|
||||
return ..()
|
||||
if(SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
|
||||
ui_interact(user)
|
||||
return
|
||||
|
||||
/obj/item/storage/portable_chem_mixer/attack_self(mob/user)
|
||||
if(loc == user)
|
||||
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
|
||||
if (locked)
|
||||
ui_interact(user)
|
||||
return
|
||||
else
|
||||
to_chat(user, "<span class='notice'>The portable chemical mixer is currently open and its contents can be accessed.</span>")
|
||||
return
|
||||
return
|
||||
|
||||
/obj/item/storage/portable_chem_mixer/MouseDrop(obj/over_object)
|
||||
. = ..()
|
||||
if(ismob(loc))
|
||||
var/mob/M = loc
|
||||
if(!M.incapacitated() && istype(over_object, /obj/screen/inventory/hand))
|
||||
var/obj/screen/inventory/hand/H = over_object
|
||||
M.putItemFromInventoryInHandIfPossible(src, H.held_index)
|
||||
|
||||
/obj/item/storage/portable_chem_mixer/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "PortableChemMixer", name)
|
||||
if(user.hallucinating())
|
||||
// to not ruin the immersion by constantly changing the fake chemicals
|
||||
ui.set_autoupdate(FALSE)
|
||||
ui.open()
|
||||
|
||||
/obj/item/storage/portable_chem_mixer/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["amount"] = amount
|
||||
data["isBeakerLoaded"] = beaker ? 1 : 0
|
||||
data["beakerCurrentVolume"] = beaker ? beaker.reagents.total_volume : null
|
||||
data["beakerMaxVolume"] = beaker ? beaker.volume : null
|
||||
data["beakerTransferAmounts"] = beaker ? beaker.possible_transfer_amounts : null
|
||||
var/chemicals[0]
|
||||
var/is_hallucinating = user.hallucinating()
|
||||
if(user.hallucinating())
|
||||
is_hallucinating = TRUE
|
||||
for(var/re in dispensable_reagents)
|
||||
var/value = dispensable_reagents[re]
|
||||
var/datum/reagent/temp = GLOB.chemical_reagents_list[re]
|
||||
if(temp)
|
||||
var/chemname = temp.name
|
||||
var/total_volume = 0
|
||||
for (var/datum/reagents/rs in value["reagents"])
|
||||
total_volume += rs.total_volume
|
||||
if(is_hallucinating && prob(5))
|
||||
chemname = "[pick_list_replacements("hallucination.json", "chemicals")]"
|
||||
chemicals.Add(list(list("title" = chemname, "id" = ckey(temp.name), "volume" = total_volume )))
|
||||
data["chemicals"] = chemicals
|
||||
var/beakerContents[0]
|
||||
if(beaker)
|
||||
for(var/datum/reagent/R in beaker.reagents.reagent_list)
|
||||
beakerContents.Add(list(list("name" = R.name, "id" = ckey(R.name), "volume" = R.volume))) // list in a list because Byond merges the first list...
|
||||
data["beakerContents"] = beakerContents
|
||||
return data
|
||||
|
||||
/obj/item/storage/portable_chem_mixer/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("amount")
|
||||
var/target = text2num(params["target"])
|
||||
amount = target
|
||||
. = TRUE
|
||||
if("dispense")
|
||||
var/reagent_name = params["reagent"]
|
||||
var/datum/reagent/reagent = GLOB.name2reagent[reagent_name]
|
||||
var/entry = dispensable_reagents[reagent]
|
||||
if(beaker)
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
var/actual = min(amount, 1000, R.maximum_volume - R.total_volume)
|
||||
// todo: add check if we have enough reagent left
|
||||
for (var/datum/reagents/source in entry["reagents"])
|
||||
var/to_transfer = min(source.total_volume, actual)
|
||||
source.trans_to(beaker, to_transfer)
|
||||
actual -= to_transfer
|
||||
if (actual <= 0)
|
||||
break
|
||||
. = TRUE
|
||||
if("remove")
|
||||
var/amount = text2num(params["amount"])
|
||||
beaker.reagents.remove_all(amount)
|
||||
. = TRUE
|
||||
if("eject")
|
||||
replace_beaker(usr)
|
||||
update_icon()
|
||||
. = TRUE
|
||||
@@ -729,10 +729,10 @@ GENETICS SCANNER
|
||||
to_chat(user, "<span class='notice'>[target] is empty!</span>")
|
||||
|
||||
if(cached_scan_results && cached_scan_results["fusion"]) //notify the user if a fusion reaction was detected
|
||||
var/fusion_power = round(cached_scan_results["fusion"], 0.01)
|
||||
var/tier = fusionpower2text(fusion_power)
|
||||
var/instability = round(cached_scan_results["fusion"], 0.01)
|
||||
var/tier = instability2text(instability)
|
||||
to_chat(user, "<span class='boldnotice'>Large amounts of free neutrons detected in the air indicate that a fusion reaction took place.</span>")
|
||||
to_chat(user, "<span class='notice'>Power of the last fusion reaction: [fusion_power]\n This power indicates it was a [tier]-tier fusion reaction.</span>")
|
||||
to_chat(user, "<span class='notice'>Instability of the last fusion reaction: [instability]\n This indicates it was [tier].</span>")
|
||||
return
|
||||
|
||||
/obj/item/analyzer/proc/scan_turf(mob/user, turf/location)
|
||||
@@ -783,10 +783,10 @@ GENETICS SCANNER
|
||||
to_chat(user, "<span class='info'>Temperature: [round(environment.return_temperature()-T0C, 0.01)] °C ([round(environment.return_temperature(), 0.01)] K)</span>")
|
||||
|
||||
if(cached_scan_results && cached_scan_results["fusion"]) //notify the user if a fusion reaction was detected
|
||||
var/fusion_power = round(cached_scan_results["fusion"], 0.01)
|
||||
var/tier = fusionpower2text(fusion_power)
|
||||
var/instability = round(cached_scan_results["fusion"], 0.01)
|
||||
var/tier = instability2text(instability)
|
||||
to_chat(user, "<span class='boldnotice'>Large amounts of free neutrons detected in the air indicate that a fusion reaction took place.</span>")
|
||||
to_chat(user, "<span class='notice'>Power of the last fusion reaction: [fusion_power]\n This power indicates it was a [tier]-tier fusion reaction.</span>")
|
||||
to_chat(user, "<span class='notice'>Instability of the last fusion reaction: [instability]\n This indicates it was [tier].</span>")
|
||||
|
||||
/obj/item/analyzer/ranged
|
||||
desc = "A hand-held scanner which uses advanced spectroscopy and infrared readings to analyze gases as a distance. Alt-Click to use the built in barometer function."
|
||||
@@ -992,4 +992,4 @@ GENETICS SCANNER
|
||||
#undef SCANMODE_CHEMICAL
|
||||
#undef SCANMODE_WOUND
|
||||
#undef SCANNER_CONDENSED
|
||||
#undef SCANNER_VERBOSE
|
||||
#undef SCANNER_VERBOSE
|
||||
|
||||
@@ -234,6 +234,9 @@
|
||||
/obj/item/melee/rapier/attack(mob/living/target, mob/living/user)
|
||||
. = ..()
|
||||
if(iscarbon(target))
|
||||
if(HAS_TRAIT(user, TRAIT_PACIFISM))
|
||||
visible_message("<span class='warning'>[user] gently taps [target] with [src].</span>",null,null,COMBAT_MESSAGE_RANGE)
|
||||
log_combat(user, target, "slept", src)
|
||||
var/mob/living/carbon/H = target
|
||||
H.Dizzy(10)
|
||||
H.adjustStaminaLoss(30)
|
||||
|
||||
+13
-11
@@ -304,18 +304,20 @@
|
||||
/obj/proc/reskin_obj(mob/M)
|
||||
if(!LAZYLEN(unique_reskin))
|
||||
return
|
||||
var/dat = "<b>Reskin options for [name]:</b>\n"
|
||||
for(var/V in unique_reskin)
|
||||
var/output = icon2html(src, M, unique_reskin[V])
|
||||
dat += "[V]: <span class='reallybig'>[output]</span>\n"
|
||||
to_chat(M, dat)
|
||||
|
||||
var/choice = input(M, always_reskinnable ? "Choose the a reskin for [src]" : "Warning, you can only reskin [src] once!","Reskin Object") as null|anything in unique_reskin
|
||||
if(QDELETED(src) || !choice || (current_skin && !always_reskinnable) || M.incapacitated() || !in_range(M,src) || !unique_reskin[choice] || unique_reskin[choice] == current_skin)
|
||||
return
|
||||
current_skin = choice
|
||||
var/list/skins = list()
|
||||
for(var/S in unique_reskin)
|
||||
skins[S] = image(icon = icon, icon_state = unique_reskin[S])
|
||||
var/choice = show_radial_menu(M, src, skins, custom_check = CALLBACK(src, .proc/check_skinnable, M), radius = 40, require_near = TRUE)
|
||||
if(!choice)
|
||||
return FALSE
|
||||
icon_state = unique_reskin[choice]
|
||||
to_chat(M, "[src] is now skinned as '[choice]'.")
|
||||
current_skin = choice
|
||||
return
|
||||
|
||||
/obj/proc/check_skinnable(/mob/M)
|
||||
if(current_skin || !always_reskinnable)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/update_overlays()
|
||||
. = ..()
|
||||
|
||||
@@ -20,8 +20,6 @@ GLOBAL_LIST(topic_status_cache)
|
||||
|
||||
log_world("World loaded at [TIME_STAMP("hh:mm:ss", FALSE)]!")
|
||||
|
||||
SetupExternalRSC()
|
||||
|
||||
GLOB.config_error_log = GLOB.world_manifest_log = GLOB.world_pda_log = GLOB.world_job_debug_log = GLOB.sql_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = "data/logs/config_error.[GUID()].log" //temporary file used to record errors with loading config, moved to log directory once logging is set bl
|
||||
|
||||
make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once)
|
||||
@@ -87,17 +85,6 @@ GLOBAL_LIST(topic_status_cache)
|
||||
#endif
|
||||
SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, /proc/addtimer, cb, 10 SECONDS))
|
||||
|
||||
/world/proc/SetupExternalRSC()
|
||||
#if (PRELOAD_RSC == 0)
|
||||
GLOB.external_rsc_urls = world.file2list("[global.config.directory]/external_rsc_urls.txt","\n")
|
||||
var/i=1
|
||||
while(i<=GLOB.external_rsc_urls.len)
|
||||
if(GLOB.external_rsc_urls[i])
|
||||
i++
|
||||
else
|
||||
GLOB.external_rsc_urls.Cut(i,i+1)
|
||||
#endif
|
||||
|
||||
/world/proc/SetupLogs()
|
||||
var/override_dir = params[OVERRIDE_LOG_DIRECTORY_PARAMETER]
|
||||
if(!override_dir)
|
||||
|
||||
Reference in New Issue
Block a user