DC's Object Core Library - Vol I: Damage

DCurrent

Site Owner, OpenBOR Project Leader
Staff member
DC's Object Core Library - Vol I: Damage

DC's Object Core Library is an effort to bring some of the benefits of object oriented programing to the OpenBOR script engine. Although it is technically impossible to define a true object through OpenBOR script, careful structuring of functions into methods properties allows us to closely simulate OOP behavior.

  • Encapsulation
  • Re-usability
  • Forward compatibility
  • Simplicity
  • Expandability

The DC Damage Library coves a fundamental building block; damaging entities. After all, there is little use in say, a bind/grappling system without a way to apply damage. It is very important to not only damage entities using the engine's built in damage system, but to do so in a controlled way. You will find this system allows you near infinite combinations of settings to cover almost any damage needs.

License

This library is released under license seen here.

Installation

[list type=decimal]
[*]Download and unzip the library.
[*]Place dc_damage folder into your scripts folder.
  • You can always put it elsewhere, but if you do, you'll need to modify all the #include and #imports accordingly.


[*]Add the line #include "data/scripts/dc_damage/main.c" to any scripts you'd like to use damage objects in, and you're ready to go.
[/list]


Use

In its most basic form, there are exactly three steps once you've installed the DC Damage Object.

[list type=decimal]
[*]Initialize an object. To do that, call dc_damage_create_object(<index>). The <index> is a required integer value of your choosing. You can have as many damage objects as you like, the <index> identifies which is which. Once initialized an object can used by any script that you installed the library to.
[*]Now you need to define a target to damage. That's easy too; call dc_damage_set_target(<index>, <entity>) and make <entity> whatever entity you want to damage.
[*]Now all you need to do is call damage_execute(<index>) and your target gets nailed!
[/list]

Code:
frame chars/dude/sprite1.png
    @cmd dc_damage_create_object 0 #Let's create an object with index of 0.
    @cmd dc_damage_create_object 0 findtarget(getlocalvar("self")) #Set the target to be the nearest enemy.
frame chars/dude/sprite2.png
frame chars/dude/sprite3.png

Code:
frame chars/dude/sprite20.png
     @cmd dc_damage_execute 0 #Apply damage the target of damage object 0.
frame chars/dude/sprite22.png

Now here's where it gets interesting. If you do nothing else but the three steps above, you get a simple knockdown with 0 damage. Not all that exciting. But that's because you applied damage without setting any properties other than the target. So now you'll want to work with the other properties to crate different effects. The amount of force, knockdown, how far, which direction, and so on are all adjustable on the fly. Just call the relevant mutator function (see below for list) with the index and you desired value. Only worry about the properties you need to - the rest have defaults (you can change these defaults if you like, see Advanced Use). There's even a set of constants provided to help you along.

Damage a target, change some settings, damage it again. Multiple objects can be used all it once, it really doesn't matter.

Action Methods

These methods are used to execute basic actions.

  • void damage_create_object(int index): Create a damage object identified by <index> and populate with default values. Object is then ready to use, but you will need to set a target before applying damage.

  • void damage_destroy_object(int index): Destroy the object and free up resources.

  • void damage_execute(int index): Apply damage effects to target. You must first set a target. If there is no target set, an alert will be sent to the log and no further action will be taken.
  • void damage_ dump_object(int index): Send all object properties to the log.
  • void damage_import_object(int index, void object): Import all properties from a another damage object to <index>. Will create new object or overwrite existing as needed.

Access Methods

Get object properties and status values. Unless noted otherwise, see the corresponding mutate method descriptions for property details.

  • void entity = damage_get_attacker(int index): Get the damaging entity.
  • int atk = damage_get_attacking(int index): Get attacking property.
  • int dir = damage_get_direction_adjustment(int index): Get direction adjustment property.
  • int dol = damage_get_dol_force(int index): Get damage on landing force property.
  • int drop = damage_get_drop(int index): Get drop power property.
  • int force = damage_get_force(int index): Get force property.
  • int force = damage_get_force_mitigated(int index): Get the damage target would receive after its defense and attacker’s offense are applied.
  • int force = damage_get_force_final(int index): Get force that target will receive after all damage mitigation and object settings are applied.
  • int min = damage_get_hp_cap_min(int index): Get target HP cap minimum property.
  • void obj = damage_get_object(int index): Get object array. Useful to copy object or save into global for game persistence.
  • int proj = damage_get_projectile(int index): Get projectile property.
  • int type = damage_get_type(int index): Get attack type property.
  • int flip = damage_get_velocity_flip_x(int index): Get X velocity flipping property.
  • float X = damage_get_velocity_x(int index): Get X drop velocity.
  • float Y = damage_get_velocity_y(int index): Get Y drop velocity.
  • float Z = damage_get_velocity_z(int index): Get Z drop velocity.

