Shtick's Smithy

SPECIAL SUPPORTS
First off, I’d like to give a massive thank you to Vesly, ditto, Jester, Sme and Contro for helping me with troubleshooting.

In Thracia 776 and Three Houses, there were some supports that were considered to be special, and got extra perks; the former just doubled bonuses while the latter added an extra point of damage.



FE5 Special Support Tree by a redditor who deleted their account.
FE16 Special Bonds by u/FakeKyloRen on reddit.

This hack leans more towards the former.

Check the video below to see it applied.

Raw C Code
#include "C_Code.h"
extern u8 SpecialSupportPartners[];
int IsSpecialSupport(int pidA, int pidB) { 
	for (int i = 0; i < 3; ++i) { 
		if (SpecialSupportPartners[pidA * 3 + i] == pidB) { return true; } 
	} 	
	return false; 
}
static void ApplyAffinitySupportBonuses(struct SupportBonuses* bonuses, int affinity, int level)
{
    const struct SupportBonuses* added = GetAffinityBonuses(affinity);

    bonuses->bonusAttack  += level * added->bonusAttack;
    bonuses->bonusDefense += level * added->bonusDefense;
    bonuses->bonusHit     += level * added->bonusHit;
    bonuses->bonusAvoid   += level * added->bonusAvoid;
    bonuses->bonusCrit    += level * added->bonusCrit;
    bonuses->bonusDodge   += level * added->bonusDodge;
}
static void ApplyAffinitySpecialSupportBonuses(struct SupportBonuses* bonuses, int affinity, int level)
{
    const struct SupportBonuses* added = GetAffinityBonuses(affinity);

    bonuses->bonusAttack  += level * (added->bonusAttack * 2);
    bonuses->bonusDefense += level * (added->bonusDefense * 2);
    bonuses->bonusHit     += level * (added->bonusHit * 2);
    bonuses->bonusAvoid   += level * (added->bonusAvoid * 2);
    bonuses->bonusCrit    += level * (added->bonusCrit * 2);
    bonuses->bonusDodge   += level * (added->bonusDodge * 2);
}
int GetUnitSupportBonuses(struct Unit* unit, struct SupportBonuses* bonuses)
{
    int i, count;
    int result = 0;
    bool specialSupport = false;
    InitSupportBonuses(bonuses);
    count = GetUnitSupporterCount(unit);
    for (i = 0; i < count; ++i)
    {
        struct Unit* other;
        int level1, level2;
        result = result >> 1;
        other = GetUnitSupporterUnit(unit, i);
        if (!other)
            continue;
        if (!(gBmSt.gameStateBits & 0x40))
        {
            if (RECT_DISTANCE(unit->xPos, unit->yPos, other->xPos, other->yPos) > SUPPORT_BONUSES_MAX_DISTANCE)
                continue;
        }
        if(IsSpecialSupport(unit->pCharacterData->number, other->pCharacterData->number))
          specialSupport = true;
        if (other->state & (US_UNAVAILABLE | US_RESCUED))
            continue;
        if (IsSpecialSupport(unit->pCharacterData->number, other->pCharacterData->number)) { 
            level1 = GetUnitSupportLevel(other, GetUnitSupporterNum(other, unit->pCharacterData->number));
            ApplyAffinitySpecialSupportBonuses(bonuses, other->pCharacterData->affinity, level1);
            level2 = GetUnitSupportLevel(unit, i);
            ApplyAffinitySpecialSupportBonuses(bonuses, unit->pCharacterData->affinity, level2);
        } else {
          level1 = GetUnitSupportLevel(other, GetUnitSupporterNum(other, unit->pCharacterData->number));
          ApplyAffinitySupportBonuses(bonuses, other->pCharacterData->affinity, level1);
          level2 = GetUnitSupportLevel(unit, i);
          ApplyAffinitySupportBonuses(bonuses, unit->pCharacterData->affinity, level2);   
        }
        if (level1 != 0 && level2 != 0)
            result += 1 << (count - 1);
    }
    if (specialSupport) {
        bonuses->bonusAttack  /= 2;
        bonuses->bonusDefense /= 2;
        bonuses->bonusHit     /= 2;
        bonuses->bonusAvoid   /= 2;
        bonuses->bonusCrit    /= 2;
        bonuses->bonusDodge   /= 2;
    } else {
      bonuses->bonusAttack  /= 2;
      bonuses->bonusDefense /= 2;
      bonuses->bonusHit     /= 2;
      bonuses->bonusAvoid   /= 2;
      bonuses->bonusCrit    /= 2;
      bonuses->bonusDodge   /= 2; 
    }
  return result;
}

Here’s the Darbus to the hack, and this post will be linked to the OP as always.

10 Likes

POKEMON CONQUEST (LEGENDARY AND BOSS BATTLE)
Been a while since I did anything for this thread, so here you go.

Here’s the Urbosa, and this game will be added to the OP as always.

3 Likes

Today is All Fool’s Day, here’s your obligatory rickroll.

1 Like

SWITCHFE INSPIRED POISON

Ever thought that poison was too weak of a status in GBA? Me too, and I think I have the fix, inspired by 3H and Engage.

3H’s poison strike took off 20% of a unit’s max HP after combat, so now poison does 20% damage at the start of the turn. Now tho, it can get the kill.
Engage’s poison did an extra 3 or so damge at the end of combat, so I decided that poison should now reduce attack, AS and defenses by 3, as well as hit/avoid/crit/critavoid by 10.

Here's the raw C code for those that are curious
#include "C_Code.h"
void MakePoisonDamageTargetList(int faction) {
    int i;
    InitTargets(0, 0);
    for (i = faction + 1; i < faction + 0x40; i++) {
        struct Unit* unit = GetUnit(i);
        if (!UNIT_IS_VALID(unit)) {
            continue;
        }
        if (unit->state & (US_DEAD | US_NOT_DEPLOYED | US_RESCUED | US_BIT16)) {
            continue;
        }
        if (unit->statusIndex != UNIT_STATUS_POISON) {
            continue;
        }
        AddTarget(unit->xPos, unit->yPos, unit->index, (GetUnitMaxHp(unit)/5));
    }
    return;
}
void ComputeBattleUnitStatusBonuses(struct BattleUnit* bu) {
    switch (bu->unit.statusIndex) {
    case UNIT_STATUS_ATTACK:
        bu->battleAttack += 10;
        break;
    case UNIT_STATUS_DEFENSE:
        bu->battleDefense += 10;
        break;
    case UNIT_STATUS_CRIT:
        bu->battleCritRate += 10;
        break;
    case UNIT_STATUS_AVOID:
        bu->battleAvoidRate += 10;
        break;
	case UNIT_STATUS_POISON:
		bu->battleAttack -=3;
		if(bu->battleAttack < 0) {
			bu->battleAttack = 0;
		}	
		bu->battleDefense -=3;
		if(bu->battleDefense < 0) {
			bu->battleDefense = 0;
		}
		bu->battleSpeed -=3;
		if(bu->battleSpeed < 0) {
			bu->battleSpeed = 0;
		}
		bu->battleHitRate -=10;
		if(bu->battleHitRate < 0) {
			bu->battleHitRate = 0;
		}
		bu->battleAvoidRate -=10;
		if(bu->battleAvoidRate < 0) {
			bu->battleAvoidRate = 0;
		}
		bu->battleCritRate -=10;
		if(bu->battleCritRate < 0) {
			bu->battleCritRate = 0;
		}
		bu->battleDodgeRate -=10;
		if(bu->battleDodgeRate < 0) {
			bu->battleDodgeRate = 0;
		}		
		break;
    } 
}

Here’s a video to show the code in action.

Here’s the Bongobongo to the EA file, and this will be added to the OP like I always do.

6 Likes

Always appreciate Poison being more dangerous of a status.

(Though, FWIW, every stack of Poison in Engage adds +1 damage - it wasn’t a set amount of 3 damage at the end of combat. Hit an Armor which takes 0 damage from a Knife user in Engage, Poison = 1. Hit them again, Poison = 2, and each one added that point of extra damage. Still, unless you can make that kind of stacking effect work on it, these fixed changes (including the offensive debuffs) are a very nice substitute.)

3 Likes

Yes, i was about to point that out.

Poison stacks +1 per combat when hit with a poison weapon. Capped at 3. And recovers 1 each turn.

1 poison makes you take 1 more damage. 2 poison is +3 damage, and 3 poison is +5 damage.

FATES KILLER WEAPONS

IMPORTANT: THIS HACK IS INCOMPATIBLE WITH SKILLSYS

In Fates, Killer Weapons have a unique property where they are able to do 4x damage on a crit as opposed to 3x from normal weapons. I thought it was a cool idea, so I managed to work it into GBAFE.

Raw C Code
#include "C_Code.h"
extern const u8 QuadCritWeapons[];
int IsWepQuadCritter(int itemID) {
	itemID &= 0xFF;
	const u8* list = QuadCritWeapons;
	while (*list) {
		if (itemID == *list) {
			return true;
		}
		list++;
	}
	return false;
}
void BattleGenerateHitAttributes(struct BattleUnit* attacker, struct BattleUnit* defender) {
    short attack, defense;
    gBattleStats.damage = 0;
    BattleCheckSureShot(attacker);
    if (!(gBattleHitIterator->attributes & BATTLE_HIT_ATTR_SURESHOT)) {
        if (!BattleRoll2RN(gBattleStats.hitRate, TRUE)) {
            gBattleHitIterator->attributes |= BATTLE_HIT_ATTR_MISS;
            return;
        }
    }
    attack = gBattleStats.attack;
    defense = gBattleStats.defense;
    BattleCheckGreatShield(attacker, defender);
	int itemID = attacker-> weapon;
    if (!(gBattleHitIterator->attributes & BATTLE_HIT_ATTR_GREATSHLD))
        BattleCheckPierce(attacker, defender);
    if (gBattleHitIterator->attributes & BATTLE_HIT_ATTR_PIERCE)
        defense = 0;
    gBattleStats.damage = attack - defense;
    if (gBattleHitIterator->attributes & BATTLE_HIT_ATTR_GREATSHLD)
        gBattleStats.damage = 0;
    if (BattleRoll1RN(gBattleStats.critRate, FALSE) == TRUE) {
        if (BattleCheckSilencer(attacker, defender)) {
            gBattleHitIterator->attributes |= BATTLE_HIT_ATTR_SILENCER;

            gBattleStats.damage = BATTLE_MAX_DAMAGE;

            gBattleHitIterator->attributes = gBattleHitIterator->attributes &~ BATTLE_HIT_ATTR_GREATSHLD;
        } else {
            gBattleHitIterator->attributes = gBattleHitIterator->attributes | BATTLE_HIT_ATTR_CRIT;
			if (IsWepQuadCritter (itemID)) {
				gBattleStats.damage = gBattleStats.damage * 4;
			}
			else {
				gBattleStats.damage = gBattleStats.damage * 3;
			}
        }
    }
    if (gBattleStats.damage > BATTLE_MAX_DAMAGE)
        gBattleStats.damage = BATTLE_MAX_DAMAGE;
    if (gBattleStats.damage < 0)
        gBattleStats.damage = 0;
    BattleCheckPetrify(attacker, defender);
    if (gBattleStats.damage != 0)
        attacker->nonZeroDamage = TRUE;
}

Here’s a YouTube video showcasing the code, somewhat narrated by yours truly. Just felt like speaking tbh.

Here’s the Daibaba, and this link will be added to the OP, like I always do.

7 Likes

Great stuff! Always super cool to see people experimenting with different crit mechanics.

I just have two quick things to note. First, the function BattleGenerateHitAttributes is hooked by Skillsys’s Battle Proc calc loop, which means your code is incompatible with Skillsys. That’s not a bad thing, of course, just important for users to be aware of.

Second, can you include your source code files with the generated lyn event? I see you’ve written the source code directly into this thread, which means users who want to edit your code will have to copy its contents into a new file and save it. This also leaves out the contents of C_Code.h.

1 Like

Not a bad idea. I plan on doing that next time.

1 Like

TRIANGLE ADEPT WEAPONS

Many thanks to GigaExcalibur for helping with troubleshooting.

Heroes is a lot of things, both good and bad. While I’ll leave you to your discretion on what is considered “good” or “bad”, a mechanic from early FEH that I liked was Triangle Adept and the associated weapons (Ruby Sword, Sapphire Lance, and Emerald Axe), given WT’s sort of heightened importance in like Book 1/Book 2 (my memory of it is fuzzy, haven’t played since last decade). Basically, what the code does is quadruple WT bonuses/penalties if the weapon is considered a “Triangle Adept Weapon”.

Here’s a Youtube Video showing the code in action.

Here’s the Mayor Bo, and this post will be added to the OP as always.

5 Likes

Thought I’d leave this here for SkillSys users:

In my personal Buildfile, I have a custom Skill called “Fateful Crit”, which as the name implies, also makes the user do x4 damage on a crit instead of 3, like Fates killer weapons. Coded by ChiChi (He doesn’t have an FEU account).

It’s implemented in a bit of a complicated way. The skill doesn’t have its own folder. I don’t know precisely how it works… but it works.

1 Like

I came up with the name hehe [I’m very proud of it!]

1 Like

PUNISHER WEAPONS

Many thanks to GigaExcalibur and Jester for helping with troubleshooting.

One thing I liked from Fates was the series of weapons that rewarded capitalizing on WTA by giving them effective damage, like the Pike-Ruin Club. I made them a thing now in GBAFE.

Here’s a video showing the code in action:

Here are the Eyes of Yeto to the hack, and this post will be added to the OP as always.

7 Likes

DSFE STYLE AVOID IN FE6

At long last, I completed the trilogy of DSFE Avoid in the GBA Games. Coincidentally, all 3 of the GBA games were done using ASM, whereas these days I like using C.

In vanilla FE6, the avoid formula is (2AS+Luck), whereas in DSFE the formula is (AS+(Luck/2)). I modded FE6 to have the latter. Check the video below to see it in action

For those curious, it is combatible with the most recent translation patch.

How to: Kill Dodgetanking, Our Boi's Style

Here’s the Bayge, and this post will be added to the OP as I always do.

6 Likes

YOUNGER SYRENE
Made this because I needed it for AoS.

7 Likes

FE6 STYLE MAGIC RANGE
Something from FE6 I grew to appreciate was its formula for staves like warp and rescue (namely warp tho) being 5+MP/2 instead of the usual MP/2 with a floor of 5. I brought that to FE8.

Here’s the Cottla, and this post will be added to the OP as always.

10 Likes

Absolutely, unfathomably based ASM right here

Thanks for the compliment, but these days I use C. This hack is no exception.

1 Like

DSFE STYLE AVOID IN FE4
Yes, folks, you heard that right. This is now a thing. I once again used a hex editor for this shenanigan. Anyways, let’s get onto the main event.

In FE4, avoid is calculated as 2AS + Luck. In Sigurd’s case, it’s 25 (2*(12 Speed - 3 Weight) + 7 Luck).


With DSFE, avoid is calc’d as (AS+(Luck/2,rounded down)), which is why it’s 12 in the screenshot below.

Here’s a video showing off the changes.

How to: Kill Dodgetanking, Belhalla BBQ Syle

Here’s the Koloktos, and this post will be added to the OP as always.

5 Likes

CRIT DISPLAY FIX
What a funny way to celebrate 100 posts on this thread lol. Anyways, let’s get into the meat and potatoes.

In vanilla FE8, battle crit can go beyond 100, even if it doesn’t functionally change anything, so this is basically a small fix to make it more aligned with the modern entries in the series. Below you can see 2 screenshots that reflect it: Eirika has 204 crit, but “only” has 100 crit againt O’Neill.


Here’s a video showing the code in action.

Here’s the Morpheel to the hack, and this post will be added to the OP like always.

6 Likes