Attribute balance

I have a very interesting question. I know how to make certain results dependent on a specific attribute (e.g. if ammunition is greater than 0, the gun fires, else the gun clicks). But I want to make it so that if one attribute is greater than another attribute you get a different result. Specifically, I have two warring nations, and I want to make it so that if the player's nation has a greater military strength, they win the battle, but if the NPC's nation has a greater military strength, they lose. Is this possible to do in Quest? If so, how?


Sounds like a simple "if script" --- you basically answered it yourself with your example ^_^

Essentially, you could create one Attribute on your player.object, one on your gun.object, and you could create one Type called, nation with an Attribute.

Player.Object
power Int (referring to it would be player.power)

Gun.Object
ammunition Int (or battery, lifetime etc whatever you wanted) (referring to it would be gun.ammunition)

if (gun.ammunition > 0) {
msg ("POW! The gun fires!")
else {
msg ("Click! Click! Oh noes! You are out of teh bulletz! Egads!")
}

Type
Attribute
nationpower Int (have all your "nations" inherit this attribute)

Then you just have to compare them which I am completely blanking on at the moment. @_@

It works exactly the same as your ammo script, except you compare the attribute to another attribute rather than a fixed number

ie:

if (player.military > opponent.military) {
//you win the fight
}
else if (player.military < opponent.military) {
//you lose
}
else {
// the armies are even
}

I have a "problem" with the simple victory here...
IE: You and I are the two fighting...
You bring 100 units
And I manage to get 101 units to the battle
I win, but how many units do I loose?
Better, but a little harder...
loop through each side, roll a d6, 1=kill (or 1,2= kill)
IE: your 100 units fire, and get 35 kills
My side fires an get 25 kills...
You loose 25, I loose 35...
You now have 75 units and I have 66...
You fire, 15 kills, I get 30 ( I got lucky!!!)
You now have 45, I have 51...
and so on until one side is out of units...
You: 6, Me: 0
You win, but it cost you 94 units that will need to be rebuilt before your next battle...


@ DarkLizard:

an example (it can be changed up, depending on what/how exactly you want the design to be for your game)

<object name="global_data_object">
  <attr name="self_1_unit_quantity_integer_attribute" type="int">999</attr>
  <attr name="self_2_unit_quantity_integer_attribute" type="int">500</attr>
  <attr name="enemy_1_unit_quantity_integer_attribute" type="int">100</attr>
  <attr name="enemy_2_unit_quantity_integer_attribute" type="int">200</attr>
  <attr name="enemy_3_unit_quantity_integer_attribute" type="int">50</attr>
</object>

<function name="combat_function" parameters="self_unit_quantity_integer_parameter, enemy_unit_quantity_integer_parameter">
  done_boolean_variable = false
  while (not done_boolean_variable) {
    self_unit_quantity_integer_variable = self_unit_quantity_integer_parameter
    enemy_unit_quantity_integer_variable = enemy_unit_quantity_integer_parameter
    for (not_used_variable, 1, self_unit_quantity_integer_variable) {
      if (DiceRoll ("1d6") < 3) { // a '1' or '2' valued dice roll is a hit/kill, '3-6' valued dice rolls are misses
        enemy_unit_quantity_integer_parameter = enemy_unit_quantity_integer_parameter - 1
      }
    }
    for (not_used_variable, 1, enemy_unit_quantity_integer_variable) {
      if (DiceRoll ("1d6") < 3) { // a '1' or '2' valued dice roll is a hit/kill, '3-6' valued dice rolls are misses
        self_unit_quantity_integer_parameter = self_unit_quantity_integer_parameter - 1
      }
    }
    if (self_unit_quantity_integer_parameter < 1) {
      msg ("You lost the battle, and the enemy has " + enemy_unit_quantity_integer_parameter + " units left")
      done_boolean_variable = true
    } else if (enemy_unit_quantity_integer_parameter < 1) {
      msg ("You won the battle, but you only have " + self_unit_quantity_integer_parameter + " units left")
      done_boolean_variable = true
    }
  }
</function>

// -----------------------------------------

// calling (using) the Function (scripting), examples:

combat_function (global_data_object.self_1_unit_quantity_integer_attribute, global_data_object.enemy_1_unit_quantity_integer_attribute)

combat_function (global_data_object.self_1_unit_quantity_integer_attribute, global_data_object.enemy_2_unit_quantity_integer_attribute)

combat_function (global_data_object.self_1_unit_quantity_integer_attribute, global_data_object.enemy_3_unit_quantity_integer_attribute)

combat_function (global_data_object.self_2_unit_quantity_integer_attribute, global_data_object.enemy_1_unit_quantity_integer_attribute)

combat_function (global_data_object.self_2_unit_quantity_integer_attribute, global_data_object.enemy_2_unit_quantity_integer_attribute)

combat_function (global_data_object.self_2_unit_quantity_integer_attribute, global_data_object.enemy_3_unit_quantity_integer_attribute)

Yep, that's the idea...
Thanks.
(Looks longer that what would have created using Basic!)


Thanks for the replies. I'm just checking back to see if I have any replies while I have a spare minute, so I haven't read much just yet. I will say this: DarkLizerd, I like your idea :) I'm still a MASSIVE noob when it comes to this though xD

