It is currently 16 Apr 2024, 09:55
   
Text Size

[fixed]Suspend prevents planewalker abilities

Moderators: BAgate, drool66, Aswan jaguar, gmzombie, stassy, CCGHQ Admins

Re: [confirmed]Suspend prevents planewalker abilities

Postby drool66 » 17 Jan 2022, 00:24

Thanks again, Korath; yes, that was the only crash.
I've got the two new functions mostly working; the only issue is something in the AI threading, specifically around the section for determining x-values. I can't get AI to cast an x spell under any circumstances. I bet it's a similar issue around a pointer - I'm not sure if I should do the recasts to char or not. Maybe you can see something obvious I'm overlooking? Maybe a lot of things I'm misunderstanding?
If not, we can just keep your shim and be done with it, although it would be very nice to start changing this function to handle hybrid.
Code: Select all
#define mana_cost_xbugrw   EXE_BYTE_PTR(0x55cf18)
static void fn_402593(card_data_t* cd)
{
  int i;
  for(i=COLOR_COLORLESS;i<=COLOR_WHITE;i++)
   pay_mana_xbugrwaU[i] = mana_cost_xbugrw[i];

  if ( cd->type & TYPE_ARTIFACT )
  {
    PAY_MANA_ARTIFACT = PAY_MANA_COLORLESS;
    PAY_MANA_COLORLESS = 0;
  }
}
#undef mana_cost_xbugrw

#define TENTATIVE_ai_branch_value_99_is_abort            EXE_DWORD(0x7a2fe4)
#define TENTATIVE_mana_paid_for_spell                  EXE_BYTE_PTR(0x55cef0)
#define TENTATIVE_ai_save_values_on_speculative_branch      EXE_FN(int, 0x498F20, int)
#define TENTATIVE_ai_retrieve_values_on_chosen_branch      EXE_FN(int, 0x499050, void)
#define charge_mana_w_global_cost_mod                  EXE_FN(int, 0x4302c0, int, int, color_t, int)
#define TENTATIVE_update_mana_spent                     EXE_FN(int, 0x430260, int)
#define FN_42DE60                                 EXE_FN(int, 0x42DE60, int, int, int, int, int)
static int charge_spell_cost(card_data_t* cd, int player, int card)
{   // 0x402680
   fn_402593(cd);
   card_ptr_t* cp = cards_ptr[ get_id(player, card) ];
   int i, is_x_spell = cp->req_colorless == 40;
   int8_t* byte_55CF20 = (int8_t*)EXE_BYTE_PTR(0x55cf20);   // Amount of surplus free mana?
   int8_t* byte_4EF4FC = (int8_t*)EXE_BYTE_PTR(0x4EF4FC);
   if ( (player == HUMAN || trace_mode & 2) && ai_is_speculating != 1 ){
   //   if ( !v5 )   // something in edx?
   //      return charge_mana_w_global_cost_mod(player, card, COLOR_COLORLESS, 0);

      int result;
      if ( !(result = charge_mana_w_global_cost_mod(player, card, COLOR_COLORLESS, 0)) )
         return 0;

      memcpy(TENTATIVE_mana_paid_for_spell, &mana_paid, 0x1Cu);
      int v7[8];
      for(i=0;i<8;i++)
         v7[i] = byte_55CF20[i];
      if ( *byte_55CF20 < 0 ){
         for(i=0;i<8;i++){
            mana_pool[player][i] -= byte_55CF20[i];
            byte_4EF4FC[player] -= v7[i];
         }
      }
      if( is_x_spell )
         charge_mana(player, 0, -1);
      goto LABEL_33;
   }
   if ( cd->type & TYPE_ARTIFACT ){
      int v9 = PAY_MANA_ARTIFACT;
      PAY_MANA_ARTIFACT = 0;
      return charge_mana_w_global_cost_mod(player, card, COLOR_ARTIFACT, v9);
   }
   int result = charge_mana_w_global_cost_mod(player, card, COLOR_COLORLESS, 0);
   if ( result ){
      result = cd->cc[1];
      if ( result < 0 ){
         memcpy(TENTATIVE_mana_paid_for_spell, &mana_paid, 0x1Cu);
         int v11 = mana_paid[COLOR_ANY];
         int v10 = TENTATIVE_mana_paid_for_spell[COLOR_ANY];
         int v12[8];
         for(i=0;i<8;i++)
            v12[i] = byte_55CF20[i];

         if ( *byte_55CF20 < 0 ){
            for(i=0;i<8;i++){
               mana_pool[player][i] -= byte_55CF20[i];
               byte_4EF4FC[player] -= v12[i];
            }
         }
         if ( player == HUMAN ){
            int old_max_x = max_x_value;
            max_x_value = has_mana(player, COLOR_ANY, 1);
            FN_42DE60(v10, v11, player, 0, -1);
            max_x_value = old_max_x;
         }
         else{
            int amt_for_x;
            if ( ai_is_speculating == 1 ){
               if ( internal_rand(2) ){
                  amt_for_x = has_mana(player, COLOR_ANY, 1);
                  TENTATIVE_ai_branch_value_99_is_abort = amt_for_x;
                  if ( life[HUMAN] < amt_for_x && !internal_rand(3) ){
                     amt_for_x = life[HUMAN];
                     TENTATIVE_ai_branch_value_99_is_abort = life[HUMAN];
                  }
                  if ( max_x_value != -1 && max_x_value < TENTATIVE_ai_branch_value_99_is_abort ){
                     amt_for_x = max_x_value;
                     TENTATIVE_ai_branch_value_99_is_abort = max_x_value;
                  }
               }
               else{
                  int v14 = has_mana(player, COLOR_ANY, 1);
                  if ( v14 )
                     v14 = internal_rand(v14) + 1;
                  amt_for_x = v14;
                  TENTATIVE_ai_branch_value_99_is_abort = v14;
               }
               TENTATIVE_ai_save_values_on_speculative_branch(v11);
            }
            else{
               TENTATIVE_ai_retrieve_values_on_chosen_branch();
               amt_for_x = TENTATIVE_ai_branch_value_99_is_abort;
            }
            int store_max_x_value = max_x_value;
            max_x_value = amt_for_x;
            FN_42DE60(v10, v11, player, 0, -1);
            max_x_value = store_max_x_value;
         }
         LABEL_33:
         result = *byte_55CF20;
         if ( byte_55CF20[COLOR_ANY] != 0 ){
            int found = 0;
            for(i=0;i<8;i++){
               if( byte_55CF20[i] + (mana_pool[player][i] < 0) )
                  found = 1;
               mana_pool[player][i] += byte_55CF20[i];
            }
            if ( found ){
               int8_t v19 = 0;
               for(i=0;i<8;i++)
                  v19 |= ((mana_pool[player][i] > 0) << i);
               EXE_FN(int, 0x4301a0, int, int)(0, v19);
               result = v19;
               memset(mana_pool[player], 0, sizeof(mana_pool[player]));
            }
            else{
               byte_4EF4FC[player] += result;
            }
         }
         if ( !x_value )
            ai_modifier -= 100;
         if ( spell_fizzled == 1 ){
            TENTATIVE_update_mana_spent(*TENTATIVE_mana_paid_for_spell);
            for(i=0;i<8;i++){
               result = TENTATIVE_mana_paid_for_spell[i];
               mana_pool[player][i] += result;
               byte_4EF4FC[player] += result;
            }
         }
         return result;
      }
   }
   return result;
}
#undef TENTATIVE_ai_branch_value_99_is_abort
#undef TENTATIVE_mana_paid_for_spell
#undef TENTATIVE_ai_save_values_on_speculative_branch
#undef TENTATIVE_ai_retrieve_values_on_chosen_branch
#undef charge_mana_w_global_cost_mod
#undef TENTATIVE_update_mana_spent
#undef FN_42DE60
Here's the pseudocode, for reference:
Code: Select all
int __usercall sub_402680@<eax>(int a1@<edi>, int a2, int a3)
{
  int v3; // edx
  int result; // eax
  int v5; // eax
  int v6; // ecx
  int v7; // eax
  int v8; // eax
  int v9; // ecx
  int v10; // eax
  int v11; // ST0C_4
  int v12; // ST0C_4
  int v13; // ecx
  bool v14; // sf
  int v15; // ST0C_4
  int v16; // ecx
  unsigned int v17; // edx
  int v18; // [esp+8h] [ebp-4h]

  sub_402593(a1);
  if ( (!a2 || dword_790640 & 2) && dword_728574 != 1 )
  {
    if ( !v3 )
      return sub_4302C0(a2, a3, 0, 0);
    result = sub_4302C0(a2, a3, 0, 0);
    if ( !result )
      return result;
    qmemcpy(dword_55CEF0, &dword_55CED0, 0x1Cu);
    v5 = (char)dword_55CF20;
    if ( (dword_55CF20 & 0x80u) != 0 )
    {
      v6 = 8 * a2;
      dword_4EF4E0[v6] -= (char)dword_55CF20;
      dword_4EF4FC[v6] -= v5;
    }
    sub_42DE60(a2, 0, -1);
    goto LABEL_33;
  }
  if ( *(_BYTE *)(a1 + 40) & 0x40 )
  {
    v7 = dword_4EF418;
    dword_4EF418 = 0;
    return sub_4302C0(a2, a3, 6, v7);
  }
  result = sub_4302C0(a2, a3, 0, 0);
  if ( result )
  {
    result = *(char *)(a1 + 44);
    if ( result < 0 )
    {
      qmemcpy(dword_55CEF0, &dword_55CED0, 0x1Cu);
      v8 = (char)dword_55CF20;
      if ( (dword_55CF20 & 0x80u) != 0 )
      {
        v9 = 8 * a2;
        dword_4EF4E0[v9] -= (char)dword_55CF20;
        dword_4EF4FC[v9] -= v8;
      }
      if ( a2 == dword_736AD8 )
      {
        v12 = dword_4EF198;
        dword_4EF198 = sub_49D510(a2, 7, 1);
        sub_42DE60(a2, 0, -1);
        dword_4EF198 = v12;
      }
      else
      {
        if ( dword_728574 == 1 )
        {
          if ( sub_44E050(2) )
          {
            v18 = sub_49D510(a2, 7, 1);
            dword_7A2FE4 = v18;
            if ( dword_4EF528 < v18 && !sub_44E050(3) )
            {
              v18 = dword_4EF528;
              dword_7A2FE4 = dword_4EF528;
            }
            if ( dword_4EF198 != -1 && dword_4EF198 < dword_7A2FE4 )
            {
              v18 = dword_4EF198;
              dword_7A2FE4 = dword_4EF198;
            }
          }
          else
          {
            v10 = sub_49D510(a2, 7, 1);
            if ( v10 )
              v10 = sub_44E050(v10) + 1;
            v18 = v10;
            dword_7A2FE4 = v10;
          }
          sub_498F20();
        }
        else
        {
          sub_499050();
          v18 = dword_7A2FE4;
        }
        v11 = dword_4EF198;
        dword_4EF198 = v18;
        sub_42DE60(a2, 0, -1);
        dword_4EF198 = v11;
      }
LABEL_33:
      v13 = 8 * a2;
      result = (char)dword_55CF20;
      if ( (dword_55CF20 & 0x80u) != 0 )
      {
        v14 = (char)dword_55CF20 + dword_4EF4E0[v13] < 0;
        dword_4EF4E0[v13] += (char)dword_55CF20;
        if ( v14 )
        {
          v15 = dword_4EF4E0[v13];
          sub_4301A0(0, v15);
          result = v15;
          dword_4EF4E0[8 * a2] = 0;
        }
        else
        {
          dword_4EF4FC[v13] += result;
        }
      }
      if ( !dword_4EF1A0 )
        dword_7A31A8 -= 100;
      if ( dword_4EF194 == 1 )
      {
        sub_430260(dword_55CEF0);
        v17 = 0;
        do
        {
          result = dword_55CEF0[v17];
          *(int *)((char *)&dword_4EF4E0[v17] + v16) += result;
          *(int *)((char *)dword_4EF4FC + v16) += result;
          ++v17;
        }
        while ( v17 < 8 );
      }
      return result;
    }
  }
  return result;
}
User avatar
drool66
Programmer
 
Posts: 1163
Joined: 25 Nov 2010, 22:38
Has thanked: 186 times
Been thanked: 267 times

Re: [confirmed]Suspend prevents planewalker abilities

Postby Korath » 17 Jan 2022, 05:33

First thing I see is that the exe version of fn_402593() returns a value in edx, equal to MIN(0, cd->cc[1]) (so zero for non-x spells, negative for x spells). That's not causing your problems, though, since it only gets used in the human codepath.

Second is that what you're calling FN_42DE60() is the original address of charge_mana(). It takes just the last three arguments you're giving it.
User avatar
Korath
DEVELOPER
 
Posts: 3707
Joined: 02 Jun 2013, 05:57
Has thanked: 496 times
Been thanked: 1106 times

Re: [confirmed]Suspend prevents planewalker abilities

Postby drool66 » 17 Jan 2022, 18:00

[...]equal to MIN(0, cd->cc[1]) (so zero for non-x spells, negative for x spells).
Well, that was the inspiration I needed because it made me remember something. Looking at this line, the gate for the AI speculation on x-values:
Code: Select all
      result = cd->cc[1];
      if ( result < 0 ){
If instead I do a direct comparison to cc[1]:
Code: Select all
      if ( cd->cc[1] < 0 ){
I get a build "error: comparison is always false due to limited range of data type"
So checking instead:
Code: Select all
      if ( is_x_spell ){
( is_x_spell == (cp->req_colorless == 40) )
and viola, AI will cast x spells and everything seems to work great. That seems copacetic to me, what do you think?

EDIT:
Oh right, it's because cc[ ] is a uint. Casting cc[1] to an int8_t and comparing to 0 works better than checking cp->req_colorless. I'll do that, clean up a little and push.
Last edited by drool66 on 19 Jan 2022, 08:09, edited 2 times in total.
Reason: see edit
User avatar
drool66
Programmer
 
Posts: 1163
Joined: 25 Nov 2010, 22:38
Has thanked: 186 times
Been thanked: 267 times

Re: [fixed]Suspend prevents planewalker abilities

Postby drool66 » 20 Jan 2022, 19:06

Magic.exe patch attempted in b0e4359, successful in 4ae8eab
Bug fixed in 7f0680e
User avatar
drool66
Programmer
 
Posts: 1163
Joined: 25 Nov 2010, 22:38
Has thanked: 186 times
Been thanked: 267 times

Re: [confirmed]Suspend prevents planewalker abilities

Postby Aswan jaguar » 21 Jan 2022, 14:45

Korath wrote:I see that the version in engine.c has already been fiddled with, despite it being disabled (for instance, by setting STATE_SICKNESS_UNUSED, which still needs to be renamed). It needs to be checked carefully against current assembly first, since it's missing at least one patch, patch_make_manasource_interrupts_interruptible.pl.
drool66 did you also made the check mentioned above against current assembly to see if any other patches are missing and set patch_make_manasource_interrupts_interruptible.pl?
---
Trying to squash some bugs and playtesting.
User avatar
Aswan jaguar
Super Tester Elite
 
Posts: 8078
Joined: 13 May 2010, 12:17
Has thanked: 730 times
Been thanked: 458 times

Re: [fixed]Suspend prevents planewalker abilities

Postby drool66 » 21 Jan 2022, 17:11

Yes; I checked everything from the current assembly. patch_make_manasource_interrupts_interruptible.pl was the only thing that had changed and is just the removal of this piece early in the second call:
Code: Select all
/*  && !(typ == TYPE_INTERRUPT && (cd->extra_ability & EA_MANA_SOURCE))*/
User avatar
drool66
Programmer
 
Posts: 1163
Joined: 25 Nov 2010, 22:38
Has thanked: 186 times
Been thanked: 267 times

Previous

Return to Archived Reports

Who is online

Users browsing this forum: No registered users and 87 guests


Who is online

In total there are 87 users online :: 0 registered, 0 hidden and 87 guests (based on users active over the past 10 minutes)
Most users ever online was 4143 on 23 Jan 2024, 08:21

Users browsing this forum: No registered users and 87 guests

Login Form