ID:272892
 
Probably worded that strangely, but I'm having issues with matching up my graphics with my coding... I have an explosion that looks like the following:
XXOXX
XOOOX The O is where it explodes,
OOoOO the X is where I don't want it to hit
XOOOX
XXOXX
But the code I have to handle the damage, only effects mobs in o-range 1, so the 4 extra blasts on the edges don't actually hit anything, they just look fancy.
Right now, I have the following
        Hit(atom/A)
var/damage
damage=round((src.Pow+rand((src.Pow*(-0.25)),(src.Pow*0.25))))
for(var/mob/X in oview(1,A))
X.health-=round(damage/2)
if(istype(A,/mob))
A.health-=damage
oview(src) << "[src] hit [A]! [damage] Damage!"
A = TurfOf(A)
if(A) loc = A
Terminate()

Terminate() is what handles the visual effects, and it works just fine. I just need the 'for(var/mob/X in oview(1,A)) to include an extra space in each direction without just making the whole square larger... O.o
Add each of those "affectable" turfs to a list when you do the FX,

for(var/turf/t in ListOfAffectableTurfs)
for(var/mob/m in t)
//...
I'm understanding what you're asking, but just for clarification; are you asking for like a "diamond-shaped" explosion?

Say we had an explosion with a range of 3:

.....X.....
....XXX....
...XXXXX...
..XXXOXXX..
...XXXXX...
....XXX....
.....X.....


Something like that?
In response to Mega fart cannon
Yes, I'm only looking for a range of 2 at the moment; but yes, that's exactly what I'm looking for.

As for the thing about Affectable turfs thing, I'm not entierly sure how to do that effectively enough to work each time... The visual FX has no effect on the actual game, it's a separate component all together, and I'd like to have the damage-portion of the code connected to the Hit, not the Terminate, so I can still reference the missle(which has the Pow var). It could work, but the amount of code I would need to use would make it clunky and likely prone to error...
In response to Big the ED
I wrote a diamond shaped splash damage dealy for Efencea.

    splashRegion(var/turf/start, var/splashSize)
if(!istype(start, /turf) )
start = start.loc

var
coordinate/coord = new()
list
region = list(start)
var/turf/currentTurf = get_step(start, NORTH)
for(var/i = 1; i <= splashSize; i++)
for(var/direction in theDiagnols)
for(var/n = 1; n <= i; n++)
var/turf/nextTurf
if(coord.hasStepped)
nextTurf = coord.getNextStep(direction)
else
nextTurf = coord.getStep(currentTurf, direction)
if(nextTurf)
currentTurf = nextTurf
region += currentTurf
coord = new(currentTurf)

currentTurf = coord.getNextStep(NORTH)
return region


That returns the diamond shape of turfs from start to splashSize without recursion. The best way I could come up with to do it, actually.

Then there was an issue when the diamonds extended outside the map bounds so I wrote this coordinate datum to keep track of the 'build' position.

coordinate
var
x
y
z = 1
hasStepped = 0
New(var/turf/start)
if(start)
x = start.x
y = start.y
z = start.z
proc
getStep(var/turf/T, var/direction)
x = T.x
y = T.y
z = T.z
return getTurfAtXY(direction)

getNextStep(var/direction)
return getTurfAtXY(direction)

getTurfAtXY(var/direction)
hasStepped = 1
switch(direction)
if(NORTH)
y++
if(SOUTH)
y--
if(SOUTHWEST)
x--
y--
if(SOUTHEAST)
y--
x++
if(WEST)
x--
if(EAST)
x++
if(NORTHWEST)
x--
y++
if(NORTHEAST)
y++
x++
var/newTurf = locate(x,y,z)
return newTurf


The final tidbit necessary is the list of diagnol directions.

var
list
theDiagnols = list(SOUTHEAST, SOUTHWEST, NORTHWEST, NORTHEAST)


It probably isnt be the BEST implementation possible but I've found that it works quite well, and it's relatively fast too.
In response to Big the ED
Diamond-shaped explosions are actually quite easy to make.

obj
FX
layer=MOB_LAYER+1
Firebolt_Explosion/icon_state="FIRE!"

Missile
var/Range

Firebolt
icon_state="Firebolt"
Range=2

proc
Cast()
//Your usual casting proc would go here.