Thanks for everyone's replies. I'll start trying a few of your answers out when I've got time to actually open the game file :)


here's my old and poor combat code (it was based upon/built from Pertex' combat code structure/design, so all credit goes to Pertex), you can take a look at for ideas on how to do some various combat things:

http://textadventures.co.uk/forum/quest/topic/3348/noobie-hks-help-me-thread#22483
http://textadventures.co.uk/forum/quest/topic/3348/noobie-hks-help-me-thread#22486 (the key/legend for all of my abrevs --- I've learned since to never ever use abrevs ever again, lol)

but, you should look into Pixie's Combat Library, to see/study/use some really good code and code design


Update:

I created a test file and just created an opponent object. I gave both objects a military attribute (as an integer), then used the expression given by TinFoilMkIV. It worked. I'm not entirely sure what I was doing wrong before, tbh.

hegemonkhan, I also used your code in the test file, but every time I tried to leave code view, it gave me an error. I don't really understand coding, so I'm probably making a huge error. I'll keep your code in mind for when I'm more clued up on how it works, though. Thanks for your help :) And thanks again for the extra links you sent in your last reply. I'll check those out.


oh, the code doesn't work, as it's not updated for the new versions (mainy of/for List/Dictionary Attributes) of syntax/coding that occured from ~ v5.3-v5.5. You'd also have to change the top/first line:

from: <asl version="530">
to: <asl version="550"> // or: <asl version="560">

as well as update all of the List/Dictionary coding/syntax to it's current form/syntax.

Aside from being lazy, there's no reason to update it, as it's really bad/poor code, so it just works as a study/idea guide for people on some ways of doing various things with the coding of/for combat.

I know it's hard to understand code, when you're new to it, but if you can try taking a look at it, hopefully some things will make some sense, and maybe you can see how to do the same via using the GUI/Editor. Basically my combat works like this:

(most of the important/main coding, which is the Functions, is at the bottom, read my code generally from the bottom up, to see the important stuff to study/understand)

  1. a main 'battle_system' Function to handle/get/setup you and the enemy and etc stuff (getting the enemy object, seeing if you can engage in combat or not)
  2. a 'battle sequence' Function that handles who goes first and etc (aka, the order of combat turns, handling the combat rounds)
  3. a 'self_battle_turn' Function for handling your combat turn
  4. a 'enemy_battle_turn' Function for handling the A.I./enemy combat turn

my apologies for not informing you that my (outdated) code doesn't work.


I would do the combat as a function...
(not true code...)
Player.army=100
Enemy.army=100

start loop {
if Player.army<0 then "player lost!" exit loop
if Enemy.army<0 then "The enemy is defeated!" exit loop
Enemy.army= Enemy.army -shoot(Player.army)
Player.army=Player.army-shoot(Enemy.army)
}

function shoot(Attacker)
return DiceRoll(1d6)*Attacker
// this will count as a hit on 1 out of 6, but, it may give a 100% hit if dice roll was a "6"
end function

