3.5 Touch spells

Discussion in 'The Temple of Elemental Evil' started by Basil the Timid, May 31, 2008.

Remove all ads!
  1. Sitra Achara

    Sitra Achara Senior Member

    Joined:
    Sep 1, 2003
    Messages:
    2,745
    Likes Received:
    91
    Judging by the code, Dispel alignment should work on summoned creatures. Dispel element is broken - the S_TouchAttack handler function is recycled from the alignment variants, but it doesn't handle the Dispel Element variants...
    Code:
    int __cdecl DispelAlignmentTouchAttackSignalHandler(Dispatcher_Callback_Args args)
    {
      // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
    
      d20a = (D20Action *)DispIoCheckIoType06(args.dispIO)->arg1;
      if ( d20a->d20Caf & D20CAF_HIT )
      {
        spellId = CondNodeGetArg(args.subDispNode->condNode, 0);
        GetSpellPacketBody(spellId, &spellPktBody);
        SpellSoundPlay(&spellPktBody, OnAreaOfEffectHit);
        FloatCombatLine(args.objHndCaller, 68);
        if ( IsPc(d20a->d20ATarget) )
        {
          PlayFizzle(d20a->d20ATarget);
        }
        else if ( D20QueryWithData(d20a->d20ATarget, Disp_Key_Q_Critter_Has_Condition, (int)&Condition_sp_Summoned, 0) == 1 )
        {
          if ( CheckSpellResistance(&spellPktBody, d20a->d20ATarget) != 1 )
          {
            switch ( args.subDispNode->subDispDef->data1 )
            {
              case 0x45u:
                v3 = StatLevelGet(d20a->d20ATarget, stat_alignment) - 2;
                if ( !v3 )
                  goto LABEL_19;
                v4 = v3 - 4;
                if ( !v4 || v4 == 4 )
                  goto LABEL_19;
                break;
              case 0x46u:
                v5 = StatLevelGet(d20a->d20ATarget, stat_alignment);
                if ( v5 >= ALIGNMENT_EVIL && v5 <= ALIGNMENT_CHAOTIC_EVIL )
                  goto LABEL_19;
                break;
              case 0x47u:
                v6 = StatLevelGet(d20a->d20ATarget, stat_alignment);
                if ( v6 >= ALIGNMENT_GOOD && v6 <= ALIGNMENT_CHAOTIC_GOOD )
                  goto LABEL_19;
                break;
              case 0x48u:
                v7 = StatLevelGet(d20a->d20ATarget, stat_alignment) - 1;
                if ( !v7 || (v8 = v7 - 4) == 0 || v8 == 4 )
                {
    LABEL_19:
                  if ( SavingThrowSpell(
                         d20a->d20ATarget,
                         spellPktBody.caster,
                         spellPktBody.spellDc,
                         2,
                         0,
                         spellPktBody.SpellID) )
                  {
                    Float_Spell_mes_Message(d20a->d20ATarget, 30001, 0, 0, 0);
                  }
                  else
                  {
                    Float_Spell_mes_Message(d20a->d20ATarget, 30002, 0, 0, 0);
                    CritterKill(d20a->d20ATarget, args.objHndCaller);
                  }
                }
                break;
              default:
                break;
            }
          }
        }
        else
        {
          DispIoInitIoType11(&dispIo);
          spellId = CondNodeGetArg(args.subDispNode->condNode, 0);
          v10 = args.subDispNode->subDispDef;
          dispIo.spellIdOfDispelSpell = spellId;
          dispIo.returnVal = 1;
          switch ( v10->data1 )
          {
            case 0x45u:
              dispIo.flags = 2;
              break;
            case 0x46u:
              dispIo.flags = 4;
              break;
            case 0x47u:
              dispIo.flags = 8;
              break;
            case 0x48u:
              dispIo.flags = 16;
              break;
            default:
              dispIo.flags = 0;
              break;
          }
          Dispatch33DispelCheck(d20a->d20ATarget, &dispIo);
          nullsub_1((BonusList *)&dispIo);
        }
        *(_QWORD *)&v11[16] = (unsigned int)args.nKey;
        *(_QWORD *)&v11[8] = *(__int64 *)((char *)&args.objHndCaller.objHndl + 4);
        *(_QWORD *)v11 = *(_QWORD *)&args.subDispNode;
        Spell_remove_spell(*(DCA *)v11);
        *(_QWORD *)&v12[16] = (unsigned int)args.nKey;
        *(_QWORD *)&v12[8] = *(__int64 *)((char *)&args.objHndCaller.objHndl + 4);
        *(_QWORD *)v12 = *(_QWORD *)&args.subDispNode;
        Spell_remove_mod(*(DCA *)v12);
        result = 0;
      }
      else
      {
        FloatCombatLine(args.objHndCaller, 69);
        result = 0;
      }
      return result;
    }
    Likewise for the GetAC handler, it uses the same function for Dispel Element as with Dispel Alignment, but the switch case only has clauses for the alignment variants, as well as a default which the Dispel Element goes into and gives a bonus unconditionally...
    Code:
    int __cdecl DispelAlignmentAcBonus(DCA args)
    {
      DispIoAttackBonus *dispIo; // esi@1
      void *v2; // ecx@1
      bool v3; // zf@2
      void *bonAmt; // edx@4
      int result; // eax@6
    
      dispIo = DispIoCheckIoType05(args.dispIO);
      v2 = args.subDispNode->subDispDef->SDDKey2;
      switch ( v2 )
      {
        case 0xAFu:
          v3 = (GetInt32(dispIo->attackPacket.attacker, obj_f_critter_alignment) & ALIGNMENT_CHAOTIC) == 0;
          goto LABEL_8;
        case 0xB0u:
          if ( !(GetInt32(dispIo->attackPacket.attacker, obj_f_critter_alignment) & ALIGNMENT_EVIL) )
            goto LABEL_12;
          v2 = args.subDispNode->subDispDef->SDDKey2;
          bonAmt = args.subDispNode->subDispDef->data1;
          goto LABEL_11;
        case 0xB1u:
          if ( !(GetInt32(dispIo->attackPacket.attacker, obj_f_critter_alignment) & ALIGNMENT_GOOD) )
            goto LABEL_12;
          bonusAddToBonusList(
            &dispIo->bonlist,
            (int)args.subDispNode->subDispDef->data1,
            11,
            (int)args.subDispNode->subDispDef->SDDKey2);
          return 0;
        case 0xB2u:
          v3 = (GetInt32(dispIo->attackPacket.attacker, obj_f_critter_alignment) & ALIGNMENT_LAWFUL) == 0;
    LABEL_8:
          if ( v3 )
            goto LABEL_12;
          bonusAddToBonusList(
            &dispIo->bonlist,
            (int)args.subDispNode->subDispDef->data1,
            11,
            (int)args.subDispNode->subDispDef->SDDKey2);
          result = 0;
          break;
        default:
          bonAmt = args.subDispNode->subDispDef->data1;
    LABEL_11:
          bonusAddToBonusList(&dispIo->bonlist, (int)bonAmt, 11, (int)v2);
    LABEL_12:
          result = 0;
          break;
      }
      return result;
    }
    
     
  2. marc1967

    marc1967 Established Member

    Joined:
    Jan 19, 2014
    Messages:
    546
    Likes Received:
    19
    Thanks a ton! I'm gonna have to start digging into this code, which scares me, but this random experimentation is so time consuming and misses cases. Apparently the relevant line checks for summoned only, so it won't affect those with mc_type_outsider , or mc_subtype_extraplaner, or whatever else, which is plain to see.

    Code:
    >D20QueryWithData(d20a->d20ATarget, Disp_Key_Q_Critter_Has_Condition, (int)&Condition_sp_Summoned, 0) == 1
    So can I access this check from a python script using obj.d20_query_with_data()? What arguments would I put in?

    edit: obj.d20_query_has_spell_condition (sp_Summoned) got the job done.
     
    Last edited: Jul 9, 2016
  3. Sitra Achara

    Sitra Achara Senior Member

    Joined:
    Sep 1, 2003
    Messages:
    2,745
    Likes Received:
    91
    Give in to the dark side... let the disassembly flow through you :D
     
Our Host!