--cd("/cirnofarm/src") --include("/cirnofarm/src/cirno.lua") function make_path(name) local base_path = "/cirnofarm/src/" -- Change this when releasing return base_path .. name end local _modules = {} function loadfile (filename) local src = fetch(filename) if (type(src) ~= "string") then notify("could not include "..filename) stop() return end -- https://www.lua.org/manual/5.4/manual.html#pdf-load -- chunk name (for error reporting), mode ("t" for text only -- no binary chunk loading), _ENV upvalue -- @ is a special character that tells debugger the string is a filename local func,err = load(src, "@"..filename, "t", _ENV) -- syntax error while loading if (not func) then send_message(3, {event="report_error", content = "*syntax error"}) send_message(3, {event="report_error", content = tostr(err)}) stop() return end return func end function require(name) local already_imported = _modules[name] if already_imported ~= nil then return already_imported end local filename = fullpath(name:gsub ('%.', '/') ..'.lua') local func = loadfile (filename) local module = func(name) _modules[name]=module return module end --local strawberry = require(make_path("strawberry")) --strawberry.func() local Cirno = require(make_path("cirno")) local mouse_debug = require(make_path("mouse_debug")) local map_manager = require(make_path("map")) local weapons_manager = require(make_path("weapons")) local Barrel = require(make_path("barrel")) local Strawberry = require(make_path("strawberry")) local Box = require(make_path("box")) local NPC = require(make_path("npc")) include(make_path("pgui" .. ".lua")) particles_list = { BLINK={ life=4, spriteIndex=81 }, EXPLOSION={ life=8, spriteIndex=83 } } bullets_list = { BASIC={ spriteIndex=80, damage=1, speed=2, life=100, radius=4, particle=particles_list.BLINK } } weapons_list = { ICE_BLASTER={ name = "Ice Blaster", rate_of_fire = 8, bullet=bullets_list.BASIC, spriteIndex=104, --shoot=function(self,x,y,dir_x,dir_y) -- create_bullet(self.bullet, x, y, dir_x, dir_y) --end }, SPAGHETTI={ name = "Spaghetti", rate_of_fire = 80, bullet=bullets_list.BASIC, spriteIndex=105, } } LAYERS = { {index=4, name="background", render=true, render_objects=false, spawn_objects=false}, {index=3, name="solid", render=true, render_objects=true, spawn_objects=false}, {index=2, name="foreground", render=true, render_objects=false, spawn_objects=false}, {index=1, name="objects", render=false, render_objects=false, spawn_objects=true} } actors_db = { {name="teleporter",sprite=88,actor=nil}, {name="barrel",sprite=3,actor=Barrel}, {name="strawberry",sprite=72,actor=Strawberry}, {name="player",sprite=65,actor=nil}, {name="box",sprite=4,actor=Box}, {name="alarm",sprite=19,actor=nil}, {name="fan",sprite=16,actor=nil}, {name="NPC",sprite=69,actor=NPC} } tile_width = 16 tile_height = 16 function _init() spawn_objects() cirnoInstance = Cirno.init() add(actors,cirnoInstance) slidervalue = 10 end function _update() --cirno.update() pgui:refresh() weapons_manager.update() for a in all(actors) do a:update() end for b in all(bullets) do b:update() end for p in all(particles) do p:update() end check_collisions() --slidervalue = pgui:component("hslider",{pos=vec(190,20),value=slidervalue}) pgui:component("vstack",{stroke=true,pos=vec(0,0),color={0,18,12,0,7,6},height=0,margin=3,gap=3,contents={ {"text_box",{text=string.format("x: %.2f y: %.2f", cirnoInstance.x, cirnoInstance.y),margin=2,stroke=true,active=false,hover=false},color={0,18,12,0,7,6}}, {"text_box",{text=string.format("mx: %.2f my: %.2f", cirnoInstance.move_x, cirnoInstance.move_y),margin=2,stroke=true,active=false,hover=false}}, {"text_box",{text=string.format("Actors: %d", count(actors)),margin=2,stroke=true,active=false,hover=false}}, {"text_box",{text=string.format("%.4f %dfps",stat(1),stat(7)),margin=2,stroke=true,active=false,hover=false}}, {"text_box",{text=string.format("Bullets: %d", count(bullets)),margin=2,stroke=true,active=false,hover=false}}, {"text_box",{text=string.format("Particles: %d", count(particles)),margin=2,stroke=true,active=false,hover=false}}, {"text_box",{text=string.format("Weapon: %s", cirnoInstance.weapon.data.name),margin=2,stroke=true,active=false,hover=false}}, {"text_box",{text=string.format("Weapon timer: %d", cirnoInstance.weapon.timer),margin=2,stroke=true,active=false,hover=false}}, {"sprite_box",{sprite=cirnoInstance.weapon.data.spriteIndex,margin=2,stroke=true,active=false,hover=false}}, }}) --pgui:component("text_box",{text=string.format("Actors: %d", count(actors)),margin=2,stroke=true,active=false,hover=false}) end actors = {} bullets = {} particles = {} function _draw() cls(0) camera(cirnoInstance.x - 240, cirnoInstance.y - 135) foreach(LAYERS, render_layer) local mx,my = mouse() mouse_debug.draw(mx,my,4, tile_width, tile_height) camera() -- Draw UI draw_ui() weapons_manager.debug_draw() --circfill(240,140,slidervalue,8) end function draw_ui() pgui:draw() --print(string.format("Actors: %d", count(actors)),0,32+8) --print(string.format("%.4f %dfps",stat(1),stat(7)),2,16,5) end include(make_path("error_explorer") .. ".lua") function spawn_objects() -- Map width and height, TODO: unhardcode local width = 32 local height = 32 for x=0,width,1 do for y=0,height,1 do local tile = map_manager.get_layer_tile(x,y,1) local a = get_actor_from_sprite(tile) if (a) then local ai = a:new(x*tile_width,y*tile_height) --local ai = Barrel:new(x*tile_width,y*tile_height) --error("ads") add(actors,ai) end -- if (tile == 3) then -- local b = Barrel:new(x*tile_width,y*tile_height) -- add(actors,b) -- elseif(tile == 72) then -- local s = Strawberry:new(x*tile_width,y*tile_height) -- add(actors,s) -- end end end end function get_actor_from_sprite(sprite) local res = nil for a in all(actors_db) do if (a.sprite == sprite) then res = a.actor end end return res end function render_layer(layer) if (layer.render) then -- todo move function in map manager map(fetch("map/".. map_manager.get_current_map() .. ".map")[layer.index].bmp) end if (layer.render_objects) then -- Render all objects here --cirno.draw() weapons_manager.draw() for b in all(actors) do b:draw() end for b in all(bullets) do b:draw() end for p in all(particles) do p:draw() end end end function distance(x1, y1, x2, y2) return math.sqrt((x2 - x1)^2 + (y2 - y1)^2) end function collided(act, bul) -- Calculate distance between actor and bullet local dist = distance(act.x, act.y, bul.x, bul.y) -- Check if distance is less than actor's half size and bullet's radius return dist < (bul.radius + math.min(act.w, act.h) / 2) end function check_collisions() for _, actor in ipairs(actors) do if (actor.shootable) then for _, bullet in ipairs(bullets) do if collided(actor, bullet) --[[and not bullet.destroyed]] then -- Destroy bullet bullet:destroy() -- Damage actor actor:damage(bullet.damage) end end end end end function raycast(x1, y1, x2, y2, max_distance) local dx = x2 - x1 local dy = y2 - y1 local step_x = dx > 0 and 1 or -1 local step_y = dy > 0 and 1 or -1 dx = dx < 0 and -dx or dx dy = dy < 0 and -dy or dy local fraction = dx - dy local x = x1 local y = y1 -- calculate the distance between start and end point local distance = (math.sqrt((x2-x1)^2 + (y2-y1)^2))\1 local scale = max_distance / distance local px = x1 + (x2 - x1) * scale local py = y1 + (y2 - y1) * scale -- limit the maximum distance if distance > max_distance then --return x2, y2, false return px, py, false end -- checking the start point --if map_manager.is_tile_shoot_solid(flr(x / tile_width), flr(y / tile_height)) then if map_manager.is_tile_shoot_solid(x, y) then return x1, y1, false end local distance_traveled = 0 while distance_traveled <= max_distance and (x ~= x2 or y ~= y2) do local prevX = x -- store previous positions for distance calculation local prevY = y if fraction >= 0 then x += step_x fraction -= dy else y += step_y fraction += dx end -- calculate distance traveled distance_traveled += math.sqrt((x - prevX) ^ 2 + (y - prevY) ^ 2)\1 -- return false as soon as a solid tile is hit if map_manager.is_tile_shoot_solid(x, y) then if x==x2 and y==y2 then -- return true only if hit tile is destination tile return x, y, true else return x, y, false end end end -- if the loop is done without hitting a solid tile, return false return x2, y2, true end