Player achievements

If you have a module that you'd like comments on or would like to know how to create your very own module, post here

Moderator: Moderator

Message
Author
shani
Halfling
Posts: 83
Joined: Tue Aug 22, 2006 9:27 am
Location: Israel

Player achievements

#1 Post by shani »

I advance to patch files! :)
This one is for player achievements gaining (made it quite hackish :D )
and dumping them in character dump.
if you want the player achievements in the Actor.lua of the engine, or somewhere else more module oriented, i'm all in for it.
The patch also cnotains a small fix for object.lua getTextualDesc (fixing a previous mistake of mine)

Code: Select all

Index: engine/interface/WorldAchievements.lua
===================================================================
--- engine/interface/WorldAchievements.lua	(revision 906)
+++ engine/interface/WorldAchievements.lua	(working copy)
@@ -27,86 +27,102 @@
 
 --- Loads achievements
 function _M:loadDefinition(dir)
-	for i, file in ipairs(fs.list(dir)) do
-		if file:find("%.lua$") then
-			local f, err = loadfile(dir.."/"..file)
-			if not f and err then error(err) end
-			setfenv(f, setmetatable({
-				newAchievement = function(t) self:newAchievement(t) end,
-			}, {__index=_G}))
-			f()
-		end
-	end
+    for i, file in ipairs(fs.list(dir)) do
+        if file:find("%.lua$") then
+            local f, err = loadfile(dir.."/"..file)
+            if not f and err then error(err) end
+            setfenv(f, setmetatable({
+                newAchievement = function(t) self:newAchievement(t) end,
+            }, {__index=_G}))
+            f()
+        end
+    end
 end
 
 --- Make a new achivement with a name and desc
 function _M:newAchievement(t)
-	assert(t.name, "no achivement name")
-	assert(t.desc, "no achivement desc")
+    assert(t.name, "no achivement name")
+    assert(t.desc, "no achivement desc")
 
-	t.mode = t.mode or "none"
-	t.id = t.id or t.name
-	t.id = t.id:upper():gsub("[ ]", "_")
-	t.order = #self.achiev_defs+1
+    t.mode = t.mode or "none"
+    t.id = t.id or t.name
+    t.id = t.id:upper():gsub("[ ]", "_")
+    t.order = #self.achiev_defs+1
 
