1 #ifndef ENT_SKATESHOP_C
2 #define ENT_SKATESHOP_C
6 #include "vg/vg_steam_ugc.h"
7 #include "ent_skateshop.h"
14 * Checks string equality but does a hash check first
16 static inline int const_str_eq( u32 hash
, const char *str
, const char *cmp
)
18 if( hash
== vg_strdjb2(cmp
) )
19 if( !strcmp( str
, cmp
) )
25 * Get an existing cache instance, allocate a new one to be loaded, or NULL if
28 VG_STATIC
struct cache_board
*skateshop_cache_fetch( u32 registry_index
)
30 struct registry_board
*reg
= NULL
;
32 if( registry_index
< global_skateshop
.registry_count
){
33 reg
= &global_skateshop
.registry
[ registry_index
];
36 return reg
->cache_ptr
;
40 /* lru eviction. should be a linked list maybe... */
41 double min_time
= 1e300
;
42 struct cache_board
*min_board
= NULL
;
44 SDL_AtomicLock( &global_skateshop
.sl_cache_access
);
45 for( u32 i
=0; i
<SKATESHOP_BOARD_CACHE_MAX
; i
++ ){
46 struct cache_board
*cache_ptr
= &global_skateshop
.cache
[i
];
48 if( cache_ptr
->state
== k_cache_board_state_load_request
) continue;
49 if( cache_ptr
->ref_count
) continue;
51 if( cache_ptr
->last_use_time
< min_time
){
52 min_time
= cache_ptr
->last_use_time
;
53 min_board
= cache_ptr
;
58 if( min_board
->state
== k_cache_board_state_loaded
){
59 struct registry_board
*other
=
60 &global_skateshop
.registry
[ min_board
->registry_id
];
62 vg_info( "Deallocating board: '%s'\n", min_board
, other
->filename
);
64 player_board_unload( &min_board
->board
);
65 other
->cache_ptr
= NULL
;
69 vg_info( "Allocating board (reg:%u) '%s'\n",
70 registry_index
, reg
->filename
);
73 vg_info( "Pre-allocating board (reg:%u) 'null'\n", registry_index
);
76 min_board
->registry_id
= registry_index
;
77 min_board
->last_use_time
= vg
.time
;
78 min_board
->ref_count
= 0;
79 min_board
->state
= k_cache_board_state_load_request
;
82 vg_error( "No free boards to load registry!\n" );
85 SDL_AtomicUnlock( &global_skateshop
.sl_cache_access
);
89 VG_STATIC
void skateshop_update_viewpage(void)
91 u32 page
= global_skateshop
.selected_registry_id
/SKATESHOP_VIEW_SLOT_MAX
;
93 for( u32 i
=0; i
<SKATESHOP_VIEW_SLOT_MAX
; i
++ ){
94 struct shop_view_slot
*slot
= &global_skateshop
.shop_view_slots
[i
];
95 u32 request_id
= page
*SKATESHOP_VIEW_SLOT_MAX
+ i
;
97 if( slot
->cache_ptr
) unwatch_cache_board( slot
->cache_ptr
);
99 slot
->cache_ptr
= skateshop_cache_fetch( request_id
);
100 if( slot
->cache_ptr
) watch_cache_board( slot
->cache_ptr
);
104 /* generic reciever */
105 VG_STATIC
void workshop_async_any_complete( void *data
, u32 size
)
111 * op/subroutine: k_workshop_op_item_load
112 * -----------------------------------------------------------------------------
116 * Reciever for board completion; only promotes the status in the main thread
118 VG_STATIC
void skateshop_async_board_loaded( void *payload
, u32 size
)
120 SDL_AtomicLock( &global_skateshop
.sl_cache_access
);
121 struct cache_board
*cache_ptr
= payload
;
122 cache_ptr
->last_use_time
= vg
.time
;
123 cache_ptr
->state
= k_cache_board_state_loaded
;
125 struct registry_board
*reg
=
126 &global_skateshop
.registry
[ cache_ptr
->registry_id
];
127 reg
->cache_ptr
= cache_ptr
;
128 SDL_AtomicUnlock( &global_skateshop
.sl_cache_access
);
130 vg_success( "Async board loaded (%s)\n", reg
->filename
);
134 * Thread(or subroutine of thread), for checking view slots that weve installed.
135 * Load the model if a view slot wants it
137 VG_STATIC
void workshop_visibile_load_loop_thread( void *_args
)
140 for( u32 i
=0; i
<SKATESHOP_BOARD_CACHE_MAX
; i
++ ){
141 struct cache_board
*cache_ptr
= &global_skateshop
.cache
[i
];
143 SDL_AtomicLock( &global_skateshop
.sl_cache_access
);
144 if( cache_ptr
->state
== k_cache_board_state_load_request
){
145 if( cache_ptr
->registry_id
>= global_skateshop
.registry_count
){
146 /* should maybe have a different value for this case */
147 cache_ptr
->state
= k_cache_board_state_none
;
148 SDL_AtomicUnlock( &global_skateshop
.sl_cache_access
);
152 /* continue with the request */
153 SDL_AtomicUnlock( &global_skateshop
.sl_cache_access
);
155 struct registry_board
*reg
=
156 &global_skateshop
.registry
[ cache_ptr
->registry_id
];
158 if( reg
->workshop_id
){
159 vg_async_item
*call
=
160 vg_async_alloc( sizeof(struct async_workshop_filepath_info
) );
162 struct async_workshop_filepath_info
*info
= call
->payload
;
164 info
->id
= reg
->workshop_id
;
165 info
->len
= vg_list_size(path
) - strlen("/board.mdl")-1;
166 vg_async_dispatch( call
, async_workshop_get_filepath
);
167 vg_async_stall(); /* too bad! */
169 if( path
[0] == '\0' ){
170 SDL_AtomicLock( &global_skateshop
.sl_cache_access
);
171 cache_ptr
->state
= k_cache_board_state_none
;
172 SDL_AtomicUnlock( &global_skateshop
.sl_cache_access
);
174 vg_error( "Failed SteamAPI_GetItemInstallInfo(" PRINTF_U64
")\n",
179 strcat( path
, "/board.mdl" );
183 snprintf( path
, 256, "models/boards/%s", reg
->filename
);
186 player_board_load( &cache_ptr
->board
, path
);
187 vg_async_call( skateshop_async_board_loaded
, cache_ptr
, 0 );
190 SDL_AtomicUnlock( &global_skateshop
.sl_cache_access
);
192 vg_async_call( workshop_async_any_complete
, NULL
, 0 );
196 * op: k_workshop_op_item_scan
197 * -----------------------------------------------------------------------------
201 * Reciever for scan completion. copies the registry_count back into t0
203 VG_STATIC
void workshop_async_reg_update( void *data
, u32 size
)
205 vg_info( "Registry update notify\n" );
206 global_skateshop
.registry_count
= global_skateshop
.t1_registry_count
;
209 VG_STATIC
void workshop_steam_scan(void)
212 * Steam workshop scan
214 vg_info( "Scanning steam workshop for boards\n" );
215 PublishedFileId_t workshop_ids
[ SKATESHOP_REGISTRY_MAX
];
216 u32 workshop_count
= SKATESHOP_REGISTRY_MAX
;
218 vg_async_item
*call
= vg_async_alloc(
219 sizeof(struct async_workshop_installed_files_info
));
220 struct async_workshop_installed_files_info
*info
= call
->payload
;
221 info
->buffer
= workshop_ids
;
222 info
->len
= &workshop_count
;
223 vg_async_dispatch( call
, async_workshop_get_installed_files
);
226 for( u32 j
=0; j
<workshop_count
; j
++ ){
227 PublishedFileId_t id
= workshop_ids
[j
];
229 for( u32 i
=0; i
<global_skateshop
.t1_registry_count
; i
++ ){
230 struct registry_board
*reg
= &global_skateshop
.registry
[i
];
232 if( reg
->workshop_id
== id
){
233 reg
->state
= k_registry_board_state_indexed
;
234 goto next_file_workshop
;
238 if( global_skateshop
.t1_registry_count
== SKATESHOP_REGISTRY_MAX
){
239 vg_error( "You have too many boards installed!\n" );
243 vg_info( "new listing from the steam workshop!: "PRINTF_U64
"\n", id
);
245 struct registry_board
*reg
= &global_skateshop
.registry
[
246 global_skateshop
.t1_registry_count
++ ];
248 reg
->cache_ptr
= NULL
;
249 snprintf( reg
->filename
, 64, PRINTF_U64
, id
);
250 reg
->filename_hash
= vg_strdjb2( reg
->filename
);
251 reg
->workshop_id
= id
;
252 reg
->state
= k_registry_board_state_indexed
;
254 workshop_file_info_clear( ®
->workshop
);
255 strcpy( reg
->workshop
.title
, "Workshop file" );
257 /* load the metadata off the disk */
258 vg_async_item
*call
=
259 vg_async_alloc( sizeof(struct async_workshop_filepath_info
) );
261 const char *meta_file
= "/board.mdl.inf";
263 struct async_workshop_filepath_info
*info
= call
->payload
;
265 info
->id
= reg
->workshop_id
;
266 info
->len
= vg_list_size(path
) - strlen(meta_file
)-1;
267 vg_async_dispatch( call
, async_workshop_get_filepath
);
268 vg_async_stall(); /* too bad! */
270 strcat( path
, meta_file
);
271 workshop_load_metadata( path
, ®
->workshop
);
278 * Async thread which scans local files for boards, as well as scheduling
279 * synchronous calls to the workshop
281 VG_STATIC
void workshop_scan_thread( void *_args
)
283 vg_linear_clear( vg_mem
.scratch
);
285 for( u32 i
=0; i
<global_skateshop
.t1_registry_count
; i
++ ){
286 struct registry_board
*reg
= &global_skateshop
.registry
[i
];
287 reg
->state
= k_registry_board_state_indexed_absent
;
293 vg_info( "Scanning models/boards/*.mdl\n" );
295 tinydir_open( &dir
, "models/boards" );
297 while( dir
.has_next
){
299 tinydir_readfile( &dir
, &file
);
302 u32 hash
= vg_strdjb2( file
.name
);
304 for( u32 i
=0; i
<global_skateshop
.t1_registry_count
; i
++ ){
305 struct registry_board
*reg
= &global_skateshop
.registry
[i
];
307 if( const_str_eq( hash
, file
.name
, reg
->filename
) ){
308 reg
->state
= k_registry_board_state_indexed
;
313 if( global_skateshop
.t1_registry_count
== SKATESHOP_REGISTRY_MAX
){
314 vg_error( "You have too many boards installed!\n" );
318 vg_info( "new listing!: %s\n", file
.name
);
320 struct registry_board
*reg
=
321 &global_skateshop
.registry
[global_skateshop
.t1_registry_count
++];
323 reg
->cache_ptr
= NULL
;
324 vg_strncpy( file
.name
, reg
->filename
, 64, k_strncpy_always_add_null
);
325 vg_strncpy( file
.name
, reg
->workshop
.title
,
326 64, k_strncpy_always_add_null
);
327 reg
->filename_hash
= hash
;
328 reg
->workshop_id
= 0;
329 reg
->state
= k_registry_board_state_indexed
;
330 reg
->workshop
.author
= 0;
331 strcpy( reg
->workshop
.author_name
, "custom" );
334 next_file
: tinydir_next( &dir
);
339 if( steam_ready
) workshop_steam_scan();
341 vg_async_call( workshop_async_reg_update
, NULL
, 0 );
343 workshop_visibile_load_loop_thread(NULL
);
347 * Asynchronous scan of local disk for items and add them to the registry
349 VG_STATIC
void workshop_op_item_scan(void)
351 skaterift_begin_op( k_workshop_op_item_scan
);
352 vg_loader_start( workshop_scan_thread
, NULL
);
357 * -----------------------------------------------------------------------------
360 /* we can only keep using a viewslot pointer for multiple frames if we watch it
361 * using this function */
362 VG_STATIC
void watch_cache_board( struct cache_board
*ptr
)
364 if( ptr
->ref_count
>= 32 ){
365 vg_fatal_error( "dynamic board watch missmatch (limit is 32)\n" );
368 ptr
->last_use_time
= vg
.time
;
372 /* after this is called, the calling code only has access to the pointer for the
373 * duration of the rest of the frame */
374 VG_STATIC
void unwatch_cache_board( struct cache_board
*ptr
)
376 if( ptr
->ref_count
== 0 ){
377 vg_fatal_error( "dynamic board unwatch missmatch (no watchers)\n" );
384 * Callback handler for persona state changes,
385 * it sets the author names on the registries
387 VG_STATIC
void callback_persona_statechange( CallbackMsg_t
*msg
)
389 PersonaStateChange_t
*info
= (PersonaStateChange_t
*)msg
->m_pubParam
;
390 ISteamFriends
*hSteamFriends
= SteamAPI_SteamFriends();
392 if( info
->m_nChangeFlags
& k_EPersonaChangeName
){
393 for( u32 i
=0; i
<global_skateshop
.registry_count
; i
++ ){
394 struct registry_board
*reg
= &global_skateshop
.registry
[i
];
395 if( reg
->workshop
.author
== info
->m_ulSteamID
){
396 const char *name
= SteamAPI_ISteamFriends_GetFriendPersonaName(
397 hSteamFriends
, info
->m_ulSteamID
);
398 str_utf8_collapse( name
, reg
->workshop
.author_name
, 32 );
407 VG_STATIC
void skateshop_init(void)
409 u32 reg_size
= sizeof(struct registry_board
)*SKATESHOP_REGISTRY_MAX
,
410 cache_size
= sizeof(struct cache_board
)*SKATESHOP_BOARD_CACHE_MAX
;
412 global_skateshop
.registry
= vg_linear_alloc( vg_mem
.rtmemory
, reg_size
);
413 global_skateshop
.registry_count
= 0;
414 global_skateshop
.cache
= vg_linear_alloc( vg_mem
.rtmemory
, cache_size
);
416 memset( global_skateshop
.cache
, 0, cache_size
);
418 for( u32 i
=0; i
<SKATESHOP_BOARD_CACHE_MAX
; i
++ ){
419 struct cache_board
*board
= &global_skateshop
.cache
[i
];
420 board
->state
= k_cache_board_state_none
;
421 board
->registry_id
= 0xffffffff;
422 board
->last_use_time
= -99999.9;
423 board
->ref_count
= 0;
427 steam_register_callback( k_iPersonaStateChange
,
428 callback_persona_statechange
);
432 VG_STATIC
struct cache_board
*skateshop_selected_cache_if_loaded(void)
434 if( global_skateshop
.registry_count
> 0 ){
435 u32 reg_id
= global_skateshop
.selected_registry_id
;
436 struct registry_board
*reg
= &global_skateshop
.registry
[ reg_id
];
438 SDL_AtomicLock( &global_skateshop
.sl_cache_access
);
439 if( reg
->cache_ptr
&&
440 (reg
->cache_ptr
->state
== k_cache_board_state_loaded
) )
442 SDL_AtomicUnlock( &global_skateshop
.sl_cache_access
);
443 return reg
->cache_ptr
;
445 SDL_AtomicUnlock( &global_skateshop
.sl_cache_access
);
454 void temp_update_playermodel(void);
455 VG_STATIC
void global_skateshop_preupdate(void)
457 float rate
= vg_minf( 1.0f
, vg
.time_frame_delta
* 2.0f
);
458 global_skateshop
.factive
= vg_lerpf( global_skateshop
.factive
,
459 global_skateshop
.active
, rate
);
461 if( !global_skateshop
.active
) return;
463 world_instance
*world
= get_active_world();
465 ent_skateshop
*shop
= global_skateshop
.ptr_ent
;
467 /* camera positioning */
468 ent_camera
*ref
= mdl_arritm( &world
->ent_camera
,
469 mdl_entity_id_id(shop
->id_camera
) );
471 v3f dir
= {0.0f
,-1.0f
,0.0f
};
472 mdl_transform_vector( &ref
->transform
, dir
, dir
);
473 m3x3_mulv( localplayer
.invbasis
, dir
, dir
);
474 player_vector_angles( localplayer
.cam_override_angles
, dir
, 1.0f
, 0.0f
);
477 if( shop
->type
== k_skateshop_type_boardshop
){
478 ent_marker
*display
= mdl_arritm( &world
->ent_marker
,
479 mdl_entity_id_id(shop
->boards
.id_display
) );
481 v3_sub( display
->transform
.co
, localplayer
.rb
.co
, lookat
);
484 else if( shop
->type
== k_skateshop_type_charshop
){
485 v3_sub( ref
->transform
.co
, localplayer
.rb
.co
, lookat
);
488 vg_fatal_error( "Unknown store (%u)\n", shop
->type
);
491 q_axis_angle( localplayer
.rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
},
492 atan2f(lookat
[0],lookat
[2]) );
494 v3_copy( ref
->transform
.co
, localplayer
.cam_override_pos
);
495 localplayer
.cam_override_fov
= ref
->fov
;
496 localplayer
.cam_override_strength
= global_skateshop
.factive
;
499 if( shop
->type
== k_skateshop_type_boardshop
){
500 gui_helper_action( axis_display_string( k_sraxis_mbrowse_h
), "browse" );
501 gui_helper_action( button_display_string( k_srbind_mback
), "exit" );
503 struct cache_board
*selected_cache
= skateshop_selected_cache_if_loaded();
505 if( selected_cache
){
506 gui_helper_action( button_display_string( k_srbind_maccept
), "pick" );
511 * ----------------------
514 if( button_down( k_srbind_mleft
) ){
515 if( global_skateshop
.selected_registry_id
> 0 ){
516 global_skateshop
.selected_registry_id
--;
520 if( button_down( k_srbind_mright
) ){
521 if( global_skateshop
.selected_registry_id
+1 <
522 global_skateshop
.registry_count
)
524 global_skateshop
.selected_registry_id
++;
528 if( selected_cache
&& button_down( k_srbind_maccept
) ){
529 vg_info( "chose board from skateshop (%u)\n",
530 global_skateshop
.selected_registry_id
);
532 if( localplayer
.board_view_slot
){
533 unwatch_cache_board( localplayer
.board_view_slot
);
536 localplayer
.board_view_slot
= selected_cache
;
537 watch_cache_board( localplayer
.board_view_slot
);
539 global_skateshop_exit();
543 else if( shop
->type
== k_skateshop_type_charshop
){
544 gui_helper_action( axis_display_string( k_sraxis_mbrowse_h
), "browse" );
545 gui_helper_action( button_display_string( k_srbind_mback
), "exit" );
546 gui_helper_action( button_display_string( k_srbind_maccept
), "pick" );
548 if( button_down( k_srbind_mleft
) ){
549 if( cl_playermdl_id
> 0 ){
553 cl_playermdl_id
= 2; /* HACK */
555 temp_update_playermodel(); /* HACK */
558 if( button_down( k_srbind_mright
) ){
559 if( cl_playermdl_id
+1 < 3 ){
563 cl_playermdl_id
= 0; /* HACK */
565 temp_update_playermodel(); /* HACK */
569 if( button_down( k_srbind_maccept
) ){
570 global_skateshop_exit();
574 vg_fatal_error( "Unknown store (%u)\n", shop
->type
);
577 if( button_down( k_srbind_mback
) ){
578 global_skateshop_exit();
583 VG_STATIC
void skateshop_render_boardshop(void)
585 world_instance
*world
= get_active_world();
586 ent_skateshop
*shop
= global_skateshop
.ptr_ent
;
588 u32 slot_count
= vg_list_size(global_skateshop
.shop_view_slots
);
590 ent_marker
*mark_rack
= mdl_arritm( &world
->ent_marker
,
591 mdl_entity_id_id(shop
->boards
.id_rack
)),
592 *mark_display
= mdl_arritm( &world
->ent_marker
,
593 mdl_entity_id_id(shop
->boards
.id_display
));
595 int visibility
[ SKATESHOP_VIEW_SLOT_MAX
];
596 SDL_AtomicLock( &global_skateshop
.sl_cache_access
);
597 for( u32 i
=0; i
<SKATESHOP_VIEW_SLOT_MAX
; i
++ ){
598 struct shop_view_slot
*slot
= &global_skateshop
.shop_view_slots
[i
];
602 if( slot
->cache_ptr
== NULL
) visibility
[i
] = 0;
603 else if( slot
->cache_ptr
->state
!= k_cache_board_state_loaded
)
606 SDL_AtomicUnlock( &global_skateshop
.sl_cache_access
);
608 /* Render loaded boards in the view slots */
609 for( u32 i
=0; i
<slot_count
; i
++ ){
610 struct shop_view_slot
*slot
= &global_skateshop
.shop_view_slots
[i
];
611 float selected
= 0.0f
;
613 if( !visibility
[i
] ) goto fade_out
;
616 transform_identity( &xform
);
618 xform
.co
[0] = -((float)i
- ((float)slot_count
)*0.5f
)*0.45f
;
619 mdl_transform_mul( &mark_rack
->transform
, &xform
, &xform
);
621 if( slot
->cache_ptr
->registry_id
==
622 global_skateshop
.selected_registry_id
){
626 float t
= slot
->view_blend
;
627 v3_lerp( xform
.co
, mark_display
->transform
.co
, t
, xform
.co
);
628 q_nlerp( xform
.q
, mark_display
->transform
.q
, t
, xform
.q
);
629 v3_lerp( xform
.s
, mark_display
->transform
.s
, t
, xform
.s
);
632 mdl_transform_m4x3( &xform
, mmdl
);
633 render_board( &main_camera
, world
, &slot
->cache_ptr
->board
, mmdl
,
634 k_board_shader_entity
);
637 float rate
= 5.0f
*vg
.time_delta
;
638 slot
->view_blend
= vg_lerpf( slot
->view_blend
, selected
, rate
);
641 ent_marker
*mark_info
= mdl_arritm( &world
->ent_marker
,
642 mdl_entity_id_id(shop
->boards
.id_info
));
644 mdl_transform_m4x3( &mark_info
->transform
, mtext
);
645 mdl_transform_m4x3( &mark_rack
->transform
, mrack
);
648 const char *text_title
= "Fish - Title";
649 const char *text_author
= "by Shaniqua";
653 m4x3_identity( mlocal
);
658 font3d_bind( &world_global
.font
, &main_camera
);
659 shader_model_font_uColour( (v4f
){1.0f
,1.0f
,1.0f
,1.0f
} );
662 * ------------------------------------------------------------------ */
664 v3_zero( mlocal
[3] );
665 mlocal
[0][0] = -scale
*2.0f
;
666 mlocal
[1][2] = -scale
*2.0f
;
667 mlocal
[2][1] = -thickness
;
668 mlocal
[3][2] = -0.7f
;
669 m4x3_mul( mrack
, mlocal
, mmdl
);
671 if( global_skateshop
.registry_count
== 0 ){
672 font3d_simple_draw( &world_global
.font
, 0,
673 "Nothing installed", &main_camera
, mmdl
);
678 i
+=highscore_intl( buf
+i
, global_skateshop
.selected_registry_id
+1, 3 );
680 i
+=highscore_intl( buf
+i
, global_skateshop
.registry_count
, 3 );
683 font3d_simple_draw( &world_global
.font
, 0, buf
, &main_camera
, mmdl
);
686 struct cache_board
*cache_ptr
= skateshop_selected_cache_if_loaded();
687 if( !cache_ptr
) return;
689 struct registry_board
*reg
=
690 &global_skateshop
.registry
[cache_ptr
->registry_id
];
691 struct workshop_file_info
*info
= ®
->workshop
;
694 * ----------------------------------------------------------------- */
696 m3x3_setdiagonalv3( mlocal
, (v3f
){ scale
, scale
, thickness
} );
697 mlocal
[3][0] = -font3d_string_width( &world_global
.font
, 0, info
->title
);
698 mlocal
[3][0] *= scale
*0.5f
;
700 m4x3_mul( mtext
, mlocal
, mmdl
);
701 font3d_simple_draw( &world_global
.font
, 0, info
->title
, &main_camera
, mmdl
);
704 * ----------------------------------------------------------------- */
706 m3x3_setdiagonalv3( mlocal
, (v3f
){ scale
, scale
, thickness
} );
707 mlocal
[3][0] = -font3d_string_width( &world_global
.font
, 0,
709 mlocal
[3][0] *= scale
*0.5f
;
711 m4x3_mul( mtext
, mlocal
, mmdl
);
712 font3d_simple_draw( &world_global
.font
, 0,
713 info
->author_name
, &main_camera
, mmdl
);
716 VG_STATIC
void skateshop_render_charshop(void)
721 * World: render event
723 VG_STATIC
void skateshop_render(void)
725 if( !global_skateshop
.active
) return;
727 ent_skateshop
*shop
= global_skateshop
.ptr_ent
;
729 if( shop
->type
== k_skateshop_type_boardshop
){
730 skateshop_render_boardshop();
732 else if( shop
->type
== k_skateshop_type_charshop
){
733 skateshop_render_charshop();
736 vg_fatal_error( "Unknown store (%u)\n", shop
->type
);
741 * Entity logic: entrance event
743 VG_STATIC
void ent_skateshop_call( world_instance
*world
, ent_call
*call
)
745 u32 index
= mdl_entity_id_id( call
->id
);
746 ent_skateshop
*shop
= mdl_arritm( &world
->ent_skateshop
, index
);
747 vg_info( "skateshop_call\n" );
749 if( menu
.active
) return;
750 if( skaterift
.async_op
!= k_async_op_none
) return;
752 if( call
->function
== k_ent_function_trigger
){
753 if( localplayer
.subsystem
!= k_player_subsystem_walk
){
757 vg_info( "Entering skateshop\n" );
759 localplayer
.immobile
= 1;
760 menu
.disable_open
= 1;
761 global_skateshop
.active
= 1;
763 v3_zero( localplayer
.rb
.v
);
764 v3_zero( localplayer
.rb
.w
);
765 localplayer
._walk
.move_speed
= 0.0f
;
766 global_skateshop
.ptr_ent
= shop
;
768 if( shop
->type
== k_skateshop_type_boardshop
){
769 skateshop_update_viewpage();
770 workshop_op_item_scan();
776 * Entity logic: exit event
778 VG_STATIC
void global_skateshop_exit(void)
780 vg_info( "exit skateshop\n" );
781 localplayer
.immobile
= 0;
782 global_skateshop
.active
= 0;
783 menu
.disable_open
= 0;
784 srinput
.ignore_input_frames
= 2;
787 #endif /* ENT_SKATESHOP_C */