Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • amagad/t-engine4
  • HirumaKai/t-engine4
  • Hogulus/t-engine4
  • Inkie/t-engine4
  • Liberty/t-engine4
  • Lokean/t-engine4
  • Mawootad/t-engine4
  • Michelle/t-engine4
  • MrFrog/t-engine4
  • Nagyhal/t-engine4
  • Recaiden/t-engine4
  • RootOfAllThings/t-engine4
  • Sebsebeleb/t-engine4
  • Sheila/t-engine4
  • Shibari/t-engine4
  • Stof/t-engine4
  • Umbral/t-engine4
  • tome/t-engine4
  • 0player/t-engine4
  • BreezyIdiot/t-engine4
  • Bunny/t-engine4
  • Effigy/t-engine4
  • Hachem_Muche/t-engine4
  • razakai/t-engine4
  • Zireael/t-engine4
  • cinornu/t-engine4
  • edge2054/t-engine4
  • gordaxx727/t-engine4
  • grayswandir/t-engine4
  • helminthauge/t-engine4
  • housepet/t-engine4
  • minqmay/t-engine4
  • nsrr/t-engine4
  • orange/t-engine4
  • otowakotori/t-engine4
  • purequestion/t-engine4
  • rexorcorum/t-engine4
  • rgeens/t-engine4
  • sageacrin/t-engine4
  • stuntofthelitter/t-engine4
  • tiger_eye/t-engine4
  • xelivous/t-engine4
  • yutio888/t-engine4
