home *** CD-ROM | disk | FTP | other *** search
/ PC Format (South-Africa) 2001 June / PCFJune.iso / Xenon / XenonSource.exe / xenon / source / level.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-11  |  14.3 KB  |  638 lines

  1. //-------------------------------------------------------------
  2. //
  3. // Class:    CLevel
  4. //
  5. // Author:    John M Phillips
  6. //
  7. // Started:    06/05/00
  8. //
  9. // Base:    None
  10. //
  11. // Derived:    None
  12. //
  13. //-------------------------------------------------------------
  14.  
  15. #include "game.h"
  16.  
  17. //-------------------------------------------------------------
  18.  
  19. CLevel::CLevel()
  20. {
  21.     m_blocks = 0;
  22. }
  23.  
  24. //-------------------------------------------------------------
  25.  
  26. CLevel::~CLevel()
  27. {
  28.     destroy();
  29. }
  30.  
  31. //-------------------------------------------------------------
  32.  
  33. void CLevel::destroy()
  34. {
  35.     m_back_layer.destroy();
  36.     m_front_layer.destroy();
  37.     m_image.destroy();
  38. }
  39.  
  40. //-------------------------------------------------------------
  41.  
  42. bool CLevel::readUDWORD(gsUDWORD& d)
  43. {
  44.     gsUBYTE b[4];
  45.  
  46.     if (m_file.read(b,4) != 4)
  47.         return false;
  48.  
  49.     d = (((gsUDWORD) b[0]) << 24) +
  50.         (((gsUDWORD) b[1]) << 16) + 
  51.         (((gsUDWORD) b[2]) << 8) + 
  52.         ((gsUDWORD) b[3]);
  53.  
  54.     return true;
  55. }
  56.  
  57. //-------------------------------------------------------------
  58.  
  59. bool CLevel::readUWORD(gsUWORD& w)
  60. {
  61.     gsUBYTE b[2];
  62.  
  63.     if (m_file.read(b,2) != 2)
  64.         return false;
  65.  
  66.     w =    (((gsUWORD) b[0]) << 8) + 
  67.         ((gsUWORD) b[1]);
  68.  
  69.     return true;
  70. }
  71.  
  72. //-------------------------------------------------------------
  73.  
  74. bool CLevel::error()
  75. {
  76.     m_file.close();
  77.     return false;
  78. }
  79.  
  80. //-------------------------------------------------------------
  81.     
  82. #define CHUNK4(a,b,c,d) ((gsUDWORD(a) << 24) + (gsUDWORD(b) << 16) + \
  83.                         (gsUDWORD(c) << 8) + gsUDWORD(d))
  84.  
  85. const gsUDWORD CHUNK_FORM = CHUNK4('F','O','R','M');
  86. const gsUDWORD CHUNK_FMAP = CHUNK4('F','M','A','P');
  87. const gsUDWORD CHUNK_MPHD = CHUNK4('M','P','H','D');
  88. const gsUDWORD CHUNK_BKDT = CHUNK4('B','K','D','T');
  89. const gsUDWORD CHUNK_BGFX = CHUNK4('B','G','F','X');
  90. const gsUDWORD CHUNK_BODY = CHUNK4('B','O','D','Y');
  91. const gsUDWORD CHUNK_LYR1 = CHUNK4('L','Y','R','1');
  92.  
  93. bool CLevel::load(const char *filename,const char *graphics_directory)
  94. {
  95.     destroy();
  96.  
  97.     gsCFile::setDirectory(DIRECTORY_LEVELS);
  98.  
  99.     if (!m_file.open(filename,gsFILE_READ))
  100.         return false;
  101.  
  102.     gsUDWORD id = 0;
  103.  
  104.     if (!readUDWORD(id) ||
  105.         id != CHUNK_FORM)
  106.         return error();
  107.  
  108.     if (!readUDWORD(id))
  109.         return error();
  110.  
  111.     if (!readUDWORD(id) ||
  112.         id != CHUNK_FMAP)
  113.         return error();
  114.  
  115.     bool loaded_back_layer = false;
  116.     bool loaded_front_layer = false;
  117.     bool loaded_tiles = false;
  118.  
  119.     for (;;) {
  120.         if (!readUDWORD(id))
  121.             return error();
  122.  
  123.         gsUDWORD chunk_length = 0;
  124.         
  125.         if (!readUDWORD(chunk_length))
  126.             return error();
  127.  
  128.         gsUDWORD chunk_end = m_file.getPosition() + chunk_length;
  129.  
  130.         switch (id) {
  131.             case CHUNK_MPHD:
  132.                 if (m_file.read(&m_header,sizeof(MPHD)) != sizeof(MPHD))
  133.                     return error();
  134.  
  135.                 if (m_header.blockdepth != 24)
  136.                     return error();
  137.  
  138.                 m_back_layer.setSize(gsCPoint(m_header.mapwidth,m_header.mapheight));
  139.                 m_front_layer.setSize(gsCPoint(m_header.mapwidth,m_header.mapheight));
  140.             
  141.                 break;
  142.  
  143.             case CHUNK_BKDT:
  144.                 {
  145.                     m_blocks = new BLKSTR[m_header.numblockstr];
  146.  
  147.                     for (int i = 0; i < m_header.numblockstr; i++) {
  148.                         gsUDWORD size = (gsUDWORD) m_header.blockstrsize;
  149.                         if (m_file.read(&m_blocks[i],size) != size)
  150.                             return error();
  151.                         }
  152.                 }
  153.                 break;
  154.  
  155.             case CHUNK_BGFX:
  156.  
  157.                 gsCFile::setDirectory(graphics_directory);
  158.  
  159.                 if (!m_image.load("blocks.bmp"))
  160.                     return error();
  161.  
  162.                 m_image.setTileSize(gsCPoint(32,32));
  163.                 m_image.enableColourKey(gsCColour(gsMAGENTA));
  164.  
  165.                 m_back_layer.setImage(&m_image);
  166.                 m_front_layer.setImage(&m_image);
  167.  
  168.                 loaded_tiles = true;
  169.                 break;
  170.             
  171.             case CHUNK_BODY:
  172.             case CHUNK_LYR1:
  173.                 {
  174.                     gsUWORD tile;
  175.  
  176.                     for (int y = 0; y < m_header.mapheight; y++) {
  177.                         for (int x = 0; x < m_header.mapwidth; x++) {
  178.                             if (m_file.read(&tile,2) != 2)
  179.                                 return error();
  180.  
  181.                             gsCMapTile mt;
  182.  
  183.                             BLKSTR *block = &m_blocks[tile / sizeof(BLKSTR)];
  184.                             int tilesize = m_header.blockheight * m_header.blockwidth * m_header.blockdepth / 8;
  185.                             tile = (gsUWORD) (block->bgoff / tilesize);
  186.                             
  187.                             mt.setTile(tile);
  188.  
  189.                             if (tile == 0) {
  190.                                 mt.setEmpty(true);
  191.                                 mt.setHidden(true);
  192.                                 }
  193.                             else {
  194.                                 mt.setEmpty(false);
  195.                                 mt.setUserData(0,(gsUBYTE) (block->user1 & 0xFF));
  196.                                 mt.setUserData(1,(gsUBYTE) (block->user2 & 0xFF));
  197.                                 mt.setUserData(2,(gsUBYTE) (block->user3 & 0xFF));
  198.                                 mt.setUserData(3,(gsUBYTE) (block->user4 & 0xFF));
  199.  
  200.                                 gsUBYTE cflags = 0;
  201.                                 if (block->tl != 0)
  202.                                     cflags |= COLLIDE_WITH_SHIP;
  203.                                 if (block->tr != 0)
  204.                                     cflags |= COLLIDE_WITH_BULLETS;
  205.  
  206.                                 mt.setCollisionFlags(cflags);
  207.                                 }
  208.  
  209.                             if (id == CHUNK_BODY)
  210.                                 m_back_layer.setMapTile(gsCPoint(x,y),mt);
  211.                             else
  212.                                 m_front_layer.setMapTile(gsCPoint(x,y),mt);
  213.                             }
  214.                         }
  215.                 }
  216.  
  217.                 if (id == CHUNK_BODY)
  218.                     loaded_back_layer = true;
  219.                 else
  220.                     loaded_front_layer = true;
  221.                 break;
  222.  
  223.             // ignored chunks
  224.  
  225.             default:
  226.                 break;
  227.             }
  228.  
  229.         if (loaded_back_layer &&
  230.             loaded_front_layer &&
  231.             loaded_tiles)
  232.             break;
  233.  
  234.         if (!m_file.setPosition(chunk_end))
  235.             return error();
  236.         }
  237.  
  238.     if (m_blocks) {
  239.         delete [] m_blocks;
  240.         m_blocks = 0;
  241.         }
  242.  
  243.     m_file.close();
  244.  
  245.     return true;
  246. }
  247.  
  248. //-------------------------------------------------------------
  249.  
  250. void CLevel::reset()
  251. {
  252.     m_boss_active = false;
  253.  
  254.     m_scan_y = (-m_front_layer.getPosition().getY() - 1 + 480) / m_image.getTileSize().getY();    //TEMP
  255.  
  256.     // hide special tiles
  257.     // unhide everything else
  258.  
  259.     for (int x = 0; x < m_front_layer.getSize().getX(); x++) {
  260.         for (int y = 0; y < m_front_layer.getSize().getY(); y++) {
  261.             gsCMapTile *mt = m_front_layer.getMapTile(gsCPoint(x,y));
  262.             switch (mt->getUserData(0)) {
  263.                 case ID_PICKUP:
  264.                 case ID_ALIEN:
  265.                 case ID_CHECKPOINT:
  266.                 case ID_WARP_START:
  267.                 case ID_WARP_END:
  268.                 case ID_BOSS_CONTROL:
  269.                     mt->setHidden(true);
  270.                     break;
  271.                 case ID_DESTROYABLE_TILE:
  272.                     mt->setHidden(false);
  273.                     mt->setUserData(3,0);    // reset hit count
  274.                     break;
  275.                 default:
  276.                     mt->setHidden(false);
  277.                     break;
  278.                 }
  279.             }
  280.         }
  281. }
  282.  
  283. //-------------------------------------------------------------
  284.  
  285. void CLevel::scanForNewActors(CScene *scene)
  286. {
  287.     gsCScreen *screen = gsCApplication::getScreen();
  288.  
  289.     if (!screen)
  290.         return;
  291.  
  292.     gsCRect screen_rect = screen->getRect();
  293.     gsCRect source_rect(gsCPoint(0,0),m_front_layer.getSizeInPixels());
  294.     gsCRect dest_rect = source_rect;
  295.     dest_rect.move(m_front_layer.getPosition());
  296.     screen_rect.clip(source_rect,dest_rect);
  297.  
  298.     if (dest_rect.isEmpty())
  299.         return;
  300.     
  301.     // convert back to tile coords
  302.  
  303.     int top = source_rect.getTop() / m_image.getTileSize().getY();
  304.  
  305.     // get row above screen
  306.  
  307.     top--;
  308.  
  309.     if (top < 0)
  310.         return;
  311.  
  312.     while (m_scan_y >= top) {
  313.  
  314.         for (int x = 0; x < m_front_layer.getSize().getX(); x++) {
  315.  
  316.             gsCMapTile *mt = m_front_layer.getMapTile(gsCPoint(x,m_scan_y));
  317.  
  318.             if (!mt->isEmpty()) {
  319.                 gsUBYTE id = mt->getUserData(0);
  320.                 gsUBYTE type = mt->getUserData(1);
  321.                 gsUBYTE grade = mt->getUserData(2);
  322.                 gsUBYTE size = mt->getUserData(3);
  323.  
  324.                 gsCVector pos((float) x * m_image.getTileSize().getX(),
  325.                               (float) m_scan_y * m_image.getTileSize().getY());
  326.  
  327.                 pos += gsCVector((float) m_image.getTileSize().getX() / 2.f,
  328.                                  (float) m_image.getTileSize().getY() / 2.f);
  329.  
  330.                 switch (id) {
  331.                     case ID_PICKUP:
  332.                         // pickups
  333.                         {
  334.                         CPickup *p = 0;
  335.                         
  336.                         switch (type) {
  337.                             case PICKUP_SHIELD:
  338.                                 p = new CShieldPickup;
  339.                                 break;
  340.                             case PICKUP_SPEEDUP:
  341.                                 p = new CSpeedPickup;
  342.                                 break;
  343.                             case PICKUP_WEAPONUP:
  344.                                 p = new CWeaponPickup;
  345.                                 break;          
  346.                             case PICKUP_CLOAK:
  347.                                 p = new CCloakPickup;
  348.                                 break;
  349.                             case PICKUP_DIVE:
  350.                                 p = new CDivePickup;
  351.                                 break;
  352.                             case PICKUP_SCOREBONUS:
  353.                                 p = new CScorePickup;
  354.                                 break;
  355.                             case PICKUP_CLONE:
  356.                                 p = new CClonePickup;
  357.                                 break;
  358.                             case PICKUP_WINGTIP:
  359.                                 p = new CWingtipPickup;
  360.                                 break;
  361.                             case PICKUP_HOMINGMISSILE:
  362.                                 p = new CHomingMissilePickup;
  363.                                 break;
  364.                             case PICKUP_LASER:
  365.                                 p = new CLaserPickup;
  366.                                 break;
  367.                             }
  368.  
  369.                         if (p) {
  370.                             scene->addActor(p);
  371.                             p->setPosition(pos);
  372.                             p->activate();
  373.                             }
  374.                         }
  375.  
  376.                         break;
  377.                     case ID_ALIEN:
  378.                         // aliens
  379.                         
  380.                         switch (type) {
  381.                             case ASTEROID:
  382.                                 {
  383.                                     CAsteroid *a = 0;
  384.                                     
  385.                                     switch (size) {
  386.                                         case 0:
  387.                                             switch (grade) {
  388.                                                 case 0:
  389.                                                     a = new CSmallStandardAsteroid();
  390.                                                     break;
  391.                                                 case 1:
  392.                                                     a = new CSmallHighDensityAsteroid();
  393.                                                     break;
  394.                                                 case 2:
  395.                                                     a = new CSmallIndestructibleAsteroid();
  396.                                                     break;
  397.                                                 }
  398.                                             break;
  399.                                         case 1:
  400.                                             switch (grade) {
  401.                                                 case 0:
  402.                                                     a = new CMediumStandardAsteroid();
  403.                                                     break;
  404.                                                 case 1:
  405.                                                     a = new CMediumHighDensityAsteroid();
  406.                                                     break;
  407.                                                 case 2:
  408.                                                     a = new CMediumIndestructibleAsteroid();
  409.                                                     break;
  410.                                                 }
  411.                                             break;
  412.                                         case 2:
  413.                                             switch (grade) {
  414.                                                 case 0:
  415.                                                     a = new CBigStandardAsteroid();
  416.                                                     break;
  417.                                                 case 1:
  418.                                                     a = new CBigHighDensityAsteroid();
  419.                                                     break;
  420.                                                 case 2:
  421.                                                     a = new CBigIndestructibleAsteroid();
  422.                                                     break;
  423.                                                 }
  424.                                             break;
  425.                                         }
  426.  
  427.                                     if (a) {
  428.                                         scene->addActor(a);
  429.                                         a->setPosition(pos);
  430.                                         a->setVelocity(gsCVector(0.f,0.5f));
  431.                                         a->activate();
  432.                                         }
  433.                                     }
  434.                                 break;
  435.  
  436.                             case LONER:
  437.                                 {
  438.                                     CLoner *l = 0;
  439.  
  440.                                     switch (grade) {
  441.                                         case 0:
  442.                                             l = new CStandardLoner();
  443.                                             break;
  444.                                         case 1:
  445.                                             l = new CMediumLoner();
  446.                                             break;
  447.                                         case 2:
  448.                                             l = new CArmouredLoner();
  449.                                             break;
  450.                                         }
  451.  
  452.                                     if (l) {
  453.                                         scene->addActor(l);
  454.                                         l->setPosition(pos);
  455.                                         l->setVelocity(gsCVector(0.f,0.5f));
  456.                                         l->activate();
  457.                                         }
  458.                                 }
  459.                                 break;
  460.  
  461.                             case HOMER:
  462.                                 {
  463.                                     CHomer *h = new CHomer();
  464.                                     scene->addActor(h);
  465.                                     h->setPosition(pos);
  466.                                     h->setVelocity(gsCVector(0.f,0.5f));
  467.                                     h->activate();
  468.                                 }
  469.                                 break;
  470.  
  471.                             case POD:
  472.                                 {
  473.                                     CPod *p = new CPod();
  474.                                     scene->addActor(p);
  475.                                     p->setPosition(pos);
  476.                                     p->setVelocity(gsCVector(0.f,0.f));
  477.                                     p->activate();
  478.                                 }
  479.                                 break;
  480.  
  481.                             case RUSHER:
  482.                                 {
  483.                                     CRusher *r = new CRusher();
  484.                                     scene->addActor(r);
  485.                                     r->setPosition(pos);
  486.                                     r->setVelocity(gsCVector(0.f,2.f));
  487.                                     r->activate();
  488.                                 }
  489.                                 break;
  490.  
  491.                             case WALLHUGGER:
  492.                                 {
  493.                                     CWallHugger *w = new CWallHugger();
  494.                                     scene->addActor(w);
  495.                                     w->setPosition(pos);
  496.                                     w->setVelocity(gsCVector(0.f,0.f));
  497.                                     w->activate();
  498.  
  499.                                     switch (grade) {
  500.                                         case 0:
  501.                                             w->setGrade(WALLHUGGER_STATIC);
  502.                                             break;
  503.                                         case 1:
  504.                                             w->setGrade(WALLHUGGER_MOVING);
  505.                                             break;
  506.                                         }
  507.                                 }
  508.                                 break;
  509.  
  510.                             case DRONE_GENERATOR:
  511.                                 {
  512.                                     CDroneGenerator *d = new CDroneGenerator();
  513.                                     scene->addActor(d);
  514.                                     d->setPosition(pos);
  515.                                     d->activate();
  516.                                 }
  517.                                 break;
  518.  
  519.                             case REVERSE_RUSHER:
  520.                                 {
  521.                                     CRusher *r = new CRusher();
  522.                                     scene->addActor(r);
  523.                                     r->setPosition(pos + gsCVector(0.f,(float) screen->getSize().getY() +
  524.                                                                        m_image.getTileSize().getY()));
  525.                                     r->setVelocity(gsCVector(0.f,-4.f));
  526.                                     r->activate();
  527.                                 }
  528.                                 break;
  529.  
  530.                             case RUSHER_GENERATOR_LEFT:
  531.                                 {
  532.                                     CRusherGenerator *r = new CRusherGenerator();
  533.                                     scene->addActor(r);
  534.                                     r->setPosition(pos);
  535.                                     r->setVelocity(gsCVector(-2.f,0.f));
  536.                                     r->activate();
  537.                                 }
  538.                                 break;
  539.  
  540.                             case RUSHER_GENERATOR_RIGHT:
  541.                                 {
  542.                                     CRusherGenerator *r = new CRusherGenerator();
  543.                                     scene->addActor(r);
  544.                                     r->setPosition(pos);
  545.                                     r->setVelocity(gsCVector(2.f,0.f));
  546.                                     r->activate();
  547.                                 }
  548.                                 break;
  549.  
  550.                             case ORGANIC_GUN:
  551.                                 {
  552.                                     COrganicGun *w = new COrganicGun();
  553.                                     scene->addActor(w);
  554.                                     w->setPosition(pos);
  555.                                     w->setVelocity(gsCVector(0.f,0.f));
  556.                                     w->activate();
  557.                                     if (grade == 0)
  558.                                         w->setDirection(1);
  559.                                     else
  560.                                         w->setDirection(-1);
  561.                                 }
  562.                                 break;
  563.  
  564.                             default:
  565.  
  566.                                 CBigExplosion *x = new CBigExplosion();
  567.                                 scene->addActor(x);
  568.                                 x->setPosition(pos);
  569.                                 x->activate();
  570.                                 break;
  571.                             }
  572.                         break;
  573.  
  574.                     case ID_CHECKPOINT:
  575.                         scene->setNextCheckpoint(pos);
  576.                         break;
  577.  
  578.                     case ID_WARP_START:
  579.                         scene->setWarp(true);
  580.                         break;
  581.  
  582.                     case ID_WARP_END:
  583.                         scene->setWarp(false);
  584.                         break;
  585.  
  586.                     case ID_BOSS_MOUTH:
  587.                         {
  588.                             CBossMouth *m = new CBossMouth();
  589.                             scene->addActor(m);
  590.                             m->setPosition(pos);
  591.                             m->setVelocity(gsCVector(0.f,0.f));
  592.                             m->activate();
  593.                         }
  594.                         break;
  595.                     case ID_BOSS_EYE:
  596.                         {
  597.                             CBossEye *e = new CBossEye();
  598.                             e->setEyeNumber(type);
  599.                             scene->addActor(e);
  600.                             switch (type) {
  601.                                 case 0:
  602.                                 case 1:
  603.                                 case 4:
  604.                                 case 5:
  605.                                     e->setPosition(pos);
  606.                                     break;
  607.                                 case 2:
  608.                                     e->setPosition(pos + gsCVector(15.f,20.f));
  609.                                     break;
  610.                                 case 3:
  611.                                     e->setPosition(pos + gsCVector(15.f,20.f));
  612.                                     break;
  613.                                 }
  614.                             e->setVelocity(gsCVector(0.f,0.f));
  615.                             e->activate();
  616.                         }
  617.                         break;
  618.                     case ID_BOSS_CONTROL:
  619.                         {
  620.                             CBossControl *m = new CBossControl();
  621.                             scene->addActor(m);
  622.                             m->setPosition(pos);
  623.                             m->setVelocity(gsCVector(0.f,0.f));
  624.                             m->activate();
  625.  
  626.                             m_boss_active = true;
  627.                         }
  628.                         break;
  629.                     }
  630.                 }
  631.             }
  632.  
  633.         m_scan_y--;
  634.         }
  635. }
  636.  
  637. //-------------------------------------------------------------
  638.