home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2006 April / Gamestar_83_2006-04_dvd.iso / Dema / demowot_english.exe / Script / Source / pacman / pacman.sma < prev   
Text File  |  2005-03-11  |  16KB  |  694 lines

  1.  
  2. #include "script.inc"
  3.  
  4. //    --- Enums ---
  5.  
  6. enum eCellType
  7. {
  8.     CT_UNDEFINED, 
  9.     CT_EMPTY, 
  10.     CT_GHOST,                     //    empty cell in the ghost respawn area
  11.     CT_WALL, 
  12.     CT_BORDER,                     //    indestructible wall
  13.     CT_MINE,                     //    yellow dot
  14.     CT_POWER,                     //    power mode mine
  15.     CT_DEATH,                    //    instant kill mine (to prevent the player from going into the ghost respawn area)
  16.     CT_RESPAWN,                    //    ghost respawn point
  17.     CT_START,                     //    player start point
  18. };
  19.  
  20. //    --- Defines & consts ---
  21.  
  22. new const playerTeam = 1;
  23. new const ghostTeam = 2;
  24.  
  25. new const wallBase[] = "pacman_wall";
  26. new const Float:wallScale[vec3] = {8.0, 8.0, 4.0};
  27. new const borderBase[] = "pacman_border";
  28. new const Float:borderScale[vec3] = {8.0, 8.0, 4.0};
  29. new const fowBeaconBase[] = "fowbacon";
  30.  
  31. new const mineBase[] = "pacman_mine"
  32. new const Float:mineScale[vec3] = {2.0, 2.0, 1.0};
  33. new const powermineBase[] = "pacman_power_mine";
  34. new const Float:powermineScale[vec3] = {4.0, 4.0, 1.0};
  35. new const deathmineBase[] = "pacman_death_mine";
  36. new const Float:deathmineScale[vec3] = {5.0, 5.0, 1.0};
  37.  
  38. new const playerTankBase[] = "pacman_player";
  39. new const ghostTankBase[] = "pacman_ghost";
  40.  
  41. new const Float:blockSize = 8.0;                    //    meters
  42. #define MAP_SIZE 31                                    //    must be 4 * k + 3
  43. #define HALF_MAP_SIZE ((MAP_SIZE + 1) / 2)
  44. new const nHoles = 12;
  45. new const nPowerMines = 8;
  46. new const playerStartX = 1;
  47. new const playerStartY = 1;
  48.  
  49. #define GHOST_AREA_SIZE 7
  50. new const eCellType:ghostArea[GHOST_AREA_SIZE][GHOST_AREA_SIZE] = 
  51. {
  52.     {CT_BORDER,    CT_BORDER,    CT_BORDER,     CT_DEATH,    CT_BORDER,    CT_BORDER,    CT_BORDER}, 
  53.     {CT_BORDER,    CT_GHOST,    CT_GHOST,     CT_GHOST,    CT_GHOST,    CT_GHOST,    CT_BORDER}, 
  54.     {CT_BORDER,    CT_GHOST,    CT_RESPAWN,    CT_GHOST,    CT_RESPAWN,    CT_GHOST,    CT_BORDER}, 
  55.     {CT_DEATH,    CT_GHOST,    CT_GHOST,     CT_GHOST,    CT_GHOST,    CT_GHOST,    CT_DEATH}, 
  56.     {CT_BORDER,    CT_GHOST,    CT_RESPAWN,    CT_GHOST,    CT_RESPAWN,    CT_GHOST,    CT_BORDER}, 
  57.     {CT_BORDER,    CT_GHOST,    CT_GHOST,     CT_GHOST,    CT_GHOST,    CT_GHOST,    CT_BORDER}, 
  58.     {CT_BORDER,    CT_BORDER,    CT_BORDER,     CT_DEATH,    CT_BORDER,    CT_BORDER,    CT_BORDER}, 
  59. }
  60.  
  61. #define N_GHOSTS 4
  62. #define N_GHOST_RESPAWN_POINTS 4
  63. new const Float:ghostRespawnDelay = 5.0;
  64.  
  65. new const Float:powerModeTime = 60.0                            //    secs
  66.  
  67. new const scoreMine = 1000;
  68. new const scorePowerMine = 2000;
  69. new const scoreKill = 10000;
  70. new const scorePowerKill = 20000; 
  71.  
  72. new const Float:aiUpdateFrequency = 2.0;
  73. new const Float:aiChaseDistMultiplier = 0.5;
  74. new const aiChaseMaxIter = 4;
  75.  
  76. #define MAX_PROGRESS_STEPS_SHOWN 15
  77.  
  78. //    --- Globals ---
  79.  
  80. new eCellType:map[MAP_SIZE][MAP_SIZE];                //    [column][row]
  81.  
  82. new player;
  83. new powerMode;                                        //    int instead of bool, so that it can store the number of active (exploded and not yet expired)
  84.                                                     //    power mines, in case the player gets one just before the previous one expires.
  85.                                                     //    (using a bool would turn off power mode when the time for the first mine expires.)
  86. new score;
  87. new nMines;
  88.  
  89. new ghosts[N_GHOSTS];
  90. new Float:ghostRespawnPoints[N_GHOST_RESPAWN_POINTS][vec3];
  91. new Float:ghostTargets[N_GHOSTS][vec3];                //    current move targets
  92.  
  93. //    --- Main ---
  94.  
  95. public main() 
  96.     CommonAKMain();
  97.  
  98. public PostGameStart()
  99. {
  100.     CommonAKInit();
  101.     AddAKEntityEvent("OnTestEvent", ANY_ENTITY, TEST_EVENT);
  102.     
  103.     GenerateMap();
  104.     CreatePlayer();
  105.     FindGhostRespawnPoints();
  106.     CreateGhosts();
  107.     InitGhostAI();
  108.     AddObjective("ExplodeMines", OT_PRIMARY, "#iMSPM_PS01#", "#iMSPM_PL01#", OS_IN_PROGRESS);
  109. }
  110.  
  111. public OnTestEvent()
  112. {
  113. }
  114.  
  115. //    --- Support functions ---
  116.  
  117. stock CellToPos(col, row, Float:result[vec3])
  118. {
  119.     result[vec3:x] = (col + 0.5) * blockSize;
  120.     result[vec3:y] = (row + 0.5) * blockSize;
  121.     result[vec3:z] = 0.0;
  122. }
  123.  
  124. stock PosToCell(Float:pos[vec3], &col, &row)
  125. {
  126.     col = floatround(pos[vec3:x] / blockSize, floatround_floor);
  127.     row = floatround(pos[vec3:y] / blockSize, floatround_floor);
  128.     if ((col < 0) || (col >= MAP_SIZE))
  129.         col = row = -1;
  130.     if ((row < 0) || (row >= MAP_SIZE))
  131.         col = row = -1;
  132. }
  133.  
  134. stock Float:FRnd(Float:low, Float:high)
  135. {
  136.     new i;
  137.     i = Rnd(0, 32767);
  138.     new Float:f = low + float(i) / 32767.0 * (high - low);
  139.     if (f < low)
  140.         f = low;
  141.     if (f > high)
  142.         f = high;
  143.     return f;
  144. }
  145.  
  146. //    --- Generate Map ---
  147.  
  148. stock ShowProgress(steps)
  149. {
  150.     static sumSteps = 0;
  151.     sumSteps += steps;
  152.     while (sumSteps > MAX_PROGRESS_STEPS_SHOWN)
  153.         sumSteps -= MAX_PROGRESS_STEPS_SHOWN;
  154.     new str[MAX_PROGRESS_STEPS_SHOWN + 1];
  155.     new i;
  156.     for (i = 0; i < sumSteps; i++)
  157.         str[i] = '.';
  158.     str[i] = 0;
  159.     SetShortInfo(str);
  160. }
  161.  
  162. stock InitMap()
  163. {
  164.     new i;
  165.     for (i = 0; i < MAP_SIZE; i++)
  166.     {
  167.         new j;
  168.         for (j = 0; j < MAP_SIZE; j++)
  169.             map[i][j] = CT_EMPTY;
  170.     }
  171.     new Float:mapCenter[vec3];
  172.     mapCenter[vec3:x] = mapCenter[vec3:y] = (MAP_SIZE * blockSize) / 2.0;
  173.     new DrID:fowBeacon = CreateEntity(fowBeaconBase, mapCenter);
  174.     SetPropertyInt(fowBeacon, "Team", playerTeam);
  175.     SetPropertyFloat(fowBeacon, "FOWRangeRadius", MAP_SIZE * blockSize);
  176.     fowBeacon = CreateEntity(fowBeaconBase, mapCenter);
  177.     SetPropertyInt(fowBeacon, "Team", ghostTeam);
  178.     SetPropertyFloat(fowBeacon, "FOWRangeRadius", MAP_SIZE * blockSize);
  179. }
  180.  
  181. //    --- Generate walls ---
  182.  
  183. stock SetCell(col, row, eCellType:type, bool:symmetrically = true)
  184. {
  185.     map[col][row] = type;
  186.     if (symmetrically)
  187.     {
  188.         map[MAP_SIZE - col - 1][row] = type;
  189.         map[col][MAP_SIZE - row - 1] = type;
  190.         map[MAP_SIZE - col - 1][MAP_SIZE - row - 1] = type;
  191.     }
  192. }
  193.  
  194. stock GenerateBorder()
  195. {
  196.     new i;
  197.     for (i = 0; i < HALF_MAP_SIZE; i++)
  198.     {
  199.         SetCell(i, 0, CT_BORDER);
  200.         SetCell(0, i, CT_BORDER);
  201.     }
  202. }
  203.  
  204. stock RndLine(bool:processed[HALF_MAP_SIZE])
  205. {
  206.     new line;
  207.     do
  208.     {
  209.         line = Rnd(1, HALF_MAP_SIZE / 2 - 1) * 2;
  210.     } while (processed[line]);
  211.     return line;
  212. }
  213.  
  214. stock GenerateRow(bool:processedRows[HALF_MAP_SIZE])
  215. {
  216.     new row = RndLine(processedRows);    
  217.     new i;
  218.     new dir = Rnd(0, 1) * 2 - 1;
  219.     new col = (dir == 1) ? 1 : HALF_MAP_SIZE - 1;
  220.     for (i = 1; i < HALF_MAP_SIZE; i++, col += dir)
  221.     {
  222.         new eCellType:nextCell = (col + dir == HALF_MAP_SIZE) ? CT_WALL : map[col + dir][row];
  223.         if ((map[col][row] == CT_EMPTY) && (nextCell == CT_EMPTY))
  224.             SetCell(col, row, CT_WALL);
  225.     }
  226.     processedRows[row] = true;
  227. }
  228.  
  229. stock GenerateColumn(bool:processedColumns[HALF_MAP_SIZE])
  230. {
  231.     new col = RndLine(processedColumns);    
  232.     new i;
  233.     new dir = Rnd(0, 1) * 2 - 1;
  234.     new row = (dir == 1) ? 1 : HALF_MAP_SIZE - 1;
  235.     for (i = 1; i < HALF_MAP_SIZE; i++, row += dir)
  236.     {
  237.         new eCellType:nextCell = (row + dir == HALF_MAP_SIZE) ? CT_WALL : map[col][row + dir];
  238.         if ((map[col][row] == CT_EMPTY) && (nextCell == CT_EMPTY))
  239.             SetCell(col, row, CT_WALL);
  240.     }
  241.     processedColumns[col] = true;
  242. }
  243.  
  244. stock AddHoles()
  245. {
  246.     new i;
  247.     for (i = 0; i < nHoles; i++)
  248.     {
  249.         new col, row;
  250.         do 
  251.         {
  252.             col = Rnd(1, HALF_MAP_SIZE);
  253.             row = Rnd(1, HALF_MAP_SIZE);
  254.         } while (map[col][row] != CT_WALL);
  255.         SetCell(col, row, CT_EMPTY);
  256.     }
  257. }
  258.  
  259. stock CreateGhostArea()
  260. {
  261.     new i, j;
  262.     new start = (MAP_SIZE - GHOST_AREA_SIZE) / 2;
  263.     for (i = 0; i < GHOST_AREA_SIZE; i++)
  264.     {
  265.         for (j = 0; j < GHOST_AREA_SIZE; j++)
  266.         {
  267.             map[start + i][start + j] = ghostArea[i][j];
  268.         }
  269.     }
  270. }
  271.  
  272. stock GenerateWalls()
  273. {
  274.     GenerateBorder();
  275.     CreateGhostArea();
  276.     new bool:processedRows[HALF_MAP_SIZE];
  277.     new bool:processedColumns[HALF_MAP_SIZE];
  278.     new i;
  279.     for (i = 0; i < HALF_MAP_SIZE; i++)
  280.     {
  281.         processedRows[i] = false;
  282.         processedColumns[i] = false; 
  283.         ShowProgress(1);
  284.     }    
  285.     for (i = 0; i < HALF_MAP_SIZE / 2 - 1; i++)
  286.     {
  287.         GenerateRow(processedRows);
  288.         GenerateColumn(processedColumns);
  289.         ShowProgress(1);
  290.     }
  291.     AddHoles();
  292. }
  293.  
  294. //    --- Generate mines ---
  295.  
  296. stock GeneratePowerMines()
  297. {
  298.     new i;
  299.     for (i = 0; i < nPowerMines / 4; i++)
  300.     {
  301.         new row, col;
  302.         do
  303.         {
  304.             row = Rnd(1, MAP_SIZE - 2);
  305.             col = Rnd(1, MAP_SIZE - 2);
  306.         } while (map[col][row] != CT_EMPTY);
  307.         SetCell(col, row, CT_POWER);
  308.     }
  309. }
  310.  
  311. stock GenerateMines()
  312. {
  313.     GeneratePowerMines();
  314.     nMines = 0;
  315.     new i, j;
  316.     for (i = 0; i < MAP_SIZE; i++)
  317.     {
  318.         for (j = 0; j < MAP_SIZE; j++)
  319.         {
  320.             if (map[i][j] == CT_EMPTY)
  321.             {
  322.                 SetCell(i, j, CT_MINE, false);
  323.                 nMines++;
  324.             }
  325.         }
  326.     }
  327. }
  328.  
  329. //    --- Create Entities --- 
  330.  
  331. stock CreateEntities()
  332. {
  333.     new col, row;
  334.     new Float:pos[vec3];
  335.     pos[vec3:z] = 0.0;
  336.     pos[vec3:x] = blockSize / 2.0;
  337.     for (col = 0; col < MAP_SIZE; col++, pos[vec3:x] += blockSize)
  338.     {
  339.         pos[vec3:y] = blockSize / 2.0;
  340.         for (row = 0; row < MAP_SIZE; row++, pos[vec3:y] += blockSize)
  341.         {
  342.             switch (map[col][row])
  343.             {
  344.                 case CT_WALL:
  345.                 {
  346.                     new DrID:wall = CreateEntity(wallBase, pos, Rnd(0, 3) * 90.0);
  347.                     SetPropertyVec3(wall, "Scale", wallScale);
  348.                 }
  349.                 case CT_BORDER:
  350.                 {
  351.                     new DrID:border = CreateEntity(borderBase, pos, Rnd(0, 3) * 90.0);
  352.                     SetPropertyVec3(border, "Scale", borderScale);
  353.                 }
  354.                 case CT_MINE:
  355.                 {
  356.                     new DrID:mine = CreateEntity(mineBase, pos);
  357.                     SetPropertyVec3(mine, "Scale", mineScale);
  358.                     AddAKEntityEvent("OnMineExplode", mine, MINE_EXPLODE);
  359.                 }
  360.                 case CT_POWER:
  361.                 {
  362.                     new DrID:mine = CreateEntity(powermineBase, pos);
  363.                     SetPropertyVec3(mine, "Scale", powermineScale);
  364.                     AddAKEntityEvent("OnPowerMineExplode", mine, MINE_EXPLODE);
  365.                     AddAKEntityEvent("OnPowerModeExpire", mine, MINE_EXPLODE, powerModeTime);
  366.                 }
  367.                 case CT_DEATH:
  368.                 {
  369.                     new DrID:mine = CreateEntity(deathmineBase, pos);
  370.                     SetPropertyVec3(mine, "Scale", deathmineScale);
  371.                 }
  372.             }
  373.         }
  374.     }        
  375. }
  376.  
  377. stock GenerateMap()
  378. {    
  379.     InitMap();    
  380.     SetCell(playerStartX, playerStartY, CT_START, false);
  381.     GenerateWalls();    
  382.     GenerateMines();
  383.     CreateEntities();
  384.     SetShortInfo("");
  385. }
  386.  
  387. //    --- Ghosts ---
  388.  
  389. stock FindGhostRespawnPoints()
  390. {
  391.     new i, j, n = 0;
  392.     for (i = 0; i < MAP_SIZE; i++)
  393.     {
  394.         for (j = 0; j < MAP_SIZE; j++)
  395.         {
  396.             if (map[i][j] == CT_RESPAWN)
  397.             {
  398.                 CellToPos(i, j, ghostRespawnPoints[n]);
  399.                 n++;
  400.             }
  401.         }
  402.     }
  403.     assert(n >= N_GHOSTS);
  404. }
  405.  
  406. stock GetGhostIndex(DrID:ghost)
  407. {
  408.     new i;
  409.     for (i = 0; i < N_GHOSTS; i++)
  410.     {
  411.         if (ghosts[i] == GetEntityID(ghost))
  412.             return i;
  413.     }
  414.     return -1;
  415. }
  416.  
  417. stock CreateGhost(index)
  418. {
  419.     new Float:respawnPoint[vec3];
  420.     respawnPoint = ghostRespawnPoints[index];
  421.     new    DrID:ghost = CreateEntity(ghostTankBase, respawnPoint, Rnd(0, 3) * 90);
  422.     ghosts[index] = GetEntityID(ghost);
  423.     SetPropertyInt(ghost, "Team", ghostTeam);
  424. /*
  425. // --- TIMBER ADDED THIS ---
  426.     MakeInvulnerable(ghost);
  427.     BurnEntity(ghost);
  428. // --- TIMBER ADDED THIS ---
  429. */
  430.     AddAKEntityEvent("OnGhostDied", ghost, UNIT_DIED);
  431.     AddAKEntityEvent("OnGhostDiedDelayed", ghost, UNIT_DIED, ghostRespawnDelay);
  432.     ghostTargets[index][vec3:x] = -1.0;            //    invalidate
  433. }
  434.  
  435. stock CreateGhosts()
  436. {
  437.     new i;
  438.     for (i = 0; i < N_GHOSTS; i++)
  439.         CreateGhost(i);
  440. }
  441.  
  442. public OnGhostDied(DrID:ghost)
  443. {
  444.     if (powerMode)
  445.         AddToScore(scorePowerKill);
  446.     else
  447.         AddToScore(scoreKill);
  448. }
  449.  
  450. public OnGhostDiedDelayed(DrID:ghost)
  451. {
  452.     DamageEntity(ghost, 666.666, 49);
  453.     CreateGhost(GetGhostIndex(ghost));
  454. }
  455.  
  456. //    --- Ghost AI ---
  457.  
  458. stock MoveGhost(DrID:ghost, Float:targetPos[vec3])
  459. {
  460.     CmdMove(ghost, _, targetPos);
  461.     ghostTargets[GetGhostIndex(ghost)] = targetPos;    
  462. }
  463.  
  464. //    --- Ghost AI - chase ---
  465.  
  466. stock IsValidTarget(DrID:ghost, Float:target[vec3])
  467. {
  468.     new Float:playerPos[vec3];
  469.     GetPropertyVec3(GetEntityByID(player), "Pos", playerPos);
  470.     new Float:ghostPos[vec3];
  471.     GetPropertyVec3(ghost, "Pos", ghostPos);
  472.     new Float:ghostDistToPlayer = Distance(playerPos, ghostPos);
  473.     new Float:targetDistToPlayer = Distance(playerPos, target);    
  474.     if (targetDistToPlayer > aiChaseDistMultiplier * ghostDistToPlayer)
  475.         return false;
  476.         
  477.     return true;
  478. }
  479.  
  480. stock IsCurrentTargetValid(DrID:ghost)
  481. {
  482.     new index = GetGhostIndex(ghost);
  483.     if (ghostTargets[index][vec3:x] == -1.0)
  484.         return false;
  485.     return IsValidTarget(ghost, ghostTargets[index]);
  486. }
  487.  
  488. stock ChasePlayer(DrID:ghost)
  489. {    
  490.     if (IsCurrentTargetValid(ghost))
  491.         return;
  492.         
  493.     new Float:playerPos[vec3];
  494.     GetPropertyVec3(GetEntityByID(player), "Pos", playerPos);
  495.     new Float:ghostPos[vec3];
  496.     GetPropertyVec3(ghost, "Pos", ghostPos);
  497.     new Float:ghostToPlayerDist = Distance(playerPos, ghostPos);
  498.     new Float:playerToGhostVec[vec3];
  499.     SubVec3(ghostPos, playerPos, playerToGhostVec);
  500.     NormalizeVec3(playerToGhostVec);
  501.     new Float:targetPos[vec3];
  502.     new col, row;
  503.  
  504.     new iter;
  505.     do
  506.     {
  507.         /*
  508.             Get a circle around the player with r = aiChaseDistMultiplier * ghostToPlayerDist.
  509.             Get the half of this circle on the ghost's side.
  510.             Generate a random point inside the half-circle.
  511.         */
  512.         new Float:targetToPlayerDist = FRnd(0, aiChaseDistMultiplier * ghostToPlayerDist);
  513.         new Float:rot = FRnd(-135.0, 135.0);
  514.         targetPos = playerToGhostVec;
  515.         RotateVec2(targetPos, rot);
  516.         targetPos[vec3:x] *= targetToPlayerDist;
  517.         targetPos[vec3:y] *= targetToPlayerDist;
  518.         AddVec3(targetPos, playerPos, targetPos);
  519.         PosToCell(targetPos, col, row);            
  520.         iter++;
  521.     } while (((col < 0) || (map[col][row] == CT_WALL) || (map[col][row] == CT_BORDER)) && (iter < aiChaseMaxIter));
  522.     
  523.     if (IsValidTarget(ghost, targetPos))
  524.         MoveGhost(ghost, targetPos);
  525. }
  526.  
  527. //    --- Ghost AI - flee ---
  528.  
  529. public Flee(DrID:ghost)
  530. {
  531.     /*
  532.         Loop through the 9 cells around the ghost, find the one farthest from the player, and move there.
  533.     */
  534.     new Float:playerPos[vec3];
  535.     GetPropertyVec3(GetEntityByID(player), "Pos", playerPos);
  536.     new Float:ghostPos[vec3];
  537.     GetPropertyVec3(ghost, "Pos", ghostPos);
  538.     new col, row;
  539.     PosToCell(ghostPos, col, row);
  540.  
  541.     new c, r_;
  542.     new maxCol, maxRow;
  543.     new Float:maxDist = -1;
  544.     for (c = -1; c < 2; c++)
  545.     {
  546.         for (r_ = -1; r_ < 2; r_++)
  547.         {
  548.             new eCellType:cell = map[col + c][row + r_];
  549.             if ((cell == CT_WALL) || (cell == CT_BORDER))
  550.                 continue;
  551.             new Float:cellPos[vec3];
  552.             CellToPos(col + c, row + r_, cellPos);
  553.             new Float:dist = Distance(playerPos, cellPos);
  554.             if (dist > maxDist)
  555.             {
  556.                 maxDist = dist;
  557.                 maxCol = col + c;
  558.                 maxRow = row + r_;
  559.             }
  560.         }
  561.     }
  562.     
  563.     new Float:targetPos[vec3];
  564.     CellToPos(maxCol, maxRow, targetPos);
  565.     if (!CmpVec3(targetPos, ghostTargets[GetGhostIndex(ghost)]))
  566.         MoveGhost(ghost, targetPos);
  567. }
  568.  
  569. public RefreshGhosts(Float:time)
  570. {
  571.     new i;
  572.     for (i = 0; i < N_GHOSTS; i++)
  573.     {
  574.         new DrID:ghost = GetEntityByID(ghosts[i]);
  575.         if (powerMode)
  576.             Flee(ghost);
  577.         else
  578.             ChasePlayer(ghost);
  579.     }
  580. }
  581.  
  582. stock InitGhostAI()
  583. {
  584.     AddTimerEvent("RefreshGhosts", 1.0 / aiUpdateFrequency);
  585. }
  586.  
  587. //    --- Player ---
  588.  
  589. stock CreatePlayer()
  590. {
  591.     new Float:startPos[vec3];
  592.     startPos[vec3:x] = 1.5 * blockSize;
  593.     startPos[vec3:y] = 1.5 * blockSize;
  594.     new DrID:pl = CreateEntity(playerTankBase, startPos);
  595.     player = GetEntityID(pl);
  596.     SetPropertyInt(pl, "Team", playerTeam);
  597.     powerMode = 0;
  598.     EnablePowerWeapon(pl, false);
  599.     SetScore(0);
  600.     AddAKEntityEvent("OnPlayerDied", pl, UNIT_DIED);
  601. }
  602.  
  603. public OnPlayerDied()
  604. {
  605.     SetObjectiveState("ExplodeMines", OS_FAILED);
  606.     EndMission(MS_FAILED);
  607. }
  608.  
  609. stock SetScore(aScore)
  610. {
  611.     score = aScore;
  612.     new str[255];
  613.     Int2Str(score, str, 255, "Score: %d");        //    TODO localize
  614.     SetShortInfo(str);
  615. }
  616.  
  617. stock AddToScore(diff)
  618. {
  619.     SetScore(score + diff);
  620. }
  621.  
  622. //    --- Mines ---
  623.  
  624. public OnMineExplode(DrID:mine)
  625. {
  626.     AddToScore(scoreMine);
  627.     nMines--;
  628.     if (nMines == 0)
  629.     {
  630.         SetObjectiveState("ExplodeMines", OS_COMPLETED);
  631.         EndMission(MS_ACCOMPLISHED);
  632.     }    
  633. }
  634.  
  635. stock EnablePowerWeapon(DrID:tank, bool:enable)
  636. {
  637. ///* Old CODE
  638.     new DrID:wm = GetComponent(tank, "cWeaponManager");
  639.     new DrID:weapon = GetArrayElement(wm, "Weapons", 1);
  640.     SetPropertyBool(weapon, "Enabled", enable);
  641. //*/
  642. /*
  643. // --- TIMBER ADDED THIS ---
  644.     if(enable)
  645.     {
  646.         MakeInvulnerable(tank);
  647.         BurnEntity(tank);
  648.     }
  649.     else
  650.     {
  651.         StopBurning(tank);
  652.         MakeVulnerable(tank);    
  653.     }
  654. // --- TIMBER ADDED THIS ---
  655. */    
  656. }
  657.  
  658. stock UpdatePowerWeapons()
  659. {
  660.     EnablePowerWeapon(GetEntityByID(player), powerMode > 0);
  661.     new i;
  662.     for (i = 0; i < N_GHOSTS; i++)
  663.         EnablePowerWeapon(GetEntityByID(ghosts[i]), powerMode == 0);
  664. }
  665.  
  666. stock StartPowerMode()
  667. {
  668.     UpdatePowerWeapons();
  669. }
  670.  
  671. public OnPowerMineExplode(DrID:mine)
  672. {
  673.     SetCountDown(floatround(powerModeTime));
  674.     powerMode++;
  675.     if (powerMode == 1)
  676.         StartPowerMode();
  677.     AddToScore(scorePowerMine);
  678. }
  679.  
  680. stock EndPowerMode()
  681. {
  682.     SetCountDown(-1);
  683.     UpdatePowerWeapons();
  684. }
  685.  
  686. public OnPowerModeExpire(DrID:mine)
  687. {
  688.     powerMode--;
  689.     if (powerMode == 0)
  690.         EndPowerMode();
  691. }
  692.  
  693.  
  694.