Jump to content

Photo

RPG.zh, An RPG System Engine for Zelda Classic

header engine alpha xp script global functions rpg rpgzh

  • Please log in to reply
39 replies to this topic

#1 ZoriaRPG

ZoriaRPG

    ZC Contributor & Wiki Editor

  • Members
  • Gender:Unspecified
  • Location:Prydon Academy

Posted 04 April 2014 - 09:10 AM

RPG.zh: RPG System Engine for Zelda Classic

 

Updates

 

 

21st November, 2015

The present version is Alpha 0.97.7, although that is not a public build. I have hopes of releasing Alpha 1.0.0 in the Spring.

The newest extension is an enemy AI system, which is still in the initial planning, and design phase.

 

Present contributors: coolgamer012345, ywkls

Pending contributors: Binx, grayswandir

Documentation: ywkls, ZoriaRPG

 

Older Updates

Note: The latest build is a0,97.4. This is as yet, unreleased, pending some changes, and further testing.

Update: RPG.zh (alpha) v0.96.8 - 21st May, 2015.
Various additions, new framework components, new engine components.
Added modern, RPG-style enemy damage values drawn on each hit.
Deprecated functions into RPG_Legacy.zlib.
Additional item, and equipment functions.
Status bar functions.

Update: RPG.zh (alpha) v0.92 - 5th May, 2015.
Various additions.
Broken into separated library files.

Update: RPG.zh (alpha) v0.85 - 30th July, 2014.

Adding: Additional in-line contributor credits.

Update: RPG.zh (alpha) v0.84 - 25th July, 2014. 91K, ~3,000 lines.

Adding: Functions for FFC governance, to determine relative position between player, qnd FFC, and facing directions. (Used for menu commands.)

Menu command functions, booleans, and arrays.

Misc other additions.

Update: RPG.zh (alpha) v0.81 - 5th June, 2014

The header is rather large now (~2,400 lines), consisting primarily of functions associated with making an RPG. It isn't well-documented, but I will take care of that over time.

Functions are broken into categories:

  • XP (and XP Counters) Constants, Counters, Variables, and Functions
  • Level Functions
  • HP & MP Functions
  • Statistics Arrays, and Functions
  • Monetary System (and banking) Arrays, Variables, and Functions
  • Carrying Capacity Arrays & Functions
  • Custom Movement Functions
  • Armour & Shield Functions (minimal, for edible items; I'll be expanding these).
  • Dice-rolling (and other random number generation) Functions
  • Skill Check Arrays & Functions
  • Saving Throw Arrays & Functions
  • Saving Throw Failure Effects
  • Elemental (and other) Resistance Arrays & Functions
  • Misc Functions
  • Game Freeze Functions (needed for menu systems)
  • Clothing Functions (not much here, as yet)

Future Plans

  • Armour System -- Will require stdWeapons, stdCombos, and related headers.
  • Weapon Functions & Weapon / Item Scripts -- Requires stdWeaons, stdCombos, related headers, and other functions that aren't yet fully de-bugged.
  • Tango Menu Extensions -- As an optional extra.
  • Tango Font Packs --Also optional extras.

I already have much of the weapon system completed, but it's not included in this package, as I'm still testing it, and it would be best served as an imported file.

This does not include a global script. i will be making a cleaner global script, when I re-package this, breaking up the constants, variables, arrays, and functions into separate files by type, and sub-type.

I'll be adding (optional) Tango menus as a framework, once I have more done on this. (I do have working JRPG menus now, thanks to Saffith, but I;d like to make a package with a basic set-up tutorial as an extension to this.

  • Feel free to examine it, use it, print it out and burn it, or whatever you please.
  • If you encounter any bugs, please report them to me in a PM, or post them here.
  • If you've any functions that you want me to add, please post them here.

Note: Some functions are superfluous, and included only for compatibility with older builds. Others are multiple variations of similar functions, that allow flexibility in use.

Note 2: If you're using ghost.zh, uncomment line 254, and line 260. These freeze ghost action, when using the freezeAction() and the unfreezeAction() functions.
















 

----------------------------

ORIGINAL POST

----------------------------


Edited by ZoriaRPG, 21 November 2015 - 10:23 AM.

  • SkyLizardGirl and Dirtyshovel like this

#2 MoscowModder

MoscowModder

    MM//Productions!

  • Members
  • Gender:Male
  • Location:Wisconsin (WHAT)

Posted 04 April 2014 - 09:25 AM

The level-up can be done in much less code.

 

if(Game->Counter[CR_EXP] >= levelCosts[Game->Counter[CR_LEVEL]]){
    levelUp(Game->Counter[CR_LEVEL]);
    Game->Counter[CR_LEVEL]++;
}

  • Dirtyshovel likes this

#3 Avataro

Avataro

    Quest maker xD

  • Members
  • Real Name:Robin xD
  • Gender:Male
  • Location:Germany

Posted 04 April 2014 - 09:34 AM

Is this a pseudo code or something? Because you've got a lot of major errors in there.

Regarding your questions though, these things will only happen once, yes :)

