Alexander Yakovlev
9b46fcdd52
All checks were successful
default/mapgen/master This commit looks good
271 lines
8.8 KiB
CoffeeScript
271 lines
8.8 KiB
CoffeeScript
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 "?"
|