library: RPG elements

Pertex
OK, here is my prototype of a RPG-library.
Some features:
equip/unequip items at spezific parts of the players body (helmet on his head, weapons in his hands...)
items affect stats
attack and loot enemys
stats like health/at/pa/strength/level/exp

The combatsystem will be changed so at the moment you only can attack an enemy

Try the demo testcombat.aslx

Pertex
Updated version running with Q5.4


BlunderingFool
Wow this looks really useful! Although I'll admit I'm having trouble figuring out how to use it now it's loaded into my game. :?

10tacle
Good morning guys, good morning Pertex!

At first, thank you for providing your combat system.
It works fine and you helped me a lot with it so far. Good job and thanks for that!
But I have some problems regarding the damage points system and that stuff, since I'm trying to modify it for my own game.
And you have to know I'm not a real programmer by the way, so… well I hope to get some help here. :)

There are two things I want to realize within my own game:
I want to add three different attacking styles to the combat instead of just one.
To do so, I have simply copied and pasted this one three times with different names (combat_lib):

<command name="Act strong">
<pattern>Act strong #text#</pattern>
<script>
cmb_attack (player, text)
</script>
</command>

<command name="Act fast">
<pattern>Act fast #text#</pattern>
<script>
cmb_attack2 (player, text)
</script>
</command>

<command name="Act smart">
<pattern>Act smart #text#</pattern>
<script>
cmb_attack3 (player, text)
</script>
</command>


… and the same with this one, to match it with the ones above:
<function name="cmb_attack" parameters="object, targetname" type="boolean">
returnvalue=false
target= getObject(targetname)

if(target=null){
msg("There is no " + targetname + " here.")
returnvalue=false
} else if (not cmb_isReachable(target)){
msg("There is no " + target.name + " here.")
returnvalue=false
} else if (GetBoolean ( target , "dead" ) ){
msg("Your target ist not alive any more.")
returnvalue=false
} else if(cmb_chkObject(object) and cmb_chkObject(target)){
if (cmb_fight(object, target)) {
if (cmb_getAttrib(target,"cmb_hp")>0) {
msg( target.name + " hits back.")
cmb_fight(target,object)
if (cmb_getAttrib(object,"cmb_hp")>0) {
msg("")
} else {
if (object=player){
msg( "A last strike hits you. You are dying.")
msg( "GAME OVER")
finish
} else {
msg( object.name + " dies.")
SetObjectFlagOn (target, "dead")
target.alias = GetDisplayAlias (target) +" (dead)"
cmb_addexp(target)
if (DictionaryContains(target.cmb_script, "killed")) {
invoke (ScriptDictionaryItem(target.cmb_script, "killed"))
}
}
}
} else {
if (target=player){
msg( "A last strike hits you. You are dying.")
msg( "GAME OVER")
finish
} else {
msg( target.name + " dies.")
SetObjectFlagOn (target, "dead")
target.alias = GetDisplayAlias (target) +" (dead)"
cmb_addexp(target)
if (DictionaryContains(target.cmb_script, "killed")) {
invoke (ScriptDictionaryItem(target.cmb_script, "killed"))
}
}
}
} else {
msg("Why do you want to do this?")
}
returnvalue=true
}
return (returnvalue)
</function>

<function name="cmb_attack2" parameters="object, targetname" type="boolean">
returnvalue=false
target= getObject(targetname)

if(target=null){
msg("There is no " + targetname + " here.")
returnvalue=false
} else if (not cmb_isReachable(target)){
msg("There is no " + target.name + " here.")
returnvalue=false
} else if (GetBoolean ( target , "dead" ) ){
msg("Your target ist not alive any more.")
returnvalue=false
} else if(cmb_chkObject(object) and cmb_chkObject(target)){
if (cmb_fight(object, target)) {
if (cmb_getAttrib(target,"cmb_hp")>0) {
msg( target.name + " hits back.")
cmb_fight(target,object)
if (cmb_getAttrib(object,"cmb_hp")>0) {
msg("")
} else {
if (object=player){
msg( "A last strike hits you. You are dying.")
msg( "GAME OVER")
finish
} else {
msg( object.name + " dies.")
SetObjectFlagOn (target, "dead")
target.alias = GetDisplayAlias (target) +" (dead)"
cmb_addexp(target)
if (DictionaryContains(target.cmb_script, "killed")) {
invoke (ScriptDictionaryItem(target.cmb_script, "killed"))
}
}
}
} else {
if (target=player){
msg( "A last strike hits you. You are dying.")
msg( "GAME OVER")
finish
} else {
msg( target.name + " dies.")
SetObjectFlagOn (target, "dead")
target.alias = GetDisplayAlias (target) +" (dead)"
cmb_addexp(target)
if (DictionaryContains(target.cmb_script, "killed")) {
invoke (ScriptDictionaryItem(target.cmb_script, "killed"))
}
}
}
} else {
msg("Why do you want to do this?")
}
returnvalue=true
}
return (returnvalue)
</function>

<function name="cmb_attack3" parameters="object, targetname" type="boolean">
returnvalue=false
target= getObject(targetname)

