@@ -374,7 +374,7 @@ define([ | |||
let foundHiddenLayer = null; | |||
hiddenRooms.forEach(h => { | |||
const { discovered, layer } = h; | |||
const { discovered, layer, interior } = h; | |||
const { x: hx, y: hy, width, height, area } = h; | |||
//Is the tile outside the hider | |||
@@ -383,8 +383,15 @@ define([ | |||
x >= hx + width || | |||
y < hy || | |||
y >= hy + height | |||
) | |||
) { | |||
//If the hider is an interior, the tile should be hidden if the player is inside the hider | |||
if (interior) { | |||
if (physics.isInPolygon(px, py, area)) | |||
foundHiddenLayer = layer; | |||
} | |||
return; | |||
} | |||
//Is the tile inside the hider | |||
if (!physics.isInPolygon(x, y, area)) | |||
@@ -206,4 +206,4 @@ | |||
.mobile .uiParty .list { | |||
max-height: calc(100% - @topPosition - 10px); | |||
} | |||
} |
@@ -24,6 +24,26 @@ module.exports = { | |||
return; | |||
} | |||
if (obj.zoneName === this.toZone) { | |||
obj.x = this.toPos.x; | |||
obj.y = this.toPos.y; | |||
const syncO = this.obj.syncer.o; | |||
syncO.x = obj.x; | |||
syncO.y = obj.y; | |||
process.send({ | |||
method: 'rezone', | |||
id: obj.serverId, | |||
args: { | |||
obj: simpleObj, | |||
newZone: this.toZone | |||
} | |||
}); | |||
return; | |||
} | |||
obj.fireEvent('beforeRezone'); | |||
obj.destroyed = true; | |||
@@ -5,10 +5,6 @@ let config = [ | |||
name: 'cave', | |||
path: 'config/maps' | |||
}, | |||
{ | |||
name: 'sewer', | |||
path: 'config/maps' | |||
}, | |||
{ | |||
name: 'fjolarok', | |||
path: 'config/maps' | |||
@@ -1,291 +0,0 @@ | |||
const { mobs: { rat: { level, faction, grantRep, regular: { drops } } } } = require('../zone'); | |||
const rewardGenerator = require('../../../../misc/rewardGenerator'); | |||
const rewardConfig = { | |||
regularKill: [{ | |||
name: 'Iron Bar', | |||
sprite: [0, 0], | |||
quality: 0, | |||
quantity: 5, | |||
chance: 10 | |||
}, { | |||
name: 'Cloth Scrap', | |||
sprite: [0, 1], | |||
quality: 0, | |||
quantity: 5, | |||
chance: 10 | |||
}, { | |||
name: 'Leather Scrap', | |||
sprite: [0, 7], | |||
quality: 0, | |||
quantity: 5, | |||
chance: 10 | |||
}, { | |||
name: 'Muddy Runestone', | |||
material: true, | |||
quality: 0, | |||
sprite: [6, 0], | |||
spritesheet: 'images/materials.png', | |||
chance: 1 | |||
}, { | |||
name: 'Epic Essence', | |||
material: true, | |||
sprite: [0, 5], | |||
quality: 3, | |||
chance: 1 | |||
}, { | |||
name: 'Rat Claw', | |||
material: true, | |||
sprite: [3, 0], | |||
spritesheet: 'images/materials.png', | |||
chance: 3 | |||
}] | |||
}; | |||
const descriptionStrings = { | |||
leadup: 'A bandit alchemist has been spotted in the sewer tunnels.', | |||
active: 'Rats are swarming towards the city.', | |||
success: 'Success: The rat invasion has been averted.', | |||
failure: 'Failure: The rats have made it to the city.', | |||
escapeCounter: 'Escapees: $ratEscapees$' | |||
}; | |||
const config = { | |||
cron: '0 */3 * * *', | |||
//cron: '* * * * *', | |||
idFirstSpawnPhase: 6, | |||
idFailPhase: 19, | |||
maxEscapees: 5, | |||
repeats: [5, 5, 3], | |||
//repeats: [1, 1, 1], | |||
rewardItemsPerKill: 3 | |||
}; | |||
const ratTargetPos = { | |||
x: 97, | |||
y: 87 | |||
}; | |||
const rat = { | |||
name: 'Bloodthirsty Rat', | |||
cell: 24, | |||
level, | |||
faction, | |||
grantRep, | |||
drops, | |||
hpMult: 3, | |||
pos: { | |||
x: 61, | |||
y: 62 | |||
}, | |||
originX: ratTargetPos.x, | |||
originY: ratTargetPos.y, | |||
maxChaseDistance: 1000, | |||
spells: [{ | |||
type: 'smokeBomb', | |||
radius: 1, | |||
duration: 20, | |||
range: 2, | |||
selfCast: 1, | |||
statMult: 1, | |||
damage: 0.125, | |||
element: 'poison', | |||
cdMax: 5, | |||
particles: { | |||
scale: { | |||
start: { | |||
min: 10, | |||
max: 25 | |||
}, | |||
end: { | |||
min: 10, | |||
max: 0 | |||
} | |||
}, | |||
opacity: { | |||
start: 0.3, | |||
end: 0 | |||
}, | |||
lifetime: { | |||
min: 1, | |||
max: 2 | |||
}, | |||
speed: { | |||
start: 3, | |||
end: 0 | |||
}, | |||
color: { | |||
start: ['db5538', '4ac441'], | |||
end: ['953f36', '386646'] | |||
}, | |||
chance: 0.125, | |||
randomColor: true, | |||
randomScale: true, | |||
blendMode: 'screen', | |||
spawnType: 'rect', | |||
spawnRect: { | |||
x: -10, | |||
y: -10, | |||
w: 20, | |||
h: 20 | |||
} | |||
} | |||
}], | |||
events: { | |||
afterMove: function () { | |||
const { obj: { x, y } } = this; | |||
if (x !== ratTargetPos.x || y !== ratTargetPos.y) | |||
return; | |||
const eventManager = this.obj.instance.events; | |||
const eventName = this.obj.event.config.name; | |||
eventManager.incrementEventVariable(eventName, 'ratEscapees', 1); | |||
const { active, escapeCounter } = descriptionStrings; | |||
const newDesc = `${active}<br /><br />${escapeCounter}`; | |||
eventManager.setEventDescription(eventName, newDesc); | |||
this.obj.destroyed = true; | |||
const totalEscapees = this.obj.event.variables.ratEscapees; | |||
if (totalEscapees >= config.maxEscapees) { | |||
const event = this.obj.event; | |||
event.currentPhase.end = true; | |||
event.nextPhase = config.idFailPhase; | |||
} | |||
}, | |||
afterDeath: function ({ source: { name } }) { | |||
const eventManager = this.obj.instance.events; | |||
const eventName = this.obj.event.config.name; | |||
const itemCount = config.rewardItemsPerKill; | |||
const rewards = rewardGenerator(itemCount, rewardConfig.regularKill); | |||
eventManager.addParticipantRewards(eventName, name, rewards); | |||
} | |||
} | |||
}; | |||
module.exports = { | |||
name: 'Plague of Rats', | |||
description: descriptionStrings.leadup, | |||
distance: -1, | |||
cron: config.cron, | |||
phases: [{ | |||
type: 'spawnMob', | |||
auto: true, | |||
mobs: [{ | |||
id: 'banditAlchemist', | |||
name: 'Bandit Alchemist', | |||
attackable: false, | |||
hpMult: 1, | |||
cell: 79, | |||
level: 15, | |||
pos: { | |||
x: 117, | |||
y: 62 | |||
} | |||
}] | |||
}, { | |||
type: 'moveMob', | |||
id: 'banditAlchemist', | |||
pos: { | |||
x: 64, | |||
y: 63 | |||
} | |||
}, { | |||
type: 'eventChain', | |||
config: [{ | |||
type: 'mobTalk', | |||
id: 'banditAlchemist', | |||
text: 'I think I cracked it! The serum should finally be complete.', | |||
delay: 15 | |||
}, { | |||
type: 'mobTalk', | |||
id: 'banditAlchemist', | |||
text: 'One taste of this and the rats\' hunger for blood will be instatiable.', | |||
delay: 15 | |||
}, { | |||
type: 'mobTalk', | |||
id: 'banditAlchemist', | |||
text: '*pours a bubbling liquid into a rat nest*', | |||
delay: 15 | |||
}, { | |||
type: 'mobTalk', | |||
id: 'banditAlchemist', | |||
text: 'Let\'s see how Fjolgard handles a rat infestation of the bloodthirsty variety.', | |||
delay: 15 | |||
}, { | |||
type: 'mobTalk', | |||
id: 'banditAlchemist', | |||
text: '*laughs*', | |||
delay: 15 | |||
}] | |||
}, { | |||
type: 'moveMob', | |||
id: 'banditAlchemist', | |||
pos: { | |||
x: 117, | |||
y: 63 | |||
}, | |||
auto: true | |||
}, { | |||
type: 'despawnMob', | |||
id: 'banditAlchemist' | |||
}, { | |||
type: 'setDescription', | |||
desc: descriptionStrings.active, | |||
auto: true | |||
}, { | |||
type: 'spawnMob', | |||
mobs: [rat], | |||
auto: true | |||
}, { | |||
type: 'wait', | |||
ttl: 15 | |||
}, { | |||
type: 'goto', | |||
gotoPhaseIndex: config.idFirstSpawnPhase, | |||
repeats: config.repeats[0] | |||
}, { | |||
type: 'spawnMob', | |||
mobs: [rat], | |||
auto: true | |||
}, { | |||
type: 'wait', | |||
ttl: 7 | |||
}, { | |||
type: 'goto', | |||
gotoPhaseIndex: config.idFirstSpawnPhase + 3, | |||
repeats: config.repeats[1] | |||
}, { | |||
type: 'spawnMob', | |||
mobs: [rat], | |||
auto: true | |||
}, { | |||
type: 'wait', | |||
ttl: 3 | |||
}, { | |||
type: 'goto', | |||
gotoPhaseIndex: config.idFirstSpawnPhase + 6, | |||
repeats: config.repeats[2] | |||
}, { | |||
type: 'killAllMobs' | |||
}, { | |||
type: 'setDescription', | |||
desc: descriptionStrings.success, | |||
ttl: 100 | |||
}, { | |||
type: 'giveRewards' | |||
}, { | |||
type: 'end' | |||
}, { | |||
type: 'setDescription', | |||
desc: descriptionStrings.failure, | |||
ttl: 100 | |||
}] | |||
}; |
@@ -1,455 +0,0 @@ | |||
const balance = { | |||
rat: { | |||
clawChance: 3 | |||
}, | |||
giantRat: { | |||
clawChance: 5 | |||
}, | |||
enragedRat: { | |||
clawChance: 80 | |||
}, | |||
stinktooth: { | |||
runestoneChance: 10, | |||
recipeChance: 3, | |||
shankChance: 0.2 | |||
}, | |||
bandit: { | |||
keyChance: 1 | |||
}, | |||
direRat: { | |||
clawChance: 7 | |||
}, | |||
bera: { | |||
recipeChance: 3, | |||
keyChance: 3 | |||
} | |||
}; | |||
module.exports = { | |||
name: 'The Fjolgard Sewer', | |||
level: [11, 13], | |||
resources: { | |||
Stinkcap: { | |||
type: 'herb', | |||
max: 1 | |||
} | |||
}, | |||
mobs: { | |||
default: { | |||
faction: 'fjolgard', | |||
deathRep: -5 | |||
}, | |||
rat: { | |||
faction: 'fjolgard', | |||
grantRep: { | |||
fjolgard: 6 | |||
}, | |||
level: 11, | |||
regular: { | |||
drops: { | |||
rolls: 1, | |||
noRandom: true, | |||
alsoRandom: true, | |||
blueprints: [{ | |||
chance: balance.rat.clawChance, | |||
name: 'Rat Claw', | |||
material: true, | |||
sprite: [3, 0], | |||
spritesheet: 'images/materials.png' | |||
}] | |||
} | |||
}, | |||
rare: { | |||
name: 'Enraged Rat', | |||
cell: 24, | |||
drops: { | |||
rolls: 1, | |||
noRandom: true, | |||
alsoRandom: true, | |||
blueprints: [{ | |||
chance: balance.enragedRat.clawChance, | |||
name: 'Rat Claw', | |||
material: true, | |||
sprite: [3, 0], | |||
spritesheet: 'images/materials.png' | |||
}] | |||
} | |||
} | |||
}, | |||
'giant rat': { | |||
faction: 'fjolgard', | |||
grantRep: { | |||
fjolgard: 6 | |||
}, | |||
level: 12, | |||
regular: { | |||
hpMult: 2, | |||
dmgMult: 1.2, | |||
drops: { | |||
rolls: 1, | |||
noRandom: true, | |||
alsoRandom: true, | |||
blueprints: [{ | |||
chance: balance.giantRat.clawChance, | |||
name: 'Rat Claw', | |||
material: true, | |||
sprite: [3, 0], | |||
spritesheet: 'images/materials.png' | |||
}] | |||
} | |||
}, | |||
rare: { | |||
count: 0 | |||
} | |||
}, | |||
stinktooth: { | |||
faction: 'hostile', | |||
grantRep: { | |||
fjolgard: 15 | |||
}, | |||
level: 13, | |||
spawnCd: 1714, | |||
regular: { | |||
hpMult: 10, | |||
dmgMult: 3, | |||
drops: { | |||
rolls: 3, | |||
chance: 100, | |||
noRandom: true, | |||
alsoRandom: true, | |||
magicFind: [2000, 125], | |||
blueprints: [{ | |||
chance: balance.stinktooth.shankChance, | |||
name: 'Putrid Shank', | |||
level: 13, | |||
quality: 4, | |||
slot: 'oneHanded', | |||
type: 'Dagger', | |||
spritesheet: '../../../images/legendaryItems.png', | |||
sprite: [0, 1], | |||
implicitStat: { | |||
stat: 'lifeOnHit', | |||
value: [5, 20] | |||
}, | |||
effects: [{ | |||
type: 'castSpellOnHit', | |||
rolls: { | |||
i_chance: [5, 20], | |||
spell: 'smokeBomb' | |||
} | |||
}] | |||
}, { | |||
chance: balance.stinktooth.recipeChance, | |||
type: 'recipe', | |||
name: 'Recipe: Rune of Whirlwind', | |||
profession: 'etching', | |||
teaches: 'runeWhirlwind' | |||
}, { | |||
chance: balance.stinktooth.runestoneChance, | |||
name: 'Muddy Runestone', | |||
material: true, | |||
sprite: [6, 0], | |||
spritesheet: 'images/materials.png' | |||
}] | |||
} | |||
}, | |||
rare: { | |||
count: 0 | |||
}, | |||
spells: [{ | |||
type: 'melee', | |||
statMult: 1, | |||
damage: 0.08 | |||
}, { | |||
type: 'whirlwind', | |||
range: 2, | |||
damage: 0.2, | |||
cdMax: 40 | |||
}, { | |||
type: 'summonSkeleton', | |||
killMinionsOnDeath: false, | |||
killMinionsBeforeSummon: false, | |||
minionsDieOnAggroClear: true, | |||
needLos: false, | |||
sheetName: 'mobs', | |||
cdMax: 60, | |||
positions: [[30, 30], [40, 30], [30, 40], [40, 40]], | |||
summonTemplates: [{ | |||
name: 'Biter Rat', | |||
cell: 16, | |||
hpPercent: 20, | |||
dmgPercent: 0.1, | |||
basicSpell: 'melee' | |||
}, { | |||
name: 'Spitter Rat', | |||
cell: 24, | |||
hpPercent: 10, | |||
dmgPercent: 0.175, | |||
basicSpell: 'projectile' | |||
}] | |||
}, { | |||
type: 'charge', | |||
castOnEnd: 1, | |||
cdMax: 50, | |||
targetRandom: true, | |||
damage: 0.3 | |||
}, { | |||
type: 'fireblast', | |||
range: 2, | |||
damage: 0.001, | |||
pushback: 2, | |||
procCast: true | |||
}] | |||
}, | |||
bandit: { | |||
faction: 'hostile', | |||
grantRep: { | |||
fjolgard: 18 | |||
}, | |||
level: 11, | |||
regular: { | |||
drops: { | |||
noRandom: true, | |||
alsoRandom: true, | |||
blueprints: [{ | |||
chance: balance.bandit.keyChance, | |||
type: 'key', | |||
noSalvage: true, | |||
name: 'Rusted Key', | |||
keyId: 'rustedSewer', | |||
singleUse: true, | |||
sprite: [12, 1], | |||
quantity: 1 | |||
}] | |||
} | |||
}, | |||
rare: { | |||
name: 'Cutthroat' | |||
} | |||
}, | |||
'dire rat': { | |||
level: 13, | |||
walkDistance: 0, | |||
faction: 'hostile', | |||
noQuest: true, | |||
grantRep: { | |||
fjolgard: 22 | |||
}, | |||
regular: { | |||
hpMult: 5, | |||
dmgMult: 1.2, | |||
drops: { | |||
rolls: 1, | |||
noRandom: true, | |||
alsoRandom: true, | |||
blueprints: [{ | |||
chance: balance.direRat.clawChance, | |||
name: 'Rat Claw', | |||
material: true, | |||
sprite: [3, 0], | |||
spritesheet: 'images/materials.png' | |||
}] | |||
} | |||
}, | |||
rare: { | |||
count: 0 | |||
} | |||
}, | |||
'bera the blade': { | |||
faction: 'hostile', | |||
grantRep: { | |||
fjolgard: 25 | |||
}, | |||
level: 14, | |||
walkDistance: 0, | |||
regular: { | |||
hpMult: 3, | |||
dmgMult: 1.5, | |||
drops: { | |||
rolls: 1, | |||
noRandom: true, | |||
alsoRandom: true, | |||
blueprints: [{ | |||
chance: balance.bera.recipeChance, | |||
type: 'recipe', | |||
name: 'Recipe: Rune of Ambush', | |||
profession: 'etching', | |||
teaches: 'runeAmbush' | |||
}, { | |||
chance: balance.bera.keyChance, | |||
type: 'key', | |||
noSalvage: true, | |||
name: 'Rusted Key', | |||
keyId: 'rustedSewer', | |||
singleUse: true, | |||
sprite: [12, 1], | |||
quantity: 1 | |||
}] | |||
} | |||
}, | |||
rare: { | |||
count: 0 | |||
} | |||
} | |||
}, | |||
objects: { | |||
'mudfish school': { | |||
max: 9, | |||
type: 'fish', | |||
quantity: [6, 12] | |||
}, | |||
sewerdoor: { | |||
properties: { | |||
cpnDoor: { | |||
autoClose: 171, | |||
locked: true, | |||
key: 'rustedSewer', | |||
destroyKey: true | |||
} | |||
} | |||
}, | |||
bubbles: { | |||
components: { | |||
cpnParticles: { | |||
simplify: function () { | |||
return { | |||
type: 'particles', | |||
blueprint: { | |||
color: { | |||
start: ['51fc9a', '80f643'], | |||
end: ['386646', '44cb95'] | |||
}, | |||
scale: { | |||
start: { | |||
min: 2, | |||
max: 8 | |||
}, | |||
end: { | |||
min: 2, | |||
max: 4 | |||
} | |||
}, | |||
speed: { | |||
start: { | |||
min: 2, | |||
max: 6 | |||
}, | |||
end: { | |||
min: 0, | |||
max: 4 | |||
} | |||
}, | |||
lifetime: { | |||
min: 1, | |||
max: 3 | |||
}, | |||
alpha: { | |||
start: 0.5, | |||
end: 0 | |||
}, | |||
randomScale: true, | |||
randomSpeed: true, | |||
chance: 0.2, | |||
randomColor: true, | |||
spawnType: 'rect', | |||
blendMode: 'screen', | |||
spawnRect: { | |||
x: -40, | |||
y: -40, | |||
w: 80, | |||
h: 80 | |||
} | |||
} | |||
}; | |||
} | |||
} | |||
} | |||
}, | |||
gas: { | |||
components: { | |||
cpnParticles: { | |||
simplify: function () { | |||
return { | |||
type: 'particles', | |||
blueprint: { | |||
color: { | |||
start: ['c0c3cf', '80f643'], | |||
end: ['386646', '69696e'] | |||
}, | |||
scale: { | |||
start: { | |||
min: 18, | |||
max: 64 | |||
}, | |||
end: { | |||
min: 8, | |||
max: 24 | |||
} | |||
}, | |||
speed: { | |||
start: { | |||
min: 2, | |||
max: 6 | |||
}, | |||
end: { | |||
min: 0, | |||
max: 4 | |||
} | |||
}, | |||
lifetime: { | |||
min: 4, | |||
max: 24 | |||
}, | |||
alpha: { | |||
start: 0.05, | |||
end: 0 | |||
}, | |||
randomScale: true, | |||
randomSpeed: true, | |||
chance: 0.02, | |||
randomColor: true, | |||
spawnType: 'rect', | |||
blendMode: 'screen', | |||
spawnRect: { | |||
x: -80, | |||
y: -80, | |||
w: 160, | |||
h: 160 | |||
} | |||
} | |||
}; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
}; |
@@ -459,6 +459,7 @@ module.exports = { | |||
} | |||
} else if (layerName === 'hiddenRooms') { | |||
blueprint.fog = (cell.properties || {}).fog; | |||
blueprint.interior = (cell.properties || {}).interior; | |||
blueprint.discoverable = (cell.properties || {}).discoverable; | |||
blueprint.layer = ~~((cell.properties || {}).layer || 0); | |||