PDA

View Full Version : Fire Rod



Lelouche Vi Britannia
09-23-2017, 06:31 PM
I'm going to attempt to create a proper fire rod item, before I do I was wondering if someone already did this. Would save me the trouble.

Lelouche Vi Britannia
09-23-2017, 10:43 PM
Ok so here is the data from my first attempt.



const int BOLT_NOUSE = 64;//1 second pause
const int FLIP_NO = 0;//no flipping
const int FLIP_H = 1;//Flip Horrizontal
const int FLIP_V = 2;//Flip Vertical
const int FLIP_B = 3;//Rotate 180 degrees
const int BOLTCSET_NF = 6;
const int BOLTCSET_F = 0;

item script BoltSpell //basic use a wand and cast a spell stuff
{
void run(int power, int arrowSprite, int speed, int wandSprite)
{
int startX;
int startY;
lweapon l;
lweapon bolt;
startX = Link->X+8;
startY = Link->Y+4;
Link->Action = LA_ATTACKING;
l = NextToLink(LW_WAND,8);
l->Tile = wandSprite;
if (Link->Dir == DIR_UP)
{
l->Flip = FLIP_NO;
}
if (Link->Dir == DIR_DOWN)
{
l->Flip = FLIP_V;
}
if (Link->Dir == DIR_RIGHT)
{
l->Tile++;
l->Flip = FLIP_NO;
}
if (Link->Dir == DIR_LEFT)
{
l->Tile++;
l->Flip = FLIP_H;
}
bolt = NextToLink(LW_ARROW, 8);
bolt->UseSprite(arrowSprite);
if (Link->Dir == DIR_UP)
{
bolt->Flip = FLIP_NO;
}
if (Link->Dir == DIR_DOWN)
{
bolt->Flip = FLIP_V;
}
if (Link->Dir == DIR_RIGHT)
{
bolt->Tile++;
bolt->Flip = FLIP_NO;
}
if (Link->Dir == DIR_LEFT)
{
bolt->Tile++;
bolt->Flip = FLIP_H;
}
bolt->Damage = power;
bolt->Step = speed;
Link->ItemJinx = BOLT_NOUSE;
}
}


Problem 1: The wand is being rendered too high vertically on Link's spirte. I compared it to the sword location and it appears to be a good 6 pixels or so higher (about nose level instead of hand level). I tried reducing the Y position to +4 from +8 (line 18), but that had no visual effect at all on the placement of the sprite. How do I fix this so it looks like a normal use of the wand?

Problem 2: Not sure if this is possible but can the damage type of the attack be changed to fire? This is supposed to be a fire rod after all. Also would like to know how to get the bolt to render an actual flame at the impact point.

Next Steps: Currently contemplating using an advanced dark room script to make LttP style braziers. I thought it would be possible to allow the Fire Rod to light them either by using an invulnerable enemy that is invisible set on the brazier. However the thought also occurred that this would probably work better as an FFC script but I am rubbish at those currently.

Currently for the "Next Steps" portion I am considering using the "Subpar Dark Room Script" found on Pure, unless someone could suggest a better one?

ywkls
09-23-2017, 11:09 PM
I'm surprised that worked at all. Unless you're using 2.50.3. (In which case, I want to start working with it ASAP.)

Normally, you can't make LW_WAND via script. The best functions for placing an item, lweapon, etc. near Link are InFrontX and InFrontY. (They're in stdfunctions)

That'd look something like this...


lweapon wand;
wand->X=Link->X+InFrontX(Link->Dir,2);
wand->Y= Link->Y+InFrontY(Link->Dir,2);


The placement of the sprite may be due to the sprite itself.

As for enemy defenses, that's another matter entirely. It's not really possible without some heavy duty engine-level scripting to make it where a LWeapon is one type but does damage to an enemy based on a different type of defense.

I have a custom script header in the works which does a lot of this sort of thing automatically if you want to try and make sense of it.
It can be found here (https://www.purezc.net/forums/index.php?showtopic=70518).

It has a custom fire rod included, though it doesn't always make fire as it should (and doesn't do that enemy defense thing).

ZoriaRPG
09-24-2017, 02:35 AM
Ok so here is the data from my first attempt.



const int BOLT_NOUSE = 64;//1 second pause
const int FLIP_NO = 0;//no flipping
const int FLIP_H = 1;//Flip Horrizontal
const int FLIP_V = 2;//Flip Vertical
const int FLIP_B = 3;//Rotate 180 degrees
const int BOLTCSET_NF = 6;
const int BOLTCSET_F = 0;

item script BoltSpell //basic use a wand and cast a spell stuff
{
void run(int power, int arrowSprite, int speed, int wandSprite)
{
int startX;
int startY;
lweapon l;
lweapon bolt;
startX = Link->X+8;
startY = Link->Y+4;
Link->Action = LA_ATTACKING;
l = NextToLink(LW_WAND,8);
l->Tile = wandSprite;
if (Link->Dir == DIR_UP)
{
l->Flip = FLIP_NO;
}
if (Link->Dir == DIR_DOWN)
{
l->Flip = FLIP_V;
}
if (Link->Dir == DIR_RIGHT)
{
l->Tile++;
l->Flip = FLIP_NO;
}
if (Link->Dir == DIR_LEFT)
{
l->Tile++;
l->Flip = FLIP_H;
}
bolt = NextToLink(LW_ARROW, 8);
bolt->UseSprite(arrowSprite);
if (Link->Dir == DIR_UP)
{
bolt->Flip = FLIP_NO;
}
if (Link->Dir == DIR_DOWN)
{
bolt->Flip = FLIP_V;
}
if (Link->Dir == DIR_RIGHT)
{
bolt->Tile++;
bolt->Flip = FLIP_NO;
}
if (Link->Dir == DIR_LEFT)
{
bolt->Tile++;
bolt->Flip = FLIP_H;
}
bolt->Damage = power;
bolt->Step = speed;
Link->ItemJinx = BOLT_NOUSE;
}
}


