[RESOLVED] Script Request: Threat/Aggro System [XP]

Started by KCMike20, January 04, 2009, 06:33:00 am

Previous topic - Next topic

Fantasist

July 06, 2009, 05:14:36 pm #40 Last Edit: July 06, 2009, 05:18:07 pm by Fantasist
The RMXP help file... *levels up*

EDIT:

New question. How do I determine if a skill is offensive? Like deals damage or applies a negative status effect? Or should I just make user configuration to let them decide which skills raise or reduce threat?
Do you like ambient/electronic music? Then you should promote a talented artist! Help out here. (I'm serious. Just listen to his work at least!)


The best of freeware reviews: Gizmo's Freeware Reviews




Blizzard

skill = $data_skills[ID]
if skill.power > 0 # offensive
end
if skill.plus_state_set.size > 0 # inflicts states
end
if (skill.plus_state_set & [BAD_STATE_ID1, BAD_STATE_ID2, BAD_STATE_ID3]).size > 0 # inflicts "bad" states
end
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

winkio

A configurable option that would be nice:

In some games, the healer has a very high aggro (most of the examples in my mind are mmos).  It would be a nice option to choose whether or not healers get high threat.

Fantasist

@winkio: I think I'll use both. Threat increases in the skill is offensive AND if it's included in a list of threat-raising skills. I could also check the skill's scope.

@Blizz: Thanks Blizz :) *goes off to modify skill_effect*

