Projectile

Projectile post thumbnail image

Please note: Projectile system is incomplete and set for depreciation in favor of a generalized sub entity system. Use the following at your own risk.

Overview

“Hadouken!”

Projectiles are generally entities spawned and thrown by another entity to cause damage from a distance. Ryu’s classic Hadouken is perhaps the most iconic, but projectiles can take virtually any form depending on your game design. OpenBOR supports two main projectile types: Knives – standard projectiles thrown straight forward, and Bombs – grenade like projectiles tossed in an arc with an optional explosion effect. Each include a wide array of settings. If the native projectile functions still aren’t enough, projectiles are tightly integrated with OpenBOR’s scripting engine allowing an infinite range of functionalities.

Assuming defaults, projectiles exhibit the following behaviors. It’s a good idea to familiarize yourself with them before you attempt to create more customized projectiles.

Knives

Knives are OpenBOR’s standard projectile method, useful for most forms of ranged attack.

  • Fly straight and are not affected by gravity.
  • Apply the projectile velocity setting (see below, default X = 2, X = 0, Z = 0). When moving the projectile model’s speed setting controls velocity.
  • Take on faction data (who they can hit and who they are hostile to) form parent/owner.
  • Can’t hit other projectiles.
  • Are subject to walls and platforms.
  • Automatically destroyed if they pass more than half a screen out of view. Ex: If horizontal resolution is 320, any knife passing more than 160 pixels out of screen terminates.

Bombs

Bombs simulate a lobbed or timed delay ranged attack. They operate identically to knives with the following exceptions:

  • Thrown in an arc determined by projectile model’s jump height. Affected by gravity.
  • Apply the projectile velocity setting (see below, default X = 2, Y = projectile model jump height, Z = 0). When moving the projectile model’s X, and Z speed setting controls velocity. Y is used for initial vertical toss velocity.
  • If a bomb touches ground without hitting a target, it will play its ATTACK1 animation if available.
  • If a bomb hits any eligible target or gets hit by any attack, it will play its ATTACK2 animation if available.
  • After a bomb hits or lands and current animation is complete (which animation doesn’t matter), the bomb disappears.

Getting Started

Before going any further, note there are a lot of legacy options and behaviors associated with projectiles. These are in place for backward compatibility, but are otherwise depreciated. It is highly recommended you ignore them and stick to the options in this guide to avoid confusion and unexpected results.

Step 1 – The Projectile Model

You need a projectile to throw first. Projectiles are entities just like players and enemies, so you need to create a model text file for them the same way. The difference is projectiles are usually much simpler. For a basic projectile all you really need is an idle animation with an attack box. Make the model’s type Projectile. Here is an example:

name         ryu_hadouken
type	     projectile
health	     1
alpha	     1

palette	data/chars/ryu/hadouken/idle_0.png

anim idle

	loop	1
	delay	5
	offset	75 56

	attack.damage.force 12
	attack.position.x 59
	attack.position.y 41
	attack.size.x 21
	attack.size.y 29
	attack.reaction.reposition.direction -1
	   	
	frame	data/chars/ryu/hadouken/idle_0.png	
	frame	data/chars/ryu/hadouken/idle_1.png
	frame	data/chars/ryu/hadouken/idle_2.png
	frame	data/chars/ryu/hadouken/idle_3.png
	frame	data/chars/ryu/hadouken/idle_4.png
	frame	data/chars/ryu/hadouken/idle_5.png
	frame	data/chars/ryu/hadouken/idle_6.png
	frame	data/chars/ryu/hadouken/idle_7.png
	frame	data/chars/ryu/hadouken/idle_8.png
	frame	data/chars/ryu/hadouken/idle_9.png

Step 2 – Knowing Is Half The Battle

We have a model ready to go, but it must be loaded into memory before we can use it. There are a several ways to do this, but the most recommended is know in models.txt and then load in any model that uses the projectile. This tells OpenBOR to only load the projectile when the model that uses it loads. Here is what the know and load commands might look like:

