From d7a34fb5e1d65d186c0459c8ba433c8320829ba1 Mon Sep 17 00:00:00 2001 From: Payl <140975567+Paylicier@users.noreply.github.com> Date: Tue, 17 Dec 2024 05:37:19 +0100 Subject: [PATCH] Cube Castle (#2683) * CubeCastle a simple platformer game * Add image for CubeCastle * Cube Castle Update 1.0.1 small bug fixes * CubeCastle | Fix tag formats * Fix tags * Fix code filename * Fix image filename --------- Co-authored-by: Gus Ruben <95830851+gusruben@users.noreply.github.com> --- games/CubeCastle.js | 469 +++++++++++++++++++++++++++++++++++++++ games/img/CubeCastle.png | Bin 0 -> 17372 bytes 2 files changed, 469 insertions(+) create mode 100644 games/CubeCastle.js create mode 100644 games/img/CubeCastle.png diff --git a/games/CubeCastle.js b/games/CubeCastle.js new file mode 100644 index 0000000000..eea6f60828 --- /dev/null +++ b/games/CubeCastle.js @@ -0,0 +1,469 @@ +/* +@title: Cube Castle +@author: Paylicier +@tags: ['platformer'] +@addedOn: 2024-12-05 +*/ + +const player = "p" +const king = "k" +const princess = "w" +const plateform = "#" +const lava = "@" +const sign = "s" +const fireball = "f" + +const DIAL_SCENE = 0 + +setLegend( + [player, bitmap` +................ +................ +..00000000000000 +..00000000000000 +0000LLLLLLLLLL00 +0000LLLLLLLLLL00 +00LLLLL00LL00L00 +00LLLLL00LL00L00 +00LLLLLLLLLLLL00 +00LLLLLLLLLLLL00 +00LLLLLLLLLLLL00 +00LLLLLLLLLLLL00 +0000LLLLLLLLLL00 +0000LLLLLLLLLL00 +..00000000000000 +..00000000000000`], + [plateform, bitmap` +0000000000000000 +0000000000000000 +0011111111111100 +0011111111111100 +0011LLLLLLLL1100 +0011LLLLLLLL1100 +0011LLLLLLLL1100 +0011LLLLLLLL1100 +0011LLLLLLLL1100 +0011LLLLLLLL1100 +0011LLLLLLLL1100 +0011LLLLLLLL1100 +0011111111111100 +0011111111111100 +0000000000000000 +0000000000000000`], + [lava, bitmap` +9999999999999999 +9999999999999999 +9999999999999999 +9999999999999999 +9999999999999999 +9999999999999999 +9999999999999999 +9999999999999999 +9999999999999999 +9999999999999999 +9999999999999999 +9999999999999999 +9999999999999999 +9999999999999999 +9999999999999999 +9999999999999999`], + [sign, bitmap` +................ +................ +................ +...CCCCCCCCCC... +..CCCCCCCCCCCC.. +..CC00000000CC.. +..CCCCCCCCCCCC.. +..CCC000000CCC.. +..CCCCCCCCCCCC.. +..CCCC0000CCCC.. +..CCCCCCCCCCCC.. +......FFFF...... +......FFFF...... +......FFFF...... +......FFFF...... +......FFFF......`], + [king, bitmap` +................ +6.66.66.66.66.66 +6.66.66.66.66.66 +6666666666666666 +6666666666666666 +0000000000000000 +0000000000000000 +00L0LLLLLLLL0L00 +00LL0LLLLLL0LL00 +00LLL0LLLL0LLL00 +00L20LLLLLL02L00 +00L20L0LL0L02L00 +00LLLLL00LLLLL00 +00LLLLLLLLLLLL00 +0000000000000000 +0000000000000000`], + [princess, bitmap` +................ +................ +................ +.............H8H +HHHHHHHHHHHHH868 +HHHHHHHHHHHHHH8H +0000000000000000 +00LLLLLLLLLLLL00 +00L20LLLLLL02L00 +00L20LLLLLL02L00 +00LLLLLLLLLLLL00 +00LLLL0000LLLL00 +00LLL0LLLL0LLL00 +00LLLLLLLLLLLL00 +0000000000000000 +0000000000000000`], + [fireball, bitmap` +................ +................ +................ +................ +................ +................ +................ +................ +....33333333.... +....39999993.... +....39666693.... +....39622693.... +....39622693.... +....39666693.... +....39999993.... +....33333333....`] +) + +setSolids([plateform, player]) + +let isJumping = false +let isDead = false +let lives = 5 + +let level = 1 +const levels = [ + map` +.`, + map` +.......... +.........s +.......### +...#.#.... +p......... +##########`, + map` +.......... +.........s +.....##.## +....###... +p..####... +#@@#@@#@@@`, + map` +.........# +.........# +p........# +########## +########## +########## +.........s +########## +@@@@@@@@@@`, + map` +............ +............ +.p.......... +.#..#..#...s +@#@@#@@#@@## +@#@@#@@#@@@@`, + map` +............ +..s......... +..##.####... +..........## +.........### +........#... +......##.... +.p.##..#.... +.#..#..#.... +@#@@#@@#@@@@ +@#@@#@@#@@@@`, + map` +................. +....w............ +...###........... +................. +..............k.s +..............### +..p.......###.... +.###..###........ +................. +@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@` +] + +const melody = tune` +185.1851851851852: C4/185.1851851851852, +185.1851851851852: D4-185.1851851851852, +185.1851851851852: E4^185.1851851851852, +185.1851851851852: D4-185.1851851851852 + B4/185.1851851851852, +185.1851851851852: E4^185.1851851851852, +185.1851851851852: D4-185.1851851851852, +185.1851851851852: E4^185.1851851851852, +185.1851851851852: D4-185.1851851851852, +185.1851851851852: C4/185.1851851851852, +185.1851851851852: C4-185.1851851851852, +185.1851851851852: D4^185.1851851851852, +185.1851851851852: C4-185.1851851851852 + B4/185.1851851851852, +185.1851851851852: D4^185.1851851851852, +185.1851851851852: C4-185.1851851851852, +185.1851851851852: D4^185.1851851851852, +185.1851851851852: C4-185.1851851851852, +185.1851851851852: C4/185.1851851851852, +185.1851851851852: D4-185.1851851851852, +185.1851851851852: E4^185.1851851851852, +185.1851851851852: D4-185.1851851851852 + B4/185.1851851851852, +185.1851851851852: E4^185.1851851851852, +185.1851851851852: D4-185.1851851851852, +185.1851851851852: E4^185.1851851851852, +185.1851851851852: D4-185.1851851851852, +185.1851851851852: C4/185.1851851851852, +185.1851851851852: C4-185.1851851851852, +185.1851851851852: D4^185.1851851851852, +185.1851851851852: C4-185.1851851851852 + B4/185.1851851851852, +185.1851851851852: D4^185.1851851851852, +185.1851851851852: C4-185.1851851851852, +185.1851851851852: D4^185.1851851851852, +185.1851851851852: C4-185.1851851851852` +let playback = playTune(melody, Infinity) +let time = 0; + +const dialogues = [{ + level: 1, + text: "In this game,\nyou're a cube\nthat needs\nto free\nthe princess\nfrom the cube\nking.\n\n\nPress L again\nto close", + targetlvl: 2 + }, + { + level: 2, + text: "Welcome to\nthe king's\ncastle\n\n\nPress L again\nto close", + targetlvl: 3 + }, + { + level: 3, + text: "You're\nentering the\nlava hallway\n\nPress L again\nto close", + targetlvl: 4 + }, + { + level: 4, + text: "You're\nentering the\nlava hallway2\n\nPress L again\nto close", + targetlvl: 5 + }, + { + level: 5, + text: "Boss Battle\ntime\n!1!1!1!1!\n\nPress L again\nto close", + targetlvl: 6 + }, + { + level: 6, + text: `You win !\nThe king failed\na jump and\ndied in lava.\n\nTime: {TIME} sec.\n\nPress L to\nrestart`, + targetlvl: 1 + } +] + +function jump(player) { + const plr = getFirst(player); + if (isJumping && player != king) return; + isJumping = true + plr.y -= 1 + setTimeout(function() { + plr.y -= 1 + if (player === king) plr.x -= 1 + setTimeout(function() { + isJumping = false + gravity(player) + }, 120) + }, 60) +} + +function gravity(obj) { + const playerSprite = getFirst(obj) + if (!playerSprite) return; + if (!isJumping) { + const belowSprites = getTile(playerSprite.x, playerSprite.y + 1) + + if (belowSprites.some(sprite => sprite?.type === lava) || belowSprites.some(sprite => sprite?.type === player)) { + if (obj != player && !belowSprites.some(sprite => sprite?.type === player)) return playerSprite.remove(); + // Player touched lava/fireball, reset the game + kill() + return; + } + + if (belowSprites.length === 0) { + isJumping = true + playerSprite.y += 1 + setTimeout(function() { + isJumping = false + gravity(obj) + }, 100) + } else { + if (obj === fireball) { + breakBlock(belowSprites[0].x, belowSprites[0].y) + return playerSprite.remove() + } + isJumping = false + } + } +} + +function kill() { + isDead = true + setMap(levels[DIAL_SCENE]) + lives-- + if (lives === 0) { + addText("Game Over !", { x: 5, y: 5, color: color`0` }) + setTimeout(function() { + isJumping = false + isDead = false + clearText() + level = 1 + lives = 5 + time = 0 + setMap(levels[1]) + }, 1200) + return; + } + addText("You died !\n\nLives:" + lives, { x: 5, y: 5, color: color`0` }) + setTimeout(function() { + isJumping = false + isDead = false + clearText() + setMap(levels[level]) + if (level === 6) bossFight(); + }, 1200) +} + +function spawnFireballs() { + if (level != 3) return; + const fireballX = Math.floor(Math.random() * width()) // Random x coordinate + const fireballY = 0 // Fixed y coordinate + addSprite(fireballX, fireballY, fireball) + gravity(fireball) + setTimeout(function() { + spawnFireballs() + }, Math.floor(Math.random() * 1000) + 100) +} + +function breakBlock(x, y) { + const blockSprite = getTile(x, y)[0] + if (blockSprite?.type === plateform) { + blockSprite.remove() // Remove the block sprite + } +} + +function bossFight() { + setTimeout(function() { + const kingSprite = getFirst(king); + if (kingSprite) { + jump(king); + } + }, 1500) +} + +function interactCheck() { + const playerSprite = getFirst(player) + if (!playerSprite) return; + const adjacentSprites = [ + getTile(playerSprite.x + 1, playerSprite.y)[0], // Right + getTile(playerSprite.x - 1, playerSprite.y)[0], // Left + getTile(playerSprite.x, playerSprite.y - 1)[0] // Up + ] + + const isNearSign = adjacentSprites.some(sprite => sprite?.type === sign) + + if (isNearSign) { + addText("Press L to interact", { x: 0, y: 14, color: color`2` }) + } else { + clearText() + } +} + + +function interact() { + const playerSprite = getFirst(player) + if (!playerSprite) { + if (isDead) return; + const dialogue = dialogues.find((dial) => dial.level === level); + clearText(); + if (dialogue?.targetlvl) level = dialogue.targetlvl + if (level === 3) spawnFireballs(); + setMap(levels[level]); + if (level === 6) bossFight(); + if (level === 1) { + time = 0; + lives = 5; + } + return; + } + const adjacentSprites = [ + getTile(playerSprite.x + 1, playerSprite.y)[0], // Right + getTile(playerSprite.x - 1, playerSprite.y)[0], // Left + ] + + const isNearSign = adjacentSprites.some(sprite => sprite?.type === sign) + + if (isNearSign) { + const dialogue = dialogues.find((dial) => dial?.level === level); + setMap(levels[DIAL_SCENE]) + clearText() + addText(dialogue?.text.replace("{TIME}", time) || "notext", { x: 3, y: 1, color: color`0` }) + } +} + + +setMap(levels[level]) + +setPushables({ + [player]: [] +}) + +onInput("w", () => { + if (!getFirst(player)) return; + jump(player) +}) + +onInput("l", () => { + interact() +}) + +onInput("d", () => { + if (!getFirst(player)) return; + getFirst(player).x += 1 +}) + +onInput("a", () => { + if (!getFirst(player)) return; + getFirst(player).x -= 1 +}) + +onInput("k", () => { + if (playback) { + playback.end() + playback = null + return; + } + playback = playTune(melody, Infinity); + +}) + +afterInput(() => { + if (!isJumping) gravity(player) + interactCheck() +}) + + +//time +setInterval(function() { + time++ +}, 1000) diff --git a/games/img/CubeCastle.png b/games/img/CubeCastle.png new file mode 100644 index 0000000000000000000000000000000000000000..2634588a7066790bb07fa38d434afec308b8e7bc GIT binary patch literal 17372 zcmeHP4LFqP`bVtjWEfxPl&?xrly=(oiSQ<{{QPbd!0Rd&K_OYymLMCyzl+>-1qa` z@BO+EPhUv+`1oSfYJZ4O($l9QXmLq2oofM2|na;}3f`Jk`tH_6?t)9V8RMc<7( zH_FM~Pnaj#uLS1iIq%qGHy)^aYhC5IfAQE69qtjGQG(70L5Cfn!wJwC^4A&m*Xcj3 zGjLdE&|jy=PrKJo``sb!zC+rb2ejWF)b2W{-F;BI-A9Y*tIhJ&?l_>`{GC?IcUlZ@ ztyXWXHXp55`!!#Gqt*D0R@1jyZ@$&4!)wy=o(MW=boA` zyfk0#*Mxf1D{$y%?&wMnbk*1BS})B~H;pnk4eDNv^1Wyp4*in{`mu{fk&DI?7mZ?9 zjS^Rlhr87ac56J^qfxj=eo$4*Z0>ZE-smD4?h`yYDvlD86$^nZIk4s7jWYlM$uu78y7!$ z5W?0R5Erfg?6a)D9#Vbfz)QRG&-sVLLv%NY?G~zr{R^+;O7Qm>+ILwePL>DpgsIePnOl7tQKNc4hqJ6j4}Bb{*@VU=(&6E~1%WT>fc@xMuBh>O{9T_7cT_1lsRE2Ow7t4kHUbqNB)qBZgss0V-d@f$#Scb#@9Aw0f?7bI0IlLi!Vz8}{AUx;k@hHGud>!j# zGxQ=?St{QfY!IuQwmD{EFvFhAa32+$F>}qNQ&vPCCuxa&g8uq4m^EC=2&uck#`Aqj z7tte2lqnUlS1#l@W?B=+-awnfU1v-+=ljw#){{FrV|T|S7+|foLybEZt`)eI;oL|@ z(xqAII;cP*T_<2)Zrd7~jIc3P>Q7xRyCRZ26F8Ne*qttZD zC_|eQqOQ8O0n1g)CrA2!9%&OE_szorIu4_2VL8={EU*Cupx!eh#ckMaj&E2=^W%z|24Vc&b9 z@mMm%=^GL@(GA;*NZdvs4Qhx{;GZ8wxbR+Ns(50+oX_^!5OGBKy!H?_)B4c@(Q6pS zkZgP|Y?;=K3fpXlstPTbn9!qas36m6Jrig98yOD-$H{m~6TYepZ- zL*CeDvDA$?3E0L{u%Pm7xTPNPcGR>U&`6azKhu{+hIn_Q2+{9NfbF4 ziMVi_tbfhbisz~od&P8AKU7VvOxsRjSsd`Is3?M6(#hDxzO|y4vm|t7q?C6sO9kHX+HU9S2a0)GYi z+0NZE{a400DNz~@Xoh-eWuBih!hv1H6`b^~Y31B3-bI-uz%!A(pSLJdbSraY=5W`_ zRK?`fFXNP$+AN*2$uC*FJuK_^wUNDcBgJMrH{_KIY7-JLW`Xe^uD&3Kq}GV2VBnyL)f@aL9+AD$)2 znSHN$FYdAYpZ2Sd`s63{!H0by0ZKpV@@&3CD@b(~$FBvMO{_%o*o7cDx>kP!;5>`%bVUi#aC7|WDFd^bVt4FZin~Yp=$C587FOB7`@zm zziRBXn>chRdLZMM2eMb&neABg-d~od??cAGN3?Dnh+b|y?Kq2~H4h_WhwS*LT6b1Q zKb!WTYe!B=#s?qnx}2pAgr9aLEysJv_|KutY+TIl5Ht45a#e{z{-j@7h9uqy8|(k( zp|@~Y9OIN;dQ3bKm1Dsq@x}|8FfV4O9ymef)0i7MYz$G*KU77}XTcrsoRFWzOL_J_ zG<*@4(|kK5(}qs!re_m&{{+q?4bg^tR%UU@==1E}JSJIiFO`_K793uJH9X~W>6j4j z?%}t(1h29*6SxUa&foSHoJyyt!8)SsoH~4IAiFxsH?N&49vi8Mp|AA^=j7+}paiUc zYe{f#dsLMp{_%0HAj95*Qg(trJd^{b@=sKG;2cA%>n=Mj9U# z3qvF%#wtW~!9q&{qku3uQegu4ki{t`C_IKdF;;sh&C0R-OZWNE8GnyQ>}K-VD|+E7 z=3~<2#M>B@S4n7qW|h+3Z6le(wa`+SQ_XE!#l#ndOx6vVI2kaW1Q_rxa;;D_6a4@n;7!p8`Z1>fWN;D%$wOQLzcd7eeYz8?vcS$zEUjdSzvr8Yvj)cp;YGV;6F*yCLqL5btU>`z@vUMa{QB($zBY+jZ?=DEIc zAN8%z^d|f0kkc?wvxhggi=ItgKr)LYkGV4Z#+n`wmU2+-w>-|4xzMo3*Z5M=(3O8y zP5Yly8UMYgMC8G|n!&!9q5^mThRJY^-%#r}-Oumlgmz3^yyCK1L4ii=+~zT^ztO8; zc>GldV~D@#GV=2k6^t47R6ilvqL|Vj&ERfcefx}};`#g@Mm=A6EBbkgC)L%lG>UK| z@uclB*V>AT{83FEbNq2J{+3$Utm|0 z;t6MTtChLfDLidl>2dr{%Y#(Pe2f_*nErcN3W)yNv)mGsfpQyLml|zLt_KUZbq0hp{qa z79tdvV~-uU-v_GCaf+umD^D6?NrP`j#L8;J?ZpwjI+Wy!m;^oRqsP3c&fsPgeSn(1 z0jrqr=U^)d5gbv?(E9jb`41a}$47J1FI$K8k6o#-PZ+{qMf7D*3{T;{FgDV&4(jjn zBRU$|92c=DLl`q(I%Px1uqgVhiKD)aL^J9NW|hpSjv0@SK&|E*bXQR@Yv^k98W|eU z$j@}5cp;=OW^S0|#zwbDm+f>Wz3s_~?ivh6*QdFe{Jn3tU_3cFd7-6+XKC2AC70&&Q*Y_4eh*BP#sj@bi{hSowc~jG4_Arxi~x#FL7| zyph4ep3>y)O{>z^)#Q(kzP{Z=pp=I4x`u0Nm5_%^fhQj@{w@nD>(A@+^-sf~)m?{e z!p2y%sF(ycv54F)s$POIBQVRt;nCL(y(j{+IIz3b67g(z=)?%n@pJTNyAF}VX--^N ziR&lQ7XxK^M|(%2dg+w*zNi2)4q5xn{01cu zuZY#e<9QaBy_waB)$j(?P=R0^pf3jP&{4Q0nqb#E$@JYNDr=<*YTtL~<$RyEd#v?>{SSN z9N&+Fr-qjNJoY+@OdMxhScP)b$qX8Tt5Fru>cg0HCAj-}WfWY+rjnqsfDt2$0+JWR z=&gjA+N8M)RIc3QG1Pd^b$zNQ^F)h*Yl561M2QTopWs$iMwPS**#30X#wCk1gGZQ< z;MD6bp&LoV*yu$ReAGbn8f%^jmtBkawYvh_5AEx1+zBP)6;ldHF^K%Io?7)VK7h6!r7mC~f@Z=fDp>`w7XGk5@7xjVS#E4{J zBE(I)gUw~$j5G02ibxf}9a3+@!{bWDlS3`*g!yIgQmP!;Hu`w4dYFiUr%LR@Fe)uhDOR6v~I1`AH% zUBTsTaUr{)pb(%M#;FWJn@D<<`7lFxDd~Qzf_(o26@~ z0IE^?A}N3rg_podA)K=ka7m3Mg_>v<65we)4X#*Foj&E{{{Vevg=v(FaU96@`6@a4wbpjOtga))sN6<5%ya~YCfK7gl(d>^>TmAnA`2cD_ z!ZOk7hneVwBs3h-KR_EKk!|ew0e~^($R7X>V56~;kJbDD!$2Ys1i}Zf2-u?>Z97kY z0AnCg3Re0*OxzAEtp5T2Jf+CT2=SDSK8B#D%6Nt_%v@*WT-bsGL@=@zf*B670?2*IbRHn0 zEbDBTu^fopXm3D-E9+R8xsHEQu%FF?YBFNzUZujZ zun9A=ffx&24ah<~Co&8A3q-+j=$>Bu?s{$$8ym5AC!{B%JD$Qav^qN4nw(smfG-K- z2T(+Kve^I3lh~u20g(7E_`j;CL9cdRM6ws>R~Q}^dKk!U%m_yrtdHnusT~M0C=C_# zcNZ6C+C&JfHn(j7={rbS0bCoQoRCozI`FavyxnGEBgFmP!bx_|%`{VG>MF;pH*p+a zawGF`7~^h4ae|>uAk+_Dzc69EPJVt4!7DFoTBSz<3;sgO!;A+JbWk28l?C&E8ZRz1 z#1c83m0Xu;(cC$1a6@S`wad^Z3~K2XnoSP37m2&7-%j76MavX#hX&~aVFCs4YfMhF zbiGS13SkegklEMo3*K$`Jk`6ZeRGv>HTB3uOY-xSfOabR{px&yvH@}zM9^t(?dj=H zLOWWUJ(})%dIm?!?3gN+`};N5XqVm}W$HJh_6@l~B9w4_A$!9y7Vmzxy;`Pq(23z! zKklB^X;67J3b}{d#eP%R`wMN3Fu`!%^sLCF{G&qbk@>RKE)Xo)3#z-@p&R}lg)bgZ zBZOsNfX>(JGP}Bx6%Uc$m>@OR<^rGIzf3>q!P7%C7=5)?+omO-DSB;jpPYlUqtFXuG!Q} zVyrmhJ;{4MD+T27w+S+>w6LdbS@0H_AB}8Q*CVExgV!+9+%G#=>-m~hD##1*3eB1A z08VYsEQB7s<)$vAx9@uboZ4Q2U*q7&s@!GD%v_^C=yR3u2|SJ5OVD{K0^h|-$O5>! z1i+sH>6OV^2=p$2*QGeVH7^@M=OqZd6zZ?08QK8=UkcJofp|5@6v6lDBnJq7~AtUYMncXgCw+mUb+3Z$1yH!qi3(jU2 zNN42iF)@2g%pQ@mN961g3H~tizxX8-Zezg~Rlh3U%$9j1e@HT0c|xM%H`M3K{zhDr lX7DepTBegBE-Zh;MnlCddBhL=*AsHv>>Rh;-L&u2{{pz4%0K`B literal 0 HcmV?d00001