obstacle damage shown help?

AlexDC22

Well-known member
sorry about the title, really unsure what to call it.. basically what the video shows... not sure how to achieve this without script and scripting have yielded me nothing at all since i suck at scripting...

this attempt at a script throws no errors but it crashes before level loads.
C:
void main()
{
    int self = getlocalvar("self");
    int health = getentityproperty(self, "health");

    if (health > 30) {
        changeentityproperty(self, "animation", openborconstant("ANI_IDLE"));
        changeentityproperty(self, "sprite", "data/chars/misc/Obstacles/t1.png");
    } else if (health > 20) {
        changeentityproperty(self, "animation", openborconstant("ANI_IDLE"));
        changeentityproperty(self, "sprite", "data/chars/misc/Obstacles/t2.png");
    } else if (health > 10) {
        changeentityproperty(self, "animation", openborconstant("ANI_IDLE"));
        changeentityproperty(self, "sprite", "data/chars/misc/Obstacles/t3.png");
    } else if (health > 0) {
        changeentityproperty(self, "animation", openborconstant("ANI_IDLE"));
        changeentityproperty(self, "sprite", "data/chars/misc/Obstacles/t4.png");
    } else {
        performattack(self);
        changeentityproperty(self, "animation", openborconstant("ANI_DIE"));
        changeentityproperty(self, "sprite", "data/chars/misc/Obstacles/t4.png");
    }
}

void takedamage(int damage)
{
    int self = getlocalvar("self");
    int health = getentityproperty(self, "health");
    health -= damage;
    changeentityproperty(self, "health", health);
    main();
}

log showing where it crashes
Code:
Level Loading:   'DATA/LEVELS/level1.TXT'
Total Ram: 42871939072 Bytes ( 40885 MB )
 Free Ram: 25588539392 Bytes ( 24403 MB )
 Used Ram:    99995648 Bytes (    95 MB )

Loading 'phoneb' from data/chars/misc/phoneb.txt
 ...done!
Loading 'devil_akuma' from data/chars/akuma/dakuma.txt
Loading 'hadoken' from data/chars/misc/hadoken.txt
 ...done!
Loading 'akumaspec' from data/chars/misc/akumaspec.txt
 ...done!
Loading 'death' from data/chars/misc/death.txt
 ...done!
Loading 'ends' from data/chars/misc/ends.txt
 ...done!
 ...done!

Level Loaded:    'DATA/LEVELS/level1.TXT'
Total Ram: 42871939072 Bytes ( 40885 MB )
 Free Ram: 25585586176 Bytes ( 24400 MB )
 Used Ram:   104595456 Bytes (    99 MB )
Total sprites mapped: 2196

and my obstacle file
Code:
name     phoneb
health 40
noatflash 1
flash noatflash
nolife 1
diesound data/sounds/glass.wav
gfxshadow 1
type obstacle
candamage player
animationscript data/scripts/obstacle_script.c


anim idle
    delay    10
    offset    60 183
    bbox    24 16 86 176
        platform  -25 -25 100 100 20 140
        frame    data/chars/misc/Obstacles/t1.png
        frame    data/chars/misc/Obstacles/t2.png
        frame    data/chars/misc/Obstacles/t3.png
        frame    data/chars/misc/Obstacles/t4.png

anim Death
    delay    99
    offset    60 183
    frame    data/chars/misc/Obstacles/t4.png

any help would be appreciated been trying for a few hours and is getting annoying >_> lol
thanks
 

 

thanks that worked :)
 
so while everything does work, ive encountered an issue... is the shadow seems to be on top of the spawned frame not under lol
for the record.. the death frame stays on screen by design like the video...

EDIT: nevermind forgot to edit the spawnframe coords smfh
 

Attachments

  • paxplode - 0004.png
    paxplode - 0004.png
    71.2 KB · Views: 5
Last edited:
ok so just when i thought this was settled, i encounter another issue and no clue how to solve it... any item i add to it it stays behind the death frame...theres a burger back there and terry is hungry xD
and unless i get rid of the death frame the item stays in the back... but the death frame is important for visual effects xD