Mutate Methods

Establish and change object properties.

  • void damage_set_attacker(int index, void value = NULL()): Set entity that will cause damage and receive credit for doing so. If no attacker is set when damage is applied, the target itself will be considered the attacker.
  • void damage_set_attacking(int index, int value = DC_DAMAGE_FALSE): Toggle the target’s attacking flag when damage is applied. Combine with projectile to create a blast effect. Uses general Boolean constants:
    • DC_DAMAGE_TRUE: Target’s attacking flag will be turned on.
    • DC_DAMAGE_FALSE: Target’s attacking flag will be turned off.

  • void damage_set_direction_adjustment(int index, int value = DC_DAMAGE_DIR_ADJ_OPP): Determines how target’s direction will be adjusted when damage is applied. Use with following constants:
    • DC_DAMAGE_DIR_ADJ_LEFT: Target will always face left.
    • DC_DAMAGE_DIR_ADJ_OPP: Target will always face opposite direction of attacker.
    • DC_DAMAGE_DIR_ADJ_NONE: Target’s facing will not be adjusted.
    • DC_DAMAGE_DIR_ADJ_SAME: Target will always face same direction as attacker.
    • DC_DAMAGE_DIR_ADJ_SAME: Target will always face right.

  • void damage_set_dol_force(int index, int value = 0): Damage target will receive upon landing from fall. May be mitigated by target's defenses or ability to land.
  • void damage_set_drop(int index, int value = 1): Drop (knockdown) power that will be applied to target with damage.
  • void damage_set_type(int index, int value = openborconstant("ATK_NORMAL")): Type of damage that will be applied to target.
  • void damage_set_force(int index, float value = 0): Quantity of damage that will be applied to target. Float types are only accepted for future expansion. The engine will truncate any decimal value when damage is applied.
  • void damage_set_hp_cap_min(int index, int value = 0): Target's minimum allowed hitpoints after damage is applied. If after mitigated force will drop target's HP to at or below <min>, applied force will be adjusted as necessary to allow target's HP to stay at minimum.
  • void damage_set_projectile(int index, int value = DC_DAMAGE_FALSE): Toogle target's projectile flag when damage is applied.
    • DC_DAMAGE_TRUE: Target's projectile flag is turned on.
    • DC_DAMAGE_FALSE: Target's projectile flag is turned off

  • void damage_set_target(int index, void value = NULL()): Set target entity to damage. You must set a target before applying damage.
  • void damage_set_velocity_flip_x(int index, float value = DC_DAMAGE_VEL_FLIP_X_AWAY): Toggle mirroring of X drop velocity when damage is applied.
    • DC_DAMAGE_VEL_FLIP_X_AWAY: Always send target away from attacker.
    • DC_DAMAGE_VEL_FLIP_X_OPP_ATK: Always send target opposite direction of attacker's facing.
    • DC_DAMAGE_VEL_FLIP_X_OPP_TARGET: Always send target opposite its own facing.
    • DC_DAMAGE_VEL_FLIP_X_NONE: Apply X drop velocity as is.
    • DC_DAMAGE_VEL_FLIP_X_SAME_ATK: Always send target same direction of attacker's facing.
    • DC_DAMAGE_VEL_FLIP_X_SAME_TARGET: Always send target same direction as its own facing.
    • DC_DAMAGE_VEL_FLIP_X_TOWARD: Always send target toward attacker.
  • void damage_set_velocity_x(int index, float value = 1.2): X axis velocity applied to target on knockdown.
  • void damage_set_velocity_y(int index, float value = 3): Y axis velocity applied to target on knockdown.
  • void damage_set_velocity_z(int index, float value = 0): Z axis velocity applied to target on knockdown.

Advanced Use

  • Efficiency notes:
    • The installation #include is merely to start a file chain of #imports. The only items truly being #included are constants.
    • Objects are actually arrays stored as an index var. Therefore each defined object requires only one indexed var.
  • Because the library is written to behave like an object, it can be easily extended like an object class. Add your own goodies, just make sure to follow the interface rules for forward compatibility and try not to get carried away. Remember this is an "object" and should remain specialized. Things like flash spawns, sound effects and such are the purview of other object libraries (which will be coming soon).
  • Settings.h allows readjusting of object behavior as needed.
    • Array keys
    • Indexed var keys
    • Default properties


