OpenBoR Tips & Tricks

Bloodbane

Well-known member
I still have draft for these but I don't feel like about splitting into single threads so I just post them here.

Generic Portal

ContraP.png


Intro: Generic Portal is advanced version of Alternate Portal above. They work exactly the same. The only difference is that Generic Portal allows modder to set different branch in level texts without making another portal.
This tutorial will describe how to modify alternate portal to make generic portal.
Procedure: 1st, here's example of alternate portal:
name    Portal
nomove  1
type    none
nolife  1
score  0 -1
antigravity  100
candamage  player
setlayer  100

anim idle
loop 1
delay 50
        followanim 1
        followcond 1
offset 13 27
attack 1 2 32 26 0 0 1 1
noreflect 1
        hitfx  data/sounds/silent.wav
frame data/chars/misc/arrowr.png
frame data/chars/misc/empty.gif

anim follow1
delay 50
offset 13 27
frame data/chars/misc/arrowr.png
        @cmd    jumptobranch "Branch1" 1
frame data/chars/misc/empty.gif
frame data/chars/misc/arrowr.png

Now modify it into this:
name    Portal
nomove  1
type    none
nolife  1
score  0 -1
antigravity  100
candamage  player
setlayer  100

anim idle
loop 1
delay 50
        followanim 1
        followcond 1
offset 13 27
attack 1 2 32 26 0 0 1 1
noreflect 1
        hitfx  data/sounds/silent.wav
frame data/chars/misc/arrowr.png
frame data/chars/misc/empty.gif

anim follow1
@script
    void self = getlocalvar("self");
    char Name = getentityproperty(self,"name");

    if(frame == 1){
      jumptobranch(Name, 1);
    }
@end_script
delay 50
offset 13 27
frame data/chars/misc/arrowr.png
frame data/chars/misc/empty.gif
frame data/chars/misc/arrowr.png

As you can see, the script in FOLLOW1 is changed while the rest remains the same. What this script do is acquire this portal's alias then in 2nd frame, jumps to branch with that alias.
See above picture. This is example of how to set it in a level:

spawn  Portal
alias T1
coords  30 222 130
at 0

spawn  Portal
alias T2
flip 1
coords  290 222 130
at 0

spawn  Portal
alias T3
coords  30 222 70
at 0

spawn  Portal
alias T4
flip 1
coords  290 222 70
at 0

spawn  Portal
alias T5
coords  30 222 10
at 0

spawn  Portal
alias T6
flip 1
coords  290 222 10
at 0

With this, you only need one portal entity to set 6 branches. Efficient, don't you think? :)

Limitation: The issue is exactly same as alternate portal's so I only mention its limitation. The most obvious limitation is that generic portal uses specific image (or nothing if you use blank image) and specific portal size. So it's recommended to set generic image and size so the portal can be used almost anywhere.

Level End Entity

Intro: Normally levels in OpenBoR are ended by defeating every enemy in the level or by defeating boss. Alternatively, touching endlevel entity also ends level. With script, level can be ended in various ways. This tutorial describes how to make entity which ends current level after it is spawned. In addition to ending level, this entity also brings player to defined branch.
Procedure: Let's name this entity as LevelEnd. Here's an example of its  text:
name    LevelEnd
type    none
antigravity  100

anim idle
@script
    void self = getlocalvar("self");
    char Name = getentityproperty(self,"name");

    if(frame == 1){
      jumptobranch(Name, 1);
    }
@end_script
delay 300  #<--- defines how long it takes before level ends
offset 1 1
frame data/chars/misc/empty.gif
frame data/chars/misc/empty.gif

LevelEnd uses 'antigravity 100' to prevent it from falling to holes. Its type doesn't matter, let's just use 'type none'.
In its IDLE, it has script which works like this: entity's alias is acquired then at 2nd frame, level is ended and jumps to branch with same name as that alias. If there's no such branch, the level only ends without jumping to any branch.
'delay 300' means after LevelEnd is spawned, it will wait 300 centiseconds or 3 seconds before ending the level. Change the value to suit your need.
It is using blank image (empty.gif) cause it's meant to be invisible.
To use LevelEnd, either spawn it directly like this:
spawn  LevelEnd
alias  BranchName
coords 160 200
at    0

