Graal Forums  

Go Back   Graal Forums > Development Forums > NPC Scripting
FAQ Members List Calendar Today's Posts

Reply
 
Thread Tools Search this Thread Display Modes
  #1  
Old 01-11-2008, 05:11 PM
Novo Novo is offline
[TServerDeveloper]
Join Date: Jun 2006
Posts: 448
Novo will become famous soon enough
The MVC model!

To make a good NPC system (not merely a stand-alone project) requires a lot of practice. I myself tend to make several versions of the system: I personally have made more than a dozen MUD systems -- each time I was finished, I'd scratch it and started anew. The reasons were simple: As time went on, the complexity of the script becomes too high to actually progress any further.

There is a way to limit complexity, however! The MVC model is based on modularizing your compartments in your scripts. This approach dictates how you should go about.

As a way to show this, I'll be displaying my Item system that I've honed.

There are three compartments to any system. The (M)odel, the (V)isual, and the (C)ontrol. The Model is the system logic, in this example, the core item system... In simple terms, the primitive functions that work on a system. The Visuals, such as the inventory, communicates with the Control to get answers from the Model or other Visuals ( if need be ). In this example, we'll focus on the Model <=> Control <=> Visual. In no instance does the visual and model communicate directly! The Model and Visual are meant to be portable: You can change the system which they work with and still maintain them without problems. The Control, however, usually needs some reworking ( To fix the links between the model and visuals ).

We'll start by the foundations of the system -- The Model. In the Item system, it becomes pretty straightforward. To design the system, you would first ask what methods that the system would have. Suggestively, I would go by this:

PHP Code:
addItemitemIDquant );
removeItemitemIDquant );
hasItemitemID ); 
It's a start, but you might want to add other functions, such as getItemQuantity, setItemQuantity, setItemState, getItemState, hasItem... But for this presentation, we'll keep it simple.

To decide the primitives, I personally like the system where you have your dynamic variables and static variables separated. In this system, the items themselves don't change ( this minimizes the memory required to run the system ).

What I prefer, in this instance, is using player.clientr.items to define the item and its quantity, and player.clientr.item_[ITEMID] to define the item information.

An easy way to get this to work would be having a multi-dimensional array for the item information, thus, {itemID, QUANT}. Alternatively, you could have more information: {itemID, QUANT, STATE, POSITION, FORSALE }...

Something that I've been starting to do with these systems, especially for the item information, is using a mapped array. I define mapped array as an array of arrays whose structure is {key, value}, in this case... {{"itemID", itemID}, {"Quantity", QUANT}, {"State", STATE}, ...}

How this information is stored, however, is up to you. For sakes of minimizing the memory footprint, I'll use {itemID, quant}.

Once you have decided on the structure of the data, it is now time to do the nitty-gritty. This 'tutorial' isn't based on how you should proceed, so I won't go through why it is made as such:

PHP Code:
// Serverside
public function addItemitemIDquant )
{
  if ( 
quant )
    return;

  for ( 
0clientr.items.size(); ++)
  {
    if ( 
clientr.itemstemp.][ ] == itemID )
    {
      
clientr.itemstemp.][ ] += quant;
      return 
true;
    }
  }

  
clientr.items.add( { itemIDquant } );
  
clientr.(@"item_"itemID ) = ITEMINFORMATIONitemID );
  return 
true;
}

public function 
removeItemitemIDquant )
{
  if ( !
hasItemitemID ) )
    return 
false;

  for ( 
temp.0temp.clientr.items.size(); temp.++ )
  {
    if ( 
clientr.itemstemp.][ ] != itemID )
      continue;
    if ( 
clientr.itemstemp.][ ] > quant )
    {
      
clientr.itemstemp.][ ] -= quant;
    } else 
clientr.items.deletetemp.);

    return 
true;
  }

  return 
false;
}

public function 
hasItemitemID )
{
  for ( 
temp.0temp.clientr.items.size(); temp.++ )
  {
    if ( 
clientr.itemstemp.][ ] == itemID )
      return 
true;
  }
  return 
false;

Simple enough. So the next step... Because I hate doing visuals, I tend to do them last. Whether the Model or Visual is done first isn't important, but by the time you do Control, you need to know what you're working with.

So... The Control... The control in this scenario is based on the clientside, but this could work just as well on the serverside. In my Item control, I don't want the items to be manipulated. First, I would decide what the control would allow us to get... For simplicity sakes, I've decided on this control:

PHP Code:
getAllItems();
getItemQuantityitemID );
getItemPropitemIDpropName );
hasItemitemID ); 
It's relatively simple, but this could be extended further to getItemState( itemID ), setItemState( itemID, state ) (something I want edited ), placeItem( itemID, position ), getSelectedItem( itemType ), and anything else that you might find important.

So... To start, I'm going to work on what I know from my Model. The values that I have access to SHOULD ONLY BE ACCESSED HERE. In no instance should my Visual interact DIRECTLY with the values. For instance, instead of returning {itemID, QUANT, STATE, POSITION, etc }, I'll have functions that are designed to return each of the properties INDEPENDANTLY. This is vital to diminish the complexity for when you change the system ( add a new property, or convert the system to one that requires more information ).

PHP Code:
//#CLIENTSIDE
public function getAllItems()
{
  
temp.itemsID null;
  for ( 
temp.itemDataclientr.items )
    
temp.itemsID.addtemp.itemData[0] );

  return 
temp.itemsID;
}

public function 
getItemQuantityitemID )
{
  for ( 
temp.itemDataclientr.items )
  {
    if ( 
temp.itemData[0] == itemID )
      return 
temp.itemData[1];
  }

  return 
0;
}

public function 
getItemPropitemIDpropName )
{
  if ( !
hasItemitemID ) )
    return 
false;

  
temp.keyMap = {"itemId""stuff""OtherStuff"};
  
temp.keyIndex temp.keyMap.indexpropName );
  return 
clientr.(@"item_"itemID )[ temp.keyIndex ];  
}

public function 
hasItemitemID )
{
  for ( 
temp.itemDataclientr.items )
  {
    if ( 
temp.itemData] == itemID )
      return 
true;
  }

  return 
false;

So far, we got the Model and Control down pretty nice. These CAN change... When you do a change in the system, all you have to do is keep the function names the same. Like that the Visual doesn't change even if you change some rather deep system components. The Control would have to remap to the new primitive data types, but in general, everything should stay the same visually.

PHP Code:
//#CLIENTSIDE
function drawInv()
{
  
temp.items ItemControl.getAllItems();
  
temp.count 0;
  for ( 
temp.itemtemp.items )
  {
    
temp.itemName ItemControl.getItemProptemp.item"Name" );
    
temp.itemIcon ItemControl.getItemProptemp.item"Icon" );
//    temp.itemState = ItemControl.getItemState( temp.item );
    
temp.itemQuant ItemControl.getItemQuantitytemp.item );

    
temp.posX temp.count [MODdisplayWidth;
    
temp.posY inttemp.count displayWidth );

    
temp.img showimg( ... );
    
temp.img.layer 5;
    
// ...

    
temp.count ++;
  }

Once that is done... The system is over! The model and visual can change, but apart from the minor changes inside the Control, the other components don't change. This allows you to focus on what makes your server unique instead of always trying to find how something is connected to something else.

I hope this helps! If you want other non-technical help on scripting, I have posted guidelines on how to increase productivity here:

http://forums.graalonline.com/forums...ad.php?t=77413
Reply With Quote
  #2  
Old 01-11-2008, 10:22 PM
Dan Dan is offline
Daniel
Join Date: Oct 2007
Posts: 383
Dan is an unknown quantity at this point
Send a message via MSN to Dan
I dislike your styling, but I can tell these scripts might be useful for someone in need of a simple, yet effective, basic item system.
__________________
Reply With Quote
  #3  
Old 01-12-2008, 12:08 AM
Novo Novo is offline
[TServerDeveloper]
Join Date: Jun 2006
Posts: 448
Novo will become famous soon enough
Quote:
Originally Posted by Dan View Post
I dislike your styling, but I can tell these scripts might be useful for someone in need of a simple, yet effective, basic item system.
Have you even read what I wrote? ( In case you did: It doesn't mention styling nor is this a working item system. Stay on topic, please. Hint: It talks about the MVC model. )
Reply With Quote
  #4  
Old 01-12-2008, 01:38 AM
Twinny Twinny is offline
My empire of dirt
Twinny's Avatar
Join Date: Mar 2006
Location: Australia
Posts: 2,422
Twinny is just really niceTwinny is just really nice
Send a message via AIM to Twinny
Although I never made it official, I guess i've always coded like this: easy to upgrade the system the base-system without screwing over everything else
Reply With Quote
  #5  
Old 01-13-2008, 05:27 PM
Kristi Kristi is offline
Bowie's Deciple
Kristi's Avatar
Join Date: Dec 2003
Location: Boston, MA
Posts: 748
Kristi has a spectacular aura aboutKristi has a spectacular aura about
Send a message via AIM to Kristi Send a message via MSN to Kristi
Quote:
Originally Posted by Dan View Post
I dislike your styling, but I can tell these scripts might be useful for someone in need of a simple, yet effective, basic item system.
I think most the world dislikes yours!

That point being made though, neither of our comments had a place in this thread
__________________
Reply With Quote
  #6  
Old 01-13-2008, 07:10 PM
Codein Codein is offline
jwd
Codein's Avatar
Join Date: Oct 2005
Location: Greater Manchester
Posts: 2,423
Codein has a spectacular aura aboutCodein has a spectacular aura about
Send a message via AIM to Codein Send a message via MSN to Codein
I just read in my Computing handbook about the importance of modularisation. It's great to see how it'd be done in GScript
Reply With Quote
  #7  
Old 01-13-2008, 08:49 PM
Inverness Inverness is offline
Incubator
Inverness's Avatar
Join Date: Aug 2004
Location: Houston, Texas
Posts: 3,613
Inverness is a jewel in the roughInverness is a jewel in the rough
Modularization is good, but its made a bit harder by not being able to use catchevent() for dynamic events.
__________________
Reply With Quote
  #8  
Old 01-16-2008, 09:47 AM
Dan Dan is offline
Daniel
Join Date: Oct 2007
Posts: 383
Dan is an unknown quantity at this point
Send a message via MSN to Dan
My bad xP
__________________
Reply With Quote
  #9  
Old 01-16-2008, 03:48 PM
MrAnonymous_P2P MrAnonymous_P2P is offline
Retired Oldbie
MrAnonymous_P2P's Avatar
Join Date: Oct 2006
Location: Cambodia
Posts: 722
MrAnonymous_P2P is an unknown quantity at this point
Looks good to me
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 02:22 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2026, vBulletin Solutions Inc.
Copyright (C) 1998-2019 Toonslab All Rights Reserved.