chichilku3 5.0.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.
- checksums.yaml +7 -0
- data/bin/chichilku3 +3 -0
- data/bin/chichilku3-server +3 -0
- data/client.json +6 -0
- data/lib/client/chichilku3.rb +18 -0
- data/lib/client/client.rb +289 -0
- data/lib/client/client_cfg.rb +15 -0
- data/lib/client/gui.rb +492 -0
- data/lib/client/img/background1024x512.png +0 -0
- data/lib/client/img/battle1024x576.png +0 -0
- data/lib/client/img/connecting1024x512.png +0 -0
- data/lib/client/img/grass1024x512.png +0 -0
- data/lib/client/img/grey128.png +0 -0
- data/lib/client/img/menu1920x1080.png +0 -0
- data/lib/client/img/stick128/stick0.png +0 -0
- data/lib/client/img/stick128/stick1.png +0 -0
- data/lib/client/img/stick128/stick2.png +0 -0
- data/lib/client/img/stick128/stick3.png +0 -0
- data/lib/client/img/stick128/stick4.png +0 -0
- data/lib/client/img/stick128/stick5.png +0 -0
- data/lib/client/img/stick128/stick_crouching0.png +0 -0
- data/lib/client/img/stick128/stick_crouching1.png +0 -0
- data/lib/client/img/stick128/stick_crouching2.png +0 -0
- data/lib/client/img/stick128/stick_crouching3.png +0 -0
- data/lib/client/img/stick128/stick_crouching4.png +0 -0
- data/lib/client/img/stick128/stick_crouching5.png +0 -0
- data/lib/client/scoreboard.rb +25 -0
- data/lib/client/test.rb +39 -0
- data/lib/client/text.rb +86 -0
- data/lib/server/chichilku3_server.rb +293 -0
- data/lib/server/gamelogic.rb +121 -0
- data/lib/server/server_cfg.rb +6 -0
- data/lib/share/config.rb +53 -0
- data/lib/share/console.rb +18 -0
- data/lib/share/network.rb +145 -0
- data/lib/share/player.rb +286 -0
- data/server.json +4 -0
- metadata +81 -0
data/lib/client/gui.rb
ADDED
@@ -0,0 +1,492 @@
|
|
1
|
+
require 'gosu'
|
2
|
+
require_relative 'client'
|
3
|
+
require_relative 'text'
|
4
|
+
require_relative 'scoreboard'
|
5
|
+
require_relative '../share/console'
|
6
|
+
require_relative '../share/player'
|
7
|
+
|
8
|
+
KEY_A = 4
|
9
|
+
KEY_C = 6
|
10
|
+
KEY_D = 7
|
11
|
+
KEY_H = 11
|
12
|
+
KEY_J = 13
|
13
|
+
KEY_K = 14
|
14
|
+
KEY_L = 15
|
15
|
+
KEY_M = 16
|
16
|
+
KEY_Q = 20
|
17
|
+
KEY_S = 22
|
18
|
+
KEY_T = 23
|
19
|
+
KEY_W = 26
|
20
|
+
KEY_RIGHT = 79
|
21
|
+
KEY_LEFT = 80
|
22
|
+
KEY_DOWN = 81
|
23
|
+
KEY_UP = 82
|
24
|
+
|
25
|
+
MENU_MAIN = 0
|
26
|
+
MENU_CONNECT = 1
|
27
|
+
MENU_USERNAME = 2
|
28
|
+
|
29
|
+
$time_point=Time.now
|
30
|
+
$time_buffer=0
|
31
|
+
|
32
|
+
def get_frame_time
|
33
|
+
diff = Time.now - $time_point
|
34
|
+
$time_point = Time.now
|
35
|
+
return diff
|
36
|
+
end
|
37
|
+
|
38
|
+
# Main Game getting gui form gosu
|
39
|
+
class Gui < Gosu::Window
|
40
|
+
def initialize(cfg)
|
41
|
+
super WINDOW_SIZE_X, WINDOW_SIZE_Y
|
42
|
+
self.caption = 'chichilku3'
|
43
|
+
self.fullscreen = true if cfg.data['fullscreen']
|
44
|
+
# images
|
45
|
+
@background_image = Gosu::Image.new("lib/client/img/battle1024x576.png")
|
46
|
+
@connecting_image = Gosu::Image.new("lib/client/img/connecting1024x512.png")
|
47
|
+
@menu_image = Gosu::Image.new("lib/client/img/menu1920x1080.png")
|
48
|
+
@stick = Gosu::Image.new("lib/client/img/stick128/stick0.png")
|
49
|
+
@stick_crouching = []
|
50
|
+
@stick_crouching << Gosu::Image.new("lib/client/img/stick128/stick_crouching0.png")
|
51
|
+
@stick_crouching << Gosu::Image.new("lib/client/img/stick128/stick_crouching1.png")
|
52
|
+
@stick_crouching << Gosu::Image.new("lib/client/img/stick128/stick_crouching2.png")
|
53
|
+
@stick_crouching << Gosu::Image.new("lib/client/img/stick128/stick_crouching3.png")
|
54
|
+
@stick_crouching << Gosu::Image.new("lib/client/img/stick128/stick_crouching4.png")
|
55
|
+
@stick_crouching << Gosu::Image.new("lib/client/img/stick128/stick_crouching5.png")
|
56
|
+
@stick_images = []
|
57
|
+
@stick_images << Gosu::Image.new("lib/client/img/stick128/stick0.png")
|
58
|
+
@stick_images << Gosu::Image.new("lib/client/img/stick128/stick1.png")
|
59
|
+
@stick_images << Gosu::Image.new("lib/client/img/stick128/stick2.png")
|
60
|
+
@stick_images << Gosu::Image.new("lib/client/img/stick128/stick3.png")
|
61
|
+
@stick_images << Gosu::Image.new("lib/client/img/stick128/stick4.png")
|
62
|
+
@stick_images << Gosu::Image.new("lib/client/img/stick128/stick5.png")
|
63
|
+
@x = 0
|
64
|
+
@y = 0
|
65
|
+
@players = []
|
66
|
+
@cfg = cfg
|
67
|
+
@tick = 0
|
68
|
+
@console = Console.new
|
69
|
+
@net_client = Client.new(@console, @cfg)
|
70
|
+
@net_err = nil
|
71
|
+
@state = @net_client.state
|
72
|
+
@menu_page = MENU_MAIN
|
73
|
+
@font = Gosu::Font.new(20)
|
74
|
+
@is_debug = false
|
75
|
+
@is_chat = false
|
76
|
+
@is_scoreboard = false
|
77
|
+
@chat_msg = "" # what we type
|
78
|
+
@server_chat_msg = "" # what we get from server
|
79
|
+
@chat_show_time = 4
|
80
|
+
@server_chat_recv = Time.now - @chat_show_time
|
81
|
+
@last_key = nil
|
82
|
+
@events = {
|
83
|
+
:blood => []
|
84
|
+
}
|
85
|
+
@menu_items = []
|
86
|
+
@selected_menu_item = 0
|
87
|
+
@menu_textfield = TextField.new(self, 60, 200)
|
88
|
+
# @chat_inp_stream = nil #TextInput.new
|
89
|
+
# @chat_inp_stream.text # didnt get it working <--- nobo xd
|
90
|
+
|
91
|
+
@last_pressed_button = {}
|
92
|
+
|
93
|
+
# depreciated ._.
|
94
|
+
# @con_msg = Gosu::Image.from_text(self, "connecting to #{@cfg.data['ip']}:#{@cfg.data['port']}...", Gosu.default_font_name, 45)
|
95
|
+
init_menu()
|
96
|
+
end
|
97
|
+
|
98
|
+
def button_press?(button)
|
99
|
+
last_btn = @last_pressed_button[button]
|
100
|
+
@last_pressed_button[button] = button_down?(button)
|
101
|
+
return false if last_btn == true
|
102
|
+
button_down?(button)
|
103
|
+
end
|
104
|
+
|
105
|
+
# def update_pos(server_data)
|
106
|
+
# server_data = server_data.split('')
|
107
|
+
# @x = server_data[0].to_i * 20
|
108
|
+
# @y = server_data[1].to_i * 20
|
109
|
+
# end
|
110
|
+
|
111
|
+
def chat_tick
|
112
|
+
if button_down?(Gosu::KB_ESCAPE)
|
113
|
+
@is_chat = false
|
114
|
+
elsif button_down?(Gosu::KB_RETURN)
|
115
|
+
@is_chat = false
|
116
|
+
return @chat_msg
|
117
|
+
else
|
118
|
+
if !button_down?(@last_key)
|
119
|
+
@last_key = nil # refresh blocker
|
120
|
+
end
|
121
|
+
if button_down?(Gosu::KB_BACKSPACE)
|
122
|
+
# press shift to fast delete
|
123
|
+
if button_down?(Gosu::KB_LEFT_SHIFT) || @last_key != Gosu::KB_BACKSPACE
|
124
|
+
@chat_msg = @chat_msg[0..-2]
|
125
|
+
@last_key = Gosu::KB_BACKSPACE
|
126
|
+
end
|
127
|
+
end
|
128
|
+
for key in 4..30 do # alphabet lowercase
|
129
|
+
if button_down?(key)
|
130
|
+
if @last_key != key
|
131
|
+
@chat_msg += button_id_to_char(key)
|
132
|
+
@last_key = key
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
nil
|
138
|
+
end
|
139
|
+
|
140
|
+
def main_tick
|
141
|
+
if @state == STATE_MENU
|
142
|
+
if @menu_page == MENU_CONNECT
|
143
|
+
enter_ip_tick
|
144
|
+
elsif @menu_page == MENU_USERNAME
|
145
|
+
enter_name_tick
|
146
|
+
else
|
147
|
+
menu_tick
|
148
|
+
end
|
149
|
+
elsif @state == STATE_ERROR
|
150
|
+
if button_down?(Gosu::KB_ESCAPE)
|
151
|
+
@state = STATE_MENU
|
152
|
+
@net_client.disconnect
|
153
|
+
end
|
154
|
+
else
|
155
|
+
game_tick
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def enter_name_tick
|
160
|
+
if button_down?(Gosu::KB_ESCAPE)
|
161
|
+
@state = STATE_MENU
|
162
|
+
@menu_page = MENU_MAIN
|
163
|
+
elsif button_down?(Gosu::KB_RETURN)
|
164
|
+
if @last_key != Gosu::KB_RETURN
|
165
|
+
@cfg.data['username'] = @menu_textfield.text[0...NAME_LEN]
|
166
|
+
@state = STATE_MENU
|
167
|
+
@menu_page = MENU_MAIN
|
168
|
+
end
|
169
|
+
else
|
170
|
+
@last_key = nil
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def enter_ip_tick
|
175
|
+
if button_down?(Gosu::KB_ESCAPE)
|
176
|
+
ip = @menu_textfield.text.split(":")
|
177
|
+
@cfg.data['ip'] = ip[0]
|
178
|
+
@cfg.data['port'] = ip[1] if ip.length > 1
|
179
|
+
@state = STATE_MENU
|
180
|
+
@menu_page = MENU_MAIN
|
181
|
+
elsif button_press?(Gosu::KB_RETURN)
|
182
|
+
if @last_key != Gosu::KB_RETURN
|
183
|
+
ip = @menu_textfield.text.split(":")
|
184
|
+
@cfg.data['ip'] = ip[0]
|
185
|
+
@cfg.data['port'] = ip[1] if ip.length > 1
|
186
|
+
connect
|
187
|
+
end
|
188
|
+
else
|
189
|
+
@last_key = nil
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def menu_tick
|
194
|
+
if button_down?(KEY_Q)
|
195
|
+
puts "quitting the game."
|
196
|
+
@cfg.save
|
197
|
+
exit
|
198
|
+
elsif button_down?(KEY_C)
|
199
|
+
connect_menu
|
200
|
+
return
|
201
|
+
end
|
202
|
+
if button_press?(KEY_DOWN) or button_press?(KEY_S) or button_press?(KEY_J) or button_press?(Gosu::MS_WHEEL_DOWN)
|
203
|
+
@selected_menu_item += 1 if @selected_menu_item < @menu_items.length - 1
|
204
|
+
elsif button_press?(KEY_UP) or button_press?(KEY_W) or button_press?(KEY_K) or button_press?(Gosu::MS_WHEEL_UP)
|
205
|
+
@selected_menu_item -= 1 if @selected_menu_item > 0
|
206
|
+
elsif button_press?(Gosu::KB_RETURN)
|
207
|
+
@menu_items[@selected_menu_item][1].call
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def game_tick
|
212
|
+
if button_down?(Gosu::KB_ESCAPE)
|
213
|
+
if @state == STATE_CONNECTING
|
214
|
+
@state = STATE_MENU
|
215
|
+
@net_client.disconnect
|
216
|
+
elsif @state == STATE_INGAME
|
217
|
+
@state = STATE_MENU
|
218
|
+
@net_client.disconnect
|
219
|
+
return
|
220
|
+
end
|
221
|
+
end
|
222
|
+
net_request = '0000'.split('')
|
223
|
+
protocol = 2
|
224
|
+
|
225
|
+
if @is_chat
|
226
|
+
msg = chat_tick
|
227
|
+
if !msg.nil?
|
228
|
+
# @console.dbg "rawmsg: #{msg}"
|
229
|
+
msg = msg.ljust(4, '0')
|
230
|
+
net_request = msg[0..3].split('')
|
231
|
+
# @console.dbg "prepedmsg: #{net_request}"
|
232
|
+
protocol = 4
|
233
|
+
end
|
234
|
+
else
|
235
|
+
net_request[0] = '0' # space for more
|
236
|
+
if button_down?(KEY_S)
|
237
|
+
net_request[0] = '1'
|
238
|
+
end
|
239
|
+
if button_down?(KEY_A)
|
240
|
+
net_request[1] = '1'
|
241
|
+
end
|
242
|
+
if button_down?(KEY_D)
|
243
|
+
net_request[2] = '1'
|
244
|
+
end
|
245
|
+
if button_down?(Gosu::KB_SPACE)
|
246
|
+
net_request[3] = '1'
|
247
|
+
end
|
248
|
+
if button_press?(KEY_M)
|
249
|
+
@is_debug = !@is_debug
|
250
|
+
end
|
251
|
+
if button_down?(KEY_T)
|
252
|
+
@last_key = KEY_T
|
253
|
+
@is_chat = true
|
254
|
+
@chat_msg = ""
|
255
|
+
end
|
256
|
+
@is_scoreboard = button_down?(Gosu::KB_TAB)
|
257
|
+
end
|
258
|
+
|
259
|
+
# Networking
|
260
|
+
begin
|
261
|
+
net_data = @net_client.tick(net_request, protocol, @tick)
|
262
|
+
rescue Errno::ECONNRESET, Errno::EPIPE
|
263
|
+
net_data = [@players, @flags, [0, NET_ERR_DISCONNECT, "connection to server lost"]]
|
264
|
+
@net_client.disconnect
|
265
|
+
end
|
266
|
+
return if net_data.nil?
|
267
|
+
|
268
|
+
@flags = net_data[1]
|
269
|
+
@state = @flags[:state]
|
270
|
+
msg = net_data[2]
|
271
|
+
if msg
|
272
|
+
type = msg[0]
|
273
|
+
if type == 0
|
274
|
+
@net_err = msg[1..-1]
|
275
|
+
@state = STATE_ERROR
|
276
|
+
elsif type == 1
|
277
|
+
@server_chat_msg = msg[1]
|
278
|
+
@server_chat_recv = Time.now
|
279
|
+
end
|
280
|
+
end
|
281
|
+
return if @flags[:skip]
|
282
|
+
|
283
|
+
@players = net_data[0]
|
284
|
+
end
|
285
|
+
|
286
|
+
def update
|
287
|
+
$time_buffer += get_frame_time
|
288
|
+
if ($time_buffer > MAX_TICK_SPEED)
|
289
|
+
@tick += 1
|
290
|
+
main_tick
|
291
|
+
$time_buffer = 0
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
def draw_main_menu
|
296
|
+
@menu_image.draw(0, 0, 0, UI_SCALE, UI_SCALE)
|
297
|
+
offset = 0
|
298
|
+
size = 2
|
299
|
+
@menu_items.each_with_index do |menu_item, index|
|
300
|
+
offset += 20 * size
|
301
|
+
if index == @selected_menu_item
|
302
|
+
@font.draw_text("> #{menu_item[0]} <", 20, 20 + offset, 0, size, size, Gosu::Color::GREEN)
|
303
|
+
else
|
304
|
+
@font.draw_text(" #{menu_item[0]} ", 20, 20 + offset, 0, size, size)
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def event_blood(x, y)
|
310
|
+
@events[:blood] << [
|
311
|
+
x,
|
312
|
+
y,
|
313
|
+
0,
|
314
|
+
[
|
315
|
+
[x, y, rand(12) - 6, rand(12) - 24, rand(3..12), rand(3..12)],
|
316
|
+
[x, y, rand(12) - 6, rand(12) - 24, rand(3..12), rand(3..12)],
|
317
|
+
[x, y, rand(12) - 6, rand(12) - 24, rand(3..12), rand(3..12)],
|
318
|
+
[x, y, rand(12) - 6, rand(12) - 24, rand(3..12), rand(3..12)],
|
319
|
+
[x, y, rand(12) - 6, rand(12) - 24, rand(3..12), rand(3..12)]
|
320
|
+
]
|
321
|
+
]
|
322
|
+
end
|
323
|
+
|
324
|
+
def draw_events
|
325
|
+
bloods = []
|
326
|
+
@events[:blood].each do |blood|
|
327
|
+
x = blood[0]
|
328
|
+
y = blood[1]
|
329
|
+
tick = blood[2]
|
330
|
+
splashes = blood[3]
|
331
|
+
new_splashes = []
|
332
|
+
splashes.each do |splash|
|
333
|
+
sx = splash[0]
|
334
|
+
sy = splash[1]
|
335
|
+
dx = splash[2]
|
336
|
+
dy = splash[3]
|
337
|
+
sw = splash[4]
|
338
|
+
sh = splash[5]
|
339
|
+
sx += dx
|
340
|
+
sy += dy
|
341
|
+
dy += 1 # gravity
|
342
|
+
draw_rect(sx, sy, sw, sh, 0xAAFF0000)
|
343
|
+
new_splashes << [sx, sy, dx, dy, sw, sh]
|
344
|
+
end
|
345
|
+
unless tick > 200
|
346
|
+
bloods << [x, y, tick + 1, new_splashes]
|
347
|
+
end
|
348
|
+
end
|
349
|
+
@events[:blood] = bloods
|
350
|
+
end
|
351
|
+
|
352
|
+
def draw
|
353
|
+
# draw_quad(0, 0, 0xffff8888, WINDOW_SIZE_X, WINDOW_SIZE_Y, 0xffffffff, 0, 0, 0xffffffff, WINDOW_SIZE_X, WINDOW_SIZE_Y, 0xffffffff, 0)
|
354
|
+
if @state == STATE_MENU
|
355
|
+
if @menu_page == MENU_CONNECT
|
356
|
+
@connecting_image.draw(0, 0, 0)
|
357
|
+
@font.draw_text("Enter server ip", 20, 20, 0, 5, 5)
|
358
|
+
@menu_textfield.draw(0)
|
359
|
+
elsif @menu_page == MENU_USERNAME
|
360
|
+
@connecting_image.draw(0, 0, 0)
|
361
|
+
@font.draw_text("Choose a username", 20, 20, 0, 5, 5)
|
362
|
+
@menu_textfield.draw(0)
|
363
|
+
else
|
364
|
+
draw_main_menu()
|
365
|
+
end
|
366
|
+
elsif @state == STATE_CONNECTING
|
367
|
+
@connecting_image.draw(0, 0, 0)
|
368
|
+
@font.draw_text("connecting to #{@cfg.data['ip']}:#{@cfg.data['port']}...", 20, 20, 0, 2, 5)
|
369
|
+
# @con_msg.draw(100,200,0)
|
370
|
+
elsif @state == STATE_INGAME
|
371
|
+
@background_image.draw(0, 0, 0)
|
372
|
+
@players.each do |player|
|
373
|
+
event_blood(player.x, player.y) if player.state[:bleeding]
|
374
|
+
player.draw_tick
|
375
|
+
@console.dbg "drawing player id=#{player.id} pos=#{player.x}/#{player.y}"
|
376
|
+
# draw_rect(player.x, player.y, TILE_SIZE, TILE_SIZE, Gosu::Color::WHITE)
|
377
|
+
# @stick.draw(player.x, player.y, 0)
|
378
|
+
if player.state[:crouching]
|
379
|
+
@stick_crouching[player.img_index].draw(player.x, player.y, 0, 0.5, 0.5)
|
380
|
+
else
|
381
|
+
@stick_images[player.img_index].draw(player.x, player.y, 0, 0.5, 0.5)
|
382
|
+
end
|
383
|
+
if @is_debug # print id
|
384
|
+
draw_rect(player.x - 2, player.y - 60, 32, 20, 0xAA000000)
|
385
|
+
@font.draw_text("#{player.id}:#{player.score}", player.x, player.y - 60, 0, 1, 1)
|
386
|
+
# @font.draw_text("#{player.id}:#{player.img_index}", player.x, player.y - TILE_SIZE * 2, 0, 1, 1)
|
387
|
+
if player.state[:crouching]
|
388
|
+
draw_rect(player.x, player.y, TILE_SIZE, TILE_SIZE/2, 0xAA00EE00)
|
389
|
+
else
|
390
|
+
draw_rect(player.x, player.y, TILE_SIZE/2, TILE_SIZE, 0xAA00EE00)
|
391
|
+
end
|
392
|
+
else
|
393
|
+
end
|
394
|
+
@font.draw_text(player.name, player.x - (TILE_SIZE/6), player.y - TILE_SIZE / 2, 0, 1, 1, 0xff_000000)
|
395
|
+
end
|
396
|
+
|
397
|
+
# chat input
|
398
|
+
if @is_chat
|
399
|
+
@font.draw_text("> #{@chat_msg}", 10, WINDOW_SIZE_Y - 30, 0, 1, 1)
|
400
|
+
end
|
401
|
+
|
402
|
+
# chat output
|
403
|
+
if @server_chat_recv + @chat_show_time > Time.now
|
404
|
+
@font.draw_text(@server_chat_msg, 10, WINDOW_SIZE_Y - 60, 0, 1, 1)
|
405
|
+
end
|
406
|
+
|
407
|
+
if @is_debug
|
408
|
+
player = Player.get_player_by_id(@players, @flags[:id])
|
409
|
+
unless player.nil?
|
410
|
+
draw_rect(5, 10, 295, 75, 0xAA000000)
|
411
|
+
@font.draw_text("Press m to deactivate debug mode", 10, 10, 0, 1, 1)
|
412
|
+
@font.draw_text("x: #{player.x} y: #{player.y}", 10, 30, 0, 1, 1)
|
413
|
+
@font.draw_text("gamestate: #{@flags[:gamestate]}", 10, 60, 0 , 1, 1)
|
414
|
+
# thats useless because collide/delta speed is not sent over the network
|
415
|
+
# @font.draw_text("dx: #{player.dx} dy: #{player.dy}", 10, 50, 0, 1, 1)
|
416
|
+
# @font.draw_text(player.collide_string, 10, 70, 0, 1, 1)
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
draw_events()
|
421
|
+
|
422
|
+
if @is_scoreboard
|
423
|
+
draw_scoreboard(WINDOW_SIZE_X, WINDOW_SIZE_Y, @players, @font)
|
424
|
+
end
|
425
|
+
elsif @state == STATE_ERROR
|
426
|
+
net_err_code = @net_err[0]
|
427
|
+
net_err_msg = @net_err[1]
|
428
|
+
@connecting_image.draw(0, 0, 0)
|
429
|
+
if net_err_code == NET_ERR_SERVER_OUTDATED || net_err_code == NET_ERR_CLIENT_OUTDATED
|
430
|
+
server_version = net_err_msg[0..4]
|
431
|
+
net_err_msg = net_err_msg[5..-1]
|
432
|
+
@font.draw_text("Server version: #{server_version} Your version: #{GAME_VERSION}", 50, 150, 0, 2, 2)
|
433
|
+
end
|
434
|
+
@font.draw_text("#{NET_ERR[net_err_code]}", 50, 30, 0, 5, 5)
|
435
|
+
@font.draw_text("#{net_err_msg}", 50, 200, 0, 2, 2)
|
436
|
+
else
|
437
|
+
@connecting_image.draw(0, 0, 0)
|
438
|
+
@font.draw_text('UNKOWN CLIENT STATE!!!', 20, 20, 0, 2, 10)
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
private
|
443
|
+
|
444
|
+
def connect()
|
445
|
+
begin
|
446
|
+
@net_client.connect(@cfg.data['ip'], @cfg.data['port'])
|
447
|
+
@state = STATE_CONNECTING;
|
448
|
+
@menu_page = MENU_MAIN
|
449
|
+
rescue Errno::ECONNREFUSED
|
450
|
+
@state = STATE_ERROR
|
451
|
+
@menu_page = MENU_MAIN
|
452
|
+
@net_err = [NET_ERR_DISCONNECT, "connection refused"]
|
453
|
+
@net_client.disconnect
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
def connect_menu()
|
458
|
+
@last_key = Gosu::KB_RETURN
|
459
|
+
self.text_input = @menu_textfield
|
460
|
+
@menu_textfield.text = "#{@cfg.data['ip']}:#{@cfg.data['port']}"
|
461
|
+
@state = STATE_MENU
|
462
|
+
@menu_page = MENU_CONNECT
|
463
|
+
end
|
464
|
+
|
465
|
+
def username_page()
|
466
|
+
@last_key = Gosu::KB_RETURN
|
467
|
+
self.text_input = @menu_textfield
|
468
|
+
@menu_textfield.text = "#{@cfg.data['username']}"
|
469
|
+
@state = STATE_MENU
|
470
|
+
@menu_page = MENU_USERNAME
|
471
|
+
end
|
472
|
+
|
473
|
+
def toggle_fullscreen()
|
474
|
+
if @cfg.data['fullscreen']
|
475
|
+
@cfg.data['fullscreen'] = self.fullscreen = false
|
476
|
+
else
|
477
|
+
@cfg.data['fullscreen'] = self.fullscreen = true
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
def init_menu()
|
482
|
+
@menu_items = []
|
483
|
+
add_menu_item("[c]onnect", Proc.new { connect_menu() })
|
484
|
+
add_menu_item("username", Proc.new { username_page() })
|
485
|
+
add_menu_item("fullscreen", Proc.new { toggle_fullscreen() })
|
486
|
+
add_menu_item("[q]uit", Proc.new { exit() })
|
487
|
+
end
|
488
|
+
|
489
|
+
def add_menu_item(name, callback)
|
490
|
+
@menu_items.push([name, callback])
|
491
|
+
end
|
492
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
def draw_scoreboard(win_size_x, win_size_y, players, font)
|
3
|
+
# TODO: do not compute those every frame
|
4
|
+
padX = win_size_x / 3
|
5
|
+
sizeX = win_size_x / 3
|
6
|
+
padY = win_size_y / 6
|
7
|
+
sizeY = win_size_y / 3
|
8
|
+
slot_height = sizeY / MAX_CLIENTS
|
9
|
+
text_scale = slot_height / 15
|
10
|
+
# background
|
11
|
+
draw_rect(padX, padY, sizeX, sizeY+3, 0xaa000000)
|
12
|
+
# left border
|
13
|
+
draw_rect(padX, padY, 3, sizeY+3, 0xaa000000)
|
14
|
+
# right border
|
15
|
+
draw_rect(padX + sizeX - 3, padY, 3, sizeY+3, 0xaa000000)
|
16
|
+
(0..MAX_CLIENTS).each do |i|
|
17
|
+
# row borders
|
18
|
+
draw_rect(padX + 3, padY + (i * slot_height), sizeX - 6, 3, 0xaa000000)
|
19
|
+
end
|
20
|
+
players.each_with_index do | player, i |
|
21
|
+
score_offset = text_scale * 10 * player.score.to_s.length
|
22
|
+
font.draw_text(player.name, padX + 5, padY + (i * slot_height), 0, text_scale, text_scale)
|
23
|
+
font.draw_text(player.score, padX + sizeX - score_offset, padY + (i * slot_height), 0, text_scale, text_scale)
|
24
|
+
end
|
25
|
+
end
|
data/lib/client/test.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative '../share/player'
|
2
|
+
|
3
|
+
def server_package_to_player_strs(slots, data)
|
4
|
+
players = []
|
5
|
+
slots.times do |index|
|
6
|
+
players[index] = data[index * 8..index * 8 + 7]
|
7
|
+
end
|
8
|
+
players
|
9
|
+
end
|
10
|
+
|
11
|
+
def player_strs_to_objects(player_strs)
|
12
|
+
players = []
|
13
|
+
player_strs.each do |player_str|
|
14
|
+
id = player_str[0..1].to_i
|
15
|
+
x = player_str[2..4].to_i
|
16
|
+
y = player_str[5..7].to_i
|
17
|
+
# puts "id: #{id} x: #{x} y: #{y}"
|
18
|
+
players << Player.new(id, x, y) unless id.zero?
|
19
|
+
end
|
20
|
+
players
|
21
|
+
end
|
22
|
+
|
23
|
+
def server_package_to_player_array(data)
|
24
|
+
# /(?<count>\d{2})(?<player>(?<id>\d{2})(?<x>\d{3})(?<y>\d{3}))/
|
25
|
+
slots = data[0..1].to_i # save slots
|
26
|
+
data = data[2..-1] # cut slots off
|
27
|
+
players = server_package_to_player_strs(slots, data)
|
28
|
+
# puts players
|
29
|
+
player_strs_to_objects(players)
|
30
|
+
end
|
31
|
+
|
32
|
+
# 3 players
|
33
|
+
pl3 = '03011001010220020203300303'
|
34
|
+
p server_package_to_player_array(pl3)
|
35
|
+
p server_package_to_player_array(pl3).count
|
36
|
+
# 2 players (first has id 00 -> offline)
|
37
|
+
pl2 = '03001001010220020203300303'
|
38
|
+
p server_package_to_player_array(pl2)
|
39
|
+
p server_package_to_player_array(pl2).count
|
data/lib/client/text.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# https://github.com/gosu/gosu-examples/blob/master/examples/text_input.rb
|
2
|
+
require "gosu"
|
3
|
+
|
4
|
+
class TextField < Gosu::TextInput
|
5
|
+
FONT = Gosu::Font.new(60)
|
6
|
+
WIDTH = 800
|
7
|
+
LENGTH_LIMIT = 20
|
8
|
+
PADDING = 5
|
9
|
+
|
10
|
+
INACTIVE_COLOR = 0xcc_666666
|
11
|
+
ACTIVE_COLOR = 0xcc_555555
|
12
|
+
SELECTION_COLOR = 0xcc_444444
|
13
|
+
CARET_COLOR = 0xff_ffffff
|
14
|
+
|
15
|
+
attr_reader :x, :y
|
16
|
+
|
17
|
+
def initialize(window, x, y)
|
18
|
+
# It's important to call the inherited constructor.
|
19
|
+
super()
|
20
|
+
|
21
|
+
@window, @x, @y = window, x, y
|
22
|
+
|
23
|
+
# Start with a self-explanatory text in each field.
|
24
|
+
self.text = "Click to edit"
|
25
|
+
end
|
26
|
+
|
27
|
+
# In this example, we use the filter method to prevent the user from entering a text that exceeds
|
28
|
+
# the length limit. However, you can also use this to blacklist certain characters, etc.
|
29
|
+
def filter new_text
|
30
|
+
allowed_length = [LENGTH_LIMIT - text.length, 0].max
|
31
|
+
new_text[0, allowed_length]
|
32
|
+
end
|
33
|
+
|
34
|
+
def draw(z)
|
35
|
+
# Change the background colour if this is the currently selected text field.
|
36
|
+
if @window.text_input == self
|
37
|
+
color = ACTIVE_COLOR
|
38
|
+
else
|
39
|
+
color = INACTIVE_COLOR
|
40
|
+
end
|
41
|
+
# ChillerDragon's epic shadow to at least have edited the stolen sample a lil bit
|
42
|
+
Gosu.draw_rect (x - PADDING) + 5, (y - PADDING) + 5, WIDTH + 2 * PADDING, height + 2 * PADDING, INACTIVE_COLOR, z
|
43
|
+
Gosu.draw_rect x - PADDING, y - PADDING, WIDTH + 2 * PADDING, height + 2 * PADDING, color, z
|
44
|
+
Gosu.draw_rect x - PADDING, y - PADDING, WIDTH + 2 * PADDING, height + 2 * PADDING, color, z
|
45
|
+
|
46
|
+
# Calculate the position of the caret and the selection start.
|
47
|
+
pos_x = x + FONT.text_width(self.text[0...self.caret_pos])
|
48
|
+
sel_x = x + FONT.text_width(self.text[0...self.selection_start])
|
49
|
+
sel_w = pos_x - sel_x
|
50
|
+
|
51
|
+
# Draw the selection background, if any. (If not, sel_x and pos_x will be
|
52
|
+
# the same value, making this a no-op call.)
|
53
|
+
Gosu.draw_rect sel_x, y, sel_w, height, SELECTION_COLOR, z
|
54
|
+
|
55
|
+
# Draw the caret if this is the currently selected field.
|
56
|
+
if @window.text_input == self
|
57
|
+
Gosu.draw_line pos_x, y, CARET_COLOR, pos_x, y + height, CARET_COLOR, z
|
58
|
+
end
|
59
|
+
|
60
|
+
# Finally, draw the text itself!
|
61
|
+
FONT.draw_text self.text, x, y, z
|
62
|
+
end
|
63
|
+
|
64
|
+
def height
|
65
|
+
FONT.height
|
66
|
+
end
|
67
|
+
|
68
|
+
# Hit-test for selecting a text field with the mouse.
|
69
|
+
def under_mouse?
|
70
|
+
@window.mouse_x > x - PADDING and @window.mouse_x < x + WIDTH + PADDING and
|
71
|
+
@window.mouse_y > y - PADDING and @window.mouse_y < y + height + PADDING
|
72
|
+
end
|
73
|
+
|
74
|
+
# Tries to move the caret to the position specifies by mouse_x
|
75
|
+
def move_caret_to_mouse
|
76
|
+
# Test character by character
|
77
|
+
1.upto(self.text.length) do |i|
|
78
|
+
if @window.mouse_x < x + FONT.text_width(text[0...i])
|
79
|
+
self.caret_pos = self.selection_start = i - 1;
|
80
|
+
return
|
81
|
+
end
|
82
|
+
end
|
83
|
+
# Default case: user must have clicked the right edge
|
84
|
+
self.caret_pos = self.selection_start = self.text.length
|
85
|
+
end
|
86
|
+
end
|