!!!!!!!!""""""""""""""!!!!!!!!!!ADADDAADDADAADADDAADDADAADAADAAADAADAAAAAAAAA    "" CCD0DD@DD@33@CD4DDDDDD331CCD0DD@DD@33@@CDDDDDDD331AD0DDD0DD@33@@@DDCD4DDDDCD131D0D4Af`ww @@DD@@D@DD`ff`f`ffADDDDfvpwpw@DD@@D@DD`ff`ffffDDDDfvwwp@@D@DD@DDfff`ffLDDDfwpwwpwDD4DD4CDD4CD4@D40D4D4C0DDAffAffAfvAvgAffAffDDffDDf0003030433C44CDC4CDD40DDpwpwpwpw         "   " """ " 0  " " "" ""2 "3 "3"3""" ""2##3"""" """" " """""""""""""" """""""" ,  2 "", "," " "" 2 """ ", """ """""""" """""""""""""""""""""""" """""""" " ""3030033330,̜3030033330,̜ f`733330A03033033331A433f`733330A0303333331A433 , ," 13!!"""33""013!!""""33""!!!!!!!!!!!!!"  d  0111222344579;<>??????????????C !!!"##$&*.B  c c#.3 >M CKC 9  #0pz ?<4 46747I7W8W94:$8#:#:!;;;;<<<<<<==>>>?8:98696<<<8:796:=?????????????  00011357:?????????????????????    40001122334444556667789:;<<=>>?; b bb b b bb b b bb b b bbbB""a%E Ee e % cC% f & F%f &f& f & F F F F F FfFfFff F& f & F FffE EEE EE %E % %EEEEEEEEE EEE E0c G G G GggggGG GgggggGtOO OOO OOO OOO O              + + +'a+`++ + +b bb bbbb b b bbb b b b b bbbb b b bb b bbgg ggg g gg` `` `         `` ``` ````    ` ` `` ` ```    ` `` `` ``   ` `` `   1Ɓ0@@44UUօօa,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD`ff3DD`ff3DD3333`v7333DDDDD3333`v7333DDDDD333333033333333DDDDDDD333333033333333DDDDDDD3333033333C3DDDDDDDD3333033333C3DDDDDDDD3333"303A1A4DDDDDDD333333"303A1A4DDDDDDD3333033A4333D33333333033A4333D333333̙03333333D33̙03333333D33ww̙0#1!DDDDDDww̙0#1!DDDDDDwẅ̈̈0111DDDDDDDwẅ̈̈0111DDDDDDD"""1333333DD"""1333333DDDDDDDDDDDD!DDDDDDDDD!DDDDDDDDD!"!"ffffffffwww!"!"ffffffffwww!""!!fffwwww!""!!fffwwww!"""""fffww!"""""fffwwffffffffM-- title: Knife 2 Meet U -- author: Anything & Nelson "darltrash" Lopez -- desc: Knife things up! -- script: lua -- saveid: KNIFETOMEETYA -- Original game made by Anything Anarchy. -- https://github.com/Anything-is-A-Dev/knife-to-meet-you --[[ Copyright (C) 2021 Nelson "darltrash" Lopez This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. ]] --[[ All music, sprites and tiles were made by Nelson "darltrash" Lopez and they're all covered by the CC-BY-SA 4.0 License. More info down here: https://creativecommons.org/licenses/by-sa/4.0/legalcode ]] local function lerp(a, b, t) return a * (1-t) + b * t end local function elerp(a, b, t) return lerp(a, b, 1-math.exp(-t)) end local function dist(x1, y1, x2, y2) return math.sqrt((x2-x1)^2 + (y2-y1)^2) end local function clamp(min, num, max) return math.max(min, math.min(num, max)) end local function aabb(x1,y1,w1,h1, x2,y2,w2,h2) return x1 < x2+w2 and x2 < x1+w1 and y1 < y2+h2 and y2 < y1+h1 end local function checkp(ent, p) if dist(p.x, p.y, ent.x, ent.y)<5 then p.gnawled = true ent.die = true sfx(15, "F-4", -1, 3) end end local w, h = 240, 136 local state = { current = 0, paused = false, -- 0: Intro -- 1: Main Menu -- 2: Main Game -- 3: Deeeeeathhh -- 4: Cool! New highscore! currentSplash = nil, splashes = { "wow so original!", "it's like arcade\nbut without the fun!", "die in one hit!", "music composed by\nneil wolfkid!", "goats are coming 4 u!", "graphics made by\nneil wolfkid!", "shameless clone!", "coded by neil wolfkid!", "this one splash is too large to be here!", "ideas by\nAnything Anarchy!", "100% lua!", "100% made with\ndeveloper tears!", "made in tic-80!", "no fun ensured!", "not closed source!", "falta traduccion\na espa*ol!", "metahome might wait.", "v a p o r w a r e", "knife things up!", "no macOS version\nbecause it's a pain!", "not like superhot!", "windows 11\ncompatible!", "left4knife2!", "the antithesis\nto undertale!", "made in more than 3 days!", "itch.io exclusive!", "overused art style!", "developed in linux!", "original by Anything!", "this is an easter egg!", -- i see you "maybe runs in haiku!", "", "sin(time()*0.06)!", "hyperrealistic goat\ncreepypasta monster!", "not very fun!", "not gluten free!", "handle knives carefully!", "a lot of effort went\ninto this game!", "videogame violence!", "i got bored of writing\nmore splashes!", "DANGER! is dangerous!", "sus.", "covered by the\nZLIB/LibPNG license!", "\"Wdym breaking bads-\nawesome\" - Anything." }, deathMessages = { "oh man, you'll get em' next time =)", "yup, you gotta be careful with those", "Rest In Peace, fellow yellow knifer", "goodbye cruel world!", "damn, almost got em'", "i died many times while betatesting,\nif that makes you feel better...", "if you're getting stressed, it might\nbe a good idea to take a break", "you tried and that's important!" }, transitionPercent = -50, introColor = 0, introMusic = false, menuT = false, menuX = 0, entitySort = function(a, b) return a.z b.score end, scoreRead = function(self) for k=1, 7 do local t = (k-1)*8 local str = "" for n=0, 6 do str = str .. string.char(pmem(t+n)) end table.insert(self.scores, { name = str, score = pmem(t+7), filled = pmem(t+7)>0 }) end table.sort(self.scores, self.scoreSort) end, scoreSave = function(self) for k, score in ipairs(self.scores) do local t = (k-1)*8 for n=0, 6 do pmem(t+n, string.byte(score.name:sub(n+1, n+1))) end pmem(t+7, score.score) end end, spawnTimer = 0, spawnRate = 70, zoneDangers = {}, dangerPercent = 30, animations = { player = {256, 258, 256, 260}, explosion = {288, 290, 292, 294, 296, 298, 300, 302}, portal = {320, 322, 324, 326, 328, 330, 332, 334}, goatmonster = {352, 354}, pumpkinevil = {356, 358} }, systems = { [0] = function(ent, state, delta) if ent.gnawled then ent.spr = 262 state.transitionPercent = -50 return 0, 0 end state.playerRef = ent ent.anim = ent.anim+delta*0.15 local mx, my, ml = mouse() local vx, vy, vm = 0, 0, 3 ent.flip = (mx>ent.x) and 0 or 1 local angle = math.atan2(ent.x-mx, ent.y-my)+(math.pi*1.5) local _ax = math.cos(angle) local _ay = math.sin(angle) ent.z = ent.y-16 -- knifeee ent.knifeX = ent.x+(_ax*-16)-4 ent.knifeY = ent.y+(_ay* 10) spr(264, ent.knifeX, ent.knifeY, 0, 1, ent.flip) if ml and dist(ent.x, ent.y, mx, my)>2 then vx = _ax*-vm vy = _ay* vm else ent.anim = 1 end if ent.anim>5 then ent.anim = 1 end ent.spr = state.animations.player[math.floor(ent.anim)] return vx/4, vy/4 end, [1] = function (ent, state, delta) ent.anim = (ent.anim or 1)+delta*0.15 if ent.anim>9 then ent.dying = true return 0, 0 end ent.z = ent.y-16 ent.spr = state.animations.explosion[math.floor(ent.anim)] ent.shadowScale = (9-ent.anim)/8 if not ent.scoreAdded then state.playerRef.score = state.playerRef.score + ent.scoreAdd ent.scoreAdded = true sfx(14, "C-5", -1, 3) end print("+"..ent.scoreAdd, ent.x, ent.y, 5) return 0, 0 end, [2] = function (ent, state, delta) ent.anim = (ent.anim or 1)+delta*0.15 if ent.anim>9 then ent.anim = 1 ent.sys = (math.random(1, 4)>2) and 4 or 3 ent.shadowScale = 1 sfx(8, math.random(36, 48), -1, 3, 5) return 0, 0 end ent.z = ent.y-16 ent.spr = state.animations.portal[math.floor(ent.anim)] ent.shadowScale = ent.anim/8 return 0, 0 end, [3] = function (ent, state, delta) local p = state.playerRef local angle = math.atan2(ent.x-p.x, ent.y-p.y)+(math.pi*1.5) local _ax = -math.cos(angle) local _ay = math.sin(angle) ent.z = ent.y-16 ent.flip = (p.x>ent.x) and 0 or 1 checkp(ent, p) if ent.gnawled or dist(p.knifeX, p.knifeY, ent.x, ent.y)<8 then ent.anim = 1 ent.sys = 1 ent.scoreAdd = math.random(1, 2) sfx(15, "F-6", -1, 3) end ent.anim = (ent.anim or 1)+delta*0.15 if ent.anim>3 then ent.anim = 1 end ent.spr = state.animations.goatmonster[math.floor(ent.anim)] return _ax*0.6, _ay*0.6 end, [4] = function (ent, state, delta) local p = state.playerRef local angle = math.atan2(ent.x-p.x, ent.y-p.y)+(math.pi*1.5) local _ax = -math.cos(angle) local _ay = math.sin(angle) ent.z = ent.y-16 ent.flip = (p.x>ent.x) and 0 or 1 checkp(ent, p) if ent.gnawled or dist(p.knifeX, p.knifeY, ent.x, ent.y)<8 then ent.anim = 1 ent.sys = 1 ent.scoreAdd = math.random(1, 2) sfx(15, "F-6", -1, 3) end ent.anim = (ent.anim or 1)+delta*0.15 if ent.anim>3 then ent.anim = 1 end ent.spr = state.animations.pumpkinevil[math.floor(ent.anim)] return _ax*0.8, _ay*0.7 end }, modes = { [0] = function(self, delta) cls(0) self.introColor = self.introColor + delta/7 local c = math.floor(self.introColor) if c<16 and c>1 then if not self.introMusic then self.introMusic = true music(0) end local introText = " A game made by \nAnything and Neil Wolkfid" local tw = print(introText, 0, -16) print(introText, (w-tw)//2, (h-6)//2, math.max(c, 12)) end if (c>18) or keyp() then self.current = 1 self.transitionPercent = 100 music() end end, [1] = function(self, delta) self.transitionPercent = self.transitionPercent - delta*3 local _, _, ml, mc, mr = mouse() local mp = ml or mc or mr -- if the transition is done -- and if any key (incl mouse) is down if self.transitionPercent<=0 and (keyp() or mp) then self.menuT = true -- enable swipe transition end -- if swiping enabled, then swipe! if self.menuT then self.menuX = elerp(self.menuX, -w*0.8, delta*0.07) if self.menuX<-w*0.73 then self.current = 2 -- once done, move to the actual game music(4) end end cls(0) map() print("Score: 0", 1, 2, 1) print("Score: 0", 1, 1, 4) -- wooow, wobblyyyy :D for y=0,h do line(self.menuX, y, self.menuX+(w*0.7)+(math.sin((time()+y*90)*0.002)*4), y, 0) end -- pick random splash (if not picked already) if not self.currentSplash then self.currentSplash = self.splashes[math.random(1, #self.splashes)] music(3) end -- draw game's title + random splash print("k2mu.tic", 20+(self.menuX*1.5), 21, 3, false, 3) print("k2mu.tic", 20+(self.menuX*1.5), 20, 4, false, 3) print(self.currentSplash, 20+(self.menuX*2), 38, 14) print(self.currentSplash, 20+(self.menuX*2), 37, 12) print("Press any key to play", 20+(self.menuX*2.5), 121, 15) print("Press any key to play", 20+(self.menuX*2.5), 120, 13) -- draw all the high scores print("High Scores ============;", 20+(self.menuX*3), 61, 2) print("High Scores ============;", 20+(self.menuX*3), 60, 4) for c, score in ipairs(self.scores) do if score.filled then local color = 12 if c>1 then color = 5+math.floor((c-2)/2) end if score.name=="PUMPKIN" then color = 3 end print(score.name..(" "):rep(12-#tostring(score.score))..score.score, 20+(self.menuX*(1+(c*0.05))), 62+(c*7), color, true ) if color==12 then print("*", 13+(self.menuX*(1+(c*0.05))), 69) end else print("NOTHING"..(" "):rep(11)..score.score, 20+(self.menuX*(1+(c*0.05))), 62+(c*7), 15, true ) end end end, [2] = function(self, delta) if not self.playerRef then self.entities = { { x=32, y=32, sys=0, spr=256, anim=1, score = 0} } self.playerRef = self.entities[1] end if self.playerRef.gnawled then cls(0) map() music() local qw, qh = (w-18)/2, (h-20)/2 local index = 0 for x=0, 1 do for y=0, 1 do local rx, ry = 10+(x*qw), 17+(y*qh) if self.zoneDangers[index]>300 then rx = rx + math.cos(time()/400) ry = ry + math.sin(time()/400) rectb(rx, ry, qw-1, qh-1, 2) for _, ent in ipairs(self.entities) do if aabb(ent.x, ent.y, 16, 16, rx, ry, qw, qh) then ent.gnawled = true end end goto continue end if self.zoneDangers[index]>200 then rectb(rx, ry, qw-1, qh-1, 2) rectb(rx+1, ry+1, qw-3, qh-3, 2) print("DANGER!", rx+16, ry+23, 4, false, 2) end ::continue:: index = index + 1 end end -- render entity shadows for _, ent in ipairs(self.entities) do if not ent.dying then local s = ent.shadowScale or 1 local w, h = 8*s, 2*s elli(ent.x, ent.y+w, w, h, 0) end end -- draw entities for _, ent in ipairs(self.entities) do if not ent.dying then spr(ent.spr, ent.x-8, ent.y-8, 0, 1, ent.flip, 0, 2, 2) end end if self.transitionPercent<-50 then self.transitionPercent = -50 end self.transitionPercent = self.transitionPercent + delta*3 if self.transitionPercent>=100 then if self.scores[1].scoreself.spawnRate then local enemyX, enemyY = 0, 0 repeat enemyX = math.random(16, w-16) enemyY = math.random(16, h-16) until dist(enemyX, enemyY, self.playerRef.x, self.playerRef.y)>30 table.insert(self.entities, { x = enemyX, y = enemyY, sys = 2 }) self.spawnTimer = 0 end self.spawnTimer = self.spawnTimer + delta -- render entity shadows for _, ent in ipairs(self.entities) do local s = ent.shadowScale or 1 local w, h = 8*s, 2*s elli(ent.x, ent.y+w, w, h, 0) end if self.playerRef then local qw, qh = (w-18)/2, (h-20)/2 local index = 0 for x=0, 1 do for y=0, 1 do local rx, ry = 10+(x*qw), 17+(y*qh) self.zoneDangers[index] = (self.zoneDangers[index] or 0) if aabb( self.playerRef.x, self.playerRef.y, 16, 16, rx, ry, qw, qh) or self.zoneDangers[index]>200 then self.zoneDangers[index] = self.zoneDangers[index] + delta * 0.5 else self.zoneDangers[index] = self.zoneDangers[index] - delta * 0.2 end self.zoneDangers[index] = clamp(0, self.zoneDangers[index], 400) if self.zoneDangers[index]>300 then if (time()*300) % 2 == 0 then sfx(11, "D#3", -1, 3) end rx = rx + math.cos(time()/5) ry = ry + math.sin(time()/5) rectb(rx, ry, qw-1, qh-1, 2) rectb(rx+1, ry+1, qw-3, qh-3, 2) for _, ent in ipairs(self.entities) do if aabb(ent.x-8, ent.y, 16, 2 , rx, ry, qw, qh) then ent.gnawled = true end end if self.zoneDangers[index]>380 then self.zoneDangers[index] = 0 end goto continue end if self.zoneDangers[index]>200 then rectb(rx, ry, qw-1, qh-1, 4) rectb(rx+1, ry+1, qw-3, qh-3, 4) if math.floor(time()/300)%2==0 then print("DANGER!", rx+16, ry+23, 4, false, 2) sfx(9, "C-4", -1, 3) end end ::continue:: index = index + 1 end end end -- render cursor local mx, my, ml = mouse() elli( clamp(16, mx, w-16), clamp(16, my, h-12), 6, 1, ml and 4 or 3 ) -- process entities and draw them local nextgen = {} for _, ent in ipairs(self.entities) do -- process entity and obtain output velocity local vx, vy = self.systems[ent.sys](ent, self, delta) -- apply velocity + border collision resolution ent.x = clamp(16, ent.x + vx*delta, w-16) ent.y = clamp(8, ent.y + vy*delta, h-16) -- draw entity spr(ent.spr, ent.x-8, ent.y-8, 0, 1, ent.flip, 0, 2, 2) if not ent.dying then -- if the entity is "dying", make it disappear table.insert(nextgen, ent) end end -- sort entities by depth table.sort(nextgen, self.entitySort) self.entities = nextgen -- apply changes -- draw borders again... for x=1, (w/8)-2 do spr(16, x*8, h-8) end for y=0, h/8 do spr(16, 0, y*8) spr(16, w-8, y*8) end -- draw score if self.playerRef then local newRec = "" -- if there's a new record, say it on the score if self.scores[1].score= 100 then self.inDeathMode = false self.enableWobble = false self.deathModeOut = false self.current = 1 self.menuX = 0 self.menuT = false self.currentSplash = nil self.playerRef = nil music() return end else self.transitionPercent = self.transitionPercent - delta*3 local _, _, ml, mc, mr = mouse() local mp = ml or mc or mr if keyp() or mp then self.deathModeOut = true self.transitionPercent = -50 end end self.enableWobble = true if not self.inDeathMode then music(2, -1, -1, false, true) self.inDeathMode = true self.currentDeathMessage = self.deathMessages[math.random(1, #self.deathMessages)] for index=0, 3 do self.zoneDangers[index] = 0 end end cls(0) local txt = "You died;" local tw = print(txt, 20, -h, 4, false, 3) for y=1, 3 do print(txt, (w-tw)//2, 40+(4-y), 0+y, false, 3) end print(txt, (w-tw)//2, 40, 4, false, 3) local txt = '"'..self.currentDeathMessage..'"' local tw = print(txt, 0, -h) print(txt, (w-tw)//2, (h/2)+2, 7) print(txt, (w-tw)//2, (h/2)+1, 5) txt = "Press any key to go back." tw = print(txt, 0, -h) print(txt, (w-tw)//2, (h/2)+45, 14) print(txt, (w-tw)//2, (h/2)+44, 12) end, [4] = function(self, delta) if self.deathModeOut then self.transitionPercent = self.transitionPercent + delta*3 if self.transitionPercent >= 100 then self.inDeathMode = false self.deathModeOut = false self.current = 1 self.menuX = 0 self.menuT = false self.currentSplash = nil self.playerRef = nil music() return end else self.transitionPercent = self.transitionPercent - delta*3 self.transitionPercent = math.max(self.transitionPercent, -50) end cls(0) if not self.inDeathMode then self.inDeathMode = true music(5) self._name = "" end for i=1, 26 do if keyp(i) then if #self._name==7 then sfx(08) else sfx(12) self._name = self._name .. string.char(64+i) end end end if keyp(51) then if #self._name>0 then sfx(14) self._name = self._name:sub(1, #self._name-1) else sfx(08) end end local txt = "==== New highscore! ====" local tw = print(txt, 0, -16) print(txt, (w//2)-(tw//2), 41, 2) print(txt, (w//2)-(tw//2), 40, 4) local txt = "Use the keyboard to write your name,\n press intro/enter when ready" local tw = print(txt, 0, -16) print(txt, (w//2)-(tw//2), 76, 15) local txt = self._name local tw = print(txt, 0, -w, 12, false, 4) print(txt, (w//2)-(tw//2), 52, 7, false, 4) print(txt, (w//2)-(tw//2), 50, 5, false, 4) if keyp(50) and not self.deathModeOut then table.insert(self.scores, { name = self._name .. (" "):rep(7-#self._name), score = self.playerRef.score, filled = true }) table.sort(self.scores, self.scoreSort) self.scores[8] = nil self.deathModeOut = true self:scoreSave() end end } } state.scores = {} state:scoreRead() local paused = false local delta, past = 0, time() function TIC() delta = (time()-past)/16 past = time() state.modes[state.current](state, delta) end function OVR() for x=0, w/8 do for y=0, h/8 do local prc = math.max(0, (state.transitionPercent+x+y)/100) spr(2+math.floor(prc*7), x*8, y*8, 1) end end end wavelimit = 0 function SCN(row) if (row