Monster = {name = 'Monster', health = 100, image = 'gfx/weiwen/circle.png', scalex = 1, scaley = 1, atk = 1, def = 1, spd = 5, x = 0, y = 0, ang = 0, imgang = 0, exp = 5, money = 50, type = 'monster', loot = {}} MONSTERS = {} local t = 0 local SPAWNS = { FULLMAP = {{1, 34}, {18, 51}}, BOTTOMHALF = {{9, 58}, {64, 58}}, BOTTOMMAP = {{5, 71}, {55, 70}}, } CONFIG.MONSTERS = { { name = 'Zombie', health = 100, image = 'gfx/minecraft_npc/zombie.png', scalex = 2, scaley = 2, r = 136, g = 224, b = 32, atk = 1.9, def = 2.1, spd = 6, atkspd = 8, x = 0, y = 0, ang = 0, imgang = 0, runat = 10, spawnchance = {['rpg_mapb'] = {5}}, spawn = { ['rpg_mineraft'] = {SPAWNS.BOTTOMHALF} }, exp = 25, money = 67, loot = {{chance = 5000, id = 102}, {chance = 250, id = 221}}, }, { name = 'Spider', health = 100, image = 'gfx/minecraft_npc/spider.png', scalex = 2, scaley = 2, atk = 2.2, def = 1.8, spd = 6, atkspd = 8, x = 0, y = 0, ang = 0, imgang = 0, runat = 10, spawnchance = {['rpg_mapb'] = {5}}, spawn = { ['rpg_mapb'] = {SPAWNS.BOTTOMMAP} }, exp = 34, money = 24, loot = {{chance = 5000, id = 100}, {chance = 250, id = 222}}, }, { name = 'Creeper', health = 100, image = 'gfx/minecraft_npc/creeper.png', scalex = 2, scaley = 2, atk = 1.9, def = 2.3, spd = 6, atkspd = 8, x = 0, y = 0, ang = 0, imgang = 0, runat = 10, spawnchance = {['rpg_minecraft'] = {5}}, spawn = { ['rpg_mapb'] = {SPAWNS.FULLMAP} }, exp = 45, money = 78, loot = {{chance = 5000, id = 101}, {chance = 250, id = 223}}, spc = {1000, function(self) if self.health < 20 then radiusmsg("Creeper uses selfdestruct!", self.x, self.y) parse('explosion ' .. self.x .. ' ' .. self.y .. ' 128 80') parse('effect "colorsmoke" ' .. self.x .. ' ' .. self.y .. ' 100 128 255 128 0') parse('effect "colorsmoke" ' .. self.x .. ' ' .. self.y .. ' 100 128 255 255 0') self:destroy() end end}, }, { name = 'Zombie Pigman', health = 100, image = 'gfx/minecraft_npc/zombie pigman.png', scalex = 1.5, scaley = 1.5, r = 104, g = 152, b = 40, atk = 3.1, def = 2.2, spd = 7, atkspd = 10, x = 0, y = 0, ang = 0, imgang = 0, runat = 20, spawnchance = {['rpg_minecraft'] = {32}}, spawn = { ['rpg_mapb'] = {SPAWNS.FULLMAP} }, exp = 5, money = 30, loot = {{chance = 8000, id = 1}}, spc = {750, function(self, id, dist) if dist <= 96 then radiusmsg("Zombie Pigman uses horn attack!", self.x, self.y) self:hit(id, 20) end end}, }, { name = 'Skeleton', health = 100, image = 'gfx/minecraft_npc/skeleton.png', scalex = 1.5, scaley = 1.5, r = 104, g = 152, b = 40, atk = 2.2, def = 1.1, spd = 7, atkspd = 10, x = 0, y = 0, ang = 0, imgang = 0, runat = 20, spawnchance = {['rpg_mapb'] = {100}}, spawn = { ['rpg_minecraft'] = {SPAWNS.FULLMAP} }, exp = 100, money = 100, loot = {{chance = 8000, id = 1}}, spc = {750, function(self, id, dist) radiusmsg("Skeleton uses arrow!", self.x, self.y) parse('explosion ' .. self.x .. ' ' .. self.y .. ' 96 40') parse('effect "colorsmoke" ' .. self.x .. ' ' .. self.y .. ' 100 96 255 255 255') parse('effect "colorsmoke" ' .. self.x .. ' ' .. self.y .. ' 75 96 128 128 255') end}, }, } CONFIG.MONSTERSKILLS = { endAgility = function(id) self = MONSTERS[tonumber(id)] self.spd = self._spd self._spd = nil imagecolor(self.image, 255, 255, 255) self.agility = nil end, endRage = function(id) self = MONSTERS[tonumber(id)] self.atk = self._atk self._atk = nil imagecolor(self.image, 255, 255, 255) self.rage = nil end, endHarden = function(id) self = MONSTERS[tonumber(id)] self.def = self._def self._def = nil imagecolor(self.image, 255, 255, 255) self.harden = nil end, } addhook("attack", "MONSTERattack") function MONSTERattack(id) if gettile(PLAYERS[id].x, PLAYERS[id].y).SAFE or gettile(PLAYERS[id].x, PLAYERS[id].y).NOMONSTERS then return end if inarray({400, 401, 402, 403, 404}, PLAYERS[id].Equipment[7]) then message(id, "You may not attack on a horse.") return end local weapon, closest = player(id, 'weapontype') for _, m in ipairs(MONSTERS) do local x, y = player(id, 'x'), player(id, 'y') local dist = math.sqrt((m.x-x)^2+(m.y-y)^2) if dist <= (closest and closest[2] or (CONFIG.WEAPONRANGE[weapon] or CONFIG.WEAPONRANGE[50])) then local rot = player(id, 'rot') if math.abs(math.rad(rot) - math.atan2(y-m.y, x-m.x) + math.pi/2)%(2*math.pi) <= (CONFIG.WEAPONWIDTH[weapon] or CONFIG.WEAPONRANGE[50]) then closest = {m, dist} end end end if closest then closest[1]:damage(id, math.ceil(20*((PLAYERS[id].Level+50)*PLAYERS[id].tmp.atk/closest[1].def)/math.random(60, 140)), weapon) end end addhook("ms100", "MONSTERms100") function MONSTERms100() t = t + 1 if t % 100 == 0 then while #MONSTERS < CONFIG.MAXMONSTERS do local rand, spawnNo, mapName while true do rand = math.random(#CONFIG.MONSTERS) mapName = CONFIG.MONSTERS[rand].spawn[map'name'] and map'name' or CONFIG.DEFAULTMAP spawnNo = math.random(#CONFIG.MONSTERS[rand].spawn[mapName]) if math.random(0, 100) < CONFIG.MONSTERS[rand].spawnchance[mapName][spawnNo] then break end end local m = deepcopy(CONFIG.MONSTERS[rand]) local x, y, tilex, tiley local spawn = m.spawn[mapName][spawnNo] repeat tilex, tiley = math.random(spawn[1][1], spawn[2][1]), math.random(spawn[1][2], spawn[2][2]) until not gettile(tilex, tiley).SAFE and not gettile(tilex, tiley).NOMONSTERS and tile(tilex, tiley, "walkable") and tile(tilex, tiley, "frame") ~= 34 m.x, m.y = math.floor(tilex*32+16), math.floor(tiley*32+16) Monster:new(m) end end for _, m in ipairs(MONSTERS) do if t % m.atkspd == 0 then m.target = nil local closest for _, p in ipairs(table.shuffle(player(0, 'table'))) do if player(p, 'health') > 0 and not gettile(PLAYERS[p].x, PLAYERS[p].y).SAFE and not gettile(PLAYERS[p].x, PLAYERS[p].y).NOMONSTERS then local dist = math.sqrt((player(p, 'x')-m.x)^2 + (player(p, 'y')-m.y)^2) if dist < 400 then if not closest or dist < closest[2] then closest = {p, dist} end end end end if closest then local dist = closest[2] if dist < 400 then m.target = closest[1] if m.spc and math.random(10000) <= m.spc[1] then m.spc[2](m, m.target, dist) elseif dist <= (m.range or 32) then m:hit(m.target, 10) end end end end m.imgang = math.sin(t/2.5*math.pi) * 15 if m.target and player(m.target, 'exists') and player(m.target, 'health') > 0 and not gettile(PLAYERS[m.target].x, PLAYERS[m.target].y).SAFE and not gettile(PLAYERS[m.target].x, PLAYERS[m.target].y).NOMONSTERS then xdist, ydist = player(m.target, 'x') - m.x, player(m.target, 'y') - m.y local dist = math.sqrt(xdist^2 + ydist^2) if dist < 400 then m.ang = math.atan2(ydist, xdist)-math.pi/2+math.random(-1, 1)/2 else m.target = nil end end if not m.target then m:rot(math.random(-1, 1)/2) end if not m:move(m:rot(), m.health > m.runat and 1 or -1) then repeat until m:move(math.rad(math.random(360)), 1) end end end function Monster:new(m) if not (m.x or m.y) then return false end m.image = image(m.image, m.x, m.y, 0) imagescale(m.image, m.scalex, m.scaley) setmetatable(m, self) self.__index = self local n = #MONSTERS+1 MONSTERS[#MONSTERS+1] = m m.id = n return m end function Monster:pos(x, y) if not x and not y then return self.x, self.y else self.x, self.y = x or self.x, y or self.y imagepos(self.image, self.x, self.y, self.imgang) end return true end function Monster:move(dir, amt) local x, y = -math.sin(dir)*amt*self.spd, math.cos(dir)*amt*self.spd local x, y = self.x+x, self.y+y local tilex, tiley = math.floor(x/32), math.floor(y/32) if tile(tilex, tiley, 'walkable') and tile(tilex, tiley, 'frame') ~= 34 and not gettile(tilex, tiley).SAFE and not gettile(tilex, tiley).NOMONSTERS then self:pos(x, y) return true else self:rot(math.random(-1, 1)*math.pi/2) return false end end function Monster:damage(id, dmg, wpntype) if not PLAYERS[id].Tutorial.damagem then message(id, "You have attacked a monster! Good job! Keep on attacking it until it dies.", "255128000") PLAYERS[id].Tutorial.damagem = true end local wpnName if weapon == 251 then wpnName = 'rune' elseif weapon == 46 then wpnName = 'firewave' dmg = dmg/5 else wpnName = PLAYERS[id].Equipment[3] and ITEMS[PLAYERS[id].Equipment[3]].name or 'dagger' end self.health = self.health - dmg --print(player(id, 'name') .. ' deals ' .. dmg .. ' damage to ' .. self.name .. ' usng a ' .. wpnName .. '.') if self.health <= 0 then if not PLAYERS[id].Tutorial.killm then message(id, "Congratulation! You have killed your first monster. You can proceed to pick up the loot by using the drop weapon button (default G)", "255128000") PLAYERS[id].Tutorial.killm = true end addexp(id, math.floor(self.exp*CONFIG.EXPRATE)) self:die() else parse('effect "colorsmoke" ' .. self.x .. ' ' .. self.y .. ' 0 ' .. self.scaley .. ' ' .. (self.r and (self.r .. ' ' .. self.g .. ' ' .. self.b) or '192 0 0')) end radiussound("weapons/machete_hit.wav", self.x, self.y) return true end function Monster:hit(id, dmg) if not PLAYERS[id].Tutorial.hitm then message(id, "A monster is attacking you! You can fight back by swinging your weapon at it.", "255128000") PLAYERS[id].Tutorial.hitm = true end if player(id, 'weapontype') == 41 and (math.abs(math.rad(player(id, 'rot')) - math.atan2(player(id, 'y')-self.y, player(id, 'x')-self.x) + math.pi/2)%(2*math.pi) <= math.pi*2/3) then EXPhit(id, self, -1, dmg/4) radiussound("weapons/ricmetal" .. math.random(1,2) .. ".wav", self.x, self.y) else EXPhit(id, self, -1, dmg) radiussound("weapons/knife_hit.wav", self.x, self.y) end return true end function Monster:die(id) local size = self.scalex+self.scaley parse('effect "colorsmoke" ' .. self.x .. ' ' .. self.y .. ' ' .. size .. ' 64 ' .. (self.r and (self.r .. ' ' .. self.g .. ' ' .. self.b) or '192 0 0')) local tilex, tiley = math.floor(self.x/32), math.floor(self.y/32) spawnitem(1337, tilex, tiley, math.floor(self.money*math.random(50, 150)/100)*CONFIG.MONEYRATE) for _, loot in ipairs(self.loot) do local chance = math.random(10000) if chance <= loot.chance then spawnitem(loot.id, tilex, tiley) end end radiussound("weapons/c4_explode.wav", self.x, self.y) self:destroy() end function Monster:destroy() freeimage(self.image) local found table.remove(MONSTERS, self.id) for i, m in ipairs(MONSTERS) do m.id = i end return true end function Monster:rot(rot) if not rot then return self.ang else self.ang = (self.ang+rot)%(math.pi*2) end return true end