Hi everyone. I'm needing a little bit of help on how to do a few things I've got planned for my Classical Weaponry mod. So anyways... 1. How would I go about flipping the direction a weapon is facing for certain attacks in a combo. (for example, first slash is downward, then the second is upward, so the weapon sprite must be flipped to put its bladed edge up instead of down, and then the third is downward again and returns the weapon to its regular orientation). Is it at simple as setting a property in the respective section of the animation or weaponability files, or would it require something more complex like a script? 2. I want a certain special attack to temporarily lock all motion and controls for a short while after it is launched. That is, the player will be completely stopped and locked in place, even if in mid-air, being pushed, or in any other instance where movement is in some way forced on the player; and all control input will be disabled, including weapon/item selection, teleporting, and opening menus. Any idea how to pull this off? What I'm intending to use this for is an attack that's capable of instant killing most same-tier enemies and maybe even some of the weaker next-tier enemies, but it leaves you wide open and completely unable to defend yourself if you miss or fail to kill in one shot. 3. Is there a way to change the names (just displayed names, not ID) of vanilla items? More specifically, I'm planning on making a set of katana type weapons, one of which will be a Solus katana, so I'd like to change the name of Asra Nox's weapon to something like "Nox's Katana" or "Solus Blade".
1. Don't know off hand. Probably some animation function for this. If nothing else, a change of frame should work. 2. I don't think you can prevent opening menus etc as far as I know. I believe you can lock out controls though. I couldn't tell you off the top of my head but I could look it up.What you need you can find in \starbound\doc\lua\actormovementcontroller.md and you can find examples of that code in use with something like Notepad++'s "find in files" feature(pointed at your unpacked asset folder). 3. Yes that's a simple patch right there. Make a soluskatana.activeitem.patch file(maintain the same path). Code: [ { "op" : "replace", "path" : "/shortdescription", "value" : "Nox's Katana" } ]
1.- In the primary ability file you will find the value "stances", there you can change the position of the weapon and the position of the arm. Look for example the file \items\active\weapons\melee\abilities\shortsword\shortswordcombo.weaponability. Advice: If you are going to create new custom combos you need to patch the weaponabilities.config file in /items/buildscripts/ folder adding by adding the path of your new combo. 2.- You can only reduce or disable the movement of the player, the rest i think that is not possible to disable it.
Code: animation.setFlipped(true) This can be applied to weapon abilities to flip the weapon sprite left-to-right. You just have to make sure that you set back the property whenever your combo step is not the desired, flipped step. (I'll post a snippet from my own code when I get on for a dirty example of how I used it.) Edit: Code: if self.comboStep > 1 then animator.setFlipped(true) else animator.setFlipped(false) end Simple, basic, but it does what it needs to do. This section I positioned in the wind-up function of my weapon combo script. In my case, all stances past the first will display the flipped sprite. Default Sprite: Flipped Sprite, Rendered In-Game: (There is very easily a better way to do this, but I have it hardcoded because I don't need to use it anywhere else in my mod.)
Thanks everyone! For anyone interested, I made a little edit to the meleecombo.lua script so that flipping can be designated in the stances of the weaponability. ^.^ Code: --Edited meleecombo script, adding an extra parameter to stances which allows flipping the direction of a weapon. --Original by Chucklefish. Edited by Vinderex. --To use: add the "flipx" parameter to stances using this script, and set it to either true or false. --Note that this will also flip any animations and damage areas associated with the stance. -- Melee primary ability MeleeCombo = WeaponAbility:new() function MeleeCombo:init() self.comboStep = 1 self.energyUsage = self.energyUsage or 0 self:computeDamageAndCooldowns() self.weapon:setStance(self.stances.idle) self.edgeTriggerTimer = 0 self.flashTimer = 0 self.cooldownTimer = self.cooldowns[1] self.animKeyPrefix = self.animKeyPrefix or "" self.weapon.onLeaveAbility = function() animator.setFlipped(false) self.weapon:setStance(self.stances.idle) end end -- Ticks on every update regardless if this is the active ability function MeleeCombo:update(dt, fireMode, shiftHeld) WeaponAbility.update(self, dt, fireMode, shiftHeld) if self.cooldownTimer > 0 then self.cooldownTimer = math.max(0, self.cooldownTimer - self.dt) if self.cooldownTimer == 0 then self:readyFlash() end end if self.flashTimer > 0 then self.flashTimer = math.max(0, self.flashTimer - self.dt) if self.flashTimer == 0 then animator.setGlobalTag("bladeDirectives", "") end end self.edgeTriggerTimer = math.max(0, self.edgeTriggerTimer - dt) if self.lastFireMode ~= (self.activatingFireMode or self.abilitySlot) and fireMode == (self.activatingFireMode or self.abilitySlot) then self.edgeTriggerTimer = self.edgeTriggerGrace end self.lastFireMode = fireMode if not self.weapon.currentAbility and self:shouldActivate() then self:setState(self.windup) end end -- State: windup function MeleeCombo:windup() local stance = self.stances["windup"..self.comboStep] self.weapon:setStance(stance) self.edgeTriggerTimer = 0 if stance.flipx==true then animator.setFlipped(true) else animator.setFlipped(false) end if stance.hold then while self.fireMode == (self.activatingFireMode or self.abilitySlot) do coroutine.yield() end else util.wait(stance.duration) end if self.energyUsage then status.overConsumeResource("energy", self.energyUsage) end if self.stances["preslash"..self.comboStep] then self:setState(self.preslash) else self:setState(self.fire) end end -- State: wait -- waiting for next combo input function MeleeCombo:wait() local stance = self.stances["wait"..(self.comboStep - 1)] self.weapon:setStance(stance) if stance.flipx==true then animator.setFlipped(true) else animator.setFlipped(false) end util.wait(stance.duration, function() if self:shouldActivate() then self:setState(self.windup) return end end) self.cooldownTimer = math.max(0, self.cooldowns[self.comboStep - 1] - stance.duration) self.comboStep = 1 end -- State: preslash -- brief frame in between windup and fire function MeleeCombo:preslash() local stance = self.stances["preslash"..self.comboStep] self.weapon:setStance(stance) if stance.flipx==true then animator.setFlipped(true) else animator.setFlipped(false) end self.weapon:updateAim() util.wait(stance.duration) self:setState(self.fire) end -- State: fire function MeleeCombo:fire() local stance = self.stances["fire"..self.comboStep] self.weapon:setStance(stance) if stance.flipx==true then animator.setFlipped(true) else animator.setFlipped(false) end self.weapon:updateAim() local animStateKey = self.animKeyPrefix .. (self.comboStep > 1 and "fire"..self.comboStep or "fire") animator.setAnimationState("swoosh", animStateKey) animator.playSound(animStateKey) local swooshKey = self.animKeyPrefix .. (self.elementalType or self.weapon.elementalType) .. "swoosh" animator.setParticleEmitterOffsetRegion(swooshKey, self.swooshOffsetRegions[self.comboStep]) animator.burstParticleEmitter(swooshKey) util.wait(stance.duration, function() local damageArea = partDamageArea("swoosh") self.weapon:setDamage(self.stepDamageConfig[self.comboStep], damageArea) end) if self.comboStep < self.comboSteps then self.comboStep = self.comboStep + 1 self:setState(self.wait) else self.cooldownTimer = self.cooldowns[self.comboStep] self.comboStep = 1 end end function MeleeCombo:shouldActivate() if self.cooldownTimer == 0 and (self.energyUsage == 0 or not status.resourceLocked("energy")) then if self.comboStep > 1 then return self.edgeTriggerTimer > 0 else return self.fireMode == (self.activatingFireMode or self.abilitySlot) end end end function MeleeCombo:readyFlash() animator.setGlobalTag("bladeDirectives", self.flashDirectives) self.flashTimer = self.flashTime end function MeleeCombo:computeDamageAndCooldowns() local attackTimes = {} for i = 1, self.comboSteps do local attackTime = self.stances["windup"..i].duration + self.stances["fire"..i].duration if self.stances["preslash"..i] then attackTime = attackTime + self.stances["preslash"..i].duration end table.insert(attackTimes, attackTime) end self.cooldowns = {} local totalAttackTime = 0 local totalDamageFactor = 0 for i, attackTime in ipairs(attackTimes) do self.stepDamageConfig[i] = util.mergeTable(copy(self.damageConfig), self.stepDamageConfig[i]) self.stepDamageConfig[i].timeoutGroup = "primary"..i local damageFactor = self.stepDamageConfig[i].baseDamageFactor self.stepDamageConfig[i].baseDamage = damageFactor * self.baseDps * self.fireTime totalAttackTime = totalAttackTime + attackTime totalDamageFactor = totalDamageFactor + damageFactor local targetTime = totalDamageFactor * self.fireTime local speedFactor = 1.0 * (self.comboSpeedFactor ^ i) table.insert(self.cooldowns, (targetTime - totalAttackTime) * speedFactor) end end function MeleeCombo:uninit() self.weapon:setDamage() end
One thing about LUA is that it handles boolean comparisons in an interesting way. Let me show you. You don't necessarily need to do this Code: if stance.flipx==true then because you could do this Code: if stance.flipx then LUA will treat all values which are not expressly false or nil as true. So if you tried to reference a nil value, the expression would simply be false... well not literally false but perhaps more like not true And that means you could optionally turn this Code: if stance.flipx==true then animator.setFlipped(true) else animator.setFlipped(false) end into this Code: animator.setFlipped(stance.flipx) ...except we wouldn't be catching the scenario of stance.flipx being nil. If you knew that would certainly not be nil, you'd be alright. In this case we aren't assured that, but this can be solved elegantly like so Code: animator.setFlipped(stance.flipx or false) or false is only there to catch scenarios of stance.flipx being nil. The expression to the right of or will not be evaluated at all if the expression on the left is true in which case you don't have to worry about running excessive code. Less code to do the same job is preferable, no? Actually you don't have to change it as I assume your code works fine as is. I just wanted to show you another way. Another consideration is you don't need to replace that script. You can just make save your alterned version as under a different name and just patch \items\active\weapons\melee\abilities\broadsword\broadswordcombo.weaponability and \items\active\weapons\melee\abilities\shortsword\shortswordcombo.weaponability That way your changes are incorporated.
Yeah, I know that part, and I'm not replacing it. I'm only using it for the new weapons in my mod that need it. As for the boolean stuff, good to know. ^.^ I kind of figured it'd work that way, but I'm a complete noob with lua (only ever worked with C, Java, and LSL before) and wasn't sure my edit would even work, so I figured better safe than sorry. lol
Bump. Still needing some tips on #2. Just disabling movement would be good enough if the other stuff isn't possible.
You could try the 'actormovementcontroller' branch: Code: mcontroller.controlModifiers({ speedModifier = 0.0, jumpModifier = 0.0, airJumpModifier = 0.0 }) Check the Lua docs concerning "actormovementcontroller". It's full of function pertaining to entity movement, while also accessible from activeitem scripts. From the sounds of what you're looking for, these functions should be right up your alley.
For the issue of freezing the player, you can use mcontroller.clearControls(), which prevents the player from using any inputs whatsoever. If you want to freeze them in the air, you could also use mcontroller.setYVelocity(0), which would remove all movement from them until you specify otherwise. So as an example code... Code: function init() self.frozenTime = 3 end function update(args) if self.frozenTime > 0 mcontroller.clearControls() mcontroller.setYVelocity(0) mcontroller.setYVelocity(0) unfreeze(arg.dt) end end function unfreeze(dt) self.frozenTime = self.frozenTime - dt end This would freeze the player for three seconds, disabling all controls and instantly stopping all movement until the freeze timer has ended.