#4 ZoriaRPG

ZoriaRPG

    ZC Contributor & Wiki Editor

  • Members
  • Gender:Unspecified
  • Location:Prydon Academy

Posted 04 April 2014 - 10:08 AM

I suppose that you could call it that: It's an initial template. That said, if you see me repeating specific errors, please feel free to comment them. I see some pretty obvious stuff, like misplaced semicolons, abut I am concerned that the Rand functions won't work together, and I wanted to check to see if theswe events will repeat infinitely.

 

O added the catch-all for 'nextLevel' to prevent that kind of thing, but I am wondering that if an item is set to true based on if nextLevel = x, that if that changes, the item will cease being ture, or if something must set it to false I think that items set to true this way won't go away until set to false, however, I should probably use assigns to set items to true, to avoid slowdown caused by setting it to true constantly.

 

Then again, if it is only set to true one time (the intent here, by using if nextLevel), I think it would work without an item assign.

 

I think that I also need to encapsulate the && stuff in another set of ( ) , which I neglected to do, but I wrote this in a hurry, while it was still in my mind, and haven't even tried to compile, much less test it yet.

 

I also didn't recall off-hand if to set the value of a counter, I should use = or ==. I need to look back at earlier work to check. I haven't done anything like this in half-a-year now, so I'm starting to forget things, and I'm working on this as a warm-up to get back into things.

 

If anyone wants to clean it up a bit, while I'm sleeping, that would also be fantastic. I plan to make this something useful for more than myself, but it will be heavily integrated into TGC. The roll functions, to produce a random number are something that I need to be able to call for a lot of events, including damage done from spells, or LWeapons, etc.

 

Essentially, something like this, called form a weapon script:

roll1d6(n);

n = power

 

I'm not wntirely certain at this moment how to use the values of a function properly, but I can check tomorrow and work on cleaning it up. Again, any patches to make these Rand functions work, and integrate them, so that I have a good working example of how to do this for the future, would be most appreciated.

 

I know that I should be setting an int in the function

void roll1d6(int n)

Then, in that function I make a Rand with an assign, something like this:

n = Rand6;

Then, I should be able to call the function roll1d6 from elsewhere, but I'm not sure of the syntax here. This is what happens when you get old, and senile, and don't do something for a while, that was new to you in the first place.

 

If the way I put any of the Rand operations together is dead wrong, I'd appreciate correction, especially if it has to do with using the values generating in one function, with another function.

 

@MM: I know that I can do it with [CR]++; if you note, I have that commented out (see while nextLevel = 1), for a very specific set of reasons. Using that method, if someone were to gain enough XP to gain more than one level, I think it may cause conflicts. This also allows me to set specific levels, and do other things, based on more fine-tuned factors.

 

I may change back to that method at some point, if I intend to implement level loss, but setting the counter with ++ versus setting a fixed value doesn't seem to be much of a difference, in my eyes, unless it is going to use more CPU cycles to track.

 

Other Note: At some point, I will need to total various Rands. I expect that it would not be best to make functions for stuff like roll4d6 (rand 1-6 + rand 1-6 + rand 1-6 + rand 1-6_). It would be better to execute roll1d6(n) four times, where needed, to avoid needing many functions, and then sum the results. I'm going to need to think on how to phrase that in the right syntax, as it can't me multiplied, the individual sums of each Rand must be totalled.

 

