Faith System

● ARCHIVED · READ-ONLY
Started by DarkprinceVI 11 posts View original ↗
  1. Currently I am creating a game with a few people, as many of you are also doing, and a primary goal I have is to make the game at least somewhat unlike the generic RPG maker game that is offered to you. In my endeavor I believe I have really screwed myself with ambition. I introduce you to the faith system. The faith system is designed on a system where exp is called faith, and this faith can be lost and or gained depending on the type of enemy you defeat. This system is designed to make you be able to level up to 50 and become more holy or level down to -50 and become more demonic. Sadly I have struggled with this script for approximately 2 weeks now. So allow me to offer the good news first

    A. I changed exp to faith

    Its always called faith

    B. I figured out how to make you lose faith in battle but not by enemy type

    C. And if I sort of mess up the game I can make you be in the negative levels.

    Now what I need to figure out is

    A. How to distinguish between two enemy types

    B. Produce skills for the negative levels

    C. Make myself level down

    D. Allow stats to continue to work even when in the negatives.

    I've been reading how to program ruby and have tried many a script to no avail so if someone could offer me either help and or guidance I would greatly appreciate it.
  2. You would need to figure out how to level in both ways. Can't help you there, would likely require a script, I don't know.

    However, if you make 50 neutral and make the scale Evil-Good be 1-99 you can use the database as it sits to make a curve that would make stats high at level one drop until they get to 50 and raise from there until high again at level 99. Wasn't sure about that, but I just tried it and it works.

    Can't help you with the rest, but I hope that helps.
  3. I did try that the first day, and even though it works it feels kinda wrong ya know? its cause im a perfectionist the symbolism of the negatives means alot to me

    But thank you alot for trying to help

    If all else fails I will use your method

    And give you credit where its due
  4. The easiest way to do this would be via script, in my opinion. Not that writing the script would necessarily be "easy". But as far as scripting goes, it wouldn't be hard to code.

    Personally, I would:

    1) Code out levels and experience, levels have to deal with stats and skills and all kinds of stuff, so changing levels around frequently would make the game near impossible to balance right.

    2) In the place of levels, create a new variable called "Faith", I'd call it karma or alignment or something else, just because having negative faith doesn't make sense to me, but it's your game :p so you decide.

    2.5) Make a gauge for the "Faith" level, if you want, if not you could just display it as a number like levels would. (If this makes you wonder "Why not just use levels then?", it's because the way levels are coded to affect other stuff. Creating something brand new and only setting connections that are needed would be easier).

    3) Make notetags for enemies so you can designate them "good" or "bad" or whatever. You could even go so far as to use notetags to provide the new "Faith" number's, version of exp you get per enemy killed. Let's call it FP (Faith points). You could then have the gauge/number from 2.5 change according to the number of FP each character has.

    4) Skills can easily be "attached" to the new "Faith" variable number. Meaning that when you hit a certain level, you can have the script add or take skills from the actor.

    5) Stats are the hard part now, only because I can't really think of a way to handle them with your system. I would need more information. Say an actor drops from 25 to 24 "Faith". Do they lose stats? Just because they are becoming "evil" or whatever doesn't necessarily mean they should be weaker, right? If that's true, then what are the stats based on since there aren't any levels? Unless you like the idea of just keeping stats the same per actor throughout the game, and letting equipment make the changes (it would probably be easier to balance that way?). If that's not a viable option, then I don't know. You tell me!

    P.S. I may forget to come back to this thread, so please quote my post if you respond, so that I get a notification and can make sure that I see your response!

    Also, how much ruby/RGSS3 do you know? I mean the concepts I listed aren't hard to code at all, but if you only know a tiny bit about ruby or RGSS3, then it may be too hard of a task for you.
  5. DarkprinceVI said:
    I did try that the first day, and even though it works it feels kinda wrong ya know? its cause im a perfectionist the symbolism of the negatives means alot to me

    But thank you alot for trying to help

    If all else fails I will use your method

    And give you credit where its due
    I definitely get what you mean, I was thinking the same thing when I mentioned it, but I thought I would bring that up just in case it hadn't occurred to you.
  6. I wouldn't think of Faith as being negative as much as being a Good/Evil marker, from the way you've described it.  To me, the concept of "negative Faith" is a contradiction in terms.  The lowest possible is No Faith (i.e. 0).

    It's more like "You can be Good from 0-50 or Evil from 0-50"

    You would probably need to parse notetags to make an enemy "type", then the type would be associated with the specific enemy.

    Here is a bit of code I use to parse the notetags and one of my smaller scripts that uses it.

    The notetag parser looks for tags like this, in the Yanfly format:

    <tag attribute="value">

    Spoiler
    ####################################################################
    # Module which reads XML formatted note tags and returns them as
    # HashMaps
    module Tag_reader
        
        ###################################################################
        # Represents a single XML node
        class XML_node
            
            #####################################
            # Constructor
            def initialize(name)
                @name=name
                
                # Set of name=value pairs
                @attributes={}
                
            end
            
            ###################################
            # Adds an attribute
            def add_attribute(name, value)
                @attributes[name]=value
            end
            
            ###################################
            # Returns this as an XML string
            def to_s
                result="<"+@name
                @attributes.each {
                    |key, value| result += " "+key+"=\""+value+"\""
                }
                result += " />\n"
                return result
            end
            
            attr_reader :)name)
            attr_reader :)attributes)
            
        end

        #######################################################
        # Reads a set of XML tags    
        class XML_Reader
            def initialize()
                @nodes=[]
            end
            
            ##########################################################
            # Reads the XML tags in note_string.  Does nothing if the
            # note string is empty or nil.  Returns the set of nodes read
            # from the note_string.  This may be empty
            def read(note_string)
                @nodes.clear
                if (note_string == nil)
                    return @nodes
                end
                note_s=note_string.to_s.strip
                # Ignore empty strings
                string_len=note_s.length
                if (string_len == 0)
                    return
                end
                index=0
                worker=""
                right_index=0
                node_name=""
                
                # Parse the XML string
                while (index < string_len)
                    
                    # Search for < mark
                    if (note_s[index] != '<')
                        index += 1
                        next
                    end
                    
                    # Find the > mark after the < mark
                    right_index=note_s.index("/>",index)
                    if (right_index == nil)
                        right_index=note_s.index('>',index)
                        if (right_index == nil)
                            break
                        end
                    end
                    
                    # This is a string from < to >
                    worker=note_s.slice(index, right_index-index+1)
                    worker=worker.strip
                    
                    # Find name="value" pairs
                    
                    # Skip the <name part of the XML
                    attr_index=worker.index(' ')
                    node_name=worker.slice(1,attr_index).strip
                    
                    new_node=XML_node.new(node_name)
                    while (worker.length > attr_index)
                        if (worker[attr_index] == ' ')
                            attr_index += 1
                            next
                        end
                        value_index=worker.index("=\"", attr_index)
                        if (value_index == nil)
                            break
                        end
                        
                        # Backspace to find the previous space or < mark - start of the
                        # attribute
                        attr_start_index=value_index-1
                        while (worker[attr_start_index] != '<' &&
                            worker[attr_start_index] != ' ')
                            attr_start_index -=1
                        end
                        # Get to the start of the attribute name
                        attr_start_index += 1
                        
                        # Skip the =" marker after attribute name
                        second_quote=worker.index("\"", value_index+3)
                        if (second_quote == nil)
                            break
                        end
                        attr=worker.slice(attr_start_index, value_index-attr_index)
                        value=worker.slice(value_index+2, second_quote-value_index-2)
                        new_node.add_attribute(attr, value)
                        attr_index = second_quote+1
                    end
                        @nodes << new_node
                    index=right_index+1
                end
                return @nodes
            end
        end
    end
     

    # And an example:

    #================================================
    #
    #    Script:    SwitchSetter
    # by:        whitesphere (whitesphere@comcast.net)
    #                July 5 2014
    #================================================
    =begin
    ================================================================================

    Description: Sets or unsets groups of switches when the map is entered

    --------------------------------------------------------------------------------
    History

    v1.0 (2014/07/10)
      Initial release
     
     
    --------------------------------------------------------------------------------
    Terms of Use

    - You are free to use this script for non-commercial projects.
    - For commercial projects, at least contact me first.
    - This script is provided as-is. Don't expect me to give support.
    - Reported bug will be fixed, but no guarantee on requested features.
    - No guarantee either for compatibility fixes.
    - Give credit to whitesphere (me), and do not delete this header.
    --------------------------------------------------------------------------------

    QUICK START:

    Add a note tag in the following format to a Map:
    <switch on="1,2,3" off="4,5">
    or
    <variable set="1=23, 2=34" >
    or
    <common_event call="1">
    or
    <common_event call="1,2,3">

    Common event executions take place after all switches and variables are
    set.

    The numbers are the Switch IDs to turn ON or OFF.
    For variables, the number is the variable ID, the value after the = is what
    the variable will be set to

    --------------------------------------------------------------------------------
    Below are the end-user SwitchSetter script functions:

        Not Applicable
            
    --------------------------------------------------------------------------------
    =end

    module SwitchSetter

        
      # Helper function which tries to convert any Ruby object to a true or
      # false value
      def self.to_b object
          if object == nil then
              return false
          end
          if object.respond_to?:)to_s) then
              obj_str=object.to_s.downcase.strip
              if obj_str == "true" || obj_str == "yes" || obj_str == "on" ||
                      obj_str == "t" || obj_str == "y" || obj_str == "1" then
                  return true
              end
              return false
          end
          if object.respond_to?:)to_i) then
              obj_int=object.to_i
              if obj_int == 0 then
                  return false
              else
                  return true
              end
          end
          return true
      end

    ###############################################################
    ###############################################################
    # Encapsulates all entries for a single Switch or Variable
        class Value_holder
        
            attr_reader:)value)
            attr_reader:)id)
            
            def initialize(id, value)
                @id=id.to_i
                @value=value
            end
            
            def to_s
                result="id="+@id.to_s+", value="+@value.to_s
                return result
            end
        end
        
    ###############################################################
    ###############################################################
    # This class handles the set of switches and variables
    class SwitchVarHolder

        # Constructor
        def initialize
            @switch_set=[]
            @variable_set=[]
            @common_event_set=[]
        end
        
        # Clear the sets
        def clear()
            @switch_set.clear
            @variable_set.clear
            @common_event_set.clear
        end

        def load_map(switch_set, variable_set, common_event_set)
            @switch_set.clear
            @variable_set.clear
            @common_event_set.clear
            if (switch_set != nil)
                switch_set.each {
                    |entry| @switch_set << entry
                    puts("Loaded switch entry "+entry.to_s)
                    }
            end
            if (variable_set != nil)
                variable_set.each {
                    |entry| @variable_set << entry
                    puts("Loaded variable entry "+entry.to_s)
                    }
            end
            if (common_event_set != nil)
                common_event_set.each {
                    |entry| @common_event_set << entry
                    puts("Loaded common event entry "+entry.to_s)
                    }
            end
            
            # Update the switches
            @switch_set.each {
                |entry| if ($game_switches[entry.id] == nil)
                    next
                end
                $game_switches[entry.id]=SwitchSetter::to_b(entry.value)
            }
            # Update the variables
            @variable_set.each {
                |entry| if ($game_variables[entry.id] == nil)
                    next
                end
                $game_variables[entry.id]=entry.value.to_i
            }
            # Queue up the common events
            @common_event_set.each {
                |entry| $game_temp.reserve_common_event(entry.id)
            }
        end
    end


        def self.init()
            @@instance=SwitchVarHolder.new()
        end
        
        def self.load(switches, variables, common_events)
            @@instance.load_map(switches, variables, common_events)
        end
        
        def self.started_everything?
            if (@@instance != nil)
                return true
            else
                return false
            end
        end

    end

    SwitchSetter::init


    # Add the accessors to get the switches to modify
    class Game_Map
        
        attr_reader :)map_id)
        
        alias SwitchSetter_setup setup
        
        def setup(map_id)
            SwitchSetter_setup(map_id)
            
            # Load the tile to region mappings
            SwitchSetter::load( switch_settings(),
                variable_settings(), common_event_settings())
        end

        # We fetch these from the RPGMap
        def switch_settings
            return @map.switch_settings
        end
        
        # We fetch these from the RPGMap
        def variable_settings
            return @map.variable_settings
        end
        
        # We fetch these from the RPGMap
        def common_event_settings
            return @map.common_event_settings
        end
        
    end


            
    class RPG::Map
            
        def read_note_tag_as_nodes
            if (@node_set == nil)
                reader=Tag_reader::XML_Reader.new
                @node_set=reader.read(@note)
            end
            return @node_set
        end
        
        # Returns the current switch settings
        def switch_settings
            if (@switch_settings != nil)
                if (@switch_settings.empty?)
                    return nil
                end
                return @switch_settings
            end
            @switch_settings=[]
            nodes=read_note_tag_as_nodes
            if (nodes == nil)
                return nil
            end
            nodes.each {
                |current|
                if (current.name != "switch")
                    next
                end
                on_string=current.attributes["on"]
                off_string=current.attributes["off"]
                if (on_string == nil && off_string == nil)
                    next
                end
                if (on_string != nil)
                    group=on_string.split(",")
                    group.each { |single|
                        new_entry=SwitchSetter::Value_holder.new(single, "true")
                        @switch_settings << new_entry
                        }
                end
                if (off_string != nil)
                    group=off_string.split(",")
                    group.each { |single|
                        new_entry=SwitchSetter::Value_holder.new(single, "false")
                        @switch_settings << new_entry
                        }
                end
            }
            return @switch_settings
        end
        
        # Returns the current variable settings
        def variable_settings
            if (@variable_settings != nil)
                if (@variable_settings.empty?)
                    return nil
                end
                return @variable_settings
            end
            @variable_settings=[]
            nodes=read_note_tag_as_nodes
            if (nodes == nil)
                return nil
            end
            nodes.each {
                |current|
                if (current.name != "variable")
                    next
                end
                set_string=current.attributes["set"]
                if (set_string == nil)
                    next
                end
                group=set_string.split(",")
                group.each { |single|
                    name_value_pair=single.split("=")
                    if (name_value_pair.length < 2)
                        next
                    end
                    new_entry=SwitchSetter::Value_holder.new(name_value_pair[0],
                        name_value_pair[1])
                    @variable_settings << new_entry
                }
            }
            return @variable_settings
        end
        
        # Returns the current common event settings
        def common_event_settings
            if (@common_event_settings != nil)
                if (@common_event_settings.empty?)
                    return nil
                end
                return @common_event_settings
            end
            @common_event_settings=[]
            nodes=read_note_tag_as_nodes
            if (nodes == nil)
                return nil
            end
            nodes.each {
                |current|
                if (current.name != "common_event")
                    next
                end
                set_string=current.attributes["set"]
                if (set_string == nil)
                    next
                end
                group=set_string.split(",")
                group.each { |single|
                    common_event_settings << single.to_i
                    new_entry=SwitchSetter::Value_holder.new(name_value_pair[0],
                        0)
                    @common_event_settings << new_entry
                }
            }
            return @common_event_settings
        end
        
    end


    # This is to support multiple common events at once which can
    # certainly happen with multiple events
    class Game_Temp

      attr_reader :reserved_common_events
      alias :old_common_event_queue_init :initialize
      def initialize
        old_common_event_queue_init
        @reserved_common_events = []
      end

      # re-write
      def reserve_common_event(common_event_id)
        @reserved_common_events.push(common_event_id) if common_event_id > 0
      end

      # Note that I don't actually need to clear it out. It's done
      # by the queue.

      # true if list is not empty
      def common_event_reserved?
        !@reserved_common_events.empty?
      end

      # Grab the first one, first-in-first-out order
      def reserved_common_event
        $data_common_events[@reserved_common_events.shift]
      end
    end
     
  7. Using a good or evil side would be interesting

    But it would require me to form a new class. Which means the new issue would be what should I use to change classes

    Items

    Events

    Enemies or personal deciscion. Or should the main character have both a good and evil bar... hmmm the script would be simple enough, I think theres a few tutorials on it as well. Your script looks rather useful though my elementary level of ruby literacy makes it difficult to grasp its full potential and workings.

    Regardless if I use your method coding is no longer a massive concern.

    Instead the new issue would be implementation and theme.

    Primarily id ask that you elaborate on your claim that my original faith system is contradicting as im very concerned with the ambiance my system gives off. So please, with all do respect, explain
  8. Did you even read my post, I explained a pretty simple way to go about coding it, and offered to help you out. If you don't want help coding this then... err... I guess this would make for an awkward post? Anyways, I offered, your choice.
  9. Sorry sorry. For some reason your post did not actually appear last night. Wow. I am so sorry you felt ignored. I will read your post real quick and see if I can emulate it
  10. DarkprinceVI said:
    Using a good or evil side would be interesting

    But it would require me to form a new class. Which means the new issue would be what should I use to change classes

    Items

    Events

    Enemies or personal deciscion. Or should the main character have both a good and evil bar... hmmm the script would be simple enough, I think theres a few tutorials on it as well. Your script looks rather useful though my elementary level of ruby literacy makes it difficult to grasp its full potential and workings.

    Regardless if I use your method coding is no longer a massive concern.

    Instead the new issue would be implementation and theme.

    Primarily id ask that you elaborate on your claim that my original faith system is contradicting as im very concerned with the ambiance my system gives off. So please, with all do respect, explain
    If I were doing a good/evil system, I would switch classes when the player crossed the good/evil threshold, after some "probation" period.  Or, if you use Yanfly's excellent scripts, you could make Good or Evil a subclass, so the attributes affect the character.  So Good characters might take extra damage from Dark attacks, and Evil from Light attacks, for example.

    I feel it is contradictory because the word "Faith" has a meaning which does not include the concept of "negative faith."  The word "faithless" doesn't mean the faith is less than 0, as much as it means the faith is 0.  

    If I were to use Faith, per se, I might use it in a Cleric.  As the Cleric is, say, possessed by a demon, the Cleric's Faith drops.  As it drops, the Cleric's magic becomes weaker and weaker (since it is clearly based on Faith).  When it reached 0, I'd call a Game Over screen that made clear "You lost your Faith and the demons took your soul to Hell."

    But, when you say "Killing certain enemies is negative Faith, or doing certain actions is negative Faith," and you say "Faith from 0 to -50 means you're a Demon" that clearly is more good vs evil, or angelic vs demonic (NOT necessarily good or evil, BTW!).

    So your interpretation looks more, to me, like Good vs Evil/Angelic vs Demonic/Law vs Chaos/etc, which is why I called it contradictory.
  11. A) There are a lot of different ways to "mark" an enemy as one that you'd receive positive or negative Faith for killing.  I assume you're using the EXP field to determine exactly how much positive or negative Faith you receive.  The easiest way would be to add an arbitrary amount (say, 50000) EXP to any enemy that would give negative faith.  Then, you could say "If Exp is greater than 50000 for an enemy, subtract 50000 and then multiply by -1".  So 50008 EXP would mean -8 Faith, whereas +8 Faith would simply be input as 8 EXP.  Just remember that you'd need to run the evaluation for each enemy, before you total up the positive and negative Faith gains.  The cleanest, best way, however, would be to use notetags and create a new "Faith Gain" property for enemies, which you would mostly copy the structure for EXP to set up.  In the long run, it will help you to learn this.  You could also set up an array or hash which associates Enemy ID to Faith Gain, if you don't want to use notetags.

    Now, where would you actually read this "EXP" field?  Check out self.gain_exp in BattleManager and gain_exp in Game_Actor.

    B. ) First of all, for "negative levels", all you need to do is change the way that levels are SHOWN to the player.  You can use that previously-suggested system where the character starts at Level 50 and can go in either direction to 1 or 99.  But wherever the Character Level text is drawn (e.g. draw_actor_level in Window_Base), have it show a number equal to 50 less than the character's actual level instead.  So if they're really level 48, it will show up as -2.  I belive this will save you a ton of work.

    As for the skills, check the level_up and level_down classes in Game_Actor.  You'll need to add logic there for resetting the character's skills based on their current level.  You could hard-code it (for example, "if character's level is 37 (13 towards Demonic) or below, Learn Skill "Dark Wave", else, Forget Skill "Dark Wave", and do that for every skill for every character), or maybe you can figure out the right way to modify the level/skill checks to add some skills where the values are low enough and others where the levels are high enough.

    C) The change_exp method in the Game_Actor class already contains the following code to run the level_up and level_down methods, so I think you can already level down.

    level_up while !max_level? && self.exp >= next_level_exp level_down while self.exp < current_level_expD) You actually want the stats (like Strength) to be able to go negative, or you simply want the Levels to be able to go negatives and the stats are adjusted accordingly?  If you just want Negative Levels, I explained how to do that in B.  If you want Negative Stats, well... "Negative Strength", for example,  would be a very weird concept since your players might not know or understand how it factors into battle formulae.  But if you really want to do it, here's the method you'll need to change: param_min in Game_BattlerBase.  Have it return 0 if MMP, 1 if MHP, and -999 otherwise.

    #-------------------------------------------------------------------------- # * Get Reduced Value of Parameter #-------------------------------------------------------------------------- def param_min(param_id) return 0 if param_id == 1 # MMP return 1 endJust be careful in your battle formulae that you never, for example, divide by a stat that might be zero at a given point.

    I hope this helps!  Your system is specific enough that you'd probably need to commission someone if you wanted the whole thing scripted for you, but if you're getting hung up on any one specific modification that you're trying to make, feel free to ask for some help!