PDA

View Full Version : A bug with Arrays? [RC5]



Majora
11-07-2012, 07:35 PM
So my buddy SUCCESSOR metaphorically pours his sweat and blood into writing a script for me (which will eventually be released to the public as it is a general-use type script instead of something overly specific) and after much trial and error and goat sacrifices, it finally works! It works at last, it works at least. Thank god almighty, it works at last! Small problem though. I did not change a single thing (that I remember?) and the next day the script breaks for no reason. So!

Here's the script:


const int IT_BOTTLE1 = 90;//empty bottle item of Bottle Class 1 const int IT_ING_RED1 = 220;//ingredient item for red potion
const int IT_ING_GRN1 = 221;//ingredient item for green potion
const int IT_ING_BLU1 = 222;//ingredient item for blue potion
const int IT_POT_RED1 = 231;//red potion item
const int IT_POT_GRN1 = 230;//green potion item
const int IT_POT_BLU1 = 229;//blue potion item
const int IT_BOT_FAIR1 = -1;//Fairy in a bottle
const int IT_BOTTLE2 = 12;//repeat for bottle class 2
const int IT_ING_RED2 = 241;
const int IT_ING_GRN2 = 252;
const int IT_ING_BLU2 = 240;
const int IT_POT_RED2 = 237;
const int IT_POT_GRN2 = 236;
const int IT_POT_BLU2 = 225;
const int IT_BOT_FAIR2 = -1;
const int IT_BOTTLE3 = 228;//bottle class 2
const int IT_ING_RED3 = -1;
const int IT_ING_GRN3 = -1;
const int IT_ING_BLU3 = -1;
const int IT_POT_RED3 = -1;
const int IT_POT_GRN3 = -1;
const int IT_POT_BLU3 = -1;
const int IT_BOT_FAIR3 = -1;
const int IT_BOTTLE4 = 227;//bottle class 4
const int IT_ING_RED4 = -1;
const int IT_ING_GRN4 = -1;
const int IT_ING_BLU4 = -1;
const int IT_POT_RED4 = -1;
const int IT_POT_GRN4 = -1;
const int IT_POT_BLU4 = -1;
const int IT_BOT_FAIR4 = -1;

//Bottle item constants set to negatives are ignored
//leave constant at -1 if you are not using that item
//item numbers do not need to be sequential

int bottles[32] = {
IT_BOTTLE1, IT_ING_RED1, IT_ING_GRN1, IT_ING_BLU1,
IT_POT_RED1, IT_POT_GRN1, IT_POT_BLU1, IT_BOT_FAIR1,
IT_BOTTLE2, IT_ING_RED2, IT_ING_GRN2, IT_ING_BLU2,
IT_POT_RED2, IT_POT_GRN2, IT_POT_BLU2, IT_BOT_FAIR2,
IT_BOTTLE3, IT_ING_RED3, IT_ING_GRN3, IT_ING_BLU3,
IT_POT_RED3, IT_POT_GRN3, IT_POT_BLU3, IT_BOT_FAIR3,
IT_BOTTLE4, IT_ING_RED4, IT_ING_GRN4, IT_ING_BLU4,
IT_POT_RED4, IT_POT_GRN4, IT_POT_BLU4, IT_BOT_FAIR4 };


//constants for bottles[] array do not change
const int BOTT_1 = 0;
const int BOTT_2 = 8;
const int BOTT_3 = 16;
const int BOTT_4 = 24;
const int POTI_RED = 4;
const int POTI_GRN = 5;
const int POTI_BLU = 6;




int EmptyBottle() //checks inventory for an empty bottle.
{
for(int i = 31; i > -1; i--){
//skip if value is not a valid item number
if(!ValidItemNum(bottles[i])) continue;
if(Link->Item[bottles[i]]) { //if item checked is in posession
if(i>BOTT_4){ i = BOTT_4; continue;} //isn't empty bottle go to next bottle
else if(i == BOTT_4) return i; //is empty bottle return value
else if(i>BOTT_3){ i = BOTT_3; continue; }
else if(i == BOTT_3) return i;
else if(i>BOTT_2){ i = BOTT_2; continue; }
else if(i == BOTT_2) return i;
else if(i>BOTT_1) break;
else if(i == BOTT_1) return i;
}
}
return -1;
}
int HasIngred(int potion) //check to see if Link has the right potion ingredient
{
int ingred = potion - 3;
if(Link->Item[bottles[ingred + BOTT_4]] && ValidItemNum(bottles[ingred + BOTT_4])){
return BOTT_4; }
if(Link->Item[bottles[ingred + BOTT_3]] && ValidItemNum(bottles[ingred + BOTT_3])){
return BOTT_3; }
if(Link->Item[bottles[ingred + BOTT_2]] && ValidItemNum(bottles[ingred + BOTT_2])){
return BOTT_2; }
if(Link->Item[bottles[ingred]] && ValidItemNum(bottles[ingred])){
return BOTT_1; }
else { return -1;} //return no ingred
}