...
know	ryu_hadouken		data/chars/ryu/hadouken/ryu_hadouken.txt     # Haoudken projectile model.
know	Ryu_e			data/chars/ryu/ryu_e.txt                     # Ryu (enemy).
load 	Ryu			data/chars/ryu/ryu.txt                       # Ryu (player).
...

Then in both the enemy and player Ryu (or any other model who might use the Hadouken) model files, we add this line somewhere in the header:
...
load ryu_haoudken
...

Behind The Curtain: In almost all cases player controlled models are loaded at all times, and that’s the case in our example too. Consequently, the ryu_haoudken model is always loaded too. But if we only had the enemy Ryu, the ryu_haoudken projectile wouldn’t load unless the player was in a level that spawned the enemy Ryu, thus saving memory. Either way it’s usually best practice using know for projectiles and sub entities.

Step 3 – Launch!

All that remains is to throw the projectile. Since we are building a straight forward Hadouken, we will use the knife command. This has two mandatory parts, both in the animation you want to throw your projectile with. The first is model declaration, custknife <model name> (short for “custom knife”). This tells OpenBOR which model projectile model you want to throw. Any model currently loaded is fair game. The second part is the frame declaration, throwframe <frame number>. This tells OpenBOR which frame of the animation to spawn the projectile. Here’s what the animation looks like with knife commands.

anim Freespecial10 # Hadouken
	
	custknife ryu_hadouken
	throwframe 4
		
	delay	5
	offset	82 147
	
	bbox.position.x 66
	bbox.position.y 49
	bbox.size.x 38
	bbox.size.y 98

	frame	data/chars/ryu/hadouken_0.png
	frame	data/chars/ryu/hadouken_1.png
	frame	data/chars/ryu/hadouken_2.png
	
	bbox.position.x 78
	bbox.position.y 51
	bbox.size.x 43
	bbox.size.y 95
	
	frame	data/chars/ryu/hadouken_3.png
	
	delay 6
	
	bbox.position.x 87
	bbox.position.y 60
	bbox.size.x 53
	bbox.size.y 85
	
	frame	data/chars/ryu/hadouken_4.png
	frame	data/chars/ryu/hadouken_5.png
	frame	data/chars/ryu/hadouken_6.png
	frame	data/chars/ryu/hadouken_7.png
	frame	data/chars/ryu/hadouken_8.png
	
	bbox.position.x 81
	bbox.position.y 58
	bbox.size.x 44
	bbox.size.y 89
	
	frame	data/chars/ryu/hadouken_9.png
	
	bbox.position.x 78
	bbox.position.y 50
	bbox.size.x 37
	bbox.size.y 98
	
	frame	data/chars/ryu/hadouken_10.png
	
	bbox.position.x 71
	bbox.position.y 48
	bbox.size.x 38
	bbox.size.y 103
	
	frame	data/chars/ryu/hadouken_11.png

When this animation reaches frame 4 (remember frames are 0 indexed), the model ryu_haoduken spawns and flies forward.

Step 4 – Extra Credit

To keep the example simple we didn’t bother with any extra setup or adjustments. That means our example “Haoduken” will mostly follow default knife behaviors. Chances are you will want to modify these behaviors. See below for all the various options available. For even more versatility, try out some script. For instance, you are normally limited to throwing one projectile of each type per animation, but you can use script functions to throw dozens or more on a single frame.

Commands

custbomb <model name>

Model to spawn and launch with tossframe. This is the most recent and recommended native method to set a model for bomb style projectile spawns.

custknife <model name>

Model to spawn and launch with throwframe. This is the most recent and recommended native method to set a model for knife style projectile spawns.

projectile_color_set_adjust <adjust type>

Adjustment (if any) to projectile’s color set (palette).

  • none (default) – No adjustment. Projectile uses its default palette.
  • parent_index – Use same palette index as parent. Ex: If parent is using palette index 2, projectile uses its palette index 2 (if available).
  • parent_table – Projectile assumes parent’s current color table. This is useful when projectile and parent sprites share the same color table. The projectile will match parent’s colors without the need for its own set of alternate palettes.

