[size=14pt]Git: https://github.com/swwu/Cataclysm-DDA/tree/martial_arts[/size]
PR: Martial arts, part 1 by swwu · Pull Request #3104 · CleverRaven/Cataclysm-DDA · GitHub (Merged!)
(This post is a little bit out of date but is more or less correct)
I wasn’t sure whether to put this here or on the drawing board since it’s not technically done yet, but it’s mostly working and you can play it if you don’t mind watching g++ poot along for 3-5 minutes, so #YOLO.
Anyways, I changed martial arts.
Here are some pictures of custom martial arts things:
[spoiler]
Just a regular ol’ custom martial arts technique… now with 100% more katana
Stacking buffs, or, LOOK AT HOW FAST I AM
[/spoiler]
Stacking buffs agin
Karate… like you’ve never seen it before
Here’s a nice bulleted list of the things I changed:
[ul][li]Martial arts are no longer items. They are their own thing. No more karate throwing, and you can use martial arts with a weapon equipped. In fact, you can set up martial arts that only benefit you when using a weapon if you want. I won’t judge.[/li]
[li] ‘_’ still selects martial arts[/li]
[li]Martial arts are waaaaaayy moddable. Like, waaayyyy. Just for fun, I added a “Berserker” style where you can use weapons and you do more damage the longer you hit things, and a “Coward” style that makes moving increase your speed but hitting things decrease your damage. These are the ones in the pics and are meant to be demos of what can be modded, not actual serious suggestions for martial arts styles. Full JSON documentation down below.[/li]
[li]I’ve only put Karate and a few other styles in so far, since there are a loooot of them and they do a lot of things and I got sick of writing JSON. I would love it if people could help JSON them up. All JSONs are in data/raw/martialarts.json. See aforementioned documentation, down below. I’m pretty sure everything except the Five Venoms styles and the silent-ness from ninjutsu can be accurately reproduced right now.[/li]
[li]The “Martial Arts Training” trait gives karate, aikido, and the demo styles mentioned above. The other martial arts traits don’t do anything (technically they still give you the old martial arts, but you can’t access those any more so they’re more or less useless).
[/li][li]I probably added a bunch of bugs too[/li][/ul]
Here’s the promised Json documentation:
[spoiler]
[size=14pt]Okay so this isn’t really like full documentation, more like a brief overview because I am getting tired and it is late[/size]
Martial arts are listed in the JSON file in an array. Let’s just look at it because I can’t think of any good segues:
[ { "id": "style_test_karate", "name": "SuperKarate", "desc": "Karate is a popular martial art, originating from Japan. It focuses on rapid, precise attacks, blocks, and fluid movement. A successful hit allows you an extra dodge and two extra blocks on the following round.", "static_buffs": [ { "id": "testkarate_static_buff", "name": "SuperKarate", "desc": "use 1000% INT to calculate to hit and damage and dodge everything", "unarmed_allowed": true, "min_unarmed": 0, "buff_duration": 2, "hit_int": 10, "hit_dex": -1, "bash_int": 10, "bash_str": -1, "dodge": 100 } ], "onhit_buffs": [ { "id": "testkarate_hit_buff", "name": "SuperKarate Hit Buff", "desc": "+1 dodges, +2 blocks per stack", "unarmed_allowed": true, "min_unarmed": 0, "buff_duration": 10, "max_stacks": 10, "dodges_bonus": 1, "blocks_bonus": 2 } ], "onmove_buffs": [ { "id": "testkarate_move_buff", "name": "SuperKarate Move Buff", "desc": "+10 speed per stack", "unarmed_allowed": true, "min_unarmed": 0, "buff_duration": 2, "max_stacks": 10, "speed": 10 } ], "techniques": [ { "name": "quickly punch", "min_unarmed": 0, "unarmed_allowed": true, "tec_flag": "RAPID", "verb_you": "%1$s quickly punch %4$s", "verb_npc": "%1$s quickly punches %4$s" }, { "name": "block", "min_unarmed": 0, "unarmed_allowed": true, "tec_flag": "BLOCK", "verb_you": "%1$s block %4$s", "verb_npc": "%1$s blocks %4$s" }, { "name": "karate chop", "min_unarmed": 0, "unarmed_allowed": true, "tec_flag": "PRECISE", "verb_you": "%1$s karate chop %4$s", "verb_npc": "%1$s karate chops %4$s" } ] } ]So this is superkarate, it is way better than normal karate in all ways and it also has Style, like capital 's' Style. Okay so let's start from the start
Thing 1: Buffs
A buff represents a change to stats you get from a style, for whatever reason. Let’s look at buff:
{ "id": "testkarate_move_buff", "name": "SuperKarate Move Buff", "desc": "+10 speed per stack", "unarmed_allowed": true, "min_unarmed": 0, "buff_duration": 2, "max_stacks": 10, "speed": 10 }Okay so what does this buff do? Well the description says "+10 speed per stack" but let's pretend we can't read regular english. There are a few important things here:
[ul][li]unarmed_allowed:true says “this buff will work when you are unarmed”. It has a counterpart, melee_allowed, that makes the buff valid when you aren’t unarmed. You need at least one of these two to be true in a buff in order for it to do anything.[/li]
[li]min_unarmed:0 says “you need at least 0 unarmed skill for this buff to work”. There are also min_melee for the melee skill, and maybe some other ones coming shortly for bashing stabbing etc. But not yet.[/li]
[li]buff_duration:2 says "this buff will last for 2 turns once applied. Keep in mind that the counter is often decremented right after the buff is applied if you get the buff on your last action of a turn, so if you set buff_duration:1 it will actually not do anything a lot of the time since it will instantly disappear.[/li]
[li]max_stacks:10 says “this buff will stack with itself up to 10 times”. If you try to apply a buff that’s already there, it will just stack the buffs until you reach max_stacks (and multiply the effects of the buff). [/li]
[li]speed:10 says, “this buff will add 10 to your speed”. There are a ton of possible fields that modify your character, and I’ve listed them below.[/li][/ul]
So when this buff is applied, assuming you are unarmed and have at least 0 unarmed skill, you will get a +10 boost to speed for 10 turns. Easy, right?
Thing 2: Events
So now we have buffs, the only thing left to do is to actually add them to people. That’s what events are for. Let’s look at the entire superkarate again, but with all the buff info cut out, and also the techniques cut out, because we don’t care about them yet:
{ "id": "style_test_karate", "name": "SuperKarate", "desc": "Karate is a popular martial art, originating from Japan. It focuses on rapid, precise attacks, blocks, and fluid movement. A successful hit allows you an extra dodge and two extra blocks on the following round.", "static_buffs": [...there would be buffs here if you hadn't killed them all...], "onhit_buffs": [...ditto...], "onmove_buffs": [...here too...], "techniques": [...] }
Okay so basically there are a bunch of things ending in “_buffs” that previously contained buffs but now do not. These things serve as event handlers. The way it works is like this: whenever a thing happens, all the buffs in its corresponding event handler are added to the player. So whenever the player moves, all the buffs in onmove_buffs are added to him. onhit_buffs are applied when you successfully hit something, onmove_buffs when you move a tile, and static_buffs are applied once per turn as long as you’re using the style, so basically they’re always on.
So with the buff we looked at above, which was in onmove_buffs, you would go +10 speed faster every time you moved a tile, and it would stack 10 times, meaning if you moved 10 times, you would have +100 speed.
Thing 3: Techniques
So these are pretty boring, they are in techniques which we have been ignoring up until now and will probably keep ignoring after this because seriously who wants to hang out with techniques? Here hold on let me highlight them for you
{ "id": "style_test_karate", "name": "SuperKarate", "desc": "Karate is a popular martial art, originating from Japan. It focuses on rapid, precise attacks, blocks, and fluid movement. A successful hit allows you an extra dodge and two extra blocks on the following round.", "static_buffs": [...], "onhit_buffs": [...], "onmove_buffs": [...], "techniques": [...] <-- TECHNIQUES }Anyways techniques represent the "flavor" attacks you get sometimes with martial arts and certain weapons.
{ "name": "karate chop", "min_unarmed": 0, "unarmed_allowed": true, "tec_flag": "PRECISE", "verb_you": "%1$s karate chop %4$s", "verb_npc": "%1$s karate chops %4$s" }Here is a technique. It has the same [b]min_X[/b] and [b]X_allowed[/b] fields as buffs do. These control the conditions under which the technique can fire, so the karate chop here works only if you are unarmed and have at least 0 unarmed skill. The different stuff:
[ul][li]tec_flag is the actual technique that’s performed. Cataclysm has a fairly small number of possible hardcoded techniques, that aren’t currently moddable, and i was too lazy to make them moddable for this so here you go, use the flag dammit. Below is a list of all possible values for tec_flag.[/li]
[li]verb_you is what text shows up when you use this technique. %1$s is usually just “you” (as in, “can %1$s come over and tell me if this smells like chloroform?”). %4$s is whatever they are, so if you are hitting a zombie it will be “the zombie” and if you are hitting a bear it will be “the bear” and if you are hitting a small child then you are a bad person.[/li]
[li]verb_npc is what text shows up when an npc uses this technique, possibly on you. %1$s is the NPC (usually their name, e.g. “Paige Thomas”). %4$s is whatever thing they are doing the technique on, could be “you” or any number of small children really[/li][/ul]
So basically you can perform a karate chop, which is, under the hood, just a “PRECISE” attack, when you are unarmed and have at least 0 unarmed skill, and it will tell you that you have karate chopped them. Certain techniques (“PRECISE” is one of them) only work under certain conditions (for “PRECISE”, if you land a crit), so keep that in mind. Some of the techniques also don’t work with some weapons right now and I’m actually not sure if that’s my fault or not.
Thing 4: Putting it together
Okay now let’s go back to the full superkarate:
[ { "id": "style_test_karate", "name": "SuperKarate", "desc": "Karate is a popular martial art, originating from Japan. It focuses on rapid, precise attacks, blocks, and fluid movement. A successful hit allows you an extra dodge and two extra blocks on the following round.", "static_buffs": [ { "id": "testkarate_static_buff", "name": "SuperKarate", "desc": "use 1000% INT to calculate to hit and damage and dodge everything", "unarmed_allowed": true, "min_unarmed": 0, "buff_duration": 2, "hit_int": 10, "hit_dex": -1, "bash_int": 10, "bash_str": -1, "dodge": 100 } ], "onhit_buffs": [ { "id": "testkarate_hit_buff", "name": "SuperKarate Hit Buff", "desc": "+1 dodges, +2 blocks per stack", "unarmed_allowed": true, "min_unarmed": 0, "buff_duration": 10, "max_stacks": 10, "dodges_bonus": 1, "blocks_bonus": 2 } ], "onmove_buffs": [ { "id": "testkarate_move_buff", "name": "SuperKarate Move Buff", "desc": "+10 speed per stack", "unarmed_allowed": true, "min_unarmed": 0, "buff_duration": 2, "max_stacks": 10, "speed": 10 } ], "techniques": [ { "name": "quickly punch", "min_unarmed": 0, "unarmed_allowed": true, "tec_flag": "RAPID", "verb_you": "%1$s quickly punch %4$s", "verb_npc": "%1$s quickly punches %4$s" }, { "name": "block", "min_unarmed": 0, "unarmed_allowed": true, "tec_flag": "BLOCK", "verb_you": "%1$s block %4$s", "verb_npc": "%1$s blocks %4$s" }, { "name": "karate chop", "min_unarmed": 0, "unarmed_allowed": true, "tec_flag": "PRECISE", "verb_you": "%1$s karate chop %4$s", "verb_npc": "%1$s karate chops %4$s" } ] } ]Now that you know what all the parts do you should know what this thing as a whole does. Obviously all the lists [] can have multiple things in them so I can have more than one static buff in a style, and each one can become active with different requirements. I want to conclude by pointing out that all the things I mentioned earlier are [i]only true if the style is currently selected[/i], and that a style does not give buffs if it is not the selected one (duh).
Full list of buff fields
bool unarmed_allowed; // does this bonus work when unarmed? bool melee_allowed; // what about with a melee weapon?int buff_duration; // total length this buff lasts int max_stacks; // total number of stacks this buff can have int min_melee; // minimum amount of unarmed to trigger this bonus int min_unarmed; // minimum amount of unarmed to trigger this bonus int min_bashing; // minimum amount of unarmed to trigger this bonus int min_cutting; // minimum amount of unarmed to trigger this bonus int min_stabbing; // minimum amount of unarmed to trigger this bonus int dodges_bonus; // extra dodges, like karate int blocks_bonus; // extra blocks, like karate int hit; // flat bonus to hit int bash; // flat bonus to bash int cut; // flat bonus to cut int dodge; // flat dodge bonus int speed; // flat speed bonus float bash_stat_mult; // bash damage multiplier, like aikido float cut_stat_mult; // cut damage multiplier float bash_str; // bonus damage to add per str point float bash_dex; // "" dex point float bash_int; // "" int point float bash_per; // "" per point float cut_str; // bonus cut damage to add per str point float cut_dex; // "" dex point float cut_int; // "" int point float cut_per; // "" per point float hit_str; // bonus to-hit to add per str point float hit_dex; // "" dex point float hit_int; // "" int point float hit_per; // "" per point float dodge_str; // bonus dodge to add per str point float dodge_dex; // "" dex point float dodge_int; // "" int point float dodge_per; // "" per point</blockquote>
Full list of technique flags
[]
// Offensive Techniques
SWEEP, // Crits may make your enemy fall & miss a turn
PRECISE, // Crits are painful and stun
BRUTAL, // Crits knock the target back
GRAB, // Hit may allow a second unarmed attack attempt
WIDE, // Attacks adjacent oppoents
RAPID, // Hits faster
FEINT, // Misses take less time
THROW, // Attacks may throw your opponent
DISARM, // Remove an NPC’s weapon
FLAMING, // Sets victim on fire
// Defensive Techniques
BLOCK, // Block attacks, reducing them to 25% damage
BLOCK_LEGS, // Block attacks, but with your legs
WBLOCK_1, // Weapon block, poor chance – e.g. pole
WBLOCK_2, // Weapon block, moderate chance – weapon made for blocking
WBLOCK_3, // Weapon block, good chance – shield
COUNTER, // Counter-attack on a block or dodge
BREAK, // Break from a grab
DEF_THROW, // Throw an enemy that attacks you
DEF_DISARM, // Disarm an enemy
[/quote]
[/spoiler]
Here’s a nice bulleted list of technical and architectural concerns:
[ul][li]Added new files, martialarts.h/cpp.[/li]
[li]Buffs are just “custom” diseases. I opted to add fields to the disease struct instead of something fancy like inheritance, since player.illness is a vector and not a vector<disease*> (meaning no upcasting things that are in the vector) and god knows I don’t really want to hunt down and change every single reference to player.illness. That would be almost as bad as dealing with C++ inheritance.[/li]
[li]I added some functions, mabuff_hit_bonus() etc to player.h. These are defined in martialarts.cpp and basically provide an easy way to get all the bonuses being provided by active martial arts buffs.[/li]
[li]The technique code is kind of janky, since I didn’t want to change the way techniques are implemented too much. I just added a “check if player has a style with this technique” to item::has_technique, and then everything else is more or less like the old way martial arts were implemented.[/li]
[li]I’ve removed almost nothing of the original martial arts implementation since I didn’t want to break too much, so all that code is still there. It just does nothing, since you can neither acquire nor select the old martial arts.[/li][/ul]
Anyways since this is a pretty big addition, I’d like to get some input on the design etc even though I don’t think it’s quite ready to merge (at the very least due to not having most of the styles defined yet). And then if this looks good to people I can look into polishing off some of the rough edges and putting in a pull request (and if it doesn’t, well…).