Knowing exactly how to use these functions will be a great aid to me for other projects.

 

A slightly fixed version:

 


Edited by ZoriaRPG, 04 April 2014 - 10:46 AM.


#5 Avataro

Avataro

    Quest maker xD

  • Members
  • Real Name:Robin xD
  • Gender:Male
  • Location:Germany

Posted 04 April 2014 - 10:31 AM

I can see how after a long break from ZScript you forget a lot of the stuff, but I can also imagine it would be easy to get back into it if you read through your older works. I oftentimes refer to scripts that I or others have written to see how to do or write certain things.

"n = Rand(6);" would assign a random value from 0 to 6 for the variable n. If you want it to be a random value from 1 to 6, you'd have to do this: "n = Rand(1, 6);". First number is the min value and second number is the max value that the Rand function should return.

What exactly do you mean by using assigns to set items to true? If you set an item to true once, it will stay true until you set it to false. That's correct. You have to keep in mind that setting an item to true actually means that Link gets this item into his inventory. The game will only slow down if you set it to true constantly, but if you only do it once, then that's no problem.

Also, you say you want to call the loops from elsewhere. This means you'll use FFCs for it, right? I don't see why you could not do this entire XP system through the global script if you do it a bit differently. I'm pretty sure it will be a lot easier if it's all handled in the global loop!

Edited by Avataro, 04 April 2014 - 10:34 AM.


#6 MoscowModder

MoscowModder

    MM//Productions!

  • Members
  • Gender:Male
  • Location:Wisconsin (WHAT)

Posted 04 April 2014 - 02:45 PM

@MM: I know that I can do it with [CR]++; if you note, I have that commented out (see while nextLevel = 1), for a very specific set of reasons. Using that method, if someone were to gain enough XP to gain more than one level, I think it may cause conflicts. This also allows me to set specific levels, and do other things, based on more fine-tuned factors.

 

Getting multiple levels at once should be fine - if your exp gets to L3 while your level is L1, the function will level up to 2, and the very next frame, level up again to 3. Depends how the function works.



#7 ZoriaRPG

ZoriaRPG

    ZC Contributor & Wiki Editor

  • Members
  • Gender:Unspecified
  • Location:Prydon Academy

Posted 04 April 2014 - 03:45 PM

I can see how after a long break from ZScript you forget a lot of the stuff, but I can also imagine it would be easy to get back into it if you read through your older works. I oftentimes refer to scripts that I or others have written to see how to do or write certain things.

"n = Rand(6);" would assign a random value from 0 to 6 for the variable n. If you want it to be a random value from 1 to 6, you'd have to do this: "n = Rand(1, 6);". First number is the min value and second number is the max value that the Rand function should return.

What exactly do you mean by using assigns to set items to true? If you set an item to true once, it will stay true until you set it to false. That's correct. You have to keep in mind that setting an item to true actually means that Link gets this item into his inventory. The game will only slow down if you set it to true constantly, but if you only do it once, then that's no problem.

Also, you say you want to call the loops from elsewhere. This means you'll use FFCs for it, right? I don't see why you could not do this entire XP system through the global script if you do it a bit differently. I'm pretty sure it will be a lot easier if it's all handled in the global loop!

 

I may have my understanding wrong here, but as I understand things, any function in the global script, can be called by any other script, even if only for one frame. Thus, the Rand operations, could be called from FFC, or any item or enemy script.

 

I didn't know that Rand included zero, but I was also wondering if there was a way to limit the lowest value. That's quite helpful.

 

I'm hoping that because the Level functions changes the int for nextLevel, that they can't run more than one time. I always worry about how ZScript ordering works.

 

@MM: I will try it both ways, and see if any has any distinct advantage; but in operations, the way I am setting this up, would there be any advantage to one method over the other? that is, setting a counter increase, or setting an exact counter value? I did it this way to ensure precision, but your method would allow to gain levels beyond 20.

 

