GameSSDWindow.cpp 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "../framework/Session_local.h"
  23. #include "DeviceContext.h"
  24. #include "Window.h"
  25. #include "UserInterfaceLocal.h"
  26. #include "GameSSDWindow.h"
  27. #define Z_NEAR 100.0f
  28. #define Z_FAR 4000.0f
  29. #define ENTITY_START_DIST 3000
  30. #define V_WIDTH 640.0f
  31. #define V_HEIGHT 480.0f
  32. /*
  33. *****************************************************************************
  34. * SSDCrossHair
  35. ****************************************************************************
  36. */
  37. #define CROSSHAIR_STANDARD_MATERIAL "game/SSD/crosshair_standard"
  38. #define CROSSHAIR_SUPER_MATERIAL "game/SSD/crosshair_super"
  39. SSDCrossHair::SSDCrossHair() {
  40. }
  41. SSDCrossHair::~SSDCrossHair() {
  42. }
  43. void SSDCrossHair::WriteToSaveGame( idFile *savefile ) {
  44. savefile->Write(&currentCrosshair, sizeof(currentCrosshair));
  45. savefile->Write(&crosshairWidth, sizeof(crosshairWidth));
  46. savefile->Write(&crosshairHeight, sizeof(crosshairHeight));
  47. }
  48. void SSDCrossHair::ReadFromSaveGame( idFile *savefile ) {
  49. InitCrosshairs();
  50. savefile->Read(&currentCrosshair, sizeof(currentCrosshair));
  51. savefile->Read(&crosshairWidth, sizeof(crosshairWidth));
  52. savefile->Read(&crosshairHeight, sizeof(crosshairHeight));
  53. }
  54. void SSDCrossHair::InitCrosshairs() {
  55. crosshairMaterial[CROSSHAIR_STANDARD] = declManager->FindMaterial( CROSSHAIR_STANDARD_MATERIAL );
  56. crosshairMaterial[CROSSHAIR_SUPER] = declManager->FindMaterial( CROSSHAIR_SUPER_MATERIAL );
  57. crosshairWidth = 64;
  58. crosshairHeight = 64;
  59. currentCrosshair = CROSSHAIR_STANDARD;
  60. }
  61. void SSDCrossHair::Draw(idDeviceContext *dc, const idVec2& cursor) {
  62. float x,y;
  63. x = cursor.x-(crosshairWidth/2);
  64. y = cursor.y-(crosshairHeight/2);
  65. dc->DrawMaterial(x, y, crosshairWidth, crosshairHeight, crosshairMaterial[currentCrosshair], colorWhite, 1.0f, 1.0f);
  66. }
  67. /*
  68. *****************************************************************************
  69. * SSDEntity
  70. ****************************************************************************
  71. */
  72. SSDEntity::SSDEntity() {
  73. EntityInit();
  74. }
  75. SSDEntity::~SSDEntity() {
  76. }
  77. void SSDEntity::WriteToSaveGame( idFile *savefile ) {
  78. savefile->Write(&type, sizeof(type));
  79. game->WriteSaveGameString(materialName, savefile);
  80. savefile->Write(&position, sizeof(position));
  81. savefile->Write(&size, sizeof(size));
  82. savefile->Write(&radius, sizeof(radius));
  83. savefile->Write(&hitRadius, sizeof(hitRadius));
  84. savefile->Write(&rotation, sizeof(rotation));
  85. savefile->Write(&matColor, sizeof(matColor));
  86. game->WriteSaveGameString(text, savefile);
  87. savefile->Write(&textScale, sizeof(textScale));
  88. savefile->Write(&foreColor, sizeof(foreColor));
  89. savefile->Write(&currentTime, sizeof(currentTime));
  90. savefile->Write(&lastUpdate, sizeof(lastUpdate));
  91. savefile->Write(&elapsed, sizeof(elapsed));
  92. savefile->Write(&destroyed, sizeof(destroyed));
  93. savefile->Write(&noHit, sizeof(noHit));
  94. savefile->Write(&noPlayerDamage, sizeof(noPlayerDamage));
  95. savefile->Write(&inUse, sizeof(inUse));
  96. }
  97. void SSDEntity::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) {
  98. savefile->Read(&type, sizeof(type));
  99. game->ReadSaveGameString(materialName, savefile);
  100. SetMaterial(materialName);
  101. savefile->Read(&position, sizeof(position));
  102. savefile->Read(&size, sizeof(size));
  103. savefile->Read(&radius, sizeof(radius));
  104. savefile->Read(&hitRadius, sizeof(hitRadius));
  105. savefile->Read(&rotation, sizeof(rotation));
  106. savefile->Read(&matColor, sizeof(matColor));
  107. game->ReadSaveGameString(text, savefile);
  108. savefile->Read(&textScale, sizeof(textScale));
  109. savefile->Read(&foreColor, sizeof(foreColor));
  110. game = _game;
  111. savefile->Read(&currentTime, sizeof(currentTime));
  112. savefile->Read(&lastUpdate, sizeof(lastUpdate));
  113. savefile->Read(&elapsed, sizeof(elapsed));
  114. savefile->Read(&destroyed, sizeof(destroyed));
  115. savefile->Read(&noHit, sizeof(noHit));
  116. savefile->Read(&noPlayerDamage, sizeof(noPlayerDamage));
  117. savefile->Read(&inUse, sizeof(inUse));
  118. }
  119. void SSDEntity::EntityInit() {
  120. inUse = false;
  121. type = SSD_ENTITY_BASE;
  122. materialName = "";
  123. material = NULL;
  124. position.Zero();
  125. size.Zero();
  126. radius = 0.0f;
  127. hitRadius = 0.0f;
  128. rotation = 0.0f;
  129. currentTime = 0;
  130. lastUpdate = 0;
  131. destroyed = false;
  132. noHit = false;
  133. noPlayerDamage = false;
  134. matColor.Set(1, 1, 1, 1);
  135. text = "";
  136. textScale = 1.0f;
  137. foreColor.Set(1, 1, 1, 1);
  138. }
  139. void SSDEntity::SetGame(idGameSSDWindow* _game) {
  140. game = _game;
  141. }
  142. void SSDEntity::SetMaterial(const char* name) {
  143. materialName = name;
  144. material = declManager->FindMaterial( name );
  145. material->SetSort( SS_GUI );
  146. }
  147. void SSDEntity::SetPosition(const idVec3& _position) {
  148. position = _position;
  149. }
  150. void SSDEntity::SetSize(const idVec2& _size) {
  151. size = _size;
  152. }
  153. void SSDEntity::SetRadius(float _radius, float _hitFactor) {
  154. radius = _radius;
  155. hitRadius = _radius*_hitFactor;
  156. }
  157. void SSDEntity::SetRotation(float _rotation) {
  158. rotation = _rotation;
  159. }
  160. void SSDEntity::Update() {
  161. currentTime = game->ssdTime;
  162. //Is this the first update
  163. if(lastUpdate == 0) {
  164. lastUpdate = currentTime;
  165. return;
  166. }
  167. elapsed = currentTime - lastUpdate;
  168. EntityUpdate();
  169. lastUpdate = currentTime;
  170. }
  171. bool SSDEntity::HitTest(const idVec2& pt) {
  172. if(noHit) {
  173. return false;
  174. }
  175. idVec3 screenPos = WorldToScreen(position);
  176. //Scale the radius based on the distance from the player
  177. float scale = 1.0f -((screenPos.z-Z_NEAR)/(Z_FAR-Z_NEAR));
  178. float scaledRad = scale*hitRadius;
  179. //So we can compare against the square of the length between two points
  180. float scaleRadSqr = scaledRad*scaledRad;
  181. idVec2 diff = screenPos.ToVec2()-pt;
  182. float dist = idMath::Fabs(diff.LengthSqr());
  183. if(dist < scaleRadSqr) {
  184. return true;
  185. }
  186. return false;
  187. }
  188. void SSDEntity::Draw(idDeviceContext *dc) {
  189. idVec2 persize;
  190. float x,y;
  191. idBounds bounds;
  192. bounds[0] = idVec3(position.x - (size.x/2.0f), position.y - (size.y/2.0f), position.z);
  193. bounds[1] = idVec3(position.x + (size.x/2.0f), position.y + (size.y/2.0f), position.z);
  194. idBounds screenBounds = WorldToScreen(bounds);
  195. persize.x = idMath::Fabs(screenBounds[1].x - screenBounds[0].x);
  196. persize.y = idMath::Fabs(screenBounds[1].y - screenBounds[0].y);
  197. idVec3 center = screenBounds.GetCenter();
  198. x = screenBounds[0].x;
  199. y = screenBounds[1].y;
  200. dc->DrawMaterialRotated(x, y, persize.x, persize.y, material, matColor, 1.0f, 1.0f, DEG2RAD(rotation));
  201. if(text.Length() > 0) {
  202. idRectangle rect( x, y, VIRTUAL_WIDTH, VIRTUAL_HEIGHT );
  203. dc->DrawText( text, textScale, 0, foreColor, rect, false );
  204. }
  205. }
  206. void SSDEntity::DestroyEntity() {
  207. inUse = false;
  208. }
  209. idBounds SSDEntity::WorldToScreen(const idBounds worldBounds) {
  210. idVec3 screenMin = WorldToScreen(worldBounds[0]);
  211. idVec3 screenMax = WorldToScreen(worldBounds[1]);
  212. idBounds screenBounds(screenMin, screenMax);
  213. return screenBounds;
  214. }
  215. idVec3 SSDEntity::WorldToScreen(const idVec3& worldPos) {
  216. float d = 0.5f*V_WIDTH*idMath::Tan(DEG2RAD(90.0f)/2.0f);
  217. //World To Camera Coordinates
  218. idVec3 cameraTrans(0,0,d);
  219. idVec3 cameraPos;
  220. cameraPos = worldPos + cameraTrans;
  221. //Camera To Screen Coordinates
  222. idVec3 screenPos;
  223. screenPos.x = d*cameraPos.x/cameraPos.z + (0.5f*V_WIDTH-0.5f);
  224. screenPos.y = -d*cameraPos.y/cameraPos.z + (0.5f*V_HEIGHT-0.5f);
  225. screenPos.z = cameraPos.z;
  226. return screenPos;
  227. }
  228. idVec3 SSDEntity::ScreenToWorld(const idVec3& screenPos) {
  229. idVec3 worldPos;
  230. worldPos.x = screenPos.x - 0.5f * V_WIDTH;
  231. worldPos.y = -(screenPos.y - 0.5f * V_HEIGHT);
  232. worldPos.z = screenPos.z;
  233. return worldPos;
  234. }
  235. /*
  236. *****************************************************************************
  237. * SSDMover
  238. ****************************************************************************
  239. */
  240. SSDMover::SSDMover() {
  241. }
  242. SSDMover::~SSDMover() {
  243. }
  244. void SSDMover::WriteToSaveGame( idFile *savefile ) {
  245. SSDEntity::WriteToSaveGame(savefile);
  246. savefile->Write(&speed, sizeof(speed));
  247. savefile->Write(&rotationSpeed, sizeof(rotationSpeed));
  248. }
  249. void SSDMover::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) {
  250. SSDEntity::ReadFromSaveGame(savefile, _game);
  251. savefile->Read(&speed, sizeof(speed));
  252. savefile->Read(&rotationSpeed, sizeof(rotationSpeed));
  253. }
  254. void SSDMover::MoverInit(const idVec3& _speed, float _rotationSpeed) {
  255. speed = _speed;
  256. rotationSpeed = _rotationSpeed;
  257. }
  258. void SSDMover::EntityUpdate() {
  259. SSDEntity::EntityUpdate();
  260. //Move forward based on speed (units per second)
  261. idVec3 moved = ((float)elapsed/1000.0f)*speed;
  262. position += moved;
  263. float rotated = ((float)elapsed/1000.0f)*rotationSpeed*360.0f;
  264. rotation += rotated;
  265. if(rotation >= 360) {
  266. rotation -= 360.0f;
  267. }
  268. if(rotation < 0) {
  269. rotation += 360.0f;
  270. }
  271. }
  272. /*
  273. *****************************************************************************
  274. * SSDAsteroid
  275. ****************************************************************************
  276. */
  277. SSDAsteroid SSDAsteroid::asteroidPool[MAX_ASTEROIDS];
  278. #define ASTEROID_MATERIAL "game/SSD/asteroid"
  279. SSDAsteroid::SSDAsteroid() {
  280. }
  281. SSDAsteroid::~SSDAsteroid() {
  282. }
  283. void SSDAsteroid::WriteToSaveGame( idFile *savefile ) {
  284. SSDMover::WriteToSaveGame(savefile);
  285. savefile->Write(&health, sizeof(health));
  286. }
  287. void SSDAsteroid::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) {
  288. SSDMover::ReadFromSaveGame(savefile, _game);
  289. savefile->Read(&health, sizeof(health));
  290. }
  291. void SSDAsteroid::Init(idGameSSDWindow* _game, const idVec3& startPosition, const idVec2& _size, float _speed, float rotate, int _health) {
  292. EntityInit();
  293. MoverInit(idVec3(0,0, -_speed), rotate);
  294. SetGame(_game);
  295. type = SSD_ENTITY_ASTEROID;
  296. SetMaterial(ASTEROID_MATERIAL);
  297. SetSize(_size);
  298. SetRadius(Max(size.x, size.y), 0.3f);
  299. SetRotation(game->random.RandomInt(360));
  300. position = startPosition;
  301. health = _health;
  302. }
  303. void SSDAsteroid::EntityUpdate() {
  304. SSDMover::EntityUpdate();
  305. }
  306. SSDAsteroid* SSDAsteroid::GetNewAsteroid(idGameSSDWindow* _game, const idVec3& startPosition, const idVec2& _size, float _speed, float rotate, int _health) {
  307. for(int i = 0; i < MAX_ASTEROIDS; i++) {
  308. if(!asteroidPool[i].inUse) {
  309. asteroidPool[i].Init(_game, startPosition, _size, _speed, rotate, _health);
  310. asteroidPool[i].inUse = true;
  311. asteroidPool[i].id = i;
  312. return &asteroidPool[i];
  313. }
  314. }
  315. return NULL;
  316. }
  317. SSDAsteroid* SSDAsteroid::GetSpecificAsteroid(int id) {
  318. return &asteroidPool[id];
  319. }
  320. void SSDAsteroid::WriteAsteroids(idFile* savefile) {
  321. int count = 0;
  322. for(int i = 0; i < MAX_ASTEROIDS; i++) {
  323. if(asteroidPool[i].inUse) {
  324. count++;
  325. }
  326. }
  327. savefile->Write(&count, sizeof(count));
  328. for(int i = 0; i < MAX_ASTEROIDS; i++) {
  329. if(asteroidPool[i].inUse) {
  330. savefile->Write(&(asteroidPool[i].id), sizeof(asteroidPool[i].id));
  331. asteroidPool[i].WriteToSaveGame(savefile);
  332. }
  333. }
  334. }
  335. void SSDAsteroid::ReadAsteroids(idFile* savefile, idGameSSDWindow* _game) {
  336. int count;
  337. savefile->Read(&count, sizeof(count));
  338. for(int i = 0; i < count; i++) {
  339. int id;
  340. savefile->Read(&id, sizeof(id));
  341. SSDAsteroid* ent = GetSpecificAsteroid(id);
  342. ent->ReadFromSaveGame(savefile, _game);
  343. }
  344. }
  345. /*
  346. *****************************************************************************
  347. * SSDAstronaut
  348. ****************************************************************************
  349. */
  350. SSDAstronaut SSDAstronaut::astronautPool[MAX_ASTRONAUT];
  351. #define ASTRONAUT_MATERIAL "game/SSD/astronaut"
  352. SSDAstronaut::SSDAstronaut() {
  353. }
  354. SSDAstronaut::~SSDAstronaut() {
  355. }
  356. void SSDAstronaut::WriteToSaveGame( idFile *savefile ) {
  357. SSDMover::WriteToSaveGame(savefile);
  358. savefile->Write(&health, sizeof(health));
  359. }
  360. void SSDAstronaut::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) {
  361. SSDMover::ReadFromSaveGame(savefile, _game);
  362. savefile->Read(&health, sizeof(health));
  363. }
  364. void SSDAstronaut::Init(idGameSSDWindow* _game, const idVec3& startPosition, float _speed, float rotate, int _health) {
  365. EntityInit();
  366. MoverInit(idVec3(0,0, -_speed), rotate);
  367. SetGame(_game);
  368. type = SSD_ENTITY_ASTRONAUT;
  369. SetMaterial(ASTRONAUT_MATERIAL);
  370. SetSize(idVec2(256,256));
  371. SetRadius(Max(size.x, size.y), 0.3f);
  372. SetRotation(game->random.RandomInt(360));
  373. position = startPosition;
  374. health = _health;
  375. }
  376. SSDAstronaut* SSDAstronaut::GetNewAstronaut(idGameSSDWindow* _game, const idVec3& startPosition, float _speed, float rotate, int _health) {
  377. for(int i = 0; i < MAX_ASTRONAUT; i++) {
  378. if(!astronautPool[i].inUse) {
  379. astronautPool[i].Init(_game, startPosition, _speed, rotate, _health);
  380. astronautPool[i].inUse = true;
  381. astronautPool[i].id = i;
  382. return &astronautPool[i];
  383. }
  384. }
  385. return NULL;
  386. }
  387. SSDAstronaut* SSDAstronaut::GetSpecificAstronaut(int id) {
  388. return &astronautPool[id];
  389. }
  390. void SSDAstronaut::WriteAstronauts(idFile* savefile) {
  391. int count = 0;
  392. for(int i = 0; i < MAX_ASTRONAUT; i++) {
  393. if(astronautPool[i].inUse) {
  394. count++;
  395. }
  396. }
  397. savefile->Write(&count, sizeof(count));
  398. for(int i = 0; i < MAX_ASTRONAUT; i++) {
  399. if(astronautPool[i].inUse) {
  400. savefile->Write(&(astronautPool[i].id), sizeof(astronautPool[i].id));
  401. astronautPool[i].WriteToSaveGame(savefile);
  402. }
  403. }
  404. }
  405. void SSDAstronaut::ReadAstronauts(idFile* savefile, idGameSSDWindow* _game) {
  406. int count;
  407. savefile->Read(&count, sizeof(count));
  408. for(int i = 0; i < count; i++) {
  409. int id;
  410. savefile->Read(&id, sizeof(id));
  411. SSDAstronaut* ent = GetSpecificAstronaut(id);
  412. ent->ReadFromSaveGame(savefile, _game);
  413. }
  414. }
  415. /*
  416. *****************************************************************************
  417. * SSDExplosion
  418. ****************************************************************************
  419. */
  420. SSDExplosion SSDExplosion::explosionPool[MAX_EXPLOSIONS];
  421. //#define EXPLOSION_MATERIAL "game/SSD/fball"
  422. //#define EXPLOSION_TELEPORT "game/SSD/teleport"
  423. const char* explosionMaterials[] = {
  424. "game/SSD/fball",
  425. "game/SSD/teleport"
  426. };
  427. #define EXPLOSION_MATERIAL_COUNT 2
  428. SSDExplosion::SSDExplosion() {
  429. type = SSD_ENTITY_EXPLOSION;
  430. }
  431. SSDExplosion::~SSDExplosion() {
  432. }
  433. void SSDExplosion::WriteToSaveGame( idFile *savefile ) {
  434. SSDEntity::WriteToSaveGame(savefile);
  435. savefile->Write(&finalSize, sizeof(finalSize));
  436. savefile->Write(&length, sizeof(length));
  437. savefile->Write(&beginTime, sizeof(beginTime));
  438. savefile->Write(&endTime, sizeof(endTime));
  439. savefile->Write(&explosionType, sizeof(explosionType));
  440. savefile->Write(&(buddy->type), sizeof(buddy->type));
  441. savefile->Write(&(buddy->id), sizeof(buddy->id));
  442. savefile->Write(&killBuddy, sizeof(killBuddy));
  443. savefile->Write(&followBuddy, sizeof(followBuddy));
  444. }
  445. void SSDExplosion::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) {
  446. SSDEntity::ReadFromSaveGame(savefile, _game);
  447. savefile->Read(&finalSize, sizeof(finalSize));
  448. savefile->Read(&length, sizeof(length));
  449. savefile->Read(&beginTime, sizeof(beginTime));
  450. savefile->Read(&endTime, sizeof(endTime));
  451. savefile->Read(&explosionType, sizeof(explosionType));
  452. int type, id;
  453. savefile->Read(&type, sizeof(type));
  454. savefile->Read(&id, sizeof(id));
  455. //Get a pointer to my buddy
  456. buddy = _game->GetSpecificEntity(type, id);
  457. savefile->Read(&killBuddy, sizeof(killBuddy));
  458. savefile->Read(&followBuddy, sizeof(followBuddy));
  459. }
  460. void SSDExplosion::Init(idGameSSDWindow* _game, const idVec3& _position, const idVec2& _size, int _length, int _type, SSDEntity* _buddy, bool _killBuddy, bool _followBuddy) {
  461. EntityInit();
  462. SetGame(_game);
  463. type = SSD_ENTITY_EXPLOSION;
  464. explosionType = _type;
  465. SetMaterial(explosionMaterials[explosionType]);
  466. SetPosition(_position);
  467. position.z -= 50;
  468. finalSize = _size;
  469. length = _length;
  470. beginTime = game->ssdTime;
  471. endTime = beginTime + length;
  472. buddy = _buddy;
  473. killBuddy = _killBuddy;
  474. followBuddy = _followBuddy;
  475. //Explosion Starts from nothing and will increase in size until it gets to final size
  476. size.Zero();
  477. noPlayerDamage = true;
  478. noHit = true;
  479. }
  480. void SSDExplosion::EntityUpdate() {
  481. SSDEntity::EntityUpdate();
  482. //Always set my position to my buddies position except change z to be on top
  483. if(followBuddy) {
  484. position = buddy->position;
  485. position.z -= 50;
  486. } else {
  487. //Only mess with the z if we are not following
  488. position.z = buddy->position.z - 50;
  489. }
  490. //Scale the image based on the time
  491. size = finalSize*((float)(currentTime-beginTime)/(float)length);
  492. //Destroy myself after the explosion is done
  493. if(currentTime > endTime) {
  494. destroyed = true;
  495. if(killBuddy) {
  496. //Destroy the exploding object
  497. buddy->destroyed = true;
  498. }
  499. }
  500. }
  501. SSDExplosion* SSDExplosion::GetNewExplosion(idGameSSDWindow* _game, const idVec3& _position, const idVec2& _size, int _length, int _type, SSDEntity* _buddy, bool _killBuddy, bool _followBuddy) {
  502. for(int i = 0; i < MAX_EXPLOSIONS; i++) {
  503. if(!explosionPool[i].inUse) {
  504. explosionPool[i].Init(_game, _position, _size, _length, _type, _buddy, _killBuddy, _followBuddy);
  505. explosionPool[i].inUse = true;
  506. return &explosionPool[i];
  507. }
  508. }
  509. return NULL;
  510. }
  511. SSDExplosion* SSDExplosion::GetSpecificExplosion(int id) {
  512. return &explosionPool[id];
  513. }
  514. void SSDExplosion::WriteExplosions(idFile* savefile) {
  515. int count = 0;
  516. for(int i = 0; i < MAX_EXPLOSIONS; i++) {
  517. if(explosionPool[i].inUse) {
  518. count++;
  519. }
  520. }
  521. savefile->Write(&count, sizeof(count));
  522. for(int i = 0; i < MAX_EXPLOSIONS; i++) {
  523. if(explosionPool[i].inUse) {
  524. savefile->Write(&(explosionPool[i].id), sizeof(explosionPool[i].id));
  525. explosionPool[i].WriteToSaveGame(savefile);
  526. }
  527. }
  528. }
  529. void SSDExplosion::ReadExplosions(idFile* savefile, idGameSSDWindow* _game) {
  530. int count;
  531. savefile->Read(&count, sizeof(count));
  532. for(int i = 0; i < count; i++) {
  533. int id;
  534. savefile->Read(&id, sizeof(id));
  535. SSDExplosion* ent = GetSpecificExplosion(id);
  536. ent->ReadFromSaveGame(savefile, _game);
  537. }
  538. }
  539. /*
  540. *****************************************************************************
  541. * SSDPoints
  542. ****************************************************************************
  543. */
  544. SSDPoints SSDPoints::pointsPool[MAX_POINTS];
  545. SSDPoints::SSDPoints() {
  546. type = SSD_ENTITY_POINTS;
  547. }
  548. SSDPoints::~SSDPoints() {
  549. }
  550. void SSDPoints::WriteToSaveGame( idFile *savefile ) {
  551. SSDEntity::WriteToSaveGame(savefile);
  552. savefile->Write(&length, sizeof(length));
  553. savefile->Write(&distance, sizeof(distance));
  554. savefile->Write(&beginTime, sizeof(beginTime));
  555. savefile->Write(&endTime, sizeof(endTime));
  556. savefile->Write(&beginPosition, sizeof(beginPosition));
  557. savefile->Write(&endPosition, sizeof(endPosition));
  558. savefile->Write(&beginColor, sizeof(beginColor));
  559. savefile->Write(&endColor, sizeof(endColor));
  560. }
  561. void SSDPoints::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) {
  562. SSDEntity::ReadFromSaveGame(savefile, _game);
  563. savefile->Read(&length, sizeof(length));
  564. savefile->Read(&distance, sizeof(distance));
  565. savefile->Read(&beginTime, sizeof(beginTime));
  566. savefile->Read(&endTime, sizeof(endTime));
  567. savefile->Read(&beginPosition, sizeof(beginPosition));
  568. savefile->Read(&endPosition, sizeof(endPosition));
  569. savefile->Read(&beginColor, sizeof(beginColor));
  570. savefile->Read(&endColor, sizeof(endColor));
  571. }
  572. void SSDPoints::Init(idGameSSDWindow* _game, SSDEntity* _ent, int _points, int _length, int _distance, const idVec4& color) {
  573. EntityInit();
  574. SetGame(_game);
  575. length = _length;
  576. distance = _distance;
  577. beginTime = game->ssdTime;
  578. endTime = beginTime + length;
  579. textScale = 0.4f;
  580. text = va("%d", _points);
  581. float width = 0;
  582. for(int i = 0; i < text.Length(); i++) {
  583. width += game->GetDC()->CharWidth(text[i], textScale);
  584. }
  585. size.Set(0,0);
  586. //Set the start position at the top of the passed in entity
  587. position = WorldToScreen(_ent->position);
  588. position = ScreenToWorld(position);
  589. position.z = 0;
  590. position.x -= (width/2.0f);
  591. beginPosition = position;
  592. endPosition = beginPosition;
  593. endPosition.y += _distance;
  594. //beginColor.Set(0,1,0,1);
  595. endColor.Set(1,1,1,0);
  596. beginColor = color;
  597. beginColor.w = 1;
  598. noPlayerDamage = true;
  599. noHit = true;
  600. }
  601. void SSDPoints::EntityUpdate() {
  602. float t = (float)(currentTime - beginTime)/(float)length;
  603. //Move up from the start position
  604. position.Lerp(beginPosition, endPosition, t);
  605. //Interpolate the color
  606. foreColor.Lerp(beginColor, endColor, t);
  607. if(currentTime > endTime) {
  608. destroyed = true;
  609. }
  610. }
  611. SSDPoints* SSDPoints::GetNewPoints(idGameSSDWindow* _game, SSDEntity* _ent, int _points, int _length, int _distance, const idVec4& color) {
  612. for(int i = 0; i < MAX_POINTS; i++) {
  613. if(!pointsPool[i].inUse) {
  614. pointsPool[i].Init(_game, _ent, _points, _length, _distance, color);
  615. pointsPool[i].inUse = true;
  616. return &pointsPool[i];
  617. }
  618. }
  619. return NULL;
  620. }
  621. SSDPoints* SSDPoints::GetSpecificPoints(int id) {
  622. return &pointsPool[id];
  623. }
  624. void SSDPoints::WritePoints(idFile* savefile) {
  625. int count = 0;
  626. for(int i = 0; i < MAX_POINTS; i++) {
  627. if(pointsPool[i].inUse) {
  628. count++;
  629. }
  630. }
  631. savefile->Write(&count, sizeof(count));
  632. for(int i = 0; i < MAX_POINTS; i++) {
  633. if(pointsPool[i].inUse) {
  634. savefile->Write(&(pointsPool[i].id), sizeof(pointsPool[i].id));
  635. pointsPool[i].WriteToSaveGame(savefile);
  636. }
  637. }
  638. }
  639. void SSDPoints::ReadPoints(idFile* savefile, idGameSSDWindow* _game) {
  640. int count;
  641. savefile->Read(&count, sizeof(count));
  642. for(int i = 0; i < count; i++) {
  643. int id;
  644. savefile->Read(&id, sizeof(id));
  645. SSDPoints* ent = GetSpecificPoints(id);
  646. ent->ReadFromSaveGame(savefile, _game);
  647. }
  648. }
  649. /*
  650. *****************************************************************************
  651. * SSDProjectile
  652. ****************************************************************************
  653. */
  654. SSDProjectile SSDProjectile::projectilePool[MAX_PROJECTILES];
  655. #define PROJECTILE_MATERIAL "game/SSD/fball"
  656. SSDProjectile::SSDProjectile() {
  657. type = SSD_ENTITY_PROJECTILE;
  658. }
  659. SSDProjectile::~SSDProjectile() {
  660. }
  661. void SSDProjectile::WriteToSaveGame( idFile *savefile ) {
  662. SSDEntity::WriteToSaveGame(savefile);
  663. savefile->Write(&dir, sizeof(dir));
  664. savefile->Write(&speed, sizeof(speed));
  665. savefile->Write(&beginTime, sizeof(beginTime));
  666. savefile->Write(&endTime, sizeof(endTime));
  667. savefile->Write(&endPosition, sizeof(endPosition));
  668. }
  669. void SSDProjectile::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) {
  670. SSDEntity::ReadFromSaveGame(savefile, _game);
  671. savefile->Read(&dir, sizeof(dir));
  672. savefile->Read(&speed, sizeof(speed));
  673. savefile->Read(&beginTime, sizeof(beginTime));
  674. savefile->Read(&endTime, sizeof(endTime));
  675. savefile->Read(&endPosition, sizeof(endPosition));
  676. }
  677. void SSDProjectile::Init(idGameSSDWindow* _game, const idVec3& _beginPosition, const idVec3& _endPosition, float _speed, float _size) {
  678. EntityInit();
  679. SetGame(_game);
  680. SetMaterial(PROJECTILE_MATERIAL);
  681. size.Set(_size,_size);
  682. position = _beginPosition;
  683. endPosition = _endPosition;
  684. dir = _endPosition - position;
  685. dir.Normalize();
  686. //speed.Zero();
  687. speed.x = speed.y = speed.z = _speed;
  688. noHit = true;
  689. }
  690. void SSDProjectile::EntityUpdate() {
  691. SSDEntity::EntityUpdate();
  692. //Move forward based on speed (units per second)
  693. idVec3 moved = dir*((float)elapsed/1000.0f)*speed.z;
  694. position += moved;
  695. if(position.z > endPosition.z) {
  696. //We have reached our position
  697. destroyed = true;
  698. }
  699. }
  700. SSDProjectile* SSDProjectile::GetNewProjectile(idGameSSDWindow* _game, const idVec3& _beginPosition, const idVec3& _endPosition, float _speed, float _size) {
  701. for(int i = 0; i < MAX_PROJECTILES; i++) {
  702. if(!projectilePool[i].inUse) {
  703. projectilePool[i].Init(_game, _beginPosition, _endPosition, _speed, _size);
  704. projectilePool[i].inUse = true;
  705. return &projectilePool[i];
  706. }
  707. }
  708. return NULL;
  709. }
  710. SSDProjectile* SSDProjectile::GetSpecificProjectile(int id) {
  711. return &projectilePool[id];
  712. }
  713. void SSDProjectile::WriteProjectiles(idFile* savefile) {
  714. int count = 0;
  715. for(int i = 0; i < MAX_PROJECTILES; i++) {
  716. if(projectilePool[i].inUse) {
  717. count++;
  718. }
  719. }
  720. savefile->Write(&count, sizeof(count));
  721. for(int i = 0; i < MAX_PROJECTILES; i++) {
  722. if(projectilePool[i].inUse) {
  723. savefile->Write(&(projectilePool[i].id), sizeof(projectilePool[i].id));
  724. projectilePool[i].WriteToSaveGame(savefile);
  725. }
  726. }
  727. }
  728. void SSDProjectile::ReadProjectiles(idFile* savefile, idGameSSDWindow* _game) {
  729. int count;
  730. savefile->Read(&count, sizeof(count));
  731. for(int i = 0; i < count; i++) {
  732. int id;
  733. savefile->Read(&id, sizeof(id));
  734. SSDProjectile* ent = GetSpecificProjectile(id);
  735. ent->ReadFromSaveGame(savefile, _game);
  736. }
  737. }
  738. /*
  739. *****************************************************************************
  740. * SSDPowerup
  741. ****************************************************************************
  742. */
  743. const char* powerupMaterials[][2] = {
  744. "game/SSD/powerupHealthClosed", "game/SSD/powerupHealthOpen",
  745. "game/SSD/powerupSuperBlasterClosed", "game/SSD/powerupSuperBlasterOpen",
  746. "game/SSD/powerupNukeClosed", "game/SSD/powerupNukeOpen",
  747. "game/SSD/powerupRescueClosed", "game/SSD/powerupRescueOpen",
  748. "game/SSD/powerupBonusPointsClosed", "game/SSD/powerupBonusPointsOpen",
  749. "game/SSD/powerupDamageClosed", "game/SSD/powerupDamageOpen",
  750. };
  751. #define POWERUP_MATERIAL_COUNT 6
  752. SSDPowerup SSDPowerup::powerupPool[MAX_POWERUPS];
  753. SSDPowerup::SSDPowerup() {
  754. }
  755. SSDPowerup::~SSDPowerup() {
  756. }
  757. void SSDPowerup::WriteToSaveGame( idFile *savefile ) {
  758. SSDMover::WriteToSaveGame(savefile);
  759. savefile->Write(&powerupState, sizeof(powerupState));
  760. savefile->Write(&powerupType, sizeof(powerupType));
  761. }
  762. void SSDPowerup::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) {
  763. SSDMover::ReadFromSaveGame(savefile, _game);
  764. savefile->Read(&powerupState, sizeof(powerupState));
  765. savefile->Read(&powerupType, sizeof(powerupType));
  766. }
  767. void SSDPowerup::OnHit(int key) {
  768. if(powerupState == POWERUP_STATE_CLOSED) {
  769. //Small explosion to indicate it is opened
  770. SSDExplosion* explosion = SSDExplosion::GetNewExplosion(game, position, size*2.0f, 300, SSDExplosion::EXPLOSION_NORMAL, this, false, true);
  771. game->entities.Append(explosion);
  772. powerupState = POWERUP_STATE_OPEN;
  773. SetMaterial(powerupMaterials[powerupType][powerupState]);
  774. } else {
  775. //Destory the powerup with a big explosion
  776. SSDExplosion* explosion = SSDExplosion::GetNewExplosion(game, position, size*2, 300, SSDExplosion::EXPLOSION_NORMAL, this);
  777. game->entities.Append(explosion);
  778. game->PlaySound("arcade_explode");
  779. noHit = true;
  780. noPlayerDamage = true;
  781. }
  782. }
  783. void SSDPowerup::OnStrikePlayer() {
  784. if(powerupState == POWERUP_STATE_OPEN) {
  785. //The powerup was open so activate it
  786. OnActivatePowerup();
  787. }
  788. //Just destroy the powerup
  789. destroyed = true;
  790. }
  791. void SSDPowerup::OnOpenPowerup() {
  792. }
  793. void SSDPowerup::OnActivatePowerup() {
  794. switch(powerupType) {
  795. case POWERUP_TYPE_HEALTH:
  796. {
  797. game->AddHealth(10);
  798. break;
  799. }
  800. case POWERUP_TYPE_SUPER_BLASTER:
  801. {
  802. game->OnSuperBlaster();
  803. break;
  804. }
  805. case POWERUP_TYPE_ASTEROID_NUKE:
  806. {
  807. game->OnNuke();
  808. break;
  809. }
  810. case POWERUP_TYPE_RESCUE_ALL:
  811. {
  812. game->OnRescueAll();
  813. break;
  814. }
  815. case POWERUP_TYPE_BONUS_POINTS:
  816. {
  817. int points = (game->random.RandomInt(5)+1) * 100;
  818. game->AddScore(this, points);
  819. break;
  820. }
  821. case POWERUP_TYPE_DAMAGE:
  822. {
  823. game->AddDamage(10);
  824. game->PlaySound("arcade_explode");
  825. break;
  826. }
  827. }
  828. }
  829. void SSDPowerup::Init(idGameSSDWindow* _game, float _speed, float _rotation) {
  830. EntityInit();
  831. MoverInit(idVec3(0,0, -_speed), _rotation);
  832. SetGame(_game);
  833. SetSize(idVec2(200,200));
  834. SetRadius(Max(size.x, size.y), 0.3f);
  835. type = SSD_ENTITY_POWERUP;
  836. idVec3 startPosition;
  837. startPosition.x = game->random.RandomInt(V_WIDTH)-(V_WIDTH/2.0f);
  838. startPosition.y = game->random.RandomInt(V_HEIGHT)-(V_HEIGHT/2.0f);
  839. startPosition.z = ENTITY_START_DIST;
  840. position = startPosition;
  841. //SetPosition(startPosition);
  842. powerupState = POWERUP_STATE_CLOSED;
  843. powerupType = game->random.RandomInt(POWERUP_TYPE_MAX+1);
  844. if(powerupType >= POWERUP_TYPE_MAX) {
  845. powerupType = 0;
  846. }
  847. /*OutputDebugString(va("Powerup: %d\n", powerupType));
  848. if(powerupType == 0) {
  849. int x = 0;
  850. }*/
  851. SetMaterial(powerupMaterials[powerupType][powerupState]);
  852. }
  853. SSDPowerup* SSDPowerup::GetNewPowerup(idGameSSDWindow* _game, float _speed, float _rotation) {
  854. for(int i = 0; i < MAX_POWERUPS; i++) {
  855. if(!powerupPool[i].inUse) {
  856. powerupPool[i].Init(_game, _speed, _rotation);
  857. powerupPool[i].inUse = true;
  858. return &powerupPool[i];
  859. }
  860. }
  861. return NULL;
  862. }
  863. SSDPowerup* SSDPowerup::GetSpecificPowerup(int id) {
  864. return &powerupPool[id];
  865. }
  866. void SSDPowerup::WritePowerups(idFile* savefile) {
  867. int count = 0;
  868. for(int i = 0; i < MAX_POWERUPS; i++) {
  869. if(powerupPool[i].inUse) {
  870. count++;
  871. }
  872. }
  873. savefile->Write(&count, sizeof(count));
  874. for(int i = 0; i < MAX_POWERUPS; i++) {
  875. if(powerupPool[i].inUse) {
  876. savefile->Write(&(powerupPool[i].id), sizeof(powerupPool[i].id));
  877. powerupPool[i].WriteToSaveGame(savefile);
  878. }
  879. }
  880. }
  881. void SSDPowerup::ReadPowerups(idFile* savefile, idGameSSDWindow* _game) {
  882. int count;
  883. savefile->Read(&count, sizeof(count));
  884. for(int i = 0; i < count; i++) {
  885. int id;
  886. savefile->Read(&id, sizeof(id));
  887. SSDPowerup* ent = GetSpecificPowerup(id);
  888. ent->ReadFromSaveGame(savefile, _game);
  889. }
  890. }
  891. /*
  892. *****************************************************************************
  893. * idGameSSDWindow
  894. ****************************************************************************
  895. */
  896. idRandom idGameSSDWindow::random;
  897. idGameSSDWindow::idGameSSDWindow(idDeviceContext *d, idUserInterfaceLocal *g) : idWindow(d, g) {
  898. dc = d;
  899. gui = g;
  900. CommonInit();
  901. }
  902. idGameSSDWindow::idGameSSDWindow(idUserInterfaceLocal *g) : idWindow(g) {
  903. gui = g;
  904. CommonInit();
  905. }
  906. idGameSSDWindow::~idGameSSDWindow() {
  907. ResetGameStats();
  908. }
  909. void idGameSSDWindow::WriteToSaveGame( idFile *savefile ) {
  910. idWindow::WriteToSaveGame(savefile);
  911. savefile->Write(&ssdTime, sizeof(ssdTime));
  912. beginLevel.WriteToSaveGame(savefile);
  913. resetGame.WriteToSaveGame(savefile);
  914. continueGame.WriteToSaveGame(savefile);
  915. refreshGuiData.WriteToSaveGame(savefile);
  916. crosshair.WriteToSaveGame(savefile);
  917. savefile->Write(&screenBounds, sizeof(screenBounds));
  918. savefile->Write(&levelCount, sizeof(levelCount));
  919. for(int i = 0; i < levelCount; i++) {
  920. savefile->Write(&(levelData[i]), sizeof(SSDLevelData_t));
  921. savefile->Write(&(asteroidData[i]), sizeof(SSDAsteroidData_t));
  922. savefile->Write(&(astronautData[i]), sizeof(SSDAstronautData_t));
  923. savefile->Write(&(powerupData[i]), sizeof(SSDPowerupData_t));
  924. }
  925. savefile->Write(&weaponCount, sizeof(weaponCount));
  926. for(int i = 0; i < weaponCount; i++) {
  927. savefile->Write(&(weaponData[i]), sizeof(SSDWeaponData_t));
  928. }
  929. savefile->Write(&superBlasterTimeout, sizeof(superBlasterTimeout));
  930. savefile->Write(&gameStats, sizeof(SSDGameStats_t));
  931. //Write All Static Entities
  932. SSDAsteroid::WriteAsteroids(savefile);
  933. SSDAstronaut::WriteAstronauts(savefile);
  934. SSDExplosion::WriteExplosions(savefile);
  935. SSDPoints::WritePoints(savefile);
  936. SSDProjectile::WriteProjectiles(savefile);
  937. SSDPowerup::WritePowerups(savefile);
  938. int entCount = entities.Num();
  939. savefile->Write(&entCount, sizeof(entCount));
  940. for(int i = 0; i < entCount; i++) {
  941. savefile->Write(&(entities[i]->type), sizeof(entities[i]->type));
  942. savefile->Write(&(entities[i]->id), sizeof(entities[i]->id));
  943. }
  944. }
  945. void idGameSSDWindow::ReadFromSaveGame( idFile *savefile ) {
  946. idWindow::ReadFromSaveGame(savefile);
  947. savefile->Read(&ssdTime, sizeof(ssdTime));
  948. beginLevel.ReadFromSaveGame(savefile);
  949. resetGame.ReadFromSaveGame(savefile);
  950. continueGame.ReadFromSaveGame(savefile);
  951. refreshGuiData.ReadFromSaveGame(savefile);
  952. crosshair.ReadFromSaveGame(savefile);
  953. savefile->Read(&screenBounds, sizeof(screenBounds));
  954. savefile->Read(&levelCount, sizeof(levelCount));
  955. for(int i = 0; i < levelCount; i++) {
  956. SSDLevelData_t newLevel;
  957. savefile->Read(&newLevel, sizeof(SSDLevelData_t));
  958. levelData.Append(newLevel);
  959. SSDAsteroidData_t newAsteroid;
  960. savefile->Read(&newAsteroid, sizeof(SSDAsteroidData_t));
  961. asteroidData.Append(newAsteroid);
  962. SSDAstronautData_t newAstronaut;
  963. savefile->Read(&newAstronaut, sizeof(SSDAstronautData_t));
  964. astronautData.Append(newAstronaut);
  965. SSDPowerupData_t newPowerup;
  966. savefile->Read(&newPowerup, sizeof(SSDPowerupData_t));
  967. powerupData.Append(newPowerup);
  968. }
  969. savefile->Read(&weaponCount, sizeof(weaponCount));
  970. for(int i = 0; i < weaponCount; i++) {
  971. SSDWeaponData_t newWeapon;
  972. savefile->Read(&newWeapon, sizeof(SSDWeaponData_t));
  973. weaponData.Append(newWeapon);
  974. }
  975. savefile->Read(&superBlasterTimeout, sizeof(superBlasterTimeout));
  976. savefile->Read(&gameStats, sizeof(SSDGameStats_t));
  977. //Reset this because it is no longer valid
  978. gameStats.levelStats.targetEnt = NULL;
  979. SSDAsteroid::ReadAsteroids(savefile, this);
  980. SSDAstronaut::ReadAstronauts(savefile, this);
  981. SSDExplosion::ReadExplosions(savefile, this);
  982. SSDPoints::ReadPoints(savefile, this);
  983. SSDProjectile::ReadProjectiles(savefile, this);
  984. SSDPowerup::ReadPowerups(savefile, this);
  985. int entCount;
  986. savefile->Read(&entCount, sizeof(entCount));
  987. for(int i = 0; i < entCount; i++) {
  988. int type, id;
  989. savefile->Read(&type, sizeof(type));
  990. savefile->Read(&id, sizeof(id));
  991. SSDEntity* ent = GetSpecificEntity(type, id);
  992. if(ent) {
  993. entities.Append(ent);
  994. }
  995. }
  996. }
  997. const char *idGameSSDWindow::HandleEvent(const sysEvent_t *event, bool *updateVisuals) {
  998. // need to call this to allow proper focus and capturing on embedded children
  999. const char *ret = idWindow::HandleEvent(event, updateVisuals);
  1000. if(!gameStats.gameRunning) {
  1001. return ret;
  1002. }
  1003. int key = event->evValue;
  1004. if ( event->evType == SE_KEY ) {
  1005. if ( !event->evValue2 ) {
  1006. return ret;
  1007. }
  1008. if ( key == K_MOUSE1 || key == K_MOUSE2) {
  1009. FireWeapon(key);
  1010. } else {
  1011. return ret;
  1012. }
  1013. }
  1014. return ret;
  1015. }
  1016. idWinVar *idGameSSDWindow::GetWinVarByName (const char *_name, bool winLookup, drawWin_t** owner) {
  1017. idWinVar *retVar = NULL;
  1018. if (idStr::Icmp(_name, "beginLevel") == 0) {
  1019. retVar = &beginLevel;
  1020. }
  1021. if (idStr::Icmp(_name, "resetGame") == 0) {
  1022. retVar = &resetGame;
  1023. }
  1024. if (idStr::Icmp(_name, "continueGame") == 0) {
  1025. retVar = &continueGame;
  1026. }
  1027. if (idStr::Icmp(_name, "refreshGuiData") == 0) {
  1028. retVar = &refreshGuiData;
  1029. }
  1030. if(retVar) {
  1031. return retVar;
  1032. }
  1033. return idWindow::GetWinVarByName(_name, winLookup, owner);
  1034. }
  1035. void idGameSSDWindow::Draw(int time, float x, float y) {
  1036. //Update the game every frame before drawing
  1037. UpdateGame();
  1038. RefreshGuiData();
  1039. if(gameStats.gameRunning) {
  1040. ZOrderEntities();
  1041. //Draw from back to front
  1042. for(int i = entities.Num()-1; i >= 0; i--) {
  1043. entities[i]->Draw(dc);
  1044. }
  1045. //The last thing to draw is the crosshair
  1046. idVec2 cursor;
  1047. //GetCursor(cursor);
  1048. cursor.x = gui->CursorX();
  1049. cursor.y = gui->CursorY();
  1050. crosshair.Draw(dc, cursor);
  1051. }
  1052. }
  1053. bool idGameSSDWindow::ParseInternalVar(const char *_name, idParser *src) {
  1054. if (idStr::Icmp(_name, "beginLevel") == 0) {
  1055. beginLevel = src->ParseBool();
  1056. return true;
  1057. }
  1058. if (idStr::Icmp(_name, "resetGame") == 0) {
  1059. resetGame = src->ParseBool();
  1060. return true;
  1061. }
  1062. if (idStr::Icmp(_name, "continueGame") == 0) {
  1063. continueGame = src->ParseBool();
  1064. return true;
  1065. }
  1066. if (idStr::Icmp(_name, "refreshGuiData") == 0) {
  1067. refreshGuiData = src->ParseBool();
  1068. return true;
  1069. }
  1070. if(idStr::Icmp(_name, "levelcount") == 0) {
  1071. levelCount = src->ParseInt();
  1072. for(int i = 0; i < levelCount; i++) {
  1073. SSDLevelData_t newLevel;
  1074. memset(&newLevel, 0, sizeof(SSDLevelData_t));
  1075. levelData.Append(newLevel);
  1076. SSDAsteroidData_t newAsteroid;
  1077. memset(&newAsteroid, 0, sizeof(SSDAsteroidData_t));
  1078. asteroidData.Append(newAsteroid);
  1079. SSDAstronautData_t newAstronaut;
  1080. memset(&newAstronaut, 0, sizeof(SSDAstronautData_t));
  1081. astronautData.Append(newAstronaut);
  1082. SSDPowerupData_t newPowerup;
  1083. memset(&newPowerup, 0, sizeof(SSDPowerupData_t));
  1084. powerupData.Append(newPowerup);
  1085. }
  1086. return true;
  1087. }
  1088. if(idStr::Icmp(_name, "weaponCount") == 0) {
  1089. weaponCount = src->ParseInt();
  1090. for(int i = 0; i < weaponCount; i++) {
  1091. SSDWeaponData_t newWeapon;
  1092. memset(&newWeapon, 0, sizeof(SSDWeaponData_t));
  1093. weaponData.Append(newWeapon);
  1094. }
  1095. return true;
  1096. }
  1097. if(idStr::FindText(_name, "leveldata", false) >= 0) {
  1098. idStr tempName = _name;
  1099. int level = atoi(tempName.Right(2))-1;
  1100. idStr levelData;
  1101. ParseString(src, levelData);
  1102. ParseLevelData(level, levelData);
  1103. return true;
  1104. }
  1105. if(idStr::FindText(_name, "asteroiddata", false) >= 0) {
  1106. idStr tempName = _name;
  1107. int level = atoi(tempName.Right(2))-1;
  1108. idStr asteroidData;
  1109. ParseString(src, asteroidData);
  1110. ParseAsteroidData(level, asteroidData);
  1111. return true;
  1112. }
  1113. if(idStr::FindText(_name, "weapondata", false) >= 0) {
  1114. idStr tempName = _name;
  1115. int weapon = atoi(tempName.Right(2))-1;
  1116. idStr weaponData;
  1117. ParseString(src, weaponData);
  1118. ParseWeaponData(weapon, weaponData);
  1119. return true;
  1120. }
  1121. if(idStr::FindText(_name, "astronautdata", false) >= 0) {
  1122. idStr tempName = _name;
  1123. int level = atoi(tempName.Right(2))-1;
  1124. idStr astronautData;
  1125. ParseString(src, astronautData);
  1126. ParseAstronautData(level, astronautData);
  1127. return true;
  1128. }
  1129. if(idStr::FindText(_name, "powerupdata", false) >= 0) {
  1130. idStr tempName = _name;
  1131. int level = atoi(tempName.Right(2))-1;
  1132. idStr powerupData;
  1133. ParseString(src, powerupData);
  1134. ParsePowerupData(level, powerupData);
  1135. return true;
  1136. }
  1137. return idWindow::ParseInternalVar(_name, src);
  1138. }
  1139. void idGameSSDWindow::ParseLevelData(int level, const idStr& levelDataString) {
  1140. idParser parser;
  1141. idToken token;
  1142. parser.LoadMemory(levelDataString.c_str(), levelDataString.Length(), "LevelData");
  1143. levelData[level].spawnBuffer = parser.ParseFloat();
  1144. levelData[level].needToWin = parser.ParseInt(); //Required Destroyed
  1145. }
  1146. void idGameSSDWindow::ParseAsteroidData(int level, const idStr& asteroidDataString) {
  1147. idParser parser;
  1148. idToken token;
  1149. parser.LoadMemory(asteroidDataString.c_str(), asteroidDataString.Length(), "AsteroidData");
  1150. asteroidData[level].speedMin = parser.ParseFloat(); //Speed Min
  1151. asteroidData[level].speedMax = parser.ParseFloat(); //Speed Max
  1152. asteroidData[level].sizeMin = parser.ParseFloat(); //Size Min
  1153. asteroidData[level].sizeMax = parser.ParseFloat(); //Size Max
  1154. asteroidData[level].rotateMin = parser.ParseFloat(); //Rotate Min (rotations per second)
  1155. asteroidData[level].rotateMax = parser.ParseFloat(); //Rotate Max (rotations per second)
  1156. asteroidData[level].spawnMin = parser.ParseInt(); //Spawn Min
  1157. asteroidData[level].spawnMax = parser.ParseInt(); //Spawn Max
  1158. asteroidData[level].asteroidHealth = parser.ParseInt(); //Health of the asteroid
  1159. asteroidData[level].asteroidDamage = parser.ParseInt(); //Asteroid Damage
  1160. asteroidData[level].asteroidPoints = parser.ParseInt(); //Points awarded for destruction
  1161. }
  1162. void idGameSSDWindow::ParsePowerupData(int level, const idStr& powerupDataString) {
  1163. idParser parser;
  1164. idToken token;
  1165. parser.LoadMemory(powerupDataString.c_str(), powerupDataString.Length(), "PowerupData");
  1166. powerupData[level].speedMin = parser.ParseFloat(); //Speed Min
  1167. powerupData[level].speedMax = parser.ParseFloat(); //Speed Max
  1168. powerupData[level].rotateMin = parser.ParseFloat(); //Rotate Min (rotations per second)
  1169. powerupData[level].rotateMax = parser.ParseFloat(); //Rotate Max (rotations per second)
  1170. powerupData[level].spawnMin = parser.ParseInt(); //Spawn Min
  1171. powerupData[level].spawnMax = parser.ParseInt(); //Spawn Max
  1172. }
  1173. void idGameSSDWindow::ParseWeaponData(int weapon, const idStr& weaponDataString) {
  1174. idParser parser;
  1175. idToken token;
  1176. parser.LoadMemory(weaponDataString.c_str(), weaponDataString.Length(), "WeaponData");
  1177. weaponData[weapon].speed = parser.ParseFloat();
  1178. weaponData[weapon].damage = parser.ParseFloat();
  1179. weaponData[weapon].size = parser.ParseFloat();
  1180. }
  1181. void idGameSSDWindow::ParseAstronautData(int level, const idStr& astronautDataString) {
  1182. idParser parser;
  1183. idToken token;
  1184. parser.LoadMemory(astronautDataString.c_str(), astronautDataString.Length(), "AstronautData");
  1185. astronautData[level].speedMin = parser.ParseFloat(); //Speed Min
  1186. astronautData[level].speedMax = parser.ParseFloat(); //Speed Max
  1187. astronautData[level].rotateMin = parser.ParseFloat(); //Rotate Min (rotations per second)
  1188. astronautData[level].rotateMax = parser.ParseFloat(); //Rotate Max (rotations per second)
  1189. astronautData[level].spawnMin = parser.ParseInt(); //Spawn Min
  1190. astronautData[level].spawnMax = parser.ParseInt(); //Spawn Max
  1191. astronautData[level].health = parser.ParseInt(); //Health of the asteroid
  1192. astronautData[level].points = parser.ParseInt(); //Asteroid Damage
  1193. astronautData[level].penalty = parser.ParseInt(); //Points awarded for destruction
  1194. }
  1195. void idGameSSDWindow::CommonInit() {
  1196. crosshair.InitCrosshairs();
  1197. beginLevel = false;
  1198. resetGame = false;
  1199. continueGame = false;
  1200. refreshGuiData = false;
  1201. ssdTime = 0;
  1202. levelCount = 0;
  1203. weaponCount = 0;
  1204. screenBounds = idBounds(idVec3(-320,-240,0), idVec3(320,240,0));
  1205. superBlasterTimeout = 0;
  1206. currentSound = 0;
  1207. //Precahce all assets that are loaded dynamically
  1208. declManager->FindMaterial(ASTEROID_MATERIAL);
  1209. declManager->FindMaterial(ASTRONAUT_MATERIAL);
  1210. for(int i = 0; i < EXPLOSION_MATERIAL_COUNT; i++) {
  1211. declManager->FindMaterial(explosionMaterials[i]);
  1212. }
  1213. declManager->FindMaterial(PROJECTILE_MATERIAL);
  1214. for(int i = 0; i < POWERUP_MATERIAL_COUNT; i++) {
  1215. declManager->FindMaterial(powerupMaterials[i][0]);
  1216. declManager->FindMaterial(powerupMaterials[i][1]);
  1217. }
  1218. // Precache sounds
  1219. declManager->FindSound( "arcade_blaster" );
  1220. declManager->FindSound( "arcade_capture " );
  1221. declManager->FindSound( "arcade_explode" );
  1222. ResetGameStats();
  1223. }
  1224. void idGameSSDWindow::ResetGameStats() {
  1225. ResetEntities();
  1226. //Reset the gamestats structure
  1227. memset(&gameStats, 0, sizeof(gameStats));
  1228. gameStats.health = 100;
  1229. }
  1230. void idGameSSDWindow::ResetLevelStats() {
  1231. ResetEntities();
  1232. //Reset the level statistics structure
  1233. memset(&gameStats.levelStats, 0, sizeof(gameStats.levelStats));
  1234. }
  1235. void idGameSSDWindow::ResetEntities() {
  1236. //Destroy all of the entities
  1237. for(int i = 0; i < entities.Num(); i++) {
  1238. entities[i]->DestroyEntity();
  1239. }
  1240. entities.Clear();
  1241. }
  1242. void idGameSSDWindow::StartGame() {
  1243. gameStats.gameRunning = true;
  1244. }
  1245. void idGameSSDWindow::StopGame() {
  1246. gameStats.gameRunning = false;
  1247. }
  1248. void idGameSSDWindow::GameOver() {
  1249. StopGame();
  1250. gui->HandleNamedEvent("gameOver");
  1251. }
  1252. void idGameSSDWindow::BeginLevel(int level) {
  1253. ResetLevelStats();
  1254. gameStats.currentLevel = level;
  1255. StartGame();
  1256. }
  1257. /**
  1258. * Continue game resets the players health
  1259. */
  1260. void idGameSSDWindow::ContinueGame() {
  1261. gameStats.health = 100;
  1262. StartGame();
  1263. }
  1264. void idGameSSDWindow::LevelComplete() {
  1265. gameStats.prebonusscore = gameStats.score;
  1266. // Add the bonuses
  1267. int accuracy;
  1268. if( !gameStats.levelStats.shotCount ) {
  1269. accuracy = 0;
  1270. } else {
  1271. accuracy = (int)( ( (float)gameStats.levelStats.hitCount / (float)gameStats.levelStats.shotCount ) * 100.0f );
  1272. }
  1273. int accuracyPoints = Max( 0, accuracy - 50 ) * 20;
  1274. gui->SetStateString("player_accuracy_score", va("%i", accuracyPoints));
  1275. gameStats.score += accuracyPoints;
  1276. int saveAccuracy;
  1277. int totalAst = gameStats.levelStats.savedAstronauts + gameStats.levelStats.killedAstronauts;
  1278. if( !totalAst ) {
  1279. saveAccuracy = 0;
  1280. } else {
  1281. saveAccuracy = (int)( ( (float)gameStats.levelStats.savedAstronauts / (float)totalAst ) * 100.0f );
  1282. }
  1283. accuracyPoints = Max( 0, saveAccuracy - 50 ) * 20;
  1284. gui->SetStateString("save_accuracy_score", va("%i", accuracyPoints));
  1285. gameStats.score += accuracyPoints;
  1286. StopSuperBlaster();
  1287. gameStats.nextLevel++;
  1288. if(gameStats.nextLevel >= levelCount) {
  1289. //Have they beaten the game
  1290. GameComplete();
  1291. } else {
  1292. //Make sure we don't go above the levelcount
  1293. //min(gameStats.nextLevel, levelCount-1);
  1294. StopGame();
  1295. gui->HandleNamedEvent("levelComplete");
  1296. }
  1297. }
  1298. void idGameSSDWindow::GameComplete() {
  1299. StopGame();
  1300. gui->HandleNamedEvent("gameComplete");
  1301. }
  1302. void idGameSSDWindow::UpdateGame() {
  1303. //Check to see if and functions where called by the gui
  1304. if(beginLevel == true) {
  1305. beginLevel = false;
  1306. BeginLevel(gameStats.nextLevel);
  1307. }
  1308. if(resetGame == true) {
  1309. resetGame = false;
  1310. ResetGameStats();
  1311. }
  1312. if(continueGame == true) {
  1313. continueGame = false;
  1314. ContinueGame();
  1315. }
  1316. if(refreshGuiData == true) {
  1317. refreshGuiData = false;
  1318. RefreshGuiData();
  1319. }
  1320. if(gameStats.gameRunning) {
  1321. //We assume an upate every 16 milliseconds
  1322. ssdTime += 16;
  1323. if(superBlasterTimeout && ssdTime > superBlasterTimeout) {
  1324. StopSuperBlaster();
  1325. }
  1326. //Find if we are targeting and enemy
  1327. idVec2 cursor;
  1328. //GetCursor(cursor);
  1329. cursor.x = gui->CursorX();
  1330. cursor.y = gui->CursorY();
  1331. gameStats.levelStats.targetEnt = EntityHitTest(cursor);
  1332. //Update from back to front
  1333. for(int i = entities.Num()-1; i >= 0; i--) {
  1334. entities[i]->Update();
  1335. }
  1336. CheckForHits();
  1337. //Delete entities that need to be deleted
  1338. for(int i = entities.Num()-1; i >= 0; i--) {
  1339. if(entities[i]->destroyed) {
  1340. SSDEntity* ent = entities[i];
  1341. ent->DestroyEntity();
  1342. entities.RemoveIndex(i);
  1343. }
  1344. }
  1345. //Check if we can spawn an asteroid
  1346. SpawnAsteroid();
  1347. //Check if we should spawn an astronaut
  1348. SpawnAstronaut();
  1349. //Check if we should spawn an asteroid
  1350. SpawnPowerup();
  1351. }
  1352. }
  1353. void idGameSSDWindow::CheckForHits() {
  1354. //See if the entity has gotten close enough
  1355. for(int i = 0; i < entities.Num(); i++) {
  1356. SSDEntity* ent = entities[i];
  1357. if(ent->position.z <= Z_NEAR) {
  1358. if(!ent->noPlayerDamage) {
  1359. //Is the object still in the screen
  1360. idVec3 entPos = ent->position;
  1361. entPos.z = 0;
  1362. idBounds entBounds(entPos);
  1363. entBounds.ExpandSelf(ent->hitRadius);
  1364. if(screenBounds.IntersectsBounds(entBounds)) {
  1365. ent->OnStrikePlayer();
  1366. //The entity hit the player figure out what is was and act appropriately
  1367. if(ent->type == SSD_ENTITY_ASTEROID) {
  1368. AsteroidStruckPlayer(static_cast<SSDAsteroid*>(ent));
  1369. } else if(ent->type == SSD_ENTITY_ASTRONAUT) {
  1370. AstronautStruckPlayer(static_cast<SSDAstronaut*>(ent));
  1371. }
  1372. } else {
  1373. //Tag for removal later in the frame
  1374. ent->destroyed = true;
  1375. }
  1376. }
  1377. }
  1378. }
  1379. }
  1380. void idGameSSDWindow::ZOrderEntities() {
  1381. //Z-Order the entities
  1382. //Using a simple sorting method
  1383. for (int i = entities.Num()-1; i >= 0; i--) {
  1384. bool flipped = false;
  1385. for (int j = 0; j<i ; j++) {
  1386. if (entities[j]->position.z > entities[j+1]->position.z) {
  1387. SSDEntity* ent = entities[j];
  1388. entities[j] = entities[j+1];
  1389. entities[j+1] = ent;
  1390. flipped = true;
  1391. }
  1392. }
  1393. if (!flipped) {
  1394. //Jump out because it is sorted
  1395. break;
  1396. }
  1397. }
  1398. }
  1399. void idGameSSDWindow::SpawnAsteroid() {
  1400. int currentTime = ssdTime;
  1401. if(currentTime < gameStats.levelStats.nextAsteroidSpawnTime) {
  1402. //Not time yet
  1403. return;
  1404. }
  1405. //Lets spawn it
  1406. idVec3 startPosition;
  1407. float spawnBuffer = levelData[gameStats.currentLevel].spawnBuffer*2.0f;
  1408. startPosition.x = random.RandomInt(V_WIDTH+spawnBuffer)-((V_WIDTH/2.0f)+spawnBuffer);
  1409. startPosition.y = random.RandomInt(V_HEIGHT+spawnBuffer)-((V_HEIGHT/2.0f)+spawnBuffer);
  1410. startPosition.z = ENTITY_START_DIST;
  1411. float speed = random.RandomInt(asteroidData[gameStats.currentLevel].speedMax - asteroidData[gameStats.currentLevel].speedMin) + asteroidData[gameStats.currentLevel].speedMin;
  1412. float size = random.RandomInt(asteroidData[gameStats.currentLevel].sizeMax - asteroidData[gameStats.currentLevel].sizeMin) + asteroidData[gameStats.currentLevel].sizeMin;
  1413. float rotate = (random.RandomFloat() * (asteroidData[gameStats.currentLevel].rotateMax - asteroidData[gameStats.currentLevel].rotateMin)) + asteroidData[gameStats.currentLevel].rotateMin;
  1414. SSDAsteroid* asteroid = SSDAsteroid::GetNewAsteroid(this, startPosition, idVec2(size, size), speed, rotate, asteroidData[gameStats.currentLevel].asteroidHealth);
  1415. entities.Append(asteroid);
  1416. gameStats.levelStats.nextAsteroidSpawnTime = currentTime + random.RandomInt(asteroidData[gameStats.currentLevel].spawnMax - asteroidData[gameStats.currentLevel].spawnMin) + asteroidData[gameStats.currentLevel].spawnMin;
  1417. }
  1418. void idGameSSDWindow::FireWeapon(int key) {
  1419. idVec2 cursorWorld = GetCursorWorld();
  1420. idVec2 cursor;
  1421. //GetCursor(cursor);
  1422. cursor.x = gui->CursorX();
  1423. cursor.y = gui->CursorY();
  1424. if(key == K_MOUSE1) {
  1425. gameStats.levelStats.shotCount++;
  1426. if(gameStats.levelStats.targetEnt) {
  1427. //Aim the projectile from the bottom of the screen directly at the ent
  1428. //SSDProjectile* newProj = new SSDProjectile(this, idVec3(320,0,0), gameStats.levelStats.targetEnt->position, weaponData[gameStats.currentWeapon].speed, weaponData[gameStats.currentWeapon].size);
  1429. SSDProjectile* newProj = SSDProjectile::GetNewProjectile(this, idVec3(0,-180,0), gameStats.levelStats.targetEnt->position, weaponData[gameStats.currentWeapon].speed, weaponData[gameStats.currentWeapon].size);
  1430. entities.Append(newProj);
  1431. //newProj = SSDProjectile::GetNewProjectile(this, idVec3(-320,-0,0), gameStats.levelStats.targetEnt->position, weaponData[gameStats.currentWeapon].speed, weaponData[gameStats.currentWeapon].size);
  1432. //entities.Append(newProj);
  1433. //We hit something
  1434. gameStats.levelStats.hitCount++;
  1435. gameStats.levelStats.targetEnt->OnHit(key);
  1436. if(gameStats.levelStats.targetEnt->type == SSD_ENTITY_ASTEROID) {
  1437. HitAsteroid(static_cast<SSDAsteroid*>(gameStats.levelStats.targetEnt), key);
  1438. } else if(gameStats.levelStats.targetEnt->type == SSD_ENTITY_ASTRONAUT) {
  1439. HitAstronaut(static_cast<SSDAstronaut*>(gameStats.levelStats.targetEnt), key);
  1440. } else if(gameStats.levelStats.targetEnt->type == SSD_ENTITY_ASTRONAUT) {
  1441. }
  1442. } else {
  1443. ////Aim the projectile at the cursor position all the way to the far clipping
  1444. //SSDProjectile* newProj = SSDProjectile::GetNewProjectile(this, idVec3(0,-180,0), idVec3(cursorWorld.x, cursorWorld.y, (Z_FAR-Z_NEAR)/2.0f), weaponData[gameStats.currentWeapon].speed, weaponData[gameStats.currentWeapon].size);
  1445. //Aim the projectile so it crosses the cursor 1/4 of screen
  1446. idVec3 vec = idVec3(cursorWorld.x, cursorWorld.y, (Z_FAR-Z_NEAR)/8.0f);
  1447. vec *= 8;
  1448. SSDProjectile* newProj = SSDProjectile::GetNewProjectile(this, idVec3(0,-180,0), vec, weaponData[gameStats.currentWeapon].speed, weaponData[gameStats.currentWeapon].size);
  1449. entities.Append(newProj);
  1450. }
  1451. //Play the blaster sound
  1452. PlaySound("arcade_blaster");
  1453. } /*else if (key == K_MOUSE2) {
  1454. if(gameStats.levelStats.targetEnt) {
  1455. if(gameStats.levelStats.targetEnt->type == SSD_ENTITY_ASTRONAUT) {
  1456. HitAstronaut(static_cast<SSDAstronaut*>(gameStats.levelStats.targetEnt), key);
  1457. }
  1458. }
  1459. }*/
  1460. }
  1461. SSDEntity* idGameSSDWindow::EntityHitTest(const idVec2& pt) {
  1462. for(int i = 0; i < entities.Num(); i++) {
  1463. //Since we ZOrder the entities every frame we can stop at the first entity we hit.
  1464. //ToDo: Make sure this assumption is true
  1465. if(entities[i]->HitTest(pt)) {
  1466. return entities[i];
  1467. }
  1468. }
  1469. return NULL;
  1470. }
  1471. void idGameSSDWindow::HitAsteroid(SSDAsteroid* asteroid, int key) {
  1472. asteroid->health -= weaponData[gameStats.currentWeapon].damage;
  1473. if(asteroid->health <= 0) {
  1474. //The asteroid has been destroyed
  1475. SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, asteroid->position, asteroid->size*2, 300, SSDExplosion::EXPLOSION_NORMAL, asteroid);
  1476. entities.Append(explosion);
  1477. PlaySound("arcade_explode");
  1478. AddScore(asteroid, asteroidData[gameStats.currentLevel].asteroidPoints);
  1479. //Don't let the player hit it anymore because
  1480. asteroid->noHit = true;
  1481. gameStats.levelStats.destroyedAsteroids++;
  1482. //if(gameStats.levelStats.destroyedAsteroids >= levelData[gameStats.currentLevel].needToWin) {
  1483. // LevelComplete();
  1484. //}
  1485. } else {
  1486. //This was a damage hit so create a real small quick explosion
  1487. SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, asteroid->position, asteroid->size/2.0f, 200, SSDExplosion::EXPLOSION_NORMAL, asteroid, false, false);
  1488. entities.Append(explosion);
  1489. }
  1490. }
  1491. void idGameSSDWindow::AsteroidStruckPlayer(SSDAsteroid* asteroid) {
  1492. asteroid->noPlayerDamage = true;
  1493. asteroid->noHit = true;
  1494. AddDamage(asteroidData[gameStats.currentLevel].asteroidDamage);
  1495. SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, asteroid->position, asteroid->size*2, 300, SSDExplosion::EXPLOSION_NORMAL, asteroid);
  1496. entities.Append(explosion);
  1497. PlaySound("arcade_explode");
  1498. }
  1499. void idGameSSDWindow::AddScore(SSDEntity* ent, int points) {
  1500. SSDPoints* pointsEnt;
  1501. if(points > 0) {
  1502. pointsEnt = SSDPoints::GetNewPoints(this, ent, points, 1000, 50, idVec4(0,1,0,1));
  1503. } else {
  1504. pointsEnt = SSDPoints::GetNewPoints(this, ent, points, 1000, 50, idVec4(1,0,0,1));
  1505. }
  1506. entities.Append(pointsEnt);
  1507. gameStats.score += points;
  1508. gui->SetStateString( "player_score", va("%i", gameStats.score ) );
  1509. }
  1510. void idGameSSDWindow::AddDamage(int damage) {
  1511. gameStats.health -= damage;
  1512. gui->SetStateString( "player_health", va("%i", gameStats.health ) );
  1513. gui->HandleNamedEvent( "playerDamage" );
  1514. if(gameStats.health <= 0) {
  1515. //The player is dead
  1516. GameOver();
  1517. }
  1518. }
  1519. void idGameSSDWindow::AddHealth(int health) {
  1520. gameStats.health += health;
  1521. gameStats.health = Min( 100, gameStats.health );
  1522. }
  1523. void idGameSSDWindow::OnNuke() {
  1524. gui->HandleNamedEvent("nuke");
  1525. //Destory All Asteroids
  1526. for(int i = 0 ; i < entities.Num(); i++) {
  1527. if(entities[i]->type == SSD_ENTITY_ASTEROID) {
  1528. //The asteroid has been destroyed
  1529. SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, entities[i]->position, entities[i]->size*2, 300, SSDExplosion::EXPLOSION_NORMAL, entities[i]);
  1530. entities.Append(explosion);
  1531. AddScore(entities[i], asteroidData[gameStats.currentLevel].asteroidPoints);
  1532. //Don't let the player hit it anymore because
  1533. entities[i]->noHit = true;
  1534. gameStats.levelStats.destroyedAsteroids++;
  1535. }
  1536. }
  1537. PlaySound("arcade_explode");
  1538. //Check to see if a nuke ends the level
  1539. /*if(gameStats.levelStats.destroyedAsteroids >= levelData[gameStats.currentLevel].needToWin) {
  1540. LevelComplete();
  1541. }*/
  1542. }
  1543. void idGameSSDWindow::OnRescueAll() {
  1544. gui->HandleNamedEvent("rescueAll");
  1545. //Rescue All Astronauts
  1546. for(int i = 0 ; i < entities.Num(); i++) {
  1547. if(entities[i]->type == SSD_ENTITY_ASTRONAUT) {
  1548. AstronautStruckPlayer((SSDAstronaut*)entities[i]);
  1549. }
  1550. }
  1551. }
  1552. void idGameSSDWindow::OnSuperBlaster() {
  1553. StartSuperBlaster();
  1554. }
  1555. void idGameSSDWindow::RefreshGuiData() {
  1556. gui->SetStateString("nextLevel", va("%i", gameStats.nextLevel+1));
  1557. gui->SetStateString("currentLevel", va("%i", gameStats.currentLevel+1));
  1558. float accuracy;
  1559. if(!gameStats.levelStats.shotCount) {
  1560. accuracy = 0;
  1561. } else {
  1562. accuracy = ((float)gameStats.levelStats.hitCount/(float)gameStats.levelStats.shotCount)*100.0f;
  1563. }
  1564. gui->SetStateString( "player_accuracy", va("%d%%", (int)accuracy));
  1565. float saveAccuracy;
  1566. int totalAst = gameStats.levelStats.savedAstronauts + gameStats.levelStats.killedAstronauts;
  1567. if(!totalAst) {
  1568. saveAccuracy = 0;
  1569. } else {
  1570. saveAccuracy = ((float)gameStats.levelStats.savedAstronauts/(float)totalAst)*100.0f;
  1571. }
  1572. gui->SetStateString( "save_accuracy", va("%d%%", (int)saveAccuracy));
  1573. if(gameStats.levelStats.targetEnt) {
  1574. int dist = (gameStats.levelStats.targetEnt->position.z/100.0f);
  1575. dist *= 100;
  1576. gui->SetStateString("target_info", va("%i meters", dist));
  1577. } else {
  1578. gui->SetStateString("target_info", "No Target");
  1579. }
  1580. gui->SetStateString( "player_health", va("%i", gameStats.health ) );
  1581. gui->SetStateString( "player_score", va("%i", gameStats.score ) );
  1582. gui->SetStateString( "player_prebonusscore", va("%i", gameStats.prebonusscore ) );
  1583. gui->SetStateString( "level_complete", va("%i/%i", gameStats.levelStats.savedAstronauts, levelData[gameStats.currentLevel].needToWin ));
  1584. if(superBlasterTimeout) {
  1585. float timeRemaining = (superBlasterTimeout - ssdTime)/1000.0f;
  1586. gui->SetStateString("super_blaster_time", va("%.2f", timeRemaining));
  1587. }
  1588. }
  1589. idVec2 idGameSSDWindow::GetCursorWorld() {
  1590. idVec2 cursor;
  1591. //GetCursor(cursor);
  1592. cursor.x = gui->CursorX();
  1593. cursor.y = gui->CursorY();
  1594. cursor.x = cursor.x - 0.5f * V_WIDTH;
  1595. cursor.y = -(cursor.y - 0.5f * V_HEIGHT);
  1596. return cursor;
  1597. }
  1598. void idGameSSDWindow::SpawnAstronaut() {
  1599. int currentTime = ssdTime;
  1600. if(currentTime < gameStats.levelStats.nextAstronautSpawnTime) {
  1601. //Not time yet
  1602. return;
  1603. }
  1604. //Lets spawn it
  1605. idVec3 startPosition;
  1606. startPosition.x = random.RandomInt(V_WIDTH)-(V_WIDTH/2.0f);
  1607. startPosition.y = random.RandomInt(V_HEIGHT)-(V_HEIGHT/2.0f);
  1608. startPosition.z = ENTITY_START_DIST;
  1609. float speed = random.RandomInt(astronautData[gameStats.currentLevel].speedMax - astronautData[gameStats.currentLevel].speedMin) + astronautData[gameStats.currentLevel].speedMin;
  1610. float rotate = (random.RandomFloat() * (astronautData[gameStats.currentLevel].rotateMax - astronautData[gameStats.currentLevel].rotateMin)) + astronautData[gameStats.currentLevel].rotateMin;
  1611. SSDAstronaut* astronaut = SSDAstronaut::GetNewAstronaut(this, startPosition, speed, rotate, astronautData[gameStats.currentLevel].health);
  1612. entities.Append(astronaut);
  1613. gameStats.levelStats.nextAstronautSpawnTime = currentTime + random.RandomInt(astronautData[gameStats.currentLevel].spawnMax - astronautData[gameStats.currentLevel].spawnMin) + astronautData[gameStats.currentLevel].spawnMin;
  1614. }
  1615. void idGameSSDWindow::HitAstronaut(SSDAstronaut* astronaut, int key) {
  1616. if(key == K_MOUSE1) {
  1617. astronaut->health -= weaponData[gameStats.currentWeapon].damage;
  1618. if(astronaut->health <= 0) {
  1619. gameStats.levelStats.killedAstronauts++;
  1620. //The astronaut has been destroyed
  1621. SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, astronaut->position, astronaut->size*2, 300, SSDExplosion::EXPLOSION_NORMAL, astronaut);
  1622. entities.Append(explosion);
  1623. PlaySound("arcade_explode");
  1624. //Add the penalty for killing the astronaut
  1625. AddScore(astronaut, astronautData[gameStats.currentLevel].penalty);
  1626. //Don't let the player hit it anymore
  1627. astronaut->noHit = true;
  1628. } else {
  1629. //This was a damage hit so create a real small quick explosion
  1630. SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, astronaut->position, astronaut->size/2.0f, 200, SSDExplosion::EXPLOSION_NORMAL, astronaut, false, false);
  1631. entities.Append(explosion);
  1632. }
  1633. }
  1634. }
  1635. void idGameSSDWindow::AstronautStruckPlayer(SSDAstronaut* astronaut) {
  1636. gameStats.levelStats.savedAstronauts++;
  1637. astronaut->noPlayerDamage = true;
  1638. astronaut->noHit = true;
  1639. //We are saving an astronaut
  1640. SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, astronaut->position, astronaut->size*2, 300, SSDExplosion::EXPLOSION_TELEPORT, astronaut);
  1641. entities.Append(explosion);
  1642. PlaySound("arcade_capture");
  1643. //Give the player points for saving the astronaut
  1644. AddScore(astronaut, astronautData[gameStats.currentLevel].points);
  1645. if(gameStats.levelStats.savedAstronauts >= levelData[gameStats.currentLevel].needToWin) {
  1646. LevelComplete();
  1647. }
  1648. }
  1649. void idGameSSDWindow::SpawnPowerup() {
  1650. int currentTime = ssdTime;
  1651. if(currentTime < gameStats.levelStats.nextPowerupSpawnTime) {
  1652. //Not time yet
  1653. return;
  1654. }
  1655. float speed = random.RandomInt(powerupData[gameStats.currentLevel].speedMax - powerupData[gameStats.currentLevel].speedMin) + powerupData[gameStats.currentLevel].speedMin;
  1656. float rotate = (random.RandomFloat() * (powerupData[gameStats.currentLevel].rotateMax - powerupData[gameStats.currentLevel].rotateMin)) + powerupData[gameStats.currentLevel].rotateMin;
  1657. SSDPowerup* powerup = SSDPowerup::GetNewPowerup(this, speed, rotate);
  1658. entities.Append(powerup);
  1659. gameStats.levelStats.nextPowerupSpawnTime = currentTime + random.RandomInt(powerupData[gameStats.currentLevel].spawnMax - powerupData[gameStats.currentLevel].spawnMin) + powerupData[gameStats.currentLevel].spawnMin;
  1660. }
  1661. void idGameSSDWindow::StartSuperBlaster() {
  1662. gui->HandleNamedEvent("startSuperBlaster");
  1663. gameStats.currentWeapon = 1;
  1664. superBlasterTimeout = ssdTime + 10000;
  1665. }
  1666. void idGameSSDWindow::StopSuperBlaster() {
  1667. gui->HandleNamedEvent("stopSuperBlaster");
  1668. gameStats.currentWeapon = 0;
  1669. superBlasterTimeout = 0;
  1670. }
  1671. SSDEntity* idGameSSDWindow::GetSpecificEntity(int type, int id) {
  1672. SSDEntity* ent = NULL;
  1673. switch(type) {
  1674. case SSD_ENTITY_ASTEROID:
  1675. ent = SSDAsteroid::GetSpecificAsteroid(id);
  1676. break;
  1677. case SSD_ENTITY_ASTRONAUT:
  1678. ent = SSDAstronaut::GetSpecificAstronaut(id);
  1679. break;
  1680. case SSD_ENTITY_EXPLOSION:
  1681. ent = SSDExplosion::GetSpecificExplosion(id);
  1682. break;
  1683. case SSD_ENTITY_POINTS:
  1684. ent = SSDPoints::GetSpecificPoints(id);
  1685. break;
  1686. case SSD_ENTITY_PROJECTILE:
  1687. ent = SSDProjectile::GetSpecificProjectile(id);
  1688. break;
  1689. case SSD_ENTITY_POWERUP:
  1690. ent = SSDPowerup::GetSpecificPowerup(id);
  1691. break;
  1692. }
  1693. return ent;
  1694. }
  1695. #define MAX_SOUND_CHANNEL 8
  1696. void idGameSSDWindow::PlaySound(const char* sound) {
  1697. session->sw->PlayShaderDirectly(sound, currentSound);
  1698. currentSound++;
  1699. if(currentSound >= MAX_SOUND_CHANNEL) {
  1700. currentSound = 0;
  1701. }
  1702. }