Skip to content

Commit

Permalink
Fix reaction/initiative aug/magic compatibility (#714)
Browse files Browse the repository at this point in the history
* Fix reaction/initiative aug/magic compatibility

* Use int instead of sbyte

* Update c-cpp.yml

* Fix decking/rigging reaction

* Fix variable name

* Control pool should be based on mental_rea

* Fix decking/rigging reaction/initiative, v2

---------

Co-authored-by: luciensadi <[email protected]>
  • Loading branch information
jdevnull and luciensadi authored Oct 23, 2023
1 parent a1b2a97 commit cd30c0a
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 46 deletions.
16 changes: 1 addition & 15 deletions src/fight.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5599,21 +5599,7 @@ void roll_individual_initiative(struct char_data *ch)
{
if (AWAKE(ch))
{
// While rigging, riggers receive only the modifications given them by the vehicle control rig (see Vehicles and Drones, p. 130) they are using.
if (IS_RIGGING(ch)) {
// Note: Dice don't explode in initiative rolls. This is your base value.
GET_INIT_ROLL(ch) = GET_REAL_REA(ch) + dice(1, 6);

for (struct obj_data *rig = ch->cyberware; rig; rig = rig->next_content) {
if (GET_CYBERWARE_TYPE(rig) == CYB_VCR) {
// Each level adds +2 to the user’s Reaction and +1D6 Initiative dice while rigging. (SR3 p301)
GET_INIT_ROLL(ch) += (GET_CYBERWARE_RATING(rig) * 2) + dice(GET_CYBERWARE_RATING(rig), 6);
break;
}
}
}
else
GET_INIT_ROLL(ch) = roll_default_initiative(ch);
GET_INIT_ROLL(ch) = roll_default_initiative(ch);
GET_INIT_ROLL(ch) -= damage_modifier(ch, buf, sizeof(buf));
if (AFF_FLAGGED(ch, AFF_ACTION)) {
GET_INIT_ROLL(ch) -= 10;
Expand Down
100 changes: 74 additions & 26 deletions src/handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,7 @@ void affect_total(struct char_data * ch)
GET_INIT_DICE(ch) += has_wired;
GET_REA(ch) += has_wired * 2;
}

/* effects of bioware */
for (cyber = ch->bioware; cyber; cyber = cyber->next_content)
{
Expand All @@ -777,10 +778,6 @@ void affect_total(struct char_data * ch)
cyber->obj_flags.bitvector, TRUE);
}

for (sust = GET_SUSTAINED(ch); sust; sust = sust->next)
if (!sust->caster)
spell_modify(ch, sust, TRUE);

for (struct obj_data *bio = ch->bioware; bio; bio = bio->next_content) {
switch (GET_BIOWARE_TYPE(bio)) {
case BIO_PAINEDITOR:
Expand All @@ -796,12 +793,21 @@ void affect_total(struct char_data * ch)
}
}

// We want the higher of either cyber+bio or magic/adept
int aug_rea = GET_REA(ch);
int aug_init_dice = GET_INIT_DICE(ch);
GET_REA(ch) = 0;
GET_INIT_DICE(ch) = 0;

/* effects of magic */
for (sust = GET_SUSTAINED(ch); sust; sust = sust->next)
if (!sust->caster)
spell_modify(ch, sust, TRUE);

if (GET_TRADITION(ch) == TRAD_ADEPT)
{
if (GET_INIT_DICE(ch) == 0)
GET_INIT_DICE(ch) += MIN(3, GET_POWER(ch, ADEPT_REFLEXES));
if (GET_REAL_REA(ch) == GET_REA(ch))
GET_REA(ch) += 2*MIN(3, GET_POWER(ch, ADEPT_REFLEXES));
GET_INIT_DICE(ch) += MIN(3, GET_POWER(ch, ADEPT_REFLEXES));
GET_REA(ch) += 2*MIN(3, GET_POWER(ch, ADEPT_REFLEXES));
GET_BOD(ch) += GET_POWER(ch, ADEPT_IMPROVED_BOD);
GET_QUI(ch) += GET_POWER(ch, ADEPT_IMPROVED_QUI);
GET_STR(ch) += GET_POWER(ch, ADEPT_IMPROVED_STR);
Expand All @@ -823,8 +829,24 @@ void affect_total(struct char_data * ch)
}
}

// We want the higher of either cyber+bio or magic/adept
GET_REA(ch) = (GET_REA(ch) > aug_rea) ? GET_REA(ch) : aug_rea;
GET_INIT_DICE(ch) = (GET_INIT_DICE(ch) > aug_init_dice) ? GET_INIT_DICE(ch) : aug_init_dice;

// Except for VCRs, reaction/initiative augmentations don't apply to rigging (R3 pg 27)
int rigger_rea = 0, rigger_init_dice = 0;

// Let drug rea/init mods apply to rigging
// Unclear in SR3 canon, but is consistent with genre fiction
// Subtract current values, then add post-drug values
rigger_rea -= GET_REA(ch);
rigger_init_dice -= GET_INIT_DICE(ch);

apply_drug_modifiers_to_ch(ch);

rigger_rea += GET_REA(ch);
rigger_init_dice += GET_INIT_DICE(ch);

// Min attribute is one, max is soft capped
int cap = ((ch_is_npc || (GET_LEVEL(ch) >= LVL_ADMIN)) ? 50 : 20);
for (int att = BOD; att <= WIL; att++) {
Expand All @@ -851,6 +873,50 @@ void affect_total(struct char_data * ch)
// We don't cap reaction because qui and int are already capped
GET_REA(ch) += (GET_INT(ch) + GET_QUI(ch)) >> 1;

// When rigging, qui mods don't contribute (R3 pg 27)
rigger_rea += (GET_INT(ch) + GET_REAL_QUI(ch)) >> 1;

// Qui bonus from mbw doesn't increase reaction (MM pg 30)
// Also makes sense that mbw DOES protect from disabling via nervestrike
if (has_mbw) {
GET_QUI(ch) += has_mbw;
GET_REA(ch) += has_mbw * 2;
GET_INIT_DICE(ch) += has_mbw;
}

// Matrix pg 18 & 24, assume pure DNI (thus reaction = intelligence)
// No direct reaction/initiative bonuses from cyber/bio apply (assume no bonuses from magic/adept either)
if (PLR_FLAGGED(ch, PLR_MATRIX)) {
GET_REA(ch) = GET_INT(ch);
GET_INIT_DICE(ch) = 0;
}

// Rigging
if (has_rig) {
// a VCR adds to reaction, thus control pool
rigger_rea += 2 * has_rig;
GET_CONTROL(ch) += rigger_rea;

// also adds to initiative dice
rigger_init_dice += has_rig;

// but reduces hacking pool
GET_HACKING(ch) -= has_rig;
if (GET_HACKING(ch) < 0)
GET_HACKING(ch) = 0;
} else {
// direct control with a datajack and no VCR (SR3 pg 140)
rigger_rea += 1;
}

if (AFF_FLAGGED(ch, AFF_RIG) || PLR_FLAGGED(ch, PLR_REMOTE)) {
GET_REA(ch) = rigger_rea;
GET_INIT_DICE(ch) = rigger_init_dice;
}

// Cap init dice
GET_INIT_DICE(ch) = MAX(0, MIN(GET_INIT_DICE(ch), 5));

// Combat pool is derived from current atts, so we calculate it after all att modifiers
GET_COMBAT(ch) += (GET_QUI(ch) + GET_WIL(ch) + GET_INT(ch)) / 2;
if (GET_TOTALBAL(ch) > GET_QUI(ch))
Expand Down Expand Up @@ -967,28 +1033,10 @@ void affect_total(struct char_data * ch)
}
}

if (has_rig)
{
int reaction = GET_REAL_INT(ch) + GET_REAL_QUI(ch);
for (struct obj_data *bio = ch->bioware; bio; bio = bio->next_content)
if (GET_OBJ_VAL(bio, 0) == BIO_CEREBRALBOOSTER)
reaction += GET_OBJ_VAL(bio, 1);
GET_CONTROL(ch) += (reaction / 2) + (int)(2 * has_rig);
GET_HACKING(ch) -= has_rig;
if (GET_HACKING(ch) < 0)
GET_HACKING(ch) = 0;
}

// Restore their max_hacking and rem_hacking, which were wiped out in the earlier aff_abils = real_abils.
GET_REM_HACKING(ch) = MIN(old_rem_hacking, GET_HACKING(ch));
GET_MAX_HACKING(ch) = MIN(old_max_hacking, GET_HACKING(ch));

if (has_mbw) {
GET_QUI(ch) += has_mbw;
GET_REA(ch) += has_mbw * 2;
GET_INIT_DICE(ch) += has_mbw;
}

// Update current vision to match what's being worn.
if (AFF_FLAGGED(ch, AFF_INFRAVISION)) {
set_vision_bit(ch, VISION_THERMOGRAPHIC, VISION_BIT_FROM_EQUIPMENT);
Expand Down
11 changes: 6 additions & 5 deletions src/newmatrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,19 +197,20 @@ bool spawn_ic(struct matrix_icon *target, vnum_t ic_vnum, int triggerstep) {

void roll_matrix_init(struct matrix_icon *icon)
{
int x = 1;
int init_dice = 1;
if (icon->decker && icon->decker->ch)
{
icon->initiative = GET_REAL_REA(icon->decker->ch) + (icon->decker->response * 2) + (icon->decker->reality ? 2 : 0);
x += icon->decker->response + (icon->decker->reality ? 1 : 0);
// Matrix pg 18 & 24, available bonuses are response increase, reality filter, and hot asist
icon->initiative = GET_REA(icon->decker->ch) + (icon->decker->response * 2) + (icon->decker->reality ? 2 : 0) + (icon->decker->asist[0] ? 2 : 0);
init_dice += GET_INIT_DICE(icon->decker->ch) + icon->decker->response + (icon->decker->reality ? 1 : 0) + (icon->decker->asist[0] ? 1 : 0);
} else
{
icon->initiative = icon->ic.rating;
if (matrix[icon->in_host].shutdown)
icon->initiative--;
x += matrix[icon->in_host].color;
init_dice += matrix[icon->in_host].color;
}
icon->initiative += dice(x, 6);
icon->initiative += dice(init_dice, 6);
icon->initiative -= matrix[icon->in_host].pass * 10;
}

Expand Down

0 comments on commit cd30c0a

Please sign in to comment.