mapgen/game/1_maze.coffee
Alexander Yakovlev 9b46fcdd52
All checks were successful
default/mapgen/master This commit looks good
Bugfixes
2018-10-14 18:57:10 +07:00

271 lines
8.8 KiB
CoffeeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class Maze
# карта игры
# для простоты мы используем только 2 типа клеток: exterior и interior
# в реале это могут быть forest (лес), rock (скалы), shore(берег)…
map: [
['interior', 'interior', 'interior', 'interior']
['interior', 'exterior', 'exterior', 'interior']
['interior', 'exterior', 'exterior', 'interior']
['interior', 'interior', 'interior', 'interior']
]
gridData: (x, y) ->
maptype = @map[y][x]
# тип ячейки:
# square - площадь
# fountain - фонтан
# street - улица
# bath - баня
# tavern - таверна
# guild - гильдия
# hospital - лечебница
# chapel - часовня
# workshop - мастерская
switch maptype
when "exterior"
# d20
rnd = salet.rnd.rand(20)
switch
when rnd < 4 then type = "fountain"
when rnd < 16 then type = "street"
else type = "square"
when "interior"
rnd = salet.rnd.rand(18)
switch
when rnd < 2 then type = "chapel"
when rnd < 3 then type = "hospital"
when rnd < 6 then type = "bath"
when rnd < 10 then type = "tavern"
when rnd < 14 then type = "guild"
else type = "workshop"
else
type = maptype
return type
constructor: (@width, @height, improv) ->
@data = []
# TODO получить координаты особых локаций
for y in [0..(@height-1)]
for x in [0..(@width-1)]
@data[x] ?= []
@data[x][y] = new Maze.Cell
@data[x][y].setTag('position', @map[y][x])
@data[x][y].setTag('type', @gridData(x, y))
@data[x][y].loctitle = improv.gen('loctitle', @data[x][y])
# special encounters
###
specialEncounters = Object.keys(salet.specials).shuffle()
plotEncounters = ["meet1"]
# зд. возможно что две особых встречи упадут на одну клетку.
for event in specialEncounters
rnd = salet.rnd.rand(20) # вероятность 5%
if plotEncounters.indexOf(event) != false
rnd = 1 # вероятность 100%
if rnd != 1
continue
x = salet.rnd.rand(@width-1)
y = salet.rnd.rand(@height-1)
@data[x][y].setTag('special', event)
console.log "Special encounter set to (#{x}, #{y})"
###
mettavern = false
metbath = false
metworkshop = false
for y in [0..(@height-1)]
for x in [0..(@width-1)]
type = @data[x][y].getType()
switch type
when 'bath'
if metbath != true
metbath = true
salet.character.bathname = @data[x][y].loctitle
jQuery(document).on("maze_"+x+"_"+y, () ->
bathevent()
)
when 'workshop'
if metworkshop != true
metworkshop = true
salet.character.workshopname = @data[x][y].loctitle
jQuery(document).on("maze_"+x+"_"+y, () ->
workshopevent()
)
when 'tavern'
if mettavern != true
mettavern = true
# если внезапно на карте ни одной бани, ставим баню на 0,0 и вешаем событие
unless metbath
# но при этом не затираем таверн
y = 0
if @data[0][0].getType() == 'tavern'
y = 1
@setCell('bath', 'interior', 0, y, improv, () ->
bathevent()
)
# если внезапно на карте ни одной мастерской…
unless metworkshop
x = @height - 2
y = @width - 1
if @data[x][y].getType() == 'tavern'
x = x + 1
@setCell('workshop', 'interior', x, y, improv, () ->
workshopevent()
)
# особенно если ни одной таверны
unless mettavern
@setCell('tavern', 'interior', 0, @width-1, improv)
return true
setCell: (type, position, x, y, improv, event) ->
@data[x][y].setTag('type', type)
@data[x][y].setTag('position', position)
@data[x][y].loctitle = improv.gen('loctitle', @data[x][y])
salet.character.bathname = @data[x][y].loctitle
if event?
jQuery(document).on("maze_"+x+"_"+y, event)
at: (x, y) ->
if x? and y? and @data[x]? and @data[x][y]?
return @data[x][y]
else
return false
describe: (x, y, improv) ->
model = @at(x,y)
retval = '<h4>'+ model.getTitle() + "</h4>\n"+improv.gen('description', model)+"\n\n"#+improv.gen('directions', model)
return retval
# Я хотел сделать дополнительные ссылки в тексте, но это жутко муторно
# писать кучу кода для Improv на разбор, какие направления доступны.
isEast: (x, y) -> return (x+1) <= (@width - 1)
isWest: (x, y) -> return (x-1) >= 0
isNorth: (x, y) -> return (y-1) >= 0
isSouth: (x, y) -> return (y+1) <= (@height - 1)
getEast: (x, y) ->
if @isEast(x, y)
return @at(x+1, y)
return false
getWest: (x, y) ->
if @isWest(x, y)
return @at(x-1, y)
return false
getNorth: (x, y) ->
if @isNorth(x, y)
return @at(x, y-1)
return false
getSouth: (x, y) ->
if @isSouth(x, y)
return @at(x, y+1)
return false
getDirection: (direction, x, y) ->
switch direction
when "north" then return @getNorth(x,y)
when "south" then return @getSouth(x,y)
when "east" then return @getEast(x,y)
when "west" then return @getWest(x,y)
else return false
log: () ->
map = ""
for y in [0..(@height-1)]
for x in [0..(@width-1)]
map += @data[x][y].log()
map += "\n"
console.log map
# выбрать особый квадрант и выставить в нём клетку нужного типа
# вернуть её координаты
# TODO
setspecialregion: (quadrant, type) ->
halfheight = Math.floor(@height/2)
halfwidth = Math.floor(@width/2)
x = 0
y = 0
return {
x: x
y: y
}
bezier: (type) ->
halfheight = Math.floor(@height/2)
halfwidth = Math.floor(@width/2)
rnd = salet.rnd.rand(2)
if rnd == 1
# P0 is in the lower left quadrant
x0 = salet.rnd.rand(halfwidth)
y0 = halfheight + salet.rnd.rand(halfheight)
else
# P0 is in the lower right quadrant
x0 = halfwidth + salet.rnd.rand(halfwidth)
y0 = halfheight + salet.rnd.rand(halfheight)
rnd = salet.rnd.rand(2)
if rnd == 1
# P1 - higher left
x1 = salet.rnd.rand(halfwidth)
y1 = salet.rnd.rand(halfheight)
else
# P1 - lower left
x1 = salet.rnd.rand(halfwidth)
y1 = halfheight + salet.rnd.rand(halfheight)
# P2 - always higher right
x2 = halfwidth+salet.rnd.rand(halfwidth)
y2 = salet.rnd.rand(halfheight)
# quadratic bezier curve
for t in [0..@width] by 0.1
xp = Math.floor(Math.pow((1-t), 2)*x0+2*t*x1-2*Math.pow(t, 2)*x1+Math.pow(t, 2)*x2)
yp = Math.floor(Math.pow((1-t), 2)*y0+2*t*y1-2*Math.pow(t, 2)*y1+Math.pow(t, 2)*y2)
if @data[xp] == undefined or @data[xp][yp] == undefined
break
@data[xp][yp].setTag('type', type)
class Maze.Cell
constructor: () ->
@tags = []
@title = ""
getType: () -> return @getTag('type')
# Полное название локации
getTitle: () ->
if @title != ""
return @title
type = @getType()
retval = (type + "_title").l() + " "
if type in ["bath", "tavern"]
retval = retval + "<q>"
retval = retval + @loctitle
if type in ["bath", "tavern"]
retval = retval + "</q>"
@title = retval
return retval
getTag: (tagName) ->
for tag in @tags
if tag[0] == tagName
return tag[1]
return undefined
hasTag: (tagName) ->
for tag in @tags
if tag[0] == tagName
return true
return false
setTag: (tagName, value) ->
for tag, index in @tags
if tag[0] == tagName
@tags[index][1] = value
return true
@tags.push([tagName, value])
return true
setTagIfNotPresent: (tagName, value) ->
if @getTag(tagName) == undefined
@tags.push([tagName, value])
log: () ->
type = @getTag('type')
switch type
when "exterior" then return "e"
when "interior" then return "i"
when "fountain" then return "f"
when "street" then return "s"
when "square" then return "O"
when "bath" then return "b"
when "tavern" then return "t"
when "guild" then return "g"
when "hospital" then return "h"
when "chapel" then return "c"
when "workshop" then return "w"
when "special" then return "!"
else return "?"