commit 8e83234a8709533c3724a71c8bd2368df074b619 Author: Woody Folsom Date: Tue Mar 6 11:42:35 2012 -0500 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..347bb94 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +bin +build +classes +dist +docs +.project +.settings +.classpath diff --git a/DetailedInfo.txt b/DetailedInfo.txt new file mode 100644 index 0000000..cb8cd11 --- /dev/null +++ b/DetailedInfo.txt @@ -0,0 +1,261 @@ +StartTime = -17 +RightMove: StTime = 94 EdTime = 32 +Jump: StTime = 119 EdTime = 132 +Jump: StTime = 139 EdTime = 155 +RightMove: StTime = 128 EdTime = 64 +RightMove: StTime = 161 EdTime = 65 +Jump: StTime = 158 EdTime = 170 +CollectCoin: time = 176 +CollectCoin: time = 177 +Jump: StTime = 176 EdTime = 184 +RightMove: StTime = 163 EdTime = 89 +BlockCoinDestroy: time = 190 +Jump: StTime = 188 EdTime = 196 +BlockPowerDestroy: time = 208 +Jump: StTime = 206 EdTime = 214 +RightMove: StTime = 200 EdTime = 112 +LeftMove: StTime = 224 EdTime = 2 +RightMove: StTime = 227 EdTime = 125 +Jump: StTime = 234 EdTime = 248 +LittleState: StTime = -17 EdTime = 251 +LeftMove: StTime = 241 EdTime = 31 +StompKill: EnemyType = 2 time = 286 +Jump: StTime = 271 EdTime = 297 +Jump: StTime = 302 EdTime = 312 +Jump: StTime = 325 EdTime = 344 +RightMove: StTime = 271 EdTime = 200 +RightMove: StTime = 347 EdTime = 201 +RightMove: StTime = 352 EdTime = 202 +Jump: StTime = 352 EdTime = 364 +CollectCoin: time = 372 +CollectCoin: time = 375 +Jump: StTime = 392 EdTime = 407 +LargeState: StTime = 251 EdTime = 407 +RightMove: StTime = 354 EdTime = 294 +RightMove: StTime = 447 EdTime = 295 +RightMove: StTime = 449 EdTime = 296 +Jump: StTime = 448 EdTime = 457 +RightMove: StTime = 451 EdTime = 328 +RightMove: StTime = 484 EdTime = 329 +RightMove: StTime = 486 EdTime = 330 +Jump: StTime = 484 EdTime = 494 +CollectCoin: time = 519 +CollectCoin: time = 519 +CollectCoin: time = 522 +Jump: StTime = 519 EdTime = 527 +CollectCoin: time = 530 +CollectCoin: time = 532 +BlockCoinDestroy: time = 532 +Jump: StTime = 530 EdTime = 538 +RightMove: StTime = 488 EdTime = 385 +Jump: StTime = 545 EdTime = 553 +LeftMove: StTime = 544 EdTime = 45 +BlockCoinDestroy: time = 560 +Jump: StTime = 558 EdTime = 566 +RightMove: StTime = 559 EdTime = 396 +Jump: StTime = 570 EdTime = 578 +LeftMove: StTime = 571 EdTime = 54 +RightMove: StTime = 581 EdTime = 398 +Jump: StTime = 590 EdTime = 598 +LeftMove: StTime = 584 EdTime = 71 +RightMove: StTime = 602 EdTime = 403 +Jump: StTime = 603 EdTime = 611 +Jump: StTime = 614 EdTime = 622 +Jump: StTime = 626 EdTime = 634 +LeftMove: StTime = 608 EdTime = 98 +RightMove: StTime = 636 EdTime = 433 +RightMove: StTime = 667 EdTime = 434 +Jump: StTime = 664 EdTime = 676 +RightMove: StTime = 669 EdTime = 442 +RightMove: StTime = 681 EdTime = 443 +RightMove: StTime = 683 EdTime = 444 +Jump: StTime = 681 EdTime = 694 +CollectCoin: time = 716 +CollectCoin: time = 718 +CollectCoin: time = 725 +CollectCoin: time = 725 +Jump: StTime = 716 EdTime = 729 +CollectCoin: time = 733 +CollectCoin: time = 741 +Jump: StTime = 731 EdTime = 744 +Jump: StTime = 751 EdTime = 765 +Jump: StTime = 801 EdTime = 811 +CollectCoin: time = 821 +CollectCoin: time = 821 +RightMove: StTime = 685 EdTime = 583 +Jump: StTime = 821 EdTime = 829 +BlockCoinDestroy: time = 836 +Jump: StTime = 834 EdTime = 842 +LeftMove: StTime = 832 EdTime = 111 +CollectCoin: time = 850 +LeftMove: StTime = 846 EdTime = 124 +CollectCoin: time = 859 +Jump: StTime = 850 EdTime = 863 +Jump: StTime = 864 EdTime = 872 +RightMove: StTime = 860 EdTime = 600 +Jump: StTime = 880 EdTime = 888 +BlockPowerDestroy: time = 895 +Jump: StTime = 893 EdTime = 901 +RightMove: StTime = 882 EdTime = 624 +LittleState: StTime = 407 EdTime = 919 +Jump: StTime = 915 EdTime = 951 +BlockPowerDestroy: time = 973 +CollectCoin: time = 974 +CollectCoin: time = 977 +Jump: StTime = 972 EdTime = 978 +CollectCoin: time = 982 +Jump: StTime = 984 EdTime = 990 +RightMove: StTime = 912 EdTime = 709 +Jump: StTime = 996 EdTime = 1010 +Jump: StTime = 1018 EdTime = 1024 +BlockCoinDestroy: time = 1030 +Jump: StTime = 1029 EdTime = 1035 +LeftMove: StTime = 1012 EdTime = 148 +LeftMove: StTime = 1039 EdTime = 165 +LargeState: StTime = 919 EdTime = 1060 +Jump: StTime = 1054 EdTime = 1081 +RightMove: StTime = 1057 EdTime = 749 +LeftMove: StTime = 1098 EdTime = 167 +Jump: StTime = 1105 EdTime = 1117 +StompKill: EnemyType = 2 time = 1133 +Jump: StTime = 1119 EdTime = 1144 +RunState: StTime = 1144 EdTime = 1148 +RunState: StTime = 1158 EdTime = 1162 +RightMove: StTime = 1169 EdTime = 751 +RightMove: StTime = 1172 EdTime = 753 +Jump: StTime = 1165 EdTime = 1175 +RightMove: StTime = 1183 EdTime = 757 +LeftMove: StTime = 1188 EdTime = 172 +RightMove: StTime = 1194 EdTime = 758 +RightMove: StTime = 1196 EdTime = 759 +BlockCoinDestroy: time = 1206 +Jump: StTime = 1205 EdTime = 1211 +Jump: StTime = 1221 EdTime = 1227 +RightMove: StTime = 1203 EdTime = 792 +Jump: StTime = 1233 EdTime = 1245 +CollectCoin: time = 1259 +Jump: StTime = 1262 EdTime = 1268 +RightMove: StTime = 1237 EdTime = 824 +Jump: StTime = 1278 EdTime = 1284 +RightMove: StTime = 1291 EdTime = 832 +Jump: StTime = 1293 EdTime = 1306 +CollectCoin: time = 1309 +Jump: StTime = 1311 EdTime = 1317 +CollectCoin: time = 1322 +Jump: StTime = 1325 EdTime = 1331 +CollectCoin: time = 1331 +Jump: StTime = 1340 EdTime = 1346 +Jump: StTime = 1356 EdTime = 1371 +Jump: StTime = 1378 EdTime = 1391 +Jump: StTime = 1401 EdTime = 1413 +Jump: StTime = 1456 EdTime = 1468 +Jump: StTime = 1509 EdTime = 1522 +Jump: StTime = 1533 EdTime = 1545 +Jump: StTime = 1560 EdTime = 1579 +RightMove: StTime = 1309 EdTime = 1104 +LeftMove: StTime = 1582 EdTime = 183 +Jump: StTime = 1594 EdTime = 1609 +Jump: StTime = 1616 EdTime = 1628 +Jump: StTime = 1630 EdTime = 1640 +Jump: StTime = 1647 EdTime = 1667 +Jump: StTime = 1671 EdTime = 1683 +Jump: StTime = 1722 EdTime = 1734 +Jump: StTime = 1738 EdTime = 1752 +CollectCoin: time = 1752 +CollectCoin: time = 1754 +CollectCoin: time = 1757 +CollectCoin: time = 1769 +CollectCoin: time = 1772 +FireState: StTime = 1060 EdTime = 1773 +CollectCoin: time = 1793 +CollectCoin: time = 1796 +CollectCoin: time = 1799 +CollectCoin: time = 1802 +Jump: StTime = 1799 EdTime = 1805 +RightMove: StTime = 1594 EdTime = 1321 +Jump: StTime = 1812 EdTime = 1818 +BlockCoinDestroy: time = 1824 +Jump: StTime = 1823 EdTime = 1829 +RightMove: StTime = 1821 EdTime = 1339 +Jump: StTime = 1835 EdTime = 1841 +Jump: StTime = 1851 EdTime = 1857 +RightMove: StTime = 1845 EdTime = 1359 +StompKill: EnemyType = 2 time = 1883 +RightMove: StTime = 1867 EdTime = 1383 +Jump: StTime = 1869 EdTime = 1894 +CollectCoin: time = 1900 +CollectCoin: time = 1904 +Jump: StTime = 1903 EdTime = 1909 +BlockPowerDestroy: time = 1914 +Jump: StTime = 1913 EdTime = 1919 +RightMove: StTime = 1892 EdTime = 1413 +Jump: StTime = 1929 EdTime = 1935 +RightMove: StTime = 1923 EdTime = 1431 +LargeState: StTime = 1773 EdTime = 1948 +LeftMove: StTime = 1942 EdTime = 210 +Jump: StTime = 1943 EdTime = 1976 +LeftMove: StTime = 1976 EdTime = 215 +StompKill: EnemyType = 2 time = 1984 +Jump: StTime = 1980 EdTime = 1995 +RightMove: StTime = 1982 EdTime = 1447 +Jump: StTime = 2009 EdTime = 2024 +Jump: StTime = 2046 EdTime = 2059 +Jump: StTime = 2083 EdTime = 2096 +RunState: StTime = 2122 EdTime = 2126 +RunState: StTime = 2148 EdTime = 2151 +Jump: StTime = 2139 EdTime = 2155 +RunState: StTime = 2156 EdTime = 2159 +RunState: StTime = 2163 EdTime = 2166 +RunState: StTime = 2170 EdTime = 2173 +LeftMove: StTime = 2028 EdTime = 372 +Jump: StTime = 2202 EdTime = 2218 +Jump: StTime = 2224 EdTime = 2236 +LeftMove: StTime = 2232 EdTime = 378 +RunState: StTime = 2294 EdTime = 2297 +RightMove: StTime = 2239 EdTime = 1511 +RunState: StTime = 2316 EdTime = 2319 +RunState: StTime = 2323 EdTime = 2326 +RunState: StTime = 2330 EdTime = 2333 +RunState: StTime = 2336 EdTime = 2339 +RightMove: StTime = 2332 EdTime = 1519 +RunState: StTime = 2346 EdTime = 2348 +FireKill: EnemyType =2time = 2349 +RunState: StTime = 2350 EdTime = 2353 +LeftMove: StTime = 2344 EdTime = 387 +RunState: StTime = 2356 EdTime = 2357 +RunState: StTime = 2362 EdTime = 2365 +RunState: StTime = 2367 EdTime = 2371 +RunState: StTime = 2373 EdTime = 2376 +RunState: StTime = 2377 EdTime = 2381 +RightMove: StTime = 2385 EdTime = 1543 +RightMove: StTime = 2410 EdTime = 1544 +RightMove: StTime = 2412 EdTime = 1545 +RightMove: StTime = 2414 EdTime = 1546 +RightMove: StTime = 2416 EdTime = 1547 +RightMove: StTime = 2418 EdTime = 1559 +Jump: StTime = 2416 EdTime = 2431 +RightMove: StTime = 2431 EdTime = 1560 +RightMove: StTime = 2433 EdTime = 1561 +RightMove: StTime = 2435 EdTime = 1562 +RightMove: StTime = 2437 EdTime = 1563 +RightMove: StTime = 2439 EdTime = 1564 +RightMove: StTime = 2441 EdTime = 1565 +RightMove: StTime = 2443 EdTime = 1566 +Jump: StTime = 2441 EdTime = 2451 +Jump: StTime = 2457 EdTime = 2472 +Jump: StTime = 2506 EdTime = 2512 +Jump: StTime = 2540 EdTime = 2546 +RightMove: StTime = 2445 EdTime = 1676 +Jump: StTime = 2570 EdTime = 2576 +LeftMove: StTime = 2556 EdTime = 408 +RightMove: StTime = 2578 EdTime = 1684 +Jump: StTime = 2593 EdTime = 2599 +LeftMove: StTime = 2587 EdTime = 424 +RightMove: StTime = 2604 EdTime = 1705 +RightMove: StTime = 2626 EdTime = 1706 +RightMove: StTime = 2628 EdTime = 1707 +Jump: StTime = 2627 EdTime = 2642 +Jump: StTime = 2651 EdTime = 2661 +Totaltime = 2678 +RightMove: StTime = 2630 EdTime = 1738 +FireState: StTime = 1948 EdTime = 2661 diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..c6fb39f --- /dev/null +++ b/build.xml @@ -0,0 +1,91 @@ + + + simple example build file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/jdom.jar b/lib/jdom.jar new file mode 100644 index 0000000..288e64c Binary files /dev/null and b/lib/jdom.jar differ diff --git a/lib/junit-4.10.jar b/lib/junit-4.10.jar new file mode 100644 index 0000000..bf5c0b9 Binary files /dev/null and b/lib/junit-4.10.jar differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 Binary files /dev/null and b/lib/slf4j-api-1.6.4.jar differ diff --git a/lib/xuggle-xuggler.jar b/lib/xuggle-xuggler.jar new file mode 100644 index 0000000..1c94174 Binary files /dev/null and b/lib/xuggle-xuggler.jar differ diff --git a/player.txt b/player.txt new file mode 100644 index 0000000..4f8057c Binary files /dev/null and b/player.txt differ diff --git a/res/Thumbs.db b/res/Thumbs.db new file mode 100644 index 0000000..55ece13 Binary files /dev/null and b/res/Thumbs.db differ diff --git a/res/abkey.png b/res/abkey.png new file mode 100644 index 0000000..e2bd814 Binary files /dev/null and b/res/abkey.png differ diff --git a/res/bgsheet.png b/res/bgsheet.png new file mode 100644 index 0000000..0891db3 Binary files /dev/null and b/res/bgsheet.png differ diff --git a/res/endscene.gif b/res/endscene.gif new file mode 100644 index 0000000..73aa011 Binary files /dev/null and b/res/endscene.gif differ diff --git a/res/enemysheet.png b/res/enemysheet.png new file mode 100644 index 0000000..4a4880b Binary files /dev/null and b/res/enemysheet.png differ diff --git a/res/firemariosheet.png b/res/firemariosheet.png new file mode 100644 index 0000000..16eeace Binary files /dev/null and b/res/firemariosheet.png differ diff --git a/res/font.gif b/res/font.gif new file mode 100644 index 0000000..213d7a0 Binary files /dev/null and b/res/font.gif differ diff --git a/res/gameovergost.gif b/res/gameovergost.gif new file mode 100644 index 0000000..5199a2e Binary files /dev/null and b/res/gameovergost.gif differ diff --git a/res/itemsheet.png b/res/itemsheet.png new file mode 100644 index 0000000..056880b Binary files /dev/null and b/res/itemsheet.png differ diff --git a/res/keys.png b/res/keys.png new file mode 100644 index 0000000..f72373e Binary files /dev/null and b/res/keys.png differ diff --git a/res/logo.gif b/res/logo.gif new file mode 100644 index 0000000..3fd6fd2 Binary files /dev/null and b/res/logo.gif differ diff --git a/res/mapsheet.png b/res/mapsheet.png new file mode 100644 index 0000000..6e776a7 Binary files /dev/null and b/res/mapsheet.png differ diff --git a/res/mariosheet.png b/res/mariosheet.png new file mode 100644 index 0000000..9577595 Binary files /dev/null and b/res/mariosheet.png differ diff --git a/res/mus/smb3map1.mid b/res/mus/smb3map1.mid new file mode 100644 index 0000000..e48140b Binary files /dev/null and b/res/mus/smb3map1.mid differ diff --git a/res/mus/smb3ovr1.mid b/res/mus/smb3ovr1.mid new file mode 100644 index 0000000..f0230fa Binary files /dev/null and b/res/mus/smb3ovr1.mid differ diff --git a/res/mus/smb3undr.mid b/res/mus/smb3undr.mid new file mode 100644 index 0000000..dc68de7 Binary files /dev/null and b/res/mus/smb3undr.mid differ diff --git a/res/mus/smwfortress.mid b/res/mus/smwfortress.mid new file mode 100644 index 0000000..ccf3fda Binary files /dev/null and b/res/mus/smwfortress.mid differ diff --git a/res/mus/smwovr1.mid b/res/mus/smwovr1.mid new file mode 100644 index 0000000..3c8b724 Binary files /dev/null and b/res/mus/smwovr1.mid differ diff --git a/res/mus/smwovr2.mid b/res/mus/smwovr2.mid new file mode 100644 index 0000000..5e6c9d4 Binary files /dev/null and b/res/mus/smwovr2.mid differ diff --git a/res/mus/smwtitle.mid b/res/mus/smwtitle.mid new file mode 100644 index 0000000..5e79707 Binary files /dev/null and b/res/mus/smwtitle.mid differ diff --git a/res/particlesheet.png b/res/particlesheet.png new file mode 100644 index 0000000..45c282e Binary files /dev/null and b/res/particlesheet.png differ diff --git a/res/racoonmariosheet.png b/res/racoonmariosheet.png new file mode 100644 index 0000000..4dae024 Binary files /dev/null and b/res/racoonmariosheet.png differ diff --git a/res/smallmariosheet.png b/res/smallmariosheet.png new file mode 100644 index 0000000..52aae25 Binary files /dev/null and b/res/smallmariosheet.png differ diff --git a/res/snd/1-up.wav b/res/snd/1-up.wav new file mode 100644 index 0000000..6b94a69 Binary files /dev/null and b/res/snd/1-up.wav differ diff --git a/res/snd/breakblock.wav b/res/snd/breakblock.wav new file mode 100644 index 0000000..60c85bc Binary files /dev/null and b/res/snd/breakblock.wav differ diff --git a/res/snd/bump.wav b/res/snd/bump.wav new file mode 100644 index 0000000..5ab8c03 Binary files /dev/null and b/res/snd/bump.wav differ diff --git a/res/snd/cannon.wav b/res/snd/cannon.wav new file mode 100644 index 0000000..500c4c2 Binary files /dev/null and b/res/snd/cannon.wav differ diff --git a/res/snd/coin.wav b/res/snd/coin.wav new file mode 100644 index 0000000..eb4baa0 Binary files /dev/null and b/res/snd/coin.wav differ diff --git a/res/snd/death.wav b/res/snd/death.wav new file mode 100644 index 0000000..206db23 Binary files /dev/null and b/res/snd/death.wav differ diff --git a/res/snd/exit.wav b/res/snd/exit.wav new file mode 100644 index 0000000..6f9c8fc Binary files /dev/null and b/res/snd/exit.wav differ diff --git a/res/snd/fireball.wav b/res/snd/fireball.wav new file mode 100644 index 0000000..61c2f19 Binary files /dev/null and b/res/snd/fireball.wav differ diff --git a/res/snd/jump.wav b/res/snd/jump.wav new file mode 100644 index 0000000..c2833ea Binary files /dev/null and b/res/snd/jump.wav differ diff --git a/res/snd/kick.wav b/res/snd/kick.wav new file mode 100644 index 0000000..e3248f1 Binary files /dev/null and b/res/snd/kick.wav differ diff --git a/res/snd/message.wav b/res/snd/message.wav new file mode 100644 index 0000000..b05ca41 Binary files /dev/null and b/res/snd/message.wav differ diff --git a/res/snd/pipe.wav b/res/snd/pipe.wav new file mode 100644 index 0000000..2d4186e Binary files /dev/null and b/res/snd/pipe.wav differ diff --git a/res/snd/powerdown.wav b/res/snd/powerdown.wav new file mode 100644 index 0000000..662b534 Binary files /dev/null and b/res/snd/powerdown.wav differ diff --git a/res/snd/powerup.wav b/res/snd/powerup.wav new file mode 100644 index 0000000..694421a Binary files /dev/null and b/res/snd/powerup.wav differ diff --git a/res/snd/sprout.wav b/res/snd/sprout.wav new file mode 100644 index 0000000..f8ee602 Binary files /dev/null and b/res/snd/sprout.wav differ diff --git a/res/snd/stagestart.wav b/res/snd/stagestart.wav new file mode 100644 index 0000000..41531bf Binary files /dev/null and b/res/snd/stagestart.wav differ diff --git a/res/snd/stomp.wav b/res/snd/stomp.wav new file mode 100644 index 0000000..d460545 Binary files /dev/null and b/res/snd/stomp.wav differ diff --git a/res/test.lvl b/res/test.lvl new file mode 100644 index 0000000..97a1c29 Binary files /dev/null and b/res/test.lvl differ diff --git a/res/tiles.dat b/res/tiles.dat new file mode 100644 index 0000000..d558418 Binary files /dev/null and b/res/tiles.dat differ diff --git a/res/title.gif b/res/title.gif new file mode 100644 index 0000000..2c309aa Binary files /dev/null and b/res/title.gif differ diff --git a/res/tweak.gif b/res/tweak.gif new file mode 100644 index 0000000..61073c6 Binary files /dev/null and b/res/tweak.gif differ diff --git a/res/worldmap.png b/res/worldmap.png new file mode 100644 index 0000000..467ad81 Binary files /dev/null and b/res/worldmap.png differ diff --git a/src/dk/itu/.DS_Store b/src/dk/itu/.DS_Store new file mode 100644 index 0000000..1286b83 Binary files /dev/null and b/src/dk/itu/.DS_Store differ diff --git a/src/dk/itu/mario/.DS_Store b/src/dk/itu/mario/.DS_Store new file mode 100644 index 0000000..f290035 Binary files /dev/null and b/src/dk/itu/mario/.DS_Store differ diff --git a/src/dk/itu/mario/MarioInterface/.DS_Store b/src/dk/itu/mario/MarioInterface/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/src/dk/itu/mario/MarioInterface/.DS_Store differ diff --git a/src/dk/itu/mario/MarioInterface/Constraints.java b/src/dk/itu/mario/MarioInterface/Constraints.java new file mode 100644 index 0000000..d2d0877 --- /dev/null +++ b/src/dk/itu/mario/MarioInterface/Constraints.java @@ -0,0 +1,10 @@ +package dk.itu.mario.MarioInterface; + +public interface Constraints { + // the submitted level should has exactly the following information + public static int levelWidth= 320; + public static int gaps = 10; + public static int turtels = 7; + public static int coinBlocks = 10; + +} diff --git a/src/dk/itu/mario/MarioInterface/GamePlay.java b/src/dk/itu/mario/MarioInterface/GamePlay.java new file mode 100644 index 0000000..9d618c7 --- /dev/null +++ b/src/dk/itu/mario/MarioInterface/GamePlay.java @@ -0,0 +1,101 @@ +package dk.itu.mario.MarioInterface; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +public class GamePlay implements Serializable { + + private static final long serialVersionUID = 1L; + + public int completionTime; // counts only the current run on the level, + // excluding death games + public int totalTime;// sums all the time, including from previous games if + // player died + public int jumpsNumber; // total number of jumps + public int duckNumber; // total number of ducks + public int timeSpentDucking; // time spent in ducking mode + public int timesPressedRun;// number of times the run key pressed + public int timeSpentRunning; // total time spent running + public int timeRunningRight; // total time spent running to the right + public int timeRunningLeft;// total time spent running to the left + public int emptyBlocksDestroyed; // number of empty blocks destroyed + public int coinsCollected; // number of coins collected + public int coinBlocksDestroyed; // number of coin block destroyed + public int powerBlocksDestroyed; // number of power block destroyed + public int kickedShells; // number of shells Mario kicked + public int enemyKillByFire; // number of enemies killed by shooting them + public int enemyKillByKickingShell; // number of enemies killed by kicking a + // shell on them + public int totalTimeLittleMode; // total time spent in little mode + public int totalTimeLargeMode; // total time spent in large mode + public int totalTimeFireMode; // total time spent in fire mode + public int timesSwichingPower; // number of Times Switched Between Little, + // Large or Fire Mario + public double aimlessJumps; // number of jumps without a reason + public double percentageBlocksDestroyed; // percentage of all blocks + // destroyed + public double percentageCoinBlocksDestroyed; // percentage of coin blocks + // destroyed + public double percentageEmptyBlockesDestroyed; // percentage of empty blocks + // destroyed + public double percentagePowerBlockDestroyed; // percentage of power blocks + // destroyed + public double timesOfDeathByFallingIntoGap; // number of death by falling + // into a gap + public int totalEnemies; // total number of enemies + public int totalEmptyBlocks; // total number of empty blocks + public int totalCoinBlocks; // total number of coin blocks + public int totalpowerBlocks; // total number of power blocks + public int totalCoins; // total number of coins + public int timesOfDeathByRedTurtle; // number of times Mario died by red + // turtle + public int timesOfDeathByGoomba; // number of times Mario died by Goomba + public int timesOfDeathByGreenTurtle; // number of times Mario died by green + // turtle + public int timesOfDeathByArmoredTurtle; // number of times Mario died by + // Armored turtle + public int timesOfDeathByJumpFlower; // number of times Mario died by Jump + // Flower + public int timesOfDeathByCannonBall; // number of time Mario died by Cannon + // Ball + public int timesOfDeathByChompFlower; // number of times Mario died by Chomp + // Flower + public int RedTurtlesKilled; // number of Red Turtle Mario killed + public int GreenTurtlesKilled;// number of Green Turtle Mario killed + public int ArmoredTurtlesKilled; // number of Armored Turtle Mario killed + public int GoombasKilled; // number of Goombas Mario killed + public int CannonBallKilled; // number of Cannon Ball Mario killed + public int JumpFlowersKilled; // number of Jump Flower Mario killed + public int ChompFlowersKilled; // number of Chomp Flower Mario killed + + public void write(String fileName) { + ObjectOutputStream out = null; + try { + FileOutputStream fos = new FileOutputStream(fileName); + out = new ObjectOutputStream(fos); + out.writeObject(this); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + public static GamePlay read(String fileName) { + FileInputStream fis = null; + ObjectInputStream in = null; + GamePlay gp = null; + try { + fis = new FileInputStream(fileName); + in = new ObjectInputStream(fis); + gp = (GamePlay) in.readObject(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return gp; + } +} diff --git a/src/dk/itu/mario/MarioInterface/LevelGenerator.java b/src/dk/itu/mario/MarioInterface/LevelGenerator.java new file mode 100644 index 0000000..02d818e --- /dev/null +++ b/src/dk/itu/mario/MarioInterface/LevelGenerator.java @@ -0,0 +1,12 @@ +package dk.itu.mario.MarioInterface; + +import java.io.File; + + +public interface LevelGenerator { + +//Use one of these methods to generate your level + + public LevelInterface generateLevel (GamePlay playerMetrics); + public LevelInterface generateLevel (String detailedInfo); +} diff --git a/src/dk/itu/mario/MarioInterface/LevelInterface.java b/src/dk/itu/mario/MarioInterface/LevelInterface.java new file mode 100644 index 0000000..9a2cb59 --- /dev/null +++ b/src/dk/itu/mario/MarioInterface/LevelInterface.java @@ -0,0 +1,41 @@ +package dk.itu.mario.MarioInterface; + +import dk.itu.mario.engine.sprites.SpriteTemplate; + +public interface LevelInterface { + + public static byte[] TILE_BEHAVIORS = new byte[256]; + + public static final int TYPE_OVERGROUND = 0; + public static final int TYPE_UNDERGROUND = 1; + public static final int TYPE_CASTLE = 2; + + public static final int BIT_BLOCK_UPPER = 1 << 0; + public static final int BIT_BLOCK_ALL = 1 << 1; + public static final int BIT_BLOCK_LOWER = 1 << 2; + public static final int BIT_SPECIAL = 1 << 3; //mashroom or flower + public static final int BIT_BUMPABLE = 1 << 4; + public static final int BIT_BREAKABLE = 1 << 5; + public static final int BIT_PICKUPABLE = 1 << 6; + public static final int BIT_ANIMATED = 1 << 7; + + public void tick(); + + //Map of WIDTH * HEIGHT that contains the level's design + public byte[][] getMap(); + + //Map of WIDTH * HEIGHT and contains the placement and type enemies + public SpriteTemplate[][] getSpriteTemplates(); + + public int getWidth(); + + public int getHeight(); + + //These are the place where the level ends + public int getxExit(); + + public int getyExit(); + + public String getName(); + +} diff --git a/src/dk/itu/mario/engine/.DS_Store b/src/dk/itu/mario/engine/.DS_Store new file mode 100644 index 0000000..416e06e Binary files /dev/null and b/src/dk/itu/mario/engine/.DS_Store differ diff --git a/src/dk/itu/mario/engine/ArgParser.java b/src/dk/itu/mario/engine/ArgParser.java new file mode 100644 index 0000000..f2fd9c5 --- /dev/null +++ b/src/dk/itu/mario/engine/ArgParser.java @@ -0,0 +1,27 @@ +package dk.itu.mario.engine; + +public class ArgParser { + public static ParsedArgs parse(String[] cmdLineArgs) { + ParsedArgs parsedArgs = new ParsedArgs(); + for (int i = 0; i < cmdLineArgs.length; i++) { + if (cmdLineArgs[i].toUpperCase().startsWith("GENERATOR=")) { + String generatorClass = cmdLineArgs[i].split("=")[1]; + parsedArgs.setGeneratorClass(generatorClass); + System.out.println("Generator class set to: " + generatorClass); + } else if (cmdLineArgs[i].toUpperCase().startsWith("SEED=")) { + String levelRandSeed = cmdLineArgs[i].split("=")[1]; + if (parsedArgs.setLevelRandSeed(levelRandSeed)) { + System.out.println("Level randomizer seed set to: " + levelRandSeed); + } else { + System.out.println("Unable to parse value of levelRandSeed: " + + levelRandSeed +". Keeping default value of: " + + parsedArgs.getLevelRandSeed()); + } + } else if (cmdLineArgs[i].toUpperCase().startsWith("VIDEO=")) { + String videoFileName = cmdLineArgs[i].split("=")[1]; + parsedArgs.setVideoFileName(videoFileName); + } + } + return parsedArgs; + } +} diff --git a/src/dk/itu/mario/engine/Art.java b/src/dk/itu/mario/engine/Art.java new file mode 100644 index 0000000..686fee7 --- /dev/null +++ b/src/dk/itu/mario/engine/Art.java @@ -0,0 +1,192 @@ +package dk.itu.mario.engine; + +import java.awt.AlphaComposite; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Transparency; +import java.awt.image.BufferedImage; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; + + +import dk.itu.mario.engine.sonar.SonarSoundEngine; +import dk.itu.mario.engine.sonar.sample.SonarSample; +import java.io.InputStream; + + +public class Art +{ + public static final int SAMPLE_BREAK_BLOCK = 0; + public static final int SAMPLE_GET_COIN = 1; + public static final int SAMPLE_MARIO_JUMP = 2; + public static final int SAMPLE_MARIO_STOMP = 3; + public static final int SAMPLE_MARIO_KICK = 4; + public static final int SAMPLE_MARIO_POWER_UP = 5; + public static final int SAMPLE_MARIO_POWER_DOWN = 6; + public static final int SAMPLE_MARIO_DEATH = 7; + public static final int SAMPLE_ITEM_SPROUT = 8; + public static final int SAMPLE_CANNON_FIRE = 9; + public static final int SAMPLE_SHELL_BUMP = 10; + public static final int SAMPLE_LEVEL_EXIT = 11; + public static final int SAMPLE_MARIO_1UP = 12; + public static final int SAMPLE_MARIO_FIREBALL = 13; + + public static Image[][] mario; + public static Image[][] smallMario; + public static Image[][] fireMario; + public static Image[][] enemies; + public static Image[][] items; + public static Image[][] level; + public static Image[][] particles; + public static Image[][] font; + public static Image[][] bg; + public static Image[][] map; + public static Image[][] endScene; + public static Image[][] gameOver; + public static Image logo; + public static Image titleScreen; + public static Image keys, abkey; + + public static SonarSample[] samples = new SonarSample[100]; + + private static Sequence[] songs = new Sequence[10]; + private static Sequencer sequencer; + + public static boolean mute = false; + private static final String PREFIX="/res"; + + + public static void init(GraphicsConfiguration gc, SonarSoundEngine sound) + { + try + { + mario = cutImage(gc, PREFIX+"/mariosheet.png", 32, 32); + smallMario = cutImage(gc, PREFIX+"/smallmariosheet.png", 16, 16); + fireMario = cutImage(gc, PREFIX+"/firemariosheet.png", 32, 32); + enemies = cutImage(gc, PREFIX+"/enemysheet.png", 16, 32); + items = cutImage(gc,PREFIX+ "/itemsheet.png", 16, 16); + level = cutImage(gc, PREFIX+"/mapsheet.png", 16, 16); + map = cutImage(gc, PREFIX+"/worldmap.png", 16, 16); + particles = cutImage(gc, PREFIX+"/particlesheet.png", 8, 8); + bg = cutImage(gc,PREFIX+ "/bgsheet.png", 32, 32); + logo = getImage(gc, PREFIX+"/logo.gif"); + titleScreen = getImage(gc, PREFIX+"/title.gif"); + font = cutImage(gc, PREFIX+"/font.gif", 8, 8); + endScene = cutImage(gc,PREFIX+ "/endscene.gif", 96, 96); + gameOver = cutImage(gc, PREFIX+"/gameovergost.gif", 96, 64); + keys = getImage(gc, PREFIX+"/keys.png"); + abkey = getImage(gc, PREFIX+"/abkey.png"); + + if (sound != null) + { + samples[SAMPLE_BREAK_BLOCK] = sound.loadSample(PREFIX+"/snd/breakblock.wav"); + samples[SAMPLE_GET_COIN] = sound.loadSample(PREFIX+"/snd/coin.wav"); + samples[SAMPLE_MARIO_JUMP] = sound.loadSample(PREFIX+"/snd/jump.wav"); + samples[SAMPLE_MARIO_STOMP] = sound.loadSample(PREFIX+"/snd/stomp.wav"); + samples[SAMPLE_MARIO_KICK] = sound.loadSample(PREFIX+"/snd/kick.wav"); + samples[SAMPLE_MARIO_POWER_UP] = sound.loadSample(PREFIX+"/snd/powerup.wav"); + samples[SAMPLE_MARIO_POWER_DOWN] = sound.loadSample(PREFIX+"/snd/powerdown.wav"); + samples[SAMPLE_MARIO_DEATH] = sound.loadSample(PREFIX+"/snd/death.wav"); + samples[SAMPLE_ITEM_SPROUT] = sound.loadSample(PREFIX+"/snd/sprout.wav"); + samples[SAMPLE_CANNON_FIRE] = sound.loadSample(PREFIX+"/snd/cannon.wav"); + samples[SAMPLE_SHELL_BUMP] = sound.loadSample(PREFIX+"/snd/bump.wav"); + samples[SAMPLE_LEVEL_EXIT] = sound.loadSample(PREFIX+"/snd/exit.wav"); + samples[SAMPLE_MARIO_1UP] = sound.loadSample(PREFIX+"/snd/1-up.wav"); + samples[SAMPLE_MARIO_FIREBALL] = sound.loadSample(PREFIX+"/snd/fireball.wav"); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + + try + { + sequencer = MidiSystem.getSequencer(); + sequencer.open(); + songs[0] = MidiSystem.getSequence(Art.class.getResourceAsStream(PREFIX+"/mus/smb3map1.mid")); + songs[1] = MidiSystem.getSequence(Art.class.getResourceAsStream(PREFIX+"/mus/smwovr1.mid")); + songs[2] = MidiSystem.getSequence(Art.class.getResourceAsStream(PREFIX+"/mus/smb3undr.mid")); + songs[3] = MidiSystem.getSequence(Art.class.getResourceAsStream(PREFIX+"/mus/smwfortress.mid")); + songs[4] = MidiSystem.getSequence(Art.class.getResourceAsStream(PREFIX+"/mus/smwtitle.mid")); + } + catch (Exception e) + { + sequencer = null; + e.printStackTrace(); + } + } + + private static Image getImage(GraphicsConfiguration gc, String imageName) throws IOException + { + InputStream p=Art.class.getResourceAsStream(imageName); + BufferedImage source = ImageIO.read(p); + Image image = gc.createCompatibleImage(source.getWidth(), source.getHeight(), Transparency.BITMASK); + Graphics2D g = (Graphics2D) image.getGraphics(); + g.setComposite(AlphaComposite.Src); + g.drawImage(source, 0, 0, null); + g.dispose(); + return image; + } + + private static Image[][] cutImage(GraphicsConfiguration gc, String imageName, int xSize, int ySize) throws IOException + { + Image source = getImage(gc, imageName); + Image[][] images = new Image[source.getWidth(null) / xSize][source.getHeight(null) / ySize]; + for (int x = 0; x < source.getWidth(null) / xSize; x++) + { + for (int y = 0; y < source.getHeight(null) / ySize; y++) + { + Image image = gc.createCompatibleImage(xSize, ySize, Transparency.BITMASK); + Graphics2D g = (Graphics2D) image.getGraphics(); + g.setComposite(AlphaComposite.Src); + g.drawImage(source, -x * xSize, -y * ySize, null); + g.dispose(); + images[x][y] = image; + } + } + + return images; + } + + public static void startMusic(int song) + { + if(!mute){ + stopMusic(); + if (sequencer != null) + { + try + { + sequencer.open(); + sequencer.setSequence((Sequence)null); + sequencer.setSequence(songs[song]); + sequencer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY); + sequencer.start(); + } + catch (Exception e) + { + } + } + } + } + + public static void stopMusic() + { + if (sequencer != null) + { + try + { + sequencer.stop(); + sequencer.close(); + } + catch (Exception e) + { + } + } + } +} diff --git a/src/dk/itu/mario/engine/BgRenderer.java b/src/dk/itu/mario/engine/BgRenderer.java new file mode 100644 index 0000000..e218989 --- /dev/null +++ b/src/dk/itu/mario/engine/BgRenderer.java @@ -0,0 +1,103 @@ +package dk.itu.mario.engine; + +import java.awt.*; +import java.util.Random; + + +import dk.itu.mario.level.Level; + + +public class BgRenderer +{ + private int xCam; + private int yCam; + private Image image; + private Graphics2D g; + private static final Color transparent = new Color(0, 0, 0, 0); + private Level level; + + private Random random = new Random(); + public boolean renderBehaviors = false; + + private int width; + private int height; + private int distance; + + public BgRenderer(Level level, GraphicsConfiguration graphicsConfiguration, int width, int height, int distance) + { + this.distance = distance; + this.width = width; + this.height = height; + + this.level = level; + image = graphicsConfiguration.createCompatibleImage(width, height, Transparency.BITMASK); + g = (Graphics2D) image.getGraphics(); + g.setComposite(AlphaComposite.Src); + + updateArea(0, 0, width, height); + } + + public void setCam(int xCam, int yCam) + { + xCam /= distance; + yCam /= distance; + int xCamD = this.xCam - xCam; + int yCamD = this.yCam - yCam; + this.xCam = xCam; + this.yCam = yCam; + + g.setComposite(AlphaComposite.Src); + g.copyArea(0, 0, width, height, xCamD, yCamD); + + if (xCamD < 0) + { + if (xCamD < -width) xCamD = -width; + updateArea(width + xCamD, 0, -xCamD, height); + } + else if (xCamD > 0) + { + if (xCamD > width) xCamD = width; + updateArea(0, 0, xCamD, height); + } + + if (yCamD < 0) + { + if (yCamD < -width) yCamD = -width; + updateArea(0, height + yCamD, width, -yCamD); + } + else if (yCamD > 0) + { + if (yCamD > width) yCamD = width; + updateArea(0, 0, width, yCamD); + } + } + + private void updateArea(int x0, int y0, int w, int h) + { + g.setBackground(transparent); + g.clearRect(x0, y0, w, h); + int xTileStart = (x0 + xCam) / 32; + int yTileStart = (y0 + yCam) / 32; + int xTileEnd = (x0 + xCam + w) / 32; + int yTileEnd = (y0 + yCam + h) / 32; + for (int x = xTileStart; x <= xTileEnd; x++) + { + for (int y = yTileStart; y <= yTileEnd; y++) + { + int b = level.getBlock(x, y) & 0xff; + g.drawImage(Art.bg[b % 8][b / 8], (x << 5) - xCam, (y << 5) - yCam-16, null); + } + } + } + + public void render(Graphics g, int tick, float alpha) + { + g.drawImage(image, 0, 0, null); + } + + public void setLevel(Level level) + { + this.level = level; + updateArea(0, 0, width, height); + } +} diff --git a/src/dk/itu/mario/engine/ConstraintsChecker.java b/src/dk/itu/mario/engine/ConstraintsChecker.java new file mode 100644 index 0000000..d4c035f --- /dev/null +++ b/src/dk/itu/mario/engine/ConstraintsChecker.java @@ -0,0 +1,56 @@ +package dk.itu.mario.engine; + +import dk.itu.mario.level.Level; +import dk.itu.mario.MarioInterface.Constraints; +import dk.itu.mario.engine.sprites.SpriteTemplate; + +public final class ConstraintsChecker { + + public static boolean check(Level level){ + if(level.getWidth() != Constraints.levelWidth) + return false; + //check the number of gaps + int levelGaps = 0, bcoins = 0; + for (int i = 0; i < level.getWidth(); i++) { + if (level.getBlock(i, level.getHeight()) == 0){ + levelGaps++; + while (i 0) + if (! (((Level.TILE_BEHAVIORS[block & 0xff]) & Level.BIT_SPECIAL) > 0)) + bcoins++; + } + } +// if(bcoins != Constraints.coinBlocks) +// return false; + return true; + } + +} diff --git a/src/dk/itu/mario/engine/DataRecorder.java b/src/dk/itu/mario/engine/DataRecorder.java new file mode 100644 index 0000000..bd459f6 --- /dev/null +++ b/src/dk/itu/mario/engine/DataRecorder.java @@ -0,0 +1,1138 @@ +package dk.itu.mario.engine; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import dk.itu.mario.MarioInterface.GamePlay; +import dk.itu.mario.engine.sprites.SpriteTemplate; +import dk.itu.mario.engine.sprites.BulletBill; +import dk.itu.mario.engine.sprites.Enemy; +import dk.itu.mario.engine.sprites.Mario; +import dk.itu.mario.engine.sprites.Shell; +import dk.itu.mario.engine.sprites.Sprite; + +import dk.itu.mario.level.Level; +import dk.itu.mario.level.RandomLevel; +import dk.itu.mario.scene.LevelScene; +import dk.itu.mario.engine.sprites.FlowerEnemy; + +public class DataRecorder { + + public boolean recording = true; + private RandomLevel level; + private boolean []keys, keyPressed; + private LevelScene levelScene; + + /** + * Time variables to record + */ + private int timeStart, timeEnd; + private int completionTime; //counts only the current run on the level, excluding death games + private int totalTime; //sums all the time, including from previous games if player died + + /** + * Jump variables to record + */ + private int totalJumpTime, startJumpTime, endJumpTime; + private int timesJumped; + public boolean isInAir; + + /** + * Duck variables to record + */ + private int totalDuckTime, startDuckTime, endDuckTime; + private int timesDucked; + + /** + * Running variables to record + */ + private int totalRunTime, startRunTime, endRunTime; + private int timesRun; + + /** + * Switching variables to record + */ + private int totalRightTime, totalLeftTime, startRightTime, endRightTime, startLeftTime, endLeftTime; + private int direction; + + /** + * How many kills the player has + */ + private int[] kills; + private int fireKills; + private int suicideKills; + private int stompKills; + private int shellKills; + + /** + * How many times dit the player die to the specific cause (monster or jump) + */ + private int[] deaths; + + /** + * How many coins did the player collect + */ + private int collectedCoins; + + /** + * How many blocks did the player destroy + */ + private int blocksEmptyDestroyed, blocksCoinDestroyed, blocksPowerDestroyed; + + /** + * How many shells the player has kicked + */ + private int shellsUnleashed; + + /** + * Power up time, how much time mario spent in what form + */ + private int totalLittleTime = 0; + private int startLittleTime = 0; + private int endLittleTime = 0; + + private int totalLargeTime = 0; + private int startLargeTime = 0; + private int endLargeTime = 0; + + private int totalFireTime = 0; + private int startFireTime = 0; + private int endFireTime = 0; + + private int switchedPower = 0; + + private boolean levelWon; + public String detailedLog = ""; + + public String getDetailedLog(){ + return detailedLog; + } + + public DataRecorder(LevelScene levelScene, RandomLevel level, boolean []keys){ + this.levelScene = levelScene; + this.level = level; + this.keys = keys; + + keyPressed = new boolean[keys.length]; + + reset(); + } + + public void reset(){ + kills = new int[7]; + deaths = new int[10]; //added one for the hole death and one for time death and one for shell + + //time reset + completionTime = 0; + timeStart = 0; + timeEnd = 0; + totalTime = 0; + + //jump reset + timesJumped = 0; + totalJumpTime = 0; + startJumpTime = 0; + endJumpTime = 0; + isInAir = false; + + //duck reset + timesDucked = 0; + totalDuckTime = 0; + startDuckTime = 0; + endDuckTime = 0; + + //run reset + timesRun = 0; + totalRunTime = 0; + startRunTime = 0; + endRunTime = 0; + + //switch reset + totalRightTime = 0; + totalLeftTime = 0; + startRightTime = 0; + startLeftTime = 0; + endRightTime = 0; + endLeftTime = 0; + + //coins reset + collectedCoins = 0; + + //blocks reset + blocksEmptyDestroyed = 0; + blocksCoinDestroyed = 0; + blocksPowerDestroyed = 0; + + //shell reset + shellsUnleashed = 0; + + //kill types + fireKills = 0; + suicideKills = 0; + stompKills = 0; + shellKills = 0; + + //power up types + totalLittleTime = 0; + startLittleTime = 0; + endLittleTime = 0; + + totalLargeTime = 0; + startLargeTime = 0; + endLargeTime = 0; + + totalFireTime = 0; + startFireTime = 0; + endFireTime = 0; + + switchedPower = 0; + + levelWon = false; + } + + public void tickRecord(){ + keysRecord(); + } + + public void levelWon(){ + levelWon = true; + } + + public boolean getLevelWon(){ + return levelWon; + } + + public void startTime(){ + if(timeStopped == true){ + timeStopped = false; + timeStart = 2982 - levelScene.timeLeft; + detailedLog += "StartTime = "+ timeStart; + detailedLog += "\n"; + } + } + + private boolean timeStopped = true; + private long endGRight; + + public void endTime(){ + if(timeStopped == false){ + timeStopped = true; + + timeEnd = 2982 - levelScene.timeLeft; + totalTime += timeEnd-timeStart; + + completionTime = timeEnd-timeStart; + detailedLog += "Totaltime = "+completionTime; + detailedLog += "\n"; + } + } + + /** + * Closes all of the recording, this should commit the data? + */ + public void stopRecord(){ + if(recording){ + recording = false; + + //time at current point + recordJumpLand(); + endTime(); + + switch(direction){ + case 1: + endRightMoveRecord(); + break; + case -1: + endLeftMoveRecord(); + break; + } + + if(levelScene.mario.running){ + endRunningRecord(); + } + + if(levelScene.mario.ducking){ + endDuckRecord(); + } + + if(Mario.large && !Mario.fire){ + endLargeRecord(); + } + + if(Mario.fire){ + endFireRecord(); + } + + if(!Mario.fire && !Mario.large){ + endLittleRecord(); + } + } + } + + public void startRightMoveRecord(){ + startRightTime = 2982 - levelScene.timeLeft; + direction = 1; + } + + public void startLeftMoveRecord(){ + startLeftTime = 2982 - levelScene.timeLeft; + direction = -1; + } + + public void endRightMoveRecord(){ + endRightTime = 2982 - levelScene.timeLeft; + + totalRightTime += endRightTime - startRightTime; + detailedLog += "RightMove: StTime = "+startRightTime +" EdTime = "+totalRightTime; + detailedLog += "\n"; + } + + public void endLeftMoveRecord(){ + endLeftTime = 2982 - levelScene.timeLeft; + + totalLeftTime += endLeftTime - startLeftTime; + detailedLog += "LeftMove: StTime = "+startLeftTime +" EdTime = "+totalLeftTime; + detailedLog += "\n"; + + } + + public void startDuckRecord(){ + if(!levelScene.mario.ducking){ + timesDucked++; + + startDuckTime = 2982 - levelScene.timeLeft; + + System.out.println("START DUCK"); + } + } + + public void endDuckRecord(){ + if(levelScene.mario.ducking){ + endDuckTime = 2982 - levelScene.timeLeft; + + totalDuckTime += endDuckTime - startDuckTime; + + System.out.println("END DUCK"); + + System.out.println("END DUCK"); + + detailedLog += "Duck: StTime = "+startDuckTime +" EdTime = "+endDuckTime; + detailedLog += "\n"; + + } + } + + private boolean littleRecording = false; + + public void startLittleRecord(){ + if(!littleRecording){ + littleRecording = true; + + switchedPower++; + + System.out.println("------------------- "+switchedPower+" -------------------"); + + startLittleTime = 2982 - levelScene.timeLeft; + + System.out.println("LITTLE START: " + startLittleTime); + } + } + + public void endLittleRecord(){ + if(littleRecording){ + littleRecording = false; + endLittleTime = 2982 - levelScene.timeLeft; + + totalLittleTime += endLittleTime - startLittleTime; + + System.out.println("LITTLE END: "+endLittleTime); + System.out.println("TOTAL LITTLE END: " + totalLittleTime); + System.out.println("LITTLE END: "+endLittleTime); + detailedLog += "LittleState: StTime = "+startLittleTime +" EdTime = "+endLittleTime; + detailedLog += "\n"; + } + } + + public void startLargeRecord(){ + switchedPower++; + + System.out.println("------------------- "+switchedPower+" -------------------"); + + startLargeTime = 2982 - levelScene.timeLeft; + + System.out.println("LARGE START"); + } + + public void endLargeRecord(){ + endLargeTime = 2982 - levelScene.timeLeft; + + totalLargeTime += endLargeTime - startLargeTime; + + System.out.println("LARGE END"); + + detailedLog += "LargeState: StTime = "+startLargeTime +" EdTime = "+endLargeTime; + detailedLog += "\n"; + + + } + + public void startFireRecord(){ + switchedPower++; + + System.out.println("------------------- "+switchedPower+" -------------------"); + + startFireTime = 2982 - levelScene.timeLeft; + + System.out.println("FIRE START"); + } + + public void endFireRecord(){ + endFireTime = 2982 - levelScene.timeLeft; + + totalFireTime += endFireTime - startFireTime; + + System.out.println("FIRE END"); + detailedLog += "FireState: StTime = "+startFireTime +" EdTime = "+endFireTime; + detailedLog += "\n"; + } + + public void startRunningRecord(){ + if(!levelScene.mario.running){ + timesRun++; + + startRunTime = 2982 - levelScene.timeLeft; + + System.out.println("START RUN"); + } + } + + public void endRunningRecord(){ + if(levelScene.mario.running){ + + System.out.println("END RUN"); + + endRunTime = 2982 - levelScene.timeLeft; + + totalRunTime += endRunTime - startRunTime; + + detailedLog += "RunState: StTime = "+startRunTime +" EdTime = "+endRunTime; + detailedLog += "\n"; + + } + } + + public void fireKillRecord(Sprite sprite){ + killRecord(sprite); + int enemyType = 0; + if(sprite instanceof FlowerEnemy){ + detailedLog += "FireKill: EnemyType = FlowerEnemy time = "+ (2982 - levelScene.timeLeft); + detailedLog += "\n"; + } + else if(sprite instanceof BulletBill){// cannon shot + } + else if(sprite instanceof Shell){ + } + else if(sprite instanceof Enemy){ + Enemy enemy = (Enemy)sprite; + detailedLog += "FireKill: EnemyType ="+ enemy.type +"time = "+ (2982 - levelScene.timeLeft); + detailedLog += "\n"; + } + fireKills++; + System.out.println(" fire kill "); + } + + public void shellKillRecord(Sprite sprite){ + killRecord(sprite); + if(sprite instanceof FlowerEnemy){ + detailedLog += "ShellKill: EnemyType = FlowerEnemy time = "+ (2982 - levelScene.timeLeft); + detailedLog += "\n"; + } + else if(sprite instanceof BulletBill){//cannon shot + } + else if(sprite instanceof Shell){ + detailedLog += "ShellKill: EnemyType = Turtle time = "+ (2982 - levelScene.timeLeft); + detailedLog += "\n"; + } + else if(sprite instanceof Enemy){ + Enemy enemy = (Enemy)sprite; + detailedLog += "ShellKill: EnemyType = "+enemy.type+" time = "+ (2982 - levelScene.timeLeft); + detailedLog += "\n"; + } + + shellKills++; + System.out.println(" shell kill "); + } + + public void killSuicideRecord(Sprite sprite){ + killRecord(sprite); + suicideKills++; + System.out.println(" suicide "); + } + + public void killStompRecord(Sprite sprite){ + killRecord(sprite); + if(sprite instanceof FlowerEnemy){ + detailedLog += "StompKill: EnemyType = FlowerEnemy time = "+ (2982 - levelScene.timeLeft); + detailedLog += "\n"; + + } + else if(sprite instanceof BulletBill){// cannon shot + detailedLog += "StompKill: EnemyType = BulletBill time = "+ (2982 - levelScene.timeLeft); + detailedLog += "\n"; + } + else if(sprite instanceof Shell){ +// levelScene.levelRecorder.enemyR.interact.add(new DataEntry(EnemyRecorder.GREEN_TURTLE, EnemyRecorder.UNLEASHED, 2982 - levelScene.timeLeft,x,y)); + } + else if(sprite instanceof Enemy){ + Enemy enemy = (Enemy)sprite; + detailedLog += "StompKill: EnemyType = "+enemy.type+" time = "+ (2982 - levelScene.timeLeft); + detailedLog += "\n"; + + } + stompKills++; + System.out.println(" stomp "); + } + + public void killRecord(Sprite sprite){ + //something goes wrong with the type of the flower enemy, this is special case + if(sprite instanceof FlowerEnemy){ + + kills[SpriteTemplate.JUMP_FLOWER]++; + } + else if(sprite instanceof BulletBill){ + kills[5]++; + } + else if(sprite instanceof Shell){ + //not sure what to do with shells + } + else if(sprite instanceof Enemy){ + Enemy enemy = (Enemy)sprite; + + kills[enemy.type]++; + } + + printKills(); + } + + public void blockEmptyDestroyRecord(){ + + blocksEmptyDestroyed++; + } + + public void blockCoinDestroyRecord(){ + detailedLog += "BlockCoinDestroy: time = "+ (2982 - levelScene.timeLeft); + detailedLog += "\n"; + blocksCoinDestroyed++; + } + + public void blockPowerDestroyRecord(){ + detailedLog += "BlockPowerDestroy: time = "+ (2982 - levelScene.timeLeft); + detailedLog += "\n"; + blocksPowerDestroyed++; + } + + public void dieRecord(Sprite sprite){ + if(sprite instanceof FlowerEnemy){ + detailedLog += "Die: EnemyType = FlowerEnemy "; + detailedLog += "\n"; + deaths[SpriteTemplate.JUMP_FLOWER]++; + } + else if(sprite instanceof BulletBill){ + detailedLog += "Die: EnemyType = BulletBill "; + detailedLog += "\n"; + deaths[5]++; + } + else if(sprite instanceof Shell){ + //not sure what to do with shells + detailedLog += "Die: EnemyType = TurtleShell "; + detailedLog += "\n"; + deaths[9]++; + } + else if(sprite instanceof Enemy){ + Enemy enemy = (Enemy)sprite; + deaths[enemy.type]++; + detailedLog += "Die: EnemyType = "+enemy.type; + detailedLog += "\n"; + + } + + + } + + public void dieTimeRecord(){ + //time + deaths[7]++; + + } + + public void dieJumpRecord(){ + //jump + deaths[8]++; + detailedLog += "Die: Gap "; + detailedLog += "\n"; + + } + + public void shellUnleashedRecord(){ + shellsUnleashed++; + System.out.println(" shell unleased"); + detailedLog += "UnleashShell: time = "+ (2982 - levelScene.timeLeft); + detailedLog += "\n"; + } + + private void keysRecord(){ + if(keys[Mario.KEY_LEFT] && !keyPressed[Mario.KEY_LEFT]){ + keyPressed[Mario.KEY_LEFT] = true; + } + else if(!keys[Mario.KEY_LEFT]){ + keyPressed[Mario.KEY_LEFT] = false; + } + } + + public void recordJump(){ + if(isInAir){ + timesJumped++; + startJumpTime = 2982 -levelScene.timeLeft; + } + } + + public void recordJumpLand(){ + if(isInAir){ + isInAir = false; + endJumpTime = 2982-levelScene.timeLeft; + + totalJumpTime += endJumpTime - startJumpTime; + + detailedLog += "Jump: StTime = "+ startJumpTime +" EdTime = "+endJumpTime; + detailedLog += "\n"; + } + } + + public void recordCoin(){ + detailedLog += "CollectCoin: time = "+ (2982 - levelScene.timeLeft); + detailedLog += "\n"; + collectedCoins++; + } + + private int convertTime(int time){ + return (int)Math.floor((time+15-1)/15); + } + + public void printAll(){ + + printKills(); + printTime(); + printJump(); + printDuck(); + printRun(); + printSwitching(); + + System.out.println("total fire: " + convertTime( totalFireTime) + " total large: " + convertTime(totalLargeTime) + " total little: " + convertTime(totalLittleTime)); + } + + private void printSwitching(){ + printStart("Switch Variables"); + System.out.println("Time Spent Moving Right: " + convertTime(totalRightTime) + " ("+Math.round((double)convertTime(totalRightTime)/(double)convertTime(totalTime)*(double)100)+"%)"); + System.out.println("Time Spent Moving Left: " + convertTime(totalLeftTime) + " ("+Math.round((double)convertTime(totalLeftTime)/(double)convertTime(totalTime)*(double)100)+"%)"); + System.out.println("Time Spent Standing Still: " + (convertTime(totalTime)-convertTime(totalLeftTime)-convertTime(totalRightTime)) + " ("+Math.round((double)(convertTime(totalTime)-convertTime(totalLeftTime)-convertTime(totalRightTime))/(double)convertTime(totalTime)*(double)100)+"%)"); + + printEnd(); + } + + private void printJump(){ + printStart("Jump Variables"); + System.out.println("Number of Times Jumped: " + timesJumped); + System.out.println("Time Spent Jumping: " + convertTime(totalJumpTime) + " ("+Math.round((double)convertTime(totalJumpTime)/(double)convertTime(totalTime)*(double)100)+"%)"); + printEnd(); + } + + private void printRun(){ + printStart("Run Variables"); + System.out.println("Number of Times Run: " + timesRun); + System.out.println("Time Spent Running: " + convertTime(totalRunTime) + " ("+Math.round((double)convertTime(totalRunTime)/(double)convertTime(totalTime)*100)+"%)"); + printEnd(); + } + + private void printDuck(){ + printStart("Duck Variables"); + System.out.println("Number of Times Ducked: " + timesDucked); + System.out.println("Time Spent Ducking: " + convertTime(totalDuckTime) + " ("+Math.round((double)convertTime(totalDuckTime)/(double)convertTime(totalTime)*(double)100)+"%)"); + printEnd(); + } + + private void printTime(){ + printStart("Time Variables"); + System.out.println("Total Completion Time: " + convertTime(totalTime)); + System.out.println("Total Last Time: " + convertTime(completionTime)); + printEnd(); + } + + private void printDeaths(){ + printStart("Player Died Against"); + int deathsTotal = 0; + + for(int i=0;i"); + + System.out.print(title); + + for(int i=0;i<50/2-title.length()/2 - tweak;++i) + System.out.print("<"); + + System.out.print("\n"); + + } + + private void printEnd(){ + System.out.println("------------------- "+switchedPower+" -------------------"); + + for(int i=0;i<50;++i) + System.out.print("-"); + + System.out.print("\n"); + } + + public void fillGamePlayMetrics(RandomLevel level){ + GamePlay gpm = new GamePlay(); + gpm.completionTime = getCompletionTime(); + gpm.totalTime = getTotalTime();////sums all the time, including from previous games if player died + gpm.jumpsNumber = getTimesJumped(); + gpm.timeSpentDucking = getTotalDuckTime(); + gpm.duckNumber = getTimesDucked(); + gpm.timeSpentRunning = getTotalRunTime(); + gpm.timesPressedRun = getTimesRun(); + gpm.timeRunningRight = getTotalRightTime(); + gpm.timeRunningLeft = getTotalLeftTime(); + gpm.coinsCollected = getCoinsCollected(); + gpm.totalCoins = level.COINS; + gpm.emptyBlocksDestroyed = getBlocksEmptyDestroyed(); + gpm.totalEmptyBlocks = level.BLOCKS_EMPTY; + gpm.coinBlocksDestroyed = getBlocksCoinDestroyed(); + gpm.totalCoinBlocks = level.BLOCKS_COINS; + gpm.powerBlocksDestroyed = getBlocksPowerDestroyed(); + gpm.totalpowerBlocks = level.BLOCKS_POWER; + gpm.kickedShells = getShellsUnleashed(); //kicked + gpm.enemyKillByFire = getKillsFire();//Number of Kills by Shooting Enemy + gpm.enemyKillByKickingShell = getKillsShell();//Number of Kills by Kicking Shell on Enemy + gpm.totalEnemies = level.ENEMIES; + + gpm.totalTimeLittleMode = getTotalLittleTime(); + gpm.totalTimeLargeMode = getTotalLargeTime();//Time Spent Being Large Mario + gpm.totalTimeFireMode = getTotalFireTime();//Time Spent Being Fire Mario + gpm.timesSwichingPower = getSwitchedPower();//Number of Times Switched Between Little, Large or Fire Mario + gpm.aimlessJumps = J();//aimless jumps + gpm.percentageBlocksDestroyed = nb();//percentage of all blocks destroyed + gpm.percentageCoinBlocksDestroyed = ncb();//percentage of coin blocks destroyed + gpm.percentageEmptyBlockesDestroyed = neb();//percentage of empty blocks destroyed + gpm.percentagePowerBlockDestroyed = np();//percentage of power blocks destroyed + gpm.timesOfDeathByFallingIntoGap = dg();//number of death by falling into a gap + gpm.timesOfDeathByRedTurtle = deaths[SpriteTemplate.RED_TURTLE]; + gpm.timesOfDeathByGreenTurtle = deaths[SpriteTemplate.GREEN_TURTLE]; + gpm.timesOfDeathByGoomba = deaths[SpriteTemplate.GOOMPA]; + gpm.timesOfDeathByArmoredTurtle = deaths[SpriteTemplate.ARMORED_TURTLE]; + gpm.timesOfDeathByJumpFlower = deaths[SpriteTemplate.JUMP_FLOWER]; + gpm.timesOfDeathByCannonBall = deaths[SpriteTemplate.CANNON_BALL]; + gpm.timesOfDeathByChompFlower = deaths[SpriteTemplate.CHOMP_FLOWER]; + + gpm.RedTurtlesKilled = kills[SpriteTemplate.RED_TURTLE]; + gpm.GreenTurtlesKilled = kills[SpriteTemplate.GREEN_TURTLE]; + gpm.GoombasKilled = kills[SpriteTemplate.GOOMPA]; + gpm.ArmoredTurtlesKilled = kills[SpriteTemplate.ARMORED_TURTLE]; + gpm.JumpFlowersKilled = kills[SpriteTemplate.JUMP_FLOWER]; + gpm.CannonBallKilled = kills[SpriteTemplate.CANNON_BALL]; + gpm.ChompFlowersKilled = kills[SpriteTemplate.CHOMP_FLOWER]; + gpm.write("player.txt"); + System.out.println(detailedLog); + write(detailedLog); + + } + + + + private void write(String detailedLog2) { + try { + FileWriter file = new FileWriter(new File("DetailedInfo.txt")); + file.write(detailedLog); + file.close(); + } catch (IOException e) { + + e.printStackTrace(); + } + + } + + public int getCompletionTime(){ + return convertTime(completionTime); + } + + public int getTotalTime(){ + return convertTime(totalTime); + } + + public int getTotalJumpTime(){ + return convertTime(totalJumpTime); + } + + public int getTimesJumped(){ + return timesJumped; + } + + public int getTotalDuckTime(){ + return convertTime(totalDuckTime); + } + + public int getTimesDucked(){ + return timesDucked; + } + + public int getTotalRunTime(){ + return convertTime(totalRunTime); + } + + public int getTimesRun(){ + return timesRun; + } + + public int getTotalRightTime(){ + return convertTime(totalRightTime); + } + + public int getTotalLeftTime(){ + return convertTime(totalLeftTime); + } + + public int getCoinsCollected(){ + return collectedCoins; + } + + public int getBlocksEmptyDestroyed(){ + return blocksEmptyDestroyed; + } + + public int getBlocksCoinDestroyed(){ + return blocksCoinDestroyed; + } + + public int getBlocksPowerDestroyed(){ + return blocksPowerDestroyed; + } + + public int getKills(int monster){ + return kills[monster]; + } + + public int getDeaths(int cause){ + return deaths[cause]; + } + + public int getShellsUnleashed(){ + return shellsUnleashed; + } + + public int getKillsStomp(){ + return stompKills; + } + + public int getKillsFire(){ + return fireKills; + } + + public int getKillsShell(){ + return shellKills; + } + + public int getKillsSuicide(){ + return suicideKills; + } + + public int getTotalLittleTime(){ + return convertTime(totalLittleTime); + } + + public int getTotalLargeTime(){ + return convertTime(totalLargeTime); + } + + public int getTotalFireTime(){ + return convertTime(totalFireTime); + } + + public int getSwitchedPower(){ + return switchedPower; + } + + + /** + * The total time taken to complete a level + * @return + */ + public double tc(){ + return (double)getTotalTime(); + } + + public double tL(){ + return (double)getTotalLeftTime()/(double)getTotalTime(); + } + + /** + * time in large form + * @return + */ + public double tl(){ + return (double)getTotalLargeTime()/(double)getTotalTime(); + } + + /** + * Time in tiny mario form + * @return + */ + public double tt(){ + return (double)getTotalLittleTime()/(double)getTotalTime(); + } + + /** + * Time spent running in percent + * @return + */ + public double tr(){ + return (double)getTotalRunTime()/(double)getTotalTime(); + } + + /** + * Time spent in powerup form + * @return + */ + public double tp(){ + return 1-((double)getTotalLittleTime()/(double)getTotalTime()); + } + + /** + * Time spent in fire mario form + * @return + */ + public double tf(){ + return (double)getTotalFireTime()/(double)getTotalTime(); + } + + public double tR(){ + return (double)getTotalRightTime()/(double)getTotalTime(); + } + + public double ks(){ + if(getKillsStomp()+getKillsFire() == 0){ + return 0; + } + else + return (double)getKillsStomp()/(double)(getKillsStomp()+getKillsFire()); + } + + public double kf(){ + if(getKillsFire()+getKillsStomp() == 0) + return 0; + else + return (double)getKillsFire()/(double)(getKillsFire()+getKillsStomp()); + } + + public double tll(){ + return getCompletionTime(); + } + + public double ts(){ + return 1-((getTotalLeftTime()+getTotalRightTime())/getTotalTime()); + } + + /** + * This is also called J' but cant be called that due to special character + * @return double of aimless jumps + */ + public double J(){ + return getTimesJumped()-getKillsStomp()-getBlocksEmptyDestroyed()-getBlocksCoinDestroyed()-getBlocksPowerDestroyed(); + } + + public double nm(){ + return getSwitchedPower(); + } + + public double nd(){ + return getTimesDucked(); + } + + /** + * Percentage of all blocks destroyed + * @return + */ + public double nb(){ + double n = 0; + if( level.BLOCKS_EMPTY != 0) + n+= getBlocksEmptyDestroyed()/level.BLOCKS_EMPTY; + if(level.BLOCKS_POWER != 0) + n+= getBlocksPowerDestroyed()/level.BLOCKS_POWER; + if( level.BLOCKS_COINS != 0) + n+= getBlocksCoinDestroyed()/level.BLOCKS_COINS; + + return n; + } + + public double ncb(){ + if( level.BLOCKS_COINS != 0) + return getBlocksCoinDestroyed()/level.BLOCKS_COINS; + else + return 0; + } + + public double neb(){ + if( level.BLOCKS_EMPTY != 0) + return getBlocksEmptyDestroyed()/level.BLOCKS_EMPTY; + else + return 0; + } + + public double np(){ + if( level.BLOCKS_POWER != 0) + return getBlocksPowerDestroyed()/level.BLOCKS_POWER; + else + return 0; + } + + /** + * Deaths by falling into gaps + * @return + */ + public double dg(){ + return getDeaths(8); + } + + /** + * Percentage of deaths by falling into gaps + * @return + */ + public double dj(){ + int tDeaths = 0; + + for(int i=0;i 1) + return 1; + else if(out < 0) + return 0; + else + return out; + } +} diff --git a/src/dk/itu/mario/engine/LevelFactory.java b/src/dk/itu/mario/engine/LevelFactory.java new file mode 100644 index 0000000..25ac4e5 --- /dev/null +++ b/src/dk/itu/mario/engine/LevelFactory.java @@ -0,0 +1,26 @@ +package dk.itu.mario.engine; + +import java.util.*; + +import dk.itu.mario.level.Level; + +public abstract class LevelFactory { + + private static Map levels = new HashMap(); + + public static void register(String name,Level level){ + levels.put(name, level); + } + + public static Level retrieve(String name){ + return levels.get(name); + } + + public static Iterator getKeyset(){ + return levels.keySet().iterator(); + } + + public static Map getLevelsMap(){ + return levels; + } +} diff --git a/src/dk/itu/mario/engine/LevelRenderer.java b/src/dk/itu/mario/engine/LevelRenderer.java new file mode 100644 index 0000000..0cc4686 --- /dev/null +++ b/src/dk/itu/mario/engine/LevelRenderer.java @@ -0,0 +1,212 @@ +package dk.itu.mario.engine; + +import java.awt.*; +import java.util.Random; + + +import dk.itu.mario.level.Level; + + +public class LevelRenderer +{ + private int xCam; + private int yCam; + private Image image; + private Graphics2D g; + private static final Color transparent = new Color(0, 0, 0, 0); + private Level level; + + private Random random = new Random(); + public boolean renderBehaviors = false; + + public int width; + public int height; + + public LevelRenderer(Level level, GraphicsConfiguration graphicsConfiguration, int width, int height) + { + this.width = width; + this.height = height; + + this.level = level; + image = graphicsConfiguration.createCompatibleImage(width, height, Transparency.BITMASK); + g = (Graphics2D) image.getGraphics(); + g.setComposite(AlphaComposite.Src); + + updateArea(0, 0, width, height); + } + + public void setCam(int xCam, int yCam) + { + int xCamD = this.xCam - xCam; + int yCamD = this.yCam - yCam; + this.xCam = xCam; + this.yCam = yCam; + + g.setComposite(AlphaComposite.Src); + g.copyArea(0, 0, width, height, xCamD, yCamD); + + if (xCamD < 0) + { + if (xCamD < -width) xCamD = -width; + updateArea(width + xCamD, 0, -xCamD, height); + } + else if (xCamD > 0) + { + if (xCamD > width) xCamD = width; + updateArea(0, 0, xCamD, height); + } + + if (yCamD < 0) + { + if (yCamD < -width) yCamD = -width; + updateArea(0, height + yCamD, width, -yCamD); + } + else if (yCamD > 0) + { + if (yCamD > width) yCamD = width; + updateArea(0, 0, width, yCamD); + } + } + + private void updateArea(int x0, int y0, int w, int h) + { + g.setBackground(transparent); + g.clearRect(x0, y0, w, h); + int xTileStart = (x0 + xCam) / 16; + int yTileStart = (y0 + yCam) / 16; + int xTileEnd = (x0 + xCam + w) / 16; + int yTileEnd = (y0 + yCam + h) / 16; + for (int x = xTileStart; x <= xTileEnd; x++) + { + for (int y = yTileStart; y <= yTileEnd; y++) + { + int b = level.getBlock(x, y) & 0xff; + if (((Level.TILE_BEHAVIORS[b]) & Level.BIT_ANIMATED) == 0) + { + g.drawImage(Art.level[b % 16][b / 16], (x << 4) - xCam, (y << 4) - yCam, null); + } + } + } + } + + public void render(Graphics g, int tick, float alpha) + { + g.drawImage(image, 0, 0, null); + + for (int x = xCam / 16; x <= (xCam + width) / 16; x++) + for (int y = yCam / 16; y <= (yCam + height) / 16; y++) + { + byte b = level.getBlock(x, y); + + if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_ANIMATED) > 0) + { + int animTime = (tick / 3) % 4; + + if ((b % 16) / 4 == 0 && b / 16 == 1) + { + animTime = (tick / 2 + (x + y) / 8) % 20; + if (animTime > 3) animTime = 0; + } + if ((b % 16) / 4 == 3 && b / 16 == 0) + { + animTime = 2; + } + int yo = 0; +// if (x >= 0 && y >= 0 && x < level.getWidth() && y < level.getyHeight()) yo = level.data[x][y]; + if (yo > 0) yo = (int) (Math.sin((yo - alpha) / 4.0f * Math.PI) * 8); + g.drawImage(Art.level[(b % 16) / 4 * 4 + animTime][b / 16], (x << 4) - xCam, (y << 4) - yCam - yo, null); + } + + /* else if (b == Level.TILE_BONUS) + { + int animTime = (tick / 3) % 4; + int yo = 0; + if (x >= 0 && y >= 0 && x < level.width && y < level.height) yo = level.data[x][y]; + if (yo > 0) yo = (int) (Math.sin((yo - alpha) / 4.0f * Math.PI) * 8); + g.drawImage(Art.mapSprites[(4 + animTime)][0], (x << 4) - xCam, (y << 4) - yCam - yo, null); + }*/ + + if (renderBehaviors) + { + if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_BLOCK_UPPER) > 0) + { + g.setColor(Color.RED); + g.fillRect((x << 4) - xCam, (y << 4) - yCam, 16, 2); + } + if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_BLOCK_ALL) > 0) + { + g.setColor(Color.RED); + g.fillRect((x << 4) - xCam, (y << 4) - yCam, 16, 2); + g.fillRect((x << 4) - xCam, (y << 4) - yCam + 14, 16, 2); + g.fillRect((x << 4) - xCam, (y << 4) - yCam, 2, 16); + g.fillRect((x << 4) - xCam + 14, (y << 4) - yCam, 2, 16); + } + if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_BLOCK_LOWER) > 0) + { + g.setColor(Color.RED); + g.fillRect((x << 4) - xCam, (y << 4) - yCam + 14, 16, 2); + } + if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_SPECIAL) > 0) + { + g.setColor(Color.PINK); + g.fillRect((x << 4) - xCam + 2 + 4, (y << 4) - yCam + 2 + 4, 4, 4); + } + if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_BUMPABLE) > 0) + { + g.setColor(Color.BLUE); + g.fillRect((x << 4) - xCam + 2, (y << 4) - yCam + 2, 4, 4); + } + if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_BREAKABLE) > 0) + { + g.setColor(Color.GREEN); + g.fillRect((x << 4) - xCam + 2 + 4, (y << 4) - yCam + 2, 4, 4); + } + if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_PICKUPABLE) > 0) + { + g.setColor(Color.YELLOW); + g.fillRect((x << 4) - xCam + 2, (y << 4) - yCam + 2 + 4, 4, 4); + } + if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_ANIMATED) > 0) + { + } + } + + } + + + } + + public void repaint(int x, int y, int w, int h) + { + updateArea(x * 16 - xCam, y * 16 - yCam, w * 16, h * 16); + } + + public void setLevel(Level level) + { + this.level = level; + updateArea(0, 0, width, height); + } + + public void renderExit0(Graphics g, int tick, float alpha, boolean bar) + { + for (int y = level.getyExit() - 8; y < level.getyExit(); y++) + { + g.drawImage(Art.level[12][y == level.getyExit() - 8 ? 4 : 5], (level.getxExit() << 4) - xCam - 16, (y << 4) - yCam, null); + } + int yh = level.getyExit() * 16 - (int) ((Math.sin((tick + alpha) / 20) * 0.5 + 0.5) * 7 * 16) - 8; + if (bar) + { + g.drawImage(Art.level[12][3], (level.getxExit() << 4) - xCam - 16, yh - yCam, null); + g.drawImage(Art.level[13][3], (level.getxExit() << 4) - xCam, yh - yCam, null); + } + } + + + public void renderExit1(Graphics g, int tick, float alpha) + { + for (int y = level.getyExit() - 8; y < level.getyExit(); y++) + { + g.drawImage(Art.level[13][y == level.getyExit() - 8 ? 4 : 5], (level.getxExit() << 4) - xCam + 16, (y << 4) - yCam, null); + } + } +} diff --git a/src/dk/itu/mario/engine/MarioComponent.java b/src/dk/itu/mario/engine/MarioComponent.java new file mode 100644 index 0000000..61a747c --- /dev/null +++ b/src/dk/itu/mario/engine/MarioComponent.java @@ -0,0 +1,306 @@ +package dk.itu.mario.engine; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.image.VolatileImage; +import java.util.Random; + +import javax.sound.sampled.LineUnavailableException; +import javax.swing.JComponent; + +import dk.itu.mario.MarioInterface.LevelGenerator; +import dk.itu.mario.engine.sonar.FakeSoundEngine; +import dk.itu.mario.engine.sonar.SonarSoundEngine; +import dk.itu.mario.engine.sprites.Mario; +import dk.itu.mario.scene.LevelScene; +import dk.itu.mario.scene.LevelSceneCustom; +import dk.itu.mario.scene.LoseScene; +import dk.itu.mario.scene.Scene; +import dk.itu.mario.scene.WinScene; + +public class MarioComponent extends JComponent implements Runnable, + KeyListener, FocusListener, MouseListener { + private static final long serialVersionUID = 739318775993206607L; + + public static final int TICKS_PER_SECOND = 24; + + public static final int EVOLVE_VERSION = 4; + public static final int GAME_VERSION = 4; + + private boolean running = false; + private int width, height; + private GraphicsConfiguration graphicsConfiguration; + private Scene scene; + private SonarSoundEngine sound; + private boolean useScale2x = false; + private boolean isCustom = false; + private LevelGenerator levelGenerator; + private Scale2x scale2x = new Scale2x(320, 240); + + public MarioComponent(int width, int height, boolean isCustomized, LevelGenerator levelGenerator) { + addFocusListener(this); + addMouseListener(this); + addKeyListener(this); + + this.setFocusable(true); + this.setEnabled(true); + this.width = width; + this.height = height; + this.isCustom = isCustomized; + + Dimension size = new Dimension(width, height); + setPreferredSize(size); + setMinimumSize(size); + setMaximumSize(size); + + try { + sound = new SonarSoundEngine(64); + } catch (LineUnavailableException e) { + e.printStackTrace(); + sound = new FakeSoundEngine(); + } + this.setFocusable(true); + this.levelGenerator = levelGenerator; + LevelScene.bothPlayed = false; + } + + private void toggleKey(int keyCode, boolean isPressed) { + if (scene == null) { + return; + } + if (keyCode == KeyEvent.VK_LEFT) { + scene.toggleKey(Mario.KEY_LEFT, isPressed); + } + if (keyCode == KeyEvent.VK_RIGHT) { + scene.toggleKey(Mario.KEY_RIGHT, isPressed); + } + if (keyCode == KeyEvent.VK_DOWN) { + scene.toggleKey(Mario.KEY_DOWN, isPressed); + } + if (keyCode == KeyEvent.VK_UP) { + scene.toggleKey(Mario.KEY_UP, isPressed); + } + if (keyCode == KeyEvent.VK_A) { + scene.toggleKey(Mario.KEY_SPEED, isPressed); + } + if (keyCode == KeyEvent.VK_S) { + scene.toggleKey(Mario.KEY_JUMP, isPressed); + } + if (keyCode == KeyEvent.VK_ENTER) { + scene.toggleKey(Mario.KEY_ENTER, isPressed); + } + if (isPressed && keyCode == KeyEvent.VK_F1) { + useScale2x = !useScale2x; + } + + if (isPressed && keyCode == KeyEvent.VK_ESCAPE) { + try { + System.exit(1); + } catch (Exception e) { + System.out.println("Unable to exit."); + } + } + } + + public void paint(Graphics g) { + super.paint(g); + } + + public void update(Graphics g) { + } + + public void start() { + if (!running) { + running = true; + new Thread(this, "Game Thread").start(); + } + } + + public void stop() { + Art.stopMusic(); + running = false; + } + + public void run() { + + graphicsConfiguration = getGraphicsConfiguration(); + + Art.init(graphicsConfiguration, sound); + + VolatileImage image = createVolatileImage(320, 240); + Graphics g = getGraphics(); + Graphics og = image.getGraphics(); + + int lastTick = -1; + + long startTime = System.nanoTime(); + + float time = (System.nanoTime() - startTime) / 1000000000f; + float now = time; + float averagePassedTime = 0; + + boolean naiveTiming = true; + + ///Not sure I understand the weird dichotomy between LevelScene and LevelInterface... + randomLevel = new LevelSceneCustom(graphicsConfiguration, this, + new Random().nextLong(), 0, 0, isCustom, levelGenerator); + + Mario.fire = false; + Mario.large = false; + Mario.coins = 0; + Mario.lives = 3; + + randomLevel.init(); + randomLevel.setSound(sound); + scene = randomLevel; + /// + + while (running) { + float lastTime = time; + time = (System.nanoTime() - startTime) / 1000000000f; + float passedTime = time - lastTime; + + if (passedTime < 0) + naiveTiming = false; // Stop relying on nanotime if it starts + // skipping around in time (ie running + // backwards at least once). This + // sometimes happens on dual core amds. + averagePassedTime = averagePassedTime * 0.9f + passedTime * 0.1f; + + if (naiveTiming) { + now = time; + } else { + now += averagePassedTime; + } + + int tick = (int) (now * TICKS_PER_SECOND); + + if (lastTick == -1) + lastTick = tick; + + while (lastTick < tick) { + scene.tick(); + + lastTick++; + } + + float alpha = (float) (now * TICKS_PER_SECOND - tick); + sound.clientTick(alpha); + + og.setColor(Color.WHITE); + og.fillRect(0, 0, 320, 240); + + scene.render(og, alpha); + + if (!this.hasFocus() && tick / 4 % 2 == 0) { + String msg = "CLICK TO PLAY"; + + drawString(og, msg, 160 - msg.length() * 4 + 1, 110 + 1, 0); + drawString(og, msg, 160 - msg.length() * 4, 110, 7); + } + og.setColor(Color.BLACK); + + if (width != 320 || height != 240) { + + if (useScale2x) { + g.drawImage(scale2x.scale(image), 0, 0, null); + } else { + g.drawImage(image, 0, 0, 640, 480, null); + + } + } else { + g.drawImage(image, 0, 0, null); + } + + try { + Thread.sleep(5); + } catch (InterruptedException e) { + } + } + + Art.stopMusic(); + } + + private void drawString(Graphics g, String text, int x, int y, int c) { + char[] ch = text.toCharArray(); + for (int i = 0; i < ch.length; i++) { + g.drawImage(Art.font[ch[i] - 32][c], x + i * 8, y, null); + } + } + + public void keyPressed(KeyEvent arg0) { + toggleKey(arg0.getKeyCode(), true); + } + + public void keyReleased(KeyEvent arg0) { + toggleKey(arg0.getKeyCode(), false); + } + + public void keyTyped(KeyEvent arg0) { + } + + public void focusGained(FocusEvent arg0) { + } + + public void focusLost(FocusEvent arg0) { + } + + public void levelWon() { + } + + public static final int OPTIMIZED_FIRST = 0; + public static final int MINIMIZED_FIRST = 1; + + private LevelScene randomLevel; + + public void lose() { + scene = new LoseScene(); + scene.setSound(sound); + scene.init(); + } + + public void win() { + scene = new WinScene(); + scene.setSound(sound); + scene.init(); + } + + public void mouseClicked(MouseEvent e) { + } + + public void mouseEntered(MouseEvent e) { + // TODO Auto-generated method stub + } + + public void mouseExited(MouseEvent e) { + // TODO Auto-generated method stub + } + + public void mousePressed(MouseEvent e) { + // TODO Auto-generated method stub + } + + public void mouseReleased(MouseEvent e) { + + while (!hasFocus()) { + System.out.println("FORCE IT"); + requestFocus(); + } + } + + /** + * Must return the actual fill of the viewable components + */ + public Dimension getPreferredSize() { + return new Dimension(width, height); + } + +} diff --git a/src/dk/itu/mario/engine/ParsedArgs.java b/src/dk/itu/mario/engine/ParsedArgs.java new file mode 100644 index 0000000..727b67e --- /dev/null +++ b/src/dk/itu/mario/engine/ParsedArgs.java @@ -0,0 +1,86 @@ +package dk.itu.mario.engine; + +import dk.itu.mario.MarioInterface.LevelGenerator; +import dk.itu.mario.level.generator.CustomizedLevelGenerator; +import dk.itu.mario.level.generator.MyLevelGenerator; +import dk.itu.mario.level.generator.RandomLevelGenerator; + +public class ParsedArgs { + public static final String NO_GEN_ERR = "Generator class not specified (use generator=... argument)."; + + //Default values per Play class: + private boolean custom = false; + private boolean videoCaptureEnabled = false; + private int levelRandSeed = (int) (Math.random() * Integer.MAX_VALUE); + private String generatorClass = "MyLevel"; + private String videoFileName = "LevelGenerator"; + + public LevelGenerator createLevelGenerator() { + if (generatorClass == null) { + throw new UnsupportedOperationException(NO_GEN_ERR); + } + if ("MyLevel".equals(generatorClass)) { + return new MyLevelGenerator(); + } else if ("CustomizedLevel".equalsIgnoreCase(generatorClass)) { + return new CustomizedLevelGenerator(); + } else if ("RandomLevel".equalsIgnoreCase(generatorClass)) { + return new RandomLevelGenerator(); + } else { + throw new UnsupportedOperationException("Cannot create LevelFactory for unrecognized class:" + generatorClass); + } + } + + public String getGeneratorClass() { + return generatorClass; + } + + public int getLevelRandSeed() { + return levelRandSeed; + } + + public String getVideoFileName() { + return videoFileName; + } + + public boolean isCustom() { + return custom; + } + + public boolean isGeneratorClassSet() { + return generatorClass != null; + } + + public boolean isVideoCaptureEnabled() { + return videoCaptureEnabled; + } + + public void setGeneratorClass(String generatorClass) { + if (generatorClass == null) { + throw new UnsupportedOperationException(NO_GEN_ERR); + } + + this.generatorClass = generatorClass; + + if ("MyLevel".equals(generatorClass)) { + custom = true; + } else if ("CustomizedLevel".equalsIgnoreCase(generatorClass)) { + custom = true; + } else { + custom = false; + } + } + + public void setVideoFileName(String videoFileName) { + this.videoFileName = videoFileName; + this.videoCaptureEnabled = true; + } + + public boolean setLevelRandSeed(String randSeedString) { + try { + levelRandSeed = Integer.valueOf(randSeedString); + return true; + } catch (NumberFormatException nfe) { + return false; + } + } +} \ No newline at end of file diff --git a/src/dk/itu/mario/engine/Play.java b/src/dk/itu/mario/engine/Play.java new file mode 100644 index 0000000..16be749 --- /dev/null +++ b/src/dk/itu/mario/engine/Play.java @@ -0,0 +1,30 @@ +package dk.itu.mario.engine; + +import java.awt.Dimension; +import java.awt.Toolkit; + +import javax.swing.JFrame; + +public class Play { + + public static void main(String[] args) { + + JFrame frame = new JFrame("Mario Experience Showcase"); + ParsedArgs parsedArgs = ArgParser.parse(args); + MarioComponent mario = new MarioComponent(640, 480, parsedArgs.isCustom(), parsedArgs.createLevelGenerator()); + + frame.setContentPane(mario); + frame.setResizable(false); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.pack(); + + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + frame.setLocation((screenSize.width - frame.getWidth()) / 2, + (screenSize.height - frame.getHeight()) / 2); + + frame.setVisible(true); + + mario.start(); + } + +} \ No newline at end of file diff --git a/src/dk/itu/mario/engine/Scale2x.java b/src/dk/itu/mario/engine/Scale2x.java new file mode 100644 index 0000000..820c1b9 --- /dev/null +++ b/src/dk/itu/mario/engine/Scale2x.java @@ -0,0 +1,130 @@ +/** + * Scale2x.java + * + * Written by Markus Persson of Mojang Specifications for a super mario programming contest. + * Implements the Scale2x algorithm described here: http://scale2x.sourceforge.net/algorithm.html + * Works on any input image size, and uses a fancy border hack to prevent range checking. + * It's fast enough for real time use on smaller images (320x240 and thereabouts) + * + * This code is public domain. Do whatever you want with it. + */ +package dk.itu.mario.engine; + +import java.awt.Graphics; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; + + +public class Scale2x +{ + private int width; + private int height; + + private BufferedImage sourceImage; + private int[] sourcePixels; + private Graphics sourceGraphics; + + private BufferedImage targetImage; + private int[] targetPixels; + + /** + * Creates a new Scale2x object. The new object will scale images of the specified size to images + * that are twice as large.
+ * + * @param width The width of the images to be scaled + * @param height The height of the images to be scaled + */ + public Scale2x(int width, int height) + { + this.width = width; + this.height = height; + + // A border of one pixel in each direction, and one down, to avoid if statements in the scale loop + sourceImage = new BufferedImage(width + 2, height + 3, BufferedImage.TYPE_INT_RGB); + DataBufferInt sourceDataBuffer = (DataBufferInt) sourceImage.getRaster().getDataBuffer(); + sourcePixels = sourceDataBuffer.getData(); + sourceGraphics = sourceImage.getGraphics(); + + targetImage = new BufferedImage(width * 2, height * 2, BufferedImage.TYPE_INT_RGB); + DataBufferInt targetDataBuffer = (DataBufferInt) targetImage.getRaster().getDataBuffer(); + targetPixels = targetDataBuffer.getData(); + } + + /** + * Scales an image and returns a twice as large image.
+ * This assumes the input image is of the dimensions specified in the Scale2x constructor.
+ * The returned image is a reference to the internal scale target in this Scale2x, so it + * will get changed if you call this method again, so don't hold on to it for too long.
+ * In other words:
+ * Image i0 = scale2x.scale(image0);
+ * Image i1 = scale2x.scale(image1);
+ * if (i0 == i1) System.exit(0); // Will always terminate

+ * + * @param img The image to be scaled + * @returns A scaled image. If you want that image to survive the next call to this method, make a copy of it. + */ + public Image scale(Image img) + { + // Offset the image by one pixel so there's a border around it. + // This lets us avoid having to check that A-I are in range of the image before samping them + sourceGraphics.drawImage(img, 1, 1, null); + + int line = width + 2; + for (int y = 0; y < height; y++) + { + // Two lines of target pixel pointers + int tp0 = y * width * 4 - 1; + int tp1 = tp0 + width * 2; + + // Three lines of source pixel pointers + int sp0 = (y) * line; + int sp1 = (y + 1) * line; + int sp2 = (y + 2) * line; + + // Fill the initial A-I values + int A = sourcePixels[sp0]; + int B = sourcePixels[++sp0]; + int C = sourcePixels[++sp0]; + int D = sourcePixels[sp1]; + int E = sourcePixels[++sp1]; + int F = sourcePixels[++sp1]; + int G = sourcePixels[sp2]; + int H = sourcePixels[++sp2]; + int I = sourcePixels[++sp2]; + + for (int x = 0; x < width; x++) + { + if (B != H && D != F) + { + targetPixels[++tp0] = D == B ? D : E; + targetPixels[++tp0] = B == F ? F : E; + targetPixels[++tp1] = D == H ? D : E; + targetPixels[++tp1] = H == F ? F : E; + } + else + { + targetPixels[++tp0] = E; + targetPixels[++tp0] = E; + targetPixels[++tp1] = E; + targetPixels[++tp1] = E; + } + + // Scroll A-I left + A = B; + B = C; + D = E; + E = F; + G = H; + H = I; + + // Resample rightmost edge + C = sourcePixels[++sp0]; + F = sourcePixels[++sp1]; + I = sourcePixels[++sp2]; + } + } + + return targetImage; + } +} \ No newline at end of file diff --git a/src/dk/itu/mario/engine/sonar/.DS_Store b/src/dk/itu/mario/engine/sonar/.DS_Store new file mode 100644 index 0000000..eff28f6 Binary files /dev/null and b/src/dk/itu/mario/engine/sonar/.DS_Store differ diff --git a/src/dk/itu/mario/engine/sonar/FakeSoundEngine.java b/src/dk/itu/mario/engine/sonar/FakeSoundEngine.java new file mode 100644 index 0000000..9c021b6 --- /dev/null +++ b/src/dk/itu/mario/engine/sonar/FakeSoundEngine.java @@ -0,0 +1,38 @@ +package dk.itu.mario.engine.sonar; + + + +import dk.itu.mario.engine.sonar.sample.SonarSample; + + +public class FakeSoundEngine extends SonarSoundEngine +{ + public void setListener(SoundListener soundListener) + { + } + + public void shutDown() + { + } + + public SonarSample loadSample(String resourceName) + { + return null; + } + + public void play(SonarSample sample, SoundSource soundSource, float volume, float priority, float rate) + { + } + + public void clientTick(float alpha) + { + } + + public void tick() + { + } + + public void run() + { + } +} diff --git a/src/dk/itu/mario/engine/sonar/FixedSoundSource.java b/src/dk/itu/mario/engine/sonar/FixedSoundSource.java new file mode 100644 index 0000000..5c60251 --- /dev/null +++ b/src/dk/itu/mario/engine/sonar/FixedSoundSource.java @@ -0,0 +1,33 @@ +package dk.itu.mario.engine.sonar; + + +/** + * @author Administrator + */ +public class FixedSoundSource implements SoundSource +{ + private float x; + private float y; + + public FixedSoundSource(float x, float y) + { + this.x = x; + this.y = y; + } + + public FixedSoundSource(SoundSource soundSource) + { + this.x = soundSource.getX(1); + this.y = soundSource.getY(1); + } + + public float getX(float alpha) + { + return x; + } + + public float getY(float alpha) + { + return y; + } +} \ No newline at end of file diff --git a/src/dk/itu/mario/engine/sonar/SonarSoundEngine.java b/src/dk/itu/mario/engine/sonar/SonarSoundEngine.java new file mode 100644 index 0000000..8719a24 --- /dev/null +++ b/src/dk/itu/mario/engine/sonar/SonarSoundEngine.java @@ -0,0 +1,145 @@ +package dk.itu.mario.engine.sonar; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import javax.sound.sampled.*; + + +import dk.itu.mario.engine.sonar.mixer.ListenerMixer; + +import dk.itu.mario.engine.sonar.sample.SamplePlayer; +import dk.itu.mario.engine.sonar.sample.SonarSample; +import dk.itu.mario.engine.sonar.sample.SampleLoader; + + + +public class SonarSoundEngine implements Runnable +{ + private SonarSample silentSample; + private SourceDataLine sdl; + private int rate = 44100; + private ListenerMixer listenerMixer; + private int bufferSize = rate / 100; // 10 ms + private ByteBuffer soundBuffer = ByteBuffer.allocate(bufferSize * 4); + private float[] leftBuf, rightBuf; + private float amplitude = 1; + private float targetAmplitude = 1; + private boolean alive = true; + + protected SonarSoundEngine() + { + } + + public SonarSoundEngine(int maxChannels) throws LineUnavailableException + { + silentSample = new SonarSample(new float[] {0}, 44100); + Mixer mixer = AudioSystem.getMixer(null); + + sdl = (SourceDataLine) mixer.getLine(new Line.Info(SourceDataLine.class)); + sdl.open(new AudioFormat(rate, 16, 2, true, false), bufferSize * 2 * 2 * 2 * 2 * 2); + soundBuffer.order(ByteOrder.LITTLE_ENDIAN); + sdl.start(); + + try + { +/* FloatControl volumeControl = (FloatControl) sdl.getControl(FloatControl.Type.MASTER_GAIN); + volumeControl.setValue(volumeControl.getMaximum());*/ + } + catch (IllegalArgumentException e) + { + System.out.println("Failed to set the sound volume"); + } + + listenerMixer = new ListenerMixer(maxChannels); + + leftBuf = new float[bufferSize]; + rightBuf = new float[bufferSize]; + + Thread thread = new Thread(this); + thread.setDaemon(true); + thread.setPriority(10); + thread.start(); + } + + public void setListener(SoundListener soundListener) + { + listenerMixer.setSoundListener(soundListener); + } + + public void shutDown() + { + alive = false; + } + + public SonarSample loadSample(String resourceName) + { + try + { + return SampleLoader.loadSample(resourceName); + } + catch (Exception e) + { + System.out.println("Failed to load sample " + resourceName + ". Using silent sample"); + e.printStackTrace(); + return silentSample; + } + } + + public void play(SonarSample sample, SoundSource soundSource, float volume, float priority, float rate) + { + synchronized (listenerMixer) + { + if(!dk.itu.mario.engine.Art.mute) + listenerMixer.addSoundProducer(new SamplePlayer((SonarSample) sample, rate), soundSource, volume, priority); + } + } + + public void clientTick(float alpha) + { + synchronized (listenerMixer) + { + listenerMixer.update(alpha); + } + } + + public void tick() + { + soundBuffer.clear(); + + // targetAmplitude = (targetAmplitude - 1) * 0.9f + 1; + // targetAmplitude = (targetAmplitude - 1) * 0.9f + 1; + synchronized (listenerMixer) + { + float maxAmplitude = listenerMixer.read(leftBuf, rightBuf, rate); + // if (maxAmplitude > targetAmplitude) targetAmplitude = maxAmplitude; + } + + soundBuffer.clear(); + float gain = 32000; + for (int i = 0; i < bufferSize; i++) + { + // amplitude += (targetAmplitude - amplitude) / rate; + // amplitude = 1; + // float gain = 30000; + int l = (int) (leftBuf[i] * gain); + int r = (int) (rightBuf[i] * gain); + if (l > 32767) l = 32767; + if (r > 32767) r = 32767; + if (l < -32767) l = -32767; + if (r < -32767) r = -32767; + soundBuffer.putShort((short)l); + soundBuffer.putShort((short)r); + } + + sdl.write(soundBuffer.array(), 0, bufferSize * 2 * 2); + } + + public void run() + { + while (alive) + { + tick(); + } + } +} diff --git a/src/dk/itu/mario/engine/sonar/SoundListener.java b/src/dk/itu/mario/engine/sonar/SoundListener.java new file mode 100644 index 0000000..b2f722e --- /dev/null +++ b/src/dk/itu/mario/engine/sonar/SoundListener.java @@ -0,0 +1,6 @@ +package dk.itu.mario.engine.sonar; + + +public interface SoundListener extends SoundSource +{ +} \ No newline at end of file diff --git a/src/dk/itu/mario/engine/sonar/SoundProducer.java b/src/dk/itu/mario/engine/sonar/SoundProducer.java new file mode 100644 index 0000000..4312b0d --- /dev/null +++ b/src/dk/itu/mario/engine/sonar/SoundProducer.java @@ -0,0 +1,8 @@ +package dk.itu.mario.engine.sonar; + +public interface SoundProducer +{ + public float read(float[] buf, int readRate); + public void skip(int samplesToSkip, int readRate); + public boolean isLive(); +} \ No newline at end of file diff --git a/src/dk/itu/mario/engine/sonar/SoundSource.java b/src/dk/itu/mario/engine/sonar/SoundSource.java new file mode 100644 index 0000000..604db50 --- /dev/null +++ b/src/dk/itu/mario/engine/sonar/SoundSource.java @@ -0,0 +1,7 @@ +package dk.itu.mario.engine.sonar; + +public interface SoundSource +{ + public float getX(float alpha); + public float getY(float alpha); +} \ No newline at end of file diff --git a/src/dk/itu/mario/engine/sonar/StereoSoundProducer.java b/src/dk/itu/mario/engine/sonar/StereoSoundProducer.java new file mode 100644 index 0000000..aef2b25 --- /dev/null +++ b/src/dk/itu/mario/engine/sonar/StereoSoundProducer.java @@ -0,0 +1,7 @@ +package dk.itu.mario.engine.sonar; + +public interface StereoSoundProducer +{ + public float read(float[] leftBuf, float[] rightBuf, int readRate); + public void skip(int samplesToSkip, int readRate); +} \ No newline at end of file diff --git a/src/dk/itu/mario/engine/sonar/mixer/.DS_Store b/src/dk/itu/mario/engine/sonar/mixer/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/src/dk/itu/mario/engine/sonar/mixer/.DS_Store differ diff --git a/src/dk/itu/mario/engine/sonar/mixer/ListenerMixer.java b/src/dk/itu/mario/engine/sonar/mixer/ListenerMixer.java new file mode 100644 index 0000000..6c986f3 --- /dev/null +++ b/src/dk/itu/mario/engine/sonar/mixer/ListenerMixer.java @@ -0,0 +1,93 @@ +package dk.itu.mario.engine.sonar.mixer; + +import java.util.*; + + + +import dk.itu.mario.engine.sonar.SoundListener; +import dk.itu.mario.engine.sonar.SoundProducer; +import dk.itu.mario.engine.sonar.SoundSource; +import dk.itu.mario.engine.sonar.StereoSoundProducer; + +public class ListenerMixer implements StereoSoundProducer +{ + private List sounds = new ArrayList(); + private float[] buf = new float[0]; + private int maxChannels; + private SoundListener soundListener; + + public ListenerMixer(int maxChannels) + { + this.maxChannels = maxChannels; + } + + public void setSoundListener(SoundListener soundListener) + { + this.soundListener = soundListener; + } + + public void addSoundProducer(SoundProducer producer, SoundSource soundSource, float volume, float priority) + { + sounds.add(new Sound(producer, soundSource, volume, priority)); + } + + public void update(float alpha) + { + for (Iterator it = sounds.iterator(); it.hasNext();) + { + Sound sound = (Sound) it.next(); + sound.update(soundListener, alpha); + if (!sound.isLive()) + { + it.remove(); + } + } + } + + @SuppressWarnings("unchecked") + public float read(float[] leftBuf, float[] rightBuf, int readRate) + { + if (buf.length != leftBuf.length) buf = new float[leftBuf.length]; + + if (sounds.size() > maxChannels) + { + Collections.sort(sounds); + } + + Arrays.fill(leftBuf, 0); + Arrays.fill(rightBuf, 0); + float maxAmplitude = 0; + for (int i = 0; i < sounds.size(); i++) + { + Sound sound = (Sound) sounds.get(i); + if (i < maxChannels) + { + sound.read(buf, readRate); + float rp = (sound.pan<0?1:1-sound.pan)*sound.amplitude; + float lp = (sound.pan>0?1:1+sound.pan)*sound.amplitude; + for (int j = 0; j < leftBuf.length; j++) + { + leftBuf[j] += buf[j]*lp; + rightBuf[j] += buf[j]*rp; + if (leftBuf[j]>maxAmplitude) maxAmplitude = leftBuf[j]; + if (rightBuf[j]>maxAmplitude) maxAmplitude = rightBuf[j]; + } + } + else + { + sound.skip(leftBuf.length, readRate); + } + } + + return maxAmplitude; + } + + public void skip(int samplesToSkip, int readRate) + { + for (int i = 0; i < sounds.size(); i++) + { + Sound sound = (Sound) sounds.get(i); + sound.skip(samplesToSkip, readRate); + } + } +} diff --git a/src/dk/itu/mario/engine/sonar/mixer/Sound.java b/src/dk/itu/mario/engine/sonar/mixer/Sound.java new file mode 100644 index 0000000..43ceb76 --- /dev/null +++ b/src/dk/itu/mario/engine/sonar/mixer/Sound.java @@ -0,0 +1,84 @@ +package dk.itu.mario.engine.sonar.mixer; + + + +import dk.itu.mario.engine.sonar.SoundListener; +import dk.itu.mario.engine.sonar.SoundProducer; +import dk.itu.mario.engine.sonar.SoundSource; + + +public class Sound implements Comparable +{ + private static final double l10 = Math.log(10); + + private SoundProducer producer; + private SoundSource source; + private float volume; + private float priority; + + private float x, y, z; + private float score = 0; + + public float pan; + public float amplitude; + + public Sound(SoundProducer producer, SoundSource source, float volume, float priority) + { + this.producer = producer; + this.source = source; + this.volume = volume; + this.priority = priority; + } + + public void update(SoundListener listener, float alpha) + { + x = source.getX(alpha)-listener.getX(alpha); + y = source.getY(alpha)-listener.getY(alpha); + + float distSqr = x*x+y*y+z*z; + float dist = (float)Math.sqrt(distSqr); + + float REFERENCE_DISTANCE = 1; + float ROLLOFF_FACTOR = 2; + +// float dB = (float)(volume + (20 * (Math.log(1.0 / distSqr) / l10))); + float dB = (float)(volume - 20*Math.log(1 + ROLLOFF_FACTOR*(dist-REFERENCE_DISTANCE)/REFERENCE_DISTANCE )/ l10); + dB = Math.min(dB, +6); +// dB = Math.max(dB, MIN_GAIN); + + score = dB*priority; + +// double angle = WMath.atan2(y, x); + + float p = -x/320.0f; + if (p<-1) p = -1; + if (p>1) p = 1; + float dd = distSqr/16; + if (dd>1) dd = 1; + pan =(p*dd); + amplitude = volume*1f; + } + + public void read(float[] buf, int readRate) + { + producer.read(buf, readRate); + } + + public void skip(int samplesToSkip, int readRate) + { + producer.skip(samplesToSkip, readRate); + } + + public boolean isLive() + { + return producer.isLive(); + } + + public int compareTo(Object o) + { + Sound s = (Sound)o; + if (s.score>score) return 1; + if (s.score 0) + { + bos.write(b, 0, read); + } + + bos.close(); + return bos.toByteArray(); + } + + /** + * Reorganizes audio sample data into the intenal sonar format + */ + private static SonarSample buildSample(byte[] b, AudioFormat af) throws UnsupportedAudioFileException + { + // Rip audioformat data + int channels = af.getChannels(); + int sampleSize = af.getSampleSizeInBits(); + float rate = af.getFrameRate(); + boolean signed = af.getEncoding() == AudioFormat.Encoding.PCM_SIGNED; + + // Sanity checking + if (channels != 1) throw new UnsupportedAudioFileException("Only mono samples are supported"); + if (!(sampleSize == 8 || sampleSize == 16 || sampleSize == 32)) throw new UnsupportedAudioFileException("Unsupported sample size"); + if (!(af.getEncoding() == AudioFormat.Encoding.PCM_UNSIGNED || af.getEncoding() == AudioFormat.Encoding.PCM_SIGNED)) throw new UnsupportedAudioFileException("Unsupported encoding"); + + // Wrap the data into a bytebuffer, and set up the byte order + ByteBuffer bb = ByteBuffer.wrap(b); + bb.order(af.isBigEndian() ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN); + + int s = b.length / (sampleSize / 8); + float[] buf = new float[s]; + // Six different cases for reordering the data. Can this be improved without slowing it down? + if (sampleSize == 8) + { + if (signed) + { + for (int i = 0; i < s; i++) + buf[i] = bb.get() / (float)0x80; + } + else + { + for (int i = 0; i < s; i++) + buf[i] = ((bb.get()&0xFF)-0x80) / (float)0x80; + } + } + else if (sampleSize == 16) + { + if (signed) + { + for (int i = 0; i < s; i++) + buf[i] = bb.getShort() / (float)0x8000; + } + else + { + for (int i = 0; i < s; i++) + buf[i] = ((bb.getShort()&0xFFFF)-0x8000) / (float)0x8000; + } + } + else if (sampleSize == 32) + { + if (signed) + { + for (int i = 0; i < s; i++) + buf[i] = bb.getInt() / (float)0x80000000; + } + else + { + // Nasty.. check this. + for (int i = 0; i < s; i++) + buf[i] = ((bb.getInt()&0xFFFFFFFFl)-0x80000000l) / (float)0x80000000; + } + } + + // Return the completed sample + return new SonarSample(buf, rate); + } +} diff --git a/src/dk/itu/mario/engine/sonar/sample/SamplePlayer.java b/src/dk/itu/mario/engine/sonar/sample/SamplePlayer.java new file mode 100644 index 0000000..a4f3865 --- /dev/null +++ b/src/dk/itu/mario/engine/sonar/sample/SamplePlayer.java @@ -0,0 +1,57 @@ +package dk.itu.mario.engine.sonar.sample; + + + +import dk.itu.mario.engine.sonar.SoundProducer; + + +public class SamplePlayer implements SoundProducer +{ + private SonarSample sample; + private float pos = 0; + public boolean alive = true; + private float rate; + + public SamplePlayer(SonarSample sample, float rate) + { + this.rate = rate; + this.sample = sample; + } + + public float read(float[] buf, int readRate) + { + float step = (sample.rate*rate)/readRate; + + for (int i=0; i=sample.buf.length) + { + buf[i] = 0; + alive = false; + } + else + { + buf[i]=sample.buf[(int)(pos)]; + } + pos+=step; + } + + return 1; + } + + public void skip(int samplesToSkip, int readRate) + { + float step = sample.rate/readRate; + pos+=step*samplesToSkip; + + if (pos>=sample.buf.length) + { + alive = false; + } + } + + public boolean isLive() + { + return alive; + } +} diff --git a/src/dk/itu/mario/engine/sonar/sample/SonarSample.java b/src/dk/itu/mario/engine/sonar/sample/SonarSample.java new file mode 100644 index 0000000..e921d8b --- /dev/null +++ b/src/dk/itu/mario/engine/sonar/sample/SonarSample.java @@ -0,0 +1,13 @@ +package dk.itu.mario.engine.sonar.sample; + +public class SonarSample +{ + public final float[] buf; + public final float rate; + + public SonarSample(float[] buf, float rate) + { + this.buf = buf; + this.rate = rate; + } +} \ No newline at end of file diff --git a/src/dk/itu/mario/engine/sprites/.DS_Store b/src/dk/itu/mario/engine/sprites/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/src/dk/itu/mario/engine/sprites/.DS_Store differ diff --git a/src/dk/itu/mario/engine/sprites/BulletBill.java b/src/dk/itu/mario/engine/sprites/BulletBill.java new file mode 100644 index 0000000..dcf23b7 --- /dev/null +++ b/src/dk/itu/mario/engine/sprites/BulletBill.java @@ -0,0 +1,152 @@ +package dk.itu.mario.engine.sprites; + + +import dk.itu.mario.engine.Art; +import dk.itu.mario.scene.LevelScene; + + +public class BulletBill extends Sprite +{ + private int width = 4; + int height = 24; + + private LevelScene world; + public int facing; + + public boolean avoidCliffs = false; + public int anim; + + public boolean dead = false; + private int deadTime = 0; + + + public BulletBill(LevelScene world, float x, float y, int dir) + { + sheet = Art.enemies; + + this.x = x; + this.y = y; + this.world = world; + xPicO = 8; + yPicO = 31; + + height = 12; + facing = 0; + wPic = 16; + yPic = 5; + + xPic = 0; + ya = -5; + this.facing = dir; + } + + public void collideCheck() + { + if (dead) return; + + float xMarioD = world.mario.x - x; + float yMarioD = world.mario.y - y; + float w = 16; + if (xMarioD > -16 && xMarioD < 16) + { + if (yMarioD > -height && yMarioD < world.mario.height) + { + if (world.mario.ya > 0 && yMarioD <= 0 && (!world.mario.onGround || !world.mario.wasOnGround)) + { + world.mario.stomp(this); + dead = true; + + xa = 0; + ya = 1; + deadTime = 100; + } + else + { + world.mario.getHurt(this); + } + } + } + } + + public void move() + { + if (deadTime > 0) + { + deadTime--; + + if (deadTime == 0) + { + deadTime = 1; + for (int i = 0; i < 8; i++) + { + world.addSprite(new Sparkle((int) (x + Math.random() * 16 - 8) + 4, (int) (y - Math.random() * 8) + 4, (float) (Math.random() * 2 - 1), (float) Math.random() * -1, 0, 1, 5)); + } + spriteContext.removeSprite(this); + } + + x += xa; + y += ya; + ya *= 0.95; + ya += 1; + + return; + } + + float sideWaysSpeed = 4f; + + xa = facing * sideWaysSpeed; + xFlipPic = facing == -1; + move(xa, 0); + } + + private boolean move(float xa, float ya) + { + x += xa; + return true; + } + + public boolean fireballCollideCheck(Fireball fireball) + { + if (deadTime != 0) return false; + + float xD = fireball.x - x; + float yD = fireball.y - y; + + if (xD > -16 && xD < 16) + { + if (yD > -height && yD < fireball.height) + { + return true; + } + } + return false; + } + + public boolean shellCollideCheck(Shell shell) + { + if (deadTime != 0) return false; + + float xD = shell.x - x; + float yD = shell.y - y; + + if (xD > -16 && xD < 16) + { + if (yD > -height && yD < shell.height) + { + world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); + + dead = true; + + xa = 0; + ya = 1; + deadTime = 100; + + if(world.recorder != null) + world.recorder.shellKillRecord(this); + + return true; + } + } + return false; + } +} diff --git a/src/dk/itu/mario/engine/sprites/CoinAnim.java b/src/dk/itu/mario/engine/sprites/CoinAnim.java new file mode 100644 index 0000000..65c2d73 --- /dev/null +++ b/src/dk/itu/mario/engine/sprites/CoinAnim.java @@ -0,0 +1,41 @@ +package dk.itu.mario.engine.sprites; + +import dk.itu.mario.engine.Art; +import dk.itu.mario.level.Level; + + + +public class CoinAnim extends Sprite +{ + private int life = 10; + + public CoinAnim(int xTile, int yTile) + { + sheet = Art.level; + wPic = hPic = 16; + + x = xTile * 16; + y = yTile * 16 - 16; + xa = 0; + ya = -6f; + xPic = 0; + yPic = 2; + } + + public void move() + { + if (life-- < 0) + { + Sprite.spriteContext.removeSprite(this); + for (int xx = 0; xx < 2; xx++) + for (int yy = 0; yy < 2; yy++) + Sprite.spriteContext.addSprite(new Sparkle((int)x + xx * 8 + (int) (Math.random() * 8), (int)y + yy * 8 + (int) (Math.random() * 8), 0, 0, 0, 2, 5)); + } + + xPic = life & 3; + + x += xa; + y += ya; + ya += 1; + } +} diff --git a/src/dk/itu/mario/engine/sprites/Enemy.java b/src/dk/itu/mario/engine/sprites/Enemy.java new file mode 100644 index 0000000..21c0883 --- /dev/null +++ b/src/dk/itu/mario/engine/sprites/Enemy.java @@ -0,0 +1,443 @@ +package dk.itu.mario.engine.sprites; + +import java.awt.Graphics; + + +import dk.itu.mario.engine.Art; +import dk.itu.mario.level.Level; +import dk.itu.mario.scene.LevelScene; + + + +public class Enemy extends Sprite +{ + public static final int ENEMY_RED_KOOPA = 0; + public static final int ENEMY_GREEN_KOOPA = 1; + public static final int ENEMY_GOOMBA = 2; + public static final int ENEMY_SPIKY = 3; + public static final int ENEMY_FLOWER = 4; + + private static float GROUND_INERTIA = 0.89f; + private static float AIR_INERTIA = 0.89f; + + private float runTime; + private boolean onGround = false; + private boolean mayJump = false; + private int jumpTime = 0; + private float xJumpSpeed; + private float yJumpSpeed; + + int width = 4; + int height = 24; + + private LevelScene world; + public int facing; + public int deadTime = 0; + public boolean flyDeath = false; + + public boolean avoidCliffs = true; + public int type; + + public boolean winged = true; + private int wingTime = 0; + + public boolean noFireballDeath; + + public Enemy(LevelScene world, int x, int y, int dir, int type, boolean winged) + { + this.type = type; + sheet = Art.enemies; + this.winged = winged; + + + this.world = world; + this.x = x; + this.y = y; + + xPicO = 8; + yPicO = 31; + + avoidCliffs = type == Enemy.ENEMY_RED_KOOPA; + + noFireballDeath = type == Enemy.ENEMY_SPIKY; + + yPic = type; + if (yPic > 1) height = 12; + facing = dir; + if (facing == 0) facing = 1; + this.wPic = 16; + } + + public void collideCheck() + { + if (deadTime != 0) + { + return; + } + + float xMarioD = world.mario.x - x; + float yMarioD = world.mario.y - y; + float w = 16; + + //if the distance to mario is within the sprite (in x) + if (xMarioD > -width*2-4 && xMarioD < width*2+4) + { + //if the distance to mario is within the sprite (in y) + if (yMarioD > -height && yMarioD < world.mario.height) + { + if (type != Enemy.ENEMY_SPIKY && world.mario.ya > 0 && yMarioD <= 0 && (!world.mario.onGround || !world.mario.wasOnGround)) + { + world.mario.stomp(this); + + if (winged) + { + winged = false; + ya = 0; + } + else + { + this.yPicO = 31 - (32 - 8); + hPic = 8; + if (spriteTemplate != null) spriteTemplate.isDead = true; + deadTime = 10; + winged = false; + + if (type == Enemy.ENEMY_RED_KOOPA) + { + spriteContext.addSprite(new Shell(world, x, y, 0)); + } + else if (type == Enemy.ENEMY_GREEN_KOOPA) + { + spriteContext.addSprite(new Shell(world, x, y, 1)); + } + } + } + else + { + world.mario.getHurt(this); + } + } + } + } + + public void move() + { + //TODO: some kind of suicide error when one enemy is created + if (y > world.level.getHeight() * 16 + 16 && deadTime <= 0) + { + if(world.recorder != null) + world.recorder.killSuicideRecord(this); + + deadTime = 1; + } + + wingTime++; + if (deadTime > 0) + { + deadTime--; + + if (deadTime == 0) + { + deadTime = 1; + for (int i = 0; i < 8; i++) + { + world.addSprite(new Sparkle((int) (x + Math.random() * 16 - 8) + 4, (int) (y - Math.random() * 8) + 4, (float) (Math.random() * 2 - 1), (float) Math.random() * -1, 0, 1, 5)); + } + spriteContext.removeSprite(this); + } + + if (flyDeath) + { + x += xa; + y += ya; + ya *= 0.95; + ya += 1; + } + return; + } + + + float sideWaysSpeed = 1.75f; + // float sideWaysSpeed = onGround ? 2.5f : 1.2f; + + if (xa > 2) + { + facing = 1; + } + if (xa < -2) + { + facing = -1; + } + + xa = facing * sideWaysSpeed; + + mayJump = (onGround); + + xFlipPic = facing == -1; + + runTime += (Math.abs(xa)) + 5; + + int runFrame = ((int) (runTime / 20)) % 2; + + if (!onGround) + { + runFrame = 1; + } + + + if (!move(xa, 0)) facing = -facing; + onGround = false; + move(0, ya); + + ya *= winged ? 0.95f : 0.85f; + if (onGround) + { + xa *= GROUND_INERTIA; + } + else + { + xa *= AIR_INERTIA; + } + + if (!onGround) + { + if (winged) + { + ya += 0.6f; + } + else + { + ya += 2; + } + } + else if (winged) + { + ya = -10; + } + + if (winged) runFrame = wingTime / 4 % 2; + + xPic = runFrame; + } + + private boolean move(float xa, float ya) + { + while (xa > 8) + { + if (!move(8, 0)) return false; + xa -= 8; + } + while (xa < -8) + { + if (!move(-8, 0)) return false; + xa += 8; + } + while (ya > 8) + { + if (!move(0, 8)) return false; + ya -= 8; + } + while (ya < -8) + { + if (!move(0, -8)) return false; + ya += 8; + } + + boolean collide = false; + if (ya > 0) + { + if (isBlocking(x + xa - width, y + ya, xa, 0)) collide = true; + else if (isBlocking(x + xa + width, y + ya, xa, 0)) collide = true; + else if (isBlocking(x + xa - width, y + ya + 1, xa, ya)) collide = true; + else if (isBlocking(x + xa + width, y + ya + 1, xa, ya)) collide = true; + } + if (ya < 0) + { + if (isBlocking(x + xa, y + ya - height, xa, ya)) collide = true; + else if (collide || isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; + else if (collide || isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; + } + if (xa > 0) + { + if (isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; + if (isBlocking(x + xa + width, y + ya - height / 2, xa, ya)) collide = true; + if (isBlocking(x + xa + width, y + ya, xa, ya)) collide = true; + + if (avoidCliffs && onGround && !world.level.isBlocking((int) ((x + xa + width) / 16), (int) ((y) / 16 + 1), xa, 1)) collide = true; + } + if (xa < 0) + { + if (isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; + if (isBlocking(x + xa - width, y + ya - height / 2, xa, ya)) collide = true; + if (isBlocking(x + xa - width, y + ya, xa, ya)) collide = true; + + if (avoidCliffs && onGround && !world.level.isBlocking((int) ((x + xa - width) / 16), (int) ((y) / 16 + 1), xa, 1)) collide = true; + } + + if (collide) + { + if (xa < 0) + { + x = (int) ((x - width) / 16) * 16 + width; + this.xa = 0; + } + if (xa > 0) + { + x = (int) ((x + width) / 16 + 1) * 16 - width - 1; + this.xa = 0; + } + if (ya < 0) + { + y = (int) ((y - height) / 16) * 16 + height; + jumpTime = 0; + this.ya = 0; + } + if (ya > 0) + { + y = (int) (y / 16 + 1) * 16 - 1; + onGround = true; + } + return false; + } + else + { + x += xa; + y += ya; + return true; + } + } + + private boolean isBlocking(float _x, float _y, float xa, float ya) + { + int x = (int) (_x / 16); + int y = (int) (_y / 16); + if (x == (int) (this.x / 16) && y == (int) (this.y / 16)) return false; + + boolean blocking = world.level.isBlocking(x, y, xa, ya); + + byte block = world.level.getBlock(x, y); + + return blocking; + } + + public boolean shellCollideCheck(Shell shell) + { + if (deadTime != 0) return false; + + float xD = shell.x - x; + float yD = shell.y - y; + + if (xD > -16 && xD < 16) + { + if (yD > -height && yD < shell.height) + { + world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); + + xa = shell.facing * 2; + ya = -5; + flyDeath = true; + if (spriteTemplate != null) spriteTemplate.isDead = true; + deadTime = 100; + winged = false; + hPic = -hPic; + yPicO = -yPicO + 16; + + if(world.recorder != null) + world.recorder.shellKillRecord(this); + + return true; + } + } + return false; + } + + public boolean fireballCollideCheck(Fireball fireball) + { + if (deadTime != 0) return false; + + float xD = fireball.x - x; + float yD = fireball.y - y; + + if (xD > -16 && xD < 16) + { + if (yD > -height && yD < fireball.height) + { + if (noFireballDeath) return true; + + world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); + + xa = fireball.facing * 2; + ya = -5; + flyDeath = true; + if (spriteTemplate != null) spriteTemplate.isDead = true; + deadTime = 100; + winged = false; + hPic = -hPic; + yPicO = -yPicO + 16; + + + if(world.recorder != null) + world.recorder.fireKillRecord(this); + + return true; + } + } + return false; + } + + public void bumpCheck(int xTile, int yTile) + { + if (deadTime != 0) return; + + if (x + width > xTile * 16 && x - width < xTile * 16 + 16 && yTile == (int) ((y - 1) / 16)) + { + world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); + + xa = -world.mario.facing * 2; + ya = -5; + flyDeath = true; + if (spriteTemplate != null) spriteTemplate.isDead = true; + deadTime = 100; + winged = false; + hPic = -hPic; + yPicO = -yPicO + 16; + + } + } + + public void render(Graphics og, float alpha) + { + if (winged) + { + int xPixel = (int) (xOld + (x - xOld) * alpha) - xPicO; + int yPixel = (int) (yOld + (y - yOld) * alpha) - yPicO; + + if (type == Enemy.ENEMY_GREEN_KOOPA || type == Enemy.ENEMY_RED_KOOPA) + { + } + else + { + xFlipPic = !xFlipPic; + og.drawImage(sheet[wingTime / 4 % 2][4], xPixel + (xFlipPic ? wPic : 0) + (xFlipPic ? 10 : -10), yPixel + (yFlipPic ? hPic : 0) - 8, xFlipPic ? -wPic : wPic, yFlipPic ? -hPic : hPic, null); + xFlipPic = !xFlipPic; + } + } + + super.render(og, alpha); + + if (winged) + { + int xPixel = (int) (xOld + (x - xOld) * alpha) - xPicO; + int yPixel = (int) (yOld + (y - yOld) * alpha) - yPicO; + + if (type == Enemy.ENEMY_GREEN_KOOPA || type == Enemy.ENEMY_RED_KOOPA) + { + og.drawImage(sheet[wingTime / 4 % 2][4], xPixel + (xFlipPic ? wPic : 0) + (xFlipPic ? 10 : -10), yPixel + (yFlipPic ? hPic : 0) - 10, xFlipPic ? -wPic : wPic, yFlipPic ? -hPic : hPic, null); + } + else + { + og.drawImage(sheet[wingTime / 4 % 2][4], xPixel + (xFlipPic ? wPic : 0) + (xFlipPic ? 10 : -10), yPixel + (yFlipPic ? hPic : 0) - 8, xFlipPic ? -wPic : wPic, yFlipPic ? -hPic : hPic, null); + } + } + } +} diff --git a/src/dk/itu/mario/engine/sprites/FireFlower.java b/src/dk/itu/mario/engine/sprites/FireFlower.java new file mode 100644 index 0000000..55e9c16 --- /dev/null +++ b/src/dk/itu/mario/engine/sprites/FireFlower.java @@ -0,0 +1,63 @@ +package dk.itu.mario.engine.sprites; + + +import dk.itu.mario.engine.Art; +import dk.itu.mario.scene.LevelScene; + + + +public class FireFlower extends Sprite +{ + private int width = 4; + int height = 24; + + private LevelScene world; + public int facing; + + public boolean avoidCliffs = false; + private int life; + + public FireFlower(LevelScene world, int x, int y) + { + sheet = Art.items; + + this.x = x; + this.y = y; + this.world = world; + xPicO = 8; + yPicO = 15; + + xPic = 1; + yPic = 0; + height = 12; + facing = 1; + wPic = hPic = 16; + life = 0; + } + + public void collideCheck() + { + float xMarioD = world.mario.x - x; + float yMarioD = world.mario.y - y; + float w = 16; + if (xMarioD > -16 && xMarioD < 16) + { + if (yMarioD > -height && yMarioD < world.mario.height) + { + world.mario.getFlower(); + spriteContext.removeSprite(this); + } + } + } + + public void move() + { + if (life<9) + { + layer = 0; + y--; + life++; + return; + } + } +} diff --git a/src/dk/itu/mario/engine/sprites/Fireball.java b/src/dk/itu/mario/engine/sprites/Fireball.java new file mode 100644 index 0000000..889f7a1 --- /dev/null +++ b/src/dk/itu/mario/engine/sprites/Fireball.java @@ -0,0 +1,220 @@ +package dk.itu.mario.engine.sprites; + + +import dk.itu.mario.engine.Art; +import dk.itu.mario.scene.LevelScene; + + + +public class Fireball extends Sprite +{ + private static float GROUND_INERTIA = 0.89f; + private static float AIR_INERTIA = 0.89f; + + private float runTime; + private boolean onGround = false; + + private int width = 4; + int height = 24; + + private LevelScene world; + public int facing; + + public boolean avoidCliffs = false; + public int anim; + + public boolean dead = false; + private int deadTime = 0; + + public Fireball(LevelScene world, float x, float y, int facing) + { + sheet = Art.particles; + + this.x = x; + this.y = y; + this.world = world; + xPicO = 4; + yPicO = 4; + + yPic = 3; + height = 8; + this.facing = facing; + wPic = 8; + hPic = 8; + + xPic = 4; + ya = 4; + } + + public void move() + { + if (deadTime > 0) + { + for (int i = 0; i < 8; i++) + { + world.addSprite(new Sparkle((int) (x + Math.random() * 8 - 4)+4, (int) (y + Math.random() * 8-4)+2, (float) Math.random() * 2 - 1-facing, (float) Math.random() *2 -1, 0, 1, 5)); + } + spriteContext.removeSprite(this); + + return; + } + + if (facing != 0) anim++; + + float sideWaysSpeed = 8f; + // float sideWaysSpeed = onGround ? 2.5f : 1.2f; + + if (xa > 2) + { + facing = 1; + } + if (xa < -2) + { + facing = -1; + } + + xa = facing * sideWaysSpeed; + + world.checkFireballCollide(this); + + xFlipPic = facing == -1; + + runTime += (Math.abs(xa)) + 5; + + xPic = (anim) % 4; + + + + if (!move(xa, 0)) + { + die(); + } + + onGround = false; + move(0, ya); + if (onGround) ya = -10; + + ya *= 0.95f; + if (onGround) + { + xa *= GROUND_INERTIA; + } + else + { + xa *= AIR_INERTIA; + } + + if (!onGround) + { + ya += 1.5; + } + } + + private boolean move(float xa, float ya) + { + while (xa > 8) + { + if (!move(8, 0)) return false; + xa -= 8; + } + while (xa < -8) + { + if (!move(-8, 0)) return false; + xa += 8; + } + while (ya > 8) + { + if (!move(0, 8)) return false; + ya -= 8; + } + while (ya < -8) + { + if (!move(0, -8)) return false; + ya += 8; + } + + boolean collide = false; + if (ya > 0) + { + if (isBlocking(x + xa - width, y + ya, xa, 0)) collide = true; + else if (isBlocking(x + xa + width, y + ya, xa, 0)) collide = true; + else if (isBlocking(x + xa - width, y + ya + 1, xa, ya)) collide = true; + else if (isBlocking(x + xa + width, y + ya + 1, xa, ya)) collide = true; + } + if (ya < 0) + { + if (isBlocking(x + xa, y + ya - height, xa, ya)) collide = true; + else if (collide || isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; + else if (collide || isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; + } + if (xa > 0) + { + if (isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; + if (isBlocking(x + xa + width, y + ya - height / 2, xa, ya)) collide = true; + if (isBlocking(x + xa + width, y + ya, xa, ya)) collide = true; + + if (avoidCliffs && onGround && !world.level.isBlocking((int) ((x + xa + width) / 16), (int) ((y) / 16 + 1), xa, 1)) collide = true; + } + if (xa < 0) + { + if (isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; + if (isBlocking(x + xa - width, y + ya - height / 2, xa, ya)) collide = true; + if (isBlocking(x + xa - width, y + ya, xa, ya)) collide = true; + + if (avoidCliffs && onGround && !world.level.isBlocking((int) ((x + xa - width) / 16), (int) ((y) / 16 + 1), xa, 1)) collide = true; + } + + if (collide) + { + if (xa < 0) + { + x = (int) ((x - width) / 16) * 16 + width; + this.xa = 0; + } + if (xa > 0) + { + x = (int) ((x + width) / 16 + 1) * 16 - width - 1; + this.xa = 0; + } + if (ya < 0) + { + y = (int) ((y - height) / 16) * 16 + height; + this.ya = 0; + } + if (ya > 0) + { + y = (int) (y / 16 + 1) * 16 - 1; + onGround = true; + } + return false; + } + else + { + x += xa; + y += ya; + return true; + } + } + + private boolean isBlocking(float _x, float _y, float xa, float ya) + { + int x = (int) (_x / 16); + int y = (int) (_y / 16); + if (x == (int) (this.x / 16) && y == (int) (this.y / 16)) return false; + + boolean blocking = world.level.isBlocking(x, y, xa, ya); + + byte block = world.level.getBlock(x, y); + + return blocking; + } + + public void die() + { + dead = true; + + xa = -facing * 2; + ya = -5; + deadTime = 100; + } +} diff --git a/src/dk/itu/mario/engine/sprites/FlowerEnemy.java b/src/dk/itu/mario/engine/sprites/FlowerEnemy.java new file mode 100644 index 0000000..4ec3a08 --- /dev/null +++ b/src/dk/itu/mario/engine/sprites/FlowerEnemy.java @@ -0,0 +1,103 @@ +package dk.itu.mario.engine.sprites; + +import dk.itu.mario.level.Level; +import dk.itu.mario.scene.LevelScene; +import dk.itu.mario.engine.sprites.*; + +public class FlowerEnemy extends Enemy +{ + private int tick; + private int yStart; + private int jumpTime = 0; + private LevelScene world; + + public FlowerEnemy(LevelScene world, int x, int y) + { + super(world, x, y, 1, ENEMY_SPIKY, false); + + noFireballDeath = false; + this.world = world; + this.xPic = 0; + this.yPic = 6; + this.yPicO = 24; + this.height = 12; + this.width = 2; + + yStart = y; + ya = -8; + + this.y-=1; + + this.layer = 0; + for (int i=0; i<4; i++) + { + move(); + } + } + + public void move() + { + if (deadTime > 0) + { + deadTime--; + + if (deadTime == 0) + { + deadTime = 1; + for (int i = 0; i < 8; i++) + { + world.addSprite(new Sparkle((int) (x + Math.random() * 16 - 8) + 4, (int) (y - Math.random() * 8) + 4, (float) (Math.random() * 2 - 1), (float) Math.random() * -1, 0, 1, 5)); + } + spriteContext.removeSprite(this); + } + + x += xa; + y += ya; + ya *= 0.95; + ya += 1; + + return; + } + + tick++; + + if (y>=yStart) + { + y = yStart; + + int xd = (int)(Math.abs(world.mario.x-x)); + jumpTime++; + if (jumpTime>40 && xd>24) + { + ya = -8; + } + else + { + ya = 0; + } + } + else + { + jumpTime = 0; + } + + y+=ya; + ya*=0.9; + ya+=0.1f; + + xPic = ((tick/2)&1)*2+((tick/6)&1); + } + +/* public void render(Graphics og, float alpha) + { + if (!visible) return; + + int xPixel = (int)(xOld+(x-xOld)*alpha)-xPicO; + int yPixel = (int)(yOld+(y-yOld)*alpha)-yPicO; + + int a = ((tick/3)&1)*2; +// a += ((tick/8)&1); + og.drawImage(sheet[a*2+0][6], xPixel-8, yPixel+8, 16, 32, null); + og.drawImage(sheet[a*2+1][6], xPixel+8, yPixel+8, 16, 32, null); + }*/ +} diff --git a/src/dk/itu/mario/engine/sprites/Mario.java b/src/dk/itu/mario/engine/sprites/Mario.java new file mode 100644 index 0000000..fbce871 --- /dev/null +++ b/src/dk/itu/mario/engine/sprites/Mario.java @@ -0,0 +1,918 @@ +package dk.itu.mario.engine.sprites; + + + + + +import dk.itu.mario.engine.Art; +import dk.itu.mario.engine.DataRecorder; +import dk.itu.mario.engine.sonar.FixedSoundSource; +import dk.itu.mario.level.Level; +import dk.itu.mario.scene.LevelScene; +import dk.itu.mario.scene.Scene; + + + + +public class Mario extends Sprite +{ + public static boolean large = false; + public static boolean fire = false; + public static int coins = 0; + public static int lives = 3; + public static String levelString = "none"; + + public static void resetStatic() + { + large = false; + fire = false; + coins = 0; + lives = 3; + levelString = "none"; + } + + public static final int KEY_LEFT = 0; + public static final int KEY_RIGHT = 1; + public static final int KEY_DOWN = 2; + public static final int KEY_UP = 3; + public static final int KEY_JUMP = 4; + public static final int KEY_SPEED = 5; + public static final int KEY_ENTER = 6; + + private static float GROUND_INERTIA = 0.89f; + private static float AIR_INERTIA = 0.89f; + + public boolean[] keys; + private float runTime; + boolean wasOnGround = false; + boolean onGround = false; + private boolean mayJump = false; + public boolean ducking = false; + public boolean running = false; + public int direction = 0; + private boolean sliding = false; + private int jumpTime = 0; + private float xJumpSpeed; + private float yJumpSpeed; + private boolean canShoot = false; + + int width = 4; + int height = 24; + + private LevelScene world; + public int facing; + private int powerUpTime = 0; + + public int xDeathPos, yDeathPos; + + public int deathTime = 0; + public int winTime = 0; + private int invulnerableTime = 0; + + public Sprite carried = null; + private static Mario instance; + + public Mario(LevelScene world) + { + Mario.instance = this; + this.world = world; + keys = Scene.keys; + x = 32; + y = 0; + + facing = 1; + + //TODO: REMOVE THESE TEST VARIABLES +// Mario.large = true; +// Mario.fire = true; + + setLarge(Mario.large, Mario.fire); + } + + private boolean lastLarge; + private boolean lastFire; + private boolean newLarge; + private boolean newFire; + + private void blink(boolean on) + { + Mario.large = on?newLarge:lastLarge; + Mario.fire = on?newFire:lastFire; + + if (large) + { + sheet = Art.mario; + if (fire) + sheet = Art.fireMario; + + xPicO = 16; + yPicO = 31; + wPic = hPic = 32; + } + else + { + sheet = Art.smallMario; + + xPicO = 8; + yPicO = 15; + wPic = hPic = 16; + } + + calcPic(); + } + + void setLarge(boolean large, boolean fire) + { + if (fire) large = true; + if (!large) fire = false; + + lastLarge = Mario.large; + lastFire = Mario.fire; + + Mario.large = large; + Mario.fire = fire; + + newLarge = Mario.large; + newFire = Mario.fire; + + blink(true); + } + + public void move() + { + if(deathTime == 0 && winTime == 0){ + if (keys[KEY_DOWN] && large && ducking) + { + if(world.recorder != null && world.recorder.recording) + world.recorder.startDuckRecord(); + } + else + { + if(world.recorder != null && world.recorder.recording && !ducking) + world.recorder.endDuckRecord(); + } + } + + if(deathTime == 0 && winTime == 0){ + if(keys[KEY_SPEED]){ + if(world.recorder!= null && world.recorder.recording){ + world.recorder.startRunningRecord(); + } + + running = true; + } + else{ + if(world.recorder!= null && world.recorder.recording){ + world.recorder.endRunningRecord(); + } + + running = false; + } + } + + if (winTime > 0) + { + + winTime++; + + xa = 0; + ya = 0; + return; + } + + if (deathTime > 0) + { + deathTime++; + if (deathTime < 11) + { + xa = 0; + ya = 0; + } + else if (deathTime == 11) + { + ya = -15; + } + else + { + ya += 2; + } + x += xa; + y += ya; + return; + } + + if (powerUpTime != 0) + { + if (powerUpTime > 0) + { + powerUpTime--; + blink(((powerUpTime / 3) & 1) == 0); + } + else + { + powerUpTime++; + blink(((-powerUpTime / 3) & 1) == 0); + } + + if (powerUpTime == 0) world.paused = false; + + calcPic(); + return; + } + + if (invulnerableTime > 0) invulnerableTime--; + visible = ((invulnerableTime / 2) & 1) == 0; + + wasOnGround = onGround; + float sideWaysSpeed = keys[KEY_SPEED] ? 1.2f : 0.6f; + // float sideWaysSpeed = onGround ? 2.5f : 1.2f; + + if (onGround) + { + if (keys[KEY_DOWN] && large) + { + if(world.recorder != null) + world.recorder.startDuckRecord(); + + ducking = true; + } + else + { + if(world.recorder != null) + world.recorder.endDuckRecord(); + + ducking = false; + } + + if(world.recorder != null) + world.recorder.recordJumpLand(); + } + + if (xa > 2) + { + facing = 1; + } + if (xa < -2) + { + facing = -1; + } + + if (keys[KEY_JUMP] || (jumpTime < 0 && !onGround && !sliding)) + { + if (jumpTime < 0) + { + xa = xJumpSpeed; + ya = -jumpTime * yJumpSpeed; + jumpTime++; + } + else if (onGround && mayJump) + { + world.sound.play(Art.samples[Art.SAMPLE_MARIO_JUMP], this, 1, 1, 1); + xJumpSpeed = 0; + yJumpSpeed = -1.9f; + jumpTime = 7; + ya = jumpTime * yJumpSpeed; + onGround = false; + sliding = false; + + if(world.recorder != null){ + world.recorder.isInAir = true; + world.recorder.recordJump(); + } + } + else if (sliding && mayJump) + { + world.sound.play(Art.samples[Art.SAMPLE_MARIO_JUMP], this, 1, 1, 1); + xJumpSpeed = -facing * 6.0f; + yJumpSpeed = -2.0f; + jumpTime = -6; + xa = xJumpSpeed; + ya = -jumpTime * yJumpSpeed; + onGround = false; + sliding = false; + facing = -facing; + } + else if (jumpTime > 0) + { + xa += xJumpSpeed; + ya = jumpTime * yJumpSpeed; + jumpTime--; + } + } + else + { + jumpTime = 0; + } + + if(world.mario.xa > 0){ + + if(direction != 1){ + direction = 1; + if(world.recorder != null){ +// world.recorder.switchRecord(); + world.recorder.startRightMoveRecord(); + } + } + + } + else if(world.mario.xa < 0){ + if(direction != -1){ + direction = -1; + if(world.recorder != null){ +// world.recorder.switchRecord(); + world.recorder.startLeftMoveRecord(); + } + } + + } + else{ + //was moving right + if(direction == 1 && world.recorder!= null){ + world.recorder.endRightMoveRecord(); + } + //was moving left + else if(direction == -1 && world.recorder!= null){ + world.recorder.endLeftMoveRecord(); + } + + direction = 0; + } + + if (keys[KEY_LEFT] && !ducking) + { + if (facing == 1) sliding = false; + xa -= sideWaysSpeed; + if (jumpTime >= 0) facing = -1; + } + + if (keys[KEY_RIGHT] && !ducking) + { + if (facing == -1) sliding = false; + xa += sideWaysSpeed; + if (jumpTime >= 0) facing = 1; + } + + if ((!keys[KEY_LEFT] && !keys[KEY_RIGHT]) || ducking || ya < 0 || onGround) + { + sliding = false; + } + + if (keys[KEY_SPEED] && canShoot && Mario.fire && world.fireballsOnScreen<2) + { + world.sound.play(Art.samples[Art.SAMPLE_MARIO_FIREBALL], this, 1, 1, 1); + world.addSprite(new Fireball(world, x+facing*6, y-20, facing)); + } + + canShoot = !keys[KEY_SPEED]; + + mayJump = (onGround || sliding) && !keys[KEY_JUMP]; + + xFlipPic = facing == -1; + + runTime += (Math.abs(xa)) + 5; + if (Math.abs(xa) < 0.5f) + { + runTime = 0; + xa = 0; + } + + calcPic(); + + if (sliding) + { + for (int i = 0; i < 1; i++) + { + world.addSprite(new Sparkle((int) (x + Math.random() * 4 - 2) + facing * 8, (int) (y + Math.random() * 4) - 24, (float) (Math.random() * 2 - 1), (float) Math.random() * 1, 0, 1, 5)); + } + ya *= 0.5f; + } + + onGround = false; + move(xa, 0); + move(0, ya); + + if (y > world.level.getHeight() * 16 + 16) + { + dieJump(); + } + + if (x < 0) + { + x = 0; + xa = 0; + } + +// if(x > world.level.xExit * 16 && ! world.level.flipped || x < world.level.xExit * 16 && world.level.flipped ) + if(x > world.level.getxExit() * 16 ) + + { + win(); + } + + if (x > world.level.getWidth() * 16) + { + x = world.level.getWidth() * 16; + xa = 0; + } + + ya *= 0.85f; + if (onGround) + { + xa *= GROUND_INERTIA; + } + else + { + xa *= AIR_INERTIA; + } + + if (!onGround) + { + ya += 3; + } + + if (carried != null) + { + carried.x = x + facing * 8; + carried.y = y - 2; + if (!keys[KEY_SPEED]) + { + carried.release(this); + carried = null; + + if(world.recorder != null){ + world.recorder.shellUnleashedRecord(); + } + } + } + } + + private void calcPic() + { + int runFrame = 0; + + if (large) + { + runFrame = ((int) (runTime / 20)) % 4; + if (runFrame == 3) runFrame = 1; + if (carried == null && Math.abs(xa) > 10) runFrame += 3; + if (carried != null) runFrame += 10; + if (!onGround) + { + if (carried != null) runFrame = 12; + else if (Math.abs(xa) > 10) runFrame = 7; + else runFrame = 6; + } + } + else + { + runFrame = ((int) (runTime / 20)) % 2; + if (carried == null && Math.abs(xa) > 10) runFrame += 2; + if (carried != null) runFrame += 8; + if (!onGround) + { + if (carried != null) runFrame = 9; + else if (Math.abs(xa) > 10) runFrame = 5; + else runFrame = 4; + } + } + + if (onGround && ((facing == -1 && xa > 0) || (facing == 1 && xa < 0))) + { + if (xa > 1 || xa < -1) runFrame = large ? 9 : 7; + + if (xa > 3 || xa < -3) + { + for (int i = 0; i < 3; i++) + { + world.addSprite(new Sparkle((int) (x + Math.random() * 8 - 4), (int) (y + Math.random() * 4), (float) (Math.random() * 2 - 1), (float) Math.random() * -1, 0, 1, 5)); + } + } + } + + if (large) + { + if (ducking) runFrame = 14; + height = ducking ? 12 : 24; + } + else + { + height = 12; + } + + xPic = runFrame; + } + + private boolean move(float xa, float ya) + { + + while (xa > 8) + { + if (!move(8, 0)) return false; + xa -= 8; + } + while (xa < -8) + { + if (!move(-8, 0)) return false; + xa += 8; + } + while (ya > 8) + { + if (!move(0, 8)) return false; + ya -= 8; + } + while (ya < -8) + { + if (!move(0, -8)) return false; + ya += 8; + } + + boolean collide = false; + if (ya > 0) + { + if (isBlocking(x + xa - width, y + ya, xa, 0)) collide = true; + else if (isBlocking(x + xa + width, y + ya, xa, 0)) collide = true; + else if (isBlocking(x + xa - width, y + ya + 1, xa, ya)) collide = true; + else if (isBlocking(x + xa + width, y + ya + 1, xa, ya)) collide = true; + } + if (ya < 0) + { + if (isBlocking(x + xa, y + ya - height, xa, ya)) collide = true; + else if (collide || isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; + else if (collide || isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; + } + if (xa > 0) + { + sliding = true; + if (isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; + else sliding = false; + if (isBlocking(x + xa + width, y + ya - height / 2, xa, ya)) collide = true; + else sliding = false; + if (isBlocking(x + xa + width, y + ya, xa, ya)) collide = true; + else sliding = false; + } + if (xa < 0) + { + sliding = true; + if (isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; + else sliding = false; + if (isBlocking(x + xa - width, y + ya - height / 2, xa, ya)) collide = true; + else sliding = false; + if (isBlocking(x + xa - width, y + ya, xa, ya)) collide = true; + else sliding = false; + } + + if (collide) + { + if (xa < 0) + { + x = (int) ((x - width) / 16) * 16 + width; + this.xa = 0; + } + if (xa > 0) + { + x = (int) ((x + width) / 16 + 1) * 16 - width - 1; + this.xa = 0; + } + if (ya < 0) + { + y = (int) ((y - height) / 16) * 16 + height; + jumpTime = 0; + this.ya = 0; + } + if (ya > 0) + { + y = (int) ((y - 1) / 16 + 1) * 16 - 1; + onGround = true; + } + return false; + } + else + { + x += xa; + y += ya; + return true; + } + } + + private boolean isBlocking(float _x, float _y, float xa, float ya) + { + //translate into block mode (since blocks are 16x16) + int x = (int) (_x / 16); + int y = (int) (_y / 16); + + if (x==(int)(this.x/16) && y==(int)(this.y/16)) + return false; + + boolean blocking = world.level.isBlocking(x, y, xa, ya); + + byte block = world.level.getBlock(x, y); + + if (((Level.TILE_BEHAVIORS[block & 0xff]) & Level.BIT_PICKUPABLE) > 0) + { + if(world.recorder != null) + world.recorder.recordCoin(); + + Mario.getCoin(); + world.sound.play(Art.samples[Art.SAMPLE_GET_COIN], new FixedSoundSource(x * 16 + 8, y * 16 + 8), 1, 1, 1); + world.level.setBlock(x, y, (byte) 0); + for (int xx = 0; xx < 2; xx++) + for (int yy = 0; yy < 2; yy++) + world.addSprite(new Sparkle(x * 16 + xx * 8 + (int) (Math.random() * 8), y * 16 + yy * 8 + (int) (Math.random() * 8), 0, 0, 0, 2, 5)); + } + + if (blocking && ya < 0) + { + world.bump(x, y, large); + } + + return blocking; + } + + public void stomp(Enemy enemy) + { + if (deathTime > 0 || world.paused) return; + + float targetY = enemy.y - enemy.height / 2; + move(0, targetY - y); + + world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); + xJumpSpeed = 0; + yJumpSpeed = -1.9f; + jumpTime = 8; + ya = jumpTime * yJumpSpeed; + onGround = false; + sliding = false; + invulnerableTime = 1; + + if(world.recorder!=null) + world.recorder.killStompRecord(enemy); + } + + public void stomp(Shell shell) + { + if (deathTime > 0 || world.paused) return; + + if (keys[KEY_SPEED] && shell.facing == 0) + { + carried = shell; + shell.carried = true; + } + else + { + float targetY = shell.y - shell.height / 2; + move(0, targetY - y); + + world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); + xJumpSpeed = 0; + yJumpSpeed = -1.9f; + jumpTime = 8; + ya = jumpTime * yJumpSpeed; + onGround = false; + sliding = false; + invulnerableTime = 1; + + if(shell.xa == 0 && world.recorder!= null){ + world.recorder.shellUnleashedRecord(); + } + } + } + + public void getHurt(Sprite sprite) + { + if (deathTime > 0 || world.paused) return; + if (invulnerableTime > 0) return; + + if (large) + { + world.paused = true; + powerUpTime = -3 * 6; + world.sound.play(Art.samples[Art.SAMPLE_MARIO_POWER_DOWN], this, 1, 1, 1); + if (fire) + { + world.mario.setLarge(true, false); + + if(world.recorder != null){ + world.recorder.endFireRecord(); + world.recorder.startLargeRecord(); + } + } + else + { + world.mario.setLarge(false, false); + + if(world.recorder != null){ + world.recorder.endLargeRecord(); + world.recorder.startLittleRecord(); + } + } + invulnerableTime = 32; + } + else + { + dieSprite(sprite); + } + } + + private void win() + { + xDeathPos = (int) x; + yDeathPos = (int) y; + world.paused = true; + winTime = 1; + Art.stopMusic(); + world.sound.play(Art.samples[Art.SAMPLE_LEVEL_EXIT], this, 1, 1, 1); + } + + public void dieSprite(Sprite sprite){ + die(); + + if(world.recorder != null){ + world.recorder.dieRecord(sprite); + } + } + + public void dieTime(){ + die(); + + if(world.recorder!=null){ + world.recorder.dieTimeRecord(); + } + } + + public void dieJump(){ + die(); + + if(world.recorder!=null){ + world.recorder.dieJumpRecord(); + } + } + + public void die() + { + xDeathPos = (int) x; + yDeathPos = (int) y; + world.paused = true; + deathTime = 1; + Art.stopMusic(); + world.sound.play(Art.samples[Art.SAMPLE_MARIO_DEATH], this, 1, 1, 1); + + if(world.recorder != null){ + + + if(running) + world.recorder.endRunningRecord(); + + if(large && !fire){ + world.recorder.endLargeRecord(); + } + + if(fire){ + world.recorder.endFireRecord(); + } + + if(!large && !fire) + world.recorder.endLittleRecord(); + + if(ducking) + world.recorder.endDuckRecord(); + + world.recorder.endTime(); + world.recorder.recordJumpLand(); + } + + large = false; + fire = false; + } + + + public void getFlower() + { + if (deathTime > 0 || world.paused) return; + + if (!fire) + { + world.paused = true; + powerUpTime = 3 * 6; + world.sound.play(Art.samples[Art.SAMPLE_MARIO_POWER_UP], this, 1, 1, 1); + world.mario.setLarge(true, true); + + if(world.recorder != null){ + if(large){ + world.recorder.endLargeRecord(); + + } + else{ + world.recorder.endLittleRecord(); + } + + world.recorder.startFireRecord(); + } + } + else + { + Mario.getCoin(); + world.sound.play(Art.samples[Art.SAMPLE_GET_COIN], this, 1, 1, 1); + } + } + + public void getMushroom() + { + if (deathTime > 0 || world.paused) return; + + if (!large) + { + world.paused = true; + powerUpTime = 3 * 6; + world.sound.play(Art.samples[Art.SAMPLE_MARIO_POWER_UP], this, 1, 1, 1); + world.mario.setLarge(true, false); + + if(world.recorder != null){ + world.recorder.endLittleRecord(); + world.recorder.startLargeRecord(); + } + } + else + { + + Mario.getCoin(); + world.sound.play(Art.samples[Art.SAMPLE_GET_COIN], this, 1, 1, 1); + } + } + + public void kick(Shell shell) + { + if (deathTime > 0 || world.paused) return; + + if (keys[KEY_SPEED]) + { + carried = shell; + shell.carried = true; + } + else + { + world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); + invulnerableTime = 1; + + if(world.recorder!=null) + world.recorder.shellUnleashedRecord(); + } + } + + public void stomp(BulletBill bill) + { + if (deathTime > 0 || world.paused) return; + + float targetY = bill.y - bill.height / 2; + move(0, targetY - y); + + world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); + xJumpSpeed = 0; + yJumpSpeed = -1.9f; + jumpTime = 8; + ya = jumpTime * yJumpSpeed; + onGround = false; + sliding = false; + invulnerableTime = 1; + + if(world.recorder!=null) + world.recorder.killStompRecord(bill); + } + + public byte getKeyMask() + { + int mask = 0; + for (int i = 0; i < 7; i++) + { + if (keys[i]) mask |= (1 << i); + } + return (byte) mask; + } + + public void setKeys(byte mask) + { + for (int i = 0; i < 7; i++) + { + keys[i] = (mask & (1 << i)) > 0; + } + } + + public static void get1Up() + { + instance.world.sound.play(Art.samples[Art.SAMPLE_MARIO_1UP], instance, 1, 1, 1); + lives++; + if (lives==99) + { + lives = 99; + } + } + + public static void getCoin() + { + coins++; + if (coins==100) + { + coins = 0; + get1Up(); + } + } +} diff --git a/src/dk/itu/mario/engine/sprites/Mushroom.java b/src/dk/itu/mario/engine/sprites/Mushroom.java new file mode 100644 index 0000000..cdd44d8 --- /dev/null +++ b/src/dk/itu/mario/engine/sprites/Mushroom.java @@ -0,0 +1,223 @@ +package dk.itu.mario.engine.sprites; + + +import dk.itu.mario.engine.Art; +import dk.itu.mario.scene.LevelScene; + + + +public class Mushroom extends Sprite +{ + private static float GROUND_INERTIA = 0.89f; + private static float AIR_INERTIA = 0.89f; + + private float runTime; + private boolean onGround = false; + private boolean mayJump = false; + private int jumpTime = 0; + private float xJumpSpeed; + private float yJumpSpeed; + + private int width = 4; + int height = 24; + + private LevelScene world; + public int facing; + + public boolean avoidCliffs = false; + private int life; + + public Mushroom(LevelScene world, int x, int y) + { + sheet = Art.items; + + this.x = x; + this.y = y; + this.world = world; + xPicO = 8; + yPicO = 15; + + yPic = 0; + height = 12; + facing = 1; + wPic = hPic = 16; + life = 0; + } + + public void collideCheck() + { + float xMarioD = world.mario.x - x; + float yMarioD = world.mario.y - y; + float w = 16; + if (xMarioD > -16 && xMarioD < 16) + { + if (yMarioD > -height && yMarioD < world.mario.height) + { + world.mario.getMushroom(); + spriteContext.removeSprite(this); + } + } + } + + public void move() + { + if (life<9) + { + layer = 0; + y--; + life++; + return; + } + float sideWaysSpeed = 1.75f; + layer = 1; + // float sideWaysSpeed = onGround ? 2.5f : 1.2f; + + if (xa > 2) + { + facing = 1; + } + if (xa < -2) + { + facing = -1; + } + + xa = facing * sideWaysSpeed; + + mayJump = (onGround); + + xFlipPic = facing == -1; + + runTime += (Math.abs(xa)) + 5; + + + + if (!move(xa, 0)) facing = -facing; + onGround = false; + move(0, ya); + + ya *= 0.85f; + if (onGround) + { + xa *= GROUND_INERTIA; + } + else + { + xa *= AIR_INERTIA; + } + + if (!onGround) + { + ya += 2; + } + } + + private boolean move(float xa, float ya) + { + while (xa > 8) + { + if (!move(8, 0)) return false; + xa -= 8; + } + while (xa < -8) + { + if (!move(-8, 0)) return false; + xa += 8; + } + while (ya > 8) + { + if (!move(0, 8)) return false; + ya -= 8; + } + while (ya < -8) + { + if (!move(0, -8)) return false; + ya += 8; + } + + boolean collide = false; + if (ya > 0) + { + if (isBlocking(x + xa - width, y + ya, xa, 0)) collide = true; + else if (isBlocking(x + xa + width, y + ya, xa, 0)) collide = true; + else if (isBlocking(x + xa - width, y + ya + 1, xa, ya)) collide = true; + else if (isBlocking(x + xa + width, y + ya + 1, xa, ya)) collide = true; + } + if (ya < 0) + { + if (isBlocking(x + xa, y + ya - height, xa, ya)) collide = true; + else if (collide || isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; + else if (collide || isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; + } + if (xa > 0) + { + if (isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; + if (isBlocking(x + xa + width, y + ya - height / 2, xa, ya)) collide = true; + if (isBlocking(x + xa + width, y + ya, xa, ya)) collide = true; + + if (avoidCliffs && onGround && !world.level.isBlocking((int) ((x + xa + width) / 16), (int) ((y) / 16 + 1), xa, 1)) collide = true; + } + if (xa < 0) + { + if (isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; + if (isBlocking(x + xa - width, y + ya - height / 2, xa, ya)) collide = true; + if (isBlocking(x + xa - width, y + ya, xa, ya)) collide = true; + + if (avoidCliffs && onGround && !world.level.isBlocking((int) ((x + xa - width) / 16), (int) ((y) / 16 + 1), xa, 1)) collide = true; + } + + if (collide) + { + if (xa < 0) + { + x = (int) ((x - width) / 16) * 16 + width; + this.xa = 0; + } + if (xa > 0) + { + x = (int) ((x + width) / 16 + 1) * 16 - width - 1; + this.xa = 0; + } + if (ya < 0) + { + y = (int) ((y - height) / 16) * 16 + height; + jumpTime = 0; + this.ya = 0; + } + if (ya > 0) + { + y = (int) (y / 16 + 1) * 16 - 1; + onGround = true; + } + return false; + } + else + { + x += xa; + y += ya; + return true; + } + } + + private boolean isBlocking(float _x, float _y, float xa, float ya) + { + int x = (int) (_x / 16); + int y = (int) (_y / 16); + if (x == (int) (this.x / 16) && y == (int) (this.y / 16)) return false; + + boolean blocking = world.level.isBlocking(x, y, xa, ya); + + byte block = world.level.getBlock(x, y); + + return blocking; + } + + public void bumpCheck(int xTile, int yTile) + { + if (x + width > xTile * 16 && x - width < xTile * 16 + 16 && yTile==(int)((y-1)/16)) + { + facing = -world.mario.facing; + ya = -10; + } + } + +} diff --git a/src/dk/itu/mario/engine/sprites/Particle.java b/src/dk/itu/mario/engine/sprites/Particle.java new file mode 100644 index 0000000..60a6ad2 --- /dev/null +++ b/src/dk/itu/mario/engine/sprites/Particle.java @@ -0,0 +1,40 @@ +package dk.itu.mario.engine.sprites; + +import dk.itu.mario.engine.Art; + + +public class Particle extends Sprite +{ + public int life; + + public Particle(int x, int y, float xa, float ya) + { + this(x, y, xa, ya, (int)(Math.random()*2), 0); + } + + public Particle(int x, int y, float xa, float ya, int xPic, int yPic) + { + sheet = Art.particles; + this.x = x; + this.y = y; + this.xa = xa; + this.ya = ya; + this.xPic = xPic; + this.yPic = yPic; + this.xPicO = 4; + this.yPicO = 4; + + wPic = 8; + hPic = 8; + life = 10; + } + + public void move() + { + if (life--<0) Sprite.spriteContext.removeSprite(this); + x+=xa; + y+=ya; + ya*=0.95f; + ya+=3; + } +} diff --git a/src/dk/itu/mario/engine/sprites/Shell.java b/src/dk/itu/mario/engine/sprites/Shell.java new file mode 100644 index 0000000..fea02b4 --- /dev/null +++ b/src/dk/itu/mario/engine/sprites/Shell.java @@ -0,0 +1,370 @@ +package dk.itu.mario.engine.sprites; + + +import dk.itu.mario.engine.Art; +import dk.itu.mario.scene.LevelScene; + + + + +public class Shell extends Sprite +{ + private static float GROUND_INERTIA = 0.89f; + private static float AIR_INERTIA = 0.89f; + + private float runTime; + private boolean onGround = false; + + private int width = 4; + int height = 24; + + private LevelScene world; + public int facing; + + public boolean avoidCliffs = false; + public int anim; + + public boolean dead = false; + private int deadTime = 0; + public boolean carried; + + + public Shell(LevelScene world, float x, float y, int type) + { + sheet = Art.enemies; + + this.x = x; + this.y = y; + this.world = world; + xPicO = 8; + yPicO = 31; + + yPic = type; + height = 12; + facing = 0; + wPic = 16; + + xPic = 4; + ya = -5; + } + + public boolean fireballCollideCheck(Fireball fireball) + { + if (deadTime != 0) return false; + + float xD = fireball.x - x; + float yD = fireball.y - y; + + if (xD > -16 && xD < 16) + { + if (yD > -height && yD < fireball.height) + { + if (facing!=0) return true; + + world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); + + xa = fireball.facing * 2; + ya = -5; + if (spriteTemplate != null) spriteTemplate.isDead = true; + deadTime = 100; + hPic = -hPic; + yPicO = -yPicO + 16; + return true; + } + } + return false; + } + + public void collideCheck() + { + if (carried || dead || deadTime>0) return; + + float xMarioD = world.mario.x - x; + float yMarioD = world.mario.y - y; + float w = 16; + if (xMarioD > -16 && xMarioD < 16) + { + if (yMarioD > -height && yMarioD < world.mario.height) + { + if (world.mario.ya > 0 && yMarioD <= 0 && (!world.mario.onGround || !world.mario.wasOnGround)) + { + world.mario.stomp(this); + if (facing != 0) + { + xa = 0; + facing = 0; + } + else + { + facing = world.mario.facing; + } + } + else + { + if (facing != 0) + { + world.mario.getHurt(this); + } + else + { + world.mario.kick(this); + facing = world.mario.facing; + } + } + } + } + } + + public void move() + { + if (y > world.level.getHeight() * 16 + 16 && deadTime == 0) + { + die(); + spriteContext.removeSprite(this); + return; + } + + if (carried) + { + world.checkShellCollide(this); + return; + } + + if (deadTime > 0) + { + deadTime--; + + if (deadTime == 0) + { + deadTime = 1; + for (int i = 0; i < 8; i++) + { + world.addSprite(new Sparkle((int) (x + Math.random() * 16 - 8) + 4, (int) (y - Math.random() * 8) + 4, (float) (Math.random() * 2 - 1), (float) Math.random() * -1, 0, 1, 5)); + } + spriteContext.removeSprite(this); + } + + x += xa; + y += ya; + ya *= 0.95; + ya += 1; + + return; + } + + if (facing != 0) anim++; + + float sideWaysSpeed = 11f; + // float sideWaysSpeed = onGround ? 2.5f : 1.2f; + + if (xa > 2) + { + facing = 1; + } + if (xa < -2) + { + facing = -1; + } + + xa = facing * sideWaysSpeed; + + if (facing != 0) + { + world.checkShellCollide(this); + } + + xFlipPic = facing == -1; + + runTime += (Math.abs(xa)) + 5; + + xPic = (anim / 2) % 4 + 3; + + + + if (!move(xa, 0)) + { + world.sound.play(Art.samples[Art.SAMPLE_SHELL_BUMP], this, 1, 1, 1); + + facing = -facing; + } + onGround = false; + move(0, ya); + + ya *= 0.85f; + if (onGround) + { + xa *= GROUND_INERTIA; + } + else + { + xa *= AIR_INERTIA; + } + + if (!onGround) + { + ya += 2; + } + } + + private boolean move(float xa, float ya) + { + while (xa > 8) + { + if (!move(8, 0)) return false; + xa -= 8; + } + while (xa < -8) + { + if (!move(-8, 0)) return false; + xa += 8; + } + while (ya > 8) + { + if (!move(0, 8)) return false; + ya -= 8; + } + while (ya < -8) + { + if (!move(0, -8)) return false; + ya += 8; + } + + boolean collide = false; + if (ya > 0) + { + if (isBlocking(x + xa - width, y + ya, xa, 0)) collide = true; + else if (isBlocking(x + xa + width, y + ya, xa, 0)) collide = true; + else if (isBlocking(x + xa - width, y + ya + 1, xa, ya)) collide = true; + else if (isBlocking(x + xa + width, y + ya + 1, xa, ya)) collide = true; + } + if (ya < 0) + { + if (isBlocking(x + xa, y + ya - height, xa, ya)) collide = true; + else if (collide || isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; + else if (collide || isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; + } + if (xa > 0) + { + if (isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; + if (isBlocking(x + xa + width, y + ya - height / 2, xa, ya)) collide = true; + if (isBlocking(x + xa + width, y + ya, xa, ya)) collide = true; + + if (avoidCliffs && onGround && !world.level.isBlocking((int) ((x + xa + width) / 16), (int) ((y) / 16 + 1), xa, 1)) collide = true; + } + if (xa < 0) + { + if (isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; + if (isBlocking(x + xa - width, y + ya - height / 2, xa, ya)) collide = true; + if (isBlocking(x + xa - width, y + ya, xa, ya)) collide = true; + + if (avoidCliffs && onGround && !world.level.isBlocking((int) ((x + xa - width) / 16), (int) ((y) / 16 + 1), xa, 1)) collide = true; + } + + if (collide) + { + if (xa < 0) + { + x = (int) ((x - width) / 16) * 16 + width; + this.xa = 0; + } + if (xa > 0) + { + x = (int) ((x + width) / 16 + 1) * 16 - width - 1; + this.xa = 0; + } + if (ya < 0) + { + y = (int) ((y - height) / 16) * 16 + height; + this.ya = 0; + } + if (ya > 0) + { + y = (int) (y / 16 + 1) * 16 - 1; + onGround = true; + } + return false; + } + else + { + x += xa; + y += ya; + return true; + } + } + + private boolean isBlocking(float _x, float _y, float xa, float ya) + { + int x = (int) (_x / 16); + int y = (int) (_y / 16); + if (x == (int) (this.x / 16) && y == (int) (this.y / 16)) return false; + + boolean blocking = world.level.isBlocking(x, y, xa, ya); + + byte block = world.level.getBlock(x, y); + + if (blocking && ya == 0 && xa!=0) + { + world.bump(x, y, true); + } + + return blocking; + } + + public void bumpCheck(int xTile, int yTile) + { + if (x + width > xTile * 16 && x - width < xTile * 16 + 16 && yTile == (int) ((y - 1) / 16)) + { + facing = -world.mario.facing; + ya = -10; + } + } + + public void die() + { + dead = true; + + carried = false; + + xa = -facing * 2; + ya = -5; + deadTime = 100; + + if(world.recorder != null) + world.recorder.killRecord(this); + } + + public boolean shellCollideCheck(Shell shell) + { + if (deadTime != 0) return false; + + float xD = shell.x - x; + float yD = shell.y - y; + + if (xD > -16 && xD < 16) + { + if (yD > -height && yD < shell.height) + { + world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); + + if (world.mario.carried == shell || world.mario.carried == this) + { + world.mario.carried = null; + } + + die(); + shell.die(); + + return true; + } + } + return false; + } + + + public void release(Mario mario) + { + carried = false; + facing = mario.facing; + x += facing * 8; + } +} diff --git a/src/dk/itu/mario/engine/sprites/Sparkle.java b/src/dk/itu/mario/engine/sprites/Sparkle.java new file mode 100644 index 0000000..3a06850 --- /dev/null +++ b/src/dk/itu/mario/engine/sprites/Sparkle.java @@ -0,0 +1,46 @@ +package dk.itu.mario.engine.sprites; + +import dk.itu.mario.engine.Art; + + +public class Sparkle extends Sprite +{ + public int life; + public int xPicStart; + + public Sparkle(int x, int y, float xa, float ya) + { + this(x, y, xa, ya, (int)(Math.random()*2), 0, 5); + } + + public Sparkle(int x, int y, float xa, float ya, int xPic, int yPic, int timeSpan) + { + sheet = Art.particles; + this.x = x; + this.y = y; + this.xa = xa; + this.ya = ya; + this.xPic = xPic; + xPicStart = xPic; + this.yPic = yPic; + this.xPicO = 4; + this.yPicO = 4; + + wPic = 8; + hPic = 8; + life = 10+(int)(Math.random()*timeSpan); + } + + public void move() + { + if (life>10) + xPic = 7; + else + xPic = xPicStart+(10-life)*4/10; + + if (life--<0) Sprite.spriteContext.removeSprite(this); + + x+=xa; + y+=ya; + } +} diff --git a/src/dk/itu/mario/engine/sprites/Sprite.java b/src/dk/itu/mario/engine/sprites/Sprite.java new file mode 100644 index 0000000..0ebed58 --- /dev/null +++ b/src/dk/itu/mario/engine/sprites/Sprite.java @@ -0,0 +1,117 @@ +package dk.itu.mario.engine.sprites; + +import java.awt.Graphics; +import java.awt.Image; + + + + + +import dk.itu.mario.engine.sonar.SoundSource; + +public class Sprite implements SoundSource +{ + public static SpriteContext spriteContext; + + public float xOld, yOld, x, y, xa, ya; + + public int xPic, yPic; + public int wPic = 32; + public int hPic = 32; + public int xPicO, yPicO; + public boolean xFlipPic = false; + public boolean yFlipPic = false; + public Image[][] sheet; + public boolean visible = true; + + public int layer = 1; + + public SpriteTemplate spriteTemplate; + + public void move() + { + x+=xa; + y+=ya; + } + + public void render(Graphics og, float alpha) + { + if (!visible) return; + + int xPixel = (int)(xOld+(x-xOld)*alpha)-xPicO; + int yPixel = (int)(yOld+(y-yOld)*alpha)-yPicO; + + og.drawImage(sheet[xPic][yPic], xPixel+(xFlipPic?wPic:0), yPixel+(yFlipPic?hPic:0), xFlipPic?-wPic:wPic, yFlipPic?-hPic:hPic, null); + } + +/* private void blit(Graphics og, Image bitmap, int x0, int y0, int x1, int y1, int w, int h) + { + if (!xFlipPic) + { + if (!yFlipPic) + { + og.drawImage(bitmap, x0, y0, x0+w, y0+h, x1, y1, x1+w, y1+h, null); + } + else + { + og.drawImage(bitmap, x0, y0, x0+w, y0+h, x1, y1+h, x1+w, y1, null); + } + } + else + { + if (!yFlipPic) + { + og.drawImage(bitmap, x0, y0, x0+w, y0+h, x1+w, y1, x1, y1+h, null); + } + else + { + og.drawImage(bitmap, x0, y0, x0+w, y0+h, x1+w, y1+h, x1, y1, null); + } + } + }*/ + + public final void tick() + { + xOld = x; + yOld = y; + move(); + } + + public final void tickNoMove() + { + xOld = x; + yOld = y; + } + + public float getX(float alpha) + { + return (xOld+(x-xOld)*alpha)-xPicO; + } + + public float getY(float alpha) + { + return (yOld+(y-yOld)*alpha)-yPicO; + } + + public void collideCheck() + { + } + + public void bumpCheck(int xTile, int yTile) + { + } + + public boolean shellCollideCheck(Shell shell) + { + return false; + } + + public void release(Mario mario) + { + } + + public boolean fireballCollideCheck(Fireball fireball) + { + return false; + } +} diff --git a/src/dk/itu/mario/engine/sprites/SpriteContext.java b/src/dk/itu/mario/engine/sprites/SpriteContext.java new file mode 100644 index 0000000..5246861 --- /dev/null +++ b/src/dk/itu/mario/engine/sprites/SpriteContext.java @@ -0,0 +1,18 @@ +package dk.itu.mario.engine.sprites; + +/** + *

Title:

+ * + *

Description:

+ * + *

Copyright: Copyright (c) 2010

+ * + *

Company:

+ * + * @author not attributable + * @version 1.0 + */ +public interface SpriteContext { + public void addSprite(Sprite sprite); + public void removeSprite(Sprite sprite); +} diff --git a/src/dk/itu/mario/engine/sprites/SpriteTemplate.java b/src/dk/itu/mario/engine/sprites/SpriteTemplate.java new file mode 100644 index 0000000..931c392 --- /dev/null +++ b/src/dk/itu/mario/engine/sprites/SpriteTemplate.java @@ -0,0 +1,60 @@ +package dk.itu.mario.engine.sprites; + +import dk.itu.mario.scene.LevelScene; + +public class SpriteTemplate +{ + public static final int RED_TURTLE = 0; + public static final int GREEN_TURTLE = 1; + public static final int GOOMPA = 2; + public static final int ARMORED_TURTLE = 3; + public static final int JUMP_FLOWER = 4; + public static final int CANNON_BALL = 5; + public static final int CHOMP_FLOWER = 6; + + public static int enemiesSpawned = 0; + public static int enemiesMax = 1000; + + public boolean hasSpawned = false; + + public int lastVisibleTick = -1; + public Sprite sprite; + public boolean isDead = false; + private boolean winged; + + public int type; + public int direction = 1; + + public SpriteTemplate(int type, boolean winged) + { + this.type = type; + this.winged = winged; + } + + public void spawn(LevelScene world, int x, int y, int dir) + { + if (isDead || enemiesSpawned >= enemiesMax) return; + + if (type==Enemy.ENEMY_FLOWER) + { + sprite = new FlowerEnemy(world, x*16+15, y*16+24); + } + else + { + sprite = new Enemy(world, x*16+8, y*16+15, dir, type, winged); + } + + //correct for flipping + if(direction == -1){ + sprite.x -= 14; + } + + sprite.spriteTemplate = this; + world.addSprite(sprite); + + if(!hasSpawned) + enemiesSpawned++; + + hasSpawned = true; + } +} diff --git a/src/dk/itu/mario/engine/util/.DS_Store b/src/dk/itu/mario/engine/util/.DS_Store new file mode 100644 index 0000000..b29de3e Binary files /dev/null and b/src/dk/itu/mario/engine/util/.DS_Store differ diff --git a/src/dk/itu/mario/engine/util/FileHandler.java b/src/dk/itu/mario/engine/util/FileHandler.java new file mode 100644 index 0000000..4948d07 --- /dev/null +++ b/src/dk/itu/mario/engine/util/FileHandler.java @@ -0,0 +1,37 @@ +package dk.itu.mario.engine.util; + +import java.io.BufferedReader; +import java.io.FileReader; + +public class FileHandler { + + public static String readFile(String fileName){ + String info = ""; + try { + FileReader input = new FileReader(fileName); + BufferedReader bufRead = new BufferedReader(input); + + String line; + + int count = 0; + line = bufRead.readLine(); + info = line +"\n"; + count++; + + + while (line != null){ +// System.out.println(count+": "+line); + line = bufRead.readLine(); + info += line + "\n"; + count++; + } + + bufRead.close(); + + }catch (Exception e){ + // If another exception is generated, print a stack trace + e.printStackTrace(); + } + return info; + } +} diff --git a/src/dk/itu/mario/engine/util/UIItem.java b/src/dk/itu/mario/engine/util/UIItem.java new file mode 100644 index 0000000..c8aac1d --- /dev/null +++ b/src/dk/itu/mario/engine/util/UIItem.java @@ -0,0 +1,22 @@ +package dk.itu.mario.engine.util; + +import java.awt.Graphics; + +public abstract class UIItem{ + + protected int x,y; + protected boolean selected; + protected int width,height; + + public abstract void render(Graphics g); + public abstract void prev(); + public abstract void next(); + + public void setSelected(){ + selected = true; + } + + public void setUnselected(){ + selected = false; + } +} diff --git a/src/dk/itu/mario/engine/util/UITextArea.java b/src/dk/itu/mario/engine/util/UITextArea.java new file mode 100644 index 0000000..8154abe --- /dev/null +++ b/src/dk/itu/mario/engine/util/UITextArea.java @@ -0,0 +1,83 @@ +package dk.itu.mario.engine.util; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; + +public class UITextArea extends UIItem{ + + protected String text; + protected int width, height; + protected Font font; + protected ArrayList lines = new ArrayList(); + + public static boolean showBox = false; + + public UITextArea(String text, Font font, int x, int y, int width){ + this.text = text; + this.font = font; + this.x = x; + this.y = y; + this.width = width; + } + + public void next() { + } + + public void prev() { + } + + public void render(Graphics g) { + Graphics2D g2 = (Graphics2D)g; + + g.setFont(font); + + lines.clear(); + + Rectangle2D rec = font.getStringBounds(text,g2.getFontRenderContext()); + + String tempText = new String(); + + if(rec.getWidth()>width){ + for(int i=0;i=width){ + lines.add(tempText); + tempText = new String(); + } + } + + lines.add(tempText); + } + else{ + lines.add(text); + } + + for(int j=0;j h1 ? 1 : 0; + if (h0 == oh) + s = 1 - s; + s += distant ? 2 : 0; + level.setBlock(x, y, (byte) (s + 8)); + } + } + } + break; + } + case LevelInterface.TYPE_UNDERGROUND: { + if (distant) { + int tt = 0; + for (int x = 0; x < width; x++) { + if (random.nextDouble() < 0.75) + tt = 1 - tt; + for (int y = 0; y < height; y++) { + int t = tt; + int yy = y - 2; + if (yy < 0 || yy > 4) { + yy = 2; + t = 0; + } + level.setBlock(x, y, (byte) (4 + t + (3 + yy) * 8)); + } + } + } else { + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + int t = x % 2; + int yy = y - 1; + if (yy < 0 || yy > 7) { + yy = 7; + t = 0; + } + if (t == 0 && yy > 1 && yy < 5) { + t = -1; + yy = 0; + } + level.setBlock(x, y, (byte) (6 + t + (yy) * 8)); + } + } + } + break; + } + case LevelInterface.TYPE_CASTLE: { + if (distant) { + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + int t = x % 2; + int yy = y - 1; + if (yy > 2 && yy < 5) { + yy = 2; + } else if (yy >= 5) { + yy -= 2; + } + if (yy < 0) { + t = 0; + yy = 5; + } else if (yy > 4) { + t = 1; + yy = 5; + } else if (t < 1 && yy == 3) { + t = 0; + yy = 3; + } else if (t < 1 && yy > 0 && yy < 3) { + t = 0; + yy = 2; + } + level.setBlock(x, y, (byte) (1 + t + (yy + 4) * 8)); + } + } + } else { + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + int t = x % 3; + int yy = y - 1; + if (yy > 2 && yy < 5) { + yy = 2; + } else if (yy >= 5) { + yy -= 2; + } + if (yy < 0) { + t = 1; + yy = 5; + } else if (yy > 4) { + t = 2; + yy = 5; + } else if (t < 2 && yy == 4) { + t = 2; + yy = 4; + } else if (t < 2 && yy > 0 && yy < 4) { + t = 4; + yy = -3; + } + level.setBlock(x, y, (byte) (1 + t + (yy + 3) * 8)); + } + } + } + break; + } + } + return level; + } +} diff --git a/src/dk/itu/mario/level/CustomizedLevel.java b/src/dk/itu/mario/level/CustomizedLevel.java new file mode 100644 index 0000000..475d1cf --- /dev/null +++ b/src/dk/itu/mario/level/CustomizedLevel.java @@ -0,0 +1,563 @@ +package dk.itu.mario.level; + +import java.util.Random; + +import dk.itu.mario.MarioInterface.Constraints; +import dk.itu.mario.MarioInterface.GamePlay; +import dk.itu.mario.MarioInterface.LevelInterface; +import dk.itu.mario.engine.sprites.Enemy; +import dk.itu.mario.engine.sprites.SpriteTemplate; + +public class CustomizedLevel extends Level implements LevelInterface { + + Random random; + + private static final int ODDS_STRAIGHT = 0; + private static final int ODDS_HILL_STRAIGHT = 1; + private static final int ODDS_TUBES = 2; + private static final int ODDS_JUMP = 3; + private static final int ODDS_CANNONS = 4; + private static final int JumpingThreshold = 3; + + private int[] odds = new int[5]; + private int totalOdds; + + private int difficulty; + private int type; + private int gaps; + private int turtles; + private int coins; + + private GamePlay playerM; + + public CustomizedLevel(int width, int height, long seed, int difficulty, + int type, GamePlay playerMetrics) { + super(width, height); + this.playerM = playerMetrics; + creat(seed, difficulty, type); + } + + public void creat(long seed, int difficulty, int type) { + this.type = type; + this.difficulty = difficulty; + odds[ODDS_STRAIGHT] = 30; + odds[ODDS_HILL_STRAIGHT] = 20; + odds[ODDS_TUBES] = 2 + 2 * difficulty; + int jumpDifficulty = 1; + // adapt the game so that it has a number of gaps proportional to the + // number of jumps the player made in the test level. The more the + // jumps, + // the more the gaps. + if (playerM.jumpsNumber > JumpingThreshold) + jumpDifficulty = 2; + odds[ODDS_JUMP] = jumpDifficulty; + odds[ODDS_CANNONS] = -10 + 5 * difficulty; + + if (type != LevelInterface.TYPE_OVERGROUND) { + odds[ODDS_HILL_STRAIGHT] = 0; + } + + for (int i = 0; i < odds.length; i++) { + // failsafe (no negative odds) + if (odds[i] < 0) { + odds[i] = 0; + } + + totalOdds += odds[i]; + odds[i] = totalOdds - odds[i]; + } + + random = new Random(seed); + + // create the start location + int length = 0; + length += buildStraight(0, getWidth(), true); + + // create all of the medium sections + while (length < getWidth() - 64) { + length += buildZone(length, getWidth() - length); + } + + // set the end piece + int floor = height - 1 - random.nextInt(4); + + // create the exit + xExit = length + 8; + yExit = floor; + + for (int x = length; x < getWidth(); x++) { + for (int y = 0; y < height; y++) { + if (y >= floor) { + setBlock(x, y, Level.GROUND); + } + } + } + + if (type == LevelInterface.TYPE_CASTLE + || type == LevelInterface.TYPE_UNDERGROUND) { + int ceiling = 0; + int run = 0; + for (int x = 0; x < width; x++) { + if (run-- <= 0 && x > 4) { + ceiling = random.nextInt(4); + run = random.nextInt(4) + 4; + } + for (int y = 0; y < height; y++) { + if ((x > 4 && y <= ceiling) || x < 1) { + setBlock(x, y, GROUND); + } + } + } + } + + fixWalls(); + + } + + private int buildZone(int x, int maxLength) { + int t = random.nextInt(totalOdds); + int type = 0; + + for (int i = 0; i < odds.length; i++) { + if (odds[ODDS_JUMP] <= t * 2 + 30) { + type = ODDS_JUMP; + break; + } + if (odds[i] <= t) { + type = i; + } + } + + switch (type) { + case ODDS_STRAIGHT: + return buildStraight(x, maxLength, false); + case ODDS_HILL_STRAIGHT: + return buildHillStraight(x, maxLength); + case ODDS_TUBES: + return buildTubes(x, maxLength); + case ODDS_JUMP: + if (gaps < Constraints.gaps) + return buildJump(x, maxLength); + else + return buildStraight(x, maxLength, false); + case ODDS_CANNONS: + return buildCannons(x, maxLength); + } + return 0; + } + + private int buildJump(int xo, int maxLength) { + gaps++; + // jl: jump length + // js: the number of blocks that are available at either side for free + int js = random.nextInt(4) + 2; + int jl = random.nextInt(2) + 2; + int length = js * 2 + jl; + + boolean hasStairs = random.nextInt(3) == 0; + + int floor = height - 1 - random.nextInt(4); + // run for the from the start x position, for the whole length + for (int x = xo; x < xo + length; x++) { + if (x < xo + js || x > xo + length - js - 1) { + // run for all y's since we need to paint blocks upward + for (int y = 0; y < height; y++) { // paint ground up until the + // floor + if (y >= floor) { + setBlock(x, y, GROUND); + } + // if it is above ground, start making stairs of rocks + else if (hasStairs) { // LEFT SIDE + if (x < xo + js) { // we need to max it out and level + // because it wont + // paint ground correctly unless two bricks are side + // by side + if (y >= floor - (x - xo) + 1) { + setBlock(x, y, ROCK); + } + } else { // RIGHT SIDE + if (y >= floor - ((xo + length) - x) + 2) { + setBlock(x, y, ROCK); + } + } + } + } + } + } + + return length; + } + + private int buildCannons(int xo, int maxLength) { + int length = random.nextInt(10) + 2; + if (length > maxLength) + length = maxLength; + + int floor = height - 1 - random.nextInt(4); + int xCannon = xo + 1 + random.nextInt(4); + for (int x = xo; x < xo + length; x++) { + if (x > xCannon) { + xCannon += 2 + random.nextInt(4); + } + if (xCannon == xo + length - 1) + xCannon += 10; + int cannonHeight = floor - random.nextInt(4) - 1; + + for (int y = 0; y < height; y++) { + if (y >= floor) { + setBlock(x, y, (byte) (1 + 9 * 16)); + } else { + if (x == xCannon && y >= cannonHeight) { + if (y == cannonHeight) { + setBlock(x, y, (byte) (14 + 0 * 16)); + } else if (y == cannonHeight + 1) { + setBlock(x, y, (byte) (14 + 1 * 16)); + } else { + setBlock(x, y, (byte) (14 + 2 * 16)); + } + } + } + } + } + + return length; + } + + private int buildHillStraight(int xo, int maxLength) { + int length = random.nextInt(10) + 10; + if (length > maxLength) + length = maxLength; + + int floor = height - 1 - random.nextInt(4); + for (int x = xo; x < xo + length; x++) { + for (int y = 0; y < height; y++) { + if (y >= floor) { + setBlock(x, y, Level.GROUND); + } + } + } + + addEnemyLine(xo + 1, xo + length - 1, floor - 1); + + int h = floor; + + boolean keepGoing = true; + + boolean[] occupied = new boolean[length]; + while (keepGoing) { + h = h - 2 - random.nextInt(3); + + if (h <= 0) { + keepGoing = false; + } else { + int l = random.nextInt(5) + 3; + int xxo = random.nextInt(length - l - 2) + xo + 1; + + if (occupied[xxo - xo] || occupied[xxo - xo + l] + || occupied[xxo - xo - 1] || occupied[xxo - xo + l + 1]) { + keepGoing = false; + } else { + occupied[xxo - xo] = true; + occupied[xxo - xo + l] = true; + addEnemyLine(xxo, xxo + l, h - 1); + if (random.nextInt(4) == 0) { + decorate(xxo - 1, xxo + l + 1, h); + keepGoing = false; + } + for (int x = xxo; x < xxo + l; x++) { + for (int y = h; y < floor; y++) { + int xx = 5; + if (x == xxo) + xx = 4; + if (x == xxo + l - 1) + xx = 6; + int yy = 9; + if (y == h) + yy = 8; + + if (getBlock(x, y) == 0) { + setBlock(x, y, (byte) (xx + yy * 16)); + } else { + if (getBlock(x, y) == Level.HILL_TOP_LEFT) + setBlock(x, y, Level.HILL_TOP_LEFT_IN); + if (getBlock(x, y) == Level.HILL_TOP_RIGHT) + setBlock(x, y, Level.HILL_TOP_RIGHT_IN); + } + } + } + } + } + } + + return length; + } + + private void addEnemyLine(int x0, int x1, int y) { + for (int x = x0; x < x1; x++) { + if (random.nextInt(50) < 25) { + int type = random.nextInt(4); + + type = random.nextInt(3); + if (turtles < Constraints.turtels) { + if (type == Enemy.ENEMY_GREEN_KOOPA + || type == Enemy.ENEMY_RED_KOOPA) { + turtles++; + setSpriteTemplate(x, y, + new SpriteTemplate(type, + random.nextInt(35) < difficulty)); + } else { + setSpriteTemplate(x, y, + new SpriteTemplate(type, + random.nextInt(35) < difficulty)); + } + } else { + setSpriteTemplate( + x, + y, + new SpriteTemplate(Enemy.ENEMY_GOOMBA, random + .nextInt(35) < difficulty)); + } + } + } + } + + private int buildTubes(int xo, int maxLength) { + int length = random.nextInt(10) + 5; + if (length > maxLength) + length = maxLength; + + int floor = height - 1 - random.nextInt(4); + int xTube = xo + 1 + random.nextInt(4); + int tubeHeight = floor - random.nextInt(2) - 2; + for (int x = xo; x < xo + length; x++) { + if (x > xTube + 1) { + xTube += 3 + random.nextInt(4); + tubeHeight = floor - random.nextInt(2) - 2; + } + if (xTube >= xo + length - 2) + xTube += 10; + + if (x == xTube && random.nextInt(11) < difficulty + 1) { + setSpriteTemplate(x, tubeHeight, new SpriteTemplate( + Enemy.ENEMY_FLOWER, false)); + } + + for (int y = 0; y < height; y++) { + if (y >= floor) { + setBlock(x, y, (byte) (1 + 9 * 16)); + + } else { + if ((x == xTube || x == xTube + 1) && y >= tubeHeight) { + int xPic = 10 + x - xTube; + + if (y == tubeHeight) { + // tube top + setBlock(x, y, (byte) (xPic + 0 * 16)); + } else { + // tube side + setBlock(x, y, (byte) (xPic + 1 * 16)); + } + } + } + } + } + + return length; + } + + private int buildStraight(int xo, int maxLength, boolean safe) { + int length = random.nextInt(10) + 2; + + if (safe) + length = 10 + random.nextInt(5); + + if (length > maxLength) + length = maxLength; + + int floor = height - 1 - random.nextInt(4); + + // runs from the specified x position to the length of the segment + for (int x = xo; x < xo + length; x++) { + for (int y = 0; y < height; y++) { + if (y >= floor) { + setBlock(x, y, Level.GROUND); + } + } + } + + if (!safe) { + if (length > 5) { + decorate(xo, xo + length, floor); + } + } + + return length; + } + + private void decorate(int xStart, int xLength, int floor) { + // if its at the very top, just return + if (floor < 1) + return; + boolean rocks = true; + + // add an enemy line above the box + addEnemyLine(xStart + 1, xLength - 1, floor - 1); + + int s = random.nextInt(4); + int e = random.nextInt(4); + + if (floor - 2 > 0) { + if ((xLength - 1 - e) - (xStart + 1 + s) > 1) { + for (int x = xStart + 1 + s; x < xLength - 1 - e; x++) { + setBlock(x, floor - 2, (byte) (2 + 2 * 16)); + } + } + } + + s = random.nextInt(4); + e = random.nextInt(4); + + if (floor - 4 > 0) { + if ((xLength - 1 - e) - (xStart + 1 + s) > 2) { + for (int x = xStart + 1 + s; x < xLength - 1 - e; x++) { + if (rocks) { + if (x != xStart + 1 && x != xLength - 2 + && random.nextInt(2) == 0) { + if (random.nextInt(2) == 0) { + setBlock(x, floor - 4, BLOCK_POWERUP); + } else { + if (coins < Constraints.coinBlocks) { + coins++; + setBlock(x, floor - 4, BLOCK_COIN); + } else { + setBlock(x, floor - 4, BLOCK_EMPTY); + } + } + } else if (random.nextInt(4) == 0) { + if (random.nextInt(4) == 0) { + setBlock(x, floor - 4, (byte) (2 + 1 * 16)); + } else { + setBlock(x, floor - 4, (byte) (1 + 1 * 16)); + } + } else { + setBlock(x, floor - 4, BLOCK_EMPTY); + } + } + } + } + } + } + + private void fixWalls() { + boolean[][] blockMap = new boolean[width + 1][height + 1]; + + for (int x = 0; x < width + 1; x++) { + for (int y = 0; y < height + 1; y++) { + int blocks = 0; + for (int xx = x - 1; xx < x + 1; xx++) { + for (int yy = y - 1; yy < y + 1; yy++) { + if (getBlockCapped(xx, yy) == GROUND) { + blocks++; + } + } + } + blockMap[x][y] = blocks == 4; + } + } + blockify(this, blockMap, width + 1, height + 1); + } + + private void blockify(Level level, boolean[][] blocks, int width, int height) { + int to = 0; + if (type == LevelInterface.TYPE_CASTLE) { + to = 4 * 2; + } else if (type == LevelInterface.TYPE_UNDERGROUND) { + to = 4 * 3; + } + + boolean[][] b = new boolean[2][2]; + + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + for (int xx = x; xx <= x + 1; xx++) { + for (int yy = y; yy <= y + 1; yy++) { + int _xx = xx; + int _yy = yy; + if (_xx < 0) + _xx = 0; + if (_yy < 0) + _yy = 0; + if (_xx > width - 1) + _xx = width - 1; + if (_yy > height - 1) + _yy = height - 1; + b[xx - x][yy - y] = blocks[_xx][_yy]; + } + } + + if (b[0][0] == b[1][0] && b[0][1] == b[1][1]) { + if (b[0][0] == b[0][1]) { + if (b[0][0]) { + level.setBlock(x, y, (byte) (1 + 9 * 16 + to)); + } else { + // KEEP OLD BLOCK! + } + } else { + if (b[0][0]) { + // down grass top? + level.setBlock(x, y, (byte) (1 + 10 * 16 + to)); + } else { + // up grass top + level.setBlock(x, y, (byte) (1 + 8 * 16 + to)); + } + } + } else if (b[0][0] == b[0][1] && b[1][0] == b[1][1]) { + if (b[0][0]) { + // right grass top + level.setBlock(x, y, (byte) (2 + 9 * 16 + to)); + } else { + // left grass top + level.setBlock(x, y, (byte) (0 + 9 * 16 + to)); + } + } else if (b[0][0] == b[1][1] && b[0][1] == b[1][0]) { + level.setBlock(x, y, (byte) (1 + 9 * 16 + to)); + } else if (b[0][0] == b[1][0]) { + if (b[0][0]) { + if (b[0][1]) { + level.setBlock(x, y, (byte) (3 + 10 * 16 + to)); + } else { + level.setBlock(x, y, (byte) (3 + 11 * 16 + to)); + } + } else { + if (b[0][1]) { + // right up grass top + level.setBlock(x, y, (byte) (2 + 8 * 16 + to)); + } else { + // left up grass top + level.setBlock(x, y, (byte) (0 + 8 * 16 + to)); + } + } + } else if (b[0][1] == b[1][1]) { + if (b[0][1]) { + if (b[0][0]) { + // left pocket grass + level.setBlock(x, y, (byte) (3 + 9 * 16 + to)); + } else { + // right pocket grass + level.setBlock(x, y, (byte) (3 + 8 * 16 + to)); + } + } else { + if (b[0][0]) { + level.setBlock(x, y, (byte) (2 + 10 * 16 + to)); + } else { + level.setBlock(x, y, (byte) (0 + 10 * 16 + to)); + } + } + } else { + level.setBlock(x, y, (byte) (0 + 1 * 16 + to)); + } + } + } + } + +} \ No newline at end of file diff --git a/src/dk/itu/mario/level/Level.java b/src/dk/itu/mario/level/Level.java new file mode 100644 index 0000000..e93c8d8 --- /dev/null +++ b/src/dk/itu/mario/level/Level.java @@ -0,0 +1,216 @@ +package dk.itu.mario.level; + +import java.io.*; + +import dk.itu.mario.MarioInterface.LevelInterface; +import dk.itu.mario.engine.sprites.SpriteTemplate; + + +public class Level implements LevelInterface +{ + + protected static final byte BLOCK_EMPTY = (byte) (0 + 1 * 16); + protected static final byte BLOCK_POWERUP = (byte) (4 + 2 + 1 * 16); + protected static final byte BLOCK_COIN = (byte) (4 + 1 + 1 * 16); + protected static final byte GROUND = (byte) (1 + 9 * 16); + protected static final byte ROCK = (byte) (9 + 0 * 16); + protected static final byte COIN = (byte) (2 + 2 * 16); + + + protected static final byte LEFT_GRASS_EDGE = (byte) (0+9*16); + protected static final byte RIGHT_GRASS_EDGE = (byte) (2+9*16); + protected static final byte RIGHT_UP_GRASS_EDGE = (byte) (2+8*16); + protected static final byte LEFT_UP_GRASS_EDGE = (byte) (0+8*16); + protected static final byte LEFT_POCKET_GRASS = (byte) (3+9*16); + protected static final byte RIGHT_POCKET_GRASS = (byte) (3+8*16); + + protected static final byte HILL_FILL = (byte) (5 + 9 * 16); + protected static final byte HILL_LEFT = (byte) (4 + 9 * 16); + protected static final byte HILL_RIGHT = (byte) (6 + 9 * 16); + protected static final byte HILL_TOP = (byte) (5 + 8 * 16); + protected static final byte HILL_TOP_LEFT = (byte) (4 + 8 * 16); + protected static final byte HILL_TOP_RIGHT = (byte) (6 + 8 * 16); + + protected static final byte HILL_TOP_LEFT_IN = (byte) (4 + 11 * 16); + protected static final byte HILL_TOP_RIGHT_IN = (byte) (6 + 11 * 16); + + protected static final byte TUBE_TOP_LEFT = (byte) (10 + 0 * 16); + protected static final byte TUBE_TOP_RIGHT = (byte) (11 + 0 * 16); + + protected static final byte TUBE_SIDE_LEFT = (byte) (10 + 1 * 16); + protected static final byte TUBE_SIDE_RIGHT = (byte) (11 + 1 * 16); + + //The level's width and height + protected int width; + protected int height; + + //This map of WIDTH * HEIGHT that contains the level's design + private byte[][] map; + + //This is a map of WIDTH * HEIGHT that contains the placement and type enemies + private SpriteTemplate[][] spriteTemplates; + + //These are the place of the end of the level + protected int xExit; + protected int yExit; + + public Level(){ + + } + + public Level(int width, int height) + { + this.width = width; + this.height = height; + + xExit = 10; + yExit = 10; + map = new byte[width][height]; + spriteTemplates = new SpriteTemplate[width][height]; + } + + public static void loadBehaviors(DataInputStream dis) throws IOException + { + dis.readFully(Level.TILE_BEHAVIORS); + } + + public static void saveBehaviors(DataOutputStream dos) throws IOException + { + dos.write(Level.TILE_BEHAVIORS); + } + + /** + *Clone the level data so that we can load it when Mario die + */ + public Level clone() throws CloneNotSupportedException { + + Level clone=new Level(width, height); + + clone.map = new byte[width][height]; + clone.spriteTemplates = new SpriteTemplate[width][height]; + clone.xExit = xExit; + clone.yExit = yExit; + + for (int i = 0; i < map.length; i++) + for (int j = 0; j < map[i].length; j++) { + clone.map[i][j]= map[i][j]; + clone.spriteTemplates[i][j] = spriteTemplates[i][j]; + } + + return clone; + + } + + public void tick(){ } + + public byte getBlockCapped(int x, int y) + { + if (x < 0) x = 0; + if (y < 0) y = 0; + if (x >= width) x = width - 1; + if (y >= height) y = height - 1; + return map[x][y]; + } + + public byte getBlock(int x, int y) + { + if (x < 0) x = 0; + if (y < 0) return 0; + if (x >= width) x = width - 1; + if (y >= height) y = height - 1; + return map[x][y]; + } + + public void setBlock(int x, int y, byte b) + { + if (x < 0) return; + if (y < 0) return; + if (x >= width) return; + if (y >= height) return; + map[x][y] = b; + } + + public boolean isBlocking(int x, int y, float xa, float ya) + { + byte block = getBlock(x, y); + + boolean blocking = ((TILE_BEHAVIORS[block & 0xff]) & BIT_BLOCK_ALL) > 0; + blocking |= (ya > 0) && ((TILE_BEHAVIORS[block & 0xff]) & BIT_BLOCK_UPPER) > 0; + blocking |= (ya < 0) && ((TILE_BEHAVIORS[block & 0xff]) & BIT_BLOCK_LOWER) > 0; + + return blocking; + } + + public SpriteTemplate getSpriteTemplate(int x, int y) + { + if (x < 0) return null; + if (y < 0) return null; + if (x >= width) return null; + if (y >= height) return null; + return spriteTemplates[x][y]; + } + + public void setSpriteTemplate(int x, int y, SpriteTemplate spriteTemplate) + { + if (x < 0) return; + if (y < 0) return; + if (x >= width) return; + if (y >= height) return; + spriteTemplates[x][y] = spriteTemplate; + } + + public SpriteTemplate[][] getSpriteTemplate(){ + return this.spriteTemplates; + } + + public void resetSpriteTemplate(){ + for (int i = 0; i < spriteTemplates.length; i++) { + for (int j = 0; j < spriteTemplates[i].length; j++) { + + SpriteTemplate st = spriteTemplates[i][j]; + if(st != null) + st.isDead = false; + } + } + } + + + public void print(byte[][] array){ + for (int i = 0; i < array.length; i++) { + for (int j = 0; j < array[i].length; j++) { + System.out.print(array[i][j]); + } + System.out.println(); + } + } + public byte[][] getMap() { + return map; + } + public SpriteTemplate[][] getSpriteTemplates() { + return spriteTemplates; + } + public int getxExit() { + // TODO Auto-generated method stub + return xExit; + } + public int getyExit() { + // TODO Auto-generated method stub + return yExit; + } + public int getWidth() { + // TODO Auto-generated method stub + return width; + } + public int getHeight() { + // TODO Auto-generated method stub + return height; + } + + + public String getName() { + // TODO Auto-generated method stub + return ""; + } + + +} diff --git a/src/dk/itu/mario/level/LevelEditView.java b/src/dk/itu/mario/level/LevelEditView.java new file mode 100644 index 0000000..bc9289c --- /dev/null +++ b/src/dk/itu/mario/level/LevelEditView.java @@ -0,0 +1,130 @@ +//package dk.itu.mario.level; +// +//import java.awt.Color; +//import java.awt.Dimension; +//import java.awt.Graphics; +//import java.awt.event.MouseEvent; +//import java.awt.event.MouseListener; +//import java.awt.event.MouseMotionListener; +// +//import javax.swing.*; +//import com.mojang.mario.*; +//import com.mojang.mario.level.*; +// +//import dk.itu.mario.engine.Art; +//import dk.itu.mario.engine.LevelRenderer; +// +// +// +//public class LevelEditView extends JComponent implements MouseListener, MouseMotionListener +//{ +// private static final long serialVersionUID = -7696446733303717142L; +// +// private LevelRenderer levelRenderer; +// private Level level; +// +// private int xTile = -1; +// private int yTile = -1; +// private TilePicker tilePicker; +// +// public LevelEditView(TilePicker tilePicker) +// { +// this.tilePicker = tilePicker; +// level = new Level(256, 15); +// Dimension size = new Dimension(level.width * 16, level.height * 16); +// setPreferredSize(size); +// setMinimumSize(size); +// setMaximumSize(size); +// +// addMouseListener(this); +// addMouseMotionListener(this); +// } +// +// public void setLevel(Level level) +// { +// this.level = level; +// Dimension size = new Dimension(level.width * 16, level.height * 16); +// setPreferredSize(size); +// setMinimumSize(size); +// setMaximumSize(size); +// repaint(); +// levelRenderer.setLevel(level); +// } +// +// public Level getLevel() +// { +// return level; +// } +// +// public void addNotify() +// { +// super.addNotify(); +// Art.init(getGraphicsConfiguration(), null); +// levelRenderer = new LevelRenderer(level, getGraphicsConfiguration(), level.width * 16, level.height * 16); +// levelRenderer.renderBehaviors = true; +// } +// +// public void paintComponent(Graphics g) +// { +// g.setColor(new Color(0x8090ff)); +// g.fillRect(0, 0, level.width * 16, level.height * 16); +// levelRenderer.render(g, 0, 0); +// g.setColor(Color.BLACK); +// g.drawRect(xTile * 16 - 1, yTile * 16 - 1, 17, 17); +// } +// +// public void mouseClicked(MouseEvent e) +// { +// } +// +// public void mouseEntered(MouseEvent e) +// { +// } +// +// public void mouseExited(MouseEvent e) +// { +// xTile = -1; +// yTile = -1; +// repaint(); +// } +// +// public void mousePressed(MouseEvent e) +// { +// xTile = e.getX() / 16; +// yTile = e.getY() / 16; +// +// if (e.getButton() == 3) +// { +// tilePicker.setPickedTile(level.getBlock(xTile, yTile)); +// } +// else +// { +// level.setBlock(xTile, yTile, tilePicker.pickedTile); +// levelRenderer.repaint(xTile - 1, yTile - 1, 3, 3); +// +// repaint(); +// } +// } +// +// public void mouseReleased(MouseEvent e) +// { +// } +// +// public void mouseDragged(MouseEvent e) +// { +// xTile = e.getX() / 16; +// yTile = e.getY() / 16; +// +// level.setBlock(xTile, yTile, tilePicker.pickedTile); +// levelRenderer.repaint(xTile - 1, yTile - 1, 3, 3); +// +// repaint(); +// } +// +// public void mouseMoved(MouseEvent e) +// { +// xTile = e.getX() / 16; +// yTile = e.getY() / 16; +// repaint(); +// } +//} diff --git a/src/dk/itu/mario/level/MyLevel.java b/src/dk/itu/mario/level/MyLevel.java new file mode 100644 index 0000000..e2012d6 --- /dev/null +++ b/src/dk/itu/mario/level/MyLevel.java @@ -0,0 +1,522 @@ +package dk.itu.mario.level; + +import java.util.Random; + +import dk.itu.mario.MarioInterface.GamePlay; +import dk.itu.mario.MarioInterface.LevelInterface; +import dk.itu.mario.engine.sprites.Enemy; +import dk.itu.mario.engine.sprites.SpriteTemplate; + +public class MyLevel extends Level { + // Store information about the level + public int ENEMIES = 0; // the number of enemies the level contains + public int BLOCKS_EMPTY = 0; // the number of empty blocks + public int BLOCKS_COINS = 0; // the number of coin blocks + public int BLOCKS_POWER = 0; // the number of power blocks + public int COINS = 0; // These are the coins in boxes that Mario collect + + public static long lastSeed; + + Random random; + + private int difficulty; + private int type; + + public MyLevel(int width, int height) { + super(width, height); + } + + public MyLevel(int width, int height, long seed, int difficulty, int type, + GamePlay playerMetrics) { + this(width, height); + creat(seed, difficulty, type); + } + + public void creat(long seed, int difficulty, int type) { + this.type = type; + this.difficulty = difficulty; + + lastSeed = seed; + random = new Random(seed); + + // create the start location + int length = 0; + length += buildStraight(0, width, true); + + // create all of the medium sections + while (length < width - 64) { + length += buildStraight(length, width - length, false); + length += buildStraight(length, width - length, false); + length += buildHillStraight(length, width - length); + length += buildJump(length, width - length); + length += buildTubes(length, width - length); + length += buildCannons(length, width - length); + } + + // set the end piece + int floor = height - 1 - random.nextInt(4); + + xExit = length + 8; + yExit = floor; + + // fills the end piece + for (int x = length; x < width; x++) { + for (int y = 0; y < height; y++) { + if (y >= floor) { + setBlock(x, y, GROUND); + } + } + } + + if (type == LevelInterface.TYPE_CASTLE + || type == LevelInterface.TYPE_UNDERGROUND) { + int ceiling = 0; + int run = 0; + for (int x = 0; x < width; x++) { + if (run-- <= 0 && x > 4) { + ceiling = random.nextInt(4); + run = random.nextInt(4) + 4; + } + for (int y = 0; y < height; y++) { + if ((x > 4 && y <= ceiling) || x < 1) { + setBlock(x, y, GROUND); + } + } + } + } + + fixWalls(); + + } + + private int buildJump(int xo, int maxLength) { + // jl: jump length + // js: the number of blocks that are available at either side for free + int js = random.nextInt(4) + 2; + int jl = random.nextInt(2) + 2; + int length = js * 2 + jl; + + boolean hasStairs = random.nextInt(3) == 0; + + int floor = height - 1 - random.nextInt(4); + // run from the start x position, for the whole length + for (int x = xo; x < xo + length; x++) { + if (x < xo + js || x > xo + length - js - 1) { + // run for all y's since we need to paint blocks upward + for (int y = 0; y < height; y++) { // paint ground up until the + // floor + if (y >= floor) { + setBlock(x, y, GROUND); + } + // if it is above ground, start making stairs of rocks + else if (hasStairs) { // LEFT SIDE + if (x < xo + js) { // we need to max it out and level + // because it wont + // paint ground correctly unless two + // bricks are side by side + if (y >= floor - (x - xo) + 1) { + setBlock(x, y, ROCK); + } + } else { // RIGHT SIDE + if (y >= floor - ((xo + length) - x) + 2) { + setBlock(x, y, ROCK); + } + } + } + } + } + } + + return length; + } + + private int buildCannons(int xo, int maxLength) { + int length = random.nextInt(10) + 2; + if (length > maxLength) + length = maxLength; + + int floor = height - 1 - random.nextInt(4); + int xCannon = xo + 1 + random.nextInt(4); + for (int x = xo; x < xo + length; x++) { + if (x > xCannon) { + xCannon += 2 + random.nextInt(4); + } + if (xCannon == xo + length - 1) + xCannon += 10; + int cannonHeight = floor - random.nextInt(4) - 1; + + for (int y = 0; y < height; y++) { + if (y >= floor) { + setBlock(x, y, GROUND); + } else { + if (x == xCannon && y >= cannonHeight) { + if (y == cannonHeight) { + setBlock(x, y, (byte) (14 + 0 * 16)); + } else if (y == cannonHeight + 1) { + setBlock(x, y, (byte) (14 + 1 * 16)); + } else { + setBlock(x, y, (byte) (14 + 2 * 16)); + } + } + } + } + } + + return length; + } + + private int buildHillStraight(int xo, int maxLength) { + int length = random.nextInt(10) + 10; + if (length > maxLength) + length = maxLength; + + int floor = height - 1 - random.nextInt(4); + for (int x = xo; x < xo + length; x++) { + for (int y = 0; y < height; y++) { + if (y >= floor) { + setBlock(x, y, GROUND); + } + } + } + + addEnemyLine(xo + 1, xo + length - 1, floor - 1); + + int h = floor; + + boolean keepGoing = true; + + boolean[] occupied = new boolean[length]; + while (keepGoing) { + h = h - 2 - random.nextInt(3); + + if (h <= 0) { + keepGoing = false; + } else { + int l = random.nextInt(5) + 3; + int xxo = random.nextInt(length - l - 2) + xo + 1; + + if (occupied[xxo - xo] || occupied[xxo - xo + l] + || occupied[xxo - xo - 1] || occupied[xxo - xo + l + 1]) { + keepGoing = false; + } else { + occupied[xxo - xo] = true; + occupied[xxo - xo + l] = true; + addEnemyLine(xxo, xxo + l, h - 1); + if (random.nextInt(4) == 0) { + decorate(xxo - 1, xxo + l + 1, h); + keepGoing = false; + } + for (int x = xxo; x < xxo + l; x++) { + for (int y = h; y < floor; y++) { + int xx = 5; + if (x == xxo) + xx = 4; + if (x == xxo + l - 1) + xx = 6; + int yy = 9; + if (y == h) + yy = 8; + + if (getBlock(x, y) == 0) { + setBlock(x, y, (byte) (xx + yy * 16)); + } else { + if (getBlock(x, y) == HILL_TOP_LEFT) + setBlock(x, y, HILL_TOP_LEFT_IN); + if (getBlock(x, y) == HILL_TOP_RIGHT) + setBlock(x, y, HILL_TOP_RIGHT_IN); + } + } + } + } + } + } + + return length; + } + + private void addEnemyLine(int x0, int x1, int y) { + for (int x = x0; x < x1; x++) { + if (random.nextInt(35) < difficulty + 1) { + int type = random.nextInt(4); + + if (difficulty < 1) { + type = Enemy.ENEMY_GOOMBA; + } else if (difficulty < 3) { + type = random.nextInt(3); + } + + setSpriteTemplate(x, y, + new SpriteTemplate(type, + random.nextInt(35) < difficulty)); + ENEMIES++; + } + } + } + + private int buildTubes(int xo, int maxLength) { + int length = random.nextInt(10) + 5; + if (length > maxLength) + length = maxLength; + + int floor = height - 1 - random.nextInt(4); + int xTube = xo + 1 + random.nextInt(4); + int tubeHeight = floor - random.nextInt(2) - 2; + for (int x = xo; x < xo + length; x++) { + if (x > xTube + 1) { + xTube += 3 + random.nextInt(4); + tubeHeight = floor - random.nextInt(2) - 2; + } + if (xTube >= xo + length - 2) + xTube += 10; + + if (x == xTube && random.nextInt(11) < difficulty + 1) { + setSpriteTemplate(x, tubeHeight, new SpriteTemplate( + Enemy.ENEMY_FLOWER, false)); + ENEMIES++; + } + + for (int y = 0; y < height; y++) { + if (y >= floor) { + setBlock(x, y, GROUND); + + } else { + if ((x == xTube || x == xTube + 1) && y >= tubeHeight) { + int xPic = 10 + x - xTube; + + if (y == tubeHeight) { + // tube top + setBlock(x, y, (byte) (xPic + 0 * 16)); + } else { + // tube side + setBlock(x, y, (byte) (xPic + 1 * 16)); + } + } + } + } + } + + return length; + } + + private int buildStraight(int xo, int maxLength, boolean safe) { + int length = random.nextInt(10) + 2; + + if (safe) + length = 10 + random.nextInt(5); + + if (length > maxLength) + length = maxLength; + + int floor = height - 1 - random.nextInt(4); + + // runs from the specified x position to the length of the segment + for (int x = xo; x < xo + length; x++) { + for (int y = 0; y < height; y++) { + if (y >= floor) { + setBlock(x, y, GROUND); + } + } + } + + if (!safe) { + if (length > 5) { + decorate(xo, xo + length, floor); + } + } + + return length; + } + + private void decorate(int xStart, int xLength, int floor) { + // if its at the very top, just return + if (floor < 1) + return; + + // boolean coins = random.nextInt(3) == 0; + boolean rocks = true; + + // add an enemy line above the box + addEnemyLine(xStart + 1, xLength - 1, floor - 1); + + int s = random.nextInt(4); + int e = random.nextInt(4); + + if (floor - 2 > 0) { + if ((xLength - 1 - e) - (xStart + 1 + s) > 1) { + for (int x = xStart + 1 + s; x < xLength - 1 - e; x++) { + setBlock(x, floor - 2, COIN); + COINS++; + } + } + } + + s = random.nextInt(4); + e = random.nextInt(4); + + // this fills the set of blocks and the hidden objects inside them + if (floor - 4 > 0) { + if ((xLength - 1 - e) - (xStart + 1 + s) > 2) { + for (int x = xStart + 1 + s; x < xLength - 1 - e; x++) { + if (rocks) { + if (x != xStart + 1 && x != xLength - 2 + && random.nextInt(3) == 0) { + if (random.nextInt(4) == 0) { + setBlock(x, floor - 4, BLOCK_POWERUP); + BLOCKS_POWER++; + } else { // the fills a block with a hidden coin + setBlock(x, floor - 4, BLOCK_COIN); + BLOCKS_COINS++; + } + } else if (random.nextInt(4) == 0) { + if (random.nextInt(4) == 0) { + setBlock(x, floor - 4, (byte) (2 + 1 * 16)); + } else { + setBlock(x, floor - 4, (byte) (1 + 1 * 16)); + } + } else { + setBlock(x, floor - 4, BLOCK_EMPTY); + BLOCKS_EMPTY++; + } + } + } + } + } + } + + private void fixWalls() { + boolean[][] blockMap = new boolean[width + 1][height + 1]; + + for (int x = 0; x < width + 1; x++) { + for (int y = 0; y < height + 1; y++) { + int blocks = 0; + for (int xx = x - 1; xx < x + 1; xx++) { + for (int yy = y - 1; yy < y + 1; yy++) { + if (getBlockCapped(xx, yy) == GROUND) { + blocks++; + } + } + } + blockMap[x][y] = blocks == 4; + } + } + blockify(this, blockMap, width + 1, height + 1); + } + + private void blockify(Level level, boolean[][] blocks, int width, int height) { + int to = 0; + if (type == LevelInterface.TYPE_CASTLE) { + to = 4 * 2; + } else if (type == LevelInterface.TYPE_UNDERGROUND) { + to = 4 * 3; + } + + boolean[][] b = new boolean[2][2]; + + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + for (int xx = x; xx <= x + 1; xx++) { + for (int yy = y; yy <= y + 1; yy++) { + int _xx = xx; + int _yy = yy; + if (_xx < 0) + _xx = 0; + if (_yy < 0) + _yy = 0; + if (_xx > width - 1) + _xx = width - 1; + if (_yy > height - 1) + _yy = height - 1; + b[xx - x][yy - y] = blocks[_xx][_yy]; + } + } + + if (b[0][0] == b[1][0] && b[0][1] == b[1][1]) { + if (b[0][0] == b[0][1]) { + if (b[0][0]) { + level.setBlock(x, y, (byte) (1 + 9 * 16 + to)); + } else { + // KEEP OLD BLOCK! + } + } else { + if (b[0][0]) { + // down grass top? + level.setBlock(x, y, (byte) (1 + 10 * 16 + to)); + } else { + // up grass top + level.setBlock(x, y, (byte) (1 + 8 * 16 + to)); + } + } + } else if (b[0][0] == b[0][1] && b[1][0] == b[1][1]) { + if (b[0][0]) { + // right grass top + level.setBlock(x, y, (byte) (2 + 9 * 16 + to)); + } else { + // left grass top + level.setBlock(x, y, (byte) (0 + 9 * 16 + to)); + } + } else if (b[0][0] == b[1][1] && b[0][1] == b[1][0]) { + level.setBlock(x, y, (byte) (1 + 9 * 16 + to)); + } else if (b[0][0] == b[1][0]) { + if (b[0][0]) { + if (b[0][1]) { + level.setBlock(x, y, (byte) (3 + 10 * 16 + to)); + } else { + level.setBlock(x, y, (byte) (3 + 11 * 16 + to)); + } + } else { + if (b[0][1]) { + // right up grass top + level.setBlock(x, y, (byte) (2 + 8 * 16 + to)); + } else { + // left up grass top + level.setBlock(x, y, (byte) (0 + 8 * 16 + to)); + } + } + } else if (b[0][1] == b[1][1]) { + if (b[0][1]) { + if (b[0][0]) { + // left pocket grass + level.setBlock(x, y, (byte) (3 + 9 * 16 + to)); + } else { + // right pocket grass + level.setBlock(x, y, (byte) (3 + 8 * 16 + to)); + } + } else { + if (b[0][0]) { + level.setBlock(x, y, (byte) (2 + 10 * 16 + to)); + } else { + level.setBlock(x, y, (byte) (0 + 10 * 16 + to)); + } + } + } else { + level.setBlock(x, y, (byte) (0 + 1 * 16 + to)); + } + } + } + } + + public RandomLevel clone() throws CloneNotSupportedException { + + RandomLevel clone = new RandomLevel(width, height); + + clone.xExit = xExit; + clone.yExit = yExit; + byte[][] map = getMap(); + SpriteTemplate[][] st = getSpriteTemplate(); + + for (int i = 0; i < map.length; i++) + for (int j = 0; j < map[i].length; j++) { + clone.setBlock(i, j, map[i][j]); + clone.setSpriteTemplate(i, j, st[i][j]); + } + clone.BLOCKS_COINS = BLOCKS_COINS; + clone.BLOCKS_EMPTY = BLOCKS_EMPTY; + clone.BLOCKS_POWER = BLOCKS_POWER; + clone.ENEMIES = ENEMIES; + clone.COINS = COINS; + + return clone; + + } + +} diff --git a/src/dk/itu/mario/level/RandomLevel.java b/src/dk/itu/mario/level/RandomLevel.java new file mode 100644 index 0000000..7be08c0 --- /dev/null +++ b/src/dk/itu/mario/level/RandomLevel.java @@ -0,0 +1,576 @@ +package dk.itu.mario.level; + +import java.util.Random; + +import dk.itu.mario.MarioInterface.Constraints; +import dk.itu.mario.MarioInterface.LevelInterface; +import dk.itu.mario.engine.sprites.SpriteTemplate; +import dk.itu.mario.engine.sprites.Enemy; + +public class RandomLevel extends Level { + // Store information about the level + public int ENEMIES = 0; // the number of enemies the level contains + public int BLOCKS_EMPTY = 0; // the number of empty blocks + public int BLOCKS_COINS = 0; // the number of coin blocks + public int BLOCKS_POWER = 0; // the number of power blocks + public int COINS = 0; // These are the coins in boxes that Mario collect + + public static long lastSeed; + + Random random; + + private static final int ODDS_STRAIGHT = 0; + private static final int ODDS_HILL_STRAIGHT = 1; + private static final int ODDS_TUBES = 2; + private static final int ODDS_JUMP = 3; + private static final int ODDS_CANNONS = 4; + + private int[] odds = new int[5]; + + private int totalOdds; + + private int difficulty; + private int type; + private int gaps; + + public RandomLevel(int width, int height) { + super(width, height); + } + + public RandomLevel(int width, int height, long seed, int difficulty, + int type) { + this(width, height); + creat(seed, difficulty, type); + } + + public void creat(long seed, int difficulty, int type) { + this.type = type; + this.difficulty = difficulty; + odds[ODDS_STRAIGHT] = 20; + odds[ODDS_HILL_STRAIGHT] = 10; + odds[ODDS_TUBES] = 2 + 1 * difficulty; + odds[ODDS_JUMP] = 2 * difficulty; + odds[ODDS_CANNONS] = -10 + 5 * difficulty; + + if (type != LevelInterface.TYPE_OVERGROUND) { + odds[ODDS_HILL_STRAIGHT] = 0; + } + + for (int i = 0; i < odds.length; i++) { + // failsafe (no negative odds) + if (odds[i] < 0) { + odds[i] = 0; + } + + totalOdds += odds[i]; + odds[i] = totalOdds - odds[i]; + } + + lastSeed = seed; + random = new Random(seed); + + // create the start location + int length = 0; + length += buildStraight(0, width, true); + + // create all of the medium sections + while (length < width - 64) { + length += buildZone(length, width - length); + } + + // set the end piece + int floor = height - 1 - random.nextInt(4); + + xExit = length + 8; + yExit = floor; + + // fills the end piece + for (int x = length; x < width; x++) { + for (int y = 0; y < height; y++) { + if (y >= floor) { + setBlock(x, y, GROUND); + } + } + } + + if (type == LevelInterface.TYPE_CASTLE + || type == LevelInterface.TYPE_UNDERGROUND) { + int ceiling = 0; + int run = 0; + for (int x = 0; x < width; x++) { + if (run-- <= 0 && x > 4) { + ceiling = random.nextInt(4); + run = random.nextInt(4) + 4; + } + for (int y = 0; y < height; y++) { + if ((x > 4 && y <= ceiling) || x < 1) { + setBlock(x, y, GROUND); + } + } + } + } + + fixWalls(); + + } + + private int buildZone(int x, int maxLength) { + int t = random.nextInt(totalOdds); + int type = 0; + + for (int i = 0; i < odds.length; i++) { + if (odds[i] <= t) { + type = i; + } + } + + switch (type) { + case ODDS_STRAIGHT: + return buildStraight(x, maxLength, false); + case ODDS_HILL_STRAIGHT: + return buildHillStraight(x, maxLength); + case ODDS_TUBES: + return buildTubes(x, maxLength); + case ODDS_JUMP: + if (gaps < Constraints.gaps) + return buildJump(x, maxLength); + else + return buildStraight(x, maxLength, false); + case ODDS_CANNONS: + return buildCannons(x, maxLength); + } + return 0; + } + + private int buildJump(int xo, int maxLength) { + gaps++; + // jl: jump length + // js: the number of blocks that are available at either side for free + int js = random.nextInt(4) + 2; + int jl = random.nextInt(2) + 2; + int length = js * 2 + jl; + + boolean hasStairs = random.nextInt(3) == 0; + + int floor = height - 1 - random.nextInt(4); + // run from the start x position, for the whole length + for (int x = xo; x < xo + length; x++) { + if (x < xo + js || x > xo + length - js - 1) { + // run for all y's since we need to paint blocks upward + for (int y = 0; y < height; y++) { // paint ground up until the + // floor + if (y >= floor) { + setBlock(x, y, GROUND); + } + // if it is above ground, start making stairs of rocks + else if (hasStairs) { // LEFT SIDE + if (x < xo + js) { // we need to max it out and level + // because it wont + // paint ground correctly unless two + // bricks are side by side + if (y >= floor - (x - xo) + 1) { + setBlock(x, y, ROCK); + } + } else { // RIGHT SIDE + if (y >= floor - ((xo + length) - x) + 2) { + setBlock(x, y, ROCK); + } + } + } + } + } + } + + return length; + } + + private int buildCannons(int xo, int maxLength) { + int length = random.nextInt(10) + 2; + if (length > maxLength) + length = maxLength; + + int floor = height - 1 - random.nextInt(4); + int xCannon = xo + 1 + random.nextInt(4); + for (int x = xo; x < xo + length; x++) { + if (x > xCannon) { + xCannon += 2 + random.nextInt(4); + } + if (xCannon == xo + length - 1) + xCannon += 10; + int cannonHeight = floor - random.nextInt(4) - 1; + + for (int y = 0; y < height; y++) { + if (y >= floor) { + setBlock(x, y, GROUND); + } else { + if (x == xCannon && y >= cannonHeight) { + if (y == cannonHeight) { + setBlock(x, y, (byte) (14 + 0 * 16)); + } else if (y == cannonHeight + 1) { + setBlock(x, y, (byte) (14 + 1 * 16)); + } else { + setBlock(x, y, (byte) (14 + 2 * 16)); + } + } + } + } + } + + return length; + } + + private int buildHillStraight(int xo, int maxLength) { + int length = random.nextInt(10) + 10; + if (length > maxLength) + length = maxLength; + + int floor = height - 1 - random.nextInt(4); + for (int x = xo; x < xo + length; x++) { + for (int y = 0; y < height; y++) { + if (y >= floor) { + setBlock(x, y, GROUND); + } + } + } + + addEnemyLine(xo + 1, xo + length - 1, floor - 1); + + int h = floor; + + boolean keepGoing = true; + + boolean[] occupied = new boolean[length]; + while (keepGoing) { + h = h - 2 - random.nextInt(3); + + if (h <= 0) { + keepGoing = false; + } else { + int l = random.nextInt(5) + 3; + int xxo = random.nextInt(length - l - 2) + xo + 1; + + if (occupied[xxo - xo] || occupied[xxo - xo + l] + || occupied[xxo - xo - 1] || occupied[xxo - xo + l + 1]) { + keepGoing = false; + } else { + occupied[xxo - xo] = true; + occupied[xxo - xo + l] = true; + addEnemyLine(xxo, xxo + l, h - 1); + if (random.nextInt(4) == 0) { + decorate(xxo - 1, xxo + l + 1, h); + keepGoing = false; + } + for (int x = xxo; x < xxo + l; x++) { + for (int y = h; y < floor; y++) { + int xx = 5; + if (x == xxo) + xx = 4; + if (x == xxo + l - 1) + xx = 6; + int yy = 9; + if (y == h) + yy = 8; + + if (getBlock(x, y) == 0) { + setBlock(x, y, (byte) (xx + yy * 16)); + } else { + if (getBlock(x, y) == HILL_TOP_LEFT) + setBlock(x, y, HILL_TOP_LEFT_IN); + if (getBlock(x, y) == HILL_TOP_RIGHT) + setBlock(x, y, HILL_TOP_RIGHT_IN); + } + } + } + } + } + } + + return length; + } + + private void addEnemyLine(int x0, int x1, int y) { + for (int x = x0; x < x1; x++) { + if (random.nextInt(35) < difficulty + 1) { + int type = random.nextInt(4); + + if (difficulty < 1) { + type = Enemy.ENEMY_GOOMBA; + } else if (difficulty < 3) { + type = random.nextInt(3); + } + + setSpriteTemplate(x, y, + new SpriteTemplate(type, + random.nextInt(35) < difficulty)); + ENEMIES++; + } + } + } + + private int buildTubes(int xo, int maxLength) { + int length = random.nextInt(10) + 5; + if (length > maxLength) + length = maxLength; + + int floor = height - 1 - random.nextInt(4); + int xTube = xo + 1 + random.nextInt(4); + int tubeHeight = floor - random.nextInt(2) - 2; + for (int x = xo; x < xo + length; x++) { + if (x > xTube + 1) { + xTube += 3 + random.nextInt(4); + tubeHeight = floor - random.nextInt(2) - 2; + } + if (xTube >= xo + length - 2) + xTube += 10; + + if (x == xTube && random.nextInt(11) < difficulty + 1) { + setSpriteTemplate(x, tubeHeight, new SpriteTemplate( + Enemy.ENEMY_FLOWER, false)); + ENEMIES++; + } + + for (int y = 0; y < height; y++) { + if (y >= floor) { + setBlock(x, y, GROUND); + + } else { + if ((x == xTube || x == xTube + 1) && y >= tubeHeight) { + int xPic = 10 + x - xTube; + + if (y == tubeHeight) { + // tube top + setBlock(x, y, (byte) (xPic + 0 * 16)); + } else { + // tube side + setBlock(x, y, (byte) (xPic + 1 * 16)); + } + } + } + } + } + + return length; + } + + private int buildStraight(int xo, int maxLength, boolean safe) { + int length = random.nextInt(10) + 2; + + if (safe) + length = 10 + random.nextInt(5); + + if (length > maxLength) + length = maxLength; + + int floor = height - 1 - random.nextInt(4); + + // runs from the specified x position to the length of the segment + for (int x = xo; x < xo + length; x++) { + for (int y = 0; y < height; y++) { + if (y >= floor) { + setBlock(x, y, GROUND); + } + } + } + + if (!safe) { + if (length > 5) { + decorate(xo, xo + length, floor); + } + } + + return length; + } + + private void decorate(int xStart, int xLength, int floor) { + // if its at the very top, just return + if (floor < 1) + return; + + // boolean coins = random.nextInt(3) == 0; + boolean rocks = true; + + // add an enemy line above the box + addEnemyLine(xStart + 1, xLength - 1, floor - 1); + + int s = random.nextInt(4); + int e = random.nextInt(4); + + if (floor - 2 > 0) { + if ((xLength - 1 - e) - (xStart + 1 + s) > 1) { + for (int x = xStart + 1 + s; x < xLength - 1 - e; x++) { + setBlock(x, floor - 2, COIN); + COINS++; + } + } + } + + s = random.nextInt(4); + e = random.nextInt(4); + + // this fills the set of blocks and the hidden objects inside them + if (floor - 4 > 0) { + if ((xLength - 1 - e) - (xStart + 1 + s) > 2) { + for (int x = xStart + 1 + s; x < xLength - 1 - e; x++) { + if (rocks) { + if (x != xStart + 1 && x != xLength - 2 + && random.nextInt(3) == 0) { + if (random.nextInt(4) == 0) { + setBlock(x, floor - 4, BLOCK_POWERUP); + BLOCKS_POWER++; + } else { // the fills a block with a hidden coin + setBlock(x, floor - 4, BLOCK_COIN); + BLOCKS_COINS++; + } + } else if (random.nextInt(4) == 0) { + if (random.nextInt(4) == 0) { + setBlock(x, floor - 4, (byte) (2 + 1 * 16)); + } else { + setBlock(x, floor - 4, (byte) (1 + 1 * 16)); + } + } else { + setBlock(x, floor - 4, BLOCK_EMPTY); + BLOCKS_EMPTY++; + } + } + } + } + } + } + + private void fixWalls() { + boolean[][] blockMap = new boolean[width + 1][height + 1]; + + for (int x = 0; x < width + 1; x++) { + for (int y = 0; y < height + 1; y++) { + int blocks = 0; + for (int xx = x - 1; xx < x + 1; xx++) { + for (int yy = y - 1; yy < y + 1; yy++) { + if (getBlockCapped(xx, yy) == GROUND) { + blocks++; + } + } + } + blockMap[x][y] = blocks == 4; + } + } + blockify(this, blockMap, width + 1, height + 1); + } + + private void blockify(Level level, boolean[][] blocks, int width, int height) { + int to = 0; + if (type == LevelInterface.TYPE_CASTLE) { + to = 4 * 2; + } else if (type == LevelInterface.TYPE_UNDERGROUND) { + to = 4 * 3; + } + + boolean[][] b = new boolean[2][2]; + + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + for (int xx = x; xx <= x + 1; xx++) { + for (int yy = y; yy <= y + 1; yy++) { + int _xx = xx; + int _yy = yy; + if (_xx < 0) + _xx = 0; + if (_yy < 0) + _yy = 0; + if (_xx > width - 1) + _xx = width - 1; + if (_yy > height - 1) + _yy = height - 1; + b[xx - x][yy - y] = blocks[_xx][_yy]; + } + } + + if (b[0][0] == b[1][0] && b[0][1] == b[1][1]) { + if (b[0][0] == b[0][1]) { + if (b[0][0]) { + level.setBlock(x, y, (byte) (1 + 9 * 16 + to)); + } else { + // KEEP OLD BLOCK! + } + } else { + if (b[0][0]) { + // down grass top? + level.setBlock(x, y, (byte) (1 + 10 * 16 + to)); + } else { + // up grass top + level.setBlock(x, y, (byte) (1 + 8 * 16 + to)); + } + } + } else if (b[0][0] == b[0][1] && b[1][0] == b[1][1]) { + if (b[0][0]) { + // right grass top + level.setBlock(x, y, (byte) (2 + 9 * 16 + to)); + } else { + // left grass top + level.setBlock(x, y, (byte) (0 + 9 * 16 + to)); + } + } else if (b[0][0] == b[1][1] && b[0][1] == b[1][0]) { + level.setBlock(x, y, (byte) (1 + 9 * 16 + to)); + } else if (b[0][0] == b[1][0]) { + if (b[0][0]) { + if (b[0][1]) { + level.setBlock(x, y, (byte) (3 + 10 * 16 + to)); + } else { + level.setBlock(x, y, (byte) (3 + 11 * 16 + to)); + } + } else { + if (b[0][1]) { + // right up grass top + level.setBlock(x, y, (byte) (2 + 8 * 16 + to)); + } else { + // left up grass top + level.setBlock(x, y, (byte) (0 + 8 * 16 + to)); + } + } + } else if (b[0][1] == b[1][1]) { + if (b[0][1]) { + if (b[0][0]) { + // left pocket grass + level.setBlock(x, y, (byte) (3 + 9 * 16 + to)); + } else { + // right pocket grass + level.setBlock(x, y, (byte) (3 + 8 * 16 + to)); + } + } else { + if (b[0][0]) { + level.setBlock(x, y, (byte) (2 + 10 * 16 + to)); + } else { + level.setBlock(x, y, (byte) (0 + 10 * 16 + to)); + } + } + } else { + level.setBlock(x, y, (byte) (0 + 1 * 16 + to)); + } + } + } + } + + public RandomLevel clone() throws CloneNotSupportedException { + + RandomLevel clone = new RandomLevel(width, height); + + clone.xExit = xExit; + clone.yExit = yExit; + byte[][] map = getMap(); + SpriteTemplate[][] st = getSpriteTemplate(); + + for (int i = 0; i < map.length; i++) + for (int j = 0; j < map[i].length; j++) { + clone.setBlock(i, j, map[i][j]); + clone.setSpriteTemplate(i, j, st[i][j]); + } + clone.BLOCKS_COINS = BLOCKS_COINS; + clone.BLOCKS_EMPTY = BLOCKS_EMPTY; + clone.BLOCKS_POWER = BLOCKS_POWER; + clone.ENEMIES = ENEMIES; + clone.COINS = COINS; + + return clone; + + } + +} diff --git a/src/dk/itu/mario/level/generator/.DS_Store b/src/dk/itu/mario/level/generator/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/src/dk/itu/mario/level/generator/.DS_Store differ diff --git a/src/dk/itu/mario/level/generator/CustomizedLevelGenerator.java b/src/dk/itu/mario/level/generator/CustomizedLevelGenerator.java new file mode 100644 index 0000000..33e19e5 --- /dev/null +++ b/src/dk/itu/mario/level/generator/CustomizedLevelGenerator.java @@ -0,0 +1,25 @@ +package dk.itu.mario.level.generator; + +import java.util.Random; + +import dk.itu.mario.MarioInterface.GamePlay; +import dk.itu.mario.MarioInterface.LevelGenerator; +import dk.itu.mario.MarioInterface.LevelInterface; +import dk.itu.mario.level.CustomizedLevel; + +public class CustomizedLevelGenerator implements LevelGenerator { + + public LevelInterface generateLevel(GamePlay playerMetrics) { + System.out.println("Generating customized level"); + LevelInterface level = new CustomizedLevel(320, 15, + new Random().nextLong(), 1, 1, playerMetrics); + return level; + } + + @Override + public LevelInterface generateLevel(String detailedInfo) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/dk/itu/mario/level/generator/MyLevelGenerator.java b/src/dk/itu/mario/level/generator/MyLevelGenerator.java new file mode 100644 index 0000000..bf39ce0 --- /dev/null +++ b/src/dk/itu/mario/level/generator/MyLevelGenerator.java @@ -0,0 +1,26 @@ +package dk.itu.mario.level.generator; + +import java.util.Random; + +import dk.itu.mario.MarioInterface.GamePlay; +import dk.itu.mario.MarioInterface.LevelGenerator; +import dk.itu.mario.MarioInterface.LevelInterface; +import dk.itu.mario.level.MyLevel; + +public class MyLevelGenerator extends CustomizedLevelGenerator implements + LevelGenerator { + + public LevelInterface generateLevel(GamePlay playerMetrics) { + System.out.println("Generating my level"); + LevelInterface level = new MyLevel(320, 15, new Random().nextLong(), 1, + LevelInterface.TYPE_OVERGROUND, playerMetrics); + return level; + } + + @Override + public LevelInterface generateLevel(String detailedInfo) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/dk/itu/mario/level/generator/RandomLevelGenerator.java b/src/dk/itu/mario/level/generator/RandomLevelGenerator.java new file mode 100644 index 0000000..a420311 --- /dev/null +++ b/src/dk/itu/mario/level/generator/RandomLevelGenerator.java @@ -0,0 +1,26 @@ +package dk.itu.mario.level.generator; + +import java.util.Random; + +import dk.itu.mario.MarioInterface.GamePlay; +import dk.itu.mario.MarioInterface.LevelGenerator; +import dk.itu.mario.MarioInterface.LevelInterface; +import dk.itu.mario.level.RandomLevel; + +public class RandomLevelGenerator extends CustomizedLevelGenerator implements + LevelGenerator { + + public LevelInterface generateLevel(GamePlay playerMetrics) { + System.out.println("Generating random level"); + LevelInterface level = new RandomLevel(320, 15, + new Random().nextLong(), 1, LevelInterface.TYPE_OVERGROUND); + return level; + } + + @Override + public LevelInterface generateLevel(String detailedInfo) { + // TODO Auto-generated method stub + return null; + } + +} \ No newline at end of file diff --git a/src/dk/itu/mario/scene/.DS_Store b/src/dk/itu/mario/scene/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/src/dk/itu/mario/scene/.DS_Store differ diff --git a/src/dk/itu/mario/scene/LevelScene.java b/src/dk/itu/mario/scene/LevelScene.java new file mode 100644 index 0000000..ea2f6b6 --- /dev/null +++ b/src/dk/itu/mario/scene/LevelScene.java @@ -0,0 +1,601 @@ +package dk.itu.mario.scene; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.event.MouseEvent; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; + +import dk.itu.mario.engine.Art; +import dk.itu.mario.engine.BgRenderer; +import dk.itu.mario.engine.DataRecorder; +import dk.itu.mario.engine.LevelRenderer; +import dk.itu.mario.engine.MarioComponent; +import dk.itu.mario.engine.sonar.FixedSoundSource; +import dk.itu.mario.engine.sprites.BulletBill; +import dk.itu.mario.engine.sprites.CoinAnim; +import dk.itu.mario.engine.sprites.FireFlower; +import dk.itu.mario.engine.sprites.Fireball; +import dk.itu.mario.engine.sprites.Mario; +import dk.itu.mario.engine.sprites.Mushroom; +import dk.itu.mario.engine.sprites.Particle; +import dk.itu.mario.engine.sprites.Shell; +import dk.itu.mario.engine.sprites.Sparkle; +import dk.itu.mario.engine.sprites.Sprite; +import dk.itu.mario.engine.sprites.SpriteContext; +import dk.itu.mario.engine.sprites.SpriteTemplate; +import dk.itu.mario.level.Level; + +public class LevelScene extends Scene implements SpriteContext { + protected List sprites = new ArrayList(); + protected List spritesToAdd = new ArrayList(); + protected List spritesToRemove = new ArrayList(); + + public Level level; + public Mario mario; + public float xCam, yCam, xCamO, yCamO; + public static Image tmpImage; + protected int tick; + + protected LevelRenderer layer; + protected BgRenderer[] bgLayer = new BgRenderer[2]; + protected Level currentLevel; + protected GraphicsConfiguration graphicsConfiguration; + + public boolean paused = false; + public int startTime = 0; + public int timeLeft; + + protected long levelSeed; + protected MarioComponent marioComponent; + protected int levelType; + protected int levelDifficulty; + + public static DataRecorder recorder; + + public boolean gameStarted; + + public static boolean bothPlayed = false; + + private int[] xPositionsArrow; + private int[] yPositionsArrow; + private int widthArrow, heightArrow, tipWidthArrow; + private int xArrow, yArrow; + + public LevelScene(GraphicsConfiguration graphicsConfiguration, + MarioComponent renderer, long seed, int levelDifficulty, int type) { + this.graphicsConfiguration = graphicsConfiguration; + this.levelSeed = seed; + this.marioComponent = renderer; + this.levelDifficulty = levelDifficulty; + this.levelType = type; + + widthArrow = 25; + tipWidthArrow = 10; + heightArrow = 20; + + xArrow = 160; + yArrow = 40; + + xPositionsArrow = new int[] { xArrow + -widthArrow / 2, + xArrow + widthArrow / 2 - tipWidthArrow, + xArrow + widthArrow / 2 - tipWidthArrow, + xArrow + widthArrow / 2, + xArrow + widthArrow / 2 - tipWidthArrow, + xArrow + widthArrow / 2 - tipWidthArrow, + xArrow + -widthArrow / 2 }; + yPositionsArrow = new int[] { yArrow + -heightArrow / 4, + yArrow + -heightArrow / 4, yArrow + -heightArrow / 2, + yArrow + 0, yArrow + heightArrow / 2, yArrow + heightArrow / 4, + yArrow + heightArrow / 4 }; + } + + public void init() { + + } + + public int fireballsOnScreen = 0; + + List shellsToCheck = new ArrayList(); + + public void checkShellCollide(Shell shell) { + shellsToCheck.add(shell); + } + + List fireballsToCheck = new ArrayList(); + + public void checkFireballCollide(Fireball fireball) { + fireballsToCheck.add(fireball); + } + + public void tick() { + timeLeft--; + + if (widthArrow < 0) { + widthArrow *= -1; + tipWidthArrow *= -1; + + xPositionsArrow = new int[] { xArrow + -widthArrow / 2, + xArrow + widthArrow / 2 - tipWidthArrow, + xArrow + widthArrow / 2 - tipWidthArrow, + xArrow + widthArrow / 2, + xArrow + widthArrow / 2 - tipWidthArrow, + xArrow + widthArrow / 2 - tipWidthArrow, + xArrow + -widthArrow / 2 }; + yPositionsArrow = new int[] { yArrow + -heightArrow / 4, + yArrow + -heightArrow / 4, yArrow + -heightArrow / 2, + yArrow + 0, yArrow + heightArrow / 2, + yArrow + heightArrow / 4, yArrow + heightArrow / 4 }; + + } + + if (timeLeft == 0) { + mario.dieTime(); + } + + xCamO = xCam; + yCamO = yCam; + + if (startTime > 0) { + startTime++; + } + + float targetXCam = mario.x - 160; + + xCam = targetXCam; + + if (xCam < 0) + xCam = 0; + if (xCam > level.getWidth() * 16 - 320) + xCam = level.getWidth() * 16 - 320; + + /* + * if (recorder != null) { recorder.addTick(mario.getKeyMask()); } + * + * if (replayer!=null) { mario.setKeys(replayer.nextTick()); } + */ + + fireballsOnScreen = 0; + + for (Sprite sprite : sprites) { + if (sprite != mario) { + float xd = sprite.x - xCam; + float yd = sprite.y - yCam; + if (xd < -64 || xd > 320 + 64 || yd < -64 || yd > 240 + 64) { + removeSprite(sprite); + } else { + if (sprite instanceof Fireball) { + fireballsOnScreen++; + } + } + } + } + + if (paused) { + for (Sprite sprite : sprites) { + if (sprite == mario) { + sprite.tick(); + } else { + sprite.tickNoMove(); + } + } + } else { + + tick++; + level.tick(); + + boolean hasShotCannon = false; + int xCannon = 0; + + for (int x = (int) xCam / 16 - 1; x <= (int) (xCam + layer.width) / 16 + 1; x++) + for (int y = (int) yCam / 16 - 1; y <= (int) (yCam + layer.height) / 16 + 1; y++) { + int dir = 0; + + if (x * 16 + 8 > mario.x + 16) + dir = -1; + if (x * 16 + 8 < mario.x - 16) + dir = 1; + + SpriteTemplate st = level.getSpriteTemplate(x, y); + + if (st != null) { + if (st.lastVisibleTick != tick - 1) { + if (st.sprite == null + || !sprites.contains(st.sprite)) { + st.spawn(this, x, y, dir); + + } + } + + st.lastVisibleTick = tick; + } + + if (dir != 0) { + byte b = level.getBlock(x, y); + if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_ANIMATED) > 0) { + if ((b % 16) / 4 == 3 && b / 16 == 0) { + if ((tick - x * 2) % 100 == 0) { + xCannon = x; + for (int i = 0; i < 8; i++) { + addSprite(new Sparkle(x * 16 + 8, y + * 16 + + (int) (Math.random() * 16), + (float) Math.random() * dir, 0, + 0, 1, 5)); + } + addSprite(new BulletBill(this, x * 16 + 8 + + dir * 8, y * 16 + 15, dir)); + hasShotCannon = true; + } + } + } + } + } + + if (hasShotCannon) { + sound.play(Art.samples[Art.SAMPLE_CANNON_FIRE], + new FixedSoundSource(xCannon * 16, yCam + 120), 1, 1, 1); + } + + for (Sprite sprite : sprites) { + sprite.tick(); + } + + for (Sprite sprite : sprites) { + sprite.collideCheck(); + } + + for (Shell shell : shellsToCheck) { + for (Sprite sprite : sprites) { + if (sprite != shell && !shell.dead) { + if (sprite.shellCollideCheck(shell)) { + if (mario.carried == shell && !shell.dead) { + mario.carried = null; + shell.die(); + } + } + } + } + } + shellsToCheck.clear(); + + for (Fireball fireball : fireballsToCheck) { + for (Sprite sprite : sprites) { + if (sprite != fireball && !fireball.dead) { + if (sprite.fireballCollideCheck(fireball)) { + fireball.die(); + } + } + } + } + fireballsToCheck.clear(); + } + + sprites.addAll(0, spritesToAdd); + sprites.removeAll(spritesToRemove); + spritesToAdd.clear(); + spritesToRemove.clear(); + } + + private DecimalFormat df = new DecimalFormat("00"); + private DecimalFormat df2 = new DecimalFormat("000"); + + public void render(Graphics g, float alpha) { + int xCam = (int) (mario.xOld + (mario.x - mario.xOld) * alpha) - 160; + int yCam = (int) (mario.yOld + (mario.y - mario.yOld) * alpha) - 120; + + if (xCam < 0) + xCam = 0; + if (yCam < 0) + yCam = 0; + if (xCam > level.getWidth() * 16 - 320) + xCam = level.getWidth() * 16 - 320; + if (yCam > level.getHeight() * 16 - 240) + yCam = level.getHeight() * 16 - 240; + + // g.drawImage(Art.background, 0, 0, null); + + for (int i = 0; i < 2; i++) { + bgLayer[i].setCam(xCam, yCam); + bgLayer[i].render(g, tick, alpha); + } + + g.translate(-xCam, -yCam); + for (Sprite sprite : sprites) { + if (sprite.layer == 0) + sprite.render(g, alpha); + } + g.translate(xCam, yCam); + + // //////////THIS RENDERS THE LEVEL + layer.setCam(xCam, yCam); + layer.render(g, tick, paused ? 0 : alpha); + layer.renderExit0(g, tick, paused ? 0 : alpha, mario.winTime == 0); + // //////////END OF LEVEL RENDER + + // //////////RENDERS SPRITES + g.translate(-xCam, -yCam); + for (Sprite sprite : sprites) { + if (sprite.layer == 1) + sprite.render(g, alpha); + } + g.translate(xCam, yCam); + g.setColor(Color.BLACK); + layer.renderExit1(g, tick, paused ? 0 : alpha); + // //////////END OF SPRITE RENDERING + + drawStringDropShadow(g, "MARIO " + df.format(Mario.lives), 0, 0, 7); + // drawStringDropShadow(g, "00000000", 0, 1, 7); + + drawStringDropShadow(g, "COIN", 14, 0, 7); + drawStringDropShadow(g, " " + df.format(Mario.coins), 14, 1, 7); + + drawStringDropShadow(g, "WORLD", 24, 0, 7); + drawStringDropShadow(g, " " + Mario.levelString, 24, 1, 7); + + drawStringDropShadow(g, "TIME", 35, 0, 7); + int time = (timeLeft + 15 - 1) / 15; + if (time < 0) + time = 0; + drawStringDropShadow(g, " " + df2.format(time), 35, 1, 7); + + renderDirectionArrow(g); + + if (startTime > 0) { + float t = startTime + alpha - 2; + t = t * t * 0.6f; + renderBlackout(g, 160, 120, (int) (t)); + } + // mario.x>level.xExit*16 + if (mario.winTime > 0) { + float t = mario.winTime + alpha; + t = t * t * 0.2f; + + if (t > 0) { + if (recorder != null) { + recorder.stopRecord(); + recorder.levelWon(); + // recorder.printAll(); + } + + } + + if (t > 900) { + + winActions(); + return; + + // replayer = new Replayer(recorder.getBytes()); + // init(); + } + + renderBlackout(g, (int) (mario.xDeathPos - xCam), + (int) (mario.yDeathPos - yCam), (int) (320 - t)); + } + + if (mario.deathTime > 0) { + g.setColor(Color.BLACK); + float t = mario.deathTime + alpha; + t = t * t * 0.4f; + + if (t > 0 && Mario.lives <= 0) { + if (recorder != null) { + recorder.stopRecord(); + } + } + + if (t > 1800) { + Mario.lives--; + deathActions(); + } + + renderBlackout(g, (int) (mario.xDeathPos - xCam), + (int) (mario.yDeathPos - yCam), (int) (320 - t)); + } + } + + public void winActions() { + + } + + public void deathActions() { + + } + + protected void reset() { + paused = false; + Sprite.spriteContext = this; + sprites.clear(); + + try { + level = currentLevel.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + level.resetSpriteTemplate(); + + layer = new LevelRenderer(level, graphicsConfiguration, 320, 240); + + mario = new Mario(this); + sprites.add(mario); + startTime = 1; + + timeLeft = 200 * 15; + Art.startMusic(1); + tick = 0; + + if (recorder != null) { + recorder.detailedLog = ""; + } + gameStarted = false; + } + + private void renderDirectionArrow(Graphics g) { + if (widthArrow < 0) + g.setColor(new Color(0, 0, 255, 150)); + else + g.setColor(new Color(255, 0, 0, 150)); + + g.fillPolygon(xPositionsArrow, yPositionsArrow, + Math.min(xPositionsArrow.length, yPositionsArrow.length)); + g.setColor(new Color(0, 0, 0, 255)); + g.drawPolygon(xPositionsArrow, yPositionsArrow, + Math.min(xPositionsArrow.length, yPositionsArrow.length)); + } + + private void drawStringDropShadow(Graphics g, String text, int x, int y, + int c) { + drawString(g, text, x * 8 + 5, y * 8 + 5, 0); + drawString(g, text, x * 8 + 4, y * 8 + 4, c); + } + + private void drawString(Graphics g, String text, int x, int y, int c) { + char[] ch = text.toCharArray(); + for (int i = 0; i < ch.length; i++) { + g.drawImage(Art.font[ch[i] - 32][c], x + i * 8, y, null); + } + } + + float decrease = (float) 0.03; + float factor = 0; + boolean in = true; + String flipText = "FLIP! MOVE THE OTHER WAY!"; + + private void renderBlackout(Graphics g, int x, int y, int radius) { + if (radius > 320) + return; + + int[] xp = new int[20]; + int[] yp = new int[20]; + for (int i = 0; i < 16; i++) { + xp[i] = x + (int) (Math.cos(i * Math.PI / 15) * radius); + yp[i] = y + (int) (Math.sin(i * Math.PI / 15) * radius); + } + xp[16] = 320; + yp[16] = y; + xp[17] = 320; + yp[17] = 240; + xp[18] = 0; + yp[18] = 240; + xp[19] = 0; + yp[19] = y; + g.fillPolygon(xp, yp, xp.length); + + for (int i = 0; i < 16; i++) { + xp[i] = x - (int) (Math.cos(i * Math.PI / 15) * radius); + yp[i] = y - (int) (Math.sin(i * Math.PI / 15) * radius); + } + xp[16] = 320; + yp[16] = y; + xp[17] = 320; + yp[17] = 0; + xp[18] = 0; + yp[18] = 0; + xp[19] = 0; + yp[19] = y; + + g.fillPolygon(xp, yp, xp.length); + } + + public void addSprite(Sprite sprite) { + spritesToAdd.add(sprite); + sprite.tick(); + } + + public void removeSprite(Sprite sprite) { + spritesToRemove.add(sprite); + } + + public float getX(float alpha) { + int xCam = (int) (mario.xOld + (mario.x - mario.xOld) * alpha) - 160; + + if (xCam < 0) + xCam = 0; + + return xCam + 160; + } + + public float getY(float alpha) { + return 0; + } + + public void bump(int x, int y, boolean canBreakBricks) { + byte block = level.getBlock(x, y); + + if ((Level.TILE_BEHAVIORS[block & 0xff] & Level.BIT_BUMPABLE) > 0) { + bumpInto(x, y - 1); + level.setBlock(x, y, (byte) 4); + + if (((Level.TILE_BEHAVIORS[block & 0xff]) & Level.BIT_SPECIAL) > 0) { + sound.play(Art.samples[Art.SAMPLE_ITEM_SPROUT], + new FixedSoundSource(x * 16 + 8, y * 16 + 8), 1, 1, 1); + if (!Mario.large) { + addSprite(new Mushroom(this, x * 16 + 8, y * 16 + 8)); + } else { + addSprite(new FireFlower(this, x * 16 + 8, y * 16 + 8)); + } + + if (recorder != null) { + recorder.blockPowerDestroyRecord(); + } + } else { + if (recorder != null) { + recorder.blockCoinDestroyRecord(); + } + + Mario.getCoin(); + sound.play(Art.samples[Art.SAMPLE_GET_COIN], + new FixedSoundSource(x * 16 + 8, y * 16 + 8), 1, 1, 1); + addSprite(new CoinAnim(x, y)); + } + } + + if ((Level.TILE_BEHAVIORS[block & 0xff] & Level.BIT_BREAKABLE) > 0) { + bumpInto(x, y - 1); + if (canBreakBricks) { + if (recorder != null) { + recorder.blockEmptyDestroyRecord(); + } + + sound.play(Art.samples[Art.SAMPLE_BREAK_BLOCK], + new FixedSoundSource(x * 16 + 8, y * 16 + 8), 1, 1, 1); + level.setBlock(x, y, (byte) 0); + for (int xx = 0; xx < 2; xx++) + for (int yy = 0; yy < 2; yy++) + addSprite(new Particle(x * 16 + xx * 8 + 4, y * 16 + yy + * 8 + 4, (xx * 2 - 1) * 4, (yy * 2 - 1) * 4 - 8)); + } + + } + } + + public void bumpInto(int x, int y) { + byte block = level.getBlock(x, y); + if (((Level.TILE_BEHAVIORS[block & 0xff]) & Level.BIT_PICKUPABLE) > 0) { + Mario.getCoin(); + sound.play(Art.samples[Art.SAMPLE_GET_COIN], new FixedSoundSource( + x * 16 + 8, y * 16 + 8), 1, 1, 1); + level.setBlock(x, y, (byte) 0); + addSprite(new CoinAnim(x, y + 1)); + + // TODO no idea when this happens... maybe remove coin count + if (recorder != null) + recorder.recordCoin(); + } + + for (Sprite sprite : sprites) { + sprite.bumpCheck(x, y); + } + } + + public void setLevel(Level level) { + this.level = level; + } + + @Override + public void mouseClicked(MouseEvent me) { + } +} diff --git a/src/dk/itu/mario/scene/LevelSceneCustom.java b/src/dk/itu/mario/scene/LevelSceneCustom.java new file mode 100644 index 0000000..9940486 --- /dev/null +++ b/src/dk/itu/mario/scene/LevelSceneCustom.java @@ -0,0 +1,198 @@ +package dk.itu.mario.scene; + +import java.awt.GraphicsConfiguration; +import java.io.DataInputStream; +import java.io.IOException; + +import dk.itu.mario.MarioInterface.GamePlay; +import dk.itu.mario.MarioInterface.LevelGenerator; +import dk.itu.mario.engine.Art; +import dk.itu.mario.engine.BgRenderer; +import dk.itu.mario.engine.DataRecorder; +import dk.itu.mario.engine.LevelRenderer; +import dk.itu.mario.engine.MarioComponent; +import dk.itu.mario.engine.sonar.FixedSoundSource; +import dk.itu.mario.engine.sprites.CoinAnim; +import dk.itu.mario.engine.sprites.FireFlower; +import dk.itu.mario.engine.sprites.Mario; +import dk.itu.mario.engine.sprites.Mushroom; +import dk.itu.mario.engine.sprites.Particle; +import dk.itu.mario.engine.sprites.Sprite; +import dk.itu.mario.engine.util.FileHandler; +import dk.itu.mario.level.BgLevelGenerator; +import dk.itu.mario.level.Level; +import dk.itu.mario.level.RandomLevel; + +public class LevelSceneCustom extends LevelScene { + private boolean isCustom; + private LevelGenerator clg; + + public LevelSceneCustom(GraphicsConfiguration graphicsConfiguration, + MarioComponent renderer, long seed, int levelDifficulty, int type, + boolean isCustom, LevelGenerator levelGenerator) { + super(graphicsConfiguration, renderer, seed, levelDifficulty, type); + this.isCustom = isCustom; + this.clg = levelGenerator; + } + + public void init() { + try { + Level.loadBehaviors(new DataInputStream(LevelSceneCustom.class + .getResourceAsStream("/res/tiles.dat"))); + } catch (IOException e) { + e.printStackTrace(); + System.exit(0); + } + + //if (level == null) + // if (isCustom) { + GamePlay gp = GamePlay.read("player.txt"); + currentLevel = (Level) clg.generateLevel(gp); + + // You can use the following commands if you want to benefit + // from + // the interface containing detailed information + String detailedInfo = FileHandler.readFile("DetailedInfo.txt"); + System.out.println("DetailedInfo: " + detailedInfo); + // } else + // currentLevel = new RandomLevel(320, 15, levelSeed, + // levelDifficulty, levelType); + + try { + level = currentLevel.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + + // level is always overground + Art.startMusic(1); + + paused = false; + Sprite.spriteContext = this; + sprites.clear(); + + layer = new LevelRenderer(level, graphicsConfiguration, 320, 240); + for (int i = 0; i < 2; i++) { + int scrollSpeed = 4 >> i; + int w = ((level.getWidth() * 16) - 320) / scrollSpeed + 320; + int h = ((level.getHeight() * 16) - 240) / scrollSpeed + 240; + Level bgLevel = BgLevelGenerator.createLevel(w / 32 + 1, + h / 32 + 1, i == 0, levelType); + bgLayer[i] = new BgRenderer(bgLevel, graphicsConfiguration, 320, + 240, scrollSpeed); + } + + mario = new Mario(this); + sprites.add(mario); + startTime = 1; + + timeLeft = 200 * 15; + + tick = 0; + + if (!isCustom && recorder == null) + recorder = new DataRecorder(this, (RandomLevel) level, keys); + + gameStarted = false; + } + + public void tick() { + super.tick(); + + if (recorder != null && !gameStarted) { + recorder.startLittleRecord(); + recorder.startTime(); + gameStarted = true; + } + if (recorder != null) + recorder.tickRecord(); + } + + public void winActions() { + if (recorder != null) + recorder.fillGamePlayMetrics((RandomLevel) level); + + marioComponent.win(); + } + + public void deathActions() { + if (Mario.lives <= 0) {// has no more lives + if (recorder != null) + recorder.fillGamePlayMetrics((RandomLevel) level); + marioComponent.lose(); + } else + // mario still has lives to play :)--> have a new beginning + reset(); + } + + public void bump(int x, int y, boolean canBreakBricks) { + byte block = level.getBlock(x, y); + + if ((Level.TILE_BEHAVIORS[block & 0xff] & Level.BIT_BUMPABLE) > 0) { + bumpInto(x, y - 1); + level.setBlock(x, y, (byte) 4); + + if (((Level.TILE_BEHAVIORS[block & 0xff]) & Level.BIT_SPECIAL) > 0) { + sound.play(Art.samples[Art.SAMPLE_ITEM_SPROUT], + new FixedSoundSource(x * 16 + 8, y * 16 + 8), 1, 1, 1); + if (!Mario.large) { + addSprite(new Mushroom(this, x * 16 + 8, y * 16 + 8)); + } else { + addSprite(new FireFlower(this, x * 16 + 8, y * 16 + 8)); + } + + if (recorder != null) { + recorder.blockPowerDestroyRecord(); + } + } else { + // TODO should only record hidden coins (in boxes) + if (recorder != null) { + recorder.blockCoinDestroyRecord(); + } + + Mario.getCoin(); + sound.play(Art.samples[Art.SAMPLE_GET_COIN], + new FixedSoundSource(x * 16 + 8, y * 16 + 8), 1, 1, 1); + addSprite(new CoinAnim(x, y)); + } + } + + if ((Level.TILE_BEHAVIORS[block & 0xff] & Level.BIT_BREAKABLE) > 0) { + bumpInto(x, y - 1); + if (canBreakBricks) { + if (recorder != null) { + recorder.blockEmptyDestroyRecord(); + } + + sound.play(Art.samples[Art.SAMPLE_BREAK_BLOCK], + new FixedSoundSource(x * 16 + 8, y * 16 + 8), 1, 1, 1); + level.setBlock(x, y, (byte) 0); + for (int xx = 0; xx < 2; xx++) + for (int yy = 0; yy < 2; yy++) + addSprite(new Particle(x * 16 + xx * 8 + 4, y * 16 + yy + * 8 + 4, (xx * 2 - 1) * 4, (yy * 2 - 1) * 4 - 8)); + } + + } + } + + public void bumpInto(int x, int y) { + byte block = level.getBlock(x, y); + if (((Level.TILE_BEHAVIORS[block & 0xff]) & Level.BIT_PICKUPABLE) > 0) { + Mario.getCoin(); + sound.play(Art.samples[Art.SAMPLE_GET_COIN], new FixedSoundSource( + x * 16 + 8, y * 16 + 8), 1, 1, 1); + level.setBlock(x, y, (byte) 0); + addSprite(new CoinAnim(x, y + 1)); + + // TODO no idea when this happens... maybe remove coin count + if (recorder != null) + recorder.recordCoin(); + } + + for (Sprite sprite : sprites) { + sprite.bumpCheck(x, y); + } + } + +} \ No newline at end of file diff --git a/src/dk/itu/mario/scene/LoseScene.java b/src/dk/itu/mario/scene/LoseScene.java new file mode 100644 index 0000000..9f344fe --- /dev/null +++ b/src/dk/itu/mario/scene/LoseScene.java @@ -0,0 +1,62 @@ +package dk.itu.mario.scene; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.event.MouseEvent; + +import dk.itu.mario.engine.Art; +import dk.itu.mario.engine.sprites.Mario; + +public class LoseScene extends Scene { + + private int tick; + private String scrollMessage = "Game over!"; + + public LoseScene() { + } + + public void init() { + } + + public void render(Graphics g, float alpha) { + g.setColor(Color.decode("#a07070")); + g.fillRect(0, 0, 320, 240); + int f = tick / 3 % 10; + if (f >= 6) + f = 10 - f; + g.drawImage(Art.gameOver[f][0], 160 - 48, 100 - 32, null); + drawString(g, scrollMessage, 160 - scrollMessage.length() * 4, 160, 0); + } + + private void drawString(Graphics g, String text, int x, int y, int c) { + char[] ch = text.toCharArray(); + for (int i = 0; i < ch.length; i++) { + g.drawImage(Art.font[ch[i] - 32][c], x + i * 8, y, null); + } + } + + private boolean wasDown = true; + + public void tick() { + tick++; + if (!wasDown && keys[Mario.KEY_JUMP]) { + // component.toTitle(); + } + if (keys[Mario.KEY_JUMP]) { + wasDown = false; + } + } + + public float getX(float alpha) { + return 0; + } + + public float getY(float alpha) { + return 0; + } + + @Override + public void mouseClicked(MouseEvent me) { + // TODO Auto-generated method stub + } +} diff --git a/src/dk/itu/mario/scene/Scene.java b/src/dk/itu/mario/scene/Scene.java new file mode 100644 index 0000000..ac31f8c --- /dev/null +++ b/src/dk/itu/mario/scene/Scene.java @@ -0,0 +1,43 @@ +package dk.itu.mario.scene; + +import java.awt.Graphics; +import java.awt.event.MouseEvent; + + +import dk.itu.mario.engine.sonar.SonarSoundEngine; +import dk.itu.mario.engine.sonar.SoundListener; + + +public abstract class Scene implements SoundListener +{ + public SonarSoundEngine sound; + public static boolean[] keys = new boolean[16]; + + public static final int COLOR_BLACK = 0; + public static final int COLOR_RED = 1; + public static final int COLOR_GREEN = 2; + public static final int COLOR_BLUE = 3; + public static final int COLOR_YELLOW = 4; + public static final int COLOR_PURPLE = 5; + public static final int COLOR_LIGHTBLUE = 6; + public static final int COLOR_WHITE = 7; + + public void toggleKey(int key, boolean isPressed) + { + keys[key] = isPressed; + } + + public final void setSound(SonarSoundEngine sound) + { + sound.setListener(this); + this.sound = sound; + } + + public abstract void mouseClicked(MouseEvent me); + + public abstract void init(); + + public abstract void tick(); + + public abstract void render(Graphics og, float alpha); +} \ No newline at end of file diff --git a/src/dk/itu/mario/scene/WinScene.java b/src/dk/itu/mario/scene/WinScene.java new file mode 100644 index 0000000..7649460 --- /dev/null +++ b/src/dk/itu/mario/scene/WinScene.java @@ -0,0 +1,58 @@ +package dk.itu.mario.scene; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.event.MouseEvent; + +import dk.itu.mario.engine.Art; +import dk.itu.mario.engine.sprites.Mario; + +public class WinScene extends Scene { + private int tick; + private String scrollMessage = "Thank you for saving me, Mario!"; + + public WinScene() { + } + + public void init() { + } + + public void render(Graphics g, float alpha) { + g.setColor(Color.decode("#8080a0")); + g.fillRect(0, 0, 320, 240); + g.drawImage(Art.endScene[tick / 24 % 2][0], 160 - 48, 100 - 48, null); + drawString(g, scrollMessage, 160 - scrollMessage.length() * 4, 160, 0); + } + + private void drawString(Graphics g, String text, int x, int y, int c) { + char[] ch = text.toCharArray(); + for (int i = 0; i < ch.length; i++) { + g.drawImage(Art.font[ch[i] - 32][c], x + i * 8, y, null); + } + } + + private boolean wasDown = true; + + public void tick() { + tick++; + if (!wasDown && keys[Mario.KEY_JUMP]) { + // component.toTitle(); + } + if (keys[Mario.KEY_JUMP]) { + wasDown = false; + } + } + + public float getX(float alpha) { + return 0; + } + + public float getY(float alpha) { + return 0; + } + + @Override + public void mouseClicked(MouseEvent me) { + // TODO Auto-generated method stub + } +} \ No newline at end of file diff --git a/test/dk/itu/mario/level/MyLevelTest.java b/test/dk/itu/mario/level/MyLevelTest.java new file mode 100644 index 0000000..4c737ec --- /dev/null +++ b/test/dk/itu/mario/level/MyLevelTest.java @@ -0,0 +1,14 @@ +package dk.itu.mario.level; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class MyLevelTest { + + @Test + public void test() { + fail("Not yet implemented"); + } + +}