ScarletBlackMarket/script/player/PrideJam_RinnoRemi/RinnoRemi_Main.dnh

694 lines
19 KiB
Plaintext

#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;
}