Graal Forums  

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

 
 
Thread Tools Search this Thread Display Modes
Prev Previous Post   Next Post Next
  #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
 


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 03:40 PM.


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