if(target=null){
msg("There is no " + targetname + " here.")
returnvalue=false
} else if (not cmb_isReachable(target)){
msg("There is no " + target.name + " here.")
returnvalue=false
} else if (GetBoolean ( target , "dead" ) ){
msg("Your target ist not alive any more.")
returnvalue=false
} else if(cmb_chkObject(object) and cmb_chkObject(target)){
if (cmb_fight(object, target)) {
if (cmb_getAttrib(target,"cmb_hp")>0) {
msg( target.name + " hits back.")
cmb_fight(target,object)
if (cmb_getAttrib(object,"cmb_hp")>0) {
msg("")
} else {
if (object=player){
msg( "A last strike hits you. You are dying.")
msg( "GAME OVER")
finish
} else {
msg( object.name + " dies.")
SetObjectFlagOn (target, "dead")
target.alias = GetDisplayAlias (target) +" (dead)"
cmb_addexp(target)
if (DictionaryContains(target.cmb_script, "killed")) {
invoke (ScriptDictionaryItem(target.cmb_script, "killed"))
}
}
}
} else {
if (target=player){
msg( "A last strike hits you. You are dying.")
msg( "GAME OVER")
finish
} else {
msg( target.name + " dies.")
SetObjectFlagOn (target, "dead")
target.alias = GetDisplayAlias (target) +" (dead)"
cmb_addexp(target)
if (DictionaryContains(target.cmb_script, "killed")) {
invoke (ScriptDictionaryItem(target.cmb_script, "killed"))
}
}
}
} else {
msg("Why do you want to do this?")
}
returnvalue=true
}
return (returnvalue)
</function>


And what I also like about this combat system is the randomness in the damage points.

So here's what I want to do:
My plan is to allocate different strengthes to the three attacking styles. Like "Act strong" would be a simple, but strong attack which deals from 15 to 20 damage points, "Act fast" deals 10-15 damage points to two different targets, and "Act smart" deals 5-10 damage points but it heals you for 5 health.

Unfortunately I can't find the exact location in the library where the damage points, health points etc. are located and defined. Could anyone please help me with that and maybe also explain how to modify the randomness in a way so that I can realize what I mentioned above?
That would be so kind, otherwise I'm stuck. :(

And the second question is:
Can I add the three attacking styles to a menu, which pops up after clicking "Attack"?
It doesn't work when I try to do that. Hard to explain.
At the moment I just have the three attacking styles as displayed verbs, which is listed between "Look at" and "Loot".
But better would be to have a simple "Attack" in the verbs list, which opens a menu in which you'd have to choose your combat strategy.
It's just an optical thing.

But that's not really important right now. The main thing is to get the three attacking styles done and I hope someone can help me out with it. :)

Thanks in advance!

HegemonKhan
you can take a look at my combat system for possibly some ideas and~or how to do some things (this uses Pertex' Combat too, and I was helped by him too, hehe), as I am doing a lot of the things you want in my combat system (ask me about any issues or questions or on help needed that you've got with it):

-------------

From another post of mine:

this is quite a bit more advanced combat system (and it uses a different structure: turn based: stuck in giant combat script blocks), but hopefully at least you might get some ideas and maybe understand a bit of it too (though it is in code, and it's quest version 530, whereas, you're probably using quest version 550, so you probably won't be able to get it to work, unless someone wants to convert its scripts over to the new version's syntax~format):

(and it's old code, along with my annoying abrevs which I've learned since to never do again lol, and I am too lazy to try to find my better code)

