Dividing the Global Script...guidelines **SOLVED**

Started by Knox, Tue 06/07/2010 16:32:20

Previous topic - Next topic

Knox

Hi,

In the manual, I found an entry "Multiple Scripts" which explains that you can break up your Global script into pieces if it starts to get large. Right now mine is about 6000 lines, but this includes many "custom scripts" to manage inventory items, various gameplay elements, etc...

Here is all I could find in that entry that explains what to keep in the GS:
Quote
The main global script still has to contain all the event functions (Look At Character scripts, Interact With Inventory scripts and so forth) and all the GUI handlers (btnSave_Click, etc).

The thing is, Im still not too sure what needs to be in the GS, it just says "and so forth"...for those who have done this already, is it a "trial and error" kind of deal?

"All the event" functions Im not to sure what it means, exactly...GUI handlers, its ok though, I understand that...
--All that is necessary for evil to triumph is for good men to do nothing.

GarageGothic

Basically anything that is linked directly from editor (the stuff that is auto-named/generated from the interaction or GUI editor). All the purely scripted stuff such as on_event, rep_exec and of course custom functions that you call from within other functions can be moved to modules. (Of course if you need to call a custom function in a module from the global script, you must first import the function in the module header).

Knox

Ok so whenever something is clicked from the editor that creates a line in the Global Script...should stay there, right?

Is it safe to say pretty much any function with "_onclick" should stay in the GS?

Also, I was thinking of doing this and was wondering if its "a good idea":

Instead of having hundreds of cThisCharacter_Look,  cThisCharacter_Talk, etc...I was thinking of processing everything for hotposts, characters and objects in my "on_mouse_click", something like this:

Code: ags

function on_mouse_click(MouseButton button)
{
    LocationType loctype = GetLocationType(mouse.x, mouse.y); 
    if (loctype== eLocationCharacter) doGameResponses(eLocationCharacter);
    else if (loctype== eLocationHotspot) doGameResponses(eLocationHotspot);
    else if (loctype== eLocationObject) doGameResponses(eLocationObject);

}


Then, I would have this in a module:
Code: ags

function doGameResponses(LocationType *loctype)
{
   Character *overCharacter = Character.GetAtScreenXY(mouse.x, mouse.y);
  Object *overObject = Object.GetAtScreenXY(mouse.x, mouse.y);
  Hotspot* overHotspot = Hotspot.GetAtScreenXY(mouse.x, mouse.y); 
   if (loctype == eLocationCharacter)
  {
     if (mouse.Mode == emodeLook)
    { 
       if (cChar == cEgo) Display ("This is the main character"); 
       else doUnhandledInv_Character(overCharacter);
     }
     else if (mouse.Mode == emodeTalk)
    {
        //etc...
     }
  }
   else if (loctype == eLocationHotspot)
  {
     //etc...
  }
   else if (loctype == eLocationObject)
  {
     //etc...
  }
}


Then, another module would handle the unhandled "generic" responses like so:
Code: ags

function doUnhandledInv_Character(Character *cChar)
{
  unhandledResponse_Inv = Random(5);
  if (unhandledResponse_Inv == 0) cChar.GSay(String.Format("Hmmm, nope, that %s doesn't look familiar.", sActiveItem)); 
  else if (unhandledResponse_Inv == 0)
   //...etc....     
}



Is this a "good" way of handling all the possible responses to left clicks for hotspots, objects and characters? I feel I can manage it better in a module so I wont make my GS even bigger than it already is...
--All that is necessary for evil to triumph is for good men to do nothing.

GarageGothic

Yeah, only skimmed the code, but it sounds very sensible. I'd probably want to keep room events (hotspots, objects etc.) in the individual room scripts, not just to decrease the number of if-statements but also to be able to refer to them by name rather than number only. You could of course have a similar piece of code in the room script to still avoid the autogenerated scripts but keeping the aforementioned benefits.

Once you've "perfected" your doGameResponse function you could put a doRoomResponse in the default template room file so you don't have to cut-n-paste for every new room.

Khris

I'd probably use one function for each object, hotspot, character and inv item; then leave the former two in the room scripts and move the latter two to a separate script.
In the function, I'd check the mouse mode or used verb and handle it accordingly, then put an else at the end with a call to a custom unhandled function.
Everything is only linked to any_click, save inv items.
This is pretty much exactly how the 9-verb template works, btw.

