Jump to content

Adding/Removing Traits from Player On Completion of Book


MountainSage

Recommended Posts

So I've been working on a the skeletal beginnings of a mod to add books that manage trait training but I've ran into a problem I can't figure out.

 

I'm pretty new to the language so a little green and I expect this is probably something really obvious that down the line I'll be hitting myself over not getting but I can't seem to modify the traits of a player on completion of a book.

 

Specifically, I'm using my own version of the ISReadABook class based off the original so to handle a book to turn Illiterate into Slow Reader and so far everything works all the way up until the point the reading finishes.

Then it just finishes reading and does nothing.

 

Here's the class below that's being used. Does anyone have any idea why this might not be working?

Side note: This is located in media/lua/client/TimedActions

--**************************************************************************************--**                    Based off "ISReadABook" by ROBERT JOHNSON                     **--**************************************************************************************require "TimedActions/ISBaseTimedAction"TTBLearnToRead = ISBaseTimedAction:derive("TTBLearnToRead");TTBLearnToRead.pageTimer = 0;function TTBLearnToRead:isValid()    return self.character:getInventory():contains(self.item) and ((self.item:getNumberOfPages() > 0 and self.item:getAlreadyReadPages() <= self.item:getNumberOfPages()) or self.item:getNumberOfPages() < 0);endfunction TTBLearnToRead:update()    TTBLearnToRead.pageTimer = TTBLearnToRead.pageTimer + 1;    self.item:setJobDelta(self:getJobDelta());    TTBLearnToRead.checkProgress(self);    if self.item:getNumberOfPages() > 0 then        local timeHours = getGameTime():getTimeOfDay()        if timeHours < self.startTimeHours then timeHours = timeHours + 24 end        local elapsedMins = (timeHours - self.startTimeHours) * 60        local pagesRead = math.floor(elapsedMins / self.minutesPerPage + 0.0001)        if self.startPage + pagesRead > self.item:getAlreadyReadPages() then        end        self.item:setAlreadyReadPages(self.startPage + pagesRead);        if self.item:getAlreadyReadPages() > self.item:getNumberOfPages() then            self.item:setAlreadyReadPages(self.item:getNumberOfPages());        end        self.character:setAlreadyReadPages(self.item:getFullType(), self.item:getAlreadyReadPages())    endend-- get how much % of the book we already read, then we apply a multiplier depending on the book read progressTTBLearnToRead.checkProgress = function(self)    local readPercent = (self.item:getAlreadyReadPages() / self.item:getNumberOfPages()) * 100;    if readPercent > 100 then        readPercent = 100;        self.character:getTraits():remove("Illiterate");        self.character:getTraits():add("SlowReader");    endendfunction TTBLearnToRead:start()    self.item:setJobType(getText("ContextMenu_Read") ..' '.. self.item:getName());    self.item:setJobDelta(0.0);    self.startTimeHours = getGameTime():getTimeOfDay()endfunction TTBLearnToRead:stop()    ISBaseTimedAction.stop(self);    if self.item:getNumberOfPages() > 0 and self.item:getAlreadyReadPages() >= self.item:getNumberOfPages() then        self.item:setAlreadyReadPages(self.item:getNumberOfPages());    end    self.item:setJobDelta(0.0);endfunction TTBLearnToRead:perform()    self.item:getContainer():setDrawDirty(true);    self.item:setJobDelta(0.0);    if self.item:getAlreadyReadPages() >= self.item:getNumberOfPages() then        self.item:setAlreadyReadPages(0);    end    ISBaseTimedAction.perform(self);endfunction TTBLearnToRead:new(character, item, time)    local o = {}    setmetatable(o, self)    self.__index = self    o.character = character;    o.item = item;    o.stopOnWalk = true;    o.stopOnRun = true;    if item:getNumberOfPages() > 0 then        item:setAlreadyReadPages(character:getAlreadyReadPages(item:getFullType()))        if isClient() then            o.minutesPerPage = ServerOptions.getFloat("MinutesPerPage") or 1.0            if o.minutesPerPage < 0.0 then o.minutesPerPage = 1.0 end        else            o.minutesPerPage = 2.0        end        o.startPage = item:getAlreadyReadPages()        local f = 1 / getGameTime():getMinutesPerDay() / 2        time = (item:getNumberOfPages() - item:getAlreadyReadPages()) * o.minutesPerPage / f        time = time + o.minutesPerPage / f -- go over the time a little so the last page is read    end    TTBLearnToRead.pageTimer = 0;    o.ignoreHandsWounds = true;    o.maxTime = time;    return o;end
Link to comment
Share on other sites

Instead of having a modified vanilla file that will conflict if the game ever updates it, why not just add a book item?

I'd imagine that the game has an event that fires once a book is read - if a book has been read and the book name is (for example) "Illiterate_To_Slowreader" and the player has the Illiterate trait, then it calls a function that removes the illiterate trait and adds the Slowreader trait.

 

I'm not sure if it's possible to remove traits, I'll look into it.
 

