[CF-Devel] Patch: new sound proposal

crossfire-devel at archives.real-time.com crossfire-devel at archives.real-time.com
Sat May 15 05:14:52 CDT 2004


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
     
     
    


More information about the crossfire mailing list