-	self.achiev_defs[t.id] = t
-	self.achiev_defs[#self.achiev_defs+1] = t
-	print("[ACHIEVEMENT] defined", t.order, t.id)
+    self.achiev_defs[t.id] = t
+    self.achiev_defs[#self.achiev_defs+1] = t
+    print("[ACHIEVEMENT] defined", t.order, t.id)
 end
 
 function _M:loadAchievements()
-	self.achieved = {}
+    self.achieved = {}
+    self.playerachieved = {}
 
-	for k, e in pairs(profile.mod) do
-		if k:find('^achievement%.') then
-			local id = k:gsub('^achievement%.', '')
-			if self.achiev_defs[id] then
-				self.achieved[id] = e
-			end
-		end
-	end
+    for k, e in pairs(profile.mod) do
+        if k:find('^achievement%.') then
+            local id = k:gsub('^achievement%.', '')
+            if self.achiev_defs[id] then
+                self.achieved[id] = e
+            end
+        end
+    end
 end
 
 function _M:getAchievementFromId(id)
-	return self.achiev_defs[id]
+    return self.achiev_defs[id]
 end
 
+
+--- Gain Personal achievement for player only
+-- @param id the achivement to gain
+-- @param src who did it
+function _M:gainPersonalAchievement(id, src, a, ...)
+   if self.playerachieved[id] then return end
+   
+   self.playerachieved[id] = {turn=game.turn, when=os.date("%Y-%m-%d %H:%M:%S")}
+   game.log("#LIGHT_GREEN#Personal New Achievement: %s!", a.name)
+   Dialog:simplePopup("Personal New Achievement: #LIGHT_GREEN#"..a.name, a.desc)
+end
+
 --- Gain an achievement
 -- @param id the achivement to gain
 -- @param src who did it
 function _M:gainAchievement(id, src, ...)
-	local a = self.achiev_defs[id]
-	if not a then error("Unknown achievement "..id) return end
-	if self.achieved[id] then return end
+    local a = self.achiev_defs[id]
+    if not a then error("Unknown achievement "..id) return end    
 
-	if a.can_gain then
-		local data = nil
-		if a.mode == "world" then
-			self.achievement_data = self.achievement_data or {}
-			self.achievement_data[id] = self.achievement_data[id] or {}
-			data = self.achievement_data[id]
-		elseif a.mode == "game" then
-			game.achievement_data = game.achievement_data or {}
-			game.achievement_data[id] = game.achievement_data[id] or {}
-			data = game.achievement_data[id]
-		elseif a.mode == "player" then
-			src.achievement_data = src.achievement_data or {}
-			src.achievement_data[id] = src.achievement_data[id] or {}
-			data = src.achievement_data[id]
-		end
-		if not a.can_gain(data, src, ...) then return end
-	end
+    if self.achieved[id] and self.playerachieved[id] then return end
+                                  
+    if a.can_gain then
+        local data = nil
+        if a.mode == "world" then
+             self.achievement_data = self.achievement_data or {}
+            self.achievement_data[id] = self.achievement_data[id] or {}
+            data = self.achievement_data[id]
+        elseif a.mode == "game" then
+            game.achievement_data = game.achievement_data or {}
+            game.achievement_data[id] = game.achievement_data[id] or {}
+            data = game.achievement_data[id]
+        elseif a.mode == "player" then
+            src.achievement_data = src.achievement_data or {}
+            src.achievement_data[id] = src.achievement_data[id] or {}
+            data = src.achievement_data[id]
+        end            
+        if not a.can_gain(data, src, data, ...) then return end
+    end
+    
+    if self.achieved[id] then self:gainPersonalAchievement(id, src, a, ...) return end
 
-	self.achieved[id] = {turn=game.turn, who=self:achievementWho(src), when=os.date("%Y-%m-%d %H:%M:%S")}
-	profile:saveModuleProfile("achievement."..id, self.achieved[id])
-
-	game.log("#LIGHT_GREEN#New Achievement: %s!", a.name)
-	Dialog:simplePopup("New Achievement: #LIGHT_GREEN#"..a.name, a.desc)
+    self.achieved[id] = {turn=game.turn, who=self:achievementWho(src), when=os.date("%Y-%m-%d %H:%M:%S")}
+    profile:saveModuleProfile("achievement."..id, self.achieved[id])
+    self.playerachieved[id] = {turn=game.turn, when=os.date("%Y-%m-%d %H:%M:%S")}
+    game.log("#LIGHT_GREEN#New Achievement: %s!", a.name)
+    Dialog:simplePopup("New Achievement: #LIGHT_GREEN#"..a.name, a.desc)
 end
 
 --- Format an achievement source
 -- By default just uses the actor's name, you can overload it to do more
 -- @param src the actor who did it
 function _M:achievementWho(src)
-	return src.name
+    return src.name
 end
Index: modules/tome/class/Object.lua
===================================================================
--- modules/tome/class/Object.lua	(revision 906)
+++ modules/tome/class/Object.lua	(working copy)
@@ -154,10 +154,7 @@
 
 --- Gets the full textual desc of the object without the name and requirements
 function _M:getTextualDesc()
-	local desc = {}
-	if self.encumber then
-		desc[#desc+1] = ("#67AD00#%0.2f Encumbrance."):format(self.encumber)
-	end
+	local desc = {}	
 
 	desc[#desc+1] = ("Type: %s / %s"):format(self.type, self.subtype)
 
@@ -295,6 +292,10 @@
 	if reqs then
 		desc[#desc+1] = reqs
 	end
+	
+	if self.encumber then
+		desc[#desc+1] = ("#67AD00#%0.2f Encumbrance."):format(self.encumber)
+	end
 
 	local textdesc = table.concat(self:getTextualDesc(), "\n")
 
Index: modules/tome/dialogs/CharacterSheet.lua
===================================================================
--- modules/tome/dialogs/CharacterSheet.lua	(revision 906)
+++ modules/tome/dialogs/CharacterSheet.lua	(working copy)
@@ -397,9 +397,17 @@
 				end
 			end
 		end
-	end
+	end	
 
 	nl()
+	nl("  [Player Achievments]")
+	nl()
+	for id, data in pairs(world.playerachieved) do
+		local a = world:getAchievementFromId(id)
+		nl(("%s Was Achieved for %s At %s"):format(a.name,a.desc,data.when))
+	end
+	
+	nl()
 	nl("  [Character Inventory]")
 	nl()
 	for item, o in ipairs(self.actor:getInven("INVEN")) do

darkgod
Master of Eyal
Posts: 10751
Joined: Wed Jul 24, 2002 9:26 pm
Location: Angolwen
Contact:

Re: Player achievements

#2 Post by darkgod »

Could you change your indentation to tabs please?
Otherwise I can not apply it :/
[tome] joylove: You can't just release an expansion like one would release a Kraken XD
--
[tome] phantomfrettchen: your ability not to tease anyone is simply stunning ;)

shani
Halfling
Posts: 83
Joined: Tue Aug 22, 2006 9:27 am
Location: Israel

Re: Player achievements

#3 Post by shani »

I thought you said spaces instead of tabs :)
Want me to repost with tabs?

darkgod
Master of Eyal
Posts: 10751
Joined: Wed Jul 24, 2002 9:26 pm
Location: Angolwen
Contact:

Re: Player achievements

#4 Post by darkgod »

Yeah please: )
Send it to me by mail it'll be less chance of broking too :)
[tome] joylove: You can't just release an expansion like one would release a Kraken XD
--
[tome] phantomfrettchen: your ability not to tease anyone is simply stunning ;)

shani
Halfling
Posts: 83
Joined: Tue Aug 22, 2006 9:27 am
Location: Israel

Re: Player achievements

#5 Post by shani »

Patch is ready, but what's your email? :)

darkgod
Master of Eyal
Posts: 10751
Joined: Wed Jul 24, 2002 9:26 pm
Location: Angolwen
Contact:

Re: Player achievements

#6 Post by darkgod »

darkgod (at) the domain of the te4 website
:)
[tome] joylove: You can't just release an expansion like one would release a Kraken XD
--
[tome] phantomfrettchen: your ability not to tease anyone is simply stunning ;)

