FILES ----- [NEW] animations\poisondust\poisondust.animation [NEW] animations\poisondust\poisondust.frames [NEW] animations\poisondust\poisondust.png behaviors\monsters\modular\basemonster.behavior behaviors\monsters\modular\actions\blink.behavior [NEW] behaviors\monsters\modular\actions\fire.behavior behaviors\monsters\modular\actions\hop.behavior [NEW] behaviors\monsters\modular\movement\jump.behavior [NEW] behaviors\monsters\modular\movement\walkapproach.behavior [NEW] behaviors\monsters\modular\movement\walkwander.behavior [NEW] effects\icethrowertrail.effectsource [NEW] effects\poisonthrowertrail.effectsource items\active\weapons\weapon.lua items\active\weapons\melee\altabilities\broadsword\traildash\traildash.lua items\active\weapons\melee\altabilities\broadsword\travelingslash\travelingslash.altability items\active\weapons\melee\altabilities\generic\blinkslash\blinkslash.altability items\active\weapons\melee\altabilities\generic\blinkslash\blinkslash.lua items\active\weapons\melee\altabilities\hammer\elementalaura\elementalaura.altability items\active\weapons\melee\altabilities\hammer\elementalaura\elementalaura.lua items\active\weapons\melee\altabilities\hammer\groundslam\groundslam.altability items\active\weapons\melee\altabilities\hammer\groundslam\groundslam.lua items\active\weapons\melee\altabilities\hammer\uppercut\uppercut.altability items\active\weapons\melee\altabilities\hammer\uppercut\uppercut.lua items\active\weapons\melee\altabilities\spear\barrier\barrier.altability items\active\weapons\melee\altabilities\spear\barrier\barrier.lua items\active\weapons\melee\altabilities\spear\rocketspear\rocketspear.altability items\active\weapons\melee\altabilities\spear\rocketspear\rocketspear.lua items\active\weapons\melee\broadsword\rarebroadsword.activeitem items\active\weapons\melee\hammer\commonhammer.activeitem items\active\weapons\ranged\altabilities\guidedrocket\guidedrocket.altability items\active\weapons\ranged\rocketlauncher\rarerocketlauncher.activeitem monsters\bmonster.lua [NEW] monsters\crawlers\crustoise\body.monsterpart [NEW] monsters\crawlers\crustoise\crustoise.animation [NEW] monsters\crawlers\crustoise\crustoise.frames [NEW] monsters\crawlers\crustoise\crustoise.monstertype [NEW] monsters\crawlers\crustoise\crustoise.png monsters\walkers\gleap\gleap.animation monsters\walkers\gleap\gleap.frames monsters\walkers\gleap\gleap.monstertype monsters\walkers\ophidaunt\ophidaunt.animation monsters\walkers\ophidaunt\ophidaunt.frames monsters\walkers\ophidaunt\ophidaunt.monstertype objects\wired\forcepad\jumppad.object [NEW] particles\icethrowertrail.particle [NEW] particles\poisondust.particle [NEW] projectiles\guns\unsorted\icethrower\icethrower.frames [NEW] projectiles\guns\unsorted\icethrower\icethrower.png [NEW] projectiles\guns\unsorted\icethrower\icethrower.projectile [NEW] projectiles\guns\unsorted\icethrower\icon.png [NEW] projectiles\guns\unsorted\poisonthrower\icon.png [NEW] projectiles\guns\unsorted\poisonthrower\poisonthrower.frames [NEW] projectiles\guns\unsorted\poisonthrower\poisonthrower.png [NEW] projectiles\guns\unsorted\poisonthrower\poisonthrower.projectile quests\generated\subquests.config scripts\behavior.lua scripts\util.lua scripts\actions\entities.lua scripts\actions\math.lua scripts\actions\movement.lua scripts\behavior\bdata.lua scripts\quest\manager\summon_npcs.lua scripts\questgen\context.lua scripts\questgen\generator.lua scripts\questgen\predicands.lua scripts\questgen\relations.lua [NEW] sfx\melee\barrier_create_electric.ogg sfx\melee\barrier_create_fire.ogg sfx\melee\barrier_create_ice.ogg sfx\melee\leap1.ogg sfx\melee\travelingslash_poison1.ogg sfx\melee\travelingslash_poison2.ogg [NEW] stats\effects\invulnerable\invulnerable.lua [NEW] stats\effects\invulnerable\invulnerable.statuseffect DIFFS ----- behaviors\monsters\modular\basemonster.behavior 2a3 > "description": "", 90c91 < "type": "movement" --- > "type": "body" 124c125 < "type": "movement" --- > "type": "body" 163c164 < "type": "movement" --- > "type": "body" 206c207 < "title": "selector", --- > "title": "sequence", 208,209c209,215 < "name": "selector", < "parameters": {}, --- > "name": "sequence", > "parameters": { > "type": "sliding", > "state": "off", > "fromEntity": "attackTarget", > "toEntity": "fleeTarget" > }, 212,214c218,220 < "title": "sequence", < "type": "composite", < "name": "sequence", --- > "title": "entityExists", > "type": "action", > "name": "entityExists", 216,242c222,283 < "type": "sliding", < "state": "off", < "fromEntity": "attackTarget", < "toEntity": "fleeTarget" < }, < "children": [ < { < "title": "entityExists", < "type": "action", < "name": "entityExists", < "parameters": { < "entity": "target" < } < }, < { < "title": "succeeder", < "type": "decorator", < "name": "succeeder", < "parameters": {}, < "child": { < "title": "hostileActions", < "type": "action", < "name": "selectorActions", < "parameters": { < "actions": "" < } < } --- > "entity": "target" > } > }, > { > "title": "flee", > "type": "action", > "name": "selectorActions", > "parameters": { > "actions": "" > } > } > ] > }, > { > "title": "parallel", > "type": "composite", > "name": "parallel", > "parameters": { > "fail": 1, > "success": -1 > }, > "children": [ > { > "title": "entityExists", > "type": "action", > "name": "entityExists", > "parameters": { > "entity": "target" > } > }, > { > "title": "hostileActions", > "type": "action", > "name": "selectorActions", > "parameters": { > "actions": "" > } > } > ] > }, > { > "title": "sequence", > "type": "composite", > "name": "sequence", > "parameters": { > "type": "sliding", > "state": "off", > "fromEntity": "attackTarget", > "toEntity": "fleeTarget" > }, > "children": [ > { > "title": "inverter", > "type": "decorator", > "name": "inverter", > "parameters": {}, > "child": { > "title": "entityExists", > "type": "action", > "name": "entityExists", > "parameters": { > "entity": "target" 244c285 < ] --- > } 254a296,372 > }, > { > "title": "parallel", > "type": "composite", > "name": "parallel", > "parameters": { > "fail": 1, > "success": -1 > }, > "children": [ > { > "title": "entityExists", > "type": "action", > "name": "entityExists", > "parameters": { > "entity": "target" > } > }, > { > "title": "succeeder", > "type": "decorator", > "name": "succeeder", > "parameters": {}, > "child": { > "title": "approach", > "type": "action", > "name": "selectorActions", > "parameters": { > "actions": "" > } > } > } > ] > }, > { > "title": "sequence", > "type": "composite", > "name": "sequence", > "parameters": { > "type": "sliding", > "state": "off", > "fromEntity": "attackTarget", > "toEntity": "fleeTarget" > }, > "children": [ > { > "title": "inverter", > "type": "decorator", > "name": "inverter", > "parameters": {}, > "child": { > "title": "entityExists", > "type": "action", > "name": "entityExists", > "parameters": { > "entity": "target" > } > } > }, > { > "title": "wander", > "type": "action", > "name": "selectorActions", > "parameters": { > "actions": "" > } > } > ] > }, > { > "title": "setAnimationState", > "type": "action", > "name": "setAnimationState", > "parameters": { > "state": "idle", > "type": "body" > } behaviors\monsters\modular\actions\blink.behavior 13c13 < "type": "movement" --- > "type": "body" behaviors\monsters\modular\actions\hop.behavior 204,205c204,205 < "state": "jump", < "type": "movement" --- > "state": "hop", > "type": "body" 306c306 < "type": "movement" --- > "type": "body" 334c334 < "type": "movement" --- > "type": "body" items\active\weapons\weapon.lua 104a105 > sb.logInfo("Setting facing direction to %s", self.aimDirection) items\active\weapons\melee\altabilities\broadsword\traildash\traildash.lua 42a43,45 > local wasInvulnerable = status.stat("invulnerable") > 0 > status.addEphemeralEffect("invulnerable", self.dashTime) > 46c49,52 < if not mcontroller.onGround() then return true end --- > if not mcontroller.onGround() then > if not wasInvulnerable then status.removeEphemeralEffect("invulnerable") end > return true > end items\active\weapons\melee\altabilities\broadsword\travelingslash\travelingslash.altability 9c9 < "poisonTravelSlash" : [ "/sfx/melee/travelingslash_poison3.ogg" ] --- > "poisonTravelSlash" : [ "/sfx/melee/travelingslash_poison2.ogg" ] items\active\weapons\melee\altabilities\generic\blinkslash\blinkslash.altability 55,56c55,57 < "maxDistance" : 12, < "blinkXOffset" : -4, --- > "blinkDistance" : 15, > "blinkYTolerance" : 3.5, > items\active\weapons\melee\altabilities\generic\blinkslash\blinkslash.lua 27a28 > 38c39,44 < self:setState(self.slash) --- > self.blinkPosition = self:findBlinkPosition() > if self.blinkPosition then > self:setState(self.slash) > else > self.cooldownTimer = self.cooldownTime > end 61a68,72 > local fromPosition = mcontroller.position() > mcontroller.setPosition(self.blinkPosition) > > self.weapon.aimDirection = -1 > -- mcontroller.setFace(self.weapon.aimDirection) 65,72d75 < local fromPosition = mcontroller.position() < local aimPosition = activeItem.ownerAimPosition() < local aimDistance = math.abs(math.floor(world.distance(aimPosition, mcontroller.position())[1])) + self.blinkXOffset < local blinkPosition = self:findBlinkPosition(math.min(aimDistance, self.maxDistance), aimPosition[2]) < if blinkPosition then < mcontroller.setPosition(blinkPosition) < end < 86a90,91 > self.weapon.aimDirection = 1 > -- mcontroller.setFace(self.weapon.aimDirection) 107,125c112,120 < function blinkSlash:findBlinkPosition(distance, height) < local position = mcontroller.position() < < local direction = mcontroller.facingDirection() < for i = 0, distance do < if direction > 0 then < position[1] = math.ceil(position[1]) < end < < -- Try to move toward target height < local heightDiff = util.toDirection(height - position[2]) < local yDirs = {heightDiff, 0, -heightDiff} < < local lastPosition = position[1] < for _,yDir in ipairs(yDirs) do < local bounds = rect.translate(mcontroller.boundBox(), {position[1] + direction, position[2] + yDir}) < if not world.rectTileCollision(bounds, {"Null", "Block", "Dynamic"}) then < position = {position[1] + direction, position[2] + yDir} < break --- > function blinkSlash:findBlinkPosition() > local collisionPoly = mcontroller.collisionPoly() > local searchStart = vec2.add(mcontroller.position(), {self.blinkDistance * mcontroller.facingDirection(), -self.blinkYTolerance - 0.2}) > for i = 0, 2 * self.blinkYTolerance do > local searchPosition = {searchStart[1], searchStart[2] + i} > if not world.lineTileCollision(mcontroller.position(), searchPosition, {"Null", "Block", "Dynamic"}) then > local resolved = world.resolvePolyCollision(collisionPoly, searchPosition, 1.0) > if resolved and resolved[2] > searchPosition[2] + 0.1 then > return resolved 128,130d122 < if position[1] == lastPosition or i == distance then < return position < end 132d123 < return mcontroller.position() items\active\weapons\melee\altabilities\hammer\elementalaura\elementalaura.altability 5c5 < "fireAuraToggle" : { --- > "fireCharge" : { 19c19 < "electricAuraToggle" : { --- > "electricCharge" : { 30c30 < "poisonAuraToggle" : { --- > "poisonCharge" : { 44c44 < "iceAuraToggle" : { --- > "iceCharge" : { 60,61c60,79 < "auraToggleOn" : [ "/sfx/tech/mech_jump2.ogg" ], < "auraToggleOff" : [ "/sfx/tech/mech_powerdown2.ogg"] --- > "firecharge" : [ "/sfx/melee/charge_combo3.ogg" ], > "firefull" : [ "/sfx/melee/charge_full_hold2.ogg" ], > "fireactivate" : [ "/sfx/tech/mech_jump2.ogg" ], > "fireactive" : [ "/sfx/melee/barrier_create_fire.ogg" ], > "firedeactivate" : [ "/sfx/tech/mech_powerdown2.ogg" ], > "electriccharge" : [ "/sfx/melee/charge_combo3.ogg" ], > "electricfull" : [ "/sfx/melee/charge_full_hold2.ogg" ], > "electricactivate" : [ "/sfx/tech/mech_jump2.ogg" ], > "electricactive" : [ "/sfx/objects/teslaspike.ogg" ], > "electricdeactivate" : [ "/sfx/tech/mech_powerdown2.ogg" ], > "icecharge" : [ "/sfx/melee/charge_combo3.ogg" ], > "icefull" : [ "/sfx/melee/charge_full_hold2.ogg" ], > "iceactivate" : [ "/sfx/tech/mech_jump2.ogg" ], > "iceactive" : [ "/sfx/melee/barrier_create_ice.ogg" ], > "icedeactivate" : [ "/sfx/tech/mech_powerdown2.ogg" ], > "poisoncharge" : [ "/sfx/melee/charge_combo3.ogg" ], > "poisonfull" : [ "/sfx/melee/charge_full_hold2.ogg" ], > "poisonactivate" : [ "/sfx/tech/mech_jump2.ogg" ], > "poisonactive" : [ "/sfx/melee/barrier_create_poison.ogg" ], > "poisondeactivate" : [ "/sfx/tech/mech_powerdown2.ogg" ] 70a89,93 > "duration" : 8.0, > > "chargeTime" : 1.5, > "minChargeTime" : 0.5, > 87c110,121 < "duration" : 0.25, --- > "armRotation" : 0, > "endArmRotation" : 50, > "weaponRotation" : 0, > "endWeaponRotation" : -50, > "weaponOffset" : [0, 0.75], > "twoHanded" : true, > > "allowRotate" : false, > "allowFlip" : true > }, > "fire" : { > "duration" : 0.3, 94c128 < "allowFlip" : false --- > "allowFlip" : true items\active\weapons\melee\altabilities\hammer\elementalaura\elementalaura.lua 11a12 > self.activeTimer = 0 21,22c22,28 < if self.weapon.currentAbility == nil and self.cooldownTimer == 0 and self.fireMode == "alt" then < self:setState(self.activate) --- > if self.weapon.currentAbility == nil > and self.cooldownTimer == 0 > and self.fireMode == "alt" > and not status.resourceLocked("energy") > and status.resource("energy") >= self:energyUsage() * (self.minChargeTime / self.chargeTime) then > > self:setState(self.windup) 26,27c32,34 < if status.overConsumeResource("energy", self:energyUsage() * self.dt) then < self.weapon:setOwnerDamage(self.damageConfig, self.damagePoly) --- > self.activeTimer = math.max(0, self.activeTimer - self.dt) > if self.activeTimer > 0 then > self.weapon:setOwnerDamage(self.damageConfig, self.damagePoly) 29c36 < self:toggleOff() --- > self:deactivate() 34c41,42 < function elementalAura:activate() --- > -- Attack state: windup > function elementalAura:windup() 38,43c46,57 < if self.active then < self:toggleOff() < else < if not status.resourceLocked("energy") then < animator.setParticleEmitterActive(self.weapon.elementalType.."AuraToggle", true) < self:toggleOn() --- > animator.setParticleEmitterActive(self.weapon.elementalType.."Charge", true) > animator.playSound(self.weapon.elementalType.."charge") > > local wasFull = false > local chargeTimer = 0 > while self.fireMode == "alt" and (chargeTimer == self.chargeTime or status.overConsumeResource("energy", self:energyUsage() * (1 / self.chargeTime) * self.dt)) do > chargeTimer = math.min(self.chargeTime, chargeTimer + self.dt) > > if chargeTimer == self.chargeTime and not wasFull then > wasFull = true > animator.stopAllSounds(self.weapon.elementalType.."charge") > animator.playSound(self.weapon.elementalType.."full", -1) 44a59,64 > > local chargeRatio = math.sin(chargeTimer / self.chargeTime * 1.57) > self.weapon.relativeArmRotation = util.toRadians(util.lerp(chargeRatio, {self.stances.windup.armRotation, self.stances.windup.endArmRotation})) > self.weapon.relativeWeaponRotation = util.toRadians(util.lerp(chargeRatio, {self.stances.windup.weaponRotation, self.stances.windup.endWeaponRotation})) > > coroutine.yield() 47c67,83 < util.wait(self.stances.windup.duration) --- > animator.setParticleEmitterActive(self.weapon.elementalType.."Charge", false) > animator.stopAllSounds(self.weapon.elementalType.."charge") > animator.stopAllSounds(self.weapon.elementalType.."full") > > if chargeTimer > self.minChargeTime then > self.activeTimer = self.duration * (chargeTimer / self.chargeTime) > self:setState(self.fire) > end > end > > -- Attack state: fire > function elementalAura:fire() > self.weapon:setStance(self.stances.fire) > > self:activate() > > util.wait(self.stances.fire.duration) 52c88 < function elementalAura:toggleOn() --- > function elementalAura:activate() 54c90,93 < animator.playSound("auraToggleOn") --- > animator.playSound(self.weapon.elementalType.."activate") > if not self.active then > animator.playSound(self.weapon.elementalType.."active", -1) > end 58c97 < function elementalAura:toggleOff() --- > function elementalAura:deactivate() 60c99,100 < animator.playSound("auraToggleOff") --- > animator.stopAllSounds(self.weapon.elementalType.."active") > animator.playSound(self.weapon.elementalType.."deactivate") 69,76c109 < return self.energyUsageMultiplier * root.evalFunction("gunLevelEnergyCostPerDamage", item.instanceValue("level", 1)) * self:damageAmount() < end < < function elementalAura:ownerPositionFromHand() < local handOffset = vec2.div(self.handOffset, -8) < local armOffset = vec2.div(self.frontArmOffset, 8) < armOffset = vec2.rotate(armOffset, self.weapon.aimAngle + self.weapon.relativeArmRotation) < return vec2.add(handOffset, armOffset) --- > return self.duration * self.energyUsageMultiplier * root.evalFunction("gunLevelEnergyCostPerDamage", item.instanceValue("level", 1)) * self:damageAmount() 81a115 > animator.stopAllSounds(self.weapon.elementalType.."active") 83c117,119 < animator.setParticleEmitterActive(self.weapon.elementalType.."AuraToggle", false) --- > animator.setParticleEmitterActive(self.weapon.elementalType.."Charge", false) > animator.stopAllSounds(self.weapon.elementalType.."charge") > animator.stopAllSounds(self.weapon.elementalType.."full") items\active\weapons\melee\altabilities\hammer\groundslam\groundslam.altability 14c14 < "groundSlamJump" : [ "/sfx/gun/grenade2.ogg" ], --- > "groundSlamJump" : [ "/sfx/melee/hammer_hit_ground3.ogg", "/sfx/melee/hammer_hit_ground4.ogg" ], 32,34d31 < < "groundJumpSpeed" : 50, < "groundJumpWaitTime" : 0.15, items\active\weapons\melee\altabilities\hammer\groundslam\groundslam.lua 19c19,24 < if self.weapon.currentAbility == nil and self.cooldownTimer == 0 and self.fireMode == "alt" and status.overConsumeResource("energy", self:energyUsage()) then --- > if self.weapon.currentAbility == nil > and self.cooldownTimer == 0 > and self.fireMode == "alt" > and not mcontroller.onGround() > and status.overConsumeResource("energy", self:energyUsage()) then > 24c29 < function groundSlam:windup(jump) --- > function groundSlam:windup() 30,31c35 < if jump == nil then jump = true end < self:setState(self.slam, jump) --- > self:setState(self.slam) 34c38 < function groundSlam:slam(jump) --- > function groundSlam:slam() 40,50d43 < if mcontroller.onGround() and jump then < mcontroller.setYVelocity(self.groundJumpSpeed) < animator.playSound("groundSlamJump") < < util.wait(self.groundJumpWaitTime, function(dt) < return mcontroller.yVelocity() < 0 < end) < self:setState(self.windup, false) < return < end < 58d50 < world.debugLine(lastSlamPosition, newSlamPosition, "yellow") items\active\weapons\melee\altabilities\hammer\uppercut\uppercut.altability 55a56,59 > "chargeTime" : 0.6, > "minChargeTime" : 0.2, > "knockback" : [0, 70], > 59d62 < "knockback" : [0, 50], 67,68c70,71 < "duration" : 0.4, < "armRotation" : -90, --- > "armRotation" : -80, > "endArmRotation" : -100, 69a73 > "endWeaponRotation" : -170, items\active\weapons\melee\altabilities\hammer\uppercut\uppercut.lua 1a2 > require "/scripts/vec2.lua" 17c18,23 < if self.weapon.currentAbility == nil and self.cooldownTimer == 0 and self.fireMode == "alt" and status.overConsumeResource("energy", self:energyUsage()) then --- > if self.weapon.currentAbility == nil > and self.cooldownTimer == 0 > and self.fireMode == "alt" > and not status.resourceLocked("energy") > and status.resource("energy") >= self:energyUsage() * (self.minChargeTime / self.chargeTime) then > 28c34,41 < util.wait(self.stances.windup.duration, function(dt) --- > local chargeTimer = 0 > while self.fireMode == "alt" and (chargeTimer == self.chargeTime or status.overConsumeResource("energy", self:energyUsage() * (1 / self.chargeTime) * self.dt)) do > chargeTimer = math.min(self.chargeTime, chargeTimer + self.dt) > > local chargeRatio = math.sin(chargeTimer / self.chargeTime * 1.57) > self.weapon.relativeArmRotation = util.toRadians(util.lerp(chargeRatio, {self.stances.windup.armRotation, self.stances.windup.endArmRotation})) > self.weapon.relativeWeaponRotation = util.toRadians(util.lerp(chargeRatio, {self.stances.windup.weaponRotation, self.stances.windup.endWeaponRotation})) > 33,35d45 < -- Interrupt wait on running out of energy < return status.resourceLocked("energy") < end) 37,38c47,51 < if status.overConsumeResource("energy", self:energyUsage()) then < self:setState(self.fire) --- > coroutine.yield() > end > > if chargeTimer >= self.minChargeTime then > self:setState(self.fire, chargeTimer / self.chargeTime) 42c55 < function uppercut:fire() --- > function uppercut:fire(charge) 47a61,62 > > self.damageConfig.knockback = vec2.mul(self.knockback, charge) items\active\weapons\melee\altabilities\spear\barrier\barrier.altability 65,68c65,68 < "fire" : [ "/sfx/melee/barrier_create_fire.ogg" ], < "electric" : [ "/sfx/objects/teslaspike.ogg" ], < "ice" : [ "/sfx/melee/barrier_create_ice.ogg" ], < "poison" : [ "/sfx/melee/barrier_create_poison.ogg" ] --- > "fireActive" : [ "/sfx/melee/barrier_create_fire.ogg" ], > "electricActive" : [ "/sfx/melee/barrier_create_electric.ogg" ], > "iceActive" : [ "/sfx/melee/barrier_create_ice.ogg" ], > "poisonActive" : [ "/sfx/melee/barrier_create_poison.ogg" ] items\active\weapons\melee\altabilities\spear\barrier\barrier.lua 24c24 < animator.playSound(self.weapon.elementalType, -1) --- > animator.playSound(self.weapon.elementalType.."Active", -1) 62c62 < animator.stopAllSounds(self.weapon.elementalType) --- > animator.stopAllSounds(self.weapon.elementalType.."Active") items\active\weapons\melee\altabilities\spear\rocketspear\rocketspear.altability 66c66 < "cooldownTime" : 1.0, --- > "cooldownTime" : 0.5, 68,70c68 < "dashSpeed" : 100, < "dashControlForce" : 1600, < "freezeTime" : 0.1, --- > "boostForce" : 130, 73,76c71,74 < "fire" : "firelance", < "ice" : "icelance", < "electric" : "electriclance", < "poison" : "poisonlance" --- > "fire" : "flamethrower", > "ice" : "icethrower", > "electric" : "flamethrower", > "poison" : "poisonthrower" 80c78 < "power" : 2 --- > "speed" : 20 82c80,81 < "projectileCount" : 5, --- > "baseDps" : 5, > "fireTime" : 0.08, 86,88c85,87 < "duration" : 0.5, < "armRotation" : -15, < "weaponRotation" : -75, --- > "duration" : 0.15, > "armRotation" : -100, > "weaponRotation" : 10, 90c89 < "weaponOffset" : [0.0, 1.5], --- > "weaponOffset" : [0, 0.5], 92,93c91,92 < "allowRotate" : true, < "allowFlip" : true --- > "allowRotate" : false, > "allowFlip" : false 96d94 < "duration" : 0.2, 100c98 < "weaponOffset" : [0.0, 1.0], --- > "weaponOffset" : [0.0, 1.25], 102,103c100,101 < "allowRotate" : false, < "allowFlip" : false --- > "allowRotate" : true, > "allowFlip" : true items\active\weapons\melee\altabilities\spear\rocketspear\rocketspear.lua 18c18 < if self.weapon.currentAbility == nil and self.fireMode == "alt" and self.cooldownTimer == 0 and status.overConsumeResource("energy", self:energyUsage()) then --- > if self.weapon.currentAbility == nil and self.fireMode == "alt" and self.cooldownTimer == 0 and not status.resourceLocked("energy") then 40,52c40,58 < local dashAngle = self.weapon.aimAngle + math.pi < local dashDirection = {mcontroller.facingDirection() * math.cos(dashAngle), math.sin(dashAngle)} < local fireInterval = self.stances.fire.duration / self.projectileCount < local shots = 0 < < while shots < self.projectileCount do < local projectile = self.elementalProjectiles[self.weapon.elementalType] < local position = vec2.add(mcontroller.position(), activeItem.handPosition(animator.partPoint("chargeSwoosh", "projectileSource"))) < local aim = self.weapon.aimAngle + util.randomInRange({-self.inaccuracy, self.inaccuracy}) < local params = copy(self.projectileParameters) < params.power = self:damageAmount() < if not world.lineTileCollision(mcontroller.position(), position) then < world.spawnProjectile(projectile, position, activeItem.ownerEntityId(), {mcontroller.facingDirection() * math.cos(aim), math.sin(aim)}, false, params) --- > local projectile = self.elementalProjectiles[self.weapon.elementalType] > local params = copy(self.projectileParameters) > params.power = self:damageAmount() * self.fireTime > > local fireTimer = 0 > while self.fireMode == "alt" and status.overConsumeResource("energy", self:energyUsage() * self.dt) do > self.weapon:updateAim() > > local boostForce = vec2.mul({mcontroller.facingDirection() * math.cos(self.weapon.aimAngle + math.pi), math.sin(self.weapon.aimAngle + math.pi)}, self.boostForce) > mcontroller.controlForce(boostForce) > > fireTimer = math.max(0, fireTimer - self.dt) > if fireTimer == 0 then > fireTimer = self.fireTime > local position = vec2.add(mcontroller.position(), activeItem.handPosition(animator.partPoint("chargeSwoosh", "projectileSource"))) > local aim = self.weapon.aimAngle + util.randomInRange({-self.inaccuracy, self.inaccuracy}) > if not world.lineTileCollision(mcontroller.position(), position) then > world.spawnProjectile(projectile, position, activeItem.ownerEntityId(), {mcontroller.facingDirection() * math.cos(aim), math.sin(aim)}, false, params) > end 54,65d59 < < shots = shots + 1 < util.wait(fireInterval, function(dt) < mcontroller.controlApproachVelocity(vec2.mul(dashDirection, self.dashSpeed), self.dashControlForce) < mcontroller.controlParameters({ < airFriction = 0, < groundFriction = 0, < liquidFriction = 0, < gravityEnabled = false < }) < end) < end 67,69c61,62 < util.wait(self.freezeTime, function(dt) < mcontroller.setVelocity({0,0}) < end) --- > coroutine.yield() > end 75c68 < return self.projectileParameters.power * root.evalFunction("swordDamageLevelMultiplier", item.instanceValue("level", 1)) * activeItem.ownerPowerMultiplier() --- > return self.baseDps * root.evalFunction("swordDamageLevelMultiplier", item.instanceValue("level", 1)) * activeItem.ownerPowerMultiplier() 79c72 < return self.energyUsageMultiplier * root.evalFunction("gunLevelEnergyCostPerDamage", item.instanceValue("level", 1)) * self:damageAmount() * self.projectileCount --- > return self.energyUsageMultiplier * root.evalFunction("gunLevelEnergyCostPerDamage", item.instanceValue("level", 1)) * self:damageAmount() items\active\weapons\melee\broadsword\rarebroadsword.activeitem 106,110c106,111 < "/items/active/weapons/melee/altabilities/broadsword/giantsword/giantsword.altability", < "/items/active/weapons/melee/altabilities/broadsword/travelingslash/travelingslash.altability", < "/items/active/weapons/melee/altabilities/generic/blinkexplosion/blinkexplosion.altability", < "/items/active/weapons/melee/altabilities/generic/blinkslash/blinkslash.altability", < "/items/active/weapons/melee/altabilities/broadsword/traildash/traildash.altability" --- > // "/items/active/weapons/melee/altabilities/broadsword/giantsword/giantsword.altability", > // "/items/active/weapons/melee/altabilities/broadsword/travelingslash/travelingslash.altability", > // "/items/active/weapons/melee/altabilities/generic/blinkexplosion/blinkexplosion.altability", > "/items/active/weapons/melee/altabilities/generic/blinkslash/blinkslash.altability" > // , > // "/items/active/weapons/melee/altabilities/broadsword/traildash/traildash.altability" items\active\weapons\melee\hammer\commonhammer.activeitem 110,111c110,111 < //"/items/active/weapons/melee/altabilities/hammer/uppercut/uppercut.altability", < //"/items/active/weapons/melee/altabilities/hammer/shockwave/physicalshockwave.altability", --- > "/items/active/weapons/melee/altabilities/hammer/uppercut/uppercut.altability", > "/items/active/weapons/melee/altabilities/hammer/shockwave/physicalshockwave.altability", items\active\weapons\ranged\altabilities\guidedrocket\guidedrocket.altability 55c55 < "duration" : 0.4, --- > "duration" : 0.7, items\active\weapons\ranged\rocketlauncher\rarerocketlauncher.activeitem 89c89 < "duration" : 0.4, --- > "duration" : 0.5, monsters\bmonster.lua 104a105,107 > if args.type == nil or args.state == nil or args.type == "" or args.state == "" then > return false > end 203c206 < if args.sound == nil then return false end --- > if args.sound == nil or args.sound == "" then return false end monsters\walkers\gleap\gleap.animation 4c4 < "movement" : { --- > "body" : { 19c19 < "jump" : { --- > "hop" : { 23c23 < "transition" : "jumpfull" --- > "transition" : "hopfull" 25c25 < "jumpfull" : { --- > "hopfull" : { 54c54 < "movement" : { --- > "body" : { 65c65 < "jump" : { --- > "hop" : { 70c70 < "jumpfull" : { --- > "hopfull" : { 72c72 < "image" : ":jump." --- > "image" : ":hop." monsters\walkers\gleap\gleap.frames 9c9 < [null, "jump.1", "jump.2", "jump.3"], --- > [null, "hop.1", "hop.2", "hop.3"], monsters\walkers\gleap\gleap.monstertype 89c89 < "movement" : "hurt" --- > "body" : "hurt" monsters\walkers\ophidaunt\ophidaunt.animation 4c4 < "movement" : { --- > "body" : { 44c44 < "movement" : { --- > "body" : { 119c119,120 < "deathPuff" : [ "/sfx/npc/enemydeathpuff.ogg" ] --- > "deathPuff" : [ "/sfx/npc/enemydeathpuff.ogg" ], > "fire" : [ "/sfx/npc/smallbiped/arrowhead_small_attack1.ogg" ] monsters\walkers\ophidaunt\ophidaunt.frames 8c8 < [ null, "slither.1", "slither.2", "slither.3", "slither.4", "slither.5", "slither.6", null, "jump.1", null, "fall.1" ], --- > [ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", null, "jump.1", null, "fall.1" ], 12c12 < } --- > } \ No newline at end of file monsters\walkers\ophidaunt\ophidaunt.monstertype 19c19 < "damageOnTouch" : false, --- > "damageOnTouch" : true, 30a31,32 > "fleeActions" : [], > 31a34,67 > { > "name" : "action-fire", > "parameters" : { > "projectileType" : "acidspit", > "power" : 5, > "fireOffset" : [1.125, 0.6875], > > "maximumRange" : 15, > "minimumRange" : 0, > > "fireWindupState" : "fire", > "fireState" : "", > "fireWinddownState" : "", > "windupTime" : 0.3, > "winddownTime" : 0.5, > "fireSound" : "fire" > } > } > ], > > "periodicActions" : [], > > "approachActions" : [ > { > "name" : "approach-walk", > "parameters" : { > "canJump" : true, > "maxJumps" : 3, > "jumpXVelocity" : 12, > "jumpYVelocity" : 30, > "jumpXControlForce" : 50, > "minXRange" : 2 > } > } 34c70,77 < "periodicActions" : [ --- > "wanderActions" : [ > { > "name" : "wander-walk", > "cooldown" : 6.0, > "parameters" : { > "wanderTime" : [0.5, 2.5] > } > } 39c82 < "poly" : [ [1.0625, 1.25], [1.0625, -1.25], [-1.0625, -1.25], [-1.0625, 1.25] ], --- > "poly" : [ [0.3125, 1.25], [0.8125, 0.75], [0.8125, -0.75], [0.3125, -1.25], [-0.3125, -1.25], [-0.8125, -0.75], [-0.8125, 0.75], [-0.3125, 1.25] ], 55c98 < "walkSpeed" : 5, --- > "walkSpeed" : 8, 57c100,107 < "jumpSpeed" : 5 --- > > "airFriction" : 0, > > "airJumpProfile" : { > "jumpSpeed" : 45.0, > "jumpInitialPercentage" : 1.0, > "jumpHoldTime" : 0.0 > } 64c114 < "movement" : "hurt" --- > "body" : "hurt" objects\wired\forcepad\jumppad.object 38,39c38,39 < "type" : "RectangularForceRegion", < "region" : [-2, 0, 2, 4], --- > "type" : "DirectionalForceRegion", > "rectRegion" : [-2, 0, 2, 4], quests\generated\subquests.config 605a606,608 > }, > "spawnPoint" : { > "type" : "location" 617c620,621 < "positionParam" : "other", --- > "positionParam" : "spawnPoint", > "spawnOffset" : [1.0, 3.5], 624a629 > ["nearbySpawnPoint", "spawnPoint"], scripts\behavior.lua 337a338,342 > function halt(args) > coroutine.yield("running") > return true > end > scripts\util.lua 64a65,88 > function util.boundBox(poly) > local min = {} > local max = {} > for _,vertex in ipairs(poly) do > if not min[1] or vertex[1] < min[1] then > min[1] = vertex[1] > end > if not min[2] or vertex[2] < min[2] then > min[2] = vertex[2] > end > if not max[1] or vertex[1] > max[1] then > max[1] = vertex[1] > end > if not max[2] or vertex[2] > max[2] then > max[2] = vertex[2] > end > end > if not min[1] or not min[2] or not max[1] or not max[2] then > return {0, 0, 0, 0} > end > return {min[1], min[2], max[1], max[2]} > end > > -------------------------------------------------------------------------------- scripts\actions\entities.lua 73a74 > -- output yDirection 86a88 > BData:setNumber(output.yDirection, util.toDirection(toTarget[2])) scripts\actions\math.lua 57a58,74 > -- param first > -- param second > -- output vector > function vecMultiply(args, output) > args = parseArgs(args, { > first = nil, > second = nil > }) > > local first = BData:getVec2(args.first) > local second = BData:getVec2(args.second) > if first == nil or second == nil then return false end > > BData:setVec2(output.vector, vec2.mul(first, second)) > return true > end > scripts\actions\movement.lua 112a113,119 > function controlJump(args, output) > args = parseArgs(args, {}) > mcontroller.controlJump() > mcontroller.controlHoldJump() > return true > end > scripts\behavior\bdata.lua 353a354,367 > -- param entity > -- output entity > function setVector(args, output) > args = parseArgs(args, { > vector = 0 > }) > > local vector = BData:getVec2(args.vector) > if vector == nil then return false end > > BData:setVec2(output.vector, BData:getVec2(args.vector)) > return true > end > scripts\quest\manager\summon_npcs.lua 28a29,37 > local function randomPositionInPoly(poly, offset) > local boundBox = util.boundBox(poly) > local rangeX = boundBox[3] - boundBox[1] - offset[1] * 2 > assert(rangeX > 0) > local x = math.random() * rangeX + boundBox[1] + offset[1] > local y = boundBox[2] + offset[2] > return {x, y} > end > 34a44,46 > end > if positionParam and positionParam.location then > position = randomPositionInPoly(positionParam.location, self.config.spawnOffset) scripts\questgen\context.lua 3a4 > self._queryPosition = queryPosition 16a18,89 > end > > -- FIXME don't hard-code the size of this poly, make it configurable to allow > -- spawning larger monsters > local function makeSpawnPoly(x,y) > return {{x-2, y}, {x+2, y}, {x+2, y+4}, {x-2, y+4}} > end > > local function makeSpawnRect(x,y) > return {x-2, y, x+2, y+4} > end > > local function canSpawnAt(x,y) > local collidesHere = world.rectTileCollision(makeSpawnRect(x,y), {"Block", "Null"}) > local collidesBelow = world.rectTileCollision(makeSpawnRect(x,y+1), {"Block", "Null", "Platform", "Dynamic"}) > return not collidesHere and collidesBelow > end > > local function findSpawnPointNear(x, approximateY) > local maxTries = entity.configParameter("questGenerator.spawnPointMaxYDelta", 16) > for dy = 0, maxTries do > if canSpawnAt(x, approximateY+dy) then > return {x, approximateY+dy} > end > if canSpawnAt(x, approximateY-dy) then > return {x, approximateY-dy} > end > end > return nil > end > > function QuestContext:spawnPoints() > -- Return a list of nearby position ideally outside of the town/colony that > -- we could spawn monsters or enemy NPCs at. Or nil if none could be found. > -- The bounds of the town/colony are approximated by the bound box of all the > -- npcs we found in our entity query. > > local npcs = self:entitiesByType()["npc"] > local minDistance = 0 > local maxDistance = 0 > local minPosition = nil > local maxPosition = nil > for _,npc in pairs(npcs) do > local diff = world.distance(npc:position(), self._queryPosition) > if diff[1] < minDistance then > minDistance = diff[1] > minPosition = npc:position() > end > if diff[1] > maxDistance then > maxDistance = diff[1] > maxPosition = npc:position() > end > end > > local spawnDistance = entity.configParameter("questGenerator.spawnPointXDelta", 10) > > local results = {} > if minPosition then > local spawnPoint = findSpawnPointNear(minPosition[1] - spawnDistance, minPosition[2]) > if spawnPoint then > results[#results+1] = spawnPoint > end > end > if maxPosition then > local spawnPoint = findSpawnPointNear(maxPosition[1] + spawnDistance, maxPosition[2]) > if spawnPoint then > results[#results+1] = spawnPoint > end > end > return util.map(results, function (position) > return QuestPredicands.Location.new(makeSpawnPoly(position[1], position[2])) > end) scripts\questgen\generator.lua 333a334,341 > [QuestPredicands.Location] = function (location) > return { > type = "location", > location = location.poly, > name = location.name > } > end, > scripts\questgen\predicands.lua 12a13,22 > function QuestPredicands.Entity:position() > if self._entityId and world.entityExists(self._entityId) then > return world.entityPosition(self._entityId) > end > assert(self._uniqueId) > -- If this entity has no uniqueId and doesn't exist, the QuestContext should > -- have removed this entity from consideration already. > return world.findUniqueEntity(self._uniqueId) > end > 243a254,260 > end > > QuestPredicands.Location = createClass("Location") > > function QuestPredicands.Location:init(poly, name) > self.poly = poly > self.name = name scripts\questgen\relations.lua 10a11 > local Location = QuestPredicands.Location 748a750,770 > > default = Relation.empty > } > > QuestRelations.nearbySpawnPoint = defineQueryRelation("nearbySpawnPoint", true) { > [case(1, Location)] = function (self, location) > if xor(self.negated, not world.polyCollision(location.poly), {"Block", "Null"}) then > return {{location}} > end > return Relation.empty > end, > > [case(2, Nil)] = function (self) > if self.negated then > return Relation.some > end > > return util.map(self.context:spawnPoints(), function (spawnPoint) > return {spawnPoint} > end) > end,