Link to comment
Share on other sites

I'm not sure if it's possible to remove traits, I'll look into it.

It is, the game does that already with traits like Athletic/Obese and Strong

 

xpUpdate.levelPerk = function(owner, perk, level, addBuffer)	-- first Strength skill, grant you some traits that gonna help you to carry more stuff, hitting harder, etc.	if perk == Perks.Strength then		-- we start to remove all previous Strength related traits		owner:getTraits():remove("Weak");		owner:getTraits():remove("Feeble");		owner:getTraits():remove("Stout");		owner:getTraits():remove("Strong");        -- now we add trait depending on your current lvl        if level >= 0 and level <= 1 then            owner:getTraits():add("Weak");        elseif level >= 2 and level <= 4 then            owner:getTraits():add("Feeble");        elseif level >= 6 and level <= 8 then            owner:getTraits():add("Stout");        elseif level >= 9 then            owner:getTraits():add("Strong");        end	end	-- then Fitness skill, grant you some traits that gonna help you to run faster, recovery faster, etc..	if perk == Perks.Fitness then		-- we start to remove all previous Fitness related traits		owner:getTraits():remove("Obese");		owner:getTraits():remove("Overweight");		owner:getTraits():remove("Fit");		owner:getTraits():remove("Athletic");		-- now we add trait depending on your current lvl		if level >= 0 and level <= 1 then			owner:getTraits():add("Obese");		elseif level >= 2 and level <= 4 then			owner:getTraits():add("Overweight");		elseif level >= 6 and level <= 8 then			owner:getTraits():add("Fit");		elseif level >= 9 then			owner:getTraits():add("Athletic");		end	end	-- we reset the xp multiplier for this perk--	owner:getXp():getMultiplierMap():remove(perk);	-- we add a "buffer" xp, so if you just get your lvl but you're still losing xp (if you've been lazy for a moment), you won't lose your lvl at the next tick	if addBuffer then--		owner:getXp():AddXP(perk, 5, false);	endend
Link to comment
Share on other sites

 

I'm not sure if it's possible to remove traits, I'll look into it.

It is, the game does that already with traits like Athletic/Obese and Strong

 

xpUpdate.levelPerk = function(owner, perk, level, addBuffer)	-- first Strength skill, grant you some traits that gonna help you to carry more stuff, hitting harder, etc.	if perk == Perks.Strength then		-- we start to remove all previous Strength related traits		owner:getTraits():remove("Weak");		owner:getTraits():remove("Feeble");		owner:getTraits():remove("Stout");		owner:getTraits():remove("Strong");        -- now we add trait depending on your current lvl        if level >= 0 and level <= 1 then            owner:getTraits():add("Weak");        elseif level >= 2 and level <= 4 then            owner:getTraits():add("Feeble");        elseif level >= 6 and level <= 8 then            owner:getTraits():add("Stout");        elseif level >= 9 then            owner:getTraits():add("Strong");        end	end	-- then Fitness skill, grant you some traits that gonna help you to run faster, recovery faster, etc..	if perk == Perks.Fitness then		-- we start to remove all previous Fitness related traits		owner:getTraits():remove("Obese");		owner:getTraits():remove("Overweight");		owner:getTraits():remove("Fit");		owner:getTraits():remove("Athletic");		-- now we add trait depending on your current lvl		if level >= 0 and level <= 1 then			owner:getTraits():add("Obese");		elseif level >= 2 and level <= 4 then			owner:getTraits():add("Overweight");		elseif level >= 6 and level <= 8 then			owner:getTraits():add("Fit");		elseif level >= 9 then			owner:getTraits():add("Athletic");		end	end	-- we reset the xp multiplier for this perk--	owner:getXp():getMultiplierMap():remove(perk);	-- we add a "buffer" xp, so if you just get your lvl but you're still losing xp (if you've been lazy for a moment), you won't lose your lvl at the next tick	if addBuffer then--		owner:getXp():AddXP(perk, 5, false);	endend

Ah, didn't see that one. Nice find!

 

...Time to immediately abuse this with Cheat Menu :P

Link to comment
Share on other sites

Instead of having a modified vanilla file that will conflict if the game ever updates it, why not just add a book item?

I'd imagine that the game has an event that fires once a book is read - if a book has been read and the book name is (for example) "Illiterate_To_Slowreader" and the player has the Illiterate trait, then it calls a function that removes the illiterate trait and adds the Slowreader trait.

 

I'm not sure if it's possible to remove traits, I'll look into it.

 

This isn't the vanilla file, this is an entirely seperate class that is based off the vanilla one that is specifically these books. That's how I'm getting around the illiterate fail check. All that bit works fine.

 

The only issue I'm running into is having the traits added or removed once the book is finished reading.

 

 

 

I'm not sure if it's possible to remove traits, I'll look into it.

It is, the game does that already with traits like Athletic/Obese and Strong

 

xpUpdate.levelPerk = function(owner, perk, level, addBuffer)	-- first Strength skill, grant you some traits that gonna help you to carry more stuff, hitting harder, etc.	if perk == Perks.Strength then		-- we start to remove all previous Strength related traits		owner:getTraits():remove("Weak");		owner:getTraits():remove("Feeble");		owner:getTraits():remove("Stout");		owner:getTraits():remove("Strong");        -- now we add trait depending on your current lvl        if level >= 0 and level <= 1 then            owner:getTraits():add("Weak");        elseif level >= 2 and level <= 4 then            owner:getTraits():add("Feeble");        elseif level >= 6 and level <= 8 then            owner:getTraits():add("Stout");        elseif level >= 9 then            owner:getTraits():add("Strong");        end	end	-- then Fitness skill, grant you some traits that gonna help you to run faster, recovery faster, etc..	if perk == Perks.Fitness then		-- we start to remove all previous Fitness related traits		owner:getTraits():remove("Obese");		owner:getTraits():remove("Overweight");		owner:getTraits():remove("Fit");		owner:getTraits():remove("Athletic");		-- now we add trait depending on your current lvl		if level >= 0 and level <= 1 then			owner:getTraits():add("Obese");		elseif level >= 2 and level <= 4 then			owner:getTraits():add("Overweight");		elseif level >= 6 and level <= 8 then			owner:getTraits():add("Fit");		elseif level >= 9 then			owner:getTraits():add("Athletic");		end	end	-- we reset the xp multiplier for this perk--	owner:getXp():getMultiplierMap():remove(perk);	-- we add a "buffer" xp, so if you just get your lvl but you're still losing xp (if you've been lazy for a moment), you won't lose your lvl at the next tick	if addBuffer then--		owner:getXp():AddXP(perk, 5, false);	endend

Already tried that. I tried one run of the lua file using owner: instead of self.character: like the traits for athletic/strength are handled, but that didn't seem to have an effect either.

 

...though that was just in my debug script. I'll try it with owner: in the book script to see if it works.

Link to comment
Share on other sites

snip

owner: is probably defined somewhere with something like

local owner = getPlayer();

Try substituting owner with getPlayer(); or defining it like that yourself in your code.

Edit: I mean try this getPlayer():getTraits():remove("Obese");

Edit 2: Scratch that, I now believe owner refers to something else and is defnined internally by an Event firing off like OnPlayerUpdate so yeah, that might itself work depending by what causes it.

Link to comment
Share on other sites

 

snip

owner: is probably defined somewhere with something like

local owner = getPlayer();

Try substituting owner with getPlayer(); or defining it like that yourself in your code.

Edit: I mean try this getPlayer():getTraits():remove("Obese");

Edit 2: Scratch that, I now believe owner refers to something else and is defnined internally by an Event firing off like OnPlayerUpdate so yeah, that might itself work depending by what causes it.

 

No luck, tried it as

TTBLearnToRead.checkProgress = function(self)    local readPercent = (self.item:getAlreadyReadPages() / self.item:getNumberOfPages()) * 100;    if readPercent >= 100 then        readPercent = 100;    end    if readpercent == 100 then        getPlayer():getTraits():remove("Illiterate");        getPlayer():getTraits():add("SlowReader");    endend

But didn't seem to work

 

EDIT: just noticed I'm doing an if with readpercent instead of readPercent. Going to see if fixing that has any effect.

 

EDIT 2: Ok so it appears that this is infact doing the intended behaviour HOWEVER it is not showing the update on character info? I still see the illiterate perk but am now able to read things. 

 

Edit 3: PROGRESS

9f80f6cbec6772a3b8709bfb5134463e.png

So the custom function is certainly working. Seems I just need to add a check to make sure it doesn't fire multiple times when reading the book. Then see if I can refreshing the characters info panel without needing to restart to see the updated traits.

 

Edit 4: Got it, no more duplicate traits being added ayyy

f2ff0ff618177b54d2e97d5bdc8b3d9d.png

Now to sort this panel refresh issue.

 

Edit 5: Panel refresh working. Thanks to Brybry helping me find the method needed to do it.

Link to comment
Share on other sites

Now that you worked it out, could you post the result (code that works) nad makr the thing as answered for future reference? Thanks :)

 

Yup here's the relevant code section with trait learning/unlearning, checks against duplicate effects and refreshing the character info panel (Provided by Brybry)

TTBLearnToRead.checkProgress = function(self)    local readPercent = (self.item:getAlreadyReadPages() / self.item:getNumberOfPages()) * 100;    if readPercent >= 100 then        readPercent = 100;    end    if readPercent == 100 then        -- self.character:Say("DEBUG: I have read the book!")        if getPlayer():HasTrait("Illiterate") then getPlayer():getTraits():remove("Illiterate"); end        if not getPlayer():HasTrait("SlowReader") then getPlayer():getTraits():add("SlowReader"); end        if ISCharacterInfoWindow.instance then ISCharacterInfoWindow.instance.charScreen:loadTraits(); end    end end
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...