OpenXcom Forum

Modding => Released Mods => XPiratez => Topic started by: karadoc on September 20, 2016, 04:18:41 am

Title: Traing bravery
Post by: karadoc on September 20, 2016, 04:18:41 am
Since the implementation of pilots, bravery has become a much more important stat. It's very useful to have a team of high bravery pilots for every base, and so training soldier for bravery is more important than it use to be.

The thing is, training bravery is not as easy as training other abilities. Most stats can be casually improved to high levels just by doing ordinary things in missions, without any special effort. (There are ways to accelerate the improvement of any stat, but generally it's enough to just equip gear that will help with the stat you want to improve... eg. carrying a couple of boom fruit can give you the opportunity to improve your throwing without too much effort. Carrying a fast weapon (particularly a fast melee weapon) can give you plenty of chances to improve reactions, etc.

But bravery, in my experience, doesn't improve much beyond ~60 through normal play. The only way I know of to reliably improve bravery is to keep a soldier's moral low for several turns; and that tends to only happen if I'm doing something special to deliberately keep their moral low - such as making them wear a slave outfit and shooting them myself; or doing lots of psi attacks with the witch outfit; or taking combat drugs (and using smokes to boost moral if moral isn't high enough to take the drugs to drop the moral!)


However, I'm pretty sure I've seen soldiers get bravery increases without their moral having been low. So I'm thinking that there must be some other way to train it. Maybe something to do with healing things? Or some particular weapon? I don't know.

I'd prefer to be able to train bravery with just a few tweaks to normal play (such as using a particular weapon), rather than having to do weird stuff like shoot my own soldiers. So I'm wondering, what are the best ways to train bravery?

Before pilots, I didn't bother trying to train bravery at all; because no one panics anyway in an ordinary mission. There's too much moral bonus from killing enemies or from +bravery armour for moral to ever be a serious issue. On higher difficulties it seems that bravery is even less important, because there's just more stuff to kill - and hence boost moral!
Title: Re: Traing bravery
Post by: ohartenstein23 on September 20, 2016, 06:18:28 am
Meridian added experience gain on interceptions - if I remember correctly, the pilots on the craft that dealt the final blow have a chance to gain at least bravery (something like 20% chance for +10, configurable in ruleset), possibly firing and reactions too.  Before the pilot update, I believe it was also made possible to train bravery by healing enemy wounds.  So try putting the low-bravery gals on civvie shootdown duty, give them light firearms to inflict wounds but not kill, and make vodka a standard part of their kit?
Title: Re: Traing bravery
Post by: Dioxine on September 20, 2016, 06:23:35 am
Vodka won't do it. You need a real medkit of some sort. Also the 'enemy' part is exploitable, but primarly you get bravery for healing your own troops.
Title: Re: Traing bravery
Post by: H0lyD4wg on September 20, 2016, 06:48:02 am
What counts as a real medkit? Anything that actually restores some HP (so, bandages and X-Grog et cetera), or only things that are some kind of bag or box with a red cross symbol on them?
Title: Re: Traing bravery
Post by: legionof1 on September 20, 2016, 07:46:54 am
HP recovery is the key not wounds.
Title: Re: Traing bravery
Post by: ohartenstein23 on September 20, 2016, 02:29:14 pm
That would explain why I thought it was tuned down a little too much, I was trying vodka as a standard stunned-enemy-stabilizer, and wasn't paying attention to bravery gains on my grog-toting gals.
Title: Re: Traing bravery
Post by: Meridian on September 20, 2016, 05:12:55 pm
Just to prevent misinformation:
 - Vodka counts as well Vodka could count as well, if it had been marked as bravery-training item
 - Healing both your own troops and enemy/neutral troops works as well

Bravery experience is awarded when fatal wounds of any unit are healed (1 exp per fatal wound).

Bravery increases (+10) if the experience is high enough to pass RNG test:

Code: [Select]
if (_expBravery && stats->bravery < caps.bravery)
{
if (_expBravery > RNG::generate(0,10)) stats->bravery += 10;
}
Title: Re: Traing bravery
Post by: Eddie on September 20, 2016, 05:23:17 pm
Bravery is trained by items which have "experienceTrainingMode: 19". Bandages have that, but vodka and grog don't.
So no, vodka doesn't train bravery.

