src/tron/gParser.cpp

Go to the documentation of this file.
00001 #include "rSDL.h"
00002 
00003 #include "aa_config.h"
00004 
00005 #include "gParser.h"
00006 
00007 #include <math.h>
00008 #include <stdio.h>
00009 #include <stdlib.h>
00010 #include <string.h>
00011 #include <sys/types.h>
00012 #include <stdarg.h>
00013 #include <memory>
00014 
00015 #include "eCoord.h"
00016 #include "eGrid.h"
00017 #include "eTess2.h"
00018 #include "gWall.h"
00019 #include "gArena.h"
00020 #include "tMemManager.h"
00021 #include "tResourceManager.h"
00022 #include "tRecorder.h"
00023 #include "tConfiguration.h"
00024 #include "tPolynomial.h"
00025 #include "tPolynomialMarshaler.h"
00026 
00027 #include "gGame.h"
00028 
00029 #include "tConfiguration.h"
00030 #include "gGame.h"
00031 
00032 #ifdef ENABLE_ZONESV2
00033 #include <boost/tokenizer.hpp> // to support splitting a string on ","
00034 #include <boost/shared_ptr.hpp>
00035 #endif
00036 
00037 #include "gWinZone.h"
00038 
00039 #ifdef __MINGW32__
00040 #define xmlFree(x) free(x)
00041 #endif
00042 
00043 #if HAVE_LIBXML2_WO_PIBCREATE
00044 #       include "tDirectories.h"
00045 #endif
00046 
00047 #ifdef ENABLE_ZONESV2
00048 typedef std::map< string, zMonitorPtr > monitorMap;
00049 monitorMap monitors;
00050 
00051 typedef std::map< string, zZonePtr > zoneMap;
00052 zoneMap mapZones;
00053 
00054 #include "nNetObject.h"
00055 typedef std::map< string, nNetObjectID > MapIdToGameId;
00056 MapIdToGameId teamAsso; // mapping between map's teamId and in-game team
00057 MapIdToGameId playerAsso; // mapping between map's playerId and in-game player
00058 
00059 #include "nConfig.h"
00060 
00061 static bool polygonal_shape_used(false);
00062 static nSettingItemWatched<bool> safetymecanism_polygonal_shapeused("POLYGONAL_SHAPE_USED_EVER",polygonal_shape_used, nConfItemVersionWatcher::Group_Breaking, 20 );
00063 
00064 #endif
00065 int mapVersion = 0; // The version of the map currently being parsed. Used to adapt parsing to support version specific features
00066 
00068 static void sg_Deprecated()
00069 {
00070     // no use informing players on the client, they can't do anything about it anyway
00071     if ( sn_GetNetState() != nCLIENT )
00072         con << "\n\n" << tColoredString::ColorString(1,.3,.3) << "WARNING: You are loading a map that is written in a deprecated format. It should work for now, but will stop to do so in one of the next releases. Have the map upgraded to an up-to-date version as soon as possible.\n\n";
00073 }
00074 
00075 #ifdef DEBUG_ZONE_SYNC
00076 // This code is to attempt to synchronize moving zones on the client and server
00077 // It just doesnt work ATM, nor it is close to any solution.
00078 static bool newGameRound; // Indicate that a round has just started when true (no not really, a bad approximation)
00079 
00080 // the following crash on the server as soon as the player being monitored dies!!!!
00081 float tSysTimeHack2(float x)
00082 {
00083     int playerID = sr_viewportBelongsToPlayer[ 0 ];
00084     // get the player
00085     ePlayer* player = ePlayer::PlayerConfig( playerID );
00086 
00087     float asdf = player->netPlayer->ping;
00088 
00089     static float basePing;
00090     // preserve basePing only at the start of a new round
00091     if (newGameRound == true) {
00092         newGameRound = false;
00093         basePing = asdf;
00094     }
00095 
00096     return static_cast<float> (tSysTimeFloat() /*+ (player->netPlayer->ping*2)*/ + basePing/2);
00097 }
00098 #endif // DEBUG_ZONE_SYNC
00099 
00100 gParser::gParser(gArena *anArena, eGrid *aGrid):
00101         theArena(anArena),
00102         theGrid(aGrid),
00103         rimTexture(0),
00104         sizeMultiplier(0.0)
00105 {
00106     m_Doc = NULL;
00107 
00108     // HACK - philippeqc
00109     // This seems as inconvenient as any other place to load the
00110     // static tables of variables and functions available.
00111     // It's run once per map loading, between round, so its basically
00112     // cost less vs the real structural mess that it cause ;)
00113 
00114     //  vars[tString("sizeMultiplier")] = &sizeMultiplier; // BAD dont use other than as an example, non static content
00115 
00116     //    tValue::Expr::functions[tString("time")] = &tSysTimeHack;
00117 #ifdef DEBUG_ZONE_SYNC
00118     tValue::Expr::functions[tString("time2")] = &tSysTimeHack2;
00119 #endif //DEBUG_ZONE_SYNC
00120     //    tValue::Expr::functions[tString("sizeMultiplier")] = &gArena::GetSizeMultiplierHack; // static
00121 
00122 }
00123 
00124 bool
00125 gParser::trueOrFalse(char *str)
00126 {
00127     // This will work with true/false/yes/no/1/-1/0/etc
00128     return (!strncasecmp(str, "t", 1) || !strncasecmp(str, "y", 1) || atoi(str));
00129 }
00130 
00131 char *
00132 gParser::myxmlGetProp(xmlNodePtr cur, const char *name) {
00133     return (char *)xmlGetProp(cur, (const xmlChar *)name);
00134 }
00135 
00136 int
00137 gParser::myxmlGetPropInt(xmlNodePtr cur, const char *name) {
00138     char *v = myxmlGetProp(cur, name);
00139     if (v == NULL)      return 0;
00140     int r = atoi(v);
00141     xmlFree(v);
00142     return r;
00143 }
00144 
00145 #ifdef ENABLE_ZONESV2
00146 rColor
00147 gParser::myxmlGetPropColorFromHex(xmlNodePtr cur, const char *name) {
00148     char *v = myxmlGetProp(cur, name);
00149     if (v == NULL)      return rColor();
00150     int r = strtoul(v, NULL, 0);
00151     rColor aColor;
00152     if (strlen(v) >= 9) {
00153         aColor.a_ = ((REAL)(r & 255)) / 255.0;
00154         r /= 256;
00155         if (aColor.a_ > 0.7)
00156             aColor.a_ = 0.7;
00157     }
00158     else {
00159         aColor.a_ = 0.7;
00160     }
00161     aColor.b_ = ((REAL)(r & 255)) / 255.0;
00162     r /= 256;
00163     aColor.g_ = ((REAL)(r & 255)) / 255.0;
00164     r /= 256;
00165     aColor.r_ = ((REAL)(r & 255)) / 255.0;
00166     r /= 256;
00167 
00168     xmlFree(v);
00169     return aColor;
00170 }
00171 #endif
00172 
00173 float
00174 gParser::myxmlGetPropFloat(xmlNodePtr cur, const char *name) {
00175     char *v = myxmlGetProp(cur, name);
00176     if (v == NULL)      return 0.;
00177     float r = atof(v);
00178     xmlFree(v);
00179     return r;
00180 }
00181 
00182 bool
00183 gParser::myxmlGetPropBool(xmlNodePtr cur, const char *name) {
00184     char *v = myxmlGetProp(cur, name);
00185     if (v == NULL)      return false;
00186     bool r = trueOrFalse(v);
00187     xmlFree(v);
00188     return r;
00189 }
00190 
00191 #ifdef ENABLE_ZONESV2
00192 Triad
00193 gParser::myxmlGetPropTriad(xmlNodePtr cur, const char *name) {
00194     Triad res = _ignore;
00195     char *v = myxmlGetProp(cur, name);
00196     if (v == NULL)           res = _false;
00197     else if (strcmp(v, "true")==0)  res = _true;
00198     else if (strcmp(v, "false")==0) res = _false;
00199 
00200     xmlFree(v);
00201     return res;
00202 }
00203 #endif
00204 
00205 #define myxmlHasProp(cur, name) xmlHasProp(cur, reinterpret_cast<const xmlChar *>(name))
00206 
00207 /*
00208  * Determine if elementName is the same as searchedElement, or any of its valid syntax.
00209  * Anything sharing the same start counts as a valid syntax. This allow for variation
00210  * on the name to reduce DTD conflicts.
00211  */
00212 bool
00213 gParser::isElement(const xmlChar *elementName, const xmlChar *searchedElement, const xmlChar * keyword) {
00214     bool valid = false;
00215     if (xmlStrcmp(elementName, searchedElement) == 0) {
00216         valid = true;
00217     }
00218     else {
00219         if (keyword != NULL) {
00220             xmlChar * searchedElementAndKeyword = xmlStrdup(searchedElement);
00221             searchedElementAndKeyword = xmlStrcat(searchedElementAndKeyword, keyword);
00222             if (xmlStrcmp(elementName, searchedElementAndKeyword) == 0) {
00223                 valid = true;
00224             }
00225             xmlFree (searchedElementAndKeyword);
00226         }
00227     }
00228 
00229     return valid;
00230 }
00231 
00232 /*
00233  * Determine if this is an alternative for us. To be an alternative for us, the
00234  * current element's name must starts with Alternative, and the version attribute
00235  * has a version that is ours ("Arthemis", "0.2.8" or "0_2_8"). If both conditions
00236  * are met, it return true.
00237  */
00238 bool
00239 gParser::isValidAlternative(xmlNodePtr cur, const xmlChar * keyword) {
00240     xmlChar *version = xmlGetProp(cur, (const xmlChar *) "version");
00241     /*
00242      * Find non empty version and
00243      * Alternative element, ie those having a name starting by "Alternative" and
00244      * only the Alternative elements that are for our version, ie Arthemis
00245      */
00246     return ((version != NULL) && isElement(cur->name, (const xmlChar *)"Alternative", keyword) && validateVersionRange(version, (const xmlChar*)"Artemis", (const xmlChar*)"0.2.8.0") );
00247 }
00248 
00249 bool
00250 gParser::isValidCodeName(const xmlChar *version)
00251 {
00252     const int NUMBER_NAMES = 24;
00253     xmlChar const *const names [] = { (const xmlChar*) "Artemis", (const xmlChar*) "Bachus", (const xmlChar*) "Cronus", (const xmlChar*) "Demeter", (const xmlChar*) "Epimetheus", (const xmlChar*) "Furiae", (const xmlChar*) "Gaia", (const xmlChar*) "Hades", (const xmlChar*) "Iapetos", (const xmlChar*) "Juno", (const xmlChar*) "Koios", (const xmlChar*) "Leto", (const xmlChar*) "Mars", (const xmlChar*) "Neptune", (const xmlChar*) "Okeanos", (const xmlChar*) "Prometheus", (const xmlChar*) "Rheia", (const xmlChar*) "Selene", (const xmlChar*) "Thanatos", (const xmlChar*) "Uranus", (const xmlChar*) "Vulcan", (const xmlChar*) "Wodan", (const xmlChar*) "Yggdrasil", (const xmlChar*) "Zeus"};
00254     /* Is is a valid codename*/
00255     int i;
00256     for (i=0; i<NUMBER_NAMES; i++)
00257     {
00258         if (xmlStrcmp(version, names[i]) == 0)
00259             return true;
00260     }
00261 
00262     return false;
00263 }
00264 
00265 bool
00266 gParser::isValidDotNumber(const xmlChar *version)
00267 {
00268     char * work = (char *) xmlStrdup(version);
00269     char * start = work;
00270     char * end = work;
00271     bool valid = false;
00272     /* Check that we have at least i.j.k.xxx */
00273     for (int i=0; i<3; i++)
00274     {
00275         strtol(start, &end, 10);
00276         if (start != end) {
00277             valid = true;
00278             start = end +1;
00279         }
00280         else {
00281             valid = false;
00282             break;
00283         }
00284     }
00285     xmlFree(work);
00286     return valid;
00287 }
00288 
00289 /* Are we within a range */
00290 bool
00291 gParser::validateVersionSubRange(const xmlChar *subRange, const xmlChar *codeName, const xmlChar *dotVersion)
00292 {
00293     bool valid = false;
00294     int posDelimiter = xmlUTF8Strloc(subRange, (const xmlChar *) "-");
00295     if (posDelimiter != -1)
00296     {
00297         xmlChar * pre = xmlUTF8Strsub(subRange, 0, posDelimiter);
00298         xmlChar * post = xmlUTF8Strsub(subRange, posDelimiter + 1, xmlUTF8Strlen(subRange) - posDelimiter - 1 );
00299 
00300         if (xmlStrlen(pre) == 0)
00301             /* The range is of type <empty>-<something>, so we pass the first part */
00302             valid = true;
00303         else
00304         {
00305             if (isValidCodeName(pre))
00306                 valid = ( xmlStrcmp(pre, codeName) <= 0 );
00307             else if (isValidDotNumber(pre))
00308                 valid = ( xmlStrcmp(pre, dotVersion) <= 0 );
00309         }
00310 
00311         if (xmlStrlen(post) == 0)
00312             /* Reject ranges of types <something>-<empty>*/
00313             valid = true;
00314         else
00315         {
00316             if (isValidCodeName(post))
00317                 valid &= ( xmlStrcmp(post, codeName) >= 0 );
00318             else if (isValidDotNumber(post))
00319                 valid &= ( xmlStrcmp(post, dotVersion) >= 0 );
00320         }
00321     }
00322     else
00323     {
00324         if (isValidCodeName(subRange))
00325             valid = ( xmlStrcmp(subRange, codeName) == 0 );
00326         else if (isValidDotNumber(subRange))
00327             valid = ( xmlStrcmp(subRange, dotVersion) == 0 );
00328     }
00329 
00330     return valid;
00331 }
00332 
00333 /*
00334  * Substitute a xmlChar string searchPattern to a xmlChar string replacePattern
00335  */
00336 bool
00337 gParser::xmlCharSearchReplace(xmlChar *&original, const xmlChar * searchPattern, const xmlChar * replace)
00338 {
00339     int pos;
00340 
00341     int lenSearchPattern = xmlUTF8Strlen(searchPattern); /* number of character */
00342     int sizeSearchPattern = xmlUTF8Strsize(searchPattern, lenSearchPattern); /* number of bytes required*/
00343 
00344     /* Ugly hack as many function are lacking in string manipulation for xmlChar * */
00345     /* xmlUTF8Strloc can only find the location of a single character, and no xmlUTF8Str... function
00346        can return the location of a string in character position */
00347     /* We are looking for the first instance searchPattern and want its position in character */
00348     for (pos=0; pos<xmlUTF8Strlen(original); pos++)
00349     {
00350         if ( xmlStrncmp( xmlUTF8Strpos(original, pos), searchPattern, sizeSearchPattern) == 0 )
00351         {
00352             int count = xmlUTF8Strlen(original);
00353             xmlChar * pre = xmlUTF8Strsub(original, 0, pos);
00354             xmlChar * post = xmlUTF8Strsub(original, pos + lenSearchPattern, count - pos - lenSearchPattern );
00355 
00356             xmlFree(original);
00357             pre = xmlStrcat ( pre, replace);
00358             original = xmlStrcat ( pre, post );
00359             xmlFree(post);
00360             return true;
00361         }
00362     }
00363 
00364     return false;
00365 }
00366 
00367 
00368 /*Separates all the comma delimited ranges*/
00369 int
00370 gParser::validateVersionRange(xmlChar *version, const xmlChar * codeName, const xmlChar * dotVersion)
00371 {
00372     xmlChar * copy = xmlStrdup(version);
00373 
00374     /* We allow numerical version to be expressed with . or _, cut down one to simplify treatment */
00375     while ( xmlCharSearchReplace(copy, (const xmlChar *) "_", (const xmlChar *) ".") ) {} ;
00376 
00377     /* Eliminate all the white space */
00378     while ( xmlCharSearchReplace(copy, (const xmlChar *) " ", (const xmlChar *) "") ) {} ;
00379 
00380     xmlChar * remain = copy;
00381     bool valid = false;
00382     int pos=0;
00383     while (xmlStrlen(remain) && valid == false)
00384     {
00385         if ( ( pos = xmlUTF8Strloc(remain, (const xmlChar *) ",")) == -1)
00386         {
00387             /* This is the last sub-range to explore */
00388             pos = xmlUTF8Strlen(remain);
00389         }
00390         xmlChar * subRange = xmlUTF8Strndup(remain, pos);
00391 
00392         /* Is the current version in the presented range */
00393         valid |= validateVersionSubRange(subRange, codeName, dotVersion);
00394         xmlFree(subRange);
00395 
00396         /* Move away from the zone explored*/
00397         remain = const_cast<xmlChar *>( xmlUTF8Strpos(remain, pos + 1) );
00398     }
00399 
00400     xmlFree(copy);
00401     return valid;
00402 }
00403 
00404 /*
00405  * This method allows for elements that are at the bottom of the
00406  * hierarchy, such as Spawn, Point, Setting and Axis, to verify if sub element
00407  * havent been added in future version(s)
00408  */
00409 void
00410 gParser::endElementAlternative(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword) {
00411     /* Verify if any sub elements are included, and if they contain any Alt
00412        Sub elements of Spawn arent defined in the current version*/
00413     cur = cur->xmlChildrenNode;
00414     while ( cur != NULL) {
00415         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
00416         else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
00417             if (isValidAlternative(cur, keyword)) {
00418                 parseAlternativeContent(grid, cur);
00419             }
00420         }
00421         cur = cur->next;
00422     }
00423 }
00424 
00425 void
00426 gParser::myxmlGetDirection(xmlNodePtr cur, float &x, float &y)
00427 {
00428     if (myxmlHasProp(cur, "angle")) {
00429         float angle = myxmlGetPropFloat(cur, "angle") * M_PI / 180.0;
00430         float speed = myxmlGetPropFloat(cur, "length");
00431         x = cosf(angle) * speed;
00432         y = sinf(angle) * speed;
00433     } else {
00434         x = myxmlGetPropFloat(cur, "xdir");
00435         y = myxmlGetPropFloat(cur, "ydir");
00436     }
00437 }
00438 
00439 void
00440 gParser::parseAxes(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword)
00441 {
00442     int number;
00443     int normalize;
00444 
00445     number = myxmlGetPropInt(cur, "number");
00446     if (number < 1)
00447         return; // 1 axis is one-way. Keep it.
00448 
00449     normalize = myxmlGetPropBool(cur, "normalize");
00450 
00451     grid->SetWinding(number);
00452 
00453     cur = cur->xmlChildrenNode;
00454     if (cur != NULL)
00455     {
00456         int index = 0;
00457         eCoord *axisDir;
00458         axisDir = (eCoord *)malloc(sizeof(eCoord) * number);
00459         for (int i=0; i<number; i++){
00460             axisDir[i] = eCoord(1,0);
00461         }
00462 
00463         while (cur!= NULL) {
00464             if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
00465             else if (isElement(cur->name, (const xmlChar *)"Axis", keyword)) {
00466                 if (index < number) {
00467                     myxmlGetDirection(cur, axisDir[index].x, axisDir[index].y);
00468                     index++;
00469                 }
00470                 else {
00471                     con << "Invalid index #" << index << "\n";
00472                 }
00473                 /* Verify if any sub elements are included, and if they contain any Alt
00474                    Sub elements of Point arent defined in the current version*/
00475                 endElementAlternative(grid, cur, keyword);
00476             }
00477             else if (isElement(cur->name, (const xmlChar *)"Point", keyword)) {
00478                 if (index < number) {
00479                     axisDir[index].x = myxmlGetPropFloat(cur, "x");
00480                     axisDir[index].y = myxmlGetPropFloat(cur, "y");
00481                     index++;
00482                 }
00483                 else {
00484                     con << "Invalid index #" << index << "\n";
00485                 }
00486                 /* Verify if any sub elements are included, and if they contain any Alt
00487                    Sub elements of Point arent defined in the current version*/
00488                 endElementAlternative(grid, cur, keyword);
00489             }
00490             else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
00491                 if (isValidAlternative(cur, keyword)) {
00492                     parseAlternativeContent(grid, cur);
00493                 }
00494             }
00495             cur = cur->next;
00496         }
00497         grid->SetWinding(number, axisDir, normalize);
00498         free(axisDir);
00499     }
00500 }
00501 
00502 void
00503 gParser::parseSpawn(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword)
00504 {
00505     float x, y, xdir, ydir;
00506 
00507     x = myxmlGetPropFloat(cur, "x");
00508     y = myxmlGetPropFloat(cur, "y");
00509     myxmlGetDirection(cur, xdir, ydir);
00510 
00511     theArena->NewSpawnPoint(eCoord(x, y), eCoord(xdir, ydir));
00512 
00513     endElementAlternative(grid, cur, keyword);
00514 }
00515 
00516 #ifdef ENABLE_ZONESV2
00517 /*
00518   Extract all the color codes and build a rColor object.
00519   Return: a rColor object.
00520 
00521  */
00522 rColor
00523 gParser::parseColor(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword)
00524 {
00525     rColor color;
00526     color.r_ = myxmlGetPropFloat(cur, "red");
00527     color.g_ = myxmlGetPropFloat(cur, "green");
00528     color.b_ = myxmlGetPropFloat(cur, "blue");
00529     color.a_ = myxmlGetPropFloat(cur, "alpha");
00530 
00531     if (myxmlHasProp(cur, "hexCode"))
00532     {
00533         color = myxmlGetPropColorFromHex(cur, "hexCode");
00534     }
00535 
00536     if (color.a_ > 1.0)
00537         color.a_ = 1.0;
00538     if (color.a_ < 0.0)
00539         color.a_ = 0.0;
00540 
00541 
00542     /*
00543     if(myxmlHasProp(cur, "name") {
00544       string colorName = myxmlGetProp(cur, "name");
00545       
00546     }
00547     */
00548 
00549 
00550     /*
00551 
00552 
00553     // Blue
00554 
00555     0xf0f8ff alice,
00556     0x007fff azure,
00557     0x007ba7 cerulean,
00558     0x0047ab cobalt
00559     0x6495ed cornflower
00560     0x0000c8 dark
00561     0x1560bd denim
00562     0x1e90ff dodger
00563     0x4b0082 indigo
00564     0x002fa7 internationalklein
00565     0xbdbbd7 lavender
00566     0x003366 midnight
00567     0x000080 navy
00568     0xccccff periwinkle
00569     0x32127a persian
00570     0x003399 powder
00571     0x003153 prussian
00572     0x4169e1 royal
00573     0x082567 sapphire
00574     0x4682b4 steel
00575     0x120a8f ultramarine
00576 
00577 
00578 
00579     // RED
00580 
00581     0xe32636 alizarin,
00582     0x800020 burgundy,
00583     0xc41e3a cardinal,
00584     0x960018 carmine,
00585     0xde3163 cerise
00586     0xcd5c5c chestnut
00587     0xdc143c crimson
00588     0x801818 falu
00589     0xff00ff fuchsia
00590     0xff0090 magenta
00591     0x800000 maroon
00592     0x993366 mauve
00593     0xc71585 red-violet
00594     0xb7410e rust
00595     0xcc8899 puce
00596     0x92000a sangria
00597     0xff2400 scarlet
00598     0xe2725b terracotta
00599     0xcc4e5c darkterracotta
00600     0xe34234 vermilion
00601     */
00602 
00603     return color;
00604 }
00605 
00606 zShapePtr
00607 gParser::parseShapeCircleArthemis(eGrid *grid, xmlNodePtr cur, unsigned short idZone, const xmlChar * keyword)
00608 {
00609     zShapePtr shape = zShapePtr( new zShapeCircle(grid, idZone) );
00610 
00611     // Build up the scale information
00612     {
00613         tFunction tfScale;
00614         tfScale.SetOffset( myxmlGetPropFloat(cur, "radius") * sizeMultiplier );
00615         tfScale.SetSlope( myxmlGetPropFloat(cur, "growth") * sizeMultiplier );
00616         shape->setScale( tfScale );
00617     }
00618 
00619     // Set up the default rotation speed
00620     {
00621         tPolynomial<nMessage> tpRotation(2);
00622         tpRotation[0] = 0.0f;
00623         tpRotation[1] = .3f;
00624         shape->setRotation2( tpRotation );
00625     }
00626 
00627     // Set up the location
00628     cur = cur->xmlChildrenNode;
00629     while ( cur != NULL) {
00630         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
00631         else if (isElement(cur->name, (const xmlChar *)"Point", keyword)) {
00632             REAL x = myxmlGetPropFloat(cur, "x");
00633             REAL y = myxmlGetPropFloat(cur, "y");
00634 
00635             tFunction tfPos;
00636             tfPos.SetOffset( x * sizeMultiplier );
00637             shape->setPosX( tfPos );
00638 
00639             tfPos.SetOffset( y * sizeMultiplier );
00640             shape->setPosY( tfPos );
00641 
00642             endElementAlternative(grid, cur, keyword);
00643         }
00644         else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
00645             if (isValidAlternative(cur, keyword)) {
00646                 parseAlternativeContent(grid, cur);
00647             }
00648         }
00649         cur = cur->next;
00650     }
00651     return shape;
00652 }
00653 
00654 zShapePtr
00655 gParser::parseShapeCircleBachus(eGrid *grid, xmlNodePtr cur, unsigned short idZone, const xmlChar * keyword)
00656 {
00657     zShapeCircle *shapePtr = new zShapeCircle(grid, idZone) ;
00658 
00659     // The radius need to be handled separatly
00660     tFunction tfRadius;
00661     if (myxmlHasProp(cur, "radius")) {
00662         string str = string(myxmlGetProp(cur, "radius"));
00663         myCheapParameterSplitter(str, tfRadius, true);
00664     }
00665     else {
00666         tfRadius.SetOffset( 1.0 * sizeMultiplier );
00667         tfRadius.SetSlope( 0.0 );
00668     }
00669     shapePtr->setRadius( tfRadius );
00670 
00671     zShapePtr shape = zShapePtr( shapePtr );
00672 
00673     parseShape(grid, cur, keyword, shape);
00674 
00675     return shape;
00676 }
00677 
00678 zShapePtr
00679 gParser::parseShapePolygon(eGrid *grid, xmlNodePtr cur, unsigned short idZone, const xmlChar * keyword)
00680 {
00681     // Polygon shapes are not supported by older clients.
00682     // Yes, it is on purpose that this item is set and never reset once polygonial shapes
00683     // are used. That way, a single map with polygonial shapes in the rotation will
00684     // lock out old clients for good. We can remove this only when we have a compatibility
00685     // plan for polygonial shapes, probably never.
00686     safetymecanism_polygonal_shapeused.Set(true);
00687 
00688     zShapePtr shape = zShapePtr( new zShapePolygon(grid, idZone) );
00689     parseShape(grid, cur, keyword, shape);
00690 
00691     return shape;
00692 }
00693 
00694 // Quick stub to allow to operate on tFunction
00695 // Remove when all that is variant has been ported to ruby
00696 void gParser::myCheapParameterSplitter(const string &str, tFunction &tf, bool addSizeMultiplier)
00697 {
00698     REAL param[2] = {0.0, 0.0};
00699     int bPos;
00700     if ( (bPos = str.find(';')) != -1)
00701     {
00702         param[0] = atof(str.substr(0, bPos).c_str());
00703         param[1] = atof(str.substr(bPos + 1, str.length()).c_str());
00704     }
00705     else
00706     {
00707         param[0] = atof(str.c_str());
00708     }
00709 
00710     if (addSizeMultiplier)
00711     {
00712         param[0] = param[0] * sizeMultiplier;
00713         param[1] = param[1] * sizeMultiplier;
00714     }
00715     tf.SetOffset(param[0]);
00716     tf.SetSlope(param[1]);
00717 }
00718 
00719 void
00720 gParser::parseShape(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword, zShapePtr &shape)
00721 {
00722     tValue::BasePtr xp;
00723     tValue::BasePtr yp;
00724     bool centerLocationFound = false;
00725 
00726     if (myxmlHasProp(cur, "scale")) {
00727         string str = string(myxmlGetProp(cur, "scale"));
00728         tFunction tfScale;
00729 
00730         myCheapParameterSplitter(str, tfScale, false);
00731         shape->setScale( tfScale );
00732     }
00733 
00734     if (myxmlHasProp(cur, "rotation")) {
00735         string str = string(myxmlGetProp(cur, "rotation"));
00736         tPolynomial<nMessage> tpRotation;
00737 
00738         tpRotation.parse(str);
00739         shape->setRotation2( tpRotation );
00740     }
00741 
00742     cur = cur->xmlChildrenNode;
00743     while ( cur != NULL) {
00744         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
00745         else if (isElement(cur->name, (const xmlChar *)"Point", keyword)) {
00746             /* We need to multipy by sizeMultiper so the item are properly placed*/
00747             string strX = string(myxmlGetProp(cur, "x"));
00748             tFunction tfX;
00749             myCheapParameterSplitter(strX, tfX, true);
00750             string strY = string(myxmlGetProp(cur, "y"));
00751             tFunction tfY;
00752             myCheapParameterSplitter(strY, tfY, true);
00753 
00754             if (centerLocationFound == false) {
00755                 shape->setPosX( tfX );
00756                 shape->setPosY( tfY );
00757                 centerLocationFound = true;
00758             }
00759             else {
00760                 zShapePolygon *tmpShapePolygon = dynamic_cast<zShapePolygon *>( (zShape*)shape );
00761                 if (tmpShapePolygon)
00762                     tmpShapePolygon->addPoint( myPoint( tfX, tfY ) );
00763             }
00764 
00765             endElementAlternative(grid, cur, keyword);
00766         }
00767 
00768         else if (isElement(cur->name, (const xmlChar *)"Color", keyword)) {
00769             shape->setColor( parseColor(grid, cur, keyword) );
00770 
00771             endElementAlternative(grid, cur, keyword);
00772         }
00773         else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
00774             if (isValidAlternative(cur, keyword)) {
00775                 parseAlternativeContent(grid, cur);
00776             }
00777         }
00778         cur = cur->next;
00779     }
00780 }
00781 
00782 zZoneInfluencePtr
00783 gParser::parseZoneEffectGroupZone(eGrid * grid, xmlNodePtr cur, const xmlChar * keyword) {
00784     string zoneName(myxmlGetProp(cur, "name"));
00785     zZoneInfluencePtr infl;
00786     zZonePtr refZone;
00787 
00788     // Does the zone to be monitored is already registered
00789     zoneMap::const_iterator iterZone;
00790     if ((iterZone = mapZones.find(zoneName)) != mapZones.end()) {
00791         // load the zone
00792         refZone = iterZone->second;
00793     }
00794     else {
00795         // make an empty zone and store under the right label
00796         // It should be populated later
00797 
00798         //  refZone = zZonePtr(new zZone(grid));
00799         refZone = tNEW(zZone)(grid);
00800         if (!zoneName.empty())
00801             mapZones[zoneName] = refZone;
00802     }
00803     infl = zZoneInfluencePtr(new zZoneInfluence(refZone));
00804 
00805     cur = cur->xmlChildrenNode;
00806     while ( cur != NULL) {
00807         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
00808         else if (isElement(cur->name, (const xmlChar *)"Rotation", keyword)) {
00809             zZoneInfluenceItemRotation *b = new zZoneInfluenceItemRotation(refZone);
00810 
00811             tPolynomialMarshaler<nMessage> tpm;
00812 
00813             std::cout << "about to read a rotation " << std::endl;
00814             if( myxmlHasProp(cur, "rotation") ) {
00815               // new notation, superseed the previous notation
00816               string str = string(myxmlGetProp(cur, "rotation"));
00817 
00818               tpm.parse(str);
00819             }
00820             else {
00821               // read the parameters from the old notation
00822               string str = string(myxmlGetProp(cur, "rotationAngle"));
00823               tPolynomial<nMessage> tpRotationAngle(str);
00824 
00825               str = string(myxmlGetProp(cur, "rotationSpeed"));
00826               tPolynomial<nMessage> tpRotationSpeed(str);
00827 
00828               // generate the equivalent polynomial marsaller
00829               tpm.setConstant(tpRotationAngle);
00830               tpm.setVariant(tpRotationSpeed);
00831 
00832               sg_Deprecated();
00833             }
00834 
00835             std::cout << "rotation read " << std::endl;
00836             b->set(tpm);
00837 
00838             infl->addZoneInfluenceRule(zZoneInfluenceItemPtr(b));
00839         }
00840         else if (isElement(cur->name, (const xmlChar *)"Scale", keyword)) {
00841             zZoneInfluenceItemScale *b = new zZoneInfluenceItemScale(refZone);
00842             b->set(myxmlGetPropFloat(cur, "scale") *sizeMultiplier);
00843             infl->addZoneInfluenceRule(zZoneInfluenceItemPtr(b));
00844         }
00845         else if (isElement(cur->name, (const xmlChar *)"Color", keyword)) {
00846             zZoneInfluenceItemColor *b = new zZoneInfluenceItemColor(refZone);
00847             b->set(parseColor(grid, cur, keyword));
00848             infl->addZoneInfluenceRule(zZoneInfluenceItemPtr(b));
00849         }
00850         else if (isElement(cur->name, (const xmlChar *)"Point", keyword)) {
00851             /* We need to multipy by sizeMultiper so the item are properly placed*/
00852             REAL x = myxmlGetPropFloat(cur, "x") *sizeMultiplier;
00853             REAL y = myxmlGetPropFloat(cur, "y") *sizeMultiplier;
00854             zZoneInfluenceItemPosition *b = new zZoneInfluenceItemPosition(refZone);
00855             b->set( eCoord(x, y) );
00856             infl->addZoneInfluenceRule(zZoneInfluenceItemPtr(b));
00857 
00858             endElementAlternative(grid, cur, keyword);
00859         }
00860         else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
00861             if (isValidAlternative(cur, keyword)) {
00862                 parseAlternativeContent(grid, cur);
00863             }
00864         }
00865         cur = cur->next;
00866     }
00867 
00868 
00869     return infl;
00870 }
00871 
00872 zMonitorInfluencePtr
00873 gParser::parseZoneEffectGroupMonitor(eGrid * grid, xmlNodePtr cur, const xmlChar * keyword) {
00874     string monitorName(myxmlGetProp(cur, "name"));
00875 
00876     zMonitorPtr ref;
00877     // Find the associated monitor
00878 
00879     monitorMap::const_iterator iterMonitor;
00880     // associate the label to the proper effector
00881     if ((iterMonitor = monitors.find(monitorName)) != monitors.end()) {
00882         ref = iterMonitor->second;
00883     }
00884     else {
00885         // make an empty zone and store under the right label
00886         // It should be populated later
00887         ref = zMonitorPtr(new zMonitor(grid));
00888         if (!monitorName.empty()) {
00889             monitors[monitorName] = ref;
00890             ref->setName(monitorName);
00891         }
00892     }
00893 
00894     zMonitorInfluencePtr infl = zMonitorInfluencePtr(new zMonitorInfluence(ref));
00895     infl->setMarked(myxmlGetPropTriad(cur, "marked"));
00896 
00897     tPolynomialMarshaler<nMessage> tpmInfluence;
00898 
00899     if (myxmlHasProp(cur, (const xmlChar*)"influence")) {
00900         // new notation, superseed the previous notation
00901         string str = string(myxmlGetProp(cur, "influence"));
00902         tpmInfluence.parse(str);
00903     }
00904     else {
00905       tPolynomial<nMessage> tpInfluenceConstant;
00906       tPolynomial<nMessage> tpInfluenceVariant;
00907       if(myxmlHasProp(cur, "influenceAdd")) {
00908         tpInfluenceConstant.parse( string(myxmlGetProp(cur, "influenceAdd")) );
00909       }
00910       if(myxmlHasProp(cur, "influenceSlide")) {
00911         tpInfluenceVariant.parse( string(myxmlGetProp(cur, "influenceSlide")) );
00912       }
00913 
00914       /*
00915       if (xmlHasProp(cur, (const xmlChar *)"influenceSet")) {
00916         string str = string(myxmlGetProp(cur, "influenceSet"));
00917         tFunction tfInfluence;
00918         myCheapParameterSplitter(str, tfInfluence, false);
00919         infl->setInfluenceSet( tfInfluence );
00920       }
00921       */
00922 
00923       tpmInfluence.setConstant(tpInfluenceConstant);
00924       tpmInfluence.setVariant(tpInfluenceVariant);
00925 
00926       sg_Deprecated();
00927     }
00928     std::cout << "influence read" << std::endl;
00929 
00930     infl->setInfluence( tpmInfluence );
00931 
00932     return infl;
00933 }
00934 
00935 zEffectorPtr
00936 gParser::parseZoneEffectGroupEffector(eGrid * grid, xmlNodePtr cur, const xmlChar * keyword) {
00937     zEffectorPtr effector;
00938     /*
00939       build the effect, in this case give points to the target(s)
00940     */
00941     typedef zEffector* (*effectorFactory)();
00942     std::map<tString, effectorFactory> effectors;
00943     // Build the list of supported effector
00944     effectors[tString("win")] = zEffectorWin::create;
00945     effectors[tString("death")] = zEffectorDeath::create;
00946     effectors[tString("point")] = zEffectorPoint::create;
00947 
00948     /*
00949       effectors[tString("event")] = zEffectorEvent::create;
00950       effectors[tString("cleartrace")] = zEffectorClearrace::create;
00951       effectors[tString("teleport")] = zEffectorTeleport::create;
00952     */
00953     effectors[tString("spawnplayer")] = zEffectorSpawnPlayer::create;
00954     effectors[tString("brakerecharge")] = zEffectorCycleBrake::create;
00955     effectors[tString("rubberrecharge")] = zEffectorCycleRubber::create;
00956     effectors[tString("acceleration")] = zEffectorCycleAcceleration::create;
00957     effectors[tString("setting")] = zEffectorSetting::create;
00958 
00959 
00960     // TODO: add tolower()
00961     // Get the label of the effector to be used
00962     string effectorAttribute( myxmlGetProp(cur, "effect"));
00963     transform (effectorAttribute.begin(), effectorAttribute.end(), effectorAttribute.begin(), tolower);
00964     std::map<tString, effectorFactory>::const_iterator iterEffectorFactory;
00965     // associate the label to the proper effector
00966     if ((iterEffectorFactory = effectors.find(effectorAttribute)) != effectors.end()) {
00967 
00968         effector = zEffectorPtr((*(iterEffectorFactory->second))());
00969         /*
00970         Save the effector for the zone effect
00971         */
00972     }
00973 
00974     // Should we load the score information
00975     zEffectorPoint *effectorPoint;
00976     effectorPoint = dynamic_cast<zEffectorPoint *>(effector.get());
00977     if (effectorPoint) {
00978         effectorPoint->setPoint(myxmlGetPropInt(cur, "score"));
00979     }
00980 
00981     // Should we load the acceleration
00982     zEffectorCycleAcceleration *effectorAcceleration;
00983     effectorAcceleration = dynamic_cast<zEffectorCycleAcceleration *>(effector.get());
00984     if (effectorAcceleration) {
00985         tFunction tfValue;
00986         string str = string(myxmlGetProp(cur, "value"));
00987         myCheapParameterSplitter(str, tfValue, false);
00988         effectorAcceleration->setValue(tfValue);
00989     }
00990 
00991     // Should we set the grid and arena for respawning
00992     zEffectorSpawnPlayer *effectorSpawnPlayer;
00993     effectorSpawnPlayer = dynamic_cast<zEffectorSpawnPlayer *>(effector.get());
00994     if (effectorSpawnPlayer) {
00995         effectorSpawnPlayer->setGrid(grid);
00996         effectorSpawnPlayer->setArena(sg_GetArena());
00997     }
00998 
00999     // Should we set the setting name and value
01000     zEffectorSetting *effectorSetting;
01001     effectorSetting = dynamic_cast<zEffectorSetting *>(effector.get());
01002     if (effectorSetting) {
01003         if (myxmlHasProp(cur, "settingName"))
01004             effectorSetting->setSettingName(tString(myxmlGetProp(cur, "settingName")));
01005         if (myxmlHasProp(cur, "settingValue"))
01006             effectorSetting->setSettingValue(tString(myxmlGetProp(cur, "settingValue")));
01007     }
01008 
01009     effector->setCount(myxmlGetPropInt(cur, "count"));
01010 
01011     if (myxmlHasProp(cur, "description"))
01012         effector->setMessage(tString(myxmlGetProp(cur, "description")));
01013 
01014     return effector;
01015 }
01016 
01017 zSelectorPtr
01018 gParser::parseZoneEffectGroupSelector(eGrid * grid, xmlNodePtr cur, const xmlChar * keyword) {
01019     zSelectorPtr selector;
01020 
01021     /*
01022       Build a selector of type self, ie: only the person activating the zone is the target
01023     */
01024     typedef zSelector* (*selectorFactory)();
01025     std::map<tString, selectorFactory> selectors;
01026     // Build the list of supported selector
01027     selectors[tString("self")] = zSelectorSelf::create;
01028     selectors[tString("teammate")] = zSelectorTeammate::create;
01029     selectors[tString("another")] = zSelectorAnother::create;
01030     selectors[tString("team")] = zSelectorTeam::create;
01031     selectors[tString("all")] = zSelectorAll::create;
01032     selectors[tString("allbutself")] = zSelectorAllButSelf::create;
01033     //  selectors[tString("allbutteam")] = zSelectorAllButTeam::create;
01034     selectors[tString("another")] = zSelectorAnother::create;
01035     /*
01036       selectors[tString("anotherteam")] = zSelectorAnotherTeam::create;
01037       selectors[tString("anotherteammate")] = zSelectorAnotherTeammate::create;
01038       selectors[tString("anothernotteammate")] = zSelectorAnotherNotTeammate::create;
01039     */
01040     selectors[tString("owner")] = zSelectorOwner::create;
01041     selectors[tString("ownerteam")] = zSelectorOwnerTeam::create;
01042     selectors[tString("ownerteamteammate")] = zSelectorOwnerTeamTeammate::create;
01043     selectors[tString("anydead")] = zSelectorAnyDead::create;
01044     selectors[tString("alldead")] = zSelectorAllDead::create;
01045     selectors[tString("singledeadowner")] = zSelectorSingleDeadOwner::create;
01046     selectors[tString("anotherteammatedead")] = zSelectorAnotherTeammateDead::create;
01047     selectors[tString("anothernotteammatedead")] = zSelectorAnotherNotTeammateDead::create;
01048 
01049     // TODO: add tolower()
01050     // Get the label of the selector to be used
01051     string selectorAttribute( myxmlGetProp(cur, "target"));
01052     transform (selectorAttribute.begin(), selectorAttribute.end(), selectorAttribute.begin(), tolower);
01053 
01054     std::map<tString, selectorFactory>::const_iterator iterSelectorFactory;
01055     // associate the label to the proper selector
01056     if ((iterSelectorFactory = selectors.find(selectorAttribute)) != selectors.end()) {
01057 
01058         selector = zSelectorPtr((*(iterSelectorFactory->second))());
01059 
01060         selector->setCount(myxmlGetPropInt(cur, "count"));
01061 
01062         cur = cur->xmlChildrenNode;
01063         while ( cur != NULL) {
01064             if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
01065             else if (isElement(cur->name, (const xmlChar *)"Effect", keyword)) {
01066                 selector->addEffector(parseZoneEffectGroupEffector(grid, cur, keyword));
01067             }
01068             else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
01069                 if (isValidAlternative(cur, keyword)) {
01070                     parseAlternativeContent(grid, cur);
01071                 }
01072             }
01073             cur = cur->next;
01074         }
01075     }
01076     return selector;
01077 }
01078 
01079 zValidatorPtr
01080 gParser::parseZoneEffectGroupValidator(eGrid * grid, xmlNodePtr cur, const xmlChar * keyword) {
01081     zValidatorPtr validator;
01082 
01083     Triad positive=myxmlGetPropTriad(cur, "positive");
01084     Triad marked  =myxmlGetPropTriad(cur, "marked"  );
01085 
01086     /*
01087      * Get the validator for this EffectGroup
01088      */
01089     typedef zValidator* (*validatorFactory)(Triad, Triad);
01090     std::map<tString, validatorFactory> validators;
01091     // Build the list of supported validator
01092     validators[tString("all")] = zValidatorAll::create;
01093     validators[tString("owner")] = zValidatorOwner::create;
01094     validators[tString("ownerteam")] = zValidatorOwnerTeam::create;
01095     validators[tString("allbutowner")] = zValidatorAllButOwner::create;
01096     validators[tString("allbutteamowner")] = zValidatorAllButTeamOwner::create;
01097     /*
01098       validators[tString("anotherteammate")] = zValidatorTeammate::create;
01099     */
01100 
01101     // TODO: add tolower()
01102     // Get the label of the validator to be used
01103     string validatorAttribute( myxmlGetProp(cur, "user"));
01104     transform (validatorAttribute.begin(),validatorAttribute.end(), validatorAttribute.begin(), tolower);
01105 
01106     std::map<tString, validatorFactory>::const_iterator iterValidatorFactory;
01107     // associate the label to the proper validator
01108     if ((iterValidatorFactory = validators.find(validatorAttribute)) != validators.end()) {
01109 
01110         validator = zValidatorPtr((*(iterValidatorFactory->second))(positive, marked));
01111         /*
01112           Save the validator for the zone effect
01113         */
01114     }
01115 
01116 
01117     cur = cur->xmlChildrenNode;
01118     while ( cur != NULL) {
01119         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
01120         else if (isElement(cur->name, (const xmlChar *)"Target", keyword)) {
01121             validator->addSelector(parseZoneEffectGroupSelector(grid, cur, keyword));
01122         }
01123         else if (isElement(cur->name, (const xmlChar *)"MonitorInfluence", keyword)) {
01124             validator->addMonitorInfluence(parseZoneEffectGroupMonitor(grid, cur, keyword));
01125         }
01126         else if (isElement(cur->name, (const xmlChar *)"ZoneInfluence", keyword)) {
01127             validator->addZoneInfluence(parseZoneEffectGroupZone(grid, cur, keyword));
01128         }
01129         else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
01130             if (isValidAlternative(cur, keyword)) {
01131                 parseAlternativeContent(grid, cur);
01132             }
01133         }
01134         cur = cur->next;
01135     }
01136 
01137 
01138     return validator;
01139 }
01140 
01141 
01142 zEffectGroupPtr
01143 gParser::parseZoneEffectGroup(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword)
01144 {
01145     /*
01146       Store the owner information
01147     */
01148     gVectorExtra< nNetObjectID > nidPlayerOwners;
01149 
01150     if (xmlHasProp(cur, (const xmlChar*)"owners"))
01151     {
01152         string ownersDesc( myxmlGetProp(cur, "owners"));
01153         boost::tokenizer<> tok(ownersDesc);
01154 
01155         // For each owner listed
01156         for (boost::tokenizer<>::iterator iter=tok.begin();
01157                 iter!=tok.end();
01158                 ++iter)
01159         {
01160             // Map from map descriptor to in-game ids
01161             MapIdToGameId::iterator mapOwnerToInGameOwnerPairIter = playerAsso.find(*iter);
01162             if (mapOwnerToInGameOwnerPairIter != playerAsso.end())
01163             {
01164                 // Found a matching in-game owner
01165                 nidPlayerOwners.push_back( (*mapOwnerToInGameOwnerPairIter).second );
01166             }
01167             else
01168             {
01169                 // No in-game owner matching, pass
01170             }
01171         }
01172     }
01173 
01174     /*
01175      * Store the teamOwners information
01176      */
01177     gVectorExtra< nNetObjectID > nidTeamOwners;
01178 
01179     if (xmlHasProp(cur, (const xmlChar*)"teamOwners"))
01180     {
01181         string ownersDesc( myxmlGetProp(cur, "teamOwners"));
01182         boost::tokenizer<> tok(ownersDesc);
01183 
01184         for (boost::tokenizer<>::iterator iter=tok.begin();
01185                 iter!=tok.end();
01186                 ++iter)
01187         {
01188             MapIdToGameId::iterator mapTeamOwnerToInGameTeamOwnerPairIter = teamAsso.find(*iter);
01189             if (mapTeamOwnerToInGameTeamOwnerPairIter != teamAsso.end())
01190             {
01191                 // Found a matching in-game owning team
01192                 nidTeamOwners.push_back( (*mapTeamOwnerToInGameTeamOwnerPairIter).second );
01193             }
01194             else {
01195                 // No in-game owning team found. pass.
01196             }
01197         }
01198     }
01199 
01200     /*
01201      * Prepare a new EffectGroup
01202      */
01203     zEffectGroupPtr currentZoneEffect = zEffectGroupPtr(new zEffectGroup(nidPlayerOwners, nidTeamOwners));
01204 
01205 
01206     cur = cur->xmlChildrenNode;
01207     while ( cur != NULL) {
01208         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
01209         else if (isElement(cur->name, (const xmlChar *)"User", keyword)) {
01210             currentZoneEffect->addValidator(parseZoneEffectGroupValidator(grid, cur, keyword));
01211         }
01212         else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
01213             if (isValidAlternative(cur, keyword)) {
01214                 parseAlternativeContent(grid, cur);
01215             }
01216         }
01217         cur = cur->next;
01218     }
01219 
01220 
01221     return currentZoneEffect;
01222 }
01223 
01224 // emulate v1 zone behavior with v2 zones
01225 void
01226 gParser::parseZoneArthemis_v2(eGrid * grid, xmlNodePtr cur, const xmlChar * keyword)
01227 {
01228     // Currently, we have no compatibility plan for any v2 zone type. When we have one,
01229     // remove the lines that look like this (apart from the one where really
01230     // polugonal shapes are parsed)
01231     safetymecanism_polygonal_shapeused.Set(true);
01232 
01233     if (sn_GetNetState() != nCLIENT )
01234     {
01235         rColor color( 1, 0, 0, .7 );
01236 
01237         // Create a new zone
01238         zZonePtr zone = zZonePtr(new zZone(grid));
01239 
01240         // Insert the zone under a bogus name
01241         string zoneName = "";
01242         zoneMap::const_iterator iterZone;
01243         do
01244         {
01245             // Fill the zone under the shortest available series of pound.
01246             zoneName += "#";
01247             iterZone = mapZones.find(zoneName);
01248         }
01249         while (iterZone != mapZones.end());
01250 
01251         // If a name was assigned to it, save the zone in a map so it can be refered to
01252         if (!zoneName.empty())
01253             mapZones[zoneName] = zone;
01254         zone->setName(zoneName);
01255 
01256 
01257         enum { win, death, fortress };
01258         int effect = win;
01259         if (!xmlStrcmp(xmlGetProp(cur, (const xmlChar *)"effect"), (const xmlChar *)"win")) {
01260             effect = win;
01261         }
01262         else if (!xmlStrcmp(xmlGetProp(cur, (const xmlChar *)"effect"), (const xmlChar *)"death")) {
01263             effect = death;
01264         }
01265         else if (!xmlStrcmp(xmlGetProp(cur, (const xmlChar *)"effect"), (const xmlChar *)"fortress")) {
01266             effect = fortress;
01267         }
01268 
01269         if (sn_GetNetState() != nCLIENT )
01270         {
01271             if (effect != fortress)
01272             {
01273                 // Create an effect group without ownership
01274                 zEffectGroupPtr currentZoneEffect = zEffectGroupPtr(new zEffectGroup(gVectorExtra< nNetObjectID >(), gVectorExtra< nNetObjectID >()));
01275 
01276                 // Create a validator for everybody (i.e. All)
01277                 zValidatorPtr validator = zValidatorPtr( new zValidatorAll(_ignore, _ignore) );
01278 
01279                 zSelectorPtr selector = zSelectorPtr( new zSelectorSelf() );
01280                 //selector->setCount( -1 ); // Give infinite usage
01281 
01282                 zEffectorPtr effector;
01283                 if (effect == win)
01284                     effector = zEffectorPtr( new zEffectorWin() );
01285                 else
01286                     effector = zEffectorPtr( new zEffectorDeath() );
01287 
01288                 effector->setCount( -1 );
01289 
01290                 // Store all the objects
01291                 selector->addEffector( effector );
01292                 validator->addSelector( selector );
01293                 currentZoneEffect->addValidator( validator );
01294                 zone->addEffectGroupEnter( currentZoneEffect );
01295             }
01296             else {
01297                 zMonitorPtr monitor = zMonitorPtr(new zMonitor(grid));
01298                 // use the same name as the associated zone
01299                 monitors[zoneName] = monitor;
01300                 // TODO: read data and populate t
01301                 tPolynomial<nMessage> t;
01302                 monitor->setInit( t );
01303                 tPolynomial<nMessage> drift(2);
01304                 drift[1] = -1.0f * sg_conquestDecayRate;
01305                 monitor->setDrift( drift );
01306                 monitor->setClampLow ( 0.0f );
01307                 monitor->setClampHigh( 1.0f );
01308 
01309                 zMonitorRulePtr rule;
01310                 {
01311                     // All that happens once the zone is conquered
01312                     rule = zMonitorRulePtr( new zMonitorRuleOver( 1.0f ) );
01313 
01314                     zEffectGroupPtr currentZoneEffect;
01315                     {
01316                         // Create an effect group without ownership
01317                         currentZoneEffect = zEffectGroupPtr(new zEffectGroup(gVectorExtra< nNetObjectID >(), gVectorExtra< nNetObjectID >()));
01318 
01319                         // Create a validator for everybody (i.e. All)
01320                         zValidatorPtr validator = zValidatorPtr( new zValidatorAll(_ignore, _ignore) );
01321 
01322                         // Once the zone is conquered, collapse the zhape
01323                         zZoneInfluenceItemScale *scaler = new zZoneInfluenceItemScale(zone);
01324                         scaler->set( -1.5f );
01325 
01326                         zZoneInfluencePtr infl = zZoneInfluencePtr(new zZoneInfluence(zone));
01327                         infl->addZoneInfluenceRule(zZoneInfluenceItemPtr(scaler));
01328 
01329                         validator->addZoneInfluence( infl );
01330                         currentZoneEffect->addValidator( validator );
01331                     }
01332 
01333                     rule->addEffectGroup( currentZoneEffect );
01334                     monitor->addRule(rule);
01335                 }
01336 
01337                 {
01338                     rule = zMonitorRulePtr( new zMonitorRuleUnder( 1.0f ) ); // i.e: Always
01339                     zEffectGroupPtr currentZoneEffect;
01340                     {
01341                         // Create an effect group without ownership
01342                         currentZoneEffect = zEffectGroupPtr(new zEffectGroup(gVectorExtra< nNetObjectID >(), gVectorExtra< nNetObjectID >()));
01343 
01344                         // Create a validator for everybody (i.e. All)
01345                         zValidatorPtr validator = zValidatorPtr( new zValidatorAll(_ignore, _ignore) );
01346 
01347                         zZoneInfluenceItemRotation *b = new zZoneInfluenceItemRotation(zone);
01348 
01349                         tPolynomialMarshaler<nMessage> tpm;
01350 
01351                         string str = string(myxmlGetProp(cur, "rotation"));
01352                         tpm.parse(str);
01353                         b->set(tpm);
01354                         
01355                         //                        b->set( tFunction(0.0f, 0.0f), tFunction(0.3f, 2.0f * 3.141f / 11.0f) );
01356 
01357                         zZoneInfluencePtr infl = zZoneInfluencePtr(new zZoneInfluence(zone));
01358                         infl->addZoneInfluenceRule(zZoneInfluenceItemPtr(b));
01359 
01360                         validator->addZoneInfluence( infl );
01361                         currentZoneEffect->addValidator( validator );
01362                     }
01363                     rule->addEffectGroup( currentZoneEffect );
01364                     monitor->addRule(rule);
01365                 }
01366 
01367                 zone->setOldFortressAutomaticAssignmentBehavior(true);
01368             }
01369         }
01370 
01371         cur = cur->xmlChildrenNode;
01372 
01373         while (cur) {
01374             if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
01375             else if (isElement(cur->name, (const xmlChar *)"ShapeCircle", keyword)) {
01376                 zone->setShape( parseShapeCircleArthemis(grid, cur, zone->ID(), keyword) );
01377             }
01378             else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
01379                 if (isValidAlternative(cur, keyword)) {
01380                     parseAlternativeContent(grid, cur);
01381                 }
01382             }
01383             cur = cur->next;
01384         }
01385 
01386 
01387     }
01388 }
01389 
01390 void
01391 gParser::parseZoneBachus(eGrid * grid, xmlNodePtr cur, const xmlChar * keyword)
01392 {
01393     // Currently, we have no compatibility plan for any v2 zone type. When we have one,
01394     // remove the lines that look like this (apart from the one where really
01395     // polugonal shapes are parsed)
01396     safetymecanism_polygonal_shapeused.Set(true);
01397 
01398     string zoneName = "";
01399 
01400     if (myxmlHasProp(cur, "name"))
01401         zoneName = myxmlGetProp(cur, "name");
01402 
01403     cur = cur->xmlChildrenNode;
01404 
01405     if (sn_GetNetState() != nCLIENT )
01406     {
01407         rColor color( 1, 0, 0, .7 );
01408 
01409         zZonePtr zone;
01410         zoneMap::const_iterator iterZone;
01411         // Has this zone been already registered, such as through a zoneInfluence
01412         if ((iterZone = mapZones.find(zoneName)) != mapZones.end()) {
01413             // Open the zone so we can fill in the details
01414             zone = iterZone->second;
01415         }
01416         else {
01417             // Create a new zone
01418             zone = zZonePtr(new zZone(grid));
01419             // If a name was assigned to it, save the zone in a map so it can be refered to
01420             if (!zoneName.empty())
01421                 mapZones[zoneName] = zone;
01422             zone->setName(zoneName);
01423         }
01424 
01425         while (cur != NULL) {
01426             if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
01427             else if (isElement(cur->name, (const xmlChar *)"ShapeCircle", keyword)) {
01428                 zone->setShape( parseShapeCircleBachus(grid, cur, zone->ID(), keyword) );
01429             }
01430             else if (isElement(cur->name, (const xmlChar *)"ShapePolygon", keyword)) {
01431                 zone->setShape( parseShapePolygon(grid, cur, zone->ID(), keyword) );
01432             }
01433             else if (isElement(cur->name, (const xmlChar *)"Enter", keyword)) {
01434                 xmlNodePtr cur2 = cur->xmlChildrenNode;
01435                 while (cur2 != NULL) {
01436                     if (!xmlStrcmp(cur2->name, (const xmlChar *)"text") || !xmlStrcmp(cur2->name, (const xmlChar *)"comment")) {}
01437                     else if (isElement(cur2->name, (const xmlChar *)"EffectGroup", keyword)) {
01438                         zone->addEffectGroupEnter(parseZoneEffectGroup(grid, cur2, keyword));
01439                     }
01440                     cur2 = cur2->next;
01441                 }
01442             }
01443             else if (isElement(cur->name, (const xmlChar *)"Inside", keyword)) {
01444                 xmlNodePtr cur2 = cur->xmlChildrenNode;
01445                 while (cur2 != NULL) {
01446                     if (!xmlStrcmp(cur2->name, (const xmlChar *)"text") || !xmlStrcmp(cur2->name, (const xmlChar *)"comment")) {}
01447                     else if (isElement(cur2->name, (const xmlChar *)"EffectGroup", keyword)) {
01448                         zone->addEffectGroupInside(parseZoneEffectGroup(grid, cur2, keyword));
01449                     }
01450                     cur2 = cur2->next;
01451                 }
01452             }
01453             else if (isElement(cur->name, (const xmlChar *)"Leave", keyword)) {
01454                 xmlNodePtr cur2 = cur->xmlChildrenNode;
01455                 while (cur2 != NULL) {
01456                     if (!xmlStrcmp(cur2->name, (const xmlChar *)"text") || !xmlStrcmp(cur2->name, (const xmlChar *)"comment")) {}
01457                     else if (isElement(cur2->name, (const xmlChar *)"EffectGroup", keyword)) {
01458                         zone->addEffectGroupLeave(parseZoneEffectGroup(grid, cur2, keyword));
01459                     }
01460                     cur2 = cur2->next;
01461                 }
01462             }
01463             else if (isElement(cur->name, (const xmlChar *)"Outside", keyword)) {
01464                 xmlNodePtr cur2 = cur->xmlChildrenNode;
01465                 while (cur2 != NULL) {
01466                     if (!xmlStrcmp(cur2->name, (const xmlChar *)"text") || !xmlStrcmp(cur2->name, (const xmlChar *)"comment")) {}
01467                     else if (isElement(cur2->name, (const xmlChar *)"EffectGroup", keyword)) {
01468                         zone->addEffectGroupOutside(parseZoneEffectGroup(grid, cur2, keyword));
01469                     }
01470                     cur2 = cur2->next;
01471                 }
01472             }
01473             else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
01474                 if (isValidAlternative(cur, keyword)) {
01475                     parseAlternativeContent(grid, cur);
01476                 }
01477             }
01478             cur = cur->next;
01479         }
01480 
01481         // leaving zone undeleted is no memory leak here, the grid takes control of it
01482         if ( zone )
01483         {
01484             zone->RequestSync();
01485         }
01486     }
01487 }
01488 #endif
01489 
01490 bool
01491 gParser::parseShapeCircle(eGrid *grid, xmlNodePtr cur, float &x, float &y, float &radius, float& growth, const xmlChar * keyword)
01492 {
01493     radius = myxmlGetPropFloat(cur, "radius");
01494     growth = myxmlGetPropFloat(cur, "growth");
01495 
01496     cur = cur->xmlChildrenNode;
01497     while( cur != NULL) {
01498         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
01499         else if (isElement(cur->name, (const xmlChar *)"Point", keyword)) {
01500             x = myxmlGetPropFloat(cur, "x");
01501             y = myxmlGetPropFloat(cur, "y");
01502 
01503             endElementAlternative(grid, cur, keyword);
01504             return true;
01505         }
01506         else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
01507             if (isValidAlternative(cur, keyword)) {
01508                 parseAlternativeContent(grid, cur);
01509             }
01510         }
01511         cur = cur->next;
01512     }
01513     return false;
01514 }
01515 
01516 // original v1 zone parsing code. Return value: was it a success?
01517 bool
01518 gParser::parseZoneArthemis_v1(eGrid * grid, xmlNodePtr cur, const xmlChar * keyword)
01519 {
01520     float x, y, radius, growth;
01521     bool shapeFound = false;
01522     xmlNodePtr shape = cur->xmlChildrenNode;
01523 
01524     while(shape != NULL && shapeFound==false) {
01525         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
01526         else if (isElement(shape->name, (const xmlChar *)"ShapeCircle", keyword)) {
01527             shapeFound = parseShapeCircle(grid, shape, x, y, radius, growth, keyword);
01528         }
01529         else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
01530             if (isValidAlternative(cur, keyword)) {
01531                 parseAlternativeContent(grid, cur);
01532             }
01533         }
01534         shape = shape->next;
01535     }
01536 
01537     if ( !shapeFound )
01538     {
01539         return false;
01540     }
01541 
01542     gZone * zone = NULL;
01543     if (sn_GetNetState() != nCLIENT )
01544     {
01545         if (!xmlStrcmp(xmlGetProp(cur, (const xmlChar *)"effect"), (const xmlChar *)"win")) {
01546             zone = tNEW( gWinZoneHack) ( grid, eCoord(x*sizeMultiplier,y*sizeMultiplier) );
01547         }
01548         else if (!xmlStrcmp(xmlGetProp(cur, (const xmlChar *)"effect"), (const xmlChar *)"death")) {
01549             zone = tNEW( gDeathZoneHack) ( grid, eCoord(x*sizeMultiplier,y*sizeMultiplier) );
01550         }
01551         else if (!xmlStrcmp(xmlGetProp(cur, (const xmlChar *)"effect"), (const xmlChar *)"fortress")) {
01552             zone = tNEW( gBaseZoneHack) ( grid, eCoord(x*sizeMultiplier,y*sizeMultiplier) );
01553         }
01554 
01555         // leaving zone undeleted is no memory leak here, the grid takes control of it
01556         if ( zone )
01557         {
01558             zone->SetRadius( radius*sizeMultiplier );
01559             zone->SetExpansionSpeed( growth*sizeMultiplier );
01560             zone->SetRotationSpeed( .3f );
01561             zone->RequestSync();
01562         }
01563     }
01564 
01565     return zone;
01566 }
01567 
01568 void
01569 gParser::parseZone(eGrid * grid, xmlNodePtr cur, const xmlChar * keyword)
01570 {
01571 #ifdef ENABLE_ZONESV2
01572     switch (mapVersion)
01573     {
01574     case 1:
01575         // was, technically, without zones IIRC. But let's parse it anyway
01576     case 2:
01577         // switch to v2 when some sort of emulation layer is ready
01578         // we should probably check for the DTD, too; v1 zones are only possible
01579         // for 0.2.x dtds and 0.3.1-b and later, and v2 zones only for 0.3.1-a and
01580         // later.
01581         if( !parseZoneArthemis_v1(grid, cur, keyword) )
01582         {
01583             parseZoneBachus(grid, cur, keyword);
01584         }
01585         break;
01586     case 3:
01587         // well, the above is a really ugly hack to keep things working, better
01588         // let users of pure zone v2 maps upgrade them to map version 3.
01589         parseZoneBachus(grid, cur, keyword);
01590         break;
01591     default:
01592         parseZoneBachus(grid, cur, keyword);
01593         break;
01594     }
01595 #else
01596     parseZoneArthemis_v1(grid, cur, keyword);
01597 #endif
01598 }
01599 
01600 #ifdef ENABLE_ZONESV2
01601 void
01602 gParser::parseMonitor(eGrid * grid, xmlNodePtr cur, const xmlChar * keyword)
01603 {
01604     if (sn_GetNetState() != nCLIENT )
01605     {
01606         zMonitorPtr monitor;
01607 
01608         string monitorName(myxmlGetProp(cur, "name"));
01609         monitorMap::const_iterator iterMonitor;
01610         // associate the label to the proper effector
01611         if ((iterMonitor = monitors.find(monitorName)) != monitors.end()) {
01612             monitor = iterMonitor->second;
01613         }
01614         else {
01615             // make an empty zone and store under the right label
01616             // It should be populated later
01617             monitor = zMonitorPtr(new zMonitor(grid));
01618             if (!monitorName.empty()) {
01619                 monitors[monitorName] = monitor;
01620                 monitor->setName(monitorName);
01621             }
01622         }
01623 
01624         // TODO: read data and populate t
01625         tPolynomial<nMessage> t;
01626         //        monitor->setInit(myxmlGetPropFloat(cur, "init"));
01627         monitor->setInit( t );
01628         tPolynomial<nMessage> drift(2);
01629         drift[1] = myxmlGetPropFloat(cur, "drift");
01630         monitor->setDrift( drift );
01631         monitor->setClampLow (myxmlGetPropFloat(cur, "low"));
01632         monitor->setClampHigh(myxmlGetPropFloat(cur, "high"));
01633 
01634         cur = cur->xmlChildrenNode;
01635 
01636         if (sn_GetNetState() != nCLIENT )
01637         {
01638             zMonitorRulePtr rule;
01639             bool ruleFound = false;
01640 
01641             while (cur != NULL) {
01642                 if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
01643                 else if (isElement(cur->name, (const xmlChar *)"OnOver", keyword)) {
01644                     rule = zMonitorRulePtr(new zMonitorRuleOver(myxmlGetPropFloat(cur, "value")));
01645                     ruleFound = true;
01646                 }
01647                 else if (isElement(cur->name, (const xmlChar *)"OnUnder", keyword)) {
01648                     rule = zMonitorRulePtr(new zMonitorRuleUnder(myxmlGetPropFloat(cur, "value")));
01649                     ruleFound = true;
01650                 }
01651                 else if (isElement(cur->name, (const xmlChar *)"InRange", keyword)) {
01652                     rule = zMonitorRulePtr(new zMonitorRuleInRange(myxmlGetPropFloat(cur, "low"), myxmlGetPropFloat(cur, "high")));
01653                     ruleFound = true;
01654                 }
01655                 else if (isElement(cur->name, (const xmlChar *)"OutsideRange", keyword)) {
01656                     rule = zMonitorRulePtr(new zMonitorRuleOutsideRange(myxmlGetPropFloat(cur, "low"), myxmlGetPropFloat(cur, "high")));
01657                     ruleFound = true;
01658                 }
01659                 else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
01660                     if (isValidAlternative(cur, keyword)) {
01661                         parseAlternativeContent(grid, cur);
01662                     }
01663                 }
01664                 if (ruleFound == true ) {
01665                     xmlNodePtr cur2 = cur->xmlChildrenNode;
01666                     while (cur2 != NULL) {
01667                         if (!xmlStrcmp(cur2->name, (const xmlChar *)"text") || !xmlStrcmp(cur2->name, (const xmlChar *)"comment")) {}
01668                         else if (isElement(cur2->name, (const xmlChar *)"EffectGroup", keyword)) {
01669                             rule->addEffectGroup(parseZoneEffectGroup(grid, cur2, keyword));
01670                         }
01671                         else if (isElement(cur2->name, (const xmlChar *)"ZoneInfluence", keyword)) {
01672                             rule->addZoneInfluence(parseZoneEffectGroupZone(grid, cur2, keyword));
01673                         }
01674                         else if (isElement(cur2->name, (const xmlChar *)"MonitorInfluence", keyword)) {
01675                             rule->addMonitorInfluence(parseZoneEffectGroupMonitor(grid, cur2, keyword));
01676                         }
01677                         cur2 = cur2->next;
01678                     }
01679                     ruleFound = false;
01680                     monitor->addRule(rule);
01681                 }
01682 
01683                 cur = cur->next;
01684             }
01685         }
01686     }
01687 }
01688 #endif
01689 
01690 ePoint * gParser::DrawRim( eGrid * grid, ePoint * start, eCoord const & stop, REAL h )
01691 {
01692     // calculate the wall's length and the rim wall textures
01693     REAL length = (stop-(*start)).Norm();
01694     REAL rimTextureStop = rimTexture + length;
01695 
01696     // create wall
01697     tJUST_CONTROLLED_PTR< gWallRim > newWall = tNEW( gWallRim )(grid, rimTexture, rimTextureStop, h);
01698 
01699     // update rim texture
01700     rimTexture = rimTextureStop;
01701 
01702     // draw line with wall
01703     return grid->DrawLine( start, stop, newWall, 0 );
01704 }
01705 
01706 void
01707 gParser::parseWallLine(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword) {
01708     REAL ox, oy, x, y;
01709     ePoint *R;
01710 
01711     ox = myxmlGetPropFloat(cur, "startx");
01712     oy = myxmlGetPropFloat(cur, "starty");
01713     x = myxmlGetPropFloat(cur,   "endx");
01714     y = myxmlGetPropFloat(cur,   "endy");
01715     R = grid->Insert(eCoord(ox, oy) * sizeMultiplier);
01716     R = this->DrawRim(grid, R, eCoord(x, y) * sizeMultiplier);
01717     sg_Deprecated();
01718 
01719     endElementAlternative(grid, cur, keyword);
01720 }
01721 
01722 void
01723 gParser::parseWallRect(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword) {
01724     REAL ox, oy, x, y;
01725     ePoint *R;
01726 
01727     ox = myxmlGetPropFloat(cur, "startx");
01728     oy = myxmlGetPropFloat(cur, "starty");
01729     x = myxmlGetPropFloat(cur,   "endx");
01730     y = myxmlGetPropFloat(cur,   "endy");
01731     R = grid->Insert(eCoord(ox, oy) * sizeMultiplier);
01732     R = this->DrawRim( grid, R, eCoord( x, oy) * sizeMultiplier);
01733     R = this->DrawRim( grid, R, eCoord( x,  y) * sizeMultiplier);
01734     R = this->DrawRim( grid, R, eCoord(ox,  y) * sizeMultiplier);
01735     R = this->DrawRim( grid, R, eCoord(ox, oy) * sizeMultiplier);
01736     sg_Deprecated();
01737 
01738     endElementAlternative(grid, cur, keyword);
01739 }
01740 
01741 void
01742 gParser::parseWall(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword)
01743 {
01744     ePoint *R = NULL, *sR = NULL;
01745     REAL ox, oy, x, y;
01746 
01747     REAL height = myxmlGetPropFloat(cur, "height");
01748     if ( height <= 0 )
01749         height = 10000;
01750 
01751     cur = cur->xmlChildrenNode;
01752 
01753     while (cur != NULL) {
01754         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
01755         else if (isElement(cur->name, (const xmlChar *)"Point", keyword)) {
01756             x = myxmlGetPropFloat(cur, "x");
01757             y = myxmlGetPropFloat(cur, "y");
01758 
01759             if (R == NULL)
01760                 R = grid->Insert(eCoord(x, y) * sizeMultiplier);
01761             else
01762                 R = this->DrawRim(grid, R, eCoord(x, y) * sizeMultiplier, height);
01763 
01764             // TODO-Alt:
01765             // if this function returns a point, use it in the wall. Otherwise, ignore what comes out.
01766             endElementAlternative(grid, cur, keyword);
01767         }
01768         else if (isElement(cur->name, (const xmlChar *)"SavePos", keyword)) {
01769             sR = R;
01770             endElementAlternative(grid, cur, keyword);
01771         }
01772         else if (isElement(cur->name, (const xmlChar *)"RestorePos", keyword)) {
01773             R = sR;
01774             endElementAlternative(grid, cur, keyword);
01775         }
01776         else if (isElement(cur->name, (const xmlChar *)"Line", keyword)) {
01777             parseWallLine(grid, cur, keyword);
01778             endElementAlternative(grid, cur, keyword);
01779         }
01780         else if (isElement(cur->name, (const xmlChar *)"Rectangle", keyword)) {
01781             parseWallRect(grid, cur, keyword);
01782             endElementAlternative(grid, cur, keyword);
01783         }
01784         else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
01785             if (isValidAlternative(cur, keyword)) {
01786                 parseAlternativeContent(grid, cur);
01787             }
01788         }
01789         cur = cur->next;
01790         ox = x;
01791         oy = y;
01792     }
01793 }
01794 
01795 void
01796 gParser::parseObstacleWall(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword)
01797 {
01798     ePoint *R = NULL;
01799     REAL x, y;
01800 
01801     REAL height = myxmlGetPropFloat(cur, "height");
01802     cur = cur->xmlChildrenNode;
01803 
01804     while (cur != NULL) {
01805         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
01806         else if (isElement(cur->name, (const xmlChar *)"Point", keyword)) {
01807             x = myxmlGetPropFloat(cur, "x");
01808             y = myxmlGetPropFloat(cur, "y");
01809 
01810             if (R == NULL)
01811                 R = grid->Insert(eCoord(x, y) * sizeMultiplier);
01812             else
01813                 R = this->DrawRim(grid, R, eCoord(x, y) * sizeMultiplier, height );
01814             endElementAlternative(grid, cur, keyword);
01815         }
01816         else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
01817             if (isValidAlternative(cur, keyword)) {
01818                 parseAlternativeContent(grid, cur);
01819             }
01820         }
01821         cur = cur->next;
01822     }
01823     sg_Deprecated();
01824 }
01825 
01826 /* processSubAlt should be applied to all and any elements, even those that are known not to have any
01827    sub elements possible. This ensure maximal future compatibility.*/
01828 
01829 // TODO-Alt:
01830 // processSubAlt need to be altered. It need to be able to "return" a <Point>, a <ShapeCircle> or NULL.
01831 // This will allow for imbricked elements to contribute to their parents, ie: Wall, Zone's shape and ShapeCircle's Point.
01832 void
01833 gParser::processSubAlt(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword) {
01834     cur = cur->xmlChildrenNode;
01835     /* Quickly goes through all the sub element until a valid Alternative is found */
01836     while ( cur != NULL) {
01837         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
01838         else if (isValidAlternative(cur, keyword)) {
01839             parseAlternativeContent(grid, cur);
01840             return; /*We process only the first matching one*/
01841         }
01842         cur = cur->next;
01843     }
01844 }
01845 
01846 /* Present a  */
01847 void
01848 gParser::parseAlternativeContent(eGrid *grid, xmlNodePtr cur)
01849 {
01850     const xmlChar * keyword = xmlGetProp(cur, (const xmlChar *) "keyword");
01851 
01852     cur = cur->xmlChildrenNode;
01853 
01854     while (cur != NULL) {
01855         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {
01856             /* Do nothing, but is required to eliminate all Text and Comment element */
01857             /* text elements are half of any other elements, drop them here rather than perform countless test */
01858         }
01859         /* The elements of Field */
01860         else if (isElement(cur->name, (const xmlChar *)"Axes", keyword)) {
01861             parseAxes(grid, cur, keyword);
01862         }
01863         else if (isElement(cur->name, (const xmlChar *)"Spawn", keyword)) {
01864             parseSpawn(grid, cur, keyword);
01865         }
01866         else if (isElement(cur->name, (const xmlChar *)"Zone", keyword)) {
01867             parseZone(grid, cur, keyword);
01868         }
01869         else if (isElement(cur->name, (const xmlChar *)"Zone_v1", keyword)) {
01870             parseZoneArthemis_v1(grid, cur, keyword);
01871         }
01872         else if (isElement(cur->name, (const xmlChar *)"Wall", keyword)) {
01873             parseWall(grid, cur, keyword);
01874         }
01875         else if (isElement(cur->name, (const xmlChar *)"ObstacleWall", keyword)) {
01876             parseObstacleWall(grid, cur, keyword);
01877         }
01878         else if (isElement(cur->name, (const xmlChar *)"Line", keyword)) {
01879             parseWallLine(grid, cur, keyword);
01880         }
01881         else if (isElement(cur->name, (const xmlChar *)"Rectangle", keyword)) {
01882             parseWallRect(grid, cur, keyword);
01883         }
01884         /* The settings */
01885         else if (isElement(cur->name, (const xmlChar *)"Settings", keyword)) {
01886             parseSettings(grid, cur, keyword);
01887         }
01888         else if (isElement(cur->name, (const xmlChar *)"Setting", keyword)) {
01889             parseSetting(grid, cur, keyword);
01890         }
01891         /* The big holders*/
01892         else if (isElement(cur->name, (const xmlChar *)"Map", keyword)) {
01893             parseMap(grid, cur, keyword);
01894         }
01895         else if (isElement(cur->name, (const xmlChar *)"World", keyword)) {
01896             parseWorld(grid, cur, keyword);
01897         }
01898         else if (isElement(cur->name, (const xmlChar *)"Field", keyword)) {
01899             parseField(grid, cur, keyword);
01900         }
01901         /* Those that cant affect the instance directly. They should return something */
01902         else if (isElement(cur->name, (const xmlChar *)"Axis", keyword)) {
01903             // TODO-Alt2: A method to read in Axis data and return an "Axis object" to be captured at some other level.
01904             // The same method could be used inside of the parseAxes
01905             //            parseAxis(grid, cur, keyword);
01906         }
01907         else if (isElement(cur->name, (const xmlChar *)"Point", keyword)) {
01908             // TODO-Alt2: A method to read in Point data and return an "Point object" to be captured at some other level.
01909             // The same method could be used to read all "Point" in the code
01910             //            parsePoint(grid, cur, keyword);
01911         }
01912         else if (isElement(cur->name, (const xmlChar *)"ShapeCircle", keyword)) {
01913             // TODO-Alt2: parseShapeCircle should be modified to return an "ShapeCircle object" to be captured at some other level.
01914             // The same method could be used inside of the parseZone
01915             //            parseShapeCircle(grid, cur, keyword);
01916         }
01917         else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
01918             if (isValidAlternative(cur, keyword)) {
01919                 parseAlternativeContent(grid, cur);
01920             }
01921         }
01922 
01923 
01924         cur = cur->next;
01925     }
01926 }
01927 
01928 void
01929 gParser::parseField(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword)
01930 {
01931     cur = cur->xmlChildrenNode;
01932     while (cur != NULL) {
01933         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
01934         else if (isElement(cur->name, (const xmlChar *)"Axes", keyword)) {
01935             parseAxes(grid, cur, keyword);
01936         }
01937         else if (isElement(cur->name, (const xmlChar *)"Spawn", keyword)) {
01938             parseSpawn(grid, cur, keyword);
01939         }
01940 #ifdef ENABLE_ZONESV2
01941         // Introduced in version 2, but no extra logic is required for it.
01942         else if (isElement(cur->name, (const xmlChar *)"Ownership", keyword)) {
01943             parseOwnership(grid, cur, keyword);
01944         }
01945         else if (isElement(cur->name, (const xmlChar *)"Monitor", keyword)) {
01946             parseMonitor(grid, cur, keyword);
01947         }
01948 #endif
01949         else if (isElement(cur->name, (const xmlChar *)"Zone", keyword)) {
01950             parseZone(grid, cur, keyword);
01951         }
01952         else if (isElement(cur->name, (const xmlChar *)"Zone_v1", keyword)) {
01953             parseZoneArthemis_v1(grid, cur, keyword);
01954         }
01955         else if (isElement(cur->name, (const xmlChar *)"Wall", keyword)) {
01956             parseWall(grid, cur, keyword);
01957         }
01958         else if (isElement(cur->name, (const xmlChar *)"ObstacleWall", keyword)) {
01959             parseObstacleWall(grid, cur, keyword);
01960         }
01961         else if (isElement(cur->name, (const xmlChar *)"Line", keyword)) {
01962             parseWallLine(grid, cur, keyword);
01963         }
01964         else if (isElement(cur->name, (const xmlChar *)"Rectangle", keyword)) {
01965             parseWallRect(grid, cur, keyword);
01966         }
01967         else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
01968             if (isValidAlternative(cur, keyword)) {
01969                 parseAlternativeContent(grid, cur);
01970             }
01971         }
01972         cur = cur->next;
01973     }
01974 }
01975 
01976 #ifdef ENABLE_ZONESV2
01977 
01980 const char * TEAM_ID_STR =  "teamId";
01981 const char * PLAYER_ID_STR = "playerId";
01982 
01983 void
01984 gParser::parseOwnership(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword)
01985 {
01986     // Prepare the structures to store the ownership information
01987     TeamOwnershipInfo mapIdOfTeamOwners;
01988 
01989     // Remove previous ownership
01990     playerAsso.erase(playerAsso.begin(), playerAsso.end());
01991     teamAsso.erase(teamAsso.begin(), teamAsso.end());
01992 
01993     cur = cur->xmlChildrenNode;
01994     while (cur != NULL) {
01995         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
01996         else if (isElement(cur->name, (const xmlChar *)"TeamOwnership", keyword)) {
01997             parseTeamOwnership(grid, cur, keyword, mapIdOfTeamOwners);
01998         }
01999         cur = cur->next;
02000     }
02001 
02002     // BOP
02003     // The association between teamId and in-game teams should be moved to its own class
02004 
02005     std::cout << "###################" << std::endl;
02006     std::cout << "number of teams " << eTeam::teams.Len() << std::endl;
02007 
02008     TeamOwnershipInfo::iterator iterTeamOwnership = mapIdOfTeamOwners.begin();
02009     for (int index=0; index<eTeam::teams.Len() && iterTeamOwnership != mapIdOfTeamOwners.end(); ) {
02010         eTeam* ee = eTeam::teams[index];
02011         string teamId = (*iterTeamOwnership).first;
02012         std::cout << "associating " << teamId << " with " << ee->Name() << " net ID:" << ee->ID() << std::endl;
02013         MapIdToGameId::value_type asdf(teamId, ee->ID());
02014 
02015         // Store the association between the map id and the in-game id
02016         teamAsso.insert(asdf);
02017 
02018         std::set<string> playerIdForThisTeam = (*iterTeamOwnership).second;
02019         int indexPlayer=0;
02020         for (std::set<string>::iterator iter = playerIdForThisTeam.begin();
02021                     iter != playerIdForThisTeam.end() && indexPlayer<ee->NumPlayers();
02022                     ++iter, ++indexPlayer) {
02023                 ePlayerNetID *aa = ee->Player(indexPlayer);
02024                 string playerId = (*iter);
02025                 // TODO
02026                 // HACK
02027                 // BOP
02028                 // The following might produce unexpected results should the same playerId be associated in many team
02029                 MapIdToGameId::value_type mapOwnerToInGameOwnerPair(playerId, aa->ID());
02030                 playerAsso.insert(mapOwnerToInGameOwnerPair);
02031             }
02032         ++index;
02033         ++iterTeamOwnership;
02034     }
02035     // EOP
02036 }
02037 
02038 void
02039 gParser::parseTeamOwnership(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword, TeamOwnershipInfo & mapIdOfTeamOwners)
02040 {
02041     // Explore the teamId attribute
02042     if (myxmlHasProp(cur, TEAM_ID_STR )) {
02043         string tOwnersDesc( myxmlGetProp(cur, TEAM_ID_STR));
02044         boost::tokenizer<> tokTeam(tOwnersDesc);
02045 
02046         for (boost::tokenizer<>::iterator tokTeamIter=tokTeam.begin();
02047                 tokTeamIter!=tokTeam.end();
02048                 ++tokTeamIter) {
02049             tString aTeamId = tString(*tokTeamIter);
02050             TeamOwnershipInfo::iterator teamIter = mapIdOfTeamOwners.find(aTeamId);
02051             // Add the teamId to the list if abscent
02052             if (teamIter == mapIdOfTeamOwners.end()) {
02053                 //      teamIter = team.insert(std::pair<string, std::set<string> >( aTeamId, std::set<string> ));
02054                 std::pair<string, std::set<string> > asdf( aTeamId, std::set<string>() );
02055                 teamIter = mapIdOfTeamOwners.insert(teamIter, asdf);
02056             }
02057 
02058             // Should the team receive playerId
02059             if (myxmlHasProp(cur, PLAYER_ID_STR)) {
02060                 // Extract all the playerId for this team
02061                 string plOwnersDesc( myxmlGetProp(cur, PLAYER_ID_STR) );
02062                 boost::tokenizer<> tokPlayer(plOwnersDesc);
02063                 for (boost::tokenizer<>::iterator tokPlayerIter=tokPlayer.begin();
02064                         tokPlayerIter!=tokPlayer.end();
02065                         ++tokPlayerIter) {
02066                     tString aPlayerId = tString(*tokPlayerIter);
02067 
02068                     std::set<string> aa = (*teamIter).second;
02069                     aa.insert(aPlayerId);
02070                     (*teamIter).second = aa;
02071                 }
02072             }
02073         }
02074     }
02075     else {
02076         // TeamId is #REQUIRED, this should not happen
02077     }
02078 }
02079 #endif
02080 
02081 void
02082 gParser::parseWorld(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword)
02083 {
02084     cur = cur->xmlChildrenNode;
02085     while (cur != NULL) {
02086         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
02087         else if (isElement(cur->name, (const xmlChar *)"Field", keyword)) {
02088             parseField(grid, cur, keyword);
02089         }
02090         else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
02091             if (isValidAlternative(cur, keyword)) {
02092                 parseAlternativeContent(grid, cur);
02093             }
02094         }
02095         cur = cur->next;
02096     }
02097 }
02098 
02099 void
02100 gParser::parseSetting(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword)
02101 {
02102     if (strlen(myxmlGetProp(cur, "name")) && strlen(myxmlGetProp(cur, "value")) && sn_GetNetState() != nCLIENT )
02103     {
02104         std::stringstream ss;
02105         /* Yes it is ackward to generate a string that will be decifered on the other end*/
02106         ss << myxmlGetProp(cur, "name")  << " " << myxmlGetProp(cur, "value");
02107         if ( tRecorder::IsPlayingBack() )
02108             tConfItemBase::LoadPlayback( true );
02109         else
02110             tConfItemBase::LoadAll(ss);
02111     }
02112     /* Verify if any sub elements are included, and if they contain any Alt
02113        Sub elements of Point arent defined in the current version*/
02114     endElementAlternative(grid, cur, keyword);
02115 }
02116 
02117 void
02118 gParser::parseSettings(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword)
02119 {
02120     cur = cur->xmlChildrenNode;
02121     while (cur != NULL) {
02122         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
02123         else if (isElement(cur->name, (const xmlChar *)"Setting", keyword)) {
02124             parseSetting(grid, cur, keyword);
02125         }
02126         else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
02127             if (isValidAlternative(cur, keyword)) {
02128                 parseAlternativeContent(grid, cur);
02129             }
02130         }
02131         cur = cur->next;
02132     }
02133 
02134     update_settings();
02135     sizeMultiplier = gArena::GetSizeMultiplier();
02136 }
02137 
02138 void
02139 gParser::parseMap(eGrid *grid, xmlNodePtr cur, const xmlChar * keyword)
02140 {
02141     mapVersion = myxmlGetPropInt(cur, "version");
02142 
02143     cur = cur->xmlChildrenNode;
02144     while (cur != NULL) {
02145         if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
02146         else if (isElement(cur->name, (const xmlChar *)"Settings", keyword)) {
02147             parseSettings (grid, cur, keyword);
02148         }
02149         else if (isElement(cur->name, (const xmlChar *)"World", keyword)) {
02150             parseWorld (theGrid, cur, keyword);
02151         }
02152         else if (isElement(cur->name, (const xmlChar *)"Alternative", keyword)) {
02153             if (isValidAlternative(cur, keyword)) {
02154                 parseAlternativeContent(grid, cur);
02155             }
02156         }
02157         cur = cur->next;
02158     }
02159 }
02160 
02161 void
02162 gParser::setSizeMultiplier(REAL aSizeMultiplier)
02163 {
02164     // BOP
02165     sizeMultiplier = aSizeMultiplier;
02166     // EOP
02167 }
02168 
02169 void
02170 gParser::Parse()
02171 {
02172     rimTexture = 0;
02173     xmlNodePtr cur;
02174     cur = xmlDocGetRootElement(m_Doc);
02175 
02176 #ifdef ENABLE_ZONESV2
02177     monitors.clear();
02178 #endif
02179 #ifdef DEBUG_ZONE_SYNC
02180     newGameRound = true;
02181 #endif //DEBUG_ZONE_SYNC
02182 
02183     if (cur == NULL) {
02184         con << "ERROR: Map file is blank\n";
02185         return;
02186     }
02187 
02188     if (isElement(cur->name, (const xmlChar *) "Resource")) {
02189         if (xmlStrcmp((const xmlChar *) "aamap", xmlGetProp(cur, (const xmlChar *) "type"))) {
02190             con << "Type aamap expected, found " << xmlGetProp(cur, (const xmlChar *) "type") << " instead\n";
02191             con << "formalise this message\n";
02192         }
02193         else {
02194             cur = cur->xmlChildrenNode;
02195             while (cur != NULL) {
02196                 if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {
02197                     /* Do nothing, but is required to eliminate all Text element */
02198                     /* text elements are half of any other elements, drop them here rather than perform countless test */
02199                 }
02200                 else if (isElement(cur->name, (const xmlChar *)"Map")) {
02201                     parseMap(theGrid, cur);
02202                 }
02203                 else if (isElement(cur->name, (const xmlChar *)"Alternative")) {
02204                     if (isValidAlternative(cur)) {
02205                         parseAlternativeContent(theGrid, cur);
02206                     }
02207                 }
02208                 cur = cur ? cur->next : NULL;
02209             }
02210         }
02211     }
02212     else if (isElement(cur->name, (const xmlChar *) "World")) {
02213         // Legacy code to support version 0.1 of the DTDs
02214         sg_Deprecated();
02215 
02216         cur = cur->xmlChildrenNode;
02217         while (cur != NULL) {
02218             if (!xmlStrcmp(cur->name, (const xmlChar *)"text") || !xmlStrcmp(cur->name, (const xmlChar *)"comment")) {}
02219             else if (isElement(cur->name, (const xmlChar *)"Map")) {
02220                 // Map and world got swapped in the current DTD, that's why this looks a little strange.
02221                 parseWorld (theGrid, cur);
02222             }
02223             else if (isElement(cur->name, (const xmlChar *)"Alternative")) {
02224                 if (isValidAlternative(cur)) {
02225                     parseAlternativeContent(theGrid, cur);
02226                 }
02227             }
02228             cur = cur->next;
02229         }
02230     }
02231 
02232 #ifdef ENABLE_ZONESV2
02233     mapZones.clear();
02234 #endif
02235 
02236     //        fprintf(stderr,"ERROR: Map file is missing root \'Resources\' node");
02237 
02238 }
02239 
02240 #ifdef ENABLE_ZONESV2
02241 zMonitorPtr
02242 gParser::getMonitor(string monitorName)
02243 {
02244     return monitors[monitorName];
02245 }
02246 #endif

Generated on Sat Mar 15 22:56:09 2008 for Armagetron Advanced by  doxygen 1.5.4