projectile_direction_adjust <direction>

Adjustment (if any) to projectile’s direction.

  • left – Projectile faces left.
  • none – No adjustment. Projectile assumes default spawn direction.
  • opposite – Projectile faces opposite direction as parent.
  • right – Projectile faces right.
  • same (default) – Projectile faces same direction as its parent.

projectile_offense <source>

Where projectile derives its offense factors.

  • parent – Copy parent’s offense on spawn.
  • self (default) – Use projectile’s own offense.

projectile_position_x <position>

X axis offset (default 0) from parent entity position to spawn projectile. Positive values adjust toward direction parent is facing, negative values adjust away.

projectile_position_y <position>

Y axis offset (default 70) from parent entity position to spawn projectile. Note throwframe and tossframe have legacy Y offset parameters. When either is used in conjunction with this command, whichever comes later in order will take precedence.

projectile_position_z <position>

Z axis offset (default 0) from parent entity position to spawn projectile.

projectile_velocity_x <velocity>

X axis speed (default 1.0). When projectile is thrown, its speed X value is overwritten with this setting.

projectile_velocity_y <velocity>

Y axis speed. Behavior varies if spawned as bomb or knife.

  • Bomb (tossframe) – Applied as a toss velocity, same principal as jumping or knockdowns. For legacy compatibility, this command must appear after tossframe. Otherwise legacy default behavior applies, and toss velocity is the projectile model’s jumpheight.
  • Knife (throwframe) – Same as projectile_velocity_x, for Y axis. Default: 0.

projectile_velocity_z <velocity>

Same as projectile_velocity_x, for Z axis. Default 0.

throwframe <frame> <Offset Y>

When animation reaches frame, selected projectile model spawns and fires as knife at Y offset. For backward compatibility the selected model may come from one of several sources.

From highest to lowest priority:

  1. Custknife (recommended)
  2. Custpshotno
  3. Project
  4. Knife
  5. Playshotno
  6. Any loaded model named “Knife”.
  7. Any loaded model named “Shot”.

tossframe <frame> <Offset Y>

When animation reaches frame, selected projectile model spawns and fires as bomb at Y offset. For backward compatibility the selected model may come from one of several sources.

From highest to lowest priority:

  1. Custbomb (recommended)
  2. Project
  3. Bomb

Legacy

Legacy commands are depreciated and included for backward compatibility only. Use at your own risk. See description for replacement method.

NameLevelDescription
custpbomb <model name>AnimationSame as custbomb.

Replacement: Ignore and use Custbomb.
custpshotno <model name>AnimationShort for “custom player shot nomove”. Model to spawn and launch with throwframe. The intended behavior is model launches and stays in place.

Replacement: Use Custknife and projectile_velocity settings of 0.
Knife <model name>ModelModel to spawn and launch with throwframe. Applies to all animations in model, method used before ability to select projectile models on a per-animation basis added.

Replacement: Use Custknife in the model’s animation.
Project <model name>ModelModel to spawn and launch with throwframe. Only applies if used as part of a weapon model. Intended as a quick means of supplanting a model level projectile.

Replacement: Use Custknife in the weapon model’s animation.

Script

Projectile properties are accessible through the get_projectile_property() and set_projectile_property() functions. You will need the projectile pointer first. Typically you will get this from an animation.

Use Cases

Get a property value. Properties and their behavior can vary wildly – see the property list for details.

mixed x = get_projectile_property(void <projectile handle>, char <identifier>); 

Modify a property value. Some properties are read only – see the property list for details.

mixed x = <value>;

set_projectile_property(void <projectile handle>, char <identifier>, x); 

List

  • Name: The identifier used to access property through script.
  • Type: The property value’s variable type.
  • Description: A short description of what the property is and does.
NameTypeDescription
color_set_adjustIntegerSource for projectile’s color settings on spawn.

* openborconstant("COLOR_SET_ADJUST_NONE") – No color change. The projectile spawns with its default palette.

* openborconstant("COLOR_SET_ADJUST_PARENT_INDEX") – Projectile spawns with same palette index as parent.

