ifmapper 0.5

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.
Files changed (87) hide show
  1. data/HISTORY.txt +2 -0
  2. data/IFMapper.gemspec +21 -0
  3. data/IFMapper.rb +27 -0
  4. data/icons/copy.png +0 -0
  5. data/icons/cut.png +0 -0
  6. data/icons/filenew.png +0 -0
  7. data/icons/fileopen.png +0 -0
  8. data/icons/filesave.png +0 -0
  9. data/icons/filesaveas.png +0 -0
  10. data/icons/help.png +0 -0
  11. data/icons/kill.png +0 -0
  12. data/icons/nextpage.png +0 -0
  13. data/icons/paste.png +0 -0
  14. data/icons/prevpage.png +0 -0
  15. data/icons/printicon.png +0 -0
  16. data/icons/redo.png +0 -0
  17. data/icons/saveas.png +0 -0
  18. data/icons/undo.png +0 -0
  19. data/icons/winapp.png +0 -0
  20. data/icons/zoom.png +0 -0
  21. data/lib/IFMapper/Connection.rb +63 -0
  22. data/lib/IFMapper/FXAboutDialogBox.rb +32 -0
  23. data/lib/IFMapper/FXConnection.rb +283 -0
  24. data/lib/IFMapper/FXConnectionDialogBox.rb +126 -0
  25. data/lib/IFMapper/FXMap.rb +1614 -0
  26. data/lib/IFMapper/FXMapDialogBox.rb +51 -0
  27. data/lib/IFMapper/FXMapFileDialog.rb +29 -0
  28. data/lib/IFMapper/FXMapperSettings.rb +45 -0
  29. data/lib/IFMapper/FXMapperWindow.rb +1051 -0
  30. data/lib/IFMapper/FXPage.rb +24 -0
  31. data/lib/IFMapper/FXPageDialogBox.rb +38 -0
  32. data/lib/IFMapper/FXRoom.rb +218 -0
  33. data/lib/IFMapper/FXRoomDialogBox.rb +119 -0
  34. data/lib/IFMapper/FXSearchDialogBox.rb +51 -0
  35. data/lib/IFMapper/FXSpline.rb +54 -0
  36. data/lib/IFMapper/FXWarningBox.rb +45 -0
  37. data/lib/IFMapper/IFMReader.rb +613 -0
  38. data/lib/IFMapper/Map.rb +110 -0
  39. data/lib/IFMapper/PDFMapExporter.rb +315 -0
  40. data/lib/IFMapper/Page.rb +158 -0
  41. data/lib/IFMapper/Room.rb +104 -0
  42. data/maps/Bureaucracy.ifm +75 -0
  43. data/maps/Hollywood_Hijinx.ifm +149 -0
  44. data/maps/Jigsaw.ifm +806 -0
  45. data/maps/LGOP.ifm +705 -0
  46. data/maps/Mercy.ifm +76 -0
  47. data/maps/Planetfall.ifm +186 -0
  48. data/maps/Plundered_Hearts.ifm +251 -0
  49. data/maps/Ralph.ifm +50 -0
  50. data/maps/Robots_of_Dawn.ifm +224 -0
  51. data/maps/Seastalker.ifm +149 -0
  52. data/maps/Sherlock.ifm +209 -0
  53. data/maps/SoFar.ifm +72 -0
  54. data/maps/Starcross.ifm +170 -0
  55. data/maps/Suspended.ifm +82 -0
  56. data/maps/Wishbringer.ifm +277 -0
  57. data/maps/Wishbringer2.ifm +246 -0
  58. data/maps/Zork1.ifm +410 -0
  59. data/maps/Zork2.ifm +150 -0
  60. data/maps/Zork3.ifm +136 -0
  61. data/maps/Zork_Zero.ifm +557 -0
  62. data/maps/anchor.ifm +645 -0
  63. data/maps/atrox.ifm +134 -0
  64. data/maps/awaken.ifm +116 -0
  65. data/maps/babel.ifm +279 -0
  66. data/maps/bse.ifm +150 -0
  67. data/maps/change.ifm +128 -0
  68. data/maps/curses.ifm +307 -0
  69. data/maps/curves.ifm +529 -0
  70. data/maps/edifice.ifm +158 -0
  71. data/maps/frozen.ifm +126 -0
  72. data/maps/glow.ifm +101 -0
  73. data/maps/library.ifm +93 -0
  74. data/maps/mindelec.ifm +89 -0
  75. data/maps/minster.ifm +234 -0
  76. data/maps/muse.ifm +154 -0
  77. data/maps/paperchase.ifm +110 -0
  78. data/maps/space_st.ifm +104 -0
  79. data/maps/stationfall.ifm +320 -0
  80. data/maps/theatre.ifm +182 -0
  81. data/maps/toonesia.ifm +54 -0
  82. data/maps/tortoise.ifm +72 -0
  83. data/maps/vgame.ifm +219 -0
  84. data/maps/weather.ifm +98 -0
  85. data/maps/windhall.ifm +154 -0
  86. data/maps/zebulon.ifm +68 -0
  87. metadata +144 -0