I'm not discounting either the validity, or the cleanliness, but I do think that doing it that way for this game may cause problems, with the intended methods of level advancement; and attaining L20 is intended to be hard--DQ hard--and highly optional. Given how many enemies you need to kill to gain 221,907XP, at a ration of enemy HP= XP, it means tacking lots of very powerful monsters, to get there, which is why bonus levels, that have no XP requirement, for completing story objectives are a cool reward.

 

For example, if there is an objective, that when completed, grants a 'bonus level', without regard to XP, then, the next time the character reaches an XP goal to level, they would also gain a level, which is not intended. As I plan to include optional events to give levels early (to avoid mandatory grinding), I wanted to ensure that the player couldn't exceed the level required for EXP totals, by doing it this way. That's one of my reasons for specifying levels.

 

If that isn't clear, I'll try explaining this, but I feat it may be a bit odd to read, as I'm half alseep:

 

The player is at Level 10, having 3900XP. To get to level 11, they would need 5772 XP.. In a special side-quest, they are given a bonus level. using the level++ method, making them Level 11, but with only 4000XP. If I used the counter++ method for everything, they they got to 5772XP, they would become Level 12, instead of needing the actual 8658XP to attain level 12.

 

The bonus level gives them features early, but doesn't allow them to skip getting XP to go further, the way I have it now, but if everything used the counter++ method, they could get to Level 20 much faster, making bonus levels far more broken.

 

I intend to offer these special side-quests for early level features, but I don't want to break the XP table in the process.

 

It's not that using counter++ is bad; but it would limit some of my other ideas. I would certainly provide both in any published script set.

 

---

 

@Avataro: Do you see anything else that is obviously broken in the updated script, other than a few missing semicolons in the functions?

 

Do these look like they would work right (and will they function together, as intended)?

 

 

For example, the function rollStat is supposed to determine the statistic to increase, uses a Rand to determine the stat to boost, and then use the roll1d6 function to determine the amount.

 

The function increaseStat() should read these values from rollStat (int stat, int v), and increase the stat provided by the stat int, by the amount of the v int, from the rollStat function. I'm not sure if these values carry over, or if I need to make an array for them.

 

For reasons to make them global functions, I think that if I make a normal weapon call roll1d10, to generate its power, for example, would generate a random number from 1 to 10 on every strike, instead of a fixed power. As I understand things, any script can call a global function. Please feel free to correct me if that is incorrect, but I was planning something like this

