The following read me file contains various notes by Ivan_the_B about the new melee attack system, combo system, dynamic spread spread system and the dynamic pain system.
notes compiles together on 10.14.08 by Revility. Any changes or additions to the systems will be added as needed.
If the weapon worldmodel has the joint "melee", a tracer is fired from that joint in its direction, otherwise is fired from the player vieworigin, as the default D3 melee.
The width of the tracer is determined by the "melee_tracerWidth" key in the weapon def. A value of "0" means that the tracer is nothing more than a line.
The lenght of the tracer is determined by the "melee_distance" key in the weapon def.
The damagedef is determined by the "def_melee" key in the weapon def.
- New weapon scriptevents:
the old "melee()" scriptevent could be used, but what makes all this so easy to use are these new scriptevents:
Code:
void startAutoMelee( float dmgMult ); //specify the damage multiplier of this attack...very useful for combo ;D
void stopAutoMelee(); //stop if active!
Once "startAutoMelee" is started, the game automatically performs something very close to "melee()" every tick, until "stopAutoMelee()" is called.
Plus, it automatically ignores the last entity hit since "startAutoMelee" was started, so that it cannot happen that the same entity is constantly hit.
Starting again "startAutoMelee()" if it's already active resets the last entity hit to null, so this is a way to say "I can hit you again from now".
- How to use it:
Sure, you could call those scriptevents from your weapons, but what would allow us a far greater flexibility is calling them at a certain frame of the player animation.
That's why I've added the following funtions in the player scriptobject
Code:
startWeaponAutoMeleeX1(); //standard damage
startWeaponAutoMeleeX2(); //double damage
//...there are also X3 X4 X5 X10 X100, and you can easily add your own.
stopWeaponAutoMeleeAny(); //stop if active!
They simply call the "startAutoMelee" and "stopAutoMelee" scriptobject on the current weapon, specifing different damage multiplyers.
Example of the first attack animation for the ruinblade, from player.def.
I had to add a lot of stuff in Physics_Player.cpp to add a new movementType ( PM_ANIM ) based on animations delta.
Player scriptevents can enable/disable this new movementType.
While it's active: dodge, dash ,weapon change, ability to attack, player model turning and other movements are disabled.
The scriptobject of the current weapon is set in a new state called "WeaponWaiting" that should do nothing more than wait (could also stop sounds/effects if needed).
When it is disabled: all is reactivated and the scriptobject of the current weapon is set in it "idle" state.
- New player scriptevents:
Code:
void setAnimMoveOn();
void setAnimMoveOff();
- How to use it:
Don't use it
It should only be started/stopped by the following player function.
As I said at the beginning, now every attack really hit enemies that touch our sword (also more than one).
This means animations become really important, because it only depends on them how useful an attack is.
That's why I've rewritten the ruinblade script allowing us to enter in the "cycle" of animation from different points. That is, when we start attacking, instead of playng always the same animation as first one, now it depends:
- If we are pressing the strafe right button, the first animation will be the attack from right to left.
- If we are pressing the strafe left button, the first animation will be the attack from left to right.
- Otherwise the first animation will be the the old one.
It is very intuitive and the player feels to have more control over what is happening. And of course more strategy is needed.
For example if we have a monster to our right, we can simply hold right before attacking and what we get is that the best animation for this situation is played.
there are 2 sets of pain anims identified by their name.
1) "pain_zonename" are meant for normal pain (monster stands in place in pain)
2) "highpain_zonename" are meant for high pain (monster falls back/down in pain)
Every damage zone has a current "damage value" that automatically slowly decreases to 0.
When the damage on a zone is greater than the maximum value specified for that zone, the right highpain anim is played and all the damage valuea are reset to 0.
- How to add a new pain animation
Simply add it in the modeldef.
Just make sure overrideLegs is called in order to play it also on legs.
Code:
anim highpain_head models/md5/monsters/vagary/chestpain.md5anim { //this is for head only
frame 1 call overrideLegs //<---!
frame 1 sound_voice
}
NOTE: overrideLegs is not called for maggots, fat and running zombies because their pain anims make them to walk. There's a fix for this in their AIs that force idle anim on legs, but are just exceptions.
In case of missing pain anim for a particular zone:
- standard pain: default anim is "pain"
- high pain: default anim is "highpain" (if even "highpain" is not present, "pain" is played)
- How AIs works
Main changes are in Torso_Pain(), where timeouts and states are set based on the values of boolean flags like AI_HIGHPAIN, AI_COMBOPAIN, AI_MELEEPAIN.
Those timeouts allow check_attacks() to choose only certain type of attacks (usually dodge) for a while after a pain animation.
If AI_HIGHPAIN is true, the monster is set in a state called state_HighPain() that wait for the pain anim to end. This will allow monsters to fall/down back with long animations without the risk that the anim could be interrupted by other attack anims.
- Define values for each monster
example for head zone:
"highpain_threshold head" "180" //180 damage points is the threshold for head zone
"highpain_resettime head" "12" //it takes 12 seconds to go from 180 to 0.
- Minimum time between pain anim
Every monster inherits from monster_default the following keys:
Code:
"pain_threshold" "1" //play pain anims if damaged more than 1hp (that is, always)
"pain_delay" "1" //minimum time between 2 pain anims and pain sounds.
Note that those values are NOT used if pain is inflicted by a melee damage (the ones with the key "melee" "1") because monsters should be always ready to react to combo or simple sword attacks.
What is really the minimum time between the beginning of 2 pain anims is the value
Code:
nextpain = sys.getTime() + 0.1;
that is set in Torso_Pain() animstate.
It is usually 0.1 seconds. But in the case of archvile, hellknight and vagary this value is much higher and is checked also in other animstates in order to make them harder to fight.
- Force pain type with combo
You can call the following function from the combo animation itself
Code:
void comboForceHighPain();
void comboAllowHighPain();
void comboDenyHighPain();
example:
Code:
anim ruinblade_combo_1 todo.md5anim{ //to do: create a proper anim