or set it as other entity's dropped item like this:
spawn  Enemy
item  LevelEnd
itemalias BranchName
coords -100 200
at    0

Alias is only added if you want LevelEnd to jump to defined branchbame after ending the level.
Limitation: Since this entity uses its name as branch destination, it will try to jump to branch named 'LevelEnd' if no alias is given to it. That means, you can't use 'LevelEnd' as name of your branches to avoid conflict with LevelEnd (why would you anyways :) ?).

Alternate Default Palette

Intro: Ever have problem in which entity's colors look awful but you are too lazy to edit all sprites? or you want to use remap as default palette but are too lazy to change sprites' palette? Now your problem is solved with this tutorial.
Before we start, this method ONLY works with 16bit/32bit colour depth.
Procedure: In 16bit/32bit colour depth, OpenBoR gets entity's palette from reference image which is either 1st defined image or image defined by palette command. This palette is used for all images/sprites by that entity.
Because of that nature, if the reference image's palette is altered, the whole images' palette will be altered too. So in order to change shown colors, all we need to do is to change the reference image's palette.
If your problem is entity's colors look awful, just find reference image and edit its palette. OTOH if you want to use a remap as default palette, just change reference image to something like this:

palette          data/chars/entity/alter.png

alter.png is the remap and it will be default palette for the entity.

Limitation: Just to reiterate, this method ONLY change SHOWN colors in game. It doesn't change the images palette at all.


Simple Striker

Intro: In Capcom beat'm ups, ever notice enemies which comes, attack then leaves? There is no official term for them so I use striker term cause they act just like King of Fighter's strikers.
This tutorial desribes how to make such striker. However, since striker is not 100% stable, this tutorial will only desribe simple striker which is stable enough.The instability issues will be explained in detail in Issue below.
One thing to mention is that strikers are optional enemies. Players could kill them or just let them go. When they are let go, 'offscreenkill' command will remove them when they are offscreen far enough. That's why you have to make sure to use latest OpenBoR version cause that command is not supported in old version.
Procedure: As mentioned before, striker comes, attack then leaves so that means the striker needs SPAWN animation for the coming in animation. For the attack animation, it can be added after the coming animation in SPAWN or in seperate ATTACK animation. Here's an example for the latter:

name FlyOctiS
health 1
nomove 1 1
type enemy
death 1
cantgrab 1
candamage player obstacle
offscreenkill 100

anim spawn
delay 10
offset 44 90
        jumpframe  1  0  1 0
frame data/chars/enemy/idle1.png
frame data/chars/enemy/idle2.png
bbox 12 18 68 63
frame data/chars/enemy/idle3.png
frame data/chars/enemy/idle1.png
frame data/chars/enemy/idle2.png
frame data/chars/enemy/idle3.png
frame data/chars/enemy/idle1.png
frame data/chars/enemy/idle2.png
frame data/chars/enemy/idle3.png
frame data/chars/enemy/idle1.png
frame data/chars/enemy/idle2.png

anim idle
loop 1
delay 10
offset 44 90
bbox 12 18 68 63
frame data/chars/enemy/idle1.png
frame data/chars/enemy/idle2.png
frame data/chars/enemy/idle3.png

anim attack1
loop 1
range 0 400
rangez -200 200
delay 20
offset 44 90
        jumpframe  0  0  2 0
bbox 12 18 68 63
attack 41 17 44 67 10 1
frame data/chars/enemy/attack.png

anim death
delay 200
offset 44 90
        jumpframe  0  3  -2 0
        landframe  1
