Skip to content

Instantly share code, notes, and snippets.

@Hanmac
Last active December 15, 2015 20:18
Show Gist options
  • Save Hanmac/46aa0ecda5d117ed061d to your computer and use it in GitHub Desktop.
Save Hanmac/46aa0ecda5d117ed061d to your computer and use it in GitHub Desktop.
require "test/unit"
require "observer"
require "turn/autorun"
module Eventable
include Observable
# Alternative method to register an observer. In
# contrast to Observable#add_observer, which requires
# you to construct an object responding to :update or
# specify another symbol, this method takes a block
# that will be called when the observed object emmits
# an event of the requested type.
# == Parameters
# [target_event (nil)]
# Only fire the callback if the observed object issued
# an event of this type. If this is +nil+, the callback
# is always fired when the observed object changes.
def observe(target_event = nil)
callback = lambda do |event, emitter, info|
yield(event, emitter, info) if !target_event || event == target_event
end
add_observer(callback, :call)
end
def observe_value(event,meth)
@__auto_observes ||= []
@__auto_observes << [event,meth]
#yield
#p send(meth) != v
#changed
#notify_observers(event)
end
def auto_observe
@__auto_observes ||= []
temp = @__auto_observes.map{|event,meth|send(meth)}
yield
temp2 = @__auto_observes.map{|event,meth|send(meth)}
@__auto_observes.each.with_index {|(event,meth),index|
changed if temp[index] != temp2[index]
notify_observers(event)
}
end
# Works the same way as Observable#notify_observers, but
# automatically inserts +self+ as the second argument to
# the +super+ call so that observers know who called.
# +info+ is a hash that will be passed through to the observers.
def notify_observers(event, info = {})
super(event, self, info)
end
end
def overwrite(meth,&block)
old = instance_method(meth)
#we need to call super first
if old.owner != self
define_method(meth) do |*args, &b|
super(*args, &b)
instance_exec(*args,&block)
end
else
define_method(meth) do |*args, &b|
old.bind(self).call(*args, &b)
instance_exec(*args,&block)
end
end
end
def overwrite_hash_sum(meth,&block)
old = instance_method(meth)
define_method(meth) do |*args, &b|
temp = self.instance_exec(*args,&block)
temp = (temp.is_a?(Array) ? temp : [temp])
temp.inject(old.bind(self).call(*args, &b)) {|el,memo|
memo.merge(el) {|k,o,n| Array(o) + Array(n)}
}
end
end
def overwrite_hash_product(meth,&block)
unless method_defined?(meth)
define_method(meth) do |*args, &b|
return Hash.new(1.0)
end
end
old = instance_method(meth)
define_method(meth) do |*args, &b|
temp = self.instance_exec(*args,&block)
temp = (temp.is_a?(Array) ? temp : [temp])
temp.inject(old.bind(self).call(*args, &b)) {|el,memo|
memo.merge(el) {|k,o,n| o * n}
}
end
end
module RPG;end
module Game;end
#state
module RPG
class State
@instances = {}
attr_accessor :name
attr_reader :states_chance
def initialize(name)
@name = name
@states_chance = Hash.new(1.0)
self.class.instances[@name] = self
end
class << self
attr_reader :instances
def [](key)
@instances[key]
end
end
end
end
module Game
class State
attr_reader :name
def initialize(name)
@name = name
#cs_init
end
def states_chance
RPG::State[@name].states_chance
end
end
end
#baseitem
module RPG
class BaseItem
attr_accessor :name
def initialize(name)
@name = name
self.class.instances[@name] = self
end
class << self
#attr_reader :instances
def instances
return @instances ||= {}
end
def [](key)
(@instances ||= {})[key]
end
end
end
end
module Game
class BaseItem
attr_reader :name
def initialize(name)
@name = name
end
end
end
#equip + stats
module RPG
module EquipableItem
attr_accessor :states_chance,:auto_states,:require_states
#private
def initialize(*)
super
@auto_states = []
@require_states = []
@states_chance = Hash.new(1.0)
end
end
end
module Game
module EquipableItem
attr_reader :auto_states
#private
def initialize(*)
super
@auto_states = {}
rpg.auto_states.each{|n| @auto_states[n] = State.new(n) }
end
def states_chance
return rpg.states_chance
end
end
end
#weapon
module RPG
class Weapon < BaseItem
include EquipableItem
end
end
module Game
class Weapon < BaseItem
include EquipableItem
def rpg
RPG::Weapon[@name]
end
end
end
#skills
module RPG
class Skill < BaseItem
end
end
module Game
class Skill < BaseItem
def rpg
RPG::Skill[@name]
end
end
end
module Game
class Battler
include Eventable
attr_reader :name
def initialize(name)
@name = name
@sockets = {}
end
def equips
return {} if @sockets.nil?
return @sockets.dup.delete_if{|k,v|v.nil?}
end
def equip(slot,item)
# cs_unequiped(slot,@sockets[slot]) unless @sockets[slot].nil?
auto_observe {
@sockets[slot]=item
changed
notify_observers(:equiped,:slot => slot, :item => item)
}
# cs_equiped(slot,item)
return self
end
end
end
#actor
module RPG
class Actor
attr_accessor :name
def initialize(name)
@name = name
self.class.instances[@name] = self
end
class << self
#attr_reader :instances
def instances
return @instances ||= {}
end
def [](key)
(@instances ||= {})[key]
end
end
end
end
module Game
class Actor < Battler
end
end
#enemy
module RPG
class Enemy
attr_accessor :name
def initialize(name)
@name = name
self.class.instances[@name] = self
end
class << self
#attr_reader :instances
def instances
return @instances ||= {}
end
def [](key)
(@instances ||= {})[key]
end
end
end
end
module Game
class Enemy < Battler
def rpg
return RPG::Enemy[@name]
end
end
end
#Battler + States
module Game
class Battler
attr_reader :states
overwrite(:initialize) {
@states = Hash.new([])
observe_value(:states_chance_changed,:states_chance)
}
overwrite_hash_product(:states_chance) { states.values.flatten.map(&:states_chance) }
def add_state(key)
temp = State.new(key)
#if(@states[k].size > temp.rpg.stocks)
# @states[k].shift
#end
#states_cancel
#temp.rpg.states_cancel.each {|c| @states[c].each{remove_state(c)} }
auto_observe {
@states[key] += [temp]
changed
notify_observers(:state_added, :state => temp)
}
#cs_add_state(k)
return temp
end
def remove_state(key)
unless(@states[key].empty?)
auto_observe {
temp = @states[key].shift
changed
notify_observers(:state_removed, :state => temp)
}
return temp
else
return nil
end
end
end
end
#Battler + States + equip
module Game
class Battler
overwrite_hash_sum(:states) { equips.each_value.flat_map(&:auto_states) }
overwrite_hash_product(:states_chance) { equips.values.flatten.map(&:states_chance) }
end
end
#Actorclass
module RPG
class ActorClass
attr_accessor :name
def initialize(name)
@name = name
self.class.instances[@name] = self
end
class << self
#attr_reader :instances
def instances
return @instances ||= {}
end
def [](key)
(@instances ||= {})[key]
end
end
end
end
module Game
class ActorClass
attr_reader :name
attr_reader :actor
attr_reader :level
def initialize(name,actor)
@name = name
@actor = actor
@level = 0
end
def rpg
RPG::ActorClass[@name]
end
end
class Actor
attr_accessor :actorclasses
attr_accessor :removed_actorclasses
overwrite(:initialize) {
@actorclasses = {}
@removed_actorclasses = {}
}
def add_actorclass(k)
if @removed_actorclasses.include?(k)
@actorclasses[k] = @removed_actorclasses[k]
@removed_actorclasses.delete(k)
elsif !@actorclasses.include?(k)
@actorclasses[k] = create_actorclass(k)
end
#cs_add_actorclass(k)
return self
end
def remove_actorclass(k)
if @actorclasses.include?(k)
@removed_actorclasses[k] = @actorclasses[k]
@actorclasses.delete(k)
#cs_remove_actorclass(k)
end
return self
end
#private
def create_actorclass(k)
@actorclasses[k] = ActorClass.new(k,@name)
end
end
end
#actorclass + states
module RPG
class ActorClass
attr_accessor :states_chance,:auto_states
overwrite(:initialize) {
@auto_states = []
@states_chance = Hash.new(1.0)
}
end
end
module Game
class ActorClass
attr_reader :auto_states
overwrite(:initialize) {
@auto_states = {}
rpg.auto_states.each{|n| @auto_states[n] = State.new(n) }
}
def states_chance
return rpg.states_chance
end
end
class Actor
overwrite_hash_sum(:states) { actorclasses.each_value.flat_map(&:auto_states) }
overwrite_hash_product(:states_chance) { actorclasses.values.flatten.map(&:states_chance) }
end
end
#battler + skills
module Game
class Battler
attr_reader :skills
overwrite(:initialize) { @skills = Hash.new([]) }
def add_skill(k)
temp = Skill.new(k)
@skills[k] += [temp]
changed
notify_observers(:skill_added, :skill => temp)
return temp
end
def remove_skill(k)
unless(@skills[k].empty?)
temp = @skills[k].shift
changed
notify_observers(:skill_removed, :skill => temp)
return temp
else
return nil
end
end
end
end
#enemy + skills
module RPG
class Enemy
attr_accessor :skills
overwrite(:initialize) { @skills = [] }
end
end
module Game
class Enemy
#overwrite_hash_sum(:skills) { actorclasses.each_value.flat_map(&:auto_states) }
overwrite(:initialize) { rpg.skills.each{|s|add_skill(s)} }
end
end
class OverwriteTest < Test::Unit::TestCase
def setup
s=RPG::State.new(:burn)
s.states_chance[:freeze] = 0.5
w=RPG::Weapon.new(:sword)
w.auto_states << :burn
st=RPG::Weapon.new(:staff)
st.states_chance[:freeze] = 0.5
warrior=RPG::ActorClass.new(:warrior)
warrior.states_chance[:freeze] = 0.5
end
def test_states
#init rpg stuff
b = Game::Actor.new(:alex)
b.observe(:state_added) {|_,_,info| throw :sta}
b.observe(:state_removed) {|_,_,info| throw :str}
b.observe(:equiped) {|_,_,info| throw :eq}
# b.observe(:states_chance_changed) {|_,_,info| p "yeah auto works" }
assert_equal({},b.states)
assert_equal(1,b.states_chance[:freeze])
#assert_throws(:stcc){
#b.observe_value(:states_chance_changed,:states_chance) do
#end
#}
assert_throws(:sta){b.add_state(:burn)}
assert_equal(1,b.states[:burn].size)
assert_equal(0.5,b.states_chance[:freeze])
assert_throws(:str){b.remove_state(:burn)}
assert_equal({:burn=>[]},b.states)
assert_equal(1,b.states_chance[:freeze])
assert_throws(:sta){b.add_state(:burn)}
sword = Game::Weapon.new(:sword)
staff = Game::Weapon.new(:staff)
#sword.auto_states << Game::State.new(:burn)
assert_throws(:eq){ b.equip :hand, sword}
assert_equal(2,b.states[:burn].size)
assert_equal(0.25,b.states_chance[:freeze])
assert_throws(:eq){b.equip :hand, nil}
assert_equal(1,b.states[:burn].size)
assert_equal(0.5,b.states_chance[:freeze])
assert_throws(:eq){b.equip :hand, sword}
assert_equal(2,b.states[:burn].size)
assert_equal(0.25,b.states_chance[:freeze])
assert_throws(:eq){b.equip :hand, staff}
assert_equal(1,b.states[:burn].size)
assert_equal(0.25,b.states_chance[:freeze])
b.add_actorclass(:warrior)
assert_equal(1,b.states[:burn].size)
assert_equal(0.125,b.states_chance[:freeze])
end
def test_changed_events
b = Game::Actor.new(:alex)
b.observe(:states_chance_changed) {|_,_,info| throw :stcc }
assert_throws(:stcc){b.add_state(:burn)}
assert_throws(:stcc){b.remove_state(:burn)}
sword = Game::Weapon.new(:sword)
staff = Game::Weapon.new(:staff)
#sword.auto_states << Game::State.new(:burn)
assert_throws(:stcc){ b.equip :hand, sword}
assert_throws(:stcc){b.equip :hand, nil}
assert_throws(:stcc){ b.equip :hand, staff}
assert_nothing_thrown(:stcc){ b.equip :hand, sword}
end
def test_skills
e = RPG::Enemy.new(:slime)
e.skills << :fireball
b = Game::Actor.new(:alex)
b.observe(:skill_added) {|_,_,info| throw :ska}
b.observe(:skill_removed) {|_,_,info| throw :skr}
assert_equal({},b.skills)
assert_equal(0,b.skills[:fireball].size)
assert_throws(:ska){b.add_skill(:fireball)}
assert_equal(1,b.skills[:fireball].size)
assert_throws(:skr){b.remove_skill(:fireball)}
assert_equal(0,b.skills[:fireball].size)
ge=Game::Enemy.new(:slime)
assert_equal(1,ge.skills[:fireball].size)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment