2 * This file is part of NumptyPhysics
3 * Copyright (C) 2008 Tim Edmonds
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 3 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
30 #include "Multitouch.h"
33 #include <SDL/SDL_image.h>
45 unsigned char levelbuf
[64*1024];
50 DemoEntry( int _t
, int _o
, SDL_Event
& _e
) : t(_t
), o(_o
), e(_e
) {}
55 class DemoLog
: public Array
<DemoEntry
>
58 std::string
asString( int i
)
63 s
<< "E:" << e
.t
<< " ";
66 s
<< "K" << e
.e
.key
.keysym
.sym
;
69 s
<< "k" << e
.e
.key
.keysym
.sym
;
71 case SDL_MOUSEBUTTONDOWN
:
72 s
<< "B" << '0'+e
.e
.button
.button
;
73 s
<< "," << e
.e
.button
.x
<< "," << e
.e
.button
.y
;
75 case SDL_MOUSEBUTTONUP
:
76 s
<< "b" << '0'+e
.e
.button
.button
;
77 s
<< "," << e
.e
.button
.x
<< "," << e
.e
.button
.y
;
80 s
<< "M" << e
.e
.button
.x
<< "," << e
.e
.button
.y
;
90 void append( int tick
, int offset
, SDL_Event
& ev
)
92 Array
<DemoEntry
>::append( DemoEntry( tick
, offset
, ev
) );
95 void appendFromString( const std::string
& str
)
97 const char *s
= str
.c_str();
102 if ( sscanf(s
,"E:%d %c%d",&t
,&c
,&v1
)==3 ) { //1 arg
104 case 'K': ev
.type
= SDL_KEYDOWN
; break;
105 case 'k': ev
.type
= SDL_KEYUP
; break;
107 ev
.key
.keysym
.sym
= (SDLKey
)v1
;
108 } else if ( sscanf(s
,"E:%d %c%d,%d",&t
,&c
,&v1
,&v2
)==4 ) { //2 args
110 case 'M': ev
.type
= SDL_MOUSEMOTION
; break;
114 } else if ( sscanf(s
,"E:%d %c%d,%d,%d",&t
,&c
,&v1
,&v2
,&v3
)==5 ) { //3 args
116 case 'B': ev
.type
= SDL_MOUSEBUTTONDOWN
; break;
117 case 'b': ev
.type
= SDL_MOUSEBUTTONUP
; break;
119 ev
.button
.button
= v1
;
123 if ( ev
.type
!= 0xff ) {
139 m_lastTickTime
= SDL_GetTicks();
145 printf("stop recording: %d events:\n", m_log
.size());
146 for ( int i
=0; i
<m_log
.size(); i
++ ) {
147 std::string e
= m_log
.asString(i
);
148 if ( e
.length() > 0 ) {
149 printf(" %s\n",e
.c_str());
159 m_lastTickTime
= SDL_GetTicks();
163 void record( SDL_Event
& ev
)
167 case SDL_MOUSEBUTTONDOWN
:
168 m_pressed
|= 1<<ev
.button
.button
;
170 case SDL_MOUSEBUTTONUP
:
171 m_pressed
&= ~(1<<ev
.button
.button
);
173 case SDL_MOUSEMOTION
:
174 if ( m_pressed
== 0 ) {
178 m_log
.append( m_lastTick
, SDL_GetTicks()-m_lastTickTime
, ev
);
182 DemoLog
& getLog() { return m_log
; }
197 void start( const DemoLog
* log
)
203 printf("start playback: %d events\n",m_log
->size());
206 bool isRunning() { return m_playing
; }
221 bool fetchEvent( SDL_Event
& ev
)
224 if ( m_index
< m_log
->size()
225 && m_log
->at(m_index
).t
<= m_lastTick
) {
226 printf("demo event at t=%d\n",m_lastTick
);
227 ev
= m_log
->at(m_index
).e
;
237 const DemoLog
* m_log
;
243 class CollectionSelector
: public ListProvider
247 CollectionSelector( GameControl
& game
)
249 m_list
= createListOverlay( game
, this );
251 Overlay
* overlay() { return m_list
; }
253 virtual int countItems() {
256 virtual Canvas
* provideItem( int i
, Canvas
* old
) {
259 sprintf(buf
,"%d. Item",i
);
260 Canvas
* c
= new Canvas( 100, 32 );
261 c
->setBackground(0xffffff);
263 Font::headingFont()->drawLeft( c
, Vec2(3,3), buf
, i
<<3 );
266 virtual void releaseItem( Canvas
* old
) {
269 virtual void onSelection( int i
, int ix
, int iy
) {
270 printf("Selected: %d (%d,%d)\n",i
,ix
,iy
);
283 startTime
= SDL_GetTicks();
290 class Game
: public GameControl
, public Widget
293 Stroke
*m_createStrokes
[MT_MAX_CURSORS
];
294 Stroke
*m_moveStrokes
[MT_MAX_CURSORS
];
295 Stroke
*m_ropeParts
[MT_MAX_CURSORS
][MAX_ROPE_PARTS
];
296 int m_numRopeLength
[MT_MAX_CURSORS
];
297 int m_numRopeParts
[MT_MAX_CURSORS
];
298 Array
<Overlay
*> m_overlays
;
300 Overlay
*m_pauseOverlay
;
301 Overlay
*m_editOverlay
;
302 Overlay
*m_completedOverlay
;
303 Overlay
*m_levelnameOverlay
;
304 int m_levelnameHideTime
;
305 // DemoOverlay m_demoOverlay;
306 DemoRecorder m_recorder
;
308 CollectionSelector m_cselector
;
314 Game( Levels
* levels
, int width
, int height
, bool fullscreen
)
315 : m_window(width
,height
,"Numpty Physics","NPhysics", fullscreen
),
316 m_pauseOverlay( NULL
),
317 m_editOverlay( NULL
),
318 m_completedOverlay( NULL
),
319 m_levelnameOverlay( NULL
),
320 m_levelnameHideTime( 0 ),
321 m_isCompleted(false),
322 m_cselector( *this ),
325 //,m_demoOverlay( *this )
327 for(int n
=0; n
<MT_MAX_CURSORS
; n
++) {
328 m_createStrokes
[n
] = NULL
;
329 m_moveStrokes
[n
] = NULL
;
330 m_numRopeLength
[n
] = NULL
;
331 m_numRopeParts
[n
] = 0;
333 configureScreenTransform( m_window
.width(), m_window
.height() );
339 virtual bool renderScene( Canvas
& c
, int level
)
342 int size
= m_levels
->load( level
, levelbuf
, sizeof(levelbuf
) );
343 if ( size
&& scene
.load( levelbuf
, size
) ) {
344 scene
.draw( c
, FULLSCREEN_RECT
);
350 void gotoLevel( int level
, bool replay
=false )
352 if ( level
>= 0 && level
< m_levels
->numLevels() ) {
353 int size
= m_levels
->load( level
, levelbuf
, sizeof(levelbuf
) );
354 if ( size
&& m_scene
.load( levelbuf
, size
) ) {
355 m_scene
.activateAll();
356 //m_window.setSubName( file );
364 m_player
.start( &m_recorder
.getLog() );
370 if (m_levelnameOverlay
&& m_levelnameHideTime
) {
371 hideOverlay(m_levelnameOverlay
);
372 delete m_levelnameOverlay
;
373 m_levelnameHideTime
= 0;
376 std::string title
= m_scene
.getTitle(), author
= m_scene
.getAuthor();
378 /* Only show title if we have at least one of (title, author) specified */
379 if (!title
.empty() || !author
.empty()) {
380 m_levelnameOverlay
= createTextOverlay( *this,
381 ((title
.empty())?(std::string("Untitled")):(title
)) +
382 std::string(" by ") +
383 ((author
.empty())?(std::string("Anonymous")):(author
)));
384 m_levelnameHideTime
= -1; /* in onTick, -1 means "show the overlay" */
391 bool save( const char *file
=NULL
)
397 p
= Config::userDataDir() + Os::pathSep
+ "L99_saved.nph";
399 if ( m_scene
.save( p
) ) {
400 m_levels
->addPath( p
.c_str() );
401 int l
= m_levels
->findLevel( p
.c_str() );
404 m_window
.setSubName( p
.c_str() );
413 if ( save( SEND_TEMP_FILE
) ) {
415 if ( h
.post( Config::planetRoot().c_str(),
416 "upload", SEND_TEMP_FILE
, "type=level" ) ) {
417 std::string id
= h
.getHeader("NP-Upload-Id");
418 if ( id
.length() > 0 ) {
419 printf("uploaded as id %s\n",id
.c_str());
420 if ( !m_os
->openBrowser((Config::planetRoot()+"?level="+id
).c_str()) ) {
421 showMessage("Unable to launch browser");
424 showMessage("UploadFailed: unknown error");
427 showMessage(std::string("UploadFailed: ")+h
.errorMessage());
433 void setTool( int t
)
438 void editMode( bool set
)
443 void showMessage( const std::string
& msg
)
446 printf("showMessage \"%s\"\n",msg
.c_str());
449 void showOverlay( Overlay
* o
)
455 void hideOverlay( Overlay
* o
)
457 parent()->remove( o
);
462 void setPause(bool pause
)
464 if (pause
== m_paused
) {
469 if ( !m_pauseOverlay
) {
470 m_pauseOverlay
= createIconOverlay( *this, "pause.png", 50, 50 );
472 showOverlay( m_pauseOverlay
);
474 hideOverlay( m_pauseOverlay
);
481 setPause( !m_paused
);
489 void edit( bool doEdit
)
491 if ( m_edit
!= doEdit
) {
494 if ( !m_editOverlay
) {
495 m_editOverlay
= createEditOverlay(*this);
497 showOverlay( m_editOverlay
);
500 hideOverlay( m_editOverlay
);
501 m_strokeFixed
= false;
502 m_strokeSleep
= false;
503 m_strokeDecor
= false;
504 if ( m_colour
< 2 ) m_colour
= 2;
510 Vec2
cursorPoint(Uint16 x
, Uint16 y
)
513 worldToScreen
.inverseTransform( pt
);
517 Vec2
mousePoint( SDL_Event ev
)
519 Vec2
pt( ev
.button
.x
, ev
.button
.y
);
520 worldToScreen
.inverseTransform( pt
);
524 bool handleGameEvent( SDL_Event
&ev
)
528 switch ( ev
.key
.keysym
.sym
) {
538 showOverlay( createMenuOverlay( *this ) );
541 showOverlay( m_cselector
.overlay() );
548 //toggleOverlay( m_demoOverlay );
552 gotoLevel( m_level
);
556 gotoLevel( m_level
+1 );
560 gotoLevel( m_level
-1 );
563 gotoLevel( m_level
, true );
575 bool handleModEvent( SDL_Event
&ev
)
578 //printf("mod=%d\n",ev.key.keysym.sym,mod);
581 //printf("mod key=%x mod=%d\n",ev.key.keysym.sym,mod);
582 if ( ev
.key
.keysym
.sym
== SDLK_F8
) {
583 mod
= 1; //zoom- == middle (delete)
585 } else if ( ev
.key
.keysym
.sym
== SDLK_F7
) {
586 mod
= 2; //zoom+ == right (move)
591 if ( ev
.key
.keysym
.sym
== SDLK_F7
592 || ev
.key
.keysym
.sym
== SDLK_F8
) {
597 case SDL_MOUSEBUTTONDOWN
:
598 case SDL_MOUSEBUTTONUP
:
599 if ( ev
.button
.button
== SDL_BUTTON_LEFT
&& mod
!= 0 ) {
600 ev
.button
.button
= ((mod
==1) ? SDL_BUTTON_MIDDLE
: SDL_BUTTON_RIGHT
);
607 bool handlePlayEvent( SDL_Event
&ev
)
610 case SDL_MOUSEBUTTONDOWN
:
611 if ( ev
.button
.button
== SDL_BUTTON_LEFT
) {
612 if ((SDL_GetModState() & KMOD_SHIFT
) > 0)
614 if(startRope(0, ev
.button
.x
, ev
.button
.y
))
621 if (startStroke(0, ev
.button
.x
, ev
.button
.y
))
628 case SDL_MOUSEBUTTONUP
:
629 if ( ev
.button
.button
== SDL_BUTTON_LEFT
) {
630 if ((SDL_GetModState() & KMOD_SHIFT
) > 0)
639 if (finishStroke(0)) {
645 case SDL_MOUSEMOTION
:
646 if ( m_createStrokes
[0] ) {
647 if ((SDL_GetModState() & KMOD_SHIFT
) > 0)
649 if (extendRope(0, ev
.button
.x
, ev
.button
.y
))
656 if (extendStroke(0, ev
.button
.x
, ev
.button
.y
)) {
663 if ( ev
.key
.keysym
.sym
== SDLK_ESCAPE
) {
669 else if ( m_scene
.deleteStroke( m_scene
.strokes().at(m_scene
.strokes().size()-1) ) ) {
682 bool checkCursorId(int index
)
684 if (index
>= MT_MAX_CURSORS
)
686 fprintf(stderr
, "coursor id %d to high (max %d)\n", index
, MT_MAX_CURSORS
);
693 bool startStroke(int index
, Uint16 x
, Uint16 y
)
695 if (!checkCursorId(index
))
700 if (m_createStrokes
[index
])
702 fprintf(stderr
, "startStroke: stroke %d already started\n", index
);
707 if ( m_strokeFixed
) {
708 attrib
|= ATTRIB_GROUND
;
710 if ( m_strokeSleep
) {
711 attrib
|= ATTRIB_SLEEPING
;
713 if ( m_strokeDecor
) {
714 attrib
|= ATTRIB_DECOR
;
716 m_createStrokes
[index
] = m_scene
.newStroke( Path()&cursorPoint(x
, y
), m_colour
, attrib
);
721 bool extendStroke(int index
, Uint16 x
, Uint16 y
)
723 if (!checkCursorId(index
))
728 if ( !m_createStrokes
[index
] ) {
729 fprintf(stderr
, "extendStroke: stroke %d not yet started\n", index
);
733 m_scene
.extendStroke( m_createStrokes
[index
], cursorPoint(x
, y
) );
737 bool finishStroke(int index
)
739 if (!checkCursorId(index
))
744 if (!m_createStrokes
[index
]) {
745 fprintf(stderr
, "finishStroke: stroke %d not yet started\n", index
);
749 int numPoints
= m_scene
.numPoints(m_createStrokes
[index
]);
750 if (numPoints
< FINISH_THRESHOLD_NUM_POINTS
)
752 fprintf(stderr
, "finishStroke: can't finish stroke with %d < %d points\n", numPoints
, FINISH_THRESHOLD_NUM_POINTS
);
757 if ( m_scene
.activate( m_createStrokes
[index
] ) ) {
758 m_stats
.strokeCount
++;
760 m_stats
.pausedStrokes
++;
763 m_scene
.deleteStroke( m_createStrokes
[index
] );
766 fprintf(stderr
, "finished stroke with %d points\n", numPoints
);
768 m_createStrokes
[index
] = NULL
;
773 bool startRope(int index
, Uint16 x
, Uint16 y
)
775 if(!checkCursorId(index
))
780 if (m_createStrokes
[index
])
782 fprintf(stderr
, "startRope: rope %d already started\n", index
);
787 m_numRopeLength
[index
] = 0;
788 m_numRopeParts
[index
] = 0;
789 m_createStrokes
[index
] = m_scene
.newStroke( Path()&cursorPoint(x
, y
), m_colour
, attrib
);
790 m_ropeParts
[index
][0] = m_createStrokes
[index
];
795 bool extendRope(int index
, Uint16 x
, Uint16 y
)
797 if (!checkCursorId(index
))
802 if ( !m_createStrokes
[index
] ) {
803 fprintf(stderr
, "extendRope: rope %d not yet started\n", index
);
807 m_numRopeLength
[index
]++;
808 m_scene
.extendStroke( m_createStrokes
[index
], cursorPoint(x
, y
) );
810 if (m_numRopeLength
[index
] == 10)
812 nextRopePart(index
, x
, y
);
817 void nextRopePart(int index
, Uint16 x
, Uint16 y
)
819 if (!checkCursorId(index
))
824 if (!m_createStrokes
[index
]) {
825 fprintf(stderr
, "nextRopePart: rope %d not yet started\n", index
);
829 if ( m_scene
.activate( m_createStrokes
[index
] ) ) {
830 m_stats
.strokeCount
++;
832 m_stats
.pausedStrokes
++;
835 m_scene
.deleteStroke( m_createStrokes
[index
] );
838 m_ropeParts
[index
][m_numRopeParts
[index
]++] = m_createStrokes
[index
];
839 m_scene
.setNoMass(m_createStrokes
[index
]);
842 m_numRopeLength
[index
] = 0;
843 m_createStrokes
[index
] = m_scene
.newStroke( Path()&cursorPoint(x
, y
), m_colour
, attrib
);
846 bool finishRope(int index
)
848 if (!checkCursorId(index
))
853 if (!m_createStrokes
[index
]) {
854 fprintf(stderr
, "finishRope: rope %d not yet started\n", index
);
858 if ( m_scene
.activate( m_createStrokes
[index
] ) ) {
859 m_stats
.strokeCount
++;
861 m_stats
.pausedStrokes
++;
864 m_scene
.deleteStroke( m_createStrokes
[index
] );
866 m_createStrokes
[index
] = NULL
;
868 for(int n
=0; n
<m_numRopeParts
[index
]; n
++)
870 m_scene
.setDefaultMass(m_ropeParts
[index
][n
]);
876 bool cancelDraw(int index
)
878 if (!checkCursorId(index
))
883 if ( !m_createStrokes
[index
] )
885 fprintf(stderr
, "cancelDraw: line %d not yet started\n", index
);
889 int numPoints
= m_scene
.numPoints(m_createStrokes
[index
]);
890 if ( numPoints
> CANCEL_THRESHOLD_NUM_POINTS
)
892 fprintf(stderr
, "won't cancel stroke with %d > %d points\n", numPoints
, CANCEL_THRESHOLD_NUM_POINTS
);
896 m_scene
.deleteStroke( m_createStrokes
[index
] );
897 m_createStrokes
[index
] = NULL
;
902 bool handleEditEvent( SDL_Event
&ev
)
904 //allow move/delete in normal play!!
905 //if ( !m_edit ) return false;
908 case SDL_MOUSEBUTTONDOWN
:
909 if ( ev
.button
.button
== SDL_BUTTON_RIGHT
) {
911 if (startMoveStroke(0, ev
.button
.x
, ev
.button
.y
)) {
915 if ( ev
.button
.button
== SDL_BUTTON_MIDDLE
) {
916 if (deleteStroke(ev
.button
.x
, ev
.button
.y
)) {
921 case SDL_MOUSEBUTTONUP
:
922 if ( ev
.button
.button
== SDL_BUTTON_RIGHT
) {
923 if (endMoveStroke(0)) {
928 case SDL_MOUSEMOTION
:
929 if (moveStroke(0, ev
.button
.x
, ev
.button
.y
)) {
939 bool startMoveStroke(int index
, Uint16 x
, Uint16 y
)
941 if (!checkCursorId(index
))
946 if (m_moveStrokes
[index
]) {
950 m_moveStrokes
[index
] = m_scene
.strokeAtPoint( cursorPoint(x
, y
),
953 if (m_moveStrokes
[index
]) {
954 m_scene
.setNoMass(m_moveStrokes
[index
]);
960 bool endMoveStroke(int index
)
962 if (!checkCursorId(index
))
967 if (!m_moveStrokes
[index
]) {
970 m_scene
.setDefaultMass(m_moveStrokes
[index
]);
974 m_moveStrokes
[index
] = NULL
;
978 bool moveStroke(int index
, Uint16 x
, Uint16 y
)
980 if (!checkCursorId(index
))
985 if (!m_moveStrokes
[index
]) {
989 m_scene
.moveStroke( m_moveStrokes
[index
], cursorPoint(x
, y
) );
994 bool deleteStroke(Uint16 x
, Uint16 y
)
996 m_scene
.deleteStroke( m_scene
.strokeAtPoint( cursorPoint(x
, y
),
997 SELECT_TOLERANCE
) );
1002 bool handleMultitouchEvent ( SDL_Event
&ev
)
1005 case SDL_NP_START_STROKE
: {
1006 DrawEvent
* de
= (DrawEvent
*)ev
.user
.data1
;
1007 if (de
== NULL
) { return false; }
1009 startStroke(de
->cursor_id
, de
->x
, de
->y
);
1011 ev
.user
.data1
= NULL
;
1015 case SDL_NP_APPEND_STROKE
: {
1016 DrawEvent
* de
= (DrawEvent
*)ev
.user
.data1
;
1017 if (de
== NULL
) { return false; }
1019 extendStroke(de
->cursor_id
, de
->x
, de
->y
);
1021 ev
.user
.data1
= NULL
;
1025 case SDL_NP_FINISH_STROKE
: {
1026 DrawEvent
* de
= (DrawEvent
*)ev
.user
.data1
;
1027 if (de
== NULL
) { return false; }
1029 finishStroke(de
->cursor_id
);
1031 ev
.user
.data1
= NULL
;
1035 case SDL_NP_START_ROPE
: {
1036 DrawEvent
* de
= (DrawEvent
*)ev
.user
.data1
;
1037 if (de
== NULL
) { return false; }
1039 startRope(de
->cursor_id
, de
->x
, de
->y
);
1041 ev
.user
.data1
= NULL
;
1045 case SDL_NP_APPEND_ROPE
: {
1046 DrawEvent
* de
= (DrawEvent
*)ev
.user
.data1
;
1047 if (de
== NULL
) { return false; }
1049 extendRope(de
->cursor_id
, de
->x
, de
->y
);
1051 ev
.user
.data1
= NULL
;
1055 case SDL_NP_FINISH_ROPE
: {
1056 DrawEvent
* de
= (DrawEvent
*)ev
.user
.data1
;
1057 finishRope(de
->cursor_id
);
1062 case SDL_NP_CANCEL_DRAW
: {
1063 CursorEvent
* ce
= (CursorEvent
*)ev
.user
.data1
;
1064 if (ce
== NULL
) { return false; }
1066 cancelDraw(ce
->cursor_id
);
1068 ev
.user
.data1
= NULL
;
1072 case SDL_NP_START_DRAG
: {
1073 DragEvent
* de
= (DragEvent
*)ev
.user
.data1
;
1074 if (de
== NULL
) { return false; }
1076 startMoveStroke(de
->cursor_id
, de
->x
, de
->y
);
1078 ev
.user
.data1
= NULL
;
1083 DragEvent
* de
= (DragEvent
*)ev
.user
.data1
;
1084 if (de
== NULL
) { return false; }
1086 moveStroke(de
->cursor_id
, de
->x
, de
->y
);
1088 ev
.user
.data1
= NULL
;
1092 case SDL_NP_END_DRAG
: {
1093 DragEvent
* de
= (DragEvent
*)ev
.user
.data1
;
1094 if (de
== NULL
) { return false; }
1096 endMoveStroke(de
->cursor_id
);
1098 ev
.user
.data1
= NULL
;
1108 case SDL_NP_DELETE
: {
1109 DeleteEvent
* de
= (DeleteEvent
*)ev
.user
.data1
;
1110 if (de
== NULL
) { return false; }
1112 deleteStroke(de
->x
, de
->y
);
1114 ev
.user
.data1
= NULL
;
1118 case SDL_NP_PREVIEW_CURSOR
: {
1119 DrawEvent
* de
= (DrawEvent
*)ev
.user
.data1
;
1120 if (de
== NULL
) { return false; }
1122 previewCursor(de
->cursor_id
, de
->x
, de
->y
);
1124 ev
.user
.data1
= NULL
;
1128 case SDL_NP_RESTART_LEVEL
: {
1129 gotoLevel( m_level
);
1133 case SDL_NP_NEXT_LEVEL
: {
1134 gotoLevel( m_level
+1 );
1138 case SDL_NP_PREV_LEVEL
: {
1139 gotoLevel( m_level
-1 );
1143 case SDL_NP_TOGGLE_MENU
: {
1148 case SDL_NP_SHOW_MENU
: {
1153 case SDL_NP_HIDE_MENU
: {
1158 case SDL_NP_TOGGLE_PAUSE
: {
1163 case SDL_NP_PAUSE
: {
1168 case SDL_NP_RESUME
: {
1178 case SDL_NP_TOGGLE_EDITOR
: {
1183 case SDL_NP_REPLAY
: {
1184 gotoLevel( m_level
, true );
1192 bool previewCursor(int cursor_id
, int x
, int y
)
1194 m_window
.previewCursor(cursor_id
, x
, y
);
1198 ////////////////////////////////////////////////////////////////
1200 ////////////////////////////////////////////////////////////////
1202 virtual bool isDirty()
1204 //TODO this can be a bit heavyweight
1205 return !dirtyArea().isEmpty();
1208 virtual Rect
dirtyArea()
1212 return FULLSCREEN_RECT
;
1214 return m_scene
.dirtyArea();
1218 virtual void onTick( int tick
)
1220 if ( !isPaused() ) {
1226 if (m_levelnameHideTime
== -1 && m_levelnameOverlay
) {
1227 showOverlay(m_levelnameOverlay
);
1228 m_levelnameHideTime
= tick
+ 4000;
1229 } else if (m_levelnameHideTime
!= 0 &&
1230 m_levelnameHideTime
<tick
&& m_levelnameOverlay
) {
1231 hideOverlay(m_levelnameOverlay
);
1232 m_levelnameHideTime
= 0;
1236 while ( m_player
.fetchEvent(ev
) ) {
1237 // todo only dispatch play events?
1239 || handleGameEvent(ev
)
1240 || handleEditEvent(ev
)
1241 || handlePlayEvent(ev
)
1242 || handleMultitouchEvent(ev
);
1245 if ( m_isCompleted
&& m_edit
) {
1246 hideOverlay( m_completedOverlay
);
1247 m_isCompleted
= false;
1249 if ( m_scene
.isCompleted() != m_isCompleted
&& !m_edit
) {
1250 m_isCompleted
= m_scene
.isCompleted();
1251 if ( m_isCompleted
) {
1252 m_stats
.endTime
= SDL_GetTicks();
1255 m_completedOverlay
= createNextLevelOverlay(*this, m_scene
.getWinner());
1256 showOverlay( m_completedOverlay
);
1258 hideOverlay( m_completedOverlay
);
1264 for ( char *f
= m_os
->getLaunchFile(); f
; f
=m_os
->getLaunchFile() ) {
1265 if ( strstr(f
,".npz") ) {
1266 //m_levels->empty();
1268 m_levels
->addPath( f
);
1269 int l
= m_levels
->findLevel( f
);
1280 if ( m_completedOverlay
== NULL
) {
1289 m_completedOverlay
= createNextLevelOverlay(*this, -2);
1290 showOverlay( m_completedOverlay
);
1295 m_completedOverlay
= NULL
;
1296 hideOverlay( m_completedOverlay
);
1299 virtual void draw( Canvas
& screen
, const Rect
& area
)
1301 m_scene
.draw( screen
, area
);
1303 screen
.fade( area
);
1307 virtual bool handleEvent( SDL_Event
& ev
)
1309 if ( m_player
.isRunning()
1310 && ( ev
.type
==SDL_MOUSEMOTION
||
1311 ev
.type
==SDL_MOUSEBUTTONDOWN
||
1312 ev
.type
==SDL_MOUSEBUTTONUP
) ) {
1314 } else if (handleModEvent(ev
)
1315 || handleGameEvent(ev
)
1316 || handleEditEvent(ev
)
1317 || handlePlayEvent(ev
)
1318 || handleMultitouchEvent(ev
)) {
1319 //\TODO only record edit,play events etc
1320 m_recorder
.record( ev
);
1326 virtual Window
* getWindow() {
1333 Widget
* createGameLayer( Levels
* levels
, int width
, int height
, bool fullscreen
)
1335 return new Game(levels
,width
,height
,fullscreen
);