diff --git a/src/fight.cpp b/src/fight.cpp
index f01c6e100..7eaa085e5 100644
--- a/src/fight.cpp
+++ b/src/fight.cpp
@@ -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;
diff --git a/src/handler.cpp b/src/handler.cpp
index 34dd2f262..e2563aeb3 100644
--- a/src/handler.cpp
+++ b/src/handler.cpp
@@ -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)
   {
@@ -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:
@@ -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);
@@ -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++) {
@@ -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))
@@ -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);
diff --git a/src/newmatrix.cpp b/src/newmatrix.cpp
index a6b1a09ef..2a4889f50 100644
--- a/src/newmatrix.cpp
+++ b/src/newmatrix.cpp
@@ -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;
 }