<asl version="530">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="Testing Game Stuff">
<gameid>d83ba5bb-2e3c-4f31-80c9-3e88a2dc082c</gameid>
<version>1.0</version>
<pov type="object">player</pov>
<start type="script">
cc
</start>
<turns type="int">0</turns>
<statusattributes type="stringdictionary">turns = </statusattributes>
</game>
<object name="room">
<inherit name="editor_room" />
<object name="player">
<inherit name="defaultplayer" />
<inherit name="pc" />
<cur_hp type="int">999</cur_hp>
<max_hp type="int">999</max_hp>
<str type="int">100</str>
<end type="int">100</end>
<dex type="int">100</dex>
<agi type="int">100</agi>
<spd type="int">100</spd>
<hc type="int">100</hc>
<pd type="int">100</pd>
<pr type="int">100</pr>
</object>
<object name="orc1">
<inherit name="editor_object" />
<inherit name="npc" />
<hostile type="boolean">true</hostile>
<dead type="boolean">false</dead>
<alias>orc</alias>
<cur_hp type="int">999</cur_hp>
<max_hp type="int">999</max_hp>
<str type="int">25</str>
<end type="int">25</end>
<dex type="int">25</dex>
<agi type="int">25</agi>
<spd type="int">25</spd>
<hc type="int">25</hc>
<pd type="int">25</pd>
<pr type="int">25</pr>
</object>
</object>
<turnscript name="game_turns">
<enabled />
<script>
sa
game.turns = game.turns + 1
</script>
</turnscript>
<command name="fight">
<pattern>fight #text#</pattern>
<script>
battle_system (game.pov,text)
</script>
</command>
<type name="char">
<cur_hp type="int">0</cur_hp>
<drop type="boolean">false</drop>
<defending type="boolean">false</defending>
<max_hp type="int">0</max_hp>
<str type="int">0</str>
<end type="int">0</end>
<dex type="int">0</dex>
<agi type="int">0</agi>
<spd type="int">0</spd>
<hp type="int">0</hp>
<hc type="int">0</hc>
<pd type="int">0</pd>
<pr type="int">0</pr>
</type>
<type name="pc">
<inherit name="char" />
<statusattributes type="stringdictionary">hp = ;str = ;end = ;dex = ;agi = ;spd = ;hc = ;pd = ;pr = </statusattributes>
</type>
<type name="npc">
<inherit name="char" />
<dead type="boolean">false</dead>
<hostile type="boolean">false</hostile>
<displayverbs type="list">Look at; Talk; Fight</displayverbs>
</type>
<function name="cc">
msg ("What is your name?")
get input {
game.pov.alias = result
msg (" - " + game.pov.alias)
show menu ("What is your gender?", split ("male;female" , ";"), false) {
game.pov.gender = result
show menu ("What is your race?", split ("human;dwarf;elf" , ";"), false) {
game.pov.race = result
show menu ("What is your class?", split ("warrior;cleric;mage;thief" , ";"), false) {
game.pov.class = result
msg (game.pov.alias + " is a " + game.pov.gender + " " + game.pov.race + " " + game.pov.class + ".")
wait {
ClearScreen
}
}
}
}
}
</function>
<function name="sa">
game.pov.hp = game.pov.cur_hp + " / " + game.pov.max_hp
</function>
<function name="battle_system" parameters="self,text" type="boolean">
first_value = false
enemy = GetObject (text)
if (enemy = null) {
foreach (obj,AllObjects()) {
if (obj.alias=text) {
enemy = obj
}
}
}
if (enemy = null) {
msg ("There is no " + text + " here.")
first_value = false
}
else if (not Doesinherit (enemy,"npc")) {
msg ("You can not battle that!")
first_value = false
}
else if (not npc_reachable (enemy)) {
msg ("There is no " + enemy.alias + " in your vicinity.")
first_value = false
}
else if (GetBoolean (enemy,"dead") = true) {
msg (enemy.alias + " is already dead.")
first_value = false
}
else if (GetBoolean (enemy,"hostile") = false) {
msg (enemy.alias + " is not hostile.")
first_value = false
}
else if (battle_sequence (self,enemy) = true) {
msg ("The battle is over.")
first_value = true
}
return (first_value)
</function>
<function name="battle_sequence" parameters="self,enemy" type="boolean"><![CDATA[
second_value = false
if (enemy.dead = false) {
if (GetInt (self,"spd") > GetInt (enemy,"spd")) {
on ready {
msg ("You get to go first for this round")
if (self_battle_turn (self,enemy) = true) {
battle_sequence (self,enemy)
}
}
on ready {
if (enemy.dead = false) {
if (enemy_battle_turn (self,enemy) = true) {
msg ("The round has ended.")
}
}
}
on ready {
battle_sequence (self,enemy)
}
}
else if (GetInt (self,"spd") < GetInt (enemy,"spd")) {
on ready {
msg (enemy.alias + " gets to go first for this round.")
if (enemy_battle_turn (self,enemy) = true) {
msg ("It is now your turn.")
}
}
on ready {
if (self_battle_turn (self,enemy) = true) {
battle_sequence (self,enemy)
}
else {
msg ("The round has ended.")
}
}
on ready {
battle_sequence (self,enemy)
}
}
else if (GetInt (self,"spd") = GetInt (enemy,"spd")) {
if (RandomChance (50) = true) {
on ready {
msg ("You get to go first for this round")
if (self_battle_turn (self,enemy) = true) {
battle_sequence (self,enemy)
}
}
on ready {
if (enemy_battle_turn (self,enemy) = true) {
msg ("The round has ended.")
}
}
on ready {
battle_sequence (self,enemy)
}
}
else {
on ready {
msg (enemy.alias + " gets to go first for this round.")
if (enemy_battle_turn (self,enemy) = true) {
msg ("It is now your turn.")
}
}
on ready {
if (self_battle_turn (self,enemy) = true) {
battle_sequence (self,enemy)
}
else {
msg ("The round has ended.")
}
}
on ready {
battle_sequence (self,enemy)
}
}
}
}
else {
second_value = true
}
return (second_value)
]]></function>
<function name="self_battle_turn" parameters="self,enemy" type="boolean"><![CDATA[
third_value = false
msg (self.alias + " has " + self.cur_hp + " HP left.")
msg (enemy.alias + " has " + enemy.cur_hp + " HP left.")
wait {
show menu ("What is your battle choice?", split ("Attack;Defend;Cast;Item;Run", ";"), false) {
switch (result) {
case ("Attack") {
fourth_value = false
if (RandomChance (GetInt (enemy,"agi") - GetInt (self,"spd")) = true) {
msg (enemy.alias + "evaded your attack!")
fourth_value = true
}
else if (RandomChance (GetInt (enemy,"Dex") - GetInt (self,"agi")) = true) {
msg (enemy.alias + "parried your attack!")
fourth_value = true
}
else if (RandomChance (GetInt (enemy,"agi") - GetInt (self,"dex")) = true) {
msg (enemy.alias + "blocked your attack!")
fourth_value = true
}
else if (RandomChance (GetInt (self,"dex") - GetInt (enemy,"spd")) = false) {
msg ("Your attack missed " + enemy.alias +"!")
fourth_value = true
}
else if (RandomChance (GetInt (enemy,"pr") - GetInt (self,"hc")) = true) {
msg ("Your attack got resisted by " + enemy.alias +"!")
fourth_value = true
}
else if (fourth_value = false) {
if (self.defending = true and enemy.defending = true) {
enemy.cur_hp = enemy.cur_hp - (crit_hit (self) * 2 * GetInt (self,"pd") / 2 + GetInt (self,"pd") * (GetInt (self,"str") - GetInt (enemy,"end")) / 100)
msg (enemy.alias + " has " + enemy.cur_hp + " HP left.")
self.defending = false
}
else if (self.defending = true and enemy.defending = false) {
enemy.cur_hp = enemy.cur_hp - (crit_hit (self) * 2 * GetInt (self,"pd") + GetInt (self,"pd") * (GetInt (self,"str") - GetInt (enemy,"end")) / 100)
msg (enemy.alias + " has " + enemy.cur_hp + " HP left.")
self.defending = false
}
else if (self.defending = false and enemy.defending = true) {
enemy.cur_hp = enemy.cur_hp - (crit_hit (self) * GetInt (self,"pd") / 2 + GetInt (self,"pd") * (GetInt (self,"str") - GetInt (enemy,"end")) / 100)
msg (enemy.alias + " has " + enemy.cur_hp + " HP left.")
}
else if (self.defending = false and enemy.defending = false) {
enemy.cur_hp = enemy.cur_hp - (crit_hit (self) * GetInt (self,"pd") + GetInt (self,"pd") * (GetInt (self,"str") - GetInt (enemy,"end")) / 100)
msg (enemy.alias + " has " + enemy.cur_hp + " HP left.")
}
}
}
case ("Defend") {
if (self.defending = false) {
self.defending = true
}
}
case ("Cast") {
self.defending = false
}
case ("Item") {
self.defending = false
}
case ("Run") {
self.defending = false
}
}
if (GetInt (enemy,"cur_hp") > 0) {
if (RandomChance (GetInt (self,"spd") - GetInt (enemy,"spd")) = true) {
msg ("You get an extra battle turn!")
self_battle_turn (self,enemy)
}
else {
msg ("Your battle turn is over.")
third_value = false
}
}
else if (GetInt (enemy,"cur_hp") <= 0) {
msg (enemy.alias + " is dead.")
msg ("You have won the battle!")
enemy.defending = false
enemy.dead = true
third_value = true
wait {
ClearScreen
}
}
}
}
return (third_value)
]]></function>
<function name="enemy_battle_turn" parameters="self,enemy" type="boolean"><![CDATA[
fifth_value = false
msg (self.alias + " has " + self.cur_hp + " HP left.")
msg (enemy.alias + " has " + enemy.cur_hp + " HP left.")
result = GetRandomInt (1,3)
switch (result) {
case (1) {
sixth_value = false
if (RandomChance (GetInt (self,"agi") - GetInt (enemy,"spd")) = true) {
msg ("You have evaded the attack!")
sixth_value = true
}
else if (RandomChance (GetInt (self,"dex") - GetInt (enemy,"agi")) = true) {
msg ("You have parried the attack!")
sixth_value = true
}
else if (RandomChance (GetInt (self,"agi") - GetInt (enemy,"dex")) = true) {
msg ("You have blocked the attack!")
sixth_value = true
}
else if (RandomChance (GetInt (enemy,"dex") - GetInt (self,"spd")) = false) {
msg (enemy.alias +"'s attack missed!")
sixth_value = true
}
else if (RandomChance (GetInt (self,"pr") - GetInt (enemy,"hc")) = true) {
msg ("You resisted the attack!")
sixth_value = true
}
else if (sixth_value = false) {
if (enemy.defending = true and self.defending = true) {
self.cur_hp = self.cur_hp - (crit_hit (enemy) * 2 * GetInt (enemy,"pd") / 2 + GetInt (enemy,"pd") * (GetInt (enemy,"str") - GetInt (self,"end")) / 100)
msg (self.alias + " has " + self.cur_hp + " HP left.")
enemy.defending = false
}
else if (enemy.defending = true and self.defending = false) {
self.cur_hp = self.cur_hp - (crit_hit (enemy) * 2 * GetInt (enemy,"pd") + GetInt (enemy,"pd") * (GetInt (enemy,"str") - GetInt (self,"end")) / 100)
msg (self.alias + " has " + self.cur_hp + " HP left.")
enemy.defending = false
}
else if (enemy.defending = false and self.defending = true) {
self.cur_hp = self.cur_hp - (crit_hit (enemy) * GetInt (enemy,"pd") / 2 + GetInt (enemy,"pd") * (GetInt (enemy,"str") - GetInt (self,"end")) / 100)
msg (self.alias + " has " + self.cur_hp + " HP left.")
}
else if (enemy.defending = false and self.defending = false) {
self.cur_hp = self.cur_hp - (crit_hit (enemy) * GetInt (enemy,"pd") + GetInt (enemy,"pd") * (GetInt (enemy,"str") - GetInt (self,"end")) / 100)
msg (self.alias + " has " + self.cur_hp + " HP left.")
}
}
}
case (2) {
if (enemy.defending = false) {
msg (enemy.alias + " has choosen to defend itself.")
enemy.defending = true
}
}
case (3) {
enemy.defending = false
msg ("Cast")
}
}
if (GetInt (self,"cur_hp") > 0) {
if (RandomChance (GetInt (enemy,"spd") - GetInt (self,"spd")) = true) {
msg (enemy.alias + " gets an extra battle turn!")
wait {
enemy_battle_turn (self,enemy)
}
}
else {
msg (enemy.alias + " 's battle turn is over.")
fifth_value = true
}
}
else if (GetInt (self,"cur_hp") <= 0) {
msg (self.alias + " has died.")
msg ("GAME OVER")
finish
}
return (fifth_value)
]]></function>
<function name="npc_reachable" parameters="object" type="boolean">
value = false
foreach (x,ScopeReachableNotHeld ()) {
if (x=object) {
value = true
}
}
return (value)
</function>
<function name="crit_hit" parameters="object" type="int">
if (RandomChance (GetInt (object,"luck")) = true) {
value = 2
}
else {
value = 1
}
return (value)
</function>
</asl>


01. cc = character creation function
02. sa = status attributes (mainly for implementing/displaying of ' cur / max ' stats) function
03. char = character object type ("pcs", "npcs", "monsters", etc., so, not a room, item, equipment, spell, etc)
04. pc = playable character object type ("player" characters / game.povs)
05. npc = non-playable character ("people", "monsters", and etc, so not a "player" character / not a game.pov, I'm going to have a hostility system, so any npc can be friendly or hostile, instead of having an actual "monster/enemy" type set aside)
06. hp = hit points (life) stat attribute
07. mp = mana points (magic) stat attribute
08. str = strength (physical damage, carry weight / equipment requirement, etc) stat attribute
09. end = endurance (physical defense, and etc) stat attribute
10. dex = dexterity (weapon~attack skill, think of this as "if your attack connects or not, do you 'whiff' or not", so not to gete confused with hc, and etc) stat attribute
11. agi = agility (dodging/evading, and etc) stat attribute
12. spd = speed (who goes first in battle, extra battle turns, escaping from battle, and etc) stat attribute
13. hc = hit chance (think of this more as piercing their armor or not, so not to get confused with dex, and etc) stat attribute
14. pd = physical damage stat attribute
15. fp = fire damage stat attribute
16. wp = water damage stat attribute
17. ap = air damage stat attribute
18. ed = earth damage stat attribute
19. ld = light damage stat attribute
20. dd = dark damage stat attribute
21. pr = physical resistance stat attribute
22. fr = fire resistance stat attribute
23. wr = water resistance stat attribute
24. ar = air resistance stat attribute
25. er = earth resistance stat attribute
26. lr = light resistance stat attribute
27. dr = dark resistance stat attribute
28. defending = boolean (reduces damage done for that character and increases the damage done by that character, if they chosoe to attack on the next turn)
29. escaped = boolean, run from battle (not completed/implemented yet)
30. hostile = boolean, any npc can be friendly or a(n) "monster/enemy", based upon a hostility scale (0-100), but not completed
31. dead = boolean
32. crit_hit = critical hit (bonus damage based upon luck)
33. luck = luck stat attribute
34. lvl = level stat attribute
35. exp = experience stat attribute
36. cash = cash stat attribute (currency)
37. lvlup = level up function


----------

Argh, I hate this computer (apple) I'm currently using (I wasn't logged in, so I lost all of my editing of this post)...