Knox

#5
Nice, thanks for the extra info guys...Im going to use your tips to see what I can do so its as good as possible :)



**EDIT**
Ok I found the solution
--All that is necessary for evil to triumph is for good men to do nothing.

Knox

Hi,

I was wondering the main reason why you guys would NOT recommend having the hotspots + objects processed in a module rather than in the room scripts? If I dont personally mind using else if's and using
the hotpost/objects .ID or .Name, is it still "ok"?

I guess I personally rather having everything in one location instead of going through all the room scripts, etc...

Here is an example (at the debuggin stage anyways) of the unhandled script for objects (same template for hotspots)

Code: ags

function unhandled_GamePlayResponses_Obj(Object *oObj)
{
  unhandledResponse_Obj = Random(5);
  //LOOK AT OBJECT 1/5
  if (mouse.Mode == eModeLookat)
  {
    Display("Unhandled response...Object: %s", oObj.Name);
  }
  //INTERACT WITH OBJECT 2/5
  else if (mouse.Mode == eModeInteract)
  {
    Display("Unhandled response...Interact with %s", oObj.Name);
  }
  //QUESTION OBJECT 3/5
  else if (mouse.Mode == eModeQuestion)
  {
    Display("Unhandled response...Question %s", oObj.Name);
  }
  //COMMAND OBJECT 4/5
  else if (mouse.Mode == eModeCommand)
  {
    Display("Unhandled response...Command %s", oObj.Name);
  }  
  //USE INVENTORY ITEM/TACTICS ITEM ON OBJECT 5/5 
  else if (mouse.Mode == eModeUseinv)
  {
    Display("Active Inventory: %d", player.ActiveInventory.ID);
      //INVENTORY ITEM
      if (unhandledResponse_Obj == 0) Display("rand00 Inventory Item \"%s\" on object: %s", sActiveItem, oObj.Name);
      else if (unhandledResponse_Obj == 1) Display("Unhandled response...rand01 Inventory Item \"%s\" on object: %s", sActiveItem, oObj.Name);
      else if (unhandledResponse_Obj == 2) Display("Unhandled response...rand02 Inventory Item \"%s\" on object: %s", sActiveItem, oObj.Name);
      else if (unhandledResponse_Obj == 3) Display("Unhandled response...rand03 Inventory Item \"%s\" on object: %s", sActiveItem, oObj.Name);
      else if (unhandledResponse_Obj == 4) Display("Unhandled response...rand04 Inventory Item \"%s\" on object: %s", sActiveItem, oObj.Name);
      else if (unhandledResponse_Obj == 5) Display("Unhandled response...rand05 Inventory Item \"%s\" on object: %s", sActiveItem, oObj.Name);  
    }
  }  
}

--All that is necessary for evil to triumph is for good men to do nothing.

GarageGothic

Nah, no problem as long as you're fine with referring to them by ID number rather than script name. That's the only real difference. Personally I like room scripts because then at least I don't break the whole game if I mess up the code, plus it's a shorter script to troubleshoot.

Knox

Yeah that IS true though, shorter to debug later...Im going to have to think about this then a bit to make sure...but again, thanks for the help :)
--All that is necessary for evil to triumph is for good men to do nothing.

Knox

Sorry for the double-post, didnt want to create another topic:

Is a "void" faster or like more efficient than a function that doesnt return anything, but still named (wrongly), a function?

I heard somewhere that its better to rename your functions to "void" if it doesnt return anything because its "better"/faster...

If so, well Id like to pass through all my scripts and rename my returnless functions to voids...how do I know if those functions returns anything...is it safe to say that if I don't see "return blah;" somewhere in the function, I can rename the function to a void?
--All that is necessary for evil to triumph is for good men to do nothing.

GarageGothic

Possibly it's faster, but not to a degree you would notice. I think the main idea is that it's good coding practice to use "void" for functions that don't return a value. And as you said, if the function doesn't contain the word "return", it can safely be marked as void. And obviously don't check for any returned values from a void function (not that it would make any sense to have done so if it never returned anything in the first place) :).

SMF spam blocked by CleanTalk