Yes, I made a Larry 7 Template! Yes, like all my previous templates the code is very messy! :P
Basically I need criticism and beta testing on this. Play with it, break it, have fun, let me now, kay?
http://12.22.230.41/MicroTech/Hosted/Game/LSL7.zip
Oh, you'll need at least AGS v2.7 beta 7...
EDIT - Version 0.1 is up, includes bug fixes and discreet extras, like the ability of having more than 24 verbs/inv items in a menu list. Still un-reviewed by RickJ.
wel I hawe the newest verion of AGS but I still can't open the template...
Really? It works for me. What happens when you try and load it? Usually AGS seems to crash if you're using an earlier version than the one the template was made with. Or do you not see the template at all? You are sure you're using the latest beta?
I'm using the 2.62 version. Since when was there a higher version?
I can't seem to find it anywhere on the main page...
Sticky in the technical forums
QuoteOh, you'll need at least AGS v2.7 beta 5...
:P
EDIT - Oh my... over 200 views, and still no reply... is it that bad?
As I posted on 'our' forums
It really kicks ass!!!!!
I'm amazed
I'm finding bugs I'm surprised no one noticed yet... I'll cook up another version with less bugs, more comments and use of the new GUI system.
Custom Properties
Have you considered adding a text property for each of the verbs. That way if someone checks a verb for an item they could just enter a text message for it right there.
So if there isn't any other action defined then the message could be displayed. If there isn't a custom message defined in the item's properties then you could display default messages according to item type as you are doing now.
Any chance you could release it for v. 2.62 too...? Or are you using AGS stuff that's only in the latest beta? Gah, that was a bad sentence. :P
Anyhow, I don't really want to upgrade to an experimental beta, so I won't be able to test your template, and I think others might feel the same. Which kinda sucks, since I love Larry 7's GUI. Oh, well.
Rick J - <scratches head> I swear I'm trying to understand, but I can't quite...
Lazy Z - This latest beta does have a current bug that doesn't allow you restoring or saving, but if you are scripting you might as well get a hold of it - there's a lot of changes being made, permanent changes, that you might as well be prepared for by checking out the betas, which allows you to take one change at a time. And yes, there's a couple of features that I want, such as the recent ability to check where in the listbox the mouse is. I'll be changing my template to incorporate that.
For example:
- For each verb check box in the custom properties schema add a corresponding text entry field.
- Now edit the properties of an item such as a rock object.
- Check the "Eat" verb (or "Drink" or whatever).
- Now enter the custom message in the text entry field: "You're not man enough to eat that rock, are you?"
- If an action is defined for this item then the message is ignored as is done now. If not then the custom property message is displayed instead. If the message in the custom properties is empty then you can display the default message for that type of item as you do now.
It's a great idea, but I think the current method not only makes it easier to manage the whole thing (it's all in the same script), your method would need exceptions - namely, the times when something ELSE happened instead of just displaying a message. THAT would need a script entry, and having some things in properties and some in script might not be too friendly...
...I think. Feel free to prove me wrong.
Ok, well I think you could do everythig in your NoMatch() function. I have taken the liberty of dressing it up a bit and modifying the "TURN" verb as I suggested above. I think you can see how to do this for the rest of the verbs.
//===================================================================
function NoMatch() {
//
// This function is called if no other actions are defined for the
// selected item. It displays a message defined for the selected item
// and verb in the custom properties. If that message is an empty
// string then a default message is displayed.
//===================================================================
string name, msg;
int type;
// Get the name of the location
GetLocationName(mouse.x, mouse.y, name);
StrToLowerCase(name);
// Get the type of the location
if (GetInvAt(mouse.x, mouse.y)!=-1) type = 4 // Inventory
else type = GetLocationType(mouse.x, mouse.y);
// Swim
if (Said("swim")) Display("You'd look silly swimming on the %s, don't you think?", temploc);
// Look
if (Said("look")) Display("What you see is what you get.");
// Examine
if (Said("examine")) Display("Further examination of the %s reveals nothing new.", temploc);
// Drink
if (Said("drink")) Display("The %s is not intended for comsumption.", temploc);
// Eat
if (Said("eat")) Display("The %s is not intended for comsumption.", temploc);
// Open
if (Said("open")) Display("The %s doesn't seem to open.", temploc);
// Close
if (Said("close")) Display("The %s doesn't seem to close.", temploc);
// Read
if (Said("read")) Display("There's nothing to read on the %s.", temploc);
// Rip
if (Said("rip")) Display("Try as you might, you can't rip the %s.", temploc);
// Smell
if (Said("smell")) Display("The %s has a farily non-descript smell.", temploc);
// Press
if (Said("press")) Display("You press the %s, but nothing seems to happen.", temploc);
// Take
if (Said("take")) Display("You can't seem to be able to take the %s.", temploc);
// Talk
if (Said("talk")) Display("The %s does not respond.", temploc);
// Turn
if (Said("turn")) {
if (type==1) { // Hotspot
GetHotspotPropertyText(GetHotspotAt(mouse.x, mouse.y), "TurnMsg", msg):
if ((StrComp(msg, "")!=0) Display(msg);
else Display("You'd be hard pressed to turn the %s.", name);
}
else if (type==2) { // Character
GetCharacterPropertyText(GetCharacterAt(mouse.x, mouse.y), "TurnMsg", msg):
if ((StrComp(msg, "")!=0) Display(msg);
else Display("You'd be hard pressed to turn the %s.", name);
}
else if (type==3) { // Object
GetObjectPropertyText(GetObjectAt(mouse.x, mouse.y), "TurnMsg", msg):
if ((StrComp(msg, "")!=0) Display(msg);
else Display("You'd be hard pressed to turn the %s.", name);
}
else if (type==4) { // Inventory
GetInvPropertyText(GetInvAt(mouse.x, mouse.y), "TurnMsg", msg):
if ((StrComp(msg, "")!=0) Display(msg);
else Display("You'd be hard pressed to turn the %s.", name);
}
else { // Unknown
Display("Hard as you try you get no satisfaction.");
}
}
}
One additional thought, I would add a check to see if the character was the player character or not. If it was the PC then have a different default message (i.e. use personal pronouns etc instead of character's name).
Ok, I think I see what you mean, but unless I'm wrong, if "turn key" actually DID something other than just display a message, the relevant code would be places here, right? And ditto for everything else, probably making the NoMatch function overloaded. And if a function gets too many if/else statements, AGS won't allow it to compile - I learned that the hard way. And we have to assume that the game made will accept a LOT of verbs. For my AGI template, I had to make THREE NoMatch functions, one calling the other once it was finished, because of this.
It's definitely a good idea, but I think it's not all that practical.
HOWEVER, you point about the PC's check is a very good one. I'll definitely add it, thanks!
Quote
... if "turn key" actually DID something other than just display a message, the relevant code would be places here, right?
I think you would you put the code for "Turn key" in the same place you do now. Why would it be placed in NoMatch()? If I understand correctly the code that does the actions would call NoMatch() nothing was defined for the action, isn't this correct?
Oh, silly me. Yes yes YES I see what you mean. I haven't had much time to update the template, and won't release it yet anyway becuase the latest beta has an issue with restarting, but I WILL do as you suggest. I understand now.
Here are a couple of other ideas to make your script more readable.
game_start(), releatedly_execute(), releatedly_execute_always()I usually don't like to put much code into these system functions. Instead I all the code into other functions and then call them from these system functions. In your case I would probably make:
- l7_start()
- l7_execute()
- l7_execute_always().
Of course you could break thins down further is you wish (i.e. l7_something_start(), l7_anotherthing_start(), etc).
Global vs Local
I always like to name things so that I know what is local and what is global. The way I choose to do it is to use mixed case for global functions and variables and to use all lowercase for local functions and variables. For example the NoMatch() function above would become l7NoMatch() if were global and l7_no_match() if it were local. There are of course many other ways of doing this.
CallRoomScript()
Are you famillar with this and have you considered using it to implement actions? The reason I ask is that this would allow all of the action code for a specific room to be included in that room's script. This makes things scalable (i.e. No matter how many rooms are added the complexity and size of the global script doesn't increase). I haven't absorbed your code enough to make a more specific recommendation.
1 - I see your point. It would be much more readable, yes. I'll do it.
2 - So for instance what's now add_inv should become AddInv? It was on purpose, so people wouldn't mistake it with the already existing function, and DoAction() and whatnot were only like that because there was none alike...
3 - Yes, I'm familiar with that, I though though it would be easier if I dumped it all in the room script and had it done with - this way the user would only have to mess with the room script.
Quote
... I see your point. It would be much more readable, yes. I'll do it.
It also makes it easier for other people to use your template. Consider doing the same for the other system event handlers such as interface_click() etc.
Quote
.. So for instance what's now add_inv should become AddInv? It was on purpose, so people wouldn't mistake it with the already existing function...
To avoid confusion with already existing functions I used a lowercase prefix. So in the BlueGui it would have been bgAddInv(). Using the new OO stuff this would likely be Bg.AddInv(). So in your case you would have something like l7AddInv() or L7.AddInv().
Quote
...I thought though it would be easier if I dumped it all in the room script and had it done with - this way the user would only have to mess with the room script.
That's why I asked about CallRoomScript(). I was thinking that interface_click() could just do a CallRoomScript() and pass the item number that was clicked in the action menu. Then in the room script you would have the following to fill out however one desired.
function on_call(int verb) {
// called when verb is selected from menu
if (verb==0) {
}
else if (verb==1) {
}
else if (verb==2) {
}
else if (verb==3) {
}
else if (verb==4) {
}
else if (verb==5) {
}
else if (verb==6) {
}
else if (verb==7) {
}
:
:
else if (verb==nn) {
}
}
I was also wondering about what you are doing in repeatedly_execute_always()? I haven't yet spent a lot of time on it but in the little time have, I didn't get a feel for what was going on there. Whenever I use any of the repeatedlys I scrutinize what I am doing.
I'm still a bit lost as to your suggestion regarding the room script, sorry...
And in repeatedly_execute_always I have... well, lots of stuff. A counter for the score, some code to make sure the menu pops up correctly, some code to highlight the cursor when over SOME GUI buttons (not all)... heh. Lots of stuff.
Quote
I'm still a bit lost as to your suggestion regarding the room script, sorry...
That's probably because I need to understand/study what you've done a bit more. Where are you handling the menu click? I assumed it was in interface_click() in the global script. I'll keep looking and try to re-explain myself ;)
Quote
And in repeatedly_execute_always I have... well, lots of stuff. A counter for the score, some code to make sure the menu pops up correctly, some code to highlight the cursor when over SOME GUI buttons (not all)... heh. Lots of stuff.
Ok. That's probably the only sensible way of over-riding the cursor's default behaviour and appearance. I'm not sure about the other stuff you mention but I will keep looking.
I you like, I can take a look at whatever progress you are making. Just let me know when and where I can get an update.
Keep up the good work.
Oh, at the mo I'm not working on it. I'm taking advantage of the break proportioned by the little problem with restart/restore in the latest beta to organize my real life, and am treating this thread as a to-do list which I'll pick up on as soon as the next beta/final is released.
I handle menu clicks in interface_click, yes... what happens in, when the player chooses a verb, the interface_click function calls up the DoStuff() function. That one basically parses the verb the player has chosen (said verb being a string previously defined by getting the name of the listbox item) and runs the MODE_USE interaction for the object/character/hotspot/inventory selected, where a "Said" command is waiting for the parsed verb. I did it like this so as to minimize scripting for the user, as odd as that may sound when considering some things in that template ;) ; the user would only have to open the correct interaction mode (USE) in the interaction editor and add whatever interactions he wanted with several "Said" commands.
Quote
Oh, at the mo I'm not working on it. I'm taking advantage of the break proportioned by the little problem with restart/restore in the latest beta to organize my real life, and am treating this thread as a to-do list which I'll pick up on as soon as the next beta/final is released.
Ok. As long as youtake my comments as "food for thought" rather than "commandments". :)
[quoe]
I handle menu clicks in interface_click, yes... what happens in, when the player chooses a verb, the interface_click function calls up the DoStuff() function. That one basically parses the verb the player has chosen (said verb being a string previously defined by getting the name of the listbox item) and runs the MODE_USE interaction for the object/character/hotspot/inventory selected, where a "Said" command is waiting for the parsed verb.
Quote
So then you're saying that the interaction editor can then be used to pickup the
"Said" command and implement the action?
Quote
I did it like this so as to minimize scripting for the user, as odd as that may sound when considering some things in that template Wink ; the user would only have to open the correct interaction mode (USE) in the interaction editor and add whatever interactions he wanted with several "Said" commands.
If I understand correctly, this accomplishes what I was suggestingwith the CallRoomScript() thingy but with the interactiion editor instead of the room script. If this is so it's quite clever and something I would never have thought of.
So do you do a ParseText(menuu_text); in the global script and then do a series of "if (Said("...")) { }s" inthe room script or interaction editor? Clever! What triggers the event then?
QuoteSo then you're saying that the interaction editor can then be used to pickup the "Said" command and implement the action?
That's just what it does, yes.
QuoteWhat triggers the event then?
Not sure if I understand the question, but if I do, it's selecting a verb in the listbox that triggers the whole works. And the thing that triggers calling the interactions in the editor is the RunHotpotInteraction (or character[].RunInteraction, or whatever) inside the function DoStuff(), called by clicking on the listbox.
Quote
Not sure if I understand the question, but if I do, it's selecting a verb in the listbox that triggers the whole works. And the thing that triggers calling the interactions in the editor is the RunHotpotInteraction (or character[].RunInteraction, or whatever) inside the function DoStuff(), called by clicking on the listbox.
Ok, I understand what you're doing now and I think it's pretty clever. I think you will need a brief explanation of this in the release. What do you do then if there are more actions than modes or if they are non-standarrd?
This also explains why my suggestion about the CallRoomScript() didn't make sense to you. You had already accomplished what I was talking about using this method.
QuoteWhat do you do then if there are more actions than modes or if they are non-standarrd?Ã,Â
Ok, if I read you well, it doesn't really matter, because whether the player has clicked on a default or a custom verb, the result is the same - the verb's name is extracted and parsed. In the demo, if (Said("swim")) works perfectly, and stuff like that is all you need to do, apart from making sure the verb is also in the vocab list.
Now that the latest beta is off, I'm converting the whole thing to this new system, plus fixing a coupla bugs and adding the ability to, Windows-style, let those USE and OTHER menus pop up if the mouse is some time over the option, even if the player doesn't click. After that, I'll implement the things in this thread, starting with COMMENTING the darn thing. ::)
EDIT - "More actions than modes" never happens, because only the MODE_USE is ever called.
Quote
"More actions than modes" never happens, because only the MODE_USE is ever called.
OK, so you then have the "Use" interaction function with a series of if Said()s?
Quote
Now that the latest beta is off, I'm converting the whole thing to this new system, plus fixing a coupla bugs and adding ....
If you need any help with the object stuff or want me to look at something jusyt let me know..
Quote
After that, I'll implement the things in this thread, starting with COMMENTING the darn thing.
One tip about generating comments, I prefer doing it at the same time I am producing code. I find that it is less burdensome this way and often contributes to the coding process by being a kind of mini-design document and keeping me out of trouble.
QuoteOK, so you then have the "Use" interaction function with a series of if Said()s?
Precisely. And a "Use Inventory On" interaction too, come to think of it - I haven't made a default response for that. I'll have to remember to add it, maybe using unhandled_event.
QuoteIf you need any help with the object stuff or want me to look at something jusyt let me know..
Thankya, I sure will! But I hope that won't be necessary. ;)
And about comments... heh. I don't like writing them AT ALL, and when I DO they're usually things only I can understand... maybe I can find someone to turn whatever comments I turn out this time into REAL comments. :P
Quote
... maybe I can find someone to turn whatever comments I turn out this time into REAL comments...
I can do some of that for you. We should just mske it part of a review process. That way I'll understand what you are doing and will have an opportunity comment. We seem to be getting along so far ... ;D
All right, deal! I'll keep making my own comments, which are probably too obscure to most non-scripters but which you'll probably make heads or tails of - especially since you seem to be familiarizing yourself with it. Then I'll upload it and PM you, and you give it the once over, see if it works, what it looks like, and add the comments. And feel free to optimise whatever you think's needed, naturally.
EDIT - I decided not to add the text-property-thingie you mentioned, RickJ. It's an extra bulk that looks nice, but isn't really practical when you consider that without it you only need one place for coding everything, namely the "Interact with (whatever)" in the interaction editor.