Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add skill to advanced defense #265

Merged
merged 5 commits into from Jun 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions code/code/cmd/cmd_bash.cc
Expand Up @@ -223,6 +223,7 @@ static int bash(TBeing *c, TBeing *victim, spellNumT skill)
(bKnown > 0) &&
(i != GUARANTEED_FAILURE) &&
(!victim->canCounterMove(bKnown)) &&
(!victim->canFocusedAvoidance(bKnown/2)) &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The () aren't necessary, but they don't hurt either.

c->bSuccess(bKnown + percent, skill)) {
rc = c->bashSuccess(victim, skill);
if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
Expand Down
56 changes: 34 additions & 22 deletions code/code/cmd/cmd_bonebreak.cc
Expand Up @@ -51,26 +51,30 @@ int TBeing::doBoneBreak(const char *argument, TBeing *vict)

}

int bonebreakMiss(TBeing *c, TBeing *v, int type)
enum bbMissType {
TYPE_DEFAULT,
TYPE_MONK,
TYPE_DEFENSE
};

int bonebreakMiss(TBeing *c, TBeing *v, bbMissType type)
{
switch(type){
case 0:{ // normal
act("$n attempts to get $N into a bone breaking hold, but fails.",
FALSE, c, 0, v, TO_NOTVICT);
act("$N avoids your puny attempt to get $M into a bone breaking hold.",
FALSE, c, 0, v, TO_CHAR);
act("$n tries get you into a bone breaking hold, but you avoid it.",
FALSE, c, 0, v, TO_VICT);
} break;
case 1:{ // monk counter move
act("$n tries to grapple $N, but $E cleverly avoids $s moves.",
FALSE, c, 0, v, TO_NOTVICT);
act("$N cleverly avoids your attempt to get $M into a bone breaking hold.",
FALSE, c, 0, v, TO_CHAR);
act("$n tries grapple you into a bone breaking hold but you avoid it.",
FALSE, c, 0, v, TO_VICT);
} break;
}
switch(type) {
case TYPE_MONK :
act("$n tries to grapple $N, but $E cleverly avoids $s moves.", FALSE, c, 0, v, TO_NOTVICT);
act("$N cleverly avoids your attempt to get $M into a bone breaking hold.", FALSE, c, 0, v, TO_CHAR);
act("$n tries grapple you into a bone breaking hold but you avoid it.", FALSE, c, 0, v, TO_VICT);
break;
case TYPE_DEFENSE :
act("$n attempts to get $N into a bone breaking hold, but fails.", FALSE, c, 0, v, TO_NOTVICT);
act("$N's focus is too great for your bone breaking hold.", FALSE, c, 0, v, TO_CHAR);
act("$n tries get you into a bone breaking hold, but your focus is too great.", FALSE, c, 0, v, TO_VICT);
break;
default : // TYPE_DEFAULT
act("$n attempts to get $N into a bone breaking hold, but fails.", FALSE, c, 0, v, TO_NOTVICT);
act("$N avoids your puny attempt to get $M into a bone breaking hold.", FALSE, c, 0, v, TO_CHAR);
act("$n tries get you into a bone breaking hold, but you avoid it.", FALSE, c, 0, v, TO_VICT);
}

c->reconcileDamage(v, 0,SKILL_BONEBREAK);
return TRUE;
Expand Down Expand Up @@ -237,15 +241,23 @@ int bonebreak(TBeing *caster, TBeing *victim)

if (victim->canCounterMove(bKnown/3)) {
SV(SKILL_BONEBREAK);
rc = bonebreakMiss(caster, victim, 1);
rc = bonebreakMiss(caster, victim, TYPE_MONK);
if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
return rc;
return TRUE;
}

if (victim->canFocusedAvoidance(bKnown/2)) {
SV(SKILL_BONEBREAK);
rc = bonebreakMiss(caster, victim, TYPE_DEFENSE);
if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
return rc;
return rc;
return TRUE;
}

return (bonebreakHit(caster, victim));
} else {
rc = bonebreakMiss(caster, victim, 0);
rc = bonebreakMiss(caster, victim, TYPE_DEFAULT);
if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
return rc;
}
Expand Down
5 changes: 5 additions & 0 deletions code/code/cmd/cmd_grapple.cc
Expand Up @@ -91,6 +91,11 @@ static int grapple(TBeing *c, TBeing *victim, spellNumT skill)
rc = c->trySpringleap(victim);
if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
return rc;
} else if (victim->canFocusedAvoidance(bKnown/2)) {
SV(skill);
act("$N avoids your grapple attempt.", TRUE, c, 0, victim, TO_CHAR, ANSI_RED);
act("$N avoids $n's attempt to grapple.", TRUE, c, 0, victim, TO_NOTVICT);
act("You evade $n's attempt to grapple.", TRUE, c, 0, victim, TO_VICT);
} else {
if (victim->riding) {
act("You pull $N off $p.", FALSE, c, victim->riding, victim, TO_CHAR);
Expand Down
3 changes: 2 additions & 1 deletion code/code/cmd/cmd_headbutt.cc
Expand Up @@ -279,7 +279,8 @@ static int headbutt(TBeing *caster, TBeing *victim)
(i = caster->specialAttack(victim,SKILL_HEADBUTT)) &&
i != GUARANTEED_FAILURE &&
percent < bKnown&&
!victim->canCounterMove(bKnown*2/5)) {
!victim->canCounterMove(bKnown*2/5) &&
!victim->canFocusedAvoidance(bKnown*2/5)) {
return (headbuttHit(caster, victim));
} else {
rc = headbuttMiss(caster, victim);
Expand Down
13 changes: 12 additions & 1 deletion code/code/cmd/cmd_spin.cc
Expand Up @@ -87,7 +87,8 @@ bool TBeing::canSpin(TBeing *victim, silentTypeT silent)
enum spinMissT {
TYPE_DEFAULT,
TYPE_DEX,
TYPE_MONK
TYPE_MONK,
TYPE_DEFENSE
};

static int spinMiss(TBeing *caster, TBeing *victim, spinMissT type)
Expand All @@ -101,6 +102,11 @@ static int spinMiss(TBeing *caster, TBeing *victim, spinMissT type)
0, victim, TO_VICT);
act("$N deftly avoids $n's attempt at spinning $M.", FALSE, caster,
0, victim, TO_NOTVICT);
} else if (type == TYPE_DEFENSE) {
act("$N is too fast and avoids your attempt at spinning $M.", FALSE, caster, 0, victim, TO_CHAR);
act("Your defensive training helps you avoid $n's feeble spin attempt.", FALSE, caster, 0, victim, TO_VICT);
act("$N deftly avoids $n's attempt at spinning $M.", FALSE, caster, 0, victim, TO_NOTVICT);

} else if (type == TYPE_MONK) {
act("$N deftly counters your attempt at spinning $M.", FALSE, caster, 0, victim, TO_CHAR, ANSI_RED);
act("You trip and land on the $g.", FALSE, caster, 0, victim, TO_CHAR, ANSI_RED);
Expand Down Expand Up @@ -242,6 +248,11 @@ static int spin(TBeing *caster, TBeing *victim)
rc = spinMiss(caster, victim, TYPE_MONK);
if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
return rc;
} else if (victim->canFocusedAvoidance(bKnown/3)) {
SV(SKILL_SPIN);
rc = spinMiss(caster, victim, TYPE_DEFENSE);
if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
return rc;
} else if (((caster->getDexReaction() -
victim->getAgiReaction()) > ::number(-10,20)) &&
victim->awake() && victim->getPosition() >= POSITION_STANDING) {
Expand Down
1 change: 1 addition & 0 deletions code/code/cmd/cmd_stat.cc
Expand Up @@ -1817,6 +1817,7 @@ void TBeing::statBeing(TBeing *k)
case SKILL_DISSECT:
case SKILL_DEFENSE:
case SKILL_ADVANCED_DEFENSE:
case SKILL_FOCUSED_AVOIDANCE:
case SKILL_OFFENSE:
case SKILL_WHITTLE:
case SKILL_WIZARDRY:
Expand Down
1 change: 1 addition & 0 deletions code/code/cmd/cmd_trip.cc
Expand Up @@ -182,6 +182,7 @@ static int trip(TBeing *c, TBeing *victim, spellNumT skill)
(bKnown > 0) &&
(i != GUARANTEED_FAILURE) &&
(!victim->canCounterMove(bKnown)) &&
(!victim->canFocusedAvoidance(bKnown)) &&
c->bSuccess(bKnown + percent, skill)) {
rc = c->tripSuccess(victim, skill);
if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
Expand Down
35 changes: 33 additions & 2 deletions code/code/disc/disc_defense.cc
Expand Up @@ -6,16 +6,20 @@


#include "disc_defense.h"
#include "being.h"


CDDefense::CDDefense() :
CDiscipline(),
skAdvancedDefense()
skAdvancedDefense(),
skFocusedAvoidance()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chances are that these constructors, destructors, operator= don't do anything useful and should be deleted.

{
}

CDDefense::CDDefense(const CDDefense &a) :
CDiscipline(a),
skAdvancedDefense(a.skAdvancedDefense)
skAdvancedDefense(a.skAdvancedDefense),
skFocusedAvoidance(a.skFocusedAvoidance)
{
}

Expand All @@ -24,9 +28,36 @@ CDDefense & CDDefense::operator=(const CDDefense &a)
if (this == &a) return *this;
CDiscipline::operator=(a);
skAdvancedDefense = a.skAdvancedDefense;
skFocusedAvoidance = a.skFocusedAvoidance;
return *this;
}

