GameSSDWindow.cpp 60 KB

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