mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-18 02:25:06 +01:00
Merge remote-tracking branch 'upstream/dev' into admin_stuff
Conflicts: code/modules/admin/admin_verbs.dm
This commit is contained in:
@@ -80,7 +80,9 @@ var/list/admin_verbs_admin = list(
|
||||
/client/proc/allow_character_respawn, /* Allows a ghost to respawn */
|
||||
/client/proc/event_manager_panel,
|
||||
/client/proc/empty_ai_core_toggle_latejoin,
|
||||
/client/proc/aooc
|
||||
/client/proc/aooc,
|
||||
/client/proc/change_human_appearance_admin, /* Allows an admin to change the basic appearance of human-based mobs */
|
||||
/client/proc/change_human_appearance_self /* Allows the human-based mob itself change its basic appearance */
|
||||
)
|
||||
var/list/admin_verbs_ban = list(
|
||||
/client/proc/unban_panel,
|
||||
@@ -718,6 +720,9 @@ var/list/admin_verbs_mentor = list(
|
||||
set name = "Rename Silicon"
|
||||
set category = "Admin"
|
||||
|
||||
if(!istype(S))
|
||||
return
|
||||
|
||||
if(holder)
|
||||
var/new_name = trim_strip_input(src, "Enter new name. Leave blank or as is to cancel.", "Enter new silicon name", S.real_name)
|
||||
if(new_name && new_name != S.real_name)
|
||||
@@ -725,6 +730,41 @@ var/list/admin_verbs_mentor = list(
|
||||
S.SetName(new_name)
|
||||
feedback_add_details("admin_verb","RAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/change_human_appearance_admin(mob/living/carbon/human/H in world)
|
||||
set name = "Change Mob Appearance - Admin"
|
||||
set desc = "Allows you to change the mob appearance"
|
||||
set category = "Admin"
|
||||
|
||||
if(!istype(H))
|
||||
return
|
||||
|
||||
if(holder)
|
||||
admin_log_and_message_admins("is altering the appearance of [H].")
|
||||
H.change_appearance(APPEARANCE_ALL, usr, usr, check_species_whitelist = 0)
|
||||
feedback_add_details("admin_verb","CHAA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/change_human_appearance_self(mob/living/carbon/human/H in world)
|
||||
set name = "Change Mob Appearance - Self"
|
||||
set desc = "Allows the mob to change its appearance"
|
||||
set category = "Admin"
|
||||
|
||||
if(!istype(H))
|
||||
return
|
||||
|
||||
if(!H.client)
|
||||
usr << "Only mobs with clients can alter their own appearance."
|
||||
return
|
||||
|
||||
if(holder)
|
||||
switch(alert("Do you wish for [H] to be allowed to select non-whitelisted races?","Alter Mob Appearance","Yes","No","Cancel"))
|
||||
if("Yes")
|
||||
admin_log_and_message_admins("has allowed [H] to change \his appearance, without whitelisting of races.")
|
||||
H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 0)
|
||||
if("No")
|
||||
admin_log_and_message_admins("has allowed [H] to change \his appearance, with whitelisting of races.")
|
||||
H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 1)
|
||||
feedback_add_details("admin_verb","CMAS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
//---- bs12 verbs ----
|
||||
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
/mob/living/carbon/human/proc/change_appearance(var/flags = APPEARANCE_ALL_HAIR, var/location = src, var/mob/user = src, var/check_species_whitelist = 1, var/list/species_whitelist = list(), var/list/species_blacklist = list())
|
||||
var/obj/nano_module/appearance_changer/AC = new(location, src, check_species_whitelist, species_whitelist, species_blacklist)
|
||||
AC.flags = flags
|
||||
AC.ui_interact(user)
|
||||
|
||||
/mob/living/carbon/human/proc/change_species(var/new_species)
|
||||
if(!new_species)
|
||||
return
|
||||
|
||||
if(species == new_species)
|
||||
return
|
||||
|
||||
if(!(new_species in all_species))
|
||||
return
|
||||
|
||||
set_species(new_species)
|
||||
reset_hair()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/proc/change_gender(var/gender)
|
||||
if(src.gender == gender)
|
||||
return
|
||||
|
||||
src.gender = gender
|
||||
reset_hair()
|
||||
update_body()
|
||||
update_dna()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/proc/change_hair(var/hair_style)
|
||||
if(!hair_style)
|
||||
return
|
||||
|
||||
if(h_style == hair_style)
|
||||
return
|
||||
|
||||
if(!(hair_style in hair_styles_list))
|
||||
return
|
||||
|
||||
h_style = hair_style
|
||||
|
||||
update_hair()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/proc/change_facial_hair(var/facial_hair_style)
|
||||
if(!facial_hair_style)
|
||||
return
|
||||
|
||||
if(f_style == facial_hair_style)
|
||||
return
|
||||
|
||||
if(!(facial_hair_style in facial_hair_styles_list))
|
||||
return
|
||||
|
||||
f_style = facial_hair_style
|
||||
|
||||
update_hair()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/proc/reset_hair()
|
||||
var/list/valid_hairstyles = generate_valid_hairstyles()
|
||||
var/list/valid_facial_hairstyles = generate_valid_facial_hairstyles()
|
||||
|
||||
if(valid_hairstyles.len)
|
||||
h_style = pick(valid_hairstyles)
|
||||
else
|
||||
//this shouldn't happen
|
||||
h_style = "Bald"
|
||||
|
||||
if(valid_facial_hairstyles.len)
|
||||
f_style = pick(valid_facial_hairstyles)
|
||||
else
|
||||
//this shouldn't happen
|
||||
f_style = "Shaved"
|
||||
|
||||
update_hair()
|
||||
|
||||
/mob/living/carbon/human/proc/change_eye_color(var/red, var/green, var/blue)
|
||||
if(red == r_eyes && green == g_eyes && blue == b_eyes)
|
||||
return
|
||||
|
||||
r_eyes = red
|
||||
g_eyes = green
|
||||
b_eyes = blue
|
||||
|
||||
update_body()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/proc/change_hair_color(var/red, var/green, var/blue)
|
||||
if(red == r_eyes && green == g_eyes && blue == b_eyes)
|
||||
return
|
||||
|
||||
r_hair = red
|
||||
g_hair = green
|
||||
b_hair = blue
|
||||
|
||||
update_hair()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/proc/change_facial_hair_color(var/red, var/green, var/blue)
|
||||
if(red == r_facial && green == g_facial && blue == b_facial)
|
||||
return
|
||||
|
||||
r_facial = red
|
||||
g_facial = green
|
||||
b_facial = blue
|
||||
|
||||
update_hair()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/proc/change_skin_color(var/red, var/green, var/blue)
|
||||
if(red == r_skin && green == g_skin && blue == b_skin || !(species.flags & HAS_SKIN_COLOR))
|
||||
return
|
||||
|
||||
r_skin = red
|
||||
g_skin = green
|
||||
b_skin = blue
|
||||
|
||||
update_body()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/proc/change_skin_tone(var/tone)
|
||||
if(s_tone == tone || !(species.flags & HAS_SKIN_TONE))
|
||||
return
|
||||
|
||||
s_tone = tone
|
||||
|
||||
update_body()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/proc/update_dna()
|
||||
check_dna()
|
||||
dna.ready_dna(src)
|
||||
|
||||
/mob/living/carbon/human/proc/generate_valid_species(var/check_whitelist = 1, var/list/whitelist = list(), var/list/blacklist = list())
|
||||
var/list/valid_species = new()
|
||||
for(var/current_species_name in all_species)
|
||||
var/datum/species/current_species = all_species[current_species_name]
|
||||
|
||||
if(check_whitelist && config.usealienwhitelist && !check_rights(R_ADMIN, 0, src)) //If we're using the whitelist, make sure to check it!
|
||||
if(!(current_species.flags & CAN_JOIN))
|
||||
continue
|
||||
if(whitelist.len && !(current_species_name in whitelist))
|
||||
continue
|
||||
if(blacklist.len && (current_species_name in blacklist))
|
||||
continue
|
||||
if((current_species.flags & IS_WHITELISTED) && !is_alien_whitelisted(src, current_species_name))
|
||||
continue
|
||||
|
||||
valid_species += current_species_name
|
||||
|
||||
return valid_species
|
||||
|
||||
/mob/living/carbon/human/proc/generate_valid_hairstyles()
|
||||
var/list/valid_hairstyles = new()
|
||||
for(var/hairstyle in hair_styles_list)
|
||||
var/datum/sprite_accessory/S = hair_styles_list[hairstyle]
|
||||
|
||||
if(gender == MALE && S.gender == FEMALE)
|
||||
continue
|
||||
if(gender == FEMALE && S.gender == MALE)
|
||||
continue
|
||||
if(!(species.name in S.species_allowed))
|
||||
continue
|
||||
valid_hairstyles += hairstyle
|
||||
|
||||
return valid_hairstyles
|
||||
|
||||
/mob/living/carbon/human/proc/generate_valid_facial_hairstyles()
|
||||
var/list/valid_facial_hairstyles = new()
|
||||
for(var/facialhairstyle in facial_hair_styles_list)
|
||||
var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle]
|
||||
|
||||
if(gender == MALE && S.gender == FEMALE)
|
||||
continue
|
||||
if(gender == FEMALE && S.gender == MALE)
|
||||
continue
|
||||
if(!(species.name in S.species_allowed))
|
||||
continue
|
||||
|
||||
valid_facial_hairstyles += facialhairstyle
|
||||
|
||||
return valid_facial_hairstyles
|
||||
|
||||
/proc/q()
|
||||
var/mob/living/carbon/human/H = usr
|
||||
H.change_appearance(APPEARANCE_ALL)
|
||||
@@ -188,6 +188,8 @@
|
||||
del(A)
|
||||
return
|
||||
A.current = target
|
||||
A.starting = get_turf(src)
|
||||
A.original = get_turf(target)
|
||||
A.yo = target:y - start:y
|
||||
A.xo = target:x - start:x
|
||||
spawn( 0 )
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
/obj/nano_module/appearance_changer
|
||||
name = "Appearance Editor"
|
||||
flags = APPEARANCE_ALL_HAIR
|
||||
var/mob/living/carbon/human/owner = null
|
||||
var/list/valid_species = list()
|
||||
var/list/valid_hairstyles = list()
|
||||
var/list/valid_facial_hairstyles = list()
|
||||
|
||||
var/check_whitelist
|
||||
var/list/whitelist
|
||||
var/list/blacklist
|
||||
|
||||
/obj/nano_module/appearance_changer/New(var/location, var/mob/living/carbon/human/H, var/check_species_whitelist = 1, var/list/species_whitelist = list(), var/list/species_blacklist = list())
|
||||
..()
|
||||
loc = location
|
||||
owner = H
|
||||
src.check_whitelist = check_species_whitelist
|
||||
src.whitelist = species_whitelist
|
||||
src.blacklist = species_blacklist
|
||||
|
||||
/obj/nano_module/appearance_changer/Topic(ref, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(href_list["race"])
|
||||
if(can_change(APPEARANCE_RACE) && (href_list["race"] in valid_species))
|
||||
if(owner.change_species(href_list["race"]))
|
||||
cut_and_generate_data()
|
||||
return 1
|
||||
if(href_list["gender"])
|
||||
if(can_change(APPEARANCE_GENDER))
|
||||
if(owner.change_gender(href_list["gender"]))
|
||||
cut_and_generate_data()
|
||||
return 1
|
||||
if(href_list["skin_tone"])
|
||||
if(can_change_skin_tone())
|
||||
var/new_s_tone = input(usr, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Skin Tone", owner.s_tone) as num|null
|
||||
if(isnum(new_s_tone) && CanUseTopic(usr) == STATUS_INTERACTIVE)
|
||||
new_s_tone = 35 - max(min( round(new_s_tone), 220),1)
|
||||
return owner.change_skin_tone(new_s_tone)
|
||||
if(href_list["skin_color"])
|
||||
if(can_change_skin_color())
|
||||
var/new_skin = input(usr, "Choose your character's skin colour: ", "Skin Color", rgb(owner.r_skin, owner.g_skin, owner.b_skin)) as color|null
|
||||
if(new_skin && can_still_topic())
|
||||
var/r_skin = hex2num(copytext(new_skin, 2, 4))
|
||||
var/g_skin = hex2num(copytext(new_skin, 4, 6))
|
||||
var/b_skin = hex2num(copytext(new_skin, 6, 8))
|
||||
if(owner.change_skin_color(r_skin, g_skin, b_skin))
|
||||
update_dna()
|
||||
return 1
|
||||
if(href_list["hair"])
|
||||
if(can_change(APPEARANCE_HAIR) && (href_list["hair"] in valid_hairstyles))
|
||||
if(owner.change_hair(href_list["hair"]))
|
||||
update_dna()
|
||||
return 1
|
||||
if(href_list["hair_color"])
|
||||
if(can_change(APPEARANCE_HAIR_COLOR))
|
||||
var/new_hair = input("Please select hair color.", "Hair Color", rgb(owner.r_hair, owner.g_hair, owner.b_hair)) as color|null
|
||||
if(new_hair && can_still_topic())
|
||||
var/r_hair = hex2num(copytext(new_hair, 2, 4))
|
||||
var/g_hair = hex2num(copytext(new_hair, 4, 6))
|
||||
var/b_hair = hex2num(copytext(new_hair, 6, 8))
|
||||
if(owner.change_hair_color(r_hair, g_hair, b_hair))
|
||||
update_dna()
|
||||
return 1
|
||||
if(href_list["facial_hair"])
|
||||
if(can_change(APPEARANCE_FACIAL_HAIR) && (href_list["facial_hair"] in valid_facial_hairstyles))
|
||||
if(owner.change_facial_hair(href_list["facial_hair"]))
|
||||
update_dna()
|
||||
return 1
|
||||
if(href_list["facial_hair_color"])
|
||||
if(can_change(APPEARANCE_FACIAL_HAIR_COLOR))
|
||||
var/new_facial = input("Please select facial hair color.", "Facial Hair Color", rgb(owner.r_facial, owner.g_facial, owner.b_facial)) as color|null
|
||||
if(new_facial && can_still_topic())
|
||||
var/r_facial = hex2num(copytext(new_facial, 2, 4))
|
||||
var/g_facial = hex2num(copytext(new_facial, 4, 6))
|
||||
var/b_facial = hex2num(copytext(new_facial, 6, 8))
|
||||
if(owner.change_facial_hair_color(r_facial, g_facial, b_facial))
|
||||
update_dna()
|
||||
return 1
|
||||
if(href_list["eye_color"])
|
||||
if(can_change(APPEARANCE_EYE_COLOR))
|
||||
var/new_eyes = input("Please select eye color.", "Eye Color", rgb(owner.r_eyes, owner.g_eyes, owner.b_eyes)) as color|null
|
||||
if(new_eyes && can_still_topic())
|
||||
var/r_eyes = hex2num(copytext(new_eyes, 2, 4))
|
||||
var/g_eyes = hex2num(copytext(new_eyes, 4, 6))
|
||||
var/b_eyes = hex2num(copytext(new_eyes, 6, 8))
|
||||
if(owner.change_eye_color(r_eyes, g_eyes, b_eyes))
|
||||
update_dna()
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
/obj/nano_module/appearance_changer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
generate_data(check_whitelist, whitelist, blacklist)
|
||||
var/data[0]
|
||||
|
||||
data["specimen"] = owner.species.name
|
||||
data["gender"] = owner.gender
|
||||
data["change_race"] = can_change(APPEARANCE_RACE)
|
||||
if(data["change_race"])
|
||||
var/species[0]
|
||||
for(var/specimen in valid_species)
|
||||
species[++species.len] = list("specimen" = specimen)
|
||||
data["species"] = species
|
||||
|
||||
data["change_gender"] = can_change(APPEARANCE_GENDER)
|
||||
data["change_skin_tone"] = can_change_skin_tone()
|
||||
data["change_skin_color"] = can_change_skin_color()
|
||||
data["change_eye_color"] = can_change(APPEARANCE_EYE_COLOR)
|
||||
data["change_hair"] = can_change(APPEARANCE_HAIR)
|
||||
if(data["change_hair"])
|
||||
var/hair_styles[0]
|
||||
for(var/hair_style in valid_hairstyles)
|
||||
hair_styles[++hair_styles.len] = list("hairstyle" = hair_style)
|
||||
data["hair_styles"] = hair_styles
|
||||
data["hair_style"] = owner.h_style
|
||||
|
||||
data["change_facial_hair"] = can_change(APPEARANCE_FACIAL_HAIR)
|
||||
if(data["change_facial_hair"])
|
||||
var/facial_hair_styles[0]
|
||||
for(var/facial_hair_style in valid_facial_hairstyles)
|
||||
facial_hair_styles[++facial_hair_styles.len] = list("facialhairstyle" = facial_hair_style)
|
||||
data["facial_hair_styles"] = facial_hair_styles
|
||||
data["facial_hair_style"] = owner.f_style
|
||||
|
||||
data["change_hair_color"] = can_change(APPEARANCE_HAIR_COLOR)
|
||||
data["change_facial_hair_color"] = can_change(APPEARANCE_FACIAL_HAIR_COLOR)
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "appearance_changer.tmpl", "[src.name]", 800, 450)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/nano_module/appearance_changer/proc/update_dna()
|
||||
if(owner && (flags & APPEARANCE_UPDATE_DNA))
|
||||
owner.update_dna()
|
||||
|
||||
/obj/nano_module/appearance_changer/proc/can_change(var/flag)
|
||||
return owner && (flags & flag)
|
||||
|
||||
/obj/nano_module/appearance_changer/proc/can_change_skin_tone()
|
||||
return owner && (flags & APPEARANCE_SKIN) && owner.species.flags & HAS_SKIN_TONE
|
||||
|
||||
/obj/nano_module/appearance_changer/proc/can_change_skin_color()
|
||||
return owner && (flags & APPEARANCE_SKIN) && owner.species.flags & HAS_SKIN_COLOR
|
||||
|
||||
/obj/nano_module/appearance_changer/proc/can_still_topic()
|
||||
return CanUseTopic(usr, list(), default_state) == STATUS_INTERACTIVE
|
||||
|
||||
/obj/nano_module/appearance_changer/proc/cut_and_generate_data()
|
||||
// Making the assumption that the available species remain constant
|
||||
valid_facial_hairstyles.Cut()
|
||||
valid_facial_hairstyles.Cut()
|
||||
generate_data()
|
||||
|
||||
/obj/nano_module/appearance_changer/proc/generate_data()
|
||||
if(!valid_species.len)
|
||||
valid_species = owner.generate_valid_species(check_whitelist, whitelist, blacklist)
|
||||
if(!valid_hairstyles.len || !valid_facial_hairstyles.len)
|
||||
valid_hairstyles = owner.generate_valid_hairstyles()
|
||||
valid_facial_hairstyles = owner.generate_valid_facial_hairstyles()
|
||||
@@ -1,11 +1,11 @@
|
||||
/atom/movable/proc/nano_host()
|
||||
/atom/proc/nano_host()
|
||||
return src
|
||||
|
||||
/obj/nano_module/nano_host()
|
||||
return loc
|
||||
|
||||
|
||||
/atom/movable/proc/CanUseTopic(var/mob/user, href_list, var/datum/topic_state/custom_state)
|
||||
/atom/proc/CanUseTopic(var/mob/user, href_list, var/datum/topic_state/custom_state)
|
||||
return user.can_use_topic(nano_host(), custom_state)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#define EMITTER_DAMAGE_POWER_TRANSFER 450 //used to transfer power to containment field generators
|
||||
|
||||
/obj/machinery/power/emitter
|
||||
name = "Emitter"
|
||||
name = "emitter"
|
||||
desc = "It is a heavy duty industrial laser."
|
||||
icon = 'icons/obj/singularity.dmi'
|
||||
icon_state = "emitter"
|
||||
@@ -60,18 +60,18 @@
|
||||
/obj/machinery/power/emitter/proc/activate(mob/user as mob)
|
||||
if(state == 2)
|
||||
if(!powernet)
|
||||
user << "The emitter isn't connected to a wire."
|
||||
user << "\The [src] isn't connected to a wire."
|
||||
return 1
|
||||
if(!src.locked)
|
||||
if(src.active==1)
|
||||
src.active = 0
|
||||
user << "You turn off the [src]."
|
||||
user << "You turn off [src]."
|
||||
message_admins("Emitter turned off by [key_name(user, user.client)](<A HREF='?_src_=holder;adminmoreinfo=\ref[user]'>?</A>) in ([x],[y],[z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)",0,1)
|
||||
log_game("Emitter turned off by [user.ckey]([user]) in ([x],[y],[z])")
|
||||
investigate_log("turned <font color='red'>off</font> by [user.key]","singulo")
|
||||
else
|
||||
src.active = 1
|
||||
user << "You turn on the [src]."
|
||||
user << "You turn on [src]."
|
||||
src.shot_number = 0
|
||||
src.fire_delay = 100
|
||||
message_admins("Emitter turned on by [key_name(user, user.client)](<A HREF='?_src_=holder;adminmoreinfo=\ref[user]'>?</A>) in ([x],[y],[z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)",0,1)
|
||||
@@ -79,9 +79,9 @@
|
||||
investigate_log("turned <font color='green'>on</font> by [user.key]","singulo")
|
||||
update_icon()
|
||||
else
|
||||
user << "\red The controls are locked!"
|
||||
user << "<span class='warning'>The controls are locked!</span>"
|
||||
else
|
||||
user << "\red The [src] needs to be firmly secured to the floor first."
|
||||
user << "<span class='warning'>\The [src] needs to be firmly secured to the floor first.</span>"
|
||||
return 1
|
||||
|
||||
|
||||
@@ -138,86 +138,83 @@
|
||||
s.set_up(5, 1, src)
|
||||
s.start()
|
||||
A.set_dir(src.dir)
|
||||
A.starting = get_turf(src)
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
A.yo = 20
|
||||
A.xo = 0
|
||||
A.original = locate(x, y+1, z)
|
||||
if(EAST)
|
||||
A.yo = 0
|
||||
A.xo = 20
|
||||
A.original = locate(x+1, y, z)
|
||||
if(WEST)
|
||||
A.yo = 0
|
||||
A.xo = -20
|
||||
A.original = locate(x-1, y, z)
|
||||
else // Any other
|
||||
A.yo = -20
|
||||
A.xo = 0
|
||||
A.process() //TODO: Carn: check this out
|
||||
A.original = locate(x, y-1, z)
|
||||
A.process()
|
||||
|
||||
|
||||
/obj/machinery/power/emitter/attackby(obj/item/W, mob/user)
|
||||
|
||||
if(istype(W, /obj/item/weapon/wrench))
|
||||
if(active)
|
||||
user << "Turn off the [src] first."
|
||||
user << "Turn off [src] first."
|
||||
return
|
||||
switch(state)
|
||||
if(0)
|
||||
state = 1
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
user.visible_message("[user.name] secures [src.name] to the floor.", \
|
||||
user.visible_message("[user.name] secures [src] to the floor.", \
|
||||
"You secure the external reinforcing bolts to the floor.", \
|
||||
"You hear a ratchet")
|
||||
src.anchored = 1
|
||||
if(1)
|
||||
state = 0
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
user.visible_message("[user.name] unsecures [src.name] reinforcing bolts from the floor.", \
|
||||
user.visible_message("[user.name] unsecures [src] reinforcing bolts from the floor.", \
|
||||
"You undo the external reinforcing bolts.", \
|
||||
"You hear a ratchet")
|
||||
src.anchored = 0
|
||||
if(2)
|
||||
user << "\red The [src.name] needs to be unwelded from the floor."
|
||||
user << "<span class='warning'>\The [src] needs to be unwelded from the floor.</span>"
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/weapon/weldingtool))
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
if(active)
|
||||
user << "Turn off the [src] first."
|
||||
user << "Turn off [src] first."
|
||||
return
|
||||
switch(state)
|
||||
if(0)
|
||||
user << "\red The [src.name] needs to be wrenched to the floor."
|
||||
user << "<span class='warning'>\The [src] needs to be wrenched to the floor.</span>"
|
||||
if(1)
|
||||
if (WT.remove_fuel(0,user))
|
||||
playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
|
||||
user.visible_message("[user.name] starts to weld the [src.name] to the floor.", \
|
||||
"You start to weld the [src] to the floor.", \
|
||||
user.visible_message("[user.name] starts to weld [src] to the floor.", \
|
||||
"You start to weld [src] to the floor.", \
|
||||
"You hear welding")
|
||||
if (do_after(user,20))
|
||||
if(!src || !WT.isOn()) return
|
||||
state = 2
|
||||
user << "You weld the [src] to the floor."
|
||||
user << "You weld [src] to the floor."
|
||||
connect_to_network()
|
||||
else
|
||||
user << "\red You need more welding fuel to complete this task."
|
||||
user << "<span class='warning'>You need more welding fuel to complete this task.</span>"
|
||||
if(2)
|
||||
if (WT.remove_fuel(0,user))
|
||||
playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
|
||||
user.visible_message("[user.name] starts to cut the [src.name] free from the floor.", \
|
||||
"You start to cut the [src] free from the floor.", \
|
||||
user.visible_message("[user.name] starts to cut [src] free from the floor.", \
|
||||
"You start to cut [src] free from the floor.", \
|
||||
"You hear welding")
|
||||
if (do_after(user,20))
|
||||
if(!src || !WT.isOn()) return
|
||||
state = 1
|
||||
user << "You cut the [src] free from the floor."
|
||||
user << "You cut [src] free from the floor."
|
||||
disconnect_from_network()
|
||||
else
|
||||
user << "\red You need more welding fuel to complete this task."
|
||||
user << "<span class='warning'>You need more welding fuel to complete this task.</span>"
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/weapon/card/id) || istype(W, /obj/item/device/pda))
|
||||
if(emagged)
|
||||
user << "\red The lock seems to be broken"
|
||||
user << "<span class='warning'>The lock seems to be broken.</span>"
|
||||
return
|
||||
if(src.allowed(user))
|
||||
if(active)
|
||||
@@ -225,16 +222,16 @@
|
||||
user << "The controls are now [src.locked ? "locked." : "unlocked."]"
|
||||
else
|
||||
src.locked = 0 //just in case it somehow gets locked
|
||||
user << "\red The controls can only be locked when the [src] is online"
|
||||
user << "<span class='warning'>The controls can only be locked when [src] is online.</span>"
|
||||
else
|
||||
user << "\red Access denied."
|
||||
user << "<span class='warning'>Access denied.</span>"
|
||||
return
|
||||
|
||||
|
||||
if(istype(W, /obj/item/weapon/card/emag) && !emagged)
|
||||
locked = 0
|
||||
emagged = 1
|
||||
user.visible_message("[user.name] emags the [src.name].","\red You short out the lock.")
|
||||
user.visible_message("[user.name] emags [src].","<span class='warning'>You short out the lock.</span>")
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/obj/effect/projectile
|
||||
icon = 'icons/effects/projectiles.dmi'
|
||||
icon_state = "bolt"
|
||||
layer = 20
|
||||
|
||||
/obj/effect/projectile/New(var/turf/location)
|
||||
if(istype(location))
|
||||
loc = location
|
||||
|
||||
/obj/effect/projectile/proc/set_transform(var/matrix/M)
|
||||
if(istype(M))
|
||||
transform = M
|
||||
|
||||
/obj/effect/projectile/proc/activate()
|
||||
spawn(3)
|
||||
delete() //see effect_system.dm - sets loc to null and lets GC handle removing these effects
|
||||
|
||||
return
|
||||
|
||||
//----------------------------
|
||||
// Laser beam
|
||||
//----------------------------
|
||||
/obj/effect/projectile/laser/tracer
|
||||
icon_state = "beam"
|
||||
|
||||
/obj/effect/projectile/laser/muzzle
|
||||
icon_state = "muzzle_laser"
|
||||
|
||||
/obj/effect/projectile/laser/impact
|
||||
icon_state = "impact_laser"
|
||||
|
||||
//----------------------------
|
||||
// Blue laser beam
|
||||
//----------------------------
|
||||
/obj/effect/projectile/laser_blue/tracer
|
||||
icon_state = "beam_blue"
|
||||
|
||||
/obj/effect/projectile/laser_blue/muzzle
|
||||
icon_state = "muzzle_blue"
|
||||
|
||||
/obj/effect/projectile/laser_blue/impact
|
||||
icon_state = "impact_blue"
|
||||
|
||||
//----------------------------
|
||||
// Omni laser beam
|
||||
//----------------------------
|
||||
/obj/effect/projectile/laser_omni/tracer
|
||||
icon_state = "beam_omni"
|
||||
|
||||
/obj/effect/projectile/laser_omni/muzzle
|
||||
icon_state = "muzzle_omni"
|
||||
|
||||
/obj/effect/projectile/laser_omni/impact
|
||||
icon_state = "impact_omni"
|
||||
|
||||
//----------------------------
|
||||
// Xray laser beam
|
||||
//----------------------------
|
||||
/obj/effect/projectile/xray/tracer
|
||||
icon_state = "xray"
|
||||
|
||||
/obj/effect/projectile/xray/muzzle
|
||||
icon_state = "muzzle_xray"
|
||||
|
||||
/obj/effect/projectile/xray/impact
|
||||
icon_state = "impact_xray"
|
||||
|
||||
//----------------------------
|
||||
// Heavy laser beam
|
||||
//----------------------------
|
||||
/obj/effect/projectile/laser_heavy/tracer
|
||||
icon_state = "beam_heavy"
|
||||
|
||||
/obj/effect/projectile/laser_heavy/muzzle
|
||||
icon_state = "muzzle_beam_heavy"
|
||||
|
||||
/obj/effect/projectile/laser_heavy/impact
|
||||
icon_state = "impact_beam_heavy"
|
||||
|
||||
//----------------------------
|
||||
// Pulse laser beam
|
||||
//----------------------------
|
||||
/obj/effect/projectile/laser_pulse/tracer
|
||||
icon_state = "u_laser"
|
||||
|
||||
/obj/effect/projectile/laser_pulse/muzzle
|
||||
icon_state = "muzzle_u_laser"
|
||||
|
||||
/obj/effect/projectile/laser_pulse/impact
|
||||
icon_state = "impact_u_laser"
|
||||
|
||||
//----------------------------
|
||||
// Pulse muzzle effect only
|
||||
//----------------------------
|
||||
/obj/effect/projectile/pulse/muzzle
|
||||
icon_state = "muzzle_pulse"
|
||||
|
||||
//----------------------------
|
||||
// Emitter beam
|
||||
//----------------------------
|
||||
/obj/effect/projectile/emitter/tracer
|
||||
icon_state = "emitter"
|
||||
|
||||
/obj/effect/projectile/emitter/muzzle
|
||||
icon_state = "muzzle_emitter"
|
||||
|
||||
/obj/effect/projectile/emitter/impact
|
||||
icon_state = "impact_emitter"
|
||||
|
||||
//----------------------------
|
||||
// Stun beam
|
||||
//----------------------------
|
||||
/obj/effect/projectile/stun/tracer
|
||||
icon_state = "stun"
|
||||
|
||||
/obj/effect/projectile/stun/muzzle
|
||||
icon_state = "muzzle_stun"
|
||||
|
||||
/obj/effect/projectile/stun/impact
|
||||
icon_state = "impact_stun"
|
||||
|
||||
//----------------------------
|
||||
// Bullet
|
||||
//----------------------------
|
||||
/obj/effect/projectile/bullet/muzzle
|
||||
icon_state = "muzzle_bullet"
|
||||
@@ -6,6 +6,8 @@
|
||||
embed = 1 //the dart is shot fast enough to pierce space suits, so I guess splintering inside the target can be a thing. Should be rare due to low damage.
|
||||
var/reagent_amount = 15
|
||||
kill_count = 15 //shorter range
|
||||
|
||||
muzzle_type = null
|
||||
|
||||
/obj/item/projectile/bullet/chemdart/New()
|
||||
reagents = new/datum/reagents(reagent_amount)
|
||||
|
||||
@@ -51,6 +51,18 @@
|
||||
var/drowsy = 0
|
||||
var/agony = 0
|
||||
var/embed = 0 // whether or not the projectile can embed itself in the mob
|
||||
|
||||
var/hitscan = 0 // whether the projectile should be hitscan
|
||||
|
||||
// effect types to be used
|
||||
var/muzzle_type
|
||||
var/tracer_type
|
||||
var/impact_type
|
||||
|
||||
var/datum/plot_vector/trajectory // used to plot the path of the projectile
|
||||
var/datum/vector_loc/location // current location of the projectile in pixel space
|
||||
var/matrix/effect_transform // matrix to rotate and scale projectile effects - putting it here so it doesn't
|
||||
// have to be recreated multiple times
|
||||
|
||||
//TODO: make it so this is called more reliably, instead of sometimes by bullet_act() and sometimes not
|
||||
/obj/item/projectile/proc/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null)
|
||||
@@ -63,6 +75,7 @@
|
||||
|
||||
//called when the projectile stops flying because it collided with something
|
||||
/obj/item/projectile/proc/on_impact(var/atom/A)
|
||||
impact_effect(effect_transform) // generate impact effect
|
||||
return
|
||||
|
||||
//Checks if the projectile is eligible for embedding. Not that it necessarily will.
|
||||
@@ -228,6 +241,7 @@
|
||||
|
||||
density = 0
|
||||
invisibility = 101
|
||||
|
||||
del(src)
|
||||
return 1
|
||||
|
||||
@@ -240,23 +254,86 @@
|
||||
return 1
|
||||
|
||||
/obj/item/projectile/process()
|
||||
var/first_step = 1
|
||||
|
||||
//plot the initial trajectory
|
||||
setup_trajectory()
|
||||
|
||||
spawn while(src)
|
||||
if(kill_count-- < 1)
|
||||
on_impact(src.loc) //for any final impact behaviours
|
||||
del(src)
|
||||
del(src)
|
||||
if((!( current ) || loc == current))
|
||||
current = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z)
|
||||
if((x == 1 || x == world.maxx || y == 1 || y == world.maxy))
|
||||
del(src)
|
||||
return
|
||||
step_towards(src, current)
|
||||
sleep(1)
|
||||
|
||||
trajectory.increment() // increment the current location
|
||||
location = trajectory.return_location(location) // update the locally stored location data
|
||||
|
||||
if(!location)
|
||||
del(src) // if it's left the world... kill it
|
||||
|
||||
Move(location.return_turf())
|
||||
|
||||
if(first_step)
|
||||
muzzle_effect(effect_transform)
|
||||
first_step = 0
|
||||
else
|
||||
tracer_effect(effect_transform)
|
||||
|
||||
if(!bumped && !isturf(original))
|
||||
if(loc == get_turf(original))
|
||||
if(!(original in permutated))
|
||||
Bump(original)
|
||||
sleep(1)
|
||||
|
||||
|
||||
if(!hitscan)
|
||||
sleep(1) //add delay between movement iterations if it's not a hitscan weapon
|
||||
|
||||
/obj/item/projectile/proc/setup_trajectory()
|
||||
// plot the initial trajectory
|
||||
trajectory = new()
|
||||
trajectory.setup(starting, original, pixel_x, pixel_y)
|
||||
|
||||
// generate this now since all visual effects the projectile makes can use it
|
||||
effect_transform = new()
|
||||
effect_transform.Scale(trajectory.return_hypotenuse(), 1)
|
||||
effect_transform.Turn(-trajectory.return_angle()) //no idea why this has to be inverted, but it works
|
||||
|
||||
/obj/item/projectile/proc/muzzle_effect(var/matrix/T)
|
||||
if(silenced)
|
||||
return
|
||||
|
||||
if(ispath(muzzle_type))
|
||||
var/obj/effect/projectile/M = new muzzle_type(get_turf(src))
|
||||
|
||||
if(istype(M))
|
||||
M.set_transform(T)
|
||||
M.pixel_x = location.pixel_x
|
||||
M.pixel_y = location.pixel_y
|
||||
M.activate()
|
||||
|
||||
/obj/item/projectile/proc/tracer_effect(var/matrix/M)
|
||||
if(ispath(tracer_type))
|
||||
var/obj/effect/projectile/P = new tracer_type(location.loc)
|
||||
|
||||
if(istype(P))
|
||||
P.set_transform(M)
|
||||
P.pixel_x = location.pixel_x
|
||||
P.pixel_y = location.pixel_y
|
||||
P.activate()
|
||||
|
||||
/obj/item/projectile/proc/impact_effect(var/matrix/M)
|
||||
if(ispath(tracer_type))
|
||||
var/obj/effect/projectile/P = new impact_type(location.loc)
|
||||
|
||||
if(istype(P))
|
||||
P.set_transform(M)
|
||||
P.pixel_x = location.pixel_x
|
||||
P.pixel_y = location.pixel_y
|
||||
P.activate()
|
||||
|
||||
//"Tracing" projectile
|
||||
/obj/item/projectile/test //Used to see if you can hit them.
|
||||
invisibility = 101 //Nope! Can't see me!
|
||||
@@ -285,12 +362,21 @@
|
||||
yo = targloc.y - curloc.y
|
||||
xo = targloc.x - curloc.x
|
||||
target = targloc
|
||||
|
||||
//plot the initial trajectory
|
||||
setup_trajectory()
|
||||
|
||||
while(src) //Loop on through!
|
||||
if(result)
|
||||
return (result - 1)
|
||||
if((!( target ) || loc == target))
|
||||
target = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z) //Finding the target turf at map edge
|
||||
step_towards(src, target)
|
||||
|
||||
trajectory.increment() // increment the current location
|
||||
location = trajectory.return_location(location) // update the locally stored location data
|
||||
|
||||
Move(location.return_turf())
|
||||
|
||||
var/mob/living/M = locate() in get_turf(src)
|
||||
if(istype(M)) //If there is someting living...
|
||||
return 1 //Return 1
|
||||
@@ -310,4 +396,4 @@
|
||||
trace.firer = user
|
||||
var/output = trace.process() //Test it!
|
||||
del(trace) //No need for it anymore
|
||||
return output //Send it back to the gun!
|
||||
return output //Send it back to the gun!
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
var/list/beam_master = list()
|
||||
//Use: Caches beam state images and holds turfs that had these images overlaid.
|
||||
//Structure:
|
||||
//beam_master
|
||||
// icon_states/dirs of beams
|
||||
// image for that beam
|
||||
// references for fired beams
|
||||
// icon_states/dirs for each placed beam image
|
||||
// turfs that have that icon_state/dir
|
||||
|
||||
/obj/item/projectile/beam
|
||||
name = "laser"
|
||||
icon_state = "laser"
|
||||
@@ -17,69 +7,11 @@ var/list/beam_master = list()
|
||||
check_armour = "laser"
|
||||
eyeblur = 4
|
||||
var/frequency = 1
|
||||
hitscan = 1
|
||||
|
||||
/obj/item/projectile/beam/process()
|
||||
var/reference = "\ref[src]" //So we do not have to recalculate it a ton
|
||||
var/first = 1 //So we don't make the overlay in the same tile as the firer
|
||||
spawn while(src) //Move until we hit something
|
||||
|
||||
if((!( current ) || loc == current)) //If we pass our target
|
||||
current = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z)
|
||||
if((x == 1 || x == world.maxx || y == 1 || y == world.maxy))
|
||||
del(src) //Delete if it passes the world edge
|
||||
return
|
||||
step_towards(src, current) //Move~
|
||||
|
||||
if(kill_count < 1)
|
||||
del(src)
|
||||
kill_count--
|
||||
|
||||
if(!bumped && !isturf(original))
|
||||
if(loc == get_turf(original))
|
||||
if(!(original in permutated))
|
||||
Bump(original)
|
||||
|
||||
if(!first) //Add the overlay as we pass over tiles
|
||||
var/target_dir = get_dir(src, current) //So we don't call this too much
|
||||
|
||||
//If the icon has not been added yet
|
||||
if( !("[icon_state][target_dir]" in beam_master) )
|
||||
var/image/I = image(icon,icon_state,10,target_dir) //Generate it.
|
||||
beam_master["[icon_state][target_dir]"] = I //And cache it!
|
||||
|
||||
//Finally add the overlay
|
||||
src.loc.overlays += beam_master["[icon_state][target_dir]"]
|
||||
|
||||
//Add the turf to a list in the beam master so they can be cleaned up easily.
|
||||
if(reference in beam_master)
|
||||
var/list/turf_master = beam_master[reference]
|
||||
if("[icon_state][target_dir]" in turf_master)
|
||||
var/list/turfs = turf_master["[icon_state][target_dir]"]
|
||||
turfs += loc
|
||||
else
|
||||
turf_master["[icon_state][target_dir]"] = list(loc)
|
||||
else
|
||||
var/list/turfs = list()
|
||||
turfs["[icon_state][target_dir]"] = list(loc)
|
||||
beam_master[reference] = turfs
|
||||
else
|
||||
first = 0
|
||||
cleanup(reference)
|
||||
return
|
||||
|
||||
/obj/item/projectile/beam/Del()
|
||||
cleanup("\ref[src]")
|
||||
..()
|
||||
|
||||
/obj/item/projectile/beam/proc/cleanup(reference) //Waits .3 seconds then removes the overlay.
|
||||
src = null //we're getting deleted! this will keep the code running
|
||||
spawn(3)
|
||||
var/list/turf_master = beam_master[reference]
|
||||
for(var/laser_state in turf_master)
|
||||
var/list/turfs = turf_master[laser_state]
|
||||
for(var/turf/T in turfs)
|
||||
T.overlays -= beam_master[laser_state]
|
||||
return
|
||||
muzzle_type = /obj/effect/projectile/laser/muzzle
|
||||
tracer_type = /obj/effect/projectile/laser/tracer
|
||||
impact_type = /obj/effect/projectile/laser/impact
|
||||
|
||||
/obj/item/projectile/beam/practice
|
||||
name = "laser"
|
||||
@@ -95,16 +27,28 @@ var/list/beam_master = list()
|
||||
icon_state = "heavylaser"
|
||||
damage = 60
|
||||
|
||||
muzzle_type = /obj/effect/projectile/laser_heavy/muzzle
|
||||
tracer_type = /obj/effect/projectile/laser_heavy/tracer
|
||||
impact_type = /obj/effect/projectile/laser_heavy/impact
|
||||
|
||||
/obj/item/projectile/beam/xray
|
||||
name = "xray beam"
|
||||
icon_state = "xray"
|
||||
damage = 30
|
||||
|
||||
muzzle_type = /obj/effect/projectile/xray/muzzle
|
||||
tracer_type = /obj/effect/projectile/xray/tracer
|
||||
impact_type = /obj/effect/projectile/xray/impact
|
||||
|
||||
/obj/item/projectile/beam/pulse
|
||||
name = "pulse"
|
||||
icon_state = "u_laser"
|
||||
damage = 50
|
||||
|
||||
muzzle_type = /obj/effect/projectile/laser_pulse/muzzle
|
||||
tracer_type = /obj/effect/projectile/laser_pulse/tracer
|
||||
impact_type = /obj/effect/projectile/laser_pulse/impact
|
||||
|
||||
/obj/item/projectile/beam/pulse/on_hit(var/atom/target, var/blocked = 0)
|
||||
if(isturf(target))
|
||||
target.ex_act(2)
|
||||
@@ -115,6 +59,10 @@ var/list/beam_master = list()
|
||||
icon_state = "emitter"
|
||||
damage = 0 // The actual damage is computed in /code/modules/power/singularity/emitter.dm
|
||||
|
||||
muzzle_type = /obj/effect/projectile/emitter/muzzle
|
||||
tracer_type = /obj/effect/projectile/emitter/tracer
|
||||
impact_type = /obj/effect/projectile/emitter/impact
|
||||
|
||||
/obj/item/projectile/beam/lastertag/blue
|
||||
name = "lasertag beam"
|
||||
icon_state = "bluelaser"
|
||||
@@ -123,6 +71,10 @@ var/list/beam_master = list()
|
||||
damage_type = BURN
|
||||
check_armour = "laser"
|
||||
|
||||
muzzle_type = /obj/effect/projectile/laser_blue/muzzle
|
||||
tracer_type = /obj/effect/projectile/laser_blue/tracer
|
||||
impact_type = /obj/effect/projectile/laser_blue/impact
|
||||
|
||||
/obj/item/projectile/beam/lastertag/blue/on_hit(var/atom/target, var/blocked = 0)
|
||||
if(istype(target, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/M = target
|
||||
@@ -153,6 +105,10 @@ var/list/beam_master = list()
|
||||
damage_type = BURN
|
||||
check_armour = "laser"
|
||||
|
||||
muzzle_type = /obj/effect/projectile/laser_omni/muzzle
|
||||
tracer_type = /obj/effect/projectile/laser_omni/tracer
|
||||
impact_type = /obj/effect/projectile/laser_omni/impact
|
||||
|
||||
/obj/item/projectile/beam/lastertag/omni/on_hit(var/atom/target, var/blocked = 0)
|
||||
if(istype(target, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/M = target
|
||||
@@ -168,6 +124,10 @@ var/list/beam_master = list()
|
||||
weaken = 3
|
||||
stutter = 3
|
||||
|
||||
muzzle_type = /obj/effect/projectile/xray/muzzle
|
||||
tracer_type = /obj/effect/projectile/xray/tracer
|
||||
impact_type = /obj/effect/projectile/xray/impact
|
||||
|
||||
/obj/item/projectile/beam/stun
|
||||
name = "stun beam"
|
||||
icon_state = "stun"
|
||||
@@ -175,3 +135,7 @@ var/list/beam_master = list()
|
||||
taser_effect = 1
|
||||
agony = 40
|
||||
damage_type = HALLOSS
|
||||
|
||||
muzzle_type = /obj/effect/projectile/stun/muzzle
|
||||
tracer_type = /obj/effect/projectile/stun/tracer
|
||||
impact_type = /obj/effect/projectile/stun/impact
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
embed = 1
|
||||
sharp = 1
|
||||
var/mob_passthrough_check = 0
|
||||
|
||||
muzzle_type = /obj/effect/projectile/bullet/muzzle
|
||||
|
||||
/obj/item/projectile/bullet/on_hit(var/atom/target, var/blocked = 0)
|
||||
if (..(target, blocked))
|
||||
|
||||
Reference in New Issue
Block a user