Entrepreneur Central

Make games! Discuss those games here.

Moderators: Bob the Hamster, marionline, SDHawk

User avatar
Bob the Hamster
Lord of the Slimes
Posts: 7658
Joined: Tue Oct 16, 2007 2:34 pm
Location: Hamster Republic (Ontario Enclave)
Contact:

Post by Bob the Hamster »

I bet arrays (and structs?) Will vastly reduce the need for a lot of locals in the same script.
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

Nah, there's no need to have 100 locals even today.

OK, if you're willing to rewrite scripts when arrays are implemented then I can give you directions.

But having another look at your scripts, I can tell you that you can already easily trim 200 thousand lines right now without arrays. There is an unbelievable amount of repetition. There's a principle in programming, and not understanding it is your worst mistake (I'm sure I've explained this to you before!): Don't Repeat Yourself (DRY). If you have the same or very similar code repeated in different places then you should move that into a script and call the script. If there's a substantial block of code repeated twice, you should definitely de-duplicate it. If the duplicated code is only 3 lines long you probably wouldn't bother with deduplicating it unless it occurs at least 5-6 times. What if you want to change the way that a duplicated script works? You would have to change every instance by hand, being careful to make exactly the same change each time! If you've duplicated it in 200 places, as you frequently do, then it becomes insurmountable to change anything.

Now unfortunately moving code to another script isn't always possible, because scripts can't modify local variables. But they can modify globals by using read/writeglobal, which is not that ugly, and subscripts can modify locals if you always change the same one. That subscript link has a good example of DRY, but lets see an example from your own scripts of something harder.

Another tip (which you probably already realised): when rewriting/cleaning up your code, do it in small steps. Small steps means the "cleaned up" scripts still have lots of obvious redundancy. As you make your scripts more compact you'll get more ideas for improving them, but don't start on that until you've finished one thing. Too many changes at once gets confusing and extremely bugprone!

Let's look at a couple Buy scripts.

Code: Select all

script,Buy Vanilla Ice Cream,begin
suspend player
if (wholesaleitem10>=100) then(
show text box (2557)
wait for text box
)
if &#40;wholesaleitem10<<100&#41; then&#40;
if &#40;wholesaleitem10>>90&#41; then&#40;
set variable &#40;itemleft,100--wholesaleitem10&#41;
show text box &#40;2558&#41;
wait for text box
&#41;
if &#40;&#40;checktag &#40;60&#41;&#41;==false&#41; then&#40;
set variable &#40;trytobuy21,1&#41;
Extra Supplies and Garnishes
&#41;
if &#40;checktag &#40;60&#41;&#41; then&#40;
show text box &#40;122&#41;
wait for text box
&#41;
&#41;
resume player
end

script,Buy Crushed Ice,begin
suspend player
if &#40;groceritem7>=100&#41; then&#40;
show text box &#40;2557&#41;
wait for text box
&#41;
if &#40;groceritem7<<100&#41; then&#40;
if &#40;groceritem7>>90&#41; then&#40;
set variable &#40;itemleft,100--groceritem7&#41;
show text box &#40;2558&#41;
wait for text box
&#41;
if &#40;&#40;checktag &#40;60&#41;&#41;==false&#41; then&#40;
set variable &#40;trytobuy22,1&#41;
Extra Supplies and Garnishes
&#41;
if &#40;checktag &#40;60&#41;&#41; then&#40;
show text box &#40;122&#41;
wait for text box
&#41;
&#41;
resume player
end
The redundancy is obvious. The solution is less: use read/writeglobal here. Create a copy of the script and replace every part of it that differs with a script argument. To write to a global variable, use writeglobal. "@a global variable name" becomes that global's ID number; pass that as an argument.

