4 * The geeky little puzzle game with a big noodly crunch!
6 * gPlanarity copyright (C) 2005 Monty <monty@xiph.org>
7 * Original Flash game by John Tantalo <john.tantalo@case.edu>
8 * Original game concept by Mary Radcliffe
10 * gPlanarity is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
15 * gPlanarity is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with Postfish; see the file COPYING. If not, write to the
22 * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <gtk/gtkmain.h>
40 #include "gameboard.h"
41 #include "levelstate.h"
42 #include "dialog_finish.h"
43 #include "dialog_pause.h"
44 #include "dialog_level.h"
47 /* game state helpers ************************************************************************************/
49 void prepare_reenter_game(Gameboard
*g
){
52 g
->delayed_background
=0;
57 g
->selection_active
=num_selected_verticies(&g
->g
);
63 void reenter_game(Gameboard
*g
){
69 void enter_game(Gameboard
*g
){
71 prepare_reenter_game(g
);
75 static void animate_verticies(Gameboard
*g
,
80 vertex
*v
=g
->g
.verticies
;
81 float *tx
=alloca(g
->g
.vertex_num
* sizeof(*tx
));
82 float *ty
=alloca(g
->g
.vertex_num
* sizeof(*ty
));
84 // hide intersections now; deactivating the verticies below will hide them anyway
85 g
->show_intersections
= 0;
86 g
->realtime_background
= 1;
89 // deactivate all the verticies so they can be moved en-masse
90 // without graph metadata updates at each move
93 deactivate_vertex(&g
->g
,v
);
106 if(v
->x
!=x_target
[count
] || v
->y
!=y_target
[count
]){
108 float xd
= x_target
[count
] - tx
[count
];
109 float yd
= y_target
[count
] - ty
[count
];
110 float m
= hypot(xd
,yd
);
112 tx
[count
]+= xd
/m
*delta
[count
];
113 ty
[count
]+= yd
/m
*delta
[count
];
115 invalidate_vertex(g
,v
);
116 invalidate_edges(GTK_WIDGET(g
),v
,0,0);
118 v
->x
= rint(tx
[count
]);
119 v
->y
= rint(ty
[count
]);
121 if( (v
->x
> x_target
[count
] && xd
> 0) ||
122 (v
->x
< x_target
[count
] && xd
< 0) ||
123 (v
->y
> y_target
[count
] && yd
> 0) ||
124 (v
->y
< y_target
[count
] && yd
< 0) ){
125 v
->x
= x_target
[count
];
126 v
->y
= y_target
[count
];
130 invalidate_vertex(g
,v
);
131 invalidate_edges(GTK_WIDGET(g
),v
,0,0);
138 gdk_window_process_all_updates();
143 // reactivate all the verticies
144 activate_verticies(&g
->g
);
149 // it's a reset; show lines is default. This also has the side
150 // effect of forcing a full board redraw and expose
151 g
->realtime_background
=0;
155 if(g
->g
.active_intersections
<= g
->g
.objective
){
164 static void scale(Gameboard
*g
,double scale
){
167 int sel
= num_selected_verticies(&g
->g
);
169 int *tx
=alloca(g
->g
.vertex_num
* sizeof(*tx
));
170 int *ty
=alloca(g
->g
.vertex_num
* sizeof(*ty
));
171 float *tm
=alloca(g
->g
.vertex_num
* sizeof(*ty
));
174 int maxx
=g
->g
.width
-1;
176 int maxy
=g
->g
.height
-1;
179 // if selected, expand from center of selected mass
202 if(!sel
|| v
->selected
){
203 float nx
= rint((v
->x
- x
)*scale
+x
);
204 float ny
= rint((v
->y
- y
)*scale
+y
);
205 float m
= hypot(nx
- v
->x
,ny
-v
->y
)/5;
208 scale
= (float)(minx
-x
) / (v
->x
-x
);
213 scale
= (float)(maxx
-x
) / (v
->x
- x
);
218 scale
= (float)(miny
-y
) / (v
->y
-y
);
223 scale
= (float)(maxy
-y
) / (v
->y
- y
);
240 if(scale
>=.99999 && scale
<=1.00001){
241 ungrab_verticies(&g
->g
);
244 if(v
->x
<2 || v
->x
>=g
->g
.width
-3)v
->grabbed
=1;
245 if(v
->y
<2 || v
->y
>=g
->g
.height
-3)v
->grabbed
=1;
249 ungrab_verticies(&g
->g
);
251 animate_verticies(g
,tx
,ty
,tm
);
255 static void gtk_main_quit_wrapper(Gameboard
*g
){
260 static void level_wrapper(Gameboard
*g
){
265 static void finish_wrapper(Gameboard
*g
){
267 finish_level_dialog(g
);
270 /* toplevel main gameboard action entry points; when a button is
271 clicked and decoded to a specific action or a game state change
272 triggers an action, one of the below functions is the entry
273 point **************************************************************************************************************/
275 void quit_action(Gameboard
*g
){
277 undeploy_buttons(g
,gtk_main_quit_wrapper
);
280 void level_action(Gameboard
*g
){
282 undeploy_buttons(g
,level_wrapper
);
285 void finish_action(Gameboard
*g
){
286 if(g
->g
.active_intersections
<=g
->g
.original_intersections
){
289 undeploy_buttons(g
,finish_wrapper
);
293 void pause_action(Gameboard
*g
){
295 undeploy_buttons(g
,pause_dialog
);
298 void about_action(Gameboard
*g
){
300 undeploy_buttons(g
,about_dialog
);
303 void expand_action(Gameboard
*g
){
307 void shrink_action(Gameboard
*g
){
311 void set_hide_lines(Gameboard
*g
, int state
){
316 void toggle_hide_lines(Gameboard
*g
){
317 g
->hide_lines
= !g
->hide_lines
;
321 void set_show_intersections(Gameboard
*g
, int state
){
322 if(g
->show_intersections
!= state
){
323 g
->show_intersections
=state
;
328 void toggle_show_intersections(Gameboard
*g
){
329 g
->show_intersections
=!g
->show_intersections
;
333 void reset_action(Gameboard
*g
){
334 vertex
*v
=g
->g
.verticies
;
335 int *target_x
= alloca(g
->g
.vertex_num
* sizeof(*target_x
));
336 int *target_y
= alloca(g
->g
.vertex_num
* sizeof(*target_y
));
337 float *target_m
= alloca(g
->g
.vertex_num
* sizeof(*target_m
));
339 int xd
= (g
->g
.width
-g
->g
.orig_width
)>>1;
340 int yd
= (g
->g
.height
-g
->g
.orig_height
)>>1;
343 target_x
[i
]=v
->orig_x
+xd
;
344 target_y
[i
]=v
->orig_y
+yd
;
345 target_m
[i
++]=RESET_DELTA
;
349 animate_verticies(g
,target_x
,target_y
,target_m
);
357 /***************** save/load gameboard the widget state we want to be persistent **************/
359 // there are only a few things; lines, intersections
360 int gameboard_write(char *basename
, Gameboard
*g
){
364 name
=alloca(strlen(boarddir
)+strlen(basename
)+1);
366 strcat(name
,boarddir
);
367 strcat(name
,basename
);
369 f
= fopen(name
,"wb");
371 fprintf(stderr
,"ERROR: Could not save board state for \"%s\":\n\t%s\n",
372 get_level_desc(),strerror(errno
));
376 graph_write(&g
->g
,f
);
379 fprintf(f
,"hide_lines 1\n");
380 if(g
->show_intersections
)
381 fprintf(f
,"show_intersections 1\n");
388 int gameboard_read(char *basename
, Gameboard
*g
){
394 name
=alloca(strlen(boarddir
)+strlen(basename
)+3);
396 strcat(name
,boarddir
);
397 strcat(name
,basename
);
399 f
= fopen(name
,"rb");
401 fprintf(stderr
,"ERROR: Could not read saved board state for \"%s\":\n\t%s\n",
402 get_level_desc(),strerror(errno
));
408 // get local game state
409 while(getline(&line
,&n
,f
)>0){
412 if (sscanf(line
,"hide_lines %d",&i
)==1)
416 if (sscanf(line
,"show_intersections %d",&i
)==1)
418 g
->show_intersections
= 1;
424 request_resize(g
->g
.width
,g
->g
.height
);
425 activate_verticies(&g
->g
);