iphone_menus.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062
  1. /*
  2. Copyright (C) 2009 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. #include "../wolfiphone.h"
  16. int intermissionStartFrameNum;
  17. int hasReleased;
  18. menuState_t menuState;
  19. colour4_t highlightColor = { 128, 128, 128, 255 };
  20. colour4_t colorPressed = { 128, 128, 0, 255 };
  21. /*
  22. ==================
  23. iphoneDrawPic
  24. ==================
  25. */
  26. void iphoneDrawPic( int x, int y, int w, int h, const char *pic ) {
  27. R_Draw_StretchPic( x, y, w, h, pic );
  28. }
  29. /*
  30. ==================
  31. iphoneDrawPicWithTouch
  32. ==================
  33. */
  34. int iphoneDrawPicWithTouch( int x, int y, int w, int h, const char *pic ) {
  35. int r = TouchReleased( x, y, w, h );
  36. if ( r ) {
  37. // make sure it is full intensity if it is touch-released, even if
  38. // it wasn't active previously
  39. pfglColor3f( 1, 1, 1 );
  40. }
  41. R_Draw_StretchPic( x, y, w, h, pic );
  42. if ( TouchDown( x, y, w, h ) ) {
  43. colour4_t color = { 255, 255, 255, 64 };
  44. R_Draw_Blend( x, y, w, h, color );
  45. }
  46. return r;
  47. }
  48. /*
  49. ==================
  50. iphoneSlider
  51. ==================
  52. */
  53. void iphoneSlider( int x, int y, int w, int h, const char *title, cvar_t *cvar,
  54. float min, float max ) {
  55. float value = cvar->value;
  56. char str[80];
  57. float f = ( value - min ) / ( max - min );
  58. colour4_t backColor = { 32, 32, 80, 255 };
  59. colour4_t highlightColor = { 64, 64, 160, 255 };
  60. if ( f < 0 ) {
  61. f = 0;
  62. }
  63. if ( f > 1 ) {
  64. f = 1;
  65. }
  66. // draw the background
  67. R_Draw_Fill( x, y, w, h, backColor );
  68. // draw the current range
  69. R_Draw_Fill( x+2, y+2, f*(w-4), h-4, highlightColor );
  70. // draw the title and fraction
  71. sprintf( str, "%s : %i%%", title, (int)(f*100) );
  72. iphoneCenterText( x+ w/2, y+h/2-8, str );
  73. // check for touches
  74. if ( numTouches > 0 && touches[0][0] >= x && touches[0][0] < x + w
  75. && touches[0][1] >= y && touches[0][1] < y+ h ) {
  76. float newValue;
  77. float delta;
  78. f = (float)( touches[0][0] - x ) / w;
  79. // round to tenths
  80. f = (int)( ( f + 0.05 ) * 10 ) * 0.1f;
  81. if ( f < 0 ) {
  82. f = 0;
  83. }
  84. if ( f > 1.0 ) {
  85. f = 1.0;
  86. }
  87. newValue = min + f * ( max - min );
  88. delta = fabs( newValue - cvar->value );
  89. if ( f == 0 && cvar->value == 0 ) {
  90. // special case of disable-at-0
  91. } else if ( delta > 0.01 ) {
  92. Cvar_SetValue( cvar->name, newValue );
  93. Sound_StartLocalSound( "iphone/slide_01.wav" );
  94. }
  95. }
  96. }
  97. /*
  98. ==================
  99. BackButton
  100. ==================
  101. */
  102. int BackButton() {
  103. if ( iphoneDrawPicWithTouch( 0, 0, 64, 32, "iphone/button_back.tga" ) ) {
  104. return 1;
  105. }
  106. return 0;
  107. }
  108. void GetMoreLevels( int x, int y ) {
  109. if ( iphoneDrawPicWithTouch( x, y, 128, 64, "iphone/button_levels.tga" ) ) {
  110. // directly to the app store for more levels
  111. OpenURL( "http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=304694876" );
  112. }
  113. }
  114. /*
  115. ==================
  116. SaveTheGame
  117. ==================
  118. */
  119. extern W8 areaconnect[ NUMAREAS ][ NUMAREAS ];
  120. extern _boolean areabyplayer[ NUMAREAS ];
  121. void SaveTheGame() {
  122. FILE *f;
  123. char path[1024];
  124. int version = SAVEGAME_VERSION;
  125. int i;
  126. my_snprintf( path, sizeof( path ), "%s/savegame.bin", iphoneDocDirectory );
  127. f = fopen( path, "wb" );
  128. if( ! f ) {
  129. Com_Printf( "Could not open savegame.bin.\n" );
  130. return;
  131. }
  132. // turn the r_world->Doors.doors from pointers to indexes
  133. // ok to be destructive, because we are quiting
  134. for ( i = 0 ; i < r_world->Doors.doornum ; i++ ) {
  135. int index = r_world->Doors.Doors[i] - &r_world->Doors.DoorMap[0][0];
  136. assert( index >= 0 && index < 4096 );
  137. r_world->Doors.Doors[i] = (void *)index;
  138. }
  139. // this is only used for the mutant death face, so just
  140. // clear it instead of fixing it up
  141. Player.LastAttacker = NULL;
  142. currentMap.version = SAVEGAME_VERSION;
  143. fwrite( &currentMap, 1,sizeof(currentMap), f );
  144. fwrite( r_world, 1,sizeof(*r_world), f );
  145. fwrite( &LevelRatios, 1,sizeof(LevelRatios), f );
  146. fwrite( &levelstate, 1,sizeof(levelstate), f );
  147. fwrite( Guards, 1,sizeof(Guards), f );
  148. fwrite( areaconnect, 1,sizeof(areaconnect), f );
  149. fwrite( areabyplayer, 1,sizeof(areabyplayer), f );
  150. fwrite( &PWall, 1,sizeof(PWall), f );
  151. fwrite( &Player, 1,sizeof(Player), f );
  152. fwrite( &version, 1,sizeof(version), f );
  153. fclose( f );
  154. }
  155. /*
  156. ==================
  157. LoadTheGame
  158. ==================
  159. */
  160. int LoadTheGame() {
  161. FILE *f;
  162. char path[1024];
  163. int version;
  164. int i;
  165. int oldCompleted;
  166. my_snprintf( path, sizeof( path ), "%s/savegame.bin", iphoneDocDirectory );
  167. f = fopen( path, "rb" );
  168. if( ! f ) {
  169. Com_Printf( "Could not open savegame.bin.\n" );
  170. return 0;
  171. }
  172. fread( &currentMap, 1,sizeof(currentMap) , f);
  173. if ( currentMap.version != SAVEGAME_VERSION ) {
  174. Com_Printf( "Savegame header version mismatch: %i != %i\n", currentMap.version, SAVEGAME_VERSION );
  175. fclose( f );
  176. return 0;
  177. }
  178. // do a normal map start
  179. Cvar_SetValue( skill->name, currentMap.skill );
  180. PL_NewGame( &Player );
  181. oldCompleted = currentMap.levelCompleted;
  182. iphoneStartMap( currentMap.episode, currentMap.map, currentMap.skill );
  183. currentMap.levelCompleted = oldCompleted;
  184. // load modifiactions on top
  185. r_world = Z_Malloc( sizeof( *r_world ) );
  186. fread( r_world, 1,sizeof(*r_world), f);
  187. fread( &LevelRatios, 1,sizeof(LRstruct), f );
  188. fread( &levelstate, 1,sizeof(levelstate), f );
  189. fread( Guards, 1,sizeof(Guards), f );
  190. fread( areaconnect, 1,sizeof(areaconnect), f );
  191. fread( areabyplayer, 1,sizeof(areabyplayer), f );
  192. fread( &PWall, 1,sizeof(PWall), f );
  193. fread( &Player, 1,sizeof(Player), f );
  194. fread( &version, 1,sizeof(version), f );
  195. fclose( f );
  196. if ( version != SAVEGAME_VERSION ) {
  197. Com_Printf( "Savegame trailer version mismatch: %i != %i\n", version, SAVEGAME_VERSION );
  198. return 0;
  199. }
  200. // turn the r_world->Doors.doors back to pointers
  201. for ( i = 0 ; i < r_world->Doors.doornum ; i++ ) {
  202. int index = (int)r_world->Doors.Doors[i];
  203. assert( index >= 0 && index < 4096 );
  204. r_world->Doors.Doors[i] = &r_world->Doors.DoorMap[0][0] + index;
  205. }
  206. return 1;
  207. }
  208. /*
  209. ==================
  210. iphoneStartMap
  211. This does not reset the player, so call PL_NewGame( &Player ) if it is a new start.
  212. ==================
  213. */
  214. void iphoneStartMap( int episodeNum, int mapNum, int skillLevel ) {
  215. char command[128];
  216. int levelNum = episodeNum*10+mapNum;
  217. Com_Printf( "iphoneStartMap( %i, %i, %i )\n", episodeNum, mapNum, skillLevel );
  218. // get the sound playing
  219. Sound_Update( vnull, vnull, vnull, vnull );
  220. // clean up game feedback
  221. damageflash = 0;
  222. bonusFrameNum = 0;
  223. attackDirTime[0] = 0;
  224. attackDirTime[1] = 0;
  225. // note that this has been tried now
  226. currentMap.mapFlags[currentMap.skill][levelNum] |= MF_TRIED;
  227. // start the game
  228. currentMap.episode = episodeNum;
  229. currentMap.map = mapNum;
  230. currentMap.skill = skillLevel;
  231. currentMap.levelCompleted = 0;
  232. Cvar_SetValue( skill->name, skillLevel );
  233. Cvar_SetValue( episode->name, episodeNum );
  234. sprintf( command, "w%i%i", currentMap.episode, currentMap.map );
  235. Client_PrepRefresh( command );
  236. menuState = IPM_GAME;
  237. }
  238. /*
  239. ==================
  240. iphoneMainMenu
  241. ==================
  242. */
  243. void iphoneMainMenu() {
  244. char str[80];
  245. float scale = 40 / 32.0;
  246. iphoneDrawPic( 480-256, 0, 256, 128, "iphone/wolf_logo.tga" );
  247. #ifdef EPISODE1
  248. iphoneDrawPic( -20, 0, 256, 64, "iphone/ep_1.tga" );
  249. GetMoreLevels( 0, 96 );
  250. #else
  251. iphoneDrawPic( -20, 0, 256, 64, "iphone/ep_1_6.tga" );
  252. #endif
  253. iphoneDrawPic( 0, 320 - 128, 128, 128, "iphone/id_logo.tga" );
  254. if ( iphoneDrawPicWithTouch( 300 - 64*scale, 80, 128*scale, 64*scale, "iphone/button_resume.tga" ) ) {
  255. // if the game was saved at the intermission screen, immediately
  256. // bring it back up when it is loaded
  257. if ( currentMap.levelCompleted ) {
  258. iphoneStartIntermission( 0 );
  259. } else {
  260. menuState = IPM_GAME;
  261. }
  262. }
  263. sprintf( str, "E%iM%i", currentMap.episode+1, currentMap.map+1 );
  264. iphoneCenterText( 300, 80+34*scale, str );
  265. if ( iphoneDrawPicWithTouch( 300 - 64*scale, 170, 128*scale, 32*scale, "iphone/button_control.tga" ) ) {
  266. menuState = IPM_CONTROLS;
  267. }
  268. if ( iphoneDrawPicWithTouch( 300 - 64*scale, 220, 128*scale, 32*scale, "iphone/button_new.tga" ) ) {
  269. menuState = IPM_SKILL;
  270. }
  271. if ( iphoneDrawPicWithTouch( 300 - 64*scale, 270, 128*scale, 32*scale, "iphone/button_web.tga" ) ) {
  272. OpenURL( "http://www.idsoftware.com/wolfenstein3dclassic/" );
  273. }
  274. }
  275. /*
  276. ==================
  277. iphoneControlMenu
  278. ==================
  279. */
  280. void iphoneControlMenu() {
  281. int i;
  282. if ( BackButton() ) {
  283. menuState = IPM_MAIN;
  284. }
  285. for ( i = 0 ; i < 4 ; i++ ) {
  286. char str[128];
  287. int remap[4] = { 3,4,1,2}; // artist named them differently than intended...
  288. sprintf( str, "iphone/layout_%i.tga", remap[i] );
  289. if ( i != controlScheme->value ) {
  290. pfglColor3f( 0.5, 0.5, 0.5 );
  291. }
  292. if ( iphoneDrawPicWithTouch( 120 * i, 40, 120, 120, str ) ) {
  293. Cvar_SetValue( controlScheme->name, i );
  294. }
  295. pfglColor3f( 1, 1, 1 );
  296. }
  297. iphoneSlider( 20, 170, 440, 40, "sensitivity", sensitivity, 0, 1 );
  298. iphoneSlider( 20, 220, 440, 40, "tilt move speed", tiltMove, 5000, 30000 );
  299. if ( tiltMove->value == 5000 ) {
  300. Cvar_SetValue( tiltMove->name, 0 );
  301. }
  302. if ( tiltMove->value ) {
  303. Cvar_SetValue( tiltTurn->name, 0 );
  304. }
  305. iphoneSlider( 20, 270, 440, 40, "tilt turn speed", tiltTurn, 500, 3000 );
  306. if ( tiltTurn->value == 500 ) {
  307. Cvar_SetValue( tiltTurn->name, 0 );
  308. }
  309. if ( tiltTurn->value ) {
  310. Cvar_SetValue( tiltMove->name, 0 );
  311. }
  312. //iphoneSlider( 20, 280, 440, 40, "tilt fire", tiltFire, 0, 1 );
  313. }
  314. /*
  315. ==================
  316. iphoneSkillMenu
  317. ==================
  318. */
  319. void iphoneSkillMenu() {
  320. int s;
  321. char str[64];
  322. if ( BackButton() ) {
  323. menuState = IPM_MAIN;
  324. }
  325. // highlight the current skill selection
  326. s = (int)skill->value;
  327. // R_Draw_Fill( 80, 40+64*s, 320, 64, highlightColor );
  328. for ( s = 0 ; s < 4 ; s++ ) {
  329. my_snprintf( str, sizeof( str ), "iphone/button_skill%i.tga", s+1 );
  330. if ( s != (int)skill->value ) {
  331. pfglColor3f( 0.5, 0.5, 0.5 );
  332. }
  333. if ( iphoneDrawPicWithTouch( 112, 40+64*s, 256, 64, str ) ) {
  334. Cvar_SetValue( skill->name, s );
  335. menuState = IPM_EPISODE;
  336. }
  337. pfglColor3f( 1, 1, 1 );
  338. }
  339. }
  340. /*
  341. ==================
  342. iphoneEpisodeMenu
  343. ==================
  344. */
  345. void iphoneEpisodeMenu() {
  346. int e;
  347. char str[64];
  348. #ifdef EPISODE1
  349. int numE = 1;
  350. #else
  351. int numE = 6;
  352. #endif
  353. if ( BackButton() ) {
  354. menuState = IPM_SKILL;
  355. }
  356. // 96 x 48 images
  357. for ( e = 0 ; e < numE ; e++ ) {
  358. my_snprintf( str, sizeof( str ), "iphone/button_ep%i.tga", e+1 );
  359. if ( e != (int)episode->value ) {
  360. pfglColor3f( 0.5, 0.5, 0.5 );
  361. }
  362. if ( iphoneDrawPicWithTouch( 48, 32+48*e, 384, 48, str ) ) {
  363. Cvar_SetValue( episode->name, e );
  364. menuState = IPM_MAPS;
  365. }
  366. pfglColor3f( 1, 1, 1 );
  367. }
  368. #ifdef EPISODE1
  369. // buy more episodes button
  370. GetMoreLevels( 240 - 64, 200 );
  371. #endif
  372. }
  373. /*
  374. ==================
  375. iphoneMapMenu
  376. ==================
  377. */
  378. void iphoneMapMenu() {
  379. int e, m, s;
  380. char str[64];
  381. if ( BackButton() ) {
  382. menuState = IPM_EPISODE;
  383. }
  384. // draw the level selection
  385. e = episode->value;
  386. if ( e < 0 ) {
  387. e = 0;
  388. }
  389. if ( e > 5 ) {
  390. e = 5;
  391. }
  392. s = skill->value;
  393. if ( s < 0 ) {
  394. s = 0;
  395. }
  396. if ( s > 3 ) {
  397. s = 3;
  398. }
  399. // draw the episode selection
  400. my_snprintf( str, sizeof( str ), "iphone/button_ep%i.tga", e+1 );
  401. iphoneDrawPicWithTouch( 96, 0, 384, 48, str );
  402. // draw the individual maps
  403. for ( m = 0 ; m < 10 ; m++ ) {
  404. int x;
  405. int y;
  406. colour4_t colorSecret = { 32, 32, 32, 255 };
  407. colour4_t colorNoTry = { 0, 0, 0, 255 };
  408. colour4_t colorTried = { 80, 80, 0, 255 };
  409. colour4_t colorCompleted = { 0, 80, 0, 255 };
  410. if ( m == 9 ) {
  411. sprintf( str, "SECRET" );
  412. x = 120;
  413. y = 90 + 160;
  414. } else if ( m == 8 ) {
  415. sprintf( str, "BOSS" );
  416. x = 360;
  417. y = 90 + 160;
  418. } else {
  419. sprintf( str, "LEVEL %i", m+1 );
  420. x = 60 + 120 * ( m % 4 );
  421. y = 90 + 80 * ( m / 4 );
  422. }
  423. unsigned char *color = colorNoTry;
  424. // decide on the background color
  425. int levelNum = e*10+m;
  426. int ch = currentMap.mapFlags[s][levelNum];
  427. // bit1 = attempted
  428. // bit2 = completed
  429. // bit3 = 100% kills
  430. // bit4 = 100% secrets
  431. // bit5 = 100% treasure
  432. if ( m == 9 && !( ch & MF_TRIED ) ) {
  433. color = colorSecret;
  434. } if ( ch & MF_COMPLETED ) {
  435. color = colorCompleted;
  436. } else if ( ch & MF_TRIED ) {
  437. color = colorTried;
  438. } else {
  439. color = colorNoTry;
  440. }
  441. // blink the level you are currently on
  442. if ( ( iphoneFrameNum & 8 ) && levelNum == currentMap.map && e == currentMap.episode ) {
  443. color = colorNoTry;
  444. }
  445. // draw the level text and check for button hit
  446. if ( TouchDown( x-46, y-9, 88, 32 ) ) {
  447. color = colorPressed;
  448. }
  449. R_Draw_Fill( x-46, y-9, 88, 32, color );
  450. iphoneCenterText( x, y, str );
  451. // draw awards
  452. if ( ch & MF_KILLS ) {
  453. iphoneDrawPic( x-46,y+23, 22, 22, "iphone/kills.tga" );
  454. }
  455. if ( ch & MF_SECRETS ) {
  456. iphoneDrawPic( x-24,y+23, 22, 22, "iphone/secrets.tga" );
  457. }
  458. if ( ch & MF_TREASURE ) {
  459. iphoneDrawPic( x-2,y+23, 22, 22, "iphone/treasure.tga" );
  460. }
  461. if ( ch & MF_TIME ) {
  462. iphoneDrawPic( x+20,y+23, 22, 22, "iphone/partime.tga" );
  463. }
  464. // don't let them go to the secret level unless they earned it
  465. if ( m == 9 && !( ch & MF_TRIED ) ) {
  466. continue;
  467. }
  468. if ( TouchReleased( x - 46, y - 9, 88, 32 ) ) {
  469. PL_NewGame( &Player );
  470. iphoneStartMap( e, m, s );
  471. }
  472. }
  473. }
  474. /*
  475. ==================
  476. iphoneStartIntermission
  477. The framesFromNow value allow boss death animations to be triggered
  478. ==================
  479. */
  480. void iphoneStartIntermission( int framesFromNow ) {
  481. // this goes in the savegame if they save at the intermission point,
  482. // which will cause it to come back up there on return
  483. currentMap.levelCompleted = 1;
  484. // mark this level as having been completed for the level selection menu
  485. int mapNum = currentMap.episode * 10 + currentMap.map;
  486. // note that this has been tried now
  487. currentMap.mapFlags[currentMap.skill][mapNum] |= MF_COMPLETED;
  488. // mark the awards
  489. if ( levelstate.time / 70.0f < levelstate.fpartime * 60 ) { // fpartime is in minutes, time is in tics
  490. currentMap.mapFlags[currentMap.skill][mapNum] |= MF_TIME;
  491. }
  492. if( levelstate.killed_monsters == levelstate.total_monsters ) {
  493. currentMap.mapFlags[currentMap.skill][mapNum] |= MF_KILLS;
  494. }
  495. if( levelstate.found_secrets == levelstate.total_secrets ) {
  496. currentMap.mapFlags[currentMap.skill][mapNum] |= MF_SECRETS;
  497. }
  498. if( levelstate.found_treasure == levelstate.total_treasure ) {
  499. currentMap.mapFlags[currentMap.skill][mapNum] |= MF_TREASURE;
  500. }
  501. intermissionStartFrameNum = iphoneFrameNum;
  502. if ( framesFromNow ) {
  503. intermissionTriggerFrame = iphoneFrameNum + framesFromNow;
  504. return;
  505. }
  506. intermissionTriggerFrame = 0;
  507. menuState = IPM_INTERMISSION;
  508. hasReleased = 0; // ensure touch up before skipping intermission
  509. }
  510. /*
  511. ==================
  512. DrawDigit
  513. ==================
  514. */
  515. void DrawDigit( int x, int y, int digit ) {
  516. R_Bind( numberPics[digit]->texnum );
  517. pfglBegin( GL_QUADS );
  518. pfglTexCoord2f( 0, 0 ); pfglVertex2i( x, y );
  519. pfglTexCoord2f( 1, 0 ); pfglVertex2i( x+32, y );
  520. pfglTexCoord2f( 1, 1 ); pfglVertex2i( x+32, y+32 );
  521. pfglTexCoord2f( 0, 1 ); pfglVertex2i( x, y+32 );
  522. pfglEnd();
  523. }
  524. void DrawDoubleDigit( int x, int y, int number ) {
  525. int step = 32;
  526. if ( number >= 100 ) {
  527. // cram three digits into the same space
  528. DrawDigit( x-8, y, number / 100 );
  529. number %= 100;
  530. x += 16;
  531. step = 24;
  532. }
  533. if ( number >= 10 ) {
  534. DrawDigit( x, y, number / 10 );
  535. number %= 10;
  536. }
  537. DrawDigit( x+step, y, number );
  538. }
  539. void DrawTime( int x, int y, int seconds ) {
  540. int min = seconds / 60;
  541. int sec = seconds % 60;
  542. DrawDoubleDigit( x, y, min );
  543. // DrawDoubleDigit( x+76, y, sec );
  544. // always print both digits of seconds, so 2:00 prints correctly
  545. DrawDigit( x+76, y, sec / 10 );
  546. DrawDigit( x+76+32, y, sec % 10 );
  547. }
  548. void DrawRatio( int y, int got, int total, const char *bonusPic ) {
  549. DrawDoubleDigit( 285, y, got );
  550. DrawDoubleDigit( 361, y, total );
  551. // draw the award icon
  552. if ( got == total ) {
  553. iphoneDrawPic( 480 - 40, y, 32, 32, bonusPic );
  554. }
  555. }
  556. /*
  557. ==================
  558. iphoneIntermission
  559. ==================
  560. */
  561. void iphoneIntermission() {
  562. int nextLevel = 0;
  563. char str[128];
  564. iphoneDrawPic( 0, 0, 480, 320, "iphone/intermission.tga" );
  565. // episode
  566. my_snprintf( str, sizeof( str ), "iphone/button_ep%i.tga", currentMap.episode+1 );
  567. iphoneDrawPic( 0, 0, 384, 48, str );
  568. // level
  569. iphoneDrawNumber( 430, 0, currentMap.map + 1, 48, 48 );
  570. // par / time
  571. DrawTime( 51, 63, levelstate.fpartime * 60 ); // fpartime is in minutes
  572. DrawTime( 285, 63, levelstate.time / 70 ); // levelstate.time is in tics
  573. if ( levelstate.time/70 <= levelstate.fpartime * 60 ) {
  574. iphoneDrawPic( 480 - 40, 63, 32, 32, "iphone/partime.tga" );
  575. }
  576. // ratios
  577. DrawRatio( 124, levelstate.killed_monsters, levelstate.total_monsters, "iphone/kills.tga" );
  578. DrawRatio( 189, levelstate.found_secrets, levelstate.total_secrets, "iphone/secrets.tga" );
  579. DrawRatio( 255, levelstate.found_treasure, levelstate.total_treasure, "iphone/treasure.tga" );
  580. // require all touches off before the intermission can exit
  581. if ( numTouches == 0 && hasReleased == 0 ) {
  582. hasReleased = 1;
  583. return; // don't let the TouchReleased immediately fire
  584. }
  585. if ( !hasReleased ) {
  586. return;
  587. }
  588. //----------------------
  589. // tap for next level
  590. //----------------------
  591. if ( !TouchReleased( 0, 0, 480, 320 ) ) {
  592. return;
  593. }
  594. menuState = IPM_GAME;
  595. PL_NextLevel( &Player );
  596. if( g_version->value == SPEAROFDESTINY ) {
  597. }
  598. else
  599. {
  600. int currentLevel = currentMap.episode * 10 + currentMap.map;
  601. if( Player.playstate == ex_secretlevel ) {
  602. switch( currentLevel ) {
  603. case 0: nextLevel = 9; break;
  604. case 10: nextLevel = 19; break;
  605. case 26: nextLevel = 29; break;
  606. case 32: nextLevel = 39; break;
  607. case 44: nextLevel = 49; break;
  608. case 52: nextLevel = 59; break;
  609. }
  610. } else {
  611. switch ( currentLevel ) {
  612. case 8:
  613. case 18:
  614. case 28:
  615. case 38:
  616. case 48:
  617. case 58:
  618. // go back to the episode select screen
  619. menuState = IPM_VICTORY;
  620. Sound_StartBGTrack( "music/URAHERO.ogg", "music/URAHERO.ogg" );
  621. return;
  622. case 9: nextLevel = 1; break;
  623. case 19: nextLevel = 11; break;
  624. case 29: nextLevel = 27; break;
  625. case 39: nextLevel = 33; break;
  626. case 49: nextLevel = 44; break;
  627. case 59: nextLevel = 53; break;
  628. default: nextLevel = currentLevel + 1; break;
  629. }
  630. }
  631. }
  632. iphoneStartMap( (nextLevel/10), (nextLevel%10), skill->value );
  633. }
  634. /*
  635. ==================
  636. iphoneVictory
  637. ==================
  638. */
  639. void iphoneVictory() {
  640. iphoneDrawPic( 0, 0, 480, 320, "iphone/victory.tga" );
  641. if ( !TouchReleased( 0, 0, 480, 320 ) ) {
  642. return;
  643. }
  644. menuState = IPM_EPISODE;
  645. }
  646. /*
  647. ==================
  648. iphoneAutomap
  649. ==================
  650. */
  651. float mapOrigin[2];
  652. float mapCenterY;
  653. float mapScale;
  654. typedef struct {
  655. W8 x, y;
  656. short texnum;
  657. } mapTile_t;
  658. #define MAPTILE_SPRITE_FLAG 1024
  659. #define MAX_MAP_TILES 5000 // 4096 tiles + sprites
  660. mapTile_t mapTiles[MAX_MAP_TILES];
  661. int numMapTiles;
  662. int MapTileSort( const void *a, const void *b ) {
  663. return ((mapTile_t *)a)->texnum - ((mapTile_t *)b)->texnum;
  664. }
  665. void iphoneOpenAutomap() {
  666. mapTile_t *mt = mapTiles;
  667. numMapTiles = 0;
  668. int x, y;
  669. int xx, yy;
  670. W32 tx, ty, n;
  671. sprite_t* sprt;
  672. mapOrigin[0] = Player.position.origin[0] / (float)TILEGLOBAL;
  673. mapOrigin[1] = Player.position.origin[1] / (float)TILEGLOBAL;
  674. mapScale = 10;
  675. menuState = IPM_AUTOMAP;
  676. // identify all the tiles to fill in
  677. for( x = 0 ; x < 64; ++x ) {
  678. for( y = 0 ; y < 64; ++y ) {
  679. if ( r_world->tilemap[ x ][ y ] & ( WALL_TILE | PUSHWALL_TILE ) ) {
  680. int visible = 0;
  681. // check all 8 surrounding tiles for visibility
  682. for ( xx = -1 ; xx <= 1 ; xx++ ) {
  683. if ( x + xx < 0 ) {
  684. continue;
  685. }
  686. if ( x + xx > 63 ) {
  687. continue;
  688. }
  689. for ( yy = -1 ; yy <= 1 ; yy++ ) {
  690. if ( y + yy < 0 ) {
  691. continue;
  692. }
  693. if ( y + yy > 63 ) {
  694. continue;
  695. }
  696. if ( r_world->tileEverVisible[x+xx][y+yy] ) {
  697. visible = 1;
  698. break;
  699. }
  700. }
  701. }
  702. if ( !visible ) {
  703. continue;
  704. }
  705. int tex = r_world->wall_tex_y[ x ][ y ];
  706. // special hack for the elevator switch tile, which is always
  707. // facing east west for the switch, and north south for the railing
  708. if ( tex == 40 && ( ( x>0 && r_world->tileEverVisible[x+1][y] )
  709. || ( x < 63 && r_world->tileEverVisible[x-1][y] ) ) ) {
  710. tex = r_world->wall_tex_x[ x ][ y ];
  711. }
  712. if ( tex < 0x6a ) { // skip pushwall destinations
  713. assert( tex >= 0 && tex < 1000 );
  714. mt->x = x;
  715. mt->y = y;
  716. mt->texnum = tex;
  717. if ( !wallTextures[mt->texnum] ) {
  718. char name[1024];
  719. my_snprintf( name, sizeof( name ), "walls/%.3d.tga", mt->texnum );
  720. wallTextures[mt->texnum] = TM_FindTexture( name, TT_Wall );
  721. assert( wallTextures[mt->texnum] );
  722. }
  723. mt++;
  724. continue;
  725. }
  726. }
  727. if ( !r_world->tileEverVisible[x][y] ) {
  728. continue;
  729. }
  730. if( r_world->tilemap[ x ][ y ] & DOOR_TILE ) {
  731. mt->x = x;
  732. mt->y = y;
  733. mt->texnum = r_world->Doors.DoorMap[ x ][ y ].texture;
  734. if ( !wallTextures[ mt->texnum] ) {
  735. char name[1024];
  736. my_snprintf( name, sizeof( name ), "walls/%.3d.tga", mt->texnum );
  737. wallTextures[mt->texnum] = TM_FindTexture( name, TT_Wall );
  738. assert( wallTextures[mt->texnum] );
  739. }
  740. mt++;
  741. continue;
  742. }
  743. // solid floor
  744. mt->x = x;
  745. mt->y = y;
  746. mt->texnum = -1;
  747. mt++;
  748. }
  749. }
  750. // add solid sprite objects
  751. for( n = 0, sprt = Spr_Sprites; n < n_of_sprt; ++n, ++sprt ) {
  752. if( sprt->flags & SPRT_REMOVE ) {
  753. continue;
  754. }
  755. if ( sprt->tex[0] >= SPR_GRD_S_1 ) {
  756. // don't draw enemies, only static sprites
  757. continue;
  758. }
  759. tx = sprt->tilex;
  760. ty = sprt->tiley;
  761. if( tx > 63 ) {
  762. continue;
  763. }
  764. if( ty > 63 ) {
  765. continue;
  766. }
  767. if ( !r_world->tileEverVisible[tx][ty] ) {
  768. continue;
  769. }
  770. mt->x = tx;
  771. mt->y = ty;
  772. mt->texnum = MAPTILE_SPRITE_FLAG | sprt->tex[0];
  773. mt++;
  774. if ( !spriteTextures[ sprt->tex[0] ] ) {
  775. char name[1024];
  776. my_snprintf( name, sizeof( name ), "sprites/%.3d.tga", sprt->tex[0] );
  777. spriteTextures[sprt->tex[0]] = TM_FindTexture( name, TT_Sprite );
  778. }
  779. if ( mt == &mapTiles[MAX_MAP_TILES] ) {
  780. break; // list is full, some items won't show (shouldn't happen)
  781. }
  782. }
  783. // sort the tiles to be drawn by texture
  784. numMapTiles = mt - mapTiles;
  785. qsort( mapTiles, numMapTiles, sizeof( mapTiles[0] ), MapTileSort );
  786. }
  787. void iphoneAutomap() {
  788. mapTile_t *mt;
  789. float px, py;
  790. float angle, c, s;
  791. int texnum;
  792. // do touch ops before drawing for minimum latency
  793. // drag for scrolling
  794. if ( numTouches == 1 ) {
  795. if ( numPrevTouches == 1 ) {
  796. mapOrigin[0] -= ( touches[0][0] - prevTouches[0][0] ) / mapScale;
  797. mapOrigin[1] += ( touches[0][1] - prevTouches[0][1] ) / mapScale;
  798. }
  799. }
  800. // pinch for scaling
  801. if ( numTouches == 2 ) {
  802. if ( numPrevTouches == 2 ) {
  803. float curDist = sqrt(
  804. ( touches[0][0] - touches[1][0] ) * ( touches[0][0] - touches[1][0] ) +
  805. ( touches[0][1] - touches[1][1] ) * ( touches[0][1] - touches[1][1] ) );
  806. float prevDist = sqrt(
  807. ( prevTouches[0][0] - prevTouches[1][0] ) * ( prevTouches[0][0] - prevTouches[1][0] ) +
  808. ( prevTouches[0][1] - prevTouches[1][1] ) * ( prevTouches[0][1] - prevTouches[1][1] ) );
  809. if ( prevDist == 0 ) {
  810. prevDist = curDist;
  811. }
  812. mapScale *= curDist / prevDist;
  813. if ( mapScale < 4 ) {
  814. mapScale = 4;
  815. }
  816. if ( mapScale > 64 ) {
  817. mapScale = 64;
  818. }
  819. }
  820. }
  821. // todo -- double tap for center on player
  822. // set up matrix for drawing in tile units
  823. pfglMatrixMode( GL_PROJECTION );
  824. pfglLoadIdentity();
  825. pfglRotatef( 90, 0, 0, 1 );
  826. pfglOrtho( mapOrigin[0]-240.0 / mapScale, mapOrigin[0]+240.0 / mapScale,
  827. mapOrigin[1]-160.0 / mapScale, mapOrigin[1]+160.0 / mapScale, -99999, 99999 );
  828. mt = mapTiles;
  829. texnum = 99999;
  830. for ( int i = 0 ; i < numMapTiles ; i++, mt++ ) {
  831. if ( texnum != mt->texnum ) {
  832. texnum = mt->texnum;
  833. if ( i != 0 ) {
  834. pfglEnd();
  835. }
  836. if ( mt->texnum == -1 ) {
  837. qglDisable( GL_TEXTURE_2D );
  838. pfglColor3f( r_world->floorColour[0]/255.0, r_world->floorColour[1]/255.0, r_world->floorColour[2]/255.0 );
  839. } else if ( mt->texnum & MAPTILE_SPRITE_FLAG ) {
  840. qglEnable( GL_TEXTURE_2D );
  841. pfglColor3f( 1, 1, 1 );
  842. R_Bind( spriteTextures[mt->texnum&~MAPTILE_SPRITE_FLAG]->texnum );
  843. } else {
  844. qglEnable( GL_TEXTURE_2D );
  845. pfglColor3f( 1, 1, 1 );
  846. R_Bind( wallTextures[mt->texnum]->texnum );
  847. }
  848. pfglBegin( GL_QUADS );
  849. }
  850. pfglTexCoord2f( 0, 1 );
  851. pfglVertex2i( mt->x, mt->y );
  852. pfglTexCoord2f( 1, 1 );
  853. pfglVertex2i( mt->x+1, mt->y );
  854. pfglTexCoord2f( 1, 0 );
  855. pfglVertex2i( mt->x+1, mt->y+1 );
  856. pfglTexCoord2f( 0, 0 );
  857. pfglVertex2i( mt->x, mt->y+1 );
  858. }
  859. pfglEnd();
  860. // draw the yellow player triangle
  861. qglDisable( GL_TEXTURE_2D );
  862. if ( iphoneFrameNum & 8 ) { // blink it
  863. pfglColor3f( 1, 1, 0 );
  864. } else {
  865. pfglColor3f( 0.5, 0.5, 0 );
  866. }
  867. angle = M_PI * Player.position.angle / (float)ANG_180;
  868. c = cos( angle );
  869. s = sin( angle );
  870. px = Player.position.origin[0] / (float)TILEGLOBAL;
  871. py = Player.position.origin[1] / (float)TILEGLOBAL;
  872. pfglBegin( GL_TRIANGLES );
  873. pfglVertex3f( px + c * 0.5, py + s * 0.5, 0 );
  874. pfglVertex3f( px - c * 0.5 - s * 0.3, py - s * 0.5 + c * 0.3, 0 );
  875. pfglVertex3f( px - c * 0.5 + s * 0.3, py - s * 0.5 - c * 0.3, 0 );
  876. pfglEnd();
  877. qglEnable( GL_TEXTURE_2D );
  878. pfglColor3f( 1, 1, 1 );
  879. // back button for returning to game
  880. pfglMatrixMode( GL_PROJECTION );
  881. pfglLoadIdentity();
  882. pfglRotatef( 90, 0, 0, 1 );
  883. pfglOrtho( 0, 480, 320, 0, -99999, 99999 );
  884. if ( BackButton() ) {
  885. menuState = IPM_GAME;
  886. }
  887. }
  888. void iphoneDrawMenus() {
  889. iphoneDrawPic( 0, 0, 480, 320, "iphone/background_1.tga" );
  890. switch ( menuState ) {
  891. case IPM_MAIN: iphoneMainMenu(); break;
  892. case IPM_SKILL: iphoneSkillMenu(); break;
  893. case IPM_EPISODE: iphoneEpisodeMenu(); break;
  894. case IPM_MAPS: iphoneMapMenu(); break;
  895. case IPM_CONTROLS: iphoneControlMenu(); break;
  896. case IPM_INTERMISSION: iphoneIntermission(); break;
  897. case IPM_VICTORY: iphoneVictory(); break;
  898. case IPM_AUTOMAP: iphoneAutomap(); break;
  899. }
  900. }