frame data/chars/enemy/fall1.png
delay 100
frame data/chars/enemy/dead.png
This striker is simple cause it only has 1 HP which means it will die if hit by any attack. It will also play DEATH when killed because of 'death 1'. Animations such as PAIN, FALL and RISE aren't required.
'cantgrab 1' is set to prevent players from grabbing this enemy.
'nomove 1 1' is set to make striker just perform the attack and won't try to walk at all.
'candamage' is set to player and obstacle. The former is obvious, the latter is so striker will also destroy obstacles if it meets any.
'offscreenkill' is important. It is required to make the striker disappear after going offscreen. 100 is chosen so striker will immediately disappear when it is 100 pixels offscreen, left or right. That also means this striker should be spawned less than 100 pixels offscreen to avoid being removed right after being spawned.

About the animations, SPAWN animation holds animation when striker comes. It will stop after animation ends. Then it has ATTACK1 which has wide and long coverage. The idea is so striker always find player and attack after coming in. Well, if there are no player, it will just stay still but it's good thing cause there's no need to attack when there's nothing to hit right? :).
In ATTACK1, there's 'jumpframe' which moves striker forward. The animation is looped also which make striker moves continuously to other screen edge. After it goes beyond offscreenkill value, it will disappear.

Here's an example to spawn striker:
spawn flyoctiS
map 2
coords 370 190
at 100

spawn flyoctiS
map 2
flip 1
coords -50 210
at 100

Notice that both striker are spawned 50 pixels offscreen. Don't forget to set 'flip' properly so they enter the screen instead of going out.

That's one way to make simple striker. Striker can do anything after coming but make sure it goes offscreen cause players can't be forced to kill striker.
Expansion: There are lots of way to expand the striker but you might need to use script to perfecten the striker. These are couple possible expansions:
1. Instead of charging forward, the striker could shoot or toss projectile in ATTACK1. After shooting or tossing, it could move away offscreen to leave. Combine 'loop' with 'jumpframe' for the leaving effect.
2. Strikers could act just as item carriers. They don't need to have attackbox (nothing wrong if they have though).
3. Strikers could be living time bomb. These type don't need offscreenkill but lifespan instead. Add explosion in DEATH animation and they are set!
4. Alternate ATTACK animation could be added to give alternate attack for the striker making it less predictable.

Aside of using ATTACK animation, striker could just use SPAWN animation for the come, attack then leave actions.

If you want to make striker which leaves from where it comes, you might need script to make sure they go to the right way after attacking. FYI enemy automatically turns if player is behind him/her that's why script is required.
Issue: The simple striker above is actually not 100% stable.
Here are couple instability issues, most of them are about ensuring striker's leave:
1. Striker might be blocked by wall and stuck. Although, it can be solved by making striker ignores walls, it is best to avoid spawning them toward walls.
2. Striker might be blocked by obstacles. The obstacles HP could be set low to help them charging though but it's best to avoide spawning them toward obstacles. OTOH some obstacles such as gate shouldn't be destroyed by them.
3. Strikers which can be grabbed can be done, just don't use 'cantgrab'. However, by allowing these, their position might change cause players could move them (with grabmove or throw) and let them go. They might bump to walls or obstacles later.
4. Strikers with higher HP is possible but make sure they have leave screen animation. This could be set in RISE or just ATTACK animation with wide range like above.
 
Would you mind I split them into separate posts? Riccochet set up a tutorial index here: http://www.chronocrash.com/forum/index.php?topic=58.msg251;topicseen#new
It's a great resource for users both new and old, It certainly simplifies things, no?
 
Hmmm... okay but only seperate posts not threads.
Speaking of which, I have other tutorial to repost too.
 
Ok, I split them up here: http://openbor.boards.net/index.cgi?board=help
For the sake of making things easy to find. I'd like to continue splitting them up, but I don't want to make a mess of the forum.  :(
 
Custom Arrows

Contra16.png


Intro: While playing a mod, you should notice an arrow which appears everytime a 'wait' area is cleared. This arrow is unfortunately not customizable aside of its sprite. Aside of only appearing after clearing 'wait' area, it's animation is limited to blinking.
Good news is latest OpenBoR allows modders to make their own 'arrow' and set its properties such as animation and position. Even better, this arrow can appear anywhere not just after wait. This tutorial will describe how to make such custom arrow.
Procedure: Before we start, the custom arrow is an entity which means it must be loaded in models.txt and spawned in level. Also the default arrow must be 'disabled' to avoid conflict with this arrow.
1. Disabling default arrow
Simply use a blank image as arrow.gif and put it in data/sprites folder
2. Creating custom arrow
Let's see an example of custom arrow:
name   Arrow
speed    10
type   Panel
shadow   0
lifespan 3
setlayer  300

anim idle
loop 1
delay 50
offset 12 149
frame data/chars/misc/arrow.gif
frame data/chars/misc/empty.gif

One important trait default arrow has is that it scrolls together with player. In order to replicate that trait, panel type is used. By setting 'speed 10', the panel type entity will scroll together with player.
Next, this arrow shouldn't cast shadow so 'shadow 0' is set. Then 'setlayer 300' is set to make arrow placed in front of other entities, just like default arrow. 'Lifespan 3' defines that this arrow will appear 3 seconds before removing itself.
For the arrow animation, IDLE defines it. In this animation, you can set animation delay and used frames.
3. Spawning arrow in level text
To spawn this arrow, simply use 'spawn' command like this:
spawn Arrow
coords 63 190
at 1000
Although this step is sufficient, you might want to modify the spawn coordinates to adjust arrow's position. Don't worry about it's z coordinate, this arrow has been set to be in front of other entities.
Actually, the arrow should be placed after wait is cleared however since it's an entity, you can spawn it anytime and anywhere.
Issue: Since this arrow is an entity, it's spawn location might conflict with walls, obstacles, platforms or holes. To solve that simply set these:
antigravity  100
subject_to_wall  0
subject_to_obstacle 0
subject_to_platform 0
'Antigravity 100' makes entity unaffected by gravity which also prevents it from falling to holes.
subject_to ... 0 commands make entity unaffected by respective object.
Extra: You can omit 'lifespan' to make the arrow live long. It's useful if you want to guide players. It's also useful to show branches so players won't need to look for the latter themselves.
Another effect you can add is sound effect. The default SFX is go.wav in data/sounds folder. You need to remove that .wav file and declare in the arrow text above to make it synch with the animation.
 
Delay

Intro: Delay is simply for delaying spawns or level objects in level text for couple seconds. Why would one want to delay them? well, would it be nice if a boss spawn is delayed until level music completely fades, for example? or enemy spawn is delayed to show some background animations? In normal levels, those are some examples of uses. In pseudo travelling levels such as bike ride and elevator levels, delay is very useful cause those level spawns are only controlled by 'group' instead of scrollposition. Of course, with creativity, more usage could be gained.
Procedure: In order to delay spawns or level objects in level texts, 'group' command is used. However enemy type is required 'group' will count it.
Here's an example of delay entity:
name    delay
health 10
type    enemy
shadow  0
nomove  1

anim idle
@script
    void self = getlocalvar("self");
    int  Health = getentityproperty(self, "health");

    if(frame==1){
      changeentityproperty(self, "health", Health-5);
      if (Health <= 0){
        killentity(self);
      }
    }
@end_script
loop 1
delay 49
offset 1 1
frame data/chars/misc/empty.gif
delay 1
frame data/chars/misc/empty.gif

'Nomove 1' is set to prevent this enemy from using WALK animation forcing this entity in IDLE animation. Shadow is disabled and blank gif is used cause this delay is invisible.
The script in IDLE animation above works like this:
Current health is attained then at 2nd frame, it is deducted 5 units. Notice that it takes 49 centiseconds before playing 2nd frame. After that the animation loops and the cycle repeats. That means, every 0.5 second or half second, delay loses 5 unit health. When health reaches 0, this entity removes itself. The default health is 10, meaning this entity will die on its won after 1 second is passed.
That's how this delay works. Since health can be altered in level texts, we can set delay time to any time we want, for instance, setting health 1200 means 2 minutes delay.

In order to use this, group settings must be set to something like this:
group 1 1
at 0

spawn delay
health 580
coords 160 200
at 0

Any coordinate will do since it's invisible but don't spawn it outside screen and playing area.
With this grouping, the next group of spawns will be held or delayed until this delay entity dies on its own.
Limit: The delay time which can be set with this trick is limited per half seconds so you can't set say 1.2 seconds delay with this. The script and animation must be adjusted for that.
Extra: If combined with enemy's SPAWN animation, you could make cool spawn effect in which group of enemies come one by one instead of all at once. Here's an example:
group  4 4
at 0

spawn TopanS
alias  Topan
flip    1
map    5
coords -60 225
at 0

spawn  delay
coords 150 195
at 0

spawn  delay
coords 150 195
at 0

spawn  delay
coords 150 195
at 0

spawn TopanS
alias  Topan
flip    1
map    5
coords -60 205
at 0

spawn  delay
coords 150 195
at 0

spawn  delay
coords 150 195
at 0

spawn TopanS
alias  Topan
flip    1
map    5
coords -60 185
at 0

spawn  delay
coords 150 195
at 0

spawn TopanS
alias  Topan
flip    1
map    5
coords -60 165
at 0

group  1 1
at 0

In this example, 4 TopanS will come one by one and it's similar to how the archers appear in King of Dragons.
TopanS is striker BTW, read tutorial on how to make Striker for more info about it
 
I tried to modify your script to force a animation change based on the alias but its not working can you tell me where I went wrong please
@script
    void self = getlocalvar("self");
    char Name = getentityproperty(self,"name");

    if(frame == 1){
    changeentityproperty(self, "animation", openborconstant("name"));
    }
@end_script

and the alias is: alias anim_freespecial3
 
It should be:

@script
    void self = getlocalvar("self");
    char Name = getentityproperty(self,"name");

    if(frame == 1){
    changeentityproperty(self, "animation", openborconstant(Name));
    }
@end_script

and the alias should be "ANI_FREESPECIAL3"

Haven't tried myself though.
 
Whoa, I didn't realize that it's almost 2 year since I posted in this thread
Anyways, I have a tip to share

Scrollable Wait

Intro: In Capcom beat'm ups, there are waits which allow players to scroll back a little while beating enemies. Default wait unfortunately doesn't allow scrolling back like that so to make game mechanic like this, we need to use other method which will be described below

Procedure: First of all, level must use direction both setting to allow scrolling back
Then by combining scrollx, group and custom arrow, scrollable wait is made
For instance, we want scrollable wait at 500, here's how to set it:
scrollx 500 600
at 500

# insert enemy or other entity spawns here

group 1 1 # ensures all enemies are defeated before scrollable wait is cleared
at 0

scrollx 500 5000
at 0

spawn  Arrow # this is custom arrow
coords  300 220
at 0

group 100 100
at 0

When scrollx 500 600 is activated at scrollpos 500, player can only scroll screen from scrollpox 500 to 600 as desired from scrollable wait. While 'waiting', enemies or any spawns set before group 1 1 will be spawned and all spawned enemies must be defeated before wait is cleared
After all enemies are defeated, group 1 1 will allow the next command i.e scrollx 500 5000 which allows scrolling from scrollpos 500 to 5000, or we can say that 'wait' is cleared. 5000 is set cause the value is big enough to allow scrolling to end of level. If you want to use exact maximum scrollpos value, simply use this formula:

Value = Level width - Screen length

But if you don't like calculating, just use 5000
This custom 'wait' doesn't show arrow like default wait therefore custom arrow by name of Arrow is spawned right after 'wait' is cleared (read Custom Arrow for further info about it)
group 100 100 is to cancel group 1 1 effect set before or IOW allow more enemies to be spawned in next scrollpos

To set another scrollable wait, just copy example above and set different scrollpos values

Limitation: The above example is only usable in direction both levels. In direction leftright levels, the setting is harder since values for scrollx are measured from leftmost edge while those levels start from rightmost edge
 
Excellent tip, I just needed something like this  :) (and wasn't aware of the scrollx command btw).

O Ilusionista said:
Why the first is set at 500 but the others are set at 0 AFTER the first one?

No particular reason in this case (at least from what I understand), but it is sometimes better & safer in direction both level to set "at 0" (or at least "back") when the player might have gone back in the level during the spawn order sequence processing. For exemple, if you encounter a boss at the end of a level, and while fighting him you end up way back in the level, enemies spawn planned during the fight at the boss initial position will not trigger. Setting "at 0" will make sure a spawn will trigger whereever the player is when it is its "turn" and "time" to spawn.

There are three general elements that restrain spawning :
  • spawn order sequence,
  • space (~ scroll position, "at" command),
  • and time (wait/group commands)
Setting "at 0" for a spawn eliminates space constraint for this spawn.
 
Why the first is set at 500 but the others are set at 0 AFTER the first one?

Easier to type :D
Spawn system in OpenBoR works like this: if current scroll position is larger than defined scrollpos AND latest group allows it, spawn or run the command
Therefore, I don't have to retype 500 or anything again to spawn anything in that scroll position

It's also my technique to define grouping which is easier for me to view. For instance:
spawn Enemy
coords ...
at 600

spawn Enemy
coords ...
at 0

spawn Enemy
coords ...
at 800

spawn Enemy
coords ...
at 0

spawn Enemy
coords ...
at 0

In this example, I can see that at scroll position 600, there will be 2 enemies spawned while at 800, there will be 3
 
Phew the dust is really thick here!  :D
Anyways, I have two tricks to be shared

Disabling Enemy's/NPC's Attack Efficiently

Intro: Creating attack animation for enemy or NPC is fun thing to do. Usually, the animation needs to be tested to see how it plays to ensure it is balanced and fits the design.
Testing single attack animation is straightforward, however testing multiple attack animations isn't always like that especially if they have overlapping attack range. In case of overlapping attack range, due to how attack animation is chosen by them, ATTACK1 is more likely to be chosen than ATTACK2, ATTACK2 is more than ATTACK3 and so on
Disabling ATTACK1 and other attack animations is best way to force enemy or NPC to choose certain attack to be tested. However, disabling an animation requires typing # before each line. This method is tedious if the animation has many frames and command lines
This trick will show a very easy way to disable attack without typing # at all
Procedure: An example of two attack animations from bear enemy:
anim attack1
range 20 100
delay 9
offset 130 140
bbox 61 60 115 80
hitflash slash
hitfx data/sounds/Slash1.wav
sound data/sounds/bearRise.wav
frame data/chars/bear/stand1.png
bbox 52 38 78 102
frame data/chars/bear/stand2.png
frame data/chars/bear/stand3.png
frame data/chars/bear/stand4.png
delay 20
sound data/sounds/bearAttack.wav
frame data/chars/bear/stand5.png
delay 8
frame data/chars/bear/stand6.png
bbox 61 60 115 80
attack  160 46 70 72 30 1 0 0 30
frame data/chars/bear/stand7.png
delay 10
attack  0
frame data/chars/bear/stand1.png

anim attack2
range 50 100
delay 20
offset 130 140
bbox 60 80 143 60
hitflash slash
hitfx data/sounds/Slash1.wav
frame data/chars/bear/bite1.png
delay 30
attack  190 90 45 20 15 0 0 0 30
frame data/chars/bear/bite2.png
delay 20
attack  0
frame data/chars/bear/bite1.png

Say we want to test ATTACK2 so ATTACK1 needs to be disabled. To disable it, simply change its range to range 20 -100 like this:
anim attack1
range 20 -100
delay 9
offset 130 140
bbox 61 60 115 80
hitflash slash
hitfx data/sounds/Slash1.wav
sound data/sounds/bearRise.wav
frame data/chars/bear/stand1.png
bbox 52 38 78 102
frame data/chars/bear/stand2.png
frame data/chars/bear/stand3.png
frame data/chars/bear/stand4.png
delay 20
sound data/sounds/bearAttack.wav
frame data/chars/bear/stand5.png
delay 8
frame data/chars/bear/stand6.png
bbox 61 60 115 80
attack  160 46 70 72 30 1 0 0 30
frame data/chars/bear/stand7.png
delay 10
attack  0
frame data/chars/bear/stand1.png

Range 20 -100 is impossible range cause it's impossible for opponent to be within minimum range of 20 pixels and maximum range of -100 pixels. The effect of this is the attack won't be played at all and thus disabling the attack ;)


Super Blocking Enemy/NPC

Intro: Enemy with high chance of blocking is annoying however for design purpose e.g boss, this kind of enemy must be created. OTOH tough NPC with high chance of blocking is needed either to support player or for story purpose
This tutorial will describe how to give enemy/NPC high chance of blocking
Procedure: Since the enemy/NPC can block, obviously BLOCK animation + blockodds setting is a must and it won't be described here
Then to increase the blocking chance, set this in enemy's/NPC's header:
nopassiveblock 1

this command will make enemy/NPC block before opponent's attack connects
Then set range in BLOCK animation like this:
anim block
range 0 400
rangez -25 25
...

this range setting will define how far opponent could be before enemy/NPC blocks. In this example, the range is wide (covering z axis as well) and will allow enemy/NPC to block attacks coming from within 0 to 400 pixels range in x axis and -25 to 25 pixels in z axis
Limitation: Even though the blocking chance is high, there is a small chance for enemy/NPC not to block
Also, enemy/NPC can't block and attack same time so if the enemy/NPC has attack animation whose range is withing block range, the enemy/NPC might perform the attack instead of blocking
That's why this high block setting is best combined with long range attacks so enemy/NPC attacks from distance and blocks close range attacks
 
More dusts to be cleared but more tricks to be shared here :D

DEATH by throw

Intro: DEATH animation is a cool way to show the death of any entity in OpenBoR. However if entity dies from being thrown, DEATH animation won't be played at all :(
This trick will show how to solve this problem
Procedure: When entity or character is thrown, he/she/it is playing FALL animation. So find that animation and add this script to make it like this:

anim fall
@script
  if( frame == 1 ){
    void self = getlocalvar("self");
    int Health = getentityproperty(self, "health");
    int Land = getentityproperty(self, "damage_on_landing");

    changeentityproperty(self, "damage_on_landing", 0);

    if( Health > Land ){ 
      changeentityproperty(self, "health", Health-Land);
    } else if( Health <= Land ){
      damageentity(self, self, 20, 1, openborconstant("ATK_NORMAL"));
    }
  }
@end_script
delay  500
        landframe 1
offset 55 110
attack  15 60 52 30 5 1
frame data/chars/jimo/fall1.png
delay  30
attack  0
frame data/chars/jimo/fall2.png

In this example, Jimo will have its health reduced like normal upon landing after being thrown. However, when the landing damage is higher than its current health, the script will damage it to force it play DEATH animation
Jimo has DEATH animation of course
This script also works if character is knocked away by attack with damageonlanding FX

Expansion: If the character has another FALL animation for being thrown animation, just apply same script to that FALL animation and change the attack type to correct one like this:

anim fall2
@script
  void self = getlocalvar("self");

  if( frame == 1 ){
    changeentityproperty(self, "damage_on_landing", 0);
  } else if( frame == 3 ){
    int Land = getentityproperty(self, "damage_on_landing");
    int Health = getentityproperty(self, "health");

    if( Health > Land ){ 
      changeentityproperty(self, "health", Health-Land);
    } else if( Health <= Land ){
      damageentity(self, self, 20, 1, openborconstant("ATK_NORMAL2"));
    }
  }
@end_script
        landframe 2
        delay  30
offset 68 69
attack  58 44 34 47 5 1
frame data/chars/jimo/thrown.png
        delay  400
offset 55 110
attack  15 60 52 30 5 1
frame  data/chars/jimo/fall1.png
attack  0
delay  5
frame data/chars/jimo/fall2.png
delay  10
frame data/chars/jimo/fall2.png

In this example, Jimo will play DEATH2 if the throw kills it



Dummy level

Intro: Dummy level is technically a level but it's played or rather ended very quickly as if it's not even there. This level can be used for tricks such as Unsaveable Alternate Endings below or character specific branches

Procedure: Create the level like this:

background data/bgs/generic/black.png
panel data/bgs/generic/black.png
fglayer data/bgs/generic/black.png 300 0 0 0 0 0 0 -1 1 1
order         a
settime 0
nofadeout 1
type 2 0 0


