Game.java 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. package me.hammerle.supersnuvi;
  2. import java.io.File;
  3. import java.util.ArrayList;
  4. import java.util.Arrays;
  5. import java.util.HashMap;
  6. import me.hammerle.snuviengine.api.ColorRenderer;
  7. import me.hammerle.snuviengine.api.Engine;
  8. import me.hammerle.snuviengine.api.FontRenderer;
  9. import me.hammerle.snuviengine.api.KeyBinding;
  10. import me.hammerle.snuviengine.api.Shader;
  11. import me.hammerle.supersnuvi.gamelogic.Level;
  12. import me.hammerle.supersnuvi.savegame.SimpleConfig;
  13. import me.hammerle.supersnuvi.tiles.*;
  14. import me.hammerle.supersnuvi.util.SoundUtils;
  15. public class Game extends Engine
  16. {
  17. public static final int MS_PER_TICK = 50;
  18. public static final float SECS_PER_TICK = MS_PER_TICK / 1000.0f;
  19. public static int getTicksForMillis(int millis)
  20. {
  21. return millis / MS_PER_TICK;
  22. }
  23. private static Game instance;
  24. public static Game get()
  25. {
  26. return instance;
  27. }
  28. // constants
  29. public static final NullTile FALLBACK_TILE = new NullTile();
  30. // tiles
  31. private final HashMap<Integer, Tile> registeredTiles = new HashMap<>();;
  32. // levels
  33. private Level currentLevel = null;
  34. private final Level[] levels;
  35. private int levelIndex = 0;
  36. // config and savegames
  37. private final SimpleConfig config = new SimpleConfig("options.txt", true);
  38. private final SimpleConfig[] saveSlots = new SimpleConfig[]
  39. {
  40. new SimpleConfig("slot1.txt", true),
  41. new SimpleConfig("slot2.txt", true),
  42. new SimpleConfig("slot3.txt", true)
  43. };
  44. private int screen = 0;
  45. private int startScreenIndex = 0;
  46. private int optionScreenIndex = 0;
  47. private int slotScreenIndex = 0;
  48. private boolean optionsDirty = false;
  49. // sound
  50. private boolean sound = config.getBoolean("sound", false);
  51. public Game()
  52. {
  53. instance = this;
  54. registerTiles();
  55. File[] files = new File("./levels").listFiles();
  56. Arrays.sort(files, (o1, o2) -> o1.compareTo(o2));
  57. ArrayList<Level> levelList = new ArrayList<>();
  58. for(File file : files)
  59. {
  60. if(file.isFile())
  61. {
  62. Level l = new Level(file);
  63. levelList.add(l);
  64. }
  65. }
  66. levels = levelList.toArray(new Level[levelList.size()]);
  67. }
  68. @Override
  69. public void init()
  70. {
  71. setMaxFps(120);
  72. setNanosPerTick(MS_PER_TICK * 1_000_000);
  73. }
  74. // -------------------------------------------------------------------------
  75. // tick, rendering
  76. // -------------------------------------------------------------------------
  77. @Override
  78. public void tick()
  79. {
  80. if(currentLevel != null)
  81. {
  82. SoundUtils.playSound(SoundUtils.Sound.SONG_1);
  83. SoundUtils.stopSound(SoundUtils.Sound.MENU_MUSIC);
  84. currentLevel.tick();
  85. // doing that here to prevent concurent modification
  86. if(currentLevel.shouldFinish())
  87. {
  88. String base = "level." + currentLevel.getFileName();
  89. SimpleConfig sp = saveSlots[slotScreenIndex];
  90. // save success
  91. sp.set(base, true);
  92. // update time, if a new highscore was scored
  93. double time = sp.getDouble(base + ".time", Integer.MAX_VALUE);
  94. if(currentLevel.getTime() < time)
  95. {
  96. sp.set(base + ".time", currentLevel.getTime());
  97. }
  98. // update bottles, if a new highscore was scored
  99. int bottles = sp.getInt(base + ".bottles", 0);
  100. if(currentLevel.getCurrentBottles() > bottles)
  101. {
  102. sp.set(base + ".bottles", currentLevel.getCurrentBottles());
  103. }
  104. // final save
  105. sp.save();
  106. currentLevel.resetLevel();
  107. currentLevel = null;
  108. return;
  109. }
  110. if(currentLevel.shouldReset())
  111. {
  112. if(currentLevel.resetLevel())
  113. {
  114. currentLevel = null;
  115. }
  116. }
  117. if(Keys.ESCAPE.isReleased())
  118. {
  119. currentLevel = null;
  120. }
  121. }
  122. else
  123. {
  124. SoundUtils.playSound(SoundUtils.Sound.MENU_MUSIC);
  125. SoundUtils.stopSound(SoundUtils.Sound.SONG_1);
  126. switch(screen)
  127. {
  128. case 0: // start screen
  129. {
  130. menuMove(() ->
  131. {
  132. // do nothing on escape in start screen
  133. }, () ->
  134. {
  135. switch(startScreenIndex)
  136. {
  137. case 0:
  138. screen = 1;
  139. break;
  140. case 1:
  141. screen = 2;
  142. break;
  143. case 2:
  144. stop();
  145. break;
  146. }
  147. }, () -> startScreenIndex++, () -> startScreenIndex--, () ->
  148. {
  149. if(startScreenIndex < 0)
  150. {
  151. startScreenIndex = 0;
  152. }
  153. else if(startScreenIndex >= 3)
  154. {
  155. startScreenIndex = 2;
  156. }
  157. });
  158. break;
  159. }
  160. case 1: // slot screen
  161. {
  162. menuMove(() ->
  163. {
  164. screen = 0;
  165. }, () ->
  166. {
  167. if(slotScreenIndex == 3)
  168. {
  169. screen = 0;
  170. return;
  171. }
  172. screen = 3;
  173. }, () -> slotScreenIndex++, () -> slotScreenIndex--, () ->
  174. {
  175. if(slotScreenIndex < 0)
  176. {
  177. slotScreenIndex = 0;
  178. }
  179. else if(slotScreenIndex >= 4)
  180. {
  181. slotScreenIndex = 3;
  182. }
  183. });
  184. break;
  185. }
  186. case 2: // option screen
  187. {
  188. menuMove(() ->
  189. {
  190. screen = 0;
  191. }, () ->
  192. {
  193. switch(optionScreenIndex)
  194. {
  195. case 0: // toggle sound
  196. sound = !sound;
  197. if(!sound)
  198. {
  199. SoundUtils.turnSoundOff();
  200. }
  201. optionsDirty = true;
  202. break;
  203. case 15: // save options
  204. Keys.write(config);
  205. config.set("sound", sound);
  206. config.save();
  207. optionsDirty = false;
  208. break;
  209. case 16: // go back
  210. screen = 0;
  211. break;
  212. default: // rebind keys
  213. Keys.rebind(Keys.get(optionScreenIndex - 1));
  214. optionsDirty = true;
  215. break;
  216. }
  217. }, () -> optionScreenIndex++, () -> optionScreenIndex--, () ->
  218. {
  219. if(optionScreenIndex < 0)
  220. {
  221. optionScreenIndex = 0;
  222. }
  223. int options = Keys.getAmount() + 3;
  224. if(optionScreenIndex >= options)
  225. {
  226. optionScreenIndex = options - 1;
  227. }
  228. });
  229. break;
  230. }
  231. case 3: // level choose screen
  232. {
  233. menuMove(() ->
  234. {
  235. screen = 1;
  236. }, () -> currentLevel = levels[levelIndex], () -> levelIndex++, () -> levelIndex--, () ->
  237. {
  238. if(levelIndex < 0)
  239. {
  240. levelIndex = 0;
  241. }
  242. else if(levelIndex >= levels.length)
  243. {
  244. levelIndex = levels.length - 1;
  245. }
  246. });
  247. break;
  248. }
  249. }
  250. }
  251. }
  252. public void tickTiles()
  253. {
  254. registeredTiles.values().forEach(tile -> tile.tick());
  255. }
  256. private final static int COLOR_BROWN = 0xFF13458B;
  257. private final static int COLOR_OVERLAY = 0x77000000;
  258. private String getKeyName(KeyBinding key)
  259. {
  260. if(key.isRebinding())
  261. {
  262. return "[...]";
  263. }
  264. return key.getName();
  265. }
  266. @Override
  267. public void renderTick(float lag)
  268. {
  269. if(currentLevel != null)
  270. {
  271. currentLevel.renderTick(lag);
  272. return;
  273. }
  274. Shader.translateTo(0.0f, 0.0f);
  275. Shader.updateMatrix();
  276. switch(screen)
  277. {
  278. case 0:
  279. {
  280. ColorRenderer cr = Shader.getColorRenderer();
  281. FontRenderer fr = Shader.getFontRenderer();
  282. float width = Shader.getViewWidth();
  283. float height = Shader.getViewHeight();
  284. float line = fr.getHeight();
  285. float left = width * 0.25f;
  286. float right = width * 0.75f;
  287. float top = (height - line * 7.0f) * 0.5f;
  288. float bottom = top + line * 7.0f;
  289. Shader.setTextureEnabled(false);
  290. Shader.setColorEnabled(true);
  291. // brown background
  292. cr.drawRectangle(0, 0, width, height, COLOR_BROWN);
  293. Shader.setBlendingEnabled(true);
  294. cr.drawRectangle(left, top, right, bottom, COLOR_OVERLAY);
  295. float base = top + (3 + startScreenIndex) * line;
  296. cr.drawRectangle(left, base, right, base + line, COLOR_OVERLAY);
  297. Shader.setBlendingEnabled(false);
  298. Shader.setTextureEnabled(true);
  299. float y = top + line;
  300. y = fr.drawString(left + line, y, "Super Snuvi");
  301. y += line;
  302. y = fr.drawString(left + line, y, "Start Game");
  303. y = fr.drawString(left + line, y, "Options");
  304. fr.drawString(left + line, y, "Exit Game");
  305. break;
  306. }
  307. case 1:
  308. {
  309. ColorRenderer cr = Shader.getColorRenderer();
  310. FontRenderer fr = Shader.getFontRenderer();
  311. float width = Shader.getViewWidth();
  312. float height = Shader.getViewHeight();
  313. float line = fr.getHeight();
  314. float left = width * 0.25f;
  315. float right = width * 0.75f;
  316. float top = (height - line * 8.0f) * 0.5f;
  317. float bottom = top + line * 8.0f;
  318. Shader.setTextureEnabled(false);
  319. Shader.setColorEnabled(true);
  320. // brown background
  321. cr.drawRectangle(0, 0, width, height, COLOR_BROWN);
  322. Shader.setBlendingEnabled(true);
  323. cr.drawRectangle(left, top, right, bottom, COLOR_OVERLAY);
  324. float base = top + (3 + slotScreenIndex) * line;
  325. cr.drawRectangle(left, base, right, base + line, COLOR_OVERLAY);
  326. Shader.setBlendingEnabled(false);
  327. Shader.setTextureEnabled(true);
  328. float y = top + line;
  329. y = fr.drawString(left + line, y, "Choose a Savegame");
  330. y += line;
  331. y = fr.drawString(left + line, y, "Slot 1");
  332. y = fr.drawString(left + line, y, "Slot 2");
  333. y = fr.drawString(left + line, y, "Slot 3");
  334. fr.drawString(left + line, y, "Back");
  335. break;
  336. }
  337. case 2:
  338. {
  339. ColorRenderer cr = Shader.getColorRenderer();
  340. FontRenderer fr = Shader.getFontRenderer();
  341. float width = Shader.getViewWidth();
  342. float height = Shader.getViewHeight();
  343. float line = fr.getHeight();
  344. float left = width * 0.2f;
  345. float right = width * 0.8f;
  346. float top = (height - line * 21.0f) * 0.5f;
  347. float bottom = top + line * 21.0f;
  348. Shader.setTextureEnabled(false);
  349. Shader.setColorEnabled(true);
  350. // brown background
  351. cr.drawRectangle(0, 0, width, height, COLOR_BROWN);
  352. Shader.setBlendingEnabled(true);
  353. cr.drawRectangle(left, top, right, bottom, COLOR_OVERLAY);
  354. float base = top + (3 + optionScreenIndex) * line;
  355. cr.drawRectangle(left, base, right, base + line, COLOR_OVERLAY);
  356. Shader.setBlendingEnabled(false);
  357. Shader.setTextureEnabled(true);
  358. left += line;
  359. float secLeft = right - line * 11;
  360. float y = top + line;
  361. y = fr.drawString(left, y, "Options");
  362. y += line;
  363. fr.drawString(left, y, "Sound");
  364. y = fr.drawString(secLeft, y, sound ? "yes" : "no");
  365. fr.drawString(left, y, "K: Up");
  366. y = fr.drawString(secLeft, y, getKeyName(Keys.UP));
  367. fr.drawString(left, y, "K: Down");
  368. y = fr.drawString(secLeft, y, getKeyName(Keys.DOWN));
  369. fr.drawString(left, y, "K: Left");
  370. y = fr.drawString(secLeft, y, getKeyName(Keys.LEFT));
  371. fr.drawString(left, y, "K: Right");
  372. y = fr.drawString(secLeft, y, getKeyName(Keys.RIGHT));
  373. fr.drawString(left, y, "K: Jump");
  374. y = fr.drawString(secLeft, y, getKeyName(Keys.JUMP));
  375. fr.drawString(left, y, "K: Run");
  376. y = fr.drawString(secLeft, y, getKeyName(Keys.RUN));
  377. fr.drawString(left, y, "K: Back");
  378. y = fr.drawString(secLeft, y, getKeyName(Keys.ESCAPE));
  379. fr.drawString(left, y, "K: Enter");
  380. y = fr.drawString(secLeft, y, getKeyName(Keys.ENTER));
  381. fr.drawString(left, y, "K: Combat");
  382. y = fr.drawString(secLeft, y, getKeyName(Keys.COMBAT));
  383. fr.drawString(left, y, "K: Switch Face");
  384. y = fr.drawString(secLeft, y, getKeyName(Keys.COMBAT_SWITCH_FACE));
  385. fr.drawString(left, y, "K: Dash/Dodge");
  386. y = fr.drawString(secLeft, y, getKeyName(Keys.COMBAT_DASH));
  387. fr.drawString(left, y, "K: Dash/Dodge");
  388. y = fr.drawString(secLeft, y, getKeyName(Keys.COMBAT_DODGE));
  389. fr.drawString(left, y, "K: Block");
  390. y = fr.drawString(secLeft, y, getKeyName(Keys.COMBAT_BLOCK));
  391. fr.drawString(left, y, "K: Attack");
  392. y = fr.drawString(secLeft, y, getKeyName(Keys.COMBAT_ATTACK));
  393. if(optionsDirty)
  394. {
  395. y = fr.drawString(left, y, true, "&cSave");
  396. }
  397. else
  398. {
  399. y = fr.drawString(left, y, true, "Save");
  400. }
  401. fr.drawString(left, y, true, "Back");
  402. break;
  403. }
  404. case 3:
  405. {
  406. ColorRenderer cr = Shader.getColorRenderer();
  407. FontRenderer fr = Shader.getFontRenderer();
  408. float width = Shader.getViewWidth();
  409. float height = Shader.getViewHeight();
  410. float line = fr.getHeight();
  411. int maxView = 7; // only for odd numbers
  412. int half = maxView / 2;
  413. float left = width * 0.2f;
  414. float right = width * 0.8f;
  415. float top = (height - line * (maxView + 4)) * 0.5f;
  416. float bottom = top + line * (maxView + 4);
  417. Shader.setTextureEnabled(false);
  418. Shader.setColorEnabled(true);
  419. // brown background
  420. cr.drawRectangle(0, 0, width, height, COLOR_BROWN);
  421. Shader.setBlendingEnabled(true);
  422. cr.drawRectangle(left, top, right, bottom, COLOR_OVERLAY);
  423. int firstIndex;
  424. int lastIndex;
  425. int baseIndex;
  426. if(levelIndex <= half) // first half
  427. {
  428. firstIndex = 0;
  429. lastIndex = Math.min(levels.length, maxView);
  430. baseIndex = levelIndex;
  431. }
  432. else if(levelIndex >= levels.length - half) // last half
  433. {
  434. lastIndex = levels.length;
  435. firstIndex = Math.max(lastIndex - maxView, 0);
  436. if(levels.length <= maxView)
  437. {
  438. baseIndex = levelIndex;
  439. }
  440. else
  441. {
  442. baseIndex = levelIndex - (levels.length - half - 1) + half;
  443. }
  444. }
  445. else // middle
  446. {
  447. firstIndex = levelIndex - half;
  448. lastIndex = firstIndex + maxView;
  449. baseIndex = half;
  450. }
  451. float base = top + (3 + baseIndex) * line;
  452. cr.drawRectangle(left, base, right, base + line, COLOR_OVERLAY);
  453. Shader.setBlendingEnabled(false);
  454. Shader.setTextureEnabled(true);
  455. left += line;
  456. float secLeft = right - line * 12;
  457. float thirdLeft = right - line * 6;
  458. float y = top + line;
  459. y = fr.drawString(left, y, "Choose a Level ...");
  460. y += line;
  461. if(firstIndex >= 1)
  462. {
  463. y = fr.drawString(left, y, "...");
  464. firstIndex++;
  465. }
  466. SimpleConfig sc = saveSlots[slotScreenIndex];
  467. for(int i = firstIndex; i < lastIndex - 1; i++)
  468. {
  469. Level l = levels[i];
  470. fr.drawString(left, y, l.getName());
  471. fr.drawString(secLeft, y, l.formatBottles(sc.getInt("level." + l.getFileName() + ".bottles", 0)));
  472. y = fr.drawString(thirdLeft, y, l.formatTime(sc.getFloat("level." + l.getFileName() + ".time", 0)));
  473. }
  474. if(lastIndex == levels.length)
  475. {
  476. Level l = levels[lastIndex - 1];
  477. fr.drawString(left, y, l.getName());
  478. fr.drawString(secLeft, y, l.formatBottles(sc.getInt("level." + l.getFileName() + ".bottles", 0)));
  479. fr.drawString(thirdLeft, y, l.formatTime(sc.getFloat("level." + l.getFileName() + ".time", 0)));
  480. }
  481. else
  482. {
  483. fr.drawString(left, y, "...");
  484. }
  485. break;
  486. }
  487. }
  488. }
  489. // -------------------------------------------------------------------------
  490. // config
  491. // -------------------------------------------------------------------------
  492. public boolean isSoundEnabled()
  493. {
  494. return sound;
  495. }
  496. // -------------------------------------------------------------------------
  497. // tile stuff
  498. // -------------------------------------------------------------------------
  499. private void registerTiles()
  500. {
  501. // dirt
  502. for(int i = 0; i < 16; i++)
  503. {
  504. registeredTiles.put(i, new BaseBoxTile(0.125f, 0.0f, 0.1875f, 0.0625f));
  505. }
  506. // grass
  507. BaseBoxTile grass = new BaseBoxTile(0.0625f, 0.0f, 0.125f, 0.0625f);
  508. registeredTiles.put(20, grass);
  509. registeredTiles.put(21, grass);
  510. registeredTiles.put(22, grass);
  511. registeredTiles.put(23, grass);
  512. registeredTiles.put(28, grass);
  513. registeredTiles.put(29, grass);
  514. registeredTiles.put(30, grass);
  515. registeredTiles.put(31, grass);
  516. // bottled soul
  517. registeredTiles.put(32, new BottledSoulTile(1));
  518. registeredTiles.put(33, new BottledSoulTile(2));
  519. registeredTiles.put(34, new BottledSoulTile(3));
  520. // bounce shroom
  521. registeredTiles.put(48, new TrampolinTile());
  522. // crumbling stones
  523. registeredTiles.put(64, new CrumblingStoneTile());
  524. // spike trap
  525. registeredTiles.put(80, new SpikeTile());
  526. // water
  527. for(int i = 0; i < 16; i++)
  528. {
  529. registeredTiles.put(96 + i, new WaterTile(15 - i));
  530. }
  531. // snuvi start block
  532. registeredTiles.put(StartTile.ID, new StartTile());
  533. // sky
  534. registeredTiles.put(128, new SkyTile());
  535. // slippery slime
  536. SlipperyTile slime = new SlipperyTile();
  537. registeredTiles.put(148, slime);
  538. registeredTiles.put(149, slime);
  539. registeredTiles.put(150, slime);
  540. registeredTiles.put(151, slime);
  541. registeredTiles.put(156, slime);
  542. registeredTiles.put(157, slime);
  543. registeredTiles.put(158, slime);
  544. registeredTiles.put(159, slime);
  545. // end level
  546. registeredTiles.put(160, new GoalTile(0.25f, 0.125f, 0.3125f, 0.1875f));
  547. registeredTiles.put(161, new GoalTile(0.25f, 0.0625f, 0.3125f, 0.125f));
  548. // thorns
  549. registeredTiles.put(176, new KillTile(0.0f, 0.125f, 0.0625f, 0.1875f, 2));
  550. registeredTiles.put(177, new KillTile(0.0625f, 0.125f, 0.125f, 0.1875f, 2));
  551. registeredTiles.put(178, new KillTile(0.125f, 0.125f, 0.1875f, 0.1875f, 2));
  552. registeredTiles.put(179, new KillTile(0.0f, 0.125f, 0.0625f, 0.1875f, -3));
  553. registeredTiles.put(180, new KillTile(0.0625f, 0.125f, 0.125f, 0.1875f, -3));
  554. registeredTiles.put(181, new KillTile(0.125f, 0.125f, 0.1875f, 0.1875f, -3));
  555. // decoration shrooms
  556. registeredTiles.put(208, new DecoShroomTile(0.0f, 0.21875f, 0.0625f, 0.25f));
  557. registeredTiles.put(209, new DecoShroomTile(0.0f, 0.1875f, 0.0625f, 0.21875f));
  558. registeredTiles.put(210, new DecoShroomTile(0.0625f, 0.21875f, 0.125f, 0.25f));
  559. registeredTiles.put(211, new DecoShroomTile(0.0625f, 0.1875f, 0.125f, 0.21875f));
  560. // fog, starting late to make length changes possible
  561. for(int i = 0; i < 16; i++)
  562. {
  563. registeredTiles.put(16000 + i, new FogTile((i + 1) / 16.0));
  564. }
  565. // london stuff
  566. //registeredTiles.put(224, new BaseBoxTile("london_background/london_background"));
  567. // london streets
  568. for(int i = 0; i < 16; i++)
  569. {
  570. //registeredTiles.put(240 + i, new BaseBoxTile("london_streets/london_streets" + i));
  571. }
  572. // london street light
  573. for(int i = 0; i < 25; i++)
  574. {
  575. //registeredTiles.put(256 + i, new BaseBoxTile("street_light/street_light" + (i % 5) + "_" + (i / 5)));
  576. }
  577. }
  578. public Tile getTile(int id)
  579. {
  580. return registeredTiles.getOrDefault(id, FALLBACK_TILE);
  581. }
  582. public void resetTiles()
  583. {
  584. registeredTiles.values().forEach(v -> v.reset());
  585. }
  586. private void menuMove(Runnable esc, Runnable enter, Runnable down, Runnable up, Runnable end)
  587. {
  588. if(Keys.ESCAPE.isReleased())
  589. {
  590. esc.run();
  591. return;
  592. }
  593. if(Keys.ENTER.isReleased())
  594. {
  595. enter.run();
  596. return;
  597. }
  598. if(Keys.DOWN.getTime() > 4)
  599. {
  600. Keys.DOWN.setTime(0);
  601. down.run();
  602. }
  603. else if(Keys.UP.getTime() > 4)
  604. {
  605. Keys.UP.setTime(0);
  606. up.run();
  607. }
  608. else if(Keys.DOWN.isReleased())
  609. {
  610. down.run();
  611. }
  612. else if(Keys.UP.isReleased())
  613. {
  614. up.run();
  615. }
  616. end.run();
  617. }
  618. }