Finding objects based on a flag

Slent
16 Sept 2013, 20:54
Hello all

I have a quick question: Is there a way to find objects with a certain flag, without knowing the object that has that specific flag? I seem to only be able to find flags on objects if I already know what object I'm dealing with.

Any help is highly appreciated :D

Thanks

HegemonKhan
17 Sept 2013, 01:43
"flags" are Boolean Attributes, so in code, look for these code lines:

Boolean Attribute:

name_of_object.name_of_attribute = true_or_false
~or~
name_of_variable_string = true_or_false

orc.dead=false // alive
orc.dead=true // dead
~or~
you_go_first_in_combat=false // enemy goes first in combat
you_go_first_in_combat=true // you go first in combat

Creation (adding an attribute to an object) Line:

<name_of_attribute type="boolean">true_or_false</name_of_attribute>


Scripting (action = using the attribute. In the GUI~Editor: Add a~new script) Line, for example:

if (name_of_object.name_of_attribute=true_or_false) {
// then do: whatever coding~script(s)
}


for example, of a common custom made~used boolean ("flag") attribute:

"dead" // for flagging (setting~changing your flag: orc.dead=false ~ alive ---> orc.dead=true ~ killed) when the enemy is killed.

<object name="orc">
<dead type="boolean">false</dead> // the orc starts out alive obviously
<displayverbs type="simplestringlist">Fight</displayverbs>
<fight type="script"><![CDATA[ // our created~added "fight" verb's scripting~scripts
if (orc.dead=true) { // you can't fight what is already killed, lol
msg ("It is already dead, silly!") // you can't fight what is already killed, lol
} else {
// combat coding
if (orc.hit_points <= 0) {
player.experience = player.experience + orc.experience
player.cash = player.cash + orc.experience
orc.dead=true // the orc is now set "flagged" as "dead", as it's hit_points is zero or below zero.
}
if (player.hit_points <= 0) {
msg ("GAME OVER")
finish
}
}
]]><fight>
</object>

Slent
17 Sept 2013, 07:30
Thank you for the reply!

I am using flags to set stuff like whether you're in combat, whether you have something equipped etc. These flags however, I can set because I know what object I'm dealing with. From your example, "orc.dead=true" we set the dead boolean to true on the orc, but that's because we know the object, orc.

I was interested in a way of finding objects with a flag without knowing the object. For example I would like to find an object in a room with flag "enemy", as this would allow me to send that object to my combat script, based on the flag and not the object, thus having that combat script universal (dunno if universal is the correct term to use, but to avoid having an enemy hardcoded into the script). This might only be a problem, because my take on a solution is wrongly angled :P

Late yesterday I was able to make another script more universal by using a function with parameters and I believe I can do the same with my combat script, or I hope so at least. I will work on that today and see what I end up with. I appreciate your code example above, and the time you put into it, as it gave me another idea as to how to solve my combat system :D

jaynabonne
17 Sept 2013, 08:57
I hope you don't mind (if so tell me), but I'm going to stick with the "code view" form of script. You should be able to map it to the GUI commands as need be - though if you're a coder and are comfortable with code, you might eventually want to just edit the code anyway. :)

You can refer to the player as "player" in your scripts, but the more general form of "game.pov" is preferred, as it leaves the possibility open for using multiple points-of-view in the future (game.pov is just "player" in a normal game).

An object of any kind can have a parent. That is specified by the attribute "parent" (naturally enough). If you are the parent of an object, then you hold it. If a room is the parent of an object (even the player), then the object is in that room.

So the current room is just "game.pov.parent". And there is a handy function called GetDirectChildren that returns all the children of an object - if passed a room, it will be all the objects in that room.

You can "foreach" over a list. You could do that and search for your flag. So, putting it all together, you could have code like:

foreach (object, GetDirectChildren(game.pov.parent)) {
if (HasFlag(object, "someflag")) {
msg("object " + object + " has flag someflag")
}
}

Of course, change "someflag" to what you want.

There are also "Scope" functions that return objects in various scopes: what you can see (ScopeVisible), what you can take (ScopeReachableNotHeld), what you hold (ScopeInventory), etc. You can find them all here:

http://quest5.net/wiki/Scopes

If you just want to look in a particular scope, you can use that scope function instead of GetDirectChildren, which gives you all objects, including scenery and objects that might be invisible.

I would suggest you take a look through the Quest library code that is installed. I have found it indispensable in learning how to do things in Quest (or at least some ways to do them ;) ).

Hope that helps.

Slent
17 Sept 2013, 09:08
That is extremely helpful jaynabonne!

That was exactly what I was looking for. Thanks a bunch! :D

What do you mean by looking through the Quest library code? Do you mean showing the library elements through the filter, and see what functions that reveals? I hadn't thought of that so will certainly do it when I look for ways to do stuff from now on :)

jaynabonne
17 Sept 2013, 10:10
Well, you can do it that way, but actually, I meant go to the install path (like C:\Program Files (x86)\Quest 5\Core) and look through the ASLX files. :) You can peruse them with a text editor and even do searches for functions and things. (I have a free version of Visual Studio, so I just point a "Find in Files" command to that folder and look up functions and things.)

You could probably do both - find the function, type, command, etc in the GUI editor, and then it will tell you which library file the thing is in.

Slent
17 Sept 2013, 10:16
Ah smart, I hadn't even thought of that! Thanks for the help :)

HegemonKhan
18 Sept 2013, 01:54
my apologies Slent! I should have asked whether you had meant "in getting~finding and using a certain flag in a script" or if you had meant "just finding certain flags attributes on your~or~all various objects". As I decided to just go with the non-scripting possible meaning, which wasn't what you were asking about, so oops, my bad!

As Jayna has already explained thoroughly, I'll just mention that there's many ways to "check and get" (find~get and use) an attribute (or an Object too):

here's a good example (has many instances) of using "checking" and "getting" scripting:

<command name="fight_command">
<pattern>fight #text#</pattern>
<script>
fight_function (game.pov,text)
</script>
</command>

<function name="fight_function" parameters="self,text">
enemy=GetObject(text)
if (enemy=null) {
foreach (obj,AllObjects()) {
if (obj.alias=text) {
enemy=obj
} else {
msg ("There seemingly is no " + text + " here.")
}
}
}
if (not enemy=null) {
if (not check_reachable_function (enemy) = true) {
msg ("There seemingly is no " + enemy.alias + " here.")
} else if (not DoesInherit (enemy,"character_object_type")) {
msg (enemy.alias + "is seemingly not something that you can battle.")
} else if (GetBoolean (enemy,"hostile") = false) {
msg (enemy.alias + " is seemingly not something that you can battle.")
} else if (GetBoolean (enemy,"dead") = true) {
msg (enemy.alias + " is already dead.")
} else {
battle_sequence_function (self,enemy)
}
}
</function>

<function name="check_reachable_function" parameters="enemy" type="boolean">
foreach (obj,ScopeReachableNotHeld ()) {
if (obj=enemy) {
value = true
} else {
value = false
}
}
return (value)
</function>


and in a more (in quasi code) general~conceptual look to it:

if (has "this") {
if (has "this") {
if (has "this") {
etc "ifs"
Get or Do "this"
}
}
}
}


here's a real example of the multiple "if has" scripting:

Chase's Wearables (Equipment) Library:

<library>
<!--
Chase's Wearables Library v2.3
Based on: Pixie's Clothing Library (originally)

You may edit this library however you please.

I decided to include a UI, since not having a UI kinda bugged me.

v1.01
-Fixed a typo

v1.02
+Added Event Handlers
+Fixed drop bug

v1.03
+Added configurable wear/remove messages
-Removed redundant events

v1.04
=Fixed an issue with wearing multiple blank items
=Fixed the issue with wearing items without aliases

v2.0
=Rewritten to better support base systems, may have broken older usages
+Added wear layer support

v2.1
=Fixed an issue of an error being thrown when trying to wear something that is not wearable.

v2.2
=Fixed an issue where the custom remove message doesn't play if the item cannot be removed.

v2.3
=Fixed a significant bug where you could not wear something if a non-wearable item was in your inventory.

Chase
chasesan@gmail.com
-->

<dynamictemplate name="WearSuccessful">"You put " + object.article + " on."</dynamictemplate>
<dynamictemplate name="WearUnsuccessful">"You can't wear " + object.article + "."</dynamictemplate>
<dynamictemplate name="AlreadyWearing">"You are already wearing " + object.article + "."</dynamictemplate>
<dynamictemplate name="CannotWearOver">"You cannot wear that over " + object.display + "."</dynamictemplate>
<dynamictemplate name="CannotWearWith">"You cannot wear that while wearing " + object.display + "."</dynamictemplate>

<dynamictemplate name="RemoveSuccessful">"You take " + object.article + " off."</dynamictemplate>
<dynamictemplate name="RemoveUnsuccessful">"You can't remove " + object.article + "."</dynamictemplate>
<dynamictemplate name="RemoveFirst">"You can't remove that while wearing "+object.display+"."</dynamictemplate>

<template name="Wear">Wear</template>
<verbtemplate name="wear">wear</verbtemplate>
<verbtemplate name="wear">put on</verbtemplate>

<template name="Remove">Remove</template>
<verbtemplate name="remove">remove</verbtemplate>
<verbtemplate name="remove">take off</verbtemplate>

<command name="wear" template="wear">
<multiple>
return (ScopeInventory())
</multiple>
<script>
foreach (obj, object) {
DoWear(obj)
}
</script>
</command>

<command name="remove" template="remove">
<multiple>
return (ScopeInventory())
</multiple>
<script>
foreach (obj, object) {
DoRemove(obj)
}
</script>
</command>

<function name="DoWear" parameters="object"><![CDATA[
if(not HasAttribute(object,"worn")) {
msg (DynamicTemplate("WearUnsuccessful", object))
} else if (object.parent = player and object.worn = true) {
msg (DynamicTemplate("AlreadyWearing", object))
} else if (not ListContains(ScopeInventory(), object)) {
msg (DynamicTemplate("WearUnsuccessful", object))
} else {
isLayerProblem = false
conflictedItem = null

if(HasAttribute(object,"wear_slots")) {
foreach(item, ScopeReachableInventory()) {
if(HasAttribute(item,"wear_slots")) {
if(item.worn = true) {
foreach(itemSlot,item.wear_slots) {
if(ListContains(object.wear_slots,itemSlot)) {
if(object.wear_layer < item.wear_layer) {
conflictedItem = item
isLayerProblem = true
} else if(object.wear_layer = item.wear_layer) {
conflictedItem = item
}
}
}
}
}
}
}

if(conflictedItem = null) {
object.worn = True
object.original_drop = object.drop
object.original_alias = object.alias
object.drop = false

object.display = GetDisplayName(object)
object.alias = GetDisplayAlias(object) + " (worn)"

if(object.wearmsg = null) {
msg (DynamicTemplate("WearSuccessful",object))
} else {
msg(object.wearmsg)
}

//do after
if (HasScript(object, "onafterwear")) {
do(object, "onafterwear")
} else if(HasString(object, "onafterwear")) {
msg(object.onafterwear)
}
} else if(isLayerProblem = true) {
msg(DynamicTemplate("CannotWearOver",conflictedItem))
} else {
msg(DynamicTemplate("CannotWearWith",conflictedItem))
}

}
]]></function>

<function name="DoRemove" parameters="object"><![CDATA[
if (not object.parent = player or not object.worn or not object.removeable) {
if(object.removemsg = null) {
msg (DynamicTemplate("RemoveUnsuccessful",object))
} else {
msg (object.removemsg)
}
} else {
conflictedItem = null
//check if we are wearing anything over it
if(HasAttribute(object,"wear_slots")) {
foreach(item, ScopeReachableInventory()) {
if(HasAttribute(item,"wear_slots")) {
if(item.worn = true) {
foreach(itemSlot,item.wear_slots) {
if(ListContains(object.wear_slots,itemSlot)) {
if(object.wear_layer < item.wear_layer) {
conflictedItem = item
}
}
}
}
}
}
}

if(conflictedItem = null) {
if(object.removemsg = null) {
msg (DynamicTemplate("RemoveSuccessful",object))
} else {
msg(object.removemsg)
}

object.worn = false
object.drop = object.original_drop
object.alias = object.original_alias
object.original_drop = null
object.original_alias = null
object.display = null

//do after
if (HasScript(object, "onafterremove")) {
do(object, "onafterremove")
} else if(HasString(object, "onafterremove")) {
msg(object.onafterremove)
}
} else {
msg (DynamicTemplate("RemoveFirst", conflictedItem))
}
}
]]></function>

<type name="wearable">
<worn type="boolean">false</worn>
<removeable type="boolean">true</removeable>
<wear_layer type="int">2</wear_layer>
<inventoryverbs type="listextend">[Wear];[Remove]</inventoryverbs>
</type>
<!-- Interface -->
<tab>
<parent>_ObjectEditor</parent>
<caption>Wearable</caption>
<mustnotinherit>editor_room; defaultplayer</mustnotinherit>

<control>
<controltype>title</controltype>
<caption>Wearable</caption>
</control>

<control>
<controltype>dropdowntypes</controltype>
<caption>Can be worn?</caption>
<types>*=Cannot be worn; wearable=Can be worn</types>
<width>150</width>
</control>

<control>
<mustinherit>wearable</mustinherit>
<controltype>checkbox</controltype>
<attribute>removeable</attribute>
<caption>Removeable?</caption>
</control>

<control>
<mustinherit>wearable</mustinherit>
<controltype>number</controltype>
<caption>Wear Layer</caption>
<attribute>wear_layer</attribute>
</control>

<control>
<mustinherit>wearable</mustinherit>
<caption>Wear Slot</caption>
<controltype>list</controltype>
<attribute>wear_slots</attribute>
<editprompt>Please enter the name for the wear location</editprompt>
</control>

<control>
<mustinherit>wearable</mustinherit>
<controltype>label</controltype>
<caption>If two objects have the same wear location, they will not be able to be worn at a same time. Any number items without wear locations can be worn.</caption>
<advanced/>
</control>

<!-- snip -->

<control>
<mustinherit>wearable</mustinherit>
<controltype>textbox</controltype>
<attribute>wearmsg</attribute>
<caption>Message to print when wearing (leave blank for default)</caption>
<nullable/>
</control>

<control>
<mustinherit>wearable</mustinherit>
<controltype>textbox</controltype>
<attribute>removemsg</attribute>
<caption>Message to print when removing or trying to remove (leave blank for default)</caption>
<nullable/>
</control>

<!-- Event Handlers from here down none/text/scripts -->

<control>
<mustinherit>wearable</mustinherit>
<controltype>title</controltype>
<caption>After Wearing</caption>
</control>

<control>
<mustinherit>wearable</mustinherit>
<selfcaption>After wearing the object</selfcaption>
<controltype>multi</controltype>
<attribute>onafterwear</attribute>
<types>null=None; string=Text; script=Run script</types>
<editors>string=textbox</editors>
<expand/>
</control>

<control>
<mustinherit>wearable</mustinherit>
<controltype>title</controltype>
<caption>After Removing</caption>
</control>

<control>
<mustinherit>wearable</mustinherit>
<selfcaption>After removing the object</selfcaption>
<controltype>multi</controltype>
<attribute>onafterremove</attribute>
<types>null=None; string=Text; script=Run script</types>
<editors>string=textbox</editors>
<expand/>
</control>

</tab>
</library>


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

really useful webpages:

http://quest5.net/wiki/Category:All_Fun ... t_Commands (page 1, range: A-S)

http://quest5.net/w/index.php?title=Cat ... h#mw-pages (page 2, range: S-Z)

Conditionals (needed for the "checking" part):

If (and "Else If" and "Else")
Switch
For
Foreach
Firsttime (and "Otherwise")
While

Also needed for the "checking":

"Has"

so, for example of the "if has" and like-kind of scripts:

if (DoesInherit (orc, "non_playable_character_object_type") { // checking if this is a "character" that you can get in a fight with, as we don't want to let you get in a fight with a mountain... or the air... or a table... a house... a room... etc... lol
if (check_reachable_function (orc) = true) { // checking if you can "reach" the orc (for examples: if the orc is across a river and you can't yet swim nor can you use projectile weapons, then you can't fight the orc, as you're not "next" to it. Or, if the orc is still inside of a locked chest, just pretend with me on this lol, then you can't fight the orc either)
if (HasAttribute (orc, "hit_points") { // checking if the orc has "life" that we can damage and kill, hehe, as we can't fight something that can't be killed... that wouldn't be fair, lol
if (HasBoolean (orc, "dead") = false) { // checking if the orc is dead, we don't want to be fighting something that is already dead, lol
if (GetBoolean (orc, "hostile") { // checking if the orc wants to fight or not, sorry, but if you want to kill any~all npcs, you got to at least make them very mad~angry (low "relationship" integer attribute) at you. We don't want to let you kill something that you have a very cordial~friendly (high) "relationship" integer attribute with the thing~npc, hehe.
// fight scripting
}
}
}
}
}


and most of the scripts:

All: AllObjects, AllExits, etc etc etc
Get: GetObject, GetString, etc etc etc
Has: HasObject, HasBoolean, etc etc etc
Does: DoesInherit (for the "Inherit" attribute, aka the Object Types)
Contains: Contains, ContainsVisible, ContainsAccessible, ContainsReachable
Scopes: ScopeInventory, ScopeReachable, etc etc etc
Lists: StringListItem, ObjectListItem, ListItem
Dictionaries: StringDictionaryItem, ObjectDictionaryItem, ScriptDictionaryItem, DictionaryItem
"Inherit" Attribute (of Object Types): DoesInherit, TypeOf

Slent
18 Sept 2013, 08:08
Ah, no apologies needed! ;)

Those are some helpful code snippets! Yesterday I was thinking about whether my condition-checking for my combat were good, so I was wondering if this is a good order in which to check conditions, before entering combat:

HegemonKhan wrote:
if (DoesInherit (orc, "non_playable_character_object_type") { // checking if this is a "character" that you can get in a fight with, as we don't want to let you get in a fight with a mountain... or the air... or a table... a house... a room... etc... lol
if (check_reachable_function (orc) = true) { // checking if you can "reach" the orc (for examples: if the orc is across a river and you can't yet swim nor can you use projectile weapons, then you can't fight the orc, as you're not "next" to it. Or, if the orc is still inside of a locked chest, just pretend with me on this lol, then you can't fight the orc either)
if (HasAttribute (orc, "hit_points") { // checking if the orc has "life" that we can damage and kill, hehe, as we can't fight something that can't be killed... that wouldn't be fair, lol
if (HasBoolean (orc, "dead") = false) { // checking if the orc is dead, we don't want to be fighting something that is already dead, lol
if (GetBoolean (orc, "hostile") { // checking if the orc wants to fight or not, sorry, but if you want to kill any~all npcs, you got to at least make them very mad~angry (low "relationship" integer attribute) at you. We don't want to let you kill something that you have a very cordial~friendly (high) "relationship" integer attribute with the thing~npc, hehe.
// fight scripting
}
}
}
}
}



My current condition checking is as follows:


if (player is in combat) {
if (enemyObject has flag enemy) {
if (player has weapon equipped) {
attack enemy
give enemy damage
if (enemy health < 1) {
enemy dead
}
} else (player does not have weapon equipped) {
can't attack
}
if (enemy health > 1) {
attack player
if (player has shield equipped) {
if (player blocked) {
no damage taken
} else (player did not block) {
give player damage
}
} else (player does not have shield) {
give player damage
}
}
}
}


Can you guys spot any obvious problems with that order of checking conditions? I have not yet been able to find an error when testing it out, but I might be overlooking something obvious :) Also obvious, I have not implemented stuff like crits, dodge, enemy block and so on.

jaynabonne
18 Sept 2013, 13:02
Here are some thoughts based on a combat system I implemented once. I'm not sure if you've actually coded the pseudo-code you posted, so I don't know if you've already worked through some of these issues. Take them as just my reaction. :)

1) It's clearly a design decision, but not allowing a player to fight who has no weapon is not typical, at least not in games I have seen. Most games I've seen, if you have no weapon, you fight with your bare hands. In a sense, you do have a weapon - your hands. (In fact, that's how I did it - if you had no equipped weapon, internally you had a "bare hands" weapon assigned.)

2) Breaking the damage phase out from the attack feels wrong to me, unless you just always get the same amount of damage for an attack. It seems the damage would have to be tied to the attack, in terms of how the attack is done (e.g. melee weapon, spell, etc), whether it was successful (attack could be blocked, enemy could dodge, inept attacker could miss, attack or spell could be diffused somehow), etc. So, to me, assigning damage is really rolled up into the attack itself, as it's a direct consequence of the attack and can only be determined at the time the attack is done.

3) Your use of "1" for a health limit is a bit odd to me, and might even be a bug in your pseudo-code, unless it has a special meaning. You have enemy health being < 1 as dead and >1 as being able to fight. Do you really mean that if the enemy has health of exactly 1, they are not dead but also cannot fight? (Perhaps they're too injured or...) I think it would be clearer to use 0 as your basis. If the health is <= 0 (if hits can drive it negative), then it's dead. If health >0 then they're alive and kicking.

4) In some combat systems, combat order is not fixed. Combatants have a "speed" attribute which determines which one goes first. If that is the case, then a hard-coded order won't work.

5) The way Quest is designed, you can't block. Since I wanted player input for an attack (e.g. attack, cast spell, use item, flee), that meant it could not be all lumped together like that. It had to be driven from one event to the next, in a taking turns sort of fashion. For example,
- Pick an initial combatant based on speed.
- Have that combatant perform some sort of an attack. If the combatant is an NPC, have it decided how to attack. If it's the player, have the player choose from a menu.
- Once the attack mode is decided, execute the attack. The attack may or may not cause damage, depending on what happens, but damage is assigned during the actual attack.
- Move to the next combatant.

