Jump to content


Photo

question about game balancing


  • Please log in to reply
3 replies to this topic

#1 Manveru

Manveru
  • Member
  • 17 posts

Posted 27 June 2005 - 09:29 AM

I am working with my girlfriend on a big project of a game. It is still in stage of story writing, game world definition, creation of world maps , etc, etc.

We will use BG2 IE for prototyping this game. One of the main issues in the game creation is the level of difficulty chosen for enemies that are set against PC. I wonder how it is solved by modders around here.

What are the methods you choose to estimate the level of monsters ?

What do you think about graduating AI power depending on the game's difficulty level ? (ie. when game is on easy level the enemies are less smart than when the level is high)

what is your oppinion on the following mixed system ? : each monster has some generic level that satisfies monster's character (like: a demon is always disposing of certain abilities, like fireball, fear ...) then there is a variable part which depends on the PC level and his party levels members (like in Diablo 2 for example). This variable part includes strength and immunities of monster and several levels of AI. The advantages imo is that this system ensures that fighting the enemy will be always demanding task, but enemy would be more matched to the player's current level (but of course a demon would be impossible to kill by 1st level PC - for this we have "fixed" part of enemy definition). The disadvantage is amount of coding required (several enemy definition files, .cre in IE and several AI scripts to deal with different levels of character).

Thank you in advance for your feedback.
Elen Sila Lumenn' Omentielvo

#2 Cuv

Cuv

    Area Maker (retired)

  • Modder
  • 925 posts

Posted 27 June 2005 - 10:12 AM

What are the methods you choose to estimate the level of monsters ?

What do you think about graduating AI power depending on the game's difficulty level ? (ie. when game is on easy level the enemies are less smart than when the level is high)

View Post


In RTW I decided to make only certain types of monsters. They do not increase in level. But the placement or appearance of such monsters depends on several scripts (whether spawn scripts or area scripts... I even have some scripts running off containers and doors) that check not only your party level, but also check our own hidden difficulty system that the player chooses through a dialog at the onset of the mod. Individually, the monsters are not that daunting, but with Xyx's AI they work together and can be devestating in groups. And there is also a certain randomness to the mod... with scripts that run random number generators to make each time through a little bit different. RTW is a high level adventure... and NOT for 1st level PC's :P

I considered a similar type of system that you describe (although you have thought it out alot more), but in order to make it work you either need a ton of different creature files for each monster... or a ton of spells and scripting to give them the desired upgrades. If you have the time.... your method is the way to go if that is all you have to do. But I might rethink that if you also have to make areas, spells, quests, and all the dialog for a story you still havent written.

Here is an obsolete spawn script from RTW to give a general idea of what we are doing:

IF
Global("RTWMyDifficulty","GLOBAL",0)
LevelLT(Player1,22)
IsOverMe(Player1)
THEN
RESPONSE #100
CreateCreature("RTWSKEL2",[-1.-1],0) // Infernal Guard
TriggerActivation("GuardSpawn",FALSE)
END

IF
Global("RTWMyDifficulty","GLOBAL",0)
LevelGT(Player1,21)
IsOverMe(Player1)
THEN
RESPONSE #100
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
TriggerActivation("GuardSpawn",FALSE)
END

IF
Global("RTWMyDifficulty","GLOBAL",1)
LevelLT(Player1,22)
IsOverMe(Player1)
THEN
RESPONSE #100
CreateCreature("RTWBANS",[-1.-1],0) // Banshee
CreateCreature("RTWSKEL2",[-1.-1],0) // Infernal Guard
TriggerActivation("GuardSpawn",FALSE)
END

IF
Global("RTWMyDifficulty","GLOBAL",1)
LevelGT(Player1,21)
IsOverMe(Player1)
THEN
RESPONSE #100
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
TriggerActivation("GuardSpawn",FALSE)
END

IF
Global("RTWMyDifficulty","GLOBAL",2)
LevelLT(Player1,22)
IsOverMe(Player1)
THEN
RESPONSE #100
CreateCreature("RTWSKEL2",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL2",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL2",[-1.-1],0) // Infernal Guard
TriggerActivation("GuardSpawn",FALSE)
END

IF
Global("RTWMyDifficulty","GLOBAL",2)
LevelGT(Player1,21)
IsOverMe(Player1)
THEN
RESPONSE #100
CreateCreature("RTWBANS",[-1.-1],0) // Banshee
CreateCreature("RTWBANS",[-1.-1],0) // Banshee
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
TriggerActivation("GuardSpawn",FALSE)
END

IF
Global("RTWMyDifficulty","GLOBAL",3)
LevelLT(Player1,22)
IsOverMe(Player1)
THEN
RESPONSE #100
CreateCreature("RTWBANS",[-1.-1],0) // Banshee
CreateCreature("RTWSKEL2",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL2",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL2",[-1.-1],0) // Infernal Guard
TriggerActivation("GuardSpawn",FALSE)
END

IF
Global("RTWMyDifficulty","GLOBAL",3)
LevelGT(Player1,21)
IsOverMe(Player1)
THEN
RESPONSE #100
CreateCreature("RTWBANS",[-1.-1],0) // Banshee
CreateCreature("RTWBANS",[-1.-1],0) // Banshee
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
TriggerActivation("GuardSpawn",FALSE)
END

IF
Global("RTWMyDifficulty","GLOBAL",4)
LevelLT(Player1,22)
IsOverMe(Player1)
THEN
RESPONSE #100
CreateCreature("RTWSKEL2",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL2",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL2",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL2",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
TriggerActivation("GuardSpawn",FALSE)
END

IF
Global("RTWMyDifficulty","GLOBAL",4)
LevelGT(Player1,21)
IsOverMe(Player1)
THEN
RESPONSE #100
CreateCreature("RTWBANS",[-1.-1],0) // Banshee
CreateCreature("RTWBANS",[-1.-1],0) // Banshee
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
CreateCreature("RTWSKEL",[-1.-1],0) // Infernal Guard
TriggerActivation("GuardSpawn",FALSE)
END

Cuv

#3 jcompton

jcompton
  • Modder
  • 492 posts

Posted 27 June 2005 - 11:04 AM

Weimer has done playbalancing simulations for a new roguelike and has put additional thought and research into abstracting that experience to other rule systems. Drop him a line at weimer@cs.berkeley.edu and I imagine he can lay it out for you in some detail. (I imagine one of the first things he'll tell you is "Don't use the IE for prototyping.")

#4 Zyraen

Zyraen
  • Modder
  • 1402 posts

Posted 27 June 2005 - 10:57 PM

For my Mod I did a few basic character types, like 3 different Assassins CREs, each at different types of player difficulty. To avoid reproducing too much work or accidentally creating CREs that were harder as they seemed, I used 3 CREs from the game, that I had fought before so I would have an idea.

- Assassin 1 - Assassin in Mae'Var's guildhouse
- Assassin 2 - Arkanis Gath from Bodhi's Chapter 3 path
- Assassin 3 - Rune Assassin

Following that I just altered their appearances where necessary, and in one case to up the backstab modifier, I increased the Thief level. After that I altered the experience to be reflective (BG2 doesn't use very good experience awards, I feel, being overgenerous in that area)

Apart from these Assassin type I used a few others, namely Archers, Mages and Clerics, each separated into 2 difficulty levels, to form a "Shadow Thief" Party.

These encounters were set on a random time base and generally check the XP of Player1 to determine what "team" shows up. Following that, based on Tester's comments, I dropped / modified certain characters of the enemy party.

This approach I think is handy, because you reuse enemies from the game and you know what to expect from their relative difficulty. The only thing is that sometimes they are harder to defeat when together, so you have to test it yourself and through others. This makes setting up an Encounter quite easy...

1) pick CREs from the game
- adjust level / hitpoints / XP / AI / Items (make sure they don't all drop a Rifthome Axe upon being killed! lol. If you want them to be invisible upon showing up give them the Item(s) to allow them to do so, and the AI Script to use it)
- maybe multiple CREs for varying "toughness" of the same type of character
2) group them
3) modify the groups in Scripts

This should cover most of it, and is a simple way of adjusting difficulty levels I think. Some code is below.

IF
Global("KKThief", "GLOBAL", 1)
XPGT(Player1, 999999)
!ActuallyInCombat()
XPLT(Player1, 2000000)
!RealGlobalTimerNotExpired("Pursuit","GLOBAL")
THEN
RESPONSE #100
SetGlobal("KKThief", "GLOBAL", 0)
DisplayString(Player1,@16)
RealSetGlobalTimer("Pursuit","GLOBAL",600)
Wait(1)
CreateCreatureObjectOffset("STAssas2",Player1,[-100.-100])
CreateCreatureObjectOffset("STAssas2",Player1,[-100.100])

CreateCreatureOffScreen("STArch1",0)
CreateCreatureOffScreen("STArch2",0)

CreateCreatureOffScreen("STPri2",0)
CreateCreatureOffScreen("STMage1",0)
END

IF
Global("KKThief", "GLOBAL", 1)
XPGT(Player1, 1999999)
!ActuallyInCombat()
XPLT(Player1, 3000000)
!RealGlobalTimerNotExpired("Pursuit","GLOBAL")
THEN
RESPONSE #100
SetGlobal("KKThief", "GLOBAL", 0)
DisplayString(Player1,@16)
RealSetGlobalTimer("Pursuit","GLOBAL",600)
Wait(1)
CreateCreatureObjectOffset("STAssas2",Player1,[100.100])
CreateCreatureObjectOffset("STAssas3",Player1,[-100.-100])

CreateCreatureOffScreen("STArch2",0)
CreateCreatureOffScreen("STArch2",0)

CreateCreatureOffScreen("STPri2",0)
CreateCreatureOffScreen("STMage2",0)
END

The other approach I used was for a "boss" character as part of a group.

Assuming the group collectively is at just about the right difficulty, if the "boss" were to operating be at "full potential" the encounter would probably be very difficult. To get around this I created a separate AI script for the boss that is reliant on a single flag (which is set when the boss gets reduced to 10 life or less) before it kicks in. Therefore the boss operates just like an ordinary member of the group, UNTIL damaged severely, whereupon a "Heal" kicks in (the boss has a MINHP1 to prevent being killed prematurely) and the AI switches.

Assuming even if player manages to reduce the boss to 10 life or less (unlikely since I put the boss far behind and the boss does have more hitpoints than the rest) and the AI kicks into high gear, the encounter would still be "do-able" by loading the game and killing off the rest of the group before ganging up on the boss. In that case, when the AI switches the boss becomes much more of a challenge, but by then is fighting alone.

Edited by Zyraen, 27 June 2005 - 11:07 PM.

kiyos.jpg____btlbn2.gif____kovaS.jpg
Love between a Law Enforcer and a Fugitive - can such a thing even happen?
SoA Release - Overview / Download Links

Zyraen's Miscellaneous Mods - Ust Natha Accelerator, item tweaks, XP caps, The Ub3r Reaver Kit, and much more...
Spellhold Gauntlet - more than just a Spellhold-Be-Gone
Hidden Kits - hidden dual-classed kits with a twist for progression