NarumiSTG_HyperSnowDrifter/script/KevinSystem/Kevin_PlayerLib.txt

829 lines
25 KiB
Plaintext
Raw Permalink Normal View History

2023-01-26 11:34:56 +00:00
/* --------------------------------------------------------------------
UNIVERSAL/GENERAL FUNCTIONS USED FOR PLAYERS
These functions may/will be reused for future scripts as well.
--------------------------------------------------------------------
*/
#include "script/KevinSystem/kevin_system/Kevin_ItemConst.txt"
#include "script/KevinSystem/kevin_system/Kevin_ItemLib.txt"
#include "script/KevinSystem/kevin_system/Lib_Const.dnh"
#include "script/KevinSystem/Kevin_PlayerLib_HUD.dnh"
//#include "script/KevinSystem/Universal_Lib.txt"
float universalAlpha = GetAreaCommonData("Config", "PlayerShotOpacity", 60);
let POINTER_PIV = LoadAreaCommonDataValuePointer("PIV", "currentvalue", 1000);
let POINTER_CHAIN = LoadAreaCommonDataValuePointer("PIV", "ChainAmount", 1);
let POINTER_CHAINGAUGE = LoadAreaCommonDataValuePointer("PIV", "ChainGauge", 0);
let POINTER_SPECIALAMMO = LoadAreaCommonDataValuePointer("PIV", "SpecialAmmo", 100);
let POINTER_SPECIALCHECK = LoadAreaCommonDataValuePointer("PIV", "IsUsingSpecial", false);
let POINTER_CHAINCHECK = LoadAreaCommonDataValuePointer("PIV", "IsChaining", false);
//universalAlpha = 255; // Debug
function CreateTextObject(
float mx, my, size,
string text, font,
int colorTop, colorBottom,
int borderColor, borderWidth,
int renderPriority
){
let obj = ObjText_Create();
ObjText_SetText(obj, text);
ObjText_SetFontSize(obj, size);
ObjText_SetFontType(obj, font);
ObjText_SetFontColorTop(obj, colorTop);
ObjText_SetFontColorBottom(obj, colorBottom);
ObjText_SetFontBorderType(obj, BORDER_FULL);
ObjText_SetFontBorderColor(obj, borderColor);
ObjText_SetFontBorderWidth(obj, borderWidth);
Obj_SetRenderPriorityI(obj, renderPriority);
ObjRender_SetX(obj, mx);
ObjRender_SetY(obj, my);
return obj;
}
function <int> _Create2DImage(imgpath, int[] rectarray){
int imgname = ObjPrim_Create(OBJ_SPRITE_2D);
ObjPrim_SetTexture(imgname, imgpath);
ObjSprite2D_SetSourceRect(imgname, rectarray);
ObjSprite2D_SetDestCenter(imgname);
//ObjRender_SetPosition(imgname, positionstart)
return imgname;
}
// thanks ttbd owo
function CreateEffectObject(px, py, img, blendtype, left, top, right, bottom)
{
let obj = ObjPrim_Create(OBJ_SPRITE_2D);
ObjPrim_SetTexture(obj, img);
ObjSprite2D_SetSourceRect(obj, left, top, right, bottom);
ObjSprite2D_SetDestCenter(obj);
if(blendtype=="ALPHA"){ObjRender_SetBlendType(obj, BLEND_ALPHA);}
else if(blendtype=="MULTIPLY"){ObjRender_SetBlendType(obj, BLEND_MULTIPLY);}
else if(blendtype=="SUBTRACT"){ObjRender_SetBlendType(obj, BLEND_SUBTRACT);}
else if(blendtype=="SHADOW"){ObjRender_SetBlendType(obj, BLEND_SHADOW);}
else if(blendtype=="RGB"){ObjRender_SetBlendType(obj, BLEND_ADD_RGB);}
else if(blendtype=="ARGB"){ObjRender_SetBlendType(obj, BLEND_ADD_ARGB);}
else if(blendtype=="INVERT"){ObjRender_SetBlendType(obj, BLEND_INV_DESTRGB);}
ObjRender_SetPosition(obj, px, py, 0);
ObjRender_SetTextureFilter(obj, FILTER_POINT, FILTER_POINT, FILTER_POINT);
return obj;
}
/*
CHAIN SYSTEM: Crystals fill up your chain amount and refill your chain gauge, up to a max of 64x
Gauge starts to go down when you don't collect crystals: it resets the entire chain after 3 seconds
*/
task _HandleChainGauge(){
// Gauge maxes at 100.
// If gauge reaches 0, reset the chain
float rateReduceNormal = 100/120;
float rateReduceCashin = 100/180; // x48-64
float rateReduceCashin_MED = 100/90; // x32-48
float rateReduceCashin_LOW = 100/60; // x16-32
float rateReduceCashin_PLACEBO = 100/30; // under x16
while(true){
if(GetCommonDataPtr(POINTER_SPECIALCHECK, false) == false && GetCommonDataPtr(POINTER_CHAIN, 1) >= 64 && !isChain){NotifyEventAll(EV_CHAIN_MAX, 1);}
else{}
if(GetCommonDataPtr(POINTER_SPECIALCHECK, false) == true){
if(GetCommonDataPtr(POINTER_CHAINGAUGE, 0) <= 1){NotifyEventAll(EV_CHAIN_END, 1);}
if(GetCommonDataPtr(POINTER_CHAIN, 1) >= 48)
{SetCommonDataPtr(POINTER_CHAINGAUGE, max(0, GetCommonDataPtr(POINTER_CHAINGAUGE, 0)-rateReduceCashin));}
else if(GetCommonDataPtr(POINTER_CHAIN, 1) >= 32 && GetCommonDataPtr(POINTER_CHAIN, 1) < 48)
{SetCommonDataPtr(POINTER_CHAINGAUGE, max(0, GetCommonDataPtr(POINTER_CHAINGAUGE, 0)-rateReduceCashin_MED));}
else if(GetCommonDataPtr(POINTER_CHAIN, 1) >= 16 && GetCommonDataPtr(POINTER_CHAIN, 1) < 32)
{SetCommonDataPtr(POINTER_CHAINGAUGE, max(0, GetCommonDataPtr(POINTER_CHAINGAUGE, 0)-rateReduceCashin_LOW));}
else
{SetCommonDataPtr(POINTER_CHAINGAUGE, max(0, GetCommonDataPtr(POINTER_CHAINGAUGE, 0)-rateReduceCashin_PLACEBO));}
}
else{
SetCommonDataPtr(POINTER_CHAINGAUGE, max(0, GetCommonDataPtr(POINTER_CHAINGAUGE, 0)-rateReduceNormal));
}
if(
GetCommonDataPtr(POINTER_CHAINGAUGE, 0) <= 0
&& GetCommonDataPtr(POINTER_CHAIN, 1) > 1
)
{
SetCommonDataPtr(POINTER_CHAIN, 1);
SetCommonDataPtr(POINTER_SPECIALCHECK, false);
}
yield;
}
}
task _ShowChain(){
// HUD
//_ShowChainHUD();
// Playfield
let objPIVNum = ObjText_Create();
ObjText_SetFontSize(objPIVNum, 40);
ObjText_SetFontBold(objPIVNum, true);
ObjText_SetFontType(objPIVNum, "GravityRegular5");
ObjText_SetFontColorTop(objPIVNum, 0xFFFFFF);
ObjText_SetFontColorBottom(objPIVNum, 0xFFFFFF);
ObjText_SetFontBorderType(objPIVNum, BORDER_FULL);
ObjText_SetFontBorderColor(objPIVNum, 0xFF9A4F);
ObjText_SetFontBorderWidth(objPIVNum, 4);
ObjText_SetHorizontalAlignment(objPIVNum, ALIGNMENT_LEFT);
//ObjText_SetFontWeight(objPIVNum, 1000);
Obj_SetRenderPriorityI(objPIVNum, 60);
ObjText_SetSidePitch(objPIVNum, -3);
ObjRender_SetPosition(objPIVNum, STG_WIDTH * 1/2 + 96, STG_HEIGHT * 10/11, 0);
// DEBUG
//Obj_SetVisible(objPIV, false);
float value = 0;
//todo: change params
let objI = CreateEffectObject(STG_WIDTH/60, STG_HEIGHT/7, "script/KevinSystem/img/lol.png", "ALPHA", 0, 0, 244, 12);
ObjSprite2D_SetDestRect(objI, 0, 0, 122, 6);
Obj_SetRenderPriorityI(objI, 60);
while(true){
value = min(GetCommonDataPtr(POINTER_SPECIALAMMO, 1), 100);
ObjText_SetText(objPIVNum, IntToString(GetCommonDataPtr(POINTER_PIV, 1000)));
//PIVMultiplierValue = value/1000;
let yass = rtos("00.00", value);
let mx = 60*5;
ObjSprite2D_SetDestRect(objI, 0, 0, (GetCommonDataPtr(POINTER_SPECIALAMMO, 100)/100)*mx, 32);
ObjRender_SetPosition(objI, STG_WIDTH/60+160, STG_HEIGHT * 11/12, 1);
if (GetPlayerY() >= STG_HEIGHT * 7/8){
ObjRender_SetAlpha(objI, 125);
ObjRender_SetAlpha(objPIVNum, 125);
}
else{
ObjRender_SetAlpha(objI, 255);
ObjRender_SetAlpha(objPIVNum, 255);
}
if (GetCommonDataPtr(POINTER_CHAINCHECK, false) == true) {
ObjRender_SetColor(objI, 0xFFAF1E);
}
else {
if(value >= 100){
ObjRender_SetColor(objI, 255, 90, 46);
}
else{
ObjRender_SetColor(objI, 255, 145, 115);
}
}
/*
if(GetCommonDataPtr(POINTER_SPECIALCHECK, false) == false){
ObjText_SetFontBorderWidth(objPIVNum, 3);
if(value < CHAIN_MAX){
ObjText_SetFontColorTop(objPIVNum, 0x9DEFFF);
ObjText_SetFontBorderColor(objPIVNum, 42, 0, 237);
ObjText_SetText(objPIVNum,
"[font size=23 oy=-8]FUN MODE CHARGING[r]" ~ yass ~ "[font size=25 oy=32]x[r]"
~ "[r][font size=21 oc=(172, 50, 50) oy=32]AMMO: " ~ rtos("00.00", GetCommonDataPtr(POINTER_SPECIALAMMO, 100))
);
}
else{
ObjText_SetFontColorTop(objPIVNum, 0x9DFFBC);
ObjText_SetFontBorderColor(objPIVNum, 0x39C832);
ObjText_SetText(objPIVNum,
"[font size=23 oy=-8]FUN MODE READY![r]" ~ yass ~ "[font size=25 oy=32]x[r]"
~ "[r][font size=21 oc=(172, 50, 50) oy=32]AMMO: " ~ rtos("00.00", GetCommonDataPtr(POINTER_SPECIALAMMO, 100))
);
}
}
else{
ObjText_SetFontColorTop(objPIVNum, 0xFFED9D);
ObjText_SetFontBorderColor(objPIVNum, 0xFF9A00);
ObjText_SetFontBorderWidth(objPIVNum, 4);
NotifyEvent(GetPlayerScriptID(), EV_CHAIN_MAX, 0);
ObjText_SetText(objPIVNum,
"[font size=23 oc=(241, 180, 0) oy=-8]CASH-IN[r]" ~ yass ~ "[font size=25 oy=32]x[r]"
~ "[r][font size=21 oc=(172, 50, 50) oy=32]AMMO: " ~ rtos("00.00", GetCommonDataPtr(POINTER_SPECIALAMMO, 100))
);
}
*/
yield;
}
}
// Self-explanatory
task _DeleteEffect(obj, scale){
ObjRender_SetBlendType(obj, BLEND_ADD_ARGB);
Obj_SetRenderPriorityI(obj, 49);
ascent(i in 0..30){
ObjRender_SetAlpha(obj, Interpolate_Decelerate(100*(universalAlpha/100), 0, i/30));
ObjRender_SetScaleXYZ(obj, Interpolate_Decelerate(scale, scale*1.5, i/20));
ObjMove_SetSpeed(obj, 12);
yield;
}
Obj_Delete(obj);
}
// Renders player movement. Assumes that all sprites are ORGANIZED HORIZONTALLY IN THE SHEET.
// flipscale can only be 1 or -1.
task _RenderPlayerMovement(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(objPlayer, flipscale);
}
// Bullet rescaling... for player shots.
task _BulletRescalePlayer(int target, float scale, bool hitboxscale, float hitboxlevel){
ObjRender_SetScaleXYZ(target, scale, scale, 1);
if (hitboxscale){
ObjShot_SetIntersectionScaleXY(target, scale*hitboxlevel, scale*hitboxlevel);
}
}
// Handles death/respawn sigil. Assumes sigils are 512x512 in size.
// If death is true (the player dies), the circle expands outwards. Otherwise (the player bombs/respawns), it shrinks inwards.
task _SigilCall(bool death, texture, int rectleft, int recttop, int rectright, int rectbottom, int objPlayer, int time){
let DeathCircle = ObjPrim_Create(OBJ_SPRITE_2D);
ObjPrim_SetTexture(DeathCircle,teamimg);
ObjSprite2D_SetSourceRect(DeathCircle, rectleft, recttop, rectright, rectbottom);
ObjSprite2D_SetDestCenter(DeathCircle);
ObjRender_SetBlendType(DeathCircle,BLEND_ALPHA);
ObjRender_SetAlpha(DeathCircle,255);
ObjRender_SetPosition(DeathCircle,GetPlayerX(),GetPlayerY(),1);
Obj_SetRenderPriorityI(DeathCircle,Obj_GetRenderPriorityI(objPlayer)-10);
alternative(death)
case(true){
ascent(i in 0..time){
float scaliealpha = Interpolate_Decelerate(255, 0, i/time);
float scaliesize = Interpolate_Decelerate(0.1, 3, i/time);
ObjRender_SetAlpha(DeathCircle, scaliealpha);
ObjRender_SetPosition(DeathCircle,GetPlayerX(),GetPlayerY(),1);
ObjRender_SetScaleXYZ(DeathCircle, scaliesize, scaliesize, 1);
yield;
}
}
case(false){
ascent(i in 0..time){
float scaliealpha = Interpolate_Accelerate(255, 0, i/time);
float scaliesize = Interpolate_Accelerate(3, 0.1, i/time);
ObjRender_SetAlpha(DeathCircle, scaliealpha);
ObjRender_SetPosition(DeathCircle,GetPlayerX(),GetPlayerY(),1);
ObjRender_SetScaleXYZ(DeathCircle, scaliesize, scaliesize, 1);
yield;
}
}
while(ObjRender_GetAlpha(DeathCircle) > 0){yield;}
Obj_Delete(DeathCircle);
}
// Handles the hitbox and its aura. What the fuck.
task _HitboxRender(
bool playerdeathbool, int objPlayer, texture_hbox, texture_aura,
int rectleft_hbox, int recttop_hbox, int rectright_hbox, int rectbottom_hbox,
int rectleft_aura, int recttop_aura, int rectright_aura, int rectbottom_aura,
float scale_hbox, float scale_aura){
// Handle hitbox
bool visible = false;
int hitbox = ObjPrim_Create(OBJ_SPRITE_2D);
ObjPrim_SetTexture(hitbox, texture_hbox);
ObjSprite2D_SetSourceRect(hitbox, rectleft_hbox, recttop_hbox, rectright_hbox, rectbottom_hbox);
ObjSprite2D_SetDestCenter(hitbox);
ObjRender_SetScaleXYZ(hitbox, scale_hbox, scale_hbox, 1);
ObjRender_SetBlendType(hitbox, BLEND_ALPHA);
Obj_SetRenderPriorityI(hitbox, 79);
Obj_SetVisible(hitbox, false);
// Handle hitbox's aura
int aura = ObjPrim_Create(OBJ_SPRITE_2D);
ObjPrim_SetTexture(aura, texture_aura);
ObjSprite2D_SetSourceRect(aura, rectleft_aura, recttop_aura, rectright_aura, rectbottom_aura);
ObjSprite2D_SetDestCenter(aura);
ObjRender_SetScaleXYZ(aura, scale_aura, scale_aura, 1);
ObjRender_SetAlpha(aura, 70);
//ObjRender_SetBlendType(aura, BLEND_ADD_ARGB);
Obj_SetRenderPriorityI(aura, Obj_GetRenderPriorityI(objPlayer)+3);
Obj_SetVisible(aura, false);
loop{
if (visible && (!Obj_IsVisible(objPlayer) || GetVirtualKeyState(VK_SLOWMOVE) != KEY_HOLD)){
visible = false;
Obj_SetVisible(hitbox, false);
Obj_SetVisible(aura, false);
}
else if (!visible && (Obj_IsVisible(objPlayer) && (GetVirtualKeyState(VK_SLOWMOVE) == KEY_HOLD || GetVirtualKeyState(VK_SLOWMOVE) == KEY_PUSH))){
visible = true;
Obj_SetVisible(aura, true);
Obj_SetVisible(hitbox, true);
async{
while(Obj_IsVisible(aura)){
float[] curang = [ObjRender_GetAngleZ(hitbox), ObjRender_GetAngleZ(aura)];
ObjRender_SetAngleZ(hitbox, curang[0]+1.5);
ObjRender_SetAngleZ(aura, curang[1]+1.5);
yield;
}
}
async{
ascent(i in 0..20){
float scalie = Interpolate_Decelerate(scale_aura*1.5, scale_aura, i/20);
ObjRender_SetScaleXYZ(aura, scalie, scalie, 1);
yield;
}
}
async{
ascent(i in 0..20){
float scalie = Interpolate_Decelerate(0, 80, i/20);
ObjRender_SetAlpha(aura, scalie);
yield;
}
}
}
ObjRender_SetPosition(hitbox, ObjMove_GetX(objPlayer), ObjMove_GetY(objPlayer), 1);
ObjRender_SetPosition(aura, ObjMove_GetX(objPlayer), ObjMove_GetY(objPlayer), 1);
yield;
}
}
/*
Simple function that handles player options. These options simply follow the player at an offset - they do not have any trajectories of their own like spinning around the player, etc.
If the options have animations, set triggeranimation to true and adjust the number of frames + speed using delay and frameno.
If the options rotate (in place), set triggerspin to true and adjust spinning speed using spinspeed.
If the options only appear unfocused or focused, set either onlyFocus or onlyUnfocus to true. Setting both to true or false makes the options always visible.
*/
function PlayerOption(
float offsetx, float offsety,
texture,
int left, int top, int right, int bottom, float scale,
int width, int animdelay, int frameno, bool triggeranimation,
bool triggerspin, float spinspeed,
bool onlyFocus, bool onlyUnfocus
){
let option = ObjPrim_Create(OBJ_SPRITE_2D);
bool visible;
int animate = 0;
float optx;
float opty;
ObjPrim_SetTexture(option, texture);
ObjSprite2D_SetSourceRect(option, left, top, right-1, bottom-1); // Allows the options to spin smoothly should the user choose to do so.
ObjSprite2D_SetDestCenter(option);
ObjRender_SetScaleXYZ(option, scale);
ObjRender_SetBlendType(option, BLEND_ALPHA);
ObjRender_SetAlpha(option, 255);
Obj_SetRenderPriorityI(option, 41);
ObjRender_SetPosition(option, offsetx, offsety, 1);
// Animation
async{
while(triggeranimation){
ObjSprite2D_SetSourceRect(option, left+width*floor(animate/animdelay), top, right+width*floor(animate/animdelay)-1, bottom-1);
animate++;
if (animate >= animdelay*frameno){animate = 0;}
yield;
}
}
// Rotation
async{
float i = 0;
while(triggerspin){
//ObjRender_SetPosition(option, GetPlayerX()+offsetx, GetPlayerY()+offsety, 1);
ObjRender_SetAngleZ(option, i);
i += spinspeed;
yield;
}
}
// Follow
async{
while(true){
ObjRender_SetPosition(option, GetPlayerX()+offsetx, GetPlayerY()+offsety, 1);
yield;
}
}
// Visibility
async{
// Always visible
if((onlyFocus && onlyUnfocus) || (!onlyFocus && !onlyUnfocus)) {
loop
{
if(GetPlayerState != STATE_NORMAL && GetPlayerState != STATE_HIT){ObjRender_SetAlpha(option, max(0, ObjRender_GetAlpha(option)-15)); visible = false;}
else {ObjRender_SetAlpha(option, min(225, ObjRender_GetAlpha(option)+15)); visible = true;}
yield;
}
}
// Visible when focused only
else if(onlyFocus && !onlyUnfocus){
loop
{
if((GetPlayerState != STATE_NORMAL && GetPlayerState != STATE_HIT) || GetVirtualKeyState(VK_SLOWMOVE) == KEY_FREE){ObjRender_SetAlpha(option, max(0, ObjRender_GetAlpha(option)-15)); visible = false;}
else {ObjRender_SetAlpha(option, min(225, ObjRender_GetAlpha(option)+15)); visible = true;}
yield;
}
}
// Visible when unfocused only
else if(!onlyFocus && onlyUnfocus){
loop
{
if((GetPlayerState != STATE_NORMAL && GetPlayerState != STATE_HIT) || GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){ObjRender_SetAlpha(option, max(0, ObjRender_GetAlpha(option)-15)); visible = false;}
else {ObjRender_SetAlpha(option, min(225, ObjRender_GetAlpha(option)+15)); visible = true;}
yield;
}
}
}
function _FadeIn(){
ascent(i in 0..15){
ObjRender_SetAlpha(option, Interpolate_Decelerate(0, 225, i/15));
yield;
}
}
function _FadeOut(){
ascent(i in 0..15){
ObjRender_SetAlpha(option, Interpolate_Decelerate(225, 0, i/15));
yield;
}
}
return option;
}
/*
A form of PlayerOption that handles basic movement towards different positionings based on whether the player is focusing or unfocusing.
If the options have animations, set triggeranimation to true and adjust the number of frames + speed using delay and frameno.
If the options rotate (in place), set triggerspin to true and adjust spinning speed using spinspeed.
If the options only appear unfocused or focused, set either onlyFocus or onlyUnfocus to true. Setting both to true or false makes the options always visible.
*/
function PlayerOption_LinearMove(
float offsetX_uf, offsetY_uf, offsetX_f, offsetY_f,
bool angchange, float ang_uf, ang_f,
texture,
int graphic, float texScale, int priorityRender,
int texWidth, int animDelay, int animFrameNo, bool animMode,
bool spinMode, float spinSpeed,
bool onlyFocus, bool onlyUnfocus
){
int option = CreatePlayerShotA1(0, 0, 0, 0, 0, 9999999, graphic);
bool visible;
int animate = 0;
float optx;
float opty;
float playerX = 0, playerY = 0;
/*
ObjPrim_SetTexture(option, texture);
ObjSprite2D_SetSourceRect(option, texRect[0], texRect[1], texRect[2]-1, texRect[3]-1); // Allows the options to spin smoothly should the user choose to do so.
ObjSprite2D_SetDestCenter(option);
*/
ObjShot_SetAutoDelete(option, false);
ObjRender_SetScaleXYZ(option, texScale);
ObjRender_SetBlendType(option, BLEND_ALPHA);
//ObjRender_SetAlpha(option, 255);
Obj_SetRenderPriorityI(option, priorityRender);
ObjRender_SetPosition(option, playerX+offsetX_uf, playerY+offsetY_uf, 1);
///// MISC /////
async{
while(true){
playerX = ObjRender_GetX(GetPlayerObjectID());
playerY = ObjRender_GetY(GetPlayerObjectID());
yield;
}
}
///// ANIMATION /////
/*
async{
while(animMode){
ObjSprite2D_SetSourceRect(option, texRect[0]+texWidth*floor(animate/animDelay), texRect[1], texRect[2]+texWidth*floor(animate/animDelay)-1, texRect[3]-1);
animate++;
if (animate >= animDelay*animFrameNo){animate = 0;}
yield;
}
}*/
///// ROTATION /////
async{
float i = 0;
while(spinMode){
//ObjRender_SetPosition(option, GetPlayerX()+offsetx, GetPlayerY()+offsety, 1);
ObjRender_SetAngleZ(option, i);
i += spinSpeed;
yield;
}
}
///// VISIBILITY /////
async{
// Always visible
if((onlyFocus && onlyUnfocus) || (!onlyFocus && !onlyUnfocus)) {
loop
{
if(GetPlayerState != STATE_NORMAL && GetPlayerState != STATE_HIT){ObjRender_SetAlpha(option, max(0, ObjRender_GetAlpha(option)-15)); visible = false;}
else {ObjRender_SetAlpha(option, min(255, ObjRender_GetAlpha(option)+15)); visible = true;}
yield;
}
}
// Visible when focused only
else if(onlyFocus && !onlyUnfocus){
loop
{
if((GetPlayerState != STATE_NORMAL && GetPlayerState != STATE_HIT) || GetVirtualKeyState(VK_SLOWMOVE) == KEY_FREE){ObjRender_SetAlpha(option, max(0, ObjRender_GetAlpha(option)-15)); visible = false;}
else {ObjRender_SetAlpha(option, min(255, ObjRender_GetAlpha(option)+15)); visible = true;}
yield;
}
}
// Visible when unfocused only
else if(!onlyFocus && onlyUnfocus){
loop
{
if((GetPlayerState != STATE_NORMAL && GetPlayerState != STATE_HIT) || GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){ObjRender_SetAlpha(option, max(0, ObjRender_GetAlpha(option)-15)); visible = false;}
else {ObjRender_SetAlpha(option, min(255, ObjRender_GetAlpha(option)+15)); visible = true;}
yield;
}
}
}
///// MOVEMENT /////
async{
loop{
if(GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){
async{
ascent(i in 0..15){
if(angchange){ObjRender_SetAngleZ(option, Interpolate_Decelerate(ObjRender_GetAngleZ(option), ang_f, i/15));}
ObjRender_SetX(option, Interpolate_Decelerate(ObjRender_GetX(option), playerX+offsetX_f, i/15));
ObjRender_SetY(option, Interpolate_Decelerate(ObjRender_GetY(option), playerY+offsetY_f, i/15));
yield;
}
}
}
else{
async{
ascent(i in 0..15){
if(angchange){ObjRender_SetAngleZ(option, Interpolate_Decelerate(ObjRender_GetAngleZ(option), ang_uf, i/15));}
ObjRender_SetX(option, Interpolate_Decelerate(ObjRender_GetX(option), playerX+offsetX_uf, i/15));
ObjRender_SetY(option, Interpolate_Decelerate(ObjRender_GetY(option), playerY+offsetY_uf, i/15));
yield;
}
}
}
yield;
}
}
function _FadeIn(){
ascent(i in 0..15){
ObjRender_SetAlpha(option, Interpolate_Decelerate(0, 225, i/15));
yield;
}
}
function _FadeOut(){
ascent(i in 0..15){
ObjRender_SetAlpha(option, Interpolate_Decelerate(225, 0, i/15));
yield;
}
}
return option;
}
/*
------------------------------------------------------
POINTBLANK-PIV MECHANIC FUNCTIONS
Will be optimized somewhere down the line.
------------------------------------------------------
*/
// Selects an enemy in the @MainLoop-updated _enemyArray, executes _PetalDrop, and adds it to _existArray so the task isn't called again for the same enemy. maxX and maxY are the bounds of the playing field.
task _Mechanic(bool playerdeathbool, int[] _enemyArray, int [] _existArray, float maxX, float maxY, int objPlayer, int bossScene, int maxrate, int addrate, float adddist){
while(!playerdeathbool){
_enemyArray = GetIntersectionRegistedEnemyID();
bossScene = GetEnemyBossSceneObjectID();
for each (int enemy in ref _enemyArray){
float enemyX = ObjMove_GetX(enemy);
float enemyY = ObjMove_GetY(enemy);
if (0 < enemyX && enemyX < maxX && 0 < enemyY && enemyY < maxY && !contains(_existArray, enemy)){
_PetalDrop(enemy, playerdeathbool, objPlayer, bossScene, maxrate, addrate, adddist);
_existArray = _existArray ~ [enemy];
}
else{continue;}
}
yield;
}
}
// Checks the boss scene type (nonspell/spell/last spell/invalid), the ID of the player object, and the target enemy. Drops petals with a type and drop rate that depends on the boss scene type and how close the player is to the target enemy.
task _PetalDrop(int target, bool playerdeathbool, int objPlayer, int bossScene, int maxrate, int addrate, float adddist){
while(!Obj_IsDeleted(target) && !playerdeathbool){
float dist = hypot(ObjMove_GetX(target)-ObjMove_GetX(objPlayer), ObjMove_GetY(target)-ObjMove_GetY(objPlayer));
let atktype = GetEnemyBossSceneObjectID();
if(dist <= (GetStgFrameHeight()-100) && atktype != ID_INVALID && ObjEnemy_GetInfo(target, INFO_SHOT_HIT_COUNT) >= 1 && ObjEnemy_GetInfo(target, INFO_DAMAGE_PREVIOUS_FRAME) > 0){
wait(maxrate + addrate*floor(dist/adddist));
}
else{yield;}
}
}
task _DeathbombWarning(imgpath, int[] imgrectarray, int deathbombframes, float basescale){
int circle = _Create2DImage(imgpath, imgrectarray);
Obj_SetRenderPriorityI(circle, 75);
ObjRender_SetAlpha(circle, 255);
ObjRender_SetPosition(circle, ObjRender_GetX(GetPlayerObjectID()), ObjRender_GetY(GetPlayerObjectID()), 1);
ObjRender_SetBlendType(circle, BLEND_INV_DESTRGB);
ascent(i in 0..deathbombframes-1){
ObjRender_SetScaleXYZ(circle, Interpolate_Accelerate(basescale, 0, i/(deathbombframes-1)));
yield;
}
Obj_Delete(circle);
return;
}
task _BombShake(shaketime, intensity){
float baseintensity = intensity;
float shakeno = shaketime;
ascent(i in 0..shakeno){
Set2DCameraFocusX(GetStgFrameWidth/2 + rand(-intensity, intensity));
Set2DCameraFocusY(GetStgFrameHeight/2 + rand(-intensity, intensity));
intensity = Interpolate_Decelerate(0, baseintensity, 1-i/shakeno);
shaketime--;
yield;
}
while(shaketime > 0){yield;}
Set2DCameraFocusX(GetStgFrameWidth/2);
Set2DCameraFocusY(GetStgFrameHeight/2);
yield;
}
task _Countdown(){
//_FunIndicator;
//int timer = time;
int counter = CreateTextObject(
playerX, playerY, 45,
"", "GravityRegular5",
0xFFFFFF, 0xFFFFFF,
0x1AEC8C, 8,
51
);
int counter2 = CreateTextObject(
1720, 870, 40,
"", "Unispace",
0xFFFFFF, 0xFFFFFF,
0x1AEC8C, 2,
19
);
ObjText_SetHorizontalAlignment(counter, ALIGNMENT_CENTER);
while(true){
if(GetPlayerInvincibilityFrame() <= 0){Obj_SetVisible(counter, false);}
else{Obj_SetVisible(counter, true);}
ObjRender_SetPosition(counter, playerX, playerY - 96, 1);
ObjText_SetText(counter, IntToString(GetPlayerInvincibilityFrame()));
ObjText_SetText(counter2, IntToString(GetPlayerInvincibilityFrame()));
yield;
}
//Obj_Delete(counter);
}
task _FunIndicator(){
int counter = CreateTextObject(
1720, 910, 41,
"FUN IS PREPARED", "Origami Mommy",
0xFFD9B8, 0xFFFFFF,
0xD96600, 4,
39
);
ObjText_SetHorizontalAlignment(counter, ALIGNMENT_CENTER);
while(true){
if(GetCommonDataPtr(POINTER_CHAIN, 1) >= 64 && GetCommonDataPtr(POINTER_SPECIALCHECK, false) == false)
{Obj_SetVisible(counter, true);}
else{Obj_SetVisible(counter, false);}
ObjRender_SetPosition(counter, playerX, playerY + 128, 1);
yield;
}
//Obj_Delete(counter);
}