* openborconstant("COLOR_SET_ADJUST_PARENT_TABLE") – Projectile spawns with same palette as parent.
direction_adjustIntegerDirection applied to projectile on spawn.

* openborconstant("DIRECTION_ADJUST_NONE") – No direction adjustment.

* openborconstant("DIRECTION_ADJUST_SAME") – Parent’s current direction.

* openborconstant("DIRECTION_ADJUST_OPPOSITE") – Opposite parent’s current direction.

* openborconstant("DIRECTION_ADJUST_RIGHT") – Face right.

* openborconstant("DIRECTION_ADJUST_LEFT") – Face Left.
frame_shootIntegerUpon reaching this frame, OpenBOR attempts to locate a model index from the sources listed here (highest to lowest priority). If a valid model index is found, it is spawned and launched as a projectile entity.

* Project property from a weapon model.

* Knife model property.

* model_index_flash.

* model_index_knife.

* Pshot model property.

* Global Shot (attempts to find a model in the database named “Shot”).

* Global Knife (attempts to find a model in the database named “Knife”).
frame_throwIntegerLegacy star projectile throw. Upon reaching this frame, OpenBOR attempts to locate a model index from the sources listed here. Repeat attempts of the same source are not typos – this is part of the legacy logic to maintain backward compatibility.

* model_index_flash.

* model_index_knife.

* projectile star.

Entity is jumping…

* Project property from a weapon model.

* Animation model_index_star.

* Star model property.

* Global Star (attempts to find a model in the database named “Star”).

* Project property from a weapon model.

* Knife model property.

* model_index_flash.

* model_index_knife.

* Pshot model property.

* Global Shot (attempts to find a model in the database named “Shot”).

* Global Knife (attempts to find a model in the database named “Knife”).

Entity not jumping…

* Project property from a weapon model.

* Knife model property.

* model_index_flash.

* model_index_knife.

* Pshot model property.

* Global Shot (attempts to find a model in the database named “Shot”).

* Global Knife (attempts to find a model in the database named “Knife”).

* Project property from a weapon model.

* projectile star.

* Star model property.

* Global Star (attempts to find a model in the database named “Star”).
frame_tossIntegerUpon reaching this frame, OpenBOR attempts to locate a model index from the sources listed here (highest to lowest priority). If a valid model index is found, it is spawned and launched as a bomb entity.

* Project property from a weapon model.

* model_index_bomb.

* Bomb model property.
model_index_bombIntegerModel index for bomb spawns by frame_toss.
model_index_flashIntegerModel index for projectile spawns by frame_shoot. If this model index is used, the projectile does not move after spawning.
model_index_knifeIntegerModel index for projectile spawns by frame_shoot.
model_index_starIntegerModel index for projectile spawns by frame_throw. When spawned as a star during jumps, three projectiles are launched at diagonal angles downward.
offenseIntegerSource for projectile’s offense settings. Note these are only applied at point of spawn.

* openborconstant("PROJECTILE_OFFENSE_PARENT") – Use parent’s current offense.

* openborconstant("PROJECTILE_OFFENSE_SELF") – Use projectile model’s offense.
placementIntegerAnchor position for spawn offset. Currently projectile spawns always use the parent location – the logic for this property is not implemented yet and does nothing.

* openborconstant("SUB_ENTITY_PLACEMENT_PARENT") – Parent.

* openborconstant("SUB_ENTITY_PLACEMENT_SCREEN") – Visible screen.

* openborconstant("SUB_ENTITY_PLACEMENT_ABSOLUTE") – Current level.
position_xIntegerX axis offset from parent (entity that throws projectile) position to spawn projectile. Offset is relative to parent’s facing. Positive values adjust position ahead of entity, negative values adjust behind.
position_yIntegerY axis offset from parent position to spawn projectile. Positive values adjust position above entity, negative values adjust below.
position_zIntegerZ axis offset from parent position to spawn projectile. Positive values adjust position toward player view, negative values adjust into screen.

Related Post