Advertisement
NovaYoshi

Nova's Rad Adventure main script

Jan 21st, 2013
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.96 KB | None | 0 0
  1. //////////////////////////////////////////
  2. // Main script for Nova's Rad Adventure //
  3. // by NovaSquirrel 2013 //
  4. //////////////////////////////////////////
  5. Gravity <- 0x0020;
  6. SpriteList <- []; SpriteList.resize(80, null);
  7. Retraces <- 0;
  8. local KeyDown = 0, KeyLast = 0, KeyNew = 0, KeyRelease = 0;
  9. local CameraX = 0;
  10.  
  11. const SCREEN_WIDTH = 320
  12. const SCREEN_HEIGHT = 240;
  13. local MinCameraX = 0, MaxCameraX = 5000;
  14. local PlayerIndex = null, PlayerObj = null;
  15.  
  16. // define enums /////////////////////////////////
  17. enum Sounds {
  18. Jump,
  19. Toss,
  20. Die,
  21. Defeat,
  22. Hit,
  23. Get,
  24. Land,
  25. Swallow,
  26. };
  27. enum Surfaces {
  28. Screen,
  29. Overlay,
  30. Player,
  31. CommonFG,
  32. ThemeFG,
  33. Enemy,
  34. Effects,
  35. };
  36. enum SpriteClass {
  37. None,
  38. Player, // special
  39. Projectile, // hurts people
  40. Enemy, // hurts player but can be stunned
  41. };
  42. enum BlockFlags {
  43. SolidMiddle = 1
  44. SolidTop = 2
  45. SolidBottom = 4
  46. SlopeL = 8
  47. SlopeR = 16
  48. DrawOutline = 32
  49. CommonSheet = 64
  50. FallThrough = 128
  51. };
  52. enum KeyMask {
  53. Left = 1
  54. Right = 2
  55. Up = 4
  56. Down = 8
  57. A = 16
  58. B = 32
  59. X = 64
  60. Y = 128
  61. SL = 256
  62. SR = 512
  63. };
  64.  
  65. // define base classes //////////////////////////
  66. class Sprite {
  67. // flags and info
  68. Edible = false
  69. static Class = SpriteClass.None
  70. CanPickup = false
  71. IsCarried = false
  72. MaxDistanceRun = 0
  73.  
  74. // location and speed
  75. PosX = 0
  76. PosY = 0
  77. VelX = 0
  78. VelY = 0
  79.  
  80. HFlip = false
  81. // for collisions
  82. Width = 0
  83. Height = 0
  84. StandingOnSolid = false
  85. OldStandingOnSolid = false
  86. SideBlocked = false
  87. WillFallThrough = false
  88.  
  89. function Run() {}
  90. function Draw() {}
  91.  
  92. function CanPickupEffect() {
  93. api.SpriteBlit(Surfaces.Effects, (rand()&1)<<3, 0, (PosX>>8)+Width/2+(sin(Retraces/2.0)*Width/2)-4, (PosY>>8)+Height/2+(cos(Retraces/2.0)*Height/2)-4, 8, 8);
  94. }
  95.  
  96. function ApplyVelocity(VelocityX, VelocityY) {
  97. OldStandingOnSolid = StandingOnSolid;
  98. StandingOnSolid = false;
  99. SideBlocked = false;
  100.  
  101. local OldPosX = PosX, OldPosY = PosY;
  102.  
  103. // check against touching stuff
  104. if(VelocityX > 0) {
  105. if(!lib.ChkBlockFlagXY(((PosX+VelocityX)>>8)+Width-1, (PosY>>8) + (Height/2), BlockFlags.SolidMiddle)
  106. && !lib.ChkBlockFlagXY(((PosX+VelocityX)>>8)+Width-1, (PosY>>8) + (Height-1), BlockFlags.SolidMiddle)
  107. && !lib.ChkBlockFlagXY(((PosX+VelocityX)>>8)+Width-1, (PosY>>8), BlockFlags.SolidMiddle))
  108. PosX += VelocityX;
  109. else {
  110. PosX = (((PosX+VelocityX)+(Width-1<<8)) & ~0xfff) - (16<<8);
  111. SideBlocked = true;
  112. }
  113. } else {
  114. if(!lib.ChkBlockFlagXY((PosX+VelocityX)>>8, (PosY>>8) + (Height/2), BlockFlags.SolidMiddle)
  115. && !lib.ChkBlockFlagXY((PosX+VelocityX)>>8, (PosY>>8) + (Height-1), BlockFlags.SolidMiddle)
  116. && !lib.ChkBlockFlagXY((PosX+VelocityX)>>8, (PosY>>8), BlockFlags.SolidMiddle))
  117. PosX += VelocityX;
  118. else {
  119. PosX = ((PosX-VelocityX) & ~0xfff);
  120. SideBlocked = true;
  121. }
  122. }
  123.  
  124. PosY += VelocityY;
  125.  
  126. // check for flat floor (best kind)
  127. if(lib.ChkBlockFlagXY((PosX>>8), (PosY>>8) + Height, BlockFlags.SolidTop)
  128. || lib.ChkBlockFlagXY((PosX>>8)+(Width-1), (PosY>>8) + Height, BlockFlags.SolidTop)) {
  129. local CanFallLeft = lib.ChkBlockFlagXY((PosX>>8), (PosY>>8) + Height, BlockFlags.FallThrough);
  130. local CanFallRight = lib.ChkBlockFlagXY((PosX>>8) + Width - 1, (PosY>>8) + Height, BlockFlags.FallThrough);
  131. if((VelocityY >= 0 && ((((PosY>>8) + Height) >>4) != (((OldPosY>>8) + Height - 1)>>4)))
  132. && !(WillFallThrough && CanFallLeft && CanFallRight)) {
  133. PosY = ((PosY+(Height<<8)) & 0xf000)-(Height<<8);
  134. VelY = 0;
  135. StandingOnSolid = true;
  136. }
  137. }
  138.  
  139. // slopes mostly fixed but still a bit buggy
  140. if(lib.ChkBlockFlagXY((PosX>>8)+(Width-1), (PosY>>8)+Height-1, BlockFlags.SlopeL) && VelocityY >= 0) {
  141. local PartX = ((PosX>>8)+(Width-1))&15, PartY = ((PosY>>8)+(Height-1))&15, MaxY = 15-PartX;
  142. if(PartY>MaxY) PosY = (((((PosY>>8)+Height-1) & ~15)) - Height + MaxY) <<8;
  143. StandingOnSolid = true;
  144. }
  145. if(lib.ChkBlockFlagXY((PosX>>8), (PosY>>8)+Height-1, BlockFlags.SlopeR) && VelocityY >= 0) {
  146. local PartX = (PosX>>8)&15, PartY = ((PosY>>8)+(Height-1))&15, MaxY = PartX;
  147. if(PartY>MaxY) PosY = (((((PosY>>8)+Height-1) & ~15)) - Height + MaxY) <<8;
  148. StandingOnSolid = true;
  149. }
  150.  
  151. // check for solids above
  152. if(lib.ChkBlockFlagXY((PosX>>8), (PosY>>8), BlockFlags.SolidMiddle)
  153. || lib.ChkBlockFlagXY((PosX>>8)+(Width-1), (PosY>>8), BlockFlags.SolidMiddle)) {
  154. VelY = 0x0f0;
  155. }
  156.  
  157. if(lib.ChkBlockType((PosX>>8), (PosY>>8) + Height - 1, 23)
  158. || lib.ChkBlockType((PosX>>8)+(Width-1), (PosY>>8) + Height - 1, 23)) {
  159. VelY = -0x0500;
  160. }
  161.  
  162. }
  163. };
  164.  
  165. class EnemySprite extends Sprite {
  166. Class = SpriteClass.Enemy
  167. StunTime = 0
  168. function ChkBouncedOn() {
  169. if(lib.SpriteTouching(this,SpriteList[PlayerIndex])) {
  170. if(((this.PosY>>8)+this.Height/2) > (SpriteList[PlayerIndex].PosY>>8)+(SpriteList[PlayerIndex].Height)) {
  171. api.PlaySound(Sounds.Hit);
  172. SpriteList[PlayerIndex].VelY = -0x200;
  173. StunTime = 200;
  174. CanPickup = true;
  175. }
  176. }
  177. }
  178. function NotCarried() {
  179. CanPickup = false;
  180. IsCarried = false;
  181. if(this == PlayerObj.CarriedObject) {
  182. PlayerObj.CarriedObject = null;
  183. PlayerObj.IsCarryingStuff = false;
  184. }
  185. }
  186. };
  187.  
  188. class GoombaEnemy extends EnemySprite {
  189. Width = 16
  190. Height = 16
  191. MaxDistanceRun = 500
  192.  
  193. function Run() {
  194. VelY += Gravity;
  195. ChkBouncedOn();
  196. if(SideBlocked)
  197. HFlip = !HFlip;
  198.  
  199. if(StunTime) {
  200. VelX = 0;
  201. StunTime--;
  202. } else {
  203. NotCarried();
  204. if(StandingOnSolid) {
  205. VelX = -0x140;
  206. if(HFlip)
  207. VelX *= -1;
  208. }
  209. }
  210. ApplyVelocity(VelX,VelY);
  211. }
  212. function Draw() {
  213. api.SpriteBlit(Surfaces.Enemy, 0, 16, PosX>>8, PosY>>8, 16, 16, (Retraces&8)!=0);
  214. if(StunTime)
  215. CanPickupEffect();
  216. }
  217. }
  218.  
  219. class PlayerSprite extends Sprite {
  220. Class = SpriteClass.Player
  221. Width = 16
  222. Height = 24
  223. WalkAnimTimer = 0
  224. HFlip = true
  225.  
  226. IsCarryingStuff = false
  227. CarriedObject = null
  228. HeadFrame = 0
  229. SwallowTimer = 0;
  230. CanMove = true;
  231. FatTimer = 0;
  232. HoldingDownTimer = 0;
  233.  
  234. function Swallow() {
  235. if(FatTimer) return;
  236. lib.DeleteSprite(CarriedObject);
  237. CarriedObject = null;
  238. IsCarryingStuff = false;
  239. SwallowTimer = 1;
  240. CanMove = false;
  241. api.PlaySound(Sounds.Swallow);
  242. }
  243. function AdjustCamera() {
  244. local ScreenX = (PosX>>8) - CameraX + (Width/2);
  245. local LeftEdge = (SCREEN_WIDTH/8)*3;
  246. local RightEdge = (SCREEN_WIDTH/8)*5;
  247. if(ScreenX < LeftEdge) CameraX -= LeftEdge - ScreenX;
  248. if(ScreenX > RightEdge) CameraX += ScreenX - RightEdge;
  249. if(CameraX < MinCameraX) CameraX = MinCameraX;
  250. if(CameraX > MaxCameraX) CameraX = MaxCameraX;
  251. }
  252. function Run() {
  253. VelX = 0;
  254. VelY += Gravity;
  255. if(FatTimer) VelY += 0x0010;
  256. HeadFrame = 0;
  257.  
  258. if(!(KeyDown & KeyMask.Down))
  259. HoldingDownTimer = 0;
  260. else
  261. HoldingDownTimer++;
  262. WillFallThrough = (HoldingDownTimer > 10);
  263.  
  264. if(FatTimer)
  265. FatTimer--;
  266. if(SwallowTimer) {
  267. SwallowTimer++;
  268. if(SwallowTimer < 10) {
  269. HeadFrame = 3;
  270. } else if (SwallowTimer < 20) {
  271. HeadFrame = 4;
  272. } else if (SwallowTimer == 20) {
  273. CanMove = true;
  274. FatTimer = 200;
  275. }
  276. }
  277. if(CanMove) {
  278. if(KeyDown & KeyMask.Left) {
  279. HFlip = false
  280. VelX = -0x0180;
  281. WalkAnimTimer++;
  282. if(KeyDown & KeyMask.Y) {
  283. VelX *= 2;
  284. WalkAnimTimer++;
  285. }
  286. }
  287. if(KeyDown & KeyMask.Right) {
  288. HFlip = true
  289. VelX = 0x0180;
  290. WalkAnimTimer++;
  291. if(KeyDown & KeyMask.Y) {
  292. VelX *= 2;
  293. WalkAnimTimer++;
  294. }
  295. }
  296.  
  297. if(KeyDown & KeyMask.Y && !IsCarryingStuff) {
  298. local i;
  299. foreach(i in SpriteList)
  300. if(i != null && i.CanPickup && !i.IsCarried && lib.SpriteDistance(this,i)<30) {
  301. api.PlaySound(Sounds.Get);
  302. i.IsCarried = true;
  303. IsCarryingStuff = true;
  304. CarriedObject = i;
  305. break;
  306. }
  307. }
  308.  
  309. if(KeyNew & KeyMask.B && StandingOnSolid) {
  310. VelY = -0x0380;
  311. api.PlaySound(Sounds.Jump);
  312. }
  313. if(KeyNew & KeyMask.A && StandingOnSolid)
  314. VelY = -0x0500;
  315. if(IsCarryingStuff && KeyDown & KeyMask.Down)
  316. HeadFrame = 2;
  317. }
  318. if(!VelX)
  319. WalkAnimTimer = 0
  320. if(WalkAnimTimer>=13)
  321. WalkAnimTimer = 1;
  322.  
  323. ApplyVelocity(VelX, VelY);
  324. AdjustCamera();
  325. }
  326. function Draw() {
  327. // tail
  328. api.SpriteBlit(Surfaces.Player, 32, 0, (PosX>>8)+(HFlip?-4:12), (PosY>>8)+6, 8, 16, HFlip);
  329. // torso+head
  330. api.SpriteBlit(Surfaces.Player, 0, HeadFrame<<4, PosX>>8, PosY>>8, 16, 16, HFlip);
  331. // legs
  332. local LegsFrame = 0;
  333. if(WalkAnimTimer) LegsFrame = (WalkAnimTimer&&(WalkAnimTimer<=6))?1:0;
  334. if(!StandingOnSolid) LegsFrame = 1;
  335. if(FatTimer) LegsFrame += 2;
  336. if(FatTimer && FatTimer < 50 && Retraces&16) LegsFrame -= 2;
  337. api.SpriteBlit(Surfaces.Player, 16, LegsFrame<<3, PosX>>8, (PosY>>8)+16, 16, 8, HFlip);
  338. }
  339. }
  340.  
  341. class ActiveBlock {
  342. constructor(SetFlags, OnTouch) {
  343. Flags = SetFlags;
  344. SpriteTouch = OnTouch;
  345. }
  346. Flags = 0;
  347. SpriteTouch = null; // (Sprite, LevelX, LevelY, CheckType)
  348. }
  349.  
  350. BlockData <- {
  351. [0] = ActiveBlock(BlockFlags.FallThrough, null),
  352. [1] = ActiveBlock(BlockFlags.SolidTop|BlockFlags.SolidMiddle|BlockFlags.SolidBottom, null),
  353. [2] = ActiveBlock(BlockFlags.SolidBottom|BlockFlags.SlopeL, null),
  354. [3] = ActiveBlock(BlockFlags.SolidBottom|BlockFlags.SlopeR, null),
  355. [7] = ActiveBlock(BlockFlags.SlopeL|BlockFlags.FallThrough, null),
  356. [8] = ActiveBlock(BlockFlags.SlopeR|BlockFlags.FallThrough, null),
  357. [11] = ActiveBlock(BlockFlags.SolidTop|BlockFlags.FallThrough, null),
  358. [17] = ActiveBlock(BlockFlags.SolidTop, null),
  359.  
  360. [14] = ActiveBlock(BlockFlags.SolidTop|BlockFlags.SolidMiddle, null), // spikes
  361. [15] = ActiveBlock(BlockFlags.SolidTop|BlockFlags.SolidMiddle, null), // spikes
  362. [18] = ActiveBlock(BlockFlags.SolidTop|BlockFlags.SolidMiddle, null), // box
  363.  
  364. [19] = ActiveBlock(BlockFlags.SolidTop|BlockFlags.SolidMiddle, null), // checker box
  365. [20] = ActiveBlock(BlockFlags.SolidTop|BlockFlags.SolidMiddle, null), // checker box
  366. [21] = ActiveBlock(BlockFlags.SolidTop|BlockFlags.SolidMiddle, null), // checker box
  367. [22] = ActiveBlock(BlockFlags.SolidTop|BlockFlags.SolidMiddle, null), // checker box
  368.  
  369. [23] = ActiveBlock(0, null), // springboard
  370. [24] = ActiveBlock(0, null), // floor switch
  371. };
  372.  
  373. // define helper functions //////////////////////
  374. lib <- {
  375. function DeleteSprite(Obj) {
  376. for(local i=0;i<SpriteList.len();i++)
  377. if(SpriteList[i] == Obj) {
  378. SpriteList[i] = null;
  379. return;
  380. }
  381. }
  382. function AllocSprite() {
  383. return SpriteList.find(null);
  384. }
  385. function ChkBlockFlagId(t) {
  386. return (t in BlockData && BlockData[t].Flags&Mask)?true:false;
  387. }
  388. function ChkBlockFlagXY(X, Y, Mask) {
  389. local t = api.GetBlock(X>>4,Y>>4);
  390. return (t in BlockData && BlockData[t].Flags&Mask)?true:false;
  391. }
  392. function ChkBlockType(X, Y, Type) {
  393. local t = api.GetBlock(X>>4,Y>>4);
  394. return t == Type;
  395. }
  396.  
  397. function SpriteDistance(Obj1, Obj2) {
  398. local X1 = (Obj1.PosX>>8)+Obj1.Width/2;
  399. local Y1 = (Obj1.PosY>>8)+Obj1.Height/2;
  400. local X2 = (Obj2.PosX>>8)+Obj2.Width/2;
  401. local Y2 = (Obj2.PosY>>8)+Obj2.Height/2;
  402. return sqrt(pow((X2-X1),2)+pow((Y2-Y1),2)).tointeger();
  403. }
  404. function SpriteTouching(Obj1, Obj2) {
  405. local LeftA, RightA, TopA, BottomA;
  406. local LeftB, RightB, TopB, BottomB;
  407.  
  408. LeftA = Obj1.PosX>>8;
  409. RightA = LeftA+Obj1.Width-1;
  410. TopA = Obj1.PosY>>8;
  411. BottomA = TopA+Obj1.Height-1;
  412.  
  413. if(typeof(Obj2)!="array") {
  414. LeftB = Obj2.PosX>>8;
  415. RightB = LeftB+Obj2.Width-1;
  416. TopB = Obj2.PosY>>8;
  417. BottomB = TopB+Obj2.Height-1;
  418. } else {
  419. LeftB = Obj2[0];
  420. RightB = LeftB+Obj2[1]-1;
  421. TopB = Obj2[1];
  422. BottomB = TopB+Obj[3]-1;
  423. }
  424.  
  425. if(BottomA <= TopB) return false;
  426. if(TopA >= BottomB) return false;
  427. if(RightA <= LeftB) return false;
  428. if(LeftA >= RightB) return false;
  429. return true;
  430. }
  431. };
  432.  
  433. event <- {
  434. function UpdateKeys(Down, Last, New) {
  435. KeyDown = Down;
  436. KeyLast = Last;
  437. KeyNew = New;
  438. KeyRelease = ~KeyDown & KeyLast;
  439. }
  440. };
  441.  
  442. // init stuff ///////////////////////////////////
  443. PlayerIndex = lib.AllocSprite();
  444. SpriteList[PlayerIndex] = PlayerSprite();
  445. SpriteList[PlayerIndex].PosX = 16<<8;
  446. PlayerObj = SpriteList[PlayerIndex];
  447.  
  448. // test stuff //////
  449. event.GameLoop <- function() {
  450. local i;
  451. Retraces++;
  452.  
  453. foreach(i in SpriteList)
  454. if(i != null) {
  455. if(i.MaxDistanceRun && lib.SpriteDistance(i, PlayerObj) > i.MaxDistanceRun)
  456. continue;
  457. i.Run();
  458. if(i.IsCarried) {
  459. if(KeyDown & KeyMask.Down && KeyRelease & KeyMask.Y && PlayerObj.StandingOnSolid == true) {
  460. PlayerObj.Swallow();
  461. } else {
  462. i.PosX = PlayerObj.PosX + (PlayerObj.HFlip?0x800:-0x800);
  463. if(PlayerObj.HeadFrame == 2)
  464. i.PosX = PlayerObj.PosX + (PlayerObj.HFlip?0x500:-0x500);
  465. if(i.Class = SpriteClass.Enemy && i.StunTime < 50)
  466. i.PosX += Retraces&1?0x100:-0x100;
  467.  
  468. i.PosY = PlayerObj.PosY + 0x400;
  469. if(KeyRelease & KeyMask.Y) {
  470. PlayerObj.IsCarryingStuff = false;
  471. PlayerObj.CarriedObject = null;
  472. i.IsCarried = false;
  473. if(i.Class = SpriteClass.Enemy)
  474. i.StunTime = 0;
  475. i.HFlip = PlayerObj.HFlip;
  476. i.VelX = PlayerObj.HFlip?0x100:-0x100;
  477. i.VelY = -0x200;
  478. if(KeyDown & KeyMask.Up) {
  479. i.VelX /= 2;
  480. i.VelY = -0x400;
  481. }
  482. if(KeyDown & KeyMask.Down && PlayerObj.StandingOnSolid == false) {
  483. i.VelX *= 2;
  484. i.VelY = 0x400;
  485. PlayerObj.VelY = -0x300;
  486. }
  487. }
  488. }
  489. }
  490. }
  491. api.SetCamera(CameraX, 0);
  492.  
  493. foreach(i in SpriteList)
  494. if(i != null)
  495. i.Draw();
  496. }
  497.  
  498. local LevelEntrances = {};
  499.  
  500. event.AddPoint <- function(PosX, PosY, Type, Meta) {
  501. local S = lib.AllocSprite();
  502. function AddSprite(SpriteType) {
  503. local S = lib.AllocSprite();
  504. if(S == null) return;
  505. SpriteList[S] = SpriteType;
  506. SpriteList[S].PosX = PosX << 12;
  507. SpriteList[S].PosY = PosY << 12;
  508. }
  509. // print("Adding " + PosX + "," + PosY + " - " + Type)
  510. switch(Type) {
  511. case 0x0100: AddSprite(GoombaEnemy()); break;
  512. case 0x0102: LevelEntrances[Meta] <- [PosX,PosY]; break;
  513. }
  514. }
  515. if(0 in LevelEntrances) {
  516. PlayerObj.PosX = LevelEntrances[0][0]<<12;
  517. PlayerObj.PosY = LevelEntrances[0][1]<<12;
  518. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement