mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 18:53:06 +00:00
Merge branch 'dev' of https://github.com/Baystation12/Baystation12 into 11/6/2015_neerti_breaks_everything_bay_merge
Conflicts: .travis.yml code/_helpers/lists.dm code/game/objects/structures/crates_lockers/closets/secure/engineering.dm code/global.dm code/modules/client/preferences.dm code/modules/client/preferences_savefile.dm code/modules/reagents/dispenser/dispenser2.dm polaris.dme
This commit is contained in:
@@ -1,13 +1,9 @@
|
||||
/*
|
||||
|
||||
Making Bombs with ZAS:
|
||||
Make burny fire with lots of burning
|
||||
Draw off 5000K gas from burny fire
|
||||
Separate gas into oxygen and phoron components
|
||||
Obtain phoron and oxygen tanks filled up about 50-75% with normal-temp gas
|
||||
Fill rest with super hot gas from separated canisters, they should be about 125C now.
|
||||
Attach to transfer valve and open. BOOM.
|
||||
|
||||
Get gas to react in an air tank so that it gains pressure. If it gains enough pressure, it goes boom.
|
||||
The more pressure, the more boom.
|
||||
If it gains pressure too slowly, it may leak or just rupture instead of exploding.
|
||||
*/
|
||||
|
||||
//#define FIREDBG
|
||||
@@ -268,16 +264,16 @@ turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0)
|
||||
//determine how far the reaction can progress
|
||||
var/reaction_limit = min(total_oxidizers*(FIRE_REACTION_FUEL_AMOUNT/FIRE_REACTION_OXIDIZER_AMOUNT), total_fuel) //stoichiometric limit
|
||||
|
||||
//calculate the firelevel.
|
||||
var/firelevel = calculate_firelevel(total_fuel, total_oxidizers, reaction_limit)
|
||||
var/firelevel_ratio = firelevel / vsc.fire_firelevel_multiplier
|
||||
|
||||
//vapour fuels are extremely volatile! The reaction progress is a percentage of the total fuel (similar to old zburn).)
|
||||
var/gas_firelevel = calculate_firelevel(gas_fuel, total_oxidizers, reaction_limit, volume*group_multiplier) / vsc.fire_firelevel_multiplier
|
||||
var/min_burn = 0.30*volume*group_multiplier/CELL_VOLUME //in moles - so that fires with very small gas concentrations burn out fast
|
||||
var/gas_reaction_progress = min(max(min_burn, firelevel_ratio*gas_fuel)*FIRE_GAS_BURNRATE_MULT, gas_fuel)
|
||||
var/gas_reaction_progress = min(max(min_burn, gas_firelevel*gas_fuel)*FIRE_GAS_BURNRATE_MULT, gas_fuel)
|
||||
|
||||
//liquid fuels are not as volatile, and the reaction progress depends on the size of the area that is burning. Limit the burn rate to a certain amount per area.
|
||||
var/liquid_reaction_progress = min((firelevel_ratio*0.2 + 0.05)*fuel_area*FIRE_LIQUID_BURNRATE_MULT, liquid_fuel)
|
||||
var/liquid_firelevel = calculate_firelevel(liquid_fuel, total_oxidizers, reaction_limit, 0) / vsc.fire_firelevel_multiplier
|
||||
var/liquid_reaction_progress = min((liquid_firelevel*0.2 + 0.05)*fuel_area*FIRE_LIQUID_BURNRATE_MULT, liquid_fuel)
|
||||
|
||||
var/firelevel = (gas_fuel*gas_firelevel + liquid_fuel*liquid_firelevel)/total_fuel
|
||||
|
||||
var/total_reaction_progress = gas_reaction_progress + liquid_reaction_progress
|
||||
var/used_fuel = min(total_reaction_progress, reaction_limit)
|
||||
@@ -286,7 +282,7 @@ turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0)
|
||||
#ifdef FIREDBG
|
||||
log_debug("gas_fuel = [gas_fuel], liquid_fuel = [liquid_fuel], total_oxidizers = [total_oxidizers]")
|
||||
log_debug("fuel_area = [fuel_area], total_fuel = [total_fuel], reaction_limit = [reaction_limit]")
|
||||
log_debug("firelevel -> [firelevel] / [vsc.fire_firelevel_multiplier]")
|
||||
log_debug("firelevel -> [firelevel] (gas: [gas_firelevel], liquid: [liquid_firelevel])")
|
||||
log_debug("liquid_reaction_progress = [liquid_reaction_progress]")
|
||||
log_debug("gas_reaction_progress = [gas_reaction_progress]")
|
||||
log_debug("total_reaction_progress = [total_reaction_progress]")
|
||||
@@ -315,13 +311,13 @@ turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0)
|
||||
|
||||
//calculate the energy produced by the reaction and then set the new temperature of the mix
|
||||
temperature = (starting_energy + vsc.fire_fuel_energy_release * (used_gas_fuel + used_liquid_fuel)) / heat_capacity()
|
||||
update_values()
|
||||
|
||||
#ifdef FIREDBG
|
||||
log_debug("used_gas_fuel = [used_gas_fuel]; used_liquid_fuel = [used_liquid_fuel]; total = [used_fuel]")
|
||||
log_debug("new temperature = [temperature]")
|
||||
log_debug("new temperature = [temperature]; new pressure = [return_pressure()]")
|
||||
#endif
|
||||
|
||||
update_values()
|
||||
return firelevel
|
||||
|
||||
datum/gas_mixture/proc/check_recombustability(list/fuel_objs)
|
||||
@@ -363,27 +359,31 @@ datum/gas_mixture/proc/check_recombustability(list/fuel_objs)
|
||||
break
|
||||
|
||||
//returns a value between 0 and vsc.fire_firelevel_multiplier
|
||||
/datum/gas_mixture/proc/calculate_firelevel(total_fuel, total_oxidizers, reaction_limit)
|
||||
/datum/gas_mixture/proc/calculate_firelevel(total_fuel, total_oxidizers, reaction_limit, gas_volume)
|
||||
//Calculates the firelevel based on one equation instead of having to do this multiple times in different areas.
|
||||
var/firelevel = 0
|
||||
|
||||
var/total_combustables = (total_fuel + total_oxidizers)
|
||||
var/active_combustables = (FIRE_REACTION_OXIDIZER_AMOUNT/FIRE_REACTION_FUEL_AMOUNT + 1)*reaction_limit
|
||||
|
||||
if(total_combustables > 0)
|
||||
//slows down the burning when the concentration of the reactants is low
|
||||
var/dampening_multiplier = min(1, reaction_limit / (total_moles/group_multiplier))
|
||||
var/damping_multiplier = min(1, active_combustables / (total_moles/group_multiplier))
|
||||
|
||||
//weight the damping mult so that it only really brings down the firelevel when the ratio is closer to 0
|
||||
damping_multiplier = 2*damping_multiplier - (damping_multiplier*damping_multiplier)
|
||||
|
||||
//calculates how close the mixture of the reactants is to the optimum
|
||||
//fires burn better when there is more oxidizer -- too much fuel will choke them out a bit, reducing firelevel.
|
||||
//fires burn better when there is more oxidizer -- too much fuel will choke the fire out a bit, reducing firelevel.
|
||||
var/mix_multiplier = 1 / (1 + (5 * ((total_fuel / total_combustables) ** 2)))
|
||||
|
||||
#ifdef FIREDBG
|
||||
ASSERT(dampening_multiplier <= 1)
|
||||
ASSERT(damping_multiplier <= 1)
|
||||
ASSERT(mix_multiplier <= 1)
|
||||
#endif
|
||||
|
||||
//toss everything together -- should produce a value between 0 and fire_firelevel_multiplier
|
||||
firelevel = vsc.fire_firelevel_multiplier * mix_multiplier * dampening_multiplier
|
||||
firelevel = vsc.fire_firelevel_multiplier * mix_multiplier * damping_multiplier
|
||||
|
||||
return max( 0, firelevel)
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ var/global/vs_control/vsc = new
|
||||
var/fire_firelevel_multiplier_NAME = "Fire - Firelevel Constant"
|
||||
var/fire_firelevel_multiplier_DESC = "Multiplied by the equation for firelevel, affects mainly the extingiushing of fires."
|
||||
|
||||
var/fire_fuel_energy_release = 397000
|
||||
//Note that this parameter and the phoron heat capacity have a significant impact on TTV yield.
|
||||
var/fire_fuel_energy_release = 866000 //J/mol. Adjusted to compensate for fire energy release being fixed, was 397000
|
||||
var/fire_fuel_energy_release_NAME = "Fire - Fuel energy release"
|
||||
var/fire_fuel_energy_release_DESC = "The energy in joule released when burning one mol of a burnable substance"
|
||||
|
||||
|
||||
@@ -59,15 +59,15 @@
|
||||
|
||||
//These control the speed at which fire burns
|
||||
#define FIRE_GAS_BURNRATE_MULT 1
|
||||
#define FIRE_LIQUID_BURNRATE_MULT 1
|
||||
#define FIRE_LIQUID_BURNRATE_MULT 0.225
|
||||
|
||||
//If the fire is burning slower than this rate then the reaction is going too slow to be self sustaining and the fire burns itself out.
|
||||
//This ensures that fires don't grind to a near-halt while still remaining active forever.
|
||||
#define FIRE_GAS_MIN_BURNRATE 0.01
|
||||
#define FIRE_LIQUD_MIN_BURNRATE 0.01
|
||||
#define FIRE_LIQUD_MIN_BURNRATE 0.0025
|
||||
|
||||
//How many moles of fuel are contained within one solid/liquid fuel volume unit
|
||||
#define LIQUIDFUEL_AMOUNT_TO_MOL 1 //mol/volume unit
|
||||
#define LIQUIDFUEL_AMOUNT_TO_MOL 0.45 //mol/volume unit
|
||||
|
||||
// XGM gas flags.
|
||||
#define XGM_GAS_FUEL 1
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
|
||||
// Click cooldown
|
||||
#define DEFAULT_ATTACK_COOLDOWN 8 //Default timeout for aggressive actions
|
||||
#define DEFAULT_QUICK_COOLDOWN 4
|
||||
|
||||
|
||||
#define MIN_SUPPLIED_LAW_NUMBER 15
|
||||
@@ -114,3 +115,13 @@
|
||||
#define MOB_SMALL 10
|
||||
#define MOB_TINY 5
|
||||
#define MOB_MINISCULE 1
|
||||
|
||||
#define TINT_NONE 0
|
||||
#define TINT_MODERATE 1
|
||||
#define TINT_HEAVY 2
|
||||
#define TINT_BLIND 3
|
||||
|
||||
#define FLASH_PROTECTION_REDUCED -1
|
||||
#define FLASH_PROTECTION_NONE 0
|
||||
#define FLASH_PROTECTION_MODERATE 1
|
||||
#define FLASH_PROTECTION_MAJOR 2
|
||||
|
||||
21
code/_helpers/areas.dm
Normal file
21
code/_helpers/areas.dm
Normal file
@@ -0,0 +1,21 @@
|
||||
//Takes: Area type as text string or as typepath OR an instance of the area.
|
||||
//Returns: A list of all turfs in areas of that type in the world.
|
||||
/proc/get_area_turfs(var/areatype, var/list/predicates)
|
||||
if(!areatype) return null
|
||||
if(istext(areatype)) areatype = text2path(areatype)
|
||||
if(isarea(areatype))
|
||||
var/area/areatemp = areatype
|
||||
areatype = areatemp.type
|
||||
|
||||
var/list/turfs = new/list()
|
||||
for(var/areapath in typesof(areatype))
|
||||
var/area/A = locate(areapath)
|
||||
for(var/turf/T in A.contents)
|
||||
if(!predicates || all_predicates_true(T, predicates))
|
||||
turfs += T
|
||||
return turfs
|
||||
|
||||
/proc/pick_area_turf(var/areatype, var/list/predicates)
|
||||
var/list/turfs = get_area_turfs(areatype, predicates)
|
||||
if(turfs && turfs.len)
|
||||
return pick(turfs)
|
||||
14
code/_helpers/functional.dm
Normal file
14
code/_helpers/functional.dm
Normal file
@@ -0,0 +1,14 @@
|
||||
/proc/all_predicates_true(var/input, var/list/predicates)
|
||||
for(var/i = 1 to predicates.len)
|
||||
if(!call(predicates[i])(input))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/proc/any_predicate_true(var/input, var/list/predicates)
|
||||
if(!predicates.len)
|
||||
return TRUE
|
||||
|
||||
for(var/i = 1 to predicates.len)
|
||||
if(call(predicates[i])(input))
|
||||
return TRUE
|
||||
return FALSE
|
||||
@@ -71,6 +71,12 @@ proc/isemptylist(list/list)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/proc/instances_of_type_in_list(var/atom/A, var/list/L)
|
||||
var/instances = 0
|
||||
for(var/type in L)
|
||||
if(istype(A, type))
|
||||
instances++
|
||||
return instances
|
||||
//Checks for specific paths in a list
|
||||
/proc/is_path_in_list(var/atom/A, var/list/L)
|
||||
for(var/path in L)
|
||||
@@ -78,11 +84,11 @@ proc/isemptylist(list/list)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Empties the list by setting the length to 0. Hopefully the elements get garbage collected
|
||||
proc/clearlist(list/list)
|
||||
if(istype(list))
|
||||
list.len = 0
|
||||
return
|
||||
|
||||
//Empties the list by .Cut(). Setting lenght = 0 has been confirmed to leak references.
|
||||
proc/clearlist(var/list/L)
|
||||
if(islist(L))
|
||||
L.Cut()
|
||||
|
||||
//Removes any null entries from the list
|
||||
proc/listclearnulls(list/list)
|
||||
|
||||
@@ -32,3 +32,12 @@
|
||||
if(!available_turfs.len)
|
||||
available_turfs = start_turfs
|
||||
return pick(available_turfs)
|
||||
|
||||
/proc/turf_contains_dense_objects(var/turf/T)
|
||||
return T.contains_dense_objects()
|
||||
|
||||
/proc/not_turf_contains_dense_objects(var/turf/T)
|
||||
return !turf_contains_dense_objects(T)
|
||||
|
||||
/proc/is_station_turf(var/turf/T)
|
||||
return T && isStationLevel(T.z)
|
||||
|
||||
@@ -558,7 +558,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
|
||||
var/y = min(world.maxy, max(1, A.y + dy))
|
||||
return locate(x,y,A.z)
|
||||
|
||||
//Makes sure MIDDLE is between LOW and HIGH. If not, it adjusts it. Returns the adjusted value.
|
||||
//Makes sure MIDDLE is between LOW and HIGH. If not, it adjusts it. Returns the adjusted value. Lower bound takes priority.
|
||||
/proc/between(var/low, var/middle, var/high)
|
||||
return max(min(middle, high), low)
|
||||
|
||||
@@ -718,21 +718,6 @@ proc/GaussRandRound(var/sigma,var/roundto)
|
||||
if(istype(N, areatype)) areas += N
|
||||
return areas
|
||||
|
||||
//Takes: Area type as text string or as typepath OR an instance of the area.
|
||||
//Returns: A list of all turfs in areas of that type of that type in the world.
|
||||
/proc/get_area_turfs(var/areatype)
|
||||
if(!areatype) return null
|
||||
if(istext(areatype)) areatype = text2path(areatype)
|
||||
if(isarea(areatype))
|
||||
var/area/areatemp = areatype
|
||||
areatype = areatemp.type
|
||||
|
||||
var/list/turfs = new/list()
|
||||
for(var/area/N in world)
|
||||
if(istype(N, areatype))
|
||||
for(var/turf/T in N) turfs += T
|
||||
return turfs
|
||||
|
||||
//Takes: Area type as text string or as typepath OR an instance of the area.
|
||||
//Returns: A list of all atoms (objs, turfs, mobs) in areas of that type of that type in the world.
|
||||
/proc/get_area_all_atoms(var/areatype)
|
||||
|
||||
@@ -1,8 +1,33 @@
|
||||
/*
|
||||
=== Item Click Call Sequences ===
|
||||
These are the default click code call sequences used when clicking on stuff with an item.
|
||||
|
||||
Atoms:
|
||||
|
||||
mob/ClickOn() calls the item's resolve_attackby() proc.
|
||||
item/resolve_attackby() calls the target atom's attackby() proc.
|
||||
|
||||
Mobs:
|
||||
|
||||
mob/living/attackby() after checking for surgery, calls the item's attack() proc.
|
||||
item/attack() generates attack logs, sets click cooldown and calls the mob's attacked_with_item() proc. If you override this, consider whether you need to set a click cooldown, play attack animations, and generate logs yourself.
|
||||
mob/attacked_with_item() should then do mob-type specific stuff (like determining hit/miss, handling shields, etc) and then possibly call the item's apply_hit_effect() proc to actually apply the effects of being hit.
|
||||
|
||||
Item Hit Effects:
|
||||
|
||||
item/apply_hit_effect() can be overriden to do whatever you want. However "standard" physical damage based weapons should make use of the target mob's hit_with_weapon() proc to
|
||||
avoid code duplication. This includes items that may sometimes act as a standard weapon in addition to having other effects (e.g. stunbatons on harm intent).
|
||||
*/
|
||||
|
||||
// Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown.
|
||||
/obj/item/proc/attack_self(mob/user)
|
||||
return
|
||||
|
||||
//I would prefer to rename this to attack(), but that would involve touching hundreds of files.
|
||||
/obj/item/proc/resolve_attackby(atom/A, mob/user)
|
||||
add_fingerprint(user)
|
||||
return A.attackby(src, user)
|
||||
|
||||
// No comment
|
||||
/atom/proc/attackby(obj/item/W, mob/user)
|
||||
return
|
||||
@@ -12,29 +37,23 @@
|
||||
visible_message("<span class='danger'>[src] has been hit by [user] with [W].</span>")
|
||||
|
||||
/mob/living/attackby(obj/item/I, mob/user)
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
if(istype(I) && ismob(user))
|
||||
I.attack(src, user)
|
||||
|
||||
if(!ismob(user))
|
||||
return 0
|
||||
if(can_operate(src) && do_surgery(src,user,I)) //Surgery
|
||||
return 1
|
||||
return I.attack(src, user, user.zone_sel.selecting)
|
||||
|
||||
// Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person.
|
||||
// Click parameters is the params string from byond Click() code, see that documentation.
|
||||
/obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
|
||||
return
|
||||
|
||||
//TODO: refactor mob attack code.
|
||||
/*
|
||||
Busy writing something else that I don't want to get mixed up in a general attack code, and I don't want to forget this so leaving a note here.
|
||||
leave attackby() as handling the general case of "using an item on a mob"
|
||||
attackby() will decide to call attacked_by() or not.
|
||||
attacked_by() will be made a living level proc and handle the specific case of "attacking with an item to cause harm"
|
||||
attacked_by() will then call attack() so that stunbatons and other weapons that have special attack effects can do their thing.
|
||||
attacked_by() will handle hitting/missing/logging as it does now, and will call attack() to apply the attack effects (damage) instead of the other way around (as it is now).
|
||||
*/
|
||||
|
||||
/obj/item/proc/attack(mob/living/M as mob, mob/living/user as mob, def_zone)
|
||||
|
||||
if(!istype(M) || (can_operate(M) && do_surgery(M,user,src))) return 0
|
||||
//I would prefer to rename this attack_as_weapon(), but that would involve touching hundreds of files.
|
||||
/obj/item/proc/attack(mob/living/M, mob/living/user, var/target_zone)
|
||||
if(!force || (flags & NOBLUDGEON))
|
||||
return 0
|
||||
if(M == user && user.a_intent != I_HURT)
|
||||
return 0
|
||||
|
||||
/////////////////////////
|
||||
user.lastattacked = M
|
||||
@@ -46,49 +65,22 @@ attacked_by() will handle hitting/missing/logging as it does now, and will call
|
||||
msg_admin_attack("[key_name(user)] attacked [key_name(M)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" )
|
||||
/////////////////////////
|
||||
|
||||
// Attacking someone with a weapon while they are neck-grabbed
|
||||
if(user.a_intent == I_HURT)
|
||||
for(var/obj/item/weapon/grab/G in M.grabbed_by)
|
||||
if(G.assailant == user && G.state >= GRAB_NECK)
|
||||
M.attack_throat(src, G, user)
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.do_attack_animation(M)
|
||||
|
||||
var/hit_zone = M.resolve_item_attack(src, user, target_zone)
|
||||
if(hit_zone)
|
||||
apply_hit_effect(M, user, hit_zone)
|
||||
|
||||
return 1
|
||||
|
||||
//Called when a weapon is used to make a successful melee attack on a mob. Returns the blocked result
|
||||
/obj/item/proc/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone)
|
||||
if(hitsound)
|
||||
playsound(loc, hitsound, 50, 1, -1)
|
||||
|
||||
var/power = force
|
||||
if(HULK in user.mutations)
|
||||
power *= 2
|
||||
return target.hit_with_weapon(src, user, power, hit_zone)
|
||||
|
||||
// TODO: needs to be refactored into a mob/living level attacked_by() proc. ~Z
|
||||
user.do_attack_animation(M)
|
||||
if(istype(M, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = M
|
||||
|
||||
// Handle striking to cripple.
|
||||
var/dislocation_str
|
||||
if(user.a_intent == I_DISARM)
|
||||
dislocation_str = H.attack_joint(src, user, def_zone)
|
||||
if(H.attacked_by(src, user, def_zone) && hitsound)
|
||||
playsound(loc, hitsound, 50, 1, -1)
|
||||
spawn(1) //ugh I hate this but I don't want to root through human attack procs to print it after this call resolves.
|
||||
if(dislocation_str) user.visible_message("<span class='danger'>[dislocation_str]</span>")
|
||||
return 1
|
||||
return 0
|
||||
else
|
||||
if(attack_verb.len)
|
||||
user.visible_message("<span class='danger'>[M] has been [pick(attack_verb)] with [src] by [user]!</span>")
|
||||
else
|
||||
user.visible_message("<span class='danger'>[M] has been attacked with [src] by [user]!</span>")
|
||||
|
||||
if (hitsound)
|
||||
playsound(loc, hitsound, 50, 1, -1)
|
||||
switch(damtype)
|
||||
if("brute")
|
||||
M.take_organ_damage(power)
|
||||
if(prob(33)) // Added blood for whacking non-humans too
|
||||
var/turf/simulated/location = get_turf(M)
|
||||
if(istype(location)) location.add_blood_floor(M)
|
||||
if("fire")
|
||||
if (!(COLD_RESISTANCE in M.mutations))
|
||||
M.take_organ_damage(0, power)
|
||||
M << "Aargh it burns!"
|
||||
M.updatehealth()
|
||||
add_fingerprint(user)
|
||||
return 1
|
||||
|
||||
75
code/datums/category.dm
Normal file
75
code/datums/category.dm
Normal file
@@ -0,0 +1,75 @@
|
||||
/**********************
|
||||
* Category Collection *
|
||||
**********************/
|
||||
/datum/category_collection
|
||||
var/category_group_type // The type of categories to initialize
|
||||
var/list/datum/category_group/categories // The list of initialized categories
|
||||
|
||||
/datum/category_collection/New()
|
||||
..()
|
||||
categories = new()
|
||||
for(var/category_type in typesof(category_group_type))
|
||||
var/datum/category_group/category = category_type
|
||||
if(initial(category.name))
|
||||
category = new category(src)
|
||||
categories += category
|
||||
categories = dd_sortedObjectList(categories)
|
||||
|
||||
/datum/category_collection/Destroy()
|
||||
for(var/category in categories)
|
||||
qdel(category)
|
||||
categories.Cut()
|
||||
return ..()
|
||||
|
||||
/******************
|
||||
* Category Groups *
|
||||
******************/
|
||||
/datum/category_group
|
||||
var/name = ""
|
||||
var/category_item_type // The type of items to initialize
|
||||
var/list/datum/category_item/items // The list of initialized items
|
||||
var/datum/category_collection/collection // The collection this group belongs to
|
||||
|
||||
/datum/category_group/New(var/datum/category_collection/cc)
|
||||
..()
|
||||
collection = cc
|
||||
items = new()
|
||||
|
||||
for(var/item_type in typesof(category_item_type))
|
||||
var/datum/category_item/item = item_type
|
||||
if(initial(item.name))
|
||||
item = new item(src)
|
||||
items += item
|
||||
|
||||
// For whatever reason dd_insertObjectList(items, item) doesn't insert in the correct order
|
||||
// If you change this, confirm that character setup doesn't become completely unordered.
|
||||
items = dd_sortedObjectList(items)
|
||||
|
||||
/datum/category_group/Destroy()
|
||||
for(var/item in items)
|
||||
qdel(item)
|
||||
items.Cut()
|
||||
collection = null
|
||||
return ..()
|
||||
|
||||
datum/category_group/dd_SortValue()
|
||||
return name
|
||||
|
||||
|
||||
/*****************
|
||||
* Category Items *
|
||||
*****************/
|
||||
/datum/category_item
|
||||
var/name = ""
|
||||
var/list/datum/category_group/category // The group this item belongs to
|
||||
|
||||
/datum/category_item/New(var/datum/category_group/cg)
|
||||
..()
|
||||
category = cg
|
||||
|
||||
/datum/category_item/Destroy()
|
||||
category = null
|
||||
return ..()
|
||||
|
||||
datum/category_item/dd_SortValue()
|
||||
return name
|
||||
@@ -53,9 +53,12 @@
|
||||
affected_mob.updatehealth()
|
||||
if(prob(40))
|
||||
if(gibbed != 0) return 0
|
||||
var/turf/T = find_loc(affected_mob)
|
||||
gibs(T)
|
||||
src.cure(0)
|
||||
gibbed = 1
|
||||
affected_mob:Alienize()
|
||||
|
||||
var/mob/living/carbon/human/H = affected_mob
|
||||
if(istype(H))
|
||||
var/turf/origin = find_loc(affected_mob)
|
||||
gibs(origin)
|
||||
H.set_species("Xenomorph [pick(list("Hunter","Sentinel","Drone"))]")
|
||||
return
|
||||
affected_mob.gib()
|
||||
@@ -41,7 +41,7 @@ var/const/AIRLOCK_WIRE_LIGHT = 2048
|
||||
(A.locked ? "The door bolts have fallen!" : "The door bolts look up."),
|
||||
((A.lights && haspower) ? "The door bolt lights are on." : "The door bolt lights are off!"),
|
||||
((haspower) ? "The test light is on." : "The test light is off!"),
|
||||
((A.backupPowerCablesCut()) ? "The backup power light is off!" : "The backup power light is on."),
|
||||
((A.backup_power_lost_until) ? "The backup power light is off!" : "The backup power light is on."),
|
||||
((A.aiControlDisabled==0 && !A.emagged && haspower)? "The 'AI control allowed' light is on." : "The 'AI control allowed' light is off."),
|
||||
((A.safe==0 && haspower)? "The 'Check Wiring' light is on." : "The 'Check Wiring' light is off."),
|
||||
((A.normalspeed==0 && haspower)? "The 'Check Timing Mechanism' light is on." : "The 'Check Timing Mechanism' light is off."),
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
/decl/xgm_gas/phoron
|
||||
id = "phoron"
|
||||
name = "Phoron"
|
||||
|
||||
//Note that this has a significant impact on TTV yield.
|
||||
//Because it is so high, any leftover phoron soaks up a lot of heat and drops the yield pressure.
|
||||
specific_heat = 200 // J/(mol*K)
|
||||
|
||||
//Hypothetical group 14 (same as carbon), period 8 element.
|
||||
|
||||
@@ -61,7 +61,7 @@ proc/can_process_hud(var/mob/M)
|
||||
return 1
|
||||
|
||||
//Deletes the current HUD images so they can be refreshed with new ones.
|
||||
mob/proc/handle_regular_hud_updates() //Used in the life.dm of mobs that can use HUDs.
|
||||
mob/proc/handle_hud_glasses() //Used in the life.dm of mobs that can use HUDs.
|
||||
if(client)
|
||||
for(var/image/hud in client.images)
|
||||
if(copytext(hud.icon_state,1,4) == "hud")
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#define ANTAG_RANDSPAWN 256 // Potentially randomly spawns due to events.
|
||||
#define ANTAG_VOTABLE 512 // Can be voted as an additional antagonist before roundstart.
|
||||
#define ANTAG_SET_APPEARANCE 1024 // Causes antagonists to use an appearance modifier on spawn.
|
||||
#define ANTAG_RANDOM_EXCEPTED 2048 // If a game mode randomly selects antag types, antag types with this flag should be excluded.
|
||||
|
||||
// Globals.
|
||||
var/global/list/all_antag_types = list()
|
||||
|
||||
@@ -11,6 +11,11 @@ var/datum/antagonist/xenos/xenomorphs
|
||||
welcome_text = "Hiss! You are a larval alien. Hide and bide your time until you are ready to evolve."
|
||||
antaghud_indicator = "hudalien"
|
||||
|
||||
faction_role_text = "Xenomorph Thrall"
|
||||
faction_descriptor = "Hive"
|
||||
faction_welcome = "Your will is ripped away as your humanity merges with the xenomorph overmind. You are now \
|
||||
a thrall to the queen and her brood. Obey their instructions without question. Serve the hive."
|
||||
|
||||
hard_cap = 5
|
||||
hard_cap_round = 8
|
||||
initial_spawn_req = 4
|
||||
|
||||
@@ -86,7 +86,8 @@
|
||||
/datum/antagonist/proc/tick()
|
||||
return 1
|
||||
|
||||
/datum/antagonist/proc/get_candidates(var/ghosts_only)
|
||||
// Get the raw list of potential players.
|
||||
/datum/antagonist/proc/build_candidate_list(var/ghosts_only)
|
||||
candidates = list() // Clear.
|
||||
|
||||
// Prune restricted status. Broke it up for readability.
|
||||
@@ -108,46 +109,57 @@
|
||||
return candidates
|
||||
|
||||
/datum/antagonist/proc/attempt_random_spawn()
|
||||
update_current_antag_max()
|
||||
build_candidate_list(flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB))
|
||||
attempt_spawn()
|
||||
finalize_spawn()
|
||||
|
||||
/datum/antagonist/proc/attempt_late_spawn(var/datum/mind/player)
|
||||
/datum/antagonist/proc/attempt_auto_spawn()
|
||||
if(!can_late_spawn())
|
||||
return 0
|
||||
if(!istype(player))
|
||||
var/list/players = get_candidates(is_latejoin_template())
|
||||
if(players && players.len)
|
||||
player = pick(players)
|
||||
if(!istype(player))
|
||||
message_admins("AUTO[uppertext(ticker.mode.name)]: Failed to find a candidate for [role_text].")
|
||||
return 0
|
||||
player.current << "<span class='danger'><i>You have been selected this round as an antagonist!</i></span>"
|
||||
message_admins("AUTO[uppertext(ticker.mode.name)]: Selected [player] as a [role_text].")
|
||||
if(istype(player.current, /mob/dead))
|
||||
create_default(player.current)
|
||||
else
|
||||
add_antagonist(player,0,0,0,1,1)
|
||||
return 1
|
||||
|
||||
/datum/antagonist/proc/build_candidate_list(var/ghosts_only)
|
||||
// Get the raw list of potential players.
|
||||
update_current_antag_max()
|
||||
candidates = get_candidates(ghosts_only)
|
||||
var/active_antags = get_active_antag_count()
|
||||
log_debug("[uppertext(id)]: Found [active_antags]/[cur_max] active [role_text_plural].")
|
||||
|
||||
if(active_antags >= cur_max)
|
||||
log_debug("Could not auto-spawn a [role_text], active antag limit reached.")
|
||||
return 0
|
||||
|
||||
build_candidate_list(flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB))
|
||||
if(!candidates.len)
|
||||
log_debug("Could not auto-spawn a [role_text], no candidates found.")
|
||||
return 0
|
||||
|
||||
attempt_spawn(1) //auto-spawn antags one at a time
|
||||
if(!pending_antagonists.len)
|
||||
log_debug("Could not auto-spawn a [role_text], none of the available candidates could be selected.")
|
||||
return 0
|
||||
|
||||
var/datum/mind/player = pending_antagonists[1]
|
||||
if(!add_antagonist(player,0,0,0,1,1))
|
||||
log_debug("Could not auto-spawn a [role_text], failed to add antagonist.")
|
||||
return 0
|
||||
|
||||
reset_antag_selection()
|
||||
|
||||
return 1
|
||||
|
||||
//Selects players that will be spawned in the antagonist role from the potential candidates
|
||||
//Selected players are added to the pending_antagonists lists.
|
||||
//Attempting to spawn an antag role with ANTAG_OVERRIDE_JOB should be done before jobs are assigned,
|
||||
//so that they do not occupy regular job slots. All other antag roles should be spawned after jobs are
|
||||
//assigned, so that job restrictions can be respected.
|
||||
/datum/antagonist/proc/attempt_spawn(var/rebuild_candidates = 1)
|
||||
/datum/antagonist/proc/attempt_spawn(var/spawn_target = null)
|
||||
if(spawn_target == null)
|
||||
spawn_target = initial_spawn_target
|
||||
|
||||
// Update our boundaries.
|
||||
if(!candidates.len)
|
||||
return 0
|
||||
|
||||
//Grab candidates randomly until we have enough.
|
||||
while(candidates.len && pending_antagonists.len < initial_spawn_target)
|
||||
while(candidates.len && pending_antagonists.len < spawn_target)
|
||||
var/datum/mind/player = pick(candidates)
|
||||
candidates -= player
|
||||
draft_antagonist(player)
|
||||
@@ -187,10 +199,15 @@
|
||||
pending_antagonists -= player
|
||||
add_antagonist(player,0,0,1)
|
||||
|
||||
//Resets all pending_antagonists, clearing their special_role (and assigned_role if ANTAG_OVERRIDE_JOB is set)
|
||||
/datum/antagonist/proc/reset()
|
||||
reset_antag_selection()
|
||||
|
||||
//Resets the antag selection, clearing all pending_antagonists and their special_role
|
||||
//(and assigned_role if ANTAG_OVERRIDE_JOB is set) as well as clearing the candidate list.
|
||||
//Existing antagonists are left untouched.
|
||||
/datum/antagonist/proc/reset_antag_selection()
|
||||
for(var/datum/mind/player in pending_antagonists)
|
||||
if(flags & ANTAG_OVERRIDE_JOB)
|
||||
player.assigned_role = null
|
||||
player.special_role = null
|
||||
pending_antagonists.Cut()
|
||||
candidates.Cut()
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
create_objectives(target)
|
||||
update_icons_added(target)
|
||||
greet(target)
|
||||
if(!gag_announcement)
|
||||
announce_antagonist_spawn()
|
||||
|
||||
/datum/antagonist/proc/create_default(var/mob/source)
|
||||
|
||||
@@ -20,6 +20,17 @@
|
||||
/datum/antagonist/proc/get_antag_count()
|
||||
return current_antagonists ? current_antagonists.len : 0
|
||||
|
||||
/datum/antagonist/proc/get_active_antag_count()
|
||||
var/active_antags = 0
|
||||
for(var/datum/mind/player in current_antagonists)
|
||||
var/mob/living/L = player.current
|
||||
if(!L || L.stat == DEAD)
|
||||
continue //no mob or dead
|
||||
if(!L.client && !L.teleop)
|
||||
continue //SSD
|
||||
active_antags++
|
||||
return active_antags
|
||||
|
||||
/datum/antagonist/proc/is_antagonist(var/datum/mind/player)
|
||||
if(player in current_antagonists)
|
||||
return 1
|
||||
@@ -33,10 +44,15 @@
|
||||
return (flags & ANTAG_VOTABLE)
|
||||
|
||||
/datum/antagonist/proc/can_late_spawn()
|
||||
update_current_antag_max()
|
||||
if(get_antag_count() >= cur_max)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/antagonist/proc/is_latejoin_template()
|
||||
return (flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB))
|
||||
|
||||
/proc/all_random_antag_types()
|
||||
// No caching as the ANTAG_RANDOM_EXCEPTED flag can be added/removed mid-round.
|
||||
var/list/antag_candidates = all_antag_types.Copy()
|
||||
for(var/datum/antagonist/antag in antag_candidates)
|
||||
if(antag.flags & ANTAG_RANDOM_EXCEPTED)
|
||||
antag_candidates -= antag
|
||||
return antag_candidates
|
||||
|
||||
@@ -23,5 +23,5 @@
|
||||
/datum/antagonist/proc/place_mob(var/mob/living/mob)
|
||||
if(!starting_locations || !starting_locations.len)
|
||||
return
|
||||
var/turf/T = pick_mobless_turf_if_exists(mob)
|
||||
var/turf/T = pick_mobless_turf_if_exists(starting_locations)
|
||||
mob.forceMove(T)
|
||||
|
||||
@@ -7,7 +7,7 @@ var/datum/antagonist/deathsquad/deathsquad
|
||||
role_text_plural = "Death Commandos"
|
||||
welcome_text = "You work in the service of corporate Asset Protection, answering directly to the Board of Directors."
|
||||
landmark_id = "Commando"
|
||||
flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_HAS_NUKE | ANTAG_HAS_LEADER
|
||||
flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_HAS_NUKE | ANTAG_HAS_LEADER | ANTAG_RANDOM_EXCEPTED
|
||||
default_access = list(access_cent_general, access_cent_specops, access_cent_living, access_cent_storage)
|
||||
antaghud_indicator = "huddeathsquad"
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ var/datum/antagonist/ert/ert
|
||||
landmark_id = "Response Team"
|
||||
id_type = /obj/item/weapon/card/id/centcom/ERT
|
||||
|
||||
flags = ANTAG_OVERRIDE_JOB | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER | ANTAG_CHOOSE_NAME
|
||||
flags = ANTAG_OVERRIDE_JOB | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER | ANTAG_CHOOSE_NAME | ANTAG_RANDOM_EXCEPTED
|
||||
antaghud_indicator = "hudloyalist"
|
||||
|
||||
hard_cap = 5
|
||||
|
||||
@@ -22,13 +22,11 @@ var/datum/antagonist/rogue_ai/malf
|
||||
malf = src
|
||||
|
||||
|
||||
/datum/antagonist/rogue_ai/get_candidates()
|
||||
/datum/antagonist/rogue_ai/build_candidate_list()
|
||||
..()
|
||||
for(var/datum/mind/player in candidates)
|
||||
if(player.assigned_role && player.assigned_role != "AI")
|
||||
candidates -= player
|
||||
if(!candidates.len)
|
||||
return list()
|
||||
return candidates
|
||||
|
||||
|
||||
|
||||
@@ -61,8 +61,8 @@ var/list/teleportlocs = list()
|
||||
for(var/area/AR in world)
|
||||
if(istype(AR, /area/shuttle) || istype(AR, /area/syndicate_station) || istype(AR, /area/wizard_station)) continue
|
||||
if(teleportlocs.Find(AR.name)) continue
|
||||
var/turf/picked = pick(get_area_turfs(AR.type))
|
||||
if (picked.z in config.station_levels)
|
||||
var/turf/picked = pick_area_turf(AR.type, list(/proc/is_station_turf))
|
||||
if (picked)
|
||||
teleportlocs += AR.name
|
||||
teleportlocs[AR.name] = AR
|
||||
|
||||
@@ -78,8 +78,8 @@ var/list/ghostteleportlocs = list()
|
||||
if(istype(AR, /area/turret_protected/aisat) || istype(AR, /area/derelict) || istype(AR, /area/tdome) || istype(AR, /area/shuttle/specops/centcom))
|
||||
ghostteleportlocs += AR.name
|
||||
ghostteleportlocs[AR.name] = AR
|
||||
var/turf/picked = pick(get_area_turfs(AR.type))
|
||||
if (picked.z in config.player_levels)
|
||||
var/turf/picked = pick_area_turf(AR.type, list(/proc/is_station_turf))
|
||||
if (picked)
|
||||
ghostteleportlocs += AR.name
|
||||
ghostteleportlocs[AR.name] = AR
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
var/global/list/space_surprises = list( /obj/item/clothing/mask/facehugger =4,
|
||||
/obj/item/weapon/pickaxe/silver =4,
|
||||
var/global/list/space_surprises = list( /obj/item/weapon/pickaxe/silver =4,
|
||||
/obj/item/weapon/pickaxe/drill =4,
|
||||
/obj/item/weapon/pickaxe/jackhammer =4,
|
||||
//mob/living/simple_animal/hostile/carp =3,
|
||||
@@ -22,7 +21,7 @@ proc/spawn_room(var/atom/start_loc,var/x_size,var/y_size,var/wall,var/floor , va
|
||||
|
||||
//world << "Room spawned at [start_loc.x],[start_loc.y],[start_loc.z]"
|
||||
if(!wall)
|
||||
wall = pick(/turf/simulated/wall/r_wall,/turf/simulated/wall,/obj/effect/alien/resin)
|
||||
wall = pick(/turf/simulated/wall/r_wall,/turf/simulated/wall,/obj/structure/alien/resin)
|
||||
if(!floor)
|
||||
floor = pick(/turf/simulated/floor,/turf/simulated/floor/tiled,/turf/simulated/floor/reinforced)
|
||||
|
||||
@@ -43,9 +42,9 @@ proc/spawn_room(var/atom/start_loc,var/x_size,var/y_size,var/wall,var/floor , va
|
||||
|
||||
|
||||
if(x == 0 || x==x_size-1 || y==0 || y==y_size-1)
|
||||
if(wall == /obj/effect/alien/resin)
|
||||
if(wall == /obj/structure/alien/resin)
|
||||
T = new floor(cur_loc)
|
||||
new /obj/effect/alien/resin(T)
|
||||
new /obj/structure/alien/resin(T)
|
||||
else
|
||||
T = new wall(cur_loc)
|
||||
room_turfs["walls"] += T
|
||||
@@ -73,7 +72,7 @@ proc/admin_spawn_room_at_pos()
|
||||
if("Regular wall")
|
||||
wall=/turf/simulated/wall
|
||||
if("Resin wall")
|
||||
wall=/obj/effect/alien/resin
|
||||
wall=/obj/structure/alien/resin
|
||||
switch(alert("Floor type",null,"Regular floor","Reinforced floor"))
|
||||
if("Regular floor")
|
||||
floor=/turf/simulated/floor/tiled
|
||||
|
||||
@@ -11,15 +11,14 @@
|
||||
event_delay_mod_major = 0.75
|
||||
|
||||
/datum/game_mode/calamity/create_antagonists()
|
||||
var/list/antag_candidates = all_random_antag_types()
|
||||
|
||||
shuffle(all_antag_types) // This is probably the only instance in the game where the order will be important.
|
||||
var/i = 1
|
||||
var/grab_antags = round(num_players()/ANTAG_TYPE_RATIO)+1
|
||||
for(var/antag_id in all_antag_types)
|
||||
if(i > grab_antags)
|
||||
break
|
||||
while(antag_candidates.len && antag_tags.len < grab_antags)
|
||||
var/antag_id = pick(antag_candidates)
|
||||
antag_candidates -= antag_id
|
||||
antag_tags |= antag_id
|
||||
i++
|
||||
|
||||
..()
|
||||
|
||||
/datum/game_mode/calamity/check_victory()
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
certain though... there is never just one of them. Good luck."
|
||||
config_tag = "changeling"
|
||||
required_players = 2
|
||||
required_players_secret = 10
|
||||
required_enemies = 1
|
||||
end_on_antag_death = 0
|
||||
antag_scaling_coeff = 10
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
extended_round_description = "The station has been infiltrated by a fanatical group of death-cultists! They will use powers from beyond your comprehension to subvert you to their cause and ultimately please their gods through sacrificial summons and physical immolation! Try to survive!"
|
||||
config_tag = "cult"
|
||||
required_players = 5
|
||||
required_players_secret = 15
|
||||
required_enemies = 3
|
||||
end_on_antag_death = 0
|
||||
antag_tags = list(MODE_CULTIST)
|
||||
|
||||
@@ -6,23 +6,35 @@
|
||||
w_class = 4
|
||||
force = 30
|
||||
throwforce = 10
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
|
||||
|
||||
/obj/item/weapon/melee/cultblade/cultify()
|
||||
return
|
||||
|
||||
/obj/item/weapon/melee/cultblade/attack(mob/living/target as mob, mob/living/carbon/human/user as mob)
|
||||
/obj/item/weapon/melee/cultblade/attack(mob/living/M, mob/living/user, var/target_zone)
|
||||
if(iscultist(user))
|
||||
playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1, -1)
|
||||
return ..()
|
||||
|
||||
var/zone = (user.hand ? "l_arm":"r_arm")
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/obj/item/organ/external/affecting = H.get_organ(zone)
|
||||
user << "<span class='danger'>An unexplicable force rips through your [affecting.name], tearing the sword from your grasp!</span>"
|
||||
else
|
||||
user.Paralyse(5)
|
||||
user << "<span class='warning'>An unexplicable force powerfully repels the sword from [target]!</span>"
|
||||
var/organ = ((user.hand ? "l_":"r_") + "arm")
|
||||
var/obj/item/organ/external/affecting = user.get_organ(organ)
|
||||
if(affecting.take_damage(rand(force/2, force))) //random amount of damage between half of the blade's force and the full force of the blade.
|
||||
user.UpdateDamageIcon()
|
||||
return
|
||||
user << "<span class='danger'>An unexplicable force rips through you, tearing the sword from your grasp!</span>"
|
||||
|
||||
//random amount of damage between half of the blade's force and the full force of the blade.
|
||||
user.apply_damage(rand(force/2, force), BRUTE, zone, 0, sharp=1, edge=1)
|
||||
user.Weaken(5)
|
||||
|
||||
user.drop_from_inventory(src)
|
||||
throw_at(get_edge_target_turf(src, pick(alldirs)), rand(1,3), throw_speed)
|
||||
|
||||
var/spooky = pick('sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg', 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/wail.ogg')
|
||||
playsound(loc, spooky, 50, 1)
|
||||
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/melee/cultblade/pickup(mob/living/user as mob)
|
||||
if(!iscultist(user))
|
||||
|
||||
@@ -527,7 +527,11 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
|
||||
user << "<span class='notice'>You do not have enough space to write a proper rune.</span>"
|
||||
var/list/runes = list("teleport", "itemport", "tome", "armor", "convert", "tear in reality", "emp", "drain", "seer", "raise", "obscure", "reveal", "astral journey", "manifest", "imbue talisman", "sacrifice", "wall", "freedom", "cultsummon", "deafen", "blind", "bloodboil", "communicate", "stun")
|
||||
r = input("Choose a rune to scribe", "Rune Scribing") in runes //not cancellable.
|
||||
var/obj/effect/rune/R = new /obj/effect/rune
|
||||
if(locate(/obj/effect/rune) in user.loc)
|
||||
user << "<span class='warning'>There is already a rune in this location.</span>"
|
||||
return
|
||||
|
||||
var/obj/effect/rune/R = new /obj/effect/rune(user.loc)
|
||||
if(istype(user, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = user
|
||||
R.blood_DNA = list()
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
name = "epidemic"
|
||||
config_tag = "epidemic"
|
||||
required_players = 1
|
||||
required_players_secret = 15
|
||||
round_description = "A deadly epidemic is spreading on the station. Find a cure as fast as possible, and keep your distance to anyone who speaks in a hoarse voice!"
|
||||
|
||||
var/cruiser_arrival
|
||||
|
||||
@@ -10,7 +10,6 @@ var/global/list/additional_antag_types = list()
|
||||
var/probability = 0
|
||||
|
||||
var/required_players = 0 // Minimum players for round to start if voted in.
|
||||
var/required_players_secret = 0 // Minimum number of players for that game mode to be chose in Secret
|
||||
var/required_enemies = 0 // Minimum antagonists for round to start.
|
||||
var/newscaster_announcements = null
|
||||
var/end_on_antag_death = 0 // Round will end when all antagonists are dead.
|
||||
@@ -22,7 +21,6 @@ var/global/list/additional_antag_types = list()
|
||||
|
||||
var/list/antag_tags = list() // Core antag templates to spawn.
|
||||
var/list/antag_templates // Extra antagonist types to include.
|
||||
var/list/latejoin_templates = list()
|
||||
var/round_autoantag = 0 // Will this round attempt to periodically spawn more antagonists?
|
||||
var/antag_scaling_coeff = 5 // Coefficient for scaling max antagonists to player count.
|
||||
var/require_all_templates = 0 // Will only start if all templates are checked and can spawn.
|
||||
@@ -147,10 +145,6 @@ var/global/list/additional_antag_types = list()
|
||||
if((player.client)&&(player.ready))
|
||||
playerC++
|
||||
|
||||
if(master_mode=="secret")
|
||||
if(playerC < required_players_secret)
|
||||
return 0
|
||||
else
|
||||
if(playerC < required_players)
|
||||
return 0
|
||||
|
||||
@@ -188,6 +182,7 @@ var/global/list/additional_antag_types = list()
|
||||
|
||||
/datum/game_mode/proc/pre_setup()
|
||||
for(var/datum/antagonist/antag in antag_templates)
|
||||
antag.update_current_antag_max()
|
||||
antag.build_candidate_list() //compile a list of all eligible candidates
|
||||
|
||||
//antag roles that replace jobs need to be assigned before the job controller hands out jobs.
|
||||
@@ -212,8 +207,6 @@ var/global/list/additional_antag_types = list()
|
||||
if(!(antag.flags & ANTAG_OVERRIDE_JOB))
|
||||
antag.attempt_spawn() //select antags to be spawned
|
||||
antag.finalize_spawn() //actually spawn antags
|
||||
if(antag.is_latejoin_template())
|
||||
latejoin_templates |= antag
|
||||
|
||||
if(emergency_shuttle && auto_recall_shuttle)
|
||||
emergency_shuttle.auto_recall = 1
|
||||
@@ -226,7 +219,7 @@ var/global/list/additional_antag_types = list()
|
||||
|
||||
/datum/game_mode/proc/fail_setup()
|
||||
for(var/datum/antagonist/antag in antag_templates)
|
||||
antag.reset()
|
||||
antag.reset_antag_selection()
|
||||
|
||||
/datum/game_mode/proc/announce_ert_disabled()
|
||||
if(!ert_disabled)
|
||||
@@ -498,6 +491,7 @@ var/global/list/additional_antag_types = list()
|
||||
if(antag)
|
||||
antag_templates |= antag
|
||||
|
||||
shuffle(antag_templates) //In the case of multiple antag types
|
||||
newscaster_announcements = pick(newscaster_standard_feeds)
|
||||
|
||||
/datum/game_mode/proc/check_victory()
|
||||
|
||||
@@ -3,55 +3,39 @@
|
||||
/datum/game_mode/var/max_autotraitor_delay = 12000 // Approx 20 minutes.
|
||||
/datum/game_mode/var/process_count = 0
|
||||
|
||||
/datum/game_mode/proc/get_usable_templates(var/list/supplied_templates)
|
||||
var/list/usable_templates = list()
|
||||
for(var/datum/antagonist/A in supplied_templates)
|
||||
if(A.can_late_spawn())
|
||||
message_admins("AUTO[uppertext(name)]: [A.id] selected for spawn attempt.")
|
||||
usable_templates |= A
|
||||
return usable_templates
|
||||
|
||||
///process()
|
||||
///Called by the gameticker
|
||||
/datum/game_mode/proc/process()
|
||||
// Slow this down a bit so latejoiners have a chance of being antags.
|
||||
process_count++
|
||||
if(process_count >= 10)
|
||||
process_count = 0
|
||||
try_latespawn()
|
||||
if(round_autoantag && world.time < next_spawn && !emergency_shuttle.departed)
|
||||
process_autoantag()
|
||||
|
||||
/datum/game_mode/proc/latespawn(var/mob/living/carbon/human/character)
|
||||
if(!character.mind)
|
||||
return
|
||||
try_latespawn(character.mind)
|
||||
//This can be overriden in case a game mode needs to do stuff when a player latejoins
|
||||
/datum/game_mode/proc/handle_latejoin(var/mob/living/carbon/human/character)
|
||||
return 0
|
||||
|
||||
/datum/game_mode/proc/try_latespawn(var/datum/mind/player, var/latejoin_only)
|
||||
/datum/game_mode/proc/process_autoantag()
|
||||
message_admins("[uppertext(name)]: Attempting autospawn.")
|
||||
|
||||
if(emergency_shuttle.departed || !round_autoantag)
|
||||
return
|
||||
var/list/usable_templates = list()
|
||||
for(var/datum/antagonist/A in antag_templates)
|
||||
if(A.can_late_spawn())
|
||||
message_admins("[uppertext(name)]: [A.id] selected for spawn attempt.")
|
||||
usable_templates |= A
|
||||
|
||||
if(world.time < next_spawn)
|
||||
return
|
||||
|
||||
message_admins("AUTO[uppertext(name)]: Attempting spawn.")
|
||||
|
||||
var/list/usable_templates
|
||||
if(latejoin_only && latejoin_templates.len)
|
||||
usable_templates = get_usable_templates(latejoin_templates)
|
||||
else if (antag_templates && antag_templates.len)
|
||||
usable_templates = get_usable_templates(antag_templates)
|
||||
else
|
||||
message_admins("AUTO[uppertext(name)]: Failed to find configured mode spawn templates, please disable auto-antagonists until one is added.")
|
||||
if(!usable_templates.len)
|
||||
message_admins("[uppertext(name)]: Failed to find configured mode spawn templates, please re-enable auto-antagonists after one is added.")
|
||||
round_autoantag = 0
|
||||
return
|
||||
|
||||
while(usable_templates.len)
|
||||
var/datum/antagonist/spawn_antag = pick(usable_templates)
|
||||
usable_templates -= spawn_antag
|
||||
if(spawn_antag.attempt_late_spawn(player))
|
||||
message_admins("AUTO[uppertext(name)]: Attempting to latespawn [spawn_antag.id]. ([spawn_antag.get_antag_count()]/[spawn_antag.cur_max])")
|
||||
|
||||
if(spawn_antag.attempt_auto_spawn())
|
||||
message_admins("[uppertext(name)]: Auto-added a new [spawn_antag.role_text].")
|
||||
message_admins("There are now [spawn_antag.get_active_antag_count()]/[spawn_antag.cur_max] active [spawn_antag.role_text_plural].")
|
||||
next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay)
|
||||
return
|
||||
message_admins("AUTO[uppertext(name)]: Failed to proc a viable spawn template.")
|
||||
next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay)
|
||||
|
||||
message_admins("[uppertext(name)]: Failed to proc a viable spawn template.")
|
||||
next_spawn = world.time + min_autotraitor_delay //recheck again in the miniumum time
|
||||
|
||||
@@ -8,7 +8,6 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind'
|
||||
name = "heist"
|
||||
config_tag = "heist"
|
||||
required_players = 15
|
||||
required_players_secret = 25
|
||||
required_enemies = 4
|
||||
round_description = "An unidentified bluespace signature has slipped past the Icarus and is approaching the station!"
|
||||
end_on_antag_death = 0
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
extended_round_description = "The AI will attempt to hack the APCs around the station in order to gain as much control as possible."
|
||||
config_tag = "malfunction"
|
||||
required_players = 2
|
||||
required_players_secret = 7
|
||||
required_enemies = 1
|
||||
end_on_antag_death = 0
|
||||
auto_recall_shuttle = 0
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
|
||||
/datum/game_mode/malfunction/verb/advanced_encryption_hack()
|
||||
set category = "Software"
|
||||
set name = "Advanced Encrypthion Hack"
|
||||
set name = "Advanced Encryption Hack"
|
||||
set desc = "75 CPU - Attempts to bypass encryption on the Command Quantum Relay, giving you ability to fake legitimate messages. Has chance of failing."
|
||||
var/price = 75
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
@@ -106,15 +106,12 @@
|
||||
announce_hack_failure(user, "quantum message relay")
|
||||
return
|
||||
|
||||
var/datum/announcement/priority/command/AN = new/datum/announcement/priority/command()
|
||||
AN.title = title
|
||||
AN.Announce(text)
|
||||
|
||||
command_announcement.Announce(text, title)
|
||||
|
||||
/datum/game_mode/malfunction/verb/elite_encryption_hack()
|
||||
set category = "Software"
|
||||
set name = "Elite Encryption Hack"
|
||||
set desc = "200 CPU - Allows you to hack station's ALERTCON system, changing alert level. Has high chance of failijng."
|
||||
set desc = "200 CPU - Allows you to hack station's ALERTCON system, changing alert level. Has high chance of failing."
|
||||
var/price = 200
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
if(!ability_prechecks(user, price))
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
name = "Memetic Anomaly"
|
||||
config_tag = "meme"
|
||||
required_players = 3
|
||||
required_players_secret = 10
|
||||
restricted_jobs = list("AI", "Cyborg")
|
||||
recommended_enemies = 2 // need at least a meme and a host
|
||||
votable = 0 // temporarily disable this mode for voting
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
round_description = "A mercenary strike force is approaching the station to eradicate a xenomorph infestation!"
|
||||
config_tag = "bughunt"
|
||||
required_players = 15
|
||||
required_players_secret = 25
|
||||
required_enemies = 1
|
||||
end_on_antag_death = 1
|
||||
antag_tags = list(MODE_XENOMORPH, MODE_DEATHSQUAD)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
extended_round_description = "Cultists and wizards spawn during this round."
|
||||
config_tag = "conflux"
|
||||
required_players = 15
|
||||
required_players_secret = 15
|
||||
required_enemies = 5
|
||||
end_on_antag_death = 1
|
||||
antag_tags = list(MODE_WIZARD, MODE_CULTIST)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
extended_round_description = "Rampant AIs, renegades and changelings spawn in this mode."
|
||||
config_tag = "paranoia"
|
||||
required_players = 2
|
||||
required_players_secret = 7
|
||||
required_enemies = 1
|
||||
end_on_antag_death = 1
|
||||
require_all_templates = 1
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
extended_round_description = "Traitors and changelings both spawn during this mode."
|
||||
config_tag = "traitorling"
|
||||
required_players = 10
|
||||
required_players_secret = 15
|
||||
required_enemies = 5
|
||||
end_on_antag_death = 1
|
||||
require_all_templates = 1
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
round_description = "Some crewmembers are attempting to start a revolution while a cult plots in the shadows!"
|
||||
extended_round_description = "Cultists and revolutionaries spawn in this round."
|
||||
required_players = 15
|
||||
required_players_secret = 15
|
||||
required_enemies = 3
|
||||
end_on_antag_death = 1
|
||||
antag_tags = list(MODE_REVOLUTIONARY, MODE_LOYALIST, MODE_CULTIST)
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
only hope this unknown assassin isn't here for you."
|
||||
config_tag = "ninja"
|
||||
required_players = 1
|
||||
required_players_secret = 10
|
||||
required_enemies = 1
|
||||
end_on_antag_death = 0
|
||||
antag_tags = list(MODE_NINJA)
|
||||
@@ -9,7 +9,6 @@ var/list/nuke_disks = list()
|
||||
round_description = "A mercenary strike force is approaching the station!"
|
||||
config_tag = "mercenary"
|
||||
required_players = 15
|
||||
required_players_secret = 25 // 25 players - 5 players to be the nuke ops = 20 players remaining
|
||||
required_enemies = 1
|
||||
end_on_antag_death = 0
|
||||
var/nuke_off_station = 0 //Used for tracking if the syndies actually haul the nuke to the station
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
round_description = "Some crewmembers are attempting to start a revolution!"
|
||||
extended_round_description = "Revolutionaries - Remove the heads of staff from power. Convert other crewmembers to your cause using the 'Convert Bourgeoise' verb. Protect your leaders."
|
||||
required_players = 4
|
||||
required_players_secret = 15
|
||||
required_enemies = 3
|
||||
auto_recall_shuttle = 0 //NO THANKS
|
||||
end_on_antag_death = 0
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
extended_round_description = "A powerful entity capable of manipulating the elements around him, most commonly referred to as a 'wizard', has infiltrated the station. They have a wide variety of powers and spells available to them that makes your own simple moral self tremble with fear and excitement. Ultimately, their purpose is unknown. However, it is up to you and your crew to decide if their powers can be used for good or if their arrival foreshadows the destruction of the entire station."
|
||||
config_tag = "wizard"
|
||||
required_players = 1
|
||||
required_players_secret = 10
|
||||
required_enemies = 1
|
||||
end_on_antag_death = 0
|
||||
antag_tags = list(MODE_WIZARD)
|
||||
|
||||
@@ -127,11 +127,4 @@
|
||||
M.deconstruct(src)
|
||||
qdel(src)
|
||||
else
|
||||
src.attack_hand(user)
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
..()
|
||||
|
||||
@@ -1081,8 +1081,8 @@ About the new airlock wires panel:
|
||||
|
||||
/obj/machinery/door/airlock/emp_act(var/severity)
|
||||
if(prob(40/severity))
|
||||
var/duration = world.time + SecondsToTicks(30 / severity)
|
||||
if(duration > electrified_until)
|
||||
var/duration = SecondsToTicks(30 / severity)
|
||||
if(electrified_until > -1 && (duration + world.time) > electrified_until)
|
||||
electrify(duration)
|
||||
..()
|
||||
|
||||
|
||||
@@ -191,7 +191,10 @@ Class Procs:
|
||||
return (stat & (NOPOWER|BROKEN|additional_flags))
|
||||
|
||||
/obj/machinery/CanUseTopic(var/mob/user)
|
||||
if(!interact_offline && (stat & (NOPOWER|BROKEN)))
|
||||
if(stat & BROKEN)
|
||||
return STATUS_CLOSE
|
||||
|
||||
if(!interact_offline && (stat & NOPOWER))
|
||||
return STATUS_CLOSE
|
||||
|
||||
return ..()
|
||||
|
||||
@@ -418,10 +418,14 @@ obj/machinery/nuclearbomb/proc/nukehack_win(mob/user as mob)
|
||||
nuke_disks |= src
|
||||
|
||||
/obj/item/weapon/disk/nuclear/Destroy()
|
||||
if(!nuke_disks.len && blobstart.len > 0)
|
||||
var/obj/D = new /obj/item/weapon/disk/nuclear(pick(blobstart))
|
||||
message_admins("[src], the last authentication disk, has been destroyed. Spawning [D] at ([D.x], [D.y], [D.z]).")
|
||||
log_game("[src], the last authentication disk, has been destroyed. Spawning [D] at ([D.x], [D.y], [D.z]).")
|
||||
nuke_disks -= src
|
||||
if(!nuke_disks.len)
|
||||
var/turf/T = pick_area_turf(/area/maintenance, list(/proc/is_station_turf, /proc/not_turf_contains_dense_objects))
|
||||
if(T)
|
||||
var/obj/D = new /obj/item/weapon/disk/nuclear(T)
|
||||
log_and_message_admins_with_location("[src], the last authentication disk, has been destroyed. Spawning [D] at ([D.x], [D.y], [D.z]).", T.x, T.y, T.z)
|
||||
else
|
||||
log_and_message_admins("[src], the last authentication disk, has been destroyed. Failed to respawn disc!")
|
||||
..()
|
||||
|
||||
/obj/item/weapon/disk/nuclear/touch_map_edge()
|
||||
|
||||
@@ -1,271 +1,11 @@
|
||||
/* Alien Effects!
|
||||
* Contains:
|
||||
* effect/alien
|
||||
* Resin
|
||||
* Weeds
|
||||
* Acid
|
||||
* Egg
|
||||
*/
|
||||
|
||||
/*
|
||||
* effect/alien
|
||||
*/
|
||||
/obj/effect/alien
|
||||
name = "alien thing"
|
||||
desc = "theres something alien about this"
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
|
||||
/*
|
||||
* Resin
|
||||
*/
|
||||
/obj/effect/alien/resin
|
||||
name = "resin"
|
||||
desc = "Looks like some kind of slimy growth."
|
||||
icon_state = "resin"
|
||||
|
||||
density = 1
|
||||
opacity = 1
|
||||
anchored = 1
|
||||
var/health = 200
|
||||
//var/mob/living/affecting = null
|
||||
|
||||
/obj/effect/alien/resin/wall
|
||||
name = "resin wall"
|
||||
desc = "Purple slime solidified into a wall."
|
||||
icon_state = "resinwall" //same as resin, but consistency ho!
|
||||
|
||||
/obj/effect/alien/resin/membrane
|
||||
name = "resin membrane"
|
||||
desc = "Purple slime just thin enough to let light pass through."
|
||||
icon_state = "resinmembrane"
|
||||
opacity = 0
|
||||
health = 120
|
||||
|
||||
/obj/effect/alien/resin/New()
|
||||
..()
|
||||
var/turf/T = get_turf(src)
|
||||
T.thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
|
||||
|
||||
/obj/effect/alien/resin/Destroy()
|
||||
var/turf/T = get_turf(src)
|
||||
T.thermal_conductivity = initial(T.thermal_conductivity)
|
||||
..()
|
||||
|
||||
/obj/effect/alien/resin/proc/healthcheck()
|
||||
if(health <=0)
|
||||
density = 0
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/effect/alien/resin/bullet_act(var/obj/item/projectile/Proj)
|
||||
health -= Proj.damage
|
||||
..()
|
||||
healthcheck()
|
||||
return
|
||||
|
||||
/obj/effect/alien/resin/ex_act(severity)
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
health-=50
|
||||
if(2.0)
|
||||
health-=50
|
||||
if(3.0)
|
||||
if (prob(50))
|
||||
health-=50
|
||||
else
|
||||
health-=25
|
||||
healthcheck()
|
||||
return
|
||||
|
||||
/obj/effect/alien/resin/hitby(AM as mob|obj)
|
||||
..()
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message("<span class='danger'>[src] was hit by [AM].</span>", 1)
|
||||
var/tforce = 0
|
||||
if(ismob(AM))
|
||||
tforce = 10
|
||||
else
|
||||
tforce = AM:throwforce
|
||||
playsound(loc, 'sound/effects/attackblob.ogg', 100, 1)
|
||||
health = max(0, health - tforce)
|
||||
healthcheck()
|
||||
..()
|
||||
return
|
||||
|
||||
/obj/effect/alien/resin/attack_hand()
|
||||
usr.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
if (HULK in usr.mutations)
|
||||
usr << "<span class='notice'>You easily destroy the [name].</span>"
|
||||
for(var/mob/O in oviewers(src))
|
||||
O.show_message("<span class='warning'>[usr] destroys the [name]!</span>", 1)
|
||||
health = 0
|
||||
else
|
||||
|
||||
// Aliens can get straight through these.
|
||||
if(istype(usr,/mob/living/carbon))
|
||||
var/mob/living/carbon/M = usr
|
||||
if(locate(/obj/item/organ/xenos/hivenode) in M.internal_organs)
|
||||
for(var/mob/O in oviewers(src))
|
||||
O.show_message("<span class='warning'>[usr] strokes the [name] and it melts away!</span>", 1)
|
||||
health = 0
|
||||
healthcheck()
|
||||
return
|
||||
|
||||
usr << "<span class='notice'>You claw at the [name].</span>"
|
||||
for(var/mob/O in oviewers(src))
|
||||
O.show_message("<span class='warning'>[usr] claws at the [name]!</span>", 1)
|
||||
health -= rand(5,10)
|
||||
healthcheck()
|
||||
return
|
||||
|
||||
/obj/effect/alien/resin/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
var/aforce = W.force
|
||||
health = max(0, health - aforce)
|
||||
playsound(loc, 'sound/effects/attackblob.ogg', 100, 1)
|
||||
healthcheck()
|
||||
..()
|
||||
return
|
||||
|
||||
/obj/effect/alien/resin/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||
if(air_group) return 0
|
||||
if(istype(mover) && mover.checkpass(PASSGLASS))
|
||||
return !opacity
|
||||
return !density
|
||||
|
||||
|
||||
/*
|
||||
* Weeds
|
||||
*/
|
||||
#define NODERANGE 3
|
||||
|
||||
/obj/effect/alien/weeds
|
||||
name = "weeds"
|
||||
desc = "Weird purple weeds."
|
||||
icon_state = "weeds"
|
||||
|
||||
anchored = 1
|
||||
density = 0
|
||||
layer = 2
|
||||
var/health = 15
|
||||
var/obj/effect/alien/weeds/node/linked_node = null
|
||||
|
||||
/obj/effect/alien/weeds/node
|
||||
icon_state = "weednode"
|
||||
name = "purple sac"
|
||||
desc = "Weird purple octopus-like thing."
|
||||
layer = 3
|
||||
light_range = NODERANGE
|
||||
var/node_range = NODERANGE
|
||||
|
||||
/obj/effect/alien/weeds/node/New()
|
||||
..(src.loc, src)
|
||||
|
||||
|
||||
/obj/effect/alien/weeds/New(pos, node)
|
||||
..()
|
||||
if(istype(loc, /turf/space))
|
||||
qdel(src)
|
||||
return
|
||||
linked_node = node
|
||||
if(icon_state == "weeds")icon_state = pick("weeds", "weeds1", "weeds2")
|
||||
spawn(rand(150, 200))
|
||||
if(src)
|
||||
Life()
|
||||
return
|
||||
|
||||
/obj/effect/alien/weeds/proc/Life()
|
||||
set background = 1
|
||||
var/turf/U = get_turf(src)
|
||||
/*
|
||||
if (locate(/obj/movable, U))
|
||||
U = locate(/obj/movable, U)
|
||||
if(U.density == 1)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
Alien plants should do something if theres a lot of poison
|
||||
if(U.poison> 200000)
|
||||
health -= round(U.poison/200000)
|
||||
update()
|
||||
return
|
||||
*/
|
||||
if (istype(U, /turf/space))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if(!linked_node || (get_dist(linked_node, src) > linked_node.node_range) )
|
||||
return
|
||||
|
||||
direction_loop:
|
||||
for(var/dirn in cardinal)
|
||||
var/turf/T = get_step(src, dirn)
|
||||
|
||||
if (!istype(T) || T.density || locate(/obj/effect/alien/weeds) in T || istype(T.loc, /area/arrival) || istype(T, /turf/space))
|
||||
continue
|
||||
|
||||
// if (locate(/obj/movable, T)) // don't propogate into movables
|
||||
// continue
|
||||
|
||||
for(var/obj/O in T)
|
||||
if(O.density)
|
||||
continue direction_loop
|
||||
|
||||
PoolOrNew(/obj/effect/alien/weeds, T, linked_node)
|
||||
|
||||
|
||||
/obj/effect/alien/weeds/ex_act(severity)
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
qdel(src)
|
||||
if(2.0)
|
||||
if (prob(50))
|
||||
qdel(src)
|
||||
if(3.0)
|
||||
if (prob(5))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/effect/alien/weeds/attackby(var/obj/item/weapon/W, var/mob/user)
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
if(W.attack_verb.len)
|
||||
visible_message("<span class='danger'>\The [src] have been [pick(W.attack_verb)] with \the [W][(user ? " by [user]." : ".")]</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>\The [src] have been attacked with \the [W][(user ? " by [user]." : ".")]</span>")
|
||||
|
||||
var/damage = W.force / 4.0
|
||||
|
||||
if(istype(W, /obj/item/weapon/weldingtool))
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
|
||||
if(WT.remove_fuel(0, user))
|
||||
damage = 15
|
||||
playsound(loc, 'sound/items/Welder.ogg', 100, 1)
|
||||
|
||||
health -= damage
|
||||
healthcheck()
|
||||
|
||||
/obj/effect/alien/weeds/proc/healthcheck()
|
||||
if(health <= 0)
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/effect/alien/weeds/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
if(exposed_temperature > 300 + T0C)
|
||||
health -= 5
|
||||
healthcheck()
|
||||
|
||||
#undef NODERANGE
|
||||
|
||||
|
||||
/*
|
||||
* Acid
|
||||
*/
|
||||
/obj/effect/alien/acid
|
||||
/obj/effect/acid
|
||||
name = "acid"
|
||||
desc = "Burbling corrossive stuff. I wouldn't want to touch it."
|
||||
desc = "Burbling corrosive stuff. Probably a bad idea to roll around in it."
|
||||
icon_state = "acid"
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
|
||||
density = 0
|
||||
opacity = 0
|
||||
@@ -275,9 +15,9 @@ Alien plants should do something if theres a lot of poison
|
||||
var/ticks = 0
|
||||
var/target_strength = 0
|
||||
|
||||
/obj/effect/alien/acid/New(loc, target)
|
||||
/obj/effect/acid/New(loc, supplied_target)
|
||||
..(loc)
|
||||
src.target = target
|
||||
target = supplied_target
|
||||
|
||||
if(isturf(target)) // Turf take twice as long to take down.
|
||||
target_strength = 8
|
||||
@@ -285,17 +25,13 @@ Alien plants should do something if theres a lot of poison
|
||||
target_strength = 4
|
||||
tick()
|
||||
|
||||
/obj/effect/alien/acid/proc/tick()
|
||||
/obj/effect/acid/proc/tick()
|
||||
if(!target)
|
||||
qdel(src)
|
||||
|
||||
ticks += 1
|
||||
|
||||
ticks++
|
||||
if(ticks >= target_strength)
|
||||
|
||||
for(var/mob/O in hearers(src, null))
|
||||
O.show_message("<span class='alium'>[src.target] collapses under its own weight into a puddle of goop and undigested debris!</span>", 1)
|
||||
|
||||
target.visible_message("<span class='alium'>\The [target] collapses under its own weight into a puddle of goop and undigested debris!</span>")
|
||||
if(istype(target, /turf/simulated/wall)) // I hate turf code.
|
||||
var/turf/simulated/wall/W = target
|
||||
W.dismantle_wall(1)
|
||||
@@ -306,135 +42,11 @@ Alien plants should do something if theres a lot of poison
|
||||
|
||||
switch(target_strength - ticks)
|
||||
if(6)
|
||||
visible_message("<span class='alium'>[src.target] is holding up against the acid!</span>")
|
||||
visible_message("<span class='alium'>\The [src.target] is holding up against the acid!</span>")
|
||||
if(4)
|
||||
visible_message("<span class='alium'>[src.target]\s structure is being melted by the acid!</span>")
|
||||
visible_message("<span class='alium'>\The [src.target]\s structure is being melted by the acid!</span>")
|
||||
if(2)
|
||||
visible_message("<span class='alium'>[src.target] is struggling to withstand the acid!</span>")
|
||||
visible_message("<span class='alium'>\The [src.target] is struggling to withstand the acid!</span>")
|
||||
if(0 to 1)
|
||||
visible_message("<span class='alium'>[src.target] begins to crumble under the acid!</span>")
|
||||
visible_message("<span class='alium'>\The [src.target] begins to crumble under the acid!</span>")
|
||||
spawn(rand(150, 200)) tick()
|
||||
|
||||
/*
|
||||
* Egg
|
||||
*/
|
||||
/var/const //for the status var
|
||||
BURST = 0
|
||||
BURSTING = 1
|
||||
GROWING = 2
|
||||
GROWN = 3
|
||||
|
||||
MIN_GROWTH_TIME = 1800 //time it takes to grow a hugger
|
||||
MAX_GROWTH_TIME = 3000
|
||||
|
||||
/obj/effect/alien/egg
|
||||
desc = "It looks like a weird egg"
|
||||
name = "egg"
|
||||
icon_state = "egg_growing"
|
||||
density = 0
|
||||
anchored = 1
|
||||
|
||||
var/health = 100
|
||||
var/status = GROWING //can be GROWING, GROWN or BURST; all mutually exclusive
|
||||
flags = PROXMOVE
|
||||
|
||||
/obj/effect/alien/egg/New()
|
||||
if(config.aliens_allowed)
|
||||
..()
|
||||
spawn(rand(MIN_GROWTH_TIME,MAX_GROWTH_TIME))
|
||||
Grow()
|
||||
else
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/alien/egg/attack_hand(user as mob)
|
||||
|
||||
var/mob/living/carbon/M = user
|
||||
if(!istype(M) || !(locate(/obj/item/organ/xenos/hivenode) in M.internal_organs))
|
||||
return attack_hand(user)
|
||||
|
||||
switch(status)
|
||||
if(BURST)
|
||||
user << "<span class='warning'>You clear the hatched egg.</span>"
|
||||
qdel(src)
|
||||
return
|
||||
if(GROWING)
|
||||
user << "<span class='warning'>The child is not developed yet.</span>"
|
||||
return
|
||||
if(GROWN)
|
||||
user << "<span class='warning'>You retrieve the child.</span>"
|
||||
Burst(0)
|
||||
return
|
||||
|
||||
/obj/effect/alien/egg/proc/GetFacehugger()
|
||||
return locate(/obj/item/clothing/mask/facehugger) in contents
|
||||
|
||||
/obj/effect/alien/egg/proc/Grow()
|
||||
icon_state = "egg"
|
||||
status = GROWN
|
||||
new /obj/item/clothing/mask/facehugger(src)
|
||||
return
|
||||
|
||||
/obj/effect/alien/egg/proc/Burst(var/kill = 1) //drops and kills the hugger if any is remaining
|
||||
if(status == GROWN || status == GROWING)
|
||||
var/obj/item/clothing/mask/facehugger/child = GetFacehugger()
|
||||
icon_state = "egg_hatched"
|
||||
flick("egg_opening", src)
|
||||
status = BURSTING
|
||||
spawn(15)
|
||||
status = BURST
|
||||
child.loc = get_turf(src)
|
||||
|
||||
if(kill && istype(child))
|
||||
child.Die()
|
||||
else
|
||||
for(var/mob/M in range(1,src))
|
||||
if(CanHug(M))
|
||||
child.Attach(M)
|
||||
break
|
||||
|
||||
/obj/effect/alien/egg/bullet_act(var/obj/item/projectile/Proj)
|
||||
health -= Proj.damage
|
||||
..()
|
||||
healthcheck()
|
||||
return
|
||||
|
||||
|
||||
/obj/effect/alien/egg/attackby(var/obj/item/weapon/W, var/mob/user)
|
||||
if(health <= 0)
|
||||
return
|
||||
if(W.attack_verb.len)
|
||||
src.visible_message("<span class='danger'>\The [src] has been [pick(W.attack_verb)] with \the [W][(user ? " by [user]." : ".")]</span>")
|
||||
else
|
||||
src.visible_message("<span class='danger'>\The [src] has been attacked with \the [W][(user ? " by [user]." : ".")]</span>")
|
||||
var/damage = W.force / 4.0
|
||||
|
||||
if(istype(W, /obj/item/weapon/weldingtool))
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
|
||||
if(WT.remove_fuel(0, user))
|
||||
damage = 15
|
||||
playsound(src.loc, 'sound/items/Welder.ogg', 100, 1)
|
||||
|
||||
src.health -= damage
|
||||
src.healthcheck()
|
||||
|
||||
|
||||
/obj/effect/alien/egg/proc/healthcheck()
|
||||
if(health <= 0)
|
||||
Burst()
|
||||
|
||||
/obj/effect/alien/egg/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
if(exposed_temperature > 500 + T0C)
|
||||
health -= 5
|
||||
healthcheck()
|
||||
|
||||
/obj/effect/alien/egg/HasProximity(atom/movable/AM as mob|obj)
|
||||
if(status == GROWN)
|
||||
if(!CanHug(AM))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/C = AM
|
||||
if(C.stat == CONSCIOUS && C.status_flags & XENO_HOST)
|
||||
return
|
||||
|
||||
Burst(0)
|
||||
|
||||
@@ -4,14 +4,76 @@
|
||||
/obj/effect/effect/smoke/chem
|
||||
icon = 'icons/effects/chemsmoke.dmi'
|
||||
opacity = 0
|
||||
layer = 6
|
||||
time_to_live = 300
|
||||
pass_flags = PASSTABLE | PASSGRILLE | PASSGLASS //PASSGLASS is fine here, it's just so the visual effect can "flow" around glass
|
||||
var/splash_amount = 10 //atoms moving through a smoke cloud get splashed with up to 10 units of reagent
|
||||
var/turf/destination
|
||||
|
||||
/obj/effect/effect/smoke/chem/New(var/newloc, smoke_duration, turf/dest_turf = null, icon/cached_icon = null)
|
||||
time_to_live = smoke_duration
|
||||
|
||||
/obj/effect/effect/smoke/chem/New()
|
||||
..()
|
||||
create_reagents(500)
|
||||
return
|
||||
|
||||
create_reagents(500)
|
||||
|
||||
if(cached_icon)
|
||||
icon = cached_icon
|
||||
|
||||
set_dir(pick(cardinal))
|
||||
pixel_x = -32 + rand(-8, 8)
|
||||
pixel_y = -32 + rand(-8, 8)
|
||||
|
||||
//switching opacity on after the smoke has spawned, and then turning it off before it is deleted results in cleaner
|
||||
//lighting and view range updates (Is this still true with the new lighting system?)
|
||||
opacity = 1
|
||||
|
||||
//float over to our destination, if we have one
|
||||
destination = dest_turf
|
||||
if(destination)
|
||||
walk_to(src, destination)
|
||||
|
||||
/obj/effect/effect/smoke/chem/Destroy()
|
||||
opacity = 0
|
||||
fadeOut()
|
||||
..()
|
||||
|
||||
/obj/effect/effect/smoke/chem/Move()
|
||||
var/list/oldlocs = view(1, src)
|
||||
. = ..()
|
||||
if(.)
|
||||
for(var/turf/T in view(1, src) - oldlocs)
|
||||
for(var/atom/movable/AM in T)
|
||||
if(!istype(AM, /obj/effect/effect/smoke/chem))
|
||||
reagents.splash(AM, splash_amount, copy = 1)
|
||||
if(loc == destination)
|
||||
bound_width = 96
|
||||
bound_height = 96
|
||||
|
||||
/obj/effect/effect/smoke/chem/Crossed(atom/movable/AM)
|
||||
..()
|
||||
if(!istype(AM, /obj/effect/effect/smoke/chem))
|
||||
reagents.splash(AM, splash_amount, copy = 1)
|
||||
|
||||
/obj/effect/effect/smoke/chem/proc/initial_splash()
|
||||
for(var/turf/T in view(1, src))
|
||||
for(var/atom/movable/AM in T)
|
||||
if(!istype(AM, /obj/effect/effect/smoke/chem))
|
||||
reagents.splash(AM, splash_amount, copy = 1)
|
||||
|
||||
// Fades out the smoke smoothly using it's alpha variable.
|
||||
/obj/effect/effect/smoke/chem/proc/fadeOut(var/frames = 16)
|
||||
if(!alpha) return //already transparent
|
||||
|
||||
frames = max(frames, 1) //We will just assume that by 0 frames, the coder meant "during one frame".
|
||||
var/alpha_step = round(alpha / frames)
|
||||
while(alpha > 0)
|
||||
alpha = max(0, alpha - alpha_step)
|
||||
sleep(world.tick_lag)
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// Chem Smoke Effect System
|
||||
/////////////////////////////////////////////
|
||||
/datum/effect/effect/system/smoke_spread/chem
|
||||
smoke_type = /obj/effect/effect/smoke/chem
|
||||
var/obj/chemholder
|
||||
@@ -115,13 +177,21 @@
|
||||
else
|
||||
I = icon('icons/effects/96x96.dmi', "smoke")
|
||||
|
||||
//Calculate smoke duration
|
||||
var/smoke_duration = 150
|
||||
|
||||
var/pressure = 0
|
||||
var/datum/gas_mixture/environment = location.return_air()
|
||||
if(environment) pressure = environment.return_pressure()
|
||||
smoke_duration = between(5, smoke_duration*pressure/(ONE_ATMOSPHERE/3), smoke_duration)
|
||||
|
||||
var/const/arcLength = 2.3559 //distance between each smoke cloud
|
||||
|
||||
for(var/i = 0, i < range, i++) //calculate positions for smoke coverage - then spawn smoke
|
||||
var/radius = i * 1.5
|
||||
if(!radius)
|
||||
spawn(0)
|
||||
spawnSmoke(location, I, 1)
|
||||
spawnSmoke(location, I, 1, 1)
|
||||
continue
|
||||
|
||||
var/offset = 0
|
||||
@@ -146,43 +216,26 @@
|
||||
// Randomizes and spawns the smoke effect.
|
||||
// Also handles deleting the smoke once the effect is finished.
|
||||
//------------------------------------------
|
||||
/datum/effect/effect/system/smoke_spread/chem/proc/spawnSmoke(var/turf/T, var/icon/I, var/dist = 1, var/obj/effect/effect/smoke/chem/passed_smoke)
|
||||
/datum/effect/effect/system/smoke_spread/chem/proc/spawnSmoke(var/turf/T, var/icon/I, var/smoke_duration, var/dist = 1, var/splash_initial=0, var/obj/effect/effect/smoke/chem/passed_smoke)
|
||||
|
||||
var/obj/effect/effect/smoke/chem/smoke
|
||||
if(passed_smoke)
|
||||
smoke = passed_smoke
|
||||
else
|
||||
smoke = PoolOrNew(/obj/effect/effect/smoke/chem, location)
|
||||
smoke = PoolOrNew(/obj/effect/effect/smoke/chem, list(location, smoke_duration + rand(0, 20), T, I))
|
||||
|
||||
if(chemholder.reagents.reagent_list.len)
|
||||
chemholder.reagents.trans_to_obj(smoke, chemholder.reagents.total_volume / dist, copy = 1) //copy reagents to the smoke so mob/breathe() can handle inhaling the reagents
|
||||
smoke.icon = I
|
||||
smoke.layer = 6
|
||||
smoke.set_dir(pick(cardinal))
|
||||
smoke.pixel_x = -32 + rand(-8, 8)
|
||||
smoke.pixel_y = -32 + rand(-8, 8)
|
||||
walk_to(smoke, T)
|
||||
smoke.opacity = 1 //switching opacity on after the smoke has spawned, and then
|
||||
sleep(150+rand(0,20)) // turning it off before it is deleted results in cleaner
|
||||
smoke.opacity = 0 // lighting and view range updates
|
||||
fadeOut(smoke)
|
||||
qdel(src)
|
||||
|
||||
/datum/effect/effect/system/smoke_spread/chem/spores/spawnSmoke(var/turf/T, var/icon/I, var/dist = 1)
|
||||
//Kinda ugly, but needed unless the system is reworked
|
||||
if(splash_initial)
|
||||
smoke.initial_splash()
|
||||
|
||||
|
||||
/datum/effect/effect/system/smoke_spread/chem/spores/spawnSmoke(var/turf/T, var/smoke_duration, var/icon/I, var/dist = 1)
|
||||
var/obj/effect/effect/smoke/chem/spores = PoolOrNew(/obj/effect/effect/smoke/chem, location)
|
||||
spores.name = "cloud of [seed.seed_name] [seed.seed_noun]"
|
||||
..(T, I, dist, spores)
|
||||
|
||||
/datum/effect/effect/system/smoke_spread/chem/proc/fadeOut(var/atom/A, var/frames = 16) // Fades out the smoke smoothly using it's alpha variable.
|
||||
if(A.alpha == 0) //Handle already transparent case
|
||||
return
|
||||
if(frames == 0)
|
||||
frames = 1 //We will just assume that by 0 frames, the coder meant "during one frame".
|
||||
var/step = A.alpha / frames
|
||||
for(var/i = 0, i < frames, i++)
|
||||
A.alpha -= step
|
||||
sleep(world.tick_lag)
|
||||
return
|
||||
..(T, I, smoke_duration, dist, spores)
|
||||
|
||||
|
||||
/datum/effect/effect/system/smoke_spread/chem/proc/smokeFlow() // Smoke pathfinder. Uses a flood fill method based on zones to quickly check what turfs the smoke (airflow) can actually reach.
|
||||
|
||||
@@ -52,10 +52,6 @@
|
||||
prisonsecuritywarp += loc
|
||||
qdel(src)
|
||||
return
|
||||
if("blobstart")
|
||||
blobstart += loc
|
||||
qdel(src)
|
||||
return
|
||||
if("xeno_spawn")
|
||||
xeno_spawn += loc
|
||||
qdel(src)
|
||||
|
||||
@@ -105,27 +105,61 @@
|
||||
qdel(src)
|
||||
*/
|
||||
|
||||
/client/proc/spawn_tanktransferbomb()
|
||||
set category = "Debug"
|
||||
set desc = "Spawn a tank transfer valve bomb"
|
||||
set name = "Instant TTV"
|
||||
|
||||
if(!check_rights(R_SPAWN)) return
|
||||
|
||||
var/obj/effect/spawner/newbomb/proto = /obj/effect/spawner/newbomb/radio/custom
|
||||
|
||||
var/p = input("Enter phoron amount (mol):","Phoron", initial(proto.phoron_amt)) as num|null
|
||||
if(p == null) return
|
||||
|
||||
var/o = input("Enter oxygen amount (mol):","Oxygen", initial(proto.oxygen_amt)) as num|null
|
||||
if(o == null) return
|
||||
|
||||
var/c = input("Enter carbon dioxide amount (mol):","Carbon Dioxide", initial(proto.carbon_amt)) as num|null
|
||||
if(c == null) return
|
||||
|
||||
new /obj/effect/spawner/newbomb/radio/custom(get_turf(mob), p, o, c)
|
||||
|
||||
/obj/effect/spawner/newbomb
|
||||
name = "bomb"
|
||||
name = "TTV bomb"
|
||||
icon = 'icons/mob/screen1.dmi'
|
||||
icon_state = "x"
|
||||
var/btype = 0 // 0=radio, 1=prox, 2=time
|
||||
|
||||
timer
|
||||
btype = 2
|
||||
var/assembly_type = /obj/item/device/assembly/signaler
|
||||
|
||||
syndicate
|
||||
//Note that the maximum amount of gas you can put in a 70L air tank at 1013.25 kPa and 519K is 16.44 mol.
|
||||
var/phoron_amt = 10.96
|
||||
var/oxygen_amt = 16.44
|
||||
var/carbon_amt = 0.0
|
||||
|
||||
proximity
|
||||
btype = 1
|
||||
/obj/effect/spawner/newbomb/timer
|
||||
name = "TTV bomb - timer"
|
||||
assembly_type = /obj/item/device/assembly/timer
|
||||
|
||||
radio
|
||||
btype = 0
|
||||
/obj/effect/spawner/newbomb/timer/syndicate
|
||||
name = "TTV bomb - merc"
|
||||
//High yield bombs. Yes, it is possible to make these with toxins
|
||||
phoron_amt = 15.66
|
||||
oxygen_amt = 24.66
|
||||
|
||||
/obj/effect/spawner/newbomb/proximity
|
||||
name = "TTV bomb - proximity"
|
||||
assembly_type = /obj/item/device/assembly/prox_sensor
|
||||
|
||||
/obj/effect/spawner/newbomb/New()
|
||||
/obj/effect/spawner/newbomb/radio/custom/New(var/newloc, ph, ox, co)
|
||||
if(ph != null) phoron_amt = ph
|
||||
if(ox != null) oxygen_amt = ox
|
||||
if(co != null) carbon_amt = co
|
||||
..()
|
||||
|
||||
/obj/effect/spawner/newbomb/New(newloc)
|
||||
..(newloc)
|
||||
|
||||
var/obj/item/device/transfer_valve/V = new(src.loc)
|
||||
var/obj/item/weapon/tank/phoron/PT = new(V)
|
||||
var/obj/item/weapon/tank/oxygen/OT = new(V)
|
||||
@@ -137,28 +171,15 @@
|
||||
OT.master = V
|
||||
|
||||
PT.air_contents.temperature = PHORON_FLASHPOINT
|
||||
PT.air_contents.adjust_multi("phoron", 12, "carbon_dioxide", 8)
|
||||
PT.air_contents.gas["phoron"] = phoron_amt
|
||||
PT.air_contents.gas["carbon_dioxide"] = carbon_amt
|
||||
PT.air_contents.update_values()
|
||||
|
||||
OT.air_contents.temperature = PHORON_FLASHPOINT
|
||||
OT.air_contents.adjust_gas("oxygen", 20)
|
||||
OT.air_contents.gas["oxygen"] = oxygen_amt
|
||||
OT.air_contents.update_values()
|
||||
|
||||
var/obj/item/device/assembly/S
|
||||
|
||||
switch (src.btype)
|
||||
// radio
|
||||
if (0)
|
||||
|
||||
S = new/obj/item/device/assembly/signaler(V)
|
||||
|
||||
// proximity
|
||||
if (1)
|
||||
|
||||
S = new/obj/item/device/assembly/prox_sensor(V)
|
||||
|
||||
// timer
|
||||
if (2)
|
||||
|
||||
S = new/obj/item/device/assembly/timer(V)
|
||||
var/obj/item/device/assembly/S = new assembly_type(V)
|
||||
|
||||
|
||||
V.attached_device = S
|
||||
|
||||
@@ -438,6 +438,9 @@ var/list/global/slot_flags_enumeration = list(
|
||||
M.attack_log += "\[[time_stamp()]\]<font color='orange'> Attacked by [user.name] ([user.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])</font>"
|
||||
msg_admin_attack("[user.name] ([user.ckey]) attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)]) (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[user.x];Y=[user.y];Z=[user.z]'>JMP</a>)") //BS12 EDIT ALG
|
||||
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.do_attack_animation(M)
|
||||
|
||||
src.add_fingerprint(user)
|
||||
//if((CLUMSY in user.mutations) && prob(50))
|
||||
// M = user
|
||||
@@ -611,7 +614,3 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
|
||||
|
||||
/obj/item/proc/pwr_drain()
|
||||
return 0 // Process Kill
|
||||
|
||||
/obj/item/proc/resolve_attackby(atom/A, mob/source)
|
||||
return A.attackby(src,source)
|
||||
|
||||
|
||||
@@ -722,7 +722,8 @@ var/global/list/obj/item/device/pda/PDAs = list()
|
||||
if("Message")
|
||||
|
||||
var/obj/item/device/pda/P = locate(href_list["target"])
|
||||
src.create_message(U, P, !href_list["notap"])
|
||||
var/tap = istype(U, /mob/living/carbon)
|
||||
src.create_message(U, P, tap)
|
||||
if(mode == 2)
|
||||
if(href_list["target"] in conversations) // Need to make sure the message went through, if not welp.
|
||||
active_conversation = href_list["target"]
|
||||
@@ -1041,7 +1042,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
|
||||
new_message(sending_device, sending_device.owner, sending_device.ownjob, message)
|
||||
|
||||
/obj/item/device/pda/proc/new_message(var/sending_unit, var/sender, var/sender_job, var/message)
|
||||
var/reception_message = "\icon[src] <b>Message from [sender] ([sender_job]), </b>\"[message]\" (<a href='byond://?src=\ref[src];choice=Message;notap=[istype(loc, /mob/living/silicon)];skiprefresh=1;target=\ref[sending_unit]'>Reply</a>)"
|
||||
var/reception_message = "\icon[src] <b>Message from [sender] ([sender_job]), </b>\"[message]\" (<a href='byond://?src=\ref[src];choice=Message;skiprefresh=1;target=\ref[sending_unit]'>Reply</a>)"
|
||||
new_info(message_silent, ttone, reception_message)
|
||||
|
||||
log_pda("[usr] (PDA: [sending_unit]) sent \"[message]\" to [name]")
|
||||
@@ -1053,7 +1054,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
|
||||
if(ismob(sending_unit.loc) && isAI(loc))
|
||||
track = "(<a href='byond://?src=\ref[loc];track=\ref[sending_unit.loc];trackname=[html_encode(sender)]'>Follow</a>)"
|
||||
|
||||
var/reception_message = "\icon[src] <b>Message from [sender] ([sender_job]), </b>\"[message]\" (<a href='byond://?src=\ref[src];choice=Message;notap=1;skiprefresh=1;target=\ref[sending_unit]'>Reply</a>) [track]"
|
||||
var/reception_message = "\icon[src] <b>Message from [sender] ([sender_job]), </b>\"[message]\" (<a href='byond://?src=\ref[src];choice=Message;skiprefresh=1;target=\ref[sending_unit]'>Reply</a>) [track]"
|
||||
new_info(message_silent, newstone, reception_message)
|
||||
|
||||
log_pda("[usr] (PDA: [sending_unit]) sent \"[message]\" to [name]")
|
||||
|
||||
@@ -31,14 +31,17 @@
|
||||
last_used = world.time
|
||||
times_used = max(0,round(times_used)) //sanity
|
||||
|
||||
|
||||
/obj/item/device/flash/attack(mob/living/M as mob, mob/user as mob)
|
||||
//attack_as_weapon
|
||||
/obj/item/device/flash/attack(mob/living/M, mob/living/user, var/target_zone)
|
||||
if(!user || !M) return //sanity
|
||||
|
||||
M.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been flashed (attempt) with [src.name] by [user.name] ([user.ckey])</font>")
|
||||
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Used the [src.name] to flash [M.name] ([M.ckey])</font>")
|
||||
msg_admin_attack("[user.name] ([user.ckey]) Used the [src.name] to flash [M.name] ([M.ckey]) (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[user.x];Y=[user.y];Z=[user.z]'>JMP</a>)")
|
||||
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.do_attack_animation(M)
|
||||
|
||||
if(!clown_check(user)) return
|
||||
if(broken)
|
||||
user << "<span class='warning'>\The [src] is broken.</span>"
|
||||
@@ -65,8 +68,9 @@
|
||||
|
||||
if(iscarbon(M))
|
||||
if(M.stat!=DEAD)
|
||||
var/safety = M:eyecheck()
|
||||
if(safety <= 0)
|
||||
var/mob/living/carbon/C = M
|
||||
var/safety = C.eyecheck()
|
||||
if(safety < FLASH_PROTECTION_MODERATE)
|
||||
var/flash_strength = 10
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
@@ -112,6 +116,9 @@
|
||||
|
||||
/obj/item/device/flash/attack_self(mob/living/carbon/user as mob, flag = 0, emp = 0)
|
||||
if(!user || !clown_check(user)) return
|
||||
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
|
||||
if(broken)
|
||||
user.show_message("<span class='warning'>The [src.name] is broken</span>", 2)
|
||||
return
|
||||
@@ -150,8 +157,8 @@
|
||||
for(var/obj/item/weapon/cloaking_device/S in M)
|
||||
S.active = 0
|
||||
S.icon_state = "shield0"
|
||||
var/safety = M:eyecheck()
|
||||
if(!safety)
|
||||
var/safety = M.eyecheck()
|
||||
if(safety < FLASH_PROTECTION_MODERATE)
|
||||
if(!M.blinded)
|
||||
flick("flash", M.flash)
|
||||
|
||||
@@ -170,7 +177,7 @@
|
||||
if(istype(loc, /mob/living/carbon))
|
||||
var/mob/living/carbon/M = loc
|
||||
var/safety = M.eyecheck()
|
||||
if(safety <= 0)
|
||||
if(safety < FLASH_PROTECTION_MODERATE)
|
||||
M.Weaken(10)
|
||||
flick("e_flash", M.flash)
|
||||
for(var/mob/O in viewers(M, null))
|
||||
@@ -183,7 +190,8 @@
|
||||
icon_state = "sflash"
|
||||
origin_tech = list(TECH_MAGNET = 2, TECH_COMBAT = 1)
|
||||
|
||||
/obj/item/device/flash/synthetic/attack(mob/living/M as mob, mob/user as mob)
|
||||
//attack_as_weapon
|
||||
/obj/item/device/flash/synthetic/attack(mob/living/M, mob/living/user, var/target_zone)
|
||||
..()
|
||||
if(!broken)
|
||||
broken = 1
|
||||
|
||||
@@ -79,6 +79,8 @@
|
||||
user << "<span class='notice'>\The [M]'s pupils narrow slightly, but are still very dilated.</span>"
|
||||
else
|
||||
user << "<span class='notice'>\The [M]'s pupils narrow.</span>"
|
||||
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //can be used offensively
|
||||
flick("flash", M.flash)
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -83,58 +83,66 @@ var/global/list/default_medbay_channels = list(
|
||||
secure_radio_connections[ch_name] = radio_controller.add_object(src, radiochannels[ch_name], RADIO_CHAT)
|
||||
|
||||
/obj/item/device/radio/attack_ghost(mob/user)
|
||||
interact(user)
|
||||
return ui_interact(user)
|
||||
|
||||
/obj/item/device/radio/attack_self(mob/user as mob)
|
||||
user.set_machine(src)
|
||||
interact(user)
|
||||
|
||||
/obj/item/device/radio/interact(mob/user as mob)
|
||||
if(!on)
|
||||
return
|
||||
/obj/item/device/radio/interact(mob/user)
|
||||
if(!user)
|
||||
return 0
|
||||
|
||||
if(active_uplink_check(user))
|
||||
return
|
||||
if(b_stat)
|
||||
wires.Interact(user)
|
||||
|
||||
var/dat = "<html><head><title>[src]</title></head><body><TT>"
|
||||
return ui_interact(user)
|
||||
|
||||
if(!istype(src, /obj/item/device/radio/headset)) //Headsets dont get a mic button
|
||||
dat += "Microphone: [broadcasting ? "<A href='byond://?src=\ref[src];talk=0'>Engaged</A>" : "<A href='byond://?src=\ref[src];talk=1'>Disengaged</A>"]<BR>"
|
||||
/obj/item/device/radio/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
var/data[0]
|
||||
|
||||
dat += {"
|
||||
Speaker: [listening ? "<A href='byond://?src=\ref[src];listen=0'>Engaged</A>" : "<A href='byond://?src=\ref[src];listen=1'>Disengaged</A>"]<BR>
|
||||
Frequency:
|
||||
<A href='byond://?src=\ref[src];freq=-10'>-</A>
|
||||
<A href='byond://?src=\ref[src];freq=-2'>-</A>
|
||||
[format_frequency(frequency)]
|
||||
<A href='byond://?src=\ref[src];freq=2'>+</A>
|
||||
<A href='byond://?src=\ref[src];freq=10'>+</A><BR>
|
||||
"}
|
||||
data["mic_status"] = broadcasting
|
||||
data["speaker"] = listening
|
||||
data["freq"] = format_frequency(frequency)
|
||||
data["rawfreq"] = num2text(frequency)
|
||||
|
||||
dat+=list_channels(user)
|
||||
data["mic_cut"] = (wires.IsIndexCut(WIRE_TRANSMIT) || wires.IsIndexCut(WIRE_SIGNAL))
|
||||
data["spk_cut"] = (wires.IsIndexCut(WIRE_RECEIVE) || wires.IsIndexCut(WIRE_SIGNAL))
|
||||
|
||||
dat+={"[text_wires()]</TT></body></html>"}
|
||||
user << browse(dat, "window=radio")
|
||||
onclose(user, "radio")
|
||||
return
|
||||
var/list/chanlist = list_channels(user)
|
||||
if(islist(chanlist) && chanlist.len)
|
||||
data["chan_list"] = chanlist
|
||||
data["chan_list_len"] = chanlist.len
|
||||
|
||||
if(syndie)
|
||||
data["useSyndMode"] = 1
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "radio_basic.tmpl", "[name]", 400, 430)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
/obj/item/device/radio/proc/list_channels(var/mob/user)
|
||||
return list_internal_channels(user)
|
||||
|
||||
/obj/item/device/radio/proc/list_secure_channels(var/mob/user)
|
||||
var/dat = ""
|
||||
var/dat[0]
|
||||
|
||||
for(var/ch_name in channels)
|
||||
dat+=text_sec_channel(ch_name, channels[ch_name])
|
||||
var/chan_stat = channels[ch_name]
|
||||
var/listening = !!(chan_stat & FREQ_LISTENING) != 0
|
||||
|
||||
dat.Add(list(list("chan" = ch_name, "display_name" = ch_name, "secure_channel" = 1, "sec_channel_listen" = !listening, "chan_span" = frequency_span_class(radiochannels[ch_name]))))
|
||||
|
||||
return dat
|
||||
|
||||
/obj/item/device/radio/proc/list_internal_channels(var/mob/user)
|
||||
var/dat = ""
|
||||
var/dat[0]
|
||||
for(var/internal_chan in internal_channels)
|
||||
if(has_channel_access(user, internal_chan))
|
||||
dat+="<A href='byond://?src=\ref[src];spec_freq=[internal_chan]'>[get_frequency_name(text2num(internal_chan))]</A><br>"
|
||||
dat.Add(list(list("chan" = internal_chan, "display_name" = get_frequency_name(text2num(internal_chan)), "chan_span" = frequency_span_class(text2num(internal_chan)))))
|
||||
|
||||
if(dat)
|
||||
dat = "<br><b>Internal Channels</b><br>" + dat
|
||||
return dat
|
||||
|
||||
/obj/item/device/radio/proc/has_channel_access(var/mob/user, var/freq)
|
||||
@@ -172,9 +180,13 @@ var/global/list/default_medbay_channels = list(
|
||||
/obj/item/device/radio/proc/ToggleReception()
|
||||
listening = !listening && !(wires.IsIndexCut(WIRE_RECEIVE) || wires.IsIndexCut(WIRE_SIGNAL))
|
||||
|
||||
/obj/item/device/radio/CanUseTopic()
|
||||
if(!on)
|
||||
return STATUS_CLOSE
|
||||
return ..()
|
||||
|
||||
/obj/item/device/radio/Topic(href, href_list)
|
||||
if(..() || !on)
|
||||
usr << browse(null, "window=radio")
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
usr.set_machine(src)
|
||||
@@ -216,7 +228,7 @@ var/global/list/default_medbay_channels = list(
|
||||
return 1
|
||||
|
||||
if(.)
|
||||
interact(usr)
|
||||
nanomanager.update_uis(src)
|
||||
|
||||
/obj/item/device/radio/proc/autosay(var/message, var/from, var/channel) //BS12 EDIT
|
||||
var/datum/radio_frequency/connection = null
|
||||
@@ -683,31 +695,40 @@ var/global/list/default_medbay_channels = list(
|
||||
. = 1
|
||||
|
||||
if(.)
|
||||
interact(usr)
|
||||
nanomanager.update_uis(src)
|
||||
|
||||
/obj/item/device/radio/borg/interact(mob/user as mob)
|
||||
if(!on)
|
||||
return
|
||||
|
||||
var/dat = "<html><head><title>[src]</title></head><body><TT>"
|
||||
dat += {"
|
||||
Speaker: [listening ? "<A href='byond://?src=\ref[src];listen=0'>Engaged</A>" : "<A href='byond://?src=\ref[src];listen=1'>Disengaged</A>"]<BR>
|
||||
Frequency:
|
||||
<A href='byond://?src=\ref[src];freq=-10'>-</A>
|
||||
<A href='byond://?src=\ref[src];freq=-2'>-</A>
|
||||
[format_frequency(frequency)]
|
||||
<A href='byond://?src=\ref[src];freq=2'>+</A>
|
||||
<A href='byond://?src=\ref[src];freq=10'>+</A><BR>
|
||||
Broadcasting: [subspace_transmission ? "<A href='byond://?src=\ref[src];mode=0'>Disable</A>" : "<A href='byond://?src=\ref[src];mode=1'>Enable</A>"]<BR>
|
||||
Loudspeaker: [shut_up ? "<A href='byond://?src=\ref[src];shutup=0'>Enable</A>" : "<A href='byond://?src=\ref[src];shutup=1'>Disable</A>"]<BR>
|
||||
"}
|
||||
. = ..()
|
||||
|
||||
if(subspace_transmission)//Don't even bother if subspace isn't turned on
|
||||
dat+=list_channels(user)
|
||||
dat+={"[text_wires()]</TT></body></html>"}
|
||||
user << browse(dat, "window=radio")
|
||||
onclose(user, "radio")
|
||||
return
|
||||
/obj/item/device/radio/borg/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
var/data[0]
|
||||
|
||||
data["mic_status"] = broadcasting
|
||||
data["speaker"] = listening
|
||||
data["freq"] = format_frequency(frequency)
|
||||
data["rawfreq"] = num2text(frequency)
|
||||
|
||||
var/list/chanlist = list_channels(user)
|
||||
if(islist(chanlist) && chanlist.len)
|
||||
data["chan_list"] = chanlist
|
||||
data["chan_list_len"] = chanlist.len
|
||||
|
||||
if(syndie)
|
||||
data["useSyndMode"] = 1
|
||||
|
||||
data["has_loudspeaker"] = 1
|
||||
data["loudspeaker"] = !shut_up
|
||||
data["has_subspace"] = 1
|
||||
data["subspace"] = subspace_transmission
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "radio_basic.tmpl", "[name]", 400, 430)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
/obj/item/device/radio/proc/config(op)
|
||||
if(radio_controller)
|
||||
|
||||
@@ -100,17 +100,9 @@
|
||||
if (src.loc != usr)
|
||||
return 0
|
||||
if(tank_one && href_list["tankone"])
|
||||
split_gases()
|
||||
valve_open = 0
|
||||
tank_one.loc = get_turf(src)
|
||||
tank_one = null
|
||||
update_icon()
|
||||
remove_tank(tank_one)
|
||||
else if(tank_two && href_list["tanktwo"])
|
||||
split_gases()
|
||||
valve_open = 0
|
||||
tank_two.loc = get_turf(src)
|
||||
tank_two = null
|
||||
update_icon()
|
||||
remove_tank(tank_two)
|
||||
else if(href_list["open"])
|
||||
toggle_valve()
|
||||
else if(attached_device)
|
||||
@@ -149,29 +141,51 @@
|
||||
if(attached_device)
|
||||
overlays += "device"
|
||||
|
||||
/obj/item/device/transfer_valve/proc/remove_tank(obj/item/weapon/tank/T)
|
||||
if(tank_one == T)
|
||||
split_gases()
|
||||
tank_one = null
|
||||
else if(tank_two == T)
|
||||
split_gases()
|
||||
tank_two = null
|
||||
else
|
||||
return
|
||||
|
||||
T.loc = get_turf(src)
|
||||
update_icon()
|
||||
|
||||
/obj/item/device/transfer_valve/proc/merge_gases()
|
||||
if(valve_open)
|
||||
return
|
||||
tank_two.air_contents.volume += tank_one.air_contents.volume
|
||||
var/datum/gas_mixture/temp
|
||||
temp = tank_one.air_contents.remove_ratio(1)
|
||||
tank_two.air_contents.merge(temp)
|
||||
valve_open = 1
|
||||
|
||||
/obj/item/device/transfer_valve/proc/split_gases()
|
||||
if (!valve_open || !tank_one || !tank_two)
|
||||
if(!valve_open)
|
||||
return
|
||||
|
||||
valve_open = 0
|
||||
|
||||
if(deleted(tank_one) || deleted(tank_two))
|
||||
return
|
||||
|
||||
var/ratio1 = tank_one.air_contents.volume/tank_two.air_contents.volume
|
||||
var/datum/gas_mixture/temp
|
||||
temp = tank_two.air_contents.remove_ratio(ratio1)
|
||||
tank_one.air_contents.merge(temp)
|
||||
tank_two.air_contents.volume -= tank_one.air_contents.volume
|
||||
|
||||
|
||||
/*
|
||||
Exadv1: I know this isn't how it's going to work, but this was just to check
|
||||
it explodes properly when it gets a signal (and it does).
|
||||
*/
|
||||
|
||||
/obj/item/device/transfer_valve/proc/toggle_valve()
|
||||
if(valve_open==0 && (tank_one && tank_two))
|
||||
valve_open = 1
|
||||
if(!valve_open && (tank_one && tank_two))
|
||||
var/turf/bombturf = get_turf(src)
|
||||
var/area/A = get_area(bombturf)
|
||||
|
||||
@@ -197,15 +211,10 @@
|
||||
message_admins(log_str, 0, 1)
|
||||
log_game(log_str)
|
||||
merge_gases()
|
||||
spawn(20) // In case one tank bursts
|
||||
for (var/i=0,i<5,i++)
|
||||
src.update_icon()
|
||||
sleep(10)
|
||||
src.update_icon()
|
||||
|
||||
else if(valve_open==1 && (tank_one && tank_two))
|
||||
split_gases()
|
||||
valve_open = 0
|
||||
|
||||
src.update_icon()
|
||||
|
||||
// this doesn't do anything but the timer etc. expects it to be here
|
||||
|
||||
@@ -10,31 +10,20 @@
|
||||
icon = 'icons/obj/decals.dmi'
|
||||
icon_state = "shock"
|
||||
|
||||
/obj/item/borg/stun/attack(var/mob/living/M, var/mob/living/silicon/robot/user)
|
||||
|
||||
if(!istype(M))
|
||||
return
|
||||
|
||||
// How the Hell.
|
||||
/obj/item/borg/stun/apply_hit_effect(mob/living/M, mob/living/silicon/robot/user, var/hit_zone)
|
||||
if(!istype(user))
|
||||
var/mob/living/temp = user
|
||||
if(istype(temp))
|
||||
temp.drop_from_inventory(src)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
M.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been attacked with [src.name] by [user.name] ([user.ckey])</font>")
|
||||
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Used the [src.name] to attack [M.name] ([M.ckey])</font>")
|
||||
msg_admin_attack("[user.name] ([user.ckey]) used the [src.name] to attack [M.name] ([M.ckey]) (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[user.x];Y=[user.y];Z=[user.z]'>JMP</a>)")
|
||||
user.visible_message("<span class='danger'>\The [user] has prodded \the [M] with \a [src]!</span>")
|
||||
|
||||
if(!user.cell || !user.cell.checked_use(1250)) //Slightly more than a baton.
|
||||
user.visible_message("<span class='danger'>\The [user] has prodded \the [M] with its arm!</span>")
|
||||
return
|
||||
|
||||
if (M.stuttering < 5)
|
||||
M.stuttering = 5
|
||||
M.stun_effect_act(0, 70, check_zone(user.zone_sel.selecting), src)
|
||||
user.visible_message("<span class='danger'>\The [user] has prodded \the [M] with \a [src]!</span>")
|
||||
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
|
||||
|
||||
M.apply_effect(5, STUTTER)
|
||||
M.stun_effect_act(0, 70, check_zone(hit_zone), src)
|
||||
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
H.forcesay(hit_appends)
|
||||
|
||||
@@ -65,24 +65,42 @@
|
||||
var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting)
|
||||
|
||||
if(affecting.open == 0)
|
||||
if(!affecting.bandage())
|
||||
if(affecting.is_bandaged())
|
||||
user << "<span class='warning'>The wounds on [M]'s [affecting.name] have already been bandaged.</span>"
|
||||
return 1
|
||||
else
|
||||
user.visible_message("<span class='notice'>\The [user] starts treating [M]'s [affecting.name].</span>", \
|
||||
"<span class='notice'>You start treating [M]'s [affecting.name].</span>" )
|
||||
var/used = 0
|
||||
for (var/datum/wound/W in affecting.wounds)
|
||||
if (W.internal)
|
||||
continue
|
||||
if(W.bandaged)
|
||||
continue
|
||||
if(used == amount)
|
||||
break
|
||||
if(!do_mob(user, M, W.damage/5))
|
||||
user << "<span class='notice'>You must stand still to bandage wounds.</span>"
|
||||
break
|
||||
if (W.current_stage <= W.max_bleeding_stage)
|
||||
user.visible_message("<span class='notice'>\The [user] bandages [W.desc] on [M]'s [affecting.name].</span>", \
|
||||
"<span class='notice'>You bandage [W.desc] on [M]'s [affecting.name].</span>" )
|
||||
user.visible_message("<span class='notice'>\The [user] bandages \a [W.desc] on [M]'s [affecting.name].</span>", \
|
||||
"<span class='notice'>You bandage \a [W.desc] on [M]'s [affecting.name].</span>" )
|
||||
//H.add_side_effect("Itch")
|
||||
else if (istype(W,/datum/wound/bruise))
|
||||
user.visible_message("<span class='notice'>\The [user] places a bruise patch over [W.desc] on [M]'s [affecting.name].</span>", \
|
||||
"<span class='notice'>You place a bruise patch over [W.desc] on [M]'s [affecting.name].</span>" )
|
||||
user.visible_message("<span class='notice'>\The [user] places a bruise patch over \a [W.desc] on [M]'s [affecting.name].</span>", \
|
||||
"<span class='notice'>You place a bruise patch over \a [W.desc] on [M]'s [affecting.name].</span>" )
|
||||
else
|
||||
user.visible_message("<span class='notice'>\The [user] places a bandaid over [W.desc] on [M]'s [affecting.name].</span>", \
|
||||
"<span class='notice'>You place a bandaid over [W.desc] on [M]'s [affecting.name].</span>" )
|
||||
use(1)
|
||||
user.visible_message("<span class='notice'>\The [user] places a bandaid over \a [W.desc] on [M]'s [affecting.name].</span>", \
|
||||
"<span class='notice'>You place a bandaid over \a [W.desc] on [M]'s [affecting.name].</span>" )
|
||||
W.bandage()
|
||||
used++
|
||||
affecting.update_damages()
|
||||
if(used == amount)
|
||||
if(affecting.is_bandaged())
|
||||
user << "<span class='warning'>\The [src] is used up.</span>"
|
||||
else
|
||||
user << "<span class='warning'>\The [src] is used up, but there are more wounds to treat on \the [affecting.name].</span>"
|
||||
use(used)
|
||||
else
|
||||
if (can_operate(H)) //Checks if mob is lying down on table for surgery
|
||||
if (do_surgery(H,user,src))
|
||||
@@ -108,13 +126,19 @@
|
||||
var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting)
|
||||
|
||||
if(affecting.open == 0)
|
||||
if(!affecting.salve())
|
||||
if(affecting.is_salved())
|
||||
user << "<span class='warning'>The wounds on [M]'s [affecting.name] have already been salved.</span>"
|
||||
return 1
|
||||
else
|
||||
user.visible_message("<span class='notice'>[user] salves wounds on [M]'s [affecting.name].</span>", \
|
||||
"<span class='notice'>You salve wounds on [M]'s [affecting.name].</span>" )
|
||||
user.visible_message("<span class='notice'>\The [user] starts salving wounds on [M]'s [affecting.name].</span>", \
|
||||
"<span class='notice'>You start salving the wounds on [M]'s [affecting.name].</span>" )
|
||||
if(!do_mob(user, M, 10))
|
||||
user << "<span class='notice'>You must stand still to salve wounds.</span>"
|
||||
return 1
|
||||
user.visible_message("<span class='notice'>[user] salved wounds on [M]'s [affecting.name].</span>", \
|
||||
"<span class='notice'>You salved wounds on [M]'s [affecting.name].</span>" )
|
||||
use(1)
|
||||
affecting.salve()
|
||||
else
|
||||
if (can_operate(H)) //Checks if mob is lying down on table for surgery
|
||||
if (do_surgery(H,user,src))
|
||||
@@ -127,7 +151,7 @@
|
||||
singular_name = "advanced trauma kit"
|
||||
desc = "An advanced trauma kit for severe injuries."
|
||||
icon_state = "traumakit"
|
||||
heal_brute = 12
|
||||
heal_brute = 0
|
||||
origin_tech = list(TECH_BIO = 1)
|
||||
|
||||
/obj/item/stack/medical/advanced/bruise_pack/attack(mob/living/carbon/M as mob, mob/user as mob)
|
||||
@@ -139,29 +163,44 @@
|
||||
var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting)
|
||||
|
||||
if(affecting.open == 0)
|
||||
var/bandaged = affecting.bandage()
|
||||
var/disinfected = affecting.disinfect()
|
||||
|
||||
if(!(bandaged || disinfected))
|
||||
if(affecting.is_bandaged() && affecting.is_disinfected())
|
||||
user << "<span class='warning'>The wounds on [M]'s [affecting.name] have already been treated.</span>"
|
||||
return 1
|
||||
else
|
||||
user.visible_message("<span class='notice'>\The [user] starts treating [M]'s [affecting.name].</span>", \
|
||||
"<span class='notice'>You start treating [M]'s [affecting.name].</span>" )
|
||||
var/used = 0
|
||||
for (var/datum/wound/W in affecting.wounds)
|
||||
if (W.internal)
|
||||
continue
|
||||
if (W.bandaged && W.disinfected)
|
||||
continue
|
||||
if(used == amount)
|
||||
break
|
||||
if(!do_mob(user, M, W.damage/5))
|
||||
user << "<span class='notice'>You must stand still to bandage wounds.</span>"
|
||||
break
|
||||
if (W.current_stage <= W.max_bleeding_stage)
|
||||
user.visible_message("<span class='notice'>\The [user] cleans [W.desc] on [M]'s [affecting.name] and seals the edges with bioglue.</span>", \
|
||||
"<span class='notice'>You clean and seal [W.desc] on [M]'s [affecting.name].</span>" )
|
||||
user.visible_message("<span class='notice'>\The [user] cleans \a [W.desc] on [M]'s [affecting.name] and seals the edges with bioglue.</span>", \
|
||||
"<span class='notice'>You clean and seal \a [W.desc] on [M]'s [affecting.name].</span>" )
|
||||
//H.add_side_effect("Itch")
|
||||
else if (istype(W,/datum/wound/bruise))
|
||||
user.visible_message("<span class='notice'>\The [user] places a medical patch over [W.desc] on [M]'s [affecting.name].</span>", \
|
||||
"<span class='notice'>You place a medical patch over [W.desc] on [M]'s [affecting.name].</span>" )
|
||||
user.visible_message("<span class='notice'>\The [user] places a medical patch over \a [W.desc] on [M]'s [affecting.name].</span>", \
|
||||
"<span class='notice'>You place a medical patch over \a [W.desc] on [M]'s [affecting.name].</span>" )
|
||||
else
|
||||
user.visible_message("<span class='notice'>\The [user] smears some bioglue over [W.desc] on [M]'s [affecting.name].</span>", \
|
||||
"<span class='notice'>You smear some bioglue over [W.desc] on [M]'s [affecting.name].</span>" )
|
||||
if (bandaged)
|
||||
affecting.heal_damage(heal_brute,0)
|
||||
use(1)
|
||||
user.visible_message("<span class='notice'>\The [user] smears some bioglue over \a [W.desc] on [M]'s [affecting.name].</span>", \
|
||||
"<span class='notice'>You smear some bioglue over \a [W.desc] on [M]'s [affecting.name].</span>" )
|
||||
W.bandage()
|
||||
W.disinfect()
|
||||
W.heal_damage(heal_brute)
|
||||
used++
|
||||
affecting.update_damages()
|
||||
if(used == amount)
|
||||
if(affecting.is_bandaged())
|
||||
user << "<span class='warning'>\The [src] is used up.</span>"
|
||||
else
|
||||
user << "<span class='warning'>\The [src] is used up, but there are more wounds to treat on \the [affecting.name].</span>"
|
||||
use(used)
|
||||
else
|
||||
if (can_operate(H)) //Checks if mob is lying down on table for surgery
|
||||
if (do_surgery(H,user,src))
|
||||
@@ -174,7 +213,7 @@
|
||||
singular_name = "advanced burn kit"
|
||||
desc = "An advanced treatment kit for severe burns."
|
||||
icon_state = "burnkit"
|
||||
heal_burn = 12
|
||||
heal_burn = 0
|
||||
origin_tech = list(TECH_BIO = 1)
|
||||
|
||||
|
||||
@@ -187,14 +226,20 @@
|
||||
var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting)
|
||||
|
||||
if(affecting.open == 0)
|
||||
if(!affecting.salve())
|
||||
if(affecting.is_salved())
|
||||
user << "<span class='warning'>The wounds on [M]'s [affecting.name] have already been salved.</span>"
|
||||
return 1
|
||||
else
|
||||
user.visible_message("<span class='notice'>\The [user] starts salving wounds on [M]'s [affecting.name].</span>", \
|
||||
"<span class='notice'>You start salving the wounds on [M]'s [affecting.name].</span>" )
|
||||
if(!do_mob(user, M, 10))
|
||||
user << "<span class='notice'>You must stand still to salve wounds.</span>"
|
||||
return 1
|
||||
user.visible_message( "<span class='notice'>[user] covers wounds on [M]'s [affecting.name] with regenerative membrane.</span>", \
|
||||
"<span class='notice'>You cover wounds on [M]'s [affecting.name] with regenerative membrane.</span>" )
|
||||
affecting.heal_damage(0,heal_burn)
|
||||
use(1)
|
||||
affecting.salve()
|
||||
else
|
||||
if (can_operate(H)) //Checks if mob is lying down on table for surgery
|
||||
if (do_surgery(H,user,src))
|
||||
|
||||
@@ -137,6 +137,7 @@
|
||||
if (istype(O, /obj/item/stack))
|
||||
var/obj/item/stack/S = O
|
||||
S.amount = produced
|
||||
S.add_to_stacks(user)
|
||||
|
||||
if (istype(O, /obj/item/weapon/storage)) //BubbleWrap - so newly formed boxes are empty
|
||||
for (var/obj/item/I in O)
|
||||
@@ -191,7 +192,7 @@
|
||||
else
|
||||
if(get_amount() < used)
|
||||
return 0
|
||||
for(var/i = 1 to uses_charge)
|
||||
for(var/i = 1 to charge_costs.len)
|
||||
var/datum/matter_synth/S = synths[i]
|
||||
S.use_charge(charge_costs[i] * used) // Doesn't need to be deleted
|
||||
return 1
|
||||
@@ -264,8 +265,8 @@
|
||||
return 0
|
||||
var/datum/matter_synth/S = synths[1]
|
||||
. = round(S.get_charge() / charge_costs[1])
|
||||
if(uses_charge > 1)
|
||||
for(var/i = 2 to uses_charge)
|
||||
if(charge_costs.len > 1)
|
||||
for(var/i = 2 to charge_costs.len)
|
||||
S = synths[i]
|
||||
. = min(., round(S.get_charge() / charge_costs[i]))
|
||||
return
|
||||
@@ -284,13 +285,13 @@
|
||||
return
|
||||
return max_amount
|
||||
|
||||
/obj/item/stack/proc/add_to_stacks(mob/usr as mob)
|
||||
for (var/obj/item/stack/item in usr.loc)
|
||||
/obj/item/stack/proc/add_to_stacks(mob/user as mob)
|
||||
for (var/obj/item/stack/item in user.loc)
|
||||
if (item==src)
|
||||
continue
|
||||
var/transfer = src.transfer_to(item)
|
||||
if (transfer)
|
||||
usr << "You add a new [item.singular_name] to the stack. It now contains [item.amount] [item.singular_name]\s."
|
||||
user << "<span class='notice'>You add a new [item.singular_name] to the stack. It now contains [item.amount] [item.singular_name]\s.</span>"
|
||||
if(!amount)
|
||||
break
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
var/uses = 10
|
||||
|
||||
/obj/item/weapon/card/emag/resolve_attackby(atom/A, mob/user)
|
||||
var/used_uses = A.emag_act(uses, user)
|
||||
var/used_uses = A.emag_act(uses, user, src)
|
||||
if(used_uses < 0)
|
||||
return ..(A, user)
|
||||
|
||||
|
||||
@@ -5,23 +5,131 @@
|
||||
/obj/item/weapon/circuitboard/air_management
|
||||
name = T_BOARD("atmosphere monitoring console")
|
||||
build_path = /obj/machinery/computer/general_air_control
|
||||
var/console_name
|
||||
var/frequency = 1439
|
||||
var/list/sensors = list()
|
||||
var/list/sensor_information = list()
|
||||
|
||||
/obj/item/weapon/circuitboard/air_management/tank_control
|
||||
name = T_BOARD("tank control")
|
||||
build_path = /obj/machinery/computer/general_air_control/large_tank_control
|
||||
frequency = 1441
|
||||
var/input_tag
|
||||
var/output_tag
|
||||
|
||||
var/list/input_info = list()
|
||||
var/list/output_info = list()
|
||||
|
||||
var/input_flow_setting = 200
|
||||
var/pressure_setting = ONE_ATMOSPHERE * 45
|
||||
|
||||
/obj/item/weapon/circuitboard/air_management/supermatter_core
|
||||
name = T_BOARD("core control")
|
||||
build_path = /obj/machinery/computer/general_air_control/supermatter_core
|
||||
frequency = 1438
|
||||
var/input_tag
|
||||
var/output_tag
|
||||
|
||||
var/list/input_info = list()
|
||||
var/list/output_info = list()
|
||||
|
||||
var/input_flow_setting = 700
|
||||
var/pressure_setting = 100
|
||||
|
||||
/obj/item/weapon/circuitboard/air_management/injector_control
|
||||
name = T_BOARD("injector control")
|
||||
build_path = /obj/machinery/computer/general_air_control/fuel_injection
|
||||
var/device_tag
|
||||
var/list/device_info
|
||||
var/automation = 0
|
||||
var/cutoff_temperature = 2000
|
||||
var/on_temperature = 1200
|
||||
|
||||
/************
|
||||
* Construct *
|
||||
************/
|
||||
/obj/item/weapon/circuitboard/air_management/construct(var/obj/machinery/computer/general_air_control/C)
|
||||
if (..(C))
|
||||
C.frequency = frequency
|
||||
if(console_name)
|
||||
C.name = console_name
|
||||
C.set_frequency(frequency)
|
||||
C.sensors = sensors.Copy()
|
||||
C.sensor_information = sensor_information.Copy()
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/circuitboard/air_management/tank_control/construct(var/obj/machinery/computer/general_air_control/large_tank_control/LTC)
|
||||
if(..(LTC))
|
||||
LTC.input_tag = input_tag
|
||||
LTC.output_tag = output_tag
|
||||
|
||||
LTC.input_info = input_info.Copy()
|
||||
LTC.output_info = output_info.Copy()
|
||||
|
||||
LTC.input_flow_setting = input_flow_setting
|
||||
LTC.pressure_setting = pressure_setting
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/circuitboard/air_management/supermatter_core/construct(var/obj/machinery/computer/general_air_control/supermatter_core/SC)
|
||||
if(..(SC))
|
||||
SC.input_tag = input_tag
|
||||
SC.output_tag = output_tag
|
||||
|
||||
SC.input_info = input_info.Copy()
|
||||
SC.output_info = output_info.Copy()
|
||||
|
||||
SC.input_flow_setting = input_flow_setting
|
||||
SC.pressure_setting = input_flow_setting
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/circuitboard/air_management/injector_control/construct(var/obj/machinery/computer/general_air_control/fuel_injection/FI)
|
||||
if(..(FI))
|
||||
FI.device_tag = device_tag
|
||||
FI.device_info = device_info.Copy()
|
||||
FI.automation = automation
|
||||
FI.cutoff_temperature = cutoff_temperature
|
||||
FI.on_temperature = on_temperature
|
||||
return 1
|
||||
|
||||
/**************
|
||||
* Deconstruct *
|
||||
**************/
|
||||
/obj/item/weapon/circuitboard/air_management/deconstruct(var/obj/machinery/computer/general_air_control/C)
|
||||
if (..(C))
|
||||
console_name = C.name
|
||||
frequency = C.frequency
|
||||
sensors = C.sensors.Copy()
|
||||
sensor_information = C.sensor_information.Copy()
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/circuitboard/air_management/tank_control/deconstruct(var/obj/machinery/computer/general_air_control/large_tank_control/LTC)
|
||||
if(..(LTC))
|
||||
input_tag = LTC.input_tag
|
||||
output_tag = LTC.output_tag
|
||||
|
||||
input_info = LTC.input_info.Copy()
|
||||
output_info = LTC.output_info.Copy()
|
||||
|
||||
input_flow_setting = LTC.input_flow_setting
|
||||
pressure_setting = LTC.pressure_setting
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/circuitboard/air_management/supermatter_core/deconstruct(var/obj/machinery/computer/general_air_control/supermatter_core/SC)
|
||||
if(..(SC))
|
||||
input_tag = SC.input_tag
|
||||
output_tag = SC.output_tag
|
||||
|
||||
input_info = SC.input_info.Copy()
|
||||
output_info = SC.output_info.Copy()
|
||||
|
||||
input_flow_setting = SC.input_flow_setting
|
||||
pressure_setting = SC.input_flow_setting
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/circuitboard/air_management/injector_control/deconstruct(var/obj/machinery/computer/general_air_control/fuel_injection/FI)
|
||||
if(..(FI))
|
||||
device_tag = FI.device_tag
|
||||
device_info = FI.device_info.Copy()
|
||||
automation = FI.automation
|
||||
cutoff_temperature = FI.cutoff_temperature
|
||||
on_temperature = FI.on_temperature
|
||||
return 1
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef T_BOARD
|
||||
#error T_BOARD macro is not defined but we need it!
|
||||
#endif
|
||||
|
||||
/obj/item/weapon/circuitboard/holodeckcontrol
|
||||
name = T_BOARD("holodeck control console")
|
||||
build_path = /obj/machinery/computer/HolodeckControl
|
||||
origin_tech = "programming=2;bluespace=2"
|
||||
var/last_to_emag
|
||||
var/linkedholodeck_area
|
||||
var/list/supported_programs
|
||||
var/list/restricted_programs
|
||||
|
||||
/obj/item/weapon/circuitboard/holodeckcontrol/construct(var/obj/machinery/computer/HolodeckControl/HC)
|
||||
if (..(HC))
|
||||
HC.supported_programs = supported_programs.Copy()
|
||||
HC.restricted_programs = restricted_programs.Copy()
|
||||
if(linkedholodeck_area)
|
||||
HC.linkedholodeck = locate(linkedholodeck_area)
|
||||
if(last_to_emag)
|
||||
HC.last_to_emag = last_to_emag
|
||||
HC.emagged = 1
|
||||
HC.safety_disabled = 1
|
||||
|
||||
/obj/item/weapon/circuitboard/holodeckcontrol/deconstruct(var/obj/machinery/computer/HolodeckControl/HC)
|
||||
if (..(HC))
|
||||
linkedholodeck_area = HC.linkedholodeck_area
|
||||
supported_programs = HC.supported_programs.Copy()
|
||||
restricted_programs = HC.restricted_programs.Copy()
|
||||
last_to_emag = HC.last_to_emag
|
||||
HC.emergencyShutdown()
|
||||
@@ -38,9 +38,11 @@
|
||||
target.clean_blood()
|
||||
return
|
||||
|
||||
/obj/item/weapon/soap/attack(mob/target as mob, mob/user as mob)
|
||||
//attack_as_weapon
|
||||
/obj/item/weapon/soap/attack(mob/living/target, mob/living/user, var/target_zone)
|
||||
if(target && user && ishuman(target) && ishuman(user) && !target.stat && !user.stat && user.zone_sel &&user.zone_sel.selecting == "mouth" )
|
||||
user.visible_message("<span class='danger'>\The [user] washes \the [target]'s mouth out with soap!</span>")
|
||||
user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) //prevent spam
|
||||
return
|
||||
..()
|
||||
|
||||
|
||||
@@ -114,6 +114,9 @@
|
||||
if(!do_after(user,50))
|
||||
return
|
||||
|
||||
user.setClickCooldown(DEFAULT_QUICK_COOLDOWN)
|
||||
user.do_attack_animation(M)
|
||||
|
||||
M.visible_message("<span class='danger'>\The [M] has been injected with \the [src] by \the [user].</span>")
|
||||
|
||||
var/mob/living/carbon/human/H = M
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
if (ismob(target) || istype(target, /turf/unsimulated) || istype(target, /turf/simulated/shuttle) || istype(target, /obj/item/weapon/storage/) || istype(target, /obj/item/clothing/accessory/storage/) || istype(target, /obj/item/clothing/under))
|
||||
return
|
||||
user << "Planting explosives..."
|
||||
user.do_attack_animation(target)
|
||||
|
||||
if(do_after(user, 50) && in_range(user, target))
|
||||
user.drop_item()
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/a_gift/attack_self(mob/M as mob)
|
||||
var/gift_type = pick(/obj/item/weapon/sord,
|
||||
var/gift_type = pick(
|
||||
/obj/item/weapon/storage/wallet,
|
||||
/obj/item/weapon/storage/photo_album,
|
||||
/obj/item/weapon/storage/box/snappops,
|
||||
@@ -80,7 +80,6 @@
|
||||
/obj/item/weapon/bikehorn,
|
||||
/obj/item/weapon/beach_ball,
|
||||
/obj/item/weapon/beach_ball/holoball,
|
||||
/obj/item/weapon/banhammer,
|
||||
/obj/item/toy/balloon,
|
||||
/obj/item/toy/blink,
|
||||
/obj/item/toy/crossbow,
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
ear_safety += 1
|
||||
|
||||
//Flashing everyone
|
||||
if(eye_safety < 1)
|
||||
if(eye_safety < FLASH_PROTECTION_MODERATE)
|
||||
flick("e_flash", M.flash)
|
||||
M.Stun(2)
|
||||
M.Weaken(10)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
var/turf/T = get_turf(src)
|
||||
playsound(T, 'sound/effects/phasein.ogg', 100, 1)
|
||||
for(var/mob/living/carbon/human/M in viewers(T, null))
|
||||
if(M:eyecheck() <= 0)
|
||||
if(M.eyecheck() < FLASH_PROTECTION_MODERATE)
|
||||
flick("e_flash", M.flash)
|
||||
|
||||
for(var/i=1, i<=deliveryamt, i++)
|
||||
|
||||
@@ -73,6 +73,9 @@
|
||||
msg_admin_attack("[key_name(user)] attempted to handcuff [key_name(H)]")
|
||||
feedback_add_details("handcuffs","H")
|
||||
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.do_attack_animation(H)
|
||||
|
||||
user.visible_message("<span class='danger'>\The [user] has put [cuff_type] on \the [H]!</span>")
|
||||
|
||||
// Apply cuffs.
|
||||
|
||||
@@ -30,18 +30,18 @@
|
||||
if (!istype(M, /mob/living/carbon))
|
||||
return
|
||||
if (user && src.imp)
|
||||
for (var/mob/O in viewers(M, null))
|
||||
O.show_message("<span class='warning'>[user] is attemping to implant [M].</span>", 1)
|
||||
M.visible_message("<span class='warning'>[user] is attemping to implant [M].</span>")
|
||||
|
||||
user.setClickCooldown(DEFAULT_QUICK_COOLDOWN)
|
||||
user.do_attack_animation(M)
|
||||
|
||||
var/turf/T1 = get_turf(M)
|
||||
if (T1 && ((M == user) || do_after(user, 50)))
|
||||
if(user && M && (get_turf(M) == T1) && src && src.imp)
|
||||
for (var/mob/O in viewers(M, null))
|
||||
O.show_message("<span class='warning'>[M] has been implanted by [user].</span>", 1)
|
||||
M.visible_message("<span class='warning'>[M] has been implanted by [user].</span>")
|
||||
|
||||
admin_attack_log(user, M, "Implanted using \the [src.name] ([src.imp.name])", "Implanted with \the [src.name] ([src.imp.name])", "used an implanter, [src.name] ([src.imp.name]), on")
|
||||
|
||||
user.show_message("<span class='warning'>You implanted the implant into [M].</span>")
|
||||
if(src.imp.implanted(M))
|
||||
src.imp.loc = M
|
||||
src.imp.imp_in = M
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
if(!M.can_eat(src))
|
||||
return
|
||||
|
||||
if (reagents.total_volume > 0)
|
||||
reagents.trans_to_mob(M, reagents.total_volume, CHEM_INGEST)
|
||||
if(M == user)
|
||||
@@ -82,13 +85,6 @@
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/material/kitchen/utensil/knife/attack(target as mob, mob/living/user as mob)
|
||||
if ((CLUMSY in user.mutations) && prob(50))
|
||||
user << "<span class='warning'>You somehow managed to cut yourself with the [src].</span>"
|
||||
user.take_organ_damage(20)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/material/kitchen/utensil/knife/plastic
|
||||
default_material = "plastic"
|
||||
|
||||
@@ -108,6 +104,7 @@
|
||||
/obj/item/weapon/material/kitchen/rollingpin/attack(mob/living/M as mob, mob/living/user as mob)
|
||||
if ((CLUMSY in user.mutations) && prob(50))
|
||||
user << "<span class='warning'>The [src] slips out of your hand and hits your head.</span>"
|
||||
user.drop_from_inventory(src)
|
||||
user.take_organ_damage(10)
|
||||
user.Paralyse(2)
|
||||
return
|
||||
|
||||
@@ -64,9 +64,8 @@
|
||||
processing_objects -= src
|
||||
..()
|
||||
|
||||
/obj/item/weapon/material/attack()
|
||||
if(!..())
|
||||
return
|
||||
/obj/item/weapon/material/apply_hit_effect()
|
||||
..()
|
||||
if(!unbreakable)
|
||||
if(material.is_brittle())
|
||||
health = 0
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "hoe"
|
||||
item_state = "hoe"
|
||||
flags = CONDUCT | NOBLUDGEON
|
||||
force_divisor = 0.25 // 5 with weight 20 (steel)
|
||||
thrown_force_divisor = 0.25 // as above
|
||||
w_class = 2
|
||||
|
||||
@@ -18,6 +18,7 @@ var/list/tape_roll_applications = list()
|
||||
anchored = 1
|
||||
var/lifted = 0
|
||||
var/crumpled = 0
|
||||
var/tape_dir = 0
|
||||
var/icon_base
|
||||
|
||||
/obj/item/tape/New()
|
||||
@@ -32,7 +33,7 @@ var/list/tape_roll_applications = list()
|
||||
/obj/item/taperoll/police
|
||||
name = "police tape"
|
||||
desc = "A roll of police tape used to block off crime scenes from the public."
|
||||
icon_state = "police_start"
|
||||
icon_state = "police"
|
||||
tape_type = /obj/item/tape/police
|
||||
icon_base = "police"
|
||||
|
||||
@@ -45,7 +46,7 @@ var/list/tape_roll_applications = list()
|
||||
/obj/item/taperoll/engineering
|
||||
name = "engineering tape"
|
||||
desc = "A roll of engineering tape used to block off working areas from the public."
|
||||
icon_state = "engineering_start"
|
||||
icon_state = "engineering"
|
||||
tape_type = /obj/item/tape/engineering
|
||||
icon_base = "engineering"
|
||||
|
||||
@@ -55,58 +56,146 @@ var/list/tape_roll_applications = list()
|
||||
req_one_access = list(access_engine,access_atmospherics)
|
||||
icon_base = "engineering"
|
||||
|
||||
/obj/item/taperoll/atmos
|
||||
name = "atmospherics tape"
|
||||
desc = "A roll of atmospherics tape used to block off working areas from the public."
|
||||
icon_state = "atmos"
|
||||
tape_type = /obj/item/tape/atmos
|
||||
icon_base = "atmos"
|
||||
|
||||
/obj/item/tape/atmos
|
||||
name = "atmospherics tape"
|
||||
desc = "A length of atmospherics tape. Better not cross it."
|
||||
req_one_access = list(access_engine,access_atmospherics)
|
||||
icon_base = "atmos"
|
||||
|
||||
/obj/item/taperoll/update_icon()
|
||||
overlays.Cut()
|
||||
if(ismob(loc))
|
||||
if(!start)
|
||||
overlays += "start"
|
||||
else
|
||||
overlays += "stop"
|
||||
|
||||
/obj/item/taperoll/dropped(mob/user)
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
/obj/item/taperoll/pickup(mob/user)
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
/obj/item/taperoll/attack_self(mob/user as mob)
|
||||
if(icon_state == "[icon_base]_start")
|
||||
if(!start)
|
||||
start = get_turf(src)
|
||||
usr << "<span class='notice'>You place the first end of \the [src].</span>"
|
||||
icon_state = "[icon_base]_stop"
|
||||
update_icon()
|
||||
else
|
||||
icon_state = "[icon_base]_start"
|
||||
end = get_turf(src)
|
||||
if(start.y != end.y && start.x != end.x || start.z != end.z)
|
||||
start = null
|
||||
update_icon()
|
||||
usr << "<span class='notice'>\The [src] can only be laid horizontally or vertically.</span>"
|
||||
return
|
||||
|
||||
var/turf/cur = start
|
||||
var/dir
|
||||
if (start.x == end.x)
|
||||
var/d = end.y-start.y
|
||||
if(d) d = d/abs(d)
|
||||
end = get_turf(locate(end.x,end.y+d,end.z))
|
||||
dir = "v"
|
||||
if(start == end)
|
||||
// spread tape in all directions, provided there is a wall/window
|
||||
var/turf/T
|
||||
var/possible_dirs = 0
|
||||
for(var/dir in cardinal)
|
||||
T = get_step(start, dir)
|
||||
if(T && T.density)
|
||||
possible_dirs += dir
|
||||
else
|
||||
var/d = end.x-start.x
|
||||
if(d) d = d/abs(d)
|
||||
end = get_turf(locate(end.x+d,end.y,end.z))
|
||||
dir = "h"
|
||||
for(var/obj/structure/window/W in T)
|
||||
if(W.is_fulltile() || W.dir == reverse_dir[dir])
|
||||
possible_dirs += dir
|
||||
if(!possible_dirs)
|
||||
start = null
|
||||
update_icon()
|
||||
usr << "<span class='notice'>You can't place \the [src] here.</span>"
|
||||
return
|
||||
if(possible_dirs & (NORTH|SOUTH))
|
||||
var/obj/item/tape/TP = new tape_type(start)
|
||||
for(var/dir in list(NORTH, SOUTH))
|
||||
if (possible_dirs & dir)
|
||||
TP.tape_dir += dir
|
||||
TP.icon_state = "[TP.icon_base]_[TP.tape_dir]"
|
||||
if(possible_dirs & (EAST|WEST))
|
||||
var/obj/item/tape/TP = new tape_type(start)
|
||||
for(var/dir in list(EAST, WEST))
|
||||
if (possible_dirs & dir)
|
||||
TP.tape_dir += dir
|
||||
TP.icon_state = "[TP.icon_base]_[TP.tape_dir]"
|
||||
start = null
|
||||
update_icon()
|
||||
usr << "<span class='notice'>You finish placing \the [src].</span>"
|
||||
return
|
||||
|
||||
var/turf/cur = start
|
||||
var/orientation = get_dir(start, end)
|
||||
var/dir = 0
|
||||
switch(orientation)
|
||||
if(NORTH, SOUTH) dir = NORTH|SOUTH // North-South taping
|
||||
if(EAST, WEST) dir = EAST|WEST // East-West taping
|
||||
|
||||
var/can_place = 1
|
||||
while (cur!=end && can_place)
|
||||
while (can_place)
|
||||
if(cur.density == 1)
|
||||
can_place = 0
|
||||
else if (istype(cur, /turf/space))
|
||||
can_place = 0
|
||||
else
|
||||
for(var/obj/O in cur)
|
||||
if(!istype(O, /obj/item/tape) && O.density)
|
||||
if(O.density)
|
||||
can_place = 0
|
||||
break
|
||||
if(cur == end)
|
||||
break
|
||||
cur = get_step_towards(cur,end)
|
||||
if (!can_place)
|
||||
start = null
|
||||
update_icon()
|
||||
usr << "<span class='warning'>You can't run \the [src] through that!</span>"
|
||||
return
|
||||
|
||||
cur = start
|
||||
var/tapetest = 0
|
||||
while (cur!=end)
|
||||
for(var/obj/item/tape/Ptest in cur)
|
||||
if(Ptest.icon_state == "[Ptest.icon_base]_[dir]")
|
||||
var/tapetest
|
||||
var/tape_dir
|
||||
while (1)
|
||||
tapetest = 0
|
||||
tape_dir = dir
|
||||
if(cur == start)
|
||||
var/turf/T = get_step(start, reverse_dir[orientation])
|
||||
if(T && !T.density)
|
||||
tape_dir = orientation
|
||||
for(var/obj/structure/window/W in T)
|
||||
if(W.is_fulltile() || W.dir == orientation)
|
||||
tape_dir = dir
|
||||
else if(cur == end)
|
||||
var/turf/T = get_step(end, orientation)
|
||||
if(T && !T.density)
|
||||
tape_dir = reverse_dir[orientation]
|
||||
for(var/obj/structure/window/W in T)
|
||||
if(W.is_fulltile() || W.dir == reverse_dir[orientation])
|
||||
tape_dir = dir
|
||||
for(var/obj/item/tape/T in cur)
|
||||
if((T.tape_dir == tape_dir) && (T.icon_base == icon_base))
|
||||
tapetest = 1
|
||||
if(tapetest != 1)
|
||||
var/obj/item/tape/P = new tape_type(cur)
|
||||
P.icon_state = "[P.icon_base]_[dir]"
|
||||
break
|
||||
if(!tapetest)
|
||||
var/obj/item/tape/T = new tape_type(cur)
|
||||
T.icon_state = "[T.icon_base]_[tape_dir]"
|
||||
T.tape_dir = tape_dir
|
||||
if(tape_dir & SOUTH)
|
||||
T.layer += 0.1 // Must always show above other tapes
|
||||
if(cur == end)
|
||||
break
|
||||
cur = get_step_towards(cur,end)
|
||||
start = null
|
||||
update_icon()
|
||||
usr << "<span class='notice'>You finish placing \the [src].</span>"
|
||||
return
|
||||
|
||||
/obj/item/taperoll/afterattack(var/atom/A, mob/user as mob, proximity)
|
||||
if(!proximity)
|
||||
@@ -149,6 +238,8 @@ var/list/tape_roll_applications = list()
|
||||
add_fingerprint(M)
|
||||
if (!allowed(M)) //only select few learn art of not crumpling the tape
|
||||
M << "<span class='warning'>You are not supposed to go past [src]...</span>"
|
||||
if(M.a_intent == I_HELP)
|
||||
return 0
|
||||
crumple()
|
||||
return ..(mover)
|
||||
|
||||
@@ -158,13 +249,45 @@ var/list/tape_roll_applications = list()
|
||||
/obj/item/tape/attack_hand(mob/user as mob)
|
||||
if (user.a_intent == I_HELP && src.allowed(user))
|
||||
user.show_viewers("<span class='notice'>\The [user] lifts \the [src], allowing passage.</span>")
|
||||
crumple()
|
||||
lifted = 1
|
||||
spawn(200)
|
||||
lifted = 0
|
||||
for(var/obj/item/tape/T in gettapeline())
|
||||
T.lift(100) //~10 seconds
|
||||
else
|
||||
breaktape(null, user)
|
||||
|
||||
/obj/item/tape/proc/lift(time)
|
||||
lifted = 1
|
||||
layer = 8
|
||||
spawn(time)
|
||||
lifted = 0
|
||||
layer = initial(layer)
|
||||
|
||||
// Returns a list of all tape objects connected to src, including itself.
|
||||
/obj/item/tape/proc/gettapeline()
|
||||
var/list/dirs = list()
|
||||
if(tape_dir & NORTH)
|
||||
dirs += NORTH
|
||||
if(tape_dir & SOUTH)
|
||||
dirs += SOUTH
|
||||
if(tape_dir & WEST)
|
||||
dirs += WEST
|
||||
if(tape_dir & EAST)
|
||||
dirs += EAST
|
||||
|
||||
var/list/obj/item/tape/tapeline = list()
|
||||
for (var/obj/item/tape/T in get_turf(src))
|
||||
tapeline += T
|
||||
for(var/dir in dirs)
|
||||
var/turf/cur = get_step(src, dir)
|
||||
var/not_found = 0
|
||||
while (!not_found)
|
||||
not_found = 1
|
||||
for (var/obj/item/tape/T in cur)
|
||||
tapeline += T
|
||||
not_found = 0
|
||||
cur = get_step(cur, dir)
|
||||
return tapeline
|
||||
|
||||
|
||||
|
||||
|
||||
/obj/item/tape/proc/breaktape(obj/item/weapon/W as obj, mob/user as mob)
|
||||
@@ -173,27 +296,11 @@ var/list/tape_roll_applications = list()
|
||||
return
|
||||
user.show_viewers("<span class='notice'>\The [user] breaks \the [src]!</span>")
|
||||
|
||||
var/dir[2]
|
||||
var/icon_dir = src.icon_state
|
||||
if(icon_dir == "[src.icon_base]_h")
|
||||
dir[1] = EAST
|
||||
dir[2] = WEST
|
||||
if(icon_dir == "[src.icon_base]_v")
|
||||
dir[1] = NORTH
|
||||
dir[2] = SOUTH
|
||||
for (var/obj/item/tape/T in gettapeline())
|
||||
if(T == src)
|
||||
continue
|
||||
if(T.tape_dir & get_dir(T, src))
|
||||
qdel(T)
|
||||
|
||||
for(var/i=1;i<3;i++)
|
||||
var/N = 0
|
||||
var/turf/cur = get_step(src,dir[i])
|
||||
while(N != 1)
|
||||
N = 1
|
||||
for (var/obj/item/tape/P in cur)
|
||||
if(P.icon_state == icon_dir)
|
||||
N = 0
|
||||
qdel(P)
|
||||
cur = get_step(cur,dir[i])
|
||||
|
||||
qdel(src)
|
||||
qdel(src) //TODO: Dropping a trash item holding fibers/fingerprints of all broken tape parts
|
||||
return
|
||||
|
||||
|
||||
|
||||
@@ -639,35 +639,36 @@
|
||||
icon_state = "light"
|
||||
desc = "This box is shaped on the inside so that only light tubes and bulbs fit."
|
||||
item_state = "syringe_kit"
|
||||
storage_slots=21
|
||||
can_hold = list(/obj/item/weapon/light/tube, /obj/item/weapon/light/bulb)
|
||||
max_storage_space = 42 //holds 21 items of w_class 2
|
||||
use_to_pickup = 1 // for picking up broken bulbs, not that most people will try
|
||||
|
||||
/obj/item/weapon/storage/box/lights/bulbs/New()
|
||||
/obj/item/weapon/storage/box/lights/New()
|
||||
..()
|
||||
make_exact_fit()
|
||||
|
||||
/obj/item/weapon/storage/box/lights/bulbs/New()
|
||||
for(var/i = 0; i < 21; i++)
|
||||
new /obj/item/weapon/light/bulb(src)
|
||||
..()
|
||||
|
||||
/obj/item/weapon/storage/box/lights/tubes
|
||||
name = "box of replacement tubes"
|
||||
icon_state = "lighttube"
|
||||
|
||||
/obj/item/weapon/storage/box/lights/tubes/New()
|
||||
..()
|
||||
for(var/i = 0; i < 21; i++)
|
||||
new /obj/item/weapon/light/tube(src)
|
||||
..()
|
||||
|
||||
/obj/item/weapon/storage/box/lights/mixed
|
||||
name = "box of replacement lights"
|
||||
icon_state = "lightmixed"
|
||||
|
||||
/obj/item/weapon/storage/box/lights/mixed/New()
|
||||
..()
|
||||
for(var/i = 0; i < 14; i++)
|
||||
new /obj/item/weapon/light/tube(src)
|
||||
for(var/i = 0; i < 7; i++)
|
||||
new /obj/item/weapon/light/bulb(src)
|
||||
..()
|
||||
|
||||
/obj/item/weapon/storage/box/freezer
|
||||
name = "portable freezer"
|
||||
|
||||
@@ -130,8 +130,7 @@
|
||||
|
||||
/obj/item/weapon/storage/firstaid/surgery
|
||||
name = "surgery kit"
|
||||
desc = "Contains tools for surgery."
|
||||
storage_slots = 10
|
||||
desc = "Contains tools for surgery. Has precise foam fitting for safe transport."
|
||||
|
||||
/obj/item/weapon/storage/firstaid/surgery/New()
|
||||
..()
|
||||
@@ -146,7 +145,8 @@
|
||||
new /obj/item/weapon/bonegel(src)
|
||||
new /obj/item/weapon/FixOVein(src)
|
||||
new /obj/item/stack/medical/advanced/bruise_pack(src)
|
||||
return
|
||||
|
||||
make_exact_fit()
|
||||
|
||||
/*
|
||||
* Pill Bottles
|
||||
|
||||
87
code/game/objects/items/weapons/storage/laundry_basket.dm
Normal file
87
code/game/objects/items/weapons/storage/laundry_basket.dm
Normal file
@@ -0,0 +1,87 @@
|
||||
// -----------------------------
|
||||
// Laundry Basket
|
||||
// -----------------------------
|
||||
// An item designed for hauling the belongings of a character.
|
||||
// So this cannot be abused for other uses, we make it two-handed and inable to have its storage looked into.
|
||||
/obj/item/weapon/storage/laundry_basket
|
||||
name = "laundry basket"
|
||||
icon = 'icons/obj/janitor.dmi'
|
||||
icon_state = "laundry-empty"
|
||||
item_state = "laundry"
|
||||
desc = "The peak of thousands of years of laundry evolution."
|
||||
|
||||
w_class = 5
|
||||
max_w_class = 4
|
||||
max_storage_space = 25 //20 for clothes + a bit of additional space for non-clothing items that were worn on body
|
||||
storage_slots = 14
|
||||
use_to_pickup = 1
|
||||
allow_quick_empty = 1
|
||||
allow_quick_gather = 1
|
||||
collection_mode = 1
|
||||
var/linked
|
||||
|
||||
|
||||
/obj/item/weapon/storage/laundry_basket/attack_hand(mob/user as mob)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/obj/item/organ/external/temp = H.get_organ("r_hand")
|
||||
if (user.hand)
|
||||
temp = H.get_organ("l_hand")
|
||||
if(!temp)
|
||||
user << "<span class='warning'>You need two hands to pick this up!</span>"
|
||||
return
|
||||
|
||||
if(user.get_inactive_hand())
|
||||
user << "<span class='warning'>You need your other hand to be empty</span>"
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/storage/laundry_basket/attack_self(mob/user as mob)
|
||||
var/turf/T = get_turf(user)
|
||||
user << "<span class='notice'>You dump the [src]'s contents onto \the [T].</span>"
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/storage/laundry_basket/pickup(mob/user)
|
||||
var/obj/item/weapon/storage/laundry_basket/offhand/O = new(user)
|
||||
O.name = "[name] - second hand"
|
||||
O.desc = "Your second grip on the [name]."
|
||||
O.linked = src
|
||||
user.put_in_inactive_hand(O)
|
||||
linked = O
|
||||
return
|
||||
|
||||
/obj/item/weapon/storage/laundry_basket/update_icon()
|
||||
if(contents.len)
|
||||
icon_state = "laundry-full"
|
||||
else
|
||||
icon_state = "laundry-empty"
|
||||
return
|
||||
|
||||
|
||||
/obj/item/weapon/storage/laundry_basket/MouseDrop(obj/over_object as obj)
|
||||
if(over_object == usr)
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/storage/laundry_basket/dropped(mob/user as mob)
|
||||
qdel(linked)
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/storage/laundry_basket/show_to(mob/user as mob)
|
||||
return
|
||||
|
||||
/obj/item/weapon/storage/laundry_basket/open(mob/user as mob)
|
||||
|
||||
|
||||
//Offhand
|
||||
/obj/item/weapon/storage/laundry_basket/offhand
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "offhand"
|
||||
name = "second hand"
|
||||
use_to_pickup = 0
|
||||
|
||||
/obj/item/weapon/storage/laundry_basket/offhand/dropped(mob/user as mob)
|
||||
user.drop_from_inventory(linked)
|
||||
return
|
||||
|
||||
@@ -235,11 +235,15 @@
|
||||
usr << "<span class='notice'>[src] is full, make some space.</span>"
|
||||
return 0 //Storage item is full
|
||||
|
||||
if(can_hold.len && !is_type_in_list(W, can_hold))
|
||||
if(!stop_messages)
|
||||
if (istype(W, /obj/item/weapon/hand_labeler))
|
||||
if(can_hold.len)
|
||||
if(!is_type_in_list(W, can_hold))
|
||||
if(!stop_messages && ! istype(W, /obj/item/weapon/hand_labeler))
|
||||
usr << "<span class='notice'>[src] cannot hold \the [W].</span>"
|
||||
return 0
|
||||
usr << "<span class='notice'>[src] cannot hold [W].</span>"
|
||||
var/max_instances = can_hold[W.type]
|
||||
if(max_instances && instances_of_type_in_list(W, contents) >= max_instances)
|
||||
if(!stop_messages && !istype(W, /obj/item/weapon/hand_labeler))
|
||||
usr << "<span class='notice'>[src] has no more space specifically for \the [W].</span>"
|
||||
return 0
|
||||
|
||||
if(cant_hold.len && is_type_in_list(W, cant_hold))
|
||||
@@ -461,6 +465,17 @@
|
||||
src.quick_empty()
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/storage/proc/make_exact_fit()
|
||||
storage_slots = contents.len
|
||||
|
||||
can_hold.Cut()
|
||||
max_w_class = 0
|
||||
max_storage_space = 0
|
||||
for(var/obj/item/I in src)
|
||||
can_hold[I.type]++
|
||||
max_w_class = max(I.w_class, max_w_class)
|
||||
max_storage_space += I.get_storage_cost()
|
||||
|
||||
//Returns the storage depth of an atom. This is the number of storage items the atom is contained in before reaching toplevel (the area).
|
||||
//Returns -1 if the atom was not found on container.
|
||||
/atom/proc/storage_depth(atom/container)
|
||||
|
||||
@@ -102,71 +102,54 @@
|
||||
user << "<span class='warning'>[src] is out of charge.</span>"
|
||||
add_fingerprint(user)
|
||||
|
||||
|
||||
/obj/item/weapon/melee/baton/attack(mob/M, mob/user)
|
||||
if(status && (CLUMSY in user.mutations) && prob(50))
|
||||
user << "<span class='danger'>You accidentally hit yourself with the [src]!</span>"
|
||||
user.Weaken(30)
|
||||
deductcharge(hitcost)
|
||||
return
|
||||
return ..()
|
||||
|
||||
if(isrobot(M))
|
||||
..()
|
||||
return
|
||||
/obj/item/weapon/melee/baton/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone)
|
||||
if(isrobot(target))
|
||||
return ..()
|
||||
|
||||
var/agony = agonyforce
|
||||
var/stun = stunforce
|
||||
var/mob/living/L = M
|
||||
var/obj/item/organ/external/affecting = null
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
affecting = H.get_organ(hit_zone)
|
||||
|
||||
var/target_zone = check_zone(user.zone_sel.selecting)
|
||||
if(user.a_intent == I_HURT)
|
||||
if (!..()) //item/attack() does it's own messaging and logs
|
||||
return 0 // item/attack() will return 1 if they hit, 0 if they missed.
|
||||
agony *= 0.5 //whacking someone causes a much poorer contact than prodding them.
|
||||
. = ..()
|
||||
//whacking someone causes a much poorer electrical contact than deliberately prodding them.
|
||||
agony *= 0.5
|
||||
stun *= 0.5
|
||||
//we can't really extract the actual hit zone from ..(), unfortunately. Just act like they attacked the area they intended to.
|
||||
else
|
||||
//copied from human_defense.dm - human defence code should really be refactored some time.
|
||||
if (ishuman(L))
|
||||
user.lastattacked = L //are these used at all, if we have logs?
|
||||
L.lastattacker = user
|
||||
|
||||
if (user != L) // Attacking yourself can't miss
|
||||
target_zone = get_zone_with_miss_chance(user.zone_sel.selecting, L)
|
||||
|
||||
if(!target_zone)
|
||||
L.visible_message("<span class='danger'>\The [user] misses [L] with \the [src]!</span>")
|
||||
return 0
|
||||
|
||||
var/mob/living/carbon/human/H = L
|
||||
var/obj/item/organ/external/affecting = H.get_organ(target_zone)
|
||||
else if(!status)
|
||||
if(affecting)
|
||||
if(!status)
|
||||
L.visible_message("<span class='warning'>[L] has been prodded in the [affecting.name] with [src] by [user]. Luckily it was off.</span>")
|
||||
return 1
|
||||
target.visible_message("<span class='warning'>[target] has been prodded in the [affecting.name] with [src] by [user]. Luckily it was off.</span>")
|
||||
else
|
||||
H.visible_message("<span class='danger'>[L] has been prodded in the [affecting.name] with [src] by [user]!</span>")
|
||||
target.visible_message("<span class='warning'>[target] has been prodded with [src] by [user]. Luckily it was off.</span>")
|
||||
else
|
||||
if(!status)
|
||||
L.visible_message("<span class='warning'>[L] has been prodded with [src] by [user]. Luckily it was off.</span>")
|
||||
return 1
|
||||
if(affecting)
|
||||
target.visible_message("<span class='danger'>[target] has been prodded in the [affecting.name] with [src] by [user]!</span>")
|
||||
else
|
||||
L.visible_message("<span class='danger'>[L] has been prodded with [src] by [user]!</span>")
|
||||
target.visible_message("<span class='danger'>[target] has been prodded with [src] by [user]!</span>")
|
||||
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
|
||||
|
||||
//stun effects
|
||||
L.stun_effect_act(stun, agony, target_zone, src)
|
||||
|
||||
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
|
||||
msg_admin_attack("[key_name(user)] stunned [key_name(L)] with the [src].")
|
||||
if(status)
|
||||
target.stun_effect_act(stun, agony, hit_zone, src)
|
||||
msg_admin_attack("[key_name(user)] stunned [key_name(target)] with the [src].")
|
||||
|
||||
deductcharge(hitcost)
|
||||
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
H.forcesay(hit_appends)
|
||||
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/melee/baton/emp_act(severity)
|
||||
if(bcell)
|
||||
bcell.emp_act(severity) //let's not duplicate code everywhere if we don't have to please.
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
/* Weapons
|
||||
* Contains:
|
||||
* Banhammer
|
||||
* Sword
|
||||
* Classic Baton
|
||||
*/
|
||||
|
||||
/*
|
||||
* Banhammer
|
||||
*/
|
||||
/obj/item/weapon/banhammer/attack(mob/M as mob, mob/user as mob)
|
||||
M << "<font color='red'><b> You have been banned FOR NO REISIN by [user]</b></font>"
|
||||
user << "<font color='red'> You have <b>BANNED</b> [M]</font>"
|
||||
|
||||
/*
|
||||
* Classic Baton
|
||||
*/
|
||||
@@ -34,33 +26,7 @@
|
||||
else
|
||||
user.take_organ_damage(2*force)
|
||||
return
|
||||
/*this is already called in ..()
|
||||
src.add_fingerprint(user)
|
||||
M.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been attacked with [src.name] by [user.name] ([user.ckey])</font>")
|
||||
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Used the [src.name] to attack [M.name] ([M.ckey])</font>")
|
||||
|
||||
log_attack("<font color='red'>[user.name] ([user.ckey]) attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])</font>")
|
||||
*/
|
||||
if (user.a_intent == I_HURT)
|
||||
if(!..()) return
|
||||
//playsound(src.loc, "swing_hit", 50, 1, -1)
|
||||
if (M.stuttering < 8 && (!(HULK in M.mutations)) /*&& (!istype(H:wear_suit, /obj/item/clothing/suit/judgerobe))*/)
|
||||
M.stuttering = 8
|
||||
M.Stun(8)
|
||||
M.Weaken(8)
|
||||
for(var/mob/O in viewers(M))
|
||||
if (O.client) O.show_message("<span class='danger'>\The [M] has been beaten with \the [src] by [user]!</span>", 1, "<span class='warning'>You hear someone fall</span>", 2)
|
||||
else
|
||||
playsound(src.loc, 'sound/weapons/Genhit.ogg', 50, 1, -1)
|
||||
M.Stun(5)
|
||||
M.Weaken(5)
|
||||
M.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been attacked with [src.name] by [user.name] ([user.ckey])</font>")
|
||||
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Used the [src.name] to attack [M.name] ([M.ckey])</font>")
|
||||
msg_admin_attack("[key_name(user)] attacked [key_name(user)] with [src.name] (INTENT: [uppertext(user.a_intent)])")
|
||||
src.add_fingerprint(user)
|
||||
|
||||
for(var/mob/O in viewers(M))
|
||||
if (O.client) O.show_message("<span class='danger'>\The [M] has been stunned with \the [src] by [user]!</span>", 1, "<span class='warning'>You hear someone fall</span>", 2)
|
||||
return ..()
|
||||
|
||||
//Telescopic baton
|
||||
/obj/item/weapon/melee/telebaton
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
|
||||
processing_objects.Remove(src)
|
||||
|
||||
if(istype(loc, /obj/item/device/transfer_valve))
|
||||
var/obj/item/device/transfer_valve/TTV = loc
|
||||
TTV.remove_tank(src)
|
||||
|
||||
..()
|
||||
|
||||
/obj/item/weapon/tank/examine(mob/user)
|
||||
@@ -249,7 +253,10 @@
|
||||
qdel(src)
|
||||
|
||||
else if(pressure > TANK_RUPTURE_PRESSURE)
|
||||
//world << "<span class='notice'>[x],[y] tank is rupturing: [pressure] kPa, integrity [integrity]</span>"
|
||||
#ifdef FIREDBG
|
||||
log_debug("<span class='warning'>[x],[y] tank is rupturing: [pressure] kPa, integrity [integrity]</span>")
|
||||
#endif
|
||||
|
||||
if(integrity <= 0)
|
||||
var/turf/simulated/T = get_turf(src)
|
||||
if(!T)
|
||||
@@ -261,7 +268,10 @@
|
||||
integrity--
|
||||
|
||||
else if(pressure > TANK_LEAK_PRESSURE)
|
||||
//world << "<span class='notice'>[x],[y] tank is leaking: [pressure] kPa, integrity [integrity]</span>"
|
||||
#ifdef FIREDBG
|
||||
log_debug("<span class='warning'>[x],[y] tank is leaking: [pressure] kPa, integrity [integrity]</span>")
|
||||
#endif
|
||||
|
||||
if(integrity <= 0)
|
||||
var/turf/simulated/T = get_turf(src)
|
||||
if(!T)
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
item_state = "cutters_yellow"
|
||||
|
||||
/obj/item/weapon/wirecutters/attack(mob/living/carbon/C as mob, mob/user as mob)
|
||||
if((C.handcuffed) && (istype(C.handcuffed, /obj/item/weapon/handcuffs/cable)))
|
||||
if(user.a_intent == I_HELP && (C.handcuffed) && (istype(C.handcuffed, /obj/item/weapon/handcuffs/cable)))
|
||||
usr.visible_message("\The [usr] cuts \the [C]'s restraints with \the [src]!",\
|
||||
"You cut \the [C]'s restraints with \the [src]!",\
|
||||
"You hear cable being cut.")
|
||||
@@ -337,18 +337,18 @@
|
||||
if(!E)
|
||||
return
|
||||
switch(safety)
|
||||
if(1)
|
||||
if(FLASH_PROTECTION_MODERATE)
|
||||
usr << "<span class='warning'>Your eyes sting a little.</span>"
|
||||
E.damage += rand(1, 2)
|
||||
if(E.damage > 12)
|
||||
user.eye_blurry += rand(3,6)
|
||||
if(0)
|
||||
if(FLASH_PROTECTION_NONE)
|
||||
usr << "<span class='warning'>Your eyes burn.</span>"
|
||||
E.damage += rand(2, 4)
|
||||
if(E.damage > 10)
|
||||
E.damage += rand(4,10)
|
||||
if(-1)
|
||||
usr << "<span class='danger'>Your thermals intensify the welder's glow. Your eyes itch and burn severely.</span>"
|
||||
if(FLASH_PROTECTION_REDUCED)
|
||||
usr << "<span class='danger'>Your equipment intensify the welder's glow. Your eyes itch and burn severely.</span>"
|
||||
user.eye_blurry += rand(12,20)
|
||||
E.damage += rand(12, 16)
|
||||
if(safety<2)
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
/obj/item/weapon/banhammer
|
||||
desc = "banhammer"
|
||||
name = "banhammer"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "toyhammer"
|
||||
slot_flags = SLOT_BELT
|
||||
throwforce = 0
|
||||
w_class = 2.0
|
||||
throw_speed = 7
|
||||
throw_range = 15
|
||||
attack_verb = list("banned")
|
||||
|
||||
suicide_act(mob/user)
|
||||
viewers(user) << "<span class='danger'>[user] is hitting \himself with the [src.name]! It looks like \he's trying to ban \himself from life.</span>"
|
||||
return (BRUTELOSS|FIRELOSS|TOXLOSS|OXYLOSS)
|
||||
|
||||
/obj/item/weapon/nullrod
|
||||
name = "null rod"
|
||||
@@ -37,6 +22,9 @@
|
||||
|
||||
msg_admin_attack("[user.name] ([user.ckey]) attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)]) (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[user.x];Y=[user.y];Z=[user.z]'>JMP</a>)")
|
||||
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.do_attack_animation(M)
|
||||
|
||||
if (!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey")
|
||||
user << "<span class='danger'>You don't have the dexterity to do this!</span>"
|
||||
return
|
||||
@@ -68,27 +56,6 @@
|
||||
user << "<span class='notice'>You hit the floor with the [src].</span>"
|
||||
call(/obj/effect/rune/proc/revealrunes)(src)
|
||||
|
||||
/obj/item/weapon/sord
|
||||
name = "\improper SORD"
|
||||
desc = "This thing is so unspeakably shitty you are having a hard time even holding it."
|
||||
icon_state = "sord"
|
||||
item_state = "sord"
|
||||
slot_flags = SLOT_BELT
|
||||
force = 2
|
||||
throwforce = 1
|
||||
sharp = 1
|
||||
edge = 1
|
||||
w_class = 3
|
||||
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
|
||||
|
||||
suicide_act(mob/user)
|
||||
viewers(user) << "<span class='danger'>[user] is impaling \himself with the [src.name]! It looks like \he's trying to commit suicide.</span>"
|
||||
return(BRUTELOSS)
|
||||
|
||||
/obj/item/weapon/sord/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
|
||||
playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1, -1)
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/energy_net
|
||||
name = "energy net"
|
||||
desc = "It's a net made of green energy."
|
||||
|
||||
@@ -46,6 +46,10 @@
|
||||
|
||||
/obj/proc/CouldUseTopic(var/mob/user)
|
||||
var/atom/host = nano_host()
|
||||
if(!isAI(user) && host.Adjacent(user))
|
||||
// We are -probably- in physical contact with the object, better than how Topics() previously did it and always applied fingerprints.
|
||||
host.add_fingerprint(user)
|
||||
else
|
||||
host.add_hiddenprint(user)
|
||||
|
||||
/obj/proc/CouldNotUseTopic(var/mob/user)
|
||||
|
||||
61
code/game/objects/structures/alien/alien.dm
Normal file
61
code/game/objects/structures/alien/alien.dm
Normal file
@@ -0,0 +1,61 @@
|
||||
/obj/structure/alien
|
||||
name = "alien thing"
|
||||
desc = "There's something alien about this."
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
var/health = 50
|
||||
|
||||
/obj/structure/alien/proc/healthcheck()
|
||||
if(health <=0)
|
||||
density = 0
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/structure/alien/bullet_act(var/obj/item/projectile/Proj)
|
||||
health -= Proj.damage
|
||||
..()
|
||||
healthcheck()
|
||||
return
|
||||
|
||||
/obj/structure/alien/ex_act(severity)
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
health-=50
|
||||
if(2.0)
|
||||
health-=50
|
||||
if(3.0)
|
||||
if (prob(50))
|
||||
health-=50
|
||||
else
|
||||
health-=25
|
||||
healthcheck()
|
||||
return
|
||||
|
||||
/obj/structure/alien/hitby(AM as mob|obj)
|
||||
..()
|
||||
visible_message("<span class='danger'>\The [src] was hit by \the [AM].</span>")
|
||||
var/tforce = 0
|
||||
if(ismob(AM))
|
||||
tforce = 10
|
||||
else
|
||||
tforce = AM:throwforce
|
||||
playsound(loc, 'sound/effects/attackblob.ogg', 100, 1)
|
||||
health = max(0, health - tforce)
|
||||
healthcheck()
|
||||
..()
|
||||
return
|
||||
|
||||
/obj/structure/alien/attack_generic()
|
||||
attack_hand(usr)
|
||||
|
||||
/obj/structure/alien/attackby(var/obj/item/weapon/W, var/mob/user)
|
||||
health = max(0, health - W.force)
|
||||
playsound(loc, 'sound/effects/attackblob.ogg', 100, 1)
|
||||
healthcheck()
|
||||
..()
|
||||
return
|
||||
|
||||
/obj/structure/alien/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||
if(air_group) return 0
|
||||
if(istype(mover) && mover.checkpass(PASSGLASS))
|
||||
return !opacity
|
||||
return !density
|
||||
96
code/game/objects/structures/alien/egg.dm
Normal file
96
code/game/objects/structures/alien/egg.dm
Normal file
@@ -0,0 +1,96 @@
|
||||
#define MAX_PROGRESS 100
|
||||
|
||||
/obj/structure/alien/egg
|
||||
desc = "It looks like a weird egg."
|
||||
name = "egg"
|
||||
icon_state = "egg_growing"
|
||||
density = 0
|
||||
anchored = 1
|
||||
var/progress = 0
|
||||
|
||||
/obj/structure/alien/egg/New()
|
||||
..()
|
||||
processing_objects += src
|
||||
|
||||
/obj/structure/alien/egg/Destroy()
|
||||
processing_objects -= src
|
||||
..()
|
||||
|
||||
/obj/structure/alien/egg/CanUseTopic(var/mob/user)
|
||||
return isobserver(user) ? STATUS_INTERACTIVE : STATUS_CLOSE
|
||||
|
||||
/obj/structure/alien/egg/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(href_list["spawn"])
|
||||
attack_ghost(usr)
|
||||
|
||||
/obj/structure/alien/egg/process()
|
||||
progress++
|
||||
if(progress >= MAX_PROGRESS)
|
||||
for(var/mob/M in dead_mob_list)
|
||||
if(istype(M,/mob/dead) && M.client && M.client.prefs && (M.client.prefs.be_special & BE_ALIEN))
|
||||
M << "<span class='notice'>An alien is ready to hatch! ([ghost_follow_link(src, M)]) (<a href='byond://?src=\ref[src];spawn=1'>spawn</a>)</span>"
|
||||
processing_objects -= src
|
||||
update_icon()
|
||||
|
||||
/obj/structure/alien/egg/update_icon()
|
||||
if(progress == -1)
|
||||
icon_state = "egg_hatched"
|
||||
else if(progress < MAX_PROGRESS)
|
||||
icon_state = "egg_growing"
|
||||
else
|
||||
icon_state = "egg"
|
||||
|
||||
/obj/structure/alien/egg/attack_ghost(var/mob/dead/observer/user)
|
||||
if(progress == -1) //Egg has been hatched.
|
||||
return
|
||||
|
||||
if(progress < MAX_PROGRESS)
|
||||
user << "\The [src] has not yet matured."
|
||||
return
|
||||
|
||||
if(!user.MayRespawn(1))
|
||||
return
|
||||
|
||||
// Check for bans properly.
|
||||
if(jobban_isbanned(user, "Xenomorph"))
|
||||
user << "<span class='danger'>You are banned from playing a Xenomorph.</span>"
|
||||
return
|
||||
|
||||
var/confirm = alert(user, "Are you sure you want to join as a Xenomorph larva?", "Become Larva", "No", "Yes")
|
||||
|
||||
if(!src || confirm != "Yes")
|
||||
return
|
||||
|
||||
if(!user || !user.ckey)
|
||||
return
|
||||
|
||||
if(progress == -1) //Egg has been hatched.
|
||||
user << "Too slow..."
|
||||
return
|
||||
|
||||
flick("egg_opening",src)
|
||||
progress = -1 // No harvesting pls.
|
||||
sleep(5)
|
||||
|
||||
if(!src || !user)
|
||||
visible_message("<span class='alium'>\The [src] writhes with internal motion, but nothing comes out.</span>")
|
||||
progress = MAX_PROGRESS // Someone else can have a go.
|
||||
return // What a pain.
|
||||
|
||||
// Create the mob, transfer over key.
|
||||
var/mob/living/carbon/alien/larva/larva = new(get_turf(src))
|
||||
larva.ckey = user.ckey
|
||||
spawn(-1)
|
||||
if(user) qdel(user) // Remove the keyless ghost if it exists.
|
||||
|
||||
visible_message("<span class='alium'>\The [src] splits open with a wet slithering noise, and \the [larva] writhes free!</span>")
|
||||
|
||||
// Turn us into a hatched egg.
|
||||
name = "hatched alien egg"
|
||||
desc += " This one has hatched."
|
||||
update_icon()
|
||||
|
||||
#undef MAX_PROGRESS
|
||||
19
code/game/objects/structures/alien/node.dm
Normal file
19
code/game/objects/structures/alien/node.dm
Normal file
@@ -0,0 +1,19 @@
|
||||
/obj/structure/alien/node
|
||||
name = "alien weed node"
|
||||
desc = "Some kind of strange, pulsating structure."
|
||||
icon_state = "weednode"
|
||||
health = 100
|
||||
layer = 3.1
|
||||
|
||||
/obj/structure/alien/node/New()
|
||||
..()
|
||||
processing_objects += src
|
||||
|
||||
/obj/structure/alien/node/Destroy()
|
||||
processing_objects -= src
|
||||
..()
|
||||
|
||||
/obj/structure/alien/node/process()
|
||||
if(locate(/obj/effect/plant) in loc)
|
||||
return
|
||||
new /obj/effect/plant(get_turf(src), plant_controller.seeds["xenomorph"])
|
||||
50
code/game/objects/structures/alien/resin.dm
Normal file
50
code/game/objects/structures/alien/resin.dm
Normal file
@@ -0,0 +1,50 @@
|
||||
/obj/structure/alien/resin
|
||||
name = "resin"
|
||||
desc = "Looks like some kind of slimy growth."
|
||||
icon_state = "resin"
|
||||
|
||||
density = 1
|
||||
opacity = 1
|
||||
anchored = 1
|
||||
health = 200
|
||||
|
||||
/obj/structure/alien/resin/wall
|
||||
name = "resin wall"
|
||||
desc = "Purple slime solidified into a wall."
|
||||
icon_state = "resinwall"
|
||||
|
||||
/obj/structure/alien/resin/membrane
|
||||
name = "resin membrane"
|
||||
desc = "Purple slime just thin enough to let light pass through."
|
||||
icon_state = "resinmembrane"
|
||||
opacity = 0
|
||||
health = 120
|
||||
|
||||
/obj/structure/alien/resin/New()
|
||||
..()
|
||||
var/turf/T = get_turf(src)
|
||||
T.thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
|
||||
|
||||
/obj/structure/alien/resin/Destroy()
|
||||
var/turf/T = get_turf(src)
|
||||
T.thermal_conductivity = initial(T.thermal_conductivity)
|
||||
..()
|
||||
|
||||
/obj/structure/alien/resin/attack_hand(var/mob/user)
|
||||
if (HULK in user.mutations)
|
||||
visible_message("<span class='danger'>\The [user] destroys \the [name]!</span>")
|
||||
health = 0
|
||||
else
|
||||
// Aliens can get straight through these.
|
||||
if(istype(user,/mob/living/carbon))
|
||||
var/mob/living/carbon/M = user
|
||||
if(locate(/obj/item/organ/xenos/hivenode) in M.internal_organs)
|
||||
visible_message("<span class='alium'>\The [user] strokes \the [name] and it melts away!</span>")
|
||||
health = 0
|
||||
healthcheck()
|
||||
return
|
||||
visible_message("<span class='danger'>\The [user] claws at \the [src]!</span>")
|
||||
// Todo check attack datums.
|
||||
health -= rand(5,10)
|
||||
healthcheck()
|
||||
return
|
||||
@@ -217,6 +217,15 @@
|
||||
M.show_message("<span class='notice'>\The [src] has been cut apart by [user] with \the [WT].</span>", 3, "You hear welding.", 2)
|
||||
qdel(src)
|
||||
return
|
||||
if(istype(W, /obj/item/weapon/storage/laundry_basket) && W.contents.len)
|
||||
var/obj/item/weapon/storage/laundry_basket/LB = W
|
||||
var/turf/T = get_turf(src)
|
||||
for(var/obj/item/I in LB.contents)
|
||||
LB.remove_from_storage(I, T)
|
||||
user.visible_message("<span class='notice'>[user] empties \the [LB] into \the [src].</span>", \
|
||||
"<span class='notice'>You empty \the [LB] into \the [src].</span>", \
|
||||
"<span class='notice'>You hear rustling of clothes.</span>")
|
||||
return
|
||||
if(isrobot(user))
|
||||
return
|
||||
if(W.loc != user) // This should stop mounted modules ending up outside the module.
|
||||
|
||||
@@ -160,6 +160,6 @@
|
||||
new /obj/item/clothing/suit/storage/hazardvest(src)
|
||||
new /obj/item/clothing/mask/gas(src)
|
||||
new /obj/item/weapon/cartridge/atmos(src)
|
||||
new /obj/item/taperoll/engineering(src)
|
||||
new /obj/item/taperoll/atmos(src)
|
||||
new /obj/item/clothing/suit/storage/hooded/wintercoat/engineering/atmos(src)
|
||||
return
|
||||
|
||||
@@ -65,6 +65,8 @@
|
||||
|
||||
/obj/structure/closet/secure_closet/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
if(src.opened)
|
||||
if(istype(W, /obj/item/weapon/storage/laundry_basket))
|
||||
return ..(W,user)
|
||||
if(istype(W, /obj/item/weapon/grab))
|
||||
var/obj/item/weapon/grab/G = W
|
||||
if(src.large)
|
||||
|
||||
@@ -82,6 +82,9 @@
|
||||
if(health <= 0)
|
||||
deflate(1)
|
||||
|
||||
/obj/structure/inflatable/CtrlClick()
|
||||
hand_deflate()
|
||||
|
||||
/obj/structure/inflatable/proc/deflate(var/violent=0)
|
||||
playsound(loc, 'sound/machines/hiss.ogg', 75, 1)
|
||||
if(violent)
|
||||
@@ -102,7 +105,7 @@
|
||||
set category = "Object"
|
||||
set src in oview(1)
|
||||
|
||||
if(isobserver(usr)) //to stop ghosts from deflating
|
||||
if(isobserver(usr) || usr.restrained() || !usr.Adjacent(src))
|
||||
return
|
||||
|
||||
verbs -= /obj/structure/inflatable/verb/hand_deflate
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/obj/structure/lamarr
|
||||
name = "lab cage"
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "labcage1"
|
||||
desc = "A glass lab container for storing interesting creatures."
|
||||
density = 1
|
||||
anchored = 1
|
||||
unacidable = 1//Dissolving the case would also delete Lamarr
|
||||
var/health = 30
|
||||
var/occupied = 1
|
||||
var/destroyed = 0
|
||||
|
||||
/obj/structure/lamarr/ex_act(severity)
|
||||
switch(severity)
|
||||
if (1)
|
||||
new /obj/item/weapon/material/shard( src.loc )
|
||||
Break()
|
||||
qdel(src)
|
||||
if (2)
|
||||
if (prob(50))
|
||||
src.health -= 15
|
||||
src.healthcheck()
|
||||
if (3)
|
||||
if (prob(50))
|
||||
src.health -= 5
|
||||
src.healthcheck()
|
||||
|
||||
|
||||
/obj/structure/lamarr/bullet_act(var/obj/item/projectile/Proj)
|
||||
health -= Proj.damage
|
||||
..()
|
||||
src.healthcheck()
|
||||
return
|
||||
|
||||
/obj/structure/lamarr/proc/healthcheck()
|
||||
if (src.health <= 0)
|
||||
if (!( src.destroyed ))
|
||||
src.density = 0
|
||||
src.destroyed = 1
|
||||
new /obj/item/weapon/material/shard( src.loc )
|
||||
playsound(src, "shatter", 70, 1)
|
||||
Break()
|
||||
else
|
||||
playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
|
||||
return
|
||||
|
||||
/obj/structure/lamarr/update_icon()
|
||||
if(src.destroyed)
|
||||
src.icon_state = "labcageb[src.occupied]"
|
||||
else
|
||||
src.icon_state = "labcage[src.occupied]"
|
||||
return
|
||||
|
||||
|
||||
/obj/structure/lamarr/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
src.health -= W.force
|
||||
src.healthcheck()
|
||||
..()
|
||||
return
|
||||
|
||||
/obj/structure/lamarr/attack_hand(mob/user as mob)
|
||||
if (src.destroyed)
|
||||
return
|
||||
else
|
||||
usr << "<span class='notice'>You kick the lab cage.</span>"
|
||||
for(var/mob/O in oviewers())
|
||||
if ((O.client && !( O.blinded )))
|
||||
O << "<span class='warning'>[usr] kicks the lab cage.</span>"
|
||||
src.health -= 2
|
||||
healthcheck()
|
||||
return
|
||||
|
||||
/obj/structure/lamarr/proc/Break()
|
||||
if(occupied)
|
||||
new /obj/item/clothing/mask/facehugger/lamarr(src.loc)
|
||||
occupied = 0
|
||||
update_icon()
|
||||
return
|
||||
|
||||
/obj/item/clothing/mask/facehugger/lamarr
|
||||
name = "Lamarr"
|
||||
desc = "The worst she might do is attempt to... couple with your head."//hope we don't get sued over a harmless reference, rite?
|
||||
sterile = 1
|
||||
gender = FEMALE
|
||||
|
||||
/obj/item/clothing/mask/facehugger/lamarr/New()//to prevent deleting it if aliums are disabled
|
||||
return
|
||||
@@ -72,6 +72,9 @@ var/global/list/stool_cache = list() //haha stool
|
||||
/obj/item/weapon/stool/attack(mob/M as mob, mob/user as mob)
|
||||
if (prob(5) && istype(M,/mob/living))
|
||||
user.visible_message("<span class='danger'>[user] breaks [src] over [M]'s back!</span>")
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.do_attack_animation(M)
|
||||
|
||||
user.remove_from_mob(src)
|
||||
dismantle()
|
||||
qdel(src)
|
||||
|
||||
@@ -491,7 +491,23 @@
|
||||
animate(src, color="#222222", time=5)
|
||||
set_opacity(1)
|
||||
|
||||
/obj/structure/window/reinforced/crescent/attack_hand()
|
||||
return
|
||||
|
||||
/obj/structure/window/reinforced/crescent/attackby()
|
||||
return
|
||||
|
||||
/obj/structure/window/reinforced/crescent/ex_act()
|
||||
return
|
||||
|
||||
/obj/structure/window/reinforced/crescent/hitby()
|
||||
return
|
||||
|
||||
/obj/structure/window/reinforced/crescent/take_damage()
|
||||
return
|
||||
|
||||
/obj/structure/window/reinforced/crescent/shatter()
|
||||
return
|
||||
|
||||
/obj/machinery/button/windowtint
|
||||
name = "window tint control"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user