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.
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
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
----------------------------
I'm working on an improved XP & Level System, and would appreciate if some of you would look at my code thus far, and tell me if I am outright breaking anything.
This version is updated, tested, and working. There is a test file, below, if you wish to examine it in operation. Grind to Level 5, if you wish, to see how the system grants skills.
This release includes many bugfixes, including the following:
XP System uses two counters. One for the values 0-9999, and one for the ten-thousands place & hundred-thousands place, allowing a maximum XP count of 999,999. (This can also be used for a points system.)
Exceeding 999,999 will no-longer roll-over any counters; or can be set to reset all counters to zero (for points games).
Level-catching is now fixed, if 10K counter and XP counter are changed simultaneously.
Added other pre-emptive catching.
The script is now too long to post directly. Please use the download link above for the latest release.
Here is a new .qst file, associated with the latest script version above. This is a much nice-looking demo, with an enemy that can be abused to quickly gain XP, testing the counters. (It includes a clean subscreen, that has all the XP System counters in actual use.)
v.58 (r0.58) (Updated 6th April, 2014)
//////////////////////////////////// XP System for ZC ////////////// v.58 //////////////////////////////////////////////////////////////////////////////////////// Creator: ZoriaRPG /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ASSISTANCE BY: ////// CONTRIBUTORS: ////// TESTING: ///////// anikom15 ////// MoscowModder ////// ///////// Avataro ////// ////// ///////// MoscowModder ////// ////// /////////////////////////////////////////////////////////////////////////////////import "std.zh"//import "stdExtra.zh" //Not a dependency at this time.//immport "sdtZoria.zh" //Not a dependency at this time.const int HP_DEAD = -999;const int NPC_MISC_MAXHP = 0; //Which npc->Misc[] value to store HP in (don't touch)const int EXP_HP_RATIO = 1; //Enemy EXP value = HP divided by thisconst int CR_HP = 8;const int CR_MP = 9;const int CR_HP_MAX = 10;const int CR_MP_MAX = 11;const int CR_XP = 12;const int CR_LEVEL = 13;const int CR_LVL = 13;const int CR_STAT_MUSC = 26;const int CR_STAT_BODY = 27;const int CR_STAT_MIND = 28;const int CR_STAT_MYST = 29;const int CR_STAT_INFL = 30;const int CR_STAT_LUCK = 31;const int L1String = 1;const int L2String = 1;const int L3String = 1;const int L4String = 1;const int L5String = 3;const int L6String = 1;const int L7String = 1;const int L8String = 1;const int L9String = 1;const int L10String = 1;const int L11String = 1;const int L12String = 1;const int L13String = 1;const int L14String = 1;const int L15String = 1;const int L16String = 1;const int L17String = 1;const int L18String = 1;const int L19String = 1;const int L20String = 1;const int levelSound = 253;global script active{ void run(){ Game->MCounter[CR_LEVEL] = 20; Game->MCounter[CR_XP] = 211500; Game->Counter[CR_STAT_BODY] = 10; Game->MCounter[CR_STAT_BODY] = 100; Game->Counter[CR_STAT_MUSC] = 10; Game->MCounter[CR_STAT_MUSC] = 100; Game->Counter[CR_STAT_MIND] = 10; Game->MCounter[CR_STAT_MIND] = 100; Game->Counter[CR_STAT_MYST] = 10; Game->MCounter[CR_STAT_MYST] = 100; Game->Counter[CR_STAT_INFL] = 10; Game->MCounter[CR_STAT_INFL] = 100; Game->Counter[CR_STAT_LUCK] = 10; Game->MCounter[CR_STAT_LUCK] = 100; while (true) { Game->Counter[CR_HP] = Link->HP; Game->Counter[CR_MP] = Link->MP; Game->Counter[CR_HP_MAX] = Link->MaxHP; Game->Counter[CR_MP_MAX] = Link->MaxMP; //UpdateEWeapons(); //CleanUpGhostFFCs(); // Only needed if __GH_USE_DRAWCOMBO is 0 //UpdateLWeapons(); //UpdateLastItem(); //if (Link->PressB) {LastItemUsed = GetEquipmentB();} //if (Link->PressA) {LastItemUsed = GetEquipmentA();} Waitdraw(); XP(); //AutoGhost(); //DrawGhostFFCs(); //lastScreen = Game->GetCurDMapScreen(); //Update last screen/DMap //lastDMap = Game->GetCurDMap(); Waitframe(); } }}////////////////////////////////////// XP System Base Functions //////////////////////////////////////int enemyEXPWorth(npc enem){ return Max(1, enem->Misc[NPC_MISC_MAXHP] / EXP_HP_RATIO);}void giveEXP(int amount){ //Give EXP Game->Counter[CR_XP] += amount; } //Check for new enemies and set their max HPvoid setMaxHP(){ for ( int i = Screen->NumNPCs(); i > 0; i-- ){ npc enem = Screen->LoadNPC(i); if ( enem->Misc[NPC_MISC_MAXHP] == 0 ) enem->Misc[NPC_MISC_MAXHP] = enem->HP; }}void checkEnemiesKilled(){ for ( int i = Screen->NumNPCs(); i > 0; i-- ){ npc enem = Screen->LoadNPC(i); if ( enem->HP <= 0 && enem->HP > HP_DEAD ){ enem->HP = HP_DEAD; int worth = enemyEXPWorth(enem); //Leadership: Chance to increase EXP worth //if ( Link->Item[I_LEADERSHIP] && Rand(EXP_LEADERSHIPCHANCE) == 0 ) worth++; giveEXP(worth); } }}void XP() { setMaxHP(); checkEnemiesKilled(); levelSystem(); }void levelSystem() { if ( Game->Counter[CR_LVL] == 0 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 100 ){ Game->Counter[CR_LVL] = 1; Level1(); } } if ( Game->Counter[CR_LVL] == 1 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 150 ) { Game->Counter[CR_LVL] = 2; Level2(); } } if ( Game->Counter[CR_LVL] == 2 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 225 ) { Game->Counter[CR_LVL] = 3; Level3(); } } if ( Game->Counter[CR_LVL] == 3 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 338 ) { Game->Counter[CR_LVL] = 4; Level4(); } } if ( Game->Counter[CR_LVL] == 4 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 507 ) { Game->Counter[CR_LVL] = 5; Level5(); } } if ( Game->Counter[CR_LVL] == 5 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 760 ){ Game->Counter[CR_LVL] = 6; Level6(); } } if ( Game->Counter[CR_LVL] == 6 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 1140 ){ Game->Counter[CR_LVL] = 7; Level7(); } } if ( Game->Counter[CR_LVL] == 7 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 1710 ){ Game->Counter[CR_LVL] = 8; Level8(); } } if ( Game->Counter[CR_LVL] == 8 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 2565 ){ Game->Counter[CR_LVL] = 9; Level9(); } } if ( Game->Counter[CR_LVL] == 9 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 3848 ){ Game->Counter[CR_LVL] = 10; Level10(); } } if ( Game->Counter[CR_LVL] == 10 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 5772 ){ Game->Counter[CR_LVL] = 11; Level11(); } } if ( Game->Counter[CR_LVL] == 11 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 8658 ){ Game->Counter[CR_LVL] = 12; Level12(); } } if ( Game->Counter[CR_LVL] == 12 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 12987 ){ Game->Counter[CR_LVL] = 13; Level13(); } } if ( Game->Counter[CR_LVL] == 13 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 19481 ){ Game->Counter[CR_LVL] = 14; Level14(); } } if ( Game->Counter[CR_LVL] == 14 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 29222 ){ Game->Counter[CR_LVL] = 15; Level15(); } } if ( Game->Counter[CR_LVL] == 15 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 43833 ){ Game->Counter[CR_LVL] = 16; Level16(); } } if ( Game->Counter[CR_LVL] == 16 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 65750 ){ Game->Counter[CR_LVL] = 17; Level17(); } } if ( Game->Counter[CR_LVL] == 17 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 98625 ){ Game->Counter[CR_LVL] = 18; Level18(); } } if ( Game->Counter[CR_LVL] == 18 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 147938 ){ Game->Counter[CR_LVL] = 19; Level19(); } } if ( Game->Counter[CR_LVL] == 19 && Screen->NumNPCs() == 0 ) { if ( Game->Counter[CR_XP] >= 210000 ){ Game->Counter[CR_LVL] = 20; Level20(); } }}/////////////////////////// XP TABLE ////////////////////////////////////// 0 = 0 /////////// 100 = 1 /////////// 150 = 2 /////////// 225 = 3 /////////// 338 = 4 /////////// 507 = 5 /////////// 760 = 6 /////////// 1140 = 7 /////////// 1710 = 8 /////////// 2565 = 9 /////////// 3848 = 10 /////////// 5772 = 11 /////////// 8658 = 12 /////////// 12987 = 13 /////////// 19481 = 14 /////////// 29222 = 15 /////////// 43833 = 16 /////////// 65750 = 17 /////////// 98625 = 18 /////////// 147938 = 19 /////////// 210000 = 20 ////////////////////////////////////////////////////// XP Algorithm //////// C = Current Base //////// H = Half Current Base //////// N = Amount Needed for Next Level //////// C + H = N //////// Thus C (100) + H (50) = N (150) /////////////////////////////////////////////////////////////////////////// Bump Functions /////////////////////////////void increaseMP() {int amount = ( rollDie(10) + rollDie(10) + rollDie(10) );int myst = ( getMystStat() / 2 );int total = ( amount + myst );Link->MP += total;Link->MaxMP += total;}void increaseHP() {int amount = ( rollDie(10) + rollDie(10) + rollDie(10) + rollDie(10) + rollDie(10) );int body = ( getBodyStat() / 2 );int total = ( amount + body );Link->HP += total;Link->MaxHP += total;}//////////////////////////// Roll Functions ////////////////////////////int rollStat() { int r = Rand(1, 6); //specific value of 1-6 set at random; if ( r == 1 ) { int stat = CR_STAT_BODY; return stat; } else if ( r == 2 ) { int stat = CR_STAT_MIND; return stat; } else if ( r == 3 ) { int stat = CR_STAT_LUCK; return stat; } else if ( r == 4 ) { int stat = CR_STAT_MYST; return stat; } else if ( r == 5 ) { int stat = CR_STAT_INFL; return stat; } else if ( r == 6 ) { int stat = CR_STAT_MUSC; return stat; } }void increaseStat() {int stat = rollStat();int n = rollDie(6);Game->Counter[stat] += n;}int rollDie(int type){int n = Rand(1, type);return n;}int roll1d4() {int n = Rand(1, 4);return n;}int roll1d6() {int n = Rand(1, 6);return n;}int roll4d6(){ int a = Rand(1, 6); int b = Rand(1, 6); int c = Rand(1, 6); int d = Rand(1, 6); int t = ( a + b + c + d ); return t; }int roll1d8() {int n = Rand(1, 8);return n;}int roll1d10() {int n = Rand(1, 10);return n;}int roll1d12() {int n = Rand(1, 12);return n;}int roll1d20() {int n = Rand(1, 20);return n;}int roll1d50() {int n = Rand(1, 50);return n;}int roll1d100() {int n = Rand(1, 100);return n;}///////////////////////////// Stats Functions ///////////////////////////////void setBodyStat(value){//}////void setMindStat(value){//}////void setLuckStat(value){//}////void setMystStat(value){//}////void setInflStat(value){//}////void setMuscStat(value){//}//void setStat(stat, value){//}int getBodyStat(){ int stat = CR_STAT_BODY; return stat;}int getMindStat(){ int stat = CR_STAT_MIND; return stat;}int getLuckStat(){ int stat = CR_STAT_LUCK; return stat;}int getMystStat(){ int stat = CR_STAT_MYST; return stat;}int getInflStat(){ int stat = CR_STAT_INFL; return stat;}int getMuscStat(){ int stat = CR_STAT_MUSC; return stat;}// Using Stats// heavy weapon script particles// discover present slot of item// set int of slot of item for bools// when trying to use the item// if CT_MUSC < x // set other slot to 'hand' until item is changed.//// Use Body to affect HP:// Use Body to set HP at level increases. Use to set HP regen rate.// Use MUSC to set-augment weapon damage, via roll1dX rands. // Use MUSC for ability to move objects.// bracelets increase Musc, as well as activating triggers. // Bracelet / gauntlet takes up a slot. Any combination of two rings, or one ring and one bracelet at one time. // Use Luck to set jinx durations.// Use Myst to set spell damage.// Require Myst of certain value to use some spells.// Ue Mind for Lore skills. // Use Mind for raw (untrained) examination checks. // Create LWeapon that deals damage based on dX rolls.// Is there any way to use MUSC and random damage on swords?// Possibly replace rhe power of the LW_SWORD generated with a sword with a different value?// INF should set the strings used on FFC scripts when conversing.// A higher INF would open up more lines of dialogue. ///////////////////////////// Level Functions /////////////////////////////void Level1() {Game->PlaySound(levelSound);Screen->Message(L1String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP(); //Increases HP by 4d10increaseMP(); //Increases MP by 3d10increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level2() {Game->PlaySound(levelSound);Screen->Message(L2String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level3() {Game->PlaySound(levelSound);Screen->Message(L3String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level4() {Game->PlaySound(levelSound);Screen->Message(L4String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level5() {Game->PlaySound(levelSound);Screen->Message(L5String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.Game->Generic[GEN_CANSLASH] = 1; //This should occur when gaining this level, and be permanent.}void Level6() {Game->PlaySound(levelSound);Screen->Message(L6String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level7() {Game->PlaySound(levelSound);Screen->Message(L7String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level8() {Game->PlaySound(levelSound);Screen->Message(L8String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level9() {Game->PlaySound(levelSound);Screen->Message(L9String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level10() {Game->PlaySound(levelSound);Screen->Message(L10String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level11() {Game->PlaySound(levelSound);Screen->Message(L11String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level12() {Game->PlaySound(levelSound);Screen->Message(L12String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level13() {Game->PlaySound(levelSound);Screen->Message(L13String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level14() {Game->PlaySound(levelSound);Screen->Message(L14String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level15() {Game->PlaySound(levelSound);Screen->Message(L15String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level16() {Game->PlaySound(levelSound);Screen->Message(L16String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level17() {Game->PlaySound(levelSound);Screen->Message(L17String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level18() {Game->PlaySound(levelSound);Screen->Message(L18String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level19() {Game->PlaySound(levelSound);Screen->Message(L19String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}void Level20() {Game->PlaySound(levelSound);Screen->Message(L20String); //This should show on-screen one time, when gaining the level, and not remain forever.increaseHP();increaseMP();increaseStat(); //This should happen one time, when gaining this level, and be permanent.}
This should all be working now.I will be updating this over time, adding new functions, skills and such, but if you want to use it now, you can easily add things to the level() functions.
Please let me know if anything here is terribly broken (in the scripts). The .qst file is a quick hack-job, to implement counters, and not to be pretty. it has four basic screens, with some enemies; the Keese drop huge 75XP items, to quickly rack it up for testing. Enemy HP -> XP conversion works as it did in MoscowModder's script.
It does have a clean passive submenu, with working counters for everything; despite not being overly flashy.
When I am further along, I will add some documentation.
Some Notes
Increases to HP & MP work based on random numbers, emulating rolling 4d10, and 3d10, plus a statistic. in this case, the statistics Body, and Myst are set to 10, and the random rolls are added to a statistic / 2, so each increase grants 4d10+5, or 3d10+5, respectively.
This includes some fixed die types to use, but it also includes a variable rollDie() function. You can set the die type like this:
rollDie(6); //rolls 1d6rollDie(13) //rolls 1d13
I plan to eventually tie most functions into the rollDie system, including attack power, working towards stdZoria.zh, an RPG header system.
Note that I intentionally designed all of these as single global functions, so that they can be called from anywhere.
Update: I added SFX code to levels, and improved the demo. The link for the demo remains the same, however I increased the version to '1', to avoid clashing with previous saves.
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:
const int CR_XP = 12;
const int CR_LVL = 13;
const int CR_STAT_BODY = 31;
const int CR_STAT_MIND = 30;
const int CR_STAT_LUCK = 29;
const int CR_STAT_MYST = 28;
const int CR_STAT_INFL = 27;
const int CR_STAT_MUSC = 26;
int Level = 0;
int LevelNext = 0;
const int L1String = 101;
const int L1String = 102;
const int L1String = 103;
const int L1String = 104;
const int L1String = 105;
const int L1String = 106;
const int L1String = 107;
const int L1String = 108;
const int L1String = 109;
const int L1String = 110;
const int L1String = 111;
const int L1String = 112;
const int L1String = 113;
const int L1String = 114;
const int L1String = 115;
const int L1String = 116;
const int L1String = 117;
const int L1String = 118;
const int L1String = 119;
const int L1String = 120;
while true{
XP();
Waitframe();
}
void XP() {
//if there are no eenemeies on the screen{
while ( LevelNext = 0 ) {
if ( Game->Counter[CR_XP] > 0 && Game->Counter[CR_XP] < 100 ){
Game->Counter[CR_LVL] = 0;
}
}
while ( LevelNext = 1 ) {
if ( Game->Counter[CR_XP] >= 100 && Game->Counter[CR_XP] < 150 ){
Game->Counter[CR_LVL] = 1;
//Game->Counter[CR_LVL]++;
Level1();
}
}
while ( LevelNext = 2 ) {
if ( Game->Counter[CR_XP] >= 150 && Game->Counter[CR_XP] < 225 ){
Game->Counter[CR_LVL] = 2;
Level2();
}
}
while ( LevelNext = 3 ) {
if ( Game->Counter[CR_XP] >= 225 && Game->Counter[CR_XP] < 338 ){
Game->Counter[CR_LVL] = 3;
Level3();
}
}
while ( LevelNext = 4 ) {
if ( Game->Counter[CR_XP] >= 338 && Game->Counter[CR_XP] < 507 ){
Game->Counter[CR_LVL] = 4;
Level4();
}
}
while ( LevelNext = 5 ) {
if ( Game->Counter[CR_XP] >= 507 && Game->Counter[CR_XP] < 760 ){
Game->Counter[CR_LVL] = 5;
Level5();
}
}
while ( LevelNext = 6 ) {
if ( XGame->Counter[CR_XP] >= 760 && Game->Counter[CR_XP] < 1140 ){
Game->Counter[CR_LVL] = 6;
Level6();
}
}
while ( LevelNext = 7 ) {
if ( Game->Counter[CR_XP] >= 1140 && Game->Counter[CR_XP] < 1710 ){
Game->Counter[CR_LVL] = 7;
Level7();
}
}
while ( LevelNext = 8 ) {
if ( Game->Counter[CR_XP] >= 1710 && Game->Counter[CR_XP] < 2565 ){
Game->Counter[CR_LVL] = 8;
Level8();
}
}
while ( LevelNext = 9 ) {
if ( Game->Counter[CR_XP] >= 2565 && Game->Counter[CR_XP] < 3848 ){
Game->Counter[CR_LVL] = 9;
Level9();
}
}
while ( LevelNext = 10 ) {
if ( Game->Counter[CR_XP] >= 3848 && Game->Counter[CR_XP] < 5772 ){
Game->Counter[CR_LVL] = 10;
Level10();
}
}
while ( LevelNext = 11 ) {
if ( Game->Counter[CR_XP] >= 5772 && Game->Counter[CR_XP] < 8658 ){
Game->Counter[CR_LVL] = 11;
Level11();
}
}
while ( LevelNext = 12 ) {
if ( Game->Counter[CR_XP] >= 8658 && Game->Counter[CR_XP] < 12987 ){
Game->Counter[CR_LVL] = 12;
Level12();
}
}
while ( LevelNext = 13 ) {
if ( Game->Counter[CR_XP] >= 12987 && Game->Counter[CR_XP] < 19481 ){
Game->Counter[CR_LVL] = 13;
Level13();
}
}
while ( LevelNext = 14 ) {
if ( Game->Counter[CR_XP] >= 19481 && Game->Counter[CR_XP] < 29222 ){
Game->Counter[CR_LVL] = 14;
Level14();
}
}
while ( LevelNext = 15 ) {
if ( Game->Counter[CR_XP] >= 29222 && Game->Counter[CR_XP] < 43833 ){
Game->Counter[CR_LVL] = 15;
Level15();
}
}
while ( LevelNext = 16 ) {
if ( Game->Counter[CR_XP] >= 43833 && Game->Counter[CR_XP] < 65750 ){
Game->Counter[CR_LVL] = 16;
Level16();
}
}
while ( LevelNext = 17 ) {
if ( Game->Counter[CR_XP] >= 65750 && Game->Counter[CR_XP] < 98625 ){
Game->Counter[CR_LVL] = 17;
Level17();
}
}
while ( LevelNext = 18 ) {
if ( Game->Counter[CR_XP] >= 98625 && Game->Counter[CR_XP] < 147938 ){
Game->Counter[CR_LVL] = 18;
Level18();
}
}
while ( LevelNext = 19 ) {
if ( Game->Counter[CR_XP] >= 147938 && Game->Counter[CR_XP] < 221907 ){
Game->Counter[CR_LVL] = 19;
Level19();
}
}
while ( LevelNext = 20 ) {
if ( Game->Counter[CR_XP] >= 221907 ){
Game->Counter[CR_LVL] = 20;
Level20();
}
}
}
////////////////////////
/// XP TABLE ///////////
////////////////////////
/// 0 = 0 ////////
/// 100 = 1 ////////
/// 150 = 2 ////////
/// 225 = 3 ////////
/// 338 = 4 ////////
/// 507 = 5 ////////
/// 760 = 6 ////////
/// 1140 = 7 ////////
/// 1710 = 8 ////////
/// 2565 = 9 ////////
/// 3848 = 10 ////////
/// 5772 = 11 ////////
/// 8658 = 12 ////////
/// 12987 = 13 ////////
/// 19481 = 14 ////////
/// 29222 = 15 ////////
/// 43833 = 16 ////////
/// 65750 = 17 ////////
/// 98625 = 18 ////////
/// 147938 = 19 ////////
/// 221907 = 20 ////////
//////////////////////////////////////////
//// XP Algorithm ////
//// C = Current Base ////
//// H = Half Current Base ////
//// N = Amount Needed for Next Level ////
//// C + H = N ////
//// Thus C (100) + H (50) = N (150) ////
//////////////////////////////////////////
void Level1(int hpx, int mpx) {
Screen->Message[L1String]; //This should show on-screen one time, when gaining the level, and not remain forever.
Link->MP += 32; //Increases MP - This should happen one time, when gaining this level, and be permanent.
Link->MaxMP += 32; //Increases Max MP - This should happen one time, and be permanent.
Link->MP += 16; //Increases HP - This should happen one time, when gaining this level, and be permanent.
Link->MaxMP += 16; //Increases Max HP - This should happen one time, when gaining this level, and be permanent.
//Use Rands for MP/HP increases witht he hpx and mpx variables.
increaseStat(); //This should happen one time, when gaining this level, and be permanent.
Game->Generic[GEN_CANSLASH] = 1; //This should occur when gaining this level, and be permanent.
int LevelNext = 2; //Sets flag to maintain permanency, and to restrict infinite increases.
/// Concerns: Will the screen message stay up forever?
/// Will HP/MP increases infinitely cascade?
/// Will items given, or set to true, remain on gaining next level?
}
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);
}
void increaseStat(int stat, int v){
rollstat();
Game->Counter[stat] =+ v;
}
void roll1d4(int n)
n = Rand(4);
}
void roll1d6(int n)
n = Rand(6);
}
void roll1d8(int n) {
n = Rand(8);
}
void roll1d10(int n) {
n = Rand(10);
}
void roll1d12(int n) {
n = Rand(12);
}
void roll1d20(int n) {
n = Rand(20);
}
void roll1d50(int n) {
n = Rand(50);
}
void roll1d100(int n) {
n = Rand(100);
}
}
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!
@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.
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)?
void Level1(int hpx, int mpx) {
Screen->Message[L1String]; //This should show on-screen one time, when gaining the level, and not remain forever.
Link->MP += 32; //Increases MP - This should happen one time, when gaining this level, and be permanent.
Link->MaxMP += 32; //Increases Max MP - This should happen one time, and be permanent.
Link->MP += 16; //Increases HP - This should happen one time, when gaining this level, and be permanent.
Link->MaxMP += 16; //Increases Max HP - This should happen one time, when gaining this level, and be permanent.
//Use Rands for MP/HP increases witht he hpx and mpx variables.
increaseStat(); //This should happen one time, when gaining this level, and be permanent.
Game->Generic[GEN_CANSLASH] = 1; //This should occur when gaining this level, and be permanent.
int LevelNext = 2; //Sets flag to maintain permanency, and to restrict infinite increases.
/// Concerns: Will the screen message stay up forever?
/// Will HP/MP increases infinitely cascade?
/// Will items given, or set to true, remain on gaining next level?
}
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);
}
void increaseStat(int stat, int v){
rollstat();
Game->Counter[stat] =+ v;
}
void roll1d4(int n)
n = Rand(1, 4);
}
void roll1d6(int n) {
n = Rand(1, 6);
}
void roll1d8(int n) {
n = Rand(1, 8);
}
void roll1d10(int n) {
n = Rand(1, 10);
}
void roll1d12(int n) {
n = Rand(1, 12);
}
void roll1d20(int n) {
n = Rand(1, 20);
}
void roll1d50(int n) {
n = Rand(1, 50);
}
void roll1d100(int n) {
n = Rand(1, 100);
}
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;
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);".
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.
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?
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)
////////////////////////////////
//// XP System for ZC //////////
//// v.17 //////////
////////////////////////////////
//import stdExtra.zh
//immport sdtZoria.zh
const int CR_XP = 12;
const int CR_LVL = 13;
const int CR_STAT_BODY = 31;
const int CR_STAT_MIND = 30;
const int CR_STAT_LUCK = 29;
const int CR_STAT_MYST = 28;
const int CR_STAT_INFL = 27;
const int CR_STAT_MUSC = 26;
const int L1String = 101;
const int L1String = 102;
const int L1String = 103;
const int L1String = 104;
const int L1String = 105;
const int L1String = 106;
const int L1String = 107;
const int L1String = 108;
const int L1String = 109;
const int L1String = 110;
const int L1String = 111;
const int L1String = 112;
const int L1String = 113;
const int L1String = 114;
const int L1String = 115;
const int L1String = 116;
const int L1String = 117;
const int L1String = 118;
const int L1String = 119;
const int L1String = 120;
global script active{
void run(){
int Level = 0;
int LevelNext = 0;
Game->MCounter[CR_LEVEL] = 20;
Game->MCounter[CR_XP] = 250000;
while true{
XP();
Waitframe();
}
}
}
void XP() {
while ( LevelNext = 0 && Screen->NumNPCs() = 0 ) { //Run if there are no enemeies on the screen
if ( Game->Counter[CR_XP] > 0 && Game->Counter[CR_XP] < 100 ){
Game->Counter[CR_LVL] = 0;
}
}
while ( LevelNext = 1 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 100 && Game->Counter[CR_XP] < 150 ){
Game->Counter[CR_LVL] = 1;
//Game->Counter[CR_LVL]++;
Level1();
}
}
while ( LevelNext = 2 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 150 && Game->Counter[CR_XP] < 225 ){
Game->Counter[CR_LVL] = 2;
Level2();
}
}
while ( LevelNext = 3 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 225 && Game->Counter[CR_XP] < 338 ){
Game->Counter[CR_LVL] = 3;
Level3();
}
}
while ( LevelNext = 4 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 338 && Game->Counter[CR_XP] < 507 ){
Game->Counter[CR_LVL] = 4;
Level4();
}
}
while ( LevelNext = 5 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 507 && Game->Counter[CR_XP] < 760 ){
Game->Counter[CR_LVL] = 5;
Level5();
}
}
while ( LevelNext = 6 && Screen->NumNPCs() = 0 ) {
if ( XGame->Counter[CR_XP] >= 760 && Game->Counter[CR_XP] < 1140 ){
Game->Counter[CR_LVL] = 6;
Level6();
}
}
while ( LevelNext = 7 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 1140 && Game->Counter[CR_XP] < 1710 ){
Game->Counter[CR_LVL] = 7;
Level7();
}
}
while ( LevelNext = 8 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 1710 && Game->Counter[CR_XP] < 2565 ){
Game->Counter[CR_LVL] = 8;
Level8();
}
}
while ( LevelNext = 9 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 2565 && Game->Counter[CR_XP] < 3848 ){
Game->Counter[CR_LVL] = 9;
Level9();
}
}
while ( LevelNext = 10 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 3848 && Game->Counter[CR_XP] < 5772 ){
Game->Counter[CR_LVL] = 10;
Level10();
}
}
while ( LevelNext = 11 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 5772 && Game->Counter[CR_XP] < 8658 ){
Game->Counter[CR_LVL] = 11;
Level11();
}
}
while ( LevelNext = 12 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 8658 && Game->Counter[CR_XP] < 12987 ){
Game->Counter[CR_LVL] = 12;
Level12();
}
}
while ( LevelNext = 13 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 12987 && Game->Counter[CR_XP] < 19481 ){
Game->Counter[CR_LVL] = 13;
Level13();
}
}
while ( LevelNext = 14 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 19481 && Game->Counter[CR_XP] < 29222 ){
Game->Counter[CR_LVL] = 14;
Level14();
}
}
while ( LevelNext = 15 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 29222 && Game->Counter[CR_XP] < 43833 ){
Game->Counter[CR_LVL] = 15;
Level15();
}
}
while ( LevelNext = 16 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 43833 && Game->Counter[CR_XP] < 65750 ){
Game->Counter[CR_LVL] = 16;
Level16();
}
}
while ( LevelNext = 17 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 65750 && Game->Counter[CR_XP] < 98625 ){
Game->Counter[CR_LVL] = 17;
Level17();
}
}
while ( LevelNext = 18 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 98625 && Game->Counter[CR_XP] < 147938 ){
Game->Counter[CR_LVL] = 18;
Level18();
}
}
while ( LevelNext = 19 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 147938 && Game->Counter[CR_XP] < 221907 ){
Game->Counter[CR_LVL] = 19;
Level19();
}
}
while ( LevelNext = 20 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 221907 ){
Game->Counter[CR_LVL] = 20;
Level20();
}
}
}
////////////////////////
/// XP TABLE ///////////
////////////////////////
/// 0 = 0 ////////
/// 100 = 1 ////////
/// 150 = 2 ////////
/// 225 = 3 ////////
/// 338 = 4 ////////
/// 507 = 5 ////////
/// 760 = 6 ////////
/// 1140 = 7 ////////
/// 1710 = 8 ////////
/// 2565 = 9 ////////
/// 3848 = 10 ////////
/// 5772 = 11 ////////
/// 8658 = 12 ////////
/// 12987 = 13 ////////
/// 19481 = 14 ////////
/// 29222 = 15 ////////
/// 43833 = 16 ////////
/// 65750 = 17 ////////
/// 98625 = 18 ////////
/// 147938 = 19 ////////
/// 221907 = 20 ////////
//////////////////////////////////////////
//// XP Algorithm ////
//// C = Current Base ////
//// H = Half Current Base ////
//// N = Amount Needed for Next Level ////
//// C + H = N ////
//// Thus C (100) + H (50) = N (150) ////
//////////////////////////////////////////
void Level1(int hpx, int mpx) {
Screen->Message[L1String]; //This should show on-screen one time, when gaining the level, and not remain forever.
Link->MP += 32; //Increases MP - This should happen one time, when gaining this level, and be permanent.
Link->MaxMP += 32; //Increases Max MP - This should happen one time, and be permanent.
Link->MP += 16; //Increases HP - This should happen one time, when gaining this level, and be permanent.
Link->MaxMP += 16; //Increases Max HP - This should happen one time, when gaining this level, and be permanent.
//Use Rands for MP/HP increases witht he hpx and mpx variables.
increaseStat(v); //This should happen one time, when gaining this level, and be permanent.
Game->Generic[GEN_CANSLASH] = 1; //This should occur when gaining this level, and be permanent.
int LevelNext = 2; //Sets flag to maintain permanency, and to restrict infinite increases.
/// Concerns: Will the screen message stay up forever?
/// Will HP/MP increases infinitely cascade?
/// Will items given, or set to true, remain on gaining next level?
}
void roll1d6(int n) {
n = Rand(1, 6);
}
void rollStat(int r, int stat, int n) {
r = Rand(1, 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);
}
void increaseStat(int stat, int v){
rollstat(r, stat, n);
Game->Counter[stat] =+ v;
}
void roll1d4(int n)
n = Rand(1, 4);
}
void roll4d6(int a, int b, int c, int d, int t){
a = Rand(1, 6);
b = Rand(1, 6);
c = Rand(1, 6);
d = Rand(1, 6);
t = ( a + b + c + d )
}
void roll1d8(int n) {
n = Rand(1, 8);
}
void roll1d10(int n) {
n = Rand(1, 10);
}
void roll1d12(int n) {
n = Rand(1, 12);
}
void roll1d20(int n) {
n = Rand(1, 20);
}
void roll1d50(int n) {
n = Rand(1, 50);
}
void roll1d100(int n) {
n = Rand(1, 100);
}
}
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.
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)
////////////////////////////////
//// XP System for ZC //////////
//// v.22 //////////
///////////////////////////////////////////////////////////////////////////
/// Creator: ZoriaRPG /////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
/// ASSISTANCE BY: ////// CONTRIBUTORS: ////// TESTING: //////
/// anikom15 ////// MoscowModder ////// //////
/// Avataro ////// ////// //////
/// MoscowModder ////// ////// //////
///////////////////////////////////////////////////////////////////////////
//import std.zh
//import stdExtra.zh //Not a dependency at this time.
//immport sdtZoria.zh //Not a dependency at this time.
const int CR_XP = 12;
const int CR_LVL = 13;
const int CR_STAT_BODY = 31;
const int CR_STAT_MIND = 30;
const int CR_STAT_LUCK = 29;
const int CR_STAT_MYST = 28;
const int CR_STAT_INFL = 27;
const int CR_STAT_MUSC = 26;
const int L1String = 101;
const int L1String = 102;
const int L1String = 103;
const int L1String = 104;
const int L1String = 105;
const int L1String = 106;
const int L1String = 107;
const int L1String = 108;
const int L1String = 109;
const int L1String = 110;
const int L1String = 111;
const int L1String = 112;
const int L1String = 113;
const int L1String = 114;
const int L1String = 115;
const int L1String = 116;
const int L1String = 117;
const int L1String = 118;
const int L1String = 119;
const int L1String = 120;
global script active{
void run(){
int Level = 0;
int LevelNext = 0;
Game->MCounter[CR_LEVEL] = 20;
Game->MCounter[CR_XP] = 250000;
while true{
XP();
Waitframe();
}
}
}
void XP() {
while ( LevelNext = 0 && Screen->NumNPCs() = 0 ) { //Run if there are no enemeies on the screen
if ( Game->Counter[CR_XP] > 0 && Game->Counter[CR_XP] < 100 ){
Game->Counter[CR_LVL] = 0;
}
}
while ( LevelNext = 1 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 100 && Game->Counter[CR_XP] < 150 ){
Game->Counter[CR_LVL] = 1;
//Game->Counter[CR_LVL]++;
Level1();
}
}
while ( LevelNext = 2 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 150 && Game->Counter[CR_XP] < 225 ){
Game->Counter[CR_LVL] = 2;
Level2();
}
}
while ( LevelNext = 3 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 225 && Game->Counter[CR_XP] < 338 ){
Game->Counter[CR_LVL] = 3;
Level3();
}
}
while ( LevelNext = 4 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 338 && Game->Counter[CR_XP] < 507 ){
Game->Counter[CR_LVL] = 4;
Level4();
}
}
while ( LevelNext = 5 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 507 && Game->Counter[CR_XP] < 760 ){
Game->Counter[CR_LVL] = 5;
Level5();
}
}
while ( LevelNext = 6 && Screen->NumNPCs() = 0 ) {
if ( XGame->Counter[CR_XP] >= 760 && Game->Counter[CR_XP] < 1140 ){
Game->Counter[CR_LVL] = 6;
Level6();
}
}
while ( LevelNext = 7 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 1140 && Game->Counter[CR_XP] < 1710 ){
Game->Counter[CR_LVL] = 7;
Level7();
}
}
while ( LevelNext = 8 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 1710 && Game->Counter[CR_XP] < 2565 ){
Game->Counter[CR_LVL] = 8;
Level8();
}
}
while ( LevelNext = 9 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 2565 && Game->Counter[CR_XP] < 3848 ){
Game->Counter[CR_LVL] = 9;
Level9();
}
}
while ( LevelNext = 10 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 3848 && Game->Counter[CR_XP] < 5772 ){
Game->Counter[CR_LVL] = 10;
Level10();
}
}
while ( LevelNext = 11 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 5772 && Game->Counter[CR_XP] < 8658 ){
Game->Counter[CR_LVL] = 11;
Level11();
}
}
while ( LevelNext = 12 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 8658 && Game->Counter[CR_XP] < 12987 ){
Game->Counter[CR_LVL] = 12;
Level12();
}
}
while ( LevelNext = 13 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 12987 && Game->Counter[CR_XP] < 19481 ){
Game->Counter[CR_LVL] = 13;
Level13();
}
}
while ( LevelNext = 14 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 19481 && Game->Counter[CR_XP] < 29222 ){
Game->Counter[CR_LVL] = 14;
Level14();
}
}
while ( LevelNext = 15 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 29222 && Game->Counter[CR_XP] < 43833 ){
Game->Counter[CR_LVL] = 15;
Level15();
}
}
while ( LevelNext = 16 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 43833 && Game->Counter[CR_XP] < 65750 ){
Game->Counter[CR_LVL] = 16;
Level16();
}
}
while ( LevelNext = 17 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 65750 && Game->Counter[CR_XP] < 98625 ){
Game->Counter[CR_LVL] = 17;
Level17();
}
}
while ( LevelNext = 18 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 98625 && Game->Counter[CR_XP] < 147938 ){
Game->Counter[CR_LVL] = 18;
Level18();
}
}
while ( LevelNext = 19 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 147938 && Game->Counter[CR_XP] < 221907 ){
Game->Counter[CR_LVL] = 19;
Level19();
}
}
while ( LevelNext = 20 && Screen->NumNPCs() = 0 ) {
if ( Game->Counter[CR_XP] >= 221907 ){
Game->Counter[CR_LVL] = 20;
Level20();
}
}
}
////////////////////////
/// XP TABLE ///////////
////////////////////////
/// 0 = 0 ////////
/// 100 = 1 ////////
/// 150 = 2 ////////
/// 225 = 3 ////////
/// 338 = 4 ////////
/// 507 = 5 ////////
/// 760 = 6 ////////
/// 1140 = 7 ////////
/// 1710 = 8 ////////
/// 2565 = 9 ////////
/// 3848 = 10 ////////
/// 5772 = 11 ////////
/// 8658 = 12 ////////
/// 12987 = 13 ////////
/// 19481 = 14 ////////
/// 29222 = 15 ////////
/// 43833 = 16 ////////
/// 65750 = 17 ////////
/// 98625 = 18 ////////
/// 147938 = 19 ////////
/// 221907 = 20 ////////
//////////////////////////////////////////
//// XP Algorithm ////
//// C = Current Base ////
//// H = Half Current Base ////
//// N = Amount Needed for Next Level ////
//// C + H = N ////
//// Thus C (100) + H (50) = N (150) ////
//////////////////////////////////////////
void Level1(int hpx, int mpx) {
Screen->Message[L1String]; //This should show on-screen one time, when gaining the level, and not remain forever.
Link->MP += 32; //Increases MP - This should happen one time, when gaining this level, and be permanent.
Link->MaxMP += 32; //Increases Max MP - This should happen one time, and be permanent.
Link->MP += 16; //Increases HP - This should happen one time, when gaining this level, and be permanent.
Link->MaxMP += 16; //Increases Max HP - This should happen one time, when gaining this level, and be permanent.
//Use Rands for MP/HP increases witht he hpx and mpx variables.
increaseStat(); //This should happen one time, when gaining this level, and be permanent.
Game->Generic[GEN_CANSLASH] = 1; //This should occur when gaining this level, and be permanent.
int LevelNext = 2; //Sets flag to maintain permanency, and to restrict infinite increases.
/// Concerns: Will the screen message stay up forever?
/// Will HP/MP increases infinitely cascade?
/// Will items given, or set to true, remain on gaining next level?
}
///int rollStat() {
/// int r = Rand(1, 6); //specific value of 1-6 set at random;
/// if ( r == 1 ) {
/// int stat = Game->Counter[CR_STAT_BODY];
/// }
/// if ( r == 2 ) {
/// int stat = Game->Counter[CR_STAT_MIND];
/// }
/// if ( r == 3 ) {
/// int stat = Game->Counter[CR_STAT_LUCK];
/// }
/// if ( r == 4 ) {
/// int stat = Game->Counter[CR_STAT_MYST];
/// }
/// if ( r == 5 ) {
/// int stat = Game->Counter[CR_STAT_INFL;
/// }
/// if ( r == 6 ) {
/// int stat = Game->Counter[CR_STAT_MUSC];
/// }
/// return stat;
///}
int rollStat() {
int r = Rand(1, 6); //specific value of 1-6 set at random;
if ( r == 1 ) {
int stat = CR_STAT_BODY;
}
if ( r == 2 ) {
int stat = CR_STAT_MIND;
}
if ( r == 3 ) {
int stat = CR_STAT_LUCK;
}
if ( r == 4 ) {
int stat = CR_STAT_MYST;
}
if ( r == 5 ) {
int stat = CR_STAT_INFL;
}
if ( r == 6 ) {
int stat = CR_STAT_MUSC;
}
return stat;
}
void increaseStat() {
int stat = rollStat();
int n = rollDie(6);
Game->Counter[stat] =+ n;
}
int rollDie(int type){
int n = Rand(1, type);
return n;
}
int roll1d4()
int n = Rand(1, 4);
return n;
}
int roll1d6()
int n = Rand(1, 6);
return n;
}
int roll4d6(){
int a = Rand(1, 6);
int b = Rand(1, 6);
int c = Rand(1, 6);
int d = Rand(1, 6);
int t = ( a + b + c + d )
return t;
}
int roll1d8()
int n = Rand(1, 8);
return n;
}
int roll1d10()
int n = Rand(1, 10);
return n;
}
int roll1d12()
int n = Rand(1, 12);
return n;
}
int roll1d20()
int n = Rand(1, 20);
return n;
}
int roll1d50()
int n = Rand(1, 50);
return n;
}
int roll1d100()
int n = Rand(1, 100);
return n;
}
}
void getBodyStat(){
}
void getMindStat(){
}
void getLuckStat(){
}
void getMystStat(){
}
void getInflStat(){
}
void getMuscStat(){
}
int getBodyStat(){
int stat = CR_STAT_BODY;
return stat;
}
int getMindStat(){
int stat = CR_STAT_MIND;
return stat;
}
int getLuckStat(){
int stat = CR_STAT_LUCK;
return stat;
}
int getMystStat(){
int stat = CR_STAT_MYST;
return stat;
}
int getInflStat(){
int stat = CR_STAT_INFL;
return stat;
}
int getMuscStat(){
int stat = CR_STAT_MUSC;
return stat;
}
// Using Stats
// heavy weapon script particles
// discover present slot of item
// set int of slot of item for bools
// when trying to use the item
// if CT_MUSC < x
// set other slot to 'hand' until item is changed.
//
// Use Body to affect HP:
// Use Body to set HP at level increases. Use to set HP regen rate.
// Use MUSC to set-augment weapon damage, via roll1dX rands.
// Use MUSC for ability to move objects.
// bracelets increase Musc, as well as activating triggers.
// Bracelet / gauntlet takes up a slot. Any combination of two rings, or one ring and one bracelet at one time.
// Use Luck to set jinx durations.
// Use Myst to set spell damage.
// Require Myst of certain value to use some spells.
// Ue Mind for Lore skills.
// Use Mind for raw (untrained) examination checks.
// Create LWeapon that deals damage based on dX rolls.
// Is there any way to use MUSC and random damage on swords?
// Possibly replace rhe power of the LW_SWORD generated with a sword with a different value?
// INF should set the strings used on FFC scripts when conversing.
// A higher INF would open up more lines of dialogue.