Jump to content

Photo

My Script Wishlist and Your Script Ideas


  • Please log in to reply
242 replies to this topic

#31 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 23 May 2015 - 07:14 PM


Which of those would allow access to the .zlib files? Because right now I can't open them. Or do I just need to change the extension? Again thanks to everyone for your advice.

 

Either: Right click, and select 'Open with application', and choose the desired programme. You can also right-click, and view the properties, then set a default programme for my ;zlib extension. They're all ASCII text in any event.

 

I also sent you a PM about comprehending arrays. It's part I, or a potential multi-part explanation, with active examples.


Edited by ZoriaRPG, 23 May 2015 - 07:14 PM.


#32 C-Dawg

C-Dawg

    Magus

  • Members

Posted 25 May 2015 - 01:29 PM

As for the Zodiac code.... I know about that. I've looked at that code. It gave me a headache. And since I haven't been able to get far enough in the demo to where those enemies appear, I don't know how they actually behave.

 

Shame on you.  The code might be long (100k lines) but everything you want is in a single script, General_Sidescrolling_Enemy. There are two of them because the script got too long to compile and/or run correctly.

 

If you want to make custom enemies, I suggest you use logic like this.  I think it's commented pretty well, but heres' the logic behind it.

 

There is a single script that runs all (or many) of the enemies.  Hence the "general" in the name.    Here's how it works.

 

(1) Initialize the Enemy

 

Basically, when the script starts, it checks to see what kind of enemy it is.  I accomplish this by passing the FFC a variable using it's "Ax" field, but you could do it by setting the FFC, or even using the data variables if you can do it.  The important thing is that you want the field that sets the enemy type to be something another script can set, not a D0 - D7 variable that the user has to set.  This becomes important later.

 

