├── README.md └── pico8.lua /README.md: -------------------------------------------------------------------------------- 1 | # pico2tic 2 | 3 | > PICO-8 API Wrapper for TIC-80 (0.80.0) 4 | by [musurca](https://github.com/musurca) and [RobLoach](https://github.com/RobLoach) 5 | 6 | Wraps the PICO-8 API for ease of porting games to the TIC-80. Favors compatibility over performance. 7 | 8 | 9 | ## Known Issues 10 | 11 | * swapping elements in the screen palette--e.g. pal(a,b,1)--doesn't work properly yet. However, pal(a,b) does work 12 | * flip_x and flip_y are currently ignored in spr() and sspr() 13 | * music() and flip() do nothing. sfx() does not take into account offset 14 | * stat(1) always returns "0.5" 15 | -------------------------------------------------------------------------------- /pico8.lua: -------------------------------------------------------------------------------- 1 | --PICO-8 Wrapper for the TIC-80 Computer 2 | --by @musurca 3 | ---------------------------------------- 4 | -- Wraps the PICO-8 API for ease of porting games 5 | -- to the TIC-80. Favors compatibility over performance. 6 | ---------------------------------------- 7 | --known issues: 8 | -- * swapping elements in the screen palette--e.g. pal(a,b,1)--doesn't work properly yet. However, pal(a,b) does work 9 | -- * flip_x and flip_y are currently ignored in spr() and sspr() 10 | -- * music() and flip() do nothing. sfx() does not take into account offset 11 | -- * stat(1) always returns "0.5" 12 | 13 | --set palette 14 | PAL_PICO8="0000001D2B537E2553008751AB52365F574FC2C3C7FFF1E8FF004DFFA300FFEC2700E43629ADFF83769CFF77A8FFCCAA" 15 | function PICO8_PALETTE() 16 | for i=0,15 do 17 | local r=tonumber(string.sub(PAL_PICO8,i*6+1,i*6+2),16) 18 | local g=tonumber(string.sub(PAL_PICO8,i*6+3,i*6+4),16) 19 | local b=tonumber(string.sub(PAL_PICO8,i*6+5,i*6+6),16) 20 | poke(0x3FC0+(i*3)+0,r) 21 | poke(0x3FC0+(i*3)+1,g) 22 | poke(0x3FC0+(i*3)+2,b) 23 | end 24 | end 25 | 26 | --sound 27 | __sfx=sfx 28 | function sfx(n,channel,offset) 29 | --does not support offset as of 0.18.0 30 | if n<0 then 31 | __sfx(0,28,channel,0) 32 | else 33 | __sfx(0,28,channel) 34 | end 35 | end 36 | 37 | function music(n,fadems,channelmask) 38 | --do nothing as of 0.18.0 39 | end 40 | 41 | --utility 42 | function stat(i) 43 | if i==0 then 44 | return collectgarbage("count") 45 | end 46 | return 0.5 47 | end 48 | 49 | --strings 50 | function sub(str,i,j) 51 | return str:sub(i,j) 52 | end 53 | 54 | --permanent cart mem 55 | function cartdata(id) 56 | --do nothing 57 | end 58 | 59 | function dget(i) 60 | return pmem(i) 61 | end 62 | 63 | function dset(i,val) 64 | pmem(i,val) 65 | end 66 | 67 | --tables 68 | add=table.insert 69 | 70 | function all(list) 71 | local i = 0 72 | return function() i = i + 1; return list[i] end 73 | end 74 | 75 | count=table.getn 76 | 77 | function del(t,a) 78 | for i,v in ipairs(t) do 79 | if v==a then 80 | t[i]=t[#t] 81 | t[#t]=nil 82 | return 83 | end 84 | end 85 | end 86 | 87 | function foreach(t, f) 88 | for v in all(t) do 89 | f(v) 90 | end 91 | end 92 | 93 | if mt ~= nil then 94 | mt = {} 95 | end 96 | 97 | --math 98 | srand=math.randomseed 99 | sqrt=math.sqrt 100 | abs=math.abs 101 | min=math.min 102 | max=math.max 103 | flr=math.floor 104 | pi=math.pi 105 | 106 | function rnd(a) 107 | a=a or 1 108 | return math.random()*a 109 | end 110 | 111 | function sgn(a) 112 | if a>=0 then return 1 end 113 | return -1 114 | end 115 | 116 | function cos(a) 117 | return math.cos(2*pi*a) 118 | end 119 | 120 | function sin(a) 121 | return -math.sin(2*pi*a) 122 | end 123 | 124 | function atan2(a,b) 125 | b=b or 1 126 | return math.atan(a,b)/(2*pi) 127 | end 128 | 129 | function mid(a,b,c) 130 | if a<=b and a<=c then return max(a,min(b,c)) 131 | elseif b<=a and b<=c then return max(b,min(a,c)) end 132 | return max(c,min(a,b)) 133 | end 134 | 135 | function band(a,b) 136 | return flr(a)&flr(b) 137 | end 138 | 139 | function bor(a,b) 140 | return flr(a)|flr(b) 141 | end 142 | 143 | function bxor(a,b) 144 | return flr(a)^flr(b) 145 | end 146 | 147 | function bnot(a,b) 148 | return flr(a)~flr(b) 149 | end 150 | 151 | function shl(a,b) 152 | return a<>b 157 | end 158 | 159 | --graphics 160 | __p8_color=7 161 | __p8_ctrans={true,false,false,false,false,false,false,false, 162 | false,false,false,false,false,false,false,false} 163 | __p8_camera_x=0 164 | __p8_camera_y=0 165 | __p8_cursor_x=0 166 | __p8_cursor_y=0 167 | __p8_sflags={} 168 | for i=1,256 do 169 | __p8_sflags[i]=0 170 | end 171 | 172 | function camera(cx,cy) 173 | cx=cx or 0 174 | cy=cy or 0 175 | __p8_camera_x=-flr(cx) 176 | __p8_camera_y=-flr(cy) 177 | end 178 | 179 | function cursor(cx,cy) 180 | cx=cx or 0 181 | cy=cy or 0 182 | __p8_cursor_x=flr(cx) 183 | __p8_cursor_y=flr(cy) 184 | end 185 | 186 | function __p8_coord(x,y) 187 | return flr(x+__p8_camera_x), 188 | flr(y+__p8_camera_y) 189 | end 190 | 191 | __print=print 192 | function print(str,x,y,c) 193 | x=x or __p8_cursor_x 194 | y=y or __p8_cursor_y 195 | c=c or __p8_color 196 | c=peek4(0x7FE0+c) 197 | __print(str,x,y,c) 198 | __p8_cursor_y=y+8 199 | end 200 | 201 | function color(c) 202 | c=c or 7 203 | __p8_color=flr(c%16) 204 | end 205 | 206 | function pal(c0,c1,type) 207 | c0=c0 or -1 208 | c1=c1 or -1 209 | type=type or 0 210 | 211 | if c0<0 and c1<0 then 212 | if type==0 then 213 | for i=0,15 do 214 | poke4(0x7FE0+i,i) 215 | end 216 | else 217 | PICO8_PALETTE() 218 | end 219 | else 220 | c0=flr(c0%16) 221 | if c1<0 then 222 | c1=c0 223 | end 224 | c1=flr(c1%16) 225 | if type==0 then 226 | poke4(0x7FE0+c0,c1) 227 | else 228 | local stri 229 | for i=0,5 do 230 | stri=#__p8_pal-(c1+1)*6+i 231 | poke4(0x3FC0*2+#__p8_pal-(c0+1)*6+i,tonumber(__p8_pal:sub(stri,stri),16)) 232 | end 233 | end 234 | end 235 | end 236 | 237 | function palt(c,trans) 238 | c=c or -1 239 | if c<0 then -- reset 240 | __p8_ctrans[1]=true 241 | for i=2,16 do 242 | __p8_ctrans[i]=false 243 | end 244 | else 245 | __p8_ctrans[flr(c%16)+1]=trans 246 | end 247 | end 248 | 249 | function pset(x,y,c) 250 | c=c or __p8_color 251 | c=peek4(0x7FE0+c) 252 | x,y=__p8_coord(x,y) 253 | poke4(y*240+x,c) 254 | end 255 | 256 | function pget(x,y) 257 | x,y=__p8_coord(x,y) 258 | return peek4(y*240+x) 259 | end 260 | 261 | __rect=rect 262 | function rectfill(x0,y0,x1,y1,c) 263 | c=c or __p8_color 264 | c=peek4(0x7FE0+c) 265 | x0,y0=__p8_coord(x0,y0) 266 | x1,y1=__p8_coord(x1,y1) 267 | local w,h=x1-x0,y1-y0 268 | __rect(x0,y0,w+sgn(w),h+sgn(h),c) 269 | end 270 | 271 | function rect(x0,y0,x1,y1,c) 272 | c=c or __p8_color 273 | c=peek4(0x7FE0+c) 274 | x0,y0=__p8_coord(x0,y0) 275 | x1,y1=__p8_coord(x1,y1) 276 | local w,h=x1-x0,y1-y0 277 | rectb(x0,y0,w+sgn(w),h+sgn(h),c) 278 | end 279 | 280 | __circ=circ 281 | function circfill(x,y,r,c) 282 | c=c or __p8_color 283 | c=peek4(0x7FE0+c) 284 | x,y=__p8_coord(x,y) 285 | __circ(x,y,r,c) 286 | end 287 | 288 | function circ(x,y,r,c) 289 | c=c or __p8_color 290 | c=peek4(0x7FE0+c) 291 | x,y=__p8_coord(x,y) 292 | circb(x,y,r,c) 293 | end 294 | 295 | __line=line 296 | function line(x0,y0,x1,y1,c) 297 | c=c or __p8_color 298 | c=peek4(0x7FE0+c) 299 | x0,y0=__p8_coord(x0,y0) 300 | x1,y1=__p8_coord(x1,y1) 301 | __line(x0,y0,x1,y1,c) 302 | end 303 | 304 | function sspr(sx,sy,sw,sh,dx,dy,dw,dh) -- todo 305 | dw=dw or sw 306 | dh=dh or sh 307 | dx,dy=__p8_coord(dx,dy) 308 | if dx>240 or dy>136 then return end 309 | local xscale,yscale=dw/sw,dh/sh 310 | local startx,starty,c=0,0 311 | if dx<0 then startx=-dx end 312 | if dy<0 then starty=-dy end 313 | if dx+dw>240 then dw=240-dx end 314 | if dy+dh>136 then dh=136-dy end 315 | for x=startx,dw-1 do 316 | for y=starty,dh-1 do 317 | c=sget(sx+x/xscale,sy+y/yscale) 318 | c=peek4(0x7FE0+c) 319 | if not __p8_ctrans[c+1] then 320 | poke4((dy+y)*240+dx+x,c) 321 | end 322 | end 323 | end 324 | end 325 | 326 | __spr=spr 327 | function spr(n,x,y,w,h) --todo flip_x,y 328 | w=w or 1 329 | h=h or 1 330 | local sx,sy,xoff,yoff=n%16*8,flr(n/16)*8,0,0 331 | for j=0,h-1 do 332 | for i=0,w-1 do 333 | sspr(sx+xoff,sy+yoff,8,8,x+xoff,y+yoff) 334 | --__spr(n+j*16+i,x+i*8,y+j*8,__p8_ctrans) 335 | xoff=xoff+8 336 | end 337 | yoff=yoff+8 338 | xoff=0 339 | end 340 | end 341 | 342 | __map=map 343 | function map(cel_x,cel_y,sx,sy,cel_w,cel_h) 344 | sx,sy=__p8_coord(sx,sy) 345 | local cel 346 | for cy=0,cel_h-1 do 347 | for cx=0,cel_w-1 do 348 | cel=mget(cx+cel_x,cy+cel_y) 349 | spr(cel,sx+cx*8,sy+cy*8) 350 | end 351 | end 352 | 353 | --__map(cel_x,cel_y,cel_w,cel_h,sx,sy,__p8_ctrans) 354 | end 355 | mapdraw=map 356 | 357 | function sset(x,y,c) 358 | x,y=flr(x),flr(y) 359 | local addr=0x8000+64*(flr(x/8)+flr(y/8)*16) 360 | poke4(addr+(y%8)*8+x%8,c) 361 | end 362 | 363 | function sget(x,y) 364 | x,y=flr(x),flr(y) 365 | local addr=0x8000+64*(flr(x/8)+flr(y/8)*16) 366 | return peek4(addr+(y%8)*8+x%8) 367 | end 368 | 369 | function flip() 370 | --do nothing 371 | end 372 | 373 | --sprite flags 374 | function fset(n,f,v) 375 | if f>7 then 376 | __p8_sflags[n+1]=f 377 | else 378 | local flags=__p8_sflags[n+1] 379 | if v then 380 | flags=flags|(1<0 then return true end 395 | return false 396 | end 397 | 398 | --input 399 | pico8ButtonMap = {} 400 | pico8ButtonMap[1] = 2 -- 0 left 401 | pico8ButtonMap[2] = 3 -- 1 right 402 | pico8ButtonMap[3] = 0 -- 2 up 403 | pico8ButtonMap[4] = 1 -- 3 down 404 | pico8ButtonMap[5] = 4 -- 4 o 405 | pico8ButtonMap[6] = 5 -- 5 x 406 | pico8ButtonMap[7] = 6 -- 6 start 407 | pico8ButtonMap[8] = 7 -- 7 Doesn't exist 408 | function pico8ButtonToTic80(i, p) 409 | if p == nil then 410 | p = 0 411 | end 412 | return p * 8 + pico8ButtonMap[i + 1] 413 | end 414 | __btn = btn 415 | function btn(i, p) 416 | return __btn(pico8ButtonToTic80(i, p)) 417 | end 418 | __btnp = btnp 419 | function btnp(i, p) 420 | return __btnp(pico8ButtonToTic80(i, p)) 421 | end 422 | 423 | -- TIC function to call pico-8 callbacks. 424 | __updateTick = true 425 | __initalized = false 426 | function TIC() 427 | -- Initialize 428 | if __initalized == false then 429 | PICO8_PALETTE() 430 | if _init ~= nil then 431 | _init() 432 | end 433 | __initalized = true 434 | end 435 | 436 | -- Update and Draw 437 | if _update60 ~= nil then -- 60 FPS 438 | _update60() 439 | if _draw ~= nil then _draw() end 440 | elseif _update ~= nil then -- 30 FPS 441 | if __updateTick then 442 | _update() 443 | if _draw ~= nil then _draw() end 444 | end 445 | __updateTick = not __updateTick 446 | end 447 | end 448 | 449 | -- Add pico-8 cart below! 450 | --------------------------------------------------------------------------------