Compare commits
2 Commits
5e7516392f
...
fb99733309
Author | SHA1 | Date |
---|---|---|
kevinmonitor | fb99733309 | |
kevinmonitor | e171607abe |
|
@ -1,5 +1,11 @@
|
||||||
# ScarletBlackMarket
|
# ScarletBlackMarket
|
||||||
|
|
||||||
|
CURRENT FINISHED ATTACKS
|
||||||
|
|
||||||
|
+ Remilia Nonspell 1
|
||||||
|
+ Remilia Nonspell 2
|
||||||
|
+ Remilia Spell 3 (Sakuya Card)
|
||||||
|
|
||||||
Repository for Kevinmonitor and co.'s Touhou Station Jam 3 game.
|
Repository for Kevinmonitor and co.'s Touhou Station Jam 3 game.
|
||||||
|
|
||||||
How to install & play available attacks:
|
How to install & play available attacks:
|
||||||
|
@ -17,6 +23,7 @@ How to change the difficulty of the attacks:
|
||||||
+ Open the .dnh file in a text editor (preferably Notepad++ since that's also what I use to code)
|
+ Open the .dnh file in a text editor (preferably Notepad++ since that's also what I use to code)
|
||||||
+ Search for the @Initialize section. (should be around lines 50-70 depending on attack)
|
+ Search for the @Initialize section. (should be around lines 50-70 depending on attack)
|
||||||
+ Find the "difficultySelect = 0; // debug" line.
|
+ Find the "difficultySelect = 0; // debug" line.
|
||||||
|
+ IF THIS LINE HAS A // BEFORE IT (example: "//difficultySelect = 0; // debug"), remove that //.
|
||||||
+ Change 0 to the difficulty you want to play:
|
+ Change 0 to the difficulty you want to play:
|
||||||
|
|
||||||
0: Normal
|
0: Normal
|
||||||
|
|
Before Width: | Height: | Size: 896 KiB After Width: | Height: | Size: 844 KiB |
|
@ -40,27 +40,26 @@ task _RenderBoss(int enemy){
|
||||||
|
|
||||||
int aniidle = 0;
|
int aniidle = 0;
|
||||||
|
|
||||||
string tex = "script/game/resourceLib/Spritesheet_StationJam.png";
|
string tex = "script/game/StageLib/BossAsset.png";
|
||||||
|
|
||||||
LoadTextureEx(tex, true, true);
|
LoadTextureEx(tex, true, true);
|
||||||
|
|
||||||
ObjPrim_SetTexture(enemy, tex);
|
ObjPrim_SetTexture(enemy, tex);
|
||||||
ObjSprite2D_SetSourceRect(enemy, 1280, 0, 1280+256, 256);
|
ObjSprite2D_SetSourceRect(enemy, 0, 0, 512, 512);
|
||||||
ObjSprite2D_SetDestCenter(enemy);
|
ObjSprite2D_SetDestCenter(enemy);
|
||||||
ObjRender_SetScaleXYZ(enemy, 1);
|
ObjRender_SetScaleXYZ(enemy, 0.48);
|
||||||
|
|
||||||
int nameText = CreateTextObject(
|
int nameText = CreateTextObject(
|
||||||
GetStgFrameWidth()*0.3, 200, 25,
|
GetStgFrameWidth()*0.38, 10, 42,
|
||||||
"REMILIA SCARLET", "Origami Mommy",
|
"BOSS: Chimata Tenkyuu", "Connecting Chain Handserif",
|
||||||
0xFF5A5A, 0xFFFFFF,
|
0x8ABFFF, 0xFFFFFF,
|
||||||
0x791D1D, 3,
|
0x552A9C, 3,
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
|
|
||||||
ObjRender_SetAngleZ(nameText, -90);
|
|
||||||
ObjText_SetFontBold(nameText, true);
|
ObjText_SetFontBold(nameText, true);
|
||||||
|
|
||||||
//_BossMarker(enemy, tex, 512, 0, 768, 256, 0.45, 30);
|
_BossMarker(enemy, tex, 512, 0, 768, 256, 0.45, 30);
|
||||||
|
|
||||||
while(!Obj_IsDeleted(enemy)){
|
while(!Obj_IsDeleted(enemy)){
|
||||||
|
|
||||||
|
@ -159,37 +158,6 @@ function <int> _CreateEnemy(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
// Hitbox and deletion
|
||||||
|
|
||||||
task _HandleEnemyWellbeing(int enemyID, float sizeHitbox, float sizeHurtbox){
|
task _HandleEnemyWellbeing(int enemyID, float sizeHitbox, float sizeHurtbox){
|
||||||
|
|
|
@ -39,7 +39,7 @@ let bossdiesnd = ObjSound_Create();
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int[] denseTrailSpiral = [7, 8, 10];
|
int[] denseTrailSpiral = [7, 8, 10];
|
||||||
float[] wvelTrailBubble = [2.5, 3.5, 4.5];
|
float[] wvelTrailBubble = [3, 4, 5];
|
||||||
float[] spdTrailBubble = [13, 14, 16];
|
float[] spdTrailBubble = [13, 14, 16];
|
||||||
|
|
||||||
int[] denseTrailCurve = [1, 1, 1];
|
int[] denseTrailCurve = [1, 1, 1];
|
||||||
|
@ -67,12 +67,12 @@ See trail burst above but x2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int[] denseAimedSpiral = [9, 10, 11];
|
int[] denseAimedSpiral = [9, 10, 11];
|
||||||
float[] wvelAimedBubble = [1.15, 1.35, 1.7];
|
float[] wvelAimedBubble = [1.25, 1.4, 1.75];
|
||||||
float[] spdAimedBubble = [12, 14, 16];
|
float[] spdAimedBubble = [12, 14, 16];
|
||||||
|
|
||||||
int[] delayAimed = [12, 10, 8];
|
int[] delayAimed = [11, 9, 7];
|
||||||
float[] accelAimed = [8/60, 9/50, 10/40];
|
float[] accelAimed = [6/60, 8/50, 10/40];
|
||||||
float[] maxspdAimed = [8, 9, 10];
|
float[] maxspdAimed = [7, 8, 9];
|
||||||
|
|
||||||
int[] delayBeforeAim = [40, 30, 20];
|
int[] delayBeforeAim = [40, 30, 20];
|
||||||
int[] delayFinalBurst = [45, 35, 30];
|
int[] delayFinalBurst = [45, 35, 30];
|
||||||
|
@ -90,7 +90,7 @@ int[] thresholdStopSpin = [80, 70, 60];
|
||||||
|
|
||||||
_InitDifficulty(difficultySelect);
|
_InitDifficulty(difficultySelect);
|
||||||
|
|
||||||
difficultySelect = 1; // debug
|
//difficultySelect = 1; // debug
|
||||||
|
|
||||||
SetShotAutoDeleteClip(64, 64, 64, 64);
|
SetShotAutoDeleteClip(64, 64, 64, 64);
|
||||||
|
|
||||||
|
@ -330,22 +330,13 @@ task _ShotAimed(shot, ang){
|
||||||
|
|
||||||
float x2 = ObjMove_GetX(shot);
|
float x2 = ObjMove_GetX(shot);
|
||||||
float y2 = ObjMove_GetY(shot);
|
float y2 = ObjMove_GetY(shot);
|
||||||
let bullet = CreateShotA1(x2, y2, 0, ObjMove_GetAngle(shot), KEV_KNIFE_LAVENDER, 15);
|
let bullet = CreateShotA1(x2, y2, 0, ObjMove_GetAngle(shot), KEV_BUTTERFLY_LAVENDER, 15);
|
||||||
|
|
||||||
if(Obj_IsDeleted(shot)){Obj_Delete(bullet);}
|
if(Obj_IsDeleted(shot)){Obj_Delete(bullet);}
|
||||||
|
|
||||||
Obj_SetRenderPriorityI(bullet, Obj_GetRenderPriorityI(shot)+1);
|
Obj_SetRenderPriorityI(bullet, Obj_GetRenderPriorityI(shot)+1);
|
||||||
Pattern(bullet, del);
|
ObjMove_AddPatternA4(bullet, delayBeforeAim[difficultySelect]-del, NO_CHANGE, 0, accelAimed[difficultySelect], maxspdAimed[difficultySelect], 0, NO_CHANGE, GetPlayerObjectID());
|
||||||
|
_BulletRescale(bullet, 0.85, true, 1);
|
||||||
task Pattern(bullet, del){
|
|
||||||
float ang = ObjMove_GetAngle(bullet);
|
|
||||||
ascent(i in 0..10){
|
|
||||||
ObjMove_AddPatternA2(bullet, delayBeforeAim[difficultySelect]-del+i, NO_CHANGE, Interpolate_Decelerate(ang, GetAngleToPlayer(bullet), i/10), accelAimed[difficultySelect], maxspdAimed[difficultySelect], 0);
|
|
||||||
yield;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_BulletRescale(bullet, 1.25, true, 1);
|
|
||||||
_Delay(bullet, 15);
|
_Delay(bullet, 15);
|
||||||
|
|
||||||
wait(delayAimed[difficultySelect]);
|
wait(delayAimed[difficultySelect]);
|
||||||
|
|
|
@ -1,193 +0,0 @@
|
||||||
#TouhouDanmakufu[Single]
|
|
||||||
#ScriptVersion[3]
|
|
||||||
#Title["Remilia Spell 1 (Remilia Card)"]
|
|
||||||
#Text["yassification"]
|
|
||||||
#System["script/KevinSystem/Kevin_System.txt"]
|
|
||||||
|
|
||||||
int difficultySelect = 0;
|
|
||||||
|
|
||||||
let objScene = GetEnemyBossSceneObjectID();
|
|
||||||
let csd = GetCurrentScriptDirectory();
|
|
||||||
|
|
||||||
let bossObj;
|
|
||||||
|
|
||||||
float bossX = 0;
|
|
||||||
float bossY = 0;
|
|
||||||
float playerY = 0;
|
|
||||||
float playerX = 0;
|
|
||||||
|
|
||||||
let aniframe = 0;
|
|
||||||
let aniframe2 = 0;
|
|
||||||
|
|
||||||
let spellsnd = ObjSound_Create();
|
|
||||||
let bossdiesnd = ObjSound_Create();
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
|
|
||||||
- Remilia wait time
|
|
||||||
- Spiral density
|
|
||||||
- Spiral angle offset per frame
|
|
||||||
|
|
||||||
- Ring density
|
|
||||||
- Ring (max) speed
|
|
||||||
- Delays between rings
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
int denseSpiral = [12, 15, 18];
|
|
||||||
int angleoffsetSpiral = [3, 4, 6];
|
|
||||||
|
|
||||||
int[] denseRing = [10, 12, 14];
|
|
||||||
float[] maxspeedRing = [8, 9, 11];
|
|
||||||
int[] deceltimeRing = [20, 30, 40];
|
|
||||||
int[] acceltimeRing = [60, 45, 35];
|
|
||||||
|
|
||||||
// Remilia takes 36 frames. Preferably, pick a number 36 can divide with.
|
|
||||||
|
|
||||||
int[] delayRing = [9, 6, 5];
|
|
||||||
|
|
||||||
// How much time Remilia takes to charge her attack and you get to GTFO.
|
|
||||||
|
|
||||||
int[] waittimeRemi = [75, 60, 50];
|
|
||||||
|
|
||||||
string tex = "script/game/resourceLib/Spritesheet_StationJam.png";
|
|
||||||
|
|
||||||
//LoadTextureEx(tex, true, true);
|
|
||||||
|
|
||||||
// Includes ahoy
|
|
||||||
|
|
||||||
#include "script/KevinSystem/Universal_Lib.txt" // The library to include all libraries :sans: :nail_care:
|
|
||||||
|
|
||||||
@Initialize {
|
|
||||||
|
|
||||||
//SetIntersectionVisualization(true);
|
|
||||||
|
|
||||||
SetAutoDeleteObject(true);
|
|
||||||
|
|
||||||
_InitDifficulty(difficultySelect);
|
|
||||||
|
|
||||||
difficultySelect = 0; // debug
|
|
||||||
|
|
||||||
SetShotAutoDeleteClip(64, 64, 64, 64);
|
|
||||||
|
|
||||||
if(!IsCommonDataAreaExists("PIV")){
|
|
||||||
CreateCommonDataArea("PIV");
|
|
||||||
SetAreaCommonData("PIV", "currentvalue", 10000);
|
|
||||||
}
|
|
||||||
else{}
|
|
||||||
|
|
||||||
// Create the boss object itself
|
|
||||||
bossObj = ObjEnemy_Create(OBJ_ENEMY_BOSS);
|
|
||||||
ObjEnemy_Regist(bossObj);
|
|
||||||
|
|
||||||
ObjMove_SetPosition(bossObj, GetCommonData("Boss Position X", STG_WIDTH/2), GetCommonData("Boss Position Y", STG_HEIGHT/2));
|
|
||||||
ObjEnemy_SetMaximumDamage(bossObj, 999);
|
|
||||||
|
|
||||||
_RenderBoss(bossObj);
|
|
||||||
|
|
||||||
//WriteLog(spellPIV);
|
|
||||||
WriteLog(ObjEnemyBossScene_GetInfo(objScene, INFO_SPELL_SCORE));
|
|
||||||
|
|
||||||
mainTask();
|
|
||||||
_FadeInvincibility(bossObj, 150, 150, 1);
|
|
||||||
endingnew();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Event {
|
|
||||||
|
|
||||||
alternative(GetEventType())
|
|
||||||
|
|
||||||
case(EV_REQUEST_LIFE) {
|
|
||||||
SetScriptResult(4000);
|
|
||||||
}
|
|
||||||
|
|
||||||
case(EV_REQUEST_TIMER) {
|
|
||||||
SetScriptResult(40);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@MainLoop {
|
|
||||||
|
|
||||||
playerY = GetPlayerY();
|
|
||||||
playerX = GetPlayerX();
|
|
||||||
//The player position is ALWAYS UPDATED
|
|
||||||
|
|
||||||
bossX = ObjMove_GetX(bossObj);
|
|
||||||
bossY = ObjMove_GetY(bossObj);
|
|
||||||
|
|
||||||
ObjEnemy_SetIntersectionCircleToShot(bossObj, ObjMove_GetX(bossObj), ObjMove_GetY(bossObj), 100);
|
|
||||||
|
|
||||||
yield;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Finalize {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
Remi Spell 1
|
|
||||||
|
|
||||||
Remi moves to your current position (takes 36 frames), fires a dense star of stars (lol) that fades away quickly, and waits a set number of frames before repeating. After 3 waves of this, she moves to the middle and shoots a thick spiral of fireballs that requires you to spin around the screen for a bit.
|
|
||||||
She also leaves behind trails of rings with every dash.
|
|
||||||
|
|
||||||
Remilia takes 36 frames to move to you each time. -> delay between rings: 9, 6, 5
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
|
|
||||||
- Remilia wait time
|
|
||||||
- Spiral density
|
|
||||||
- Spiral speed
|
|
||||||
- Spiral angle offset per frame
|
|
||||||
|
|
||||||
- Ring density
|
|
||||||
- Ring speed
|
|
||||||
- Delays between rings
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
task mainTask {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function <void> _VampireChase(){
|
|
||||||
|
|
||||||
ObjMove_SetDestAtFrame(bossObj, playerX, playerY, 36, LERP_DECELERATE);
|
|
||||||
|
|
||||||
loop(36/delayRing){
|
|
||||||
|
|
||||||
ascent(i in 0..denseRing[difficultySelect]){
|
|
||||||
int shot = CreateShotA2(bossX, bossY, maxspeedRing[difficultySelect], ang + 360/denseRing[difficultySelect] * i, -maxspeedRing[difficultySelect]/deceltimeRing[difficultySelect], 0, 0, color, 10);
|
|
||||||
if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){Obj_Delete(shot);}
|
|
||||||
else{
|
|
||||||
_Delay(shot, 10);
|
|
||||||
ObjMove_AddPatternA2(shot, 30, NO_CHANGE, NO_CHANGE, maxspeedRing[difficultySelect]/acceltimeRing[difficultySelect], maxspeedRing[difficultySelect], 0);
|
|
||||||
_BulletRescale(shot, 0.65, true, 1);
|
|
||||||
//Shoot1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wait(delayRing);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
task endingnew(){
|
|
||||||
|
|
||||||
while(ObjEnemy_GetInfo(bossObj, INFO_LIFE)>0){
|
|
||||||
yield;
|
|
||||||
}
|
|
||||||
|
|
||||||
_GoToBrazil(objScene, bossObj, 12, 24);
|
|
||||||
wait(120);
|
|
||||||
ObjSound_SetVolumeRate(fire2, 20);
|
|
||||||
|
|
||||||
CloseScript(GetOwnScriptID);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -23,46 +23,31 @@ let spellsnd = ObjSound_Create();
|
||||||
let bossdiesnd = ObjSound_Create();
|
let bossdiesnd = ObjSound_Create();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
|
|
||||||
- Line density
|
- Movement speed (in frames)
|
||||||
- Line speed
|
|
||||||
- Line delay
|
|
||||||
|
|
||||||
- Ring density
|
- Ring density
|
||||||
- Ring max speed
|
- Ring speed
|
||||||
- Delays between rings
|
|
||||||
- Remilia charge time
|
|
||||||
|
|
||||||
- Aim speed
|
- Density of one knife line
|
||||||
|
- Speed of knives
|
||||||
|
|
||||||
|
- Number of knife rings
|
||||||
|
- Density of each knife ring
|
||||||
|
- Speed of each knife ring
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int[] denseLine = [3, 4, 5];
|
int[] frameMove = [9*27, 9*25, 9*23]; // Divisible by 9
|
||||||
int[] speedLine = [8.5, 10, 12];
|
int[] denseRing = [15, 18, 21];
|
||||||
float[] delayLine = [23, 20, 18];
|
int[] speedRing = [4, 5, 6];
|
||||||
|
|
||||||
int[] denseRing = [10, 12, 14];
|
int[] denseKnifeLine = [5, 6, 7];
|
||||||
float[] maxspeedRing = [8, 9, 11];
|
float[] speedKnife = [8, 9, 10];
|
||||||
int[] deceltimeRing = [20, 30, 40];
|
float[] spaceKnifeFan = [5, 7, 9];
|
||||||
int[] acceltimeRing = [60, 45, 35];
|
|
||||||
|
|
||||||
// Remilia takes 36 frames to charge down the screen. Preferably, pick a number 36 can divide with.
|
int[] ringcountKnife = [3, 5, 7];
|
||||||
|
int[] ringdenseKnife = [10, 12, 14];
|
||||||
int[] ringDelay = [12, 9, 6];
|
float[] ringspeedKnife = [8, 9, 10];
|
||||||
|
|
||||||
// How much time Remilia takes to charge her attack and you get to GTFO.
|
|
||||||
|
|
||||||
int[] chargetimeRemi = [75, 60, 50];
|
|
||||||
float[] maxspeedBookAim = [10, 12, 15];
|
|
||||||
|
|
||||||
int[] bookArray = []; // it's a secret tool that will help us later
|
|
||||||
bool bookShooting = false; // it's a secret tool that will help us later
|
|
||||||
|
|
||||||
string tex = "script/game/resourceLib/Spritesheet_StationJam.png";
|
|
||||||
|
|
||||||
//LoadTextureEx(tex, true, true);
|
|
||||||
|
|
||||||
// Includes ahoy
|
// Includes ahoy
|
||||||
|
|
||||||
|
@ -93,7 +78,23 @@ string tex = "script/game/resourceLib/Spritesheet_StationJam.png";
|
||||||
ObjMove_SetPosition(bossObj, GetCommonData("Boss Position X", STG_WIDTH/2), GetCommonData("Boss Position Y", STG_HEIGHT/2));
|
ObjMove_SetPosition(bossObj, GetCommonData("Boss Position X", STG_WIDTH/2), GetCommonData("Boss Position Y", STG_HEIGHT/2));
|
||||||
ObjEnemy_SetMaximumDamage(bossObj, 999);
|
ObjEnemy_SetMaximumDamage(bossObj, 999);
|
||||||
|
|
||||||
_RenderBoss(bossObj);
|
// PLACEHOLDER!
|
||||||
|
let imgExRumia = GetModuleDirectory() ~ "script/ExRumia/ExRumia.png";
|
||||||
|
ObjPrim_SetTexture(bossObj, imgExRumia);
|
||||||
|
ObjSprite2D_SetSourceRect(bossObj, 64, 1, 127, 64);
|
||||||
|
ObjSprite2D_SetDestCenter(bossObj);
|
||||||
|
ObjRender_SetScaleXYZ(bossObj, 2, 2, 1);
|
||||||
|
ObjRender_SetColor(bossObj, 0xB93C3C);
|
||||||
|
ObjMove_SetDestAtFrame(bossObj, STG_WIDTH/2, 550, 1);
|
||||||
|
// PLACEHOLDER!
|
||||||
|
|
||||||
|
/*_SoloCutin(
|
||||||
|
"script/invalid.png",
|
||||||
|
0, 0, 1, 1,
|
||||||
|
bossObj, objScene, "\"Euphoric Blooming of a New Market\"",
|
||||||
|
40, 4, 0x2868B9, 0x1D115D,
|
||||||
|
10, STG_HEIGHT*1/10-30, 41
|
||||||
|
);*/
|
||||||
|
|
||||||
//WriteLog(spellPIV);
|
//WriteLog(spellPIV);
|
||||||
WriteLog(ObjEnemyBossScene_GetInfo(objScene, INFO_SPELL_SCORE));
|
WriteLog(ObjEnemyBossScene_GetInfo(objScene, INFO_SPELL_SCORE));
|
||||||
|
@ -108,23 +109,13 @@ string tex = "script/game/resourceLib/Spritesheet_StationJam.png";
|
||||||
alternative(GetEventType())
|
alternative(GetEventType())
|
||||||
|
|
||||||
case(EV_REQUEST_LIFE) {
|
case(EV_REQUEST_LIFE) {
|
||||||
SetScriptResult(2500);
|
SetScriptResult(5200);
|
||||||
}
|
}
|
||||||
|
|
||||||
case(EV_REQUEST_TIMER) {
|
case(EV_REQUEST_TIMER) {
|
||||||
SetScriptResult(40);
|
SetScriptResult(40);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start firing from books
|
|
||||||
case(EV_USER+999){
|
|
||||||
bookShooting = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop firing from books
|
|
||||||
case(EV_USER+1000){
|
|
||||||
bookShooting = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainLoop {
|
@MainLoop {
|
||||||
|
@ -164,68 +155,19 @@ Parameters:
|
||||||
|
|
||||||
- Ring density
|
- Ring density
|
||||||
- Ring speed
|
- Ring speed
|
||||||
- Delays between rings
|
|
||||||
- Remilia charge time
|
- Remilia charge time
|
||||||
- Remilia charge delay
|
- Remilia charge delay
|
||||||
|
|
||||||
- Aim speed
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
task mainTask {
|
task mainTask {
|
||||||
|
|
||||||
wait(45);
|
wait(45);
|
||||||
|
|
||||||
// Create 5 books
|
|
||||||
|
|
||||||
CreateBook([0, 0, 256, 256], STG_WIDTH*1/6, 0.65, KEV_LEAF_RED);
|
|
||||||
CreateBook([256, 0, 512, 256], STG_WIDTH*2/6, 0.65, KEV_LEAF_AQUA);
|
|
||||||
CreateBook([512, 0, 768, 256], STG_WIDTH*3/6, 0.65, KEV_LEAF_ORANGE);
|
|
||||||
CreateBook([768, 0, 1024, 256], STG_WIDTH*4/6, 0.65, KEV_LEAF_WHITE);
|
|
||||||
CreateBook([1024, 0, 1280, 256], STG_WIDTH*5/6, 0.65, KEV_LEAF_GREEN);
|
|
||||||
|
|
||||||
bookShooting = true;
|
|
||||||
|
|
||||||
// It takes 60 seconds for the books to start firing..
|
|
||||||
|
|
||||||
wait(60+delayLine[difficultySelect]*3);
|
|
||||||
|
|
||||||
// Repeat 3 times: Choose an area based on the player's position, charge down there while firing fireballs + rings, then return to same position.
|
|
||||||
|
|
||||||
while(ObjEnemy_GetInfo(bossObj, INFO_LIFE) > 0){
|
while(ObjEnemy_GetInfo(bossObj, INFO_LIFE) > 0){
|
||||||
|
|
||||||
if(playerX <= STG_WIDTH/6 && playerY >= 0){
|
|
||||||
ChargeAttack(0.5*STG_WIDTH/6, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(playerX <= 2*STG_WIDTH/6 && playerY >= STG_WIDTH/6){
|
|
||||||
ChargeAttack(1.5*STG_WIDTH/6, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if(playerX <= 3*STG_WIDTH/6 && playerY >= 2*STG_WIDTH/6){
|
|
||||||
ChargeAttack(2.5*STG_WIDTH/6, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if(playerX <= 4*STG_WIDTH/6 && playerY >= 3*STG_WIDTH/6){
|
|
||||||
ChargeAttack(3.5*STG_WIDTH/6, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if(playerX <= 5*STG_WIDTH/6 && playerY >= 4*STG_WIDTH/6){
|
|
||||||
ChargeAttack(4.5*STG_WIDTH/6, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
else{
|
|
||||||
ChargeAttack(5.5*STG_WIDTH/6, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
yield;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aim books at the player.
|
|
||||||
|
|
||||||
// Remove books from bookArray and then restart pattern.
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -236,193 +178,11 @@ Metal: 768, 0, 1024, 256
|
||||||
Earth: 1024, 0, 1280, 256
|
Earth: 1024, 0, 1280, 256
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function <void> ChargeAttack(float x, int colorselect){
|
task _CreateBook(
|
||||||
|
int[] [rectLeft, rectTop, rectRight, rectBottom],
|
||||||
ObjMove_SetDestAtFrame(bossObj, x, STG_HEIGHT/7, 30, LERP_DECELERATE);
|
float scale
|
||||||
wait(30);
|
|
||||||
|
|
||||||
_CreateCustomTelegraphLine(
|
|
||||||
x, 0,
|
|
||||||
90, 90,
|
|
||||||
3333, 3333,
|
|
||||||
0, STG_WIDTH/6,
|
|
||||||
0xDC7171, 220,
|
|
||||||
15, chargetimeRemi[difficultySelect], 15
|
|
||||||
);
|
|
||||||
|
|
||||||
wait(chargetimeRemi[difficultySelect]-30);
|
|
||||||
|
|
||||||
// MOVEEEEE BITCH
|
|
||||||
|
|
||||||
ObjMove_SetDestAtFrame(bossObj, x, STG_HEIGHT/9, 30, LERP_DECELERATE);
|
|
||||||
wait(25);
|
|
||||||
|
|
||||||
//ObjEnemy_SetDamageRate(bossObj, 0, 0);
|
|
||||||
ObjMove_SetDestAtFrame(bossObj, x, STG_HEIGHT*1.2, 36, LERP_DECELERATE);
|
|
||||||
|
|
||||||
float ang = GetAngleToPlayer(bossObj);
|
|
||||||
|
|
||||||
async{
|
|
||||||
loop(36){
|
|
||||||
loop(2){
|
|
||||||
int shot = CreateShotA1(bossX+rand(-STG_HEIGHT/12, STG_HEIGHT/12), bossY, 18, rand(269, 271), KEV_FIRE_RED, 5);
|
|
||||||
if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){Obj_Delete(shot);}
|
|
||||||
else{
|
|
||||||
_Delay(shot, 5);
|
|
||||||
_BulletRescale(shot, 0.85, true, 1);
|
|
||||||
Shoot2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wait(1);
|
|
||||||
}
|
|
||||||
ObjEnemy_SetDamageRate(bossObj, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int color = [KEV_AURABALL_RED, KEV_AURABALL_AQUA, KEV_AURABALL_ORANGE, KEV_AURABALL_WHITE, KEV_AURABALL_GREEN, KEV_AURABALL_PINK][colorselect];
|
|
||||||
|
|
||||||
loop(36/ringDelay){
|
|
||||||
|
|
||||||
ascent(i in 0..denseRing[difficultySelect]){
|
|
||||||
int shot = CreateShotA2(bossX, bossY, maxspeedRing[difficultySelect], ang + 360/denseRing[difficultySelect] * i, -maxspeedRing[difficultySelect]/deceltimeRing[difficultySelect], 0, 0, color, 10);
|
|
||||||
if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){Obj_Delete(shot);}
|
|
||||||
else{
|
|
||||||
_Delay(shot, 10);
|
|
||||||
ObjMove_AddPatternA2(shot, 30, NO_CHANGE, NO_CHANGE, maxspeedRing[difficultySelect]/acceltimeRing[difficultySelect], maxspeedRing[difficultySelect], 0);
|
|
||||||
_BulletRescale(shot, 0.65, true, 1);
|
|
||||||
//Shoot1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wait(ringDelay);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
wait(45);
|
|
||||||
|
|
||||||
ObjMove_SetPosition(bossObj, STG_WIDTH/2, -256);
|
|
||||||
ObjMove_SetDestAtFrame(bossObj, STG_WIDTH/2, STG_HEIGHT/2, 30, LERP_DECELERATE);
|
|
||||||
|
|
||||||
wait(15);
|
|
||||||
ObjEnemy_SetDamageRate(bossObj, 100, 100);
|
|
||||||
|
|
||||||
wait(75);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
task CreateBook(
|
|
||||||
int[] rect,
|
|
||||||
int destX,
|
|
||||||
float scaleEnm, int graphicBullet
|
|
||||||
){
|
){
|
||||||
|
|
||||||
int book = _CreateEnemy(
|
|
||||||
false,
|
|
||||||
bossX, bossY, destX, STG_HEIGHT/7.5, 60,
|
|
||||||
scaleEnm, scaleEnm,
|
|
||||||
99999, -1, -1,
|
|
||||||
tex,
|
|
||||||
rect[0], rect[1], rect[2], rect[3]
|
|
||||||
);
|
|
||||||
|
|
||||||
Obj_SetRenderPriorityI(book, 39);
|
|
||||||
|
|
||||||
ObjEnemy_SetEnableIntersectionPositionFetching(book, false); // so the lock-on shot doesn't home onto the books
|
|
||||||
bookArray ~= [book];
|
|
||||||
|
|
||||||
// Fire task
|
|
||||||
async{
|
|
||||||
|
|
||||||
wait(60);
|
|
||||||
|
|
||||||
while(!Obj_IsDeleted(book) && bookShooting){
|
|
||||||
|
|
||||||
loop(denseLine[difficultySelect]){
|
|
||||||
int shot = CreateShotA1(ObjMove_GetX(book), ObjMove_GetY(book), speedLine[difficultySelect], 90, graphicBullet, 15);
|
|
||||||
if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){Obj_Delete(shot);}
|
|
||||||
else{
|
|
||||||
_Delay(shot, 10);
|
|
||||||
_BulletRescale(shot, 0.85, true, 1);
|
|
||||||
Shoot1;
|
|
||||||
}
|
|
||||||
wait([3, 4, 4][difficultySelect]);
|
|
||||||
}
|
|
||||||
|
|
||||||
wait(delayLine[difficultySelect]);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
async{
|
|
||||||
while(ObjEnemy_GetInfo(bossObj, INFO_LIFE) > 0){
|
|
||||||
yield;
|
|
||||||
}
|
|
||||||
Obj_Delete(book);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
async{
|
|
||||||
|
|
||||||
wait(60);
|
|
||||||
|
|
||||||
while(bookShooting){
|
|
||||||
|
|
||||||
ascent(i in 0..24){
|
|
||||||
int shot = CreateShotA1(ObjMove_GetX(book), ObjMove_GetY(book), 12, Interpolate_Smoother(190, 350, i/24), graphicBullet+44, 15);
|
|
||||||
if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){Obj_Delete(shot);}
|
|
||||||
else{
|
|
||||||
_Delay(shot, 0);
|
|
||||||
_BulletRescale(shot, 0.5, true, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wait(delayLine[difficultySelect]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function <int> CreateFan (int parent, int way, int graphic, int stack,
|
|
||||||
float ang, float angspace, float spd1, float spd2, float scale,
|
|
||||||
int type){
|
|
||||||
|
|
||||||
int objPattern = ObjPatternShot_Create();
|
|
||||||
|
|
||||||
ObjPatternShot_SetParentObject(objPattern, parent);
|
|
||||||
|
|
||||||
if(ObjEnemyBossScene_GetInfo(GetEnemyBossSceneObjectID(), INFO_CURRENT_LIFE) == 0){Obj_Delete(objPattern); return;}
|
|
||||||
|
|
||||||
ObjPatternShot_SetPatternType(objPattern, PATTERN_LINE); // PATTERN_FAN or PATTERN_FAN_AIMED
|
|
||||||
ObjPatternShot_SetShotType(objPattern, OBJ_SHOT);
|
|
||||||
ObjPatternShot_SetInitialBlendMode(objPattern, BLEND_ALPHA);
|
|
||||||
|
|
||||||
ObjPatternShot_SetShotCount(objPattern, way, stack);
|
|
||||||
ObjPatternShot_SetSpeed(objPattern, spd1, spd2);
|
|
||||||
ObjPatternShot_SetAngle(objPattern, ang, angspace);
|
|
||||||
|
|
||||||
ObjPatternShot_SetBasePointOffset(objPattern, 0, 0);
|
|
||||||
//ObjPatternShot_SetDelay(objPattern, 15);
|
|
||||||
ObjPatternShot_SetGraphic(objPattern, graphic);
|
|
||||||
|
|
||||||
Shoot2;
|
|
||||||
int[] arrayPattern = ObjPatternShot_FireReturn(objPattern);
|
|
||||||
|
|
||||||
for each (int bullet in ref arrayPattern){
|
|
||||||
_BulletRescale(bullet, scale, true, 1);
|
|
||||||
_Delay(bullet, 10);
|
|
||||||
_EnemyShotFade(bullet, 600, true, 2.5); // Placeholder
|
|
||||||
Obj_SetRenderPriorityI(bullet, 51);
|
|
||||||
//if (reflect) {_ReflectToPlayer(bullet);}
|
|
||||||
}
|
|
||||||
|
|
||||||
async{
|
|
||||||
wait(600);
|
|
||||||
Obj_Delete(objPattern);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return objPattern;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
task endingnew(){
|
task endingnew(){
|
||||||
|
|
|
@ -38,12 +38,12 @@ Parameters:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int[] frameMove = [9*27, 9*25, 9*23]; // Divisible by 9
|
int[] frameMove = [9*27, 9*25, 9*23]; // Divisible by 9
|
||||||
int[] denseRing = [14, 16, 20];
|
int[] denseRing = [15, 18, 21];
|
||||||
int[] speedRing = [4, 5, 6];
|
int[] speedRing = [4, 5, 6];
|
||||||
|
|
||||||
int[] denseKnifeLine = [4, 5, 6];
|
int[] denseKnifeLine = [5, 6, 7];
|
||||||
float[] speedKnife = [8, 10, 12];
|
float[] speedKnife = [8, 9, 10];
|
||||||
float[] spaceKnifeFan = [4, 6, 8];
|
float[] spaceKnifeFan = [5, 7, 9];
|
||||||
|
|
||||||
int[] ringcountKnife = [3, 5, 7];
|
int[] ringcountKnife = [3, 5, 7];
|
||||||
int[] ringdenseKnife = [10, 12, 14];
|
int[] ringdenseKnife = [10, 12, 14];
|
||||||
|
@ -78,7 +78,23 @@ float[] ringspeedKnife = [8, 9, 10];
|
||||||
ObjMove_SetPosition(bossObj, GetCommonData("Boss Position X", STG_WIDTH/2), GetCommonData("Boss Position Y", STG_HEIGHT/2));
|
ObjMove_SetPosition(bossObj, GetCommonData("Boss Position X", STG_WIDTH/2), GetCommonData("Boss Position Y", STG_HEIGHT/2));
|
||||||
ObjEnemy_SetMaximumDamage(bossObj, 999);
|
ObjEnemy_SetMaximumDamage(bossObj, 999);
|
||||||
|
|
||||||
_RenderBoss(bossObj);
|
// PLACEHOLDER!
|
||||||
|
let imgExRumia = GetModuleDirectory() ~ "script/ExRumia/ExRumia.png";
|
||||||
|
ObjPrim_SetTexture(bossObj, imgExRumia);
|
||||||
|
ObjSprite2D_SetSourceRect(bossObj, 64, 1, 127, 64);
|
||||||
|
ObjSprite2D_SetDestCenter(bossObj);
|
||||||
|
ObjRender_SetScaleXYZ(bossObj, 2, 2, 1);
|
||||||
|
ObjRender_SetColor(bossObj, 0xB93C3C);
|
||||||
|
ObjMove_SetDestAtFrame(bossObj, STG_WIDTH/2, 550, 1);
|
||||||
|
// PLACEHOLDER!
|
||||||
|
|
||||||
|
/*_SoloCutin(
|
||||||
|
"script/invalid.png",
|
||||||
|
0, 0, 1, 1,
|
||||||
|
bossObj, objScene, "\"Euphoric Blooming of a New Market\"",
|
||||||
|
40, 4, 0x2868B9, 0x1D115D,
|
||||||
|
10, STG_HEIGHT*1/10-30, 41
|
||||||
|
);*/
|
||||||
|
|
||||||
//WriteLog(spellPIV);
|
//WriteLog(spellPIV);
|
||||||
WriteLog(ObjEnemyBossScene_GetInfo(objScene, INFO_SPELL_SCORE));
|
WriteLog(ObjEnemyBossScene_GetInfo(objScene, INFO_SPELL_SCORE));
|
||||||
|
@ -237,20 +253,20 @@ function <void> MoveToBottom(){
|
||||||
// If you're at bottom, you die. (Hyper and above)
|
// If you're at bottom, you die. (Hyper and above)
|
||||||
|
|
||||||
if(difficultySelect >= 0){
|
if(difficultySelect >= 0){
|
||||||
loop([6, 7, 9][difficultySelect]){
|
loop(9){
|
||||||
|
|
||||||
float ang = GetAngleToPlayer(bossObj);
|
float ang = GetAngleToPlayer(bossObj);
|
||||||
float[] spawn = [bossX+rand(-25, 25), bossY+rand(-25, 25)];
|
float[] spawn = [bossX+rand(-25, 25), bossY+rand(-25, 25)];
|
||||||
|
|
||||||
ascent(i in -1..denseRing[difficultySelect]-1){
|
ascent(i in -1..denseRing[difficultySelect]-1){
|
||||||
int shot = CreateShotA2(spawn[0], spawn[1], speedRing[difficultySelect]*2.5, ang+(360/denseRing[difficultySelect])*i, -speedRing[difficultySelect]*2.5/[30, 40, 45][difficultySelect], speedRing[difficultySelect]*[0.3, 0.2, 0.1][difficultySelect], KEV_KNIFE_LAVENDER, 10);
|
int shot = CreateShotA2(spawn[0], spawn[1], speedRing[difficultySelect]*2.5, ang+(360/denseRing[difficultySelect])*i, -speedRing[difficultySelect]*2.5/[30, 40, 45][difficultySelect], speedRing[difficultySelect]*[0.3, 0.2, 0.1][difficultySelect], KEV_KNIFE_RED, 10);
|
||||||
if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) == 0){Obj_Delete(shot);}
|
if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) == 0){Obj_Delete(shot);}
|
||||||
else{
|
else{
|
||||||
ObjMove_AddPatternA2(shot, 90, NO_CHANGE, NO_CHANGE, speedRing[difficultySelect]/45, speedRing[difficultySelect]*[1.65, 1.4, 1.25][difficultySelect], 0);
|
ObjMove_AddPatternA2(shot, 90, NO_CHANGE, NO_CHANGE, speedRing[difficultySelect]/45, speedRing[difficultySelect]*[1.65, 1.4, 1.25][difficultySelect], 0);
|
||||||
_Delay(shot, 10);
|
_Delay(shot, 10);
|
||||||
//ObjRender_SetBlendType(shot, BLEND_ADD_ARGB);
|
ObjRender_SetBlendType(shot, BLEND_ADD_ARGB);
|
||||||
_BulletRescale(shot, 1.25, true, 1);
|
_BulletRescale(shot, 1.25, true, 1);
|
||||||
Shoot2;
|
Shoot1;
|
||||||
if(difficultySelect >= 1){_ReflectToPlayer(shot);}
|
if(difficultySelect >= 1){_ReflectToPlayer(shot);}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,11 +281,11 @@ function <void> MoveToBottom(){
|
||||||
loop(3){
|
loop(3){
|
||||||
|
|
||||||
CreateFan(3, KEV_KNIFE_LAVENDER, denseKnifeLine[difficultySelect],
|
CreateFan(3, KEV_KNIFE_LAVENDER, denseKnifeLine[difficultySelect],
|
||||||
0, spaceKnifeFan[difficultySelect], speedKnife[difficultySelect]/1.18, speedKnife[difficultySelect], 1.25,
|
0, spaceKnifeFan[difficultySelect], speedKnife[difficultySelect]/1.3, speedKnife[difficultySelect], 1.25,
|
||||||
PATTERN_FAN, true);
|
PATTERN_FAN, true);
|
||||||
|
|
||||||
CreateFan(3, KEV_KNIFE_LAVENDER, denseKnifeLine[difficultySelect],
|
CreateFan(3, KEV_KNIFE_LAVENDER, denseKnifeLine[difficultySelect],
|
||||||
180, spaceKnifeFan[difficultySelect], speedKnife[difficultySelect]/1.18, speedKnife[difficultySelect], 1.25,
|
180, spaceKnifeFan[difficultySelect], speedKnife[difficultySelect]/1.3, speedKnife[difficultySelect], 1.25,
|
||||||
PATTERN_FAN, true);
|
PATTERN_FAN, true);
|
||||||
|
|
||||||
wait(frameMove[difficultySelect]/3);
|
wait(frameMove[difficultySelect]/3);
|
||||||
|
@ -329,7 +345,7 @@ task _ReflectToPlayer(int target){
|
||||||
if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) == 0){Obj_Delete(target); return;}
|
if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) == 0){Obj_Delete(target); return;}
|
||||||
if (ObjMove_GetX(target) <= -15 || ObjMove_GetX(target) >= GetStgFrameWidth()+15){
|
if (ObjMove_GetX(target) <= -15 || ObjMove_GetX(target) >= GetStgFrameWidth()+15){
|
||||||
ObjMove_AddPatternA4(target, 0, NO_CHANGE, 0, NO_CHANGE, NO_CHANGE, 0, KEV_KNIFE_GREEN, GetPlayerObjectID());
|
ObjMove_AddPatternA4(target, 0, NO_CHANGE, 0, NO_CHANGE, NO_CHANGE, 0, KEV_KNIFE_GREEN, GetPlayerObjectID());
|
||||||
Shoot1;
|
Shoot2;
|
||||||
ObjShot_SetAutoDelete(target, true);
|
ObjShot_SetAutoDelete(target, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 314 KiB After Width: | Height: | Size: 290 KiB |
Before Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 51 KiB |
|
@ -0,0 +1,452 @@
|
||||||
|
#TouhouDanmakufu[Player]
|
||||||
|
#ScriptVersion[3]
|
||||||
|
#ID["Rinno"]
|
||||||
|
#Title["Rinnosuke"]
|
||||||
|
#Text["Unfocused Shot: Rage of the Electronic[r]Focused Shot: Doomsday Button[r]Spell Card: Prototype \"Volatile Hakkero\""]
|
||||||
|
//#Image["./kevkou_lib/gayimg.png"]
|
||||||
|
|
||||||
|
#ReplayName["Rinno"]
|
||||||
|
|
||||||
|
#include "script/KevinSystem/Kevin_PlayerLib.txt"
|
||||||
|
#include "./Rinnosuke_ShotConst.dnh"
|
||||||
|
#include "./soundlib.txt"
|
||||||
|
|
||||||
|
#include "script/KevinSystem/kevin_system/Kevin_ItemConst.txt"
|
||||||
|
#include "script/KevinSystem/kevin_system/Kevin_ItemLib.txt"
|
||||||
|
|
||||||
|
let csd = GetCurrentScriptDirectory();
|
||||||
|
|
||||||
|
// Global Variables
|
||||||
|
|
||||||
|
float maxX = GetStgFrameWidth();
|
||||||
|
float maxY = GetStgFrameHeight();
|
||||||
|
|
||||||
|
int targetedenemy = 0; // This will be used to store the enemy ID Kouda's homing shots aim at
|
||||||
|
|
||||||
|
// Images & Sound
|
||||||
|
|
||||||
|
let teamimg = "script/TouhouJam8_SRE/Jam8_Resource/jam8Sprite.png";
|
||||||
|
LoadTextureEx(teamimg, true, true);
|
||||||
|
//ObjRender_SetTextureFilterMip(teamimg, FILTER_LINEAR);
|
||||||
|
|
||||||
|
let sndpath = csd ~ "./sound";
|
||||||
|
|
||||||
|
// Other stuff
|
||||||
|
|
||||||
|
float playerX = 0;
|
||||||
|
float playerY = 0;
|
||||||
|
|
||||||
|
let objPlayer = GetPlayerObjectID();
|
||||||
|
int plrender = Obj_GetRenderPriorityI(objPlayer);
|
||||||
|
|
||||||
|
bool ripplayer = false;
|
||||||
|
float shotspeed = 0;
|
||||||
|
float bombrand = 0;
|
||||||
|
|
||||||
|
bool bombenable = false;
|
||||||
|
bool focusactive = false;
|
||||||
|
bool ishoming = false;
|
||||||
|
|
||||||
|
int[] _enemyArray = []; // Prepare an array to store enemy IDs for Kouda's homing shot
|
||||||
|
int[] _existArray = [];
|
||||||
|
|
||||||
|
int grazecounter = 0; // For basic graze = PIV mechanic
|
||||||
|
|
||||||
|
// Custom events for scoring mechanic
|
||||||
|
|
||||||
|
const EV_PIV_100 = EV_USER + 100i; // Normal enemies and nons
|
||||||
|
const EV_PIV_250 = EV_USER + 101i; // Spells
|
||||||
|
const EV_PIV_500 = EV_USER + 102i; // Last Spells
|
||||||
|
const EV_PIV_2000 = EV_USER + 103i; // What.
|
||||||
|
|
||||||
|
@Initialize{
|
||||||
|
|
||||||
|
if(!IsCommonDataAreaExists("PIV")){
|
||||||
|
CreateCommonDataArea("PIV");
|
||||||
|
SetAreaCommonData("PIV", "currentvalue", 10000);
|
||||||
|
}
|
||||||
|
else{}
|
||||||
|
|
||||||
|
// Stuff
|
||||||
|
parameterrender();
|
||||||
|
playerrender();
|
||||||
|
plrender = Obj_GetRenderPriorityI(objPlayer);
|
||||||
|
|
||||||
|
_SoundTask();
|
||||||
|
|
||||||
|
_Mechanic(ripplayer, _enemyArray, _existArray, GetStgFrameWidth(), GetStgFrameHeight(), objPlayer, GetEnemyBossSceneObjectID(), 3, 2, 30);
|
||||||
|
|
||||||
|
_HitboxRender(ripplayer, objPlayer, teamimg, teamimg, 512, 0, 640, 128, 768, 0, 1024, 256, 0.2, 1);
|
||||||
|
|
||||||
|
// Shot functions
|
||||||
|
|
||||||
|
//_EnemySelect();
|
||||||
|
|
||||||
|
_Homing();
|
||||||
|
//_UnfocusedShot();
|
||||||
|
|
||||||
|
//_ShotType();
|
||||||
|
|
||||||
|
// Shot data loading
|
||||||
|
LoadPlayerShotData(csd ~ "./Rinnosuke_ShotData.dnh");
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainLoop{
|
||||||
|
_enemyArray = GetIntersectionRegistedEnemyID; // Constantly update the enemy ID array
|
||||||
|
shotspeed += 1; // Managing the shot rate
|
||||||
|
playerX = ObjMove_GetX(objPlayer);
|
||||||
|
playerY = ObjMove_GetY(objPlayer);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Event{
|
||||||
|
alternative(GetEventType)
|
||||||
|
|
||||||
|
// PIV-item spawning events
|
||||||
|
|
||||||
|
case(EV_DELETE_SHOT_PLAYER){
|
||||||
|
let graphic = GetEventArgument(2);
|
||||||
|
float[] position = GetEventArgument(1);
|
||||||
|
let obj = CreatePlayerShotA1(position[0], position[1], 0, 0, 0, 99999, graphic);
|
||||||
|
ObjShot_SetIntersectionEnable(obj, false);
|
||||||
|
_DeleteEffect(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_PIV_100){
|
||||||
|
let arg = GetEventArgument(0);
|
||||||
|
CreatePIVItem(PIV_100, arg[0], arg[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_PIV_250){
|
||||||
|
let arg = GetEventArgument(0);
|
||||||
|
CreatePIVItem(PIV_250, arg[0], arg[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_PIV_500){
|
||||||
|
let arg = GetEventArgument(0);
|
||||||
|
CreatePIVItem(PIV_500, arg[0], arg[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic functionality events
|
||||||
|
case(EV_REQUEST_SPELL){
|
||||||
|
let bomb = GetPlayerSpell();
|
||||||
|
|
||||||
|
if (bomb >= 1){
|
||||||
|
SetScriptResult(true);
|
||||||
|
SetPlayerSpell(bomb - 1);
|
||||||
|
Bomb();
|
||||||
|
_SigilCall(false, teamimg, 256, 512, 512, 768, objPlayer, GetPlayerInvincibilityFrame());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SetScriptResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_HIT){
|
||||||
|
//_DeathbombWarning(teamimg, [2560, 512, 2560+512, 1024], 30, 0.65);
|
||||||
|
ObjSound_Play(predeathsfx);
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_PLAYER_SHOOTDOWN){
|
||||||
|
ObjSound_Play(deathsfx);
|
||||||
|
ripplayer = true;
|
||||||
|
_SigilCall(true, teamimg, 0, 512, 256, 768, objPlayer, 120);
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_PLAYER_REBIRTH){
|
||||||
|
ripplayer = false;
|
||||||
|
SetPlayerInvincibilityFrame(180);
|
||||||
|
_SigilCall(false, teamimg, 256, 512, 512, 768, objPlayer, GetPlayerInvincibilityFrame());
|
||||||
|
SetPlayerSpell( max(3, GetPlayerSpell()) );
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_GRAZE){
|
||||||
|
grazecounter += GetEventArgument(0);
|
||||||
|
while(grazecounter >= 10){
|
||||||
|
SetAreaCommonData("PIV", "currentvalue", GetAreaCommonData("PIV", "currentvalue")+10);
|
||||||
|
grazecounter -= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Finalize{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
task _DeleteEffect(obj){
|
||||||
|
ObjRender_SetBlendType(obj, BLEND_ADD_ARGB);
|
||||||
|
ascent(i in 0..30){
|
||||||
|
ObjRender_SetAlpha(obj, Interpolate_Decelerate(120, 0, i/30));
|
||||||
|
ObjRender_SetScaleXYZ(obj, Interpolate_Decelerate(0.5, 2, i/30));
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
Obj_Delete(obj);
|
||||||
|
}
|
||||||
|
// Basic player parameters
|
||||||
|
|
||||||
|
task parameterrender(){
|
||||||
|
SetPlayerItemScope(200); // Special Ability 1
|
||||||
|
SetPlayerLife(5); // Debug
|
||||||
|
SetPlayerSpell(3);
|
||||||
|
SetPlayerSpeed(6.5, 2.8); // (original: 4.5/1.75)
|
||||||
|
SetPlayerRebirthFrame(30); // Special Ability 2
|
||||||
|
SetPlayerAutoItemCollectLine(GetStgFrameHeight/3); //596x632 STG frame
|
||||||
|
SetPlayerRebirthLossFrame(0);
|
||||||
|
ObjPlayer_AddIntersectionCircleA1(objPlayer,0,0,1.5,25);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renders the shottype
|
||||||
|
|
||||||
|
// Selects an enemy to home on.
|
||||||
|
|
||||||
|
task _HomeShot(int shot_) {
|
||||||
|
|
||||||
|
float duration = 55;
|
||||||
|
bool homingBool = false;
|
||||||
|
float basepenetrate = ObjShot_GetPenetration(shot_);
|
||||||
|
float basedmg = ObjShot_GetDamage(shot_);
|
||||||
|
|
||||||
|
// Original code
|
||||||
|
|
||||||
|
async{
|
||||||
|
_BulletRescalePlayer(shot_, 0.75, true, 1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
for (int t = 0i; t < duration && !Obj_IsDeleted(shot_); t++) {
|
||||||
|
|
||||||
|
// Checks if enemies are on screen. If enemies are visible, enable homing for the shots.
|
||||||
|
// _enemyArray is an array containing all enemy IDs, and is constantly updated in @MainLoop.
|
||||||
|
|
||||||
|
if (0 < length(_enemyArray)) {
|
||||||
|
float targetDist = 2000; // Arbitrary number (???)
|
||||||
|
int targetID = 0;
|
||||||
|
|
||||||
|
// Checks distance of every enemy on screen.
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
|
// Returns the hypotenuse of the triangle formed by the x & y distances between the shot and the enemy.
|
||||||
|
|
||||||
|
float shotDist = hypot(enemyX - ObjMove_GetX(objPlayer), enemyY - ObjMove_GetY(objPlayer));
|
||||||
|
|
||||||
|
// Locks the shot onto the enemy.
|
||||||
|
|
||||||
|
if (shotDist < targetDist) {
|
||||||
|
targetDist = shotDist;
|
||||||
|
targetID = enemy;
|
||||||
|
homingBool = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code to handle the actual homing.
|
||||||
|
|
||||||
|
if (homingBool) {
|
||||||
|
for (int f = 0; t < duration && !Obj_IsDeleted(shot_) && !Obj_IsDeleted(targetID) && ObjEnemy_GetInfo(targetID, INFO_LIFE) != 0 && !ObjCol_IsIntersected(shot_); t++) {
|
||||||
|
ObjShot_SetAutoDelete(shot_, false);
|
||||||
|
float shotAngle = NormalizeAngle(ObjMove_GetAngle(shot_)); // Angle of the player shot
|
||||||
|
float targetAngle = NormalizeAngle(atan2(ObjMove_GetY(targetID) - ObjMove_GetY(shot_), ObjMove_GetX(targetID) - ObjMove_GetX(shot_))); // Returns angle from the shot to the enemy.
|
||||||
|
float angleDistance = AngularDistance(shotAngle, targetAngle); // Angular distance between enemy and player shot
|
||||||
|
float homeRate = Interpolate_Decelerate(0, 0.75, min(60, f) / 60);
|
||||||
|
// Homing speed?
|
||||||
|
ObjMove_SetAngle(shot_, Interpolate_Accelerate(shotAngle, shotAngle + angleDistance, homeRate)); // Interpolate_Necko
|
||||||
|
f++;
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
ObjShot_SetAutoDelete(shot_, true);
|
||||||
|
ObjMove_SetAngularVelocity(shot_, 0);
|
||||||
|
homingBool = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task _Homing(){
|
||||||
|
|
||||||
|
let optionA = PlayerOption(50, 0, 256, 256, 512, 512);
|
||||||
|
let optionB = PlayerOption(-50, 0, 256, 256, 512, 512);
|
||||||
|
let optionC = PlayerOption(90, 30, 256, 256, 512, 512);
|
||||||
|
let optionD = PlayerOption(-90, 30, 256, 256, 512, 512);
|
||||||
|
|
||||||
|
int shotspeedhome = 0;
|
||||||
|
|
||||||
|
int[] optionList = [optionA, optionB, optionC, optionD];
|
||||||
|
int[] optionList1 = [optionA, optionC];
|
||||||
|
int[] optionList2 = [optionB, optionD];
|
||||||
|
|
||||||
|
int a = 0;
|
||||||
|
|
||||||
|
loop{
|
||||||
|
if(shotspeedhome % 5 == 0 && GetVirtualKeyState(VK_SHOT) != KEY_FREE && IsPermitPlayerShot && !ripplayer){
|
||||||
|
|
||||||
|
if(GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){
|
||||||
|
|
||||||
|
for each (int option in ref optionList){
|
||||||
|
//"l
|
||||||
|
float x = ObjRender_GetX(option);
|
||||||
|
float y = ObjRender_GetY(option);
|
||||||
|
|
||||||
|
let shotA = CreatePlayerShotA1(x, y, 15, 270, 2.65, 2, FOCUSED);
|
||||||
|
//ObjMove_AddPatternA2(shotA, 1, 5, NO_CHANGE, -0.1, 3.75, rand(-0.4, 0.4));
|
||||||
|
|
||||||
|
_HomeShot(shotA);
|
||||||
|
}
|
||||||
|
|
||||||
|
ascent(i in -2..3){
|
||||||
|
int shot = CreatePlayerShotA1(playerX, playerY, 17, 270-5*i, 3.5, 2, UNFOCUSED);
|
||||||
|
_BulletRescalePlayer(shot, 0.5, true, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else{
|
||||||
|
|
||||||
|
for each (int option in ref optionList1){
|
||||||
|
//"
|
||||||
|
float x = ObjRender_GetX(option);
|
||||||
|
float y = ObjRender_GetY(option);
|
||||||
|
|
||||||
|
ascent(i in -1..2){
|
||||||
|
int shot = CreatePlayerShotA1(x, y, 17, 240-10*i, 4, 1.75, UNFOCUSED);
|
||||||
|
_BulletRescalePlayer(shot, 0.5, true, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for each (int option in ref optionList2){
|
||||||
|
//"
|
||||||
|
float x = ObjRender_GetX(option);
|
||||||
|
float y = ObjRender_GetY(option);
|
||||||
|
|
||||||
|
ascent(i in -1..2){
|
||||||
|
int shot = CreatePlayerShotA1(x, y, 17, 300+10*i, 4, 1.75, UNFOCUSED);
|
||||||
|
_BulletRescalePlayer(shot, 0.5, true, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shotspeedhome++;
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Player option rendering
|
||||||
|
|
||||||
|
function PlayerOption(offsetx, offsety, left, top, right, bottom){
|
||||||
|
let option = ObjPrim_Create(OBJ_SPRITE_2D);
|
||||||
|
bool visible;
|
||||||
|
int animate = 0;
|
||||||
|
float optx;
|
||||||
|
float opty;
|
||||||
|
|
||||||
|
ObjPrim_SetTexture(option, teamimg);
|
||||||
|
ObjSprite2D_SetSourceRect(option, left, top, right, bottom);
|
||||||
|
ObjSprite2D_SetDestCenter(option);
|
||||||
|
ObjRender_SetScaleXYZ(option, 0.25, 0.25, 1);
|
||||||
|
ObjRender_SetBlendType(option, BLEND_ALPHA);
|
||||||
|
ObjRender_SetAlpha(option, 180);
|
||||||
|
Obj_SetRenderPriorityI(option, 41);
|
||||||
|
ObjRender_SetPosition(option, offsetx, offsety, 1);
|
||||||
|
|
||||||
|
async{
|
||||||
|
loop{
|
||||||
|
ObjRender_SetPosition(option, GetPlayerX()+offsetx, GetPlayerY()+offsety, 1);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async{
|
||||||
|
loop{
|
||||||
|
if(ripplayer){Obj_SetVisible(option, false); visible = false;}
|
||||||
|
else {Obj_SetVisible(option, true); visible = true;}
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Player sprites
|
||||||
|
|
||||||
|
task playerrender(){
|
||||||
|
|
||||||
|
// Why is this movement code so cursed jesus fucking christ
|
||||||
|
|
||||||
|
float scale = 0.4; // Scalies
|
||||||
|
|
||||||
|
ObjPrim_SetTexture(objPlayer, teamimg);
|
||||||
|
ObjSprite2D_SetSourceRect(objPlayer, 0, 256, 256, 512);
|
||||||
|
ObjSprite2D_SetDestCenter(objPlayer);
|
||||||
|
Obj_SetRenderPriorityI(objPlayer, 42);
|
||||||
|
ObjRender_SetScaleXYZ(objPlayer, scale, scale, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
task Bomb(){
|
||||||
|
// Preparation
|
||||||
|
//SetForbidPlayerShot(true);
|
||||||
|
SetForbidPlayerSpell(true);
|
||||||
|
SetPlayerInvincibilityFrame(300);
|
||||||
|
// Spell object
|
||||||
|
let manageObj = GetSpellManageObject(); // SPELL BEGINS
|
||||||
|
ObjSpell_Regist(manageObj);
|
||||||
|
ObjSound_Play(bombsfx);
|
||||||
|
|
||||||
|
// Spell
|
||||||
|
|
||||||
|
int hakkero = CreatePlayerShotA1(playerX, playerY, 0, 0, 12, 999999, BOMB);
|
||||||
|
ObjShot_SetIntersectionEnable(hakkero, true);
|
||||||
|
ObjShot_SetEraseShot(hakkero, true);
|
||||||
|
ObjShot_SetSpellFactor(hakkero, true);
|
||||||
|
|
||||||
|
async{
|
||||||
|
ascent(i in 0..45){
|
||||||
|
_BulletRescalePlayer(hakkero, Interpolate_Decelerate(0.5, 2.25, i/45), true, 1);
|
||||||
|
ObjRender_SetAlpha(hakkero, Interpolate_Decelerate(0, 255, i/45));
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ascent(i in 0..240){
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup, end of spell
|
||||||
|
ObjShot_FadeDelete(hakkero);
|
||||||
|
SetForbidPlayerShot(false);
|
||||||
|
wait(60);
|
||||||
|
SetForbidPlayerSpell(false);
|
||||||
|
Obj_Delete(manageObj); // !!! IMPORTANT !!!
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Screenshake function for bomb's duration - adapted from Sparen's tutorials
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
let current = GetCurrentScriptDirectory();
|
||||||
|
let path = current ~ "Rinnosuke_ShotData.dnh";
|
||||||
|
LoadPlayerShotData(path);
|
||||||
|
// -----
|
||||||
|
const FOCUSED = 1;
|
||||||
|
const UNFOCUSED = 2;
|
||||||
|
const BOMB = 3;
|
|
@ -0,0 +1,14 @@
|
||||||
|
shot_image = "./../../TouhouJam8_SRE/Jam8_Resource/jam8Sprite.png"
|
||||||
|
|
||||||
|
ShotData{
|
||||||
|
id = 0 // Dummy
|
||||||
|
rect = (0,0,0,0)
|
||||||
|
render = ALPHA
|
||||||
|
alpha = 0
|
||||||
|
collision = 12
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rinnosuke's shots
|
||||||
|
ShotData{id = 1 rect = (512, 256, 639, 383) render = ALPHA alpha = 180 collision = 38 fixed_angle = false angular_velocity = 3} // Homing shot, spins
|
||||||
|
ShotData{id = 2 rect = (640, 256, 768, 384) render = ALPHA alpha = 150 collision = 38} // Unfocused shot
|
||||||
|
ShotData{id = 3 rect = (768, 256, 1023, 511) render = ADD_ARGB alpha = 255 collision = 115 fixed_angle = false angular_velocity = 8} // Bomb
|
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
let sddir = GetCurrentScriptDirectory() ~ "./sound";
|
||||||
|
|
||||||
|
function LoadEx(targetobj, targetpath, targetvol){
|
||||||
|
|
||||||
|
ObjSound_Load(targetobj, targetpath);
|
||||||
|
ObjSound_SetVolumeRate(targetobj, targetvol);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Universal sounds
|
||||||
|
|
||||||
|
let bomb = sddir ~ "./bfxr_RinnoBomb.wav";
|
||||||
|
let ded = sddir ~ "./bfxr_PlayerDie.wav";
|
||||||
|
let hit = sddir ~ "./bfxr_PreDeath.wav";
|
||||||
|
|
||||||
|
let bombsfx = ObjSound_Create();
|
||||||
|
let deathsfx = ObjSound_Create();
|
||||||
|
let predeathsfx = ObjSound_Create();
|
||||||
|
|
||||||
|
task _SoundTask(){
|
||||||
|
LoadEx(bombsfx, bomb, 15);
|
||||||
|
LoadEx(deathsfx, ded, 40);
|
||||||
|
LoadEx(predeathsfx, hit, 55);
|
||||||
|
}
|
|
@ -0,0 +1,218 @@
|
||||||
|
|
||||||
|
// Particle list for laser effect
|
||||||
|
|
||||||
|
int LaserEffect = ObjParticleList_Create(OBJ_PARTICLE_LIST_2D);
|
||||||
|
int[] rect = [2816, 0, 2816+256, 0+256];
|
||||||
|
|
||||||
|
ObjPrim_SetTexture(LaserEffect, "script/player/PrideJam_ByakMiko/playerlib/ByakMiko_Sheet.png");
|
||||||
|
|
||||||
|
Obj_SetRenderPriorityI(LaserEffect, 41);
|
||||||
|
ObjPrim_SetPrimitiveType(LaserEffect, PRIMITIVE_TRIANGLELIST);
|
||||||
|
ObjPrim_SetVertexCount(LaserEffect, 4);
|
||||||
|
|
||||||
|
ObjRender_SetBlendType(LaserEffect, BLEND_ADD_ARGB);
|
||||||
|
|
||||||
|
// Left-top, right-top, left-bottom, right-bottom
|
||||||
|
|
||||||
|
ObjPrim_SetVertexUVT(LaserEffect, 0, rect[0], rect[1]);
|
||||||
|
ObjPrim_SetVertexUVT(LaserEffect, 1, rect[2], rect[1]);
|
||||||
|
ObjPrim_SetVertexUVT(LaserEffect, 2, rect[0], rect[3]);
|
||||||
|
ObjPrim_SetVertexUVT(LaserEffect, 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(LaserEffect, 0, -dU, -dV, 1);
|
||||||
|
ObjPrim_SetVertexPosition(LaserEffect, 1, dU, -dV, 1);
|
||||||
|
ObjPrim_SetVertexPosition(LaserEffect, 2, -dU, dV, 1);
|
||||||
|
ObjPrim_SetVertexPosition(LaserEffect, 3, dU, dV, 1);
|
||||||
|
|
||||||
|
ObjPrim_SetVertexIndex(LaserEffect, [0, 1, 2, 1, 2, 3]);
|
||||||
|
|
||||||
|
task _CreateLaserParticle(float x, float y, float spdX, float spdY, float baseAng){
|
||||||
|
|
||||||
|
int effectLength = 45;
|
||||||
|
let x_speed = spdX;
|
||||||
|
let y_speed = spdY;
|
||||||
|
let z_add = rand(-5, 5);
|
||||||
|
|
||||||
|
ascent(i in 0..effectLength){
|
||||||
|
_PetalMovement(Interpolate_Decelerate(0.5, 0.2, i/effectLength), Interpolate_Decelerate(255, 0, i/effectLength));
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
task _PetalMovement(scale, alpha){
|
||||||
|
|
||||||
|
ObjParticleList_SetScale(LaserEffect, scale);
|
||||||
|
ObjParticleList_SetAngleZ(LaserEffect, baseAng);
|
||||||
|
ObjParticleList_SetPosition(LaserEffect, x, y, 1);
|
||||||
|
ObjParticleList_SetAlpha(LaserEffect, alpha);
|
||||||
|
|
||||||
|
//Submits the current data to an instance, cleared every frame.
|
||||||
|
ObjParticleList_AddInstance(LaserEffect);
|
||||||
|
|
||||||
|
x += x_speed;
|
||||||
|
y += y_speed;
|
||||||
|
baseAng += z_add;
|
||||||
|
|
||||||
|
yield;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
task _LaserSpriteRender(
|
||||||
|
img, int target, float targetAng,
|
||||||
|
int rectLeft, int rectTop, int rectRight, int rectBottom,
|
||||||
|
float scaleX, float scaleY, int renderPriority, float alpha,
|
||||||
|
float scaleSpeed
|
||||||
|
){
|
||||||
|
|
||||||
|
int[] EnemyList = [];
|
||||||
|
let lasersprite = ObjPrim_Create(OBJ_SPRITE_2D);
|
||||||
|
|
||||||
|
ObjPrim_SetTexture(lasersprite, img);
|
||||||
|
ObjSprite2D_SetSourceRect(lasersprite, rectLeft, rectTop, rectRight, rectBottom);
|
||||||
|
ObjRender_SetScaleXYZ(lasersprite, 0, scaleY, 1);
|
||||||
|
ObjSprite2D_SetDestRect(lasersprite, -(rectRight-rectLeft)/2, 0, (rectRight-rectLeft)/2, rectTop-rectBottom);
|
||||||
|
Obj_SetRenderPriorityI(lasersprite, renderPriority);
|
||||||
|
ObjRender_SetAlpha(lasersprite, 0);
|
||||||
|
ObjRender_SetBlendType(lasersprite, BLEND_ADD_ARGB);
|
||||||
|
|
||||||
|
async{
|
||||||
|
loop{
|
||||||
|
EnemyList = ObjCol_GetListOfIntersectedEnemyID(target);
|
||||||
|
if(GetVirtualKeyState(VK_SHOT) != KEY_FREE && GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE && !ripplayer && IsPermitPlayerShot){
|
||||||
|
|
||||||
|
// Assumes the intersecting color is right next to the right of the original color
|
||||||
|
|
||||||
|
if (length(EnemyList) > 0) {ObjSprite2D_SetSourceRect(lasersprite, rectRight, rectTop, rectRight+(rectRight-rectLeft), rectBottom);}
|
||||||
|
else{ObjSprite2D_SetSourceRect(lasersprite, rectLeft, rectTop, rectRight, rectBottom);}
|
||||||
|
float targetx = ObjRender_GetX(target);
|
||||||
|
float targety = ObjRender_GetY(target);
|
||||||
|
ObjRender_SetScaleX(lasersprite, min(scaleX+rand(-0.025, 0.025), ObjRender_GetScaleX(lasersprite) + scaleSpeed));
|
||||||
|
ObjRender_SetAlpha(lasersprite, min(alpha, ObjRender_GetAlpha(lasersprite)+alpha/5));
|
||||||
|
ObjRender_SetAngleZ(lasersprite, targetAng);
|
||||||
|
ObjRender_SetPosition(lasersprite, targetx, targety, 1);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ObjRender_SetScaleX(lasersprite, max(0, ObjRender_GetScaleX(lasersprite) - scaleSpeed));
|
||||||
|
ObjRender_SetAlpha(lasersprite, max(0, ObjRender_GetAlpha(lasersprite)-alpha/5));
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _RenderLaser(target, float ang, float maxintersectX, float maxLength, float width, float speedLength, float dmg){ /* */
|
||||||
|
|
||||||
|
int[] EnemyList = [];
|
||||||
|
|
||||||
|
float angRender = asin(maxintersectX/absolute(maxLength));
|
||||||
|
//int laser = CreatePlayerShotA1(ObjRender_GetX(target), ObjRender_GetY(target), 0, ang, dmg, 9999999, 0);
|
||||||
|
int laser = CreateStraightLaserA1(ObjRender_GetX(target), ObjRender_GetY(target), ang-90, maxLength, width, 99999999, 0, 1);
|
||||||
|
ObjLaser_SetInvalidLength(laser, 0, 0);
|
||||||
|
ObjShot_SetDamage(laser, dmg);
|
||||||
|
ObjShot_SetAutoDelete(laser, false);
|
||||||
|
Obj_SetRenderPriorityI(laser, 38);
|
||||||
|
_Follow(laser, target);
|
||||||
|
|
||||||
|
_LaserSpriteRender(
|
||||||
|
teamimg, laser, ang,
|
||||||
|
3072, 0, 3072+256, 256,
|
||||||
|
0.45, 20, 38, 255*(universalAlpha/100),
|
||||||
|
0.14
|
||||||
|
);
|
||||||
|
|
||||||
|
// This also affects damage of the laser, not just effects
|
||||||
|
LaserHitEffect(EnemyList, laser, dmg);
|
||||||
|
|
||||||
|
// When shot key is being held, create a line intersection that stretches across the laser.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Calculations:
|
||||||
|
|
||||||
|
startx: x of target
|
||||||
|
|
||||||
|
starty: y of target
|
||||||
|
|
||||||
|
endx: x of laser
|
||||||
|
|
||||||
|
endy: maxLength
|
||||||
|
|
||||||
|
width = width of laser
|
||||||
|
*/
|
||||||
|
async{
|
||||||
|
|
||||||
|
loop{
|
||||||
|
|
||||||
|
if(GetVirtualKeyState(VK_SHOT) != KEY_FREE && GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE && !ripplayer && IsPermitPlayerShot){
|
||||||
|
|
||||||
|
if(shotspeed % 5 == 0){
|
||||||
|
ObjSound_Play(inferno);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjShot_SetIntersectionEnable(laser, true);
|
||||||
|
|
||||||
|
//ObjShot_SetIntersectionLine(laser, ObjRender_GetX(target), ObjRender_GetY(target), ObjRender_GetX(target)+maxintersectX, -maxLength, width);
|
||||||
|
//WriteLog(ObjMove_GetX(laserfwd));
|
||||||
|
yield;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else{
|
||||||
|
ObjShot_SetIntersectionEnable(laser, false);
|
||||||
|
ObjShot_SetPenetration(laser, 99999999);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// After shot key is released, let the laser leave and then delete it.
|
||||||
|
|
||||||
|
return laser;
|
||||||
|
}
|
||||||
|
|
||||||
|
task LaserHitEffect(int[] EnemyList, int target, float basedmg){
|
||||||
|
|
||||||
|
async{
|
||||||
|
loop{
|
||||||
|
EnemyList = ObjCol_GetListOfIntersectedEnemyID(target);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Particle effects
|
||||||
|
async{
|
||||||
|
loop{
|
||||||
|
ascent(i in -1..length(EnemyList)-1){
|
||||||
|
_CreateLaserParticle(ObjMove_GetX(EnemyList[i])+prand(-30, 30), ObjMove_GetY(EnemyList[i])+prand(-30, 30), [prand(-8, -5), prand(-4, 4), prand(5, 8)][prand_int(0, 2)], [prand(-8, -6), prand(6, 8)][prand_int(0, 1)], rand(0, 360));
|
||||||
|
}
|
||||||
|
//Resort;
|
||||||
|
//WriteLog(EnemyList);
|
||||||
|
wait(rand_int(9, 11));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Damage effects
|
||||||
|
|
||||||
|
}
|
||||||
|
task _Follow(follower, followed){
|
||||||
|
|
||||||
|
while(!Obj_IsDeleted(follower)){
|
||||||
|
float x = ObjRender_GetX(followed);
|
||||||
|
float y = ObjRender_GetY(followed);
|
||||||
|
ObjMove_SetPosition(follower, x, y);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,246 @@
|
||||||
|
|
||||||
|
// Particle list for laser effect
|
||||||
|
|
||||||
|
int LaserEffect = ObjParticleList_Create(OBJ_PARTICLE_LIST_2D);
|
||||||
|
int[] rect = [2816, 0, 2816+256, 0+256];
|
||||||
|
|
||||||
|
ObjPrim_SetTexture(LaserEffect, "script/player/PrideJam_ByakMiko/playerlib/ByakMiko_Sheet.png");
|
||||||
|
|
||||||
|
Obj_SetRenderPriorityI(LaserEffect, 39);
|
||||||
|
ObjPrim_SetPrimitiveType(LaserEffect, PRIMITIVE_TRIANGLELIST);
|
||||||
|
ObjPrim_SetVertexCount(LaserEffect, 4);
|
||||||
|
|
||||||
|
ObjRender_SetBlendType(LaserEffect, BLEND_ALPHA);
|
||||||
|
|
||||||
|
// Left-top, right-top, left-bottom, right-bottom
|
||||||
|
|
||||||
|
ObjPrim_SetVertexUVT(LaserEffect, 0, rect[0], rect[1]);
|
||||||
|
ObjPrim_SetVertexUVT(LaserEffect, 1, rect[2], rect[1]);
|
||||||
|
ObjPrim_SetVertexUVT(LaserEffect, 2, rect[0], rect[3]);
|
||||||
|
ObjPrim_SetVertexUVT(LaserEffect, 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(LaserEffect, 0, -dU, -dV, 1);
|
||||||
|
ObjPrim_SetVertexPosition(LaserEffect, 1, dU, -dV, 1);
|
||||||
|
ObjPrim_SetVertexPosition(LaserEffect, 2, -dU, dV, 1);
|
||||||
|
ObjPrim_SetVertexPosition(LaserEffect, 3, dU, dV, 1);
|
||||||
|
|
||||||
|
ObjPrim_SetVertexIndex(LaserEffect, [0, 1, 2, 1, 2, 3]);
|
||||||
|
|
||||||
|
task _CreateLaserParticle(float x, float y, float spdX, float spdY, float baseAng){
|
||||||
|
|
||||||
|
int effectLength = 45;
|
||||||
|
let x_speed = spdX;
|
||||||
|
let y_speed = spdY;
|
||||||
|
let z_add = rand(-5, 5);
|
||||||
|
|
||||||
|
ascent(i in 0..effectLength){
|
||||||
|
_PetalMovement(Interpolate_Decelerate(0.5, 0.2, i/effectLength), Interpolate_Decelerate(255, 0, i/effectLength));
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
task _PetalMovement(scale, alpha){
|
||||||
|
|
||||||
|
ObjParticleList_SetScale(LaserEffect, scale);
|
||||||
|
ObjParticleList_SetAngleZ(LaserEffect, baseAng);
|
||||||
|
ObjParticleList_SetPosition(LaserEffect, x, y, 1);
|
||||||
|
ObjParticleList_SetAlpha(LaserEffect, alpha);
|
||||||
|
|
||||||
|
//Submits the current data to an instance, cleared every frame.
|
||||||
|
ObjParticleList_AddInstance(LaserEffect);
|
||||||
|
|
||||||
|
x += x_speed;
|
||||||
|
y += y_speed;
|
||||||
|
baseAng += z_add;
|
||||||
|
|
||||||
|
yield;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
task _LaserSpriteRender(
|
||||||
|
img, int target, float targetAng,
|
||||||
|
int rectLeft, int rectTop, int rectRight, int rectBottom,
|
||||||
|
float scaleX, float scaleY, int renderPriority, float alpha,
|
||||||
|
float scaleSpeed
|
||||||
|
){
|
||||||
|
|
||||||
|
int[] EnemyList = [];
|
||||||
|
let lasersprite = ObjPrim_Create(OBJ_SPRITE_2D);
|
||||||
|
|
||||||
|
ObjPrim_SetTexture(lasersprite, img);
|
||||||
|
ObjSprite2D_SetSourceRect(lasersprite, rectLeft, rectTop, rectRight, rectBottom);
|
||||||
|
ObjRender_SetScaleXYZ(lasersprite, 0, scaleY, 1);
|
||||||
|
ObjSprite2D_SetDestRect(lasersprite, -(rectRight-rectLeft)/2, 0, (rectRight-rectLeft)/2, rectTop-rectBottom);
|
||||||
|
Obj_SetRenderPriorityI(lasersprite, renderPriority);
|
||||||
|
ObjRender_SetAlpha(lasersprite, 0);
|
||||||
|
ObjRender_SetBlendType(lasersprite, BLEND_ADD_ARGB);
|
||||||
|
|
||||||
|
async{
|
||||||
|
loop{
|
||||||
|
EnemyList = ObjCol_GetListOfIntersectedEnemyID(target);
|
||||||
|
if(GetVirtualKeyState(VK_SHOT) != KEY_FREE && GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE && !ripplayer && IsPermitPlayerShot){
|
||||||
|
|
||||||
|
// Assumes the intersecting color is right next to the right of the original color
|
||||||
|
|
||||||
|
if (length(EnemyList) > 0) {ObjSprite2D_SetSourceRect(lasersprite, rectRight, rectTop, rectRight+(rectRight-rectLeft), rectBottom);}
|
||||||
|
else{ObjSprite2D_SetSourceRect(lasersprite, rectLeft, rectTop, rectRight, rectBottom);}
|
||||||
|
float targetx = ObjRender_GetX(target);
|
||||||
|
float targety = ObjRender_GetY(target);
|
||||||
|
ObjRender_SetScaleX(lasersprite, min(scaleX+rand(-0.025, 0.025), ObjRender_GetScaleX(lasersprite) + scaleSpeed));
|
||||||
|
ObjRender_SetAlpha(lasersprite, min(alpha, ObjRender_GetAlpha(lasersprite)+alpha/5));
|
||||||
|
ObjRender_SetAngleZ(lasersprite, targetAng);
|
||||||
|
ObjRender_SetPosition(lasersprite, targetx, targety, 1);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ObjRender_SetScaleX(lasersprite, max(0, ObjRender_GetScaleX(lasersprite) - scaleSpeed));
|
||||||
|
ObjRender_SetAlpha(lasersprite, max(0, ObjRender_GetAlpha(lasersprite)-alpha/5));
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _RenderLaser(target, float ang, float maxintersectX, float maxLength, float width, float speedLength, float dmg){ /* */
|
||||||
|
|
||||||
|
int[] EnemyList = [];
|
||||||
|
|
||||||
|
float angRender = asin(maxintersectX/absolute(maxLength));
|
||||||
|
//int laser = CreatePlayerShotA1(ObjRender_GetX(target), ObjRender_GetY(target), 0, ang, dmg, 9999999, 0);
|
||||||
|
int laser = CreateStraightLaserA1(ObjRender_GetX(target), ObjRender_GetY(target), ang-90, maxLength, width, 99999999, 0, 1);
|
||||||
|
ObjLaser_SetInvalidLength(laser, 0, 0);
|
||||||
|
//ObjShot_SetDamage(laser, dmg);
|
||||||
|
ObjShot_SetAutoDelete(laser, false);
|
||||||
|
Obj_SetRenderPriorityI(laser, 38);
|
||||||
|
_Follow(laser, target);
|
||||||
|
|
||||||
|
_LaserSpriteRender(
|
||||||
|
teamimg, laser, ang,
|
||||||
|
3072, 0, 3072+256, 256,
|
||||||
|
0.45, 20, 38, 200,
|
||||||
|
0.14
|
||||||
|
);
|
||||||
|
|
||||||
|
// This also affects damage of the laser, not just effects
|
||||||
|
LaserHitEffect(EnemyList, laser, dmg);
|
||||||
|
|
||||||
|
// When shot key is being held, create a line intersection that stretches across the laser.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Calculations:
|
||||||
|
|
||||||
|
startx: x of target
|
||||||
|
|
||||||
|
starty: y of target
|
||||||
|
|
||||||
|
endx: x of laser
|
||||||
|
|
||||||
|
endy: maxLength
|
||||||
|
|
||||||
|
width = width of laser
|
||||||
|
*/
|
||||||
|
async{
|
||||||
|
|
||||||
|
loop{
|
||||||
|
|
||||||
|
if(GetVirtualKeyState(VK_SHOT) != KEY_FREE && GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE && !ripplayer && IsPermitPlayerShot){
|
||||||
|
|
||||||
|
if(shotspeed % 5 == 0){
|
||||||
|
ObjSound_Play(inferno);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjShot_SetIntersectionEnable(laser, true);
|
||||||
|
|
||||||
|
//ObjShot_SetIntersectionLine(laser, ObjRender_GetX(target), ObjRender_GetY(target), ObjRender_GetX(target)+maxintersectX, -maxLength, width);
|
||||||
|
//WriteLog(ObjMove_GetX(laserfwd));
|
||||||
|
yield;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else{
|
||||||
|
ObjShot_SetIntersectionEnable(laser, false);
|
||||||
|
ObjShot_SetPenetration(laser, 99999999);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// After shot key is released, let the laser leave and then delete it.
|
||||||
|
|
||||||
|
return laser;
|
||||||
|
}
|
||||||
|
|
||||||
|
task LaserHitEffect(int[] EnemyList, int target, float basedmg){
|
||||||
|
|
||||||
|
int[] ResortList = [];
|
||||||
|
|
||||||
|
// Debugging: gets distance from player to the laser, appends it into an array
|
||||||
|
|
||||||
|
task Resort(){
|
||||||
|
for each(int enm in EnemyList){
|
||||||
|
ResortList = append(ResortList, GetObjectDistance(enm, target));
|
||||||
|
}
|
||||||
|
WriteLog(ResortList);
|
||||||
|
ResortList = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async{
|
||||||
|
loop{
|
||||||
|
EnemyList = ObjCol_GetListOfIntersectedEnemyID(target);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async{
|
||||||
|
loop{
|
||||||
|
Resort();
|
||||||
|
wait(60);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Particle effects
|
||||||
|
async{
|
||||||
|
loop{
|
||||||
|
ascent(i in -1..length(EnemyList)-1){
|
||||||
|
_CreateLaserParticle(ObjMove_GetX(EnemyList[i])+prand(-30, 30), ObjMove_GetY(EnemyList[i])+prand(-30, 30), [prand(-8, -5), prand(-4, 4), prand(5, 8)][prand_int(0, 2)], [prand(-8, -6), prand(6, 8)][prand_int(0, 1)], rand(0, 360));
|
||||||
|
}
|
||||||
|
//Resort;
|
||||||
|
//WriteLog(EnemyList);
|
||||||
|
wait(rand_int(9, 11));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Damage effects
|
||||||
|
async{
|
||||||
|
loop{
|
||||||
|
ascent(i in -1..length(EnemyList)-1){
|
||||||
|
float dmgCalc = max(1, basedmg - (basedmg * 0.2 * i));
|
||||||
|
ObjEnemy_SetLife(EnemyList[i], ObjEnemy_GetInfo(EnemyList[i], INFO_LIFE) - dmgCalc);
|
||||||
|
}
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
task _Follow(follower, followed){
|
||||||
|
|
||||||
|
while(!Obj_IsDeleted(follower)){
|
||||||
|
float x = ObjRender_GetX(followed);
|
||||||
|
float y = ObjRender_GetY(followed);
|
||||||
|
ObjMove_SetPosition(follower, x, y);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,575 @@
|
||||||
|
#TouhouDanmakufu[Player]
|
||||||
|
#ScriptVersion[3]
|
||||||
|
#ID["ByakMiko"]
|
||||||
|
#Title["Byakuren Hijiri & Toyosatomimi no Miko"]
|
||||||
|
#Text["Unfocused Shot: Indra's Sorcery Buzzsaws[r]An elegant spread of thunder needles.[r][r]Focused Shot: Four Shining Articles[r]A crossing of high-power divine lasers.[r][r]Special Ability: Smaller hitbox."]
|
||||||
|
|
||||||
|
//#Image["./marimiko_lib/marimiko_illust.png"]
|
||||||
|
|
||||||
|
#ReplayName["ByakMiko"]
|
||||||
|
|
||||||
|
#include "script/KevinSystem/Kevin_PlayerLib.txt"
|
||||||
|
#include "script/KevinSystem/PlayerSoundLib.dnh"
|
||||||
|
|
||||||
|
#include "./ByakMiko_Function.dnh"
|
||||||
|
#include "./ByakMiko_ShotConst.dnh"
|
||||||
|
|
||||||
|
#include "script/KevinSystem/kevin_system/Kevin_ItemConst.txt"
|
||||||
|
#include "script/KevinSystem/kevin_system/Kevin_ItemLib.txt"
|
||||||
|
|
||||||
|
let csd = GetCurrentScriptDirectory();
|
||||||
|
|
||||||
|
// Global Variables
|
||||||
|
|
||||||
|
float maxX = GetStgFrameWidth();
|
||||||
|
float maxY = GetStgFrameHeight();
|
||||||
|
|
||||||
|
// Images & Sound
|
||||||
|
|
||||||
|
let teamimg = csd ~ "./playerlib/ByakMiko_Sheet.png";
|
||||||
|
LoadTextureEx(teamimg, true, true);
|
||||||
|
//ObjRender_SetTextureFilterMip(teamimg, FILTER_LINEAR);
|
||||||
|
|
||||||
|
let sndpath = csd ~ "./sound";
|
||||||
|
|
||||||
|
// Other stuff
|
||||||
|
|
||||||
|
float playerX = 0;
|
||||||
|
float playerY = 0;
|
||||||
|
|
||||||
|
let objPlayer = GetPlayerObjectID();
|
||||||
|
int plrender = Obj_GetRenderPriorityI(objPlayer);
|
||||||
|
|
||||||
|
int frameidlebyak = 0;
|
||||||
|
int frameidlemiko = 0;
|
||||||
|
int framemovebyak = 0;
|
||||||
|
int framemovemiko = 0;
|
||||||
|
|
||||||
|
bool ripplayer = false;
|
||||||
|
float shotspeed = 0;
|
||||||
|
float bombrand = 0;
|
||||||
|
|
||||||
|
bool bombenable = false;
|
||||||
|
bool focusactive = false;
|
||||||
|
bool ishoming = false;
|
||||||
|
|
||||||
|
int[] _enemyArray = []; // Prepare an array to store enemy IDs for Kouda's homing shot
|
||||||
|
int[] _existArray = [];
|
||||||
|
int[] _shotArray = [];
|
||||||
|
|
||||||
|
int grazecounter = 0; // For basic graze = PIV mechanic
|
||||||
|
|
||||||
|
float[] PlayerSpd = [11.5, 5.8];
|
||||||
|
|
||||||
|
// Custom events for scoring mechanic
|
||||||
|
|
||||||
|
const EV_PIV_100 = EV_USER + 100i; // Normal enemies and nons
|
||||||
|
const EV_PIV_250 = EV_USER + 101i; // Spells
|
||||||
|
const EV_PIV_500 = EV_USER + 102i; // Last Spells
|
||||||
|
const EV_PIV_2000 = EV_USER + 103i; // What.
|
||||||
|
|
||||||
|
@Initialize{
|
||||||
|
|
||||||
|
if(!IsCommonDataAreaExists("PIV")){
|
||||||
|
CreateCommonDataArea("PIV");
|
||||||
|
SetAreaCommonData("PIV", "currentvalue", 10000);
|
||||||
|
}
|
||||||
|
else{}
|
||||||
|
|
||||||
|
SetPlayerStateEndEnable(true);
|
||||||
|
|
||||||
|
// Stuff
|
||||||
|
parameterrender();
|
||||||
|
playerrender();
|
||||||
|
Obj_SetRenderPriorityI(objPlayer, 43);
|
||||||
|
plrender = Obj_GetRenderPriorityI(objPlayer);
|
||||||
|
_SoundTask();
|
||||||
|
|
||||||
|
//SetIntersectionVisualization(true); // Debug
|
||||||
|
|
||||||
|
_Mechanic(ripplayer, _enemyArray, _existArray, GetStgFrameWidth(), GetStgFrameHeight(), objPlayer, GetEnemyBossSceneObjectID(), 5, 2, 80);
|
||||||
|
|
||||||
|
_HitboxRender(ripplayer, objPlayer, teamimg, teamimg, 2560, 512, 2688, 640, 2816, 1024, 2816+511, 1024+511, 0.22, 0.65);
|
||||||
|
SetShotAutoDeleteClip(256, 256, 256, 256);
|
||||||
|
|
||||||
|
// Shot functions
|
||||||
|
|
||||||
|
//_CAVELaser();
|
||||||
|
ByakShot();
|
||||||
|
_MikoOption();
|
||||||
|
|
||||||
|
// Shot data loading
|
||||||
|
LoadPlayerShotData(csd ~ "./ByakMiko_ShotData.dnh");
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainLoop{
|
||||||
|
shotspeed += 1; // Managing the shot rate
|
||||||
|
//_shotArray = GetAllShotID(TARGET_PLAYER);
|
||||||
|
//UniversalAlphaHandle(_shotArray);
|
||||||
|
playerX = ObjMove_GetX(objPlayer);
|
||||||
|
playerY = ObjMove_GetY(objPlayer);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Event{
|
||||||
|
alternative(GetEventType)
|
||||||
|
|
||||||
|
// Delete effect
|
||||||
|
case(EV_DELETE_SHOT_PLAYER){
|
||||||
|
let graphic = GetEventArgument(2);
|
||||||
|
float[] position = GetEventArgument(1);
|
||||||
|
let obj = CreatePlayerShotA1(position[0], position[1], 0, ObjMove_GetAngle(GetEventArgument(0)), 0, 99999, graphic);
|
||||||
|
ObjShot_SetIntersectionEnable(obj, false);
|
||||||
|
_DeleteEffect(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PIV-item spawning events
|
||||||
|
case(EV_PIV_100){
|
||||||
|
let arg = GetEventArgument(0);
|
||||||
|
CreatePIVItem(PIV_100, arg[0], arg[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_PIV_250){
|
||||||
|
let arg = GetEventArgument(0);
|
||||||
|
CreatePIVItem(PIV_250, arg[0], arg[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_PIV_500){
|
||||||
|
let arg = GetEventArgument(0);
|
||||||
|
CreatePIVItem(PIV_500, arg[0], arg[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic functionality events
|
||||||
|
case(EV_REQUEST_SPELL){
|
||||||
|
let bomb = GetPlayerSpell();
|
||||||
|
|
||||||
|
if (bomb >= 1){
|
||||||
|
SetScriptResult(true);
|
||||||
|
SetPlayerSpell(bomb - 1);
|
||||||
|
if(GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){_FocusBomb(); _SigilCall(false, teamimg, 2816+256, 512, 2816+512, 768, objPlayer, GetPlayerInvincibilityFrame());}
|
||||||
|
else{_UnfocusBomb();
|
||||||
|
_SigilCall(false, teamimg, 2816+256, 512, 2816+512, 768, objPlayer, GetPlayerInvincibilityFrame());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
SetScriptResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_HIT){
|
||||||
|
ObjSound_Play(predeathsfx);
|
||||||
|
_DeathbombWarning(teamimg, [1792, 512, 1792+512, 512+512], 15, 0.75);
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_PLAYER_SHOOTDOWN){
|
||||||
|
ObjSound_Play(deathsfx);
|
||||||
|
ripplayer = true;
|
||||||
|
_SigilCall(true, teamimg, 2816, 512, 2816+256, 768, objPlayer, 120);
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_PLAYER_REBIRTH){
|
||||||
|
ripplayer = false;
|
||||||
|
SetPlayerInvincibilityFrame(180);
|
||||||
|
_SigilCall(false, teamimg, 2816+256, 512, 2816+512, 768, objPlayer, 150);
|
||||||
|
SetPlayerSpell( max(2,GetPlayerSpell()) );
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_GRAZE){
|
||||||
|
grazecounter += GetEventArgument(0);
|
||||||
|
ObjSound_Play(grazesfx);
|
||||||
|
while(grazecounter >= 10){
|
||||||
|
SetAreaCommonData("PIV", "currentvalue", GetAreaCommonData("PIV", "currentvalue")+10);
|
||||||
|
grazecounter -= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Finalize{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
task _MikoOption(){
|
||||||
|
|
||||||
|
// Offsets for 4 front options
|
||||||
|
|
||||||
|
float offsetX1 = 90;
|
||||||
|
float offsetX2 = offsetX1 * 2;
|
||||||
|
float offsetY1 = 45;
|
||||||
|
|
||||||
|
// Array that contains static/unchanging values for the PlayerOption
|
||||||
|
|
||||||
|
let val = [1792, 256, 2048, 512, 0.65, 256, 1, 1, false, false, 0, true, false];
|
||||||
|
|
||||||
|
// Option handling (right -> rightmost -> left -> leftmost)
|
||||||
|
|
||||||
|
float[][] offsetArray = [[offsetX1, offsetY1], [offsetX2, 0], [-offsetX1, offsetY1], [-offsetX2, 0]];
|
||||||
|
|
||||||
|
int opt1 = PlayerOption(
|
||||||
|
offsetArray[0][0], offsetArray[0][1],
|
||||||
|
teamimg,
|
||||||
|
val[0], val[1], val[2], val[3], val[4],
|
||||||
|
val[5], val[6], val[7], val[8],
|
||||||
|
val[9], val[10],
|
||||||
|
val[11], val[12]);
|
||||||
|
|
||||||
|
int opt2 = PlayerOption(
|
||||||
|
offsetArray[1][0], offsetArray[1][1],
|
||||||
|
teamimg,
|
||||||
|
val[0], val[1], val[2], val[3], val[4],
|
||||||
|
val[5], val[6], val[7], val[8],
|
||||||
|
val[9], val[10],
|
||||||
|
val[11], val[12]);
|
||||||
|
|
||||||
|
int opt3 = PlayerOption(
|
||||||
|
offsetArray[2][0], offsetArray[2][1],
|
||||||
|
teamimg,
|
||||||
|
val[0], val[1], val[2], val[3], val[4],
|
||||||
|
val[5], val[6], val[7], val[8],
|
||||||
|
val[9], val[10],
|
||||||
|
val[11], val[12]);
|
||||||
|
|
||||||
|
int opt4 = PlayerOption(
|
||||||
|
offsetArray[3][0], offsetArray[3][1],
|
||||||
|
teamimg,
|
||||||
|
val[0], val[1], val[2], val[3], val[4],
|
||||||
|
val[5], val[6], val[7], val[8],
|
||||||
|
val[9], val[10],
|
||||||
|
val[11], val[12]);
|
||||||
|
|
||||||
|
int[] optArray = [opt1, opt2, opt3, opt4];
|
||||||
|
|
||||||
|
ascent(i in -1..length(optArray)-1){
|
||||||
|
_SwingBehaviour(optArray[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
task _SwingBehaviour(target){
|
||||||
|
float ang = 0;
|
||||||
|
Obj_SetRenderPriorityI(target, 42);
|
||||||
|
while(true){
|
||||||
|
ObjRender_SetAngleZ(target, 0+20*sin(ang));
|
||||||
|
ang += 360/120;
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int laser1 = _RenderLaser(opt1, -7, 300, GetStgFrameHeight*1.25, 65, 0, 2.6);
|
||||||
|
int laser2 = _RenderLaser(opt2, -14, 600, GetStgFrameHeight*1.25, 65, 0, 2.6);
|
||||||
|
int laser3 = _RenderLaser(opt3, 7, 300, GetStgFrameHeight*1.25, 65, 0, 2.6);
|
||||||
|
int laser4 = _RenderLaser(opt4, 14, 600, GetStgFrameHeight*1.25, 65, 0, 2.6);
|
||||||
|
|
||||||
|
//int laser3 = _RenderLaser(opt3, 0, 300, GetStgFrameHeight*1.25, 50, 0, 5);
|
||||||
|
|
||||||
|
float focusDist = 280;
|
||||||
|
let dummy = CreatePlayerShotA1(playerX, playerY-focusDist, 0, 0, 0, 99999, 0);
|
||||||
|
|
||||||
|
ObjShot_SetAutoDelete(dummy, false);
|
||||||
|
ObjShot_SetIntersectionEnable(dummy, false);
|
||||||
|
|
||||||
|
//ObjMove_AddPatternA4(laser1, 0, NO_CHANGE, 0, NO_CHANGE, NO_CHANGE, NO_CHANGE, NO_CHANGE, dummy);
|
||||||
|
//ObjMove_AddPatternA4(laser2, 0, NO_CHANGE, 0, NO_CHANGE, NO_CHANGE, NO_CHANGE, NO_CHANGE, dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Miko's lasers
|
||||||
|
|
||||||
|
// Basic player parameters
|
||||||
|
|
||||||
|
task parameterrender(){
|
||||||
|
|
||||||
|
SetPlayerItemScope(120);
|
||||||
|
SetPlayerLife(9); // Debug
|
||||||
|
SetPlayerSpell(2);
|
||||||
|
SetPlayerSpeed(PlayerSpd[0], PlayerSpd[1]); // (original: 5.25/2.0)
|
||||||
|
SetPlayerRebirthFrame(25);
|
||||||
|
SetPlayerAutoItemCollectLine(GetStgFrameHeight/3);
|
||||||
|
SetPlayerRebirthLossFrame(0);
|
||||||
|
ObjPlayer_AddIntersectionCircleA1(objPlayer, 0, 0, 2.0, 55);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renders the shottype
|
||||||
|
// Player sprites
|
||||||
|
|
||||||
|
task playerrender(){
|
||||||
|
|
||||||
|
// Why is this movement code so cursed jesus fucking christ
|
||||||
|
|
||||||
|
float scale = 0.34; // Scalies
|
||||||
|
|
||||||
|
ObjPrim_SetTexture(objPlayer, teamimg);
|
||||||
|
ObjSprite2D_SetSourceRect(objPlayer, 0, 0, 320, 384);
|
||||||
|
ObjSprite2D_SetDestCenter(objPlayer);
|
||||||
|
Obj_SetRenderPriorityI(objPlayer, 42);
|
||||||
|
ObjRender_SetScaleXYZ(objPlayer, scale, scale, 1);
|
||||||
|
|
||||||
|
// Lower "speed" parameter = FASTER SPEED
|
||||||
|
|
||||||
|
// FOR WHEN ONLY IDLE SPRITES ARE DONE
|
||||||
|
|
||||||
|
loop{
|
||||||
|
// Focused
|
||||||
|
if(GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){
|
||||||
|
frameidlemiko++;
|
||||||
|
_RenderPlayerMovement(objPlayer, frameidlemiko, 0, 1152, 320, 384, scale, 4, 5);
|
||||||
|
if (frameidlemiko >= (5*4-1)){frameidlemiko = 0;}
|
||||||
|
}
|
||||||
|
// Unfocused
|
||||||
|
else{
|
||||||
|
frameidlebyak++;
|
||||||
|
_RenderPlayerMovement(objPlayer, frameidlebyak, 0, 0, 320, 384, scale, 5, 5);
|
||||||
|
if (frameidlebyak >= (5*5-1)){frameidlebyak = 0;}
|
||||||
|
}
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
task ByakShot(){
|
||||||
|
|
||||||
|
// Offsets for 4 front options
|
||||||
|
|
||||||
|
float offsetX1 = 75;
|
||||||
|
float offsetX2 = offsetX1 * 2;
|
||||||
|
float offsetY1 = -75;
|
||||||
|
|
||||||
|
// Array that contains static/unchanging values for the PlayerOption
|
||||||
|
|
||||||
|
let valL = [2048, 256, 2048+256, 512, 0.32, 256, 1, 1, false, true, 6, false, true];
|
||||||
|
let valR = [2048, 256, 2048+256, 512, 0.32, 256, 1, 1, false, true, -6, false, true];
|
||||||
|
|
||||||
|
// Option handling
|
||||||
|
|
||||||
|
float[][] offsetArray = [[offsetX1, offsetY1], [offsetX2, 0], [-offsetX1, offsetY1], [-offsetX2, 0]];
|
||||||
|
|
||||||
|
int opt1 = PlayerOption(
|
||||||
|
offsetArray[0][0], offsetArray[0][1],
|
||||||
|
teamimg,
|
||||||
|
valR[0], valR[1], valR[2], valR[3], valR[4],
|
||||||
|
valR[5], valR[6], valR[7], valR[8],
|
||||||
|
valR[9], valR[10],
|
||||||
|
valR[11], valR[12]);
|
||||||
|
|
||||||
|
int opt2 = PlayerOption(
|
||||||
|
offsetArray[1][0], offsetArray[1][1],
|
||||||
|
teamimg,
|
||||||
|
valR[0], valR[1], valR[2], valR[3], valR[4],
|
||||||
|
valR[5], valR[6], valR[7], valR[8],
|
||||||
|
valR[9], valR[10],
|
||||||
|
valR[11], valR[12]);
|
||||||
|
|
||||||
|
int opt3 = PlayerOption(
|
||||||
|
offsetArray[2][0], offsetArray[2][1],
|
||||||
|
teamimg,
|
||||||
|
valL[0], valL[1], valL[2], valL[3], valL[4],
|
||||||
|
valL[5], valL[6], valL[7], valL[8],
|
||||||
|
valL[9], valL[10],
|
||||||
|
valL[11], valL[12]);
|
||||||
|
|
||||||
|
int opt4 = PlayerOption(
|
||||||
|
offsetArray[3][0], offsetArray[3][1],
|
||||||
|
teamimg,
|
||||||
|
valL[0], valL[1], valL[2], valL[3], valL[4],
|
||||||
|
valL[5], valL[6], valL[7], valL[8],
|
||||||
|
valL[9], valL[10],
|
||||||
|
valL[11], valL[12]);
|
||||||
|
|
||||||
|
int[] optArray = [opt1, opt2, opt3, opt4];
|
||||||
|
|
||||||
|
ObjRender_SetAngleX(opt1, (-1)*valR[4]);
|
||||||
|
ObjRender_SetAngleX(opt2, (-1)*valR[4]);
|
||||||
|
|
||||||
|
ascent(i in -1..length(optArray)-1){
|
||||||
|
_ThunderNeedle(optArray[i], 270, 7.5, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ThunderNeedle(optArray[1], 135, 7.5, 2);
|
||||||
|
_ThunderNeedle(optArray[3], 45, 7.5, 2);
|
||||||
|
|
||||||
|
//_ThunderNeedle(opt1, 270, 12, 2);
|
||||||
|
//_ThunderNeedle(opt2, 250, 5, 2);
|
||||||
|
//_ThunderNeedle(opt4, 290, 5, 2);
|
||||||
|
//_ThunderNeedle(opt3, 270, 12, 2);
|
||||||
|
|
||||||
|
// Byakuren's shot
|
||||||
|
|
||||||
|
task _ThunderNeedle(int target, float baseang, float tiltang, int num){
|
||||||
|
|
||||||
|
//float baseang = 270;
|
||||||
|
|
||||||
|
int a = 0;
|
||||||
|
|
||||||
|
loop{
|
||||||
|
if(IsPermitPlayerShot && !ripplayer && GetVirtualKeyState(VK_SHOT) != KEY_FREE && GetVirtualKeyState(VK_SLOWMOVE) == KEY_FREE){
|
||||||
|
if(shotspeed % 5 == 0){
|
||||||
|
ascent(i in 0..num){
|
||||||
|
float shot = CreatePlayerShotA1(ObjRender_GetX(target), ObjRender_GetY(target), 44, baseang-tiltang+a*tiltang*2, 4.1, 1.8, BYAKUREN_NEEDLE);
|
||||||
|
ObjRender_SetAlpha(shot, 255*(universalAlpha/100));
|
||||||
|
_BulletRescalePlayer(shot, 0.7, true, 0.7);
|
||||||
|
//Fadein(shot);
|
||||||
|
a++;
|
||||||
|
if (a == num){a = 0;}
|
||||||
|
}
|
||||||
|
ObjSound_Play(basesfx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
task Fadein(target){
|
||||||
|
ascent(i in 0..5){
|
||||||
|
//ObjRender_SetAlpha(target, Interpolate_Decelerate(180, 255, i/5));
|
||||||
|
_BulletRescalePlayer(target, Interpolate_Decelerate(0.4, 0.7, i/5), true, Interpolate_Decelerate(0.4, 0.7,i/5));
|
||||||
|
//ObjRender_SetBlendType(target, BLEND_ADD_ARGB);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
ObjRender_SetBlendType(target, BLEND_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handling of bomb
|
||||||
|
task Fadein(target, len, targetscale, targetscalehitbox){
|
||||||
|
ascent(i in 0..len){
|
||||||
|
//ObjRender_SetAlpha(target, Interpolate_Decelerate(180, 255, i/len));
|
||||||
|
_BulletRescalePlayer(target, Interpolate_Decelerate(0.4, targetscale, i/len), true, Interpolate_Decelerate(1, targetscalehitbox, i/len));
|
||||||
|
//ObjRender_SetBlendType(target, BLEND_ADD_ARGB);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
ObjRender_SetBlendType(target, BLEND_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
|
task _FocusBomb(){
|
||||||
|
|
||||||
|
// Preparation
|
||||||
|
SetForbidPlayerShot(true);
|
||||||
|
SetForbidPlayerSpell(true);
|
||||||
|
SetPlayerInvincibilityFrame(32*3+32*3+42*3+120+45);
|
||||||
|
// Spell object
|
||||||
|
let manageObj = GetSpellManageObject(); // SPELL BEGINS
|
||||||
|
ObjSpell_Regist(manageObj);
|
||||||
|
ObjSound_Play(bombsfx);
|
||||||
|
SetPlayerSpeed(5, 5);
|
||||||
|
|
||||||
|
float angvel = 0.75;
|
||||||
|
float revolve = 2;
|
||||||
|
float spd = 21;
|
||||||
|
float dmg = 2;
|
||||||
|
float revolvechange = 12;
|
||||||
|
|
||||||
|
ascent(i in 0..16){
|
||||||
|
|
||||||
|
float angBase = rand(0, 360);
|
||||||
|
|
||||||
|
alternative(revolve)
|
||||||
|
case(2){revolve = -2;}
|
||||||
|
case(-2){revolve = 2;}
|
||||||
|
|
||||||
|
ascent(i in 0..12){
|
||||||
|
float ang = angBase + 360/12 * i;
|
||||||
|
int shot = CreateShotA2(playerX, playerY, 24, ang, 0, 24, revolve, 3, 0);
|
||||||
|
Fadein(shot, 10, 1.5, 1.5);
|
||||||
|
ObjRender_SetBlendType(shot, BLEND_ADD_ARGB);
|
||||||
|
ObjShot_SetIntersectionEnable(shot, true);
|
||||||
|
ObjShot_SetPenetration(shot, 9999);
|
||||||
|
ObjShot_SetDamage(shot, 2.5);
|
||||||
|
ObjShot_SetEraseShot(shot, true);
|
||||||
|
ObjShot_SetSpellFactor(shot, true);
|
||||||
|
ObjMove_AddPatternA2(shot, 90, NO_CHANGE, NO_CHANGE, 1, 40, 0);
|
||||||
|
//ObjShot_SetDeleteFrame(shot, 120);
|
||||||
|
ObjSound_Play(inferno);
|
||||||
|
}
|
||||||
|
|
||||||
|
ascent(i in 0..12){
|
||||||
|
float ang = angBase + 360/12 * i;
|
||||||
|
int shot = CreateShotA2(playerX, playerY, 24, ang, 0, 24, -revolve, 3, 0);
|
||||||
|
Fadein(shot, 10, 1.5, 1.5);
|
||||||
|
ObjRender_SetBlendType(shot, BLEND_ADD_ARGB);
|
||||||
|
ObjShot_SetIntersectionEnable(shot, true);
|
||||||
|
ObjShot_SetPenetration(shot, 9999);
|
||||||
|
ObjShot_SetDamage(shot, 2.5);
|
||||||
|
ObjShot_SetEraseShot(shot, true);
|
||||||
|
ObjShot_SetSpellFactor(shot, true);
|
||||||
|
ObjMove_AddPatternA2(shot, 90, NO_CHANGE, NO_CHANGE, 1, 40, 0);
|
||||||
|
//ObjShot_SetDeleteFrame(shot, 120);
|
||||||
|
ObjSound_Play(inferno);
|
||||||
|
}
|
||||||
|
|
||||||
|
wait(15);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup, end of spell
|
||||||
|
SetPlayerSpeed(PlayerSpd[0], PlayerSpd[1]);
|
||||||
|
SetForbidPlayerShot(false);
|
||||||
|
wait(60);
|
||||||
|
SetForbidPlayerSpell(false);
|
||||||
|
Obj_Delete(manageObj); // !!! IMPORTANT !!!
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
task _UnfocusBomb(){
|
||||||
|
|
||||||
|
// Preparation
|
||||||
|
SetForbidPlayerShot(true);
|
||||||
|
SetForbidPlayerSpell(true);
|
||||||
|
SetPlayerInvincibilityFrame(32*3+32*3+42*3+120+45);
|
||||||
|
// Spell object
|
||||||
|
let manageObj = GetSpellManageObject(); // SPELL BEGINS
|
||||||
|
ObjSpell_Regist(manageObj);
|
||||||
|
ObjSound_Play(bombsfx);
|
||||||
|
SetPlayerSpeed(10, 10);
|
||||||
|
|
||||||
|
float angvel = 0.75;
|
||||||
|
float revolve = 0;
|
||||||
|
float spd = 21;
|
||||||
|
float dmg = 2;
|
||||||
|
float revolvechange = 12;
|
||||||
|
|
||||||
|
ascent(i in 0..100){
|
||||||
|
int shot = CreateShotA1(rand(0, GetStgFrameWidth()), -125, 36, 90, 2, 0);
|
||||||
|
|
||||||
|
Fadein(shot, 18, 1.4, 1.4);
|
||||||
|
ObjRender_SetBlendType(shot, BLEND_ADD_ARGB);
|
||||||
|
ObjShot_SetSpinAngularVelocity(shot, 5);
|
||||||
|
ObjShot_SetIntersectionEnable(shot, true);
|
||||||
|
ObjShot_SetPenetration(shot, 9999);
|
||||||
|
ObjShot_SetDamage(shot, 3.5);
|
||||||
|
ObjShot_SetEraseShot(shot, true);
|
||||||
|
ObjShot_SetSpellFactor(shot, true);
|
||||||
|
ObjSound_Play(inferno);
|
||||||
|
|
||||||
|
wait(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup, end of spell
|
||||||
|
SetPlayerSpeed(PlayerSpd[0], PlayerSpd[1]);
|
||||||
|
SetForbidPlayerShot(false);
|
||||||
|
wait(60);
|
||||||
|
SetForbidPlayerSpell(false);
|
||||||
|
Obj_Delete(manageObj); // !!! IMPORTANT !!!
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Screenshake function for bomb's duration - adapted from Sparen's tutorials
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
let current = GetCurrentScriptDirectory();
|
||||||
|
let path = current ~ "ByakMiko_ShotData.dnh";
|
||||||
|
LoadPlayerShotData(path);
|
||||||
|
// -----
|
||||||
|
|
||||||
|
const BYAKUREN_NEEDLE = 1;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
shot_image = "./playerlib/ByakMiko_Sheet.png"
|
||||||
|
|
||||||
|
ShotData{
|
||||||
|
id = 0 // Dummy
|
||||||
|
rect = (0,0,0,0)
|
||||||
|
render = ALPHA
|
||||||
|
alpha = 0
|
||||||
|
collision = 32
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Arrow (Option)
|
||||||
|
|
||||||
|
ShotData{
|
||||||
|
id = 1
|
||||||
|
rect = (2048, 0, 2304, 256)
|
||||||
|
render = ALPHA
|
||||||
|
alpha = 255
|
||||||
|
collision = (75, 0, 0) // Hitbox of arrows is not centered on the sprite
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bomb
|
||||||
|
|
||||||
|
ShotData{
|
||||||
|
id = 2
|
||||||
|
rect = (2560, 0, 2816, 256)
|
||||||
|
render = ADD_ARGB
|
||||||
|
alpha = 255
|
||||||
|
collision = 80 // Hitbox of arrows is not centered on the sprite
|
||||||
|
}
|
||||||
|
|
||||||
|
ShotData{
|
||||||
|
id = 3
|
||||||
|
rect = (2816, 0, 3072, 256)
|
||||||
|
render = ADD_ARGB
|
||||||
|
alpha = 255
|
||||||
|
collision = 80 // Hitbox of arrows is not centered on the sprite
|
||||||
|
}
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 1.3 MiB |
|
@ -0,0 +1 @@
|
||||||
|
2,0.57,,0.3442,,0.2691,0.3,0.2179,,0.3445,,,,,,,,,,,0.2992,,0.5139,,,1,,,,,,,masterVolume
|
|
@ -0,0 +1,115 @@
|
||||||
|
|
||||||
|
task _LaserSpriteRender(
|
||||||
|
img, int target, float targetAng,
|
||||||
|
int rectLeft, int rectTop, int rectRight, int rectBottom,
|
||||||
|
float scaleX, float scaleY, int renderPriority, float alpha,
|
||||||
|
float scaleSpeed
|
||||||
|
){
|
||||||
|
|
||||||
|
let lasersprite = ObjPrim_Create(OBJ_SPRITE_2D);
|
||||||
|
|
||||||
|
ObjPrim_SetTexture(lasersprite, img);
|
||||||
|
ObjSprite2D_SetSourceRect(lasersprite, rectLeft, rectTop, rectRight, rectBottom);
|
||||||
|
ObjRender_SetScaleXYZ(lasersprite, 0, scaleY, 1);
|
||||||
|
ObjSprite2D_SetDestRect(lasersprite, -(rectRight-rectLeft)/2, 0, (rectRight-rectLeft)/2, rectTop-rectBottom);
|
||||||
|
Obj_SetRenderPriorityI(lasersprite, renderPriority);
|
||||||
|
ObjRender_SetAlpha(lasersprite, 0);
|
||||||
|
ObjRender_SetBlendType(lasersprite, BLEND_ADD_ARGB);
|
||||||
|
|
||||||
|
async{
|
||||||
|
loop{
|
||||||
|
int[] EnemyList = ObjCol_GetListOfIntersectedEnemyID(target);
|
||||||
|
if(GetVirtualKeyState(VK_SHOT) != KEY_FREE && GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE && !ripplayer && IsPermitPlayerShot){
|
||||||
|
|
||||||
|
// Assumes the intersecting color is right next to the right of the original color
|
||||||
|
|
||||||
|
if (length(EnemyList) > 0) {ObjSprite2D_SetSourceRect(lasersprite, rectRight, rectTop, rectRight+(rectRight-rectLeft), rectBottom);}
|
||||||
|
else{ObjSprite2D_SetSourceRect(lasersprite, rectLeft, rectTop, rectRight, rectBottom);}
|
||||||
|
float targetx = ObjRender_GetX(target);
|
||||||
|
float targety = ObjRender_GetY(target);
|
||||||
|
ObjRender_SetScaleX(lasersprite, min(scaleX+rand(-0.025, 0.025), ObjRender_GetScaleX(lasersprite) + scaleSpeed));
|
||||||
|
ObjRender_SetAlpha(lasersprite, min(alpha, ObjRender_GetAlpha(lasersprite)+alpha/5));
|
||||||
|
ObjRender_SetAngleZ(lasersprite, targetAng);
|
||||||
|
ObjRender_SetPosition(lasersprite, targetx, targety, 1);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ObjRender_SetScaleX(lasersprite, max(0, ObjRender_GetScaleX(lasersprite) - scaleSpeed));
|
||||||
|
ObjRender_SetAlpha(lasersprite, max(0, ObjRender_GetAlpha(lasersprite)-alpha/5));
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _RenderLaser(target, float ang, float maxintersectX, float maxLength, float width, float speedLength, float dmg){ /* */
|
||||||
|
|
||||||
|
float angRender = asin(maxintersectX/absolute(maxLength));
|
||||||
|
//int laser = CreatePlayerShotA1(ObjRender_GetX(target), ObjRender_GetY(target), 0, ang, dmg, 9999999, 0);
|
||||||
|
int laser = CreateStraightLaserA1(ObjRender_GetX(target), ObjRender_GetY(target), ang-90, maxLength, width, 9999999, 0, 1);
|
||||||
|
ObjLaser_SetInvalidLength(laser, 0, 0);
|
||||||
|
ObjShot_SetDamage(laser, dmg);
|
||||||
|
ObjShot_SetAutoDelete(laser, false);
|
||||||
|
Obj_SetRenderPriorityI(laser, 38);
|
||||||
|
_Follow(laser, target);
|
||||||
|
|
||||||
|
_LaserSpriteRender(
|
||||||
|
teamimg, laser, ang,
|
||||||
|
3072, 0, 3072+256, 256,
|
||||||
|
0.45, 20, 38, 240,
|
||||||
|
0.14
|
||||||
|
);
|
||||||
|
|
||||||
|
// When shot key is being held, create a line intersection that stretches across the laser.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Calculations:
|
||||||
|
|
||||||
|
startx: x of target
|
||||||
|
|
||||||
|
starty: y of target
|
||||||
|
|
||||||
|
endx: x of laser
|
||||||
|
|
||||||
|
endy: maxLength
|
||||||
|
|
||||||
|
width = width of laser
|
||||||
|
*/
|
||||||
|
async{
|
||||||
|
|
||||||
|
loop{
|
||||||
|
|
||||||
|
if(GetVirtualKeyState(VK_SHOT) != KEY_FREE && GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE && !ripplayer && IsPermitPlayerShot){
|
||||||
|
|
||||||
|
if(shotspeed % 5 == 0){ObjSound_Play(inferno);}
|
||||||
|
ObjShot_SetIntersectionEnable(laser, true);
|
||||||
|
//ObjShot_SetIntersectionLine(laser, ObjRender_GetX(target), ObjRender_GetY(target), ObjRender_GetX(target)+maxintersectX, -maxLength, width);
|
||||||
|
//WriteLog(ObjMove_GetX(laserfwd));
|
||||||
|
yield;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else{ObjShot_SetIntersectionEnable(laser, false); yield;}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// After shot key is released, let the laser leave and then delete it.
|
||||||
|
|
||||||
|
return laser;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
task _Follow(follower, followed){
|
||||||
|
|
||||||
|
while(!Obj_IsDeleted(follower)){
|
||||||
|
float x = ObjRender_GetX(followed);
|
||||||
|
float y = ObjRender_GetY(followed);
|
||||||
|
ObjMove_SetPosition(follower, x, y);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,693 @@
|
||||||
|
#TouhouDanmakufu[Player]
|
||||||
|
#ScriptVersion[3]
|
||||||
|
#ID["RinnoRemi"]
|
||||||
|
#Title["Rinnosuke Morichika & Remilia Scarlet"]
|
||||||
|
#Text["Unfocused Shot: Electronic Doombringer[r]Outbursts of fire from the Outside World's doomsday devices.[r][r]Focused Shot: Fate-Sealing Stars[r]High-speed homing stars.[r][r]Special Ability: Longer deathbomb timer."]
|
||||||
|
|
||||||
|
//#Image["./mariremi_lib/mariremi_illust.png"]
|
||||||
|
|
||||||
|
#ReplayName["RinnoRemi"]
|
||||||
|
|
||||||
|
#include "script/KevinSystem/Kevin_PlayerLib.txt"
|
||||||
|
#include "script/KevinSystem/PlayerSoundLib.dnh"
|
||||||
|
|
||||||
|
#include "./RinnoRemi_Function.dnh"
|
||||||
|
#include "./RinnoRemi_ShotConst.dnh"
|
||||||
|
|
||||||
|
#include "script/KevinSystem/kevin_system/Kevin_ItemConst.txt"
|
||||||
|
#include "script/KevinSystem/kevin_system/Kevin_ItemLib.txt"
|
||||||
|
|
||||||
|
let csd = GetCurrentScriptDirectory();
|
||||||
|
|
||||||
|
// Global Variables
|
||||||
|
|
||||||
|
float maxX = GetStgFrameWidth();
|
||||||
|
float maxY = GetStgFrameHeight();
|
||||||
|
|
||||||
|
// Images & Sound
|
||||||
|
|
||||||
|
let teamimg = csd ~ "./playerlib/RinnoRemi_Sheet.png";
|
||||||
|
LoadTextureEx(teamimg, true, true);
|
||||||
|
//ObjRender_SetTextureFilterMip(teamimg, FILTER_LINEAR);
|
||||||
|
|
||||||
|
let sndpath = csd ~ "./sound";
|
||||||
|
|
||||||
|
// Other stuff
|
||||||
|
|
||||||
|
float playerX = 0;
|
||||||
|
float playerY = 0;
|
||||||
|
|
||||||
|
let objPlayer = GetPlayerObjectID();
|
||||||
|
int plrender = Obj_GetRenderPriorityI(objPlayer);
|
||||||
|
|
||||||
|
int frameidlerinno = 0;
|
||||||
|
int frameidleremi = 0;
|
||||||
|
int framemoverinno = 0;
|
||||||
|
int framemoveremi = 0;
|
||||||
|
|
||||||
|
bool ripplayer = false;
|
||||||
|
float shotspeed = 0;
|
||||||
|
float bombrand = 0;
|
||||||
|
|
||||||
|
bool bombenable = false;
|
||||||
|
bool focusactive = false;
|
||||||
|
bool ishoming = false;
|
||||||
|
|
||||||
|
int[] _enemyArray = []; // Prepare an array to store enemy IDs for Kouda's homing shot
|
||||||
|
int[] _existArray = [];
|
||||||
|
int[] _shotArray = [];
|
||||||
|
|
||||||
|
int grazecounter = 0; // For basic graze = PIV mechanic
|
||||||
|
|
||||||
|
float[] PlayerSpd = [9.5, 5.2];
|
||||||
|
|
||||||
|
// Custom events for scoring mechanic
|
||||||
|
|
||||||
|
const EV_PIV_100 = EV_USER + 100i; // Normal enemies and nons
|
||||||
|
const EV_PIV_250 = EV_USER + 101i; // Spells
|
||||||
|
const EV_PIV_500 = EV_USER + 102i; // Last Spells
|
||||||
|
const EV_PIV_2000 = EV_USER + 103i; // What.
|
||||||
|
|
||||||
|
@Initialize{
|
||||||
|
|
||||||
|
if(!IsCommonDataAreaExists("PIV")){
|
||||||
|
CreateCommonDataArea("PIV");
|
||||||
|
SetAreaCommonData("PIV", "currentvalue", 10000);
|
||||||
|
}
|
||||||
|
else{}
|
||||||
|
|
||||||
|
SetPlayerStateEndEnable(true);
|
||||||
|
|
||||||
|
// Stuff
|
||||||
|
parameterrender();
|
||||||
|
playerrender();
|
||||||
|
Obj_SetRenderPriorityI(objPlayer, 43);
|
||||||
|
plrender = Obj_GetRenderPriorityI(objPlayer);
|
||||||
|
_SoundTask();
|
||||||
|
|
||||||
|
//SetIntersectionVisualization(true); // Debug
|
||||||
|
|
||||||
|
_Mechanic(ripplayer, _enemyArray, _existArray, GetStgFrameWidth(), GetStgFrameHeight(), objPlayer, GetEnemyBossSceneObjectID(), 5, 2, 80);
|
||||||
|
|
||||||
|
_HitboxRender(ripplayer, objPlayer, teamimg, teamimg, 2560, 512, 2688, 640, 2816, 1024, 2816+511, 1024+511, 0.22, 0.65);
|
||||||
|
SetShotAutoDeleteClip(256, 256, 256, 256);
|
||||||
|
|
||||||
|
// Shot functions
|
||||||
|
|
||||||
|
//_CAVELaser();
|
||||||
|
rinnoShot();
|
||||||
|
_BaseShot();
|
||||||
|
_remiOption();
|
||||||
|
//UniversalAlphaHandle(_shotArray);
|
||||||
|
|
||||||
|
// Shot data loading
|
||||||
|
LoadPlayerShotData(csd ~ "./RinnoRemi_ShotData.dnh");
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainLoop{
|
||||||
|
_enemyArray = GetIntersectionRegistedEnemyID;
|
||||||
|
shotspeed += 1; // Managing the shot rate
|
||||||
|
//_shotArray = GetAllShotID(TARGET_PLAYER);
|
||||||
|
//UniversalAlphaHandle(_shotArray);
|
||||||
|
playerX = ObjMove_GetX(objPlayer);
|
||||||
|
playerY = ObjMove_GetY(objPlayer);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Event{
|
||||||
|
alternative(GetEventType)
|
||||||
|
|
||||||
|
// Delete effect
|
||||||
|
case(EV_DELETE_SHOT_PLAYER){
|
||||||
|
let graphic = GetEventArgument(2);
|
||||||
|
float[] position = GetEventArgument(1);
|
||||||
|
let obj = CreatePlayerShotA1(position[0], position[1], 0, ObjMove_GetAngle(GetEventArgument(0)), 0, 99999, graphic);
|
||||||
|
ObjShot_SetIntersectionEnable(obj, false); _DeleteEffect(obj);
|
||||||
|
//if(graphic == ELECTRIC_FIRE_ALT) {_DeleteEffectAlt(obj);}
|
||||||
|
//else{_DeleteEffect(obj);}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PIV-item spawning events
|
||||||
|
case(EV_PIV_100){
|
||||||
|
let arg = GetEventArgument(0);
|
||||||
|
CreatePIVItem(PIV_100, arg[0], arg[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_PIV_250){
|
||||||
|
let arg = GetEventArgument(0);
|
||||||
|
CreatePIVItem(PIV_250, arg[0], arg[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_PIV_500){
|
||||||
|
let arg = GetEventArgument(0);
|
||||||
|
CreatePIVItem(PIV_500, arg[0], arg[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic functionality events
|
||||||
|
case(EV_REQUEST_SPELL){
|
||||||
|
let bomb = GetPlayerSpell();
|
||||||
|
|
||||||
|
if (bomb >= 1){
|
||||||
|
SetScriptResult(true);
|
||||||
|
SetPlayerSpell(bomb - 1);
|
||||||
|
if(GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){_FocusBomb(); _SigilCall(false, teamimg, 2816+256, 512, 2816+512, 768, objPlayer, GetPlayerInvincibilityFrame());}
|
||||||
|
else{_UnfocusBomb();
|
||||||
|
_SigilCall(false, teamimg, 2816+256, 512, 2816+512, 768, objPlayer, GetPlayerInvincibilityFrame());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
SetScriptResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_HIT){
|
||||||
|
ObjSound_Play(predeathsfx);
|
||||||
|
_DeathbombWarning(teamimg, [1792, 512, 1792+512, 512+512], 15, 0.75);
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_PLAYER_SHOOTDOWN){
|
||||||
|
ObjSound_Play(deathsfx);
|
||||||
|
ripplayer = true;
|
||||||
|
_SigilCall(true, teamimg, 2816, 512, 2816+256, 768, objPlayer, 120);
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_PLAYER_REBIRTH){
|
||||||
|
ripplayer = false;
|
||||||
|
SetPlayerInvincibilityFrame(180);
|
||||||
|
_SigilCall(false, teamimg, 2816+256, 512, 2816+512, 768, objPlayer, 150);
|
||||||
|
SetPlayerSpell( max(2,GetPlayerSpell()) );
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EV_GRAZE){
|
||||||
|
grazecounter += GetEventArgument(0);
|
||||||
|
ObjSound_Play(grazesfx);
|
||||||
|
while(grazecounter >= 10){
|
||||||
|
SetAreaCommonData("PIV", "currentvalue", GetAreaCommonData("PIV", "currentvalue")+10);
|
||||||
|
grazecounter -= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Finalize{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Homing
|
||||||
|
|
||||||
|
task _BaseShot(){
|
||||||
|
|
||||||
|
loop{
|
||||||
|
if(IsPermitPlayerShot && !ripplayer && GetVirtualKeyState(VK_SHOT) != KEY_FREE){
|
||||||
|
if(shotspeed % 5 == 0){
|
||||||
|
if(GetVirtualKeyState(VK_SLOWMOVE) == KEY_FREE){
|
||||||
|
float ang2 = 270-2*9;
|
||||||
|
//float angvel = (3.6-3*0.6)*1.2;
|
||||||
|
loop(5){
|
||||||
|
let bullet = CreatePlayerShotA1(playerX, playerY, 32, ang2, 1.4, 1.8, BASE);
|
||||||
|
Obj_SetRenderPriorityI(bullet, 39);
|
||||||
|
ObjRender_SetAlpha(bullet, 255*(universalAlpha/100));
|
||||||
|
ObjShot_SetSpinAngularVelocity(bullet, 10);
|
||||||
|
_BulletRescalePlayer(bullet, 0.5, true, 0.8);
|
||||||
|
//angvel -= 0.6*1.2;
|
||||||
|
ang2 += 9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){
|
||||||
|
float ang2 = 270-2*5;
|
||||||
|
//float angvel = (3.6-3*0.6)*1.2;
|
||||||
|
loop(5){
|
||||||
|
let bullet = CreatePlayerShotA1(playerX, playerY, 32, ang2, 1.2, 1.8, BASE);
|
||||||
|
Obj_SetRenderPriorityI(bullet, 39);
|
||||||
|
ObjRender_SetAlpha(bullet, 255*(universalAlpha/100));
|
||||||
|
ObjShot_SetSpinAngularVelocity(bullet, 10);
|
||||||
|
_BulletRescalePlayer(bullet, 0.5, true, 0.8);
|
||||||
|
//angvel -= 0.6*1.2;
|
||||||
|
ang2 += 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//ObjSound_Play(basesfx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
task _HomeShot(int shot_) {
|
||||||
|
|
||||||
|
float duration = 1;
|
||||||
|
bool homingBool = false;
|
||||||
|
float basepenetrate = ObjShot_GetPenetration(shot_);
|
||||||
|
float basedmg = ObjShot_GetDamage(shot_);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
for (int t = 0i; t < duration && !Obj_IsDeleted(shot_); t++) {
|
||||||
|
|
||||||
|
// Checks if enemies are on screen. If enemies are visible, enable homing for the shots.
|
||||||
|
// _enemyArray is an array containing all enemy IDs, and is constantly updated in @MainLoop.
|
||||||
|
|
||||||
|
if (0 < length(_enemyArray)) {
|
||||||
|
float targetDist = 2000; // Arbitrary number (???)
|
||||||
|
int targetID = 0;
|
||||||
|
|
||||||
|
// Checks distance of every enemy on screen.
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
|
// Returns the hypotenuse of the triangle formed by the x & y distances between the shot and the enemy.
|
||||||
|
|
||||||
|
float shotDist = hypot(enemyX - ObjMove_GetX(objPlayer), enemyY - ObjMove_GetY(objPlayer));
|
||||||
|
|
||||||
|
// Locks the shot onto the enemy.
|
||||||
|
|
||||||
|
if (shotDist < targetDist) {
|
||||||
|
targetDist = shotDist;
|
||||||
|
targetID = enemy;
|
||||||
|
homingBool = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code to handle the actual homing.
|
||||||
|
|
||||||
|
/*if (homingBool) {
|
||||||
|
for (int f = 0; t < duration && !Obj_IsDeleted(shot_) && !Obj_IsDeleted(targetID) && ObjEnemy_GetInfo(targetID, INFO_LIFE) != 0 && !ObjCol_IsIntersected(shot_); t++) {
|
||||||
|
ObjShot_SetAutoDelete(shot_, false);
|
||||||
|
|
||||||
|
float shotAngle = NormalizeAngle(ObjMove_GetAngle(shot_)); // Angle of the player shot
|
||||||
|
float targetAngle = NormalizeAngle(atan2(ObjMove_GetY(targetID) - ObjMove_GetY(shot_), ObjMove_GetX(targetID) - ObjMove_GetX(shot_))); // Returns angle from the shot to the enemy.
|
||||||
|
float angleDistance = AngularDistance(shotAngle, targetAngle); // Angular distance between enemy and player shot
|
||||||
|
float homeRate = Interpolate_Decelerate(0, 0.75, min(60, f) / 60);
|
||||||
|
// Homing speed?
|
||||||
|
ObjMove_SetAngle(shot_, Interpolate_Accelerate(shotAngle, shotAngle + angleDistance, homeRate)); // Interpolate_Necko
|
||||||
|
f++;
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
ObjShot_SetAutoDelete(shot_, true);
|
||||||
|
ObjMove_SetAngularVelocity(shot_, 0);
|
||||||
|
homingBool = false;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if (homingBool) {
|
||||||
|
for (int f = 0; t < duration && !Obj_IsDeleted(shot_) && !Obj_IsDeleted(targetID) && ObjEnemy_GetInfo(targetID, INFO_LIFE) != 0 && !ObjCol_IsIntersected(shot_); t++) {
|
||||||
|
ObjShot_SetAutoDelete(shot_, false);
|
||||||
|
|
||||||
|
float shotAngle = NormalizeAngle(ObjMove_GetAngle(shot_)); // Angle of the player shot
|
||||||
|
float targetAngle = NormalizeAngle(atan2(ObjMove_GetY(targetID) - ObjMove_GetY(shot_), ObjMove_GetX(targetID) - ObjMove_GetX(shot_))); // Returns angle from the shot to the enemy.
|
||||||
|
float angleDistance = AngularDistance(shotAngle, targetAngle); // Angular distance between enemy and player shot
|
||||||
|
float homeRate = Interpolate_Decelerate(0, 0.75, min(60, f) / 60);
|
||||||
|
// Homing speed?
|
||||||
|
ObjMove_SetAngle(shot_, Interpolate_Accelerate(shotAngle, shotAngle + angleDistance, 1)); // Interpolate_Necko
|
||||||
|
f++;
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
ObjShot_SetAutoDelete(shot_, true);
|
||||||
|
ObjMove_SetAngularVelocity(shot_, 0);
|
||||||
|
homingBool = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task _SwingBehaviour(target){
|
||||||
|
float ang = 0;
|
||||||
|
Obj_SetRenderPriorityI(target, 42);
|
||||||
|
while(true){
|
||||||
|
ObjRender_SetAngleZ(target, 0+20*sin(ang));
|
||||||
|
ang += 360/120;
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task _remiOption(){
|
||||||
|
|
||||||
|
// Offsets for 4 front options
|
||||||
|
|
||||||
|
float offsetX1 = 150;
|
||||||
|
float offsetX2 = offsetX1 * 2;
|
||||||
|
float offsetY1 = 90;
|
||||||
|
|
||||||
|
// Array that contains static/unchanging values for the PlayerOption
|
||||||
|
|
||||||
|
let val = [2048, 256, 2304, 512, 0.6, 256, 1, 1, false, false, 0, true, false];
|
||||||
|
|
||||||
|
// Option handling (right -> rightmost -> left -> leftmost)
|
||||||
|
|
||||||
|
float[][] offsetArray = [[offsetX1, offsetY1], [offsetX2, 0], [-offsetX1, offsetY1], [-offsetX2, 0]];
|
||||||
|
|
||||||
|
int opt1 = PlayerOption(
|
||||||
|
offsetArray[0][0], offsetArray[0][1],
|
||||||
|
teamimg,
|
||||||
|
val[0], val[1], val[2], val[3], val[4],
|
||||||
|
val[5], val[6], val[7], val[8],
|
||||||
|
val[9], val[10],
|
||||||
|
val[11], val[12]);
|
||||||
|
|
||||||
|
int opt2 = PlayerOption(
|
||||||
|
offsetArray[1][0], offsetArray[1][1],
|
||||||
|
teamimg,
|
||||||
|
val[0], val[1], val[2], val[3], val[4],
|
||||||
|
val[5], val[6], val[7], val[8],
|
||||||
|
val[9], val[10],
|
||||||
|
val[11], val[12]);
|
||||||
|
|
||||||
|
int opt3 = PlayerOption(
|
||||||
|
offsetArray[2][0], offsetArray[2][1],
|
||||||
|
teamimg,
|
||||||
|
val[0], val[1], val[2], val[3], val[4],
|
||||||
|
val[5], val[6], val[7], val[8],
|
||||||
|
val[9], val[10],
|
||||||
|
val[11], val[12]);
|
||||||
|
|
||||||
|
int opt4 = PlayerOption(
|
||||||
|
offsetArray[3][0], offsetArray[3][1],
|
||||||
|
teamimg,
|
||||||
|
val[0], val[1], val[2], val[3], val[4],
|
||||||
|
val[5], val[6], val[7], val[8],
|
||||||
|
val[9], val[10],
|
||||||
|
val[11], val[12]);
|
||||||
|
|
||||||
|
int[] optArray = [opt1, opt2, opt3, opt4];
|
||||||
|
|
||||||
|
ascent(i in -1..length(optArray)-1){
|
||||||
|
_SwingBehaviour(optArray[i]);
|
||||||
|
_HomingStars(optArray[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
task _HomingStars(option){
|
||||||
|
|
||||||
|
loop{
|
||||||
|
if(shotspeed % 5 == 0 && GetVirtualKeyState(VK_SHOT) != KEY_FREE && IsPermitPlayerShot && !ripplayer){
|
||||||
|
|
||||||
|
if(GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){
|
||||||
|
|
||||||
|
float x = ObjRender_GetX(option);
|
||||||
|
float y = ObjRender_GetY(option);
|
||||||
|
|
||||||
|
ascent(i in -1..1){
|
||||||
|
let shotA = CreatePlayerShotA1(-50+x+25-50*i, y, 50, 270, 1.37, 1.25, LOCKON_KNIFE);
|
||||||
|
//ObjMove_AddPatternA2(shotA, 1, 5, NO_CHANGE, -0.1, 3.75, rand(-0.4, 0.4));
|
||||||
|
|
||||||
|
//ObjMove_AddPatternA2(shotA, 1, NO_CHANGE, NO_CHANGE, 25, 50, 0);
|
||||||
|
_BulletRescalePlayer(shotA, 0.7, true, 1);
|
||||||
|
ObjRender_SetAlpha(shotA, 255*(universalAlpha/100));
|
||||||
|
ObjSound_Play(inferno);
|
||||||
|
_HomeShot(shotA);
|
||||||
|
//Fadein(shotA, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic player parameters
|
||||||
|
|
||||||
|
task parameterrender(){
|
||||||
|
|
||||||
|
SetPlayerItemScope(120);
|
||||||
|
SetPlayerLife(9); // Debug
|
||||||
|
SetPlayerSpell(2);
|
||||||
|
SetPlayerSpeed(PlayerSpd[0], PlayerSpd[1]); // (original: 5.25/2.0)
|
||||||
|
SetPlayerRebirthFrame(12);
|
||||||
|
SetPlayerAutoItemCollectLine(GetStgFrameHeight/3);
|
||||||
|
SetPlayerRebirthLossFrame(0);
|
||||||
|
ObjPlayer_AddIntersectionCircleA1(objPlayer, 0, 0, 1.25, 40);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renders the shottype
|
||||||
|
// Player sprites
|
||||||
|
|
||||||
|
task playerrender(){
|
||||||
|
|
||||||
|
// Why is this movement code so cursed jesus fucking christ
|
||||||
|
|
||||||
|
float scale = 0.39; // Scalies
|
||||||
|
|
||||||
|
ObjPrim_SetTexture(objPlayer, teamimg);
|
||||||
|
ObjSprite2D_SetSourceRect(objPlayer, 0, 0, 320, 384);
|
||||||
|
ObjSprite2D_SetDestCenter(objPlayer);
|
||||||
|
Obj_SetRenderPriorityI(objPlayer, 42);
|
||||||
|
ObjRender_SetScaleXYZ(objPlayer, scale, scale, 1);
|
||||||
|
|
||||||
|
// Lower "speed" parameter = FASTER SPEED
|
||||||
|
|
||||||
|
// FOR WHEN ONLY IDLE SPRITES ARE DONE
|
||||||
|
|
||||||
|
loop{
|
||||||
|
// Focused
|
||||||
|
if(GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){
|
||||||
|
frameidleremi++;
|
||||||
|
_RenderPlayerMovement(objPlayer, frameidleremi, 0, 1152, 320, 384, scale, 4, 6);
|
||||||
|
if (frameidleremi >= (5*4-1)){frameidleremi = 0;}
|
||||||
|
}
|
||||||
|
// Unfocused
|
||||||
|
else{
|
||||||
|
frameidlerinno++;
|
||||||
|
_RenderPlayerMovement(objPlayer, frameidlerinno, 0, 0, 320, 384, scale, 4, 6);
|
||||||
|
if (frameidlerinno >= (5*4-1)){frameidlerinno = 0;}
|
||||||
|
}
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
task rinnoShot(){
|
||||||
|
|
||||||
|
// Offsets for 4 front options
|
||||||
|
|
||||||
|
float offsetX1 = 90;
|
||||||
|
|
||||||
|
// Array that contains static/unchanging values for the PlayerOption
|
||||||
|
|
||||||
|
let valR = [1792, 256, 2048, 512, 0.5, 256, 1, 1, false, false, 6, false, true];
|
||||||
|
|
||||||
|
// Option handling
|
||||||
|
|
||||||
|
float[][] offsetArray = [[offsetX1, 0], [-offsetX1, 0]];
|
||||||
|
|
||||||
|
/*int opt1 = PlayerOption(
|
||||||
|
offsetArray[0][0], offsetArray[0][1],
|
||||||
|
teamimg,
|
||||||
|
valR[0], valR[1], valR[2], valR[3], valR[4],
|
||||||
|
valR[5], valR[6], valR[7], valR[8],
|
||||||
|
valR[9], valR[10],
|
||||||
|
valR[11], valR[12]);
|
||||||
|
|
||||||
|
int opt2 = PlayerOption(
|
||||||
|
offsetArray[1][0], offsetArray[1][1],
|
||||||
|
teamimg,
|
||||||
|
valR[0], valR[1], valR[2], valR[3], valR[4],
|
||||||
|
valR[5], valR[6], valR[7], valR[8],
|
||||||
|
valR[9], valR[10],
|
||||||
|
valR[11], valR[12]);*/
|
||||||
|
|
||||||
|
int opt3 = PlayerOption(
|
||||||
|
0, 150,
|
||||||
|
teamimg,
|
||||||
|
valR[0], valR[1], valR[2], valR[3], valR[4],
|
||||||
|
valR[5], valR[6], valR[7], valR[8],
|
||||||
|
valR[9], valR[10],
|
||||||
|
valR[11], valR[12]);
|
||||||
|
|
||||||
|
//int[] optArray = [opt1, opt2];
|
||||||
|
|
||||||
|
float angle = 255;
|
||||||
|
|
||||||
|
/*ascent(i in -1..length(optArray)-1){
|
||||||
|
_ThunderNeedle(optArray[i], angle, 10, 4);
|
||||||
|
_ThunderNeedle(optArray[i], 90, 7.5, 2.5);
|
||||||
|
_SwingBehaviour(optArray[i]);
|
||||||
|
angle += 35;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
_ThunderNeedle(opt3, 15, 270, 10, 8, 4.2);
|
||||||
|
_ThunderNeedle(opt3, -15, 90, 15, 4, 4.4);
|
||||||
|
_SwingBehaviour(opt3);
|
||||||
|
|
||||||
|
task _ThunderNeedle(int target, float yoffset, float baseang, float tiltang, int num, float dmg){
|
||||||
|
|
||||||
|
//float baseang = 270;
|
||||||
|
|
||||||
|
//int a = trunc(-num/2);
|
||||||
|
|
||||||
|
// Odd numbers only
|
||||||
|
|
||||||
|
loop{
|
||||||
|
if(IsPermitPlayerShot && !ripplayer && GetVirtualKeyState(VK_SHOT) != KEY_FREE && GetVirtualKeyState(VK_SLOWMOVE) == KEY_FREE){
|
||||||
|
if(shotspeed % 5 == 0){
|
||||||
|
ascent(i in trunc(-num/2)..trunc(num/2)+1){
|
||||||
|
float shot = CreatePlayerShotA1(ObjRender_GetX(target), ObjRender_GetY(target)+yoffset, 65, baseang-tiltang*i, dmg, 1.0, ELECTRIC_FIRE_ALT);
|
||||||
|
ObjRender_SetAlpha(shot, 255*(universalAlpha/100));
|
||||||
|
Obj_SetRenderPriorityI(shot, 39);
|
||||||
|
_BulletRescalePlayer(shot, 0.55, true, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(shotspeed % 5 == 0){ObjSound_Play(basesfx);}
|
||||||
|
}
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
task PointblankPlacebo(target, scale, multiplier){
|
||||||
|
int len = 10;
|
||||||
|
while(GetObjectDistance(target, objPlayer) < 90){
|
||||||
|
_BulletRescalePlayer(target, scale*multiplier, true, multiplier); // Pointblank
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
ascent(i in 0..len){
|
||||||
|
_BulletRescalePlayer(target, Interpolate_Decelerate(scale*multiplier, scale, i/len), true, Interpolate_Decelerate(multiplier, 1, i/len));
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task Fadein(target, len){
|
||||||
|
ascent(i in 0..len){
|
||||||
|
_BulletRescalePlayer(target, Interpolate_Decelerate(0.4, 0.7, i/len), true, Interpolate_Decelerate(0.4, 0.7, i/len));
|
||||||
|
//ObjRender_SetBlendType(target, BLEND_ADD_ARGB);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
ObjRender_SetBlendType(target, BLEND_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
|
task Fadein(target, len, targetscale, targetscalehitbox){
|
||||||
|
ascent(i in 0..len){
|
||||||
|
_BulletRescalePlayer(target, Interpolate_Decelerate(0.1, targetscale, i/len), true, Interpolate_Decelerate(1, targetscalehitbox, i/len));
|
||||||
|
//ObjRender_SetBlendType(target, BLEND_ADD_ARGB);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
ObjRender_SetBlendType(target, BLEND_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handling of bomb
|
||||||
|
|
||||||
|
task _FocusBomb(){
|
||||||
|
|
||||||
|
// Preparation
|
||||||
|
SetForbidPlayerShot(true);
|
||||||
|
SetForbidPlayerSpell(true);
|
||||||
|
SetPlayerInvincibilityFrame(32*3+32*3+42*3+120+45);
|
||||||
|
// Spell object
|
||||||
|
let manageObj = GetSpellManageObject(); // SPELL BEGINS
|
||||||
|
ObjSpell_Regist(manageObj);
|
||||||
|
ObjSound_Play(bombsfx);
|
||||||
|
SetPlayerSpeed(PlayerSpd[1]-2, PlayerSpd[1]-2);
|
||||||
|
|
||||||
|
float angvel = 0.75;
|
||||||
|
float revolve = 0;
|
||||||
|
float spd = 21;
|
||||||
|
float dmg = 2;
|
||||||
|
float revolvechange = 12;
|
||||||
|
|
||||||
|
ascent(i in 0..40){
|
||||||
|
|
||||||
|
int shot = CreateShotA2(playerX, playerY, 25, rand(260, 280), rand(-1.5, -1), 0.5, HOMING_STAR, 15);
|
||||||
|
//_BulletRescalePlayer(shot, 3, true, 1);
|
||||||
|
ObjShot_SetSpinAngularVelocity(shot, 6);
|
||||||
|
Fadein(shot, 20, 2, 2);
|
||||||
|
ObjRender_SetBlendType(shot, BLEND_ADD_ARGB);
|
||||||
|
ObjMove_AddPatternA2(shot, 30, NO_CHANGE, NO_CHANGE, 0.8, 32, 0);
|
||||||
|
ObjShot_SetIntersectionEnable(shot, true);
|
||||||
|
ObjShot_SetPenetration(shot, 9999);
|
||||||
|
ObjShot_SetDamage(shot, 2);
|
||||||
|
ObjShot_SetEraseShot(shot, true);
|
||||||
|
ObjShot_SetSpellFactor(shot, true);
|
||||||
|
ObjSound_Play(inferno);
|
||||||
|
wait(5);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup, end of spell
|
||||||
|
SetPlayerSpeed(PlayerSpd[0], PlayerSpd[1]);
|
||||||
|
SetForbidPlayerShot(false);
|
||||||
|
wait(60);
|
||||||
|
SetForbidPlayerSpell(false);
|
||||||
|
Obj_Delete(manageObj); // !!! IMPORTANT !!!
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
task _UnfocusBomb(){
|
||||||
|
|
||||||
|
// Preparation
|
||||||
|
SetForbidPlayerShot(true);
|
||||||
|
SetForbidPlayerSpell(true);
|
||||||
|
SetPlayerInvincibilityFrame(32*3+32*3+42*3+120+45);
|
||||||
|
// Spell object
|
||||||
|
let manageObj = GetSpellManageObject(); // SPELL BEGINS
|
||||||
|
ObjSpell_Regist(manageObj);
|
||||||
|
ObjSound_Play(bombsfx);
|
||||||
|
SetPlayerSpeed(PlayerSpd[0], PlayerSpd[0]);
|
||||||
|
|
||||||
|
float angvel = 0.75;
|
||||||
|
float revolve = 0;
|
||||||
|
float spd = 21;
|
||||||
|
float dmg = 2;
|
||||||
|
float revolvechange = 12;
|
||||||
|
|
||||||
|
int hakkero = CreatePlayerShotA1(playerX, playerY, 0, 0, 12, 999999, 4);
|
||||||
|
ObjShot_SetIntersectionEnable(hakkero, true);
|
||||||
|
ObjShot_SetEraseShot(hakkero, true);
|
||||||
|
ObjShot_SetSpellFactor(hakkero, true);
|
||||||
|
ObjShot_SetSpinAngularVelocity(hakkero, 8);
|
||||||
|
|
||||||
|
async{
|
||||||
|
ascent(i in 0..45){
|
||||||
|
_BulletRescalePlayer(hakkero, Interpolate_Decelerate(0.5, 2.25, i/45), true, 1);
|
||||||
|
ObjRender_SetAlpha(hakkero, Interpolate_Decelerate(0, 255, i/45));
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ascent(i in 0..240){
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup, end of spell
|
||||||
|
ObjShot_FadeDelete(hakkero);
|
||||||
|
SetPlayerSpeed(PlayerSpd[0], PlayerSpd[1]);
|
||||||
|
SetForbidPlayerShot(false);
|
||||||
|
wait(60);
|
||||||
|
SetForbidPlayerSpell(false);
|
||||||
|
Obj_Delete(manageObj); // !!! IMPORTANT !!!
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Screenshake function for bomb's duration - adapted from Sparen's tutorials
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
let current = GetCurrentScriptDirectory();
|
||||||
|
let path = current ~ "RinnoRemi_ShotData.dnh";
|
||||||
|
LoadPlayerShotData(path);
|
||||||
|
// -----
|
||||||
|
|
||||||
|
const HOMING_STAR = 1;
|
||||||
|
const ELECTRIC_FIRE = 2;
|
||||||
|
const BASE = 3;
|
||||||
|
const ELECTRIC_FIRE_ALT = 5;
|
||||||
|
const LOCKON_KNIFE = 6;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
shot_image = "./playerlib/RinnoRemi_Sheet.png"
|
||||||
|
|
||||||
|
ShotData{
|
||||||
|
id = 0 // Dummy
|
||||||
|
rect = (0,0,0,0)
|
||||||
|
render = ALPHA
|
||||||
|
alpha = 0
|
||||||
|
collision = 32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Homing stars
|
||||||
|
|
||||||
|
ShotData{
|
||||||
|
id = 1
|
||||||
|
rect = (1792, 0, 2048, 256)
|
||||||
|
render = ALPHA
|
||||||
|
alpha = 255
|
||||||
|
collision = (75, 0, 0) // Hitbox of arrows is not centered on the sprite
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unfocused fire
|
||||||
|
|
||||||
|
ShotData{
|
||||||
|
id = 2
|
||||||
|
rect = (2048, 0, 2304, 256)
|
||||||
|
render = ALPHA
|
||||||
|
alpha = 200
|
||||||
|
collision = (52, 0, 0) // Hitbox of arrows is not centered on the sprite
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ShotData{
|
||||||
|
id = 3
|
||||||
|
rect = (2304, 0, 2560, 256)
|
||||||
|
render = ALPHA
|
||||||
|
alpha = 200
|
||||||
|
collision = (75, 0, 0) // Hitbox of arrows is not centered on the sprite
|
||||||
|
}
|
||||||
|
|
||||||
|
ShotData{
|
||||||
|
id = 5
|
||||||
|
rect = (2560, 0, 2816, 384)
|
||||||
|
render = ALPHA
|
||||||
|
alpha = 210
|
||||||
|
collision = (115, 0, 128) // Hitbox of arrows is not centered on the sprite
|
||||||
|
}
|
||||||
|
|
||||||
|
ShotData{
|
||||||
|
id = 6
|
||||||
|
rect = (2816, 0, 3072, 256)
|
||||||
|
render = ALPHA
|
||||||
|
alpha = 225
|
||||||
|
collision = (75, 0, 0) // Hitbox of arrows is not centered on the sprite
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bomb
|
||||||
|
|
||||||
|
ShotData{
|
||||||
|
id = 4
|
||||||
|
rect = (3328, 1024, 3840, 1536)
|
||||||
|
render = ADD_ARGB
|
||||||
|
alpha = 255
|
||||||
|
collision = 160
|
||||||
|
}
|
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 1.1 MiB |
|
@ -0,0 +1 @@
|
||||||
|
2,0.57,,0.3442,,0.2691,0.3,0.2179,,0.3445,,,,,,,,,,,0.2992,,0.5139,,,1,,,,,,,masterVolume
|
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 25 KiB |
|
@ -0,0 +1,322 @@
|
||||||
|
// Lasers that don't penetrate
|
||||||
|
// Can be pasted into default player Rumia by adding `TLasers();` to @Initialize
|
||||||
|
// Activation logic is focused-shooting with a slight delay, similar to CAVE games.
|
||||||
|
// "RemovePLaserGfx()" can go into shutting-down (probably not necessary).
|
||||||
|
// Made by razzy
|
||||||
|
|
||||||
|
task TLasers{
|
||||||
|
|
||||||
|
InitPLaserGfx(); // Probably effects that occur when the laser reaches an enemy? (KEV)
|
||||||
|
|
||||||
|
let lasers0 = [ID_INVALID,ID_INVALID,ID_INVALID,ID_INVALID,ID_INVALID,ID_INVALID,ID_INVALID,ID_INVALID,ID_INVALID];
|
||||||
|
|
||||||
|
// this delays when the laser fires
|
||||||
|
// laser fires when laserMode==0
|
||||||
|
// laserMode increments by 1 per frame
|
||||||
|
// so laser fires after 15 frames
|
||||||
|
|
||||||
|
// KEV: To fire the laser immediately, just set laserMode to 0.
|
||||||
|
|
||||||
|
let laserLimit = 15;
|
||||||
|
let laserMode=-laserLimit;
|
||||||
|
|
||||||
|
loop{
|
||||||
|
if(IsPermitPlayerShot
|
||||||
|
&& GetPlayerState!=STATE_HIT
|
||||||
|
&& GetPlayerState!=STATE_DOWN
|
||||||
|
&& GetPlayerState!=STATE_END
|
||||||
|
&& (GetVirtualKeyState(VK_SHOT)==KEY_PUSH || GetVirtualKeyState(VK_SHOT)==KEY_HOLD)
|
||||||
|
){
|
||||||
|
if(GetVirtualKeyState(VK_SLOWMOVE)==KEY_PUSH || GetVirtualKeyState(VK_SLOWMOVE)==KEY_HOLD){
|
||||||
|
laserMode=min(0,laserMode+1);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// reset laser delay when slowmove is let go
|
||||||
|
laserMode=-laserLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(laserMode>=0){
|
||||||
|
let odd = 1;
|
||||||
|
|
||||||
|
//NonPenetrationLaser(obj, xoff, yoff, ang, spd, maxLen, dmg, IsStrongLaser, width, vwidth)
|
||||||
|
// KEV: Ascent loop determines the number of lasers that will be spawned.
|
||||||
|
|
||||||
|
ascent(i in 0..1){
|
||||||
|
let las = lasers0[i];
|
||||||
|
if(Obj_IsValueExists(las,"DEL") || Obj_IsDeleted(las)){
|
||||||
|
let magnitude = 1;
|
||||||
|
lasers0[i]=NonPenetrationLaser(objPlayer, 0, -36, 270, 40, GetStgFrameHeight()*1.5, 2, true, 2, 2);
|
||||||
|
}
|
||||||
|
odd=-odd;
|
||||||
|
}
|
||||||
|
//PlaySnd(SND_p_shot, 93);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// reset laser delay when fire is let go
|
||||||
|
// KEV: Unnecessary if the laser fires immediately
|
||||||
|
laserMode=-laserLimit;
|
||||||
|
}
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
// of an array of 2d coords, return the one closest to (sx,sy). Also returns the distance from (sx,sy) as the third value.
|
||||||
|
function GetClosestCoord(coords, sx,sy){
|
||||||
|
let closest=[];
|
||||||
|
let last_dist=99999;
|
||||||
|
let arrayLen=length(coords);
|
||||||
|
if(arrayLen==1){
|
||||||
|
let cur_dist;
|
||||||
|
if(length(coords[0])==3){ cur_dist=coords[0][2]; }
|
||||||
|
else{ cur_dist=((coords[0][0]-sx)^2+(coords[0][1]-sy)^2)^0.5; }
|
||||||
|
closest=[coords[0][0],coords[0][1], cur_dist];
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ascent(i in 0..arrayLen){
|
||||||
|
let cur_dist;
|
||||||
|
if(length(coords[i])==3){ cur_dist=(coords[i][2]); }
|
||||||
|
else{ cur_dist=((coords[i][0]-sx)^2+(coords[i][1]-sy)^2)^0.5; }
|
||||||
|
if(cur_dist < last_dist){
|
||||||
|
last_dist=cur_dist;
|
||||||
|
closest=[coords[i][0], coords[i][1], cur_dist];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
|
||||||
|
// non-penetrating laser object
|
||||||
|
function NonPenetrationLaser(obj, xoff, yoff, ang, spd, maxLen, dmg, IsStrongLaser, width, vwidth){
|
||||||
|
|
||||||
|
/* KEV: Parameter explanations:
|
||||||
|
|
||||||
|
obj: Where the laser is fired from
|
||||||
|
xoff/yoff: x and y offsets relative to the object
|
||||||
|
ang, spd: Self-explanatory
|
||||||
|
maxLen: max length of the laser, DON'T SET THIS TOO HIGH! GetStgFrameHeight() + a generous number should be enough
|
||||||
|
dmg: Self-explanatory
|
||||||
|
IsStrongLaser: use this if you want to differentiate between strong and weak lasers I guess, I don't play CAVE games so idk
|
||||||
|
width, vwidth: intersection & render width of laser
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// KEV: Defines the laser object.
|
||||||
|
let damager = ObjShot_Create(OBJ_STRAIGHT_LASER);
|
||||||
|
ObjShot_SetGraphic(damager, 1);
|
||||||
|
Obj_SetVisible(damager, false);
|
||||||
|
ObjShot_Regist(damager);
|
||||||
|
ObjShot_SetDamage(damager, dmg);
|
||||||
|
ObjShot_SetPenetration(damager, 8);
|
||||||
|
ObjLaser_SetLength(damager, 0);
|
||||||
|
ObjLaser_SetIntersectionWidth(damager, 64*width);
|
||||||
|
ObjLaser_SetRenderWidth(damager, 64*vwidth);
|
||||||
|
ObjStLaser_SetAngle(damager, ang);
|
||||||
|
TNonPenetrationLaser();
|
||||||
|
return damager;
|
||||||
|
|
||||||
|
task TNonPenetrationLaser(){
|
||||||
|
let scroll=rand(0,64);
|
||||||
|
let len=0; // the length of the laser (increased until maxLen)
|
||||||
|
let cosine=cos(ang); // grab this value for placement of the tip. **this assumes the laser never changes angle**
|
||||||
|
let sine=sin(ang); // grab this value for placement of the tip. **this assumes the laser never changes angle**
|
||||||
|
|
||||||
|
// **for lasers that change angle, cosine and sine will need to be updated**
|
||||||
|
|
||||||
|
// Laser is now firing
|
||||||
|
while(!Obj_IsDeleted(damager) // KEV: The four following states can be reduced to !ripplayer in my player scripts
|
||||||
|
&& IsPermitPlayerShot
|
||||||
|
&& GetPlayerState!=STATE_HIT
|
||||||
|
&& GetPlayerState!=STATE_DOWN
|
||||||
|
&& GetPlayerState!=STATE_END // Reduce these below to != KEY_FREE
|
||||||
|
&& (GetVirtualKeyState(VK_SHOT)==KEY_PUSH || GetVirtualKeyState(VK_SHOT)==KEY_HOLD)
|
||||||
|
&& (GetVirtualKeyState(VK_SLOWMOVE)==KEY_PUSH || GetVirtualKeyState(VK_SLOWMOVE)==KEY_HOLD)
|
||||||
|
){
|
||||||
|
CheckLaserIntersection;
|
||||||
|
|
||||||
|
// Set the laser's position and length
|
||||||
|
ObjMove_SetPosition(damager, ObjRender_GetX(obj)+xoff,ObjRender_GetY(obj)+yoff);
|
||||||
|
len = min(maxLen, len+spd);
|
||||||
|
ObjLaser_SetLength(damager, len);
|
||||||
|
MakeLaserGfxFrame;
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This laser isn't deleted just yet. I let it fly away first.
|
||||||
|
// This value lets other tasks check when this happens.
|
||||||
|
Obj_SetValue(damager, "DEL", true);
|
||||||
|
|
||||||
|
// Laser is now leaving
|
||||||
|
ObjMove_SetAngle(damager, ObjStLaser_GetAngle(damager));
|
||||||
|
ObjMove_SetSpeed(damager, spd);
|
||||||
|
while(!Obj_IsDeleted(damager) && len>8){
|
||||||
|
MakeLaserGfxFrame;
|
||||||
|
len=max(0,len-spd);
|
||||||
|
ObjLaser_SetLength(damager, len);
|
||||||
|
CheckLaserIntersection;
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
Obj_Delete(damager);
|
||||||
|
|
||||||
|
function MakeLaserGfxFrame(){
|
||||||
|
let hyper=0;
|
||||||
|
let gLen = max(0, len-32-24);
|
||||||
|
let gLen2 = max(0, len-32);
|
||||||
|
|
||||||
|
// add sprites to the per-frame sprite list
|
||||||
|
|
||||||
|
// KEV: Function reference: PLaserGfxFrameLaser(gfxObj, u, v, u2, v2, ry, x, y, ang, sx, sy, rd, gn, bl, al)
|
||||||
|
|
||||||
|
/*
|
||||||
|
KEV: Function description:
|
||||||
|
|
||||||
|
Adds a vertex to the attached gfxObj sprite list. Uses u, v, u2, v2 as coordinates for the SourceRect, ry for DestRect (rx is calculated in the function), x & y for vertex position, sx & sy for the scaling, rd, gn and bl for colors, and al for alpha.
|
||||||
|
|
||||||
|
PLaserGfxFrame is similar but is used for the base and tip of the laser. The ry (and by extension rx) parameters are removed.
|
||||||
|
|
||||||
|
(The color values should be unnecessary.)
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ObjStLaser_SetEndGraphic (ph3sx) may come in handy for the base/tips.
|
||||||
|
|
||||||
|
// !IsStrongLaser = 0, IsStrongLaser = 1
|
||||||
|
|
||||||
|
PLaserGfxFrameLaser(lasGfxObj[0], 32+hyper*32+!IsStrongLaser*64, scroll, 63+hyper*32+!IsStrongLaser*64, (len-1)/4+scroll, 64, ObjMove_GetX(damager)+cosine*24, ObjMove_GetY(damager)+sine*24, ang+90, vwidth*rand(0.75,1.0),gLen/64, 255, 255, 255, 255);
|
||||||
|
|
||||||
|
PLaserGfxFrameLaser(lasGfxObj[1], 32+hyper*32+!IsStrongLaser*64, scroll, 63+hyper*32+!IsStrongLaser*64, (len-1)/4+scroll, 64, ObjMove_GetX(damager)+cosine*24, ObjMove_GetY(damager)+sine*24, ang+90, vwidth*rand(0.75,1.0), gLen/64, 255, 255, 255, 48);
|
||||||
|
|
||||||
|
PLaserGfxFrame(lasGfxObj[2], 160, 0, 191, 31, ObjMove_GetX(damager)+cosine*24, ObjMove_GetY(damager)+sine*24, ang+90, vwidth+rand(0.4, 0.5), 6, 255,255,255, 255); // Base of laser
|
||||||
|
|
||||||
|
PLaserGfxFrame(lasGfxObj[2], 160, 32, 191, 63, ObjMove_GetX(damager)+cosine*gLen2, ObjMove_GetY(damager)+sine*gLen2, ang+90, vwidth+rand(0.4, 0.5), 6, 255, 255, 255, 255);// Tip of laser
|
||||||
|
|
||||||
|
scroll += 3; // Scrolls the laser's graphic.
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function CheckLaserIntersection(){
|
||||||
|
// ------------------ Check for enemy collisions ------------------
|
||||||
|
let enemies=ObjCol_GetListOfIntersectedEnemyID(damager); // Get enemy array
|
||||||
|
let closest=[];
|
||||||
|
let arrayLen=length(enemies);
|
||||||
|
// Check all enemies hit (if any)
|
||||||
|
if(arrayLen>0){
|
||||||
|
let enm_pos=[]; // will be a 2-dimensional array
|
||||||
|
|
||||||
|
// KEV: If there is no strong/weak laser differentiation, this ascent loop can be removed entirely(?)
|
||||||
|
|
||||||
|
ascent(i in 0..arrayLen){ // go through the enemies list
|
||||||
|
// Weaker lasers get pushed back by "popcorn" enemies.
|
||||||
|
|
||||||
|
// KEV: I don't really want to implement strong/weak laser differentiations...
|
||||||
|
|
||||||
|
if(!IsStrongLaser || ObjEnemy_GetInfo(enemies[i], INFO_LIFE) > 1){
|
||||||
|
// There are multiple collisions per enemy to check as well
|
||||||
|
// It's rare that there's more than one, but it's allowed
|
||||||
|
|
||||||
|
let pos=GetEnemyIntersectionPositionByIdA1(enemies[i]); // KEV: Returns the multiple hitboxes of the enemy as a 2D array, format is [index][x, y of hitbox].
|
||||||
|
|
||||||
|
/* KEV: Further explanation (rough and probably incorrect);
|
||||||
|
|
||||||
|
An enemy has 2 hitboxes, one at coords [16, 16] and one at [32, 32].
|
||||||
|
|
||||||
|
You get a 2D array named "coords" containing the coordinates of these 2 hitboxes by using GetEnemyIntersectionPositionByIdA1.
|
||||||
|
|
||||||
|
You then write this line "float num = coords[0][1];" and WriteLog() the value of num.
|
||||||
|
|
||||||
|
coords[0][1] corresponds to the y coordinate of the first hitbox, which would give you a num value of 16.
|
||||||
|
|
||||||
|
(I don't know the order the hitboxes will be sorted in the array, though. For all I know, coords[0][1] may be the second hitbox's y (32)...?)
|
||||||
|
|
||||||
|
*/
|
||||||
|
let closest2=GetClosestCoord(pos, ObjMove_GetX(damager),ObjMove_GetY(damager));
|
||||||
|
if(closest2[0]!=-1234){
|
||||||
|
enm_pos=enm_pos~[closest2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closest = GetClosestCoord(enm_pos, ObjMove_GetX(damager),ObjMove_GetY(damager));
|
||||||
|
}
|
||||||
|
// ------------------ ------------------ ------------------
|
||||||
|
|
||||||
|
// There has been a collision, dial back laser length to (roughly) the point of collision.
|
||||||
|
// (Roughly) because we can't get the exact location, and doing it ourselves requires finding the hitbox dimensions.
|
||||||
|
|
||||||
|
// KEV: Getting the hitbox dimensions/locations should be perfectly possible with ph3sx's intersection-obtaining functions. Will need re-examining
|
||||||
|
|
||||||
|
if(length(closest) > 0){
|
||||||
|
let dist=closest[2]-16;
|
||||||
|
len=max(0,dist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // NonPenetrationLaser
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let lasGfxObj=[]; // KEV: An array that will contain three sprite lists, rendering three different parts of the laser (base, body, tip).
|
||||||
|
|
||||||
|
// KEV: Creates the sprite lists, assigns the texture to them, and adds them as indexes into lasGfxObj.
|
||||||
|
|
||||||
|
task InitPLaserGfx(){
|
||||||
|
|
||||||
|
let imgLaser = GetCurrentScriptDirectory() ~ "laser_fx.png";
|
||||||
|
LoadTexture(imgLaser);
|
||||||
|
|
||||||
|
ascent(i in 0..3){
|
||||||
|
let gfx = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
|
||||||
|
ObjPrim_SetTexture(gfx, imgLaser);
|
||||||
|
Obj_SetRenderPriorityI(gfx, 41);
|
||||||
|
lasGfxObj = lasGfxObj~[gfx];
|
||||||
|
}
|
||||||
|
ObjRender_SetBlendType(lasGfxObj[1], BLEND_ADD_ARGB);
|
||||||
|
Obj_SetRenderPriorityI(lasGfxObj[2], 42);
|
||||||
|
|
||||||
|
while(true){
|
||||||
|
ascent(i in 0..length(lasGfxObj)){
|
||||||
|
ObjSpriteList2D_ClearVertexCount(lasGfxObj[i]);
|
||||||
|
}
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task RemovePLaserGfx{
|
||||||
|
let imgLaser = GetCurrentScriptDirectory() ~ "laser_fx.png";
|
||||||
|
RemoveTexture(imgLaser);
|
||||||
|
|
||||||
|
ascent(i in 0..length(lasGfxObj)){
|
||||||
|
Obj_Delete(lasGfxObj[i]);
|
||||||
|
lasGfxObj[i]=ID_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See the non-penetrating laser object task for information on these tasks.
|
||||||
|
|
||||||
|
task PLaserGfxFrame(gfxObj, u, v, u2, v2, x, y, ang, sx, sy, rd, gn, bl, al){
|
||||||
|
if(gfxObj==ID_INVALID){return;}
|
||||||
|
|
||||||
|
ObjRender_SetPosition(gfxObj, x, y, 0);
|
||||||
|
ObjRender_SetAngleZ(gfxObj, ang);
|
||||||
|
ObjRender_SetScaleXYZ(gfxObj, sx, sy, 1);
|
||||||
|
ObjRender_SetColor(gfxObj, rd, gn, bl);
|
||||||
|
ObjRender_SetAlpha(gfxObj, al);
|
||||||
|
ObjSpriteList2D_SetSourceRect(gfxObj, u, v, u2, v2);
|
||||||
|
ObjSpriteList2D_SetDestCenter(gfxObj);
|
||||||
|
ObjSpriteList2D_AddVertex(gfxObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
task PLaserGfxFrameLaser(gfxObj, u, v, u2, v2, ry, x, y, ang, sx, sy, rd, gn, bl, al){
|
||||||
|
if(gfxObj==ID_INVALID){return;}
|
||||||
|
|
||||||
|
ObjRender_SetPosition(gfxObj, x,y,0);
|
||||||
|
ObjRender_SetAngleZ(gfxObj, ang);
|
||||||
|
ObjRender_SetScaleXYZ(gfxObj, sx ,sy, 1);
|
||||||
|
ObjRender_SetColor(gfxObj, rd,gn,bl);
|
||||||
|
ObjRender_SetAlpha(gfxObj, al);
|
||||||
|
ObjSpriteList2D_SetSourceRect(gfxObj, u, v, u2, v2);
|
||||||
|
let rx=(u2-u)/2;
|
||||||
|
ObjSpriteList2D_SetDestRect(gfxObj, -rx,0,rx,-ry);
|
||||||
|
ObjSpriteList2D_AddVertex(gfxObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
|