I spent an hour learning how to Git. Help

This commit is contained in:
kevinmonitor 2022-09-14 23:26:09 +07:00
commit 8356c73017
258 changed files with 18172 additions and 0 deletions

BIN
script/player/Chimata.rar Normal file

Binary file not shown.

View file

@ -0,0 +1,489 @@
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;
}
}
// Special functions for Tenshi's CAVE laser shottype.
// Original code by Razzy/Razzly, edited and tweaked by Kevinmonitor
// DEBUG
float LaserAlpha = 0; // Not used
task _CAVELaser(){
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/laserLimit to 0.
let laserLimit = 0;
let laserMode=-laserLimit;
loop{
if(
GetPlayerState!=STATE_HIT
&& GetPlayerState!=STATE_DOWN
&& GetPlayerState!=STATE_END
&& (GetVirtualKeyState(VK_SHOT)==KEY_PUSH || GetVirtualKeyState(VK_SHOT)==KEY_HOLD)
){
if(IsPlayerSpellActive()){
laserMode=min(0,laserMode+1);
}
else{
// reset laser delay when slowmove is let go
laserMode=-laserLimit;
}
laserMode=min(0,laserMode+1);
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, 7, 1.25, 1);
}
odd=-odd;
}
//PlaySnd(SND_p_shot, 93);
}
else{
// reset laser delay when fire is let go
// KEV: Unnecessary if the laser fires immediately
RemovePLaserGfx();
LaserAlpha = 0;
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, 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 (REMOVED HERE): 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.
int a = 0;
let damager = ObjShot_Create(OBJ_STRAIGHT_LASER);
ObjShot_SetGraphic(damager, 0);
Obj_SetVisible(damager, true);
ObjShot_Regist(damager);
ObjShot_SetDamage(damager, dmg);
ObjShot_SetPenetration(damager, 9999);
ObjShot_SetEraseShot(damager, true);
ObjLaser_SetLength(damager, 0);
ObjLaser_SetIntersectionWidth(damager, 256*width);
ObjLaser_SetRenderWidth(damager, 256*vwidth);
ObjStLaser_SetAngle(damager, ang); ObjShot_SetAutoDelete(damager, false);
ObjShot_SetIntersectionEnable(damager, true);
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(
IsPlayerSpellActive()
&& !Obj_IsDeleted(damager) // KEV: The four following states can be reduced to !ripplayer in my player scripts
&& !ripplayer
&& (GetVirtualKeyState(VK_SHOT) != KEY_FREE)
){
a++;
if(a % 5 == 0){ObjSound_Play(inferno);}
CheckLaserIntersection;
// Set the laser's position and length
ObjMove_SetPosition(damager, ObjMove_GetX(obj)+xoff,ObjMove_GetY(obj)+yoff);
len = min(maxLen, len+spd);
ObjLaser_SetLength(damager, len);
//ObjShot_SetIntersectionLine(damager, ObjMove_GetX(obj), ObjMove_GetY(obj)+yoff, ObjMove_GetX(obj), -len, 128*width);
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 > 128){
MakeLaserGfxFrame;
len=max(0,len-spd);
ObjLaser_SetLength(damager, len);
CheckLaserIntersection;
yield;
}
Obj_Delete(damager);
function MakeLaserGfxFrame(){
//let hyper=0;
// Values related to graphic lengths
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.
//(rd, gn, bl values have been removed)
// ObjStLaser_SetEndGraphic (ph3sx) may come in handy for the base/tips.
// After reaching the bottom rect, value loops back to the top.
PLaserGfxFrameLaser(lasGfxObj[0], 512, scroll, 1024, scroll*512, 64, ObjMove_GetX(damager)+cosine*24, ObjMove_GetY(damager)+sine*24, ang+90, vwidth*rand(1.0, 1.05), gLen/64, 255);
PLaserGfxFrameLaser(lasGfxObj[1], 512, scroll, 1024, scroll*512, 64, ObjMove_GetX(damager)+cosine*24, ObjMove_GetY(damager)+sine*24, ang+90, vwidth*rand(1.4, 1.5), gLen/64, 60); // Glow effect
PLaserGfxFrame(lasGfxObj[2], 512, 768, 1024, 1280, ObjMove_GetX(damager)+cosine*24, ObjMove_GetY(damager)+sine*24-20, ang+90, 1.15*vwidth+rand(0.2, 0.3), 1.15+rand(0.2, 0.3), 255); // Base of laser
PLaserGfxFrame(lasGfxObj[3], 1024, 0, 1536, 512, ObjMove_GetX(damager)+cosine*gLen2, 10+ObjMove_GetY(damager)+sine*gLen2, ang+90, 0.6*width+rand(0.2, 0.3), 0.8, 255);// Tip of laser
ObjRender_SetAngleZ(lasGfxObj[2], ObjRender_GetAngleZ(lasGfxObj[2])+10);
//WriteLog([ObjMove_GetX(damager), ObjMove_GetY(damager)]);
scroll += 0.05; // Scrolls the laser's graphic.
if (scroll >= 1) {scroll = 0.1;}
}
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(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.
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
// Set the damage of the laser.
float dmgBase = 12;
float dmgMax = 12;
if(length(closest) > 0){
let dist=closest[2]-16;
len=max(0,dist);
// The laser deals higher damage the closer it is to the enemy.
float ratioDist = 120/closest[2];
ObjShot_SetDamage(damager, Interpolate_Decelerate(dmgBase, dmgMax, min(1, ratioDist)));
// The laser changes colours depending on distance.
}
}
}
} // 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() ~ "./playerlib/Chimata_Sheet.png";
LoadTextureEx(imgLaser, true, true); // Loaded in main script
ascent(i in 0..4){
let gfx = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
ObjSpriteList2D_SetAutoClearVertexCount(gfx, true);
ObjPrim_SetTexture(gfx, imgLaser);
Obj_SetRenderPriorityI(gfx, 41);
lasGfxObj = lasGfxObj~[gfx];
//ObjRender_SetBlendType(lasGfxObj[i-1], BLEND_ADD_ARGB);
}
async{
while(length(lasGfxObj) >= 3){
ObjRender_SetAngleZ(lasGfxObj[2], ObjRender_GetAngleZ(lasGfxObj[2])+10);
yield;
}
}
//ObjRender_SetBlendType(lasGfxObj[2], BLEND_ADD_ARGB);
Obj_SetRenderPriorityI(lasGfxObj[2], 42);
}
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(
int gfxObj,
float rectLeft, float rectTop, float rectRight, float rectBottom,
float posX, float posY,
float ang,
float scaleX, float scaleY,
float alpha){
if(gfxObj==ID_INVALID){return;}
//ObjRender_SetBlendType(gfxObj, BLEND_ADD_ARGB);
ObjRender_SetPosition(gfxObj, posX, posY, 0);
ObjRender_SetAngleZ(gfxObj, ang);
ObjRender_SetScaleXYZ(gfxObj, scaleX, scaleY, 1);
ObjSpriteList2D_SetSourceRect(gfxObj, rectLeft, rectTop, rectRight, rectBottom);
ObjSpriteList2D_SetDestCenter(gfxObj);
ObjSpriteList2D_AddVertex(gfxObj);
ObjRender_SetAlpha(gfxObj, alpha);
}
task PLaserGfxFrameLaser(
int gfxObj,
float rectLeft, float rectTop, float rectRight, float rectBottom,
float destY,
float posX, float posY,
float ang,
float scaleX, float scaleY,
float alpha){
if(gfxObj==ID_INVALID){return;}
//ObjRender_SetBlendType(gfxObj, BLEND_ADD_ARGB);
ObjRender_SetPosition(gfxObj, posX, posY,0);
ObjRender_SetAngleZ(gfxObj, ang);
ObjRender_SetScaleXYZ(gfxObj, scaleX, scaleY, 1);
ObjRender_SetAlpha(gfxObj, alpha);
ObjSpriteList2D_SetSourceRect(gfxObj, rectLeft, rectTop, rectRight, rectBottom);
let destX = (rectRight - rectLeft)/2;
ObjSpriteList2D_SetDestRect(gfxObj, -destX, 0, destX, -destY);
ObjSpriteList2D_AddVertex(gfxObj);
}

View file

@ -0,0 +1,833 @@
#TouhouDanmakufu[Player]
#ScriptVersion[3]
#ID["Cirno"]
#Title["Cirno"]
#Text["Shot Type: Blank Card Set[r]Spell Card: Shield of Market Regulation"]
//#Image["./mariremi_lib/mariremi_illust.png"]
#ReplayName["Cirno"]
#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.125);
float shotScale = 0.6+(GetCommonData("Rank", 1)*0.125);
let csd = GetCurrentScriptDirectory();
// Global Variables
float maxX = GetStgFrameWidth();
float maxY = GetStgFrameHeight();
// Images & Sound
let teamimg = csd ~ "./playerlib/Chimata_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;
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);
}
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, 1280, 512, 1408, 640, 1536, 896, 2048, 1408, 0.3, 0.65);
SetShotAutoDeleteClip(256, 256, 256, 256);
// Shot functions
_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){
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(predeathsfx);
_DeathbombWarning(teamimg, [1536, 384, 1536+512, 384+512], 15, 0.75);
}
case(EV_PLAYER_SHOOTDOWN){
ObjSound_Play(deathsfx);
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);
_SigilCall(false, teamimg, 768+256, 512, 768+512, 768, objPlayer, 150);
}
case(EV_GRAZE){
grazecounter += GetEventArgument(0);
ObjSound_Play(grazesfx);
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 _HomeShot(int option_) {
int shot_ = 0;
float duration = 1;
float durationOption = 99999;
bool homingBool = false;
float basepenetrate = ObjShot_GetPenetration(shot_);
float basedmg = ObjShot_GetDamage(shot_);
//
for (int t = 0i; t < durationOption && !Obj_IsDeleted(option_); 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 < durationOption && !Obj_IsDeleted(option_) && !Obj_IsDeleted(targetID) && ObjEnemy_GetInfo(targetID, INFO_LIFE) != 0 && GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE; t++) {
ObjShot_SetAutoDelete(option_, false);
float shotAngle = NormalizeAngle(ObjMove_GetAngle(option_)); // Angle of the player shot
float targetAngle = NormalizeAngle(atan2(ObjMove_GetY(targetID) - ObjMove_GetY(option_), ObjMove_GetX(targetID) - ObjMove_GetX(option_))); // 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(15, f) / 15);
// Homing speed?
ObjMove_SetAngle(option_, Interpolate_Decelerate(shotAngle, shotAngle + angleDistance, homeRate)); // Interpolate_Necko
f++;
yield;
}
}
/*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 _ShotType(){
// Offsets for 4 front options
// Alternative player option function
function PlayerOption(
float offsetx, float offsety,
texture,
int left, int top, int right, int bottom, float scale,
int width, int animdelay, int frameno, bool triggeranimation,
bool triggerspin, float spinspeed,
bool onlyFocus, bool onlyUnfocus
){
// IMPORTANT!
let option = ObjShot_Create(OBJ_SHOT);
ObjShot_Regist(option);
ObjShot_SetAutoDelete(option, false);
ObjShot_SetGraphic(option, 3);
ObjShot_SetPenetration(option, 9999^9999);
ObjShot_SetDamage(option, 0);
ObjShot_SetIntersectionEnable(option, false);
ObjMove_SetAngle(option, 270);
//
bool visible;
int animate = 0;
float optx;
float opty;
ObjRender_SetScaleXYZ(option, scale);
ObjRender_SetBlendType(option, BLEND_ALPHA);
ObjRender_SetAlpha(option, 225);
Obj_SetRenderPriorityI(option, 41);
ObjRender_SetPosition(option, offsetx, offsety, 1);
// Animation
async{
while(triggeranimation){
ObjSprite2D_SetSourceRect(option, left+width*floor(animate/animdelay), top, right+width*floor(animate/animdelay)-1, bottom-1);
animate++;
if (animate >= animdelay*frameno){animate = 0;}
yield;
}
}
// Rotation
async{
float i = 0;
while(triggerspin){
//ObjRender_SetPosition(option, GetPlayerX()+offsetx, GetPlayerY()+offsety, 1);
ObjRender_SetAngleZ(option, i);
i += spinspeed;
yield;
}
}
// Follow
async{
while(true){
ObjMove_SetPosition(option, GetPlayerX()+offsetx, GetPlayerY()+offsety);
yield;
}
}
// Visibility
async{
// Always visible
if((onlyFocus && onlyUnfocus) || (!onlyFocus && !onlyUnfocus)) {
loop
{
if(GetPlayerState != STATE_NORMAL && GetPlayerState != STATE_HIT){ObjRender_SetAlpha(option, max(0, ObjRender_GetAlpha(option)-15)); visible = false;}
else {ObjRender_SetAlpha(option, min(225, ObjRender_GetAlpha(option)+15)); visible = true;}
yield;
}
}
// Visible when focused only
else if(onlyFocus && !onlyUnfocus){
loop
{
if((GetPlayerState != STATE_NORMAL && GetPlayerState != STATE_HIT) || GetVirtualKeyState(VK_SLOWMOVE) == KEY_FREE){ObjRender_SetAlpha(option, max(0, ObjRender_GetAlpha(option)-15)); visible = false;}
else {ObjRender_SetAlpha(option, min(225, ObjRender_GetAlpha(option)+15)); visible = true;}
yield;
}
}
// Visible when unfocused only
else if(!onlyFocus && onlyUnfocus){
loop
{
if((GetPlayerState != STATE_NORMAL && GetPlayerState != STATE_HIT) || GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){ObjRender_SetAlpha(option, max(0, ObjRender_GetAlpha(option)-15)); visible = false;}
else {ObjRender_SetAlpha(option, min(225, ObjRender_GetAlpha(option)+15)); visible = true;}
yield;
}
}
}
function _FadeIn(){
ascent(i in 0..15){
ObjRender_SetAlpha(option, Interpolate_Decelerate(0, 225, i/15));
yield;
}
}
function _FadeOut(){
ascent(i in 0..15){
ObjRender_SetAlpha(option, Interpolate_Decelerate(225, 0, i/15));
yield;
}
}
return option;
}
float offsetX1 = 125;
float offsetX2 = offsetX1 * 2;
float offsetY1 = 75;
// Array that contains static/unchanging values for the PlayerOption
let val = [0, 512, 256, 768, 0.45, 256, 1, 1, false, false, 0, true, true];
// 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];
BaseShot;
UpdateParam;
task UpdateParam(){
loop{
shotDamage = 2.4+(GetCommonData("Rank", 1)*0.125);
shotScale = 0.6+(GetCommonData("Rank", 1)*0.125);
wait(60);
}
}
task BaseShot(){
loop{
if(GetVirtualKeyState(VK_SHOT) != KEY_FREE && IsPermitPlayerShot && !ripplayer){
if(shotspeed % 4 == 0){
let shotB = CreatePlayerShotA1(playerX, playerY, 50, 270, 2.6, shotDamage*1.25, 1);
_BulletRescalePlayer(shotB, shotScale, true, 1);
ObjRender_SetAlpha(shotB, shotAlpha);
Obj_SetRenderPriorityI(shotB, 41);
}
}
yield;
}
}
_HomingStars(optArray[0], 0); //_HomeShot(optArray[0]);
_HomingStars(optArray[1], 1); //_HomeShot(optArray[1]);
_HomingStars(optArray[2], 2); //_HomeShot(optArray[2]);
_HomingStars(optArray[3], 3); //_HomeShot(optArray[3]);
task _HomingStars(option, value){
int angMultiplier = 0;
loop{
if(GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){
async{
if(value == 0){
ascent(i in 0..15){
ObjMove_SetAngle(option, Interpolate_Decelerate(ObjMove_GetAngle(option), 265, i/15));
ObjMove_SetX(option, Interpolate_Decelerate(ObjMove_GetX(option), playerX+offsetX1*0.5, i/15));
ObjMove_SetY(option, Interpolate_Decelerate(ObjMove_GetY(option), playerY+offsetY1, i/15));
yield;
}
}
else if(value == 1){
ascent(i in 0..15){
ObjMove_SetAngle(option, Interpolate_Decelerate(ObjMove_GetAngle(option), 255, i/15));
ObjMove_SetX(option, Interpolate_Decelerate(ObjMove_GetX(option), playerX+offsetX1*0.8, i/15));
ObjMove_SetY(option, Interpolate_Decelerate(ObjMove_GetY(option), playerY, i/15));
yield;
}
}
else if(value == 2){
ascent(i in 0..15){
ObjMove_SetAngle(option, Interpolate_Decelerate(ObjMove_GetAngle(option), 275, i/15));
ObjMove_SetX(option, Interpolate_Decelerate(ObjMove_GetX(option), playerX-offsetX1*0.5, i/15));
ObjMove_SetY(option, Interpolate_Decelerate(ObjMove_GetY(option), playerY+offsetY1, i/15));
yield;
}
}
else if(value == 3){
ascent(i in 0..15){
ObjMove_SetAngle(option, Interpolate_Decelerate(ObjMove_GetAngle(option), 285, i/15));
ObjMove_SetX(option, Interpolate_Decelerate(ObjMove_GetX(option), playerX-offsetX1*0.8, i/15));
ObjMove_SetY(option, Interpolate_Decelerate(ObjMove_GetY(option), playerY, i/15));
yield;
}
}
}
async{
if(GetVirtualKeyState(VK_SHOT) != KEY_FREE && IsPermitPlayerShot && !ripplayer){
if(shotspeed % 4 == 0){
//float x = ObjRender_GetX(option);
//float y = ObjRender_GetY(option);
float x = ObjMove_GetX(option);
float y = ObjMove_GetY(option);
int multiplier;
float angSwing;
if(x-playerX > 0){multiplier = 1;}
else{multiplier = -1;}
if(value == 1 || value == 3) {angSwing = 6;}
else{angSwing = 4;}
let shotA = CreatePlayerShotA1(x, y, 50, ObjMove_GetAngle(option)+angSwing*multiplier*angMultiplier, shotDamage*1.2, 1.1, 1);
_BulletRescalePlayer(shotA, shotScale, true, 1);
ObjRender_SetAlpha(shotA, shotAlpha);
Obj_SetRenderPriorityI(shotA, 41);
ObjSound_Play(basesfx);
angMultiplier ++;
if (angMultiplier > 3) {angMultiplier = 0;}
}
}
}
}
else{
async{
if(value == 0){
ascent(i in 0..15){
ObjMove_SetAngle(option, Interpolate_Decelerate(ObjMove_GetAngle(option), 275, i/15));
ObjMove_SetX(option, Interpolate_Decelerate(ObjMove_GetX(option), playerX+offsetX1*0.5, i/15));
ObjMove_SetY(option, Interpolate_Decelerate(ObjMove_GetY(option), playerY+offsetY1, i/15));
yield;
}
}
else if(value == 1){
ascent(i in 0..15){
ObjMove_SetAngle(option, Interpolate_Decelerate(ObjMove_GetAngle(option), 295, i/15));
ObjMove_SetX(option, Interpolate_Decelerate(ObjMove_GetX(option), playerX+offsetX1*0.8, i/15));
ObjMove_SetY(option, Interpolate_Decelerate(ObjMove_GetY(option), playerY, i/15));
yield;
}
}
else if(value == 2){
ascent(i in 0..15){
ObjMove_SetAngle(option, Interpolate_Decelerate(ObjMove_GetAngle(option), 265, i/15));
ObjMove_SetX(option, Interpolate_Decelerate(ObjMove_GetX(option), playerX-offsetX1*0.5, i/15));
ObjMove_SetY(option, Interpolate_Decelerate(ObjMove_GetY(option), playerY+offsetY1, i/15));
yield;
}
}
else if(value == 3){
ascent(i in 0..15){
ObjMove_SetAngle(option, Interpolate_Decelerate(ObjMove_GetAngle(option), 245, i/15));
ObjMove_SetX(option, Interpolate_Decelerate(ObjMove_GetX(option), playerX-offsetX1*0.8, i/15));
ObjMove_SetY(option, Interpolate_Decelerate(ObjMove_GetY(option), playerY, i/15));
yield;
}
}
}
async{
if(GetVirtualKeyState(VK_SHOT) != KEY_FREE && IsPermitPlayerShot && !ripplayer){
if(shotspeed % 4 == 0){
//float x = ObjRender_GetX(option);
//float y = ObjRender_GetY(option);
float x = ObjMove_GetX(option);
float y = ObjMove_GetY(option);
int multiplier;
float angSwing;
if(x-playerX > 0){multiplier = 1;}
else{multiplier = -1;}
if(value == 1 || value == 3) {angSwing = 8;}
else{angSwing = 6;}
let shotA = CreatePlayerShotA1(x, y, 50, ObjMove_GetAngle(option)+angSwing*multiplier*angMultiplier, shotDamage*1.5, 1.1, 1);
_BulletRescalePlayer(shotA, shotScale, true, 1);
ObjRender_SetAlpha(shotA, shotAlpha);
Obj_SetRenderPriorityI(shotA, 41);
ObjSound_Play(basesfx);
angMultiplier ++;
if (angMultiplier > 3) {angMultiplier = 0;}
}
}
}
}
yield;
}
}
}
// 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, 1.25, 40);
}
// Renders the shottype
// Player sprites
task playerrender(){
// Why is this movement code so cursed jesus fucking christ
float scale = 0.35; // Scalies
int frame = 0;
ObjPrim_SetTexture(objPlayer, teamimg);
ObjSprite2D_SetSourceRect(objPlayer, 0, 0, 400, 400);
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{
//frame++;
_RenderPlayerMovement(objPlayer, frame, 0, 0, 400, 400, 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
SetForbidPlayerShot(true);
SetForbidPlayerSpell(true);
SetPlayerInvincibilityFrame(240);
// Spell object
let manageObj = GetSpellManageObject(); // SPELL BEGINS
ObjSpell_Regist(manageObj);
//ObjSound_Play(bombsfx);
SetPlayerSpeed(PlayerSpd[0]*1.5, PlayerSpd[1]*1.5);
// 180 seconds DEATH LASER
//SetCommonData("IsBomb", true);
async{
loop(90){
Fire();
Fire();
wait(2);
}
}
task Fire(){
let shotA = CreatePlayerShotA1(playerX, playerY, 25, rand(-15, 195), shotDamage/10, 25, 2);
_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, 2);
ObjShot_SetSpellFactor(shotA, true);
ObjShot_SetEraseShot(shotA, true);
}
loop(30){
if(GetVirtualKeyState(VK_SHOT) != KEY_FREE){ObjSound_Play(inferno);}
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);
//SetCommonData("IsBomb", 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;
}

View file

@ -0,0 +1,12 @@
let current = GetCurrentScriptDirectory();
let path = current ~ "Chimata_ShotData.dnh";
LoadPlayerShotData(path);
// -----
const HOMING_STAR = 1;
const ELECTRIC_FIRE = 2;
const BASE = 3;
const ELECTRIC_FIRE_ALT = 5;
const LOCKON_KNIFE = 6;

View file

@ -0,0 +1,50 @@
shot_image = "./playerlib/Chimata_Sheet.png"
ShotData{
id = 0 // Dummy
rect = (0,0,0,0)
render = ALPHA
alpha = 0
collision = 32
}
// IceShot
ShotData{
id = 1
rect = (256, 512, 512, 768)
render = ALPHA
alpha = 255
collision = 128 // Hitbox of arrows is not centered on the sprite
}
// BombShot
ShotData{
id = 2
rect = (512, 512, 768, 768)
render = ADD_ARGB
alpha = 255
collision = 128 // Hitbox of arrows is not centered on the sprite
}
// Option
ShotData{
id = 3
rect = (0, 512, 256, 768)
render = ALPHA
alpha = 255
collision = 128 // Hitbox of arrows is not centered on the sprite
}
// Bomb
ShotData{
id = 4
rect = (0, 896, 512, 1408)
render = ADD_ARGB
angular_velocity = 5;
alpha = 255
collision = 160
}

View file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
2,0.57,,0.3442,,0.2691,0.3,0.2179,,0.3445,,,,,,,,,,,0.2992,,0.5139,,,1,,,,,,,masterVolume

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.