PageRenderTime 68ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/Poing2/GameCharacter.cs

http://github.com/BCProgramming/BASeBlock
C# | 1317 lines | 856 code | 280 blank | 181 comment | 115 complexity | 5ab6058c9ac3aae5a54f4b9c81683e78 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Drawing;
  5. using System.Drawing.Drawing2D;
  6. using System.Drawing.Imaging;
  7. using System.Linq;
  8. using System.Text;
  9. using BASeCamp.BASeBlock.Blocks;
  10. using BASeCamp.BASeBlock.Events;
  11. using BASeCamp.BASeBlock.GameObjects.Orbs;
  12. using BASeCamp.BASeBlock.Particles;
  13. namespace BASeCamp.BASeBlock
  14. {
  15. public class GameCharacter : PlatformObject, iBumpable
  16. {
  17. private List<GameCharacterAbility> _Abilities = new List<GameCharacterAbility>();
  18. private bool flInit = false;
  19. public List<GameCharacterAbility> Abilities { get { return _Abilities; } set { _Abilities = value; } }
  20. public GameCharacter(PointF pPosition)
  21. : this(pPosition, new SizeF(16, 16))
  22. {
  23. }
  24. public GameCharacter(PointF pPosition, SizeF pSize)
  25. : this(pPosition, new Nullable<SizeF>(pSize))
  26. { }
  27. public GameCharacter(PointF pPosition, SizeF? pSize)
  28. : base(pPosition, new PointF(0, 0), null, 6, null)
  29. {
  30. foreach (var iterate in Enum.GetValues(typeof(ButtonConstants)))
  31. {
  32. Buttonspressed[(ButtonConstants)iterate] = false;
  33. }
  34. StateFrameImageKeys = new Dictionary<string, string[]>();
  35. FrameDelayTimes = new Dictionary<string, int[]>();
  36. StateFrameImageKeys.Add("IDLELEFT", new string[] { "FLIPX:CHAR_STAND" });
  37. StateFrameImageKeys.Add("IDLERIGHT", new string[] { "CHAR_STAND" });
  38. StateFrameImageKeys.Add("WALKLEFT", new string[] { "FLIPX:CHAR_STAND", "FLIPX:CHAR_WALK" });
  39. StateFrameImageKeys.Add("WALKRIGHT", new string[] { "CHAR_STAND", "CHAR_WALK" });
  40. StateFrameImageKeys.Add("JUMPLEFT", new string[] { "FLIPX:CHAR_JUMP" });
  41. //StateFrameImageKeys.Add("JUMPLEFTUP", new string[] { "FLIPX:CHAR_JUMP" });
  42. StateFrameImageKeys.Add("JUMPRIGHT", new string[] { "CHAR_JUMP" });
  43. //StateFrameImageKeys.Add("JUMPRIGHTUP", new string[] { "CHAR_JUMP" });
  44. StateFrameImageKeys.Add("STOPLEFT", new string[] { "FLIPX:CHAR_TURN" });
  45. StateFrameImageKeys.Add("STOPRIGHT", new string[] { "CHAR_TURN" });
  46. StateFrameImageKeys.Add("DYING", new string[] { "CHAR_DEAD" }); //shows dead, waits half a second then advanced to "DEATH" stage.
  47. StateFrameImageKeys.Add("DEATH", new string[] { "CHAR_DEAD" });
  48. StateFrameIndex = new Dictionary<string, int>();
  49. StateFrameIndex.Add("IDLELEFT", 0);
  50. StateFrameIndex.Add("IDLERIGHT", 0);
  51. StateFrameIndex.Add("WALKLEFT", 0);
  52. StateFrameIndex.Add("WALKRIGHT", 0);
  53. StateFrameIndex.Add("JUMPLEFT", 0);
  54. //StateFrameIndex.Add("JUMPLEFTUP", 0);
  55. StateFrameIndex.Add("JUMPRIGHT", 0);
  56. //StateFrameIndex.Add("JUMPRIGHTUP", 0);
  57. StateFrameIndex.Add("STOPLEFT", 0);
  58. StateFrameIndex.Add("STOPRIGHT", 0);
  59. StateFrameIndex.Add("DYING", 0);
  60. StateFrameIndex.Add("DEATH", 0);
  61. FrameDelayTimes = new Dictionary<string, int[]>();
  62. FrameDelayTimes.Add("IDLELEFT", new int[] { 2 });
  63. FrameDelayTimes.Add("IDLERIGHT", new int[] { 2 });
  64. FrameDelayTimes.Add("WALKLEFT", new int[] { 2, 2 });
  65. FrameDelayTimes.Add("WALKRIGHT", new int[] { 2, 2 });
  66. FrameDelayTimes.Add("JUMPLEFT", new int[] { 2 });
  67. //FrameDelayTimes.Add("JUMPLEFTUP", new int[] { 2 });
  68. FrameDelayTimes.Add("JUMPRIGHT", new int[] { 2 });
  69. //FrameDelayTimes.Add("JUMPRIGHTUP", new int[] { 2 });
  70. FrameDelayTimes.Add("STOPLEFT", new int[] { 2 });
  71. FrameDelayTimes.Add("STOPRIGHT", new int[] { 2 });
  72. FrameDelayTimes.Add("DYING", new int[] { 2 });
  73. FrameDelayTimes.Add("DEATH", new int[] { 2 });
  74. EnemyAction = "IDLELEFT";
  75. if (pSize != null) useSize = pSize.Value;
  76. InitActions();
  77. //_ActionIndex.Add("JUMPLEFTUP", "JUMPLEFT");
  78. //_ActionIndex.Add("JUMPRIGHTUP", "JUMPRIGHT");
  79. }
  80. private DateTime? DeadTime = null;
  81. public bool GetPowerup(BCBlockGameState gstate, GameCharacterPowerup power)
  82. {
  83. return power.GivePowerTo(gstate, this);
  84. }
  85. public override void Bump(Block bumpedby)
  86. {
  87. base.Bump(bumpedby);
  88. }
  89. public override bool Die(BCBlockGameState gstate)
  90. {
  91. //play death x (mardeathx)
  92. if (_EnemyState != "DEATH" && _EnemyState != "DYING")
  93. {
  94. if (ptd.TrackBlock != null)
  95. {
  96. if (ptd.TrackBlock is iPlatformBlockExtension)
  97. ((iPlatformBlockExtension)ptd.TrackBlock).Standon(gstate, this, false);
  98. }
  99. ptd.TrackBlock = null; //set to null to stop tracking if we were on a block.
  100. BCBlockGameState.Soundman.PlaySound("MARDEATHX");
  101. Velocity = new PointF(0, 0);
  102. GravityEffect = new PointF(0, 0);
  103. //set dead time
  104. DeadTime = DateTime.Now;
  105. //change state to DYING
  106. EnemyAction = "DYING";
  107. }
  108. return true;
  109. }
  110. protected override void hitside(BCBlockGameState gamestate, List<Block> hitblocks)
  111. {
  112. //do nothing.
  113. }
  114. private bool isonground { get { return onground || ongroundlastframe; } }
  115. public override CollideTypeConstants Collide(BCBlockGameState gstate, PlatformObject otherobject)
  116. {
  117. bool currreturn = false;
  118. foreach (GameCharacterAbility gca in _Abilities)
  119. {
  120. currreturn = gca.Collide(gstate,this, otherobject);
  121. }
  122. if (!currreturn) return base.Collide(gstate,otherobject);
  123. else return CollideTypeConstants.Collide_Nothing;
  124. }
  125. public override void Draw(Graphics g)
  126. {
  127. //save current draw properties.
  128. //call each powerups beforedraw routine.
  129. //draw.
  130. //reset draw properties.
  131. ImageAttributes cacheAttributes = DrawAttributes;
  132. if (_Abilities.Any())
  133. {
  134. foreach (GameCharacterAbility gma in _Abilities)
  135. {
  136. gma.BeforeDraw(this, g);
  137. }
  138. }
  139. base.Draw(g);
  140. DrawAttributes = cacheAttributes;
  141. }
  142. public override bool PerformFrame(BCBlockGameState gamestate)
  143. {
  144. if (_Abilities.Any())
  145. {
  146. List<GameCharacterAbility> addabilities = new List<GameCharacterAbility>();
  147. List<GameCharacterAbility> removeabilities = new List<GameCharacterAbility>();
  148. foreach (GameCharacterAbility gma in _Abilities)
  149. {
  150. if (gma.PerformFrame(this, gamestate))
  151. removeabilities.Add(gma);
  152. }
  153. foreach (var removeit in removeabilities)
  154. {
  155. Abilities.Remove(removeit);
  156. }
  157. foreach (var addit in addabilities)
  158. {
  159. Abilities.Add(addit);
  160. }
  161. }
  162. bool nobasecall = false;
  163. if (!flInit)
  164. {
  165. flInit = true;
  166. //hook the GameClient events...
  167. gamestate.ClientObject.ButtonDown += ClientObject_ButtonDown;
  168. gamestate.ClientObject.ButtonUp += ClientObject_ButtonUp;
  169. }
  170. if (EnemyAction == "DEATH") return base.PerformFrame(gamestate);
  171. if (EnemyAction == "DYING")
  172. {
  173. if (DateTime.Now - DeadTime.Value > new TimeSpan(0, 0, 0, 1))
  174. {
  175. EnemyAction = "DEATH";
  176. BCBlockGameState.Soundman.PlaySound("MARDEATH2");
  177. Velocity = new PointF(0, -4);
  178. _GravityEffect = new PointF(0, 8f);
  179. Nocollisions = true;
  180. nobasecall = true;
  181. }
  182. return base.PerformFrame(gamestate);
  183. }
  184. /* case Keys.W:
  185. return ButtonConstants.Button_E;
  186. case Keys.A:
  187. return ButtonConstants.Button_F;
  188. case Keys.S:
  189. return ButtonConstants.Button_G;
  190. case Keys.D:
  191. return ButtonConstants.Button_H;*/
  192. if (EnemyAction == "IDLELEFT" || EnemyAction == "IDLERIGHT")
  193. {
  194. if (Buttonspressed[ButtonConstants.Button_F])
  195. {
  196. EnemyAction = "WALKLEFT";
  197. }
  198. else if (Buttonspressed[ButtonConstants.Button_H])
  199. {
  200. EnemyAction = "WALKRIGHT";
  201. }
  202. }
  203. switch (EnemyAction)
  204. {
  205. case "IDLELEFT":
  206. if (!isonground) EnemyAction = "JUMPLEFT";
  207. break;
  208. case "IDLERIGHT":
  209. if (!isonground) EnemyAction = "JUMPRIGHT";
  210. break;
  211. case "JUMPLEFT":
  212. if (isonground)
  213. EnemyAction = "WALKLEFT";
  214. Decelerate();
  215. break;
  216. case "JUMPRIGHT":
  217. if (isonground)
  218. EnemyAction = "WALKRIGHT";
  219. Decelerate();
  220. break;
  221. case "WALKLEFT":
  222. Decelerate();
  223. if (Math.Abs(Velocity.X) < 0.1) EnemyAction = "IDLELEFT";
  224. if (!isonground) EnemyAction = "JUMPLEFT";
  225. break;
  226. case "WALKRIGHT":
  227. Decelerate();
  228. if (Math.Abs(Velocity.X) < 0.1) EnemyAction = "IDLERIGHT";
  229. if (!isonground) EnemyAction = "JUMPRIGHT";
  230. break;
  231. }
  232. //check for ball collisions.
  233. foreach (var loopball in gamestate.Balls)
  234. {
  235. Polygon ppoly = loopball.GetBallPoly();
  236. Polygon boundbox = new Polygon(this.GetRectangleF());
  237. var result = GeometryHelper.PolygonCollision(ppoly, boundbox, new Vector(0, 0));
  238. if (result.Intersect)
  239. {
  240. Die(gamestate);
  241. break;
  242. }
  243. }
  244. if (!nobasecall) return base.PerformFrame(gamestate); else return false;
  245. }
  246. private void Decelerate()
  247. {
  248. Decelerate(false);
  249. }
  250. private float maxXSpeed = 7;
  251. /// <summary>
  252. /// managed acceleration/deceleration when keys are pressed/unpressed.
  253. /// </summary>
  254. /// <param name="fast"></param>
  255. private void Decelerate(bool fast)
  256. {
  257. float reductionfactor = fast ? 0.6f : 0.9f;
  258. //decelerate.
  259. //if idle and a button is pressed, change state to that direction walking.
  260. if (_EnemyState == "IDLELEFT" || _EnemyState == "WALKLEFT" || _EnemyState == "JUMPLEFT")
  261. {
  262. if (Buttonspressed[ButtonConstants.Button_H])
  263. {
  264. if (Math.Abs(Velocity.X) < 0.1f)
  265. {
  266. _EnemyState = _EnemyState.Replace("LEFT", "RIGHT");
  267. //swap to right facing...
  268. }
  269. else
  270. {
  271. reductionfactor = 0.6f;
  272. }
  273. }
  274. if ((!Buttonspressed[ButtonConstants.Button_F]))
  275. {
  276. Velocity = new PointF(Velocity.X * reductionfactor, Velocity.Y);
  277. if (Math.Abs(Velocity.X) < 0.5) Velocity = new PointF(0, Velocity.Y);
  278. }
  279. else
  280. {
  281. //if it is pressed, increase to a maximum.
  282. if (Math.Abs(Velocity.X) < maxXSpeed)
  283. {
  284. Velocity = new PointF(Velocity.X - 0.4f, Velocity.Y);
  285. }
  286. }
  287. }
  288. else if (_EnemyState == "IDLERIGHT" || _EnemyState == "WALKRIGHT" || _EnemyState == "JUMPRIGHT")
  289. {
  290. if (Buttonspressed[ButtonConstants.Button_F])
  291. {
  292. if (Velocity.X < 0.1f)
  293. {
  294. _EnemyState = _EnemyState.Replace("RIGHT", "LEFT");
  295. //swap to Left facing...
  296. }
  297. else
  298. {
  299. reductionfactor = 0.6f;
  300. }
  301. }
  302. if ((!Buttonspressed[ButtonConstants.Button_H]))
  303. {
  304. Velocity = new PointF(Velocity.X * reductionfactor, Velocity.Y);
  305. if (Math.Abs(Velocity.X) < 0.5) Velocity = new PointF(0, Velocity.Y);
  306. }
  307. else
  308. {
  309. if (Math.Abs(Velocity.X) < maxXSpeed)
  310. {
  311. Velocity = new PointF(Velocity.X + 0.4f, Velocity.Y);
  312. }
  313. }
  314. }
  315. }
  316. private Dictionary<ButtonConstants, bool> Buttonspressed = new Dictionary<ButtonConstants, bool>();
  317. void ClientObject_ButtonUp(Object sender,ButtonEventArgs<bool> e )
  318. {
  319. Buttonspressed[e.Button] = false;
  320. if (e.Button == ButtonConstants.Button_A)
  321. {
  322. //GravityEffect = new PointF(0, 1f);
  323. }
  324. e.Result = true;
  325. }
  326. public override void TouchLeft(BCBlockGameState gamestate, List<Block> touched, Block mainblock)
  327. {
  328. Velocity = new PointF(0, Velocity.Y);
  329. }
  330. public override void TouchRight(BCBlockGameState gamestate, List<Block> touched, Block mainblock)
  331. {
  332. Velocity = new PointF(0, Velocity.Y);
  333. }
  334. protected override void TouchLevelSide(BCBlockGameState gamestate, ref List<GameObject> Addobjects, ref List<GameObject> removeobjects, bool LeftSide)
  335. {
  336. Velocity = new PointF(0, Velocity.Y);
  337. //base.TouchLevelSide(gamestate, ref Addobjects, ref removeobjects, LeftSide);
  338. }
  339. public override bool TouchPaddle(BCBlockGameState gamestate, Paddle PlayerPaddle)
  340. {
  341. Velocity = new PointF(Velocity.X, 0);
  342. /*if (EnemyAction == "JUMPLEFT" || EnemyAction == "JUMPRIGHT")
  343. EnemyAction = EnemyAction.Replace("JUMP", "IDLE");*/
  344. return false;
  345. }
  346. public override void TouchTop(BCBlockGameState gamestate, List<Block> touched, Block mainblock)
  347. {
  348. Velocity = new PointF(Velocity.X, Math.Abs(Velocity.Y * 0.5f));
  349. Block smackit = touched.First();
  350. BCBlockGameState.Block_Hit(gamestate, smackit, Velocity); //smack it with the player's velocity.
  351. gamestate.Forcerefresh = true;
  352. gamestate.Defer(() => gamestate.Forcerefresh = true);
  353. }
  354. protected override void standingon(BCBlockGameState gamestate, List<Block> standingon, Block Mainblock)
  355. {
  356. onground = true;
  357. }
  358. /* case Keys.W:
  359. return ButtonConstants.Button_E;
  360. case Keys.A:
  361. return ButtonConstants.Button_F;
  362. case Keys.S:
  363. return ButtonConstants.Button_G;
  364. case Keys.D:
  365. return ButtonConstants.Button_H; */
  366. void ClientObject_ButtonDown(Object sender,ButtonEventArgs<bool> e)
  367. {
  368. lock (this)
  369. {
  370. Buttonspressed[e.Button] = true;
  371. if (_EnemyState == "DYING" || _EnemyState == "DEATH") { e.Result = false; return; }
  372. if (e.Button == ButtonConstants.Button_D)
  373. {
  374. //GravityEffect = new PointF(0, 0.5f);
  375. //jump...
  376. if (_EnemyState != "JUMPLEFT" && _EnemyState != "JUMPRIGHT" && _EnemyState != "DYING" && _EnemyState != "DEATH")
  377. {
  378. if (_EnemyState == "IDLELEFT" || _EnemyState == "WALKLEFT")
  379. _EnemyState = "JUMPLEFT";
  380. else if (_EnemyState == "IDLERIGHT" || _EnemyState == "WALKRIGHT")
  381. _EnemyState = "JUMPRIGHT";
  382. BCBlockGameState.Soundman.PlaySound("SMBJUMP");
  383. Velocity = new PointF(Velocity.X, -8 - (Math.Abs(Velocity.X / 3))); //jump!
  384. Location = new PointF(Location.X, Location.Y - 3);
  385. onground = false;
  386. ongroundlastframe = false; //we need to set these otherwise jumping would suck.
  387. }
  388. }
  389. }
  390. e.Result = true;
  391. return;
  392. }
  393. public override float GetGroundOffset()
  394. {
  395. return 3;
  396. }
  397. }
  398. //analogous to the coins in Mario
  399. public class macGuffinpowerup : GameCharacterPowerup
  400. {
  401. static String addedkey = "";
  402. static readonly TimeSpan Poptime = new TimeSpan(0, 0, 0, 0,500);
  403. private GameStopwatch gsw = null;
  404. private static String getOrbKey()
  405. {
  406. if (addedkey == "")
  407. {
  408. addedkey = "ORB";
  409. BCBlockGameState.Imageman.AddImage(addedkey, BCBlockGameState.GetSphereImage(Color.Blue,new Size(10,10)));
  410. }
  411. return addedkey;
  412. }
  413. public override string GetEmergeSound()
  414. {
  415. return "COIN";
  416. }
  417. public override void Bump(Block bumpedby)
  418. {
  419. return;
  420. }
  421. public override void TouchTop(BCBlockGameState gamestate, List<Block> touched, Block mainblock)
  422. {
  423. return;
  424. }
  425. public override void TouchLeft(BCBlockGameState gamestate, List<Block> touched, Block mainblock)
  426. {
  427. return;
  428. }
  429. public override void TouchRight(BCBlockGameState gamestate, List<Block> touched, Block mainblock)
  430. {
  431. return;
  432. }
  433. protected override void TouchLevelSide(BCBlockGameState gamestate, ref List<GameObject> Addobjects, ref List<GameObject> removeobjects, bool LeftSide)
  434. {
  435. return;
  436. }
  437. protected override void standingon(BCBlockGameState gamestate, List<Block> standingon, Block Mainblock)
  438. {
  439. return;
  440. }
  441. public macGuffinpowerup(Block EmergeFrom):base(EmergeFrom,getOrbKey(),20)
  442. {
  443. Emerging = false;
  444. GravityEffect = new PointF(0, 2);
  445. Velocity = new PointF(0, -5);
  446. DrawSize = new SizeF(10, 10);
  447. Location = new PointF(EmergeFrom.CenterPoint().X-DrawSize.Width/2,EmergeFrom.BlockRectangle.Top-DrawSize.Height);
  448. }
  449. public override bool GivePowerTo(BCBlockGameState gamestate, GameCharacter gamechar)
  450. {
  451. return false;
  452. }
  453. private Particle Defaultemitterroutine(BCBlockGameState gstate, EmitterParticle source, int framenum, int ttl)
  454. {
  455. FireParticle p = new FireParticle(new PointF(source.Location.X, source.Location.Y));
  456. p.TTL = 60;
  457. p.Velocity = BCBlockGameState.GetRandomVelocity(0, 2);
  458. return p;
  459. }
  460. public override bool Powerup_PerformFrame(BCBlockGameState gamestate)
  461. {
  462. GravityEffect = new PointF(0, 0);
  463. if (gsw == null) gsw = new GameStopwatch(gamestate);
  464. //throw new NotImplementedException();
  465. //Location = new PointF(Location.X + Velocity.X, Location.Y + Velocity.Y);
  466. //get current time...
  467. long elapsedticks = gsw.Elapsed.Ticks;
  468. long lengthticks = Poptime.Ticks;
  469. //first, if our time is up, we're done.
  470. if (elapsedticks > lengthticks || Math.Abs(Velocity.Y) < 0.1f)
  471. {
  472. //spawn some particles.
  473. for (int i = 0; i < 10; i++)
  474. {
  475. EmitterParticle createdemitter = new EmitterParticle(this.GetRectangleF().CenterPoint(), Defaultemitterroutine);
  476. createdemitter.Velocity = BCBlockGameState.GetRandomVelocity(0, 5);
  477. gamestate.Particles.Add(createdemitter);
  478. }
  479. gamestate.SpawnOrbs(45, GetRectangleF().CenterPoint(), typeof(MacGuffinOrb));
  480. gamestate.NextFrameCalls.Enqueue(new BCBlockGameState.NextFrameStartup(() => gamestate.GameObjects.Remove(this)));
  481. return true; //destroy us NAU...
  482. }
  483. else
  484. {
  485. //get percentage through...
  486. float percentcomplete = ((float)elapsedticks) / ((float)lengthticks);
  487. //set velocity.Y to -(1-Sin(percentcomplete)...
  488. //Velocity = new PointF(Velocity.X, -2*(float)(Math.Abs(1 - Math.Sin(percentcomplete))));
  489. if(Velocity.Y < 0)
  490. Velocity = new PointF(Velocity.X, Velocity.Y +0.5f);
  491. Debug.Print("percentage through:" + percentcomplete + Velocity);
  492. }
  493. Debug.Print("Velocity is " + Velocity);
  494. return false;
  495. }
  496. }
  497. public class InvinciblePowerup : GameCharacterPowerup
  498. {
  499. public InvinciblePowerup(Block EmergeFrom)
  500. : base(EmergeFrom, BCBlockGameState.Imageman.getImageFramesString("vc"), 3)
  501. {
  502. GravityEffect = new PointF(0, 30f);
  503. }
  504. public InvinciblePowerup(PointF pPosition, SizeF psize)
  505. : base(pPosition, new PointF(1, -3), BCBlockGameState.Imageman.getImageFramesString("vc"), 3)
  506. {
  507. GravityEffect = new PointF(0, 30f);
  508. }
  509. public override void EmergeComplete(Block EmergedFrom, BCBlockGameState gstate)
  510. {
  511. Velocity = new PointF(0.75f, -2f);
  512. }
  513. public override bool GivePowerTo(BCBlockGameState gamestate, GameCharacter gamechar)
  514. {
  515. bool founditem = false;
  516. foreach (GameCharacterAbility gca in gamechar.Abilities)
  517. {
  518. if (gca is InvinciblePowerupAbility)
  519. {
  520. InvinciblePowerupAbility ipa = gca as InvinciblePowerupAbility;
  521. ipa.AbilityStart = DateTime.Now; //reset.
  522. ipa.ChangeDelayTime(gamestate, gamestate.GetDelayData(ipa.DelayIdentifier).waitdelay,true);
  523. founditem = true;
  524. break;
  525. }
  526. }
  527. if (!founditem)
  528. {
  529. //if there is no invincible powerup, we add it.
  530. InvinciblePowerupAbility newpower = new InvinciblePowerupAbility();
  531. gamechar.Abilities.Add(newpower);
  532. }
  533. BCBlockGameState.Soundman.PlaySound("grow");
  534. Block.AddScore(gamestate, 1000, Location);
  535. return true;
  536. }
  537. public override bool Powerup_PerformFrame(BCBlockGameState gamestate)
  538. {
  539. Random rg = BCBlockGameState.rgen;
  540. Color usecolor = new HSLColor(BCBlockGameState.rgen.NextDouble() * 240, 240, 120);
  541. //select a random position.
  542. RectangleF baserect = GetRectangleF();
  543. PointF randompos = new PointF(baserect.Left + (float)(baserect.Width * rg.NextDouble()), baserect.Top + (float)(baserect.Height * rg.NextDouble()));
  544. PointF RandomVelocity = new PointF((float)rg.NextDouble() * 0.5f - 0.25f, (float)rg.NextDouble() * 0.5f - 0.25f);
  545. Sparkle sp = new Sparkle(randompos, RandomVelocity, usecolor);
  546. sp.MaxRadius = (float)(1 + rg.NextDouble() * 4);
  547. gamestate.Particles.Add(sp);
  548. return false;
  549. }
  550. public override void TouchTop(BCBlockGameState gamestate, List<Block> touched, Block mainblock)
  551. {
  552. base.TouchTop(gamestate, touched, mainblock);
  553. }
  554. protected override void standingon(BCBlockGameState gamestate, List<Block> standingon, Block Mainblock)
  555. {
  556. onground = false;
  557. ongroundlastframe = false;
  558. Location = new PointF(Location.X, Location.Y - 4);
  559. Velocity = new PointF(Velocity.X, -4);
  560. }
  561. }
  562. /// <summary>
  563. /// abstract class, gives GameCharacter an ability when touched.
  564. /// </summary>
  565. /*
  566. public abstract class CharacterAbilityPowerup : GameCharacterPowerup
  567. {
  568. private Type _PowerupAbilityType = null;
  569. protected CharacterAbilityPowerup(Block EmergeFrom, Dictionary<String, String[]> pStateFrameData, int pFrameDelay,Type pPowerupAbilityType)
  570. : base(EmergeFrom, pStateFrameData, pFrameDelay)
  571. {
  572. if (!pPowerupAbilityType.IsSubclassOf(typeof(GameCharacterAbility)))
  573. throw new ArgumentException("Argument must be a subclass of BASeBlock.GameCharacterAbility", "PowerupAbilityType");
  574. _PowerupAbilityType = pPowerupAbilityType;
  575. }
  576. protected CharacterAbilityPowerup(Block EmergeFrom, String[] StateFrameData, int pFrameDelay, Type pPowerupAbility)
  577. : this(EmergeFrom, new Dictionary<string, string[]>() { { "IDLE", StateFrameData } }, pFrameDelay, pPowerupAbility)
  578. {
  579. }
  580. protected CharacterAbilityPowerup(Block EmergeFrom, String StateFrameData, int pFrameDelay, Type pPowerupAbility)
  581. : this(EmergeFrom, new string[] { StateFrameData }, pFrameDelay, pPowerupAbility)
  582. {
  583. }
  584. }
  585. */
  586. public class ExtraLifeItem : GameCharacterPowerup
  587. {
  588. //Extra life item collectable by gamecharacter.
  589. private static ImageAttributes extralifedraw()
  590. {
  591. ImageAttributes dAttrib = new ImageAttributes();
  592. dAttrib.SetColorMatrix(ColorMatrices.GetColourizer(Color.Lime));
  593. return dAttrib;
  594. }
  595. public ExtraLifeItem(Block EmergeFrom)
  596. : base(EmergeFrom, "Mushroom", 2,extralifedraw())
  597. {
  598. }
  599. public ExtraLifeItem(PointF pPosition, SizeF psize)
  600. :base(pPosition,new PointF(2,0),new string[] { "Mushroom"},2,extralifedraw())
  601. {
  602. useSize = psize;
  603. }
  604. public override bool GivePowerTo(BCBlockGameState gamestate, GameCharacter gamechar)
  605. {
  606. BCBlockGameState.Soundman.PlaySound("1up");
  607. BasicFadingText bft = new BasicFadingText("1-Up", Location, new PointF(0, -2), new Font(BCBlockGameState.GetMonospaceFont(), 14), new Pen(Color.Black,2), new SolidBrush(Color.Green), 500);
  608. gamestate.playerLives++;
  609. gamestate.Forcerefresh = true;
  610. gamestate.Defer(() => gamestate.GameObjects.AddLast(bft));
  611. return true;
  612. }
  613. public override bool Powerup_PerformFrame(BCBlockGameState gamestate)
  614. {
  615. return false;
  616. }
  617. }
  618. public class MushroomPower : GameCharacterPowerup
  619. {
  620. public MushroomPower(Block EmergeFrom)
  621. : base(EmergeFrom, "Mushroom", 2)
  622. {
  623. }
  624. public MushroomPower(PointF pPosition, SizeF psize)
  625. : base(pPosition, new PointF(2, 0), new string[] { "Mushroom" }, 0)
  626. {
  627. useSize = psize;
  628. }
  629. public override void Bump(Block bumpedby)
  630. {
  631. base.Bump(bumpedby);
  632. onground = false;
  633. ongroundlastframe = false;
  634. Velocity = new PointF(Velocity.X, -5);
  635. }
  636. public override bool GivePowerTo(BCBlockGameState gamestate, GameCharacter gamechar)
  637. {
  638. BCBlockGameState.Soundman.PlaySound("grow");
  639. Block.AddScore(gamestate, 1000, Location);
  640. return true;
  641. }
  642. public override bool Powerup_PerformFrame(BCBlockGameState gamestate)
  643. {
  644. //nuttin
  645. return false;
  646. }
  647. }
  648. /// <summary>
  649. /// used to indicate a GameCharacterPowerup that does not "emerge".
  650. /// </summary>
  651. public class NoEmergePowerupAttribute : Attribute
  652. {
  653. }
  654. /// <summary>
  655. /// abstract base class for powerups and items acquirable by the GameCharacter.
  656. /// </summary>
  657. public abstract class GameCharacterPowerup : PlatformObject
  658. {
  659. protected Block EmergingFrom = null; //block this powerup is emerging from.
  660. protected bool Emerging = false;
  661. //moar constructor overloads...
  662. protected GameCharacterPowerup(Block EmergeFrom, String ImageFrame, int pFrameDelay)
  663. : this(EmergeFrom, ImageFrame, pFrameDelay, new ImageAttributes())
  664. {
  665. }
  666. protected GameCharacterPowerup(Block EmergeFrom, String ImageFrame, int pFrameDelay, ImageAttributes puseattributes)
  667. : this(EmergeFrom, new string[] { ImageFrame }, pFrameDelay, puseattributes)
  668. {
  669. }
  670. protected GameCharacterPowerup(Block EmergeFrom, String[] ImageFrames, int pFrameDelay) :
  671. this(EmergeFrom, ImageFrames, pFrameDelay, new ImageAttributes())
  672. {
  673. }
  674. /// <summary>
  675. /// Creates a powerup emerging from a block. set of imageframes will be set to the "idle" state
  676. /// </summary>
  677. /// <param name="EmergeFrom"></param>
  678. /// <param name="ImageFrames"></param>
  679. /// <param name="pFrameDelay"></param>
  680. /// <param name="puseattributes"></param>
  681. protected GameCharacterPowerup(Block EmergeFrom, String[] ImageFrames, int pFrameDelay, ImageAttributes puseattributes)
  682. : this(EmergeFrom, new Dictionary<string, string[]>() { { "IDLE", ImageFrames } }, pFrameDelay, puseattributes)
  683. {
  684. }
  685. protected GameCharacterPowerup(Block EmergeFrom, Dictionary<String, String[]> pStateFrameData, int pFrameDelay)
  686. : this(EmergeFrom, pStateFrameData, pFrameDelay, new ImageAttributes())
  687. {
  688. }
  689. protected GameCharacterPowerup(Block EmergeFrom, Dictionary<String, String[]> pStateFrameData, int pFrameDelay, ImageAttributes puseattributes)
  690. : base(EmergeFrom.CenterPoint(), new PointF(0, 0), pStateFrameData, pFrameDelay, puseattributes)
  691. {
  692. //set starting position to emerge from the center of the block.
  693. EnemyAction = "IDLE";
  694. //Image gotimage = base.GetCurrentImage();
  695. SizeF grabsize = DrawSize;
  696. int Xcoord = (int)(EmergeFrom.CenterPoint().X - (grabsize.Width / 2));
  697. int Ycoord = (int)(EmergeFrom.BlockRectangle.Top);
  698. Location = new PointF(Xcoord, Ycoord);
  699. Emerging = true;
  700. EmergingFrom = EmergeFrom;
  701. }
  702. public virtual String GetEmergeSound()
  703. {
  704. return "EMERGE";
  705. }
  706. protected GameCharacterPowerup(PointF pPosition, PointF pVelocity, Dictionary<String, String[]> pStateFrameData, int pFrameDelay, ImageAttributes puseattributes)
  707. : base(pPosition, pVelocity, pStateFrameData, pFrameDelay, puseattributes)
  708. {
  709. }
  710. protected GameCharacterPowerup(PointF pPosition, PointF pVelocity, Dictionary<String, String[]> pStateFrameData, int pFrameDelay) :
  711. base(pPosition, pVelocity, pStateFrameData, pFrameDelay, new ImageAttributes())
  712. {
  713. }
  714. private static Dictionary<String, String[]> Powerupstateframedata(String[] powerframes)
  715. {
  716. return new Dictionary<string, string[]> { { "IDLE", powerframes } };
  717. }
  718. protected GameCharacterPowerup(PointF pPosition, PointF pVelocity, String powerupimagekey, int pFrameDelay, ImageAttributes puseattributes)
  719. : this(pPosition, pVelocity, Powerupstateframedata(new string[] { powerupimagekey }), pFrameDelay, puseattributes)
  720. {
  721. }
  722. protected GameCharacterPowerup(PointF pPosition, PointF pVelocity, String[] PowerupFrames, int pFrameDelay)
  723. : this(pPosition, pVelocity, PowerupFrames, pFrameDelay, new ImageAttributes())
  724. {
  725. }
  726. protected GameCharacterPowerup(PointF pPosition, PointF pVelocity, String[] PowerupFrames, int pFrameDelay, ImageAttributes puseattributes)
  727. : this(pPosition, pVelocity, Powerupstateframedata(PowerupFrames), pFrameDelay, puseattributes)
  728. {
  729. EnemyAction = "IDLE";
  730. }
  731. public abstract bool GivePowerTo(BCBlockGameState gamestate, GameCharacter gamechar);
  732. public abstract bool Powerup_PerformFrame(BCBlockGameState gamestate);
  733. public override void TouchTop(BCBlockGameState gamestate, List<Block> touched, Block mainblock)
  734. {
  735. Velocity = new PointF(Velocity.X, Math.Abs(Velocity.Y));
  736. //base.TouchTop(gamestate, ref AddObjects, ref removeobjects, touched, mainblock);
  737. }
  738. public sealed override void Draw(Graphics g)
  739. {
  740. //set clip so we only appear above the block.
  741. //this was changed from previously where we set the clip to the bounds of the block itself,
  742. //meaning that smaller blocks would show the powerup through the sides.
  743. var copiedclip = g.Clip;
  744. if (EmergingFrom != null && Emerging)
  745. {
  746. g.SetClip(EmergingFrom.BlockRectangle, CombineMode.Exclude);
  747. //RectangleF setrect = new RectangleF(float.MinValue, EmergingFrom.BlockRectangle.Top, float.MaxValue, float.MaxValue);
  748. //g.SetClip(setrect, CombineMode.Exclude);
  749. }
  750. base.Draw(g);
  751. //if (Emerging) EmergingFrom.Draw(g); //make sure the block draws "on top" of us.
  752. //reset the clip
  753. if (EmergingFrom != null && Emerging) g.SetClip(copiedclip, CombineMode.Replace);
  754. }
  755. public virtual void DrawPowerup(Graphics g)
  756. {
  757. }
  758. public override sealed bool PerformFrame(BCBlockGameState gamestate)
  759. {
  760. Rectangle ourrect = this.GetRectangle();
  761. if (!Emerging)
  762. {
  763. foreach (GameCharacter gamechar in
  764. (from m in gamestate.GameObjects
  765. where
  766. m is GameCharacter &&
  767. !(new String[] { "DYING", "DEATH" }.Contains(((GameCharacter)m).EnemyAction.ToUpper()))
  768. select m))
  769. {
  770. //only give power to living GameCharacters...
  771. Rectangle gamecharrect = gamechar.GetRectangle();
  772. if (ourrect.IntersectsWith(gamecharrect))
  773. {
  774. //intersection...
  775. return gamechar.GetPowerup(gamestate, this);
  776. }
  777. }
  778. //if we are emerging, handle that stuff ourselves and return false.
  779. //otherwise, return the result of PowerUp_PerformFrame || base.PerformFrame.
  780. }
  781. else
  782. {
  783. //move us up a bit
  784. Location = new PointF(Location.X, Location.Y - 2);
  785. //if we are clear of the block, disable the Emerging flag
  786. //the Location check is to ensure that we don't pop out the bottom of the block is smaller than the powerup.
  787. if (Location.Y < EmergingFrom.BlockRectangle.Top && !(EmergingFrom.BlockRectangle.IntersectsWith(GetRectangleF())))
  788. {
  789. Emerging = false;
  790. //call virtual method
  791. EmergeComplete(EmergingFrom, gamestate);
  792. }
  793. return false; //DON'T perform default processing, otherwise it will move the powerup via gravity and stuff and we may never emerge at all.
  794. }
  795. //only call default if it returns true...
  796. if(!Powerup_PerformFrame(gamestate))
  797. return base.PerformFrame(gamestate);
  798. else
  799. {
  800. return true;
  801. }
  802. }
  803. public override CollideTypeConstants Collide(BCBlockGameState gstate, PlatformObject otherobject)
  804. {
  805. return CollideTypeConstants.Collide_Nothing; //nuffin happens.
  806. }
  807. public virtual void EmergeComplete(Block EmergedFrom, BCBlockGameState gstate)
  808. {
  809. //set standard speed.
  810. Velocity = new PointF(3, 0);
  811. }
  812. }
  813. public abstract class GameCharacterAbility
  814. {
  815. //abstract base class for the abilities givable to the character.
  816. //typically a powerup gives the game character an ability.
  817. bool flInit = false;
  818. /// <summary>
  819. /// return true to remove this ability from the character.
  820. /// </summary>
  821. /// <param name="gamechar"></param>
  822. /// <param name="gstatem"></param>
  823. /// <returns></returns>
  824. public bool PerformFrame(GameCharacter gamechar, BCBlockGameState gstatem)
  825. {
  826. if (!flInit)
  827. {
  828. flInit = true;
  829. AbilityInit(gamechar, gstatem);
  830. }
  831. return AbilityFrame(gamechar, gstatem);
  832. }
  833. public abstract void AbilityInit(GameCharacter gamechar, BCBlockGameState gstatem);
  834. public virtual void BeforeDraw(GameCharacter gamechar, Graphics g)
  835. {
  836. //nothing.... well, by default nothing.
  837. }
  838. /// <summary>
  839. /// Called during the gamecharacter frame for each ability.
  840. /// </summary>
  841. /// <param name="gamechar"></param>
  842. /// <param name="gstatem"></param>
  843. /// <returns>true to remove this ability. False otherwise.</returns>
  844. public abstract bool AbilityFrame(GameCharacter gamechar, BCBlockGameState gstatem);
  845. /// <summary>
  846. /// called when gamecharacter collides with a platformobject.
  847. /// </summary>
  848. /// <param name="gstate"></param>
  849. /// <param name="gamechar"></param>
  850. /// <param name="otherobject"></param>
  851. /// <returns>false to continue default processing. true to return immediately without default processing.</returns>
  852. public abstract bool Collide(BCBlockGameState gstate, GameCharacter gamechar, PlatformObject otherobject);
  853. }
  854. /// <summary>
  855. /// subclass of GameCharacterAbility adding timing constraints.
  856. /// </summary>
  857. public abstract class TimedCharacterAbility : GameCharacterAbility
  858. {
  859. private static readonly TimeSpan defaultduration = new TimeSpan(0, 0, 0, 10);
  860. private DateTime _AbilityStart;
  861. private TimeSpan _Duration = defaultduration; //10 second default.
  862. private String _AbilityMusic = ""; //music to use; null or empty to not affect music.
  863. public DateTime AbilityStart { get { return _AbilityStart; } set {
  864. _AbilityStart = value;
  865. } }
  866. public String AbilityMusic { get { return _AbilityMusic; } set { _AbilityMusic = value; } }
  867. protected TimedCharacterAbility()
  868. : this(defaultduration)
  869. {
  870. }
  871. protected TimedCharacterAbility(TimeSpan Duration)
  872. : this(Duration, "")
  873. {
  874. }
  875. protected TimedCharacterAbility(TimeSpan Duration,String pAbilityMusic)
  876. {
  877. _Duration = Duration;
  878. _AbilityMusic = pAbilityMusic;
  879. }
  880. protected TimedCharacterAbility(String pAbilityMusic):this(defaultduration,pAbilityMusic)
  881. {
  882. }
  883. public String DelayIdentifier = null;
  884. public override void AbilityInit(GameCharacter gamechar, BCBlockGameState gstatem)
  885. {
  886. gamechar.OnDeath += gamechar_OnDeath;
  887. DelayIdentifier = gstatem.DelayInvoke(_Duration, revertroutinefunc, new object[] { gamechar, gstatem });
  888. AbilityStart = DateTime.Now;
  889. if (!String.IsNullOrEmpty(_AbilityMusic))
  890. //BCBlockGameState.Soundman.PushMusic(_AbilityMusic, 1.0f, true);
  891. BCBlockGameState.Soundman.PlayTemporaryMusic(_AbilityMusic, 1.0f, true);
  892. }
  893. public bool ChangeDelayTime(BCBlockGameState gstate,TimeSpan newdelay,bool resetstart)
  894. {
  895. return gstate.ChangeDelayData(DelayIdentifier, newdelay, null,resetstart);
  896. }
  897. public void revertroutinefunc(object[] parameters)
  898. {
  899. BCBlockGameState grabstate = (BCBlockGameState)parameters[1];
  900. GameCharacter gamechar = (GameCharacter)parameters[0];
  901. List<GameObject> objectsadd = new List<GameObject>();
  902. List<GameObject> objectsremove = new List<GameObject>();
  903. List<GameCharacterAbility> addabilities = new List<GameCharacterAbility>();
  904. AbilityEnd(gamechar, grabstate, ref objectsadd, ref objectsremove, ref addabilities);
  905. foreach (var iterate in objectsadd)
  906. grabstate.GameObjects.AddLast(iterate);
  907. foreach (var iterate in objectsremove)
  908. grabstate.GameObjects.Remove(iterate);
  909. foreach (var iterate in addabilities)
  910. gamechar.Abilities.Add(iterate);
  911. }
  912. void gamechar_OnDeath(Object sender,EnemyDeathEventArgs e)
  913. {
  914. //reset the music.
  915. if (!String.IsNullOrEmpty(_AbilityMusic))
  916. //BCBlockGameState.Soundman.PopMusic(_AbilityMusic);
  917. BCBlockGameState.Soundman.StopTemporaryMusic(_AbilityMusic);
  918. }
  919. bool AbilityEnded = false;
  920. public virtual void AbilityEnd(GameCharacter gamechar, BCBlockGameState gstate, ref List<GameObject> addobjects, ref List<GameObject> removeobjects, ref List<GameCharacterAbility> addabilities)
  921. {
  922. //called when ability is "over"
  923. // BCBlockGameState.Soundman.PopMusic(_AbilityMusic);
  924. AbilityEnded = true;
  925. BCBlockGameState.Soundman.StopTemporaryMusic(_AbilityMusic);
  926. }
  927. public override bool AbilityFrame(GameCharacter gamechar, BCBlockGameState gstatem)
  928. {
  929. /*
  930. if ((DateTime.Now - AbilityStart) > _Duration)
  931. {
  932. AbilityEnd(gamechar, gstatem, ref addobjects, ref removeobjects, ref addabilities);
  933. return true;
  934. }
  935. */
  936. return AbilityEnded;
  937. }
  938. }
  939. public class InvinciblePowerupAbility : TimedCharacterAbility
  940. {
  941. private static ImageAttributes IAfromCM(ColorMatrix frommatrix)
  942. {
  943. ImageAttributes ia = new ImageAttributes();
  944. ia.SetColorMatrix(frommatrix);
  945. return ia;
  946. }
  947. private static ImageAttributes[] CreateDrawAttributes()
  948. {
  949. return new ImageAttributes[] {
  950. IAfromCM(ColorMatrices.GetColourizer(Color.Red)),
  951. IAfromCM(ColorMatrices.GetColourizer(Color.Green)),
  952. IAfromCM(ColorMatrices.GetColourizer(Color.Blue)),
  953. IAfromCM(ColorMatrices.GetColourizer(Color.Violet)),
  954. IAfromCM(ColorMatrices.GetColourizer(Color.Orange)),
  955. IAfromCM(ColorMatrices.GetColourizer(Color.Purple)),
  956. IAfromCM(ColorMatrices.GetColourizer(Color.Brown)),
  957. IAfromCM(ColorMatrices.GetColourizer(Color.Yellow))
  958. };
  959. }
  960. private static ImageAttributes[] useDrawAttributes = CreateDrawAttributes();
  961. public InvinciblePowerupAbility(TimeSpan Duration, String Music):base(Duration,Music)
  962. {
  963. }
  964. public InvinciblePowerupAbility()
  965. : base("INVINCIBLE")
  966. {
  967. }
  968. /// <summary>
  969. /// called when gamecharacter collides with a platformobject.
  970. /// </summary>
  971. /// <param name="gstate"></param>
  972. /// <param name="gamechar"></param>
  973. /// <param name="otherobject"></param>
  974. /// <returns>false to continue default processing. true to return immediately without default processing.</returns>
  975. public override bool Collide(BCBlockGameState gstate, GameCharacter gamechar, PlatformObject otherobject)
  976. {
  977. //kill the other object, and leave us unaffected.
  978. //but- only for types deriving from PlatformEnemy
  979. if(otherobject is PlatformEnemy)
  980. {
  981. otherobject.Kill();
  982. return true;
  983. }
  984. return false; //default processing...
  985. }
  986. ImageAttributes cached = null;
  987. public override void AbilityInit(GameCharacter gamechar, BCBlockGameState gstatem)
  988. {
  989. base.AbilityInit(gamechar, gstatem);
  990. //cached = gamechar.DrawAttributes;
  991. }
  992. public override void AbilityEnd(GameCharacter gamechar, BCBlockGameState gstate, ref List<GameObject> addobjects, ref List<GameObject> removeobjects, ref List<GameCharacterAbility> addabilities)
  993. {
  994. base.AbilityEnd(gamechar, gstate, ref addobjects, ref removeobjects, ref addabilities);
  995. //gamechar.DrawAttributes = cached;
  996. }
  997. public override void BeforeDraw(GameCharacter gamechar, Graphics g)
  998. {
  999. gamechar.DrawAttributes = usetheseattributes;
  1000. base.BeforeDraw(gamechar, g);
  1001. }
  1002. ImageAttributes usetheseattributes = null;
  1003. int delayfactor = 2;
  1004. int delayvalue = 0;
  1005. public override bool AbilityFrame(GameCharacter gamechar, BCBlockGameState gstatem)
  1006. {
  1007. delayvalue++;
  1008. if (delayvalue == delayfactor)
  1009. {
  1010. usetheseattributes = BCBlockGameState.Choose(useDrawAttributes);
  1011. delayvalue = 0;
  1012. }
  1013. //also spawn a sparkly. One sparkley per frame.
  1014. //choose a random colour...
  1015. Random rg = BCBlockGameState.rgen;
  1016. Color usecolor = new HSLColor(BCBlockGameState.rgen.NextDouble()*240, 240, 120);
  1017. //select a random position.
  1018. RectangleF baserect = gamechar.GetRectangleF();
  1019. PointF randompos = new PointF(baserect.Left + (float)(baserect.Width * rg.NextDouble()), baserect.Top + (float)(baserect.Height * rg.NextDouble()));
  1020. PointF RandomVelocity = new PointF((float)rg.NextDouble()*0.5f-0.25f,(float)rg.NextDouble()*0.5f-0.25f);
  1021. Sparkle sp = new Sparkle(randompos, RandomVelocity, usecolor);
  1022. sp.MaxRadius = 5;
  1023. gstatem.Particles.Add(sp);
  1024. return base.AbilityFrame(gamechar, gstatem);
  1025. }
  1026. }
  1027. }