I just got all these links for you and lost all that work I editted in... argh...

I'm not excited to do this all over again right now...

but, here's a few of the things that I had up, but lost... argh:

1. http://quest5.net/wiki/Category:All_Fun ... t_Commands (page 1, range: A-S)
2. http://quest5.net/w/index.php?title=Cat ... t#mw-pages (page 2, range: S-Z)
3. http://quest5.net/wiki/Main_Page
4. http://quest5.net/wiki/How_to
5. http://quest5.net/wiki/Tutorial
6. viewforum.php?f=18

look up on the quest wiki site:

GetRandomInt
GetRandomDouble
DiceRoll
RandomChance

show menu
switch
split
using lists
character creation

hope this helps for now.

10tacle
Hi and thanks for your reply!

Yes, I am using Quest 5.5 so I'm afraid it won't work.
But to be honest I don't really need such an advanced combat system.
I don't even need a Level Up and that stuff. :D

It would be enough if someone could explain Pertex' Code to me (maybe Pertex himself?), at least a bit, so that I understand how to modify the random damage points. Because at the moment when you hit your opponent, you cause him a random damage (from 0 up to around 8) and basically I just need to know where I can change the values for that (I can't find anything about it in the code, as I said I'm not even a programmer, but I need a short text adventure for a Uni project, that's why I'm doing this).

And my colleague and I were just wondering how we could remove the Level Up stuff, because we don't really need it.
Any idea where it's located in the code?
And by the way: what's AT and PA (in Pertex' code)? :?

jaynabonne
The simple one (I think):

And by the way: what's AT and PA (in Pertex' code)?



Judging from the names I see, I'm guessing it stands for "attack" and "parade", the latter seeming to be a measure of defense ("parry" perhaps?), at least based on what I see in the code (e.g. an attack roll must exceed the "pa" value to achieve a hit).

10tacle
Ah thanks, good to know!
Okay, I mostly deleted the attributes now, at least the ones which are displayed in the upper right corner under "Status".
Because we just need a very basic combat system with damage and health. Everything else should be removed.

And that brings me to a new question. How get I rid of these ATs and PAs in the game text?

I successfully removed them from the "status" list, but neither shall they be displayed in the game text.
That's one of a few things I'd like to know, so our game can focus only on HP and damage points.

And any ideas on how to modify/tweak the random damage points now? :(
Sorry for bothering you guys, but I'm pretty stuck with it and it's not really the time to learn programming in the next days.

jaynabonne
Remove this line:

msg("at: " + ToString(vattack) + ", pa: "+ToString(vparade))

from the function cmb_fight.

I gave it a cursory look (at work right now!), and it seems that the damage is die-based (1-6, etc). I'd have to look at it in a more idle time to be able to work out how you'd want it changed.

10tacle
jaynabonne wrote:Remove this line:
msg("at: " + ToString(vattack) + ", pa: "+ToString(vparade))

from the function cmb_fight.

Oh that worked, thank you! :)
Now I only have HP and damage displayed on the screen, which is fine.