spawn delay
@script
void main()
{
    jumptobranch("Lanjut",1);
}
@end_script
coords 480 500
at 0

Black.png is a black colored image whose size is the same size as mod's resolution
When this level is played, it will immediately end without fading out and play the next level or scene



Unsaveable Alternate Endings

Intro: Having alternate branches with its own ending is great thing. However due to how autosave works which saves the game even after an end, player can load the saved game and continue from the level right
after that end causing glitch
This trick will describe how to prevent this
An example of mod using this trick is Die Fuhrer Die which can be downloaded here:

http://www.chronocrash.com/forum/index.php?topic=3377.0

Procedure: First this trick requires update.c and the latter must be run while a scene is played. In order to allow that, script.txt placed together with models.txt and levels.txt must have alwaysupdate 1. If there isn't any script.txt then make one

Next, make an update.c like this:

Code:
void main()
{
    void scene = openborvariant("current_scene");

    if(scene=="data/scenes/escape.txt"){
      jumptobranch("Akhir",0);
    }
}

If there's already an update.c, then add those lines there
This script works by finding a scene whose path is data/scenes/escape.txt then alters the next branch to "Akhir" if it finds one. That's the example taken from Die Fuhrer Die mod, if you have other final scene then rename that line to that scene
Here's a quote of levels from Die Fuhrer Die mod:

...
z 220 250 160
file data/levels/uboot2.txt
file data/levels/uboot.txt
scene data/scenes/escape.txt
end
#######
branch ex1
z 200 260 200
file data/levels/cave.txt
scene data/scenes/noescape.txt
branch Akhir
file data/levels/akhir.txt

As you can see, escape.txt is the final scene played before end of main branch. The above update.c will bring to branch Akhir at end of levels to ensure that after the scene is played, it will play last level and thus ending the game
Akhir is a dummy level (see above trick) which will be played real quick
With all of these set, when player ends the game from main branch, escape.txt scene will be played then player will be taken to branch Akhir. Since akhir.txt is the last level, loading saved game will simply end the game

Expansion: This update.c can also be expanded other purposes such as playing certain scene after getting two artifacts OR play character specific scene based on currently chosen character
 
Bloodbane, you can simplify the landing death a bit, because landing has its own damage type: ATK_LAND.

There are also ATK_PIT, ATK_LIFESPAN, and ATK_TIMEOVER types. Previously these all used the default normal attack type, but I separated them to make these kinds of scripts and offense/defense set ups easier to make without conflicts.

There are no associated death animations, but you can use the attack type to take action accordingly.

DC
 
I have a question regarding scrollx with the use of direction leftright. Could we have the stage scrollable with that direction similar to directions both and rightleft? Could it be set with scrolling in 100 pixels for moving to the left like this?

scrollx 400 500, scrollx 500 400, or scroll -500 -400

I can be wrong with those values, but I'm curious how a scrollable wait for moving left is set.


Procedure: First of all, level must use direction both setting to allow scrolling back

Darn. This means it's only used for direction both? If no can do, then the answer would be using script with OpenBOR variants (scrollminx and scrollmaxx). Though I do not know how scrollminX and scrollmaxX work, I think they would useful for direction leftright since scrollx is capable for direction both.

EDIT 2: Is there such script for making the camera scrollable if direction leftright is used? Making a fake entity with camera script for scrollable wait could help?
 
Last edited:
Well, scrollx can be used in direction right (default) levels to limit how far player could scroll to the right. Useful if you have one long background panel to be used by multiple levels but don't want to split that panel and want to divide the panel in certain division for each level.

I think they would useful for direction leftright since scrollx is capable for direction both.

So are you using scrollx for direction leftright level?

Is there such script for making the camera scrollable if direction leftright is used?

Uhh... I don't understand why you would do that.
 
Back
Top Bottom