home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2007 September / maximum-cd-2007-09.iso / Assets / data / AssaultCube_v0.93.exe / source / src / bot / bot_waypoint.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-12-07  |  102.8 KB  |  3,270 lines

  1. //
  2. // C++ Implementation: bot_waypoint
  3. //
  4. // Description: Waypoint class for bots
  5. //
  6. //
  7. // Author: Rick <rickhelmus@gmail.com>
  8. //
  9.  
  10. #include "bot.h"
  11.  
  12. vec v_debuggoal = g_vecZero;
  13.  
  14. #if defined AC_CUBE
  15. CACWaypointClass WaypointClass;
  16. #elif defined VANILLA_CUBE
  17. CCubeWaypointClass WaypointClass;
  18. #endif
  19.  
  20. VAR(xhairwpsel, 0, 1, 1);
  21. extern block sel;
  22. #define curselection (xhairwpsel ? vec(sel.x, sel.y, S(sel.x, sel.y)->floor+2.0f) : vec(player1->o.x, player1->o.y, player1->o.z))
  23.  
  24. // Waypoint class begin
  25.  
  26. CWaypointClass::CWaypointClass(void) : m_bDrawWaypoints(false), m_bDrawWPPaths(true),
  27.                                        m_bAutoWaypoint(false),  m_bAutoPlacePaths(true),
  28.                                        m_bDrawWPText(false), m_vLastCreatedWP(g_vecZero),
  29.                                        m_bFlooding(false), m_bFilteringNodes(false),
  30.                                        m_iFloodStartTime(0), m_iCurFloodX(0),
  31.                                        m_iCurFloodY(0), m_iFloodSize(0), 
  32.                                        m_iFilteredNodes(0), m_iWaypointCount(0)
  33. {
  34.      loopi(MAX_MAP_GRIDS)
  35.      {
  36.           loopj(MAX_MAP_GRIDS)
  37.           {
  38.                while(!m_Waypoints[i][j].Empty())
  39.                     delete m_Waypoints[i][j].Pop();
  40.           }
  41.      }
  42.      
  43.      m_szMapName[0] = 0;
  44. }
  45.  
  46. void CWaypointClass::Init()
  47. {
  48.      Clear();  // Free previously allocated path memory
  49.  
  50.      loopi(MAX_MAP_GRIDS)
  51.      {
  52.           loopj(MAX_MAP_GRIDS)
  53.           {
  54.                while(!m_Waypoints[i][j].Empty())
  55.                     delete m_Waypoints[i][j].Pop();
  56.           }
  57.      }
  58.  
  59.      m_fPathDrawTime = 0.0;
  60.      m_iWaypointCount = 0;
  61.      m_vLastCreatedWP = g_vecZero;
  62. }
  63.  
  64. void CWaypointClass::Clear()
  65. {
  66.      for(int i=0;i<MAX_MAP_GRIDS;i++)
  67.      {
  68.           for(int j=0;j<MAX_MAP_GRIDS;j++)
  69.           {
  70.                while(!m_Waypoints[i][j].Empty())
  71.                {
  72.                     node_s *p = m_Waypoints[i][j].Pop();
  73.                     p->ConnectedWPs.DeleteAllNodes();
  74.                     p->ConnectedWPsWithMe.DeleteAllNodes();
  75.                     BotManager.DelWaypoint(p);
  76.                     delete p;
  77.                }
  78.           }
  79.      }     
  80. }
  81.  
  82. //fixme
  83. TLinkedList<node_s *>::node_s *testx;
  84.  
  85. // returns true if waypoints succesfull loaded
  86. bool CWaypointClass::LoadWaypoints()
  87. {
  88.      FILE *bfp;
  89.      char szWPFileName[64];
  90.      char filename[256];
  91.      waypoint_header_s header;
  92.      short num, triggernr, yaw;
  93.      int i, j, flags;
  94.      vec from, to;
  95.  
  96.      strcpy(szWPFileName, m_szMapName);
  97.      strcat(szWPFileName, ".wpt");
  98.  
  99.      BotManager.MakeBotFileName(szWPFileName, "waypoints", NULL, filename);
  100.  
  101.      bfp = fopen(filename, "rb");
  102.  
  103.      BotManager.m_sCurrentTriggerNr = -1;
  104.       
  105.      // if file exists, read the waypoint structure from it
  106.      if (bfp != NULL)
  107.      {
  108.           fread(&header, sizeof(header), 1, bfp);
  109.           
  110.           header.szFileType[10] = 0;
  111.           if (strcmp(header.szFileType, "cube_bot") == 0)
  112.           {
  113.                header.szMapName[31] = 0;
  114.  
  115.                if (strcmp(header.szMapName, m_szMapName) == 0)
  116.                {
  117.                     Init();  // remove any existing waypoints
  118.  
  119.                     // Check which waypoint file version this is, handle each of them different
  120.                     if (header.iFileVersion == 1)
  121.                     {
  122.                          // First version, works with an big array and has a limit
  123.                          
  124.                          waypoint_version_1_s WPs[1024];
  125.                          int path_index;
  126.                                    
  127.                          m_iWaypointCount = header.iWPCount;         
  128.                          for (i=0; i < header.iWPCount; i++)
  129.                          {
  130.                               fread(&WPs[i], sizeof(WPs[0]), 1, bfp);
  131.                               WPs[i].ConnectedWPs.Reset(); // We get garbage when we read this from
  132.                                                            // a file, so just clear it
  133.                               
  134.                               // Convert to new waypoint structure
  135.                               node_s *pNode = new node_s(WPs[i].v_origin, WPs[i].iFlags, 0);
  136.                               
  137.                               short x, y;
  138.                               GetNodeIndexes(pNode->v_origin, &x, &y);
  139.                                    
  140.                               m_Waypoints[x][y].AddNode(pNode);
  141.                               BotManager.AddWaypoint(pNode);
  142.                          }
  143.                     
  144.                          // read and add waypoint paths...
  145.                          for (i=0; i < m_iWaypointCount; i++)
  146.                          {
  147.                               // read the number of paths from this node...
  148.                               fread(&num, sizeof(num), 1, bfp);
  149.  
  150.                               // See which waypoint the current is
  151.                               node_s *pCurrent = GetWaypointFromVec(WPs[i].v_origin);
  152.                          
  153.                               if (!pCurrent)
  154.                               {
  155.                                    conoutf("Error: NULL path in waypoint file");
  156.                                    continue;
  157.                               }
  158.                               
  159.                               for (j=0; j < num; j++)
  160.                               {
  161.                                    fread(&path_index, sizeof(path_index), 1, bfp);
  162.                                    
  163.                                    // See which waypoint this is
  164.                                    node_s *pTo = GetWaypointFromVec(WPs[path_index].v_origin);
  165.                          
  166.                                    if (!pTo)
  167.                                    {
  168.                                         conoutf("Error: NULL path in waypoint file");
  169.                                         continue;
  170.                                    }
  171.                                    
  172.                                    AddPath(pCurrent, pTo);
  173.                               }                              
  174.                          }
  175.                          conoutf("Old waypoint version(%d) converted to new version(%d)",
  176.                                   header.iFileVersion, WAYPOINT_VERSION);
  177.                          conoutf("Use the wpsave command to convert permently");
  178.                          
  179.                     }
  180.                     else if (header.iFileVersion == 2)
  181.                     {
  182.                          m_iWaypointCount = header.iWPCount;
  183.                          
  184.                          for (i=0; i < header.iWPCount; i++)
  185.                          {
  186.                               fread(&from, sizeof(from), 1, bfp); // Read origin
  187.                               fread(&flags, sizeof(flags), 1, bfp); // Read waypoint flags
  188.                               fread(&triggernr, sizeof(triggernr), 1, bfp); // Read trigger nr
  189.                               fread(&yaw, sizeof(yaw), 1, bfp); // Read target yaw
  190.                               
  191.                               node_s *pNode = new node_s(from, flags, triggernr, yaw);
  192.                          
  193.                               short x, y;
  194.                               GetNodeIndexes(pNode->v_origin, &x, &y);
  195.                                    
  196.                               m_Waypoints[x][y].AddNode(pNode);
  197.                               BotManager.AddWaypoint(pNode);
  198.                               
  199.                               if ((BotManager.m_sCurrentTriggerNr == -1) ||
  200.                                   (triggernr < BotManager.m_sCurrentTriggerNr))
  201.                                   BotManager.m_sCurrentTriggerNr = triggernr;
  202.                          }
  203.                
  204.                          for (i=0; i < header.iWPCount; i++)
  205.                          {
  206.                               // read the number of paths from this node...
  207.                               fread(&num, sizeof(num), 1, bfp);
  208.                               fread(&from, sizeof(from), 1, bfp);
  209.                                                        
  210.                               if (!num)
  211.                                    continue;
  212.                               
  213.                               node_s *pCurrent = GetWaypointFromVec(from);
  214.                          
  215.                               if (!pCurrent)
  216.                               {
  217.                                    conoutf("Error: NULL path in waypoint file");
  218.                                    
  219.                                    for(j=0;j<num;j++) fread(&to, sizeof(to), 1, bfp); // Read rest of block
  220.                                    continue;
  221.                               }
  222.  
  223.                               for (j=0; j < num; j++)
  224.                               {
  225.                                    fread(&to, sizeof(to), 1, bfp);
  226.                                    node_s *p = GetWaypointFromVec(to);
  227.                                    if (p)
  228.                                         AddPath(pCurrent, p);
  229.                               }                         
  230.                          }
  231.                     }
  232.                     else if (header.iFileVersion > WAYPOINT_VERSION)
  233.                     {
  234.                          conoutf("Error: Waypoint file is newer then current, upgrade cube bot.");
  235.                          fclose(bfp);
  236.                          return false;
  237.                     }
  238.                     else
  239.                     {
  240.                          conoutf("Error: Unknown waypoint version for cube bot");
  241.                          fclose(bfp);
  242.                          return false;
  243.                     }
  244.                }
  245.                else
  246.                {
  247.                     conoutf("Waypoints aren't for map %s but for map %s", m_szMapName,
  248.                                   header.szMapName);
  249.                     fclose(bfp);
  250.                     return false;
  251.                }
  252.           }
  253.           else
  254.           {
  255.                conoutf("Waypoint file isn't for cube bot");
  256.                //conoutf("Header FileType: %s", int(header.szFileType));
  257.  
  258.                fclose(bfp);
  259.                return false;
  260.           }
  261.  
  262.           fclose(bfp);
  263.  
  264.           //RouteInit();
  265.      }
  266.      else
  267.      {
  268.           conoutf("Waypoint file %s does not exist", (filename));
  269.           return false;
  270.      }
  271.  
  272.      if (BotManager.m_sCurrentTriggerNr == -1)
  273.           BotManager.m_sCurrentTriggerNr = 0;
  274.           
  275.      ReCalcCosts();
  276.      
  277.      conoutf("Waypoints for map %s loaded", (m_szMapName));
  278.  
  279.      testx = m_Waypoints[1][1].pNodeList;
  280.  
  281.      return true;
  282. }
  283.  
  284. void CWaypointClass::SaveWaypoints()
  285. {
  286.      char filename[256];
  287.      char mapname[64];
  288.      waypoint_header_s header;
  289.      short int num;
  290.      TLinkedList<node_s *>::node_s *pPath;
  291.  
  292.      strcpy(header.szFileType, "cube_bot");
  293.  
  294.      header.iFileVersion = WAYPOINT_VERSION;
  295.  
  296.      header.iFileFlags = 0;  // not currently used
  297.  
  298.      header.iWPCount = m_iWaypointCount;
  299.  
  300.      memset(header.szMapName, 0, sizeof(header.szMapName));
  301.      strncpy(header.szMapName, m_szMapName, 31);
  302.      header.szMapName[31] = 0;
  303.  
  304.      strcpy(mapname, m_szMapName);
  305.      strcat(mapname, ".wpt");
  306.  
  307.      BotManager.MakeBotFileName(mapname, "waypoints", NULL, filename);
  308.  
  309.      FILE *bfp = fopen(filename, "wb");
  310.  
  311.      if (!bfp)
  312.      {
  313.           conoutf("Error writing waypoint file, check if the directory \"bot/waypoint\" exists and "
  314.                        "the right permissions are set");
  315.           return;
  316.      }
  317.      
  318.      // write the waypoint header to the file...
  319.      fwrite(&header, sizeof(header), 1, bfp);
  320.      
  321.      // write the waypoint data to the file...
  322.      loopi(MAX_MAP_GRIDS)
  323.      {
  324.           loopj(MAX_MAP_GRIDS)
  325.           {
  326.                TLinkedList<node_s *>::node_s *p = m_Waypoints[i][j].GetFirst();
  327.                while(p)
  328.                {
  329.                     fwrite(&p->Entry->v_origin, sizeof(p->Entry->v_origin), 1, bfp); // Write origin
  330.                     fwrite(&p->Entry->iFlags, sizeof(p->Entry->iFlags), 1, bfp); // Write waypoint flags
  331.                     fwrite(&p->Entry->sTriggerNr, sizeof(p->Entry->sTriggerNr), 1, bfp); // Write trigger nr
  332.                     fwrite(&p->Entry->sYaw, sizeof(p->Entry->sYaw), 1, bfp); // Write target yaw
  333.                     
  334.                     p = p->next;
  335.                }               
  336.           }
  337.      }
  338.      
  339.      loopi(MAX_MAP_GRIDS)
  340.      {
  341.           loopj(MAX_MAP_GRIDS)
  342.           {
  343.                TLinkedList<node_s *>::node_s *p = m_Waypoints[i][j].GetFirst();
  344.                while(p)
  345.                {          
  346.                     // save the waypoint paths...
  347.           
  348.                     // count the number of paths from this node...
  349.                     pPath = p->Entry->ConnectedWPs.GetFirst();
  350.                     num = p->Entry->ConnectedWPs.NodeCount();
  351.                     
  352.                     fwrite(&num, sizeof(num), 1, bfp);  // write the count
  353.                     fwrite(&p->Entry->v_origin, sizeof(p->Entry->v_origin), 1, bfp); // write the origin of this path
  354.                     
  355.                     // now write out each path...          
  356.                     while (pPath != NULL)
  357.                     {
  358.                          fwrite(&pPath->Entry->v_origin, sizeof(pPath->Entry->v_origin), 1, bfp);
  359.                          pPath = pPath->next;  // go to next node in linked list
  360.                     }
  361.                     p = p->next;
  362.                }
  363.           }
  364.      }
  365.      
  366.      fclose(bfp);
  367. }
  368.  
  369. bool CWaypointClass::LoadWPExpFile()
  370. {
  371.      FILE *bfp;
  372.      char szWPFileName[64];
  373.      char filename[256];
  374.      waypoint_header_s header;
  375.      short int num;
  376.      int i, j;
  377.      vec from, to;
  378.  
  379.      if (m_iWaypointCount == 0)
  380.           return false;
  381.           
  382.      strcpy(szWPFileName, m_szMapName);
  383.      strcat(szWPFileName, ".exp");
  384.  
  385.      BotManager.MakeBotFileName(szWPFileName, "waypoints", NULL, filename);
  386.  
  387.      bfp = fopen(filename, "rb");
  388.  
  389.      // if file exists, read the waypoint structure from it
  390.      if (bfp != NULL)
  391.      {
  392.           fread(&header, sizeof(header), 1, bfp);
  393.           
  394.           header.szFileType[10] = 0;
  395.           if (strcmp(header.szFileType, "cube_bot") == 0)
  396.           {
  397.                header.szMapName[31] = 0;
  398.  
  399.                if (strcmp(header.szMapName, m_szMapName) == 0)
  400.                {
  401.                     // Check which waypoint file version this is, handle each of them different
  402.                     if (header.iFileVersion == 1)
  403.                     {                                                       
  404.                          for (i=0; i < header.iWPCount; i++)
  405.                          {
  406.                               // read the number of paths from this node...
  407.                               fread(&num, sizeof(num), 1, bfp);
  408.                               fread(&from, sizeof(vec), 1, bfp);
  409.                          
  410.                               if (!num) continue;
  411.                               
  412.                               node_s *pCurrent = GetWaypointFromVec(from);
  413.                          
  414.                               if (!pCurrent)
  415.                               {
  416.                                    conoutf("Error: NULL node in waypoint experience file");
  417.                                    continue;
  418.                               }
  419.  
  420.                               for (j=0; j < num; j++)
  421.                               {
  422.                                    fread(&to, sizeof(vec), 1, bfp);
  423.                                    node_s *p = GetWaypointFromVec(to);
  424.                                    if (p)
  425.                                    {
  426.                                         pCurrent->FailedGoalList.AddNode(p);
  427.                                    }
  428.                               }                         
  429.                          }
  430.                     }
  431.                     else if (header.iFileVersion > EXP_WP_VERSION)
  432.                     {
  433.                          conoutf("Error: Waypoint experience file is newer then current, upgrade cube bot.");
  434.                          fclose(bfp);
  435.                          return false;
  436.                     }
  437.                     else
  438.                     {
  439.                          conoutf("Error: Unknown waypoint experience file version for cube bot");
  440.                          fclose(bfp);
  441.                          return false;
  442.                     }
  443.                }
  444.                else
  445.                {
  446.                     conoutf("Waypoint experience file isn't for map %s but for map %s", (m_szMapName),
  447.                                   (header.szMapName));
  448.                     fclose(bfp);
  449.                     return false;
  450.                }
  451.           }
  452.           else
  453.           {
  454.                conoutf("Waypoint experience file isn't for cube bot");
  455.                //conoutf("Header FileType: %s", int(header.szFileType));
  456.  
  457.                fclose(bfp);
  458.                return false;
  459.           }
  460.  
  461.           fclose(bfp);
  462.  
  463.           //RouteInit();
  464.      }
  465.      else
  466.      {
  467.           conoutf("Waypoint experience file %s does not exist", (filename));
  468.           return false;
  469.      }
  470.  
  471.      conoutf("Waypoint experience file for map %s loaded", (m_szMapName));
  472.      return true;
  473. }
  474.  
  475. void CWaypointClass::SaveWPExpFile()
  476. {
  477.      if (!m_iWaypointCount)
  478.           return;
  479.           
  480.      char filename[256];
  481.      char mapname[64];
  482.      waypoint_header_s header;
  483.      short int num;
  484.  
  485.      strcpy(header.szFileType, "cube_bot");
  486.  
  487.      header.iFileVersion = EXP_WP_VERSION;
  488.  
  489.      header.iFileFlags = 0;  // not currently used
  490.  
  491.      header.iWPCount = m_iWaypointCount;
  492.  
  493.      memset(header.szMapName, 0, sizeof(header.szMapName));
  494.      strncpy(header.szMapName, m_szMapName, 31);
  495.      header.szMapName[31] = 0;
  496.  
  497.      strcpy(mapname, m_szMapName);
  498.      strcat(mapname, ".exp");
  499.  
  500.      BotManager.MakeBotFileName(mapname, "waypoints", NULL, filename);
  501.  
  502.      FILE *bfp = fopen(filename, "wb");
  503.  
  504.      if (!bfp)
  505.      {
  506.           conoutf("Error writing waypoint experience file, check if the directory \"bot/waypoint\" exists and "
  507.                        "the right permissions are set");
  508.           return;
  509.      }
  510.      
  511.      // write the waypoint header to the file...
  512.      fwrite(&header, sizeof(header), 1, bfp);
  513.          
  514.      // save the waypoint experience data...     
  515.      loopi(MAX_MAP_GRIDS)
  516.      {
  517.           loopj(MAX_MAP_GRIDS)
  518.           {
  519.                TLinkedList<node_s *>::node_s *p = m_Waypoints[i][j].GetFirst();
  520.                while(p)
  521.                {
  522.                     // count the number of paths from this node...                    
  523.                     TLinkedList<node_s *>::node_s *p2 = p->Entry->FailedGoalList.GetFirst();
  524.                     num = p->Entry->FailedGoalList.NodeCount();
  525.  
  526.                     if (!num || !p2) continue;
  527.                          
  528.                     fwrite(&num, sizeof(num), 1, bfp);  // write the count
  529.                     fwrite(&p->Entry->v_origin, sizeof(vec), 1, bfp); // write the origin of this node
  530.  
  531.                     while (p2 != NULL)
  532.                     {
  533.                          // Write out the node which a bot can't reach with the current node
  534.                          fwrite(&p2->Entry->v_origin, sizeof(vec), 1, bfp);
  535.                          p2 = p2->next;  // go to next node in linked list
  536.                     }
  537.                     p = p->next;
  538.                }
  539.           }
  540.      }
  541.      
  542.      fclose(bfp);
  543. }
  544.  
  545. void CWaypointClass::Think()
  546. {
  547.      if (dedserv) return;
  548.      
  549. #ifdef WP_FLOOD
  550.      FloodThink();
  551. #endif
  552.                    
  553.      if (m_bAutoWaypoint) // is auto waypoint on?
  554.      {
  555.           // find the distance from the last used waypoint
  556.           float flDistance = GetDistance(m_vLastCreatedWP, player1->o);
  557.  
  558.           bool NoLastCreatedWP = ((m_vLastCreatedWP.x == 0) && (m_vLastCreatedWP.y == 0) &&
  559.                                                     (m_vLastCreatedWP.z == 0));
  560.           
  561.           if ((flDistance > 3.0f) || NoLastCreatedWP)
  562.           {
  563.                // check that no other reachable waypoints are nearby...
  564.                if (!GetNearestWaypoint(player1, 10.0f))
  565.                {
  566.                     AddWaypoint(player1->o, true);  // place a waypoint here
  567.                }
  568.           }
  569.      }
  570.  
  571.      // Draw info for nearest waypoint?
  572.      if (m_bDrawWPText)
  573.      {
  574.           node_s *nearestwp = GetNearestWaypoint(player1, 20.0f);
  575.           
  576. #ifdef WP_FLOOD
  577.           if (!nearestwp)
  578.                nearestwp = GetNearestFloodWP(player1, 10.0f);
  579. #endif
  580.                
  581.           if (nearestwp)
  582.           {
  583.                char szWPInfo[256];
  584.                sprintf(szWPInfo, "Distance nearest waypoint: %f", GetDistance(player1->o, nearestwp->v_origin));
  585.                AddScreenText(szWPInfo);
  586.                               
  587.                strcpy(szWPInfo, "Flags: ");
  588.                if (nearestwp->iFlags & W_FL_TELEPORT)
  589.                     strcat(szWPInfo, "Teleport ");
  590.                if (nearestwp->iFlags & W_FL_TELEPORTDEST)
  591.                     strcat(szWPInfo, "Teleport destination ");
  592.                if (nearestwp->iFlags & W_FL_JUMP)
  593.                     strcat(szWPInfo, "Jump ");
  594.                if (nearestwp->iFlags & W_FL_TRIGGER)
  595.                {
  596.                     char sz[32];
  597.                     sprintf(sz, "Trigger(nr %d) ", nearestwp->sTriggerNr);
  598.                     strcat(szWPInfo, sz);
  599.                }
  600.                if (nearestwp->iFlags & W_FL_INTAG)
  601.                     strcat(szWPInfo, "In tagged cube(s) ");
  602.                if (strlen(szWPInfo) == 7)
  603.                     strcat(szWPInfo, "None");
  604.                                    
  605.                AddScreenText(szWPInfo);
  606.                
  607.                if (nearestwp->sYaw != -1)
  608.                     AddScreenText("yaw %d", nearestwp->sYaw);
  609.                
  610.                sprintf(szWPInfo, "Waypoint has %d connections",
  611.                        nearestwp->ConnectedWPs.NodeCount());
  612.                AddScreenText(szWPInfo);
  613.                AddScreenText("Base Cost: %d", nearestwp->sCost);
  614.           }
  615.      }
  616.   
  617.      if (m_bDrawWaypoints)  // display the waypoints if turned on...
  618.      {
  619.           DrawNearWaypoints();
  620.      }
  621. }
  622.  
  623. void CWaypointClass::DrawNearWaypoints()
  624. {
  625.      TLinkedList<node_s *>::node_s *pNode;
  626.      node_s *pNearest = NULL;
  627.      short i, j, MinI, MaxI, MinJ, MaxJ, Offset = (short)ceilf(15.0f / MAX_MAP_GRIDS);
  628.      float flNearestDist = 9999.99f, flDist;
  629.  
  630.      GetNodeIndexes(player1->o, &i, &j);
  631.      MinI = i - Offset;
  632.      MaxI = i + Offset;
  633.      MinJ = j - Offset;
  634.      MaxJ = j + Offset;
  635.  
  636.      if (MinI < 0)
  637.           MinI = 0;
  638.      if (MaxI > MAX_MAP_GRIDS - 1)
  639.           MaxI = MAX_MAP_GRIDS - 1;
  640.      if (MinJ < 0)
  641.           MinJ = 0;
  642.      if (MaxJ > MAX_MAP_GRIDS - 1)
  643.           MaxJ = MAX_MAP_GRIDS - 1;
  644.  
  645.      node_s *nearestwp = WaypointClass.GetNearestWaypoint(curselection, 20.0f);
  646.      
  647. #ifdef WP_FLOOD
  648.      if (!nearestwp)
  649.           nearestwp = GetNearestFloodWP(player1, 20.0f);
  650. #endif
  651.      
  652.      for (int x=MinI;x<=MaxI;x++)
  653.      {
  654.           for(int y=MinJ;y<=MaxJ;y++)
  655.           {
  656.                pNode = m_Waypoints[x][y].GetFirst();
  657.  
  658.                while(pNode)
  659.                {
  660.                     flDist = GetDistance(worldpos, pNode->Entry->v_origin);
  661.                     if (flDist <= 15)
  662.                     {
  663.                          vec o = pNode->Entry->v_origin;
  664.                          vec e = o;
  665.                          o.z -= 2;
  666.                          e.z += 2;
  667.                          
  668.                          if (pNode->Entry->iFlags & W_FL_JUMP)
  669.                          {
  670.                               // draw a red waypoint
  671.                               linestyle(2.5f, 0xFF, 0x40, 0x40);
  672.                          }                    
  673.                          else if (nearestwp == pNode->Entry)
  674.                          {
  675.                               // draw a green waypoint
  676.                               linestyle(2.5f, 0x40, 0xFF, 0x40);
  677.                          }
  678.                          else
  679.                          {
  680.                               // draw a blue waypoint
  681.                               linestyle(2.5f, 0x40, 0x40, 0xFF);
  682.                          }
  683.                          
  684.                          line(int(o.x), int(o.y), int(o.z), int(e.x), int(e.y), int(e.z)); 
  685.                          
  686.                          if (flNearestDist > flDist)
  687.                          {
  688.                               flNearestDist = flDist;
  689.                               pNearest = pNode->Entry;
  690.                          }                              
  691.                     }
  692.  
  693.                     pNode = pNode->next;
  694.                }
  695.           }
  696.      }
  697.  
  698.      if (pNearest)
  699.      {
  700.           pNode = pNearest->ConnectedWPs.GetFirst();
  701.           
  702.           linestyle(2.0f, 0xFF, 0xFF, 0xFF);
  703.           
  704.           while(pNode)
  705.           {
  706.                vec o = pNode->Entry->v_origin;
  707.                vec e = pNearest->v_origin;
  708.                
  709.                line(int(o.x), int(o.y), int(o.z), int(e.x), int(e.y), int(e.z));
  710.                               
  711.                pNode = pNode->next;
  712.           }
  713.           
  714.           // Has this waypoint an target yaw?
  715.           if (pNearest->sYaw != -1)
  716.           {
  717.                vec angles(0, pNearest->sYaw, 0);
  718.                vec from = pNearest->v_origin, end = pNearest->v_origin;
  719.                vec forward, right, up;
  720.                
  721.                from.z = end.z = (pNearest->v_origin.z-1.0f);
  722.                
  723.                AnglesToVectors(angles, forward, right, up);
  724.                forward.mul(5.0f);
  725.                end.add(forward);
  726.             
  727.                linestyle(2.0f, 0xFF, 0x40, 0x40);
  728.                line(int(from.x), int(from.y), int(from.z), int(end.x), int(end.y), int(end.z));
  729.           }
  730.      }
  731.  
  732. #ifndef RELEASE_BUILD                    
  733.      // check if path waypointing is on...
  734.      if (m_bDrawWPPaths)
  735.      {
  736.           // Draw path from first bot
  737.           if (bots.length() && bots[0] && bots[0]->pBot && bots[0]->pBot->m_pCurrentWaypoint &&
  738.                bots[0]->pBot->m_pCurrentGoalWaypoint)
  739.           {
  740.                CBot *pB = bots[0]->pBot;
  741.                if (!pB->m_bCalculatingAStarPath && !pB->m_AStarNodeList.Empty())
  742.                {
  743.                     TLinkedList<waypoint_s *>::node_s *pNode = pB->m_AStarNodeList.GetFirst(), *pNext;
  744.                          
  745.                     linestyle(2.5f, 0xFF, 0x40, 0x40);
  746.                          
  747.                     line((int)pB->m_pCurrentWaypoint->pNode->v_origin.x,
  748.                            (int)pB->m_pCurrentWaypoint->pNode->v_origin.y,
  749.                            (int)pB->m_pCurrentWaypoint->pNode->v_origin.z,
  750.                            (int)pNode->Entry->pNode->v_origin.x,
  751.                            (int)pNode->Entry->pNode->v_origin.y,
  752.                            (int)pNode->Entry->pNode->v_origin.z);
  753.                                 
  754.                     while(pNode && pNode->next)
  755.                     {
  756.                          pNext = pNode->next;
  757.                          vec &v1 = pNode->Entry->pNode->v_origin;
  758.                          vec &v2 = pNext->Entry->pNode->v_origin;
  759.                               
  760.                          line(int(v1.x), int(v1.y), int(v1.z), int(v2.x), int(v2.y), int(v2.z));
  761.                                    
  762.                          pNode = pNode->next;
  763.                     }
  764.                }
  765.           } 
  766.      }
  767.      
  768.      if (intermission) return;
  769.      
  770.      /*for(int i=0;i<MAX_STORED_LOCATIONS;i++)
  771.      {
  772.           if (player1->PrevLocations.prevloc[i]==g_vecZero) continue;
  773.           vec v1 = player1->PrevLocations.prevloc[i];
  774.           v1.z -= 1.0f;
  775.           vec v2 = v1;
  776.           v2.z += 2.0f;
  777.           linestyle(2.5f, 0xFF, 0x40, 0x40);
  778.           line(int(v1.x), int(v1.y), int(v1.z), int(v2.x), int(v2.y), int(v2.z));
  779.      }*/
  780. #endif     
  781. }
  782.  
  783. // Add waypoint at location o, returns pointer of created wp
  784. node_s *CWaypointClass::AddWaypoint(vec o, bool connectwp)
  785. {
  786.      short x, y;
  787.      int flags = 0;
  788.      if (S((int)o.x, (int)o.y)->tag) flags |= W_FL_INTAG;
  789.      
  790.      node_s *pNode = new node_s(o, flags, 0);
  791.      m_vLastCreatedWP = o;
  792.  
  793.      GetNodeIndexes(o, &x, &y);
  794.  
  795.      m_Waypoints[x][y].AddNode(pNode);
  796.      BotManager.AddWaypoint(pNode);
  797.      
  798.      m_iWaypointCount++;
  799.      
  800.      if (connectwp && m_bAutoPlacePaths)
  801.      {
  802.           // Connect new waypoint with other near waypoints.
  803.           
  804.           loopi(MAX_MAP_GRIDS)
  805.           {
  806.                loopj(MAX_MAP_GRIDS)
  807.                {
  808.                     TLinkedList<node_s *>::node_s *p = m_Waypoints[i][j].GetFirst();
  809.                     
  810.                     while(p)
  811.                     {
  812.                          if (p->Entry == pNode)
  813.                          {
  814.                               p = p->next;
  815.                               continue;  // skip the waypoint that was just added
  816.                          }
  817.  
  818.                          // check if the waypoint is reachable from the new one (one-way)
  819.                          if (WPIsReachable(o, p->Entry->v_origin))
  820.                               AddPath(pNode, p->Entry); // Add a path from a to b
  821.                          if (WPIsReachable(p->Entry->v_origin, pNode->v_origin))
  822.                               AddPath(p->Entry, pNode); // Add a path from b to a
  823.                               
  824.                          p = p->next;
  825.                     }
  826.                }
  827.           }
  828.      }
  829.      
  830.      return pNode;
  831. }
  832.  
  833. void CWaypointClass::DeleteWaypoint(vec v_src)
  834. {
  835.      node_s *pWP;
  836.  
  837.      pWP = GetNearestWaypoint(v_src, 7.0f);
  838.  
  839.      if (!pWP)
  840.      {
  841.           conoutf("Error: Couldn┤t find near waypoint");
  842.           return;
  843.      }
  844.      
  845.      BotManager.DelWaypoint(pWP);
  846.      
  847.      // delete any paths that lead to this index...
  848.      DeletePath(pWP);
  849.      
  850.      short x, y;
  851.      GetNodeIndexes(pWP->v_origin, &x, &y);
  852.      
  853.      m_Waypoints[x][y].DeleteEntry(pWP);
  854.      
  855.      pWP->ConnectedWPs.DeleteAllNodes();
  856.      pWP->ConnectedWPsWithMe.DeleteAllNodes();
  857.      
  858.      m_iWaypointCount--;
  859.      delete pWP;
  860. }
  861.  
  862. void CWaypointClass::AddPath(node_s *pWP1, node_s *pWP2)
  863. {
  864.      pWP1->ConnectedWPs.AddNode(pWP2);
  865.      pWP2->ConnectedWPsWithMe.AddNode(pWP1);
  866. }
  867.  
  868. // Deletes all paths connected to the given waypoint
  869. void CWaypointClass::DeletePath(node_s *pWP)
  870. {
  871.      TLinkedList<node_s *>::node_s *p;
  872.  
  873.      loopi(MAX_MAP_GRIDS)
  874.      {
  875.           loopj(MAX_MAP_GRIDS)
  876.           {
  877.                p = m_Waypoints[i][j].GetFirst();
  878.                while (p)
  879.                {
  880.                     p->Entry->ConnectedWPs.DeleteEntry(pWP);
  881.                     pWP->ConnectedWPsWithMe.DeleteEntry(p->Entry);
  882.                     p = p->next;
  883.                }
  884.           }
  885.      }
  886. }
  887.  
  888. // Deletes path between 2 waypoints(1 way)
  889. void CWaypointClass::DeletePath(node_s *pWP1, node_s *pWP2)
  890. {
  891.      pWP1->ConnectedWPs.DeleteEntry(pWP2);
  892.      pWP2->ConnectedWPsWithMe.DeleteEntry(pWP1);
  893. }
  894.  
  895. void CWaypointClass::ManuallyCreatePath(vec v_src, int iCmd, bool TwoWay)
  896. {
  897.      static node_s *waypoint1 = NULL;  // initialized to unassigned
  898.      static node_s *waypoint2 = NULL;  // initialized to unassigned
  899.  
  900.      if (iCmd == 1)  // assign source of path
  901.      {
  902.           waypoint1 = GetNearestWaypoint(v_src, 7.0f);
  903.  
  904.           if (!waypoint1)
  905.           {
  906.                conoutf("Error: Couldn't find near waypoint");
  907.                return;
  908.           }
  909.  
  910.           return;
  911.      }
  912.  
  913.      if (iCmd == 2)  // assign dest of path and make path
  914.      {
  915.           if (!waypoint1)
  916.           {
  917.                conoutf("Error: First waypoint unset");
  918.                return;
  919.           }
  920.           
  921.           waypoint2 = GetNearestWaypoint(v_src, 7.0f);
  922.  
  923.           if (!waypoint2)
  924.           {
  925.                conoutf("Error: Couldn't find near waypoint");
  926.                return;
  927.           }
  928.  
  929.           AddPath(waypoint1, waypoint2);
  930.  
  931.           if (TwoWay)
  932.                AddPath(waypoint2, waypoint1);
  933.      }
  934. }
  935.  
  936. void CWaypointClass::ManuallyDeletePath(vec v_src, int iCmd, bool TwoWay)
  937. {
  938.      static node_s *waypoint1 = NULL;  // initialized to unassigned
  939.      static node_s *waypoint2 = NULL;  // initialized to unassigned
  940.  
  941.      if (iCmd == 1)  // assign source of path
  942.      {
  943.           waypoint1 = GetNearestWaypoint(v_src, 7.0f);
  944.  
  945.           if (!waypoint1)
  946.           {
  947.                conoutf("Error: Couldn't find near waypoint");
  948.                return;
  949.           }
  950.  
  951.           return;
  952.      }
  953.  
  954.      if (iCmd == 2)  // assign dest of path and delete path
  955.      {
  956.           if (!waypoint1)
  957.           {
  958.                conoutf("Error: First waypoint unset");
  959.                return;
  960.           }
  961.           
  962.           waypoint2 = GetNearestWaypoint(v_src, 7.0f);
  963.  
  964.           if (!waypoint2)
  965.           {
  966.                conoutf("Error: Couldn't find near waypoint");
  967.                return;
  968.           }
  969.  
  970.           DeletePath(waypoint1, waypoint2);
  971.  
  972.           if (TwoWay)
  973.                DeletePath(waypoint2, waypoint1);
  974.      }
  975. }
  976.  
  977. bool CWaypointClass::WPIsReachable(vec from, vec to)
  978. {
  979.      traceresult_s tr;
  980.      float curr_height, last_height;
  981.  
  982.      float distance = GetDistance(from, to);
  983.  
  984.      // is the destination close enough?
  985.      if (distance < REACHABLE_RANGE)
  986.      {
  987.           if (IsVisible(from, to))
  988.           {                              
  989.                if (UnderWater(from) && UnderWater(to))
  990.                {
  991.                     // No need to worry about heights in water
  992.                     return true;
  993.                }
  994. /*
  995.                if (to.z > (from.z + JUMP_HEIGHT))
  996.                {
  997.                     vec v_new_src = to;
  998.                     vec v_new_dest = to;
  999.  
  1000.                     v_new_dest.z = v_new_dest.z - (JUMP_HEIGHT + 1.0f);
  1001.  
  1002.                     // check if we didn't hit anything, if so then it's in mid-air
  1003.                     if (::IsVisible(v_new_src, v_new_dest, NULL))
  1004.                     {
  1005.                          conoutf("to is in midair");
  1006.                          debugbeam(from, to);
  1007.                          return false;  // can't reach this one
  1008.                     }
  1009.                }
  1010. */
  1011.  
  1012.                // check if distance to ground increases more than jump height
  1013.                // at points between from and to...
  1014.  
  1015.                vec v_temp = to;
  1016.                v_temp.sub(from);
  1017.                vec v_direction = Normalize(v_temp);  // 1 unit long
  1018.                vec v_check = from;
  1019.                vec v_down = from;
  1020.  
  1021.                v_down.z = v_down.z - 100.0f;  // straight down
  1022.  
  1023.                TraceLine(v_check, v_down, NULL, false, &tr);
  1024.  
  1025.                  // height from ground
  1026.                last_height = GetDistance(v_check, tr.end);
  1027.  
  1028.                distance = GetDistance(to, v_check);  // distance from goal
  1029.  
  1030.                while (distance > 2.0f)
  1031.                {
  1032.                     // move 2 units closer to the goal
  1033.                     v_temp = v_direction;
  1034.                     v_temp.mul(2.0f);
  1035.                     v_check.add(v_temp);
  1036.  
  1037.                     v_down = v_check;
  1038.                     v_down.z = v_down.z - 100.0f;
  1039.  
  1040.                     TraceLine(v_check, v_down, NULL, false, &tr);
  1041.  
  1042.                     curr_height = GetDistance(v_check, tr.end);
  1043.  
  1044.                     // is the difference in the last height and the current height
  1045.                     // higher that the jump height?
  1046.                     if ((last_height - curr_height) >= JUMP_HEIGHT)
  1047.                     {
  1048.                          // can't get there from here...
  1049.                          //conoutf("traces failed to to");
  1050.                          return false;
  1051.                     }
  1052.  
  1053.                     last_height = curr_height;
  1054.  
  1055.                     distance = GetDistance(to, v_check);  // distance from goal
  1056.                }
  1057.  
  1058.                return true;
  1059.           }
  1060.      }
  1061.  
  1062.      return false;
  1063. }
  1064.  
  1065. node_s *CWaypointClass::GetNearestWaypoint(vec v_src, float flRange)
  1066. {
  1067.      TLinkedList<node_s *>::node_s *pNode;
  1068.      node_s *pNearest = NULL;
  1069.      short i, j, MinI, MaxI, MinJ, MaxJ, Offset = (short)ceil(flRange / MAX_MAP_GRIDS);
  1070.      float flNearestDist = 9999.99f, flDist;
  1071.  
  1072.      GetNodeIndexes(v_src, &i, &j);
  1073.      MinI = i - Offset;
  1074.      MaxI = i + Offset;
  1075.      MinJ = j - Offset;
  1076.      MaxJ = j + Offset;
  1077.  
  1078.      if (MinI < 0)
  1079.           MinI = 0;
  1080.      if (MaxI > MAX_MAP_GRIDS - 1)
  1081.           MaxI = MAX_MAP_GRIDS - 1;
  1082.      if (MinJ < 0)
  1083.           MinJ = 0;
  1084.      if (MaxJ > MAX_MAP_GRIDS - 1)
  1085.           MaxJ = MAX_MAP_GRIDS - 1;
  1086.  
  1087.      for (int x=MinI;x<=MaxI;x++)
  1088.      {
  1089.           for(int y=MinJ;y<=MaxJ;y++)
  1090.           {
  1091.                pNode = m_Waypoints[x][y].GetFirst();
  1092.  
  1093.                while(pNode)
  1094.                {
  1095.                     flDist = GetDistance(v_src, pNode->Entry->v_origin);
  1096.                     if ((flDist < flNearestDist) && (flDist <= flRange))
  1097.                     {
  1098.                          if (IsVisible(v_src, pNode->Entry->v_origin, NULL))
  1099.                          {
  1100.                               pNearest = pNode->Entry;
  1101.                               flNearestDist = flDist;
  1102.                          }
  1103.                     }
  1104.  
  1105.                     pNode = pNode->next;
  1106.                }
  1107.           }
  1108.      }
  1109.      return pNearest;
  1110. }
  1111.  
  1112. node_s *CWaypointClass::GetNearestTriggerWaypoint(vec v_src, float flRange)
  1113. {
  1114.      TLinkedList<node_s *>::node_s *pNode;
  1115.      node_s *pNearest = NULL;
  1116.      short i, j, MinI, MaxI, MinJ, MaxJ, Offset = (short)ceil(flRange / MAX_MAP_GRIDS);
  1117.      float flNearestDist = 9999.99f, flDist;
  1118.  
  1119.      GetNodeIndexes(v_src, &i, &j);
  1120.      MinI = i - Offset;
  1121.      MaxI = i + Offset;
  1122.      MinJ = j - Offset;
  1123.      MaxJ = j + Offset;
  1124.  
  1125.      if (MinI < 0)
  1126.           MinI = 0;
  1127.      if (MaxI > MAX_MAP_GRIDS - 1)
  1128.           MaxI = MAX_MAP_GRIDS - 1;
  1129.      if (MinJ < 0)
  1130.           MinJ = 0;
  1131.      if (MaxJ > MAX_MAP_GRIDS - 1)
  1132.           MaxJ = MAX_MAP_GRIDS - 1;
  1133.  
  1134.      for (int x=MinI;x<=MaxI;x++)
  1135.      {
  1136.           for(int y=MinJ;y<=MaxJ;y++)
  1137.           {
  1138.                pNode = m_Waypoints[x][y].GetFirst();
  1139.  
  1140.                while(pNode)
  1141.                {
  1142.                     if ((pNode->Entry->iFlags & W_FL_FLOOD) || !(pNode->Entry->iFlags & W_FL_TRIGGER))
  1143.                     {
  1144.                          pNode = pNode->next;
  1145.                          continue;
  1146.                     }
  1147.                
  1148.                     flDist = GetDistance(v_src, pNode->Entry->v_origin);
  1149.                     if ((flDist < flNearestDist) && (flDist <= flRange))
  1150.                     {
  1151.                          if (IsVisible(v_src, pNode->Entry->v_origin, NULL))
  1152.                          {
  1153.                               pNearest = pNode->Entry;
  1154.                               flNearestDist = flDist;
  1155.                          }
  1156.                     }
  1157.  
  1158.                     pNode = pNode->next;
  1159.                }
  1160.           }
  1161.      }
  1162.      return pNearest;
  1163. }
  1164.  
  1165. node_s *CWaypointClass::GetWaypointFromVec(const vec &v_src)
  1166. {
  1167.      static TLinkedList<node_s *>::node_s *pNode;
  1168.      static short x, y;
  1169.  
  1170.      GetNodeIndexes(v_src, &x, &y);
  1171.      
  1172.      pNode = m_Waypoints[x][y].GetFirst();
  1173.  
  1174.      while(pNode)
  1175.      {
  1176.           if (pNode->Entry->v_origin==v_src)
  1177.                return pNode->Entry;
  1178.                     
  1179.           pNode = pNode->next;
  1180.      }
  1181.      return NULL;
  1182. }
  1183.  
  1184. void CWaypointClass::CalcCost(node_s *pNode)
  1185. {
  1186.      float flCost = 10.0f;
  1187.  
  1188.      // Check nearby cubes...
  1189.      int x = int(pNode->v_origin.x);
  1190.      int y = int(pNode->v_origin.y);
  1191.      int a, b, row;
  1192.      
  1193.      for (row=0;row<=1;row++)
  1194.      {
  1195.           if (row==0) b = y - 6;
  1196.           else b = y + 6;
  1197.  
  1198.           for (a=(x-6);a<=(x+6);a++)
  1199.           {
  1200.                if (OUTBORD(a, b)) continue;
  1201.                
  1202.                vec to(a, b, GetCubeFloor(a, b) + 1.0f);
  1203.                
  1204.                // See if there is a obstacle(cube or mapmodel) nearby          
  1205.                traceresult_s tr;
  1206.                TraceLine(pNode->v_origin, to, NULL, false, &tr);
  1207.                if (tr.collided)
  1208.                {
  1209.                     float flFraction = (GetDistance(pNode->v_origin, tr.end) /
  1210.                                         GetDistance(pNode->v_origin, to));
  1211.                     flCost += (1.0f-flFraction)*0.5f;
  1212.                }
  1213.                
  1214.                if ((abs(a) > 4) || (abs(b) > 4)) continue;
  1215.                
  1216.                vec from = to;
  1217.                to.z -= (JUMP_HEIGHT - 1.0f);
  1218.                TraceLine(from, to, NULL, false, &tr);
  1219.                if (!tr.collided)
  1220.                     flCost += 0.5f;
  1221.           }
  1222.           
  1223.           if (row==0) a = x - 6;
  1224.           else a = x + 6;
  1225.  
  1226.           for (b=(y-6);b<=(y+6);b++)
  1227.           {
  1228.                if (OUTBORD(a, b)) continue;
  1229.                
  1230.                vec to(a, b, GetCubeFloor(a, b) + 1.0f);
  1231.                
  1232.                // See if there is a obstacle(cube or mapmodel) nearby          
  1233.                traceresult_s tr;
  1234.                TraceLine(pNode->v_origin, to, NULL, false, &tr);
  1235.                if (tr.collided)
  1236.                {
  1237.                     float flFraction = (GetDistance(pNode->v_origin, tr.end) /
  1238.                                         GetDistance(pNode->v_origin, to));
  1239.                     flCost += (1.0f-flFraction)*0.5f;
  1240.                }
  1241.                
  1242.                if ((abs(a) > 4) || (abs(b) > 4)) continue;
  1243.                
  1244.                vec from = to;
  1245.                to.z -= (JUMP_HEIGHT - 1.0f);
  1246.                TraceLine(from, to, NULL, false, &tr);
  1247.                if (!tr.collided)
  1248.                     flCost += 0.5f;
  1249.           }
  1250.      }
  1251.          
  1252.      if (UnderWater(pNode->v_origin)) // Water is annoying
  1253.           flCost += 5.0f;
  1254.      
  1255.      pNode->sCost = (short)flCost;          
  1256. }
  1257.  
  1258. void CWaypointClass::ReCalcCosts(void)
  1259. {
  1260.      loopi(MAX_MAP_GRIDS)
  1261.      {
  1262.           loopj(MAX_MAP_GRIDS)
  1263.           {
  1264.                TLinkedList<node_s *>::node_s *p = m_Waypoints[i][j].GetFirst();
  1265.                while(p)
  1266.                {
  1267.                     CalcCost(p->Entry);
  1268.                     p = p->next;
  1269.                }
  1270.           }
  1271.      }
  1272. }
  1273.  
  1274. #ifdef WP_FLOOD
  1275.  
  1276. void CWaypointClass::StartFlood()
  1277. {
  1278.      if (m_bFlooding) return;
  1279.      
  1280.      conoutf("Starting flood, this may take a while on large maps....");
  1281.      m_bFlooding = true;
  1282.      m_iFloodStartTime = SDL_GetTicks();
  1283.      m_iCurFloodX = m_iCurFloodY = MINBORD;
  1284.      m_iFloodSize = 0;
  1285. }
  1286.  
  1287. void CWaypointClass::FloodThink()
  1288. {
  1289.      if (!m_bFlooding) return;
  1290.      
  1291.      static int x, y, count;
  1292.      count = 0;
  1293.      
  1294.      if (!m_bFilteringNodes)
  1295.      {
  1296.           // loop through ALL cubes and check if we should add a waypoint here
  1297.           for (x=m_iCurFloodX; x<(ssize-MINBORD); x+=4)
  1298.           {
  1299.                if (count >= 3)
  1300.                {
  1301.                     AddScreenText("Flooding map with waypoints... %.2f %%",
  1302.                                   ((float)x / float(ssize-MINBORD)) * 100.0f);
  1303.                     m_iCurFloodX = x;
  1304.                     return;
  1305.                }
  1306.           
  1307.                count++;
  1308.  
  1309.                for (y=MINBORD; y<(ssize-MINBORD); y+=4)
  1310.                {               
  1311.                     vec from(x, y, GetCubeFloor(x, y)+2.0f);
  1312.                     bool bFound = CanPlaceNodeHere(from);
  1313.                     
  1314.                     if (!bFound)
  1315.                     {
  1316.                          for (int a=x-2;a<=(x+2);a++)
  1317.                          {
  1318.                               for (int b=y-2;b<=(y+2);b++)
  1319.                               {
  1320.                                    if (OUTBORD(a, b)) continue;
  1321.                                    if ((a==x) && (b==y)) continue;
  1322.                                    makevec(&from, a, b, GetCubeFloor(a, b) + 2.0f);
  1323.                                    if (CanPlaceNodeHere(from))
  1324.                                    {
  1325.                                         bFound = true;
  1326.                                         break;
  1327.                                    }
  1328.                               }
  1329.                               
  1330.                               if (bFound) break;
  1331.                          }
  1332.                     }
  1333.                     
  1334.                     if (!bFound) continue;
  1335.                     
  1336.                     // Add WP
  1337.                     int flags = W_FL_FLOOD;
  1338.                     if (S((int)from.x, (int)from.y)->tag) flags |= W_FL_INTAG;
  1339.                     
  1340.                     node_s *pWP = new node_s(from, flags, 0);
  1341.                
  1342.                     short i, j;
  1343.                     GetNodeIndexes(from, &i, &j);
  1344.                     m_Waypoints[i][j].PushNode(pWP);
  1345.                     BotManager.AddWaypoint(pWP);
  1346.                     m_iFloodSize += sizeof(node_s);
  1347.                     m_iWaypointCount++;               
  1348.                
  1349.                     // Connect with other nearby nodes
  1350.                     ConnectFloodWP(pWP);
  1351.                }
  1352.           }
  1353.      }
  1354.           
  1355.      if (!m_bFilteringNodes)
  1356.      {
  1357.           m_bFilteringNodes = true;
  1358.           m_iCurFloodX = m_iCurFloodY = 0;
  1359.           m_iFilteredNodes = 0;
  1360.      }
  1361.      
  1362.      count = 0;
  1363.      
  1364.      // Filter all nodes which aren't connected to any other nodes
  1365.      for (x=m_iCurFloodX;x<MAX_MAP_GRIDS;x++)
  1366.      {
  1367.           if (count > 3)
  1368.           {
  1369.                AddScreenText("Filtering useless waypoints and");
  1370.                AddScreenText("adding costs... %.2f %%", ((float)x / float(MAX_MAP_GRIDS)) * 100.0f);
  1371.                m_iCurFloodX = x;
  1372.                return;
  1373.           }
  1374.  
  1375.           count++;
  1376.                               
  1377.           for (y=0;y<MAX_MAP_GRIDS;y++)
  1378.           {
  1379.                TLinkedList<node_s *>::node_s *pNode = m_Waypoints[x][y].GetFirst(), *pTemp;
  1380.                while(pNode)
  1381.                {
  1382.                     if (pNode->Entry->ConnectedWPs.Empty() ||
  1383.                          pNode->Entry->ConnectedWPsWithMe.Empty())
  1384.                     {
  1385.                          BotManager.DelWaypoint(pNode->Entry);
  1386.                          pTemp = pNode;
  1387.                          pNode = pNode->next;
  1388.                          delete pTemp->Entry;
  1389.                          m_Waypoints[x][y].DeleteNode(pTemp);
  1390.                          m_iFilteredNodes++;
  1391.                          m_iFloodSize -= sizeof(node_s);
  1392.                          m_iWaypointCount--;
  1393.                          continue;
  1394.                     }
  1395.                     else
  1396.                          CalcCost(pNode->Entry);
  1397.                     pNode = pNode->next;
  1398.                }
  1399.           }
  1400.      }
  1401.      
  1402.      // Done with flooding
  1403.      m_bFlooding = false;
  1404.      m_bFilteringNodes = false;
  1405.      
  1406.      //ReCalcCosts();
  1407.      BotManager.PickNextTrigger();
  1408.                         
  1409.      m_iFloodSize += sizeof(m_Waypoints);
  1410.      conoutf("Added %d wps in %d milliseconds", m_iWaypointCount, SDL_GetTicks()-m_iFloodStartTime);
  1411.      conoutf("Filtered %d wps", m_iFilteredNodes);
  1412.      
  1413.      BotManager.CalculateMaxAStarCount();
  1414.      
  1415.      char szSize[64];
  1416.      sprintf(szSize, "Total size: %.2f Kb", float(m_iFloodSize)/1024.0f);
  1417.      conoutf(szSize);
  1418. }
  1419.  
  1420. bool CWaypointClass::CanPlaceNodeHere(const vec &from)
  1421. {
  1422.      static short x, y, a, b;
  1423.      static traceresult_s tr;
  1424.      static vec to, v1, v2;
  1425.      
  1426.      x = short(from.x);
  1427.      y = short(from.y);
  1428.      
  1429.      sqr *s = S(x, y);
  1430.      if (SOLID(s))
  1431.      {
  1432.           return false;
  1433.      }
  1434.                
  1435.      if (fabs((float)(s->ceil - s->floor)) < player1->radius)
  1436.      {
  1437.           return false;
  1438.      }
  1439.  
  1440.      if (GetNearestFloodWP(from, 2.0f, NULL)) return false;
  1441.                
  1442.      for (a=(x-1);a<=(x+1);a++)
  1443.      {
  1444.           for (b=(y-1);b<=(y+1);b++)
  1445.           {
  1446.                if ((x==a) && (y==b)) continue;
  1447.                if (OUTBORD(a, b)) return false;
  1448.                makevec(&v1, a, b, from.z);
  1449.                v2 = v1;
  1450.                v2.z -= 1000.0f;
  1451.                
  1452.                TraceLine(v1, v2, NULL, false, &tr, true);
  1453.                to = tr.end;
  1454.                          
  1455.                if ((a >= (x-1)) && (a <= (x+1)) && (b >= (y-1)) && (b <= (y+1)))
  1456.                {
  1457.                     if (!tr.collided || (to.z < (from.z-4.0f)))
  1458.                     {
  1459.                          return false;
  1460.                     }
  1461.                }
  1462.                          
  1463.                to.z += 2.0f;
  1464.                
  1465.                if (from.z < (to.z-JUMP_HEIGHT))
  1466.                {
  1467.                     return false;
  1468.                }                         
  1469.                          
  1470.                TraceLine(from, to, NULL, false, &tr, true);
  1471.                if (tr.collided)
  1472.                     return false;
  1473.           }
  1474.      }
  1475.  
  1476.      return true;
  1477. }
  1478.  
  1479. void CWaypointClass::ConnectFloodWP(node_s *pWP)
  1480. {
  1481.      if (!pWP) return;
  1482.      
  1483.      static float flRange;
  1484.      static TLinkedList<node_s *>::node_s *pNode;
  1485.      static short i, j, MinI, MaxI, MinJ, MaxJ, x, y, Offset;
  1486.      static float flDist;
  1487.      static node_s *p;
  1488.      
  1489.      // Calculate range, based on distance to nearest node
  1490.      p = GetNearestFloodWP(pWP->v_origin, 15.0f, pWP, true);
  1491.      if (p)
  1492.      {
  1493.           flDist = GetDistance(pWP->v_origin, p->v_origin);
  1494.           flRange = min(flDist+2.0f, 15.0f);
  1495.           if (flRange < 5.0f) flRange = 5.0f;
  1496.      }
  1497.      else
  1498.           return;
  1499.           
  1500.      Offset = (short)ceil(flRange / MAX_MAP_GRIDS);
  1501.  
  1502.      GetNodeIndexes(pWP->v_origin, &i, &j);
  1503.      MinI = i - Offset;
  1504.      MaxI = i + Offset;
  1505.      MinJ = j - Offset;
  1506.      MaxJ = j + Offset;
  1507.  
  1508.      if (MinI < 0)
  1509.           MinI = 0;
  1510.      if (MaxI > MAX_MAP_GRIDS - 1)
  1511.           MaxI = MAX_MAP_GRIDS - 1;
  1512.      if (MinJ < 0)
  1513.           MinJ = 0;
  1514.      if (MaxJ > MAX_MAP_GRIDS - 1)
  1515.           MaxJ = MAX_MAP_GRIDS - 1;
  1516.  
  1517.      for (x=MinI;x<=MaxI;x++)
  1518.      {
  1519.           for(y=MinJ;y<=MaxJ;y++)
  1520.           {
  1521.                pNode = m_Waypoints[x][y].GetFirst();
  1522.  
  1523.                while(pNode)
  1524.                {
  1525.                     if (pNode->Entry == pWP)
  1526.                     {
  1527.                          pNode = pNode->next;
  1528.                          continue;
  1529.                     }
  1530.  
  1531.                     flDist = GetDistance(pWP->v_origin, pNode->Entry->v_origin);
  1532.                     if (flDist <= flRange)
  1533.                     {
  1534.                          if (IsVisible(pWP->v_origin, pNode->Entry->v_origin, NULL, true))
  1535.                          {
  1536.                               // Connect a with b
  1537.                               pWP->ConnectedWPs.AddNode(pNode->Entry);
  1538.                               pNode->Entry->ConnectedWPsWithMe.AddNode(pWP);
  1539.                               
  1540.                               // Connect b with a
  1541.                               pNode->Entry->ConnectedWPs.AddNode(pWP);
  1542.                               pWP->ConnectedWPsWithMe.AddNode(pNode->Entry);
  1543.                               
  1544.                               m_iFloodSize += (2 * sizeof(node_s *));
  1545.                          }
  1546.                     }
  1547.  
  1548.                     pNode = pNode->next;
  1549.                }
  1550.           }
  1551.      }
  1552. }
  1553.  
  1554. node_s *CWaypointClass::GetNearestFloodWP(vec v_origin, float flRange, node_s *pIgnore,
  1555.                                           bool SkipTags)
  1556. {
  1557.      TLinkedList<node_s *>::node_s *p;
  1558.      node_s *pNearest = NULL;
  1559.      short i, j, MinI, MaxI, MinJ, MaxJ, Offset = (short)ceil(flRange / MAX_MAP_GRIDS);
  1560.      float flNearestDist = 9999.99f, flDist;
  1561.  
  1562.      GetNodeIndexes(v_origin, &i, &j);
  1563.      MinI = i - Offset;
  1564.      MaxI = i + Offset;
  1565.      MinJ = j - Offset;
  1566.      MaxJ = j + Offset;
  1567.  
  1568.      if (MinI < 0)
  1569.           MinI = 0;
  1570.      if (MaxI > MAX_MAP_GRIDS - 1)
  1571.           MaxI = MAX_MAP_GRIDS - 1;
  1572.      if (MinJ < 0)
  1573.           MinJ = 0;
  1574.      if (MaxJ > MAX_MAP_GRIDS - 1)
  1575.           MaxJ = MAX_MAP_GRIDS - 1;
  1576.  
  1577.      for (int x=MinI;x<=MaxI;x++)
  1578.      {
  1579.           for(int y=MinJ;y<=MaxJ;y++)
  1580.           {
  1581.                p = m_Waypoints[x][y].GetFirst();
  1582.  
  1583.                while(p)
  1584.                {
  1585.                     if ((p->Entry == pIgnore) || (!(p->Entry->iFlags & W_FL_FLOOD)))
  1586.                     {
  1587.                          p = p->next;
  1588.                          continue;
  1589.                     }
  1590.  
  1591.                     flDist = GetDistance(v_origin, p->Entry->v_origin);
  1592.                     if ((flDist < flNearestDist) && (flDist <= flRange))
  1593.                     {
  1594.                          if (IsVisible(v_origin, p->Entry->v_origin, NULL, SkipTags))
  1595.                          {
  1596.                               pNearest = p->Entry;
  1597.                               flNearestDist = flDist;
  1598.                          }
  1599.                     }
  1600.  
  1601.                     p = p->next;
  1602.                }
  1603.           }
  1604.      }
  1605.      return pNearest;
  1606. }
  1607.  
  1608. node_s *CWaypointClass::GetNearestTriggerFloodWP(vec v_origin, float flRange)
  1609. {
  1610.      TLinkedList<node_s *>::node_s *p;
  1611.      node_s *pNearest = NULL;
  1612.      short i, j, MinI, MaxI, MinJ, MaxJ, Offset = (short)ceil(flRange / MAX_MAP_GRIDS);
  1613.      float flNearestDist = 9999.99f, flDist;
  1614.  
  1615.      GetNodeIndexes(v_origin, &i, &j);
  1616.      MinI = i - Offset;
  1617.      MaxI = i + Offset;
  1618.      MinJ = j - Offset;
  1619.      MaxJ = j + Offset;
  1620.  
  1621.      if (MinI < 0)
  1622.           MinI = 0;
  1623.      if (MaxI > MAX_MAP_GRIDS - 1)
  1624.           MaxI = MAX_MAP_GRIDS - 1;
  1625.      if (MinJ < 0)
  1626.           MinJ = 0;
  1627.      if (MaxJ > MAX_MAP_GRIDS - 1)
  1628.           MaxJ = MAX_MAP_GRIDS - 1;
  1629.  
  1630.      for (int x=MinI;x<=MaxI;x++)
  1631.      {
  1632.           for(int y=MinJ;y<=MaxJ;y++)
  1633.           {
  1634.                p = m_Waypoints[x][y].GetFirst();
  1635.  
  1636.                while(p)
  1637.                {
  1638.                     if (!(p->Entry->iFlags & (W_FL_FLOOD | W_FL_TRIGGER)))
  1639.                     {
  1640.                          p = p->next;
  1641.                          continue;
  1642.                     }
  1643.  
  1644.                     flDist = GetDistance(v_origin, p->Entry->v_origin);
  1645.                     if ((flDist < flNearestDist) && (flDist <= flRange))
  1646.                     {
  1647.                          if (IsVisible(v_origin, p->Entry->v_origin, NULL))
  1648.                          {
  1649.                               pNearest = p->Entry;
  1650.                               flNearestDist = flDist;
  1651.                          }
  1652.                     }
  1653.  
  1654.                     p = p->next;
  1655.                }
  1656.           }
  1657.      }
  1658.      return pNearest;
  1659. }
  1660.  
  1661. void CWaypointClass::GetNodeIndexes(const vec &v_origin, short *i, short *j)
  1662. {
  1663.      // Function code by cheesy and PMB
  1664.      //*i = abs((int)((int)(v_origin.x + (2*ssize)) / SECTOR_SIZE));
  1665.      //*j = abs((int)((int)(v_origin.y + (2*ssize)) / SECTOR_SIZE));
  1666.      //*i = (int)((v_origin.x) / ssize * MAX_MAP_GRIDS);
  1667.      //*j = (int)((v_origin.y) / ssize * MAX_MAP_GRIDS);
  1668.      *i = abs((int)((v_origin.x) / MAX_MAP_GRIDS));
  1669.      *j = abs((int)((v_origin.y) / MAX_MAP_GRIDS));
  1670.  
  1671.      if (*i > MAX_MAP_GRIDS - 1)
  1672.           *i = MAX_MAP_GRIDS - 1;
  1673.      if (*j > MAX_MAP_GRIDS - 1)
  1674.           *j = MAX_MAP_GRIDS - 1;
  1675. }
  1676.  
  1677. #endif // WP_FLOOD
  1678. // Waypoint class end
  1679.  
  1680. #if defined AC_CUBE
  1681.  
  1682. // AC waypoint class begin
  1683. void CACWaypointClass::StartFlood()
  1684.      // UNDONE?    
  1685.      CWaypointClass::StartFlood();
  1686. }
  1687.  
  1688. // AC waypoint class end
  1689.  
  1690. #elif defined VANILLA_CUBE
  1691.  
  1692. // Cube waypoint class begin
  1693.  
  1694. void CCubeWaypointClass::StartFlood()
  1695. {
  1696.      CWaypointClass::StartFlood();
  1697.      
  1698.      // Add wps at triggers and teleporters and their destination
  1699.      loopv(ents)
  1700.      {
  1701.           entity &e = ents[i];
  1702.           
  1703.           if (OUTBORD(e.x, e.y)) continue;
  1704.  
  1705.           if (e.type == TELEPORT)
  1706.           {
  1707.                vec telepos = { e.x, e.y, S(e.x, e.y)->floor+player1->eyeheight }, teledestpos = g_vecZero;
  1708.           
  1709.                // Find the teleport destination          
  1710.                int n = -1, tag = e.attr1, beenhere = -1;
  1711.                for(;;)
  1712.                {
  1713.                     n = findentity(TELEDEST, n+1);
  1714.                     if(n==beenhere || n<0) { conoutf("no teleport destination for tag %d", tag); break; };
  1715.                     if(beenhere<0) beenhere = n;
  1716.                     if(ents[n].attr2==tag)
  1717.                     {
  1718.                          teledestpos.x = ents[n].x;
  1719.                          teledestpos.y = ents[n].y;
  1720.                          teledestpos.z = S(ents[n].x, ents[n].y)->floor+player1->eyeheight;
  1721.                          break;
  1722.                     }
  1723.                }
  1724.           
  1725.                if (vis(teledestpos, g_vecZero)) continue;
  1726.           
  1727.                int flags = (W_FL_FLOOD | W_FL_TELEPORT);
  1728.                if (S((int)telepos.x, (int)telepos.y)->tag) flags |= W_FL_INTAG;
  1729.                
  1730.                // Add waypoint at teleporter and teleport destination
  1731.                node_s *pWP = new node_s(telepos, flags, 0);
  1732.                
  1733.                short i, j;
  1734.                GetNodeIndexes(telepos, &i, &j);
  1735.                m_Waypoints[i][j].PushNode(pWP);
  1736.                BotManager.AddWaypoint(pWP);
  1737.                m_iFloodSize += sizeof(node_s);               
  1738.                m_iWaypointCount++;
  1739.           
  1740.                flags = (W_FL_FLOOD | W_FL_TELEPORTDEST);
  1741.                if (S((int)teledestpos.x, (int)teledestpos.y)->tag) flags |= W_FL_INTAG;
  1742.  
  1743.                node_s *pWP2 = new node_s(teledestpos, flags, 0);
  1744.           
  1745.                GetNodeIndexes(teledestpos, &i, &j);
  1746.                m_Waypoints[i][j].PushNode(pWP2);
  1747.                BotManager.AddWaypoint(pWP2);
  1748.                m_iFloodSize += sizeof(node_s);               
  1749.                m_iWaypointCount++;
  1750.           
  1751.                // Connect the teleporter waypoint with the teleport-destination waypoint(1 way)
  1752.                AddPath(pWP, pWP2);
  1753.                
  1754.                // Connect with other nearby nodes
  1755.                ConnectFloodWP(pWP);               
  1756.           }
  1757.           else if (e.type == CARROT)
  1758.           {
  1759.                vec pos = { e.x, e.y, S(e.x, e.y)->floor+player1->eyeheight };
  1760.                
  1761.                int flags = (W_FL_FLOOD | W_FL_TRIGGER);
  1762.                if (S(e.x, e.y)->tag) flags |= W_FL_INTAG;
  1763.                
  1764.                node_s *pWP = new node_s(pos, flags, 0);
  1765.                
  1766.                short i, j;
  1767.                GetNodeIndexes(pos, &i, &j);
  1768.                m_Waypoints[i][j].PushNode(pWP);
  1769.                BotManager.AddWaypoint(pWP);
  1770.                m_iFloodSize += sizeof(node_s);               
  1771.                m_iWaypointCount++;
  1772.                
  1773.                // Connect with other nearby nodes
  1774.                ConnectFloodWP(pWP);               
  1775.           }
  1776.           else if (e.type == MAPMODEL)
  1777.           {
  1778.                mapmodelinfo &mmi = getmminfo(e.attr2);
  1779.                if(!&mmi || !mmi.h || !mmi.rad) continue;
  1780.     
  1781.                float floor = (float)(S(e.x, e.y)->floor+mmi.zoff+e.attr3)+mmi.h;
  1782.               
  1783.                float x1 = e.x - mmi.rad;
  1784.                float x2 = e.x + mmi.rad;
  1785.                float y1 = e.y - mmi.rad;
  1786.                float y2 = e.y + mmi.rad;
  1787.  
  1788.                // UNDONE?
  1789.                for (float x=(x1+1.0f);x<=(x2-1.0f);x++)
  1790.                {
  1791.                     for (float y=(y1+1.0f);y<=(y2-1.0f);y++)
  1792.                     {
  1793.                          vec from = { x, y, floor+2.0f };
  1794.                          if (GetNearestFloodWP(from, 2.0f, NULL)) continue;
  1795.                                        
  1796.                          // Add WP
  1797.                          int flags = W_FL_FLOOD;
  1798.                          if (S((int)x, (int)y)->tag) flags |= W_FL_INTAG;
  1799.                          
  1800.                          node_s *pWP = new node_s(from, flags, 0);
  1801.                
  1802.                          short i, j;
  1803.                          GetNodeIndexes(from, &i, &j);
  1804.                          m_Waypoints[i][j].PushNode(pWP);
  1805.                          BotManager.AddWaypoint(pWP);
  1806.                          m_iFloodSize += sizeof(node_s);               
  1807.                          m_iWaypointCount++;
  1808.                
  1809.                          // Connect with other nearby nodes
  1810.                          ConnectFloodWP(pWP);
  1811.                     }
  1812.                }
  1813.           }    
  1814.      }
  1815.      CWaypointClass::StartFlood();
  1816. }
  1817.  
  1818. void CCubeWaypointClass::CreateWPsAtTeleporters()
  1819. {
  1820.      loopv(ents)
  1821.      {
  1822.           entity &e = ents[i];
  1823.           
  1824.           if (e.type != TELEPORT) continue;
  1825.           if (OUTBORD(e.x, e.y)) continue;
  1826.  
  1827.           vec telepos = { e.x, e.y, S(e.x, e.y)->floor+player1->eyeheight }, teledestpos = g_vecZero;
  1828.           
  1829.           // Find the teleport destination          
  1830.           int n = -1, tag = e.attr1, beenhere = -1;
  1831.           for(;;)
  1832.           {
  1833.                n = findentity(TELEDEST, n+1);
  1834.                if(n==beenhere || n<0) { conoutf("no teleport destination for tag %d", tag); continue; };
  1835.                if(beenhere<0) beenhere = n;
  1836.                if(ents[n].attr2==tag)
  1837.                {
  1838.                     teledestpos.x = ents[n].x;
  1839.                     teledestpos.y = ents[n].y;
  1840.                     teledestpos.z = S(ents[n].x, ents[n].y)->floor+player1->eyeheight;
  1841.                     break;
  1842.                }
  1843.           }
  1844.           
  1845.           if (vis(teledestpos, g_vecZero)) continue;
  1846.           
  1847.           // Add waypoint at teleporter and teleport destination
  1848.           node_s *telewp = AddWaypoint(telepos, false);
  1849.           node_s *teledestwp = AddWaypoint(teledestpos, false);
  1850.           
  1851.           if (telewp && teledestwp)
  1852.           {
  1853.                // Connect the teleporter waypoint with the teleport-destination waypoint(1 way)
  1854.                AddPath(telewp, teledestwp);
  1855.                
  1856.                // Flag waypoints
  1857.                telewp->iFlags = W_FL_TELEPORT;
  1858.                teledestwp->iFlags = W_FL_TELEPORTDEST;
  1859.           }
  1860.      }
  1861. }
  1862.                          
  1863. void CCubeWaypointClass::CreateWPsAtTriggers()
  1864. {
  1865.      loopv(ents)
  1866.      {
  1867.           entity &e = ents[i];
  1868.           
  1869.           if (e.type != CARROT) continue;
  1870.           if (OUTBORD(e.x, e.y)) continue;
  1871.  
  1872.           vec pos = { e.x, e.y, S(e.x, e.y)->floor+player1->eyeheight };
  1873.           
  1874.           node_s *wp = AddWaypoint(pos, false);
  1875.           
  1876.           if (wp)
  1877.           {
  1878.                // Flag waypoints
  1879.                wp->iFlags = W_FL_TRIGGER;
  1880.           }
  1881.      }
  1882. }
  1883.  
  1884. #endif
  1885.  
  1886. // Cube waypoint class end
  1887.  
  1888. // Waypoint commands begin
  1889.  
  1890. void addwp(int autoconnect)
  1891. {
  1892.      WaypointClass.SetWaypointsVisible(true);
  1893.      WaypointClass.AddWaypoint(curselection, autoconnect!=0);
  1894. }
  1895.  
  1896. COMMAND(addwp, ARG_1INT);
  1897.  
  1898. void delwp(void)
  1899. {
  1900.      WaypointClass.SetWaypointsVisible(true);
  1901.      WaypointClass.DeleteWaypoint(curselection);
  1902. }
  1903.      
  1904. COMMAND(delwp, ARG_NONE);
  1905.  
  1906. void wpvisible(int on)
  1907. {
  1908.      WaypointClass.SetWaypointsVisible(on!=0);
  1909. }
  1910.  
  1911. COMMAND(wpvisible, ARG_1INT);
  1912.  
  1913. void wpsave(void)
  1914. {
  1915.      WaypointClass.SaveWaypoints();
  1916. }
  1917.  
  1918. COMMAND(wpsave, ARG_NONE);
  1919.  
  1920. void wpload(void)
  1921. {
  1922.      WaypointClass.LoadWaypoints();
  1923. }
  1924.  
  1925. COMMAND(wpload, ARG_NONE);
  1926.  
  1927. void wpclear(void)
  1928. {
  1929.     WaypointClass.Clear();
  1930. }
  1931.  
  1932. COMMAND(wpclear, ARG_NONE);
  1933.  
  1934. void autowp(int on)
  1935. {
  1936.      WaypointClass.SetWaypointsVisible(true);
  1937.      WaypointClass.SetAutoWaypoint(on!=0);
  1938. }
  1939.  
  1940. COMMAND(autowp, ARG_1INT);
  1941.  
  1942. void wpinfo(int on)
  1943. {
  1944.      WaypointClass.SetWaypointsVisible(true);
  1945.      WaypointClass.SetWPInfo(on!=0);
  1946. }
  1947.  
  1948. COMMAND(wpinfo, ARG_1INT);
  1949.  
  1950. void addpath1way1(void)
  1951. {
  1952.      WaypointClass.SetWaypointsVisible(true);
  1953.      WaypointClass.ManuallyCreatePath(curselection, 1, false);
  1954. }
  1955.  
  1956. COMMAND(addpath1way1, ARG_NONE);
  1957.  
  1958. void addpath1way2(void)
  1959. {
  1960.      WaypointClass.SetWaypointsVisible(true);
  1961.      WaypointClass.ManuallyCreatePath(curselection, 2, false);
  1962. }
  1963.  
  1964. COMMAND(addpath1way2, ARG_NONE);
  1965.  
  1966. void addpath2way1(void)
  1967. {
  1968.      WaypointClass.SetWaypointsVisible(true);
  1969.      WaypointClass.ManuallyCreatePath(curselection, 1, true);
  1970. }
  1971.  
  1972. COMMAND(addpath2way1, ARG_NONE);
  1973.  
  1974. void addpath2way2(void)
  1975. {
  1976.      WaypointClass.SetWaypointsVisible(true);
  1977.      WaypointClass.ManuallyCreatePath(curselection, 2, true);
  1978. }
  1979.  
  1980. COMMAND(addpath2way2, ARG_NONE);
  1981.  
  1982. void delpath1way1(void)
  1983. {
  1984.      WaypointClass.SetWaypointsVisible(true);
  1985.      WaypointClass.ManuallyDeletePath(curselection, 1, false);
  1986. }
  1987.  
  1988. COMMAND(delpath1way1, ARG_NONE);
  1989.  
  1990. void delpath1way2(void)
  1991. {
  1992.      WaypointClass.SetWaypointsVisible(true);
  1993.      WaypointClass.ManuallyDeletePath(curselection, 2, false);
  1994. }
  1995.  
  1996. COMMAND(delpath1way2, ARG_NONE);
  1997.  
  1998. void delpath2way1(void)
  1999. {
  2000.      WaypointClass.SetWaypointsVisible(true);
  2001.      WaypointClass.ManuallyDeletePath(curselection, 1, true);
  2002. }
  2003.  
  2004. COMMAND(delpath2way1, ARG_NONE);
  2005.  
  2006. void delpath2way2(void)
  2007. {
  2008.      WaypointClass.SetWaypointsVisible(true);
  2009.      WaypointClass.ManuallyDeletePath(curselection, 2, true);
  2010. }
  2011.  
  2012. COMMAND(delpath2way2, ARG_NONE);
  2013.  
  2014. void setjumpwp(void)
  2015. {
  2016.      node_s *wp = WaypointClass.GetNearestWaypoint(curselection, 20.0f);
  2017.      if (wp)
  2018.      {
  2019.           WaypointClass.SetWPFlags(wp, W_FL_JUMP);
  2020.      }
  2021. }
  2022.  
  2023. COMMAND(setjumpwp, ARG_NONE);
  2024.  
  2025. void unsetjumpwp(void)
  2026. {
  2027.      node_s *wp = WaypointClass.GetNearestWaypoint(curselection, 20.0f);
  2028.      if (wp)
  2029.      {
  2030.           WaypointClass.UnsetWPFlags(wp, W_FL_JUMP);
  2031.      }
  2032. }
  2033.  
  2034. COMMAND(unsetjumpwp, ARG_NONE);
  2035.  
  2036. void setwptriggernr(int nr)
  2037. {
  2038.      node_s *wp = WaypointClass.GetNearestWaypoint(curselection, 20.0f);
  2039.      if (wp)
  2040.      {
  2041.           WaypointClass.SetWPTriggerNr(wp, nr);
  2042.      }
  2043. }
  2044.  
  2045. COMMAND(setwptriggernr, ARG_1INT);
  2046.  
  2047. void setwpyaw(void)
  2048. {
  2049.      node_s *wp = WaypointClass.GetNearestWaypoint(curselection, 20.0f);
  2050.      if (wp)
  2051.      {
  2052.           WaypointClass.SetWPYaw(wp, short(player1->yaw));
  2053.      }
  2054. }
  2055.  
  2056. COMMAND(setwpyaw, ARG_NONE);
  2057.  
  2058. #ifdef WP_FLOOD
  2059. void wpflood(void)
  2060. {
  2061.      WaypointClass.StartFlood();
  2062. }
  2063.  
  2064. COMMAND(wpflood, ARG_NONE);
  2065. #endif
  2066.  
  2067. #ifdef VANILLA_CUBE
  2068. // Commands specific for cube
  2069. void addtelewps(void)
  2070. {
  2071.      WaypointClass.SetWaypointsVisible(true);
  2072.      WaypointClass.CreateWPsAtTeleporters();
  2073. }
  2074.  
  2075. COMMAND(addtelewps, ARG_NONE);
  2076.  
  2077. void addtriggerwps(void)
  2078. {
  2079.      WaypointClass.SetWaypointsVisible(true);
  2080.      WaypointClass.CreateWPsAtTriggers();
  2081. }
  2082.  
  2083. COMMAND(addtriggerwps, ARG_NONE);
  2084. #endif
  2085.  
  2086. // Debug functions
  2087. #ifdef WP_FLOOD
  2088.  
  2089. #ifndef RELEASE_BUILD
  2090. void botsheadtome(void)
  2091. {
  2092.      loopv(bots)
  2093.      {
  2094.           if (!bots[i] || !bots[i]->pBot) continue;
  2095.           
  2096.           bots[i]->pBot->GoToDebugGoal(player1->o);
  2097.      }
  2098. }
  2099.  
  2100. COMMAND(botsheadtome, ARG_NONE);
  2101.  
  2102. void setdebuggoal(void) { v_debuggoal = player1->o; };
  2103. COMMAND(setdebuggoal, ARG_NONE);
  2104.  
  2105. void botsheadtodebuggoal(void)
  2106. {
  2107.      loopv(bots)
  2108.      {
  2109.           if (!bots[i] || !bots[i]->pBot) continue;
  2110.           
  2111.           bots[i]->pBot->GoToDebugGoal(v_debuggoal);
  2112.      }
  2113. }
  2114.  
  2115. COMMAND(botsheadtodebuggoal, ARG_NONE);
  2116.  
  2117. #endif // RELEASE_BUILD
  2118.  
  2119. #endif // WP_FLOOD
  2120.  
  2121. // End debug functions
  2122. // Waypoint commands end
  2123.  
  2124.  
  2125. // Bot class begin
  2126.  
  2127. bool CBot::FindWaypoint()
  2128. {
  2129.      waypoint_s *wp, *wpselect;
  2130.      int index;
  2131.      float distance, min_distance[3];
  2132.      waypoint_s *min_wp[3];
  2133.  
  2134.      for (index=0; index < 3; index++)
  2135.      {
  2136.           min_distance[index] = 9999.0;
  2137.           min_wp[index] = NULL;
  2138.      }
  2139.  
  2140.      TLinkedList<node_s *>::node_s *pNode = m_pCurrentWaypoint->pNode->ConnectedWPs.GetFirst();
  2141.  
  2142.      while (pNode)
  2143.      {
  2144.           if ((pNode->Entry->iFlags & W_FL_INTAG) &&
  2145.               SOLID(S((int)pNode->Entry->v_origin.x, (int)pNode->Entry->v_origin.y)))
  2146.           {
  2147.                pNode = pNode->next;
  2148.                continue;
  2149.           }
  2150.      
  2151.           wp = GetWPFromNode(pNode->Entry);
  2152.           if (!wp)
  2153.           {
  2154.                pNode = pNode->next;
  2155.                continue;
  2156.           }
  2157.                     
  2158.           // if index is not a current or recent previous waypoint...
  2159.           if ((wp != m_pCurrentWaypoint) &&
  2160.               (wp != m_pPrevWaypoints[0]) &&
  2161.               (wp != m_pPrevWaypoints[1]) &&
  2162.               (wp != m_pPrevWaypoints[2]) &&
  2163.               (wp != m_pPrevWaypoints[3]) &&
  2164.               (wp != m_pPrevWaypoints[4]))
  2165.           {
  2166.                // find the distance from the bot to this waypoint
  2167.                distance = GetDistance(wp->pNode->v_origin);
  2168.  
  2169.                if (distance < min_distance[0])
  2170.                {
  2171.                     min_distance[2] = min_distance[1];
  2172.                     min_wp[2] = min_wp[1];
  2173.  
  2174.                     min_distance[1] = min_distance[0];
  2175.                     min_wp[1] = min_wp[0];
  2176.  
  2177.                     min_distance[0] = distance;
  2178.                     min_wp[0] = wp;
  2179.                }
  2180.                else if (distance < min_distance [1])
  2181.                {
  2182.                     min_distance[2] = min_distance[1];
  2183.                     min_wp[2] = min_wp[1];
  2184.  
  2185.                     min_distance[1] = distance;
  2186.                     min_wp[1] = wp;
  2187.                }
  2188.                else if (distance < min_distance[2])
  2189.                {
  2190.                     min_distance[2] = distance;
  2191.                     min_wp[2] = wp;
  2192.                }
  2193.           }
  2194.           pNode = pNode->next;
  2195.      }
  2196.  
  2197.      wpselect = NULL;
  2198.  
  2199.      // about 20% of the time choose a waypoint at random
  2200.      // (don't do this any more often than every 10 seconds)
  2201.  
  2202.      if ((RandomLong(1, 100) <= 20) && (m_iRandomWaypointTime <= lastmillis))
  2203.      {
  2204.           m_iRandomWaypointTime = lastmillis + 10000;
  2205.  
  2206.           if (min_wp[2])
  2207.                index = RandomLong(0, 2);
  2208.           else if (min_wp[1])
  2209.                index = RandomLong(0, 1);
  2210.           else if (min_wp[0])
  2211.                index = 0;
  2212.           else
  2213.                return false;  // no waypoints found!
  2214.  
  2215.           wpselect = min_wp[index];
  2216.      }
  2217.      else
  2218.      {
  2219.           // use the closest waypoint that has been recently used
  2220.           wpselect = min_wp[0];
  2221.      }
  2222.  
  2223.      if (wpselect)  // was a waypoint found?
  2224.      {
  2225.           m_pPrevWaypoints[4] = m_pPrevWaypoints[3];
  2226.           m_pPrevWaypoints[3] = m_pPrevWaypoints[2];
  2227.           m_pPrevWaypoints[2] = m_pPrevWaypoints[1];
  2228.           m_pPrevWaypoints[1] = m_pPrevWaypoints[0];
  2229.           m_pPrevWaypoints[0] = m_pCurrentWaypoint;
  2230.  
  2231.           SetCurrentWaypoint(wpselect);
  2232.           return true;
  2233.      }
  2234.  
  2235.      return false;  // couldn't find a waypoint
  2236. }
  2237.  
  2238. bool CBot::HeadToWaypoint()
  2239. {
  2240.      if (!m_pCurrentWaypoint)
  2241.           return false; // Can't head to waypoint
  2242.  
  2243.      bool Touching = false;
  2244.      float WPDist = GetDistance(m_pCurrentWaypoint->pNode->v_origin);
  2245.  
  2246. #ifndef RELEASE_BUILD
  2247.      if (m_pCurrentGoalWaypoint && m_vGoal==g_vecZero)
  2248.           condebug("Warning: m_vGoal unset");
  2249. #endif
  2250.  
  2251.      // did the bot run past the waypoint? (prevent the loop-the-loop problem)
  2252.      if ((m_fPrevWaypointDistance > 1.0) && (WPDist > m_fPrevWaypointDistance) &&
  2253.          (WPDist <= 5.0f))
  2254.           Touching = true;
  2255.      // bot needs to be close for jump and trigger waypoints
  2256.      else if ((m_pCurrentWaypoint->pNode->iFlags & W_FL_JUMP) ||
  2257.                 (m_pCurrentWaypoint->pNode->iFlags & W_FL_TRIGGER))
  2258.           Touching = (WPDist <= 1.5f);
  2259.      else if (m_pCurrentWaypoint->pNode->iFlags & W_FL_TELEPORT)
  2260.           Touching = (WPDist <= 4.0f);
  2261.      // are we close enough to a target waypoint...
  2262.      else if (WPDist <= 3.0f)
  2263.      {
  2264.           if (!m_pCurrentGoalWaypoint || (m_pCurrentWaypoint != m_pCurrentGoalWaypoint) ||
  2265.                IsVisible(m_vGoal) || (WPDist <= 1.5f))
  2266.                Touching = true;
  2267.           // If the bot has a goal check if he can see his next wp
  2268.           if (m_pCurrentGoalWaypoint && (m_pCurrentGoalWaypoint != m_pCurrentWaypoint) &&
  2269.              !m_AStarNodeList.Empty() && (WPDist >= 1.0f) &&
  2270.              !IsVisible(m_AStarNodeList.GetFirst()->Entry->pNode->v_origin))
  2271.                Touching = false;
  2272.      }
  2273.      
  2274.      // save current distance as previous
  2275.      m_fPrevWaypointDistance = WPDist;
  2276.  
  2277.      // Reached the waypoint?
  2278.      if (Touching)
  2279.      {
  2280.           // Does this waypoint has a targetyaw?
  2281.           if (m_pCurrentWaypoint->pNode->sYaw != -1)
  2282.           {
  2283.                // UNDONE: Inhuman
  2284.                m_pMyEnt->yaw = m_pMyEnt->targetyaw = m_pCurrentWaypoint->pNode->sYaw;
  2285.           }
  2286.           
  2287.           // Reached a jump waypoint?
  2288.           if (m_pCurrentWaypoint->pNode->iFlags & W_FL_JUMP)
  2289.                m_pMyEnt->jumpnext = true;
  2290.                               
  2291.           m_fPrevWaypointDistance = 0.0f;
  2292.  
  2293.           // Does the bot has a goal?
  2294.           if (m_pCurrentGoalWaypoint)
  2295.           {               
  2296.                if (m_pCurrentWaypoint != m_pCurrentGoalWaypoint)
  2297.                {
  2298.                     if (m_AStarNodeList.Empty())
  2299.                     {
  2300.                          if (!AStar())
  2301.                          {
  2302.                               // Bot is calculating a new path, just stand still for now
  2303.                               ResetMoveSpeed();
  2304.                               m_iWaypointTime += 200;
  2305.                               return true;
  2306.                          }
  2307.                          else
  2308.                          {
  2309.                               if (m_AStarNodeList.Empty())
  2310.                               {
  2311.                                    //m_UnreachableNodes.PushNode(unreachable_node_s(m_pCurrentGoalWaypoint, gpGlobals->time));
  2312.                                    return false; // Couldn't get a new wp to go to
  2313.                               }
  2314.                          }
  2315.                     }
  2316.                                         
  2317.                     m_pCurrentWaypoint = m_AStarNodeList.Pop();
  2318.  
  2319.                     if (!IsVisible(m_pCurrentWaypoint->pNode->v_origin)) 
  2320.                         //(!(m_pCurrentWaypoint->iFlags & W_FL_TELEPORT)))
  2321.                     {
  2322.                          //m_UnreachableNodes.PushNode(unreachable_node_s(m_pCurrentGoalWaypoint, gpGlobals->time));
  2323.                          condebug("Next WP not visible");
  2324.                          return false;
  2325.                     }
  2326.  
  2327.                     SetCurrentWaypoint(m_pCurrentWaypoint);
  2328.                }
  2329.                else
  2330.                {
  2331.                     // Bot reached the goal waypoint but couldn't reach the goal itself
  2332.                     // (otherwise we wouldn't be in this function)
  2333.                     //m_UnreachableNodes.PushNode(unreachable_node_s(m_pCurrentGoalWaypoint, gpGlobals->time));
  2334.                     return false;
  2335.                }
  2336.           }
  2337.           else
  2338.           {
  2339.                short index = 4;
  2340.                bool status;
  2341.  
  2342.                // try to find the next waypoint
  2343.                while (((status = FindWaypoint()) == false) && (index > 0))
  2344.                {
  2345.                     // if waypoint not found, clear oldest previous index and try again
  2346.  
  2347.                     m_pPrevWaypoints[index] = NULL;
  2348.                     index--;
  2349.                }
  2350.  
  2351.                if (status == false)
  2352.                {
  2353.                     ResetWaypointVars();
  2354.                     condebug("Couldn't find new random waypoint");
  2355.                     return false;
  2356.                }
  2357.           }
  2358.           m_iWaypointHeadPauseTime = lastmillis + 75;
  2359.           m_iWaypointTime += 75;          
  2360.      }
  2361.  
  2362.      // keep turning towards the waypoint...
  2363.      /*if (m_pCurrentWaypoint->pNode->iFlags & W_FL_FLOOD)
  2364.      {UNDONE?
  2365.           vec aim = m_pCurrentWaypoint->pNode->v_origin;
  2366.           aim.x+=0.5f;
  2367.           aim.y+=0.5f;
  2368.           AimToVec(aim);
  2369.      }
  2370.      else*/
  2371.           AimToVec(m_pCurrentWaypoint->pNode->v_origin);
  2372.  
  2373.      if (m_fYawToTurn <= 25.0f)
  2374.           m_iWaypointHeadLastTurnLessTime = lastmillis;
  2375.  
  2376.      // Bot had to turn much for a while?
  2377.      if ((m_iWaypointHeadLastTurnLessTime > 0) &&
  2378.          (m_iWaypointHeadLastTurnLessTime < (lastmillis - 1000)))
  2379.      {
  2380.           m_iWaypointHeadPauseTime = lastmillis + 200;
  2381.           m_iWaypointTime += 200;
  2382.      }
  2383.  
  2384.      if (m_iWaypointHeadPauseTime >= lastmillis)
  2385.      {
  2386.           m_pMyEnt->move = 0;
  2387.           //conoutf("Pause in HeadToWaypoint()");
  2388.      }
  2389.      else
  2390.      {
  2391.           // Check if bot has to jump
  2392.           vec from = m_pMyEnt->o;
  2393.           from.z -= (m_pMyEnt->eyeheight - 1.25f);
  2394.           float flEndDist;
  2395.           if (!IsVisible(from, FORWARD, 3.0f, false, &flEndDist) &&
  2396.               (GetDistance(from, m_pCurrentWaypoint->pNode->v_origin) > flEndDist))
  2397.           {
  2398.                m_pMyEnt->jumpnext = true;
  2399.                condebug("Low wall in HeadToWaypoint()");
  2400.           }
  2401.      
  2402.           // Check if bot has to strafe
  2403.           if (m_iStrafeTime > lastmillis)
  2404.                SetMoveDir(m_iMoveDir, true);
  2405.           else
  2406.           {
  2407.                m_iStrafeTime = 0;
  2408.                m_iMoveDir = DIR_NONE;
  2409.                
  2410.                vec forward, up, right;
  2411.                AnglesToVectors(GetViewAngles(), forward, right, up);
  2412.                
  2413.                float flLeftDist = -1.0f, flRightDist = -1.0f;          
  2414.                vec dir = right;
  2415.                bool bStrafe = false;
  2416.                int iStrafeDir = 0;
  2417.           
  2418.                dir.mul(m_pMyEnt->radius);
  2419.           
  2420.                // Check left
  2421.                from = m_pMyEnt->o;
  2422.                from.sub(dir);
  2423.                if (IsVisible(from, FORWARD, 3.0f, false, &flLeftDist))
  2424.                     flLeftDist = -1.0f;
  2425.  
  2426.                // Check right
  2427.                from = m_pMyEnt->o;
  2428.                from.add(dir);
  2429.                if (IsVisible(from, FORWARD, 3.0f, false, &flRightDist))
  2430.                     flRightDist = -1.0f;
  2431.           
  2432.                if ((flLeftDist != -1.0f) && (flRightDist != -1.0f))
  2433.                {
  2434.                     if (flLeftDist < flRightDist)
  2435.                     {
  2436.                          // Strafe right
  2437.                          bStrafe = true;
  2438.                          iStrafeDir = RIGHT;
  2439.                     }
  2440.                     else if (flRightDist < flLeftDist)
  2441.                     {
  2442.                          // Strafe left
  2443.                          bStrafe = true;
  2444.                          iStrafeDir = LEFT;
  2445.                     }
  2446.                     else
  2447.                     {
  2448.                          // Randomly choose a strafe direction
  2449.                          bStrafe = true;
  2450.                          if (RandomLong(0, 1))
  2451.                               iStrafeDir = LEFT;
  2452.                          else
  2453.                               iStrafeDir = RIGHT;
  2454.                     }
  2455.                }
  2456.                else if (flLeftDist != -1.0f)
  2457.                {
  2458.                     // Strafe right
  2459.                     bStrafe = true;
  2460.                     iStrafeDir = RIGHT;
  2461.                }
  2462.                else if (flRightDist != -1.0f)
  2463.                {
  2464.                     // Strafe left
  2465.                     bStrafe = true;
  2466.                     iStrafeDir = LEFT;
  2467.                }
  2468.      
  2469.                if (bStrafe)
  2470.                {
  2471.                     SetMoveDir(iStrafeDir, true);
  2472.                     m_iMoveDir = iStrafeDir;
  2473.                     m_iStrafeTime = lastmillis + RandomLong(30, 50);
  2474.                }
  2475.           }
  2476.      }
  2477.      
  2478.      return true;
  2479. }
  2480.  
  2481. // returns true when done or failure
  2482. bool CBot::HeadToGoal()
  2483. {
  2484.      // Does the bot has a goal(waypoint)?
  2485.      if (m_pCurrentGoalWaypoint)
  2486.      {
  2487.           if (ReachedGoalWP())
  2488.           {
  2489.                return false;
  2490.           }
  2491.           else
  2492.           {
  2493.                if (CurrentWPIsValid())
  2494.                {
  2495.                     if (m_bCalculatingAStarPath)
  2496.                     {
  2497.                          // Bot is calculating a new path, just stand still for now
  2498.                          ResetMoveSpeed();
  2499.                          m_iWaypointTime += 200;
  2500.  
  2501.                          // Done calculating the path?
  2502.                          if (AStar())
  2503.                          {
  2504.                               if (m_AStarNodeList.Empty())
  2505.                               {
  2506.                                    return false; // Couldn't find a path
  2507.                               }
  2508.                               //else
  2509.                                //    SetCurrentWaypoint(m_AStarNodeList.Pop());
  2510.                          }
  2511.                          else
  2512.                               return true; // else just wait a little bit longer
  2513.                     }
  2514.                     //ResetMoveSpeed();
  2515.                     //return true;                    
  2516.                }
  2517.                else
  2518.                {
  2519.                     // Current waypoint isn't reachable, search new one
  2520.                     waypoint_s *pWP = NULL;
  2521.  
  2522. #ifdef WP_FLOOD                                        
  2523.                     if (m_pCurrentGoalWaypoint->pNode->iFlags & W_FL_FLOOD)
  2524.                          pWP = GetNearestFloodWP(8.0f);
  2525.                     else
  2526. #endif                    
  2527.                          pWP = GetNearestWaypoint(15.0f);
  2528.  
  2529.                     if (!pWP || (pWP == m_pCurrentWaypoint))
  2530.                          return false;
  2531.                                         
  2532.                     SetCurrentWaypoint(pWP);
  2533.                     if (AStar())
  2534.                     {
  2535.                          if (m_AStarNodeList.Empty()) return false;
  2536.                     }
  2537.                     else
  2538.                     {
  2539.                          m_iWaypointTime += 200;
  2540.                          ResetMoveSpeed();
  2541.                          return true;
  2542.                     }
  2543.                }
  2544.                
  2545.                //debugbeam(m_pMyEnt->o, m_pCurrentWaypoint->pNode->v_origin);               
  2546.           }
  2547.      }
  2548.      else
  2549.           return false;
  2550.                     
  2551.      return HeadToWaypoint();
  2552. }
  2553.  
  2554. // return true when done calculating
  2555. bool CBot::AStar()
  2556. {
  2557.      if (!m_pCurrentGoalWaypoint || !m_pCurrentWaypoint)
  2558.      {
  2559.           if (m_bCalculatingAStarPath)
  2560.           {
  2561.                m_bCalculatingAStarPath = false;
  2562.                BotManager.m_sUsingAStarBotsCount--;
  2563.           }
  2564.           return true;
  2565.      }
  2566.      
  2567.      // Ideas by PMB :
  2568.      // * Make locals static to speed up a bit
  2569.      // * MaxCycles per frame and make it fps dependent
  2570.  
  2571.      static int iMaxCycles;
  2572.      static int iCurrentCycles;
  2573.      static short newg;
  2574.      static waypoint_s *n, *n2;
  2575.      static TLinkedList<node_s *>::node_s *pPath = NULL;
  2576.      static bool bPathFailed;
  2577.  
  2578.      iMaxCycles = BotManager.m_iFrameTime / 10;
  2579.      if (iMaxCycles < 10) iMaxCycles = 10;
  2580.      //condebug("MaxCycles: %d", iMaxCycles);
  2581.      iCurrentCycles = 0;
  2582.      bPathFailed = false;
  2583.  
  2584.      if (!m_bCalculatingAStarPath)
  2585.      {
  2586.           if ((BotManager.m_sUsingAStarBotsCount+1) > BotManager.m_sMaxAStarBots)
  2587.           {
  2588.                return true;
  2589.           }
  2590.      
  2591.           BotManager.m_sUsingAStarBotsCount++;
  2592.           
  2593.           CleanAStarLists(false);
  2594.           
  2595.           m_pCurrentWaypoint->g[0] = m_pCurrentWaypoint->g[1] = 0;
  2596.           m_pCurrentWaypoint->pParent[0] = m_pCurrentWaypoint->pParent[1] = NULL;        
  2597.           m_pCurrentGoalWaypoint->g[0] = m_pCurrentGoalWaypoint->g[1] = 0;
  2598.           m_pCurrentGoalWaypoint->pParent[0] = m_pCurrentGoalWaypoint->pParent[1] = NULL;
  2599.  
  2600.           m_AStarNodeList.DeleteAllNodes();
  2601.                     
  2602.           m_AStarOpenList[0].Clear();
  2603.           m_AStarOpenList[1].Clear();
  2604.           m_AStarClosedList[0].DeleteAllNodes();
  2605.           m_AStarClosedList[1].DeleteAllNodes();
  2606.           
  2607.           m_AStarOpenList[0].AddEntry(m_pCurrentWaypoint,
  2608.                                       GetDistance(m_pCurrentGoalWaypoint->pNode->v_origin));
  2609.           m_AStarOpenList[1].AddEntry(m_pCurrentGoalWaypoint,
  2610.                                       GetDistance(m_pCurrentGoalWaypoint->pNode->v_origin));
  2611.           
  2612.           m_pCurrentWaypoint->bIsOpen[0] = m_pCurrentGoalWaypoint->bIsOpen[1] = true;
  2613.           m_pCurrentWaypoint->bIsOpen[1] = m_pCurrentGoalWaypoint->bIsOpen[0] = false;
  2614.           m_pCurrentWaypoint->bIsClosed[0] = m_pCurrentGoalWaypoint->bIsClosed[1] = false;
  2615.           m_pCurrentWaypoint->bIsClosed[1] = m_pCurrentGoalWaypoint->bIsClosed[0] = false;
  2616.      }
  2617.      
  2618.      while(!m_AStarOpenList[0].Empty())
  2619.      {
  2620.           if (iCurrentCycles >= (iMaxCycles/2))
  2621.           {
  2622.                m_bCalculatingAStarPath = true;
  2623.                break;
  2624.           }
  2625.  
  2626.           n = m_AStarOpenList[0].Pop();
  2627.           n->bIsOpen[0] = false;
  2628.          
  2629.           if (n->pNode->FailedGoalList.IsInList(m_pCurrentGoalWaypoint->pNode))
  2630.           {
  2631.                bPathFailed = true;
  2632.                break; // Can't make path to goal
  2633.           }
  2634.                     
  2635.           // Done with calculating
  2636.           if (n == m_pCurrentGoalWaypoint)
  2637.           {
  2638.                m_bCalculatingAStarPath = false;
  2639.                BotManager.m_sUsingAStarBotsCount--;
  2640.           
  2641.                while(n)
  2642.                {
  2643.                     m_AStarNodeList.PushNode(n);                    
  2644.                     n = n->pParent[0];
  2645.                }
  2646.  
  2647.                CleanAStarLists(false);               
  2648.                
  2649.                return true;
  2650.           }
  2651.  
  2652.           pPath = n->pNode->ConnectedWPs.GetFirst();
  2653.           while(pPath)
  2654.           {
  2655.                if ((pPath->Entry->iFlags & W_FL_INTAG) &&
  2656.                     SOLID(S((int)pPath->Entry->v_origin.x, (int)pPath->Entry->v_origin.y)))
  2657.                {
  2658.                     pPath = pPath->next;
  2659.                     continue;
  2660.                }
  2661.           
  2662.                n2 = GetWPFromNode(pPath->Entry);
  2663.                
  2664.                if (!n2)
  2665.                {
  2666.                     pPath = pPath->next;
  2667.                     continue;
  2668.                }
  2669.                
  2670.                if (n2->bIsClosed[1])
  2671.                {
  2672.                     m_bCalculatingAStarPath = false;
  2673.                     BotManager.m_sUsingAStarBotsCount--;
  2674.                     
  2675.                     while(n2)
  2676.                     {
  2677.                          m_AStarNodeList.AddNode(n2);
  2678.                          n2 = n2->pParent[1];
  2679.                     }
  2680.                
  2681.                     while(n)
  2682.                     {
  2683.                          m_AStarNodeList.PushNode(n);                    
  2684.                          n = n->pParent[0];
  2685.                     }
  2686.  
  2687.                     CleanAStarLists(false);
  2688.                
  2689.                     return true;
  2690.                }
  2691.                
  2692.                newg = n->g[0] + (short)AStarCost(n, n2);
  2693.  
  2694.                if ((n2->g[0] <= newg) && (n2->bIsOpen[0] || n2->bIsClosed[0]))
  2695.                {
  2696.                     pPath = pPath->next;
  2697.                     continue;
  2698.                }
  2699.                
  2700.                n2->pParent[0] = n;
  2701.                n2->g[0] = newg;
  2702.                n2->bIsClosed[0] = false;
  2703.  
  2704.                if (!n2->bIsOpen[0])
  2705.                {
  2706.                     m_AStarOpenList[0].AddEntry(n2, n2->g[1] + GetDistance(n2->pNode->v_origin,
  2707.                                                  m_pCurrentGoalWaypoint->pNode->v_origin));
  2708.                     n2->bIsOpen[0] = true;
  2709.                }
  2710.                pPath = pPath->next;
  2711.           }
  2712.           
  2713.           m_AStarClosedList[0].PushNode(n);
  2714.           n->bIsClosed[0] = true;
  2715.           iCurrentCycles++;
  2716.      }
  2717.      
  2718.      if (!bPathFailed)
  2719.      {
  2720.           while(!m_AStarOpenList[1].Empty())
  2721.           {
  2722.                if (iCurrentCycles >= iMaxCycles)
  2723.                {
  2724.                     m_bCalculatingAStarPath = true;
  2725.                     return false;
  2726.                }
  2727.  
  2728.                n = m_AStarOpenList[1].Pop();
  2729.                n->bIsOpen[1] = false;
  2730.          
  2731.                if (n->pNode->FailedGoalList.IsInList(m_pCurrentWaypoint->pNode))
  2732.                {
  2733.                     bPathFailed = true;
  2734.                     break; // Can't make path to goal
  2735.                }
  2736.                     
  2737.                // Done with calculating
  2738.                if (n == m_pCurrentWaypoint)
  2739.                {
  2740.                     m_bCalculatingAStarPath = false;
  2741.                     BotManager.m_sUsingAStarBotsCount--;
  2742.                            
  2743.                     while(n)
  2744.                     {
  2745.                          m_AStarNodeList.AddNode(n);                    
  2746.                          n = n->pParent[1];
  2747.                     }    
  2748.  
  2749.                     CleanAStarLists(false);               
  2750.                
  2751.                     return true;
  2752.                }
  2753.  
  2754.                pPath = n->pNode->ConnectedWPsWithMe.GetFirst();
  2755.                while(pPath)
  2756.                {
  2757.                     if ((pPath->Entry->iFlags & W_FL_INTAG) &&
  2758.                         SOLID(S((int)pPath->Entry->v_origin.x, (int)pPath->Entry->v_origin.y)))
  2759.                     {
  2760.                          pPath = pPath->next;
  2761.                          continue;
  2762.                     }
  2763.                
  2764.                     n2 = GetWPFromNode(pPath->Entry);
  2765.                     
  2766.                     if (!n2)
  2767.                     {
  2768.                          pPath = pPath->next;
  2769.                          continue;
  2770.                     }
  2771.                     
  2772.                     if (n2->bIsClosed[0])
  2773.                     {
  2774.                          m_bCalculatingAStarPath = false;
  2775.                          BotManager.m_sUsingAStarBotsCount--;
  2776.                     
  2777.                          while(n2)
  2778.                          {
  2779.                               m_AStarNodeList.PushNode(n2);
  2780.                               n2 = n2->pParent[0];
  2781.                          }
  2782.                
  2783.                          while(n)
  2784.                          {
  2785.                               m_AStarNodeList.AddNode(n);                    
  2786.                               n = n->pParent[1];
  2787.                          }
  2788.  
  2789.                          CleanAStarLists(false);               
  2790.                
  2791.                          return true;
  2792.                     }
  2793.                     
  2794.                     newg = n->g[1] + (short)AStarCost(n, n2);
  2795.  
  2796.                     if ((n2->g[1] <= newg) && (n2->bIsOpen[1] || n2->bIsClosed[1]))
  2797.                     {
  2798.                          pPath = pPath->next;
  2799.                          continue;
  2800.                     }
  2801.                
  2802.                     n2->pParent[1] = n;
  2803.                     n2->g[1] = newg;
  2804.                     n2->bIsClosed[1] = false;
  2805.  
  2806.                     if (!n2->bIsOpen[1])
  2807.                     {
  2808.                          m_AStarOpenList[1].AddEntry(n2, n2->g[1] + GetDistance(n2->pNode->v_origin,
  2809.                                                       m_pCurrentWaypoint->pNode->v_origin));
  2810.                          n2->bIsOpen[1] = true;
  2811.                     }
  2812.                     pPath = pPath->next;
  2813.                }
  2814.           
  2815.                m_AStarClosedList[1].PushNode(n);
  2816.                n->bIsClosed[1] = true;
  2817.                iCurrentCycles++;
  2818.           }
  2819.      }
  2820.      
  2821.      // Failed making path  
  2822.      condebug("Path failed");
  2823.                
  2824.      CleanAStarLists(true);
  2825.      m_bCalculatingAStarPath = false;
  2826.      BotManager.m_sUsingAStarBotsCount--;
  2827.      return true;
  2828. }
  2829.  
  2830. float CBot::AStarCost(waypoint_s *pWP1, waypoint_s *pWP2)
  2831. {
  2832.      // UNDONE?
  2833.      return (GetDistance(pWP1->pNode->v_origin, pWP2->pNode->v_origin) * pWP2->pNode->sCost);
  2834. }
  2835.  
  2836. void CBot::CleanAStarLists(bool bPathFailed)
  2837. {
  2838.      while(m_AStarOpenList[0].Empty() == false)
  2839.      {
  2840.           waypoint_s *p = m_AStarOpenList[0].Pop();
  2841.           p->bIsOpen[0] = p->bIsOpen[1] = false;
  2842.           p->bIsClosed[0] = p->bIsClosed[1] = false;
  2843.           p->pParent[0] = p->pParent[1] = NULL;
  2844.           p->g[0] = p->g[1] = 0;
  2845.      }
  2846.      
  2847.      while(m_AStarOpenList[1].Empty() == false)
  2848.      {
  2849.           waypoint_s *p = m_AStarOpenList[1].Pop();
  2850.           p->bIsOpen[0] = p->bIsOpen[1] = false;
  2851.           p->bIsClosed[0] = p->bIsClosed[1] = false;
  2852.           p->pParent[0] = p->pParent[1] = NULL;
  2853.           p->g[0] = p->g[1] = 0;
  2854.      }
  2855.                                                        
  2856.      while(m_AStarClosedList[0].Empty() == false)
  2857.      {
  2858.           waypoint_s *p = m_AStarClosedList[0].Pop();
  2859.           p->bIsOpen[0] = p->bIsOpen[1] = false;
  2860.           p->bIsClosed[0] = p->bIsClosed[1] = false;
  2861.           p->pParent[0] = p->pParent[1] = NULL;
  2862.           p->g[0] = p->g[1] = 0;
  2863.           if (bPathFailed)
  2864.                p->pNode->FailedGoalList.AddNode(m_pCurrentGoalWaypoint->pNode);
  2865.      }
  2866.      
  2867.      while(m_AStarClosedList[1].Empty() == false)
  2868.      {
  2869.           waypoint_s *p = m_AStarClosedList[1].Pop();
  2870.           p->bIsOpen[0] = p->bIsOpen[1] = false;
  2871.           p->bIsClosed[0] = p->bIsClosed[1] = false;
  2872.           p->pParent[0] = p->pParent[1] = NULL;
  2873.           p->g[0] = p->g[1] = 0;
  2874.           if (bPathFailed)
  2875.                p->pNode->FailedGoalList.AddNode(m_pCurrentWaypoint->pNode);
  2876.      }
  2877. }
  2878.  
  2879. void CBot::ResetWaypointVars()
  2880. {
  2881.      m_iWaypointTime = 0;
  2882.      m_pCurrentWaypoint = NULL;
  2883.      m_pCurrentGoalWaypoint = NULL;
  2884.      m_pPrevWaypoints[0] = NULL;
  2885.      m_pPrevWaypoints[1] = NULL;
  2886.      m_pPrevWaypoints[2] = NULL;
  2887.      m_pPrevWaypoints[3] = NULL;
  2888.      m_pPrevWaypoints[4] = NULL;
  2889.      m_fPrevWaypointDistance = 0;
  2890.      m_iWaypointHeadLastTurnLessTime = 0;
  2891.      m_iWaypointHeadPauseTime = 0;
  2892.      if (m_bCalculatingAStarPath)
  2893.      {
  2894.           m_bCalculatingAStarPath = false;
  2895.           BotManager.m_sUsingAStarBotsCount--;
  2896.      }
  2897.      m_AStarNodeList.DeleteAllNodes();
  2898.      CleanAStarLists(false);
  2899.      m_bGoToDebugGoal = false;
  2900. }
  2901.  
  2902. void CBot::SetCurrentWaypoint(node_s *pNode)
  2903. {
  2904.      waypoint_s *pWP = GetWPFromNode(pNode);
  2905. #ifndef RELEASE_BUILD
  2906.      if (!pWP || !pNode) condebug("NULL WP In SetCurrentWP");
  2907. #endif
  2908.      
  2909.      m_pCurrentWaypoint = pWP;
  2910.      m_iWaypointTime = lastmillis;
  2911. }
  2912.  
  2913. void CBot::SetCurrentWaypoint(waypoint_s *pWP)
  2914. {
  2915. #ifndef RELEASE_BUILD
  2916.      if (!pWP) condebug("NULL WP In SetCurrentWP(2)");
  2917. #endif
  2918.      
  2919.      m_pCurrentWaypoint = pWP;
  2920.      m_iWaypointTime = lastmillis;
  2921. }
  2922.  
  2923. void CBot::SetCurrentGoalWaypoint(node_s *pNode)
  2924. {
  2925.      waypoint_s *pWP = GetWPFromNode(pNode);
  2926. #ifndef RELEASE_BUILD
  2927.      if (!pWP || !pNode) condebug("NULL WP In SetCurrentGoalWP");
  2928. #endif
  2929.      
  2930.      m_pCurrentGoalWaypoint = pWP;
  2931. }
  2932.  
  2933. void CBot::SetCurrentGoalWaypoint(waypoint_s *pWP)
  2934. {
  2935. #ifndef RELEASE_BUILD
  2936.      if (!pWP) condebug("NULL WP In SetCurrentGoalWP(2)");
  2937. #endif
  2938.      
  2939.      m_pCurrentGoalWaypoint = pWP;
  2940. }
  2941.  
  2942. bool CBot::CurrentWPIsValid()
  2943. {
  2944.      if (!m_pCurrentWaypoint)
  2945.      {
  2946.           //condebug("Invalid WP: Is NULL");
  2947.           return false;
  2948.      }
  2949.      
  2950.      // check if the bot has been trying to get to this waypoint for a while...
  2951.      if ((m_iWaypointTime + 5000) < lastmillis)
  2952.      {   
  2953.           condebug("Invalid WP: time over");
  2954.           return false;
  2955.      }
  2956.  
  2957. #ifndef RELEASE_BUILD     
  2958.      if (!IsVisible(m_pCurrentWaypoint->pNode->v_origin))
  2959.           condebug("Invalid WP: Not visible");
  2960. #endif
  2961.           
  2962.      return (IsVisible(m_pCurrentWaypoint->pNode->v_origin));
  2963. }
  2964.  
  2965. bool CBot::ReachedGoalWP()
  2966. {
  2967.      if ((!m_pCurrentWaypoint) || (!m_pCurrentGoalWaypoint))
  2968.           return false;
  2969.  
  2970.      if (m_pCurrentWaypoint != m_pCurrentGoalWaypoint)
  2971.           return false;
  2972.  
  2973.      return ((GetDistance(m_pCurrentGoalWaypoint->pNode->v_origin) <= 3.0f) &&
  2974.              (IsVisible(m_pCurrentGoalWaypoint->pNode->v_origin)));
  2975. }
  2976.  
  2977. waypoint_s *CBot::GetWPFromNode(node_s *pNode)
  2978. {
  2979.      if (!pNode) return NULL;
  2980.      
  2981.      short x, y;
  2982.      WaypointClass.GetNodeIndexes(pNode->v_origin, &x, &y);
  2983.      
  2984.      TLinkedList<waypoint_s *>::node_s *p = m_WaypointList[x][y].GetFirst();
  2985.      while(p)
  2986.      {
  2987.           if (p->Entry->pNode == pNode)
  2988.                return p->Entry;
  2989.                
  2990.           p = p->next;
  2991.      }
  2992.      
  2993.      return NULL;
  2994. }
  2995.  
  2996. waypoint_s *CBot::GetNearestWaypoint(vec v_src, float flRange)
  2997. {
  2998.      TLinkedList<waypoint_s *>::node_s *p;
  2999.      waypoint_s *pNearest = NULL;
  3000.      short i, j, MinI, MaxI, MinJ, MaxJ, Offset = (short)ceil(flRange / MAX_MAP_GRIDS);
  3001.      float flNearestDist = 9999.99f, flDist;
  3002.  
  3003.      WaypointClass.GetNodeIndexes(v_src, &i, &j);
  3004.      MinI = i - Offset;
  3005.      MaxI = i + Offset;
  3006.      MinJ = j - Offset;
  3007.      MaxJ = j + Offset;
  3008.  
  3009.      if (MinI < 0)
  3010.           MinI = 0;
  3011.      if (MaxI > MAX_MAP_GRIDS - 1)
  3012.           MaxI = MAX_MAP_GRIDS - 1;
  3013.      if (MinJ < 0)
  3014.           MinJ = 0;
  3015.      if (MaxJ > MAX_MAP_GRIDS - 1)
  3016.           MaxJ = MAX_MAP_GRIDS - 1;
  3017.  
  3018.      for (int x=MinI;x<=MaxI;x++)
  3019.      {
  3020.           for(int y=MinJ;y<=MaxJ;y++)
  3021.           {
  3022.                p = m_WaypointList[x][y].GetFirst();
  3023.  
  3024.                while(p)
  3025.                {
  3026.                     if (p->Entry->pNode->iFlags & W_FL_FLOOD)
  3027.                     {
  3028.                          p = p->next;
  3029.                          continue;
  3030.                     }
  3031.                
  3032.                     flDist = GetDistance(v_src, p->Entry->pNode->v_origin);
  3033.                     if ((flDist < flNearestDist) && (flDist <= flRange))
  3034.                     {
  3035.                          if (::IsVisible(v_src, p->Entry->pNode->v_origin, NULL))
  3036.                          {
  3037.                               pNearest = p->Entry;
  3038.                               flNearestDist = flDist;
  3039.                          }
  3040.                     }
  3041.  
  3042.                     p = p->next;
  3043.                }
  3044.           }
  3045.      }
  3046.      return pNearest;
  3047. }
  3048.  
  3049. waypoint_s *CBot::GetNearestTriggerWaypoint(vec v_src, float flRange)
  3050. {
  3051.      TLinkedList<waypoint_s *>::node_s *p;
  3052.      waypoint_s *pNearest = NULL;
  3053.      short i, j, MinI, MaxI, MinJ, MaxJ, Offset = (short)ceil(flRange / MAX_MAP_GRIDS);
  3054.      float flNearestDist = 9999.99f, flDist;
  3055.  
  3056.      WaypointClass.GetNodeIndexes(v_src, &i, &j);
  3057.      MinI = i - Offset;
  3058.      MaxI = i + Offset;
  3059.      MinJ = j - Offset;
  3060.      MaxJ = j + Offset;
  3061.  
  3062.      if (MinI < 0)
  3063.           MinI = 0;
  3064.      if (MaxI > MAX_MAP_GRIDS - 1)
  3065.           MaxI = MAX_MAP_GRIDS - 1;
  3066.      if (MinJ < 0)
  3067.           MinJ = 0;
  3068.      if (MaxJ > MAX_MAP_GRIDS - 1)
  3069.           MaxJ = MAX_MAP_GRIDS - 1;
  3070.  
  3071.      for (int x=MinI;x<=MaxI;x++)
  3072.      {
  3073.           for(int y=MinJ;y<=MaxJ;y++)
  3074.           {
  3075.                p = m_WaypointList[x][y].GetFirst();
  3076.  
  3077.                while(p)
  3078.                {
  3079.                     if (!(p->Entry->pNode->iFlags & W_FL_TRIGGER))
  3080.                     {
  3081.                          p = p->next;
  3082.                          continue;
  3083.                     }
  3084.                
  3085.                     flDist = GetDistance(v_src, p->Entry->pNode->v_origin);
  3086.                     if ((flDist < flNearestDist) && (flDist <= flRange))
  3087.                     {
  3088.                          if (::IsVisible(v_src, p->Entry->pNode->v_origin, NULL))
  3089.                          {
  3090.                               pNearest = p->Entry;
  3091.                               flNearestDist = flDist;
  3092.                          }
  3093.                     }
  3094.  
  3095.                     p = p->next;
  3096.                }
  3097.           }
  3098.      }
  3099.      return pNearest;
  3100. }
  3101.  
  3102. // Makes a waypoint list for this bot based on the list from WaypointClass
  3103. void CBot::SyncWaypoints()
  3104. {
  3105.      short x, y;
  3106.      TLinkedList<node_s *>::node_s *p;
  3107.      
  3108.      // Clean everything first
  3109.      for (x=0;x<MAX_MAP_GRIDS;x++)
  3110.      {
  3111.           for (y=0;y<MAX_MAP_GRIDS;y++)
  3112.           {
  3113.                while(!m_WaypointList[x][y].Empty())
  3114.                     delete m_WaypointList[x][y].Pop();
  3115.           }
  3116.      }
  3117.      
  3118.      // Sync
  3119.      for (x=0;x<MAX_MAP_GRIDS;x++)
  3120.      {
  3121.           for (y=0;y<MAX_MAP_GRIDS;y++)
  3122.           {
  3123.                p = WaypointClass.m_Waypoints[x][y].GetFirst();
  3124.                while(p)
  3125.                {
  3126.                     waypoint_s *pWP = new waypoint_s;
  3127.                     pWP->pNode = p->Entry;
  3128.                     m_WaypointList[x][y].AddNode(pWP);
  3129.                     
  3130. #ifndef RELEASE_BUILD
  3131.                     if (!GetWPFromNode(p->Entry)) condebug("Error adding bot wp!");
  3132. #endif                                   
  3133.                     
  3134.                     p = p->next;
  3135.                }
  3136.           }
  3137.      }
  3138. }
  3139.      
  3140. #ifdef WP_FLOOD
  3141. waypoint_s *CBot::GetNearestFloodWP(vec v_origin, float flRange)
  3142. {
  3143.      TLinkedList<waypoint_s *>::node_s *p;
  3144.      waypoint_s *pNearest = NULL;
  3145.      short i, j, MinI, MaxI, MinJ, MaxJ, Offset = (short)ceil(flRange / MAX_MAP_GRIDS);
  3146.      float flNearestDist = 9999.99f, flDist;
  3147.  
  3148.      WaypointClass.GetNodeIndexes(v_origin, &i, &j);
  3149.      MinI = i - Offset;
  3150.      MaxI = i + Offset;
  3151.      MinJ = j - Offset;
  3152.      MaxJ = j + Offset;
  3153.  
  3154.      if (MinI < 0)
  3155.           MinI = 0;
  3156.      if (MaxI > MAX_MAP_GRIDS - 1)
  3157.           MaxI = MAX_MAP_GRIDS - 1;
  3158.      if (MinJ < 0)
  3159.           MinJ = 0;
  3160.      if (MaxJ > MAX_MAP_GRIDS - 1)
  3161.           MaxJ = MAX_MAP_GRIDS - 1;
  3162.  
  3163.      for (int x=MinI;x<=MaxI;x++)
  3164.      {
  3165.           for(int y=MinJ;y<=MaxJ;y++)
  3166.           {
  3167.                p = m_WaypointList[x][y].GetFirst();
  3168.  
  3169.                while(p)
  3170.                {
  3171.                     if (!(p->Entry->pNode->iFlags & W_FL_FLOOD))
  3172.                     {
  3173.                          p = p->next;
  3174.                          continue;
  3175.                     }
  3176.                          
  3177.                     flDist = GetDistance(v_origin, p->Entry->pNode->v_origin);
  3178.                     if ((flDist < flNearestDist) && (flDist <= flRange))
  3179.                     {
  3180.                          if (::IsVisible(v_origin, p->Entry->pNode->v_origin, NULL))
  3181.                          {
  3182.                               pNearest = p->Entry;
  3183.                               flNearestDist = flDist;
  3184.                          }
  3185.                     }
  3186.  
  3187.                     p = p->next;
  3188.                }
  3189.           }
  3190.      }
  3191.      return pNearest;
  3192. }
  3193.  
  3194. waypoint_s *CBot::GetNearestTriggerFloodWP(vec v_origin, float flRange)
  3195. {
  3196.      TLinkedList<waypoint_s *>::node_s *p;
  3197.      waypoint_s *pNearest = NULL;
  3198.      short i, j, MinI, MaxI, MinJ, MaxJ, Offset = (short)ceil(flRange / MAX_MAP_GRIDS);
  3199.      float flNearestDist = 9999.99f, flDist;
  3200.  
  3201.      WaypointClass.GetNodeIndexes(v_origin, &i, &j);
  3202.      MinI = i - Offset;
  3203.      MaxI = i + Offset;
  3204.      MinJ = j - Offset;
  3205.      MaxJ = j + Offset;
  3206.  
  3207.      if (MinI < 0)
  3208.           MinI = 0;
  3209.      if (MaxI > MAX_MAP_GRIDS - 1)
  3210.           MaxI = MAX_MAP_GRIDS - 1;
  3211.      if (MinJ < 0)
  3212.           MinJ = 0;
  3213.      if (MaxJ > MAX_MAP_GRIDS - 1)
  3214.           MaxJ = MAX_MAP_GRIDS - 1;
  3215.  
  3216.      for (int x=MinI;x<=MaxI;x++)
  3217.      {
  3218.           for(int y=MinJ;y<=MaxJ;y++)
  3219.           {
  3220.                p = m_WaypointList[x][y].GetFirst();
  3221.  
  3222.                while(p)
  3223.                {
  3224.                     if (!(p->Entry->pNode->iFlags & (W_FL_FLOOD | W_FL_TRIGGER)))
  3225.                     {
  3226.                          p = p->next;
  3227.                          continue;
  3228.                     }
  3229.                          
  3230.                     flDist = GetDistance(v_origin, p->Entry->pNode->v_origin);
  3231.                     if ((flDist < flNearestDist) && (flDist <= flRange))
  3232.                     {
  3233.                          if (::IsVisible(v_origin, p->Entry->pNode->v_origin, NULL))
  3234.                          {
  3235.                               pNearest = p->Entry;
  3236.                               flNearestDist = flDist;
  3237.                          }
  3238.                     }
  3239.  
  3240.                     p = p->next;
  3241.                }
  3242.           }
  3243.      }
  3244.      return pNearest;
  3245. }
  3246.  
  3247. void CBot::GoToDebugGoal(vec o)
  3248. {
  3249.      ResetWaypointVars();
  3250.      
  3251.      node_s *wp = WaypointClass.GetNearestWaypoint(m_pMyEnt, 20.0f);
  3252.      node_s *goalwp = WaypointClass.GetNearestWaypoint(player1, 20.0f);
  3253.      
  3254.      if (!wp || !goalwp)
  3255.      {
  3256.           wp = WaypointClass.GetNearestFloodWP(m_pMyEnt, 8.0f);
  3257.           goalwp = WaypointClass.GetNearestFloodWP(player1, 5.0f);
  3258.      }
  3259.      if (!wp || !goalwp) { condebug("No near WP"); return; }
  3260.           
  3261.      SetCurrentWaypoint(wp);
  3262.      SetCurrentGoalWaypoint(goalwp);
  3263.      m_vGoal = o;
  3264.      m_bGoToDebugGoal = true;
  3265. }
  3266. #endif
  3267.  
  3268. // Bot class end
  3269.