shani
Halfling
Posts: 83
Joined: Tue Aug 22, 2006 9:27 am
Location: Israel

Re: Player achievements

#7 Post by shani »

Ok sent. Did you receive?

darkgod
Master of Eyal
Posts: 10751
Joined: Wed Jul 24, 2002 9:26 pm
Location: Angolwen
Contact:

Re: Player achievements

#8 Post by darkgod »

Yup thanks!
[tome] joylove: You can't just release an expansion like one would release a Kraken XD
--
[tome] phantomfrettchen: your ability not to tease anyone is simply stunning ;)

darkgod
Master of Eyal
Posts: 10751
Joined: Wed Jul 24, 2002 9:26 pm
Location: Angolwen
Contact:

Re: Player achievements

#9 Post by darkgod »

Integrated and fixed a few bugs :)

Now for player profiles:
- Have a new main menu entry to handle them (it exists already but it does not work)
- check out engine/PlayerProfile class
- make a screen to handle player profile, it should allow to display profile informations, create a new profile and register a profile online
- make the profile count interresting things, like the number of characters players, which modules, what birth descriptors, ...
- when online profile is requested it will need to ask for a login, and email and a password (see PlayerProfile:newProfile, you need to change it to work better)
- when the game runs for the first time make it ask the player for his online account or create one if he wishes

The synchronisation itself is already present and working you "just" need to make an UI for it

Thanks :)
[tome] joylove: You can't just release an expansion like one would release a Kraken XD
--
[tome] phantomfrettchen: your ability not to tease anyone is simply stunning ;)

Antagonist
Higher
Posts: 71
Joined: Sun May 23, 2010 9:55 am

Re: Player achievements

#10 Post by Antagonist »

Hmm, a thought.

Some people's natural instinct will be 'no online profile, dont submit, keep local, dont track my personal information, dont install spyware and track my shopping habits and sign me up for spam!'

For those, you already have an offline profile.

But how about, if you have an offline profile, then either YAWP or YASD you want to share, be able to sumbit an 'anonymous' character dump?

Unrelated, but I am VERY interested in the online profiles tho for data mining for balancing. Like... tracking that 65% of all players die when encountering The Master. Or 80% of Fighters lose against Bill, while only 10% of mages die. Or theres 20x more shadowblade players than rogue players. Or all the sources where ppl died due to a single hit doing >100% of their hp. Amount of poison/burning deaths and from what. All from a collection of character dumps.

Maybe even track some non-dump info, like instances where >70% of hp dmg is done in a single source, but doesn't kill the player. Or how common it is to do Trollshanks first, or those who go directly to Old Forest say.

This could be insanely useful for improving the balance of the game.

EDIT: Well, tracking statistically anyway, not individually.

darkgod
Master of Eyal
Posts: 10751
Joined: Wed Jul 24, 2002 9:26 pm
Location: Angolwen
Contact:

Re: Player achievements

#11 Post by darkgod »

Yeah such things would indeed be super good for balancing things
[tome] joylove: You can't just release an expansion like one would release a Kraken XD
--
[tome] phantomfrettchen: your ability not to tease anyone is simply stunning ;)

shani
Halfling
Posts: 83
Joined: Tue Aug 22, 2006 9:27 am
Location: Israel

Re: Player achievements

#12 Post by shani »

The synchronisation itself is already present and working you "just" need to make an UI for it
I liked the "just" bit :)
I'll start working on it after my current test, it's a hard one.

darkgod
Master of Eyal
Posts: 10751
Joined: Wed Jul 24, 2002 9:26 pm
Location: Angolwen
Contact:

Re: Player achievements

#13 Post by darkgod »

Yeah I have a way to make things sound so easy ;)
[tome] joylove: You can't just release an expansion like one would release a Kraken XD
--
[tome] phantomfrettchen: your ability not to tease anyone is simply stunning ;)

darkgod
Master of Eyal
Posts: 10751
Joined: Wed Jul 24, 2002 9:26 pm
Location: Angolwen
Contact:

Re: Player achievements

#14 Post by darkgod »

BTW shani could you check out this thread please ?
http://forum.t-o-m-e.net/viewtopic.php?f=36&t=21351
:)
[tome] joylove: You can't just release an expansion like one would release a Kraken XD
--
[tome] phantomfrettchen: your ability not to tease anyone is simply stunning ;)

shani
Halfling
Posts: 83
Joined: Tue Aug 22, 2006 9:27 am
Location: Israel

Re: Player achievements

#15 Post by shani »

I read it long time ago...
Everything I contribute is yours to do whatever you want with.
Throw use abuse, whatever suits you... :)

Post Reply