43 results
Show changes
Showing
with 1203 additions and 811 deletions
......@@ -110,7 +110,7 @@ function _M:okclick()
end
game:unregisterDialog(self)
game:createProfile({create=self.c_email and true or false, login=self.c_login.text, pass=self.c_pass.text, email=self.c_email and self.c_email.text, news=self.c_news.checked})
game:createProfile({create=self.c_email and true or false, login=self.c_login.text, pass=self.c_pass.text, email=self.c_email and self.c_email.text, news=self.c_news and self.c_news.checked})
end
function _M:cancelclick()
......
......@@ -82,7 +82,7 @@ function _M:generateList()
-- Have to load the profile to get the highscores
profile:addStatFields(unpack(mod.profile_stats_fields or {}))
profile:loadModuleProfile(mod.short_name)
profile:loadModuleProfile(mod.short_name, mod)
print ("Loaded profile for "..mod.short_name.."\n")
mod.highscores = {}
if (profile.mod.scores and profile.mod.scores.sc) then
......
This diff is collapsed.
......@@ -918,7 +918,7 @@ end
function _M:changeLevelReal(lev, zone, params)
local oz, ol = self.zone, self.level
-- Unlock first!
if not params.temporary_zone_shift_back and self.level and self.level.temp_shift_zone then
self:changeLevelReal(1, "useless", {temporary_zone_shift_back=true})
......@@ -944,7 +944,7 @@ function _M:changeLevelReal(lev, zone, params)
end
-- clear chrono worlds and their various effects
if self._chronoworlds then self._chronoworlds = nil end
if self._chronoworlds and not params.keep_chronoworlds then self._chronoworlds = nil end
local left_zone = self.zone
local old_lev = (self.level and not zone) and self.level.level or -1000
......@@ -1101,7 +1101,7 @@ function _M:changeLevelReal(lev, zone, params)
list[#list+1] = {i, j}
end
end end
if #list > 0 then x, y = unpack(rng.table(list)) end
if #list > 0 then x, y = unpack((rng.table(list))) end
elseif params.auto_level_stair then
-- Dirty but quick
local list = {}
......@@ -1111,7 +1111,7 @@ function _M:changeLevelReal(lev, zone, params)
list[#list+1] = {i, j}
end
end end
if #list > 0 then x, y = unpack(rng.table(list)) end
if #list > 0 then x, y = unpack((rng.table(list))) end
end
-- if self.level.exited then -- use the last location, if defined
......@@ -1857,8 +1857,6 @@ do return end
print(f, err)
setfenv(f, setmetatable({level=self.level, zone=self.zone}, {__index=_G}))
print(pcall(f))
do return end
self:registerDialog(require("mod.dialogs.DownloadCharball").new())
end end,
[{"_f","ctrl"}] = function() if config.settings.cheat then
self.player.quests["love-melinda"] = nil
......
This diff is collapsed.
......@@ -77,7 +77,7 @@ function _M:act()
if self.emote_random and self.x and self.y and game.level.map.seens(self.x, self.y) and rng.range(0, 999) < self.emote_random.chance * 10 then
local e = util.getval(rng.table(self.emote_random))
if e then
local dur = util.bound(#e, 30, 90)
local dur = util.bound(#e, 45, 90)
self:doEmote(e, dur)
end
end
......@@ -474,25 +474,22 @@ function _M:addedToLevel(level, x, y)
for tid, lev in pairs(self.talents) do
self:learnTalent(tid, true, math.floor(lev / 2))
end
-- Give unrand bosses extra classes
-- Give randbosses extra classes
if not self.randboss and self.rank >= 3.5 and not self.no_difficulty_random_class then
local data = {}
if self.rank == 3.5 then data = {nb_classes=1}
elseif self.rank == 4 then data = {nb_classes=1}
elseif self.rank == 5 then data = {nb_classes=2}
elseif self.rank >= 10 then data = {nb_classes=3}
local nb_classes = 0
if self.rank >= 10 then nb_classes = 3
elseif self.rank >= 5 then nb_classes = 2
elseif self.rank >= 3.5 then nb_classes = 1
end
data.auto_sustain = true
data.forbid_equip = true
local data = {auto_sustain=true, forbid_equip=false, nb_classes=nb_classes, update_body=true, spend_points=true, autolevel=nb_classes<2 and self.autolevel or "random_boss"}
game.state:applyRandomClass(self, data, true)
self:resolve() self:resolve(nil, true)
end
-- Increase life
self.max_life_no_difficulty_boost = self.max_life
local lifeadd = self.max_life * 0.2
self.max_life = self.max_life + lifeadd
self.life = self.life + lifeadd
-- print("Insane increasing " .. self.name .. " life by " .. lifeadd)
self:attr("difficulty_boosted", 1)
elseif game.difficulty == game.DIFFICULTY_MADNESS then
-- Increase talent level
......@@ -500,15 +497,15 @@ function _M:addedToLevel(level, x, y)
self:learnTalent(tid, true, math.ceil(lev * 1.7))
end
if not self.randboss and self.rank >= 3.5 and not self.no_difficulty_random_class then
local data = {}
if self.rank == 3.5 then data = {nb_classes=1}
elseif self.rank == 4 then data = {nb_classes=2}
elseif self.rank == 5 then data = {nb_classes=3}
elseif self.rank >= 10 then data = {nb_classes=5}
local nb_classes = 0
if self.rank >= 10 then nb_classes = 5
elseif self.rank >= 5 then nb_classes = 3
elseif self.rank >= 4 then nb_classes = 2
elseif self.rank >= 3.5 then nb_classes = 1
end
data.auto_sustain = true
data.forbid_equip = true
local data = {auto_sustain=true, forbid_equip=false, nb_classes=nb_classes, update_body=true, spend_points=true, autolevel=nb_classes<2 and self.autolevel or "random_boss"}
game.state:applyRandomClass(self, data, true)
self:resolve() self:resolve(nil, true)
end
-- Increase life
self.max_life_no_difficulty_boost = self.max_life
......@@ -518,37 +515,8 @@ function _M:addedToLevel(level, x, y)
self:attr("difficulty_boosted", 1)
end
-- try to equip inventory items
local MainInven, o = self:getInven(self.INVEN_INVEN)
--if config.settings.cheat then self:inventoryApplyAll(function(inv, item, o) o:identify(true) end) end-- temp
if MainInven then --try to equip items from inventory
for i = #MainInven, 1, -1 do
o = MainInven[i]
local inven, worn = self:getInven(o:wornInven())
if inven and game.state:checkPowers(self, o, nil, "antimagic_only") then -- check antimagic restrictions
local ro, replace = inven and inven[1], false
o = self:removeObject(self.INVEN_INVEN, i)
if o then
-- could put more sophisticated criteria here to pick the best gear
if ro and o.type == ro.type and o.subtype == ro.subtype and (o.rare or o.randart or o.unique) and not (ro.rare or ro.randart or ro.unique) then replace = true end
worn = self:wearObject(o, replace, false)
if worn then
print("[NPC:addedToLevel]", self.name, self.uid, "wearing", o.name)
if type(worn) == "table" then
print("--- replacing", worn.name)
self:addObject(self.INVEN_INVEN, worn)
end
else
self:addObject(self.INVEN_INVEN, o) -- put object back in main inventory
end
end
end
end
end
self:wearAllInventory()
if self:knowTalent(self.T_COMMAND_STAFF) then -- make sure staff aspect is appropriate to talents
self:forceUseTalent(self.T_COMMAND_STAFF, {ignore_energy = true, ignore_cd=true, silent=true})
end
......
This diff is collapsed.
......@@ -1012,7 +1012,7 @@ function _M:restCheck()
-- Check for resources
for res, res_def in ipairs(_M.resources_def) do
if res_def.wait_on_rest and res_def.regen_prop and self:attr(res_def.regen_prop) then
if not res_def.invert_values then
if not res_def.invert_values and not res_def.switch_direction then
if self[res_def.regen_prop] > 0.0001 and self:check(res_def.getFunction) < self:check(res_def.getMaxFunction) then return true end
else
if self[res_def.regen_prop] < -0.0001 and self:check(res_def.getFunction) > self:check(res_def.getMinFunction) then return true end
......
......@@ -68,27 +68,46 @@ function _M:loadup(level, zone)
local old_minml = zone.min_material_level
local old_maxml = zone.max_material_level
if zone.store_levels_by_restock then
zone.base_level = zone.store_levels_by_restock[game.state.stores_restock] or zone.base_level
end
self.last_filled = self.last_filled or 0
if self.store.ignore_material_levels then
zone.min_material_level = 1
zone.max_material_level = 5
end
while self.last_filled < game.state.stores_restock do
local lev = (game.state.stores_restock_levels and game.state.stores_restock_levels[self.last_filled]) or 8
if zone.store_levels_by_restock then
zone.base_level = zone.store_levels_by_restock[self.last_filled] or zone.base_level
end
if Store.loadup(self, level, zone, self.store.nb_fill) then
self.last_filled = game.state.stores_restock
end
-- Increment material level every 10 levels with a special case at level 5
if self.store.player_material_level then
if lev == 5 then
zone.min_material_level = 1
zone.max_material_level = 2
else
zone.max_material_level = math.min(5, math.floor(lev / 10) + 1)
zone.min_material_level = math.max(1, zone.max_material_level - 1)
end
end
-- ignore_material_levels gets priority over other systems
if self.store.ignore_material_levels then
zone.min_material_level = 1
zone.max_material_level = 5
end
zone.min_material_level = old_minml
zone.max_material_level = old_maxml
zone.base_level = oldlev
-- Engine.store.loadup sets last_filled to something silly so we have to save it
local old_last_filled = self.last_filled
if Store.loadup(self, level, zone, self.store.nb_fill) then
self.last_filled = old_last_filled + 1
end
zone.min_material_level = old_minml
zone.max_material_level = old_maxml
zone.base_level = oldlev
-- clear chrono worlds and their various effects
if game._chronoworlds then
game.log("#CRIMSON#Your timetravel has no effect on pre-determined outcomes such as this.")
game._chronoworlds = nil
-- clear chrono worlds and their various effects
if game._chronoworlds then
game.log("#CRIMSON#Your timetravel has no effect on pre-determined outcomes such as this.")
game._chronoworlds = nil
end
end
end
......
......@@ -75,6 +75,8 @@ function _M:event(e)
self.chat:addMessage("link", e.channel, e.login, {e.name, color}, "#ANTIQUE_WHITE#has linked a creature: #WHITE# "..data.name, {mode="tooltip", tooltip=data.desc})
elseif data.kind == "killer-link" then
self.chat:addMessage("death", e.channel, e.login, {e.name, color}, "#CRIMSON#"..data.msg.."#WHITE#", data.desc and {mode="tooltip", tooltip=data.desc} or nil)
else
self:triggerHook{"UserChat:event", color=color, e=e, data=data}
end
end
end
......@@ -57,7 +57,7 @@ function _M:generate(lev, old_lev)
local rm
for i = 0, self.map.w - 1 do for j = 0, self.map.h - 1 do
rm = self.map.room_map[i][j]
if not rm.room then
if not (rm.room or rm.special or rm.can_open) then
local g
if self.level.data.subvaults_surroundings then g = self:resolve(self.level.data.subvaults_surroundings, nil, true)
else g = self:resolve("subvault_wall") end
......@@ -81,12 +81,13 @@ function _M:generate(lev, old_lev)
sx, sy = e.sx, e.sy
ex, ey = e.x, e.y
if not (sx and sy) then -- vault connection point: connect to a (nearest) non-vault grid
print("[VaultLevel] generating level start point from vault connection at", ex, ey)
-- start at center of room and pick a random direction
sx, sy = math.floor(rx+(room.w-1)/2), math.floor(ry+(room.h-1)/2)
local dir, xd, yd = util.getDir(ex, ey, sx+rng.normal(0, 1), sy+rng.normal(0, 1))
if dir == 5 then dir = rng.table(util.primaryDirs()) end
local rm
local steps = (self.map.w + self.map.h)/4
local steps = math.max(room.w, room.h) + 2*(room.border or 0) + 1
repeat
steps = steps - 1
rm = self.map.room_map[sx][sy]
......
......@@ -41,6 +41,11 @@ end
function _M:takeHit(value, src, death_note)
if self.onTakeHit then value = self:onTakeHit(value, src, death_note) end
if value <= 0 then return false, 0 end
if death_note and death_note.cant_die then
if value >= self.life then value = self.life - 1 end
end
self.life = self.life - value
self.changed = true
if self.life <= self.die_at and not self.dead then
......
......@@ -274,11 +274,10 @@ end
--- Computes a logarithmic chance to hit, opposing chance to hit to chance to miss
-- This will be used for melee attacks, physical and spell resistance
function _M:checkHitOld(atk, def, min, max, factor)
if atk < 0 then atk = 0 end
if def < 0 then def = 0 end
print("checkHit", atk, def)
print("checkHitOld", atk, def)
if atk == 0 then atk = 1 end
local hit = nil
factor = factor or 5
......@@ -293,7 +292,7 @@ function _M:checkHitOld(atk, def, min, max, factor)
return rng.percent(hit), hit
end
--Tells the tier difference between two values
--- Applies crossTierEffects according to the tier difference between power and save
function _M:crossTierEffect(eff_id, apply_power, apply_save, use_given_e)
local q = game.player:hasQuest("tutorial-combat-stats")
if q and not q:isCompleted("final-lesson")then
......@@ -328,7 +327,12 @@ function _M:getTierDiff(atk, def)
def = math.floor(def)
return math.max(0, math.max(math.ceil(atk/20), 1) - math.max(math.ceil(def/20), 1))
end
--[[
--- Gets the duration for crossTier effects based on the tier difference between atk and def
function _M:getTierDiff(atk, def)
return math.floor(math.max(0, self:combatScale(atk - def, 1, 20, 5, 100)))
end
--]]
--New, simpler checkHit that relies on rescaleCombatStats() being used elsewhere
function _M:checkHit(atk, def, min, max, factor, p)
if atk < 0 then atk = 0 end
......@@ -433,7 +437,7 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
end
local dam, apr, armor = force_dam or self:combatDamage(weapon), self:combatAPR(weapon), target:combatArmor()
print("[ATTACK] to ", target.name, " :: ", dam, apr, armor, atk, "vs.", def, "::", mult)
print("[ATTACK] to ", target.name, "dam/apr/atk/mult ::", dam, apr, atk, mult, "vs. armor/def", armor, def)
-- check repel
local repelled = false
......@@ -448,7 +452,7 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
self:fireTalentCheck("callbackOMeleeAttackBonuses", hd)
target, weapon, damtype, mult, dam, apr, atk, def, armor = hd.target, hd.weapon, hd.damtype, hd.mult, hd.dam, hd.apr, hd.atk, hd.def, hd.armor
if hd.stop then return end
print("[ATTACK] after melee attack bonus hooks and callbacks :: ", dam, apr, armor, atk, "vs.", def, "::", mult)
print("[ATTACK] after melee attack bonus hooks & callbacks::", dam, apr, atk, mult, "vs. armor/def", armor, def)
-- If hit is over 0 it connects, if it is 0 we still have 50% chance
local hitted = false
......@@ -503,6 +507,13 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
self:logCombat(target, "#Target# evades #Source#.")
elseif self.turn_procs.auto_melee_hit or (self:checkHit(atk, def) and (self:canSee(target) or self:attr("blind_fight") or target:attr("blind_fighted") or rng.chance(3))) then
local pres = util.bound(target:combatArmorHardiness() / 100, 0, 1)
-- Apply weapon damage range
-- By doing this first, variable damage is more "smooth" against high armor
local damrange = self:combatDamageRange(weapon)
dam = rng.range(dam, dam * damrange)
print("[ATTACK] HIT:: damrange", damrange, "==> dam/apr::", dam, apr, "vs. armor/hardiness", armor, pres)
local eff = target.knowTalent and target:hasEffect(target.EFF_PARRY)
-- check if target deflects the blow (deflected blows cannot crit)
if eff then
......@@ -515,28 +526,24 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
end
if target.knowTalent and target:hasEffect(target.EFF_GESTURE_OF_GUARDING) and not target:attr("encased_in_ice") then
local deflect = math.min(dam, target:callTalent(target.T_GESTURE_OF_GUARDING, "doGuard")) or 0
if deflect > 0 then
game:delayedLogDamage(self, target, 0, ("%s(%d gestured#LAST#)"):format(DamageType:get(damtype).text_color or "#aaaaaa#", deflect), false)
dam = dam - deflect
local g_deflect = math.min(dam, target:callTalent(target.T_GESTURE_OF_GUARDING, "doGuard")) or 0
if g_deflect > 0 then
game:delayedLogDamage(self, target, 0, ("%s(%d gestured#LAST#)"):format(DamageType:get(damtype).text_color or "#aaaaaa#", g_deflect), false)
dam = dam - g_deflect; deflect = deflect + g_deflect
end
print("[ATTACK] after GESTURE_OF_GUARDING", dam)
end
if self:isAccuracyEffect(weapon, "knife") then
local bonus = 1 + self:getAccuracyEffect(weapon, atk, def, 0.005, 0.25)
print("[ATTACK] dagger accuracy bonus", atk, def, "=", bonus, "previous", apr)
apr = apr * bonus
print("[ATTACK] dagger accuracy bonus", atk, def, "=", bonus, "apr ==>", apr)
end
print("[ATTACK] raw dam", dam, "versus", armor, pres, "with APR", apr)
armor = math.max(0, armor - apr)
dam = math.max(dam * pres - armor, 0) + (dam * (1 - pres))
print("[ATTACK] after armor", dam)
local damrange = self:combatDamageRange(weapon)
dam = rng.range(dam, dam * damrange)
print("[ATTACK] after range", dam)
if deflect == 0 then dam, crit = self:physicalCrit(dam, weapon, target, atk, def) end
print("[ATTACK] after crit", dam)
dam = dam * mult
......@@ -787,7 +794,7 @@ function _M:attackTargetHitProcs(target, weapon, dam, apr, armor, damtype, mult,
if dam > 0 and self:attr("damage_backfire") then
local hurt = math.min(dam, old_target_life) * self.damage_backfire / 100
if hurt > 0 then
self:takeHit(hurt, self)
self:takeHit(hurt, self, {cant_die=true})
end
end
......@@ -1281,13 +1288,19 @@ function _M:combatArmor()
if self:knowTalent(self.T_ARMOUR_OF_SHADOWS) and not game.level.map.lites(self.x, self.y) then
add = add + self:callTalent(self.T_ARMOUR_OF_SHADOWS,"ArmourBonus")
end
local light_armor = self:hasLightArmor()
if light_armor then
if self:knowTalent(self.T_SKIRMISHER_BUCKLER_EXPERTISE) then
add = add + self:callTalent(self.T_SKIRMISHER_BUCKLER_EXPERTISE, "getArmour")
end
end
if self:knowTalent(self.T_CORRUPTED_SHELL) then
add = add + self:getCon() / 3.5
end
if self:knowTalent(self.T_CARBON_SPIKES) and self:isTalentActive(self.T_CARBON_SPIKES) then
add = add + self.carbon_armor
end
if self:knowTalent(self["T_RESHAPE_WEAPON/ARMOUR"]) then add = add + self:callTalent(self["T_RESHAPE_WEAPON/ARMOUR"], "getArmorBoost") end
if self:knowTalent(self["T_FORM_AND_FUNCTION"]) then add = add + self:callTalent(self["T_FORM_AND_FUNCTION"], "getArmorBoost") end
return self.combat_armor + add
end
......@@ -1297,9 +1310,6 @@ end
function _M:combatArmorHardiness()
local add = 0
local multi = 1
if self:knowTalent(self.T_SKIRMISHER_BUCKLER_EXPERTISE) then
add = add + self:callTalent(self.T_SKIRMISHER_BUCKLER_EXPERTISE, "getHardiness")
end
if self:hasHeavyArmor() and self:knowTalent(self.T_ARMOUR_TRAINING) then
local at = Talents:getTalentFromId(Talents.T_ARMOUR_TRAINING)
add = add + at.getArmorHardiness(self, at)
......@@ -1316,6 +1326,9 @@ function _M:combatArmorHardiness()
if self:knowTalent(self.T_LIGHT_ARMOUR_TRAINING) then
add = add + self:callTalent(self.T_LIGHT_ARMOUR_TRAINING, "getArmorHardiness")
end
if self:knowTalent(self.T_SKIRMISHER_BUCKLER_EXPERTISE) then
add = add + self:callTalent(self.T_SKIRMISHER_BUCKLER_EXPERTISE, "getArmorHardiness")
end
end
if self:knowTalent(self.T_ARMOUR_OF_SHADOWS) and not game.level.map.lites(self.x, self.y) then
add = add + 50
......@@ -1332,7 +1345,7 @@ function _M:combatAttackBase(weapon, ammo)
local talent = self:callTalent(self.T_WEAPON_COMBAT, "getAttack")
local atk = 4 + self.combat_atk + talent + (weapon.atk or 0) + (ammo and ammo.atk or 0) + (self:getLck() - 50) * 0.4
if self:knowTalent(self["T_RESHAPE_WEAPON/ARMOUR"]) then atk = atk + self:callTalent(self["T_RESHAPE_WEAPON/ARMOUR"], "getDamBoost", weapon) end
if self:knowTalent(self["T_FORM_AND_FUNCTION"]) then atk = atk + self:callTalent(self["T_FORM_AND_FUNCTION"], "getDamBoost", weapon) end
if self:attr("hit_penalty_2h") then atk = atk * (1 - math.max(0, 20 - (self.size_category - 4) * 5) / 100) end
......@@ -1504,6 +1517,7 @@ end
-- raw if true specifies use of raw talent level
function _M:combatTalentScale(t, low, high, power, add, shift, raw)
local tl = type(t) == "table" and (raw and self:getTalentLevelRaw(t) or self:getTalentLevel(t)) or t
if tl <= 0 then tl = 0.1 end
power, add, shift = power or 0.5, add or 0, shift or 0
local x_low, x_high = 1, 5 -- Implied talent levels to fit
local x_low_adj, x_high_adj
......@@ -1565,6 +1579,7 @@ end
function _M:combatTalentLimit(t, limit, low, high, raw)
local x_low, x_high = 1,5 -- Implied talent levels for low and high values respectively
local tl = type(t) == "table" and (raw and self:getTalentLevelRaw(t) or self:getTalentLevel(t)) or t
if tl <= 0 then tl = 0.1 end
if low then
local p = limit*(x_high-x_low)
local m = x_high*high - x_low*low
......@@ -1658,9 +1673,10 @@ function _M:combatDamage(weapon, adddammod, damage)
totstat = totstat + self:getStat(stat) * mod
end
end
if self:knowTalent(self["T_FORM_AND_FUNCTION"]) then totstat = totstat + self:callTalent(self["T_FORM_AND_FUNCTION"], "getDamBoost", weapon) end
local talented_mod = 1 + self:combatTrainingPercentInc(weapon)
local power = self:combatDamagePower(damage or weapon)
return self:rescaleDamage(0.3*(self:combatPhysicalpower(nil, weapon) + totstat) * power * talented_mod)
local power = self:combatDamagePower(damage or weapon, totstat)
return self:rescaleDamage(0.3*self:combatPhysicalpower(nil, weapon, totstat) * power * talented_mod)
end
--- Gets the 'power' portion of the damage
......@@ -1668,8 +1684,6 @@ function _M:combatDamagePower(weapon_combat, add)
if not weapon_combat then return 1 end
local power = math.max((weapon_combat.dam or 1) + (add or 0), 1)
if self:knowTalent(self["T_RESHAPE_WEAPON/ARMOUR"]) then power = power + self:callTalent(self["T_RESHAPE_WEAPON/ARMOUR"], "getDamBoost", weapon_combat) end
return (math.sqrt(power / 10) - 1) * 0.5 + 1
end
......@@ -1807,7 +1821,7 @@ function _M:combatFatigue()
local min = self.min_fatigue or 0
local fatigue = self.fatigue
if self:knowTalent(self["T_RESHAPE_WEAPON/ARMOUR"]) then fatigue = fatigue - self:callTalent(self["T_RESHAPE_WEAPON/ARMOUR"], "getFatigueBoost") end
if self:knowTalent(self["T_FORM_AND_FUNCTION"]) then fatigue = fatigue - self:callTalent(self["T_FORM_AND_FUNCTION"], "getFatigueBoost") end
if self:knowTalent(self.T_LIGHT_ARMOUR_TRAINING) then
fatigue = fatigue - self:callTalent(self.T_LIGHT_ARMOUR_TRAINING, "getFatigue")
......
......@@ -87,17 +87,13 @@ function _M:dumpToJSON(js, bypass, nosub)
-------------------------------------------------------------------
local r = js:newSection("resources")
r.life = string.format("%d/%d", self.life, self.max_life)
if self:knowTalent(self.T_STAMINA_POOL) then r.stamina=string.format("%d/%d", self.stamina, self.max_stamina) end
if self:knowTalent(self.T_MANA_POOL) then r.mana=string.format("%d/%d", self.mana, self.max_mana) end
if self:knowTalent(self.T_SOUL_POOL) then r.souls=string.format("%d/%d", self.soul, self.max_soul) end
if self:knowTalent(self.T_POSITIVE_POOL) then r.positive=string.format("%d/%d", self.positive, self.max_positive) end
if self:knowTalent(self.T_NEGATIVE_POOL) then r.negative=string.format("%d/%d", self.negative, self.max_negative) end
if self:knowTalent(self.T_VIM_POOL) then r.vim=string.format("%d/%d", self.vim, self.max_vim) end
if self:knowTalent(self.T_PSI_POOL) then r.psi=string.format("%d/%d", self.psi, self.max_psi) end
if self.psionic_feedback_max then r.psi_feedback=string.format("%d/%d", self:getFeedback(), self:getMaxFeedback()) end
if self:knowTalent(self.T_EQUILIBRIUM_POOL) then r.equilibrium=string.format("%d", self.equilibrium) end
if self:knowTalent(self.T_PARADOX_POOL) then r.paradox=string.format("%d", self.paradox) end
if self:knowTalent(self.T_HATE_POOL) then r.hate=string.format("%d/%d", self.hate, self.max_hate) end
for res, res_def in ipairs(self.resources_def) do if res_def.talent and self:knowTalent(res_def.talent) then
if res_def.invert_values then
r[res_def.short_name] = string.format("%d", self[res_def.getFunction](self))
else
r[res_def.short_name] = string.format("%d/%d", self[res_def.getFunction](self), self[res_def.getMaxFunction](self))
end
end end
-------------------------------------------------------------------
-- Inscriptions
......@@ -108,7 +104,7 @@ function _M:dumpToJSON(js, bypass, nosub)
for i = 1, self.max_inscriptions do if self.inscriptions[i] then
local t = self:getTalentFromId("T_"..self.inscriptions[i])
local desc = tostring(self:getTalentFullDescription(t))
ins[#ins+1] = {name=t.name, kind=t.type[1], desc=desc}
ins[#ins+1] = {name=t.name, image=t.image, kind=t.type[1], desc=desc}
end end
-------------------------------------------------------------------
......@@ -237,7 +233,7 @@ function _M:dumpToJSON(js, bypass, nosub)
c.damage = {}
if self.inc_damage.all then c.damage.all = string.format("%d%%", self.inc_damage.all) end
for i, t in ipairs(DamageType.dam_def) do
for i, t in pairs(DamageType.dam_def) do
if self:combatHasDamageIncrease(DamageType[t.type]) then
c.damage[t.name] = string.format("%d%%", self:combatGetDamageIncrease(DamageType[t.type]))
end
......@@ -246,7 +242,7 @@ function _M:dumpToJSON(js, bypass, nosub)
c.damage_pen = {}
if self.resists_pen.all then c.damage_pen.all = string.format("%d%%", self.resists_pen.all) end
for i, t in ipairs(DamageType.dam_def) do
for i, t in pairs(DamageType.dam_def) do
if self.resists_pen[DamageType[t.type]] and self.resists_pen[DamageType[t.type]] ~= 0 then
c.damage_pen[t.name] = string.format("%d%%", self.resists_pen[DamageType[t.type]] + (self.resists_pen.all or 0))
end
......@@ -268,7 +264,7 @@ function _M:dumpToJSON(js, bypass, nosub)
d.resistances = {}
if self.resists.all then d.resistances.all = string.format("%3d%%(%3d%%)", self.resists.all, self.resists_cap.all or 0) end
for i, t in ipairs(DamageType.dam_def) do
for i, t in pairs(DamageType.dam_def) do
if self.resists[DamageType[t.type]] and self.resists[DamageType[t.type]] ~= 0 then
d.resistances[t.name] = string.format("%3d%%(%3d%%)", self:combatGetResist(DamageType[t.type]), (self.resists_cap[DamageType[t.type]] or 0) + (self.resists_cap.all or 0))
end
......@@ -307,7 +303,7 @@ function _M:dumpToJSON(js, bypass, nosub)
if not t.hide then
local skillname = t.name
local desc = self:getTalentFullDescription(t):toString()
td.list[#td.list+1] = { name=skillname, val=("%d/%d"):format(self:getTalentLevelRaw(t.id), t.points), desc=desc}
td.list[#td.list+1] = { name=skillname, image=t.image, val=("%d/%d"):format(self:getTalentLevelRaw(t.id), t.points), desc=desc}
end
end
end
......@@ -367,7 +363,7 @@ function _M:dumpToJSON(js, bypass, nosub)
local desc = tostring(o:getDesc())
equip[self.inven_def[inven_id].name] = equip[self.inven_def[inven_id].name] or {}
local ie = equip[self.inven_def[inven_id].name]
ie[#ie+1] = { name=o:getName{do_color=true, no_image=true}, desc=desc }
ie[#ie+1] = { name=o:getName{do_color=true, no_image=true}, image=o.image, desc=desc }
end
end
end
......@@ -378,7 +374,7 @@ function _M:dumpToJSON(js, bypass, nosub)
local inven = js:newSection("inventory")
for item, o in ipairs(self.inven[self.INVEN_INVEN]) do
local desc = tostring(o:getDesc())
inven[#inven+1] = { name=o:getName{do_color=true, no_image=true}, desc=desc }
inven[#inven+1] = { name=o:getName{do_color=true, no_image=true}, image=o.image, desc=desc }
end
-------------------------------------------------------------------
......@@ -424,6 +420,12 @@ function _M:dumpToJSON(js, bypass, nosub)
if self.has_custom_tile then
tags.tile = self.has_custom_tile
js:hiddenData("tile", self.has_custom_tile)
elseif self.moddable_tile then
local doll = { self.image }
for i, mo in ipairs(self.add_mos or {}) do
doll[#doll+1] = mo.image
end
js:hiddenData("doll", doll)
end
self:triggerHook{"ToME:PlayerDumpJSON", title=title, js=js, tags=tags}
......
......@@ -29,13 +29,13 @@ end
function _M:registerDeath(src)
local pid = self:playerStatGetCharacterIdentifier(game.party:findMember{main=true})
local name = src.name
profile:saveModuleProfile("deaths", {source=name, cid=pid, nb={"inc",1}})
profile:incrDataProfile("deaths", {source=name, cid=pid, nb=1})
end
function _M:registerUniqueKilled(who)
local pid = self:playerStatGetCharacterIdentifier(game.party:findMember{main=true})
profile:saveModuleProfile("uniques", {victim=who.name, cid=pid, nb={"inc",1}})
profile:incrDataProfile("uniques", {victim=who.name, cid=pid, nb=1})
end
function _M:registerArtifactsPicked(what)
......@@ -44,13 +44,13 @@ function _M:registerArtifactsPicked(what)
local pid = self:playerStatGetCharacterIdentifier(game.party:findMember{main=true})
local name = what:getName{do_color=false, do_count=false, force_id=true, no_add_name=true}
profile:saveModuleProfile("artifacts", {name=name, cid=pid, nb={"inc",1}})
profile:incrDataProfile("artifacts", {name=name, cid=pid, nb=1})
end
function _M:registerCharacterPlayed()
local pid = self:playerStatGetCharacterIdentifier(game.party:findMember{main=true})
profile:saveModuleProfile("characters", {cid=pid, nb={"inc",1}})
profile:incrDataProfile("characters", {cid=pid, nb=1})
end
function _M:registerLoreFound(lore)
......
......@@ -779,9 +779,9 @@ function _M:displayResources(scale, bx, by, a)
end
local shield, max_shield = 0, 0
if player:attr("time_shield") then shield = shield + player.time_shield_absorb max_shield = max_shield + player.time_shield_absorb_max end
if player:attr("damage_shield") then shield = shield + player.damage_shield_absorb max_shield = max_shield + player.damage_shield_absorb_max end
if player:attr("displacement_shield") then shield = shield + player.displacement_shield max_shield = max_shield + player.displacement_shield_max end
if player:attr("time_shield") then shield = shield + (player.time_shield_absorb or 0) max_shield = max_shield + (player.time_shield_absorb_max or 0) end
if player:attr("damage_shield") then shield = shield + (player.damage_shield_absorb or 0) max_shield = max_shield + (player.damage_shield_absorb_max or 0) end
if player:attr("displacement_shield") then shield = shield + (player.displacement_shield or 0) max_shield = max_shield + (player.displacement_shield_max or 0) end
local front = fshat_life_dark
if max_shield > 0 then
......
......@@ -79,6 +79,7 @@ newBirthDescriptor{
end
end end
end
tts["technique/combat-training"] = {true, 0}
return tts
end,
copy_add = {
......
......@@ -148,6 +148,10 @@ newBirthDescriptor{
},
copy = {
max_life = 90,
resolvers.auto_equip_filters{
MAINHAND = {type="weapon", subtype="mindstar"},
OFFHAND = {type="weapon", subtype="mindstar"},
},
resolvers.equipbirth{ id=true,
{type="weapon", subtype="mindstar", name="mossy mindstar", autoreq=true, ego_chance=-1000},
{type="weapon", subtype="mindstar", name="mossy mindstar", autoreq=true, ego_chance=-1000},
......
......@@ -49,6 +49,11 @@ newBirthDescriptor{
},
}
local shield_special = function(e) -- allows any object with shield combat
local combat = e.shield_normal_combat and e.combat or e.special_combat
return combat and combat.block
end
newBirthDescriptor{
type = "subclass",
name = "Sun Paladin",
......@@ -91,6 +96,24 @@ newBirthDescriptor{
},
copy = {
max_life = 110,
resolvers.auto_equip_filters{
MAINHAND = {type="weapon", special=function(e, filter) -- allow any weapon that doesn't forbid OFFHAND
if e.slot_forbid == "OFFHAND" then
local who = filter._equipping_entity
return who and not who:slotForbidCheck(e, who.INVEN_MAINHAND)
end
return true
end},
OFFHAND = {special=shield_special},
BODY = {type="armor", special=function(e, filter)
if e.subtype=="heavy" or e.subtype=="massive" then return true end
local who = filter._equipping_entity
if who then
local body = who:getInven(who.INVEN_BODY)
return not (body and body[1])
end
end},
},
resolvers.equipbirth{ id=true,
{type="weapon", subtype="mace", name="iron mace", autoreq=true, ego_chance=-1000},
{type="armor", subtype="shield", name="iron shield", autoreq=true, ego_chance=-1000},
......@@ -145,9 +168,20 @@ newBirthDescriptor{
},
copy = {
max_life = 90,
resolvers.auto_equip_filters{
MAINHAND = {type="weapon", subtype="staff"},
OFFHAND = {special=function(e, filter) -- only allow if there is a 1H weapon in MAINHAND
local who = filter._equipping_entity
if who then
local mh = who:getInven(who.INVEN_MAINHAND) mh = mh and mh[1]
if mh and (not mh.slot_forbid or not who:slotForbidCheck(e, who.INVEN_MAINHAND)) then return true end
end
return false
end}
},
resolvers.equipbirth{ id=true,
{type="weapon", subtype="staff", name="elm staff", autoreq=true, ego_chance=-1000},
{type="armor", subtype="cloth", name="linen robe", autoreq=true, ego_chance=-1000}
{type="armor", subtype="cloth", name="linen robe", autoreq=true, ego_chance=-1000},
},
},
}
......@@ -127,6 +127,17 @@ newBirthDescriptor{
},
copy = {
max_life = 90,
resolvers.auto_equip_filters{
MAINHAND = {type="weapon", subtype="staff"},
OFFHAND = {special=function(e, filter) -- only allow if there is a 1H weapon in MAINHAND
local who = filter._equipping_entity
if who then
local mh = who:getInven(who.INVEN_MAINHAND) mh = mh and mh[1]
if mh and (not mh.slot_forbid or not who:slotForbidCheck(e, who.INVEN_MAINHAND)) then return true end
end
return false
end}
},
resolvers.equipbirth{ id=true,
{type="weapon", subtype="staff", name="elm staff", autoreq=true, ego_chance=-1000},
{type="armor", subtype="cloth", name="linen robe", autoreq=true, ego_chance=-1000},
......@@ -200,6 +211,15 @@ newBirthDescriptor{
},
copy = {
max_life = 100,
resolvers.auto_equip_filters{MAINHAND = {type="weapon", subtype="longbow"},
OFFHAND = {type="none"},
QUIVER={properties={"archery_ammo"}, special=function(e, filter) -- must match the MAINHAND weapon, if any
local mh = filter._equipping_entity and filter._equipping_entity:getInven(filter._equipping_entity.INVEN_MAINHAND)
mh = mh and mh[1]
if not mh or mh.archery == e.archery_ammo then return true end
end},
QS_MAINHAND = {type="weapon", not_properties={"twohanded"}},
},
resolvers.equipbirth{ id=true,
{type="weapon", subtype="longbow", name="elm longbow", autoreq=true, ego_chance=-1000},
{type="ammo", subtype="arrow", name="quiver of elm arrows", autoreq=true, ego_chance=-1000},
......