p = roll1d10(); // or would this be p = roll1d10(n); ? 
lweapon foo;
foo = NextToLink(LType, 8);
foo->UseSprite(#);
bolt->Damage = p;

Edited by ZoriaRPG, 04 April 2014 - 03:49 PM.


#8 Avataro

Avataro

    Quest maker xD

  • Members
  • Real Name:Robin xD
  • Gender:Male
  • Location:Germany

Posted 04 April 2014 - 05:08 PM

At first, it seemed to me that you made some of these functions have loops in them, which would break global scripts and thus the global script better shouldn't call them, but nevermind this now :)

I can't see anything wrong anymore, but I'm not the best person to ask about functions with variables. I'm on the same boat as you actually. Not sure when variables will be carried over or how to correctly return values. But yeah, I think that in yor final code, the correct way to do it is "p = roll1d10(p);".

#9 Master Maniac

Master Maniac

    Earth, Wind, Fire, and Water.

  • Members
  • Real Name:kris
  • Gender:Intersexed

Posted 05 April 2014 - 07:16 AM

Rand can set the lower limit by using two arguments. The first argument is the lowest possible number and the second argument is the highest. Using one argument produces a random number between zero and your argument.

#10 ZoriaRPG

ZoriaRPG

    ZC Contributor & Wiki Editor

  • Members
  • Gender:Unspecified
  • Location:Prydon Academy

Posted 05 April 2014 - 10:49 AM

Right, now that Avataro had posted this, in use, with an example, it was much clearer. The ZScript.txt file doesn;t explain this, and make it seem that Rand can parse only one value:
 
 

/**
* Computes and returns a random integer i such that 0 <= i < maxvalue.
* The return value is undefined if maxvalue is 0 or negative.
*/
int Rand(int maxvalue);

 
The documentation didn't include any mention of minimum values or how to express them; but then, the included documentation doesn't give working examples of anything. (I have the same complaint about many manpage files).
 
I still don't know if I need to add any arrays, to store the values produced by a Rand in one command, to be used by another; or return functions to the commands, but I have a feeling that I will need one of the two, on most of the commands that produce an integer; except that the documentation states that Rand already returns a value.
 
In other words, is what I am doing going to forward the values from one function to another; or do I need to return that value separately, or ads that value to a global array of some kind, so that it is retained, until something else replaces that same value?
 
 
Let me put some of these functions together in a series, to explain what I mean:
 
(1): This function, called with the XP system, will call other functions. In this example, it calls the function increaseStat(). I probably need additional ints in the function , such as. void Level1(int hpx, int mpx, int n, int v, int stat) for the values returned by the other functions in this chain, in each function, including possibly changing this to increaseStat(stat, v) but I would appreciate some clarification on this point.
 
 

void Level1(int hpx, int mpx) {
increaseStat(); //This should happen one time, when gaining this level, and be permanent.
}

 
(2): The increaseStat() function calls on the rollstat() function; I am intentionally separating this, to allow more flexibility later:
 
 

void increaseStat(int stat, int v){
rollstat();
Game->Counter[stat] =+ v;
}

 
(3): The rollStat() function uses an internal Rand to select a random stat to increase, and then calls on the roll1d6() function, to generate the value of the increase. If the first Rand provides a 3, it would increase the counter CR_LUCK by the value returned by roll1d6(). This is also intentionally separated, to allow for different statistic systems, later. I should also call this rollRandomStat() to allow for specific stat increases, but I'll add a new function to do that, and rename this, once I comprehend how to forward the values returned from one function to another.
 
 

void rollStat(int r, int stat, int n) {
    r = Rand(6); //specific value of 1-6 set at random;
    if ( r == 1 ) {
    stat = Game->Counter[CR_STAT_BODY];
    }
    if ( r == 2 ) {
    stat = Game->Counter[CR_STAT_MIND];
    }
    if ( r == 3 ) {
    stat = Game->Counter[CR_STAT_LUCK];
    }
    if ( r == 4 ) {
    stat = Game->Counter[CR_STAT_MYST];
    }
    if ( r == 5 ) {
    stat = Game->Counter[CR_STAT_INFL;
    }
    if ( r == 6 ) {
    stat = Game->Counter[CR_STAT_MUSC];
    }
    v = roll1d6(n);
}

 
(4): This finally calls on roll1d6(n). i don;t know if that is the correct way to call the function, to forward the value produced by void roll1d6(int n). :
 
 

void roll1d6(int n) {
n = Rand(1, 6);
}

Level-Up only on Screens Free of Enemies

 

One other very important thing that I want to include, is a prerequisite that a screen be entirely clear of enemies, before levelling. This isn't intended to punish the player, but rather, to prevent interruption during combat. The last thing anyone wants is a random message, and events happening, while in a desperate fight.

 

How should I determine of there are no enemies on the current screen?


Edited by ZoriaRPG, 05 April 2014 - 10:52 AM.


#11 MoscowModder

MoscowModder

    MM//Productions!

  • Members
  • Gender:Male
  • Location:Wisconsin (WHAT)

Posted 05 April 2014 - 11:02 AM

1. Rand(int min, int max) is declared in std_functions.zh

 

2. Do this:

while(Screen->NumNPCs() > 0)
    Waitframe();


#12 ZoriaRPG

ZoriaRPG

    ZC Contributor & Wiki Editor

  • Members
  • Gender:Unspecified
  • Location:Prydon Academy

Posted 05 April 2014 - 01:21 PM

I assume that this would also work an an if statement:

if ( Screen->NumNPCs() > 0 )
    //Do this

I'm a bit concerned over the best way to approach this, to ensure that if the triggering *level) event happens while there are NPCs on the screen, that it isn't cancelled; bit instead, waits for the screen to be clear of NPCs, and then occurs.

 

I expect that adding an additional while, with the NPCs are a catch-all, would certainly work; being that the function is in a global loop, and will keep waitframing out until the condition no longer exists. I don't know if prefixing the commands inside the function with an if statement would operate in the same way, however I can add that to the XP functions, in an inverted manner.

 

(Example)

while ( LevelNext = 1 && Screen->NumNPCs() = 0 )

I still need to worry about carrying over the values from one function to another. Do you have any advice in that regard?

 

I'll look over some other script sets that do this, particularly ghost.zh to re-examine the format, and syntax; but if there are any guidelines that you would suggest using, I'd be happy to hear them.

 

I also think that I need some additional catchalls, for any instance where the player gains levels out of sequence. That is, if something increases their level from 12 to 14, that they gain whatever they are due from Level 13 in the process. I don't think this will happen in my game, but if others use this with much closer XP values, it could.

 

I don;t know, for example, if the player would gain the benefits of levelling twice, for example, if , occur at the same time, because the event that triggers one will supercede the other. I still don;t understand ZScript order of operations, and simultaneity; and I'm\not certain if anyone does.

 

This is what I foresee as a problem:

 

Level 1 requires 100 XP

Level 2 requires 150 XP

Level 2 requires 300 XP.

 

If the player goes from ( >100 ) to ( < 300 ) XP, they may not gain the benefits for Level 2, which requires a value between ( 150 ) and ( 299 ).The closer the values are to each-other, the more feasible it is that this could happen.

 

Last, I already require stdExtra.zh with most of my files, but it's good to know that to use the minvalue for a Rand, that it is mandatory to include stdExtra.zh. I try to be accurate when listing dependencies.

 

I assume that you created an entirely new Rand routine, that replaces the one in std.zh, which is why the default docs don;t handle the function in this manner. I was hoping when I first envisioned this, that I could set a minimum value, for some things. One of the ideas for my game will require generating a random value, and comparing that to another value, to determine success, much like most pen & paper RPGs; but some would work better with specific values, such as string selection, with a minimum string value, and a maximum string value.

 

I was planning to do those with assigns, and may still need to do that, if the strings are not a full sequence in series.

 

Is there a way to operate the Rand function to produce a number from X to Y, excluding specific numbers in that range; or should I add that kind of function?

 

Something like this:

 

void exRand(minvalue, maxvalue, exclude, excludeRange, excludeList)
exclude sets a specific number to exclude.

excludeRange sets a range of numbers to exclude

excludeList reads numbers from a list, and excludes those

If exRand produces a number from any of these excluded values, it clears that value, and produces another random value, repeating this, until it produces one that is not excluded.

 

I should probably add that function to something, as it shouldn't be hard to create, although the excludeList would be a tad tricky to work out in a way that isn't hideous.

 

Updated Script (v.17)


Edited by ZoriaRPG, 05 April 2014 - 01:34 PM.


#13 MoscowModder

MoscowModder

    MM//Productions!

  • Members
  • Gender:Male
  • Location:Wisconsin (WHAT)

Posted 05 April 2014 - 01:44 PM

Rand(min, max) is in std_functions.zh (half of std.zh), not stdExtra.zh.

 

I think you're over-complicating the problem. I still think that my idea (with the code snippet from my first post) will allow you to gain multiple levels at once. You can also put the enemy check inside that snippet to wait for enemies to be gone.

if(Game->Counter[CR_EXP] >= levelCosts[Game->Counter[CR_LEVEL]] && Screen->NumNPCs() == 0){
    levelUp(Game->Counter[CR_LEVEL]);
    Game->Counter[CR_LEVEL]++;
}

Why don't you just give it a try instead of theorizing about what might happen?



#14 ZoriaRPG

ZoriaRPG

    ZC Contributor & Wiki Editor

  • Members
  • Gender:Unspecified
  • Location:Prydon Academy

Posted 05 April 2014 - 04:32 PM

Sorry, I mis-read your post. I removed stdExtra.zh as a current dependency, but it is likely to be one at some point.

 

Current Version (v.22)
 


Edited by ZoriaRPG, 05 April 2014 - 04:42 PM.


#15 ZoriaRPG

ZoriaRPG

    ZC Contributor & Wiki Editor

  • Members
  • Gender:Unspecified
  • Location:Prydon Academy

Posted 06 April 2014 - 01:47 AM

Updated in top post, with working demo. Thanks mates!



Also tagged with one or more of these keywords: header, engine, alpha, xp, script, global, functions, rpg, rpgzh

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users