Changing all NPC from friendly to aggressive

I decide to revamp my game(again). I am creating races of NPC's using a race type. If the player attacks one friendly NPC of a certain race type, how can I change all of that type to aggressive/enemy. They all inherit a friendly = true attribute. just unclear how to change that to false for a race type.
I have created a race tab on quest to create the NPCs so perhaps there is something I can add there.


If friendly = false, attack player?

Something like that.

I personally love the aggression system Morrowind and other Elder Scrolls games have. Each creature has a certain "aggression level," although the creature has this individually, unlike what you said. Once the aggression level reaches a certain point, the npc behaves differently. It may be friendly, neutral, aggressive, and go out of its way to attack the player no matter what.


Right. But I need to be able to have NPCs of that race to attack the player from then on. I need to change all npcs to friendly = false.

I'm also wanting to use this script for a light spell to change dark rooms to lighted.


After thinking about it, I believe adding an attribute/flag to the player to be read when the npc comes in contact with player it will change the npc friendly flag to false is the best way to go. That's the best I can come up with.


This may not be the best way to go about it, but what I would do is create a permanent object list with the game's startup script. Let's say the race you want to change are Bunny People (yes, I'm being a little silly), I would have them all inherit the attribute: race = "BunnyPeople". Then in the game startup script, I would add the following code:

TheBunnyPeople = NewObjectList()
foreach (NPC, AllObjects()) {
  if (NPC.race = "BunnyPeople") {
    list add (TheBunnyPeople, NPC)
  }
}
game.TheBunnyPeople = TheBunnyPeople

That script checks all game objects. For every object that is among the Bunny People, it adds them to an object list, and then permanently stores that list to game.TheBunnyPeople. From this point on, you can refer to all Bunny People in the game from that list, no matter where they are.

In your scenario, once the condition has been met to make them hostile, I'd run this script:

foreach (NPC, game.TheBunnyPeople) {
  SetObjectFlagOff (NPC, "friendly")
}

Assuming I didn't make any errors (and I very well may have), that should make all the Bunny People in the entire game hostile. If there is anything else that you want to do to the Bunny People, the good news is that anything you can do with any other object list can be done to game.TheBunnyPeople once you've created that list in the startup.

Of course, you'll have to change my examples of Bunny People to whatever you are actually using, but hopefully you get the idea.


That's what I was looking for! Thanks Humble Maybe make it a function and call it when needed


I think adding "game.friendly = false" directly onto your "player attack" function/command is the best way to go.
Before that, you will need to edit the creature spawn script, or wherever you keep the attributes.

How does having one attribute say game.friendly, and one say this.aggression/obj.agression sound?

if (game.friendly = false) {
  this.agression = true
}

(I didn't realise someone else answered the question.)

I still think having an aggression level is a good idea.


How about a player attribute called (whatever_race_friendly = true) ie. orc, elf, human. Then when whatever race is attacked the corresponding flag can be changed to "false" and when the (whatever race) comes in contact with player it will read the flag and control whether it attacks or not.

if (orc.parent = player.parent and player.orc_friendly = false)
   then (attack_player script)
else (give'm a big old smooch)

jmnevil54 ,
(laughing) That's what you said earlier in your first reply! Here I thought I figured it out....

Proudly Humble's script may be the ticket too...We'll see


Proudly Humbly method is really the only way to do it:

have/create/generate a list for each race type (as you don't want to be iterating through every object in the game, every time, lol), as that way you can set each of them to how you want them, via the iterating (foreach) Function.


if you want to have a more complex system, via having a scale (integer):

0 to 33: hostile // attacks you immediately / "on sight", etc features
34 to 66: neutral // whatever features
67 to 100: friendly // whatever features

(you can of course have more segments/levels than just 3, but this is just an example)

instead of just a toggle (boolean):

hostile = true // attacks you immediately / "on sight", etc features
hostile = false // doesn't attack you, etc features

// using pseudo TES: Morrowind's 'disposition' Attribute as concept (disposition is a good word for this game aspect, lol) example:

<attr name="changeddisposition_integer" type="script">
  <![CDATA[
    if (this.disposition_integer >  66) {
      this.disposition_string = "friendly"
    } else if (this.disposition_integer > 33) {
      this.disposition_string = "neutral"
    } else {
      this.disposition_string = "hostile"
    }
  ]]>
</attr>

You should be able to do this to get a list of your NPCs:

listofnpcs = FilterByType(AllObjects(), "BunnyPeople")

My first thought would be having a 'race' attribute, and using something like this to make them all hate you:

foreach (bunny, FilterByAttribute(AllObjects(), "race", "BunnyPeople")) {
  bunny.friendly = false
}

Many Looks like many different ways to do it :)


I really hope there are bunny people in your game after all this, Forgewright.


I'm confused. So what was your process in making the enemies? Are they made by the regular "object" button, or by a function?


Pixie said:

I really hope there are bunny people in your game after all this, Forgewright.

and orcs too, Pixie. Then at some point if the races get along... orc bunnies.


jmnevil54 said:

So what was your process in making the enemies? Are they made by the regular "object" button, or by a function?

Yes, the object button, with the combatlib tab and a race tab I made(just to see if I could make a tab...yay!) the race tab add race, and agility, strength, intelligence, friendly or not to player. plus whatever I want to the NPCs.


Glad I could help. I had a similar problem some time back and creating object lists this way was the solution I came up with. When I read your post, I wanted to share my solution. I've long suspected there was a solution similar to what Pixie supplied, but that was (and still is) in an area I'm unfamiliar with, and what I have is good enough for me.

Yes, I would actually make this a function. Actually, I'd put both scripts into functions (to keep the startup script neater and to help track errors on startup). The first function I'd name Character_Setup and call it as the game loads. If you have other races that you might want to reference globally, you could expand this Character_Setup function to something like:

Character_Setup

TheBunnyPeople = NewObjectList()
Orcs = NewObjectList()
Pixies = NewObjectList()
HumbleYellowMinions = NewObjectList()
foreach (NPC, AllObjects()) {
  if (NPC.race = "BunnyPeople") {
    list add (TheBunnyPeople, NPC)
  }
  else if (NPC.race = "orc") {
    list add (Orcs, "NPC")
  }
  else if (NPC.race = "Pixie") {
    list add (Pixies, "NPC")
  }
  else if (NPC.race = "HumbleYellowMinion") {
    list add (HumbleYellowMinions, "NPC")
  }
}
game.TheBunnyPeople = TheBunnyPeople
game.Orcs = Orcs
game.Pixies = Pixies
game.HumbleYellowMinions = HumbleYellowMinions 

...and so on.

There are many different ways you could do the second function, which is the one that actually changes the attribute. You could create one just simply to make all of the one race hostile. And you could add another one to make them friendly again.

Or you could create just one function, and determine the kindness/hostility with a parameter. In the follwing case, I would add a parameter named "mode":

Change_Hostility

foreach (NPC, game.TheBunnyPeople) {
  if (mode = "mean") {
    SetObjectFlagOff (NPC, "friendly")
  }
  if (mode = "kind") {
    SetObjectFlagOn (NPC, "friendly")
  }
}

So you could change the demeanor of the Bunny People with this simple line of script when conditions are met:

Change_Hostility ("mean")

or

Change_Hostility ("kind")

You could create functions like this for each and every race. Or you could have a function with two parameters that would work with any race set up with the Character_Setup function (which is what I would do). The two parameters, in order, would be NPCList and mode.

Change_Hostility

foreach (NPC, NPCList) {
  if (mode = "mean") {
    SetObjectFlagOff (NPC, "friendly")
  }
  if (mode = "kind") {
    SetObjectFlagOn (NPC, "friendly")
  }
}

For instance, this simple line of code would call the Change_Hostility funtion and make all pixies in a game turn peaceful:

Change_Hostility (game.Pixies, "kind")

(filler for getting my edited post, updated/posted)


it's basically the difference between Java and C++ engines/software in how they work:

  1. you can code in everything yourself (lots of manual work, but it's only one time, and I think it's usually faster for the compiler doing it, than quest running scripts to automatically do it for you)

  2. you can use scripts to generate your code/content (less/least manual work,but every time you play the game, it has to do all of the scripting, to generate your game content, which is probably slower than it compiling the game from permanent code done by you)


for example:

  1. you code everything in yourself/manually (a skeleton example below only obviously, lol):
<object name="monster">

  <attr name="monster_stringlist" type="simplestringlist">orc;ogre</attr>
  <attr name="monster_objectlist" type="objectlist">orc;ogre</attr>

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

  <object name="ogre">
    <inherit name="ogre_type" />
  </object>

</object>

<type name="monster_type">
</type>

<type name="orc_type">
  <inherit name="monster_type" />
</type>

<type name="ogre_type">
  <inherit name="monster_type" />
</type>
  1. using scripting to generate your code/content (a skeleton example below only obviously, lol):
<game name="example_game">
  <attr name="start" type="script">
    do (content_generation, "content_generation_script")
  </attr>
</game>

<object name="content_generation">
  <attr name="content_generation_script" type="script">
    create (monster)
    create (orc, orc_type)
    create (ogre, ogre_type)
    object_variable_1 = GetObject (orc)
    object_variable_1.parent = monster
    object_variable_2 = GetObject (ogre)
    object_variable_2.parent = monster
    monster.monster_stringlist = NewStringList ()
    monster.monster_objectlist = NewObjectList ()
    foreach (object_variable_3, AllObjects ()) {
      if (DoesInherit (object_variable_3, "monster_type")) {
        list add (monster.monster_stringlist, object_variable_3.name)
        list add (monster.monster_objectlist, object_variable_3)
      }
    }
  </attr>
</object>

<!--
There might be a scripting way of creating the Object Types too, but I'm not sure, so I just manually created/coded them in below
-->

<type name="monster_type">
</type>

<type name="orc_type">
  <inherit name="monster_type" />
</type>

<type name="ogre_type">
  <inherit name="monster_type" />
</type>

P.S.

personally, now that I've learned how Delegates work, I usually use Objects and their Script Attributes (+ Delegates), instead of Functions now, as it does allow for great organization/compartmentalization/encapsulation design, and it allows for more dynamic scripting too, as you can directly match-up/check those Objects with what you want to do within the scripting, making it dynamic, whereas you can't do that as directly with using Functions.

here's how Delegates work:

Delegates are basically how you can turn a Script Attribute into a Function, meaning that the Script Attribute can have a return value and/or arguments/parameters, just like a Function does/has.

// (Delegates are kind of similar to creating a 'prototype', except it's a 'prototype' for a Script Attribute, instead of a Function)
// (probably a good/safe place to put delegates is right under your library reference tags and above your 'game' Game Settings Object)

<delegate name="return_sum_of_two_integers_delegate" parameters="integer_parameter_1, integer_parameter_2" type="int" />

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

<game name="example_game">
  <attr name="start" type="script">
    get input {
      integer_variable_1 = ToInt (result)
      get input {
        integer_variable_2 = ToInt (result)
        this.sum = do (example_object, "sum_of_two_integers_script_attribute", integer_variable_1, integer_variable_2)
        this.sum_2 = do (example_object_2, "example_script_attribute_2", integer_variable_1, integer_variable_2)
        msg (this.sum)
        msg (this.sum_2)
      }
    }
  </attr>
</game>

<object name="example_object">
  <attr name="sum_of_two_integers_script_attribute" type="return_sum_of_two_integers_delegate">
    if (TypeOf (integer_parameter_1) = "int" andTypeOf (integer_parameter_2) = "int") {
      return (integer_parameter_1 + integer_parameter_2)
    } else {
      msg ("wrong input, try again")
    }
  </attr>
</object>

// the below is to just show that a Delegate can be used for multiple Script Attributes:

<object name="example_object_2">
  <attr name="example_script_attribute_2" type="return_sum_of_two_integers_delegate">
    if (TypeOf (integer_parameter_1) = "int" andTypeOf (integer_parameter_2) = "int") {
      return (integer_parameter_1 + integer_parameter_2)
    } else {
      msg ("wrong input, try again")
    }
  </attr>
</object>

I quite like Proudly Humble's way of setting it up. But for the Character_setup script, I'd suggest it can be easier if you give the lists consistent naming. For example:

foreach (NPC, AllObjects()) {
  if (HasString (NPC, "race")) {
    race = NPC.race
    if (not HasAttribute (game, "list_of_"+race)) {
      set (game, "list_of_"+race, NewObjectList())
    }
    racelist = GetAttribute (game, "list_of_"+race)
    list add (racelist, NPC)
  }
}

Then you have your lists game.list_of_bunnyperson, game.list_of_orc, and so on; and giving a character a new race will create a new list automatically.

Or as this script is only running once, if you want to use names like the one you've chosen, it's not that much difference to use the builtin filters:

game.TheBunnyPeople = FilterByAttribute (AllObjects(), "race", "BunnyPeople")
game.Orcs = FilterByAttribute (AllObjects(), "race", "orc")
game.Pixies = FilterByAttribute (AllObjects(), "race", "Pixie")
game.HumbleYellowMinions = FilterByAttribute (AllObjects(), "race", "HumbleYellowMinion")

Sorry if there's errors in there, I'm writing off the top of my head and half asleep right now.


Log in to post a reply.

Support

Forums