diff options
| author | realtradam <[email protected]> | 2021-05-26 01:24:30 -0400 |
|---|---|---|
| committer | realtradam <[email protected]> | 2021-05-26 01:24:30 -0400 |
| commit | 7bec71db2680e0503f39c31047f5f90ca89433df (patch) | |
| tree | 4d987b479b0670256af5c1a4ffe5ab7b75fb23b4 | |
| download | FelECS-7bec71db2680e0503f39c31047f5f90ca89433df.tar.gz FelECS-7bec71db2680e0503f39c31047f5f90ca89433df.zip | |
init
| -rw-r--r-- | README.mdown | 284 | ||||
| -rw-r--r-- | component_manager.rb | 35 | ||||
| -rw-r--r-- | components/00_renderable.rb | 16 | ||||
| -rw-r--r-- | components/01_sprite.rb | 44 | ||||
| -rw-r--r-- | components/02_label.rb | 27 | ||||
| -rw-r--r-- | components/03_player_control.rb | 21 | ||||
| -rw-r--r-- | components/04_map.rb | 21 | ||||
| -rw-r--r-- | components/05_interactable.rb | 16 | ||||
| -rw-r--r-- | components/06_collidable.rb | 22 | ||||
| -rw-r--r-- | components/07_battle.rb | 4 | ||||
| -rw-r--r-- | components/07_indoor.rb | 4 | ||||
| -rw-r--r-- | components/07_overworld.rb | 16 | ||||
| -rw-r--r-- | components/debug_singleton.rb | 13 | ||||
| -rw-r--r-- | entity_manager.rb | 63 | ||||
| -rw-r--r-- | helpers/00_tileset.rb | 49 | ||||
| -rw-r--r-- | helpers/01_component.rb | 102 | ||||
| -rw-r--r-- | logos/felflame-logo-text.png | bin | 0 -> 38979 bytes | |||
| -rw-r--r-- | logos/felflame-logo-text.svg | 172 | ||||
| -rw-r--r-- | logos/felflame-logo.png | bin | 0 -> 25459 bytes | |||
| -rw-r--r-- | logos/felflame-logo.svg | 97 | ||||
| -rw-r--r-- | signatures.rb | 54 | ||||
| -rw-r--r-- | system_manager.rb | 5 | ||||
| -rw-r--r-- | systems/00_update_levels.rb | 34 | ||||
| -rw-r--r-- | systems/10_player.rb | 41 | ||||
| -rw-r--r-- | systems/99_render.rb | 37 | ||||
| -rw-r--r-- | test.rb | 18 |
26 files changed, 1195 insertions, 0 deletions
diff --git a/README.mdown b/README.mdown new file mode 100644 index 0000000..a8f3b46 --- /dev/null +++ b/README.mdown @@ -0,0 +1,284 @@ + + + +# What is this? + +This is a Ruby ECS Framework for developing games. It is still a work in progress in the early stages, is not fit for use, and does not work. +It is originally designed with DragonRuby in mind but should work with anything that runs on Ruby. + +I wanted a reusable framework so I could quickly and effectively develop games. I also want it to be more complete, as opposed to barebones or boilerplate. +I plan to eventually add functionality outside of just ECS such as loading tilesets, a camera system, etc. that are built into the framework to work seamlessly. + +Below are the specifications I have imagined for this framework and have been written out. They are subject to change as FelFlame is developed and used. + +# Specification + +## Aliases: +```ruby +FF = FelFlame +FF::Ent = FelFlame::Entities +FF::Cmp = FelFlame::Components +FF::Sys = FelFlame::Systems +FF::Sce = FelFlame::Scenes +FF::Stg = FelFlame::Stage +``` +## Classes: + +### FF::Entities +```ruby +FF::Ent.new(@component1, @component2) +@entity = FF::Ent.get(entity_id) +FF::Ent.delete(entity_id) [email protected] # => unique entity id + [email protected] @component [email protected] @component [email protected] # => [:id, :scenes, :components] +FF::Ent.load @entity_dump +``` + +### FF::Components +```ruby +FF::Cmp.new('Name', 'param1', param2: 'default') +FF::Cmp::Name.new(param1: value1) +@component = FF::Cmp::Name.get(component_id) +FF::Cmp::Name.get_by_entity(entity_id) # gets array of components [email protected](param2: 'not default') [email protected] = 'different not default' +FF::Cmp::Name.delete(component_id) +FF::Cmp::Name.delete_by_entity(entity_id) # deletes all related components attached to entity [email protected] # returns hash of all variables!(and the id) +FF::Cmp::Name.load @component_dump + +FF::Cmp::Health.added # => returns values for sys to setup +FF::Cmp::Health.removed # => returns values for sys to setup +FF::Cmp::Health.is_set('var') # => returns values for sys to setup +``` + +### FF::Systems +```ruby +FF::Sys.new(name: 'Render', position: 5, frame: 1) do + @component.each do + # functionality + end +end +FF::Sys::Render.trigger_when FF::Cmp::Health.added +FF::Sys::Render.trigger_when FF::Cmp::Health.removed +FF::Sys::Render.trigger_when FF::Cmp::Health.is_set('var') +``` + +### FF::Scenes +```ruby +FF::Scn.new(name: 'Scene1', position: 1) +FF::Scn::Scene1.add @entity +FF::Scn::Scene1.add FF::Sys::Render +FF::Scn::Scene1.entities # => [id_1, id_7, etc] +FF::Scn::Scene1.systems # => [:Render, :Damage, etc] +FF::Scn::Scene1.dump # => [:name, :entities, :systems] +FF::Scn::Scene1.load @scene_dump +``` + +### FF::Stage +```ruby +FF::Stg.add FF::Scn::Scene1 +FF::Stg.remove FF::Scn::Scene1 +FF::Stg.scene # => [:Scene1, :Scene2, etc] +FF::Stg.dump # => [:Scene1, :Scene2, etc] +FF::Stg.load @stage_dump +FF::Stg.clear +``` + +### FelFlame +```ruby +FF.dump # => all data +FF.load @felflame_dump +``` +--- + + + +--- +# Ramblings: +Was my originally written up specs. Rewrote it as what is written above to be more clear. +The below are more verbose but not as helpful for me for implementation. Once the framework is +complete I will use a more verbose explanation as below to help users of the framework. + +--- + +Creating Entities: + +```ruby +# Plain: +@my_entity = FF:Ent.new + +# With components: +FF::Ent.new(FF::Cmp::Position.new(var1: 'val', var3: 'change_default'), + FF::Cmp::Health.new(hp: 20), + FF::Cmp::Poison.new(dps: 3), + FF::Cmp::Poison.new(dps: 2), # This entity has 2 of the same component in it! + FF::Cmp::Selection.get(component_id)) # Components can belong to multiple entities, this component already existed elsewhere! +``` + +Adding and Removing Components from Entities: +```ruby +@my_entity = FF::Ent.get(entity_id) + +@my_entity.remove(component_id) +# Remove the specific component with that id + +@my_entity.remove(FF::Cmp::Poison) +# Removes all components of that type + +@my_entity.add(FF::Cmp::Selection.new) +# Adds a new Component +``` + +Creating Component Class: + +```ruby +# Creating a component 'factory': +FF::Cmp.new('Name', 'var1', 'var2', var3: 'default') # Name, *no_default, **with_default +``` + +And then using those components: +```ruby +@new_cmp = FF::Cmp::Name.new(var1: 'oke') # var3 will be 'default', var2 will be nil +@new_cmp.var2 = 3 # now var2 is set +@new_cmp.set(var1: 'nope', var3: 'different') # var1 and var3 are now changed! +@new_cmp.to_hash # returns the hash of all variables! +``` + +Referencing Components: +```ruby +FF::Cmp::Name.get(component_id) # gets component by their unique id +FF::Cmp::Name.get_by_entity(entity_id) # gets component that is attached to the entitry +# will return array of components if there is multiple of same component +# if it returns array, see the `dump` section. Need to add custom method to the array +``` + +Creating Systems: +```ruby +FF::Sys.new(name: 'Render', position: 5, frame: 1) do +# position is the order in which systems get executed, can be overlapping but then order is unexpected between same positions +# frame is on which frame the system will be called. 0 is never, 1 is on each frame, 2 is every other frame, etc + FF::Cmp::Position.each do + #render your sprite + end +end +``` + +Enabling Systems: +```ruby +# By default systems are not enabled. You need to add them to a scene +FF::Scn::Scene1.add FF::Sys::Render + +# They can also be disabled by removing them +FF::Scn::Scene1.remove FF::Sys::Render +``` + +Custom Hooks: +```ruby +# Systems can be configured to be called whenever a certain component is added, removed or set +FF::Sys::Damage.trigger_when FF::Cmp::Health.added +FF::Sys::Revive.trigger_when FF::Cmp::Health.removed +FF::Sys::Healup.trigger_when FF::Cmp::Health.is_set + +# Systems can also be manually called so you can code custom hooks! +FF::Sys::Restore.run +``` + +Scenes contain Entities and Systems +```ruby +FF::Scn.new(name: 'Scene1', position: 1) +# Multiple scenes could be ran at once, if they do then they will run according +# to their positions as explained above + +FF::Scn::Scene1.add FF::Entity.get(entity_id) +# You can also just pass the id on its own => FF::Scn::Scene1.add entity_id +FF::Scn::Scene1.add FF::Entity.new + +FF::Scn::Scene1.add FF::Sys::Render +``` + +To List Systems and Enties +```ruby +FF::Scn::Scene1.get_entities # => [id_1, id_7, etc] +FF::Scn::Scene1.get_systems # => [:Render, :Damage, etc] +``` + +To run a Scene it must be added to the Stage +```ruby +FF::Stg.add FF::Scn::Scene1 +``` + +Or remove it: +```ruby +FF::Stg.remove FF::Scn::Scene1 +``` + +Show all Scenes on the Stage: +```ruby +FF::Stg.scenes # => [:Scene1, :Scene2, etc] +``` + +Remove all Scenes from the Stage: +```ruby +FF::Stg.clear +``` + +You can save the current game state: +```ruby +@json_save_data = FF.dump +``` + +You can also specifically choose what you want to save: +```ruby +@hash_entity = FF::Ent.get(entity_id).dump +# to save all components related to a player + +@hash_component_single = FF::Cmp::Health.get(component_id).dump +# save all data in the single component(needs to handle arrays of components) + +@hash_component = FF::Cmp::Health.dump +# save all components of a certain component type + +@hash_components_all = FF::Cmp.dump +# save all components + +@hash_scene = FF::Scn::Scene1.dump +# save all entities, components, and activated systems in a given scene +``` + +And then they can be loaded back in: +```ruby +FF::Ent.load(@hash_entity) +FF::Cmp::Health.load(@hash_component) +FF::Cmp.load(@hash_component) +FF::Cmp.load(@hash_components_all) +FF::Scn.load(@Hash_scene) +``` + +### To Do List(old) + +--- + +* [ ] Some level of hierarchical support? +* [ ] One Component to many entities. +* [ ] Multiple of same component to one entity +* [ ] State Machine? +* [ ] Systems execute code on an event + * [ ] Adding/removing/setting component is event + * [ ] Frame is an event +* [ ] System Execution Order +* [ ] Save Dump/Load + + + + + + + + + + + diff --git a/component_manager.rb b/component_manager.rb new file mode 100644 index 0000000..f54c5f6 --- /dev/null +++ b/component_manager.rb @@ -0,0 +1,35 @@ +#require 'app/ECS/base_component.rb' + +#require 'app/ECS/components/00_test_component.rb' +#require 'app/ECS/components/01_based.rb' + +class Components + class <<self + def entity_destroyed(entity_id) + constants.each do |component| + component.delete(entity_id) unless (component.id & Entity.signatures[entity_id]).zero? + end + end + + def entity_created(entity_id) + constants.each do |component| + const_get(component.to_s).add(entity_id) unless (const_get(component.to_s).id & Entity.signatures[entity_id]).zero? + end + end + + def new(component_name, *attrs, **attrs_with_defaults) + const_set(component_name, Class.new(Helper::BaseComponent) {}) + attrs.each do |attr| + Components.const_get(component_name).attr_accessor attr + end + attrs_with_defaults.each do |attr, default| + Components.const_get(component_name).attr_writer attr + Components.const_get(component_name).define_method(attr) do + return default unless instance_variable_defined? "@#{attr}" + + instance_variable_get "@#{attr}" + end + end + end + end +end diff --git a/components/00_renderable.rb b/components/00_renderable.rb new file mode 100644 index 0000000..3971c8c --- /dev/null +++ b/components/00_renderable.rb @@ -0,0 +1,16 @@ +class Components + # If an entity can be rendered on screen + class Renderable < Helper::BaseComponent + attr_accessor :z + + def initialize + @z = 0 + end + + def set(**opts) + opts.each do |key, value| + self.send "#{key}=", value + end + end + end +end diff --git a/components/01_sprite.rb b/components/01_sprite.rb new file mode 100644 index 0000000..8d30cdf --- /dev/null +++ b/components/01_sprite.rb @@ -0,0 +1,44 @@ +class Components + # If an entity can be rendered on screen + class Sprite < Helper::BaseComponent + + attr_accessor :x, :y, :w, :h, :path, :angle, :a, :r, :g, :b, + :source_x, :source_y, :source_w, :source_h, + :tile_x, :tile_y, :tile_w, :tile_h, + :flip_horizontally, :flip_vertically, + :angle_anchor_x, :angle_anchor_y + + def set(x: @x, y: @y, w: @w, h: @h, path: @path, angle: @angle, a: @a, r: @r, g: @g, b: @b, + source_x: @source_x, source_y: @source_y, source_w: @source_w, source_h: @source_h, + tile_x: @tile_x, tile_y: @tile_y, tile_w: @tile_w, tile_h: @tile_h, + flip_horizontally: @flip_horizontally, flip_vertically: @flip_vertically, + angle_anchor_x: @angle_anchor_x, angle_anchor_y: @angle_anchor_y) + {x: @x = x, + y: @y = y, + w: @w = w, + h: @h = h, + path: @path = path, + angle: @angle = angle, + a: @a = a, + r: @r = r, + g: @g = g, + b: @b = b, + source_x: @source_x = source_x, + source_y: @source_y = source_y, + source_w: @source_w = source_w, + source_h: @source_h = source_h, + tile_x: @tile_x = tile_x, + tile_y: @tile_y = tile_y, + tile_w: @tile_w = tile_w, + tile_h: @tile_h = tile_h, + flip_horizontally: @flip_horizontally = flip_horizontally, + flip_vertically: @flip_vertically = flip_vertically, + angle_anchor_x: @angle_anchor_x = angle_anchor_x, + angle_anchor_y: @angle_anchor_y = angle_anchor_y} + end + + def primative_marker + :sprite + end + end +end diff --git a/components/02_label.rb b/components/02_label.rb new file mode 100644 index 0000000..13544b7 --- /dev/null +++ b/components/02_label.rb @@ -0,0 +1,27 @@ +class Components + # A dragonruby label wrapper + class Label < Helper::BaseComponent + + attr_accessor :x, :y, :text, :size_enum, :alignment_enum, + :a, :r, :g, :b, :font, :vertical_alignment_enum + + def set(x: @x, y: @y, text: @text, size_enum: @size_enum, alignment_enum: @alignment_enum, + a: @a, r: @r, g: @g, b: @b, font: @font, vertical_alignment_enum: @vertical_alignment_enum) + {x: @x = x, + y: @y = y, + text: @text = text, + size_enum: @size_enum = size_enum, + alignment_enum: @alignment_enum = alignment_enum, + r: @r = r, + g: @g = g, + b: @b = b, + a: @a = a, + font: @font = font, + vertical_alignment_enum: @vertical_alignment_enum = vertical_alignment_enum } + end + + def primative_marker + :label + end + end +end diff --git a/components/03_player_control.rb b/components/03_player_control.rb new file mode 100644 index 0000000..d5d8f7a --- /dev/null +++ b/components/03_player_control.rb @@ -0,0 +1,21 @@ +class Components + # Gives control(keyboard or otherwise) over an object + class PlayerControl < Helper::BaseComponent + attr_accessor :north, :south, :east, :west, :interact, :menu + + def initialize + @north = 'up' + @south = 'down' + @east = 'right' + @west = 'left' + @interact = 'space' + @menu = 'enter' + end + + def set(**opts) + opts.each do |key, value| + send "#{key}=", value + end + end + end +end diff --git a/components/04_map.rb b/components/04_map.rb new file mode 100644 index 0000000..7700e9f --- /dev/null +++ b/components/04_map.rb @@ -0,0 +1,21 @@ +class Components + # dragonruby label wrapper + class Map < Helper::BaseComponent + + attr_accessor :json_name, :json, :x, :y, :tilewidth, :tileheight, :a, :r, :g, :b + + def set(json_name: @json_name, x: @x, y: @y, tilewidth: @tilewidth, + tileheight: @tileheight, a: @a, r: @r, g: @g, b: @b) + { json_name: @json_name = json_name, + json: @json = Helper.get_json_tiles(json_name), + x: @x = x, + y: @y = y, + tilewidth: @tilewidth = tilewidth, + tileheight: @tileheight = tileheight, + r: @r = r, + g: @g = g, + b: @b = b, + a: @a = a } + end + end +end diff --git a/components/05_interactable.rb b/components/05_interactable.rb new file mode 100644 index 0000000..636a216 --- /dev/null +++ b/components/05_interactable.rb @@ -0,0 +1,16 @@ +class Components + # If an entity can be rendered on screen + class Interactable < Helper::BaseComponent + attr_accessor :z + + def initialize + @z = z + end + + def set(**opts) + opts.each do |key, value| + self.send "#{key}=", value + end + end + end +end diff --git a/components/06_collidable.rb b/components/06_collidable.rb new file mode 100644 index 0000000..76ce51e --- /dev/null +++ b/components/06_collidable.rb @@ -0,0 +1,22 @@ +class Components + # If an entity can be rendered on screen + class Collidable < Helper::BaseComponent + class <<self + def add(entity_id) + super(entity_id) + #add to grid? + end + end + attr_accessor :grid + + def initialize + @grid = [[]] + end + + def set(**opts) + opts.each do |key, value| + self.send "#{key}=", value + end + end + end +end diff --git a/components/07_battle.rb b/components/07_battle.rb new file mode 100644 index 0000000..b4ef622 --- /dev/null +++ b/components/07_battle.rb @@ -0,0 +1,4 @@ +class Components + class Battle < Helper::Level + end +end diff --git a/components/07_indoor.rb b/components/07_indoor.rb new file mode 100644 index 0000000..e409da8 --- /dev/null +++ b/components/07_indoor.rb @@ -0,0 +1,4 @@ +class Components + class Indoor < Helper::Level + end +end diff --git a/components/07_overworld.rb b/components/07_overworld.rb new file mode 100644 index 0000000..55ab38a --- /dev/null +++ b/components/07_overworld.rb @@ -0,0 +1,16 @@ +class Components + class Overworld < Helper::Level + attr_accessor :x, :y + + def initialize + @x = 0 + @y = 0 + end + + def set(**opts) + opts.each do |key, value| + self.send "#{key}=", value + end + end + end +end diff --git a/components/debug_singleton.rb b/components/debug_singleton.rb new file mode 100644 index 0000000..f298172 --- /dev/null +++ b/components/debug_singleton.rb @@ -0,0 +1,13 @@ +class Components + # If an entity can be rendered on screen + class DebugSingleton + class <<self + @data = false + attr_accessor :data + + def id + 0 + end + end + end +end diff --git a/entity_manager.rb b/entity_manager.rb new file mode 100644 index 0000000..7d0d1ff --- /dev/null +++ b/entity_manager.rb @@ -0,0 +1,63 @@ +class Entity + attr_accessor :id + + def initialize(*signature) + final_signature = 0 + signature.each do |sig| + final_signature += sig + end + @id = Entity.generate_new_id + self.class.all.push self + self.class.signatures.push final_signature + Components.entity_created(@id) + end + + class <<self + # All entities that exist + def all + @all ||= [] + end + + def id_queue + @id_queue ||= [] + end + + def generate_new_id + if id_queue.empty? + all.size + else + id_queue.shift + end + end + + # What components a given entity uses + def signatures + @signatures ||= [] + end + + def destroy_entity(entity_id) + if all[entity_id].nil? + puts 'Entity can not be destroyed, id out of bounds' + elsif entity_id < all.size - 1 + Components.constants.each do |constant| + unless (signatures[entity_id] & Components::const_get(constant).id).zero? + Components::const_get(constant).delete(entity_id) + end + end + all[entity_id] = nil + signatures[entity_id] = nil + id_queue.push entity_id + elsif entity_id == all.size - 1 + Components.constants.each do |constant| + unless (signatures[entity_id] & Components::const_get(constant).id).zero? + Components::const_get(constant).delete(entity_id) + end + end + all.pop + signatures.pop + else + puts 'Unknown error with destroy_entity, entity not destroyed' + end + end + end +end diff --git a/helpers/00_tileset.rb b/helpers/00_tileset.rb new file mode 100644 index 0000000..3890550 --- /dev/null +++ b/helpers/00_tileset.rb @@ -0,0 +1,49 @@ +class Helper + # Returns a loaded map and its dependecies(images,json) + # If any are missing then it will load them from files + + @json_data = {} + class <<self + attr_accessor :json_data + + def get_json_tiles(json_name, hitbox: false) + unless hitbox + return nil if json_name == 'hitbox' && !Components::DebugSingleton.data + end + + if self.json_data[json_name].nil? + self.json_data[json_name] = $gtk.parse_json_file "assets/json/#{json_name}.json" + raise Exception.new "#{json_name} is null and not loaded. Cannot get json tile" if self.json_data[json_name].nil? + + if self.json_data[json_name]['type'] == 'map' #json_name.split("_").first == 'map' + self.json_data[json_name]['tilesets'].each do |tileset| + tileset = Helper.get_json_tiles(tileset['source'].split('/').last.delete_suffix('.tsx')) + # download tileset here + # $gtk.args.gtk.http_get 'https://mysite.net/#{tileset['name']}.png' + end + end + end + self.json_data[json_name] + end + + def get_tile(json_name:, tile_index:) + if json_name == 'hitbox' && !Components::DebugSingleton.data + return tile_index - 1 if tile_index > 1 + return {} + end + + json_tiles = self.get_json_tiles(json_name) + raise Exception.new "Error, json file not a tileset" unless json_tiles['type'] == 'tileset' + return tile_index - json_tiles['tilecount'] if tile_index > json_tiles['tilecount'] + source_height_tiles = (tile_index.to_i / json_tiles['columns'].to_i).to_i# * json_tiles['tileheight'] + { w: json_tiles['tilewidth'], + h: json_tiles['tileheight'], + path: json_tiles['image'].split('mygame/').last.delete('\\'), + source_x: [((tile_index % json_tiles['columns']) - 1) * json_tiles['tilewidth'], 0].max, + # source_y gets special treatment + source_y: [json_tiles['imageheight'] - ((source_height_tiles + 1) * json_tiles['tileheight']), 0].max, + source_w: json_tiles['tilewidth'], + source_h: json_tiles['tileheight'] } + end + end +end diff --git a/helpers/01_component.rb b/helpers/01_component.rb new file mode 100644 index 0000000..ca4f86d --- /dev/null +++ b/helpers/01_component.rb @@ -0,0 +1,102 @@ +class Helper + class BaseComponent + class <<self + def id + @id ||= ID.create_new_id Helper::ComponentHelper.underscore(ancestors[0].name.split('::').last) + #@id ||= ID.send(Helper::ComponentHelper.underscore(ancestors[0].name.split('::').last)) + end + + def data + @data ||= {} + end + + def add(entity_id) + data[entity_id] = new + end + + def delete(entity_id) + data.delete entity_id + end + end + + def self.inherited(subclass) #TODO this should automagically create the ID(handle it with ID) + #@id = ID.send(subclass) + # maybe overwrite this? + end + + def set(**opts) + opts.each do |key, value| + send "#{key}=", value + end + end + + def create_data(name, default = nil) + #TODO fill this out + end + + def get #TODO maybe optimize removeing the @ symbol | doesnt get defaults + instance_variables.each_with_object({}) do |key, final| + final[key.to_s.delete_prefix('@').to_sym] = instance_variable_get(key) + end + end + + def dump #TODO already does what get does? + # should return a json or hash of all data in this component + end + end + + class Level < Helper::BaseComponent + class <<self + def data + @data ||= { add: [], remove: [], grid: Helper::Array2D.new } + end + + def add(entity_id) + super + data[:add].push entity_id + end + + def remove(entity_id) + data[:remove].push entity_id + super + end + end + end + + class Array2D < Array + def [](val) + unless val.nil? + return self[val] = [] if super.nil? + end + super + end + end + + + module ComponentHelper + class <<self + def up? char + char == char.upcase + end + + def down? char + char == char.downcase + end + + def underscore(input) + output = input[0].downcase + (1...(input.length - 1)).each do |iter| + if down?(input[iter]) && up?(input[iter + 1]) + output += "#{input[iter].downcase}_" + elsif up?(input[iter - 1]) && up?(input[iter]) && down?(input[iter + 1]) + output += "_#{input[iter].downcase}" + else + output += input[iter].downcase + end + end + output += input[-1].downcase unless input.length == 1 + output + end + end + end +end diff --git a/logos/felflame-logo-text.png b/logos/felflame-logo-text.png Binary files differnew file mode 100644 index 0000000..a274c1f --- /dev/null +++ b/logos/felflame-logo-text.png diff --git a/logos/felflame-logo-text.svg b/logos/felflame-logo-text.svg new file mode 100644 index 0000000..b4dac61 --- /dev/null +++ b/logos/felflame-logo-text.svg @@ -0,0 +1,172 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="408.86401mm" + height="179.90401mm" + viewBox="0 0 408.86401 179.90401" + version="1.1" + id="svg5" + inkscape:version="1.2-dev (25cba68356, 2021-05-16, custom)" + sodipodi:docname="felflame-logo-text.svg" + inkscape:export-filename="/home/tradam/Documents/felflame-logo-text.png" + inkscape:export-xdpi="67.093208" + inkscape:export-ydpi="67.093208" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview7" + pagecolor="#505050" + bordercolor="#eeeeee" + borderopacity="1" + inkscape:pageshadow="0" + inkscape:pageopacity="0" + inkscape:pagecheckerboard="0" + inkscape:document-units="mm" + showgrid="false" + showborder="true" + inkscape:object-paths="true" + inkscape:snap-smooth-nodes="false" + inkscape:zoom="0.5" + inkscape:cx="885" + inkscape:cy="100" + inkscape:window-width="1670" + inkscape:window-height="1029" + inkscape:window-x="670" + inkscape:window-y="1425" + inkscape:window-maximized="0" + inkscape:current-layer="g7470" + fit-margin-top="15" + fit-margin-left="15" + fit-margin-right="0" + fit-margin-bottom="15" + inkscape:snap-text-baseline="true" + inkscape:snap-global="true" /> + <defs + id="defs2" /> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-5.925697,16.359175)"> + <g + id="g5942" + transform="matrix(0.7150444,0,0,0.7150444,7.9079079,19.106173)" + style="fill:#005522" /> + <g + id="g7470" + transform="translate(45.740503,25.047998)"> + <ellipse + style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#1c241c;fill-opacity:0.7;fill-rule:evenodd;stroke:none;stroke-width:1.24602;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:7.2;stroke-dasharray:none;stroke-dashoffset:3.8766;stroke-opacity:1;paint-order:normal;stop-color:#000000;stop-opacity:1" + id="path6921" + ry="11.676038" + rx="54.259499" + cy="111.82079" + cx="29.444693" /> + <g + id="g5900" + transform="matrix(0.94670406,0,0,0.94670406,-1.3225283,-1.4073951)"> + <path + id="path846" + style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#00ff66;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4.79999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:7.2;stroke-dasharray:none;stroke-dashoffset:3.8766;stroke-opacity:1;paint-order:normal;stop-color:#000000;stop-opacity:1" + d="m 48.043994,-26.407173 c -35.640626,21.8403454 -59.4465,56.770237 -59.4465,101.334381 3e-5,44.723632 35.927436,44.724922 44.724917,44.724922 8.797481,0 44.72492,-0.0806 44.72492,-44.724922 0,-43.365499 -48.544546,-56.571942 -30.003337,-101.334381 z" + sodipodi:nodetypes="cczcc" /> + <path + id="path4245" + style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#00d455;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:18.1417;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:7.2;stroke-dasharray:none;stroke-dashoffset:3.8766;stroke-opacity:1;paint-order:normal;stop-color:#000000;stop-opacity:1" + d="M 181.58398,-99.806641 C 46.879256,-17.260453 -43.095703,114.75804 -43.095703,283.18945 c 1.13e-4,169.0342 135.78874,169.03907 169.039063,169.03907 3.33332,0 7.73446,-0.012 12.88867,-0.1875 -46.385395,-1.56991 -155.927631,-17.00003 -155.927733,-168.85157 0,-153.77238 79.303367,-290.0927365 194.863233,-373.226336 3.81607,-9.769753 0,0 3.81645,-9.769755 z" + transform="scale(0.26458333)" + sodipodi:nodetypes="ccscccc" /> + </g> + <g + id="g5904" + transform="matrix(0.94111257,0,0,0.94111257,3.0800803,7.5916104)"> + <path + id="path846-3" + style="font-variation-settings:normal;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3.61297;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:7.2;stroke-dasharray:none;stroke-dashoffset:3.8766;stroke-opacity:1;paint-order:normal;stop-color:#000000" + d="M 52.149066,-3.2818086 C 70.471317,22.295981 76.75521,53.486612 63.710707,84.389882 56.651708,101.11305 36.733365,109.54332 19.604384,102.31307 2.4754112,95.082796 -5.5490668,75.335735 1.6811862,58.206753 14.374829,28.134691 51.904029,33.186223 52.149066,-3.2818086 Z" + sodipodi:nodetypes="ccccc" /> + <path + id="path4266" + style="font-variation-settings:normal;vector-effect:none;fill:#1c241c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:13.6553;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:7.2;stroke-dasharray:none;stroke-dashoffset:3.8766;stroke-opacity:1;paint-order:normal;stop-color:#000000" + d="M 197.09961,-12.404297 C 196.17349,125.42763 54.329488,106.33595 6.3535156,219.99414 -20.973425,284.7336 9.3562784,359.36829 74.095703,386.69531 c 20.124509,8.49468 41.266977,11.26604 61.652347,9.15821 -11.99594,-1.24491 -23.99476,-4.23747 -35.65235,-9.15821 C 35.356265,359.36829 5.0265759,284.7336 32.353516,219.99414 75.872098,116.89584 196.62125,123.02178 219.375,22.177734 212.5918,10.387797 205.1587,-1.1538421 197.09961,-12.404297 Z" + transform="scale(0.26458333)" /> + </g> + <g + id="g10504" + transform="translate(-67.885213,43.329639)"> + <g + id="g10530"> + <text + xml:space="preserve" + style="font-size:70.5556px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;stroke-width:0.264583" + id="text16309"><textPath + xlink:href="#path8946" + startOffset="50%" + id="textPath16307"><tspan + id="tspan16305" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:70.5556px;font-family:Asul;-inkscape-font-specification:Asul;text-align:center;text-anchor:middle;stroke-width:0.264583"><tspan + style="fill:#00ff66;fill-opacity:1" + id="tspan16301">F</tspan>el<tspan + style="fill:#00ff66;fill-opacity:1" + id="tspan16303">F</tspan>lame</tspan></textPath></text> + <g + aria-label="FelFlame" + id="text2900" + style="font-size:70.5556px;line-height:1.25;letter-spacing:0px;stroke-width:0.264583"> + <path + d="m 163.3819,-24.820664 q -3.75224,0.869143 -7.23224,2.237747 -3.41434,1.342781 -5.72646,2.403719 l 2.96961,7.55094 q 3.66682,9.3237686 6.3184,12.98154649 l 0.18076,0.4596224 -8.86415,3.48606591 -0.18076,-0.4596224 q -0.55044,-4.48410465 -4.19144,-13.7422131 l -7.20454,-18.3192363 q -3.641,-9.258108 -6.29258,-12.915886 l -0.18076,-0.459622 26.51498,-10.655179 0.32101,5.635754 -0.45962,0.180759 q -4.54976,0.576265 -9.93391,2.693727 -5.38415,2.117462 -6.84269,2.842705 0.51204,2.073102 6.2705,16.715358 l 15.23541,-6.370816 -0.2419,5.553872 z" + style="fill:#00ff66" + id="path19193" /> + <path + d="m 197.32692,-10.137557 q -7.20751,1.7132745 -12.31804,-1.785819 -5.11053,-3.499094 -6.84012,-10.775244 -1.74591,-7.344794 1.47917,-13.913144 3.22508,-6.568349 9.95209,-8.167405 12.28709,-2.920725 15.89312,12.249363 l -1.95238,3.074871 -18.25902,4.340294 q 1.37062,5.766006 4.52708,8.061601 3.15645,2.295595 7.34367,1.300264 1.64743,-0.391605 4.43928,-2.07055 2.77554,-1.747587 4.78306,-3.67522 l 2.33611,2.200509 q -0.99419,1.614236 -4.81625,5.06102 -3.75341,3.430468 -6.56777,4.09946 z m -8.14663,-30.915762 q -2.883,0.68531 -4.15177,2.364814 -0.87997,2.094738 -0.98237,5.019941 -0.10239,2.925203 0.38711,4.984491 l 13.94127,-3.894107 q -2.39859,-10.090511 -9.19424,-8.475139 z" + style="font-size:70.5556px;font-family:Asul;-inkscape-font-specification:Asul;text-align:center;text-anchor:middle" + id="path19195" /> + <path + d="m 227.39129,-16.019152 -9.03046,1.136292 -0.1057,-0.840043 q 0.74964,-3.649924 -0.20168,-11.210313 l -3.67313,-29.191501 q -0.70468,-5.600288 -4.31241,-8.275257 l -0.10571,-0.840043 9.37909,-2.886846 0.50811,0.647185 q 0.0454,2.05653 1.48121,13.467117 l 3.37318,26.242541 q 0.95132,7.560389 2.5818,10.910825 z" + style="font-size:70.5556px;font-family:Asul;-inkscape-font-specification:Asul;text-align:center;text-anchor:middle" + id="path19197" /> + <path + d="m 260.90643,-39.860583 q -3.81425,-0.534992 -7.55358,-0.506101 -3.66878,0.02835 -6.20762,0.189076 l 0.0627,8.113652 q 0.0774,10.018597 1.24005,14.384192 l 0.004,0.493875 -9.52472,0.07359 -0.004,-0.493875 q 1.09506,-4.383038 1.0182,-14.331081 l -0.15208,-19.684426 q -0.0769,-9.948043 -1.23952,-14.313638 l -0.004,-0.493875 28.57253,-0.432428 -1.72241,5.375693 -0.49387,0.0038 q -4.4536,-1.094514 -10.23898,-1.049816 -5.78539,0.0447 -7.40703,0.198344 -0.26586,2.118785 -0.1443,17.852215 l 16.50679,-0.480323 -2.21846,5.097296 z" + style="fill:#00ff66" + id="path19199" /> + <path + d="m 283.31547,-15.436956 -9.06607,-0.804226 0.0748,-0.843356 q 1.50647,-3.407998 2.17977,-10.998198 l 2.59971,-29.306606 q 0.49874,-5.622371 -2.45981,-9.001453 l 0.0748,-0.843355 9.77793,-0.832611 0.35934,0.740202 q -0.39164,2.019406 -1.40783,13.474986 l -2.26758,26.361096 q -0.67331,7.5902 0.20973,11.210165 z" + style="font-size:70.5556px;font-family:Asul;-inkscape-font-specification:Asul;text-align:center;text-anchor:middle" + id="path19201" /> + <path + d="m 312.35784,-25.845813 q -2.70925,-1.465672 -6.47918,-2.016827 -3.70011,-0.540949 -5.54915,0.400922 -1.28195,1.452611 -1.68001,4.175335 -0.38785,2.652912 0.85369,4.403146 1.24154,1.750234 3.40576,2.066638 2.23403,0.326611 4.70118,-0.453587 2.47735,-0.850012 3.78829,-2.013162 z m -0.35273,10.216443 q -4.94246,4.0549 -10.3181,3.268993 -5.30582,-0.7757 -8.0408,-3.528633 -2.66516,-2.742727 -1.92008,-7.83911 0.75529,-5.166196 4.64239,-6.879691 3.95691,-1.703288 10.51937,-0.74387 l 6.11297,1.10762 0.58177,-3.979367 q 0.54095,-3.700114 -0.93738,-6.269329 -1.47834,-2.569215 -5.17845,-3.110164 -2.73293,-0.328243 -9.49217,3.960187 -1.64695,-2.879088 -1.88252,-7.120561 7.23814,-1.22358 13.03266,-0.376434 5.79451,0.847147 8.8463,4.359454 3.05179,3.512308 2.24547,9.027571 l -1.7147,11.728661 q -0.38949,3.151812 0.12003,6.007222 0.58954,2.795804 1.97234,4.06755 l 0.0376,0.718548 -7.73541,0.723046 q -0.58097,-2.366716 -0.89125,-5.121693 z" + style="font-size:70.5556px;font-family:Asul;-inkscape-font-specification:Asul;text-align:center;text-anchor:middle" + id="path19203" /> + <path + d="m 361.21774,-25.21257 -2.67715,12.486799 q -1.18328,5.5190273 -0.93238,9.3972464 l -0.10353,0.4829149 -8.5545,-1.8340723 0.10354,-0.4829148 q 1.81874,-3.434492 3.00201,-8.9535192 l 2.36654,-11.038055 q 0.84308,-3.932307 0.19283,-5.947854 -0.63546,-2.084535 -3.73992,-2.750126 -3.10445,-0.665591 -9.10186,1.72868 l -2.79548,13.038702 q -1.43472,6.691821 -0.41027,11.6739545 l -0.10354,0.4829149 -9.6583,-2.0707268 0.10354,-0.4829149 q 1.91234,-3.1979467 3.13998,-8.9239377 l 2.51446,-11.727933 q 0.63601,-2.966477 6.5e-4,-6.061215 -0.55157,-3.148934 -1.93122,-4.454955 l 0.1085,-0.842645 9.49593,-0.201014 0.26602,0.778623 q 0.005,2.670878 -0.28147,5.351579 2.94208,-1.60615 4.15439,-2.212141 1.29609,-0.660187 3.43482,-1.211872 2.20772,-0.536893 3.93242,-0.16712 7.10574,1.523463 7.85899,8.107108 8.42214,-4.616455 12.42343,-3.758582 4.82915,1.035363 6.8393,4.785649 2.01014,3.750286 0.73812,9.683241 l -2.12989,9.934249 q -1.40513,6.5538446 -0.34128,11.688745 l -0.10354,0.4829149 -9.72728,-2.08551772 0.10353,-0.48291489 q 1.91234,-3.19794669 3.13999,-8.92393749 l 2.26301,-10.5551398 q 1.73053,-8.071577 -3.30558,-9.151313 -4.20826,-0.902246 -9.87552,1.634968 -0.21701,1.68529 -0.40929,2.582132 z" + style="font-size:70.5556px;font-family:Asul;-inkscape-font-specification:Asul;text-align:center;text-anchor:middle" + id="path19205" /> + <path + d="m 400.76163,8.5291819 q -7.16225,-1.8935634 -10.01455,-7.3913425 -2.8523,-5.4977791 -0.9407,-12.7282454 1.92963,-7.298679 7.87433,-11.565395 5.94471,-4.266717 12.62948,-2.499391 12.20994,3.228075 8.22444,18.3029161 l -3.17307,1.7883745 -18.14438,-4.7970276 q -1.51485,5.7298042 0.18336,9.2439279 1.6982,3.5141237 5.85913,4.6141938 1.63709,0.4328145 4.89089,0.2713404 3.27183,-0.229686 5.95172,-0.9807711 l 1.02001,3.0429025 q -1.63867,0.9533823 -6.63543,2.1866286 -4.92854,1.2512802 -7.72523,0.5118888 z m 7.41904,-31.0983869 q -2.8649,-0.757425 -4.77642,0.123821 -1.76491,1.430866 -3.2366,3.960971 -1.47168,2.530104 -2.0127,4.576463 l 14.12772,3.151261 q 2.65099,-10.027156 -4.102,-11.812516 z" + style="font-size:70.5556px;font-family:Asul;-inkscape-font-specification:Asul;text-align:center;text-anchor:middle" + id="path19207" /> + </g> + <path + id="path838" + style="font-size:70.5556px;line-height:1.25;letter-spacing:0px;fill:#00d455;fill-opacity:1;stroke-width:0.264583" + d="m 159.49288,-52.253005 -26.51518,10.655162 0.18087,0.45992 c 1.76772,2.438519 3.86531,6.743935 6.29264,12.916008 l 7.20421,18.3192947 c 2.42734,6.1720721 3.82452,10.75239313 4.19148,13.7417959 l 0.18086,0.4599199 1.14567,-0.4506171 c -0.58682,-2.93751539 -1.89545,-6.988974 -3.93051,-12.1635995 l -7.20421,-18.3192939 c -2.42733,-6.172073 -4.52492,-10.477489 -6.29264,-12.916008 l -0.18087,-0.45992 25.0517,-10.067086 z m 4.59042,21.697899 -15.23529,6.370627 1.58754,1.587545 13.54801,-5.665288 z" + sodipodi:nodetypes="ccccccccccccccccccc" /> + <path + style="fill:none;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 125.46431,18.025536 c 0,0 52.56445,-35.227404 125.89097,-35.227404 73.32652,0 185.57913,35.227404 185.57913,35.227404" + id="path8946" + sodipodi:nodetypes="czc" /> + <path + id="path844" + style="font-size:70.5556px;line-height:1.25;letter-spacing:0px;fill:#00d455;fill-opacity:1;stroke-width:0.264583" + d="m 267.11835,-66.861416 -28.57241,0.432014 0.004,0.494027 c 0.77508,2.910397 1.18793,7.681826 1.2392,14.313856 l 0.15245,19.684068 c 0.0512,6.63203 -0.28851,11.4094 -1.01855,14.331426 l 0.004,0.493509 1.82417,-0.01395 c 0.56344,-2.963405 0.82296,-7.369797 0.77774,-13.223484 l -0.15245,-19.684068 c -0.0513,-6.63203 -0.46412,-11.403459 -1.2392,-14.313856 l -0.004,-0.494027 26.46608,-0.399975 z m -3.49953,21.899954 -16.50702,0.480076 c 0.004,0.548283 1.58267,1.01188 1.58757,1.587497 l 14.19913,-0.412893 z" + sodipodi:nodetypes="ccccccccccccccccccc" /> + </g> + </g> + </g> + </g> +</svg> diff --git a/logos/felflame-logo.png b/logos/felflame-logo.png Binary files differnew file mode 100644 index 0000000..a3d08a4 --- /dev/null +++ b/logos/felflame-logo.png diff --git a/logos/felflame-logo.svg b/logos/felflame-logo.svg new file mode 100644 index 0000000..8990883 --- /dev/null +++ b/logos/felflame-logo.svg @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="200mm" + height="200mm" + viewBox="0 0 200 200" + version="1.1" + id="svg5" + inkscape:version="1.2-dev (25cba68356, 2021-05-16, custom)" + sodipodi:docname="felflame-logo.svg" + inkscape:export-filename="/home/tradam/Documents/felflame-logo.png" + inkscape:export-xdpi="88.900002" + inkscape:export-ydpi="88.900002" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview7" + pagecolor="#505050" + bordercolor="#eeeeee" + borderopacity="1" + inkscape:pageshadow="0" + inkscape:pageopacity="0" + inkscape:pagecheckerboard="0" + inkscape:document-units="mm" + showgrid="false" + showborder="true" + inkscape:object-paths="true" + inkscape:snap-smooth-nodes="false" + inkscape:zoom="1" + inkscape:cx="245.5" + inkscape:cy="317.5" + inkscape:window-width="1682" + inkscape:window-height="1078" + inkscape:window-x="338" + inkscape:window-y="1518" + inkscape:window-maximized="0" + inkscape:current-layer="g7470" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" /> + <defs + id="defs2" /> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(24.814804,26.407173)"> + <g + id="g5942" + transform="matrix(0.7150444,0,0,0.7150444,7.9079079,19.106173)" + style="fill:#005522" /> + <g + id="g7470" + transform="translate(45.740503,25.047998)"> + <ellipse + style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#1c241c;fill-opacity:0.69999999;fill-rule:evenodd;stroke:none;stroke-width:1.24602;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:7.2;stroke-dasharray:none;stroke-dashoffset:3.8766;stroke-opacity:1;paint-order:normal;stop-color:#000000;stop-opacity:1" + id="path6921" + ry="11.676038" + rx="54.259499" + cy="111.82079" + cx="29.444693" /> + <g + id="g5900" + transform="matrix(0.94670406,0,0,0.94670406,-1.3225283,-1.4073951)"> + <path + id="path846" + style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#00ff66;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4.79999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:7.2;stroke-dasharray:none;stroke-dashoffset:3.8766;stroke-opacity:1;paint-order:normal;stop-color:#000000;stop-opacity:1" + d="m 48.043994,-26.407173 c -35.640626,21.8403454 -59.4465,56.770237 -59.4465,101.334381 3e-5,44.723632 35.927436,44.724922 44.724917,44.724922 8.797481,0 44.72492,-0.0806 44.72492,-44.724922 0,-43.365499 -48.544546,-56.571942 -30.003337,-101.334381 z" + sodipodi:nodetypes="cczcc" /> + <path + id="path4245" + style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#00d455;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:18.1417;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:7.2;stroke-dasharray:none;stroke-dashoffset:3.8766;stroke-opacity:1;paint-order:normal;stop-color:#000000;stop-opacity:1" + d="M 181.58398,-99.806641 C 46.879256,-17.260453 -43.095703,114.75804 -43.095703,283.18945 c 1.13e-4,169.0342 135.78874,169.03907 169.039063,169.03907 3.33332,0 7.73446,-0.012 12.88867,-0.1875 -46.385395,-1.56991 -155.927631,-17.00003 -155.927733,-168.85157 0,-153.77238 79.303367,-290.0927365 194.863233,-373.226336 3.81607,-9.769753 0,0 3.81645,-9.769755 z" + transform="scale(0.26458333)" + sodipodi:nodetypes="ccscccc" /> + </g> + <g + id="g5904" + transform="matrix(0.94111257,0,0,0.94111257,3.0800803,7.5916104)"> + <path + id="path846-3" + style="font-variation-settings:normal;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3.61297;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:7.2;stroke-dasharray:none;stroke-dashoffset:3.8766;stroke-opacity:1;paint-order:normal;stop-color:#000000" + d="M 52.149066,-3.2818086 C 70.471317,22.295981 76.75521,53.486612 63.710707,84.389882 56.651708,101.11305 36.733365,109.54332 19.604384,102.31307 2.4754112,95.082796 -5.5490668,75.335735 1.6811862,58.206753 14.374829,28.134691 51.904029,33.186223 52.149066,-3.2818086 Z" + sodipodi:nodetypes="ccccc" /> + <path + id="path4266" + style="font-variation-settings:normal;vector-effect:none;fill:#1c241c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:13.6553;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:7.2;stroke-dasharray:none;stroke-dashoffset:3.8766;stroke-opacity:1;paint-order:normal;stop-color:#000000" + d="M 197.09961,-12.404297 C 196.17349,125.42763 54.329488,106.33595 6.3535156,219.99414 -20.973425,284.7336 9.3562784,359.36829 74.095703,386.69531 c 20.124509,8.49468 41.266977,11.26604 61.652347,9.15821 -11.99594,-1.24491 -23.99476,-4.23747 -35.65235,-9.15821 C 35.356265,359.36829 5.0265759,284.7336 32.353516,219.99414 75.872098,116.89584 196.62125,123.02178 219.375,22.177734 212.5918,10.387797 205.1587,-1.1538421 197.09961,-12.404297 Z" + transform="scale(0.26458333)" /> + </g> + </g> + </g> +</svg> diff --git a/signatures.rb b/signatures.rb new file mode 100644 index 0000000..c11c048 --- /dev/null +++ b/signatures.rb @@ -0,0 +1,54 @@ +class ID + class <<self + @next_id = 0b0_010_000_000_000 + + def create_new_id(name) + temp = @next_id + @next_id *= 2 + define_singleton_method(name) do + temp + end + send(name) + end + + def renderable + 0b0_001 + end + + def sprite + 0b0_010 + end + + def label + 0b0_100 + end + + def player_control + 0b0_001_000 + end + + def map + 0b0_010_000 + end + + def interactable + 0b0_100_000 + end + + def collidable + 0b0_001_000_000 + end + + def overworld + 0b0_010_000_000 + end + + def indoor + 0b0_100_000_000 + end + + def battle + 0b0_001_000_000_000 + end + end +end diff --git a/system_manager.rb b/system_manager.rb new file mode 100644 index 0000000..e63375c --- /dev/null +++ b/system_manager.rb @@ -0,0 +1,5 @@ +#require 'app/ECS/systems/00_movement.rb' +#require 'app/ECS/systems/01_flying.rb' + +class Systems +end diff --git a/systems/00_update_levels.rb b/systems/00_update_levels.rb new file mode 100644 index 0000000..6f3a056 --- /dev/null +++ b/systems/00_update_levels.rb @@ -0,0 +1,34 @@ +class Systems + class UpdateLevels + @co = Components::Overworld + def self.run + @co.data[:add].each do |id| + @co.data[:add].delete(id) + if !(Components::Sprite.id & Entity.signatures[id]).zero? + @co.data[:grid][@co.data[id].x][@co.data[id].y] = {} if @co.data[:grid][@co.data[id].x][@co.data[id].y].nil? + #@co.data[:grid][@co.data[id].x][@co.data[id].y].merge!({ player: true }) + puts @co.data[:grid][@co.data[id].x][@co.data[id].y].inspect + elsif !(Components::Map.id & Entity.signatures[id]).zero? + if Components::Map.data[id].json['tilesets'].last['source'].split('/').last.delete('\\').delete_suffix('.tsx') == 'hitbox' + Components::Map.data[id].json['layers'].each do |layer| + layer['chunks'].each do |chunk| + chunk['data'].each_slice(chunk['width']).with_index do |row, row_index| + row.each_with_index do |tile, column_index| + if tile.to_i == Components::Map.data[id].json['tilesets'].last['firstgid'].to_i + @co.data[:grid][column_index][row_index] = {} if @co.data[:grid][column_index][row_index].nil? + @co.data[:grid][column_index][row_index].merge!({ hitbox: true }) + end + end + end + end + end + end + end + puts @co.data[:grid] + end + Components::Overworld.data[:remove].each do |id| + Components::Overworld.data[:remove].delete(id) + end + end + end +end diff --git a/systems/10_player.rb b/systems/10_player.rb new file mode 100644 index 0000000..307731a --- /dev/null +++ b/systems/10_player.rb @@ -0,0 +1,41 @@ +class Systems + class Player + @co = Components::Overworld + def self.run + Components::PlayerControl.data.each do |id, data| + puts6 "Right: #{@co.data[:grid][@co.data[id].x+1][@co.data[id].y]}" + puts6 "Left #{@co.data[:grid][@co.data[id].x-1][@co.data[id].y]}" + puts6 "Down #{@co.data[:grid][@co.data[id].x][@co.data[id].y+1]}" + puts6 "Up #{@co.data[:grid][@co.data[id].x][@co.data[id].y-1]}" + #puts6 @co.data[:grid][@co.data[id].x + 1][@co.data[id].y][:hitbox].nil? + + if !(Components::Sprite.id & Entity.signatures[id]).zero? + if $gtk.args.inputs.keyboard.key_down.send(data.north) &&\ + (@co.data[:grid][@co.data[id].x][@co.data[id].y - 1].nil? ||\ + @co.data[:grid][@co.data[id].x][@co.data[id].y - 1][:hitbox].nil?) + Components::Sprite.data[id].y -= 64 + @co.data[id].y -= 1 + elsif $gtk.args.inputs.keyboard.key_down.send(data.south) &&\ + (@co.data[:grid][@co.data[id].x][@co.data[id].y + 1].nil? ||\ + @co.data[:grid][@co.data[id].x][@co.data[id].y + 1][:hitbox].nil?) + Components::Sprite.data[id].y += 64 + @co.data[id].y += 1 + elsif $gtk.args.inputs.keyboard.key_down.send(data.east) &&\ + (@co.data[:grid][@co.data[id].x + 1][@co.data[id].y].nil? ||\ + @co.data[:grid][@co.data[id].x + 1][@co.data[id].y][:hitbox].nil?) + Components::Sprite.data[id].x += 64 + @co.data[id].x += 1 + elsif $gtk.args.inputs.keyboard.key_down.send(data.west) &&\ + (@co.data[:grid][@co.data[id].x - 1][@co.data[id].y].nil? || @co.data[:grid][@co.data[id].x - 1][@co.data[id].y][:hitbox].nil?) + Components::Sprite.data[id].x -= 64 + @co.data[id].x -= 1 + end + #Components::Sprite.data[id].y -= 64 if $gtk.args.inputs.keyboard.key_down.send(data.north) + #Components::Sprite.data[id].y += 64 if $gtk.args.inputs.keyboard.key_down.send(data.south) + #Components::Sprite.data[id].x += 64 if $gtk.args.inputs.keyboard.key_down.send(data.east) + #Components::Sprite.data[id].x -= 64 if $gtk.args.inputs.keyboard.key_down.send(data.west) + end + end + end + end +end diff --git a/systems/99_render.rb b/systems/99_render.rb new file mode 100644 index 0000000..c71c6fc --- /dev/null +++ b/systems/99_render.rb @@ -0,0 +1,37 @@ +class Systems + class Render + def self.run + Components::Renderable.data.sort_by { |v| v[1].z }.each do |key, data| + if !(Components::Sprite.id & Entity.signatures[key]).zero? + $gtk.args.outputs.sprites << Components::Sprite.data[key].set + elsif !(Components::Label.id & Entity.signatures[key]).zero? + $gtk.args.outputs.labels << Components::Label.data[key].set + elsif !(Components::Map.id & Entity.signatures[key]).zero? + Components::Map.data[key].json['layers'].each do |layer| + layer['chunks'].each do |chunk| + chunk['data'].each_slice(chunk['width']).with_index do |row, row_index| + row.each_with_index do |tile, column_index| + unless tile.zero? + iter = 0 + loop do + tile = Helper.get_tile(json_name: Components::Map.data[key].json['tilesets'][iter]['source'].split('/').last.delete('\\').delete_suffix('.tsx'), tile_index: tile) + break if tile.is_a?(Hash) + raise Exception.new "#{Components::Map.data[key].json['json_name']} not valid map, exceeded tile range" if (iter += 1) >= Components::Map.data[key].json['tilesets'].count + end + unless tile.empty? + tile[:x] = Components::Map.data[key].x + (Components::Map.data[key].tilewidth * column_index) + chunk['x'] + tile[:y] = Components::Map.data[key].y + (Components::Map.data[key].tileheight * row_index) + chunk['y'] + tile[:w] = Components::Map.data[key].tilewidth + tile[:h] = Components::Map.data[key].tileheight + $gtk.args.outputs.sprites << tile + end + end + end + end + end + end + end + end + end + end +end @@ -0,0 +1,18 @@ +require_relative './entity_manager.rb' +require_relative './component_manager.rb' +require_relative './system_manager.rb' + +move = '0001'.to_i(2) +base = '0010'.to_i(2) +both = '0011'.to_i(2) +Entity.new(move) +Entity.new(base) +Entity.new(both) + +3.times do + Systems.constants.each do |constant| + puts "|----#{constant.to_s.upcase}----|" + Systems::const_get(constant).run + end + #ECS::Entity.destroy_entity(ECS::Entity.all.last.id) unless ECS::Entity.all.empty? +end |