The break in the action for the player comes in where the player is deciding how to attack. So there must be allowance for that to happen, allowing for functions to return so Quest can continue (that is - no blocking for input).

I don't know if that helps, and maybe you already have code working that you like. I just think that you're going to need a different code structure, especially as you start to implement some of those things you haven't put in yet. :)

Slent
18 Sept 2013, 13:33
Thank you for your reactions :) I appreciate it

1) It is a design decision to not being able to attack without a weapon equipped. Whether it is a good decision I'm not yet sure of though. You might be right that it is better to be able to fight with just your bare hands so I'll give this some thought

2) When you say breaking up my damage and attack phase, is that based on the two lines "attack enemy" and "give enemy damage"? If so, they are not meant as two actual events like attacking and dealing damage. That is an error from my side in writing it as such in the above example. I simply meant that I print out the damage I give (because it is a constant number) and then I'm subtracting that number from the enemies health. But the damage and attack doesn't actually happen at different times. If I change the damage to be a random number, I would have to change this though, which I am aware of :)

3) The < 1 and > 1 was because of me not wanting an enemy with 0 life that can fight. As the way I see it, if you hit 0 (or less life) you are dead. Is < 1 not the same, but not as explicit, as 0, -1, -2 etc? The reason I'm not using 0 is because that would mean the enemy could be at 0 as < 0 is -1 and below. Then I would end up with two limits, a < 1 for dead but a > 0 for alive? :P

4) I have indeed thought about an attack speed as that really is a very nice way of making a turn based game less turn based :P But I believe that such a system is a bit too advaced for me right now, but I certainly am interested in implementing such a system at some point! It might not be as advanced as I think, but I'll wait a bit with implementing this.

5) I am not entirely sure what you mean about this. The player can not write "block" in the command and use a turn on that, instead it is a random chance based on the block value the player has. When the enemy attacks after the player has attacked (as the player always starts first in my system, for now :D), it first checks whether the player has a shield equipped. If so, it takes the players block chance and sets that as a random chance. If that random chance is "met", it merely prints out that the player blocked, and the enemy turn is over. If, however, the random chance was not met, the enemy attacks.

I am aware that this system is a bit "square". The player always attacks first, the enemy only attacks if the player attacks, the damage is a constant number etc. I am however working on a turn script in which the enemy will attack even if the player does not attack. But I'm having a small error with that, something I might ask for help with later tonight :P I'm also heavily considering making the damage a damage range, but that is not yet done.

If I may be so bold, what kind of structure would you then recommend? Right now I'm not yet set on which attributes should play a factor in combat (crit, dodge, speed etc.) which is also why I'm not sure what kind of problems I might run into further down the road :P

jaynabonne
18 Sept 2013, 14:00
Ok, so it sounds like you do actually have code working for this. As long as it's doing what you want, then I have no objection. :) I was judging just based on the pseudo-code, and I was anticipating problems that don't seem to be an issue. So... good! lol

As far as the "< 1" - "> 1" thing, you still have it where if the enemy is alive but with health of 1, then it will be alive but no longer fight. If you want it that way, cool. It just looked like an error to me. If you don't mean it that way, you can just make it ">= 1" for the fight condition. (Note that in my example, I didn't have "< 0" for dead - I had "<= 0" which includes 0. Normally, something would be dead when its health = 0. Since you had < 1 to begin with, I thought you might have been including negative health as well, so I included that in mine.)

I don't really have a structure to suggest, as it would be more complex. We could discuss that further if you think you might need to expand your code. I'd have to figure out how to explain it. :) I sort of did already, but not with much code or pseudo-code.

jaynabonne
18 Sept 2013, 14:06
Also, I forgot about the "block" thing. I'm afraid I used a word that had (at least) two meanings. I wasn't referring to blocking in combat; I was referring to code being able to block while it waits for input. If, for example, you wanted the player to be able to choose a type of attack in your pseudo-code where "attack" takes place, you would have to rewrite all the code, as you can't sit and wait (block) for the input to complete. You'd have to exit the function and then have a script kick in when the input happens. That doesn't sound like an issue now, but just keep it in mind.

Slent
18 Sept 2013, 15:50
Yes I have this code actually working. I just wrote it in pseudo form to shorten it, hopefully making it more reader-friendly - although I'm not sure that it did :P As I wrote before I have not yet been able to provoke errors where my current script does not work. As far as I can tell, it is bahaving as it is supposed to, although with the flaws as mentioned above with no crit, no speed etc. My concern is whether this specific order of checking conditions might cause some problems later. But I guess I'll find out if/when that happens :P

Now I can see what you're saying about the > 1 statement. I thought you meant > 0 which would be 1, but you are totally right that my code is bugged if the enemy lands at 1 hp. I have to fix that, thank you! :)

I can see what you mean by not being able to block/halt the code, waiting for player input. I'm not sure how you would build up a system that could do that, except putting it all in either a switch or lots of if, if else statements? Is there another way to do that? It would be nice to, in the future, be able to differentiate between, let's say "stab" and "swing", where each type of attack had a different purpose. Is that what you mean? :)

I certainly would be interested in discussing it further as I'm not sure whether I'm doing it correct or if there is an easier and more robust way of doing things. You easily get caught in a specific way of doing things when coding but it might not be very suited for this kind of development. Not just with this combat script but with everything.

Once again, I really appreciate the time you guys put into helping a new Quester out :)

HegemonKhan
19 Sept 2013, 00:16
ooo goodie good, hehe! You're getting into combat coding! I left out big chunks of my own combat coding as I thought you just wanted the "checking" stuff for whether to fight or not.

a quick note: a major choice to make about combat, is whether you want it "(script block) controlled" (turn based), or more of a "real time" combat feel, where you don't get locked into a script block until combat ends. Pixie's Combat Library is an example of a real time combat feel, whereas, Pertex or mine+Pertex, is a turn based combat design.

(do note, I'm still quite an amature~noob with coding, but I've come far enough to do this, at least)

(Full credit goes to Pertex and his Combat Library as I used its structure as my guide for my combat code)

take a look at what I've done, for hopefully some helpful ideas

and feel free to download or copy-n-paste it, and test~play it out, hehe

here's my combat code:

viewtopic.php?f=10&t=3348&hilit=hk+noob+thread&start=120
(if it doesn't go to the last pages, go to the last pages for my working combat coding, my "veni vidi vici" post, lol)

Also, the code below, is cleaned up, by and thanks to, Pertex, whereas my code in the link to the post~thread above isn't.

(sorry about all the abrevs... I haven't got around to writing them out... yet, so forgive me for the inconvenience of having to use the key~legend I'll provide below for it. I made this code a good while ago, before I realized that it's good to write things out, so not only can others know what is going on or what is what, but also so that I myself know as well, as I found~realize that it is easy to forget what you yourself were doing after not that much length of time, even if you think you'd never forget, lol)

<asl version="540">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="Test">
<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="simplestringdictionary">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="simplestringdictionary">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="simplestringlist">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">
enemy = GetObject (text)
if (enemy = null) {
foreach (obj,AllObjects()) {
if (obj.alias=text) {
enemy = obj
}
}
}
if (enemy = null) {
msg ("There is no " + text + " here.")
}
else if (not Doesinherit (enemy,"npc")) {
msg ("You can not battle that!")
}
else if (not npc_reachable (enemy)) {
msg ("There is no " + enemy.alias + " in your vicinity.")
}
else if (GetBoolean (enemy,"dead") = true) {
msg (enemy.alias + " is already dead.")
}
else if (GetBoolean (enemy,"hostile") = false) {
msg (enemy.alias + " is not hostile.")
}
else {
battle_sequence (self,enemy)
}

</function>
<function name="battle_sequence" parameters="self,enemy"><![CDATA[
if (enemy.dead = false) {
playerfirst=false
if (GetInt (self,"spd") > GetInt (enemy,"spd")) {
playerfirst=true
} else if (GetInt (self,"spd") = GetInt (enemy,"spd") and RandomChance (50)) {
playerfirst=true
}

if (playerfirst) {
msg ("You get to go first for this round")
self_battle_turn (self,enemy)
on ready {
if (not enemy.dead){
enemy_battle_turn (self,enemy)
}
}
} else {
msg (enemy.alias + " gets to go first for this round.")
enemy_battle_turn (self,enemy)
msg ("It is now your turn.")
self_battle_turn (self,enemy)
}
on ready {
msg ("The round has ended.")
msg("")
battle_sequence (self,enemy)
}
} else {
msg ("The battle is over.")
}
]]></function>
<function name="self_battle_turn" parameters="self,enemy"><![CDATA[
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.")
}
}
else if (GetInt (enemy,"cur_hp") <= 0) {
msg (enemy.alias + " is dead.")
msg ("You have won the battle!")
enemy.defending = false
enemy.dead = true
}
}
}
]]></function>
<function name="enemy_battle_turn" parameters="self,enemy"><![CDATA[
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.")
}
}
else if (GetInt (self,"cur_hp") <= 0) {
msg (self.alias + " has died.")
msg ("GAME OVER")
finish
}
]]></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>


and the legend~key for it:

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

HegemonKhan
19 Sept 2013, 00:18
and here's this too (I've written stuff out in this, so it's easier to follow), it's a more recent (hopefully better) work of mine:

(this may not be functional though ~ it may not work ~ might have errors too, as I haven't got around to testing it out yet)

(it was~is just a "brainstorm coding" work of mine, trying to figure out how to do a stat selection when you choose to do your level up menu~scripting thing, and maybe there might be some lines of trying to work on adding in equipment and~or magic too script stuff, I'm still working on learning how to do equipment+magic coding... laughs)

<library>

<!-- New Game -->

<asl version="540">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="Colloseum">
<gameid>bbc85c01-6e80-4a71-8abf-c1e870fb5b42</gameid>
<version>1.0</version>
<firstpublished>2013</firstpublished>
</game>
<object name="room">
<inherit name="editor_room" />
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
</object>
</asl>

<!-- Object Types -->

<type name="character_object_type">

<strength type="int">0</strength>
<endurance type="int">0</endurance>
<dexterity type="int">0</dexterity>
<agility type="int">0</agility>
<speed type="int">0</speed>
<intelligence type="int">0</intelligence>
<spirituality type="int">0</spirituality>
<mentality type="int">0</mentality>
<piety type="int">0</piety>
<luck type="int">0</luck>

<dead type="boolean">false</dead>

<undead type="boolean">false</undead>

<defending type="boolean">false</defending>
<casting type="boolean">false</casting>

<experience_points type="int">0</experience_points>
<cash type="int">0</cash>
<level type="int">0</level>
<level_up_points type="int">0</level_up_points>
<attribute_points type="int">0</attribute_points>

<health_points type="string">0/0</health_points>
<mana_points type="string">0/0</mana_points>

<current_health_points type="int">0</current_health_points>
<maximum_health_points type="int">0</maximum_health_points>
<current_mana_points type="int">0</current_mana_points>
<maximum_mana_points type="int">0</maximum_mana_points>

</type>

<!-- Turnscripts -->

<turnscript name="global_events_turnscript">
status_attributes_function
level_up_function
game.turns = game.turns + 1
</turnscript>

<!-- Commands -->

<command name="fight_command">
<pattern>fight #text#</pattern>
<script>
fight_function (game.pov,text)
</script>
</command>

<command name="level_up_system_command">
<pattern>lvlup</pattern>
<script>
level_up_system_function
</script>
</command>

<!-- Functions -->

<function name="fight_function" parameters="self,text">
enemy=GetObject(text)
if (enemy=null) {
foreach (obj,AllObjects()) {
if (obj.alias=text) {
enemy=obj
} else {
msg ("There seemingly is no " + text + " here.")
}
}
} else if (not check_reachable_function (enemy) = true) {
msg ("There seemingly is no " + enemy.alias + " here.")
} else if (not DoesInherit (enemy,"character_object_type")) {
msg (enemy.alias + "is seemingly not something that you can battle.")
} else if (GetBoolean (enemy,"hostile") = false) {
msg (enemy.alias + " is seemingly not something that you can battle.")
} else if (GetBoolean (enemy,"dead") = true) {
msg (enemy.alias + " is already dead.")
} else {
battle_sequence_function (self,enemy)
}
</function>

<function name="battle_sequence_function" parameters="self,enemy"><![CDATA[
if (enemy.dead=false or self.escaped=false) {
you_go_first=false
if (GetInt (self,"speed") > GetInt (enemy,"speed") {
you_go_first=true
} else if (GetInt (self,"speed") = GetInt (enemy,"speed") and RandomChance (50)=true) {
you_go_first=true
}
if (you_go_first=true) {
msg ("You get to go first for this round")
self_battle_turn_function (self,enemy)
on ready {
if (not enemy.dead=true or not self.escaped=true){
enemy_battle_turn_function (self,enemy)
}
}
} else {
msg (enemy.alias + " gets to go first for this round.")
enemy_battle_turn_function (self,enemy)
on ready {
if (not enemy.dead=true or not self.escaped=true){
msg ("It is now your turn.")
self_battle_turn_function (self,enemy)
}
}
}
on ready {
msg ("The round has ended.")
battle_sequence_function (self,enemy)
}
} else {
msg ("The battle is over.")
}
]]></function>

<function name="self_battle_turn_function" parameters="self,enemy"><![CDATA[
msg (self.alias + " has " + self.current_health_points + " HP left.")
msg (enemy.alias + " has " + enemy.current_health_points + " HP left.")
wait {
show menu ("What is your battle choice?", split ("Attack;Defend;Cast;Item;Run", ";"), false) {
switch (result) {
case ("Attack") {
self_attack_failed = false
if (RandomChance (GetInt (enemy,"agility") - GetInt (self,"speed")) = true) {
msg (enemy.alias + "evaded your attack!")
self_attack_failed = true
self.defending = false
} else if (RandomChance (GetInt (enemy,"dexterity") - GetInt (self,"agility")) = true) {
msg (enemy.alias + "parried your attack!")
self_attack_failed = true
self.defending = false
} else if (RandomChance (GetInt (enemy,"agility") - GetInt (self,"dexterity")) = true) {
msg (enemy.alias + "blocked your attack!")
self_attack_failed = true
self.defending = false
} else if (RandomChance (GetInt (self,"dexterity") - GetInt (enemy,"speed")) = false) {
msg ("Your attack missed " + enemy.alias +"!")
self_attack_failed = true
self.defending = false
} else if (RandomChance (GetInt (enemy,"armor_class") - GetInt (self,"attack_rating")) = true) {
msg ("Your attack failed to penetrate " + enemy.alias +"!")
self_attack_failed = true
self.defending = false
} else if (self_attack_failed = false) {
if (self.defending = true and enemy.defending = true) {
enemy.current_health_points = enemy.current_health_points - (critical_hit_function (self) * 2 * GetInt (self,"physical_damage") / 2 + GetInt (self,"physical_damage") * (GetInt (self,"strength") - GetInt (enemy,"endurance")) / 100)
msg (enemy.alias + " has " + enemy.current_health_points + " HP left.")
self.defending = false
} else if (self.defending = true and enemy.defending = false) {
enemy.current_health_points = enemy.current_health_points - (critical_hit_function (self) * 2 * GetInt (self,"physical_damage") + GetInt (self,"physical_damage") * (GetInt (self,"strength") - GetInt (enemy,"endurance")) / 100)
msg (enemy.alias + " has " + enemy.current_health_points + " HP left.")
self.defending = false
} else if (self.defending = false and enemy.defending = true) {
enemy.current_health_points = enemy.current_health_points - (critical_hit_function (self) * GetInt (self,"physical_damage") / 2 + GetInt (self,"physical_damage") * (GetInt (self,"strength") - GetInt (enemy,"endurance")) / 100)
msg (enemy.alias + " has " + enemy.current_health_points + " HP left.")
} else if (self.defending = false and enemy.defending = false) {
enemy.current_health_points = enemy.current_health_points - (critical_hit_function (self) * GetInt (self,"physical_damage") + GetInt (self,"physical_damage") * (GetInt (self,"strength") - GetInt (enemy,"endurance")) / 100)
msg (enemy.alias + " has " + enemy.current_health_points + " HP left.")
}
}
}
case ("Defend") {
msg ("You defend yourself against " + enemy.alias)
self.defending = true
}
case ("Cast") {
self.defending = false
}
case ("Item") {
self.defending = false
}
case ("Run") {
self.defending = false
self.escaping = true
}
}
if (GetInt (enemy,"current_health_points") > 0) {
if ( RandomChance (GetInt (self,"speed") - GetInt (enemy,"speed"))= true) {
msg ("You get an extra battle turn!")
self_battle_turn (self,enemy)
} else {
msg ("Your battle turn is over.")
}
} else if (GetInt (enemy,"current_health_points") <= 0) {
msg (enemy.alias + " is dead.")
msg ("You have won the battle!")
self.defending = false
self.escaping = false
enemy.defending = false
enemy.dead = true
}
}
}
]]></function>

<function name="enemy_battle_turn_function" parameters="self,enemy"><![CDATA[
msg (self.alias + " has " + self.current_health_points + " HP left.")
msg (enemy.alias + " has " + enemy.current_health_points + " HP left.")
result = GetRandomInt (1,3)
switch (result) {
case (1) {
enemy_attack_failed = false
if (RandomChance (GetInt (self,"agility") - GetInt (enemy,"speed")) = true) {
msg ("You have evaded the attack!")
enemy_attack_failed = true
enemy.defending = false
} else if (RandomChance (GetInt (self,"dexterity") - GetInt (enemy,"agility")) = true) {
msg ("You have parried the attack!")
enemy_attack_failed = true
enemy.defending = false
} else if (RandomChance (GetInt (self,"agility") - GetInt (enemy,"dexterity")) = true) {
msg ("You have blocked the attack!")
enemy_attack_failed = true
enemy.defending = false
} else if (RandomChance (GetInt (enemy,"dexterity") - GetInt (self,"speed")) = false) {
msg (enemy.alias +"'s attack missed!")
enemy_attack_failed = true
enemy.defending = false
} else if (RandomChance (GetInt (self,"armor_class") - GetInt (enemy,"attack_rating")) = true) {
msg ("You weren't penetrated by the attack!")
enemy_attack_failed = true
enemy.defending = false
} else if (enemy_attack_failed = false) {
if (enemy.defending = true and self.defending = true) {
self.current_health_points = self.current_health_points - (critical_hit_function (enemy) * 2 * GetInt (enemy,"physical_damage") / 2 + GetInt (enemy,"physical_damage") * (GetInt (enemy,"strength") - GetInt (self,"endurance")) / 100)
msg (self.alias + " has " + self.cur_hp + " HP left.")
enemy.defending = false
} else if (enemy.defending = true and self.defending = false) {
self.current_health_points = self.current_health_points - (critical_hit_function (enemy) * 2 * GetInt (enemy,"physical_damage") + GetInt (enemy,"physical_damage") * (GetInt (enemy,"strength") - GetInt (self,"endurance")) / 100)
msg (self.alias + " has " + self.current_health_points + " HP left.")
enemy.defending = false
} else if (enemy.defending = false and self.defending = true) {
self.current_health_points = self.current_health_points - (critical_hit_function (enemy) * GetInt (enemy,"physical_damage") / 2 + GetInt (enemy,"physical_damage") * (GetInt (enemy,"strength") - GetInt (self,"endurance")) / 100)
msg (self.alias + " has " + self.current_health_points + " HP left.")
} else if (enemy.defending = false and self.defending = false) {
self.current_health_points = self.current_health_points - (critical_hit_function (enemy) * GetInt (enemy,"physical_damage") + GetInt (enemy,"physical_damage") * (GetInt (enemy,"strength") - GetInt (self,"endurance")) / 100)
msg (self.alias + " has " + self.current_health_points + " HP left.")
}
}
}
case (2) {
msg (enemy.alias + " has choosen to defend itself.")
enemy.defending = true
}
case (3) {
enemy.defending = false
msg ("Cast")
}
}
if (GetInt (self,"current_health_points") > 0) {
if (RandomChance (GetInt (enemy,"speed") - GetInt (self,"speed")) = true) {
msg (enemy.alias + " gets an extra battle turn!")
wait {
enemy_battle_turn (self,enemy)
}
} else {
msg (enemy.alias + " 's battle turn is over.")
}
} else if (GetInt (self,"current_health_points") <= 0) {
msg (self.alias + " has died.")
msg ("GAME OVER")
finish
}
]]></function>

<function name="check_reachable_function" parameters="enemy" type="boolean">
foreach (obj,ScopeReachableNotHeld ()) {
if (obj=enemy) {
value = true
} else {
value = false
}
}
return (value)
</function>

<function name="critical_hit_function" parameters="target" type="int">
if (RandomChance (GetInt (target,"luck")) = true) {
value = 2
} else {
value = 1
}
return (value)
</function>

<function name="level_up_function"><![CDATA[
if (game.pov.experience_points >= game.pov.level * 100 + 100) {
game.pov.experience_points = game.pov.experience_points - (game.pov.level * 100 + 100)
game.pov.attribute_points = game.pov.attribute_points + 5
game.pov.level_up_points = game.pov.level_up_points + 1
game.pov.level = game.pov.level + 1
level_up_function
}
]]></function>

<function name="level_up_system_function"><![CDATA[
if (game.pov.level_up_points > 0) {
if (game.pov.attribute_points > 0) {
show menu ("What attribute would you like to raise?",split("strength;endurance;dexterity;agility;speed;intelligence;spirituality;mentality;piety;luck",";"),false) {
switch (result) {
case ("strength") {
msg ("How many points?")
get input {
game.pov.points=result
}
}
}
}
]]></function>

<function name="status_attributes_function">
game.pov.health_points = game.pov.current_health_points + "/" + game.pov.maximum_health_points
game.pov.mana_points = game.pov.current_mana_points + "/" + game.pov.maximum_mana_points
</function>

<function name="shop_function">
</function>

</library>


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

p.s.

[HK Edit: ignore this part, as I wrote this post before reading the latter posts of yours, Jayna. I too thought you meant a "combat block" effect, so my apologies. Some day, I'll be thinking at your high level of coding, lol. HK still thinks at a low level of code, and so that was: block = "combat blocking effect", lol]

You can quasi "block" (and parry, dodge~evade, and etc)... there's a few ways (simple to more complex) to code in this effect... :P

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

P.S.S.

in regards to #3, I think Jayna was talking about, what happens when~(if) the enemy has exactly 1 life, as you're using greater than and lesser than, you'll have a problem as the quest engine won't know what to do at 1 life, is the enemy dead or is it still alive? You simply need to change one of your operators to being: "and equal to"

if (orc.hit_points < 1) {
orc.dead=true
msg ("the orc is now dead")
} else if (orc.hit_points >= 1) {
msg ("the orc is still alive")
}

~OR~

if (orc.hit_points <= 0) {
orc.dead=true
msg ("the orc is now dead")
} else if (orc.hit_points > 0) {
msg ("the orc is still alive")
}

but not what you have:

if (orc.hit_points < 1) {
orc.dead=true
msg ("the orc is now dead")
} else if (orc.hit_points > 1) {
msg ("the orc is still alive")
} else if (orc.hit_points = 1) {
// quest engine: ...???...???....???....
// quest engine: ERROR!
}


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

Quest's Operators:

name: format~syntax

// sorry, I forgot the correct terminology... argh! Jayna can explain this easily though of what I'm trying to say, lol.
1. equals a value (computational equals): =
2. equals ("the same as this" ~ string comparison equals ~ algebraic substitution): =
// quest internally knows when to do "=" vs "==", Alex did this for noobs, who may not understand~realize the difference, and so, they can safely just type in "=", and quest will figure out whether it's suppose to do the function for "=" or for "==".

3. greater than: >
4. lesser than: <
5. greater than and equal to: >=
6. lesser than and equal to: <=

~ I'm not sure if you can put the equals sign first too (I haven't tested~tried it), or if not:
5. =>
6. =<

NOTE: since the "tags" (not sure if this is the correct terminology) are: < object name="blah" >, to tell quest that you want the ">" and "<" to be understood as the symbols for "greater than" and "lesser than", then you got to add this in to your script:

<fight name="script"><![CDATA[
if (orc.hit_points <= 0) {
// blah coding
}
]]></fight>

<function name"blah"><![CDATA[
if (orc.hit_points <= 0) {
// blah coding
}
]]></function>

etc...

<![CDATA[ greater than and~or lesser than scripting ]]>


as otherwise you get an error, as it'll think the:

<= 0 ) {

is a tag, and it's like: where's the ending tag? thus the ERROR.

missing: ></blah>
and: incorrect ID "tag" format~syntax too

as the correct syntax~format is (a single example only):

<object name="orc"></object>

and not:

<= 0 ) {

lol

Slent
19 Sept 2013, 06:55
Well my question was meant for the order of condition checking (the if, if else etc), which is also why I did it in pseudo form.

Even though I'm a big fan of a more real time based combat system that feels fluent and not so turn based, I think I'll wait a bit with implementing that. I've already learned a lot about Quest by doing my current combat system and to make sure I progress with the rest of the game, I'll let it stay in its current locked, turn based form.

I'll add a lot of other stuff to the game and also the combat script and at some point when I feel more comfortable with the game I'll probably rewrite the combat code to a more fluent system. I already have some ideas for it based on your guys code, so that is awesome. And I can certainly use the code you've pasted for the system!

I'm very impressed by all the attributes you have in the script, like endurance, dexterity, agility etc. Very detailed and with a lot of possibilities. I like that! I might steal from it at some point :D

A detail I spotted in your script is the chance to get an extra turn. That one would be somewhat simple to implement yet give the system a more fluent feel!

And you are right about the #3 point I had with the life being 1. I have fixed that, thanks! :)

The last code you posted about how to implement the <= is very helpful. I tried to implement the <= and >= at some point but got the error you are talking about. Good to know how to implement it without getting that error! Thanks.

Again, thanks for all the useful code. I'll get a lot out of just reading through it! Appreciated.

Slent
22 Sept 2013, 08:10
I got another, more general questions, regarding flags.

I was just sitting working on some code when I realized I was switching between using flags and boolean attributes. For instance, when the player enters combat I set a flag but when I'm checking whether an enemy is dead I check a boolean attribute on that enemy object.

I know that a flag is a quick way to assess a true/false state, but when would it be appropriate to use a boolean attribute on an object instead of just setting/unsetting a flag? It might be wrong that I'm "only" setting a flag when player enters combat, so I might wanna rework that, dunno?

jaynabonne
22 Sept 2013, 09:53
A "flag" in Quest is just a Boolean attribute. There is no flag attribute as such. If you select "Set flag" in the editor, it turns into SetObjectFlagOn, and "Unset flag" turns into SetObjectFlagOff. Those functions look like this:

  <function name="SetObjectFlagOn" parameters="object, flag">
set (object, flag, true)
</function>

<function name="SetObjectFlagOff" parameters="object, flag">
set (object, flag, false)
</function>


"true" and "false" are just Boolean values. Similarly, and "if" with "object has flag" turns into "GetBoolean". Basically, flags are just Boolean attributes.

I suspect it was deemed more scary and less obvious to use "Set Boolean" and "object has Boolean" for less coding-skilled game developers, so the more neutral word "flag" was used up in the editor instead - mostly. Unfortunately, it creates this conceptual dissonance since they sound like two different things. :)

Slent
22 Sept 2013, 10:14
Hmm I might have formulated my question bad :P I am aware that flags are boolean attributes, but you can also set a boolean attribute on your object directly (in the example I posted above enemy.dead = false/true).

My question is more meant as a "do you use flags in some situations and if so, in which, or do you only use boolean attributes"? I know a flag is also a boolean attribute, but when I say attribute, i mean one you create on the object and set to a boolean type :P

More simply put; when do you simply use flags and when do you use the boolean type on an attribute? Or do you only ever use one or the other? :P

jaynabonne
22 Sept 2013, 10:31
I personally edit code in Code View (or via a text editor), and it makes more sense to me to simply put "object.flag = true" rather than "SetObjectFlagOn(object, "flag")), which just turns into the same thing. :)

If I want a pre-defined attribute (which can simplify checks), then I will create a Boolean attribute. (You'd have to even if you wanted a flag, if you wanted the flag to be pre-existing.)

HegemonKhan
22 Sept 2013, 13:04
I'm still not quite clear in what you're trying to ask about, as I and maybe Jayna are confused, due to that "flags" are booleans (boolean attributes).

I believe that in the GUI~Editor, there's two types of scripts, one to create (add) the "flag" (boolean attribute), and another (well two of them) to toggle the "flag" (boolean attribute) between "on" ("=true") and "off" ("=false"), if my memory serves (I'm too lazy to start up quest).

-----

Creating the Flag~Boolean:

In-Code:

<object name="blah">
-> <inherit name="editor_object" />
-> <name_of_boolean type="boolean">true_or_false</name_of_boolean>
</object>

~is the SAME as~

GUI~Editor:

whatever the script is called... meh

---------

Toggling the Flag~Boolean:

In-Code: Object.Boolean=true <---> SetObjectFlagOn :GUI~Editor
In-Code: Object.Boolean=false <---> SetObjectFlagOff :GUI~Editor

----------

are you any change refering to, for example:

variable_string=true_or_false
handled=false // or true
you_go_first=false // or true
result_x=false // or true
value_x=false // or true

~vs~

Object.Boolean=true_or_false
orc.dead=false // or true
etc examples

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

for me, I got my own question in terms of what is a better code design structure:

booleans vs (strings vs stringlists)

booleans are quicker~easier to toggle, but you got to make the booleans for everything ~ lots of booleans!

string~stringlists reduce the amount of code lines for them compared to the amount of code lines needed for booleans, but they take more code lines to toggle them.

for example:

object.walking=true vs object.current_locomotion=walking vs object.current_locomotion_string_list // walking
object.running=false
object.flying=false

object.running=true vs object.current_locomotion=running vs object.current_locomotion_string_list // running
object.walking=false
object.flying=false

object.flying=true vs object.current_locomotion=flying vs object.current_locomotion_string_list // flying
object.running=false
object.walking=false

etc... etc... etc...

(or other examples: such as like with traditional rpg status effects: poisoned, confused, muted~silenced, paralyzed, stunned, sleeping, blinded, cursed, petrified, and etc)

And, are there certain scenerios~situations where for some things it is better to use booleans, other certain scenerios~situations where for some things it is better to use strings, and still other certain scenerios~situations where for some things it is better to use stringlists ???

Slent
22 Sept 2013, 15:00
Haha yeh I do know it is hard as I'm having a hard time explaining it. It makes it even harder when I don't know the system that well yet. And writing it doesn't really help on it either :D So sorry about that! I'll try again:

When you want something to be either true or false you use a boolean. I do know what a boolean is; that is not my concern nor is it how to use it.

In Quest, you can set a boolean by either setting a flag on an object OR you can set an attribute with the type boolean on the object and then change it when you need to. As far as I know, the attribute with the type boolean has to be set at the start of the game and can then be toggled between true and false as the game progresses. The flag, however, you do not need to have predefined on your object.

So my question is:

When would you just set a flag and when would you use an attribute with the type boolean on your object? I know you can use them to achieve the same goal (checking whether something is true or false), which is why I wonder if there is any situation in which you would rather use the one over the other?

Indeed Khan, I have the same questions when working with Quest - in what situations are what ways of doing something appropriate. This is actually a bit in that category :)

jaynabonne
22 Sept 2013, 16:15
Ok, so let me rephrase your question:

When would you just set a Boolean in script and when would you pre-define an attribute with the type boolean on your object?



Basically, why pre-define a Boolean attribute or not? There are a couple of ways to use a Boolean on an object, and the answer changes depending on what you're doing.

1) Check for the *existence* of a Boolean attribute. I've seen this used in some code that HK posted, and I thought it was an error at first, but then I realized it was an alternate way of using attributes. In this case, you would start out with no attribute defined, and then your code would use HasBoolean to see if the attribute exists. This is a bit odd to me to go this route, and you can use GetBoolean just as easily, since that function will return false if the attribute does not exist or is not Boolean. The trick with going this way is that in order to "unset" the Boolean, you need to assign it to null to remove it from the object, since it's an existence check. That makes it even more bizarre to me, but I have seen this route taken, especially for Boolean values that don't change.

2) Check for the *value* of a Boolean attribute. This is the more standard way of doing things, and the GetBoolean method makes it simple, since it returns false if the attribute doesn't exist. If you always use GetBoolean, then it doesn't matter whether you pre-define the attribute or not. A missing attribute comes back false. You only get true if you set it to true.

Why would you want to predefine the Boolean? It allows you to not use GetBoolean but use the attribute directly - object.flag instead of GetBoolean(object, "flag") since the attribute always exists. I don't know if there is any advantage to this speed-wise, but it might seem cleaner to some (I have gone that way myself). If you get in the habit of always using GetBoolean, then it doesn't matter whether you predefine your Boolean attributes or not.

I hope I at least touched on what you were asking. :)

jaynabonne
22 Sept 2013, 16:22
Another thought:

If I have a single object that has Boolean attributes, I will typically just define them in the object. They are part of the particular signature of that object.

If I have a *class* of objects, some of which have the Boolean attribute and some of which don't, then I will often not bother putting it in the base type, to keep from proliferating the attribute to all the objects created from that type. It seems more compact to do it that way, and GetBoolean makes it simple, since it will return false when the attribute doesn't exist.

In the end, it comes down to your own design thoughts, how you want to do code based on the principles that make sense to you!

HegemonKhan
22 Sept 2013, 16:33
Sorry for the confusion jayna with my posts using HasBoolean, as I just use it as I figure it makes more sense for noobs, then the GetBoolean's "auto check" if the attribute exists and if set to true, as noobs probably don't know about this aspect of it.

if (HasAttribute (object, "attribute") = false_or_true) { script }

I feel this a very clear script for new people to understand, and allows you to also set it to act on false ~ more customization.

jaynabonne
22 Sept 2013, 17:33
You can definitely use HasXXXX for existence checks. But I think it would be more confusing to try to explain to a newbie that you can use SetObjectFlagOn with HasBoolean but you then can't use SetObjectFlagOff - you have to set the attribute to null to make it go away, which is completely non-parallel and doesn't fit in with the GUI editor's command set.

As I said, if you're using it as an existence check for something you define *in your game file*, such that they are static flags on an object (not changing), then you can get away with it. If you want to turn flags on and off, it works much better to simply use GetBoolean (which corresponds to the GUI editor's "object has flag" script command). That then allows you to set the flag to true and false (and not something more mind-bending like true and null).

And just so we're clear:

For HasBoolean, it will return true if there is a Boolean attribute with value of either true or false, and it will return false if there is no Boolean attribute.

For GetBoolea, it will return true if there is a Boolean attribute with value true. Else it will return false.

The fact that HasBoolean will return true if an object has a Boolean with value false is the part that needs to be remembered.

Slent
22 Sept 2013, 17:55
Okay that makes it clearer. I did suspect that it was just a matter of design choice but I wasn't sure whether there was any difference with the two. I think I'll go through my code and change some of the instances where I use flag as I feel a predefined attribute would be more appropriate.

I can see what you say HK, with the check with HasBoolean. I find it rather neat actually but whether I'll ever need such a check instead of following jaynas way I'm not sure. But thanks for your input, greatly appreciated.

HegemonKhan
22 Sept 2013, 19:04
oops, I seem to have gotten my "facts" wrong, lol. Thanks for the correction and explanation, Jayna. Hopefully, I'll remember these actual facts now... HK crosses his fingers. Use GetBoolean, don't use HasBoolean, HK rehearses, hehe.