Daimonin
Members login
Sign Up!
problems?
Home
•
Game Guide
•
Support
•
Shop
•
Gallery
•
Forum
•
Download
Daimonin Forum
Welcome Guest, you have to register to post here.
Search
Advanced search
News
Stats
74021
Posts in
6703
Topics by
8113
Members
Latest Member:
honda
Daimonin Forum
|
Project News
|
Official announcements
|
Programmers' blogs
| Topic:
SENTInce
« previous
next »
Pages:
[
1
]
2
3
...
8
Go Down
Topic: SENTInce (Read 5384 times)
smacky
Administrator
Karma: +114/-96
Posts: 5251
SENTInce
«
on:
April 23, 2007, 08:06:33 pm »
Here is /scripts/church.lua reworked for SENTInce. I hope you'll agree it kicks the old version's arse (not sure who I just insulted
).
To run it you need to fetch streams/SENTInce/maps/lua/*.lua (well, ib and tl) and copy them over your local versions. It won't work without, but old scripts will continue to work with.
For the moment ignore the first line and just copy this script over /scripts/church.lua.
Note that this is only a bare bones version, so it's not intended to do much more (ie, have the priest talk about other topics) than the original and I have not added any synonyms to tl really.
The reason I am posting it here rather than committing it is because I feel B4 should not use the stuff in /scripts/, but its own non-public scripts (as I posted somewhere before) and this is intended as the basis for that.
Oh, ignore any warnings you get about truncation (which doesn't seem to work ATM). I think that is still in development.
Code:
-- /planes/demon_plane/stoneglow/priest.lua
require("interface_builder")
require("topic_list")
local activator = event.activator
local me = event.me
local ib = InterfaceBuilder()
local tl = TopicList()
local topic_greeting = function ()
ib:SetMsg("Welcome to the Holy Church of the Tabernacle! I am " .. me:GetName() ..".\n")
ib:AddMsg("\nIf you are confused by my services, I can ^explain^ them further.\n")
ib:AddMsg("\nHow can I help, my child?")
ib:AddLink("Teach me Minor Healing", "teach minor healing")
ib:AddLink("Cast Remove Death Sickness on me", "cast remove death sickness")
ib:AddLink("Cast Remove Depletion on me", "cast remove depletion")
ib:AddLink("Cast Restoration on me", "cast restoration")
ib:AddLink("Cast Cure Disease on me", "cast cure disease")
ib:AddLink("Cast Cure Poison on me", "cast cure poison")
ib:AddLink("Cast Remove Curse on my inventory", "cast remove curse")
ib:AddLink("Cast Remove Damnation on my inventory", "cast remove damnation")
ib:AddLink("Please share some food", "share food")
end
local topic_explain = function (service)
if service == "minor healing" then
ib:SetMsg("I will ^teach Minor Healing^ to you for no charge.")
return "explain", "explain services"
elseif service == "death sickness" then
ib:SetMsg("Death sickness is a stronger form of ^depletion^.\n")
ib:AddMsg("\nEverytime you die your stats are depleted by death sickness.\n")
ib:AddMsg("\nI will ^cast Remove Death Sickness^ on you for " .. activator:ShowCost(100 + (4 * activator.level * activator.level)))
return "explain", "explain services"
elseif service == "depletion" then
ib:SetMsg("I will ^cast Remove Depletion^ on you for ".. activator:ShowCost(5 * activator.level))
return "explain", "explain services"
elseif service == "restoration" then
ib:SetMsg("I will ^cast Restoration^ on you for 150 copper")
return "explain", "explain services"
elseif service == "disease" then
ib:SetMsg("I will ^cast Cure Disease^ on you for ".. activator:ShowCost(100 * activator.level))
return "explain", "explain services"
elseif service == "poison" then
ib:SetMsg("I will ^cast Cure Poison^ for " .. activator:ShowCost(5 * activator.level))
return "explain", "explain services"
elseif service == "curse" then
ib:SetMsg("I will ^cast Remove Curse^ over your inventory for ".. activator:ShowCost(100 * activator.level))
return "explain", "explain services"
elseif service == "damnation" then
ib:SetMsg("I will ^cast Remove Damnation^ over your inventory for " .. activator:ShowCost(100 + (3 * activator.level * activator.level)))
return "explain", "explain services"
else -- if not services then
ib:SetMsg("I can teach you basic prayers that you can cast yourself.\n")
ib:AddMsg("\nI can also cure various ailments and exorcise evil spirits from your items.")
ib:AddLink("Explain Minor Healing to me", "explain minor healing")
ib:AddLink("Explain Death Sickness to me", "explain death sickness")
ib:AddLink("Explain Depletion to me", "explain depletion")
ib:AddLink("Explain Restoration to me", "explain restoration")
ib:AddLink("Explain Disease to me", "explain disease")
ib:AddLink("Explain Poison to me", "explain poison")
ib:AddLink("Explain Curse to me", "explain curse")
ib:AddLink("Explain Damnation to me", "explain damnation")
return "services"
end
end
local topic_teach = function (prayer) -- Clumsy. Should be rewritten if the priest can ever teach more than one spell.
if prayer == "minor healing" then
local prayernr = game:GetSpellNr(prayer)
if activator:DoKnowSpell(prayernr) then
ib:SetMsg("You already know the prayer '" .. prayer .. "'!")
return "services"
else
local skill = "divine prayers"
local skillnr = game:GetSkillNr(skill)
ib:SetMsg("Yes, you seem worthy of that knowledge.\n")
if activator:FindSkill(skillnr) == nil then
ib:AddMsg("\nFirst I will teach you the skill you need to cast prayers.\n")
ib:AddMsg("\n|** You learn '" .. skill .. "' **|")
activator:AcquireSkill(skillnr, game.LEARN)
end
activator:AcquireSpell(prayernr, game.LEARN)
ib:AddMsg("\n|** You learn the prayer '" .. prayer .. "' **|")
end
else
ib:SetMsg("I don't think I know that one.")
end
return "services"
end
local topic_cast = function (prayer)
local sum = 0
if prayer == "remove death sickness" then
sum = 100 + (4 * activator.level * activator.level)
elseif prayer == "remove depletion" then
sum = 5 * activator.level
elseif prayer == "restoration" then
sum = 150
elseif prayer == "cure disease" then
sum = 100 * activator.level
elseif prayer == "cure poison" then
sum = 5 * activator.level
elseif prayer == "remove curse" then
sum = 100 * activator.level
elseif prayer == "remove damnation" then
sum = 100 + (3 * activator.level * activator.level)
else
ib:SetMsg("I don't think I know that one.")
end
if sum then
if activator:PayAmount(sum) == 1 then
me:CastSpell(activator, game:GetSpellNr(prayer), 1, 0, "")
ib:SetMsg("|** " .. me:GetName() .. " takes your money **|\n")
ib:AddMsg("\nHold still... done!")
else
ib:SetMsg("You have not the funds!")
end
end
return "services"
end
local topic_sharefood = function ()
if activator.food < 150 then
activator.food = 500
ib:SetMsg("Eat, my child, eat.\n")
ib:AddMsg("\n|** Your stomach is filled again **|")
else
ib:SetMsg("You don't look very hungry to me.")
end
return "services"
end
tl:SetDefault("I am not quite getting your meaning. Please try other words.")
tl:AddTopics({ unpack(tl.synonyms.greeting), "services?" }, topic_greeting)
tl:AddTopics({ "explain", "explain%s+(.+)" }, topic_explain)
tl:AddTopics({ "(minor%s+healing)", "(death%s+sickness)", "(depletion)", "(restoration)", "(disease)", "(poison)", "(curse)", "(damnation)" }, topic_explain)
tl:AddTopics("teach%s+(.+)", topic_teach)
tl:AddTopics("cast%s+(.+)", topic_cast)
tl:AddTopics({ "share%s+food", "food" }, topic_sharefood)
ib:ShowInterface(event, tl:CheckMessage(event))
Logged
Read
Smacky's Guides
Syber
Giant slime
Karma: +0/-0
Posts: 17
SENTInce
«
Reply #1 on:
April 23, 2007, 10:24:46 pm »
It does look cleaner
Logged
smacky
Administrator
Karma: +114/-96
Posts: 5251
SENTInce
«
Reply #2 on:
April 23, 2007, 11:15:46 pm »
You made it here Syber.
The main reason it looks cleaner is simply my coding style. I like my whitespace and non-cryptic variable names (sadly people don't find calling the player variable 'moron' nearly as funny as I do so as I refuse to use 'pl' I've gone with the bland 'activator' -- where is the love?)
But also SENTInce handles the interface header, title, and buttons for you and opens/closes it automatically too. So instead of dealing with all that in each topic_foo function in your script you just call ib:ShowInterface() once at the end.
Finally, by using sensible natural language topics and pattern matching you can cut out a lot of duplicated code (reading this Grommit?
), so my version is 3 or 4 functions shorter than the original.
It's better in play as well.
Logged
Read
Smacky's Guides
grommit
Administrator
Karma: +27/-2
Posts: 2481
SENTInce
«
Reply #3 on:
April 24, 2007, 09:49:23 am »
Quote from: "smacky"
you can cut out a lot of duplicated code (reading this Grommit?
)
I hate duplicated code - don't know why you singled me out. If I need code in more than one place it goes in a function. If it's a repeated string it goes in a variable.
Logged
smacky
Administrator
Karma: +114/-96
Posts: 5251
SENTInce
«
Reply #4 on:
April 24, 2007, 10:40:52 am »
You took the wrong half of my sentence:
Quote
by using sensible natural language topics and pattern matching ... (reading this Grommit? Razz)
Logged
Read
Smacky's Guides
Gecko
Administrator
Karma: +4/-0
Posts: 817
SENTInce
«
Reply #5 on:
April 24, 2007, 11:30:02 am »
A few comments based on the example script:
- A very readable script. Congratulations! Now if only you felt like rewriting all the other scripts ;-)
- I think dropping "moron" for "activator" was a good idea. I hate opinionated source.
- The sensible use of patterns and captures in the topics make for really simple code. Unfortunately it is probably too complex for inexperienced scripters =(
- I see only two negative points:
* the use of "{ unpack(foo),bar,baz }" is a bit annoying. AddTopics can be extended to accept nested tables so that it would be enough to write "{ foo, bar, baz }" and let AddTopics deal with the unpacking.
* the use of return values from the topic functions is very non-self-explaining. I don't understand it (without reading the specs or source), so I believe other will have similar problems. I would prefer a slightly more verbose and self-explaining API. Something like "tl:SetFoo('services')" or even "ib:SetFoo('services')" instead of "return 'services'".
Logged
Daimonin developer, admin and moderator.
grommit
Administrator
Karma: +27/-2
Posts: 2481
SENTInce
«
Reply #6 on:
April 24, 2007, 11:51:11 am »
Quote from: "smacky"
You took the wrong half of my sentence:
Quote
by using sensible natural language topics and pattern matching ... (reading this Grommit? Razz)
Did you look at my updated trade_safe.lua? They don't come much more pattern-matchy than that.
Also using the form
Code:
local topic_greeting = function ()
just because you can, is imo just crypticising
Code:
local function topic_greeting()
Logged
Alderan
Administrator
Karma: +16/-2
Posts: 461
SENTInce example script
«
Reply #7 on:
April 24, 2007, 03:01:17 pm »
Quote from: "smacky"
Oh, ignore any warnings you get about truncation (which doesn't seem to work ATM). I think that is still in development.
The warning will be thrown out by the client (in the development-version) when a title/link/button is too long to get fully shown. (So the scripter can rewrite that to fit in the interface)
the title: 'topic: cast remove death sickness' is too long, so this warning is right.
The truncation works, header-titles and buttons-text will be truncated in the string.
For message-titles and links the truncation will be automatically done by SDL_ClipRect.
See here the different truncations:
http://daimonin.fapo.domainfactory-kunde.de/ib_bright.jpg
Logged
Leider habe ich keine Zeit, Ihr Buch zu lesen, schicken Sie mir bitte ein bereits gelesenes.
smacky
Administrator
Karma: +114/-96
Posts: 5251
SENTInce
«
Reply #8 on:
April 24, 2007, 03:13:27 pm »
Quote from: "Gecko"
- A very readable script. Congratulations! Now if only you felt like rewriting all the other scripts ;-)
Actually that kind of is my intention (I am now doing scripts/smith.lua -- I want to make Stoneglow-specific versions of all the scripts in scripts/ at the very least). But rewriting scripts is a bit dull for me and might not make me too popular with the original authors.
My hope is that with a few examples people will agree that doing things a la SENTInce is good for scripters and players (a little structure and consistency makes the end result so much better and contrary to popular belief structure does not stifle creativity; it enables it. So sticking to the style guide won't hinder anyone's conversation-writing).
Quote
- The sensible use of patterns and captures in the topics make for really simple code. Unfortunately it is probably too complex for inexperienced scripters =(
It probably depends more on how the individual's brain works rather than scripting experience, but yeah, patterns and captures probably will always be underused.
Quote
* the use of "{ unpack(foo),bar,baz }" is a bit annoying. AddTopics can be extended to accept nested tables so that it would be enough to write "{ foo, bar, baz }" and let AddTopics deal with the unpacking.
Ooh, I didn't realise this! So to take the actual example, instead of:
Code:
l:AddTopics({ unpack(tl.synonyms.greeting), "services?" }, topic_greeting)
I could use:
Code:
l:AddTopics({ tl.synonyms.greeting, "services?" }, topic_greeting)
In fact, to my eye, the former is clearer (especially with syntax highlighting in vim so unpack is light blue), but yeah, fair point.
Quote
* the use of return values from the topic functions is very non-self-explaining. I don't understand it (without reading the specs or source), so I believe other will have similar problems. I would prefer a slightly more verbose and self-explaining API. Something like "tl:SetFoo('services')" or even "ib:SetFoo('services')" instead of "return 'services'".
Well yes it needs to be documented. After all, the whole ib/tl API is a bit unlear IMO without reading the docs.
The problem with doing it as you suggest is precisely the point you have made: is it a tl or an ib issue? I'd say tl because the topic_foo functions deal directly with tl:CheckMessage(). But then ultimately the returns are utilised by ib:ShowInterface() and ib:SetDecline(). I'd prefer not to have those lua/ scripts rely on each other's structures (ib:ShowInterface() uses the returns of tl:CheckMessage() but not the tl table itself).
Logged
Read
Smacky's Guides
grommit
Administrator
Karma: +27/-2
Posts: 2481
SENTInce
«
Reply #9 on:
April 24, 2007, 03:13:40 pm »
Very nice, Alderan! But "truancated" needs fixing
Logged
smacky
Administrator
Karma: +114/-96
Posts: 5251
SENTInce
«
Reply #10 on:
April 24, 2007, 03:24:01 pm »
Quote from: "grommit"
Did you look at my updated trade_safe.lua? They don't come much more pattern-matchy than that.
Actually no I haven't yet, but I remember you mentioned it. I'll have a look in a bit.
Quote
Also using the form
Code:
local topic_greeting = function ()
just because you can, is imo just crypticising
Code:
local function topic_greeting()
Ooh you meaney! It's not 'just because I can'. It's because that is correct and it makes more sense to me because it highlights the fact that Lua functions are normal variables, not special cases.
http://www.lua.org/manual/5.0/manual.html#2.5.8
So in fact you're just using syntactic sugar and I'm not crypticising at all.
It's like using the cursed mouse instead of the keyboard is just interfacial sugar.
Logged
Read
Smacky's Guides
smacky
Administrator
Karma: +114/-96
Posts: 5251
SENTInce example script
«
Reply #11 on:
April 24, 2007, 03:36:42 pm »
Quote from: "Alderan"
the title: 'topic: cast remove death sickness' is too long, so this warning is right.
The truncation works, header-titles and buttons-text will be truncated in the string.
For message-titles and links the truncation will be automatically done by SDL_ClipRect.
Yes, the thing that got me was that (is that) that title is just chopped halfway through the letter e of sickness IIRC. I think this is too precise. I think that truncation should be performed down to whole letters and you should replace the last letter of the truncated string with an ellipsis ('…') to indicate to the player that the string is longer but has been truncated. So eg, 'Topic cast remove death sickness' becomes 'Topic: cast remove death sick…'.
The problem is that the font bitmaps don't have an ellipsis defined (well, 11x15 does but in a character defined as a smiley in 7x4 *sigh*). Perhaps we should just say 255 is the Daimonin ellipsis character and add this to all the font bitmaps?
Logged
Read
Smacky's Guides
Alderan
Administrator
Karma: +16/-2
Posts: 461
SENTInce
«
Reply #12 on:
April 24, 2007, 06:36:29 pm »
Ah i see what you mean. In the code was for the whole interface-body already with ClipRect some graphical truncation, so i didn't touch that. But that can be done. I think we even don't need an ellipsis, due to the proportional fonts.
Quote
But "truancated" needs fixing
Yeah, that's atm one of my favorite word for misspelling, but i try my best do improve my english;-)
EDIT: truncation with ellipsis done
Logged
Leider habe ich keine Zeit, Ihr Buch zu lesen, schicken Sie mir bitte ein bereits gelesenes.
Gecko
Administrator
Karma: +4/-0
Posts: 817
SENTInce
«
Reply #13 on:
April 24, 2007, 09:05:50 pm »
Quote from: "smacky"
Quote
* the use of "{ unpack(foo),bar,baz }" is a bit annoying. AddTopics can be extended to accept nested tables so that it would be enough to write "{ foo, bar, baz }" and let AddTopics deal with the unpacking.
Ooh, I didn't realise this! So to take the actual example, instead of:
Code:
l:AddTopics({ unpack(tl.synonyms.greeting), "services?" }, topic_greeting)
I could use:
Code:
l:AddTopics({ tl.synonyms.greeting, "services?" }, topic_greeting)
In fact, to my eye, the former is clearer (especially with syntax highlighting in vim so unpack is light blue), but yeah, fair point.
Well, I would prefer
Code:
l:AddTopics({ tl.greetings, "services?" }, topic_greeting)
But you get the point. This of course requires a little recursive coding of AddTopics()...
Quote from: "smacky"
Quote
* the use of return values from the topic functions is very non-self-explaining. I don't understand it (without reading the specs or source), so I believe other will have similar problems. I would prefer a slightly more verbose and self-explaining API. Something like "tl:SetFoo('services')" or even "ib:SetFoo('services')" instead of "return 'services'".
Well yes it needs to be documented. After all, the whole ib/tl API is a bit unlear IMO without reading the docs.
The problem with doing it as you suggest is precisely the point you have made: is it a tl or an ib issue? I'd say tl because the topic_foo functions deal directly with tl:CheckMessage(). But then ultimately the returns are utilised by ib:ShowInterface() and ib:SetDecline(). I'd prefer not to have those lua/ scripts rely on each other's structures (ib:ShowInterface() uses the returns of tl:CheckMessage() but not the tl table itself).
If it is an interface function, it should go into ib. tl should not be tightly coupled to ib. I'm still not clear what the returned values are used for, which is precisely why I think an explicit method name would make it easier to understand. While the function return style is compact it is neither obvious nor extensible. Remember that readability is usually more important than writability.
Logged
Daimonin developer, admin and moderator.
smacky
Administrator
Karma: +114/-96
Posts: 5251
SENTInce
«
Reply #14 on:
April 24, 2007, 10:28:46 pm »
Quote from: "Gecko"
Well, I would prefer
Code:
l:AddTopics({ tl.greetings, "services?" }, topic_greeting)
Well yes. The reason for including the synonyms subtable is to keep that second layer nice and clean, for readability and possible future expandability (to throw you adjectives back at you
).
Quote
But you get the point. This of course requires a little recursive coding of AddTopics()...
Yes just had a go at this and got massively confused :lol: I'll try again later/tomorrow.
Re the magic returns, this is how it works:
A topic_foo function returns 1 or 2 values (counting the default implicit return nil).
These values, called txt and cmd, are then returned by tl:CheckMessage() via the internal _DoActions. If _DoActtions operates on a string (as often in the case of the default) txt is set to boolean true (and cmd is nil).
ib:ShowInterface() then takes txt and cmd as its second and third arguments, so the canonical way to call it is:
Code:
ib:ShowInterface(event, tl:CheckMessage(event))
(but of course this doesn't mean the one function relies on the other and importantly neither ib or tl structure has any direct contact with the other.)
So that is the journey of txt and cmd: they're born in topic_foo, educated in tl._DoActions(), graduate in tl:CheckMessage(), and work in ib:ShowInterface().
But what do they do? Well, cmd is only relevant if txt is a string. If txt is boolean true it tells ib:ShowInterface() to do an activator:Inteface(-1) -- close the interface immediately.
If txt is (currently) any other value but not a string (if I ever expand this the specific value is nil so this is the default behaviour) it tells ib:ShowInterface() to only show a Bye button (lhs).
If txt is a string it tells ib:ShowInterface() to also show a rhs button with txt as the text. In this case, if cmd is also a string it will be the command issued by selecting that button. If cmd is not a string then txt will be used as the command. Basically you usually want the text to be the same as the command so only one return is needed (eg, return "hello") but occasionally you will want different string (eg, where the command is more than about 12 characters, eg, return "explain", "explain services").
Quote
If it is an interface function, it should go into ib. tl should not be tightly coupled to ib.
Agreed. So which do you think is more appropriate?
Quote
I'm still not clear what the returned values are used for, which is precisely why I think an explicit method name would make it easier to understand. While the function return style is compact it is neither obvious nor extensible. Remember that readability is usually more important than writability.
Well hopefully my explanation has cleared things up. I can't argue that it is obvious but I do think the return system is in fact more extensible than tieing things down to an explicit method. But perhaps that would be more readable. But wbhat you gain in readbility perhaps you lose in flexibility?
Logged
Read
Smacky's Guides
Pages:
[
1
]
2
3
...
8
Go Up
Daimonin Forum
|
Project News
|
Official announcements
|
Programmers' blogs
| Topic:
SENTInce
« previous
next »
Jump to:
Please select a destination:
-----------------------------
Project News
-----------------------------
=> Official announcements
===> Michtoen's blog
===> Programmers' blogs
===> Artists' blogs
===> Musicians' blogs
===> Mapmakers' blogs
-----------------------------
Development
-----------------------------
=> This website
===> Forum
===> Wiki
===> Gallery
===> Shop
=> Daimonin project
===> Bug discussion
===> Suggestions
===> 3D client
=> Arches
=> Maps
===> Mapping tools
===> Map sets
===> Map wizardry
=> Scripts
-----------------------------
Contributions
-----------------------------
=> Graphics
===> Graphics requests
=> Sound & music
=> Writing
-----------------------------
Community
-----------------------------
=> Game rules
=> Newbies
=> Tech support
=> Community chat
=> Main server
===> Events
===> Clans
===> Marketplace
===> Spoilers
=> Test server
Page created in 0.216 seconds with 22 queries.
Powered by SMF 1.1.4
|
SMF © 2006-2007, Simple Machines LLC
Seo4Smf v0.2 © Webmaster's Talks
Loading...
Copyright 2008 Daimonin MMORPG •
Terms of Service
•
XHTML
•