To Do

  • Clean up some of the calculation formulas. A few of them are pretty crude.
  • % based damage option.
  • Maximum option for HP cap.
  • Min/max damage caps.
  • No reflect option (currently not available in OpenBOR script).
 
Working on Vol II, sounds. This will be a rewrite of my Soun0005 function. Obviously all the current functionality (on screen location based stereo, randomizing, categorized auto cataloging, etc.) will be retained.

Also, nothing at all to say guys? I can hear the crickets chirping, lol.

DC
 
Yes, but that's not part of my library. findtarget({ent}, {ani}) is an OpenBOR script function. It returns the first hostile entity. {ani} is optional. If used then then the target search is limited to that animation's range.

The library function is just dc_damage_set_target({index}, {ent}). I was merely providing an example of how you would set a target.

DC
 
I like the thinking behind this library so far with the objects and all, it's one of the things that script lacked and would be a better primer for the upcoming engine am I right?

The problem now is, no offense, without a concrete thing to demonstrate it, i don't think people would see something of significance. I could make something out of it though, a demonstration gig that would help people understand what OOP can do. Problem now is what could be something that it could demonstrate?

I believe in this though, especially if it would be applied in grabs and throws, which with the OOP's  capabilities, it would be much easier as to assign the entity grappled by player, what its new x and y values are and etc.

Edit: BTW, i did notice the thing here:
Damon Caskey said:
The DC Damage Library coves a fundamental building block; damaging entities. After all, there is little use in say, a bind/grappling system without a way to apply damage.

How about if the OOP grapple system would have a relationship with the OOP damage library, since what a grapple script do is just assist in binding while the damage script does the damage that the grapple can concur. I don't know if my opinion made sense DC, i hope it does.
 
CRxTRDude said:
The problem now is, no offense, without a concrete thing to demonstrate it, i don't think people would see something of significance. I could make something out of it though, a demonstration gig that would help people understand what OOP can do. Problem now is what could be something that it could demonstrate?

None taken because I already thought of this. I've been using Pierwolf's Double Dragon Gold as a test bed. It's perfect for the job. Well put together, loads fast, and has no preexisting script that might interfere.

The problem is it's also way too big and elaborate to work as a demonstrator. Plus, Pierwolf might not like me using his module like that. The best thing to do would probably be to take the original BOR and strip it down - One music track, one PC, one enemy, and a single small area.

I believe in this though, especially if it would be applied in grabs and throws, which with the OOP's  capabilities, it would be much easier as to assign the entity grappled by player, what its new x and y values are and etc.

It's not just about grappling - but yeah, damage application is a big part of any grapple system.

How about if the OOP grapple system would have a relationship with the OOP damage library, since what a grapple script do is just assist in binding while the damage script does the damage that the grapple can concur. I don't know if my opinion made sense DC, i hope it does.

It does, but part of OOP is encapsulation. Each has a specific job to do, and I want to avoid code dependency so that each can be used on its own. Normally in a situation like this you'd apply a technique called injected dependency, but that's not an option here. Don't worry though, I'll still have you covered. You'll just have to see how it all comes together when the other libraries are released.

DC
 
Thanks for understanding DC, apparently you're right, we can't say for sure what will happen until all libs are released for sure, it's hard to say things on just one part of the machine anyway.  ;)

I also think of what you said as well, reminds me of what I did at the story system, one hero, one enemy, a dummy level and just a track, stripped down for a demo, and it's not just one lib i think, like a library for a program. I will see that when the time that the libs are finally finished that this will happen.
 
Good work, though personally I think damage is not really what will benefits the most from object oriented approach (cancel  ::) ). But now that I'm thinking about it, we could really use some kind of abstract access to dropv properties so as to create custom knockback (if enemy doesn't fall) and grab end trajectory for examples.

About the functions naming, I would have set shorter names when possible (e.g. dc_damage_create_object => dc_dmg_create). But I guess avoiding shortened words might be a good thing for transparency.

 
I actually used long names intentionally. The idea is to be less obfuscated for rookie script users. One of my goals is ease of use. The other reason is compatibility. The naming convention is meant to avoid ever conflicting with pre-existing functions in a module.

 
Back
Top Bottom