mirror of
https://github.com/goonstation/goonstation-2020.git
synced 2026-07-12 23:52:20 +01:00
1779 lines
46 KiB
Plaintext
1779 lines
46 KiB
Plaintext
/client/proc/dbg_itemspecial(var/obj/item/I in world)
|
|
set name = "Give Special"
|
|
var/sel = input(usr,"Type:","Select type") in childrentypesof(/datum/item_special)
|
|
I.max_stack = INFINITY
|
|
I.amount = INFINITY
|
|
I.setItemSpecial(sel)
|
|
return
|
|
|
|
/datum/limb/proc/dbg_itemspecial()
|
|
var/sel = input(usr,"Type:","Select type for Disarm:") in childrentypesof(/datum/item_special)
|
|
src.setDisarmSpecial(sel)
|
|
sel = input(usr,"Type:","Select type for Harm:") in childrentypesof(/datum/item_special)
|
|
src.setHarmSpecial(sel)
|
|
|
|
/proc/get_dir_alt(var/atom/source, var/atom/target) //Opposite of default get dir, only returns diagonal if target perfectly diagonal
|
|
if(abs(source.x-target.x) > abs(source.y-target.y)) //Mostly left/right with a little up or down
|
|
if(source.x > target.x) //Target left
|
|
return WEST
|
|
else if (source.x < target.x) //Target right
|
|
return EAST
|
|
else if (abs(source.x-target.x) < abs(source.y-target.y)) //Mostly up/down with a little left right
|
|
if(source.y > target.y) //Target below
|
|
return SOUTH
|
|
else if (source.y < target.y) //Target above
|
|
return NORTH
|
|
else if (abs(source.x-target.x) == abs(source.y-target.y)) //Perfectly diagonal
|
|
if(source.x > target.x) //Target left
|
|
if(source.y > target.y) //Target below
|
|
return SOUTHWEST
|
|
else if (source.y < target.y) //Target above
|
|
return NORTHWEST
|
|
else if (source.x < target.x) //Target right
|
|
if(source.y > target.y) //Target below
|
|
return SOUTHEAST
|
|
else if (source.y < target.y) //Target above
|
|
return NORTHEAST
|
|
return NORTH
|
|
|
|
/proc/get_dir_pixel(var/atom/source, var/atom/target, params) //Get_dir using pixel coordinates of mouse
|
|
var/dx = (target.x - source.x) * 32
|
|
var/dy = (target.y - source.y) * 32
|
|
|
|
if (!islist(params))
|
|
params = params2list(params)
|
|
|
|
if(params["icon-x"])
|
|
dx += (text2num(params["icon-x"]) - 16)
|
|
|
|
if(params["icon-y"])
|
|
dy += (text2num(params["icon-y"]) - 16)
|
|
|
|
var/angle = atan2(dy,dx)
|
|
//boutput(world, "[dx] : [dy] ::: makes for [angle]")
|
|
|
|
//oh no ! i'm bad!!!!!!!!!!!
|
|
//note that the diagonals have a slightly smaller click area than cardinals.
|
|
if (angle >= 0)
|
|
if (angle < 25)
|
|
return NORTH
|
|
else if (angle <= 65)
|
|
return NORTHEAST
|
|
else if (angle < 115)
|
|
return EAST
|
|
else if (angle <= 155)
|
|
return SOUTHEAST
|
|
else
|
|
return SOUTH
|
|
else if (angle < 0)
|
|
if (angle > -25)
|
|
return NORTH
|
|
else if (angle >= -65)
|
|
return NORTHWEST
|
|
else if (angle > -115)
|
|
return WEST
|
|
else if (angle >= -155)
|
|
return SOUTHWEST
|
|
else
|
|
return SOUTH
|
|
|
|
return NORTH
|
|
|
|
|
|
|
|
|
|
#define ITEMSPECIAL_PIXELDIST_SQUARED (70 * 70) //lol i'm putting the define RIGHT HERE.
|
|
// These two numbers will be compared later (pixeldist squared AND the result of this function). We don't need to do unnessecary sqrt cause this is just a simple < > comparison!
|
|
/proc/get_dist_pixel_squared(var/atom/source, var/atom/target, params)
|
|
var/dx = (target.x - source.x) * 32
|
|
var/dy = (target.y - source.y) * 32
|
|
|
|
if (!islist(params))
|
|
params = params2list(params)
|
|
|
|
if(params["icon-x"])
|
|
dx += (text2num(params["icon-x"]) - 16)
|
|
|
|
if(params["icon-y"])
|
|
dy += (text2num(params["icon-y"]) - 16)
|
|
|
|
return ((dx*dx) + (dy*dy))
|
|
|
|
//Handles setup for specials and adds / removes them from items.
|
|
/obj/item/proc/setItemSpecial(var/type = null)
|
|
if(!ispath(type))
|
|
if(isnull(type))
|
|
if(src.special)
|
|
src.special.onRemove()
|
|
src.special = null
|
|
return null
|
|
|
|
if(src.special)
|
|
src.special.onRemove()
|
|
|
|
var/datum/item_special/S = new type
|
|
S.master = src
|
|
S.onAdd()
|
|
src.special = S
|
|
return S
|
|
|
|
/datum/limb/proc/setDisarmSpecial(var/type = null)
|
|
if(!ispath(type))
|
|
if(isnull(type))
|
|
if(src.disarm_special)
|
|
src.disarm_special.onRemove()
|
|
src.disarm_special = null
|
|
return null
|
|
|
|
if(src.disarm_special)
|
|
src.disarm_special.onRemove()
|
|
|
|
src.disarm_special = new type
|
|
src.disarm_special.onAdd()
|
|
return src.disarm_special
|
|
|
|
/datum/limb/proc/setHarmSpecial(var/type = null)
|
|
if(!ispath(type))
|
|
if(isnull(type))
|
|
if(src.harm_special)
|
|
src.harm_special.onRemove()
|
|
src.harm_special = null
|
|
return null
|
|
|
|
if(src.harm_special)
|
|
src.harm_special.onRemove()
|
|
|
|
src.harm_special = new type
|
|
src.harm_special.onAdd()
|
|
return src.harm_special
|
|
|
|
|
|
//This needs to happen in process_move(), not Move() so we can change the delay modifier before it is put to use
|
|
/mob/living/process_move(keys)
|
|
if (apply_movement_delay_until != -1)
|
|
if (apply_movement_delay_until >= world.time)
|
|
//Don't pick a delay modifier that will exceed the bounds of our delay apply window
|
|
movement_delay_modifier = min(movement_delay_modifier, (apply_movement_delay_until - world.time))
|
|
return ..(keys)
|
|
|
|
/datum/item_special/dummy //These don't do anything and are simply used for the tooltip. Used when the special is implemented in another way. Hacky and ugly.
|
|
getDesc()
|
|
return desc + "<br>"
|
|
usable()
|
|
return 0
|
|
|
|
|
|
/datum/item_special
|
|
var/obj/item/master = null //Item that owns this attack
|
|
var/last_use = 0 //Last world.time this was used.
|
|
|
|
var/cooldown = 20 //Cooldown time of attack
|
|
var/staminaCost = 15 //Stamina cost of attack
|
|
var/moveDelay = 10 //Slow movement by this much after attack
|
|
var/moveDelayDuration = 10 //Slow for this long (in BYOND time)
|
|
var/restrainDuration = 0 //time in 1/10th seconds during which we are held in place following an attack
|
|
|
|
var/overrideCrit = 0 //Temporarily switch item to this crit chance during attacks. (if not -1/negative)
|
|
var/overrideStaminaDamage = -1 //Temporarily set item stamina damage to this during attacks (if not -1/negative)
|
|
|
|
var/requiresStaminaToFire = 0 //If true, the user will need to meet a certain stamina requirement to begin the attack.
|
|
var/staminaReqAmt = 15 //Amount of stamina needed to fire. default to stamina cost
|
|
|
|
var/image = "whirlwind"
|
|
var/name = "Whirlwind"
|
|
var/desc = ""
|
|
var/prefix = "" //optional prefix this might apply to some crafted items.
|
|
|
|
var/damageMult = 1
|
|
|
|
proc/onAdd() //Called when added to an item.
|
|
return
|
|
|
|
proc/onRemove() //Called when removed from an item.
|
|
src.master = null
|
|
return
|
|
|
|
proc/getDesc()
|
|
var/infoStr = "[staminaCost ? "[staminaCost] stam, ":""][round(cooldown/10, 0.1)]s CD<br>"
|
|
return infoStr + desc
|
|
|
|
proc/onMouseDrag(src_object,atom/over_object,src_location,over_location,src_control,over_control,params)
|
|
return
|
|
|
|
proc/onMouseDown(atom/target,location,control,params)
|
|
return
|
|
|
|
proc/onMouseUp(atom/target,location,control,params)
|
|
return
|
|
|
|
proc/pixelaction(atom/target, params, mob/user, reach)
|
|
return
|
|
|
|
//move to define probably?
|
|
proc/isTarget(var/atom/A, var/mob/user = null)
|
|
if (istype(A, /obj/itemspecialeffect))
|
|
var/obj/itemspecialeffect/E = A
|
|
return (E.can_clash && world.time != E.create_time && E.clash_time > 0 && world.time <= E.create_time + E.clash_time)
|
|
.= ((istype(A, /obj/critter) || (ismob(A) && isliving(A))) && A != usr && A != user)
|
|
|
|
proc/showEffect(var/name = null, var/direction = NORTH, var/mob/user)
|
|
if(name == null || master == null) return
|
|
if(!user) user = usr
|
|
var/obj/itemspecialeffect/E = unpool(/obj/itemspecialeffect)
|
|
E.setup(get_turf(user))
|
|
E.dir = direction
|
|
E.icon_state = name
|
|
|
|
proc/usable(var/mob/user)
|
|
if (!user) user = usr
|
|
|
|
if(istype(user, /mob/living/carbon/human) && src.requiresStaminaToFire)
|
|
var/mob/living/carbon/human/H = user
|
|
if(H.stamina < staminaReqAmt) return 0
|
|
|
|
if(world.time < (last_use + cooldown))
|
|
return 0
|
|
|
|
if(user.a_intent == "help" || user.a_intent == "grab")
|
|
return 0
|
|
|
|
if (!istype(user.loc, /turf))
|
|
return 0
|
|
|
|
return 1
|
|
|
|
//Should be called before attacks begin. Make sure you call this when appropriate in your mouse procs etc.
|
|
//MBC : Removed Damage/Stamina modifications from preUse() and afterUse() and moved their to item.attack() to avoid race condition
|
|
proc/preUse(var/mob/person)
|
|
if(istype(person, /mob/living/carbon/human))
|
|
var/mob/living/carbon/human/H = person
|
|
|
|
if(STAMINA_NO_ATTACK_CAP && H.stamina > STAMINA_MIN_ATTACK)
|
|
var/cost = staminaCost
|
|
cost = min(cost,H.stamina - STAMINA_MIN_ATTACK)
|
|
H.remove_stamina(cost)
|
|
|
|
if(moveDelayDuration && moveDelay)
|
|
SPAWN_DBG(0)
|
|
person.movement_delay_modifier += moveDelay
|
|
person.apply_movement_delay_until = world.time + moveDelayDuration //handle move() started mid-delay
|
|
sleep(moveDelayDuration)
|
|
person.movement_delay_modifier = 0
|
|
person.apply_movement_delay_until = -1
|
|
last_use = world.time
|
|
|
|
//Should be called after everything is done and all attacks are finished. Make sure you call this when appropriate in your mouse procs etc.
|
|
proc/afterUse(var/mob/person)
|
|
if(restrainDuration)
|
|
person.restrain_time = world.timeofday + restrainDuration
|
|
|
|
rush
|
|
cooldown = 100
|
|
staminaCost = 25
|
|
image = "rush"
|
|
name = "Rush"
|
|
desc = "Hold to charge, release to rush."
|
|
var/maxRange = 17
|
|
damageMult = 2
|
|
|
|
var/datum/action/bar/private/icon/rush/action = null
|
|
|
|
onMouseDown(atom/target,location,control,params)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable()) return
|
|
var/list/parameters = params2list(params)
|
|
if(parameters["left"] && master && get_dist_pixel_squared(usr, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
action = new(src, usr, target)
|
|
action.params = params
|
|
actions.start(action, usr)
|
|
return
|
|
|
|
onMouseUp(atom/target,location,control,params)
|
|
var/list/parameters = params2list(params)
|
|
if(parameters["left"])
|
|
if(action)
|
|
if (target)
|
|
action.target = target
|
|
action.params = params
|
|
action.state = ACTIONSTATE_FINISH
|
|
return
|
|
|
|
proc/rush(atom/movable/user, atom/target, progress, params)
|
|
preUse(user)
|
|
action = null
|
|
src.cooldown = round(max(10, initial(src.cooldown) * progress))
|
|
|
|
var/atom/lastTurf = null
|
|
var/direction = get_dir_pixel(user, target, params)
|
|
var/list/attacked = list()
|
|
var/blurX = 0
|
|
var/blurY = 0
|
|
|
|
user.dir = direction
|
|
|
|
switch(direction)
|
|
if(NORTH)
|
|
blurY = 16
|
|
if(SOUTH)
|
|
blurY = -16
|
|
if(EAST)
|
|
blurX = 16
|
|
if(WEST)
|
|
blurX = -16
|
|
if(NORTHEAST)
|
|
blurX = 16
|
|
blurY = 16
|
|
if(SOUTHEAST)
|
|
blurY = -16
|
|
blurX = 16
|
|
if(SOUTHWEST)
|
|
blurY = -16
|
|
blurX = -16
|
|
if(NORTHWEST)
|
|
blurY = 16
|
|
blurX = -16
|
|
|
|
for(var/i=0, i < max(1,round(maxRange * progress)), i++)
|
|
if(lastTurf)
|
|
lastTurf = get_step(lastTurf, direction)
|
|
else
|
|
lastTurf = get_turf(user)
|
|
|
|
var/cancel = 0
|
|
for(var/atom/A in lastTurf)
|
|
if(A.density && !isTarget(A))
|
|
cancel = 1
|
|
break
|
|
if(cancel) //Doing it like this because breaking the outer loop with a label just fails.
|
|
break
|
|
|
|
if(lastTurf.density)
|
|
break
|
|
|
|
user.set_loc(lastTurf)
|
|
user.dir = direction
|
|
var/obj/itemspecialeffect/bluefade/E = unpool(/obj/itemspecialeffect/bluefade)
|
|
E.setup(user.loc)
|
|
E.filters = filter(type="motion_blur", x=blurX, y=blurY)
|
|
|
|
animate(E, alpha=255,time=0,loop=0)
|
|
animate(alpha=0,pixel_x=((blurX*(-1))*3),pixel_y=((blurY*(-1))*3), time=(15+(i*3)),loop=0)
|
|
|
|
var/hit = 0
|
|
for(var/atom/A in lastTurf)
|
|
if(A in attacked) continue
|
|
if(isTarget(A, user) && A != user)
|
|
A.attackby(master, user, params, 1)
|
|
attacked += A
|
|
hit = 1
|
|
|
|
if(hit)
|
|
if(prob(1))
|
|
var/obj/itemspecialeffect/zantetsuken/Z = unpool(/obj/itemspecialeffect/zantetsuken)
|
|
Z.setup(user.loc)
|
|
else
|
|
var/obj/itemspecialeffect/rushhit/R = unpool(/obj/itemspecialeffect/rushhit)
|
|
R.setup(user.loc)
|
|
|
|
sleep(0.2)
|
|
|
|
afterUse(user)
|
|
playsound(get_turf(master), 'sound/impact_sounds/Rush_Slash.ogg', 50, 0)
|
|
return
|
|
|
|
throwing
|
|
cooldown = 10
|
|
staminaCost = 5
|
|
moveDelay = 0
|
|
moveDelayDuration = 0
|
|
overrideCrit = -1
|
|
|
|
image = "throw"
|
|
name = "Throw"
|
|
desc = "Throw one of your weapons."
|
|
onMouseUp(atom/target,location,control,params)
|
|
if(!usable()) return
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
var/list/parameters = params2list(params)
|
|
if(parameters["left"] && master && get_dist_pixel_squared(usr, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
var/obj/item/copy = master.split_stack(1)
|
|
if(copy)
|
|
preUse(usr)
|
|
var/atom/step = get_step(usr, get_dir_pixel(usr, target, params))
|
|
copy.set_loc(step)
|
|
copy.throw_at(target, 20, 3, params)
|
|
afterUse(usr)
|
|
playsound(get_turf(master), 'sound/effects/swoosh.ogg', 50, 0)
|
|
return
|
|
|
|
simple
|
|
cooldown = 0
|
|
staminaCost = 0
|
|
moveDelay = 0//5
|
|
moveDelayDuration = 0//4
|
|
damageMult = 0.9
|
|
|
|
image = "simple"
|
|
name = "Attack"
|
|
desc = "Attack in direction. No crits."
|
|
|
|
onAdd()
|
|
if(master)
|
|
overrideStaminaDamage = master.stamina_damage * 0.8
|
|
return
|
|
|
|
pixelaction(atom/target, params, mob/user, reach)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable(user)) return
|
|
if(params["left"] && master && get_dist_pixel_squared(user, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
preUse(user)
|
|
var/direction = get_dir_pixel(user, target, params)
|
|
var/turf/turf = get_step(master, direction)
|
|
|
|
var/obj/itemspecialeffect/simple/S = unpool(/obj/itemspecialeffect/simple)
|
|
S.setup(turf)
|
|
|
|
var/hit = 0
|
|
for(var/atom/A in turf)
|
|
if(isTarget(A))
|
|
A.attackby(master, user, params, 1)
|
|
hit = 1
|
|
break
|
|
|
|
afterUse(user)
|
|
|
|
if (!hit)
|
|
playsound(get_turf(master), 'sound/effects/swoosh.ogg', 50, 0)
|
|
return
|
|
|
|
rangestab
|
|
cooldown = 0 //10
|
|
staminaCost = 5
|
|
moveDelay = 5
|
|
moveDelayDuration = 5
|
|
|
|
image = "stab"
|
|
name = "Stab"
|
|
desc = "Attack with a 2 tile range."
|
|
|
|
onAdd()
|
|
if(master)
|
|
//cooldown = master.click_delay
|
|
overrideStaminaDamage = master.stamina_damage * 0.8
|
|
return
|
|
|
|
pixelaction(atom/target, params, mob/user, reach)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable(user)) return
|
|
if(params["left"] && master && get_dist_pixel_squared(user, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
preUse(user)
|
|
var/direction = get_dir_pixel(user, target, params)
|
|
var/list/attacked = list()
|
|
|
|
var/turf/one = get_step(master, direction)
|
|
var/turf/two = get_step(one, direction)
|
|
|
|
showEffect("spear", direction)
|
|
|
|
var/hit = 0
|
|
for(var/turf/T in list(one, two))
|
|
for(var/atom/A in T)
|
|
if(A in attacked) continue
|
|
if(isTarget(A))
|
|
A.attackby(master, user, params, 1)
|
|
attacked += A
|
|
hit = 1
|
|
|
|
afterUse(user)
|
|
if (!hit)
|
|
playsound(get_turf(master), 'sound/effects/swoosh.ogg', 50, 0)
|
|
return
|
|
|
|
swipe
|
|
cooldown = 0 //30
|
|
staminaCost = 5
|
|
moveDelay = 5
|
|
moveDelayDuration = 5
|
|
|
|
damageMult = 0.8
|
|
|
|
image = "swipe"
|
|
name = "Swipe"
|
|
desc = "Attack with a wide swing."
|
|
var/swipe_color
|
|
|
|
onAdd()
|
|
if(master)
|
|
overrideStaminaDamage = master.stamina_damage * 0.6 //maybe too low? thinking about stuff like baseball bat or rolling pin tho
|
|
var/obj/item/toy/sword/saber = master
|
|
if (istype(saber))
|
|
swipe_color = get_hex_color_from_blade(saber.bladecolor)
|
|
return
|
|
|
|
//Sampled these hex colors from each c-saber sprite.
|
|
proc/get_hex_color_from_blade(var/C as text)
|
|
switch(C)
|
|
if("R")
|
|
return "#FF0000"
|
|
if("O")
|
|
return "#FF9A00"
|
|
if("Y")
|
|
return "#FFFF00"
|
|
if("G")
|
|
return "#00FF78"
|
|
if("C")
|
|
return "#00FFFF"
|
|
if("B")
|
|
return "#0081DF"
|
|
if("P")
|
|
return "#CC00FF"
|
|
if("Pi")
|
|
return "#FFCCFF"
|
|
if("W")
|
|
return "#EBE6EB"
|
|
return "RAND"
|
|
|
|
pixelaction(atom/target, params, mob/user, reach)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable(user)) return
|
|
if(params["left"] && master && get_dist_pixel_squared(user, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
preUse(user)
|
|
var/direction = get_dir_pixel(user, target, params)
|
|
if(direction == NORTHEAST || direction == NORTHWEST || direction == SOUTHEAST || direction == SOUTHWEST)
|
|
direction = (prob(50) ? turn(direction, 45) : turn(direction, -45))
|
|
|
|
var/list/attacked = list()
|
|
|
|
var/turf/one = get_step(master, direction)
|
|
var/turf/effect = get_step(one, direction)
|
|
var/turf/two = get_step(one, turn(direction, 90))
|
|
var/turf/three = get_step(one, turn(direction, -90))
|
|
|
|
var/obj/itemspecialeffect/swipe/swipe = unpool(/obj/itemspecialeffect/swipe)
|
|
//pick random colour from get_hex_color_from_blade if the bladecolor/swipe_color is null. Randomized color each swing cause this saber is multicolored.
|
|
if (swipe_color == "RAND")
|
|
swipe.color = pick("#FF0000","#FF9A00","#FFFF00","#00FF78","#00FFFF","#0081DF","#CC00FF","#FFCCFF","#EBE6EB")
|
|
else
|
|
swipe.color = swipe_color
|
|
swipe.setup(effect)
|
|
swipe.dir = direction
|
|
|
|
var/hit = 0
|
|
for(var/turf/T in list(one, two, three))
|
|
for(var/atom/movable/A in T)
|
|
if(A in attacked) continue
|
|
if(isTarget(A))
|
|
A.attackby(master, user, params, 1)
|
|
attacked += A
|
|
hit = 1
|
|
|
|
afterUse(user)
|
|
if (!hit)
|
|
playsound(get_turf(master), 'sound/effects/swoosh.ogg', 50, 0)
|
|
return
|
|
|
|
|
|
csaber //no stun and less damage than normal csaber hit ( see sword/attack() )
|
|
|
|
damageMult = 0.54
|
|
|
|
onAdd()
|
|
if(master)
|
|
//cooldown = master.click_delay
|
|
overrideStaminaDamage = master.stamina_damage * 0.9
|
|
var/obj/item/sword/saber = master
|
|
if (istype(saber))
|
|
swipe_color = get_hex_color_from_blade(saber.bladecolor)
|
|
return
|
|
|
|
slam
|
|
cooldown = 50
|
|
staminaCost = 30
|
|
moveDelay = 10
|
|
moveDelayDuration = 20
|
|
restrainDuration = 1
|
|
damageMult = 0.22
|
|
|
|
image = "slam"
|
|
name = "Slam"
|
|
desc = "Knock back and damage targets."
|
|
prefix = "Massive"
|
|
|
|
onAdd()
|
|
if(master)
|
|
staminaCost = master.stamina_cost * 2 //Inherits from the item.
|
|
overrideStaminaDamage = master.stamina_damage * 0.7
|
|
return
|
|
|
|
afterUse(var/mob/person)
|
|
..()
|
|
if (istype(master,/obj/item/mining_tool))
|
|
var/obj/item/mining_tool/M = master
|
|
if (M.status)
|
|
M.process_charges(3)
|
|
|
|
pixelaction(atom/target, params, mob/user, reach)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable(user)) return
|
|
|
|
if(params["left"] && master && get_dist_pixel_squared(user, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
preUse(user)
|
|
var/direction = get_dir_pixel(user, target, params)
|
|
if(direction == NORTHEAST || direction == NORTHWEST || direction == SOUTHEAST || direction == SOUTHWEST)
|
|
direction = (prob(50) ? turn(direction, 45) : turn(direction, -45))
|
|
|
|
var/list/attacked = list()
|
|
|
|
var/turf/one = get_step(master, direction)
|
|
|
|
var/turf/two = get_step(one, direction)
|
|
var/turf/twoB = get_step(two, direction)
|
|
|
|
var/turf/three = get_step(two, turn(direction, 90))
|
|
var/turf/four = get_step(two, turn(direction, -90))
|
|
|
|
var/turf/threeB = get_step(three, direction)
|
|
var/turf/fourB = get_step(four, direction)
|
|
|
|
var/obj/itemspecialeffect/cracks = unpool(/obj/itemspecialeffect/cracks)
|
|
cracks.setup(two)
|
|
cracks.dir = direction
|
|
animate(cracks, alpha=0, time=30)
|
|
|
|
for(var/mob/M in viewers())
|
|
shake_camera(M, 8, 3)
|
|
|
|
for(var/turf/T in list(one, two, three, four, twoB, threeB, fourB))
|
|
animate_shake(T)
|
|
for(var/atom/movable/A in T)
|
|
if(A in attacked) continue
|
|
if(isTarget(A))
|
|
A.attackby(master, user, params, 1)
|
|
attacked += A
|
|
A.throw_at(get_edge_target_turf(A,direction), 5, 3)
|
|
|
|
afterUse(user)
|
|
playsound(get_turf(master), 'sound/effects/exlow.ogg', 50, 0)
|
|
return
|
|
|
|
slam/no_item_attack //slam without item attackby
|
|
pixelaction(atom/target, params, mob/user, reach)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable(user)) return
|
|
|
|
if(params["left"] && get_dist_pixel_squared(user, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
preUse(user)
|
|
var/direction = get_dir_pixel(user, target, params)
|
|
if(direction == NORTHEAST || direction == NORTHWEST || direction == SOUTHEAST || direction == SOUTHWEST)
|
|
direction = (prob(50) ? turn(direction, 45) : turn(direction, -45))
|
|
|
|
var/list/attacked = list()
|
|
|
|
var/turf/one = get_step(user, direction)
|
|
|
|
var/turf/two = get_step(one, direction)
|
|
var/turf/twoB = get_step(two, direction)
|
|
|
|
var/turf/three = get_step(two, turn(direction, 90))
|
|
var/turf/four = get_step(two, turn(direction, -90))
|
|
|
|
var/turf/threeB = get_step(three, direction)
|
|
var/turf/fourB = get_step(four, direction)
|
|
|
|
var/obj/itemspecialeffect/cracks = unpool(/obj/itemspecialeffect/cracks)
|
|
cracks.setup(two)
|
|
cracks.dir = direction
|
|
animate(cracks, alpha=0, time=30)
|
|
|
|
for(var/mob/M in viewers())
|
|
shake_camera(M, 8, 3)
|
|
|
|
for(var/turf/T in list(one, two, three, four, twoB, threeB, fourB))
|
|
animate_shake(T)
|
|
for(var/atom/movable/A in T)
|
|
if(A in attacked) continue
|
|
if(isTarget(A))
|
|
if (isliving(A))
|
|
var/mob/living/L = A
|
|
L.TakeDamage("chest", 0, rand(1,5), 0, DAMAGE_BLUNT)
|
|
attacked += A
|
|
A.throw_at(get_edge_target_turf(A,direction), 5, 3)
|
|
|
|
afterUse(user)
|
|
playsound(get_turf(user), 'sound/effects/exlow.ogg', 50, 0)
|
|
return
|
|
|
|
|
|
whirlwind
|
|
cooldown = 20
|
|
staminaCost = 15
|
|
restrainDuration = 1
|
|
image = "whirlwind"
|
|
name = "Whirlwind"
|
|
desc = "Hit all enemies around you."
|
|
|
|
onMouseUp(atom/target,location,control,params)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable()) return
|
|
var/list/parameters = params2list(params)
|
|
if(parameters["left"] && master && get_dist_pixel_squared(usr, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
preUse(usr)
|
|
var/list/attacked = list()
|
|
|
|
for(var/turf/T in orange(2,get_turf(master)))
|
|
for(var/atom/A in T)
|
|
if(A in attacked) continue
|
|
if(isTarget(A))
|
|
A.attackby(master, usr, params, 1)
|
|
attacked += A
|
|
|
|
showEffect("whirlwind", NORTH)
|
|
afterUse(usr)
|
|
playsound(get_turf(master), 'sound/effects/swoosh_double.ogg', 100, 0)
|
|
return
|
|
|
|
//Disarm and Harm are odd ones out. They have no master item, they are attached to a limb. As such, some vars (like all of our item damage/crit modifiers) won't affect these. See the top of the limb.dm file if you want to adjust how they are enacted
|
|
//kind of messying things up, sorry!!
|
|
//Right now, item specials will NOT accept MouseUp and MouseDown events from limbs. Only pixelaction cause i'm lazsy
|
|
|
|
disarm
|
|
cooldown = 0
|
|
staminaCost = 0
|
|
moveDelay = 0
|
|
moveDelayDuration = 0
|
|
|
|
image = "conc"
|
|
name = "Shove"
|
|
desc = "Shove someone backwards."
|
|
|
|
var/datum/limb/L
|
|
|
|
preUse(var/mob/person)
|
|
..()
|
|
L = person.equipped_limb()
|
|
if (!L)
|
|
return
|
|
L.special_next = 1
|
|
|
|
afterUse(var/mob/person)
|
|
..()
|
|
if (L)
|
|
L.special_next = 0
|
|
|
|
pixelaction(atom/target, params, mob/user, reach)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable(user)) return
|
|
if(params["left"] && get_dist_pixel_squared(user, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
preUse(user)
|
|
var/direction = get_dir_pixel(user, target, params)
|
|
var/turf/turf = get_step(user, direction)
|
|
|
|
var/obj/itemspecialeffect/conc/C = unpool(/obj/itemspecialeffect/conc)
|
|
C.setup(turf)
|
|
|
|
var/hit = 0
|
|
for(var/atom/A in turf)
|
|
if(isTarget(A))
|
|
A.attack_hand(user,params)
|
|
hit = 1
|
|
break
|
|
|
|
afterUse(user)
|
|
|
|
if (!hit)
|
|
playsound(get_turf(user), 'sound/impact_sounds/Generic_Swing_1.ogg', 40, 0)
|
|
return
|
|
|
|
harm
|
|
cooldown = 0
|
|
staminaCost = 0//todo: adjust?
|
|
moveDelay = 0
|
|
moveDelayDuration = 0
|
|
|
|
image = "conc"
|
|
name = "Harm"
|
|
desc = "Throw a punch."
|
|
|
|
var/datum/limb/L
|
|
|
|
preUse(var/mob/person)
|
|
..()
|
|
L = person.equipped_limb()
|
|
if (!L)
|
|
return
|
|
L.special_next = 1
|
|
|
|
afterUse(var/mob/person)
|
|
..()
|
|
if (L)
|
|
L.special_next = 0
|
|
|
|
pixelaction(atom/target, params, mob/user, reach)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable(user)) return
|
|
if(params["left"] && get_dist_pixel_squared(user, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
preUse(user)
|
|
var/direction = get_dir_pixel(user, target, params)
|
|
var/turf/turf = get_step(user, direction)
|
|
|
|
var/obj/itemspecialeffect/conc/C = unpool(/obj/itemspecialeffect/conc)
|
|
C.setup(turf)
|
|
|
|
var/hit = 0
|
|
for(var/atom/A in turf)
|
|
if(isTarget(A))
|
|
A.attack_hand(user,params)
|
|
hit = 1
|
|
break
|
|
|
|
afterUse(user)
|
|
|
|
if (!hit)
|
|
playsound(get_turf(user), 'sound/impact_sounds/Generic_Swing_1.ogg', 40, 0)
|
|
return
|
|
|
|
swipe/limb //meant for use on limbs
|
|
var/datum/limb/L
|
|
|
|
preUse(var/mob/person)
|
|
..()
|
|
L = person.equipped_limb()
|
|
if (!L)
|
|
return
|
|
L.special_next = 1
|
|
|
|
afterUse(var/mob/person)
|
|
..()
|
|
if (L)
|
|
L.special_next = 0
|
|
|
|
pixelaction(atom/target, params, mob/user, reach)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable(user)) return
|
|
if(params["left"] && get_dist_pixel_squared(user, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
preUse(user)
|
|
var/direction = get_dir_pixel(user, target, params)
|
|
if(direction == NORTHEAST || direction == NORTHWEST || direction == SOUTHEAST || direction == SOUTHWEST)
|
|
direction = (prob(50) ? turn(direction, 45) : turn(direction, -45))
|
|
|
|
var/list/attacked = list()
|
|
|
|
var/turf/one = get_step(user, direction)
|
|
var/turf/effect = get_step(one, direction)
|
|
var/turf/two = get_step(one, turn(direction, 90))
|
|
var/turf/three = get_step(one, turn(direction, -90))
|
|
|
|
var/obj/itemspecialeffect/swipe/swipe = unpool(/obj/itemspecialeffect/swipe)
|
|
swipe.setup(effect)
|
|
swipe.dir = direction
|
|
|
|
var/hit = 0
|
|
for(var/turf/T in list(one, two, three))
|
|
for(var/atom/movable/A in T)
|
|
if(A in attacked) continue
|
|
if(isTarget(A))
|
|
A.attack_hand(user,params)
|
|
attacked += A
|
|
hit = 1
|
|
|
|
afterUse(user)
|
|
if (!hit)
|
|
playsound(get_turf(user), 'sound/effects/swoosh.ogg', 50, 0)
|
|
return
|
|
|
|
spark
|
|
cooldown = 0
|
|
moveDelay = 5
|
|
moveDelayDuration = 3
|
|
|
|
image = "sparks"
|
|
name = "Spark"
|
|
desc = "Throw a spark from the end of your baton."
|
|
|
|
var/secondhit_delay = 1
|
|
var/stamina_damage = 50
|
|
|
|
|
|
pixelaction(atom/target, params, mob/user, reach)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable(user)) return
|
|
if(master && istype(master, /obj/item/baton) && !master:can_stun())
|
|
playsound(get_turf(master), 'sound/weapons/Gunclick.ogg', 50, 0, 0.1, 2)
|
|
return
|
|
|
|
if(params["left"] && master && get_dist_pixel_squared(user, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
preUse(user)
|
|
var/direction = get_dir_pixel(user, target, params)
|
|
var/list/attacked = list()
|
|
|
|
var/turf/effect = get_step(master, direction)
|
|
|
|
var/obj/itemspecialeffect/spark/spark = unpool(/obj/itemspecialeffect/spark)
|
|
spark.setup(effect)
|
|
spark.dir = direction
|
|
|
|
var/hit = 0
|
|
for(var/atom/movable/A in effect)
|
|
if(A in attacked) continue
|
|
if(isTarget(A))
|
|
on_hit(A,2)
|
|
attacked += A
|
|
hit = 1
|
|
break
|
|
if (!hit)
|
|
SPAWN_DBG(secondhit_delay)
|
|
step(spark, direction, 2)
|
|
for(var/atom/movable/A in spark.loc)
|
|
if(A in attacked) continue
|
|
if(isTarget(A))
|
|
on_hit(A)
|
|
attacked += A
|
|
hit = 1
|
|
break
|
|
|
|
if(master && istype(master, /obj/item/baton))
|
|
master:process_charges(-1, user)
|
|
|
|
afterUse(user)
|
|
//if (!hit)
|
|
playsound(get_turf(master), 'sound/effects/sparks6.ogg', 70, 0)
|
|
return
|
|
|
|
|
|
proc/on_hit(var/mob/hit, var/mult = 1)
|
|
if (ishuman(hit))
|
|
var/mob/living/carbon/human/H = hit
|
|
H.do_disorient(src.stamina_damage * mult, weakened = 10)
|
|
|
|
hit.TakeDamage("chest", 0, rand(2 * mult,5 * mult), 0, DAMAGE_BLUNT)
|
|
hit.bodytemperature += 4 * mult
|
|
|
|
playsound(get_turf(hit), 'sound/effects/electric_shock.ogg', 60, 1, 0.1, 2.8)
|
|
|
|
double
|
|
cooldown = 0
|
|
staminaCost = 0
|
|
moveDelay = 5
|
|
moveDelayDuration = 5
|
|
damageMult = 0.33
|
|
|
|
image = "dagger"
|
|
name = "Slice"
|
|
desc = "Attack twice in rapid succession."
|
|
|
|
var/secondhitdelay = 2
|
|
|
|
onAdd()
|
|
if(master)
|
|
staminaCost = master.stamina_cost * 0.2 //Inherits from the item.
|
|
overrideStaminaDamage = master.stamina_damage * 0.33
|
|
return
|
|
|
|
pixelaction(atom/target, params, mob/user, reach)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable(user)) return
|
|
if(params["left"] && master && get_dist_pixel_squared(user, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
preUse(user)
|
|
var/direction = get_dir_pixel(user, target, params)
|
|
var/turf/turf = get_step(master, direction)
|
|
|
|
var/obj/itemspecialeffect/simple2/S = unpool(/obj/itemspecialeffect/simple2)
|
|
S.setup(turf)
|
|
|
|
var/hit = 0
|
|
for(var/atom/A in turf)
|
|
if(isTarget(A))
|
|
A.attackby(master, user, params, 1)
|
|
hit = 1
|
|
break
|
|
if (!hit)
|
|
playsound(get_turf(user), 'sound/impact_sounds/Generic_Swing_1.ogg', 40, 0, 0.1, 1.4)
|
|
|
|
SPAWN_DBG(secondhitdelay)
|
|
|
|
turf = get_step(master, direction)
|
|
var/obj/itemspecialeffect/simple2/SS = unpool(/obj/itemspecialeffect/simple2)
|
|
SS.setup(turf)
|
|
|
|
hit = 0
|
|
for(var/atom/A in turf)
|
|
if(isTarget(A))
|
|
A.attackby(master, user, params, 1)
|
|
hit = 1
|
|
break
|
|
if (!hit)
|
|
playsound(get_turf(user), 'sound/impact_sounds/Generic_Swing_1.ogg', 40, 0, 0.1, 1.4)
|
|
|
|
afterUse(user)
|
|
|
|
return
|
|
|
|
barrier
|
|
cooldown = 0
|
|
staminaCost = 0
|
|
moveDelay = 7
|
|
moveDelayDuration = 6
|
|
damageMult = 1
|
|
restrainDuration = 3
|
|
|
|
image = "barrier"
|
|
name = "Energy Barrier"
|
|
desc = "Deploy a temporary barrier that reflects projectiles. The barrier can be easily broken by any attack or a sustained push. "
|
|
|
|
onAdd()
|
|
if(master)
|
|
staminaCost = master.stamina_cost * 0.1 //Inherits from the item.
|
|
overrideStaminaDamage = master.stamina_damage * 0.8
|
|
return
|
|
|
|
pixelaction(atom/target, params, mob/user, reach)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable(user)) return
|
|
if(params["left"] && master && get_dist_pixel_squared(user, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
preUse(user)
|
|
var/direction = get_dir_pixel(user, target, params)
|
|
var/turf/turf = get_step(master, direction)
|
|
|
|
var/obj/itemspecialeffect/barrier/E = unpool(/obj/itemspecialeffect/barrier)
|
|
E.setup(turf)
|
|
E.master = user
|
|
E.dir = direction
|
|
if(master && istype(master, /obj/item/barrier))
|
|
var/obj/item/barrier/B = master
|
|
B.destroy_deployed_barrier(user)
|
|
B.E = E //set barrier
|
|
var/mob/living/L = user
|
|
|
|
//set move callback (when user moves, shield go down)
|
|
if (islist(L.move_laying))
|
|
L.move_laying += B
|
|
else
|
|
if (L.move_laying)
|
|
L.move_laying = list(L.move_laying, B)
|
|
else
|
|
L.move_laying = list(B)
|
|
|
|
var/hit = 0
|
|
for(var/atom/A in turf)
|
|
if(isTarget(A))
|
|
A.attackby(master, user, params, 1)
|
|
hit = 1
|
|
break
|
|
|
|
if (hit)
|
|
E.was_clashed(0)
|
|
else
|
|
playsound(get_turf(master), 'sound/items/miningtool_on.ogg', 30, 0.1, 0, 2)
|
|
|
|
afterUse(user)
|
|
return
|
|
|
|
|
|
flame
|
|
cooldown = 0
|
|
moveDelay = 5
|
|
moveDelayDuration = 2
|
|
|
|
damageMult = 0.8
|
|
|
|
|
|
image = "flame"
|
|
name = "Flame"
|
|
desc = "Pop out a flame 1 tile away from you in a direction."
|
|
|
|
var/time = 6 SECONDS
|
|
var/tiny_time = 1 SECOND
|
|
|
|
onAdd()
|
|
if(master)
|
|
staminaCost = master.stamina_cost * 0.4 //Inherits from the item.
|
|
overrideStaminaDamage = master.stamina_damage * 0.8
|
|
return
|
|
|
|
pixelaction(atom/target, params, mob/user, reach)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable(user)) return
|
|
if(params["left"] && master && get_dist_pixel_squared(user, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
preUse(user)
|
|
var/direction = get_dir_pixel(user, target, params)
|
|
|
|
//THIS IS BAD, FIX IT! (the random shit)
|
|
if(direction == NORTHEAST || direction == NORTHWEST || direction == SOUTHEAST || direction == SOUTHWEST)
|
|
direction = (prob(50) ? turn(direction, 45) : turn(direction, -45))
|
|
|
|
var/turf/turf = get_step(master, direction)
|
|
|
|
var/obj/itemspecialeffect/flame/S = unpool(/obj/itemspecialeffect/flame)
|
|
S.dir = direction
|
|
turf = get_step(turf,S.dir)
|
|
|
|
var/flame_succ = 0
|
|
if (master)
|
|
if(istype(master,/obj/item/device/light/zippo))
|
|
var/obj/item/device/light/zippo/Z = master
|
|
if (Z.fuel > 0)
|
|
Z.fuel--
|
|
flame_succ = 1
|
|
else
|
|
flame_succ = 0
|
|
if (istype(master,/obj/item/weldingtool))
|
|
var/obj/item/weldingtool/WT = master
|
|
if (WT.get_fuel())
|
|
WT.use_fuel(1)
|
|
flame_succ = 1
|
|
else
|
|
flame_succ = 0
|
|
|
|
if (flame_succ)
|
|
S.setup(turf)
|
|
flick("flame",S)
|
|
else
|
|
S.setup(turf)
|
|
flick("spark",S)
|
|
|
|
|
|
if (flame_succ)
|
|
turf.hotspot_expose(T0C + 400, 400)
|
|
for(var/mob/A in turf)
|
|
if(isTarget(A))
|
|
if (iscritter(A))
|
|
var/obj/critter/crit = A
|
|
crit.blob_act(8) //REMOVE WHEN WE ADD BURNING OBJCRITTERS
|
|
|
|
if (A.getStatusDuration("burning"))
|
|
A.changeStatus("burning", tiny_time)
|
|
else
|
|
A.changeStatus("burning", flame_succ ? time : tiny_time)
|
|
break
|
|
|
|
playsound(get_turf(master), 'sound/effects/flame.ogg', 50, 0)
|
|
else
|
|
turf.hotspot_expose(T0C + 50, 50)
|
|
playsound(get_turf(master), 'sound/effects/spark_lighter.ogg', 50, 0)
|
|
|
|
afterUse(user)
|
|
return
|
|
///////////////////////////////////
|
|
spark/ntso
|
|
cooldown = 0
|
|
moveDelay = 5
|
|
moveDelayDuration = 2
|
|
|
|
image = "baton-spark-ntso"
|
|
name = "Baton Hit"
|
|
desc = "Attack in direction with baton. Stun safety features overridden for more damage."
|
|
|
|
secondhit_delay = 1
|
|
stamina_damage = 50
|
|
|
|
//default to regular hit if we can't stun.
|
|
proc/default_to_simple()
|
|
var/datum/item_special/simple/S = new/datum/item_special/simple(src)
|
|
S.pixelaction()
|
|
|
|
|
|
pixelaction(atom/target, params, mob/user, reach)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable(user)) return
|
|
|
|
if(params["left"] && master && get_dist_pixel_squared(user, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
preUse(user)
|
|
|
|
var/direction = get_dir_pixel(user, target, params)
|
|
|
|
var/turf/effect = get_step(master, direction)
|
|
|
|
var/obj/itemspecialeffect/E = null
|
|
|
|
//sorry about this, it's so I don't unpool a simple effect twice by mistake
|
|
if(istype(master, /obj/item/baton))
|
|
if (!master:can_stun())
|
|
E = unpool(/obj/itemspecialeffect/simple)
|
|
else
|
|
E = unpool(/obj/itemspecialeffect/spark/ntso)
|
|
master:process_charges(-1)
|
|
// master:process_charges(-1, user)
|
|
else
|
|
E = unpool(/obj/itemspecialeffect/simple)
|
|
|
|
|
|
E.setup(effect)
|
|
E.dir = direction
|
|
|
|
var/hit = 0
|
|
for(var/atom/movable/A in effect)
|
|
if(isTarget(A))
|
|
on_hit(A)
|
|
//fake harmbaton it
|
|
A.attackby(master, user, params, 1)
|
|
hit = 1
|
|
playsound(get_turf(master), 'sound/effects/sparks6.ogg', 70, 0)
|
|
break
|
|
|
|
afterUse(user)
|
|
if (!hit)
|
|
if (E.type == /obj/itemspecialeffect/simple)
|
|
playsound(get_turf(master), 'sound/effects/swoosh.ogg', 50, 0)
|
|
else
|
|
playsound(get_turf(master), 'sound/effects/sparks1.ogg', 70, 0)
|
|
|
|
return
|
|
|
|
usable(var/mob/user)
|
|
if (!..())
|
|
return 0
|
|
if(istype(master, /obj/item/baton/ntso))
|
|
if (master:state == 1)
|
|
return 0
|
|
return 1
|
|
|
|
on_hit(var/mob/hit, var/mult = 1)
|
|
//maybe add this in, chance to weaken. I dunno a good amount offhand so leaving out for now - kyle
|
|
// if (ishuman(hit))
|
|
// var/mob/living/carbon/human/H = hit
|
|
// H.do_disorient(src.stamina_damage * mult, weakened = 10)
|
|
if(istype(master, /obj/item))
|
|
hit.TakeDamage("chest", 0/*master.force*/, rand(2 * mult,5 * mult), 0, DAMAGE_BLUNT)
|
|
hit.bodytemperature += 4 * mult
|
|
|
|
playsound(get_turf(hit), 'sound/effects/electric_shock.ogg', 60, 1, 0.1, 2.8)
|
|
|
|
katana_dash
|
|
cooldown = 9
|
|
moveDelay = 0
|
|
moveDelayDuration = 0
|
|
staminaCost = 30 //Stamina cost of attack
|
|
requiresStaminaToFire = 1
|
|
staminaReqAmt = 80
|
|
|
|
image = "katana"
|
|
name = "Katana Dash"
|
|
desc = "Instantly dash to a location like you saw in all those Japanese cartoons."
|
|
|
|
var/secondhit_delay = 1
|
|
var/stamina_damage = 80
|
|
var/obj/item/katana/K
|
|
var/reversed = 0
|
|
|
|
onAdd()
|
|
if(istype(master, /obj/item/katana))
|
|
K = master
|
|
return
|
|
|
|
pixelaction(atom/target, params, mob/user, reach)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable(user)) return
|
|
|
|
if(params["left"] && (master && K) && get_dist_pixel_squared(user, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
preUse(user)
|
|
var/direction = get_dir_pixel(user, target, params)
|
|
if (reversed)
|
|
direction = turn(direction, 180)
|
|
var/list/attacked = list()
|
|
|
|
var/turf/T1 = get_turf(user)
|
|
var/turf/T2 = null
|
|
var/turf/T3 = null
|
|
var/turf/T4 = null
|
|
|
|
//This steps the user to his destination and gets the turfs needed for drawing the effects and where the attack hits
|
|
var/stopped = 0
|
|
if (step(user, direction))
|
|
T2 = get_turf(user)
|
|
else
|
|
stopped = 1
|
|
|
|
if (!stopped && step(user, direction))
|
|
T3 = get_turf(user)
|
|
else
|
|
stopped = 2
|
|
|
|
if (!stopped && step(user, direction))
|
|
T4 = get_turf(user)
|
|
else
|
|
stopped = 3
|
|
|
|
//Draws the effects // I did this backwards maybe, but won't fix it -kyle
|
|
K.start.loc = T1
|
|
K.start.dir = direction
|
|
flick(K.start.icon_state, K.start)
|
|
sleep(1)
|
|
if (T4)
|
|
K.mid1.loc = T2
|
|
K.mid1.dir = direction
|
|
flick(K.mid1.icon_state, K.mid1)
|
|
sleep(1)
|
|
K.mid2.loc = T3
|
|
K.mid2.dir = direction
|
|
flick(K.mid2.icon_state, K.mid2)
|
|
sleep(1)
|
|
K.end.loc = T4
|
|
K.end.dir = direction
|
|
flick(K.end.icon_state, K.end)
|
|
else if (T3)
|
|
K.mid1.loc = T2
|
|
K.mid1.dir = direction
|
|
flick(K.mid1.icon_state, K.mid1)
|
|
sleep(1)
|
|
K.end.loc = T3
|
|
K.end.dir = direction
|
|
flick(K.end.icon_state, K.end)
|
|
else if (T2)
|
|
K.end.loc = T2
|
|
K.end.dir = direction
|
|
flick(K.end.icon_state, K.end)
|
|
|
|
//Reset the effects after they're drawn and put back into master for re-use later
|
|
SPAWN_DBG(8 DECI SECONDS)
|
|
K.start.loc = master
|
|
K.mid1.loc = master
|
|
K.mid2.loc = master
|
|
K.end.loc = master
|
|
// var/hit = 0
|
|
for(var/atom/movable/A in get_step(user, direction))
|
|
if(A in attacked) continue
|
|
if(isTarget(A))
|
|
on_hit(A)
|
|
attacked += A
|
|
A.attackby(master, user, params, 1)
|
|
// hit = 1
|
|
break
|
|
afterUse(user)
|
|
//if (!hit)
|
|
playsound(get_turf(master), 'sound/effects/sparks6.ogg', 70, 0)
|
|
return
|
|
|
|
proc/on_hit(var/mob/hit)
|
|
return
|
|
|
|
katana_dash/reverse
|
|
staminaCost = 10
|
|
reversed = 1
|
|
|
|
on_hit(var/mob/hit)
|
|
if (ishuman(hit))
|
|
var/mob/living/carbon/human/H = hit
|
|
H.do_disorient(src.stamina_damage, stunned = 10)
|
|
|
|
|
|
|
|
nunchucks
|
|
cooldown = 30
|
|
staminaCost = 40
|
|
moveDelay = 5
|
|
moveDelayDuration = 5
|
|
|
|
damageMult = 0.8
|
|
|
|
image = "nunchucks"
|
|
name = "double hit"
|
|
desc = "Attack with two quick hits."
|
|
|
|
onAdd()
|
|
if(master)
|
|
overrideStaminaDamage = master.stamina_damage * 0.6 //maybe too low? thinking about stuff like baseball bat or rolling pin tho
|
|
return
|
|
|
|
pixelaction(atom/target, params, mob/user, reach)
|
|
if(!isturf(target.loc) && !isturf(target)) return
|
|
if(!usable(user)) return
|
|
if(params["left"] && master && get_dist_pixel_squared(user, target, params) > ITEMSPECIAL_PIXELDIST_SQUARED)
|
|
preUse(user)
|
|
var/direction = get_dir_pixel(user, target, params)
|
|
if(direction == NORTHEAST || direction == NORTHWEST || direction == SOUTHEAST || direction == SOUTHWEST)
|
|
direction = (prob(50) ? turn(direction, 45) : turn(direction, -45))
|
|
|
|
var/list/attacked = list()
|
|
|
|
var/turf/one = get_step(master, direction)
|
|
var/turf/effect = get_step(one, direction)
|
|
var/turf/two = get_step(one, turn(direction, 90))
|
|
var/turf/three = get_step(one, turn(direction, -90))
|
|
|
|
var/obj/itemspecialeffect/nunchucks/nunchuck = unpool(/obj/itemspecialeffect/nunchucks)
|
|
nunchuck.setup(effect)
|
|
nunchuck.dir = direction
|
|
|
|
var/hit = 0
|
|
for(var/turf/T in list(two, three))
|
|
for(var/atom/movable/A in T)
|
|
if(A in attacked) continue
|
|
if(isTarget(A))
|
|
A.attackby(master, user, params, 1)
|
|
attacked += A
|
|
hit = 1
|
|
|
|
for(var/atom/movable/A in one)
|
|
if(A in attacked) continue
|
|
if(isTarget(A))
|
|
A.attackby(master, user, params, 1)
|
|
SPAWN_DBG(5 DECI SECONDS)
|
|
A.attackby(master, user, params, 1)
|
|
attacked += A
|
|
hit = 1
|
|
|
|
afterUse(user)
|
|
if (!hit)
|
|
playsound(get_turf(master), 'sound/effects/swoosh.ogg', 50, 0)
|
|
return
|
|
|
|
|
|
/obj/itemspecialeffect
|
|
name = ""
|
|
desc = ""
|
|
icon = 'icons/effects/160x160.dmi'
|
|
icon_state = ""
|
|
anchored = 1
|
|
layer = EFFECTS_LAYER_1
|
|
pixel_x = -64
|
|
pixel_y = -64
|
|
var/can_clash = 0
|
|
var/del_self = 1
|
|
var/del_time = 5 SECONDS
|
|
|
|
var/create_time = 0
|
|
var/clash_time = 6
|
|
|
|
var/do_flick = 1
|
|
New()
|
|
..()
|
|
|
|
|
|
proc/setup(atom/location)
|
|
src.set_loc(location)
|
|
//src.loc = location
|
|
if (do_flick)
|
|
flick(icon_state,src)
|
|
create_time = world.time //mbc : kind of janky lightweight way of making us not clash with ourselves. compare spawn time.
|
|
if (del_self)
|
|
SPAWN_DBG(del_time)
|
|
pool(src)
|
|
|
|
unpooled()
|
|
..()
|
|
|
|
pooled()
|
|
..()
|
|
|
|
attackby()
|
|
was_clashed()
|
|
|
|
attack_hand()
|
|
was_clashed()
|
|
|
|
proc/was_clashed(var/playsound = 1)
|
|
if (playsound)
|
|
playsound(src.loc, 'sound/impact_sounds/Stone_Cut_1.ogg', 50, 0.1, 0, 2)
|
|
var/obj/itemspecialeffect/clash/C = unpool(/obj/itemspecialeffect/clash)
|
|
C.setup(src.loc)
|
|
|
|
|
|
zantetsuken
|
|
icon = 'icons/effects/64x64.dmi'
|
|
icon_state = "zantetsuken"
|
|
pixel_x = -16
|
|
pixel_y = -16
|
|
blend_mode = BLEND_ADD
|
|
layer = EFFECTS_LAYER_1 + 1
|
|
|
|
setup(atom/location)
|
|
loc = location
|
|
var/matrix/M = matrix()
|
|
M.Scale(0.01)
|
|
animate(src, transform=M, time=0)
|
|
animate(transform=matrix(), time=2)
|
|
animate(time=10)
|
|
M = matrix()
|
|
M.Scale(2)
|
|
animate(alpha=0,transform=M, time=10)
|
|
..()
|
|
|
|
rushhit
|
|
icon = 'icons/effects/64x64.dmi'
|
|
icon_state = "rushhit"
|
|
pixel_x = -16
|
|
pixel_y = -16
|
|
blend_mode = BLEND_ADD
|
|
layer = EFFECTS_LAYER_1 + 1
|
|
|
|
cracks
|
|
icon = 'icons/effects/96x96.dmi'
|
|
icon_state = "cracks"
|
|
pixel_x = -32
|
|
pixel_y = -32
|
|
layer = OBJ_LAYER
|
|
|
|
swipe
|
|
icon = 'icons/effects/meleeeffects.dmi'
|
|
icon_state = "sabre"
|
|
pixel_x = -32
|
|
pixel_y = -32
|
|
can_clash = 1
|
|
|
|
bluefade
|
|
icon = 'icons/effects/effects.dmi'
|
|
icon_state = "bluefade2"
|
|
pixel_x = 0
|
|
pixel_y = 0
|
|
blend_mode = BLEND_ADD
|
|
|
|
simple
|
|
icon = 'icons/effects/effects.dmi'
|
|
icon_state = "simple"
|
|
pixel_x = 0
|
|
pixel_y = 0
|
|
can_clash = 1
|
|
|
|
conc
|
|
icon = 'icons/effects/effects.dmi'
|
|
icon_state = "conc_fast"
|
|
pixel_x = 0
|
|
pixel_y = 0
|
|
can_clash = 1
|
|
|
|
spark
|
|
icon = 'icons/effects/effects.dmi'
|
|
icon_state = "sparks_attack"
|
|
pixel_x = 0
|
|
pixel_y = 0
|
|
|
|
ntso
|
|
icon = 'icons/effects/effects.dmi'
|
|
icon_state = "baton-spark-ntso"
|
|
pixel_x = 0
|
|
pixel_y = 0
|
|
can_clash = 1
|
|
|
|
simple2
|
|
icon = 'icons/effects/effects.dmi'
|
|
icon_state = "hammer"
|
|
pixel_x = 0
|
|
pixel_y = 0
|
|
can_clash = 0
|
|
|
|
clash
|
|
icon = 'icons/effects/effects.dmi'
|
|
icon_state = "clash"
|
|
pixel_x = 0
|
|
pixel_y = 0
|
|
|
|
pooled()
|
|
..()
|
|
transform = null
|
|
|
|
barrier
|
|
name = "energy barrier"
|
|
icon = 'icons/effects/effects.dmi'
|
|
icon_state = "barrier"
|
|
pixel_x = 0
|
|
pixel_y = 0
|
|
can_clash = 1
|
|
density = 1
|
|
del_self = 0
|
|
clash_time = -1
|
|
event_handler_flags = USE_CANPASS
|
|
|
|
//mouse_opacity = 1
|
|
var/bump_count = 0
|
|
var/mob/master = 0
|
|
|
|
setup(atom/location)
|
|
src.density = 1
|
|
..()
|
|
|
|
disposing()
|
|
density = 0
|
|
..()
|
|
|
|
was_clashed(var/playsound = 1)
|
|
..(0)
|
|
if (playsound)
|
|
playsound(src.loc, 'sound/impact_sounds/Crystal_Shatter_1.ogg', 50, 0.1, 0, 0.5)
|
|
pool(src)
|
|
|
|
proc/deactivate()
|
|
if (src.qdeled || src.pooled)
|
|
return
|
|
playsound(src.loc, 'sound/items/miningtool_off.ogg', 30, 0.1, 0, 2)
|
|
pool(src)
|
|
|
|
Bumped()
|
|
bump_count++
|
|
if(bump_count >= 4)
|
|
was_clashed()
|
|
|
|
bullet_act(var/obj/projectile/P)
|
|
if (!P.goes_through_mobs)
|
|
var/obj/projectile/Q = shoot_reflected(P, src)
|
|
P.die()
|
|
|
|
src.visible_message("<span style=\"color:red\">[src] reflected [Q.name]!</span>")
|
|
playsound(src.loc, 'sound/impact_sounds/Energy_Hit_1.ogg', 40, 0.1, 0, 2.6)
|
|
|
|
//was_clashed()
|
|
return
|
|
|
|
poof
|
|
icon = 'icons/effects/64x64.dmi'
|
|
icon_state = "poof"
|
|
pixel_x = -16
|
|
pixel_y = -8
|
|
can_clash = 0
|
|
mouse_opacity = 0
|
|
|
|
setup(atom/location, forced = 0)
|
|
loc = location
|
|
if (del_self)
|
|
SPAWN_DBG(5 SECONDS)
|
|
pool(src)
|
|
|
|
was_clashed(var/playsound = 1)
|
|
.=0
|
|
|
|
screech
|
|
icon = 'icons/effects/64x64.dmi'
|
|
icon_state = "screamstack"
|
|
pixel_x = -16
|
|
pixel_y = -8
|
|
can_clash = 0
|
|
mouse_opacity = 0
|
|
|
|
glare
|
|
icon = 'icons/effects/64x64.dmi'
|
|
icon_state = "glare"
|
|
pixel_x = -16
|
|
pixel_y = -8
|
|
can_clash = 0
|
|
|
|
derev
|
|
icon = 'icons/effects/64x64.dmi'
|
|
icon_state = "derev"
|
|
pixel_x = -16
|
|
pixel_y = -8
|
|
can_clash = 0
|
|
|
|
flame
|
|
icon = 'icons/effects/effects.dmi'
|
|
icon_state = "flame"
|
|
pixel_x = 0
|
|
pixel_y = 0
|
|
can_clash = 0
|
|
do_flick = 0
|
|
|
|
katana_dash
|
|
icon = 'icons/effects/effects.dmi'
|
|
pixel_x = 0
|
|
pixel_y = 0
|
|
do_flick = 0
|
|
can_clash = 0
|
|
icon_state = "ka-start"
|
|
del_time = 2 SECONDS
|
|
|
|
start
|
|
icon_state = "ka-start"
|
|
mid
|
|
icon_state = "ka-mid"
|
|
end
|
|
icon_state = "ka-end"
|
|
|
|
nunchucks
|
|
icon = 'icons/effects/meleeeffects.dmi'
|
|
icon_state = "nunchucks"
|
|
pixel_x = -32
|
|
pixel_y = -32
|
|
can_clash = 1
|
|
|
|
/obj/itemspecialeffect/impact
|
|
icon = 'icons/effects/impacts.dmi'
|
|
del_time = 2 SECONDS
|
|
pixel_x = 0
|
|
pixel_y = 0
|
|
|
|
|
|
unpooled()
|
|
pixel_x = rand(-3,3)
|
|
pixel_y = rand(-15,6)
|
|
..()
|
|
|
|
/obj/itemspecialeffect/impact/blood
|
|
icon_state = "blood_impact1"
|
|
|
|
unpooled()
|
|
..()
|
|
if (prob(50))
|
|
icon_state = "blood_impact2"
|
|
|
|
/obj/itemspecialeffect/impact/energy
|
|
icon_state = "energy_impact"
|
|
|
|
/obj/itemspecialeffect/impact/taser
|
|
icon_state = "taser_impact"
|
|
|
|
/obj/itemspecialeffect/impact/silicon
|
|
icon_state = "silicon_impact1"
|
|
|
|
unpooled()
|
|
..()
|
|
if (prob(66))
|
|
icon_state = "silicon_impact2"
|
|
|
|
/////////REFERENCES
|
|
|
|
/datum/action/bar/private/icon/rush
|
|
id = "rush"
|
|
interrupt_flags = INTERRUPT_MOVE | INTERRUPT_STUNNED | INTERRUPT_ACTION
|
|
icon = 'icons/effects/effects.dmi'
|
|
icon_state = "conc"
|
|
var/datum/item_special/rush/special
|
|
var/mob/user
|
|
var/atom/target
|
|
var/progress = 0.01
|
|
var/params = null
|
|
duration = -1
|
|
|
|
New(var/datum/item_special/rush/D, var/mob/U, var/atom/T)
|
|
if(!istype(D, /datum/item_special/rush))
|
|
interrupt(INTERRUPT_ALWAYS)
|
|
if(!D || !U || !T)
|
|
interrupt(INTERRUPT_ALWAYS)
|
|
else
|
|
special = D
|
|
user = U
|
|
target = T
|
|
|
|
onStart()
|
|
..()
|
|
|
|
onInterrupt(var/flag)
|
|
..()
|
|
|
|
onEnd()
|
|
..()
|
|
if(target == null || user == null)
|
|
interrupt(INTERRUPT_ALWAYS)
|
|
return
|
|
|
|
if(special)
|
|
if(special.master == user.equipped() && istype(special, /datum/item_special/rush))
|
|
special.rush(user, target, progress, params)
|
|
return
|
|
|
|
onUpdate()
|
|
if(target == null || user == null || !istype(special, /datum/item_special/rush))
|
|
interrupt(INTERRUPT_ALWAYS)
|
|
return
|
|
|
|
if(special)
|
|
if(special.master != user.equipped())
|
|
interrupt(INTERRUPT_ALWAYS)
|
|
return
|
|
|
|
progress = min(progress + 0.2, 1)
|
|
|
|
bar.color = "#0000FF"
|
|
bar.transform = matrix(progress, 1, MATRIX_SCALE)
|
|
bar.pixel_x = -nround( ((30 - (30 * progress)) / 2) )
|
|
|
|
if(progress == 1)
|
|
state = ACTIONSTATE_FINISH
|
|
return |