const int NPCM_DIFFICULTYFLAG = 14; //npc->Misc[] index used to track enemy difficulty modification. Be sure this doesn't overlap with other scripts.
const int DIFFICULTY_APPLY_NPC_SCALING = 1; //If 1, scaling will be applied to enemies based on settings. If not, that will be skipped completely
//Global damage multipliers for all difficulties
const int DIFFICULTY_VERYEASY_DAMAGE_MULTIPLIER = 1;
const int DIFFICULTY_EASY_DAMAGE_MULTIPLIER = 1;
const int DIFFICULTY_NORMAL_DAMAGE_MULTIPLIER = 1;
const int DIFFICULTY_HARD_DAMAGE_MULTIPLIER = 1;
const int DIFFICULTY_VERYHARD_DAMAGE_MULTIPLIER = 1;
//Enemy base damage multipliers
const int DIFFICULTY_ENEMY_VERYEASY_DAMAGE_MULTIPLIER = 0.5;
const int DIFFICULTY_ENEMY_EASY_DAMAGE_MULTIPLIER = 0.75;
const int DIFFICULTY_ENEMY_NORMAL_DAMAGE_MULTIPLIER = 1;
const int DIFFICULTY_ENEMY_HARD_DAMAGE_MULTIPLIER = 2;
const int DIFFICULTY_ENEMY_VERYHARD_DAMAGE_MULTIPLIER = 4;
//Enemy base HP multipliers
const int DIFFICULTY_ENEMY_VERYEASY_HP_MULTIPLIER = 0.5;
const int DIFFICULTY_ENEMY_EASY_HP_MULTIPLIER = 0.75;
const int DIFFICULTY_ENEMY_NORMAL_HP_MULTIPLIER = 1;
const int DIFFICULTY_ENEMY_HARD_HP_MULTIPLIER = 1.1;
const int DIFFICULTY_ENEMY_VERYHARD_HP_MULTIPLIER = 1.2;
//Enemy base Step multipliers
const int DIFFICULTY_ENEMY_VERYEASY_STEP_MULTIPLIER = 0.8;
const int DIFFICULTY_ENEMY_EASY_STEP_MULTIPLIER = 0.9;
const int DIFFICULTY_ENEMY_NORMAL_STEP_MULTIPLIER = 1;
const int DIFFICULTY_ENEMY_HARD_STEP_MULTIPLIER = 1.1;
const int DIFFICULTY_ENEMY_VERYHARD_STEP_MULTIPLIER = 1.2;
//Item IDs for difficulty selection items
//If using damage divisors for lower difficulties, these should use Peril Ring items for best results
//If 0, that difficulty level will go unused
const int I_DIFF_VERYEASY = 0;
const int I_DIFF_EASY = 0;
const int I_DIFF_NORMAL = 0;
const int I_DIFF_HARD = 0;
const int I_DIFF_VERYHARD = 0;
void DifficultyGlobal_SetEnemyHP(npc n, int val){
//If using ghost.zh, uncomment the following and comment out the line below
//SetEnemyProperty(n, ENPROP_HP, val);
n->HP = val;
}
int DifficultyGlobal_GetEnemyHP(npc n){
//If using ghost.zh, uncomment the following and comment out the line below
//return GetEnemyProperty(n, ENPROP_HP);
return n->HP;
}
//This function handles exceptions to enemy stat calculation / manual stat assignment based on difficulty
//
//Use the following functions as shown in the example comment.
//All use the same 6 arguments, the Enemy's ID, followed by 5 settings for each of the possible difficulties.
//Entering -1 for an argument will tell the script to defer to the global settings.
//Entering -2 for an argument will tell the script to ignore even the global settings, leaving the stat completely unchanged.
// EnemyDiff_HP(NPCID, VeryEasy, Easy, Normal, Hard, VeryHard) - Sets enemy HP
// EnemyDiff_Damage(NPCID, VeryEasy, Easy, Normal, Hard, VeryHard) - Sets contact and weapon damage
// EnemyDiff_ContactDamage(NPCID, VeryEasy, Easy, Normal, Hard, VeryHard) - Sets only contact damage
// EnemyDiff_WeaponDamage(NPCID, VeryEasy, Easy, Normal, Hard, VeryHard) - Sets only weapon damage
// EnemyDiff_Step(NPCID, VeryEasy, Easy, Normal, Hard, VeryHard) - Sets step speed
// EnemyDiff_RandomRate(NPCID, VeryEasy, Easy, Normal, Hard, VeryHard) - Sets random rate
// EnemyDiff_HaltRate(NPCID, VeryEasy, Easy, Normal, Hard, VeryHard) - Sets halt rate
// EnemyDiff_Homing(NPCID, VeryEasy, Easy, Normal, Hard, VeryHard) - Sets homing
// EnemyDiff_Weapon(NPCID, VeryEasy, Easy, Normal, Hard, VeryHard) - Sets weapon (use WPN_ constants from std_constants.zh)
// EnemyDiff_ItemSet(NPCID, VeryEasy, Easy, Normal, Hard, VeryHard) - Sets item dropset
// EnemyDiff_Replace(NPCID, VeryEasy, Easy, Normal, Hard, VeryHard) - Replaces an enemy with another enemy
void DifficultyGlobal_InitEnemyTables(){
//Example Enemy Configuration:
//This would set the Stalfos 2's HP, beam damage, turns off beams on easy mode, and turns off hearts on higher difficulties
//Stalfos 2
// EnemyDiff_HP(NPC_STALFOS2, 2, 2, 4, 4, 6);
// EnemyDiff_WeaponDamage(NPC_STALFOS2, 2, 2, 4, 8, 8);
// EnemyDiff_Weapon(NPC_STALFOS2, WPN_NONE, WPN_NONE, WPN_ENEMYSWORD, WPN_ENEMYSWORD, WPN_ENEMYSWORD);
// EnemyDiff_ItemSet(NPC_STALFOS2, 1, 1, 1, 0, 0);
}
//======= INTERNAL CONSTANTS, DO NOT CHANGE ======
const int DIFF_VERYEASY = 0;
const int DIFF_EASY = 1;
const int DIFF_NORMAL = 2;
const int DIFF_HARD = 3;
const int DIFF_VERYHARD = 4;
//Global array indices
const int __DI_CURDIFFICULTY = 0;
const int __DI_LINKLASTHP = 1;
const int __DI_DIFFICULTYOVERRIDE = 2;
const int __DI_LASTDMAP = 3;
const int __DI_LASTSCREEN = 4;
//Everything past this in the global array is occupied by the enemy table, size 25600 (512x10*5)
const int __DI_ENEMYTABLES_START = 32;
const int __DI_ENEMYTABLES_SLOTSIZE = 10;
const int __DI_ENEMYTABLES_DIFFSIZE = 5120;
const int __DI_ENEMYTABLES_MAXSIZE = 25600;
//Enemy table sub indices
const int __DIT_HP = 0;
const int __DIT_DAMAGE = 1;
const int __DIT_WDAMAGE = 2;
const int __DIT_STEP = 3;
const int __DIT_RANDRATE = 4;
const int __DIT_HALTRATE = 5;
const int __DIT_HOMING = 6;
const int __DIT_WEAPON = 7; //Use WPN_ constants!
const int __DIT_ITEMSET = 8;
const int __DIT_REPLACE = 9;
//===============================================
int DifficultyGlobal[65536];
//Init function for the difficulty script. Call once in global script before void run(){
void DifficultyGlobal_Init(){
DifficultyGlobal_Init(true);
__DifficultyGlobal_ScreenChangeUpdate();
}
void DifficultyGlobal_Init(bool resetOverride){
int i;
for(i=0; i<__DI_ENEMYTABLES_MAXSIZE; ++i)
DifficultyGlobal[__DI_ENEMYTABLES_START+i] = 0;
DifficultyGlobal[__DI_CURDIFFICULTY] = Difficulty_GetDifficulty();
DifficultyGlobal[__DI_LINKLASTHP] = Link->HP;
DifficultyGlobal[__DI_LASTDMAP] = Game->GetCurDMap();
DifficultyGlobal[__DI_LASTSCREEN] = Game->GetCurDMapScreen();
if(resetOverride)
DifficultyGlobal[__DI_DIFFICULTYOVERRIDE] = 0;
DifficultyGlobal_InitEnemyTables();
}
//Update function for the difficulty script. Call once in global script before Waitframe();
void DifficultyGlobal_Update(){
//Update difficulty every frame in case items change
DifficultyGlobal[__DI_CURDIFFICULTY] = Difficulty_GetDifficulty();
//Apply difficulty override
if(DifficultyGlobal[__DI_DIFFICULTYOVERRIDE]){
//<100 = temporary (1 frame) override
if(DifficultyGlobal[__DI_DIFFICULTYOVERRIDE]<100){
DifficultyGlobal[__DI_CURDIFFICULTY] = DifficultyGlobal[__DI_DIFFICULTYOVERRIDE]-1;
DifficultyGlobal[__DI_DIFFICULTYOVERRIDE] = 0;
}
//>100 = permanent override
else if(DifficultyGlobal[__DI_DIFFICULTYOVERRIDE]>100){
DifficultyGlobal[__DI_CURDIFFICULTY] = DifficultyGlobal[__DI_DIFFICULTYOVERRIDE]-101;
}
}
//Remember Link's last HP and apply damage modifiers
if(Link->HP!=DifficultyGlobal[__DI_LINKLASTHP]){
if(Link->HP<DifficultyGlobal[__DI_LINKLASTHP]){
int mult = Difficulty_GetGlobalDamageMultiplier();
//Multipliers of <1 subtract the remainder of the damage Link has taken, leaving only the amount represented by the multiplier
//(this does not actually work as intended at <1 HP, but this is how IoR did it and it)
if(mult<1)
Link->HP -= Abs(DifficultyGlobal[__DI_LINKLASTHP]-Link->HP)*(1-mult);
//Multipliers of >1 subtract the multiplier-1, assuming the damage Link took is 1x damage
else if(mult>1)
Link->HP -= Abs(DifficultyGlobal[__DI_LINKLASTHP]-Link->HP)*(mult-1);
}
DifficultyGlobal[__DI_LINKLASTHP] = Link->HP;
}
//Check when the screen changes and update settings on screen change
if(Game->GetCurDMap()!=DifficultyGlobal[__DI_LASTDMAP]||Game->GetCurDMapScreen()!=DifficultyGlobal[__DI_LASTSCREEN]){
__DifficultyGlobal_ScreenChangeUpdate();
DifficultyGlobal[__DI_LASTDMAP] = Game->GetCurDMap();
DifficultyGlobal[__DI_LASTSCREEN] = Game->GetCurDMapScreen();
}
}
//Enemy update loop for the difficulty script. Call once in global script after DifficultyGlobal_Update();
void DifficultyGlobal_EnemyUpdate(){
int i;
for(i=Screen->NumNPCs(); i>=1; --i){
npc n = Screen->LoadNPC(i);
__DifficultyGlobal_EnemyUpdate_Difficulty(n);
}
}
//Updates difficulty per enemy as they spawn
void __DifficultyGlobal_EnemyUpdate_Difficulty(npc n){
int id = n->ID;
int stat;
int mult;
if(!n->Misc[NPCM_DIFFICULTYFLAG]&&DIFFICULTY_APPLY_NPC_SCALING){
if(n->Type!=NPCT_GUY&&n->Type!=NPCT_FAIRY){
//<< ENEMY HP >>
stat = __EnemyDiff_GetAttrib(id, __DIT_HP, DifficultyGlobal[__DI_CURDIFFICULTY]);
mult = DifficultyGlobal_GetEnemyHPMultiplier();
//If an override was set, use that
if(stat>0){
//Prevent lowering the HP of a splitter
if(!__DifficultyGlobal_HPExceptions(n, stat-1))
DifficultyGlobal_SetEnemyHP(n, stat-1);
}
//Else use the base multiplier
else if(mult>0){
if(DifficultyGlobal_GetEnemyHP(n)>0&&stat!=-1){
stat = Max(1, Ceiling(DifficultyGlobal_GetEnemyHP(n)*mult));
//Prevent lowering the HP of a splitter
if(!__DifficultyGlobal_HPExceptions(n, stat))
DifficultyGlobal_SetEnemyHP(n, stat);
}
}
//<< ENEMY CONTACT DAMAGE >>
stat = __EnemyDiff_GetAttrib(id, __DIT_DAMAGE, DifficultyGlobal[__DI_CURDIFFICULTY]);
mult = Difficulty_GetEnemyDamageMultiplier();
//If an override was set, use that
if(stat>0){
n->Damage = stat-1;
}
//Else use the base multiplier
else if(mult>0){
if(n->Damage>0&&stat!=-1){
n->Damage = Max(1, Ceiling(n->Damage*mult));
}
}
//<< ENEMY WEAPON DAMAGE >>
stat = __EnemyDiff_GetAttrib(id, __DIT_WDAMAGE, DifficultyGlobal[__DI_CURDIFFICULTY]);
mult = Difficulty_GetEnemyDamageMultiplier();
//If an override was set, use that
if(stat>0){
n->WeaponDamage = stat-1;
}
//Else use the base multiplier
else if(mult>0){
if(n->WeaponDamage>0&&stat!=-1){
n->WeaponDamage = Max(1, Ceiling(n->WeaponDamage*mult));
}
}
//<< ENEMY STEP SPEED >>
stat = __EnemyDiff_GetAttrib(id, __DIT_STEP, DifficultyGlobal[__DI_CURDIFFICULTY]);
mult = Difficulty_GetEnemyStepMultiplier();
//If an override was set, use that
if(stat>0){
n->Step = stat-1;
}
//Else use the base multiplier
else if(mult>0&&stat!=-1){
n->Step = Ceiling(n->Step*mult);
}
//<< ENEMY RANDOM RATE >>
stat = __EnemyDiff_GetAttrib(id, __DIT_RANDRATE, DifficultyGlobal[__DI_CURDIFFICULTY]);
//If an override was set, use that
if(stat>0){
n->Rate = stat-1;
}
//<< ENEMY HALT RATE >>
stat = __EnemyDiff_GetAttrib(id, __DIT_HALTRATE, DifficultyGlobal[__DI_CURDIFFICULTY]);
//If an override was set, use that
if(stat>0){
n->Haltrate = stat-1;
}
//<< ENEMY HOMING >>
stat = __EnemyDiff_GetAttrib(id, __DIT_HOMING, DifficultyGlobal[__DI_CURDIFFICULTY]);
//If an override was set, use that
if(stat>0){
n->Homing = stat-1;
}
//<< ENEMY WEAPON >>
stat = __EnemyDiff_GetAttrib(id, __DIT_WEAPON, DifficultyGlobal[__DI_CURDIFFICULTY]);
//If an override was set, use that
if(stat>0){
n->Weapon = stat-1;
}
//<< ENEMY ITEM SET >>
stat = __EnemyDiff_GetAttrib(id, __DIT_ITEMSET, DifficultyGlobal[__DI_CURDIFFICULTY]);
//If an override was set, use that
if(stat>0){
n->ItemSet = stat-1;
}
}
n->Misc[NPCM_DIFFICULTYFLAG] = 1;
}
}
//Updates difficulty settings as the screen changes
void __DifficultyGlobal_ScreenChangeUpdate(){
int i;
int id;
int replace;
int newEnemies[10];
int enemyCount;
for(i=0; i<10; ++i){
id = Screen->Enemy[i];
replace = __EnemyDiff_GetAttrib(id, __DIT_REPLACE, DifficultyGlobal[__DI_CURDIFFICULTY]);
if(replace){
id = replace-1;
}
if(id){
newEnemies[enemyCount] = id;
++enemyCount;
}
}
for(i=0; i<10; ++i){
Screen->Enemy[i] = newEnemies[i];
}
}
void __EnemyDiff_SetAttrib(int npcID, int attrib, int veryEasy, int easy, int normal, int hard, int veryHard){
if(veryHard!=-1)
DifficultyGlobal[__DI_ENEMYTABLES_START+__DI_ENEMYTABLES_DIFFSIZE*DIFF_VERYHARD+__DI_ENEMYTABLES_SLOTSIZE*npcID+attrib] = veryHard+1;
if(hard!=-1)
DifficultyGlobal[__DI_ENEMYTABLES_START+__DI_ENEMYTABLES_DIFFSIZE*DIFF_HARD+__DI_ENEMYTABLES_SLOTSIZE*npcID+attrib] = hard+1;
if(normal!=-1)
DifficultyGlobal[__DI_ENEMYTABLES_START+__DI_ENEMYTABLES_DIFFSIZE*DIFF_NORMAL+__DI_ENEMYTABLES_SLOTSIZE*npcID+attrib] = normal+1;
if(easy!=-1)
DifficultyGlobal[__DI_ENEMYTABLES_START+__DI_ENEMYTABLES_DIFFSIZE*DIFF_EASY+__DI_ENEMYTABLES_SLOTSIZE*npcID+attrib] = easy+1;
if(veryEasy!=-1)
DifficultyGlobal[__DI_ENEMYTABLES_START+__DI_ENEMYTABLES_DIFFSIZE*DIFF_VERYEASY+__DI_ENEMYTABLES_SLOTSIZE*npcID+attrib] = veryEasy+1;
}
int __EnemyDiff_GetAttrib(int npcID, int attrib, int diff){
return DifficultyGlobal[__DI_ENEMYTABLES_START+__DI_ENEMYTABLES_DIFFSIZE*diff+__DI_ENEMYTABLES_SLOTSIZE*npcID+attrib];
}
void EnemyDiff_HP(int npcID, int veryEasy, int easy, int normal, int hard, int veryHard){
__EnemyDiff_SetAttrib(npcID, __DIT_HP, veryEasy, easy, normal, hard, veryHard);
}
void EnemyDiff_Damage(int npcID, int veryEasy, int easy, int normal, int hard, int veryHard){
__EnemyDiff_SetAttrib(npcID, __DIT_DAMAGE, veryEasy, easy, normal, hard, veryHard);
__EnemyDiff_SetAttrib(npcID, __DIT_WDAMAGE, veryEasy, easy, normal, hard, veryHard);
}
void EnemyDiff_ContactDamage(int npcID, int veryEasy, int easy, int normal, int hard, int veryHard){
__EnemyDiff_SetAttrib(npcID, __DIT_DAMAGE, veryEasy, easy, normal, hard, veryHard);
}
void EnemyDiff_WeaponDamage(int npcID, int veryEasy, int easy, int normal, int hard, int veryHard){
__EnemyDiff_SetAttrib(npcID, __DIT_WDAMAGE, veryEasy, easy, normal, hard, veryHard);
}
void EnemyDiff_Step(int npcID, int veryEasy, int easy, int normal, int hard, int veryHard){
__EnemyDiff_SetAttrib(npcID, __DIT_STEP, veryEasy, easy, normal, hard, veryHard);
}
void EnemyDiff_RandomRate(int npcID, int veryEasy, int easy, int normal, int hard, int veryHard){
__EnemyDiff_SetAttrib(npcID, __DIT_RANDRATE, veryEasy, easy, normal, hard, veryHard);
}
void EnemyDiff_HaltRate(int npcID, int veryEasy, int easy, int normal, int hard, int veryHard){
__EnemyDiff_SetAttrib(npcID, __DIT_HALTRATE, veryEasy, easy, normal, hard, veryHard);
}
void EnemyDiff_Homing(int npcID, int veryEasy, int easy, int normal, int hard, int veryHard){
__EnemyDiff_SetAttrib(npcID, __DIT_HOMING, veryEasy, easy, normal, hard, veryHard);
}
void EnemyDiff_Weapon(int npcID, int veryEasy, int easy, int normal, int hard, int veryHard){
__EnemyDiff_SetAttrib(npcID, __DIT_WEAPON, veryEasy, easy, normal, hard, veryHard);
}
void EnemyDiff_ItemSet(int npcID, int veryEasy, int easy, int normal, int hard, int veryHard){
__EnemyDiff_SetAttrib(npcID, __DIT_ITEMSET, veryEasy, easy, normal, hard, veryHard);
}
void EnemyDiff_Replace(int npcID, int veryEasy, int easy, int normal, int hard, int veryHard){
__EnemyDiff_SetAttrib(npcID, __DIT_REPLACE, veryEasy, easy, normal, hard, veryHard);
}
//Returns true if an enemy has problems with lowering HP
bool __DifficultyGlobal_HPExceptions(npc n, int targetHP){
int hp = DifficultyGlobal_GetEnemyHP(n);
if(n->Type==NPCT_WALK&&n->Attributes[1]==1)
return true;
if(n->Type==NPCT_GLEEOK&&targetHP<hp)
return true;
return false;
}
void DifficultyGlobal_SetDifficulty(int diffLevel){
//Remove items for all active levels of difficulty
if(I_DIFF_VERYEASY)
Link->Item[I_DIFF_VERYEASY] = false;
if(I_DIFF_EASY)
Link->Item[I_DIFF_EASY] = false;
if(I_DIFF_NORMAL)
Link->Item[I_DIFF_NORMAL] = false;
if(I_DIFF_HARD)
Link->Item[I_DIFF_HARD] = false;
if(I_DIFF_VERYHARD)
Link->Item[I_DIFF_VERYHARD] = false;
//Give the item for the current difficulty level
if(diffLevel==0)
Link->Item[I_DIFF_VERYEASY] = true;
else if(diffLevel==1)
Link->Item[I_DIFF_EASY] = true;
else if(diffLevel==2)
Link->Item[I_DIFF_NORMAL] = true;
else if(diffLevel==3)
Link->Item[I_DIFF_HARD] = true;
else if(diffLevel==4)
Link->Item[I_DIFF_VERYHARD] = true;
else
Link->Item[I_DIFF_NORMAL] = true;
}
//Returns a numbered value for the current difficulty level
//Based on items in Link's inventory
int Difficulty_GetDifficulty(){
if(DifficultyGlobal[__DI_DIFFICULTYOVERRIDE]){
//<100 = temporary (1 frame) override
if(DifficultyGlobal[__DI_DIFFICULTYOVERRIDE]<100){
return DifficultyGlobal[__DI_DIFFICULTYOVERRIDE]-1;
}
//>100 = permanent override
else if(DifficultyGlobal[__DI_DIFFICULTYOVERRIDE]>100){
return DifficultyGlobal[__DI_DIFFICULTYOVERRIDE]-101;
}
}
if(I_DIFF_VERYHARD){
if(Link->Item[I_DIFF_VERYHARD])
return DIFF_VERYHARD;
}
if(I_DIFF_HARD){
if(Link->Item[I_DIFF_HARD])
return DIFF_HARD;
}
if(I_DIFF_NORMAL){
if(Link->Item[I_DIFF_NORMAL])
return DIFF_NORMAL;
}
if(I_DIFF_EASY){
if(Link->Item[I_DIFF_EASY])
return DIFF_EASY;
}
if(I_DIFF_VERYEASY){
if(Link->Item[I_DIFF_VERYEASY])
return DIFF_VERYEASY;
}
return DIFF_NORMAL;
}
//Returns one of 5 options based on the current difficulty, starting from easy and going to very hard
int Difficulty_DiffMod(int dVeryEasy, int dEasy, int dNormal, int dHard, int dVeryHard){
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_VERYHARD)
return dVeryHard;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_HARD)
return dHard;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_NORMAL)
return dNormal;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_EASY)
return dEasy;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_VERYEASY)
return dVeryEasy;
return dNormal;
}
//Returns the global damage multiplier, which all Link's damage is multiplied by
int Difficulty_GetGlobalDamageMultiplier(){
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_VERYHARD)
return DIFFICULTY_VERYHARD_DAMAGE_MULTIPLIER;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_HARD)
return DIFFICULTY_HARD_DAMAGE_MULTIPLIER;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_NORMAL)
return DIFFICULTY_NORMAL_DAMAGE_MULTIPLIER;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_EASY)
return DIFFICULTY_EASY_DAMAGE_MULTIPLIER;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_VERYEASY)
return DIFFICULTY_VERYEASY_DAMAGE_MULTIPLIER;
return DIFFICULTY_NORMAL_DAMAGE_MULTIPLIER;
}
//Returns the enemy HP multiplier, which all enemy HP is multiplied by
int DifficultyGlobal_GetEnemyHPMultiplier(){
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_VERYHARD)
return DIFFICULTY_ENEMY_VERYHARD_HP_MULTIPLIER;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_HARD)
return DIFFICULTY_ENEMY_HARD_HP_MULTIPLIER;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_NORMAL)
return DIFFICULTY_ENEMY_NORMAL_HP_MULTIPLIER;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_EASY)
return DIFFICULTY_ENEMY_EASY_HP_MULTIPLIER;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_VERYEASY)
return DIFFICULTY_ENEMY_VERYEASY_HP_MULTIPLIER;
return DIFFICULTY_ENEMY_NORMAL_HP_MULTIPLIER;
}
//Returns the enemy damage multiplier, which all enemy damage to Link is multiplied by
int Difficulty_GetEnemyDamageMultiplier(){
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_VERYHARD)
return DIFFICULTY_ENEMY_VERYHARD_DAMAGE_MULTIPLIER;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_HARD)
return DIFFICULTY_ENEMY_HARD_DAMAGE_MULTIPLIER;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_NORMAL)
return DIFFICULTY_ENEMY_NORMAL_DAMAGE_MULTIPLIER;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_EASY)
return DIFFICULTY_ENEMY_EASY_DAMAGE_MULTIPLIER;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_VERYEASY)
return DIFFICULTY_ENEMY_VERYEASY_DAMAGE_MULTIPLIER;
return DIFFICULTY_ENEMY_NORMAL_DAMAGE_MULTIPLIER;
}
//Returns the enemy step multiplier, which all enemy step speed is multiplied by
int Difficulty_GetEnemyStepMultiplier(){
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_VERYHARD)
return DIFFICULTY_ENEMY_VERYHARD_STEP_MULTIPLIER;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_HARD)
return DIFFICULTY_ENEMY_HARD_STEP_MULTIPLIER;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_NORMAL)
return DIFFICULTY_ENEMY_NORMAL_STEP_MULTIPLIER;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_EASY)
return DIFFICULTY_ENEMY_EASY_STEP_MULTIPLIER;
if(DifficultyGlobal[__DI_CURDIFFICULTY]==DIFF_VERYEASY)
return DIFFICULTY_ENEMY_VERYEASY_STEP_MULTIPLIER;
return DIFFICULTY_ENEMY_NORMAL_STEP_MULTIPLIER;
}
//Item script for difficulty pickups (for removing other difficulty items)
//D0: ID of this item
item script Difficulty_PickupItem{
void run(int itemID){
//Remove items for all active levels of difficulty
if(I_DIFF_VERYEASY)
Link->Item[I_DIFF_VERYEASY] = false;
if(I_DIFF_EASY)
Link->Item[I_DIFF_EASY] = false;
if(I_DIFF_NORMAL)
Link->Item[I_DIFF_NORMAL] = false;
if(I_DIFF_HARD)
Link->Item[I_DIFF_HARD] = false;
if(I_DIFF_VERYHARD)
Link->Item[I_DIFF_VERYHARD] = false;
//Give Link the item for the currently selected difficulty
Link->Item[itemID] = true;
DifficultyGlobal_Init();
}
}
//Forces difficulty on a screen to the desired level
//D0: Level to set difficulty to. 0 = Very Easy, 4 = Very Hard. -1 = Unset Override
//D1: Whether to make the change permanent
// If 1, the difficulty change will give Link the actual difficulty item and apply forever.
// If 2, it will persist until F6 or encountering another instance of this script
ffc script Difficulty_Override{
void run(int diffLevel, int perm){
if(perm){
//Give item permanently
if(perm==1){
diffLevel = Clamp(diffLevel, 0, 4);
DifficultyGlobal_SetDifficulty(diffLevel);
//Initialize the difficulty global to update enemy data
DifficultyGlobal_Init();
}
//Turn on long term override
else if(perm==2){
diffLevel = Clamp(diffLevel, -1, 4);
//Turn off long term override
if(diffLevel==-1){
DifficultyGlobal[__DI_DIFFICULTYOVERRIDE] = 0;
}
else{
//Difficulty Override >100 means temporary override is on until turned off
DifficultyGlobal[__DI_DIFFICULTYOVERRIDE] = 101+diffLevel;
}
//Initialize the difficulty global to update enemy data
DifficultyGlobal_Init(false);
}
}
else{
diffLevel = Clamp(diffLevel, 0, 4);
DifficultyGlobal[__DI_DIFFICULTYOVERRIDE] = 1+diffLevel;
//Initialize the difficulty global to update enemy data
DifficultyGlobal_Init(false);
while(true){
//Difficulty Override >1 means temporary override is on for that frame
DifficultyGlobal[__DI_DIFFICULTYOVERRIDE] = 1+diffLevel;
Waitframe();
}
}
}
}
const int SFX_DIFFICULTY_SELECT = 6; //Sound when moving difficulty selection cursor
const int CMB_AUTOWARPA = 504; //An invisible combo with the Auto Side Warp A type
//Colors for black, white, and gray. Used for selection menu drawing.
const int C_WHITE = 0x01;
const int C_GRAY = 0x02;
const int C_BLACK = 0x0F;
//Very basic script for a difficulty selection menu:
//D0: The default difficulty. See DIFF_ constants.
//D3-D7: Editor strings containing the names of each difficulty level from Very Easy (D3) to Very Hard (D7). If 0, that difficulty will be skipped
ffc script Difficulty_SelectionScreen{
void run(int defaultDifficulty, int dummy1, int dummy2, int[] msgVeryEasy, int[] msgEasy, int[] msgNormal, int[] msgHard, int[] msgVeryHard){
int i;
int sSelect[] = "SELECT YOUR DIFFICULTY:";
int sVeryEasy[256];
int sEasy[256];
int sNormal[256];
int sHard[256];
int sVeryHard[256];
untyped options[5];
int optionValues[5];
int selection;
int numOptions;
if(msgVeryEasy){
GetMessage(msgVeryEasy, sVeryEasy);
if(defaultDifficulty==DIFF_VERYEASY)
selection = numOptions;
options[numOptions] = sVeryEasy;
optionValues[numOptions] = 0;
++numOptions;
}
if(msgEasy){
GetMessage(msgEasy, sEasy);
if(defaultDifficulty==DIFF_EASY)
selection = numOptions;
options[numOptions] = sEasy;
optionValues[numOptions] = 1;
++numOptions;
}
if(msgNormal){
GetMessage(msgNormal, sNormal);
if(defaultDifficulty==DIFF_NORMAL)
selection = numOptions;
options[numOptions] = sNormal;
optionValues[numOptions] = 2;
++numOptions;
}
if(msgHard){
GetMessage(msgHard, sHard);
if(defaultDifficulty==DIFF_HARD)
selection = numOptions;
options[numOptions] = sHard;
optionValues[numOptions] = 3;
++numOptions;
}
if(msgVeryHard){
GetMessage(msgVeryHard, sVeryHard);
if(defaultDifficulty==DIFF_VERYHARD)
selection = numOptions;
options[numOptions] = sVeryHard;
optionValues[numOptions] = 4;
++numOptions;
}
if(numOptions){
while(true){
DiffMenu_DrawString(6, 128, 32, FONT_Z1, C_WHITE, C_BLACK, TF_CENTERED, sSelect, 128);
if(Link->PressUp){
Game->PlaySound(SFX_DIFFICULTY_SELECT);
--selection;
if(selection<0)
selection = numOptions-1;
}
else if(Link->PressDown){
Game->PlaySound(SFX_DIFFICULTY_SELECT);
++selection;
if(selection>numOptions-1)
selection = 0;
}
for(i=0; i<numOptions; ++i){
if(selection==i)
DiffMenu_DrawString(6, 128, 64+12*i, FONT_Z1, C_WHITE, C_BLACK, TF_CENTERED, options[i], 128);
else
DiffMenu_DrawString(6, 128, 64+12*i, FONT_Z1, C_GRAY, C_BLACK, TF_CENTERED, options[i], 128);
}
if(Link->PressA||Link->PressStart){
DifficultyGlobal_SetDifficulty(optionValues[selection]);
this->Data = CMB_AUTOWARPA;
}
Link->PressStart = false; Link->InputStart = false;
Link->PressMap = false; Link->InputMap = false;
NoAction();
Waitframe();
}
}
}
void DiffMenu_DrawString(int layer, int x, int y, int font, int c1, int c2, int tf, int str, int op){
Screen->DrawString(layer, x-1, y, font, c2, -1, tf, str, op);
Screen->DrawString(layer, x+1, y, font, c2, -1, tf, str, op);
Screen->DrawString(layer, x, y-1, font, c2, -1, tf, str, op);
Screen->DrawString(layer, x, y+1, font, c2, -1, tf, str, op);
Screen->DrawString(layer, x, y, font, c1, -1, tf, str, op);
}
}
//Script to copy an entire screen onto another screen or layer based on difficulty.
//This cannot change enemy lists or FFC data. Sorry.
//D0: Map to copy screens from
//D1: If >0, copy to that layer on this screen (this change is permanent until save/load)
//D3-D7: Screens on the map (in decimal) to copy from for difficulties Very Easy (D3) to Very Hard (D7). If -1, don't copy screen
ffc script Difficulty_ReplaceScreen{
void run(int map, int layer, int dummy1, int scrnVeryEasy, int scrnEasy, int scrnNormal, int scrnHard, int scrnVeryHard){
layer = Clamp(layer, 0, 6);
int diff = Difficulty_GetDifficulty();
if(diff==DIFF_VERYEASY){
if(scrnVeryEasy>-1){
ChangeScreen_CopyScreen(map, scrnVeryEasy, layer);
}
}
else if(diff==DIFF_EASY){
if(scrnEasy>-1){
ChangeScreen_CopyScreen(map, scrnEasy, layer);
}
}
else if(diff==DIFF_NORMAL){
if(scrnNormal>-1){
ChangeScreen_CopyScreen(map, scrnNormal, layer);
}
}
else if(diff==DIFF_HARD){
if(scrnHard>-1){
ChangeScreen_CopyScreen(map, scrnHard, layer);
}
}
else if(diff==DIFF_VERYHARD){
if(scrnVeryHard>-1){
ChangeScreen_CopyScreen(map, scrnVeryHard, layer);
}
}
}
void ChangeScreen_CopyScreen(int map, int scrn, int layer){
layer = Clamp(layer, 0, 6);
if(layer==0){
for(int i=0; i<176; ++i){
Screen->ComboD[i] = Game->GetComboData(map, scrn, i);
Screen->ComboC[i] = Game->GetComboCSet(map, scrn, i);
Screen->ComboF[i] = Game->GetComboFlag(map, scrn, i);
}
}
else{
int layerMap = Screen->LayerMap(layer);
int layerScreen = Screen->LayerScreen(layer);
if(layerMap>-1&&layerScreen>-1){
for(int i=0; i<176; ++i){
Game->SetComboData(layerMap, layerScreen, i, Game->GetComboData(map, scrn, i));
Game->SetComboCSet(layerMap, layerScreen, i, Game->GetComboCSet(map, scrn, i));
Game->SetComboFlag(layerMap, layerScreen, i, Game->GetComboFlag(map, scrn, i));
}
}
}
}
}
//Script to replace all instances of a combo onscreen based on difficulty
//D0: A combo to search for on layer 0
//D3-D7: Combos to replace it with on each difficulty from Very Easy (D3) to Very Hard (D7). If 0, don't replace for that difficulty.
ffc script Difficulty_ReplaceCombo{
void run(int srcCombo, int dummy1, int dummy2, int destVeryEasy, int destEasy, int destNormal, int destHard, int destVeryHard){
int diff = Difficulty_GetDifficulty();
int destCombo = -1;
if(diff==DIFF_VERYEASY){
destCombo = destVeryEasy;
}
else if(diff==DIFF_EASY){
destCombo = destEasy;
}
else if(diff==DIFF_NORMAL){
destCombo = destNormal;
}
else if(diff==DIFF_HARD){
destCombo = destHard;
}
else if(diff==DIFF_VERYHARD){
destCombo = destVeryHard;
}
if(destCombo>0){
for(int i=0; i<176; ++i){
if(Screen->ComboD[i]==srcCombo){
Screen->ComboD[i] = destCombo;
}
}
}
}
}
//Script to change a warp based on difficulty
//D0: Warp DMap
//D1: Warp Screen
//D2: Whether to change a tile warp or side warp. 0 = Tile Warp, 1 = Side Warp
//D3: Which warp to change (0 = A, 1 = B, 2 = C, 3 = D)
//D4: Difficulty level to activate the warp (See DIFF_ constants)
ffc script Difficulty_ChangeWarp{
void run(int dmap, int scrn, int sideWarp, int whichWarp, int warpDifficulty){
int warpType;
int diff = Difficulty_GetDifficulty();
if(diff==warpDifficulty){
if(sideWarp==0){
warpType = Screen->GetTileWarpType(whichWarp);
if(warpType==WT_CAVE)
warpType = WT_IWARPBLACKOUT;
Screen->SetTileWarp(whichWarp, scrn, dmap, warpType);
}
else{
warpType = Screen->GetSideWarpType(whichWarp);
if(warpType==WT_CAVE)
warpType = WT_IWARPBLACKOUT;
Screen->SetSideWarp(whichWarp, scrn, dmap, warpType);
}
}
}
}
//Example global script
global script Difficulty_Example{
void run(){
DifficultyGlobal_Init();
while(true){
DifficultyGlobal_Update();
DifficultyGlobal_EnemyUpdate();
Waitframe();
}
}
}