Ok, finally did some code for new sound support. I prefer to submit it here before committing :p Only server-side code is here, client or client/server one isn't there yet. Attached a diff, and a sounds.c that should go into common. Sound works like that: * add to archetypes something like: Object waybread ... soundinfo apply eat_waybread 100 <- a sound name, and a probability. endsoundinfo end * create a 'sound_arch' file in share/ directory, put sound eat_waybread endsound That should be enough to get a (wrong) sound when eating a waybread. Code-wise: * items have a 'sounds' field, containing for some event codes the sound(s) to be played. Multiple sounds per event, random one chosen (or none played, depending on total probability) * a 'sound_cache' field helps know quickly if a sound is defined or not for an event * right now, only events are 'death', 'move', 'apply', and only that one is used (from manual_apply). There are #define in sounds.h for those codes, and an array with 'readable' names in (new) common/sounds.c * if a sound has no sounds for an event type, archetype is checked. * when loading, sound info is cleared, since archetype is used by default. * also, sounds structure is always saved if not null. Because if not null it means item has a special sound structure, so should be saved. what needs yet to be done: * change the collect script to get merge sound info from (yet to be done) .snd files * make a way for client to get that list * add a field for 'new sound support' to NewSocket, for backwards compatibility Ryo -------------- next part -------------- Index: common/init.c =================================================================== RCS file: /cvsroot/crossfire/crossfire/common/init.c,v retrieving revision 1.36 diff -u -r1.36 init.c --- common/init.c 8 May 2004 13:38:04 -0000 1.36 +++ common/init.c 15 May 2004 09:51:36 -0000 @@ -176,6 +176,7 @@ init_objects(); init_vars(); init_block(); + init_sounds( ); ReadBmapNames (); ReadSmooth(); init_anim(); /* Must be after we read in the bitmaps */ Index: common/loader.l =================================================================== RCS file: /cvsroot/crossfire/crossfire/common/loader.l,v retrieving revision 1.57 diff -u -r1.57 loader.l --- common/loader.l 26 Mar 2004 21:59:28 -0000 1.57 +++ common/loader.l 15 May 2004 09:51:42 -0000 @@ -479,6 +479,7 @@ %x MESSAGE %x LORE %x SCRIPT +%x SOUNDINFO /* Don't have to link with -lfl with this */ %option noyywrap @@ -565,7 +566,11 @@ tmp=get_object(); tmp->arch = find_archetype(yval()); if (tmp->arch!=NULL) - copy_object(&tmp->arch->clone,tmp); + { + copy_object(&tmp->arch->clone,tmp); + /* Remove soundinfo */ + free_soundinfo_for_object( tmp ); + } strcpy(msgbuf, ""); strcpy(lorebuf, ""); lex_load(tmp, map_flags); @@ -574,7 +579,12 @@ /* This is the actual archetype definition then */ else { op->arch=find_archetype(yval()); - if (op->arch!=NULL) copy_object(&op->arch->clone,op); + if (op->arch!=NULL) + { + copy_object(&op->arch->clone,op); + /* Remove soundinfo */ + free_soundinfo_for_object( op ); + } } } @@ -1150,6 +1160,10 @@ }; } +^soundinfo{WS}$ { BEGIN( SOUNDINFO ); } +<SOUNDINFO>.* { read_sound_info( op, yytext ); } +<SOUNDINFO>^endsoundinfo$ { BEGIN( INITIAL ); } + <*>(^{WS}$)|\n {/* ignore empty lines, newlines we don't do above */} #.*\n {} @@ -1506,6 +1520,31 @@ } + if ( op->sounds ) + { + soundinfo* info; + const char* name; + int sound; + + FAST_STRCAT( fastbuf, "soundinfo\n" ); + + for ( info = op->sounds; info; info = info->next ) + { + name = get_sound_event_name( info->type ); + for ( sound = 0; sound < info->count; sound++ ) + { + FAST_STRCAT( fastbuf, name ); + FAST_STRCAT( fastbuf, " " ); + FAST_STRCAT( fastbuf, get_sound_name( info->sounds[ sound ] ) ); + FAST_STRCAT( fastbuf, " " ); + FAST_STRCAT( fastbuf, ltostr10( info->chance[ sound ] ) ); + FAST_STRCAT( fastbuf, "\n" ); + } + } + + FAST_STRCAT( fastbuf, "endsoundinfo\n" ); + } + if (op->animation_id != op2->animation_id) { if (op->animation_id) { ADD_STRINGLINE_ENTRY(fastbuf,"animation ",animations[GET_ANIM_ID(op)].name,10); @@ -1840,9 +1879,3 @@ } return NULL; } - - - - - - Index: common/object.c =================================================================== RCS file: /cvsroot/crossfire/crossfire/common/object.c,v retrieving revision 1.86 diff -u -r1.86 object.c --- common/object.c 14 Apr 2004 07:24:30 -0000 1.86 +++ common/object.c 15 May 2004 09:51:48 -0000 @@ -479,6 +479,7 @@ op->lore = NULL; op->current_weapon_script = NULL; op->events=NULL; + op->sounds = NULL; clear_object(op); } /* @@ -507,6 +508,16 @@ } op->events = NULL; + while ( op->sounds ) + { + soundinfo* info = op->sounds->next; + free( op->sounds->sounds ); + free( op->sounds->chance ); + free( op->sounds ); + + op->sounds = info; + } + op->sounds = NULL; /* the memset will clear all these values for us, but we need * to reduce the refcount on them. @@ -565,6 +576,7 @@ void copy_object(object *op2, object *op) { int is_freed=QUERY_FLAG(op,FLAG_FREED),is_removed=QUERY_FLAG(op,FLAG_REMOVED); event *evt, *evt2, *evt_new; + soundinfo* info; if(op->name!=NULL) free_string(op->name); if(op->name_pl!=NULL) free_string(op->name_pl); @@ -589,6 +601,8 @@ } op->events = NULL; + free_soundinfo_for_object( op ); + (void) memcpy((void *)((char *) op +offsetof(object,name)), (void *)((char *) op2+offsetof(object,name)), sizeof(object)-offsetof(object, name)); @@ -629,7 +643,23 @@ evt2 = evt_new; } - + + /* Copy sound info */ + info = op2->sounds; + op->sounds = NULL; + while ( info ) + { + soundinfo* new = ( soundinfo* )malloc( sizeof( soundinfo ) ); + memcpy( new, info, sizeof( soundinfo ) ); + new->sounds = ( int* )malloc( new->count * sizeof( int ) ); + memcpy( new->sounds, info->sounds, sizeof( int ) * new->count ); + new->chance = ( int* )malloc( new->count * sizeof( int ) ); + memcpy( new->chance, info->chance, sizeof( int ) * new->count ); + new->next = op->sounds; + op->sounds = new; + info = info->next; + } + update_ob_speed(op); } @@ -709,6 +739,7 @@ op->prev=NULL; op->active_next = NULL; op->active_prev = NULL; + op->sounds = NULL; if(objects!=NULL) objects->prev=op; objects=op; Index: include/libproto.h =================================================================== RCS file: /cvsroot/crossfire/crossfire/include/libproto.h,v retrieving revision 1.56 diff -u -r1.56 libproto.h --- include/libproto.h 28 Apr 2004 22:04:09 -0000 1.56 +++ include/libproto.h 15 May 2004 09:55:40 -0000 @@ -414,3 +414,11 @@ extern void save_object(FILE *fp, object *op, int flag); extern void insert_event(object *op, int etype, char *ehook, char *eplug, char *eoptions); extern event *find_event(object *op, int etype); +/* sounds.c */ +int init_sounds( ); +int get_sound_event_count( ); +extern void read_sound_info( object* op, const char* line ); +void play_object_sound( object* ob, int sound_type, object* onlyfor ); +void free_soundinfo_for_object( object* ob ); +const char* get_sound_name( int sound_number ); +const char* get_sound_event_name( int event_code ); Index: include/object.h =================================================================== RCS file: /cvsroot/crossfire/crossfire/include/object.h,v retrieving revision 1.34 diff -u -r1.34 object.h --- include/object.h 16 Feb 2004 18:05:32 -0000 1.34 +++ include/object.h 15 May 2004 09:55:41 -0000 @@ -52,6 +52,19 @@ struct _event *next; } event; +/** + * This contains information for one sound event type. + */ +typedef struct _soundinfo + { + int type; + int count; + int total_chance; + int* sounds; + int* chance; + struct _soundinfo* next; + } soundinfo; + /* Definition for WILL_APPLY values. Replaces having harcoded values * sprinkled in the code. Note that some of these also replace fields * that were in the can_apply area. What is the point of having both @@ -219,6 +232,9 @@ char *custom_name; /* Custom name assigned by player */ + soundinfo* sounds; /* Object sounds */ + int sound_cache[ 1 ]; /* Flags for sound events */ + } object; typedef struct oblnk { /* Used to link together several objects */ Index: include/sounds.h =================================================================== RCS file: /cvsroot/crossfire/crossfire/include/sounds.h,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 sounds.h --- include/sounds.h 2 Apr 1999 19:10:04 -0000 1.1.1.1 +++ include/sounds.h 15 May 2004 09:55:42 -0000 @@ -51,4 +51,27 @@ /* NROF_SOUNDS is defined in "defines.h". Don't forget to change this number * if you add or remove any sound. */ + +/** + * New sound event mechanism: + * like plugin events, define event types. Items will have 'soundinfo' blocks + * with all needed info. + * Note that you need to make those define match with sound_events[ ] (in common/sounds.c). + */ + +#define SE_DEATH 0 +#define SE_MOVE 1 +#define SE_APPLY 2 + +/** + * Sound event cache: to avoid going through the sound lists, just cache values + */ + +#define QUERY_SE( xyz, p ) \ + ((xyz)->sound_cache[ p / 32 ] & ( 1U << ( p % 32 ) ) ) +#define SET_SE(xyz, p) \ + ((xyz)->sound_cache[p/32] |= (1U << (p % 32))) +#define CLEAR_SE(xyz, p) \ + ((xyz)->sound_cache[p/32] &= ~(1U << (p % 32))) + #endif Index: server/apply.c =================================================================== RCS file: /cvsroot/crossfire/crossfire/server/apply.c,v retrieving revision 1.107 diff -u -r1.107 apply.c --- server/apply.c 8 May 2004 13:38:05 -0000 1.107 +++ server/apply.c 15 May 2004 09:56:39 -0000 @@ -280,6 +280,7 @@ CLEAR_FLAG(tmp, FLAG_APPLIED); fix_player(op); decrease_ob(tmp); + return 1; } @@ -2280,6 +2281,10 @@ if (rtn_script!=0) return 1; } } + + /* Play sound event 'apply' */ + play_object_sound( tmp, SE_APPLY, op ); + switch (tmp->type) { case CF_HANDLE: -------------- next part -------------- /* * static char *rcsid_sound_c = * "$Id$"; */ /* CrossFire, A Multiplayer game for X-windows Copyright (C) 2001-2003 Mark Wedel & Crossfire Development Team Copyright (C) 1992 Frank Tore Johansen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The authors can be reached via e-mail at crossfire-devel at real-time.com */ /** * This file deals with sound support. * It'll load sound definition from file(s), and assign unique numbers * to sounds, things like that. * * Author: Ryo * Date: April 28th 2004 (start) */ #include <global.h> #include <object.h> #include <sounds.h> static const char** sounds = NULL; static int sound_count = 0; /**< Sound count, to go fast & alloc memory for sound structures */ static int sound_event_count = 0; /**< Sound event count, to alloc memory for events */ /** * This is the text-int match for 'sound' lines in archetypes. */ const char* sound_events[ ] = { "death", "move", "apply", NULL }; /** * Get sound event count. * Just a wrapper to return sound_event_count */ int get_sound_event_count( ) { return sound_event_count; } /** * Get soundname from number. * Just a wrapper to sounds[ number ]. */ const char* get_sound_name( int sound_number ) { if ( ( sound_number < 0 ) || ( sound_number >= sound_count ) ) return NULL; return sounds[ sound_number ]; } /** * Adds specified sound to our sound list. Doesn't check for duplicates. */ void add_sound( const char* soundname ) { if ( !soundname || ( strlen( soundname ) == 0 ) ) { LOG( llevDebug, "Empty sound line" ); return; } sound_count++; sounds = ( const char** )realloc( ( void* )sounds, sizeof( const char* ) * sound_count ); sounds[ sound_count - 1 ] = strdup( soundname ); } #define SOUND_WORD "sound " #define SOUND_LEN 6 /** * This parses specified sound file. * Basically just looks for lines 'sound xxx', adds 'xxx' to * internal list if not yet, ignore the rest. */ int parse_sound_file( const char* filename ) { FILE* fp; int comp; char buf[ MAX_BUF ]; char* nl; LOG( llevDebug, "Reading sound info from %s...", filename ); if ( ( fp = open_and_uncompress( filename, 0, &comp ) ) == NULL) { LOG( llevError, "Can't open sound file %s.\n", filename ); return 0; } while ( fgets( buf, MAX_BUF, fp ) != NULL ) { if ( nl = strstr( buf, "\n" ) ) *nl = '\0'; if ( !strncmp( buf, SOUND_WORD, SOUND_LEN ) ) /* Found a sound, add it */ add_sound( buf + SOUND_LEN ); } LOG( llevDebug, "done.\n" ); close_and_delete( fp, comp ); return 1; } /** * Returns sound identifier by name. * -1 if not found, else < get_sound_event_count( ) */ int get_sound_by_name( const char* sound_name ) { int sound = 0; if ( !sound_name || ( strlen( sound_name ) == 0 ) ) { LOG( llevDebug, "get_sound_by_name: NULL or empty event_code._n" ); return -1; } while ( sound < sound_count ) { if ( !strcmp( sound_name, sounds[ sound ] ) ) return sound; sound++; } return -1; } /** * Returns sound event identifier for specified name. */ int get_sound_event_code( const char* event_name ) { int sound = 0; if ( !event_name || ( strlen( event_name ) == 0 ) ) { LOG( llevDebug, "get_sound_event_code: NULL or empty event_code.\n" ); return -1; } while ( sound < sound_event_count ) { if ( !strcmp( event_name, sound_events[ sound ] ) ) return sound; sound++; } return -1; } /** * Return sound event name, used for saving. */ const char* get_sound_event_name( int event_code ) { if ( event_code < 0 || event_code >= sound_event_count ) { LOG( llevDebug, "get_sound_event_name: invalid sound %d\n", event_code ); return NULL; } return sound_events[ event_code ]; } /** * Init sounds. * Reads sound file, inits some variables. */ int init_sounds( ) { char filename[MAX_BUF]; sprintf( filename, "%s/sounds_arch", settings.datadir ); if ( !parse_sound_file( filename ) ) return 0; LOG( llevDebug, "Done loading sounds, %d found, ", sound_count ); while ( sound_events[ sound_event_count ] ) sound_event_count++; LOG( llevDebug, "%d sound events.\n", sound_event_count ); return 1; } /** * Parses a soundinfo (called from loader.c). */ void read_sound_info( object* op, const char* line ) { soundinfo* info; char stype[ HUGE_BUF ], name[ HUGE_BUF ]; int chance, type, number; if ( sscanf( line, "%s %s %d", &stype, &name, &chance ) != 3 ) { LOG( llevDebug, "invalid sound line: %s\n", line ); return; } type = get_sound_event_code( stype ); if ( type == -1 ) { LOG( llevDebug, "invalid sound type: %s\n", line ); return; } number = get_sound_by_name( name ); if ( number == -1 ) { LOG( llevDebug, "invalid sound name: %s\n", line ); return; } for ( info = op->sounds; info; info = info->next ) { if ( info->type == type ) break; } if ( !info ) { info = ( soundinfo* )malloc( sizeof( soundinfo ) ); info->type = type; info->count = 0; info->total_chance = 0; info->sounds = NULL; info->chance = NULL; info->next = op->sounds; op->sounds = info; } info->count++; info->total_chance += chance; info->sounds = ( int* )realloc( info->sounds, sizeof( int* ) * info->count ); info->sounds[ info->count - 1 ] = number; info->chance = ( int* )realloc( info->chance, sizeof( int* ) * info->count ); info->chance[ info->count - 1 ] = chance; SET_SE( op, type ); if ( info->total_chance > 100 ) { LOG( llevDebug, "Object %s has sound total chance > 100 for type %d !\n", op->name, type ); } } /** * Plays sound for object & type. */ void play_object_sound( object* ob, int sound_type, object* onlyfor ) { soundinfo* info; int chance, sound; if ( !QUERY_SE( ob, sound_type ) && !QUERY_SE( &ob->arch->clone, sound_type ) ) return; if ( onlyfor && onlyfor->type != PLAYER ) return; if ( !ob ) { LOG( llevDebug, "play_sound_object: NULL object!\n" ); return; } if ( !ob->map ) { if ( !onlyfor ) { LOG( llevDebug, "play_sound_object: NULL map and onlyfor!\n" ); return; } if ( !onlyfor->contr ) { LOG( llevDebug, "play_sound_object: NULL onlyfor->contr!\n" ); return; } } info = NULL; if ( QUERY_SE( ob, sound_type ) ) info = ob->sounds; else info = ob->arch->clone.sounds; for ( ; info; info = info->next ) { if ( info->type == sound_type ) break; } if ( !info ) { LOG( llevDebug, "play_sound_event: no sound list %d for object!\n", sound_type ); CLEAR_SE( ob, sound_type ); return; } chance = 1 + RANDOM( ) % 100; if ( chance > info->total_chance ) /* Not playing any sound */ return; sound = -1; while ( chance > 0 ) { chance -= info->chance[ ++sound ]; } if ( !onlyfor ) play_sound_map( ob->map, ob->x, ob->y, info->sounds[ sound ] ); else play_sound_player_only( onlyfor->contr, info->sounds[ sound ], ob->x, ob->y ); } /** * Free sound information structure. */ void free_soundinfo_for_object( object* ob ) { soundinfo* info; while ( ob->sounds ) { info = ob->sounds->next; free( ob->sounds->sounds ); free( ob->sounds->chance ); free( ob->sounds ); ob->sounds = info; } } -------------- next part -------------- _______________________________________________ crossfire-devel mailing list crossfire-devel at lists.real-time.com https://mailman.real-time.com/mailman/listinfo/crossfire-devel