ascension 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,209 @@
1
+ require 'mharris_ext'
2
+ require 'rchoice'
3
+ require 'mongo_persist'
4
+
5
+ def playing_on_command_line?
6
+ $playing_on_command_line = true if $playing_on_command_line.nil?
7
+ $playing_on_command_line
8
+ end
9
+
10
+ %w(to_json).each do |f|
11
+ load File.dirname(__FILE__) + "/ascension/#{f}.rb"
12
+ end
13
+
14
+ def db
15
+ Mongo::Connection.new.db('ascension')
16
+ end
17
+
18
+ class Array
19
+ def sum
20
+ inject { |s,i| s + i }
21
+ end
22
+ end
23
+
24
+ class Object
25
+ def klass
26
+ self.class
27
+ end
28
+ end
29
+
30
+ class Events
31
+ def fire(event)
32
+
33
+ end
34
+ end
35
+
36
+ class Game
37
+ setup_mongo_persist :sides, :center, :void, :honor, :deck, :turn_manager
38
+ def addl_json_attributes
39
+ %w(mongo_id engageable_cards constant_cards current_side_index last_update_dt)
40
+ end
41
+
42
+ fattr(:sides) { [] }
43
+ fattr(:center) { Center.new(:game => self) }
44
+ fattr(:void) { Void.new }
45
+ fattr(:honor) { 60 }
46
+ fattr(:deck) { CenterDeck.starting }
47
+ fattr(:center_wc) { CenterWithConstants.new(:game => self) }
48
+ fattr(:turn_manager) { TurnManager.new(:game => self) }
49
+
50
+ def engageable_cards
51
+ turn_manager.current_side.engageable_cards
52
+ end
53
+ def constant_cards
54
+ center_wc.constant_cards
55
+ end
56
+ def current_side_index
57
+ turn_manager.current_side_index
58
+ end
59
+ def last_update_dt
60
+ Time.now
61
+ end
62
+
63
+ def card_places
64
+ places = [deck,center,void]
65
+ sides.each do |side|
66
+ places += [side.hand,side.discard,side.deck,side.played]
67
+ end
68
+ places
69
+ end
70
+
71
+ def after_mongo_load
72
+ center.game = self
73
+ turn_manager.game = self
74
+
75
+ sides.each do |s|
76
+ s.game = self
77
+ %w(discard deck hand played constructs).each do |m|
78
+ s.send(m).side = s
79
+ end
80
+ s.choices.each do |c|
81
+ c.side = s
82
+ end
83
+ end
84
+
85
+ card_places.each do |cards|
86
+ cards.hydrate!
87
+ end
88
+ end
89
+
90
+ def find_card(card_id)
91
+ raise "blank card id" if card_id.blank?
92
+ card_places.each do |cards|
93
+ res = cards.find { |x| x.card_id.to_s == card_id.to_s }
94
+ return res if res
95
+ end
96
+ raise "no card #{card_id}"
97
+ end
98
+
99
+ class << self
100
+ def reset!
101
+ Game.collection.remove
102
+ game = Game.new
103
+ side = Side.new(:game => game)
104
+ game.sides << side
105
+ game.sides << Side.new(:game => game)
106
+
107
+ game.deck = CenterDeck.starting
108
+ #game.deck << Parse.get("Mephit")
109
+ game.center.fill!
110
+ #side.deck << game.deck.get_one('Temple Librarian')
111
+ #side.deck[-1] = Card::Hero.arha
112
+
113
+ #side.deck << Parse.get("Shade ot Black Watch")
114
+ #side.deck << Parse.get("Seer of the Forked Path")
115
+ #side.deck << Parse.get("Demon Slayer")
116
+ game.sides.each do |s|
117
+ s.draw_hand!
118
+ end
119
+ #side.hand << game.deck.get_one('Void Thirster')
120
+ #side.deck << game.deck.get_one('Void Initiate')
121
+
122
+ game.mongo.save!
123
+ game
124
+ end
125
+ end
126
+ end
127
+
128
+ class Side
129
+ include FromHash
130
+ setup_mongo_persist :discard, :deck, :hand, :played, :constructs, :honor, :side_id, :choices
131
+ attr_accessor :game
132
+ fattr(:discard) { Discard.new(:side => self) }
133
+ fattr(:deck) { PlayerDeck.starting(:side => self) }
134
+ fattr(:hand) { Hand.new(:side => self) }
135
+ fattr(:played) { Played.new(:side => self) }
136
+ fattr(:constructs) { Constructs.new(:side => self) }
137
+ fattr(:honor) { 0 }
138
+ fattr(:side_id) { rand(100000000000000) }
139
+ fattr(:choices) { [] }
140
+
141
+ def draw_hand!
142
+ 5.times { draw_one! }
143
+ end
144
+ def draw_one!
145
+ hand << deck.draw_one
146
+ end
147
+ def play(card)
148
+ played << card
149
+ hand.remove(card)
150
+ end
151
+ def acquire_free(card)
152
+ discard << card
153
+ game.center_wc.remove(card)
154
+ fire_event Event::CardPurchased.new(:card => card)
155
+ end
156
+ def purchase(card)
157
+ acquire_free(card)
158
+ #card.apply_abilities(self)
159
+ played.pool.runes -= card.rune_cost
160
+ end
161
+ def defeat(monster)
162
+ game.void << monster
163
+ game.center.remove(monster) unless monster.name =~ /cultist/i && !game.center.include?(monster)
164
+
165
+ fire_event Event::MonsterKilled.new(:card => monster, :center => true)
166
+
167
+ monster.apply_abilities(self)
168
+ played.pool.power -= monster.power_cost
169
+ end
170
+ def engage(card)
171
+ if card.monster?
172
+ defeat(card)
173
+ else
174
+ purchase(card)
175
+ end
176
+ end
177
+ def engageable_cards
178
+ game.center_wc.engageable_cards(self)
179
+ end
180
+ def end_turn!
181
+ played.discard!
182
+ hand.discard!
183
+ constructs.apply!
184
+ draw_hand!
185
+
186
+ end
187
+ def total_cards
188
+ [hand,played,deck,discard].map { |x| x.size }.sum
189
+ end
190
+
191
+ fattr(:events) { Event::Events.new(:side => self) }
192
+ def fire_event(event)
193
+ events << event
194
+ end
195
+ def other_side
196
+ game.sides.reject { |x| x == self }.first
197
+ end
198
+ def print_status!
199
+ puts "Center " + game.center.to_s_cards
200
+ puts "Hand " + hand.to_s_cards
201
+ puts "Played " + played.to_s_cards
202
+ puts "Constructs " + constructs.to_s_cards unless constructs.empty?
203
+ puts "Pool " + played.pool.to_s
204
+ end
205
+ end
206
+
207
+ %w(card cards ability pool events parse turn_manager setup_rchoice).each do |f|
208
+ load File.dirname(__FILE__) + "/ascension/#{f}.rb"
209
+ end
@@ -0,0 +1,49 @@
1
+ "Realm Short","Card Type","Name","count","rune_cost","honor","runes","honor","power","+C","draw","banish_center","banish_hand","banish_discard","banish_hand_discard","discard_from_hand","special_ability","triggerable_ability","undefined"
2
+ "V","H","Void Initiate",3,1,1,1,,,"(-1)",,,,,"o1",,,,
3
+ "V","H","Spike Vixen",2,2,1,,,1,1,1,,,,,,,,
4
+ "V","H","Shade ot Black Watch",3,3,1,,,2,"(-1)",,,,,"o1",,,,
5
+ "V","C","Shadow Star",2,3,2,,,1,,,,,,,,,,
6
+ "V","H","Arbiter ot Precipice",2,4,1,,,,"2-1",2,,1,,,,,,
7
+ "V","H","Demon Slayer",2,4,2,,,3,,,,,,,,,,
8
+ "V","C","Void Thirster",2,5,3,,"1 on first_center_monster_killed","1",,,,,,,,,,
9
+ "V","H","Emeri One with the Void",1,6,3,,,4,,,,,,,,,,
10
+ "V","C","Muramasa",1,7,4,,,3,,,,,,,,,,
11
+ "E","H","Arha Initiate",3,1,1,,,,1,1,,,,,,,,
12
+ "E","H","Temple Librarian",3,2,1,,,,"(2)",2,,,,,1,,,
13
+ "E","H","Seer ot Forked Path",3,2,1,,,,1,1,"o1",,,,,,,
14
+ "E","H","Twofold Askara",1,4,2,,,,,,,,,,,"copy_hero",,
15
+ "E","H","Arha Templar",2,4,3,,,,,,,,,,,"kill_monster_4",,
16
+ "E","H","Ascetic ot Lidless Eye",2,5,2,,,,2,2,,,,,,,,
17
+ "E","C","Tablet of Times Dawn",1,5,2,,,,,,,,,,,,,
18
+ "E","C","The All Seeing Eye",1,6,2,,,,1,,,,,,,,"draw_1",
19
+ "E","H","Oziah the Peerless",1,6,3,,,,,,,,,,,"kill_monster_6",,
20
+ "E","H","Master Dhartha",1,7,3,,,,3,3,,,,,,,,
21
+ "L","H","Lifeblood Initiate",3,1,1,1,1,,,,,,,,,,,
22
+ "L","H","Wolf Shaman",3,3,1,1,,,1,1,,,,,,,,
23
+ "L","H","Runic Lycanthrope",2,3,1,2,,"2 if lifebound_hero_played",,,,,,,,,,
24
+ "L","C","Yggdrasil Staff",2,4,2,,,"1",,,,,,,,,"4_rune_to_3_honor",
25
+ "L","H","Druids ot Stone Circle",2,4,3,,,,,,,,,,,"acquire_hero_3",,
26
+ "L","C","Snapdragon",2,5,2,1,"1 on first_lifebound_hero_played",,,,,,,,,,,
27
+ "L","H","Flytrap Witch",2,5,2,,2,,1,1,,,,,,,,
28
+ "L","H","Landtalker",1,6,3,3,,,,,,,,,,,,
29
+ "L","H","Cetra Weaver ot Stars",1,7,4,,,,,,,,,,,"acquire_hero_10",,
30
+ "M","H","Mechana Initiate",3,1,1,,,,,,,,,,,"power_or_rune_1",,
31
+ "M","H","Kor the Ferromancer",1,3,2,,,2,"(1)","1 if 2_or_more_constructs",,,,,,,,
32
+ "M","C","Burrower Mk II",2,3,3,,,,"(1)","1 on mechana_construct_played",,,,,,,,
33
+ "M","H","Avatar Golem",2,4,2,,"1 foreach type_of_construct","2",,,,,,,,,,
34
+ "M","H","Reactor Monk",2,4,2,"2, 1 for construct",,,,,,,,,,,,
35
+ "M","C","Rocket Courier X-99",2,4,4,,,,,,,,,,,,,"something"
36
+ "M","C","Watchmaker Altar",2,5,5,"1 for mechana",,,,,,,,,,,,
37
+ "M","C","The Grand Deisgn",2,6,6,"2 for mechana",,,,,,,,,,,,
38
+ "M","C","Hedron Link Device",1,7,7,,,,,,,,,,,,,"all_mechana"
39
+ "M","C","Hedron Cannon",1,8,8,,,,,,,,,,,,"power_for_mechana",
40
+ "S","M","Samael's Trickster",4,"3P","-",1,1,,,,,,,,,,,
41
+ "S","M","Tormented Soul",3,"3P","-",,1,,1,,,,,,,,,
42
+ "S","M","Mephit",3,"3P","-",,2,,,,"o1",,,,,,,
43
+ "S","M","Corrosive Widow",4,"4P","-",,3,,,,,,,,,"discard_construct",,
44
+ "S","M","Mistake of Creation",4,"4P","-",,4,,"(-1)",,"o1",,"o1",,,,,
45
+ "S","M","Wind Tyrant",3,"5P","-",3,3,,,,,,,,,,,
46
+ "S","M","Sea Tyrant",3,"5P","-",,5,,,,,,,,,"discard_all_but_one_construct",,
47
+ "S","M","Earth Tyrant",2,"6P","-",,5,,2,2,,,,,,,,
48
+ "S","M","Xeron Duke of Lies",1,"6P","-",,3,,,,,,,,,"take_opponents_card",,
49
+ "S","M","Avatar ot Fallen",1,"7P","-",,4,,,,,,,,,"acquire_center",,
@@ -0,0 +1,222 @@
1
+ str = <<EOF
2
+ Card
3
+ Ability
4
+ CardChoice
5
+ RChoice
6
+ EOF
7
+
8
+ module Ability
9
+ class ChoiceInstance
10
+ include FromHash
11
+ attr_accessor :choice, :side
12
+
13
+ setup_mongo_persist :choice, :choice_id
14
+ def addl_json_attributes
15
+ %w(choosable_cards name)
16
+ end
17
+ def name
18
+ choice.class.to_s
19
+ end
20
+
21
+ fattr(:choice_id) { rand(100000000000000) }
22
+
23
+ fattr(:choosable_cards) do
24
+ res = choice.choosable_cards(side)
25
+ res = res.cards if res.respond_to?(:cards)
26
+ res
27
+ end
28
+ def save!
29
+ side.choices << self
30
+ end
31
+
32
+ def execute!(chosen_card)
33
+ choice.action(chosen_card,side)
34
+ delete!
35
+ end
36
+
37
+ def delete!
38
+ side.choices -= [self]
39
+ end
40
+ end
41
+
42
+
43
+ class Base
44
+ fattr(:optional) { false }
45
+ include FromHash
46
+ attr_accessor :parent_card
47
+ setup_mongo_persist :parent_card
48
+ def call_until_nil(side)
49
+ loop do
50
+ choice = call(side)
51
+ yield if block_given?
52
+ return unless choice.choice.chosen_option && choosable_cards(side).size > 0
53
+ end
54
+ end
55
+ def choice_instance(side)
56
+ ChoiceInstance.new(:choice => self, :side => side)
57
+ end
58
+ end
59
+
60
+ class BaseChoice < Base
61
+ def side_for_card_choice(side)
62
+ side
63
+ end
64
+ def card_choice(side)
65
+ CardChoice.new(:ability => self, :side => side_for_card_choice(side))
66
+ end
67
+ def call(side)
68
+ card_choice(side).tap { |x| x.run! }
69
+ end
70
+ end
71
+
72
+ class CardChoice
73
+ include FromHash
74
+ attr_accessor :ability, :side
75
+ fattr(:choosable_cards) do
76
+ ability.choosable_cards(side)
77
+ end
78
+ class << self
79
+ fattr(:chooser) {}
80
+ end
81
+ fattr(:choice) do
82
+ res = RChoice::Choice.new(:optional => ability.optional, :name => ability.klass.to_s, :parent_obj => self)
83
+ choosable_cards.each do |card|
84
+ res.add_option card
85
+ end
86
+ res.action_blk = lambda { |card| ability.action(card,side) }
87
+ res.chooser = klass.chooser
88
+ res
89
+ end
90
+ def run!
91
+ choice.execute!
92
+ end
93
+ end
94
+
95
+ class Banish < BaseChoice
96
+ end
97
+
98
+ class BanishCenter < Banish
99
+ def action(card,side)
100
+ side.game.center.banish(card)
101
+ end
102
+ def choosable_cards(side)
103
+ side.game.center
104
+ end
105
+ end
106
+
107
+ class BanishHandDiscard < Banish
108
+ def action(card,side)
109
+ if side.hand.include?(card)
110
+ side.hand.banish(card)
111
+ else
112
+ side.discard.banish(card)
113
+ end
114
+ end
115
+ def choosable_cards(side)
116
+ side.hand.cards + side.discard.cards
117
+ end
118
+ end
119
+
120
+ class EarnHonor < Base
121
+ attr_accessor :honor
122
+ def call(side)
123
+ side.game.honor -= honor
124
+ side.honor += honor
125
+ end
126
+ end
127
+
128
+ class Draw < Base
129
+ def call(side)
130
+ side.draw_one!
131
+ end
132
+ end
133
+
134
+ class DoCenterAction < BaseChoice
135
+ def optional; true; end
136
+ def choosable_cards(side)
137
+ side.game.center_wc.select { |x| can?(x,side) }
138
+ end
139
+ def can?(card,side)
140
+ if card.monster?
141
+ raise card.name unless card.power_cost
142
+ side.played.pool.power >= card.power_cost
143
+ else
144
+ side.played.pool.can_purchase?(card)
145
+ end
146
+ end
147
+ def action(card,side)
148
+ if card.monster?
149
+ side.defeat(card)
150
+ else
151
+ side.purchase(card)
152
+ end
153
+ end
154
+ end
155
+
156
+ class KillMonster < BaseChoice
157
+ attr_accessor :max_power
158
+ def choosable_cards(side)
159
+ side.game.center_wc.select { |x| x.monster? && x.power_cost <= (max_power||99) }
160
+ end
161
+ def action(card,side)
162
+ side.defeat(card)
163
+ end
164
+ end
165
+
166
+ class AcquireHero < BaseChoice
167
+ attr_accessor :max_rune_cost
168
+ def choosable_cards(side)
169
+ #side.game.center_wc.select { |x| x.hero? }.each { |x| puts [x.name,x.rune_cost].inspect }
170
+ side.game.center_wc.select { |x| x.hero? && x.rune_cost <= (max_rune_cost||99) }
171
+ end
172
+ def action(card,side)
173
+ side.purchase(card)
174
+ end
175
+ end
176
+
177
+ class CopyHero < BaseChoice
178
+ def choosable_cards(side)
179
+ side.played
180
+ end
181
+ def action(card,side)
182
+ side.played.apply(card)
183
+ end
184
+ end
185
+
186
+ class OtherSideChoice < BaseChoice
187
+ def side_for_card_choice(side)
188
+ side.other_side
189
+ end
190
+ end
191
+
192
+ class DiscardConstruct < OtherSideChoice
193
+ def choosable_cards(side)
194
+ side.constructs
195
+ end
196
+ def action(card,side)
197
+ side.constructs.discard(card)
198
+ end
199
+ end
200
+
201
+ class KeepOneConstruct < OtherSideChoice
202
+ def choosable_cards(side)
203
+ side.constructs
204
+ end
205
+ def action(card,side)
206
+ other = side.constructs.reject { |x| x == card }
207
+ other.each do |o|
208
+ side.constructs.discard(o)
209
+ end
210
+ end
211
+ end
212
+
213
+ class TakeOpponentsCard < BaseChoice
214
+ def choosable_cards(side)
215
+ side.other_side.hand
216
+ end
217
+ def action(card,side)
218
+ side.other_side.hand.remove(card)
219
+ side.hand << card
220
+ end
221
+ end
222
+ end