Explode(mob/Ref)
for(var/X = -Range to Range)
for(var/Y = -Range to Range)
if((abs(X) + abs(Y)) > Range || (X+Ref.x) > world.maxx || (X+Ref.x) <= 0 || (Y+Ref.y) > world.maxy || (Y+Ref.y) <= 0) continue
//If the coordinates are outside of the map bounds, or if they are not part of the diamond shape, skip them.

var/o = text2type("/obj/FX/[name]_Explosion") //This is so we don't have to rewrite this proc over... and over...
var/obj/boom = new o(locate(Ref.x+X,Ref.y+Y,Ref.z))
spawn(40) del boom //Wait 4 seconds then delete.


For the range of 2, the above would produce:

..x..
.xxx.
xxoxx
.xxx.
..x..
In response to Mega fart cannon
Sorry, it's not you... But this is making me extremely angry... I could never do programming for a living.

It looks like the coding -would- work, except that I already have the visual effect complete(through a bunch of if-else statements and a chunk of new/obj/boom, x+=1, y-=1, blah blah blah sorta things), and to be honest it would be a lot more difficult to manipulate either to do what I need without creating a couple different procs for every different type of explosion(I'm using both square and diamond-shape).

I tried using these codes to overwrite what I had, to see if it would streamline it, but all it did was complicate it and fill it with errors; my original code is set up to explode whenever it hits any obstacle, not just mobs or objs. The issue is, your explosion code doesn't work if it hits a dense turf or obj like I need it to; it returns Ref as null, and the missle keeps going... I'll keep trying, but what I'm essentially looking for is a way to make orange or oview select a diamond instead of a square.
In response to Big the ED
Atoms would probably be your answer then; since an atom is the parent of basically everything except datums, you can use it to get the desired effect.

      Explode(atom/Ref, Shape="Square")  //Added a Shape argument to help apply the shape of the explosion later on.
if(!Ref.density) return
for(var/X = -Range to Range)
for(var/Y = -Range to Range)
if(Shape=="Diamond")
if((abs(X) + abs(Y)) > Range || (X+Ref.x) > world.maxx || (X+Ref.x) <= 0 || (Y+Ref.y) > world.maxy || (Y+Ref.y) <= 0) continue
//If "Shape" isn't a diamond, then apply the explosion obj to all designated coordinates.

// ...

del src //At the end of the proc


Also, orange and oview will never return anything other than a square, so you have to make your own custom proc to return something that isn't a square.
In response to Mega fart cannon
I'm still getting a bunch of "runtime error: Cannot read null.density" in a row; probably still some sort of descrepency bewteen how the two programs function. Right now, as I have it set up, there's three parts; the code than handles shooting crap(which works independantly), the code that handles the thing hitting something, and the code that handles the explosion that follows; and I think something isn't connecting between it hitting and then exploding... And I figured oview/range wouldn't help much, but my point is I wanna know how to add the extra 4 spaces into a list; the list is the important thing, not the explosion itself, but I'm terrible at manipulating lists...
Thank you for trying so far, and I'm still trying to fix up whatever is going wrong, but no luck yet =\
In response to Big the ED
Yeah, I made my initial coding work; it's very large and quite bulky, but it's effective enough to do what I need it to. Thanks for all the help!
In response to Big the ED
Big the ED wrote:
Yeah, I made my initial coding work; it's very large and quite bulky, but it's effective enough to do what I need it to. Thanks for all the help!

I'd like to submit the following small system that could do what you want even better, this allows you to customize the area for ANY spell or ability.

Make a list for your ability called area[]

area = list(\
0,0,0,0,0,\
0,0,1,0,0,\
0,1,1,1,0,\
0,0,1,0,0,\
0,0,0,0,0)


1 = hit, 0 = not hit

Use this small procedure to get a list of all the turfs within that area:

GetArea(atom/M, area[])
var/new_area[] = list()
var/len = sqrt(area.len)
var/mid = (len + 1) / 2
for(var/iy = 1, iy <= len, iy++)
for(var/ix = 1, ix <= len, ix++)
var/turf/T = locate(M.x - mid + ix, M.y - mid + iy, M.z)
var/check = area[(iy-1) * 5 + ix]
if(check)
new_area.Add(T)
return new_area


Now whenever you want to do stuff to everything in that area, use something like this small loop:

for(var/turf/T in GetArea(some_mob, area))
SpellHit(T)


Let me know if you have any questions!


~Polatrite~