/mona/src/muzz/muzzWorld.cpp

# · C++ · 4145 lines · 3534 code · 367 blank · 244 comment · 731 complexity · 3454fa1b80c6c635759610d79a53c870 MD5 · raw file

Large files are truncated click here to view the full file

  1. // For conditions of distribution and use, see copyright notice in muzz.hpp
  2. /*
  3. *
  4. * The Muzz World.
  5. *
  6. * Muzz creatures interact with a block world.
  7. * Each muzz has a mona neural network for a brain.
  8. *
  9. */
  10. #ifdef WIN32
  11. #include <windows.h>
  12. #include <io.h>
  13. #endif
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <assert.h>
  17. #include "../gui/TimeUtils.h"
  18. #include "../gui/EasyGL.h"
  19. #include "muzzWorld.hpp"
  20. // Version.
  21. const char *MuzzWorldVersion = MUZZ_WORLD_VERSION;
  22. // Print version.
  23. void
  24. printVersion(FILE *out)
  25. {
  26. fprintf(out, "%s\n", &MuzzWorldVersion[4]);
  27. }
  28. #ifndef MUZZ_WORLD_DRIVER
  29. char *Usage[] =
  30. {
  31. (char *)"Usage: muzz_world\n",
  32. (char *)" [-cycles <number of cycles>]\n",
  33. (char *)" [-initHunger (initial hunger)]\n",
  34. (char *)" [-initThirst (initial thirst)]\n",
  35. (char *)" [-numMuzzes <number of muzzes>]\n",
  36. (char *)" [-numMushrooms <number of mushrooms>]\n",
  37. (char *)" [-numPools <number of pools>]\n",
  38. (char *)" [-load <load file name>]\n",
  39. (char *)" [-save <save file name>]\n",
  40. (char *)" [-randomSeed <random seed>]\n",
  41. (char *)" [-objectSeed <object placement seed>]\n",
  42. (char *)" [-TmazeTerrain (create T-maze terrain)]\n",
  43. (char *)" [-terrainSeed <terrain generation seed>]\n",
  44. (char *)" [-terrainDimension <terrain size = dimension x dimension> (minimum=2)]\n",
  45. (char *)" [-noGraphics (turn off graphics)]\n",
  46. (char *)" [-pause (graphics only)]\n",
  47. (char *)" [-numTrainingTrials <number of training trials>]\n",
  48. (char *)" (Pauses when training trials are completed)\n",
  49. (char *)" [-forcedResponseTrain (train correct responses by forcibly overriding them)]\n",
  50. #ifdef WIN32
  51. (char *)" [-attachConsole (attach to console)]\n",
  52. #endif
  53. (char *)" [-version (print version)]\n",
  54. NULL
  55. };
  56. void printUsage()
  57. {
  58. for (int i = 0; Usage[i] != NULL; i++)
  59. {
  60. fprintf(stderr, (char *)"%s", Usage[i]);
  61. }
  62. }
  63. #endif
  64. // Run cycles.
  65. int Cycles = -1;
  66. int CycleCounter = 0;
  67. // Show graphics.
  68. bool Graphics = true;
  69. // Smooth movements.
  70. bool SmoothMove = true;
  71. // Random numbers.
  72. RANDOM RandomSeed = INVALID_RANDOM;
  73. Random *Randomizer = NULL;
  74. RANDOM ObjectSeed = INVALID_RANDOM;
  75. RANDOM TerrainSeed = INVALID_RANDOM;
  76. // Files.
  77. char *SaveFile = NULL;
  78. char *LoadFile = NULL;
  79. // Graphics window dimensions.
  80. #define WINDOW_WIDTH 850
  81. #define WINDOW_HEIGHT 690
  82. int WindowWidth = WINDOW_WIDTH;
  83. int WindowHeight = WINDOW_HEIGHT;
  84. int GUIheight = WINDOW_HEIGHT / 8;
  85. int MainWindow;
  86. // Viewports.
  87. #define TERRAIN_VIEWPORT 0
  88. #define MUZZ_VIEWPORT 1
  89. #define CONTROLS_VIEWPORT 2
  90. #define MUZZ_STATUS_VIEWPORT 3
  91. #define TERRAIN_HELP_VIEWPORT 4
  92. #define MUZZ_HELP_VIEWPORT 5
  93. #define NUM_VIEWPORTS 6
  94. typedef enum
  95. {
  96. MUZZ_VIEW_ONLY = 0, TERRAIN_VIEW_ONLY = 1, VIEW_BOTH = 2
  97. }
  98. VIEW_SELECTION;
  99. VIEW_SELECTION ViewSelection = VIEW_BOTH;
  100. VIEW_SELECTION PendingViewSelection = (VIEW_SELECTION)(-1);
  101. struct ViewportDimension
  102. {
  103. GLint x, y;
  104. GLint width, height;
  105. GLfloat aspect;
  106. }
  107. Viewports[NUM_VIEWPORTS];
  108. // Picking.
  109. #define BUFSIZE 1024
  110. GLuint selectBuf[BUFSIZE];
  111. GLint pickHits;
  112. GLenum renderMode = GL_RENDER;
  113. int cursorX, cursorY;
  114. void startPicking();
  115. void processHits(GLint hits, GLuint buffer[], int sw);
  116. void stopPicking();
  117. // Muzzes.
  118. int NUM_MUZZES = DEFAULT_NUM_MUZZES;
  119. vector<Muzz *> Muzzes;
  120. // Muzz states.
  121. #define MUZZ_FRUSTUM_ANGLE 60.0f
  122. #define MUZZ_FRUSTUM_NEAR 0.01f
  123. #define MUZZ_FRUSTUM_FAR 10.0f
  124. #define MUZZ_TURN_DELTA 5.0f
  125. #define MUZZ_MOVEMENT_DELTA 0.002f
  126. int CurrentMuzz;
  127. struct MuzzState
  128. {
  129. int sensors[Muzz::NUM_SENSORS];
  130. int response;
  131. int x, z;
  132. int dir;
  133. BlockTerrain::Block::DIRECTION forward;
  134. BlockTerrain::Block::DIRECTION backward;
  135. int lookAtX, lookAtZ;
  136. int moveType;
  137. GLfloat moveAmount;
  138. };
  139. vector<struct MuzzState> MuzzStates;
  140. // Move a muzz.
  141. bool moveMuzz(int muzzIndex);
  142. // Sense muzz world.
  143. void senseMuzz(int muzzIndex);
  144. void senseMuzzDir(int muzzIndex, int direction, GLfloat view[3],
  145. int &senseX, int &senseZ, int &terrain, int &object);
  146. // Run a muzz.
  147. #define INVALID_RESPONSE (-100)
  148. void runMuzz(int muzzIndex, int forcedResponse = INVALID_RESPONSE);
  149. // Place muzz in world without changing initial placement.
  150. void placeMuzz(int muzzIndex, int placeX, int placeY,
  151. BlockTerrain::Block::DIRECTION placeDir);
  152. // Terrain.
  153. // See blockTerrain.hpp for terrain generation parameters.
  154. typedef enum
  155. {
  156. STANDARD_TERRAIN = 0, TMAZE_TERRAIN = 1
  157. }
  158. TERRAIN_TYPE;
  159. TERRAIN_TYPE TerrainType = STANDARD_TERRAIN;
  160. int TerrainDimension = DEFAULT_TERRAIN_DIMENSION;
  161. BlockTerrain *Terrain = NULL;
  162. TmazeTerrain *MazeTerrain = NULL;
  163. // Terrain view/movement.
  164. #define TERRAIN_FRUSTUM_ANGLE 60.0f
  165. #define TERRAIN_FRUSTUM_NEAR 0.01f
  166. #define TERRAIN_FRUSTUM_FAR 10.0f
  167. #define TERRAIN_MOVEMENT_DELTA 0.01f
  168. #define TERRAIN_INITIAL_VIEW_HEIGHT 0.5f
  169. GLfloat TerrainViewPosition[3];
  170. // Mushrooms.
  171. int NUM_MUSHROOMS = DEFAULT_NUM_MUSHROOMS;
  172. vector<Mushroom *> Mushrooms;
  173. GLfloat MushroomColor[3] = { 1.0f, 1.0f, 0.0f };
  174. // Water pools.
  175. int NUM_POOLS = DEFAULT_NUM_POOLS;
  176. vector<Pool *> Pools;
  177. GLfloat PoolColor[3] = { 0.0f, 0.0f, 1.0f };
  178. // Training.
  179. int NumTrainingTrials = -1;
  180. int CurrentTrial = 0;
  181. int CurrentTrialStep = 0;
  182. int TrialResetDelay = -1;
  183. int TrainingTrialResume = -1;
  184. // Return runMuzzWorld when all muzzes have gotten food and water.
  185. bool RunMuzzWorldUntilGoalsGotten = false;
  186. // Forced response training.
  187. bool ForcedResponseTrain = false;
  188. vector<struct SensoryResponse> ForcedResponseSequence;
  189. enum
  190. {
  191. INIT_INDEX=(-1), ERROR_INDEX=(-2)
  192. };
  193. int ResponseIdx = INIT_INDEX;
  194. // Get response sequence to obtain food and water.
  195. struct SensoryResponse
  196. {
  197. vector<int> sensors;
  198. int response;
  199. int x, y, dir;
  200. };
  201. typedef enum
  202. {
  203. BREADTH_SEARCH = 0, DEPTH_SEARCH = 1
  204. }
  205. SEARCH_TYPE;
  206. bool getResponseSequenceToGoals(int muzzIndex,
  207. vector<struct SensoryResponse> &responseSequence,
  208. SEARCH_TYPE, int maxSearchDepth = (-1));
  209. // Camera.
  210. Camera camera;
  211. // Frame rate management.
  212. #define TARGET_FRAME_RATE 100.0f
  213. FrameRate frameRate(TARGET_FRAME_RATE);
  214. /*
  215. * Available fonts:
  216. * GLUT_BITMAP_8_BY_13
  217. * GLUT_BITMAP_9_BY_15
  218. * GLUT_BITMAP_TIMES_ROMAN_10
  219. * GLUT_BITMAP_TIMES_ROMAN_24
  220. * GLUT_BITMAP_HELVETICA_10
  221. * GLUT_BITMAP_HELVETICA_12
  222. * GLUT_BITMAP_HELVETICA_18
  223. */
  224. #define FONT GLUT_BITMAP_9_BY_15
  225. #define LINE_SPACE 15
  226. // Modes.
  227. typedef enum
  228. {
  229. MANUAL_MODE = 0, TERRAIN_MODE = 1, HELP_MODE = 2
  230. }
  231. MODE;
  232. MODE Mode = TERRAIN_MODE;
  233. bool TerrainMode = true;
  234. bool WireView = false;
  235. bool Pause = false;
  236. bool Step = false;
  237. int ManualResponse = INVALID_RESPONSE;
  238. // 2D functions.
  239. void helpInfo(int viewport), drawPartitions();
  240. void enter2Dmode(), exit2Dmode();
  241. void draw2Dstring(GLfloat x, GLfloat y, void *font, char *string);
  242. void enter2DMode(int width, int height), exit2DMode();
  243. // Save muzz world to file.
  244. bool saveMuzzWorld(char *saveFile);
  245. // Muzz control help.
  246. char *MuzzControlHelp[] =
  247. {
  248. (char *)"Checks:",
  249. (char *)" Manual : \"Drive\" selected muzz",
  250. (char *)" Pause : Pause world",
  251. (char *)"",
  252. (char *)"Buttons:",
  253. (char *)" Reset : Reset world to initial state",
  254. (char *)" Step : Single-step world",
  255. (char *)" Help : Show help",
  256. (char *)" Quit : Terminate",
  257. (char *)"",
  258. (char *)"Keys:",
  259. (char *)" Up arrow : Move forward",
  260. (char *)" Left arrow : Turn left",
  261. (char *)" Right arrow : Turn right",
  262. (char *)" e : Eat",
  263. (char *)" d : Drink",
  264. (char *)" p : Print selected muzz brain",
  265. (char *)" s : Save world to file",
  266. (char *)" \"muzz.world\"",
  267. (char *)" f : Full screen",
  268. NULL
  269. };
  270. // Terrain view control help.
  271. char *TerrainViewControlHelp[] =
  272. {
  273. (char *)" Up arrow : Scroll camera up",
  274. (char *)" Down arrow : Scroll camera down",
  275. (char *)" Left arrow : Scroll camera left",
  276. (char *)" Right arrow : Scroll camera right",
  277. (char *)" PgUp arrow : Zoom camera out",
  278. (char *)"PgDown arrow : Zoom camera in",
  279. (char *)" Left mouse : Select/deselect muzz",
  280. (char *)" and select view pane",
  281. NULL
  282. };
  283. // GUI components.
  284. class EventsHandler : public GUIEventListener
  285. {
  286. public:
  287. virtual void actionPerformed(GUIEvent& evt);
  288. };
  289. EventsHandler handler;
  290. FPSCounter counter;
  291. GUICheckBox *manualCheck;
  292. GUICheckBox *pauseCheck;
  293. GUIFrame *guiFrame = NULL;
  294. // Annotate graph?
  295. bool AnnotateGraph = true;
  296. // Run muzzes.
  297. void runMuzzes()
  298. {
  299. int i;
  300. bool moveDone, gotGoals, foundGoals;
  301. // Complete movements for previous responses before proceeding.
  302. moveDone = true;
  303. for (i = 0; i < NUM_MUZZES; i++)
  304. {
  305. if (!moveMuzz(i))
  306. {
  307. moveDone = false;
  308. }
  309. }
  310. if (!moveDone)
  311. {
  312. return;
  313. }
  314. // Determine sensory input for muzzes.
  315. for (i = 0; i < NUM_MUZZES; i++)
  316. {
  317. senseMuzz(i);
  318. }
  319. // Manual mode?
  320. if (Mode == MANUAL_MODE)
  321. {
  322. // Only current muzz can run.
  323. if (CurrentMuzz != -1)
  324. {
  325. // Manual response provided?
  326. if (ManualResponse != INVALID_RESPONSE)
  327. {
  328. // Override muzz with manual response.
  329. Muzzes[CurrentMuzz]->brain->responseOverride = ManualResponse;
  330. runMuzz(CurrentMuzz);
  331. Muzzes[CurrentMuzz]->brain->responseOverride = Mona::NULL_RESPONSE;
  332. // Wait for next manual response.
  333. ManualResponse = INVALID_RESPONSE;
  334. }
  335. // Reset training when leaving manual mode.
  336. if (CurrentTrial < NumTrainingTrials)
  337. {
  338. TrainingTrialResume = CurrentTrial;
  339. }
  340. }
  341. return;
  342. }
  343. // Resume training?
  344. if (TrainingTrialResume != -1)
  345. {
  346. i = TrainingTrialResume;
  347. resetTraining();
  348. resetMuzzWorld();
  349. CurrentTrial = i;
  350. TrainingTrialResume = -1;
  351. if (CurrentTrial > NumTrainingTrials)
  352. {
  353. CurrentTrial = NumTrainingTrials;
  354. }
  355. }
  356. // One-time search for forced response training? Much faster.
  357. if (ForcedResponseTrain && (ResponseIdx == INIT_INDEX) &&
  358. (CurrentTrial < NumTrainingTrials))
  359. {
  360. if (getResponseSequenceToGoals(0, ForcedResponseSequence, DEPTH_SEARCH))
  361. {
  362. ResponseIdx = 0;
  363. }
  364. else
  365. {
  366. ResponseIdx = ERROR_INDEX;
  367. }
  368. }
  369. // Muzzes already have goals?
  370. gotGoals = true;
  371. for (i = 0; i < NUM_MUZZES; i++)
  372. {
  373. if (!Muzzes[i]->gotFood || !Muzzes[i]->gotWater)
  374. {
  375. gotGoals = false;
  376. }
  377. }
  378. // Run the muzzes.
  379. if (gotGoals)
  380. {
  381. foundGoals = false;
  382. }
  383. else
  384. {
  385. foundGoals = true;
  386. }
  387. gotGoals = true;
  388. for (i = 0; i < NUM_MUZZES; i++)
  389. {
  390. // For forced response training, get response to obtain food and water.
  391. if (ForcedResponseTrain && (CurrentTrial < NumTrainingTrials))
  392. {
  393. if ((ResponseIdx >= 0) && (ResponseIdx <
  394. (int)ForcedResponseSequence.size()))
  395. {
  396. Muzzes[i]->brain->responseOverride =
  397. ForcedResponseSequence[ResponseIdx].response;
  398. ResponseIdx++;
  399. }
  400. else
  401. {
  402. Muzzes[i]->brain->responseOverride = Mona::NULL_RESPONSE;
  403. }
  404. }
  405. // Run the muzz.
  406. runMuzz(i);
  407. // Goals not gotten?
  408. if (!Muzzes[i]->gotFood || !Muzzes[i]->gotWater)
  409. {
  410. gotGoals = foundGoals = false;
  411. }
  412. }
  413. // Increment training trial.
  414. if (CurrentTrial < NumTrainingTrials)
  415. {
  416. // Increment trial step.
  417. CurrentTrialStep++;
  418. // Trial complete?
  419. if (gotGoals)
  420. {
  421. if (TrialResetDelay == -1)
  422. {
  423. TrialResetDelay = 1;
  424. }
  425. else
  426. {
  427. TrialResetDelay--;
  428. }
  429. }
  430. if (TrialResetDelay == 0)
  431. {
  432. // Reset for next trial.
  433. TrialResetDelay = -1;
  434. CurrentTrial++;
  435. CurrentTrialStep = 0;
  436. if (ForcedResponseTrain && (ResponseIdx >= 0))
  437. {
  438. ResponseIdx = 0;
  439. }
  440. resetMuzzWorld();
  441. }
  442. }
  443. }
  444. // Idle muzzes.
  445. void idleMuzzes()
  446. {
  447. // Complete movements for previous responses.
  448. for (int i = 0; i < NUM_MUZZES; i++)
  449. {
  450. moveMuzz(i);
  451. }
  452. }
  453. // Reset muzz world.
  454. void resetMuzzWorld()
  455. {
  456. int i;
  457. for (i = 0; i < NUM_MUZZES; i++)
  458. {
  459. Muzzes[i]->brain->responseOverride = Mona::NULL_RESPONSE;
  460. Muzzes[i]->reset();
  461. if (NUM_MUSHROOMS == 0)
  462. {
  463. Muzzes[i]->clearNeed(Muzz::FOOD);
  464. }
  465. if (NUM_POOLS == 0)
  466. {
  467. Muzzes[i]->clearNeed(Muzz::WATER);
  468. }
  469. MuzzStates[i].response = Muzz::WAIT;
  470. MuzzStates[i].moveType = Muzz::FORWARD;
  471. MuzzStates[i].moveAmount = 0.0f;
  472. }
  473. for (i = 0; i < NUM_MUSHROOMS; i++)
  474. {
  475. Mushrooms[i]->setAlive(true);
  476. }
  477. }
  478. // Move muzz.
  479. // Returns true when movement is complete.
  480. bool moveMuzz(int i)
  481. {
  482. int j, x, z, x2, z2, x3, z3;
  483. GLfloat a, p[3], p2[3], f[3], u[3];
  484. bool move;
  485. // Continue queued movement.
  486. if (MuzzStates[i].moveAmount > 0.0)
  487. {
  488. move = true;
  489. }
  490. else
  491. {
  492. move = false;
  493. }
  494. Muzzes[i]->getPosition(p);
  495. x = (int)(p[0] / Terrain->BLOCK_SIZE);
  496. z = (int)(p[2] / Terrain->BLOCK_SIZE);
  497. if (move)
  498. {
  499. switch (MuzzStates[i].moveType)
  500. {
  501. case Muzz::FORWARD:
  502. if (SmoothMove)
  503. {
  504. a = MUZZ_MOVEMENT_DELTA * frameRate.speedFactor;
  505. if (a > MuzzStates[i].moveAmount)
  506. {
  507. a = MuzzStates[i].moveAmount;
  508. }
  509. }
  510. else
  511. {
  512. a = MuzzStates[i].moveAmount;
  513. }
  514. MuzzStates[i].moveAmount -= a;
  515. Muzzes[i]->forward(a);
  516. // Check for collision.
  517. Muzzes[i]->getPosition(p);
  518. x2 = (int)(p[0] / Terrain->BLOCK_SIZE);
  519. z2 = (int)(p[2] / Terrain->BLOCK_SIZE);
  520. if ((x != x2) || (z != z2))
  521. {
  522. for (j = 0; j < NUM_MUZZES; j++)
  523. {
  524. if (j == i)
  525. {
  526. continue;
  527. }
  528. Muzzes[j]->getPosition(p2);
  529. x3 = (int)(p2[0] / Terrain->BLOCK_SIZE);
  530. z3 = (int)(p2[2] / Terrain->BLOCK_SIZE);
  531. if ((x2 == x3) && (z2 == z3))
  532. {
  533. Muzzes[i]->backward(a);
  534. MuzzStates[i].moveAmount = 0.0f;
  535. break;
  536. }
  537. }
  538. }
  539. break;
  540. case Muzz::RIGHT:
  541. if (SmoothMove)
  542. {
  543. a = MUZZ_TURN_DELTA * frameRate.speedFactor;
  544. if (a > MuzzStates[i].moveAmount)
  545. {
  546. a = MuzzStates[i].moveAmount;
  547. }
  548. }
  549. else
  550. {
  551. a = MuzzStates[i].moveAmount;
  552. }
  553. MuzzStates[i].moveAmount -= a;
  554. Muzzes[i]->right(a);
  555. break;
  556. case Muzz::LEFT:
  557. if (SmoothMove)
  558. {
  559. a = MUZZ_TURN_DELTA * frameRate.speedFactor;
  560. if (a > MuzzStates[i].moveAmount)
  561. {
  562. a = MuzzStates[i].moveAmount;
  563. }
  564. }
  565. else
  566. {
  567. a = MuzzStates[i].moveAmount;
  568. }
  569. MuzzStates[i].moveAmount -= a;
  570. Muzzes[i]->left(a);
  571. break;
  572. }
  573. }
  574. // Continue movement?
  575. if (MuzzStates[i].moveAmount > 0.0f)
  576. {
  577. return(false);
  578. }
  579. MuzzStates[i].moveAmount = 0.0f;
  580. // Center muzz on block, orient orthogonally and
  581. // store position and direction.
  582. Muzzes[i]->getPosition(p);
  583. x = (int)(p[0] / Terrain->BLOCK_SIZE);
  584. z = (int)(p[2] / Terrain->BLOCK_SIZE);
  585. if (move)
  586. {
  587. p2[0] = ((GLfloat)x + 0.5f) * Terrain->BLOCK_SIZE;
  588. p2[1] = p[1];
  589. p2[2] = ((GLfloat)z + 0.5f) * Terrain->BLOCK_SIZE;
  590. for (j = 0; j < 3; j++)
  591. {
  592. p2[j] = p[j] + ((p2[j] - p[j]) * 0.1f);
  593. }
  594. Muzzes[i]->setPosition(p2);
  595. }
  596. Muzzes[i]->getForward(f);
  597. f[1] = 0.0f;
  598. cSpacial::normalize(f);
  599. u[0] = 0.0f;
  600. u[1] = 1.0f;
  601. u[2] = 0.0f;
  602. if (fabs(f[0]) > fabs(f[2]))
  603. {
  604. if (f[0] < 0.0f)
  605. {
  606. MuzzStates[i].dir = 3;
  607. MuzzStates[i].forward = BlockTerrain::Block::WEST;
  608. MuzzStates[i].backward = BlockTerrain::Block::EAST;
  609. if (move)
  610. {
  611. Muzzes[i]->loadRotation(90.0f, u);
  612. Muzzes[i]->forward(0.0f);
  613. }
  614. }
  615. else
  616. {
  617. MuzzStates[i].dir = 1;
  618. MuzzStates[i].forward = BlockTerrain::Block::EAST;
  619. MuzzStates[i].backward = BlockTerrain::Block::WEST;
  620. if (move)
  621. {
  622. Muzzes[i]->loadRotation(270.0f, u);
  623. Muzzes[i]->forward(0.0f);
  624. }
  625. }
  626. }
  627. else
  628. {
  629. if (f[2] < 0.0f)
  630. {
  631. MuzzStates[i].dir = 0;
  632. MuzzStates[i].forward = BlockTerrain::Block::NORTH;
  633. MuzzStates[i].backward = BlockTerrain::Block::SOUTH;
  634. if (move)
  635. {
  636. Muzzes[i]->loadRotation(180.0f, u);
  637. Muzzes[i]->forward(0.0f);
  638. }
  639. }
  640. else
  641. {
  642. MuzzStates[i].dir = 2;
  643. MuzzStates[i].forward = BlockTerrain::Block::SOUTH;
  644. MuzzStates[i].backward = BlockTerrain::Block::NORTH;
  645. if (move)
  646. {
  647. Muzzes[i]->loadRotation(0.0f, u);
  648. Muzzes[i]->forward(0.0f);
  649. }
  650. }
  651. }
  652. Muzzes[i]->getPosition(p);
  653. MuzzStates[i].x = (int)(p[0] / Terrain->BLOCK_SIZE);
  654. MuzzStates[i].z = (int)(p[2] / Terrain->BLOCK_SIZE);
  655. return(true);
  656. }
  657. // Sense muzz world.
  658. void senseMuzz(int i)
  659. {
  660. int terrain, object, lookx, lookz;
  661. GLfloat view[3];
  662. // Determine sensory input.
  663. Muzzes[i]->getRight(view);
  664. for (int j = 0; j < 3; j++)
  665. {
  666. view[j] = -view[j];
  667. }
  668. senseMuzzDir(i, (MuzzStates[i].dir + 1) % 4, view, lookx, lookz, terrain, object);
  669. if ((terrain == Muzz::WALL) || (terrain == Muzz::DROP) ||
  670. ((object == Muzz::MUSHROOM) && Muzzes[i]->gotFood) ||
  671. (object == Muzz::MUZZ))
  672. {
  673. MuzzStates[i].sensors[Muzz::RIGHT_SENSOR] = Muzz::CLOSED;
  674. }
  675. else
  676. {
  677. MuzzStates[i].sensors[Muzz::RIGHT_SENSOR] = Muzz::OPEN;
  678. }
  679. Muzzes[i]->getRight(view);
  680. senseMuzzDir(i, (MuzzStates[i].dir + 3) % 4, view, lookx, lookz, terrain, object);
  681. if ((terrain == Muzz::WALL) || (terrain == Muzz::DROP) ||
  682. ((object == Muzz::MUSHROOM) && Muzzes[i]->gotFood) ||
  683. (object == Muzz::MUZZ))
  684. {
  685. MuzzStates[i].sensors[Muzz::LEFT_SENSOR] = Muzz::CLOSED;
  686. }
  687. else
  688. {
  689. MuzzStates[i].sensors[Muzz::LEFT_SENSOR] = Muzz::OPEN;
  690. }
  691. Muzzes[i]->getForward(view);
  692. senseMuzzDir(i, MuzzStates[i].dir, view, lookx, lookz, terrain, object);
  693. MuzzStates[i].sensors[Muzz::TERRAIN_SENSOR] = terrain;
  694. MuzzStates[i].sensors[Muzz::OBJECT_SENSOR] = object;
  695. if ((terrain == Muzz::WALL) || (terrain == Muzz::DROP) ||
  696. ((object == Muzz::MUSHROOM) && Muzzes[i]->gotFood) ||
  697. (object == Muzz::MUZZ))
  698. {
  699. MuzzStates[i].sensors[Muzz::FORWARD_SENSOR] = Muzz::CLOSED;
  700. }
  701. else
  702. {
  703. MuzzStates[i].sensors[Muzz::FORWARD_SENSOR] = Muzz::OPEN;
  704. }
  705. MuzzStates[i].lookAtX = lookx;
  706. MuzzStates[i].lookAtZ = lookz;
  707. }
  708. // Sense muzz world in a given direction and view vector.
  709. void senseMuzzDir(int muzzIndex, int direction, GLfloat view[3],
  710. int& senseX, int& senseZ, int& terrain, int& object)
  711. {
  712. int i, h, x, z, x2, z2, x3, z3;
  713. GLfloat p[3], p2[3], v[3];
  714. BlockTerrain::Block::DIRECTION forward, backward;
  715. Muzzes[muzzIndex]->getPosition(p);
  716. x = (int)(p[0] / Terrain->BLOCK_SIZE);
  717. z = (int)(p[2] / Terrain->BLOCK_SIZE);
  718. switch (direction)
  719. {
  720. case 0: // North.
  721. if (z == 0)
  722. {
  723. terrain = Muzz::DROP;
  724. object = Muzz::EMPTY;
  725. return;
  726. }
  727. else
  728. {
  729. senseX = x2 = x;
  730. senseZ = z2 = z - 1;
  731. }
  732. forward = BlockTerrain::Block::NORTH;
  733. backward = BlockTerrain::Block::SOUTH;
  734. break;
  735. case 1: // East.
  736. if (x == Terrain->WIDTH - 1)
  737. {
  738. terrain = Muzz::DROP;
  739. object = Muzz::EMPTY;
  740. return;
  741. }
  742. else
  743. {
  744. senseX = x2 = x + 1;
  745. senseZ = z2 = z;
  746. }
  747. forward = BlockTerrain::Block::EAST;
  748. backward = BlockTerrain::Block::WEST;
  749. break;
  750. case 2: // South.
  751. if (z == Terrain->HEIGHT - 1)
  752. {
  753. terrain = Muzz::DROP;
  754. object = Muzz::EMPTY;
  755. return;
  756. }
  757. else
  758. {
  759. senseX = x2 = x;
  760. senseZ = z2 = z + 1;
  761. }
  762. forward = BlockTerrain::Block::SOUTH;
  763. backward = BlockTerrain::Block::NORTH;
  764. break;
  765. case 3: // West.
  766. if (x == 0)
  767. {
  768. terrain = Muzz::DROP;
  769. object = Muzz::EMPTY;
  770. return;
  771. }
  772. else
  773. {
  774. senseX = x2 = x - 1;
  775. senseZ = z2 = z;
  776. }
  777. forward = BlockTerrain::Block::WEST;
  778. backward = BlockTerrain::Block::EAST;
  779. break;
  780. }
  781. // Object in view?
  782. // Cannot see objects when crosswise on ramp.
  783. if ((Terrain->blocks[x][z].type != BlockTerrain::Block::RAMP) ||
  784. ((Terrain->blocks[x][z].type == BlockTerrain::Block::RAMP) &&
  785. ((Terrain->blocks[x][z].rampDir == forward) ||
  786. (Terrain->blocks[x][z].rampDir == backward))))
  787. {
  788. // Determine point in view.
  789. x3 = (int)(p[0] / Terrain->BLOCK_SIZE);
  790. p2[0] = ((GLfloat)x3 + 0.5f) * Terrain->BLOCK_SIZE;
  791. p2[1] = p[1];
  792. z3 = (int)(p[2] / Terrain->BLOCK_SIZE);
  793. p2[2] = ((GLfloat)z3 + 0.5f) * Terrain->BLOCK_SIZE;
  794. for (i = 0; i < 3; i++)
  795. {
  796. v[i] = view[i];
  797. }
  798. cSpacial::normalize(v);
  799. for (i = 0; i < 3; i++)
  800. {
  801. p[i] = p2[i] + (v[i] * Terrain->BLOCK_SIZE);
  802. }
  803. for (i = 0; i < NUM_MUZZES; i++)
  804. {
  805. if (i == muzzIndex)
  806. {
  807. continue;
  808. }
  809. Muzzes[i]->getPosition(p2);
  810. if (fabs(cSpacial::pointDistance(p, p2)) < (Terrain->BLOCK_SIZE * 0.4f))
  811. {
  812. x3 = (int)(p2[0] / Terrain->BLOCK_SIZE);
  813. z3 = (int)(p2[2] / Terrain->BLOCK_SIZE);
  814. if (Terrain->blocks[x3][z3].type != BlockTerrain::Block::RAMP)
  815. {
  816. terrain = Muzz::PLATFORM;
  817. }
  818. else
  819. {
  820. if (Terrain->blocks[x3][z3].rampDir == forward)
  821. {
  822. terrain = Muzz::RAMP_UP;
  823. }
  824. else
  825. {
  826. terrain = Muzz::RAMP_DOWN;
  827. }
  828. }
  829. object = Muzz::MUZZ;
  830. return;
  831. }
  832. }
  833. for (i = 0; i < NUM_MUSHROOMS; i++)
  834. {
  835. if (!Mushrooms[i]->isAlive())
  836. {
  837. continue;
  838. }
  839. Mushrooms[i]->getPosition(p2);
  840. if (fabs(cSpacial::pointDistance(p, p2)) < (Terrain->BLOCK_SIZE * 0.4f))
  841. {
  842. terrain = Muzz::PLATFORM;
  843. object = Muzz::MUSHROOM;
  844. return;
  845. }
  846. }
  847. for (i = 0; i < NUM_POOLS; i++)
  848. {
  849. Pools[i]->getPosition(p2);
  850. if (fabs(cSpacial::pointDistance(p, p2)) < (Terrain->BLOCK_SIZE * 0.4f))
  851. {
  852. terrain = Muzz::PLATFORM;
  853. object = Muzz::POOL;
  854. return;
  855. }
  856. }
  857. }
  858. // View terrain.
  859. h = Terrain->blocks[x2][z2].elevation - Terrain->blocks[x][z].elevation;
  860. switch (Terrain->blocks[x][z].type)
  861. {
  862. case BlockTerrain::Block::PLATFORM:
  863. switch (Terrain->blocks[x2][z2].type)
  864. {
  865. case BlockTerrain::Block::PLATFORM:
  866. case BlockTerrain::Block::LANDING:
  867. if (h < 0)
  868. {
  869. terrain = Muzz::DROP;
  870. object = Muzz::EMPTY;
  871. }
  872. else if (h > 0)
  873. {
  874. terrain = Muzz::WALL;
  875. #if (SENSE_BLOCK_ID == 1)
  876. object = (Terrain->blocks[x2][z2].id << 8) |
  877. (unsigned char )((int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation + 1]);
  878. #else
  879. object = (int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation + 1];
  880. #endif
  881. }
  882. else
  883. {
  884. terrain = Muzz::PLATFORM;
  885. #if (SENSE_BLOCK_ID == 1)
  886. object = (Terrain->blocks[x2][z2].id << 8) |
  887. (unsigned char )((int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation]);
  888. #else
  889. object = (int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation];
  890. #endif
  891. }
  892. break;
  893. case BlockTerrain::Block::RAMP:
  894. if (h < 0)
  895. {
  896. terrain = Muzz::DROP;
  897. object = Muzz::EMPTY;
  898. }
  899. else if (h > 0)
  900. {
  901. terrain = Muzz::WALL;
  902. object = Muzz::EMPTY;
  903. }
  904. else
  905. {
  906. if (Terrain->isUpperRamp(x2, z2))
  907. {
  908. terrain = Muzz::DROP;
  909. object = Muzz::EMPTY;
  910. }
  911. else
  912. {
  913. terrain = Muzz::WALL;
  914. object = Muzz::EMPTY;
  915. }
  916. }
  917. break;
  918. }
  919. break;
  920. case BlockTerrain::Block::LANDING:
  921. switch (Terrain->blocks[x2][z2].type)
  922. {
  923. case BlockTerrain::Block::PLATFORM:
  924. case BlockTerrain::Block::LANDING:
  925. if (h < 0)
  926. {
  927. terrain = Muzz::DROP;
  928. object = Muzz::EMPTY;
  929. }
  930. else if (h > 0)
  931. {
  932. terrain = Muzz::WALL;
  933. #if (SENSE_BLOCK_ID == 1)
  934. object = (Terrain->blocks[x2][z2].id << 8) |
  935. (unsigned char )((int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation + 1]);
  936. #else
  937. object = (int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation + 1];
  938. #endif
  939. }
  940. else
  941. {
  942. terrain = Muzz::PLATFORM;
  943. #if (SENSE_BLOCK_ID == 1)
  944. object = (Terrain->blocks[x2][z2].id << 8) |
  945. (unsigned char )((int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation]);
  946. #else
  947. object = (int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation];
  948. #endif
  949. }
  950. break;
  951. case BlockTerrain::Block::RAMP:
  952. if (Terrain->blocks[x2][z2].rampDir == forward)
  953. {
  954. terrain = Muzz::RAMP_UP;
  955. object = Muzz::EMPTY;
  956. }
  957. else if (Terrain->blocks[x2][z2].rampDir == backward)
  958. {
  959. terrain = Muzz::RAMP_DOWN;
  960. object = Muzz::EMPTY;
  961. }
  962. else if (h < 0)
  963. {
  964. terrain = Muzz::DROP;
  965. object = Muzz::EMPTY;
  966. }
  967. else if (h > 0)
  968. {
  969. terrain = Muzz::WALL;
  970. object = Muzz::EMPTY;
  971. }
  972. else
  973. {
  974. if (Terrain->isUpperRamp(x2, z2))
  975. {
  976. terrain = Muzz::DROP;
  977. object = Muzz::EMPTY;
  978. }
  979. else
  980. {
  981. terrain = Muzz::WALL;
  982. object = Muzz::EMPTY;
  983. }
  984. }
  985. break;
  986. }
  987. break;
  988. case BlockTerrain::Block::RAMP:
  989. switch (Terrain->blocks[x2][z2].type)
  990. {
  991. case BlockTerrain::Block::PLATFORM:
  992. if (h < 0)
  993. {
  994. terrain = Muzz::DROP;
  995. object = Muzz::EMPTY;
  996. }
  997. else if (h > 0)
  998. {
  999. terrain = Muzz::WALL;
  1000. object = Muzz::EMPTY;
  1001. }
  1002. else
  1003. {
  1004. if (Terrain->isUpperRamp(x, z))
  1005. {
  1006. terrain = Muzz::WALL;
  1007. object = Muzz::EMPTY;
  1008. }
  1009. else
  1010. {
  1011. terrain = Muzz::DROP;
  1012. object = Muzz::EMPTY;
  1013. }
  1014. }
  1015. break;
  1016. case BlockTerrain::Block::LANDING:
  1017. if ((Terrain->blocks[x][z].rampDir == forward) ||
  1018. (Terrain->blocks[x][z].rampDir == backward))
  1019. {
  1020. terrain = Muzz::PLATFORM;
  1021. #if (SENSE_BLOCK_ID == 1)
  1022. object = (Terrain->blocks[x2][z2].id << 8) |
  1023. (unsigned char )((int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation]);
  1024. #else
  1025. object = (int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation];
  1026. #endif
  1027. }
  1028. else if (h < 0)
  1029. {
  1030. terrain = Muzz::DROP;
  1031. object = Muzz::EMPTY;
  1032. }
  1033. else if (h > 0)
  1034. {
  1035. terrain = Muzz::WALL;
  1036. object = Muzz::EMPTY;
  1037. }
  1038. else
  1039. {
  1040. if (Terrain->isUpperRamp(x, z))
  1041. {
  1042. terrain = Muzz::WALL;
  1043. object = Muzz::EMPTY;
  1044. }
  1045. else
  1046. {
  1047. terrain = Muzz::DROP;
  1048. object = Muzz::EMPTY;
  1049. }
  1050. }
  1051. break;
  1052. case BlockTerrain::Block::RAMP:
  1053. if ((Terrain->blocks[x][z].rampDir == forward) &&
  1054. (Terrain->blocks[x2][z2].rampDir == forward))
  1055. {
  1056. terrain = Muzz::RAMP_UP;
  1057. object = Muzz::EMPTY;
  1058. }
  1059. else if ((Terrain->blocks[x][z].rampDir == backward) &&
  1060. (Terrain->blocks[x2][z2].rampDir == backward))
  1061. {
  1062. terrain = Muzz::RAMP_DOWN;
  1063. object = Muzz::EMPTY;
  1064. }
  1065. else if (h < 0)
  1066. {
  1067. terrain = Muzz::DROP;
  1068. object = Muzz::EMPTY;
  1069. }
  1070. else if (h > 0)
  1071. {
  1072. terrain = Muzz::WALL;
  1073. object = Muzz::EMPTY;
  1074. }
  1075. else
  1076. {
  1077. if (Terrain->isUpperRamp(x, z))
  1078. {
  1079. terrain = Muzz::DROP;
  1080. object = Muzz::EMPTY;
  1081. }
  1082. else if (Terrain->isUpperRamp(x2, z2))
  1083. {
  1084. terrain = Muzz::WALL;
  1085. object = Muzz::EMPTY;
  1086. }
  1087. else
  1088. {
  1089. terrain = Muzz::DROP;
  1090. object = Muzz::EMPTY;
  1091. }
  1092. }
  1093. break;
  1094. }
  1095. break;
  1096. }
  1097. }
  1098. // Run muzz.
  1099. void runMuzz(int i, int forcedResponse)
  1100. {
  1101. int j, dir, x, z, x2, z2, x3, z3;
  1102. bool hadFood;
  1103. GLfloat p[3], p2[3], f[3];
  1104. BlockTerrain::Block::DIRECTION forward;
  1105. BlockTerrain::Block::DIRECTION backward;
  1106. // Get muzz response.
  1107. hadFood = Muzzes[i]->gotFood;
  1108. if (forcedResponse == INVALID_RESPONSE)
  1109. {
  1110. // Let brain decide.
  1111. MuzzStates[i].response = Muzzes[i]->cycle(MuzzStates[i].sensors);
  1112. }
  1113. else
  1114. {
  1115. // Force response.
  1116. MuzzStates[i].response = forcedResponse;
  1117. if ((MuzzStates[i].sensors[Muzz::OBJECT_SENSOR] == Muzz::MUSHROOM) &&
  1118. (MuzzStates[i].response == Muzz::EAT))
  1119. {
  1120. Muzzes[i]->gotFood = true;
  1121. }
  1122. if ((MuzzStates[i].sensors[Muzz::OBJECT_SENSOR] == Muzz::POOL) &&
  1123. (MuzzStates[i].response == Muzz::DRINK))
  1124. {
  1125. Muzzes[i]->gotWater = true;
  1126. }
  1127. }
  1128. // Process response.
  1129. x = MuzzStates[i].x;
  1130. z = MuzzStates[i].z;
  1131. dir = MuzzStates[i].dir;
  1132. forward = MuzzStates[i].forward;
  1133. backward = MuzzStates[i].backward;
  1134. switch (MuzzStates[i].response)
  1135. {
  1136. case Muzz::WAIT:
  1137. break;
  1138. case Muzz::FORWARD:
  1139. MuzzStates[i].moveType = Muzz::FORWARD;
  1140. MuzzStates[i].moveAmount = Terrain->BLOCK_SIZE;
  1141. if ((MuzzStates[i].sensors[Muzz::OBJECT_SENSOR] == Muzz::MUSHROOM) ||
  1142. (MuzzStates[i].sensors[Muzz::OBJECT_SENSOR] == Muzz::MUZZ))
  1143. {
  1144. MuzzStates[i].moveAmount = 0.0f;
  1145. break;
  1146. }
  1147. switch (dir)
  1148. {
  1149. case 0: // North.
  1150. if (z == 0)
  1151. {
  1152. MuzzStates[i].moveAmount = 0.0f;
  1153. return;
  1154. }
  1155. x2 = x;
  1156. z2 = z - 1;
  1157. break;
  1158. case 1: // East.
  1159. if (x == Terrain->WIDTH - 1)
  1160. {
  1161. MuzzStates[i].moveAmount = 0.0f;
  1162. return;
  1163. }
  1164. x2 = x + 1;
  1165. z2 = z;
  1166. break;
  1167. case 2: // South.
  1168. if (z == Terrain->HEIGHT - 1)
  1169. {
  1170. MuzzStates[i].moveAmount = 0.0f;
  1171. return;
  1172. }
  1173. x2 = x;
  1174. z2 = z + 1;
  1175. break;
  1176. case 3: // West.
  1177. if (x == 0)
  1178. {
  1179. MuzzStates[i].moveAmount = 0.0f;
  1180. return;
  1181. }
  1182. x2 = x - 1;
  1183. z2 = z;
  1184. break;
  1185. }
  1186. if (Terrain->blocks[x][z].type == BlockTerrain::Block::RAMP)
  1187. {
  1188. if ((Terrain->blocks[x][z].rampDir != forward) &&
  1189. (Terrain->blocks[x][z].rampDir != backward))
  1190. {
  1191. MuzzStates[i].moveAmount = 0.0f;
  1192. return;
  1193. }
  1194. }
  1195. if (((Terrain->blocks[x][z].type != BlockTerrain::Block::RAMP) ||
  1196. (Terrain->blocks[x2][z2].type != BlockTerrain::Block::RAMP)) &&
  1197. (Terrain->blocks[x][z].elevation != Terrain->blocks[x2][z2].elevation))
  1198. {
  1199. MuzzStates[i].moveAmount = 0.0f;
  1200. }
  1201. else if ((Terrain->blocks[x][z].type != BlockTerrain::Block::RAMP) &&
  1202. (Terrain->blocks[x2][z2].type == BlockTerrain::Block::RAMP) &&
  1203. (Terrain->blocks[x2][z2].rampDir != forward) &&
  1204. (Terrain->blocks[x2][z2].rampDir != backward))
  1205. {
  1206. MuzzStates[i].moveAmount = 0.0f;
  1207. }
  1208. else
  1209. {
  1210. switch (Terrain->blocks[x][z].type)
  1211. {
  1212. case BlockTerrain::Block::LANDING:
  1213. if (Terrain->blocks[x2][z2].type == BlockTerrain::Block::RAMP)
  1214. {
  1215. MuzzStates[i].moveAmount = (Terrain->BLOCK_SIZE * 0.5f) +
  1216. (Terrain->BLOCK_SIZE * (2.236f / 4.0f));
  1217. }
  1218. break;
  1219. case BlockTerrain::Block::RAMP:
  1220. if (Terrain->blocks[x2][z2].type == BlockTerrain::Block::RAMP)
  1221. {
  1222. MuzzStates[i].moveAmount = Terrain->BLOCK_SIZE * (2.236f / 2.0f);
  1223. }
  1224. else if (Terrain->blocks[x2][z2].type == BlockTerrain::Block::LANDING)
  1225. {
  1226. MuzzStates[i].moveAmount = (Terrain->BLOCK_SIZE * 0.5f) +
  1227. (Terrain->BLOCK_SIZE * (2.236f / 4.0f));
  1228. }
  1229. break;
  1230. }
  1231. }
  1232. break;
  1233. case Muzz::RIGHT:
  1234. MuzzStates[i].moveType = Muzz::RIGHT;
  1235. MuzzStates[i].moveAmount = 90.0f;
  1236. break;
  1237. case Muzz::LEFT:
  1238. MuzzStates[i].moveType = Muzz::LEFT;
  1239. MuzzStates[i].moveAmount = 90.0f;
  1240. break;
  1241. case Muzz::EAT:
  1242. if (!hadFood && Muzzes[i]->gotFood &&
  1243. (MuzzStates[i].sensors[Muzz::OBJECT_SENSOR] == Muzz::MUSHROOM))
  1244. {
  1245. Muzzes[i]->getPosition(p);
  1246. x3 = (int)(p[0] / Terrain->BLOCK_SIZE);
  1247. p2[0] = ((GLfloat)x3 + 0.5f) * Terrain->BLOCK_SIZE;
  1248. p2[1] = p[1];
  1249. z3 = (int)(p[2] / Terrain->BLOCK_SIZE);
  1250. p2[2] = ((GLfloat)z3 + 0.5f) * Terrain->BLOCK_SIZE;
  1251. Muzzes[i]->getForward(f);
  1252. cSpacial::normalize(f);
  1253. for (j = 0; j < 3; j++)
  1254. {
  1255. p[j] = p2[j] + (f[j] * Terrain->BLOCK_SIZE);
  1256. }
  1257. for (j = 0; j < NUM_MUSHROOMS; j++)
  1258. {
  1259. if (!Mushrooms[j]->isAlive())
  1260. {
  1261. continue;
  1262. }
  1263. Mushrooms[j]->getPosition(p2);
  1264. if (fabs(cSpacial::pointDistance(p, p2)) < (Terrain->BLOCK_SIZE * 0.4f))
  1265. {
  1266. Mushrooms[j]->setAlive(false);
  1267. }
  1268. }
  1269. }
  1270. break;
  1271. case Muzz::DRINK:
  1272. break;
  1273. }
  1274. }
  1275. // Place muzz in world without changing its initial stored placement.
  1276. void placeMuzz(int muzzIndex, int placeX, int placeZ, BlockTerrain::Block::DIRECTION placeDir)
  1277. {
  1278. GLfloat p[3];
  1279. Vector n;
  1280. // Clear pending movement.
  1281. MuzzStates[muzzIndex].moveType = Muzz::FORWARD;
  1282. MuzzStates[muzzIndex].moveAmount = 0.0f;
  1283. Muzzes[muzzIndex]->clearSpacial();
  1284. p[0] = ((GLfloat)placeX * Terrain->BLOCK_SIZE) + (Terrain->BLOCK_SIZE * 0.5f);
  1285. p[2] = ((GLfloat)placeZ * Terrain->BLOCK_SIZE) + (Terrain->BLOCK_SIZE * 0.5f);
  1286. Terrain->getGeometry(p[0], p[2], p[1], n);
  1287. Muzzes[muzzIndex]->setPosition(p);
  1288. switch (placeDir)
  1289. {
  1290. case BlockTerrain::Block::NORTH:
  1291. Muzzes[muzzIndex]->setYaw(0.0f);
  1292. break;
  1293. case BlockTerrain::Block::EAST:
  1294. Muzzes[muzzIndex]->setYaw(90.0f);
  1295. break;
  1296. case BlockTerrain::Block::SOUTH:
  1297. Muzzes[muzzIndex]->setYaw(180.0f);
  1298. break;
  1299. case BlockTerrain::Block::WEST:
  1300. Muzzes[muzzIndex]->setYaw(270.0f);
  1301. break;
  1302. }
  1303. Muzzes[muzzIndex]->forward(0.0f);
  1304. }
  1305. // Reset training.
  1306. void resetTraining()
  1307. {
  1308. CurrentTrial = 0;
  1309. CurrentTrialStep = 0;
  1310. TrialResetDelay = -1;
  1311. TrainingTrialResume = -1;
  1312. if (ResponseIdx > 0)
  1313. {
  1314. ResponseIdx = 0;
  1315. }
  1316. }
  1317. // Draw world.
  1318. void drawWorld(int skipMuzz)
  1319. {
  1320. int i;
  1321. glColor3f(1.0f, 1.0f, 1.0f);
  1322. if (WireView)
  1323. {
  1324. glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  1325. }
  1326. else
  1327. {
  1328. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  1329. }
  1330. glPushMatrix();
  1331. // Draw the terrain.
  1332. Terrain->draw();
  1333. // Draw muzzes.
  1334. for (i = 0; i < NUM_MUZZES; i++)
  1335. {
  1336. if (i != skipMuzz)
  1337. {
  1338. // Name the muzz for selection purposes.
  1339. glPushMatrix();
  1340. glPushName(i + 1);
  1341. Muzzes[i]->draw();
  1342. glPopName();
  1343. glPopMatrix();
  1344. }
  1345. }
  1346. // Draw mushrooms.
  1347. for (i = 0; i < NUM_MUSHROOMS; i++)
  1348. {
  1349. if (Mushrooms[i]->isAlive())
  1350. {
  1351. Mushrooms[i]->draw();
  1352. }
  1353. }
  1354. // Draw water pools.
  1355. for (i = 0; i < NUM_POOLS; i++)
  1356. {
  1357. Pools[i]->draw();
  1358. }
  1359. glPopMatrix();
  1360. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  1361. }
  1362. // Display muzz view.
  1363. void displayMuzzView(void)
  1364. {
  1365. if (ViewSelection == TERRAIN_VIEW_ONLY)
  1366. {
  1367. return;
  1368. }
  1369. // Clear transform matrix.
  1370. glMatrixMode(GL_MODELVIEW);
  1371. glLoadIdentity();
  1372. // Place camera at current muzz view point.
  1373. if (CurrentMuzz != -1)
  1374. {
  1375. // Camera follows muzz.
  1376. Muzzes[CurrentMuzz]->aimCamera(camera);
  1377. // Set viewport and frustum.
  1378. glViewport(Viewports[MUZZ_VIEWPORT].x, Viewports[MUZZ_VIEWPORT].y,
  1379. Viewports[MUZZ_VIEWPORT].width, Viewports[MUZZ_VIEWPORT].height);
  1380. camera.setFrustum(MUZZ_FRUSTUM_ANGLE, Viewports[MUZZ_VIEWPORT].aspect,
  1381. MUZZ_FRUSTUM_NEAR, MUZZ_FRUSTUM_FAR);
  1382. // Draw the world.
  1383. drawWorld(CurrentMuzz);
  1384. }
  1385. else
  1386. {
  1387. // Set viewport.
  1388. glViewport(Viewports[MUZZ_VIEWPORT].x, Viewports[MUZZ_VIEWPORT].y,
  1389. Viewports[MUZZ_VIEWPORT].width, Viewports[MUZZ_VIEWPORT].height);
  1390. }
  1391. // Label view.
  1392. glLineWidth(2.0);
  1393. enter2Dmode();
  1394. draw2Dstring(5, 12, FONT, (char *)"Muzz");
  1395. exit2Dmode();
  1396. }
  1397. // Display the terrain view.
  1398. void displayTerrainView(void)
  1399. {
  1400. if (ViewSelection == MUZZ_VIEW_ONLY)
  1401. {
  1402. return;
  1403. }
  1404. glMatrixMode(GL_MODELVIEW);
  1405. glLoadIdentity();
  1406. // Set viewport and frustum.
  1407. glViewport(Viewports[TERRAIN_VIEWPORT].x, Viewports[TERRAIN_VIEWPORT].y,
  1408. Viewports[TERRAIN_VIEWPORT].width, Viewports[TERRAIN_VIEWPORT].height);
  1409. camera.setFrustum(TERRAIN_FRUSTUM_ANGLE, Viewports[TERRAIN_VIEWPORT].aspect,
  1410. MUZZ_FRUSTUM_NEAR, MUZZ_FRUSTUM_FAR);
  1411. // Position camera.
  1412. camera.clearSpacial();
  1413. camera.setPosition(TerrainViewPosition);
  1414. camera.setPitch(-90.0f);
  1415. camera.setRoll(180.0f);
  1416. camera.place();
  1417. // Rendering to select a muzz?
  1418. if (renderMode == GL_SELECT)
  1419. {
  1420. startPicking();
  1421. }
  1422. // Draw the world with a small perspective angle.
  1423. glPushMatrix();
  1424. glRotatef(20.0f, 1.0f, 0.0f, 1.0f);
  1425. drawWorld(-1);
  1426. if (renderMode == GL_SELECT)
  1427. {
  1428. stopPicking();
  1429. }
  1430. else
  1431. {
  1432. // Highlight current muzz.
  1433. if (CurrentMuzz != -1)
  1434. {
  1435. Muzzes[CurrentMuzz]->highlight();
  1436. }
  1437. }
  1438. glPopMatrix();
  1439. // Label view.
  1440. glLineWidth(2.0);
  1441. enter2Dmode();
  1442. draw2Dstring(5, 12, FONT, (char *)"Terrain");
  1443. exit2Dmode();
  1444. }
  1445. // Display the controls view.
  1446. void displayControls(void)
  1447. {
  1448. int vw, vh;
  1449. GLint viewport[4];
  1450. char buf[100];
  1451. // Set viewport.
  1452. glViewport(Viewports[CONTROLS_VIEWPORT].x, Viewports[CONTROLS_VIEWPORT].y,
  1453. Viewports[CONTROLS_VIEWPORT].width, Viewports[CONTROLS_VIEWPORT].height);
  1454. glGetIntegerv(GL_VIEWPORT, viewport);
  1455. vw = viewport[2];
  1456. vh = viewport[3];
  1457. // Render the GUI.
  1458. counter.markFrameStart();
  1459. enter2DMode(guiFrame->getWidth(), guiFrame->getHeight());
  1460. guiFrame->render(counter.getFrameInterval());
  1461. counter.markFrameEnd();
  1462. // Show frame rate.
  1463. sprintf(buf, "FPS: %.2f", frameRate.FPS);
  1464. draw2Dstring(5, 15, FONT, buf);
  1465. // Show cycle?
  1466. if (Cycles >= 0)
  1467. {
  1468. // Show training trial also?
  1469. if ((NumTrainingTrials >= 0) && (CurrentTrial >= 0) &&
  1470. (CurrentTrial <= NumTrainingTrials))
  1471. {
  1472. sprintf(buf, "Cycle=%d/%d Training trial=%d/%d",
  1473. CycleCounter, Cycles, CurrentTrial, NumTrainingTrials);
  1474. draw2Dstring(5, vh - 10, FONT, buf);
  1475. }
  1476. else
  1477. {
  1478. sprintf(buf, "Cycle=%d/%d", CycleCounter, Cycles);
  1479. draw2Dstring(5, vh - 10, FONT, buf);
  1480. }
  1481. }
  1482. else
  1483. {
  1484. // Show training trial?
  1485. if ((NumTrainingTrials >= 0) && (CurrentTrial >= 0) &&
  1486. (CurrentTrial <= NumTrainingTrials))
  1487. {
  1488. sprintf(buf, "Training trial=%d/%d",
  1489. CurrentTrial, NumTrainingTrials);
  1490. draw2Dstring(5, vh - 10, FONT, buf);
  1491. }
  1492. }
  1493. exit2DMode();
  1494. }
  1495. // Display the muzz status panel.
  1496. void displayMuzzStatus(void)
  1497. {
  1498. int vw, vh, xoff, yoff;
  1499. GLint viewport[4];
  1500. char buf[50];
  1501. // Set viewport.
  1502. glViewport(Viewports[MUZZ_STATUS_VIEWPORT].x, Viewports[MUZZ_STATUS_VIEWPORT].y,
  1503. Viewports[MUZZ_STATUS_VIEWPORT].width, Viewports[MUZZ_STATUS_VIEWPORT].height);
  1504. enter2Dmode();
  1505. if (CurrentMuzz != -1)
  1506. {
  1507. sprintf(buf, "Muzz %d status", Muzzes[CurrentMuzz]->id);
  1508. draw2Dstring(5, 12, FONT, buf);
  1509. }
  1510. else
  1511. {
  1512. draw2Dstring(5, 12, FONT, (char *)"Muzz status");
  1513. }
  1514. glGetIntegerv(GL_VIEWPORT, viewport);
  1515. vw = viewport[2];
  1516. vh = viewport[3];
  1517. // Show sensors.
  1518. xoff = 5;
  1519. yoff = vh / 3;
  1520. draw2Dstring(xoff, yoff, FONT, (char *)"Sensors:");
  1521. xoff += 5;
  1522. yoff += 15;
  1523. if (CurrentMuzz != -1)
  1524. {
  1525. if (MuzzStates[CurrentMuzz].sensors[Muzz::RIGHT_SENSOR] != Muzz::CLOSED)
  1526. {
  1527. if (MuzzStates[CurrentMuzz].sensors[Muzz::LEFT_SENSOR] != Muzz::CLOSED)
  1528. {
  1529. if (MuzzStates[CurrentMuzz].sensors[Muzz::FORWARD_SENSOR] != Muzz::CLOSED)
  1530. {
  1531. draw2Dstring(xoff, yoff, FONT, (char *)" open<-open->open");
  1532. }
  1533. else
  1534. {
  1535. draw2Dstring(xoff, yoff, FONT, (char *)" open<-closed->open");
  1536. }
  1537. }
  1538. else
  1539. {
  1540. if (MuzzStates[CurrentMuzz].sensors[Muzz::FORWARD_SENSOR] != Muzz::CLOSED)
  1541. {
  1542. draw2Dstring(xoff, yoff, FONT, (char *)" closed<-open->open");
  1543. }
  1544. else
  1545. {
  1546. draw2Dstring(xoff, yoff, FONT, (char *)" closed<-closed->open");
  1547. }
  1548. }
  1549. }
  1550. else
  1551. {
  1552. if (MuzzStates[CurrentMuzz].sensors[Muzz::LEFT_SENSOR] != Muzz::CLOSED)
  1553. {
  1554. if (MuzzStates[CurrentMuzz].sensors[Muzz::FORWARD_SENSOR] != Muzz::CLOSED)
  1555. {
  1556. draw2Dstring(xoff, yoff, FONT, (char *)" open<-open->closed");
  1557. }
  1558. else
  1559. {
  1560. draw2Dstring(xoff, yoff, FONT, (char *)" open<-closed->closed");
  1561. }
  1562. }
  1563. else
  1564. {
  1565. if (MuzzStates[CurrentMuzz].sensors[Muzz::FORWARD_SENSOR] != Muzz::CLOSED)
  1566. {
  1567. draw2Dstring(xoff, yoff, FONT, (char *)" closed<-open->closed");
  1568. }
  1569. else
  1570. {
  1571. draw2Dstring(xoff, yoff, FONT, (char *)" closed<-closed->closed");
  1572. }
  1573. }
  1574. }
  1575. yoff += 15;
  1576. switch (MuzzStates[CurrentMuzz].sensors[Muzz::TERRAIN_SENSOR])
  1577. {
  1578. case Muzz::PLATFORM:
  1579. draw2Dstring(xoff, yoff, FONT, (char *)" Terrain=platform");
  1580. break;
  1581. case Muzz::WALL:
  1582. draw2Dstring(xoff, yoff, FONT, (char *)" Terrain=wall");
  1583. break;
  1584. case Muzz::DROP:
  1585. draw2Dstring(xoff, yoff, FONT, (char *)" Terrain=drop off");
  1586. break;
  1587. case Muzz::RAMP_UP:
  1588. draw2Dstring(xoff, yoff, FONT, (char *)" Terrain=ramp up");
  1589. break;
  1590. case Muzz::RAMP_DOWN:
  1591. draw2Dstring(xoff, yoff, FONT, (char *)" Terrain=ramp down");
  1592. break;
  1593. }
  1594. yoff += 15;
  1595. switch (MuzzStates[CurrentMuzz].sensors[Muzz::OBJECT_SENSOR])
  1596. {
  1597. case Muzz::MUSHROOM:
  1598. draw2Dstring(xoff, yoff, FONT, (char *)" Object=mushroom");
  1599. break;
  1600. case Muzz::POOL:
  1601. draw2Dstring(xoff, yoff, FONT, (char *)" Object=pool");
  1602. break;
  1603. case Muzz::MUZZ:
  1604. draw2Dstring(xoff, yoff, FONT, (char *)" Object=muzz");
  1605. break;
  1606. case Muzz::EMPTY:
  1607. draw2Dstring(xoff, yoff, FONT, (char *)" Object=empty");
  1608. break;
  1609. default:
  1610. #if (SENSE_BLOCK_ID == 1)
  1611. if ((char)(MuzzStates[CurrentMuzz].sensors[Muzz::OBJECT_SENSOR] & 0xff) == '[')
  1612. {
  1613. sprintf(buf, " Object=blank(%d)", MuzzStates[CurrentMuzz].sensors[Muzz::OBJECT_SENSOR]);
  1614. }
  1615. else
  1616. {
  1617. sprintf(buf, " Object=%c(%d)", (char)(MuzzStates[CurrentMuzz].sensors[Muzz::OBJECT_SENSOR] & 0xff),
  1618. MuzzStates[CurrentMuzz].sensors[Muzz::OBJECT_SENSOR]);
  1619. }
  1620. #else
  1621. if ((char)MuzzStates[CurrentMuzz].sensors[Muzz::OBJECT_SENSOR] == '[')
  1622. {
  1623. sprintf(buf, " Object=blank");
  1624. }
  1625. else
  1626. {
  1627. sprintf(buf, " Object=%c", MuzzStates[CurrentMuzz].sensors[Muzz::OBJECT_SENSOR]);
  1628. }
  1629. #endif
  1630. draw2Dstring(xoff, yoff, FONT, buf);
  1631. break;
  1632. }
  1633. }
  1634. else
  1635. {
  1636. draw2Dstring(xoff, yoff, FONT, (char *)" NA<-NA->NA");
  1637. yoff += 15;
  1638. draw2Dstring(xoff, yoff, FONT, (char *)" Terrain=NA");
  1639. yoff += 15;
  1640. draw2Dstring(xoff, yoff, FONT, (char *)" Object=NA");
  1641. }
  1642. // Show response.
  1643. xoff = (vw / 2) + 15;
  1644. yoff = vh / 4;
  1645. if (CurrentMuzz != -1)
  1646. {
  1647. switch (MuzzStates[CurrentMuzz].response)
  1648. {
  1649. case Muzz::WAIT:
  1650. draw2Dstring(xoff, yoff, FONT, (char *)"Response=wait");
  1651. break;
  1652. case Muzz::FORWARD:
  1653. draw2Dstring(xoff, yoff, FONT, (char *)"Response=forward");
  1654. break;
  1655. case Muzz::RIGHT:
  1656. draw2Dstring(xoff, yoff, FONT, (char *)"Response=right");
  1657. break;
  1658. case Muzz::LEFT:
  1659. draw2Dstring(xoff, yoff, FONT, (char *)"Response=left");
  1660. break;
  1661. case Muzz::EAT:
  1662. draw2Dstring(xoff, yoff, FONT, (char *)"Response=eat");
  1663. break;
  1664. case Muzz::DRINK:
  1665. draw2Dstring(xoff, yoff, FONT, (char *)"Response=drink");
  1666. break;
  1667. }
  1668. }
  1669. else
  1670. {
  1671. draw2Dstring(xoff, yoff, FONT, (char *)"Response=NA");
  1672. }
  1673. // Show needs.
  1674. yoff += 15;
  1675. draw2Dstring(xoff, yoff, FONT, (char *)"Needs:");
  1676. xoff += 5;
  1677. yoff += 15;
  1678. if (CurrentMuzz != -1)
  1679. {
  1680. sprintf(buf, " Water=%.2f", Muzzes[CurrentMuzz]->getNeed(Muzz::WATER));
  1681. draw2Dstring(xoff, yoff, FONT, buf);
  1682. yoff += 15;
  1683. sprintf(buf, " Food=%.2f", Muzzes[CurrentMuzz]->getNeed(Muzz::FOOD));
  1684. draw2Dstring(xoff, yoff, FONT, buf);
  1685. }
  1686. else
  1687. {
  1688. draw2Dstring(xoff, yoff, FONT, (char *)" Water=NA");
  1689. yoff += 15;
  1690. draw2Dstring(xoff, yoff, FONT, (char *)" Food=NA");
  1691. }
  1692. exit2Dmode();
  1693. }
  1694. // Display muzz help view.
  1695. void displayMuzzHelpView(void)
  1696. {
  1697. glMatrixMode(GL_MODELVIEW);
  1698. glLoadIdentity();
  1699. glViewport(Viewports[MUZZ_HELP_VIEWPORT].x, Viewports[MUZZ_HELP_VIEWPORT].y,
  1700. Viewports[MUZZ_HELP_VIEWPORT].width, Viewports[MUZZ_HELP_VIEWPORT].height);
  1701. glLineWidth(2.0);
  1702. enter2Dmode();
  1703. helpInfo(MUZZ_HELP_VIEWPORT);
  1704. draw2Dstring(5, 12, FONT, (char *)"Muzz");
  1705. exit2Dmode();
  1706. }
  1707. // Display the terrain help view.
  1708. void displayTerrainHelpView(void)
  1709. {
  1710. glMatrixMode(GL_MODELVIEW);
  1711. glLoadIdentity();
  1712. glViewport(Viewports[TERRAIN_HELP_VIEWPORT].x, Viewports[TERRAIN_HELP_VIEWPORT].y,
  1713. Viewports[TERRAIN_HELP_VIEWPORT].width, Viewports[TERRAIN_HELP_VIEWPORT].height);
  1714. glLineWidth(2.0);
  1715. enter2Dmode();
  1716. helpInfo(TERRAIN_HELP_VIEWPORT);
  1717. draw2Dstring(5, 12, FONT, (char *)"Terrain");
  1718. exit2Dmode();
  1719. }
  1720. // Display function.
  1721. void display(void)
  1722. {
  1723. // Clear display.
  1724. glutSetWindow(MainWindow);
  1725. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  1726. // Normal rendering?
  1727. if (renderMode == GL_RENDER)
  1728. {
  1729. // Display viewports.
  1730. if (Mod