[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