paxplode - 0008.png

this is the obstacle text which is almost the same as maxmans example
Code:
name     phoneb
health 50
noatflash 1
flash noatflash
death 1
nomove 1
nolife 1
diesound data/sounds/glass.wav
gfxshadow 1
type obstacle
candamage player
load phoneb1

anim    idle
@script
    void self = getlocalvar("self"); //Get calling entity
    int MHP = getentityproperty(self, "maxhealth");
    int HP = getentityproperty(self, "health");

    if(HP < MHP*1){//20 < 30*1 = 30; 20<30
      changeentityproperty(self, "animation", openborconstant("ANI_FOLLOW1"));
    }
    @end_script
        loop    1
    delay    5
    offset    65 183
    bbox    28 31 77 160
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t1.png

anim    follow1
@script
    void self = getlocalvar("self"); //Get calling entity
    int MHP = getentityproperty(self, "maxhealth");
    int HP = getentityproperty(self, "health");

    if(HP < MHP*0.5){//10 <30*0.5 = 15; 10<15
      changeentityproperty(self, "animation", openborconstant("ANI_FOLLOW2"));
    }
    @end_script
        loop    1
    delay    5
    offset    65 183
    bbox    28 31 77 160
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t2.png

    
anim    follow2
        loop    1
    delay    5
    offset    65 183
    bbox    28 31 77 160
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t3.png


anim    death
        loop    0
    delay    0
    offset    65 183
        spawnframe    1 1 1 0 0
        custentity    phoneb1
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t4.png
        frame   Data/chars/misc/empty.gif

this is the spawn for it
Code:
name     phoneb1
death 1
nomove 1
gfxshadow 1
type obstacle

anim    idle
        loop    0
    offset    66 183
        frame    data/chars/misc/Obstacles/t4.png

not sure if its correctable without a whole lot of hassle... thanks for any assist.
 
Have you tried using setlayer? Remember the Z part for fglayer?

setlayer {int}

  • This entity will be displayed as if it were at z position {int}, regardless of it's actual position.

I think you have two choices. 1) You can either add setlayer with a negative value without spawnframe if you use nodieblink 3 which makes the entities not disappear unless it's off-screen. 2) Or you can add setlayer without nodieblink 3 from spawnframe of the real obstacle.

nodieblink {int}

  • Sets how entity's death animation is played.
    • 0 = entity starts blinking as soon as entity die in respective FALL animation.
    • 1 = entity won't blink until after the last frame of entity's FALL or DEATH animation when killed.
    • 2 = entity won't blink at all during death, and entity will disappear after the last frame of their death animation.
    • 3 = entity will play it's death animation without blinking, and will not disappear until scrolled offscreen. The enemy won't count towards 'group's after dying, even though they don't disappear. This setting ONLY works for enemies.

Option #1:
Code:
name     phoneb
health 50
noatflash 1
flash noatflash
death 1
nomove 1
nolife 1
diesound data/sounds/glass.wav
gfxshadow 1
type obstacle
candamage player
nodieblink 3

anim    idle
@script
    void self = getlocalvar("self"); //Get calling entity
    int MHP = getentityproperty(self, "maxhealth");
    int HP = getentityproperty(self, "health");

    if(HP < MHP*1){//20 < 30*1 = 30; 20<30
      changeentityproperty(self, "animation", openborconstant("ANI_FOLLOW1"));
    }
    @end_script
        loop    1
    delay    5
    offset    65 183
    bbox    28 31 77 160
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t1.png

anim    follow1
@script
    void self = getlocalvar("self"); //Get calling entity
    int MHP = getentityproperty(self, "maxhealth");
    int HP = getentityproperty(self, "health");

    if(HP < MHP*0.5){//10 <30*0.5 = 15; 10<15
      changeentityproperty(self, "animation", openborconstant("ANI_FOLLOW2"));
    }
    @end_script
        loop    1
    delay    5
    offset    65 183
    bbox    28 31 77 160
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t2.png

   
anim    follow2
        loop    1
    delay    5
    offset    65 183
    bbox    28 31 77 160
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t3.png


anim    death
        loop    1 1
    delay    3
    offset    65 183
        platform  65 195 -66 -66 75 75 20 1111
        @cmd changeentityproperty getlocalvar("self") "setlayer" -500
        frame    data/chars/misc/Obstacles/t4.png
        platform 0 0 0 0 0 0 0 0
        frame   Data/chars/misc/Obstacles/t4.png

You can add loop in its anim death or not. That's up to you.

loop {bi} {start} {end}

  • Determines how loop effect is applied in current animation
  • {bi} toggles looping on or off.
    • 0 = looping off
    • 1 = looping on
  • {start} determines the number of frame the animation loops to. Defaults to 0 or 1st frame.
  • {end} determines the number of frame which starts the loop. If left blank, the animation will loop at the end of animation.
  • Some animations should NOT be set to loop (loop temporary at least). Examples include most attacks and injured animations.

Option #2:

You only change this one, so there's no need to change things for phoneb since you're using spawnframe.

Code:
name     phoneb1
death 1
nomove 1
gfxshadow 1
type obstacle
setlayer -500

anim    idle
        loop    0
    offset    66 183
        frame    data/chars/misc/Obstacles/t4.png

I haven't tested nodieblink 3 with other entity types, but I did test it with players too and it works. Check if nodieblink 3 works for dead entities or not. If it's only working for enemies as the manual says, you can use the second option.

Oh, by the way, you don't have to just put type obstacle as a stage view unless you wanna break it to be completely nothing. Type none is better (for phoneb1) as an extra, a stage view, a substitute, or whatever, like seeing a cameo on screen or an easter egg. But I'm not telling you that you should change from type obstacle to none. I'm just letting you know you have other options, like using type none without having to add anim fall and death. Leaving it with anim idle only is okay. Did you know that you can use type none as platforms for platformers?

type {type}

  • {type}:
    • player: The entity is a human-controlled player.
    • enemy: The entity is a CPU controlled enemy or enemy projectile.
    • npc: The entity is a CPU controlled ally that will seek out and attack
    • enemies. The entity is otherwise functionally identical to enemy entities with the chase subtype. You can change the NPC allegiance via hostile setting. Npc types do not count toward groups.
    • item: The entity is a stationary item which can be picked up. Items can only give one bonus per item. In other words, you can't make one item that both gives 2000 points AND gives a 1-up.
    • none: The entity is a useless decoration.
    • steamer: The entity constantly spews the object called Steam upwards with alpha transparency. Default offscreenkill value is 80.
    • obstacle: The entity is a stationary blockade which can (normally) be destroyed.
    • text: The entity is a message object. When spawned, it will freeze all objects in play and show it's *IDLE* animation, then dissapear. It can be sped up by pressing attack or jump. Can be used for level intros, mid-level cutscenes, etc.
    • trap: The entity is an obstacle which cannot be attacked. It can be made to attack, though, and will hit both players and enemies. If a trap is not set up to knock the entity down, the trap will only damage the entity one time. To hit them again, the target entity must take damage from another entity.
    • endlevel: The entity is an item which, when touched by a player, will end the stage. It can be given a score value to be awarded for level completion.
    • pshot: The type is outdated and does nothing. You can still use it, but it's ignored.
    • panel:The entity will scroll together with level. If the entity's speed is 10, entity will stay with panel. If the speed is 5, it will stay with background (for direction left,right and both). This type is used to make multiple layers.
These bikers here, you see in the video, are type none. In case you're wondering about their movement, I just use script for a reason, but you don't have to do scripts for all none type ones. Same for other entities you want to do and that depends on your choice.


EDIT:
I think what's better is that you can use this scripted health point trick without relying on the max health value.

Code:
name     phoneb
health 50
noatflash 1
flash noatflash
death 1
nomove 1
nolife 1
diesound data/sounds/glass.wav
gfxshadow 1
type obstacle
candamage player
load phoneb1

anim    idle
@script
    void self = getlocalvar("self"); //Get calling entity
    int HP = getentityproperty(self, "health"); // Get entity's health point

    if(HP <= 30){ // Change animation when active health point is 30 and below
      changeentityproperty(self, "animation", openborconstant("ANI_FOLLOW1"));
    }
    @end_script
        loop    1
    delay    5
    offset    65 183
    bbox    28 31 77 160
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t1.png

anim    follow1
@script
    void self = getlocalvar("self"); //Get calling entity
    int HP = getentityproperty(self, "health");

    if(HP <= 15){
      changeentityproperty(self, "animation", openborconstant("ANI_FOLLOW2"));
    }
    @end_script
        loop    1
    delay    5
    offset    65 183
    bbox    28 31 77 160
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t2.png

    
anim    follow2
        loop    1
    delay    5
    offset    65 183
    bbox    28 31 77 160
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t3.png


anim    death
        loop    0
    delay    0
    offset    65 183
        spawnframe    1 1 1 0 0
        custentity    phoneb1
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t4.png
        frame   Data/chars/misc/empty.gif

Is it working for you? There are other ways you can script health points with, not only this example I provided.
 
Last edited:
Have you tried using setlayer? Remember the Z part for fglayer?



I think you have two choices. 1) You can either add setlayer with a negative value without spawnframe if you use nodieblink 3 which makes the entities not disappear unless it's off-screen. 2) Or you can add setlayer without nodieblink 3 from spawnframe of the real obstacle.



Option #1:
Code:
name     phoneb
health 50
noatflash 1
flash noatflash
death 1
nomove 1
nolife 1
diesound data/sounds/glass.wav
gfxshadow 1
type obstacle
candamage player
nodieblink 3

anim    idle
@script
    void self = getlocalvar("self"); //Get calling entity
    int MHP = getentityproperty(self, "maxhealth");
    int HP = getentityproperty(self, "health");

    if(HP < MHP*1){//20 < 30*1 = 30; 20<30
      changeentityproperty(self, "animation", openborconstant("ANI_FOLLOW1"));
    }
    @end_script
        loop    1
    delay    5
    offset    65 183
    bbox    28 31 77 160
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t1.png

anim    follow1
@script
    void self = getlocalvar("self"); //Get calling entity
    int MHP = getentityproperty(self, "maxhealth");
    int HP = getentityproperty(self, "health");

    if(HP < MHP*0.5){//10 <30*0.5 = 15; 10<15
      changeentityproperty(self, "animation", openborconstant("ANI_FOLLOW2"));
    }
    @end_script
        loop    1
    delay    5
    offset    65 183
    bbox    28 31 77 160
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t2.png

 
anim    follow2
        loop    1
    delay    5
    offset    65 183
    bbox    28 31 77 160
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t3.png


anim    death
        loop    1 1
    delay    3
    offset    65 183
        platform  65 195 -66 -66 75 75 20 1111
        @cmd changeentityproperty getlocalvar("self") "setlayer" -500
        frame    data/chars/misc/Obstacles/t4.png
        platform 0 0 0 0 0 0 0 0
        frame   Data/chars/misc/Obstacles/t4.png

You can add loop in its anim death or not. That's up to you.



Option #2:

You only change this one, so there's no need to change things for phoneb since you're using spawnframe.

Code:
name     phoneb1
death 1
nomove 1
gfxshadow 1
type obstacle
setlayer -500

anim    idle
        loop    0
    offset    66 183
        frame    data/chars/misc/Obstacles/t4.png

I haven't tested nodieblink 3 with other entity types, but I did test it with players too and it works. Check if nodieblink 3 works for dead entities or not. If it's only working for enemies as the manual says, you can use the second option.

Oh, by the way, you don't have to just put type obstacle as a stage view unless you wanna break it to be completely nothing. Type none is better (for phoneb1) as an extra, a stage view, a substitute, or whatever, like seeing a cameo on screen or an easter egg. But I'm not telling you that you should change from type obstacle to none. I'm just letting you know you have other options, like using type none without having to add anim fall and death. Leaving it with anim idle only is okay. Did you know that you can use type none as platforms for platformers?


These bikers here, you see in the video, are type none. In case you're wondering about their movement, I just use script for a reason, but you don't have to do scripts for all none type ones. Same for other entities you want to do and that depends on your choice.


EDIT:
I think what's better is that you can use this scripted health point trick without relying on the max health value.

Code:
name     phoneb
health 50
noatflash 1
flash noatflash
death 1
nomove 1
nolife 1
diesound data/sounds/glass.wav
gfxshadow 1
type obstacle
candamage player
load phoneb1

anim    idle
@script
    void self = getlocalvar("self"); //Get calling entity
    int HP = getentityproperty(self, "health"); // Get entity's health point

    if(HP <= 30){ // Change animation when active health point is 30 and below
      changeentityproperty(self, "animation", openborconstant("ANI_FOLLOW1"));
    }
    @end_script
        loop    1
    delay    5
    offset    65 183
    bbox    28 31 77 160
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t1.png

anim    follow1
@script
    void self = getlocalvar("self"); //Get calling entity
    int HP = getentityproperty(self, "health");

    if(HP <= 15){
      changeentityproperty(self, "animation", openborconstant("ANI_FOLLOW2"));
    }
    @end_script
        loop    1
    delay    5
    offset    65 183
    bbox    28 31 77 160
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t2.png

 
anim    follow2
        loop    1
    delay    5
    offset    65 183
    bbox    28 31 77 160
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t3.png


anim    death
        loop    0
    delay    0
    offset    65 183
        spawnframe    1 1 1 0 0
        custentity    phoneb1
        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/Obstacles/t4.png
        frame   Data/chars/misc/empty.gif

Is it working for you? There are other ways you can script health points with, not only this example I provided.
so much info... thank you brother... i didnt think of using set layer on the spawn frame at all.. and a -1 did the trick,anything more would put the frame under the graphic shadow on it.
i also had to shave a pixel... yes 1 pixel from the death frame platform to be able to actually grab it lol
and i also changed it to type none for phomeb1.
everything is working great now, thanks so much... that setlayer i just didnt think of it :(
thanks for all the info have to go eat now, just got home from watching deadpool 3 in 3D ... fun movie :)


EdIt: damn just saw that SF video... wow looks great.
Edit: had to add nodieblink 2 because if the obstacle breaks offscreen, it would keep blinking... and theres 1 or 2 moves in the game that cause this.
 
Last edited:
@AlexDC22 I just created a new method for the animated broken object. It's based on your original attempt which you posted in your topic at first. I already showed you an improvement from my previous post of this thread. Here, I created a very simple damage script for the object to change, but it changes sprite in both animationscript and takedamagescript.

Code:
name     phonea
health 50 # HEALTH POINT
noatflash 1
flash noatflash
death 1
nomove 1
nolife 1
nodieblink 2
diesound data/sounds/glass.wav
gfxshadow 1
type obstacle
candamage player
load phoneb1
takedamagescript data/chars/misc/phoneb/phoneb.c
animationscript data/scripts/animation/default.c

anim    idle
    delay    5
    offset    65 183
    bbox    28 31 77 160

    #### PHASE 1

        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/phoneb/t1.png #0
    @cmd changeFrame 0 # Change animation frame
        frame    data/chars/misc/phoneb/t1.png #1

    #### PHASE 2

        frame    data/chars/misc/phoneb/t2.png #2
    @cmd changeFrame 2
        frame    data/chars/misc/phoneb/t2.png #3

    #### PHASE 3

        frame    data/chars/misc/phoneb/t3.png #4
    @cmd changeFrame 4
        frame    data/chars/misc/phoneb/t3.png #5

anim    death
        loop    0
    delay    0
    offset    65 183
        spawnframe    1 1 1 0 0
        custentity    phoneb1
        platform  65 194 -66 -66 75 75 20 1111
        frame    data/chars/misc/phoneb/t4.png
        frame   Data/chars/misc/empty.gif

Here's a simple damage script.

phoneb.c:
C:
void main(){ // Exclusively for the phone booth object
    void self = getlocalvar("self"); // Get acting entity
    int hp = getentityproperty(self, "health"); // Get entity's health value

    if(hp <= 30){ //If its health point is 30 or less...
        updateframe(self, 2); // Change frame to 2 (3rd frame of the current animation)
    }
    if(hp <= 15){ //If its health point is 15 or less...
        updateframe(self, 4); // Change frame to 4
    }
}

Here's an animation script that supports to change frame which acts like a loop within certain frames.

C:
void changeFrame(int frame){
    void self = getlocalvar("self");
    updateframe(self, frame);
}

I don't know what the masters of coding here think, but I tried to make this takedamagescript as simple as I could. It works well, but I'd like to know their opinions in this.
 
@AlexDC22 I just created a new method for the animated broken object. It's based on your original attempt which you posted in your topic at first. I already showed you an improvement from my previous post of this thread. Here, I created a very simple damage script for the object to change, but it changes sprite in both animationscript and takedamagescript.

Code:
name     phonea
health 50 # HEALTH POINT
noatflash 1
flash noatflash
death 1
nomove 1
nolife 1
nodieblink 2
diesound data/sounds/glass.wav
gfxshadow 1
type obstacle
candamage player
load phoneb1
takedamagescript data/chars/misc/phoneb/phoneb.c
animationscript data/scripts/animation/default.c

anim    idle
    delay    5
    offset    65 183
    bbox    28 31 77 160

    #### PHASE 1

        platform  65 195 -66 -66 75 75 20 1111
        frame    data/chars/misc/phoneb/t1.png #0
    @cmd changeFrame 0 # Change animation frame
        frame    data/chars/misc/phoneb/t1.png #1

    #### PHASE 2

        frame    data/chars/misc/phoneb/t2.png #2
    @cmd changeFrame 2
        frame    data/chars/misc/phoneb/t2.png #3

    #### PHASE 3

        frame    data/chars/misc/phoneb/t3.png #4
    @cmd changeFrame 4
        frame    data/chars/misc/phoneb/t3.png #5

anim    death
        loop    0
    delay    0
    offset    65 183
        spawnframe    1 1 1 0 0
        custentity    phoneb1
        platform  65 194 -66 -66 75 75 20 1111
        frame    data/chars/misc/phoneb/t4.png
        frame   Data/chars/misc/empty.gif

Here's a simple damage script.

phoneb.c:
C:
void main(){ // Exclusively for the phone booth object
    void self = getlocalvar("self"); // Get acting entity
    int hp = getentityproperty(self, "health"); // Get entity's health value

    if(hp <= 30){ //If its health point is 30 or less...
        updateframe(self, 2); // Change frame to 2 (3rd frame of the current animation)
    }
    if(hp <= 15){ //If its health point is 15 or less...
        updateframe(self, 4); // Change frame to 4
    }
}

Here's an animation script that supports to change frame which acts like a loop within certain frames.

C:
void changeFrame(int frame){
    void self = getlocalvar("self");
    updateframe(self, frame);
}

I don't know what the masters of coding here think, but I tried to make this takedamagescript as simple as I could. It works well, but I'd like to know their opinions in this.
will have to test at some point today.... thanks brother :)
 
It's done with script, though the result is similar. You can change the health points in the damage script to whatever you desire for its damage point.

I don't know how exactly you want it to act like.
 
It's done with script, though the result is similar. You can change the health points in the damage script to whatever you desire for its damage point.

I don't know how exactly you want it to act like.
the way it does ATM... only issue i had was when it got destroyed offscreen it would keep blinking but i fixed that in phoneb1 using noblinkdie...the one i sent you was all set already and ready to go....your way is done differently but it achieves the same afaik :)

could be adapted to be use for other obstacles with similar traits...might come in handy you have multiple like that i believe.
 
Back
Top Bottom