npclevel.cpp 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769
  1. /**
  2. * ideas, ...
  3. * hexafield with rotate
  4. * different kind of block-checks, ... row-like, neuralplay like.
  5. *
  6. * seven kind of game with changing target sum, .. generated from the level so correct answer is always there.
  7. *
  8. * NOTES:
  9. * ::randomBlock defines a random block in the selected space.
  10. *
  11. */
  12. #define EMPTY_CARD 100
  13. #define JOKER_CARD 101
  14. #define DECK_POSITION_X (52000)
  15. #define DECK_POSITION_Y (14000)
  16. #define TILE_SIZE_ADD 3000
  17. #define DESTROYINGSPEED 1024 // 256 = 1
  18. #define ALLOW_VOID_MOVES // Allow moves that do not result destroying
  19. #define SQUARE_BASED // square-based or hexagon-based
  20. //#include <qdebug>
  21. #include "npclevel.h"
  22. #include <math.h> // for cosine.
  23. #include <memory.h> // for memcpy and memset
  24. #include <stdio.h> // for debug.
  25. #include <stdlib.h> // for random, can be changed if needed.
  26. #include <string.h> // for strlen
  27. #ifndef __int64
  28. #define __int64 long long int
  29. #endif
  30. CNpcLevel::CNpcLevel(ITileRenderer *renderer, CParticleEngine *pengine, int width, int height ) : m_renderer(renderer) {
  31. m_pengine = pengine;
  32. m_deckVisibility = 0;
  33. m_destroyingRound = 0;
  34. m_dragBegan = 0;
  35. m_hint1 = 0;
  36. m_hint2 = 0;
  37. m_levelScore = 0;
  38. m_levelProgressChange = 0;
  39. //m_wasDropping = 0;
  40. m_grid = 0;
  41. m_difficulty = 1;
  42. m_gridWidth = 0;
  43. m_gridHeight = 0;
  44. m_floatingAngle = 0;
  45. m_state = eLEVELSTATE_IDLE;
  46. m_levelScore = 0;
  47. m_levelProgressChange = 0;
  48. m_currentLevel = 0;
  49. m_hasMoves = 0;
  50. m_changing[0] = 0;
  51. m_changing[1] = 0;
  52. setGameArea( 0,0, 65536, 65536 );
  53. m_changingCounter = 0;
  54. m_illegalMoveCounter = 0;
  55. for (int f=0; f<4096; f++) {
  56. m_cosineTable[f] = (int)( cos( (float)f/4096.0f * 3.14159f*2.0f ) * 65536.0f );
  57. };
  58. resetGrid( width, height );
  59. // Reset sprays
  60. pengine->createSprayType( &m_scoreSpray, (TexFont<<16)+10, 0, 0,0,65535,0, 65536/8, 0,0,0, scoreParticleRenderFunction, this );
  61. pengine->createSprayType( &m_smokeSpray, (TexParticle<<16),0, 0,0, 65536/4,65536/4, 65536/16,65536/16, 65536/4,65536/8,0,0,0,65536,0,8000 );
  62. pengine->createSprayType( &m_sparkleSpray, (TexParticle<<16)+2,0, 80000,3000, 32536,80536, 65536/20,65536/16, -9000,6000,0,0,0,65536,-32000,32000, 1 );
  63. pengine->createSprayType( &m_fruitSpray, (TexPieces<<16),8, 164000,4000, 65536,65536, 65536/10,65536/10, -5500,4000,0,0,0,65536,-90000,180000, 0 );
  64. pengine->createSprayType( &m_morphSpray, (TexParticle<<16)+3, 0,
  65. 0,2000, 65536/3,65536/8, 65536/2,0, -32000,0,0,0,0,65536,0,16000, 1 );
  66. };
  67. CNpcLevel::~CNpcLevel() {
  68. resetGrid(0,0); // release
  69. };
  70. void CNpcLevel::scoreParticleRenderFunction( void *data, SParticle *p ) {
  71. CNpcLevel *l = (CNpcLevel*)data;
  72. int x = p->x;// - p->size/2;
  73. int y = p->y; // - p->size/2;
  74. char testr[20];
  75. int size = 120000 + 65536-p->lifeTime/2;
  76. size/=14;
  77. y-=size/2;
  78. if ((p->userData>>16)==0) {
  79. size/=2;
  80. int val = (p->userData&255);
  81. int type = ((p->userData>>8)&255);
  82. switch (type) {
  83. case 0:
  84. default:
  85. sprintf(testr, "%d of a kind", val );
  86. break;
  87. case 1:
  88. sprintf(testr, "flush of %d", val );
  89. break;
  90. case 2:
  91. sprintf(testr, "straight of %d", val );
  92. break;
  93. }
  94. } else {
  95. int j =((p->userData>>16)&255);
  96. if (j==50) {
  97. size/=2;
  98. strcpy( testr, "solve bonus");
  99. } else {
  100. if (j==51) {
  101. size/=2;
  102. strcpy( testr, "taptap");
  103. } else
  104. sprintf(testr, "x%d", j );
  105. }
  106. };
  107. char *text = testr;
  108. x-= strlen(testr)*size*3/5/2;
  109. char ch;
  110. // end fade
  111. int fade =255-(p->lifeTime>>6);
  112. if (fade<0) fade = 0;
  113. if (fade==0) { // START FADE
  114. fade = (65536-p->lifeTime)/20;
  115. if (fade<0) fade = 0;
  116. //fade = (p->lifeTime>>7);
  117. //if (fade>255) fade = 255;
  118. fade>>=8;
  119. };
  120. while (*text!=0) {
  121. if (*text!=' ') {
  122. ch = *text-32;
  123. l->m_renderer->renderTile( x,y,size,size, 0, 0, (TexFont<<16) | ch | (fade<<24), 0 );
  124. }
  125. x+=size*3/5;
  126. text++;
  127. };
  128. };
  129. void CNpcLevel::setLevelState( eLEVELSTATE newState ) {
  130. m_state = newState;
  131. switch (m_state) {
  132. case eLEVELSTATE_BEGINNING:
  133. zeroMask( GRIDFLAG_CALCULATION_TEMP );
  134. m_renderer->effectNotify( eEFFECT_NEWLEVEL, 0,0 );
  135. m_startupCounter = 65536*5;
  136. break;
  137. case eLEVELSTATE_GAMEOVER:
  138. m_startupCounter = (m_gridWidth*m_gridHeight)*65536 ;
  139. break;
  140. case eLEVELSTATE_LEVELCOMPLETED:
  141. zeroMask( GRIDFLAG_CALCULATION_TEMP );
  142. m_startupCounter = 65536*5;
  143. break;
  144. };
  145. };
  146. int CNpcLevel::randomBlock() {
  147. int amount_of_numbers = 7;
  148. int rval = (rand()&3)*13 + ((13-amount_of_numbers)+(rand()%amount_of_numbers));
  149. //return (rand()&3)*13 + (4+(rand()%9));
  150. //return (rand()&3)*13 + (4+(rand()%9));
  151. int empty_prob = -2+m_currentLevel * 3;
  152. if (empty_prob>38) empty_prob = 48;
  153. if ((rand() & 255) < empty_prob) rval = EMPTY_CARD;
  154. //if ((rand() & 255) < 32) rval = JOKER_CARD;
  155. return rval;
  156. //return (rand()%(13*4));
  157. };
  158. void CNpcLevel::createLevel( int levelIndex ) {
  159. m_currentLevel = levelIndex;
  160. m_hint1 = 0;
  161. m_hint2 = 0;
  162. int tecount = 0;
  163. do {
  164. // "plant the seeds"
  165. for (int f=0; f<m_gridWidth*m_gridHeight; f++) {
  166. m_grid[f].index = randomBlock();
  167. m_grid[f].flags = 0;
  168. m_grid[f].animationCount = (rand()&65535)*8;
  169. m_grid[f].destroying = -1;
  170. m_grid[f].dropping = -1;
  171. m_grid[f].wobble = 0;
  172. m_grid[f].wobbleinc = 0;
  173. }
  174. tecount++;
  175. } while (checkDestroyWholeLevel(0) != 0 || hasMovesLeft() != 1);
  176. m_hasMoves = 1;
  177. zeroMask( 0xFFFFFFFF );
  178. m_changing[0] = 0;
  179. m_changing[1] = 0;
  180. m_levelScore = 0;
  181. m_levelProgressChange = 0;
  182. cancelSelection(0);
  183. cancelSelection(1);
  184. m_destroyingRound = 0;
  185. hasMovesLeft(); // update hint
  186. setLevelState( eLEVELSTATE_BEGINNING );
  187. };
  188. void CNpcLevel::resetGrid( int width, int height ) {
  189. if (m_grid) {
  190. delete [] m_grid;
  191. m_grid = 0;
  192. };
  193. m_hint1 = 0;
  194. m_hint2 = 0;
  195. m_gridWidth = width;
  196. m_gridHeight = height;
  197. if (m_gridHeight<1 || m_gridWidth<1) return;
  198. m_grid = new SNpcGridItem[ m_gridWidth * m_gridHeight ];
  199. m_itemWidth = 65536 / m_gridWidth;
  200. m_itemHeight = 65536 / m_gridHeight;
  201. int w = m_itemWidth;
  202. int h = m_itemHeight;
  203. int x,y;
  204. // (re)calculate coordinates
  205. for (int g=0; g<m_gridWidth; g++) {
  206. x = (g<<16)/m_gridWidth + (65536/2)/m_gridWidth;
  207. #ifdef SQUARE_BASED
  208. int yoff= (65536/2)/m_gridHeight; // + (65536/2)/m_gridHeight;
  209. #else
  210. int yoff = (g&1)*h/2;
  211. #endif
  212. SNpcGridItem *i = m_grid + g;
  213. for (int f=0; f<m_gridHeight; f++ ) {
  214. i->gridxpos = g;
  215. i->gridypos = f;
  216. y = ((f)<<16)/m_gridHeight + yoff;
  217. i->lposx = x - (w>>1);
  218. i->lposy = y - (h>>1);
  219. i->genCount = 0;
  220. i->destroying = -1;
  221. i->dropping = -1;
  222. i->animationCount = 0;
  223. i->wobble = 0;
  224. i->wobbleinc = 0;
  225. i+=m_gridWidth;
  226. };
  227. };
  228. };
  229. // PUZZLEPOKER LOGIC.
  230. int CNpcLevel::calculateSimilar( int index, int x, int y, int checkmode, int dir ) {
  231. switch (dir) {
  232. case 0: y--; break;
  233. case 1: y++; break;
  234. case 2: x--; break;
  235. case 3: x++; break;
  236. };
  237. SNpcGridItem *i = getGridItemAt(x,y);
  238. if (!i) return 0;
  239. if (i->index==EMPTY_CARD) return 0;
  240. if (i->index==-1) return 0;
  241. if (i->dropping!=-1) return 0;
  242. if (i->destroying>0) return 0; // 0 is correct,... NOT -1
  243. //if (i->flags&GRIDFLAG_MARKED) return 0;
  244. //if (i==0 || i->index!=index) return 0;
  245. int earth_index = i->index/13;
  246. int number_index = i->index-earth_index*13;
  247. switch (checkmode) {
  248. default:
  249. case 0: // similar earth
  250. if ((i->flags & GRIDFLAG_SAME_EARTH) != 0) return 0;
  251. if ((earth_index != index/13)) return 0;
  252. i->flags |= GRIDFLAG_SAME_EARTH;
  253. break;
  254. case 1: // similar number
  255. if ((i->flags & GRIDFLAG_SAME_NUMBER) != 0) return 0;
  256. if (number_index != (index-index/13*13)) return 0;
  257. i->flags |= GRIDFLAG_SAME_NUMBER;
  258. break;
  259. case 2: // "normal" minus straight
  260. if ((i->flags & GRIDFLAG_MINUS_STRAIGHT) != 0) return 0;
  261. if ((dir&1)==0) { // backwards
  262. if (number_index!=(index-index/13*13)-1) return 0;
  263. } else {
  264. if (number_index!=(index-index/13*13)+1) return 0;
  265. };
  266. i->flags |= GRIDFLAG_MINUS_STRAIGHT;
  267. break;
  268. case 3: // "reverse" plus straight
  269. if ((i->flags & GRIDFLAG_PLUS_STRAIGHT) != 0) return 0;
  270. if ((dir&1)==0) { // backwards
  271. if (number_index!=(index-index/13*13)+1) return 0;
  272. } else {
  273. if (number_index!=(index-index/13*13)-1) return 0;
  274. };
  275. i->flags |= GRIDFLAG_PLUS_STRAIGHT;
  276. break;
  277. };
  278. return 1+calculateSimilar(i->index, x,y, checkmode, dir );
  279. };
  280. int CNpcLevel::checkDestroyAt( int blockx, int blocky, char apply ) {
  281. SNpcGridItem *i = getGridItemAt( blockx, blocky);
  282. int rval = 0;
  283. int sim_earth;
  284. int sim_number;
  285. int minus_straight;
  286. int plus_straight;
  287. if (i->index!=-1 && i->index!=EMPTY_CARD) {
  288. for (int dir = 0; dir<2; dir++) {
  289. zeroMask( GRIDFLAG_PLUS_STRAIGHT | GRIDFLAG_MINUS_STRAIGHT | GRIDFLAG_SAME_EARTH | GRIDFLAG_SAME_NUMBER | GRIDFLAG_CALCULATION_TEMP);
  290. minus_straight = calculateSimilar( i->index, blockx, blocky, 2, dir*2) +
  291. calculateSimilar( i->index, blockx, blocky, 2, dir*2+1) + 1;
  292. if (minus_straight>3) {
  293. i->flags |= GRIDFLAG_MINUS_STRAIGHT;
  294. if (apply) applyDestroy( GRIDFLAG_MINUS_STRAIGHT );
  295. rval = 1;
  296. };
  297. plus_straight = calculateSimilar( i->index, blockx, blocky, 3, dir*2) +
  298. calculateSimilar( i->index, blockx, blocky, 3, dir*2+1) + 1;
  299. if (plus_straight>3) {
  300. i->flags |= GRIDFLAG_PLUS_STRAIGHT;
  301. if (apply) applyDestroy( GRIDFLAG_PLUS_STRAIGHT );
  302. rval = 1;
  303. };
  304. // similar earth
  305. sim_earth = calculateSimilar( i->index, blockx, blocky, 0, dir*2) +
  306. calculateSimilar( i->index, blockx, blocky, 0, dir*2+1) + 1;
  307. if (sim_earth>=4) {
  308. i->flags |= GRIDFLAG_SAME_EARTH;
  309. if (apply) applyDestroy( GRIDFLAG_SAME_EARTH );
  310. rval = 1;
  311. };
  312. sim_number = calculateSimilar( i->index, blockx, blocky, 1, dir*2) +
  313. calculateSimilar( i->index, blockx, blocky, 1, dir*2+1) + 1;
  314. if (sim_number>2) {
  315. i->flags |= GRIDFLAG_SAME_NUMBER;
  316. if (apply) applyDestroy( GRIDFLAG_SAME_NUMBER );
  317. rval = 1;
  318. };
  319. }
  320. }
  321. return rval;
  322. };
  323. /*
  324. // basic match3 -> fruitcake logic
  325. int CNpcLevel::calculateSimilar( int index, int x, int y, int checkmode, int dir ) {
  326. int rval = 0;
  327. SNpcGridItem *i = getGridItemAt(x,y);
  328. if (i==0 || i->index==0xFFFFFFFF) return 0;
  329. // seek the beginning ...
  330. int x2=x;
  331. int y2=y;
  332. while (1) {
  333. #ifdef SQUARE_BASED
  334. if (dir==0) {x2--;} else {y2--;}
  335. #else
  336. if (dir==0) { y2+=(x2&1); x2--; }
  337. else if (dir==1) { x2--; y2-=(x2&1); }
  338. else { y2--; }
  339. #endif
  340. i = getGridItemAt( x2,y2 );
  341. if (!i) break;
  342. if (i->index != index) break;
  343. x = x2;
  344. y = y2;
  345. };
  346. while (1) {
  347. i = getGridItemAt( x,y );
  348. if (!i) break;
  349. if (i->index != index ) break;
  350. rval++;
  351. i->flags |= GRIDFLAG_CALCULATION_TEMP;
  352. #ifdef SQUARE_BASED
  353. if (dir==0) x++; else y++;
  354. #else
  355. if (dir==0) { x++; y-=(x&1); }
  356. else if (dir==1) { y+=(x&1); x++; }
  357. else { y++; }
  358. #endif
  359. };
  360. return rval;
  361. };
  362. int CNpcLevel::checkDestroyAt( int blockx, int blocky, char apply ) {
  363. SNpcGridItem *i = getGridItemAt( blockx, blocky);
  364. int rval = 0;
  365. int a = 0;
  366. if (i->index!=0xFFFFFFFF) {
  367. zeroMask( GRIDFLAG_CALCULATION_TEMP );
  368. a = calculateSimilar( i->index, blockx,blocky,0,0 );
  369. if (a>=3) { if (apply) applyDestroy(GRIDFLAG_CALCULATION_TEMP); rval = 1; } else zeroMask( GRIDFLAG_CALCULATION_TEMP );
  370. a = calculateSimilar( i->index, blockx,blocky,0,1 );
  371. if (a>=3) { if (apply) applyDestroy(GRIDFLAG_CALCULATION_TEMP); rval = 1; } else zeroMask( GRIDFLAG_CALCULATION_TEMP );
  372. #ifndef SQUARE_BASED // check the thrid direction with hexagons.
  373. a = calculateSimilar( i->index, blockx,blocky,0,2 );
  374. if (a>=3) { if (apply) applyDestroy(GRIDFLAG_CALCULATION_TEMP); rval = 1; }
  375. #endif
  376. }
  377. return rval;
  378. };
  379. */
  380. int CNpcLevel::checkDestroyWholeLevel(char apply) {
  381. int rval = 0;
  382. for (int f=0; f<m_gridHeight; f++)
  383. for (int g=0; g<m_gridWidth; g++)
  384. if (checkDestroyAt( g,f,apply ) != 0) rval = 1;
  385. return rval;
  386. };
  387. void CNpcLevel::wobbleHint() {
  388. //return; // TODO, BACK ON
  389. if (m_hint1==0 || m_hint2==0) return; // error
  390. m_hint1->wobbleinc = -65535/16;
  391. m_hint2->wobbleinc = -65535/15;
  392. if (m_currentLevel==0) { // switch us
  393. int x= xtoGameArea((65536/m_gridWidth+m_hint1->lposx+m_hint2->lposx)/2 );
  394. int y= ytoGameArea((65536/m_gridHeight+m_hint1->lposy+m_hint2->lposy)/2 );
  395. int dx= xtoGameArea(65536/2)-x;
  396. int dy= ytoGameArea(65536/2)-y;
  397. m_pengine->spray( 1, x,y,0, dx/4,dy/4,0, 51<<16, &m_scoreSpray );
  398. }
  399. };
  400. int CNpcLevel::tryMoveWith( SNpcGridItem *i1, SNpcGridItem *i2 ) {
  401. //qdebug() << "trymovewith start";
  402. if (i1==0 || i2==0) return 0;
  403. int ctemp = i1->index;
  404. i1->index = i2->index;
  405. i2->index = ctemp;
  406. int rval = 0;
  407. if (checkDestroyAt( i1->gridxpos, i1->gridypos, 0 ) == 1 ||
  408. checkDestroyAt( i2->gridxpos, i2->gridypos, 0 ) == 1) {
  409. rval = 1;
  410. };
  411. ctemp = i1->index; // change back
  412. i1->index = i2->index;
  413. i2->index = ctemp;
  414. //qdebug() << "trymovewith end";
  415. return rval;
  416. };
  417. int CNpcLevel::hasMovesLeft() {
  418. m_hint1 = 0;
  419. m_hint2 = 0;
  420. //qdebug()<<"hasmovesleft start";
  421. // seek through moves
  422. for (int y=m_gridHeight-1; y>1; y--) {
  423. SNpcGridItem *i1 = (m_grid+m_gridWidth*y);
  424. for (int x=0; x<m_gridWidth; x++) {
  425. // simulate the moves..
  426. #ifdef SQUARE_BASED
  427. if (tryMoveWith( i1,getGridItemAt( x,y+1 ) ) == 1) {
  428. //i1->flags |= GRIDFLAG_SELECTED;
  429. m_hint1 = i1;
  430. m_hint2 = getGridItemAt( x,y+1 );
  431. //qdebug()<<"hasmovesleft end";
  432. return 1;
  433. }
  434. if (tryMoveWith( i1,getGridItemAt( x+1,y ) ) == 1) {
  435. //i1->flags |= GRIDFLAG_SELECTED;
  436. m_hint1 = i1;
  437. m_hint2 = getGridItemAt( x+1,y );
  438. //qdebug()<<"hasmovesleft end";
  439. return 1;
  440. }
  441. #else
  442. if (tryMoveWith( i1,getGridItemAt( x,y+1 ) ) == 1) {
  443. //i1->flags |= GRIDFLAG_SELECTED;
  444. m_hint1 = i1;
  445. m_hint2 = getGridItemAt( x,y+1 );
  446. //qdebug()<<"hasmovesleft end";
  447. return 1;
  448. }
  449. if (tryMoveWith( i1,getGridItemAt( x+1,y-1+(x&1) ) ) == 1) {
  450. //i1->flags |= GRIDFLAG_SELECTED;
  451. m_hint1 = i1;
  452. m_hint2 = getGridItemAt( x+1,y-1+(x&1) );
  453. //qdebug()<<"hasmovesleft end";
  454. return 1;
  455. }
  456. if (tryMoveWith( i1,getGridItemAt( x+1,y-1+(x&1)+1 ) ) == 1) {
  457. //i1->flags |= GRIDFLAG_SELECTED;
  458. m_hint1 = i1;
  459. m_hint2 = getGridItemAt( x+1,y-1+(x&1)+1 );
  460. //qdebug()<<"hasmovesleft end";
  461. return 1;
  462. }
  463. #endif
  464. i1++;
  465. };
  466. };
  467. //qdebug()<<"hasmovesleft end";
  468. return 0;
  469. };
  470. void CNpcLevel::applyDestroy(unsigned int flag) {
  471. char wasFirst = 0;
  472. int width = m_itemWidth;
  473. int height = m_itemHeight;
  474. m_doingNothing = false;
  475. int blocks = 0;
  476. int mx = 0;
  477. int my = 0;
  478. SNpcGridItem *i = m_grid;
  479. SNpcGridItem *i_target = i+m_gridWidth*m_gridHeight;
  480. while (i!=i_target) {
  481. // just destoy the ones that are not already destroying
  482. if (i->index!=-1 && (i->flags&flag) && (i->destroying==-1)) {
  483. // at least one of the line wasnt marked before, .. this was first found. mark for scores
  484. if (!(i->flags&GRIDFLAG_MARKED)) wasFirst = 1;
  485. mx += i->lposx;
  486. my += i->lposy;
  487. blocks++;
  488. i->flags |=GRIDFLAG_MARKED;
  489. i->destroying = 0; // start destroying.
  490. // stop dropping when destroynig?
  491. //if (i->dropping!=-1) {
  492. // i->dropping = -1;
  493. // i->posoffsety = 0;
  494. //};
  495. //i->flags &= 0xFFFFFFFF^GRIDFLAG_CALCULATION_TEMP;
  496. };
  497. i++;
  498. };
  499. if (blocks<1) return;
  500. if (wasFirst==1) {
  501. //if (1) {
  502. //int m = (3-m_destroyingRound);
  503. //if (m<1) m = 1;
  504. //int scoreAdd = 1+(((blocks-2)*(blocks-2))*10) / (m_destroyingRound+1);
  505. //blocks = 5;
  506. //int scoreAdd = (((blocks-REQUIRED_BLOCKS)+1) * (blocks));
  507. int scoreAdd = (blocks*blocks*2) / (m_destroyingRound+1); // TODO, CHANGE THIS
  508. //scoreAdd *= (m_destroyingRound+1);
  509. int sind = 0;
  510. int scoreMul = 1;
  511. switch (flag) {
  512. case GRIDFLAG_MINUS_STRAIGHT:
  513. case GRIDFLAG_PLUS_STRAIGHT:
  514. sind = 2;
  515. scoreMul = 11;
  516. break;
  517. case GRIDFLAG_SAME_EARTH:
  518. sind = 1;
  519. scoreMul = 3;
  520. break;
  521. case GRIDFLAG_SAME_NUMBER:
  522. sind = 0;
  523. scoreMul = 7;
  524. break;
  525. };
  526. if (scoreAdd<1) scoreAdd = 1;
  527. scoreAdd = (scoreAdd*scoreMul)/3; // most scores fropm straights, then from earth, then from number
  528. m_levelProgressChange += (scoreAdd);// / (m_destroyingRound+1));
  529. int x= xtoGameArea(mx/blocks+width/2);
  530. int y = ytoGameArea( my/blocks+height/2 );
  531. int dx= xtoGameArea(65536/2)-x;
  532. int dy= ytoGameArea(65536/2)-y;
  533. m_pengine->spray(1, x, y,0, dx,dy, 0, sind*256 + blocks, &m_scoreSpray );
  534. //scoreAdd = scoreAdd*(m_destroyingRound+3)/3;
  535. m_levelScore += scoreAdd;
  536. }
  537. };
  538. int CNpcLevel::tryApplyChange( SNpcGridItem *i ) {
  539. // cannot select another peace when other than in normal mode
  540. if ( m_state!=eLEVELSTATE_NORMAL ) {
  541. m_renderer->effectNotify(eILLEGAL_MOVE, 0, 0);
  542. cancelSelection(0);
  543. cancelSelection(1);
  544. return 0; // cannot continue, level is processing itself.
  545. };
  546. char allowChange = 0;
  547. if (m_difficulty==0) allowChange = 1; // for kids.
  548. if (allowChange==0) {
  549. // must be next to changing[0] to be allowed
  550. #ifdef SQUARE_BASED
  551. if ((abs( m_changing[0]->gridxpos - i->gridxpos ) +
  552. abs( m_changing[0]->gridypos - i->gridypos )) <= 1) allowChange = 1;
  553. #else
  554. int yofs = (m_changing[0]->gridxpos&1);
  555. int dx = m_changing[0]->gridxpos - i->gridxpos;
  556. int dy = m_changing[0]->gridypos - i->gridypos;
  557. if (dx==0 && abs(dy)<=1) allowChange = 1;
  558. dy += yofs;
  559. if (dx==1 || dx==-1) if (dy==0 || dy==1) allowChange = 1;
  560. #endif
  561. }
  562. if (allowChange) {
  563. m_renderer->effectNotify(eCHANGING, 0, 0);
  564. m_changing[1] = i;
  565. m_changingCounter = 65536;
  566. m_illegalMoveCounter = 0;
  567. // changing is now enabled
  568. i->flags ^= GRIDFLAG_SELECTED; // flip the first bit
  569. }
  570. else
  571. {
  572. m_renderer->effectNotify(eILLEGAL_MOVE, 0, 0);
  573. cancelSelection(0);
  574. return 0;
  575. }
  576. return 1;
  577. };
  578. void CNpcLevel::cancelSelection( int index ) {
  579. if (m_changing[index]!=0) {
  580. m_changing[index]->posoffsetx = 0;
  581. m_changing[index]->posoffsety = 0;
  582. m_changing[index]->flags &= 0xFFFFFFFF^GRIDFLAG_SELECTED;
  583. m_changing[index] = 0;
  584. }
  585. };
  586. void CNpcLevel::click( int fixedx, int fixedy, int type ) {
  587. // dont process these.
  588. if (m_state==eLEVELSTATE_BEGINNING || m_state==eLEVELSTATE_LEVELCOMPLETED || m_state==eLEVELSTATE_GAMEOVER) return;
  589. if (m_changingCounter>0) return; // we are currently changing.
  590. fixedx = ((fixedx-m_areaX)<<12)/(m_areaWidth>>4);
  591. fixedy = ((fixedy-m_areaY)<<12)/(m_areaHeight>>4);
  592. if (fixedx<0 || fixedy<0 || fixedx>65535 || fixedy>65535) return; // not inside gamelevel
  593. int gx = ((fixedx*m_gridWidth)>>16);
  594. #ifdef SQUARE_BASED
  595. int gy = ((fixedy*m_gridHeight)>>16);
  596. #else
  597. int gyoff = (65536/m_gridHeight/2) -(65536/m_gridHeight/2) * (gx&1);
  598. int gy = (((fixedy+gyoff)*m_gridHeight)>>16);
  599. #endif
  600. if (gy<0) return;
  601. SNpcGridItem *i = getGridItemAt( gx, gy );
  602. switch (type) {
  603. case 1:
  604. if (m_changing[0]!=0) {
  605. if (m_difficulty>0) {
  606. //float fx = (fixedx-m_changing[0]->lposx)-(m_areaWidth/m_gridWidth/2);
  607. //float fy = (fixedy-m_changing[0]->lposy)-(m_areaHeight/m_gridHeight/2);
  608. float fx = (fixedx-m_changing[0]->lposx)-(65536/m_gridWidth/2);
  609. float fy = (fixedy-m_changing[0]->lposy)-(65536/m_gridHeight/2);
  610. float le = sqrtf( fx*fx+fy*fy );
  611. if (le>6000.0f) {
  612. fx=fx/le*6000.0f;
  613. fy=fy/le*6000.0f;
  614. }
  615. m_changing[0]->posoffsetx = fx;
  616. m_changing[0]->posoffsety = fy;
  617. //m_changing[0]->posoffsetx = 10000;
  618. // place absolute position under the cursor
  619. //m_changing[0]->posoffsetx = (fixedx-m_changing[0]->lposx)-(65536/m_gridWidth/2);
  620. //m_changing[0]->posoffsety = (fixedy-m_changing[0]->lposy)-(65536/m_gridHeight/2);
  621. gx = m_changing[0]->lposx + m_changing[0]->posoffsetx + (65536/m_gridWidth/2);
  622. gy = m_changing[0]->lposy + m_changing[0]->posoffsety + (65536/m_gridHeight/2);
  623. gx = ((gx*m_gridWidth)>>16);
  624. #ifdef SQUARE_BASED
  625. gy = ((gy*m_gridHeight)>>16);
  626. #else
  627. int gyoff = (65536/m_gridHeight/2) -(65536/m_gridHeight/2) * (gx&1);
  628. gy = (((gy+gyoff)*m_gridHeight)>>16);
  629. if (gy<0) return;
  630. #endif
  631. i = getGridItemAt(gx,gy);
  632. } else {
  633. m_changing[0]->posoffsetx = (fixedx-m_changing[0]->lposx)-(65536/m_gridWidth/2);
  634. m_changing[0]->posoffsety = (fixedy-m_changing[0]->lposy)-(65536/m_gridHeight/2);
  635. }
  636. /*
  637. if (m_dragBegan==0) {
  638. m_changing[0]->posoffsetx = 0;
  639. m_changing[0]->posoffsety = 0;
  640. };
  641. */
  642. if (i!=m_changing[0]) {
  643. if (m_changing[1]!=i) {
  644. //if (m_changing[1]) m_changing[1]->flags ^= GRIDFLAG_SELECTED;
  645. m_changing[1] = i;
  646. //if (i) i->flags ^= GRIDFLAG_SELECTED; // flip the first bit
  647. };
  648. m_dragBegan = 1;
  649. };
  650. } else return;
  651. break;
  652. case 2:
  653. if (m_difficulty>0 && m_dragBegan && m_changing[1]) i = m_changing[1];
  654. if (m_changing[0]!=0 && m_changing[0]!=i && i->destroying==-1 && i->dropping==-1) {
  655. tryApplyChange(i);
  656. } else {
  657. if (m_dragBegan) {
  658. cancelSelection(0);
  659. cancelSelection(1);
  660. };
  661. }
  662. m_dragBegan = 0;
  663. break;
  664. case 0:
  665. m_dragBegan = 0;
  666. if (!i) return;
  667. if (i==m_changing[0]) { // was already selected and now we are cancelling it.
  668. m_renderer->effectNotify(eCLICK, 0, 0);
  669. cancelSelection(0);
  670. } else {
  671. if (i->destroying==-1 && i->dropping==-1) {
  672. if (m_changing[0]==0)
  673. {
  674. // click empty card..
  675. if (i->index == EMPTY_CARD) {
  676. m_renderer->effectNotify(eCHANGE_COMPLETED, 0, 0);
  677. while (i->index == EMPTY_CARD) i->index = randomBlock();
  678. m_levelProgressChange -= 20;
  679. m_pengine->spray(1,
  680. xtoGameArea(i->lposx + m_itemWidth/2),
  681. ytoGameArea(i->lposy+m_itemHeight/2),
  682. 200, 0, 0, 0, 0, &m_morphSpray );
  683. m_pengine->spray(20,
  684. xtoGameArea(i->lposx + m_itemWidth/2),
  685. ytoGameArea(i->lposy+m_itemHeight/2),
  686. 8000, 0, -16000, 64000, 0, &m_sparkleSpray );
  687. checkDestroyAt(i->gridxpos, i->gridypos );
  688. } else {
  689. m_renderer->effectNotify(eCLICK, 0, 0);
  690. m_changing[0] = i;
  691. i->flags ^= GRIDFLAG_SELECTED; // flip the first bit
  692. }
  693. }
  694. else {
  695. tryApplyChange( i );
  696. };
  697. }
  698. }
  699. break;
  700. }
  701. };
  702. SNpcGridItem *CNpcLevel::getGridItemAt( int blockx, int blocky ) {
  703. if (blockx<0 || blocky<0 || blockx>=m_gridWidth || blocky>=m_gridHeight) return 0;
  704. return m_grid + blocky*m_gridWidth + blockx;
  705. };
  706. void CNpcLevel::zeroMask( unsigned int maskToZero ) {
  707. for (int f=0; f<m_gridWidth*m_gridHeight; f++) {
  708. m_grid [f].flags &= (0xFFFFFFFF^maskToZero );
  709. };
  710. };
  711. void CNpcLevel::run( int fixedFrameTime16Bit ) {
  712. //fixedFrameTime16Bit/= 10;
  713. if (m_state == eLEVELSTATE_BEGINNING)
  714. m_deckVisibility += ((65536 - m_deckVisibility)*(fixedFrameTime16Bit>>4))>>10;
  715. else
  716. m_deckVisibility -= ((m_deckVisibility)*(fixedFrameTime16Bit>>4))>>10;
  717. if (m_state == eLEVELSTATE_IDLE) return;
  718. if (fixedFrameTime16Bit>8000) fixedFrameTime16Bit = 8000;
  719. int f,g;
  720. m_floatingAngle += fixedFrameTime16Bit;
  721. int width = 65536 / m_gridWidth;
  722. int height = 65536 / m_gridHeight;
  723. m_doingNothing = true;
  724. int something_destroyed = 0;
  725. int something_dropped = 0;
  726. int something_destroying = 0;
  727. int something_dropping = 0;
  728. int something_created = 0;
  729. int ind = 0;
  730. SNpcGridItem *i = m_grid;
  731. SNpcGridItem *i_target = i + m_gridWidth*m_gridHeight;
  732. while (i!=i_target) {
  733. if (ind<m_gridWidth && i->index == -1) {
  734. int safeCount = 0;
  735. do { // try a block as long as required
  736. i->index = randomBlock();
  737. safeCount++;
  738. } while (safeCount<1000 && checkDestroyAt(ind,0,0)!=0);
  739. something_created = 1;
  740. m_doingNothing = false;
  741. };
  742. if (i->destroying>=0) {
  743. something_destroying = 1;
  744. f = i->destroying;
  745. i->destroying+=((fixedFrameTime16Bit*DESTROYINGSPEED)>>8); // destroying speed
  746. if (f<=(65536+65536/2) && i->destroying>(65536+65536/2)) {
  747. /*
  748. m_pengine->spray(10, xtoGameArea(i->lposx+width/2), ytoGameArea(i->lposy+height/2),4000,
  749. 0,0, 8000, 0, &m_smokeSpray );
  750. */
  751. m_pengine->spray(10, xtoGameArea(i->lposx+width/2), ytoGameArea(i->lposy+height/2),8000,
  752. 0,-10000, 16000, 0, &m_sparkleSpray );
  753. m_pengine->spray(6+(rand()&3), xtoGameArea(i->lposx+width/2), ytoGameArea(i->lposy+height/2),6000,
  754. 0,-40000, 50000, 0, &m_fruitSpray );
  755. };
  756. if (i->destroying>=65536*2) { // destroy, finally.
  757. if (i==m_changing[0] || i==m_changing[1]) {
  758. cancelSelection(0);
  759. cancelSelection(1);
  760. m_changingCounter = 0;
  761. }
  762. i->index=-1;
  763. i->destroying = -1;
  764. i->dropping = -1;
  765. i->posoffsetx = 0;
  766. i->posoffsety = 0;
  767. i->flags = 0;
  768. i->animationCount = 0;
  769. something_destroyed = 1;
  770. };
  771. };
  772. i->animationCount += fixedFrameTime16Bit;
  773. i->animationCount&=(65536*16-1);
  774. g = ((i->wobble * fixedFrameTime16Bit)>>12); // string effect
  775. i->wobbleinc-=g;
  776. g = ((i->wobbleinc * fixedFrameTime16Bit)>>13); // slowdown
  777. i->wobbleinc -= g;
  778. g = ((i->wobbleinc * fixedFrameTime16Bit)>>13); // add
  779. i->wobble+=g;
  780. if (m_state!=eLEVELSTATE_GAMEOVER) {
  781. if (i->flags&GRIDFLAG_SELECTED) {
  782. i->genCount += (((8000-i->genCount) * fixedFrameTime16Bit) >> 14);
  783. } else {
  784. // TEST
  785. //int g = (m_cosineTable[ ((m_floatingAngle>>4) + (ind/(m_gridWidth-1)<<6))&4095 ]>>6);
  786. int g = (m_cosineTable[ ((m_floatingAngle>>4) + (ind<<10))&4095 ]>>6);
  787. i->genCount += (((g-i->genCount)*fixedFrameTime16Bit)>>13);
  788. // gameovereffect
  789. i->genCount += (((-i->genCount) * fixedFrameTime16Bit) >> 14);
  790. //i->genCount = 0;
  791. }
  792. }
  793. i++;
  794. ind++;
  795. };
  796. if (something_destroyed==1) {
  797. m_renderer->effectNotify(eEFFECT_DESTROYING, m_destroyingRound,0);
  798. m_destroyingRound++;
  799. };
  800. int count = 0;
  801. i = m_grid;
  802. i_target = i + m_gridWidth*(m_gridHeight-1);
  803. while (i!=i_target) {
  804. if (i->dropping==-1 && i->index!=-1) {
  805. /*
  806. // destroying pieces wont drop
  807. if (i->destroying==-1 && (i[m_gridWidth].index==-1 || i[m_gridWidth].dropping!=-1)) {
  808. i->dropping = 5000; // enable dropping.
  809. i->posoffsety=0;
  810. };
  811. */
  812. // destroying pieces will drop
  813. if ((i[m_gridWidth].index==-1 || i[m_gridWidth].dropping!=-1)) {
  814. i->dropping = 5000; // enable dropping.
  815. something_dropping = 1;
  816. i->posoffsety=0;
  817. };
  818. } else {
  819. something_dropping = 1;
  820. i->dropping+=fixedFrameTime16Bit*4;
  821. i->posoffsety+=((i->dropping*fixedFrameTime16Bit)>>16);
  822. if (i->posoffsety>=height) {
  823. if (i[m_gridWidth].index==-1) {
  824. //i->posoffsety = 0;
  825. i->posoffsety-=height;
  826. i[m_gridWidth].animationCount = i->animationCount;
  827. i[m_gridWidth].destroying = i->destroying;
  828. i[m_gridWidth].flags = i->flags;
  829. i[m_gridWidth].index = i->index;
  830. i[m_gridWidth].posoffsetx = i->posoffsetx;
  831. i[m_gridWidth].posoffsety = i->posoffsety;
  832. i[m_gridWidth].dropping = i->dropping;
  833. i[m_gridWidth].wobble = i->wobble;
  834. i[m_gridWidth].wobbleinc = i->wobbleinc;
  835. i->index = -1;
  836. i->dropping = -1;
  837. i->wobble = 0;
  838. i->wobbleinc = 0;
  839. }
  840. }
  841. if (i[m_gridWidth].index!=-1 && i[m_gridWidth].dropping==-1) {
  842. // stop dropping...
  843. f = count/m_gridWidth;
  844. checkDestroyAt( count-f*m_gridWidth, f, 1 );
  845. something_dropped = 1;
  846. i->dropping = -1;
  847. i->wobbleinc = 4000;
  848. i->posoffsety = 0;
  849. };
  850. };
  851. count++;
  852. i++;
  853. };
  854. // stop the last line
  855. i = m_grid + m_gridWidth*(m_gridHeight-1);
  856. i_target=i+m_gridWidth;
  857. while (i!=i_target) {
  858. if (i->dropping!=-1) {
  859. i->dropping = -1;
  860. i->posoffsety =0;
  861. };
  862. i++;
  863. };
  864. if (something_destroyed != 0 || something_dropped != 0 ||
  865. something_destroying != 0 || something_dropping != 0)
  866. m_doingNothing = false;
  867. switch (m_state) {
  868. case eLEVELSTATE_BEGINNING:
  869. {
  870. m_startupCounter -= fixedFrameTime16Bit;
  871. if (m_startupCounter<=0) {
  872. m_startupCounter = 0;
  873. setLevelState( eLEVELSTATE_NORMAL );
  874. };
  875. int amount = m_gridWidth * m_gridHeight;
  876. SNpcGridItem *i = m_grid;
  877. for (int f=0; f<m_gridWidth*m_gridHeight; f++) {
  878. int g = m_startupCounter - ((f<<16)*4/amount);
  879. if (g<0) {
  880. g = 0;
  881. if ((i->flags&GRIDFLAG_CALCULATION_TEMP) == 0) {
  882. i->flags|=GRIDFLAG_CALCULATION_TEMP;
  883. // do something when block is in place
  884. m_renderer->effectNotify( eEFFECT_BLOCK_BEGIN_FINISHED, 0,0 );
  885. };
  886. } else i->wobble = -1000;
  887. g>>=4;
  888. if (g>1024) g = 1024;
  889. //i->posoffsetx = -(65536-m_cosineTable[ ((g>>9)) & 4095 ])>>4;
  890. //i->posoffsety = -(g>>5);
  891. //i->posoffsetx = (m_areaX + m_areaWidth/2) - i->lposx;
  892. //i->posoffsety = (m_areaY + m_areaHeight/2) - i->lposy;
  893. i->posoffsetx = DECK_POSITION_X-i->lposx -m_itemWidth/2;
  894. i->posoffsety = DECK_POSITION_Y-i->lposy - m_itemHeight/2;
  895. i->posoffsetx = (i->posoffsetx * g)>>10;
  896. i->posoffsety = (i->posoffsety * g)>>10;
  897. i->genCount = g*48;
  898. i++;
  899. };
  900. }
  901. break;
  902. case eLEVELSTATE_LEVELCOMPLETED:
  903. {
  904. m_startupCounter -= fixedFrameTime16Bit;
  905. if (m_startupCounter<=0) {
  906. m_startupCounter = 0;
  907. setLevelState( eLEVELSTATE_IDLE );
  908. };
  909. int amount = m_gridWidth * m_gridHeight;
  910. SNpcGridItem *i = m_grid;
  911. for (int f=0; f<m_gridWidth*m_gridHeight; f++) {
  912. int g = ((f<<16)*4/amount) - m_startupCounter;
  913. g>>=4;
  914. if (g>1024) g = 1024;
  915. if (g<=0)
  916. g = 0;
  917. else {
  918. if ((i->flags&GRIDFLAG_CALCULATION_TEMP) == 0) {
  919. i->flags|=GRIDFLAG_CALCULATION_TEMP;
  920. // do something when block is taken from its place
  921. //if (((f)) == 0)
  922. m_renderer->effectNotify( eEFFECT_BLOCK_VANISH_STARTED, 0,0 );
  923. };
  924. }
  925. //i->posoffsetx = -(65536-m_cosineTable[ ((g>>9)) & 4095 ])>>4;
  926. //i->posoffsety = -(g>>5);
  927. //i->posoffsetx = (m_areaX + m_areaWidth/2) - i->lposx;
  928. //i->posoffsety = (m_areaY + m_areaHeight/2) - i->lposy;
  929. //i->posoffsetx = DECK_POSITION_X-i->lposx -m_itemWidth/2;
  930. //i->posoffsety = DECK_POSITION_Y-i->lposy - m_itemHeight/2;
  931. i->posoffsetx = ((65536-i->lposx + m_itemWidth) * g)>>10;
  932. i->posoffsety = ((65536-i->lposy + m_itemHeight) * g)>>10;
  933. i->genCount = g*48;
  934. i++;
  935. };
  936. break;
  937. }
  938. case eLEVELSTATE_GAMEOVER:
  939. {
  940. int jj = ((m_gridWidth*m_gridHeight)<<16) - m_startupCounter/2;
  941. if (jj<65536) jj=65536;
  942. jj = (__int64)(( jj * (__int64)fixedFrameTime16Bit ) >>16 );
  943. m_startupCounter -= jj;
  944. if (m_startupCounter<=-65536*32) {
  945. m_startupCounter=-65536*32;
  946. setLevelState( eLEVELSTATE_IDLE );
  947. //setLevelState( eLEVELSTATE_NORMAL );
  948. // wait and do nothing... until the game changes levelstate to something else.
  949. };
  950. SNpcGridItem *i = m_grid;
  951. for (int f=0; f<m_gridWidth*m_gridHeight; f++) {
  952. int g = (f<<16)-m_startupCounter;
  953. if (g<0) g = 0;
  954. if (g>65536*28) g = 65536*28;
  955. i->genCount=-(g>>5);
  956. //
  957. //i->posoffsetx = +(g>>5);
  958. //i->posoffsety = +(g>>5);
  959. i++;
  960. };
  961. }
  962. break;
  963. case eLEVELSTATE_NORMAL:
  964. {
  965. if (something_created)
  966. checkDestroyWholeLevel();
  967. // check if the level have moves left and update the hint
  968. if (something_destroyed || something_dropped || something_created) {
  969. m_hint1 = 0;
  970. m_hint2 = 0;
  971. if (something_destroying==0 && something_dropping==0) {
  972. if (hasMovesLeft()) {
  973. } else {
  974. // NO MOVES LEFT!!
  975. // give scores
  976. m_pengine->spray(1, xtoGameArea(65536/2),
  977. ytoGameArea( 65536/4 ),
  978. 0, 0, 8000, 0, (50<<16), &m_scoreSpray );
  979. m_levelScore += 800;
  980. m_levelProgressChange += 40;
  981. // destroy randomly?
  982. int dcount = m_gridHeight;
  983. int safeCount = 0;
  984. while (dcount>0 && safeCount<2000) {
  985. SNpcGridItem *i = getGridItemAt( (rand()&255)*m_gridWidth/256, (rand()&255)*m_gridHeight/256 );
  986. if (i->index!=-1 && ((i->flags&GRIDFLAG_MARKED) == 0) && i!=m_changing[0] && i!=m_changing[1]) {
  987. i->flags |= GRIDFLAG_MARKED;
  988. dcount--;
  989. };
  990. safeCount++;
  991. }
  992. applyDestroy(GRIDFLAG_MARKED);
  993. };
  994. }
  995. };
  996. // combo
  997. if (m_destroyingRound>3 && m_doingNothing) {
  998. //m_pengine->spray(10, xtoGameArea(65536/2), ytoGameArea( 65536/2 ), 2000,0,0, 8000, 0, &m_destroySpray );
  999. m_pengine->spray(1, xtoGameArea(65536/2),
  1000. ytoGameArea( 65536/2 ),
  1001. 0, 0, 8000, 0, ((m_destroyingRound-1)<<16), &m_scoreSpray );
  1002. m_renderer->effectNotify( eEFFECT_XBONUS, 0,0 );
  1003. m_levelProgressChange += m_destroyingRound*3;
  1004. m_levelScore += (m_destroyingRound*30);
  1005. m_destroyingRound = 0;
  1006. }
  1007. if (m_changingCounter>0) {
  1008. m_changingCounter -= fixedFrameTime16Bit*6; // CHANGE THIS, WAS 6
  1009. // do the change with m_changing[0] and [1]
  1010. if (m_changingCounter<=0) {
  1011. int temp = m_changing[0]->index;
  1012. m_changing[0]->index = m_changing[1]->index;
  1013. m_changing[1]->index = temp;
  1014. // reset the destroying rounds.
  1015. m_destroyingRound = 0;
  1016. int allow_move = 0;
  1017. // check destroy.
  1018. if (checkDestroyAt( m_changing[0]->gridxpos, m_changing[0]->gridypos )!=0) allow_move = 1;
  1019. if (checkDestroyAt( m_changing[1]->gridxpos, m_changing[1]->gridypos )!=0) allow_move = 1;
  1020. #ifdef ALLOW_VOID_MOVES
  1021. if (allow_move == 0) {
  1022. allow_move = 1; // subtract some scores
  1023. m_levelProgressChange -= 15;
  1024. }
  1025. #endif
  1026. if (allow_move!=0) {
  1027. m_renderer->effectNotify( eCHANGE_COMPLETED, 0 ,0 );
  1028. m_changingCounter = 0;
  1029. } else {
  1030. // ILLEGAL MOVE
  1031. // was a bad move .. change back
  1032. if (m_illegalMoveCounter == 0) {
  1033. m_changingCounter = 65536;
  1034. m_illegalMoveCounter++;
  1035. m_renderer->effectNotify( eILLEGAL_MOVE, 0, 0);
  1036. } else {
  1037. // this was a "backwards" move.
  1038. m_changingCounter = 0; // stay still.
  1039. };
  1040. };
  1041. if (m_changingCounter==0) {
  1042. m_changing[0]->flags &= 0xFFFFFFFF^GRIDFLAG_SELECTED;
  1043. m_changing[1]->flags &= 0xFFFFFFFF^GRIDFLAG_SELECTED;
  1044. m_changing[0]->posoffsetx = 0;
  1045. m_changing[0]->posoffsety = 0;
  1046. m_changing[1]->posoffsetx = 0;
  1047. m_changing[1]->posoffsety = 0;
  1048. m_changing[0] = 0;
  1049. m_changing[1] = 0;
  1050. }
  1051. } else {
  1052. int dx,dy;
  1053. if (m_changing[0] && m_changing[1]) {
  1054. dx = (m_changing[1]->lposx - m_changing[0]->lposx);
  1055. dy = (m_changing[1]->lposy - m_changing[0]->lposy);
  1056. int i = 65536-m_changingCounter;
  1057. dx = ((dx*(i>>4))>>12);
  1058. dy = ((dy*(i>>4))>>12);
  1059. i >>=6;
  1060. i&=4095;
  1061. int ndx = (((dy) * (m_cosineTable[i]>>2)) >> 14);
  1062. int ndy = (((-dx) * (m_cosineTable[i]>>2)) >> 14);
  1063. m_changing[0]->posoffsetx = dx+ndx*3/2;
  1064. m_changing[0]->posoffsety = dy+ndy;
  1065. m_changing[1]->posoffsetx = -dx-ndx*3/2;
  1066. m_changing[1]->posoffsety = -dy-ndy;
  1067. } else {
  1068. cancelSelection(0);
  1069. cancelSelection(1);
  1070. m_changingCounter = 0;
  1071. }
  1072. };
  1073. break; // dont continue.
  1074. };
  1075. }
  1076. break;
  1077. };
  1078. };
  1079. int CNpcLevel::xtoGameArea( const int sourcex ) {
  1080. return m_areaX + ((sourcex*(m_areaWidth>>6))>>10);
  1081. };
  1082. int CNpcLevel::ytoGameArea( const int sourcey ) {
  1083. return m_areaY + ((sourcey*(m_areaHeight>>6))>>10);
  1084. };
  1085. const char num_letters[]={28,29,30,31,32,33,34,35,26,9,16,10,0 };
  1086. void CNpcLevel::renderTileCaller( SNpcGridItem *i, ITileRenderer &renderer ) {
  1087. // change size from i's gencount
  1088. int sizeAdd = TILE_SIZE_ADD + (i->genCount>>2);
  1089. int fade = 0;
  1090. int width = m_itemWidth;
  1091. int height = m_itemHeight;
  1092. int tex = TexPieces;
  1093. int earth_index =i->index/13;
  1094. int num_index = i->index - earth_index*13;
  1095. num_index++;
  1096. if (num_index>12) {
  1097. num_index = 0;
  1098. }
  1099. if (i->index == JOKER_CARD) {
  1100. earth_index = rand() & 3;
  1101. num_index = 6+ (rand()&7);
  1102. };
  1103. if (i->destroying!=-1) {
  1104. tex = TexPiecesSelected;
  1105. //sizeAdd -= i->destroying/8;
  1106. };
  1107. if (i->flags&GRIDFLAG_MARKED) { // marked
  1108. tex = TexPiecesSelected;
  1109. };
  1110. if (i->flags&GRIDFLAG_SELECTED) {
  1111. tex = TexPiecesSelected;
  1112. };
  1113. //int wadd = (((sizeAdd>>2)* (256*m_itemWidth/m_itemHeight)) >>8); // aspect here
  1114. int wadd = ((sizeAdd*5)>>3) + m_itemWidth / 2;
  1115. int hadd = (sizeAdd>>2);
  1116. int rx = i->lposx + i->posoffsetx - (wadd>>1);
  1117. //int ry = i->lposy + i->posoffsety - hadd; //- (hadd>>1); // align to bottom
  1118. int ry = i->lposy + i->posoffsety - (hadd>>1); //- (hadd>>1); // align to bottom
  1119. ry+=i->wobble;
  1120. width += wadd;
  1121. height += hadd;
  1122. if (width<=0 || height<=0) return;
  1123. // convert
  1124. if (m_state == eLEVELSTATE_GAMEOVER) {
  1125. fade = -i->genCount / 200;
  1126. };
  1127. if (fade<0) fade = 0;
  1128. if (fade>255) fade = 255;
  1129. int rx2 = xtoGameArea( rx+width );
  1130. int ry2 = ytoGameArea( ry+height );
  1131. rx = xtoGameArea( rx );
  1132. ry = ytoGameArea( ry );
  1133. width = rx2-rx;
  1134. height = ry2-ry;
  1135. if (i->destroying!=-1) {
  1136. fade = ((i->destroying>>1)-65536*4/5);
  1137. if (fade<0) fade = 0; else fade*=10;
  1138. };
  1139. if (fade<255) {
  1140. if (i->index != EMPTY_CARD) {
  1141. // base
  1142. renderer.renderTile(
  1143. rx,
  1144. ry,
  1145. width,
  1146. height,
  1147. 0,0,
  1148. 1 | (tex<<16) | (fade<<24), 0 );
  1149. // "earth"
  1150. renderer.renderTile(
  1151. rx+(width>>2),
  1152. ry+(height>>4),
  1153. (width*4)>>3,
  1154. height>>1,
  1155. 0,0,
  1156. (earth_index+2) | (tex<<16) | (fade<<24), 0 );
  1157. if (num_index==13) num_index = 0;
  1158. //num
  1159. renderer.renderTile(
  1160. rx+(width>>2),
  1161. ry+(height>>1),
  1162. (width*4)>>3,
  1163. (height>>1),
  1164. 0,0,
  1165. (num_index+6) | (tex<<16) | (fade<<24), 0 );
  1166. } else {
  1167. // empty card
  1168. renderer.renderTile(
  1169. rx,
  1170. ry,
  1171. width,
  1172. height,
  1173. 0,0,
  1174. 0 | (tex<<16) | (fade<<24), 0 );
  1175. };
  1176. /*
  1177. if (i->backVisibility>0) {
  1178. renderer.renderTile(
  1179. rx,
  1180. ry,
  1181. width,
  1182. height,
  1183. 0,0,
  1184. 0 | (tex<<16) | ((i->backVisibility>>8)<<24), 0 );
  1185. };
  1186. */
  1187. }
  1188. // draw flare
  1189. if (i->destroying!=-1) {
  1190. //fade = 255-(((i->destroying>>8) * (i->destroying>>8))>>10);
  1191. fade = 255-(i->destroying>>9)*5/4;
  1192. if (fade<0) fade=-fade*5;
  1193. if (fade<0) fade = 0;
  1194. int size = 4000 + (((i->destroying>>8) * (i->destroying>>8))>>4);
  1195. //int size = 40000 + (255-fade)*20;
  1196. if (fade<255)
  1197. renderer.renderTile(
  1198. rx-size,
  1199. ry-size,
  1200. width+size*2,
  1201. height+size*2,
  1202. i->animationCount>>4,1,2 | (TexParticle<<16) | (fade<<24), 0 );
  1203. }
  1204. }
  1205. void CNpcLevel::draw (ITileRenderer &renderer ) {
  1206. if (m_state == eLEVELSTATE_IDLE) return;
  1207. SNpcGridItem *i = m_grid;
  1208. SNpcGridItem *i_target = i+m_gridWidth * m_gridHeight;
  1209. // first draw.
  1210. while (i!=i_target) {
  1211. if (i->index!=0xFFFFFFFF && //i->index!=8 &&
  1212. !(i->flags&GRIDFLAG_HIDDEN) &&
  1213. !(i->flags&GRIDFLAG_SELECTED) &&
  1214. !(i->flags&GRIDFLAG_MARKED) &&
  1215. (i->genCount<1000)) {
  1216. renderTileCaller( i, renderer );
  1217. }
  1218. i++;
  1219. };
  1220. // second draw.
  1221. i = m_grid;
  1222. while (i!=i_target) {
  1223. if (i->index!=0xFFFFFFFF &&
  1224. !(i->flags&GRIDFLAG_HIDDEN)) {
  1225. if (i->flags&(GRIDFLAG_SELECTED|GRIDFLAG_MARKED) || i->genCount>=1000) {
  1226. renderTileCaller(i, renderer );
  1227. };
  1228. }
  1229. i++;
  1230. };
  1231. if (m_deckVisibility>1024) {
  1232. // deck draw
  1233. for (int f=0; f<3; f++) {
  1234. int ysize = m_itemHeight*3;
  1235. int xsize = m_itemWidth*3;
  1236. int amount = 256;
  1237. //if (m_startupCounter<65536*4) amount = 0;
  1238. int a = (m_startupCounter>>4) + (f*650);
  1239. renderer.renderTile( DECK_POSITION_X -xsize/2 + ((((((m_cosineTable[ a& 4095 ]>>6)*(m_cosineTable[ (a*2+1500)&4095]>>8))>>8))*amount)>>8),
  1240. DECK_POSITION_Y -ysize/2 + (((m_cosineTable[ (a+1200)& 4095 ]>>6)*amount)>>8),
  1241. xsize,
  1242. ysize,
  1243. 0, 0, 0|(TexPieces<<16) | ((255-(m_deckVisibility>>8))<<24), 0 );
  1244. };
  1245. };
  1246. };
  1247. void CNpcLevel::saveToFile( FILE *file ) {
  1248. SNpcGridItem *i = m_grid;
  1249. SNpcGridItem *i_target = m_grid + m_gridWidth * m_gridHeight;
  1250. while (i!=i_target) {
  1251. fwrite( &i->index, sizeof(int), 1, file );
  1252. i++;
  1253. };
  1254. };
  1255. void CNpcLevel::loadFromFile( FILE *file ) {
  1256. createLevel(0); // just create something so flags etc are ok
  1257. SNpcGridItem *i = m_grid;
  1258. SNpcGridItem *i_target = m_grid + m_gridWidth * m_gridHeight;
  1259. while (i!=i_target) {
  1260. fread( &i->index, sizeof(int), 1, file );
  1261. i->posoffsetx = 0;
  1262. i->posoffsety = 0;
  1263. i++;
  1264. };
  1265. if (checkDestroyWholeLevel()!=0) {
  1266. }
  1267. hasMovesLeft(); // update hint
  1268. m_destroyingRound = 0;
  1269. };