#include "common.h"
#include "War2Mod.h"
#include "War2API.h"
#include "UnitList.h"
void runestone()
{
for (int i = 0; i < 16; i++)
{
int* p = (int*)(UNITS_LISTS + 4 * i);
if (p)
{
p = (int*)(*p);
while (p)
{
bool f = *((byte*)((uintptr_t)p + S_ID)) == U_RUNESTONE;
if (f)
{
if (!check_unit_dead(p) && check_unit_complete(p))
{//alive and completed runestone
byte x = *((byte*)((uintptr_t)p + S_X));
byte y = *((byte*)((uintptr_t)p + S_Y));
set_region((int)x - 4, (int)y - 4, (int)x + 5, (int)y + 5);//set region around myself
find_all_alive_units(ANY_MEN);
sort_in_region();
if (runes[8] == 1)//only allied units can can recieve bufs
{
byte o = *((byte*)((uintptr_t)p + S_OWNER));
for (int ui = 0; ui < 16; ui++)
{
if (!check_ally(o, ui))// tp
sort_stat(S_OWNER, ui, CMP_NEQ);
}
}
if (runes[0] == 1)set_stat_all(S_INVIZ, (int)(*(WORD*)INVIZ_TIME));//inviz
if (runes[1] == 1)set_stat_all(S_SHIELD, (int)(*(WORD*)SHIELD_TIME));//shield
if (runes[2] == 1)set_stat_all(S_BLOOD, (int)(*(WORD*)BLOOD_TIME));//blood
if (runes[3] == 1)set_stat_all(S_HASTE, (int)(*(WORD*)HASTE_TIME1));//haste
if (runes[4] == 1)flame_all();
//5 mana
//6 heal
if (runes[7] == 1)//kill all not my owner units
{
byte o = *((byte*)((uintptr_t)p + S_OWNER));
sort_stat(S_OWNER, o, CMP_NEQ);
kill_all();
}
sort_stat(S_KILLS + 1, 0, CMP_EQ);
set_stat_all(S_KILLS + 1, 100);
if (runes[5] != 0)mana_regen_all(runes[5]);
if (runes[6] != 0)heal_all(runes[6], 0);
}
}
p = (int*)(*((int*)((uintptr_t)p + S_NEXT_UNIT_POINTER)));
}
}
}
}
void portal()
{
bool mp = true;
for (int i = 0; i < 16; i++)
{
units = 0;
int* p = (int*)(UNITS_LISTS + 4 * i);
if (p)
{
p = (int*)(*p);
int* fp = NULL;
while (p)
{
bool f = *((byte*)((uintptr_t)p + S_ID)) == U_PORTAL;
if (f)
{
if (!check_unit_dead(p) && check_unit_complete(p))
{//alive and completed portal
if (!fp)fp = p;//remember first portal
byte tx = *((byte*)((uintptr_t)p + S_X)) + 1;
byte ty = *((byte*)((uintptr_t)p + S_Y)) + 1;//exit point is in center of portal
move_all(tx, ty);//teleport from previous portal
set_tp_flag(true);
set_stat_all(S_NEXT_ORDER, ORDER_STOP);
set_stat_all(S_ORDER_X, 128);
set_stat_all(S_ORDER_Y, 128);
byte x = *((byte*)((uintptr_t)p + S_X));
byte y = *((byte*)((uintptr_t)p + S_Y));
set_region((int)x - 1, (int)y - 1, (int)x + 4, (int)y + 4);//set region around myself
find_all_alive_units(ANY_MEN);
sort_in_region();
if (aport)
{
byte o = *((byte*)((uintptr_t)p + S_OWNER));
for (int ui = 0; ui < 16; ui++)
{
if (!check_ally(o, ui))//only allied units can tp
sort_stat(S_OWNER, ui, CMP_NEQ);
}
}
sort_tp_flag();//flag show if unit was not teleported
mp = true;
if (mport)//only teleport if some caster near
{
mp = false;
for (int ui = 0; ui < units; ui++)
{
byte uid = *((byte*)((uintptr_t)unit[ui] + S_ID));
if ((uid == U_MAGE) || (uid == U_DK) || (uid == U_TERON) || (uid == U_HADGAR) || (uid == U_GULDAN))
mp = true;//can tp only if mage nearby (teron hadgar and guldan too)
}
}
if (!mp)units = 0;
else
{
sort_stat(S_ORDER, ORDER_STOP, CMP_EQ);
sort_stat(S_ORDER_UNIT_POINTER, 0, CMP_EQ);
sort_stat(S_ORDER_UNIT_POINTER + 1, 0, CMP_EQ);
sort_stat(S_ORDER_UNIT_POINTER + 2, 0, CMP_EQ);
sort_stat(S_ORDER_UNIT_POINTER + 3, 0, CMP_EQ);
set_region((int)x, (int)y, (int)x + 3, (int)y + 3);//set region inside myself
sort_target_in_region();
}
}
}
p = (int*)(*((int*)((uintptr_t)p + S_NEXT_UNIT_POINTER)));
}
if (fp)//first portal teleports from last
{
byte tx = *((byte*)((uintptr_t)fp + S_X)) + 1;
byte ty = *((byte*)((uintptr_t)fp + S_Y)) + 1;
move_all(tx, ty);
set_tp_flag(true);
set_stat_all(S_NEXT_ORDER, ORDER_STOP);
set_stat_all(S_ORDER_X, 128);
set_stat_all(S_ORDER_Y, 128);
}
}
}
find_all_alive_units(ANY_MEN);
set_tp_flag(false);//reset tp flags to all
}
void wharf()
{
for (int i = 0; i < 16; i++)
{
int* p = (int*)(UNITS_LISTS + 4 * i);
if (p)
{
p = (int*)(*p);
while (p)
{
bool f = (*((byte*)((uintptr_t)p + S_ID)) == U_SHIPYARD) || (*((byte*)((uintptr_t)p + S_ID)) == U_WHARF);
if (f)
{
if (!check_unit_dead(p) && check_unit_complete(p))
{
byte x = *((byte*)((uintptr_t)p + S_X));
byte y = *((byte*)((uintptr_t)p + S_Y));
set_region((int)x - 2, (int)y - 2, (int)x + 4, (int)y + 4);//set region around myself
find_all_alive_units(ANY_MEN);
sort_in_region();
sort_hidden();
sort_stat(S_MOVEMENT_TYPE, MOV_WATER, CMP_BIGGER_EQ);//find ships - movement type >= water (2 or 3 actually(ships=2 transport=3))
byte o = *((byte*)((uintptr_t)p + S_OWNER));
for (int ui = 0; ui < 16; ui++)
{
if (!check_ally(o, ui))//only allied ships
sort_stat(S_OWNER, ui, CMP_NEQ);
}
heal_all(4, 0);
}
}
p = (int*)(*((int*)((uintptr_t)p + S_NEXT_UNIT_POINTER)));
}
}
}
}
void paladin()
{
for (int ii = 0; ii < 16; ii++)
{
int* p = (int*)(UNITS_LISTS + 4 * ii);
if (p)
{
p = (int*)(*p);
while (p)
{
bool f = ((*((byte*)((uintptr_t)p + S_ID)) == U_PALADIN) ||
(*((byte*)((uintptr_t)p + S_ID)) == U_UTER) ||
(*((byte*)((uintptr_t)p + S_ID)) == U_TYRALYON));
if (f)
{
if (!check_unit_dead(p) && !check_unit_hidden(p))
{
byte o = *((byte*)((uintptr_t)p + S_OWNER));
if (((*(byte*)(SPELLS_LEARNED + 4 * o) & (1 << L_HEAL)) != 0) &&
((*(byte*)(SPELLS_LEARNED + 4 * o) & (1 << L_GREATER_HEAL)) != 0))
//if player learned heal and autoheal
{
byte x = *((byte*)((uintptr_t)p + S_X));
byte y = *((byte*)((uintptr_t)p + S_Y));
set_region((int)x - 5, (int)y - 5, (int)x + 5, (int)y + 5);//set region around myself
find_all_alive_units(ANY_MEN);
sort_in_region();
sort_hidden();
sort_fleshy();//fleshy units (not heal cata and ships)
sort_full_hp();//if unit hp not full
sort_self(p);//not heal self
sort_order_hp();//heal lovest hp first
for (int ui = 0; ui < 16; ui++)
{
if (!check_ally(o, ui))//only allied units
sort_stat(S_OWNER, ui, 1);
}
byte cost = *(byte*)(MANACOST + 2 * GREATER_HEAL);//2* cause manacost is WORD
if (war2mod)
if (*((byte*)((uintptr_t)p + S_ID)) == U_UTER)cost = 1;
for (int i = 0; i < units; i++)
{
byte mp = *((byte*)((uintptr_t)p + S_MANA));//paladin mp
if (mp >= cost)
{
byte id = *((byte*)((uintptr_t)unit[i] + S_ID));//unit id
WORD mhp = *(WORD*)(UNIT_HP_TABLE + 2 * id);//max hp
WORD hp = *((WORD*)((uintptr_t)unit[i] + S_HP));//unit hp
WORD shp = mhp - hp;//shortage of hp
while (!(mp >= (shp * cost)) && (shp > 0))shp -= 1;
if (shp > 0)//if can heal at least 1 hp
{
heal(unit[i], (byte)shp, 0);
mp -= shp * cost;
*((byte*)((uintptr_t)p + S_MANA)) = mp;
WORD xx = *((WORD*)((uintptr_t)unit[i] + S_DRAW_X));
WORD yy = *((WORD*)((uintptr_t)unit[i] + S_DRAW_Y));
bullet_create(xx + 16, yy + 16, B_HEAL);//create heal effect
if (shp >= 3)
((void (*)(WORD, WORD, byte))F_SPELL_SOUND_XY)(xx + 16, yy + 16, SS_HEAL);//heal sound
}
}
else i = units;
}
}
}
}
p = (int*)(*((int*)((uintptr_t)p + S_NEXT_UNIT_POINTER)));
}
}
}
}
void transport()
{
for (int i = 0; i < 16; i++)
{
int* p = (int*)(UNITS_LISTS + 4 * i);
if (p)
{
p = (int*)(*p);
while (p)
{
bool f = (*((byte*)((uintptr_t)p + S_ID)) == U_HTRANSPORT) || (*((byte*)((uintptr_t)p + S_ID)) == U_OTRANSPORT);
if (f)
{
if (!check_unit_dead(p) && (cmp_stat(p, ANIM_STOP, S_ANIMATION, CMP_EQ)))//if transport stop
{
byte x = *((byte*)((uintptr_t)p + S_X));
byte y = *((byte*)((uintptr_t)p + S_Y));
byte o = *((byte*)((uintptr_t)p + S_OWNER));
for (byte ui = 0; ui < 16; ui++)
{
set_region((int)x - 1, (int)y - 1, (int)x + 1, (int)y + 1);//set region around myself
find_all_alive_units(ANY_MEN);
sort_in_region();
sort_hidden();
sort_stat(S_MOVEMENT_TYPE, MOV_LAND, CMP_EQ);
sort_stat(S_ORDER, ORDER_STOP, CMP_EQ);
sort_stat(S_ANIMATION, ANIM_STOP, CMP_EQ);
sort_stat(S_OWNER, ui, CMP_EQ);
bool f = false;
if ((*(byte*)(CONTROLER_TYPE + o) == C_PLAYER))
{
f = true;
if ((*(byte*)(CONTROLER_TYPE + ui) == C_COMP))
{
if (!check_ally(o, ui))//only allied comps
sort_stat(S_OWNER, ui, CMP_NEQ);
}
if ((*(byte*)(CONTROLER_TYPE + ui) == C_PLAYER))
{
if (!check_ally(o, ui) || (ui == o))//only allied players
{
sort_stat(S_OWNER, ui, CMP_NEQ);
}
sort_stat(S_ORDER_UNIT_POINTER, 0, CMP_EQ);
sort_stat(S_ORDER_UNIT_POINTER + 1, 0, CMP_EQ);
sort_stat(S_ORDER_UNIT_POINTER + 2, 0, CMP_EQ);
sort_stat(S_ORDER_UNIT_POINTER + 3, 0, CMP_EQ);
set_region((int)x, (int)y, (int)x, (int)y);//set region inside myself
sort_target_in_region();
}
}
if ((*(byte*)(CONTROLER_TYPE + o) == C_COMP))
{
f = true;
if ((*(byte*)(CONTROLER_TYPE + ui) == C_COMP))
{
if (!check_ally(o, ui) || (ui == o))//only allied comps
sort_stat(S_OWNER, ui, CMP_NEQ);
}
if ((*(byte*)(CONTROLER_TYPE + ui) == C_PLAYER))
{
if (!check_ally(o, ui))//only allied players
{
sort_stat(S_OWNER, ui, CMP_NEQ);
}
sort_stat(S_ORDER_UNIT_POINTER, 0, CMP_EQ);
sort_stat(S_ORDER_UNIT_POINTER + 1, 0, CMP_EQ);
sort_stat(S_ORDER_UNIT_POINTER + 2, 0, CMP_EQ);
sort_stat(S_ORDER_UNIT_POINTER + 3, 0, CMP_EQ);
set_region((int)x, (int)y, (int)x, (int)y);//set region inside myself
sort_target_in_region();
}
}
if (f)
{
sort_stat(S_KILLS + 1, 0, CMP_EQ);
set_stat_all(S_KILLS + 1, 100);
set_stat_all(S_NEXT_ORDER, ORDER_ENTER_TRANSPORT);
set_stat_all(S_ORDER_UNIT_POINTER, ((int)p) % 256);
set_stat_all(S_ORDER_UNIT_POINTER + 1, (((int)p) / 256) % 256);
set_stat_all(S_ORDER_UNIT_POINTER + 2, ((((int)p) / 256) / 256) % 256);
set_stat_all(S_ORDER_UNIT_POINTER + 3, (((((int)p) / 256) / 256) / 256) % 256);
}
}
}
}
p = (int*)(*((int*)((uintptr_t)p + S_NEXT_UNIT_POINTER)));
}
}
}
}
void slow_aura(byte id)
{
for (int i = 0; i < 16; i++)
{
int* p = (int*)(UNITS_LISTS + 4 * i);
if (p)
{
p = (int*)(*p);
while (p)
{
bool f = (*((byte*)((uintptr_t)p + S_ID)) == id);
if (f)
{
if (!check_unit_dead(p))
{
byte x = *((byte*)((uintptr_t)p + S_X));
byte y = *((byte*)((uintptr_t)p + S_Y));
set_region((int)x - 5, (int)y - 5, (int)x + 5, (int)y + 5);//set region around myself
find_all_alive_units(ANY_MEN);
sort_in_region();
byte o = *((byte*)((uintptr_t)p + S_OWNER));
for (int ui = 0; ui < 16; ui++)
{
if (check_ally(o, ui))//only enemies
sort_stat(S_OWNER, ui, CMP_NEQ);
}
set_stat_all(S_HASTE, 0xfcdf);//-800
}
}
p = (int*)(*((int*)((uintptr_t)p + S_NEXT_UNIT_POINTER)));
}
}
}
}
void death_aura(byte id)
{
for (int i = 0; i < 16; i++)
{
int* p = (int*)(UNITS_LISTS + 4 * i);
if (p)
{
p = (int*)(*p);
while (p)
{
bool f = (*((byte*)((uintptr_t)p + S_ID)) == id);
if (f)
{
if (!check_unit_dead(p))
{
byte mp = *((byte*)((uintptr_t)p + S_MANA));
byte x = *((byte*)((uintptr_t)p + S_X));
byte y = *((byte*)((uintptr_t)p + S_Y));
byte xx = *((byte*)((uintptr_t)p + S_ORDER_X));
byte yy = *((byte*)((uintptr_t)p + S_ORDER_Y));
set_stat(p, 255, S_MANA);
set_stat(p, x, S_ORDER_X);
set_stat(p, y, S_ORDER_Y);
char buf[] = "\x90\x90\x90\x90\x90\x90\x90\x90";
PATCH_SET((char*)RAISE_DEAD_DOING_SPELL1, buf);
char buf3[] = "\x90\x90\x90";
PATCH_SET((char*)RAISE_DEAD_DOING_SPELL2, buf3);
((void (*)(int*))F_RAISE_DEAD)(p);
char buf2[] = "\x6a\x2\x53\xe8\x9f\x3\x1\x0";
PATCH_SET((char*)RAISE_DEAD_DOING_SPELL1, buf2);
char buf4[] = "\x83\xc4\x8";
PATCH_SET((char*)RAISE_DEAD_DOING_SPELL2, buf4);
set_stat(p, mp, S_MANA);
set_stat(p, xx, S_ORDER_X);
set_stat(p, yy, S_ORDER_Y);
}
}
p = (int*)(*((int*)((uintptr_t)p + S_NEXT_UNIT_POINTER)));
}
}
}
}
void sneak(byte id)
{
for (int i = 0; i < 16; i++)
{
int* p = (int*)(UNITS_LISTS + 4 * i);
if (p)
{
p = (int*)(*p);
while (p)
{
bool f = (*((byte*)((uintptr_t)p + S_ID)) == id);
if (f)
{
if (!check_unit_dead(p))
{
byte o = *((byte*)((uintptr_t)p + S_ORDER));
WORD n = *((WORD*)((uintptr_t)p + S_INVIZ));
if (o == ORDER_STAND)
{
if (n <= 10)set_stat(p, 10, S_INVIZ);
}
}
}
p = (int*)(*((int*)((uintptr_t)p + S_NEXT_UNIT_POINTER)));
}
}
}
}