#TouhouDanmakufu[Player] #ScriptVersion[3] #ID["Flandre"] #Title["Flandre"] #Text["E"] //#Image["./mariremi_lib/mariremi_illust.png"] #ReplayName["Flandre"] #include "script/KevinSystem/kevin_system/Lib_Const.dnh" #include "script/KevinSystem/Kevin_PlayerLib.txt" #include "script/KevinSystem/PlayerSoundLib.dnh" #include "./Chimata_Function.dnh" #include "./Chimata_ShotConst.dnh" #include "script/KevinSystem/kevin_system/Kevin_ItemConst.txt" #include "script/KevinSystem/kevin_system/Kevin_ItemLib.txt" float shotDamage = 2.4+(GetCommonData("Rank", 1)*0.3); float shotScale = 0.6+(GetCommonData("Rank", 1)*0.125); float shotSpeed = 50+(GetCommonData("Rank", 1)*1.5); let csd = GetCurrentScriptDirectory(); // Global Variables float maxX = GetStgFrameWidth(); float maxY = GetStgFrameHeight(); // Images & Sound let teamimg = csd ~ "./playerlib/Flan_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); bool ripplayer = false; float shotspeed = 0; float bombrand = 0; bool bombenable = false; bool focusactive = false; bool ishoming = false; bool isChain = 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 int shotAlpha = (GetAreaCommonData("Config", "PlayerShotOpacity", 60)*0.01)*255; float[] PlayerSpd = [15.5, 7.5]; // 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); SetAreaCommonData("PIV", "ChainAmount", 1); } 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); _ShowChain(); _HitboxRender(ripplayer, objPlayer, teamimg, teamimg, 1280, 512, 1408, 640, 1536, 896, 2048, 1408, 0.3, 0.65); SetShotAutoDeleteClip(256, 256, 256, 256); // Shot functions //SetPlayerSpell(99); _Countdown(); _CAVELaser(); _ShotType(); //UniversalAlphaHandle(_shotArray); // Shot data loading LoadPlayerShotData(csd ~ "./Chimata_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){ if(GetCommonDataPtr(EFFECTCUT_PTR, 0) >= 3){} else{ 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, shotScale); } //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); _Bomb(); SetCommonData("Rank", max(1, GetCommonData("Rank", 1)-1)); _SigilCall(false, teamimg, 768+256, 512, 768+512, 768, objPlayer, GetPlayerInvincibilityFrame()); } else { SetScriptResult(false); } } case(EV_HIT){ ObjSound_Play(PlayerHit); _DeathbombWarning(teamimg, [1536, 384, 1536+512, 384+512], 15, 0.75); } case(EV_CHAIN_MAX){ if(!isChain){ ObjSound_Play(Shine); isChain = true; } else{} } case(EV_CHAIN_RELEASE){ } case(EV_CHAIN_END){ SetAreaCommonData("PIV", "ChainAmount", 1); isChain = false; } case(EV_PLAYER_SHOOTDOWN){ ObjSound_Play(PlayerDie2); BombRefund(); ripplayer = true; DeleteShotAll(TYPE_SHOT, TYPE_ITEM); SetCommonData("Rank", max(1, round(GetCommonData("Rank", 1)/2))); _SigilCall(true, teamimg, 768, 512, 768+256, 768, objPlayer, 60); } case(EV_PLAYER_REBIRTH){ ripplayer = false; SetPlayerInvincibilityFrame(180); //_Countdown(); _SigilCall(false, teamimg, 768+256, 512, 768+512, 768, objPlayer, 150); } case(EV_GRAZE){ grazecounter += GetEventArgument(0); ObjSound_Play(Graze); while(grazecounter >= 10){ SetAreaCommonData("PIV", "currentvalue", GetAreaCommonData("PIV", "currentvalue")+10); grazecounter -= 10; } } } @Finalize{ } // Homing task BombRefund(){ SetPlayerSpell(GetPlayerSpell()+[1, 2, 3, 3][clamp((GetCommonData("Rank", 1)/2)-1, 0, 3)]); } task _SwingBehaviour(target){ float ang = 0; Obj_SetRenderPriorityI(target, 42); while(true){ ObjRender_SetAngleZ(target, 0+20*sin(ang)); ang += 360/120; yield; } } task _ShotType(){ _Option(125, 0, 0, 1); _Option(125, 90, 0, 1); _Option(125, 180, 0, 1); _Option(125, 270, 0, 1); // Rank while(true){ shotDamage = 2.4+(GetCommonData("Rank", 1)*0.2); shotScale = 0.6+(GetCommonData("Rank", 1)*0.1); shotSpeed = 50+(GetCommonData("Rank", 1)*2); wait(30); } } function _Option(dist, startang, wvel, counterspin){ //let shot = CreatePlayerShotA1(playerX+x, playerY-150+y, 0, startang, 0, 99999, KEV_OPTION); let dummy = CreatePlayerShotA1(playerX, playerY-180, 0, startang, 0, 99999, 0); bool visible = true; int shotspeedhome = 0; float counter = 0; float scythex = 0; float scythey = 0; float offset = 0; float dummyX = ObjMove_GetX(dummy); float dummyY = ObjMove_GetY(dummy); let shot = CreatePlayerShotA1(dummyX, dummyY, 0, startang, 0, 99999, OPTION); float spaceX = 0, spaceY = 0; float shotang = startang; //ObjShot_SetSpinAngularVelocity(shot, wvel); ObjShot_SetAutoDelete(shot, false); ObjShot_SetAutoDelete(dummy, false); _BulletRescalePlayer(shot, 0.25, true, 1); ObjRender_SetBlendType(shot, BLEND_ALPHA); ObjRender_SetAlpha(shot, 255); Obj_SetRenderPriorityI(shot, plrender-1); // Handles the spinning and shooting of the options. async{ //SetShotAutoDeleteClip(-500, 128, -500, -500); //int i = 0; loop{ float shotx = ObjMove_GetX(shot); float shoty = ObjMove_GetY(shot); ObjRender_SetAngleZ(shot, 0); if(!IsPermitPlayerShot || ripplayer){ //spaceX = clamp(spaceX-2, 0, x); //Obj_SetVisible(shot, false); Obj_SetVisible(dummy, false); visible = false; shotspeedhome = 0; } else{ //spaceX = min(x, spaceX+x/45); //spaceY = min(y, spaceY+y/45); Obj_SetVisible(shot, true); visible = true; Obj_SetVisible(dummy, true); if(shotspeedhome % 4 == 0 && GetVirtualKeyState(VK_SHOT) != KEY_FREE){ let water = CreatePlayerShotA1(shotx, shoty, 50, 270, 4, 1.5, FIRE); //let water2 = CreatePlayerShotA1(shotx+25, shoty, 15, shotang+180, 1.82, 1.25, KEV_OPTIONSHOT); ObjShot_SetAutoDelete(water, false); ObjRender_SetAlpha(water, shotAlpha); _HandleDeletion(water); _BulletRescalePlayer(water, shotScale, true, 1); //ObjMove_SetAngularVelocity(water, [0, 0.2][typeGun]); //ObjMove_SetAngularVelocity(water2, [0, 0.2][typeGun]); Obj_SetRenderPriorityI(water, plrender-1); ObjSound_Play(Base2); } shotspeedhome++; //counter; } yield; } } task _HandleDeletion(int target){ while(ObjMove_GetY(target) > -128){ if(Obj_IsDeleted(target)){break;} yield; } Obj_Delete(target); return; } // Having the options move with Kevin if not shooting and/or focused. async{ float angmove = 0; loop{ ObjMove_SetPosition(shot, playerX+counterspin*spaceX*cos(shotang), playerY-offset+counterspin*spaceY*sin(shotang)); shotang += 3.5*counterspin; ObjMove_SetPosition(dummy, playerX, playerY); if(GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){ spaceX = max(dist*0.75, spaceX-dist*1.5/15); spaceY = max(dist*0.75, spaceY-dist*1.5/15); } else{ spaceX = min(dist*1.5, spaceX+dist*1.5/15); spaceY = min(dist*1.5, spaceY+dist*1.5/15); } yield; } } async{ loop{ if(visible == true){ObjShot_SetIntersectionEnable(shot, true); ObjShot_SetIntersectionEnable(dummy, true); counter += (1/240); counter = min(counter, 1);} else if (visible != true && GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){ObjShot_SetIntersectionEnable(shot, false); ObjShot_SetIntersectionEnable(dummy, false);} else {ObjShot_SetIntersectionEnable(shot, false); ObjShot_SetIntersectionEnable(dummy, false); counter = 0;} yield; } } return shot; } // Basic player parameters task parameterrender(){ SetPlayerItemScope(120); SetPlayerLife(9); // Debug SetPlayerSpell(2); SetPlayerSpeed(PlayerSpd[0], PlayerSpd[1]); // (original: 5.25/2.0) SetPlayerRebirthFrame(15); SetPlayerDownStateFrame(60); SetPlayerAutoItemCollectLine(GetStgFrameHeight/3); SetPlayerRebirthLossFrame(0); ObjPlayer_AddIntersectionCircleA1(objPlayer, 0, 0, 0, 40); } // Renders the shottype // Player sprites task playerrender(){ // Why is this movement code so cursed jesus fucking christ float scale = 0.4; // Scalies int frame = 0; ObjPrim_SetTexture(objPlayer, teamimg); ObjSprite2D_SetSourceRect(objPlayer, 0, 0, 512, 384); ObjSprite2D_SetDestCenter(objPlayer); Obj_SetRenderPriorityI(objPlayer, 42); //ObjRender_SetTextureFilterMin(objPlayer, FILTER_ANISOTROPIC); ObjRender_SetScaleXYZ(objPlayer, scale, scale, 1); // Lower "speed" parameter = FASTER SPEED // FOR WHEN ONLY IDLE SPRITES ARE DONE loop{ //frame++; _RenderPlayerMovement(objPlayer, frame, 0, 0, 512, 384, scale, 4, 6); //if (frame >= (1*4-1)){frame = 0;} 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 _Bomb(){ // Preparation SetAreaCommonData("ChainChecks", "IsChaining", true); SetForbidPlayerShot(true); SetForbidPlayerSpell(true); SetPlayerInvincibilityFrame(270); // Spell object let manageObj = GetSpellManageObject(); // SPELL BEGINS ObjSpell_Regist(manageObj); //ObjSound_Play(bombsfx); SetPlayerSpeed(PlayerSpd[0]*2, PlayerSpd[1]*2); // 180 seconds DEATH LASER //SetCommonData("IsBomb", true); //_Countdown(270); async{ loop(90){ Fire(); Fire(); wait(2); } } function Fire(){ let shotA = CreatePlayerShotA1(playerX, playerY, 25, rand(-15, 195), shotDamage/2, 25, FIRE); _BulletRescalePlayer(shotA, 1.25, true, 1); ObjRender_SetAlpha(shotA, 255); Fading(shotA); ObjRender_SetBlendType(shotA, BLEND_ADD_ARGB); Obj_SetRenderPriorityI(shotA, 41); ObjShot_SetPenetrateShotEnable(shotA, false); //ObjShot_SetEnemyIntersectionInvalidFrame(shotA, 5); // CURRENTLY BUGGED AS OF PH3SX 1.32B ObjShot_SetSpellFactor(shotA, true); ObjShot_SetEraseShot(shotA, true); } loop(30){ if(GetVirtualKeyState(VK_SHOT) != KEY_FREE){ObjSound_Play(Fire);} wait(6); } task Fading(shot){ ObjMove_SetAcceleration(shot, -1.5); ObjMove_SetMaxSpeed(shot, 3); ascent(i in 0..40){ ObjRender_SetAlpha(shot, Interpolate_Decelerate(255, 0, i/40)); yield; } Obj_Delete(shot); } SetPlayerSpeed(PlayerSpd[0], PlayerSpd[1]); SetForbidPlayerShot(false); Obj_Delete(manageObj); // !!! IMPORTANT !!! SetAreaCommonData("ChainChecks", "IsChaining", false); NotifyEventOwn(EV_CHAIN_END, 0); wait(60); SetForbidPlayerSpell(false); } // Screenshake function for bomb's duration - adapted from Sparen's tutorials task _Countdown(){ //int timer = time; int counter = CreateTextObject( playerX, playerY, 58, "", "Origami Mommy", 0xFFFFFF, 0xFFFFFF, 0x1AEC8C, 10, Obj_GetRenderPriorityI(objPlayer)+1 ); ObjText_SetHorizontalAlignment(counter, ALIGNMENT_CENTER); while(true){ if(GetPlayerInvincibilityFrame() <= 0){Obj_SetVisible(counter, false);} else{Obj_SetVisible(counter, true);} ObjRender_SetPosition(counter, playerX, playerY - 140, 1); ObjText_SetText(counter, IntToString(GetPlayerInvincibilityFrame())); yield; } //Obj_Delete(counter); } 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; } function CreateTextObject( float mx, my, size, string text, font, int colorTop, colorBottom, int borderColor, borderWidth, int renderPriority ){ let obj = ObjText_Create(); ObjText_SetText(obj, text); ObjText_SetFontSize(obj, size); ObjText_SetFontType(obj, font); ObjText_SetFontColorTop(obj, colorTop); ObjText_SetFontColorBottom(obj, colorBottom); ObjText_SetFontBorderType(obj, BORDER_FULL); ObjText_SetFontBorderColor(obj, borderColor); ObjText_SetFontBorderWidth(obj, borderWidth); Obj_SetRenderPriorityI(obj, renderPriority); ObjRender_SetX(obj, mx); ObjRender_SetY(obj, my); return obj; }