(Note, I couldn't figure out what these variables actually mean as it was too confusing, so I might have the variable names wrong.)

Code: Select all

# 'trytobuy global' is the ID of a global
# Return true to run the script
script,Standard Buy Extra Supplies, amountincart, trytobuy global, begin
suspend player
if &#40;amountincart>=100&#41; then&#40;
show text box &#40;2557&#41;
wait for text box
&#41;
if &#40;amountincart<<100&#41; then&#40;
if &#40;amountincart>>90&#41; then&#40;
set variable &#40;itemleft,100--amountincart&#41;
show text box &#40;2558&#41;
wait for text box
&#41;
if &#40;&#40;checktag &#40;60&#41;&#41;==false&#41; then&#40;
write global &#40;trytobuy global, 1&#41;
return&#40;true&#41;
&#41;
if &#40;checktag &#40;60&#41;&#41; then&#40;
show text box &#40;122&#41;
wait for text box
&#41;
&#41;
resume player
end


script,Buy Vanilla Ice Cream,begin
  Standard Buy Extra Supplies&#40;wholesaleitem10, @trytobuy21&#41;
end

script,Buy Crushed Ice, begin
  Standard Buy Extra Supplies&#40;groceritem7, @trytobuy22&#41;
end
Now as you wrote, the Buy script calls either Extra Supplies and Garnishes or Extra Equipment, or Health Supplies. Some of the Buy scripts also have extra logic. So you might need many different versions of the above script for each variant used at least twice. For example, all the scripts for buying cans of paint are the same. Most of these variants are very similar to each other, so once again you can split that part out.

Hmmm, the equipment scripts use different thresholds instead of 90 and 100 and different structure. Suppose you want to combine the variants for "health supplies" and "Extra Supplies and Garnishes" (which is something you may not want to bother with, but this is just can example). There are many ways to do so. You could have the general script return true instead of calling the inner script, and you will also need to move "suspend player" and "resume player":

Code: Select all

# 'trytobuy global' is the ID of a global
# Returns true if should call "Extra Supplies and Garnishes", or whatever
script,Standard Buy Item, amountincart, trytobuy global, begin
if &#40;amountincart>=100&#41; then&#40;
show text box &#40;2557&#41;
wait for text box
&#41;
if &#40;amountincart<<100&#41; then&#40;
if &#40;amountincart>>90&#41; then&#40;
set variable &#40;itemleft,100--amountincart&#41;
show text box &#40;2558&#41;
wait for text box
&#41;
if &#40;&#40;checktag &#40;60&#41;&#41;==false&#41; then&#40;
write global &#40;trytobuy global, 1&#41;
return&#40;true&#41;   ### Changed
&#41;
if &#40;checktag &#40;60&#41;&#41; then&#40;
show text box &#40;122&#41;
wait for text box
&#41;
&#41;
end

script,Standard Buy Supplies, amountincart, trytobuy global, begin
 suspend player
 if &#40;Standard Buy Item&#40;amountincart, trytobuy global&#41;&#41; then &#40;
   Extra Supplies and Garnishes
 &#41;
 resume player
end

script,Standard Buy Health Supplies, amountincart, trytobuy global, begin
 suspend player
 if &#40;Standard Buy Item&#40;amountincart, trytobuy global&#41;&#41; then &#40;
   Health Supplies
 &#41;
 resume player
end

script,Buy Vanilla Ice Cream,begin
  Standard Buy Extra Supplies&#40;wholesaleitem10, @trytobuy21&#41;
end

script,Buy Crushed Ice, begin
  Standard Buy Extra Supplies&#40;groceritem7, @trytobuy22&#41;
end

script,Buy Apple Syrup,begin
  Standard Buy Health Supplies&#40;healthitem4, @trytobuy56&#41;
end
However, looking closer, "Extra Supplies and Garnishes" itself is a mess (as are the others), 4000 lines of duplication, but should be only ~12 lines long. Add arguments for the textbox number, etc. Those arguments should be passed through ultimately from "Buy Crushed Ice" etc. You want to have the data (textbox numbers, price, etc) for each item concentrated in just a couple places rather than spread all over the place. That also lets you get rid of the trytobuy variables completely, which are each only used in those two places! I hope you see those variables are useless.
Last edited by TMC on Wed Aug 10, 2016 12:29 pm, edited 3 times in total.
User avatar
Pepsi Ranger
Liquid Metal Slime
Posts: 1457
Joined: Thu Nov 22, 2007 6:25 am
Location: South Florida

Post by Pepsi Ranger »

I actually have three scripts that bust the 99 local limit by a lot in this game, and one script that busts it in Powerstick Man XE, but I know how to work around them, so if extending them is going to mess up the new interpreter, I wouldn't bother with it. Plus, I didn't know subscripts worked that way (I'd actually forgotten they existed), so I'm sure I can find reasonable ways around them. This instructional, while a little confusing at the moment (because I know why I wrote my scripts the way I did), is helpful, and I'm pretty sure I can make great use of them. So thanks for that.

A couple of things:

Code: Select all

script,Standard Buy Supplies, amountincart, trytobuy global, begin
 suspend player
 if &#40;Standard Buy Item&#40;amountincart, trytobuy global&#41;&#41; then &#40;
   Extra Supplies and Garnishes
 &#41;
 resume player
end


Am I to assume that you can call scripts from within an if/then block? I didn't know this either. How does that work?
TMC wrote:However, looking closer, "Extra Supplies and Garnishes" itself is a mess (as are the others), 4000 lines of duplication, but should be only ~12 lines long. Add arguments for the textbox number, etc. Those arguments should be passed through ultimately from "Buy Crushed Ice" etc. You want to have the data (textbox numbers, price, etc) for each item concentrated in just a couple places rather than spread all over the place. That also lets you get rid of the trytobuy variables completely, which are each only used in those two places! I hope you see those variables are useless.
The "trytobuy###" variables are there to detect post-purchase thievery. They work in conjunction with a second set of variables, "trytobuy###post," which compares values to see if the player is trying to swindle the game after he's bought his items and then tries to swipe something off the shelf on his way out the door. They aren't necessary for legitimate purchases, but highly necessary for identifying thieves, especially those who think they've found an exploit in the system.

I agree that the game is full of duplicate scripts, and I definitely want to spend some time at some point trimming those down to simplified constructions, but the main reason for them is because each one does something a little different than the one it duplicates. I don't think I need to keep duplicating if I have a clear head about how to organize everything (not my strong point), but every variable I use in the game is necessary for something. "Trytobuy" has to stay, or at the very least the thing it accomplishes has to stay.
(Note, I couldn't figure out what these variables actually mean as it was too confusing, so I might have the variable names wrong.)
Variables like "groceritem7" are stock quantity items that shops use to determine how much of that item is still on the shelf. Background shoppers will buy things like Buck does, so the later in the day he shops, the less likely he'll get what he wants. Every item has a shop item ID. Groceritem7 is the shop item ID for crushed ice. The 100 and the 90 are stock thresholds. Once the value hits 90 (as in 90 have already been sold that day), it warns the player that there isn't much of that item left available to buy for the day. Equipment has a much lower number (usually 10) because the majority of equipment items are more expensive and less likely to sell out. And to implement some realism, a store is more likely to have fewer quantities of larger items.

I agree that I need to get to a safe zone before I start paring these scripts down. Maybe once I'm finished with the shopping scripts, I can start rewriting them. At least now I know what I want them to accomplish.

It would be nice to implement systems a lot faster.
Place Obligatory Signature Here
User avatar
Feenicks
Metal Slime
Posts: 696
Joined: Tue Aug 10, 2010 9:23 pm
Location: ON THE AIR IN THE AIR
Contact:

Post by Feenicks »

Okay, what exactly are you using over 99 variables in these scripts for? Your scripts sound like a complete nightmare to work with, and I want to know how they got to this point.
User avatar
Pepsi Ranger
Liquid Metal Slime
Posts: 1457
Joined: Thu Nov 22, 2007 6:25 am
Location: South Florida

Post by Pepsi Ranger »

I'm not going to post the samples here, but a few scripts compare all purchasable items in the game to one another for ranking or other math purposes, and because they do it internally, I don't need to waste global variables on them. But I'm sure there are simpler ways to accomplish that goal than by what I've done, so it's not a big deal. I've been able to successfully split scripts and achieve the same results. It means using more globals in the long run, but not much more than what I can "download" into for specific mathematical operations.

Again, with arrays, this wouldn't even come up in the conversation.

My scripts became what they are because I learned "programming" through plotscripting, and I learned it back when Hamsterspeak was still practically brand new and nothing like it is today, and I learned it primarily for stage direction. When years passed and I decided I wanted to take a stab at my dream of making a business sim, and to do it on the one engine I knew how to use, I realized I needed to learn how to script well beyond stage directions, but I didn't teach myself how to do them economically, so here we are.

TMC has been grilling me about sound organization for years, but I never listen because I'm stuck to my old habits, which I learned from early Hamsterspeak (which is why I still use "set variable" to this day, even though I know there's no reason to). But I also recognize the need to learn and practice new habits, so I'm moving in that direction, albeit slowly. It took me forever to finally grasp how arguments work in a script (thanks to a lesson by msw188, who managed to explain it to me in a way I could understand--as an English major, I've learned arguments as a form of rhetoric, not programming, so it took a while for me to retrain my brain to think of it as a top-level variable). A game like Entrepreneur needs a traditional programming foundation to work well without the chaos, and because I wasn't brought up on traditional programming (as I see it written everywhere else), I created the game based on the programming structure that I did understand, which is what TMC is going to eventually suffer a stroke over if he has to keep reading my scripts.

The important thing is that even though no one else can make sense of them, I can, so if I ever do manage to implement saner scripting techniques into my game, I'll know how to convert the old scripts into new ones without destroying their functionality. This lesson from TMC is helpful. I didn't think "write global" as an argument in a script function would actually work, so I never tried it. If I'd known in 2009 that it would, I'd probably be finished with the game by now.
Place Obligatory Signature Here
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

Am I to assume that you can call scripts from within an if/then block? I didn't know this either. How does that work?
Yes, it's just like a builtin command like keyispressed.

Code: Select all

if &#40;my script&#40;...&#41;&#41; then &#40;...&#41;
is identical to

Code: Select all

variable&#40;temp&#41;
temp &#58;= my script&#40;...&#41;
if &#40;temp&#41; then &#40;...&#41;
If the value in the 'if' condition equals 0 (which is the default return value for a script), that means 'false', anything else is 'true'.
The "trytobuy###" variables are there to detect post-purchase thievery.
Really? I was looking at trytobuy222, which is the one for hazelnut cream. That variable is only used in two places: Buy Hazelnut Cream which sets it to 1 and then immediately calls Extra Supplies and Garnishes, and Extra Supplies and Garnishes which sets it to 0 if it's not 0 (although I guess it's possible that some 'exit script' earlier in the script gets triggered... it's in practice impossible to tell if that might be the case, because of the extreme complexity). If it's meant to used for checking theft then you forgot to add that part, and likewise for other items I checked like crushed ice.
I agree that the game is full of duplicate scripts, and I definitely want to spend some time at some point trimming those down to simplified constructions, but the main reason for them is because each one does something a little different than the one it duplicates.
Yes, I see that you do have lots of variations with slightly different code. When that is necessary you should try to find a way to split the code up into the part that's always the same and the part that differs. And do feel free to have multiple variants of the "general" script.
My scripts became what they are because I learned "programming" through plotscripting, and I learned it back when Hamsterspeak was still practically brand new and nothing like it is today
Actually, HS really hasn't changed significantly in the last 15 years. Hundreds of new commands, but changes to the language itself are very few.

You've been doing this for a while, but HamsterSpeak sadly is a crippling language with no features that encourage use of abstraction and encapsulation, so you've learnt much less than you would elsewhere. I'm baffled that you've so far managed to pull off such a complicated game. Learning the basics of multiple languages is critical to the education of any beginning programmer. Therefore I think it might be a good idea if you actually went and learnt the basics of a language like Python (maybe with something like Learn Python the Hard Way? I don't know if I can recommend that, it does seem too basic). Coming back to HS after that will be a bit frustrating, but many of the things you would learn would be applicable in any programming language, it's just more difficult to see how to accomplish the same thing in HS. The point is that you would know that there ought to be an easier way. And as a bonus, Python is heavily influencing the design of the next version of HS so a lot of what you learn would transfer.
Last edited by TMC on Thu Aug 11, 2016 6:24 am, edited 1 time in total.
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

OK, more tips! Now for things that would be useful for most people to read; e.g. ones I used when cleaning up the scripts to Fridge Racer because Giz missed much easier ways to script stuff.

OK, so you have lots of different things in some category, in this case items (but also shops, customers, recipes, etc). The first thing you should do is give each item an ID number in order to refer to it. Since each of these items also exists in the Items editor in Custom, you could just use THAT ID number. That way you get a list of constants for free. Alternatively, you have all these constants like "compareitem:coffee pot", and I don't know if they are the same as the item editor ID numbers. You could rename these to something more convenient like "itm:coffee pot" (to avoid the clash with the automatically defined item:coffeepot).

Now that you have a list of ID numbers you can refer to items by ID in your scripts, and even better, you can create tables of data. Lets say you want to check if an item is a piece of equipment. Create a script:

Code: Select all

# Returns true or false
script, is equipment, item, begin
  switch &#40;item&#41; do &#40;
    case &#40;itm&#58;coffee pot, itm&#58;coffee sock, itm&#58;lawn mower&#41;
       return &#40;true&#41;
  &#41;
  # Otherwise defaults to false
end
And so forth for health items and other categories.

Now whenever you have a general script acting on an item, give that script the item ID number as an argument. This is incredibly useful, because now if you have some variant scripts that behave differently for equipment, you can combine them, and do an 'if' test, e.g.:

Code: Select all

script, buy item, item, begin
   ...common stuff
   if &#40;is equipment&#40;item&#41;&#41; then &#40;
     Extra Equipment
   &#41; else if &#40;is health item&#40;item&#41;&#41; then &#40;
     Health Supplies
   &#41; else if &#40;is garnish&#40;item&#41;&#41; then &#40;
     Extra Supplies and Garnishes
   &#41;
   ...more common code
end
OK, actually instead of the above there's an even better way. (But if you want to do it the way above instead of the better way I won't complain; you're still getting 98% of the benefit.) Each item (or shop, customer, type of coffee, etc) has various static data associated with it, like price, type, name and so forth. Define some constants for those:

Code: Select all

# Item data fields
define constant &#40;
 0, itemdata&#58;value
 1, itemdata&#58;name
 2, itemdata&#58;type    # One of the itemtype&#58; constants
 3, itemdata&#58;stock var   # ID of a global for the stock level
 ...
&#41;

define constant&#40;
 0, itemtype&#58;equipment
 1, itemtype&#58;garnish
 2, itemtype&#58;health
 ...
&#41;
(You may want to use a shorter prefix than "itemdata:")

Then create a script which is a giant lookup table for item data:

Code: Select all

# 'item' is an item ID constant
# 'data' is an itemdata&#58;... constant
script, item data, item, data, begin
  switch &#40;item&#41; do &#40;

     case&#40;item&#58;coffee pot&#41;
        switch &#40;data&#41; do &#40;
           case &#40;itemdata&#58;value&#41;      return &#40;80&#41;
           case &#40;itemdata&#58;name&#41;       $0="Coffee pot"   # a temporary string
           case &#40;itemdata&#58;type&#41;       return &#40;itemtype&#58;equipment&#41;
           case &#40;itemdata&#58;stock var&#41;  return &#40;@shopitem1&#41;
        &#41;

      case&#40;item&#58;coffee sock&#41;
        ...
  &#41;
end
If you have different stores selling an item for different prices, then the price information belongs in some table of data for the shop instead. And actually itemdata:name is probably unnecessary, because you can use getitemname instead, but in general that's how you handle strings.

And as an example of its use, you can reimplement "is equipment", now as just a convenience script:

Code: Select all

# Returns true or false
script, is equipment, item, begin
  return &#40;item data&#40;item, itemdata&#58;type&#41; == itemtype&#58;equipment&#41;
end
Please ensure you understand 100% how the above script works.

Do this, and you could ideally reduce your checklist for defining a new item (without actually using it anywhere) to about 3 steps:
-define a new item ID (define a constant or an item in the item editor)
-define the global variables for tracking stock, etc.
-add a block to the "item data" script by filling in the blanks.
Done. Of course then you have to also add it to the list of stuff in some shop, but that would ideally also be a really short check list.

Now because you already have all this code that doesn't use item IDs, you have a lot of work to do to get to that ideal. Go through the things on your implementation checklist and delete them one by one. Pass item IDs to scripts even if you don't currently know how to switch to using them, because those scripts will call other scripts which will eventually need them.

I had a look at "customer store buys health", which is a script with 50 locals, and actually the way you're using them as an array is not extremely unreasonable... however by using locals like that you can't deduplicate the different cases and switch to item IDs. You should instead use a temporary array of global variables (which you can zero out before/after use).
Last edited by TMC on Thu Aug 11, 2016 7:48 am, edited 11 times in total.
User avatar
Pepsi Ranger
Liquid Metal Slime
Posts: 1457
Joined: Thu Nov 22, 2007 6:25 am
Location: South Florida

Post by Pepsi Ranger »

TMC wrote:Really? I was looking at trytobuy222, which is the one for hazelnut cream. That variable is only used in two places: Buy Hazelnut Cream which sets it to 1 and then immediately calls Extra Supplies and Garnishes, and Extra Supplies and Garnishes which sets it to 0 if it's not 0 (although I guess it's possible that some 'exit script' earlier in the script gets triggered... it's in practice impossible to tell if that might be the case, because of the extreme complexity). If it's meant to used for checking theft then you forgot to add that part, and likewise for other items I checked like crushed ice.
There are five cases where either trytobuy222 or trytobuy222post (and their 278 cousins) is used:

(trytobuy222)

- Extra Supplies and Garnishes (used to convert the shopping cart item--aka real engine defined item--to Buck's official inventory when he checks out from the store's register--this gives the player the freedom to actively dump the item from his inventory before he buys it if he decides he either doesn't want it or can't afford it after he takes it off the shelf)

- Buy Hazelnut Cream (sets the condition to be used in "Extra Supplies and Garnishes," activated at the store shelf, and defines intention to buy by putting it into the shopping cart--aka engine defined inventory screen--but does not actually buy at this stage)

- Locate Shop and Item (used to define strings for the "shop item select display," which is the window that displays all relevant information about the item the player is attempting to buy)

(trytobuy222post)

- Inventory Check Before (records all items in Buck's inventory prior to leaving the shop)

- Inventory Check After (records all items in Buck's inventory when he tries to leave the shop--checks for consistent values with those found in "inventory check before" and punishes him for any value found mismatched--this is where post-sale thievery is detected)
TMC wrote:Yes, I see that you do have lots of variations with slightly different code. When that is necessary you should try to find a way to split the code up into the part that's always the same and the part that differs. And do feel free to have multiple variants of the "general" script.
I tell myself to do this every time I'm about to clone and modify a script, but I generally don't see a way to make that work. Now that I know I can use "write global" as an argument, I don't see this being a problem any longer. Now I just have to break the habit.
TMC wrote:You've been doing this for a while, but HamsterSpeak sadly is a crippling language with no features that encourage use of abstraction and encapsulation, so you've learnt much less than you would elsewhere. I'm baffled that you've so far managed to pull off such a complicated game. Learning the basics of multiple languages is critical to the education of any beginning programmer. Therefore I think it might be a good idea if you actually went and learnt the basics of a language like Python (maybe with something like Learn Python the Hard Way? I don't know if I can recommend that, it does seem too basic). Coming back to HS after that will be a bit frustrating, but many of the things you would learn would be applicable in any programming language, it's just more difficult to see how to accomplish the same thing in HS. The point is that you would know that there ought to be an easier way. And as a bonus, Python is heavily influencing the design of the next version of HS so a lot of what you learn would transfer.
After playing Stardew Valley last February and basically seeing what a newbie could do with the programming language he's learning (in that case, C#), I decided it was time to learn a true programming language, if for no other reason than to make a better version of Entrepreneur someday. I haven't started yet because I'm still invested in improving my writing skills--well, more like my editing for commercial readership skills--and my marketing skills, but it's still on the list of things I want to do in the near future. So, I will give this a look when I have some free brain space. I'm taking advantage of my time away from active writing to learn professional editing and marketing by working on the game again, which is why I've done more in the last week than I have in the last six months, but learning Python with everything else would be spreading myself thin at the moment. I can do it, sure, but I won't be able to dedicate myself to it as much as I'd like just yet. Have to master one thing at a time.
TMC wrote:OK, so you have lots of different things in some category, in this case items (but also shops, customers, recipes, etc). The first thing you should do is give each item an ID number in order to refer to it. Since each of these items also exists in the Items editor in Custom, you could just use THAT ID number. That way you get a list of constants for free. Alternatively, you have all these constants like "compareitem:coffee pot", and I don't know if they are the same as the item editor ID numbers. You could rename these to something more convenient like "itm:coffee pot" (to avoid the clash with the automatically defined item:coffeepot).
You may have forgotten, but "compareitem" is actually your contribution to the game. You put it together when I was trying to figure out how to make trending work without arrays. Defining constants is something I didn't know anything about at the time.

And technically, after looking at your following sample...

Code: Select all

# Item data fields
define constant &#40;
 0, itemdata&#58;value
 1, itemdata&#58;name
 2, itemdata&#58;type    # One of the itemtype&#58; constants
 3, itemdata&#58;stock var   # ID of a global for the stock level
 ...
&#41;

define constant&#40;
 0, itemtype&#58;equipment
 1, itemtype&#58;garnish
 2, itemtype&#58;health
 ...
&#41; 
it seems to me that I still don't know all there is to know. Is the constant defined by the first term (before the colon)? because you're resetting the numbers back to zero in the second example. If so, I never knew you could do that. I always figured constants were defined sequentially, like global variables are.
TMC wrote:Please ensure you understand 100% how the above script works.
Ha, don't worry about that. I'd never attempt to script anything crazy without knowledge of how to do it. :P

For the record, there is a consistency among numbers to define certain items. Trytobuy is an example of that, as is the various shop item codes. So, converting them to constants doesn't seem so outrageous to me. I could give that a try. (Figures we talk about this after I implement nearly every item I plan to put into the game. But, who am I kidding? There will be more.)
TMC wrote:I had a look at "customer store buys health", which is a script with 50 locals, and actually the way you're using them as an array is not extremely unreasonable... however by using locals like that you can't deduplicate the different cases and switch to item IDs. You should instead use a temporary array of global variables (which you can zero out before/after use).
You're talking about the "charge[item]" variables, and they're the ones that consistently run high in every script they're used. I keep thinking I should just turn them into globals since I reuse that same variable ID in every script that amasses items for a singular value. I don't, though, because they're only ever used in the scripts they're defined in and never need to be recalled. I thought it was a good way to save about 300 global variables.

Like I said in an earlier post, I didn't really see a need to convert them to globals. They're mostly used for shops, and no shop has more than 100 items. The scripts that locally attempt to compile all of the items together can be split into pieces. I've already done that for "record list" and something else that escapes me at the moment, and the behavior works the same. I'm currently in the process of splitting "trending sales" down to shop units, since that's basically how it should work anyway. So, I don't think I have a script in this game that must allow more than 100 locals. As long as I don't build a shop that sells more than 99 types of items, I shouldn't have any problems in the future, either. (No plans for that, by the way, so no need to panic.)

But I agree that locals can't allow me to deduplicate, so maybe I'll change them to globals anyway. Had to happen sometime.
Place Obligatory Signature Here
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

Actually, "locate shop and item" only goes up to trytobuy106. So maybe you did forget something. Regardless, locate shop and item and called right at the start of the scripts like "Health Supplies", so the point stands: using a global variable is pointless, you can use script arguments instead. Actually, I was surprised to see that "locate shop and item" checks all the trytobuy## globals to find the one that is nonzero, and then passes a corresponding ID number to "shop item select display". See! You do get that ID numbers are useful! You just haven't defined constants for each of the items. You could get rid of "locate shop and item" and pass the ID number directly.
You may have forgotten, but "compareitem" is actually your contribution to the game.
I figured that was probably the case, although I had no memory of it.

Regarding constants:
You can have multiple constants with the same variable (for example "zero" and "hero:bob" and "item:carrot" might all have the value 0). And any constant can have any value, so the order that constants are defined also does not matter. Also, it makes no difference whether you define multiple constants in one "defineconstant" block; it's completely equivalent to a separate defineconstant per constant.

The colon is just part of the name, and has no meaning to the script compiler whatsoever. I used a name like "itemdata:name" just to match the convention used by many other constants like item:coffeepot.

You're talking about the "charge[item]" variables, and they're the ones that consistently run high in every script they're used.
No no, those charge[item] variables ARE an unreasonable use of huge numbers of redundant local variables. You should write instead:

Code: Select all

total += 3 * inventory &#40;23&#41;  # sandwich
without needing a local. (I know in a couple scripts you also use an 'if' to check the map to determine the value, but in those cases you still don't need to use a local unless you really want.) Of course, I would instead have the list of items for sale in a shop, including prices, defined in one place, and use a for loop instead to calculate the total.

The "not extremely unreasonable" locals I was talking about are the variables it1, etc, used to prevent the same item from being picked twice in a for loop.


Anyway, I was serious about wanting to make sure you totally understand the scripts I posted (meaning nothing in them should be taken on faith/as magic). They're very short scripts. Let me know what you still don't understand. Don't despair. HS is an incredibly simple language, it's no exaggeration to say it's less than 1% as complex as Python. (Although, when I say that, I realise there are obscure features of HS that few people know about, probably even ones that noone aside from me knows about.)
Last edited by TMC on Fri Aug 12, 2016 3:34 pm, edited 1 time in total.
User avatar
Pepsi Ranger
Liquid Metal Slime
Posts: 1457
Joined: Thu Nov 22, 2007 6:25 am
Location: South Florida

Post by Pepsi Ranger »

TMC wrote:Actually, "locate shop and item" only goes up to trytobuy106. So maybe you did forget something. Regardless, locate shop and item and called right at the start of the scripts like "Health Supplies", so the point stands: using a global variable is pointless, you can use script arguments instead. Actually, I was surprised to see that "locate shop and item" checks all the trytobuy## globals to find the one that is nonzero, and then passes a corresponding ID number to "shop item select display". See! You do get that ID numbers are useful! You just haven't defined constants for each of the items. You could get rid of "locate shop and item" and pass the ID number directly.
No, I didn't forget. Because I do things in stages, I add to scripts as I get to them in the checklist. "Locate shop and item" is a very late stage addition, so I typically don't add to that until near the end of the item's implementation stage. As it turns out, I hadn't gotten to that script yet when I uploaded the most recent file, but I did get to it the following night, so even though you don't have the version where hazelnut cream is included in the script, I do. That's why I was able to find it and you weren't. I had literally just added it to the script shortly before addressing the post. Timing!

I think the moral of the story is that I need to go back and reevaluate the effectiveness of all of my scripts. One of my lingering plans that I've been meaning to do for years and still haven't gotten to yet is to redistribute the plotscript into separate thematic files, so that all shop scripts will be in one file, customer scripts in another, narrative scripts in another, and so on. This will make it easier for me to find what I'm looking for. But the secondary advantage is that by doing so, I can better attempt the economic methods that you're suggesting here.

I don't want to start something like that until I get through this phase of development. I know it'll ultimately prove redundant if I do this correctly, but sometimes the creation process requires placeholders before it can open up to the refined, edited way. I'd rather finish this section, and then go back to the beginning and start the process of rebuilding. By the time I get back to where I left off, I should have a clue or two about how to do this efficiently.
TMC wrote:Anyway, I was serious about wanting to make sure you totally understand the scripts I posted (meaning nothing in them should be taken on faith/as magic). They're very short scripts. Let me know what you still don't understand. Don't despair. HS is an incredibly simple language, it's no exaggeration to say it's less than 1% as complex as Python. (Although, when I say that, I realise there are obscure features of HS that few people know about, probably even ones that noone aside from me knows about.)
Heh, I never despair. I just plow ahead whether I know what I'm doing or not. I see things in terms of the end goal, not just how clean the roads are getting there. If it can be done, I'll find a way. But knowledge is better than ignorance, so we'll get there smoothly eventually. I'll make sure I know this stuff before I apply it to this game. I have a separate file for practicing scripts and features that I don't fully grasp, and work with them until I do grasp them. Then I can apply them to the main game. That's why "Mouse Tester" is a different file. Don't want to add that to the game until I know it works (and until I know I can select menu items with the mouse).
Place Obligatory Signature Here
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

Rewriting everything is definitely a big task. But as you continue adding new items (although you said you wouldn't immediately...) you can still do them in a more sensible way. Even if you've already duplicated a script 270 times I wouldn't duplicate it 5 more times. Also, we've been discussing the scripts for items, but you should also apply the same principles to everything else that needs scripting. Don't wait until the end to switch to better methods, that's totally counterproductive.

On the topic of mouse control of menus, there is still a bug in "menu item at pixel" where it doesn't work right if the menu has a scrollbar. (Note: I wrote a script for menu control, but didn't post it on the wiki for that reason. And anyway, the idea was to build support into the engine.)
User avatar
Pepsi Ranger
Liquid Metal Slime
Posts: 1457
Joined: Thu Nov 22, 2007 6:25 am
Location: South Florida

Post by Pepsi Ranger »

I can wait on mouse menus. I still don't fully know how I want to implement mouse support. There are plenty of things I'd like to implement, including support for pixel-based movement, maybe even dumping the built-in menu completely and using clickable buttons instead (like in a real business sim), and other things that occasionally come to mind. None of these are for certain, though. Just ideas. Take your time in getting it done right. I care more about having the ability to change menu item colors through plotscript, as that supports my plan for customer psychology, which I wanted to do for v1.3, then I do about selecting menus via the mouse. But, I think having the ability to select menus via mouse is still very important, and probably more immediately needed for other games that I have no involvement with. Possibly.

Obviously, if I implement clickable buttons, then I won't really need the menu anymore. But that's a conversion that, if it happens at all, won't happen for a long, long time, and probably only if I decide to strip the music and direct pop culture references out and produce a commercial version of the game for Steam--again, something I don't foresee happening any time soon.
Place Obligatory Signature Here
User avatar
kylekrack
Liquid Metal Slime
Posts: 1240
Joined: Mon Jun 16, 2014 8:58 am
Location: USA
Contact:

Post by kylekrack »

I'm just gonna pop in here; I just played Entrepreneur for the first time. I... am very confused. The first time I played, I ended up buying too much ground coffee in the tutorial and didn't have enough money to get paper cups, so I ended up stealing them. But then I realized I also needed a new filter, and I figured I should probably just start over at that point.

I still can't figure out how to finish brewing a cup of coffee, though. I got the coffee pot, activated it in the venue, then added a filter, and coffee powder. I waited for it to finish brewing, then went to get the coffee. It said I had nothing to put the coffee in. I have coffee cups, so do I need something else to put brewed coffee in? I can't find anything at the store that makes sense to use.

My problem is that there's no checklist of things I need to start out, but there are a bunch of things that are available to me. It's also possible that I missed something(s) in the tutorial because it was a lot of information about a lot of different things. Bottom-line, the game's introduction isn't stupid-proof. I ended up getting stuck. This may or may not be helpful as playtesting feedback, but if I can figure out how to get going in this game, I'll gladly play more. I'm a big fan of the aesthetic.
My pronouns are they/them
Ps. I love my wife
User avatar
Pepsi Ranger
Liquid Metal Slime
Posts: 1457
Joined: Thu Nov 22, 2007 6:25 am
Location: South Florida

Post by Pepsi Ranger »

kylekrack wrote:I'm just gonna pop in here; I just played Entrepreneur for the first time. I... am very confused. The first time I played, I ended up buying too much ground coffee in the tutorial and didn't have enough money to get paper cups, so I ended up stealing them. But then I realized I also needed a new filter, and I figured I should probably just start over at that point.
I'm eventually going to set it up so that the game recognizes that you're doing something foolish and will shape your experience around it. Kind of like the real business mechanic of learning by failure. It already allows you to make business mistakes, and it's flexible enough to let you run with the consequences (and recover from them), but I want to actually build an RPG stat progression based on stuff like that. That's probably still a ways off though.

For now, you may or may not have found it (I admit it's in a terrible location, as it's hard to know it's there until you read the signs, and I may eventually move it), but there's a consignment shop across the street from the Shop Down the Street (yes, that's the actual name of the store), where you can sell anything you don't want. It's a great way to refund those bad purchases. You can sell equipment, too, but they depreciate each day, so you won't want to wait long if you need to sell them.

I'm also going to rewrite the system to allow you to buy up to four of each piece of equipment so that you can have four coffeepots running at once, instead of one coffeepot, one coffee sock, etc. That'll also give you more varieties to brew at once. I'm expecting to have that ready for v1.3.

As far as starting supplies go, if you've played through the whole tutorial, then you should already know, but you can get everything you need at the start by searching through trash cans. There's also one point in the tutorial where you can earn an extra $50, but I'll let you figure out how to do that for yourself.
kylekrack wrote:I still can't figure out how to finish brewing a cup of coffee, though. I got the coffee pot, activated it in the venue, then added a filter, and coffee powder. I waited for it to finish brewing, then went to get the coffee. It said I had nothing to put the coffee in. I have coffee cups, so do I need something else to put brewed coffee in? I can't find anything at the store that makes sense to use.
You did everything right but one thing. You have to actually get the cup from the counter and take it to the machine. Entreprener does few things magically. If something doesn't work "the RPG way," then try it the way you would do it in real life. The only thing it'll do magically is stock your counter with your cups, garnishes, etc. (after you've initiated their graphics on Day 1). Though, even that may change when I get the storage system in place (it won't change in a wonky way, though).
kylekrack wrote:My problem is that there's no checklist of things I need to start out, but there are a bunch of things that are available to me. It's also possible that I missed something(s) in the tutorial because it was a lot of information about a lot of different things. Bottom-line, the game's introduction isn't stupid-proof. I ended up getting stuck. This may or may not be helpful as playtesting feedback, but if I can figure out how to get going in this game, I'll gladly play more. I'm a big fan of the aesthetic.
No, it is definitely helpful. Giz had many of the same issues, even with the tutorial. Be glad you're not playing a version before 1.2. The game didn't have any kind of tutorial before then. But, one of my plans for v1.3 is to write a new tutorial that does more to hold your hand in the step-by-step. I won't be getting rid of the one that's there, though. I'll be making a new tutorial for "beginners" and changing the current one to "refresher" for those who've played before but not in a while.

For now, if you're stuck, you can visit the Whipping Shed and talk to Miyagi about the different categories the game features. The instructions are also fairly detailed. And, of course, you can just come here and ask if something doesn't make sense to you. I definitely welcome the feedback, especially when something doesn't work well, or if you have an idea about how to make something better. I take all considerations that don't compromise my plans for the game's future.

I can also write up a plan of attack if you need one. I eventually want to make a Youtube video of the first five days, but not until I ditch the commercial music. That'll probably also happen in 1.3.

Keep in mind, though, that holding the player's hand was never my priority. Part of the thrill of the game (in my opinion) is to learn what works and what doesn't, and to change your strategy according to what you learn. I certainly don't want to make progression impossible, but I'm not that concerned about giving players an easy victory, especially when the information is given to them in the instructions and things. I liken it to an education. You can learn how to succeed at the coffee business if you do the study (read the directions), or you can wing it (just dive into the game) and figure things out on your own. I think the game is fun either way. Kind of like playing Terraria. There's so much the game just expects you to learn and adjust to, even though previous players who have discovered its secrets will post their findings on the wiki for the benefit of other players. That's an extreme example, though. This game is nowhere near as complicated as that one.
Place Obligatory Signature Here
User avatar
kylekrack
Liquid Metal Slime
Posts: 1240
Joined: Mon Jun 16, 2014 8:58 am
Location: USA
Contact:

Post by kylekrack »

Thank you for the response. I definitely feel like it all makes more sense now. I'll get to playing it when I'm done working on my own project for today.

I was considering the whole hand-holding element. I didn't mean to suggest that there *should* be a checklist of things to start out, simply that I didn't have one, and got really lost, probably because I have a bad memory. It's clear that giving an easy victory is not the goal of this game. The way it throws in so suddenly did not set the bar low. I like that. It does feel more emotionally realistic that way, starting a business from scratch and figuring things out each step of the way. It is important to balance difficulty with player progression, though, especially when the player is first starting out. I can see how it could be difficult to know just what a newbie needs to get going without becoming too frustrated right off the bat. In fact, I can't even imagine how you end up balancing all of the resources in this game, it's huge.

That being said, I think just having easy access to a simple map of the city would help. Learning the layout of any area takes time, whether it's playing a new game, or moving to a new town IRL. With a map, there are at least landmarks to travel to for potential information grabbing.
My pronouns are they/them
Ps. I love my wife
Post Reply