1
0
Fork 0
mirror of https://codeberg.org/noisytoot/notnotdnethack.git synced 2025-05-01 21:05:12 +01:00

add knightly styles

following the etherpad outline wiith minor tweaks

all knights can get expert in any of the 4 style skills: shield bashing, great weapon fighting, half-sword style, and advanced knightly styles
in total, 6 styles exist - those 4, but advanced is one skill for "sacred style", "runic style", and "eldritch style". the same skill is used for the 3, so enhancing/training via any work for the others
all skills can be used when unskilled, they just probably don't do anything (shield/half sword have minor effects), because you need to be in the stance to train it

style breakdown:

shield bashing:
- allows you to make an offhand shield attack when in the style where uarms exists. does not really like two-weaponing + uarms exists, but that shouldn't happen, jsut don't add paired greatshields.... yet
- this shield attack uses hmon and treats this as a proper weapon attack, so it will add enchantment or property bonus damages like a normal weapon attack. this is treated as having a base die of d2/d4/d6/d8 for unskilled->expert skills, and dmod is factored in as normal so a large shield is larger funny numbers
- the whole dmod/damage thing doesn't go SUPER well with the assumption that all shields are one-handed regardless of size (cuz armor slot not weapon slot) but hey, it would be really badass...
- this actually would work well if a shield arti/otyp with bonus damage is added later, or even just a spiked kite shield or something in the knight quest
- note that any shield always has the same damage dice, regardless of size
- the offhand attack also lowers morale by a substantial chunk. caps at -0/-5/-10/-15 for unskilled->expert, dealing 1/1/2/3 points of morale damage each. is this really strong? possibly. I'm not really sure the balance implications of -15 damage to all attacks after 5/6 hits on something, but my logic here is that you're trading a shield with decent but mediocre damage for the debuff, and you'd kill most things in <6 hits anyway. if it lives longer, then the -15 morale is probably justified on that target
- trains shield bash skill by bashing with things, successful hits like any other weapon skill (just added a thing to wtype for shields)

great weapon fighting:
- reduces the minimum roll for bimanual weapons, depending on skill, by 0/1/2/3 for unskilled->expert. so unskilled is no effect, but expert makes d6 always roll 4-6
- this is implemented as NdX becoming Nd(X-i) + N*i, where i is the highest roll we're slicing off. so 3d6 becomes 3d3 + 9. this stacks with both exploding and lucky dice, but NOT exploding lucky dice, because 1. it's probably really strong as-is on an exploding d6 or something, and 2. i'm not fucking with those functions
- possibly the easiest here to use, since it has absolutely no downsides and only upsides. balance-wise, shouldn't actually be too much of a big deal for non-exploding weapons, since this doesn't add any extra damage (by definition) only makes your damage more consistent/raises your avg, not the peak damage
- trained by attacking with bimanual things while its active

half-sword style:
- basically, allows longswords to be shining and two-handed, but locks them to piercing and two-handed.
- the real-life thing apparently involves grasping the middle of the sword with your offhand to help aim/improve your thrusts, so this turns all longswords to bimanual. oversized ones presumably just require two-hands like normal, just positioned differently - ignore the whole thing about "your arms reaching the halfway point".
- this cannot be swapped to or off of with a cursed longsword/no free hands, since it involves repositioning your hands
- the gameplay effects are kind of odd. at first, the issue was "why train past basic if it pierces ac/dr at basic", or s/basic/whatever skill/. so i gave it like, 1d6-3d6 precision damage with skill, so that's a minor damage bonus. then i later implemented the two-handed thing, so now it also has the niche benefit of letting you forcibly two-hand your sword, so if you're fighting with only one sword (no shield or twoweap) then you can get the 2x str bonus + the precision damage. this is probably pretty good, becausee i'ts "free" damage (applies to almost everything), but the actual dmg values are kinda low sooo
- trained by making precision attacks while its active (no bonus damage at unskilled thouhg, just training)

sacred style:
- allows for bonus holy/unholy damage for any weapon
- costs 5 pw/hit, doesn't activate if <5 pw
- deals an extra 1d8/3d8/6d8 holy/unholy damage at basic-expert. unskilled is no damage
- holy/unholy is decided by being holy for holy/neutral gods with good align, or chaotic/void gods with bad align. vice versa for unholy damage
- the damage DOES require the sword to actually BE blessed/cursed, it's not like artifact holy dmg where its always applied and double for vulnerabilities, this extends the normal blessed/cursed item damage (and stacks with it, for things like excalibur etc.)
- trains your advanced techniques when successfully dealing bonus holy/unholy damage (even if no damage is applied bc unskilled)

runic style:
- allows for MR when wielding a long sword above basic skill
- that is it. does not do anything else, can't train it or anything (it woudl train advanced ofc but like, you just can't train it).
- if you are wielding a long sword, if you have above basic skill, and you're in the form -> MR get.

eldritch style:
- allows for extra elemental damage for any weapon
- basically, you select a spell that you know and can cast, and apply its damage type to your weapon
- valid spells are fireball/storm, cone of cold/blizzard, lightning bolt/storm, acid splash, poison spray, finger of death
- they each grant their element damage. dice are 1/3/6 for b/s/e, size is 13 for death, 8 for the storm spells, and 6 otherwise
- note that death checks AD_DARK because.... i think it's cool? and also probably easier htan fuckign with AD_DISN or some shit. i think its appropriate. poison also sets weapont o have basic poison because i want lawful penalties for poison. acid is OK lugh doesnt notice. not like u can easily get acid/poison without BOIS or ana bones, and poison isnt good so its fine
- to actually apply the damage, you must know the spell and have good odds of casting it. i think right now (i realize as i write this) you can probably set the spell, forget it, and it won't unset the damage - so that'll be fixed later, i have to write more messages too so
- the damage is applied with same odds of spell success, so percentage > rn2(100) basically. so a 75% fail rate with expert kni advance skill on finger of death gives a 25% of 6d13 dark damage per hit, 75% nothing. trains skill regardless though. doens't care about attack spell skill unless you need it to cast - so 0% fail artis DO work with this.
- trains every single time you hit with it active, regardless of whether its applying extra damage. i'll change that later to be "every time it would have applied damage if you weren't unskilled" probably.