Anyway, once the script determines what kind of enemy it is (and, if you're using Ax as the variable-passing field, set that field back to 0 so it doesn't muck up the enemy's movement) then the script sets up variables for that kind of enemy.  It creates a fire-type enemy to act as the Ghost and sets that NPC's health and item drops accordingly.  It sets some local variables to control the damage and whatever else you care about for this kind of enemy.  

 

Since I spawn my enemies randomly, here's where the code calls another function that looks for a place to spawn this particular enemy.  I have different spawn requirements for different enemies; some have to be on the ceiling, some need to be on the wall, etc.  Since I can't pass back X and Y variables, I just have this little sub-function move the FFC to its spawn point directly.

 

Another thing I do when initializing an enemy is I grab a second FFC and set it to a blank damage combo dependent on the "damage" level of this enemy.  It gets stashed off screen initially (not very far; if you push FFCs much beyond 1 tile off screen they will stop functioning, so beware of that).  This becomes important later.

 

(2) Using Hit Points to Determine Loop While Enemy Is Alive

 

Once that's all done, the script enters a while loop that executes while the NPC is alive.  Now, I do something strange with hit points to determine if the NPC is alive.  See. all the enemies in Zodiac, including bosses, actually have 100 more hit points that you can see.  Why would I do that?  Here's the thing.  I want to know when the enemy dies and do something afterwards.  An explosion, clearing the FFC's variables, whatever.  I ran into a problem back in 2008 with this where once an NPC dies, my script had a hard time detecting that.  I suspect what was happening was the NPC pointer was dependent on the Screen's NPC index, so killing one enemy reset the index and sometimes resulted in the pointer staying valid but pointing at something else.

 

Whatever the reason, I found it better to always set hit points 100 HIGHER than the in-game hit points I wanted.  Then, when the enemy's hit points drop below 100, I can tell the script to stash the enemy off screen while I do whatever I want to do when it dies, and then clean up the NPC while resetting the FFC.  Anyway, that means that the While loop that determines each NPC's behavior after it is set up runs while the ghost's hit points are greater than 100.  If that stops being true, the code moves on from the loop to the death behavior.

 

(3) Graphics and Collision Detection

 

What does the enemy have to do while it is alive?  Well, a few things.  It has to draw graphics showing itself and it has to detect collisions.  Now, not every enemy in my game cares about the solidity of combos, but they do all care about contact with Link.  Since I want enemies to be of arbitrary size, and I want the graphics to line up with the collision detection for the player, I handle both (1) drawing and (2) collision detection with the player using the same function.  

 

This function accepts the ID of the enemy and some other information; check the code.  If the enemy is frozen, this function draws it using a blue palette and does nothing else.  If the enemy has recently been damaged, it randomly assigns a new CSet each frame.  Whatever else it is doing, it will then draw the appropriate frame of animation (using Drawtile directly).  It will also check to see if the player is within the enemy's damage area.  This is usually just a square, since that's easy, but it doesn't have to be.  You can define whatever shape area you want.  Some of my enemies, like the hoppers, have kind of a U-shape area.  

 

If the player is inside this zone, for one frame, the script takes that off-screen damage FFC we set up earlier and plops it on top of the player.  That way, the ZClassic engine handles all the knockback and damage and that jazz.  (It also means you shouldn't use the anti-spike boots in a quest that does things this way,  although you could use an offsreen NPC for the same effect if you really wanted to.)

 

(4) Behavior

 

Okay, now we have to tell the enemy what to do.  I tend to organize enemies with simple AI based on States.  The enemy can be in one of several "states," each organized around a simple concept.  One state might be walking back and forth.  Or jumping.  Or firing a shot.  Anyway, within each state I increment "state_counter" that I use to determine time within that state.  At some point, perhaps after enough time has passed or after the player is in a certain position or whatever, the enemy has to make a decision about a new state.  And so it does.  In a nutshell, that's how every enemy in Zodiac thinks.

 

I handle collision with solid combos here, state by state.  That's because some enemies have different collision in different states.    For enemies that are effected by gravity, I usually set up a constant gravity effect outside of any particular state.  

 

(5) Death

 

Since ZClassic is keeping track of damage to the NPC, all you have to do is wait for the ghosts HP to drop below 100.  When that happens, you kill the associated NPC (triggering its item drop) and set the Data field of this FFC and the FFC it was using for damage to 0.  That stops them from doing anything and sets them up to be used again later.  Easy peasy.  If you want, you can have another loop here before you get that far that keeps drawing the enemy during an explosion.  Spawning lweapon Bomb Explosions in a general area around the FFC gives you a nice explosion result.

 

(6) In-game Setup

 

Now, you don't want to set up each friggin' enemy on every FFC of every screen.  That would be tedious as hell.  So, instead, I have another function that sets them up for you.  On each room, you load up the enemy setter function on an FFC.  In it's variables, tell it the Index of the enemies to spawn, and how many.  This script then goes and looks for FFCs using data 0 (meaning they are not in use), assigns them the general_enemy script, and passes them the ID of the enemy it should start acting like.  

 

You COULD handle the initial placement of the enemy in this function, too, and that's probably the best place for it.  Because I had already coded random placement directly into the enemy script, I had to pass a second variable to the newly born enemy (using Ay) that tells it if it needs to find a home or not.  

 

When would you not want the NPC to find its own home?  Well, if it was spawned, that's why.  You can use the general_enemy script to make things like spawned worms, missiles, and whatever the hell else.  Any other script in the game can go look for a Data == 0 FFC and then load the right variables into it to make a new enemy.  But, if you don't turn off the spawn location part of the initalization, it will not spawn where your new script wants it.

 

And...

 

That's it, really.  There are some small wrinkles for particular problems in some of the enemy code, but this is all that you're looking at.  It's really easy to manipulate this code.  For a simple enemy that doesn't make complicated decisions, you can use this kind of code to crank out new NPCs at like two or three an hour.  It's neat.



#33 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 25 May 2015 - 01:35 PM

I like your enemy HP handling, although because I'm already using large numbers, I may not have the luxury of that cheat...

Still, I've read some of it, and appreciate the commenting. 107K+ lines, if you're curious, so no, I've not read all of it. It is however, well-organised, despite being one huge file.

#34 C-Dawg

C-Dawg

    Magus

  • Members

Posted 25 May 2015 - 01:41 PM

Zora: You can be using large numbers and still use the Life+100 workaround.  Just make sure you have a maximum cap on how much damage can be dealt using a single blow, and then make sure your threshold is above that.
 
By the way, all of these things are in Zodiac, too:

Moving Platform/Solid FFCs- Mero recently released code that is designed for this function. I haven't tested it myself yet, but look for the topic Solid FFCs beta.

 

...

 

Whip/True Grappling Beam- this is mostly something that bothered me about sideview gravity areas. You can't latch onto a grapple point and swing across a gap like Indiana Jones or Samus in Metroid. Instead you just go straight across. Can this be done? Who knows... but I think there are some who would be interested.

 

 

...

 

Multiple Items/Scripted Triggers- You can make extra swords. If you want, you could even make extra versions of nearly every item in the game. But doing that serves almost no purpose when you can't easily create secrets that can only be triggered by that item. So, a trigger that would detect you had the item and activate secrets when you hit it with it. Then, making a more powerful hammer; new bow, boomerang, hookshot, etc. items would actually serve a useful purpose.

 

 

Moving platforms are implemented using a script that draws solid combos beneath the FFC and moves the player left or right if the player is standing on it.  Now, if you wanted to make a more elegant solution you would need to change it from drawing solid FFCs to just preventing the player from falling through it, allow it to adjust the player's position Up or Down, and make sure the jumping functions treated the player being on top of the platform the same as being on solid ground.  Still, if all you want is a platform moving back and forth, you can use what I've got.

 

Grapple beam is in there, brah.  The Zodiac script uses a Grapple Beam that draws a line between the player and whatever direction she is pressing (thanks be to Saffith), and then allows the player to swing around or pull towards the contact point.  You'd need to tweak it to your own uses, of course, but most of what you'd need to change is graphical.  It works great.

 

Zodiac handles new triggers by just having a script look at the combos.  So, for example, I have blocks that the Spin Jump breaks.  To do this, I have the Spin Jump script check the combo ID for combos within the radius of the effect.  If it finds one that is set to a combo that it can break, it replaces that combo with a cycling combo showing the block being destroyed.  It's like an initiate secret combo.  While you couldn't just export this and use it directly, the logic is pretty easy to apply to your own scripts.


Edited by C-Dawg, 25 May 2015 - 01:42 PM.

  • ywkls likes this

#35 ywkls

ywkls

    Master

  • Members

Posted 25 May 2015 - 02:16 PM

Moving platforms are implemented using a script that draws solid combos beneath the FFC and moves the player left or right if the player is standing on it.  Now, if you wanted to make a more elegant solution you would need to change it from drawing solid FFCs to just preventing the player from falling through it, allow it to adjust the player's position Up or Down, and make sure the jumping functions treated the player being on top of the platform the same as being on solid ground.  Still, if all you want is a platform moving back and forth, you can use what I've got.

 

Thanks for this tip. Those notes at the top were actually a list of common script requests and the best answers I'd found to them, however.

 

 

 

Grapple beam is in there, brah.  The Zodiac script uses a Grapple Beam that draws a line between the player and whatever direction she is pressing (thanks be to Saffith), and then allows the player to swing around or pull towards the contact point.  You'd need to tweak it to your own uses, of course, but most of what you'd need to change is graphical.  It works great.

 

I'll definitely download the latest demo and look for it. One of the primary reasons I gave up on the code before is because it is so long that finding anything specific can be hard. That and the fact it is designed for your game and I'd almost certainly have to make a lot of changes and not necessarily know how to do so.

 

 

Zodiac handles new triggers by just having a script look at the combos.  So, for example, I have blocks that the Spin Jump breaks.  To do this, I have the Spin Jump script check the combo ID for combos within the radius of the effect.  If it finds one that is set to a combo that it can break, it replaces that combo with a cycling combo showing the block being destroyed.  It's like an initiate secret combo.  While you couldn't just export this and use it directly, the logic is pretty easy to apply to your own scripts.

 

Does it do this by looking at the Combo Type, the Combo ID number or the flag that is placed on the combo? After studying the code ZoriaRPG pointed me to, I think I can figure out how to use it to create the scripted triggers. Now if I could only get a script to detect collision between a moving ffc and a weapon...

 

I may come up with more ideas for scripting things at some point. For now, I'm still in the process of implementing those things this topic has brought to my attention that I haven't yet begun to learn how to use.



#36 C-Dawg

C-Dawg

    Magus

  • Members

Posted 25 May 2015 - 02:32 PM

Yes, you'd have to tweak whatever code you take out of Zodiac, but the idea is that the algorithm is all there.

 

 

 

Does it do this by looking at the Combo Type, the Combo ID number or the flag that is placed on the combo?

 

 

Whatever you want.  Checking any of those things is easy to do.  I found that checking combo ID itself was easiest because I could avoid overlapping with other functions.  Like, if you check for a Secret Flag, now you can't use ZQuest's own secret system on that screen or you get weird effects.  With the combo ID, you can dedicate one combo to interact with that script specifically.

 

We've got mountains of combo and tile space, let's use it up.

 

After studying the code ZoriaRPG pointed me to, I think I can figure out how to use it to create the scripted triggers. Now if I could only get a script to detect collision between a moving ffc and a weapon...

 

Right, because LWeapons can't run scripts.  That's the biggest problem.  I encountered that early on.  You can do two things to fix this.

 

(1) Have a global script that always checks to see what kind of Lweapons are on the screen, and what combos they are colliding with.  This would be fine if you don't want to otherwise change the way LWeapons work, and if you're just tweaking the engine a little bit, go for it. 

 

(2) Do what I did - make most player weapons into FFCs.  See, most weapons and tools in Zodiac are scripted FFCs.  One script, the item script, goes and gets a blank FFC (or, in the case of some critical primary weapons, I dedicate FFCs 29 - 32 for this purpose only).  Then, it gives that FFC a script that tells it to act like a weapon of some kind.  

 

The FFC script you just assigned can now check for collisions, just like the global script could, with less processing power.  Perhaps more importantly, it can now do... whatever.  It can travel not-just-in-a-straight-line.  It can make enemies move, or damage them.  It can interact with other items.  Sky's the limit.


Edited by C-Dawg, 25 May 2015 - 02:34 PM.


#37 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 26 May 2015 - 06:58 AM

Thanks for this tip. Those notes at the top were actually a list of common script requests and the best answers I'd found to them, however.
 
 
 
I'll definitely download the latest demo and look for it. One of the primary reasons I gave up on the code before is because it is so long that finding anything specific can be hard. That and the fact it is designed for your game and I'd almost certainly have to make a lot of changes and not necessarily know how to do so.




You want:
 


if ( Collision(lw,this) )

Collision accepts l, and f pointers by default. If you are running an FFC to check collision, the 'this' pointer is always valid with that FFC. If the weapon is using an FFC (launched from it), that FFC can detect collision. You can check for collision with an lweapon from an FFC.

If you are doing it globally, with collision between lweapons, and combos; you don't want to check collision with FFCs, or use them for this. You want to check for collision with a combo by its data, type, or flag.

Making weapons FFCs is good, as long as you don;t have a dozen FFC weapons running at all times. The problem there, is the FFC instance cap, more than anything else. You can check for collision between an ffc and a Combo too, but it requires additional functions.

I likewise use FFC weapons to go outside the boundaries of what ZScript lweapons, and eweapons can achieve 'out of the box'.

As to the code being too long, ywkls, it must be in one file, like that, to be stored in the buffer, and distributed with the .qst file. If C-Dawg used import lines to call it from separate files, it would not be internalised in the buffer.

You can always start slicing it into files, and make a master import file on your own, to split it up however you see fit. The code is divided into clean sections, by purpose; but if you're still using basic notepad.exe, this alone should convince you that it's time to shift to one of those editing programmes we've advised you to use.


  • ywkls likes this

#38 ywkls

ywkls

    Master

  • Members

Posted 26 May 2015 - 09:13 AM

You want:
 


if ( Collision(lw,this) )

Collision accepts l, and f pointers by default. If you are running an FFC to check collision, the 'this' pointer is always valid with that FFC. If the weapon is using an FFC (launched from it), that FFC can detect collision. You can check for collision with an lweapon from an FFC.

If you are doing it globally, with collision between lweapons, and combos; you don't want to check collision with FFCs, or use them for this. You want to check for collision with a combo by its data, type, or flag.

 

I'd forgotten about that Collision function. Then again, I created a list of all functions I thought I was likely to use and my own explanation of them because I was tired of trying to figure out other people's explanations of them; then forget to look at it when I'm writing code. I'm assuming that in order for this to work, the item would have to actually create an lweapon. Or would it work with things like the arrows and wand that shoot projectiles?

 

 

Making weapons FFCs is good, as long as you don;t have a dozen FFC weapons running at all times. The problem there, is the FFC instance cap, more than anything else. You can check for collision between an ffc and a Combo too, but it requires additional functions.

I likewise use FFC weapons to go outside the boundaries of what ZScript lweapons, and eweapons can achieve 'out of the box'.

 

Even this is light-years beyond my state of development in creating code. Maybe some day...

 

 

As to the code being too long, ywkls, it must be in one file, like that, to be stored in the buffer, and distributed with the .qst file. If C-Dawg used import lines to call it from separate files, it would not be internalised in the buffer.

You can always start slicing it into files, and make a master import file on your own, to split it up however you see fit. The code is divided into clean sections, by purpose; but if you're still using basic notepad.exe, this alone should convince you that it's time to shift to one of those editing programmes we've advised you to use.

 

Oh, I realize that the code has to be in one file. It's just that finding anything I want in it takes a lot of time and even then, there's no guarantee I have enough knowledge to use what I discover. Generally speaking, in my own code; I create a table of contents at the beginning then a reference to the various sections of my code.

 

Each one is numbered, with a brief commented header explaining what it does. I keep all of the code that does the same kind of thing in the same place in the file so that I don't get confused. Thus, the global script is in one section; the enemy scripts are next to other enemy scripts; each numbered for convenience; other ffc scripts are each in their section; and item scripts are listed together in their section.

 

To give one example, I finally found the code for that grappling beam C-Dawg mentioned, but after looking it over; I'm not sure I even know how it works. As near as I can figure, the item script just sets up the animation and activates the ffc script; which then figures out what direction that you're facing; draws a line between you and the designated grapple point and after that.... I'm lost.



#39 C-Dawg

C-Dawg

    Magus

  • Members

Posted 26 May 2015 - 09:57 AM

 

Even this is light-years beyond my state of development in creating code. Maybe some day...

 

.....

 

To give one example, I finally found the code for that grappling beam C-Dawg mentioned, but after looking it over; I'm not sure I even know how it works. As near as I can figure, the item script just sets up the animation and activates the ffc script; which then figures out what direction that you're facing; draws a line between you and the designated grapple point and after that.... I'm lost.

 

You're not shootin' high enough.  A custom weapon FFC is insanely simple to script.  Here's a simple algorithm:

 

item script SuperArrowItem{

 

If the player has enough magic to use this item, then:

1. Look for an FFC that is not in use, with Data = 0.

2. Once you find such an FFC, set it's Data to 1.

3. Tell the FFC to start running the SuperArrow ffc script.

4. Set the FFC's X,Y to be in front of the player - so check for Link->Dir and set it accordingly.  

5. Set the FFC's Vx or Vy to move away from the player.

6. Have a beer.

 

} // end of item script

 

ffc script SuperArrow{

 

Since the item script already set Vx and Vy, we don't need to move this ffc at all.  

While (true){

 

Check for collisions with NPCs and walls.  

If this ffc is coliding with an NPC, lower that NPC's hit points by whatever.

If this ffc is coliding with a wall or NPC:

1. spawn four lweapon arrows and send them off in the four cardinal directions

2. set this ffc's data to 0.

 

}

 

And you're done.  I mean, these can be exceedingly simple.


  • ywkls likes this

#40 ywkls

ywkls

    Master

  • Members

Posted 26 May 2015 - 10:57 AM

Okay... looking at your item scripts, I think I understand how to do the item part. The trick for me would probably be the ffc part. More specifically, anything involving Screen->DrawTile. Although I have my own reference to how that is supposed to be set up, I often have trouble getting it to work properly.

 

For the collisions between ffcs, that Collision function ZoriaRPG mentioned would probably work best for me. It's rather versatile, allowing for the detection of all sorts of things with one another. All I'd have to set up is the code that directs the ffc in different directions depending on which way you're facing, the animation for whatever you're using, then somehow get DrawTile to work.

 

Or I could have the item spawn an lweapon... which seems simpler than an ffc.



#41 C-Dawg

C-Dawg

    Magus

  • Members

Posted 26 May 2015 - 11:25 AM

It is much simpler, but if you do that, your LWeapon will always act like an LWeapon.  Remember, an item script only runs for ONE FRAME.  It cannot enter a while loop and keep doing something; when it hits a Waitframe, it dies.  So you can't control the LWeapon after it is created.  (Unless some other FFC script or global script does it.)


  • ywkls likes this

#42 ywkls

ywkls

    Master

  • Members

Posted 26 May 2015 - 12:04 PM

It is much simpler, but if you do that, your LWeapon will always act like an LWeapon.  Remember, an item script only runs for ONE FRAME.  It cannot enter a while loop and keep doing something; when it hits a Waitframe, it dies.  So you can't control the LWeapon after it is created.  (Unless some other FFC script or global script does it.)

 

One way I've gotten around this in the past was to have the item script trigger a function I created that handled things for multiple frames. While it is true that the function would probably have to be called by the global script or an ffc script might have to be run that would handle things; I know how to do those things.

 

Keep in mind that in my 8 months of learning scripting, I've gone from having trouble getting an item message script to work to writing code in my head. Not that the code that I write that way works all of the time, but you'd be surprised how often I end up going down a path that is at least close to the correct one and eventually working things out. 



#43 C-Dawg

C-Dawg

    Magus

  • Members

Posted 26 May 2015 - 12:12 PM

I don't think an item script can call a global function and allow the global function to operate for multiple frames.  If it can, then that's an interesting (and un-intuitive!) workaround that I was unaware of.


  • ywkls likes this

#44 coolgamer012345

coolgamer012345

    🔸

  • Members
  • Location:Indiana, USA

Posted 26 May 2015 - 12:17 PM

I don't think an item script can call a global function and allow the global function to operate for multiple frames.  If it can, then that's an interesting (and un-intuitive!) workaround that I was unaware of.

Wouldn't using a Boolean check in the global script, and then when using the item script turn the bool on, and then in the Global Function/Script it could turn the Bool back off when it's done firing (or doing whatever it is supposed to do) work?


  • ywkls likes this

#45 C-Dawg

C-Dawg

    Magus

  • Members

Posted 26 May 2015 - 01:21 PM

Of course, but this requires the Global Script or another FFC script, like I said.  

 

A "Global Function" is not the same thing as the Global Script.  A Global Function is some function you define that can be called by any FFC script or the Global script in your game.  For instance, I have a function, " void life_bar," that any other script can call to draw a life bar on the screen for a given enemy.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users