Things that train bravery:
- bandages
- first aid kit
- small medipack
- medipack
- super medipack

The saviour medipack trains psy and not bravery.

Other things that I have found in the rouleset that train bravery:
- wand of bliss
- bad touch + good touch
- medipack of nurse outfit
- cake

It would be nice if there were some melee weapons that trained bravery, like there are melee weapons that train reaction. Bravery is actually quite useful early game because the handle is the best early game stunning weapon. With high bravery, the damage output of the handle can compete with the cattle prod even vs medium armored enemies (osiron security)
Title: Re: Traing bravery
Post by: Meridian on September 20, 2016, 06:19:40 pm
Bravery is trained by items which have "experienceTrainingMode: 19".

You're right, forgot about that.
Title: Re: Traing bravery
Post by: karadoc on September 21, 2016, 12:55:44 am
Thanks for the info.

20% chance of increase for shooting down a ship is pretty good. So now that I know that, I won't feel bad about using 70-90 bravery pilots.

As for healing wounds giving bravery experience, I'm left wondering if there are any other exceptions or special cases. I definitely have noticed that when soldiers are using a nurse outfit and doing a lot of healing, they improve their bravery (and saviour outfits don't have the same effect); but in an attempt to get better bravery training I tried shooting my own troops a lot and healing them up.

I had a few soldiers in slave armour, and I shot them a heap of times with fletchette guns to create wounds which I then healed. I wasn't keeping count of the heals, but I know I had a few soldiers heal 8 wounds (because their first-aid kits ran out); and others healed 4 (with small medikits)...   in any case, there was a huge amount of healing going on; and no one at all got any bravery increase at the end of the mission.

So, was that just crazy bad luck? Or does the game not count wounds that are self-inflicted? Or perhaps the healing doesn't count no armour which has natural regen? Or something else?

(Incidentally, I reckon slave armour might be a bit too powerful for it's very low cost.)
Title: Re: Traing bravery
Post by: Eddie on September 21, 2016, 04:24:20 am
Each bravery xp gives you a 10% chance to increase bravery at the end of the mission. With 10 or more bravery xp you have a guaranteed bravery increase. Each wound you heal with a medikit gives one bravery xp. As I posted above, the medipack of the nurse outfit gives bravery xp.

One thing that I am not sure about: using medikits for other things (painkillers, stimulant) might also give bravery xp.
Title: Re: Traing bravery
Post by: karadoc on September 21, 2016, 04:53:54 am
Vodka won't do it. You need a real medkit of some sort. Also the 'enemy' part is exploitable, but primarly you get bravery for healing your own troops.
I just looked at the source code to get an answer for why I didn't gain bravery when I tried to exploit / test the system by shooting my own soldiers and healing them. By the look of it, you don't get any bravery experience from healing your own troops. You only get it from healing the enemy.

As far as I can tell, here's how it works. `medikitHeal` calls `awardExperience` if you've healed (any) fatal wound. But the first thing `awardExperience` does is to check if the target is an enemy or not. If it is not an enemy, you don't get any experience.

Code: [Select]
void TileEngine::medikitHeal(BattleAction *action, BattleUnit *target, int bodyPart)
{
const RuleItem *rule = action->weapon->getRules();

if (target->getFatalWound(bodyPart))
{
https:// award experience only if healed body part has a fatal wound (to prevent abuse)
awardExperience(action->actor, action->weapon, target, false);
}

target->heal(bodyPart, rule->getWoundRecovery(), rule->getHealthRecovery());
action->weapon->setHealQuantity(action->weapon->getHealQuantity() - 1);

_save->getBattleGame()->playSound(action->weapon->getRules()->getHitSound());
}

Code: [Select]
bool TileEngine::awardExperience(BattleUnit *unit, BattleItem *weapon, BattleUnit *target, bool rangeAtack)
{
if (!target)
{
return false;
}
else
{
https:// only enemies count, not friends or neutrals
if (target->getOriginalFaction() != FACTION_HOSTILE) return false;

https:// mind-controlled enemies don't count though!
if (target->getFaction() != FACTION_HOSTILE) return false;
}
https:// ...
Title: Re: Traing bravery
Post by: karadoc on September 21, 2016, 08:48:16 am
I was having vague memories that the awardExperience function use to have a special case for healing. So I pulled up an older version of the code.

Behold!
Code: [Select]
bool TileEngine::awardExperience(BattleUnit *unit, BattleItem *weapon, BattleUnit *target, bool rangeAtack)
{
if (!weapon)
{
return false;
}

if (!target)
{
return false;
}
else if (weapon->getRules()->getBattleType() != BT_MEDIKIT)
{
https:// only enemies count, not friends or neutrals
if (target->getOriginalFaction() != FACTION_HOSTILE) return false;

https:// mind-controlled enemies don't count though!
if (target->getFaction() != FACTION_HOSTILE) return false;
}
https:// ...
So in the older code, the check for enemies isn't performed if the 'weapon' is of medikit type. I'm not sure if that covers all of the healing items; and I'm not sure why it was changed. (I haven't tried to find the commit that changed it.)

My best guess is that it was changed because it was easily exploitable. So to solve that, I have a suggestion: only award the experience if the most recent attack was from an enemy. Like this:
Code: [Select]
bool TileEngine::awardExperience(BattleUnit *unit, BattleItem *weapon, BattleUnit *target, bool rangeAtack)
{
if (!weapon)
{
return false;
}

if (!target)
{
return false;
}
else if (!(weapon->getRules()->getBattleType() == BT_MEDIKIT && target->killedBy() == FACTION_HOSTILE))
{
https:// Only give experience for actions performed on enemies...
https:// ... unless the action is to heal a wound which was inflicted by an enemy

https:// only enemies count, not friends or neutrals
if (target->getOriginalFaction() != FACTION_HOSTILE) return false;

https:// mind-controlled enemies don't count though!
if (target->getFaction() != FACTION_HOSTILE) return false;
}
https:// ...
`killedBy` is set whenever a unit is shot and has fatal wounds. (The unit doesn't actually need to have died.) So this is a reliable way to make sure the soldier has actually come under enemy fire.

It would still be exploitable in the sense that a player could inflict wounds, then deliberately get shot by a very weak enemy, then heal the wounds... but I don't think that kind of exploitation is any easier than using the kind of 'low moral' tactics I was describing earlier.
Title: Re: Traing bravery
Post by: Meridian on September 21, 2016, 10:06:42 am
I was having vague memories that the awardExperience function use to have a special case for healing. So I pulled up an older version of the code.

Yes, it had!

Looks like it was incorrectly merged :(
https://github.com/MeridianOXC/OpenXcom/commit/016406cabb25b3cbb6cb92defdb0f9b72b86c706
This merging thingy really makes me worry more and more... I don't know how much longer I can merge without breaking more and more stuff.

I'll fix this one, thanks for the investigation and suggestion.
Title: Re: Traing bravery
Post by: Dioxine on September 21, 2016, 10:13:29 am
Well, the game has a large player base, so any bugs created by incorrect merging will be found, eventually. So no reason to over worry. By the way, while we're at it, I'd vote for including Karadoc's fix as well.

As for bravery training, my favorite way is as follows: you'll get a lot by using any outfit with a large combat stress increase (like Rags). You can get easily to 50-60 that way, especially when Warehouse/Temple missions spawn in some urbanized terrain and take a lot of turns (or you can linger before finishing any mission, if you're into exploits). After that, Battle Flag and Wench outfit's attacks are a good way to get all the way to 100 (also both get more powerful as your Bravery rises).
Title: Re: Traing bravery
Post by: Meridian on September 21, 2016, 10:26:08 am
By the way, while we're at it, I'd vote for including Karadoc's fix as well.

Yes, I will.

you'll get a lot by using any outfit with a large combat stress increase (like Rags).

Btw. I never really understood just from pedia entries, which outfits increase combat stress and which decrease it.

For me "Combat stress: +4" and "Combat stress: -4" can both be interpreted both ways.

How about changing to "Combat stress increase: 4" and "Combat stress decrease: 4" instead? Or vice versa, whichever interpretation is actually correct. Or even completely without numbers, just say which effect it has.
Title: Re: Traing bravery
Post by: Dioxine on September 21, 2016, 10:47:54 am
Your proposition is sound, but it's 8 letters longer, and that's an insane waste of space for the tiny amount of text one can use in an Armor entry :)
Title: Re: Traing bravery
Post by: Meridian on September 21, 2016, 10:49:34 am
"More stress" and "Less stress" then?
Title: Re: Traing bravery
Post by: Dioxine on September 21, 2016, 10:53:41 am
Less Stress: +4 or Less Stress: -4? That's confusing as hell :)
Stress +4 or Stress -4 are IMO much more precise, since '-' means 'less', doesn't it?
Title: Re: Traing bravery
Post by: Meridian on September 21, 2016, 10:56:44 am
Less Stress: +4 or Less Stress: -4? That's confusing as hell :)
Stress +4 or Stress -4 are IMO much more precise, since '-' means 'less', doesn't it?

No no, just "Less stress" and "More stress", without any numbers. Or something along those lines, in non-broken english :)
Title: Re: Traing bravery
Post by: Dioxine on September 21, 2016, 11:02:43 am
But Sire, numbers are very important! Especially since some armors yield negligible differences, while other major ones (like +8, which is equal to -40 Bravery).
I think I can do it like Higher Stress (x) and Lower Stress (x), w/o any +/- if they're ambigous for some reason; but what is less ambiguous and more internationally comprehensible than mathematical symbols?
Title: Re: Traing bravery
Post by: Meridian on September 21, 2016, 11:08:22 am
Do as you wish basically. It is correct, it's just confusing (for me).

It's the double negative that is the confusing part.

"Combat stress: -8" means +40 bravery, or something like that... one negative is the word "stress", second negative is the number "-8"... giving you a positive result.

That's what I am having problems with every time I look at that description. The minus sign and the lack of minus sign are not strong enough to convey the message immediately and without thinking. Words less and more are strong enough (for me).
Title: Re: Traing bravery
Post by: Eddie on September 21, 2016, 03:58:19 pm
How about "Morale bonus" and "Morale penalty"?
Title: Re: Traing bravery
Post by: Dioxine on September 21, 2016, 04:41:12 pm
It doesn't penalize Morale though. You always have 100 Morale pool.
Title: Re: Traing bravery
Post by: yrizoud on September 21, 2016, 06:22:10 pm
I think "Stress tolerance" fits the bill. It's a quality (+x = good, -x=bad), you have the word "stress" in common with the "Combat stress" Piratez topic, and it's an actual expression in the English language.

A more gamey name would be "morale regen"
Title: Re: Traing bravery
Post by: Meridian on September 21, 2016, 08:18:20 pm
I have a suggestion: only award the experience if the most recent attack was from an enemy.

I have made 2 changes to your code:
- also if the attack on player comes from a neutral (not only from enemy), it will work... this is not possible yet, but will be once we merge changes from vanilla
- healing enemies should work as it worked before... I think your change allowed only healing enemies hurt by enemies, not by player

Please review, I'm quite confused from all the ands, ors and nots right now:
https://github.com/MeridianOXC/OpenXcom/commit/b2713dc6c5b789ae2dae0b99461863a6a0a4c3a2
Title: Re: Traing bravery
Post by: karadoc on September 22, 2016, 02:09:55 am
I have made 2 changes to your code:
- also if the attack on player comes from a neutral (not only from enemy), it will work... this is not possible yet, but will be once we merge changes from vanilla
- healing enemies should work as it worked before... I think your change allowed only healing enemies hurt by enemies, not by player

Please review, I'm quite confused from all the ands, ors and nots right now:
https://github.com/MeridianOXC/OpenXcom/commit/b2713dc6c5b789ae2dae0b99461863a6a0a4c3a2
The diff you posted looks totally wrong... but it isn't. It's just that you've put the changes in two separate commits, and so it all looks a bit different.
I'm pretty sure my code still worked fine for healing enemies. The conditions we are adding are to check whether or not we should abort the function; not continue to add experience. So the added conditions wouldn't have changed the fact that healing enemies worked in the first place.

I don't think we need to check the original faction of the target; because the wound still needs to be caused by our enemy. I kind of like the idea of gaining bravery for healing neutrals who were wounded by the enemy. So I'd probably skip the original faction check for that reason, and for simplicity.

I can't see any problems with your code. And I commend you moving the weapon condition to the top. Good call on that.

But since you've moved things around a bit, I'll suggest a few more minor tweaks changes for readability. The main thing is that the 'else' block after checking that there's a target doesn't need to be a block at all. Because if there's no target, we abort immediately.

Here's what I suggest for now:
Code: [Select]
if (!weapon) return false;

if (!target) return false;

https:// only give experience for actions performed on enemies...
https:// ... unless the action is to heal a fatal wound which was inflicted by an enemy (or neutral)
if (weapon->getRules()->getBattleType() == BT_MEDIKIT && target->killedBy() != FACTION_PLAYER)
{
https:// continue as normal
}
else
{
https:// only enemies count, not friends or neutrals
if (target->getOriginalFaction() != FACTION_HOSTILE) return false;

https:// mind-controlled enemies don't count though!
if (target->getFaction() != FACTION_HOSTILE) return false;
}
I usually wouldn't use an empty if block like that; but I've left if that way because it does kind of make the conditions easier to follow, somehow.

It would probably be nice to have some consistency in how the `if() return` things are done. In the current version of the code, there are three versions...
Code: [Select]
if (condition) return false;

if (condition)
{
return false;
}

if (condition)
return false;
If it were up to me, I'd use the final one all the time. But I'm pretty sure I've read that the style guidelines for this project say not to use that one ever! (All `if`s are meant to have braces.)
So I've changed it to use the shortest one, just to keep it... short. Its probably good to be able to see all the ways the code can return early without having to scroll.


In any case, your current code looks fine to me. I'm just tinkering at the edges now.
Title: Re: Traing bravery
Post by: karadoc on September 22, 2016, 10:03:23 am
While we're talking about healing stuff, I'd like to mention another minor bug, and fix it.

The bug is that the player cannot heal enemy units while they are mind-controlled. (In fact, by the look of it, enemy units also cannot be wounded while they are mind-controlled.)

Here's the relevant code:
Code: [Select]
bool BattleUnit::isWoundable() const
{
return !_armor->getBleedImmune(!(_type=="SOLDIER" || (Options::alienBleeding && _faction != FACTION_PLAYER)));
}

And my suggested fixed version... which I haven't tested yet:
Code: [Select]
bool BattleUnit::isWoundable() const
{
return !_armor->getBleedImmune(!(_type=="SOLDIER" || (Options::alienBleeding && __originalFaction != FACTION_PLAYER)));
}
I don't think the woundability of a unit should depend on whether it is mind controlled; so it makes sense to check their original faction rather than their current faction.

--

By the way, one minor problem with our bravery changes is that melee attack of the super-medikit will probably give xp when used on a friendly unit. The problem is that we're just checking if the item is a medikit; whereas what we really want to know is if we're trying to heal something...   I don't know an easy fix for that off the top of my head.
Title: Re: Traing bravery
Post by: karadoc on September 24, 2016, 07:07:13 am
I have bad news. It still doesn't give experience for healing wounds on friendly soldiers.

I was mistaken about `killedBy()` being a reliable way to tell who caused the wounds.

Apparently killedBy doesn't get set when a player character is wounded. Here is the relevant code.
Code: [Select]
if (unit && target->getFaction() != FACTION_PLAYER)
{
https:// if it's going to bleed to death and it's not a player, give credit for the kill.
if (wounds < target->getFatalWounds())
{
target->killedBy(unit->getFaction());
}
}

The obvious solution would be to just remove that condition, so that killedBy does get set. That's probably what I'd do if it was my game. But I don't know what the justification is for how it currently works, and changing it would probably be yet another divergence from the core game. Maybe there are a good reason for leaving it as is. Maybe it would be better to just let medikits give experience for all wounds, caused by the enemy or otherwise. That's how it worked previously anyway.

Sorry for the mistake about killedBy.