Problem 1: The wand is being rendered too high vertically on Link's spirte. I compared it to the sword location and it appears to be a good 6 pixels or so higher (about nose level instead of hand level). I tried reducing the Y position to +4 from +8 (line 18), but that had no visual effect at all on the placement of the sprite. How do I fix this so it looks like a normal use of the wand?

Problem 2: Not sure if this is possible but can the damage type of the attack be changed to fire? This is supposed to be a fire rod after all. Also would like to know how to get the bolt to render an actual flame at the impact point.

Next Steps: Currently contemplating using an advanced dark room script to make LttP style braziers. I thought it would be possible to allow the Fire Rod to light them either by using an invulnerable enemy that is invisible set on the brazier. However the thought also occurred that this would probably work better as an FFC script but I am rubbish at those currently.

Currently for the "Next Steps" portion I am considering using the "Subpar Dark Room Script" found on Pure, unless someone could suggest a better one?



In general, you want LW_SCRIPT for this, or LW_BEAM, or even LW_REFMAGIC.

There was a recent request on Pure for this sort of thing, but I frankly do not want to do it until 2.54 is out, and I can make it both cleaner, and easier.

ZoriaRPG
09-24-2017, 03:24 AM
This is the general idea for how I do this type of thing in 2.50.x:



////////////////////////////
/// Simple Firerod ///
/// v0.2 ///
/// By: ZoriaRPG ///
/// 24th September, 2017 ///
////////////////////////////
/// Note: All of this is ugly. In 2.54, you will be able to set NPCs to specific script defences, so you can use a real
/// FLAME weapon that you set up, and 2.54 may add SCRIPT weapon triggers to combos, as well.


int LightSources[3120]; //All the light source metrics for drawing, per frame.
//x, y, diameter: 176 combos * 3 layers, (255 weapons * 2) * 3

//Settings
const int LW_CUST_FLAME = 31; //Script 1
const int FIREROD_MIN_STEP = 100;
const int FIREROD_DAMAGE = 4;
const int FIREROD_MISC_INDEX = 1;
const int FIREROD_FLAME_FLAG = 00001000b;
const int FIREROD_FLAME_SPRITE = 89;
const int BLANK_FIRE_SPRITE = 90; //Should be a blank tile sprite.

//The diameter of the light source for combos.
const int LIGHT_SOURCE_COMBO_RADIUS_MIN = 29;
const int LIGHT_SOURCE_COMBO_RADIUS_MAX = 33;
//The diameter of the light source for weapons.
const int LIGHT_SOURCE_WPN_RADIUS_MIN = 22;
const int LIGHT_SOURCE_WPN_RADIUS_MAX = 26;

const int BITMAP_DARKNESS = 2; //The bitmap ID to use for the darkness effect.
const int DARKROOM_LAYER = 7; //The layer to blit the output bitmap.
const int COLOUR_BLACK = 0x0F; //A black colour swatch in your palette.

const int LIGHT_SOURCE_CIRCLE_SCALE = 1; //Scale and layer args for the colour-0 circles.
const int LIGHT_SOURCE_CIRCLE_LAYER = 0;

item script BasicFireRod{
void run(int sprite, int damage, int step_speed){
Link->Action = LA_ATTACKING;
lweapon flame = Screen->CreateLWeapon(LW_CUST_FLAME);
flame->X = Link->X;
flame->Y = Link->Y;
flame->UseSprite = Cond(sprite > 0, sprite, FIREROD_FLAME_SPRITE);
flame->Dir = Link->Dir;
if ( Link->Dir == DIR_UP ) {
flame->Y -= 16;
}
if ( Link->Dir == DIR_DOWN ) {
flame->Flip = FLIP_VERTICAL;
flame->Y += 16;

}
if ( Link->Dir == DIR_RIGHT ) {
flame->Flip = ROT_CCW;
flame->X += 16;
}
if ( Link->Dir = DIR_RIGHT ) {
flame->Flip = ROT_CW;
flame->X -= 16;
}
//Ternary would help here, as it would jus tbe:
//flame->Step = step_speed > 0 ? step_speed : FIREROD_MIN_STEP;
//sigh.
flame->Step = Cond(step_speed > 0, step_speed, FIREROD_MIN_STEP);
flame->Damage = Cond(damage > 0, damage, FIREROD_DAMAGE);
//! Damage is forwarded to the real fire weapon via the global active script.
flame->Misc[FIREROD_MISC_INDEX] |= FIREROD_FLAME_FLAG; //Mark it for detection.
flame->HitYOffset = -214747; //Move the true hitbox offscreen so that it cannot trigger or hit anything.
//! The global active script handles real collisions.
}
}

//Returns true if the combo at '(x, y)' has either an inherent or place flag of type 'flag'
bool ____LayerComboFI(int pos, int flag, int layer){
return GetLayerComboF(layer,pos) == flag || GetLayerComboI(layer,pos) == flag;
}



//Call before Waitdraw.
void DoFireRod(){
int cmb_pos; bool makeflame; int flags[3]={CF_CANDLE1, CF_CANDLE2};
for ( int q = Screen->NumLWeapons(); q > 0; q-- ) {
lweapon l = Screen->LoadLWeapon(q);
if ( l->ID == LW_CUST_FLAME ){
if ( l->Misc[FIREROD_MISC_INDEX]&FIREROD_FLAME_FLAG ) {
//We make a real dire weapon on top of fire trigger combos.
cmb_pos = ComboAt(l->X, l->X);
for ( int q = 0; q < 3; q++ ) {
for ( int w = 0; w < 2; w++ ) {
if ( ____LayerComboFI(pos, flags[w] , layer ) ) {
lweapon makefire = Screen->CreateLWeapon(LW_FIRE);
makefire->X = ComboX(cmb_pos);
makefire->Y = ComboY(cmb_pos);
makefire->UseSprite = BLANK_FIRE_SPRITE;
SetLayerComboF(LAYER_TORCH_FLAG, cmb_pos, CF_LIT_TORCH);
}
}
}
//Make fire weapon on enemies on collision if the enemy has its hitbox enabled, and on-screen.
for ( int e = Screen->NumNPCs(); e > 0; e-- ) {
npc n = Screen->LoadNPC(e);
if ( !n->CollDetection ) continue;
if ( n->HitXOffset < 0 ) continue;
if ( n->HitXOffset > 255 ) continue;
if ( n->HitYOffset < 0 ) continue;
if ( n->HitYOffset > 255 ) continue;
if ( Collision(l,e) ){
lweapon makefire = Screen->CreateLWeapon(LW_FIRE);
makefire->Damage = l->Damage;
makefire->X = n->X + n->HitXOffset;
makefire->Y = n->Y + n->HitYOffset;
Remove(l); //Remove the fire rod object.
//Fire weapons on enemies should be real gfx.
//makefire->UseSprite = BLANK_FIRE_SPRITE;
}
}
}
}
}
}

const int CF_LIT_TORCH = 99; //script 2.
const int LAYER_TORCH_FLAG = 0; //Look for them on his layer.


//Call before Waitdraw()
//DarkDroom(DARKROOM_LAYER, false, BITMAP_DARKNESS);
void DarkRoom(int layer, bool trans, int bitmap_id)
{
int q[16]; int src; int cnt;
int lightsourceflags[]={CF_LIT_TORCH};
q[9] = SizeOfArray(lightsourceflags);
int lightsourceflaglayers[]={LAYER_TORCH_FLAG};
q[15] = SizeOfArray(lightsourceflaglayers);

for ( q[10] = SizeOfArray(LightSources); q[10] >= 0; q[10]-- ) { LightSources[ q[10] ] = -1; } //Wipe it every frame.
Screen->SetRendertarget(bitmap_id);
Screen->Rectangle(layer, 0, 0, 256, 256, COLOUR_BLACK, 100, 0, 0, 0, true, OP_OPAQUE);
//Add light sources to the array for combos.
for ( q[0] = 0; q[0] < q[15]; q[0]++ )
{
//Check for light sources on layers
for ( q[1] = 0; q[1] < 176; q[1]++ )
{
//check all positions.
for ( q[2] = 0; q[2] < q[9]; q[2]++ )
{ //and all flags
if ( ____LayerComboFI(q[1], lightsourceflags[ q[2] ], lightsourceflaglayers[ [q[0] ] )
{
LightSources[src] = ComboX(q[1]);
LightSources[src+1] = ComboY(q[1]);
LightSources[src+2] = Rand(LIGHT_SOURCE_COMBO_RADIUS_MIN, LIGHT_SOURCE_COMBO_RADIUS_MAX);
cnt++;
src+=3;
}
}
}
}
//add light sources to the array for weapons
for ( q[4] = Screen->NumLWeapons(); q[4] > 0; q[4] -- )
{
lweapon l = Screen->LoadLWeapon[q[4]];
//for special fire rod weapons
if ( l->ID == LW_CUST_FLAME )
{
LightSources[src] = l->X + 8;
LightSources[src+1] = l->Y + 8;
LightSources[src+2] = Rand(LIGHT_SOURCE_WPN_RADIUS_MIN, LIGHT_SOURCE_WPN_RADIUS_MAX);
cnt++;
src+=3;
}
//for fire weapons that are not dummy weapons
if ( l->ID == LW_FIRE )
{
if ( l->UseSprite != BLANK_FIRE_SPRITE )
{
LightSources[src] = l->X + 8;
LightSources[src+1] = l->Y + 8;
LightSources[src+2] = Rand(LIGHT_SOURCE_WPN_RADIUS_MIN, LIGHT_SOURCE_WPN_RADIUS_MAX);
cnt++;
src+=3;
}
}
}

q[13] = cnt*3;
//Draw all light sources to the bitmap.
for ( q[12] = 0; q[12] <= q[13]; q[12] += 3 )
{
Screen->Circle(LIGHT_SOURCE_CIRCLE_LAYER, LightSources[ q[12] ], LightSources[ q[12] ]+1, LightSources[ q[12] ]+2, 0, LIGHT_SOURCE_CIRCLE_SCALE,
0,0,0, true, OP_OPAQUE);
if ( LightSources[ q[12] ] == -1 ) break; //Sanity check.
}

//! Blits
Screen->SetRenderTarget(RT_SCREEN);
// if ( trans ) //2.54+ stuff t/b/a
// {
// Screen->DrawBitmapEx()
// }
// else {
Screen->DrawBitmap(layer, bitmap_id, 0, 0, 256, 176, 0, 0, 256, 176, 0, true);
}





Keep an eye on this, if you want updates:

https://github.com/ZoriaRPG/Zelda3.zh/blob/master/Firerod.zs

Lelouche Vi Britannia
09-24-2017, 10:45 AM
Sounds like some exciting changes are coming in 2.54 that will make everyone's lives easier.

Code as it is doesn't compile, copied from the link you left. Not sure if its a version thing or a syntax thing. Made an attempt to fix it and ran into more errors. Seems to be syntax.

ZoriaRPG
09-24-2017, 11:22 AM
Sounds like some exciting changes are coming in 2.54 that will make everyone's lives easier.

Code as it is doesn't compile, copied from the link you left. Not sure if its a version thing or a syntax thing. Made an attempt to fix it and ran into more errors. Seems to be syntax.

IDK if you compiled the latest. I expect errors as this is pretty long, and I rewrote it from scratch today, based on the formula that I used in the past. You will have a number of errors if you are not using 2.53 though, as it relies on std.zh stuff such as FLIP_ and ROT_ . It'll give you missing identifiers for those, and then syntactical stuff, might follow.

For the most part, I wanted to outline it, and push it to the Z3 template package. I can fix it, or update it, later, but you can always have a look at how I did things and try to implement them on your own, if you wish. I have been putting this off because I wanted to make it for the Z3 package, which will use 2.54 or above for quite a lot. Nothing in it is 2.54-specific though, unless the array usage is a problem. I'll load it and see what happens.

Here is a version free of compiler errors:



////////////////////////////
/// Simple Firerod ///
/// v0.3 ///
/// By: ZoriaRPG ///
/// 24th September, 2017 ///
////////////////////////////
/// Note: All of this is ugly. In 2.54, you will be able to set NPCs to specific script defences, so you can use a real
/// FLAME weapon that you set up, and 2.54 may add SCRIPT weapon triggers to combos, as well.


int LightSources[3120]; //All the light source metrics for drawing, per frame.
//x, y, diameter: 176 combos * 3 layers, (255 weapons * 2) * 3

//Settings
const int LW_CUST_FLAME = 31; //Script 1
const int FIREROD_MIN_STEP = 100;
const int FIREROD_DAMAGE = 4;
const int FIREROD_MISC_INDEX = 1;
const int FIREROD_FLAME_FLAG = 00001000b;
const int FIREROD_FLAME_SPRITE = 89;
const int BLANK_FIRE_SPRITE = 90; //Should be a blank tile sprite.

//The diameter of the light source for combos.
const int LIGHT_SOURCE_COMBO_RADIUS_MIN = 29;
const int LIGHT_SOURCE_COMBO_RADIUS_MAX = 33;
//The diameter of the light source for weapons.
const int LIGHT_SOURCE_WPN_RADIUS_MIN = 22;
const int LIGHT_SOURCE_WPN_RADIUS_MAX = 26;

const int BITMAP_DARKNESS = 2; //The bitmap ID to use for the darkness effect.
const int DARKROOM_LAYER = 7; //The layer to blit the output bitmap.
const int COLOUR_BLACK = 0x0F; //A black colour swatch in your palette.

const int LIGHT_SOURCE_CIRCLE_SCALE = 1; //Scale and layer args for the colour-0 circles.
const int LIGHT_SOURCE_CIRCLE_LAYER = 0;

item script BasicFireRod{
void run(int sprite, int damage, int step_speed){
Link->Action = LA_ATTACKING;
lweapon flame = Screen->CreateLWeapon(LW_CUST_FLAME);
flame->X = Link->X;
flame->Y = Link->Y;
flame->UseSprite(Cond(sprite > 0, sprite, FIREROD_FLAME_SPRITE));
flame->Dir = Link->Dir;
if ( Link->Dir == DIR_UP ) {
flame->Y -= 16;
}
if ( Link->Dir == DIR_DOWN ) {
flame->Flip = FLIP_VERTICAL;
flame->Y += 16;

}
if ( Link->Dir == DIR_RIGHT ) {
flame->Flip = ROT_CCW;
flame->X += 16;
}
if ( Link->Dir == DIR_RIGHT ) {
flame->Flip = ROT_CW;
flame->X -= 16;
}
//Ternary would help here, as it would jus tbe:
//flame->Step = step_speed > 0 ? step_speed : FIREROD_MIN_STEP;
//sigh.
flame->Step = Cond(step_speed > 0, step_speed, FIREROD_MIN_STEP);
flame->Damage = Cond(damage > 0, damage, FIREROD_DAMAGE);
//! Damage is forwarded to the real fire weapon via the global active script.
flame->Misc[FIREROD_MISC_INDEX] |= FIREROD_FLAME_FLAG; //Mark it for detection.
flame->HitYOffset = -214747; //Move the true hitbox offscreen so that it cannot trigger or hit anything.
//! The global active script handles real collisions.
}
}

//Returns true if the combo at '(x, y)' has either an inherent or place flag of type 'flag'
bool ____LayerComboFI(int pos, int flag, int layer){
return GetLayerComboF(layer,pos) == flag || GetLayerComboI(layer,pos) == flag;
}



//Call before Waitdraw.
void DoFireRod(){
int cmb_pos; bool makeflame; int flags[3]={CF_CANDLE1, CF_CANDLE2};
for ( int q = Screen->NumLWeapons(); q > 0; q-- ) {
lweapon l = Screen->LoadLWeapon(q);
if ( l->ID == LW_CUST_FLAME ){
if ( l->Misc[FIREROD_MISC_INDEX]&FIREROD_FLAME_FLAG ) {
//We make a real dire weapon on top of fire trigger combos.
cmb_pos = ComboAt(l->X, l->X);
for ( int q = 0; q < 3; q++ ) {
for ( int w = 0; w < 2; w++ ) {
if ( ____LayerComboFI(cmb_pos, flags[w] , q ) ) {
lweapon makefire = Screen->CreateLWeapon(LW_FIRE);
makefire->X = ComboX(cmb_pos);
makefire->Y = ComboY(cmb_pos);
makefire->UseSprite(BLANK_FIRE_SPRITE);
makefire->Misc[FIREROD_MISC_INDEX] |= FIREROD_FLAME_FLAG;
SetLayerComboF(LAYER_TORCH_FLAG, cmb_pos, CF_LIT_TORCH);
}
}
}
//Make fire weapon on enemies on collision if the enemy has its hitbox enabled, and on-screen.
for ( int e = Screen->NumNPCs(); e > 0; e-- ) {
npc n = Screen->LoadNPC(e);
if ( !n->CollDetection ) continue;
if ( n->HitXOffset < 0 ) continue;
if ( n->HitXOffset > 255 ) continue;
if ( n->HitYOffset < 0 ) continue;
if ( n->HitYOffset > 255 ) continue;
if ( Collision(l,n) ){
lweapon makefire = Screen->CreateLWeapon(LW_FIRE);
makefire->Damage = l->Damage;
makefire->X = n->X + n->HitXOffset;
makefire->Y = n->Y + n->HitYOffset;
Remove(l); //Remove the fire rod object.
//Fire weapons on enemies should be real gfx.
//makefire->UseSprite = BLANK_FIRE_SPRITE;
}
}
}
}
}
}

const int CF_LIT_TORCH = 99; //script 2.
const int LAYER_TORCH_FLAG = 0; //Look for them on his layer.


//Call before Waitdraw()
//DarkDroom(DARKROOM_LAYER, false, BITMAP_DARKNESS);
void DarkRoom(int layer, bool trans, int bitmap_id)
{
int q[16]; int src; int cnt;
int lightsourceflags[]={CF_LIT_TORCH};
q[9] = SizeOfArray(lightsourceflags);
int lightsourceflaglayers[]={LAYER_TORCH_FLAG};
q[15] = SizeOfArray(lightsourceflaglayers);

for ( q[10] = SizeOfArray(LightSources); q[10] >= 0; q[10]-- ) { LightSources[ q[10] ] = -1; } //Wipe it every frame.
Screen->SetRenderTarget(bitmap_id);
Screen->Rectangle(layer, 0, 0, 256, 256, COLOUR_BLACK, 100, 0, 0, 0, true, OP_OPAQUE);
//Add light sources to the array for combos.
for ( q[0] = 0; q[0] < q[15]; q[0]++ )
{
//Check for light sources on layers
for ( q[1] = 0; q[1] < 176; q[1]++ )
{
//check all positions.
for ( q[2] = 0; q[2] < q[9]; q[2]++ )
{ //and all flags
if ( ____LayerComboFI(q[1], lightsourceflags[ q[2] ], lightsourceflaglayers[ q[0] ] ) )
{
LightSources[src] = ComboX(q[1]);
LightSources[src+1] = ComboY(q[1]);
LightSources[src+2] = Rand(LIGHT_SOURCE_COMBO_RADIUS_MIN, LIGHT_SOURCE_COMBO_RADIUS_MAX);
cnt++;
src+=3;
}
}
}
}
//add light sources to the array for weapons
for ( q[4] = Screen->NumLWeapons(); q[4] > 0; q[4] -- )
{
lweapon l = Screen->LoadLWeapon(q[4]);
//for special fire rod weapons
if ( l->ID == LW_CUST_FLAME )
{
LightSources[src] = l->X + 8;
LightSources[src+1] = l->Y + 8;
LightSources[src+2] = Rand(LIGHT_SOURCE_WPN_RADIUS_MIN, LIGHT_SOURCE_WPN_RADIUS_MAX);
cnt++;
src+=3;
}
//for fire weapons that are not dummy weapons
if ( l->ID == LW_FIRE )
{
if ( (l->Misc[FIREROD_MISC_INDEX]&FIREROD_FLAME_FLAG) != 0 )
{
LightSources[src] = l->X + 8;
LightSources[src+1] = l->Y + 8;
LightSources[src+2] = Rand(LIGHT_SOURCE_WPN_RADIUS_MIN, LIGHT_SOURCE_WPN_RADIUS_MAX);
cnt++;
src+=3;
}
}
}

q[13] = cnt*3;
//Draw all light sources to the bitmap.
for ( q[12] = 0; q[12] <= q[13]; q[12] += 3 )
{
Screen->Circle(LIGHT_SOURCE_CIRCLE_LAYER, LightSources[ q[12] ], LightSources[ q[12]+1 ], LightSources[ q[12]+2 ], 0, LIGHT_SOURCE_CIRCLE_SCALE,
0,0,0, true, OP_OPAQUE);
if ( LightSources[ q[12] ] == -1 ) break; //Sanity check.
}

//! Blits
Screen->SetRenderTarget(RT_SCREEN);
// if ( trans ) //2.54+ stuff t/b/a
// {
// Screen->DrawBitmapEx()
// }
// else {
Screen->DrawBitmap(layer, bitmap_id, 0, 0, 256, 176, 0, 0, 256, 176, 0, true);
}





It should be obvious, but, this does not mean that it works as-is. I fixed all of the actual syntactical issues, but I have not tested it. Any major issues at this stage, would most likely be from inappropriate pointers, calling stuff in loops using the wrong identifier, or the wrong array index; and similar. Then again, it might work. You never know.

You can view the diffs on GitHub if you want to see what I changed at each stage.

Lelouche Vi Britannia
09-24-2017, 12:50 PM
Well I am still trying to learn. Sadly my knowledge is woefully lacking. I'll give it a go tonight and see if I can fix any errors that pop up. If I'm successful, I'll repost the results.

Think I'm using 3.50.? Bit I'm pretty sure I downloaded 3.53.? . Currently in very early stages of my current project so I've been running code on my TestBed, then adding to the actual quest once I have confirmed it's working as intended.

ZoriaRPG
09-24-2017, 02:01 PM
Well I am still trying to learn. Sadly my knowledge is woefully lacking. I'll give it a go tonight and see if I can fix any errors that pop up. If I'm successful, I'll repost the results.

Think I'm using 3.50.? Bit I'm pretty sure I downloaded 3.53.? . Currently in very early stages of my current project so I've been running code on my TestBed, then adding to the actual quest once I have confirmed it's working as intended.

I think that you mean 2.53. :D

Latest 2.53 Beta as of this post (http://timelord.insomnia247.nl/zc/zc_dev/2.53_Win_Beta_9--fixdrunkguys--fixscrollingmap--extrasanitycombosm--importscriptsimprovement.zip).

Let me know if it works. It's pretty complex, and will likely need me to do debugging.

ZoriaRPG
09-24-2017, 02:54 PM
Lelouche Vi Britannia : I also wanted to say that you are doing fine, picking up this stuff. You are quicky learning style elements, how to keepthings clean, and the syntax. Well done.

ZoriaRPG
09-24-2017, 02:55 PM
[double-post] Please remove.

Lelouche Vi Britannia
09-24-2017, 04:05 PM
Thanks. I don't get off work till kinda late and won't have much time tonight, but I'll definitely have some info for you by tomorrow.

ZoriaRPG
09-25-2017, 10:39 AM
Thanks. I don't get off work till kinda late and won't have much time tonight, but I'll definitely have some info for you by tomorrow.

There is obviously no rush on my end of things. :D

Lelouche Vi Britannia
09-25-2017, 10:48 PM
Well this is frustrating... I can't seem to run 2.53 for some reason. It keeps giving me an error.

Failed to execute ./zquest-w.exe : 5.

Lelouche Vi Britannia
09-25-2017, 10:54 PM
NM I figured it out. Avast was acting stupid and trying to "protect" me from the file. lol.

Lelouche Vi Britannia
09-25-2017, 11:21 PM
Ok let's begin...

First, still had a couple of minor errors but was easy to fix (one spelling error and two instances of Right direction instruction, I changed the first one to a Left and that fixed the graphic issue with the projectile).

During test, the bolt is appear just behind Link before flying forward. This is only visible when firing Left and Right.

Would still like to see an actual weapon held out when used, but I figured out how to do that with my earlier attempt. Is there an easier way to do it in 2.53?

The slightly modded code follows... only error corrected for now. Not sure what I would need to change to get the bolt to look right on the left/right firing, or if that can even be fixed at this stage.



import "std.zh"

global script Active
{
void run()
{
DoFireRod();
DarkRoom(DARKROOM_LAYER, false, BITMAP_DARKNESS);
Waitdraw();
Waitframe();
}
}

////////////////////////////
/// Simple Firerod ///
/// v0.3 ///
/// By: ZoriaRPG ///
/// 24th September, 2017 ///
////////////////////////////
/// Note: All of this is ugly. In 2.54, you will be able to set NPCs to specific script defences, so you can use a real
/// FLAME weapon that you set up, and 2.54 may add SCRIPT weapon triggers to combos, as well.


int LightSources[3120]; //All the light source metrics for drawing, per frame.
//x, y, diameter: 176 combos * 3 layers, (255 weapons * 2) * 3

//Settings
const int LW_CUST_FLAME = 31; //Script 1
const int FIREROD_MIN_STEP = 100;
const int FIREROD_DAMAGE = 4;
const int FIREROD_MISC_INDEX = 1;
const int FIREROD_FLAME_FLAG = 00001000b;
const int FIREROD_FLAME_SPRITE = 89;
const int BLANK_FIRE_SPRITE = 90; //Should be a blank tile sprite.

//The diameter of the light source for combos.
const int LIGHT_SOURCE_COMBO_RADIUS_MIN = 29;
const int LIGHT_SOURCE_COMBO_RADIUS_MAX = 33;
//The diameter of the light source for weapons.
const int LIGHT_SOURCE_WPN_RADIUS_MIN = 22;
const int LIGHT_SOURCE_WPN_RADIUS_MAX = 26;

const int BITMAP_DARKNESS = 2; //The bitmap ID to use for the darkness effect.
const int DARKROOM_LAYER = 7; //The layer to blit the output bitmap.
const int COLOUR_BLACK = 0x0F; //A black colour swatch in your palette.

const int LIGHT_SOURCE_CIRCLE_SCALE = 1; //Scale and layer args for the colour-0 circles.
const int LIGHT_SOURCE_CIRCLE_LAYER = 0;

item script BasicFireRod{
void run(int sprite, int damage, int step_speed){
Link->Action = LA_ATTACKING;
lweapon flame = Screen->CreateLWeapon(LW_CUST_FLAME);
flame->X = Link->X;
flame->Y = Link->Y;
flame->UseSprite(Cond(sprite > 0, sprite, FIREROD_FLAME_SPRITE));
flame->Dir = Link->Dir;
if ( Link->Dir == DIR_UP ) {
flame->Y -= 16;
}
if ( Link->Dir == DIR_DOWN ) {
flame->Flip = FLIP_VERTICAL;
flame->Y += 16;

}
if ( Link->Dir == DIR_LEFT ) {
flame->Flip = ROT_CCW;
flame->X += 16;
}
if ( Link->Dir == DIR_RIGHT ) {
flame->Flip = ROT_CW;
flame->X -= 16;
}
//Ternary would help here, as it would jus tbe:
//flame->Step = step_speed > 0 ? step_speed : FIREROD_MIN_STEP;
//sigh.
flame->Step = Cond(step_speed > 0, step_speed, FIREROD_MIN_STEP);
flame->Damage = Cond(damage > 0, damage, FIREROD_DAMAGE);
//! Damage is forwarded to the real fire weapon via the global active script.
flame->Misc[FIREROD_MISC_INDEX] |= FIREROD_FLAME_FLAG; //Mark it for detection.
flame->HitYOffset = -214747; //Move the true hitbox offscreen so that it cannot trigger or hit anything.
//! The global active script handles real collisions.
}
}

//Returns true if the combo at '(x, y)' has either an inherent or place flag of type 'flag'
bool ____LayerComboFI(int pos, int flag, int layer){
return GetLayerComboF(layer,pos) == flag || GetLayerComboI(layer,pos) == flag;
}



//Call before Waitdraw.
void DoFireRod(){
int cmb_pos; bool makeflame; int flags[3]={CF_CANDLE1, CF_CANDLE2};
for ( int q = Screen->NumLWeapons(); q > 0; q-- ) {
lweapon l = Screen->LoadLWeapon(q);
if ( l->ID == LW_CUST_FLAME ){
if ( l->Misc[FIREROD_MISC_INDEX]&FIREROD_FLAME_FLAG ) {
//We make a real dire weapon on top of fire trigger combos.
cmb_pos = ComboAt(l->X, l->X);
for ( int q = 0; q < 3; q++ ) {
for ( int w = 0; w < 2; w++ ) {
if ( ____LayerComboFI(cmb_pos, flags[w] , q ) ) {
lweapon makefire = Screen->CreateLWeapon(LW_FIRE);
makefire->X = ComboX(cmb_pos);
makefire->Y = ComboY(cmb_pos);
makefire->UseSprite(BLANK_FIRE_SPRITE);
makefire->Misc[FIREROD_MISC_INDEX] |= FIREROD_FLAME_FLAG;
SetLayerComboF(LAYER_TORCH_FLAG, cmb_pos, CF_LIT_TORCH);
}
}
}
//Make fire weapon on enemies on collision if the enemy has its hitbox enabled, and on-screen.
for ( int e = Screen->NumNPCs(); e > 0; e-- ) {
npc n = Screen->LoadNPC(e);
if ( !n->CollDetection ) continue;
if ( n->HitXOffset < 0 ) continue;
if ( n->HitXOffset > 255 ) continue;
if ( n->HitYOffset < 0 ) continue;
if ( n->HitYOffset > 255 ) continue;
if ( Collision(l,n) ){
lweapon makefire = Screen->CreateLWeapon(LW_FIRE);
makefire->Damage = l->Damage;
makefire->X = n->X + n->HitXOffset;
makefire->Y = n->Y + n->HitYOffset;
Remove(l); //Remove the fire rod object.
//Fire weapons on enemies should be real gfx.
//makefire->UseSprite = BLANK_FIRE_SPRITE;
}
}
}
}
}
}

const int CF_LIT_TORCH = 99; //script 2.
const int LAYER_TORCH_FLAG = 0; //Look for them on his layer.


//Call before Waitdraw()
//DarkDroom(DARKROOM_LAYER, false, BITMAP_DARKNESS);
void DarkRoom(int layer, bool trans, int bitmap_id)
{
int q[16]; int src; int cnt;
int lightsourceflags[]={CF_LIT_TORCH};
q[9] = SizeOfArray(lightsourceflags);
int lightsourceflaglayers[]={LAYER_TORCH_FLAG};
q[15] = SizeOfArray(lightsourceflaglayers);

for ( q[10] = SizeOfArray(LightSources); q[10] >= 0; q[10]-- ) { LightSources[ q[10] ] = -1; } //Wipe it every frame.
Screen->SetRenderTarget(bitmap_id);
Screen->Rectangle(layer, 0, 0, 256, 256, COLOUR_BLACK, 100, 0, 0, 0, true, OP_OPAQUE);
//Add light sources to the array for combos.
for ( q[0] = 0; q[0] < q[15]; q[0]++ )
{
//Check for light sources on layers
for ( q[1] = 0; q[1] < 176; q[1]++ )
{
//check all positions.
for ( q[2] = 0; q[2] < q[9]; q[2]++ )
{ //and all flags
if ( ____LayerComboFI(q[1], lightsourceflags[ q[2] ], lightsourceflaglayers[ q[0] ] ) )
{
LightSources[src] = ComboX(q[1]);
LightSources[src+1] = ComboY(q[1]);
LightSources[src+2] = Rand(LIGHT_SOURCE_COMBO_RADIUS_MIN, LIGHT_SOURCE_COMBO_RADIUS_MAX);
cnt++;
src+=3;
}
}
}
}
//add light sources to the array for weapons
for ( q[4] = Screen->NumLWeapons(); q[4] > 0; q[4] -- )
{
lweapon l = Screen->LoadLWeapon(q[4]);
//for special fire rod weapons
if ( l->ID == LW_CUST_FLAME )
{
LightSources[src] = l->X + 8;
LightSources[src+1] = l->Y + 8;
LightSources[src+2] = Rand(LIGHT_SOURCE_WPN_RADIUS_MIN, LIGHT_SOURCE_WPN_RADIUS_MAX);
cnt++;
src+=3;
}
//for fire weapons that are not dummy weapons
if ( l->ID == LW_FIRE )
{
if ( (l->Misc[FIREROD_MISC_INDEX]&FIREROD_FLAME_FLAG) != 0 )
{
LightSources[src] = l->X + 8;
LightSources[src+1] = l->Y + 8;
LightSources[src+2] = Rand(LIGHT_SOURCE_WPN_RADIUS_MIN, LIGHT_SOURCE_WPN_RADIUS_MAX);
cnt++;
src+=3;
}
}
}

q[13] = cnt*3;
//Draw all light sources to the bitmap.
for ( q[12] = 0; q[12] <= q[13]; q[12] += 3 )
{
Screen->Circle(LIGHT_SOURCE_CIRCLE_LAYER, LightSources[ q[12] ], LightSources[ q[12]+1 ], LightSources[ q[12]+2 ], 0, LIGHT_SOURCE_CIRCLE_SCALE,
0,0,0, true, OP_OPAQUE);
if ( LightSources[ q[12] ] == -1 ) break; //Sanity check.
}

//! Blits
Screen->SetRenderTarget(RT_SCREEN);
// if ( trans ) //2.54+ stuff t/b/a
// {
// Screen->DrawBitmapEx()
// }
// else {
Screen->DrawBitmap(layer, bitmap_id, 0, 0, 256, 176, 0, 0, 256, 176, 0, true);
}

ZoriaRPG
09-25-2017, 11:41 PM
Ok let's begin...

First, still had a couple of minor errors but was easy to fix (one spelling error and two instances of Right direction instruction, I changed the first one to a Left and that fixed the graphic issue with the projectile).

During test, the bolt is appear just behind Link before flying forward. This is only visible when firing Left and Right.


This is because the first instance was supposed to be RIGHT, and the last, is LEFT. When you edited them, you accidentally transposed the offsets. Either flip the instances of flame->X += 16 and flame->X -= 16, or flip DIR_LEFT with DIR_RIGHT.



if ( Link->Dir == DIR_LEFT ) {
flame->Flip = ROT_CCW;
flame->X -= 16;
}
if ( Link->Dir == DIR_RIGHT ) {
flame->Flip = ROT_CW;
flame->X += 16;
}



Would still like to see an actual weapon held out when used, but I figured out how to do that with my earlier attempt. Is there an easier way to do it in 2.53?

The script already calls Link->Action = LA_ATTACKING. Is it not doing that, or did you want to see a physical wand item in his hands? That is relatively easy to add as a second lweapon, that uses a LW_SPARKLE type, and a sprite with the correct number of animation frames. The position of the fireball would need to be offset based on the LW_SPARKLE weapon as well.

I'll add that in, when I have a chance.


[The slightly modded code follows... only error corrected for now. Not sure what I would need to change to get the bolt to look right on the left/right firing, or if that can even be fixed at this stage.

Fair enough. I will look at a diff, and see what you changed.

Lelouche Vi Britannia
09-26-2017, 12:35 AM
Whoops at the changed the wrong one, lol. I saw CCW and figured that was supposed to be the left one. Yeah seeing a visible rod would be cool and please, take your time. You're helping a lot as it is.

The only real error correction then was just a typo... DarkDroom was supposed to be DarkRoom. Haven't tested that part of it yet.

ZoriaRPG
09-26-2017, 01:14 AM
Whoops at the changed the wrong one, lol. I saw CCW and figured that was supposed to be the left one. Yeah seeing a visible rod would be cool and please, take your time. You're helping a lot as it is.

The only real error correction then was just a typo... DarkDroom was supposed to be DarkRoom. Haven't tested that part of it yet.


Revisions to add the rod weapon.
-=SPOILER=-

Lelouche Vi Britannia
09-26-2017, 11:07 AM
Compile Error and I can't figure out what I need to do to fix it...

-=SPOILER=-

The line in question is here, its the first line of the DoFireRod() function....



void DoFireRod(){
int q[DOFIREROD_COMBO_POS]; bool makeflame; int flags[2]={CF_CANDLE1, CF_CANDLE2}


Any ideas?

ZoriaRPG
09-27-2017, 06:59 AM
Compile Error and I can't figure out what I need to do to fix it...

-=SPOILER=-

The line in question is here, its the first line of the DoFireRod() function....



void DoFireRod(){
int q[DOFIREROD_COMBO_POS]; bool makeflame; int flags[2]={CF_CANDLE1, CF_CANDLE2};
int q[5];


Any ideas?

The declaration of the array is a find-replace error.



bool makeflame; int flags[2]={CF_CANDLE1, CF_CANDLE2};
int q[5];


I pushed the change to GitHub, and I verified that it compiles in 2.53.

Lelouche Vi Britannia
09-27-2017, 12:14 PM
Awesome! Thanks. I won't have a chance to play with it till tomorrow.

ZoriaRPG
09-27-2017, 01:12 PM
Awesome! Thanks. I won't have a chance to play with it till tomorrow.

The item script should be fine, although you may need to adjust the sprite metrics (constants). I am more worried that I might have some kind of minor error in the light sources code, or something of that nature. Unlike some users, I do not simply presume that my code will always work, but it should be sufficiently commented, and detailed, that you can see what it is doing at every stage.

The repo version on GitHub has a test global script with a debug feature that you may want to grab, and use, if you encounter problems.