CDDefense::~CDDefense()
{
}

// The larger perc is passed in the harder it is to avoid
bool TBeing::canFocusedAvoidance(int perc) {

if (!doesKnowSkill(SKILL_FOCUSED_AVOIDANCE))
return FALSE;

if (!awake() || getPosition() < POSITION_CRAWLING)
return FALSE;

int skill = getSkillValue(SKILL_FOCUSED_AVOIDANCE);

// Agi seems to be the defense stat so this makes sense
skill *= getAgiMod();

if (eitherLegHurt())
skill = (skill * 0.75);

skill -= perc;

// bSuccess is modified by focus
if (!bSuccess(skill, SKILL_FOCUSED_AVOIDANCE))
return FALSE;

return TRUE;
}
1 change: 1 addition & 0 deletions code/code/disc/disc_defense.h
Expand Up @@ -15,6 +15,7 @@ class CDDefense : public CDiscipline
{
public:
CSkill skAdvancedDefense;
CSkill skFocusedAvoidance;

CDDefense();
CDDefense(const CDDefense &a);
Expand Down
1 change: 1 addition & 0 deletions code/code/misc/being.h
Expand Up @@ -1405,6 +1405,7 @@ class TBeing : public TThing {
bool checkSmashed(TBeing *, wearSlotT, spellNumT, TThing *, int, const char * = NULL);
int hit(TBeing *, int pulse = -1);
bool canCounterMove(int);
bool canFocusedAvoidance(int);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder why these skills live in TBeing? This causes horrible recompilation times for everything, as well as leaking inner workings of disciplines into generic code of beings.

As most things in TBeing are public, maybe it makes more sense to have that code in disciplines?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like all the combat type code is dealing with two objects that are subclasses of TBeing of some sort. So it kind of makes sense to be able to write

if (victim->canFocusedAvoidance(bKnown/2)) {

I guess the other option would just be

if (canFocusedAvoidance(victim, bKnown/2)) {

Just not object oriented. It seems a little easier to reason about in the first instance but if the performance impact is huge the other way it's not a big deal to change it all.

I feel like "Disciplines" or "Abilities" maybe should be a class that is instantiated per being.

int trySpringleap(TBeing *);
int damageLimb(TBeing *, wearSlotT, TThing *, int *);
int damageHand(TBeing *, wearSlotT);
Expand Down
1 change: 1 addition & 0 deletions code/code/misc/info.cc
Expand Up @@ -1519,6 +1519,7 @@ sstring TBeing::describeAffects(TBeing *ch, showMeT showme) const
case SKILL_DISSECT:
case SKILL_DEFENSE:
case SKILL_ADVANCED_DEFENSE:
case SKILL_FOCUSED_AVOIDANCE:
case SKILL_OFFENSE:
case SKILL_WHITTLE:
case SKILL_WIZARDRY:
Expand Down
2 changes: 2 additions & 0 deletions code/code/misc/skills.cc
Expand Up @@ -1182,6 +1182,8 @@ CSkill *TBeing::getSkill(spellNumT skill) const
// disc_defense
case SKILL_ADVANCED_DEFENSE: // 674
return &((CDDefense *) cd)->skAdvancedDefense;
case SKILL_FOCUSED_AVOIDANCE:
return &((CDDefense *) cd)->skFocusedAvoidance;
wershlak marked this conversation as resolved.
Show resolved Hide resolved

// disc_psionics
case SKILL_PSITELEPATHY:
Expand Down
9 changes: 7 additions & 2 deletions code/code/misc/spell_info.cc
Expand Up @@ -1117,8 +1117,6 @@ void buildSpellArray()

discArray[SKILL_DEFENSE] = new spellInfo(SKILL_GENERAL, DISC_ADVENTURING, DISC_ADVENTURING, "defense", TASK_NORMAL, LAG_0, POSITION_SITTING, MANA_0, LIFEFORCE_0, PRAY_0, 0, SYMBOL_STRESS_0, "", "", "", "", START_1, LEARN_1, START_DO_1, LEARN_DO_1, START_DO_NO, LEARN_DO_NO, LEARN_DIFF_UNUSUAL, 0.0, 0, 0);

discArray[SKILL_ADVANCED_DEFENSE] = new spellInfo(SKILL_GENERAL, DISC_DEFENSE, DISC_DEFENSE, "advanced defense", TASK_NORMAL, LAG_0, POSITION_SITTING, MANA_0, LIFEFORCE_0, PRAY_0, 0, SYMBOL_STRESS_0, "", "", "", "", START_1, LEARN_1, START_DO_1, LEARN_DO_1, START_DO_NO, LEARN_DO_NO, LEARN_DIFF_UNUSUAL, 0.0, 0, 0);

discArray[SKILL_OFFENSE] = new spellInfo(SKILL_GENERAL, DISC_ADVENTURING, DISC_ADVENTURING, "offense", TASK_NORMAL, LAG_0, POSITION_SITTING, MANA_0, LIFEFORCE_0, PRAY_0, 0, SYMBOL_STRESS_0, "", "", "", "", START_1, LEARN_1, START_DO_1, LEARN_DO_1, START_DO_NO, LEARN_DO_NO, LEARN_DIFF_UNUSUAL, 0.0, 0, 0);

discArray[SKILL_WHITTLE] = new spellInfo(SKILL_GENERAL, DISC_ADVENTURING, DISC_ADVENTURING, "whittle", TASK_NORMAL, LAG_0, POSITION_STANDING, MANA_0, LIFEFORCE_0, PRAY_0, 0, SYMBOL_STRESS_0, "", "", "", "", START_50, LEARN_2, START_DO_1, LEARN_DO_1, START_DO_NO, LEARN_DO_NO, LEARN_DIFF_UNUSUAL, 0.0, 0, 0);
Expand Down Expand Up @@ -1147,6 +1145,13 @@ void buildSpellArray()

discArray[SKILL_BAREHAND_PROF] = new spellInfo(SKILL_GENERAL, DISC_COMBAT, DISC_COMBAT, "barehand proficiency", TASK_NORMAL, LAG_0, POSITION_DEAD, MANA_0, LIFEFORCE_0, PRAY_0, 0, SYMBOL_STRESS_0, "", "", "", "", START_1, LEARN_1, START_DO_1, LEARN_DO_1, START_DO_NO, LEARN_DO_NO, LEARN_DIFF_UNUSUAL, 0.0, 0, 0);

// disc_defense

discArray[SKILL_ADVANCED_DEFENSE] = new spellInfo(SKILL_GENERAL, DISC_DEFENSE, DISC_DEFENSE, "advanced defense", TASK_NORMAL, LAG_0, POSITION_SITTING, MANA_0, LIFEFORCE_0, PRAY_0, 0, SYMBOL_STRESS_0, "", "", "", "", START_1, LEARN_1, START_DO_1, LEARN_DO_1, START_DO_NO, LEARN_DO_NO, LEARN_DIFF_UNUSUAL, 0.0, 0, 0);

discArray[SKILL_FOCUSED_AVOIDANCE] = new spellInfo(SKILL_GENERAL, DISC_DEFENSE, DISC_DEFENSE, "focused avoidance", TASK_EASY, LAG_0, POSITION_SITTING, MANA_0, LIFEFORCE_0, PRAY_0, 0, SYMBOL_STRESS_0, "", "", "", "", START_1, LEARN_1, START_DO_1, LEARN_DO_1, START_DO_NO, LEARN_DO_NO, LEARN_DIFF_UNUSUAL, 0.0, 0, 0);


// disc_wizardry

discArray[SKILL_WIZARDRY] = new spellInfo(SPELL_MAGE, DISC_WIZARDRY, DISC_WIZARDRY, "wizardry", TASK_NORMAL, LAG_0, POSITION_SLEEPING, MANA_0, LIFEFORCE_0, PRAY_0, 0, SYMBOL_STRESS_0, "", "", "", "", START_1, LEARN_1, START_DO_NO, LEARN_DO_NO, START_DO_NO, LEARN_DO_NO, LEARN_DIFF_UNUSUAL, 0.0, 0, 0);
Expand Down
4 changes: 4 additions & 0 deletions code/code/misc/spell_num.cc
Expand Up @@ -593,6 +593,8 @@ int mapSpellnumToFile(spellNumT stt)
return 381;
case SPELL_CALL_LIGHTNING_DEIKHAN:
return 382;
case SKILL_FOCUSED_AVOIDANCE:
return 390;
case SKILL_YOGINSA:
return 397;
case SKILL_CINTAI:
Expand Down Expand Up @@ -1688,6 +1690,8 @@ spellNumT mapFileToSpellnum(int stt)
return SPELL_EARTHQUAKE_DEIKHAN;
case 382:
return SPELL_CALL_LIGHTNING_DEIKHAN;
case 390:
return SKILL_FOCUSED_AVOIDANCE;
case 397:
return SKILL_YOGINSA;
case 398:
Expand Down
1 change: 1 addition & 0 deletions code/code/misc/spells.h
Expand Up @@ -556,6 +556,7 @@ enum spellNumT {
SKILL_FISHING,
SKILL_LOGGING,
SKILL_ADVANCED_DEFENSE,
SKILL_FOCUSED_AVOIDANCE,
SKILL_MANA,
SKILL_MEND,
SKILL_FORAGE,
Expand Down
6 changes: 6 additions & 0 deletions lib/help/_skills/focused avoidance
@@ -0,0 +1,6 @@
Focused avoidance allows one who is a seasoned combatant to anticipate a foe's
attempt to perform a special attack and avoid it completely. Those with higher
agility and focus will have better success avoiding attacks.

Focused avoidance is passive and attempted at all times.

4 changes: 4 additions & 0 deletions lib/txt/news
@@ -1,3 +1,7 @@
05-01-20 : New Skill! Focused Avoidance is available in the advanced defense
disc. This should help reduce the amount of time warriors and
deikhans spend on their butts.

03-28-20 : Some multiclass fixes:
- Evaluating magic items should use the best skill
- Shaman/Mage combinations can now use the spells command
Expand Down