Regarding the damage thing: thank you so much in advance. You'd really save my day with that.
Just to let you know what I want it to be like:

There are three attacking styles: "Act strong", "Act fast" and "Act smart".
Act strong deals between 15 and 20 damage
Act fast deals between 5-10 damage to two different opponents (unless it's too hard to program, then just leave it away and keep the 5-10 damage to only one opponent)
Act smart deals 10 damage to the opponent and heals you 5

I just took a look at the die-thing by the way and I totally mess up the game with it.
I have absolutely no idea how it works... so thank you.

jaynabonne
See how the attached works. Most of the changes are in the combat lib. (The first thing I did was get rid of the cmb_attackN functions and pass a parameter into the common one.) I also commented out some code in the test game that was causing an error. I also got rid of the msg line mentioned before.

One thing I noticed is that when you get healed for 5, it exceeds the limit for some reason. That could be fixed if it's a problem that needs to be corrected. :)

10tacle
Wow! I just tested it and it works perfectly! =)

The only thing I changed is the msg line in the cmb_fight function.
Because the player gets healed for 5 points but the game doesn't tell you.
So I copied and pasted the msg line into each case and now when you choose "Act smart", it says "player hits target for 10 points and heals himself for 5 points." ;)

What I mentioned before, that "Act fast" should damage two opponents instead of one, is not important anymore.
But would it be possible to increase the player's damage if the player's health is below a certain threshold?
So for example you only have 10 HP left, it triples your healing (from 5 to 15) and doubles your damage or something like that.

Can I just write something like: if (HP<15) {…} ?
I'll try it out a bit. ;)

Edit: Okay I almost have it done, but it seems the engine doesn't like "<".
Because when I write:

if (cmb_getAttrib(object,"cmb_hp")>99) { <--- higher than 99
msg("RAGE MODE")
}

everything's fine, but when I write:

if (cmb_getAttrib(object,"cmb_hp")<99) { <--- smaller than 99
msg("RAGE MODE")
}

It doesn't work because Quest gives me an error right at the beginning which says: Invalid XML.

But how else am I supposed to query the HP?!

But everything else: just perfect. Can't thank you enough! :o

EDIT:

Got it! And it works! =)
I just wrote this:

case ("strong") {
if (cmb_getAttrib(object,"cmb_hp")>99) {
damage=GetRandomInt(15, 20)
msg(object.name + " hits " + target.name + " for " + damage + " points.")
}
else {
damage=(25)
msg(object.name + " heavily hits " + target.name + " for " + damage + " points.")
}


So everything's done! Thanks!

HegemonKhan
^#%^#$%$@^#^ ..... I HATE HATE HATE HATE apple computers...

again, I lost my post on your questions (targeting multiple and specific sets of monsters in a group) and , another attempted post on explaining using the ' < ' and ' > in code writing...

BLOODY APPLE COMPUTERS !!!!!!

------------

you need to use this below to TELL quest that your ' < and ' > ' are being used as greater than and lesser than, and not their normal usage as beginning and ending tags:

normal usage-definition by quest of the symbols ' < ' and ' > ' :

<element name="blah">
</element>

telling quest to use them as their operator (greater than and lesser than) definition~usage:

encase your scripting within:

<![CDATA[ your_scripting ]]>

<function name="blah"><![CDATA[
-> if (player.hp < 15) {
->-> // blah scripts
-> }
]]></function>

<attr name="blah" type="script"><![CDATA[
-> if (player.hp < 15) {
->-> // blah scripts
-> }
]]></attr>

10tacle
Alright, thanks for your explanation.

Uhm, does anyone know how to import that combat stuff into another Quest game now?
I've imported the combat libraries into our game now, but what about the opponents?
Do I have to do everything manually or is there an import function for that?

I mean, the combat opponents have countless attributes and stuff...

Edit:

Okay I just added a new object to a room in our game, named it Crewmember 1 (as in the combat test), added "cmb_fighter" to the inherit types and he applied every attribute which is also in the combat test.
The libraries are imported as well.
But when I start the game and click on the Crewmember and choose for example "Act strong", the game asks me "Why do you want to do this?".

What's missing?!

Edit2:

Okay got it. I forgot to add the same inherit type to the player. ;) Now it works.

Edit3:

We're making good progress, but now we'd like to know how to change the opponents damage.
Does anyone know that? Sorry for bothering you guys. :(
Can't find anything in the code.

HegemonKhan
Note to self:

copy and paste this into notepad before hitting the submit button... getting tired of losing everything I type... GRR!

(I hate this apple computer argh, I don't know if it's safari or the apple computer itself, but it seems to time out from being logged in to this site... and~or whatever its problems~issues are, which wipes out what I written or edited in my posts. I need to get a new PC, ASAP, I can't stand apple computers... V.V

-------------------------------

if you're interested in targetting specific monsters within a group:

put the monsters into an Object List:

game.monster_group = NewObjectList ()
list add (game.monster_group, orc)
list add (game.monster_group, troll)
list add (game.monster_group, ogre)
list add (game.monster_group, goblin)
list add (game.monster_group, gremlin)

now while the: ' ListCount (game.monster_group) ' = 5,
the list index ordering = 0 to 4

0: orc (monster #1/5)
1: troll (monster #2/5)
2: ogre (monster #3/5)
3: goblin (monster #4/5)
4: gremlin (monster #5/5)

---------------

when we're using (acting upon) the entire (all~every~each) list's items, we don't care about their list index numbers:

ALL~EVERY~EACH: foreach // (hence the for*EACH*)

foreach (variable, list) {
-> // blah scripts
}

foreach (monster_x, game.monster_group) {
-> monster_x.hp = monster_x.hp - GetRandomInt (10,15)
}

a good analogy to understanding this:

foreach (team_member, game.team) {
-> game.team.team_member.run_laps
}
// output~returns: all of the team_members will run_laps

-----

but, when we don't want to do ALL, we got: for

the list index number is what 'gets~references~uses' what item in the list, which is done by:

0: orc (monster #1/5)
1: troll (monster #2/5)
2: ogre (monster #3/5)
3: goblin (monster #4/5)
4: gremlin (monster #5/5)

*5: _____ (null)*

for (variable, min_range, max_range, optional: index_count_interval) {
-> // scripts
}

for (variable, 3, 3) = goblin
for (variable, 1, 1) = troll
for (variable, 4, 4) = gremlin
for (variable, 0, 0) = orc
for (variable, 2, 2) = ogre

*for (variable, 5, 5) = ERROR, as there is no 5th index ordering, ie there is no 6th monster*

for (variable, 0, 4) = orc, troll, ogre, goblin, and gremlin
for (variable, 0, 2) = orc, troll, and ogre
for (variable, 3, 4) = goblin and gremlin
for (variable, 2, 3) = ogre and goblin

for (variable, 0, 4, 1) = orc, troll, ogre, goblin, and gremlin
for (variable, 0, 4, 2) = orc, ogre, and gremlin
for (variable, 0, 4, 3) = orc and goblin
for (variable, 0, 4, 4) = orc and gremlin
for (variable, 1, 4, 2) = troll and goblin
for (variable, 1, 4, 1) = troll, ogre, goblin, and gremlin
for (variable, 2, 4, 2) = troll and goblin
etc etc etc

------------------

so for example:

for (monster_x, 0, 2) {
-> game.monster_group.monster_x.hp = game.monster_group.monster_x.hp - GetRandomInt (10,15)
}
for (monster_x, 3, 4) {
-> game.monster_group.monster_x.hp = game.monster_group.monster_x.hp - GetRandomInt (50,100)
}

-----------

or you could do 'diminishing returns' damage:

for (monster_x, 0, 0) {
-> game.monster_group.monster_x.hp = game.monster_group.monster_x.hp - GetRandomInt (50,100)
}
for (monster_x, 1,1) {
-> game.monster_group.monster_x.hp = game.monster_group.monster_x.hp - GetRandomInt (25,50)
}
for (monster_x, 2,2) {
-> game.monster_group.monster_x.hp = game.monster_group.monster_x.hp - GetRandomInt (12,25)
}
for (monster_x, 3,3) {
-> game.monster_group.monster_x.hp = game.monster_group.monster_x.hp - GetRandomInt (6,12)
}
for (monster_x, 4,4) {
-> game.monster_group.monster_x.hp = game.monster_group.monster_x.hp - GetRandomInt (3,6)
}

-------------

ListCount is useful for quest-auto-finding the current list's number of items, which for example is useful for when you want to remove items from the list, which you'll use over and over:

game.my_list = split ("1;2;3;4;5", ";")

msg ("I am thinking of a number between 1 and 5, what is my number?")
result_x = StringListItem (game.my_list, GetRandomInt (0, ListCount (game.my_list) - 1))
if (result_x = 3) {
-> msg ("congrats, you guessed my number!")
-> finish
} else {
-> list remove (game.my_list, result_x)
-> // do the function again (ie 'call function')
}

and we can use this for a huge selection of choices too, hehe:

(a 'quest built password cracker', lol)

game.my_list = split ("1;...;1000000000", ";")

msg ("I am thinking of a number between 1 and 1000000000, what is my number?")
result_x = StringListItem (game.my_list, GetRandomInt (0, ListCount (game.my_list) - 1))
if (result_x = 674548906) {
-> msg ("congrats, you guessed my number!")
-> finish
} else {
-> list remove (game.my_list, result_x)
-> // do the function again (ie 'call function')

10tacle
Yeah I already found the code for the opponent's damage. 8)
Thanks anyway.


OT:
After seeing you complaining about your computer for the fourth or fifth time now... I can guarantee you that there's gotta be something else wrong with your system, because I''ve been a Mac User (although running Windows via Boot Camp right now because of Quest) for many years now and I've never had these problems. It's neither Safari's nor OS X' fault, because both work absolutely satisfying. Safari doesn't delete/refresh your postings on its own.

Do you have any Tune Up- or Antivirus-Tools installed? Because that would explain a lot.
Or did you try to tweak the system somehow and just damaged it?
Which OS X and which Mac are you using?

You should consider a clean install and after that you leave the system as it is. Because OS X can manage itself, since it's a good UNIX system and as long as the user doesn't use any of the above mentioned tools or messes around in the system folders, OS X is fine and stays fine forever. Normally... So i would consider that before buying a new computer...

Just my point of view.

jaynabonne
The problem with trying to cause damage to two enemies at once with the current code is that it only knows about a single enemy at a time. You tell it to engage in combat between the player and another opponent. The rest of the enemies are just "out there" somewhere. It might be possible to look through all existing objects in the game, find which ones are derived from cmb_monster, see which of *those* are in the player's current room, etc, but that seems more work than it's worth. A better (theoretical) solution would be to have a list of combatants instead of a single one (on both side - maybe you'd want to fight with someone against the forces of evil). You'd have to extend the logic a bit to do turn taking, etc. I've done it before in another project, but it was a bit much to attempt for now. :) Since you said it was optional, I didn't address it

10tacle
Alright, good to know and thanks for the explanation.
Yes, it was just optional and anyway, my colleage said he's going to turn the three opponents into only one object, so that the opponents appear as a single object ingame, but the text describtion mentioned it as three opponents. So we're fine with it. :)

But my colleage has a new question. I quote:
I'd like to know if I can program in an room/object that deals damage to me each time i enter/use it, and run a script. Can I edit the players health with a simple variable command within quest?

HegemonKhan
in the GUI~Editor: 'whatever' (room Object) -> 'whatever' (one of the Tabs) -> 'on entering room' -> run as a script -> (create your script)

in code, I think it is something like: 'onenterroom' Attribute, or something like this.

-------

or, there's also:

(put the turnscript or timer inside of a room for it to only activate~execute when you're in that room, otherwise, if you want it to be global, simply place it outside of a room, as an element tag all by itself (have it indented~nested-lined up with the <game></game> tag)

Turnscripts
Timers (these don't work well online... due to internet speed variance issues and etc, ie 'lag' if you're a mp gamer)

<object name="room">
-> <inherit name="editor_room" />
-> <turnscript name="room_turnscript">
->-> <enabled /> // if you want it to be initially activated, otherwise you can script activate it, such as due to an event, in the game
->-> <script>
->->-> // scripts
->-> </script>
-> </turnscript>
</object>

<asl version="540">
-> <game name="blah">
->-> // blah code~attribute lines
-> </game>
-> <turnscript name="global_turnscript">
->-> <enabled />
->-> <script>
->->-> player.hp = player.hp - 5
->->-> msg ("It's the apocalypse age, radiation damage is now a fact of life, endure it, or die.")
->->-> game.turns = game.turns + 1
->-> </script>
-> </turnscript>
</asl>

-----------

think of turnscripts and timers as: 'aways* running functions'

*that is, when you got them activated (enabled) and~or are in the same room as it.

----------

P.S.

@10tacle:

thanks for the help, 10tacle, but I'm using a friend's computer, and nor do I know anything about apple computers (it might also just be the internet connection, possibly a bad router and~or physical interference, too. Or, maybe it's just a security setting, as it doesn't keep~store any logon strings on the computer), so I can't mess with it, as I don't want to mess it up, as it's not mine. I'm without my own computer right now... I need to get a new one. Sorry, for venting my frustration... I so much prefer PCs !!

---------

Object Types (It's hidden under the 'Advanced' in the left pane's 'tree of stuff' in the GUI~Editor) = <inherit name"blah" /> = <type name="blah></type> = 'a group of attributes', some examples:

<type name="character_object_type">
-> <attr name="strength_integer" type="int">0</attr>
-> <attr name="endurance_integer" type="int">0</attr>
-> <attr name="dexterity_integer" type="int">0</attr>
-> <attr name="agility_integer" type="int">0</attr>
-> <attr name="speed_integer" type="int">0</attr>
-> <attr name="intelligence_integer" type="int">0</attr>
-> <attr name="spirituality_integer" type="int">0</attr>
-> <attr name="mentality_integer" type="int">0</attr>
-> <attr name="piety_integer" type="int">0</attr>
-> <attr name="luck_integer" type="int">0</attr>
-> <attr name="level_integer" type="int">0</attr>
-> <attr name="experience_integer" type="int">0</attr>
-> <attr name="cash_integer" type="int">0</attr>
</type>

<type name="fire_monster_nonplayable_character_object_type">
-> <attr name="dead_boolean">false</attr>
-> <attr name="elemental_string">fire</attr>
</type>

<type name="weapon_object_type">
-> <attr name="physical_damage" type="int">0</attr>
-> <attr name="fire_damage" type="int">0</attr>
-> <attr name="water_damage" type="int">0</attr>
-> <attr name="air_damage" type="int">0</attr>
-> <attr name="earth_damage" type="int">0</attr>
</type>

<type name="armor_object_type">
-> <attr name="physical_resistance" type="int">0</attr>
-> <attr name="fire_resistance" type="int">0</attr>
-> <attr name="water_resistance" type="int">0</attr>
-> <attr name="air_resistance" type="int">0</attr>
-> <attr name="earth_resistance" type="int">0</attr>
</type>

<object name="player">
-> <inherit name="object_editor" />
-> <inherit name="object_player" />
-> <inherit name="character_object_type" />
-> <object name="wooden_sword">
->-> <inherit name="editor_object" />
->-> <inherit name="weapon_object_type" />
-> </object>
-> <object name="full_plate_armor">
->-> <inherit name="editor_object" />
->-> <inherit name="armor_object_type" />
-> </object>
</object>

<object name="balrog">
-> <inherit name="editor_object" />
-> <inherit name="fire_monster_nonplayable_character_object_type" />
-> <alias>Killer of Gandalf'</alias>
</object>

-----------------

HOWEVER, Object Types' Attributes can't be changed, so there's some big issues with using Object Types. Now, you can create the exact same attribute within the object, which will over-write the inherited Attribute from the Object Type, and thus allow you to now be able to change that Attribute (ie for~in scripting), though, but then why even create the Object Types and their Attributes in the first place (and there is copy and paste too, for that matter)... laughs. Object Types are good for giving many Objects the same initial values of many Attributes.

jaynabonne
Object types are good for avoiding duplicating code and semantically equivalent data.

This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums