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.
34 #include "gameboard.h"
35 #include "gameboard_draw_button.h"
36 #include "dialog_level.h"
37 #include "levelstate.h"
40 static void draw_forward_arrow(graph
*g
,dialog_level_oneicon
*l
, cairo_t
*c
,int fill
){
46 cairo_translate(c
,l
->x
+g
->width
/2+.5,l
->y
+g
->height
/2+.5);
48 cairo_set_line_width(c
,B_LINE
);
50 cairo_move_to(c
,w
-10,cy
);
51 cairo_line_to(c
,cx
,h
-10);
52 cairo_line_to(c
,cx
,(int)h
*.75);
53 cairo_line_to(c
,10,(int)h
*.75);
54 cairo_line_to(c
,10,(int)h
*.25);
55 cairo_line_to(c
,cx
,(int)h
*.25);
56 cairo_line_to(c
,cx
,10);
60 cairo_set_source_rgba (c
, B_COLOR
);
61 cairo_fill_preserve (c
);
63 cairo_set_source_rgba (c
, B_LINE_COLOR
);
68 static void draw_backward_arrow(graph
*g
,dialog_level_oneicon
*l
, cairo_t
*c
,int fill
){
74 cairo_translate(c
,l
->x
+g
->width
/2-.5,l
->y
+g
->height
/2+.5);
76 cairo_set_line_width(c
,B_LINE
);
78 cairo_move_to(c
,10,cy
);
79 cairo_line_to(c
,cx
,h
-10);
80 cairo_line_to(c
,cx
,(int)h
*.75);
81 cairo_line_to(c
,w
-10,(int)h
*.75);
82 cairo_line_to(c
,w
-10,(int)h
*.25);
83 cairo_line_to(c
,cx
,(int)h
*.25);
84 cairo_line_to(c
,cx
,10);
88 cairo_set_source_rgba (c
, B_COLOR
);
89 cairo_fill_preserve (c
);
91 cairo_set_source_rgba (c
, B_LINE_COLOR
);
96 static void invalidate_icon(Gameboard
*g
,dialog_level_oneicon
*l
){
97 int cx
= g
->g
.width
/2;
98 int cy
= g
->g
.height
/2;
101 r
.x
=l
->x
+cx
+g
->d
.center_x
;
106 gdk_window_invalidate_rect (GTK_WIDGET(g
)->window
, &r
, FALSE
);
109 static void dialog_level_oneicon_init(Gameboard
*g
, int num
, dialog_level_oneicon
*l
){
110 int current
= get_level_num();
111 l
->num
= num
+current
;
113 if(l
->icon
)cairo_surface_destroy(l
->icon
);
114 l
->icon
= levelstate_get_icon(num
+ current
);
119 l
->x
= num
*ICON_WIDTH
*1.2 - (l
->w
*.5);
120 l
->y
= 120 - (LEVELBOX_HEIGHT
) / 2;
124 static void deploy_reset_button(Gameboard
*g
){
125 buttonstate
*states
=g
->b
.states
;
127 if(!g
->d
.reset_deployed
){
128 states
[10].sweepdeploy
+= SWEEP_DELTA
;
130 states
[2].position
= 2; //activate it
131 states
[2].y_target
= states
[2].y_active
;
133 g
->d
.reset_deployed
=1;
135 if(g
->b
.buttons_ready
){
136 if(g
->button_timer
!=0)
137 g_source_remove(g
->button_timer
);
138 g
->button_callback
=0;
139 g
->button_timer
= g_timeout_add(BUTTON_ANIM_INTERVAL
, animate_button_frame
, (gpointer
)g
);
144 static void undeploy_reset_button(Gameboard
*g
){
145 buttonstate
*states
=g
->b
.states
;
147 if(g
->d
.reset_deployed
){
149 states
[10].sweepdeploy
-= SWEEP_DELTA
;
150 states
[2].y_target
= states
[2].y_inactive
;
152 g
->d
.reset_deployed
=0;
154 if(g
->b
.buttons_ready
){
155 if(g
->button_timer
!=0)
156 g_source_remove(g
->button_timer
);
157 g
->button_callback
= 0;
158 g
->button_timer
= g_timeout_add(BUTTON_ANIM_INTERVAL
, animate_button_frame
, (gpointer
)g
);
163 static void alpha_update(Gameboard
*g
,dialog_level_oneicon
*l
){
164 int distance
= labs(l
->x
- g
->d
.level_icons
[2].x
+ g
->d
.center_x
);
165 double alpha
= 1. - (distance
/300.);
166 if(alpha
<0.)alpha
=0.;
167 //if(alpha>1.)alpha=1.;
171 void level_icons_init(Gameboard
*g
){
175 dialog_level_oneicon_init(g
,i
-2,g
->d
.level_icons
+i
);
180 g
->d
.reset_deployed
= 0;
182 if(levelstate_in_progress())
183 deploy_reset_button(g
);
185 memset(&g
->d
.text1
,0,sizeof(g
->d
.text1
));
186 memset(&g
->d
.text2
,0,sizeof(g
->d
.text2
));
187 memset(&g
->d
.text3
,0,sizeof(g
->d
.text3
));
188 memset(&g
->d
.text4
,0,sizeof(g
->d
.text4
));
191 void render_level_icons(Gameboard
*g
, cairo_t
*c
, int ex
,int ey
, int ew
, int eh
){
192 if(g
->level_dialog_active
){
195 int y
= h
/2-LEVELBOX_HEIGHT
/2+SCOREHEIGHT
/2;
202 dialog_level_oneicon
*l
=g
->d
.level_icons
+i
;
204 if(l
->num
>= 0 && l
->num
< levelstate_limit() && c
){
208 int ix
= l
->x
+g
->d
.center_x
+w
/2;
211 if( l
->alpha
== 0.) continue;
213 if( ix
+iw
< ex
) continue;
214 if( ix
> ex2
) continue;
215 if( iy
+ih
< ey
) continue;
216 if( iy
> ey2
) continue;
218 if(l
->icon
&& cairo_surface_status(l
->icon
)==CAIRO_STATUS_SUCCESS
){
219 cairo_set_source_surface(c
,l
->icon
,ix
,iy
);
220 cairo_paint_with_alpha(c
,l
->alpha
);
223 if(g
->d
.center_x
==0 && g
->d
.center_done
){
225 cairo_set_source_rgba (c
, B_COLOR
);
226 borderbox_path(c
,ix
+1.5,iy
+1.5,iw
-3,ih
-3);
231 draw_backward_arrow(&g
->g
,l
,c
,i
==g
->d
.level_lit
);
233 draw_forward_arrow(&g
->g
,l
,c
,i
==g
->d
.level_lit
);
238 // render level related text
239 if(g
->d
.center_x
== 0 && g
->d
.center_done
&& c
){
243 if(g
->d
.text1
.width
==0 ||
244 (ey
<g
->d
.text1
.y
+g
->d
.text1
.height
&& ey2
>g
->d
.text1
.y
)){
246 snprintf(buffer
,160,_("Level %d:"),get_level_num()+1);
247 set_font(c
,20,20,0,1);
248 cairo_set_source_rgba (c
, TEXT_COLOR
);
249 g
->d
.text1
=render_bordertext_centered(c
, buffer
,w
/2,y
+45);
252 if(g
->d
.text2
.width
==0 ||
253 (ey
<g
->d
.text2
.y
+g
->d
.text2
.height
&& ey2
>g
->d
.text2
.y
)){
254 set_font(c
,18,18,0,0);
255 cairo_set_source_rgba (c
, TEXT_COLOR
);
256 g
->d
.text2
=render_bordertext_centered(c
, get_level_desc(),w
/2,y
+70);
259 if(g
->d
.text3
.width
==0 ||
260 (ey
<g
->d
.text3
.y
+g
->d
.text3
.height
&& ey2
>g
->d
.text3
.y
)){
262 if(levelstate_get_hiscore()==0){
263 set_font(c
,18,18,1,0);
264 snprintf(buffer
,160,_("[not yet completed]"));
266 set_font(c
,18,18,0,0);
267 snprintf(buffer
,160,_("level high score: %ld"),levelstate_get_hiscore());
270 cairo_set_source_rgba (c
, TEXT_COLOR
);
271 g
->d
.text3
=render_bordertext_centered(c
, buffer
,w
/2,y
+245);
274 if(g
->d
.text4
.width
==0 ||
275 (ey
<g
->d
.text4
.y
+g
->d
.text4
.height
&& ey2
>g
->d
.text4
.y
)){
277 snprintf(buffer
,160,_("total score all levels: %ld"),levelstate_total_hiscore());
279 set_font(c
,18,18,0,0);
280 cairo_set_source_rgba (c
, TEXT_COLOR
);
281 g
->d
.text4
=render_bordertext_centered(c
, buffer
,w
/2,y
+265);
284 memset(&g
->d
.text1
,0,sizeof(g
->d
.text1
));
285 memset(&g
->d
.text2
,0,sizeof(g
->d
.text2
));
286 memset(&g
->d
.text3
,0,sizeof(g
->d
.text3
));
287 memset(&g
->d
.text4
,0,sizeof(g
->d
.text4
));
292 static gboolean
animate_level_frame(gpointer ptr
){
293 Gameboard
*g
= GAMEBOARD (ptr
);
296 if(g
->d
.center_x
== 0){
298 g_source_remove(g
->d
.icon_timer
);
301 if(levelstate_in_progress())
302 deploy_reset_button(g
);
310 if(g
->d
.level_icons
[i
].alpha
)
311 invalidate_icon(g
, g
->d
.level_icons
+i
);
313 if(g
->d
.center_x
< 0){
314 g
->d
.center_x
+= ICON_DELTA
;
315 if(g
->d
.center_x
> 0) g
->d
.center_x
= 0;
317 g
->d
.center_x
-= ICON_DELTA
;
318 if(g
->d
.center_x
< 0) g
->d
.center_x
= 0;
321 // trick 'expose'; run it with a region that does nothing in order
322 // to update the visibility flags
324 render_level_icons(g
, 0, 0, 0, 0, 0);
327 if(g
->d
.level_icons
[i
].alpha
)
328 invalidate_icon(g
, g
->d
.level_icons
+i
);
333 static int find_icon(Gameboard
*b
,graph
*g
, int x
, int y
){
342 dialog_level_oneicon
*l
=b
->d
.level_icons
+i
;
343 if(l
->num
>=0 && l
->num
<levelstate_limit()){
354 void local_reset (Gameboard
*g
){
356 dialog_level_oneicon_init(g
,0,g
->d
.level_icons
+2);
357 invalidate_icon(g
, g
->d
.level_icons
+2);
358 undeploy_reset_button(g
);
361 void level_mouse_motion(Gameboard
*g
, int x
, int y
){
363 int icon
= find_icon(g
,&g
->g
,x
,y
);
365 if(icon
!= g
->d
.level_lit
){
366 invalidate_icon(g
, g
->d
.level_icons
+g
->d
.level_lit
);
367 g
->d
.level_lit
= icon
;
368 invalidate_icon(g
, g
->d
.level_icons
+g
->d
.level_lit
);
372 void level_mouse_press(Gameboard
*g
, int x
, int y
){
375 level_mouse_motion(g
, x
, y
);
377 if(g
->d
.level_lit
== 1){
378 if(levelstate_prev()){
380 if(!levelstate_in_progress())
381 undeploy_reset_button(g
);
383 if(g
->d
.level_icons
[4].icon
)
384 cairo_surface_destroy(g
->d
.level_icons
[4].icon
);
386 g
->d
.level_icons
[i
].num
= g
->d
.level_icons
[i
-1].num
;
387 g
->d
.level_icons
[i
].icon
= g
->d
.level_icons
[i
-1].icon
;
389 g
->d
.level_icons
[0].icon
=0;
390 dialog_level_oneicon_init(g
,-2,g
->d
.level_icons
);
392 if(g
->d
.center_x
==0 && g
->d
.center_done
)expose_full(g
); // only needed to 'undraw' the text
394 g
->d
.center_x
= g
->d
.level_icons
[1].x
- g
->d
.level_icons
[2].x
;
398 if(g
->d
.level_lit
== 3){
399 if(levelstate_next()){
401 if(!levelstate_in_progress())
402 undeploy_reset_button(g
);
404 if(g
->d
.level_icons
[0].icon
)
405 cairo_surface_destroy(g
->d
.level_icons
[0].icon
);
407 g
->d
.level_icons
[i
].num
= g
->d
.level_icons
[i
+1].num
;
408 g
->d
.level_icons
[i
].icon
= g
->d
.level_icons
[i
+1].icon
;
410 g
->d
.level_icons
[4].icon
=0;
411 dialog_level_oneicon_init(g
,2,g
->d
.level_icons
+4);
413 if(g
->d
.center_x
==0 && g
->d
.center_done
)expose_full(g
); // only needed to 'undraw' the text
415 g
->d
.center_x
= g
->d
.level_icons
[3].x
- g
->d
.level_icons
[2].x
;
422 g_source_remove(g
->d
.icon_timer
);
423 g
->d
.icon_timer
= g_timeout_add(BUTTON_ANIM_INTERVAL
, animate_level_frame
, (gpointer
)g
);