Author Topic: Danmakufu Q&A/Problem Thread  (Read 172145 times)

Tracedragon

Re: Danmakufu Q&A/Problem Thread
« Reply #150 on: June 15, 2009, 11:21:39 PM »
Hello. I have a question on Danmakufu in regards to bullet control.

Let us say that in a spellcard, I have:
Code: [Select]
CreateShot01(GetX, GetY, 1, GetAngleToPlayer, BLUE03, 0);And I want to change it so that it fires 03-type bullets in random alternating colors.
How would I go about doing this?

In a player script, I can use:
Code: [Select]
CreatePlayerShot01(GetPlayerX(), GetPlayerY(), 5, rand(1,5), 1, 2, rand(1,2));
However, used in a spellcard,
Code: [Select]
CreateShot01(GetX, GetY, 1, GetAngleToPlayer, rand(RED03, ORANGE03, YELLOW03, GREEN03, BLUE03, TEAL03, PURPLE03), 0);doesn't seem to work.

Any other ways I can go about doing this?

Drake

  • *
Re: Danmakufu Q&A/Problem Thread
« Reply #151 on: June 15, 2009, 11:55:44 PM »
Make an array.

let randcolor = [RED03, ORANGE03, YELLOW03, GREEN03, AQUA03, BLUE03, PURPLE03];
CreateShot01(GetX, GetY, 1, GetAngleToPlayer, randcolor[trunc(rand(0,6))], 0);

by the way it's aqua not teal


A Colorful Calculating Creative and Cuddly Crafty Callipygous Clever Commander
- original art by Aiけん | ウサホリ -

Cabblecorento

  • I'm a cat!
  • MEOW.
Re: Danmakufu Q&A/Problem Thread
« Reply #152 on: June 16, 2009, 12:04:32 AM »
This is really sad but,

how do you use the ascent function?

Also, how do you move your boss around?

CK Crash

  • boozer
Re: Danmakufu Q&A/Problem Thread
« Reply #153 on: June 16, 2009, 12:18:38 AM »
Ascent is basically the same as looping, but while increasing a variable each loop. You don't even need to declare the variable first with "let variable = number" or anything. For example...

ascent(shotspeed in 0..5)
{CreateShot01(GetX,GetY,2+shotspeed/2,GetAngleToPlayer,RED01,30);}

...would create a line of shots towards the player.

As for movement, check this page and look at the SetMovePosition functions. They are pretty self explanatory.

Drake

  • *
Re: Danmakufu Q&A/Problem Thread
« Reply #154 on: June 16, 2009, 12:19:05 AM »
ascent(x in y..z){

}

x is a new variable created only for the loop. It starts out as y, then when it reaches the end it increases by one until it equals z. y and z are numbers, obv.

A Colorful Calculating Creative and Cuddly Crafty Callipygous Clever Commander
- original art by Aiけん | ウサホリ -

Cabblecorento

  • I'm a cat!
  • MEOW.
Re: Danmakufu Q&A/Problem Thread
« Reply #155 on: June 16, 2009, 12:21:19 AM »
Thanks. Also, can you help me to get this to work?

Code: [Select]
#TouhouDanmakufu
#Title[how do I shot bullets?]
#Text[lol i dunno]
#Player[FREE]
#ScriptVersion[2]

script_enemy_main {
    let frame = 0;
    @Initialize {
        SetLife(100);
        SetEnemyMarker(true);
        SetDamageRate(3, 3);
    }

    @MainLoop {
        SetCollisionA(GetX, GetY, 32);
        SetCollisionB(GetX, GetY, 24);
        if(frame==99-GetEnemyLife()){
CreateShot01(GetX, GetY, 3, 0, RED01, 10);
CreateShot01(GetX, GetY, 3, 45, RED01, 10);
CreateShot01(GetX, GetY, 3, 90, RED01, 10);
CreateShot01(GetX, GetY, 3, 135, RED01, 10);
CreateShot01(GetX, GetY, 3, 180, RED01, 10);
CreateShot01(GetX, GetY, 3, 225, RED01, 10);
CreateShot01(GetX, GetY, 3, 270, RED01, 10);
CreateShot01(GetX, GetY, 3, 315, RED01, 10);
CreateShot01(GetX, GetY, 3, 360, RED01, 10);

CreateShot01(GetX, GetY, 6, 0, BLUE01, 10);
CreateShot01(GetX, GetY, 6, 45, BLUE01, 10);
CreateShot01(GetX, GetY, 6, 90, BLUE01, 10);
CreateShot01(GetX, GetY, 6, 135, BLUE01, 10);
CreateShot01(GetX, GetY, 6, 180, BLUE01, 10);
CreateShot01(GetX, GetY, 6, 225, BLUE01, 10);
CreateShot01(GetX, GetY, 6, 270, BLUE01, 10);
CreateShot01(GetX, GetY, 6, 315, BLUE01, 10);
CreateShot01(GetX, GetY, 6, 360, BLUE01, 10);
            frame = 0;
        }
        frame++;
    }

    @DrawLoop {       
    }

    @Finalize {
    }
}

It doesn't shoot out bullets for some reason.

Re: Danmakufu Q&A/Problem Thread
« Reply #156 on: June 16, 2009, 12:43:32 AM »
It will skip over the correct frame value. Remove "frame++;" from your mainloop and it might fire, but only a few times, provided the player characters don't do a decimal amount of damage, which is almost guarenteed. Truncate GetEnemyLife with:

trunc(GetEnemyLife);

...So that it will always be an integer, but even then the script won't fire bullets many times. I would just avoid GetEnemyLife, especially when used in conjunction with "==", because most of the time it will either be a decimal or skip over the value you're looking for. Use something like "<=" or ">=", but avoid adding and subtracting changing numbers because it's too hard to tell when bullets will shoot.

Actually, I would rethink how you want to approach this script, it'll take many an hour and headache to get it to work... If you even get that far.

Also, to Drake: rand_int(0, 6) is much easier to use than trunc(rand(0, 6)), for your records.

Hat

  • Just an unassuming chapeau.
  • I will never be ready.