second option
function shoot(Attacker)
H=0 // count of hits
for (A,1,Attacker){
if(DiceRoll(1d6)<3 then H=H+1
}
return(H)
end function

(This is a mix of Basic, which I know VERY! well, and Quest, which I know VERRY! little. But I'm sure someone here
can clean this up easy)
You could add a "retreat" command after each round if the battle is turning against you,
at the cost of a free attack against you...
And a moral roll, so that, if the enemy is loosing, he may flee the fight, and you get one last attack.


my code does an individual roll for each/every individual unit for whether they get a kill/hit or not.

also, the design (I didn't know what you wanted, so I decided upon doing this design for an example for you) of my code does this effect:

both sides get to do rolls for their starting size of/at each combat round (which is why I used two, iterations: the 'for' Functions, and had to use copy local attributes, to hold the initial rounds' armies sizes, while using the original global attributes to do the actual subtractions from, in order to have both sides/armies using their initial sizes for the rolls. A different design would be to have them take turns and that generally would mean that who'ever attacks first is reducing the other side's size and thus that reduced size would be used for the dice rolls on their turn after whoever goes first)


I'm sure my code can be made a bit more efficient, but it's not too far off in terms of top efficiency. Unfortunately, for efficiency/performance, high level code/language, does have much more overhead, than does basic or especially assembly (low level language), but for scale and human usability, high level language is better. There's a reason language has moved away from the early and/or low-evel languages to the more robust (more functions/conveniences/etc, but more overhead) current high level languages in use, like: C++, Java, Python, etc (it can take a year to learn everything that these language packages provide for you to use!)


I don't know basic, but I've worked with MS-DoS (well modern computer's cmd line/prompt/shell anyways) and Assembly, which generally has the code lines which you can jump around and also create blocks('label:') of code lines, for loops/iterations/function-macros-effects. Is this how the 'basic' language design works? or no?


Basic and Quest appear to be cousins...
Both high level, and easy to learn.
But I my case, I think in Basic, then need to convert the command into Quest...
But you just think in Quest first, this makes it easer for you...

But I will get there some day...
Yea, mine did not show a step of saving the kills so that they can be killed after both sides shot...
A personal note... Your variable names are WAYYY!!! to long to easy follow.
I use much shorter ones. (personal lazy habit)
But I know this is all just personal choices and the computer could not care less.
from your thread#22486, looks like you started with short variables too...

Did you set the army sizes or did you make them random, I could not follow that part or your code...
Here is an example: Basic-Quest

Basic:
for a=1 to 10
Print A
next A
(the output would be: 1 2 3 4... 10)
which I could also do on the same line:
for a=1 to 10: Print A: next A

Quest:
for (A, 1, 10) {
msg (A)
}
(The output would be the same)
Can Quest do single line?
Would it look like:
for (a,1,10){ msg(a)}

Actually both would be:
1
2
3
4
...
10
OK, I'm learning Quest my the minute... (yea, that fast)
Your function does both sides of the attacks, right?
I just had a simple generic single sided attack function.
I could see where yours would be quicker, 1 call instead of 2...
But why self_1 and _2 and enemy_1, _2, _3 ???
That I don't follow...


oh, the army sizes would be a totally separate case: depends on however you want to design your game. We can get into how your armies and their unit-sizes are generated/determined.

for my example, to show case the functions only, I just quickly created 2 armies of yours ('self') and 3 rival ('enemy') armies, via merely as Integer Attributes of my 'global_data_object' Object, just so you can see how the Function can take different inputs/arguments/parameters (which in this case is the different armies, one of yours and one of the enemies):

<object name="global_data_object">

  // two armies of yours:
  <attr name="self_1_unit_quantity_integer_attribute" type="int">999</attr> // one army of yours, having 999 forces/units
  <attr name="self_2_unit_quantity_integer_attribute" type="int">500</attr> // another army of yours, having 500 forces/units

  // three armies of rivals:
  <attr name="enemy_1_unit_quantity_integer_attribute" type="int">100</attr> // you hopefully understand now
  <attr name="enemy_2_unit_quantity_integer_attribute" type="int">200</attr> // ....
  <attr name="enemy_3_unit_quantity_integer_attribute" type="int">50</attr> // ....

</object>

and this is just an example of all of the different combinations of battles you can do:

// your army 1 vs enemy army 1:
combat_function (global_data_object.self_1_unit_quantity_integer_attribute, global_data_object.enemy_1_unit_quantity_integer_attribute)

// your army 1 vs enemy army 2:
combat_function (global_data_object.self_1_unit_quantity_integer_attribute, global_data_object.enemy_2_unit_quantity_integer_attribute)

// your army 1 vs enemy army 3:
combat_function (global_data_object.self_1_unit_quantity_integer_attribute, global_data_object.enemy_3_unit_quantity_integer_attribute)

// your army 2 vs enemy army 1:
combat_function (global_data_object.self_2_unit_quantity_integer_attribute, global_data_object.enemy_1_unit_quantity_integer_attribute)

// your army 2 vs enemy army 2:
combat_function (global_data_object.self_2_unit_quantity_integer_attribute, global_data_object.enemy_2_unit_quantity_integer_attribute)

// your army 2 vs enemy army 3:
combat_function (global_data_object.self_2_unit_quantity_integer_attribute, global_data_object.enemy_3_unit_quantity_integer_attribute)

oh, ya, just my personal preference, I know the convention is to have short labels/names (and single camel case), but for me, I like them being descriptive (and I hate shifting: upper case vs lower case, and I love underscores: as I have a hard time reading the label when there's no space between their words, for example: intStrength vs int_strength), as I can just read it and know exactly what I'm working with. It's kinda like instead of having an additional comment for what I'm doing, I put the comment into the label/name of it, itself, lol. It is a pain (a lot more typing on my part) and not easy to read them, I do admit I too have trouble some times with them. But, it's better than when I first started to learn to code and went about abrev'ing everything and forgetting what everything stands for and/or getting them confused/mixed up, laughs. I've learned never ever ever to abrev ever again. I try to make it as short as I can but without losing knowing what it is I'm working with. The reason for most of it's length is because I like that it ensures uniqueness and is good for organization, for example:

player.strength_integer_attribute = 100
player.strength_string_attribute = "strong"

this way, I clearly have 2 'strength' Attributes, one as an integer and one as a string. I like this descriptive clarity for myself. It's more useful for me than the irritation of having to type more and read fully/slowly due to such long labels/names.


I think quest can do horizontal code, or maybe just some things horizontal code, haven't really tested it much...


some of quest's Functions are capable of using concatenation, including that of a Function's return value, for example:

// just example of being able to have a Function's return value within another Function's header/signature (as a input/argument/parameter):

show menu ("Color?", split ("red;blue;yellow", ";"), false) { /* scripting */ }
// quest automatically (hidden from you), with the 'show menu', 'Showmenu', and 'get input' Functions does this: result = YOUR_INPUT/SELECTION, which you can then use the built-in 'result' Variable for whatever you want
msg ("Displaying your selected color: " + result)

vs

color_list = split ("red;blue;yellow", ";")
show menu ("Color?", color_list, false) { /* scripting */ }
// quest automatically (hidden from you), with the 'show menu', 'Showmenu', and 'get input' Functions does this: result = YOUR_INPUT/SELECTION, which you can then use this built-in 'result' Variable for whatever you want
msg ("Displaying your selected color: " + result)

example of complex concatenation and Functions within Functions' headers/signatures/parameters/arguments/inputs:

(not a practical example though, lol. That would take me awhile to come up with and craft/code correctly...)

<object name="global_data_object">
  <attr name="verb_list" type="simplestringlist">talk;search;equip</attr>
  <attr name="talk_script_attribute" type="script">
    msg ("talk")
  </attr>
  <attr name="search_script_attribute" type="script">
    msg ("search")
  </attr>
  <attr name="equip_script_attribute" type="script">
    msg ("equip")
  </attr>
</object>

<verb>
  <property>talk_script_attribute</property>
  <pattern>talk_script_attribute</pattern>
  <defaultexpression>You can't talk with that!</defaultexpression>
</verb>

<verb>
  <property>search_script_attribute</property>
  <pattern>search_script_attribute</pattern>
  <defaultexpression>You can't search that!</defaultexpression>
</verb>

<verb>
  <property>equip_script_attribute</property>
  <pattern>equip_script_attribute</pattern>
  <defaultexpression>You can't equip that!</defaultexpression>
</verb>

// scripting:

random_number = GetRandomInt (0, ListCount (global_data_object.verb_list) - 1)
random_choice = StringListItem (global_data_object.verb_list, random_number)
do (global_data_object, random_choice + "_script_attribute")

// I think you can combine the above all into one line (not recommended due to human readability/understanding difficulty, and especially prone to having a missing/NOT:even-matching-sided parenthesis when trying to write it in, lol):

do (global_data_object, StringListItem (global_data_object.verb_list, GetRandomInt (0, ListCount (global_data_object.verb_list) - 1)) + "_script_attribute")

// --------------

the 'do' and 'set' Functions, for example, are powerful as you can concatenate with them, as shown with 'do' above.

// -----------

whereas, for example, you can't with 'invoke':

invoke (global_data_object.talk_script_attribute) // NO error, but you're stuck with using static inputs
or
invoke (global_data_object.search_script_attribute) // NO error
or
invoke (global_data_object.equip_script_attribute) // NO error

So... 5 armies... got-it...


Ok, so, my original question was definitely answered. I'm actually not sure what I did wrong the first time, but TinFoilMkIV's reply solved the issue.

On top of this, DarkLizerd gave me some constructive criticism regarding the simplicity of my combat system. This resulted in a lot of useful instructions on combat systems. I've learned a lot from this thread, so thanks fellow game makers :)


Glad to be of help. Also wanted to add that the simplicity of your original idea is not necessarily a bad thing. Depending on how you want to game to play it can be a good idea to keep things simple and straight forwards. I suppose it comes down to how big of a part the battle between armies is to your game and how predictable you want them to be. I've played games where the variable outcomes works well and I've played others with very static outcomes in which random chance could potentially break the whole game.

So just something to keep in mind.


Simple works if simple is all you need...
If the guy with the biggest bat wins every time, you just need a bigger bat to beat him...
But it never gives an underdog a chance...
Glad to help.
(And a free Quest lesson... bonus!)


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

Support

Forums