//potion use POTI_ constants for potion, disc is cheaper price with ingredient
void BuyPotion(int potion, int price, int disc, int stringNoBott, int stringNotEnough)
{
bool discount;
int bottle = HasIngred(potion);

//if HasIngred returns -1 check for empty bottle
if(bottle<0)bottle = EmptyBottle();
else discount = true;

//if EmptyBottle() returns -1 show No Empty Bottle string
if(bottle<0){ //No empty bottle
Screen->Message(stringNoBott); NoAction(); return; }

if(discount) {
//Check to see if Player has enough rupees
if(Game->Counter[CR_RUPEES] < disc){
Screen->Message(stringNotEnough);
NoAction(); return;
}
else {

//take away the ingredient
Link->Item[bottles[bottle + potion - 3]] = false;
//Give link the potion
GiveLinkItem(bottles[bottle + potion]);
Deduct(CR_RUPEES, disc);
}
}
else{
//Check to see if Player has enough rupees
if(Game->Counter[CR_RUPEES] < price){
Screen->Message(stringNotEnough);
NoAction(); return;
}
else {
//give link the potion
GiveLinkItem(bottles[bottle + potion]);
Deduct(CR_RUPEES, price);
}
}
}


//delete if you use a shop script with this function
bool ShopCanBuy(ffc buy)
{
return (Abs(Link->X-buy->X) < 8 && Abs(Link->Y-(buy->Y+8)) < 8 && Link->Dir == DIR_UP);
}
//end of ShopCanBuy


void GiveLinkItem(int itm)//Gives Link an item and makes him hold it up
{
item make = Screen->CreateItem(itm);
make->HitWidth = 16; make->HitHeight = 16;
make->X = Link->X; make->Y = Link->Y;
Game->PlaySound(SFX_PICKUP);
Link->Action = LA_HOLD2LAND;
Link->HeldItem = itm;
while(Link->HeldItem == itm && Link->Action == LA_HOLD2LAND)
WaitNoAction();
}
void Deduct(int counter, int amount) //deduct amount from counter
{
int comb0 = Screen->ComboT[0];
Screen->ComboT[0] = CT_SCREENFREEZE;
for(int i=0;i<amount;i++)
{
Game->PlaySound(SFX_MSG);
Game->Counter[counter]--;
WaitNoAction();
}
Screen->ComboT[0] = comb0;
}


//IF you use another script with these functions
//either delete these or the one in the other script
//these ones allows Ex buttons
//input great than 3 0r -4 allows any button
bool SelectPressInput(int input)
{
if(input == 0) return Link->PressA;
else if(input == 1) return Link->PressB;
else if(input == 2) return Link->PressL;
else if(input == 3) return Link->PressR;
else if(input == -1) return Link->PressEx1;
else if(input == -2) return Link->PressEx2;
else if(input == -3) return Link->PressEx3;
else if(input == -4) return Link->PressEx4;
else return (Link->PressA || Link->PressB || Link->PressL || Link->PressR ||
Link->PressEx1 || Link->PressEx3 || Link->PressEx3 || Link->PressEx4);
}
void SetInput(int input, bool state){
if(input == 0) Link->InputA = state;
else if(input == 1) Link->InputB = state;
else if(input == 2) Link->InputL = state;
else if(input == 3) Link->InputR = state;
else if(input == -1) Link->PressEx1 = state;
else if(input == -2) Link->PressEx2 = state;
else if(input == -3) Link->PressEx3 = state;
else if(input == -4) Link->PressEx4 = state;
else if(!state) NoAction();
}


//^^^


bool ValidItemNum(int num)
{
return num > -1 && num < 256;
}
//D0: The potion this cauldron sells see POTI_ constants (4 is RED, 5 is GREEN, 6 is BLUE)
//D1: The full price
//D2: The discounted price when player has ingredient for potion
//D3: button to press to buy
// 0 is A, 1 is B, 2 is L, 3 is R, -1 is Ex1, -2 is Ex2, -3 is Ex3, -4 is Ex4
// any other value allows any of the above
//D4: String that shows when Link approaches for info, price, price with ingred...
//D5: String that shows if Link has no empty bottles
//D6: String that shows if Link doesn't have enough rupees
ffc script Cauldron
{
void run(int potion, int price, int disc, int input, int stringInfo, int stringNoBott, int stringNotEnough)
{
//whether or not info string is on screen
bool info;
// Run continuously
while(true)
{
// If Link is below the FFC facing up
if(ShopCanBuy(this))
{
// If he hits the provided input button
if(SelectPressInput(input))
{

BuyPotion(potion, price, disc, stringNoBott, stringNotEnough);
Waitframes(20);
info = false;
}
// Else Link is under the FFC but has not hit the correct button
else
{
// Do stuff here if you want something to happen when Link is under the item but hasn't hit the input button
if(!info){ Screen->Message(stringInfo); info = true; }
}
} //! End of if(ShopCanBuy(this))
else if(info)info = false;

Waitframe();
} //! End of while(true)
} //! End of void run(int itm, int price, int input)
}//! End of ffc script Shop

What this script is for is basically a bottles system like in the 3D zeldas. In this version, you must have a total of XY items where x is the number of bottles in the quest and y is the number of possible items that a bottle is required for. Then whenever you "talk" to an FFC with this script on it, it's a shop script basically. it checks link's inventory for bottle items (of unique item classes, in my case zz251-254) and either gives him the appropriate potion item, or tells him to stop being a punk-ass cheapskate, or tells him that he needs a bottle of potion-holding.

THE POINT IS. The script broke for no reason that I could think of. I tried recompiling it and nothing. The FFC would refuse to sell link any potions despite having something to carry them in and having the necessary amount of money. Then I look in allegro.log and I got this error:


Invalid index (25) to local array of size 4
Invalid index (25) to local array of size 4
Invalid index (17) to local array of size 4
Invalid index (17) to local array of size 4
Invalid index (9) to local array of size 4
Invalid index (9) to local array of size 4
Invalid index (31) to local array of size 4
Invalid index (30) to local array of size 4
Invalid index (29) to local array of size 4
Invalid index (28) to local array of size 4
Invalid index (27) to local array of size 4
Invalid index (26) to local array of size 4
Invalid index (25) to local array of size 4
Invalid index (24) to local array of size 4
Invalid index (23) to local array of size 4
Invalid index (22) to local array of size 4
Invalid index (21) to local array of size 4
Invalid index (20) to local array of size 4
Invalid index (19) to local array of size 4
Invalid index (18) to local array of size 4
Invalid index (17) to local array of size 4
Invalid index (16) to local array of size 4
Invalid index (15) to local array of size 4
Invalid index (14) to local array of size 4
Invalid index (13) to local array of size 4
Invalid index (12) to local array of size 4
Invalid index (11) to local array of size 4
Invalid index (10) to local array of size 4
Invalid index (9) to local array of size 4
Invalid index (8) to local array of size 4
Invalid index (7) to local array of size 4
Invalid index (6) to local array of size 4
Invalid index (5) to local array of size 4
Invalid index (4) to local array of size 4

I am working on reproducing this bug, and if I am able to I will post a test quest. But my hunches are that:

The script works as intended once more if you start a new file and begin the quest again. Once it stopped working, I restarted my quest and everything functioned as it should. The script, upon producing the above error, behaves as if Link no longer had any items to carry potions in) Some kind of information is being stored in the quest file in some way, and then some limit somewhere is being reached. In the vein of "you can only buy x number of potions in the entire quest". The script otherwise works beautifully. But I'm not a developer and much less a programmer in general so fuck if I know how the actual mechanics are. but hey, maybe it'll give the devs an idea of where to look maybe? Bleh.

Like I said, a test quest if I am able to reproduce it.

Saffith
11-07-2012, 08:13 PM
To make sure I'm understanding correctly, it works when you start the quest, but if you save and quit and reopen the quest without editing it, it breaks?

Majora
11-07-2012, 09:35 PM
More or less! sorry for being confusing. but it's not dependent on simply starting and restarting the quest. For example, I could buy a few potions in one session, save and quit. then play again and buy another few, and eventually it just broke.

SUCCESSOR
11-07-2012, 09:37 PM
To make sure I'm understanding correctly, it works when you start the quest, but if you save and quit and reopen the quest without editing it, it breaks?

I can't seem to recreate the problem. I have tried continuing and saving but it still works when I test it.

Edit: Tried in both RC4 and RC5.

Gleeok
11-07-2012, 09:59 PM
What line of what script is causing the error? Can we isolate the problem further?

SUCCESSOR
11-07-2012, 10:08 PM
What line of what script is causing the error? Can we isolate the problem further?

I was assuming it was bottles[] which is a global array of 32.

Majora
11-07-2012, 10:44 PM
After buying 3000 rupees worth of potions and saving and continuing a few times in between, I can't reproduce it. Maybe it was just a fluke with ZC or something. But should it pop back up I'll report back.

Saffith
11-09-2012, 02:02 AM
Well, let me ask specifically, because it's the only thing I can think of so far. Are you aware that after modifying and recompiling scripts, even if the changes seem innocuous, existing saves become unreliable? This is exactly the sort of problem it can cause, so that's what we need to rule out.

Majora
11-09-2012, 03:05 AM
Oh, well then I probably did make minor edits (and thus thought nothing of them), and probably recompiled the buffer for the sake of updating other scripts. So! with that, I apologize for the wild goose chase. :doh:

Gleeok
11-09-2012, 04:49 AM
Yep. Never save a quest to a save file for development testing while you are modifying scripts for that quest file. Ever. (Unless you know what you are doing.) Use the Init Data settings and cheat options instead. ;)

Here's a script that will automatically enable cheats every time you load that quest:


global script GlobalMain
{
void run()
{
Game->Cheat = 4;
}
}