data/HISTORY.txt ADDED
@@ -0,0 +1,2 @@
1
+
2
+ v0.5 - First public release on Rubyforge.
data/IFMapper.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ require "rubygems"
2
+
3
+ spec = Gem::Specification.new do |spec|
4
+ spec.name = "ifmapper"
5
+ spec.version = '0.5'
6
+ spec.author = "Gonzalo Garramuno"
7
+ spec.email = 'GGarramuno@aol.com or ggarram@advance.dsl.com.ar'
8
+ spec.homepage = 'http://www.rubyforge.org/projects/ifmapper/'
9
+ spec.summary = 'Interactive Fiction Mapping Tool.'
10
+ spec.require_path = "lib"
11
+ spec.files = ['IFMapper.rb'] + Dir.glob("lib/IFMapper/*.rb") + Dir.glob("maps/*.ifm") + Dir.glob("icons/*")
12
+ spec.description = <<-EOF
13
+ Interactive Fiction Mapping Tool.
14
+ EOF
15
+ spec.add_dependency("fxruby", ">= 1.2.6")
16
+ spec.add_dependency("pdf-writer", ">= 1.1.1")
17
+ spec.extra_rdoc_files = ["HISTORY.txt", "IFMapper.gemspec"]
18
+ spec.has_rdoc = true
19
+ spec.rubyforge_project = 'ifmapper'
20
+ spec.required_ruby_version = '>= 1.6.8'
21
+ end
data/IFMapper.rb ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Add current path, so modules are found locally
4
+ $LOAD_PATH << './lib'
5
+ require 'IFMapper/FXMapperWindow'
6
+
7
+ if __FILE__ == $0
8
+ # Make application
9
+ application = FXApp.new("IFMapper", "gga")
10
+
11
+ # Make window
12
+ m = FXMapperWindow.new(application)
13
+
14
+ # Create the application windows
15
+ application.create
16
+
17
+ # Run the application
18
+ begin
19
+ application.run
20
+ rescue => e
21
+ m.autosave
22
+ $stderr.puts e
23
+ $stderr.flush
24
+ raise e
25
+ end
26
+ end
27
+
data/icons/copy.png ADDED
Binary file
data/icons/cut.png ADDED
Binary file
data/icons/filenew.png ADDED
Binary file
Binary file
Binary file
Binary file
data/icons/help.png ADDED
Binary file
data/icons/kill.png ADDED
Binary file
Binary file
data/icons/paste.png ADDED
Binary file
Binary file
Binary file
data/icons/redo.png ADDED
Binary file
data/icons/saveas.png ADDED
Binary file
data/icons/undo.png ADDED
Binary file
data/icons/winapp.png ADDED
Binary file
data/icons/zoom.png ADDED
Binary file
@@ -0,0 +1,63 @@
1
+
2
+ #
3
+ # Class used to represent a connection between one
4
+ # room and another
5
+ #
6
+ class Connection
7
+ attr_accessor :type
8
+ attr_accessor :dir
9
+ attr_accessor :roomA, :roomB
10
+ attr_accessor :exitAtext, :exitBtext
11
+
12
+ # Type constants
13
+ FREE = 0
14
+ LOCKED_DOOR = 1
15
+ SPECIAL = 2
16
+
17
+ # Direction constants
18
+ BOTH = 0
19
+ AtoB = 1
20
+ BtoA = 2
21
+
22
+ # Text near connection (to indicate other dir)
23
+ EXIT_TEXT = [
24
+ '',
25
+ 'U',
26
+ 'D',
27
+ 'I',
28
+ 'O'
29
+ ]
30
+
31
+ def initialize( roomA, roomB, dir = BOTH, type = FREE )
32
+ @roomA = roomA
33
+ @roomB = roomB
34
+ @dir = dir
35
+ @type = type
36
+ @exitAtext = 0
37
+ @exitBtext = 0
38
+ end
39
+
40
+ def to_s
41
+ dirA = dirB = ''
42
+ a = @roomA? @roomA.name : 'nil'
43
+ b = @roomB? @roomB.name : 'nil'
44
+ if exitAtext > 0
45
+ dirA = EXIT_TEXT[exitBtext]
46
+ else
47
+ if @roomA
48
+ idx = @roomA.exits.index(self)
49
+ dirA = Room::DIRECTIONS[idx] if idx
50
+ end
51
+ end
52
+ if exitBtext > 0
53
+ dirB = EXIT_TEXT[exitBtext]
54
+ else
55
+ if @roomB
56
+ idx = @roomB.exits.rindex(self)
57
+ dirB = Room::DIRECTIONS[idx] if idx
58
+ end
59
+ end
60
+ "#{a} #{dirA}<->#{b} #{dirB}"
61
+ end
62
+ end
63
+
@@ -0,0 +1,32 @@
1
+
2
+
3
+ class FXAboutDialogBox < FXDialogBox
4
+
5
+ def initialize(parent, title, text)
6
+ decor = DECOR_TITLE|DECOR_BORDER|DECOR_CLOSE
7
+
8
+ super( parent, title, decor, 40, 40, 0, 0 )
9
+ mainFrame = FXVerticalFrame.new(self,
10
+ FRAME_SUNKEN|FRAME_THICK|
11
+ LAYOUT_FILL_X|LAYOUT_FILL_Y)
12
+
13
+ frame = FXHorizontalFrame.new(mainFrame, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
14
+
15
+ FXLabel.new(frame, text, nil, 0, LAYOUT_FILL_ROW)
16
+
17
+ # c = FXText.new(frame, nil, 0, LAYOUT_FILL_ROW)
18
+ # c.visibleRows = 10
19
+ # c.visibleColumns = 80
20
+ # c.editable = false
21
+ # c.text = text
22
+
23
+ buttons = FXHorizontalFrame.new(mainFrame,
24
+ LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|
25
+ PACK_UNIFORM_WIDTH)
26
+ # Accept
27
+ FXButton.new(buttons, "&Super!", nil, self, FXDialogBox::ID_ACCEPT,
28
+ FRAME_RAISED|LAYOUT_FILL_X|FRAME_THICK|LAYOUT_RIGHT|LAYOUT_CENTER_Y)
29
+
30
+ create
31
+ end
32
+ end
@@ -0,0 +1,283 @@
1
+
2
+ require 'IFMapper/FXSpline'
3
+ require 'IFMapper/Connection'
4
+ require 'IFMapper/FXConnectionDialogBox'
5
+
6
+ ######################################################
7
+ #
8
+ # WW
9
+ # +---------------------+
10
+ # | W |
11
+ # | +-------------+ |
12
+ # HH | | |WS2|
13
+ # | H | |---|
14
+ # | +-------------+ |
15
+ # | |HS2 |
16
+ # +---------------------+
17
+ #
18
+ #####################################################
19
+
20
+ W = 120
21
+ H = 75
22
+ WS = 40
23
+ HS = 40
24
+ WW = W+WS
25
+ HH = H+HS
26
+
27
+ WS_2 = WS / 2
28
+ HS_2 = HS / 2
29
+
30
+ WIDX = 24
31
+ HIDX = 18
32
+
33
+
34
+ class FXConnection < Connection
35
+ attr_accessor :selected
36
+ attr_accessor :failed
37
+ attr_accessor :pts, :gpts
38
+
39
+ @@win = nil
40
+
41
+ def initialize( roomA, roomB, dir = Connection::BOTH,
42
+ type = Connection::FREE )
43
+ super( roomA, roomB, dir, type )
44
+ @selected = @failed = false
45
+ @pts = @gpts = []
46
+ end
47
+
48
+ def marshal_load(vars)
49
+ @selected, @type, @dir, @roomA, @roomB,
50
+ @exitAtext, @exitBtext = vars
51
+ @pts = @gpts = []
52
+ end
53
+
54
+ def marshal_dump
55
+ [ @selected, @type, @dir, @roomA, @roomB, @exitAtext, @exitBtext ]
56
+ end
57
+
58
+ def selected=(value)
59
+ if value and @@win
60
+ @@win.copy_from(self)
61
+ end
62
+ @selected = value
63
+ end
64
+
65
+ def toggle_direction
66
+ # If a self-loop, we cannot change dir
67
+ if @roomA == @roomB
68
+ return if @roomA.exits.index(self) == @roomA.exits.rindex(self)
69
+ end
70
+
71
+ @dir += 1
72
+ if @dir > BtoA
73
+ @dir = BOTH
74
+ end
75
+
76
+ if @@win
77
+ @@win.copy_from(self)
78
+ end
79
+ end
80
+
81
+ #
82
+ # Is this a complex path. Check if connection is
83
+ # contiguous
84
+ #
85
+ def complex?()
86
+ return false if not @roomB
87
+ return true if @roomB == @roomA
88
+ return true unless @roomA.next_to?(@roomB)
89
+
90
+ # Even if rooms are next to each other, we need to
91
+ # verify that following the exits does indeed take us to next room.
92
+ exitA = @roomA.exits.index(self)
93
+ dir = Room::DIR_TO_VECTOR[exitA]
94
+
95
+ if @roomA.x + dir[0] == @roomB.x and
96
+ @roomA.y + dir[1] == @roomB.y
97
+ exitB = @roomB.exits.rindex(self)
98
+ dir = Room::DIR_TO_VECTOR[exitB]
99
+ if @roomB.x + dir[0] == @roomA.x and
100
+ @roomB.y + dir[1] == @roomA.y
101
+ return false
102
+ else
103
+ return true
104
+ end
105
+ else
106
+ return true
107
+ end
108
+ end
109
+
110
+ def draw_complex_as_lines(dc, zoom)
111
+ p = []
112
+ @pts.each { |pt|
113
+ p << FXPoint.new( (pt[0] * zoom).to_i, (pt[1] * zoom).to_i )
114
+ }
115
+ dc.drawLines( p )
116
+ return p
117
+ end
118
+
119
+ def draw_complex_as_bspline(dc, zoom)
120
+ p = []
121
+ p << [ @pts[0][0] * zoom, @pts[0][1] * zoom ]
122
+ p << p[0]
123
+ p << p[0]
124
+ @pts.each { |pt|
125
+ p << [ pt[0] * zoom, pt[1] * zoom ]
126
+ }
127
+ p << p[-1]
128
+ p << p[-1]
129
+ p << p[-1]
130
+ return dc.drawBSpline( p )
131
+ end
132
+
133
+ def draw_complex(dc, zoom, opt)
134
+ if opt['Paths as Curves']
135
+ p = draw_complex_as_bspline(dc, zoom)
136
+ else
137
+ p = draw_complex_as_lines(dc, zoom)
138
+ end
139
+
140
+ x1, y1 = [p[0].x, p[0].y]
141
+ x2, y2 = [p[-1].x, p[-1].y]
142
+ draw_arrow(dc, zoom, x1, y1, x2, y2)
143
+ end
144
+
145
+ def draw_simple(dc, zoom)
146
+ dir = @roomA.exits.index(self)
147
+ x1, y1 = @roomA.corner(self, zoom, dir)
148
+ if @roomB
149
+ x2, y2 = @roomB.corner(self, zoom)
150
+ dc.drawLine( x1, y1, x2, y2 )
151
+ draw_arrow(dc, zoom, x1, y1, x2, y2)
152
+ if @type == LOCKED_DOOR
153
+ v = [ (x2-x1)*0.25, (y2-y1)*0.25 ]
154
+ m = [ (x2+x1)/2, (y2+y1)/2 ]
155
+ x1, y1 = [m[0] + v[1], m[1] - v[0]]
156
+ x2, y2 = [m[0] - v[1], m[1] + v[0]]
157
+ dc.drawLine(x1, y1, x2, y2)
158
+ end
159
+ else
160
+ v = FXRoom::DIR_TO_VECTOR[dir]
161
+ x2, y2 = [ @roomA.x + v[0] * 0.5, @roomA.y + v[1] * 0.5 ]
162
+ x2 *= WW * zoom
163
+ y2 *= HH * zoom
164
+ x2 += WW / 2 * zoom
165
+ y2 += HH / 2 * zoom
166
+ dc.drawLine( x1, y1, x2, y2 )
167
+ end
168
+ end
169
+
170
+ RAD_45 = 45 * Math::PI / 180
171
+ SIN_45 = Math.sin(RAD_45)
172
+ COS_45 = Math.cos(RAD_45)
173
+
174
+ def _arrow_info( x1, y1, x2, y2, zoom = 1.0 )
175
+ pt1 = []
176
+ dir = 0
177
+ if @dir == AtoB
178
+ dir = @roomB.exits.rindex(self)
179
+ pt1 = [ x2, y2 ]
180
+ else
181
+ dir = @roomA.exits.index(self)
182
+ pt1 = [ x1, y1 ]
183
+ end
184
+ x, y = Room::DIR_TO_VECTOR[dir]
185
+ arrow_len = 20.0 / Math.sqrt(x * x + y * y)
186
+ x *= arrow_len * zoom
187
+ y *= arrow_len * -zoom
188
+
189
+ d = [
190
+ x * COS_45 + y * SIN_45,
191
+ x * SIN_45 - y * COS_45
192
+ ]
193
+ return pt1, d
194
+ end
195
+
196
+
197
+ def draw_arrow( dc, zoom, x1, y1, x2, y2 )
198
+ return if @dir == BOTH
199
+ pt1, d = _arrow_info( x1, y1, x2, y2, zoom )
200
+
201
+ p = []
202
+ p << FXPoint.new( pt1[0].to_i, pt1[1].to_i )
203
+ pt2 = [ pt1[0] + d[0], pt1[1] + d[1] ]
204
+ p << FXPoint.new( pt2[0].to_i, pt2[1].to_i )
205
+ pt2 = [ pt1[0] + d[1], pt1[1] - d[0] ]
206
+ p << FXPoint.new( pt2[0].to_i, pt2[1].to_i )
207
+
208
+ dc.fillPolygon(p)
209
+ end
210
+
211
+ def draw_text(dc, zoom, x, y, dir, text, arrow)
212
+ if dir == 7 or dir < 6 and dir != 1
213
+ if arrow and (dir == 0 or dir == 4)
214
+ x += 10 * zoom
215
+ end
216
+ x += 5 * zoom
217
+ elsif dir == 6 or dir == 1
218
+ x -= 15 * zoom
219
+ end
220
+
221
+ if dir > 5 or dir < 4
222
+ if arrow and (dir == 6 or dir == 2)
223
+ y -= 10 * zoom
224
+ end
225
+ y -= 5 * zoom
226
+ elsif dir == 4 or dir == 5
227
+ y += 15 * zoom
228
+ end
229
+
230
+ dc.drawText(x, y, text)
231
+ end
232
+
233
+ def draw_exit_text(dc, zoom)
234
+ if @exitAtext != 0
235
+ dir = @roomA.exits.index(self)
236
+ x, y = @roomA.corner(self, zoom, dir)
237
+ draw_text( dc, zoom, x, y, dir,
238
+ EXIT_TEXT[@exitAtext], @dir == BtoA)
239
+ end
240
+ if @exitBtext != 0
241
+ dir = @roomB.exits.rindex(self)
242
+ x, y = @roomB.corner(self, zoom, dir)
243
+ draw_text( dc, zoom, x, y, dir,
244
+ EXIT_TEXT[@exitBtext], @dir == AtoB)
245
+ end
246
+ end
247
+
248
+ def draw(dc, zoom, opt)
249
+ if @selected
250
+ dc.foreground = 'yellow'
251
+ elsif @failed
252
+ dc.foreground = 'red'
253
+ else
254
+ dc.foreground = opt['Arrow Color']
255
+ end
256
+
257
+ draw_exit_text(dc, zoom)
258
+ if @type == SPECIAL
259
+ dc.lineStyle = LINE_ONOFF_DASH
260
+ else
261
+ dc.lineStyle = LINE_SOLID
262
+ end
263
+ if pts.size > 0
264
+ draw_complex(dc, zoom, opt)
265
+ else
266
+ draw_simple(dc, zoom)
267
+ end
268
+ end
269
+
270
+
271
+ def properties(map, event = nil)
272
+ if not @@win
273
+ @@win = FXConnectionDialogBox.new(map, self, event)
274
+ else
275
+ @@win.map = map
276
+ end
277
+ @@win.copy_from(self)
278
+ @@win.show
279
+ return
280
+ end
281
+
282
+ end
283
+