smoothretro82

Squarie playground 1.2.4

Dec 4th, 2025 (edited)
48
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.55 KB | None | 0 0
  1. // --- Grid helpers (unchanged) ---
  2. by = []
  3. bx = []
  4. acol = []
  5. atxt = []
  6.  
  7. for (let i = 0; i < 800; i++) {
  8. bx.push(i % 40 - 20)
  9. by.push(Math.floor(i / 40) % 20 - 10)
  10. }
  11.  
  12. // --- Sprites / types (unchanged) ---
  13. squarieNames = ["ypactl", "jesus_mata"]
  14. squarieMap = [
  15. ["[]##", [5, 5, 18, 18], [0, 1, 0, 1], [0, 0, -1, -1],
  16. "[7v7]###", [5, 5, 5, 18, 5, 5, 5, 18], [-2, -1, 0, 1, 2, -1, 0, 1], [0, 0, 0, 0, 0, -1, -1, -1],
  17. "[###]", [5, 18, 5, 5, 5], [-2, -1, 0, 1, 2, 0], [0, -1, -1, -1, 0],
  18. "[]##", [5, 5, 5, 5], [-1, 0, -1, 0], [0, 0, -1, -1]],
  19.  
  20. ["J]", [4, 5], [0, 1], [-1, 0],
  21. "[o̮o]J", [7, 8, 25, 11, 13, 21], [-2, -1, 0, 1, 2, 0], [0, 0, 0, 0, 0, -1],
  22. "[]J", [4, 5, 7], [-2, 2, 0], [0, 0, -1],
  23. "[J", [8, 25], [-1, 0], [0, -1]]
  24. ]
  25.  
  26. squarieHealth = [241, 4294967296]
  27.  
  28. // --- ID generator fallback ---
  29. let _idCounter = 0
  30. function makeId() {
  31. if (typeof crypto !== "undefined" && crypto.randomUUID) return crypto.randomUUID()
  32. _idCounter++
  33. return "sq-" + Date.now().toString(36) + "-" + (_idCounter)
  34. }
  35.  
  36. // --- Squarie list (objects with stats inside) ---
  37. let squaries = [
  38. {
  39. id: makeId(),
  40. type: 0,
  41. dir: 1,
  42. x: 10,
  43. y: 5,
  44. vx: 0,
  45. vy: 0,
  46. health: squarieHealth[0],
  47. damage: 0,
  48. kills: 0
  49. },
  50. {
  51. id: makeId(),
  52. type: 1,
  53. dir: 2,
  54. x: 30,
  55. y: 15,
  56. vx: 0,
  57. vy: 0,
  58. health: squarieHealth[1],
  59. damage: 0,
  60. kills: 0
  61. }
  62. ]
  63.  
  64. // --- Text + objects ---
  65. text = [
  66. ["Squarie Playground v . .", 7, 0, 0, 4294967296],
  67. ["1", 11, 20, 0, 4294967296],
  68. ["2", 9, 22, 0, 4294967296],
  69. ["3", 4, 24, 0, 4294967296]
  70. ]
  71.  
  72. // objects: { type: 0|1|2, x, y, angle?, owner? }
  73. objects = [
  74. { type: 1, x: 7, y: 13 },
  75. { type: 1, x: 39, y: 15 },
  76. { type: 1, x: 38, y: 17 }
  77. ]
  78.  
  79. // --- Speed Control ---
  80. let speedMultiplier = 0.1
  81. let running = true
  82.  
  83. function mod(x, y) {
  84. return x - (Math.floor(x / y) * y)
  85. }
  86.  
  87. // --- Main update loop (physics, collisions, drawing) ---
  88. function update() {
  89. if (!running) return
  90.  
  91. // decay text lifetime
  92. text = text.filter(t => t[4] - 0.0625 > 0).map(t =>
  93. [t[0], t[1], t[2], t[3], t[4] - 0.0625]
  94. )
  95.  
  96. // remove "cleared" objects (type 0)
  97. objects = objects.filter(o => o.type !== 0)
  98.  
  99. // --- Bullet collision ---
  100. for (let i = 0; i < objects.length; i++) {
  101. let obj = objects[i]
  102. if (obj.type === 2) {
  103. for (let j = 0; j < squaries.length; j++) {
  104. let s = squaries[j]
  105. if (s.health <= 0) continue
  106. if (
  107. mod(Math.round(obj.x), 40) === mod(Math.round(s.x), 40) &&
  108. mod(Math.round(obj.y), 20) === mod(Math.round(s.y), 20)
  109. ) {
  110. let dmg = Math.random() * 50 + 50
  111. s.health -= dmg
  112.  
  113. // attribute damage and kills to owner id (if still present)
  114. let owner = squaries.find(ss => ss.id === obj.owner)
  115. if (owner) {
  116. owner.damage += dmg
  117. if (s.health <= 0) {
  118. owner.kills++
  119. }
  120. }
  121.  
  122. // apply knockback
  123. if (typeof obj.angle === "number") {
  124. s.vx += Math.sin(obj.angle)
  125. s.vy += Math.cos(obj.angle)
  126. }
  127.  
  128. text.push([Math.round(dmg) + " DMG", 4, s.x, s.y, 5])
  129. obj.type = 0 // mark consumed
  130. break // bullet consumed, stop checking other squaries
  131. }
  132. }
  133. }
  134. }
  135.  
  136. // --- Movement + shooting ---
  137. for (let s of squaries) {
  138. if (s.health <= 0) continue
  139.  
  140. s.x = mod(s.x + s.vx * speedMultiplier, 40)
  141. s.y = mod(s.y + s.vy * speedMultiplier, 20)
  142. s.vx /= Math.pow(1.1, speedMultiplier)
  143. s.vy /= Math.pow(1.1, speedMultiplier)
  144.  
  145. if (Math.random() < 0.01) {
  146. let dir = Math.floor(Math.random() * 4)
  147. s.dir = dir
  148. s.vx += Math.random() * ((dir == 3) - (dir == 0))
  149. s.vy += Math.random() * ((dir == 1) - (dir == 2))
  150. }
  151.  
  152. // squarie type 1 sometimes fires
  153. if (s.type === 1 && Math.random() < 0.003) {
  154. objects.push({
  155. type: 2,
  156. x: s.x + s.vx,
  157. y: s.y + s.vy,
  158. angle: [Math.PI / -2, 0, Math.PI, Math.PI / 2][s.dir] + Math.PI * (Math.random() - 0.5),
  159. owner: s.id
  160. })
  161. }
  162. }
  163.  
  164. // --- Clear grid ---
  165. atxt = " ".repeat(800).split("")
  166. acol = atxt.map(v => 0)
  167.  
  168. // --- Draw ASCII border ---
  169. for (let x = 0; x < 40; x++) {
  170. atxt[x] = (x === 0 ? "+" : (x === 39 ? "+" : "-"))
  171. atxt[x + 19 * 40] = (x === 0 ? "+" : (x === 39 ? "+" : "-"))
  172. acol[x] = 15
  173. acol[x + 19 * 40] = 15
  174. }
  175. for (let y = 1; y < 19; y++) {
  176. atxt[y * 40] = "|"
  177. atxt[y * 40 + 39] = "|"
  178. acol[y * 40] = 15
  179. acol[y * 40 + 39] = 15
  180. }
  181.  
  182. // --- Draw squaries ---
  183. for (let s of squaries) {
  184. if (s.health <= 0) continue
  185. let rdr = squarieMap[s.type]
  186. for (let j = 0; j < rdr[s.dir * 4].length; j++) {
  187. let px = mod(Math.round(s.x + rdr[s.dir * 4 + 2][j]), 40)
  188. let py = mod(Math.round(s.y + rdr[s.dir * 4 + 3][j]), 20)
  189. atxt[px + py * 40] = rdr[s.dir * 4][j]
  190. acol[px + py * 40] = rdr[s.dir * 4 + 1][j]
  191. }
  192. }
  193.  
  194. // --- Draw objects ---
  195. for (let o of objects) {
  196. if (o.type == 2) {
  197. if (o.angle === undefined) o.angle = Math.random() * 2 * Math.PI
  198. o.x += Math.sin(o.angle) * speedMultiplier
  199. o.y -= Math.cos(o.angle) * speedMultiplier
  200. }
  201. o.x = mod(o.x, 40)
  202. o.y = mod(o.y, 20)
  203. let ch = ["!", "0", "x"]
  204. let col = [4, 11, 13]
  205. let px = Math.round(o.x)
  206. let py = Math.round(o.y)
  207. atxt[px + py * 40] = ch[o.type]
  208. acol[px + py * 40] = col[o.type]
  209. }
  210.  
  211. // --- Draw text labels ---
  212. for (let i = 0; i < text.length; i++) {
  213. for (let j = 0; j < text[i][0].length; j++) {
  214. let tx = mod(Math.round(text[i][2] + j), 40)
  215. let ty = mod(Math.round(text[i][3]), 20)
  216. atxt[tx + ty * 40] = text[i][0][j]
  217. acol[tx + ty * 40] = text[i][1]
  218. }
  219. }
  220.  
  221. // --- Scoreboard at bottom lines ---
  222. let scoreboardStartY = 18
  223. for (let i = 0; i < squaries.length; i++) {
  224. let row = scoreboardStartY + i
  225. if (row >= 20) break
  226. let s = squaries[i]
  227. let scoreText = `S${i} HP:${Math.round(s.health)} Dmg:${Math.round(s.damage)} K:${s.kills}`
  228. for (let j = 0; j < scoreText.length && j < 40; j++) {
  229. let pos = j + row * 40
  230. atxt[pos] = scoreText[j]
  231. acol[pos] = 11
  232. }
  233. }
  234.  
  235. requestAnimationFrame(update)
  236. }
  237.  
  238. // start physics/render update
  239. update()
  240.  
  241. // --- Compatibility helpers from your original environment ---
  242. // ct checks whether tile at (x,y) already shows a given char/color
  243. function ct(x, y, t, c) {
  244. if (typeof Tile !== "undefined" && Tile.exists(Math.floor(x / 20) * 20, Math.floor(y / 10) * 10)) {
  245. return (getCharInfoXY(x, y).char == t && getCharInfoXY(x, y).color == c)
  246. } else {
  247. return false
  248. }
  249. }
  250.  
  251. // ap() writes the buffer to the display using writeCharAt and writeBuffer (your environment)
  252. function ap() {
  253. if (!running) return
  254. if (typeof writeBuffer === "undefined" || typeof writeCharAt === "undefined") {
  255. // If your environment doesn't expose writeBuffer/writeCharAt, skip and let update() handle logic.
  256. requestAnimationFrame(ap)
  257. return
  258. }
  259.  
  260. if (writeBuffer.length < 50) {
  261. let i = 0
  262. for (let j = 0; j < 5; j++) {
  263. while (i < atxt.length && ct(bx[i], by[i], atxt[i], acol[i])) {
  264. i++
  265. }
  266. if (i < atxt.length) {
  267. writeCharAt(atxt[i], acol[i], bx[i], by[i])
  268. }
  269. }
  270. }
  271. requestAnimationFrame(ap)
  272. }
  273. ap()
  274.  
  275. // --- Chat / command handlers (adapted to object shape) ---
  276. if (typeof w !== "undefined" && w.on) {
  277. w.on("msg", (data) => {
  278. let msg = data.msg.toLowerCase()
  279.  
  280. if (msg.startsWith("spg#addsquarie")) {
  281. let na = data.msg.substring(15).trim()
  282. let idx = squarieNames.indexOf(na)
  283. if (idx !== -1) {
  284. let s = {
  285. id: makeId(),
  286. type: idx,
  287. dir: Math.floor(Math.random() * 4),
  288. x: Math.random() * 40,
  289. y: Math.random() * 20,
  290. vx: 0,
  291. vy: 0,
  292. health: squarieHealth[idx],
  293. damage: 0,
  294. kills: 0
  295. }
  296. squaries.push(s)
  297. setTimeout(() => w.chat.send("Added squarie " + na), 250)
  298. } else {
  299. let namsg = [
  300. na + " does not exist yet.",
  301. "Who is " + na + ", anyway?",
  302. "N\\A> " + na + "?",
  303. na + " is not available yet.",
  304. na + " tried to swim in lava.",
  305. na + " hit the ground too hard.",
  306. na + " blew up by a creeper",
  307. na + " died.",
  308. na.toUpperCase() + " WAS USED UP. " + data.nick.toUpperCase() + " WAS USED UP.",
  309. na + "? Nah, we got " + data.nick
  310. ]
  311. setTimeout(() => w.chat.send(namsg[Math.floor(Math.random() * namsg.length)]), 250)
  312. }
  313. }
  314.  
  315. if (msg.startsWith("spg#stats")) {
  316. let nsqu = Number(data.msg.substring(10))
  317. if (!isNaN(nsqu) && nsqu >= 0 && nsqu < squaries.length && Math.floor(nsqu) == nsqu) {
  318. let s = squaries[nsqu]
  319. setTimeout(() => w.chat.send("Squarie #" + nsqu + ": [Type: " + s.type + " Direction: " + s.dir + " x: " + s.x + " y: " + s.y + " xVel: " + s.vx + " yVel: " + s.vy + " HP: " + Math.round(s.health) + " Dmg: " + Math.round(s.damage) + " K: " + s.kills + "]"), 250)
  320. } else {
  321. setTimeout(() => w.chat.send("Error! Squarie #" + nsqu + " does not exist!"), 250)
  322. }
  323. }
  324.  
  325. if (msg.startsWith("spg#speed")) {
  326. let val = parseFloat(data.msg.substring(10))
  327. if (!isNaN(val) && val > 0 && val <= 10) {
  328. speedMultiplier = val
  329. setTimeout(() => w.chat.send("Simulation speed set to " + val + "x"), 250)
  330. } else {
  331. setTimeout(() => w.chat.send("Invalid speed! Use a number between 0.1 and 10."), 250)
  332. }
  333. }
  334.  
  335. if (msg.startsWith("spg#quit")) {
  336. running = false
  337. setTimeout(() => w.chat.send("Simulation stopped."), 250)
  338. }
  339.  
  340. if (msg.startsWith("spg#help")) {
  341. let helpMsg = [
  342. "Available commands:",
  343. "spg#addsquarie [name] - Add a squarie to the simulation",
  344. "spg#stats [index] - Get stats for a specific squarie",
  345. "spg#speed [value] - Set simulation speed (0.1 to 10)",
  346. "spg#quit - Stop the simulation",
  347. "spg#help - Show this help message",
  348. "spg#scores - Show squarie damage and kills"
  349. ]
  350. w.chat.send(helpMsg.join("\n"))
  351. }
  352.  
  353. if (msg.startsWith("spg#scores")) {
  354. let scoreList = squaries.map((s, i) =>
  355. `S${i}: HP:${Math.round(s.health)} Dmg:${Math.round(s.damage)} K:${s.kills}`
  356. ).join("\n")
  357. w.chat.send(scoreList)
  358. }
  359. })
  360. }
  361.  
Advertisement
Add Comment
Please, Sign In to add comment