Merge pull request #2864 from Fox-McCloud/medigun

Ports TG Beam Code and Medigun
This commit is contained in:
TheDZD
2015-12-17 21:19:13 -05:00
6 changed files with 276 additions and 88 deletions
+136
View File
@@ -0,0 +1,136 @@
//Beam Datum and effect
/datum/beam
var/atom/origin = null
var/atom/target = null
var/list/elements = list()
var/icon/base_icon = null
var/icon
var/icon_state = "" //icon state of the main segments of the beam
var/max_distance = 0
var/endtime = 0
var/sleep_time = 3
var/finished = 0
var/target_oldloc = null
var/origin_oldloc = null
var/static_beam = 0
var/beam_type = /obj/effect/ebeam //must be subtype
/datum/beam/New(beam_origin,beam_target,beam_icon='icons/effects/beam.dmi',beam_icon_state="b_beam",time=50,maxdistance=10,btype = /obj/effect/ebeam)
endtime = world.time+time
origin = beam_origin
origin_oldloc = origin.loc
if(isarea(origin_oldloc))
origin_oldloc = origin
target = beam_target
target_oldloc = target.loc
if(isarea(target_oldloc))
target_oldloc = target
if(origin_oldloc == origin && target_oldloc == target)
static_beam = 1
max_distance = maxdistance
base_icon = new(beam_icon,beam_icon_state)
icon = beam_icon
icon_state = beam_icon_state
beam_type = btype
/datum/beam/proc/Start()
Draw()
while(!finished && origin && target && world.time < endtime && get_dist(origin,target)<max_distance && origin.z == target.z)
if(!static_beam && (origin.loc != origin_oldloc || target.loc != target_oldloc))
origin_oldloc = origin.loc //so we don't keep checking against their initial positions, leading to endless Reset()+Draw() calls
target_oldloc = target.loc
Reset()
Draw()
sleep(sleep_time)
qdel(src)
/datum/beam/proc/End()
finished = 1
/datum/beam/proc/Reset()
for(var/obj/effect/ebeam/B in elements)
qdel(B)
/datum/beam/Destroy()
Reset()
target = null
origin = null
return ..()
/datum/beam/proc/Draw()
var/Angle = round(Get_Angle(origin,target))
var/matrix/rot_matrix = matrix()
rot_matrix.Turn(Angle)
//Translation vector for origin and target
var/DX = (32*target.x+target.pixel_x)-(32*origin.x+origin.pixel_x)
var/DY = (32*target.y+target.pixel_y)-(32*origin.y+origin.pixel_y)
var/N = 0
var/length = round(sqrt((DX)**2+(DY)**2)) //hypotenuse of the triangle formed by target and origin's displacement
for(N in 0 to length-1 step 32)//-1 as we want < not <=, but we want the speed of X in Y to Z and step X
var/obj/effect/ebeam/X = new beam_type(origin_oldloc)
X.owner = src
elements |= X
//Assign icon, for main segments it's base_icon, for the end, it's icon+icon_state
//cropped by a transparent box of length-N pixel size
if(N+32>length)
var/icon/II = new(icon, icon_state)
II.DrawBox(null,1,(length-N),32,32)
X.icon = II
else
X.icon = base_icon
X.transform = rot_matrix
//Calculate pixel offsets (If necessary)
var/Pixel_x
var/Pixel_y
if(DX == 0)
Pixel_x = 0
else
Pixel_x = round(sin(Angle)+32*sin(Angle)*(N+16)/32)
if(DY == 0)
Pixel_y = 0
else
Pixel_y = round(cos(Angle)+32*cos(Angle)*(N+16)/32)
//Position the effect so the beam is one continous line
var/a
if(abs(Pixel_x)>32)
a = Pixel_x > 0 ? round(Pixel_x/32) : Ceiling(Pixel_x/32)
X.x += a
Pixel_x %= 32
if(abs(Pixel_y)>32)
a = Pixel_y > 0 ? round(Pixel_y/32) : Ceiling(Pixel_y/32)
X.y += a
Pixel_y %= 32
X.pixel_x = Pixel_x
X.pixel_y = Pixel_y
/obj/effect/ebeam
mouse_opacity = 0
anchored = 1
var/datum/beam/owner
/obj/effect/ebeam/Destroy()
owner = null
return ..()
/atom/proc/Beam(atom/BeamTarget,icon_state="b_beam",icon='icons/effects/beam.dmi',time=50, maxdistance=10,beam_type=/obj/effect/ebeam)
var/datum/beam/newbeam = new(src,BeamTarget,icon,icon_state,time,maxdistance,beam_type)
spawn(0)
newbeam.Start()
return newbeam
+9
View File
@@ -827,6 +827,15 @@ var/list/uplink_items = list()
gamemodes = list("nuclear emergency")
surplus = 20
/datum/uplink_item/device_tools/medgun
name = "Medbeam Gun"
desc = "Medical Beam Gun, useful in prolonged firefights."
item = /obj/item/weapon/gun/medbeam
reference = "MBG"
cost = 15
gamemodes = list("nuclear emergency")
// IMPLANTS
/datum/uplink_item/implants
-88
View File
@@ -131,94 +131,6 @@
return found
/*
Beam code by Gunbuddy
Beam() proc will only allow one beam to come from a source at a time. Attempting to call it more than
once at a time per source will cause graphical errors.
Also, the icon used for the beam will have to be vertical and 32x32.
The math involved assumes that the icon is vertical to begin with so unless you want to adjust the math,
its easier to just keep the beam vertical.
*/
/atom/proc/Beam(atom/BeamTarget,icon_state="b_beam",icon='icons/effects/beam.dmi',time=50, maxdistance=10)
//BeamTarget represents the target for the beam, basically just means the other end.
//Time is the duration to draw the beam
//Icon is obviously which icon to use for the beam, default is beam.dmi
//Icon_state is what icon state is used. Default is b_beam which is a blue beam.
//Maxdistance is the longest range the beam will persist before it gives up.
var/EndTime=world.time+time
var/broken = 0
var/obj/item/projectile/beam/lightning/light = new
while(BeamTarget&&world.time<EndTime&&get_dist(src,BeamTarget)<maxdistance&&z==BeamTarget.z)
//If the BeamTarget gets deleted, the time expires, or the BeamTarget gets out
//of range or to another z-level, then the beam will stop. Otherwise it will
//continue to draw.
//dir=get_dir(src,BeamTarget) //Causes the source of the beam to rotate to continuosly face the BeamTarget.
for(var/obj/effect/overlay/beam/O in orange(10,src)) //This section erases the previously drawn beam because I found it was easier to
if(O.BeamSource==src) //just draw another instance of the beam instead of trying to manipulate all the
qdel(O) //pieces to a new orientation.
var/Angle=round(Get_Angle(src,BeamTarget))
var/icon/I=new(icon,icon_state)
I.Turn(Angle)
var/DX=(32*BeamTarget.x+BeamTarget.pixel_x)-(32*x+pixel_x)
var/DY=(32*BeamTarget.y+BeamTarget.pixel_y)-(32*y+pixel_y)
var/N=0
var/length=round(sqrt((DX)**2+(DY)**2))
for(N,N<length,N+=32)
var/obj/effect/overlay/beam/X=new(loc)
X.BeamSource=src
if(N+32>length)
var/icon/II=new(icon,icon_state)
II.DrawBox(null,1,(length-N),32,32)
II.Turn(Angle)
X.icon=II
else X.icon=I
var/Pixel_x=round(sin(Angle)+32*sin(Angle)*(N+16)/32)
var/Pixel_y=round(cos(Angle)+32*cos(Angle)*(N+16)/32)
if(DX==0) Pixel_x=0
if(DY==0) Pixel_y=0
if(Pixel_x>32)
for(var/a=0, a<=Pixel_x,a+=32)
X.x++
Pixel_x-=32
if(Pixel_x<-32)
for(var/a=0, a>=Pixel_x,a-=32)
X.x--
Pixel_x+=32
if(Pixel_y>32)
for(var/a=0, a<=Pixel_y,a+=32)
X.y++
Pixel_y-=32
if(Pixel_y<-32)
for(var/a=0, a>=Pixel_y,a-=32)
X.y--
Pixel_y+=32
X.pixel_x=Pixel_x
X.pixel_y=Pixel_y
var/turf/TT = get_turf(X.loc)
if(TT.density)
qdel(X)
break
for(var/obj/O in TT)
if(!O.CanPass(light))
broken = 1
break
else if(O.density)
broken = 1
break
if(broken)
qdel(X)
break
sleep(3) //Changing this to a lower value will cause the beam to follow more smoothly with movement, but it will also be more laggy.
//I've found that 3 ticks provided a nice balance for my use.
for(var/obj/effect/overlay/beam/O in orange(10,src)) if(O.BeamSource==src) qdel(O)
//All atoms
/atom/proc/examine(mob/user, var/distance = -1, var/infix = "", var/suffix = "")
//This reformat names to get a/an properly working on item descriptions when they are bloody
+2
View File
@@ -569,6 +569,8 @@ var/send_emergency_team
M.equip_to_slot_or_del(new /obj/item/weapon/reagent_containers/hypospray/combat/nanites(src), slot_l_store)
M.equip_to_slot_or_del(new /obj/item/weapon/melee/classic_baton/telescopic(M), slot_r_store)
M.equip_to_slot_or_del(new /obj/item/weapon/gun/medbeam(M), slot_r_hand)
if("Commander")
M.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat/swat(M), slot_shoes)
M.equip_to_slot_or_del(new /obj/item/clothing/gloves/combat(M), slot_gloves)
+127
View File
@@ -0,0 +1,127 @@
/obj/item/weapon/gun/medbeam
name = "Medical Beamgun"
desc = "Delivers medical nanites in a focused beam."
icon = 'icons/obj/chronos.dmi'
icon_state = "chronogun"
item_state = "chronogun"
w_class = 3.0
var/mob/living/current_target
var/last_check = 0
var/check_delay = 10 //Check los as often as possible, max resolution is SSobj tick though
var/max_range = 8
var/active = 0
var/datum/beam/current_beam = null
heavy_weapon = 1
/obj/item/weapon/gun/medbeam/New()
..()
processing_objects.Add(src)
/obj/item/weapon/gun/medbeam/Destroy()
processing_objects.Remove(src)
return ..()
/obj/item/weapon/gun/medbeam/dropped(mob/user)
..()
LoseTarget()
/obj/item/weapon/gun/medbeam/proc/LoseTarget()
if(active)
qdel(current_beam)
active = 0
on_beam_relase(current_target)
current_target = null
/obj/item/weapon/gun/medbeam/Fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, params)
add_fingerprint(user)
if(!isliving(target))
return
if(current_target)
LoseTarget()
current_target = target
active = 1
current_beam = new(user,current_target,time=6000)
spawn(0)
current_beam.Start()
feedback_add_details("gun_fired","[src.type]")
/obj/item/weapon/gun/medbeam/afterattack(obj/target, mob/user, proximity)
if(target.loc == loc || target == user)
return
if(!current_target && isliving(target))
current_target = target
active = 1
current_beam = new(user,current_target,time=6000)
spawn(0)
current_beam.Start()
/obj/item/weapon/gun/medbeam/process()
var/mob/living/carbon/human/H = loc
if(!istype(H))
LoseTarget()
return
if(!current_target)
LoseTarget()
return
if(world.time <= last_check+check_delay)
return
last_check = world.time
if(get_dist(H,current_target)>max_range || !los_check(H,current_target))
LoseTarget()
H << "<span class='warning'>You lose control of the beam!</span>"
return
if(current_target)
on_beam_tick(current_target)
/obj/item/weapon/gun/medbeam/proc/los_check(mob/user,mob/target)
var/turf/user_turf = user.loc
if(!istype(user_turf))
return 0
var/obj/dummy = new(user_turf)
dummy.pass_flags |= PASSTABLE & PASSGLASS & PASSGRILLE //Grille/Glass so it can be used through common windows
for(var/turf/turf in getline(user_turf,target))
if(turf.density)
qdel(dummy)
return 0
for(var/atom/movable/AM in turf)
if(!AM.CanPass(dummy,turf,1))
qdel(dummy)
return 0
for(var/obj/effect/ebeam/medical/B in turf)// Don't cross the str-beams!
if(B.owner != current_beam)
explosion(B.loc,0,3,5,8)
qdel(dummy)
return 0
qdel(dummy)
return 1
/obj/item/weapon/gun/medbeam/proc/on_beam_hit(var/mob/living/target)
return
/obj/item/weapon/gun/medbeam/proc/on_beam_tick(var/mob/living/target)
target.adjustBruteLoss(-4)
target.adjustFireLoss(-4)
if(ishuman(target))
var/var/mob/living/carbon/human/H = target
for(var/obj/item/organ/external/E in H.organs)
if(prob(10))
if(E.mend_fracture())
E.perma_injury = 0
return
/obj/item/weapon/gun/medbeam/proc/on_beam_relase(var/mob/living/target)
return
/obj/effect/ebeam/medical
name = "medical beam"
+2
View File
@@ -176,6 +176,7 @@
#include "code\controllers\ProcessScheduler\core\processScheduler.dm"
#include "code\datums\ai_law_sets.dm"
#include "code\datums\ai_laws.dm"
#include "code\datums\beam.dm"
#include "code\datums\browser.dm"
#include "code\datums\cargoprofile.dm"
#include "code\datums\computerfiles.dm"
@@ -1627,6 +1628,7 @@
#include "code\modules\procedural_mapping\mapGenerators\syndicate.dm"
#include "code\modules\projectiles\ammunition.dm"
#include "code\modules\projectiles\gun.dm"
#include "code\modules\projectiles\medbeam.dm"
#include "code\modules\projectiles\projectile.dm"
#include "code\modules\projectiles\targeting.dm"
#include "code\modules\projectiles\ammunition\ammo_casings.dm"