1
+ import Character
2
+ import credential
3
+ import messages
4
+
5
+ import pygame
6
+ from pygame .locals import QUIT
7
+ import random
8
+ import string
9
+ import sys
10
+ import socket
11
+ import time
12
+ import hashlib
13
+ import os
14
+ from Crypto .Util .Padding import pad
15
+ from Crypto .Cipher import AES
16
+
17
+ EAT_COMMAND = 1
18
+ PWN_COMMAND = 2
19
+ SLEEP_COMMAND = 3
20
+ DATE_COMMAND = 4
21
+ SAVE_COMMAND = 5
22
+
23
+ SAVE_SUCCESS = 11
24
+ SAVE_FAIL = 12
25
+
26
+ DEBUG = True
27
+
28
+ def alert (s ):
29
+ if DEBUG :
30
+ print (s )
31
+ else :
32
+ return
33
+
34
+ def get_random_str ():
35
+ return '' .join (random .sample (string .ascii_lowercase + string .ascii_uppercase + string .digits , k = 20 )) + os .urandom (10 ).hex ()
36
+
37
+ def get_credential ():
38
+ status , ID , PW , nickname = credential .load_credential ()
39
+ if status == credential .LOAD_SUCCESS :
40
+ alert ("[+] Load credential.. success" )
41
+
42
+ else :
43
+ ID = get_random_str ()
44
+ PW = get_random_str ()
45
+ nickname = "You"
46
+ status = credential .save_credential (ID , PW , nickname )
47
+ if status == credential .SAVE_SUCCESS :
48
+ alert ("[+] Save a new credential.. success" )
49
+ else :
50
+ alert ("[-] Save a new credential.. failed" )
51
+ exit (- 1 )
52
+
53
+ return ID , PW , nickname
54
+
55
+ def encrypt_data (ID , PW , character ):
56
+ id_hash = hashlib .sha256 (ID .encode ()).digest ()
57
+ pw_hash = hashlib .sha256 (PW .encode ()).digest ()
58
+ nonce = id_hash [:12 ]
59
+ file_name = id_hash [16 :24 ].hex ()
60
+ key = pw_hash [:16 ]
61
+ cipher = AES .new (key , AES .MODE_GCM , nonce )
62
+
63
+ file_data = b''
64
+ file_data += len (character .nickname ).to_bytes (2 , 'little' )
65
+ file_data += character .nickname .encode ()
66
+ file_data += character .day .to_bytes (4 , 'little' )
67
+ file_data += character .stamina .to_bytes (4 , 'little' )
68
+ file_data += character .intelligence .to_bytes (4 , 'little' )
69
+ file_data += character .friendship .to_bytes (4 , 'little' )
70
+
71
+ file_data = pad (file_data , 16 )
72
+ file_data_enc , tag = cipher .encrypt_and_digest (file_data )
73
+ return file_data_enc , tag
74
+
75
+ def put_script (font , screen , writer , msg , sleep_time = 0 ):
76
+ pygame .draw .rect (screen , (0 ,0 ,0 ), pygame .Rect (0 , 768 , 1024 , 100 ))
77
+ script = font .render (f"{ writer } : { msg } " , True , (0 , 255 , 0 ))
78
+ screen .blit (script , [10 , 768 + 20 ])
79
+ pygame .display .flip ()
80
+ if sleep_time :
81
+ time .sleep (sleep_time )
82
+
83
+ def put_character_status (font , screen , character ):
84
+ pygame .draw .rect (screen , (0 ,0 ,0 ), pygame .Rect (512 , 0 , 300 , 200 ))
85
+ status = font .render (f"day : { character .day } " , True , (0 , 255 , 0 ))
86
+ screen .blit (status , [520 , 10 ])
87
+
88
+ status = font .render (f"stamina : { character .stamina } " , True , (0 , 255 , 0 ))
89
+ screen .blit (status , [520 , 50 ])
90
+
91
+ status = font .render (f"intelligence : { character .intelligence } " , True , (0 , 255 , 0 ))
92
+ screen .blit (status , [520 , 90 ])
93
+
94
+ status = font .render (f"friendship : { character .friendship } / 34" , True , (0 , 255 , 0 ))
95
+ screen .blit (status , [520 , 130 ])
96
+
97
+ pygame .display .flip ()
98
+
99
+
100
+ def GUI (ID , PW , character , sock , is_new_game ):
101
+ #### GUI INIT ####
102
+ pygame .init ()
103
+ screen = pygame .display .set_mode ([1024 , 868 ])
104
+ pygame .display .set_caption ('Cogechan Dating Game' )
105
+
106
+ # load cogechan image
107
+ cogechan_img = pygame .image .load ("assets/cogechan.png" ).convert ()
108
+ screen .blit (cogechan_img , (0 ,0 ))
109
+
110
+ # Set font
111
+ fontname = 'couriernew'
112
+ if fontname not in pygame .font .get_fonts ():
113
+ fontname = pygame .font .get_fonts ()[0 ]
114
+ font = pygame .font .SysFont (fontname , 25 , True , False )
115
+
116
+ # Set Eat/Pwn/Sleep/Date buttons
117
+ pygame .draw .rect (screen , (225 ,125 ,206 ), pygame .Rect (550 , 250 , 170 , 50 ))
118
+ btn = font .render ("Eat" , True , (255 , 255 , 255 ))
119
+ screen .blit (btn , [570 , 260 ])
120
+ pygame .draw .rect (screen , (225 ,125 ,206 ), pygame .Rect (550 , 350 , 170 , 50 ))
121
+ btn = font .render ("Pwn" , True , (255 , 255 , 255 ))
122
+ screen .blit (btn , [570 , 360 ])
123
+ pygame .draw .rect (screen , (225 ,125 ,206 ), pygame .Rect (550 , 450 , 170 , 50 ))
124
+ btn = font .render ("Sleep" , True , (255 , 255 , 255 ))
125
+ screen .blit (btn , [570 , 460 ])
126
+ pygame .draw .rect (screen , (225 ,125 ,206 ), pygame .Rect (550 , 550 , 170 , 50 ))
127
+ btn = font .render ("Date" , True , (255 , 255 , 255 ))
128
+ screen .blit (btn , [570 , 560 ])
129
+
130
+ # Set save buttons
131
+ pygame .draw .rect (screen , (225 ,0 ,206 ), pygame .Rect (850 , 70 , 170 , 50 ))
132
+ btn = font .render ("Game save" , True , (255 , 255 , 255 ))
133
+ screen .blit (btn , [870 , 80 ])
134
+ pygame .display .flip ()
135
+
136
+ put_character_status (font , screen , character )
137
+ if is_new_game :
138
+ put_script (font , screen , 'System' , f'A saved game is loaded from server.' )
139
+ else :
140
+ put_script (font , screen , 'System' , f'A new game is started.' )
141
+
142
+ last_click = None
143
+ while True :
144
+ for event in pygame .event .get ():
145
+ if event .type == QUIT :
146
+ pygame .quit ()
147
+ sock .close ()
148
+ exit ()
149
+
150
+ if event .type == pygame .MOUSEBUTTONUP :
151
+ if last_click != None and (time .time () - last_click ) < 0.4 :
152
+ continue
153
+ mouse = pygame .mouse .get_pos ()
154
+
155
+ # Eat
156
+ if 550 <= mouse [0 ] <= 550 + 170 and 250 <= mouse [1 ] <= 250 + 50 :
157
+ sock .send (EAT_COMMAND .to_bytes (1 , 'little' ))
158
+ rnd = int .from_bytes (sock .recv (1 ), 'little' )
159
+ if rnd == 0 :
160
+ put_script (font , screen , 'System' , f'Server connection broken.. bye..' , 1 )
161
+ exit ()
162
+ character .stamina += rnd
163
+ character .day += 1
164
+ put_script (font , screen , character .nickname , random .choice (messages .EAT_MESSAGE ), 1 )
165
+ put_script (font , screen , 'System' , f'stamina +{ rnd } ' )
166
+ put_character_status (font , screen , character )
167
+
168
+ # Pwn
169
+ elif 550 <= mouse [0 ] <= 550 + 170 and 350 <= mouse [1 ] <= 350 + 50 :
170
+ sock .send (PWN_COMMAND .to_bytes (1 , 'little' ))
171
+ rnd = int .from_bytes (sock .recv (1 ), 'little' )
172
+ if rnd == 0 :
173
+ put_script (font , screen , 'System' , f'Server connection broken.. bye..' , 1 )
174
+ exit ()
175
+ if character .stamina >= 10 :
176
+ character .stamina -= 10
177
+ character .intelligence += rnd
178
+ character .day += 1
179
+ put_script (font , screen , character .nickname , random .choice (messages .PWN_SUCCESS_MESSAGE ), 1 )
180
+ put_script (font , screen , 'System' , f'stamina -10, intelligence +{ rnd } ' )
181
+
182
+ else :
183
+ put_script (font , screen , character .nickname , random .choice (messages .PWN_FAIL_MESSAGE ), 1 )
184
+
185
+ # Sleep
186
+ elif 550 <= mouse [0 ] <= 550 + 170 and 450 <= mouse [1 ] <= 450 + 50 :
187
+ sock .send (SLEEP_COMMAND .to_bytes (1 , 'little' ))
188
+ rnd = int .from_bytes (sock .recv (1 ), 'little' )
189
+ if rnd == 0 :
190
+ put_script (font , screen , 'System' , f'Server connection broken.. bye..' , 1 )
191
+ exit ()
192
+ character .stamina += rnd
193
+ character .day += 1
194
+ put_script (font , screen , character .nickname , random .choice (messages .SLEEP_MESSAGE ), 1 )
195
+ put_script (font , screen , 'System' , f'stamina +{ rnd } ' )
196
+ put_character_status (font , screen , character )
197
+
198
+ # Date
199
+ elif 550 <= mouse [0 ] <= 550 + 170 and 550 <= mouse [1 ] <= 550 + 50 :
200
+ sock .send (DATE_COMMAND .to_bytes (1 , 'little' ))
201
+ rnd = int .from_bytes (sock .recv (1 ), 'little' )
202
+ if rnd == 0 :
203
+ put_script (font , screen , 'System' , f'Server connection broken.. bye..' , 1 )
204
+ exit ()
205
+ put_script (font , screen , character .nickname , messages .DATE_REQUEST_MESSAGE [min (character .friendship , 33 )], 1 )
206
+ if character .stamina >= 10 and character .intelligence .bit_length () >= character .friendship :
207
+ character .stamina -= 10
208
+ character .friendship += 1
209
+ character .day += 1
210
+ if character .friendship == 34 :
211
+ flag_len = int .from_bytes (sock .recv (2 ), 'little' )
212
+ flag = sock .recv (flag_len ).decode ()
213
+ put_script (font , screen , "Cogechan" , "Not only that, I want to spend my whole life with you." , 1 )
214
+ put_script (font , screen , 'System' , flag )
215
+
216
+ else :
217
+ put_script (font , screen , "Cogechan" , random .choice (messages .DATE_SUCCESS_MESSAGE ), 1 )
218
+ put_script (font , screen , 'System' , f'stamina -10, friendship +1' )
219
+
220
+ else :
221
+ put_script (font , screen , "Cogechan" , random .choice (messages .DATE_FAIL_MESSAGE ), 1 )
222
+
223
+
224
+ # Game save
225
+ elif 850 <= mouse [0 ] <= 850 + 170 and 70 <= mouse [1 ] <= 70 + 50 :
226
+ sock .send (SAVE_COMMAND .to_bytes (1 , 'little' ))
227
+ file_data_enc , tag = encrypt_data (ID , PW , character )
228
+ sock .send (len (file_data_enc ).to_bytes (2 , 'little' ) + file_data_enc )
229
+ sock .send (tag )
230
+ status = int .from_bytes (sock .recv (1 ), 'little' )
231
+ if status == 0 :
232
+ put_script (font , screen , 'System' , f'Server connection broken.. bye..' , 1 )
233
+ exit ()
234
+ elif status == SAVE_SUCCESS :
235
+ put_script (font , screen , "System" , "Save success" )
236
+ else :
237
+ put_script (font , screen , "System" , "Save failed" )
238
+
239
+ last_click = time .time ()
240
+
241
+ put_character_status (font , screen , character )
242
+
243
+ def main ():
244
+ if len (sys .argv ) != 3 :
245
+ print (f"usage : { sys .argv [0 ]} ip port" )
246
+ return
247
+
248
+ ip = sys .argv [1 ]
249
+ port = int (sys .argv [2 ])
250
+
251
+ sock = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
252
+ try :
253
+ sock .connect ((ip , port ))
254
+ except :
255
+ alert ("[-] failed to connect a server" )
256
+ return
257
+
258
+ ID , PW , nickname = get_credential ()
259
+ sock .send (len (ID ).to_bytes (2 , 'little' ) + ID .encode ())
260
+ sock .send (len (PW ).to_bytes (2 , 'little' ) + PW .encode ())
261
+ status = sock .recv (1 )
262
+ character = Character .Character ()
263
+
264
+ if status [0 ] == 1 : # LOAD_SUCCESS
265
+ nickname_len = int .from_bytes (sock .recv (2 ), 'little' )
266
+ character .nickname = sock .recv (nickname_len ).decode ()
267
+ character .day = int .from_bytes (sock .recv (4 ), 'little' )
268
+ character .stamina = int .from_bytes (sock .recv (4 ), 'little' )
269
+ character .intelligence = int .from_bytes (sock .recv (4 ), 'little' )
270
+ character .friendship = int .from_bytes (sock .recv (4 ), 'little' )
271
+
272
+ else :
273
+ sock .send (len (nickname ).to_bytes (2 , 'little' ) + nickname .encode ())
274
+ character .nickname = nickname
275
+ character .stamina = 100
276
+
277
+ GUI (ID , PW , character , sock , status [0 ] == 1 )
278
+
279
+ if __name__ == "__main__" :
280
+ main ()
0 commit comments