939 lines
26 KiB
Plaintext
939 lines
26 KiB
Plaintext
/*
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
UNIVERSAL LIBRARY FOR ENEMY-RELATED FUNCTIONS
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
*/
|
|
|
|
// Code by Kevinmonitor with some assistance.
|
|
/*
|
|
|
|
///////////// ENEMY SPAWNING DURING STAGES /////////////
|
|
|
|
*/
|
|
|
|
function <int> _InitDifficulty(int diffInt){
|
|
|
|
int difficulty = 0;
|
|
|
|
if(GetCommonData("Difficulty", "Normal") == "Normal"){
|
|
difficulty = 0;
|
|
}
|
|
|
|
else if(GetCommonData("Difficulty", "Normal") == "Hard"){
|
|
difficulty = 1;
|
|
}
|
|
|
|
else if(GetCommonData("Difficulty", "Normal") == "Lunatic"){
|
|
difficulty = 2;
|
|
}
|
|
|
|
return difficulty;
|
|
}
|
|
|
|
// Explosion Sound Effects
|
|
|
|
task _RenderBoss(int enemy){
|
|
|
|
int aniidle = 0;
|
|
|
|
string tex = "script/game/resourceLib/Spritesheet_StationJam.png";
|
|
|
|
LoadTextureEx(tex, true, true);
|
|
|
|
ObjPrim_SetTexture(enemy, tex);
|
|
ObjSprite2D_SetSourceRect(enemy, 1280, 0, 1280+256, 256);
|
|
ObjSprite2D_SetDestCenter(enemy);
|
|
ObjRender_SetScaleXYZ(enemy, 1);
|
|
|
|
int nameText = CreateTextObject(
|
|
GetStgFrameWidth()*0.3, 200, 25,
|
|
"REMILIA SCARLET", "Origami Mommy",
|
|
0xFF5A5A, 0xFFFFFF,
|
|
0x791D1D, 3,
|
|
1
|
|
);
|
|
|
|
ObjRender_SetAngleZ(nameText, -90);
|
|
ObjText_SetFontBold(nameText, true);
|
|
|
|
//_BossMarker(enemy, tex, 512, 0, 768, 256, 0.45, 30);
|
|
|
|
while(!Obj_IsDeleted(enemy)){
|
|
|
|
yield;
|
|
|
|
}
|
|
}
|
|
|
|
task _RenderMidboss(int enemy){
|
|
|
|
int aniidle = 0;
|
|
|
|
string tex = "script/game/StageLib/BossAsset.png";
|
|
|
|
LoadTextureEx(tex, true, true);
|
|
|
|
int nameText = CreateTextObject(
|
|
GetStgFrameWidth()*0.38, 10, 42,
|
|
"MIDBOSS: Kobiko", "Connecting Chain Handserif",
|
|
0xBA8AFF, 0xFFFFFF,
|
|
0x552A9C, 3,
|
|
1
|
|
);
|
|
|
|
ObjText_SetFontBold(nameText, true);
|
|
ObjPrim_SetTexture(enemy, tex);
|
|
ObjSprite2D_SetSourceRect(enemy, 768, 0, 768+512, 512);
|
|
ObjSprite2D_SetDestCenter(enemy);
|
|
ObjRender_SetScaleXYZ(enemy, 0.5);
|
|
|
|
_BossMarker(enemy, tex, 512, 256, 768, 512, 0.45, 30);
|
|
|
|
while(!Obj_IsDeleted(enemy)){
|
|
|
|
yield;
|
|
|
|
}
|
|
}
|
|
|
|
task _FadeInSpawn(
|
|
int enemyID,
|
|
float spawnX, float spawnY,
|
|
float destX, float destY,
|
|
float spawnScale, float destScale,
|
|
int time){
|
|
|
|
ObjMove_SetPosition(enemyID, spawnX, spawnY);
|
|
ObjRender_SetAlpha(enemyID, 0);
|
|
|
|
ObjMove_SetDestAtFrame(enemyID, destX, destY, time, LERP_DECELERATE);
|
|
|
|
ascent(i in 0..time){
|
|
ObjRender_SetAlpha(enemyID, Interpolate_Decelerate(0, 255, i/time));
|
|
ObjRender_SetScaleXYZ(enemyID, Interpolate_Decelerate(spawnScale, destScale, i/time));
|
|
yield;
|
|
}
|
|
|
|
}
|
|
|
|
int itemScript = LoadScriptInThread("script/KevinSystem/kevin_system/KevinSystem_Item.txt");
|
|
StartScript(itemScript);
|
|
|
|
// Creates an enemy and spawns them using _FadeInSpawn. Shooting and movement tasks not covered.
|
|
// Task also handles deleting the enemy after their life reaches 0.
|
|
|
|
/*
|
|
BhestieBlue: 0, 0, 256, 256
|
|
BhestieGreen: 256, 0, 512, 256
|
|
GaySamoyed: 0, 256, 256, 512
|
|
EvilSamoyed: 256, 256, 512, 512
|
|
*/
|
|
|
|
function <int> _CreateEnemy(
|
|
float spawnX, float spawnY, float destX, float destY, int spawntime,
|
|
float spawnScale, float destScale,
|
|
float health, float sizeHitbox, float sizeHurtbox,
|
|
texture,
|
|
int rectLeft, int rectTop, int rectRight, int rectBottom){
|
|
|
|
// Essentials
|
|
int enemyID = ObjEnemy_Create(OBJ_ENEMY);
|
|
ObjEnemy_Regist(enemyID);
|
|
ObjEnemy_SetLife(enemyID, health);
|
|
ObjEnemy_SetAutoDelete(enemyID, true);
|
|
|
|
// TBA: Handle animations
|
|
ObjPrim_SetTexture(enemyID, texture);
|
|
ObjSprite2D_SetSourceRect(enemyID, rectLeft, rectTop, rectRight, rectBottom);
|
|
ObjSprite2D_SetDestCenter(enemyID);
|
|
|
|
// Spawning
|
|
_FadeInSpawn(enemyID, spawnX, spawnY, destX, destY, spawnScale, destScale, spawntime);
|
|
_HandleEnemyWellbeing(enemyID, sizeHitbox, sizeHurtbox);
|
|
|
|
return enemyID;
|
|
|
|
}
|
|
|
|
// Special overload for creating hitbox/hurtboxless enemies.
|
|
|
|
function <int> _CreateEnemy(
|
|
bool intersectionrender,
|
|
float spawnX, float spawnY, float destX, float destY, int spawntime,
|
|
float spawnScale, float destScale,
|
|
float health, float sizeHitbox, float sizeHurtbox,
|
|
texture,
|
|
int rectLeft, int rectTop, int rectRight, int rectBottom){
|
|
|
|
// Essentials
|
|
int enemyID = ObjEnemy_Create(OBJ_ENEMY);
|
|
ObjEnemy_Regist(enemyID);
|
|
ObjEnemy_SetLife(enemyID, health);
|
|
ObjEnemy_SetAutoDelete(enemyID, true);
|
|
|
|
// TBA: Handle animations
|
|
ObjPrim_SetTexture(enemyID, texture);
|
|
ObjSprite2D_SetSourceRect(enemyID, rectLeft, rectTop, rectRight, rectBottom);
|
|
ObjSprite2D_SetDestCenter(enemyID);
|
|
|
|
// Spawning
|
|
_FadeInSpawn(enemyID, spawnX, spawnY, destX, destY, spawnScale, destScale, spawntime);
|
|
if (intersectionrender){_HandleEnemyWellbeing(enemyID, sizeHitbox, sizeHurtbox);}
|
|
else{}
|
|
|
|
return enemyID;
|
|
|
|
}
|
|
|
|
|
|
// Hitbox and deletion
|
|
|
|
task _HandleEnemyWellbeing(int enemyID, float sizeHitbox, float sizeHurtbox){
|
|
|
|
while(ObjEnemy_GetInfo(enemyID, INFO_LIFE) > 0){
|
|
ObjEnemy_SetIntersectionCircleToShot(enemyID, ObjMove_GetX(enemyID), ObjMove_GetY(enemyID), sizeHitbox);
|
|
ObjEnemy_SetIntersectionCircleToPlayer(enemyID, ObjMove_GetX(enemyID), ObjMove_GetY(enemyID), sizeHurtbox);
|
|
yield;
|
|
}
|
|
Obj_Delete(enemyID);
|
|
}
|
|
|
|
|
|
// Fading invincibility for bosses/enemies (with parameters for wait times and fade times, and a separate multiplier for bomb damage rate (final spells))
|
|
|
|
task _FadeInvincibility(int target, int waittime, int fadetime, float bombmultiplier){
|
|
|
|
float x = 0;
|
|
ObjEnemy_SetDamageRate(target, 0, 0);
|
|
wait(waittime);
|
|
ascent(i in 0..fadetime){
|
|
x = Interpolate_Accelerate(0, 100, i/fadetime);
|
|
ObjEnemy_SetDamageRate(target, x, x*bombmultiplier);
|
|
yield;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
///////////// HANDLING THE END OF SINGLES (DURING BOSS/MIDBOSS FIGHTS) /////////////
|
|
|
|
To-do: Move item creation to the item script(s)
|
|
|
|
*/
|
|
|
|
////// NEW //////
|
|
|
|
task _GoToBrazil(
|
|
int targetscene, targetenemy,
|
|
int maxitemdrop, int minitemdrop){
|
|
|
|
while(ObjEnemy_GetInfo(targetenemy, INFO_LIFE)>0){
|
|
yield;
|
|
}
|
|
|
|
maxitemdrop = 14;
|
|
minitemdrop = 7;
|
|
|
|
int finalItemDrop = 0;
|
|
let itemType = POINT_RAINBOW;
|
|
|
|
int maxTimer = ObjEnemyBossScene_GetInfo(targetscene, INFO_ORGTIMERF);
|
|
int killTimer = ObjEnemyBossScene_GetInfo(targetscene, INFO_TIMERF);
|
|
|
|
bool isnon = ObjEnemyBossScene_GetInfo(targetscene, INFO_IS_SPELL);
|
|
|
|
// If the boss is killed within the first 1/5 of the timer, drop full items
|
|
|
|
if(killTimer >= maxTimer*(4/5)) {finalItemDrop = maxitemdrop;}
|
|
|
|
// Starting from the rest of the timer, the maximum items that can be dropped is equal to 4/5 of the max drop amount
|
|
|
|
else{finalItemDrop = Interpolate_Decelerate(minitemdrop, maxitemdrop*(4/5), killTimer/(maxTimer*4/5));}
|
|
|
|
// If the player has lost a life, lock the number of items to the lowest possible
|
|
|
|
if(ObjEnemyBossScene_GetInfo(targetscene, INFO_PLAYER_SHOOTDOWN_COUNT) > 0){
|
|
finalItemDrop = minitemdrop;
|
|
//itemType = POINT_REGULAR;
|
|
}
|
|
|
|
DeleteShotAll(TYPE_ALL,TYPE_ITEM);
|
|
|
|
SetPlayerInvincibilityFrame(120);
|
|
|
|
// Common Data
|
|
|
|
NotifyEventAll(EV_SINGLE_ITEM_DROP, ObjMove_GetX(targetenemy), ObjMove_GetY(targetenemy), finalItemDrop, itemType);
|
|
|
|
wait(120);
|
|
|
|
float[] enemyPos = [ObjMove_GetX(targetenemy), ObjMove_GetY(targetenemy)];
|
|
|
|
SetCommonData("Entering PIV", GetAreaCommonData("PIV", "currentvalue", 10000));
|
|
SetCommonData("Boss Position X", enemyPos[0]);
|
|
SetCommonData("Boss Position Y", enemyPos[1]);
|
|
|
|
Obj_Delete(targetenemy);
|
|
|
|
}
|
|
|
|
////// OLD/LEGACY //////
|
|
// Basic post-death handling after every attack (Duo).
|
|
|
|
function _GoToBrazilDuo(targetscene, targetenemy, targetenemyA, targetenemyB, returnXA, returnYA, returnXB, returnYB, bool isnon, int itemdropamount){
|
|
|
|
while(ObjEnemy_GetInfo(targetenemy, INFO_LIFE) > 0){
|
|
yield;
|
|
}
|
|
|
|
DeleteShotAll(TYPE_ALL,TYPE_ITEM);
|
|
SetPlayerInvincibilityFrame(120);
|
|
|
|
// returnX and returnY are the boss positions they return to at the end of every pattern. (I'm too lazy for common data...)
|
|
|
|
ObjMove_CancelMovement(targetenemyA); ObjMove_CancelMovement(targetenemyB);
|
|
|
|
ObjMove_SetDestAtFrame(targetenemyA, returnXA, returnYA, 45, LERP_DECELERATE);
|
|
ObjMove_SetDestAtFrame(targetenemyB, returnXB, returnYB, 45, LERP_DECELERATE);
|
|
|
|
async{
|
|
wait(45);
|
|
ObjMove_CancelMovement(targetenemyA); ObjMove_CancelMovement(targetenemyB);
|
|
ObjMove_SetDestAtFrame(targetenemyA, returnXA, returnYA, 15, LERP_DECELERATE);
|
|
ObjMove_SetDestAtFrame(targetenemyB, returnXB, returnYB, 15, LERP_DECELERATE);
|
|
ObjMove_SetProcessMovement(targetenemyA, false);
|
|
ObjMove_SetProcessMovement(targetenemyB, false);
|
|
return;
|
|
}
|
|
|
|
alternative(isnon)
|
|
|
|
case(true){_NonspellItemDrop(targetscene, targetenemyA, itemdropamount); _NonspellItemDrop(targetscene, targetenemyB, itemdropamount);}
|
|
|
|
others{_SpellItemDrop(targetscene, targetenemyA, itemdropamount); _SpellItemDrop(targetscene, targetenemyB, itemdropamount);}
|
|
|
|
wait(120);
|
|
|
|
Obj_Delete(targetenemy);
|
|
Obj_Delete(targetenemyA);
|
|
Obj_Delete(targetenemyB);
|
|
|
|
}
|
|
|
|
// Basic post-death handling after every attack (Solo).
|
|
|
|
task _GoToBrazil(targetscene, targetenemy, returnX, returnY, bool isnon, int itemdropamount){
|
|
|
|
while(ObjEnemy_GetInfo(targetenemy, INFO_LIFE)>0){
|
|
yield;
|
|
}
|
|
|
|
DeleteShotAll(TYPE_ALL,TYPE_ITEM);
|
|
|
|
SetPlayerInvincibilityFrame(120);
|
|
|
|
// ITS COMMON DATA TIME BITCHES
|
|
|
|
float[] enemyPos = [ObjMove_GetX(targetenemy), ObjMove_GetY(targetenemy)];
|
|
SetCommonData("Boss Position", enemyPos);
|
|
|
|
alternative(isnon)
|
|
case(true){_NonspellItemDrop(targetscene, targetenemy, itemdropamount);}
|
|
others{_NonspellItemDrop(targetscene, targetenemy, itemdropamount);}
|
|
|
|
wait(120);
|
|
|
|
Obj_Delete(targetenemy);
|
|
|
|
}
|
|
|
|
task _GoToBrazilMidboss(targetscene, targetenemy, bool isnon, int itemdropamount){
|
|
|
|
while(ObjEnemy_GetInfo(targetenemy, INFO_LIFE)>0){
|
|
yield;
|
|
}
|
|
|
|
DeleteShotAll(TYPE_ALL,TYPE_ITEM);
|
|
|
|
SetPlayerInvincibilityFrame(120);
|
|
|
|
// ITS COMMON DATA TIME BITCHES
|
|
|
|
float[] enemyPos = [ObjMove_GetX(targetenemy), ObjMove_GetY(targetenemy)];
|
|
SetCommonData("Boss Position", enemyPos);
|
|
|
|
alternative(isnon)
|
|
case(true){_NonspellItemDrop(targetscene, targetenemy, itemdropamount);}
|
|
others{_NonspellItemDrop(targetscene, targetenemy, itemdropamount);}
|
|
|
|
wait(60);
|
|
|
|
ObjMove_SetDestAtFrame(targetenemy, enemyPos[0], -150, 45, LERP_SMOOTHER);
|
|
|
|
wait(45);
|
|
|
|
Obj_Delete(targetenemy);
|
|
|
|
}
|
|
|
|
// Used after end of last spell for dramatic effect. NOTE TO SELF: REPLACE SOUND & GRAPHICAL EFFECTS
|
|
|
|
task _ByeBitch(targetscene, targetenemy){
|
|
|
|
while(ObjEnemyBossScene_GetInfo(targetscene, INFO_CURRENT_LIFE) > 0){
|
|
yield;
|
|
}
|
|
|
|
/*ObjSound_Load(death, defeatsnd);
|
|
ObjSound_SetVolumeRate(death, 30);
|
|
ObjSound_SetFade(death, 5);*/
|
|
|
|
let x = ObjMove_GetX(targetenemy);
|
|
let y = ObjMove_GetY(targetenemy);
|
|
|
|
StartSlow(TARGET_ALL, 30);
|
|
SetPlayerInvincibilityFrame(180);
|
|
DeleteShotAll(TYPE_ALL,TYPE_ITEM);
|
|
//ObjSound_Play(death);
|
|
TExplosionA(x,y,10,0.5);
|
|
wait(120);
|
|
|
|
StopSlow(TARGET_ALL);
|
|
//ObjSound_Play(death);
|
|
//Obj_Delete(target);
|
|
TExplosionA(x,y,10,0.5);
|
|
wait(120);
|
|
|
|
}
|
|
|
|
function <void> _ByeBitches(int targetscene, int targetboss, int targetenemyA, int targetenemyB, int itemdropamount){
|
|
|
|
//wait(120);
|
|
|
|
loop{
|
|
float life = ObjEnemy_GetInfo(targetboss, INFO_LIFE);
|
|
if(life > 0){yield;}
|
|
else{break;}
|
|
}
|
|
|
|
int death = ObjSound_Create();
|
|
ObjSound_Load(death, defeatsnd);
|
|
ObjSound_SetVolumeRate(death, 40);
|
|
ObjSound_SetFade(death, 7.5);
|
|
|
|
StartSlow(TARGET_ALL, 30);
|
|
SetPlayerInvincibilityFrame(180);
|
|
DeleteShotAll(TYPE_ALL,TYPE_ITEM);
|
|
ObjSound_Play(death);
|
|
TExplosionA(ObjMove_GetX(targetenemyA), ObjMove_GetY(targetenemyA), 10, 0.5);
|
|
TExplosionA(ObjMove_GetX(targetenemyB), ObjMove_GetY(targetenemyB), 10, 0.5);
|
|
wait(120);
|
|
|
|
_SpellItemDrop(targetscene, targetenemyA, itemdropamount);
|
|
_SpellItemDrop(targetscene, targetenemyB, itemdropamount);
|
|
|
|
StopSlow(TARGET_ALL);
|
|
|
|
ObjSound_Play(death);
|
|
|
|
TExplosionA(ObjMove_GetX(targetenemyA), ObjMove_GetY(targetenemyA), 10, 0.5);
|
|
TExplosionA(ObjMove_GetX(targetenemyB), ObjMove_GetY(targetenemyB), 10, 0.5);
|
|
|
|
Obj_Delete(targetboss);
|
|
Obj_Delete(targetenemyA);
|
|
Obj_Delete(targetenemyB);
|
|
|
|
wait(120);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
//////////////// GRAPHICAL/VISUAL-RELATED TASKS AND FUNCTIONS ////////////////
|
|
|
|
*/
|
|
|
|
// Handles boss markers during boss fights.
|
|
|
|
task _BossMarker(int targetenemy, markertex, int left, int top, int right, int bottom, float scale, float heightoffset){
|
|
|
|
int marker = ObjPrim_Create(OBJ_SPRITE_2D);
|
|
ObjPrim_SetTexture(marker, markertex);
|
|
ObjSprite2D_SetSourceRect(marker, left, top, right, bottom);
|
|
ObjSprite2D_SetDestCenter(marker);
|
|
ObjRender_SetScaleXYZ(marker, scale);
|
|
Obj_SetRenderPriorityI(marker, 19);
|
|
ObjRender_SetAlpha(marker, 255);
|
|
//ObjRender_SetY(marker, GetStgFrameHeight()+heightoffset);
|
|
|
|
while(!Obj_IsDeleted(targetenemy)){
|
|
ObjRender_SetPosition(marker, ObjRender_GetX(targetenemy)+(GetScreenWidth()-GetStgFrameWidth())/2, GetStgFrameHeight()+heightoffset+(GetScreenHeight()-GetStgFrameHeight())/2, 1);
|
|
yield;
|
|
}
|
|
|
|
Obj_Delete(marker);
|
|
}
|
|
|
|
// Tasks that handle calling a spellcard. No spell card history.
|
|
|
|
task _DuoCutin(
|
|
image1, image2,
|
|
int rectleft, int recttop, int rectright, int rectbottom,
|
|
int spellID, string spellname,
|
|
float textsize, float bordersize, int bordercolor, int bonusbordercolor,
|
|
float textstartx, float textendx, int render1, int render2
|
|
){
|
|
|
|
// Handle the appearance and disappearances of the images
|
|
|
|
// 0 = upwards, 1 = downwards || 0 = left, 1 = right
|
|
|
|
// Handle the spell text
|
|
|
|
int spelltext = ObjText_Create();
|
|
ObjText_SetText(spelltext, spellname);
|
|
ObjText_SetFontType(spelltext, "Connecting Chain Handserif");
|
|
|
|
ObjText_SetFontSize(spelltext, textsize);
|
|
ObjText_SetFontColorTop(spelltext, 255, 255, 255);
|
|
ObjText_SetFontColorBottom(spelltext, 255, 255, 255);
|
|
ObjText_SetFontBorderType(spelltext, BORDER_FULL);
|
|
ObjText_SetFontBorderColor(spelltext, bordercolor);
|
|
ObjText_SetFontBorderWidth(spelltext, bordersize);
|
|
|
|
ObjText_SetHorizontalAlignment(spelltext, ALIGNMENT_RIGHT);
|
|
ObjText_SetMaxWidth(spelltext, GetStgFrameWidth);
|
|
Obj_SetRenderPriorityI(spelltext, 79);
|
|
ObjRender_SetPosition(spelltext, textstartx, GetStgFrameHeight/8-10, 0); // WIP
|
|
ObjRender_SetAlpha(spelltext, 255);
|
|
|
|
// Handle the spell bonus
|
|
|
|
let objBonus = ObjText_Create();
|
|
ObjText_SetFontSize(objBonus, 38);
|
|
ObjText_SetFontBold(objBonus, true);
|
|
ObjText_SetFontType(objBonus, "Anke Calligraph");
|
|
ObjText_SetFontColorTop(objBonus, 255, 255, 255);
|
|
ObjText_SetFontColorBottom(objBonus, 255, 255, 255);
|
|
ObjText_SetFontBorderType(objBonus, BORDER_FULL);
|
|
ObjText_SetFontBorderColor(objBonus, bonusbordercolor);
|
|
ObjText_SetFontBorderWidth(objBonus, 2);
|
|
|
|
ObjText_SetHorizontalAlignment(objBonus, ALIGNMENT_RIGHT);
|
|
ObjText_SetMaxWidth(objBonus, GetStgFrameWidth-24);
|
|
Obj_SetRenderPriorityI(objBonus, 79);
|
|
ObjRender_SetPosition(objBonus, textendx, GetStgFrameHeight/8+12, 0); // WIP
|
|
ObjRender_SetAlpha(objBonus, 255);
|
|
|
|
async{
|
|
while(ObjEnemyBossScene_GetInfo(spellID, INFO_PLAYER_SHOOTDOWN_COUNT) == 0 && ObjEnemyBossScene_GetInfo(spellID, INFO_PLAYER_SPELL_COUNT) == 0)
|
|
{
|
|
int score = trunc(ObjEnemyBossScene_GetInfo(spellID, INFO_SPELL_SCORE)/10) * 10;
|
|
score = min(score, 9999999990);
|
|
let yass = DigitToCommaArray(score);
|
|
ObjText_SetText(objBonus, yass);
|
|
yield;
|
|
}
|
|
ObjText_SetText(objBonus, ":(");
|
|
}
|
|
|
|
// Actually call the tasks and functions here
|
|
|
|
// Mm
|
|
|
|
int objCutin1 = _Create2DImage(image1, rectleft, recttop, rectright, rectbottom);
|
|
int objCutin2 = _Create2DImage(image2, rectleft, recttop, rectright, rectbottom);
|
|
|
|
Obj_SetRenderPriorityI(objCutin1, render1);
|
|
Obj_SetRenderPriorityI(objCutin2, render2);
|
|
|
|
_MoveVertical(objCutin1, 0, 0);
|
|
_MoveVertical(objCutin2, 1, 1);
|
|
|
|
//WriteLog(ObjRender_GetY(objCutin1));
|
|
|
|
//_MoveIntoPlace(spelltext, textstartx, textendx);
|
|
_FadeAtPlayer(spelltext);
|
|
_FadeAtPlayer(objBonus);
|
|
|
|
while(ObjEnemyBossScene_GetInfo(spellID, INFO_CURRENT_LIFE) > 0){yield;}
|
|
|
|
Obj_Delete(spelltext);
|
|
Obj_Delete(objBonus);
|
|
|
|
//return;
|
|
|
|
}
|
|
|
|
task _SoloCutin(
|
|
image,
|
|
int rectleft, int recttop, int rectright, int rectbottom,
|
|
int bossID, int spellID, string spellname,
|
|
float textsize, float bordersize, int bordercolor, int bonusbordercolor,
|
|
float textstartx, float texty, int render
|
|
){
|
|
|
|
// Handle the spell text
|
|
|
|
int spelltext = ObjText_Create();
|
|
ObjText_SetText(spelltext, spellname);
|
|
ObjText_SetFontType(spelltext, "Connecting Chain Handserif");
|
|
|
|
ObjText_SetFontSize(spelltext, textsize);
|
|
ObjText_SetFontColorTop(spelltext, 255, 255, 255);
|
|
ObjText_SetFontColorBottom(spelltext, 255, 255, 255);
|
|
ObjText_SetFontBorderType(spelltext, BORDER_FULL);
|
|
ObjText_SetFontBorderColor(spelltext, bordercolor);
|
|
ObjText_SetFontBorderWidth(spelltext, bordersize);
|
|
|
|
ObjText_SetHorizontalAlignment(spelltext, ALIGNMENT_LEFT);
|
|
//ObjText_SetMaxWidth(spelltext, GetStgFrameWidth);
|
|
Obj_SetRenderPriorityI(spelltext, 79);
|
|
ObjRender_SetPosition(spelltext, textstartx, texty, 0); // WIP
|
|
ObjRender_SetAlpha(spelltext, 255);
|
|
|
|
// Handle the spell bonus
|
|
|
|
let objBonus = ObjText_Create();
|
|
ObjText_SetFontSize(objBonus, textsize*1.25);
|
|
ObjText_SetFontBold(objBonus, true);
|
|
ObjText_SetFontType(objBonus, "Anke Calligraph");
|
|
ObjText_SetFontColorTop(objBonus, 255, 255, 255);
|
|
ObjText_SetFontColorBottom(objBonus, 255, 255, 255);
|
|
ObjText_SetFontBorderType(objBonus, BORDER_FULL);
|
|
ObjText_SetFontBorderColor(objBonus, bonusbordercolor);
|
|
ObjText_SetFontBorderWidth(objBonus, 2);
|
|
|
|
ObjText_SetHorizontalAlignment(objBonus, ALIGNMENT_LEFT);
|
|
//ObjText_SetMaxWidth(objBonus, GetStgFrameWidth-24);
|
|
Obj_SetRenderPriorityI(objBonus, 79);
|
|
ObjRender_SetPosition(objBonus, textstartx, texty+textsize-5, 0); // WIP
|
|
ObjRender_SetAlpha(objBonus, 255);
|
|
|
|
async{
|
|
while(ObjEnemyBossScene_GetInfo(spellID, INFO_PLAYER_SHOOTDOWN_COUNT) == 0 && ObjEnemyBossScene_GetInfo(spellID, INFO_PLAYER_SPELL_COUNT) == 0)
|
|
{
|
|
int score = trunc(ObjEnemyBossScene_GetInfo(spellID, INFO_SPELL_SCORE)/10) * 10;
|
|
score = min(score, 9999999990);
|
|
let yass = DigitToCommaArray(score);
|
|
ObjText_SetText(objBonus, "Bonus: " ~ yass);
|
|
yield;
|
|
}
|
|
ObjText_SetText(objBonus, "Bonus Failed...");
|
|
}
|
|
|
|
// Actually call the tasks and functions here
|
|
|
|
// Mm
|
|
|
|
int objCutin = _Create2DImage(image, rectleft, recttop, rectright, rectbottom);
|
|
|
|
Obj_SetRenderPriorityI(objCutin, render);
|
|
|
|
_MoveDiagonal(objCutin, GetStgFrameWidth()*1.25, -120, GetStgFrameWidth()/2, GetStgFrameHeight()/2, -120, GetStgFrameHeight()*1.25);
|
|
//WriteLog(Obj_IsVisible(spelltext));
|
|
|
|
//_MoveIntoPlace(spelltext, textstartx, textendx);
|
|
_FadeAtPlayer(spelltext);
|
|
_FadeAtPlayer(objBonus);
|
|
|
|
while(ObjEnemyBossScene_GetInfo(spellID, INFO_CURRENT_LIFE) > 0){yield;}
|
|
|
|
Obj_Delete(spelltext);
|
|
Obj_Delete(objBonus);
|
|
|
|
//return;
|
|
|
|
}
|
|
|
|
function DigitToCommaArray(num){ //Natashinitai
|
|
|
|
let srcStr = IntToString(num);
|
|
let res = [];
|
|
let nChar = 0;
|
|
for(let i = length(srcStr) - 1; i >= 0; i--){
|
|
res = [srcStr[i]] ~ res;
|
|
nChar++;
|
|
if(nChar % 3 == 0 && i > 0) res = "," ~ res;
|
|
}
|
|
return res;
|
|
|
|
}
|
|
|
|
// Tasks meant to be used with cutin tasks.
|
|
|
|
task _MoveVertical(int target, int move, int widthposition){
|
|
|
|
float positionstart = [GetStgFrameHeight()*1.5, -GetStgFrameHeight()][move];
|
|
float positionmid = GetStgFrameHeight()/2;
|
|
float positionend = [-GetStgFrameHeight()*1.5, GetStgFrameHeight()*1.5][move];
|
|
|
|
float positionhort = [3*GetStgFrameWidth/8, 6*GetStgFrameWidth/8][widthposition];
|
|
|
|
ObjRender_SetPosition(target, positionhort, positionstart, 0);
|
|
|
|
ascent(i in 0..30){
|
|
ObjRender_SetY(target, Interpolate_Decelerate(positionstart, positionmid, i/30));
|
|
yield;
|
|
}
|
|
|
|
wait(30);
|
|
|
|
ascent(i in 0..30){
|
|
ObjRender_SetY(target, Interpolate_Accelerate(positionmid, positionend, i/30));
|
|
yield;
|
|
}
|
|
|
|
Obj_Delete(target);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
task _MoveDiagonal(int target, int startx, int starty, int midx, int midy, int endx, int endy){
|
|
|
|
//"
|
|
|
|
ObjRender_SetPosition(target, startx, endx, 1);
|
|
|
|
ascent(i in 0..30){
|
|
ObjRender_SetPosition(target, Interpolate_Decelerate(startx, midx, i/30), Interpolate_Decelerate(starty, midy, i/30), 1);
|
|
ObjRender_SetAlpha(target, Interpolate_Decelerate(0, 255, i/30));
|
|
yield;
|
|
}
|
|
|
|
wait(30);
|
|
|
|
ascent(i in 0..30){
|
|
ObjRender_SetPosition(target, Interpolate_Decelerate(midx, endx, i/30), Interpolate_Decelerate(midy, endy, i/30), 1);
|
|
ObjRender_SetAlpha(target, Interpolate_Decelerate(255, 0, i/30));
|
|
yield;
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
task _MoveIntoPlace(int target, int startx, int endx){
|
|
ascent(i in 0..30){
|
|
ObjRender_SetX(target, Interpolate_Decelerate(startx, endx, i/30));
|
|
ObjRender_SetAlpha(target, Interpolate_Decelerate(0, 255, i/30));
|
|
yield;
|
|
}
|
|
return;
|
|
}
|
|
|
|
task _FadeAtPlayer(int target){
|
|
wait(30);
|
|
while(!Obj_IsDeleted(target)){
|
|
int player = GetPlayerObjectID();
|
|
if(ObjRender_GetY(player) <= GetStgFrameHeight()/3.5){ObjRender_SetAlpha(target, 60);}
|
|
else{ObjRender_SetAlpha(target, 255);}
|
|
yield;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Enemy render tasks
|
|
|
|
/*
|
|
These render tasks assume the order of the spritesheet goes like this:
|
|
|
|
Idle Idle2 Idle3 ...
|
|
Left Left2 Left3 ...
|
|
Right
|
|
|
|
*/
|
|
|
|
task _RenderEnemyMovement(int obj, int frame, int offsetleft, int offsettop, int width, int height, float flipscale, int frameno, int speed){
|
|
|
|
ObjSprite2D_SetSourceRect(obj, offsetleft+width*floor(frame/speed), offsettop, width+width*floor(frame/speed), offsettop+height);
|
|
ObjRender_SetScaleX(obj, flipscale);
|
|
|
|
}
|
|
|
|
task _EnemyRenderFull(int enemyobj, int texture, int offsetleft, int offsettop, int width, int height, int framenoidle, int framenomovement, int speed){
|
|
|
|
int aniidle = 0;
|
|
int animove = 0;
|
|
|
|
while(!Obj_IsDeleted(enemyobj)){
|
|
|
|
float dir = ObjMove_GetAngle(enemyobj);
|
|
float speed = ObjMove_GetSpeed(enemyobj);
|
|
|
|
// Idle
|
|
if (speed == 0){
|
|
_RenderEnemyMovement(enemyobj, aniidle, offsetleft, offsettop, width, height, 1, framenoidle, speed);
|
|
aniidle++;
|
|
if(aniidle >= speed*framenoidle){aniidle = 0;}
|
|
}
|
|
// Left
|
|
else if (cos(dir) < 0){
|
|
_RenderEnemyMovement(enemyobj, aniidle, offsetleft, offsettop+height, width, height*2, 1, framenomovement, speed);
|
|
animove++;
|
|
if(animove >= speed*framenomovement){animove = 0;}
|
|
}
|
|
// Right
|
|
else if (cos(dir) > 0){
|
|
_RenderEnemyMovement(enemyobj, aniidle, offsetleft, offsettop+height*2, width, height*3, 1, framenomovement, speed);
|
|
animove++;
|
|
if(animove >= speed*framenomovement){animove = 0;}
|
|
}
|
|
yield;
|
|
}
|
|
}
|
|
|
|
// Enemy deletion/explosion effects.
|
|
|
|
// This particle list is used for all instances of the effect.
|
|
|
|
task _EffectListPreRender(
|
|
int targetList,
|
|
texture, int[] rect
|
|
){
|
|
|
|
ObjPrim_SetTexture(targetList, texture);
|
|
|
|
Obj_SetRenderPriorityI(targetList, 39);
|
|
ObjPrim_SetPrimitiveType(targetList, PRIMITIVE_TRIANGLELIST);
|
|
ObjPrim_SetVertexCount(targetList, 4);
|
|
|
|
ObjRender_SetBlendType(targetList, BLEND_ALPHA);
|
|
|
|
// Left-top, right-top, left-bottom, right-bottom
|
|
|
|
ObjPrim_SetVertexUVT(targetList, 0, rect[0], rect[1]);
|
|
ObjPrim_SetVertexUVT(targetList, 1, rect[2], rect[1]);
|
|
ObjPrim_SetVertexUVT(targetList, 2, rect[0], rect[3]);
|
|
ObjPrim_SetVertexUVT(targetList, 3, rect[2], rect[3]);
|
|
|
|
// Vertex positions are offset with deltas so that the sprite is centered
|
|
|
|
float dU = (rect[2] - rect[0])/2;
|
|
float dV = (rect[3] - rect[1])/2;
|
|
|
|
ObjPrim_SetVertexPosition(targetList, 0, -dU, -dV, 1);
|
|
ObjPrim_SetVertexPosition(targetList, 1, dU, -dV, 1);
|
|
ObjPrim_SetVertexPosition(targetList, 2, -dU, dV, 1);
|
|
ObjPrim_SetVertexPosition(targetList, 3, dU, dV, 1);
|
|
|
|
ObjPrim_SetVertexIndex(targetList, [0, 1, 2, 1, 2, 3]);
|
|
|
|
}
|
|
|
|
// Drop a number of point items and petals depending on how fast you kill the enemy and how close you are to them.
|
|
|
|
task _EnemyItemDrop(
|
|
int ID,
|
|
int minPoint, int minPIV,
|
|
int maxPoint, int maxPIV,
|
|
int maxTimer, int maxDist
|
|
){
|
|
|
|
//wait(spawnTime+5);
|
|
float enmX = ObjMove_GetX(ID), enmY = ObjMove_GetY(ID);
|
|
int Bitch = ID;
|
|
float timer = 1;
|
|
float dmgCheck = 0;
|
|
|
|
ObjEnemy_SetDamageRate(Bitch, 100, 100);
|
|
|
|
while(ObjEnemy_GetInfo(Bitch, INFO_LIFE) > 0){
|
|
enmX = ObjMove_GetX(Bitch);
|
|
enmY = ObjMove_GetY(Bitch);
|
|
dmgCheck = ObjEnemy_GetInfo(Bitch, INFO_DAMAGE_PREVIOUS_FRAME);
|
|
timer++;
|
|
yield;
|
|
}
|
|
|
|
if(
|
|
(-96 < enmX && enmX < STG_WIDTH+96)
|
|
&&
|
|
(-96 < enmY && enmY < STG_HEIGHT+96)
|
|
)
|
|
|
|
{
|
|
_ExplosionEffect(enmX, enmY, PetalEffect);
|
|
//_ScorePopup(float enmX, float enmY, int pointNum, int pivNum);
|
|
|
|
// NotifyEvent is faster than NotifyEventAll, considering how the item event will be called many times.
|
|
|
|
NotifyEvent(itemScript, EV_DROP_POINT_ENEMY, [enmX, enmY], timer, maxTimer, minPoint, maxPoint);
|
|
NotifyEvent(itemScript, EV_DROP_PIV_ENEMY, GetPlayerObjectID(), [enmX, enmY], minPIV, maxPIV, maxDist);
|
|
}
|
|
|
|
}
|
|
|
|
// Enemy go Boom
|
|
|
|
/*
|
|
5 flower petals appear from the enemy and spin outwards.
|
|
Their angle constantly changes and their alpha lowers over time.
|
|
*/
|
|
|
|
task _ExplosionEffect(float enmX, float enmY, int targetList){
|
|
|
|
int i = 0;
|
|
int effectLength = 45;
|
|
int effectNum = 5;
|
|
int dir = 1;
|
|
|
|
TExplosionA(enmX, enmY, 255/effectLength, 9/effectLength);
|
|
|
|
/*ascent(i in 0..effectNum){
|
|
_CreatePetal(rand(5, 10)*dir, rand(5, 10)*dir, rand(0, 360));
|
|
dir *= -1;
|
|
//_CreatePetal(rand(50, 80), rand(-80, -50), rand(0, 360));
|
|
}*/
|
|
|
|
_CreatePetal(rand(8, 11), rand(-8, -11), rand(0, 360));
|
|
_CreatePetal(rand(-11, -8), rand(-2, 2), rand(0, 360));
|
|
_CreatePetal(rand(8, 8), rand(-2, 2), rand(0, 360));
|
|
_CreatePetal(rand(-11, -8), rand(8, 11), rand(0, 360));
|
|
_CreatePetal(rand(8, 11), rand(8, 11), rand(0, 360));
|
|
|
|
ObjSound_Play(sfxBoom);
|
|
|
|
// Create a petal with:
|
|
// x offset every frame, y offset every frame
|
|
|
|
task _CreatePetal(float spdX, float spdY, float baseAng){
|
|
|
|
float x = enmX, y = enmY;
|
|
let x_speed = spdX;
|
|
let y_speed = spdY;
|
|
let z_add = rand(-5, 5);
|
|
|
|
ascent(i in 0..effectLength){
|
|
_PetalMovement(Interpolate_Decelerate(1.5, 0.5, i/effectLength), Interpolate_Decelerate(255, 0, i/effectLength));
|
|
yield;
|
|
}
|
|
|
|
task _PetalMovement(scale, alpha){
|
|
|
|
ObjParticleList_SetScale(targetList, scale);
|
|
ObjParticleList_SetAngleZ(targetList, baseAng);
|
|
ObjParticleList_SetPosition(targetList, x, y, 1);
|
|
ObjParticleList_SetAlpha(targetList, alpha);
|
|
|
|
//Submits the current data to an instance, cleared every frame.
|
|
ObjParticleList_AddInstance(targetList);
|
|
|
|
x += x_speed;
|
|
y += y_speed;
|
|
baseAng += z_add;
|
|
|
|
yield;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} |