Re: Danmakufu Q&A/Problem Thread
« Reply #157 on: June 16, 2009, 02:23:36 AM »
How do you set a global effect for a plural script? (e.g. a constant weak field of gravity for an entire bossfight... that's not at all what I want to use, but eh, it might be fun for somebody. I forget what I was actually trying to do... but yeah, halp?)

Re: Danmakufu Q&A/Problem Thread
« Reply #158 on: June 16, 2009, 03:02:40 AM »
Make it a stage script instead, but immediately call the plural script so that it acts the same as a plural. In the stage script you can make tasks to add effects like gravity and whatnot that are active throughout the battle.

Drake

  • *
Re: Danmakufu Q&A/Problem Thread
« Reply #159 on: June 16, 2009, 03:30:07 AM »
Also, to Drake: rand_int(0, 6) is much easier to use than trunc(rand(0, 6)), for your records.
Oh. I knew that, I just C+P from an old file.

A Colorful Calculating Creative and Cuddly Crafty Callipygous Clever Commander
- original art by Aiけん | ウサホリ -

Re: Danmakufu Q&A/Problem Thread
« Reply #160 on: June 16, 2009, 09:58:03 PM »
Is it possible to put variables within strings?

Drake

  • *
Re: Danmakufu Q&A/Problem Thread
« Reply #161 on: June 16, 2009, 10:00:07 PM »
string = "text" + variable + "text";

A Colorful Calculating Creative and Cuddly Crafty Callipygous Clever Commander
- original art by Aiけん | ウサホリ -

Re: Danmakufu Q&A/Problem Thread
« Reply #162 on: June 16, 2009, 10:17:35 PM »
You wish that worked.

Code: [Select]
#TouhouDanmakufu
#Title[ffffffftextfffffff]
#Text[ffffff]
#Player[FREE]
#ScriptVersion[2]

script_enemy_main {

let res = 0;
let strings;

    @Initialize {
        SetLife(6000);
        SetTimer(120);
        SetScore(1000000);
    }

    @MainLoop {
        SetCollisionA(GetX, GetY, 32);
        SetCollisionB(GetX, GetY, 16);
        yield;
        res++;
    }

    @DrawLoop {
strings = "Hi there " + res + " ffffff";
DrawText(strings, 37, 425, 12, 255);
    }

    @Finalize {
    }
}

No idea what I'm doing lalalala I hate drawing things in Danmakufu lalalala

Tracedragon

Re: Danmakufu Q&A/Problem Thread
« Reply #163 on: June 17, 2009, 12:06:33 AM »
Make it a stage script instead, but immediately call the plural script so that it acts the same as a plural. In the stage script you can make tasks to add effects like gravity and whatnot that are active throughout the battle.

Or you can include a common script function in each spellcard in the plural, if you really need it as a "plural". :P

Nuclear Cheese

  • Relax and enjoy the danmaku.
    • My homepage
Re: Danmakufu Q&A/Problem Thread
« Reply #164 on: June 17, 2009, 01:00:59 AM »
string = "text" + variable + "text";

Not sure if it works with non-string variables, but to concatenate strings you use the tilde (~), not the plus sign:

Code: [Select]
let string_a = "hello";
let string_b = "world";
let result = string_a ~ " " ~ string_b ~ "!";
to quote Naut:
"I can see the background, there are too many safespots."
:V

Re: Danmakufu Q&A/Problem Thread
« Reply #165 on: June 17, 2009, 02:32:05 AM »
Basically I was wondering if it was possible to do something like

ascent(i in 1..20){
   somethingsomestuffblahblahcode(ry... GetCurrentScriptDirectory ~ "i.png";}

I was thinking if there was a way so I can get the "i" in "i.png" to work with ascent so I don't have to take up 20 lines (or more) to load stuff.

Hat

  • Just an unassuming chapeau.
  • I will never be ready.
Re: Danmakufu Q&A/Problem Thread
« Reply #166 on: June 17, 2009, 02:53:34 AM »
Quick question wrt drawing functions. Supposing I wanted to do something like... Reimu-A's bomb from SA. How would I accomplish that scrolliness that the waves do? It takes one little 'ripple' graphic, then loops that, moving through these triangular 'windows'... eeh, go see it for yourself. oxo

Stuffman

  • *
  • We're having a ball!
Re: Danmakufu Q&A/Problem Thread
« Reply #167 on: June 17, 2009, 05:09:37 AM »
Mind you, I haven't actually tried this so this is theoretical, but I'm pretty sure this is how.

First you gotta make an effect object using PRIMITIVE_FAN. Vertex 0 should be in the center, and the other vertexes form the outside rim. Make sure vertex 1 and the last vertex touch to complete the shape.

Then you're gonna want to put some SetVertexUV shenanigans in a loop. Basically if you make a triangle with vertex 0 as one corner, the even vertexes as the second, and the odd vertexes as the third, you'll make a wedge of the image that gets patterned repeatedly around the center vertex. Then you scroll the positions of the SetVertexUV as the loop goes on, like just +1 to the y values each loop or something, and each wedge will repeat the scrolling image, and since they all scroll towards vertex 0 it'll create a vortexy thing. That oughta do it.


Nimono

  • wat
Re: Danmakufu Q&A/Problem Thread
« Reply #168 on: June 17, 2009, 07:06:56 PM »
Okay, I'm having some problems here. Really annoying ones. Okay, technically one single problem, but still...

Code: [Select]
script_enemy_main
{
#include_function "lib\SHOT_REPLACE\shot_replace.dnh"
let BossImage = GetCurrentScriptDirectory ~ "boss_remilia.png";
let BossCutIn = GetCurrentScriptDirectory ~ "Remilia.png";
let frame = -100;
let frame2 = -90;
let frame3 = -90;
let frame4 = -90;
let frame5 = -90;
let frame6 = -90;
let move = -240;
let anim_frame = 0;
let Angle = 90;
let Angle2 = 90;
//let ShotSFX = "script\sfx\shot.wav";
//let LaserSFX = "script\sfx\laser.wav";
let Movecount = 0;
let BAT = [0, 0, 0, 0, 0];

@Initialize
{
shotinit;
LoadGraphic(BossImage);
SetLife(2120);
SetTimer(32);
SetInvincibility(30);
SetEnemyMarker(true);
MagicCircle(false);
SetMovePosition02(GetCenterX, 90, 30);
}

@MainLoop
{
anim_frame++;
AddLife(GetCommonDataDefault("Life", 0));
SetCollisionA(GetX(),GetY(),32);
SetCollisionB(GetX(),GetY(),24);
if(move == 0)
{
if(Movecount == 0)
{
SetMovePosition02(120, 126, 30);
Movecount = 1;
}
else if(Movecount == 1)
{
SetMovePosition02(GetCenterX - 53, 105, 30);
Movecount = 2;
}
else if(Movecount == 2)
{
SetMovePosition02(GetCenterX, 90, 30);
Movecount = 0;
}
move = -160;
}
if(frame == 0)
{
if(Movecount == 0)
{
loop(20)
{
CreateShotA(0, GetX, GetY, 20);
CreateShotA(1, GetX, GetY, 20);
CreateShotA(2, GetX, GetY, 20);
SetShotDataA(0, 0, 3, Angle, 0, 0, 0, RED02);
SetShotDataA(1, 0, 3, Angle, 0, 0, 0, RED02);
SetShotDataA(2, 0, 3, Angle, 0, 0, 0, RED02);
SetShotDirectionType(PLAYER);
SetShotDataA(0, 20, 0, 0, 0, 0, 0, WHITE02);
SetShotDataA(1, 40, 0, 0, 0, 0, 0, WHITE02);
SetShotDataA(2, 60, 0, 0, 0, 0, 0, WHITE02);
SetShotDataA(0, 180, NULL, NULL, 0, 0.2, 5, RED02);
SetShotDataA(1, 140, NULL, NULL, 0, 0.2, 5, RED02);
SetShotDataA(2, 100, NULL, NULL, 0, 0.2, 5, RED02);
FireShot(0);
FireShot(1);
FireShot(2);
SetShotDirectionType(ABSOLUTE);
Angle += 18;
}
}
else if(Movecount == 1)
{
}
else if(Movecount == 2)
{
}
frame = -120;
}
if(frame2 == 0)
{
let array = [0, 40, 0];
BAT[0] = 1;
CreateEnemyFromFile(GetCurrentScriptDirectory ~ "Bat1.txt", GetX, GetY + 40, 0, 90, array);
frame2 = -90;
}
if(frame3 == 0)
{
BAT[1] = 1;
let array = [-25, 35, 1];
CreateEnemyFromFile(GetCurrentScriptDirectory ~ "Bat1.txt", GetX - 25, GetY + 35, 0, 90, array);
frame3 = -90;
}
if(frame4 == 0)
{
BAT[2] = 1;
let array = [25, 35, 2];
CreateEnemyFromFile(GetCurrentScriptDirectory ~ "Bat1.txt", GetX + 25, GetY + 35, 0, 90, array);
frame4 = -90;
}
if(frame5 == 0)
{
BAT[3] = 1;
let array = [-35, 20, 3];
CreateEnemyFromFile(GetCurrentScriptDirectory ~ "Bat1.txt", GetX - 35, GetY + 20, 0, 90, array);
frame5 = -90;
}
if(frame6 == 0)
{
BAT[4] = 1;
let array = [35, 20, 4];
CreateEnemyFromFile(GetCurrentScriptDirectory ~ "Bat1.txt", GetX + 35, GetY + 20, 0, 90, array);
frame6 = -90;
}
frame++;
move++;
if(BAT[0] == 0)
{
if(frame2 == -30)
{
CreateShotA(255, GetX, GetY + 40, 30);
SetShotDataA(255, 0, 0, 0, 0, 0, 0, WHITE02);
SetShotKillTime(255, 0);
FireShot(255);
}
frame2++;
}
if(BAT[1] == 0)
{
if(frame3 == -30)
{
CreateShotA(255, GetX - 25, GetY + 35, 30);
SetShotDataA(255, 0, 0, 0, 0, 0, 0, WHITE02);
SetShotKillTime(255, 0);
FireShot(255);
}
frame3++;
}
if(BAT[2] == 0)
{
if(frame4 == -30)
{
CreateShotA(255, GetX + 25, GetY + 35, 30);
SetShotDataA(255, 0, 0, 0, 0, 0, 0, WHITE02);
SetShotKillTime(255, 0);
FireShot(255);
}
frame4++;
}
if(BAT[3] == 0)
{
if(frame5 == -30)
{
CreateShotA(255, GetX - 35, GetY + 20, 30);
SetShotDataA(255, 0, 0, 0, 0, 0, 0, WHITE02);
SetShotKillTime(255, 0);
FireShot(255);
}
frame5++;
}
if(BAT[4] == 0)
{
if(frame6 == -30)
{
CreateShotA(255, GetX + 35, GetY + 20, 30);
SetShotDataA(255, 0, 0, 0, 0, 0, 0, WHITE02);
SetShotKillTime(255, 0);
FireShot(255);
}
frame6++;
}
if(GetCommonDataDefault("Fami1", 0) == 1)
{
BAT[0] = 0;
SetCommonData("Fami1", 0);
}
if(GetCommonDataDefault("Fami2", 0) == 1)
{
BAT[1] = 0;
SetCommonData("Fami2", 0);
}
if(GetCommonDataDefault("Fami3", 0) == 1)
{
BAT[2] = 0;
SetCommonData("Fami3", 0);
}
if(GetCommonDataDefault("Fami4", 0) == 1)
{
BAT[3] = 0;
SetCommonData("Fami4", 0);
}
if(GetCommonDataDefault("Fami5", 0) == 1)
{
BAT[4] = 0;
SetCommonData("Fami5", 0);
}
}

@DrawLoop
{
SetTexture(BossImage);
if(anim_frame >= 0 && anim_frame < 8)
{
if(GetSpeedX()==0)
{
SetGraphicRect(31,31,95,94);
}
else if(GetSpeedX()>0)
{
SetGraphicRect(286,415,352,478);
}
else if(GetSpeedX()<0)
{
SetGraphicRect(286,159,348,222);
}
}
if(anim_frame >= 8 && anim_frame < 16)
{
if(GetSpeedX()==0)
{
SetGraphicRect(31,159,95,222);
}
else if(GetSpeedX()>0)
{
SetGraphicRect(286,415,352,478);
}
else if(GetSpeedX()<0)
{
SetGraphicRect(286,159,348,222);
}
}
if(anim_frame >= 16 && anim_frame < 24)
{
if(GetSpeedX()==0)
{
SetGraphicRect(31,287,95,350);
}
else if(GetSpeedX()>0)
{
SetGraphicRect(286,415,352,478);
}
else if(GetSpeedX()<0)
{
SetGraphicRect(286,159,348,222);
}
}
if(anim_frame >= 24 && anim_frame < 32)
{
if(GetSpeedX()==0)
{
SetGraphicRect(31,415,95,478);
}
else if(GetSpeedX()>0)
{
SetGraphicRect(286,415,352,478);
}
else if(GetSpeedX()<0)
{
SetGraphicRect(286,159,348,222);
}
}
if(anim_frame >= 32)
{
anim_frame = 0;
}
DrawGraphic(GetX, GetY);
}

@Finalize
{
DeleteGraphic(BossImage);
}
}

Code: [Select]
script_enemy_main
{
#include_function "lib\SHOT_REPLACE\shot_replace.dnh"
let BossImage = GetCurrentScriptDirectory ~ "servant.png";
let frame = -30;
let frame2 = -30;
let anim_frame = 0;
let Angle = 0;
let Angle2 = 0;
let ShotSFX = "script\sfx\shot.wav";
let LaserSFX = "script\sfx\laser.wav";
let PrevLife = 200;

@Initialize
{
shotinit;
LoadGraphic(BossImage);
SetLife(200);
SetDamageRate(100, 100);
//SetDamageRateEx(100,100,100,40);
}

@MainLoop
{
SetCommonData("Life", GetLife() - PrevLife);
SetX(GetEnemyX + GetArgument[0]);
SetY(GetEnemyY + GetArgument[1]);
anim_frame++;
SetCollisionA(GetX(),GetY(),32);
SetCollisionB(GetX(),GetY(),24);
PrevLife = GetLife();
if(frame == 0)
{
if(GetArgument[2] == 0)
{
CreateShot01(GetX, GetY, 5, 90, RED05, 5);
}
if(GetArgument[2] == 1)
{
CreateShot01(GetX, GetY, 5, 87, RED11, 5);
CreateShot01(GetX, GetY, 5, 100, RED11, 5);
CreateShot01(GetX, GetY, 5, 115, RED11, 5);
}
if(GetArgument[2] == 2)
{
CreateShot01(GetX, GetY, 5, 93, RED11, 5);
CreateShot01(GetX, GetY, 5, 80, RED11, 5);
CreateShot01(GetX, GetY, 5, 65, RED11, 5);
}
if(GetArgument[2] == 3)
{
CreateShot01(GetX, GetY, 5, 115, RED11, 5);
CreateShot01(GetX, GetY, 5, 135, RED11, 5);
CreateShot01(GetX, GetY, 5, 157, RED11, 5);
}
if(GetArgument[2] == 4)
{
CreateShot01(GetX, GetY, 5, 65, RED11, 5);
CreateShot01(GetX, GetY, 5, 45, RED11, 5);
CreateShot01(GetX, GetY, 5, 22, RED11, 5);
}
frame = -10;
}
if(frame2 == 0)
{
if(GetArgument[2] == 0)
{
loop(6)
{
CreateShotA(0, GetX, GetY, 5);
SetShotDataA(0, 0, 5, Angle, 1, 0, 0, RED01);
SetShotDirectionType(PLAYER);
SetShotDataA(0, 30, 5, 0, 0, 0, 0, RED01);
FireShot(0);
SetShotDirectionType(ABSOLUTE);
Angle += 60;
}
}
frame2 = -30;
}
frame++;
frame2++;
}

@DrawLoop
{
SetTexture(BossImage);
if(anim_frame >= 0 && anim_frame < 8)
{
SetGraphicRect(1,40,31,56);
}
if(anim_frame >= 8 && anim_frame < 16)
{
SetGraphicRect(33,40,63,57);
}
if(anim_frame >= 16 && anim_frame < 24)
{
SetGraphicRect(65,40,95,57);
}
if(anim_frame >= 24 && anim_frame < 32)
{
SetGraphicRect(97,40,127,57);
}
if(anim_frame >= 32)
{
anim_frame = 0;
}
DrawGraphic(GetX, GetY);
}

@Finalize
{
if(GetArgument[2] == 0)
{
SetCommonData("Fami1", 1);
}
if(GetArgument[2] == 1)
{
SetCommonData("Fami2", 1);
}
if(GetArgument[2] == 2)
{
SetCommonData("Fami3", 1);
}
if(GetArgument[2] == 3)
{
SetCommonData("Fami4", 1);
}
if(GetArgument[2] == 4)
{
SetCommonData("Fami5", 1);
}
DeleteGraphic(BossImage);
}
}


(For the picture files, get them from CtC, as that's where the ones I'm using are from.)

Okay, so the problem is, no matter what I do, shooting the bats will NOT damage the boss. I started with SetDamageRateEx, as that worked with an enemy spawned by a spellcard I made, but that didn't do anything, so I decided to fall back to my old method of AddLife and Common Data, but THAT doesn't do anything, either! Like despite setting it, it's ALWAYS zero. I KNOW that it works, because it worked on that other enemy I previously mentioned, before I realized exactly what SetDamageRateEx did, but why is it not working for THIS enemy? I don't want the player to have to destroy the bats before they can hit Remilia, because that would pretty much MAKE them run out of time, because the bats are blocking your attacks on Remilia...thus, it takes far too long to be able to slightly hurt her. Help, please? (Also, there's a reason the life is 2120- it's a bit of a joke. Kudos to you if you can actually figure out its meaning. Without help.)


EDIT: I just realized why the AddLife method isn't working: Because I'm spawning five Bats! Each is returning 0 on life difference when not being attacked, so if you're not attacking all at once, you're not hurting Remilia! Easy fix! But I doubt that's why SetDamageRateEx is failing...
« Last Edit: June 17, 2009, 07:09:42 PM by pikaguy900 »

Nuclear Cheese

  • Relax and enjoy the danmaku.
    • My homepage
Re: Danmakufu Q&A/Problem Thread
« Reply #169 on: June 18, 2009, 01:14:57 AM »
Basically I was wondering if it was possible to do something like

ascent(i in 1..20){
   somethingsomestuffblahblahcode(ry... GetCurrentScriptDirectory ~ "i.png";}

I was thinking if there was a way so I can get the "i" in "i.png" to work with ascent so I don't have to take up 20 lines (or more) to load stuff.

I just played around with code for a few minutes, and here's the solution.  There's two pieces to it.

Piece 1: A function to get an integer to a string

You can normally translate a number to a string by using ToString().  However, that always leaves several decimal places, even if it doesn't need them (for instance, the number 1 gets written as "1.0000000" or such).

However, I wrote this little function to get only the part before the decimal point:

Code: [Select]
// IntString()
// Takes as an argument a single number.
// Returns the integer part of that number, as a string.
// By Nuclear Cheese
function IntString(number)
{
   let str = ToString(number);
   let str2 = "";
   let i = 0;
   while (str[i] != '.')
   {
      str2 = str2 ~ [str[i]];
      i++;
   }
   return(str2);
}

I think I first wrote this function for the (now defunct :-\) EoAD project we had going for a while.  Basically, you pass it a number, and it returns the string equivalent, without the decimal places.

Calling IntString(1) will return the string "1"

Note: in case you don't know, you put the function declaration (the above code) inside your script_enemy_main or script_stage_main, but outside of any of the more specific pieces such as @MainLoop ... so it looks something like this:
Code: [Select]
script_enemy_main
{
   function IntString()
   {
      // The above code.
   }

   @Initialize
   {
      // Setup stuff.
   }

   @MainLoop
   {
      // Fun stuff.
   }

   @DrawLoop
   {
      // Ooh shiny!
   }

   @Finalize
   {
      // Stuff go boom.
   }
}


Piece 2: Generating the file names

With the before piece of code in place, your code for creating the file names becomes something like this:

Code: [Select]
ascent (i in 1..20)
{
   let file_name = GetCurrentScriptDirectory() ~ IntString(i) ~ ".png";
   // do stuff with the file name
}

This will generate file names "1.png", "2.png", etc in the current directory, and then do whatever you need with them.


I hope this helps!
to quote Naut:
"I can see the background, there are too many safespots."
:V

Re: Danmakufu Q&A/Problem Thread
« Reply #170 on: June 18, 2009, 03:16:47 AM »
Basically I was wondering if it was possible to do something like

ascent(i in 1..20){
   somethingsomestuffblahblahcode(ry... GetCurrentScriptDirectory ~ "i.png";}

I was thinking if there was a way so I can get the "i" in "i.png" to work with ascent so I don't have to take up 20 lines (or more) to load stuff.

I just played around with code for a few minutes, and here's the solution.  There's two pieces to it.

Piece 1: A function to get an integer to a string

You can normally translate a number to a string by using ToString().  However, that always leaves several decimal places, even if it doesn't need them (for instance, the number 1 gets written as "1.0000000" or such).

However, I wrote this little function to get only the part before the decimal point:

Code: [Select]
// IntString()
// Takes as an argument a single number.
// Returns the integer part of that number, as a string.
// By Nuclear Cheese
function IntString(number)
{
   let str = ToString(number);
   let str2 = "";
   let i = 0;
   while (str[i] != '.')
   {
      str2 = str2 ~ [str[i]];
      i++;
   }
   return(str2);
}

I think I first wrote this function for the (now defunct :-\) EoAD project we had going for a while.  Basically, you pass it a number, and it returns the string equivalent, without the decimal places.

Calling IntString(1) will return the string "1"

Note: in case you don't know, you put the function declaration (the above code) inside your script_enemy_main or script_stage_main, but outside of any of the more specific pieces such as @MainLoop ... so it looks something like this:
Code: [Select]
script_enemy_main
{
   function IntString()
   {
      // The above code.
   }

   @Initialize
   {
      // Setup stuff.
   }

   @MainLoop
   {
      // Fun stuff.
   }

   @DrawLoop
   {
      // Ooh shiny!
   }

   @Finalize
   {
      // Stuff go boom.
   }
}


Piece 2: Generating the file names

With the before piece of code in place, your code for creating the file names becomes something like this:

Code: [Select]
ascent (i in 1..20)
{
   let file_name = GetCurrentScriptDirectory() ~ IntString(i) ~ ".png";
   // do stuff with the file name
}

This will generate file names "1.png", "2.png", etc in the current directory, and then do whatever you need with them.


I hope this helps!
Perfect :D


I wonder if it's possible to do something like this with varaible names as well...

Nimono

  • wat
Re: Danmakufu Q&A/Problem Thread
« Reply #171 on: June 18, 2009, 04:29:19 AM »
New question: Is there ANY way I can make BOTH the 3rd and last parameters of SetLaserDataA, related to angles, angle towards the player's location? For some reason, SetShotDirectionType(PLAYER) only affects the last parameter, which determines WHERE it goes! However, I also want the laser to be angled VISUALLY towards the player, too! Nothing I do will get me this. I can use atan2 and GetAngleToPlayer, but from what I heard, those only return correctly for these bullets and lasers (or at all, for that matter) on the exact frame you create them on! Therefore, I cannot find a single way to make the laser aim at the player. I want to avoid using objects if possible, though. Is there a way to use CreateLaserA and have both angles aim towards the player?

Stuffman

  • *
  • We're having a ball!
Re: Danmakufu Q&A/Problem Thread
« Reply #172 on: June 18, 2009, 04:50:02 AM »
SetShotDirectionType(PLAYER) is the only way to get CreateShot/LaserA to dynamically calculate the angle to the player, so if that doesn't work, no. You'll have to make an object laser.

Infy♫

  • Demonic★Moe
  • *
Re: Danmakufu Q&A/Problem Thread
« Reply #173 on: June 18, 2009, 03:47:34 PM »
is there any way i can use alpha values on images that are additive blended? I want to create something like reimu's shadow in IN. i use a task and i had to put the yield in the drawloop so when you press the spacebar all is screwed.

Nimono

  • wat
Re: Danmakufu Q&A/Problem Thread
« Reply #174 on: June 19, 2009, 05:52:03 PM »
SetShotDirectionType(PLAYER) is the only way to get CreateShot/LaserA to dynamically calculate the angle to the player, so if that doesn't work, no. You'll have to make an object laser.

Okay, I made the Object Laser, but I overlooked one thing: You can't set a speed on a laser. If you do, it ignores it. I need a way to make it move towards the player's position at the time it was thrown. I tried using the gravity thing that I asked for earlier in this thread, but every time I try to reverse any part of it to where it's affecting the ENEMY instead of the player, everything messes up! When used on this laser...

-If you're directly below the boss, nothing happens to the laser other than it centers on the boss's X, but the source goes behind the boss. What.
-If you're off in the far corners, the laser mysteriously vanishes.


Here's the script:

Code: [Select]
#TouhouDanmakufu
#Title[Scarlet Sign "Gungnir Windmill"]
#Text[]
#Image[]
#BackGround[Default]
#PlayLevel[]
#Player[FREE]
#ScriptVersion[2]

script_enemy_main
{
#include_function "lib\SHOT_REPLACE\shot_replace.dnh"
let BossImage = GetCurrentScriptDirectory ~ "boss_remilia.png";
let BossCutIn = GetCurrentScriptDirectory ~ "Remilia.png";
let frame = -100;
let frame2 = -100;
let anim_frame = 0;
let Angle = 90;
let Angle2 = 90;
let ShotSFX = "script\sfx\shot.wav";
let LaserSFX = "script\sfx\laser.wav";
let IsGungnir = false;
let Gungnir = [];
let IsThrow = false;
let Distance = 0;
let LasAng = 0;
let LasSpd = 2;

task GungnirSpin
{
let i = 0;
while (i < length(Gungnir))
{
if (Obj_BeDeleted(Gungnir[i]))
{
Gungnir = erase(Gungnir, i);
i--;
}
else if(IsThrow)
{
Obj_SetX(Gungnir[i], (GetX - (Distance - LasSpd)*cos(LasAng))); //LasSpd FOR X!
Obj_SetY(Gungnir[i],(GetY - (Distance - LasSpd)*sin(LasAng))); //LasSpd FOR Y!
}
else if(frame < 381 && frame > -1)
{
if(frame < 240)
{
Obj_SetAngle(Gungnir[i], Obj_GetAngle(Gungnir[i]) + 3);
}
if(frame == 240)
{
Obj_SetAngle(Gungnir[i], 270);
}
if(frame == 380)
{
LasAng = atan2(GetPlayerY - Obj_GetY(Gungnir[i]), GetPlayerX - Obj_GetX(Gungnir[i])); //ANGLE FORMULA!
Distance = ((Obj_GetX(Gungnir[i]) - GetPlayerX)^2 + (Obj_GetY(Gungnir[i] - GetPlayerY)^2)^0.5); //DISTANCE FORMULA!
Obj_SetAngle(Gungnir[i], atan2(GetPlayerY - Obj_GetY(Gungnir[i]), GetPlayerX - Obj_GetX(Gungnir[i])));
IsThrow = true;
}
}
i++;
}
}

@Initialize
{
shotinit;
LoadGraphic(BossImage);
SetLife(400);
SetDamageRate(10,5);
SetTimer(62);
SetInvincibility(30);
CutIn(YOUMU, "Devil Sign "\""Scarlet Streak"\", BossCutIn, 0, 0, 256, 320);
SetScore(70000);
SetEnemyMarker(true);
MagicCircle(true);
SetMovePosition02(GetCenterX,90,30);
CreateEnemyFromFile(GetCurrentScriptDirectory ~ "LaserEnem.txt", GetCenterX, GetCenterY, 0, 0, 0);
}

@MainLoop
{
GungnirSpin;
anim_frame++;
SetShotAutoDeleteClip(200, 200, 200, 200);
SetCollisionA(GetX(),GetY(),32);
SetCollisionB(GetX(),GetY(),24);
if(frame == 0)
{
IsGungnir = true;
let obj = Obj_Create(OBJ_LASER);
ObjLaser_SetLength(obj, 300);
ObjLaser_SetWidth(obj, 30);
Obj_SetPosition(obj, GetX+10, GetY-5);
Obj_SetAngle(obj, 270);
Gungnir = Gungnir ~ [obj];

}
if(frame2 == 380)
{
IsGungnir = false;
frame2 = -40;
}
frame++;
frame2++;
}

@DrawLoop
{
SetTexture(BossImage);
if(anim_frame >= 0 && anim_frame < 8)
{
if(GetSpeedX()==0 && !IsGungnir)
{
SetGraphicRect(31,31,95,94);
}
else if(GetSpeedX()>0 && !IsGungnir)
{
SetGraphicRect(286,415,352,478);
}
else if(GetSpeedX()<0 || IsGungnir)
{
SetGraphicRect(286,159,348,222);
}
}
if(anim_frame >= 8 && anim_frame < 16)
{
if(GetSpeedX()==0 && !IsGungnir)
{
SetGraphicRect(31,159,95,222);
}
else if(GetSpeedX()>0 && !IsGungnir)
{
SetGraphicRect(286,415,352,478);
}
else if(GetSpeedX()<0 || IsGungnir)
{
SetGraphicRect(286,159,348,222);
}
}
if(anim_frame >= 16 && anim_frame < 24)
{
if(GetSpeedX()==0 && !IsGungnir)
{
SetGraphicRect(31,287,95,350);
}
else if(GetSpeedX()>0 && !IsGungnir)
{
SetGraphicRect(286,415,352,478);
}
else if(GetSpeedX()<0 || IsGungnir)
{
SetGraphicRect(286,159,348,222);
}
}
if(anim_frame >= 24 && anim_frame < 32)
{
if(GetSpeedX()==0 && !IsGungnir)
{
SetGraphicRect(31,415,95,478);
}
else if(GetSpeedX()>0 && !IsGungnir)
{
SetGraphicRect(286,415,352,478);
}
else if(GetSpeedX()<0 || IsGungnir)
{
SetGraphicRect(286,159,348,222);
}
}
if(anim_frame >= 32)
{
anim_frame = 0;
}
DrawGraphic(GetX, GetY);
}

@Finalize
{
DeleteGraphic(BossImage);
}
}

The enemy that comes with it can be ignored if you choose, but here's its code, anyways:

Code: [Select]
script_enemy_main
{
#include_function "lib\SHOT_REPLACE\shot_replace.dnh"
let BossImage = GetCurrentScriptDirectory ~ "servant.png";
let frame = -60;
let frame2 = -120;
let Angle = 60;
let Angle2 = 0;
let ShotSFX = "script\sfx\shot.wav";
let LaserSFX = "script\sfx\laser.wav";

@Initialize
{
shotinit;
LoadGraphic(BossImage);
SetLife(200);
SetDamageRate(100, 100);
}

@MainLoop
{
if(frame == 0)
{
CreateLaserB(0, 200, 20, RED01, 60);
SetLaserDataB(0, 0, 0, 100, 0, 60, 2, 208, 2);
FireShot(0);

CreateLaserB(1, 200, 20, RED01, 60);
SetLaserDataB(1, 0, 0, 100, 0, 180, 2, 328, 2);
FireShot(1);

CreateLaserB(2, 200, 20, RED01, 60);
SetLaserDataB(2, 0, 0, 100, 0, 300, 2, 88, 2);
FireShot(2);
}
if(frame2 == 0)
{
CreateShotA(0, GetX, GetY, 5);
SetShotDataA(0, 0, 4, Angle, -1, 0, 0, SP02);
CreateShotA(1, GetX, GetY, 5);
SetShotDataA(1, 0, 4, Angle+120, -1, 0, 0, SP02);
CreateShotA(2, GetX, GetY, 5);
SetShotDataA(2, 0, 4, Angle+240, -1, 0, 0, SP02);
SetShotKillTime(0, 360);
SetShotKillTime(1, 360);
SetShotKillTime(2, 360);
FireShot(0);
FireShot(1);
FireShot(2);
Angle += 13;
frame2 = -3;
}
frame++;
frame2++;
}

@DrawLoop
{
SetTexture(BossImage);
SetGraphicRect(7,165,8,166);
DrawGraphic(GetX, GetY);
}

@Finalize
{
DeleteGraphic(BossImage);
}
}

I'd appreciate ANY help you can give me on getting this to throw at the player at a certain speed (I want speed 8 here). Thanks...

randomdragoon

Re: Danmakufu Q&A/Problem Thread
« Reply #175 on: June 19, 2009, 07:05:15 PM »
SetShotDirectionType(PLAYER) is the only way to get CreateShot/LaserA to dynamically calculate the angle to the player, so if that doesn't work, no. You'll have to make an object laser.

You can use atan2(Y-GetPlayerY, GetPlayerX-X) to dynamically get the direction to the player, no? Where X and Y are the coordinates where the bullet starts from.

Iryan

  • Ph?nglui mglw?nafh
  • Cat R?lyeh wgah?nagl fhtagn.
Re: Danmakufu Q&A/Problem Thread
« Reply #176 on: June 19, 2009, 10:57:49 PM »
You can use atan2(Y-GetPlayerY, GetPlayerX-X) to dynamically get the direction to the player, no? Where X and Y are the coordinates where the bullet starts from.
Not with SetShotDataA. It will always give you the angle for the time the bulelt is fired, not for the time when this angle should actually be evaluated.


@ Pikaguy:
Simple.
obj=id of the object
v=movement speed
ang=movement angle

Put this in the while loop:
Code: [Select]
Obj_SetPosition(obj, Obj_GetX(obj)+v*cos(ang),  Obj_GetY(obj)+v*sin(ang));
That should work.  ;)
Old Danmakufu stuff can be found here!

"As the size of an explosion increases, the numbers of social situations it is incapable of solving approaches zero."

Nimono

  • wat
Re: Danmakufu Q&A/Problem Thread
« Reply #177 on: June 20, 2009, 12:22:51 AM »
@ Pikaguy:
Simple.
obj=id of the object
v=movement speed
ang=movement angle

Put this in the while loop:
Code: [Select]
Obj_SetPosition(obj, Obj_GetX(obj)+v*cos(ang),  Obj_GetY(obj)+v*sin(ang));
That should work.  ;)

Oh wow, and I actually already had that code from when I tried to spin things around a point. Never realized I could use it like THAT. ...nor did I even think to use it at all in this situation... I'll remember this for the next time I need to manually move something to a specific point. Thanks!

Nimono

  • wat
Re: Danmakufu Q&A/Problem Thread
« Reply #178 on: June 21, 2009, 11:02:16 PM »
Sorry to doublepost, but I need help badly...

Code: [Select]
#TouhouDanmakufu
#Title[Red Magic]
#Text[]
#Image[]
#BackGround[Default]
#PlayLevel[]
#Player[FREE]
#ScriptVersion[2]

script_enemy_main
{
#include_function "lib\SHOT_REPLACE\shot_replace.dnh"
let BossImage = GetCurrentScriptDirectory ~ "boss_remilia.png";
let BossCutIn = GetCurrentScriptDirectory ~ "Remilia.png";
let frame = -100;
let frame2 = -100;
let frame3 = -100;
let frame4 = -100;
let frame5 = -100;
let anim_frame = 0;
let Angle = 0;
let Angle2 = 0;
let Angle3 = 0;
let Timer = [];
let Wave = [];
let ShotSFX = "script\sfx\se_tan00.wav";
let LaserSFX = "script\sfx\se_lazer00.wav";
let RedMagic = [];
let RedMagic2 = [];
let Bounce = [];
let DoRedMagic = false;
let Count = -1;
let yes = 0;

task Reflect
{
let i = 0;
while (i < length(RedMagic))
{
if (Obj_BeDeleted(RedMagic[i]))
{
RedMagic = erase(RedMagic, i);
Bounce = erase(Bounce, i);
Timer = erase(Timer, i);
i--;
}
else if(Bounce[i] > 0)
{
if(Obj_GetX(RedMagic[i]) <= GetClipMinX() || Obj_GetX(RedMagic[i]) >= GetClipMaxX())
{
Obj_SetAngle(RedMagic[i], 180-Obj_GetAngle(RedMagic[i]));
Bounce[i] = Bounce[i] - 1;
}
if(Obj_GetY(RedMagic[i]) <= GetClipMinY() || Obj_GetY(RedMagic[i]) >= GetClipMaxY())
{
Obj_SetAngle(RedMagic[i], 360-Obj_GetAngle(RedMagic[i]));
Bounce[i] = Bounce[i] - 1;
}
if(frame4%15 == 0)
{
if(Timer[i] < 15)
{
Timer[i] = 138;
}
let obj = Obj_Create(OBJ_SHOT);
Obj_SetPosition(obj, Obj_GetX(RedMagic[i]), Obj_GetY(RedMagic[i]));
Obj_SetAngle(obj, (Angle + Angle2) + Angle3);
Obj_SetSpeed(obj, 0);
ObjShot_SetDelay(obj, 40);
ObjLaser_SetWidth(obj, Count);
ObjShot_SetGraphic(obj, RED01);
RedMagic2 = RedMagic2 ~ [obj];
if(Timer[i] > 108 && Count > 0)
{
Wave = Wave ~ [Count-1];
}
else{Wave = Wave ~ [Count];}
Angle3 += 2;
Timer[i] =  Timer[i] - 15;
}
}
i++;
}
}

task Red
{
let i = 0;
while (i < length(RedMagic2))
{
if(Wave[i] != Count)
{
yes = Wave[i];
}
if (Obj_BeDeleted(RedMagic2[i]) || frame5 == 210)
{
RedMagic2 = erase(RedMagic2, i);
Wave = erase(Wave, i);
i--;
}
else if(frame5 >= 180 && Wave[i] == Count - 1)
{
if(frame5 < 210)
{
Obj_SetAngle(RedMagic2[i], Obj_GetAngle(RedMagic2[i]) + 3);
}
if(Obj_GetSpeed(RedMagic2[i]) < 1)
{
Obj_SetSpeed(RedMagic2[i], Obj_GetSpeed(RedMagic2[i]) + 0.2);
}
}
i++;
}
}

@Initialize
{
shotinit;
LoadGraphic(BossImage);
SetLife(1000);
SetDamageRate(10,5);
SetTimer(202);
SetInvincibility(30);
CutIn(YOUMU, "Red Magic", BossCutIn, 0, 0, 256, 320);
SetScore(70000);
SetEnemyMarker(true);
MagicCircle(true);
SetMovePosition02(GetCenterX,90,30);
}

@MainLoop
{
Reflect;
Red;
anim_frame++;
SetCollisionA(GetX(),GetY(),32);
SetCollisionB(GetX(),GetY(),24);
if(frame2 == 0)
{
Count++;
loop(10)
{
let obj = Obj_Create(OBJ_SHOT);
Obj_SetPosition(obj, GetX, GetY);
Obj_SetAngle(obj, Angle + Angle2);
Obj_SetSpeed(obj, 2);
ObjShot_SetGraphic(obj, PURPLE03);
RedMagic = RedMagic ~ [obj];
Bounce = Bounce ~ [1];
Timer = Timer ~ [138];
Angle += 36;
}
let obj = Obj_Create(OBJ_SHOT);
Obj_SetPosition(obj, GetX, GetY);
Obj_SetAngle(obj, Angle);
Obj_SetSpeed(obj, 0);
ObjShot_SetDelay(obj, 30);
ObjShot_SetGraphic(obj, RED01);
RedMagic2 = RedMagic2 ~ [obj];
if(Count == 0)
{
Wave = Wave ~ [Count-1];
}
else{Wave = Wave ~ [Count];}
Angle2 += 7;
frame2 = -180;
SetMovePositionRandom01(65, 20, 10, GetClipMinX + 50, GetClipMinY + 50, GetClipMaxX - 50, GetClipMinY + 170);
}
if(frame5 == 210)
{
frame5 = 30;
}
frame++;
frame2++;
frame3++;
frame4++;
frame5++;
}

@DrawLoop
{
SetTexture(BossImage);
if(anim_frame >= 0 && anim_frame < 8)
{
if(GetSpeedX()==0)
{
SetGraphicRect(31,31,95,94);
}
else if(GetSpeedX()>0)
{
SetGraphicRect(286,415,352,478);
}
else if(GetSpeedX()<0)
{
SetGraphicRect(286,159,348,222);
}
}
if(anim_frame >= 8 && anim_frame < 16)
{
if(GetSpeedX()==0)
{
SetGraphicRect(31,159,95,222);
}
else if(GetSpeedX()>0)
{
SetGraphicRect(286,415,352,478);
}
else if(GetSpeedX()<0)
{
SetGraphicRect(286,159,348,222);
}
}
if(anim_frame >= 16 && anim_frame < 24)
{
if(GetSpeedX()==0)
{
SetGraphicRect(31,287,95,350);
}
else if(GetSpeedX()>0)
{
SetGraphicRect(286,415,352,478);
}
else if(GetSpeedX()<0)
{
SetGraphicRect(286,159,348,222);
}
}
if(anim_frame >= 24 && anim_frame < 32)
{
if(GetSpeedX()==0)
{
SetGraphicRect(31,415,95,478);
}
else if(GetSpeedX()>0)
{
SetGraphicRect(286,415,352,478);
}
else if(GetSpeedX()<0)
{
SetGraphicRect(286,159,348,222);
}
}
if(anim_frame >= 32)
{
anim_frame = 0;
}
DrawGraphic(GetX, GetY);
DrawText(ToString(yes), GetPlayerX + 20, GetPlayerY, 15, 255);
}

@Finalize
{
DeleteGraphic(BossImage);
}
}

I'm trying to copy Red Magic, as you can see, though I don't care about it being perfect. (Too many people may have great experience foiling Red Magic, after all!) Anyways, my problem is that Count variable. Despite the debug DrawText I used (I picked "yes" as a variable for no reason whatsoever), I cannot pinpoint the problem... See, I'm using Count as a wave counter, so bullets from the previous wave don't change angles when the next wave moves, if they're still onscreen at that time. However, when the next wave is spawned, the inner 2 or 3 rings, counting the center bullet, DON'T MOVE! I can't figure out why! I seriously need help with this, please!

Re: Danmakufu Q&A/Problem Thread
« Reply #179 on: June 21, 2009, 11:49:55 PM »
The last few bullets of a wave will also not move on occasion, if that helps your debugging process. I can't see the problem either, though I'm having a hard time wrapping my head around the cavalcade of arrays you've constructed...