PS: This topic is so active today, wink or Blizz always posted before I did >.<
Do you like ambient/electronic music? Then you should promote a talented artist! Help out here. (I'm serious. Just listen to his work at least!)


The best of freeware reviews: Gizmo's Freeware Reviews




winkio

That's because I'm bored and am trying to get back into scripting like I get into swimming pools: with your m-- I mean by jumping in.

Ryex

this will be a great system, one quick question is it going to have the threat displayed or is it going to be a back ground system, it doesn't matter much as i can edit it to my liking either way if you release it, but I kinda want to know.
I no longer keep up with posts in the forum very well. If you have a question or comment, about my work, or in general I welcome PM's. if you make a post in one of my threads and I don't reply with in a day or two feel free to PM me and point it out to me.<br /><br />DropBox, the best free file syncing service there is.<br />

Blizzard

I didn't sleep much last night so I'm not really capable of anything useful. *coughs at actual scripts and the new Blizz-ABS plugin* <_<; Erm... Ignore those.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Fantasist

@Blizz: And I'm depriving myself of sleep right now O.O

@Ryex: I plan to make some sort of display for the DBS, but I haven't decided the layout yet.

Stop watching this topic for now guys. I've been working on the transitions thingy alongside this and I'm about to post the undocumented version:
http://forum.chaos-project.com/index.php?topic=1390.0
Do you like ambient/electronic music? Then you should promote a talented artist! Help out here. (I'm serious. Just listen to his work at least!)


The best of freeware reviews: Gizmo's Freeware Reviews




G_G

if anything fant heres this as well
it was in Game_Troop
  def random_target_enemy(hp0 = false)
   # Initialize roulette
   roulette = []
   # Loop
   for enemy in @enemies
     # If it fits the conditions
     if (not hp0 and enemy.exist?) or (hp0 and enemy.hp0?)
       # Add an enemy to the roulette
       roulette.push(enemy)
     end
   end
   # If roulette size is 0
   if roulette.size == 0
     return nil
   end
   # Spin the roulette, choose an enemy
   return roulette[rand(roulette.size)]
 end

Fantasist

July 09, 2009, 01:02:53 pm #49 Last Edit: July 09, 2009, 01:04:18 pm by Fantasist
I think that method is executed when a skill/status's scope is "Attack all enemies", am I right? If so, then it has nothing to do with this system.

Anyway, I completed the first draft. Here it is:

Spoiler: ShowHide

module ThreatConfig
  #--------------------------------------------------------------------------
  # * Config
  #--------------------------------------------------------------------------
  ThreatChance = 100 # The chance of enemies attacking based on threat
  #--------------------------------------------------------------------------
  # * Get the threat attribute
  #--------------------------------------------------------------------------
  attr_reader :threat
  def self.get_skill_threat(skill_id)
    threat = case skill_id
    # when skill_ID then [ user_threat, party_threat ]
    when 57 then [10, -2]
    else false
    end
    return threat
  end
  #--------------------------------------------------------------------------
  # * Get the threat attribute
  #--------------------------------------------------------------------------
  attr_reader :threat
  def self.get_item_threat(item_id)
    threat = case item_id
    # when item_ID then [ user_threat, party_threat ]
    when 33 then [10, -20]
    else false
    end
    return threat
  end
  #:::::::::::::: Don't touch these yet ::::::::::::::
  MaxThreat = 100
  MinThreat = 0
  AutoDetect = false # Automatically determine if a skill or item is dangerous
end
#==============================================================================
# ** Game_Actor
#==============================================================================
class Game_Actor
  #--------------------------------------------------------------------------
  # * Initialize threat attribute
  #--------------------------------------------------------------------------
  alias game_actor_threat_setup setup
  def setup(actor_id)
    @threat = 0
    game_actor_threat_setup(actor_id)
  end
  #--------------------------------------------------------------------------
  # * Get the threat attribute
  #--------------------------------------------------------------------------
  attr_reader :threat
  #--------------------------------------------------------------------------
  # * Set the threat attribute
  #--------------------------------------------------------------------------
  def threat=(val)
    max = ThreatConfig::MaxThreat
    min = ThreatConfig::MinThreat
    val = max if val > max
    val = min if val < min
    @threat = val
  end
  #--------------------------------------------------------------------------
  # * Threat at battle start
  #--------------------------------------------------------------------------
  def start_threat
    actor_id = self.id
    threat = case actor_id
    when 1 then 6
    when 2 then 7
    when 7 then 6
    else 0
    end
    return threat
  end
end
#==============================================================================
# ** Game_Party
#==============================================================================
class Game_Party
  #--------------------------------------------------------------------------
  # * Choose actor by threat
  #--------------------------------------------------------------------------
  alias choose_actor_by_threat random_target_actor
  def random_target_actor(hp0 = false)
    if rand(100) >= ThreatConfig::ThreatChance
      return choose_actor_by_threat(hp0)
    end
    # Collect valid actors
    targets = []
    for actor in @actors
      next unless (!hp0 && actor.exist?) || (hp0 && actor.hp0?)
      targets.push(actor)
    end
    # Get actors with maximum threat
    targets.sort! {|a, b| b.threat - a.threat}
    targets = targets.find_all {|a| a.threat == targets[0].threat}
    # Choose random
    target = targets[rand(targets.size)]
    return target
  end
end
#==============================================================================
# ** Game_Battler
#==============================================================================
class Game_Battler
  #--------------------------------------------------------------------------
  # * Attack Threat
  #--------------------------------------------------------------------------
  alias attack_effect_threat attack_effect
  def attack_effect(attacker)
    attacker.threat += 1 if attacker.is_a?(Game_Actor)
    attack_effect_threat(attacker)
  end
  #--------------------------------------------------------------------------
  # * Skill Threat
  #--------------------------------------------------------------------------
  alias skill_effect_threat skill_effect
  def skill_effect(user, skill)
    threat = user.is_a?(Game_Actor) && ThreatConfig.get_skill_threat(skill.id)
    if threat
      user_threat, party_threat = threat[0], threat[1]
      for actor in $game_party.actors
        threat_plus = actor.id == user.id ? user_threat : party_threat
        actor.threat += threat_plus
      end
    end
    skill_effect_threat(user, skill)
  end
end
#==============================================================================
# ** Scene_Battle
#==============================================================================
class Scene_Battle
  #--------------------------------------------------------------------------
  # * Defend Threat
  #--------------------------------------------------------------------------
  alias basic_action_threat_result make_basic_action_result
  def make_basic_action_result
    if @active_battler.current_action.basic == 1 &&
      @active_battler.is_a?(Game_Actor)
       @active_battler.threat -= 1
    end
    basic_action_threat_result
  end
  #--------------------------------------------------------------------------
  # * Item Threat
  #--------------------------------------------------------------------------
  alias item_action_threat_result make_item_action_result
  def make_item_action_result
    item_action_threat_result
    threat = @active_battler.is_a?(Game_Actor) && ThreatConfig.get_item_threat(@item.id)
    if threat
      user_threat, party_threat = threat[0], threat[1]
      for actor in $game_party.actors
        threat_plus = actor.id == @active_battler.id ? user_threat : party_threat
        actor.threat += threat_plus
      end
    end
  end
  #--------------------------------------------------------------------------
  # * Clear threats before battle
  #--------------------------------------------------------------------------
  alias clear_threats_start_phase1 start_phase1
  def start_phase1
    clear_threats_start_phase1
    $game_party.actors.each {|actor| actor.threat = actor.start_threat}
  end
end

class Window_Threat < Window_Base
 
  H = 20
 
  def initialize(x, y, w)
    super(x, y, w, 32 + actors.size * H)
    @threats = []
    actors.each {|a| @threats.push(a.threat)}
    self.contents = Bitmap.new(w-32, self.height-32)
    self.contents.font.size = H
    self.contents.font.bold = H <= 22
    refresh
  end
 
  def refresh
    self.contents.clear
    actors.each_with_index {|a, i|
    self.contents.draw_text(0, i*H, self.width-32, H, a.name)
    self.contents.draw_text(0, i*H, self.width-32, H, @threats[i].to_s, 2)
    }
  end
 
  def update
    flag = false
    actors.each_with_index {|a, i|
    @threats[i] = a.threat if a.threat != @threats[i]
    flag = true}
    refresh if flag
  end
 
  def actors
    return $game_party.actors
  end
 
end

class Scene_Battle
 
  alias threat_win_init main
  def main
    @threat_win = Window_Threat.new(0, 64, 160)
    threat_win_init
    @threat_win.dispose
  end
 
  alias threat_win_upd update
  def update
    @threat_win.update
    threat_win_upd
  end
 
end


Features:


  • Attacking increases threat by 1
  • Defending decreases threat by 1
  • Using skills changes threat as set in config
  • Using items changes threat as set in config


As for the skill and item config, here's a quote from the original request:

Quote
When ID then return [[X, Y]]

when 1 then return [[0, 0]]
when 2 then return [[50, 0]]
when 3 then return [[-100, 0]]
when 4 then return [[30, -10]]

This script allows the user to determine the maximum threat possible as well as the amount of threat each skill produces or removes from the actor using it.  The ID is the ID Number of the skill in the database, the X value is the amount of threat a skill produces (or removes) for the actor using it and the Y value is the amount of threat it produces or removes from all actors.  In the above example we made four different skills.  Skill 1 would be an example of a skill that produces no threat for the actor.  Skill 2 is an example of a skill that produces quite a bit of threat.  Skill 3 is a skill that removes all threat from the actor, and skill 4 would produce threat for the actor while removing threat from all actors.

The config is similar.

So anyone who's interested, please try it and test it to your content. I'd be happy to correct and improve this system :)
Do you like ambient/electronic music? Then you should promote a talented artist! Help out here. (I'm serious. Just listen to his work at least!)


The best of freeware reviews: Gizmo's Freeware Reviews




Holyrapid

I´ll try this. This will be extra nice for abs game. Or does this work with babs allready? Or do i need a plugin?

Fantasist

You know, good point. Frankly, I have no idea if this works with BABS. I'm taking a rough guess that it should, but for now, it's intended for the DBS.
Do you like ambient/electronic music? Then you should promote a talented artist! Help out here. (I'm serious. Just listen to his work at least!)


The best of freeware reviews: Gizmo's Freeware Reviews




Holyrapid

Well, i´ll try it and tell you if it works or not.

Fantasist

Wait, I just realized. This will most likely NOT work with BABS.
Do you like ambient/electronic music? Then you should promote a talented artist! Help out here. (I'm serious. Just listen to his work at least!)


The best of freeware reviews: Gizmo's Freeware Reviews




Holyrapid

Yea, it just gave me error of line 34. and all it says on that line is end... too bad.

Fantasist

July 09, 2009, 01:39:39 pm #55 Last Edit: July 09, 2009, 01:55:44 pm by Fantasist
Wait, what!? Did it say a Syntax Error? nvm, I'll look into it.

EDIT: No syntax error in the script I posted above. I guess it's not compatible with BABS just yet.
Do you like ambient/electronic music? Then you should promote a talented artist! Help out here. (I'm serious. Just listen to his work at least!)


The best of freeware reviews: Gizmo's Freeware Reviews




Jackolas

July 10, 2009, 04:43:16 pm #56 Last Edit: July 10, 2009, 05:22:46 pm by Jackolas
Fantasist. did I already say your brilliant?
script works like a dream... better even

just 1 question
i know u have defined MaxThreat = 100
what happens when you hit 100 threat.. ore if 2 players hit it?


Edit to more bug testing etc:

first 1 is... players can get -Aggro. its only not displayed... for example... if I use a skill that is doing -10 while i have 1 aggro. i can do 9 attacks before my aggro go's above 0

Second (not a major 1).. the main aggro target is picked at the beginning of the  turn and dos not regonise changes in aggro in the turn. example:
Spoiler: ShowHide
aggro begin turn is:
player 1 - 1 agro
player 2 - 5 agro
player 3 - 0 agro

first turn begins.
Player 1 attacks and gains till 20 agro.
player 2 defends and gains till 8 agro.
enemy attacks player 2 while player 1 has almost double aggro (because begin of turn player 2 had most aggro)
player 3 attacks and gains till 3 aggro.

next turn.
player 1 use skill and loses till 10 aggro
player 2 attacks and gains till 15 aggro
enemy attacks player 1 (same reason turn 1)
player 3 attacks and gains till 2 agro.

hope its clear

Fantasist

July 11, 2009, 04:47:08 am #57 Last Edit: July 13, 2009, 09:18:13 am by Fantasist
Thanks for the praise and feedback Jackolas :)

Quotewhat happens when you hit 100 threat.. ore if 2 players hit it?

Nothing. The threat won't go any higher than that. It's more of a technical setting than a configurable option. I might remove it eventually (and make the threat range 0-100) (and remove the limit for the highest threat).

QuoteSecond (not a major 1).. the main aggro target is picked at the beginning of the  turn and dos not regonise changes in aggro in the turn.

Thanks for pointing it out, I'll fix it. It IS a major issue btw.

EDIT:

OK, I fixed the above issue, now any changes in threat in the current turn are considered by the enemies.

Spoiler: ShowHide

module ThreatConfig
  #--------------------------------------------------------------------------
  # * Config
  #--------------------------------------------------------------------------
  ATTACK_THREAT = 1 # Threat to increase when actor attacks
  DEFEND_THREAT = 1 # Threat to decrease when actor defends
  THREAT_CHANCE = 100 # The chance of enemies attacking based on threat
 
  def self.get_skill_threat(skill_id)
    threat = case skill_id
    #========================================================================
    # SKILL THREAT CONFIG BEGIN
    #========================================================================
    when 57 then [10, -2]
    # when skill_ID then [ user_threat, party_threat ]
    #========================================================================
    # SKILL THREAT CONFIG END
    #========================================================================
    else false
    end
    return threat
  end
 
  def self.get_item_threat(item_id)
    threat = case item_id
    #========================================================================
    # SKILL THREAT CONFIG BEGIN
    #========================================================================
    when 33 then [10, -20]
    # when item_ID then [ user_threat, party_threat ]
    #========================================================================
    # SKILL THREAT CONFIG END
    #========================================================================
    else false
    end
    return threat
  end
end

#==============================================================================
# ** Game_Actor
#==============================================================================
class Game_Actor
  #--------------------------------------------------------------------------
  # * Initialize threat attribute
  #--------------------------------------------------------------------------
  alias game_actor_threat_setup setup
  def setup(actor_id)
    @threat = 0
    game_actor_threat_setup(actor_id)
  end
  #--------------------------------------------------------------------------
  # * Get the threat attribute
  #--------------------------------------------------------------------------
  attr_reader :threat
  #--------------------------------------------------------------------------
  # * Set the threat attribute
  #--------------------------------------------------------------------------
  def threat=(val)
    val = 0 if val < 0
    @threat = val
  end
  #--------------------------------------------------------------------------
  # * Threat at battle start
  #--------------------------------------------------------------------------
  def start_threat
    actor_id = self.id
    threat = case actor_id
    when 1 then 6
    when 2 then 7
    when 7 then 6
    else 0
    end
    return threat
  end
end
#==============================================================================
# ** Game_Party
#==============================================================================
class Game_Party
  #--------------------------------------------------------------------------
  # * Choose actor by threat
  #--------------------------------------------------------------------------
  alias choose_actor_threat_orig random_target_actor
  def random_target_actor(hp0 = false)
    if rand(100) >= ThreatConfig::THREAT_CHANCE
      return choose_actor_threat_orig(hp0)
    else
      return threat_target_actor(hp0)
    end
  end
  #--------------------------------------------------------------------------
  # * Calculate threat and choose actor
  #--------------------------------------------------------------------------
  def threat_target_actor(hp0=false)
    # Collect valid actors
    targets = []
    for actor in @actors
      next unless (!hp0 && actor.exist?) || (hp0 && actor.hp0?)
      targets.push(actor)
    end
    # Get actors with maximum threat
    targets.sort! {|a, b| b.threat - a.threat}
    targets = targets.find_all {|a| a.threat == targets[0].threat}
    # Choose random
    target = targets[rand(targets.size)]
    return target
  end
end
#==============================================================================
# ** Game_Battler
#==============================================================================
class Game_Battler
  #--------------------------------------------------------------------------
  # * Attack Threat
  #--------------------------------------------------------------------------
  alias attack_effect_threat attack_effect
  def attack_effect(attacker)
    attacker.threat += ThreatConfig::ATTACK_THREAT if attacker.is_a?(Game_Actor)
    attack_effect_threat(attacker)
  end
  #--------------------------------------------------------------------------
  # * Skill Threat
  #--------------------------------------------------------------------------
  alias skill_effect_threat skill_effect
  def skill_effect(user, skill)
    threat = user.is_a?(Game_Actor) && ThreatConfig.get_skill_threat(skill.id)
    if threat
      user_threat, party_threat = threat[0], threat[1]
      for actor in $game_party.actors
        threat_plus = actor.id == user.id ? user_threat : party_threat
        actor.threat += threat_plus
      end
    end
    skill_effect_threat(user, skill)
  end
end
#==============================================================================
# ** Scene_Battle
#==============================================================================
class Scene_Battle
  #--------------------------------------------------------------------------
  # * Defend Threat
  #--------------------------------------------------------------------------
  alias basic_action_threat_result make_basic_action_result
  def make_basic_action_result
    if @active_battler.current_action.basic == 1 && @active_battler.is_a?(Game_Actor)
      @active_battler.threat -= ThreatConfig::DEFEND_THREAT
    end
    basic_action_threat_result
  end
  #--------------------------------------------------------------------------
  # * Item Threat
  #--------------------------------------------------------------------------
  alias item_action_threat_result make_item_action_result
  def make_item_action_result
    item_action_threat_result
    threat = @active_battler.is_a?(Game_Actor) && ThreatConfig.get_item_threat(@item.id)
    if threat
      user_threat, party_threat = threat[0], threat[1]
      for actor in $game_party.actors
        threat_plus = actor.id == @active_battler.id ? user_threat : party_threat
        actor.threat += threat_plus
      end
    end
  end
  #--------------------------------------------------------------------------
  # * Choose target actor in realtime
  #--------------------------------------------------------------------------
  alias update_phase4_step2_choose_actor_realtime update_phase4_step2
  def update_phase4_step2
    @active_battler.make_action if @active_battler.is_a?(Game_Enemy)
    update_phase4_step2_choose_actor_realtime
  end
  #--------------------------------------------------------------------------
  # * Clear threats before battle
  #--------------------------------------------------------------------------
  alias clear_threats_start_phase1 start_phase1
  def start_phase1
    clear_threats_start_phase1
    $game_party.actors.each {|actor| actor.threat = actor.start_threat}
  end
end

class Window_Threat < Window_Base
 
  H = 20
 
  def initialize(x, y, w)
    super(x, y, w, 32 + actors.size * H)
    @threats = []
    actors.each {|a| @threats.push(a.threat)}
    self.contents = Bitmap.new(w-32, self.height-32)
    self.contents.font.size = H
    self.contents.font.bold = H <= 22
    refresh
  end
 
  def refresh
    self.contents.clear
    actors.each_with_index {|a, i|
    self.contents.draw_text(0, i*H, self.width-32, H, a.name)
    self.contents.draw_text(0, i*H, self.width-32, H, @threats[i].to_s, 2)}
  end
 
  def update
    flag = false
    actors.each_with_index {|a, i|
    @threats[i] = a.threat if a.threat != @threats[i]
    flag = true}
    refresh if flag
  end
 
  def actors
    return $game_party.actors
  end
 
end

class Scene_Battle
 
  alias threat_win_init main
  def main
    @threat_win = Window_Threat.new(0, 64, 160)
    threat_win_init
    @threat_win.dispose
  end
 
  alias threat_win_upd update
  def update
    @threat_win.update
    threat_win_upd
  end
 
end
Do you like ambient/electronic music? Then you should promote a talented artist! Help out here. (I'm serious. Just listen to his work at least!)


The best of freeware reviews: Gizmo's Freeware Reviews




Holyrapid

I take it, that it´s not BABS compatible yet?

Fantasist

Nope. And I don't think I will be doing it. Make a request in the script request forum, I'd like to see it in BABS :)

Oh, don't do it until I release the script. I'm documenting and fine-tuning the script right now.
Do you like ambient/electronic music? Then you should promote a talented artist! Help out here. (I'm serious. Just listen to his work at least!)


The best of freeware reviews: Gizmo's Freeware Reviews