oh yeah styles are blocked by
sacred, eldritch - nothing (eldritch cares about spell success)
great wep - no bimanual weapon
shield bash - no shield
runic - no long sword
half-sword - no long sword that you can two-hand (i.e. no uarms/twoweap/whatever)

TODO:
- add messages to sacred, eldritch styles
- move skill up code for eldritch styles
- need to double check when sacred/eldritch styles are applying. it SEEMED fine, and it's intentional that they should still work on some thrown items, but it definitely needs to be looked at
- all knights get this. should berith give some of this? i have NO clue. i will 99% chance not add it to anybody else, but for the future. dwarf knights do get this btw
This commit is contained in:
RikerW 2023-09-11 17:39:11 -07:00
parent 483bfb108e
commit de3efe593e
16 changed files with 343 additions and 78 deletions

View file

@ -2831,6 +2831,7 @@ E void FDECL(losespells, (int));
E int NDECL(throwgaze);
E int NDECL(dovspell);
E int NDECL(base_casting_stat);
E int FDECL(percent_success, (int));
E void FDECL(initialspell, (struct obj *));
E void FDECL(initialforgotwizardspells, (int));
E void FDECL(initialforgotpriestspells, (int));

View file

@ -21,6 +21,7 @@ struct weapon_dice {
Bitfield(lucky, 1); /* use luck-biased dice (rnl()) */
Bitfield(exploding, 1); /* use exploding dice */
Bitfield(explode_amt, 3); /* additional amount to increase roll by when dice explode */
Bitfield(ignore_rolls, 2); /* rolls to ignore */
};
/* definition of a class of objects */

View file

@ -129,12 +129,12 @@
#define FIRST_LS_FFORM FFORM_SHII_CHO
#define LAST_LS_FFORM FFORM_JUYO
#define FFORM_SHIELD_BASH 0 + 32
#define FFORM_GREAT_WEP 1 + 32
#define FFORM_HALF_SWORD 2 + 32
#define FFORM_KNI_SACRED 3 + 32
#define FFORM_KNI_RUNIC 4 + 32
#define FFORM_KNI_ELDRITCH 5 + 32
#define FFORM_SHIELD_BASH 1 + 32
#define FFORM_GREAT_WEP 2 + 32
#define FFORM_HALF_SWORD 3 + 32
#define FFORM_KNI_SACRED 4 + 32
#define FFORM_KNI_RUNIC 5 + 32
#define FFORM_KNI_ELDRITCH 6 + 32
#define FIRST_KNI_FFORM FFORM_SHIELD_BASH
#define LAST_KNI_FFORM FFORM_KNI_ELDRITCH

View file

@ -39,6 +39,10 @@ struct spell {
spellid(spell) == SPE_MASS_HEALING || \
spellid(spell) == SPE_CURE_BLINDNESS || spellid(spell) == SPE_FULL_HEALING || \
spellid(spell) == SPE_RESTORE_ABILITY || spellid(spell) == SPE_REMOVE_CURSE)
#define metal_blocks_spellcasting(otmp) (otmp && \
(is_metallic(otmp) || otmp->oartifact == ART_DRAGON_PLATE) && \
!(check_oprop(otmp, OPROP_BRIL) || otmp->otyp == HELM_OF_BRILLIANCE || (otmp->otyp == HELM_OF_TELEPATHY && base_casting_stat() == A_CHA)))
#define FIRST_LIGHT MAXSPELL+1
#define PART_WATER MAXSPELL+2
#define OVERGROW MAXSPELL+3

View file

@ -327,6 +327,17 @@ struct you {
#define FFORM_LISTSIZE (LAST_FFORM/32 + 1)
unsigned long int fightingForm[FFORM_LISTSIZE];/* special properties */
int ueldritch_style;
boolean uavoid_passives;
int umystic; /*Monk mystic attacks active*/
#define monk_style_active(style) (u.umystic & (1 << (style-1)))
#define toggle_monk_style(style) (u.umystic = u.umystic ^ (1 << (style-1)))
#define DIVE_KICK 1
#define AURA_BOLT 2
#define BIRD_KICK 3
#define METODRIVE 4
#define PUMMEL 5
// long laststruck;
long lastmoved;
long lastcast;
@ -654,17 +665,6 @@ struct you {
int divetimer; /* how long you can stay under water */
int role_variant; /*Records what variant of your role you are.*/
boolean uavoid_passives;
int umystic; /*Monk mystic attacks active*/
#define monk_style_active(style) (u.umystic & (1 << (style-1)))
#define toggle_monk_style(style) (u.umystic = u.umystic ^ (1 << (style-1)))
#define DIVE_KICK 1
#define AURA_BOLT 2
#define BIRD_KICK 3
#define METODRIVE 4
#define PUMMEL 5
long wardsknown; /* known wards */
#define WARD_ELBERETH (0x1L<<0)
#define WARD_HEPTAGRAM (0x1L<<1)

View file

@ -86,6 +86,8 @@
#define Antimagic (EAntimagic || HAntimagic || \
(u.usteed && u.usteed->misc_worn_check & W_SADDLE \
&& which_armor(u.usteed, W_SADDLE)->oartifact == ART_HELLRIDER_S_SADDLE) || \
(activeFightingForm(FFORM_KNI_RUNIC) && FightingFormSkillLevel(FFORM_KNI_RUNIC) >= P_BASIC && \
uwep && uwep->otyp == LONG_SWORD) ||\
Nullmagic ||\
(Upolyd && resists_magm(&youmonst)))

View file

@ -2049,6 +2049,9 @@ int fform;
case FFORM_SHII_CHO:
case FFORM_KNI_SACRED:
return FALSE;
/* affected by spell success rate, handled elsewhere */
case FFORM_KNI_ELDRITCH:
return FALSE;
/* blocked by heavy armor */
case FFORM_MAKASHI:
case FFORM_SORESU:
@ -2061,18 +2064,19 @@ int fform;
return (uarm && !(is_light_armor(uarm)));
/* blocked by metal armor */
case FFORM_NIMAN:
case FFORM_KNI_ELDRITCH:
return (uarm && (is_metallic(uarm)));
/* requires longsword */
return (uarm && (metal_blocks_spellcasting(uarm)));
/* requires longsword and free hand */
case FFORM_HALF_SWORD:
return !(uwep && uwep->otyp == LONG_SWORD && !uarms && !(u.twoweap && !bimanual(uwep, youracedata)));
/* require longsword*/
case FFORM_KNI_RUNIC:
return (uwep && uwep->otyp == LONG_SWORD);
return !(uwep && uwep->otyp == LONG_SWORD);
/* requires shield */
case FFORM_SHIELD_BASH:
return (!!uarms);
return (!uarms);
/* requires two-handed weapon */
case FFORM_GREAT_WEP:
return (uwep && bimanual(uwep, youracedata));
return !(uwep && bimanual(uwep, youracedata));
default:
impossible("Attempting to get blockage of fighting form number %d?", fform);
break;

149
src/cmd.c
View file

@ -1007,7 +1007,7 @@ doLightsaberForm()
int curskill;
for (i = FIRST_LS_FFORM; i <= LAST_LS_FFORM; i++) {
if (P_SKILL(getFightingFormSkill(i)) >= P_BASIC)
if (FightingFormSkillLevel(i) >= P_BASIC)
remotely_competent = TRUE;
}
@ -1020,7 +1020,7 @@ doLightsaberForm()
if (remotely_competent){
for (i = FIRST_LS_FFORM; i <= LAST_LS_FFORM; i++) {
curskill = P_SKILL(getFightingFormSkill(i));
curskill = FightingFormSkillLevel(i);
if (curskill >= P_BASIC) {
boolean active = selectedFightingForm(i);
boolean blocked = blockedFightingForm(i);
@ -1068,6 +1068,92 @@ doLightsaberForm()
}
}
int doEldritchKniForm()
{
winid tmpwin;
int n, how, i, j, damagetype, success_odds, spell_id;
char buf[BUFSZ];
char incntlet = 'a';
menu_item *selected;
anything any;
boolean remotely_competent = FALSE;
int curskill = FightingFormSkillLevel(FFORM_KNI_ELDRITCH);;
int spell_list[] = {0, SPE_FIREBALL, SPE_FIRE_STORM, SPE_CONE_OF_COLD, SPE_BLIZZARD,
SPE_LIGHTNING_BOLT, SPE_LIGHTNING_STORM, SPE_ACID_SPLASH, SPE_POISON_SPRAY, SPE_FINGER_OF_DEATH, 0};
for (i = 1; spell_list[i]; i++)
for (j = 0; j < MAXSPELL; j++)
if (spellid(j) == spell_list[i] && spellknow(j) > 0)
remotely_competent = TRUE;
if (!remotely_competent){
pline("You don't know any appropriate spells!");
return MOVE_CANCELLED;
} else {
setFightingForm(FFORM_KNI_ELDRITCH);
}
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
any.a_void = 0; /* zero out all bits */
Sprintf(buf, "Known Eldritch Styles");
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED);
for (i = 1; spell_list[i]; i++) {
for (spell_id = 0; spell_id < MAXSPELL; spell_id++)
if (spellid(spell_id) == spell_list[i])
break;
if (spell_id >= MAXSPELL || spellknow(spell_id) <= 0)
continue;
success_odds = percent_success(spell_id);
Strcpy(buf, spellname(spell_id));
Strcat(buf, " (");
if (success_odds <= 0)
Strcat(buf, "impossible");
else if (success_odds < 25)
Strcat(buf, "very difficult");
else if (success_odds < 50)
Strcat(buf, "difficult");
else if (success_odds < 75)
Strcat(buf, "moderate");
else if (success_odds < 95)
Strcat(buf, "easy");
else
Strcat(buf, "trivial");
Strcat(buf, ")");
any.a_int = i; /* must be non-zero */
add_menu(tmpwin, NO_GLYPH, &any,
incntlet, 0, ATR_NONE, buf,
MENU_UNSELECTED);
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
end_menu(tmpwin, "Choose preferred eldritch style:");
how = PICK_ONE;
n = select_menu(tmpwin, how, &selected);
destroy_nhwindow(tmpwin);
if(n <= 0 ){
return MOVE_CANCELLED;
} else {
if (spell_list[selected[0].item.a_int] == u.ueldritch_style){
free(selected);
return MOVE_CANCELLED;
} else {
u.ueldritch_style = spell_list[selected[0].item.a_int];
free(selected);
return MOVE_INSTANT;
}
}
return MOVE_CANCELLED;
}
int doKnightForm()
{
winid tmpwin;
@ -1078,9 +1164,10 @@ int doKnightForm()
anything any;
boolean remotely_competent = FALSE;
int curskill;
char* block_reason;
for (i = FIRST_KNI_FFORM; i <= LAST_KNI_FFORM; i++) {
if (P_SKILL(getFightingFormSkill(i)) >= P_BASIC)
if (FightingFormSkillLevel(i) >= P_BASIC)
remotely_competent = TRUE;
}
@ -1088,24 +1175,41 @@ int doKnightForm()
start_menu(tmpwin);
any.a_void = 0; /* zero out all bits */
Sprintf(buf, "Known Knightly Styles");
Sprintf(buf, "Known Knightly Styles");
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED);
for (i = FIRST_KNI_FFORM; i <= LAST_KNI_FFORM; i++) {
curskill = P_SKILL(getFightingFormSkill(i));
if (curskill >= P_BASIC) {
curskill = FightingFormSkillLevel(i);
/* knight forms are shown if unskilled but not restricted, since training involves starting from unskilled */
if (curskill >= P_UNSKILLED) {
boolean active = selectedFightingForm(i);
boolean blocked = blockedFightingForm(i);
Strcpy(buf, nameOfFightingForm(i));
Strcat(buf, " (");
Strcat(buf, (curskill >= P_EXPERT) ? "expert" : ((curskill >= P_SKILLED) ? "skilled" : "basic"));
if (active && blocked)
Strcat(buf, ", selected; blocked by armor");
Strcat(buf, (curskill >= P_EXPERT) ? "expert" : ((curskill >= P_SKILLED) ? "skilled" :
((curskill >= P_BASIC) ? "basic" : "unskilled")));
if (i == FFORM_SHIELD_BASH)
block_reason = "lack of a shield";
else if (i == FFORM_HALF_SWORD || i == FFORM_KNI_RUNIC)
block_reason = "lack of a longsword";
else if (i == FFORM_GREAT_WEP)
block_reason = "lack of a two-handed weapon";
else if (i == FFORM_KNI_ELDRITCH)
block_reason = "your metallic armor";
if (active && blocked){
Strcat(buf, ", selected; blocked by ");
Strcat(buf, block_reason);
}
else if (active)
Strcat(buf, ", active");
else if (blocked)
Strcat(buf, ", blocked by armor");
else if (blocked){
Strcat(buf, ", blocked by ");
Strcat(buf, block_reason);
}
Strcat(buf, ")");
any.a_int = i; /* must be non-zero */
@ -1115,14 +1219,23 @@ int doKnightForm()
incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
}
}
end_menu(tmpwin, "Choose preferred fighting style:");
end_menu(tmpwin, "Choose preferred fighting style:");
how = PICK_ONE;
n = select_menu(tmpwin, how, &selected);
destroy_nhwindow(tmpwin);
if(n <= 0 || selectedFightingForm(selected[0].item.a_int)){
if(n>0) free(selected);
if(n <= 0){
return MOVE_CANCELLED;
} else if ((selected[0].item.a_int == FFORM_HALF_SWORD || activeFightingForm(FFORM_HALF_SWORD)) &&
(!freehand() || (uwep && uwep->otyp == LONG_SWORD && welded(uwep)))){
pline("You need a free hand to adjust your grip!");
return MOVE_CANCELLED;
} else if (selected[0].item.a_int == FFORM_KNI_ELDRITCH){
free(selected);
return doEldritchKniForm();
} else if (selectedFightingForm(selected[0].item.a_int)) {
free(selected);
return MOVE_CANCELLED;
} else {
setFightingForm(selected[0].item.a_int);
@ -1158,8 +1271,8 @@ dofightingform()
/* forms relevant due to situation/role are shown, even if you're bad at them (if applicable) */
if(Role_if(PM_MONK))
monk_forms = TRUE;
/*if(Role_if(PM_KNIGHT))
knight_forms = TRUE;*/
if(Role_if(PM_KNIGHT))
knight_forms = TRUE;
if((uwep && is_lightsaber(uwep)) || (uswapwep && is_lightsaber(uswapwep)))
lightsaber_forms = TRUE;
if (u.uavoid_passives)
@ -1175,12 +1288,12 @@ dofightingform()
/* next, forms trained are shown, even if inapplicable at the moment*/
for (i = FIRST_LS_FFORM; i <= LAST_LS_FFORM; i++) {
if (P_SKILL(getFightingFormSkill(i)) >= P_BASIC)
if (FightingFormSkillLevel(i) >= P_BASIC)
lightsaber_forms = TRUE;
}
for (i = FIRST_KNI_FFORM; i <= LAST_KNI_FFORM; i++) {
if (P_SKILL(getFightingFormSkill(i)) >= P_BASIC)
if (FightingFormSkillLevel(i) >= P_BASIC)
knight_forms = TRUE;
}

View file

@ -2575,7 +2575,7 @@ donull()
{
static long lastreped = -13;//hacky way to tell if the player has recently tried repairing themselves
u.unull = TRUE;
if(uclockwork){
if(!Upolyd && u.uhp<u.uhpmax){
if(lastreped < monstermoves-13) You("attempt to make repairs.");

View file

@ -1819,10 +1819,9 @@ boolean noisy;
if (noisy) already_wearing(an(c_shield));
err++;
} else if (uwep && bimanual(uwep,youracedata)) {
const char *term = is_sword(uwep) ? c_sword : (uwep->otyp == BATTLE_AXE) ? c_axe : c_weapon;
if (noisy)
You("cannot wear a shield while wielding a two-handed %s.",
is_sword(uwep) ? c_sword :
(uwep->otyp == BATTLE_AXE) ? c_axe : c_weapon);
You("cannot wear a shield while wielding %s in both hands.", an(term));
err++;
} else if (u.twoweap) {
if (noisy)

View file

@ -30,7 +30,6 @@ STATIC_DCL boolean FDECL(spiritLets, (char *, int));
STATIC_DCL int FDECL(dospiritmenu, (int, int *, int));
STATIC_DCL boolean FDECL(dospellmenu, (int,int *));
STATIC_DCL void FDECL(describe_spell, (int));
STATIC_DCL int FDECL(percent_success, (int));
STATIC_DCL int NDECL(throwspell);
STATIC_DCL void NDECL(cast_protection);
STATIC_DCL void NDECL(cast_abjuration);
@ -5882,7 +5881,7 @@ base_casting_stat()
return stat;
}
STATIC_OVL int
int
percent_success(spell)
int spell;
{
@ -6060,11 +6059,11 @@ int spell;
if (uarm){
if(arm_blocks_upper_body(uarm->otyp)){
if ((is_metallic(uarm) || uarm->oartifact == ART_DRAGON_PLATE) && !check_oprop(uarm, OPROP_BRIL))
if (metal_blocks_spellcasting(uarm))
splcaster += casting_stat == A_CHA ? uarmgbon : urole.spelarmr;
}
else {
if ((is_metallic(uarm) || uarm->oartifact == ART_DRAGON_PLATE) && !check_oprop(uarm, OPROP_BRIL))
if (metal_blocks_spellcasting(uarm))
splcaster += uarmfbon;
}
@ -6074,11 +6073,11 @@ int spell;
if (uarmu){
if(arm_blocks_upper_body(uarmu->otyp)){
if (is_metallic(uarmu) && !check_oprop(uarmu, OPROP_BRIL))
if (metal_blocks_spellcasting(uarmu))
splcaster += casting_stat == A_CHA ? uarmgbon : urole.spelarmr;
}
else {
if (is_metallic(uarmu) && !check_oprop(uarmu, OPROP_BRIL))
if (metal_blocks_spellcasting(uarmu))
splcaster += uarmfbon;
}
}
@ -6090,17 +6089,16 @@ int spell;
splcaster -= 2;
if (uarmc->otyp == SMOKY_VIOLET_FACELESS_ROBE)
splcaster -= 4;
if (uarmc->otyp == ROBE)
splcaster -= (urole.spelarmr
* ((uarmc->oartifact) ? 2 : 1)
/ ((uarm && (is_metallic(uarm) || uarm->oartifact == ART_DRAGON_PLATE) && !check_oprop(uarm, OPROP_BRIL)) ? 2 : 1));
if (is_metallic(uarmc) && !check_oprop(uarmc, OPROP_BRIL))
if (uarmc->otyp == ROBE){
splcaster -= (urole.spelarmr * ((uarmc->oartifact) ? 2 : 1) / ((metal_blocks_spellcasting(uarm)) ? 2 : 1));
}
if (metal_blocks_spellcasting(uarmc))
splcaster += uarmfbon;
}
if (uarmh && !Role_if(PM_MONK)) {
//Something up with madmen and this, it doesn't affect much.
if (is_metallic(uarmh) && uarmh->otyp != HELM_OF_BRILLIANCE && (uarmh->otyp != HELM_OF_TELEPATHY && casting_stat == A_CHA) && !check_oprop(uarmh, OPROP_BRIL)){
if (metal_blocks_spellcasting(uarmh)){
if(casting_stat == A_CHA){
splcaster += FacelessHelm(uarmh) ? 4*urole.spelarmr :
(uarmh->otyp == find_gcirclet()) ? urole.spelarmr/2 :
@ -6118,13 +6116,13 @@ int spell;
if(is_hard(uarmg) && uarmg->oartifact != ART_PREMIUM_HEART && uarmg->oartifact != ART_GODHANDS)
splcaster += uarmgbon;
}
else if (is_metallic(uarmg) && !check_oprop(uarmg, OPROP_BRIL)){
else if (metal_blocks_spellcasting(uarmg)){
splcaster += casting_stat == A_CHA ? uarmfbon : uarmgbon;
}
}
if (uarmf && !Role_if(PM_MONK)) {
if (is_metallic(uarmf) && !check_oprop(uarmf, OPROP_BRIL))
if (metal_blocks_spellcasting(uarmf))
splcaster += uarmfbon;
}
@ -6193,7 +6191,7 @@ int spell;
* to cast a spell. The penalty is not quite so bad for the
* player's role-specific spell.
*/
if (uarms && casting_stat != A_CHA && (is_metallic(uarms) || weight(uarms) > (int) objects[BUCKLER].oc_weight)) {
if (uarms && casting_stat != A_CHA && ((metal_blocks_spellcasting(uarms)) || weight(uarms) > (int) objects[BUCKLER].oc_weight)) {
if (spellid(spell) == urole.spelspec) {
chance /= 2;
} else {

View file

@ -1221,6 +1221,14 @@ static const struct def_skill Skill_K[] = {
{ P_NONE, 0 }
};
static const struct def_skill Skill_Kni_Forms[] = {
{ P_SHIELD_BASH, P_EXPERT },
{ P_GREAT_WEP, P_EXPERT },
{ P_HALF_SWORD, P_EXPERT },
{ P_KNI_ADVANCED, P_EXPERT },
{ P_NONE, 0 }
};
static const struct def_skill Skill_Mon[] = {
{ P_QUARTERSTAFF, P_EXPERT }, { P_SPEAR, P_BASIC },
{ P_SHURIKEN, P_EXPERT }, { P_HARVEST, P_EXPERT },
@ -2255,6 +2263,8 @@ u_init()
HJumping |= FROMOUTSIDE;
if(Race_if(PM_DWARF)) skill_init(Skill_DwaNob);
else skill_init(Skill_K);
skill_add(Skill_Kni_Forms);
break;
case PM_MONK:
u.umartial = TRUE;

View file

@ -344,6 +344,10 @@ struct monst *magr;
))){
attackmask |= PIERCE;
}
if (youagr && otyp == LONG_SWORD && activeFightingForm(FFORM_HALF_SWORD)){
attackmask = PIERCE; // only thrusting
}
if ( oartifact == ART_LIECLEAVER
|| oartifact == ART_INFINITY_S_MIRRORED_ARC
|| oartifact == ART_GREAT_CLAWS_OF_URDLEN
@ -436,12 +440,13 @@ struct monst *magr;
boolean lucky;
boolean exploding;
int explode_amt;
int ignore_rolls;
if (obj && (!valid_weapon(obj) || is_launcher(obj))){
struct weapon_dice nulldice = {0};
*wdice = nulldice;
ocn = wdice->oc_damn = 1;
ocd = wdice->oc_damd = 2;
bonn = bond = flat = lucky = exploding = explode_amt = 0;
bonn = bond = flat = lucky = exploding = explode_amt = ignore_rolls = 0;
}
else {
/* grab dice from the objclass definition */
@ -454,6 +459,7 @@ struct monst *magr;
lucky = (wdice->lucky);
exploding = (wdice->exploding);
explode_amt = (wdice->explode_amt);
ignore_rolls = (wdice->ignore_rolls);
}
/* set dmod, if possible*/
@ -515,6 +521,14 @@ struct monst *magr;
ocd = max(12 + 2 * dmod, 2);
}
/* shield bash skill buffs shield damage to d4/6/8 with skill, affected by dmod */
if (is_shield(obj) && magr == &youmonst && activeFightingForm(FFORM_SHIELD_BASH)){
ocn = 1;
ocd = max(2, 2 * FightingFormSkillLevel(FFORM_SHIELD_BASH)); // 2-8 for unskilled-expert
} else if (magr == &youmonst && bimanual(obj, youracedata) && activeFightingForm(FFORM_GREAT_WEP)){
ignore_rolls = max(0, FightingFormSkillLevel(FFORM_GREAT_WEP) - 1); // 0-3 for unskilled-expert
}
if (otyp == HEAVY_IRON_BALL) {
int wt = (int)objects[HEAVY_IRON_BALL].oc_weight;
@ -984,6 +998,7 @@ struct monst *magr;
(wdice->lucky) = lucky;
(wdice->exploding) = exploding;
(wdice->explode_amt) = explode_amt;
(wdice->ignore_rolls) = ignore_rolls;
return spe_mult;
}
@ -1015,6 +1030,7 @@ struct weapon_dice * wdie;
boolean youdef;
{
int tmp = 0;
int igrolls = wdie->ignore_rolls;
/* verify there are appropriate dice to roll */
if (!n)
@ -1027,25 +1043,29 @@ boolean youdef;
/* determine function to use */
if (!wdie->exploding && !wdie->lucky) {
/* standard dice */
tmp += d(n, x);
tmp += d(n, x-igrolls);
tmp += n*igrolls;
}
else if (wdie->exploding && !wdie->lucky) {
/* exploding non-lucky dice */
tmp += exploding_d(n, x, wdie->explode_amt);
/* great weapon fighting is a LARGE buff to these. possibly too strong */
tmp += exploding_d(n, x-igrolls, wdie->explode_amt);
tmp += n*igrolls;
}
else if (!wdie->exploding && wdie->lucky) {
/* lucky non-exploding dice */
int i;
for (i = n; i; i--)
{
tmp += youdef ?
(rnl(x) + 1) :
(x - rnl(x));
tmp += youdef ? (rnl(x-igrolls) + igrolls + 1) : (x - rnl(x-igrolls));
}
}
else if (wdie->exploding && wdie->lucky) {
/* EXTEMELY POTENT exploding lucky dice */
tmp += (youdef ? unlucky_exploding_d : lucky_exploding_d)(n, x, wdie->explode_amt);
/* going to be honest - no CLUE what the distr with GWF turned on does,
* but if you manage to get that, it's probably stupid or deserved */
tmp += (youdef ? unlucky_exploding_d : lucky_exploding_d)(n, x-igrolls, wdie->explode_amt);
tmp += n*igrolls;
}
return tmp;
}
@ -1334,9 +1354,37 @@ struct monst *magr;
}
}
/*
* shield bash morale damage
* morale damag values _should_ be reasonable?
* idk, I think with endgame dps builds you mostly kill things in <5 turns, so you're not really hitting max stacks.
* plus, since this prevents you from running extra holy damage or smth
* it also seems pretty reasonable vs. like demon lords/similar - anything that lives to -15 hits hard enough to deserve it
*/
if (is_shield(otmp) && magr == &youmonst && activeFightingForm(FFORM_SHIELD_BASH)){
switch (FightingFormSkillLevel(FFORM_SHIELD_BASH)){
case P_ISRESTRICTED:
case P_UNSKILLED:
if (mon->encouraged > 0) mon->encouraged -= 1;
break;
case P_BASIC:
if (mon->encouraged > -5) mon->encouraged -= 1;
break;
case P_SKILLED:
if (mon->encouraged > -10) mon->encouraged -= 2;
break;
case P_EXPERT:
if (mon->encouraged > -15) mon->encouraged -= 3;
break;
}
}
/* enchantment damage */
if ((otmp->oclass == WEAPON_CLASS) || is_weptool(otmp) || (otmp->otyp >= LUCKSTONE && otmp->otyp <= ROCK && otmp->ovar1_projectileSkill == -P_FIREARM))
{
if ((otmp->oclass == WEAPON_CLASS) || is_weptool(otmp)
|| (otmp->otyp >= LUCKSTONE && otmp->otyp <= ROCK && otmp->ovar1_projectileSkill == -P_FIREARM)
|| (is_shield(otmp) && magr == &youmonst && activeFightingForm(FFORM_SHIELD_BASH))
){
int dambon = otmp->spe;
/* player orcs can use their level as their weapon's enchantment */
if (otmp->where == OBJ_INVENT && Race_if(PM_ORC))
@ -3451,6 +3499,8 @@ struct obj *obj;
#endif /* CONVICT */
if ((obj->otyp == CHAIN) && (Role_if(PM_CONVICT) || u.sealsActive&SEAL_AHAZU))
return objects[obj->otyp].oc_skill;
if (is_shield(obj) && activeFightingForm(FFORM_SHIELD_BASH))
return P_SHIELD_BASH; // not P_SHIELD, that's for defensive uses
if (obj->oclass != WEAPON_CLASS && obj->oclass != TOOL_CLASS &&
obj->oclass != GEM_CLASS && obj->oartifact != ART_WAND_OF_ORCUS)
/* Not a weapon, weapon-tool, or ammo */

View file

@ -150,11 +150,10 @@ boolean quietly; /* hide the basic message saying what you are now wielding */
mons[wep->corpsenm].mname, makeplural(body_part(HAND)));
Sprintf(kbuf, "%s corpse", an(mons[wep->corpsenm].mname));
instapetrify(kbuf);
} else if (uarms && bimanual(wep,youracedata))
You("cannot wield a two-handed %s while wearing a shield.",
is_sword(wep) ? "sword" :
wep->otyp == BATTLE_AXE ? "axe" : "weapon");
else if (wep->otyp == ARM_BLASTER && uarmg && is_metallic(uarmg))
} else if (uarms && bimanual(wep,youracedata)){
char* term = is_sword(wep) ? "sword" : wep->otyp == BATTLE_AXE ? "axe" : "weapon";
You("cannot wield %s in both hands while wearing a shield.", an(term));
} else if (wep->otyp == ARM_BLASTER && uarmg && is_metallic(uarmg))
You("cannot fit the bracer over such bulky, rigid gloves.");
else if (wep->oartifact == ART_KUSANAGI_NO_TSURUGI && !(u.ulevel >= 30 || u.uhave.amulet)) {
pline("Only a Shogun, or a bearer of the Amulet of Yendor, is truly worthy of wielding this sword.");
@ -587,6 +586,8 @@ test_twoweapon()
You_cant("fight two-handed with this.");
}
/* cannot be wearing a shield */
else if (uarms && activeFightingForm(FFORM_SHIELD_BASH))
You("are already using a shield to bash enemies.");
else if (uarms)
You_cant("use two weapons while wearing a shield.");
/* cannot fit armblaster over metal gloves */
@ -976,6 +977,10 @@ struct permonst * ptr;
if (ptr && always_one_hand_mtyp(ptr))
return FALSE;
/* half-sword style requires both hands on the sword, regardless of size */
if (ptr == youracedata && otmp->otyp == LONG_SWORD && selectedFightingForm(FFORM_HALF_SWORD))
return TRUE;
/* get object size */
size_mod = objects[otmp->otyp].oc_size - MZ_MEDIUM;

View file

@ -572,7 +572,7 @@ int tary;
/* Generalized offhand attack when not allowed */
if ((attk->offhand) && ( // offhand attack
(youagr && (uarms || (uwep && bimanual(uwep, youracedata)))) || // player attacking with shield
(youagr && ((uarms && !activeFightingForm(FFORM_SHIELD_BASH)) || (uwep && bimanual(uwep, youracedata)))) || // player attacking with shield
(!youagr && (which_armor(magr, W_ARMS) || (MON_WEP(magr) && bimanual(MON_WEP(magr), pa)))) // monster attacking with shield
)
) {
@ -635,7 +635,7 @@ int tary;
}
/* 2: Offhand attack when not allowed */
if ((aatyp == AT_XWEP || aatyp == AT_XSPR) && ( // offhand attack
(youagr && !u.twoweap) || // player attacking and choosing not to twoweapon
(youagr && !(u.twoweap || activeFightingForm(FFORM_SHIELD_BASH))) || // player attacking and choosing not to twoweapon
(!youagr && (which_armor(magr, W_ARMS) || (MON_WEP(magr) && bimanual(MON_WEP(magr), pa)))) // monster attacking and cannot twoweapon (wearing shield)
)
) {
@ -657,7 +657,7 @@ int tary;
}
else if (aatyp == AT_XWEP) {
/* offhand */
otmp = (youagr) ? uswapwep : MON_SWEP(magr);
otmp = (youagr) ? (u.twoweap ? uswapwep : uarms) : MON_SWEP(magr);
}
else if (aatyp == AT_MARI) {
if(youagr && !uwep && !(u.twoweap && uswapwep)){
@ -1689,7 +1689,7 @@ int * tohitmod; /* some attacks are made with decreased accuracy */
/* if the player IS polymorphed, they are limited to their polyform's attacks */
/* some things give the player additional weapon attacks; they can reset SUBOUT_XWEP to allow another offhand hit if unpoly'd */
/* stilettos and wind and fire wheels add extra damage instead */
if (!by_the_book && *indexnum > 0 && u.twoweap
if (!by_the_book && *indexnum > 0 && (u.twoweap || activeFightingForm(FFORM_SHIELD_BASH))
&& !(uwep && (uwep->otyp == STILETTOS || uwep->otyp == WIND_AND_FIRE_WHEELS))
) {
/* follow a weapon attack with an offhand attack */
@ -3931,6 +3931,8 @@ int *shield_margin;
if ((youagr && u.sealsActive&SEAL_CHUPOCLOPS && (melee || thrust)) ||
(!youagr && magr && mad_monster_turn(magr, MAD_NON_EUCLID)) ||
(weapon && arti_shining(weapon)) ||
(melee && youagr && weapon && weapon->otyp == LONG_SWORD && activeFightingForm(FFORM_HALF_SWORD)
&& FightingFormSkillLevel(FFORM_HALF_SWORD) >= P_BASIC) ||
(melee && attk->aatyp == AT_TUCH) ||
(melee && attk->aatyp == AT_VINE) ||
(melee && spirit_rapier_at(attk->aatyp)) ||
@ -13291,6 +13293,9 @@ int vis; /* True if action is at all visible to the player */
/* Spellbooks are weapons if you have Paimon bound */
else if (melee && weapon && weapon->oclass == SPBOOK_CLASS && youagr && u.sealsActive&SEAL_PAIMON)
valid_weapon_attack = TRUE;
/* shield bashes are possibly if and only if using the style (youagr only) */
else if (melee && weapon && is_shield(weapon) && youagr && activeFightingForm(FFORM_SHIELD_BASH))
valid_weapon_attack = TRUE;
else
invalid_weapon_attack = TRUE;
}
@ -13839,6 +13844,8 @@ int vis; /* True if action is at all visible to the player */
else
poisons |= OPOISON_BASIC;
}
if (youagr && poisonedobj == uwep && activeFightingForm(FFORM_KNI_ELDRITCH) && u.ueldritch_style == AD_DRST)
poisons |= OPOISON_BASIC;
}
/* All AD_SHDW attacks are poisoned as well */
if (attk && attk->adtyp == AD_SHDW) {
@ -14740,6 +14747,8 @@ int vis; /* True if action is at all visible to the player */
phase_armor = (
(weapon && arti_shining(weapon)) ||
(youagr && u.sealsActive&SEAL_CHUPOCLOPS) ||
(youagr && weapon && weapon->otyp == LONG_SWORD && activeFightingForm(FFORM_HALF_SWORD)
&& FightingFormSkillLevel(FFORM_HALF_SWORD) >= P_BASIC) ||
(!youagr && magr && mad_monster_turn(magr, MAD_NON_EUCLID)) ||
(originalattk && spirit_rapier_at(originalattk->aatyp) && originalattk->adtyp != AD_BLUD && originalattk->adtyp != AD_WET) ||
(swordofblood) /* this touch adtyp is only conditionally phasing */
@ -14812,6 +14821,47 @@ int vis; /* True if action is at all visible to the player */
if(uarmg && uarmg->otyp == IMPERIAL_ELVEN_GAUNTLETS && check_imp_mod(uarmg, IEA_INC_DAM))
bonsdmg += uarmg->spe;
/* to make half-sword style actually useful to enhance, give it bonus precision damage*/
if (weapon && weapon->otyp == LONG_SWORD && activeFightingForm(FFORM_HALF_SWORD) && !noanatomy(pd)){
if (FightingFormSkillLevel(FFORM_HALF_SWORD) >= P_BASIC)
bonsdmg += d(max(1, FightingFormSkillLevel(FFORM_HALF_SWORD)-1), 6); // 1d6-3d6 at basic-expert, not bad for 'free'
use_skill(P_HALF_SWORD, 1);
}
/* due to lack of a nicer place, check for eldritch style bonuses here*/
#define eld_bon_dice ((FightingFormSkillLevel(FFORM_KNI_ELDRITCH) >= P_EXPERT) ? 6 : (FightingFormSkillLevel(FFORM_KNI_ELDRITCH) >= P_SKILLED ? 3 : 1))
#define eld_bon_size ((u.ueldritch_style == SPE_FINGER_OF_DEATH) ? 13 : (\
(u.ueldritch_style == SPE_FIRE_STORM || u.ueldritch_style == SPE_BLIZZARD || u.ueldritch_style == SPE_LIGHTNING_STORM) ? 8 : 6))
if (weapon && activeFightingForm(FFORM_KNI_ELDRITCH)){
if (FightingFormSkillLevel(FFORM_KNI_ELDRITCH) >= P_BASIC){
boolean resist_check = FALSE;
int spell_id;
if (u.ueldritch_style == SPE_FIREBALL || u.ueldritch_style == SPE_FIRE_STORM)
resist_check = Fire_res(mdef);
else if (u.ueldritch_style == SPE_CONE_OF_COLD || u.ueldritch_style == SPE_BLIZZARD)
resist_check = Cold_res(mdef);
else if (u.ueldritch_style == SPE_LIGHTNING_BOLT || u.ueldritch_style == SPE_LIGHTNING_STORM)
resist_check = Shock_res(mdef);
else if (u.ueldritch_style == SPE_ACID_SPLASH)
resist_check = Acid_res(mdef);
else if (u.ueldritch_style == SPE_POISON_SPRAY)
resist_check = Poison_res(mdef);
else if (u.ueldritch_style == SPE_FINGER_OF_DEATH)
resist_check = Dark_res(mdef);
for (spell_id = 0; spell_id < MAXSPELL; spell_id++)
if (spellid(spell_id) == u.ueldritch_style)
break;
if (spell_id < MAXSPELL && percent_success(spell_id) > rn2(100)){
if (!resist_check && u.uen >= objects[u.ueldritch_style].oc_level){
bonsdmg += d(eld_bon_dice, eld_bon_size);
u.uen -= objects[u.ueldritch_style].oc_level;
}
}
}
use_skill(P_KNI_ADVANCED, 1);
}
/* when bound, Dantalion gives bonus "precision" damage based on INT; 1x for all melee and ranged */
if ((u.sealsActive&SEAL_DANTALION) && !noanatomy(pd)) {
if (ACURR(A_INT) == 25) bonsdmg += 8;
@ -14888,6 +14938,8 @@ int vis; /* True if action is at all visible to the player */
wtype = P_PICK_AXE;
else if (weapon && weapon->otyp == KAMEREL_VAJRA && !litsaber(weapon))
wtype = P_MACE;
else if (weapon && is_shield(weapon) && activeFightingForm(FFORM_SHIELD_BASH))
wtype = P_SHIELD_BASH;
else if (weapon && (!valid_weapon(weapon) || is_launcher(weapon))){
if (weapon && check_oprop(weapon, OPROP_BLADED))
wtype = P_AXE;
@ -14933,6 +14985,8 @@ int vis; /* True if action is at all visible to the player */
/* now, train skills */
use_skill((melee && u.twoweap) ? P_TWO_WEAPON_COMBAT : wtype, 1);
if (weapon && bimanual(weapon, youracedata) && activeFightingForm(FFORM_GREAT_WEP))
use_skill(P_GREAT_WEP, 1);
if (melee && weapon && is_lightsaber(weapon) && litsaber(weapon) && P_SKILL(wtype) >= P_BASIC){
use_skill(P_SHII_CHO, 1);

View file

@ -1465,6 +1465,19 @@ struct obj * otmp;
dmg += vd(1, 10) + otmp->spe;
else if (otmp->oartifact == ART_VAMPIRE_KILLER)
dmg += 7;
#define sacred_bonus_dice ((FightingFormSkillLevel(FFORM_KNI_SACRED) >= P_EXPERT) ? 6 : (FightingFormSkillLevel(FFORM_KNI_SACRED) >= P_SKILLED ? 3 : 1))
if (activeFightingForm(FFORM_KNI_SACRED) && otmp->otyp == LONG_SWORD){
if (((Holiness_if(HOLY_HOLINESS) || Holiness_if(NEUTRAL_HOLINESS)) && u.ualign.record >= 0) ||
((Holiness_if(UNHOLY_HOLINESS) || Holiness_if(VOID_HOLINESS)) && u.ualign.record < 0)){
if (FightingFormSkillLevel(FFORM_KNI_SACRED) >= P_BASIC && u.uen >= 5){
dmg += vd(sacred_bonus_dice, 8); // 1d8/3d8/6d8 for basic/skilled/expert
u.uen -= 5;
}
use_skill(P_KNI_ADVANCED, 1);
}
}
/* special cases that do affect dice */
if (otmp->oartifact == ART_AMHIMITL)
ndice = 3;
@ -1507,6 +1520,17 @@ struct obj * otmp;
else if (otmp->oartifact == ART_TECPATL_OF_HUHETOTL) /* SCOPECREEP: add ART_TECPATL_OF_HUHETOTL to is_unholy() macro */
{ ndice = (otmp->cursed ? 4 : 2); diesize = 4; }
if (activeFightingForm(FFORM_KNI_SACRED) && otmp->otyp == LONG_SWORD){
if (((Holiness_if(HOLY_HOLINESS) || Holiness_if(NEUTRAL_HOLINESS)) && u.ualign.record < 0) ||
((Holiness_if(UNHOLY_HOLINESS) || Holiness_if(VOID_HOLINESS)) && u.ualign.record >= 0)){
if (FightingFormSkillLevel(FFORM_KNI_SACRED) >= P_BASIC && u.uen >= 5){
dmg += vd(sacred_bonus_dice, 8); // 1d8/3d8/6d8 for basic/skilled/expert
u.uen -= 5;
}
use_skill(P_KNI_ADVANCED, 1);
}
}
#undef sacred_bonus_dice
if (otmp->otyp == KHAKKHARA)
ndice *= khakharadice;
/* gold has a particular affinity to blessings and curses */